1

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);
      }
   }
}
4

1 に答える 1

1

Windows SCSI_PASS_THROUGH_DIRECT 構造のドキュメントをよく読んでいると、次のことに気付きました。

DataTransferLength: データ バッファーのサイズをバイト単位で示します。多くのデバイスは、あらかじめ定義された長さのデータのチャンクを転送します。DataTransferLength の値は、デバイスによって指定されたこの定義済みの最小長の整数倍である必要があります。アンダーランが発生した場合、ミニポート ドライバーは、このメンバーを実際に転送されたバイト数に更新する必要があります。

datain_buffer のサイズを大きくして、DataTransferLength に 512 バイトを使用するようにコードを変更したところ、コードは問題なく動作するようになりました。

于 2015-06-24T08:35:53.203 に答える