Главная страница  Межпроцессное взаимодействие (состязание) 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 [ 76 ] 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

к передаче параметров контроллеру, выполняет повторную калибровку устройства (для старых моделей), передавая команду поиска нулевого цилиндра.

Теперь мы готовы обсудить функции, вызываемые при обработке запроса на передачу данных. Сначала вызывается уже рассмотренная нами функция w prepare. Здесь важно то, что она инициализирует нулем значение переменной w count. Далее при передаче данных вызывается функция w schedule, принимающая три параметра: откуда брать данные, куда их поместить и какое количество байтов передавать. Количество байтов должно быть кратно размеру сектора, что проверяется в коде функции. Бит необязательного выполнения, который может присутствовать в запросе SCATTEREDJO, сбрасывается при передаче кода операции контроллеру, но заметьте, что он сохраняется в поле io request структуры iorequest s. Жесткий диск будет пытаться выполнять все запросы, но, как мы увидим далее, драйвер вправе отказаться от некоторых из них, если произошли ошибки. Затем производится контроль выхода последнего байта запроса за пределы устройства, и при необходимости уменьшается запрошенное количество байтов. К этому моменту вычисляется первый сектор, который будет запрошен.

Начиная отсюда, процесс планирования приобретает серьезный характер. Если уже имеются текущие запросы (для этого проверяется, равно ли значение переменной w count нулю) и если новый запрошенный сектор не следует за последним сектором в очереди, вызывается функция w finish, которая выполняет отложенные запросы. В противном случае в переменную w nextblock, хранящую номер следующего сектора в цепочке, записывается свежее значение, и новый запрошенный сектор добавляется в очередь. Когда достигается максимально допустимое количество запросов, определяемое переменной max count, опять же вызывается w finish. Как мы увидим, хранить предельное значение в переменной удобно тем, что его несложно потом подстроить.

Итак, в функции w prepare есть два места, где делается вызов w finish. Обычно w prepare завершается, не обращаясь к w finish, но этот вызов так или иначе производится из главного цикла в файле driver.c. Таким образом, вызов может произойти повторно, что грозит ошибкой. Чтобы этого не случилось, в коде w finish прежде всего проверяется, не был ли вызов повторным. Если в массиве все еще есть запросы, управление переходит в основную часть кода w fin1sh.

Так как ожидаемо получение значительного количества запросов, главная часть w finish представляет собой цикл. Перед входом в цикл в переменную г помещается значение, сигнализирующее об ошибке, с целью принудительно провести повторную инициализацию контроллера. Структура command используется для передачи всех требуемых параметров в функцию, которая занимается действительным взаимодействием с контроллером диска. Параметр cmd.precomp необходим для некоторых дисков, чтобы компенсировать различие в производительности магнитного носителя и скорости, с которой поверхность диска проходит под магнитными головками, когда они перемещаются от внешних цилиндров к внутренним. Этот параметр для одного диска всегда принимает одно и то же значение, а многие диски его просто игнорируют. Параметр cmd.count хранит количество передаваемых секторов, усеченное до одного байта, так как именно такова разрядность всех командных регистров и регистров состояния контроллера. По-



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

Наконец, загружается сама команда (чтение или запись) и, чтобы инициировать обмен данными, вызывается подпрограмма com out. Этот вызов может потерпеть неудачу, если контроллер не готов принимать команды или не придет в готовность за заданное время ожидания. В таком случае увеличивается значение счетчика ошибок и, если оно достигнет значения MAX ERRORS, операция прерывается. Иначе оператор языка С continue вызывает переход на начало цикла, то есть начинает повторную попытку.

После того как контроллер принял переданную в подпрограмму com out команду, требуется ждать некоторое время до тех пор, пока данные не будут готовы. Поэтому (если команда была DEV READ) вызывается функция w intr wait. Подробнее мы рассмотрим ее позже, а сейчас скажем лишь, что она вызывает receive, соответственно, в данной точке задача жесткого диска приостанавливается. Некоторое время спустя (задержка зависит от того, пришлось ли диску делать поиск цилиндра) подпрограмма w intr read завершается.

Данный драйвер не использует DMA, хотя многие контроллеры поддерживают такую возможность. Вместо этого драйвер применяет программный ввод/вывод. Если функция ожидания w intr wait не сообщила об ошибке, ассемблерная подпрограмма port transfer считывает SECTOR SIZE байтов из порта данных контроллера в буфер назначения, который должен находиться в кэше блоков файловой системы. Затем изменяются значения различных указателей и счетчиков, что регистрирует успешную передачу данных. Наконец, если количество байтов в текущем запросе подошло к О, указатель на текущий запрос перемещается на следующую запись в массиве запросов.

В том случае, когда обрабатывается команда DEV READ, первая часть кода, устанавливающая параметры команды и передающая ее в контроллер, выглядит точно так же, отличаясь лишь кодом операции. Но последующие действия в случае чтения другие. Прежде всего, ожидается, когда контроллер подаст сигнал о своей готовности принимать данные. Команда waitfor представляет собой макроопределение и обычно выполняется очень быстро. Подробнее мы расскажем о ней позже, сейчас скажем только, что waitfor в конечном итоге завершится, но долгие задержки должны быть исключительно редкими. Затем при помощи процедуры port write данные записываются в порт данных контроллера, после чего делается вызов wjntr wait и задача жесткого диска приостанавливается. Через какое-то время, когда произойдет прерывание и задача проснется , производятся некоторые результирующие подсчеты.

Наконец, нужно разобраться с ошибками чтения или записи, которые могли произойти. Если контроллер уведомил драйвер, что причина ошибки в сбойном секторе, повторять то же самое смысла нет. Но для других типов ошибок стоит сделать некоторое количество повторов. Это количество определяется путем подсчета ошибок до достижения счетчиком значения MAX ERRORS. Когда дости-



гается значение MAX ERR0RS/2, вызывается функция w need reset, принудительно инициализирующая контроллер перед следующей попыткой. Но, если запрос был необязательным (такие запросы имеют место при SCATTERED IO), повторных попыток не делается.

Когда w finish завершается, успешно или с ошибкой, в переменную w command всегда помещается значение CMD IDLE. Это позволяет другим функциям определить, что причиной ошибки является не механическое или электрическое повреждение диска, вызывающее прерывание при попытке выполнить операцию.

Контроллер диска управляется посредством набора регистров, которые на некоторых системах отображаются в память, но на IBM PC-совместимых системах находятся в отдельном адресном пространстве портов ввода/вывода. Список регистров, используемых стандартным АТ-совместимым контроллером, приведен в табл. 3.6. Структура регистра № 6 расписана в табл. 3.7, где буквенные обозначения раскрываются так:

♦ LBA - для режима адресации цилиндр/головка/сектор (CHS) - 0. Для режима логической адресации блоков (LBA) - 1;

f D - для главного диска (master) - 0. Для подчиненного диска (slave) - 1;

♦ HSn - для режима CHS: выбор головки. Для режима LBA: 24-27 биты выбора блока.

Таблица 3.6. Регистры управления ЮЕ-контроллером жесткого диска. Номера в скобках означают биты логического адреса блока, соответствующие каждому регистру в режиме LBA

Регистр

Чтение

Запись

Данные

Данные

Ошибка

Предкомпенсация записи

Количество секторов

Количество секторов

Номер сектора (0-7)

Номер сектора (0-7)

Цилиндр (младш.) (8-15)

Цилиндр (младш.) (8-15)

Цилиндр (старш.) (16-23)

Цилиндр (старш.) (16-23)

Выбор привода/головки (24-27)

Выбор привода/головки (24-27)

Состояние

Команда

Таблица 3.7. Поля регистра Выбор привода/головки (пояснения в тексте)

6 5 4 3

2 1 0

LBA 1 D HS3

HS2 HS1 HSO

Это наша первая встреча с аппаратным обеспечением ввода/вывода и полезно напомнить, что порты ввода/вывода могут вести себя совершенно иначе, чем адреса памяти. Вообще говоря, входные и выходные регистры, которым соответствует один и тот же порт ввода/вывода, не обязательно совпадают. Таким образом, данные, записанные в некоторый порт, нельзя считать из него последующей операцией чтения. Например, последний регистр в табл. 3.6 показывает состоя-



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 [ 76 ] 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

© 2000 - 2018 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.