📜 ⬆️ ⬇️

Get SMART attributes

SMART is a hard disk state estimation technology that helps to assess the current state and predict possible problems and device failure. SMART attributes can be divided into two groups: parameters reflecting the process of wear (aging) of a disk and current parameters (for example, performance parameters).

Each attribute has an identifier, type (critical, performance indicator, error counter, event counter), current value, threshold value (if the current is less than the threshold - start looking for a new disk), the lowest fixed value of the attribute. A description of each attribute can be found here .

This theoretical part ends, let's move on to practice. Write a program that will read and display the attributes SMART Download the finished program with the source code here .


')
To begin with, we will define the structures in which we will receive information of interest to us:
//
typedef struct _DRIVEATTRIBUTEHDR
{
//
WORD wRevision;
//
BYTE bData[1];
}
DRIVEATTRIBUTEHDR, *PDRIVEATTRIBUTEHDR, *LPDRIVEATTRIBUTEHDR;

// SMART
typedef struct _DRIVEATTRIBUTE
{
//
BYTE bAttrID;
// (, ..)
WORD wStatusFlags;
//
BYTE bAttrValue;
// , ,
BYTE bWorstValue;
// ,
BYTE bRawValue[6];
BYTE bReserved;
}
DRIVEATTRIBUTE, *PDRIVEATTRIBUTE, *LPDRIVEATTRIBUTE;

// Threshold ( ) SMART
typedef struct _ATTRTHRESHOLD
{
//
BYTE bAttrID;
//
BYTE bWarrantyThreshold;
BYTE bReserved[10];
}
ATTRTHRESHOLD, *PATTRTHRESHOLD, *LPATTRTHRESHOLD;


* This source code was highlighted with Source Code Highlighter .

It all starts with getting a disk handle:

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 .

Here 0 in "\\\\. \\ PHYSICALDRIVE0" means the number of the physical disk in the system.

After receiving the descriptor, you must fill in the structure 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 .

Attribute attributes:

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 .

If successful, the attributes will be written to the bOutAttributes buffer . Transform the pointer so that you can work with it as with an array of structures

//
LPDRIVEATTRIBUTEHDR lpAttrHdr = (LPDRIVEATTRIBUTEHDR)(((LPSENDCMDOUTPARAMS)bOutAttributes)->bBuffer);
//
LPDRIVEATTRIBUTE lpAttr = (LPDRIVEATTRIBUTE)(lpAttrHdr->bData);

// -
// NUM_ATTRIBUTE_STRUCTS - SMART
// 30-
for ( int iAttr = 0; iAttr < NUM_ATTRIBUTE_STRUCTS; iAttr++)
{
}


* This source code was highlighted with Source Code Highlighter .

We get the threshold values ​​( Threshold ), it is done in almost the same way as in the case of reading attributes. SENDCMDINPARAMS structure is filled , two parameters change

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 .

For ease of work, I wrapped up getting information in the CSMARTInfo class .
// - SMART
typedef struct SMARTAttribute
{
int nId;

BYTE bValue;
BYTE bWorst;
BYTE bThreshold;

WORD wStatusFlags;

__int64 nRaw;
}
SMARTAttribute;

// SMART
class CSMARTInfo
{
public :
CSMARTInfo();
~CSMARTInfo();

public :
// ,
//
BOOL GetDriveModel( int nDrive, wstring &strModel);

// SMART
BOOL IsSmartSupported( int nDrive);
// SMART
BOOL EnableSmart( int nDrive);

//
BOOL GetInfo( int nDrive, GETVERSIONINPARAMS &info);
// SMART
BOOL GetAttributes( int nDrive, vector<SMARTAttribute> &attributes);
};


* This source code was highlighted with Source Code Highlighter .


While I was dealing with SMART made an interesting observation. The standard is the standard, but the meaning and purpose of the attributes, as well as their interpretation from different manufacturers, is different. For example, my Seagate shows the creepy, ever-increasing value of the Raw Read Error Rate (ID = 0x1) and Seek Error Rate (ID = 0x7) attributes. I tried to find information about these parameters in relation to Seagate, but I didn’t find anything, apart from the users' messages on this topic on the Seagate forum and the certified answers of those. support that everything is fine, so it should be.

You can use SMART not only to diagnose and predict problems, but also, for example, to check whether you bought the item, not the used one, the Power-On Hours attribute (ID = 0x9, number of hours spent on power) or Device Power Cycle Count (ID = 0x0C, the number of full cycles of on-off disk). Did this disk fall in the process of working (physically, on the floor) - the attribute G-sense error rate (0xBF, the number of errors resulting from shock loads)

Source: https://habr.com/ru/post/78652/


All Articles