ATASMARTClient.cpp [plain text]
#include "ATASMARTLib.h"
#include "ATASMARTClient.h"
#include "ATASMARTLibPriv.h"
#include <stdio.h>
enum
{
kATASMARTLogDirectoryEntry = 0x00
};
enum
{
kATADefaultSectorSize = 512
};
#define ATA_SMART_DEBUGGING_LEVEL 0
#if ( ATA_SMART_DEBUGGING_LEVEL > 0 )
#define PRINT(x) printf x
#else
#define PRINT(x)
#endif
UInt32 ATASMARTClient::sFactoryRefCount = 0;
IOCFPlugInInterface
ATASMARTClient::sIOCFPlugInInterface =
{
0,
&ATASMARTClient::sQueryInterface,
&ATASMARTClient::sAddRef,
&ATASMARTClient::sRelease,
1, 0, &ATASMARTClient::sProbe,
&ATASMARTClient::sStart,
&ATASMARTClient::sStop
};
IOATASMARTInterface
ATASMARTClient::sATASMARTInterface =
{
0,
&ATASMARTClient::sQueryInterface,
&ATASMARTClient::sAddRef,
&ATASMARTClient::sRelease,
1, 0, &ATASMARTClient::sSMARTEnableDisableOperations,
&ATASMARTClient::sSMARTEnableDisableAutosave,
&ATASMARTClient::sSMARTReturnStatus,
&ATASMARTClient::sSMARTExecuteOffLineImmediate,
&ATASMARTClient::sSMARTReadData,
&ATASMARTClient::sSMARTValidateReadData,
&ATASMARTClient::sSMARTReadDataThresholds,
&ATASMARTClient::sSMARTReadLogDirectory,
&ATASMARTClient::sSMARTReadLogAtAddress,
&ATASMARTClient::sSMARTWriteLogAtAddress,
&ATASMARTClient::sGetATAIdentifyData
};
#if 0
#pragma mark -
#pragma mark Methods associated with ATASMARTLib factory
#pragma mark -
#endif
void *
ATASMARTLibFactory ( CFAllocatorRef allocator, CFUUIDRef typeID )
{
PRINT ( ( "ATASMARTLibFactory called\n" ) );
if ( CFEqual ( typeID, kIOATASMARTUserClientTypeID ) )
return ( void * ) ATASMARTClient::alloc ( );
else
return NULL;
}
IOCFPlugInInterface **
ATASMARTClient::alloc ( void )
{
ATASMARTClient * userClient;
IOCFPlugInInterface ** interface = NULL;
PRINT ( ( "ATASMARTClient::alloc called\n" ) );
userClient = new ATASMARTClient;
if ( userClient != NULL )
{
interface = ( IOCFPlugInInterface ** ) &userClient->fCFPlugInInterfaceMap.pseudoVTable;
}
return interface;
}
void
ATASMARTClient::sFactoryAddRef ( void )
{
if ( sFactoryRefCount++ == 0 )
{
CFUUIDRef factoryID = kIOATASMARTLibFactoryID;
CFRetain ( factoryID );
CFPlugInAddInstanceForFactory ( factoryID );
}
}
void
ATASMARTClient::sFactoryRelease ( void )
{
if ( sFactoryRefCount-- == 1 )
{
CFUUIDRef factoryID = kIOATASMARTLibFactoryID;
CFPlugInRemoveInstanceForFactory ( factoryID );
CFRelease ( factoryID );
}
else if ( sFactoryRefCount < 0 )
{
sFactoryRefCount = 0;
}
}
#if 0
#pragma mark -
#pragma mark Public Methods
#pragma mark -
#endif
ATASMARTClient::ATASMARTClient ( void ) : fRefCount ( 1 )
{
fCFPlugInInterfaceMap.pseudoVTable = ( IUnknownVTbl * ) &sIOCFPlugInInterface;
fCFPlugInInterfaceMap.obj = this;
fATASMARTInterfaceMap.pseudoVTable = ( IUnknownVTbl * ) &sATASMARTInterface;
fATASMARTInterfaceMap.obj = this;
sFactoryAddRef ( );
}
ATASMARTClient::~ATASMARTClient ( void )
{
sFactoryRelease ( );
}
#if 0
#pragma mark -
#endif
HRESULT
ATASMARTClient::QueryInterface ( REFIID iid, void ** ppv )
{
CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes ( NULL, iid );
HRESULT result = S_OK;
PRINT ( ( "ATASMARTClient : QueryInterface called\n" ) );
if ( CFEqual ( uuid, IUnknownUUID ) ||
CFEqual ( uuid, kIOCFPlugInInterfaceID ) )
{
PRINT ( ( "IUnknownUUID | kIOCFPlugInInterfaceID requested\n" ) );
*ppv = &fCFPlugInInterfaceMap;
AddRef ( );
}
else if ( CFEqual ( uuid, kIOATASMARTInterfaceID ) )
{
PRINT ( ( "kIOATASMARTInterfaceID requested\n" ) );
*ppv = &fATASMARTInterfaceMap;
AddRef ( );
}
else
{
PRINT ( ( "unknown interface requested\n" ) );
*ppv = 0;
result = E_NOINTERFACE;
}
CFRelease ( uuid );
return result;
}
UInt32
ATASMARTClient::AddRef ( void )
{
fRefCount += 1;
return fRefCount;
}
UInt32
ATASMARTClient::Release ( void )
{
UInt32 returnValue = fRefCount - 1;
if ( returnValue > 0 )
{
fRefCount = returnValue;
}
else if ( returnValue == 0 )
{
fRefCount = returnValue;
delete this;
}
else
{
returnValue = 0;
}
return returnValue;
}
IOReturn
ATASMARTClient::Probe ( CFDictionaryRef propertyTable,
io_service_t inService,
SInt32 * order )
{
CFMutableDictionaryRef dict = 0;
IOReturn status = kIOReturnBadArgument;
PRINT ( ( "ATASMARTClient::Probe called\n" ) );
if ( inService == 0 )
{
goto Exit;
}
status = IORegistryEntryCreateCFProperties ( inService, &dict, NULL, 0 );
if ( status != kIOReturnSuccess )
{
goto Exit;
}
if ( !CFDictionaryContainsKey ( dict, CFSTR ( "IOCFPlugInTypes" ) ) )
{
goto Exit;
}
status = kIOReturnSuccess;
Exit:
if ( dict != 0 )
{
CFRelease ( dict );
dict = 0;
}
return status;
}
IOReturn
ATASMARTClient::Start ( CFDictionaryRef propertyTable, io_service_t service )
{
IOReturn status = kIOReturnSuccess;
PRINT ( ( "ATASMARTClient : Start\n" ) );
fService = service;
status = IOServiceOpen ( fService,
mach_task_self ( ),
kIOATASMARTLibConnection,
&fConnection );
if ( !fConnection )
status = kIOReturnNoDevice;
PRINT ( ( "ATASMARTClient : IOServiceOpen status = 0x%08lx, connection = %d\n",
( UInt32 ) status, fConnection ) );
return status;
}
IOReturn
ATASMARTClient::Stop ( void )
{
PRINT ( ( "ATASMARTClient : Stop\n" ) );
if ( fConnection )
{
PRINT ( ( "ATASMARTClient : IOServiceClose connection = %d\n", fConnection ) );
IOServiceClose ( fConnection );
fConnection = MACH_PORT_NULL;
}
return kIOReturnSuccess;
}
#if 0
#pragma mark -
#pragma mark SMART Methods
#pragma mark -
#endif
IOReturn
ATASMARTClient::SMARTEnableDisableOperations ( Boolean enable )
{
IOReturn status = kIOReturnSuccess;
int selection = ( enable == true ) ? 1 : 0;
PRINT ( ( "ATASMARTClient::SMARTEnableDisableOperations called\n" ) );
status = IOConnectMethodScalarIScalarO ( fConnection,
kIOATASMARTEnableDisableOperations,
1,
0,
&selection );
PRINT ( ( "ATASMARTClient::SMARTEnableDisableOperations status = %d\n", status ) );
return status;
}
IOReturn
ATASMARTClient::SMARTEnableDisableAutosave ( Boolean enable )
{
IOReturn status = kIOReturnSuccess;
int selection = ( enable == true ) ? 1 : 0;
PRINT ( ( "ATASMARTClient::SMARTEnableDisableAutosave called\n" ) );
status = IOConnectMethodScalarIScalarO ( fConnection,
kIOATASMARTEnableDisableAutoSave,
1,
0,
&selection );
PRINT ( ( "ATASMARTClient::SMARTEnableDisableAutosave status = %d\n", status ) );
return status;
}
IOReturn
ATASMARTClient::SMARTReturnStatus ( Boolean * exceededCondition )
{
IOReturn status = kIOReturnSuccess;
int condition = 0;
PRINT ( ( "ATASMARTClient::SMARTReturnStatus called\n" ) );
status = IOConnectMethodScalarIScalarO ( fConnection,
kIOATASMARTReturnStatus,
0,
1,
&condition );
if ( status == kIOReturnSuccess )
{
*exceededCondition = ( condition != 0 ) ? true : false;
PRINT ( ( "exceededCondition = %d\n", condition ) );
}
PRINT ( ( "ATASMARTClient::SMARTReturnStatus status = %d\n", status ) );
return status;
}
IOReturn
ATASMARTClient::SMARTExecuteOffLineImmediate ( Boolean extendedTest )
{
IOReturn status = kIOReturnSuccess;
int selection = ( extendedTest == true ) ? 1 : 0;;
PRINT ( ( "ATASMARTClient::SMARTExecuteOffLineImmediate called\n" ) );
status = IOConnectMethodScalarIScalarO ( fConnection,
kIOATASMARTExecuteOffLineImmediate,
1,
0,
&selection );
PRINT ( ( "ATASMARTClient::SMARTExecuteOffLineImmediate status = %d\n", status ) );
return status;
}
IOReturn
ATASMARTClient::SMARTReadData ( ATASMARTData * data )
{
IOReturn status;
PRINT ( ( "ATASMARTClient::SMARTReadData called\n" ) );
status = IOConnectMethodScalarIScalarO ( fConnection,
kIOATASMARTReadData,
1,
0,
( int * ) data );
PRINT ( ( "ATASMARTClient::SMARTReadData status = %d\n", status ) );
#if 0
if ( status == kIOReturnSuccess )
{
UInt8 * ptr = ( UInt8 * ) data;
printf ( "ATA SMART DATA\n" );
for ( UInt8 index = 0; ( index < sizeof ( ATASMARTData ) ); index += 8 )
{
printf ( "0x%02x 0x%02x 0x%02x 0x%02x | 0x%02x 0x%02x 0x%02x 0x%02x\n",
ptr[index + 0], ptr[index + 1], ptr[index + 2], ptr[index + 3],
ptr[index + 4], ptr[index + 5], ptr[index + 6], ptr[index + 7] );
}
}
#endif
return status;
}
IOReturn
ATASMARTClient::SMARTReadDataThresholds ( ATASMARTDataThresholds * data )
{
IOReturn status;
PRINT ( ( "ATASMARTClient::SMARTReadDataThresholds called\n" ) );
status = IOConnectMethodScalarIScalarO ( fConnection,
kIOATASMARTReadDataThresholds,
1,
0,
( int * ) data );
PRINT ( ( "ATASMARTClient::SMARTReadDataThresholds status = %d\n", status ) );
#if 0
if ( status == kIOReturnSuccess )
{
UInt8 * ptr = ( UInt8 * ) data;
printf ( "ATA SMART DATA THRESHOLDS\n" );
for ( UInt8 index = 0; ( index < sizeof ( ATASMARTDataThresholds ) ); index += 8 )
{
printf ( "0x%02x 0x%02x 0x%02x 0x%02x | 0x%02x 0x%02x 0x%02x 0x%02x\n",
ptr[index + 0], ptr[index + 1], ptr[index + 2], ptr[index + 3],
ptr[index + 4], ptr[index + 5], ptr[index + 6], ptr[index + 7] );
}
}
#endif
return status;
}
IOReturn
ATASMARTClient::SMARTReadLogDirectory ( ATASMARTLogDirectory * log )
{
IOReturn status;
status = SMARTReadLogAtAddress ( kATASMARTLogDirectoryEntry,
( void * ) log,
sizeof ( ATASMARTLogDirectory ) );
PRINT ( ( "ATASMARTClient::SMARTReadLogDirectory status = %d\n", status ) );
#if 0
if ( status == kIOReturnSuccess )
{
UInt8 * ptr = ( UInt8 * ) log;
printf ( "ATA SMART Log Directory\n" );
for ( UInt8 index = 0; ( index < sizeof ( ATASMARTLogDirectory ) ); index += 8 )
{
printf ( "0x%02x 0x%02x 0x%02x 0x%02x | 0x%02x 0x%02x 0x%02x 0x%02x\n",
ptr[index + 0], ptr[index + 1], ptr[index + 2], ptr[index + 3],
ptr[index + 4], ptr[index + 5], ptr[index + 6], ptr[index + 7] );
}
}
#endif
return status;
}
IOReturn
ATASMARTClient::SMARTReadLogAtAddress ( UInt32 address,
void * buffer,
UInt32 bufferSize )
{
IOReturn status;
IOByteCount byteCount;
ATASMARTReadLogStruct params;
PRINT ( ( "ATASMARTClient::SMARTReadLogAtAddress called\n" ) );
if ( ( address > 0xFF ) || ( buffer == NULL ) )
{
status = kIOReturnBadArgument;
goto Exit;
}
byteCount = sizeof ( ATASMARTReadLogStruct );
params.numSectors = bufferSize / kATADefaultSectorSize;
params.logAddress = address & 0xFF;
params.buffer = buffer;
params.bufferSize = bufferSize;
if ( params.numSectors > 16 )
{
status = kIOReturnBadArgument;
goto Exit;
}
PRINT ( ( "ATASMARTClient::SMARTReadLogAtAddress address = %ld\n", address ) );
status = IOConnectMethodScalarIStructureI ( fConnection,
kIOATASMARTReadLogAtAddress,
0,
byteCount,
( void * ) ¶ms );
Exit:
PRINT ( ( "ATASMARTClient::SMARTReadLogAtAddress status = %d\n", status ) );
return status;
}
IOReturn
ATASMARTClient::SMARTWriteLogAtAddress ( UInt32 address,
const void * buffer,
UInt32 bufferSize )
{
IOReturn status;
IOByteCount byteCount;
ATASMARTWriteLogStruct params;
PRINT ( ( "ATASMARTClient::SMARTWriteLogAtAddress called\n" ) );
if ( ( address > 0xFF ) || ( buffer == NULL ) )
{
status = kIOReturnBadArgument;
goto Exit;
}
byteCount = sizeof ( ATASMARTWriteLogStruct );
params.numSectors = bufferSize / kATADefaultSectorSize;
params.logAddress = address & 0xFF;
params.buffer = buffer;
params.bufferSize = bufferSize;
if ( params.numSectors > 16 )
{
status = kIOReturnBadArgument;
goto Exit;
}
PRINT ( ( "ATASMARTClient::SMARTWriteLogAtAddress address = %ld\n", address ) );
status = IOConnectMethodScalarIStructureI ( fConnection,
kIOATASMARTWriteLogAtAddress,
0,
byteCount,
( void * ) ¶ms );
Exit:
PRINT ( ( "ATASMARTClient::SMARTWriteLogAtAddress status = %d\n", status ) );
return status;
}
#if 0
#pragma mark -
#pragma mark Additional Methods
#pragma mark -
#endif
IOReturn
ATASMARTClient::GetATAIdentifyData ( void * buffer, UInt32 inSize, UInt32 * outSize )
{
IOReturn status = kIOReturnBadArgument;
IOByteCount byteCount = 0;
ATAGetIdentifyDataStruct params = { 0 };
UInt32 bytesTransferred = 0;
if ( ( buffer == NULL ) || ( inSize > 512 ) || ( inSize == 0 ) )
{
status = kIOReturnBadArgument;
goto Exit;
}
byteCount = sizeof ( UInt32 );
params.buffer = buffer;
params.bufferSize = inSize;
PRINT ( ( "ATASMARTClient::GetATAIdentifyData\n" ) );
status = IOConnectMethodStructureIStructureO ( fConnection,
kIOATASMARTGetIdentifyData,
sizeof ( ATAGetIdentifyDataStruct ),
&byteCount,
( void * ) ¶ms,
( void * ) &bytesTransferred );
if ( outSize != NULL )
{
*outSize = bytesTransferred;
}
Exit:
PRINT ( ( "ATASMARTClient::GetATAIdentifyData status = %d\n", status ) );
return status;
}
#if 0
#pragma mark -
#pragma mark Static C->C++ Glue Functions
#pragma mark -
#endif
HRESULT
ATASMARTClient::sQueryInterface ( void * self, REFIID iid, void ** ppv )
{
ATASMARTClient * obj = ( ( InterfaceMap * ) self )->obj;
return obj->QueryInterface ( iid, ppv );
}
UInt32
ATASMARTClient::sAddRef ( void * self )
{
ATASMARTClient * obj = ( ( InterfaceMap * ) self )->obj;
return obj->AddRef ( );
}
UInt32
ATASMARTClient::sRelease ( void * self )
{
ATASMARTClient * obj = ( ( InterfaceMap * ) self )->obj;
return obj->Release ( );
}
IOReturn
ATASMARTClient::sProbe ( void * self,
CFDictionaryRef propertyTable,
io_service_t service,
SInt32 * order )
{
return getThis ( self )->Probe ( propertyTable, service, order );
}
IOReturn
ATASMARTClient::sStart ( void * self,
CFDictionaryRef propertyTable,
io_service_t service )
{
return getThis ( self )->Start ( propertyTable, service );
}
IOReturn
ATASMARTClient::sStop ( void * self )
{
return getThis ( self )->Stop ( );
}
IOReturn
ATASMARTClient::sSMARTEnableDisableOperations ( void * self, Boolean enable )
{
return getThis ( self )->SMARTEnableDisableOperations ( enable );
}
IOReturn
ATASMARTClient::sSMARTEnableDisableAutosave ( void * self, Boolean enable )
{
return getThis ( self )->SMARTEnableDisableAutosave ( enable );
}
IOReturn
ATASMARTClient::sSMARTReturnStatus ( void * self, Boolean * exceededCondition )
{
return getThis ( self )->SMARTReturnStatus ( exceededCondition );
}
IOReturn
ATASMARTClient::sSMARTExecuteOffLineImmediate ( void * self, Boolean extendedTest )
{
return getThis ( self )->SMARTExecuteOffLineImmediate ( extendedTest );
}
IOReturn
ATASMARTClient::sSMARTReadData ( void * self, ATASMARTData * data )
{
return getThis ( self )->SMARTReadData ( data );
}
IOReturn
ATASMARTClient::sSMARTValidateReadData ( void * self, const ATASMARTData * data )
{
SInt8 checksum = 0;
UInt32 index = 0;
SInt8 * ptr = ( SInt8 * ) data;
IOReturn status = kIOReturnError;
PRINT ( ( "sSMARTValidateReadData called\n" ) );
for ( index = 0; index < ( sizeof ( ATASMARTData ) - 1 ); index++ )
{
checksum += ptr[index];
}
PRINT ( ( "Checksum = %d\n", checksum ) );
PRINT ( ( "ptr[511] = %d\n", ptr[511] ) );
if ( ( checksum + ptr[511] ) == 0 )
{
PRINT ( ( "Checksum is valid\n" ) );
status = kIOReturnSuccess;
}
return status;
}
IOReturn
ATASMARTClient::sSMARTReadDataThresholds (
void * self,
ATASMARTDataThresholds * data )
{
return getThis ( self )->SMARTReadDataThresholds ( data );
}
IOReturn
ATASMARTClient::sSMARTReadLogDirectory ( void * self, ATASMARTLogDirectory * log )
{
return getThis ( self )->SMARTReadLogDirectory ( log );
}
IOReturn
ATASMARTClient::sSMARTReadLogAtAddress ( void * self,
UInt32 address,
void * buffer,
UInt32 size )
{
return getThis ( self )->SMARTReadLogAtAddress ( address, buffer, size );
}
IOReturn
ATASMARTClient::sSMARTWriteLogAtAddress ( void * self,
UInt32 address,
const void * buffer,
UInt32 size )
{
return getThis ( self )->SMARTWriteLogAtAddress ( address, buffer, size );
}
IOReturn
ATASMARTClient::sGetATAIdentifyData ( void * self, void * buffer, UInt32 inSize, UInt32 * outSize )
{
return getThis ( self )->GetATAIdentifyData ( buffer, inSize, outSize );
}