Finally, from Windows 10, NVM Express Admin Command passthrough interface has arrived.
Windows 10 provides two IOCTLs, IOCTL_STORAGE_QUERY_PROPERTY and IOCTL_STORAGE_PROTOCOL_COMMAND. Then you would think that second one would be one-size-fits-all IOCTL, but it’s not. That one can only be used for “Vendor specific” command. Therefore, only three commands in known commands can be used. If you want others, you should use driver specific passthrough interface. I wrote about them in ‘Naraeon NVMe Tools‘ category.
- Identify
- Get Log Page
- Get Features
But there is an issue. Get Features with 07h(Number of Queues) would cause error. In Feb 2017, there is only one driver that correctly get this information. Samsung NVMe driver 2.1. If you have other product and want to get this information, try other methods to passthrough, which provided in ‘Naraeon NVMe Tools‘ category.
Full version source
I am trying to Test self test on WDC PC SN720 SDAPNTW-512G-1006 drive (NVMe 1.3 interface is supported) on Windows 10 RS3 OS but DeviceIoControl() method returned 0 and GetLastError() method return error code 87. NVMe version of the drive is 1.3 as per datasheet and “Drive self Test” bit is enabled in Idenitfy structure.
Can you suggest what could be wrong with the following code.
BOOL NVMeTest::NVMeSelfTest(std::string driveHandleStr)
{
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;
HANDLE hPhyDrive = CreateFile(LPCSTR(driveHandleStr.c_str()),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPhyDrive == INVALID_HANDLE_VALUE)
{
//printf(“Invalid handle!”);
return FALSE;
}
//
// Allocate buffer for use.
//
ULONG testlength = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND, Command);
bufferLength = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND, Command) + STORAGE_PROTOCOL_COMMAND_LENGTH_NVME +
4096 + sizeof(NVME_ERROR_INFO_LOG);
buffer = malloc(bufferLength);
ZeroMemory(buffer, bufferLength);
if (buffer == NULL) {
//printf(“DeviceNVMeQueryProtocolDataTest: allocate buffer failed, exit.\n”);
return FALSE;
}
PSTORAGE_PROTOCOL_COMMAND protocolCommand = (PSTORAGE_PROTOCOL_COMMAND)buffer;
protocolCommand->Version = STORAGE_PROTOCOL_STRUCTURE_VERSION;
protocolCommand->Length = sizeof(STORAGE_PROTOCOL_COMMAND);
protocolCommand->ProtocolType = ProtocolTypeNvme;
protocolCommand->Flags = STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST;
protocolCommand->CommandLength = STORAGE_PROTOCOL_COMMAND_LENGTH_NVME;
protocolCommand->ErrorInfoLength = sizeof(NVME_ERROR_INFO_LOG);
// protocolCommand->DataFromDeviceTransferLength = 4096;
protocolCommand->DataToDeviceTransferLength = 4096; // 4096;
protocolCommand->TimeOutValue = 180;
protocolCommand->ErrorInfoOffset = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND, Command) + STORAGE_PROTOCOL_COMMAND_LENGTH_NVME;
// protocolCommand->DataFromDeviceBufferOffset = protocolCommand->ErrorInfoOffset + protocolCommand->ErrorInfoLength;
protocolCommand->DataToDeviceBufferOffset = protocolCommand->ErrorInfoOffset + protocolCommand->ErrorInfoLength;
protocolCommand->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND;
PNVME_COMMAND command = (PNVME_COMMAND)protocolCommand->Command;
command->CDW0.OPC = 0x14;
//command->NSID = 0x01;
command->u.GENERAL.CDW10 = 0x01;
//
// Send request down.
//
result = DeviceIoControl(hPhyDrive,
IOCTL_STORAGE_PROTOCOL_COMMAND,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
if (result == 0)
{
printf(“Error occurred %d\n”, GetLastError()); // Returns 87
free(buffer);
return FALSE;
}
return TRUE;
}
IOCTL_STORAGE_PROTOCOL_COMMAND support Vendor cmd only
Device self test is a Admin cmd, which is not supported by inbox driver API.