IOUSBMassStorageUFISubclass.cpp [plain text]
#include <IOKit/usb/IOUSBMassStorageUFISubclass.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/usb/IOUFIStorageServices.h>
#include <IOKit/scsi-commands/SCSICmds_INQUIRY_Definitions.h>
#include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
#if (USB_MASS_STORAGE_DEBUG == 0)
#define USB_MSC_UFI_DEBUGGING_LEVEL 0
#else
#define USB_MSC_UFI_DEBUGGING_LEVEL 3
#endif
#if ( USB_MSC_UFI_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( USB_MSC_UFI_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( USB_MSC_UFI_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define super IOUSBMassStorageClass
OSDefineMetaClassAndStructors( IOUSBMassStorageUFISubclass, IOUSBMassStorageClass )
bool
IOUSBMassStorageUFISubclass::BeginProvidedServices( void )
{
fDeviceCharacteristicsDictionary = OSDictionary::withCapacity( 1 );
if( fDeviceCharacteristicsDictionary == NULL )
{
ERROR_LOG( ( "%s: couldn't device characteristics dictionary.\n", getName() ) );
return false;
}
if( InitializeDeviceSupport() == false )
{
return false;
}
CreateStorageServiceNub();
EnablePolling();
return true;
}
bool
IOUSBMassStorageUFISubclass::EndProvidedServices( void )
{
return true;
}
#pragma mark -
#pragma mark Static Class Methods
void
IOUSBMassStorageUFISubclass::sProcessPoll( void * theUFIDriver, void * refCon )
{
IOUSBMassStorageUFISubclass * driver;
driver = (IOUSBMassStorageUFISubclass *) theUFIDriver;
driver->ProcessPoll();
if( driver->fPollingMode != kPollingMode_Suspended )
{
driver->EnablePolling();
}
driver->release();
}
#pragma mark -
bool
IOUSBMassStorageUFISubclass::InitializeDeviceSupport( void )
{
bool setupSuccessful = false;
fMediumPresent = false;
fMediumIsWriteProtected = true;
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::InitializeDeviceSupport called\n" ) );
ClearNotReadyStatus();
setupSuccessful = DetermineDeviceCharacteristics();
if( setupSuccessful == true )
{
fPollingMode = kPollingMode_NewMedia;
fPollingThread = thread_call_allocate(
( thread_call_func_t ) IOUSBMassStorageUFISubclass::sProcessPoll,
( thread_call_param_t ) this );
if( fPollingThread == NULL )
{
ERROR_LOG( ( "fPollingThread allocation failed.\n" ) );
setupSuccessful = false;
goto ERROR_EXIT;
}
}
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::InitializeDeviceSupport setupSuccessful = %d\n", setupSuccessful ) );
ERROR_EXIT:
return setupSuccessful;
}
void
IOUSBMassStorageUFISubclass::SuspendDeviceSupport( void )
{
if( fPollingMode != kPollingMode_Suspended )
{
DisablePolling();
}
}
void
IOUSBMassStorageUFISubclass::ResumeDeviceSupport( void )
{
if( fMediumPresent == false )
{
fPollingMode = kPollingMode_NewMedia;
EnablePolling();
}
}
void
IOUSBMassStorageUFISubclass::TerminateDeviceSupport( void )
{
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::cleanUp called.\n" ) );
if ( fPollingThread != NULL )
{
thread_call_free ( fPollingThread );
fPollingThread = NULL;
}
}
bool
IOUSBMassStorageUFISubclass::ClearNotReadyStatus( void )
{
SCSI_Sense_Data senseBuffer;
IOMemoryDescriptor * bufferDesc;
SCSITaskIdentifier request;
bool driveReady = false;
bool result = true;
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
STATUS_LOG( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
bufferDesc = IOMemoryDescriptor::withAddress( ( void * ) &senseBuffer,
kSenseDefaultSize,
kIODirectionIn );
request = GetSCSITask();
do
{
if( TEST_UNIT_READY( request ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW( ( "IOUSBMassStorageUFISubclass::ClearNotReadyStatus malformed command" ) );
}
if( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
bool validSense = false;
if ( GetTaskStatus( request ) == kSCSITaskStatus_CHECK_CONDITION )
{
validSense = GetAutoSenseData( request, &senseBuffer );
if( validSense == false )
{
if( REQUEST_SENSE( request, bufferDesc, kSenseDefaultSize ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW( ( "IOUSBMassStorageUFISubclass::ClearNotReadyStatus malformed command" ) );
}
if( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
validSense = true;
}
}
if( validSense == true )
{
if( ( ( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ) == kSENSE_KEY_NOT_READY ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE == 0x04 ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x01 ) )
{
STATUS_LOG( ( "%s::drive not ready\n", getName ( ) ) );
driveReady = false;
IOSleep( 200 );
}
else if( ( ( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ) == kSENSE_KEY_NOT_READY ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE == 0x04 ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x02 ) )
{
if( START_STOP_UNIT( request, 0x00, 0x00, 0x01 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
}
else
{
driveReady = true;
STATUS_LOG( ( "%s::drive READY\n", getName ( ) ) );
}
STATUS_LOG( ( "sense data: %01x, %02x, %02x\n",
( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ),
senseBuffer.ADDITIONAL_SENSE_CODE,
senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER ) );
}
}
else
{
driveReady = true;
}
}
else
{
IOSleep( 200 );
}
} while( ( driveReady == false ) && ( isInactive() == false ) );
bufferDesc->release();
ReleaseSCSITask( request );
result = isInactive() ? false : true;
return result;
}
void
IOUSBMassStorageUFISubclass::EnablePolling( void )
{
AbsoluteTime time;
if(( fPollingMode != kPollingMode_Suspended ) && fPollingThread )
{
retain();
clock_interval_to_deadline( 1000, kMillisecondScale, &time );
thread_call_enter_delayed( fPollingThread, time );
}
}
void
IOUSBMassStorageUFISubclass::DisablePolling( void )
{
fPollingMode = kPollingMode_Suspended;
if( thread_call_cancel( fPollingThread ) )
{
release();
}
}
bool
IOUSBMassStorageUFISubclass::DetermineDeviceCharacteristics( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request = NULL;
IOMemoryDescriptor * bufferDesc = NULL;
SCSICmd_INQUIRY_StandardData * inquiryBuffer = NULL;
UInt8 inquiryBufferCount = sizeof( SCSICmd_INQUIRY_StandardData );
bool succeeded = false;
int loopCount;
char tempString[17]; OSString * string;
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::DetermineDeviceCharacteristics called\n" ) );
inquiryBuffer = ( SCSICmd_INQUIRY_StandardData * ) IOMalloc( inquiryBufferCount );
if( inquiryBuffer == NULL )
{
STATUS_LOG( ( "%s: Couldn't allocate Inquiry buffer.\n", getName ( ) ) );
goto ErrorExit;
}
bufferDesc = IOMemoryDescriptor::withAddress( inquiryBuffer, inquiryBufferCount, kIODirectionIn );
if( bufferDesc == NULL )
{
ERROR_LOG ( ( "%s: Couldn't alloc Inquiry buffer: ", getName ( ) ) );
goto ErrorExit;
}
request = GetSCSITask();
if( request == NULL )
{
goto ErrorExit;
}
if( INQUIRY( request,
bufferDesc,
0,
inquiryBufferCount ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW( ( "IOUSBMassStorageUFISubclass::DetermineDeviceCharacteristics malformed command" ) );
goto ErrorExit;
}
if( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
ERROR_LOG ( ( "%s: Inquiry completed with an error: ", getName ( ) ) );
goto ErrorExit;
}
for( loopCount = 0; loopCount < kINQUIRY_VENDOR_IDENTIFICATION_Length; loopCount++ )
{
tempString[loopCount] = inquiryBuffer->VENDOR_IDENTIFICATION[loopCount];
}
tempString[loopCount] = 0;
for( loopCount = kINQUIRY_VENDOR_IDENTIFICATION_Length - 1; loopCount >= 0; loopCount-- )
{
if( tempString[loopCount] != ' ' )
{
tempString[loopCount+1] = '\0';
break;
}
}
string = OSString::withCString( tempString );
if( string != NULL )
{
fDeviceCharacteristicsDictionary->setObject( kIOPropertyVendorNameKey, string );
string->release();
}
for( loopCount = 0; loopCount < kINQUIRY_PRODUCT_IDENTIFICATION_Length; loopCount++ )
{
tempString[loopCount] = inquiryBuffer->PRODUCT_INDENTIFICATION[loopCount];
}
tempString[loopCount] = 0;
for( loopCount = kINQUIRY_PRODUCT_IDENTIFICATION_Length - 1; loopCount >= 0; loopCount-- )
{
if( tempString[loopCount] != ' ' )
{
tempString[loopCount+1] = '\0';
break;
}
}
string = OSString::withCString( tempString );
if( string != NULL )
{
fDeviceCharacteristicsDictionary->setObject( kIOPropertyProductNameKey, string );
string->release();
}
for( loopCount = 0; loopCount < kINQUIRY_PRODUCT_REVISION_LEVEL_Length; loopCount++ )
{
tempString[loopCount] = inquiryBuffer->PRODUCT_REVISION_LEVEL[loopCount];
}
tempString[loopCount] = 0;
for( loopCount = kINQUIRY_PRODUCT_REVISION_LEVEL_Length - 1; loopCount >= 0; loopCount-- )
{
if ( tempString[loopCount] != ' ' )
{
tempString[loopCount+1] = '\0';
break;
}
}
string = OSString::withCString( tempString );
if( string != NULL )
{
fDeviceCharacteristicsDictionary->setObject( kIOPropertyProductRevisionLevelKey, string );
string->release();
}
succeeded = true;
ErrorExit:
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::DetermineDeviceCharacteristics exiting\n" ) );
if( request )
{
ReleaseSCSITask( request );
request = NULL;
}
if( bufferDesc )
{
bufferDesc->release();
bufferDesc = NULL;
}
if( inquiryBuffer )
{
IOFree( ( void * ) inquiryBuffer, inquiryBufferCount );
inquiryBuffer = NULL;
}
return succeeded;
}
void
IOUSBMassStorageUFISubclass::SetMediumCharacteristics( UInt32 blockSize, UInt32 blockCount )
{
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::SetMediumCharacteristics called\n" ) );
STATUS_LOG( ( "mediumBlockSize = %ld, blockCount = %ld\n", blockSize, blockCount ) );
fMediumBlockSize = blockSize;
fMediumBlockCount = blockCount;
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::SetMediumCharacteristics exiting\n" ) );
}
void
IOUSBMassStorageUFISubclass::ResetMediumCharacteristics( void )
{
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::ResetMediumCharacteristics called\n" ) );
fMediumBlockSize = 0;
fMediumBlockCount = 0;
fMediumPresent = false;
fMediumIsWriteProtected = true;
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::ResetMediumCharacteristics exiting\n" ) );
}
void
IOUSBMassStorageUFISubclass::CreateStorageServiceNub( void )
{
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::CreateStorageServiceNub entering.\n" ) );
IOService * nub = new IOUFIStorageServices;
if( nub == NULL )
{
ERROR_LOG( ( "IOUSBMassStorageUFISubclass::CreateStorageServiceNub failed\n" ) );
PANIC_NOW(( "IOUSBMassStorageUFISubclass::CreateStorageServiceNub failed\n" ));
return;
}
nub->init();
if( !nub->attach( this ) )
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::CreateStorageServiceNub unable to attach nub" ));
return;
}
nub->registerService();
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::CreateStorageServiceNub exiting.\n" ) );
nub->release();
}
void
IOUSBMassStorageUFISubclass::ProcessPoll( void )
{
switch( fPollingMode )
{
case kPollingMode_NewMedia:
{
PollForNewMedia();
}
break;
case kPollingMode_MediaRemoval:
{
PollForMediaRemoval();
}
break;
default:
{
ERROR_LOG ( ( "%s:ProcessPoll Unknown polling mode.\n", getName() ) );
}
break;
}
}
void
IOUSBMassStorageUFISubclass::PollForNewMedia( void )
{
bool mediaFound = false;
UInt64 blockCount;
UInt64 blockSize;
fMediumPresent = false;
mediaFound = DetermineMediaPresence();
if( mediaFound == false )
{
return;
}
if( DetermineMediumCapacity( &blockSize, &blockCount ) == false )
{
return;
}
SetMediumCharacteristics( blockSize, blockCount );
fMediumIsWriteProtected = DetermineMediumWriteProtectState();
fMediumPresent = true;
fPollingMode = kPollingMode_Suspended;
messageClients( kIOMessageMediaStateHasChanged,
( void * ) kIOMediaStateOnline,
sizeof( IOMediaState ) );
}
bool
IOUSBMassStorageUFISubclass::DetermineMediaPresence( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request = NULL;
bool mediaFound = false;
STATUS_LOG(( "IOUSBMassStorageUFISubclass::DetermineMediaPresence called" ));
request = GetSCSITask();
if( request == NULL )
{
return false;
}
if( TEST_UNIT_READY( request ) == true )
{
serviceResponse = SendCommand( request, 10 * 1000 );
}
else
{
ERROR_LOG(( "IOUSBMassStorageUFISubclass::DetermineMediaPresence malformed command" ));
goto CHECK_DONE;
}
if( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
bool validSense;
SCSI_Sense_Data senseBuffer;
validSense = GetAutoSenseData( request, &senseBuffer );
if( validSense == false )
{
IOMemoryDescriptor * bufferDesc;
bufferDesc = IOMemoryDescriptor::withAddress ( ( void * ) &senseBuffer,
kSenseDefaultSize,
kIODirectionIn );
if( bufferDesc == NULL )
{
ERROR_LOG ( ( "%s: could not allocate sense buffer descriptor.\n", getName() ) );
goto CHECK_DONE;
}
if( REQUEST_SENSE( request, bufferDesc, kSenseDefaultSize ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
ERROR_LOG(( "IOUSBMassStorageUFISubclass::PollForMedia malformed command" ));
bufferDesc->release();
goto CHECK_DONE;
}
bufferDesc->release();
if ( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
ERROR_LOG ( ( "%s: REQUEST_SENSE failed\n", getName() ) );
goto CHECK_DONE;
}
}
if( ( senseBuffer.ADDITIONAL_SENSE_CODE == 0x04 ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x02 ) )
{
if( START_STOP_UNIT( request, 0x00,0x00, 1 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
goto CHECK_DONE;
}
else if( ( senseBuffer.ADDITIONAL_SENSE_CODE != 0x00 ) ||
( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER != 0x00 ) )
{
ERROR_LOG ( ( "ASC = 0x%02x, ASCQ = 0x%02x\n",
senseBuffer.ADDITIONAL_SENSE_CODE,
senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER ) );
goto CHECK_DONE;
}
}
else
{
ERROR_LOG ( ( "serviceResponse = %d\n", serviceResponse ) );
goto CHECK_DONE;
}
UInt8 formatBuffer[12];
IOMemoryDescriptor * formatDesc;
formatDesc = IOMemoryDescriptor::withAddress ( ( void * ) &formatBuffer[0],
12,
kIODirectionIn );
if( formatDesc == NULL )
{
ERROR_LOG ( ( "%s: could not allocate sense buffer descriptor.\n", getName() ) );
goto CHECK_DONE;
}
if ( READ_FORMAT_CAPACITIES( request, formatDesc, 12 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
ERROR_LOG(( "IOUSBMassStorageUFISubclass::PollForMedia malformed command" ));
formatDesc->release();
goto CHECK_DONE;
}
formatDesc->release();
if( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if( GetTaskStatus( request ) == kSCSITaskStatus_CHECK_CONDITION )
{
bool validSense;
SCSI_Sense_Data senseBuffer;
validSense = GetAutoSenseData( request, &senseBuffer );
if( validSense == false )
{
IOMemoryDescriptor * bufferDesc;
bufferDesc = IOMemoryDescriptor::withAddress ( ( void * ) &senseBuffer,
kSenseDefaultSize,
kIODirectionIn );
if( bufferDesc == NULL )
{
ERROR_LOG ( ( "%s: could not allocate sense buffer descriptor.\n", getName() ) );
goto CHECK_DONE;
}
if( REQUEST_SENSE( request, bufferDesc, kSenseDefaultSize ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
ERROR_LOG(( "IOUSBMassStorageUFISubclass::PollForMedia malformed command" ));
bufferDesc->release();
goto CHECK_DONE;
}
bufferDesc->release();
if ( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
ERROR_LOG ( ( "%s: REQUEST_SENSE failed\n", getName() ) );
goto CHECK_DONE;
}
}
if( (( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ) == kSENSE_KEY_ILLEGAL_REQUEST )
&& ( senseBuffer.ADDITIONAL_SENSE_CODE == 0x20 ) )
{
mediaFound = true;
goto CHECK_DONE;
}
}
else if( GetTaskStatus( request ) != kSCSITaskStatus_GOOD )
{
goto CHECK_DONE;
}
}
else
{
ERROR_LOG ( ( "serviceResponse = %d\n", serviceResponse ) );
goto CHECK_DONE;
}
STATUS_LOG ( ( "%s: Formats data: ", getName() ) );
for ( int i=0; i < 12; i ++ )
{
STATUS_LOG(("%X : ", formatBuffer[i]));
}
STATUS_LOG(( "\n" ));
if( formatBuffer[8] == 0x01 )
{
STATUS_LOG ( ( "%s: unformatted media was found.\n", getName() ) );
goto CHECK_DONE;
}
else if ( formatBuffer[8] != 0x02 )
{
STATUS_LOG ( ( "%s: no media was found.\n", getName() ) );
goto CHECK_DONE;
}
STATUS_LOG ( ( "%s: media was found.\n", getName() ) );
mediaFound = true;
CHECK_DONE:
if( request != NULL )
{
ReleaseSCSITask( request );
request = NULL;
}
return mediaFound;
}
bool
IOUSBMassStorageUFISubclass::DetermineMediumCapacity( UInt64 * blockSize, UInt64 * blockCount )
{
SCSIServiceResponse serviceResponse= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
UInt32 capacityData[2];
IOMemoryDescriptor * bufferDesc = NULL;
SCSITaskIdentifier request = NULL;
bool result;
*blockSize = 0;
*blockCount = 0;
request = GetSCSITask();
if ( request == NULL )
{
result = false;
goto isDone;
}
bufferDesc = IOMemoryDescriptor::withAddress( capacityData, 8, kIODirectionIn );
if ( bufferDesc == NULL )
{
result = false;
goto isDone;
}
if ( READ_CAPACITY( request, bufferDesc, 0, 0x00, 0 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
ERROR_LOG(( "IOUSBMassStorageUFISubclass::PollForMedia malformed command" ));
result = false;
goto isDone;
}
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( GetTaskStatus( request ) == kSCSITaskStatus_GOOD ) )
{
*blockSize = ( UInt64 ) OSSwapBigToHostInt32 ( capacityData[1] );
*blockCount = ( UInt64 ) ( OSSwapBigToHostInt32 ( capacityData[0] ) + 1 );
STATUS_LOG ( ( "%s: Media capacity: %x and block size: %x\n",
getName(), (UInt32) *blockCount, (UInt32) *blockSize ) );
result = true;
}
else
{
ERROR_LOG ( ( "%s: Read Capacity failed\n", getName() ) );
result = false;
}
isDone:
if ( request != NULL )
{
ReleaseSCSITask( request );
}
if ( bufferDesc != NULL )
{
bufferDesc->release();
}
return result;
}
bool
IOUSBMassStorageUFISubclass::DetermineMediumWriteProtectState( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
UInt8 modeBuffer[8];
IOMemoryDescriptor * bufferDesc = NULL;
SCSITaskIdentifier request = NULL;
bool mediumIsProtected = true;
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::checkWriteProtection called\n" ) );
request = GetSCSITask();
if( request == NULL )
{
return true;
}
bufferDesc = IOMemoryDescriptor::withAddress( modeBuffer,
8,
kIODirectionIn );
if ( bufferDesc == NULL )
{
goto WP_CHECK_DONE;
}
if ( MODE_SENSE_10( request,
bufferDesc,
0,
0,
0x3F,
8 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
ERROR_LOG(( "IOUSBMassStorageUFISubclass::CheckWriteProtection malformed command" ));
goto WP_CHECK_DONE;
}
if( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( GetTaskStatus( request ) == kSCSITaskStatus_GOOD ) )
{
if( ( modeBuffer[3] & 0x80 ) != 0 )
{
mediumIsProtected = true;
}
else
{
mediumIsProtected = false;
}
}
WP_CHECK_DONE:
if( bufferDesc != NULL )
{
bufferDesc->release();
bufferDesc = NULL;
}
if( request != NULL )
{
ReleaseSCSITask( request );
request = NULL;
}
return mediumIsProtected;
}
void
IOUSBMassStorageUFISubclass::PollForMediaRemoval( void )
{
SCSIServiceResponse serviceResponse= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request = NULL;
bool mediaRemoved = false;
request = GetSCSITask();
if( request == NULL )
{
return;
}
if( TEST_UNIT_READY( request ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::PollForMedia malformed command" ));
goto REMOVE_CHECK_DONE;
}
if( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
bool validSense;
SCSI_Sense_Data senseBuffer;
IOMemoryDescriptor * bufferDesc;
validSense = GetAutoSenseData( request, &senseBuffer );
if( validSense == false )
{
bufferDesc = IOMemoryDescriptor::withAddress( ( void * ) &senseBuffer,
kSenseDefaultSize,
kIODirectionIn );
if( bufferDesc == NULL )
{
ERROR_LOG( ( "%s: could not allocate sense buffer descriptor.\n", getName() ) );
goto REMOVE_CHECK_DONE;
}
if( REQUEST_SENSE( request, bufferDesc, kSenseDefaultSize ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::PollForMedia malformed command" ));
bufferDesc->release();
goto REMOVE_CHECK_DONE;
}
bufferDesc->release();
if( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
ERROR_LOG ( ( "%s: REQUEST_SENSE failed\n", getName() ) );
goto REMOVE_CHECK_DONE;
}
}
if( ( senseBuffer.ADDITIONAL_SENSE_CODE == 0x28 ) ||
( senseBuffer.ADDITIONAL_SENSE_CODE == 0x3A ) )
{
mediaRemoved = true;
}
}
REMOVE_CHECK_DONE:
if( request != NULL )
{
ReleaseSCSITask( request );
request = NULL;
}
if( mediaRemoved == true )
{
fPollingMode = kPollingMode_NewMedia;
}
}
#pragma mark -
#pragma mark Client Requests Support
void
IOUSBMassStorageUFISubclass::AsyncReadWriteComplete( SCSITaskIdentifier request )
{
void * clientData;
IOReturn status;
UInt64 actCount = 0;
IOUSBMassStorageUFISubclass * taskOwner;
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest == NULL )
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::AsyncReadWriteComplete scsiRequest==NULL." ));
}
clientData = scsiRequest->GetApplicationLayerReference();
if (( scsiRequest->GetServiceResponse() == kSCSIServiceResponse_TASK_COMPLETE ) &&
( scsiRequest->GetTaskStatus() == kSCSITaskStatus_GOOD ))
{
status = kIOReturnSuccess;
}
else
{
ERROR_LOG ( ( "Error on read/write\n" ) );
status = kIOReturnError;
}
if ( status == kIOReturnSuccess )
{
actCount = scsiRequest->GetDataBuffer()->getLength();
}
taskOwner = OSDynamicCast( IOUSBMassStorageUFISubclass, scsiRequest->GetTaskOwner());
if ( taskOwner == NULL )
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::AsyncReadWriteComplete taskOwner==NULL." ));
}
taskOwner->ReleaseSCSITask( request );
IOUFIStorageServices::AsyncReadWriteComplete( clientData, status, actCount );
}
IOReturn
IOUSBMassStorageUFISubclass::IssueRead( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
STATUS_LOG ( ( "%s: syncRead Attempted\n", getName() ) );
request = GetSCSITask ( );
if ( READ_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == false )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::IssueRead malformed command" ));
}
ReleaseSCSITask ( request );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
return kIOReturnSuccess;
}
else
{
return kIOReturnError;
}
}
IOReturn
IOUSBMassStorageUFISubclass::IssueRead( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
void * clientData )
{
IOReturn status = kIOReturnSuccess;
SCSITaskIdentifier request;
STATUS_LOG ( ( "%s: asyncRead Attempted\n", getName() ) );
request = GetSCSITask();
if (READ_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
SetApplicationLayerReference( request, clientData );
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::IssueRead send command.\n" ) );
SendCommand( request, 0, &this->AsyncReadWriteComplete );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::IssueWrite malformed command" ));
status = kIOReturnError;
}
return status;
}
IOReturn
IOUSBMassStorageUFISubclass::IssueWrite( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
STATUS_LOG ( ( "%s: syncWrite Attempted\n", getName() ) );
request = GetSCSITask();
if ( WRITE_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::IssueWrite malformed command" ));
}
ReleaseSCSITask ( request );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
return kIOReturnSuccess;
}
else
{
return kIOReturnError;
}
}
IOReturn
IOUSBMassStorageUFISubclass::IssueWrite( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
void * clientData )
{
IOReturn status = kIOReturnSuccess;
SCSITaskIdentifier request;
STATUS_LOG ( ( "%s: asyncWrite Attempted\n", getName() ) );
request = GetSCSITask();
if ( WRITE_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
SetApplicationLayerReference( request, clientData );
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::IssueWrite send command.\n" ) );
SendCommand( request, 0, &this->AsyncReadWriteComplete );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::IssueWrite malformed command" ));
}
return status;
}
IOReturn
IOUSBMassStorageUFISubclass::SyncReadWrite ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
UInt64 blockSize )
{
IODirection direction;
IOReturn theErr;
if ( GetInterfaceReference() == NULL )
{
return kIOReturnOffline;
}
direction = buffer->getDirection();
if ( direction == kIODirectionIn )
{
theErr = IssueRead( buffer, startBlock, blockCount );
}
else if ( direction == kIODirectionOut )
{
theErr = IssueWrite( buffer, startBlock, blockCount );
}
else
{
ERROR_LOG ( ( "%s: doSyncReadWrite bad direction argument\n", getName() ) );
theErr = kIOReturnBadArgument;
}
return theErr;
}
IOReturn
IOUSBMassStorageUFISubclass::AsyncReadWrite ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
UInt64 blockSize,
void * clientData )
{
IODirection direction;
IOReturn theErr;
if ( GetInterfaceReference() == NULL )
{
return kIOReturnOffline;
}
direction = buffer->getDirection();
if ( direction == kIODirectionIn )
{
IssueRead( buffer, startBlock, blockCount, clientData );
theErr = kIOReturnSuccess;
}
else if ( direction == kIODirectionOut )
{
IssueWrite( buffer, startBlock, blockCount, clientData );
theErr = kIOReturnSuccess;
}
else
{
ERROR_LOG ( ( "%s: doAsyncReadWrite bad direction argument\n", getName() ) );
theErr = kIOReturnBadArgument;
}
return theErr;
}
IOReturn
IOUSBMassStorageUFISubclass::EjectTheMedium( void )
{
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::EjectTheMedium called\n" ) );
if ( GetInterfaceReference() == NULL )
{
return kIOReturnOffline;
}
ResetMediumCharacteristics();
fPollingMode = kPollingMode_MediaRemoval;
EnablePolling();
return kIOReturnSuccess;
}
IOReturn
IOUSBMassStorageUFISubclass::FormatMedium( UInt64 blockCount, UInt64 blockSize )
{
IOReturn theErr = kIOReturnSuccess;
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::FormatMedium called\n" ) );
if ( GetInterfaceReference() == NULL )
{
return kIOReturnOffline;
}
return theErr;
}
UInt32
IOUSBMassStorageUFISubclass::GetFormatCapacities( UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::doGetFormatCapacities called\n" ) );
return 0;
}
#pragma mark -
#pragma mark Device Information Retrieval Methods
char *
IOUSBMassStorageUFISubclass::GetVendorString ( void )
{
OSString * vendorString;
STATUS_LOG ( ( "%s::%s\n", getName ( ), __FUNCTION__ ) );
vendorString = ( OSString * ) fDeviceCharacteristicsDictionary->getObject( kIOPropertyVendorNameKey );
if ( vendorString != NULL )
{
return ( ( char * ) vendorString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
char *
IOUSBMassStorageUFISubclass::GetProductString ( void )
{
OSString * productString;
STATUS_LOG ( ( "%s::%s\n", getName ( ), __FUNCTION__ ) );
productString = ( OSString * ) fDeviceCharacteristicsDictionary->getObject( kIOPropertyProductNameKey );
if ( productString != NULL )
{
return ( ( char * ) productString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
char *
IOUSBMassStorageUFISubclass::GetRevisionString ( void )
{
OSString * revisionString;
STATUS_LOG ( ( "%s::%s\n", getName ( ), __FUNCTION__ ) );
revisionString = ( OSString * ) fDeviceCharacteristicsDictionary->getObject( kIOPropertyProductRevisionLevelKey );
if ( revisionString )
{
return ( ( char * ) revisionString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
OSDictionary *
IOUSBMassStorageUFISubclass::GetProtocolCharacteristicsDictionary ( void )
{
STATUS_LOG ( ( "%s::%s\n", getName ( ), __FUNCTION__ ) );
return ( OSDictionary * ) getProperty( kIOPropertyProtocolCharacteristicsKey );
}
OSDictionary *
IOUSBMassStorageUFISubclass::GetDeviceCharacteristicsDictionary ( void )
{
STATUS_LOG ( ( "%s::%s\n", getName ( ), __FUNCTION__ ) );
return fDeviceCharacteristicsDictionary;
}
#pragma mark -
#pragma mark Query methods to report device characteristics
UInt64
IOUSBMassStorageUFISubclass::ReportDeviceMaxBlocksReadTransfer( void )
{
UInt64 maxBlockCount;
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::reportMaxReadTransfer\n" ) );
maxBlockCount = 256;
return maxBlockCount;
}
UInt64
IOUSBMassStorageUFISubclass::ReportDeviceMaxBlocksWriteTransfer( void )
{
UInt64 maxBlockCount;
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::reportMaxWriteTransfer.\n" ) );
maxBlockCount = 256;
return maxBlockCount;
}
#pragma mark -
#pragma mark Query methods to report installed medium characteristics
UInt64
IOUSBMassStorageUFISubclass::ReportMediumBlockSize( void )
{
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::ReportMediumBlockSize blockSize = %ld\n", ( UInt32 ) fMediumBlockSize ) );
return fMediumBlockSize;
}
UInt64
IOUSBMassStorageUFISubclass::ReportMediumTotalBlockCount( void )
{
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::ReportMediumTotalBlockCount maxBlock = %ld\n", fMediumBlockCount ) );
return fMediumBlockCount;
}
bool
IOUSBMassStorageUFISubclass::ReportMediumWriteProtection( void )
{
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::ReportMediumWriteProtection isWriteProtected = %d.\n", fMediumIsWriteProtected ) );
return fMediumIsWriteProtected;
}
#pragma mark -
#pragma mark SCSI Task Get and Release
SCSITaskIdentifier
IOUSBMassStorageUFISubclass::GetSCSITask( void )
{
SCSITask * newTask = new SCSITask;
newTask->SetTaskOwner( this );
retain();
return ( SCSITaskIdentifier ) newTask;
}
void
IOUSBMassStorageUFISubclass::ReleaseSCSITask ( SCSITaskIdentifier request )
{
if( request != NULL )
{
request->release();
release();
}
}
#pragma mark -
#pragma mark Task Execution Support Methods
void
IOUSBMassStorageUFISubclass::TaskCallback( SCSITaskIdentifier completedTask )
{
SCSIServiceResponse serviceResponse;
SCSITask * scsiRequest;
IOSyncer * fSyncLock;
STATUS_LOG ( ( "IOUSBMassStorageUFISubclass::TaskCallback called\n.") );
scsiRequest = OSDynamicCast ( SCSITask, completedTask );
if ( scsiRequest == NULL )
{
PANIC_NOW ( ( "IOUSBMassStorageUFISubclass::TaskCallback scsiRequest==NULL." ) );
ERROR_LOG ( ( "IOUSBMassStorageUFISubclass::TaskCallback scsiRequest==NULL." ) );
return;
}
fSyncLock = ( IOSyncer * ) scsiRequest->GetApplicationLayerReference ( );
serviceResponse = scsiRequest->GetServiceResponse ( );
fSyncLock->signal ( serviceResponse, false );
}
SCSIServiceResponse
IOUSBMassStorageUFISubclass::SendCommand ( SCSITaskIdentifier request, UInt32 timeoutDuration )
{
SCSIServiceResponse serviceResponse;
IOSyncer * fSyncLock;
if ( GetInterfaceReference() == NULL )
{
SetServiceResponse ( request, kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE );
SetTaskStatus ( request, kSCSITaskStatus_No_Status );
return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
}
fSyncLock = IOSyncer::create ( false );
if ( fSyncLock == NULL )
{
PANIC_NOW ( ( "IOUSBMassStorageUFISubclass::SendCommand Allocate fSyncLock failed." ) );
ERROR_LOG ( ( "IOUSBMassStorageUFISubclass::SendCommand Allocate fSyncLock failed." ) );
SetServiceResponse ( request, kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE );
SetTaskStatus ( request, kSCSITaskStatus_No_Status );
return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
}
fSyncLock->signal ( kIOReturnSuccess, false );
SetTimeoutDuration ( request, timeoutDuration );
SetTaskCompletionCallback ( request, &this->TaskCallback );
SetApplicationLayerReference ( request, ( void * ) fSyncLock );
SetAutosenseCommand ( request, 0x03, 0x00, 0x00, 0x00, sizeof ( SCSI_Sense_Data ), 0x00 );
STATUS_LOG ( ( "%s:SendCommand Reinit the syncer.\n", getName ( ) ) );
fSyncLock->reinit ( );
STATUS_LOG ( ( "%s:SendCommand Execute the command.\n", getName ( ) ) );
ExecuteCommand( request );
serviceResponse = ( SCSIServiceResponse) fSyncLock->wait ( false );
fSyncLock->release ( );
STATUS_LOG ( ( "%s:SendCommand return the service response.\n", getName ( ) ) );
return serviceResponse;
}
void
IOUSBMassStorageUFISubclass::SendCommand (
SCSITaskIdentifier request,
UInt32 timeoutDuration,
SCSITaskCompletion taskCompletion )
{
STATUS_LOG ( ( "%s: called.\n", getName ( ) ) );
if ( GetInterfaceReference() == NULL )
{
SetServiceResponse ( request, kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE );
SetTaskStatus ( request, kSCSITaskStatus_No_Status );
TaskCompletedNotification ( request );
return;
}
SetTimeoutDuration ( request, timeoutDuration );
SetTaskCompletionCallback ( request, taskCompletion );
SetAutosenseCommand ( request, 0x03, 0x00, 0x00, 0x00, sizeof ( SCSI_Sense_Data ), 0x00 );
ExecuteCommand( request );
}
#pragma mark -
#pragma mark SCSI Task Field Accessors
bool
IOUSBMassStorageUFISubclass::SetTaskAttribute( SCSITaskIdentifier request, SCSITaskAttribute newAttribute )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->SetTaskAttribute( newAttribute );
}
SCSITaskAttribute
IOUSBMassStorageUFISubclass::GetTaskAttribute( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->GetTaskAttribute();
}
bool
IOUSBMassStorageUFISubclass::SetTaskState( SCSITaskIdentifier request,
SCSITaskState newTaskState )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->SetTaskState( newTaskState );
}
SCSITaskState
IOUSBMassStorageUFISubclass::GetTaskState ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetTaskState( );
}
bool
IOUSBMassStorageUFISubclass::SetTaskStatus ( SCSITaskIdentifier request,
SCSITaskStatus newStatus )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetTaskStatus ( newStatus );
}
SCSITaskStatus
IOUSBMassStorageUFISubclass::GetTaskStatus ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetTaskStatus ( );
}
bool
IOUSBMassStorageUFISubclass::SetDataTransferDirection ( SCSITaskIdentifier request,
UInt8 newDirection )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetDataTransferDirection ( newDirection );
}
UInt8
IOUSBMassStorageUFISubclass::GetDataTransferDirection ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetDataTransferDirection ( );
}
bool
IOUSBMassStorageUFISubclass::SetRequestedDataTransferCount ( SCSITaskIdentifier request,
UInt64 newRequestedCount )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->SetRequestedDataTransferCount( newRequestedCount );
}
UInt64
IOUSBMassStorageUFISubclass::GetRequestedDataTransferCount ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetRequestedDataTransferCount ( );
}
bool
IOUSBMassStorageUFISubclass::SetRealizedDataTransferCount ( SCSITaskIdentifier request,
UInt64 newRealizedDataCount )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetRealizedDataTransferCount ( newRealizedDataCount );
}
UInt64
IOUSBMassStorageUFISubclass::GetRealizedDataTransferCount ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetRealizedDataTransferCount ( );
}
bool
IOUSBMassStorageUFISubclass::SetDataBuffer ( SCSITaskIdentifier request,
IOMemoryDescriptor * newBuffer )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetDataBuffer ( newBuffer );
}
IOMemoryDescriptor *
IOUSBMassStorageUFISubclass::GetDataBuffer ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetDataBuffer ( );
}
bool
IOUSBMassStorageUFISubclass::SetTimeoutDuration ( SCSITaskIdentifier request,
UInt32 newTimeout )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetTimeoutDuration ( newTimeout );
}
UInt32
IOUSBMassStorageUFISubclass::GetTimeoutDuration ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetTimeoutDuration ( );
}
bool
IOUSBMassStorageUFISubclass::SetTaskCompletionCallback (
SCSITaskIdentifier request,
SCSITaskCompletion newCallback )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetTaskCompletionCallback ( newCallback );
}
void
IOUSBMassStorageUFISubclass::TaskCompletedNotification (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->TaskCompletedNotification( );
}
bool
IOUSBMassStorageUFISubclass::SetServiceResponse(
SCSITaskIdentifier request,
SCSIServiceResponse serviceResponse )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetServiceResponse( serviceResponse );
}
SCSIServiceResponse
IOUSBMassStorageUFISubclass::GetServiceResponse (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->GetServiceResponse();
}
bool
IOUSBMassStorageUFISubclass::SetAutosenseCommand (
SCSITaskIdentifier request,
UInt8 cdbByte0,
UInt8 cdbByte1,
UInt8 cdbByte2,
UInt8 cdbByte3,
UInt8 cdbByte4,
UInt8 cdbByte5 )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->SetAutosenseCommand ( cdbByte0, cdbByte1, cdbByte2,
cdbByte3, cdbByte4, cdbByte5 );
}
bool
IOUSBMassStorageUFISubclass::GetAutoSenseData( SCSITaskIdentifier request,
SCSI_Sense_Data * senseData )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->GetAutoSenseData( senseData );
}
bool
IOUSBMassStorageUFISubclass::SetApplicationLayerReference( SCSITaskIdentifier request,
void * newReferenceValue )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->SetApplicationLayerReference ( newReferenceValue );
}
void *
IOUSBMassStorageUFISubclass::GetApplicationLayerReference ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
return scsiRequest->GetApplicationLayerReference();
}
#pragma mark -
#pragma mark Command Builders Utility Methods
inline bool
IOUSBMassStorageUFISubclass::IsParameterValid( SCSICmdField1Byte param,
SCSICmdField1Byte mask )
{
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::IsParameterValid called\n" ) );
if( ( param | mask ) != mask )
{
STATUS_LOG( ( "param = %x not valid, mask = %x\n", param, mask ) );
return false;
}
return true;
}
inline bool
IOUSBMassStorageUFISubclass::IsParameterValid( SCSICmdField2Byte param,
SCSICmdField2Byte mask )
{
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::IsParameterValid called\n" ) );
if( ( param | mask ) != mask )
{
STATUS_LOG ( ( "param = %x not valid, mask = %x\n", param, mask ) );
return false;
}
return true;
}
inline bool
IOUSBMassStorageUFISubclass::IsParameterValid( SCSICmdField4Byte param,
SCSICmdField4Byte mask )
{
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::IsParameterValid called\n" ) );
if( ( param | mask ) != mask )
{
STATUS_LOG( ( "param = %x not valid, mask = %x\n", param, mask ) );
return false;
}
return true;
}
inline bool
IOUSBMassStorageUFISubclass::IsBufferAndCapacityValid(
IOMemoryDescriptor * dataBuffer,
UInt32 requiredSize )
{
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::IsBufferAndCapacityValid called\n" ) );
if( dataBuffer == NULL )
{
STATUS_LOG ( ( "dataBuffer = %x not valid\n", dataBuffer ) );
return false;
}
if( dataBuffer->getLength() < requiredSize )
{
STATUS_LOG ( ( "dataBuffer length = %x not valid, requiredSize = %x\n",
dataBuffer->getLength(), requiredSize ) );
return false;
}
return true;
}
bool
IOUSBMassStorageUFISubclass::SetCommandDescriptorBlock(
SCSITask * request,
UInt8 cdbByte0,
UInt8 cdbByte1,
UInt8 cdbByte2,
UInt8 cdbByte3,
UInt8 cdbByte4,
UInt8 cdbByte5,
UInt8 cdbByte6 = 0,
UInt8 cdbByte7 = 0,
UInt8 cdbByte8 = 0,
UInt8 cdbByte9 = 0,
UInt8 cdbByte10 = 0,
UInt8 cdbByte11 = 0)
{
return request->SetCommandDescriptorBlock(
cdbByte0,
cdbByte1,
cdbByte2,
cdbByte3,
cdbByte4,
cdbByte5,
cdbByte6,
cdbByte7,
cdbByte8,
cdbByte9,
cdbByte10,
cdbByte11 );
}
bool
IOUSBMassStorageUFISubclass::SetDataTransferControl(
SCSITask * request,
UInt8 dataTransferDirection,
IOMemoryDescriptor * dataBuffer = NULL,
UInt64 transferCountInBytes = 0 )
{
bool result = false;
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::SetDataTransferControl called\n" ) );
if( ( transferCountInBytes != 0 ) && ( dataBuffer == NULL ) )
{
STATUS_LOG( ( "transferCountInBytes = %x not valid, dataBuffer = %x\n",
transferCountInBytes, dataBuffer ) );
return result;
}
result = request->SetDataTransferDirection( dataTransferDirection );
if( result == false )
{
STATUS_LOG( ( "SetDataTransferDirection failed, dataTransferDirection = %x\n",
dataTransferDirection ) );
return result;
}
result = request->SetDataBuffer( dataBuffer );
if( result == false )
{
STATUS_LOG( ( "SetDataBuffer failed, dataBuffer = %x\n",
dataBuffer ) );
return result;
}
result = request->SetRequestedDataTransferCount( transferCountInBytes );
if( result == false )
{
STATUS_LOG( ( "SetRequestedDataTransferCount failed, transferCountInBytes = %x\n",
transferCountInBytes ) );
return result;
}
return true;
}
#pragma mark -
#pragma mark Command Builder Methods
bool
IOUSBMassStorageUFISubclass::FORMAT_UNIT(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
IOByteCount defectListSize,
SCSICmdField1Byte TRACK_NUMBER,
SCSICmdField2Byte INTERLEAVE )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::FORMAT_UNIT called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if( IsParameterValid( INTERLEAVE, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG( ( "INTERLEAVE = %x not valid\n", INTERLEAVE ) );
return false;
}
if( defectListSize > 0 )
{
if( IsBufferAndCapacityValid( dataBuffer, defectListSize )
== false )
{
STATUS_LOG( ( "dataBuffer = %x not valid, defectListSize = %x\n",
dataBuffer, defectListSize ) );
return false;
}
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_FORMAT_UNIT,
0x00,
0x00,
( INTERLEAVE >> 8 ) & 0xFF,
INTERLEAVE & 0xFF,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromInitiatorToTarget,
dataBuffer );
return true;
}
bool
IOUSBMassStorageUFISubclass::INQUIRY(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Byte PAGE_OR_OPERATION_CODE,
SCSICmdField1Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::INQUIRY called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if ( IsParameterValid( PAGE_OR_OPERATION_CODE, kSCSICmdFieldMask1Byte ) == false )
{
STATUS_LOG( ( "PAGE_OR_OPERATION_CODE = %x not valid\n",
PAGE_OR_OPERATION_CODE ) );
return false;
}
if ( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask1Byte ) == false )
{
STATUS_LOG( ( "ALLOCATION_LENGTH = %x not valid\n", ALLOCATION_LENGTH ) );
return false;
}
if ( IsBufferAndCapacityValid( dataBuffer, ALLOCATION_LENGTH ) == false )
{
STATUS_LOG ( ( "dataBuffer = %x not valid, ALLOCATION_LENGTH = %x\n",
dataBuffer, ALLOCATION_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_INQUIRY,
0x00,
PAGE_OR_OPERATION_CODE,
0x00,
ALLOCATION_LENGTH,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromTargetToInitiator,
dataBuffer,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFISubclass::MODE_SELECT_10(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Bit PF,
SCSICmdField1Bit SP,
SCSICmdField2Byte PARAMETER_LIST_LENGTH )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::MODE_SELECT_10 called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if( IsParameterValid( PF, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "PF = %x not valid\n", PF ) );
return false;
}
if( IsParameterValid( SP, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG ( ( "SP = %x not valid\n", SP ) );
return false;
}
if( IsParameterValid( PARAMETER_LIST_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG( ( "PARAMETER_LIST_LENGTH = %x not valid\n",
PARAMETER_LIST_LENGTH ) );
return false;
}
if( IsBufferAndCapacityValid( dataBuffer, PARAMETER_LIST_LENGTH ) == false )
{
STATUS_LOG( ( "dataBuffer = %x not valid, PARAMETER_LIST_LENGTH = %x\n",
dataBuffer, PARAMETER_LIST_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_MODE_SELECT_10,
( PF << 4 ) | SP,
0x00,
0x00,
0x00,
0x00,
0x00,
( PARAMETER_LIST_LENGTH >> 8 ) & 0xFF,
PARAMETER_LIST_LENGTH & 0xFF,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromInitiatorToTarget,
dataBuffer,
PARAMETER_LIST_LENGTH );
return true;
}
bool
IOUSBMassStorageUFISubclass::MODE_SENSE_10(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Bit DBD,
SCSICmdField2Bit PC,
SCSICmdField6Bit PAGE_CODE,
SCSICmdField2Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::MODE_SENSE_10 called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if( IsParameterValid( DBD, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "DBD = %x not valid\n", DBD ) );
return false;
}
if( IsParameterValid( PC, kSCSICmdFieldMask2Bit ) == false )
{
STATUS_LOG( ( "PC = %x not valid\n", PC ) );
return false;
}
if( IsParameterValid( PAGE_CODE, kSCSICmdFieldMask6Bit ) == false )
{
STATUS_LOG( ( "PAGE_CODE = %x not valid\n", PAGE_CODE ) );
return false;
}
if( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG( ( "ALLOCATION_LENGTH = %x not valid\n",
ALLOCATION_LENGTH ) );
return false;
}
if( IsBufferAndCapacityValid( dataBuffer, ALLOCATION_LENGTH ) == false )
{
STATUS_LOG( ( "dataBuffer = %x not valid, ALLOCATION_LENGTH = %x\n",
dataBuffer, ALLOCATION_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_MODE_SENSE_10,
( DBD << 3 ),
( PC << 6 ) | PAGE_CODE,
0x00,
0x00,
0x00,
0x00,
( ALLOCATION_LENGTH >> 8 ) & 0xFF,
ALLOCATION_LENGTH & 0xFF,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromTargetToInitiator,
dataBuffer,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFISubclass::PREVENT_ALLOW_MEDIUM_REMOVAL(
SCSITaskIdentifier request,
SCSICmdField1Bit PREVENT )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::PREVENT_ALLOW_MEDIUM_REMOVAL called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if( IsParameterValid( PREVENT, kSCSICmdFieldMask2Bit ) == false )
{
STATUS_LOG( ( "PREVENT = %x not valid\n", PREVENT ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_PREVENT_ALLOW_MEDIUM_REMOVAL,
0x00,
0x00,
0x00,
PREVENT,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_NoDataTransfer );
return true;
}
bool
IOUSBMassStorageUFISubclass::READ_10(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit FUA,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
SCSITask * scsiRequest;
UInt32 requestedByteCount;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::READ_10 called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if ( blockSize == 0 )
{
return false;
}
if (dataBuffer == NULL )
{
return false;
}
else
{
requestedByteCount = TRANSFER_LENGTH * blockSize;
if ( dataBuffer->getLength() < requestedByteCount )
{
return false;
}
}
if( IsParameterValid( DPO, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "DPO = %x not valid\n", DPO ) );
return false;
}
if( IsParameterValid( FUA, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "FUA = %x not valid\n", FUA ) );
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "RELADR = %x not valid\n", RELADR ) );
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG( ( "LOGICAL_BLOCK_ADDRESS = %x not valid\n",
LOGICAL_BLOCK_ADDRESS ) );
return false;
}
if( IsParameterValid( TRANSFER_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG( ( "TRANSFER_LENGTH = %x not valid\n",
TRANSFER_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_READ_10,
( DPO << 4 ) | ( FUA << 3 ) | RELADR,
( LOGICAL_BLOCK_ADDRESS >> 24 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 16 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 8 ) & 0xFF,
LOGICAL_BLOCK_ADDRESS & 0xFF,
0x00,
( TRANSFER_LENGTH >> 8 ) & 0xFF,
TRANSFER_LENGTH & 0xFF,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromTargetToInitiator,
dataBuffer,
requestedByteCount );
return true;
}
bool
IOUSBMassStorageUFISubclass::READ_12(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit FUA,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField4Byte TRANSFER_LENGTH )
{
SCSITask * scsiRequest;
UInt32 requestedByteCount;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::READ_12 called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if ( blockSize == 0 )
{
return false;
}
if (dataBuffer == NULL )
{
return false;
}
else
{
requestedByteCount = TRANSFER_LENGTH * blockSize;
if ( dataBuffer->getLength() < requestedByteCount )
{
return false;
}
}
if( IsParameterValid( DPO, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "DPO = %x not valid\n", DPO ) );
return false;
}
if( IsParameterValid( FUA, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "FUA = %x not valid\n", FUA ) );
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "RELADR = %x not valid\n", RELADR ) );
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG( ( "LOGICAL_BLOCK_ADDRESS = %x not valid\n",
LOGICAL_BLOCK_ADDRESS ) );
return false;
}
if( IsParameterValid( TRANSFER_LENGTH, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG( ( "TRANSFER_LENGTH = %x not valid\n",
TRANSFER_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_READ_12,
( DPO << 4 ) | ( FUA << 3 ) | RELADR,
( LOGICAL_BLOCK_ADDRESS >> 24 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 16 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 8 ) & 0xFF,
LOGICAL_BLOCK_ADDRESS & 0xFF,
( TRANSFER_LENGTH >> 24 ) & 0xFF,
( TRANSFER_LENGTH >> 16 ) & 0xFF,
( TRANSFER_LENGTH >> 8 ) & 0xFF,
TRANSFER_LENGTH & 0xFF,
0x00,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromTargetToInitiator,
dataBuffer,
requestedByteCount );
return true;
}
bool
IOUSBMassStorageUFISubclass::READ_CAPACITY(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField1Bit PMI )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::READ_CAPACITY called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if ( dataBuffer == NULL )
{
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "RELADR = %x not valid\n", RELADR ) );
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG( ( "LOGICAL_BLOCK_ADDRESS = %x not valid\n",
LOGICAL_BLOCK_ADDRESS ) );
return false;
}
if( IsParameterValid( PMI, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "PMI = %x not valid\n", PMI ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_READ_CAPACITY,
RELADR,
( LOGICAL_BLOCK_ADDRESS >> 24 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 16 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 8 ) & 0xFF,
LOGICAL_BLOCK_ADDRESS & 0xFF,
0x00,
0x00,
PMI,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromTargetToInitiator,
dataBuffer,
8 );
return true;
}
bool
IOUSBMassStorageUFISubclass::READ_FORMAT_CAPACITIES(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField2Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::READ_CAPACITY called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if ( dataBuffer == NULL )
{
return false;
}
if( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG( ( "ALLOCATION_LENGTH = %x not valid\n", ALLOCATION_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_READ_FORMAT_CAPACITIES,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
( ALLOCATION_LENGTH >> 8 ) & 0xFF,
ALLOCATION_LENGTH & 0xFF,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromTargetToInitiator,
dataBuffer,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFISubclass::REQUEST_SENSE(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::REQUEST_SENSE called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask1Byte ) == false )
{
STATUS_LOG( ( "ALLOCATION_LENGTH = %x not valid\n",
ALLOCATION_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_REQUEST_SENSE,
0x00,
0x00,
0x00,
ALLOCATION_LENGTH,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromTargetToInitiator,
dataBuffer,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFISubclass::REZERO_UNIT(
SCSITaskIdentifier request )
{
return false;
}
bool
IOUSBMassStorageUFISubclass::SEEK(
SCSITaskIdentifier request,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS )
{
return false;
}
bool
IOUSBMassStorageUFISubclass::SEND_DIAGNOSTICS(
SCSITaskIdentifier request,
SCSICmdField1Bit PF,
SCSICmdField1Bit SELF_TEST,
SCSICmdField1Bit DEF_OFL,
SCSICmdField1Bit UNIT_OFL )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::SEND_DIAGNOSTICS called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if( IsParameterValid( PF, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "PF = %x not valid\n", PF ) );
return false;
}
if( IsParameterValid ( SELF_TEST, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG ( ( "SELF_TEST = %x not valid\n", SELF_TEST ) );
return false;
}
if( IsParameterValid( DEF_OFL, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "DEF_OFL = %x not valid\n", DEF_OFL ) );
return false;
}
if( IsParameterValid( UNIT_OFL, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "UNIT_OFL = %x not valid\n", UNIT_OFL ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_SEND_DIAGNOSTICS,
( PF << 4 ) |
( SELF_TEST << 2 ) | ( DEF_OFL << 1 ) | UNIT_OFL,
0x00,
0x00,
0x00,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_NoDataTransfer);
return true;
}
bool
IOUSBMassStorageUFISubclass::START_STOP_UNIT(
SCSITaskIdentifier request,
SCSICmdField1Bit IMMED,
SCSICmdField1Bit LOEJ,
SCSICmdField1Bit START )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::START_STOP_UNIT called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if( IsParameterValid( IMMED, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "IMMED = %x not valid\n", IMMED ) );
return false;
}
if( IsParameterValid( LOEJ, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "LOEJ = %x not valid\n", LOEJ ) );
return false;
}
if( IsParameterValid( START, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "START = %x not valid\n", START ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_START_STOP_UNIT,
IMMED,
0x00,
0x00,
( LOEJ << 1 ) | START,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_NoDataTransfer );
return true;
}
bool
IOUSBMassStorageUFISubclass::TEST_UNIT_READY(
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::TEST_UNIT_READY called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_TEST_UNIT_READY,
0x00,
0x00,
0x00,
0x00,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_NoDataTransfer );
return true;
}
bool
IOUSBMassStorageUFISubclass::VERIFY(
SCSITaskIdentifier request,
SCSICmdField1Bit DPO,
SCSICmdField1Bit BYTCHK,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte VERIFICATION_LENGTH )
{
return false;
}
bool
IOUSBMassStorageUFISubclass::WRITE_10(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit FUA,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
SCSITask * scsiRequest;
UInt32 requestedByteCount;
scsiRequest = OSDynamicCast ( SCSITask, request );
STATUS_LOG( ( "IOUSBMassStorageUFISubclass::WRITE_10 called\n" ) );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
if ( blockSize == 0 )
{
return false;
}
if (dataBuffer == NULL )
{
return false;
}
else
{
requestedByteCount = TRANSFER_LENGTH * blockSize;
if ( dataBuffer->getLength() < requestedByteCount )
{
return false;
}
}
if( IsParameterValid ( DPO, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "DPO = %x not valid\n", DPO ) );
return false;
}
if( IsParameterValid( FUA, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "FUA = %x not valid\n", FUA ) );
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG( ( "RELADR = %x not valid\n", RELADR ) );
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG( ( "LOGICAL_BLOCK_ADDRESS = %x not valid\n",
LOGICAL_BLOCK_ADDRESS ) );
return false;
}
if( IsParameterValid( TRANSFER_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG( ( "TRANSFER_LENGTH = %x not valid\n",
TRANSFER_LENGTH ) );
return false;
}
SetCommandDescriptorBlock( scsiRequest,
kSCSICmd_WRITE_10,
( DPO << 4 ) | ( FUA << 3 ) | RELADR,
( LOGICAL_BLOCK_ADDRESS >> 24 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 16 ) & 0xFF,
( LOGICAL_BLOCK_ADDRESS >> 8 ) & 0xFF,
LOGICAL_BLOCK_ADDRESS & 0xFF,
0x00,
( TRANSFER_LENGTH >> 8 ) & 0xFF,
TRANSFER_LENGTH & 0xFF,
0x00 );
SetDataTransferControl( scsiRequest,
kSCSIDataTransfer_FromInitiatorToTarget,
dataBuffer,
requestedByteCount );
return true;
}
bool
IOUSBMassStorageUFISubclass::WRITE_12(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit EBP,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField4Byte TRANSFER_LENGTH )
{
return false;
}
bool
IOUSBMassStorageUFISubclass::WRITE_AND_VERIFY(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit BYTCHK,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
return false;
}