====== DeviceIOControl en Pascal ====== ===== Commandes ===== ==== SMART_SEND_DRIVE_COMMAND ==== Pour pouvoir utiliser SMART il faut que le fichier soit ouvert avec GENERIC_WRITE CreateFile(PChar(AFile), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0) === Types utiles === == TSendCmdInParams == _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; [[https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntdddisk/ns-ntdddisk-_ideregs|_IDEREGS @ Microsoft]] == TSendCmdOutParams == _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; === Constantes Utiles === == Commandes SMART == // 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; [[https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntdddisk/ns-ntdddisk-_ideregs|Explications @ Microsoft]] == Autres constantes == 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; === A etudier === Avec #define DRIVE_HEAD_REG 0xA0 ([[https://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fwinsdk%2FHard_drive_Information%2F%2FSMARTSRC.zip&zep=SMART%2FSmartReader.cpp&obid=16671&obtid=2&ovid=1|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; } [[http://mojolabs.nz/posts.php?topic=105995|Source de ci-dessous]] /* * 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: https://en.wikipedia.org/wiki/S.M.A.R.T. */ #include #include #include #include #include #include #include #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; ibBuffer); 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="< Projet Delphi : [[https://www.delphipraxis.net/97172-s-m-r-t-figured-out.html]] === Sources === * [[https://docs.microsoft.com/en-us/previous-versions/windows/hardware/drivers/ff566206(v%3Dvs.85)]] ====== Sources & Ressources====== * [[https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol|DeviceIOControl chez Doc Microsoft]] * [[https://www.smartmontools.org/static/doxygen/atacmds_8cpp_source.html]] * [[https://www.delphipraxis.net/97172-s-m-r-t-figured-out.html]]