1/* 2 * Copyright (c) 1998-2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25 26//----------------------------------------------------------------------------- 27// Includes 28//----------------------------------------------------------------------------- 29 30// BSD includes 31#include <sys/sysctl.h> 32 33// FireWire includes 34#include <IOKit/firewire/IOConfigDirectory.h> 35#include <IOKit/firewire/IOFireWireDevice.h> 36#include <IOKit/IOKitKeys.h> 37#include <IOKit/IOTimeStamp.h> 38 39// FireWire Transport includes 40#include "IOFireWireSerialBusProtocolTransport.h" 41#include "IOFireWireSerialBusProtocolTransportTimestamps.h" 42 43 44//----------------------------------------------------------------------------- 45// Macros 46//----------------------------------------------------------------------------- 47 48#define DEBUG 0 49#define DEBUG_ASSERT_COMPONENT_NAME_STRING "FireWire SBP2 Transport" 50 51#include "IOFireWireSerialBusProtocolTransportDebugging.h" 52 53#if DEBUG 54#define FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL 0 55#endif 56 57#if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 1 ) 58#define PANIC_NOW(x) panic x 59#else 60#define PANIC_NOW(x) 61#endif 62 63#if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 2 ) 64#define ERROR_LOG(x) IOLog x 65#else 66#define ERROR_LOG(x) 67#endif 68 69#if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 3 ) 70#define DLOG(x) IOLog x 71#else 72#define DLOG(x) 73#endif 74 75#define super IOSCSIProtocolServices 76OSDefineMetaClassAndStructors ( IOFireWireSerialBusProtocolTransport, IOSCSIProtocolServices ) 77 78 79#define TRANSPORT_FAILURE_RETRIES 1 80 81 82//----------------------------------------------------------------------------- 83// Structs 84//----------------------------------------------------------------------------- 85 86// SCSI Status Block as defined in Annex B of SBP-2. NB: This is a big-endian 87// representation of the status block, not a host memory representation. 88typedef struct FWSBP2SCSIStatusBlock 89{ 90 UInt8 details; 91 UInt8 sbpStatus; 92 UInt16 orbOffsetHi; 93 UInt32 orbOffsetLo; 94 UInt8 status; 95 UInt8 senseKey; 96 UInt8 ASC; 97 UInt8 ASCQ; 98 UInt32 information; 99 UInt32 commandSpecificInformation; 100 UInt32 senseKeyDependent; 101} FWSBP2SCSIStatusBlock; 102 103 104enum 105{ 106 kSBP2StatusBlock_Details_DeadBit = 3, 107 108 kSBP2StatusBlock_Details_LenMask = 0x7, 109 kSBP2StatusBlock_Details_DeadMask = (1 << kSBP2StatusBlock_Details_DeadBit), 110 kSBP2StatusBlock_Details_RespMask = 0x30, 111 kSBP2StatusBlock_Details_SrcMask = 0xC0 112}; 113 114 115enum 116{ 117 kSBP2StatusBlock_Resp_REQUEST_COMPLETE = 0, 118 kSBP2StatusBlock_Resp_TRANSPORT_FAILURE = 1, 119 kSBP2StatusBlock_Resp_ILLEGAL_REQUEST = 2, 120 kSBP2StatusBlock_Resp_VENDOR_DEPENDENT = 3 121}; 122 123 124enum 125{ 126 kSBP2StatusBlock_SBPStatus_NoAdditionalInformation = 0, 127 kSBP2StatusBlock_SBPStatus_RequestTypeUnsupported = 1, 128 kSBP2StatusBlock_SBPStatus_SpeedUnsupported = 2, 129 kSBP2StatusBlock_SBPStatus_PageSizeUnsupported = 3, 130 kSBP2StatusBlock_SBPStatus_AccessDenied = 4, 131 kSBP2StatusBlock_SBPStatus_LogicalUnitNotSupported = 5, 132 kSBP2StatusBlock_SBPStatus_MaxPayloadTooSmall = 6, 133 // 7 - reserved 134 kSBP2StatusBlock_SBPStatus_ResourcesUnavailable = 8, 135 kSBP2StatusBlock_SBPStatus_FunctionRejected = 9, 136 kSBP2StatusBlock_SBPStatus_LoginIDNotRecognized = 10, 137 kSBP2StatusBlock_SBPStatus_DummyORBCompleted = 11, 138 kSBP2StatusBlock_SBPStatus_RequestAborted = 12, 139 kSBP2StatusBlock_SBPStatus_UnspecifiedError = 0xFF 140}; 141 142 143enum 144{ 145 146 kFWSBP2SCSIStatusBlock_StatusBlockFormatCurrentError = (0 << 6), 147 kFWSBP2SCSIStatusBlock_StatusBlockFormatDeferredError = (1 << 6), 148 kFWSBP2SCSIStatusBlock_StatusBlockFormatMask = 0xC0, 149 // reserved 2 150 // Vendor defined 3 151 152 kFWSBP2SCSIStatusBlock_StatusBlockStatusMask = 0x3F 153}; 154 155 156enum 157{ 158 kFWSBP2SCSIStatusBlock_SenseKeyMask = 0x0F, 159 160 kFWSBP2SCSIStatusBlock_ILI_Bit = 4, 161 kFWSBP2SCSIStatusBlock_ILI_Mask = (1 << kFWSBP2SCSIStatusBlock_ILI_Bit), 162 163 kFWSBP2SCSIStatusBlock_EOM_Bit = 5, 164 kFWSBP2SCSIStatusBlock_EOM_Mask = (1 << kFWSBP2SCSIStatusBlock_EOM_Bit), 165 166 kFWSBP2SCSIStatusBlock_FILEMARK_Bit = 6, 167 kFWSBP2SCSIStatusBlock_FILEMARK_Mask = (1 << kFWSBP2SCSIStatusBlock_FILEMARK_Bit), 168 169 kFWSBP2SCSIStatusBlock_VALID_Bit = 7, 170 kFWSBP2SCSIStatusBlock_VALID_Mask = (1 << kFWSBP2SCSIStatusBlock_VALID_Bit), 171 172 kFWSBP2SCSIStatusBlock_MEI_Mask = kFWSBP2SCSIStatusBlock_ILI_Mask | kFWSBP2SCSIStatusBlock_EOM_Mask | kFWSBP2SCSIStatusBlock_FILEMARK_Mask 173 174}; 175 176 177//----------------------------------------------------------------------------- 178// Constants 179//----------------------------------------------------------------------------- 180 181#define kPreferredNameKey "Preferred Name" 182#define kFireWireGUIDKey "GUID" 183#define kFireWireVendorNameKey "FireWire Vendor Name" 184#define kSBP2ReceiveBufferByteCountKey "SBP2ReceiveBufferByteCount" 185#define kAlwaysSetAutoSenseData "Always Set AutoSense Data" 186#define kDontUsePTPacketLimitKey "Do Not Use PT Packet Limit" 187#define kDefaultIOBlockCount 256 188#define kCRSModelInfo_ValidBitsMask 0x00FFFFFF 189#define kCRSModelInfo_TargetDiskMode 0x0054444D 190#define kIOFireWireMessageServiceIsRequestingClose kIOFWMessageServiceIsRequestingClose 191#define kDefaultTimeOutValue 30000 192#define kCommandPoolOrbCount 1 193#define kFWSBP2DefaultPageTableEntriesCount 512 194#define kDoubleBufferCommandSizeCheckThreshold 512 195#define kLoginRetryCount 32 196#define kLoginDelayTime 1000000 197 198 199enum 200{ 201 kFireWireSBP2CommandTransferDataToTarget = 0L, 202 kFireWireSBP2CommandTransferDataFromTarget = kFWSBP2CommandTransferDataFromTarget 203}; 204 205 206//----------------------------------------------------------------------------- 207// Class 208//----------------------------------------------------------------------------- 209 210class FWSBP2TransportGlobals 211{ 212 213public: 214 215 // Constructor 216 FWSBP2TransportGlobals ( void ); 217 218 // Destructor 219 virtual ~FWSBP2TransportGlobals ( void ); 220 221}; 222 223 224//----------------------------------------------------------------------------- 225// Prototypes 226//----------------------------------------------------------------------------- 227 228static inline void 229RecordFireWireTimeStamp ( 230 unsigned int code, 231 unsigned int a = 0, unsigned int b = 0, 232 unsigned int c = 0, unsigned int d = 0 ); 233 234static int 235FirewireSBPTransportSysctl ( 236 struct sysctl_oid * oidp, 237 void * arg1, 238 int arg2, 239 struct sysctl_req * req ); 240 241 242//----------------------------------------------------------------------------- 243// Globals 244//----------------------------------------------------------------------------- 245 246static FWSBP2TransportGlobals gFWGlobals; 247UInt32 gSBP2DiskDebugFlags = 0; 248 249SYSCTL_PROC ( _debug, OID_AUTO, FirewireSBPTransport, CTLFLAG_RW, 0, 0, FirewireSBPTransportSysctl, "FirewireSBPTransport", "FireWire SBP2 Transport debug interface" ); 250 251 252//----------------------------------------------------------------------------- 253// FirewireSBPTransportSysctl - Sysctl handler. [PRIVATE] 254//----------------------------------------------------------------------------- 255 256static int 257FirewireSBPTransportSysctl ( struct sysctl_oid * oidp, void * arg1, int arg2, struct sysctl_req * req ) 258{ 259 260 int error = 0; 261 FWSysctlArgs fwArgs; 262 263 DEBUG_UNUSED ( oidp ); 264 DEBUG_UNUSED ( arg1 ); 265 DEBUG_UNUSED ( arg2 ); 266 267 DLOG ( ( "+FirewireSBPTransportSysctl: gSBP2DiskDebugFlags = 0x%08X\n", ( unsigned int ) gSBP2DiskDebugFlags ) ); 268 269 error = SYSCTL_IN ( req, &fwArgs, sizeof ( fwArgs ) ); 270 if ( ( error == 0 ) && ( fwArgs.type == kFWTypeDebug ) ) 271 { 272 273 if ( fwArgs.operation == kFWOperationGetFlags ) 274 { 275 276 fwArgs.debugFlags = gSBP2DiskDebugFlags; 277 error = SYSCTL_OUT ( req, &fwArgs, sizeof ( fwArgs ) ); 278 279 } 280 281 else if ( fwArgs.operation == kFWOperationSetFlags ) 282 { 283 gSBP2DiskDebugFlags = fwArgs.debugFlags; 284 } 285 286 } 287 288 DLOG ( ( "-FirewireSBPTransportSysctl: gSBP2DiskDebugFlags = 0x%08X\n", ( unsigned int ) gSBP2DiskDebugFlags ) ); 289 290 return error; 291 292} 293 294 295//----------------------------------------------------------------------------- 296// Default Constructor 297//----------------------------------------------------------------------------- 298 299FWSBP2TransportGlobals::FWSBP2TransportGlobals ( void ) 300{ 301 302 int debugFlags; 303 304 DLOG ( ( "+FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) ); 305 306 if ( PE_parse_boot_argn ( "sbp2disk", &debugFlags, sizeof ( debugFlags ) ) ) 307 { 308 309 gSBP2DiskDebugFlags = debugFlags; 310 311 } 312 313 // Register our sysctl interface 314 sysctl_register_oid ( &sysctl__debug_FirewireSBPTransport ); 315 316 DLOG ( ( "-FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) ); 317 318} 319 320 321//----------------------------------------------------------------------------- 322// Destructor 323//----------------------------------------------------------------------------- 324 325FWSBP2TransportGlobals::~FWSBP2TransportGlobals ( void ) 326{ 327 328 DLOG ( ( "+~FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) ); 329 330 // Unregister our sysctl interface 331 sysctl_unregister_oid ( &sysctl__debug_FirewireSBPTransport ); 332 333 DLOG ( ( "-~FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) ); 334 335} 336 337 338#if 0 339#pragma mark - 340#pragma mark Public Methods 341#pragma mark - 342#endif 343 344//----------------------------------------------------------------------------- 345// init - Called by IOKit to initialize us. [PUBLIC] 346//----------------------------------------------------------------------------- 347 348bool 349IOFireWireSerialBusProtocolTransport::init ( OSDictionary * propTable ) 350{ 351 352 fDeferRegisterService = true; 353 return super::init ( propTable ); 354 355} 356 357 358//----------------------------------------------------------------------------- 359// start - Called by IOKit to start our services. [PUBLIC] 360//----------------------------------------------------------------------------- 361 362bool 363IOFireWireSerialBusProtocolTransport::start ( IOService * provider ) 364{ 365 366 IOReturn status = kIOReturnSuccess; 367 bool returnValue = false; 368 bool openSucceeded = false; 369 OSNumber * number = NULL; 370 OSDictionary * dict = NULL; 371 372 // See if there is a read time out duration passed in the property dictionary - if not 373 // set the default to 30 seconds. 374 number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) ); 375 if ( number == NULL ) 376 { 377 378 number = OSNumber::withNumber ( kDefaultTimeOutValue, 32 ); 379 require ( number, exit ); 380 381 setProperty ( kIOPropertyReadTimeOutDurationKey, number ); 382 number->release ( ); 383 384 number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) ); 385 386 } 387 388 DLOG ( ( "%s: start read time out = %ld\n", getName ( ), number->unsigned32BitValue ( ) ) ); 389 390 // See if there is a write time out duration passed in the property dictionary - if not 391 // set the default to 30 seconds. 392 number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyWriteTimeOutDurationKey ) ); 393 if ( number == NULL ) 394 { 395 396 number = OSNumber::withNumber ( kDefaultTimeOutValue, 32 ); 397 require ( number, exit ); 398 399 setProperty ( kIOPropertyWriteTimeOutDurationKey, number ); 400 number->release ( ); 401 402 number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyWriteTimeOutDurationKey ) ); 403 404 } 405 406 DLOG ( ( "%s: start read time out = %ld\n", getName ( ), number->unsigned32BitValue ( ) ) ); 407 408 // Set the default maximum page table constraints for SBP2 409 // $$$ ( this should probably be moved down to SBP2 - ping Collin ) 410 411 setProperty ( kIOMaximumSegmentCountReadKey, kFWSBP2DefaultPageTableEntriesCount, 32 ); 412 setProperty ( kIOMaximumSegmentCountWriteKey, kFWSBP2DefaultPageTableEntriesCount, 32 ); 413 414 setProperty ( kIOMaximumSegmentByteCountReadKey, kFWSBP2MaxPageClusterSize, 32 ); 415 setProperty ( kIOMaximumSegmentByteCountWriteKey, kFWSBP2MaxPageClusterSize, 32 ); 416 417 fSBPTarget = OSDynamicCast ( IOFireWireSBP2LUN, provider ); 418 require ( fSBPTarget, exit ); 419 420 // Add a retain here so we can keep IOFireWireSBP2LUN from doing garbage collection on us 421 // when we are in the middle of our finalize method. 422 423 fSBPTarget->retain ( ); 424 425 openSucceeded = super::start ( provider ); 426 require ( openSucceeded, exit ); 427 428 openSucceeded = provider->open ( this ); 429 require ( openSucceeded, exit ); 430 431 fUnit = fSBPTarget->getFireWireUnit ( ); 432 require ( fUnit, exit ); 433 434 // Explicitly set the "enable retry on ack d" flag. 435 fUnit->setNodeFlags ( kIOFWEnableRetryOnAckD ); 436 437 number = OSDynamicCast ( OSNumber, getProperty ( kFireWireGUIDKey, gIOServicePlane ) ); 438 if ( number != NULL ) 439 { 440 441 UInt64 GUID = 0; 442 443 GUID = number->unsigned64BitValue ( ); 444 445 RecordFireWireTimeStamp ( 446 FW_TRACE ( kGUID ), 447 ( uintptr_t ) this, 448 ( unsigned int ) ( ( GUID >> 32 ) & 0xFFFFFFFF ), 449 ( unsigned int ) ( GUID & 0xFFFFFFFF ), 450 0 ); 451 452 } 453 454 status = AllocateResources ( ); 455 require_noerr ( status, exit ); 456 457 // Get us on the workloop so we can sleep the start thread. 458 fCommandGate->runAction ( ConnectToDeviceStatic ); 459 460 if ( reserved->fLoginState == kLogginSucceededState ) 461 { 462 registerService ( ); 463 } 464 465 DLOG ( ( "%s: start complete\n", getName ( ) ) ); 466 467 returnValue = true; 468 469 // Copy some values to the Protocol Characteristics Dictionary. 470 dict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertyProtocolCharacteristicsKey ) ); 471 if ( dict != NULL ) 472 { 473 474 OSDictionary * protocolDict = NULL; 475 OSString * string = NULL; 476 477 // Make a copy of the existing Protocol Characteristics Dictionary to Modify. 478 protocolDict = OSDictionary::withDictionary ( dict ); 479 check ( protocolDict ); 480 481 string = OSString::withCString ( kFireWireGUIDKey ); 482 if ( string != NULL ) 483 { 484 485 protocolDict->setObject ( string, getProperty ( kFireWireGUIDKey, gIOServicePlane ) ); 486 string->release ( ); 487 string = NULL; 488 489 } 490 491 string = OSString::withCString ( kPreferredNameKey ); 492 if ( string != NULL ) 493 { 494 495 protocolDict->setObject ( kPreferredNameKey, getProperty ( kFireWireVendorNameKey, gIOServicePlane ) ); 496 string->release ( ); 497 string = NULL; 498 499 } 500 501 // Replace the existing Protocol Characteristics Dictionary with our new one. 502 setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict ); 503 protocolDict->release ( ); 504 protocolDict = NULL; 505 506 } 507 508 // False by default. 509 reserved->fAutonomousSpinDownWorkAround = false; 510 511 if ( ( getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ) != NULL ) 512 { 513 514 OSDictionary * characterDict = NULL; 515 516 517 characterDict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ); 518 if ( characterDict->getObject ( kIOPropertyAutonomousSpinDownKey ) != NULL ) 519 { 520 521 reserved->fAutonomousSpinDownWorkAround = true; 522 523 } 524 525 } 526 527 if ( ( getProperty ( kDontUsePTPacketLimitKey ) ) != NULL ) 528 { 529 530 IOFireWireSBP2Target * target = NULL; 531 532 target = OSDynamicCast ( IOFireWireSBP2Target, fSBPTarget->getProvider( ) ); 533 534 if ( target != NULL ) 535 { 536 target->setTargetFlags ( kIOFWSBP2DontUsePTPacketLimit ); 537 } 538 539 } 540 541 InitializePowerManagement ( provider ); 542 543 544exit: 545 546 547 if ( returnValue == false ) 548 { 549 550 DLOG ( ( "%s: start failed. status = %x\n", getName ( ), status) ); 551 552 // Call the cleanUp method to clean up any allocated resources. 553 cleanUp ( ); 554 555 } 556 557 return returnValue; 558 559} 560 561 562//----------------------------------------------------------------------------- 563// cleanUp - This is misleadingly named due to binary compatibility burdens. 564// The cleanUp method actually just closes the SBP2LUN. fSBPTarget 565// is actually a SBP2LUN object. [PUBLIC] 566//----------------------------------------------------------------------------- 567 568void 569IOFireWireSerialBusProtocolTransport::cleanUp ( void ) 570{ 571 572 DLOG ( ( "%s: cleanUp called\n", getName ( ) ) ); 573 574 if ( fSBPTarget != NULL ) 575 { 576 577 // Close SBP2 if we have opened it. 578 if ( fSBPTarget->isOpen ( this ) ) 579 { 580 581 OSNumber * number = NULL; 582 583 number = OSDynamicCast ( OSNumber, getProperty ( kFireWireGUIDKey, gIOServicePlane ) ); 584 if ( number != NULL ) 585 { 586 587 UInt64 GUID = 0; 588 589 GUID = number->unsigned64BitValue ( ); 590 591 RecordFireWireTimeStamp ( 592 FW_TRACE ( kGUID ), 593 ( uintptr_t ) this, 594 ( unsigned int ) ( ( GUID >> 32 ) & 0xFFFFFFFF ), 595 ( unsigned int ) ( GUID & 0xFFFFFFFF ), 596 1 ); 597 598 } 599 600 fSBPTarget->close ( this ); 601 602 } 603 604 } 605 606} 607 608 609//----------------------------------------------------------------------------- 610// finalize - Terminates all power management. [PROTECTED] 611//----------------------------------------------------------------------------- 612 613bool 614IOFireWireSerialBusProtocolTransport::finalize ( IOOptionBits options ) 615{ 616 617 DeallocateResources ( ); 618 619 // Release the retain we took to keep IOFireWireSBP2LUN from doing garbage collection on us 620 // when we are in the middle of DeallocateResources. 621 if ( fSBPTarget != NULL ) 622 { 623 624 fSBPTarget->release ( ); 625 fSBPTarget = NULL; 626 627 } 628 629 return super::finalize ( options ); 630 631} 632 633 634//----------------------------------------------------------------------------- 635// free - Called to deallocate ExpansionData. [PUBLIC] 636//----------------------------------------------------------------------------- 637 638void 639IOFireWireSerialBusProtocolTransport::free ( void ) 640{ 641 642 if ( reserved != NULL ) 643 { 644 645 if ( reserved->fCommandPool != NULL ) 646 { 647 648 reserved->fCommandPool->release ( ); 649 reserved->fCommandPool = NULL; 650 651 } 652 653 IOFree ( reserved, sizeof ( ExpansionData ) ); 654 reserved = NULL; 655 656 } 657 658 super::free ( ); 659 660} 661 662 663#if 0 664#pragma mark - 665#pragma mark Protected Methods 666#pragma mark - 667#endif 668 669 670//----------------------------------------------------------------------------- 671// CommandORBAccessor - Retrieves command orb. [PROTECTED] 672//----------------------------------------------------------------------------- 673 674IOFireWireSBP2ORB * 675IOFireWireSerialBusProtocolTransport::CommandORBAccessor ( void ) 676{ 677 return fORB; 678} 679 680 681//----------------------------------------------------------------------------- 682// SBP2LoginAccessor - Retrieves login orb. [PROTECTED] 683//----------------------------------------------------------------------------- 684 685IOFireWireSBP2Login * 686IOFireWireSerialBusProtocolTransport::SBP2LoginAccessor ( void ) 687{ 688 return fLogin; 689} 690 691 692//----------------------------------------------------------------------------- 693// message - Called by IOKit to deliver messages. [PROTECTED] 694//----------------------------------------------------------------------------- 695 696IOReturn 697IOFireWireSerialBusProtocolTransport::message ( 698 UInt32 type, 699 IOService * nub, 700 void * arg ) 701{ 702 703 IOFireWireSBP2ORB * orb = NULL; 704 SBP2ClientOrbData * clientData = NULL; 705 IOReturn status = kIOReturnSuccess; 706 707 switch ( type ) 708 { 709 710 case kIOMessageServiceIsSuspended: 711 { 712 713 DLOG ( ( "%s: kIOMessageServiceIsSuspended\n", getName ( ) ) ); 714 715 // Bus reset started - set flag to stop submitting orbs. 716 fLoggedIn = false; 717 718 } 719 break; 720 721 case kIOMessageServiceIsResumed: 722 { 723 724 DLOG ( ( "%s: kIOMessageServiceIsResumed\n", getName ( ) ) ); 725 726 // Bus reset finished - if we have failed to log in previously, try again. 727 if ( fNeedLogin == true ) 728 { 729 730 fNeedLogin = false; 731 fLoginRetryCount = 0; 732 733 // In case we are resumed after a terminate. 734 if ( fLogin != NULL ) 735 { 736 737 login ( ); 738 739 } 740 741 } 742 743 } 744 break; 745 746 case kIOMessageFWSBP2ReconnectComplete: 747 { 748 749 // As of this writing FireWireSBP2LUN will message all multi-LUN instances with this 750 // message. So qualify this message with our instance variable fLogin and ignore others. 751 if ( ( ( FWSBP2ReconnectParams * ) arg )->login == fLogin ) 752 { 753 754 DLOG ( ( "%s: kIOMessageFWSBP2ReconnectComplete\n", getName ( ) ) ); 755 756 fLoggedIn = true; 757 758 if ( fReconnectCount < kMaxReconnectCount) 759 { 760 761 DLOG ( ( "%s: resubmit orb \n", getName ( ) ) ); 762 fReconnectCount++; 763 submitOrbFromQueue ( ); 764 765 } 766 767 else 768 { 769 770 // Unable to recover from bus reset storm. We have exhausted the 771 // fReconnectCount - punt... 772 773 if ( fORB != NULL ) 774 { 775 776 clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ( ); 777 if ( clientData != NULL ) 778 { 779 780 clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 781 clientData->taskStatus = kSCSITaskStatus_DeliveryFailure; 782 CompleteSCSITask ( fORB ); 783 784 } 785 786 } 787 788 } 789 790 } 791 792 } 793 break; 794 795 case kIOMessageFWSBP2ReconnectFailed: 796 { 797 798 // As of this writing FireWireSBP2LUN will message all multi-LUN instances with this 799 // message. So qualify this message with our instance variable fLogin and ignore others. 800 if ( ( ( FWSBP2ReconnectParams * ) arg )->login == fLogin ) 801 { 802 803 DLOG ( ( "%s: kIOMessageFWSBP2ReconnectFailed\n", getName ( ) ) ); 804 805 // Try to reestablish log in. 806 fLoginRetryCount = 0; 807 login ( ); 808 809 } 810 811 } 812 break; 813 814 case kIOFireWireMessageServiceIsRequestingClose: 815 { 816 817 DLOG ( ( "%s: kIOFireWireMessageServiceIsRequestingClose\n", getName ( ) ) ); 818 819 // Tell our super to message it's clients that the device is gone. 820 821 SendNotification_DeviceRemoved ( ); 822 823 // We need to drain the queued commands. See if there is an in flight orb (e.g. fORB) 824 // if not pull the first one out of the submit queue if there are any. 825 826 orb = fORB; 827 828 do 829 { 830 831 if ( orb != NULL ) 832 { 833 834 clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( ); 835 if ( clientData != NULL ) 836 { 837 838 if ( clientData->scsiTask != NULL ) 839 { 840 841 clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 842 clientData->taskStatus = kSCSITaskStatus_DeviceNotPresent; 843 CompleteSCSITask ( orb ); 844 845 } 846 847 } 848 849 } 850 851 } while ( ( orb = ( IOFireWireSBP2ORB * ) reserved->fSubmitQueue->getCommand ( false ) ) ); 852 853 cleanUp ( ); 854 855 } 856 break; 857 858 case kIOMessageServiceIsTerminated: 859 { 860 861 DLOG ( ( "%s: kIOMessageServiceIsTerminated\n", getName ( ) ) ); 862 // Let go of memory and what not. 863 cleanUp ( ); 864 865 } 866 break; 867 868 default: 869 { 870 871 status = IOService::message ( type, nub, arg ); 872 873 } 874 break; 875 876 } 877 878 return status; 879 880} 881 882 883//----------------------------------------------------------------------------- 884// SendSCSICommand - Converts a SCSITask to an ORB. [PROTECTED] 885//----------------------------------------------------------------------------- 886 887bool 888IOFireWireSerialBusProtocolTransport::SendSCSICommand ( 889 SCSITaskIdentifier request, 890 SCSIServiceResponse * serviceResponse, 891 SCSITaskStatus * taskStatus ) 892{ 893 894 SBP2ClientOrbData * clientData = NULL; 895 IOFireWireSBP2ORB * orb = NULL; 896 SCSICommandDescriptorBlock cdb = { 0 }; 897 UInt8 commandLength = 0; 898 UInt32 commandFlags = 0; 899 UInt32 timeOut = 0; 900 bool commandProcessed = false; 901 902 DLOG ( ( "%s: SendSCSICommand called\n", getName ( ) ) ); 903 904 *serviceResponse = kSCSIServiceResponse_Request_In_Process; 905 *taskStatus = kSCSITaskStatus_No_Status; 906 907 if ( isInactive ( ) == true ) 908 { 909 910 // Device is disconnected - we can not service command requests. 911 *serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 912 commandProcessed = true; 913 goto exit; 914 915 } 916 917 // Get an orb from our orb pool and do not block until we get one. 918 orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false ); 919 require ( orb, exit ); 920 921 GetCommandDescriptorBlock ( request, &cdb ); 922 923 RecordFireWireTimeStamp ( 924 FW_TRACE ( kSendSCSICommand1 ), 925 ( uintptr_t ) this, 926 ( uintptr_t ) request, 927 cdb[0] | ( cdb[1] << 8 ) | ( cdb[2] << 16 ) | ( cdb[3] << 24 ), 928 cdb[4] | ( cdb[5] << 8 ) | ( cdb[6] << 16 ) | ( cdb[7] << 24 ) ); 929 930 RecordFireWireTimeStamp ( 931 FW_TRACE ( kSendSCSICommand2 ), 932 ( uintptr_t ) this, 933 ( uintptr_t ) request, 934 cdb[ 8] | ( cdb[ 9] << 8 ) | ( cdb[10] << 16 ) | ( cdb[11] << 24 ), 935 cdb[12] | ( cdb[13] << 8 ) | ( cdb[14] << 16 ) | ( cdb[15] << 24 ) ); 936 937 clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( ); 938 require ( clientData, exit ); 939 940 commandLength = GetCommandDescriptorBlockSize ( request ); 941 commandFlags = ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromTargetToInitiator ) ? 942 kFireWireSBP2CommandTransferDataFromTarget : 943 kFireWireSBP2CommandTransferDataToTarget; 944 945 orb->setCommandFlags ( commandFlags | 946 kFWSBP2CommandCompleteNotify | 947 kFWSBP2CommandImmediate | 948 kFWSBP2CommandNormalORB ); 949 950 require ( ( SetCommandBuffers ( orb, request ) == kIOReturnSuccess ), exit ); 951 952 orb->setCommandBlock ( cdb, commandLength ); 953 954 // SBP-2 needs a non-zero timeout to fire completion routines if timeout is not expressed 955 // default to 0xFFFFFFFF. 956 timeOut = GetTimeoutDuration ( request ); 957 if ( timeOut == 0 ) 958 { 959 timeOut = 0xFFFFFFFF; 960 } 961 962 orb->setCommandTimeout ( timeOut ); 963 964#if TRANSPORT_FAILURE_RETRIES 965 reserved->fLUNResetCount = 3; 966#endif 967 968 // Close the gate here to eliminate potenially rare double append of orb. If on a DP machine 969 // and a bus reset occurs the login thread can append the orb as well as here. 970 fCommandGate->runAction ( CriticalOrbSubmissionStatic, orb, request ); 971 commandProcessed = true; 972 973 974exit: 975 976 977 DLOG ( ( "%s: SendSCSICommand exit, Service Response = %x\n", getName ( ), *serviceResponse ) ); 978 979 return commandProcessed; 980 981} 982 983 984//----------------------------------------------------------------------------- 985// SetCommandBuffers - Sets the command buffers in the ORB. [PROTECTED] 986//----------------------------------------------------------------------------- 987 988IOReturn 989IOFireWireSerialBusProtocolTransport::SetCommandBuffers ( 990 IOFireWireSBP2ORB * orb, 991 SCSITaskIdentifier request ) 992{ 993 994 SBP2ClientOrbData * clientData = NULL; 995 IOReturn status = kIOReturnError; 996 997 clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( ); 998 require ( clientData, Exit ); 999 1000 clientData->quadletAlignedBuffer = NULL; 1001 if ( GetDataBuffer ( request ) != NULL ) 1002 { 1003 1004 // Does this command require double buffering in order to ensure quadlet alignment? 1005 if ( ( GetDataBuffer ( request )->getLength ( ) < kDoubleBufferCommandSizeCheckThreshold ) && 1006 ( ( GetDataBuffer ( request )->getLength ( ) & 3 ) != 0 ) ) 1007 { 1008 1009 // Create quadlet aligned IOBufferMemoryDescriptor, to be released in CompleteSCSITask(). 1010 clientData->quadletAlignedBuffer = IOBufferMemoryDescriptor::withOptions ( 1011 kIODirectionOutIn, 1012 GetDataBuffer ( request )->getLength ( ), 1013 4 ); 1014 1015 require ( clientData->quadletAlignedBuffer, Exit ); 1016 1017 // If necessary copy data from the non-aligned buffer to the aligned buffer. 1018 if ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 1019 { 1020 1021 GetDataBuffer ( request )->readBytes ( GetDataBufferOffset ( request ), 1022 clientData->quadletAlignedBuffer->getBytesNoCopy ( ), 1023 GetDataBuffer ( request )->getLength ( ) ); 1024 1025 } 1026 1027 status = orb->setCommandBuffers ( clientData->quadletAlignedBuffer, 1028 GetDataBufferOffset ( request ), 1029 GetRequestedDataTransferCount ( request ) ); 1030 1031 require_success ( status, Exit ); 1032 1033 } 1034 1035 } 1036 1037 if ( clientData->quadletAlignedBuffer == NULL ) 1038 { 1039 1040 status = orb->setCommandBuffers ( GetDataBuffer ( request ), 1041 GetDataBufferOffset ( request ), 1042 GetRequestedDataTransferCount ( request ) ); 1043 1044 } 1045 1046 1047Exit: 1048 1049 1050 return status; 1051 1052} 1053 1054 1055//----------------------------------------------------------------------------- 1056// CompleteSCSITask - Completes a task. [PROTECTED] 1057//----------------------------------------------------------------------------- 1058 1059void 1060IOFireWireSerialBusProtocolTransport::CompleteSCSITask ( IOFireWireSBP2ORB * orb ) 1061{ 1062 1063 SBP2ClientOrbData * clientData = NULL; 1064 1065 DLOG ( ( "%s: CompleteSCSITask called\n", getName ( ) ) ); 1066 1067 clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( ); 1068 if ( clientData != NULL ) 1069 { 1070 1071 if ( clientData->scsiTask != NULL ) 1072 { 1073 1074 SCSITaskIdentifier scsiTask = NULL; 1075 SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 1076 SCSITaskStatus taskStatus = kSCSITaskStatus_No_Status; 1077 IOByteCount bytesTransfered = 0; 1078 1079 // /!\ WARNING - because SBP-2 can send status information at different 1080 // stage of an orb's life ( or send none at all ) the caller of this routine 1081 // has determined that the orb is indeed done. So we need to explicitly tell 1082 // SBP-2 to let go of the buffer reference by calling releaseCommandBuffers. 1083 orb->releaseCommandBuffers ( ); 1084 1085 if ( clientData->taskStatus == kSCSITaskStatus_GOOD ) 1086 { 1087 bytesTransfered = GetRequestedDataTransferCount ( clientData->scsiTask ); 1088 } 1089 1090 SetRealizedDataTransferCount ( clientData->scsiTask, bytesTransfered ); 1091 1092 // Did we double buffer this command to ensure quadlet alignment? 1093 // If so, copy over memory if necessary. 1094 if ( clientData->quadletAlignedBuffer != NULL ) 1095 { 1096 1097 if ( GetDataTransferDirection ( clientData->scsiTask ) == kSCSIDataTransfer_FromTargetToInitiator ) 1098 { 1099 1100 GetDataBuffer ( clientData->scsiTask )->writeBytes ( 1101 GetDataBufferOffset ( clientData->scsiTask ), 1102 clientData->quadletAlignedBuffer->getBytesNoCopy ( ), 1103 clientData->quadletAlignedBuffer->getLength ( ) ); 1104 1105 } 1106 1107 clientData->quadletAlignedBuffer->release ( ); 1108 clientData->quadletAlignedBuffer = NULL; 1109 1110 } 1111 1112 // Re-entrancy protection. 1113 scsiTask = clientData->scsiTask; 1114 serviceResponse = clientData->serviceResponse; 1115 taskStatus = clientData->taskStatus; 1116 clientData->scsiTask = NULL; 1117 fORB = NULL; 1118 1119 submitOrbFromQueue ( ); 1120 1121 reserved->fCommandPool->returnCommand ( orb ); 1122 1123 RecordFireWireTimeStamp ( 1124 FW_TRACE ( kCompleteSCSICommand ), 1125 ( uintptr_t ) this, 1126 ( uintptr_t ) scsiTask, 1127 ( serviceResponse << 8 ) | taskStatus ); 1128 1129 CommandCompleted ( scsiTask, serviceResponse, taskStatus ); 1130 1131 } 1132 1133 } 1134 1135} 1136 1137 1138//----------------------------------------------------------------------------- 1139// AbortSCSICommand - Aborts an outstanding I/O. [PROTECTED] 1140//----------------------------------------------------------------------------- 1141 1142SCSIServiceResponse 1143IOFireWireSerialBusProtocolTransport::AbortSCSICommand ( SCSITaskIdentifier request ) 1144{ 1145 1146 SCSIServiceResponse serviceResponse; 1147 1148 DEBUG_UNUSED ( request ); 1149 1150 DLOG ( ( "%s: AbortSCSICommand called\n", getName ( ) ) ); 1151 1152 serviceResponse = kSCSIServiceResponse_FUNCTION_REJECTED; 1153 1154 return serviceResponse; 1155 1156} 1157 1158 1159//----------------------------------------------------------------------------- 1160// IsProtocolServiceSupported - Checks for protocol services supported by 1161// this device. [PROTECTED] 1162//----------------------------------------------------------------------------- 1163 1164bool 1165IOFireWireSerialBusProtocolTransport::IsProtocolServiceSupported ( 1166 SCSIProtocolFeature feature, 1167 void * serviceValue ) 1168{ 1169 1170 bool isSupported = false; 1171 OSDictionary * characterDict = NULL; 1172 1173 characterDict = OSDynamicCast ( OSDictionary, ( getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ) ); 1174 1175 DLOG ( ( "IOFireWireSerialBusProtocolTransport::IsProtocolServiceSupported called\n" ) ); 1176 1177 switch ( feature ) 1178 { 1179 1180 case kSCSIProtocolFeature_CPUInDiskMode: 1181 { 1182 1183 isSupported = IsDeviceCPUInDiskMode ( ); 1184 1185 } 1186 break; 1187 1188 case kSCSIProtocolFeature_MaximumReadBlockTransferCount: 1189 { 1190 1191 OSNumber * number = NULL; 1192 1193 // Start with our default value. 1194 * ( ( UInt32 * ) serviceValue ) = kDefaultIOBlockCount; 1195 1196 if ( characterDict != NULL ) 1197 { 1198 1199 number = OSDynamicCast ( OSNumber, characterDict->getObject ( kIOMaximumByteCountReadKey ) ); 1200 if ( number != NULL ) 1201 { 1202 *( ( UInt32 * ) serviceValue ) = number->unsigned32BitValue ( ); 1203 } 1204 1205 } 1206 1207 isSupported = true; 1208 1209 } 1210 break; 1211 1212 case kSCSIProtocolFeature_MaximumWriteBlockTransferCount: 1213 { 1214 1215 OSNumber * number = NULL; 1216 1217 // Start with our default value. 1218 * ( ( UInt32 * ) serviceValue ) = kDefaultIOBlockCount; 1219 1220 if ( characterDict != NULL ) 1221 { 1222 1223 number = OSDynamicCast ( OSNumber, characterDict->getObject ( kIOMaximumBlockCountWriteKey ) ); 1224 if ( number != NULL ) 1225 { 1226 *( ( UInt32 * ) serviceValue ) = number->unsigned32BitValue ( ); 1227 } 1228 1229 } 1230 1231 isSupported = true; 1232 1233 } 1234 break; 1235 1236 case kSCSIProtocolFeature_MaximumReadTransferByteCount: 1237 { 1238 1239 OSNumber * number = NULL; 1240 1241 // If the property SBP2ReceiveBufferByteCount exists we have a FireWire host 1242 // with the physical unit off and there is a software FIFO. ( i.e. Lynx ) 1243 // We should tell clients to deblock on the SBP2ReceiveBufferByteCount. 1244 // bounds to avoid stalled I/O. 1245 number = OSDynamicCast ( 1246 OSNumber, 1247 getProperty ( kSBP2ReceiveBufferByteCountKey, gIOServicePlane ) ); 1248 1249 if ( number != NULL ) 1250 { 1251 1252 * ( ( UInt64 * ) serviceValue ) = number->unsigned32BitValue ( ); 1253 isSupported = true; 1254 1255 } 1256 1257 } 1258 break; 1259 1260 case kSCSIProtocolFeature_GetMaximumLogicalUnitNumber: 1261 { 1262 1263 * ( ( UInt32 * ) serviceValue ) = kMaxFireWireLUN; 1264 isSupported = true; 1265 1266 } 1267 break; 1268 1269 case kSCSIProtocolFeature_ProtocolAlwaysReportsAutosenseData: 1270 { 1271 1272 isSupported = true; 1273 1274 } 1275 break; 1276 1277 case kSCSIProtocolFeature_ProtocolSpecificPowerControl: 1278 { 1279 1280 if ( reserved->fAutonomousSpinDownWorkAround == true ) 1281 { 1282 isSupported = true; 1283 } 1284 1285 } 1286 break; 1287 1288 default: 1289 { 1290 1291 isSupported = false; 1292 1293 } 1294 break; 1295 1296 } 1297 1298 return isSupported; 1299 1300} 1301 1302 1303//----------------------------------------------------------------------------- 1304// HandleProtocolServiceFeature - Handles protocol service features. 1305// [PROTECTED] 1306//----------------------------------------------------------------------------- 1307 1308bool 1309IOFireWireSerialBusProtocolTransport::HandleProtocolServiceFeature ( 1310 SCSIProtocolFeature feature, 1311 void * serviceValue ) 1312{ 1313 1314 bool returnValue = false; 1315 1316 switch ( feature ) 1317 { 1318 1319 case kSCSIProtocolFeature_ProtocolSpecificPowerControl: 1320 { 1321 1322 // This a workaround for devices which spin themselves up/down and can't 1323 // properly handle START_STOP commands from the host when the drive is 1324 // already in the requested state. 1325 if ( reserved->fAutonomousSpinDownWorkAround == true ) 1326 { 1327 1328 // This essentially NOPs the spin up/down request. 1329 returnValue = true; 1330 1331 } 1332 1333 } 1334 break; 1335 1336 default: 1337 { 1338 1339 returnValue = false; 1340 1341 } 1342 break; 1343 1344 } 1345 1346 return returnValue; 1347 1348} 1349 1350 1351//----------------------------------------------------------------------------- 1352// IsDeviceCPUInDiskMode - Checks if device is a CPU in FireWire Target 1353// Disk Mode. [PROTECTED] 1354//----------------------------------------------------------------------------- 1355 1356bool 1357IOFireWireSerialBusProtocolTransport::IsDeviceCPUInDiskMode ( void ) 1358{ 1359 1360 UInt32 csrModelInfo = 0;; 1361 IOConfigDirectory * directory = NULL; 1362 IOFireWireDevice * device = NULL; 1363 IOReturn status = kIOReturnSuccess; 1364 bool isCPUDiskMode = false; 1365 1366 1367 DLOG ( ( "%s: IsDeviceCPUInDiskMode was called\n", getName ( ) ) ); 1368 1369 device = OSDynamicCast ( IOFireWireDevice, fUnit->getProvider ( ) ); 1370 require ( device, Exit ); 1371 1372 status = device->getConfigDirectory ( directory ); 1373 require_success ( status, Exit ); 1374 1375 status = directory->getKeyValue ( kCSRModelInfoKey, csrModelInfo ); 1376 require_success ( status, Exit ); 1377 1378 if ( ( csrModelInfo & kCRSModelInfo_ValidBitsMask ) == kCRSModelInfo_TargetDiskMode ) 1379 { 1380 isCPUDiskMode = true; 1381 } 1382 1383 1384Exit: 1385 1386 1387 DLOG ( ( "%s: CPU Disk Mode = %d\n", getName ( ), isCPUDiskMode ) ); 1388 1389 return isCPUDiskMode; 1390 1391} 1392 1393 1394//----------------------------------------------------------------------------- 1395// StatusNotifyStatic - C->C++ glue method. [PROTECTED] 1396//----------------------------------------------------------------------------- 1397 1398void 1399IOFireWireSerialBusProtocolTransport::StatusNotifyStatic ( 1400 void * refCon, 1401 FWSBP2NotifyParams * params ) 1402{ 1403 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->StatusNotify ( params ); 1404} 1405 1406 1407//----------------------------------------------------------------------------- 1408// StatusNotify - Status notify handler. [PROTECTED] 1409//----------------------------------------------------------------------------- 1410 1411void 1412IOFireWireSerialBusProtocolTransport::StatusNotify ( FWSBP2NotifyParams * params ) 1413{ 1414 1415 IOFireWireSBP2ORB * orb = NULL; 1416 FWSBP2StatusBlock * statusBlock = NULL; 1417 SBP2ClientOrbData * clientData = NULL; 1418 SCSI_Sense_Data * targetData = NULL; 1419 UInt8 senseData[kSenseDefaultSize + 8] = { 0 }; 1420 1421 targetData = ( SCSI_Sense_Data * ) &senseData [ 0 ]; 1422 1423 if ( ( params->message != NULL ) && ( params->length != 0 ) ) 1424 { 1425 statusBlock = ( FWSBP2StatusBlock * ) params->message; 1426 } 1427 1428 orb = ( IOFireWireSBP2ORB * ) params->commandObject; 1429 if ( orb != NULL ) 1430 { 1431 clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( ); 1432 } 1433 1434 RecordFireWireTimeStamp ( 1435 FW_TRACE ( kStatusNotify ), 1436 ( uintptr_t ) this, 1437 ( uintptr_t ) orb, 1438 params->notificationEvent ); 1439 1440 switch ( params->notificationEvent ) 1441 { 1442 1443 case kFWSBP2NormalCommandStatus: 1444 { 1445 1446 if ( clientData != NULL ) 1447 { 1448 1449 // Read the status block details bits. See SBP-2 spec section 5.3. 1450 // Check the dead bit ( i.e. that the 'd' field == 1 ). 1451 if ( statusBlock->details & kSBP2StatusBlock_Details_DeadMask ) 1452 { 1453 1454 SetValidAutoSenseData ( clientData, statusBlock, targetData ); 1455 1456 // Wait for fetch agent to reset before calling CompleteSCSITask which will 1457 // be called in FetchAgentResetComplete. 1458 RecordFireWireTimeStamp ( 1459 FW_TRACE ( kFetchAgentReset ), 1460 ( uintptr_t ) this, 1461 ( uintptr_t ) orb ); 1462 1463 fLogin->submitFetchAgentReset ( ); 1464 1465 } 1466 1467 else if ( ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) && 1468 ( statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_FunctionRejected ) ) 1469 { 1470 1471 SetValidAutoSenseData ( clientData, statusBlock, targetData ); 1472 1473 // Complete the SCSI request without a retry for devices that return a 1474 // SBP function rejected status but in actuality have successfully 1475 // processed the SCSI request with a CHECK condition 1476 // and have valid sense data. 1477 // 1478 // Certain Oxford 911 based devices seem to fall under this category 1479 1480 if ( clientData->taskStatus == kSCSITaskStatus_CHECK_CONDITION ) 1481 { 1482 1483 CompleteSCSITask ( orb ); 1484 1485 } 1486 1487 else 1488 { 1489 1490 clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 1491 clientData->taskStatus = kSCSITaskStatus_DeviceNotResponding; 1492 1493 reserved->fLUNResetPathFlag = true; 1494 fLUNResetORB->submit ( ); 1495 1496 } 1497 1498 } 1499 1500 else if ( ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) && 1501 ( ( statusBlock->details & kSBP2StatusBlock_Details_LenMask ) == 1 ) && 1502 ( statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_NoAdditionalInformation ) ) 1503 { 1504 1505 clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE; 1506 clientData->taskStatus = kSCSITaskStatus_GOOD; 1507 1508 CompleteSCSITask ( orb ); 1509 1510 DLOG ( ( "%s: StatusNotify normal complete \n", getName ( ) ) ); 1511 1512 } 1513 1514 else 1515 { 1516 1517 SetValidAutoSenseData ( clientData, statusBlock, targetData ); 1518 CompleteSCSITask ( orb ); 1519 1520 DLOG ( ( "%s: StatusNotify have sense data or an unexpected error? \n", getName ( ) ) ); 1521 1522 } 1523 1524 } 1525 1526 } 1527 break; 1528 1529 case kFWSBP2NormalCommandTimeout: 1530 { 1531 1532 DLOG ( ( "%s: kFWSBP2NormalCommandTimeout \n", getName ( ) ) ); 1533 1534 if ( clientData != NULL ) 1535 { 1536 1537 if ( clientData->scsiTask != NULL ) 1538 { 1539 1540 clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 1541 clientData->taskStatus = kSCSITaskStatus_ProtocolTimeoutOccurred; 1542 1543 } 1544 1545 } 1546 1547 // Set flag so FetchAgentReset knows it is being called from a timeout path. 1548 // reserved->fLUNResetPathFlag = true; 1549 1550 RecordFireWireTimeStamp ( 1551 FW_TRACE ( kLogicalUnitReset ), 1552 ( uintptr_t ) this, 1553 ( uintptr_t ) fLUNResetORB ); 1554 1555 // We reset the LUN as good measure in case device is wedged. The LUN reset completion 1556 // handler will call the fetch agent to be reset. The FetchAgentReset completion handler 1557 // will call CompleteSCSITask() and complete the command with the approrpiate task status. 1558 fLUNResetORB->submit ( ); 1559 1560 } 1561 break; 1562 1563 case kFWSBP2NormalCommandReset: 1564 { 1565 1566 DLOG ( ( "%s: kFWSBP2NormalCommandReset\n", getName ( ) ) ); 1567 1568 // kFWSBP2NormalCommandReset - is a misleading definition. A pending command has 1569 // failed so we need notify the upper layers to complete failed command. 1570 1571 if ( clientData != NULL ) 1572 { 1573 1574 if ( clientData->scsiTask != NULL ) 1575 { 1576 1577 clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 1578 clientData->taskStatus = kSCSITaskStatus_DeliveryFailure; 1579 1580 CompleteSCSITask ( orb ); 1581 1582 } 1583 1584 } 1585 1586 } 1587 break; 1588 1589 default: 1590 { 1591 DLOG ( ( "%s: StatusNotify with unknown notificationEvent\n", getName ( ) ) ); 1592 } 1593 break; 1594 1595 } 1596 1597} 1598 1599 1600//----------------------------------------------------------------------------- 1601// SetValidAutoSenseData - Sets any valid sense data. [PROTECTED] 1602//----------------------------------------------------------------------------- 1603 1604void 1605IOFireWireSerialBusProtocolTransport::SetValidAutoSenseData ( 1606 SBP2ClientOrbData * clientData, 1607 FWSBP2StatusBlock * statusBlock, 1608 SCSI_Sense_Data * targetData ) 1609{ 1610 1611 UInt8 quadletCount = 0; 1612 1613 clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; 1614 clientData->taskStatus = kSCSITaskStatus_No_Status; 1615 1616 quadletCount = ( statusBlock->details & kSBP2StatusBlock_Details_LenMask ) - 1; 1617 1618 // See if we have any valid sense data. 1619 if ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) 1620 { 1621 1622 clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE; 1623 clientData->taskStatus = CoalesceSenseData ( statusBlock, quadletCount, targetData ); 1624 1625 } 1626 1627 if ( ( clientData->taskStatus == kSCSITaskStatus_CHECK_CONDITION ) || 1628 ( reserved->fAlwaysSetSenseData ) ) 1629 { 1630 1631 if ( clientData->scsiTask != NULL ) 1632 { 1633 SetAutoSenseData ( clientData->scsiTask, targetData, kSenseDefaultSize + 8 ); 1634 } 1635 1636 } 1637 1638 RecordFireWireTimeStamp ( 1639 FW_TRACE ( kSCSICommandSenseData ), 1640 ( uintptr_t ) this, 1641 ( uintptr_t ) clientData->scsiTask, 1642 targetData->SENSE_KEY & kSENSE_KEY_Mask, 1643 ( targetData->ADDITIONAL_SENSE_CODE << 8 ) | targetData->ADDITIONAL_SENSE_CODE_QUALIFIER ); 1644 1645} 1646 1647 1648//----------------------------------------------------------------------------- 1649// CoalesceSenseData - Sets sense data in the data buffer. [PROTECTED] 1650//----------------------------------------------------------------------------- 1651 1652SCSITaskStatus 1653IOFireWireSerialBusProtocolTransport::CoalesceSenseData ( 1654 FWSBP2StatusBlock * sourceData, 1655 UInt8 quadletCount, 1656 SCSI_Sense_Data * targetData ) 1657{ 1658 1659 SCSITaskStatus returnValue = kSCSITaskStatus_GOOD; 1660 UInt8 statusBlockFormat = 0; 1661 FWSBP2SCSIStatusBlock * scsiStatusBlock = NULL; 1662 1663 scsiStatusBlock = ( FWSBP2SCSIStatusBlock * ) sourceData; 1664 1665 // Pull bits out of SBP-2 status block ( see SBP-2 Annex B section B.2 ) 1666 // and copy them into sense data block ( see SPC-2 section 7.23.2 ) 1667 if ( quadletCount > 0 ) 1668 { 1669 1670 statusBlockFormat = scsiStatusBlock->status & kFWSBP2SCSIStatusBlock_StatusBlockFormatMask; 1671 returnValue = ( SCSITaskStatus ) ( scsiStatusBlock->status & kFWSBP2SCSIStatusBlock_StatusBlockStatusMask ); 1672 1673 if ( statusBlockFormat == kFWSBP2SCSIStatusBlock_StatusBlockFormatCurrentError ) 1674 { 1675 targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Current_Errors; 1676 } 1677 1678 else if ( statusBlockFormat == kFWSBP2SCSIStatusBlock_StatusBlockFormatDeferredError ) 1679 { 1680 targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Deferred_Errors; 1681 } 1682 1683 if ( statusBlockFormat < 2 ) 1684 { 1685 1686 targetData->VALID_RESPONSE_CODE |= ( scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_VALID_Mask ); 1687 targetData->ADDITIONAL_SENSE_CODE = scsiStatusBlock->ASC; 1688 targetData->ADDITIONAL_SENSE_CODE_QUALIFIER = scsiStatusBlock->ASCQ; 1689 targetData->SENSE_KEY = scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_SenseKeyMask; 1690 1691 // Set the M, E, I bits: M->FileMark, E->EOM, I->ILI. 1692 targetData->SENSE_KEY |= ( scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_MEI_Mask ) << 1; 1693 1694 if ( quadletCount > 1 ) 1695 { 1696 1697 scsiStatusBlock->information = OSSwapBigToHostInt32 ( scsiStatusBlock->information ); 1698 1699 targetData->INFORMATION_1 = ( scsiStatusBlock->information >> 24 ) & 0xFF; 1700 targetData->INFORMATION_2 = ( scsiStatusBlock->information >> 16 ) & 0xFF; 1701 targetData->INFORMATION_3 = ( scsiStatusBlock->information >> 8 ) & 0xFF; 1702 targetData->INFORMATION_4 = scsiStatusBlock->information & 0xFF; 1703 targetData->ADDITIONAL_SENSE_LENGTH = 6; 1704 1705 } 1706 1707 if ( quadletCount > 2 ) 1708 { 1709 1710 scsiStatusBlock->commandSpecificInformation = OSSwapBigToHostInt32 ( scsiStatusBlock->commandSpecificInformation ); 1711 1712 targetData->COMMAND_SPECIFIC_INFORMATION_1 = ( scsiStatusBlock->commandSpecificInformation >> 24 ) & 0xFF; 1713 targetData->COMMAND_SPECIFIC_INFORMATION_2 = ( scsiStatusBlock->commandSpecificInformation >> 16 ) & 0xFF; 1714 targetData->COMMAND_SPECIFIC_INFORMATION_3 = ( scsiStatusBlock->commandSpecificInformation >> 8 ) & 0xFF; 1715 targetData->COMMAND_SPECIFIC_INFORMATION_4 = scsiStatusBlock->commandSpecificInformation & 0xFF; 1716 targetData->ADDITIONAL_SENSE_LENGTH = 6; 1717 1718 } 1719 1720 if ( quadletCount > 3 ) 1721 { 1722 1723 UInt8 count = 0; 1724 1725 // Get bytes to copy and clip if greater than sizeof SCSI_Sense_Data. 1726 scsiStatusBlock->senseKeyDependent = OSSwapBigToHostInt32 ( scsiStatusBlock->senseKeyDependent ); 1727 1728 count = ( quadletCount - 3 ) * sizeof ( UInt32 ); 1729 if ( count > 4 ) 1730 count = 4; 1731 1732 bcopy ( &scsiStatusBlock->senseKeyDependent, 1733 &targetData->FIELD_REPLACEABLE_UNIT_CODE, 1734 count ); 1735 1736 targetData->ADDITIONAL_SENSE_LENGTH = count + 6; 1737 1738 } 1739 1740 } 1741 1742 } 1743 1744 return returnValue; 1745 1746} 1747 1748 1749//----------------------------------------------------------------------------- 1750// LoginCompletionStatic - C->C++ glue method. [PROTECTED] 1751//----------------------------------------------------------------------------- 1752 1753void 1754IOFireWireSerialBusProtocolTransport::LoginCompletionStatic ( 1755 void * refCon, 1756 FWSBP2LoginCompleteParams * params ) 1757{ 1758 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LoginCompletion ( params ); 1759} 1760 1761//----------------------------------------------------------------------------- 1762// LoginCompletion - Login completion handler. [PROTECTED] 1763//----------------------------------------------------------------------------- 1764 1765void 1766IOFireWireSerialBusProtocolTransport::LoginCompletion ( 1767 FWSBP2LoginCompleteParams * params ) 1768{ 1769 1770 DLOG ( ( "%s: LoginCompletion complete \n", getName ( ) ) ); 1771 1772 // If login failed, retry if we haven't already exceeded max retry count. 1773 require_success ( params->status, Retry ); 1774 1775 // We only have a valid SBP2 login params block if the login completed successfully. 1776 // Otherwise the block is NULL. 1777 require ( params->statusBlock, Retry ); 1778 1779 RecordFireWireTimeStamp ( 1780 FW_TRACE ( kLoginCompletion ), 1781 ( uintptr_t ) this, 1782 params->status, 1783 params->statusBlock->details, 1784 params->statusBlock->sbpStatus ); 1785 1786 if ( ( ( params->statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) && 1787 ( params->statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_NoAdditionalInformation ) ) 1788 { 1789 1790 fLoginRetryCount = 0; 1791 fLoggedIn = true; 1792 fNeedLogin = false; 1793 1794 if ( reserved->fLoginState == kFirstTimeLoggingInState ) 1795 { 1796 1797 reserved->fLoginState = kLogginSucceededState; 1798 fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState ); 1799 1800 } 1801 1802 submitOrbFromQueue ( ); 1803 1804 RecordFireWireTimeStamp ( FW_TRACE ( kLoginResumed ), ( uintptr_t ) this ); 1805 loginResumed ( ); 1806 1807 return; 1808 1809 } 1810 1811 1812Retry: 1813 1814 RecordFireWireTimeStamp ( 1815 FW_TRACE ( kLoginCompletion ), 1816 ( uintptr_t ) this, 1817 params->status, NULL, NULL ); 1818 1819 if ( fLoginRetryCount < kMaxLoginRetryCount ) 1820 { 1821 1822 IOReturn status = kIOReturnSuccess; 1823 1824 fLoginRetryCount++; 1825 1826 DLOG ( ( "%s: resubmitting Login\n", getName ( ) ) ); 1827 1828 status = login ( ); 1829 if ( status != kIOReturnSuccess ) 1830 { 1831 1832 if ( reserved->fLoginState == kFirstTimeLoggingInState ) 1833 { 1834 1835 reserved->fLoginState = kLogginFailedState; 1836 1837 // Wake up sleeping start thread. 1838 fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState ); 1839 1840 } 1841 1842 } 1843 1844 } 1845 1846 else 1847 { 1848 1849 // Device can not be logged into after kMaxLoginRetryCount attemptes let's reset 1850 // the need login flag in case the device was unplugged during login. 1851 1852 fNeedLogin = true; 1853 1854 RecordFireWireTimeStamp ( 1855 FW_TRACE ( kLoginLost ), 1856 ( uintptr_t ) this, 1857 reserved->fLoginState ); 1858 1859 loginLost ( ); 1860 1861 if ( reserved->fLoginState == kFirstTimeLoggingInState ) 1862 { 1863 1864 reserved->fLoginState = kLogginFailedState; 1865 1866 // Wake up sleeping start thread. 1867 fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState ); 1868 1869 } 1870 1871 } 1872 1873} 1874 1875 1876//----------------------------------------------------------------------------- 1877// LogoutCompletionStatic - C->C++ glue. [PROTECTED] 1878//----------------------------------------------------------------------------- 1879 1880void 1881IOFireWireSerialBusProtocolTransport::LogoutCompletionStatic ( 1882 void * refCon, 1883 FWSBP2LogoutCompleteParams * params ) 1884{ 1885 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LogoutCompletion ( params ); 1886} 1887 1888 1889//----------------------------------------------------------------------------- 1890// LogoutCompletion - Logout completion handler. [PROTECTED] 1891//----------------------------------------------------------------------------- 1892 1893void 1894IOFireWireSerialBusProtocolTransport::LogoutCompletion ( 1895 FWSBP2LogoutCompleteParams * params ) 1896{ 1897 1898 DEBUG_UNUSED ( params ); 1899 DLOG ( ( "%s: LogoutCompletion complete \n", getName ( ) ) ); 1900 1901} 1902 1903 1904//----------------------------------------------------------------------------- 1905// UnsolicitedStatusNotifyStatic - C->C++ glue. [PROTECTED] 1906//----------------------------------------------------------------------------- 1907 1908void 1909IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotifyStatic ( 1910 void * refCon, 1911 FWSBP2NotifyParams * params ) 1912{ 1913 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->UnsolicitedStatusNotify ( params ); 1914} 1915 1916 1917//----------------------------------------------------------------------------- 1918// UnsolicitedStatusNotify - Unsolicited status handler. [PROTECTED] 1919//----------------------------------------------------------------------------- 1920 1921void 1922IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotify ( 1923 FWSBP2NotifyParams * params ) 1924{ 1925 1926 DEBUG_UNUSED ( params ); 1927 1928 DLOG ( ( "%s: UnsolicitedStatusNotify called\n", getName ( ) ) ); 1929 1930 // Parse and handle unsolicited status. 1931 fLogin->enableUnsolicitedStatus ( ); 1932 1933} 1934 1935 1936//----------------------------------------------------------------------------- 1937// FetchAgentResetCompleteStatic - C->C++ glue. [PROTECTED] 1938//----------------------------------------------------------------------------- 1939 1940void 1941IOFireWireSerialBusProtocolTransport::FetchAgentResetCompleteStatic ( 1942 void * refCon, 1943 IOReturn status ) 1944{ 1945 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->FetchAgentResetComplete ( status ); 1946} 1947 1948 1949//----------------------------------------------------------------------------- 1950// FetchAgentResetComplete - Fetch agent reset handler. [PROTECTED] 1951//----------------------------------------------------------------------------- 1952 1953void 1954IOFireWireSerialBusProtocolTransport::FetchAgentResetComplete ( IOReturn status ) 1955{ 1956 1957 SBP2ClientOrbData * clientData = NULL; 1958 1959 DEBUG_UNUSED ( status ); 1960 1961 DLOG ( ( "%s: FetchAgentResetComplete called\n", getName ( ) ) ); 1962 1963 require ( fORB, exit ); 1964 1965 // When orb chaining is implemented we will notify upper layer 1966 // to reconfigure device state and resubmitting commands 1967 1968 clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ( ); 1969 if ( clientData != NULL ) 1970 { 1971 1972 if ( clientData->scsiTask != NULL ) 1973 { 1974 1975 RecordFireWireTimeStamp ( 1976 FW_TRACE ( kFetchAgentResetComplete ), 1977 ( uintptr_t ) this, 1978 ( uintptr_t ) fORB ); 1979 1980 #if TRANSPORT_FAILURE_RETRIES 1981 if ( reserved->fLUNResetPathFlag && ( reserved->fLUNResetCount > 0 ) ) 1982 { 1983 1984 reserved->fLUNResetCount--; 1985 submitOrbFromQueue ( ); 1986 1987 } 1988 1989 else 1990 #endif 1991 { 1992 CompleteSCSITask ( fORB ); 1993 } 1994 1995 } 1996 1997 } 1998 1999 2000exit: 2001 2002 reserved->fLUNResetPathFlag = false; 2003 2004} 2005 2006 2007//----------------------------------------------------------------------------- 2008// LunResetCompleteStatic - C->C++ glue. [PROTECTED] 2009//----------------------------------------------------------------------------- 2010 2011void 2012IOFireWireSerialBusProtocolTransport::LunResetCompleteStatic ( 2013 void * refCon, 2014 IOReturn status, 2015 IOFireWireSBP2ManagementORB * orb ) 2016{ 2017 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LunResetComplete ( status, orb ); 2018} 2019 2020 2021//----------------------------------------------------------------------------- 2022// LunResetComplete - LUN reset completion handler. [PROTECTED] 2023//----------------------------------------------------------------------------- 2024 2025void 2026IOFireWireSerialBusProtocolTransport::LunResetComplete ( 2027 IOReturn status, 2028 IOFireWireSBP2ManagementORB * orb ) 2029{ 2030 2031 DEBUG_UNUSED ( status ); 2032 DEBUG_UNUSED ( orb ); 2033 2034 DLOG ( ( "%s: LunResetComplete called\n", getName ( ) ) ); 2035 2036 RecordFireWireTimeStamp ( 2037 FW_TRACE ( kLogicalUnitResetComplete ), 2038 ( uintptr_t ) this, 2039 ( uintptr_t ) orb, 2040 status ); 2041 2042 RecordFireWireTimeStamp ( 2043 FW_TRACE ( kFetchAgentReset ), 2044 ( uintptr_t ) this, 2045 ( uintptr_t ) orb ); 2046 2047 fLogin->submitFetchAgentReset ( ); 2048 2049} 2050 2051 2052//----------------------------------------------------------------------------- 2053// ConnectToDeviceStatic - C->C++ glue. [PROTECTED] 2054//----------------------------------------------------------------------------- 2055 2056IOReturn 2057IOFireWireSerialBusProtocolTransport::ConnectToDeviceStatic ( 2058 OSObject * refCon, 2059 void * val1, 2060 void * val2, 2061 void * val3, 2062 void * val4 ) 2063{ 2064 2065 DEBUG_UNUSED ( val1 ); 2066 DEBUG_UNUSED ( val2 ); 2067 DEBUG_UNUSED ( val3 ); 2068 DEBUG_UNUSED ( val4 ); 2069 2070 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->ConnectToDevice ( ); 2071 2072 return kIOReturnSuccess; 2073 2074} 2075 2076 2077//----------------------------------------------------------------------------- 2078// ConnectToDevice - Connects to the device. [PROTECTED] 2079//----------------------------------------------------------------------------- 2080 2081void 2082IOFireWireSerialBusProtocolTransport::ConnectToDevice ( void ) 2083{ 2084 2085 IOReturn status = kIOReturnSuccess; 2086 2087 DLOG ( ( "%s: ConnectToDevice called\n", getName ( ) ) ); 2088 2089 // Avoid double logins during login phase. 2090 fNeedLogin = false; 2091 fLoginRetryCount = 0; 2092 2093 status = login ( ); 2094 if ( status == kIOReturnSuccess ) 2095 { 2096 2097 // Sleep the start thread - we'll wake it up on login completion. 2098 fCommandGate->commandSleep ( ( void * ) &reserved->fLoginState, THREAD_UNINT ); 2099 2100 } 2101 2102} 2103 2104 2105//----------------------------------------------------------------------------- 2106// DisconnectFromDevice - Disconnects from device. [PROTECTED] 2107//----------------------------------------------------------------------------- 2108 2109void 2110IOFireWireSerialBusProtocolTransport::DisconnectFromDevice ( void ) 2111{ 2112 2113 DLOG ( ( "%s: DisconnectFromDevice called\n", getName ( ) ) ); 2114 2115 fLoggedIn = false; 2116 2117 // Avoid logins during a logout phase. 2118 fNeedLogin = false; 2119 fLogin->submitLogout ( ); 2120 2121} 2122 2123 2124//----------------------------------------------------------------------------- 2125// CriticalOrbSubmissionStatic - C->C++ glue. [PROTECTED] 2126//----------------------------------------------------------------------------- 2127 2128IOReturn 2129 IOFireWireSerialBusProtocolTransport::CriticalOrbSubmissionStatic ( 2130 OSObject * refCon, 2131 void * val1, 2132 void * val2, 2133 void * val3, 2134 void * val4 ) 2135{ 2136 2137 DEBUG_UNUSED ( val3 ); 2138 DEBUG_UNUSED ( val4 ); 2139 2140 ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->CriticalOrbSubmission ( 2141 ( IOFireWireSBP2ORB * ) val1, ( SCSITaskIdentifier ) val2 ); 2142 2143 return kIOReturnSuccess; 2144 2145} 2146 2147 2148//----------------------------------------------------------------------------- 2149// CriticalOrbSubmission - add command to queue on workloop. [PROTECTED] 2150//----------------------------------------------------------------------------- 2151 2152void 2153IOFireWireSerialBusProtocolTransport::CriticalOrbSubmission ( 2154 IOFireWireSBP2ORB * orb, 2155 SCSITaskIdentifier request ) 2156{ 2157 2158 SBP2ClientOrbData * clientData; 2159 2160 clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( ); 2161 require ( clientData, exit ); 2162 2163 clientData->scsiTask = request; 2164 2165 reserved->fSubmitQueue->returnCommand ( orb ); 2166 2167 // Avoid double appending an active orb ( not this one ). 2168 if ( fORB == NULL ) 2169 { 2170 submitOrbFromQueue ( ); 2171 } 2172 2173 2174exit: 2175 2176 2177 return; 2178 2179} 2180 2181 2182//----------------------------------------------------------------------------- 2183// submitOrbFromQueue - submitORB on workloop. [PROTECTED] 2184//----------------------------------------------------------------------------- 2185 2186OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 6 ); 2187 2188void 2189IOFireWireSerialBusProtocolTransport::submitOrbFromQueue ( void ) 2190{ 2191 2192 DLOG ( ( "%s: submitOrbFromQueue called\n", getName ( ) ) ); 2193 2194 // This check is necessary because we may be draining the queue on the requesting close path. 2195 2196 if ( fLoggedIn == true ) 2197 { 2198 2199 if ( fORB == NULL ) 2200 { 2201 2202 fORB = ( IOFireWireSBP2ORB * ) reserved->fSubmitQueue->getCommand ( false ); 2203 fReconnectCount = 0; 2204 2205 } 2206 2207 if ( fORB != NULL ) 2208 { 2209 2210 RecordFireWireTimeStamp ( FW_TRACE ( kSubmitOrb ), ( uintptr_t ) this, ( uintptr_t ) fORB ); 2211 fLogin->submitORB ( fORB ); 2212 2213 } 2214 2215 } 2216 2217} 2218 2219 2220//----------------------------------------------------------------------------- 2221// AllocateResources - Allocates resources. [PROTECTED] 2222//----------------------------------------------------------------------------- 2223 2224IOReturn 2225IOFireWireSerialBusProtocolTransport::AllocateResources ( void ) 2226{ 2227 2228 IOReturn status = kIOReturnSuccess; 2229 IOWorkLoop * workLoop = NULL; 2230 2231 DLOG ( ( "%s: AllocateResources called\n", getName ( ) ) ); 2232 2233 fLogin = fSBPTarget->createLogin ( ); 2234 require_action ( fLogin, exit, status = kIOReturnNoMemory ); 2235 2236 fLogin->setLoginFlags ( kFWSBP2ExclusiveLogin ); 2237 fLogin->setLoginRetryCountAndDelayTime ( kLoginRetryCount, kLoginDelayTime ); 2238 fLogin->setMaxPayloadSize ( kMaxFireWirePayload ); 2239 fLogin->setStatusNotifyProc ( this, StatusNotifyStatic ); 2240 fLogin->setUnsolicitedStatusNotifyProc ( this, UnsolicitedStatusNotifyStatic ); 2241 fLogin->setLoginCompletion ( this, LoginCompletionStatic ); 2242 fLogin->setLogoutCompletion ( this, LogoutCompletionStatic ); 2243 fLogin->setFetchAgentResetCompletion ( this, FetchAgentResetCompleteStatic ); 2244 2245 // Set BUSY_TIMEOUT register value see SBP-2 spec section 6.2 2246 // also see IEEE Std 1394-1995 section 8.3.2.3.5 ( no I am not kidding ) 2247 fLogin->setBusyTimeoutRegisterValue ( kDefaultBusyTimeoutValue ); 2248 2249 fLUNResetORB = fSBPTarget->createManagementORB ( this, LunResetCompleteStatic ); 2250 require_action ( fLUNResetORB, exit, status = kIOReturnNoMemory ); 2251 2252 fLUNResetORB->setCommandFunction ( kFWSBP2LogicalUnitReset ); 2253 fLUNResetORB->setManageeCommand ( fLogin ); 2254 2255 // Allocate expansion data. 2256 reserved = ( ExpansionData * ) IOMalloc ( sizeof ( ExpansionData ) ); 2257 require_action ( reserved, exit, status = kIOReturnNoMemory ); 2258 bzero ( reserved, sizeof ( ExpansionData ) ); 2259 2260 reserved->fLoginState = kFirstTimeLoggingInState; 2261 2262 // Cache this as a member variable since we don't want to do this on every command. 2263 reserved->fAlwaysSetSenseData = getProperty ( kAlwaysSetAutoSenseData, gIOServicePlane ) ? true : false; 2264 2265 workLoop = getWorkLoop ( ); 2266 require_action ( workLoop, exit, status = kIOReturnNoMemory ); 2267 2268 reserved->fCommandPool = IOCommandPool::withWorkLoop ( workLoop ); 2269 require_action ( reserved->fCommandPool, exit, status = kIOReturnNoMemory ); 2270 2271 reserved->fSubmitQueue = IOCommandPool::withWorkLoop ( workLoop ); 2272 require_action ( reserved->fSubmitQueue, exit, status = kIOReturnNoMemory ); 2273 2274 for ( UInt32 i = 0; i < kCommandPoolOrbCount; ++i ) 2275 { 2276 2277 IOFireWireSBP2ORB * orb = NULL; 2278 SBP2ClientOrbData * clientData = NULL; 2279 2280 orb = fLogin->createORB ( ); 2281 require_action ( orb, exit, status = kIOReturnNoMemory ); 2282 2283 clientData = ( SBP2ClientOrbData * ) IOMalloc ( sizeof ( SBP2ClientOrbData ) ); 2284 require_action ( clientData, exit, status = kIOReturnNoMemory ); 2285 2286 bzero ( clientData, sizeof ( SBP2ClientOrbData ) ); 2287 clientData->orb = orb; 2288 orb->setRefCon ( ( void * ) clientData ); 2289 2290 2291 // Enqueue the command in the free list. 2292 reserved->fCommandPool->returnCommand ( orb ); 2293 2294 } 2295 2296 status = kIOReturnSuccess; 2297 2298 2299exit: 2300 2301 2302 return status; 2303 2304} 2305 2306//----------------------------------------------------------------------------- 2307// DeallocateResources - Deallocates resources. [PROTECTED] 2308//----------------------------------------------------------------------------- 2309 2310void 2311IOFireWireSerialBusProtocolTransport::DeallocateResources ( void ) 2312{ 2313 2314 IOFireWireSBP2ORB * orb = NULL; 2315 SBP2ClientOrbData * clientData = NULL; 2316 2317 DLOG ( ( "%s: DeallocateResources called\n", getName ( ) ) ); 2318 2319 // /!\ WARNING - always release orb's before logins. 2320 if ( fLUNResetORB != NULL ) 2321 { 2322 2323 fLUNResetORB->release ( ); 2324 fLUNResetORB = NULL; 2325 2326 } 2327 2328 if ( reserved != NULL ) 2329 { 2330 2331 // Drain the queue when requesting close so there are no in use commands when this is called. 2332 while ( ( orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false ) ) ) 2333 { 2334 2335 clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( ); 2336 if ( clientData != NULL ) 2337 { 2338 2339 IOFree ( clientData, sizeof ( SBP2ClientOrbData ) ); 2340 clientData = NULL; 2341 2342 } 2343 2344 orb->release ( ); 2345 orb = NULL; 2346 2347 } 2348 2349 reserved->fCommandPool->release ( ); 2350 reserved->fCommandPool = NULL; 2351 2352 reserved->fSubmitQueue->release ( ); 2353 reserved->fSubmitQueue = NULL; 2354 2355 } 2356 2357 if ( fLogin != NULL ) 2358 { 2359 2360 fLogin->release ( ); 2361 fLogin = NULL; 2362 2363 } 2364 2365} 2366 2367 2368//----------------------------------------------------------------------------- 2369// login - login bottleneck to track retries. [PROTECTED] 2370//----------------------------------------------------------------------------- 2371 2372OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 1 ); 2373 2374IOReturn 2375IOFireWireSerialBusProtocolTransport::login ( void ) 2376{ 2377 2378 IOReturn status = kIOReturnError; 2379 2380 DLOG ( ( "%s: submitting login.\n", getName ( ) ) ); 2381 2382 fNeedLogin = false; 2383 fLoggedIn = false; 2384 2385 // If we enter this again and fLoginRetryCount is already 2386 // at kMaxLoginRetryCount - we should default status to an error. 2387 for ( ; fLoginRetryCount < kMaxLoginRetryCount; ++fLoginRetryCount ) 2388 { 2389 2390 RecordFireWireTimeStamp ( 2391 FW_TRACE ( kLoginRequest ), 2392 ( uintptr_t ) this, 2393 reserved->fLoginState, 2394 fLoginRetryCount ); 2395 2396 status = submitLogin ( ); 2397 if ( status == kIOReturnSuccess ) 2398 { 2399 break; 2400 } 2401 2402 } 2403 2404 if ( status != kIOReturnSuccess ) 2405 { 2406 2407 fNeedLogin = true; 2408 fLoggedIn = false; 2409 2410 RecordFireWireTimeStamp ( 2411 FW_TRACE ( kLoginLost ), 2412 ( uintptr_t ) this, 2413 reserved->fLoginState ); 2414 2415 loginLost ( ); 2416 2417 } 2418 2419 return status; 2420 2421} 2422 2423 2424//----------------------------------------------------------------------------- 2425// submitLogin - submitLogin bottleneck for subclass. [PROTECTED] 2426//----------------------------------------------------------------------------- 2427 2428OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 2 ); 2429 2430IOReturn 2431IOFireWireSerialBusProtocolTransport::submitLogin ( void ) 2432{ 2433 2434 IOReturn status = kIOReturnSuccess; 2435 2436 DLOG ( ( "%s: submitting login.\n", getName ( ) ) ); 2437 2438 status = fLogin->submitLogin ( ); 2439 2440 return status; 2441 2442} 2443 2444 2445//----------------------------------------------------------------------------- 2446// loginLost - login lost bottleneck for subclass. [PROTECTED] 2447//----------------------------------------------------------------------------- 2448 2449OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 3 ); 2450 2451void IOFireWireSerialBusProtocolTransport::loginLost ( void ) 2452{ 2453 2454 DLOG ( ( "%s: login lost.\n", getName ( ) ) ); 2455 // Notification that the login is lost. 2456 2457} 2458 2459 2460//----------------------------------------------------------------------------- 2461// loginSuspended - login suspended bottleneck for subclass. [PROTECTED] 2462//----------------------------------------------------------------------------- 2463 2464OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 4 ); 2465 2466void 2467IOFireWireSerialBusProtocolTransport::loginSuspended ( void ) 2468{ 2469 2470 DLOG ( ( "%s: login suspended.\n", getName ( ) ) ); 2471 // A successful reconnect orb is required. 2472 2473} 2474 2475 2476//----------------------------------------------------------------------------- 2477// loginResumed - login resumed bottleneck for subclass. [PROTECTED] 2478//----------------------------------------------------------------------------- 2479 2480OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 5 ); 2481 2482void 2483IOFireWireSerialBusProtocolTransport::loginResumed ( void ) 2484{ 2485 2486 DLOG ( ( "%s: login resumed.\n", getName ( ) ) ); 2487 // A reconnect orb has succeeded. 2488 2489} 2490 2491 2492#if 0 2493#pragma mark - 2494#pragma mark Static Debug Assertion Method 2495#pragma mark - 2496#endif 2497 2498 2499//----------------------------------------------------------------------------- 2500// IOFireWireSerialBusProtocolTransportDebugAssert [STATIC] 2501//----------------------------------------------------------------------------- 2502 2503#if !DEBUG_ASSERT_PRODUCTION_CODE 2504 2505void 2506IOFireWireSerialBusProtocolTransportDebugAssert ( 2507 const char * componentNameString, 2508 const char * assertionString, 2509 const char * exceptionLabelString, 2510 const char * errorString, 2511 const char * fileName, 2512 long lineNumber, 2513 int errorCode ) 2514{ 2515 IOLog ( "%s Assert failed: %s ", componentNameString, assertionString ); 2516 2517 if ( exceptionLabelString != NULL ) { IOLog ( "%s ", exceptionLabelString ); } 2518 2519 if ( errorString != NULL ) { IOLog ( "%s ", errorString ); } 2520 2521 if ( fileName != NULL ) { IOLog ( "file: %s ", fileName ); } 2522 2523 if ( lineNumber != 0 ) { IOLog ( "line: %ld ", lineNumber ); } 2524 2525 if ( ( long ) errorCode != 0 ) { IOLog ( "error: %ld ( 0x%08lx )", 2526 ( long ) errorCode, 2527 ( long ) errorCode ); } 2528 2529 IOLog ( "\n" ); 2530} 2531 2532#endif 2533 2534 2535//----------------------------------------------------------------------------- 2536// RecordFireWireTimeStamp [STATIC] 2537//----------------------------------------------------------------------------- 2538 2539static inline void 2540RecordFireWireTimeStamp ( 2541 unsigned int code, 2542 unsigned int a, unsigned int b, 2543 unsigned int c, unsigned int d ) 2544{ 2545 2546 if ( gSBP2DiskDebugFlags & kSBP2DiskEnableTracePointsMask ) 2547 { 2548 IOTimeStampConstant ( code, a, b, c, d ); 2549 } 2550 2551} 2552 2553 2554#if 0 2555#pragma mark - 2556#pragma mark VTable Padding 2557#pragma mark - 2558#endif 2559 2560OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 7 ); 2561OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 8 ); 2562OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 9 ); 2563OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 10 ); 2564OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 11 ); 2565OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 12 ); 2566OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 13 ); 2567OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 14 ); 2568OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 15 ); 2569OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 16 ); 2570