S.M.A.R.T это технология оценки состояния жесткого диска, помогающая оценить текущее состояние и предсказать возможные проблемы и выход устройства из строя. Атрибуты S.M.A.R.T условно можно разделить на две группы: параметры, отражающие процесс изнашивания (старения) диска и текущие параметры (например, параметры производительности).
Каждый атрибут имеет идентификатор, тип (критический, показатель производительности, счетчик ошибок, счетчик событий), текущее значение, пороговое значение (если текущее меньше порогового — начинайте искать новый диск), самое низкое, зафиксированное, значение атрибута. Описание каждого атрибута можно посмотреть здесь.
На этом теоретическая часть заканчивается, перейдем к практике. Напишем программу, которая будет считывать и отображать атрибуты S.M.A.R.T. Скачать готовую программу с исходниками можно здесь.
Для начала определим структуры, в которые мы будем получать интересующую нас информацию:
Все начинается с получения дескриптора диска:
Здесь 0 в "\\\\.\\PHYSICALDRIVE0" означает номер физического диска в системе.
После получения дескриптора необходимо заполнить структуру SENDCMDINPARAMS
Запрашиваем атрибуты:
При успешном выполнении атрибуты будут записаны в буффер bOutAttributes. Преобразуем указатель, чтобы с ним можно было работать как с массивом структур
Получим пороговые значения (Threshold), делается это почти так же, как и в случае чтение атрибутов. Заполняется структура SENDCMDINPARAMS, меняются два параметра
Для простоты работы я обернул получение информации в класс CSMARTInfo
Пока я разбирался со 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, количество ошибок, возникающих в результате ударных нагрузок)
Каждый атрибут имеет идентификатор, тип (критический, показатель производительности, счетчик ошибок, счетчик событий), текущее значение, пороговое значение (если текущее меньше порогового — начинайте искать новый диск), самое низкое, зафиксированное, значение атрибута. Описание каждого атрибута можно посмотреть здесь.
На этом теоретическая часть заканчивается, перейдем к практике. Напишем программу, которая будет считывать и отображать атрибуты 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, количество ошибок, возникающих в результате ударных нагрузок)