IOATABlockStorageDriver.cpp [plain text]
#include <IOKit/assert.h>
#include "IOATABlockStorageDriver.h"
#include "IOATABlockStorageDevice.h"
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOKitKeys.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 super IOService
OSDefineMetaClassAndStructors ( IOATABlockStorageDriver, IOService );
#pragma mark Public Methods
bool
IOATABlockStorageDriver::init ( OSDictionary * properties )
{
if ( super::init ( properties ) == false )
{
return false;
}
return true;
}
bool
IOATABlockStorageDriver::start ( IOService * provider )
{
IOReturn theErr = kIOReturnSuccess;
IOWorkLoop * workLoop = NULL;
OSNumber * numCommandObjects = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::start entering.\n" ) );
fATADevice = NULL;
fCommandPool = NULL;
fATAUnitID = kATAInvalidDeviceID;
fATADeviceType = kUnknownATADeviceType;
fATASocketType = kUnknownSocket;
fAPMLevel = 0xFF;
if ( super::start ( provider ) == false )
return false;
fATADevice = OSDynamicCast ( IOATADevice, provider );
if ( fATADevice == NULL )
return false;
if ( fATADevice->getDeviceType ( ) != reportATADeviceType ( ) )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::start exiting, not an ATA device.\n" ) );
return false;
}
reserved = ( ExpansionData * ) IOMalloc ( sizeof ( ExpansionData ) );
bzero ( reserved, sizeof ( ExpansionData ) );
STATUS_LOG ( ( "IOATABlockStorageDriver::start opening device.\n" ) );
if ( fATADevice->open ( this ) == false )
return false;
fATAUnitID = fATADevice->getUnitID ( );
fATADeviceType = fATADevice->getDeviceType ( );
STATUS_LOG ( ( "IOATABlockStorageDriver::start fATAUnitID = %d.\n", ( UInt8 ) fATAUnitID ) );
STATUS_LOG ( ( "IOATABlockStorageDriver::start fATADeviceType is %d\n", ( UInt8 ) fATADeviceType ) );
bzero ( fDeviceIdentifyData, 512 );
fDeviceIdentifyBuffer = IOMemoryDescriptor::withAddress ( ( void * ) fDeviceIdentifyData,
512,
kIODirectionIn );
assert ( fDeviceIdentifyBuffer != NULL );
numCommandObjects = OSDynamicCast ( OSNumber, getProperty ( "IOCommandPoolSize" ) );
fNumCommandObjects = numCommandObjects->unsigned32BitValue ( );
STATUS_LOG ( ( "IOATABlockStorageDriver::start fNumCommandObjects = %ld\n", fNumCommandObjects ) );
fCommandGate = IOCommandGate::commandGate ( this );
assert ( fCommandGate != NULL );
workLoop = getWorkLoop ( );
assert ( workLoop != NULL );
theErr = workLoop->addEventSource ( fCommandGate );
assert ( theErr == kIOReturnSuccess );
fCommandPool = IOCommandPool::commandPool ( this, workLoop, fNumCommandObjects );
assert ( fCommandPool != NULL );
allocateATACommandObjects ( );
if ( inspectDevice ( fATADevice ) == false )
return false;
fCurrentPowerState = kIOATAPowerStateActive;
fProposedPowerState = kIOATAPowerStateActive;
fNumCommandsOutstanding = 0;
fPowerTransitionInProgress = false;
fPowerManagementThread = thread_call_allocate (
( thread_call_func_t ) IOATABlockStorageDriver::sPowerManagement,
( thread_call_param_t ) this );
if ( fPowerManagementThread == NULL )
{
ERROR_LOG ( ( "thread allocation failed.\n" ) );
return false;
}
PMinit ( ); provider->joinPMtree ( this ); setIdleTimerPeriod ( k5Minutes ); makeUsable ( );
fPowerManagementInitialized = true;
if ( fSupportedFeatures & kIOATAFeaturePowerManagement )
initForPM ( );
return ( createNub ( provider ) );
}
bool
IOATABlockStorageDriver::finalize ( IOOptionBits options )
{
if ( fPowerManagementInitialized )
{
while ( fPowerTransitionInProgress )
{
IOSleep ( 1 );
}
fCommandGate->commandWakeup ( &fCurrentPowerState, false );
PMstop ( );
if ( fPowerManagementThread != NULL )
{
thread_call_cancel ( fPowerManagementThread );
}
fPowerManagementInitialized = false;
}
return super::finalize ( options );
}
void
IOATABlockStorageDriver::stop ( IOService * provider )
{
super::stop ( provider );
}
#pragma mark -
#pragma mark Protected Methods
void
IOATABlockStorageDriver::free ( void )
{
IOWorkLoop * workLoop;
if ( fCommandPool != NULL )
{
deallocateATACommandObjects ( );
fCommandPool->release ( );
fCommandPool = NULL;
}
if ( fCommandGate != NULL )
{
workLoop = getWorkLoop ( );
if ( workLoop != NULL )
{
workLoop->removeEventSource ( fCommandGate );
}
fCommandGate->release ( );
fCommandGate = NULL;
}
if ( fPowerManagementThread != NULL )
{
thread_call_free ( fPowerManagementThread );
}
if ( reserved != NULL )
{
IOFree ( reserved, sizeof ( ExpansionData ) );
reserved = NULL;
}
if ( fDeviceIdentifyBuffer != NULL )
{
fDeviceIdentifyBuffer->release ( );
fDeviceIdentifyBuffer = NULL;
}
super::free ( );
}
bool
IOATABlockStorageDriver::inspectDevice ( IOATADevice * ataDevice )
{
OSString * string = NULL;
IOReturn theErr = kIOReturnSuccess;
string = OSDynamicCast ( OSString,
ataDevice->getProperty ( kATAVendorPropertyKey ) );
if ( string != NULL )
{
strncpy ( fModel, string->getCStringNoCopy ( ), kSizeOfATAModelString );
fModel[kSizeOfATAModelString] = '\0';
}
string = OSDynamicCast ( OSString,
ataDevice->getProperty ( kATARevisionPropertyKey ) );
if ( string != NULL )
{
strncpy ( fRevision, string->getCStringNoCopy ( ), kSizeOfATARevisionString );
fRevision[kSizeOfATARevisionString] = '\0';
}
theErr = identifyAndConfigureATADevice ( );
if ( theErr != kIOReturnSuccess )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::inspectDevice theErr = %ld\n", ( UInt32 ) theErr ) );
return false;
}
setProperty ( kIOATASupportedFeaturesKey,
fSupportedFeatures,
sizeof ( fSupportedFeatures ) * 8 );
return true;
}
ataDeviceType
IOATABlockStorageDriver::reportATADeviceType ( void ) const
{
return kATADeviceType;
}
const char *
IOATABlockStorageDriver::getDeviceTypeName ( void )
{
return kIOBlockStorageDeviceTypeGeneric;
}
IOService *
IOATABlockStorageDriver::instantiateNub ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::instantiateNub entering.\n" ) );
IOService * nub = new IOATABlockStorageDevice;
STATUS_LOG ( ( "IOATABlockStorageDriver::instantiateNub exiting nub = %p.\n", nub ) );
return nub;
}
bool
IOATABlockStorageDriver::createNub ( IOService * provider )
{
IOService * nub = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::createNub entering.\n" ) );
nub = instantiateNub ( );
if ( nub == NULL )
{
ERROR_LOG ( ( "IOATABlockStorageDriver::createNub instantiateNub() failed, returning false\n" ) );
return false;
}
nub->init ( );
if ( !nub->attach ( this ) )
{
PANIC_NOW ( ( "IOATABlockStorageDriver::createNub() unable to attach nub" ) );
return false;
}
nub->registerService ( );
nub->release ( );
STATUS_LOG ( ( "IOATABlockStorageDriver::createNub exiting true.\n" ) );
return true;
}
IOReturn
IOATABlockStorageDriver::doAsyncReadWrite (
IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
IOStorageCompletion completion )
{
IOReturn ret;
IOATACommand * cmd = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::doAsyncReadWrite entering.\n" ) );
cmd = ataCommandReadWrite ( buffer, block, nblks );
if ( cmd == NULL )
{
return kIOReturnNoMemory;
}
ret = asyncExecute ( cmd, completion );
STATUS_LOG ( ( "IOATABlockStorageDriver::doAsyncReadWrite exiting ret = %ld.\n", ( UInt32 ) ret ) );
return ret;
}
IOReturn
IOATABlockStorageDriver::doSyncReadWrite (
IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks )
{
IOReturn ret;
IOATACommand * cmd = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::doSyncReadWrite entering\n" ) );
cmd = ataCommandReadWrite ( buffer, block, nblks );
if ( cmd == NULL )
{
return kIOReturnNoMemory;
}
ret = syncExecute ( cmd );
STATUS_LOG ( ( "IOATABlockStorageDriver::doSyncReadWrite exiting ret = %ld.\n", ( UInt32 ) ret ) );
return ret;
}
IOReturn
IOATABlockStorageDriver::doEjectMedia ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::doEjectMedia called.\n" ) );
return kIOReturnUnsupported;
}
IOReturn
IOATABlockStorageDriver::doFormatMedia ( UInt64 byteCapacity )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::doFormatMedia called.\n" ) );
return kIOReturnUnsupported;
}
UInt32
IOATABlockStorageDriver::doGetFormatCapacities ( UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
if ( ( capacities != NULL ) && ( capacitiesMaxCount > 0 ) )
{
if ( fUseExtendedLBA )
{
UInt32 hiLBA = 0;
UInt32 loLBA = 0;
IOATADevConfig::sDriveExtendedLBASize ( &hiLBA, &loLBA, fDeviceIdentifyData );
*capacities = ( ( UInt64 ) hiLBA ) << 32 | loLBA;
}
else if ( fUseLBAAddressing )
{
*capacities = ( fDeviceIdentifyData[kATAIdentifyLBACapacity + 1] << 16 ) +
( UInt32 ) fDeviceIdentifyData[kATAIdentifyLBACapacity];
}
else
{
*capacities = fDeviceIdentifyData[kATAIdentifySectorsPerTrack] *
fDeviceIdentifyData[kATAIdentifyLogicalHeadCount] *
fDeviceIdentifyData[kATAIdentifyLogicalCylinderCount];
}
*capacities *= kATADefaultSectorSize;
return 1;
}
return 0;
}
IOReturn
IOATABlockStorageDriver::doLockUnlockMedia ( bool doLock )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::doLockUnlockMedia called.\n" ) );
return kIOReturnUnsupported;
}
IOReturn
IOATABlockStorageDriver::doSynchronizeCache ( void )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * cmd = NULL;
STATUS_LOG ( ( "IOATABlockStorageDriver::doSynchronizeCache called.\n" ) );
if ( fATASocketType == kPCCardSocket )
{
fNumCommandsOutstanding--;
status = kIOReturnSuccess;
goto Exit;
}
cmd = ataCommandFlushCache ( );
if ( cmd == NULL )
{
fNumCommandsOutstanding--;
status = kIOReturnNoMemory;
goto Exit;
}
status = syncExecute ( cmd, kATATimeout1Minute, 0 );
Exit:
STATUS_LOG ( ( "IOATABlockStorageDriver::doSynchronizeCache returning status = %ld.\n", ( UInt32 ) status ) );
return status;
}
IOReturn
IOATABlockStorageDriver::doStart ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::doStart called.\n" ) );
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::doStop ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::doStop called.\n" ) );
return kIOReturnSuccess;
}
char *
IOATABlockStorageDriver::getAdditionalDeviceInfoString ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::getAdditionalDeviceInfoString called.\n" ) );
return ( "[ATA]" );
}
char *
IOATABlockStorageDriver::getProductString ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::getProductString called.\n" ) );
return fModel;
}
char *
IOATABlockStorageDriver::getRevisionString ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::getRevisionString called.\n" ) );
return fRevision;
}
char *
IOATABlockStorageDriver::getVendorString ( void )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::getVendorString called.\n" ) );
return NULL;
}
IOReturn
IOATABlockStorageDriver::reportBlockSize ( UInt64 * blockSize )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::reportBlockSize called.\n" ) );
*blockSize = kATADefaultSectorSize;
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportEjectability ( bool * isEjectable )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::reportEjectability called.\n" ) );
*isEjectable = false;
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportLockability ( bool * isLockable )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::reportLockability called.\n" ) );
*isLockable = false;
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportPollRequirements ( bool * pollRequired,
bool * pollIsExpensive )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::reportPollRequirements called.\n" ) );
*pollIsExpensive = false;
*pollRequired = false;
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportMaxReadTransfer ( UInt64 blocksize, UInt64 * max )
{
OSNumber * size;
STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxReadTransfer called.\n" ) );
*max = blocksize * kIOATAMaximumBlockCount8Bit;
size = OSDynamicCast ( OSNumber, getProperty ( kIOMaximumBlockCountReadKey ) );
if ( size != NULL )
{
*max = size->unsigned64BitValue ( ) * blocksize;
}
STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxReadTransfer max = %ld.\n", *max ) );
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportMaxWriteTransfer ( UInt64 blocksize, UInt64 * max )
{
OSNumber * size;
STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxWriteTransfer called.\n" ) );
*max = blocksize * kIOATAMaximumBlockCount8Bit;
size = OSDynamicCast ( OSNumber, getProperty ( kIOMaximumBlockCountWriteKey ) );
if ( size != NULL )
{
*max = size->unsigned64BitValue ( ) * blocksize;
}
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportMaxValidBlock ( UInt64 * maxBlock )
{
UInt64 diskCapacity = 0;
assert ( fATADevice && maxBlock );
STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxValidBlock called.\n" ) );
doGetFormatCapacities ( &diskCapacity, 1 );
*maxBlock = ( diskCapacity / kATADefaultSectorSize ) - 1;
STATUS_LOG ( ( "IOATABlockStorageDriver::reportMaxValidBlock maxBlock = %ld.\n", *maxBlock ) );
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportMediaState ( bool * mediaPresent, bool * changed )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::reportMediaState called.\n" ) );
*mediaPresent = true;
*changed = true;
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportRemovability ( bool * isRemovable )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::reportRemovability called.\n" ) );
*isRemovable = false;
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::reportWriteProtection ( bool * isWriteProtected )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::reportWriteProtection called.\n" ) );
*isWriteProtected = false;
return kIOReturnSuccess;
}
IOReturn
IOATABlockStorageDriver::sendSMARTCommand ( IOATACommand * command )
{
IOReturn status = kIOReturnSuccess;
if ( activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive ) )
{
command->setUnit ( fATAUnitID );
command->setDevice_Head ( fATAUnitID << 4 );
status = fATADevice->executeCommand ( command );
if ( status == kATANoErr )
status = kIOReturnSuccess;
else
status = kIOReturnIOError;
}
else
{
status = kIOReturnNotResponding;
}
return status;
}
IOReturn
IOATABlockStorageDriver::message ( UInt32 type, IOService * provider, void * argument )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "IOATABlockStorageDriver::message %p %lx\n", this, type ) );
switch ( type )
{
case kATAResetEvent: SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::message reset happened\n" ) );
fWakeUpResetOccurred = true;
status = reconfigureATADevice ( );
break;
case kATANullEvent:
case kATAOnlineEvent: case kATAOfflineEvent: case kATARemovedEvent:
case kATAOfflineRequest: case kATAEjectRequest:
case kATAPIResetEvent: break;
case kIOMessageServiceIsRequestingClose:
{
STATUS_LOG ( ("%s: kIOMessageServiceIsRequestingClose Received\n", getName( ) ) );
terminate ( kIOServiceRequired );
fATADevice->close ( this );
status = kIOReturnSuccess;
}
break;
default:
status = super::message ( type, provider, argument );
break;
}
return status;
}
#pragma mark -
#pragma mark Static Functions
void
IOATABlockStorageDriver::sSwapBytes16 ( UInt8 * buffer, IOByteCount numBytesToSwap )
{
IOByteCount index;
UInt8 temp;
UInt8 * firstBytePtr;
STATUS_LOG ( ( "IOATABlockStorageDriver::swapBytes16 called.\n" ) );
for ( index = 0; index < numBytesToSwap; index += 2 )
{
firstBytePtr = buffer; temp = *buffer++; *firstBytePtr = *buffer; *buffer++ = temp;
}
}
UInt8
IOATABlockStorageDriver::sConvertHighestBitToNumber ( UInt16 bitField )
{
STATUS_LOG ( ( "IOATABlockStorageDriver::convertHighestBitToNumber called.\n" ) );
UInt16 index, integer;
for ( index = 0x0080, integer = 7; ( ( index & bitField ) == 0 && index != 0 ) ; index >>= 1, integer-- )
{ ; }
return integer;
}
OSMetaClassDefineReservedUsed ( IOATABlockStorageDriver, 1 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 2 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 3 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 4 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 5 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 6 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 7 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 8 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 9 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 10 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 11 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 12 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 13 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 14 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 15 );
OSMetaClassDefineReservedUnused ( IOATABlockStorageDriver, 16 );