NVMe S.M.A.R.T。数据检索
NVMe S.M.A.R.T. data retrieval
我开发了一个程序,它能够在 WMI 的帮助下检索 SATA 设备的智能数据,如下所示:
Get-WmiObject -Namespace 'Root\WMI' -Class 'MSStorageDriver_ATAPISMartData' | Select -ExpandProperty Vendorspecific
但是,它无法获得 NVMe 的。你们有人知道找回它的方法吗? (即使它不是 Powershell cmdlet)
显然微软文档已经解决了这个问题:
https://docs.microsoft.com/en-us/windows/win32/fileio/working-with-nvme-devices
但是,如果有人设法解决它并向我发送源代码,我将无法执行代码,将不胜感激
我刚刚发现微软实际上有一个关于这个问题的半好的文档。所以你检索的方式 S.M.A.R.T。来自 NVMe 的 C++ 如下:
我对 wszDrive 的定义是:#define wszDrive L"\\.\PhysicalDrive1"
您可以指定从0开始的驱动器编号(第一个驱动器)
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
hDevice = CreateFileW((LPWSTR)wszDrive, // drive to open
0, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
FILE_FLAG_OVERLAPPED, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
return (FALSE);
}
BOOL result;
PVOID buffer = NULL;
ULONG bufferLength = 0;
ULONG returnedLength = 0;
PSTORAGE_PROPERTY_QUERY query = NULL;
PSTORAGE_PROTOCOL_SPECIFIC_DATA protocolData = NULL;
PSTORAGE_PROTOCOL_DATA_DESCRIPTOR protocolDataDescr = NULL;
//
// Allocate buffer for use.
//
bufferLength = FIELD_OFFSET(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + NVME_MAX_LOG_SIZE;
buffer = malloc(bufferLength);
if (buffer == NULL) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: allocate buffer failed, exit.\n"));
goto exit;
}
//
// Initialize query data structure to get Identify Controller Data.
//
ZeroMemory(buffer, bufferLength);
query = (PSTORAGE_PROPERTY_QUERY)buffer;
protocolDataDescr = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;
query->PropertyId = StorageDeviceProtocolSpecificProperty;
query->QueryType = PropertyStandardQuery;
protocolData->ProtocolType = ProtocolTypeNvme;
protocolData->DataType = NVMeDataTypeLogPage;
protocolData->ProtocolDataRequestValue = NVME_LOG_PAGE_HEALTH_INFO;
protocolData->ProtocolDataRequestSubValue = 0; // This will be passed as the lower 32 bit of log page offset if controller supports extended data for the Get Log Page.
protocolData->ProtocolDataRequestSubValue2 = 0; // This will be passed as the higher 32 bit of log page offset if controller supports extended data for the Get Log Page.
protocolData->ProtocolDataRequestSubValue3 = 0; // This will be passed as Log Specific Identifier in CDW11.
protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
protocolData->ProtocolDataLength = sizeof(NVME_HEALTH_INFO_LOG);
//
// Send request down.
//
result = DeviceIoControl(hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
if (!result || (returnedLength == 0)) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log failed. Error Code %d.\n"), GetLastError());
goto exit;
}
//
// Validate the returned data.
//
if ((protocolDataDescr->Version != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR)) ||
(protocolDataDescr->Size != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log - data descriptor header not valid.\n"));
return 0;
}
protocolData = &protocolDataDescr->ProtocolSpecificData;
if ((protocolData->ProtocolDataOffset < sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA)) ||
(protocolData->ProtocolDataLength < sizeof(NVME_HEALTH_INFO_LOG))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log - ProtocolData Offset/Length not valid.\n"));
goto exit;
}
//
// SMART/Health Information Log Data
//
{
PNVME_HEALTH_INFO_LOG smartInfo = (PNVME_HEALTH_INFO_LOG)((PCHAR)protocolData + protocolData->ProtocolDataOffset);
// print the S.M.A.R.T. data which you need
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log Data - Temperature %d.\n"), ((ULONG)smartInfo->Temperature[1] << 8 | smartInfo->Temperature[0]) - 273);
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log Data - Available Spares: %d.\n"), ((ULONG)smartInfo->AvailableSpare));
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: ***SMART/Health Information Log succeeded***.\n"));
}
exit:
我开发了一个程序,它能够在 WMI 的帮助下检索 SATA 设备的智能数据,如下所示:
Get-WmiObject -Namespace 'Root\WMI' -Class 'MSStorageDriver_ATAPISMartData' | Select -ExpandProperty Vendorspecific
但是,它无法获得 NVMe 的。你们有人知道找回它的方法吗? (即使它不是 Powershell cmdlet)
显然微软文档已经解决了这个问题: https://docs.microsoft.com/en-us/windows/win32/fileio/working-with-nvme-devices 但是,如果有人设法解决它并向我发送源代码,我将无法执行代码,将不胜感激
我刚刚发现微软实际上有一个关于这个问题的半好的文档。所以你检索的方式 S.M.A.R.T。来自 NVMe 的 C++ 如下:
我对 wszDrive 的定义是:#define wszDrive L"\\.\PhysicalDrive1"
您可以指定从0开始的驱动器编号(第一个驱动器)
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
hDevice = CreateFileW((LPWSTR)wszDrive, // drive to open
0, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
FILE_FLAG_OVERLAPPED, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
return (FALSE);
}
BOOL result;
PVOID buffer = NULL;
ULONG bufferLength = 0;
ULONG returnedLength = 0;
PSTORAGE_PROPERTY_QUERY query = NULL;
PSTORAGE_PROTOCOL_SPECIFIC_DATA protocolData = NULL;
PSTORAGE_PROTOCOL_DATA_DESCRIPTOR protocolDataDescr = NULL;
//
// Allocate buffer for use.
//
bufferLength = FIELD_OFFSET(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + NVME_MAX_LOG_SIZE;
buffer = malloc(bufferLength);
if (buffer == NULL) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: allocate buffer failed, exit.\n"));
goto exit;
}
//
// Initialize query data structure to get Identify Controller Data.
//
ZeroMemory(buffer, bufferLength);
query = (PSTORAGE_PROPERTY_QUERY)buffer;
protocolDataDescr = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;
query->PropertyId = StorageDeviceProtocolSpecificProperty;
query->QueryType = PropertyStandardQuery;
protocolData->ProtocolType = ProtocolTypeNvme;
protocolData->DataType = NVMeDataTypeLogPage;
protocolData->ProtocolDataRequestValue = NVME_LOG_PAGE_HEALTH_INFO;
protocolData->ProtocolDataRequestSubValue = 0; // This will be passed as the lower 32 bit of log page offset if controller supports extended data for the Get Log Page.
protocolData->ProtocolDataRequestSubValue2 = 0; // This will be passed as the higher 32 bit of log page offset if controller supports extended data for the Get Log Page.
protocolData->ProtocolDataRequestSubValue3 = 0; // This will be passed as Log Specific Identifier in CDW11.
protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
protocolData->ProtocolDataLength = sizeof(NVME_HEALTH_INFO_LOG);
//
// Send request down.
//
result = DeviceIoControl(hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
if (!result || (returnedLength == 0)) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log failed. Error Code %d.\n"), GetLastError());
goto exit;
}
//
// Validate the returned data.
//
if ((protocolDataDescr->Version != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR)) ||
(protocolDataDescr->Size != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log - data descriptor header not valid.\n"));
return 0;
}
protocolData = &protocolDataDescr->ProtocolSpecificData;
if ((protocolData->ProtocolDataOffset < sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA)) ||
(protocolData->ProtocolDataLength < sizeof(NVME_HEALTH_INFO_LOG))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log - ProtocolData Offset/Length not valid.\n"));
goto exit;
}
//
// SMART/Health Information Log Data
//
{
PNVME_HEALTH_INFO_LOG smartInfo = (PNVME_HEALTH_INFO_LOG)((PCHAR)protocolData + protocolData->ProtocolDataOffset);
// print the S.M.A.R.T. data which you need
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log Data - Temperature %d.\n"), ((ULONG)smartInfo->Temperature[1] << 8 | smartInfo->Temperature[0]) - 273);
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log Data - Available Spares: %d.\n"), ((ULONG)smartInfo->AvailableSpare));
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: ***SMART/Health Information Log succeeded***.\n"));
}
exit: