• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья Программирование HDD/SSD. Часть.1 – устройство

Жёсткие диски это тот раздел программирования, который покрыт мраком и тайной. Дефицит информации на эту тему накладывает свой отпечаток, и даже простое копирование больших объёмов данных может стать нетривиальной задачей. Но если копнуть глубже, оказывается не всё так плохо, и большинство базовых операций на низком уровне доступно не только админу, но и простому смертному юзеру. На практике, мифы о высоком либидо и буйном темпераменте дисков несколько преувеличены, и надеюсь данная статья поможет нам разобраться в этом. Поскольку материал получился обширным, пришлось разделить его на две части – теория и практика.

В этой части:

• Общие сведения
• Интерфейсы ATA/SATA
• Регистры IDE-устройств
• Интерфейсы SCSI/SAS
• Выводы
-------------------------------------------------

Общие сведения

Любые накопители HDD относятся к устройствам с интегрированным контролёром. Это означает, что на материнской плате находится лишь обслуживающий шлейф шинный адаптер HBA – , который представляет собой обычный мост для согласования шин АТА/SATA, с магистральной системной шиной PCI. А вот управляющий непосредственно диском контролёр (и его регистры) расположены уже на плате самого жёсткого диска. Такие девайсы принимают аббревиатуру IDE, или Integrated Drive Electronics.

Термин-же АТА (AT Attachment for Disk Drive) уходит корнями в прошлое, когда примитивный дисковый контролёр был частью материнской платы. Нужно отметить, что подобная схема благополучно дожила и до наших дней, в виде контролёра гибких дисков Floppy-Disk-Drive (здесь в устройство заложена только механика). Таким образом, на данный момент термин АТА/IDE подразумевает дисковый накопитель со-встроенным в тело контролёром.

Все IDE-устройства поддерживают только блочный обмен данным, когда мин.порцией чтения/записи является сектор размером 512 байт (4096 для Advanced-Format AF). Позже, на вооружение была принята спецификация ATAPI – ATA Packet Interface. Отличается она тем, что если в АТА команды 1-байтные (плюс ещё байт как аргумент, итого 2-байта), то в ATAPI эту команду нужно заворачивать в пакет определённой структуры CDB (Command Descriptor Block) и в таком виде отсылать уже драйверу. По сути, способ с использованием командных пакетов не нов, и для интерфейса ATAPI его слизали с древней спецификации SCSI. Как говорится, "всё новое – это хорошо забытое/старое" и ничего лучше пока придумать не могут. Главное преподнести это громко..

Для прикладных программистов SCSI открывает большие возможности, хотя и требует привилегий админа в системе. Он позволяет общаться с диском напрямую, минуя даже драйверы Win. В своё время, интерфейс был разработан специально для устройств со-встроенными контролёрами, которые считались мини-компьютерами (диски, принтеры, CD-ROM и прочие). Собственно об этом прямым текстом сообщает и аббревиатура SCSI –
.

В наш век мы стали очевидцами преображения параллельного SCSI в достойный внимания последовательный интерфейс дисковых подсистем SAS – Serial Attached SCSI. Windows всех мастей предлагает нам свою поддержку этой технологии в виде механизма ASPI - "Advanced SCSI Programming Interface", и его расширения SPTI – "SCSI Pass-Through Interface" (сквозной вариант). Необходимые для его работы функции сосредоточены в системной библиотеке wnaspi32.dll, хотя если мы устанавливаем софт фирмы "Adaptec", то к нему непременно прилагается сторонний их драйвер aspi.sys.

Не верьте утверждениям, что из прикладного уровня у нас нет доступа к регистрам жёсткого диска – это вовсе не так! К примеру функция взаимодействия с драйверами DeviceIoControl() имеет ряд IOCTL-кодов, которым в качестве параметров передаётся структура SENDCMDINPARAMS. В этой структуре имеется вложенная структура
, в которой и перечисляются все/восемь физических регистров контролёра HDD. Нам остаётся лишь указать в полях данных структур требуемые значения, и передать их драйверу посредством упомянутой функции.

Таким-макаром мы можем посылать накопителю любые АТА-команды, список которых регламентирует спецификация под названием ACS – (доступная версия вроде 4, датированная 2016 годом). Эта спека в красках расписывает каждую АТА-команду, и на несколько световых лет приблизит нас к решению задач.



Интерфейсы ATA/SATA

В современной архитектуре, основной информационной артерией является параллельная шина PCI. Она объединяет буквально все внешние устройства материнской платы, и в своём зародыше была даже фронтальной шиной CPU. Разрядность 32-бита при частоте 33 МГц. Чтобы получить пропускную способность, нужно разрядность в байтах [4] умножить на частоту = 132 Мб/сек. Шина полностью оправдала надежды разработчиков и позже появились ещё несколько её версий:


Версия
Частота
Разрядность
Скорость
PCI ver.2.3
66 MГц
32-бит
266 Мб/с
PCI64 ver.2.3
66 MHz
64-бит
533 Мб/с
PCI-Х ver.2.0
533 MHz
64-бит
4096 Мб/с

Что касается теоретической пропускной способности параллельного интерфейса ATA/IDE, то она не превышает отметки в 133 Мб/сек (а в реале и того меньше, см.тест скорости в HD-Tune). Связано это с тем, что при передачи данных на более высоких частотах, сигналы на каждом из 32-х проводников начинают отставать друг-от-друга по времени, и в конечной точке приходится собирать их в буфер. А где буфер, там и тормоза.

Именно поэтому инженеры перешли на последовательный интерфейс SATA, в котором шина 1-битная, зато работает она на частоте 1.5 ГГц. В результате, получаем пропускную способность 1.5 Гбит/сек =150 Мб/с. Дальше, по нарастающей мир увидел ещё две версии SATA с удвоенными частотами:


SATA-1
150 Мб/с
PCI ver.2.0 (Parallel)
SATA-2
300 Мб/с
PCI-Х ver.2.0 (Parallel)
SATA-3
600 Мб/с
PCI-Express (Serial)

Посмотрим на рисунок ниже..
Здесь, для согласования шин ATA/SATA с транспортной жилой чипсета применяются мосты, которые играют роль интерфейсных контролёров HDD. В случае с устаревшим АТА это даже не контролёр, а простой адаптер шины. Как-правило, встроен он в мат.плату, хотя может быть и более совершенным в виде внешней платы PCI для организации RAID-массивов.

АТА хост-адаптер имеет два внешних порта, которые числятся в системном пространстве под номерами 1F0h и 170h. Эти порты открывают доступ к 8-ми регистрам встроенного в диск контролёра.

В отличии от АТА, хост-адаптер SATA называют уже контролёром, поскольку помимо обычного моста в него заложены и функции реального контролёра диска. Встроенный для каждого из портов отдельный UDMA, возможность захватывать PCI-шину в своё распоряжение (Bus-Mastering), а так-же отображаемые в нём физические регистры HDD, присваивают ему более высокий приоритет, по сравнению с базовым АТА-адаптером. Рисунок ниже демонстрирует сказанное:

ATA_face.png


Устройства АТА/IDE соединяются с хостом посредством 80-жильного кабеля. На каждом порту могут висеть 2-устройства Master/Slave. Не смотря, что девайсов на канале два, в каждый момент времени только одно из них может использовать шину. Причиной тому способ адресации устройств, для чего выделяется всего 1-бит под названием "Device Select" (спрятан в регистре 1F6h для первого канала, и 176h для второго). Поскольку это бит, он может принимать только два значения – нуль адресует мастера, а единица перенаправляет запросы в Slave. Фактически, параллельно могут работать только два устройства на разных каналах АТА. Здесь радует то, что при работе с диском в Win, нам не нужно адресовать устройства явно, т.к. мы будем обращаться к диску по его дескриптору Handle – об остальном позаботиться уже системный драйвер.

В зависимости от типа HDD, чипсет может сконфигурировать АТА хост-адаптер на работу в одном из двух режимов – оставшийся в наследство "Legacy-ATA", и типичный для современной архитектуры режим "PCI-IDE". В первом случае, обмен HDD с ОЗУ происходит только под управлением процессора и называется он PIO – Programmable I/O. Процессору приходится ждать окончания операций и в это время он не может заниматься чем-то другим. Здесь для чтения/записи секторов применяются инструкции ассемблера IN/OUT, а так-же их мод с префиксом REP. Этот режим необходим для сервисных работ с диском (макс.скорость 14 Мб/с), и абсолютно не пригоден для обмена большими массивами данных.

Поэтому ввели и второй режим работы АТА хост-адаптера - это "PCI-IDE". В нём задействуется DMA-контролёр (Direct Memory Access, прямой доступ к памяти), и вообще полностью меняется программный облик адаптера. Чипсет не может менять режимы интерфейса динамически – биос запрашивает его поддержку у диска при включении машины. В это время, процедура POST отправляет контролёру HDD запрос IDENTIFY_DEVICE, на что диск возвращает свой паспорт размером 512-байт (один сектор). Анализируя поля паспорта, биос определяет версию DMA конкретного диска и по ней выставляет режим.

После того-как всё настроено, прямой обмен с памятью в режиме DMA происходит только по инициативе самого контролёра HDD. Для этого предусмотрены спец.линии в шлейфе, по которым передаются не менее специальные сигналы DREQ и DACK# (решётка обозначает низкий активный уровень нуль). Когда диск планирует обмен по DMA, он посылает хосту запрос DREQ (DMA-Request), на что хост отвечает (или нет) сигналом подтверждения DACK# (Acknowledgment). После этого, процессор не вмешивается уже в диалог диска с памятью, и может заниматься другими делами. Сигналы, которые выставляет хост на шину, представлены рисунком ниже:

Face_signal.png


С хост-контролёром SATA дела обстоят чуть иначе. В нём уже вырезали режим Legacy-ATA, и для совместимости оставили только PCI-IDE и то, чтобы на программном уровне эмулировать пару устройств Master/Slave. Зато добавлен новый режим DPA – Direct-Port-Access (прямой доступ к портам). В купе с архитектурным решением в виде контролёра AHCI (Advanced Host Controller Interface) он полностью отказывается от модели M/S, когда все четыре SATA-порта абсолютно независимы, и обмен по ним может осуществляться параллельно во времени.

Для быстрого доступа, регистры SATA отображаются в память, а их базовые адреса можно прочитать из кфг.пространства PCI, по смещениям BAR0-BAR4. В связи с тем, что эти регионы памяти недоступны из прикладного уровня Win, мы будем программировать SATA только в унаследованном режиме PCI-IDE.


Регистры контролёра HDD

В независимости от типа интерфейса ATA или SATA, их контролёры имеют базовый набор физических регистров, которые одинаковы для всех. Отличается только доступ к ним – через системные порты 1F0-1F7h, или-же память MMIO (Memory-Mapped-I/O). Базовый набор включает в себя восемь 1-байтных регистров, список и назначение которых представлен в таблице ниже:

ATA_Reg.png


Рассмотрим одну транзакацию (цикл обмена) на шине ATA..

• Чтобы произвести какую-нибудь операцию с сектором диска, сначала в командном регистре 1F7h мы должны указать код этой операции. Ознакомиться со-списком всех кодов можно в спецификации ATA-Command-Set (см.линк в начале статьи). Команда может иметь параметр, тогда заносим его в регистр-свойств 1F1h.

• Если операция подразумевает чтение/запись секторов, то в регистре-счётчика 1F2h нужно указать кол-во секторов для R/W (макс.256-штук за раз), а в четырёх регистрах 1F3-1F6h определяем стартовый номер сектора в формате LBA (Logical-Block-Address). В реальном режиме, началом операции является момент записи команды в регистр 1F7h, а в защищённом – команду выполняет функция DeviceIoControl(), так-что все регистры можно заполнять заранее.

• Мин.порцией обмена с диском является 512-байтный сектор, но регистр-данных 1F0h имеет размер всего 1-байт. Поэтому контролёр HDD в цикле будет обновлять регистр 1F0h всё новыми и новыми байтами, не затрагивая при этом остальных регистров. Цикл будет продолжаться до тех пор, пока контролёр не считает весь сектор с диска. По окончании операции, чтением регистра 1F7h можно проверить её статус, и если бит [0] в нём будет взведён, значит произошла ошибка, а какая именно – хранит регистр 1F1h.

• Биты [7,5] старшей тетрады регистра 1F6h зарезервированы и должны быть установлены в единицу. Бит [6] меняет трехмерную адресацию секторов CHS на последовательную LBA, а под выбор устройства на канале Master/Slave отводится бит [4] "Device Select".

Выше упоминалось, что при работе с диском, функция DeviceIoControl() в качестве аргумента может принимать указатель на структуру SENDCMDINPARAMS, а она в свою очередь имеет вложенную IDEREGS (см.сишный хидер ntdddisk.h). Если приглядеться к последней, то каждый её член описывает один из регистров контролёра диска! Это позволяет прямо из прикладного уровня передавать любые АТА-команды через драйвер диску, со всеми вытекающими последствиями:


C-подобный:
struct IDEREGS
    bFeaturesReg         db  0   ;// 1F1h – аргумент команд
    bSectorCountReg      db  0   ;// 1F2h – счётчик секторов
    bSectorNumberReg     db  0   ;// 1F3h – номер сектора
    bCylLowReg           db  0   ;// 1F4h – номер цилиндра
    bCylHighReg          db  0   ;// ^^^
    bDriveHeadReg        db  0   ;// 1F6h – номер головки
    bCommandReg          db  0   ;// 1F7h – АТА-команда
    bReserved            db  0   ;
ends

struct SENDCMDINPARAMS
    cBufferSize          dd  sizeof.SENDCMDINPARAMS
    irDriveRegs          IDEREGS     ;// вложенная структура с регистрами
    bDriveNumber         db  0       ;// номер диска (игнор, т.к. открываем по хэндлу)
    bReserved            rb  19      ;//
    bBuffer              rb  512     ;// входной буфер.
ends

В следующей части мы пощупаем эти структуры руками, а пока поверхностно рассмотрим, что из себя представляют более продвинутые интерфейсы подключения IDE.


Интерфейсы SCSI и SAS

Как-правило, на десктопных платах бесполезно искать контролёры SCSI – их там попросту нет (в отличии от серверных). Однако любой чипсет эмулирует этот интерфейс на случай, если пользователь решит установить внешний SCSI-адаптер в слот PCI. На рынке можно встретить всякие их разновидности, например как на рисунке ниже:

SCSI_01.png


SCSI имеет множество преимуществ перед интерфейсами ATA/SATA – рассмотрим их бегло..
Во-первых, для адресации устройств на шине выделяется 4-бита, а значит всего девайсов на одной 16-битной шине может быть 16 (Wide-SCSI), в то время как АТА поддерживает только Master/Slave.

Каждое устройство должно иметь свой уникальный идентификатор Target-ID. В случае с параллельным SCSI, идентификатор задаётся перемычками в зад, а в случае с последовательным SAS – его назначает хост автоматически. Когда несколько устройств одновременно запрашивают шину, арбитраж выигрывает тот, у которого наивысший ID (самый приоритетный #15 хост забирает себе).

Спецификацией SCSI предусматривается параллельная передача данных по 8, 16 или 32 линиям данных. Шина является магистральной, хотя устройства подключаются к ней по принципу "последовательной цепочки". Устройства SCSI могут иметь два разъёма – один входной, а другой выходной. Все устройства на одной шине объединяются в цепочку, один конец которой подключается к контролёру интерфейса. Устройства на шине работают независимо и могут обмениваться данными как с хостом, так и друг-с-другом.

SCSI_face.png


Термины Target и LUN (Logical-Unit-Address) используются для 4-уровневой адресации устройств на одной шине: (1)номер SCSI-адаптера, (2)номер шины, (3)идентификатор девайса Target-ID, и его логический номер LUN в цепочке. С номером адаптера и шины всё ясно, а дальше.. На одной шине, устройство с данным ID может быть только одно – это и есть Target или "целевое устройство". Любое SCSI-Device относится к IDE и содержит в себе контролёр, который может обслуживать до 8-ми дополнительных устройств – вот они-то и нумеруются с помощью LUN.

Вся эта котовасия с лунами и таргет на практике нам не нужна, поскольку мы будем открывать устройства по их именам функцией CreateFile() и дальше уже обращаться к нему по дескриптору. Однако знать теорию нужно хотя-бы для того, чтобы понимать, зачем предусмотрено то-или-иное поле в структурах.

Интерфейс SAS или Serial Attached SCSI - это отдельная тема и сама потянет на пару-тройку статей. Кого интересуют детали, можете почитать материал по
, где он рассматривается во-всей красе.

Что касается программной поддержки, то здесь так-же используется функция DeviceIoControl(), только IOCTL-коды у этого интерфейса свои. Один из таких кодов SCSI_GET_INQUIRY_DATA я использовал в своей программе, чтобы просканировать чипсет на наличие в нём эмулируемых SCSI-портов. При том-что у меня нет физического адаптера, прога обнаружила целых 4-шины, на которых висят 2 моих винта и один DVD-ROM. Исходник мы обсудим в следующей части статьи. а здесь я прикреплю уже готовый к исполнению файл, чтобы вы могли ознакомиться с портами на своей машине:


Inquiry_Data.png


Данный IOCTL-код возвращает структуру SCSI_INQUIRY_DATA (см.хидер ntddscsi.h), и нам остаётся лишь вывести на консоль эти данные:

C-подобный:
struct SCSI_INQUIRY_DATA
  PathId                   db  0    ;// номер шины, на которой висит устройство
  TargetId                 db  0    ;// номер устройства на шине
  Lun                      db  0    ;// номер лог.единицы на целевом устройстве
  DeviceClaimed            db  0    ;// TRUE указывает, что устройство было запрошено "драйвером класса"
  InquiryDataLength        dd  0    ;// длина в байтах данных запроса
  NextInquiryDataOffset    dd  0    ;// смещение к данным сл.устройства
  InquiryData              rb  8    ;// буфер, содержащий данные запроса
  ProductId                rb  24   ;// имя устройства,
  ProductRevisionLevel     rb  4    ;//    ..и его ревизия.
ends


Заключение

Программирование жёстких дисков в зародыше дело не простое, а без базовых знаний в этой области и делать нечего. Теоретическая часть настолько обширна, что охватить весь материал в одной статье не представляется возможным. Но и в этом случае, вводная часть вон разбухла до размеров слона, хотя я старался делать акцент только на необходимых на мой взгляд вещах.

Зато теперь у нас в запазухе есть некоторый багаж, и в следующей части можно будет рассмотреть программную сторону интерфейсов. Это система АТА-команд, идентификация устройств на шинах, атрибуты S.M.A.R.T жёстких дисков, ну и конечно-же чтение/запись сырых RAW-секторов. До скорого!
 

Вложения

  • GET_SCSI_INQUIRY_DATA.ZIP
    716 байт · Просмотры: 649
Последнее редактирование:

SearcherSlava

Red Team
10.06.2017
943
1 260
BIT
153
Жёсткие диски это та часть программирования, которая покрыта мраком и тайной. Дефицит информации на эту тему накладывает свой отпечаток, и даже простое копирование больших объёмов данных становится нетривиальной задачей. Но если копнуть глубже, оказывается не всё так плохо, и большинство базовых операций на низком уровне доступно не только админу, но и простому смертному юзеру. На практике, мифы о высоком либидо и буйном темпераменте дисков несколько преувеличены, и надеюсь данная статья поможет разобраться нам в этом. Поскольку материал получился обширным, пришлось разделить его на две части – теория и практика.

В этой части:

• Общие сведения
• Интерфейсы ATA/SATA
• Регистры IDE-устройств
• Интерфейсы SCSI/SAS
• Выводы
-------------------------------------------------

Общие сведения

Любые накопители HDD относятся к устройствам с интегрированным контролёром. Это означает, что на материнской плате находится лишь обслуживающий шлейф шинный адаптер HBA – , который представляет собой обычный мост для согласования шин АТА/SATA, с магистральной системной шиной PCI. А вот управляющий непосредственно диском контролёр (и его регистры) расположены уже на плате самого жёсткого диска. Такие девайсы принимают аббревиатуру IDE, или Integrated Drive Electronics.

Термин-же АТА (AT Attachment for Disk Drive) уходит корнями в прошлое с архитектурой АТ, когда примитивный дисковый контролёр был частью материнской платы. Нужно отметить, что подобная схема благополучно дожила и до наших дней, в виде контролёра гибких дисков Floppy-Disk-Drive (здесь в устройство заложена только механика). Таким образом, на данный момент термин АТА/IDE подразумевает дисковый накопитель со-встроенным в тело контролёром.

Все устройства IDE поддерживают только блочный обмен данным, когда мин.порцией чтения/записи является сектор размером 512 байт (4096 для Advanced-Format AF). Позже, на вооружение была принята спецификация ATAPI – ATA Packet Interface. Отличается она тем, что если в АТА команды 1-байтные (плюс ещё байт как аргумент, итого 2-байта), то в ATAPI эту команду нужно заворачивать в пакет определённой структуры CDB (Command Descriptor Block) и в таком виде отсылать уже драйверу. По сути, способ с использованием командных пакетов не нов, и для интерфейса ATAPI его слизали с древней спецификации SCSI. Как говорится, "всё новое – это хорошо забытое/старое" и ничего лучше пока придумать не смогли. Главное преподнести это громко..

Для прикладных программистов SCSI открывает большие возможности, хотя и требует привилегий админа в системе. Он позволяет общаться с диском напрямую, минуя даже драйверы Win. В своё время, SCSI был разработан специально для устройств со-встроенными контролёрами, которые считались мини-компьютерами (диски, принтеры, CD-ROM и прочие). Собственно об этом прямым текстом сообщает и аббревиатура SCSI –
.

В наш век мы стали очевидцами преображения параллельного SCSI в достойный внимания последовательный интерфейс дисковых подсистем SAS – Serial Attached SCSI. Windows всех мастей предлагает нам свою поддержку этой технологии в виде механизма ASPI - "Advanced SCSI Programming Interface", и его расширения SPTI – "SCSI Pass-Through Interface" (сквозной интерфейс). Необходимые для его работы стандартные функции сосредоточены в системной библиотеке wnaspi32.dll, хотя если мы устанавливаем софт фирмы Adaptec, то к нему непременно прилагается сторонний их драйвер aspi.sys.

Не верьте утверждениям, что из прикладного уровня у нас нет доступа к регистрам жёсткого диска – это вовсе не так! К примеру функция взаимодействия с драйверами устройств DeviceIoControl() имеет ряд IOCTL-кодов, которым в качестве параметров передаётся структура SENDCMDINPARAMS. В этой структуре имеется вложенная структура
, в которой и перечисляются все/восемь физических регистров контролёра HDD. Нам остаётся лишь указать в полях данных структур требуемые значения, и передать их драйверу посредством упомянутой функции.

Таким-макаром мы можем посылать накопителю любые АТА-команды, список которых регламентирует спецификация под названием ACS – (доступная версия вроде 4, датированная 2016 годом). Эта спека в красках расписывает каждую АТА-команду, и на несколько световых лет приблизит нас к решению задач.



Интерфейсы ATA/SATA

В современной архитектуре, основной информационной артерией является параллельная шина PCI. Она объединяет буквально все внешние устройства материнской платы, и в своём зародыше была даже фронтальной шиной CPU. Разрядность 32-бита при частоте 33 МГц. Чтобы получить пропускную способность в секунду, нужно разрядность в байтах [4] умножить на 33 МГц = 132 Мб/сек. Шина полностью оправдала надежды разработчиков и позже появились ещё несколько её версий:


Версия
Частота
Разрядность
Скорость
PCI ver.2.3
66 MГц
32-бит
266 Мб/с
PCI64 ver.2.3
66 MHz
64-бит
533 Мб/с
PCI-Х ver.2.0
533 MHz
64-бит
4096 Мб/с

Что касается теоретической пропускной способности параллельного интерфейса ATA/IDE, то она не превышает отметки в 133 Мб/сек (в реале и того меньше, см.тест скорости в HD-Tune). Связано это с тем, что при передачи данных на более высоких частотах, сигналы на каждом из 32-х проводников начинают отставать друг-от-друга по времени, и в конечной точке приходится собирать их в буфер. А где буфер, там и тормоза.

Именно поэтому инженеры перешли на последовательный интерфейс SATA, в котором шина 1-битная, зато работает она на частоте 1.5 ГГц. В результате, получаем пропускную способность 1.5 Гбит/сек =150 Мб/с (чуть больше, чем у АТА-7). Дальше, по нарастающей мир увидел ещё две версии SATA с удвоенными частотами:


SATA-1
150 Мб/с
PCI ver.2.0 (Parallel)
SATA-2
300 Мб/с
PCI-Х ver.2.0 (Parallel)
SATA-3
600 Мб/с
PCI-Express (Serial)

Посмотрим на рисунок ниже..
Здесь, для согласования шин ATA/SATA с транспортной жилой чипсета применяются мосты, которые играют роль интерфейсных контролёров HDD. В случае с устаревшим АТА это даже не контролёр, а простой адаптер шины. Как-правило, встроен он в боард (дискретный), хотя может быть и более совершенным в виде внешней платы PCI для организации RAID-массивов. АТА хост-адаптер имеет два внешних порта, которые числятся в системном пространстве под номерами 1F0h и 170h. Эти порты открывают доступ к 8-ми регистрам встроенного в диск контролёра.

В отличии от АТА, хост-адаптер SATA называют уже контролёром, поскольку помимо обычного моста в него заложены и функции реального контролёра диска. Встроенный для каждого из портов отдельный UDMA-контролёр, возможность захватывать PCI-шину в своё распоряжение (Bus-Mastering), а так-же отображаемые в нём физические регистры HDD, присваивают ему более высокий приоритет, по сравнению с базовым АТА-адаптером. Рисунок ниже демонстрирует сказанное:

Посмотреть вложение 43041

Устройства АТА/IDE соединяются с хостом посредством 80-жильного кабеля. На каждом порту могут висеть 2-устройства Master/Slave. Не смотря, что девайсов на канале два, в каждый момент времени только одно из них может использовать шину. Причиной тому способ адресации устройств на канале, для чего выделяется всего 1-бит под названием "Device Select" (спрятан в регистре 1F6h для первого канала, и 176h для второго). Поскольку это бит, он может принимать только два значения – нуль адресует мастера, а единица перенаправляет запросы в Slave. Фактически, параллельно могут работать только два устройства на разных каналах АТА. Здесь радует то, что при работе с диском в Win, нам не нужно адресовать устройства явно, т.к. мы будем обращаться к диску по его дескриптору Handle – об остальном позаботиться уже системный драйвер.

В зависимости от типа HDD, чипсет может сконфигурировать АТА хост-адаптер на работу в одном из двух режимов – оставшийся в наследство "Legacy-ATA", и типичный для архитектуры АТХ режим "PCI-IDE". В первом случае, обмен HDD с ОЗУ происходит только под управлением процессора и называется он PIO – Programmable I/O. Процессору приходится ждать окончания операций и в это время он не может заниматься чем-то другим. Здесь для чтения/записи секторов применяются инструкции ассемблера in/out, а так-же их мод с префиксом rep. Этот режим необходим для сервисных работ с диском (макс.скорость 14 Мб/с), но абсолютно не пригоден для обмена большими массивами данных.

Поэтому предусмотрен и второй режим работы АТА хост-адаптера - "PCI-IDE". В нём задействуется DMA-контролёр (Direct Memory Access, прямой доступ к памяти), и вообще полностью меняется программный облик адаптера. Чипсет не может менять режимы интерфейса динамически – биос запрашивает его поддержку у диска при включении машины. В это время, процедура POST отправляет контролёру HDD запрос IDENTIFY_DEVICE, на что диск возвращает свой паспорт размером 512-байт (один сектор). Анализируя поля паспорта, биос определяет версию DMA конкретного диска и по ней выставляет режим.

После того-как всё настроено, прямой обмен с памятью в режиме DMA происходит только по инициативе самого контролёра HDD. Для этого предусмотрены спец.линии в шлейфе, по которым передаются не менее специальные сигналы DREQ и DACK# (решётка обозначает активный уровень нуль). Когда диск планирует обмен по DMA, он посылает хосту запрос DREQ (DMA-Request), на что хост отвечает (или нет) сигналом подтверждения DACK# (Acknowledgment). После этого, процессор не вмешивается уже в диалог диска с памятью, и может заниматься другими делами. Сигналы, которые выставляет хост на шину, представлены рисунком ниже:

Посмотреть вложение 43042

С хост-контролёром SATA дела обстоят чуть иначе.. В нём уже вырезали режим Legacy-ATA, и для совместимости оставили только PCI-IDE и то, чтобы на программном уровне эмулировать пару АТА-девайсов Master/Slave. Зато добавлен новый режим DPA – Direct-Port-Access (прямой доступ к портам). В купе с архитектурным решением в виде контролёра AHCI (Advanced Host Controller Interface) он полностью отказывается от модели Master/Slave, когда все четыре SATA-порта абсолютно независимы, и обмен по ним может осуществляться параллельно во времени.

Для быстрого доступа, регистры SATA отображаются в память, а их базовые адреса можно прочитать из кфг.пространства PCI, по смещениям BAR0-BAR4. В связи с тем, что эти регионы памяти недоступны из прикладного уровня Win, мы будем программировать SATA только в унаследованном режиме PCI-IDE.


Регистры контролёра HDD

В независимости от типа интерфейса ATA или SATA, их контролёры имеют базовый набор физических регистров, которые одинаковы для всех. Отличается только доступ к ним – через системные порты 1F0-1F7h, или-же через память MMIO (Memory-Mapped-I/O). Базовый набор включает в себя восемь 1-байтных регистров, список и назначение которых представлен в таблице ниже:

Посмотреть вложение 43043

Рассмотрим одну транзакацию (цикл обмена) на шине ATA..

• Чтобы произвести какую-нибудь операцию с сектором диска, сначала в командном регистре 1F7h мы должны указать код этой операции. Ознакомиться со-списком всех кодов можно в спецификации ATA-Command-Set (см.линк в начале статьи). Команда может иметь параметр, тогда заносим его в регистр-свойств 1F1h.

• Если операция подразумевает чтение/запись секторов, то в регистре-счётчика 1F2h нужно указать кол-во секторов для R/W (макс.256-штук за раз), а в четырёх регистрах 1F3-1F6h определяем стартовый номер сектора в формате LBA (Logical-Block-Address). В реальном режиме, началом операции является момент записи команды в регистр 1F7h, а в защищённом – команду выполняет функция DeviceIoControl(), так-что все регистры можно заполнять заранее.

• Мин.порцией обмена с диском является 512-байтный сектор, но регистр-данных 1F0h имеет размер всего 1-байт. Поэтому контролёр HDD в цикле будет обновлять регистр 1F0h всё новыми и новыми байтами, не затрагивая при этом остальных регистров. Цикл будет продолжаться до тех пор, пока контролёр не считает весь сектор с диска. По окончании операции, чтением регистра 1F7h можно проверить её статус, и если бит [0] в нём будет взведён, значит произошла ошибка, а какая именно – хранит регистр 1F1h.

• Биты [7,5] старшей тетрады регистра 1F6h зарезервированы и должны быть установлены в единицу. Бит [6] меняет трехмерную адресацию секторов CHS на последовательную LBA, а под выбор устройства на канале Master/Slave отводится бит [4] "Device Select".

Выше упоминалось, что при работе с диском, функция DeviceIoControl() в качестве аргумента может принимать указатель на структуру SENDCMDINPARAMS, а она в свою очередь имеет вложенную структуру IDEREGS (см.сишный хидер ntdddisk.h). Если приглядеться к последней, то каждый её член описывает один из регистров контролёра диска! Это позволяет прямо из прикладного уровня передавать любые АТА-команды через драйвер диску, со всеми вытекающими последствиями:


C-подобный:
struct IDEREGS
    bFeaturesReg         db  0   ;// 1F1h – аргумент команд
    bSectorCountReg      db  0   ;// 1F2h – счётчик секторов
    bSectorNumberReg     db  0   ;// 1F3h – номер сектора
    bCylLowReg           db  0   ;// 1F4h – номер цилиндра
    bCylHighReg          db  0   ;// ^^^
    bDriveHeadReg        db  0   ;// 1F6h – номер головки
    bCommandReg          db  0   ;// 1F7h – АТА-команда
    bReserved            db  0   ;
ends

struct SENDCMDINPARAMS
    cBufferSize          dd  sizeof.SENDCMDINPARAMS
    irDriveRegs          IDEREGS     ;// вложенная структура с регистрами
    bDriveNumber         db  0       ;// номер диска (игнор, т.к. открываем по хэндлу)
    bReserved            rb  19      ;//
    bBuffer              rb  512     ;// входной буфер.
ends

В следующей части мы пощупаем эти структуры руками, а пока поверхностно рассмотрим, что из себя представляют более продвинутые интерфейсы подключения IDE.


Интерфейсы SCSI и SAS

Как-правило, на десктопных платах бесполезно искать контролёры SCSI – их там попросту нет (в отличии от серверных). Однако любой чипсет эмулирует этот интерфейс на случай, если пользователь решит установить внешний SCSI-адаптер в слот PCI. На рынке можно встретить всякие их разновидности, например как на рисунке ниже:

Посмотреть вложение 43044

SCSI имеет множество преимуществ перед интерфейсами ATA/SATA – рассмотрим их бегло..
Во-первых, для адресации устройств на шине SCSI выделяется 4-бита, а значит всего девайсов на одной 16-битной шине может быть 16 (Wide-SCSI), в то время как АТА поддерживает только Master/Slave.

Каждое устройство должно иметь свой уникальный идентификатор Target-ID. В случае с параллельным SCSI, идентификатор задаётся перемычками в зад, а в случае с последовательным SAS – его назначает хост автоматически. Когда несколько устройств одновременно запрашивают шину, арбитраж выигрывает тот, у которого наивысший ID (самый приоритетный 15 хост забирает себе).

Спецификацией SCSI предусматривается параллельная передача данных по 8, 16 или 32 линиям данных. Шина является магистральной, хотя устройства подключаются к ней по принципу "последовательной цепочки". Каждое SCSI-устройство имеет два разъема – один входной, а другой выходной. Все устройства на одной шине объединяются в цепочку, один конец которой подключается к контроллёру интерфейса. Устройства на шине работают независимо и могут обмениваться данными как с хостом, так и друг-с-другом.

Посмотреть вложение 43045

Термины Target и LUN (Logical-Unit-Address) используются для адресации устройства на одной шине. Итого получаем 4-уровневую адресацию устройств: (1)номер SCSI-адаптера, (2)номер шины BUS, (3)идентификатор девайса Target-ID, и логический номер в цепочке LUN. С номером адаптера и шины всё ясно, а дальше - на одной шине, устройство с данным ID может быть только одно – это и есть Target или "целевое устройство". Любое SCSI-устройство относится к IDE и содержит в себе контролёр, который может обслуживать до 8-ми дополнительных устройств – вот они-то и нумеруются с помощью LUN.

Интерфейс SAS или Serial Attached SCSI - это отдельная тема и сама потянет на пару-тройку статей. Кого интересуют детали, можете почитать материал по
, где он рассматривается во-всей красе.

Что касается программной поддержки, то здесь так-же используется функция DeviceIoControl(), только IOCTL-коды у этого интерфейса свои и начинаются с приставки SCSI. Один из таких кодов SCSI_GET_INQUIRY_DATA я использовал в своей программе, чтобы просканировать чипсет на наличие в нём эмулируемых SCSI-портов. При том-что у меня нет физического адаптера, прога обнаружила целых 4-шины, на которых висят 2 моих винта и один DVD-ROM. Исходник мы обсудим в следующей части статьи. а здесь я прикреплю уже готовый экзешник, чтобы вы могли ознакомиться с портами своей машины:


Посмотреть вложение 43046

Данный IOCTL-код возвращает структуру SCSI_INQUIRY_DATA (см.хидер ntddscsi.h), и нам остаётся лишь вывести на консоль эти данные:

C-подобный:
struct SCSI_INQUIRY_DATA
  PathId                   db  0    ;// номер шины, на которой висит устройство
  TargetId                 db  0    ;// номер устройства на шине
  Lun                      db  0    ;// номер лог.единицы на целевом устройстве
  DeviceClaimed            db  0    ;// TRUE указывает, что устройство было запрошено "драйвером класса"
  InquiryDataLength        dd  0    ;// длина в байтах данных запроса
  NextInquiryDataOffset    dd  0    ;// смещение к данным сл.устройства
  InquiryData              rb  8    ;// буфер, содержащий данные запроса
  ProductId                rb  24   ;// имя устройства,
  ProductRevisionLevel     rb  4    ;//    ..и его ревизия.
ends


Заключение

Программирование жёстких дисков в зародыше дело не простое, а без базовых знаний в этой области и вообще нечего делать. Теоретическая часть настолько обширна, что охватить весь материал в одной статье не представляется возможным. Но и в этом случае, статья вон разбухла до размеров слона, хотя я старался делать акцент только на необходимых на мой взгляд вещах. Зато теперь у нас в запазухе есть некоторый багаж, и в следующей части можно будет рассмотреть программную сторону интерфейсов. Это система АТА-команд, идентификация устройств на шинах, атрибуты S.M.A.R.T жёстких дисков, ну и конечно-же чтение/запись сырых RAW-секторов. До скорого!

Здрав будь!

Пономарев В.А. Моделирование и оптимизация функционирования твердотельной системы хранения данных
Климов Р.В. ИССЛЕДОВАНИЕ МЕТОДОВ ОПТИМИЗАЦИИ НАГРУЗКИ ВОССТАНОВЛЕНИЯ РАСПРЕДЕЛЕННЫХ СИСТЕМ ХРАНЕНИЯ ДАННЫХ НА БАЗЕ КОРРЕКТИРУЮЩИХ КОДОВ
Акберов Р.В. ЭЛЕКТРОННОЕ УЧЕБНОЕ ПОСОБИЕ «ЭКСПЛУАТАЦИЯ И ДИАГНОСТИКА ЖЕСТКОГО ДИСКА»
 
Последнее редактирование:

Сергей Попов

Кодебай
30.12.2015
4 702
6 609
BIT
448
Для таких балдежных статей надо отделный раздел создать
Разделы создаются под большое количество контента. Мы создали несколько разделов по просьбе участников форума. Эти разделы практически пусты и не пополняются. Так что говорить о целом разделе для одной-двух статей рановато.
 
  • Нравится
Реакции: billy_605
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!