Получение информации о S.M.A.R.T. атрибутах

Для получения значений S.M.A.R.T. атрибутов жёстких дисков на сегодняшний день существует множество платных и бесплатных программ, отличающихся дополнительными функциями при обработке данных. К наиболее известным программам данного типа относятся: HDDLife, Hard Drive Inspector, HD Tune, PCS, ActivSMART и др. Однако с помощью несложных команд возможно написание собственных программ для получения значений атрибутов и предсказания выхода из строя жёстких дисков. Для получения значения атрибутов необходимо обратиться или непосредственно к жёсткому диску или к драйверу мини-порта контроллера SCSI.

Пример алгоритма программы по получению значений атрибутов показан на рис. 2. Данная программа опрашивает первый накопитель (из четырёх) на интерфейсе IDE (PATA), а в случае отсутствия накопителей с таким интерфейсом выдает сообщение об ошибке. В приложении А приведён пример листинга программы для FreePascal, которая получает значения атрибута температуры и выводит их в консоли.

Чтение S.M.A.R.T. атрибутов можно выполнить с помощью функции DeviceIOControl, которая отправляет управляющий код непосредственно указанному драйверу устройства, заставляя соответствующее устройство выполнять указанную операцию.

Перед выполнением функции DeviceIOControl необходимо прочитать манипулятор (дескриптор или handle) диска как файл функцией CreateFile, которая для операционной системы Windows NT/2000/XP имеет следующий синтаксис:

NameHandle:= CreateFile ( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttribute, hTemplateFile)

где NameHandle – имя манипулятора;

Рис. 2

lpFileName – указатель на символьную строку, устанавливающую имя открываемого объекта;

dwDesiredAccess – режим доступа к объекту;

dwShareMode – режим совместного использования;

lpSecurityAttributes – указатель на структуру SECURITY _ATTRIBUTES, которая устанавливает может ли возвращённый дескриптор быть унаследован дочерними процессами;

dwCreationDisposition – выполняемое действие;

dwFlagsAndAttribute –атрибуты и флаги файла;

hTemplateFile – дескриптор шаблона файла.

Для создания манипулятора диска с именем SMART_Handle команда будет иметь следующие параметры:

SMART_Handle:= CreateFile (PChar('\\.\PhysicalDrive'+IntToStr(drvNumber)), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);

Данная функция работает, если программа запущена с административными правами доступа, в противном случае функция CreateFile завершается с ошибкой и возвращает значение – INVALID_HANDLE_VALUE.

Функция DeviceIOControl имеет следующий формат:

Var:= DeviceIOControl (hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped)

где hDevice – имя манипулятора устройства, над которым должна выполниться операция;

dwIoControlCode – управляющий код для операции;

lpInBuffer – указатель на буфер ввода данных, который содержит данные необходимые, чтобы выполнить операцию;

nInBufferSize – размер буфера ввода данных, в байтах;

lpOutBuffer – указатель на буфер вывода данных, который должен получить данные, возвращенные операцией;

nOutBufferSize – размер буфера вывода данных, в байтах;

lpBytesReturned – указатель на переменную, которая получает размер данных, сохраненных в буфере вывода данных, в байтах;

lpOverlapped – указатель на структуру OVERLAPPED.

Для передачи жесткому диску команды активации S.M.A.R.T. в качестве управляющего кода необходимо указать константу DFP_SEND_DRIVE_COMMAND (0007С084h), а для получения данных от диска константу DFP_RECEIVE_DRIVE_DATA (0007C088h). Сами команды S.M.A.R.T. указываются в буфере ввода данных, который удобно оформить в виде структуры данных (табл. 6.2). Для активации S.M.A.R.T. в поле bFeaturesReg необходимо занести число D8h, а для получения текущего и порогового значений атрибута D0h и D1h соответственно. Для вычисления номера диска/головки IDE в поле bDriveHeadReg необходимо записать формулу [A0h or ((drvNumber and 1) shl 4)].

Структура буфера вывода данных представлена в табл. 6.3. Так как буферы вывода данных для текущих и пороговых значений имеют одинаковую структуру, то желательно создать два буфера с разными именами. Значения всех атрибутов возвращается в массиве bBuffer со смещение в 2 байта. Его состав для текущих и пороговых значений показан в табл. 6.4.


Табл. 6.2 – Структура буфера ввода данных для команды DeviceIOControl Описание размер буфера в байтах структура регистров диска физический номер диска зарезервировано зарезервировано входной буфер регистр подкоманды S.M.A.R.T. регистр количества секторов диска регистр номера сектора диска младший разряд номера цилиндра диска старший разряд номера цилиндра диска регистр диска/головки регистр фактической команды зарезервировано
Значения элемента                   4Fh С2h   В0h  
Размер элемента 4 байта TIDERegs 1 байт 3 байта 16 байт 1 байт 1 байт 1 байт 1 байт 1 байт 1 байт 1 байт 1 байт 1 байт
Элемент структуры cBufferSize irDriveRegs bDriveNumber bReserved dwReserved bBuffer bFeaturesReg bSectorCountReg bSectorNumberReg bCylLowReg bCylHighReg bDriveHeadReg bCommandReg bReserved
Имя структуры записи TSendCmdInParams (SCIP) TIDERegs

Табл. 6.3 – Структура буфера вывода данных для команды DeviceIOControl

Имя структуры записи Элемент структуры Размер элемента Описание
TSendCmdOutParams (SCOP) cBufferSize 4 байта размер буфера в байтах
DriverStatus TDriverStatus структура состояния диска
bBuffer массив буфер произвольной длины для сохранения данных, прочитанных с диска
TDriverStatus bDriverError 1 байт код ошибки драйвера
bIDEStatus 1 байт содержание регистра ошибки
bReserved 1 байт зарезервировано
dwReserved 2 байта зарезервировано

Табл. 6.4 – Структура возвращаемых данных в bBuffer

Имя структуры записи Элемент структуры Размер элемента Описание
TDriveAttribute bAttrID 1 байт идентификатор атрибута
wStatusFlags 2 байта флаги состояния
bAttrValue 1 байт текущее нормализованное значение
bWorstValue 1 байт худшее значение
bRawValue массив [0..5] байт текущее ненормализованное значение
bReserved 1 байт зарезервировано
TAttrThreshold bAttrID 1 байт идентификатор атрибута
bWarrantyThreshold 1 байт пороговое значение
bReserved массив [0..9] байт зарезервировано

ПРИЛОЖЕНИЕ А

Листинг 1 – Программа SMARTView

program SMARTView;

{$MODE DELPHI}

Uses

Windows, strings, SysUtils;

Const

READ_ATTRIBUTE_BUFFER_SIZE = 512; // Размер буфера атрибутов

READ_THRESHOLD_BUFFER_SIZE = 512; // Размер буфера пороговых значений

DFP_SEND_DRIVE_COMMAND = $0007C084; // управляющие коды для

DFP_RECEIVE_DRIVE_DATA = $0007C088; // функции DeviceIOControl

Type

TIDERegs = packed record // структура записи регистров IDE

bFeaturesReg: BYTE; // регистр подкоманда SMART

bSectorCountReg: BYTE; // регистр количества секторов IDE

bSectorNumberReg: BYTE; // регистр номера сектора IDE

bCylLowReg: BYTE; // младший разряд номера цилиндра IDE

bCylHighReg: BYTE; // старший разряд номера цилиндра IDE

bDriveHeadReg: BYTE; // регистр номера диска/головки IDE

bCommandReg: BYTE; // фактическая команда IDE

bReserved: BYTE; // зарезервировано. Должен быть 0

end;

IDEREGS = TIDERegs;

PIDERegs = ^TIDERegs;

TsendCmdInParams = packed record // структуру записи входных параметров для функции DeviceIOControl

cBufferSize: DWORD; // размер буфера в байтах

irDriveRegs: TIDERegs; // структура со значениями регистров диска

bDriveNumber: BYTE; // физ. номер диска для посылки команд SMART (0...3)

bReserved: array [0..2] of BYTE; // зарезервировано

dwReserved: array [0..3] of DWORD; // зарезервировано

bBuffer: array [0..0] of BYTE; // входной буфер

end;

SENDCMDINPARAMS = TSendCmdInParams;

PSendCmdInParams = ^TSendCmdInParams;

TDriverStatus = packed record // структура состояния диска

bDriverError: BYTE; // код ошибки драйвера

bIDEStatus: BYTE; // содержание регистра ошибки только, когда bDriverError = SMART_IDE_ERROR

bReserved: array [0..1] of BYTE; // зарезервировано

dwReserved: array [0..1] of DWORD; // зарезервировано

end;

DRIVERSTATUS = TDriverStatus;

PDriverStatus = ^TDriverStatus;

TSendCmdOutParams = packed record // структуру записи выходных параметров, возвращаемых функцией DeviceIOControl

cBufferSize: DWORD; // размер буфера в байтах

DriverStatus: TDriverStatus; // структура состояния диска

bBuffer: array [0..0] of BYTE; // буфер произвольной длины для сохранения данных, полученных от диска

end;

SENDCMDOUTPARAMS = TsendCmdOutParams;

PSendCmdOutParams = ^TsendCmdOutParams;

TDriveAttribute = packed record // структуру записи значений атрибутов

bAttrID: BYTE; // идентификатор атрибута

wStatusFlags: WORD; // флаг состояния

bAttrValue: BYTE; // текущее нормализованное значение

bWorstValue: BYTE; // худшее значение

bRawValue: array [0..5] of BYTE; // текущее ненормализованное значение

bReserved: BYTE; // зарезервировано

end;

DRIVEATTRIBUTE = TDriveAttribute;

PDriveAttribute = ^TDriveAttribute;

TAttrThreshold = packed record // структуру записи порогового значения атрибута

bAttrID: BYTE; // идентификатор атрибута

bWarrantyThreshold: BYTE; // пороговое значение

bReserved: array [0..9] of BYTE; // зарезервировано

end;

ATTRTHRESHOLD = TAttrThreshold;

PAttrThreshold = ^TAttrThreshold;

TParam = record // общая структура со значениями атрибутов диска

DriveAttr: TDriveAttribute; // атрибуты диска

AttrThres: TAttrThreshold; // пороговое значение

end;

Var

driveHandle: THandle; // дескриптор жёсткого диска

drvNumber: integer; // номер жёсткого диска

i: integer;

j: integer;

p: TParam;

function startSMART(drvNumber: byte; var SMART_Handle: THandle): boolean;

Var

SCIP: TSendCmdInParams; // входные параметры

SCOP: TSendCmdOutParams; // выходные параметры

bytesReturned: Cardinal; // число байт, возвращённых функцией

Begin

result:=false;

SMART_Handle:= CreateFile(PChar('\\.\PhysicalDrive'+IntToStr(drvNumber)), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);

if SMART_Handle = INVALID_HANDLE_VALUE then

begin

result:=false;

exit;

end;

ZeroMemory(@SCIP, sizeof(TSendCmdInParams));

SCIP.cBufferSize:= 0;

with SCIP.irDriveRegs do

begin

bFeaturesReg:= $D8;

bSectorCountReg:= 1;

bSectorNumberReg:= 1;

bCylLowReg:= $4F;

bCylHighReg:= $C2;

bDriveHeadReg:= $A0 or ((drvNumber and 1) shl 4);

bCommandReg:= $B0;

end;

SCIP.bDriveNumber:= DrvNumber;

result:=DeviceIOControl(SMART_Handle, DFP_SEND_DRIVE_COMMAND, @SCIP, sizeof(SCIP), @SCOP, sizeof(SCOP), bytesReturned, nil);

end;

function ReadParam(var param: TParam): boolean;

Const

ATTR_SIZE = sizeof(TSendCmdOutParams)+READ_ATTRIBUTE_BUFFER_SIZE; // размер буфера под значения атрибутов

THRES_SIZE =sizeof(TSendCmdOutParams)+READ_THRESHOLD_BUFFER_SIZE; // размер буфера под пороговые значения атрибутов

Var

SCIP: TSendCmdInParams; // структура входных параметров

pSCOP, pSCOP1: PSendCmdOutParams; // структуры выходных параметров

bytesReturned: Cardinal; // число байт, возвращённых функцией

pDA: PDriveAttribute; // структуру значений атрибутов

pAT: PAttrThreshold; // структура пороговых значений атрибутов

i: integer;

Begin

getmem(pSCOP, ATTR_SIZE);

getmem(pSCOP1, THRES_SIZE);

SCIP.cBufferSize:= READ_ATTRIBUTE_BUFFER_SIZE;

SCIP.bDriveNumber:= DrvNumber;

with SCIP.irDriveRegs do

begin

bFeaturesReg:= $D0;

bCylLowReg:= $4F;

bCylHighReg:= $C2;

bDriveHeadReg:= $A0 or ((drvNumber and 1) shl 4);

bCommandReg:= $B0;

end;

result:= DeviceIOControl(driveHandle, DFP_RECEIVE_DRIVE_DATA, @SCIP, sizeof(SCIP), pSCOP, ATTR_SIZE, bytesReturned, nil);

SCIP.cBufferSize:= READ_THRESHOLD_BUFFER_SIZE;

with SCIP.irDriveRegs do

begin

bFeaturesReg:= $D1;

bCommandReg:= $B0;

end;

result:= result and DeviceIOControl(driveHandle, DFP_RECEIVE_DRIVE_DATA, @SCIP, sizeof(SCIP), pSCOP1, THRES_SIZE, bytesReturned, nil);

//атрибуты и предельные значения имеют смещение 2 байта

pDA:= PDriveAttribute(@PSendCmdOutParams(@PChar(pSCOP)[2]).bBuffer);

pAT:= PAttrThreshold(@PSendCmdOutParams(@PChar(pSCOP1)[2]).bBuffer);

ZeroMemory(@param, sizeof(param));

for i:= 1 to 30 do

begin

if (pDA^.bAttrID = 194) or (pDA^.bAttrID = 231) then

begin

param.DriveAttr:= pDA^;

param.AttrThres:= pAT^;

break;

end;

inc(pDA);

inc(pAT);

end;

freemem(pSCOP, ATTR_SIZE);

freemem(pSCOP1, THRES_SIZE);

end;

BEGIN

drvNumber:= -1;

for i:=0 to 3 do

if StartSMART(i, driveHandle) then

begin

drvNumber:=i;

if ReadParam(p) then

begin

writeln('S.M.A.R.T. attribute HDD', drvNumber);

writeln(' Attribute= ', p.DriveAttr.bAttrID,' - Temperature');

writeln('Attribute Value= ', p.DriveAttr.bAttrValue);

writeln(' Worst Value= ', p.DriveAttr.bWorstValue);

writeln('Threshold Value= ', p.AttrThres.bWarrantyThreshold);

write(' RAW Value= ');

for j:= 0 to 5 do

write(p.DriveAttr.bRawValue[j]);

writeln;

end;

end;

if drvNumber < 0 then

begin

Writeln (' 'Нет устройств, поддерживающих технологию S.M.A.R.T. или у Вас нет прав администратора');

end;

END.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: