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/sbp2/IOFireWireSBP2ManagementORB.h> 24#include <IOKit/sbp2/IOFireWireSBP2LUN.h> 25 26#define FIREWIREPRIVATE 27#include <IOKit/firewire/IOFireWireController.h> 28#undef FIREWIREPRIVATE 29 30#include <IOKit/firewire/IOConfigDirectory.h> 31 32#include "FWDebugging.h" 33 34extern const OSSymbol *gUnit_Characteristics_Symbol; 35extern const OSSymbol *gManagement_Agent_Offset_Symbol; 36 37OSDefineMetaClassAndStructors( IOFireWireSBP2ManagementORB, IOFWCommand ); 38 39//OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 0); 40OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 1); 41OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 2); 42OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 3); 43OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 4); 44OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 5); 45OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 6); 46OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 7); 47OSMetaClassDefineReservedUnused(IOFireWireSBP2ManagementORB, 8); 48 49// init 50// 51// 52 53bool IOFireWireSBP2ManagementORB::initWithLUN( IOFireWireSBP2LUN * lun, void * refCon, FWSBP2ManagementCallback completion ) 54{ 55 bool res = true; 56 IOReturn status = kIOReturnSuccess; 57 58 // we want the expansion data member to be zeroed if it's available 59 // so create and zero in a local then assign to the member when were done 60 61 ExpansionData * exp_data = (ExpansionData*) IOMalloc( sizeof(ExpansionData) ); 62 if( !exp_data ) 63 { 64 return false; 65 } 66 67 bzero( exp_data, sizeof(ExpansionData) ); 68 69 fExpansionData = exp_data; 70 71 // store LUN & Unit 72 fLUN = lun; 73 fUnit = fLUN->getFireWireUnit(); 74 75 fExpansionData->fInCriticalSection = false; 76 77 // init command fields 78 fControl = fUnit->getController(); 79 fTimeout = 0; 80 fSync = false; 81 82 // set completion routine and refcon 83 fCompletionCallback = completion; 84 fCompletionRefCon = refCon; 85 86 // timer flags 87 fTimeoutTimerSet = false; 88 89 fStatusBlockAddressSpace = NULL; 90 fManagementORBAddressSpace = NULL; 91 fWriteCommand = NULL; 92 fWriteCommandMemory = NULL; 93 94 fFunction = 0; 95 fResponseBuf = NULL; 96 fResponseLen = 0; 97 fResponseAddressSpace = NULL; 98 fResponseAddress = NULL; 99 100 fCompleting = false; 101 102 // init super 103 res = IOFWCommand::initWithController( fControl ); 104 105 // scan unit 106 if( res ) 107 { 108 status = getUnitInformation(); 109 res = ( status == kIOReturnSuccess ); 110 } 111 112 // allocate resources 113 if( res ) 114 { 115 status = allocateResources(); 116 res = ( status == kIOReturnSuccess ); 117 } 118 119 return res; 120} 121 122///////////////////////////////////////////////////////////////////// 123// getUnitInformation 124// 125// gathers SBP2 specific information from unit's ROM 126// specifically it reads, the management agent, and unit dependent 127// characterisitcs 128 129IOReturn IOFireWireSBP2ManagementORB::getUnitInformation( void ) 130{ 131 IOReturn status = kIOReturnSuccess; 132 UInt32 unitCharacteristics = 0; 133 OSObject * prop = NULL; 134 135 prop = fLUN->getProperty( gManagement_Agent_Offset_Symbol ); 136 if( prop == NULL ) 137 status = kIOReturnError; 138 139 if( status == kIOReturnSuccess ) 140 { 141 fManagementOffset = ((OSNumber*)prop)->unsigned32BitValue(); 142 } 143 144 FWKLOG( ("IOFireWireSBP2ManagementORB<%p> : status = %d, fManagementOffset = %d\n", this, status, fManagementOffset) ); 145 146 // 147 // find unit characteristics 148 // 149 150 if( status == kIOReturnSuccess ) 151 { 152 prop = fLUN->getProperty( gUnit_Characteristics_Symbol ); 153 if( prop == NULL ) 154 status = kIOReturnError; 155 } 156 157 if( status == kIOReturnSuccess ) 158 { 159 unitCharacteristics = ((OSNumber*)prop)->unsigned32BitValue(); 160 161 // extract management timeout, max ORB size, max command block size 162 163 fManagementTimeout = ((unitCharacteristics >> 8) & 0xff) * 500; // in milliseconds 164 } 165 166 return status; 167} 168 169// allocateResources 170// 171// 172 173IOReturn IOFireWireSBP2ManagementORB::allocateResources( void ) 174{ 175 IOReturn status = kIOReturnSuccess; 176 177 // 178 // allocate and register an address space for the management ORB 179 // 180 181 FWAddress host_address(0,0); 182 183 if( status == kIOReturnSuccess ) 184 { 185 fManagementORBAddressSpace = IOFWPseudoAddressSpace::simpleRead( fControl, &host_address, 186 sizeof(FWSBP2TaskManagementORB), & fManagementORB ); 187 if ( fManagementORBAddressSpace == NULL ) 188 status = kIOReturnNoMemory; 189 } 190 191 if( status == kIOReturnSuccess ) 192 { 193 fManagementORBAddress.nodeID = OSSwapHostToBigInt16(host_address.nodeID); 194 fManagementORBAddress.addressHi = OSSwapHostToBigInt16(host_address.addressHi); 195 fManagementORBAddress.addressLo = OSSwapHostToBigInt32(host_address.addressLo); 196 197 status = fManagementORBAddressSpace->activate(); 198 } 199 200 // 201 // allocate and register an address space for the status block 202 // 203 204 if( status == kIOReturnSuccess ) 205 { 206 fStatusBlockAddressSpace = fUnit->createPseudoAddressSpace( &fStatusBlockAddress, sizeof(FWSBP2StatusBlock), 207 NULL, IOFireWireSBP2ManagementORB::statusBlockWriteStatic, 208 this ); 209 if ( fStatusBlockAddressSpace == NULL ) 210 status = kIOReturnNoMemory; 211 } 212 213 if( status == kIOReturnSuccess ) 214 { 215 status = fStatusBlockAddressSpace->activate(); 216 } 217 218 // 219 // create command for writing the management agent 220 // 221 222 if( status == kIOReturnSuccess ) 223 { 224 fWriteCommandMemory = IOMemoryDescriptor::withAddress( &fManagementORBAddress, 8, kIODirectionOut ); 225 if( fWriteCommandMemory == NULL ) 226 status = kIOReturnNoMemory; 227 } 228 229 if( status == kIOReturnSuccess ) 230 { 231 fWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)), 232 fWriteCommandMemory, 233 IOFireWireSBP2ManagementORB::writeCompleteStatic, this, true ); 234 if( fWriteCommand == NULL ) 235 status = kIOReturnNoMemory; 236 } 237 238 if( status == kIOReturnSuccess ) 239 { 240 fManagementORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fStatusBlockAddress.nodeID << 16) | fStatusBlockAddress.addressHi); 241 fManagementORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fStatusBlockAddress.addressLo); 242 } 243 244 if( status == kIOReturnSuccess ) 245 { 246 fTimeoutCommand = fControl->createDelayedCmd( fManagementTimeout * 1000, 247 IOFireWireSBP2ManagementORB::handleTimeoutStatic, this ); 248 if( !fTimeoutCommand ) 249 status = kIOReturnNoMemory; 250 } 251 252 return status; 253} 254 255// free 256// 257// 258 259void IOFireWireSBP2ManagementORB::free( void ) 260{ 261 IOReturn status = kIOReturnSuccess; 262 263 removeManagementORB( this ); 264 265 // cancel timer 266 if( fTimeoutTimerSet ) 267 fTimeoutCommand->cancel(kIOReturnAborted); 268 269 if( fTimeoutCommand ) 270 fTimeoutCommand->release(); 271 272 // 273 // deallocate management orb address space 274 // 275 276 if( fManagementORBAddressSpace != NULL && status == kIOReturnSuccess ) 277 { 278 fManagementORBAddressSpace->deactivate(); 279 fManagementORBAddressSpace->release(); 280 } 281 282 // 283 // deallocate status block address space 284 // 285 286 if( fStatusBlockAddressSpace != NULL && status == kIOReturnSuccess ) 287 { 288 fStatusBlockAddressSpace->deactivate(); 289 fStatusBlockAddressSpace->release(); 290 } 291 292 if( fResponseMap != NULL ) 293 { 294 fResponseMap->release(); 295 fResponseMap = NULL; 296 } 297 298 // 299 // deallocate response address space 300 // 301 302 if( fResponseAddressSpace != NULL && status == kIOReturnSuccess ) 303 { 304 fResponseAddressSpace->deactivate(); 305 fResponseAddressSpace->release(); 306 } 307 308 // 309 // release command for writing the management agent 310 // 311 312 if( fWriteCommand != NULL ) 313 fWriteCommand->release(); 314 315 if( fWriteCommandMemory != NULL ) 316 fWriteCommandMemory->release(); 317 318 // 319 // free expansion data 320 // 321 322 if( fExpansionData ) 323 { 324 IOFree( fExpansionData, sizeof(ExpansionData) ); 325 fExpansionData = NULL; 326 } 327 328 IOFWCommand::free(); 329} 330 331void IOFireWireSBP2ManagementORB::release() const 332{ 333 if( getRetainCount() >= 2 ) 334 IOFWCommand::release(2); 335} 336 337// 338// accessors 339// 340 341// get / set command function 342 343IOReturn IOFireWireSBP2ManagementORB::setCommandFunction( UInt32 function ) 344{ 345 // disallow login/reconnect/password/logout functions 346 if( function == 0 || function == 3 || function == 4 || function == 7 ) 347 { 348 return kIOReturnBadArgument; 349 } 350 else 351 { 352 fFunction = function; 353 354 fManagementORB.options &= OSSwapHostToBigInt16(0xfff0); 355 fManagementORB.options |= OSSwapHostToBigInt16(function | 0x8000); // new and notify 356 } 357 358 return kIOReturnSuccess; 359} 360 361UInt32 IOFireWireSBP2ManagementORB::getCommandFunction( void ) 362{ 363 return fFunction; 364} 365 366// get / set managee command 367 368void IOFireWireSBP2ManagementORB::setManageeCommand( OSObject * command ) 369{ 370 fManageeCommand = command; 371} 372 373OSObject* IOFireWireSBP2ManagementORB::getManageeCommand( void ) 374{ 375 return fManageeCommand; 376} 377 378// get / set response buffer 379 380IOReturn IOFireWireSBP2ManagementORB::setResponseBuffer( void * buf, UInt32 len ) 381{ 382 IOReturn status = kIOReturnSuccess; 383 384 // 385 // deallocate old response address space 386 // 387 388 if( fResponseAddressSpace != NULL ) 389 { 390 fResponseAddressSpace->deactivate(); 391 fResponseAddressSpace->release(); 392 } 393 394 fResponseBuf = buf; 395 fResponseLen = len; 396 397 // 398 // allocate and register an address space for the response 399 // 400 401 if( status == kIOReturnSuccess && buf != NULL && len != 0 ) 402 { 403 fResponseAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, 404 &fResponseAddress, 405 len, buf ); 406 if ( fResponseAddressSpace == NULL ) 407 status = kIOReturnNoMemory; 408 409 if( status == kIOReturnSuccess ) 410 { 411 status = fResponseAddressSpace->activate(); 412 } 413 } 414 415 if( status != kIOReturnSuccess ) 416 { 417 fResponseBuf = NULL; 418 fResponseLen = 0; 419 } 420 421 return status; 422} 423 424void IOFireWireSBP2ManagementORB::getResponseBuffer( void ** buf, UInt32 * len ) 425{ 426 *buf = fResponseBuf; 427 *len = fResponseLen; 428} 429 430IOReturn IOFireWireSBP2ManagementORB::setResponseBuffer 431 ( IOMemoryDescriptor * desc ) 432{ 433 IOReturn status = kIOReturnSuccess; 434 void * buf = NULL; 435 UInt32 len = 0; 436 437 // 438 // deallocate old response address space 439 // 440 441 if( fResponseAddressSpace != NULL ) 442 { 443 fResponseAddressSpace->deactivate(); 444 fResponseAddressSpace->release(); 445 } 446 447 if( fResponseMap != NULL ) 448 { 449 fResponseMap->release(); 450 } 451 452 if( desc != NULL ) 453 { 454 len = desc->getLength(); 455 456 fResponseMap = desc->map(); 457 if( fResponseMap != NULL ) 458 { 459 buf = (void*)fResponseMap->getVirtualAddress(); 460 } 461 } 462 463 fResponseBuf = buf; 464 fResponseLen = len; 465 466 // 467 // allocate and register an address space for the response 468 // 469 470 if( status == kIOReturnSuccess && desc != NULL && buf != NULL && len != 0 ) 471 { 472 fResponseAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, 473 &fResponseAddress, 474 desc ); 475 if ( fResponseAddressSpace == NULL ) 476 status = kIOReturnNoMemory; 477 478 if( status == kIOReturnSuccess ) 479 { 480 status = fResponseAddressSpace->activate(); 481 } 482 } 483 484 if( status != kIOReturnSuccess ) 485 { 486 fResponseBuf = NULL; 487 fResponseLen = 0; 488 } 489 490 return status; 491} 492 493 494// 495// command execution 496// 497 498IOReturn IOFireWireSBP2ManagementORB::execute( void ) 499{ 500 FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : execute\n", this ) ); 501 IOReturn status = kIOReturnSuccess; 502 503 IOFireWireSBP2Login * login = NULL; 504 IOFireWireSBP2ORB * orb = NULL; 505 506 switch( fFunction ) 507 { 508 case kFWSBP2TargetReset: 509 case kFWSBP2LogicalUnitReset: 510 case kFWSBP2AbortTaskSet: 511 login = OSDynamicCast( IOFireWireSBP2Login, fManageeCommand ); 512 if( login == NULL ) 513 status = kIOReturnBadArgument; 514 break; 515 516 case kFWSBP2AbortTask: 517 orb = OSDynamicCast( IOFireWireSBP2ORB, fManageeCommand ); 518 if( orb == NULL ) 519 status = kIOReturnBadArgument; 520 else 521 login = orb->getLogin(); 522 break; 523 524 case kFWSBP2QueryLogins: 525 break; 526 527 default: 528 status = kIOReturnBadArgument; 529 } 530 531 // set login ID for all transactions except query logins 532 if( status == kIOReturnSuccess && fFunction != kFWSBP2QueryLogins ) 533 { 534 fManagementORB.loginID = OSSwapHostToBigInt16(login->getLoginID()); 535 } 536 537 if( status == kIOReturnSuccess && fFunction == kFWSBP2AbortTask ) 538 { 539 // set orb address 540 FWAddress address; 541 orb->getORBAddress( &address ); 542 fManagementORB.orbOffsetHi = OSSwapHostToBigInt32(0x0000ffff & address.addressHi); 543 fManagementORB.orbOffsetLo = OSSwapHostToBigInt32(0xfffffffc & address.addressLo); 544 545 // abort orb 546 setORBToDummy( orb ); 547 } 548 549 if( status == kIOReturnSuccess && fFunction == kFWSBP2QueryLogins ) 550 { 551 FWSBP2QueryLoginsORB * queryLoginsORB = (FWSBP2QueryLoginsORB *)&fManagementORB; 552 553 queryLoginsORB->lun = OSSwapHostToBigInt16(fLUN->getLUNumber()); 554 queryLoginsORB->queryResponseAddressHi = OSSwapHostToBigInt32(0x0000ffff & fResponseAddress.addressHi); 555 queryLoginsORB->queryResponseAddressLo = OSSwapHostToBigInt32(fResponseAddress.addressLo); 556 queryLoginsORB->queryResponseLength = OSSwapHostToBigInt16(fResponseLen); 557 } 558 559 if( status == kIOReturnSuccess ) 560 { 561 fWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)), 562 fWriteCommandMemory, 563 IOFireWireSBP2ManagementORB::writeCompleteStatic, this, true ); 564 565 status = fLUN->getTarget()->beginIOCriticalSection(); 566 } 567 568 if( status == kIOReturnSuccess ) 569 { 570 fExpansionData->fInCriticalSection = true; 571 status = fWriteCommand->submit(); 572 } 573 574 if( status != kIOReturnSuccess ) 575 { 576 if( fExpansionData->fInCriticalSection ) 577 { 578 fExpansionData->fInCriticalSection = false; 579 fLUN->getTarget()->endIOCriticalSection(); 580 } 581 582 return status; 583 } 584 585 return kIOReturnBusy; // this means we are now busy working on this command 586} 587 588// 589// write complete handler 590// 591 592void IOFireWireSBP2ManagementORB::writeCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd ) 593{ 594 ((IOFireWireSBP2ManagementORB*)refcon)->writeComplete( status, device, fwCmd ); 595} 596 597void IOFireWireSBP2ManagementORB::writeComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd ) 598{ 599 FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : write complete\n", this ) ); 600 601 if( status == kIOReturnSuccess ) 602 { 603 // we wrote the management agent, now set a timer and wait for response & status 604 fTimeoutTimerSet = true; 605 if( fTimeoutCommand->submit() != kIOReturnSuccess ) 606 fTimeoutTimerSet = false; 607 } 608 else 609 complete( status ); // complete with error 610 611} 612 613// 614// timeout handler 615// 616 617void IOFireWireSBP2ManagementORB::handleTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd ) 618{ 619 ((IOFireWireSBP2ManagementORB*)refcon)->handleTimeout( status, bus, fwCmd ); 620} 621 622void IOFireWireSBP2ManagementORB::handleTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd ) 623{ 624 fTimeoutTimerSet = false; 625 626 if( status == kIOReturnTimeout ) 627 { 628 FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : handle timeout\n", this ) ); 629 complete( kIOReturnTimeout ); 630 } 631} 632 633// 634// status block write handler 635// 636 637UInt32 IOFireWireSBP2ManagementORB::statusBlockWriteStatic( void *refcon, UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, 638 UInt32 len, const void *buf, IOFWRequestRefCon lockRead ) 639{ 640 return ((IOFireWireSBP2ManagementORB*)refcon)->statusBlockWrite( nodeID, addr, len, buf, lockRead ); 641} 642 643UInt32 IOFireWireSBP2ManagementORB::statusBlockWrite( UInt16 nodeID, FWAddress addr, UInt32 len, const void *buf, 644 IOFWRequestRefCon lockRead ) 645{ 646 // if timer isn't running we should not have been called. don't panic... 647 if( !fTimeoutTimerSet ) 648 return kFWResponseComplete; 649 650 // cancel timeout 651 fTimeoutCommand->cancel(kIOReturnAborted); 652 653 if( fFunction == kFWSBP2AbortTaskSet || 654 fFunction == kFWSBP2TargetReset || 655 fFunction == kFWSBP2LogicalUnitReset ) 656 { 657 // all tasks aborted once these babies complete 658 fCompleting = true; 659 clearAllTasksInSet(); 660 fCompleting = false; 661 } 662 663 // complete command 664 complete( kIOReturnSuccess ); 665 666 return kFWResponseComplete; 667} 668 669// 670// suspendedNotify method 671// 672// called when a suspended message is received 673 674void IOFireWireSBP2ManagementORB::suspendedNotify( void ) 675{ 676 FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : suspendedNotify\n", this ) ); 677 678 if( fStatus == kIOReturnBusy && !fCompleting ) 679 { 680 if( fTimeoutTimerSet ) 681 { 682 // cancel timeout 683 fTimeoutCommand->cancel( kIOReturnAborted ); 684 } 685 686 // complete command 687 complete( kIOFireWireBusReset ); 688 } 689} 690 691// 692// complete 693// 694 695IOReturn IOFireWireSBP2ManagementORB::complete( IOReturn state ) 696{ 697 state = IOFWCommand::complete( state ); 698 FWKLOG( ( "IOFireWireSBP2ManagementORB<%p> : complete\n", this ) ); 699 700 if( fExpansionData->fInCriticalSection ) 701 { 702 fExpansionData->fInCriticalSection = false; 703 fLUN->getTarget()->endIOCriticalSection(); 704 } 705 706 if( fCompletionCallback != NULL ) 707 (*fCompletionCallback)(fCompletionRefCon, state, this); 708 709 return state; 710} 711 712// async ref handling for user client 713// 714// 715 716void IOFireWireSBP2ManagementORB::setAsyncCallbackReference( void * asyncRef ) 717{ 718 bcopy( asyncRef, fCallbackAsyncRef, sizeof(OSAsyncReference64) ); 719} 720 721void IOFireWireSBP2ManagementORB::getAsyncCallbackReference( void * asyncRef ) 722{ 723 bcopy( fCallbackAsyncRef, asyncRef, sizeof(OSAsyncReference64) ); 724} 725 726////////////////////////////////////////////////////////////////////////////////////////// 727// friend class wrappers 728 729// IOFireWireSBP2LUN friend class wrappers 730 731void IOFireWireSBP2ManagementORB::clearAllTasksInSet( void ) 732{ 733 fLUN->clearAllTasksInSet(); 734} 735 736void IOFireWireSBP2ManagementORB::removeManagementORB( IOFireWireSBP2ManagementORB * orb ) 737{ 738 fLUN->removeManagementORB( orb ); 739} 740 741// IOFireWireSBP2ORB friend class wrappers 742 743void IOFireWireSBP2ManagementORB::setORBToDummy( IOFireWireSBP2ORB * orb ) 744{ 745 orb->setToDummy(); 746} 747