ken-yossy / nvmetool-win

Communicate with NVMe SSD using Windows' inbox device driver
Other
83 stars 48 forks source link

write, read fail #26

Closed fadu-dufresne closed 2 years ago

fadu-dufresne commented 2 years ago

Hello!

I tried to read(-r), write(-w) to my nvme device using the tool you produced, but it failed. Scsi status comes out as 02h. But 'get log page' works very well. Here is snapshot.

Can you tell me what the problem is?

ken-yossy commented 2 years ago

Hi!

Thank you for your report.

From your important information, it seems that your read and write operation failed in status "CHECK CONDITION" (status = 02h) with "Invalid Field in CDB" (Sense Key = 05h, ASC = 24h, ASCQ = 00h). So, it seems that there was something wrong with the value in the Command Descriptor Block (CDB) using in read and write operations.

Constructing CDB for read operation is in iReadViaSCSIPassThrough() in NVMeSCSIPassThrough.c as follows:

        sptwb_ex.spt.Cdb[0] = SCSIOP_READ;
        sptwb_ex.spt.Cdb[5] = 0; // Starting LBA
        sptwb_ex.spt.Cdb[8] = 1; // TRANSFER LENGTH

But this code is working in my environment (Win10 with Western Digital's NVMe SSD and Samsung's NVMe SSD). If your environment has something special, please let me know.

Hope it help you.

Note: in this tool, read and write operations use "SCSI PassThrough" mechanism in Windows. it enables us to issue some NVMe commands to drives via corresponding SCSI commands (Windows' device driver stack translates it into NVMe command).

Regards, Ken

fadu-dufresne commented 2 years ago

Thank you for your help.

I checked my CDB option, but it has no problem, I think. T-T

image

I am also using Windows 10, so there seems to be no environmental difference.

I will keep looking for the cause. Thank you again. :)

ken-yossy commented 2 years ago

Hi!

I've just found that Microsoft says that SCSI commands READ(16) and WRITE(16) are used to issue Read and Write commands to NVMe drive via SCSI PassThrough mechanism in this page, but I use READ(10) and WRITE(10) in this tool.

So, this difference might be one of the causes of your problem.

Could you please try applying the following patch to NVMeSCSIPassThrough.c and sending Read command to your NVMe drive? With this patch, this tool changes to use READ(16) and WRITE(16) instead of READ(10) and WRITE(10).

In my environment, after applying this patch, Read command for an NVMe SSD has successfully completed.

@ -50,6 +50,7 @@ typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER_EX
 #define CDB6GENERIC_LENGTH                   6
 #define CDB10GENERIC_LENGTH                  10
 #define CDB12GENERIC_LENGTH                  12
+#define CDB16GENERIC_LENGTH                  16
 #define SETBITON                             1
 #define SETBITOFF                            0

@ -586,7 +587,7 @@ int iWriteViaSCSIPassThrough(HANDLE _hDevice)
         sptdwb_ex.sptd.Version                  = 0;
         sptdwb_ex.sptd.Length                   = sizeof(SCSI_PASS_THROUGH_DIRECT_EX);
         sptdwb_ex.sptd.ScsiStatus               = 0;
-        sptdwb_ex.sptd.CdbLength                = CDB10GENERIC_LENGTH;
+        sptdwb_ex.sptd.CdbLength                = CDB16GENERIC_LENGTH;
         sptdwb_ex.sptd.StorAddressLength        = sizeof(STOR_ADDR_BTL8);
         sptdwb_ex.sptd.SenseInfoLength          = SPT_SENSE_LENGTH;
         sptdwb_ex.sptd.DataOutBuffer            = (PVOID)databuffer;
@ -602,9 +603,9 @@ int iWriteViaSCSIPassThrough(HANDLE _hDevice)
         sptdwb_ex.StorAddress.Target            = 0;
         sptdwb_ex.StorAddress.Lun               = 0;
         sptdwb_ex.sptd.SenseInfoOffset          = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER_EX, ucSenseBuf);
-        sptdwb_ex.sptd.Cdb[0]                   = SCSIOP_WRITE;
-        sptdwb_ex.sptd.Cdb[5]                   = 0; // Starting LBA
-        sptdwb_ex.sptd.Cdb[8]                   = 1; // TRANSFER LENGTH
+        sptdwb_ex.sptd.Cdb[0]                   = SCSIOP_WRITE16;
+        sptdwb_ex.sptd.Cdb[9]                   = 0; // Starting LBA
+        sptdwb_ex.sptd.Cdb[13]                  = 1; // TRANSFER LENGTH

         length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER_EX);
         iResult = iIssueDeviceIoControl(
@ -642,16 +643,16 @@ int iWriteViaSCSIPassThrough(HANDLE _hDevice)
         sptdwb.sptd.PathId              = 0;
         sptdwb.sptd.TargetId            = 0;
         sptdwb.sptd.Lun                 = 0;
-        sptdwb.sptd.CdbLength           = CDB10GENERIC_LENGTH;
+        sptdwb.sptd.CdbLength           = CDB16GENERIC_LENGTH;
         sptdwb.sptd.SenseInfoLength     = SPT_SENSE_LENGTH;
         sptdwb.sptd.SenseInfoOffset     = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
         sptdwb.sptd.DataIn              = SCSI_IOCTL_DATA_OUT;
         sptdwb.sptd.DataTransferLength  = sectorSize;
         sptdwb.sptd.TimeOutValue        = 5;
         sptdwb.sptd.DataBuffer          = databuffer;
-        sptdwb.sptd.Cdb[0]              = SCSIOP_WRITE;
-        sptdwb.sptd.Cdb[5]              = 0; // Starting LBA
-        sptdwb.sptd.Cdb[8]              = 1; // TRANSFER LENGTH
+        sptdwb.sptd.Cdb[0]              = SCSIOP_WRITE16; // 8Ah
+        sptdwb.sptd.Cdb[9]              = 0; // Starting LBA
+        sptdwb.sptd.Cdb[13]             = 1; // TRANSFER LENGTH

         length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
         iResult = iIssueDeviceIoControl(
@ -687,7 +688,7 @@ int iReadViaSCSIPassThrough(HANDLE _hDevice)
         sptwb_ex.spt.Version = 0;
         sptwb_ex.spt.Length = sizeof(SCSI_PASS_THROUGH_EX);
         sptwb_ex.spt.ScsiStatus = 0;
-        sptwb_ex.spt.CdbLength = CDB10GENERIC_LENGTH;
+        sptwb_ex.spt.CdbLength = CDB16GENERIC_LENGTH;
         sptwb_ex.spt.StorAddressLength = sizeof(STOR_ADDR_BTL8);
         sptwb_ex.spt.SenseInfoLength = SPT_SENSE_LENGTH;
         sptwb_ex.spt.DataOutTransferLength = 0;
@ -704,9 +705,9 @@ int iReadViaSCSIPassThrough(HANDLE _hDevice)
         sptwb_ex.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS_EX, ucSenseBuf);
         sptwb_ex.spt.DataOutBufferOffset = 0;
         sptwb_ex.spt.DataInBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS_EX, ucDataBuf);
-        sptwb_ex.spt.Cdb[0] = SCSIOP_READ;
-        sptwb_ex.spt.Cdb[5] = 0; // Starting LBA
-        sptwb_ex.spt.Cdb[8] = 1; // TRANSFER LENGTH
+        sptwb_ex.spt.Cdb[0] = SCSIOP_READ16; // 88h
+        sptwb_ex.spt.Cdb[9] = 0; // Starting LBA
+        sptwb_ex.spt.Cdb[13] = 1; // TRANSFER LENGTH
         length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS_EX);

         iResult = iIssueDeviceIoControl(
@ -728,16 +729,16 @@ int iReadViaSCSIPassThrough(HANDLE _hDevice)
         sptwb.spt.PathId = 0;
         sptwb.spt.TargetId = 0;
         sptwb.spt.Lun = 0;
-        sptwb.spt.CdbLength = CDB10GENERIC_LENGTH;
+        sptwb.spt.CdbLength = CDB16GENERIC_LENGTH;
         sptwb.spt.SenseInfoLength = SPT_SENSE_LENGTH;
         sptwb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
         sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
         sptwb.spt.DataTransferLength = 512;
         sptwb.spt.TimeOutValue = 5;
         sptwb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
-        sptwb.spt.Cdb[0] = SCSIOP_READ;
-        sptwb.spt.Cdb[5] = 0; // Starting LBA
-        sptwb.spt.Cdb[8] = 1; // TRANSFER LENGTH
+        sptwb.spt.Cdb[0] = SCSIOP_READ16; // 88h
+        sptwb.spt.Cdb[9] = 0; // Starting LBA
+        sptwb.spt.Cdb[13] = 1; // TRANSFER LENGTH

         length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf) + sptwb.spt.DataTransferLength;
         iResult = iIssueDeviceIoControl(

Regards, Ken

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.