Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-doc
Path: blob/main/documentation/content/en/books/arch-handbook/scsi/_index.po
18099 views
# SOME DESCRIPTIVE TITLE
# Copyright (C) YEAR The FreeBSD Project
# This file is distributed under the same license as the FreeBSD Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: FreeBSD Documentation VERSION\n"
"POT-Creation-Date: 2025-05-01 19:56-0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:100
#, no-wrap
msgid ""
"#include <cam/cam.h>\n"
"#include <cam/cam_ccb.h>\n"
"#include <cam/cam_sim.h>\n"
"#include <cam/cam_xpt_sim.h>\n"
"#include <cam/cam_debug.h>\n"
"#include <cam/scsi/scsi_all.h>\n"
msgstr ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:102
#, no-wrap
msgid "Device configuration: xxx_attach"
msgstr ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:113
#, no-wrap
msgid "    struct cam_devq *devq;\n"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:129
msgid "Next we create a descriptor of our SIM:"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:133
#, no-wrap
msgid "    struct cam_sim *sim;\n"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:158
msgid "`poll_func` - pointer to the driver's `xxx_poll()`"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:228
msgid "ID of the SIM driver (`cam_sim_path(sim)`)"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:247
#, no-wrap
msgid "    struct ccb_setasync csa;\n"
msgstr ""

#. 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 ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:256
#, no-wrap
msgid "Processing CAM messages: xxx_action"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:275
msgid "`cam_sim_path(sim)` - the path ID (see above)"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:276
msgid "`cam_sim_name(sim)` - the name of the sim"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:278
msgid "`cam_sim_unit(sim)` - the unit number"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:279
msgid "`cam_sim_bus(sim)` - the bus ID"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:325
msgid "_CAM_QOS_VALID_ - The QOS data is now valid."
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:330
msgid "The CCB header contains the following fields:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:332
msgid "_path_ - path ID for the request"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:333
msgid "_target_id_ - target device ID for the request"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:334
msgid "_target_lun_ - LUN ID of the target device"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:335
msgid "_timeout_ - timeout interval for this command, in milliseconds"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:355
msgid "_cdb_len_ - SCSI command length"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:357
msgid "_dxfer_len_ - length of the data to transfer"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:358
msgid "_sglist_cnt_ - counter of the scatter/gather segments"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:359
msgid "_scsi_status_ - place to return the SCSI status"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:365
msgid "_tag_action_ - the kind of tag to use:"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:486
#, no-wrap
msgid "    int rv;\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:488
#, no-wrap
msgid "    initialize_hcb_for_data(hcb);\n"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Title ===
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:651
#, no-wrap
msgid "_XPT_ABORT_ - abort the specified CCB"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:657
msgid "_abort_ccb_ - pointer to the CCB to be aborted"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:682
#, no-wrap
msgid "    struct xxx_hcb *hcb, *h;\n"
msgstr ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:684
#, no-wrap
msgid "    hcb = NULL;\n"
msgstr ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:704
#, no-wrap
msgid "    hcb=found_hcb;\n"
msgstr ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:713
#, no-wrap
msgid "    int hstatus;\n"
msgstr ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:720
#, no-wrap
msgid "    abort_again:\n"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:755
#, no-wrap
msgid "        break;\n"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:808
msgid "_valid_ - a bitmask showing which settings should be updated:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:809
msgid "_CCB_TRANS_SYNC_RATE_VALID_ - synchronous transfer rate"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:810
msgid "_CCB_TRANS_SYNC_OFFSET_VALID_ - synchronous offset"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:811
msgid "_CCB_TRANS_BUS_WIDTH_VALID_ - bus width"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:812
msgid "_CCB_TRANS_DISC_VALID_ - set enable/disable disconnection"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:813
msgid "_CCB_TRANS_TQ_VALID_ - set enable/disable tagged queuing"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:816
msgid "_CCB_TRANS_DISC_ENB_ - enable disconnection"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:817
msgid "_CCB_TRANS_TAG_ENB_ - enable tagged queuing"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:836
msgid "_user_ - the user set, as above"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:837
msgid "_current_ - those actually in effect"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:838
msgid "_goal_ - those requested by setting of the \"current\" parameters"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:927
msgid "_volume_size_ - input, volume size in bytes"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:928
msgid "_cylinders_ - output, logical cylinders"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:929
msgid "_heads_ - output, logical heads"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:930
msgid "_secs_per_track_ - output, logical sectors per track"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:978
msgid "hba_inquiry - bitmask of features supported by the controller:"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:979
msgid "PI_MDP_ABLE - supports MDP message (something from SCSI3?)"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:980
msgid "PI_WIDE_32 - supports 32 bit wide SCSI"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:981
msgid "PI_WIDE_16 - supports 16 bit wide SCSI"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:982
msgid "PI_SDTR_ABLE - can negotiate synchronous transfer rate"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:983
msgid "PI_LINKED_CDB - supports linked commands"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:984
msgid "PI_TAG_ABLE - supports tagged commands"
msgstr ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:987
msgid "hba_misc - miscellaneous controller features:"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:989
msgid "PIM_NOREMOVE - removable devices not included in scan"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:990
msgid "PIM_NOINITIATOR - initiator role not supported"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:991
msgid "PIM_NOBUSRESET - user has disabled initial BUS RESET"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:993
msgid "vuhba_flags - vendor-unique flags, unused now"
msgstr ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:996
msgid "async_flags - bitmask of installed Async handler, unused now"
msgstr ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:999
msgid "bus_id - the bus number, cam_sim_bus(sim)"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1000
msgid "initiator_id - the SCSI ID of the controller itself"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Title ==
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1015
#, no-wrap
msgid "Polling xxx_poll"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1062
msgid "callback_arg - the value supplied when registering the callback"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1063
msgid "code - identifies the type of event"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1064
msgid "path - identifies the devices to which the event applies"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1065
msgid "arg - event-specific argument"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: delimited block . 4
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1341
#, no-wrap
msgid "    switch (hcb_status) {\n"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1468
msgid "_CAM_UNCOR_PARITY_ - unrecovered parity error occurred"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1472
msgid "_CAM_SCSI_STATUS_ERROR_ - the device returned error"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1474
msgid "_CAM_MSG_REJECT_REC_ - MESSAGE REJECT message was received"
msgstr ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1475
msgid "_CAM_SCSI_BUS_RESET_ - received SCSI bus reset"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1477
msgid "_CAM_UNEXP_BUSFREE_ - unexpected disconnect occurred"
msgstr ""

#. 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 ""

#. type: Plain text
#: documentation/content/en/books/arch-handbook/scsi/_index.adoc:1479
msgid "_CAM_UNREC_HBA_ERROR_ - unrecoverable Host Bus Adapter Error"
msgstr ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""

#. 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 ""