Я пытаюсь отправить команды 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
);
Но после этого Im затихал о том, что делать.
Я подумал о передаче 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, существует ряд допустимых Коды управления дисками, например:
- 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 и прочитать его ответ?
См. также
- IOCTL_ATA_PASS_THROUGH Контрольный код
- IOCTL_ATA_PASS_THROUGH_DIRECT Код управления
- Структура ATA_PASS_THROUGH_EX
Ответьте части
Откройте диск с доступом 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
кодом управления IO:
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();