Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
prog:lazarus:cas:disks:deviceiocontrol [25/03/2020 18:59] thierry [A etudier] |
prog:lazarus:cas:disks:deviceiocontrol [11/04/2023 16:42] (Version actuelle) thierry [Sources] |
||
---|---|---|---|
Ligne 2: | Ligne 2: | ||
===== Commandes ===== | ===== Commandes ===== | ||
==== SMART_SEND_DRIVE_COMMAND ==== | ==== SMART_SEND_DRIVE_COMMAND ==== | ||
+ | <note important>Pour pouvoir utiliser SMART il faut que le fichier soit ouvert avec GENERIC_WRITE | ||
+ | <code pascal> | ||
+ | CreateFile(PChar(AFile), GENERIC_READ or GENERIC_WRITE, | ||
+ | FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0) | ||
+ | </code> | ||
+ | </note> | ||
=== Types utiles === | === Types utiles === | ||
== TSendCmdInParams == | == TSendCmdInParams == | ||
Ligne 76: | Ligne 82: | ||
=== A etudier === | === 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]]) | ||
<code c++> | <code c++> | ||
BOOL CSmartReader::IsSmartEnabled(HANDLE hDevice,UCHAR ucDriveIndex) | BOOL CSmartReader::IsSmartEnabled(HANDLE hDevice,UCHAR ucDriveIndex) | ||
Ligne 102: | Ligne 109: | ||
} | } | ||
</code> | </code> | ||
+ | [[http://mojolabs.nz/posts.php?topic=105995|Source de ci-dessous]] | ||
+ | <code c++> | ||
+ | /* | ||
+ | * 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; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ---- | ||
+ | <code c++> | ||
+ | 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"); | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Projet Delphi : [[https://www.delphipraxis.net/97172-s-m-r-t-figured-out.html]] | ||
=== Sources === | === Sources === | ||
Ligne 108: | Ligne 323: | ||
- | ===== Sources ===== | + | ====== Sources & Ressources====== |
* [[https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol|DeviceIOControl chez Doc Microsoft]] | * [[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]] | ||