none
NVMe Passthrough for Windows 10 IOCTL_STORAGE_PROTOCOL_COMMAND OPC:0xc0 error code:87 RRS feed

  • Question

  • I try to send vendor-specific cmd 0xc0 for NVMe passthrough. I have read this document in great detail, however, I can not seem to get the pass-through mechanism to work against NVMe SSD.  

    https://msdn.microsoft.com/en-us/library/windows/desktop/mt718131(v=vs.85).aspx

    Has anyone discovered any caveats to this procedure?  The obvious one is the Log page 5 support and I have tested my code without success.  I inspected log page 5 and the format appears correct.  The error error returned is 87 (Parameter Error).

    Below is my code:

            BOOL    result;
    PVOID   buffer = NULL;
    ULONG   bufferLength = 0;
    ULONG   returnedLength = 0;
    PSTORAGE_PROTOCOL_COMMAND protocolCommand = NULL;
    PNVME_COMMAND command = NULL;

    //
    // Allocate buffer for use.
    //
    bufferLength = FIELD_OFFSET(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + 4096;
    buffer = malloc(bufferLength);

    if (buffer == NULL) {
    _tprintf(_T("GetPanicLog: allocate buffer failed, error code:%d exit.\n"), GetLastError());
    return GetLastError();
    }
    ZeroMemory(buffer, bufferLength);

    ZeroMemory(buffer, bufferLength);
    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->TimeOutValue = 10;
    protocolCommand->ErrorInfoOffset = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND, Command) + STORAGE_PROTOCOL_COMMAND_LENGTH_NVME;
    protocolCommand->DataFromDeviceBufferOffset = protocolCommand->ErrorInfoOffset + protocolCommand->ErrorInfoLength;
    protocolCommand->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND;

    command = (PNVME_COMMAND)protocolCommand->Command;
     
    command->CDW0.OPC = 0xc0;
    command->u.GENERAL.CDW10 = 0;
    command->u.GENERAL.CDW12 = 8;
    command->u.GENERAL.CDW13 = 0;
    command->u.GENERAL.CDW15 = 0;

    //  
    // Send request down.  
    //  

    result = DeviceIoControl(handle,
    IOCTL_STORAGE_PROTOCOL_COMMAND,
    buffer,
    bufferLength,
    buffer,
    bufferLength,
    &returnedLength,
    NULL
    );

    Thursday, June 1, 2017 11:08 AM

Answers

  • the bufferLength should be looked like below, after that I can send passthrough cmd to device successfully.

    int bufferLength = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND,Command) +

                STORAGE_PROTOCOL_COMMAND_LENGTH_NVME +
                4096 +
                sizeof(NVME_ERROR_INFO_LOG);
    • Marked as answer by yufeng0571 Friday, July 7, 2017 3:31 AM
    Friday, July 7, 2017 3:31 AM

All replies

  • Thursday, June 1, 2017 11:20 AM
  • Hi Don

    Thank you very much for your quick reply. Do you mean the Windows driver block my cmd? But the MSDN did said it could support vendor-specific opcode 0xc0.

    side1out in your linkage said he could send passthrough cmd

    https://msdn.microsoft.com/en-us/library/windows/desktop/mt718131(v=vs.85).aspx

    Thursday, June 1, 2017 11:53 AM
  • The Microsoft NVME driver is definitely limited in its capabilities.  I haven't done much with it, most of my work was helping a vendor fix the OFA driver so it wasn't total crap.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Thursday, June 1, 2017 6:33 PM
  • the bufferLength should be looked like below, after that I can send passthrough cmd to device successfully.

    int bufferLength = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND,Command) +

                STORAGE_PROTOCOL_COMMAND_LENGTH_NVME +
                4096 +
                sizeof(NVME_ERROR_INFO_LOG);
    • Marked as answer by yufeng0571 Friday, July 7, 2017 3:31 AM
    Friday, July 7, 2017 3:31 AM
  • I copy the code from MSDN,but after calling  DeviceIoControl(),then getLastError()=1,could you give me a recommend?

    Below is my code:

    INT32 ret = 0;
     ULONG returnedLength = 0;
     ULONG bufferLength = 0;
     PVOID  buffer = NULL;
     PVOID cmdData = NULL;
     PSTORAGE_PROTOCOL_COMMAND protocolCommand = NULL;
     PNVME_COMMAND command = NULL;
     PSCT_DATA sctData = NULL;
     //bufferLength = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND, Command) + STORAGE_PROTOCOL_COMMAND_LENGTH_NVME + 4096 + sizeof(NVME_ERROR_INFO_LOG);
     cout << "bufferLength========== " << bufferLength << endl;
     bufferLength = 512*9;
     buffer = malloc(bufferLength);
     ZeroMemory(buffer, bufferLength);
     cmdData = malloc(512);
     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->TimeOutValue = 10;
     protocolCommand->ErrorInfoOffset = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND, Command) + STORAGE_PROTOCOL_COMMAND_LENGTH_NVME;
     protocolCommand->DataFromDeviceBufferOffset = protocolCommand->ErrorInfoOffset + protocolCommand->ErrorInfoLength;
     protocolCommand->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND;
     command = (PNVME_COMMAND)protocolCommand->Command;
     sctData = (PSCT_DATA)cmdData;
     sctData->actionCode = 0xC000 ^ KEY_WORD;
     sctData->functionCode = 0x0 ^ KEY_WORD;
     //*(UINT16*)cmdData = sctData.actionCode ^ KEY_WORD;
     //*(UINT16*)(cmdData + 2) = sctData.functionCode ^ KEY_WORD;
     command->CDW0.OPC = 0xC0;
     command->CDW0.FUSE = 0;
     command->CDW0.Reserved0 = 0;
     command->CDW0.PSDT = 0;
     //command->CDW0.AsUlong = 0;
     command->NSID = 0x01;
     //command->PRP1 = (ULONGLONG)cmdData;
     //command->PRP2 = (ULONGLONG)cmdData;
     command->u.GENERAL.CDW10 = 0x01;
     command->u.GENERAL.CDW11 = 0x01;
     command->u.GENERAL.CDW12 = 0x0;
     command->u.GENERAL.CDW13 = 0x0;
     command->u.GENERAL.CDW14 = 0x0;
     command->u.GENERAL.CDW15 = 0x0;
     HANDLE diskHandle = NULL;
     diskHandle = CreateFile("\\\\.\\PhysicalDrive1",
      GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);
     //IOCTL_STORAGE_PROTOCOL_COMMAND
     ret = DeviceIoControl(diskHandle,
      IOCTL_STORAGE_PROTOCOL_COMMAND,
      buffer,
      bufferLength,
      buffer,
      bufferLength,
      &returnedLength,
      NULL
     );
     
     cout << "getlasterror() = " << GetLastError() << endl;

    Thursday, August 3, 2017 8:31 AM
  • how did you set your effect log for cmd 0xC0?thank you!
    Monday, February 26, 2018 7:18 AM