# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR The FreeBSD Project # This file is distributed under the same license as the FreeBSD Documentation package. # Vladlen Popolitov , 2025, 2026. msgid "" msgstr "" "Project-Id-Version: FreeBSD Documentation VERSION\n" "POT-Creation-Date: 2025-05-01 19:56-0300\n" "PO-Revision-Date: 2026-03-04 20:01+0000\n" "Last-Translator: Vladlen Popolitov \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 4.17\n" #. type: Title = #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:14 #, no-wrap msgid "Common Access Method SCSI Controllers" msgstr "Контроллеры SCSI с общим методом доступа (CAM)" #. type: YAML Front Matter: title #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1 #, no-wrap msgid "Chapter 12. Common Access Method SCSI Controllers" msgstr "Глава 12. Контроллеры SCSI с общим методом доступа (CAM)" #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:52 #, no-wrap msgid "Synopsis" msgstr "Обзор" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:56 msgid "" "This document assumes that the reader has a general understanding of device " "drivers in FreeBSD and of the SCSI protocol. Much of the information in " "this document was extracted from the drivers:" msgstr "" "Этот документ предполагает, что читатель имеет общее представление о " "драйверах устройств в FreeBSD и о протоколе SCSI. Большая часть информации в " "этом документе была извлечена из драйверов:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:58 msgid "" "ncr ([.filename]#/sys/pci/ncr.c#) by Wolfgang Stanglmeier and Stefan Esser" msgstr "" "ncr ([.filename]#/sys/pci/ncr.c#) от Wolfgang Stanglmeier и Stefan Esser" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:59 msgid "sym ([.filename]#/sys/dev/sym/sym_hipd.c#) by Gerard Roudier" msgstr "sym ([.filename]#/sys/dev/sym/sym_hipd.c#) от Gerard Roudier" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:60 msgid "aic7xxx ([.filename]#/sys/dev/aic7xxx/aic7xxx.c#) by Justin T. Gibbs" msgstr "aic7xxx ([.filename]#/sys/dev/aic7xxx/aic7xxx.c#) от Justin T. Gibbs" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:63 msgid "" "and from the CAM code itself (by Justin T. Gibbs, see [.filename]#/sys/cam/" "*#). When some solution looked the most logical and was essentially " "verbatim extracted from the code by Justin T. Gibbs, I marked it as " "\"recommended\"." msgstr "" "и из самого кода CAM (автор Justin T. Gibbs, см. [.filename]#/sys/cam/*#). " "Когда какое-то решение выглядело наиболее логичным и было практически " "дословно взято из кода Justin T. Gibbs, я отмечал его как \"рекомендуемое\"." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:71 msgid "" "The document is illustrated with examples in pseudo-code. Although " "sometimes the examples have many details and look like real code, it is " "still pseudo-code. It was written to demonstrate the concepts in an " "understandable way. For a real driver other approaches may be more modular " "and efficient. It also abstracts from the hardware details, as well as " "issues that would cloud the demonstrated concepts or that are supposed to be " "described in the other chapters of the developers handbook. Such details " "are commonly shown as calls to functions with descriptive names, comments or " "pseudo-statements. Fortunately real life full-size examples with all the " "details can be found in the real drivers." msgstr "" "Документ иллюстрирован примерами на псевдокоде. Хотя иногда примеры содержат " "много деталей и выглядят как настоящий код, это всё ещё псевдокод. Он был " "написан, чтобы продемонстрировать концепции в понятной форме. Для реального " "драйвера могут быть более модульные и эффективные подходы. Также он " "абстрагируется от деталей оборудования, а также от вопросов, которые могли " "бы затмить демонстрируемые концепции или которые предполагается описать в " "других главах руководства разработчика. Такие детали обычно показаны в виде " "вызовов функций с описательными именами, комментариев или псевдооператоров. " "К счастью, полные примеры из реальной жизни со всеми деталями можно найти в " "реальных драйверах." #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:73 #, no-wrap msgid "General Architecture" msgstr "Общая архитектура" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:79 msgid "" "CAM stands for Common Access Method. It is a generic way to address the I/O " "buses in a SCSI-like way. This allows a separation of the generic device " "drivers from the drivers controlling the I/O bus: for example the disk " "driver becomes able to control disks on both SCSI, IDE, and/or any other bus " "so the disk driver portion does not have to be rewritten (or copied and " "modified) for every new I/O bus. Thus the two most important active " "entities are:" msgstr "" "CAM означает Common Access Method (Общий Метод Доступа). Это универсальный " "способ адресации шин ввода-вывода в стиле SCSI. Это позволяет отделить общие " "драйверы устройств от драйверов, управляющих шиной ввода-вывода: например, " "драйвер диска получает возможность управлять дисками как на SCSI, IDE, так и " "на любой другой шине, так что часть драйвера диска не нужно переписывать (" "или копировать и изменять) для каждой новой шины ввода-вывода. Таким " "образом, двумя наиболее важными активными сущностями являются:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:81 msgid "" "_Peripheral Modules_ - a driver for peripheral devices (disk, tape, CD-ROM, " "etc.)" msgstr "" "_Модули периферийных устройств_ - драйвер для периферийных устройств (диски, " "ленты, CD-ROM и т.д.)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:82 msgid "" "_SCSI Interface Modules_ (SIM) - a Host Bus Adapter drivers for connecting " "to an I/O bus such as SCSI or IDE." msgstr "" "_Модули интерфейса SCSI_ (SIM) - драйверы адаптеров шины для подключения к " "шине ввода-вывода, такой как SCSI или IDE." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:85 msgid "" "A peripheral driver receives requests from the OS, converts them to a " "sequence of SCSI commands and passes these SCSI commands to a SCSI Interface " "Module. The SCSI Interface Module is responsible for passing these commands " "to the actual hardware (or if the actual hardware is not SCSI but, for " "example, IDE then also converting the SCSI commands to the native commands " "of the hardware)." msgstr "" "Периферийный драйвер получает запросы от ОС, преобразует их в " "последовательность команд SCSI и передаёт эти команды SCSI модулю интерфейса " "SCSI. Модуль интерфейса SCSI отвечает за передачу этих команд реальному " "оборудованию (или, если оборудование не поддерживает SCSI, а использует, " "например, IDE, также преобразует команды SCSI в собственные команды " "оборудования)." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:87 msgid "" "As we are interested in writing a SCSI adapter driver here, from this point " "on we will consider everything from the SIM standpoint." msgstr "" "Так как мы заинтересованы в написании драйвера адаптера SCSI, с этого " "момента мы будем рассматривать всё с точки зрения модуля SCSI-интерфейса " "(SIM)." #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:88 #, no-wrap msgid "Globals and Boilerplate" msgstr "Глобальные переменные и Шаблонный код" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:91 msgid "" "A typical SIM driver needs to include the following CAM-related header files:" msgstr "" "Типичный драйвер SIM должен включать следующие заголовочные файлы, связанные " "с CAM:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:100 #, no-wrap msgid "" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" msgstr "" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:102 #, no-wrap msgid "Device configuration: xxx_attach" msgstr "Конфигурация устройства: xxx_attach" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:107 msgid "" "The first thing each SIM driver must do is register itself with the CAM " "subsystem. This is done during the driver's `xxx_attach()` function (here " "and further xxx_ is used to denote the unique driver name prefix). The " "`xxx_attach()` function itself is called by the system bus auto-" "configuration code which we do not describe here." msgstr "" "Первое, что должен сделать каждый драйвер SIM, — это зарегистрироваться в " "подсистеме CAM. Это выполняется в функции `xxx_attach()` драйвера (здесь и " "далее xxx_ используется для обозначения уникального префикса имени драйвера)" ". Сама функция `xxx_attach()` вызывается кодом автонастройки системной шины, " "который мы здесь не описываем." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:109 msgid "" "This is achieved in multiple steps: first it is necessary to allocate the " "queue of requests associated with this SIM:" msgstr "" "Это достигается в несколько этапов: сначала необходимо выделить очередь " "запросов, связанных с этой SIM:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:113 #, no-wrap msgid " struct cam_devq *devq;\n" msgstr " struct cam_devq *devq;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:117 #, no-wrap msgid "" " if ((devq = cam_simq_alloc(SIZE)) == NULL) {\n" " error; /* some code to handle the error */\n" " }\n" msgstr "" " if ((devq = cam_simq_alloc(SIZE)) == NULL) {\n" " error; /* some code to handle the error */\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:122 msgid "" "Here `SIZE` is the size of the queue to be allocated, maximal number of " "requests it could contain. It is the number of requests that the SIM driver " "can handle in parallel on one SCSI card. Commonly it can be calculated as:" msgstr "" "Вот `SIZE` — это размер выделяемой очереди, максимальное количество " "запросов, которые она может содержать. Это количество запросов, которые " "драйвер SIM может обрабатывать параллельно на одной SCSI-карте. Обычно его " "можно вычислить как:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:126 #, no-wrap msgid "SIZE = NUMBER_OF_SUPPORTED_TARGETS * MAX_SIMULTANEOUS_COMMANDS_PER_TARGET\n" msgstr "" "SIZE = NUMBER_OF_SUPPORTED_TARGETS * MAX_SIMULTANEOUS_COMMANDS_PER_TARGET\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:129 msgid "Next we create a descriptor of our SIM:" msgstr "Далее мы создаем описание нашего SIM:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:133 #, no-wrap msgid " struct cam_sim *sim;\n" msgstr " struct cam_sim *sim;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:140 #, no-wrap msgid "" " if ((sim = cam_sim_alloc(action_func, poll_func, driver_name,\n" " softc, unit, mtx, max_dev_transactions,\n" " max_tagged_dev_transactions, devq)) == NULL) {\n" " cam_simq_free(devq);\n" " error; /* some code to handle the error */\n" " }\n" msgstr "" " if ((sim = cam_sim_alloc(action_func, poll_func, driver_name,\n" " softc, unit, mtx, max_dev_transactions,\n" " max_tagged_dev_transactions, devq)) == NULL) {\n" " cam_simq_free(devq);\n" " error; /* some code to handle the error */\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:143 msgid "" "Note that if we are not able to create a SIM descriptor we free the `devq` " "also because we can do nothing else with it and we want to conserve memory." msgstr "" "Обратите внимание, что если мы не сможем создать дескриптор SIM, мы также " "освобождаем `devq`, потому что больше ничего не можем с ним сделать и хотим " "сэкономить память." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:145 msgid "" "If a SCSI card has multiple SCSI buses on it then each bus requires its own " "`cam_sim` structure." msgstr "" "Если SCSI-карта имеет несколько шин SCSI, то каждой шине требуется " "собственная структура `cam_sim`." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:148 msgid "" "An interesting question is what to do if a SCSI card has more than one SCSI " "bus, do we need one `devq` structure per card or per SCSI bus? The answer " "given in the comments to the CAM code is: either way, as the driver's author " "prefers." msgstr "" "Интересный вопрос: что делать, если SCSI-карта имеет более одной SCSI-шины, " "нужна ли одна структура `devq` на карту или на SCSI-шину? Ответ, приведённый " "в комментариях к коду CAM, таков: как угодно, на усмотрение автора драйвера." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:150 msgid "The arguments are:" msgstr "Аргументы:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:152 msgid "`action_func` - pointer to the driver's `xxx_action` function." msgstr "`action_func` - указатель на функцию `xxx_action` драйвера." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:156 #, no-wrap msgid "static void xxx_action(struct cam_sim *, union ccb *);\n" msgstr "static void xxx_action(struct cam_sim *, union ccb *);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:158 msgid "`poll_func` - pointer to the driver's `xxx_poll()`" msgstr "`poll_func` - указатель на функцию `xxx_poll()` драйвера" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:162 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1020 #, no-wrap msgid "static void xxx_poll(struct cam_sim *);\n" msgstr "static void xxx_poll(struct cam_sim *);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:164 msgid "" "driver_name - the name of the actual driver, such as \"ncr\" or \"wds\"." msgstr "`driver_name` — имя фактического драйвера, например `ncr` или `wds`." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:166 msgid "" "`softc` - pointer to the driver's internal descriptor for this SCSI card. " "This pointer will be used by the driver in future to get private data." msgstr "" "`softc` — указатель на внутренний дескриптор драйвера для данной SCSI-карты. " "Этот указатель будет использоваться драйвером в дальнейшем для получения " "приватных данных." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:167 msgid "" "unit - the controller unit number, for example for controller \"mps0\" this " "number will be 0" msgstr "" "unit - номер управляющего устройства, например, для контроллера \"mps0\" это " "число будет 0" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:171 msgid "" "mtx - Lock associated with this SIM. For SIMs that don't know about " "locking, pass in Giant. For SIMs that do, pass in the lock used to guard " "this SIM's data structures. This lock will be held when xxx_action and " "xxx_poll are called." msgstr "" "mtx - Блокировка, связанная с данной SIM. Для SIM, которые не поддерживают " "блокировку, передаётся Giant. Для SIM, которые поддерживают, передаётся " "блокировка, используемая для защиты структур данных этой SIM. Эта блокировка " "будет удерживаться при вызовах xxx_action и xxx_poll." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:174 msgid "" "max_dev_transactions - maximal number of simultaneous transactions per SCSI " "target in the non-tagged mode. This value will be almost universally equal " "to 1, with possible exceptions only for the non-SCSI cards. Also the " "drivers that hope to take advantage by preparing one transaction while " "another one is executed may set it to 2 but this does not seem to be worth " "the complexity." msgstr "" "max_dev_transactions - максимальное количество одновременных транзакций на " "целевом SCSI-устройстве в режиме без тегов. Это значение почти всегда равно " "1, за исключением возможных исключений только для не-SCSI карт. Также " "драйверы, которые надеются получить преимущество, подготавливая одну " "транзакцию во время выполнения другой, могут установить его в 2, но это не " "кажется оправданным из-за сложности." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:179 msgid "" "max_tagged_dev_transactions - the same thing, but in the tagged mode. Tags " "are the SCSI way to initiate multiple transactions on a device: each " "transaction is assigned a unique tag and the transaction is sent to the " "device. When the device completes some transaction it sends back the result " "together with the tag so that the SCSI adapter (and the driver) can tell " "which transaction was completed. This argument is also known as the maximal " "tag depth. It depends on the abilities of the SCSI adapter." msgstr "" "max_tagged_dev_transactions - то же самое, но в режиме с тегами. Теги — это " "способ в SCSI инициировать несколько транзакций на устройстве: каждая " "транзакция получает уникальный тег и отправляется на устройство. Когда " "устройство завершает транзакцию, оно возвращает результат вместе с тегом, " "чтобы SCSI-адаптер (и драйвер) могли определить, какая транзакция была " "завершена. Этот аргумент также известен как максимальная глубина тега. Он " "зависит от возможностей SCSI-адаптера." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:181 msgid "Finally we register the SCSI buses associated with our SCSI adapter:" msgstr "Наконец, мы регистрируем шины SCSI, связанные с нашим SCSI-адаптером:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:188 #, no-wrap msgid "" " if (xpt_bus_register(sim, softc, bus_number) != CAM_SUCCESS) {\n" " cam_sim_free(sim, /*free_devq*/ TRUE);\n" " error; /* some code to handle the error */\n" " }\n" msgstr "" " if (xpt_bus_register(sim, softc, bus_number) != CAM_SUCCESS) {\n" " cam_sim_free(sim, /*free_devq*/ TRUE);\n" " error; /* some code to handle the error */\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:192 msgid "" "If there is one `devq` structure per SCSI bus (i.e., we consider a card with " "multiple buses as multiple cards with one bus each) then the bus number will " "always be 0, otherwise each bus on the SCSI card should be get a distinct " "number. Each bus needs its own separate structure cam_sim." msgstr "" "Если существует одна структура `devq` на каждую шину SCSI (т.е. мы " "рассматриваем карту с несколькими шинами как несколько карт с одной шиной " "каждая), то номер шины всегда будет 0, в противном случае каждая шина на " "SCSI-карте должна получить уникальный номер. Каждой шине требуется своя " "отдельная структура `cam_sim`." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:195 msgid "" "After that our controller is completely hooked to the CAM system. The value " "of `devq` can be discarded now: sim will be passed as an argument in all " "further calls from CAM and devq can be derived from it." msgstr "" "После этого наш контроллер полностью подключён к системе CAM. Значение `devq`" " теперь можно отбросить: sim будет передаваться в качестве аргумента во всех " "последующих вызовах из CAM, а devq можно получить из него." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:199 msgid "" "CAM provides the framework for such asynchronous events. Some events " "originate from the lower levels (the SIM drivers), some events originate " "from the peripheral drivers, some events originate from the CAM subsystem " "itself. Any driver can register callbacks for some types of the " "asynchronous events, so that it would be notified if these events occur." msgstr "" "CAM предоставляет инфраструктуру для подобных асинхронных событий. Некоторые " "события возникают на нижних уровнях (драйверы SIM), некоторые — в драйверах " "периферийных устройств, а некоторые — в самой подсистеме CAM. Любой драйвер " "может зарегистрировать обработчики для определённых типов асинхронных " "событий, чтобы получать уведомления при их возникновении." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:207 msgid "" "A typical example of such an event is a device reset. Each transaction and " "event identifies the devices to which it applies by the means of \"path\". " "The target-specific events normally occur during a transaction with this " "device. So the path from that transaction may be re-used to report this " "event (this is safe because the event path is copied in the event reporting " "routine but not deallocated nor passed anywhere further). Also it is safe " "to allocate paths dynamically at any time including the interrupt routines, " "although that incurs certain overhead, and a possible problem with this " "approach is that there may be no free memory at that time. For a bus reset " "event we need to define a wildcard path including all devices on the bus. " "So we can create the path for the future bus reset events in advance and " "avoid problems with the future memory shortage:" msgstr "" "Типичным примером такого события является сброс устройства. Каждая " "транзакция и событие идентифицируют устройства, к которым они применяются, с " "помощью \"пути\". Специфичные для целевого устройства события обычно " "происходят во время транзакции с этим устройством. Таким образом, путь из " "этой транзакции может быть повторно использован для сообщения о данном " "событии (это безопасно, потому что путь события копируется в процедуре " "сообщения о событии, но не освобождается и не передаётся дальше). Также " "безопасно динамически выделять пути в любое время, включая процедуры " "обработки прерываний, хотя это влечёт определённые накладные расходы, и " "возможная проблема такого подхода заключается в том, что в этот момент может " "не быть свободной памяти. Для события сброса шины нам необходимо определить " "путь-шаблон, включающий все устройства на шине. Поэтому мы можем заранее " "создать путь для будущих событий сброса шины и избежать проблем с возможной " "нехваткой памяти в будущем:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:211 #, no-wrap msgid " struct cam_path *path;\n" msgstr " struct cam_path *path;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:219 #, no-wrap msgid "" " if (xpt_create_path(&path, /*periph*/NULL,\n" " cam_sim_path(sim), CAM_TARGET_WILDCARD,\n" " CAM_LUN_WILDCARD) != CAM_REQ_CMP) {\n" " xpt_bus_deregister(cam_sim_path(sim));\n" " cam_sim_free(sim, /*free_devq*/TRUE);\n" " error; /* some code to handle the error */\n" " }\n" msgstr "" " if (xpt_create_path(&path, /*periph*/NULL,\n" " cam_sim_path(sim), CAM_TARGET_WILDCARD,\n" " CAM_LUN_WILDCARD) != CAM_REQ_CMP) {\n" " xpt_bus_deregister(cam_sim_path(sim));\n" " cam_sim_free(sim, /*free_devq*/TRUE);\n" " error; /* some code to handle the error */\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:222 #, no-wrap msgid "" " softc->wpath = path;\n" " softc->sim = sim;\n" msgstr "" " softc->wpath = path;\n" " softc->sim = sim;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:225 msgid "As you can see the path includes:" msgstr "Как вы можете видеть, путь включает:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:227 msgid "ID of the peripheral driver (NULL here because we have none)" msgstr "" "Идентификатор драйвера периферийного устройства (NULL здесь, так как у нас " "его нет)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:228 msgid "ID of the SIM driver (`cam_sim_path(sim)`)" msgstr "Идентификатор драйвера SIM (`cam_sim_path(sim)`)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:229 msgid "" "SCSI target number of the device (CAM_TARGET_WILDCARD means \"all devices\")" msgstr "" "Номер целевого устройства SCSI (CAM_TARGET_WILDCARD означает \"все " "устройства\")" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:230 msgid "SCSI LUN number of the subdevice (CAM_LUN_WILDCARD means \"all LUNs\")" msgstr "Номер SCSI LUN подустройства (CAM_LUN_WILDCARD означает \"все LUN\")" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:232 msgid "" "If the driver can not allocate this path it will not be able to work " "normally, so in that case we dismantle that SCSI bus." msgstr "" "Если драйвер не может выделить этот путь, он не сможет нормально работать, " "поэтому в таком случае мы демонтируем эту шину SCSI." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:235 msgid "" "And we save the path pointer in the `softc` structure for future use. After " "that we save the value of sim (or we can also discard it on the exit from " "`xxx_probe()` if we wish)." msgstr "" "И мы сохраняем указатель пути в структуре `softc` для дальнейшего " "использования. После этого сохраняем значение sim (или можем также отбросить " "его при выходе из `xxx_probe()`, если захотим)." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:238 msgid "" "That is all for a minimalistic initialization. To do things right there is " "one more issue left." msgstr "" "Вот и всё для минималистичной инициализации. Чтобы сделать всё правильно, " "остался ещё один вопрос." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:243 msgid "" "For a SIM driver there is one particularly interesting event: when a target " "device is considered lost. In this case resetting the SCSI negotiations " "with this device may be a good idea. So we register a callback for this " "event with CAM. The request is passed to CAM by requesting CAM action on a " "CAM control block for this type of request:" msgstr "" "Для драйвера SIM есть одно особенно важное событие: когда целевое устройство " "считается потерянным. В этом случае может быть хорошей идеей сбросить SCSI-" "переговоры с этим устройством. Поэтому мы регистрируем обратный вызов для " "этого события в CAM. Запрос передаётся в CAM путём запроса действия CAM в " "блоке управления CAM для этого типа запроса:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:247 #, no-wrap msgid " struct ccb_setasync csa;\n" msgstr " struct ccb_setasync csa;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:254 #, no-wrap msgid "" " xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);\n" " csa.ccb_h.func_code = XPT_SASYNC_CB;\n" " csa.event_enable = AC_LOST_DEVICE;\n" " csa.callback = xxx_async;\n" " csa.callback_arg = sim;\n" " xpt_action((union ccb *)&csa);\n" msgstr "" " xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);\n" " csa.ccb_h.func_code = XPT_SASYNC_CB;\n" " csa.event_enable = AC_LOST_DEVICE;\n" " csa.callback = xxx_async;\n" " csa.callback_arg = sim;\n" " xpt_action((union ccb *)&csa);\n" #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:256 #, no-wrap msgid "Processing CAM messages: xxx_action" msgstr "Обработка сообщений CAM: xxx_action" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:261 #, no-wrap msgid "static void xxx_action(struct cam_sim *sim, union ccb *ccb);\n" msgstr "static void xxx_action(struct cam_sim *sim, union ccb *ccb);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:268 msgid "" "Do some action on request of the CAM subsystem. Sim describes the SIM for " "the request, CCB is the request itself. CCB stands for \"CAM Control " "Block\". It is a union of many specific instances, each describing " "arguments for some type of transactions. All of these instances share the " "CCB header where the common part of arguments is stored." msgstr "" "Выполнить некоторое действие по запросу подсистемы CAM. Sim описывает SIM " "для запроса, CCB — это сам запрос. CCB расшифровывается как \"CAM Control " "Block\" (блок управления CAM). Это объединение множества конкретных " "экземпляров, каждый из которых описывает аргументы для определённого типа " "транзакций. Все эти экземпляры имеют общий заголовок CCB, в котором " "хранится общая часть аргументов." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:271 msgid "" "CAM supports the SCSI controllers working in both initiator (\"normal\") " "mode and target (simulating a SCSI device) mode. Here we only consider the " "part relevant to the initiator mode." msgstr "" "CAM поддерживает SCSI-контроллеры, работающие как в режиме инициатора " "(«обычном»), так и в режиме цели (эмулирующем SCSI-устройство). Здесь мы " "рассматриваем только часть, относящуюся к режиму инициатора." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:273 msgid "" "There are a few function and macros (in other words, methods) defined to " "access the public data in the struct sim:" msgstr "" "Существует несколько функций и макросов (другими словами, методов), " "определённых для доступа к публичным данным в структуре sim:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:275 msgid "`cam_sim_path(sim)` - the path ID (see above)" msgstr "`cam_sim_path(sim)` - идентификатор пути (см. выше)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:276 msgid "`cam_sim_name(sim)` - the name of the sim" msgstr "`cam_sim_name(sim)` — имя sim" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:277 msgid "" "`cam_sim_softc(sim)` - the pointer to the softc (driver private data) " "structure" msgstr "" "`cam_sim_softc(sim)` - указатель на структуру softc (приватные данные " "драйвера)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:278 msgid "`cam_sim_unit(sim)` - the unit number" msgstr "`cam_sim_unit(sim)` - номер устройства" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:279 msgid "`cam_sim_bus(sim)` - the bus ID" msgstr "`cam_sim_bus(sim)` - идентификатор шины" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:281 msgid "" "To identify the device, `xxx_action()` can get the unit number and pointer " "to its structure softc using these functions." msgstr "" "Для идентификации устройства `xxx_action()` может получить номер устройства " "и указатель на его структуру softc, используя следующие функции." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:284 msgid "" "The type of request is stored in `ccb->ccb_h.func_code`. So generally " "`xxx_action()` consists of a big switch:" msgstr "" "Тип запроса хранится в `ccb->ccb_h.func_code`. Поэтому, как правило, " "`xxx_action()` состоит из большого оператора switch:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:291 #, no-wrap msgid "" " struct xxx_softc *softc = (struct xxx_softc *) cam_sim_softc(sim);\n" " struct ccb_hdr *ccb_h = &ccb->ccb_h;\n" " int unit = cam_sim_unit(sim);\n" " int bus = cam_sim_bus(sim);\n" msgstr "" " struct xxx_softc *softc = (struct xxx_softc *) cam_sim_softc(sim);\n" " struct ccb_hdr *ccb_h = &ccb->ccb_h;\n" " int unit = cam_sim_unit(sim);\n" " int bus = cam_sim_bus(sim);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:300 #, no-wrap msgid "" " switch (ccb_h->func_code) {\n" " case ...:\n" " ...\n" " default:\n" " ccb_h->status = CAM_REQ_INVALID;\n" " xpt_done(ccb);\n" " break;\n" " }\n" msgstr "" " switch (ccb_h->func_code) {\n" " case ...:\n" " ...\n" " default:\n" " ccb_h->status = CAM_REQ_INVALID;\n" " xpt_done(ccb);\n" " break;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:303 msgid "" "As can be seen from the default case (if an unknown command was received) " "the return code of the command is set into `ccb->ccb_h.status` and the " "completed CCB is returned back to CAM by calling `xpt_done(ccb)`." msgstr "" "Как видно из случая по умолчанию (если получена неизвестная команда) код " "возврата команды устанавливается в `ccb->ccb_h.status`, а завершённый CCB " "возвращается обратно в CAM вызовом `xpt_done(ccb)`." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:306 msgid "" "`xpt_done()` does not have to be called from `xxx_action()`: For example an " "I/O request may be enqueued inside the SIM driver and/or its SCSI " "controller. Then when the device would post an interrupt signaling that the " "processing of this request is complete `xpt_done()` may be called from the " "interrupt handling routine." msgstr "" "`xpt_done()` не обязательно вызывать из `xxx_action()`: Например, запрос " "ввода-вывода может быть поставлен в очередь внутри драйвера SIM и/или его " "SCSI-контроллера. Затем, когда устройство пошлет прерывание, сигнализирующее " "о завершении обработки этого запроса, `xpt_done()` может быть вызван из " "процедуры обработки прерывания." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:314 msgid "" "Actually, the CCB status is not only assigned as a return code but a CCB has " "some status all the time. Before CCB is passed to the `xxx_action()` " "routine it gets the status CCB_REQ_INPROG meaning that it is in progress. " "There are a surprising number of status values defined in [.filename]#/sys/" "cam/cam.h# which should be able to represent the status of a request in " "great detail. More interesting yet, the status is in fact a \"bitwise or\" " "of an enumerated status value (the lower 6 bits) and possible additional " "flag-like bits (the upper bits). The enumerated values will be discussed " "later in more detail. The summary of them can be found in the Errors " "Summary section. The possible status flags are:" msgstr "" "На самом деле, статус CCB не только присваивается в качестве кода возврата, " "но и CCB всегда имеет какой-то статус. Перед тем как CCB передаётся в " "процедуру `xxx_action()`, он получает статус CCB_REQ_INPROG, означающий, что " "запрос находится в процессе выполнения. В [.filename]#/sys/cam/cam.h# " "определено удивительно большое количество значений статуса, которые должны " "детально отражать состояние запроса. Что ещё интереснее, статус фактически " "представляет собой \"побитовое ИЛИ\" перечисленного значения статуса (" "младшие 6 бит) и возможных дополнительных флагов (старшие биты). " "Перечисленные значения будут подробно рассмотрены далее. Их краткое описание " "можно найти в разделе \"Сводка ошибок\". Возможные флаги статуса:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:317 msgid "" "_CAM_DEV_QFRZN_ - if the SIM driver gets a serious error (for example, the " "device does not respond to the selection or breaks the SCSI protocol) when " "processing a CCB it should freeze the request queue by calling " "`xpt_freeze_simq()`, return the other enqueued but not processed yet CCBs " "for this device back to the CAM queue, then set this flag for the " "troublesome CCB and call `xpt_done()`. This flag causes the CAM subsystem " "to unfreeze the queue after it handles the error." msgstr "" "_CAM_DEV_QFRZN_ - если драйвер SIM получает серьёзную ошибку (например, " "устройство не отвечает на выборку или нарушает протокол SCSI) при обработке " "CCB, он должен заморозить очередь запросов, вызвав `xpt_freeze_simq()`, " "вернуть другие поставленные в очередь, но ещё не обработанные CCB для этого " "устройства обратно в очередь CAM, затем установить этот флаг для проблемного " "CCB и вызвать `xpt_done()`. Этот флаг заставляет подсистему CAM разморозить " "очередь после обработки ошибки." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:319 msgid "" "_CAM_AUTOSNS_VALID_ - if the device returned an error condition and the flag " "CAM_DIS_AUTOSENSE is not set in CCB the SIM driver must execute the REQUEST " "SENSE command automatically to extract the sense (extended error " "information) data from the device. If this attempt was successful the sense " "data should be saved in the CCB and this flag set." msgstr "" "_CAM_AUTOSNS_VALID_ - если устройство вернуло состояние ошибки и флаг " "CAM_DIS_AUTOSENSE не установлен в CCB, драйвер SIM должен автоматически " "выполнить команду REQUEST SENSE, чтобы извлечь данные sense (расширенную " "информацию об ошибке) из устройства. Если попытка была успешной, данные " "sense должны быть сохранены в CCB, а этот флаг установлен." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:322 msgid "" "_CAM_RELEASE_SIMQ_ - like CAM_DEV_QFRZN but used in case there is some " "problem (or resource shortage) with the SCSI controller itself. Then all " "the future requests to the controller should be stopped by " "`xpt_freeze_simq()`. The controller queue will be restarted after the SIM " "driver overcomes the shortage and informs CAM by returning some CCB with " "this flag set." msgstr "" "_CAM_RELEASE_SIMQ_ - аналогично CAM_DEV_QFRZN, но используется в случае " "возникновения проблем (или нехватки ресурсов) с самим SCSI-контроллером. В " "этом случае все последующие запросы к контроллеру должны быть остановлены с " "помощью `xpt_freeze_simq()`. Очередь контроллера будет возобновлена после " "того, как драйвер SIM устранит нехватку и уведомит CAM, вернув некоторый CCB " "с установленным этим флагом." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:324 msgid "" "_CAM_SIM_QUEUED_ - when SIM puts a CCB into its request queue this flag " "should be set (and removed when this CCB gets dequeued before being returned " "back to CAM). This flag is not used anywhere in the CAM code now, so its " "purpose is purely diagnostic." msgstr "" "_CAM_SIM_QUEUED_ - этот флаг должен быть установлен, когда SIM помещает CCB " "в свою очередь запросов (и снят, когда этот CCB извлекается из очереди перед " "возвратом в CAM). В настоящее время этот флаг нигде не используется в коде " "CAM, поэтому его назначение чисто диагностическое." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:325 msgid "_CAM_QOS_VALID_ - The QOS data is now valid." msgstr "_CAM_QOS_VALID_ - Данные QOS теперь действительны." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:328 msgid "" "The function `xxx_action()` is not allowed to sleep, so all the " "synchronization for resource access must be done using SIM or device queue " "freezing. Besides the aforementioned flags the CAM subsystem provides " "functions `xpt_release_simq()` and `xpt_release_devq()` to unfreeze the " "queues directly, without passing a CCB to CAM." msgstr "" "Функция `xxx_action()` не может находиться в состоянии ожидания, поэтому вся " "синхронизация доступа к ресурсам должна выполняться с использованием SIM или " "заморозки очереди устройств. Помимо упомянутых флагов, подсистема CAM " "предоставляет функции `xpt_release_simq()` и `xpt_release_devq()` для " "разморозки очередей напрямую, без передачи CCB в CAM." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:330 msgid "The CCB header contains the following fields:" msgstr "Заголовок CCB содержит следующие поля:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:332 msgid "_path_ - path ID for the request" msgstr "_path_ - идентификатор пути для запроса" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:333 msgid "_target_id_ - target device ID for the request" msgstr "_target_id_ - идентификатор целевого устройства для запроса" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:334 msgid "_target_lun_ - LUN ID of the target device" msgstr "_target_lun_ - идентификатор LUN целевого устройства" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:335 msgid "_timeout_ - timeout interval for this command, in milliseconds" msgstr "_timeout_ - интервал таймаута для этой команды, в миллисекундах" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:336 msgid "" "_timeout_ch_ - a convenience place for the SIM driver to store the timeout " "handle (the CAM subsystem itself does not make any assumptions about it)" msgstr "" "_timeout_ch_ - удобное место для драйвера SIM, чтобы хранить обработчик " "таймаута (сама подсистема CAM не делает никаких предположений о нём)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:337 msgid "" "_flags_ - various bits of information about the request spriv_ptr0, " "spriv_ptr1 - fields reserved for private use by the SIM driver (such as " "linking to the SIM queues or SIM private control blocks); actually, they " "exist as unions: spriv_ptr0 and spriv_ptr1 have the type (void *), " "spriv_field0 and spriv_field1 have the type unsigned long, " "sim_priv.entries[0].bytes and sim_priv.entries[1].bytes are byte arrays of " "the size consistent with the other incarnations of the union and " "sim_priv.bytes is one array, twice bigger." msgstr "" "_flags_ - различные биты информации о запросе spriv_ptr0, spriv_ptr1 — поля, " "зарезервированные для приватного использования драйвером SIM (например, для " "связи с очередями SIM или приватными блоками управления SIM); фактически они " "существуют как объединения: spriv_ptr0 и spriv_ptr1 имеют тип (void *), " "spriv_field0 и spriv_field1 имеют тип unsigned long, sim_priv.entries[0]." "bytes и sim_priv.entries[1].bytes - это байтовые массивы размера, " "согласованного с другими вариантами объединения, а sim_priv.bytes - это один " "массив, вдвое большего размера." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:339 msgid "" "The recommended way of using the SIM private fields of CCB is to define some " "meaningful names for them and use these meaningful names in the driver, like:" msgstr "" "Рекомендуемый способ использования приватных полей SIM в CCB — это " "определить для них осмысленные имена и использовать эти осмысленные имена в " "драйвере, например:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:344 #, no-wrap msgid "" "#define ccb_some_meaningful_name sim_priv.entries[0].bytes\n" "#define ccb_hcb spriv_ptr1 /* for hardware control block */\n" msgstr "" "#define ccb_some_meaningful_name sim_priv.entries[0].bytes\n" "#define ccb_hcb spriv_ptr1 /* for hardware control block */\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:347 msgid "The most common initiator mode requests are:" msgstr "Наиболее распространённые запросы в режиме инициатора:" #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:348 #, no-wrap msgid "_XPT_SCSI_IO_ - execute an I/O transaction" msgstr "_XPT_SCSI_IO_ — выполнить транзакцию ввода-вывода" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:352 msgid "" "The instance \"struct ccb_scsiio csio\" of the union ccb is used to transfer " "the arguments. They are:" msgstr "" "Экземпляр \"struct ccb_scsiio csio\" объединения ccb используется для " "передачи аргументов. Они включают:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:354 msgid "_cdb_io_ - pointer to the SCSI command buffer or the buffer itself" msgstr "_cdb_io_ - указатель на буфер команды SCSI или сам буфер" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:355 msgid "_cdb_len_ - SCSI command length" msgstr "_cdb_len_ - длина команды SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:356 msgid "" "_data_ptr_ - pointer to the data buffer (gets a bit complicated if scatter/" "gather is used)" msgstr "" "_data_ptr_ - указатель на буфер данных (усложняется, если используется " "scatter/gather)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:357 msgid "_dxfer_len_ - length of the data to transfer" msgstr "_dxfer_len_ - длина передаваемых данных" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:358 msgid "_sglist_cnt_ - counter of the scatter/gather segments" msgstr "_sglist_cnt_ - счетчик сегментов scatter/gather" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:359 msgid "_scsi_status_ - place to return the SCSI status" msgstr "_scsi_status_ - место для возврата статуса SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:360 msgid "" "_sense_data_ - buffer for the SCSI sense information if the command returns " "an error (the SIM driver is supposed to run the REQUEST SENSE command " "automatically in this case if the CCB flag CAM_DIS_AUTOSENSE is not set)" msgstr "" "_sense_data_ - буфер для информации SCSI sense, если команда возвращает " "ошибку (драйвер SIM должен автоматически выполнить команду REQUEST SENSE в " "этом случае, если флаг CCB CAM_DIS_AUTOSENSE не установлен)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:361 msgid "" "_sense_len_ - the length of that buffer (if it happens to be higher than " "size of sense_data the SIM driver must silently assume the smaller value)" msgstr "" "_sense_len_ - длина этого буфера (если она окажется больше размера " "sense_data, драйвер SIM должен без уведомления принять меньшее значение)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:364 msgid "" "_resid_, _sense_resid_ - if the transfer of data or SCSI sense returned an " "error these are the returned counters of the residual (not transferred) " "data. They do not seem to be especially meaningful, so in a case when they " "are difficult to compute (say, counting bytes in the SCSI controller's FIFO " "buffer) an approximate value will do as well. For a successfully completed " "transfer they must be set to zero." msgstr "" "_resid_, _sense_resid_ — если передача данных или SCSI sense вернула ошибку, " "это счётчики остаточных (не переданных) данных. Они не кажутся особенно " "значимыми, поэтому в случаях, когда их сложно вычислить (например, подсчёт " "байтов в FIFO-буфере SCSI-контроллера), подойдёт и приблизительное значение. " "Для успешно завершённой передачи они должны быть установлены в ноль." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:365 msgid "_tag_action_ - the kind of tag to use:" msgstr "_tag_action_ - тип используемого тега:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:366 msgid "CAM_TAG_ACTION_NONE - do not use tags for this transaction" msgstr "`CAM_TAG_ACTION_NONE` - не использовать теги для данной транзакции" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:367 msgid "" "MSG_SIMPLE_Q_TAG, MSG_HEAD_OF_Q_TAG, MSG_ORDERED_Q_TAG - value equal to the " "appropriate tag message (see /sys/cam/scsi/scsi_message.h); this gives only " "the tag type, the SIM driver must assign the tag value itself" msgstr "" "MSG_SIMPLE_Q_TAG, MSG_HEAD_OF_Q_TAG, MSG_ORDERED_Q_TAG — значение, " "соответствующее указанному теговому сообщению (см. /sys/cam/scsi/scsi_message" ".h); указывает только тип тега, значение тега должно быть назначено самим " "драйвером SIM" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:369 msgid "The general logic of handling this request is the following:" msgstr "Общая логика обработки этого запроса следующая:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:371 msgid "" "The first thing to do is to check for possible races, to make sure that the " "command did not get aborted when it was sitting in the queue:" msgstr "" "Первое, что нужно сделать, это проверить возможные состояния гонки, чтобы " "убедиться, что команда не была прервана, пока находилась в очереди:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:375 #, no-wrap msgid " struct ccb_scsiio *csio = &ccb->csio;\n" msgstr " struct ccb_scsiio *csio = &ccb->csio;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:380 #, no-wrap msgid "" " if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {\n" " xpt_done(ccb);\n" " return;\n" " }\n" msgstr "" " if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {\n" " xpt_done(ccb);\n" " return;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:383 msgid "Also we check that the device is supported at all by our controller:" msgstr "" "Также мы проверяем, что устройство вообще поддерживается нашим контроллером:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:397 #, no-wrap msgid "" " if (ccb_h->target_id > OUR_MAX_SUPPORTED_TARGET_ID\n" " || cch_h->target_id == OUR_SCSI_CONTROLLERS_OWN_ID) {\n" " ccb_h->status = CAM_TID_INVALID;\n" " xpt_done(ccb);\n" " return;\n" " }\n" " if (ccb_h->target_lun > OUR_MAX_SUPPORTED_LUN) {\n" " ccb_h->status = CAM_LUN_INVALID;\n" " xpt_done(ccb);\n" " return;\n" " }\n" msgstr "" " if (ccb_h->target_id > OUR_MAX_SUPPORTED_TARGET_ID\n" " || cch_h->target_id == OUR_SCSI_CONTROLLERS_OWN_ID) {\n" " ccb_h->status = CAM_TID_INVALID;\n" " xpt_done(ccb);\n" " return;\n" " }\n" " if (ccb_h->target_lun > OUR_MAX_SUPPORTED_LUN) {\n" " ccb_h->status = CAM_LUN_INVALID;\n" " xpt_done(ccb);\n" " return;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:403 msgid "" "Then allocate whatever data structures (such as card-dependent hardware " "control block) we need to process this request. If we can not then freeze " "the SIM queue and remember that we have a pending operation, return the CCB " "back and ask CAM to re-queue it. Later when the resources become available " "the SIM queue must be unfrozen by returning a ccb with the " "`CAM_SIMQ_RELEASE` bit set in its status. Otherwise, if all went well, link " "the CCB with the hardware control block (HCB) and mark it as queued." msgstr "" "Затем выделяем все необходимые структуры данных (такие как зависящий от " "карты блок управления оборудованием), которые нам нужны для обработки этого " "запроса. Если мы не можем этого сделать, то замораживаем очередь SIM и " "запоминаем, что у нас есть отложенная операция, возвращаем CCB обратно и " "просим CAM поставить его в очередь снова. Позже, когда ресурсы станут " "доступны, очередь SIM должна быть разморожена путём возврата CCB с " "установленным битом `CAM_SIMQ_RELEASE` в его статусе. В противном случае, " "если всё прошло успешно, связываем CCB с блоком управления оборудованием " "(HCB) и помечаем его как поставленный в очередь." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:407 #, no-wrap msgid " struct xxx_hcb *hcb = allocate_hcb(softc, unit, bus);\n" msgstr " struct xxx_hcb *hcb = allocate_hcb(softc, unit, bus);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:415 #, no-wrap msgid "" " if (hcb == NULL) {\n" " softc->flags |= RESOURCE_SHORTAGE;\n" " xpt_freeze_simq(sim, /*count*/1);\n" " ccb_h->status = CAM_REQUEUE_REQ;\n" " xpt_done(ccb);\n" " return;\n" " }\n" msgstr "" " if (hcb == NULL) {\n" " softc->flags |= RESOURCE_SHORTAGE;\n" " xpt_freeze_simq(sim, /*count*/1);\n" " ccb_h->status = CAM_REQUEUE_REQ;\n" " xpt_done(ccb);\n" " return;\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:418 #, no-wrap msgid "" " hcb->ccb = ccb; ccb_h->ccb_hcb = (void *)hcb;\n" " ccb_h->status |= CAM_SIM_QUEUED;\n" msgstr "" " hcb->ccb = ccb; ccb_h->ccb_hcb = (void *)hcb;\n" " ccb_h->status |= CAM_SIM_QUEUED;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:423 msgid "" "Extract the target data from CCB into the hardware control block. Check if " "we are asked to assign a tag and if yes then generate an unique tag and " "build the SCSI tag messages. The SIM driver is also responsible for " "negotiations with the devices to set the maximal mutually supported bus " "width, synchronous rate and offset." msgstr "" "Извлечь целевые данные из CCB в аппаратный блок управления. Проверить, " "запрошено ли назначение тега, и если да, то сгенерировать уникальный тег и " "построить сообщения тега SCSI. Драйвер SIM также отвечает за согласование с " "устройствами для установки максимальной взаимно поддерживаемой ширины шины, " "синхронной скорости и смещения." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:432 #, no-wrap msgid "" " hcb->target = ccb_h->target_id; hcb->lun = ccb_h->target_lun;\n" " generate_identify_message(hcb);\n" " if (ccb_h->tag_action != CAM_TAG_ACTION_NONE)\n" " generate_unique_tag_message(hcb, ccb_h->tag_action);\n" " if (!target_negotiated(hcb))\n" " generate_negotiation_messages(hcb);\n" msgstr "" " hcb->target = ccb_h->target_id; hcb->lun = ccb_h->target_lun;\n" " generate_identify_message(hcb);\n" " if (ccb_h->tag_action != CAM_TAG_ACTION_NONE)\n" " generate_unique_tag_message(hcb, ccb_h->tag_action);\n" " if (!target_negotiated(hcb))\n" " generate_negotiation_messages(hcb);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:438 msgid "" "Then set up the SCSI command. The command storage may be specified in the " "CCB in many interesting ways, specified by the CCB flags. The command " "buffer can be contained in CCB or pointed to, in the latter case the pointer " "may be physical or virtual. Since the hardware commonly needs physical " "address we always convert the address to the physical one, typically using " "the busdma API." msgstr "" "Затем настройте команду SCSI. Хранилище команды может быть указано в CCB " "различными способами, определяемыми флагами CCB. Буфер команды может " "содержаться в CCB или указываться на него; в последнем случае указатель " "может быть физическим или виртуальным. Поскольку оборудованию обычно " "требуется физический адрес, мы всегда преобразуем адрес в физический, как " "правило, используя API busdma." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:441 msgid "" "In case if a physical address is requested it is OK to return the CCB with " "the status `CAM_REQ_INVALID`, the current drivers do that. If necessary a " "physical address can be also converted or mapped back to a virtual address " "but with big pain, so we do not do that." msgstr "" "В случае, если запрашивается физический адрес, допустимо вернуть CCB со " "статусом `CAM_REQ_INVALID`, текущие драйверы так и делают. При необходимости " "физический адрес также может быть преобразован или отображен обратно в " "виртуальный, но с большими трудностями, поэтому мы этого не делаем." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:458 #, no-wrap msgid "" " if (ccb_h->flags & CAM_CDB_POINTER) {\n" " /* CDB is a pointer */\n" " if (!(ccb_h->flags & CAM_CDB_PHYS)) {\n" " /* CDB pointer is virtual */\n" " hcb->cmd = vtobus(csio->cdb_io.cdb_ptr);\n" " } else {\n" " /* CDB pointer is physical */\n" " hcb->cmd = csio->cdb_io.cdb_ptr ;\n" " }\n" " } else {\n" " /* CDB is in the ccb (buffer) */\n" " hcb->cmd = vtobus(csio->cdb_io.cdb_bytes);\n" " }\n" " hcb->cmdlen = csio->cdb_len;\n" msgstr "" " if (ccb_h->flags & CAM_CDB_POINTER) {\n" " /* CDB is a pointer */\n" " if (!(ccb_h->flags & CAM_CDB_PHYS)) {\n" " /* CDB pointer is virtual */\n" " hcb->cmd = vtobus(csio->cdb_io.cdb_ptr);\n" " } else {\n" " /* CDB pointer is physical */\n" " hcb->cmd = csio->cdb_io.cdb_ptr ;\n" " }\n" " } else {\n" " /* CDB is in the ccb (buffer) */\n" " hcb->cmd = vtobus(csio->cdb_io.cdb_bytes);\n" " }\n" " hcb->cmdlen = csio->cdb_len;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:464 msgid "" "Now it is time to set up the data. Again, the data storage may be specified " "in the CCB in many interesting ways, specified by the CCB flags. First we " "get the direction of the data transfer. The simplest case is if there is no " "data to transfer:" msgstr "" "Теперь настало время настроить данные. Опять же, хранилище данных может быть " "указано в CCB различными интересными способами, определяемыми флагами CCB. " "Сначала мы получаем направление передачи данных. Самый простой случай — если " "нет данных для передачи:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:468 #, no-wrap msgid " int dir = (ccb_h->flags & CAM_DIR_MASK);\n" msgstr " int dir = (ccb_h->flags & CAM_DIR_MASK);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:471 #, no-wrap msgid "" " if (dir == CAM_DIR_NONE)\n" " goto end_data;\n" msgstr "" " if (dir == CAM_DIR_NONE)\n" " goto end_data;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:482 msgid "" "Then we check if the data is in one chunk or in a scatter-gather list, and " "the addresses are physical or virtual. The SCSI controller may be able to " "handle only a limited number of chunks of limited length. If the request " "hits this limitation we return an error. We use a special function to " "return the CCB to handle in one place the HCB resource shortages. The " "functions to add chunks are driver-dependent, and here we leave them without " "detailed implementation. See description of the SCSI command (CDB) handling " "for the details on the address-translation issues. If some variation is too " "difficult or impossible to implement with a particular card it is OK to " "return the status `CAM_REQ_INVALID`. Actually, it seems like the scatter-" "gather ability is not used anywhere in the CAM code now. But at least the " "case for a single non-scattered virtual buffer must be implemented, it is " "actively used by CAM." msgstr "" "Затем мы проверяем, находятся ли данные в одном фрагменте или в списке " "scatter-gather, а также являются ли адреса физическими или виртуальными. " "SCSI-контроллер может обрабатывать только ограниченное количество фрагментов " "ограниченной длины. Если запрос превышает это ограничение, мы возвращаем " "ошибку. Мы используем специальную функцию для возврата CCB, чтобы в одном " "месте обрабатывать нехватку ресурсов HCB. Функции для добавления фрагментов " "зависят от драйвера, и здесь мы оставляем их без детальной реализации. " "Подробности о проблемах трансляции адресов см. в описании обработки SCSI-" "команд (CDB). Если какая-то вариация слишком сложна или невозможна для " "реализации с конкретной картой, допустимо вернуть статус `CAM_REQ_INVALID`. " "На самом деле, похоже, что возможность scatter-gather нигде в коде CAM " "сейчас не используется. Но как минимум случай с единичным неразделённым " "виртуальным буфером должен быть реализован, так как он активно используется " "CAM." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:486 #, no-wrap msgid " int rv;\n" msgstr " int rv;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:488 #, no-wrap msgid " initialize_hcb_for_data(hcb);\n" msgstr " initialize_hcb_for_data(hcb);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:501 #, no-wrap msgid "" " if ((!(ccb_h->flags & CAM_SCATTER_VALID)) {\n" " /* single buffer */\n" " if (!(ccb_h->flags & CAM_DATA_PHYS)) {\n" " rv = add_virtual_chunk(hcb, csio->data_ptr, csio->dxfer_len, dir);\n" " }\n" " } else {\n" " rv = add_physical_chunk(hcb, csio->data_ptr, csio->dxfer_len, dir);\n" " }\n" " } else {\n" " int i;\n" " struct bus_dma_segment *segs;\n" " segs = (struct bus_dma_segment *)csio->data_ptr;\n" msgstr "" " if ((!(ccb_h->flags & CAM_SCATTER_VALID)) {\n" " /* single buffer */\n" " if (!(ccb_h->flags & CAM_DATA_PHYS)) {\n" " rv = add_virtual_chunk(hcb, csio->data_ptr, csio->dxfer_len, " "dir);\n" " }\n" " } else {\n" " rv = add_physical_chunk(hcb, csio->data_ptr, csio->dxfer_len, " "dir);\n" " }\n" " } else {\n" " int i;\n" " struct bus_dma_segment *segs;\n" " segs = (struct bus_dma_segment *)csio->data_ptr;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:533 #, no-wrap msgid "" " if ((ccb_h->flags & CAM_SG_LIST_PHYS) != 0) {\n" " /* The SG list pointer is physical */\n" " rv = setup_hcb_for_physical_sg_list(hcb, segs, csio->sglist_cnt);\n" " } else if (!(ccb_h->flags & CAM_DATA_PHYS)) {\n" " /* SG buffer pointers are virtual */\n" " for (i = 0; i < csio->sglist_cnt; i++) {\n" " rv = add_virtual_chunk(hcb, segs[i].ds_addr,\n" " segs[i].ds_len, dir);\n" " if (rv != CAM_REQ_CMP)\n" " break;\n" " }\n" " } else {\n" " /* SG buffer pointers are physical */\n" " for (i = 0; i < csio->sglist_cnt; i++) {\n" " rv = add_physical_chunk(hcb, segs[i].ds_addr,\n" " segs[i].ds_len, dir);\n" " if (rv != CAM_REQ_CMP)\n" " break;\n" " }\n" " }\n" " }\n" " if (rv != CAM_REQ_CMP) {\n" " /* we expect that add_*_chunk() functions return CAM_REQ_CMP\n" " * if they added a chunk successfully, CAM_REQ_TOO_BIG if\n" " * the request is too big (too many bytes or too many chunks),\n" " * CAM_REQ_INVALID in case of other troubles\n" " */\n" " free_hcb_and_ccb_done(hcb, ccb, rv);\n" " return;\n" " }\n" " end_data:\n" msgstr "" " if ((ccb_h->flags & CAM_SG_LIST_PHYS) != 0) {\n" " /* The SG list pointer is physical */\n" " rv = setup_hcb_for_physical_sg_list(hcb, segs, csio->sglist_cnt);" "\n" " } else if (!(ccb_h->flags & CAM_DATA_PHYS)) {\n" " /* SG buffer pointers are virtual */\n" " for (i = 0; i < csio->sglist_cnt; i++) {\n" " rv = add_virtual_chunk(hcb, segs[i].ds_addr,\n" " segs[i].ds_len, dir);\n" " if (rv != CAM_REQ_CMP)\n" " break;\n" " }\n" " } else {\n" " /* SG buffer pointers are physical */\n" " for (i = 0; i < csio->sglist_cnt; i++) {\n" " rv = add_physical_chunk(hcb, segs[i].ds_addr,\n" " segs[i].ds_len, dir);\n" " if (rv != CAM_REQ_CMP)\n" " break;\n" " }\n" " }\n" " }\n" " if (rv != CAM_REQ_CMP) {\n" " /* we expect that add_*_chunk() functions return CAM_REQ_CMP\n" " * if they added a chunk successfully, CAM_REQ_TOO_BIG if\n" " * the request is too big (too many bytes or too many chunks),\n" " * CAM_REQ_INVALID in case of other troubles\n" " */\n" " free_hcb_and_ccb_done(hcb, ccb, rv);\n" " return;\n" " }\n" " end_data:\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:536 msgid "" "If disconnection is disabled for this CCB we pass this information to the " "hcb:" msgstr "" "Если отключение запрещено для этого CCB, мы передаем эту информацию в hcb:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:541 #, no-wrap msgid "" " if (ccb_h->flags & CAM_DIS_DISCONNECT)\n" " hcb_disable_disconnect(hcb);\n" msgstr "" " if (ccb_h->flags & CAM_DIS_DISCONNECT)\n" " hcb_disable_disconnect(hcb);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:544 msgid "" "If the controller is able to run REQUEST SENSE command all by itself then " "the value of the flag CAM_DIS_AUTOSENSE should also be passed to it, to " "prevent automatic REQUEST SENSE if the CAM subsystem does not want it." msgstr "" "Если контроллер способен самостоятельно выполнять команду REQUEST SENSE, то " "ему также следует передать значение флага CAM_DIS_AUTOSENSE, чтобы " "предотвратить автоматическое выполнение REQUEST SENSE, если подсистема CAM " "этого не требует." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:546 msgid "" "The only thing left is to set up the timeout, pass our hcb to the hardware " "and return, the rest will be done by the interrupt handler (or timeout " "handler)." msgstr "" "Осталось только установить таймаут, передать наш hcb оборудованию и " "вернуться, остальное будет сделано обработчиком прерывания (или обработчиком " "таймаута)." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:553 #, no-wrap msgid "" " ccb_h->timeout_ch = timeout(xxx_timeout, (caddr_t) hcb,\n" " (ccb_h->timeout * hz) / 1000); /* convert milliseconds to ticks */\n" " put_hcb_into_hardware_queue(hcb);\n" " return;\n" msgstr "" " ccb_h->timeout_ch = timeout(xxx_timeout, (caddr_t) hcb,\n" " (ccb_h->timeout * hz) / 1000); /* convert milliseconds to ticks */\n" " put_hcb_into_hardware_queue(hcb);\n" " return;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:556 msgid "And here is a possible implementation of the function returning CCB:" msgstr "И вот возможная реализация функции, возвращающей CCB:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:563 #, no-wrap msgid "" " static void\n" " free_hcb_and_ccb_done(struct xxx_hcb *hcb, union ccb *ccb, u_int32_t status)\n" " {\n" " struct xxx_softc *softc = hcb->softc;\n" msgstr "" " static void\n" " free_hcb_and_ccb_done(struct xxx_hcb *hcb, union ccb *ccb, u_int32_t " "status)\n" " {\n" " struct xxx_softc *softc = hcb->softc;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:578 #, no-wrap msgid "" " ccb->ccb_h.ccb_hcb = 0;\n" " if (hcb != NULL) {\n" " untimeout(xxx_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch);\n" " /* we're about to free a hcb, so the shortage has ended */\n" " if (softc->flags & RESOURCE_SHORTAGE) {\n" " softc->flags &= ~RESOURCE_SHORTAGE;\n" " status |= CAM_RELEASE_SIMQ;\n" " }\n" " free_hcb(hcb); /* also removes hcb from any internal lists */\n" " }\n" " ccb->ccb_h.status = status |\n" " (ccb->ccb_h.status & ~(CAM_STATUS_MASK|CAM_SIM_QUEUED));\n" " xpt_done(ccb);\n" " }\n" msgstr "" " ccb->ccb_h.ccb_hcb = 0;\n" " if (hcb != NULL) {\n" " untimeout(xxx_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch);\n" " /* we're about to free a hcb, so the shortage has ended */\n" " if (softc->flags & RESOURCE_SHORTAGE) {\n" " softc->flags &= ~RESOURCE_SHORTAGE;\n" " status |= CAM_RELEASE_SIMQ;\n" " }\n" " free_hcb(hcb); /* also removes hcb from any internal lists */\n" " }\n" " ccb->ccb_h.status = status |\n" " (ccb->ccb_h.status & ~(CAM_STATUS_MASK|CAM_SIM_QUEUED));\n" " xpt_done(ccb);\n" " }\n" #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:580 #, no-wrap msgid "_XPT_RESET_DEV_ - send the SCSI \"BUS DEVICE RESET\" message to a device" msgstr "" "_XPT_RESET_DEV_ — отправить устройству сообщение SCSI \"BUS DEVICE RESET\"" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:585 msgid "" "There is no data transferred in CCB except the header and the most " "interesting argument of it is target_id. Depending on the controller " "hardware a hardware control block just like for the XPT_SCSI_IO request may " "be constructed (see XPT_SCSI_IO request description) and sent to the " "controller or the SCSI controller may be immediately programmed to send this " "RESET message to the device or this request may be just not supported (and " "return the status `CAM_REQ_INVALID`). Also on completion of the request all " "the disconnected transactions for this target must be aborted (probably in " "the interrupt routine)." msgstr "" "В CCB не передаются данные, кроме заголовка, и наиболее интересным " "аргументом в нём является target_id. В зависимости от аппаратного " "обеспечения контроллера может быть создан аппаратный блок управления (как " "для запроса XPT_SCSI_IO, см. описание запроса XPT_SCSI_IO) и отправлен " "контроллеру, или SCSI-контроллер может быть немедленно запрограммирован на " "отправку этого сообщения RESET устройству, или этот запрос может просто не " "поддерживаться (и возвращать статус `CAM_REQ_INVALID`). Также при завершении " "запроса все отключенные транзакции для этого целевого устройства должны быть " "прерваны (вероятно, в процедуре прерывания)." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:588 msgid "" "Also all the current negotiations for the target are lost on reset, so they " "might be cleaned too. Or they clearing may be deferred, because anyway the " "target would request re-negotiation on the next transaction." msgstr "" "Кроме того, все текущие переговоры для цели теряются при сбросе, поэтому они " "также могут быть очищены. Или их очистка может быть отложена, так как в " "любом случае цель запросит повторные переговоры при следующей транзакции." #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:589 #, no-wrap msgid "_XPT_RESET_BUS_ - send the RESET signal to the SCSI bus" msgstr "_XPT_RESET_BUS_ — отправить сигнал RESET на шину SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:592 msgid "" "No arguments are passed in the CCB, the only interesting argument is the " "SCSI bus indicated by the struct sim pointer." msgstr "" "В CCB не передаются аргументы, единственный интересный аргумент — это шина " "SCSI, указанная структурой sim." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:594 msgid "" "A minimalistic implementation would forget the SCSI negotiations for all the " "devices on the bus and return the status CAM_REQ_CMP." msgstr "" "Минималистичная реализация могла бы пропустить SCSI-переговоры для всех " "устройств на шине и вернуть статус CAM_REQ_CMP." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:597 msgid "" "The proper implementation would in addition actually reset the SCSI bus " "(possible also reset the SCSI controller) and mark all the CCBs being " "processed, both those in the hardware queue and those being disconnected, as " "done with the status CAM_SCSI_BUS_RESET. Like:" msgstr "" "Правильная реализация дополнительно должна фактически сбросить шину SCSI (" "возможно, также сбросить контроллер SCSI) и пометить все обрабатываемые CCB, " "как находящиеся в аппаратной очереди, так и отключенные, как завершенные со " "статусом CAM_SCSI_BUS_RESET. Например:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:603 #, no-wrap msgid "" " int targ, lun;\n" " struct xxx_hcb *h, *hh;\n" " struct ccb_trans_settings neg;\n" " struct cam_path *path;\n" msgstr "" " int targ, lun;\n" " struct xxx_hcb *h, *hh;\n" " struct ccb_trans_settings neg;\n" " struct cam_path *path;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:609 #, no-wrap msgid "" " /* The SCSI bus reset may take a long time, in this case its completion\n" " * should be checked by interrupt or timeout. But for simplicity\n" " * we assume here that it is really fast.\n" " */\n" " reset_scsi_bus(softc);\n" msgstr "" " /* The SCSI bus reset may take a long time, in this case its completion\n" " * should be checked by interrupt or timeout. But for simplicity\n" " * we assume here that it is really fast.\n" " */\n" " reset_scsi_bus(softc);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:615 #, no-wrap msgid "" " /* drop all enqueued CCBs */\n" " for (h = softc->first_queued_hcb; h != NULL; h = hh) {\n" " hh = h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" msgstr "" " /* drop all enqueued CCBs */\n" " for (h = softc->first_queued_hcb; h != NULL; h = hh) {\n" " hh = h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:621 #, no-wrap msgid "" " /* the clean values of negotiations to report */\n" " neg.bus_width = 8;\n" " neg.sync_period = neg.sync_offset = 0;\n" " neg.valid = (CCB_TRANS_BUS_WIDTH_VALID\n" " | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID);\n" msgstr "" " /* the clean values of negotiations to report */\n" " neg.bus_width = 8;\n" " neg.sync_period = neg.sync_offset = 0;\n" " neg.valid = (CCB_TRANS_BUS_WIDTH_VALID\n" " | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:625 #, no-wrap msgid "" " /* drop all disconnected CCBs and clean negotiations */\n" " for (targ=0; targ <= OUR_MAX_SUPPORTED_TARGET; targ++) {\n" " clean_negotiations(softc, targ);\n" msgstr "" " /* drop all disconnected CCBs and clean negotiations */\n" " for (targ=0; targ <= OUR_MAX_SUPPORTED_TARGET; targ++) {\n" " clean_negotiations(softc, targ);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:633 #, no-wrap msgid "" " /* report the event if possible */\n" " if (xpt_create_path(&path, /*periph*/NULL,\n" " cam_sim_path(sim), targ,\n" " CAM_LUN_WILDCARD) == CAM_REQ_CMP) {\n" " xpt_async(AC_TRANSFER_NEG, path, &neg);\n" " xpt_free_path(path);\n" " }\n" msgstr "" " /* report the event if possible */\n" " if (xpt_create_path(&path, /*periph*/NULL,\n" " cam_sim_path(sim), targ,\n" " CAM_LUN_WILDCARD) == CAM_REQ_CMP) {\n" " xpt_async(AC_TRANSFER_NEG, path, &neg);\n" " xpt_free_path(path);\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:640 #, no-wrap msgid "" " for (lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++)\n" " for (h = softc->first_discon_hcb[targ][lun]; h != NULL; h = hh) {\n" " hh=h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" " }\n" msgstr "" " for (lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++)\n" " for (h = softc->first_discon_hcb[targ][lun]; h != NULL; h = hh) {" "\n" " hh=h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:643 #, no-wrap msgid "" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" msgstr "" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:647 #, no-wrap msgid "" " /* report the event */\n" " xpt_async(AC_BUS_RESET, softc->wpath, NULL);\n" " return;\n" msgstr "" " /* report the event */\n" " xpt_async(AC_BUS_RESET, softc->wpath, NULL);\n" " return;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:650 msgid "" "Implementing the SCSI bus reset as a function may be a good idea because it " "would be re-used by the timeout function as a last resort if the things go " "wrong." msgstr "" "Реализация сброса шины SCSI в виде функции может быть хорошей идеей, так как " "она может быть повторно использована функцией таймаута в качестве последнего " "средства, если что-то пойдёт не так." #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:651 #, no-wrap msgid "_XPT_ABORT_ - abort the specified CCB" msgstr "_XPT_ABORT_ — прервать указанный CCB" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:655 msgid "" "The arguments are transferred in the instance \"struct ccb_abort cab\" of " "the union ccb. The only argument field in it is:" msgstr "" "Аргументы передаются в экземпляре \"struct ccb_abort cab\" объединения ccb. " "Единственное поле аргумента в нём:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:657 msgid "_abort_ccb_ - pointer to the CCB to be aborted" msgstr "_abort_ccb_ — указатель на CCB, который необходимо прервать" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:660 msgid "" "If the abort is not supported just return the status CAM_UA_ABORT. This is " "also the easy way to minimally implement this call, return CAM_UA_ABORT in " "any case." msgstr "" "Если прерывание не поддерживается, просто верните статус CAM_UA_ABORT. Это " "также простой способ минимальной реализации этого вызова — в любом случае " "возвращать CAM_UA_ABORT." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:663 msgid "" "The hard way is to implement this request honestly. First check that abort " "applies to a SCSI transaction:" msgstr "" "Трудный путь — честно реализовать этот запрос. Сначала проверьте, что " "прерывание применяется к SCSI-транзакции:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:668 #, no-wrap msgid "" " struct ccb *abort_ccb;\n" " abort_ccb = ccb->cab.abort_ccb;\n" msgstr "" " struct ccb *abort_ccb;\n" " abort_ccb = ccb->cab.abort_ccb;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:674 #, no-wrap msgid "" " if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {\n" " ccb->ccb_h.status = CAM_UA_ABORT;\n" " xpt_done(ccb);\n" " return;\n" " }\n" msgstr "" " if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {\n" " ccb->ccb_h.status = CAM_UA_ABORT;\n" " xpt_done(ccb);\n" " return;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:678 msgid "" "Then it is necessary to find this CCB in our queue. This can be done by " "walking the list of all our hardware control blocks in search for one " "associated with this CCB:" msgstr "" "Затем необходимо найти этот CCB в нашей очереди. Это можно сделать, пройдясь " "по списку всех наших блоков управления оборудованием в поисках связанного с " "этим CCB:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:682 #, no-wrap msgid " struct xxx_hcb *hcb, *h;\n" msgstr " struct xxx_hcb *hcb, *h;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:684 #, no-wrap msgid " hcb = NULL;\n" msgstr " hcb = NULL;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:695 #, no-wrap msgid "" " /* We assume that softc->first_hcb is the head of the list of all\n" " * HCBs associated with this bus, including those enqueued for\n" " * processing, being processed by hardware and disconnected ones.\n" " */\n" " for (h = softc->first_hcb; h != NULL; h = h->next) {\n" " if (h->ccb == abort_ccb) {\n" " hcb = h;\n" " break;\n" " }\n" " }\n" msgstr "" " /* We assume that softc->first_hcb is the head of the list of all\n" " * HCBs associated with this bus, including those enqueued for\n" " * processing, being processed by hardware and disconnected ones.\n" " */\n" " for (h = softc->first_hcb; h != NULL; h = h->next) {\n" " if (h->ccb == abort_ccb) {\n" " hcb = h;\n" " break;\n" " }\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:702 #, no-wrap msgid "" " if (hcb == NULL) {\n" " /* no such CCB in our queue */\n" " ccb->ccb_h.status = CAM_PATH_INVALID;\n" " xpt_done(ccb);\n" " return;\n" " }\n" msgstr "" " if (hcb == NULL) {\n" " /* no such CCB in our queue */\n" " ccb->ccb_h.status = CAM_PATH_INVALID;\n" " xpt_done(ccb);\n" " return;\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:704 #, no-wrap msgid " hcb=found_hcb;\n" msgstr " hcb=found_hcb;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:709 msgid "" "Now we look at the current processing status of the HCB. It may be either " "sitting in the queue waiting to be sent to the SCSI bus, being transferred " "right now, or disconnected and waiting for the result of the command, or " "actually completed by hardware but not yet marked as done by software. To " "make sure that we do not get in any races with hardware we mark the HCB as " "being aborted, so that if this HCB is about to be sent to the SCSI bus the " "SCSI controller will see this flag and skip it." msgstr "" "Теперь мы рассмотрим текущее состояние обработки HCB. Он может находиться в " "очереди, ожидая отправки на шину SCSI, передаваться в данный момент, быть " "отключенным и ожидать результата команды, или фактически завершённым с точки " "зрения аппаратуры, но ещё не отмеченным программным обеспечением, как " "выполненный. Чтобы избежать состояний гонки с аппаратурой, мы помечаем HCB " "как прерванный, так что если этот HCB вот-вот будет отправлен на шину SCSI, " "контроллер SCSI увидит этот флаг и пропустит его." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:713 #, no-wrap msgid " int hstatus;\n" msgstr " int hstatus;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:718 #, no-wrap msgid "" " /* shown as a function, in case special action is needed to make\n" " * this flag visible to hardware\n" " */\n" " set_hcb_flags(hcb, HCB_BEING_ABORTED);\n" msgstr "" " /* shown as a function, in case special action is needed to make\n" " * this flag visible to hardware\n" " */\n" " set_hcb_flags(hcb, HCB_BEING_ABORTED);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:720 #, no-wrap msgid " abort_again:\n" msgstr " abort_again:\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:730 #, no-wrap msgid "" " hstatus = get_hcb_status(hcb);\n" " switch (hstatus) {\n" " case HCB_SITTING_IN_QUEUE:\n" " remove_hcb_from_hardware_queue(hcb);\n" " /* FALLTHROUGH */\n" " case HCB_COMPLETED:\n" " /* this is an easy case */\n" " free_hcb_and_ccb_done(hcb, abort_ccb, CAM_REQ_ABORTED);\n" " break;\n" msgstr "" " hstatus = get_hcb_status(hcb);\n" " switch (hstatus) {\n" " case HCB_SITTING_IN_QUEUE:\n" " remove_hcb_from_hardware_queue(hcb);\n" " /* FALLTHROUGH */\n" " case HCB_COMPLETED:\n" " /* this is an easy case */\n" " free_hcb_and_ccb_done(hcb, abort_ccb, CAM_REQ_ABORTED);\n" " break;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:737 msgid "" "If the CCB is being transferred right now we would like to signal to the " "SCSI controller in some hardware-dependent way that we want to abort the " "current transfer. The SCSI controller would set the SCSI ATTENTION signal " "and when the target responds to it send an ABORT message. We also reset the " "timeout to make sure that the target is not sleeping forever. If the " "command would not get aborted in some reasonable time like 10 seconds the " "timeout routine would go ahead and reset the whole SCSI bus. Since the " "command will be aborted in some reasonable time we can just return the abort " "request now as successfully completed, and mark the aborted CCB as aborted " "(but not mark it as done yet)." msgstr "" "Если CCB передаётся в данный момент, мы хотели бы сигнализировать " "контроллеру SCSI аппаратно-зависимым способом, что хотим прервать текущую " "передачу. Контроллер SCSI установит сигнал SCSI ATTENTION, и когда целевое " "устройство ответит на него, отправит сообщение ABORT. Мы также сбрасываем " "таймаут, чтобы убедиться, что целевое устройство не засыпает навсегда. Если " "команда не будет прервана в разумное время, например, за 10 секунд, " "процедура таймаута продолжит работу и сбросит всю шину SCSI. Поскольку " "команда будет прервана в разумные сроки, мы можем просто вернуть запрос на " "прерывание как успешно выполненный и пометить прерванный CCB как прерванный (" "но пока не помечать его как завершённый)." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:753 #, no-wrap msgid "" " case HCB_BEING_TRANSFERRED:\n" " untimeout(xxx_timeout, (caddr_t) hcb, abort_ccb->ccb_h.timeout_ch);\n" " abort_ccb->ccb_h.timeout_ch =\n" " timeout(xxx_timeout, (caddr_t) hcb, 10 * hz);\n" " abort_ccb->ccb_h.status = CAM_REQ_ABORTED;\n" " /* ask the controller to abort that HCB, then generate\n" " * an interrupt and stop\n" " */\n" " if (signal_hardware_to_abort_hcb_and_stop(hcb) < 0) {\n" " /* oops, we missed the race with hardware, this transaction\n" " * got off the bus before we aborted it, try again */\n" " goto abort_again;\n" " }\n" msgstr "" " case HCB_BEING_TRANSFERRED:\n" " untimeout(xxx_timeout, (caddr_t) hcb, abort_ccb->ccb_h.timeout_ch);\n" " abort_ccb->ccb_h.timeout_ch =\n" " timeout(xxx_timeout, (caddr_t) hcb, 10 * hz);\n" " abort_ccb->ccb_h.status = CAM_REQ_ABORTED;\n" " /* ask the controller to abort that HCB, then generate\n" " * an interrupt and stop\n" " */\n" " if (signal_hardware_to_abort_hcb_and_stop(hcb) < 0) {\n" " /* oops, we missed the race with hardware, this transaction\n" " * got off the bus before we aborted it, try again */\n" " goto abort_again;\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:755 #, no-wrap msgid " break;\n" msgstr " break;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:759 msgid "" "If the CCB is in the list of disconnected then set it up as an abort request " "and re-queue it at the front of hardware queue. Reset the timeout and " "report the abort request to be completed." msgstr "" "Если CCB находится в списке отключенных, то настроить его как запрос " "прерывания и повторно поставить в начало аппаратной очереди. Сбросить " "таймаут и сообщить о завершении запроса прерывания." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:773 #, no-wrap msgid "" " case HCB_DISCONNECTED:\n" " untimeout(xxx_timeout, (caddr_t) hcb, abort_ccb->ccb_h.timeout_ch);\n" " abort_ccb->ccb_h.timeout_ch =\n" " timeout(xxx_timeout, (caddr_t) hcb, 10 * hz);\n" " put_abort_message_into_hcb(hcb);\n" " put_hcb_at_the_front_of_hardware_queue(hcb);\n" " break;\n" " }\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" msgstr "" " case HCB_DISCONNECTED:\n" " untimeout(xxx_timeout, (caddr_t) hcb, abort_ccb->ccb_h.timeout_ch);\n" " abort_ccb->ccb_h.timeout_ch =\n" " timeout(xxx_timeout, (caddr_t) hcb, 10 * hz);\n" " put_abort_message_into_hcb(hcb);\n" " put_hcb_at_the_front_of_hardware_queue(hcb);\n" " break;\n" " }\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:778 msgid "" "That is all for the ABORT request, although there is one more issue. As the " "ABORT message cleans all the ongoing transactions on a LUN we have to mark " "all the other active transactions on this LUN as aborted. That should be " "done in the interrupt routine, after the transaction gets aborted." msgstr "" "Вот и все, что касается запроса ABORT, хотя есть ещё один момент. Поскольку " "сообщение ABORT очищает все текущие транзакции на LUN, нам необходимо " "пометить все остальные активные транзакции на этом LUN как прерванные. Это " "должно быть выполнено в процедуре аппаратного прерывания после того, как " "транзакция будет прервана." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:782 msgid "" "Implementing the CCB abort as a function may be quite a good idea, this " "function can be re-used if an I/O transaction times out. The only " "difference would be that the timed out transaction would return the status " "CAM_CMD_TIMEOUT for the timed out request. Then the case XPT_ABORT would be " "small, like that:" msgstr "" "Реализация прерывания CCB в виде функции может быть довольно хорошей идеей, " "эта функция может быть повторно использована, если транзакция ввода-вывода " "превысит время ожидания. Единственное различие будет в том, что для " "транзакции с истекшим временем ожидания будет возвращён статус " "CAM_CMD_TIMEOUT. Тогда код в case XPT_ABORT будет небольшим, например:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:788 #, no-wrap msgid "" " case XPT_ABORT:\n" " struct ccb *abort_ccb;\n" " abort_ccb = ccb->cab.abort_ccb;\n" msgstr "" " case XPT_ABORT:\n" " struct ccb *abort_ccb;\n" " abort_ccb = ccb->cab.abort_ccb;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:801 #, no-wrap msgid "" " if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {\n" " ccb->ccb_h.status = CAM_UA_ABORT;\n" " xpt_done(ccb);\n" " return;\n" " }\n" " if (xxx_abort_ccb(abort_ccb, CAM_REQ_ABORTED) < 0)\n" " /* no such CCB in our queue */\n" " ccb->ccb_h.status = CAM_PATH_INVALID;\n" " else\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" msgstr "" " if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {\n" " ccb->ccb_h.status = CAM_UA_ABORT;\n" " xpt_done(ccb);\n" " return;\n" " }\n" " if (xxx_abort_ccb(abort_ccb, CAM_REQ_ABORTED) < 0)\n" " /* no such CCB in our queue */\n" " ccb->ccb_h.status = CAM_PATH_INVALID;\n" " else\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:803 #, no-wrap msgid "_XPT_SET_TRAN_SETTINGS_ - explicitly set values of SCSI transfer settings" msgstr "" "_XPT_SET_TRAN_SETTINGS_ — явно установить значения настроек передачи SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:806 msgid "" "The arguments are transferred in the instance \"struct ccb_trans_setting " "cts\" of the union ccb:" msgstr "" "Аргументы передаются в экземпляре \"struct ccb_trans_setting cts\" " "объединения ccb:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:808 msgid "_valid_ - a bitmask showing which settings should be updated:" msgstr "" "_valid_ - битовая маска, показывающая, какие настройки должны быть обновлены:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:809 msgid "_CCB_TRANS_SYNC_RATE_VALID_ - synchronous transfer rate" msgstr "_CCB_TRANS_SYNC_RATE_VALID_ - скорость синхронной передачи" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:810 msgid "_CCB_TRANS_SYNC_OFFSET_VALID_ - synchronous offset" msgstr "_CCB_TRANS_SYNC_OFFSET_VALID_ - синхронное смещение" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:811 msgid "_CCB_TRANS_BUS_WIDTH_VALID_ - bus width" msgstr "_CCB_TRANS_BUS_WIDTH_VALID_ - ширина шины" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:812 msgid "_CCB_TRANS_DISC_VALID_ - set enable/disable disconnection" msgstr "_CCB_TRANS_DISC_VALID_ - установить разрешение/запрет отключения" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:813 msgid "_CCB_TRANS_TQ_VALID_ - set enable/disable tagged queuing" msgstr "_CCB_TRANS_TQ_VALID_ - установить разрешение/запрет очередей с тегами" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:815 msgid "" "_flags_ - consists of two parts, binary arguments and identification of sub-" "operations. The binary arguments are:" msgstr "" "_flags_ - состоит из двух частей: бинарных аргументов и идентификации " "подопераций. Бинарные аргументы:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:816 msgid "_CCB_TRANS_DISC_ENB_ - enable disconnection" msgstr "_CCB_TRANS_DISC_ENB_ - разрешить отключение" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:817 msgid "_CCB_TRANS_TAG_ENB_ - enable tagged queuing" msgstr "_CCB_TRANS_TAG_ENB_ - разрешить тегированную очередь" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:818 msgid "the sub-operations are:" msgstr "подоперации:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:819 msgid "_CCB_TRANS_CURRENT_SETTINGS_ - change the current negotiations" msgstr "_CCB_TRANS_CURRENT_SETTINGS_ - изменить текущие параметры согласования" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:820 msgid "" "_CCB_TRANS_USER_SETTINGS_ - remember the desired user values sync_period, " "sync_offset - self-explanatory, if sync_offset==0 then the asynchronous mode " "is requested bus_width - bus width, in bits (not bytes)" msgstr "" "_CCB_TRANS_USER_SETTINGS_ - сохранять желаемые пользовательские значения " "sync_period, sync_offset - самоочевидные параметры; если sync_offset==0, то " "запрашивается асинхронный режим bus_width - ширина шины в битах (не в байтах)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:825 msgid "" "Two sets of negotiated parameters are supported, the user settings and the " "current settings. The user settings are not really used much in the SIM " "drivers, this is mostly just a piece of memory where the upper levels can " "store (and later recall) its ideas about the parameters. Setting the user " "parameters does not cause re-negotiation of the transfer rates. But when " "the SCSI controller does a negotiation it must never set the values higher " "than the user parameters, so it is essentially the top boundary." msgstr "" "Поддерживаются два набора согласованных параметров: пользовательские " "настройки и текущие настройки. Пользовательские настройки не так часто " "используются в драйверах SIM, это в основном просто область памяти, где " "верхние уровни могут сохранять (и позже извлекать) свои представления о " "параметрах. Установка пользовательских параметров не вызывает повторного " "согласования скоростей передачи. Однако, когда SCSI-контроллер выполняет " "согласование, он никогда не должен устанавливать значения выше " "пользовательских параметров, так что они по сути являются верхней границей." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:830 msgid "" "The current settings are, as the name says, current. Changing them means " "that the parameters must be re-negotiated on the next transfer. Again, " "these \"new current settings\" are not supposed to be forced on the device, " "just they are used as the initial step of negotiations. Also they must be " "limited by actual capabilities of the SCSI controller: for example, if the " "SCSI controller has 8-bit bus and the request asks to set 16-bit wide " "transfers this parameter must be silently truncated to 8-bit transfers " "before sending it to the device." msgstr "" "Текущие настройки, как следует из названия, являются текущими. Их изменение " "означает, что параметры должны быть повторно согласованы при следующей " "передаче. Опять же, эти «новые текущие настройки» не предназначены для " "принудительного применения к устройству, они лишь используются в качестве " "начального шага переговоров. Кроме того, они должны быть ограничены " "реальными возможностями SCSI-контроллера: например, если SCSI-контроллер " "имеет 8-битную шину, а запрос требует установки 16-битных передач, этот " "параметр должен быть тихо усечён до 8-битных передач перед отправкой на " "устройство." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:832 msgid "" "One caveat is that the bus width and synchronous parameters are per target " "while the disconnection and tag enabling parameters are per lun." msgstr "" "Один нюанс заключается в том, что ширина шины и синхронные параметры " "относятся к цели, тогда как параметры отключения и включения тегов относятся " "к логическому устройству LUN." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:834 msgid "" "The recommended implementation is to keep 3 sets of negotiated (bus width " "and synchronous transfer) parameters:" msgstr "" "Рекомендуемая реализация заключается в хранении 3 наборов согласованных " "параметров (ширина шины и синхронная передача):" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:836 msgid "_user_ - the user set, as above" msgstr "_user_ - пользовательский набор, как указано выше" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:837 msgid "_current_ - those actually in effect" msgstr "_current_ - тот, который фактически действуют" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:838 msgid "_goal_ - those requested by setting of the \"current\" parameters" msgstr "" "_goal_ - тот набор, который запрошен для установки параметров в качестве " "\"текущих\"" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:840 msgid "The code looks like:" msgstr "Код выглядит следующим образом:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:846 #, no-wrap msgid "" " struct ccb_trans_settings *cts;\n" " int targ, lun;\n" " int flags;\n" msgstr "" " struct ccb_trans_settings *cts;\n" " int targ, lun;\n" " int flags;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:858 #, no-wrap msgid "" " cts = &ccb->cts;\n" " targ = ccb_h->target_id;\n" " lun = ccb_h->target_lun;\n" " flags = cts->flags;\n" " if (flags & CCB_TRANS_USER_SETTINGS) {\n" " if (flags & CCB_TRANS_SYNC_RATE_VALID)\n" " softc->user_sync_period[targ] = cts->sync_period;\n" " if (flags & CCB_TRANS_SYNC_OFFSET_VALID)\n" " softc->user_sync_offset[targ] = cts->sync_offset;\n" " if (flags & CCB_TRANS_BUS_WIDTH_VALID)\n" " softc->user_bus_width[targ] = cts->bus_width;\n" msgstr "" " cts = &ccb->cts;\n" " targ = ccb_h->target_id;\n" " lun = ccb_h->target_lun;\n" " flags = cts->flags;\n" " if (flags & CCB_TRANS_USER_SETTINGS) {\n" " if (flags & CCB_TRANS_SYNC_RATE_VALID)\n" " softc->user_sync_period[targ] = cts->sync_period;\n" " if (flags & CCB_TRANS_SYNC_OFFSET_VALID)\n" " softc->user_sync_offset[targ] = cts->sync_offset;\n" " if (flags & CCB_TRANS_BUS_WIDTH_VALID)\n" " softc->user_bus_width[targ] = cts->bus_width;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:877 #, no-wrap msgid "" " if (flags & CCB_TRANS_DISC_VALID) {\n" " softc->user_tflags[targ][lun] &= ~CCB_TRANS_DISC_ENB;\n" " softc->user_tflags[targ][lun] |= flags & CCB_TRANS_DISC_ENB;\n" " }\n" " if (flags & CCB_TRANS_TQ_VALID) {\n" " softc->user_tflags[targ][lun] &= ~CCB_TRANS_TQ_ENB;\n" " softc->user_tflags[targ][lun] |= flags & CCB_TRANS_TQ_ENB;\n" " }\n" " }\n" " if (flags & CCB_TRANS_CURRENT_SETTINGS) {\n" " if (flags & CCB_TRANS_SYNC_RATE_VALID)\n" " softc->goal_sync_period[targ] =\n" " max(cts->sync_period, OUR_MIN_SUPPORTED_PERIOD);\n" " if (flags & CCB_TRANS_SYNC_OFFSET_VALID)\n" " softc->goal_sync_offset[targ] =\n" " min(cts->sync_offset, OUR_MAX_SUPPORTED_OFFSET);\n" " if (flags & CCB_TRANS_BUS_WIDTH_VALID)\n" " softc->goal_bus_width[targ] = min(cts->bus_width, OUR_BUS_WIDTH);\n" msgstr "" " if (flags & CCB_TRANS_DISC_VALID) {\n" " softc->user_tflags[targ][lun] &= ~CCB_TRANS_DISC_ENB;\n" " softc->user_tflags[targ][lun] |= flags & CCB_TRANS_DISC_ENB;\n" " }\n" " if (flags & CCB_TRANS_TQ_VALID) {\n" " softc->user_tflags[targ][lun] &= ~CCB_TRANS_TQ_ENB;\n" " softc->user_tflags[targ][lun] |= flags & CCB_TRANS_TQ_ENB;\n" " }\n" " }\n" " if (flags & CCB_TRANS_CURRENT_SETTINGS) {\n" " if (flags & CCB_TRANS_SYNC_RATE_VALID)\n" " softc->goal_sync_period[targ] =\n" " max(cts->sync_period, OUR_MIN_SUPPORTED_PERIOD);\n" " if (flags & CCB_TRANS_SYNC_OFFSET_VALID)\n" " softc->goal_sync_offset[targ] =\n" " min(cts->sync_offset, OUR_MAX_SUPPORTED_OFFSET);\n" " if (flags & CCB_TRANS_BUS_WIDTH_VALID)\n" " softc->goal_bus_width[targ] = min(cts->bus_width, OUR_BUS_WIDTH);" "\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:890 #, no-wrap msgid "" " if (flags & CCB_TRANS_DISC_VALID) {\n" " softc->current_tflags[targ][lun] &= ~CCB_TRANS_DISC_ENB;\n" " softc->current_tflags[targ][lun] |= flags & CCB_TRANS_DISC_ENB;\n" " }\n" " if (flags & CCB_TRANS_TQ_VALID) {\n" " softc->current_tflags[targ][lun] &= ~CCB_TRANS_TQ_ENB;\n" " softc->current_tflags[targ][lun] |= flags & CCB_TRANS_TQ_ENB;\n" " }\n" " }\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" msgstr "" " if (flags & CCB_TRANS_DISC_VALID) {\n" " softc->current_tflags[targ][lun] &= ~CCB_TRANS_DISC_ENB;\n" " softc->current_tflags[targ][lun] |= flags & CCB_TRANS_DISC_ENB;\n" " }\n" " if (flags & CCB_TRANS_TQ_VALID) {\n" " softc->current_tflags[targ][lun] &= ~CCB_TRANS_TQ_ENB;\n" " softc->current_tflags[targ][lun] |= flags & CCB_TRANS_TQ_ENB;\n" " }\n" " }\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:894 msgid "" "Then when the next I/O request will be processed it will check if it has to " "re-negotiate, for example by calling the function target_negotiated(hcb). " "It can be implemented like this:" msgstr "" "Затем, когда следующий запрос ввода-вывода будет обработан, он проверит, " "нужно ли повторное согласование, например, вызовом функции " "target_negotiated(hcb). Это может быть реализовано следующим образом:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:902 #, no-wrap msgid "" " int\n" " target_negotiated(struct xxx_hcb *hcb)\n" " {\n" " struct softc *softc = hcb->softc;\n" " int targ = hcb->targ;\n" msgstr "" " int\n" " target_negotiated(struct xxx_hcb *hcb)\n" " {\n" " struct softc *softc = hcb->softc;\n" " int targ = hcb->targ;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:910 #, no-wrap msgid "" " if (softc->current_sync_period[targ] != softc->goal_sync_period[targ]\n" " || softc->current_sync_offset[targ] != softc->goal_sync_offset[targ]\n" " || softc->current_bus_width[targ] != softc->goal_bus_width[targ])\n" " return 0; /* FALSE */\n" " else\n" " return 1; /* TRUE */\n" " }\n" msgstr "" " if (softc->current_sync_period[targ] != softc->goal_sync_period[targ]" "\n" " || softc->current_sync_offset[targ] != softc->goal_sync_offset[targ]" "\n" " || softc->current_bus_width[targ] != softc->goal_bus_width[targ])\n" " return 0; /* FALSE */\n" " else\n" " return 1; /* TRUE */\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:914 msgid "" "After the values are re-negotiated the resulting values must be assigned to " "both current and goal parameters, so for future I/O transactions the current " "and goal parameters would be the same and `target_negotiated()` would return " "TRUE. When the card is initialized (in `xxx_attach()`) the current " "negotiation values must be initialized to narrow asynchronous mode, the goal " "and current values must be initialized to the maximal values supported by " "controller." msgstr "" "После пересогласования значений полученные значения должны быть присвоены " "как текущим, так и целевым параметрам, чтобы для будущих операций ввода-" "вывода текущие и целевые параметры совпадали, и функция `target_negotiated()`" " возвращала TRUE. При инициализации карты (в `xxx_attach()`) текущие " "параметры согласования должны быть инициализированы узким асинхронным " "режимом, а целевые и текущие значения должны быть инициализированы " "максимальными значениями, поддерживаемыми контроллером." #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:915 #, no-wrap msgid "_XPT_GET_TRAN_SETTINGS_ - get values of SCSI transfer settings" msgstr "_XPT_GET_TRAN_SETTINGS_ — получить значения настроек передачи SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:920 msgid "" "This operations is the reverse of XPT_SET_TRAN_SETTINGS. Fill up the CCB " "instance \"struct ccb_trans_setting cts\" with data as requested by the " "flags CCB_TRANS_CURRENT_SETTINGS or CCB_TRANS_USER_SETTINGS (if both are set " "then the existing drivers return the current settings). Set all the bits in " "the valid field." msgstr "" "Эта операция является обратной XPT_SET_TRAN_SETTINGS. Заполните экземпляр " "CCB \"struct ccb_trans_setting cts\" данными, запрошенными флагами " "CCB_TRANS_CURRENT_SETTINGS или CCB_TRANS_USER_SETTINGS (если установлены " "оба, существующие драйверы возвращают текущие настройки). Установите все " "биты в поле valid." #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:921 #, no-wrap msgid "_XPT_CALC_GEOMETRY_ - calculate logical (BIOS) geometry of the disk" msgstr "_XPT_CALC_GEOMETRY_ — вычислить логическую (BIOS) геометрию диска" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:924 msgid "" "The arguments are transferred in the instance \"struct ccb_calc_geometry " "ccg\" of the union ccb:" msgstr "" "Аргументы передаются в экземпляре \"struct ccb_calc_geometry ccg\" " "объединения ccb:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:926 msgid "_block_size_ - input, block (A.K.A sector) size in bytes" msgstr "_block_size_ - вход, размер блока (также известный как сектор) в байтах" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:927 msgid "_volume_size_ - input, volume size in bytes" msgstr "_volume_size_ - вход, размер тома в байтах" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:928 msgid "_cylinders_ - output, logical cylinders" msgstr "_cylinders_ - выход, логические цилиндры" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:929 msgid "_heads_ - output, logical heads" msgstr "_heads_ - выход, логические головки" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:930 msgid "_secs_per_track_ - output, logical sectors per track" msgstr "_secs_per_track_ - выход, логических секторов на дорожку" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:933 msgid "" "If the returned geometry differs much enough from what the SCSI controller " "BIOS thinks and a disk on this SCSI controller is used as bootable the " "system may not be able to boot. The typical calculation example taken from " "the aic7xxx driver is:" msgstr "" "Если возвращённая геометрия значительно отличается от той, которую " "предполагает BIOS SCSI-контроллера, и диск на этом SCSI-контроллере " "используется как загрузочный, система может не загрузиться. Типичный пример " "расчёта, взятый из драйвера `aic7xxx`, выглядит следующим образом:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:940 #, no-wrap msgid "" " struct ccb_calc_geometry *ccg;\n" " u_int32_t size_mb;\n" " u_int32_t secs_per_cylinder;\n" " int extended;\n" msgstr "" " struct ccb_calc_geometry *ccg;\n" " u_int32_t size_mb;\n" " u_int32_t secs_per_cylinder;\n" " int extended;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:945 #, no-wrap msgid "" " ccg = &ccb->ccg;\n" " size_mb = ccg->volume_size\n" " / ((1024L * 1024L) / ccg->block_size);\n" " extended = check_cards_EEPROM_for_extended_geometry(softc);\n" msgstr "" " ccg = &ccb->ccg;\n" " size_mb = ccg->volume_size\n" " / ((1024L * 1024L) / ccg->block_size);\n" " extended = check_cards_EEPROM_for_extended_geometry(softc);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:958 #, no-wrap msgid "" " if (size_mb > 1024 && extended) {\n" " ccg->heads = 255;\n" " ccg->secs_per_track = 63;\n" " } else {\n" " ccg->heads = 64;\n" " ccg->secs_per_track = 32;\n" " }\n" " secs_per_cylinder = ccg->heads * ccg->secs_per_track;\n" " ccg->cylinders = ccg->volume_size / secs_per_cylinder;\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" msgstr "" " if (size_mb > 1024 && extended) {\n" " ccg->heads = 255;\n" " ccg->secs_per_track = 63;\n" " } else {\n" " ccg->heads = 64;\n" " ccg->secs_per_track = 32;\n" " }\n" " secs_per_cylinder = ccg->heads * ccg->secs_per_track;\n" " ccg->cylinders = ccg->volume_size / secs_per_cylinder;\n" " ccb->ccb_h.status = CAM_REQ_CMP;\n" " xpt_done(ccb);\n" " return;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:963 msgid "" "This gives the general idea, the exact calculation depends on the quirks of " "the particular BIOS. If BIOS provides no way set the \"extended " "translation\" flag in EEPROM this flag should normally be assumed equal to " "1. Other popular geometries are:" msgstr "" "Это даёт общее представление, точный расчет зависит от особенностей " "конкретной BIOS. Если BIOS не предоставляет возможности установить флаг " "\"расширенной трансляции\" в EEPROM, этот флаг обычно следует считать равным " "1. Другие популярные геометрии:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:968 #, no-wrap msgid "" " 128 heads, 63 sectors - Symbios controllers\n" " 16 heads, 63 sectors - old controllers\n" msgstr "" " 128 heads, 63 sectors - Symbios controllers\n" " 16 heads, 63 sectors - old controllers\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:971 msgid "" "Some system BIOSes and SCSI BIOSes fight with each other with variable " "success, for example a combination of Symbios 875/895 SCSI and Phoenix BIOS " "can give geometry 128/63 after power up and 255/63 after a hard reset or " "soft reboot." msgstr "" "Некоторые системные BIOS и SCSI BIOS конфликтуют друг с другом с переменным " "успехом. Например, комбинация Symbios 875/895 SCSI и Phoenix BIOS может " "выдавать геометрию 128/63 после включения питания и 255/63 после жёсткого " "сброса или мягкой перезагрузки." #. type: Title === #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:972 #, no-wrap msgid "_XPT_PATH_INQ_ - path inquiry, in other words get the SIM driver and SCSI controller (also known as HBA - Host Bus Adapter) properties" msgstr "" "_XPT_PATH_INQ_ — запрос пути, другими словами, получение свойств драйвера " "SIM и контроллера SCSI (также известного как HBA - Host Bus Adapter)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:975 msgid "" "The properties are returned in the instance \"struct ccb_pathinq cpi\" of " "the union ccb:" msgstr "" "Свойства возвращаются в экземпляре \"struct ccb_pathinq cpi\" объединения " "ccb:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:977 msgid "version_num - the SIM driver version number, now all drivers use 1" msgstr "" "`version_num` - номер версии драйвера SIM, в настоящее время все драйверы " "используют 1" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:978 msgid "hba_inquiry - bitmask of features supported by the controller:" msgstr "hba_inquiry - битовая маска функций, поддерживаемых контроллером:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:979 msgid "PI_MDP_ABLE - supports MDP message (something from SCSI3?)" msgstr "PI_MDP_ABLE - поддерживает сообщение MDP (что-то из SCSI3?)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:980 msgid "PI_WIDE_32 - supports 32 bit wide SCSI" msgstr "PI_WIDE_32 — поддерживает 32-битную широкую SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:981 msgid "PI_WIDE_16 - supports 16 bit wide SCSI" msgstr "PI_WIDE_16 — поддерживает 16-битную широкую SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:982 msgid "PI_SDTR_ABLE - can negotiate synchronous transfer rate" msgstr "PI_SDTR_ABLE - может согласовать синхронную скорость передачи" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:983 msgid "PI_LINKED_CDB - supports linked commands" msgstr "PI_LINKED_CDB - поддерживает связанные команды" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:984 msgid "PI_TAG_ABLE - supports tagged commands" msgstr "PI_TAG_ABLE - поддерживает помеченные команды" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:985 msgid "" "PI_SOFT_RST - supports soft reset alternative (hard reset and soft reset are " "mutually exclusive within a SCSI bus)" msgstr "" "PI_SOFT_RST — поддерживает альтернативу мягкого сброса (жёсткий сброс и " "мягкий сброс являются взаимоисключающими в пределах шины SCSI)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:986 msgid "target_sprt - flags for target mode support, 0 if unsupported" msgstr "target_sprt - флаги поддержки целевого режима, 0 если не поддерживается" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:987 msgid "hba_misc - miscellaneous controller features:" msgstr "hba_misc - различные функции контроллера:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:988 msgid "PIM_SCANHILO - bus scans from high ID to low ID" msgstr "PIM_SCANHILO - сканирование шины от высокого ID к низкому ID" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:989 msgid "PIM_NOREMOVE - removable devices not included in scan" msgstr "PIM_NOREMOVE - съемные устройства не включены в сканирование" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:990 msgid "PIM_NOINITIATOR - initiator role not supported" msgstr "PIM_NOINITIATOR - роль инициатора не поддерживается" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:991 msgid "PIM_NOBUSRESET - user has disabled initial BUS RESET" msgstr "PIM_NOBUSRESET - пользователь отключил начальный BUS RESET" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:992 msgid "" "hba_eng_cnt - mysterious HBA engine count, something related to compression, " "now is always set to 0" msgstr "" "hba_eng_cnt - загадочное количество движков HBA, что-то связанное со " "сжатием, в настоящее время всегда устанавливается в 0" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:993 msgid "vuhba_flags - vendor-unique flags, unused now" msgstr "" "vuhba_flags - уникальные флаги производителя, в настоящее время не " "используются" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:994 msgid "" "max_target - maximal supported target ID (7 for 8-bit bus, 15 for 16-bit " "bus, 127 for Fibre Channel)" msgstr "" "max_target - максимальный поддерживаемый идентификатор целевого устройства (" "7 для 8-битной шины, 15 для 16-битной шины, 127 для Fibre Channel)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:995 msgid "" "max_lun - maximal supported LUN ID (7 for older SCSI controllers, 63 for " "newer ones)" msgstr "" "max_lun - максимально поддерживаемый идентификатор LUN (7 для старых SCSI-" "контроллеров, 63 для новых)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:996 msgid "async_flags - bitmask of installed Async handler, unused now" msgstr "" "async_flags - битовая маска установленных обработчиков Async, в настоящее " "время не используется" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:997 msgid "hpath_id - highest Path ID in the subsystem, unused now" msgstr "" "hpath_id - наивысший Path ID в подсистеме, в настоящее время не используется" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:998 msgid "unit_number - the controller unit number, cam_sim_unit(sim)" msgstr "unit_number - номер контроллера, cam_sim_unit(sim)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:999 msgid "bus_id - the bus number, cam_sim_bus(sim)" msgstr "bus_id - номер шины, cam_sim_bus(sim)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1000 msgid "initiator_id - the SCSI ID of the controller itself" msgstr "initiator_id - SCSI ID самого контроллера" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1001 msgid "" "base_transfer_speed - nominal transfer speed in KB/s for asynchronous narrow " "transfers, equals to 3300 for SCSI" msgstr "" "base_transfer_speed - номинальная скорость передачи в КБ/с для асинхронных " "узкополосных передач, равна 3300 для SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1002 msgid "" "sim_vid - SIM driver's vendor id, a zero-terminated string of maximal length " "SIM_IDLEN including the terminating zero" msgstr "" "sim_vid - идентификатор производителя драйвера SIM, строка с нулевым " "окончанием максимальной длины SIM_IDLEN, включая завершающий ноль" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1003 msgid "" "hba_vid - SCSI controller's vendor id, a zero-terminated string of maximal " "length HBA_IDLEN including the terminating zero" msgstr "" "hba_vid - идентификатор производителя SCSI-контроллера, строка с нулевым " "окончанием максимальной длины HBA_IDLEN, включая завершающий ноль" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1004 msgid "" "dev_name - device driver name, a zero-terminated string of maximal length " "DEV_IDLEN including the terminating zero, equal to cam_sim_name(sim)" msgstr "" "dev_name - имя драйвера устройства, строка с нулевым окончанием максимальной " "длины DEV_IDLEN, включая завершающий ноль, эквивалентно cam_sim_name(sim)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1006 msgid "" "The recommended way of setting the string fields is using strncpy, like:" msgstr "" "Рекомендуемый способ установки строковых полей — использование strncpy, " "например:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1010 #, no-wrap msgid " strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);\n" msgstr " strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1013 msgid "" "After setting the values set the status to CAM_REQ_CMP and mark the CCB as " "done." msgstr "" "После установки значений установите статус в CAM_REQ_CMP и пометьте CCB как " "завершённый." #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1015 #, no-wrap msgid "Polling xxx_poll" msgstr "Опрос xxx_poll" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1029 msgid "" "The poll function is used to simulate the interrupts when the interrupt " "subsystem is not functioning (for example, when the system has crashed and " "is creating the system dump). The CAM subsystem sets the proper interrupt " "level before calling the poll routine. So all it needs to do is to call the " "interrupt routine (or the other way around, the poll routine may be doing " "the real action and the interrupt routine would just call the poll " "routine). Why bother about a separate function then? This has to do with " "different calling conventions. The `xxx_poll` routine gets the struct " "cam_sim pointer as its argument while the PCI interrupt routine by common " "convention gets pointer to the struct `xxx_softc` and the ISA interrupt " "routine gets just the device unit number. So the poll routine would " "normally look as:" msgstr "" "Функция poll используется для имитации прерываний, когда подсистема " "прерываний не функционирует (например, когда система аварийно завершила " "работу и создает дамп памяти). Подсистема CAM устанавливает соответствующий " "уровень прерывания перед вызовом процедуры poll. Таким образом, все, что ей " "нужно сделать, — это вызвать процедуру прерывания (или наоборот, процедура " "poll может выполнять реальные действия, а процедура прерывания просто " "вызывает процедуру poll). Зачем тогда нужна отдельная функция? Это связано с " "различными соглашениями о вызовах. Процедура `xxx_poll` получает указатель " "на структуру cam_sim в качестве аргумента, в то время как процедура " "прерывания PCI по общему соглашению получает указатель на структуру " "`xxx_softc`, а процедура прерывания ISA получает только номер устройства. " "Таким образом, процедура poll обычно выглядит следующим образом:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1037 #, no-wrap msgid "" "static void\n" "xxx_poll(struct cam_sim *sim)\n" "{\n" " xxx_intr((struct xxx_softc *)cam_sim_softc(sim)); /* for PCI device */\n" "}\n" msgstr "" "static void\n" "xxx_poll(struct cam_sim *sim)\n" "{\n" " xxx_intr((struct xxx_softc *)cam_sim_softc(sim)); /* for PCI device */\n" "}\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1040 msgid "or" msgstr "или" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1048 #, no-wrap msgid "" "static void\n" "xxx_poll(struct cam_sim *sim)\n" "{\n" " xxx_intr(cam_sim_unit(sim)); /* for ISA device */\n" "}\n" msgstr "" "static void\n" "xxx_poll(struct cam_sim *sim)\n" "{\n" " xxx_intr(cam_sim_unit(sim)); /* for ISA device */\n" "}\n" #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1051 #, no-wrap msgid "Asynchronous Events" msgstr "Асинхронные события" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1054 msgid "" "If an asynchronous event callback has been set up then the callback function " "should be defined." msgstr "" "Если была настроена асинхронная callback-функция для события, то callback-" "функция должна быть определена." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1059 #, no-wrap msgid "" "static void\n" "ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)\n" msgstr "" "static void\n" "ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void " "*arg)\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1062 msgid "callback_arg - the value supplied when registering the callback" msgstr "callback_arg - значение, переданное при регистрации callback" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1063 msgid "code - identifies the type of event" msgstr "code - определяет тип события" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1064 msgid "path - identifies the devices to which the event applies" msgstr "path - определяет устройства, к которым применяется событие" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1065 msgid "arg - event-specific argument" msgstr "arg - аргумент, специфичный для события" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1067 msgid "Implementation for a single type of event, AC_LOST_DEVICE, looks like:" msgstr "" "Реализация для одного типа события, AC_LOST_DEVICE, выглядит следующим " "образом:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1074 #, no-wrap msgid "" " struct xxx_softc *softc;\n" " struct cam_sim *sim;\n" " int targ;\n" " struct ccb_trans_settings neg;\n" msgstr "" " struct xxx_softc *softc;\n" " struct cam_sim *sim;\n" " int targ;\n" " struct ccb_trans_settings neg;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1093 #, no-wrap msgid "" " sim = (struct cam_sim *)callback_arg;\n" " softc = (struct xxx_softc *)cam_sim_softc(sim);\n" " switch (code) {\n" " case AC_LOST_DEVICE:\n" " targ = xpt_path_target_id(path);\n" " if (targ <= OUR_MAX_SUPPORTED_TARGET) {\n" " clean_negotiations(softc, targ);\n" " /* send indication to CAM */\n" " neg.bus_width = 8;\n" " neg.sync_period = neg.sync_offset = 0;\n" " neg.valid = (CCB_TRANS_BUS_WIDTH_VALID\n" " | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID);\n" " xpt_async(AC_TRANSFER_NEG, path, &neg);\n" " }\n" " break;\n" " default:\n" " break;\n" " }\n" msgstr "" " sim = (struct cam_sim *)callback_arg;\n" " softc = (struct xxx_softc *)cam_sim_softc(sim);\n" " switch (code) {\n" " case AC_LOST_DEVICE:\n" " targ = xpt_path_target_id(path);\n" " if (targ <= OUR_MAX_SUPPORTED_TARGET) {\n" " clean_negotiations(softc, targ);\n" " /* send indication to CAM */\n" " neg.bus_width = 8;\n" " neg.sync_period = neg.sync_offset = 0;\n" " neg.valid = (CCB_TRANS_BUS_WIDTH_VALID\n" " | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID);\n" " xpt_async(AC_TRANSFER_NEG, path, &neg);\n" " }\n" " break;\n" " default:\n" " break;\n" " }\n" #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1096 #, no-wrap msgid "Interrupts" msgstr "Прерывания" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1099 msgid "" "The exact type of the interrupt routine depends on the type of the " "peripheral bus (PCI, ISA and so on) to which the SCSI controller is " "connected." msgstr "" "Точный тип процедуры прерывания зависит от типа периферийной шины (PCI, ISA " "и так далее), к которой подключен SCSI-контроллер." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1106 msgid "" "The interrupt routines of the SIM drivers run at the interrupt level " "splcam. So `splcam()` should be used in the driver to synchronize activity " "between the interrupt routine and the rest of the driver (for a " "multiprocessor-aware driver things get yet more interesting but we ignore " "this case here). The pseudo-code in this document happily ignores the " "problems of synchronization. The real code must not ignore them. A simple-" "minded approach is to set `splcam()` on the entry to the other routines and " "reset it on return thus protecting them by one big critical section. To " "make sure that the interrupt level will be always restored a wrapper " "function can be defined, like:" msgstr "" "Прерывания в драйверах SIM выполняются на уровне прерывания splcam. Поэтому " "в драйвере следует использовать `splcam()` для синхронизации между " "обработчиком прерывания и остальной частью драйвера (для драйверов, " "учитывающих многопроцессорность, ситуация становится ещё сложнее, но здесь " "мы этот случай не рассматриваем). Псевдокод в этом документе беззаботно " "игнорирует проблемы синхронизации. Реальный код так делать не должен. " "Простейший подход — установить `splcam()` при входе в другие функции и " "сбросить при выходе, защищая их одной большой критической секцией. Чтобы " "гарантировать восстановление уровня прерывания, можно определить обёрточную " "функцию, например:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1117 #, no-wrap msgid "" " static void\n" " xxx_action(struct cam_sim *sim, union ccb *ccb)\n" " {\n" " int s;\n" " s = splcam();\n" " xxx_action1(sim, ccb);\n" " splx(s);\n" " }\n" msgstr "" " static void\n" " xxx_action(struct cam_sim *sim, union ccb *ccb)\n" " {\n" " int s;\n" " s = splcam();\n" " xxx_action1(sim, ccb);\n" " splx(s);\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1123 #, no-wrap msgid "" " static void\n" " xxx_action1(struct cam_sim *sim, union ccb *ccb)\n" " {\n" " ... process the request ...\n" " }\n" msgstr "" " static void\n" " xxx_action1(struct cam_sim *sim, union ccb *ccb)\n" " {\n" " ... process the request ...\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1127 msgid "" "This approach is simple and robust but the problem with it is that " "interrupts may get blocked for a relatively long time and this would " "negatively affect the system's performance. On the other hand the functions " "of the `spl()` family have rather high overhead, so vast amount of tiny " "critical sections may not be good either." msgstr "" "Этот подход прост и надежен, но проблема в том, что прерывания могут " "блокироваться на относительно долгое время, что негативно скажется на " "производительности системы. С другой стороны, функции семейства `spl()` " "имеют довольно высокие накладные расходы, поэтому большое количество мелких " "критических секций также может быть нежелательным." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1130 msgid "" "The conditions handled by the interrupt routine and the details depend very " "much on the hardware. We consider the set of \"typical\" conditions." msgstr "" "Условия, обрабатываемые процедурой прерывания, и детали сильно зависят от " "оборудования. Мы рассматриваем набор \"типичных\" условий." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1135 msgid "" "First, we check if a SCSI reset was encountered on the bus (probably caused " "by another SCSI controller on the same SCSI bus). If so we drop all the " "enqueued and disconnected requests, report the events and re-initialize our " "SCSI controller. It is important that during this initialization the " "controller will not issue another reset or else two controllers on the same " "SCSI bus could ping-pong resets forever. The case of fatal controller error/" "hang could be handled in the same place, but it will probably need also " "sending RESET signal to the SCSI bus to reset the status of the connections " "with the SCSI devices." msgstr "" "Сначала проверяем, было ли на шине событие SCSI сброса (вероятно, вызванное " "другим SCSI-контроллером на той же SCSI-шине). Если это так, мы отменяем все " "поставленные в очередь и отключенные запросы, сообщаем о событиях и повторно " "инициализируем наш SCSI-контроллер. Важно, чтобы во время этой инициализации " "контроллер не инициировал ещё один сброс, иначе два контроллера на одной " "SCSI-шине могут бесконечно обмениваться сбросами. Случай фатальной ошибки/" "зависания контроллера может быть обработан в том же месте, но, вероятно, " "также потребуется отправка сигнала RESET на SCSI-шину для сброса состояния " "соединений с SCSI-устройствами." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1141 #, no-wrap msgid "" " int fatal=0;\n" " struct ccb_trans_settings neg;\n" " struct cam_path *path;\n" msgstr "" " int fatal=0;\n" " struct ccb_trans_settings neg;\n" " struct cam_path *path;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1146 #, no-wrap msgid "" " if (detected_scsi_reset(softc)\n" " || (fatal = detected_fatal_controller_error(softc))) {\n" " int targ, lun;\n" " struct xxx_hcb *h, *hh;\n" msgstr "" " if (detected_scsi_reset(softc)\n" " || (fatal = detected_fatal_controller_error(softc))) {\n" " int targ, lun;\n" " struct xxx_hcb *h, *hh;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1152 #, no-wrap msgid "" " /* drop all enqueued CCBs */\n" " for(h = softc->first_queued_hcb; h != NULL; h = hh) {\n" " hh = h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" msgstr "" " /* drop all enqueued CCBs */\n" " for(h = softc->first_queued_hcb; h != NULL; h = hh) {\n" " hh = h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1158 #, no-wrap msgid "" " /* the clean values of negotiations to report */\n" " neg.bus_width = 8;\n" " neg.sync_period = neg.sync_offset = 0;\n" " neg.valid = (CCB_TRANS_BUS_WIDTH_VALID\n" " | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID);\n" msgstr "" " /* the clean values of negotiations to report */\n" " neg.bus_width = 8;\n" " neg.sync_period = neg.sync_offset = 0;\n" " neg.valid = (CCB_TRANS_BUS_WIDTH_VALID\n" " | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1162 #, no-wrap msgid "" " /* drop all disconnected CCBs and clean negotiations */\n" " for (targ=0; targ <= OUR_MAX_SUPPORTED_TARGET; targ++) {\n" " clean_negotiations(softc, targ);\n" msgstr "" " /* drop all disconnected CCBs and clean negotiations */\n" " for (targ=0; targ <= OUR_MAX_SUPPORTED_TARGET; targ++) {\n" " clean_negotiations(softc, targ);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1170 #, no-wrap msgid "" " /* report the event if possible */\n" " if (xpt_create_path(&path, /*periph*/NULL,\n" " cam_sim_path(sim), targ,\n" " CAM_LUN_WILDCARD) == CAM_REQ_CMP) {\n" " xpt_async(AC_TRANSFER_NEG, path, &neg);\n" " xpt_free_path(path);\n" " }\n" msgstr "" " /* report the event if possible */\n" " if (xpt_create_path(&path, /*periph*/NULL,\n" " cam_sim_path(sim), targ,\n" " CAM_LUN_WILDCARD) == CAM_REQ_CMP) {\n" " xpt_async(AC_TRANSFER_NEG, path, &neg);\n" " xpt_free_path(path);\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1180 #, no-wrap msgid "" " for (lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++)\n" " for (h = softc->first_discon_hcb[targ][lun]; h != NULL; h = hh) {\n" " hh=h->next;\n" " if (fatal)\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_UNREC_HBA_ERROR);\n" " else\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" " }\n" msgstr "" " for (lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++)\n" " for (h = softc->first_discon_hcb[targ][lun]; h != NULL; h = " "hh) {\n" " hh=h->next;\n" " if (fatal)\n" " free_hcb_and_ccb_done(h, h->ccb, " "CAM_UNREC_HBA_ERROR);\n" " else\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);" "\n" " }\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1183 #, no-wrap msgid "" " /* report the event */\n" " xpt_async(AC_BUS_RESET, softc->wpath, NULL);\n" msgstr "" " /* report the event */\n" " xpt_async(AC_BUS_RESET, softc->wpath, NULL);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1197 #, no-wrap msgid "" " /* re-initialization may take a lot of time, in such case\n" " * its completion should be signaled by another interrupt or\n" " * checked on timeout - but for simplicity we assume here that\n" " * it is really fast\n" " */\n" " if (!fatal) {\n" " reinitialize_controller_without_scsi_reset(softc);\n" " } else {\n" " reinitialize_controller_with_scsi_reset(softc);\n" " }\n" " schedule_next_hcb(softc);\n" " return;\n" " }\n" msgstr "" " /* re-initialization may take a lot of time, in such case\n" " * its completion should be signaled by another interrupt or\n" " * checked on timeout - but for simplicity we assume here that\n" " * it is really fast\n" " */\n" " if (!fatal) {\n" " reinitialize_controller_without_scsi_reset(softc);\n" " } else {\n" " reinitialize_controller_with_scsi_reset(softc);\n" " }\n" " schedule_next_hcb(softc);\n" " return;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1202 msgid "" "If interrupt is not caused by a controller-wide condition then probably " "something has happened to the current hardware control block. Depending on " "the hardware there may be other non-HCB-related events, we just do not " "consider them here. Then we analyze what happened to this HCB:" msgstr "" "Если прерывание не вызвано условием, общим для всего контроллера, то, " "вероятно, что-то произошло с текущим блоком управления аппаратным " "обеспечением. В зависимости от оборудования могут быть и другие события, не " "связанные с HCB, но мы их здесь не рассматриваем. Затем мы анализируем, что " "произошло с этим HCB:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1210 #, no-wrap msgid "" " struct xxx_hcb *hcb, *h, *hh;\n" " int hcb_status, scsi_status;\n" " int ccb_status;\n" " int targ;\n" " int lun_to_freeze;\n" msgstr "" " struct xxx_hcb *hcb, *h, *hh;\n" " int hcb_status, scsi_status;\n" " int ccb_status;\n" " int targ;\n" " int lun_to_freeze;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1219 #, no-wrap msgid "" " hcb = get_current_hcb(softc);\n" " if (hcb == NULL) {\n" " /* either stray interrupt or something went very wrong\n" " * or this is something hardware-dependent\n" " */\n" " handle as necessary;\n" " return;\n" " }\n" msgstr "" " hcb = get_current_hcb(softc);\n" " if (hcb == NULL) {\n" " /* either stray interrupt or something went very wrong\n" " * or this is something hardware-dependent\n" " */\n" " handle as necessary;\n" " return;\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1222 #, no-wrap msgid "" " targ = hcb->target;\n" " hcb_status = get_status_of_current_hcb(softc);\n" msgstr "" " targ = hcb->target;\n" " hcb_status = get_status_of_current_hcb(softc);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1225 msgid "" "First we check if the HCB has completed and if so we check the returned SCSI " "status." msgstr "" "Сначала мы проверяем, завершился ли HCB, и если да, то проверяем " "возвращённый статус SCSI." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1230 #, no-wrap msgid "" " if (hcb_status == COMPLETED) {\n" " scsi_status = get_completion_status(hcb);\n" msgstr "" " if (hcb_status == COMPLETED) {\n" " scsi_status = get_completion_status(hcb);\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1233 msgid "" "Then look if this status is related to the REQUEST SENSE command and if so " "handle it in a simple way." msgstr "" "Затем проверьте, связан ли этот статус с командой REQUEST SENSE, и если да, " "обработайте его простым способом." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1247 #, no-wrap msgid "" " if (hcb->flags & DOING_AUTOSENSE) {\n" " if (scsi_status == GOOD) { /* autosense was successful */\n" " hcb->ccb->ccb_h.status |= CAM_AUTOSNS_VALID;\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_SCSI_STATUS_ERROR);\n" " } else {\n" " autosense_failed:\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_AUTOSENSE_FAIL);\n" " }\n" " schedule_next_hcb(softc);\n" " return;\n" " }\n" msgstr "" " if (hcb->flags & DOING_AUTOSENSE) {\n" " if (scsi_status == GOOD) { /* autosense was successful */\n" " hcb->ccb->ccb_h.status |= CAM_AUTOSNS_VALID;\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_SCSI_STATUS_ERROR);" "\n" " } else {\n" " autosense_failed:\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_AUTOSENSE_FAIL);\n" " }\n" " schedule_next_hcb(softc);\n" " return;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1251 msgid "" "Else the command itself has completed, pay more attention to details. If " "auto-sense is not disabled for this CCB and the command has failed with " "sense data then run REQUEST SENSE command to receive that data." msgstr "" "Иначе сама команда завершена, уделяйте больше внимания деталям. Если " "автоопределение не отключено для этого CCB и команда завершилась неудачно с " "данными состояния, выполните команду REQUEST SENSE для получения этих данных." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1256 #, no-wrap msgid "" " hcb->ccb->csio.scsi_status = scsi_status;\n" " calculate_residue(hcb);\n" msgstr "" " hcb->ccb->csio.scsi_status = scsi_status;\n" " calculate_residue(hcb);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1273 #, no-wrap msgid "" " if ((hcb->ccb->ccb_h.flags & CAM_DIS_AUTOSENSE)==0\n" " && (scsi_status == CHECK_CONDITION\n" " || scsi_status == COMMAND_TERMINATED)) {\n" " /* start auto-SENSE */\n" " hcb->flags |= DOING_AUTOSENSE;\n" " setup_autosense_command_in_hcb(hcb);\n" " restart_current_hcb(softc);\n" " return;\n" " }\n" " if (scsi_status == GOOD)\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_REQ_CMP);\n" " else\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_SCSI_STATUS_ERROR);\n" " schedule_next_hcb(softc);\n" " return;\n" " }\n" msgstr "" " if ((hcb->ccb->ccb_h.flags & CAM_DIS_AUTOSENSE)==0\n" " && (scsi_status == CHECK_CONDITION\n" " || scsi_status == COMMAND_TERMINATED)) {\n" " /* start auto-SENSE */\n" " hcb->flags |= DOING_AUTOSENSE;\n" " setup_autosense_command_in_hcb(hcb);\n" " restart_current_hcb(softc);\n" " return;\n" " }\n" " if (scsi_status == GOOD)\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_REQ_CMP);\n" " else\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_SCSI_STATUS_ERROR);\n" " schedule_next_hcb(softc);\n" " return;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1276 msgid "" "One typical thing would be negotiation events: negotiation messages received " "from a SCSI target (in answer to our negotiation attempt or by target's " "initiative) or the target is unable to negotiate (rejects our negotiation " "messages or does not answer them)." msgstr "" "Типичным примером могут быть события согласования: сообщения согласования, " "полученные от цели SCSI (в ответ на нашу попытку согласования или по " "инициативе цели), или если цель не может согласовать (отклоняет наши " "сообщения согласования или не отвечает на них)." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1292 #, no-wrap msgid "" " switch (hcb_status) {\n" " case TARGET_REJECTED_WIDE_NEG:\n" " /* revert to 8-bit bus */\n" " softc->current_bus_width[targ] = softc->goal_bus_width[targ] = 8;\n" " /* report the event */\n" " neg.bus_width = 8;\n" " neg.valid = CCB_TRANS_BUS_WIDTH_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" " continue_current_hcb(softc);\n" " return;\n" " case TARGET_ANSWERED_WIDE_NEG:\n" " {\n" " int wd;\n" msgstr "" " switch (hcb_status) {\n" " case TARGET_REJECTED_WIDE_NEG:\n" " /* revert to 8-bit bus */\n" " softc->current_bus_width[targ] = softc->goal_bus_width[targ] = 8;\n" " /* report the event */\n" " neg.bus_width = 8;\n" " neg.valid = CCB_TRANS_BUS_WIDTH_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" " continue_current_hcb(softc);\n" " return;\n" " case TARGET_ANSWERED_WIDE_NEG:\n" " {\n" " int wd;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1298 #, no-wrap msgid "" " wd = get_target_bus_width_request(softc);\n" " if (wd <= softc->goal_bus_width[targ]) {\n" " /* answer is acceptable */\n" " softc->current_bus_width[targ] =\n" " softc->goal_bus_width[targ] = neg.bus_width = wd;\n" msgstr "" " wd = get_target_bus_width_request(softc);\n" " if (wd <= softc->goal_bus_width[targ]) {\n" " /* answer is acceptable */\n" " softc->current_bus_width[targ] =\n" " softc->goal_bus_width[targ] = neg.bus_width = wd;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1311 #, no-wrap msgid "" " /* report the event */\n" " neg.valid = CCB_TRANS_BUS_WIDTH_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" " } else {\n" " prepare_reject_message(hcb);\n" " }\n" " }\n" " continue_current_hcb(softc);\n" " return;\n" " case TARGET_REQUESTED_WIDE_NEG:\n" " {\n" " int wd;\n" msgstr "" " /* report the event */\n" " neg.valid = CCB_TRANS_BUS_WIDTH_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" " } else {\n" " prepare_reject_message(hcb);\n" " }\n" " }\n" " continue_current_hcb(softc);\n" " return;\n" " case TARGET_REQUESTED_WIDE_NEG:\n" " {\n" " int wd;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1315 #, no-wrap msgid "" " wd = get_target_bus_width_request(softc);\n" " wd = min (wd, OUR_BUS_WIDTH);\n" " wd = min (wd, softc->user_bus_width[targ]);\n" msgstr "" " wd = get_target_bus_width_request(softc);\n" " wd = min (wd, OUR_BUS_WIDTH);\n" " wd = min (wd, softc->user_bus_width[targ]);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1320 #, no-wrap msgid "" " if (wd != softc->current_bus_width[targ]) {\n" " /* the bus width has changed */\n" " softc->current_bus_width[targ] =\n" " softc->goal_bus_width[targ] = neg.bus_width = wd;\n" msgstr "" " if (wd != softc->current_bus_width[targ]) {\n" " /* the bus width has changed */\n" " softc->current_bus_width[targ] =\n" " softc->goal_bus_width[targ] = neg.bus_width = wd;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1330 #, no-wrap msgid "" " /* report the event */\n" " neg.valid = CCB_TRANS_BUS_WIDTH_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" " }\n" " prepare_width_nego_rsponse(hcb, wd);\n" " }\n" " continue_current_hcb(softc);\n" " return;\n" " }\n" msgstr "" " /* report the event */\n" " neg.valid = CCB_TRANS_BUS_WIDTH_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" " }\n" " prepare_width_nego_rsponse(hcb, wd);\n" " }\n" " continue_current_hcb(softc);\n" " return;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1334 msgid "" "Then we handle any errors that could have happened during auto-sense in the " "same simple-minded way as before. Otherwise we look closer at the details " "again." msgstr "" "Затем мы обрабатываем любые ошибки, которые могли произойти во время " "автоопределения, тем же простым способом, что и раньше. В противном случае " "мы снова внимательно изучаем детали." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1339 #, no-wrap msgid "" " if (hcb->flags & DOING_AUTOSENSE)\n" " goto autosense_failed;\n" msgstr "" " if (hcb->flags & DOING_AUTOSENSE)\n" " goto autosense_failed;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1341 #, no-wrap msgid " switch (hcb_status) {\n" msgstr " switch (hcb_status) {\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1345 msgid "" "The next event we consider is unexpected disconnect. Which is considered " "normal after an ABORT or BUS DEVICE RESET message and abnormal in other " "cases." msgstr "" "Следующее событие, которое мы рассматриваем, — это неожиданное отключение. " "Оно считается нормальным после сообщения ABORT или BUS DEVICE RESET и " "аномальным в остальных случаях." #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1361 #, no-wrap msgid "" " case UNEXPECTED_DISCONNECT:\n" " if (requested_abort(hcb)) {\n" " /* abort affects all commands on that target+LUN, so\n" " * mark all disconnected HCBs on that target+LUN as aborted too\n" " */\n" " for (h = softc->first_discon_hcb[hcb->target][hcb->lun];\n" " h != NULL; h = hh) {\n" " hh=h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_REQ_ABORTED);\n" " }\n" " ccb_status = CAM_REQ_ABORTED;\n" " } else if (requested_bus_device_reset(hcb)) {\n" " int lun;\n" msgstr "" " case UNEXPECTED_DISCONNECT:\n" " if (requested_abort(hcb)) {\n" " /* abort affects all commands on that target+LUN, so\n" " * mark all disconnected HCBs on that target+LUN as aborted too\n" " */\n" " for (h = softc->first_discon_hcb[hcb->target][hcb->lun];\n" " h != NULL; h = hh) {\n" " hh=h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_REQ_ABORTED);\n" " }\n" " ccb_status = CAM_REQ_ABORTED;\n" " } else if (requested_bus_device_reset(hcb)) {\n" " int lun;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1365 #, no-wrap msgid "" " /* reset affects all commands on that target, so\n" " * mark all disconnected HCBs on that target+LUN as reset\n" " */\n" msgstr "" " /* reset affects all commands on that target, so\n" " * mark all disconnected HCBs on that target+LUN as reset\n" " */\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1372 #, no-wrap msgid "" " for (lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++)\n" " for (h = softc->first_discon_hcb[hcb->target][lun];\n" " h != NULL; h = hh) {\n" " hh=h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" msgstr "" " for (lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++)\n" " for (h = softc->first_discon_hcb[hcb->target][lun];\n" " h != NULL; h = hh) {\n" " hh=h->next;\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET);\n" " }\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1375 #, no-wrap msgid "" " /* send event */\n" " xpt_async(AC_SENT_BDR, hcb->ccb->ccb_h.path_id, NULL);\n" msgstr "" " /* send event */\n" " xpt_async(AC_SENT_BDR, hcb->ccb->ccb_h.path_id, NULL);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1386 #, no-wrap msgid "" " /* this was the CAM_RESET_DEV request itself, it is completed */\n" " ccb_status = CAM_REQ_CMP;\n" " } else {\n" " calculate_residue(hcb);\n" " ccb_status = CAM_UNEXP_BUSFREE;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = hcb->lun;\n" " }\n" " break;\n" msgstr "" " /* this was the CAM_RESET_DEV request itself, it is completed */" "\n" " ccb_status = CAM_REQ_CMP;\n" " } else {\n" " calculate_residue(hcb);\n" " ccb_status = CAM_UNEXP_BUSFREE;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = hcb->lun;\n" " }\n" " break;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1389 msgid "" "If the target refuses to accept tags we notify CAM about that and return " "back all commands for this LUN:" msgstr "" "Если цель отказывается принимать теги, мы уведомляем CAM об этом и " "возвращаем все команды для этого LUN:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1397 #, no-wrap msgid "" " case TAGS_REJECTED:\n" " /* report the event */\n" " neg.flags = 0 & ~CCB_TRANS_TAG_ENB;\n" " neg.valid = CCB_TRANS_TQ_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" msgstr "" " case TAGS_REJECTED:\n" " /* report the event */\n" " neg.flags = 0 & ~CCB_TRANS_TAG_ENB;\n" " neg.valid = CCB_TRANS_TQ_VALID;\n" " xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1403 #, no-wrap msgid "" " ccb_status = CAM_MSG_REJECT_REC;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = hcb->lun;\n" " break;\n" msgstr "" " ccb_status = CAM_MSG_REJECT_REC;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = hcb->lun;\n" " break;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1406 msgid "" "Then we check a number of other conditions, with processing basically " "limited to setting the CCB status:" msgstr "" "Затем мы проверяем ряд других условий, при этом обработка в основном " "ограничивается установкой статуса CCB:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1430 #, no-wrap msgid "" " case SELECTION_TIMEOUT:\n" " ccb_status = CAM_SEL_TIMEOUT;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = CAM_LUN_WILDCARD;\n" " break;\n" " case PARITY_ERROR:\n" " ccb_status = CAM_UNCOR_PARITY;\n" " break;\n" " case DATA_OVERRUN:\n" " case ODD_WIDE_TRANSFER:\n" " ccb_status = CAM_DATA_RUN_ERR;\n" " break;\n" " default:\n" " /* all other errors are handled in a generic way */\n" " ccb_status = CAM_REQ_CMP_ERR;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = CAM_LUN_WILDCARD;\n" " break;\n" " }\n" msgstr "" " case SELECTION_TIMEOUT:\n" " ccb_status = CAM_SEL_TIMEOUT;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = CAM_LUN_WILDCARD;\n" " break;\n" " case PARITY_ERROR:\n" " ccb_status = CAM_UNCOR_PARITY;\n" " break;\n" " case DATA_OVERRUN:\n" " case ODD_WIDE_TRANSFER:\n" " ccb_status = CAM_DATA_RUN_ERR;\n" " break;\n" " default:\n" " /* all other errors are handled in a generic way */\n" " ccb_status = CAM_REQ_CMP_ERR;\n" " /* request the further code to freeze the queue */\n" " hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN;\n" " lun_to_freeze = CAM_LUN_WILDCARD;\n" " break;\n" " }\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1433 msgid "" "Then we check if the error was serious enough to freeze the input queue " "until it gets proceeded and do so if it is:" msgstr "" "Затем мы проверяем, была ли ошибка достаточно серьёзной, чтобы заморозить " "очередь ввода до её обработки, и если да, то делаем это:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1439 #, no-wrap msgid "" " if (hcb->ccb->ccb_h.status & CAM_DEV_QFRZN) {\n" " /* freeze the queue */\n" " xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);\n" msgstr "" " if (hcb->ccb->ccb_h.status & CAM_DEV_QFRZN) {\n" " /* freeze the queue */\n" " xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1441 #, no-wrap msgid " /* re-queue all commands for this target/LUN back to CAM */\n" msgstr " /* re-queue all commands for this target/LUN back to CAM */\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1444 #, no-wrap msgid "" " for (h = softc->first_queued_hcb; h != NULL; h = hh) {\n" " hh = h->next;\n" msgstr "" " for (h = softc->first_queued_hcb; h != NULL; h = hh) {\n" " hh = h->next;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1453 #, no-wrap msgid "" " if (targ == h->targ\n" " && (lun_to_freeze == CAM_LUN_WILDCARD || lun_to_freeze == h->lun))\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_REQUEUE_REQ);\n" " }\n" " }\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, ccb_status);\n" " schedule_next_hcb(softc);\n" " return;\n" msgstr "" " if (targ == h->targ\n" " && (lun_to_freeze == CAM_LUN_WILDCARD || lun_to_freeze == " "h->lun))\n" " free_hcb_and_ccb_done(h, h->ccb, CAM_REQUEUE_REQ);\n" " }\n" " }\n" " free_hcb_and_ccb_done(hcb, hcb->ccb, ccb_status);\n" " schedule_next_hcb(softc);\n" " return;\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1456 msgid "" "This concludes the generic interrupt handling although specific controllers " "may require some additions." msgstr "" "На этом общее описание обработки прерываний завершается, хотя для некоторых " "контроллеров могут потребоваться дополнительные действия." #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1458 #, no-wrap msgid "Errors Summary" msgstr "Сводка ошибок" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1464 msgid "" "When executing an I/O request many things may go wrong. The reason of error " "can be reported in the CCB status with great detail. Examples of use are " "spread throughout this document. For completeness here is the summary of " "recommended responses for the typical error conditions:" msgstr "" "При выполнении запроса ввода-вывода может произойти множество ошибок. " "Причина ошибки может быть указана в статусе CCB с большим количеством " "деталей. Примеры использования разбросаны по всему документу. Для полноты " "изложения приведём сводку рекомендуемых действий при типичных ошибках:" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1467 msgid "" "_CAM_RESRC_UNAVAIL_ - some resource is temporarily unavailable and the SIM " "driver cannot generate an event when it will become available. An example " "of this resource would be some intra-controller hardware resource for which " "the controller does not generate an interrupt when it becomes available." msgstr "" "_CAM_RESRC_UNAVAIL_ — некоторый ресурс временно недоступен, и драйвер SIM не " "может сгенерировать событие, когда он станет доступен. Примером такого " "ресурса может быть некоторый внутренний аппаратный ресурс контроллера, для " "которого контроллер не генерирует прерывание при его доступности." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1468 msgid "_CAM_UNCOR_PARITY_ - unrecovered parity error occurred" msgstr "_CAM_UNCOR_PARITY_ - произошла неисправимая ошибка чётности" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1469 msgid "" "_CAM_DATA_RUN_ERR_ - data overrun or unexpected data phase (going in other " "direction than specified in CAM_DIR_MASK) or odd transfer length for wide " "transfer" msgstr "" "_CAM_DATA_RUN_ERR_ - переполнение данных или неожиданная фаза данных (" "направление передачи не соответствует указанному в CAM_DIR_MASK) или " "нечётная длина передачи для широкой передачи" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1470 msgid "" "_CAM_SEL_TIMEOUT_ - selection timeout occurred (target does not respond)" msgstr "_CAM_SEL_TIMEOUT_ - произошел таймаут выбора (цель не отвечает)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1471 msgid "_CAM_CMD_TIMEOUT_ - command timeout occurred (the timeout function ran)" msgstr "" "_CAM_CMD_TIMEOUT_ - произошло превышение времени ожидания команды (сработала " "функция таймаута)" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1472 msgid "_CAM_SCSI_STATUS_ERROR_ - the device returned error" msgstr "_CAM_SCSI_STATUS_ERROR_ - устройство вернуло ошибку" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1473 msgid "" "_CAM_AUTOSENSE_FAIL_ - the device returned error and the REQUEST SENSE " "COMMAND failed" msgstr "" "_CAM_AUTOSENSE_FAIL_ - устройство вернуло ошибку и команда REQUEST SENSE " "завершилась неудачно" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1474 msgid "_CAM_MSG_REJECT_REC_ - MESSAGE REJECT message was received" msgstr "_CAM_MSG_REJECT_REC_ - получено сообщение MESSAGE REJECT" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1475 msgid "_CAM_SCSI_BUS_RESET_ - received SCSI bus reset" msgstr "_CAM_SCSI_BUS_RESET_ - получен сброс шины SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1476 msgid "" "_CAM_REQ_CMP_ERR_ - \"impossible\" SCSI phase occurred or something else as " "weird or just a generic error if further detail is not available" msgstr "" "_CAM_REQ_CMP_ERR_ - произошла «невозможная» фаза SCSI или что-то столь же " "странное, либо это просто общая ошибка, если дополнительная информация " "недоступна" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1477 msgid "_CAM_UNEXP_BUSFREE_ - unexpected disconnect occurred" msgstr "_CAM_UNEXP_BUSFREE_ - произошло неожиданное отключение" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1478 msgid "_CAM_BDR_SENT_ - BUS DEVICE RESET message was sent to the target" msgstr "" "_CAM_BDR_SENT_ - Сообщение BUS DEVICE RESET было отправлено целевому " "устройству" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1479 msgid "_CAM_UNREC_HBA_ERROR_ - unrecoverable Host Bus Adapter Error" msgstr "_CAM_UNREC_HBA_ERROR_ - невосстановимая ошибка адаптера шины хоста" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1480 msgid "_CAM_REQ_TOO_BIG_ - the request was too large for this controller" msgstr "_CAM_REQ_TOO_BIG_ - запрос слишком велик для данного контроллера" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1484 msgid "" "_CAM_REQUEUE_REQ_ - this request should be re-queued to preserve transaction " "ordering. This typically occurs when the SIM recognizes an error that " "should freeze the queue and must place other queued requests for the target " "at the sim level back into the XPT queue. Typical cases of such errors are " "selection timeouts, command timeouts and other like conditions. In such " "cases the troublesome command returns the status indicating the error, the " "and the other commands which have not be sent to the bus yet get re-queued." msgstr "" "_CAM_REQUEUE_REQ_ - этот запрос должен быть повторно поставлен в очередь для " "сохранения порядка транзакций. Обычно это происходит, когда SIM обнаруживает " "ошибку, которая должна заморозить очередь, и необходимо поместить другие " "запросы в очереди для цели на уровне SIM обратно в очередь XPT. Типичными " "случаями таких ошибок являются тайм-ауты выбора, тайм-ауты команд и другие " "подобные условия. В таких случаях проблемная команда возвращает статус, " "указывающий на ошибку, а другие команды, которые ещё не были отправлены на " "шину, повторно ставятся в очередь." #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1485 msgid "" "_CAM_LUN_INVALID_ - the LUN ID in the request is not supported by the SCSI " "controller" msgstr "" "_CAM_LUN_INVALID_ - идентификатор LUN в запросе не поддерживается " "контроллером SCSI" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1486 msgid "" "_CAM_TID_INVALID_ - the target ID in the request is not supported by the " "SCSI controller" msgstr "" "_CAM_TID_INVALID_ - идентификатор целевого устройства в запросе не " "поддерживается контроллером SCSI" #. type: Title == #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1488 #, no-wrap msgid "Timeout Handling" msgstr "Обработка таймаутов" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1496 msgid "" "When the timeout for an HCB expires that request should be aborted, just " "like with an XPT_ABORT request. The only difference is that the returned " "status of aborted request should be CAM_CMD_TIMEOUT instead of " "CAM_REQ_ABORTED (that is why implementation of the abort better be done as a " "function). But there is one more possible problem: what if the abort " "request itself will get stuck? In this case the SCSI bus should be reset, " "just like with an XPT_RESET_BUS request (and the idea about implementing it " "as a function called from both places applies here too). Also we should " "reset the whole SCSI bus if a device reset request got stuck. So after all " "the timeout function would look like:" msgstr "" "Когда время ожидания для HCB истекает, этот запрос должен быть прерван, как " "и в случае с запросом XPT_ABORT. Единственное отличие заключается в том, что " "возвращаемый статус прерванного запроса должен быть CAM_CMD_TIMEOUT вместо " "CAM_REQ_ABORTED (вот почему реализацию прерывания лучше сделать в виде " "функции). Но есть ещё одна возможная проблема: что если сам запрос на " "прерывание зависнет? В этом случае шина SCSI должна быть сброшена, как и при " "запросе XPT_RESET_BUS (и идея о реализации этого в виде функции, вызываемой " "из обоих мест, применима и здесь). Также мы должны сбросить всю шину SCSI, " "если запрос на сброс устройства завис. В итоге функция обработки таймаута " "будет выглядеть следующим образом:" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1505 #, no-wrap msgid "" "static void\n" "xxx_timeout(void *arg)\n" "{\n" " struct xxx_hcb *hcb = (struct xxx_hcb *)arg;\n" " struct xxx_softc *softc;\n" " struct ccb_hdr *ccb_h;\n" msgstr "" "static void\n" "xxx_timeout(void *arg)\n" "{\n" " struct xxx_hcb *hcb = (struct xxx_hcb *)arg;\n" " struct xxx_softc *softc;\n" " struct ccb_hdr *ccb_h;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1508 #, no-wrap msgid "" " softc = hcb->softc;\n" " ccb_h = &hcb->ccb->ccb_h;\n" msgstr "" " softc = hcb->softc;\n" " ccb_h = &hcb->ccb->ccb_h;\n" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1515 #, no-wrap msgid "" " if (hcb->flags & HCB_BEING_ABORTED || ccb_h->func_code == XPT_RESET_DEV) {\n" " xxx_reset_bus(softc);\n" " } else {\n" " xxx_abort_ccb(hcb->ccb, CAM_CMD_TIMEOUT);\n" " }\n" "}\n" msgstr "" " if (hcb->flags & HCB_BEING_ABORTED || ccb_h->func_code == XPT_RESET_DEV) " "{\n" " xxx_reset_bus(softc);\n" " } else {\n" " xxx_abort_ccb(hcb->ccb, CAM_CMD_TIMEOUT);\n" " }\n" "}\n" #. type: Plain text #: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1520 msgid "" "When we abort a request all the other disconnected requests to the same " "target/LUN get aborted too. So there appears a question, should we return " "them with status CAM_REQ_ABORTED or CAM_CMD_TIMEOUT? The current drivers use " "CAM_CMD_TIMEOUT. This seems logical because if one request got timed out " "then probably something really bad is happening to the device, so if they " "would not be disturbed they would time out by themselves." msgstr "" "Когда мы прерываем запрос, все остальные отключенные запросы к тому же " "целевому устройству/LUN также прерываются. Возникает вопрос: следует ли " "возвращать их со статусом CAM_REQ_ABORTED или CAM_CMD_TIMEOUT? Текущие " "драйверы используют CAM_CMD_TIMEOUT. Это кажется логичным, потому что если " "один запрос превысил время ожидания, то, вероятно, с устройством происходит " "что-то действительно плохое, и если их не трогать, они бы сами превысили " "время ожидания."