Я пытаюсь использовать 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;
}
}