DeviceIoControl возвращает 1306 с IOCTL_SCSI_PASS_THROUGH - PullRequest
0 голосов
/ 03 ноября 2019

Я пытаюсь использовать DeviceIoControl с управляющим кодом IOCTL_SCSI_PASS_THROUGH в C #. Но DeviceIoControl возвращает код ошибки 1306.

Я хочу получить SMART для твердотельного накопителя INTEL NVMe.

Я попытался сослаться на исходный код Crystal Disk Info.

Он успешно работает на C или C ++.

Где проблема со следующим исходным кодом?

[DllImport("kernel32.dll", SetLastError = true,
            CallingConvention = CallingConvention.StdCall,
            CharSet = CharSet.Auto)]
public static extern IntPtr CreateFile(
            [MarshalAs(UnmanagedType.LPTStr)] string filename,
            [MarshalAs(UnmanagedType.U4)] FileAccess access,
            [MarshalAs(UnmanagedType.U4)] FileShare share,
            IntPtr securityAttributes,
            [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
            UInt32 flagsAndAttributes,
            IntPtr templateFile);

[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeviceIoControl(
            IntPtr hDevice,
            UInt32 dwIoControlCode,
            IntPtr lpInBuffer,
            UInt32 nInBufferSize,
            IntPtr lpOutBuffer,
            UInt32 nOutBufferSize,
            [Out]out UInt32 lpBytesReturned,
            IntPtr lpOverlapped);

[StructLayout(LayoutKind.Sequential)]
struct SCSI_PASS_THROUGH
{
    public ushort length;
    public byte scsiStatus;
    public byte pathId;
    public byte targetId;
    public byte lun;
    public byte cdbLength;
    public byte senseInfoLength;
    public byte dataIn;
    public uint dataTransferLength;
    public uint timeOutValue;
    public ulong dataBufferOffset;
    public uint senseInfoOffset;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public byte[] cdb;
};

[StructLayout(LayoutKind.Sequential)]
struct SCSI_PASS_THROUGH_WITH_BUFFERS24
{
    public SCSI_PASS_THROUGH spt;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
    public byte[] senseBuf;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)]
    public byte[] dataBuf;
};

private static void VolumeDeviceIoControl(string physicalDriveId)
{
    IntPtr handle = CreateFile(physicalDriveId, FileAccess.ReadWrite,
                FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);

    if (handle != System.IntPtr.Zero && (uint)handle.ToInt32() != (uint)0xffffffff)
    {
        Console.WriteLine("hadle success open");
    }
    else
    {
        throw new Exception("handle failed open", new Win32Exception());
    }

    uint returned = 0;
    SCSI_PASS_THROUGH_WITH_BUFFERS24 sptwb = new SCSI_PASS_THROUGH_WITH_BUFFERS24();

    // initialize
    sptwb.spt.length = 0;
    sptwb.spt.scsiStatus = 0;
    sptwb.spt.pathId = 0;
    sptwb.spt.targetId = 0;
    sptwb.spt.lun = 0;
    sptwb.spt.cdbLength = 0;
    sptwb.spt.senseInfoLength = 0;
    sptwb.spt.dataIn = 0;
    sptwb.spt.dataTransferLength = 0;
    sptwb.spt.timeOutValue = 0;
    sptwb.spt.dataBufferOffset = 0;
    sptwb.spt.senseInfoOffset = 0;
    sptwb.spt.cdb = new byte[16];
    sptwb.senseBuf = new byte[24];
    sptwb.dataBuf = new byte[4096];

    // set input parameter
    sptwb.spt.length = 56;
    sptwb.spt.pathId = 0;
    sptwb.spt.targetId = 0;
    sptwb.spt.lun = 0;
    sptwb.spt.senseInfoLength = 24;
    sptwb.spt.dataIn = 0;
    sptwb.spt.dataTransferLength = 512;
    sptwb.spt.timeOutValue = 2;
    sptwb.spt.dataBufferOffset = 80;
    sptwb.spt.senseInfoOffset = 56;
    sptwb.spt.cdbLength = 12;
    sptwb.spt.cdb[0] = 0xA1;
    sptwb.spt.cdb[1] = 0x80;
    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.dataBuf[0] = 0x4e;
    sptwb.dataBuf[1] = 0x56;
    sptwb.dataBuf[2] = 0x4d;
    sptwb.dataBuf[3] = 0x45;
    sptwb.dataBuf[8] = 0x02;
    sptwb.dataBuf[10] = 0x56;
    sptwb.dataBuf[12] = 0xFF;
    sptwb.dataBuf[13] = 0xFF;
    sptwb.dataBuf[14] = 0xFF;
    sptwb.dataBuf[15] = 0xFF;
    sptwb.dataBuf[0x21] = 0x40;
    sptwb.dataBuf[0x22] = 0x7A;
    sptwb.dataBuf[0x30] = 0x02;
    sptwb.dataBuf[0x32] = 0x7F;

    // sptwbPtr
    IntPtr sptwbPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(SCSI_PASS_THROUGH_WITH_BUFFERS24)));
    Marshal.StructureToPtr(sptwb, sptwbPtr, false);

    // DeviceIoControl
    bool isSuccess = false;
    isSuccess = DeviceIoControl(handle, 0x4d004 /* IOCTL_SCSI_PASS_THROUGH */, sptwbPtr, 592, sptwbPtr, 592, out returned, IntPtr.Zero);
    Console.Write("DeviceIoControl=" + isSuccess);
    if (!isSuccess)
    {
        // return 1306
        Console.WriteLine("DeviceIoControl ErrorCd=" + Marshal.GetLastWin32Error() + " returned=" + returned);
        try { throw new Win32Exception(); } catch (Exception e) { Console.WriteLine("Msg=" + e.Message); }
        Marshal.FreeCoTaskMem(sptwbPtr);
        return;
     } else if (isSuccess)
     {
         return;
     }
}
...