SCSI Read(10) on a Physical Drive on Windows

匿名 (未验证) 提交于 2019-12-03 01:45:01

问题:

I tried issuing a SCSI Read(10) command to a physical drive on a Windows 7 machine. Below is the code snippet that I am using. It is failing with error code 87.

void scsi_read()  {   const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };  UCHAR buf[512];  BYTE senseBuf[196];  const int SENSE_LENGTH = 196;  LPCSTR fname = "\\\\.\\E:";  HANDLE fh;   DWORD ioctl_bytes;  DWORD err = 0;   SCSI_PASS_THROUGH s = {0};  memcpy(s.Cdb, cdb, sizeof(cdb));  s.CdbLength = 10;  s.DataIn = SCSI_IOCTL_DATA_IN;  s.TimeOutValue = 30;  s.Length = sizeof(SCSI_PASS_THROUGH);    s.ScsiStatus         = 0x00;  s.SenseInfoOffset =  senseBuf;  s.SenseInfoLength  = SENSE_LENGTH;  s.DataBufferOffset = buf;  s.DataTransferLength = 512;   fh = CreateFile("\\\\.\\E:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,  OPEN_EXISTING, 0, NULL);  if(fh == INVALID_HANDLE_VALUE) {     printf("Could not open %s file, error %d\n", fname, GetLastError());     return (FALSE);  }   int ret = DeviceIoControl(fh,IOCTL_SCSI_PASS_THROUGH, &s,sizeof(s), //scsiPassThrough.sizeof,                                 &s,                                 sizeof(s),                                 &ioctl_bytes,                                 NULL);   printf("ret %d",(int)ret);                                      if (ret==1) {     printf("OK");  }  else {      err = GetLastError();     printf("Last error code %u\n", err);     printf("Return size %d\n", ioctl_bytes);     printf("Sense data\n");     int i=0;     for (i = 0; i < 20; i++) {         printf("\t%x", senseBuf[i]);     }     printf("\n");  }  CloseHandle(fh); } 

Error: Hex dumps are printed in the output

回答1:

you got error code 87 - ERROR_INVALID_PARAMETER because code totally wrong.

for example:

const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 }; 

but 512 is > 255 (MAXUCHAR) are you not got compiler warning here ?

warning C4305: 'initializing': truncation from 'int' to 'const UCHAR' 

look at this line !

s.DataBufferOffset = buf; 

from SCSI_PASS_THROUGH structure:

DataBufferOffset

Contains an offset from the beginning of this structure to the data buffer. The offset must respect the data alignment requirements of the device.

so offset to buffer, not pointer to buffer

for use this correct you code need be like this:

struct MY_DATA : SCSI_PASS_THROUGH  {     UCHAR buf[512]; } s;  s.DataBufferOffset = FIELD_OFFSET(MY_DATA, buf); 

but better use SCSI_PASS_THROUGH_DIRECT with IOCTL_SCSI_PASS_THROUGH_DIRECT

you hardcode sector size (512), when need get it at runtime. and how you initialize CDB ?!? at all unclear what you try todo.

working code example (sorry but on c++ instead c)

#define _NTSCSI_USER_MODE_ #include <scsi.h> #include <ntddscsi.h>  BOOL scsi_read(HANDLE fh, PVOID buf, DWORD cb, ULONGLONG LogicalBlock, ULONG TransferBlocks) {     SCSI_PASS_THROUGH_DIRECT s = {          sizeof(SCSI_PASS_THROUGH_DIRECT), 0, 0, 0, 0, 0, 0, SCSI_IOCTL_DATA_IN, cb, 30, buf     };      union {         PUCHAR Cdb;         CDB::_CDB10* Cdb10;         CDB::_CDB16* Cdb16;     };      Cdb = s.Cdb;      if (MAXULONG < LogicalBlock || MAXUSHORT < TransferBlocks)     {         s.CdbLength = sizeof(CDB::_CDB16);         Cdb16->OperationCode = SCSIOP_READ16;         *(ULONGLONG*)Cdb16->LogicalBlock = _byteswap_uint64(LogicalBlock);         *(ULONG*)Cdb16->TransferLength = _byteswap_ulong(TransferBlocks);     }     else     {         s.CdbLength = sizeof(CDB::_CDB10);         Cdb10->OperationCode = SCSIOP_READ;         *(ULONG*)&Cdb10->LogicalBlockByte0 = _byteswap_ulong((ULONG)LogicalBlock);         *(USHORT*)&Cdb10->TransferBlocksMsb = _byteswap_ushort((USHORT)TransferBlocks);     }      DWORD ioctl_bytes;      return DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &s, sizeof(s), &s, sizeof(s), &ioctl_bytes, NULL); }  BOOL test_scsi_read(PCWSTR fname)  {     BOOL fOk = FALSE;      HANDLE fh = CreateFileW(fname, GENERIC_READ | GENERIC_WRITE,          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);      if (fh != INVALID_HANDLE_VALUE)      {         DWORD ioctl_bytes;          DISK_GEOMETRY_EX dg;          if (DeviceIoControl(fh, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dg, sizeof(dg), &ioctl_bytes, 0))         {             // 16 sectors for example             ULONG cb = 16 * dg.Geometry.BytesPerSector;              if (PVOID buf = new CHAR[cb])             {                 // read first 16 sectors                 fOk = scsi_read(fh, buf, cb, 0, 16);                  if (ULONGLONG LogicalBlock = dg.DiskSize.QuadPart / dg.Geometry.BytesPerSector)                 {                     // read last sector                     fOk = scsi_read(fh, buf, dg.Geometry.BytesPerSector, LogicalBlock - 1, 1);                 }                  delete buf;             }         }          CloseHandle(fh);     }      return fOk; }     test_scsi_read(L"\\\\?\\e:"); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!