IOATABlockStorageCommands.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/storage/IOMedia.h>
#include "IOATABlockStorageDriver.h"
#define ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL 0
#if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#if ( ATA_BLOCK_STORAGE_DRIVER_PM_DEBUGGING_LEVEL >= 1 )
#define SERIAL_STATUS_LOG(x) kprintf x
#else
#define SERIAL_STATUS_LOG(x)
#endif
#define kCFBundleIdentifierKey "CFBundleIdentifier"
#define kIOATABlockStorageIdentifierKey "com.apple.iokit.IOATABlockStorage"
#define kPCCardIconFileKey "PCCard.icns"
enum
{
kPIOTransferModeSetup = 1,
kPIOTransferModeDone = 2,
kDMATransferModeDone = 3,
kReadAheadEnableDone = 4,
kWriteCacheEnableDone = 5
};
struct ATAConfigData
{
IOATABlockStorageDriver * self;
UInt32 state;
IOSyncer * syncer;
};
typedef struct ATAConfigData ATAConfigData;
IOReturn
IOATABlockStorageDriver::identifyATADevice ( void )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * cmd = NULL;
ATAClientData * clientData = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyATADevice entering.\n" ) );
cmd = getATACommandObject ( );
assert ( cmd != NULL );
clientData = ( ATAClientData * ) cmd->refCon;
cmd->zeroCommand ( );
cmd->setUnit ( fATAUnitID );
sSetCommandBuffers ( cmd, fDeviceIdentifyBuffer, 0, 1 );
cmd->setCommand ( kATAcmdDriveIdentify );
cmd->setFlags ( mATAFlagIORead );
cmd->setOpcode ( kATAFnExecIO );
cmd->setDevice_Head ( fATAUnitID << 4 );
cmd->setRegMask ( ( ataRegMask ) ( mATAErrFeaturesValid | mATAStatusCmdValid ) );
clientData->command = kATAcmdDriveIdentify;
clientData->flags = mATAFlagIORead;
clientData->opCode = kATAFnExecIO;
clientData->regMask = ( ataRegMask ) ( mATAErrFeaturesValid | mATAStatusCmdValid );
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyATADevice executing identify command.\n" ) );
status = syncExecute ( cmd, kATATimeout10Seconds );
if ( status != kIOReturnSuccess )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::identifyATADevice result = %ld.\n", ( UInt32 ) cmd->getResult ( ) ) );
return status;
}
status = sValidateIdentifyData ( ( UInt8 * ) fDeviceIdentifyData );
#if defined(__BIG_ENDIAN__)
sSwapBytes16 ( ( UInt8 * ) fDeviceIdentifyData, 512 );
#endif
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyATADevice exiting with status = %ld.\n", ( UInt32 ) status ) );
return status;
}
void
IOATABlockStorageDriver::setupReadWriteTaskFile (
IOATACommand * cmd,
IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks )
{
ATAClientData * clientData;
UInt32 flags = mATAFlagUseConfigSpeed;
UInt8 command = 0;
bool isWrite = ( buffer->getDirection ( ) == kIODirectionOut );
STATUS_LOG ( ( "IOATABlockStorageDriver::setupReadWriteTaskFile entering.\n" ) );
clientData = ( ATAClientData * ) cmd->refCon;
cmd->zeroCommand ( );
if ( fUltraDMAMode || fDMAMode )
{
if ( fUseExtendedLBA )
{
command = ( isWrite ) ? 0x35 : 0x25;
flags |= mATAFlag48BitLBA;
}
else
{
command = ( isWrite ) ? kATAcmdWriteDMA : kATAcmdReadDMA;
}
flags |= mATAFlagUseDMA;
}
else
{
if ( fUseExtendedLBA )
{
command = ( isWrite ) ? 0x34 : 0x24;
}
else
{
command = ( isWrite ) ? kATAcmdWrite : kATAcmdRead;
}
}
flags |= ( isWrite ) ? mATAFlagIOWrite : mATAFlagIORead;
cmd->setCommand ( command );
cmd->setSectorCount ( ( nblks == kIOATAMaxBlocksPerXfer ) ? 0 : nblks );
if ( fUseLBAAddressing )
{
if ( fUseExtendedLBA )
{
IOExtendedLBA * extLBA = cmd->getExtendedLBA ( );
extLBA->setExtendedLBA ( 0, block, fATAUnitID, ( UInt16 ) nblks, command );
clientData->useExtendedLBA = true;
clientData->lbaLow16 = extLBA->getLBALow16 ( );
clientData->lbaMid16 = extLBA->getLBAMid16 ( );
clientData->lbaHigh16 = extLBA->getLBAHigh16 ( );
clientData->sectorCount16 = extLBA->getSectorCount16 ( );
clientData->features16 = extLBA->getFeatures16 ( );
clientData->device = extLBA->getDevice ( );
clientData->command16 = extLBA->getCommand ( );
}
else
{
STATUS_LOG ( ( "IOATABlockStorageDriver::setupReadWriteTaskFile block = %lx.\n", block ) );
cmd->setLBA28 ( block, fATAUnitID );
}
clientData->sectorNumber = ( block & 0xFF );
clientData->cylLow = ( ( block & 0xFF00 ) >> 8 );
clientData->cylHigh = ( ( block & 0x00FF0000 ) >> 16 );
}
else
{
UInt32 heads = 0;
UInt32 sectors = 0;
heads = fDeviceIdentifyData[kATAIdentifyLogicalHeadCount];
sectors = fDeviceIdentifyData[kATAIdentifySectorsPerTrack];
sConvertBlockToCHSAddress ( cmd, block, heads, sectors, fATAUnitID );
}
sSetCommandBuffers ( cmd, buffer, 0, nblks );
cmd->setUnit ( fATAUnitID );
cmd->setFlags ( flags );
cmd->setOpcode ( kATAFnExecIO );
clientData->command = command;
clientData->opCode = kATAFnExecIO;
clientData->flags = flags;
STATUS_LOG ( ( "IOATABlockStorageDriver::setupReadWriteTaskFile exiting.\n" ) );
}
IOATACommand *
IOATABlockStorageDriver::ataCommandReadWrite (
IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks )
{
IOATACommand * cmd = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::ataCommandReadWrite entering.\n" ) );
assert ( buffer != NULL );
cmd = getATACommandObject ( );
if ( cmd == NULL )
return NULL;
setupReadWriteTaskFile ( cmd, buffer, block, nblks );
STATUS_LOG ( ( "IOATABlockStorageDriver::ataCommandReadWrite exiting.\n" ) );
return cmd;
}
IOReturn
IOATABlockStorageDriver::ataCommandSetFeatures (
UInt8 features,
UInt8 sectorCount,
UInt8 sectorNumber,
UInt8 cylinderLow,
UInt8 cylinderHigh,
UInt32 flags,
bool forceSync )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "IOATABlockStorageDriver::ataCommandSetFeatures entering.\n" ) );
fConfigurationCommand->zeroCommand ( );
fConfigurationCommand->setUnit ( fATAUnitID );
fConfigurationCommand->setFeatures ( features );
fConfigurationCommand->setSectorCount ( sectorCount );
fConfigurationCommand->setSectorNumber ( sectorNumber );
fConfigurationCommand->setOpcode ( kATAFnExecIO );
fConfigurationCommand->setCommand ( kATAcmdSetFeatures );
fConfigurationCommand->setDevice_Head ( fATAUnitID << 4 );
fConfigurationCommand->setCylHi ( cylinderHigh );
fConfigurationCommand->setCylLo ( cylinderLow );
fConfigurationCommand->setFlags ( flags );
fConfigurationCommand->setTimeoutMS ( kATATimeout10Seconds );
if ( forceSync )
{
fConfigurationCommand->setCallbackPtr ( &IOATABlockStorageDriver::sATAVoidCallback );
}
else
{
fConfigurationCommand->setCallbackPtr ( &IOATABlockStorageDriver::sATAConfigStateMachine );
}
status = fATADevice->executeCommand ( fConfigurationCommand );
STATUS_LOG ( ( "IOATABlockStorageDriver::ataCommandSetFeatures exiting.\n" ) );
return status;
}
IOATACommand *
IOATABlockStorageDriver::ataCommandFlushCache ( void )
{
IOATACommand * cmd = NULL;
ATAClientData * clientData = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::ataCommandFlushCache entering.\n" ) );
cmd = getATACommandObject ( );
if ( cmd == NULL )
return NULL;
clientData = ( ATAClientData * ) cmd->refCon;
cmd->zeroCommand ( );
if ( fDeviceIdentifyData[kATAIdentifyCommandSetSupported2] & kATASupportsFlushCacheExtendedMask )
{
IOExtendedLBA * extLBA = cmd->getExtendedLBA ( );
extLBA->setExtendedLBA ( 0, 0, fATAUnitID, 0, 0xEA );
cmd->setFlags ( mATAFlag48BitLBA );
clientData->useExtendedLBA = true;
clientData->lbaLow16 = extLBA->getLBALow16 ( );
clientData->lbaMid16 = extLBA->getLBAMid16 ( );
clientData->lbaHigh16 = extLBA->getLBAHigh16 ( );
clientData->sectorCount16 = extLBA->getSectorCount16 ( );
clientData->features16 = extLBA->getFeatures16 ( );
clientData->device = extLBA->getDevice ( );
clientData->command16 = extLBA->getCommand ( );
}
cmd->setOpcode ( kATAFnExecIO );
cmd->setCommand ( 0xE7 );
cmd->setDevice_Head ( fATAUnitID << 4 );
cmd->setUnit ( fATAUnitID );
clientData->command = 0xE7;
clientData->opCode = kATAFnExecIO;
STATUS_LOG ( ( "IOATABlockStorageDriver::ataCommandFlushCache exiting.\n" ) );
return cmd;
}
IOReturn
IOATABlockStorageDriver::syncExecute (
IOATACommand * cmd,
UInt32 timeout,
UInt8 retries )
{
ATAClientData * clientData = NULL;
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "IOATABlockStorageDriver::syncExecute entering.\n" ) );
clientData = ( ATAClientData * ) cmd->refCon;
assert ( clientData != NULL );
cmd->setTimeoutMS ( timeout );
cmd->setCallbackPtr ( &IOATABlockStorageDriver::sHandleCommandCompletion );
clientData->completion.syncLock = IOSyncer::create ( );
assert ( clientData->completion.syncLock != NULL );
if ( clientData->completion.syncLock == NULL )
{
returnATACommandObject ( cmd );
return kIOReturnNoResources;
}
clientData->isSync = true;
clientData->self = this;
clientData->maxRetries = retries;
clientData->timeout = timeout;
sSaveStateData ( cmd );
fATADevice->executeCommand ( cmd );
clientData->completion.syncLock->wait ( );
STATUS_LOG ( ( "IOATABlockStorageDriver::syncExecute exiting.\n" ) );
status = clientData->returnCode;
returnATACommandObject ( cmd );
return status;
}
IOReturn
IOATABlockStorageDriver::asyncExecute (
IOATACommand * cmd,
IOStorageCompletion completion,
UInt32 timeout,
UInt8 retries )
{
ATAClientData * clientData = NULL;
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "IOATABlockStorageDriver::asyncExecute entering.\n" ) );
clientData = ( ATAClientData * ) cmd->refCon;
assert ( clientData != NULL );
cmd->setTimeoutMS ( timeout );
cmd->setCallbackPtr ( &IOATABlockStorageDriver::sHandleCommandCompletion );
clientData->isSync = false;
clientData->self = this;
clientData->maxRetries = retries;
clientData->completion.async = completion;
clientData->timeout = timeout;
sSaveStateData ( cmd );
status = fATADevice->executeCommand ( cmd );
if ( status != kATANoErr )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::asyncExecute executeCommand returned error = %ld.\n", ( UInt32 ) status ) );
}
return status;
}
void
IOATABlockStorageDriver::allocateATACommandObjects ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::allocateATACommandObjects entering\n" ) );
IOATACommand * cmd = NULL;
ATAClientData * clientData = NULL;
IOSyncer * syncer = NULL;
ATAConfigData * configData = NULL;
for ( UInt32 index = 0; index < fNumCommandObjects; index++ )
{
cmd = fATADevice->allocCommand ( );
assert ( cmd != NULL );
clientData = ( ATAClientData * ) IOMalloc ( sizeof ( ATAClientData ) );
assert ( clientData != NULL );
bzero ( clientData, sizeof ( ATAClientData ) );
cmd->refCon = ( void * ) clientData;
clientData->cmd = cmd;
STATUS_LOG ( ( "adding command to pool\n" ) );
fCommandPool->returnCommand ( cmd );
}
fResetCommand = fATADevice->allocCommand ( );
fPowerManagementCommand = fATADevice->allocCommand ( );
fConfigurationCommand = fATADevice->allocCommand ( );
assert ( fResetCommand != NULL );
assert ( fPowerManagementCommand != NULL );
assert ( fConfigurationCommand != NULL );
syncer = IOSyncer::create ( );
assert ( syncer != NULL );
fPowerManagementCommand->refCon = ( void * ) syncer;
configData = ( ATAConfigData * ) IOMalloc ( sizeof ( ATAConfigData ) );
assert ( configData != NULL );
bzero ( configData, sizeof ( ATAConfigData ) );
configData->syncer = IOSyncer::create ( );
assert ( configData->syncer != NULL );
fConfigurationCommand->refCon = ( void * ) configData;
STATUS_LOG ( ( "IOATABlockStorageDriver::allocateATACommandObjects exiting\n" ) );
}
void
IOATABlockStorageDriver::deallocateATACommandObjects ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::dellocateATACommandObjects entering\n" ) );
IOATACommand * cmd = NULL;
ATAClientData * clientData = NULL;
IOSyncer * syncer = NULL;
ATAConfigData * configData = NULL;
cmd = ( IOATACommand * ) fCommandPool->getCommand ( false );
assert ( cmd != NULL );
while ( cmd != NULL )
{
clientData = ( ATAClientData * ) cmd->refCon;
assert ( clientData != NULL );
IOFree ( clientData, sizeof ( ATAClientData ) );
clientData = NULL;
fATADevice->freeCommand ( cmd );
cmd = ( IOATACommand * ) fCommandPool->getCommand ( false );
}
syncer = ( IOSyncer * ) fPowerManagementCommand->refCon;
syncer->release ( );
configData = ( ATAConfigData * ) fConfigurationCommand->refCon;
configData->syncer->release ( );
IOFree ( configData, sizeof ( ATAConfigData ) );
fATADevice->freeCommand ( fResetCommand );
fATADevice->freeCommand ( fPowerManagementCommand );
fATADevice->freeCommand ( fConfigurationCommand );
STATUS_LOG ( ( "IOATABlockStorageDriver::dellocateATACommandObjects exiting.\n" ) );
}
IOATACommand *
IOATABlockStorageDriver::getATACommandObject ( bool blockForCommand )
{
IOATACommand * cmd = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::getATACommandObject entering.\n" ) );
cmd = ( IOATACommand * ) fCommandPool->getCommand ( blockForCommand );
assert ( cmd != NULL );
return cmd;
}
void
IOATABlockStorageDriver::returnATACommandObject ( IOATACommand * cmd )
{
ATAClientData * clientData;
STATUS_LOG ( ( "IOATABlockStorageDriver::returnATACommandObject entering.\n" ) );
assert ( cmd != NULL );
clientData = ( ATAClientData * ) cmd->refCon;
assert ( clientData != NULL );
bzero ( clientData, sizeof ( ATAClientData ) );
cmd->refCon = ( void * ) clientData;
clientData->cmd = cmd;
fCommandPool->returnCommand ( cmd );
}
IOReturn
IOATABlockStorageDriver::identifyAndConfigureATADevice ( void )
{
IOReturn status = kIOReturnSuccess;
IOATABusInfo * busInfoPtr = NULL;
IOATADevConfig * deviceConfigPtr = NULL;
UInt16 tempWord = 0;
UInt16 maxBlocks = 0;
UInt64 maxSize = 0;
busInfoPtr = IOATABusInfo::atabusinfo ( );
if ( busInfoPtr == NULL )
return kIOReturnNoResources;
busInfoPtr->zeroData ( );
status = fATADevice->provideBusInfo ( busInfoPtr );
if ( status != kIOReturnSuccess )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice provide bus info failed thErr = %ld.\n", ( UInt32 ) status ) );
goto ReleaseBusInfoAndBail;
}
fATASocketType = busInfoPtr->getSocketType ( );
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice socket type = %d.\n", ( UInt8 ) fATASocketType ) );
if ( fATASocketType == kPCCardSocket )
{
OSDictionary * dict = OSDictionary::withCapacity ( 2 );
if ( dict != NULL )
{
OSString * identifier = OSString::withCString ( kIOATABlockStorageIdentifierKey );
OSString * resourceFile = OSString::withCString ( kPCCardIconFileKey );
if ( ( identifier != NULL ) && ( resourceFile != NULL ) )
{
dict->setObject ( kCFBundleIdentifierKey, identifier );
dict->setObject ( kIOBundleResourceFileKey, resourceFile );
setProperty ( kIOMediaIconKey, dict );
}
if ( identifier != NULL )
identifier->release ( );
if ( resourceFile != NULL )
resourceFile->release ( );
dict->release ( );
}
}
status = identifyATADevice ( );
if ( status != kIOReturnSuccess )
{
goto ReleaseBusInfoAndBail;
}
tempWord = fDeviceIdentifyData[kATAIdentifyCommandSetSupported];
if ( ( tempWord & kATASupportsSMARTMask ) == kATASupportsSMARTMask )
fSupportedFeatures |= kIOATAFeatureSMART;
if ( ( tempWord & kATASupportsPowerManagementMask ) == kATASupportsPowerManagementMask )
fSupportedFeatures |= kIOATAFeaturePowerManagement;
if ( ( tempWord & kATASupportsWriteCacheMask ) == kATASupportsWriteCacheMask )
fSupportedFeatures |= kIOATAFeatureWriteCache;
tempWord = fDeviceIdentifyData[kATAIdentifyCommandSetSupported2];
if ( ( tempWord & kATADataIsValidMask ) == 0x4000 )
{
if ( ( tempWord & kATASupportsAdvancedPowerManagementMask ) == kATASupportsAdvancedPowerManagementMask )
fSupportedFeatures |= kIOATAFeatureAdvancedPowerManagement;
if ( ( tempWord & kATASupportsCompactFlashMask ) == kATASupportsCompactFlashMask )
fSupportedFeatures |= kIOATAFeatureCompactFlash;
}
if ( fDeviceIdentifyData[kATAIdentifyDriveCapabilities] & kLBASupportedMask )
fUseLBAAddressing = true;
fUseExtendedLBA = busInfoPtr->supportsExtendedLBA ( );
fUseExtendedLBA &= IOATADevConfig::sDriveSupports48BitLBA ( fDeviceIdentifyData );
if ( fUseExtendedLBA )
{
maxBlocks = busInfoPtr->maxBlocksExtended ( );
fSupportedFeatures |= kIOATAFeature48BitLBA;
}
else
{
maxBlocks = kIOATAMaximumBlockCount8Bit;
}
maxSize = ( UInt64 ) maxBlocks * ( UInt64 ) kATADefaultSectorSize;
setProperty ( kIOMaximumBlockCountReadKey, maxBlocks, 64 );
setProperty ( kIOMaximumBlockCountWriteKey, maxBlocks, 64 );
setProperty ( kIOMaximumSegmentCountReadKey, maxSize / PAGE_SIZE, 64 );
setProperty ( kIOMaximumSegmentCountWriteKey, maxSize / PAGE_SIZE, 64 );
deviceConfigPtr = IOATADevConfig::atadevconfig ( );
assert ( deviceConfigPtr != NULL );
status = fATADevice->provideConfig ( deviceConfigPtr );
if ( status != kIOReturnSuccess )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice provideConfig returned an error = %ld.\n", ( UInt32 ) status ) );
goto ReleaseBusInfoAndBail;
}
status = deviceConfigPtr->initWithBestSelection ( fDeviceIdentifyData, busInfoPtr );
if ( status != kIOReturnSuccess )
{
goto ReleaseBusInfoAndBail;
}
status = fATADevice->selectConfig ( deviceConfigPtr );
if ( status != kIOReturnSuccess )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice selectConfig returned error = %ld.\n", ( UInt32 ) status ) );
}
fPIOMode = deviceConfigPtr->getPIOMode ( );
fDMAMode = deviceConfigPtr->getDMAMode ( );
fUltraDMAMode = deviceConfigPtr->getUltraMode ( );
status = configureATADevice ( );
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice configureATADevice returned status = %ld.\n", ( UInt32 ) status ) );
ReleaseBusInfoAndBail:
if ( busInfoPtr != NULL )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice releasing bus info.\n" ) );
busInfoPtr->release ( );
busInfoPtr = NULL;
}
if ( deviceConfigPtr != NULL )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice releasing device config.\n" ) );
deviceConfigPtr->release ( );
deviceConfigPtr = NULL;
}
STATUS_LOG ( ( "IOATABlockStorageDriver::identifyAndConfigureATADevice returning status = %ld.\n", ( UInt32 ) status ) );
return status;
}
IOReturn
IOATABlockStorageDriver::configureATADevice ( void )
{
ATAConfigData * configData;
STATUS_LOG ( ( "IOATABlockStorageDriver::configureATADevice entering.\n" ) );
configData = ( ATAConfigData * ) fConfigurationCommand->refCon;
configData->self = this;
configData->state = kPIOTransferModeSetup;
sATAConfigStateMachine ( fConfigurationCommand );
configData->syncer->reinit ( );
configData->syncer->wait ( false );
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reconfigureATADevice ( void )
{
if ( fConfigurationCommand != NULL )
{
setPIOTransferMode ( true );
setDMATransferMode ( true );
if ( fAPMLevel != 0xFF )
{
setAdvancedPowerManagementLevel ( fAPMLevel, true );
}
ataCommandSetFeatures ( kATAEnableReadAhead,
0,
0,
0,
0,
mATAFlagImmediate,
true );
ataCommandSetFeatures ( kATAEnableWriteCache,
0,
0,
0,
0,
mATAFlagImmediate,
true );
}
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::setPIOTransferMode ( bool forceSync )
{
IOReturn status = kIOReturnSuccess;
UInt8 mode = 0;
STATUS_LOG ( ( "IOATABlockStorageDriver::setPIOTransferMode entering.\n" ) );
mode = sConvertHighestBitToNumber ( fPIOMode );
if ( mode > 4 )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::setPIOTransferMode mode > 4 = %ld.\n", ( UInt32 ) mode ) );
mode = 4;
}
status = ataCommandSetFeatures ( kATASetTransferMode,
( kATAEnablePIOModeMask | mode ),
0,
0,
0,
mATAFlagImmediate,
forceSync );
STATUS_LOG ( ( "IOATABlockStorageDriver::setPIOTransferMode exiting with error = %ld.\n", ( UInt32 ) status ) );
return status;
}
IOReturn
IOATABlockStorageDriver::setDMATransferMode ( bool forceSync )
{
IOReturn status = kIOReturnSuccess;
UInt8 mode = 0;
UInt8 sectorCount = 0;
STATUS_LOG ( ( "IOATABlockStorageDriver::SetDMATransferMode entering.\n" ) );
if ( fUltraDMAMode )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::SetDMATransferMode choosing UltraDMA.\n" ) );
mode = sConvertHighestBitToNumber ( fUltraDMAMode );
if ( mode > 8 )
mode = 8;
sectorCount = ( kATAEnableUltraDMAModeMask | mode );
}
else
{
STATUS_LOG ( ( "IOATABlockStorageDriver::SetDMATransferMode choosing DMA.\n" ) );
mode = sConvertHighestBitToNumber ( fDMAMode );
if ( mode > 2 )
mode = 2;
sectorCount = ( kATAEnableMultiWordDMAModeMask | mode );
}
status = ataCommandSetFeatures ( kATASetTransferMode,
sectorCount,
0,
0,
0,
mATAFlagImmediate,
forceSync );
STATUS_LOG ( ( "IOATABlockStorageDriver::SetDMATransferMode exiting with error = %ld.\n", ( UInt32 ) status ) );
return status;
}
IOReturn
IOATABlockStorageDriver::setAdvancedPowerManagementLevel ( UInt8 level, bool forceSync )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "IOATABlockStorageDriver::setAdvancedPowerManagementLevel entering.\n" ) );
fAPMLevel = level;
if ( ( fSupportedFeatures & kIOATAFeatureAdvancedPowerManagement ) == 0 )
return status;
status = ataCommandSetFeatures ( 0x05,
fAPMLevel,
0,
0,
0,
mATAFlagImmediate,
forceSync );
STATUS_LOG ( ( "IOATABlockStorageDriver::setAdvancedPowerManagementLevel exiting with error = %ld.\n", ( UInt32 ) status ) );
return status;
}
void
IOATABlockStorageDriver::sATAVoidCallback ( IOATACommand * cmd )
{
return;
}
void
IOATABlockStorageDriver::sATAConfigStateMachine ( IOATACommand * cmd )
{
ATAConfigData * configData;
IOATABlockStorageDriver * driver;
STATUS_LOG ( ( "IOATABlockStorageDriver::sATAConfigStateMachine entering\n" ) );
configData = ( ATAConfigData * ) cmd->refCon;
driver = configData->self;
switch ( configData->state )
{
case kPIOTransferModeSetup:
configData->state = kPIOTransferModeDone;
driver->setPIOTransferMode ( false );
break;
case kPIOTransferModeDone:
if ( ( driver->fUltraDMAMode != 0 ) || ( driver->fDMAMode != 0 ) )
{
configData->state = kDMATransferModeDone;
driver->setDMATransferMode ( false );
break;
}
case kDMATransferModeDone:
{
configData->state = kReadAheadEnableDone;
driver->ataCommandSetFeatures ( kATAEnableReadAhead,
0,
0,
0,
0,
mATAFlagImmediate,
false );
}
break;
case kReadAheadEnableDone:
{
configData->state = kWriteCacheEnableDone;
driver->ataCommandSetFeatures ( kATAEnableWriteCache,
0,
0,
0,
0,
mATAFlagImmediate,
false );
}
break;
case kWriteCacheEnableDone:
configData->syncer->signal ( kIOReturnSuccess, false );
break;
default:
PANIC_NOW ( ( "sATAPIConfigStateMachine unexpected state\n" ) );
break;
}
}
IOReturn
IOATABlockStorageDriver::resetATADevice ( void )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "IOATABlockStorageDriver::resetATADevice entering.\n" ) );
SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::resetATADevice executing reset.\n" ) );
if ( fResetInProgress )
return kIOReturnNotPermitted;
fResetInProgress = true;
fResetCommand->zeroCommand ( );
fResetCommand->setUnit ( fATAUnitID );
fResetCommand->setTimeoutMS ( kATATimeout45Seconds );
fResetCommand->setOpcode ( kATAFnBusReset );
fResetCommand->setFlags ( mATAFlagImmediate );
fResetCommand->setCallbackPtr ( &IOATABlockStorageDriver::sHandleReset );
fResetCommand->refCon = ( void * ) this;
status = fATADevice->executeCommand ( fResetCommand );
fResetInProgress = false;
return status;
}
#pragma mark -
#pragma mark Static Routines
void
IOATABlockStorageDriver::sHandleCommandCompletion ( IOATACommand * cmd )
{
ATAClientData * clientData = NULL;
UInt32 result = kATANoErr;
STATUS_LOG ( ( "IOATABlockStorageDriver::sHandleCommandCompletion entering.\n" ) );
assert ( cmd != NULL );
clientData = ( ATAClientData * ) cmd->refCon;
assert ( clientData != NULL );
result = cmd->getResult ( );
switch ( result )
{
case kATANoErr:
STATUS_LOG ( ( "IOATABlockStorageDriver::sHandleCommandCompletion actual xfer = %ld.\n", ( UInt32 ) cmd->getActualTransfer ( ) ) );
clientData->returnCode = kIOReturnSuccess;
break;
case kATATimeoutErr:
case kATAErrDevBusy:
clientData->self->resetATADevice ( );
case kATADeviceError:
ERROR_LOG ( ( "IOATABlockStorageDriver::sHandleCommandCompletion result = %ld.\n", result ) );
if ( clientData->maxRetries > 0 )
{
sReissueCommandFromClientData ( cmd );
return;
}
break;
default:
break;
}
clientData->self->fNumCommandsOutstanding--;
if ( clientData->isSync )
{
clientData->returnCode = result;
assert ( clientData->completion.syncLock );
clientData->completion.syncLock->signal ( );
}
else
{
IOStorage::complete ( clientData->completion.async,
result,
( UInt64 ) cmd->getActualTransfer ( ) );
clientData->self->returnATACommandObject ( cmd );
}
STATUS_LOG ( ( "IOATABlockStorageDriver::sHandleCommandCompletion exiting.\n" ) );
}
void
IOATABlockStorageDriver::sHandleSimpleSyncTransaction ( IOATACommand * cmd )
{
IOReturn status;
IOSyncer * syncer;
syncer = ( IOSyncer * ) cmd->refCon;
status = cmd->getResult ( );
syncer->signal ( status, false );
}
void
IOATABlockStorageDriver::sHandleReset ( IOATACommand * cmd )
{
IOATABlockStorageDriver * self;
if ( cmd->getResult ( ) == kATANoErr )
{
self = ( IOATABlockStorageDriver * ) cmd->refCon;
self->fWakeUpResetOccurred = true;
}
}
void
IOATABlockStorageDriver::sConvertBlockToCHSAddress ( IOATACommand * cmd,
UInt32 block,
UInt32 heads,
UInt32 sectors,
ataUnitID unitID )
{
ATAClientData * clientData;
clientData = ( ATAClientData * ) cmd->refCon;
UInt16 startingCylinder = block / ( sectors * heads );
UInt16 whichHead = ( block / sectors ) % heads;
cmd->setSectorNumber ( ( block % sectors ) + 1 ); cmd->setCylLo ( ( UInt8 ) startingCylinder );
cmd->setCylHi ( ( UInt8 ) ( startingCylinder >> 8 ) );
cmd->setDevice_Head ( ( ( ( UInt8 ) unitID ) << 4 ) | ( whichHead & mATAHeadNumber ) );
clientData->sectorNumber = ( block % sectors ) + 1;
clientData->cylLow = ( UInt8 ) startingCylinder;
clientData->cylHigh = ( UInt8 ) ( startingCylinder >> 8 );
}
void
IOATABlockStorageDriver::sReissueCommandFromClientData ( IOATACommand * cmd )
{
ATAClientData * clientData;
clientData = ( ATAClientData * ) cmd->refCon;
if ( clientData == NULL )
{
PANIC_NOW ( ( "No client data associated with this command.\n" ) );
return;
}
clientData->maxRetries--;
cmd->zeroCommand ( );
cmd->setOpcode ( clientData->opCode );
cmd->setFlags ( clientData->flags );
cmd->setUnit ( clientData->self->fATAUnitID );
cmd->setTimeoutMS ( clientData->timeout );
cmd->setCallbackPtr ( &IOATABlockStorageDriver::sHandleCommandCompletion );
cmd->setRegMask ( clientData->regMask );
cmd->setBuffer ( clientData->buffer );
cmd->setPosition ( clientData->bufferOffset );
cmd->setByteCount ( clientData->numberOfBlocks * kATADefaultSectorSize );
cmd->setTransferChunkSize ( kATADefaultSectorSize );
cmd->setFeatures ( clientData->featuresReg );
cmd->setSectorCount ( clientData->sectorCount );
cmd->setSectorNumber ( clientData->sectorNumber );
cmd->setCylLo ( clientData->cylLow );
cmd->setCylHi ( clientData->cylHigh );
cmd->setDevice_Head ( clientData->sdhReg );
cmd->setCommand ( clientData->command );
if ( clientData->useExtendedLBA )
{
IOExtendedLBA * extLBA = cmd->getExtendedLBA ( );
extLBA->setLBALow16 ( clientData->lbaLow16 );
extLBA->setLBAMid16 ( clientData->lbaMid16 );
extLBA->setLBAHigh16 ( clientData->lbaHigh16 );
extLBA->setSectorCount16 ( clientData->sectorCount16 );
extLBA->setFeatures16 ( clientData->features16 );
extLBA->setDevice ( clientData->device );
extLBA->setCommand ( clientData->command16 );
}
clientData->self->fATADevice->executeCommand ( cmd );
STATUS_LOG ( ( "%ssReissueCommandFromClientData%s\n", "\033[33m", "\033[0m" ) );
}
void
IOATABlockStorageDriver::sSetCommandBuffers ( IOATACommand * cmd,
IOMemoryDescriptor * buffer,
IOByteCount offset,
IOByteCount numBlocks )
{
ATAClientData * clientData;
clientData = ( ATAClientData * ) cmd->refCon;
cmd->setBuffer ( buffer );
cmd->setPosition ( offset );
cmd->setByteCount ( numBlocks * kATADefaultSectorSize );
cmd->setTransferChunkSize ( kATADefaultSectorSize );
clientData->buffer = buffer;
clientData->bufferOffset = offset;
clientData->numberOfBlocks = numBlocks;
}
void
IOATABlockStorageDriver::sSaveStateData ( IOATACommand * cmd )
{
ATAClientData * clientData;
clientData = ( ATAClientData * ) cmd->refCon;
clientData->sectorCount = cmd->getSectorCount ( );
clientData->sectorNumber = cmd->getSectorNumber ( );
clientData->cylHigh = cmd->getCylHi ( );
clientData->cylLow = cmd->getCylLo ( );
clientData->sdhReg = cmd->getDevice_Head ( );
}
IOReturn
IOATABlockStorageDriver::sValidateIdentifyData ( UInt8 * deviceIdentifyData )
{
IOReturn status = kIOReturnSuccess;
UInt8 checkSum = 0;
UInt32 index = 0;
UInt16 offset = kATAIdentifyIntegrity * sizeof ( UInt16 );
if ( deviceIdentifyData[offset] == kChecksumValidCookie )
{
for ( index = 0; index < 512; index++ )
checkSum += deviceIdentifyData[index];
if ( checkSum != 0 )
{
IOLog ( "Identify data is incorrect - bad checksum\n" );
}
}
return status;
}