【问题标题】:SCSI Read(10) on a Physical Drive on WindowsWindows 上物理驱动器上的 SCSI 读取 (10)
【发布时间】:2017-01-04 03:58:56
【问题描述】:

我尝试向 Windows 7 机器上的物理驱动器发出 SCSI Read(10) 命令。下面是我正在使用的代码 sn-p。它失败,错误代码为 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);
}

错误:输出中打印了十六进制转储

【问题讨论】:

    标签: c winapi


    【解决方案1】:

    您收到错误代码 87 - ERROR_INVALID_PARAMETER,因为代码完全错误。

    例如:

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

    但是512&gt; 255 (MAXUCHAR) 你这里没有编译器警告吗?

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

    看看这条线!

    s.DataBufferOffset = buf;
    

    来自SCSI_PASS_THROUGH 结构:

    DataBufferOffset

    包含从这个结构的开头到数据的偏移量 缓冲。偏移量必须遵守数据对齐要求 设备。

    所以 offset 到缓冲区,而不是 指针 到缓冲区

    为了使用这个正确的代码,你的代码需要是这样的:

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

    但最好将SCSI_PASS_THROUGH_DIRECTIOCTL_SCSI_PASS_THROUGH_DIRECT 一起使用

    您在运行时需要时硬编码扇区大小 (512)。以及如何初始化CDB ?!?完全不清楚你尝试做什么。

    工作代码示例(抱歉,使用 c++ 而不是 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:");
    

    【讨论】:

      猜你喜欢
      • 2021-06-19
      • 2012-08-05
      • 1970-01-01
      • 2011-06-26
      • 2012-10-13
      • 2012-04-11
      • 2013-02-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多