IOFireWireSerialBusProtocolTransport.cpp [plain text]
#include "IOFireWireSerialBusProtocolTransport.h"
#include <IOKit/firewire/IOConfigDirectory.h>
#include <IOKit/firewire/IOFireWireDevice.h>
#if 0
#pragma mark -
#pragma mark == Macros ==
#pragma mark -
#endif
#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 STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define super IOSCSIProtocolServices
OSDefineMetaClassAndStructors ( IOFireWireSerialBusProtocolTransport, IOSCSIProtocolServices )
#if 0
#pragma mark -
#pragma mark == Constants ==
#pragma mark -
#endif
#define kSBP2ReceiveBufferByteCountKey "SBP2ReceiveBufferByteCount"
#define kDefaultIOBlockCount 256
#define kCRSModelInfo_ValidBitsMask 0x00FFFFFF
#define kCRSModelInfo_TargetDiskMode 0x0054444D
#define kIOFireWireMessageServiceIsRequestingClose kIOFWMessageServiceIsRequestingClose
enum {
kFireWireSBP2CommandTransferDataToTarget = 0L,
kFireWireSBP2CommandTransferDataFromTarget = kFWSBP2CommandTransferDataFromTarget
};
#if 0
#pragma mark -
#pragma mark == Static Debug Assertion Method ==
#pragma mark -
#endif
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" );
}
#if 0
#pragma mark -
#pragma mark == Public Methods ==
#pragma mark -
#endif
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;
}
bool IOFireWireSerialBusProtocolTransport::start ( IOService * provider )
{
IOReturn status = kIOReturnSuccess;
Boolean returnValue = false;
Boolean openSucceeded;
fSBPTarget = OSDynamicCast ( IOFireWireSBP2LUN, provider );
require ( fSBPTarget, exit );
openSucceeded = super::start ( provider );
require ( openSucceeded, exit );
openSucceeded = provider->open ( this );
require ( openSucceeded, exit );
fUnit = fSBPTarget->getFireWireUnit ();
require ( fUnit, exit );
fUnit->setNodeFlags ( kIOFWEnableRetryOnAckD );
status = AllocateResources ();
require_noerr ( status, exit );
fCommandGate->runAction ( ConnectToDeviceStatic );
if ( reserved->fLoginState == kLogginSucceededState )
{
registerService ();
}
STATUS_LOG ( ( "%s: start complete\n", getName () ) );
returnValue = true;
InitializePowerManagement ( provider );
exit:
if ( returnValue == false )
{
STATUS_LOG ( ( "%s: start failed. status = %x\n", getName (), status) );
cleanUp ();
}
return returnValue;
}
void IOFireWireSerialBusProtocolTransport::cleanUp ( void )
{
STATUS_LOG ( ( "%s: cleanUp called\n", getName () ) );
if ( fSBPTarget != NULL )
{
DeallocateResources ();
if ( fSBPTarget->isOpen ( this ) )
{
fSBPTarget->close ( this );
}
fSBPTarget = NULL;
}
}
#if 0
#pragma mark -
#pragma mark == Protected Methods ==
#pragma mark -
#endif
IOFireWireSBP2ORB * IOFireWireSerialBusProtocolTransport::CommandORBAccessor ( void )
{
return fORB;
}
IOFireWireSBP2Login * IOFireWireSerialBusProtocolTransport::SBP2LoginAccessor ( void )
{
return fLogin;
}
IOReturn IOFireWireSerialBusProtocolTransport::message ( UInt32 type,
IOService * nub,
void * arg )
{
SBP2ClientOrbData * clientData = NULL;
IOReturn status = kIOReturnSuccess;
switch ( type )
{
case kIOMessageServiceIsSuspended:
STATUS_LOG ( ( "%s: kIOMessageServiceIsSuspended\n", getName () ) );
fLoggedIn = false;
break;
case kIOMessageServiceIsResumed:
STATUS_LOG ( ( "%s: kIOMessageServiceIsResumed\n", getName () ) );
if ( fNeedLogin )
{
fNeedLogin = false;
fLoginRetryCount = 0;
if ( fLogin != NULL )
{
login ();
}
}
break;
case kIOMessageFWSBP2ReconnectComplete:
STATUS_LOG ( ( "%s: kIOMessageFWSBP2ReconnectComplete\n", getName () ) );
fLoggedIn = true;
clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ();
if ( clientData != NULL )
{
if ( ( clientData->scsiTask != NULL ) && ( fReconnectCount < kMaxReconnectCount ) )
{
STATUS_LOG ( ( "%s: resubmit orb \n", getName () ) );
fReconnectCount++;
fLogin->submitORB ( fORB );
}
else
{
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_No_Status;
CompleteSCSITask ( fORB );
}
}
break;
case kIOMessageFWSBP2ReconnectFailed:
STATUS_LOG ( ( "%s: kIOMessageFWSBP2ReconnectFailed\n", getName () ) );
fLoginRetryCount = 0;
login ();
break;
case kIOFireWireMessageServiceIsRequestingClose:
STATUS_LOG ( ( "%s: kIOFireWireMessageServiceIsRequestingClose\n", getName () ) );
SendNotification_DeviceRemoved ();
if ( fORB != NULL )
{
clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ();
if ( clientData != NULL )
{
if ( clientData->scsiTask != NULL )
{
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_No_Status;
CompleteSCSITask ( fORB );
}
}
}
if ( fSBPTarget != NULL )
{
if ( fSBPTarget->isOpen ( this ) )
{
fSBPTarget->close ( this );
}
}
break;
case kIOMessageServiceIsTerminated:
STATUS_LOG ( ( "%s: kIOMessageServiceIsTerminated\n", getName () ) );
cleanUp ();
break;
default:
status = IOService::message (type, nub, arg);
break;
}
return status;
}
bool IOFireWireSerialBusProtocolTransport::SendSCSICommand ( SCSITaskIdentifier request,
SCSIServiceResponse * serviceResponse,
SCSITaskStatus * taskStatus )
{
SBP2ClientOrbData * clientData = NULL;
IOFireWireSBP2ORB * orb = NULL;
SCSICommandDescriptorBlock cdb = { 0 };
UInt8 commandLength = 0;
UInt32 commandFlags = 0;
UInt32 timeOut = 0;
bool commandProcessed = true;
STATUS_LOG ( ( "%s: SendSCSICommand called\n", getName () ) );
*serviceResponse = kSCSIServiceResponse_Request_In_Process;
*taskStatus = kSCSITaskStatus_No_Status;
if ( isInactive () )
{
*serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
commandProcessed = false;
goto exit;
}
orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false );
if ( orb == NULL )
{
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 )
{
STATUS_LOG ( ( "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 )
{
STATUS_LOG ( ( "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 )
{
STATUS_LOG ( ( "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
fReconnectCount = 0;
commandFlags = ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromTargetToInitiator ) ?
kFireWireSBP2CommandTransferDataFromTarget :
kFireWireSBP2CommandTransferDataToTarget;
orb->setCommandFlags ( commandFlags |
kFWSBP2CommandCompleteNotify |
kFWSBP2CommandImmediate |
kFWSBP2CommandNormalORB );
clientData->scsiTask = request;
SetCommandBuffers ( orb, request );
orb->setCommandBlock ( cdb, commandLength );
timeOut = GetTimeoutDuration ( request );
if ( timeOut == 0 )
{
timeOut = 0xFFFFFFFF;
}
orb->setCommandTimeout ( timeOut );
if ( fLoggedIn )
{
fLogin->submitORB ( orb );
}
exit:
STATUS_LOG ( ( "%s: SendSCSICommand exit, Service Response = %x\n", getName (), *serviceResponse) );
return commandProcessed;
}
IOReturn IOFireWireSerialBusProtocolTransport::SetCommandBuffers ( IOFireWireSBP2ORB * orb,
SCSITaskIdentifier request )
{
return orb->setCommandBuffers ( GetDataBuffer ( request ),
GetDataBufferOffset ( request ),
GetRequestedDataTransferCount ( request ) );
}
void IOFireWireSerialBusProtocolTransport::CompleteSCSITask ( IOFireWireSBP2ORB * orb )
{
SBP2ClientOrbData * clientData = NULL;
STATUS_LOG ( ( "%s: CompleteSCSITask called\n", getName () ) );
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ();
if ( clientData != NULL )
{
if ( clientData->scsiTask != NULL )
{
SCSITaskIdentifier scsiTask = NULL;
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskStatus taskStatus = kSCSITaskStatus_No_Status;
IOByteCount bytesTransfered = 0;
orb->releaseCommandBuffers ();
if ( clientData->taskStatus == kSCSITaskStatus_GOOD )
{
bytesTransfered = GetRequestedDataTransferCount ( clientData->scsiTask );
}
SetRealizedDataTransferCount ( clientData->scsiTask, bytesTransfered );
scsiTask = clientData->scsiTask;
serviceResponse = clientData->serviceResponse;
taskStatus = clientData->taskStatus;
clientData->scsiTask = NULL;
reserved->fCommandPool->returnCommand ( orb );
CommandCompleted ( scsiTask, serviceResponse, taskStatus );
}
}
}
SCSIServiceResponse IOFireWireSerialBusProtocolTransport::AbortSCSICommand ( SCSITaskIdentifier request )
{
DEUBUG_UNUSED ( request );
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_FUNCTION_REJECTED;
STATUS_LOG ( ( "%s: AbortSCSICommand called\n", getName () ) );
return serviceResponse;
}
bool IOFireWireSerialBusProtocolTransport::IsProtocolServiceSupported ( SCSIProtocolFeature feature,
void * serviceValue )
{
bool isSupported = false;
STATUS_LOG ( ( "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;
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;
default:
break;
}
return isSupported;
}
bool IOFireWireSerialBusProtocolTransport::HandleProtocolServiceFeature ( SCSIProtocolFeature feature,
void * serviceValue )
{
DEUBUG_UNUSED ( feature );
DEUBUG_UNUSED ( serviceValue );
return false;
}
bool IOFireWireSerialBusProtocolTransport::IsDeviceCPUInDiskMode ( void )
{
UInt32 csrModelInfo = 0;
IOConfigDirectory * directory = NULL;
IOFireWireDevice * device = NULL;
IOReturn status = kIOReturnSuccess;
IOService * providerService = fUnit->getProvider ();
bool isCPUDiskMode = false;
STATUS_LOG ( ( "%s: IsDeviceCPUInDiskMode was called\n", getName () ) );
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:
STATUS_LOG ( ( "%s: CPU Disk Mode = %d\n", getName (), isCPUDiskMode ) );
return isCPUDiskMode;
}
void IOFireWireSerialBusProtocolTransport::StatusNotifyStatic ( void * refCon,
FWSBP2NotifyParams * params )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->StatusNotify ( params );
}
void IOFireWireSerialBusProtocolTransport::StatusNotify ( FWSBP2NotifyParams * params )
{
IOFireWireSBP2ORB * orb = NULL;
FWSBP2StatusBlock * statusBlock = NULL;
SBP2ClientOrbData * clientData = NULL;
SCSI_Sense_Data * targetData = NULL;
UInt8 senseData[kSenseDefaultSize + 8] = { 0 };
targetData = ( SCSI_Sense_Data * ) &senseData[0];
if ( ( params->message != NULL ) && ( params->length != 0 ) )
{
orb = ( IOFireWireSBP2ORB * ) params->commandObject;
statusBlock = ( FWSBP2StatusBlock * ) params->message;
if ( orb != NULL )
{
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ();
}
}
switch ( params->notificationEvent )
{
case kFWSBP2NormalCommandStatus:
if ( ( clientData != NULL ) && ( statusBlock->details & 0x08 ) )
{
SetValidAutoSenseData ( clientData, statusBlock, targetData );
fLogin->submitFetchAgentReset ();
}
else if ( clientData &&
( ( statusBlock->details & 0x30 ) == 0 ) && ( ( statusBlock->details & 0x07 ) == 1 ) && ( statusBlock->sbpStatus == 0 ) ) {
clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE;
clientData->taskStatus = kSCSITaskStatus_GOOD;
CompleteSCSITask ( orb );
STATUS_LOG ( ( "%s: StatusNotify normal complete \n", getName () ) );
}
else if ( clientData )
{
SetValidAutoSenseData ( clientData, statusBlock, targetData );
CompleteSCSITask ( orb );
STATUS_LOG ( ( "%s: StatusNotify unexpected error? \n", getName () ) );
}
break;
case kFWSBP2NormalCommandTimeout:
STATUS_LOG ( ( "%s: kFWSBP2NormalCommandTimeout \n", getName () ) );
if ( clientData )
{
if ( clientData->scsiTask )
{
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_No_Status;
CompleteSCSITask ( orb );
}
}
fLUNResetORB->submit ();
break;
case kFWSBP2NormalCommandReset:
STATUS_LOG ( ( "%s: kFWSBP2NormalCommandReset\n", getName () ) );
if ( clientData != NULL )
{
if ( clientData->scsiTask != NULL )
{
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_No_Status;
CompleteSCSITask ( orb );
}
}
break;
default:
STATUS_LOG ( ( "%s: StatusNotify with unknown notificationEvent\n", getName () ) );
break;
}
}
void IOFireWireSerialBusProtocolTransport::SetValidAutoSenseData ( SBP2ClientOrbData * clientData,
FWSBP2StatusBlock * statusBlock,
SCSI_Sense_Data * targetData )
{
UInt8 quadletCount = 0;
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_No_Status;
quadletCount = ( statusBlock->details & 0x07 ) - 1 ;
if ( ( statusBlock->details & 0x30 ) == 0 )
{
clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE;
clientData->taskStatus = CoalesceSenseData ( statusBlock, quadletCount, targetData );
}
if ( clientData->taskStatus == kSCSITaskStatus_CHECK_CONDITION )
{
if ( clientData->scsiTask != NULL )
{
SetAutoSenseData ( clientData->scsiTask, targetData, kSenseDefaultSize + 8 );
}
}
}
SCSITaskStatus IOFireWireSerialBusProtocolTransport::CoalesceSenseData ( FWSBP2StatusBlock * sourceData,
UInt8 quadletCount,
SCSI_Sense_Data * targetData )
{
SCSITaskStatus returnValue = kSCSITaskStatus_GOOD;
UInt8 statusBlockFormat = 0;
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;
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;
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;
}
void IOFireWireSerialBusProtocolTransport::LoginCompletionStatic ( void * refCon,
FWSBP2LoginCompleteParams * params )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LoginCompletion ( params );
}
void IOFireWireSerialBusProtocolTransport::LoginCompletion ( FWSBP2LoginCompleteParams * params )
{
SBP2ClientOrbData * clientData = NULL;
STATUS_LOG ( ( "%s: LoginCompletion complete \n", getName () ) );
if ( ( params->status == kIOReturnSuccess ) && ( ( params->statusBlock->details & 0x30 ) == 0 ) && ( params->statusBlock->sbpStatus == 0 ) ) {
fLoginRetryCount = 0;
fLoggedIn = true;
fNeedLogin = false;
if ( reserved->fLoginState == kFirstTimeLoggingInState )
{
reserved->fLoginState = kLogginSucceededState;
fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
}
clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ();
if ( clientData != NULL )
{
if ( clientData->scsiTask )
{
fLogin->submitORB ( fORB );
}
}
loginResumed ();
}
else
{
if ( fLoginRetryCount < kMaxLoginRetryCount )
{
fLoginRetryCount++;
STATUS_LOG ( ( "%s: resubmitting Login\n", getName () ) );
IOReturn status = login ();
if ( status != kIOReturnSuccess )
{
if ( reserved->fLoginState == kFirstTimeLoggingInState )
{
reserved->fLoginState = kLogginFailedState;
fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
}
}
}
else
{
fNeedLogin = true;
loginLost ();
if ( reserved->fLoginState == kFirstTimeLoggingInState )
{
reserved->fLoginState = kLogginFailedState;
fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
}
}
}
}
void IOFireWireSerialBusProtocolTransport::LogoutCompletionStatic ( void * refCon, FWSBP2LogoutCompleteParams * params )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LogoutCompletion ( params );
}
void IOFireWireSerialBusProtocolTransport::LogoutCompletion ( FWSBP2LogoutCompleteParams * params )
{
DEUBUG_UNUSED ( params );
STATUS_LOG ( ( "%s: LogoutCompletion complete \n", getName () ) );
}
void IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotifyStatic ( void * refCon,
FWSBP2NotifyParams * params )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->UnsolicitedStatusNotify ( params );
}
void IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotify ( FWSBP2NotifyParams * params )
{
DEUBUG_UNUSED ( params );
STATUS_LOG ( ( "%s: UnsolicitedStatusNotify called\n", getName () ) );
fLogin->enableUnsolicitedStatus ();
}
void IOFireWireSerialBusProtocolTransport::FetchAgentResetCompleteStatic ( void * refCon,
IOReturn status )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->FetchAgentResetComplete ( status );
}
void IOFireWireSerialBusProtocolTransport::FetchAgentResetComplete ( IOReturn status )
{
DEUBUG_UNUSED ( status );
SBP2ClientOrbData * clientData = NULL;
STATUS_LOG ( ( "%s: FetchAgentResetComplete called\n", getName () ) );
clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ();
if ( clientData != NULL )
{
if ( clientData->scsiTask != NULL )
{
CompleteSCSITask ( fORB );
}
}
}
void IOFireWireSerialBusProtocolTransport::LunResetCompleteStatic ( void * refCon,
IOReturn status,
IOFireWireSBP2ManagementORB * orb )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LunResetComplete ( status, orb );
}
void IOFireWireSerialBusProtocolTransport::LunResetComplete ( IOReturn status, IOFireWireSBP2ManagementORB * orb )
{
DEUBUG_UNUSED ( status );
DEUBUG_UNUSED ( orb );
STATUS_LOG ( ( "%s: LunResetComplete called\n", getName () ) );
fLogin->submitFetchAgentReset ();
}
IOReturn IOFireWireSerialBusProtocolTransport::ConnectToDeviceStatic ( OSObject * refCon,
void * val1,
void * val2,
void * val3,
void * val4 )
{
DEUBUG_UNUSED ( val1 );
DEUBUG_UNUSED ( val2 );
DEUBUG_UNUSED ( val3 );
DEUBUG_UNUSED ( val4 );
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->ConnectToDevice ();
return kIOReturnSuccess;
}
void IOFireWireSerialBusProtocolTransport::ConnectToDevice ( void )
{
STATUS_LOG ( ( "%s: ConnectToDevice called\n", getName () ) );
IOReturn status;
fNeedLogin = false;
fLoginRetryCount = 0;
status = login ();
if ( status == kIOReturnSuccess )
{
fCommandGate->commandSleep ( ( void * ) &reserved->fLoginState , THREAD_UNINT );
}
}
void IOFireWireSerialBusProtocolTransport::DisconnectFromDevice ( void )
{
STATUS_LOG ( ( "%s: DisconnectFromDevice called\n", getName () ) );
fLoggedIn = false;
fNeedLogin = false;
fLogin->submitLogout ();
}
IOReturn IOFireWireSerialBusProtocolTransport::AllocateResources ( void )
{
IOReturn status;
SBP2ClientOrbData * clientData = NULL;
IOWorkLoop * workLoop = NULL;
STATUS_LOG ( ( "%s: AllocateResources called\n", getName () ) );
fLogin = fSBPTarget->createLogin ();
require_action ( fLogin, exit, status = kIOReturnNoMemory );
fORB = fLogin->createORB ();
require_action ( fORB, exit, status = kIOReturnNoMemory );
clientData = ( SBP2ClientOrbData * ) IOMalloc ( sizeof ( SBP2ClientOrbData ) );
require_action ( clientData, exit, status = kIOReturnNoMemory );
bzero ( clientData, sizeof ( SBP2ClientOrbData ) );
clientData->orb = fORB;
fORB->setRefCon ( ( void * ) clientData );
fLogin->setLoginFlags ( kFWSBP2ExclusiveLogin );
fLogin->setLoginRetryCountAndDelayTime ( 32, 1000000 );
fLogin->setMaxPayloadSize ( kMaxFireWirePayload );
fLogin->setStatusNotifyProc ( this, StatusNotifyStatic );
fLogin->setUnsolicitedStatusNotifyProc ( this, UnsolicitedStatusNotifyStatic );
fLogin->setLoginCompletion ( this, LoginCompletionStatic );
fLogin->setLogoutCompletion ( this, LogoutCompletionStatic );
fLogin->setFetchAgentResetCompletion ( this, FetchAgentResetCompleteStatic );
fLogin->setBusyTimeoutRegisterValue ( kDefaultBusyTimeoutValue );
fLUNResetORB = fSBPTarget->createManagementORB ( this, LunResetCompleteStatic );
require_action ( fLUNResetORB, exit, status = kIOReturnNoMemory );
fLUNResetORB->setCommandFunction ( kFWSBP2LogicalUnitReset );
fLUNResetORB->setManageeCommand ( fLogin );
reserved = ( ExpansionData * ) IOMalloc ( sizeof ( ExpansionData ) );
require_action ( reserved, exit, status = kIOReturnNoMemory );
bzero ( reserved, sizeof ( ExpansionData ) );
reserved->fLoginState = kFirstTimeLoggingInState;
workLoop = getWorkLoop ();
require_action ( workLoop, exit, status = kIOReturnNoMemory );
reserved->fCommandPool = IOCommandPool::withWorkLoop ( workLoop );
require_action ( reserved->fCommandPool, exit, status = kIOReturnNoMemory );
reserved->fCommandPool->returnCommand ( fORB );
status = kIOReturnSuccess;
exit:
return status;
}
void IOFireWireSerialBusProtocolTransport::DeallocateResources ( void )
{
SBP2ClientOrbData * clientData = NULL;
STATUS_LOG ( ( "%s: DeallocateResources called\n", getName () ) );
if ( reserved != NULL )
{
if ( reserved->fCommandPool != NULL )
{
reserved->fCommandPool->release ();
reserved->fCommandPool = NULL;
}
IOFree ( reserved, sizeof ( ExpansionData ) );
reserved = NULL;
}
if ( fLUNResetORB != NULL )
{
fLUNResetORB->release ();
fLUNResetORB = NULL;
}
if ( fORB != NULL )
{
clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ();
if ( clientData != NULL )
{
IOFree ( clientData, sizeof ( SBP2ClientOrbData ) );
}
fORB->release ();
fORB = NULL;
}
if ( fLogin != NULL )
{
fLogin->release ();
fLogin = NULL;
}
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 1 );
IOReturn IOFireWireSerialBusProtocolTransport::login ( void )
{
STATUS_LOG ( ( "%s: submitting login.\n", getName () ) );
IOReturn status;
fNeedLogin = false;
fLoggedIn = false;
status = kIOReturnSuccess;
for ( ; fLoginRetryCount < kMaxLoginRetryCount; ++fLoginRetryCount )
{
status = submitLogin ();
if ( status == kIOReturnSuccess )
{
break;
}
}
if ( status != kIOReturnSuccess )
{
fNeedLogin = true;
fLoggedIn = false;
loginLost ();
}
return status;
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 2 );
IOReturn IOFireWireSerialBusProtocolTransport::submitLogin ( void )
{
STATUS_LOG ( ( "%s: submitting login.\n", getName () ) );
IOReturn status = kIOReturnSuccess;
status = fLogin->submitLogin ();
return status;
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 3 );
void IOFireWireSerialBusProtocolTransport::loginLost ( void )
{
STATUS_LOG ( ( "%s: login lost.\n", getName () ) );
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 4 );
void IOFireWireSerialBusProtocolTransport::loginSuspended ( void )
{
STATUS_LOG ( ( "%s: login suspended.\n", getName () ) );
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 5 );
void IOFireWireSerialBusProtocolTransport::loginResumed ( void )
{
STATUS_LOG ( ( "%s: login resumed.\n", getName () ) );
}
#if 0
#pragma mark -
#pragma mark == VTable Padding ==
#pragma mark -
#endif
OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 6 );
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 );