Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 16.4. Несколько других подробностей

Оглавление
Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

16.4. Несколько других подробностей

hardorsoft 26.10.10 в 00:42

0

Этот подраздел содержит дополнительную информацию об уровне
блочных устройств, которая может быть интересна тем, кто хочет достичь
более глубокого понимания. Можно написать корректный драйвер и без
нижеследующих возможностей, но, в некоторых ситуациях, они могут
быть полезны.

hardorsoft 26.10.10 в 00:42

0

16.4.1. Предварительная подготовка команд

hardorsoft 26.10.10 в 00:43

0

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

hardorsoft 26.10.10 в 00:43

0

Если вы хотите использовать это свойство, создайте функцию
предварительной подготовки, в соответствии со следующим прототипом:
typedef int (prep_rq_fn) (request_queue_t *queue, struct request *req);

hardorsoft 26.10.10 в 00:43

0

Структура request содержит поле cmd, которое является массивом
из BLK_MAX_CDB байт. Этот массив может быть использован функцией
предварительной подготовки для хранения аппаратных команд или любой
другой информации. Эта функция возвращает одно из следующих
значений:

hardorsoft 26.10.10 в 00:44

0

BLKPREP_OK
Подготовка прошла успешно, и запрос может быть обработан
функцией request вашего драйвера.

hardorsoft 26.10.10 в 00:44

0

BLKPREP_KILL
Запрос не может быть выполнен. Сопровождается кодом ошибки.

hardorsoft 26.10.10 в 00:44

0

BLKPREP_DEFER
Запрос не может быть выполнен в настоящее время. Он остается в
начале очереди, но не обрабатывается функцией request.

hardorsoft 26.10.10 в 00:44

0

Функция предварительной подготовки вызывается из
elv_next_request непосредственно перед возвратом из нее в ваш драйвер.
Если возвращается значение BLKPREP_DEFER, то elv_next_request вернет
NULL. Данный режим может быть использован, например, тогда, когда
количество выполняемых запросов в вашем устройстве достигло
максимального значения.

hardorsoft 26.10.10 в 00:45

0

Чтобы уровень блочных устройств мог вызывать вашу функцию,
передайте ее в:

hardorsoft 26.10.10 в 00:45

0

void blk_queue_prep_rq(request_queue_t *queue, prep_rq_fn *func);

hardorsoft 26.10.10 в 00:45

0

По умолчанию очередь запросов не имеет функции предварительной
подготовки.
16.4.2. Пометка команд очереди

hardorsoft 26.10.10 в 00:46

0

Аппаратное обеспечение, которое может обслуживать сразу
несколько запросов, обычно поддерживает пометку команд очереди (TCQ
– tagged command queueing). TCQ – простая технология, прикрепляющая
целочисленную метку (tag) к каждому запросу, что позволяет устройству
сообщить драйверу о выполнении одного из запросов. В предыдущих
версиях ядра, драйвера реализующие TCQ, выполняли всю работу
самостоятельно. В ядре 2.6, в уровень блочных устройств добавлена
инфраструктура поддержки TCQ.

hardorsoft 26.10.10 в 00:46

0

Если ваш драйвер использует TCQ, вы должны проинформировать об
этом ядро во время инициализации с помощью вызова:

hardorsoft 26.10.10 в 00:46

0

int blk_queue_init_tags(request_queue_t *queue, int depth, struct
blk_queue_tag *tags);
Параметр queue – это ваша очередь запросов, depth – количество
помечаемых запросов, которое ваше устройство может обработать. Параметр tags – опциональный указатель на массив структур
blk_queue_tag, состоящий из depth элементов. Обычно параметр tags
равен NULL, в этом случае функция blk_queue_init_tags создает массив.
Однако, если вам необходимо, чтобы массив tags был общим у нескольких
устройств, вы можете передать в tags указатель из другой очереди
запросов, хранящийся в поле queue_tags. Вы не должны самостоятельно
выделять массив tags. Уровень блочных устройств должен сам
инициализировать массив, и он не экспортирует функцию инициализации
в модули.

hardorsoft 26.10.10 в 00:47

0

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

hardorsoft 26.10.10 в 00:47

0

При изменении размера массива меток tags, необходимо
проинформировать об этом ядро с помощью функции:

hardorsoft 26.10.10 в 00:47

0

int blk_queue_resize_tags(request_queue_t *queue, int new_depth);

hardorsoft 26.10.10 в 00:47

0

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

hardorsoft 26.10.10 в 00:48

0

Массив меток ассоциируется со структурой request, вызовом
функции blk_queue_start_tag. При вызове этой функции блокировка
очереди так же должена быть захвачена.

hardorsoft 26.10.10 в 00:48

0

int blk_queue_start_tag(request_queue_t *queue, struct request *req);

hardorsoft 26.10.10 в 00:48

0

Если имеется доступная метка, эта функция использует ее для
запроса, сохраняя ее значение в req->tag и возвращает «0». Так же
функция выводит запрос из очереди и связывает его со структурой
хранения меток. Таким образом, вашему драйверу не требуется убирать
запросы из очереди, если он использует TCQ. В случае, когда нет больше
свободных меток, функция blk_queue_start_tag оставляет запрос в
очереди и возвращает не нулевое значение.

hardorsoft 26.10.10 в 00:48

0

Когда данные запроса полностью переданы, ваш драйвер должен
освободить метку. Для этого используется команда:

hardorsoft 26.10.10 в 00:48

0

void blk_queue_end_tag(request_queue_t *queue, struct request *req);

hardorsoft 26.10.10 в 00:49

0

Перед этим вызовом вы снова должны захватить блокировку
очереди. Функция должна вызываться только после того, как вызов
blk_queue_start_tag вернул нулевое значение, и до вызова
end_that_request_last. И помните, что запрос уже выведен из очереди.

hardorsoft 26.10.10 в 00:49

0

Если требуется найти запрос ассоциированный с меткой (например
когда драйвер сообщает о выполнении) используйте функцию:

hardorsoft 26.10.10 в 00:49

0

struct request *blk_queue_find_tag(request_queue_t *qeue, int tag);

hardorsoft 26.10.10 в 00:49

0

Возвращаемое значение является ассоциированной структурой
request, если все работает правильно.

hardorsoft 26.10.10 в 00:49

0

Если действительно произошел какой-то сбой, ваш драйвер может
произвести сброс, или какое-либо еще действие над устройством. В этом
случае оставшиеся команды не будут выполнены. Предоставляется функция, которая может помочь в исправлении этой ситуации:

hardorsoft 26.10.10 в 00:50

0

void blk_queue_invalidate_tags(request_queue_t *queue);

hardorsoft 26.10.10 в 00:50

0

Эта функция возвращает все ожидающие исполнения запросы
обратно в очередь. При выполнении этого вызова, блокировка очереди
должна быть захвачена.

hardorsoft 26.10.10 в 00:50

0
Минутку...