Я использую 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.Спасибо!