I can send SCSIOP_WRITE, but there are always 2 SCSIOP_READ_CAPACITY sent before my SCSIOP_WRITE. Am I doing anything wrong?

0

I am using C# to build an application to write data to device(such as SD card) at specific address. I found many useful sample code online and I can write data to SD card now. But here is a problem. There are always 2 SCSIOP_READ_CAPACITY(0x25) sent before my application actually send my SCSIOP_WRITE(0x2A). Here are the Bushound log.

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

As the log show, 2 READ_CAPACITY(0x25) are ahead of my WRITE(0x2A). But I do not even send or configure the CDB of READ_CAPACITY in my code. I don't know where the 2 READ_CAPACITY came from. Here are the code I am using.

[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;
}

After d.SendCommand(cdb, wBuffer) executed, Bushound recorded the log above. Please help me get rid of the 2 READ_CAPACITY. There should be no READ_CAPACITY in Bushound log. Thank you!

c#
.net
winapi
dllimport
scsi
asked on Stack Overflow Apr 18, 2019 by ohnotme

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0