IOSCSIPrimaryCommandsDevice.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
#include "IOSCSIPrimaryCommandsDevice.h"
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "SPC"
#if DEBUG
#define SCSI_SPC_DEVICE_DEBUGGING_LEVEL 0
#endif
#include "IOSCSIArchitectureModelFamilyDebugging.h"
#if ( SCSI_SPC_DEVICE_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( SCSI_SPC_DEVICE_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( SCSI_SPC_DEVICE_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define super IOSCSIProtocolInterface
OSDefineMetaClass ( IOSCSIPrimaryCommandsDevice, IOSCSIProtocolInterface );
OSDefineAbstractStructors ( IOSCSIPrimaryCommandsDevice, IOSCSIProtocolInterface );
enum
{
kSecondsInAMinute = 60
};
#define kPowerConditionsModePage 0x1A
#define kPowerConditionsModePageSize 12
#define kIOPropertyPowerConditionsSupportedKey "PowerConditionsSupported"
#define kAppleKeySwitchProperty "AppleKeyswitch"
#define kKeySwitchProperty "Keyswitch"
#define fKeySwitchNotifier fIOSCSIPrimaryCommandsDeviceReserved->fKeySwitchNotifier
#define fANSIVersion fIOSCSIPrimaryCommandsDeviceReserved->fANSIVersion
#if 0
#pragma mark -
#pragma mark ₯ Public Methods
#pragma mark -
#endif
bool
IOSCSIPrimaryCommandsDevice::init ( OSDictionary * propTable )
{
bool result = false;
require ( super::init ( propTable ), ErrorExit );
result = true;
ErrorExit:
return result;
}
bool
IOSCSIPrimaryCommandsDevice::start ( IOService * provider )
{
OSString * string = NULL;
OSIterator * iterator = NULL;
OSObject * obj = NULL;
UInt64 maxByteCount = 0;
bool result = false;
require ( super::start ( provider ), ErrorExit );
fDeviceAccessEnabled = false;
fDeviceAccessSuspended = false;
fDeviceSupportsPowerConditions = false;
fNumCommandsOutstanding = 0;
fIOSCSIPrimaryCommandsDeviceReserved = ( IOSCSIPrimaryCommandsDeviceExpansionData * )
IOMalloc ( sizeof ( IOSCSIPrimaryCommandsDeviceExpansionData ) );
require_nonzero ( fIOSCSIPrimaryCommandsDeviceReserved, ErrorExit );
bzero ( fIOSCSIPrimaryCommandsDeviceReserved,
sizeof ( IOSCSIPrimaryCommandsDeviceExpansionData ) );
fANSIVersion = kINQUIRY_ANSI_VERSION_NoClaimedConformance;
fProtocolDriver = OSDynamicCast ( IOSCSIProtocolInterface, provider );
require_nonzero ( fProtocolDriver, FreeReservedMemory );
fDeviceCharacteristicsDictionary = OSDictionary::withCapacity ( 1 );
require_nonzero ( fDeviceCharacteristicsDictionary, FreeReservedMemory );
string = ( OSString * ) GetProtocolDriver ( )->getProperty ( kIOPropertySCSIVendorIdentification );
check ( string );
fDeviceCharacteristicsDictionary->setObject ( kIOPropertyVendorNameKey, string );
string = ( OSString * ) GetProtocolDriver ( )->getProperty ( kIOPropertySCSIProductIdentification );
check ( string );
fDeviceCharacteristicsDictionary->setObject ( kIOPropertyProductNameKey, string );
string = ( OSString * ) GetProtocolDriver ( )->getProperty ( kIOPropertySCSIProductRevisionLevel );
check ( string );
fDeviceCharacteristicsDictionary->setObject ( kIOPropertyProductRevisionLevelKey, string );
require ( CreateCommandSetObjects ( ), FreeDeviceDictionary );
GetProtocolDriver ( )->open ( this );
STATUS_LOG ( ( "%s: Check for the SCSI Device Characteristics property from provider.\n", getName ( ) ) );
if ( ( GetProtocolDriver ( )->getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ) == NULL )
{
STATUS_LOG ( ( "%s: No SCSI Device Characteristics property, set defaults.\n", getName ( ) ) );
fDefaultInquiryCount = 0;
}
else
{
OSDictionary * characterDict;
STATUS_LOG ( ( "%s: Get the SCSI Device Characteristics property from provider.\n", getName ( ) ) );
characterDict = OSDynamicCast ( OSDictionary, ( GetProtocolDriver ( )->getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ) );
STATUS_LOG ( ( "%s: set this SCSI Device Characteristics property.\n", getName ( ) ) );
setProperty ( kIOPropertySCSIDeviceCharacteristicsKey, characterDict );
STATUS_LOG ( ( "%s: check for the Inquiry Length property.\n", getName ( ) ) );
if ( characterDict->getObject ( kIOPropertySCSIInquiryLengthKey ) == NULL )
{
STATUS_LOG ( ( "%s: No Inquiry Length property, use default.\n", getName ( ) ) );
fDefaultInquiryCount = 0;
}
else
{
OSNumber * defaultInquiry;
STATUS_LOG ( ( "%s: Get Inquiry Length property.\n", getName ( ) ) );
defaultInquiry = OSDynamicCast ( OSNumber, characterDict->getObject ( kIOPropertySCSIInquiryLengthKey ) );
fDefaultInquiryCount = defaultInquiry->unsigned32BitValue ( );
}
}
if ( IsProtocolServiceSupported ( kSCSIProtocolFeature_MaximumReadTransferByteCount, &maxByteCount ) )
{
if ( maxByteCount > 0 )
{
setProperty ( kIOMaximumSegmentCountReadKey, maxByteCount / page_size, 64 );
}
}
maxByteCount = 0;
if ( IsProtocolServiceSupported ( kSCSIProtocolFeature_MaximumWriteTransferByteCount, &maxByteCount ) )
{
if ( maxByteCount > 0 )
{
setProperty ( kIOMaximumSegmentCountWriteKey, maxByteCount / page_size, 64 );
}
}
fProtocolAccessEnabled = true;
require ( InitializeDeviceSupport ( ), CloseProvider );
iterator = getMatchingServices ( nameMatching ( kAppleKeySwitchProperty ) );
if ( iterator != NULL )
{
while ( obj = iterator->getNextObject ( ) )
{
IOService * service = ( IOService * ) obj;
OSBoolean * boolKey = NULL;
boolKey = OSDynamicCast (
OSBoolean,
service->getProperty ( kKeySwitchProperty ) );
setProperty ( kAppleKeySwitchProperty, boolKey );
}
iterator->release ( );
iterator = NULL;
}
fDeviceAccessEnabled = true;
StartDeviceSupport ( );
if ( getProperty ( kAppleKeySwitchProperty ) )
{
removeProperty ( kAppleKeySwitchProperty );
}
fKeySwitchNotifier = addNotification (
gIOMatchedNotification,
nameMatching ( kAppleKeySwitchProperty ),
( IOServiceNotificationHandler ) &IOSCSIPrimaryCommandsDevice::ServerKeyswitchCallback,
this,
0 );
result = true;
return result;
CloseProvider:
GetProtocolDriver ( )->close ( this );
FreeDeviceDictionary:
require_nonzero ( fDeviceCharacteristicsDictionary, FreeReservedMemory );
fDeviceCharacteristicsDictionary->release ( );
fDeviceCharacteristicsDictionary = NULL;
FreeReservedMemory:
require_nonzero ( fIOSCSIPrimaryCommandsDeviceReserved, ErrorExit );
IOFree ( fIOSCSIPrimaryCommandsDeviceReserved,
sizeof ( IOSCSIPrimaryCommandsDeviceExpansionData ) );
fIOSCSIPrimaryCommandsDeviceReserved = NULL;
ErrorExit:
return result;
}
void
IOSCSIPrimaryCommandsDevice::stop ( IOService * provider )
{
fProtocolAccessEnabled = false;
if ( fDeviceAccessEnabled == true )
{
fDeviceAccessEnabled = false;
StopDeviceSupport ( );
}
if ( ( fProtocolDriver != NULL ) && ( fProtocolDriver == provider ) )
{
fProtocolDriver->close ( this );
fProtocolDriver = NULL;
super::stop ( provider );
}
}
void
IOSCSIPrimaryCommandsDevice::free ( void )
{
FreeCommandSetObjects ( );
if ( fIOSCSIPrimaryCommandsDeviceReserved != NULL )
{
IOFree ( fIOSCSIPrimaryCommandsDeviceReserved,
sizeof ( IOSCSIPrimaryCommandsDeviceExpansionData ) );
fIOSCSIPrimaryCommandsDeviceReserved = NULL;
}
super::free ( );
}
IOReturn
IOSCSIPrimaryCommandsDevice::message ( UInt32 type,
IOService * nub,
void * arg )
{
IOReturn status;
switch ( type )
{
case kIOMessageServiceIsRequestingClose:
{
STATUS_LOG ( ( "%s: kIOMessageServiceIsRequestingClose Received\n", getName ( ) ) );
fProtocolAccessEnabled = false;
if ( fDeviceAccessEnabled == true )
{
fDeviceAccessEnabled = false;
StopDeviceSupport ( );
}
if ( fKeySwitchNotifier != NULL )
{
fKeySwitchNotifier->remove ( );
fKeySwitchNotifier = NULL;
}
TerminateDeviceSupport ( );
if ( fProtocolDriver != NULL )
{
fProtocolDriver->close ( this );
}
status = kIOReturnSuccess;
}
break;
case kSCSIServicesNotification_Suspend:
{
ERROR_LOG ( ( "type = kSCSIServicesNotification_Suspend, nub = %p\n", nub ) );
fDeviceAccessSuspended = true;
SuspendDeviceSupport ( );
status = kIOReturnSuccess;
}
break;
case kSCSIServicesNotification_Resume:
{
ERROR_LOG ( ( "type = kSCSIServicesNotification_Resume, nub = %p\n", nub ) );
fDeviceAccessSuspended = false;
ResumeDeviceSupport ( );
status = kIOReturnSuccess;
}
break;
case kSCSIProtocolNotification_VerifyDeviceState:
{
STATUS_LOG ( ("%s: kSCSIProtocolNotification_VerifyDeviceState Received\n", getName ( ) ) );
status = VerifyDeviceState ( );
}
break;
default:
{
status = super::message ( type, nub, arg );
}
break;
}
return status;
}
IOReturn
IOSCSIPrimaryCommandsDevice::VerifyDeviceState ( void )
{
return kIOReturnSuccess;
}
bool
IOSCSIPrimaryCommandsDevice::IsProtocolAccessEnabled ( void )
{
return fProtocolAccessEnabled;
}
bool
IOSCSIPrimaryCommandsDevice::IsDeviceAccessEnabled ( void )
{
return fDeviceAccessEnabled;
}
bool
IOSCSIPrimaryCommandsDevice::IsDeviceAccessSuspended ( void )
{
return fDeviceAccessSuspended;
}
#if 0
#pragma mark -
#pragma mark ₯ Power Management Methods
#pragma mark -
#endif
IOReturn
IOSCSIPrimaryCommandsDevice::setAggressiveness ( UInt32 type, UInt32 minutes )
{
UInt32 numStateTransitions = 0;
if ( type == kPMMinutesToSpinDown )
{
STATUS_LOG ( ( "IOSCSIPrimaryCommandsDevice: setting idle timer to %ld min\n", minutes ) );
numStateTransitions = GetNumberOfPowerStateTransitions ( );
if ( numStateTransitions != 0 )
{
setIdleTimerPeriod ( minutes * ( kSecondsInAMinute / numStateTransitions ) );
}
else
{
setIdleTimerPeriod ( 0 );
}
}
return ( super::setAggressiveness ( type, minutes ) );
}
bool
IOSCSIPrimaryCommandsDevice::ClearPowerOnReset ( void )
{
SCSI_Sense_Data senseBuffer;
IOMemoryDescriptor * bufferDesc;
SCSITaskIdentifier request;
bool driveReady = false;
bool result = true;
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
bufferDesc = IOMemoryDescriptor::withAddress( ( void * ) &senseBuffer,
kSenseDefaultSize,
kIODirectionIn );
request = GetSCSITask ( );
do
{
if ( TEST_UNIT_READY ( request, 0 ) == true )
{
serviceResponse = SendCommand ( request, kTenSecondTimeoutInMS );
}
else
{
PANIC_NOW ( ( "IOSCSIPrimaryCommandsDevice::ClearPowerOnReset malformed command" ) );
}
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
bool validSense = false;
if ( GetTaskStatus ( request ) == kSCSITaskStatus_CHECK_CONDITION )
{
validSense = GetAutoSenseData ( request, &senseBuffer, sizeof ( senseBuffer ) );
if ( validSense == false )
{
if ( REQUEST_SENSE ( request, bufferDesc, kSenseDefaultSize, 0 ) == true )
{
serviceResponse = SendCommand ( request, kTenSecondTimeoutInMS );
}
else
{
PANIC_NOW ( ( "IOSCSIPrimaryCommandsDevice::ClearPowerOnReset REQUEST_SENSE malformed command" ) );
}
if ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE )
{
validSense = true;
}
else
{
IOSleep ( 200 );
}
}
if ( validSense == true )
{
if ( ( ( ( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ) == kSENSE_KEY_UNIT_ATTENTION ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE == 0x29 ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x00 ) ) ||
( ( ( senseBuffer.SENSE_KEY & kSENSE_KEY_Mask ) == kSENSE_KEY_UNIT_ATTENTION ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE == 0x28 ) &&
( senseBuffer.ADDITIONAL_SENSE_CODE_QUALIFIER == 0x00 ) ) )
{
STATUS_LOG ( ( "%s::drive NOT READY\n", getName ( ) ) );
driveReady = false;
IOSleep ( 200 );
}
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
IOSCSIPrimaryCommandsDevice::CheckPowerConditionsModePage ( void )
{
UInt8 buffer[kPowerConditionsModePageSize];
IOMemoryDescriptor * bufferDesc;
IOReturn status;
bool use10Byte = true;
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
bufferDesc = IOMemoryDescriptor::withAddress ( ( void * ) buffer,
kPowerConditionsModePageSize,
kIODirectionIn );
if ( bufferDesc != NULL )
{
status = GetModeSense ( bufferDesc,
kPowerConditionsModePage,
kPowerConditionsModePageSize,
&use10Byte );
if ( status == kIOReturnSuccess )
{
if ( ( buffer[8] & 0x3F ) == kPowerConditionsModePage )
{
STATUS_LOG ( ( "Device supports power conditions page\n" ) );
fDeviceSupportsPowerConditions = true;
}
}
bufferDesc->release ( );
}
#if ( SCSI_SPC_DEVICE_DEBUGGING_LEVEL > 0 )
setProperty ( kIOPropertyPowerConditionsSupportedKey, fDeviceSupportsPowerConditions );
#endif
}
void
IOSCSIPrimaryCommandsDevice::IncrementOutstandingCommandsCount ( void )
{
fCommandGate->runAction ( ( IOCommandGate::Action )
&IOSCSIPrimaryCommandsDevice::sIncrementOutstandingCommandsCount );
}
void
IOSCSIPrimaryCommandsDevice::sIncrementOutstandingCommandsCount (
IOSCSIPrimaryCommandsDevice * self )
{
self->HandleIncrementOutstandingCommandsCount ( );
}
void
IOSCSIPrimaryCommandsDevice::HandleIncrementOutstandingCommandsCount ( void )
{
fNumCommandsOutstanding++;
}
#if 0
#pragma mark -
#pragma mark ₯ΚSCSI Task Get and Release
#pragma mark -
#endif
SCSITaskIdentifier
IOSCSIPrimaryCommandsDevice::GetSCSITask ( void )
{
SCSITask * newTask = new SCSITask;
check ( newTask );
newTask->SetTaskOwner ( this );
IncrementOutstandingCommandsCount ( );
retain ( );
return ( SCSITaskIdentifier ) newTask;
}
void
IOSCSIPrimaryCommandsDevice::ReleaseSCSITask ( SCSITaskIdentifier request )
{
require_nonzero ( request, Exit );
fNumCommandsOutstanding--;
request->release ( );
release ( );
Exit:
return;
}
#if 0
#pragma mark -
#pragma mark ₯ Supporting Object Accessor Methods
#pragma mark -
#endif
IOSCSIProtocolInterface *
IOSCSIPrimaryCommandsDevice::GetProtocolDriver ( void )
{
check ( fProtocolDriver );
return fProtocolDriver;
}
SCSIPrimaryCommands *
IOSCSIPrimaryCommandsDevice::GetSCSIPrimaryCommandObject ( void )
{
STATUS_LOG ( ( "%s: getSCSIPrimaryCommandObject called.\n", getName ( ) ) );
return fSCSIPrimaryCommandObject;
}
bool
IOSCSIPrimaryCommandsDevice::CreateCommandSetObjects ( void )
{
bool result = false;
fSCSIPrimaryCommandObject =
SCSIPrimaryCommands::CreateSCSIPrimaryCommandObject ( );
require_nonzero ( fSCSIPrimaryCommandObject, ErrorExit );
result = true;
ErrorExit:
return result;
}
void
IOSCSIPrimaryCommandsDevice::FreeCommandSetObjects ( void )
{
if ( fSCSIPrimaryCommandObject != NULL )
{
fSCSIPrimaryCommandObject->release( );
fSCSIPrimaryCommandObject = NULL;
}
}
#if 0
#pragma mark -
#pragma mark ₯ Task Execution Support Methods
#pragma mark -
#endif
void
IOSCSIPrimaryCommandsDevice::TaskCallback ( SCSITaskIdentifier completedTask )
{
SCSIServiceResponse serviceResponse;
SCSITask * scsiRequest;
IOSyncer * fSyncLock;
scsiRequest = OSDynamicCast ( SCSITask, completedTask );
require_nonzero ( scsiRequest, ErrorExit );
fSyncLock = ( IOSyncer * ) scsiRequest->GetApplicationLayerReference ( );
check ( fSyncLock );
serviceResponse = scsiRequest->GetServiceResponse ( );
fSyncLock->signal ( serviceResponse, false );
return;
ErrorExit:
IOPanic ( "IOSCSIPrimaryCommandsDevice::TaskCallback called with no SCSITask\n" );
return;
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::SendCommand (
SCSITaskIdentifier request,
UInt32 timeoutDuration )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
IOSyncer * fSyncLock = NULL;
require ( IsProtocolAccessEnabled ( ), ProtocolAccessDisabledError );
fSyncLock = IOSyncer::create ( false );
require_nonzero ( fSyncLock, SyncerCreationFailedError );
fSyncLock->signal ( kIOReturnSuccess, false );
SetTimeoutDuration ( request, timeoutDuration );
SetTaskCompletionCallback ( request, &IOSCSIPrimaryCommandsDevice::TaskCallback );
SetApplicationLayerReference ( request, ( void * ) fSyncLock );
SetAutosenseCommand ( request,
kSCSICmd_REQUEST_SENSE,
0x00,
0x00,
0x00,
sizeof ( SCSI_Sense_Data ),
0x00 );
fSyncLock->reinit ( );
GetProtocolDriver ( )->ExecuteCommand ( request );
serviceResponse = ( SCSIServiceResponse) fSyncLock->wait ( false );
fSyncLock->release ( );
return serviceResponse;
SyncerCreationFailedError:
ProtocolAccessDisabledError:
SetServiceResponse ( request, serviceResponse );
SetTaskStatus ( request, kSCSITaskStatus_No_Status );
return serviceResponse;
}
void
IOSCSIPrimaryCommandsDevice::SendCommand (
SCSITaskIdentifier request,
UInt32 timeoutDuration,
SCSITaskCompletion taskCompletion )
{
SetTaskCompletionCallback ( request, taskCompletion );
require ( IsProtocolAccessEnabled ( ), ProtocolAccessDisabledError );
SetTimeoutDuration ( request, timeoutDuration );
SetAutosenseCommand ( request,
kSCSICmd_REQUEST_SENSE,
0x00,
0x00,
0x00,
sizeof ( SCSI_Sense_Data ),
0x00 );
GetProtocolDriver ( )->ExecuteCommand ( request );
return;
ProtocolAccessDisabledError:
SetServiceResponse ( request,
kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE );
SetTaskStatus ( request, kSCSITaskStatus_No_Status );
TaskCompletedNotification ( request );
return;
}
#if 0
#pragma mark -
#pragma mark ₯ SCSI Task Field Accessors
#pragma mark -
#endif
bool
IOSCSIPrimaryCommandsDevice::SetTaskAttribute (
SCSITaskIdentifier request,
SCSITaskAttribute newAttribute )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetTaskAttribute ( newAttribute );
}
SCSITaskAttribute
IOSCSIPrimaryCommandsDevice::GetTaskAttribute ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetTaskAttribute ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetTaskState ( SCSITaskIdentifier request,
SCSITaskState newTaskState )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetTaskState ( newTaskState );
}
SCSITaskState
IOSCSIPrimaryCommandsDevice::GetTaskState ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
return scsiRequest->GetTaskState( );
}
bool
IOSCSIPrimaryCommandsDevice::SetTaskStatus ( SCSITaskIdentifier request,
SCSITaskStatus newStatus )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetTaskStatus ( newStatus );
}
SCSITaskStatus
IOSCSIPrimaryCommandsDevice::GetTaskStatus ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetTaskStatus ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetDataTransferDirection (
SCSITaskIdentifier request,
UInt8 newDirection )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetDataTransferDirection ( newDirection );
}
UInt8
IOSCSIPrimaryCommandsDevice::GetDataTransferDirection (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetDataTransferDirection ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetRequestedDataTransferCount (
SCSITaskIdentifier request,
UInt64 newRequestedCount )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetRequestedDataTransferCount ( newRequestedCount );
}
UInt64
IOSCSIPrimaryCommandsDevice::GetRequestedDataTransferCount (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetRequestedDataTransferCount ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetRealizedDataTransferCount (
SCSITaskIdentifier request,
UInt64 newRealizedDataCount )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetRealizedDataTransferCount ( newRealizedDataCount );
}
UInt64
IOSCSIPrimaryCommandsDevice::GetRealizedDataTransferCount (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetRealizedDataTransferCount ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetDataBuffer ( SCSITaskIdentifier request,
IOMemoryDescriptor * newBuffer )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetDataBuffer ( newBuffer );
}
IOMemoryDescriptor *
IOSCSIPrimaryCommandsDevice::GetDataBuffer ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetDataBuffer ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetTimeoutDuration (
SCSITaskIdentifier request,
UInt32 newTimeout )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetTimeoutDuration ( newTimeout );
}
UInt32
IOSCSIPrimaryCommandsDevice::GetTimeoutDuration ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetTimeoutDuration ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetTaskCompletionCallback (
SCSITaskIdentifier request,
SCSITaskCompletion newCallback )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetTaskCompletionCallback ( newCallback );
}
void
IOSCSIPrimaryCommandsDevice::TaskCompletedNotification (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->TaskCompletedNotification ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetServiceResponse (
SCSITaskIdentifier request,
SCSIServiceResponse serviceResponse )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetServiceResponse ( serviceResponse );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::GetServiceResponse (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetServiceResponse ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetAutosenseCommand (
SCSITaskIdentifier request,
UInt8 cdbByte0,
UInt8 cdbByte1,
UInt8 cdbByte2,
UInt8 cdbByte3,
UInt8 cdbByte4,
UInt8 cdbByte5 )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetAutosenseCommand ( cdbByte0, cdbByte1, cdbByte2,
cdbByte3, cdbByte4, cdbByte5 );
}
bool
IOSCSIPrimaryCommandsDevice::GetAutoSenseData ( SCSITaskIdentifier request,
SCSI_Sense_Data * senseData )
{
return GetAutoSenseData ( request, senseData, sizeof ( SCSI_Sense_Data ) );
}
bool
IOSCSIPrimaryCommandsDevice::GetAutoSenseData ( SCSITaskIdentifier request,
SCSI_Sense_Data * senseData,
UInt8 senseDataSize )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetAutoSenseData ( senseData, senseDataSize );
}
UInt8
IOSCSIPrimaryCommandsDevice::GetAutoSenseDataSize ( SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetAutoSenseDataSize ( );
}
bool
IOSCSIPrimaryCommandsDevice::SetApplicationLayerReference (
SCSITaskIdentifier request,
void * newReferenceValue )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->SetApplicationLayerReference ( newReferenceValue );
}
void *
IOSCSIPrimaryCommandsDevice::GetApplicationLayerReference (
SCSITaskIdentifier request )
{
SCSITask * scsiRequest;
scsiRequest = OSDynamicCast ( SCSITask, request );
check ( scsiRequest );
return scsiRequest->GetApplicationLayerReference ( );
}
#if 0
#pragma mark -
#pragma mark ₯ Device Information Methods
#pragma mark -
#endif
char *
IOSCSIPrimaryCommandsDevice::GetVendorString ( void )
{
OSString * vendorString;
vendorString = ( OSString * ) GetProtocolDriver ( )->getProperty (
kIOPropertySCSIVendorIdentification );
if ( vendorString != NULL )
{
return ( ( char * ) vendorString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
char *
IOSCSIPrimaryCommandsDevice::GetProductString ( void )
{
OSString * productString;
productString = ( OSString * ) GetProtocolDriver ( )->getProperty (
kIOPropertySCSIProductIdentification );
if ( productString != NULL )
{
return ( ( char * ) productString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
char *
IOSCSIPrimaryCommandsDevice::GetRevisionString ( void )
{
OSString * revisionString;
STATUS_LOG ( ( "%s::%s\n", getName ( ), __FUNCTION__ ) );
revisionString = ( OSString * ) GetProtocolDriver ( )->getProperty (
kIOPropertySCSIProductRevisionLevel );
if ( revisionString != NULL )
{
return ( ( char * ) revisionString->getCStringNoCopy ( ) );
}
else
{
return "NULL STRING";
}
}
OSDictionary *
IOSCSIPrimaryCommandsDevice::GetProtocolCharacteristicsDictionary ( void )
{
return ( OSDictionary * ) GetProtocolDriver ( )->getProperty (
kIOPropertyProtocolCharacteristicsKey );
}
OSDictionary *
IOSCSIPrimaryCommandsDevice::GetDeviceCharacteristicsDictionary ( void )
{
check ( fDeviceCharacteristicsDictionary );
return fDeviceCharacteristicsDictionary;
}
UInt8
IOSCSIPrimaryCommandsDevice::GetANSIVersion ( void )
{
return fANSIVersion;
}
void
IOSCSIPrimaryCommandsDevice::SetANSIVersion ( UInt8 newVersion )
{
fANSIVersion = newVersion;
}
IOReturn
IOSCSIPrimaryCommandsDevice::GetModeSense (
IOMemoryDescriptor * dataBuffer,
SCSICmdField6Bit PAGE_CODE,
SCSICmdField2Byte ALLOCATION_LENGTH,
bool * use10ByteModeSense )
{
SCSIServiceResponse serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
SCSITaskIdentifier request = NULL;
SCSICmdField1Bit DBD = 0;
IOReturn status = kIOReturnNoResources;
bool commandOK = false;
request = GetSCSITask ( );
require_nonzero ( request, ErrorExit );
OUTERLOOP:
DBD = 1;
INNERLOOP:
if ( *use10ByteModeSense )
{
commandOK = MODE_SENSE_10 ( request,
dataBuffer,
0x00,
DBD,
0x00,
PAGE_CODE,
ALLOCATION_LENGTH,
0 );
}
else
{
commandOK = MODE_SENSE_6 ( request,
dataBuffer,
DBD,
0x00,
PAGE_CODE,
ALLOCATION_LENGTH & 0xFF,
0 );
}
if ( commandOK )
{
serviceResponse = SendCommand ( request, kThirtySecondTimeoutInMS );
}
else
{
PANIC_NOW ( ( "IOSCSIMultimediaCommandsDevice::GetMechanicalCapabilitiesSize malformed command" ) );
}
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( GetTaskStatus ( request ) == kSCSITaskStatus_GOOD ) )
{
if ( GetRealizedDataTransferCount ( request ) == GetRequestedDataTransferCount ( request ) )
{
status = kIOReturnSuccess;
}
else if ( GetRealizedDataTransferCount ( request ) < GetRequestedDataTransferCount ( request ) )
{
status = kIOReturnUnderrun;
}
else
{
status = kIOReturnIOError;
}
}
else
{
if ( DBD == 1 )
{
ERROR_LOG ( ( "Trying again with DBD=0\n" ) );
DBD = 0;
goto INNERLOOP;
}
ERROR_LOG ( ( "Modes sense returned error\n" ) );
}
if ( status != kIOReturnSuccess )
{
if ( *use10ByteModeSense )
{
ERROR_LOG ( ( "Trying again with MODE_SENSE_6 command\n" ) );
*use10ByteModeSense = false;
goto OUTERLOOP;
}
ERROR_LOG ( ( "Modes sense returned error\n" ) );
}
ReleaseSCSITask ( request );
ErrorExit:
return status;
}
#if 0
#pragma mark -
#pragma mark ₯ SCSI Protocol Interface Implementations
#pragma mark -
#endif
void
IOSCSIPrimaryCommandsDevice::ExecuteCommand ( SCSITaskIdentifier request )
{
GetProtocolDriver ( )->ExecuteCommand ( request );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::AbortCommand ( SCSITaskIdentifier request )
{
return GetProtocolDriver ( )->AbortCommand ( request );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::AbortTask (
UInt8 theLogicalUnit,
SCSITaggedTaskIdentifier theTag )
{
return GetProtocolDriver ( )->AbortTask ( theLogicalUnit, theTag );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::AbortTaskSet ( UInt8 theLogicalUnit )
{
return GetProtocolDriver ( )->AbortTaskSet ( theLogicalUnit );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::ClearACA ( UInt8 theLogicalUnit )
{
return GetProtocolDriver ( )->ClearACA ( theLogicalUnit );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::ClearTaskSet ( UInt8 theLogicalUnit )
{
return GetProtocolDriver ( )->ClearTaskSet ( theLogicalUnit );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::LogicalUnitReset ( UInt8 theLogicalUnit )
{
return GetProtocolDriver ( )->LogicalUnitReset ( theLogicalUnit );
}
SCSIServiceResponse
IOSCSIPrimaryCommandsDevice::TargetReset ( void )
{
return GetProtocolDriver ( )->TargetReset ( );
}
bool
IOSCSIPrimaryCommandsDevice::IsProtocolServiceSupported (
SCSIProtocolFeature feature,
void * serviceValue )
{
return GetProtocolDriver ( )->IsProtocolServiceSupported ( feature, serviceValue );
}
bool
IOSCSIPrimaryCommandsDevice::HandleProtocolServiceFeature (
SCSIProtocolFeature feature,
void * serviceValue )
{
return GetProtocolDriver ( )->HandleProtocolServiceFeature ( feature, serviceValue );
}
#if 0
#pragma mark -
#pragma mark ₯ Static Methods C->C++ Glue
#pragma mark -
#endif
bool
IOSCSIPrimaryCommandsDevice::ServerKeyswitchCallback (
void * target,
void * refCon,
IOService * newDevice )
{
OSBoolean * shouldNotPoll = NULL;
IOSCSIPrimaryCommandsDevice * device = NULL;
shouldNotPoll = OSDynamicCast (
OSBoolean,
newDevice->getProperty ( kKeySwitchProperty ) );
device = OSDynamicCast ( IOSCSIPrimaryCommandsDevice, ( OSObject * ) target );
if ( ( shouldNotPoll != NULL ) && ( device != NULL ) )
{
if ( shouldNotPoll->isFalse ( ) )
{
device->ResumeDeviceSupport ( );
}
else if ( shouldNotPoll->isTrue ( ) )
{
device->SuspendDeviceSupport ( );
}
}
return true;
}
#if 0
#pragma mark -
#pragma mark ₯ VTable Padding
#pragma mark -
#endif
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 1 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 2 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 3 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 4 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 5 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 6 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 7 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 8 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 9 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 10 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 11 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 12 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 13 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 14 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 15 );
OSMetaClassDefineReservedUnused ( IOSCSIPrimaryCommandsDevice, 16 );