|
【如题】:通过贵公司的这款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;
- }
复制代码
希望能够得到你们工程师的支持,把写的操作能够实现。 |
|