CreateFile(PChar(AFile), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0)
_SENDCMDINPARAMS = packed record cBufferSize: DWORD; // Buffer size in bytes irDriveRegs: IDEREGS; // Structure with drive register values. bDriveNumber: BYTE; // Physical drive number to send // command to (0,1,2,3). bReserved: array [0..2] of BYTE; // Reserved for future expansion. dwReserved: array [0..3] of DWORD; // For future use. bBuffer: array [0..0] of BYTE; // Input buffer. end; ... _IDEREGS = packed record bFeaturesReg: BYTE; // Used for specifying SMART "commands". bSectorCountReg: BYTE; // IDE sector count register bSectorNumberReg: BYTE; // IDE sector number register bCylLowReg: BYTE; // IDE low order cylinder value bCylHighReg: BYTE; // IDE high order cylinder value bDriveHeadReg: BYTE; // IDE drive/head register bCommandReg: BYTE; // Actual IDE command. bReserved: BYTE; // reserved for future use. Must be zero. end;
_SENDCMDOUTPARAMS = packed record cBufferSize: DWORD; // Size of bBuffer in bytes DriverStatus: DRIVERSTATUS; // Driver status structure. bBuffer: array [0..0] of BYTE; // Buffer of arbitrary length in which to store the data read from the drive. end; ... _DRIVERSTATUS = packed record bDriverError: BYTE; // Error code from driver, or 0 if no error. bIDEError: BYTE; // Contents of IDE Error register. Only valid when bDriverError is SMART_IDE_ERROR. bReserved: array [0..1] of BYTE; // Reserved for future expansion. dwReserved: array [0..1] of DWORD; // Reserved for future expansion. end;
// Feature register defines for SMART "sub commands" READ_ATTRIBUTES = $D0; READ_THRESHOLDS = $D1; ENABLE_DISABLE_AUTOSAVE = $D2; SAVE_ATTRIBUTE_VALUES = $D3; EXECUTE_OFFLINE_DIAGS = $D4; SMART_READ_LOG = $D5; SMART_WRITE_LOG = $d6; ENABLE_SMART = $D8; DISABLE_SMART = $D9; RETURN_SMART_STATUS = $DA; ENABLE_DISABLE_AUTO_OFFLINE = $DB;
SMART_CMD = $B0; // Performs SMART cmd. Requires valid bFeaturesReg, bCylLowReg, and bCylHighReg // Cylinder register defines for SMART command SMART_CYL_LOW = $4F; SMART_CYL_HI = $C2;
Avec #define DRIVE_HEAD_REG 0xA0 (Trouvé ici)
BOOL CSmartReader::IsSmartEnabled(HANDLE hDevice,UCHAR ucDriveIndex) { SENDCMDINPARAMS cmdInParams={0}; SENDCMDOUTPARAMS smdOutParams={0}; DWORD dwRet=0; BOOL bRet=FALSE; cmdInParams.cBufferSize=0; cmdInParams.bDriveNumber =ucDriveIndex; cmdInParams.irDriveRegs.bFeaturesReg=ENABLE_SMART; cmdInParams.irDriveRegs.bSectorCountReg = 1; cmdInParams.irDriveRegs.bSectorNumberReg = 1; cmdInParams.irDriveRegs.bCylLowReg = SMART_CYL_LOW; cmdInParams.irDriveRegs.bCylHighReg = SMART_CYL_HI; cmdInParams.irDriveRegs.bDriveHeadReg = DRIVE_HEAD_REG; cmdInParams.irDriveRegs.bCommandReg = SMART_CMD; bRet=DeviceIoControl(hDevice,SMART_SEND_DRIVE_COMMAND,&cmdInParams,sizeof(cmdInParams),&smdOutParams,sizeof(smdOutParams),&dwRet,NULL); if(!bRet) { dwRet=GetLastError(); } return bRet; }
/* * smart.c - reads S.M.A.R.T data from disks * * usage: smart driveid [--raw] * * !!! ADMIN privilidges is needed to read s.m.a.r.t data !!! * * for list of attributes and their ids: <a href="https://en.wikipedia.org/wiki/S.M.A.R.T." target="_blank">https://en.wikipedia.org/wiki/S.M.A.R.T.</a> */ #include <windows.h> #include <ntdddisk.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <inttypes.h> #if READ_ATTRIBUTE_BUFFER_SIZE != READ_THRESHOLD_BUFFER_SIZE #error "This code assumes READ_ATTRIBUTE_BUFFER_SIZE == READ_THRESHOLD_BUFFER_SIZE" #endif // only meant to read ATTRIBUTES and THRESHOLDS static SENDCMDOUTPARAMS* read_smart_data( int drive, int smartcmd) { char path[32]; sprintf( path, "\\\\.\\PhysicalDrive%d", drive); HANDLE handle = CreateFile( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if(handle == INVALID_HANDLE_VALUE) return NULL; SENDCMDINPARAMS cmd = { .cBufferSize = sizeof(SENDCMDINPARAMS) - 1, .irDriveRegs = { .bFeaturesReg = smartcmd, .bSectorCountReg = 1, .bSectorNumberReg = 0, .bCylLowReg = SMART_CYL_LOW, .bCylHighReg = SMART_CYL_HI, .bDriveHeadReg = 0xA0, .bCommandReg = SMART_CMD, }, .bDriveNumber = drive, }; DWORD datasz = (sizeof(SENDCMDOUTPARAMS) - 1) + READ_ATTRIBUTE_BUFFER_SIZE; SENDCMDOUTPARAMS* data = malloc(datasz); DWORD writesz = 0; if(!DeviceIoControl( handle, SMART_RCV_DRIVE_DATA, &cmd, sizeof(cmd) - 1, data, datasz, &writesz, NULL)) { free(data); CloseHandle(handle); return NULL; } CloseHandle(handle); return data; } static bool check_smart( const char* name, SENDCMDOUTPARAMS* data) { if(data->DriverStatus.bDriverError || data->DriverStatus.bIDEError) { printf( "Error while reading S.M.A.R.T. %s...\n", name); printf( "DriverError = %d\n", data->DriverStatus.bDriverError); printf( "IDEError = %d\n", data->DriverStatus.bIDEError); return false; } return true; } static void print_raw( const char* name, void* attrs) { printf("\n------------- RAW %9s DATA --------------\n", name); for( uint8_t *p = attrs, *end = attrs + READ_ATTRIBUTE_BUFFER_SIZE; p < end; p += 16) { printf( "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] ); } } /* * format of S.M.A.R.T attribute/threshold data: * * size of attribute/threshold data is normally 512 bytes (1 sector). * READ_ATTRIBUTE_BUFFER_SIZE and READ_THRESHOLD_BUFFER_SIZE holds actual size if it ever changes. * * * OFFS SIZE DESC * 0 2 ? * 2 12 attribute/threshold * ... * all attributes/thresholds from here * * * format of S.M.A.R.T attribute: * * OFFS SIZE DESC * 0 1 type * 1 2 flags * 3 1 value * 4 1 worst * 5 6 raw value (48-bits big-endian) * 11 1 ? * * if type==0 no attribute in that slot * * the raw value is vendor specific, and for certain attributes that denote time or temperature further calculations are needed to display correctly. * * * format of S.M.A.R.T threshold: * * OFFS SIZE DESC * 0 1 type * 1 1 threshold * 2 10 ? * * if type==0 no threshold in that slot * */ static void print_smart( void* attrs, void* thresh) { printf( "\nID FLAG VALUE WORST THRESH RAW\n"); uint8_t* aend = attrs + READ_ATTRIBUTE_BUFFER_SIZE; uint8_t* t = thresh; for( uint8_t *a = attrs + 2; a < aend; a += 12) { if(*a) { uint8_t id = *a; uint16_t flags = *(uint16_t*)(a+1); uint8_t value = a[3]; uint8_t worst = a[4]; uint8_t threshold = t ? (t[a - (uint8_t*)attrs] ? t[(a - (uint8_t*)attrs) + 1] : 0) : 0; uint8_t raw[8] = {0}; // reverse byte order for( int i=5; i<11; i++) raw[i-5] = a[i]; printf( "%3d 0x%04x %03d %03d %03d %" PRIu64 "\n", id, flags, value, worst, threshold, *((uint64_t*)raw) & 0xFFFFFFFFFFFFL); } } } int main( int argc, const char* argv[argc]) { if(argc == 1) { printf( "usage: smart driveid [--raw]\n"); return 0; } int drive = -1; bool showraw = false; for( int i=1; i<argc; i++) { if(!strcmp( argv[i], "--raw")) showraw = true; else { drive = strtol( argv[1], NULL, 10); if(drive < 0) { fprintf( stderr, "error: invalid drive id (%d)\n", drive); return 1; } } } if(drive == -1) { fprintf( stderr, "error: no drive id specified\n"); return 1; } SENDCMDOUTPARAMS* adata = read_smart_data( drive, READ_ATTRIBUTES); SENDCMDOUTPARAMS* tdata = read_smart_data( drive, READ_THRESHOLDS); if(!adata) { fprintf( stderr, "error: unable to read S.M.A.R.T ATTRIBUTES of drive %d\n", drive); return 1; } if(!check_smart( "ATTRIBUTES", adata) || (tdata && !check_smart( "THRESHOLDS", tdata))) { free(adata); free(tdata); return 1; } if(showraw) { print_raw( "ATTRIBUTE", adata->bBuffer); if(tdata) print_raw( "THRESHOLD", tdata->bBuffer); } print_smart( adata->bBuffer, tdata ? tdata->bBuffer : NULL); free(adata); free(tdata); return 0; }
SENDCMDINPARAMS stCIP={0}; SENDCMDOUTPARAMS stCOP={0}; DWORD dwRet=0; BOOL bRet=FALSE; BYTE szAttributes[sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1]; stCIP.cBufferSize=0; stCIP.bDriveNumber = drive; stCIP.irDriveRegs.bFeaturesReg= 0xD0; stCIP.irDriveRegs.bSectorCountReg = 1; stCIP.irDriveRegs.bSectorNumberReg = 1; stCIP.irDriveRegs.bCylLowReg = 0x4F; stCIP.irDriveRegs.bCylHighReg = 0xC2; stCIP.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4); stCIP.irDriveRegs.bCommandReg = 0xB0; bRet=DeviceIoControl(handle,SMART_RCV_DRIVE_DATA,&stCIP,sizeof(stCIP),szAttributes,sizeof(SENDCMDOUTPARAMS)+ READ_ATTRIBUTE_BUFFER_SIZE - 1,&dwRet,NULL); //std::cout<<"output="<<dwRet<<std::endl; //printf("\n");
Projet Delphi : https://www.delphipraxis.net/97172-s-m-r-t-figured-out.html