0

I am writing a SMART monitor tool and I managed to get SMART attributes [Current, Worst, Raw Data] with SMART_REA_DATA command, but I need the thresholds too, and I searched the ATA documentation but I have not found anything about how to read the thresholds. Does anyone know from where can I get those values ?

Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55

1 Answers1

0

I found the answer :) It was simple. To get the threshold values you must use 0xD1 in Feature register and configure the rest as for 0xD0 (SMART_READ_DATA) command. I was not finding it because 0xD1 it's an obsolete feature... but it seems it's still used even in new hard drives.

The structure for results can be the like this:

  SMART_ATTRIBUTE = packed record
   ID: Byte;
   case byte of
    0: (Flags: Word;
        CurrValue: Byte;
        WorstValue: Byte;
        RawData: array [0..5] of Byte;
        Reserved0: Byte;);
    1: (Threshold: Byte;
        Reserved1: array [0..9] of Byte;);
  end;

  SMART_DATA = packed record
   Version: Word;
   Attribute: array [0..29] of SMART_ATTRIBUTE;
  end;

And the function for retrieving attributes an thresholds:

function GetSMARTData(Drive:Byte; Feature:Byte; var SMARTData:SMART_DATA):Boolean;
var hDrive: THandle;
    atpexb: ATA_PASS_THROUGH_EX_WITH_BUFFERS;
    bytesRet: DWord;
begin
 //Result:=false;
 hDrive:=CreateFile(PWideChar('\\.\PhysicalDrive'+IntToStr(Drive)), GENERIC_READ or GENERIC_WRITE,
  FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
 if hDrive = INVALID_HANDLE_VALUE then RaiseLastOSError;
 try
  bytesRet:=0;
  FillChar(atpexb,SizeOf(atpexb),0);
  atpexb.Length:=SizeOf(ATA_PASS_THROUGH_EX);
  atpexb.AtaFlags:=ATA_FLAGS_DATA_IN;
  atpexb.DataTransferLength:=512;
  atpexb.TimeOutValue:=1;
  atpexb.DataBufferOffset:=SizeOf(ATA_PASS_THROUGH_EX);
  atpexb.CurrentTaskFile.Command:=WIN_SMART;
  atpexb.CurrentTaskFile.Features:=Feature;
  atpexb.CurrentTaskFile.LBA_Mid:=$4F;
  atpexb.CurrentTaskFile.LBA_High:=$C2;

  if not DeviceIoControl(hDrive, IOCTL_ATA_PASS_THROUGH, @atpexb, SizeOf(ATA_PASS_THROUGH_EX),
   @atpexb, SizeOf(atpexb), bytesRet, nil) then RaiseLastOSError;

  Result:=(atpexb.CurrentTaskFile.Command and 1)=0;
  if Result then Move(atpexb.DataBuff, SMARTData, SizeOf(SMART_DATA));

 finally
  CloseHandle(hDrive);
 end;
end;
Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55