IOSCSIParallelInterfaceDevice.cpp [plain text]
#include <libkern/c++/OSData.h>
#include <libkern/c++/OSDictionary.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
#include <IOKit/scsi/SCSICommandOperationCodes.h>
#include <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h>
#include "IOSCSIParallelInterfaceDevice.h"
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "SPI Device"
#if DEBUG
#define SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL 0
#endif
#include "IOSCSIParallelFamilyDebugging.h"
#if ( SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) kprintf x
#else
#define ERROR_LOG(x)
#endif
#if ( SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) kprintf x
#else
#define STATUS_LOG(x)
#endif
#define super IOSCSIProtocolServices
OSDefineMetaClassAndStructors ( IOSCSIParallelInterfaceDevice, IOSCSIProtocolServices );
#define kIOPropertyIOUnitKey "IOUnit"
#ifndef kIOPropertySASAddressKey
#define kIOPropertySASAddressKey "SAS Address"
#endif
enum
{
kWorldWideNameDataSize = 8,
kAddressIdentifierDataSize = 3,
kALPADataSize = 1,
kSASAddressDataSize = 8
};
#if 0
#pragma mark -
#pragma mark ₯ IOKit Member Routines
#pragma mark -
#endif
bool
IOSCSIParallelInterfaceDevice::SetInitialTargetProperties (
OSDictionary * properties )
{
OSDictionary * protocolDict = NULL;
OSObject * value = NULL;
bool result = false;
protocolDict = OSDictionary::withCapacity ( properties->getCount ( ) );
require_nonzero ( protocolDict, INIT_FAILURE );
setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
protocolDict->release ( );
protocolDict = NULL;
value = properties->getObject ( kIOPropertyFibreChannelNodeWorldWideNameKey );
SetTargetProperty ( kIOPropertyFibreChannelNodeWorldWideNameKey, value );
value = properties->getObject ( kIOPropertyFibreChannelPortWorldWideNameKey );
SetTargetProperty ( kIOPropertyFibreChannelPortWorldWideNameKey, value );
value = properties->getObject ( kIOPropertyFibreChannelAddressIdentifierKey );
SetTargetProperty ( kIOPropertyFibreChannelAddressIdentifierKey, value );
value = properties->getObject ( kIOPropertyFibreChannelALPAKey );
SetTargetProperty ( kIOPropertyFibreChannelALPAKey, value );
value = properties->getObject ( kIOPropertySASAddressKey );
SetTargetProperty ( kIOPropertySASAddressKey, value );
result = true;
INIT_FAILURE:
return result;
}
bool
IOSCSIParallelInterfaceDevice::start ( IOService * provider )
{
OSDictionary * protocolDict = NULL;
bool result = false;
char unit[10];
fController = OSDynamicCast ( IOSCSIParallelInterfaceController, provider );
require_nonzero ( fController, PROVIDER_CAST_FAILURE );
result = super::start ( provider );
require ( result, PROVIDER_START_FAILURE );
result = fController->open ( this );
require ( result, CONTROLLER_OPEN_FAILURE );
result = fController->InitializeTargetForID ( fTargetIdentifier );
require ( result, CONTROLLER_INIT_FAILURE );
InitializePowerManagement ( provider );
protocolDict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertyProtocolCharacteristicsKey ) );
protocolDict = OSDictionary::withDictionary ( protocolDict );
if ( protocolDict != NULL )
{
OSNumber * targetID = NULL;
targetID = OSNumber::withNumber ( fTargetIdentifier, 64 );
if ( targetID != NULL )
{
protocolDict->setObject ( kIOPropertySCSITargetIdentifierKey, targetID );
setProperty ( kIOPropertyIOUnitKey, targetID );
targetID->release ( );
}
setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
protocolDict->release ( );
protocolDict = NULL;
}
sprintf ( unit, "%x", ( int ) fTargetIdentifier );
setLocation ( unit );
CreateSCSITargetDevice ( );
return true;
CONTROLLER_INIT_FAILURE:
CONTROLLER_OPEN_FAILURE:
PROVIDER_START_FAILURE:
PROVIDER_CAST_FAILURE:
return false;
}
void
IOSCSIParallelInterfaceDevice::stop ( IOService * provider )
{
super::stop ( provider );
}
bool
IOSCSIParallelInterfaceDevice::willTerminate ( IOService * provider,
IOOptionBits options )
{
ERROR_LOG ( ( "IOSCSIParallelInterfaceDevice::willTerminate\n" ) );
SendNotification_DeviceRemoved ( );
return true;
}
bool
IOSCSIParallelInterfaceDevice::didTerminate ( IOService * provider,
IOOptionBits options,
bool * defer )
{
ERROR_LOG ( ( "IOSCSIParallelInterfaceDevice::didTerminate\n" ) );
if ( fController != NULL )
{
fController->close ( this );
fController = NULL;
}
return true;
}
void
IOSCSIParallelInterfaceDevice::free ( void )
{
if ( fHBAData != NULL )
{
IOFree ( fHBAData, fHBADataSize );
fHBAData = NULL;
fHBADataSize = 0;
}
if ( fQueueLock != NULL )
{
IOSimpleLockFree ( fQueueLock );
fQueueLock = NULL;
}
if ( fResendQueueLock != NULL )
{
IOSimpleLockFree ( fResendQueueLock );
fResendQueueLock = NULL;
}
super::free ( );
}
IOReturn
IOSCSIParallelInterfaceDevice::message (
UInt32 type,
IOService * provider,
void * argument )
{
IOReturn result = kIOReturnSuccess;
switch ( type )
{
case kSCSIControllerNotificationBusReset:
{
for ( int index = 0; index < kSCSIParallelFeature_TotalFeatureCount; index++ )
{
fFeatureIsNegotiated[index] = false;
}
SendNotification_VerifyDeviceState ( );
}
break;
case kSCSIPort_NotificationStatusChange:
{
messageClients ( kSCSIPort_NotificationStatusChange, argument );
}
default:
{
result = super::message ( type, provider, argument );
}
break;
}
return result;
}
IOReturn
IOSCSIParallelInterfaceDevice::requestProbe ( IOOptionBits options )
{
if ( isOpen ( ) == false )
{
CreateSCSITargetDevice ( );
return kIOReturnSuccess;
}
else
{
return kIOReturnNotPermitted;
}
}
#if 0
#pragma mark -
#pragma mark ₯ Device Object Management Member routines
#pragma mark -
#endif
IOSCSIParallelInterfaceDevice *
IOSCSIParallelInterfaceDevice::CreateTarget (
SCSITargetIdentifier targetID,
UInt32 sizeOfHBAData,
IORegistryEntry * entry )
{
IOSCSIParallelInterfaceDevice * newDevice = OSTypeAlloc ( IOSCSIParallelInterfaceDevice );
require_nonzero ( newDevice, DEVICE_CREATION_FAILURE );
if ( entry != NULL )
newDevice->init ( entry, gIODTPlane );
else
newDevice->init ( 0 );
newDevice->fHBAData = NULL;
newDevice->fHBADataSize = sizeOfHBAData;
newDevice->fTargetIdentifier = targetID;
newDevice->fPreviousParallelDevice = NULL;
newDevice->fNextParallelDevice = NULL;
newDevice->fOutstandingTaskList = NULL;
newDevice->fQueueLock = NULL;
newDevice->fResendTaskList = NULL;
newDevice->fResendQueueLock = NULL;
bzero ( newDevice->fFeatureIsNegotiated,
kSCSIParallelFeature_TotalFeatureCount * sizeof ( bool ) );
bzero ( newDevice->fITNexusSupportsFeature,
kSCSIParallelFeature_TotalFeatureCount * sizeof ( bool ) );
newDevice->fQueueLock = IOSimpleLockAlloc ( );
require_nonzero ( newDevice->fQueueLock, LOCK_ALLOC_FAILURE );
newDevice->fResendQueueLock = IOSimpleLockAlloc ( );
require_nonzero ( newDevice->fResendQueueLock, LOCK_ALLOC_FAILURE );
if ( sizeOfHBAData != 0 )
{
newDevice->fHBAData = IOMalloc ( sizeOfHBAData );
require_nonzero ( newDevice->fHBAData, HBA_DATA_ALLOC_FAILURE );
bzero ( newDevice->fHBAData, sizeOfHBAData );
}
return newDevice;
HBA_DATA_ALLOC_FAILURE:
if ( newDevice->fQueueLock != NULL )
{
IOSimpleLockFree ( newDevice->fQueueLock );
newDevice->fQueueLock = NULL;
}
if ( newDevice->fResendQueueLock != NULL )
{
IOSimpleLockFree ( newDevice->fResendQueueLock );
newDevice->fResendQueueLock = NULL;
}
LOCK_ALLOC_FAILURE:
require_nonzero_quiet ( newDevice, DEVICE_CREATION_FAILURE );
newDevice->release ( );
newDevice = NULL;
DEVICE_CREATION_FAILURE:
return NULL;
}
void
IOSCSIParallelInterfaceDevice::DestroyTarget ( void )
{
#if 0
while ( fResendTaskList != NULL )
{
SCSIParallelTaskIdentifier parallelTask = NULL;
SCSITaskIdentifier request = NULL;
parallelTask = fResendTaskList;
RemoveFromResendTaskList ( parallelTask);
RemoveFromOutstandingTaskList ( parallelTask );
request = GetSCSITaskIdentifier ( parallelTask );
FreeSCSIParallelTask ( parallelTask );
CommandCompleted ( request,
kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE,
kSCSITaskStatus_DeviceNotPresent );
}
#endif
}
IOSCSIParallelInterfaceDevice *
IOSCSIParallelInterfaceDevice::GetPreviousDeviceInList ( void )
{
return fPreviousParallelDevice;
}
void
IOSCSIParallelInterfaceDevice::SetPreviousDeviceInList (
IOSCSIParallelInterfaceDevice * newPrev )
{
fPreviousParallelDevice = newPrev;
}
IOSCSIParallelInterfaceDevice *
IOSCSIParallelInterfaceDevice::GetNextDeviceInList ( void )
{
return fNextParallelDevice;
}
void
IOSCSIParallelInterfaceDevice::SetNextDeviceInList (
IOSCSIParallelInterfaceDevice * newNext )
{
fNextParallelDevice = newNext;
}
void
IOSCSIParallelInterfaceDevice::DetermineParallelFeatures ( UInt8 * inqData )
{
OSDictionary * dict = NULL;
OSNumber * features = NULL;
UInt64 deviceFeatures = 0;
UInt64 ITNexusFeatures = 0;
bool supported = false;
UInt8 inqSCSIVersion = 0;
UInt8 inqDataLength = 0;
inqSCSIVersion = ( ( SCSICmd_INQUIRY_StandardData * ) inqData )->VERSION & kINQUIRY_ANSI_VERSION_Mask;
inqDataLength = ( ( SCSICmd_INQUIRY_StandardData * ) inqData )->ADDITIONAL_LENGTH + 5;
if ( ( inqSCSIVersion >= kINQUIRY_ANSI_VERSION_SCSI_2_Compliant ) &&
( inqDataLength > kINQUIRY_Byte7_Offset ) )
{
if ( inqData[kINQUIRY_Byte7_Offset] & kINQUIRY_Byte7_SYNC_Mask )
{
deviceFeatures |= (1 << kSCSIParallelFeature_SynchronousDataTransfer);
supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_SynchronousDataTransfer );
if ( supported == true )
{
fITNexusSupportsFeature[kSCSIParallelFeature_SynchronousDataTransfer] = true;
ITNexusFeatures |= (1 << kSCSIParallelFeature_SynchronousDataTransfer);
}
}
if ( inqData[kINQUIRY_Byte7_Offset] & kINQUIRY_Byte7_WBUS16_Mask )
{
deviceFeatures |= (1 << kSCSIParallelFeature_WideDataTransfer);
supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_WideDataTransfer );
if ( supported == true )
{
fITNexusSupportsFeature[kSCSIParallelFeature_WideDataTransfer] = true;
ITNexusFeatures |= (1 << kSCSIParallelFeature_WideDataTransfer);
}
}
}
if ( ( inqSCSIVersion >= kINQUIRY_ANSI_VERSION_SCSI_SPC_Compliant ) &&
( inqDataLength > kINQUIRY_Byte56_Offset ) )
{
if ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_IUS_Mask )
{
deviceFeatures |= (1 << kSCSIParallelFeature_InformationUnitTransfers);
supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_InformationUnitTransfers );
if ( supported == true )
{
fITNexusSupportsFeature[kSCSIParallelFeature_InformationUnitTransfers] = true;
ITNexusFeatures |= (1 << kSCSIParallelFeature_InformationUnitTransfers);
}
}
if ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_QAS_Mask )
{
deviceFeatures |= (1 << kSCSIParallelFeature_QuickArbitrationAndSelection);
supported = DoesHBASupportSCSIParallelFeature( kSCSIParallelFeature_QuickArbitrationAndSelection );
if ( supported == true )
{
fITNexusSupportsFeature[kSCSIParallelFeature_QuickArbitrationAndSelection] = true;
ITNexusFeatures |= (1 << kSCSIParallelFeature_QuickArbitrationAndSelection);
}
}
if ( ( ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_CLOCKING_Mask ) == kINQUIRY_Byte56_CLOCKING_ONLY_DT ) ||
( ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_CLOCKING_Mask ) == kINQUIRY_Byte56_CLOCKING_ST_AND_DT ) )
{
deviceFeatures |= (1 << kSCSIParallelFeature_DoubleTransitionDataTransfers);
supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_DoubleTransitionDataTransfers );
if ( supported == true )
{
fITNexusSupportsFeature[kSCSIParallelFeature_DoubleTransitionDataTransfers] = true;
ITNexusFeatures |= (1 << kSCSIParallelFeature_DoubleTransitionDataTransfers);
}
}
}
dict = ( OSDictionary * ) getProperty ( kIOPropertyProtocolCharacteristicsKey );
dict = OSDictionary::withDictionary ( dict );
if ( dict != NULL )
{
features = OSNumber::withNumber ( deviceFeatures, 64 );
if ( features != NULL )
{
dict->setObject ( kIOPropertySCSIDeviceFeaturesKey, features );
features->release ( );
features = NULL;
}
features = OSNumber::withNumber ( ITNexusFeatures, 64 );
if ( features != NULL )
{
dict->setObject ( kIOPropertySCSI_I_T_NexusFeaturesKey, features );
features->release ( );
features = NULL;
}
setProperty ( kIOPropertyProtocolCharacteristicsKey, dict );
dict->release ( );
dict = NULL;
}
}
SCSITargetIdentifier
IOSCSIParallelInterfaceDevice::GetTargetIdentifier ( void )
{
return fTargetIdentifier;
}
void *
IOSCSIParallelInterfaceDevice::GetHBADataPointer ( void )
{
return fHBAData;
}
UInt32
IOSCSIParallelInterfaceDevice::GetHBADataSize ( void )
{
return fHBADataSize;
}
bool
IOSCSIParallelInterfaceDevice::IsFeatureNegotiationNecessary (
SCSIParallelFeature feature )
{
if ( feature >= kSCSIParallelFeature_TotalFeatureCount )
{
return false;
}
return ( fITNexusSupportsFeature[feature] &&
( fFeatureIsNegotiated[feature] == false ) );
}
SCSIParallelTaskIdentifier
IOSCSIParallelInterfaceDevice::FindTaskForAddress (
SCSILogicalUnitNumber theL,
SCSITaggedTaskIdentifier theQ )
{
SCSIParallelTask * tempTask;
IOSimpleLockLock ( fQueueLock );
tempTask = fOutstandingTaskList;
while ( tempTask != NULL )
{
if ( ( GetLogicalUnitNumber ( tempTask ) == theL ) &&
( GetTaggedTaskIdentifier ( tempTask ) == theQ ) )
{
break;
}
tempTask = tempTask->GetNextTaskInList ( );
}
IOSimpleLockUnlock ( fQueueLock );
return tempTask;
}
SCSIParallelTaskIdentifier
IOSCSIParallelInterfaceDevice::FindTaskForControllerIdentifier (
UInt64 theIdentifier )
{
SCSIParallelTask * tempTask;
IOSimpleLockLock ( fQueueLock );
tempTask = fOutstandingTaskList;
while ( tempTask != NULL )
{
if ( theIdentifier == kSCSIParallelTaskControllerIDQueueHead )
{
break;
}
if ( GetControllerTaskIdentifier ( tempTask ) == theIdentifier )
{
break;
}
tempTask = tempTask->GetNextTaskInList ( );
}
IOSimpleLockUnlock ( fQueueLock );
return tempTask;
}
bool
IOSCSIParallelInterfaceDevice::SetTargetProperty (
const char * key,
OSObject * value )
{
bool result = false;
OSDictionary * protocolDict = NULL;
require_nonzero ( key, ErrorExit );
require_nonzero ( value, ErrorExit );
protocolDict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertyProtocolCharacteristicsKey ) );
protocolDict = OSDictionary::withDictionary ( protocolDict );
require_nonzero ( protocolDict, ErrorExit );
if ( strcmp ( key, kIOPropertyFibreChannelPortWorldWideNameKey ) == 0 )
{
OSData * data = OSDynamicCast ( OSData, value );
require_nonzero ( data, ErrorExit );
require ( ( data->getLength ( ) == kWorldWideNameDataSize ), ErrorExit );
result = protocolDict->setObject ( key, value );
}
else if ( strcmp ( key, kIOPropertyFibreChannelNodeWorldWideNameKey ) == 0 )
{
OSData * data = OSDynamicCast ( OSData, value );
char name[27] = { 0 };
require_nonzero ( data, ErrorExit );
require ( ( data->getLength ( ) == kWorldWideNameDataSize ), ErrorExit );
result = protocolDict->setObject ( key, value );
snprintf ( name, sizeof ( name ), "FC Target %016qX", OSSwapHostToBigInt64 ( *( UInt64 * ) data->getBytesNoCopy ( ) ) );
setName ( name, gIOServicePlane );
}
else if ( strcmp ( key, kIOPropertyFibreChannelAddressIdentifierKey ) == 0 )
{
OSData * data = OSDynamicCast ( OSData, value );
require_nonzero ( data, ErrorExit );
require ( ( data->getLength ( ) == kAddressIdentifierDataSize ), ErrorExit );
result = protocolDict->setObject ( key, value );
}
else if ( strcmp ( key, kIOPropertyFibreChannelALPAKey ) == 0 )
{
OSData * data = OSDynamicCast ( OSData, value );
require_nonzero ( data, ErrorExit );
require ( ( data->getLength ( ) == kALPADataSize ), ErrorExit );
result = protocolDict->setObject ( key, value );
}
else if ( strcmp ( key, kIOPropertySASAddressKey ) == 0 )
{
OSData * data = OSDynamicCast ( OSData, value );
char name[28] = { 0 };
require_nonzero ( data, ErrorExit );
require ( ( data->getLength ( ) == kSASAddressDataSize ), ErrorExit );
result = protocolDict->setObject ( key, value );
snprintf ( name, sizeof ( name ), "SAS Target %016qX", OSSwapHostToBigInt64 ( *( UInt64 * ) data->getBytesNoCopy ( ) ) );
setName ( name, gIOServicePlane );
}
setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
protocolDict->release ( );
protocolDict = NULL;
ErrorExit:
return result;
}
void
IOSCSIParallelInterfaceDevice::RemoveTargetProperty ( const char * key )
{
OSDictionary * protocolDict = NULL;
require_nonzero ( key, ErrorExit );
protocolDict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertyProtocolCharacteristicsKey ) );
protocolDict = OSDictionary::withDictionary ( protocolDict );
require_nonzero ( protocolDict, ErrorExit );
if ( protocolDict->getObject ( key ) != NULL )
{
protocolDict->removeObject ( key );
}
setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
protocolDict->release ( );
protocolDict = NULL;
ErrorExit:
return;
}
#if 0
#pragma mark -
#pragma mark ₯ SCSI Protocol Services Member Routines
#pragma mark -
#endif
bool
IOSCSIParallelInterfaceDevice::SendSCSICommand (
SCSITaskIdentifier request,
SCSIServiceResponse * serviceResponse,
SCSITaskStatus * taskStatus )
{
SCSIParallelTaskIdentifier parallelTask = NULL;
IOMemoryDescriptor * buffer = NULL;
IOReturn status = kIOReturnBadArgument;
*taskStatus = kSCSITaskStatus_No_Status;
*serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
if ( request == NULL )
{
return true;
}
parallelTask = GetSCSIParallelTask ( true );
if ( parallelTask == NULL )
{
return false;
}
SetTargetIdentifier ( parallelTask, fTargetIdentifier );
SetSCSITaskIdentifier ( parallelTask, request );
for ( UInt32 index = 0; index < kSCSIParallelFeature_TotalFeatureCount; index++ )
{
if ( IsFeatureNegotiationNecessary ( ( SCSIParallelFeature ) index ) == true )
{
SetSCSIParallelFeatureNegotiation (
parallelTask,
( SCSIParallelFeature ) index,
kSCSIParallelFeature_AttemptNegotiation );
}
}
AddToOutstandingTaskList ( parallelTask );
buffer = GetDataBuffer ( parallelTask );
if ( buffer != NULL )
{
status = SetDMABuffer ( parallelTask, buffer );
if ( status != kIOReturnSuccess )
{
ERROR_LOG ( ( "SetDMABuffer failed, status = 0x%08x\n", status ) );
RemoveFromOutstandingTaskList ( parallelTask );
FreeSCSIParallelTask ( parallelTask );
CommandCompleted ( request, *serviceResponse, *taskStatus );
return true;
}
}
*serviceResponse = ExecuteParallelTask ( parallelTask );
if ( *serviceResponse != kSCSIServiceResponse_Request_In_Process )
{
RemoveFromOutstandingTaskList ( parallelTask );
FreeSCSIParallelTask ( parallelTask );
CommandCompleted ( request, *serviceResponse, *taskStatus );
}
return true;
}
void
IOSCSIParallelInterfaceDevice::CompleteSCSITask (
SCSIParallelTaskIdentifier completedTask,
SCSIServiceResponse serviceResponse,
SCSITaskStatus completionStatus )
{
SCSITaskIdentifier clientRequest = NULL;
if ( completedTask == NULL )
{
return;
}
if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
( completionStatus == kSCSITaskStatus_TASK_SET_FULL ) )
{
AddToResendTaskList ( completedTask );
return;
}
RemoveFromOutstandingTaskList ( completedTask );
clientRequest = GetSCSITaskIdentifier ( completedTask );
if ( clientRequest == NULL )
{
IOPanic ( "clientRequest is NULL in CompleteSCSITask\n" );
}
IOSCSIProtocolServices::SetRealizedDataTransferCount ( clientRequest, GetRealizedDataTransferCount ( completedTask ) );
for ( UInt32 index = 0; index < kSCSIParallelFeature_TotalFeatureCount; index++ )
{
if ( IsFeatureNegotiationNecessary ( ( SCSIParallelFeature ) index ) == true )
{
if ( GetSCSIParallelFeatureNegotiationResult ( completedTask, ( SCSIParallelFeature ) index ) ==
kSCSIParallelFeature_NegotitiationSuccess )
{
fFeatureIsNegotiated[index] = true;
}
}
}
FreeSCSIParallelTask ( completedTask );
while ( fResendTaskList != NULL )
{
SCSIParallelTaskIdentifier parallelTask;
parallelTask = fResendTaskList;
RemoveFromResendTaskList ( parallelTask);
if ( ExecuteParallelTask ( parallelTask ) != kSCSIServiceResponse_Request_In_Process )
{
SCSITaskIdentifier nextRequest = NULL;
RemoveFromOutstandingTaskList ( parallelTask );
nextRequest = GetSCSITaskIdentifier ( completedTask );
FreeSCSIParallelTask ( parallelTask );
CommandCompleted ( nextRequest, kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE, kSCSITaskStatus_No_Status );
continue;
}
break;
}
CommandCompleted ( clientRequest, serviceResponse, completionStatus );
}
#if 0
#pragma mark -
#pragma mark ₯ SCSI Protocol Service Feature routines
#pragma mark -
#endif
bool
IOSCSIParallelInterfaceDevice::IsProtocolServiceSupported (
SCSIProtocolFeature feature,
void * value )
{
bool isSupported = false;
switch ( feature )
{
case kSCSIProtocolFeature_GetMaximumLogicalUnitNumber:
{
isSupported = true;
*( UInt32 * ) value = ReportHBAHighestLogicalUnitNumber ( );
}
break;
case kSCSIProtocolFeature_SubmitDefaultInquiryData:
{
isSupported = true;
}
break;
case kSCSIProtocolFeature_ProtocolAlwaysReportsAutosenseData:
{
isSupported = fController->DoesHBAPerformAutoSense ( );
}
break;
default:
{
}
break;
}
return isSupported;
}
bool
IOSCSIParallelInterfaceDevice::HandleProtocolServiceFeature (
SCSIProtocolFeature feature,
void * serviceValue )
{
bool wasHandled = false;
switch ( feature )
{
case kSCSIProtocolFeature_SubmitDefaultInquiryData:
{
DetermineParallelFeatures ( ( UInt8 * ) serviceValue );
wasHandled = true;
registerService ( );
}
break;
default:
{
break;
}
}
return wasHandled;
}
#if 0
#pragma mark -
#pragma mark ₯ SCSI Management Functions
#pragma mark -
#endif
SCSIServiceResponse
IOSCSIParallelInterfaceDevice::AbortSCSICommand (
SCSITaskIdentifier request )
{
return kSCSIServiceResponse_FUNCTION_REJECTED;
}
#if 0
#pragma mark -
#pragma mark ₯ Controller Object Accessors
#pragma mark -
#endif
SCSIServiceResponse
IOSCSIParallelInterfaceDevice::ExecuteParallelTask (
SCSIParallelTaskIdentifier parallelRequest )
{
return fController->ExecuteParallelTask ( parallelRequest );
}
SCSIParallelTaskIdentifier
IOSCSIParallelInterfaceDevice::GetSCSIParallelTask ( bool blockForCommand )
{
return fController->GetSCSIParallelTask ( blockForCommand );
}
void
IOSCSIParallelInterfaceDevice::FreeSCSIParallelTask (
SCSIParallelTaskIdentifier returnTask )
{
return fController->FreeSCSIParallelTask ( returnTask );
}
SCSILogicalUnitNumber
IOSCSIParallelInterfaceDevice::ReportHBAHighestLogicalUnitNumber ( void )
{
return fController->ReportHBAHighestLogicalUnitNumber ( );
}
bool
IOSCSIParallelInterfaceDevice::DoesHBASupportSCSIParallelFeature (
SCSIParallelFeature theFeature )
{
return fController->DoesHBASupportSCSIParallelFeature ( theFeature );
}
#if 0
#pragma mark -
#pragma mark ₯ SCSI Parallel Task Object Accessors
#pragma mark -
#endif
bool
IOSCSIParallelInterfaceDevice::AddToOutstandingTaskList (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return false;
}
IOSimpleLockLock ( fQueueLock );
if ( fOutstandingTaskList == NULL )
{
fOutstandingTaskList = tempTask;
tempTask->SetPreviousTaskInList ( NULL );
tempTask->SetNextTaskInList ( NULL );
}
else
{
SCSIParallelTask * listTask;
listTask = fOutstandingTaskList;
while ( listTask->GetNextTaskInList ( ) != NULL )
{
listTask = listTask->GetNextTaskInList ( );
}
listTask->SetNextTaskInList ( tempTask );
tempTask->SetPreviousTaskInList ( listTask );
tempTask->SetNextTaskInList ( NULL );
}
IOSimpleLockUnlock ( fQueueLock );
return true;
}
void
IOSCSIParallelInterfaceDevice::RemoveFromOutstandingTaskList (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
SCSIParallelTask * nextTask = NULL;
SCSIParallelTask * prevTask = NULL;
IOSimpleLockLock ( fQueueLock );
nextTask = tempTask->GetNextTaskInList ( );
prevTask = tempTask->GetPreviousTaskInList ( );
if ( prevTask != NULL )
{
prevTask->SetNextTaskInList ( nextTask );
}
else
{
fOutstandingTaskList = nextTask;
}
if ( nextTask != NULL )
{
nextTask->SetPreviousTaskInList ( prevTask );
}
tempTask->SetNextTaskInList ( NULL );
tempTask->SetPreviousTaskInList ( NULL );
IOSimpleLockUnlock ( fQueueLock );
}
bool
IOSCSIParallelInterfaceDevice::AddToResendTaskList (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return false;
}
IOSimpleLockLock ( fResendQueueLock );
if ( fResendTaskList == NULL )
{
fResendTaskList = tempTask;
tempTask->SetPreviousResendTaskInList ( NULL );
tempTask->SetNextResendTaskInList ( NULL );
}
else
{
SCSIParallelTask * listTask;
listTask = fResendTaskList;
while ( listTask->GetNextResendTaskInList ( ) != NULL )
{
listTask = listTask->GetNextResendTaskInList ( );
}
listTask->SetNextResendTaskInList ( tempTask );
tempTask->SetPreviousResendTaskInList ( listTask );
tempTask->SetNextResendTaskInList ( NULL );
}
IOSimpleLockUnlock ( fResendQueueLock );
return true;
}
void
IOSCSIParallelInterfaceDevice::RemoveFromResendTaskList (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
SCSIParallelTask * nextTask = NULL;
SCSIParallelTask * prevTask = NULL;
IOSimpleLockLock ( fResendQueueLock );
nextTask = tempTask->GetNextResendTaskInList ( );
prevTask = tempTask->GetPreviousResendTaskInList ( );
if ( prevTask != NULL )
{
prevTask->SetNextResendTaskInList ( nextTask );
}
else
{
fResendTaskList = nextTask;
}
if ( nextTask != NULL )
{
nextTask->SetPreviousResendTaskInList ( prevTask );
}
tempTask->SetNextResendTaskInList ( NULL );
tempTask->SetPreviousResendTaskInList ( NULL );
IOSimpleLockUnlock ( fResendQueueLock );
}
bool
IOSCSIParallelInterfaceDevice::SetSCSITaskIdentifier (
SCSIParallelTaskIdentifier parallelTask,
SCSITaskIdentifier scsiRequest )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return false;
}
return tempTask->SetSCSITaskIdentifier ( scsiRequest );
}
SCSITaskIdentifier
IOSCSIParallelInterfaceDevice::GetSCSITaskIdentifier (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return NULL;
}
return tempTask->GetSCSITaskIdentifier ( );
}
bool
IOSCSIParallelInterfaceDevice::SetTargetIdentifier (
SCSIParallelTaskIdentifier parallelTask,
SCSITargetIdentifier theTargetID )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return false;
}
return tempTask->SetTargetIdentifier ( theTargetID );
}
SCSITargetIdentifier
IOSCSIParallelInterfaceDevice::GetTargetIdentifier (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return NULL;
}
return tempTask->GetTargetIdentifier ( );
}
IOReturn
IOSCSIParallelInterfaceDevice::SetDMABuffer (
SCSIParallelTaskIdentifier parallelTask,
IOMemoryDescriptor * buffer )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return NULL;
}
return tempTask->SetBuffer ( buffer );
}
SCSILogicalUnitNumber
IOSCSIParallelInterfaceDevice::GetLogicalUnitNumber (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetLogicalUnitNumber ( );
}
SCSITaggedTaskIdentifier
IOSCSIParallelInterfaceDevice::GetTaggedTaskIdentifier (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return kSCSIUntaggedTaskIdentifier;
}
return tempTask->GetTaggedTaskIdentifier ( );
}
SCSITaskAttribute
IOSCSIParallelInterfaceDevice::GetTaskAttribute (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return kSCSITask_SIMPLE;
}
return tempTask->GetTaskAttribute ( );
}
UInt8
IOSCSIParallelInterfaceDevice::GetCommandDescriptorBlockSize (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetCommandDescriptorBlockSize ( );
}
bool
IOSCSIParallelInterfaceDevice::GetCommandDescriptorBlock (
SCSIParallelTaskIdentifier parallelTask,
SCSICommandDescriptorBlock * cdbData )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return false;
}
return tempTask->GetCommandDescriptorBlock ( cdbData );
}
UInt8
IOSCSIParallelInterfaceDevice::GetDataTransferDirection (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return kSCSIDataTransfer_NoDataTransfer;
}
return tempTask->GetDataTransferDirection ( );
}
UInt64
IOSCSIParallelInterfaceDevice::GetRequestedDataTransferCount (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetRequestedDataTransferCount ( );
}
UInt64
IOSCSIParallelInterfaceDevice::GetRealizedDataTransferCount (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetRealizedDataTransferCount ( );
}
bool
IOSCSIParallelInterfaceDevice::SetRealizedDataTransferCount (
SCSIParallelTaskIdentifier parallelTask,
UInt64 realizedTransferCountInBytes )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return false;
}
return tempTask->SetRealizedDataTransferCount ( realizedTransferCountInBytes );
}
void
IOSCSIParallelInterfaceDevice::IncrementRealizedDataTransferCount (
SCSIParallelTaskIdentifier parallelTask,
UInt64 realizedTransferCountInBytes )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return;
}
return tempTask->IncrementRealizedDataTransferCount ( realizedTransferCountInBytes );
}
IOMemoryDescriptor *
IOSCSIParallelInterfaceDevice::GetDataBuffer (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return NULL;
}
return tempTask->GetDataBuffer ( );
}
UInt64
IOSCSIParallelInterfaceDevice::GetDataBufferOffset (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetDataBufferOffset ( );
}
UInt32
IOSCSIParallelInterfaceDevice::GetTimeoutDuration (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetTimeoutDuration ( );
}
void
IOSCSIParallelInterfaceDevice::SetSCSIParallelFeatureNegotiation (
SCSIParallelTaskIdentifier parallelTask,
SCSIParallelFeature requestedFeature,
SCSIParallelFeatureRequest newRequest )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return;
}
return tempTask->SetSCSIParallelFeatureNegotiation ( requestedFeature, newRequest );
}
SCSIParallelFeatureRequest
IOSCSIParallelInterfaceDevice::GetSCSIParallelFeatureNegotiation (
SCSIParallelTaskIdentifier parallelTask,
SCSIParallelFeature requestedFeature )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return kSCSIParallelFeature_NoNegotiation;
}
return tempTask->GetSCSIParallelFeatureNegotiation ( requestedFeature );
}
SCSIParallelFeatureResult
IOSCSIParallelInterfaceDevice::GetSCSIParallelFeatureNegotiationResult (
SCSIParallelTaskIdentifier parallelTask,
SCSIParallelFeature requestedFeature )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return kSCSIParallelFeature_NegotitiationUnchanged;
}
return tempTask->GetSCSIParallelFeatureNegotiationResult ( requestedFeature );
}
UInt64
IOSCSIParallelInterfaceDevice::GetControllerTaskIdentifier (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetControllerTaskIdentifier ( );
}
UInt32
IOSCSIParallelInterfaceDevice::GetHBADataSize (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return 0;
}
return tempTask->GetHBADataSize ( );
}
void *
IOSCSIParallelInterfaceDevice::GetHBADataPointer (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return NULL;
}
return tempTask->GetHBADataPointer ( );
}
IOMemoryDescriptor *
IOSCSIParallelInterfaceDevice::GetHBADataDescriptor (
SCSIParallelTaskIdentifier parallelTask )
{
SCSIParallelTask * tempTask = ( SCSIParallelTask * ) parallelTask;
if ( tempTask == NULL )
{
return NULL;
}
return tempTask->GetHBADataDescriptor ( );
}