Pull to refresh

Получаем атрибуты S.M.A.R.T

Reading time 5 min
Views 13K
S.M.A.R.T это технология оценки состояния жесткого диска, помогающая оценить текущее состояние и предсказать возможные проблемы и выход устройства из строя. Атрибуты S.M.A.R.T условно можно разделить на две группы: параметры, отражающие процесс изнашивания (старения) диска и текущие параметры (например, параметры производительности).

Каждый атрибут имеет идентификатор, тип (критический, показатель производительности, счетчик ошибок, счетчик событий), текущее значение, пороговое значение (если текущее меньше порогового — начинайте искать новый диск), самое низкое, зафиксированное, значение атрибута. Описание каждого атрибута можно посмотреть здесь.

На этом теоретическая часть заканчивается, перейдем к практике. Напишем программу, которая будет считывать и отображать атрибуты S.M.A.R.T. Скачать готовую программу с исходниками можно здесь.



Для начала определим структуры, в которые мы будем получать интересующую нас информацию:
// Заголовок атрибутов
typedef struct _DRIVEATTRIBUTEHDR
{
    // Номер версии
    WORD    wRevision;
    // Данные
    BYTE    bData[1];
}
DRIVEATTRIBUTEHDR, *PDRIVEATTRIBUTEHDR, *LPDRIVEATTRIBUTEHDR;

// атрибут S.M.A.R.T
typedef struct _DRIVEATTRIBUTE
{
    // Идентификатор атрибута
    BYTE    bAttrID;
    // Тип атрибута (критический, счетчик ошибок и т.д.)
    WORD    wStatusFlags;
    // Значение атрибута
    BYTE    bAttrValue;
    // Худшее, зафиксированное, значение
    BYTE    bWorstValue;
    // Значение атрибута, ненормализованное
    BYTE    bRawValue[6];
    BYTE    bReserved;
}
DRIVEATTRIBUTE, *PDRIVEATTRIBUTE, *LPDRIVEATTRIBUTE;

// Пареметр Threshold (пороговое значение) атрибута S.M.A.R.T
typedef    struct    _ATTRTHRESHOLD
{
    // Идентификатор атрибута
    BYTE    bAttrID;
    // Значение
    BYTE    bWarrantyThreshold;
    BYTE    bReserved[10];
}
ATTRTHRESHOLD, *PATTRTHRESHOLD, *LPATTRTHRESHOLD;


* This source code was highlighted with Source Code Highlighter.

Все начинается с получения дескриптора диска:

HANDLE hDrive = CreateFile("\\\\.\\PHYSICALDRIVE0", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

* This source code was highlighted with Source Code Highlighter.

Здесь 0 в "\\\\.\\PHYSICALDRIVE0" означает номер физического диска в системе.

После получения дескриптора необходимо заполнить структуру SENDCMDINPARAMS

SENDCMDINPARAMS cmdIn = {0};
// Размер буфера для получения атрибутов
cmdIn.cBufferSize = READ_ATTRIBUTE_BUFFER_SIZE;
// Комманда IDE
cmdIn.irDriveRegs.bCommandReg = SMART_CMD;
// Запрос на чтение атрибутов
cmdIn.irDriveRegs.bFeaturesReg = READ_ATTRIBUTES;
// Младший разряд, указывающий на номер цилиндра
cmdIn.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
// Старший разряд, указывающий на номер цилиндра
cmdIn.irDriveRegs.bCylHighReg = SMART_CYL_HI;
// Регистр количества секторов
cmdIn.irDriveRegs.bSectorCountReg = 1;
// Регистр номера сектора
cmdIn.irDriveRegs.bSectorNumberReg = 1;
// Регистр диска\головки IDE
cmdIn.irDriveRegs.bDriveHeadReg = 0xA0 | (((BYTE)nDrive & 1) << 4);

* This source code was highlighted with Source Code Highlighter.

Запрашиваем атрибуты:

BYTE bOutAttributes[sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1] = {0};
DeviceIoControl(hDrive, SMART_RCV_DRIVE_DATA, &cmdIn, sizeof(cmdIn), bOutAttributes, sizeof(bOutAttributes), &dwReturn, NULL);

* This source code was highlighted with Source Code Highlighter.

При успешном выполнении атрибуты будут записаны в буффер bOutAttributes. Преобразуем указатель, чтобы с ним можно было работать как с массивом структур

// Заголовок
LPDRIVEATTRIBUTEHDR lpAttrHdr = (LPDRIVEATTRIBUTEHDR)(((LPSENDCMDOUTPARAMS)bOutAttributes)->bBuffer);
// Указатель на атрибуты
LPDRIVEATTRIBUTE lpAttr    = (LPDRIVEATTRIBUTE)(lpAttrHdr->bData);

// Что-то делаем с полученными атрибутами
// NUM_ATTRIBUTE_STRUCTS - максимально возможное количество атрибутов S.M.A.R.T
// в настоящий момент равняется 30-ти
for(int iAttr = 0; iAttr < NUM_ATTRIBUTE_STRUCTS; iAttr++)
{
}


* This source code was highlighted with Source Code Highlighter.

Получим пороговые значения (Threshold), делается это почти так же, как и в случае чтение атрибутов. Заполняется структура SENDCMDINPARAMS, меняются два параметра

cmdIn.cBufferSize = READ_THRESHOLD_BUFFER_SIZE;
cmdIn.irDriveRegs.bFeaturesReg = READ_THRESHOLDS;

// Получаем значения
BYTE bOutThresholds[sizeof(SENDCMDOUTPARAMS) + READ_THRESHOLD_BUFFER_SIZE - 1] = {0};
bResult = DeviceIoControl(drive, SMART_RCV_DRIVE_DATA, &cmdIn, sizeof(cmdIn), bOutThresholds, sizeof(bOutThresholds), &dwReturn, NULL);

// Получем указатели
LPDRIVEATTRIBUTEHDR lpThrHdr = (LPDRIVEATTRIBUTEHDR)(((LPSENDCMDOUTPARAMS)bOutThresholds)->bBuffer);
LPATTRTHRESHOLD lpThresholds = (LPATTRTHRESHOLD)(lpThrHdr->bData);

// Что-то делаем с полученными значениями
for(int iAttr = 0; iAttr < NUM_ATTRIBUTE_STRUCTS; iAttr++)
{
}


* This source code was highlighted with Source Code Highlighter.

Для простоты работы я обернул получение информации в класс CSMARTInfo
// Структура-обертка для S.M.A.R.T атрибута
typedef struct SMARTAttribute
{
    int nId;

    BYTE bValue;
    BYTE bWorst;
    BYTE bThreshold;

    WORD wStatusFlags;

    __int64    nRaw;
}
SMARTAttribute;

// Класс для работы со S.M.A.R.T
class CSMARTInfo
{
public:
    CSMARTInfo();
    ~CSMARTInfo();

public:
    // Вспомогательная функция, возвращающая
    // название модели жесткого диска
    BOOL GetDriveModel(int nDrive, wstring &strModel);

    // Поддерживается ли S.M.A.R.T на указанном диске
    BOOL IsSmartSupported(int nDrive);
    // Включить S.M.A.R.T на указанном диске
    BOOL EnableSmart(int nDrive);

    // Получить информацию о диске
    BOOL GetInfo(int nDrive, GETVERSIONINPARAMS &info);
    // Получить S.M.A.R.T атрибуты
    BOOL GetAttributes(int nDrive, vector<SMARTAttribute> &attributes);
};


* This source code was highlighted with Source Code Highlighter.


Пока я разбирался со S.M.A.R.T сделал интересное наблюдение. Стандарт-стандартом, а вот значение и предназначение атрибутов, так же как и их трактовка у различных производителей своя. Например мой Seagate показывает жуткое, постоянно увеличивающееся, значение атрибутов Raw Read Error Rate (ID = 0x1) и Seek Error Rate (ID = 0x7). Я попытался найти информацию об этих параметрах применительно к Seagate, но так ничего и не нашел, не считая сообщений пользователей на данную тему на форуме Seagate и заверетильные ответы тех. поддержки, что все нормально, так должно и быть.

Использовать S.M.A.R.T можно не только для диагностики и предсказания проблем, но и, например, для проверки — а не б\у ли мы купили, атрибут Power-On Hours (ID=0х9, число часов, проведенных во включенном состоянии) или Device Power Cycle Count (ID=0x0C, количество полных циклов включения-выключения диска). А не падал ли этот диск в процессе работы (в смысле физически, на пол) — атрибут G-sense error rate (0хBF, количество ошибок, возникающих в результате ударных нагрузок)
Tags:
Hubs:
+35
Comments 43
Comments Comments 43

Articles