Я пытаюсь отправить команды ATA на физический диск в Windows и получить ответ от устройства.
Примечание: В этом случае я хочу отправитькоманда IDENTIFY DEVICE
(0xEC).Устройство ответит 512-байтовым блоком данных.(В частности, меня интересует бит 0 слова 119 - поддержка устройством команды 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
);
Но это совершенно неправильно.Код IoControlCode, отправленный на DeviceIoControl , должен быть действительным IO_CTL, который построен с использованием макроса :
#define CTL_CODE(DeviceType, Function, Method, Access) (
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)
)
Если посмотреть на SDK, существует ряд допустимых коды управления Управление дисками , например:
Но ни одна из них не является 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 и прочитать его ответ?
См. Также
Ответы
Открыть диск с доступом ReadWrite:
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
);
Установить структуру 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;
Call 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();