Windowsの物理ディスクにATAコマンドを送信し、デバイスから応答を取得しようとしています。
注:この場合、
IDENTIFY DEVICE
(0xEC)コマンドを送信します。デバイスは512バイトのデータブロックで応答します。(特に、ワード119のビット0(デバイスによるコマンドのサポートTRIM
)に関心があります)。
CreateFile
デバイスを開くために使用する必要があることを知っています。
handle = CreateFile(
"\\.\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ,
nil, // no security attributes
OPEN_EXISTING,
0, // flags and attributes
nil // no template file
);
しかし、この後、私は何をすべきかについて悩まされています。
0xEC
を使って送ることを考えました[DeviceIoControl][4]
:
// const ATACommand_IdentifyDevice = 0xEC;
uint bytesReturned = 0;
DeviceIoControl(handle,
0xEC, // IO Control Code
nil, // input buffer not needed
0, // input buffer is zero bytes
@buffer, // output buffer to store the returned 512-bytes
512, // output buffer is 512 bytes long
out bytesReturned,
nil // not an overlapped operation
);
しかし、これは完全に間違っています。DeviceIoControlに送信されるIoControlCodeは、マクロを使用して構築された有効なIO_CTLである必要があります。
#define CTL_CODE(DeviceType, Function, Method, Access) (
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)
)
SDKを見ると、有効なディスク管理制御コードがいくつかあります。例:
- IOCTL_DISK_CREATE_DISK
- IOCTL_DISK_GET_DRIVE_GEOMETRY
- IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
- IOCTL_DISK_GET_PARTITION_INFO
- IOCTL_STORAGE_QUERY_PROPERTY
しかし、それらのどれもIDENTIFY DEVICE
コマンドではなく、それが返すものは何でも返しません。
したがって、コマンドを送信するための「生の」方法を使用する必要があると思います。
周りを検索して、文書化されていないIOCTLに出くわしました
#define DFP_RECEIVE_DRIVE_DATA 0x0007c088
これは、IOCTLの断片を分解すると、次のことを意味します。
Custom: (0)
Device Type: (7) FILE_DEVICE_DISK
Required Access: (3) METHOD_NEITHER
Custom: (0)
Function Code: (34)
Transfer Type: (0)
inputBuffer
しかし、何を含める必要があるか、そのサイズ、何を含めるか、または必要なものについてのドキュメントはどこにもありませんoutputBuffer
。functionCode
また、 34(0x22)が何であるかを理解することもできません。
私の質問:生のATAコマンド(0xECなど)をATAデバイスに送信し、その応答を読み取るにはどうすればよいですか?
も参照してください
回答ピース
読み取り/書き込みアクセスでドライブを開きます。
handle = CreateFile(
"\\.\PhysicalDrive0",
GENERIC_READ or GENERIC_WRITE, // IOCTL_ATA_PASS_THROUGH requires read-write
FILE_SHARE_READ,
nil, // no security attributes
OPEN_EXISTING,
0, // flags and attributes
nil // no template file
);
IO制御コードATA_PASS_THROUGH_EX
で使用する入力バッファーとして構造を設定します。IOCTL_ATA_PASS_THROUGH
ATA_PASS_THROUGH_EX inputBuffer;
inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
inputBuffer.DataTransferLength = 0;
inputBuffer.DataBufferOffset = 0;
// todo: put the ATA command (e.g. 0xEC) somewhere
uint inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);
ドライブからの予想される512バイトの応答を保持するように出力バッファを設定します。
Byte[] outputBuffer = new Byte[512];
uint outputBufferSize = 512;
電話DeviceIoControl
:
int ioControlCode = IOCTL_ATA_PASS_THROUGH; // or maybe IOCTL_ATA_PASS_THROUGH_DIRECT
uint bytesReturned = 0;
DeviceIoControl(handle, ioControlCode,
inputBuffer, inputBufferSize,
outputBuffer, outputBufferSize,
out bytesReturned,
nil // not an overlapped operation
);
ファイルハンドルを閉じます。
handle.Close();