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/SCSICmds_INQUIRY_Definitions.h>
#include <IOKit/scsi/SCSICommandOperationCodes.h>
#include <IOKit/scsi/SCSITask.h>
#include "Debugging.h"
#if ( USB_MASS_STORAGE_DEBUG == 1 )
#define PANIC_NOW(x) IOPanic x
#define DEBUG_LEVEL 1
#include <IOKit/usb/IOUSBLog.h>
#define STATUS_LOG(x) USBLog x
#else
#define PANIC_NOW(x)
#define STATUS_LOG(x)
#endif
#define kKeySwitchProperty "Keyswitch"
#define kAppleKeySwitchProperty "AppleKeyswitch"
OSDefineMetaClassAndStructors( IOUSBMassStorageUFISubclass, IOUSBMassStorageClass )
#pragma mark -
#pragma mark *** IOUSBMassStorageUFIDevice declaration ***
#pragma mark -
OSDefineMetaClassAndStructors( IOUSBMassStorageUFIDevice, IOSCSIPrimaryCommandsDevice )
#pragma mark -
#pragma mark *** Static Class Methods ***
#pragma mark -
void
IOUSBMassStorageUFIDevice::sProcessPoll( void * theUFIDriver, void * refCon )
{
UNUSED( refCon );
IOUSBMassStorageUFIDevice * driver;
driver = (IOUSBMassStorageUFIDevice *) theUFIDriver;
require_nonzero ( driver, ErrorExit );
if( driver->fPollingMode != kPollingMode_Suspended )
{
driver->ProcessPoll();
if( driver->fPollingMode != kPollingMode_Suspended )
{
driver->EnablePolling();
}
}
driver->release();
ErrorExit:
return;
}
void
IOUSBMassStorageUFIDevice::AsyncReadWriteComplete( SCSITaskIdentifier request )
{
void * clientData;
IOReturn status;
UInt64 actCount = 0;
IOUSBMassStorageUFIDevice * taskOwner;
if ( request == NULL )
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::AsyncReadWriteComplete request==NULL." ));
}
taskOwner = OSDynamicCast( IOUSBMassStorageUFIDevice, IOSCSIPrimaryCommandsDevice::sGetOwnerForTask( request ));
if ( taskOwner == NULL )
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::AsyncReadWriteComplete taskOwner==NULL." ));
}
clientData = taskOwner->GetApplicationLayerReference( request );
if (( taskOwner->GetServiceResponse( request ) == kSCSIServiceResponse_TASK_COMPLETE ) &&
( taskOwner->GetTaskStatus( request ) == kSCSITaskStatus_GOOD ))
{
status = kIOReturnSuccess;
}
else
{
STATUS_LOG(( 4, "%s[%p]::Error on read/write", taskOwner->getName(), taskOwner ));
status = kIOReturnError;
}
if ( status == kIOReturnSuccess )
{
actCount = taskOwner->GetDataBuffer( request )->getLength();
}
taskOwner->ReleaseSCSITask( request );
IOUFIStorageServices::AsyncReadWriteComplete( clientData, status, actCount );
}
#pragma mark -
#pragma mark *** Class Methods ***
#pragma mark -
bool
IOUSBMassStorageUFIDevice::InitializeDeviceSupport( void )
{
bool setupSuccessful = false;
fMediumPresent = false;
fMediumIsWriteProtected = true;
STATUS_LOG(( 6, "%s[%p]::InitializeDeviceSupport called", getName(), this ));
ClearNotReadyStatus();
require( ( DetermineDeviceCharacteristics( ) == true ), ERROR_EXIT );
fPollingMode = kPollingMode_NewMedia;
fPollingThread = thread_call_allocate(
( thread_call_func_t ) IOUSBMassStorageUFIDevice::sProcessPoll,
( thread_call_param_t ) this );
require_nonzero( fPollingThread, ERROR_EXIT );
#if 0
fIOUSBMassStorageUFIDeviceReserved = ( IOUSBMassStorageUFIDeviceExpansionData * )
IOMalloc ( sizeof ( IOUSBMassStorageUFIDeviceExpansionData ) );
require_nonzero ( fIOUSBMassStorageUFIDeviceReserved, ERROR_EXIT );
bzero ( fIOUSBMassStorageUFIDeviceReserved,
sizeof ( IOUSBMassStorageUFIDeviceExpansionData ) );
#endif
STATUS_LOG(( 5, "%s[%p]::InitializeDeviceSupport setupSuccessful = %d", getName(), this, setupSuccessful ));
setupSuccessful = true;
ERROR_EXIT:
return setupSuccessful;
}
void
IOUSBMassStorageUFIDevice::StartDeviceSupport( void )
{
OSBoolean * shouldNotPoll = NULL;
shouldNotPoll = OSDynamicCast ( OSBoolean,
getProperty ( kAppleKeySwitchProperty ) );
if ( shouldNotPoll != NULL )
{
require ( shouldNotPoll->isFalse ( ), Exit );
}
EnablePolling ( );
Exit:
CreateStorageServiceNub ( );
}
void
IOUSBMassStorageUFIDevice::SuspendDeviceSupport( void )
{
if( fPollingMode != kPollingMode_Suspended )
{
DisablePolling();
}
}
void
IOUSBMassStorageUFIDevice::ResumeDeviceSupport( void )
{
if( fMediumPresent == false )
{
fPollingMode = kPollingMode_NewMedia;
EnablePolling();
}
}
void
IOUSBMassStorageUFIDevice::StopDeviceSupport( void )
{
}
void
IOUSBMassStorageUFIDevice::TerminateDeviceSupport( void )
{
STATUS_LOG(( 6, "%s[%p]::cleanUp called.", getName(), this ));
if ( fPollingThread != NULL )
{
thread_call_free ( fPollingThread );
fPollingThread = NULL;
}
}
bool
IOUSBMassStorageUFIDevice::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(( 6, "%s[%p]::%s called", getName(), this, __FUNCTION__));
bufferDesc = IOMemoryDescriptor::withAddress( ( void * ) &senseBuffer,
kSenseDefaultSize,
kIODirectionIn );
request = GetSCSITask();
do
{
if( TEST_UNIT_READY( request ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW( ( "IOUSBMassStorageUFIDevice::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( ( "IOUSBMassStorageUFIDevice::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(( 5, "%s[%p]::drive not ready", getName(), this ));
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((5, "%s[%p]::drive READY", getName(), this ));
}
STATUS_LOG(( 5, "%s[%p]:: sense data: %01x, %02x, %02x", getName(), this,
( 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
IOUSBMassStorageUFIDevice::EnablePolling( void )
{
AbsoluteTime time;
if( ( fPollingMode != kPollingMode_Suspended ) &&
fPollingThread &&
( isInactive() == false ) )
{
retain();
clock_interval_to_deadline( 1000, kMillisecondScale, &time );
thread_call_enter_delayed( fPollingThread, time );
}
}
void
IOUSBMassStorageUFIDevice::DisablePolling( void )
{
fPollingMode = kPollingMode_Suspended;
if( thread_call_cancel( fPollingThread ) )
{
release();
}
}
bool
IOUSBMassStorageUFIDevice::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[kINQUIRY_PRODUCT_IDENTIFICATION_Length + 1]; OSString * string;
STATUS_LOG(( 6, "%s[%p]::DetermineDeviceCharacteristics called", getName(), this ));
inquiryBuffer = ( SCSICmd_INQUIRY_StandardData * ) IOMalloc( inquiryBufferCount );
if( inquiryBuffer == NULL )
{
STATUS_LOG((1, "%s[%p]: Couldn't allocate Inquiry buffer.", getName(), this ));
goto ErrorExit;
}
bufferDesc = IOMemoryDescriptor::withAddress( inquiryBuffer, inquiryBufferCount, kIODirectionIn );
if( bufferDesc == NULL )
{
STATUS_LOG(( 1, "%s[%p]: Couldn't alloc Inquiry buffer: ", getName(), this ));
goto ErrorExit;
}
request = GetSCSITask();
if( request == NULL )
{
goto ErrorExit;
}
if( INQUIRY( request,
bufferDesc,
0,
inquiryBufferCount ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::DetermineDeviceCharacteristics malformed command" ));
goto ErrorExit;
}
if( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
STATUS_LOG(( 2, "%s[%p]: Inquiry completed with an error: ", getName(), this ));
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_IDENTIFICATION[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(( 6, "%s[%p]::DetermineDeviceCharacteristics exiting", getName(), this ));
if( request )
{
ReleaseSCSITask( request );
request = NULL;
}
if( bufferDesc )
{
bufferDesc->release();
bufferDesc = NULL;
}
if( inquiryBuffer )
{
IOFree( ( void * ) inquiryBuffer, inquiryBufferCount );
inquiryBuffer = NULL;
}
return succeeded;
}
void
IOUSBMassStorageUFIDevice::SetMediumCharacteristics( UInt32 blockSize, UInt32 blockCount )
{
STATUS_LOG(( 6, "%s[%p]::SetMediumCharacteristics called", getName(), this ));
STATUS_LOG(( 5, "%s[%p]::mediumBlockSize = %ld, blockCount = %ld", getName(), this, blockSize, blockCount));
fMediumBlockSize = blockSize;
fMediumBlockCount = blockCount;
STATUS_LOG(( 6, "%s[%p]::SetMediumCharacteristics exiting", getName(), this ));
}
void
IOUSBMassStorageUFIDevice::ResetMediumCharacteristics( void )
{
STATUS_LOG(( 6, "%s[%p]::ResetMediumCharacteristics called", getName(), this ));
fMediumBlockSize = 0;
fMediumBlockCount = 0;
fMediumPresent = false;
fMediumIsWriteProtected = true;
STATUS_LOG(( 6, "%s[%p]::ResetMediumCharacteristics exiting", getName(), this ));
}
void
IOUSBMassStorageUFIDevice::CreateStorageServiceNub( void )
{
STATUS_LOG(( 6, "%s[%p]::CreateStorageServiceNub entering.", getName(), this ));
IOService * nub = OSTypeAlloc ( IOUFIStorageServices );
if( nub == NULL )
{
STATUS_LOG(( 1, "%s[%p]::CreateStorageServiceNub failed", getName(), this ));
PANIC_NOW(( "IOUSBMassStorageUFIDevice::CreateStorageServiceNub failed" ));
return;
}
nub->init();
if( !nub->attach( this ) )
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::CreateStorageServiceNub unable to attach nub" ));
return;
}
nub->registerService(kIOServiceAsynchronous);
STATUS_LOG(( 6, "%s[%p]::CreateStorageServiceNub exiting.", getName(), this ));
nub->release();
}
void
IOUSBMassStorageUFIDevice::ProcessPoll( void )
{
switch( fPollingMode )
{
case kPollingMode_NewMedia:
{
PollForNewMedia();
}
break;
case kPollingMode_MediaRemoval:
{
PollForMediaRemoval();
}
break;
default:
{
STATUS_LOG(( 1, "%s[%p]:ProcessPoll Unknown polling mode.", getName(), this ));
}
break;
}
}
void
IOUSBMassStorageUFIDevice::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;
messageClients( kIOMessageMediaStateHasChanged,
( void * ) kIOMediaStateOnline,
sizeof( IOMediaState ) );
fPollingMode = kPollingMode_MediaRemoval;
}
bool
IOUSBMassStorageUFIDevice::DetermineMediaPresence( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request = NULL;
bool mediaFound = false;
OSBoolean * keySwitchLocked = NULL;
STATUS_LOG(( 6, "%s[%p]::DetermineMediaPresence called", getName(), this ));
keySwitchLocked = OSDynamicCast ( OSBoolean, getProperty ( kAppleKeySwitchProperty ) );
if ( keySwitchLocked != NULL )
{
if ( keySwitchLocked->isTrue ( ) )
{
return false;
}
}
request = GetSCSITask();
if( request == NULL )
{
return false;
}
if( TEST_UNIT_READY( request ) == true )
{
serviceResponse = SendCommand( request, 10 * 1000 );
}
else
{
STATUS_LOG(( 1, "%s[%p]::DetermineMediaPresence malformed command", getName(), this ));
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 )
{
STATUS_LOG(( 1, "%s[%p]: could not allocate sense buffer descriptor.", getName(), this ));
goto CHECK_DONE;
}
if( REQUEST_SENSE( request, bufferDesc, kSenseDefaultSize ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
STATUS_LOG(( 1, "%s[%p]::PollForMedia malformed command", getName(), this ));
bufferDesc->release();
goto CHECK_DONE;
}
bufferDesc->release();
if ( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
STATUS_LOG(( 2, "%s[%p]: REQUEST_SENSE failed", getName(), this ));
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 ) )
{
STATUS_LOG(( 2, "%s[%p]:: ASC = 0x%02x, ASCQ = 0x%02x",
getName(),
this,
senseBuffer.ADDITIONAL_SENSE_CODE,
senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER ));
goto CHECK_DONE;
}
}
else
{
STATUS_LOG(( 2, "%s[%p]:: serviceResponse = %d", getName(), this, serviceResponse ));
goto CHECK_DONE;
}
UInt8 formatBuffer[12];
IOMemoryDescriptor * formatDesc;
formatDesc = IOMemoryDescriptor::withAddress ( ( void * ) &formatBuffer[0],
12,
kIODirectionIn );
if( formatDesc == NULL )
{
STATUS_LOG(( 1, "%s[%p]: could not allocate sense buffer descriptor.", getName(), this ));
goto CHECK_DONE;
}
if ( READ_FORMAT_CAPACITIES( request, formatDesc, 12 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
STATUS_LOG(( 1, "%s[%p]::PollForMedia malformed command", getName(), this ));
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 )
{
STATUS_LOG(( 1, "%s[%p]: could not allocate sense buffer descriptor.", getName(), this ));
goto CHECK_DONE;
}
if( REQUEST_SENSE( request, bufferDesc, kSenseDefaultSize ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
STATUS_LOG(( 1, "%s[%p]::PollForMedia malformed command", getName(), this ));
bufferDesc->release();
goto CHECK_DONE;
}
bufferDesc->release();
if ( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
STATUS_LOG(( 2, "%s[%p]: REQUEST_SENSE failed", getName(), this ));
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
{
STATUS_LOG(( 2, "%s[%p]:: serviceResponse = %d", getName(), this, serviceResponse ) );
goto CHECK_DONE;
}
STATUS_LOG(( 4, "%s[%p]:: Formats data: ", getName(), this ));
for ( int i=0; i < 12; i ++ )
{
STATUS_LOG(( 4, "%s[%p]:: %X : ", getName(), this, formatBuffer[i] ));
}
if( formatBuffer[8] == 0x01 )
{
STATUS_LOG(( 4, "%s[%p]: unformatted media was found.", getName(), this ));
goto CHECK_DONE;
}
else if ( formatBuffer[8] != 0x02 )
{
STATUS_LOG(( 5, "%s[%p]: no media was found.", getName(), this ));
goto CHECK_DONE;
}
STATUS_LOG(( 5, "%s[%p]: media was found.", getName(), this ));
mediaFound = true;
CHECK_DONE:
if( request != NULL )
{
ReleaseSCSITask( request );
request = NULL;
}
return mediaFound;
}
bool
IOUSBMassStorageUFIDevice::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
{
STATUS_LOG(( 1, "%s[%p]::PollForMedia malformed command", getName(), this ));
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(( 4, "%s[%p]: Media capacity: %lx and block size: %lx",
getName(), this, (UInt32) *blockCount, (UInt32) *blockSize ));
result = true;
}
else
{
STATUS_LOG(( 2, "%s[%p]: Read Capacity failed", getName(), this ));
result = false;
}
isDone:
if ( request != NULL )
{
ReleaseSCSITask( request );
}
if ( bufferDesc != NULL )
{
bufferDesc->release();
}
return result;
}
bool
IOUSBMassStorageUFIDevice::DetermineMediumWriteProtectState( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
UInt8 modeBuffer[72];
IOMemoryDescriptor * bufferDesc = NULL;
SCSITaskIdentifier request = NULL;
bool mediumIsProtected = true;
STATUS_LOG(( 6, "%s[%p]::checkWriteProtection called", getName(), this ));
request = GetSCSITask();
if( request == NULL )
{
return true;
}
bufferDesc = IOMemoryDescriptor::withAddress( modeBuffer,
72,
kIODirectionIn );
if ( bufferDesc == NULL )
{
goto WP_CHECK_DONE;
}
if ( MODE_SENSE_10( request,
bufferDesc,
0,
0,
0x3F,
72 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
STATUS_LOG(( 1, "%s[%p]::CheckWriteProtection malformed command", getName(), this ));
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
IOUSBMassStorageUFIDevice::PollForMediaRemoval( void )
{
SCSIServiceResponse serviceResponse= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request = NULL;
bool mediaRemoved = false;
if ( isInactive() == true )
{
fPollingMode = kPollingMode_Suspended;
}
request = GetSCSITask();
if( request == NULL )
{
return;
}
if( TEST_UNIT_READY( request ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::PollForMediaRemoval 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 )
{
STATUS_LOG(( 1, "%s[%p]: could not allocate sense buffer descriptor.", getName(), this ));
goto REMOVE_CHECK_DONE;
}
if( REQUEST_SENSE( request, bufferDesc, kSenseDefaultSize ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::PollForMediaRemoval malformed command" ));
bufferDesc->release();
goto REMOVE_CHECK_DONE;
}
bufferDesc->release();
if( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus( request ) != kSCSITaskStatus_GOOD ) )
{
STATUS_LOG(( 2, "%s[%p]: REQUEST_SENSE failed", getName(), this ));
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;
messageClients( kIOMessageMediaStateHasChanged,
( void * ) kIOMediaStateOffline );
}
}
UInt32
IOUSBMassStorageUFIDevice::GetInitialPowerState ( void )
{
return 0;
}
void
IOUSBMassStorageUFIDevice::HandlePowerChange ( void )
{
}
void
IOUSBMassStorageUFIDevice::HandleCheckPowerState ( void )
{
}
void
IOUSBMassStorageUFIDevice::TicklePowerManager ( void )
{
}
UInt32
IOUSBMassStorageUFIDevice::GetNumberOfPowerStateTransitions ( void )
{
return 0;
}
#pragma mark -
#pragma mark *** Client Requests Support ***
#pragma mark -
IOReturn
IOUSBMassStorageUFIDevice::IssueRead( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
STATUS_LOG(( 6, "%s[%p]: syncRead Attempted", getName(), this ));
request = GetSCSITask ( );
if ( READ_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == false )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::IssueRead malformed command" ));
}
ReleaseSCSITask ( request );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
return kIOReturnSuccess;
}
else
{
return kIOReturnError;
}
}
IOReturn
IOUSBMassStorageUFIDevice::IssueRead( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
void * clientData )
{
IOReturn status = kIOReturnSuccess;
SCSITaskIdentifier request;
STATUS_LOG(( 6, "%s[%p]: asyncRead Attempted", getName(), this ));
request = GetSCSITask();
if (READ_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
SetApplicationLayerReference( request, clientData );
STATUS_LOG(( 6, "%s[%p]::IssueRead send command.", getName(), this ));
SendCommand( request, 0, &this->AsyncReadWriteComplete );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::IssueWrite malformed command" ));
status = kIOReturnError;
}
return status;
}
IOReturn
IOUSBMassStorageUFIDevice::IssueWrite( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
STATUS_LOG(( 6, "%s[%p]: syncWrite Attempted", getName(), this ));
request = GetSCSITask();
if ( WRITE_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::IssueWrite malformed command" ));
}
ReleaseSCSITask ( request );
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
return kIOReturnSuccess;
}
else
{
return kIOReturnError;
}
}
IOReturn
IOUSBMassStorageUFIDevice::IssueWrite( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
void * clientData )
{
IOReturn status = kIOReturnSuccess;
SCSITaskIdentifier request;
STATUS_LOG(( 6, "%s[%p]:: asyncWrite Attempted", getName(), this ));
request = GetSCSITask();
if ( WRITE_10( request,
buffer,
fMediumBlockSize,
0,
0,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
SetApplicationLayerReference( request, clientData );
STATUS_LOG(( 6, "%s[%p]::IssueWrite send command.", getName(), this ));
SendCommand( request, 0, &this->AsyncReadWriteComplete );
}
else
{
PANIC_NOW(( "IOUSBMassStorageUFIDevice::IssueWrite malformed command" ));
}
return status;
}
IOReturn
IOUSBMassStorageUFIDevice::SyncReadWrite ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
UInt64 blockSize )
{
UNUSED( blockSize );
IODirection direction;
IOReturn theErr;
direction = buffer->getDirection();
if ( direction == kIODirectionIn )
{
theErr = IssueRead( buffer, startBlock, blockCount );
}
else if ( direction == kIODirectionOut )
{
theErr = IssueWrite( buffer, startBlock, blockCount );
}
else
{
STATUS_LOG(( 1, "%s[%p]: doSyncReadWrite bad direction argument", getName(), this ));
theErr = kIOReturnBadArgument;
}
return theErr;
}
IOReturn
IOUSBMassStorageUFIDevice::AsyncReadWrite ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
UInt64 blockSize,
void * clientData )
{
UNUSED( blockSize );
IODirection direction;
IOReturn theErr;
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
{
STATUS_LOG(( 1, "%s[%p]: doAsyncReadWrite bad direction argument", getName(), this ));
theErr = kIOReturnBadArgument;
}
return theErr;
}
IOReturn
IOUSBMassStorageUFIDevice::EjectTheMedium( void )
{
STATUS_LOG(( 6, "%s[%p]::EjectTheMedium called", getName(), this ));
ResetMediumCharacteristics();
if ( fPollingMode != kPollingMode_MediaRemoval )
{
fPollingMode = kPollingMode_MediaRemoval;
EnablePolling();
}
return kIOReturnSuccess;
}
IOReturn
IOUSBMassStorageUFIDevice::FormatMedium( UInt64 blockCount, UInt64 blockSize )
{
UNUSED( blockCount );
UNUSED( blockSize );
IOReturn theErr = kIOReturnSuccess;
STATUS_LOG(( 6, "%s[%p]::FormatMedium called", getName(), this ));
return theErr;
}
UInt32
IOUSBMassStorageUFIDevice::GetFormatCapacities( UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
UNUSED( capacities );
UNUSED( capacitiesMaxCount );
STATUS_LOG(( 6, "%s[%p]::doGetFormatCapacities called", getName(), this ));
return 0;
}
#pragma mark -
#pragma mark *** Device Information Retrieval Methods ***
#pragma mark -
char *
IOUSBMassStorageUFIDevice::GetVendorString ( void )
{
OSString * vendorString;
STATUS_LOG(( 6, "%s[%p]::%s", getName(), this, __FUNCTION__ ));
vendorString = ( OSString * ) fDeviceCharacteristicsDictionary->getObject( kIOPropertyVendorNameKey );
if ( vendorString != NULL )
{
return ( ( char * ) vendorString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
char *
IOUSBMassStorageUFIDevice::GetProductString ( void )
{
OSString * productString;
STATUS_LOG(( 6, "%s[%p]::%s", getName(), this, __FUNCTION__ ));
productString = ( OSString * ) fDeviceCharacteristicsDictionary->getObject( kIOPropertyProductNameKey );
if ( productString != NULL )
{
return ( ( char * ) productString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
char *
IOUSBMassStorageUFIDevice::GetRevisionString ( void )
{
OSString * revisionString;
STATUS_LOG(( 6, "%s[%p]::%s", getName(), this, __FUNCTION__ ));
revisionString = ( OSString * ) fDeviceCharacteristicsDictionary->getObject( kIOPropertyProductRevisionLevelKey );
if ( revisionString )
{
return ( ( char * ) revisionString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
OSDictionary *
IOUSBMassStorageUFIDevice::GetProtocolCharacteristicsDictionary ( void )
{
STATUS_LOG(( 6, "%s[%p]::%s", getName(), this, __FUNCTION__ ));
return ( OSDictionary * ) getProperty( kIOPropertyProtocolCharacteristicsKey );
}
OSDictionary *
IOUSBMassStorageUFIDevice::GetDeviceCharacteristicsDictionary ( void )
{
STATUS_LOG(( 6, "%s[%p]::%s", getName(), this, __FUNCTION__ ));
return fDeviceCharacteristicsDictionary;
}
#pragma mark -
#pragma mark *** Query methods to report device characteristics ***
#pragma mark -
UInt64
IOUSBMassStorageUFIDevice::ReportDeviceMaxBlocksReadTransfer( void )
{
UInt64 maxBlockCount;
STATUS_LOG(( 6, "%s[%p]::%s", getName(), this, __FUNCTION__ ));
maxBlockCount = 256;
return maxBlockCount;
}
UInt64
IOUSBMassStorageUFIDevice::ReportDeviceMaxBlocksWriteTransfer( void )
{
UInt64 maxBlockCount;
STATUS_LOG(( 6, "%s[%p]::%s", getName(), this, __FUNCTION__ ));
maxBlockCount = 256;
return maxBlockCount;
}
#pragma mark -
#pragma mark *** Query methods to report installed medium characteristics ***
#pragma mark -
UInt64
IOUSBMassStorageUFIDevice::ReportMediumBlockSize( void )
{
STATUS_LOG(( 5, "%s[%p]::ReportMediumBlockSize blockSize = %ld", getName(), this, ( UInt32 ) fMediumBlockSize ));
return fMediumBlockSize;
}
UInt64
IOUSBMassStorageUFIDevice::ReportMediumTotalBlockCount( void )
{
STATUS_LOG(( 5, "%s[%p]::ReportMediumTotalBlockCount maxBlock = %ld", getName(), this, fMediumBlockCount ));
return fMediumBlockCount;
}
bool
IOUSBMassStorageUFIDevice::ReportMediumWriteProtection( void )
{
STATUS_LOG(( 5, "%s[%p]::ReportMediumWriteProtection isWriteProtected = %d.", getName(), this, fMediumIsWriteProtected ));
return fMediumIsWriteProtected;
}
#pragma mark -
#pragma mark *** Command Builders Utility Methods ***
#pragma mark -
bool
IOUSBMassStorageUFIDevice::IsParameterValid( SCSICmdField1Byte param,
SCSICmdField1Byte mask )
{
STATUS_LOG(( 6, "%s[%p]::IsParameterValid called", getName(), this ));
if( ( param | mask ) != mask )
{
STATUS_LOG(( 4, "%s[%p]:: param = %x not valid, mask = %x", getName(), this, param, mask ));
return false;
}
return true;
}
bool
IOUSBMassStorageUFIDevice::IsParameterValid( SCSICmdField2Byte param,
SCSICmdField2Byte mask )
{
STATUS_LOG(( 6, "%s[%p]::IsParameterValid called", getName(), this ));
if( ( param | mask ) != mask )
{
STATUS_LOG(( 4, "%s[%p]:: param = %x not valid, mask = %x", getName(), this, param, mask ));
return false;
}
return true;
}
bool
IOUSBMassStorageUFIDevice::IsParameterValid( SCSICmdField4Byte param,
SCSICmdField4Byte mask )
{
STATUS_LOG(( 6, "%s[%p]::IsParameterValid called", getName(), this ));
if( ( param | mask ) != mask )
{
STATUS_LOG(( 4, "%s[%p]:: param = %x not valid, mask = %x", getName(), this,
(unsigned int) param, (unsigned int) mask ));
return false;
}
return true;
}
#pragma mark -
#pragma mark *** Command Builder Methods ***
#pragma mark -
bool
IOUSBMassStorageUFIDevice::FORMAT_UNIT(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
IOByteCount defectListSize,
SCSICmdField1Byte TRACK_NUMBER,
SCSICmdField2Byte INTERLEAVE )
{
UNUSED( TRACK_NUMBER );
STATUS_LOG(( 6, "%s[%p]::FORMAT_UNIT called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if( IsParameterValid( INTERLEAVE, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: INTERLEAVE = %x not valid", getName(), this, INTERLEAVE ));
return false;
}
if( defectListSize > 0 )
{
if( IsMemoryDescriptorValid( dataBuffer, defectListSize )
== false )
{
STATUS_LOG(( 4, "%s[%p]:: dataBuffer = %x not valid, defectListSize = %x",
getName(), this, dataBuffer, defectListSize ));
return false;
}
}
SetCommandDescriptorBlock( request,
kSCSICmd_FORMAT_UNIT,
0x00,
0x00,
( INTERLEAVE >> 8 ) & 0xFF,
INTERLEAVE & 0xFF,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromInitiatorToTarget );
SetDataBuffer( request,
dataBuffer );
return true;
}
bool
IOUSBMassStorageUFIDevice::INQUIRY(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Byte PAGE_OR_OPERATION_CODE,
SCSICmdField1Byte ALLOCATION_LENGTH )
{
STATUS_LOG(( 6, "%s[%p]::INQUIRY called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if ( IsParameterValid( PAGE_OR_OPERATION_CODE, kSCSICmdFieldMask1Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PAGE_OR_OPERATION_CODE = %x not valid",
getName(), this, PAGE_OR_OPERATION_CODE ));
return false;
}
if ( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask1Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: ALLOCATION_LENGTH = %x not valid", getName(), this, ALLOCATION_LENGTH ));
return false;
}
if ( IsMemoryDescriptorValid( dataBuffer, ALLOCATION_LENGTH ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: dataBuffer = %x not valid, ALLOCATION_LENGTH = %x",
getName(), this, dataBuffer, ALLOCATION_LENGTH ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_INQUIRY,
0x00,
PAGE_OR_OPERATION_CODE,
0x00,
ALLOCATION_LENGTH,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromTargetToInitiator );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFIDevice::MODE_SELECT_10(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Bit PF,
SCSICmdField1Bit SP,
SCSICmdField2Byte PARAMETER_LIST_LENGTH )
{
STATUS_LOG(( 6, "%s[%p]::MODE_SELECT_10 called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if( IsParameterValid( PF, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PF = %x not valid", getName(), this, PF ));
return false;
}
if( IsParameterValid( SP, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: SP = %x not valid", getName(), this, SP ));
return false;
}
if( IsParameterValid( PARAMETER_LIST_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PARAMETER_LIST_LENGTH = %x not valid",
getName(), this, PARAMETER_LIST_LENGTH ));
return false;
}
if( IsMemoryDescriptorValid( dataBuffer, PARAMETER_LIST_LENGTH ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: dataBuffer = %x not valid, PARAMETER_LIST_LENGTH = %x",
getName(), this, dataBuffer, PARAMETER_LIST_LENGTH ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_MODE_SELECT_10,
( PF << 4 ) | SP,
0x00,
0x00,
0x00,
0x00,
0x00,
( PARAMETER_LIST_LENGTH >> 8 ) & 0xFF,
PARAMETER_LIST_LENGTH & 0xFF,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromInitiatorToTarget );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
PARAMETER_LIST_LENGTH );
return true;
}
bool
IOUSBMassStorageUFIDevice::MODE_SENSE_10(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Bit DBD,
SCSICmdField2Bit PC,
SCSICmdField6Bit PAGE_CODE,
SCSICmdField2Byte ALLOCATION_LENGTH )
{
STATUS_LOG(( 6, "%s[%p]::MODE_SENSE_10 called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if( IsParameterValid( DBD, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: DBD = %x not valid", getName(), this, DBD ));
return false;
}
if( IsParameterValid( PC, kSCSICmdFieldMask2Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PC = %x not valid", getName(), this, PC ));
return false;
}
if( IsParameterValid( PAGE_CODE, kSCSICmdFieldMask6Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PAGE_CODE = %x not valid", getName(), this, PAGE_CODE ));
return false;
}
if( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: ALLOCATION_LENGTH = %x not valid", getName(), this, ALLOCATION_LENGTH ));
return false;
}
if( IsMemoryDescriptorValid( dataBuffer, ALLOCATION_LENGTH ) == false )
{
STATUS_LOG((4, "%s[%p]:: dataBuffer = %x not valid, ALLOCATION_LENGTH = %x",
dataBuffer, ALLOCATION_LENGTH, getName(), this ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_MODE_SENSE_10,
( DBD << 3 ),
( PC << 6 ) | PAGE_CODE,
0x00,
0x00,
0x00,
0x00,
( ALLOCATION_LENGTH >> 8 ) & 0xFF,
ALLOCATION_LENGTH & 0xFF,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromTargetToInitiator );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFIDevice::PREVENT_ALLOW_MEDIUM_REMOVAL(
SCSITaskIdentifier request,
SCSICmdField1Bit PREVENT )
{
STATUS_LOG(( 6, "%s[%p]::PREVENT_ALLOW_MEDIUM_REMOVAL called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if( IsParameterValid( PREVENT, kSCSICmdFieldMask2Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PREVENT = %x not valid", getName(), this, PREVENT ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_PREVENT_ALLOW_MEDIUM_REMOVAL,
0x00,
0x00,
0x00,
PREVENT,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_NoDataTransfer );
return true;
}
bool
IOUSBMassStorageUFIDevice::READ_10(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit FUA,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
UInt32 requestedByteCount;
STATUS_LOG(( 6, "%s[%p]::READ_10 called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
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(( 4, "%s[%p]:: DPO = %x not valid", getName(), this, DPO ));
return false;
}
if( IsParameterValid( FUA, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: FUA = %x not valid", getName(), this, FUA ));
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: RELADR = %x not valid", getName(), this, RELADR ));
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: LOGICAL_BLOCK_ADDRESS = %x not valid",
getName(), this, LOGICAL_BLOCK_ADDRESS ));
return false;
}
if( IsParameterValid( TRANSFER_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: TRANSFER_LENGTH = %x not valid",
getName(), this, TRANSFER_LENGTH ));
return false;
}
SetCommandDescriptorBlock( request,
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 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromTargetToInitiator );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
requestedByteCount );
return true;
}
bool
IOUSBMassStorageUFIDevice::READ_12(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit FUA,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField4Byte TRANSFER_LENGTH )
{
UInt32 requestedByteCount;
STATUS_LOG(( 6, "%s[%p]::READ_12 called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
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(( 4, "%s[%p]:: DPO = %x not valid", getName(), this, DPO ));
return false;
}
if( IsParameterValid( FUA, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: FUA = %x not valid", getName(), this, FUA ));
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: RELADR = %x not valid", getName(), this, RELADR ));
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: LOGICAL_BLOCK_ADDRESS = %x not valid",
getName(), this, LOGICAL_BLOCK_ADDRESS ));
return false;
}
if( IsParameterValid( TRANSFER_LENGTH, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: TRANSFER_LENGTH = %x not valid",
getName(), this, TRANSFER_LENGTH ));
return false;
}
SetCommandDescriptorBlock( request,
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 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromTargetToInitiator );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
requestedByteCount );
return true;
}
bool
IOUSBMassStorageUFIDevice::READ_CAPACITY(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField1Bit PMI )
{
STATUS_LOG(( 6, "%s[%p]::READ_CAPACITY called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if ( dataBuffer == NULL )
{
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: RELADR = %x not valid", getName(), this, RELADR ));
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: LOGICAL_BLOCK_ADDRESS = %x not valid",
getName(), this, LOGICAL_BLOCK_ADDRESS ));
return false;
}
if( IsParameterValid( PMI, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PMI = %x not valid", getName(), this, PMI ));
return false;
}
SetCommandDescriptorBlock( request,
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 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromTargetToInitiator );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request, 8 );
return true;
}
bool
IOUSBMassStorageUFIDevice::READ_FORMAT_CAPACITIES(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField2Byte ALLOCATION_LENGTH )
{
STATUS_LOG(( 6, "%s[%p]::READ_CAPACITY called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if ( dataBuffer == NULL )
{
return false;
}
if( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG((4, "%s[%p]:: ALLOCATION_LENGTH = %x not valid", getName(), this, ALLOCATION_LENGTH ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_READ_FORMAT_CAPACITIES,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
( ALLOCATION_LENGTH >> 8 ) & 0xFF,
ALLOCATION_LENGTH & 0xFF,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromTargetToInitiator );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFIDevice::REQUEST_SENSE(
SCSITaskIdentifier request,
IOMemoryDescriptor *dataBuffer,
SCSICmdField1Byte ALLOCATION_LENGTH )
{
STATUS_LOG(( 6, "%s[%p]::REQUEST_SENSE called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if( IsParameterValid( ALLOCATION_LENGTH, kSCSICmdFieldMask1Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]ALLOCATION_LENGTH = %x not valid",
getName(), this, ALLOCATION_LENGTH ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_REQUEST_SENSE,
0x00,
0x00,
0x00,
ALLOCATION_LENGTH,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromTargetToInitiator );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
ALLOCATION_LENGTH );
return true;
}
bool
IOUSBMassStorageUFIDevice::REZERO_UNIT(
SCSITaskIdentifier request )
{
UNUSED( request );
return false;
}
bool
IOUSBMassStorageUFIDevice::SEEK(
SCSITaskIdentifier request,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS )
{
UNUSED( request );
UNUSED( LOGICAL_BLOCK_ADDRESS );
return false;
}
bool
IOUSBMassStorageUFIDevice::SEND_DIAGNOSTICS(
SCSITaskIdentifier request,
SCSICmdField1Bit PF,
SCSICmdField1Bit SELF_TEST,
SCSICmdField1Bit DEF_OFL,
SCSICmdField1Bit UNIT_OFL )
{
STATUS_LOG(( 6, "%s[%p]::SEND_DIAGNOSTICS called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if( IsParameterValid( PF, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: PF = %x not valid", getName(), this, PF ));
return false;
}
if( IsParameterValid ( SELF_TEST, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: SELF_TEST = %x not valid", getName(), this, SELF_TEST ));
return false;
}
if( IsParameterValid( DEF_OFL, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: DEF_OFL = %x not valid", getName(), this, DEF_OFL ));
return false;
}
if( IsParameterValid( UNIT_OFL, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: UNIT_OFL = %x not valid", getName(), this, UNIT_OFL ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_SEND_DIAGNOSTICS,
( PF << 4 ) |
( SELF_TEST << 2 ) | ( DEF_OFL << 1 ) | UNIT_OFL,
0x00,
0x00,
0x00,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_NoDataTransfer);
return true;
}
bool
IOUSBMassStorageUFIDevice::START_STOP_UNIT(
SCSITaskIdentifier request,
SCSICmdField1Bit IMMED,
SCSICmdField1Bit LOEJ,
SCSICmdField1Bit START )
{
STATUS_LOG(( 6, "%s[%p]::START_STOP_UNIT called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
if( IsParameterValid( IMMED, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: IMMED = %x not valid", getName(), this, IMMED ));
return false;
}
if( IsParameterValid( LOEJ, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: LOEJ = %x not valid", getName(), this, LOEJ ));
return false;
}
if( IsParameterValid( START, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: START = %x not valid", getName(), this, START ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_START_STOP_UNIT,
IMMED,
0x00,
0x00,
( LOEJ << 1 ) | START,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_NoDataTransfer );
return true;
}
bool
IOUSBMassStorageUFIDevice::TEST_UNIT_READY(
SCSITaskIdentifier request )
{
STATUS_LOG(( 6, "%s[%p]::TEST_UNIT_READY called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
return false;
}
SetCommandDescriptorBlock( request,
kSCSICmd_TEST_UNIT_READY,
0x00,
0x00,
0x00,
0x00,
0x00 );
SetDataTransferDirection( request,
kSCSIDataTransfer_NoDataTransfer );
return true;
}
bool
IOUSBMassStorageUFIDevice::VERIFY(
SCSITaskIdentifier request,
SCSICmdField1Bit DPO,
SCSICmdField1Bit BYTCHK,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte VERIFICATION_LENGTH )
{
UNUSED( request );
UNUSED( DPO );
UNUSED( BYTCHK );
UNUSED( RELADR );
UNUSED( LOGICAL_BLOCK_ADDRESS );
UNUSED( VERIFICATION_LENGTH );
return false;
}
bool
IOUSBMassStorageUFIDevice::WRITE_10(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit FUA,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
UInt32 requestedByteCount;
STATUS_LOG(( 6, "%s[%p]::WRITE_10 called", getName(), this ));
if ( ResetForNewTask( request ) == false )
{
STATUS_LOG(( 1, "%s[%p]:: ResetForNewTask on the request SCSITask failed.", getName(), this ));
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(( 4, "%s[%p]:: DPO = %x not valid", getName(), this, DPO ));
return false;
}
if( IsParameterValid( FUA, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: FUA = %x not valid", getName(), this, FUA ));
return false;
}
if( IsParameterValid( RELADR, kSCSICmdFieldMask1Bit ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: RELADR = %x not valid", getName(), this, RELADR ));
return false;
}
if( IsParameterValid( LOGICAL_BLOCK_ADDRESS, kSCSICmdFieldMask4Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: LOGICAL_BLOCK_ADDRESS = %x not valid",
getName(), this, LOGICAL_BLOCK_ADDRESS ));
return false;
}
if( IsParameterValid( TRANSFER_LENGTH, kSCSICmdFieldMask2Byte ) == false )
{
STATUS_LOG(( 4, "%s[%p]:: TRANSFER_LENGTH = %x not valid",
getName(), this, TRANSFER_LENGTH ));
return false;
}
SetCommandDescriptorBlock( request,
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 );
SetDataTransferDirection( request,
kSCSIDataTransfer_FromInitiatorToTarget );
SetDataBuffer( request,
dataBuffer );
SetRequestedDataTransferCount( request,
requestedByteCount );
return true;
}
bool
IOUSBMassStorageUFIDevice::WRITE_12(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit EBP,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField4Byte TRANSFER_LENGTH )
{
UNUSED( request );
UNUSED( dataBuffer );
UNUSED( blockSize );
UNUSED( DPO );
UNUSED( EBP );
UNUSED( RELADR );
UNUSED( LOGICAL_BLOCK_ADDRESS );
UNUSED( TRANSFER_LENGTH );
return false;
}
bool
IOUSBMassStorageUFIDevice::WRITE_AND_VERIFY(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit DPO,
SCSICmdField1Bit BYTCHK,
SCSICmdField1Bit RELADR,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
UNUSED( request );
UNUSED( dataBuffer );
UNUSED( blockSize );
UNUSED( DPO );
UNUSED( BYTCHK );
UNUSED( RELADR );
UNUSED( LOGICAL_BLOCK_ADDRESS );
UNUSED( TRANSFER_LENGTH );
return false;
}
#pragma mark -
#pragma mark *** IOUSBMassStorageUFISubclass methods ***
#pragma mark -
bool
IOUSBMassStorageUFISubclass::BeginProvidedServices( void )
{
IOUSBMassStorageUFIDevice * ufiDevice = OSTypeAlloc ( IOUSBMassStorageUFIDevice );
if( ufiDevice == NULL )
{
STATUS_LOG(( 1, "%s[%p]::BeginProvidedServices failed", getName(), this ));
PANIC_NOW(( "IOUSBMassStorageUFISubclass::BeginProvidedServices failed" ));
return false;
}
ufiDevice->init( NULL );
if( !ufiDevice->attach( this ) )
{
PANIC_NOW(( "IOUSBMassStorageUFISubclass::BeginProvidedServices unable to attach nub" ));
return false;
}
if ( ufiDevice->start( this ) == false )
{
ufiDevice->detach( this );
}
STATUS_LOG(( 4, "%s[%p]::BeginProvidedServices exiting.", getName(), this ));
ufiDevice->release();
return true;
}
bool
IOUSBMassStorageUFISubclass::EndProvidedServices( void )
{
return true;
}