| 
 | 
 
【如题】:通过贵公司的这款USB->NVMe转换器,我应该怎么发送标准的NVMe 读和写的操作给SSD呢? 
 
【产品】:佳翼(JEYI) 红色海豹i9 NVME USB3.1 TYPE C移动硬盘盒JMS583 PCIE ,我从你们的京东链接上买的: https://item.jd.com/29046814090.html  
 
【背景】:我们公司正在基于贵公司的这款USB->NVMe转换器发送标准的读写命令给SSD。如果能够把这个tool做出来,当然会采购更多的转换器用到SSD产线上。但是现在我遇到了这么一个难题,基于你们的这个转换器(JMicron),我怎么才能通过Windows的标准的DeviceIoControl()这个函数,发送读(NVMe OpCode=0x02 write command)命令给SSD呢? 
 
【尝试】:我研究了开源的软件:CrystalDiskInfo, https://crystalmark.info/en/software/crystaldiskinfo/ ,这个软件能够识别到贵公司转接的NVMe SSD。里面用的代码是SCSI_PASS_THROUGH这个结构体,然后通过DeviceIoControl发出去identify 命令的。但是里面的代码却没有对NVMe的写操作。这点我已经和作者交流过,他也没办法知道JMicron的操作办法。 
- /*---------------------------------------------------------------------------*/
 
 - //  NVMe JMicron
 
 - /*---------------------------------------------------------------------------*/
 
  
- BOOL CAtaSmart::DoIdentifyDeviceNVMeJMicron(INT physicalDriveId, INT scsiPort, INT scsiTargetId, IDENTIFY_DEVICE* data)
 
 - {
 
 -         BOOL        bRet;
 
 -         HANDLE        hIoCtrl;
 
 -         DWORD        dwReturned;
 
 -         DWORD        length;
 
  
-         SCSI_PASS_THROUGH_WITH_BUFFERS24 sptwb;
 
  
-         if (data == NULL)
 
 -         {
 
 -                 return        FALSE;
 
 -         }
 
  
-         ::ZeroMemory(data, sizeof(IDENTIFY_DEVICE));
 
  
-         hIoCtrl = GetIoCtrlHandle(physicalDriveId);
 
  
-         if (hIoCtrl == INVALID_HANDLE_VALUE)
 
 -         {
 
 -                 return        FALSE;
 
 -         }
 
  
-         ::ZeroMemory(&sptwb, sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS24));
 
  
-         sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
 
 -         sptwb.Spt.PathId = 0;
 
 -         sptwb.Spt.TargetId = 0;
 
 -         sptwb.Spt.Lun = 0;
 
 -         sptwb.Spt.SenseInfoLength = 24;
 
 -         sptwb.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
 
 -         sptwb.Spt.DataTransferLength = IDENTIFY_BUFFER_SIZE;
 
 -         sptwb.Spt.TimeOutValue = 2;
 
 -         sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS24, DataBuf);
 
 -         sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS24, SenseBuf);
 
  
-         sptwb.Spt.CdbLength = 12;
 
 -         sptwb.Spt.Cdb[0] = 0xA1; // NVME PASS THROUGH
 
 -         sptwb.Spt.Cdb[1] = 0x80; // ADMIN
 
 -         sptwb.Spt.Cdb[2] = 0;
 
 -         sptwb.Spt.Cdb[3] = 0;
 
 -         sptwb.Spt.Cdb[4] = 2;
 
 -         sptwb.Spt.Cdb[5] = 0;
 
 -         sptwb.Spt.Cdb[6] = 0;
 
 -         sptwb.Spt.Cdb[7] = 0;
 
 -         sptwb.Spt.Cdb[8] = 0;
 
 -         sptwb.Spt.Cdb[9] = 0;
 
 -         sptwb.Spt.Cdb[10]= 0;
 
 -         sptwb.Spt.Cdb[11]= 0;
 
 -         sptwb.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
 
 -         sptwb.DataBuf[0] = 'N';
 
 -         sptwb.DataBuf[1] = 'V';
 
 -         sptwb.DataBuf[2] = 'M';
 
 -         sptwb.DataBuf[3] = 'E';
 
 -         sptwb.DataBuf[8] = 0x06; // Identify
 
 -         sptwb.DataBuf[0x30] = 0x01;
 
  
-         length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS24, DataBuf) + sptwb.Spt.DataTransferLength;
 
  
-         bRet = ::DeviceIoControl(hIoCtrl, IOCTL_SCSI_PASS_THROUGH,
 
 -                 &sptwb, length,
 
 -                 &sptwb, length, &dwReturned, NULL);
 
  
-         if (bRet == FALSE)
 
 -         {
 
 -                 ::CloseHandle(hIoCtrl);
 
 -                 return        FALSE;
 
 -         }
 
  
- //        ::ZeroMemory(&sptwb, sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS24));
 
 -         sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
 
 -         sptwb.Spt.PathId = 0;
 
 -         sptwb.Spt.TargetId = 0;
 
 -         sptwb.Spt.Lun = 0;
 
 -         sptwb.Spt.SenseInfoLength = 24;
 
 -         sptwb.Spt.DataTransferLength = 512;
 
 -         sptwb.Spt.TimeOutValue = 2;
 
 -         sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS24, DataBuf);
 
 -         sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS24, SenseBuf);
 
 -         
 
 -         sptwb.Spt.CdbLength = 12;
 
 -         sptwb.Spt.Cdb[0] = 0xA1; // NVME PASS THROUGH
 
 -         sptwb.Spt.Cdb[1] = 0x82; // ADMIN + DMA-IN
 
 -         sptwb.Spt.Cdb[2] = 0;
 
 -         sptwb.Spt.Cdb[3] = 0;
 
 -         sptwb.Spt.Cdb[4] = 2;
 
 -         sptwb.Spt.Cdb[5] = 0;
 
 -         sptwb.Spt.Cdb[6] = 0;
 
 -         sptwb.Spt.Cdb[7] = 0;
 
 -         sptwb.Spt.Cdb[8] = 0;
 
 -         sptwb.Spt.Cdb[9] = 0;
 
 -         sptwb.Spt.Cdb[10]= 0;
 
 -         sptwb.Spt.Cdb[11]= 0;
 
 -         sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN;
 
  
-         length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS24, DataBuf) + sptwb.Spt.DataTransferLength;
 
  
 
-         bRet = ::DeviceIoControl(hIoCtrl, IOCTL_SCSI_PASS_THROUGH,
 
 -                 &sptwb, length,
 
 -                 &sptwb, length, &dwReturned, NULL);
 
  
-         if (bRet == FALSE)
 
 -         {
 
 -                 ::CloseHandle(hIoCtrl);
 
 -                 return        FALSE;
 
 -         }
 
  
-         DWORD count = 0;
 
 -         for (int i = 0; i < 512; i++)
 
 -         {
 
 -                 count += sptwb.DataBuf[i];
 
 -         }
 
 -         if (count == 0 || count == 317)
 
 -         {
 
 -                 ::CloseHandle(hIoCtrl);
 
 -                 return        FALSE;
 
 -         }
 
  
-         memcpy_s(data, sizeof(IDENTIFY_DEVICE), sptwb.DataBuf, sizeof(IDENTIFY_DEVICE));
 
  
-         ::CloseHandle(hIoCtrl);
 
  
-         return TRUE;
 
 - }
 
  复制代码 
 
希望能够得到你们工程师的支持,把写的操作能够实现。 |   
 
 
 
 |