IOFireWireSerialBusProtocolTransport.cpp [plain text]
#include <sys/sysctl.h>
#include <IOKit/firewire/IOConfigDirectory.h>
#include <IOKit/firewire/IOFireWireDevice.h>
#include <IOKit/IOKitKeys.h>
#include "IOFireWireSerialBusProtocolTransport.h"
#include "IOFireWireSerialBusProtocolTransportTimestamps.h"
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "FireWire SBP2 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) panic 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 )
#define TRANSPORT_FAILURE_RETRIES 1
typedef struct FWSBP2SCSIStatusBlock
{
UInt8 details;
UInt8 sbpStatus;
UInt16 orbOffsetHi;
UInt32 orbOffsetLo;
UInt8 status;
UInt8 senseKey;
UInt8 ASC;
UInt8 ASCQ;
UInt32 information;
UInt32 commandSpecificInformation;
UInt32 senseKeyDependent;
} FWSBP2SCSIStatusBlock;
enum
{
kSBP2StatusBlock_Details_DeadBit = 3,
kSBP2StatusBlock_Details_LenMask = 0x7,
kSBP2StatusBlock_Details_DeadMask = (1 << kSBP2StatusBlock_Details_DeadBit),
kSBP2StatusBlock_Details_RespMask = 0x30,
kSBP2StatusBlock_Details_SrcMask = 0xC0
};
enum
{
kSBP2StatusBlock_Resp_REQUEST_COMPLETE = 0,
kSBP2StatusBlock_Resp_TRANSPORT_FAILURE = 1,
kSBP2StatusBlock_Resp_ILLEGAL_REQUEST = 2,
kSBP2StatusBlock_Resp_VENDOR_DEPENDENT = 3
};
enum
{
kSBP2StatusBlock_SBPStatus_NoAdditionalInformation = 0,
kSBP2StatusBlock_SBPStatus_RequestTypeUnsupported = 1,
kSBP2StatusBlock_SBPStatus_SpeedUnsupported = 2,
kSBP2StatusBlock_SBPStatus_PageSizeUnsupported = 3,
kSBP2StatusBlock_SBPStatus_AccessDenied = 4,
kSBP2StatusBlock_SBPStatus_LogicalUnitNotSupported = 5,
kSBP2StatusBlock_SBPStatus_MaxPayloadTooSmall = 6,
kSBP2StatusBlock_SBPStatus_ResourcesUnavailable = 8,
kSBP2StatusBlock_SBPStatus_FunctionRejected = 9,
kSBP2StatusBlock_SBPStatus_LoginIDNotRecognized = 10,
kSBP2StatusBlock_SBPStatus_DummyORBCompleted = 11,
kSBP2StatusBlock_SBPStatus_RequestAborted = 12,
kSBP2StatusBlock_SBPStatus_UnspecifiedError = 0xFF
};
enum
{
kFWSBP2SCSIStatusBlock_StatusBlockFormatCurrentError = (0 << 6),
kFWSBP2SCSIStatusBlock_StatusBlockFormatDeferredError = (1 << 6),
kFWSBP2SCSIStatusBlock_StatusBlockFormatMask = 0xC0,
kFWSBP2SCSIStatusBlock_StatusBlockStatusMask = 0x3F
};
enum
{
kFWSBP2SCSIStatusBlock_SenseKeyMask = 0x0F,
kFWSBP2SCSIStatusBlock_ILI_Bit = 4,
kFWSBP2SCSIStatusBlock_ILI_Mask = (1 << kFWSBP2SCSIStatusBlock_ILI_Bit),
kFWSBP2SCSIStatusBlock_EOM_Bit = 5,
kFWSBP2SCSIStatusBlock_EOM_Mask = (1 << kFWSBP2SCSIStatusBlock_EOM_Bit),
kFWSBP2SCSIStatusBlock_FILEMARK_Bit = 6,
kFWSBP2SCSIStatusBlock_FILEMARK_Mask = (1 << kFWSBP2SCSIStatusBlock_FILEMARK_Bit),
kFWSBP2SCSIStatusBlock_VALID_Bit = 7,
kFWSBP2SCSIStatusBlock_VALID_Mask = (1 << kFWSBP2SCSIStatusBlock_VALID_Bit),
kFWSBP2SCSIStatusBlock_MEI_Mask = kFWSBP2SCSIStatusBlock_ILI_Mask | kFWSBP2SCSIStatusBlock_EOM_Mask | kFWSBP2SCSIStatusBlock_FILEMARK_Mask
};
#define kPreferredNameKey "Preferred Name"
#define kFireWireGUIDKey "GUID"
#define kFireWireVendorNameKey "FireWire Vendor Name"
#define kSBP2ReceiveBufferByteCountKey "SBP2ReceiveBufferByteCount"
#define kAlwaysSetAutoSenseData "Always Set AutoSense Data"
#define kDefaultIOBlockCount 256
#define kCRSModelInfo_ValidBitsMask 0x00FFFFFF
#define kCRSModelInfo_TargetDiskMode 0x0054444D
#define kIOFireWireMessageServiceIsRequestingClose kIOFWMessageServiceIsRequestingClose
#define kDefaultTimeOutValue 30000
#define kCommandPoolOrbCount 1
#define kFWSBP2DefaultPageTableEntriesCount 512
#define kDoubleBufferCommandSizeCheckThreshold 512
#define kLoginRetryCount 32
#define kLoginDelayTime 1000000
enum
{
kFireWireSBP2CommandTransferDataToTarget = 0L,
kFireWireSBP2CommandTransferDataFromTarget = kFWSBP2CommandTransferDataFromTarget
};
class FWSBP2TransportGlobals
{
public:
FWSBP2TransportGlobals ( void );
virtual ~FWSBP2TransportGlobals ( void );
};
static inline void
RecordFireWireTimeStamp (
unsigned int code,
unsigned int a = 0, unsigned int b = 0,
unsigned int c = 0, unsigned int d = 0 );
static int
FirewireSBPTransportSysctl (
struct sysctl_oid * oidp,
void * arg1,
int arg2,
struct sysctl_req * req );
static FWSBP2TransportGlobals gFWGlobals;
UInt32 gSBP2DiskDebugFlags = 0;
SYSCTL_PROC ( _debug, OID_AUTO, FirewireSBPTransport, CTLFLAG_RW, 0, 0, FirewireSBPTransportSysctl, "FirewireSBPTransport", "FireWire SBP2 Transport debug interface" );
static int
FirewireSBPTransportSysctl ( struct sysctl_oid * oidp, void * arg1, int arg2, struct sysctl_req * req )
{
int error = 0;
FWSysctlArgs fwArgs;
DEBUG_UNUSED ( oidp );
DEBUG_UNUSED ( arg1 );
DEBUG_UNUSED ( arg2 );
DLOG ( ( "+FirewireSBPTransportSysctl: gSBP2DiskDebugFlags = 0x%08X\n", ( unsigned int ) gSBP2DiskDebugFlags ) );
error = SYSCTL_IN ( req, &fwArgs, sizeof ( fwArgs ) );
if ( ( error == 0 ) && ( fwArgs.type == kFWTypeDebug ) )
{
if ( fwArgs.operation == kFWOperationGetFlags )
{
fwArgs.debugFlags = gSBP2DiskDebugFlags;
error = SYSCTL_OUT ( req, &fwArgs, sizeof ( fwArgs ) );
}
else if ( fwArgs.operation == kFWOperationSetFlags )
{
gSBP2DiskDebugFlags = fwArgs.debugFlags;
}
}
DLOG ( ( "-FirewireSBPTransportSysctl: gSBP2DiskDebugFlags = 0x%08X\n", ( unsigned int ) gSBP2DiskDebugFlags ) );
return error;
}
FWSBP2TransportGlobals::FWSBP2TransportGlobals ( void )
{
int debugFlags;
DLOG ( ( "+FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
if ( PE_parse_boot_argn ( "sbp2disk", &debugFlags, sizeof ( debugFlags ) ) )
{
gSBP2DiskDebugFlags = debugFlags;
}
sysctl_register_oid ( &sysctl__debug_FirewireSBPTransport );
DLOG ( ( "-FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
}
FWSBP2TransportGlobals::~FWSBP2TransportGlobals ( void )
{
DLOG ( ( "+~FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
sysctl_unregister_oid ( &sysctl__debug_FirewireSBPTransport );
DLOG ( ( "-~FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
}
#if 0
#pragma mark -
#pragma mark Public Methods
#pragma mark -
#endif
bool
IOFireWireSerialBusProtocolTransport::init ( OSDictionary * propTable )
{
fDeferRegisterService = true;
return super::init ( propTable );
}
bool
IOFireWireSerialBusProtocolTransport::start ( IOService * provider )
{
IOReturn status = kIOReturnSuccess;
bool returnValue = false;
bool openSucceeded = false;
OSNumber * number = NULL;
OSDictionary * dict = NULL;
number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) );
if ( number == NULL )
{
number = OSNumber::withNumber ( kDefaultTimeOutValue, 32 );
require ( number, exit );
setProperty ( kIOPropertyReadTimeOutDurationKey, number );
number->release ( );
number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) );
}
DLOG ( ( "%s: start read time out = %ld\n", getName ( ), number->unsigned32BitValue ( ) ) );
number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyWriteTimeOutDurationKey ) );
if ( number == NULL )
{
number = OSNumber::withNumber ( kDefaultTimeOutValue, 32 );
require ( number, exit );
setProperty ( kIOPropertyWriteTimeOutDurationKey, number );
number->release ( );
number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyWriteTimeOutDurationKey ) );
}
DLOG ( ( "%s: start read time out = %ld\n", getName ( ), number->unsigned32BitValue ( ) ) );
setProperty ( kIOMaximumSegmentCountReadKey, kFWSBP2DefaultPageTableEntriesCount, 32 );
setProperty ( kIOMaximumSegmentCountWriteKey, kFWSBP2DefaultPageTableEntriesCount, 32 );
setProperty ( kIOMaximumSegmentByteCountReadKey, kFWSBP2MaxPageClusterSize, 32 );
setProperty ( kIOMaximumSegmentByteCountWriteKey, kFWSBP2MaxPageClusterSize, 32 );
fSBPTarget = OSDynamicCast ( IOFireWireSBP2LUN, provider );
require ( fSBPTarget, exit );
fSBPTarget->retain ( );
openSucceeded = super::start ( provider );
require ( openSucceeded, exit );
openSucceeded = provider->open ( this );
require ( openSucceeded, exit );
fUnit = fSBPTarget->getFireWireUnit ( );
require ( fUnit, exit );
fUnit->setNodeFlags ( kIOFWEnableRetryOnAckD );
number = OSDynamicCast ( OSNumber, getProperty ( kFireWireGUIDKey, gIOServicePlane ) );
if ( number != NULL )
{
UInt64 GUID = 0;
GUID = number->unsigned64BitValue ( );
RecordFireWireTimeStamp (
FW_TRACE ( kGUID ),
( uintptr_t ) this,
( unsigned int ) ( ( GUID >> 32 ) & 0xFFFFFFFF ),
( unsigned int ) ( GUID & 0xFFFFFFFF ),
0 );
}
status = AllocateResources ( );
require_noerr ( status, exit );
fCommandGate->runAction ( ConnectToDeviceStatic );
if ( reserved->fLoginState == kLogginSucceededState )
{
registerService ( );
}
DLOG ( ( "%s: start complete\n", getName ( ) ) );
returnValue = true;
dict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertyProtocolCharacteristicsKey ) );
if ( dict != NULL )
{
OSDictionary * protocolDict = NULL;
OSString * string = NULL;
protocolDict = OSDictionary::withDictionary ( dict );
check ( protocolDict );
string = OSString::withCString ( kFireWireGUIDKey );
if ( string != NULL )
{
protocolDict->setObject ( string, getProperty ( kFireWireGUIDKey, gIOServicePlane ) );
string->release ( );
string = NULL;
}
string = OSString::withCString ( kPreferredNameKey );
if ( string != NULL )
{
protocolDict->setObject ( kPreferredNameKey, getProperty ( kFireWireVendorNameKey, gIOServicePlane ) );
string->release ( );
string = NULL;
}
setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
protocolDict->release ( );
protocolDict = NULL;
}
reserved->fAutonomousSpinDownWorkAround = false;
if ( ( getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ) != NULL )
{
OSDictionary * characterDict = NULL;
characterDict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) );
if ( characterDict->getObject ( kIOPropertyAutonomousSpinDownKey ) != NULL )
{
reserved->fAutonomousSpinDownWorkAround = true;
}
}
InitializePowerManagement ( provider );
exit:
if ( returnValue == false )
{
DLOG ( ( "%s: start failed. status = %x\n", getName ( ), status) );
cleanUp ( );
}
return returnValue;
}
void
IOFireWireSerialBusProtocolTransport::cleanUp ( void )
{
DLOG ( ( "%s: cleanUp called\n", getName ( ) ) );
if ( fSBPTarget != NULL )
{
if ( fSBPTarget->isOpen ( this ) )
{
OSNumber * number = NULL;
number = OSDynamicCast ( OSNumber, getProperty ( kFireWireGUIDKey, gIOServicePlane ) );
if ( number != NULL )
{
UInt64 GUID = 0;
GUID = number->unsigned64BitValue ( );
RecordFireWireTimeStamp (
FW_TRACE ( kGUID ),
( uintptr_t ) this,
( unsigned int ) ( ( GUID >> 32 ) & 0xFFFFFFFF ),
( unsigned int ) ( GUID & 0xFFFFFFFF ),
1 );
}
fSBPTarget->close ( this );
}
}
}
bool
IOFireWireSerialBusProtocolTransport::finalize ( IOOptionBits options )
{
DeallocateResources ( );
if ( fSBPTarget != NULL )
{
fSBPTarget->release ( );
fSBPTarget = NULL;
}
return super::finalize ( options );
}
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 -
#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 )
{
IOFireWireSBP2ORB * orb = NULL;
SBP2ClientOrbData * clientData = NULL;
IOReturn status = kIOReturnSuccess;
switch ( type )
{
case kIOMessageServiceIsSuspended:
{
DLOG ( ( "%s: kIOMessageServiceIsSuspended\n", getName ( ) ) );
fLoggedIn = false;
}
break;
case kIOMessageServiceIsResumed:
{
DLOG ( ( "%s: kIOMessageServiceIsResumed\n", getName ( ) ) );
if ( fNeedLogin == true )
{
fNeedLogin = false;
fLoginRetryCount = 0;
if ( fLogin != NULL )
{
login ( );
}
}
}
break;
case kIOMessageFWSBP2ReconnectComplete:
{
if ( ( ( FWSBP2ReconnectParams * ) arg )->login == fLogin )
{
DLOG ( ( "%s: kIOMessageFWSBP2ReconnectComplete\n", getName ( ) ) );
fLoggedIn = true;
if ( fReconnectCount < kMaxReconnectCount)
{
DLOG ( ( "%s: resubmit orb \n", getName ( ) ) );
fReconnectCount++;
submitOrbFromQueue ( );
}
else
{
if ( fORB != NULL )
{
clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ( );
if ( clientData != NULL )
{
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_DeliveryFailure;
CompleteSCSITask ( fORB );
}
}
}
}
}
break;
case kIOMessageFWSBP2ReconnectFailed:
{
if ( ( ( FWSBP2ReconnectParams * ) arg )->login == fLogin )
{
DLOG ( ( "%s: kIOMessageFWSBP2ReconnectFailed\n", getName ( ) ) );
fLoginRetryCount = 0;
login ( );
}
}
break;
case kIOFireWireMessageServiceIsRequestingClose:
{
DLOG ( ( "%s: kIOFireWireMessageServiceIsRequestingClose\n", getName ( ) ) );
SendNotification_DeviceRemoved ( );
orb = fORB;
do
{
if ( orb != NULL )
{
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
if ( clientData != NULL )
{
if ( clientData->scsiTask != NULL )
{
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 ( ) ) );
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 = false;
DLOG ( ( "%s: SendSCSICommand called\n", getName ( ) ) );
*serviceResponse = kSCSIServiceResponse_Request_In_Process;
*taskStatus = kSCSITaskStatus_No_Status;
if ( isInactive ( ) == true )
{
*serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
commandProcessed = true;
goto exit;
}
orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false );
require ( orb, exit );
GetCommandDescriptorBlock ( request, &cdb );
RecordFireWireTimeStamp (
FW_TRACE ( kSendSCSICommand1 ),
( uintptr_t ) this,
( uintptr_t ) request,
cdb[0] | ( cdb[1] << 8 ) | ( cdb[2] << 16 ) | ( cdb[3] << 24 ),
cdb[4] | ( cdb[5] << 8 ) | ( cdb[6] << 16 ) | ( cdb[7] << 24 ) );
RecordFireWireTimeStamp (
FW_TRACE ( kSendSCSICommand2 ),
( uintptr_t ) this,
( uintptr_t ) request,
cdb[ 8] | ( cdb[ 9] << 8 ) | ( cdb[10] << 16 ) | ( cdb[11] << 24 ),
cdb[12] | ( cdb[13] << 8 ) | ( cdb[14] << 16 ) | ( cdb[15] << 24 ) );
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
require ( clientData, exit );
commandLength = GetCommandDescriptorBlockSize ( request );
commandFlags = ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromTargetToInitiator ) ?
kFireWireSBP2CommandTransferDataFromTarget :
kFireWireSBP2CommandTransferDataToTarget;
orb->setCommandFlags ( commandFlags |
kFWSBP2CommandCompleteNotify |
kFWSBP2CommandImmediate |
kFWSBP2CommandNormalORB );
require ( ( SetCommandBuffers ( orb, request ) == kIOReturnSuccess ), exit );
orb->setCommandBlock ( cdb, commandLength );
timeOut = GetTimeoutDuration ( request );
if ( timeOut == 0 )
{
timeOut = 0xFFFFFFFF;
}
orb->setCommandTimeout ( timeOut );
#if TRANSPORT_FAILURE_RETRIES
reserved->fLUNResetCount = 3;
#endif
fCommandGate->runAction ( CriticalOrbSubmissionStatic, orb, request );
commandProcessed = true;
exit:
DLOG ( ( "%s: SendSCSICommand exit, Service Response = %x\n", getName ( ), *serviceResponse ) );
return commandProcessed;
}
IOReturn
IOFireWireSerialBusProtocolTransport::SetCommandBuffers (
IOFireWireSBP2ORB * orb,
SCSITaskIdentifier request )
{
SBP2ClientOrbData * clientData = NULL;
IOReturn status = kIOReturnError;
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
require ( clientData, Exit );
clientData->quadletAlignedBuffer = NULL;
if ( GetDataBuffer ( request ) != NULL )
{
if ( ( GetDataBuffer ( request )->getLength ( ) < kDoubleBufferCommandSizeCheckThreshold ) &&
( ( GetDataBuffer ( request )->getLength ( ) & 3 ) != 0 ) )
{
clientData->quadletAlignedBuffer = IOBufferMemoryDescriptor::withOptions (
kIODirectionOutIn,
GetDataBuffer ( request )->getLength ( ),
4 );
require ( clientData->quadletAlignedBuffer, Exit );
if ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromInitiatorToTarget )
{
GetDataBuffer ( request )->readBytes ( GetDataBufferOffset ( request ),
clientData->quadletAlignedBuffer->getBytesNoCopy ( ),
GetDataBuffer ( request )->getLength ( ) );
}
status = orb->setCommandBuffers ( clientData->quadletAlignedBuffer,
GetDataBufferOffset ( request ),
GetRequestedDataTransferCount ( request ) );
require_success ( status, Exit );
}
}
if ( clientData->quadletAlignedBuffer == NULL )
{
status = orb->setCommandBuffers ( GetDataBuffer ( request ),
GetDataBufferOffset ( request ),
GetRequestedDataTransferCount ( request ) );
}
Exit:
return status;
}
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 = 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 );
if ( clientData->quadletAlignedBuffer != NULL )
{
if ( GetDataTransferDirection ( clientData->scsiTask ) == kSCSIDataTransfer_FromTargetToInitiator )
{
GetDataBuffer ( clientData->scsiTask )->writeBytes (
GetDataBufferOffset ( clientData->scsiTask ),
clientData->quadletAlignedBuffer->getBytesNoCopy ( ),
clientData->quadletAlignedBuffer->getLength ( ) );
}
clientData->quadletAlignedBuffer->release ( );
clientData->quadletAlignedBuffer = NULL;
}
scsiTask = clientData->scsiTask;
serviceResponse = clientData->serviceResponse;
taskStatus = clientData->taskStatus;
clientData->scsiTask = NULL;
fORB = NULL;
submitOrbFromQueue ( );
reserved->fCommandPool->returnCommand ( orb );
RecordFireWireTimeStamp (
FW_TRACE ( kCompleteSCSICommand ),
( uintptr_t ) this,
( uintptr_t ) scsiTask,
( serviceResponse << 8 ) | taskStatus );
CommandCompleted ( scsiTask, serviceResponse, taskStatus );
}
}
}
SCSIServiceResponse
IOFireWireSerialBusProtocolTransport::AbortSCSICommand ( SCSITaskIdentifier request )
{
SCSIServiceResponse serviceResponse;
DEBUG_UNUSED ( request );
DLOG ( ( "%s: AbortSCSICommand called\n", getName ( ) ) );
serviceResponse = kSCSIServiceResponse_FUNCTION_REJECTED;
return serviceResponse;
}
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 * number = NULL;
number = OSDynamicCast (
OSNumber,
getProperty ( kSBP2ReceiveBufferByteCountKey, gIOServicePlane ) );
if ( number != NULL )
{
* ( ( UInt64 * ) serviceValue ) = number->unsigned32BitValue ( );
isSupported = true;
}
}
break;
case kSCSIProtocolFeature_GetMaximumLogicalUnitNumber:
{
* ( ( UInt32 * ) serviceValue ) = kMaxFireWireLUN;
isSupported = true;
}
break;
case kSCSIProtocolFeature_ProtocolAlwaysReportsAutosenseData:
{
isSupported = true;
}
break;
case kSCSIProtocolFeature_ProtocolSpecificPowerControl:
{
if ( reserved->fAutonomousSpinDownWorkAround == true )
{
isSupported = true;
}
}
break;
default:
{
isSupported = false;
}
break;
}
return isSupported;
}
bool
IOFireWireSerialBusProtocolTransport::HandleProtocolServiceFeature (
SCSIProtocolFeature feature,
void * serviceValue )
{
bool returnValue = false;
switch ( feature )
{
case kSCSIProtocolFeature_ProtocolSpecificPowerControl:
{
if ( reserved->fAutonomousSpinDownWorkAround == true )
{
returnValue = true;
}
}
break;
default:
{
returnValue = false;
}
break;
}
return returnValue;
}
bool
IOFireWireSerialBusProtocolTransport::IsDeviceCPUInDiskMode ( void )
{
UInt32 csrModelInfo = 0;;
IOConfigDirectory * directory = NULL;
IOFireWireDevice * device = NULL;
IOReturn status = kIOReturnSuccess;
bool isCPUDiskMode = false;
DLOG ( ( "%s: IsDeviceCPUInDiskMode was called\n", getName ( ) ) );
device = OSDynamicCast ( IOFireWireDevice, fUnit->getProvider ( ) );
require ( device, Exit );
status = device->getConfigDirectory ( directory );
require_success ( status, Exit );
status = directory->getKeyValue ( kCSRModelInfoKey, csrModelInfo );
require_success ( status, Exit );
if ( ( csrModelInfo & kCRSModelInfo_ValidBitsMask ) == kCRSModelInfo_TargetDiskMode )
{
isCPUDiskMode = true;
}
Exit:
DLOG ( ( "%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 ) )
{
statusBlock = ( FWSBP2StatusBlock * ) params->message;
}
orb = ( IOFireWireSBP2ORB * ) params->commandObject;
if ( orb != NULL )
{
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
}
RecordFireWireTimeStamp (
FW_TRACE ( kStatusNotify ),
( uintptr_t ) this,
( uintptr_t ) orb,
params->notificationEvent );
switch ( params->notificationEvent )
{
case kFWSBP2NormalCommandStatus:
{
if ( clientData != NULL )
{
if ( statusBlock->details & kSBP2StatusBlock_Details_DeadMask )
{
SetValidAutoSenseData ( clientData, statusBlock, targetData );
RecordFireWireTimeStamp (
FW_TRACE ( kFetchAgentReset ),
( uintptr_t ) this,
( uintptr_t ) orb );
fLogin->submitFetchAgentReset ( );
}
else if ( ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) &&
( statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_FunctionRejected ) )
{
if ( clientData != NULL )
{
if ( clientData->scsiTask != NULL )
{
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_DeviceNotResponding;
}
}
reserved->fLUNResetPathFlag = true;
fLUNResetORB->submit ( );
}
else if ( ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) &&
( ( statusBlock->details & kSBP2StatusBlock_Details_LenMask ) == 1 ) &&
( statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_NoAdditionalInformation ) )
{
clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE;
clientData->taskStatus = kSCSITaskStatus_GOOD;
CompleteSCSITask ( orb );
DLOG ( ( "%s: StatusNotify normal complete \n", getName ( ) ) );
}
else
{
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 != NULL )
{
if ( clientData->scsiTask != NULL )
{
clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
clientData->taskStatus = kSCSITaskStatus_ProtocolTimeoutOccurred;
}
}
RecordFireWireTimeStamp (
FW_TRACE ( kLogicalUnitReset ),
( uintptr_t ) this,
( uintptr_t ) fLUNResetORB );
fLUNResetORB->submit ( );
}
break;
case kFWSBP2NormalCommandReset:
{
DLOG ( ( "%s: kFWSBP2NormalCommandReset\n", getName ( ) ) );
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;
}
}
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 & kSBP2StatusBlock_Details_LenMask ) - 1;
if ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE )
{
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 );
}
}
RecordFireWireTimeStamp (
FW_TRACE ( kSCSICommandSenseData ),
( uintptr_t ) this,
( uintptr_t ) clientData->scsiTask,
targetData->SENSE_KEY & kSENSE_KEY_Mask,
( targetData->ADDITIONAL_SENSE_CODE << 8 ) | targetData->ADDITIONAL_SENSE_CODE_QUALIFIER );
}
SCSITaskStatus
IOFireWireSerialBusProtocolTransport::CoalesceSenseData (
FWSBP2StatusBlock * sourceData,
UInt8 quadletCount,
SCSI_Sense_Data * targetData )
{
SCSITaskStatus returnValue = kSCSITaskStatus_GOOD;
UInt8 statusBlockFormat = 0;
FWSBP2SCSIStatusBlock * scsiStatusBlock = NULL;
scsiStatusBlock = ( FWSBP2SCSIStatusBlock * ) sourceData;
if ( quadletCount > 0 )
{
statusBlockFormat = scsiStatusBlock->status & kFWSBP2SCSIStatusBlock_StatusBlockFormatMask;
returnValue = ( SCSITaskStatus ) ( scsiStatusBlock->status & kFWSBP2SCSIStatusBlock_StatusBlockStatusMask );
if ( statusBlockFormat == kFWSBP2SCSIStatusBlock_StatusBlockFormatCurrentError )
{
targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Current_Errors;
}
else if ( statusBlockFormat == kFWSBP2SCSIStatusBlock_StatusBlockFormatDeferredError )
{
targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Deferred_Errors;
}
if ( statusBlockFormat < 2 )
{
targetData->VALID_RESPONSE_CODE |= ( scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_VALID_Mask );
targetData->ADDITIONAL_SENSE_CODE = scsiStatusBlock->ASC;
targetData->ADDITIONAL_SENSE_CODE_QUALIFIER = scsiStatusBlock->ASCQ;
targetData->SENSE_KEY = scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_SenseKeyMask;
targetData->SENSE_KEY |= ( scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_MEI_Mask ) << 1;
if ( quadletCount > 1 )
{
scsiStatusBlock->information = OSSwapBigToHostInt32 ( scsiStatusBlock->information );
targetData->INFORMATION_1 = ( scsiStatusBlock->information >> 24 ) & 0xFF;
targetData->INFORMATION_2 = ( scsiStatusBlock->information >> 16 ) & 0xFF;
targetData->INFORMATION_3 = ( scsiStatusBlock->information >> 8 ) & 0xFF;
targetData->INFORMATION_4 = scsiStatusBlock->information & 0xFF;
targetData->ADDITIONAL_SENSE_LENGTH = 6;
}
if ( quadletCount > 2 )
{
scsiStatusBlock->commandSpecificInformation = OSSwapBigToHostInt32 ( scsiStatusBlock->commandSpecificInformation );
targetData->COMMAND_SPECIFIC_INFORMATION_1 = ( scsiStatusBlock->commandSpecificInformation >> 24 ) & 0xFF;
targetData->COMMAND_SPECIFIC_INFORMATION_2 = ( scsiStatusBlock->commandSpecificInformation >> 16 ) & 0xFF;
targetData->COMMAND_SPECIFIC_INFORMATION_3 = ( scsiStatusBlock->commandSpecificInformation >> 8 ) & 0xFF;
targetData->COMMAND_SPECIFIC_INFORMATION_4 = scsiStatusBlock->commandSpecificInformation & 0xFF;
targetData->ADDITIONAL_SENSE_LENGTH = 6;
}
if ( quadletCount > 3 )
{
UInt8 count = 0;
scsiStatusBlock->senseKeyDependent = OSSwapBigToHostInt32 ( scsiStatusBlock->senseKeyDependent );
count = ( quadletCount - 3 ) * sizeof ( UInt32 );
if ( count > 4 )
count = 4;
bcopy ( &scsiStatusBlock->senseKeyDependent,
&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 )
{
DLOG ( ( "%s: LoginCompletion complete \n", getName ( ) ) );
require_success ( params->status, Retry );
require ( params->statusBlock, Retry );
RecordFireWireTimeStamp (
FW_TRACE ( kLoginCompletion ),
( uintptr_t ) this,
params->status,
params->statusBlock->details,
params->statusBlock->sbpStatus );
if ( ( ( params->statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) &&
( params->statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_NoAdditionalInformation ) )
{
fLoginRetryCount = 0;
fLoggedIn = true;
fNeedLogin = false;
if ( reserved->fLoginState == kFirstTimeLoggingInState )
{
reserved->fLoginState = kLogginSucceededState;
fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
}
submitOrbFromQueue ( );
RecordFireWireTimeStamp ( FW_TRACE ( kLoginResumed ), ( uintptr_t ) this );
loginResumed ( );
return;
}
Retry:
RecordFireWireTimeStamp (
FW_TRACE ( kLoginCompletion ),
( uintptr_t ) this,
params->status, NULL, NULL );
if ( fLoginRetryCount < kMaxLoginRetryCount )
{
IOReturn status = kIOReturnSuccess;
fLoginRetryCount++;
DLOG ( ( "%s: resubmitting Login\n", getName ( ) ) );
status = login ( );
if ( status != kIOReturnSuccess )
{
if ( reserved->fLoginState == kFirstTimeLoggingInState )
{
reserved->fLoginState = kLogginFailedState;
fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
}
}
}
else
{
fNeedLogin = true;
RecordFireWireTimeStamp (
FW_TRACE ( kLoginLost ),
( uintptr_t ) this,
reserved->fLoginState );
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 )
{
DEBUG_UNUSED ( params );
DLOG ( ( "%s: LogoutCompletion complete \n", getName ( ) ) );
}
void
IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotifyStatic (
void * refCon,
FWSBP2NotifyParams * params )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->UnsolicitedStatusNotify ( params );
}
void
IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotify (
FWSBP2NotifyParams * params )
{
DEBUG_UNUSED ( params );
DLOG ( ( "%s: UnsolicitedStatusNotify called\n", getName ( ) ) );
fLogin->enableUnsolicitedStatus ( );
}
void
IOFireWireSerialBusProtocolTransport::FetchAgentResetCompleteStatic (
void * refCon,
IOReturn status )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->FetchAgentResetComplete ( status );
}
void
IOFireWireSerialBusProtocolTransport::FetchAgentResetComplete ( IOReturn status )
{
SBP2ClientOrbData * clientData = NULL;
DEBUG_UNUSED ( status );
DLOG ( ( "%s: FetchAgentResetComplete called\n", getName ( ) ) );
require ( fORB, exit );
clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ( );
if ( clientData != NULL )
{
if ( clientData->scsiTask != NULL )
{
RecordFireWireTimeStamp (
FW_TRACE ( kFetchAgentResetComplete ),
( uintptr_t ) this,
( uintptr_t ) fORB );
#if TRANSPORT_FAILURE_RETRIES
if ( reserved->fLUNResetPathFlag && ( reserved->fLUNResetCount > 0 ) )
{
reserved->fLUNResetCount--;
submitOrbFromQueue ( );
}
else
#endif
{
CompleteSCSITask ( fORB );
}
}
}
exit:
reserved->fLUNResetPathFlag = false;
}
void
IOFireWireSerialBusProtocolTransport::LunResetCompleteStatic (
void * refCon,
IOReturn status,
IOFireWireSBP2ManagementORB * orb )
{
( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LunResetComplete ( status, orb );
}
void
IOFireWireSerialBusProtocolTransport::LunResetComplete (
IOReturn status,
IOFireWireSBP2ManagementORB * orb )
{
DEBUG_UNUSED ( status );
DEBUG_UNUSED ( orb );
DLOG ( ( "%s: LunResetComplete called\n", getName ( ) ) );
RecordFireWireTimeStamp (
FW_TRACE ( kLogicalUnitResetComplete ),
( uintptr_t ) this,
( uintptr_t ) orb,
status );
RecordFireWireTimeStamp (
FW_TRACE ( kFetchAgentReset ),
( uintptr_t ) this,
( uintptr_t ) orb );
fLogin->submitFetchAgentReset ( );
}
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;
}
void
IOFireWireSerialBusProtocolTransport::ConnectToDevice ( void )
{
IOReturn status = kIOReturnSuccess;
DLOG ( ( "%s: ConnectToDevice called\n", getName ( ) ) );
fNeedLogin = false;
fLoginRetryCount = 0;
status = login ( );
if ( status == kIOReturnSuccess )
{
fCommandGate->commandSleep ( ( void * ) &reserved->fLoginState, THREAD_UNINT );
}
}
void
IOFireWireSerialBusProtocolTransport::DisconnectFromDevice ( void )
{
DLOG ( ( "%s: DisconnectFromDevice called\n", getName ( ) ) );
fLoggedIn = false;
fNeedLogin = false;
fLogin->submitLogout ( );
}
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;
}
void
IOFireWireSerialBusProtocolTransport::CriticalOrbSubmission (
IOFireWireSBP2ORB * orb,
SCSITaskIdentifier request )
{
SBP2ClientOrbData * clientData;
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
require ( clientData, exit );
clientData->scsiTask = request;
reserved->fSubmitQueue->returnCommand ( orb );
if ( fORB == NULL )
{
submitOrbFromQueue ( );
}
exit:
return;
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 6 );
void
IOFireWireSerialBusProtocolTransport::submitOrbFromQueue ( void )
{
DLOG ( ( "%s: submitOrbFromQueue called\n", getName ( ) ) );
if ( fLoggedIn == true )
{
if ( fORB == NULL )
{
fORB = ( IOFireWireSBP2ORB * ) reserved->fSubmitQueue->getCommand ( false );
fReconnectCount = 0;
}
if ( fORB != NULL )
{
RecordFireWireTimeStamp ( FW_TRACE ( kSubmitOrb ), ( uintptr_t ) this, ( uintptr_t ) fORB );
fLogin->submitORB ( fORB );
}
}
}
IOReturn
IOFireWireSerialBusProtocolTransport::AllocateResources ( void )
{
IOReturn status = kIOReturnSuccess;
IOWorkLoop * workLoop = NULL;
DLOG ( ( "%s: AllocateResources called\n", getName ( ) ) );
fLogin = fSBPTarget->createLogin ( );
require_action ( fLogin, exit, status = kIOReturnNoMemory );
fLogin->setLoginFlags ( kFWSBP2ExclusiveLogin );
fLogin->setLoginRetryCountAndDelayTime ( kLoginRetryCount, kLoginDelayTime );
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;
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 = NULL;
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 );
reserved->fCommandPool->returnCommand ( orb );
}
status = kIOReturnSuccess;
exit:
return status;
}
void
IOFireWireSerialBusProtocolTransport::DeallocateResources ( void )
{
IOFireWireSBP2ORB * orb = NULL;
SBP2ClientOrbData * clientData = NULL;
DLOG ( ( "%s: DeallocateResources called\n", getName ( ) ) );
if ( fLUNResetORB != NULL )
{
fLUNResetORB->release ( );
fLUNResetORB = NULL;
}
while ( ( orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false ) ) )
{
clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
if ( clientData != NULL )
{
IOFree ( clientData, sizeof ( SBP2ClientOrbData ) );
clientData = NULL;
}
orb->release ( );
orb = NULL;
}
if ( reserved != NULL )
{
reserved->fCommandPool->release ( );
reserved->fCommandPool = NULL;
reserved->fSubmitQueue->release ( );
reserved->fSubmitQueue = NULL;
}
if ( fLogin != NULL )
{
fLogin->release ( );
fLogin = NULL;
}
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 1 );
IOReturn
IOFireWireSerialBusProtocolTransport::login ( void )
{
IOReturn status = kIOReturnError;
DLOG ( ( "%s: submitting login.\n", getName ( ) ) );
fNeedLogin = false;
fLoggedIn = false;
for ( ; fLoginRetryCount < kMaxLoginRetryCount; ++fLoginRetryCount )
{
RecordFireWireTimeStamp (
FW_TRACE ( kLoginRequest ),
( uintptr_t ) this,
reserved->fLoginState,
fLoginRetryCount );
status = submitLogin ( );
if ( status == kIOReturnSuccess )
{
break;
}
}
if ( status != kIOReturnSuccess )
{
fNeedLogin = true;
fLoggedIn = false;
RecordFireWireTimeStamp (
FW_TRACE ( kLoginLost ),
( uintptr_t ) this,
reserved->fLoginState );
loginLost ( );
}
return status;
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 2 );
IOReturn
IOFireWireSerialBusProtocolTransport::submitLogin ( void )
{
IOReturn status = kIOReturnSuccess;
DLOG ( ( "%s: submitting login.\n", getName ( ) ) );
status = fLogin->submitLogin ( );
return status;
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 3 );
void IOFireWireSerialBusProtocolTransport::loginLost ( void )
{
DLOG ( ( "%s: login lost.\n", getName ( ) ) );
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 4 );
void
IOFireWireSerialBusProtocolTransport::loginSuspended ( void )
{
DLOG ( ( "%s: login suspended.\n", getName ( ) ) );
}
OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 5 );
void
IOFireWireSerialBusProtocolTransport::loginResumed ( void )
{
DLOG ( ( "%s: login resumed.\n", getName ( ) ) );
}
#if 0
#pragma mark -
#pragma mark Static Debug Assertion Method
#pragma mark -
#endif
#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
static inline void
RecordFireWireTimeStamp (
unsigned int code,
unsigned int a, unsigned int b,
unsigned int c, unsigned int d )
{
if ( gSBP2DiskDebugFlags & kSBP2DiskEnableTracePointsMask )
{
IOTimeStampConstant ( code, a, b, c, d );
}
}
#if 0
#pragma mark -
#pragma mark VTable Padding
#pragma mark -
#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 );