Отправка команд ATA непосредственно на устройство в Windows?

Я пытаюсь отправить команды 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, есть несколько допустимых Коды управления дисками, например:

  • 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 и прочитать его ответ?

См. также


Answer pieces

Откройте диск с доступом 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;

Вызов 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();
17
задан Ivan Akulov 12 January 2016 в 00:18
поделиться