1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <IOKit/IOMessage.h> 24#include <IOKit/IOWorkLoop.h> 25 26#include <IOKit/sbp2/IOFireWireSBP2Target.h> 27#include <IOKit/sbp2/IOFireWireSBP2LUN.h> 28#include <IOKit/sbp2/IOFireWireSBP2UserClient.h> 29#include "FWDebugging.h" 30#include "IOFireWireSBP2Diagnostics.h" 31 32extern const OSSymbol *gCommand_Set_Spec_ID_Symbol; 33extern const OSSymbol *gCommand_Set_Symbol; 34extern const OSSymbol *gModule_Vendor_ID_Symbol; 35extern const OSSymbol *gCommand_Set_Revision_Symbol; 36extern const OSSymbol *gIOUnit_Symbol; 37extern const OSSymbol *gFirmware_Revision_Symbol; 38extern const OSSymbol *gDevice_Type_Symbol; 39extern const OSSymbol *gGUID_Symbol; 40 41const OSSymbol *gDiagnostics_Symbol; 42 43OSDefineMetaClassAndStructors( IOFireWireSBP2LUN, IOService ); 44 45OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 0); 46OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 1); 47OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 2); 48OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 3); 49OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 4); 50OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 5); 51OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 6); 52OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 7); 53OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 8); 54 55bool IOFireWireSBP2LUN::attach(IOService *provider) 56{ 57 IOReturn status = kIOReturnSuccess; 58 59 // init fields 60 fProviderTarget = NULL; 61 fGate = NULL; 62 fLUNumber = 0; 63 fORBSet = NULL; 64 fORBSetIterator = NULL; 65 66 FWKLOG( ( "IOFireWireSBP2LUN<%p> : attach\n", this ) ); 67 68 // 69 // attach to provider 70 // 71 72 if( status == kIOReturnSuccess ) 73 { 74 fProviderTarget = OSDynamicCast( IOFireWireSBP2Target, provider ); 75 if( !fProviderTarget ) 76 status = kIOReturnError; 77 } 78 79 if( status == kIOReturnSuccess ) 80 { 81 fProviderTarget->retain(); 82 if( !IOService::attach(provider) ) 83 status = kIOReturnError; 84 } 85 86#if FWDIAGNOSTICS 87 88 if( gDiagnostics_Symbol == NULL ) 89 gDiagnostics_Symbol = OSSymbol::withCString("SBP2 Diagnostics"); 90 91 fDiagnostics = IOFireWireSBP2Diagnostics::createDiagnostics(); 92 if( fDiagnostics ) 93 { 94 setProperty( gDiagnostics_Symbol, fDiagnostics ); 95 } 96 97#endif 98 99 // 100 // get lun number 101 // 102 103 if( status == kIOReturnSuccess ) 104 { 105 OSObject *prop; 106 107 // read lun number from registry 108 prop = getProperty( gIOUnit_Symbol ); 109 fLUNumber = ((OSNumber*)prop)->unsigned32BitValue(); 110 } 111 112 // 113 // create login set 114 // 115 116 if( status == kIOReturnSuccess ) 117 { 118 fLoginSet = OSSet::withCapacity(1); 119 if( fLoginSet == NULL ) 120 status = kIOReturnNoMemory; 121 } 122 123 if( status == kIOReturnSuccess ) 124 { 125 if( fLoginSet ) 126 fLoginSetIterator = OSCollectionIterator::withCollection( fLoginSet ); 127 } 128 129 130 // 131 // create management orb set 132 // 133 134 if( status == kIOReturnSuccess ) 135 { 136 fORBSet = OSSet::withCapacity(1); 137 if( fORBSet == NULL ) 138 status = kIOReturnNoMemory; 139 } 140 141 if( status == kIOReturnSuccess ) 142 { 143 if( fORBSet ) 144 fORBSetIterator = OSCollectionIterator::withCollection( fORBSet ); 145 } 146 147 // 148 // set up command gate 149 // 150 151 IOWorkLoop * workLoop = NULL; 152 if( status == kIOReturnSuccess ) 153 { 154 workLoop = getWorkLoop(); 155 if( !workLoop ) 156 status = kIOReturnNoResources; 157 } 158 159 if( status == kIOReturnSuccess ) 160 { 161 fGate = IOCommandGate::commandGate( this ); 162 if( !fGate ) 163 status = kIOReturnNoMemory; 164 } 165 166 if( status == kIOReturnSuccess ) 167 { 168 workLoop->retain(); 169 workLoop->addEventSource( fGate ); 170 } 171 172 return (status == kIOReturnSuccess); 173} 174 175// finalize 176// 177// 178 179bool IOFireWireSBP2LUN::finalize( IOOptionBits options ) 180{ 181 FWKLOG( ( "IOFireWireSBP2LUN<%p> : finalize\n", this ) ); 182 183 return IOService::finalize( options ); 184} 185 186// 187// free 188// 189 190void IOFireWireSBP2LUN::free( void ) 191{ 192 FWKLOG( ( "IOFireWireSBP2LUN<%p> : free\n", this ) ); 193 194 // 195 // free unreleased orbs 196 // 197 198// flushAllManagementORBs(); 199 200 if( fORBSetIterator ) 201 fORBSetIterator->release(); 202 203 if( fORBSet ) 204 fORBSet->release(); 205 206 // 207 // release login set 208 // 209 210 if( fLoginSetIterator ) 211 fLoginSetIterator->release(); 212 213 if( fLoginSet ) 214 fLoginSet->release(); 215 216 // 217 // destroy command gate 218 // 219 220 if( fGate != NULL ) 221 { 222 IOWorkLoop * workLoop = NULL; 223 224 workLoop = fGate->getWorkLoop(); 225 workLoop->removeEventSource( fGate ); 226 workLoop->release(); 227 228 fGate->release(); 229 fGate = NULL; 230 } 231 232 if( fProviderTarget ) 233 { 234 fProviderTarget->release(); 235 fProviderTarget = NULL; 236 } 237 238 IOService::free(); 239} 240 241// flushAllManagementORBs 242// 243// 244 245void IOFireWireSBP2LUN::flushAllManagementORBs( void ) 246{ 247 IOReturn status = kIOReturnSuccess; 248 249 status = fGate->runAction( staticExecuteFlushAllMgmtORBs); 250} 251 252IOReturn IOFireWireSBP2LUN::staticExecuteFlushAllMgmtORBs( OSObject * self, void *, 253 void *, void *, void * ) 254{ 255 return ((IOFireWireSBP2LUN *)self)->executeFlushAllMgmtORBs(); 256} 257 258IOReturn IOFireWireSBP2LUN::executeFlushAllMgmtORBs( void ) 259{ 260 // 261 // free unreleased orbs 262 // 263 264 if( fORBSetIterator ) 265 { 266 IOFireWireSBP2ManagementORB * item = NULL; 267 do 268 { 269 fORBSetIterator->reset(); 270 item = (IOFireWireSBP2ManagementORB *)fORBSetIterator->getNextObject(); 271 if( item ) 272 item->release(); 273 } while( item ); 274 } 275 276 return kIOReturnSuccess; 277} 278 279//////////////////////////////////////////////////////////////////// 280 281// 282// handleOpen / handleClose 283// 284 285bool IOFireWireSBP2LUN::handleOpen( IOService * forClient, IOOptionBits options, void * arg ) 286{ 287 FWKLOG(( "IOFireWireSBP2LUN<%p> (%d) : handleOpen\n", this, fLUNumber )); 288 289 bool ok = false; 290 291 if( !isOpen() ) 292 { 293 ok = fProviderTarget->open(this, options, arg); 294 if(ok) 295 ok = IOService::handleOpen(forClient, options, arg); 296 } 297 298 return ok; 299} 300 301void IOFireWireSBP2LUN::handleClose( IOService * forClient, IOOptionBits options ) 302{ 303 FWKLOG(( "IOFireWireSBP2LUN<%p> (%d) : handleClose\n", this, fLUNumber )); 304 305 if( isOpen( forClient ) ) 306 { 307 IOService::handleClose(forClient, options); 308 fProviderTarget->close(this, options); 309 } 310} 311 312// 313// message method 314// 315 316IOReturn IOFireWireSBP2LUN::message( UInt32 type, IOService *nub, void *arg ) 317{ 318 IOReturn res = kIOReturnUnsupported; 319 320 //IOLog("IOFireWireSBP2LUN, message 0x%x\n", type); 321 322 res = IOService::message(type, nub, arg); 323 324 if( kIOReturnUnsupported == res ) 325 { 326 switch (type) 327 { 328 case kIOMessageServiceIsTerminated: 329 terminateNotify(); 330 FWKLOG( ( "IOFireWireSBP2LUN<%p> : kIOMessageServiceIsTerminated\n", this ) ); 331 res = kIOReturnSuccess; 332 break; 333 334 case kIOMessageServiceIsSuspended: 335 FWKLOG( ( "IOFireWireSBP2LUN<%p> : kIOMessageServiceIsSuspended\n", this ) ); 336 suspendedNotify(); 337 res = kIOReturnSuccess; 338 break; 339 340 case kIOMessageServiceIsResumed: 341 FWKLOG( ( "IOFireWireSBP2LUN<%p> : kIOMessageServiceIsResumed\n", this ) ); 342 resumeNotify(); 343 res = kIOReturnSuccess; 344 break; 345 346 default: // default the action to return kIOReturnUnsupported 347 break; 348 } 349 } 350 351 // we must send resumeNotify and/or suspendNotify before messaging clients 352 if( type != kIOMessageServiceIsTerminated && 353 type != (UInt32)kIOMessageFWSBP2ReconnectFailed && 354 type != (UInt32)kIOMessageFWSBP2ReconnectComplete ) 355 { 356 messageClients( type, arg ); 357 } 358 359 // send reset notification for all busy orbs 360 // we must send orb reset notification after messaging clients 361 if( type == kIOMessageServiceIsSuspended ) 362 clearAllTasksInSet(); 363 364 return res; 365} 366 367//////////////////////////////////////////////////////////////////// 368 369// getFireWireUnit 370// 371// returns the FireWire unit for doing non-SBP2 work 372 373IOFireWireUnit * IOFireWireSBP2LUN::getFireWireUnit( void ) 374{ 375 IOService * unit = NULL; 376 377 IOService * provider = getProvider(); 378 if( provider ) 379 { 380 unit = provider->getProvider(); 381 } 382 383 return (IOFireWireUnit*)unit; 384} 385 386// getLUNumber 387// 388// lun number accessor 389 390UInt32 IOFireWireSBP2LUN::getLUNumber( void ) 391{ 392 return fLUNumber; 393} 394 395// getTarget 396// 397// target accessor 398 399IOFireWireSBP2Target * IOFireWireSBP2LUN::getTarget( void ) 400{ 401 return (IOFireWireSBP2Target*)getProvider(); 402} 403 404//////////////////////////////////////////////////////////////////// 405 406// createLogin 407// 408// create a login object 409 410IOFireWireSBP2Login * IOFireWireSBP2LUN::createLogin( void ) 411{ 412 IOReturn status = kIOReturnSuccess; 413 IOFireWireSBP2Login * login; 414 415 status = fGate->runAction( staticCreateLogin, &login ); 416 417 return login; 418} 419 420IOReturn IOFireWireSBP2LUN::staticCreateLogin( OSObject *self, void * login, void *, void *, void * ) 421{ 422 return ((IOFireWireSBP2LUN *)self)->createLoginAction( (IOFireWireSBP2Login **)login ); 423} 424 425IOReturn IOFireWireSBP2LUN::createLoginAction( IOFireWireSBP2Login ** login ) 426{ 427 IOFireWireSBP2Login * newLogin; 428 newLogin = new IOFireWireSBP2Login; 429 if( newLogin != NULL && !initLoginWithLUN( newLogin, this ) ) 430 { 431 newLogin->release(); 432 newLogin = NULL; 433 } 434 435 *login = newLogin; 436 437 fLoginSet->setObject( *login ); 438 439 return kIOReturnSuccess; 440} 441 442// 443// remove login 444// 445 446// removeManagementORB 447// 448// remove management orb from LUN's set 449 450void IOFireWireSBP2LUN::removeLogin( IOFireWireSBP2Login * login ) 451{ 452 IOReturn status = kIOReturnSuccess; 453 454 status = fGate->runAction( (IOCommandGate::Action)staticRemoveLoginAction, (void*)login ); 455} 456 457IOReturn IOFireWireSBP2LUN::staticRemoveLoginAction( OSObject *self, void * login, void *, void *, void * ) 458{ 459 return ((IOFireWireSBP2LUN*)self)->removeLoginAction( (IOFireWireSBP2Login *)login ); 460} 461 462IOReturn IOFireWireSBP2LUN::removeLoginAction( IOFireWireSBP2Login * login ) 463{ 464 fLoginSet->removeObject( login ); 465 return kIOReturnSuccess; 466} 467 468// clearAllTasksInSet 469// 470// send reset notification for all busy orbs 471 472void IOFireWireSBP2LUN::clearAllTasksInSet( void ) 473{ 474 if( fORBSetIterator ) 475 { 476 IOFireWireSBP2ManagementORB * item = NULL; 477 fORBSetIterator->reset(); 478 do 479 { 480 item = (IOFireWireSBP2ManagementORB *)fORBSetIterator->getNextObject(); 481 if( item ) 482 item->suspendedNotify(); 483 } while( item ); 484 } 485 486 if( fLoginSetIterator ) 487 { 488 IOFireWireSBP2Login * item = NULL; 489 fLoginSetIterator->reset(); 490 do 491 { 492 item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject(); 493 if( item ) 494 item->clearAllTasksInSet(); 495 } while( item ); 496 } 497} 498 499//////////////////////////////////////////////////////////////////// 500 501// createManagementORB 502// 503// create a management object 504 505IOFireWireSBP2ManagementORB * IOFireWireSBP2LUN::createManagementORB( void * refCon, FWSBP2ManagementCallback completion ) 506{ 507 IOReturn status = kIOReturnSuccess; 508 IOFireWireSBP2ManagementORB * orb; 509 510 status = fGate->runAction( staticCreateManagementORBAction, refCon, (void*)completion, &orb ); 511 512 return orb; 513} 514 515IOReturn IOFireWireSBP2LUN::staticCreateManagementORBAction( OSObject *self, 516 void * refCon, void * completion, 517 void * orb, void * ) 518{ 519 return ((IOFireWireSBP2LUN *)self)->createManagementORBAction( refCon, (FWSBP2ManagementCallback)completion, (IOFireWireSBP2ManagementORB **)orb ); 520} 521 522IOReturn IOFireWireSBP2LUN::createManagementORBAction( 523 void * refCon, FWSBP2ManagementCallback completion, 524 IOFireWireSBP2ManagementORB ** orb ) 525{ 526 IOFireWireSBP2ManagementORB * newORB = new IOFireWireSBP2ManagementORB; 527 if( newORB != NULL && !initMgmtORBWithLUN( newORB, this, refCon, completion ) ) 528 { 529 newORB->release(); 530 newORB = NULL; 531 } 532 533 *orb = newORB; 534 535 fORBSet->setObject( *orb ); 536 537 return kIOReturnSuccess; 538} 539 540// removeManagementORB 541// 542// remove management orb from LUN's set 543 544void IOFireWireSBP2LUN::removeManagementORB( IOFireWireSBP2ManagementORB * orb ) 545{ 546 IOReturn status = kIOReturnSuccess; 547 548 status = fGate->runAction( (IOCommandGate::Action)staticRemoveManagementORBAction, (void*)orb ); 549} 550 551IOReturn IOFireWireSBP2LUN::staticRemoveManagementORBAction( OSObject *self, void * orb, 552 void *, void *, void * ) 553{ 554 return ((IOFireWireSBP2LUN*)self)->removeManagementORBAction( (IOFireWireSBP2ManagementORB *)orb ); 555} 556 557IOReturn IOFireWireSBP2LUN::removeManagementORBAction( 558 IOFireWireSBP2ManagementORB * orb ) 559{ 560 fORBSet->removeObject( orb ); 561 562 return kIOReturnSuccess; 563} 564 565//////////////////////////////////////////////////////////////////// 566 567// matchPropertyTable 568// 569// 570 571bool IOFireWireSBP2LUN::matchPropertyTable(OSDictionary * table) 572{ 573 574 // 575 // If the service object wishes to compare some of its properties in its 576 // property table against the supplied matching dictionary, 577 // it should do so in this method and return truth on success. 578 // 579 580 if( !IOService::matchPropertyTable(table) ) 581 return false; 582 583 // We return success if the following expression is true -- individual 584 // comparisions evaluate to truth if the named property is not present 585 // in the supplied matching dictionary. 586 587 bool res = compareProperty(table, gCommand_Set_Spec_ID_Symbol) && 588 compareProperty(table, gCommand_Set_Symbol) && 589 compareProperty(table, gModule_Vendor_ID_Symbol) && 590 compareProperty(table, gCommand_Set_Revision_Symbol) && 591 compareProperty(table, gIOUnit_Symbol) && 592 compareProperty(table, gFirmware_Revision_Symbol) && 593 compareProperty(table, gDevice_Type_Symbol) && 594 compareProperty(table, gGUID_Symbol) && 595 compareProperty(table, gFireWireModel_ID); 596 597 return res; 598} 599 600//////////////////////////////////////////////////////////////////// 601 602// 603// IOFireWireSBP2ManagementORB friend class wrappers 604// 605 606bool IOFireWireSBP2LUN::initMgmtORBWithLUN( IOFireWireSBP2ManagementORB * orb, IOFireWireSBP2LUN * lun, 607 void * refCon, 608 FWSBP2ManagementCallback completion ) 609{ 610 return orb->initWithLUN( lun, refCon, completion ); 611} 612 613// 614// IOFireWireSBP2Login friend class wrappers 615// 616 617bool IOFireWireSBP2LUN::initLoginWithLUN( IOFireWireSBP2Login * login, IOFireWireSBP2LUN * lun ) 618{ 619 return login->initWithLUN( lun ); 620} 621 622void IOFireWireSBP2LUN::suspendedNotify( void ) 623{ 624 if( fLoginSetIterator ) 625 { 626 IOFireWireSBP2Login * item = NULL; 627 fLoginSetIterator->reset(); 628 do 629 { 630 item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject(); 631 if( item ) 632 item->suspendedNotify(); 633 } while( item ); 634 } 635} 636 637void IOFireWireSBP2LUN::resumeNotify( void ) 638{ 639 if( fLoginSetIterator ) 640 { 641 IOFireWireSBP2Login * item = NULL; 642 fLoginSetIterator->reset(); 643 do 644 { 645 item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject(); 646 if( item ) 647 item->resumeNotify(); 648 } while( item ); 649 } 650} 651 652void IOFireWireSBP2LUN::terminateNotify( void ) 653{ 654 if( fLoginSetIterator ) 655 { 656 IOFireWireSBP2Login * item = NULL; 657 fLoginSetIterator->reset(); 658 do 659 { 660 item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject(); 661 if( item ) 662 item->terminateNotify(); 663 } while( item ); 664 } 665} 666 667 668// getDiagnostics 669// 670// return a pointer to the diagnostics object 671 672OSObject * IOFireWireSBP2LUN::getDiagnostics( void ) 673{ 674 return fDiagnostics; 675} 676