/* * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ //-------------------------------------------------------------------------------------------------- // Includes //-------------------------------------------------------------------------------------------------- #include "IOFireWireSerialBusProtocolTransport.h" #include #include #include #if 0 #pragma mark == Macros == #endif //-------------------------------------------------------------------------------------------------- // Macros //-------------------------------------------------------------------------------------------------- #define DEBUG 0 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "FireWire SBP Transport" #include "IOFireWireSerialBusProtocolTransportDebugging.h" #if DEBUG #define FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL 0 #endif #if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 1 ) #define PANIC_NOW(x) IOPanic x #else #define PANIC_NOW(x) #endif #if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 2 ) #define ERROR_LOG(x) IOLog x #else #define ERROR_LOG(x) #endif #if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 3 ) #define DLOG(x) IOLog x #else #define DLOG(x) #endif #define super IOSCSIProtocolServices OSDefineMetaClassAndStructors ( IOFireWireSerialBusProtocolTransport, IOSCSIProtocolServices ) // Uncomment _TRANSPORT_FAILURE_RETRIES_ to enable tranport level retires for protocol timeouts. // #define _TRANSPORT_FAILURE_RETRIES_ true #if 0 #pragma mark == Constants == #endif //-------------------------------------------------------------------------------------------------- // Constants //-------------------------------------------------------------------------------------------------- #define kPreferredNameKey "Preferred Name" #define kFireWireGUIDKey "GUID" #define kFireWireVendorNameKey "FireWire Vendor Name" #define kSBP2ReceiveBufferByteCountKey "SBP2ReceiveBufferByteCount" #define kDefaultIOBlockCount 256 #define kCRSModelInfo_ValidBitsMask 0x00FFFFFF #define kCRSModelInfo_TargetDiskMode 0x0054444D #define kIOFireWireMessageServiceIsRequestingClose kIOFWMessageServiceIsRequestingClose #define kDefaultTimeOutValue 30000 #define kCommandPoolOrbCount 1 #define kFWSBP2DefaultPageTableEntriesCount 512 enum { kFireWireSBP2CommandTransferDataToTarget = 0L, kFireWireSBP2CommandTransferDataFromTarget = kFWSBP2CommandTransferDataFromTarget }; #if 0 #pragma mark == Static Debug Assertion Method == #endif //-------------------------------------------------------------------------------------------------- // IOFireWireSerialBusProtocolTransportDebugAssert [STATIC] //-------------------------------------------------------------------------------------------------- #if !DEBUG_ASSERT_PRODUCTION_CODE void IOFireWireSerialBusProtocolTransportDebugAssert ( const char * componentNameString, const char * assertionString, const char * exceptionLabelString, const char * errorString, const char * fileName, long lineNumber, int errorCode ) { IOLog ( "%s Assert failed: %s ", componentNameString, assertionString ); if ( exceptionLabelString != NULL ) { IOLog ( "%s ", exceptionLabelString ); } if ( errorString != NULL ) { IOLog ( "%s ", errorString ); } if ( fileName != NULL ) { IOLog ( "file: %s ", fileName ); } if ( lineNumber != 0 ) { IOLog ( "line: %ld ", lineNumber ); } if ( ( long ) errorCode != 0 ) { IOLog ( "error: %ld ( 0x%08lx )", ( long ) errorCode, ( long ) errorCode ); } IOLog ( "\n" ); } #endif #if 0 #pragma mark == Public Methods == #endif //-------------------------------------------------------------------------------------------------- // init - Called by IOKit to initialize us. [PUBLIC] //-------------------------------------------------------------------------------------------------- bool IOFireWireSerialBusProtocolTransport::init ( OSDictionary * propTable ) { fORB = 0; fLogin = 0; fLoginRetryCount = 0; fReconnectCount = 0; fLoggedIn = false; fNeedLogin = false; fLUNResetORB = NULL; fDeferRegisterService = true; fObjectIsOpen = false; if ( super::init ( propTable ) == false ) { return false; } return true; } //-------------------------------------------------------------------------------------------------- // start - Called by IOKit to start our services. [PUBLIC] //-------------------------------------------------------------------------------------------------- bool IOFireWireSerialBusProtocolTransport::start ( IOService * provider ) { IOReturn status; Boolean returnValue; Boolean openSucceeded; OSNumber * rto; OSNumber * wto; OSDictionary * dict; bool sucess; status = kIOReturnSuccess; returnValue = false; openSucceeded = false; rto = NULL; wto = NULL; sucess = false; dict = NULL; // See if there is a read time out duration passed in the property dictionary - if not // set the default to 30 seconds. rto = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) ); if ( rto == NULL ) { rto = OSNumber::withNumber ( kDefaultTimeOutValue, 32 ); require ( rto, exit ); sucess = setProperty ( kIOPropertyReadTimeOutDurationKey, rto ); check ( sucess ); rto->release(); rto = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) ); } DLOG ( ( "%s: start read time out = %ld\n", getName (), rto->unsigned32BitValue ( ) ) ); // See if there is a write time out duration passed in the property dictionary - if not // set the default to 30 seconds. wto = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyWriteTimeOutDurationKey ) ); if ( wto == NULL ) { wto = OSNumber::withNumber ( kDefaultTimeOutValue, 32 ); require ( wto, exit ); sucess = setProperty ( kIOPropertyWriteTimeOutDurationKey, wto ); check ( sucess ); wto->release(); wto = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyWriteTimeOutDurationKey ) ); } DLOG ( ( "%s: start read time out = %ld\n", getName (), wto->unsigned32BitValue ( ) ) ); // Set the default maximum page table constraints for SBP2 // $$$ ( this should probably be moved down to SBP2 - ping Collin ) setProperty ( kIOMaximumSegmentCountReadKey, kFWSBP2DefaultPageTableEntriesCount, 32 ); setProperty ( kIOMaximumSegmentCountWriteKey, kFWSBP2DefaultPageTableEntriesCount, 32 ); setProperty ( kIOMaximumSegmentByteCountReadKey, kFWSBP2MaxPageClusterSize, 32 ); setProperty ( kIOMaximumSegmentByteCountWriteKey, kFWSBP2MaxPageClusterSize, 32 ); fSBPTarget = OSDynamicCast ( IOFireWireSBP2LUN, provider ); require ( fSBPTarget, exit ); // Add a retain here so we can keep IOFireWireSBP2LUN from doing garbage collection on us // when we are in the middle of our finalize method. fSBPTarget->retain ( ); openSucceeded = super::start ( provider ); require ( openSucceeded, exit ); openSucceeded = provider->open ( this ); require ( openSucceeded, exit ); fUnit = fSBPTarget->getFireWireUnit (); require ( fUnit, exit ); // Explicitly set the "enable retry on ack d" flag. fUnit->setNodeFlags ( kIOFWEnableRetryOnAckD ); status = AllocateResources (); require_noerr ( status, exit ); // Get us on the workloop so we can sleep the start thread. fCommandGate->runAction ( ConnectToDeviceStatic ); if ( reserved->fLoginState == kLogginSucceededState ) { registerService (); } DLOG ( ( "%s: start complete\n", getName () ) ); returnValue = true; // Copy some values to the Protocol Characteristics Dictionary. dict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertyProtocolCharacteristicsKey ) ); if ( dict != NULL ) { OSDictionary * protocolDict; OSString * string; protocolDict = NULL; string = NULL; // Make a copy of the existing Protocol Characteristics Dictionary to Modify. protocolDict = OSDictionary::withDictionary ( dict ); check ( protocolDict ); string = OSString::withCString ( kFireWireGUIDKey ); if ( string != NULL ) { protocolDict->setObject ( string, getProperty ( kFireWireGUIDKey, gIOServicePlane ) ); string->release ( ); } string = OSString::withCString ( kPreferredNameKey ); if ( string != NULL ) { protocolDict->setObject ( kPreferredNameKey, getProperty ( kFireWireVendorNameKey, gIOServicePlane ) ); string->release ( ); } // Replace the existing Protocol Characteristics Dictionary with our new one. setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict ); protocolDict->release ( ); } InitializePowerManagement ( provider ); exit: if ( returnValue == false ) { DLOG ( ( "%s: start failed. status = %x\n", getName (), status) ); // Call the cleanUp method to clean up any allocated resources. cleanUp (); } return returnValue; } //-------------------------------------------------------------------------------------------------- // cleanUp - [PUBLIC] // Note: This is misleadingly named due to binary compatibility burdens. The cleanUp method // actually just closes the SBP2LUN. fSBPTarget is actually a SBP2LUN object. //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::cleanUp ( void ) { DLOG ( ( "%s: cleanUp called\n", getName () ) ); if ( fSBPTarget != NULL ) { // Close SBP2 if we have opened it. if ( fSBPTarget->isOpen ( this ) ) { fSBPTarget->close ( this ); } } } #if 0 //-------------------------------------------------------------------------------------------------- // close - attempt to log out of device. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::close ( IOService * provider, IOOptionBits options ) { IOLog ( "**** DOES THIS EVEN GET CALLED AT SHUTDOWN OR RESTART? - TERM STATE = %d ****\n", isInactive () ); if ( !isInactive () ) { IOReturn err; err = fLogin->submitLogout (); } super::close ( provider, options ); } #endif //-------------------------------------------------------------------------------------------------- // finalize - Terminates all power management. [PROTECTED] //-------------------------------------------------------------------------------------------------- bool IOFireWireSerialBusProtocolTransport::finalize ( IOOptionBits options ) { DeallocateResources ( ); // Release the retain we took to keep IOFireWireSBP2LUN from doing garbage collection on us // when we are in the middle of DeallocateResources. if ( fSBPTarget ) { fSBPTarget->release ( ); fSBPTarget = NULL; } return super::finalize ( options ); } //-------------------------------------------------------------------------------------------------- // free - Called to deallocate ExpansionData. [PUBLIC] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::free ( void ) { if ( reserved != NULL ) { if ( reserved->fCommandPool != NULL ) { reserved->fCommandPool->release (); reserved->fCommandPool = NULL; } IOFree ( reserved, sizeof ( ExpansionData ) ); reserved = NULL; } super::free ( ); } #if 0 #pragma mark == Protected Methods == #endif //-------------------------------------------------------------------------------------------------- // CommandORBAccessor - Retrieves command orb. [PROTECTED] //-------------------------------------------------------------------------------------------------- IOFireWireSBP2ORB * IOFireWireSerialBusProtocolTransport::CommandORBAccessor ( void ) { return fORB; } //-------------------------------------------------------------------------------------------------- // SBP2LoginAccessor - Retrieves login orb. [PROTECTED] //-------------------------------------------------------------------------------------------------- IOFireWireSBP2Login * IOFireWireSerialBusProtocolTransport::SBP2LoginAccessor ( void ) { return fLogin; } //-------------------------------------------------------------------------------------------------- // message - Called by IOKit to deliver messages. [PROTECTED] //-------------------------------------------------------------------------------------------------- IOReturn IOFireWireSerialBusProtocolTransport::message ( UInt32 type, IOService * nub, void * arg ) { IOFireWireSBP2ORB * orb; SBP2ClientOrbData * clientData; IOReturn status; orb = NULL; clientData = NULL; status = kIOReturnSuccess; switch ( type ) { case kIOMessageServiceIsSuspended: DLOG ( ( "%s: kIOMessageServiceIsSuspended\n", getName () ) ); // Bus reset started - set flag to stop submitting orbs. fLoggedIn = false; break; case kIOMessageServiceIsResumed: DLOG ( ( "%s: kIOMessageServiceIsResumed\n", getName () ) ); // Bus reset finished - if we have failed to log in previously, try again. if ( fNeedLogin ) { fNeedLogin = false; fLoginRetryCount = 0; // In case we are resumed after a terminate. if ( fLogin != NULL ) { login (); } } break; case kIOMessageFWSBP2ReconnectComplete: // As of this writing FireWireSBP2LUN will message all multi-LUN instances with this // message. So qualify this message with our instance variable fLogin and ignore others. if( ( ( FWSBP2ReconnectParams* ) arg )->login == fLogin ) { DLOG ( ( "%s: kIOMessageFWSBP2ReconnectComplete\n", getName () ) ); fLoggedIn = true; if ( fReconnectCount < kMaxReconnectCount) { DLOG ( ( "%s: resubmit orb \n", getName () ) ); fReconnectCount++; submitOrbFromQueue (); } else { // Unable to recover from bus reset storm. We have exhausted the // fReconnectCount - punt... if ( fORB ) { clientData = ( SBP2ClientOrbData * ) fORB->getRefCon (); if ( clientData != NULL ) { clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; clientData->taskStatus = kSCSITaskStatus_DeliveryFailure; CompleteSCSITask ( fORB ); } } } } break; case kIOMessageFWSBP2ReconnectFailed: // As of this writing FireWireSBP2LUN will message all multi-LUN instances with this // message. So qualify this message with our instance variable fLogin and ignore others. if( ( ( FWSBP2ReconnectParams* ) arg )->login == fLogin ) { DLOG ( ( "%s: kIOMessageFWSBP2ReconnectFailed\n", getName () ) ); // Try to reestablish log in. fLoginRetryCount = 0; login (); } break; case kIOFireWireMessageServiceIsRequestingClose: DLOG ( ( "%s: kIOFireWireMessageServiceIsRequestingClose\n", getName () ) ); // Tell our super to message it's clients that the device is gone. SendNotification_DeviceRemoved (); // We need to drain the queued commands. See if there is an in flight orb (e.g. fORB) // if not pull the first one out of the submit queue if there are any. orb = fORB; do { if ( orb ) { clientData = ( SBP2ClientOrbData * ) orb->getRefCon (); if ( clientData ) { if ( clientData->scsiTask) { clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; clientData->taskStatus = kSCSITaskStatus_DeviceNotPresent; CompleteSCSITask ( orb ); } } } } while ( ( orb = ( IOFireWireSBP2ORB * ) reserved->fSubmitQueue->getCommand ( false ) ) ); cleanUp (); break; case kIOMessageServiceIsTerminated: DLOG ( ( "%s: kIOMessageServiceIsTerminated\n", getName () ) ); // Let go of memory and what not. cleanUp (); break; default: status = IOService::message (type, nub, arg); break; } return status; } //-------------------------------------------------------------------------------------------------- // SendSCSICommand - Converts a SCSITask to an ORB. [PROTECTED] //-------------------------------------------------------------------------------------------------- bool IOFireWireSerialBusProtocolTransport::SendSCSICommand ( SCSITaskIdentifier request, SCSIServiceResponse * serviceResponse, SCSITaskStatus * taskStatus ) { SBP2ClientOrbData * clientData; IOFireWireSBP2ORB * orb; SCSICommandDescriptorBlock cdb = { 0 }; UInt8 commandLength; UInt32 commandFlags; UInt32 timeOut; bool commandProcessed; DLOG ( ( "%s: SendSCSICommand called\n", getName () ) ); clientData = NULL; orb = NULL; commandLength = 0; commandFlags = 0; timeOut = 0; commandProcessed = true; *serviceResponse = kSCSIServiceResponse_Request_In_Process; *taskStatus = kSCSITaskStatus_No_Status; if ( isInactive () ) { // Device is disconnected - we can not service command requests. *serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; commandProcessed = true; goto exit; } // Get an orb from our orb pool and do not block until we get one. orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false ); if ( orb == NULL ) { // We're busy - return false - command will be resent next time CommandComplete is called. commandProcessed = false; goto exit; } clientData = ( SBP2ClientOrbData * ) orb->getRefCon (); if ( clientData == NULL ) goto exit; GetCommandDescriptorBlock ( request, &cdb ); commandLength = GetCommandDescriptorBlockSize ( request ); #if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 3 ) if ( commandLength == kSCSICDBSize_6Byte ) { DLOG ( ( "cdb = %02x:%02x:%02x:%02x:%02x:%02x\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5] ) ); } else if ( commandLength == kSCSICDBSize_10Byte ) { DLOG ( ( "cdb = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9] ) ); } else if ( commandLength == kSCSICDBSize_12Byte ) { DLOG ( ( "cdb = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11] ) ); } #endif // (FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 3) commandFlags = ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromTargetToInitiator ) ? kFireWireSBP2CommandTransferDataFromTarget : kFireWireSBP2CommandTransferDataToTarget; orb->setCommandFlags ( commandFlags | kFWSBP2CommandCompleteNotify | kFWSBP2CommandImmediate | kFWSBP2CommandNormalORB ); SetCommandBuffers ( orb, request ); orb->setCommandBlock ( cdb, commandLength ); // SBP-2 needs a non-zero timeout to fire completion routines if timeout is not expressed // default to 0xFFFFFFFF. timeOut = GetTimeoutDuration ( request ); if ( timeOut == 0 ) { timeOut = 0xFFFFFFFF; } orb->setCommandTimeout ( timeOut ); #ifdef _TRANSPORT_FAILURE_RETRIES_ reserved->fLUNResetCount = 3; #endif // Close the gate here to eliminate potenially rare double append of orb. If on a DP machine // and a bus reset occurs the login thread can append the orb as well as here. fCommandGate->runAction ( CriticalOrbSubmissionStatic, orb, request ); exit: DLOG ( ( "%s: SendSCSICommand exit, Service Response = %x\n", getName (), *serviceResponse) ); return commandProcessed; } //-------------------------------------------------------------------------------------------------- // SetCommandBuffers - Sets the command buffers in the ORB. [PROTECTED] //-------------------------------------------------------------------------------------------------- IOReturn IOFireWireSerialBusProtocolTransport::SetCommandBuffers ( IOFireWireSBP2ORB * orb, SCSITaskIdentifier request ) { return orb->setCommandBuffers ( GetDataBuffer ( request ), GetDataBufferOffset ( request ), GetRequestedDataTransferCount ( request ) ); } //-------------------------------------------------------------------------------------------------- // CompleteSCSITask - Completes a task. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::CompleteSCSITask ( IOFireWireSBP2ORB * orb ) { SBP2ClientOrbData * clientData = NULL; DLOG ( ( "%s: CompleteSCSITask called\n", getName () ) ); clientData = ( SBP2ClientOrbData * ) orb->getRefCon (); if ( clientData != NULL ) { if ( clientData->scsiTask != NULL ) { SCSITaskIdentifier scsiTask = NULL; SCSIServiceResponse serviceResponse; SCSITaskStatus taskStatus; IOByteCount bytesTransfered = 0; // /!\ WARNING - because SBP-2 can send status information at different // stage of an orb's life ( or send none at all ) the caller of this routine // has determined that the orb is indeed done. So we need to explicitly tell // SBP-2 to left go of the buffer reference by calling releaseCommandBuffers. orb->releaseCommandBuffers (); if ( clientData->taskStatus == kSCSITaskStatus_GOOD ) { bytesTransfered = GetRequestedDataTransferCount ( clientData->scsiTask ); } SetRealizedDataTransferCount ( clientData->scsiTask, bytesTransfered ); // Re-entrancy protection. scsiTask = clientData->scsiTask; serviceResponse = clientData->serviceResponse; taskStatus = clientData->taskStatus; clientData->scsiTask = NULL; fORB = NULL; submitOrbFromQueue (); reserved->fCommandPool->returnCommand ( orb ); CommandCompleted ( scsiTask, serviceResponse, taskStatus ); } } } //-------------------------------------------------------------------------------------------------- // AbortSCSICommand - Aborts an outstanding I/O. [PROTECTED] //-------------------------------------------------------------------------------------------------- SCSIServiceResponse IOFireWireSerialBusProtocolTransport::AbortSCSICommand ( SCSITaskIdentifier request ) { SCSIServiceResponse serviceResponse; DEBUG_UNUSED ( request ); DLOG ( ( "%s: AbortSCSICommand called\n", getName () ) ); serviceResponse = kSCSIServiceResponse_FUNCTION_REJECTED; return serviceResponse; } //-------------------------------------------------------------------------------------------------- // IsProtocolServiceSupported - Checks for protocol services supported by this device. [PROTECTED] //-------------------------------------------------------------------------------------------------- bool IOFireWireSerialBusProtocolTransport::IsProtocolServiceSupported ( SCSIProtocolFeature feature, void * serviceValue ) { bool isSupported = false; DLOG ( ( "IOFireWireSerialBusProtocolTransport::IsProtocolServiceSupported called\n" ) ); switch ( feature ) { case kSCSIProtocolFeature_CPUInDiskMode: isSupported = IsDeviceCPUInDiskMode (); break; case kSCSIProtocolFeature_MaximumReadBlockTransferCount: case kSCSIProtocolFeature_MaximumWriteBlockTransferCount: *( UInt32 * ) serviceValue = kDefaultIOBlockCount; isSupported = true; break; case kSCSIProtocolFeature_MaximumReadTransferByteCount: OSNumber * valuePointer; // If the property SBP2ReceiveBufferByteCount exists we have a FireWire host // with the physical unit off and there is a software FIFO. ( i.e. Lynx ) // We should tell clients to deblock on the SBP2ReceiveBufferByteCount. // bounds to avoid stalled I/O. valuePointer = OSDynamicCast ( OSNumber, getProperty ( kSBP2ReceiveBufferByteCountKey, gIOServicePlane ) ); if ( valuePointer != NULL ) { *( UInt64 * ) serviceValue = valuePointer->unsigned32BitValue (); isSupported = true; } break; case kSCSIProtocolFeature_GetMaximumLogicalUnitNumber: *( UInt32 * ) serviceValue = kMaxFireWireLUN; isSupported = true; break; case kSCSIProtocolFeature_ProtocolAlwaysReportsAutosenseData: isSupported = true; break; default: break; } return isSupported; } //-------------------------------------------------------------------------------------------------- // HandleProtocolServiceFeature - Handles protocol service features. [PROTECTED] //-------------------------------------------------------------------------------------------------- bool IOFireWireSerialBusProtocolTransport::HandleProtocolServiceFeature ( SCSIProtocolFeature feature, void * serviceValue ) { DEBUG_UNUSED ( feature ); DEBUG_UNUSED ( serviceValue ); return false; } //-------------------------------------------------------------------------------------------------- // IsDeviceCPUInDiskMode - Checks if device is a CPU in FireWire Target Disk Mode. [PROTECTED] //-------------------------------------------------------------------------------------------------- bool IOFireWireSerialBusProtocolTransport::IsDeviceCPUInDiskMode ( void ) { UInt32 csrModelInfo; IOConfigDirectory * directory; IOFireWireDevice * device; IOReturn status; IOService * providerService; bool isCPUDiskMode; DLOG ( ( "%s: IsDeviceCPUInDiskMode was called\n", getName () ) ); csrModelInfo = 0; directory = NULL; device = NULL; status = kIOReturnSuccess; providerService = fUnit->getProvider (); isCPUDiskMode = false; if ( providerService == NULL ) { goto exit; } device = OSDynamicCast ( IOFireWireDevice, providerService ); if ( device == NULL ) { goto exit; } status = device->getConfigDirectory ( directory ); if ( status == kIOReturnSuccess ) { status = directory->getKeyValue ( kCSRModelInfoKey, csrModelInfo ); if ( status == kIOReturnSuccess ) { if ( ( csrModelInfo & kCRSModelInfo_ValidBitsMask ) == kCRSModelInfo_TargetDiskMode ) { isCPUDiskMode = true; } } } exit: DLOG ( ( "%s: CPU Disk Mode = %d\n", getName (), isCPUDiskMode ) ); return isCPUDiskMode; } //-------------------------------------------------------------------------------------------------- // StatusNotifyStatic - C->C++ glue method. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::StatusNotifyStatic ( void * refCon, FWSBP2NotifyParams * params ) { ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->StatusNotify ( params ); } //-------------------------------------------------------------------------------------------------- // StatusNotify - Status notify handler. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::StatusNotify ( FWSBP2NotifyParams * params ) { IOFireWireSBP2ORB * orb; FWSBP2StatusBlock * statusBlock; SBP2ClientOrbData * clientData; SCSI_Sense_Data * targetData; UInt8 senseData [ kSenseDefaultSize + 8 ] = { 0 }; statusBlock = NULL; clientData = NULL; targetData = ( SCSI_Sense_Data * ) &senseData [ 0 ]; if ( ( params->message != NULL ) && ( params->length != 0 ) ) { statusBlock = ( FWSBP2StatusBlock * ) params->message; } orb = ( IOFireWireSBP2ORB * ) params->commandObject; if ( orb ) { clientData = ( SBP2ClientOrbData * ) orb->getRefCon (); } switch ( params->notificationEvent ) { case kFWSBP2NormalCommandStatus: // Read the status block detail bits see SBP-2 spec section 5.3 check the dead bit // ( i.e. that the 'd' field == 1 ). if ( ( clientData != NULL ) && ( statusBlock->details & 0x08 ) ) { SetValidAutoSenseData ( clientData, statusBlock, targetData ); // Wait for fetch agent to reset before calling CompleteSCSITask which will // be called in FetchAgentResetComplete. fLogin->submitFetchAgentReset (); } else if ( clientData && ( ( statusBlock->details & 0x30 ) == 0 ) && // ( is 'resp' field == 0 ) ( ( statusBlock->details & 0x07 ) == 1 ) && // ( is 'len' field == 1 ) ( statusBlock->sbpStatus == 0 ) ) // ( is 'sbp_status' field == 0 ) { clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE; clientData->taskStatus = kSCSITaskStatus_GOOD; CompleteSCSITask ( orb ); DLOG ( ( "%s: StatusNotify normal complete \n", getName () ) ); } else if ( clientData ) { SetValidAutoSenseData ( clientData, statusBlock, targetData ); CompleteSCSITask ( orb ); DLOG ( ( "%s: StatusNotify have sense data or an unexpected error? \n", getName () ) ); } break; case kFWSBP2NormalCommandTimeout: DLOG ( ( "%s: kFWSBP2NormalCommandTimeout \n", getName () ) ); if ( clientData ) { if ( clientData->scsiTask ) { clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; clientData->taskStatus = kSCSITaskStatus_ProtocolTimeoutOccurred; } } // Set flag so FetchAgentReset knows it is being called from a timeout path. reserved->fLUNResetPathFlag = true; // We reset the LUN as good measure in case device is wedged. The LUN reset completion // handler will call the fetch agent to be reset. The FetchAgentReset completion handler // will call CompleteSCSITask and complete the command with the approrpiate task status. fLUNResetORB->submit (); break; case kFWSBP2NormalCommandReset: DLOG ( ( "%s: kFWSBP2NormalCommandReset\n", getName () ) ); // kFWSBP2NormalCommandReset - is a misleading definition. A pending command has // failed so we need notify the upper layers to complete failed command. if ( clientData != NULL ) { if ( clientData->scsiTask != NULL ) { clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; clientData->taskStatus = kSCSITaskStatus_DeliveryFailure; CompleteSCSITask ( orb ); } } break; default: DLOG ( ( "%s: StatusNotify with unknown notificationEvent\n", getName () ) ); break; } } //-------------------------------------------------------------------------------------------------- // SetValidAutoSenseData - Sets any valid sense data. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::SetValidAutoSenseData ( SBP2ClientOrbData * clientData, FWSBP2StatusBlock * statusBlock, SCSI_Sense_Data * targetData ) { UInt8 quadletCount; clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE; clientData->taskStatus = kSCSITaskStatus_No_Status; quadletCount = ( statusBlock->details & 0x07 ) - 1 ; // See if we have any valid sense data. if ( ( statusBlock->details & 0x30 ) == 0 ) { clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE; clientData->taskStatus = CoalesceSenseData ( statusBlock, quadletCount, targetData ); } if ( clientData->taskStatus == kSCSITaskStatus_CHECK_CONDITION || reserved->fAlwaysSetSenseData ) { if ( clientData->scsiTask != NULL ) { SetAutoSenseData ( clientData->scsiTask, targetData, kSenseDefaultSize + 8 ); } } } //-------------------------------------------------------------------------------------------------- // CoalesceSenseData - Sets sense data in the data buffer. [PROTECTED] //-------------------------------------------------------------------------------------------------- SCSITaskStatus IOFireWireSerialBusProtocolTransport::CoalesceSenseData ( FWSBP2StatusBlock * sourceData, UInt8 quadletCount, SCSI_Sense_Data * targetData ) { SCSITaskStatus returnValue; UInt8 statusBlockFormat; returnValue = kSCSITaskStatus_GOOD; statusBlockFormat = 0; // Pull bits out of SBP-2 status block ( see SBP-2 Annex B section B.2 ) // and copy them into sense data block ( see SPC-2 section 7.23.2 ) if ( quadletCount > 0 ) { statusBlockFormat = ( sourceData->status[0] >> 30 ) & 0x03; returnValue = ( SCSITaskStatus ) ( ( sourceData->status[0] >> 24 ) & 0x3F ); if ( statusBlockFormat == 0 ) { targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Current_Errors; } else if ( statusBlockFormat == 1 ) { targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Deferred_Errors; } if ( statusBlockFormat < 2 ) { targetData->VALID_RESPONSE_CODE |= ( sourceData->status[0] >> 16 ) & 0x80; targetData->ADDITIONAL_SENSE_CODE = ( sourceData->status[0] >> 8 ) & 0xFF; targetData->ADDITIONAL_SENSE_CODE_QUALIFIER = sourceData->status[0] & 0xFF; targetData->SENSE_KEY = ( sourceData->status[0] >> 16 ) & 0x0F; // Set the M, E, I bits: M->FileMark, E->EOM, I->ILI. targetData->SENSE_KEY |= ( ( sourceData->status[0] >> 16 ) & 0x70 ) << 1; if ( quadletCount > 1 ) { targetData->INFORMATION_1 = ( sourceData->status[1] >> 24 ) & 0xFF; targetData->INFORMATION_2 = ( sourceData->status[1] >> 16 ) & 0xFF; targetData->INFORMATION_3 = ( sourceData->status[1] >> 8 ) & 0xFF; targetData->INFORMATION_4 = sourceData->status[1] & 0xFF; targetData->ADDITIONAL_SENSE_LENGTH = 6; } if ( quadletCount > 2 ) { targetData->COMMAND_SPECIFIC_INFORMATION_1 = ( sourceData->status[2] >> 24 ) & 0xFF; targetData->COMMAND_SPECIFIC_INFORMATION_2 = ( sourceData->status[2] >> 16 ) & 0xFF; targetData->COMMAND_SPECIFIC_INFORMATION_3 = ( sourceData->status[2] >> 8 ) & 0xFF; targetData->COMMAND_SPECIFIC_INFORMATION_4 = sourceData->status[2] & 0xFF; targetData->ADDITIONAL_SENSE_LENGTH = 6; } if ( quadletCount > 3 ) { UInt8 count; // Get bytes to copy and clip if greater than sizeof SCSI_Sense_Data. count = ( quadletCount - 3 ) * sizeof ( UInt32 ); if ( count > 4 ) count = 4; bcopy ( &sourceData->status[3], &targetData->FIELD_REPLACEABLE_UNIT_CODE, count ); targetData->ADDITIONAL_SENSE_LENGTH = count + 6; } } } return returnValue; } //----------------------------------------------------------------------------- // ¥ LoginCompletionStatic - C->C++ glue method. [PROTECTED] //----------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::LoginCompletionStatic ( void * refCon, FWSBP2LoginCompleteParams * params ) { ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LoginCompletion ( params ); } //-------------------------------------------------------------------------------------------------- // LoginCompletion - Login completion handler. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::LoginCompletion ( FWSBP2LoginCompleteParams * params ) { DLOG ( ( "%s: LoginCompletion complete \n", getName () ) ); if ( ( params->status == kIOReturnSuccess ) && // ( kIOReturnSuccess ) ( ( params->statusBlock->details & 0x30 ) == 0 ) && // ( is 'resp' field == 0 ) ( params->statusBlock->sbpStatus == 0 ) ) // ( is 'sbp_status' field == 0 ) { fLoginRetryCount = 0; fLoggedIn = true; fNeedLogin = false; if ( reserved->fLoginState == kFirstTimeLoggingInState ) { reserved->fLoginState = kLogginSucceededState; fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState ); } submitOrbFromQueue (); loginResumed (); } else { if ( fLoginRetryCount < kMaxLoginRetryCount ) { fLoginRetryCount++; DLOG ( ( "%s: resubmitting Login\n", getName () ) ); IOReturn status = login (); if ( status != kIOReturnSuccess ) { if ( reserved->fLoginState == kFirstTimeLoggingInState ) { reserved->fLoginState = kLogginFailedState; // Wake up sleeping start thread. fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState ); } } } else { // Device can not be logged into after kMaxLoginRetryCount attemptes let's reset // the need login flag in case the device was unplugged during login. fNeedLogin = true; loginLost (); if ( reserved->fLoginState == kFirstTimeLoggingInState ) { reserved->fLoginState = kLogginFailedState; // Wake up sleeping start thread. fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState ); } } } } //-------------------------------------------------------------------------------------------------- // LogoutCompletionStatic - C->C++ glue. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::LogoutCompletionStatic ( void * refCon, FWSBP2LogoutCompleteParams * params ) { ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LogoutCompletion ( params ); } //-------------------------------------------------------------------------------------------------- // LogoutCompletion - Logout completion handler. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::LogoutCompletion ( FWSBP2LogoutCompleteParams * params ) { DEBUG_UNUSED ( params ); DLOG ( ( "%s: LogoutCompletion complete \n", getName () ) ); } //-------------------------------------------------------------------------------------------------- // UnsolicitedStatusNotifyStatic - C->C++ glue. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotifyStatic ( void * refCon, FWSBP2NotifyParams * params ) { ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->UnsolicitedStatusNotify ( params ); } //-------------------------------------------------------------------------------------------------- // UnsolicitedStatusNotify - Unsolicited status handler. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotify ( FWSBP2NotifyParams * params ) { DEBUG_UNUSED ( params ); DLOG ( ( "%s: UnsolicitedStatusNotify called\n", getName () ) ); // Parse and handle unsolicited status. fLogin->enableUnsolicitedStatus (); } //-------------------------------------------------------------------------------------------------- // FetchAgentResetCompleteStatic - C->C++ glue. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::FetchAgentResetCompleteStatic ( void * refCon, IOReturn status ) { ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->FetchAgentResetComplete ( status ); } //-------------------------------------------------------------------------------------------------- // FetchAgentResetComplete - Fetch agent reset handler. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::FetchAgentResetComplete ( IOReturn status ) { SBP2ClientOrbData * clientData; DEBUG_UNUSED ( status ); DLOG ( ( "%s: FetchAgentResetComplete called\n", getName () ) ); require ( fORB, exit ); // When orb chaining is implemented we will notify upper layer // to reconfigure device state and resubmitting commands clientData = ( SBP2ClientOrbData * ) fORB->getRefCon (); if ( clientData != NULL ) { if ( clientData->scsiTask != NULL ) { #ifdef _TRANSPORT_FAILURE_RETRIES_ if ( reserved->fLUNResetPathFlag && ( reserved->fLUNResetCount > 0 ) ) { reserved->fLUNResetCount--; submitOrbFromQueue (); } else #endif { CompleteSCSITask ( fORB ); } } } exit: reserved->fLUNResetPathFlag = false; } //-------------------------------------------------------------------------------------------------- // LunResetCompleteStatic - C->C++ glue. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::LunResetCompleteStatic ( void * refCon, IOReturn status, IOFireWireSBP2ManagementORB * orb ) { ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LunResetComplete ( status, orb ); } //-------------------------------------------------------------------------------------------------- // LunResetComplete - LUN reset completion handler. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::LunResetComplete ( IOReturn status, IOFireWireSBP2ManagementORB * orb ) { DEBUG_UNUSED ( status ); DEBUG_UNUSED ( orb ); DLOG ( ( "%s: LunResetComplete called\n", getName () ) ); fLogin->submitFetchAgentReset (); } //-------------------------------------------------------------------------------------------------- // ConnectToDeviceStatic - C->C++ glue. [PROTECTED] //-------------------------------------------------------------------------------------------------- IOReturn IOFireWireSerialBusProtocolTransport::ConnectToDeviceStatic ( OSObject * refCon, void * val1, void * val2, void * val3, void * val4 ) { DEBUG_UNUSED ( val1 ); DEBUG_UNUSED ( val2 ); DEBUG_UNUSED ( val3 ); DEBUG_UNUSED ( val4 ); ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->ConnectToDevice (); return kIOReturnSuccess; } //-------------------------------------------------------------------------------------------------- // ConnectToDevice - Connects to the device. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::ConnectToDevice ( void ) { IOReturn status; DLOG ( ( "%s: ConnectToDevice called\n", getName () ) ); // Avoid double logins during login phase. fNeedLogin = false; fLoginRetryCount = 0; status = login (); if ( status == kIOReturnSuccess ) { // Sleep the start thread - we'll wake it up on login completion. fCommandGate->commandSleep ( ( void * ) &reserved->fLoginState , THREAD_UNINT ); } } //-------------------------------------------------------------------------------------------------- // DisconnectFromDevice - Disconnects from device. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::DisconnectFromDevice ( void ) { DLOG ( ( "%s: DisconnectFromDevice called\n", getName () ) ); fLoggedIn = false; // Avoid logins during a logout phase. fNeedLogin = false; fLogin->submitLogout (); } //-------------------------------------------------------------------------------------------------- // CriticalOrbSubmissionStatic - C->C++ glue. [PROTECTED] //-------------------------------------------------------------------------------------------------- IOReturn IOFireWireSerialBusProtocolTransport::CriticalOrbSubmissionStatic ( OSObject * refCon, void * val1, void * val2, void * val3, void * val4 ) { DEBUG_UNUSED ( val3 ); DEBUG_UNUSED ( val4 ); ( ( IOFireWireSerialBusProtocolTransport * ) refCon )->CriticalOrbSubmission ( ( IOFireWireSBP2ORB * ) val1, ( SCSITaskIdentifier ) val2 ); return kIOReturnSuccess; } //-------------------------------------------------------------------------------------------------- // CriticalOrbSubmission - add command to queue on workloop. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::CriticalOrbSubmission ( IOFireWireSBP2ORB * orb, SCSITaskIdentifier request ) { SBP2ClientOrbData * clientData; clientData = ( SBP2ClientOrbData * ) orb->getRefCon (); require ( clientData, exit ); clientData->scsiTask = request; reserved->fSubmitQueue->returnCommand ( orb ); // Avoid double appending an active orb ( not this one ). if ( !fORB ) { submitOrbFromQueue (); } exit: return; } //-------------------------------------------------------------------------------------------------- // CriticalOrbSubmission - submitORB on workloop. [PROTECTED] //-------------------------------------------------------------------------------------------------- OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 6 ); void IOFireWireSerialBusProtocolTransport::submitOrbFromQueue ( ) { DLOG ( ( "%s: submitOrbFromQueue called\n", getName () ) ); // This check is necessary because we may be draining the queue on the requesting close path. if ( fLoggedIn ) { if ( !fORB ) { fORB = ( IOFireWireSBP2ORB * ) reserved->fSubmitQueue->getCommand (false); fReconnectCount = 0; } if ( fORB ) { fLogin->submitORB ( fORB ); } } } //-------------------------------------------------------------------------------------------------- // AllocateResources - Allocates resources. [PROTECTED] //-------------------------------------------------------------------------------------------------- IOReturn IOFireWireSerialBusProtocolTransport::AllocateResources ( void ) { IOReturn status; IOWorkLoop * workLoop = NULL; DLOG ( ( "%s: AllocateResources called\n", getName () ) ); fLogin = fSBPTarget->createLogin (); require_action ( fLogin, exit, status = kIOReturnNoMemory ); fLogin->setLoginFlags ( kFWSBP2ExclusiveLogin ); fLogin->setLoginRetryCountAndDelayTime ( 32, 1000000 ); //$$$ define constants for these fLogin->setMaxPayloadSize ( kMaxFireWirePayload ); fLogin->setStatusNotifyProc ( this, StatusNotifyStatic ); fLogin->setUnsolicitedStatusNotifyProc ( this, UnsolicitedStatusNotifyStatic ); fLogin->setLoginCompletion ( this, LoginCompletionStatic ); fLogin->setLogoutCompletion ( this, LogoutCompletionStatic ); fLogin->setFetchAgentResetCompletion ( this, FetchAgentResetCompleteStatic ); // Set BUSY_TIMEOUT register value see SBP-2 spec section 6.2 // also see IEEE Std 1394-1995 section 8.3.2.3.5 ( no I am not kidding ) fLogin->setBusyTimeoutRegisterValue ( kDefaultBusyTimeoutValue ); fLUNResetORB = fSBPTarget->createManagementORB ( this, LunResetCompleteStatic ); require_action ( fLUNResetORB, exit, status = kIOReturnNoMemory ); fLUNResetORB->setCommandFunction ( kFWSBP2LogicalUnitReset ); fLUNResetORB->setManageeCommand ( fLogin ); // Allocate expansion data. reserved = ( ExpansionData * ) IOMalloc ( sizeof ( ExpansionData ) ); require_action ( reserved, exit, status = kIOReturnNoMemory ); bzero ( reserved, sizeof ( ExpansionData ) ); reserved->fLoginState = kFirstTimeLoggingInState; // Cache this as a member variable since we don't want to do this on every command. #define kAlwaysSetAutoSenseData "Always Set AutoSense Data" reserved->fAlwaysSetSenseData = getProperty ( kAlwaysSetAutoSenseData, gIOServicePlane ) ? TRUE : FALSE; workLoop = getWorkLoop (); require_action ( workLoop, exit, status = kIOReturnNoMemory ); reserved->fCommandPool = IOCommandPool::withWorkLoop ( workLoop ); require_action ( reserved->fCommandPool, exit, status = kIOReturnNoMemory ); reserved->fSubmitQueue = IOCommandPool::withWorkLoop ( workLoop ); require_action ( reserved->fSubmitQueue, exit, status = kIOReturnNoMemory ); for ( UInt32 i = 0; i < kCommandPoolOrbCount; ++i ) { IOFireWireSBP2ORB * orb; SBP2ClientOrbData * clientData = NULL; orb = fLogin->createORB (); require_action ( orb, exit, status = kIOReturnNoMemory ); clientData = ( SBP2ClientOrbData * ) IOMalloc ( sizeof ( SBP2ClientOrbData ) ); require_action ( clientData, exit, status = kIOReturnNoMemory ); bzero ( clientData, sizeof ( SBP2ClientOrbData ) ); clientData->orb = orb; orb->setRefCon ( ( void * ) clientData ); // Enqueue the command in the free list. reserved->fCommandPool->returnCommand ( orb ); } status = kIOReturnSuccess; exit: return status; } //-------------------------------------------------------------------------------------------------- // DeallocateResources - Deallocates resources. [PROTECTED] //-------------------------------------------------------------------------------------------------- void IOFireWireSerialBusProtocolTransport::DeallocateResources ( void ) { IOFireWireSBP2ORB * orb; SBP2ClientOrbData * clientData; orb = NULL; clientData = NULL; DLOG ( ( "%s: DeallocateResources called\n", getName () ) ); // /!\ WARNING - always release orb's before logins. if ( fLUNResetORB != NULL ) { fLUNResetORB->release (); fLUNResetORB = NULL; } // Drain the queue when requesting close so there are no in use commands when this is called. while ( ( orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false ) ) ) { clientData = ( SBP2ClientOrbData * ) orb->getRefCon (); if ( clientData ) { IOFree ( clientData, sizeof ( SBP2ClientOrbData ) ); clientData = NULL; } orb->release (); orb = NULL; } reserved->fCommandPool->release (); reserved->fCommandPool = NULL; reserved->fSubmitQueue->release (); reserved->fSubmitQueue = NULL; if ( fLogin != NULL ) { fLogin->release (); fLogin = NULL; } } //-------------------------------------------------------------------------------------------------- // login - login bottleneck to track retries. [PROTECTED] //-------------------------------------------------------------------------------------------------- OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 1 ); IOReturn IOFireWireSerialBusProtocolTransport::login ( void ) { DLOG ( ( "%s: submitting login.\n", getName () ) ); IOReturn status; fNeedLogin = false; fLoggedIn = false; // If we enter this again and fLoginRetryCount is already // at kMaxLoginRetryCount - we should default status to an error. status = kIOReturnError; for ( ; fLoginRetryCount < kMaxLoginRetryCount; ++fLoginRetryCount ) { status = submitLogin (); if ( status == kIOReturnSuccess ) { break; } } if ( status != kIOReturnSuccess ) { fNeedLogin = true; fLoggedIn = false; loginLost (); } return status; } //-------------------------------------------------------------------------------------------------- // submitLogin - submitLogin bottleneck for subclass. [PROTECTED] //-------------------------------------------------------------------------------------------------- OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 2 ); IOReturn IOFireWireSerialBusProtocolTransport::submitLogin ( void ) { IOReturn status; DLOG ( ( "%s: submitting login.\n", getName () ) ); status = fLogin->submitLogin (); return status; } //-------------------------------------------------------------------------------------------------- // loginLost - login lost bottleneck for subclass. [PROTECTED] //-------------------------------------------------------------------------------------------------- OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 3 ); void IOFireWireSerialBusProtocolTransport::loginLost ( void ) { DLOG ( ( "%s: login lost.\n", getName () ) ); // Notification that the login is lost. } //-------------------------------------------------------------------------------------------------- // loginSuspended - login resumed bottleneck for subclass. [PROTECTED] //-------------------------------------------------------------------------------------------------- OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 4 ); void IOFireWireSerialBusProtocolTransport::loginSuspended ( void ) { DLOG ( ( "%s: login suspended.\n", getName () ) ); // A successful reconnect orb is required. } //-------------------------------------------------------------------------------------------------- // loginResumed - login resumed bottleneck for subclass. [PROTECTED] //-------------------------------------------------------------------------------------------------- OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 5 ); void IOFireWireSerialBusProtocolTransport::loginResumed ( void ) { DLOG ( ( "%s: login resumed.\n", getName () ) ); // A reconnect orb has succeeded. } //-------------------------------------------------------------------------------------------------- // Binary compatibility reserved method space. //-------------------------------------------------------------------------------------------------- #if 0 #pragma mark == VTable Padding == #endif OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 7 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 8 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 9 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 10 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 11 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 12 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 13 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 14 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 15 ); OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 16 ); //-------------------------------------------------------------------------------------------------- // EOF //--------------------------------------------------------------------------------------------------