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:55]
thierry [Constantes Utiles]
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 61: Ligne 67:
 [[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 == == Autres constantes ==
-<code delphi>+<code delphi ​jwawinioctl.pas> 
 +  SMART_CMD ​   = $B0;       // Performs SMART cmd. Requires valid bFeaturesReg,​ bCylLowReg, and bCylHighReg 
 // Cylinder register defines for SMART command // Cylinder register defines for SMART command
   SMART_CYL_LOW = $4F;   SMART_CYL_LOW = $4F;
Ligne 74: 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 100: 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_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++> <code c++>
-#define SMART_CYL_LOW  ​0x4F +SENDCMDINPARAMS stCIP={0};​ 
- #define SMART_CYL_HI ​  0xC2+ 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>​ </​code>​
 +
 +Projet Delphi : [[https://​www.delphipraxis.net/​97172-s-m-r-t-figured-out.html]]
  
 === Sources === === Sources ===
Ligne 113: 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]]