D を使用して Windows のボリュームに scsi ReadCapacity16 (0x9E) を送信しようとしています。Windows の非問い合わせ呼び出しのみが、Windows カーネルの「不正な関数」で機能しません。
問い合わせのみが機能するため、Windows カーネルを介して非問い合わせを送信するためのトリックはありますか? これを機能させるためのヒントはありますか?私は数週間調査しましたが、これを解決していません。
これはCDBの例です:
\\.\physicaldrive0 CDB バッファーの内容: 9e 10 00 00 00 00 00 00 - 00 00 00 00 00 20 00 00 sgio.exceptions.IoctlFailException@sgio\exceptions.d(13): ioctl エラー コードは 1 です。関数が正しくありません。
ここでは、CDB が DeviceIoControl 呼び出し用のバッファーにコピーされます。これは、Inquiry コマンドを正常に送信するのと同じコード パスです (ただし、readcap では失敗します)。以下に貼り付けたgithubのコード:
void sgio_execute(ubyte[] cdb_buf, ubyte[] dataout_buf, ubyte[] datain_buf, ubyte[] sense_buf)
version (Windows)
{
const uint SENSE_LENGTH = 196;
ubyte[512] iobuffer = 0;
DWORD amountTransferred = -1;
SCSI_PASS_THROUGH_DIRECT scsiPassThrough = {0};
scsiPassThrough.Cdb[] = 0;
uint size = cast(uint)((cdb_buf.length <= scsiPassThrough.Cdb.length ?
cdb_buf.length : scsiPassThrough.Cdb.length));
scsiPassThrough.Cdb[0..size] = cdb_buf[0..size];
scsiPassThrough.Length = SCSI_PASS_THROUGH_DIRECT.sizeof;
scsiPassThrough.ScsiStatus = 0x00;
scsiPassThrough.TimeOutValue = 0x40;
scsiPassThrough.CdbLength = cast(ubyte)(size);
scsiPassThrough.SenseInfoOffset = SCSI_PASS_THROUGH_DIRECT.sizeof;
scsiPassThrough.SenseInfoLength = SENSE_LENGTH;
scsiPassThrough.DataIn = SCSI_IOCTL_DATA_IN;
scsiPassThrough.DataBuffer = datain_buf.ptr;
scsiPassThrough.DataTransferLength = bigEndianToNative!ushort(cast(ubyte[2]) cdb_buf[3..5]);
int status = DeviceIoControl( m_device,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
&scsiPassThrough,
iobuffer.length, //scsiPassThrough.sizeof,
&iobuffer,
iobuffer.length,
&amountTransferred,
null);
if (status == 0)
{
int errorCode = GetLastError();
// build error message ...
throw new IoctlFailException(exceptionMessage);
}
}
}