Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

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:48]
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 45: Ligne 51:
 === Constantes Utiles === === Constantes Utiles ===
 == Commandes SMART == == Commandes SMART ==
-<code delphi>+<code delphi ​jwawinioctl.pas>
 // Feature register defines for SMART "sub commands"​ // Feature register defines for SMART "sub commands"​
   READ_ATTRIBUTES ​            = $D0;   READ_ATTRIBUTES ​            = $D0;
Ligne 60: Ligne 66:
 </​code>​ </​code>​
 [[https://​docs.microsoft.com/​en-us/​windows-hardware/​drivers/​ddi/​ntdddisk/​ns-ntdddisk-_ideregs|Explications @ Microsoft]] [[https://​docs.microsoft.com/​en-us/​windows-hardware/​drivers/​ddi/​ntdddisk/​ns-ntdddisk-_ideregs|Explications @ Microsoft]]
 +== Autres constantes ==
 +<code delphi jwawinioctl.pas>​
 +  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;
 +</​code>​
 +
  
  
Ligne 67: 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 93: 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>​
  
-on trouve : (dans [[https://www.smartmontools.org/static/doxygen/atacmds_8cpp_source.html]])+#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_dataint 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>​
  
-#define SMART_CYL_LOW ​ 0x4F +Projet Delphi : [[https://​www.delphipraxis.net/​97172-s-m-r-t-figured-out.html]]
- #​define SMART_CYL_HI ​  0xC2+
  
 === Sources === === Sources ===
Ligne 104: 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]]