Как прочитать определенный сектор диска с помощью команды ATA?

Я хочу прочитать определенный сектор (сектор MBR) диска, используя команды ATA в vc++. Я новичок в VC++, поэтому столкнулся с проблемой при отправке команды на диск с помощью DeviceIoControl. Я предоставляю код, который я использую для считывания сектора с помощью команды «Прочитать сектор (ы)» (0x20).

  BOOL status = FALSE;
 PATA_PASS_THROUGH_EX pATAData;
DWORD dataSize = sizeof(ATA_PASS_THROUGH_EX) + 512;
BYTE Buffer[sizeof(ATA_PASS_THROUGH_EX) + 512];
DWORD bytescopied = 0;

    pATAData = (ATA_PASS_THROUGH_EX*)Buffer;

    ZeroMemory(pATAData,dataSize); // clears the buffer

    pATAData->Length = sizeof(ATA_PASS_THROUGH_EX);
    pATAData->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
    pATAData->DataTransferLength = 512;
    pATAData->TimeOutValue = 2;

    pATAData->CurrentTaskFile[1] = 0x01;
    pATAData->CurrentTaskFile[2] = 0x00;
    pATAData->CurrentTaskFile[3] = 0x00;
    pATAData->CurrentTaskFile[4] = 0x00;
    pATAData->AtaFlags =ATA_FLAGS_DATA_IN;

    pATAData->CurrentTaskFile[6] = 0x20; // command Read Sector(s)(0x20)
    /* sends the command to the device, **hDevice** is device handle*/
    status = DeviceIoControl(hDevice, IOCTL_ATA_PASS_THROUGH, pATAData, dataSize,Buffer, dataSize, &bytescopied, NULL );

Я не могу понять, что не так в этом коде и что мне здесь не хватает, но он не работает. Что мне здесь не хватает? Если есть проблема с параметрами структуры PATA_PASS_THROUGH_EX, то скажите, как читать первый сектор (MBR).


person Sam    schedule 08.05.2015    source источник
comment
Вы вызывали GetLastError, чтобы узнать, почему это не удалось?   -  person Retired Ninja    schedule 08.05.2015
comment
Не уверен, что это применимо, поскольку вы не показываете код для открытия устройства, но вы все равно можете взглянуть. stackoverflow.com/questions/3362037/   -  person Retired Ninja    schedule 08.05.2015
comment
Почему у этого есть тег qt? Вы можете получить лучшую помощь с другими тегами, такими как: device, hard-drive или sata. Кроме того, какую ошибку вы получаете?   -  person titusjan    schedule 08.05.2015
comment
Да, я вызываю GetLastError. Выдает ошибку ERROR_INVALID_PARAMETER (0x57). Но я не могу понять, какой параметр неверен. На самом деле я новичок в программировании Windows.   -  person Sam    schedule 08.05.2015
comment
Теги исправлены в соответствии с кодом.   -  person MSalters    schedule 08.05.2015
comment
Спасибо @RetiredNinja за вашу помощь. Я прочитал вашу ссылку, но она дает только информацию о разделе, на самом деле я хочу прочитать полный сектор или несколько секторов. На самом деле я должен выполнять чтение и запись с помощью команд ATA.   -  person Sam    schedule 11.05.2015
comment
Явных ошибок в коде не вижу. (1) Пробовали ли вы выравнивать буферный кеш? (2) Пробовали ли вы более простую команду, такую ​​как IDENTIFY_DEVICE (ECh)?   -  person tchau.dev    schedule 12.05.2015


Ответы (3)


Спасибо всем за вашу помощь. Я получил решение. Маленькая вещь, которую я не заметил. Это Ата Флагс. Я должен отправить несколько флагов. Например.

pATAData->ataFlags = ATA_FLAGS_48BIT_COMMAND | ATA_FLAGS_DRDY_REQUIRED | ATA_FLAGS_DATA_IN

а также отправить код операции ATA команды в PreviousTaskFile[6]. И несколько вещей, на которые следует обратить внимание: каков размер блока жесткого диска? Это может быть более 512 байт, особенно если это большой диск (1 ТБ ... 4 ТБ). Таким образом, вам нужно будет соответствующим образом отрегулировать размеры. Вы можете увидеть, каков размер, выполнив команду EC Identify ATA, а затем посмотрите на результирующую структуру данных.

person Sam    schedule 26.05.2015

Спасибо за помощь ребята. Я получил решение. Я не назначал дескриптор устройства в CurrentTaskFile.

pATAData->CurrentTaskFile[5] = (UCHAR)hDevice;

Но команда IDENTIFY_DEVICE(ECh) успешно отправлялась и без этого. Я не знаю, правильно это или неправильно, но это работает.

person Sam    schedule 12.05.2015
comment
Теперь я могу читать сектора, но теперь мне нужно читать большой диск (до 4 ТБ). Может ли кто-нибудь помочь мне, как отправить данные в CurrentTaskFile [], чтобы прочитать большой космический диск. Поскольку CurrentTaskFile[] является массивом типа UCHAR. Если я хочу прочитать последний сектор с диска объемом 1 ТБ. - person Sam; 12.05.2015
comment
Вам нужно использовать расширенные команды (EXT) вместе с PreviousTaskFile[] - person tchau.dev; 19.05.2015
comment
Относительно CurrentTaskFile[5], также известного как регистр устройства. Старая спецификация ATA зарезервировала бит 6 этого регистра для режима LBA. Это означает, что вы должны установить этот бит, чтобы включить режим LBA, и очистить его, чтобы использовать режим CHS. Для простоты всегда используйте режим LBA, установив для этого регистра значение 0x40. Причина, по которой команда IDENTIFY_DEVICE работает, заключается в том, что она не обращается ни к каким секторам, поэтому ее не волнует режим LBA или CHS. - person tchau.dev; 19.05.2015
comment
Спасибо @tchau.dev . Ваши последние два комментария очень полезны для меня. Да, я должен использовать расширенные команды (EXT) вместе с PreviousTaskFile[] для большого диска. - person Sam; 19.05.2015

Спасибо, ребята, за вашу помощь. После долгого обсуждения я обнаружил, что мне нужно отправлять расширенные команды для большого диска. Но теперь я отправляю команду чтения секторов Ext (0x24 oppcode).

BOOL status = FALSE;
PATA_PASS_THROUGH_EX pATAData;
DWORD dataSize = sizeof(ATA_PASS_THROUGH_EX) + 512;
BYTE Buffer[sizeof(ATA_PASS_THROUGH_EX) + 512];
DWORD bytescopied = 0;

pATAData = (ATA_PASS_THROUGH_EX*)Buffer;

ZeroMemory(pATAData,dataSize); // clears the buffer

pATAData->Length = sizeof(ATA_PASS_THROUGH_EX);
pATAData->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
pATAData->DataTransferLength = 512;
pATAData->TimeOutValue = 2;

pATAData->CurrentTaskFile[0] = 0x00;
pATAData->CurrentTaskFile[1] = 0x01;
pATAData->CurrentTaskFile[2] = 0x01;
pATAData->CurrentTaskFile[3] = 0x00;
pATAData->CurrentTaskFile[4] = 0x00;
pATAData->CurrentTaskFile[5] = 0x40;
pATAData->CurrentTaskFile[7]=  0x00;
pATAData->AtaFlags =ATA_FLAGS_48BIT_COMMAND;

pATAData->PreviousTaskFile[0] = 0x00;
pATAData->PreviousTaskFile[1] = 0x00;
pATAData->PreviousTaskFile[2] = 0x00;
pATAData->PreviousTaskFile[3] = 0x00;
pATAData->PreviousTaskFile[4] = 0x00;
pATAData->PreviousTaskFile[5] = 0x04;
pATAData->PreviousTaskFile[7]=  0x00;

pATAData->CurrentTaskFile[6] = 0x24; // command Read Sector(s) Ext(0x24)
/* sends the command to the device, **hDevice** is device handle*/
status = DeviceIoControl(hDevice, IOCTL_ATA_PASS_THROUGH, pATAData, dataSize,Buffer, dataSize, &bytescopied, NULL );

Но тут такая же проблема. команда выполнена успешно, но не читает ни одного сектора. Я не могу найти какую-либо ошибку.

person Sam    schedule 19.05.2015
comment
При использовании DeviceIoControl необходимо учитывать два типа ошибок. (1) Первый из DeviceIoControl сообщает вам, была ли команда успешно отправлена ​​на устройство. (2) Второй - от самого устройства. В данном случае диск SATA или PATA. Каждая команда возвращает статус, указывающий, была ли команда успешной или нет. Это будет в регистре состояния (CurrentTaskFile[7]) и регистре ошибок (CurrentTaskFile[0]). Регистр состояния сообщает вам, есть ли ошибка, а регистр ошибок сообщает вам тип ошибки. - person tchau.dev; 19.05.2015
comment
У меня не было ни одной из вышеперечисленных ошибок. Все выглядит нормально, но буфер не читается с диска. Регистр состояния (CurrentTaskFile[7] и регистр ошибок (CurrentTaskFile[0]) равны нулю. GetLastError() повторно запускает код (0x57) (ERROR_INVALID_PARAMETER). DeviceIoControl возвращает TRUE, но выходной буфер пуст. Значение параметра lpBytesReturned равно 40 (точно размер структуры PATA_PASS_THROUGH_EX), это означает, что данные с диска не считываются. - person Sam; 20.05.2015
comment
Регистр ошибок может быть равен нулю, но в регистре состояния должен быть хотя бы бит готовности устройства, установленный в единицу (бит 6). Не доверяйте статусу возврата DeviceIoControl(). Похоже, GetLastError() говорит правду. - person tchau.dev; 20.05.2015
comment
Поправка с моей стороны, регистр состояния должен быть таким же, как регистр команды, то есть CurrentTaskFile[6]. - person tchau.dev; 20.05.2015
comment
Нет ошибки нет результата, что делать. Регистр состояния (CurrentTaskFile[7] и регистр ошибок (CurrentTaskFile[0]) оба равны нулю. Только два регистра Регистр команд имеет значение 0x58, а регистр устройства 0xE0 имеет какое-либо возвращаемое значение, которое не помогает. Что мне делать. - person Sam; 25.05.2015
comment
Вы все еще застряли на этом? Если это так, вы можете отправить мне код, и я его протестирую. - person tchau.dev; 01.06.2015
comment
Спасибо @tchau.dev. Теперь он работает. Но вот беда, не проходит ›256 секторов длины передачи (АТА 48-битная способна передавать до 65536 секторов). Я использовал все команды «Чтение секторов», «Чтение нескольких». Я не могу сделать передачу более 256 секторов за один раз. Для 256 секторов работает, но если я отправлю 257 или более, DeviceIOControl вернет 0. Знаете ли вы что-нибудь об этом. - person Sam; 02.06.2015
comment
Да это ограничение. Не уверен, почему, но единственный способ обойти это - отправить ReadFile и WriteFile. Проблема заключается в том, что вы не можете отправить конкретную команду чтения и записи, которую хотите. - person tchau.dev; 02.06.2015
comment
Любая идея, чтобы преодолеть это ограничение. Любая альтернатива. почему мы можем использовать полную мощность 48-битных команд ATA (48-битные ATA способны передавать до 65536 секторов). Только ATA я должен использовать. Спасибо @tchau.dev. - person Sam; 05.06.2015
comment
Ограничение находится на уровне ядра. Большинство компаний пишут свои собственные драйверы для преодоления этого ограничения. Вы можете сделать то же самое. Тем не менее, я бы не рекомендовал это, если вы действительно не знаете, что делаете, или знаете кого-то, кто это делает. - person tchau.dev; 05.06.2015
comment
@Sam Сэм, в чем причина твоей ошибки в этом коде? Как ты это починил? - person Mery Ted; 30.06.2020