Windows 10의 NVMe 명령어들

드디어 나온 Windows 10의 NVM Express Admin Command 명령어들에 대해서 알아보자.

Windows 10에서 제공하는 IOCTL 코드는 IOCTL_STORAGE_QUERY_PROPERTY와 IOCTL_STORAGE_PROTOCOL_COMMAND 두 가지다. 그렇다면 후자를 사용하면 모든 명령어에 대한 일반적인 구현이 가능할 거라 생각할 거다. 아니다. 후자는 지정된 “Vendor specific” 명령어만 사용할 수 있다. 따라서 우리가 알고 있는 일반적인 명령어는 다음의 세 가지만 사용할 수 있는 거다. 만약 다른 명령에 대해 passthrough를 원한다면 ‘나래온 NVMe 툴‘ 카테고리의 다른 글들을 보시라.

  1. Identify
  2. Get Log Page
  3. Get Features

다만 문제가 하나 있는데, Get Features의 경우 07h(Number of Queues)를 가져오는 데 오류를 발생시킨다. 2017년 2월 현재 해당 문제가 발생하지 않는 드라이버는, 삼성 NVMe 드라이버 2.1버전 하나 뿐이다. 다른 제품의 경우는 역시 ‘나래온 NVMe 툴‘ 카테고리의 다른 글들을 참고해 다른 방법으로 시도하기 바란다.

풀버전 소스

Delphi
C++ (Identify)
C++ (Get Features)

1 comment on “Windows 10의 NVMe 명령어들

  1. 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;
    }

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다