SCSITaskUserClient.cpp [plain text]
#include "SCSITaskUserClient.h"
#include <IOKit/scsi-commands/IOSCSIPrimaryCommandsDevice.h>
#include <IOKit/scsi-commands/IOSCSIMultimediaCommandsDevice.h>
#include <IOKit/scsi-commands/SCSICmds_REQUEST_SENSE_Defs.h>
#include <IOKit/scsi-commands/SCSICmds_INQUIRY_Definitions.h>
#include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#define SCSI_TASK_USER_CLIENT_DEBUGGING_LEVEL 0
#if ( SCSI_TASK_USER_CLIENT_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( SCSI_TASK_USER_CLIENT_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( SCSI_TASK_USER_CLIENT_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define super IOUserClient
OSDefineMetaClassAndStructors ( SCSITaskUserClient, IOUserClient );
IOExternalMethod
SCSITaskUserClient::sMethods[kSCSITaskUserClientMethodCount] =
{
{
0,
( IOMethod ) &SCSITaskUserClient::IsExclusiveAccessAvailable,
kIOUCScalarIScalarO,
0,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::ObtainExclusiveAccess,
kIOUCScalarIScalarO,
0,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::ReleaseExclusiveAccess,
kIOUCScalarIScalarO,
0,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::CreateTask,
kIOUCScalarIScalarO,
0,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::ReleaseTask,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::AbortTask,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::ExecuteTaskAsync,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::ExecuteTaskSync,
kIOUCScalarIScalarO,
2,
3
},
{
0,
( IOMethod ) &SCSITaskUserClient::IsTaskActive,
kIOUCScalarIScalarO,
1,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetTransferDirection,
kIOUCScalarIScalarO,
2,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetTaskAttribute,
kIOUCScalarIScalarO,
2,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetTaskAttribute,
kIOUCScalarIScalarO,
1,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetCommandDescriptorBlock,
kIOUCScalarIStructI,
2,
sizeof ( SCSICommandDescriptorBlock )
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetScatterGatherList,
kIOUCScalarIStructI,
5,
0xFFFFFFFF
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetSenseDataBuffer,
kIOUCScalarIScalarO,
3,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetTimeoutDuration,
kIOUCScalarIScalarO,
2,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetTimeoutDuration,
kIOUCScalarIScalarO,
1,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetTaskStatus,
kIOUCScalarIScalarO,
1,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetSCSIServiceResponse,
kIOUCScalarIScalarO,
1,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetTaskState,
kIOUCScalarIScalarO,
1,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetAutoSenseData,
kIOUCScalarIStructO,
1,
sizeof ( SCSI_Sense_Data )
},
{
0,
( IOMethod ) &SCSITaskUserClient::Inquiry,
kIOUCScalarIScalarO,
3,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::TestUnitReady,
kIOUCScalarIScalarO,
1,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetPerformance,
kIOUCScalarIScalarO,
5,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetConfiguration,
kIOUCScalarIScalarO,
5,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::ModeSense10,
kIOUCScalarIScalarO,
5,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetWriteParametersModePage,
kIOUCScalarIScalarO,
3,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::GetTrayState,
kIOUCScalarIScalarO,
0,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::SetTrayState,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &SCSITaskUserClient::ReadTableOfContents,
kIOUCScalarIScalarO,
5,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::ReadDiscInformation,
kIOUCScalarIScalarO,
3,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::ReadTrackInformation,
kIOUCScalarIScalarO,
5,
1
},
{
0,
( IOMethod ) &SCSITaskUserClient::ReadDVDStructure,
kIOUCScalarIScalarO,
5,
1
}
};
IOExternalAsyncMethod SCSITaskUserClient::sAsyncMethods[kSCSITaskUserClientAsyncMethodCount] =
{
{ 0,
( IOAsyncMethod ) &SCSITaskUserClient::SetAsyncCallback,
kIOUCScalarIScalarO,
3,
0
}
};
bool
SCSITaskUserClient::init ( OSDictionary * dictionary )
{
STATUS_LOG ( ( "SCSITaskUserClient::init\n" ) );
if ( !IOService::init ( dictionary ) )
return false;
fTask = NULL;
fProvider = NULL;
fProtocolInterface = NULL;
fSetOfSCSITasks = NULL;
return true;
}
bool
SCSITaskUserClient::start ( IOService * provider )
{
STATUS_LOG ( ( "SCSITaskUserClient::start\n" ) );
OSIterator * iterator;
OSObject * object;
if ( fProvider != NULL )
return false;
if ( !IOUserClient::start ( provider ) )
return false;
STATUS_LOG ( ( "assigning fProvider\n" ) );
fProvider = provider;
fProtocolInterface = OSDynamicCast ( IOSCSIProtocolInterface, provider );
if ( fProtocolInterface == NULL )
{
STATUS_LOG ( ( "provider not IOSCSIProtocolInterface\n" ) );
iterator = provider->getParentIterator ( gIOServicePlane );
if ( iterator != NULL )
{
STATUS_LOG ( ( "got parent iterator\n" ) );
while ( object = iterator->getNextObject ( ) )
{
fProtocolInterface = OSDynamicCast ( IOSCSIProtocolInterface,
( IOService * ) object );
STATUS_LOG ( ( "%s candidate IOSCSIProtocolInterface\n", ( ( IOService * ) object )->getName ( ) ) );
if ( fProtocolInterface != NULL )
{
STATUS_LOG ( ( "found IOSCSIProtocolInterface\n" ) );
break;
}
}
iterator->release ( );
if ( fProtocolInterface == NULL )
{
STATUS_LOG ( ( "didn't find IOSCSIProtocolInterface\n" ) );
fProvider = NULL;
return false;
}
}
}
STATUS_LOG ( ( "Opening provider\n" ) );
if ( !fProvider->open ( this, kIOSCSITaskUserClientAccessMask, 0 ) )
{
STATUS_LOG ( ( "Open failed\n" ) );
return false;
}
STATUS_LOG ( ( "start done\n" ) );
fSetOfSCSITasks = OSSet::withCapacity ( 1 );
return true;
}
bool
SCSITaskUserClient::initWithTask ( task_t owningTask,
void * securityToken,
UInt32 type )
{
STATUS_LOG ( ( "SCSITaskUserClient::initWithTask called\n" ) );
if ( type != kSCSITaskLibConnection )
return false;
fTask = owningTask;
return true;
}
IOReturn
SCSITaskUserClient::clientClose ( void )
{
STATUS_LOG ( ( "clientClose called\n" ) );
HandleTermination ( fProvider );
STATUS_LOG ( ( "Done\n" ) );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::clientDied ( void )
{
STATUS_LOG ( ( "SCSITaskUserClient::clientDied called\n" ) );
if ( fProvider != NULL )
{
return clientClose ( );
}
return kIOReturnSuccess;
}
IOExternalMethod *
SCSITaskUserClient::getTargetAndMethodForIndex ( IOService ** target, UInt32 index )
{
if ( index >= kSCSITaskUserClientMethodCount )
return NULL;
if ( fProtocolInterface == NULL )
return NULL;
if ( fProtocolInterface->IsPowerManagementIntialized ( ) )
{
fProtocolInterface->CheckPowerState ( );
}
*target = this;
return &sMethods[index];
}
IOExternalAsyncMethod *
SCSITaskUserClient::getAsyncTargetAndMethodForIndex ( IOService ** target, UInt32 index )
{
if ( index >= kSCSITaskUserClientAsyncMethodCount )
return NULL;
if ( fProtocolInterface == NULL )
return NULL;
if ( fProtocolInterface->IsPowerManagementIntialized ( ) )
{
fProtocolInterface->CheckPowerState ( );
}
*target = this;
return &sAsyncMethods[index];
}
IOReturn
SCSITaskUserClient::IsExclusiveAccessAvailable ( void )
{
IOReturn status = kIOReturnExclusiveAccess;
bool state = true;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
STATUS_LOG ( ( "IsExclusiveAccessAvailable called\n" ) );
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == false )
{
STATUS_LOG ( ( "No current exclusive client\n" ) );
status = kIOReturnSuccess;
}
STATUS_LOG ( ( "IsExclusiveAccessAvailable: status = %d\n", status ) );
return status;
}
IOReturn
SCSITaskUserClient::ObtainExclusiveAccess ( void )
{
IOReturn status = kIOReturnExclusiveAccess;
bool state = true;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
STATUS_LOG ( ( "ObtainExclusiveAccess called\n" ) );
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == false )
{
STATUS_LOG ( ( "No current exclusive client\n" ) );
status = fProtocolInterface->SetUserClientExclusivityState ( this, true );
if ( status == kIOReturnSuccess )
{
if ( fProtocolInterface->IsPowerManagementIntialized ( ) )
{
UInt32 minutes = 0;
fProtocolInterface->getAggressiveness ( kPMMinutesToSpinDown, &minutes );
fProtocolInterface->setAggressiveness ( kPMMinutesToSpinDown, minutes );
}
}
}
STATUS_LOG ( ( "ObtainExclusiveAccess: status = %d\n", status ) );
return status;
}
IOReturn
SCSITaskUserClient::ReleaseExclusiveAccess ( void )
{
IOReturn status = kIOReturnExclusiveAccess;
bool state = true;
STATUS_LOG ( ( "ReleaseExclusiveAccess called\n" ) );
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
STATUS_LOG ( ( "There is a current exclusive client\n" ) );
status = fProtocolInterface->SetUserClientExclusivityState ( this, false );
if ( status == kIOReturnSuccess )
{
if ( fProtocolInterface->IsPowerManagementIntialized ( ) )
{
UInt32 minutes = 0;
fProtocolInterface->getAggressiveness ( kPMMinutesToSpinDown, &minutes );
fProtocolInterface->setAggressiveness ( kPMMinutesToSpinDown, minutes );
}
}
}
STATUS_LOG ( ( "ReleaseExclusiveAccess: status = %d\n", status ) );
return status;
}
IOReturn
SCSITaskUserClient::CreateTask ( SCSITask ** outSCSITask, void *, void *, void *, void *, void * )
{
IOReturn status = kIOReturnSuccess;
SCSITask * task;
UInt8 * internalRefCon;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
STATUS_LOG ( ( "CreateTask called\n" ) );
task = new SCSITask;
if ( task == NULL )
{
status = kIOReturnNoMemory;
goto TASK_ALLOCATION_FAILURE;
}
STATUS_LOG ( ( "Initializing task\n" ) );
if ( task->ResetForNewTask ( ) == false )
{
status = kIOReturnNoMemory;
goto INIT_FAILURE;
}
STATUS_LOG ( ( "Allocating refcon storage\n" ) );
internalRefCon = ( UInt8 * ) IOMalloc ( sizeof ( OSAsyncReference ) );
if ( internalRefCon == NULL )
{
status = kIOReturnNoMemory;
goto INIT_FAILURE;
}
task->SetApplicationLayerReference ( internalRefCon );
*outSCSITask = task;
fSetOfSCSITasks->setObject ( task );
return status;
INIT_FAILURE:
if ( task != NULL )
{
task->release ( );
}
TASK_ALLOCATION_FAILURE:
return status;
}
IOReturn
SCSITaskUserClient::ReleaseTask ( SCSITask * inSCSITask, void *, void *, void *, void *, void * )
{
IOMemoryDescriptor * buffer;
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
STATUS_LOG ( ( "SCSITaskUserClient::ReleaseTask\n" ) );
if ( task != NULL )
{
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
fSetOfSCSITasks->removeObject ( task );
STATUS_LOG ( ( "Removed object from OSSet\n" ) );
buffer = task->GetDataBuffer ( );
if ( buffer != NULL )
{
buffer->release ( );
STATUS_LOG ( ( "Released buffer\n" ) );
}
task->release ( );
STATUS_LOG ( ( "Released task\n" ) );
}
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::ExecuteTaskAsync ( SCSITask * inSCSITask, void *, void *, void *, void *, void * )
{
IOMemoryDescriptor * buffer;
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
task->SetAutosenseIsValid ( false );
#if ( SCSI_TASK_USER_CLIENT_DEBUGGING_LEVEL >= 3 )
{
SCSICommandDescriptorBlock cdb;
UInt8 commandLength;
task->GetCommandDescriptorBlock ( &cdb );
commandLength = task->GetCommandDescriptorBlockSize ( );
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] ) );
}
else if ( commandLength == kSCSICDBSize_16Byte )
{
STATUS_LOG ( ( "cdb = %02x:%02x:%02x:%02x:%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], cdb[12], cdb[13], cdb[14], cdb[15] ) );
}
}
#endif
buffer = task->GetDataBuffer ( );
if ( buffer != NULL )
buffer->prepare ( );
task->SetTaskCompletionCallback ( sAsyncTaskCallback );
task->SetAutosenseCommand ( kSCSICmd_REQUEST_SENSE, 0x00, 0x00, 0x00, sizeof ( SCSI_Sense_Data ), 0x00 );
fProtocolInterface->ExecuteCommand ( task );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::ExecuteTaskSync ( SCSITask * inSCSITask, vm_address_t senseDataBuffer,
SCSITaskStatus * taskStatus, UInt32 * tranferCountHi,
UInt32 * tranferCountLo, void * )
{
SCSI_Sense_Data senseDataBytes;
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
IOMemoryDescriptor * senseBuffer = NULL;
IOMemoryDescriptor * dataBuffer = NULL;
IOReturn status = kIOReturnSuccess;
SCSITask * task = NULL;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
task->SetAutosenseIsValid ( false );
senseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( senseBuffer == NULL )
{
return kIOReturnNoMemory;
}
dataBuffer = task->GetDataBuffer ( );
if ( dataBuffer != NULL )
dataBuffer->prepare ( );
serviceResponse = SendCommand ( task );
*taskStatus = task->GetTaskStatus ( );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
UInt64 transferCount = 0;
transferCount = task->GetRealizedDataTransferCount ( );
*tranferCountHi = ( transferCount >> 32 ) & 0xFFFFFFFF;
*tranferCountLo = transferCount & 0xFFFFFFFF;
if ( *taskStatus == kSCSITaskStatus_CHECK_CONDITION )
{
if ( task->GetAutoSenseData ( &senseDataBytes ) )
{
senseBuffer->prepare ( );
senseBuffer->writeBytes ( 0, &senseDataBytes, sizeof ( SCSI_Sense_Data ) );
senseBuffer->complete ( );
}
}
}
senseBuffer->release ( );
if ( dataBuffer != NULL )
dataBuffer->complete ( );
return status;
}
IOReturn
SCSITaskUserClient::AbortTask ( SCSITask * inSCSITask, void *, void *, void *, void *, void * )
{
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) == false )
{
return kIOReturnNotPermitted;
}
fProtocolInterface->AbortCommand ( inSCSITask );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::SetAsyncCallback ( OSAsyncReference asyncRef,
SCSITask * inTask,
void * callback, void * refCon,
void *, void * )
{
SCSITask * task;
UInt8 * internalRefCon;
mach_port_t wakePort;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
task = OSDynamicCast ( SCSITask, inTask );
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
STATUS_LOG ( ( "asyncRef[0] = %d\n", asyncRef[0] ) );
wakePort = ( mach_port_t ) asyncRef[0];
IOUserClient::setAsyncReference ( asyncRef, wakePort, callback, refCon );
internalRefCon = ( UInt8 * ) task->GetApplicationLayerReference ( );
bcopy ( asyncRef, internalRefCon, sizeof ( OSAsyncReference ) );
STATUS_LOG ( ( "internalRefCon[0] = %d\n", internalRefCon[0] ) );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::IsTaskActive ( SCSITask * inSCSITask, UInt32 * active, void *, void *, void *, void * )
{
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
*active = task->IsTaskActive ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::SetTransferDirection ( SCSITask * inSCSITask, UInt32 transferDirection, void *, void *, void *, void * )
{
UInt8 direction;
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
switch ( transferDirection )
{
case kSCSIDataTransfer_NoDataTransfer:
case kSCSIDataTransfer_FromInitiatorToTarget:
case kSCSIDataTransfer_FromTargetToInitiator:
break;
default:
return kIOReturnBadArgument;
break;
}
direction = transferDirection & 0xFF;
if ( task->SetDataTransferDirection ( direction ) == false )
return kIOReturnError;
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::SetTaskAttribute ( SCSITask * inSCSITask, UInt32 attribute, void *, void *, void *, void * )
{
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
SCSITaskAttribute taskAttribute = ( SCSITaskAttribute ) attribute;
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
if ( task->SetTaskAttribute ( taskAttribute ) == false )
return kIOReturnError;
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetTaskAttribute ( SCSITask * inSCSITask, UInt32 * attribute, void *, void *, void *, void * )
{
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
*attribute = ( UInt32 ) task->GetTaskAttribute ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::SetCommandDescriptorBlock ( SCSITask * inSCSITask, UInt32 size, UInt8 * cdb, UInt32 inDataSize, void *, void * )
{
SCSITask * task = OSDynamicCast ( SCSITask, inSCSITask );
bool result;
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
switch ( size )
{
case 6:
result = task->SetCommandDescriptorBlock ( cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5] );
break;
case 10:
result = task->SetCommandDescriptorBlock ( cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5],
cdb[6], cdb[7], cdb[8], cdb[9] );
break;
case 12:
result = task->SetCommandDescriptorBlock ( cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5],
cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11] );
break;
case 16:
result = task->SetCommandDescriptorBlock ( cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5],
cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11],
cdb[12], cdb[13], cdb[14], cdb[15] );
break;
default:
return kIOReturnBadArgument;
break;
}
if ( result == false )
return kIOReturnError;
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::SetScatterGatherList ( SCSITask * inSCSITask, UInt32 inScatterGatherEntries,
UInt32 inTransferCountHi, UInt32 inTransferCountLo,
UInt32 inTransferDirection,
IOVirtualRange * inScatterGatherList )
{
IOReturn status = kIOReturnSuccess;
IOMemoryDescriptor * buffer = NULL;
SCSITask * task = NULL;
UInt64 transferCount;
UInt8 direction;
STATUS_LOG ( ( "SCSITaskUserClient::SetScatterGatherList\n" ) );
STATUS_LOG ( ( "inScatterGatherEntries = %ld\n", inScatterGatherEntries ) );
STATUS_LOG ( ( "inTransferCountHi = %ld\n", inTransferCountHi ) );
STATUS_LOG ( ( "inTransferCountLo = %ld\n", inTransferCountLo ) );
STATUS_LOG ( ( "inTransferDirection = %ld\n", inTransferDirection ) );
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
transferCount = inTransferCountHi;
transferCount = ( transferCount << 32 ) | inTransferCountLo;
if ( inTransferDirection == kSCSIDataTransfer_NoDataTransfer )
direction = kIODirectionNone;
else if ( inTransferDirection == kSCSIDataTransfer_FromTargetToInitiator )
direction = kIODirectionIn;
else if ( inTransferDirection == kSCSIDataTransfer_FromInitiatorToTarget )
direction = kIODirectionOut;
else
return kIOReturnBadArgument;
buffer = task->GetDataBuffer ( );
if ( buffer != NULL )
buffer->release ( );
buffer = IOMemoryDescriptor::withRanges ( inScatterGatherList,
inScatterGatherEntries,
( IODirection ) direction,
fTask,
false );
if ( buffer == NULL )
return kIOReturnNoMemory;
task->SetDataTransferDirection ( inTransferDirection );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( transferCount );
return status;
}
IOReturn
SCSITaskUserClient::SetSenseDataBuffer ( SCSITask * inSCSITask, vm_address_t buffer, UInt32 bufferSize, void *, void *, void * )
{
#if 0
IOMemoryDescriptor * senseBuffer = NULL;
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
senseBuffer = IOMemoryDescriptor::withAddress ( buffer,
bufferSize,
kIODirectionOut,
fTask );
senseBuffer->prepare ( );
#endif
return kIOReturnUnsupported;
}
IOReturn
SCSITaskUserClient::SetTimeoutDuration ( SCSITask * inSCSITask, UInt32 timeoutMS, void *, void *, void *, void * )
{
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->IsTaskActive ( ) )
{
return kIOReturnNotPermitted;
}
if ( task->SetTimeoutDuration ( timeoutMS ) == false )
return kIOReturnError;
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetTimeoutDuration ( SCSITask * inSCSITask, UInt32 * timeoutMS, void *, void *, void *, void * )
{
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
*timeoutMS = task->GetTimeoutDuration ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetTaskStatus ( SCSITask * inSCSITask, SCSITaskStatus * taskStatus, void *, void *, void *, void * )
{
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
*taskStatus = task->GetTaskStatus ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetSCSIServiceResponse ( SCSITask * inSCSITask, SCSIServiceResponse * serviceResponse, void *, void *, void *, void * )
{
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
*serviceResponse = task->GetServiceResponse ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetTaskState ( SCSITask * inSCSITask, SCSITaskState * taskState, void *, void *, void *, void * )
{
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
*taskState = task->GetTaskState ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetRealizedDataTransferCount ( SCSITask * inSCSITask, UInt64 * transferCount, void *, void *, void *, void * )
{
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
*transferCount = task->GetRealizedDataTransferCount ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetAutoSenseData ( SCSITask * inSCSITask, SCSI_Sense_Data * senseDataBuffer, void *, void *, void *, void * )
{
SCSITask * task = NULL;
task = OSDynamicCast ( SCSITask, inSCSITask );
if ( task == NULL )
return kIOReturnBadArgument;
if ( task->GetAutoSenseData ( senseDataBuffer ) == false )
return kIOReturnError;
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::Inquiry ( UInt32 inqBufferSize,
vm_address_t inqBuffer,
vm_address_t senseBuffer,
UInt32 * outTaskStatus,
void *, void * )
{
SCSITask * task = NULL;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
bool state = true;
SCSIServiceResponse serviceResponse;
SCSITaskStatus taskStatus;
IOReturn status = kIOReturnSuccess;
SCSI_Sense_Data senseData;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
if ( inqBufferSize > 0xFF )
return kIOReturnBadArgument;
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
buffer = IOMemoryDescriptor::withAddress ( inqBuffer,
inqBufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_INQUIRY,
0x00,
0x00,
0x00,
inqBufferSize & 0xFF,
0x00 );
task->SetTimeoutDuration ( 10 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( inqBufferSize );
buffer->prepare ( );
serviceResponse = SendCommand ( task );
taskStatus = task->GetTaskStatus ( );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( taskStatus != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) taskStatus;
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::TestUnitReady ( vm_address_t senseDataBuffer,
UInt32 * outTaskStatus,
void *, void *, void *, void * )
{
SCSITask * task = NULL;
SCSITaskStatus taskStatus;
bool state = true;
SCSIServiceResponse serviceResponse;
SCSI_Sense_Data senseData;
IOMemoryDescriptor * buffer;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_TEST_UNIT_READY,
0x00,
0x00,
0x00,
0x00,
0x00 );
task->SetTimeoutDuration ( 10 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_NoDataTransfer );
serviceResponse = SendCommand ( task );
taskStatus = task->GetTaskStatus ( );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( taskStatus == kSCSITaskStatus_CHECK_CONDITION )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
buffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( buffer != NULL )
{
buffer->prepare ( );
buffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
buffer->complete ( );
buffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) taskStatus;
task->release ( );
return kIOReturnSuccess;
}
IOReturn
SCSITaskUserClient::GetPerformance ( UInt32 TOLERANCE_WRITE_EXCEPT, UInt32 STARTING_LBA,
UInt32 MAXIMUM_NUMBER_OF_DESCRIPTORS_AND_BUFFER_SIZE,
vm_address_t performanceBuffer, vm_address_t senseDataBuffer,
UInt32 * outTaskStatus )
{
SCSITask * task = NULL;
IOReturn status = kIOReturnSuccess;
bool state = true;
SCSIServiceResponse serviceResponse;
SCSITaskStatus taskStatus;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
SCSI_Sense_Data senseData;
SCSICmdField2Bit TOLERANCE;
SCSICmdField1Bit WRITE;
SCSICmdField2Bit EXCEPT;
SCSICmdField2Byte MAXIMUM_NUMBER_OF_DESCRIPTORS;
UInt16 bufferSize;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
TOLERANCE = ( TOLERANCE_WRITE_EXCEPT >> 16 ) & 0x03;
WRITE = ( TOLERANCE_WRITE_EXCEPT >> 8 ) & 0x01;
EXCEPT = ( TOLERANCE_WRITE_EXCEPT & 0x03 );
MAXIMUM_NUMBER_OF_DESCRIPTORS = ( MAXIMUM_NUMBER_OF_DESCRIPTORS_AND_BUFFER_SIZE >> 16 ) & 0xFFFF;
bufferSize = MAXIMUM_NUMBER_OF_DESCRIPTORS_AND_BUFFER_SIZE & 0xFFFF;
buffer = IOMemoryDescriptor::withAddress ( performanceBuffer,
bufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_GET_PERFORMANCE,
( TOLERANCE << 3 ) | ( WRITE << 2 ) | EXCEPT,
( STARTING_LBA >> 24 ) & 0xFF,
( STARTING_LBA >> 16 ) & 0xFF,
( STARTING_LBA >> 8 ) & 0xFF,
STARTING_LBA & 0xFF,
0x00,
0x00,
( MAXIMUM_NUMBER_OF_DESCRIPTORS >> 8 ) & 0xFF,
MAXIMUM_NUMBER_OF_DESCRIPTORS & 0xFF,
0x00,
0x00 );
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( bufferSize );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
taskStatus = task->GetTaskStatus ( );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( taskStatus != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) taskStatus;
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::GetConfiguration ( UInt32 RT, UInt32 STARTING_FEATURE_NUMBER, vm_address_t configBuffer,
UInt32 bufferSize, vm_address_t senseDataBuffer, UInt32 * outTaskStatus )
{
SCSITask * task = NULL;
IOReturn status = kIOReturnSuccess;
bool state = true;
SCSIServiceResponse serviceResponse;
SCSITaskStatus taskStatus;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
SCSI_Sense_Data senseData;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
buffer = IOMemoryDescriptor::withAddress ( configBuffer,
bufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_GET_CONFIGURATION,
RT,
( STARTING_FEATURE_NUMBER >> 8 ) & 0xFF,
STARTING_FEATURE_NUMBER & 0xFF,
0x00,
0x00,
0x00,
( bufferSize >> 8 ) & 0xFF,
bufferSize & 0xFF,
0x00 );
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( bufferSize );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
taskStatus = task->GetTaskStatus ( );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( taskStatus != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) taskStatus;
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::ModeSense10 ( UInt32 LLBAAandDBD, UInt32 PCandPageCode, vm_address_t pageBuffer,
UInt32 bufferSize, vm_address_t senseDataBuffer, UInt32 * outTaskStatus )
{
SCSITask * task = NULL;
IOReturn status = kIOReturnSuccess;
bool state = true;
SCSIServiceResponse serviceResponse;
SCSITaskStatus taskStatus;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
UInt8 byte1, byte2;
UInt16 ALLOCATION_LENGTH;
SCSI_Sense_Data senseData;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
ALLOCATION_LENGTH = ( bufferSize & 0xFFFF );
byte1 = LLBAAandDBD & 0xFF;
byte2 = PCandPageCode & 0xFF;
buffer = IOMemoryDescriptor::withAddress ( pageBuffer,
ALLOCATION_LENGTH,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_MODE_SENSE_10,
byte1,
byte2,
0x00,
0x00,
0x00,
0x00,
( ALLOCATION_LENGTH >> 8 & 0xFF ),
( ALLOCATION_LENGTH & 0xFF ),
0x00 );
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( ALLOCATION_LENGTH );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
taskStatus = task->GetTaskStatus ( );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( taskStatus != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) taskStatus;
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::SetWriteParametersModePage ( vm_address_t paramBuffer,
UInt32 bufferSize,
vm_address_t senseDataBuffer,
UInt32 * outTaskStatus )
{
SCSITask * task = NULL;
IOReturn status = kIOReturnSuccess;
bool state = true;
SCSIServiceResponse serviceResponse;
SCSITaskStatus taskStatus;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
SCSI_Sense_Data senseData;
UInt16 pageSize = ( bufferSize & 0xFF );
SCSICmdField1Bit PF = 1;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
buffer = IOMemoryDescriptor::withAddress ( paramBuffer,
pageSize,
kIODirectionOut,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_MODE_SELECT_10,
( PF << 4),
0x00,
0x00,
0x00,
0x00,
0x00,
( pageSize >> 8 ) & 0xFF,
pageSize & 0xFF,
0x00 );
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromInitiatorToTarget );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( pageSize );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
taskStatus = task->GetTaskStatus ( );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( taskStatus != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) taskStatus;
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::GetTrayState ( UInt32 * trayState )
{
IOReturn status = kIOReturnSuccess;
UInt8 actualTrayState = 0;
bool state = false;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
status = ( ( IOSCSIMultimediaCommandsDevice * ) fProtocolInterface )->GetTrayState ( &actualTrayState );
if ( status == kIOReturnSuccess )
{
*trayState = actualTrayState;
}
return status;
}
IOReturn
SCSITaskUserClient::SetTrayState ( UInt32 trayState )
{
IOReturn status = kIOReturnSuccess;
UInt8 desiredTrayState = 0;
bool state = false;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
desiredTrayState = trayState & 0x01;
status = ( ( IOSCSIMultimediaCommandsDevice * ) fProtocolInterface )->SetTrayState ( desiredTrayState );
return status;
}
IOReturn
SCSITaskUserClient::ReadTableOfContents ( UInt32 MSF_FORMAT,
UInt32 TRACK_SESSION_NUMBER,
vm_address_t tocBuffer,
UInt32 bufferSize,
vm_address_t senseDataBuffer,
UInt32 * outTaskStatus )
{
IOReturn status = kIOReturnSuccess;
SCSITask * task = NULL;
SCSIServiceResponse serviceResponse;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
SCSI_Sense_Data senseData;
bool state = true;
UInt8 MSF = ( ( MSF_FORMAT >> 8 ) & 0x01 );
UInt8 FORMAT = ( MSF_FORMAT & 0xFF );
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
if ( bufferSize > 0xFFFF )
{
return kIOReturnBadArgument;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
buffer = IOMemoryDescriptor::withAddress ( tocBuffer,
bufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
if ( FORMAT & 0x04 )
{
task->SetCommandDescriptorBlock ( kSCSICmd_READ_TOC_PMA_ATIP,
MSF << 1,
FORMAT,
0x00,
0x00,
0x00,
TRACK_SESSION_NUMBER,
( bufferSize >> 8 ) & 0xFF,
bufferSize & 0xFF,
0x00 );
}
else
{
task->SetCommandDescriptorBlock ( kSCSICmd_READ_TOC_PMA_ATIP,
MSF << 1,
0x00,
0x00,
0x00,
0x00,
TRACK_SESSION_NUMBER,
( bufferSize >> 8 ) & 0xFF,
bufferSize & 0xFF,
( FORMAT & 0x03 ) << 6 );
}
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( bufferSize );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( task->GetTaskStatus ( ) != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) task->GetTaskStatus ( );
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::ReadDiscInformation ( vm_address_t discInfoBuffer, UInt32 bufferSize,
vm_address_t senseDataBuffer, UInt32 * outTaskStatus,
void *, void * )
{
IOReturn status = kIOReturnSuccess;
SCSITask * task = NULL;
SCSIServiceResponse serviceResponse;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
SCSI_Sense_Data senseData;
bool state = true;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
if ( bufferSize > 0xFFFF )
{
return kIOReturnBadArgument;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
buffer = IOMemoryDescriptor::withAddress ( discInfoBuffer,
bufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_READ_DISC_INFORMATION,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
( bufferSize >> 8 ) & 0xFF,
bufferSize & 0xFF,
0x00 );
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( bufferSize );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( task->GetTaskStatus ( ) != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) task->GetTaskStatus ( );
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::ReadTrackInformation ( UInt32 ADDRESS_NUMBER_TYPE,
UInt32 LOGICAL_BLOCK_ADDRESS_TRACK_SESSION_NUMBER,
vm_address_t trackInfoBuffer,
UInt32 bufferSize, vm_address_t senseDataBuffer,
UInt32 * outTaskStatus )
{
IOReturn status = kIOReturnSuccess;
SCSITask * task = NULL;
SCSIServiceResponse serviceResponse;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
SCSI_Sense_Data senseData;
bool state = true;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
if ( bufferSize > 0xFFFF )
{
return kIOReturnBadArgument;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
buffer = IOMemoryDescriptor::withAddress ( trackInfoBuffer,
bufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_READ_TRACK_INFORMATION,
ADDRESS_NUMBER_TYPE & 0x03,
( LOGICAL_BLOCK_ADDRESS_TRACK_SESSION_NUMBER >> 24 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS_TRACK_SESSION_NUMBER >> 16 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS_TRACK_SESSION_NUMBER >> 8 ) & 0xFF,
LOGICAL_BLOCK_ADDRESS_TRACK_SESSION_NUMBER & 0xFF,
0x00,
( bufferSize >> 8 ) & 0xFF,
bufferSize & 0xFF,
0x00 );
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( bufferSize );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( task->GetTaskStatus ( ) != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) task->GetTaskStatus ( );
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
IOReturn
SCSITaskUserClient::ReadDVDStructure ( UInt32 LBA,
UInt32 LAYER_FORMAT,
vm_address_t dvdBuffer,
UInt32 bufferSize,
vm_address_t senseDataBuffer,
UInt32 * outTaskStatus )
{
IOReturn status = kIOReturnSuccess;
SCSITask * task = NULL;
SCSIServiceResponse serviceResponse;
IOMemoryDescriptor * buffer;
IOMemoryDescriptor * reqSenseBuffer;
SCSI_Sense_Data senseData;
bool state = true;
UInt8 LAYER = ( LAYER_FORMAT >> 8 ) & 0xFF;
UInt8 FORMAT = LAYER_FORMAT & 0xFF;
if ( fProtocolInterface == NULL )
return kIOReturnNoDevice;
state = fProtocolInterface->GetUserClientExclusivityState ( );
if ( state == true )
{
return kIOReturnExclusiveAccess;
}
if ( bufferSize > 0xFFFF )
{
return kIOReturnBadArgument;
}
task = new SCSITask;
if ( task == NULL )
return kIOReturnNoMemory;
if ( task->ResetForNewTask ( ) == false )
{
task->release ( );
task = NULL;
return kIOReturnNoMemory;
}
buffer = IOMemoryDescriptor::withAddress ( dvdBuffer,
bufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
task->release ( );
return kIOReturnNoMemory;
}
task->SetCommandDescriptorBlock ( kSCSICmd_READ_DVD_STRUCTURE,
0x00,
( LBA >> 24 ) & 0xFF,
( LBA >> 16 ) & 0xFF,
( LBA >> 8 ) & 0xFF,
LBA & 0xFF,
LAYER,
FORMAT,
( bufferSize >> 8 ) & 0xFF,
bufferSize & 0xFF,
0x00,
0x00 );
task->SetTimeoutDuration ( 30 * 1000 );
task->SetDataTransferDirection ( kSCSIDataTransfer_FromTargetToInitiator );
task->SetDataBuffer ( buffer );
task->SetRequestedDataTransferCount ( bufferSize );
IOReturn bufErr = buffer->prepare ( );
if ( bufErr != kIOReturnSuccess )
{
STATUS_LOG ( ( "Error preparing buffer" ) );
}
serviceResponse = SendCommand ( task );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( task->GetTaskStatus ( ) != kSCSITaskStatus_GOOD )
{
if ( task->GetAutoSenseData ( &senseData ) )
{
reqSenseBuffer = IOMemoryDescriptor::withAddress ( senseDataBuffer,
sizeof ( SCSI_Sense_Data ),
kIODirectionIn,
fTask );
if ( reqSenseBuffer != NULL )
{
reqSenseBuffer->prepare ( );
reqSenseBuffer->writeBytes ( 0, &senseData, sizeof ( SCSI_Sense_Data ) );
reqSenseBuffer->complete ( );
reqSenseBuffer->release ( );
}
}
}
}
*outTaskStatus = ( UInt32 ) task->GetTaskStatus ( );
buffer->complete ( );
buffer->release ( );
task->release ( );
return status;
}
SCSIServiceResponse
SCSITaskUserClient::SendCommand ( SCSITask * request )
{
SCSIServiceResponse serviceResponse;
IOSyncer * fSyncLock;
fSyncLock = IOSyncer::create ( false );
if ( fSyncLock == NULL )
{
PANIC_NOW ( ( "SCSITaskUserClient::SendCommand Allocate fSyncLock failed.") );
}
fSyncLock->signal ( kIOReturnSuccess, false );
request->SetTaskCompletionCallback ( &SCSITaskUserClient::sTaskCallback );
request->SetApplicationLayerReference ( ( void * ) fSyncLock );
request->SetAutosenseCommand ( 0x03, 0x00, 0x00, 0x00, sizeof ( SCSI_Sense_Data ), 0x00 );
fSyncLock->reinit ( );
fProtocolInterface->ExecuteCommand ( request );
serviceResponse = ( SCSIServiceResponse ) fSyncLock->wait ( false );
fSyncLock->release ( );
return serviceResponse;
}
void
SCSITaskUserClient::sTaskCallback ( SCSITaskIdentifier completedTask )
{
IOSyncer * fSyncLock;
SCSIServiceResponse serviceResponse;
SCSITask * scsiRequest;
STATUS_LOG ( ( "SCSITaskUserClient::sTaskCallback called.\n") );
scsiRequest = OSDynamicCast( SCSITask, completedTask );
if ( scsiRequest == NULL )
{
PANIC_NOW(( "SCSITaskUserClient::sAsyncTaskCallback scsiRequest==NULL." ));
}
fSyncLock = ( IOSyncer * ) scsiRequest->GetApplicationLayerReference ( );
serviceResponse = scsiRequest->GetServiceResponse ( );
fSyncLock->signal ( serviceResponse, false );
}
void
SCSITaskUserClient::sAsyncTaskCallback ( SCSITaskIdentifier completedTask )
{
OSAsyncReference asyncRef;
IOMemoryDescriptor * buffer;
UInt8 * internalRefCon;
IOReturn status;
SCSITask * scsiRequest;
STATUS_LOG ( ( "SCSITaskUserClient::sAsyncTaskCallback called.\n") );
scsiRequest = OSDynamicCast( SCSITask, completedTask );
if ( scsiRequest == NULL )
{
PANIC_NOW(( "SCSITaskUserClient::sAsyncTaskCallback scsiRequest==NULL." ));
}
buffer = scsiRequest->GetDataBuffer ( );
if ( buffer != NULL )
buffer->complete ( );
internalRefCon = ( UInt8 * ) scsiRequest->GetApplicationLayerReference ( );
bcopy ( internalRefCon, asyncRef, sizeof ( OSAsyncReference ) );
STATUS_LOG ( ( "asyncRef[0] = %d\n", asyncRef[0] ) );
if ( asyncRef[0] != 0 )
{
void * args[16];
UInt64 actualTransferCount;
STATUS_LOG ( ( "serviceResponse = %d\n", scsiRequest->GetServiceResponse ( ) ) );
STATUS_LOG ( ( "taskStatus = %d\n", scsiRequest->GetTaskStatus ( ) ) );
args[0] = ( void * ) scsiRequest->GetServiceResponse ( );
args[1] = ( void * ) scsiRequest->GetTaskStatus ( );
actualTransferCount = scsiRequest->GetRealizedDataTransferCount ( );
STATUS_LOG ( ( "actualTransferCount = %ld\n", ( UInt32 ) actualTransferCount ) );
args[2] = ( void * )( ( actualTransferCount >> 32 ) & 0xFFFFFFFF );
args[3] = ( void * )( actualTransferCount & 0xFFFFFFFF );
status = sendAsyncResult ( asyncRef, kIOReturnSuccess, ( void ** ) &args, 4 );
STATUS_LOG ( ( "sendAsyncResult status = 0x%08x\n", status ) );
}
}
IOReturn
SCSITaskUserClient::message ( UInt32 type, IOService * provider, void * arg )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "message called\n" ) );
STATUS_LOG ( ( "type = %ld, provider = %p\n", type, provider ) );
switch ( type )
{
case kIOMessageServiceIsRequestingClose:
break;
case kIOMessageServiceIsTerminated:
STATUS_LOG ( ( "kIOMessageServiceIsTerminated called\n" ) );
status = HandleTermination ( provider );
break;
default:
status = super::message ( type, provider, arg );
break;
}
return status;
}
IOReturn
SCSITaskUserClient::HandleTermination ( IOService * provider )
{
IOReturn status = kIOReturnSuccess;
if ( provider->isOpen ( this ) )
{
STATUS_LOG ( ( "Closing provider\n" ) );
provider->close ( this );
STATUS_LOG ( ( "Closed provider\n" ) );
}
STATUS_LOG ( ( "Detaching provider\n" ) );
detach ( provider );
fProvider = NULL;
STATUS_LOG ( ( "Detached provider\n" ) );
if ( fProtocolInterface != NULL )
{
STATUS_LOG ( ( "Releasing exclusive access\n" ) );
( void ) ReleaseExclusiveAccess ( );
fProtocolInterface = NULL;
}
if ( fSetOfSCSITasks != NULL )
{
STATUS_LOG ( ( "Releasing any leftover SCSITasks...\n" ) );
for ( UInt32 index = 0; index < fSetOfSCSITasks->getCount ( ); index ++ )
{
SCSITask * task = NULL;
task = ( SCSITask * ) fSetOfSCSITasks->getAnyObject ( );
if ( task == NULL )
break;
STATUS_LOG ( ( "Releasing task = %p\n", task ) );
ReleaseTask ( task, ( void * ) NULL, ( void * ) NULL,
( void * ) NULL, ( void * ) NULL, ( void * ) NULL );
}
fSetOfSCSITasks = NULL;
}
return status;
}