IOSCSIReducedBlockCommandsDevice.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/scsi-commands/SCSICommandDefinitions.h>
#include <IOKit/scsi-commands/IOSCSIReducedBlockCommandsDevice.h>
#include <IOKit/scsi-commands/IOReducedBlockServices.h>
#if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define kMaxRetryCount 8
#define super IOSCSIPrimaryCommandsDevice
OSDefineMetaClass ( IOSCSIReducedBlockCommandsDevice, IOSCSIPrimaryCommandsDevice );
OSDefineAbstractStructors ( IOSCSIReducedBlockCommandsDevice, IOSCSIPrimaryCommandsDevice );
#pragma mark - Public Methods
bool
IOSCSIReducedBlockCommandsDevice::InitializeDeviceSupport( void )
{
bool setupSuccessful = false;
fMediaIsRemovable = false;
fMediaChanged = false;
fMediaPresent = false;
fMediaIsRemovable = false;
fMediaIsWriteProtected = true;
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::InitializeDeviceSupport called\n" ) );
if ( ClearNotReadyStatus ( ) == false )
{
goto ERROR_EXIT;
}
setupSuccessful = DetermineDeviceCharacteristics ( );
if ( setupSuccessful == true )
{
fPollingThread = thread_call_allocate (
( thread_call_func_t ) IOSCSIReducedBlockCommandsDevice::sPollForMedia,
( thread_call_param_t ) this );
if ( fPollingThread == NULL )
{
ERROR_LOG ( ( "fPollingThread allocation failed.\n" ) );
setupSuccessful = false;
goto ERROR_EXIT;
}
InitializePowerManagement ( GetProtocolDriver ( ) );
}
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::InitializeDeviceSupport setupSuccessful = %d\n", setupSuccessful ) );
return setupSuccessful;
ERROR_EXIT:
return setupSuccessful;
}
void
IOSCSIReducedBlockCommandsDevice::StartDeviceSupport( void )
{
if( fMediaIsRemovable == false )
{
UInt32 attempts = 0;
do {
PollForMedia();
} while ( ( fMediaPresent == false ) &&
( ++attempts < kMaxRetryCount ) &&
( isInactive ( ) == false ) );
}
else
{
EnablePolling();
}
CreateStorageServiceNub();
}
void
IOSCSIReducedBlockCommandsDevice::SuspendDeviceSupport( void )
{
DisablePolling();
}
void
IOSCSIReducedBlockCommandsDevice::ResumeDeviceSupport( void )
{
EnablePolling();
}
void
IOSCSIReducedBlockCommandsDevice::StopDeviceSupport( void )
{
DisablePolling();
}
void
IOSCSIReducedBlockCommandsDevice::TerminateDeviceSupport( void )
{
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::cleanUp called.\n" ) );
if ( fPollingThread != NULL )
{
thread_call_free ( fPollingThread );
fPollingThread = NULL;
}
}
bool
IOSCSIReducedBlockCommandsDevice::CreateCommandSetObjects ( void )
{
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::CreateCommandSetObjects called\n" ) );
fSCSIReducedBlockCommandObject = SCSIReducedBlockCommands::CreateSCSIReducedBlockCommandObject ( );
if ( fSCSIReducedBlockCommandObject == NULL )
{
ERROR_LOG ( ( "IOSCSIReducedBlockCommandsDevice::start exiting false, RBC object not created\n" ) );
return false;
}
return true;
}
void
IOSCSIReducedBlockCommandsDevice::FreeCommandSetObjects ( void )
{
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::FreeCommandSetObjects called\n" ) );
if ( fSCSIReducedBlockCommandObject )
{
fSCSIReducedBlockCommandObject->release ( );
fSCSIReducedBlockCommandObject = NULL;
}
}
SCSIReducedBlockCommands *
IOSCSIReducedBlockCommandsDevice::GetSCSIReducedBlockCommandObject ( void )
{
return fSCSIReducedBlockCommandObject;
}
SCSIPrimaryCommands *
IOSCSIReducedBlockCommandsDevice::GetSCSIPrimaryCommandObject ( void )
{
return OSDynamicCast ( SCSIPrimaryCommands, GetSCSIReducedBlockCommandObject ( ) );
}
bool
IOSCSIReducedBlockCommandsDevice::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 ( ( "IOSCSIBlockCommandsDevice::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 ( ( "IOSCSIBlockCommandsDevice::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, 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;
}
#pragma mark - Protected Methods
void
IOSCSIReducedBlockCommandsDevice::EnablePolling ( void )
{
AbsoluteTime time;
if ( ( isInactive ( ) == false ) && fPollingThread )
{
retain ( );
clock_interval_to_deadline ( 1000, kMillisecondScale, &time );
thread_call_enter_delayed ( fPollingThread, time );
}
}
void
IOSCSIReducedBlockCommandsDevice::DisablePolling ( void )
{
if ( thread_call_cancel ( fPollingThread ) )
{
release ( );
}
}
bool
IOSCSIReducedBlockCommandsDevice::DetermineDeviceCharacteristics ( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
UInt8 loop;
UInt8 inquiryBufferCount = sizeof ( SCSICmd_INQUIRY_StandardData );
SCSICmd_INQUIRY_StandardData * inquiryBuffer = NULL;
IOMemoryDescriptor * bufferDesc = NULL;
SCSITaskIdentifier request = NULL;
bool succeeded = false;
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
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;
}
for ( loop = 0; ( loop < kMaxRetryCount ) && ( isInactive ( ) == false ) ; loop++ )
{
if ( INQUIRY( request,
bufferDesc,
0,
0,
0x00,
inquiryBufferCount) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW ( ( "IOSCSIBlockCommandsDevice::DetermineDeviceCharacteristics malformed command" ) );
goto ErrorExit;
}
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) )
{
break;
}
}
if ( ( serviceResponse != kSCSIServiceResponse_TASK_COMPLETE ) ||
( GetTaskStatus ( request ) != kSCSITaskStatus_GOOD ) )
{
goto ErrorExit;
}
succeeded = true;
if ( ( inquiryBuffer->RMB & kINQUIRY_PERIPHERAL_RMB_BitMask )
== kINQUIRY_PERIPHERAL_RMB_MediumRemovable )
{
STATUS_LOG ( ( "Media is removable\n" ) );
fMediaIsRemovable = true;
}
else
{
STATUS_LOG ( ( "Media is NOT removable\n" ) );
fMediaIsRemovable = false;
}
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::DetermineDeviceCharacteristics exiting\n" ) );
ErrorExit:
if ( request )
{
ReleaseSCSITask ( request );
request = NULL;
}
if ( bufferDesc )
{
bufferDesc->release ( );
bufferDesc = NULL;
}
if ( inquiryBuffer )
{
IOFree( ( void *) inquiryBuffer, inquiryBufferCount );
inquiryBuffer = NULL;
}
return succeeded;
}
void
IOSCSIReducedBlockCommandsDevice::SetMediaCharacteristics ( UInt32 blockSize, UInt32 blockCount )
{
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
STATUS_LOG ( ( "mediaBlockSize = %ld, blockCount = %ld\n", blockSize, blockCount ) );
fMediaBlockSize = blockSize;
fMediaBlockCount = blockCount;
STATUS_LOG ( ( "%s::%s exiting\n", getName ( ), __FUNCTION__ ) );
}
void
IOSCSIReducedBlockCommandsDevice::ResetMediaCharacteristics ( void )
{
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
fMediaBlockSize = 0;
fMediaBlockCount = 0;
fMediaPresent = false;
STATUS_LOG ( ( "%s::%s exiting\n", getName ( ), __FUNCTION__ ) );
}
void
IOSCSIReducedBlockCommandsDevice::CreateStorageServiceNub ( void )
{
STATUS_LOG ( ( "%s::%s entering.\n", getName ( ), __FUNCTION__ ) );
IOService * nub = new IOReducedBlockServices;
if ( nub == NULL )
{
PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::createStorageServiceNub failed\n" ) );
}
nub->init ( );
if ( !nub->attach ( this ) )
{
PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::createStorageServiceNub unable to attach nub" ) );
}
nub->registerService ( );
STATUS_LOG ( ( "%s::%s exiting.\n", getName ( ), __FUNCTION__ ) );
nub->release();
}
void
IOSCSIReducedBlockCommandsDevice::PollForMedia ( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSI_Sense_Data senseBuffer;
UInt32 capacityData[2];
IOMemoryDescriptor * bufferDesc;
SCSITaskIdentifier request;
bool mediaFound = false;
bool validSense;
SCSITaskStatus taskStatus;
bufferDesc = IOMemoryDescriptor::withAddress ( ( void * ) &senseBuffer,
kSenseDefaultSize,
kIODirectionIn );
if ( bufferDesc == NULL )
{
return;
}
request = GetSCSITask ( );
if ( TEST_UNIT_READY ( request ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" ));
}
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
if ( GetTaskStatus( request ) == kSCSITaskStatus_CHECK_CONDITION )
{
validSense = GetAutoSenseData( request, &senseBuffer );
if ( validSense == false )
{
if ( REQUEST_SENSE ( request, bufferDesc, kSenseDefaultSize ) == false )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" ));
}
}
if ( ( senseBuffer.ADDITIONAL_SENSE_CODE == 0x00 ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x00 ) )
{
mediaFound = true;
}
}
else
{
mediaFound = true;
}
}
bufferDesc->release ( );
if ( mediaFound == false )
{
ReleaseSCSITask ( request );
return;
}
if ( fMediaIsRemovable == true )
{
if ( PREVENT_ALLOW_MEDIUM_REMOVAL ( request, 1 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" ));
}
}
bufferDesc = IOMemoryDescriptor::withAddress ( capacityData,
8,
kIODirectionIn );
if ( READ_CAPACITY ( request, bufferDesc ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::PollForMedia malformed command" ));
}
taskStatus = GetTaskStatus( request );
ReleaseSCSITask ( request );
bufferDesc->release ( );
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( taskStatus == kSCSITaskStatus_GOOD ) )
{
SetMediaCharacteristics ( OSSwapBigToHostInt32 ( capacityData[1] ), OSSwapBigToHostInt32 ( capacityData[0] ) + 1 );
STATUS_LOG ( ( "%s: Media capacity: %x and block size: %x\n",
getName ( ), fMediaBlockCount, fMediaBlockSize ) );
}
else
{
ERROR_LOG ( ( "%s: Read Capacity failed\n", getName() ) );
return;
}
CheckWriteProtection ( );
fMediaPresent = true;
fMediaChanged = true;
messageClients ( kIOMessageMediaStateHasChanged,
( void * ) kIOMediaStateOnline,
sizeof ( IOMediaState ) );
}
void
IOSCSIReducedBlockCommandsDevice::CheckWriteProtection ( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
UInt8 modeSenseBuffer[17];
IOMemoryDescriptor * bufferDesc;
SCSITaskIdentifier request;
SCSITaskStatus taskStatus;
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::checkWriteProtection called\n" ) );
bufferDesc = IOMemoryDescriptor::withAddress ( modeSenseBuffer,
17,
kIODirectionIn );
request = GetSCSITask ( );
if ( MODE_SENSE_6 ( request,
bufferDesc,
0x01,
0,
0x06,
17 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::CheckWriteProtection malformed command" ));
}
taskStatus = GetTaskStatus ( request );
ReleaseSCSITask ( request );
bufferDesc->release ( );
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( taskStatus == kSCSITaskStatus_GOOD ) )
{
STATUS_LOG ( ( "%s: Returned Mode sense data: ", getName ( ) ) );
#if ( SCSI_RBC_DEVICE_DEBUGGING_LEVEL >=3 )
for ( UInt32 i = 0; i < 17; i++ )
{
STATUS_LOG ( ( "%x: ", modeSenseBuffer[i] ) );
}
STATUS_LOG ( ( "\n" ) );
#endif
if ( ( modeSenseBuffer[15] & 0x04 ) != 0 )
{
fMediaIsWriteProtected = true;
}
else
{
fMediaIsWriteProtected = false;
}
}
else
{
STATUS_LOG ( ( "%s: Mode Sense failed with service response = %x\n", getName ( ), serviceResponse ) );
fMediaIsWriteProtected = true;
}
}
void
IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete ( SCSITaskIdentifier request )
{
void * clientData;
IOReturn status;
UInt64 actCount = 0;
IOSCSIReducedBlockCommandsDevice * taskOwner;
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest == NULL )
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete scsiRequest==NULL." ));
}
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete retrieve clientData.\n" ) );
clientData = scsiRequest->GetApplicationLayerReference();
if ( ( scsiRequest->GetServiceResponse ( ) == kSCSIServiceResponse_TASK_COMPLETE ) &&
( scsiRequest->GetTaskStatus ( ) == kSCSITaskStatus_GOOD ) )
{
status = kIOReturnSuccess;
actCount = scsiRequest->GetRealizedDataTransferCount ( );
}
else
{
status = kIOReturnError;
}
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete retrieve taskowner.\n" ) );
taskOwner = OSDynamicCast ( IOSCSIReducedBlockCommandsDevice, scsiRequest->GetTaskOwner ( ) );
if ( taskOwner == NULL )
{
PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete taskOwner==NULL." ) );
}
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete release SCSITask.\n" ) );
taskOwner->ReleaseSCSITask ( request );
STATUS_LOG ( ( "IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete call IOBlockStorageServices::Complete.\n" ) );
IOReducedBlockServices::AsyncReadWriteComplete( clientData, status, actCount );
}
IOReturn
IOSCSIReducedBlockCommandsDevice::IssueRead ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
IOReturn status = kIOReturnError;
STATUS_LOG ( ( "%s: syncRead Attempted\n", getName() ) );
request = GetSCSITask ( );
if ( READ_10 ( request,
buffer,
fMediaBlockSize,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::IssueRead malformed command" ));
}
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) )
{
status = kIOReturnSuccess;
}
ReleaseSCSITask ( request );
return status;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::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,
fMediaBlockSize,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
SetApplicationLayerReference( request, clientData );
SendCommand ( request, 0, &IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete );
}
else
{
PANIC_NOW ( ( "IOSCSIReducedBlockCommandsDevice::IssueRead malformed command" ) );
}
return status;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::IssueWrite ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
IOReturn status = kIOReturnError;
STATUS_LOG ( ( "%s: syncWrite Attempted\n", getName ( ) ) );
request = GetSCSITask ( );
if ( WRITE_10 ( request,
buffer,
fMediaBlockSize,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::IssueWrite malformed command" ));
}
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) )
{
status = kIOReturnSuccess;
}
ReleaseSCSITask ( request );
return status;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::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,
fMediaBlockSize,
0,
( SCSICmdField4Byte ) startBlock,
( SCSICmdField2Byte ) blockCount ) == true )
{
SetApplicationLayerReference( request, clientData );
SendCommand ( request, 0, &IOSCSIReducedBlockCommandsDevice::AsyncReadWriteComplete );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::IssueWrite malformed command" ));
}
return status;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::SyncReadWrite ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount )
{
IODirection direction;
IOReturn status;
direction = buffer->getDirection ( );
if ( direction == kIODirectionIn )
{
status = IssueRead ( buffer, startBlock, blockCount );
}
else if ( direction == kIODirectionOut )
{
status = IssueWrite ( buffer, startBlock, blockCount );
}
else
{
ERROR_LOG ( ( "%s: SyncReadWrite bad direction argument\n", getName ( ) ) );
status = kIOReturnBadArgument;
}
return status;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::AsyncReadWrite ( IOMemoryDescriptor * buffer,
UInt64 startBlock,
UInt64 blockCount,
void * clientData )
{
IODirection direction;
IOReturn status;
direction = buffer->getDirection ( );
if ( direction == kIODirectionIn )
{
IssueRead ( buffer, startBlock, blockCount, clientData );
status = kIOReturnSuccess;
}
else if ( direction == kIODirectionOut )
{
IssueWrite ( buffer, startBlock, blockCount, clientData );
status = kIOReturnSuccess;
}
else
{
ERROR_LOG ( ( "%s: AsyncReadWrite bad direction argument\n", getName ( ) ) );
status = kIOReturnBadArgument;
}
return status;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::EjectTheMedia ( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
request = GetSCSITask ( );
if ( fMediaIsRemovable == false )
{
if ( SYNCHRONIZE_CACHE( request ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::EjectTheMedia malformed command" ));
}
ReleaseSCSITask ( request );
return kIOReturnSuccess;
}
if ( PREVENT_ALLOW_MEDIUM_REMOVAL ( request, 0 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::EjectTheMedia malformed command" ));
}
if ( START_STOP_UNIT ( request, 0, 0, 1, 0 ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::EjectTheMedia malformed command" ));
}
ReleaseSCSITask ( request );
ResetMediaCharacteristics ( );
fMediaIsWriteProtected = true;
EnablePolling ( );
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::FormatMedia ( UInt64 byteCapacity )
{
IOReturn status = kIOReturnUnsupported;
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
return status;
}
UInt32
IOSCSIReducedBlockCommandsDevice::GetFormatCapacities ( UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
return 0;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::LockUnlockMedia ( bool doLock )
{
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::SynchronizeCache ( void )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request;
IOReturn status = kIOReturnError;
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
request = GetSCSITask ( );
if ( SYNCHRONIZE_CACHE ( request ) == true )
{
serviceResponse = SendCommand( request, 0 );
}
else
{
PANIC_NOW(( "IOSCSIReducedBlockCommandsDevice::SynchronizeCache malformed command" ));
}
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) )
{
status = kIOReturnSuccess;
}
ReleaseSCSITask ( request );
return status;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportBlockSize ( UInt64 * blockSize )
{
STATUS_LOG ( ( "%s::%s ReportBlockSize blockSize = %ld\n",
getName ( ), __FUNCTION__, ( UInt32 ) fMediaBlockSize ) );
*blockSize = fMediaBlockSize;
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportEjectability ( bool * isEjectable )
{
STATUS_LOG ( ( "%s::%s ReportEjectability mediaIsRemovable = %d\n",
getName ( ), __FUNCTION__, fMediaIsRemovable ) );
*isEjectable = fMediaIsRemovable;
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportLockability ( bool * isLockable )
{
STATUS_LOG ( ( "%s::%s isLockable = %d\n", getName ( ), __FUNCTION__, true ) );
*isLockable = true;
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportPollRequirements ( bool * pollIsRequired,
bool * pollIsExpensive )
{
STATUS_LOG ( ( "%s::%s called \n", getName ( ), __FUNCTION__ ) );
*pollIsRequired = false;
*pollIsExpensive = false;
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportMaxReadTransfer ( UInt64 blockSize,
UInt64 * max )
{
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
*max = blockSize * 256;
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportMaxValidBlock ( UInt64 * maxBlock )
{
STATUS_LOG ( ( "%s::%s maxBlock = %ld\n", getName ( ),
__FUNCTION__, fMediaBlockCount - 1 ) );
*maxBlock = fMediaBlockCount - 1;
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportMaxWriteTransfer ( UInt64 blockSize,
UInt64 * max )
{
STATUS_LOG ( ( "%s::%s called.\n", getName ( ), __FUNCTION__ ) );
return ( ReportMaxReadTransfer ( blockSize, max ) );
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportMediaState ( bool * mediaPresent,
bool * changed )
{
STATUS_LOG ( ( "%s::%s called.\n", getName ( ), __FUNCTION__ ) );
*mediaPresent = fMediaPresent;
*changed = fMediaChanged;
if ( fMediaChanged )
{
fMediaChanged = !fMediaChanged;
}
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportRemovability ( bool * isRemovable )
{
STATUS_LOG ( ( "%s::%s isRemovable = %d.\n", getName ( ),
__FUNCTION__, fMediaIsRemovable ) );
*isRemovable = fMediaIsRemovable;
return kIOReturnSuccess;
}
IOReturn
IOSCSIReducedBlockCommandsDevice::ReportWriteProtection ( bool * isWriteProtected )
{
STATUS_LOG ( ( "%s::%s isWriteProtected = %d.\n", getName ( ),
__FUNCTION__, fMediaIsWriteProtected ) );
*isWriteProtected = fMediaIsWriteProtected;
return kIOReturnSuccess;
}
void
IOSCSIReducedBlockCommandsDevice::sPollForMedia ( void * pdtDriver, void * refCon )
{
IOSCSIReducedBlockCommandsDevice * driver;
driver = ( IOSCSIReducedBlockCommandsDevice * ) pdtDriver;
driver->PollForMedia ( );
if ( !driver->fMediaPresent )
{
driver->EnablePolling ( );
}
driver->release ( );
}
#pragma mark -
#pragma mark Reduced Block Commands Builders
bool
IOSCSIReducedBlockCommandsDevice::FORMAT_UNIT(
SCSITaskIdentifier request,
SCSICmdField1Bit IMMED,
SCSICmdField1Bit PROGRESS,
SCSICmdField1Bit PERCENT_TIME,
SCSICmdField1Bit INCREMENT )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIReducedBlockCommandObject()->FORMAT_UNIT(
scsiRequest,
IMMED,
PROGRESS,
PERCENT_TIME,
INCREMENT );
}
bool
IOSCSIReducedBlockCommandsDevice::INQUIRY(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField1Bit CMDDT,
SCSICmdField1Bit EVPD,
SCSICmdField1Byte PAGE_OR_OPERATION_CODE,
SCSICmdField1Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->INQUIRY(
scsiRequest,
dataBuffer,
CMDDT,
EVPD,
PAGE_OR_OPERATION_CODE,
ALLOCATION_LENGTH,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::MODE_SELECT_6(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField1Bit PF,
SCSICmdField1Bit SP,
SCSICmdField1Byte PARAMETER_LIST_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->MODE_SELECT_6(
scsiRequest,
dataBuffer,
PF,
SP,
PARAMETER_LIST_LENGTH,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::MODE_SENSE_6(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField1Bit DBD,
SCSICmdField2Bit PC,
SCSICmdField6Bit PAGE_CODE,
SCSICmdField1Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->MODE_SENSE_6(
scsiRequest,
dataBuffer,
DBD,
PC,
PAGE_CODE,
ALLOCATION_LENGTH,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::PERSISTENT_RESERVE_IN(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField5Bit SERVICE_ACTION,
SCSICmdField2Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->PERSISTENT_RESERVE_IN(
scsiRequest,
dataBuffer,
SERVICE_ACTION,
ALLOCATION_LENGTH,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::PERSISTENT_RESERVE_OUT (
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField5Bit SERVICE_ACTION,
SCSICmdField4Bit SCOPE,
SCSICmdField4Bit TYPE )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->PERSISTENT_RESERVE_OUT(
scsiRequest,
dataBuffer,
SERVICE_ACTION,
SCOPE,
TYPE,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::PREVENT_ALLOW_MEDIUM_REMOVAL(
SCSITaskIdentifier request,
SCSICmdField2Bit PREVENT )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->PREVENT_ALLOW_MEDIUM_REMOVAL(
scsiRequest,
PREVENT,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::READ_10(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIReducedBlockCommandObject()->READ_10(
scsiRequest,
dataBuffer,
blockSize,
LOGICAL_BLOCK_ADDRESS,
TRANSFER_LENGTH );
}
bool
IOSCSIReducedBlockCommandsDevice::READ_CAPACITY(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIReducedBlockCommandObject()->READ_CAPACITY(
scsiRequest,
dataBuffer );
}
bool
IOSCSIReducedBlockCommandsDevice::RELEASE_6(
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->RELEASE_6(
scsiRequest,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::REQUEST_SENSE(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField1Byte ALLOCATION_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->REQUEST_SENSE(
scsiRequest,
dataBuffer,
ALLOCATION_LENGTH,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::RESERVE_6(
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->RESERVE_6(
scsiRequest,
0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::START_STOP_UNIT(
SCSITaskIdentifier request,
SCSICmdField1Bit IMMED,
SCSICmdField4Bit POWER_CONDITIONS,
SCSICmdField1Bit LOEJ,
SCSICmdField1Bit START )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIReducedBlockCommandObject()->START_STOP_UNIT(
scsiRequest,
IMMED,
POWER_CONDITIONS,
LOEJ,
START );
}
bool
IOSCSIReducedBlockCommandsDevice::SYNCHRONIZE_CACHE(
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIReducedBlockCommandObject()->SYNCHRONIZE_CACHE( scsiRequest );
}
bool
IOSCSIReducedBlockCommandsDevice::TEST_UNIT_READY(
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->TEST_UNIT_READY( scsiRequest, 0x00 );
}
bool
IOSCSIReducedBlockCommandsDevice::VERIFY(
SCSITaskIdentifier request,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte VERIFICATION_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIReducedBlockCommandObject()->VERIFY(
scsiRequest,
LOGICAL_BLOCK_ADDRESS,
VERIFICATION_LENGTH );
}
bool
IOSCSIReducedBlockCommandsDevice::WRITE_10(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
UInt32 blockSize,
SCSICmdField1Bit FUA,
SCSICmdField4Byte LOGICAL_BLOCK_ADDRESS,
SCSICmdField2Byte TRANSFER_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIReducedBlockCommandObject()->WRITE_10(
scsiRequest,
dataBuffer,
blockSize,
FUA,
LOGICAL_BLOCK_ADDRESS,
TRANSFER_LENGTH );
}
bool
IOSCSIReducedBlockCommandsDevice::WRITE_BUFFER(
SCSITaskIdentifier request,
IOMemoryDescriptor * dataBuffer,
SCSICmdField4Bit MODE,
SCSICmdField1Byte BUFFER_ID,
SCSICmdField3Byte BUFFER_OFFSET,
SCSICmdField3Byte PARAMETER_LIST_LENGTH )
{
SCSITask * scsiRequest;
STATUS_LOG ( ( "%s::%s called\n", getName(), __FUNCTION__ ) );
scsiRequest = OSDynamicCast( SCSITask, request );
if ( scsiRequest->ResetForNewTask() == false )
{
ERROR_LOG ( ( "ResetForNewTask on the request SCSITask failed.\n" ) );
return false;
}
return GetSCSIPrimaryCommandObject()->WRITE_BUFFER(
scsiRequest,
dataBuffer,
MODE,
BUFFER_ID,
BUFFER_OFFSET,
PARAMETER_LIST_LENGTH,
0x00 );
}
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 1 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 2 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 3 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 4 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 5 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 6 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 7 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 8 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 9 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 10 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 11 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 12 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 13 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 14 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 15 );
OSMetaClassDefineReservedUnused( IOSCSIReducedBlockCommandsDevice, 16 );