ATASMARTUserClient.cpp [plain text]
#include "ATASMARTUserClient.h"
#include "ATASMARTLib.h"
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/ata/IOATADevice.h>
#include <IOKit/ata/IOATATypes.h>
#include <IOKit/ata/IOATACommand.h>
#include "IOATABlockStorageDevice.h"
#define ATA_SMART_USER_CLIENT_DEBUGGING_LEVEL 0
#if ( ATA_SMART_USER_CLIENT_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( ATA_SMART_USER_CLIENT_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( ATA_SMART_USER_CLIENT_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define super IOUserClient
OSDefineMetaClassAndStructors ( ATASMARTUserClient, IOUserClient );
#if 0
#pragma mark -
#pragma mark Constants
#endif
enum
{
kATAcmdSMART = 0xB0
};
enum
{
kFeaturesRegisterReadData = 0xD0,
kFeaturesRegisterReadDataThresholds = 0xD1,
kFeaturesRegisterEnableDisableAutoSave = 0xD2,
kFeaturesRegisterExecuteOfflineImmed = 0xD4,
kFeaturesRegisterReadLogAtAddress = 0xD5,
kFeaturesRegisterWriteLogAtAddress = 0xD6,
kFeaturesRegisterEnableOperations = 0xD8,
kFeaturesRegisterDisableOperations = 0xD9,
kFeaturesRegisterReturnStatus = 0xDA
};
enum
{
kSMARTMagicCylinderLoValue = 0x4F,
kSMARTMagicCylinderHiValue = 0xC2
};
enum
{
kSMARTReturnStatusValidLoValue = 0xF4,
kSMARTReturnStatusValidHiValue = 0x2C
};
enum
{
kSMARTAutoSaveEnable = 0xF1,
kSMARTAutoSaveDisable = 0x00
};
enum
{
kATAThirtySecondTimeoutInMS = 30000
};
IOExternalMethod
ATASMARTUserClient::sMethods[kIOATASMARTMethodCount] =
{
{
0,
( IOMethod ) &ATASMARTUserClient::EnableDisableOperations,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &ATASMARTUserClient::EnableDisableAutoSave,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &ATASMARTUserClient::ReturnStatus,
kIOUCScalarIScalarO,
0,
1
},
{
0,
( IOMethod ) &ATASMARTUserClient::ExecuteOfflineImmediate,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &ATASMARTUserClient::ReadData,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &ATASMARTUserClient::ReadDataThresholds,
kIOUCScalarIScalarO,
1,
0
},
{
0,
( IOMethod ) &ATASMARTUserClient::ReadLogAtAddress,
kIOUCScalarIStructI,
0,
sizeof ( ATASMARTReadLogStruct )
},
{
0,
( IOMethod ) &ATASMARTUserClient::WriteLogAtAddress,
kIOUCScalarIStructI,
0,
sizeof ( ATASMARTWriteLogStruct )
}
};
#if 0
#pragma mark -
#pragma mark Public Methods
#pragma mark -
#endif
bool
ATASMARTUserClient::init ( OSDictionary * dictionary )
{
STATUS_LOG ( ( "ATASMARTUserClient::init\n" ) );
if ( !super::init ( dictionary ) )
return false;
fTask = NULL;
fProvider = NULL;
fOutstandingCommands = 0;
return true;
}
bool
ATASMARTUserClient::start ( IOService * provider )
{
IOWorkLoop * workLoop;
STATUS_LOG ( ( "ATASMARTUserClient::start\n" ) );
if ( fProvider != NULL )
{
ERROR_LOG ( ( "fProvider != NULL, returning false\n" ) );
return false;
}
STATUS_LOG ( ( "assigning fProvider\n" ) );
fProvider = OSDynamicCast ( IOATABlockStorageDevice, provider );
if ( fProvider == NULL )
{
ERROR_LOG ( ( "Provider not IOATABlockStorageDevice\n" ) );
return false;
}
if ( !super::start ( provider ) )
{
ERROR_LOG ( ( "super rejected provider in start\n" ) );
return false;
}
STATUS_LOG ( ( "Creating command gate\n" ) );
fCommandGate = IOCommandGate::commandGate ( this );
if ( fCommandGate == NULL )
{
ERROR_LOG ( ( "Command gate creation failed\n" ) );
return false;
}
workLoop = getWorkLoop ( );
if ( workLoop == NULL )
{
ERROR_LOG ( ( "workLoop == NULL\n" ) );
fCommandGate->release ( );
fCommandGate = NULL;
}
STATUS_LOG ( ( "Adding command gate\n" ) );
workLoop->addEventSource ( fCommandGate );
STATUS_LOG ( ( "Opening provider\n" ) );
if ( !fProvider->open ( this, kIOATASMARTUserClientAccessMask, 0 ) )
{
ERROR_LOG ( ( "Open failed\n" ) );
fCommandGate->release ( );
fCommandGate = NULL;
return false;
}
STATUS_LOG ( ( "start done\n" ) );
return true;
}
bool
ATASMARTUserClient::initWithTask ( task_t owningTask,
void * securityToken,
UInt32 type )
{
STATUS_LOG ( ( "ATASMARTUserClient::initWithTask called\n" ) );
if ( type != kIOATASMARTLibConnection )
return false;
fTask = owningTask;
return true;
}
IOReturn
ATASMARTUserClient::clientClose ( void )
{
STATUS_LOG ( ( "clientClose called\n" ) );
HandleTerminate ( fProvider );
STATUS_LOG ( ( "Done\n" ) );
return kIOReturnSuccess;
}
IOReturn
ATASMARTUserClient::clientDied ( void )
{
STATUS_LOG ( ( "ATASMARTUserClient::clientDied called\n" ) );
if ( isInactive ( ) == false )
{
return clientClose ( );
}
return kIOReturnSuccess;
}
void
ATASMARTUserClient::free ( void )
{
if ( fCommandGate != NULL )
{
fCommandGate->release ( );
fCommandGate = NULL;
}
}
IOReturn
ATASMARTUserClient::message ( UInt32 type, IOService * provider, void * arg )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( "message called\n" ) );
STATUS_LOG ( ( "type = %ld, provider = %p\n", type, provider ) );
switch ( type )
{
case kIOMessageServiceIsRequestingClose:
break;
case kIOMessageServiceIsTerminated:
STATUS_LOG ( ( "kIOMessageServiceIsTerminated called\n" ) );
status = HandleTerminate ( provider );
break;
default:
status = super::message ( type, provider, arg );
break;
}
return status;
}
IOReturn
ATASMARTUserClient::EnableDisableOperations ( UInt32 enable )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command;
STATUS_LOG ( ( "EnableDisableOperations called\n" ) );
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
if ( enable == 0 )
{
command->setFeatures ( kFeaturesRegisterDisableOperations );
}
else
{
command->setFeatures ( kFeaturesRegisterEnableOperations );
}
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setCylLo ( kSMARTMagicCylinderLoValue );
command->setCylHi ( kSMARTMagicCylinderHiValue );
command->setCommand ( kATAcmdSMART );
status = SendSMARTCommand ( command );
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "Enable/Disable unsupported\n" ) );
status = kIOReturnUnsupported;
}
}
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
IOReturn
ATASMARTUserClient::EnableDisableAutoSave ( UInt32 enable )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command;
STATUS_LOG ( ( "EnableDisableAutoSave called\n" ) );
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
if ( enable == 0 )
{
command->setSectorCount ( kSMARTAutoSaveDisable );
}
else
{
command->setSectorCount ( kSMARTAutoSaveEnable );
}
command->setFeatures ( kFeaturesRegisterEnableDisableAutoSave );
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setCylLo ( kSMARTMagicCylinderLoValue );
command->setCylHi ( kSMARTMagicCylinderHiValue );
command->setCommand ( kATAcmdSMART );
status = SendSMARTCommand ( command );
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "Enable/Disable autosave unsupported\n" ) );
status = kIOReturnUnsupported;
}
}
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
IOReturn
ATASMARTUserClient::ReturnStatus ( UInt32 * exceededCondition )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command = NULL;
UInt8 lbaMid = kSMARTMagicCylinderLoValue;
UInt8 lbaHigh = kSMARTMagicCylinderHiValue;
STATUS_LOG ( ( "ReturnStatus called\n" ) );
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
command->setFeatures ( kFeaturesRegisterReturnStatus );
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setCylLo ( lbaMid );
command->setCylHi ( lbaHigh );
command->setCommand ( kATAcmdSMART );
command->setRegMask ( ( ataRegMask ) ( mATACylinderHiValid | mATACylinderLoValid ) );
command->setFlags ( mATAFlagTFAccessResult );
status = SendSMARTCommand ( command );
lbaMid = command->getCylLo ( );
lbaHigh = command->getCylHi ( );
if ( status == kIOReturnSuccess )
{
if ( ( lbaMid == kSMARTReturnStatusValidLoValue ) &&
( lbaHigh == kSMARTReturnStatusValidHiValue ) )
{
*exceededCondition = 1;
}
else
{
*exceededCondition = 0;
}
}
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "Return Status unsupported\n" ) );
status = kIOReturnUnsupported;
}
}
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
IOReturn
ATASMARTUserClient::ExecuteOfflineImmediate ( UInt32 extendedTest )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command = NULL;
STATUS_LOG ( ( "ExecuteOfflineImmediate called\n" ) );
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
command->setFeatures ( kFeaturesRegisterExecuteOfflineImmed );
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setSectorNumber ( ( extendedTest == 0 ) ? 0x01 : 0x02 );
command->setCylLo ( kSMARTMagicCylinderLoValue );
command->setCylHi ( kSMARTMagicCylinderHiValue );
command->setCommand ( kATAcmdSMART );
status = SendSMARTCommand ( command );
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "Execute Offline Immediate unsupported\n" ) );
status = kIOReturnUnsupported;
}
}
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
IOReturn
ATASMARTUserClient::ReadData ( vm_address_t data )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command = NULL;
IOMemoryDescriptor * buffer = NULL;
STATUS_LOG ( ( "ReadData called\n" ) );
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
buffer = IOMemoryDescriptor::withAddress ( data,
sizeof ( ATASMARTData ),
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
status = kIOReturnNoResources;
goto ReleaseCommand;
}
status = buffer->prepare ( );
if ( status != kIOReturnSuccess )
{
goto ReleaseBuffer;
}
command->setBuffer ( buffer );
command->setByteCount ( sizeof ( ATASMARTData ) );
command->setFeatures ( kFeaturesRegisterReadData );
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setCylLo ( kSMARTMagicCylinderLoValue );
command->setCylHi ( kSMARTMagicCylinderHiValue );
command->setCommand ( kATAcmdSMART );
command->setFlags ( mATAFlagIORead );
status = SendSMARTCommand ( command );
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "ReadData unsupported\n" ) );
status = kIOReturnUnsupported;
}
if ( command->getEndErrorReg ( ) & 0x10 )
{
ERROR_LOG ( ( "ReadData Not readable\n" ) );
status = kIOReturnNotReadable;
}
}
buffer->complete ( );
ReleaseBuffer:
buffer->release ( );
buffer = NULL;
ReleaseCommand:
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
IOReturn
ATASMARTUserClient::ReadDataThresholds ( vm_address_t data )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command = NULL;
IOMemoryDescriptor * buffer = NULL;
STATUS_LOG ( ( "ReadDataThresholds called\n" ) );
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
buffer = IOMemoryDescriptor::withAddress ( data,
sizeof ( ATASMARTDataThresholds ),
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
status = kIOReturnNoResources;
goto ReleaseCommand;
}
status = buffer->prepare ( );
if ( status != kIOReturnSuccess )
{
goto ReleaseBuffer;
}
command->setBuffer ( buffer );
command->setByteCount ( sizeof ( ATASMARTDataThresholds ) );
command->setFeatures ( kFeaturesRegisterReadDataThresholds );
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setCylLo ( kSMARTMagicCylinderLoValue );
command->setCylHi ( kSMARTMagicCylinderHiValue );
command->setCommand ( kATAcmdSMART );
command->setFlags ( mATAFlagIORead );
status = SendSMARTCommand ( command );
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "ReadDataThresholds unsupported\n" ) );
status = kIOReturnUnsupported;
}
if ( command->getEndErrorReg ( ) & 0x10 )
{
ERROR_LOG ( ( "ReadDataThresholds Not readable\n" ) );
status = kIOReturnNotReadable;
}
}
buffer->complete ( );
ReleaseBuffer:
buffer->release ( );
buffer = NULL;
ReleaseCommand:
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
IOReturn
ATASMARTUserClient::ReadLogAtAddress ( ATASMARTReadLogStruct * readLogData,
UInt32 inStructSize )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command = NULL;
IOMemoryDescriptor * buffer = NULL;
STATUS_LOG ( ( "ReadLogAtAddress called\n" ) );
if ( inStructSize != sizeof ( ATASMARTReadLogStruct ) )
return kIOReturnBadArgument;
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
buffer = IOMemoryDescriptor::withAddress ( ( vm_address_t ) readLogData->buffer,
readLogData->bufferSize,
kIODirectionIn,
fTask );
if ( buffer == NULL )
{
status = kIOReturnNoResources;
goto ReleaseCommand;
}
status = buffer->prepare ( );
if ( status != kIOReturnSuccess )
{
goto ReleaseBuffer;
}
command->setBuffer ( buffer );
command->setByteCount ( readLogData->bufferSize );
command->setFeatures ( kFeaturesRegisterReadLogAtAddress );
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setSectorCount ( readLogData->numSectors );
command->setSectorNumber ( readLogData->logAddress );
command->setCylLo ( kSMARTMagicCylinderLoValue );
command->setCylHi ( kSMARTMagicCylinderHiValue );
command->setCommand ( kATAcmdSMART );
command->setFlags ( mATAFlagIORead );
status = SendSMARTCommand ( command );
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "ReadLogAtAddress %d unsupported\n", readLogData->logAddress ) );
status = kIOReturnUnsupported;
}
if ( command->getEndErrorReg ( ) & 0x10 )
{
ERROR_LOG ( ( "ReadLogAtAddress %d unreadable\n", readLogData->logAddress ) );
status = kIOReturnNotReadable;
}
}
buffer->complete ( );
ReleaseBuffer:
buffer->release ( );
buffer = NULL;
ReleaseCommand:
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
IOReturn
ATASMARTUserClient::WriteLogAtAddress ( ATASMARTWriteLogStruct * writeLogData,
UInt32 inStructSize )
{
IOReturn status = kIOReturnSuccess;
IOATACommand * command = NULL;
IOMemoryDescriptor * buffer = NULL;
STATUS_LOG ( ( "WriteLogAtAddress called\n" ) );
if ( inStructSize != sizeof ( ATASMARTWriteLogStruct ) )
return kIOReturnBadArgument;
fOutstandingCommands++;
if ( isInactive ( ) )
{
status = kIOReturnNoDevice;
goto ErrorExit;
}
fProvider->retain ( );
command = AllocateCommand ( );
if ( command == NULL )
{
status = kIOReturnNoResources;
goto ReleaseProvider;
}
buffer = IOMemoryDescriptor::withAddress ( ( vm_address_t ) writeLogData->buffer,
writeLogData->bufferSize,
kIODirectionOut,
fTask );
if ( buffer == NULL )
{
status = kIOReturnNoResources;
goto ReleaseCommand;
}
status = buffer->prepare ( );
if ( status != kIOReturnSuccess )
{
goto ReleaseBuffer;
}
command->setBuffer ( buffer );
command->setByteCount ( writeLogData->bufferSize );
command->setFeatures ( kFeaturesRegisterWriteLogAtAddress );
command->setOpcode ( kATAFnExecIO );
command->setTimeoutMS ( kATAThirtySecondTimeoutInMS );
command->setSectorCount ( writeLogData->numSectors );
command->setSectorNumber ( writeLogData->logAddress );
command->setCylLo ( kSMARTMagicCylinderLoValue );
command->setCylHi ( kSMARTMagicCylinderHiValue );
command->setCommand ( kATAcmdSMART );
command->setFlags ( mATAFlagIOWrite );
status = SendSMARTCommand ( command );
if ( status == kIOReturnIOError )
{
if ( command->getEndErrorReg ( ) & 0x04 )
{
ERROR_LOG ( ( "ReadLogAtAddress %d unsupported\n", writeLogData->logAddress ) );
status = kIOReturnUnsupported;
}
if ( command->getEndErrorReg ( ) & 0x10 )
{
ERROR_LOG ( ( "ReadLogAtAddress %d unwriteable\n", writeLogData->logAddress ) );
status = kIOReturnNotWritable;
}
}
buffer->complete ( );
ReleaseBuffer:
buffer->release ( );
buffer = NULL;
ReleaseCommand:
DeallocateCommand ( command );
command = NULL;
ReleaseProvider:
fProvider->release ( );
ErrorExit:
fOutstandingCommands--;
return status;
}
#if 0
#pragma mark -
#pragma mark Protected Methods
#pragma mark -
#endif
IOExternalMethod *
ATASMARTUserClient::getTargetAndMethodForIndex ( IOService ** target, UInt32 index )
{
if ( index >= kIOATASMARTMethodCount )
return NULL;
if ( isInactive ( ) )
return NULL;
*target = this;
return &sMethods[index];
}
IOReturn
ATASMARTUserClient::GatedWaitForCommand ( IOATACommand * command )
{
IOReturn status = kIOReturnSuccess;
ATASMARTRefCon * refCon;
STATUS_LOG ( ( "GatedWaitForCommand called\n" ) );
refCon = ( ATASMARTRefCon * ) command->refCon;
while ( refCon->isDone != true )
{
fCommandGate->commandSleep ( &refCon->sleepOnIt, THREAD_UNINT );
}
return status;
}
IOReturn
ATASMARTUserClient::HandleTerminate ( IOService * provider )
{
IOReturn status = kIOReturnSuccess;
IOWorkLoop * workLoop = NULL;
STATUS_LOG ( ( "HandleTerminate called\n" ) );
if ( provider->isOpen ( this ) )
{
while ( fOutstandingCommands != 0 )
{
IOSleep ( 10 );
}
STATUS_LOG ( ( "Closing provider\n" ) );
provider->close ( this, kIOATASMARTUserClientAccessMask );
}
detach ( provider );
workLoop = getWorkLoop ( );
if ( workLoop != NULL )
workLoop->removeEventSource ( fCommandGate );
return status;
}
IOReturn
ATASMARTUserClient::SendSMARTCommand ( IOATACommand * command )
{
ATASMARTRefCon refCon;
IOReturn status = kIOReturnSuccess;
bzero ( &refCon, sizeof ( refCon ) );
refCon.isDone = false;
refCon.self = this;
STATUS_LOG ( ( "SendSMARTCommand called\n" ) );
command->setCallbackPtr ( &ATASMARTUserClient::sCommandCallback );
command->refCon = ( void * ) &refCon;
retain ( );
status = fProvider->sendSMARTCommand ( command );
if ( status == kIOReturnSuccess )
{
fCommandGate->runAction ( ( IOCommandGate::Action ) &ATASMARTUserClient::sWaitForCommand,
( void * ) command );
STATUS_LOG ( ( "SendSMARTCommand runAction done\n" ) );
switch ( command->getResult ( ) )
{
case kATANoErr:
status = kIOReturnSuccess;
break;
case kATATimeoutErr:
status = kIOReturnTimeout;
break;
default:
status = kIOReturnIOError;
break;
}
}
else
{
release ( );
}
return status;
}
void
ATASMARTUserClient::CommandCallback ( IOATACommand * command )
{
ATASMARTRefCon * refCon = NULL;
refCon = ( ATASMARTRefCon * ) command->refCon;
fCommandGate->commandWakeup ( &refCon->sleepOnIt, true );
release ( );
}
IOATACommand *
ATASMARTUserClient::AllocateCommand ( void )
{
IOATACommand * command = NULL;
IOATADevice * device = NULL;
STATUS_LOG ( ( "AllocateCommand called\n" ) );
device = ( IOATADevice * ) ( fProvider->getProvider ( )->getProvider ( ) );
command = device->allocCommand ( );
return command;
}
void
ATASMARTUserClient::DeallocateCommand ( IOATACommand * command )
{
STATUS_LOG ( ( "DeallocateCommand called\n" ) );
if ( command != NULL )
{
IOATADevice * device = NULL;
device = ( IOATADevice * ) ( fProvider->getProvider ( )->getProvider ( ) );
device->freeCommand ( command );
}
}
#if 0
#pragma mark -
#pragma mark Static Methods
#pragma mark -
#endif
IOReturn
ATASMARTUserClient::sWaitForCommand ( void * userClient,
IOATACommand * command )
{
return ( ( ATASMARTUserClient * ) userClient )->GatedWaitForCommand ( command );
}
void
ATASMARTUserClient::sCommandCallback ( IOATACommand * command )
{
ATASMARTRefCon * refCon = NULL;
STATUS_LOG ( ( "ATASMARTUserClient::sCommandCallback called.\n") );
refCon = ( ATASMARTRefCon * ) command->refCon;
if ( refCon == NULL )
{
ERROR_LOG ( ( "ATASMARTUserClient::sCommandCallback refCon == NULL.\n" ) );
PANIC_NOW ( ( "ATASMARTUserClient::sCommandCallback refCon == NULL." ) );
return;
}
refCon->isDone = true;
refCon->self->CommandCallback ( command );
}