# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR The FreeBSD Project # This file is distributed under the same license as the FreeBSD Documentation package. # FIRST AUTHOR , 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 \n" "Language-Team: LANGUAGE \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 \n" "#include \n" "#include \n" "#include \n" "#include \n" "#include \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 ""