Я могу отправить SCSIOP_WRITE, но перед моим SCSIOP_WRITE всегда отправляются 2 SCSIOP_READ_CAPACITY. Я делаю что-то не так? - PullRequest
0 голосов
/ 18 апреля 2019

Я использую C # для создания приложения для записи данных на устройство (например, SD-карту) по определенному адресу.Я нашел много полезных примеров кода в Интернете и теперь могу записывать данные на SD-карту.Но здесь есть проблема.Перед отправкой моей заявки моего SCSIOP_WRITE (0x2A) всегда отправляется 2 сообщения SCSIOP_READ_CAPACITY (0x25).Вот журнал Bushound.

Device  Phase  Data                                                Description       Cmd.Phase.Ofs(rep)
------  -----  --------------------------------------------------  ----------------  ------------------
  40    CMD    00 00 00 00  00 00                                  TEST UNIT READY          1.1.0(16)    
  40    ok                                                                                  1.2.0        
  40    CMD    25 00 00 00  00 00 00 00  00 00                     READ CAPACITY           17.1.0(2)     
  40    IN     00 e6 1f ff  00 00 02 00                            ........                17.2.0        
  40    CMD    2a 00 00 00  00 00 00 04  00 00                     WRITE                   19.1.0        
  40    OUT    c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.0        
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.16       
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.32       
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.48       
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.64       
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.80       
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.96       
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.112      
               c0 76 db e7  c0 76 db e7  c0 76 db e7  c0 76 db e7  .v...v...v...v..        19.2.128

Как показывает журнал, 2 READ_CAPACITY (0x25) опережают мой WRITE (0x2A).Но я даже не отправляю и не настраиваю CDB READ_CAPACITY в моем коде.Я не знаю, откуда взялись 2 READ_CAPACITY.Вот код, который я использую.

[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
static extern bool DeviceIoControl(
    SafeFileHandle hDevice, //IntPtr hDevice, 
    uint dwIoControlCode,
    IntPtr lpInBuffer, 
    uint nInBufferSize,
    IntPtr lpOutBuffer, 
    uint nOutBufferSize,
    out uint lpBytesReturned, 
    IntPtr lpOverlapped
    );

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT
{
    private const int _CDB_LENGTH = 16;
    public short Length;
    public byte ScsiStatus;
    public byte PathId;
    public byte TargetId;
    public byte Lun;
    public byte CdbLength;
    public byte SenseInfoLength;
    public byte DataIn;
    public int DataTransferLength;
    public int TimeOutValue;
    public IntPtr DataBuffer;
    public uint SenseInfoOffset;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = _CDB_LENGTH)]
    public byte[] Cdb;

    #region Constructors

    public SCSI_PASS_THROUGH_DIRECT()
    {
        Cdb = new byte[_CDB_LENGTH];
    }

    #endregion Constructors
}

[StructLayout(LayoutKind.Sequential)]
class SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
{
    private const int _SENSE_LENGTH = 32;
    internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT();
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = _SENSE_LENGTH)]
    internal byte[] sense;

    #region Constructors

    public SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER()
    {
        sense = new byte[_SENSE_LENGTH];
    }

    #endregion Constructors
}

private void btnWrite512KB_Click(object sender, EventArgs e)
{
    uint Pattern = 0x12345678;
    byte[] pattern = BitConverter.GetBytes(Pattern).Reverse().ToArray();
    uint wbuffer_blkcnt = 0x400;
    uint wbuffer_datasize = wbuffer_blkcnt * 512;
    byte[] wBuffer = new byte[wbuffer_datasize];
    int errorCode = 0;

    Array.Clear(wBuffer, 0, wBuffer.Length);
    for (int wbuffer_idx = 0; wbuffer_idx <= (wbuffer_datasize - pattern.Length); wbuffer_idx += pattern.Length)
    {
        Array.Copy(pattern, 0, wBuffer, wbuffer_idx, pattern.Length);
    }

    byte[] cdb = new byte[10];
    cdb[0] = 0x2a;
    cdb[1] = 0x00;
    cdb[2] = 0x00;  // MSB of address
    cdb[3] = 0x00;
    cdb[4] = 0x00;
    cdb[5] = 0x00;  // LSB of address
    cdb[6] = 0x00;
    cdb[7] = 0x04;  // MSB of BlkLen
    cdb[8] = 0x00;  // LSB of BlkLen
    cdb[9] = 0x00;

    d.SendCommand(cdb, wBuffer);
}

public void SendCommand(byte[] cmd, byte[] data)
{
    _SendCommand(_handle, cmd, data, 0);
}

private static byte[] _SendCommand(SafeFileHandle handle, byte[] cmd, byte[] data, int bytesExpected)
{
    const int IOCTL_SCSI_BASE = 0x00000004;
    const int IOCTL_SCSI_PASS_THROUGH = IOCTL_SCSI_BASE << 16 | 3 << 14 | 0x0401 << 2 | 0;
    //const int IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014;
    const int IOCTL_SCSI_PASS_THROUGH_DIRECT = IOCTL_SCSI_BASE << 16 | 3 << 14 | 0x0405 << 2 | 0;
    const int TIMEOUT_SECS = 30;
    SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER scsi = null;
    //SCSI_PASS_THROUGH_DIRECT scsi = null;
    IntPtr inBuffer = IntPtr.Zero;
    byte[] ret = null;

    try
    {
        scsi = new SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER();
        scsi.sptd.Length = (short)Marshal.SizeOf(scsi.sptd);
        scsi.sptd.TimeOutValue = TIMEOUT_SECS;
        scsi.sptd.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), "sense");
        scsi.sptd.SenseInfoLength = (byte)scsi.sense.Length;
        scsi.sptd.CdbLength = (byte)cmd.Length;
        Array.Copy(cmd, scsi.sptd.Cdb, cmd.Length);
        scsi.sptd.DataIn = data != null && data.Length > 0 ? SCSI_IOCTL_DATA_OUT : SCSI_IOCTL_DATA_IN;
        scsi.sptd.DataTransferLength = data != null && data.Length > 0 ? data.Length : bytesExpected;
        scsi.sptd.DataBuffer = Marshal.AllocHGlobal(scsi.sptd.DataTransferLength);
        if (data != null && data.Length > 0)
        {
            Marshal.Copy(data, 0, scsi.sptd.DataBuffer, data.Length);
        }

        uint bytesReturned;
        inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(scsi));
        var size = (uint)Marshal.SizeOf(scsi);
        Marshal.StructureToPtr(scsi, inBuffer, false);
        //if (!DeviceIoControl(handle.DangerousGetHandle(), IOCTL_SCSI_PASS_THROUGH_DIRECT,
        //    inBuffer, size, inBuffer, size, out bytesReturned, IntPtr.Zero))
        if (!DeviceIoControl(handle, IOCTL_SCSI_PASS_THROUGH_DIRECT,
            inBuffer, size, inBuffer, size, out bytesReturned, IntPtr.Zero))
        {
            //Whoops, do something with the error code
            int last = Marshal.GetLastWin32Error();
            throw new InvalidOperationException("DeviceIoControl failed: " + last.ToString("X04"));
        }
        else
        {
            if (scsi.sptd.ScsiStatus != 0)
            {
                //Whoops, do something with the error code
                throw new InvalidOperationException("SCSI command failed: " + scsi.sptd.ScsiStatus.ToString("X02"));
            }
            else
            {
                //Success, marshal back any data we received
                if (scsi.sptd.DataTransferLength > 0)
                {
                    ret = new byte[scsi.sptd.DataTransferLength];
                    Marshal.Copy(scsi.sptd.DataBuffer, ret, 0, ret.Length);
                }
            }
        }
    }
    finally
    {
        /* Free any unmanaged resources */

        if (scsi != null && scsi.sptd.DataBuffer != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(scsi.sptd.DataBuffer);
        }

        if (inBuffer != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(inBuffer);
        }
    }

    return ret;
}

После выполнения d.SendCommand (cdb, wBuffer) Бушун записал журнал выше.Пожалуйста, помогите мне избавиться от 2 READ_CAPACITY.В журнале Бушаунда не должно быть READ_CAPACITY.Спасибо!

...