diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /Documentation/scsi/scsi_mid_low_api.txt | |
download | kernel_samsung_tuna-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.zip kernel_samsung_tuna-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.gz kernel_samsung_tuna-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.bz2 |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'Documentation/scsi/scsi_mid_low_api.txt')
-rw-r--r-- | Documentation/scsi/scsi_mid_low_api.txt | 1546 |
1 files changed, 1546 insertions, 0 deletions
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt new file mode 100644 index 0000000..1f24129 --- /dev/null +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -0,0 +1,1546 @@ + Linux Kernel 2.6 series + SCSI mid_level - lower_level driver interface + ============================================= + +Introduction +============ +This document outlines the interface between the Linux SCSI mid level and +SCSI lower level drivers. Lower level drivers (LLDs) are variously called +host bus adapter (HBA) drivers and host drivers (HD). A "host" in this +context is a bridge between a computer IO bus (e.g. PCI or ISA) and a +single SCSI initiator port on a SCSI transport. An "initiator" port +(SCSI terminology, see SAM-3 at http://www.t10.org) sends SCSI commands +to "target" SCSI ports (e.g. disks). There can be many LLDs in a running +system, but only one per hardware type. Most LLDs can control one or more +SCSI HBAs. Some HBAs contain multiple hosts. + +In some cases the SCSI transport is an external bus that already has +its own subsystem in Linux (e.g. USB and ieee1394). In such cases the +SCSI subsystem LLD is a software bridge to the other driver subsystem. +Examples are the usb-storage driver (found in the drivers/usb/storage +directory) and the ieee1394/sbp2 driver (found in the drivers/ieee1394 +directory). + +For example, the aic7xxx LLD controls Adaptec SCSI parallel interface +(SPI) controllers based on that company's 7xxx chip series. The aic7xxx +LLD can be built into the kernel or loaded as a module. There can only be +one aic7xxx LLD running in a Linux system but it may be controlling many +HBAs. These HBAs might be either on PCI daughter-boards or built into +the motherboard (or both). Some aic7xxx based HBAs are dual controllers +and thus represent two hosts. Like most modern HBAs, each aic7xxx host +has its own PCI device address. [The one-to-one correspondence between +a SCSI host and a PCI device is common but not required (e.g. with +ISA or MCA adapters).] + +The SCSI mid level isolates an LLD from other layers such as the SCSI +upper layer drivers and the block layer. + +This version of the document roughly matches linux kernel version 2.6.8 . + +Documentation +============= +There is a SCSI documentation directory within the kernel source tree, +typically Documentation/scsi . Most documents are in plain +(i.e. ASCII) text. This file is named scsi_mid_low_api.txt and can be +found in that directory. A more recent copy of this document may be found +at http://www.torque.net/scsi/scsi_mid_low_api.txt.gz . +Many LLDs are documented there (e.g. aic7xxx.txt). The SCSI mid-level is +briefly described in scsi.txt which contains a url to a document +describing the SCSI subsystem in the lk 2.4 series. Two upper level +drivers have documents in that directory: st.txt (SCSI tape driver) and +scsi-generic.txt (for the sg driver). + +Some documentation (or urls) for LLDs may be found in the C source code +or in the same directory as the C source code. For example to find a url +about the USB mass storage driver see the +/usr/src/linux/drivers/usb/storage directory. + +The Linux kernel source Documentation/DocBook/scsidrivers.tmpl file +refers to this file. With the appropriate DocBook tool-set, this permits +users to generate html, ps and pdf renderings of information within this +file (e.g. the interface functions). + +Driver structure +================ +Traditionally an LLD for the SCSI subsystem has been at least two files in +the drivers/scsi directory. For example, a driver called "xyz" has a header +file "xyz.h" and a source file "xyz.c". [Actually there is no good reason +why this couldn't all be in one file; the header file is superfluous.] Some +drivers that have been ported to several operating systems have more than +two files. For example the aic7xxx driver has separate files for generic +and OS-specific code (e.g. FreeBSD and Linux). Such drivers tend to have +their own directory under the drivers/scsi directory. + +When a new LLD is being added to Linux, the following files (found in the +drivers/scsi directory) will need some attention: Makefile and Kconfig . +It is probably best to study how existing LLDs are organized. + +As the 2.5 series development kernels evolve into the 2.6 series +production series, changes are being introduced into this interface. An +example of this is driver initialization code where there are now 2 models +available. The older one, similar to what was found in the lk 2.4 series, +is based on hosts that are detected at HBA driver load time. This will be +referred to the "passive" initialization model. The newer model allows HBAs +to be hot plugged (and unplugged) during the lifetime of the LLD and will +be referred to as the "hotplug" initialization model. The newer model is +preferred as it can handle both traditional SCSI equipment that is +permanently connected as well as modern "SCSI" devices (e.g. USB or +IEEE 1394 connected digital cameras) that are hotplugged. Both +initialization models are discussed in the following sections. + +An LLD interfaces to the SCSI subsystem several ways: + a) directly invoking functions supplied by the mid level + b) passing a set of function pointers to a registration function + supplied by the mid level. The mid level will then invoke these + functions at some point in the future. The LLD will supply + implementations of these functions. + c) direct access to instances of well known data structures maintained + by the mid level + +Those functions in group a) are listed in a section entitled "Mid level +supplied functions" below. + +Those functions in group b) are listed in a section entitled "Interface +functions" below. Their function pointers are placed in the members of +"struct scsi_host_template", an instance of which is passed to +scsi_host_alloc() ** . Those interface functions that the LLD does not +wish to supply should have NULL placed in the corresponding member of +struct scsi_host_template. Defining an instance of struct +scsi_host_template at file scope will cause NULL to be placed in function + pointer members not explicitly initialized. + +Those usages in group c) should be handled with care, especially in a +"hotplug" environment. LLDs should be aware of the lifetime of instances +that are shared with the mid level and other layers. + +All functions defined within an LLD and all data defined at file scope +should be static. For example the slave_alloc() function in an LLD +called "xxx" could be defined as +"static int xxx_slave_alloc(struct scsi_device * sdev) { /* code */ }" + +** the scsi_host_alloc() function is a replacement for the rather vaguely +named scsi_register() function in most situations. The scsi_register() +and scsi_unregister() functions remain to support legacy LLDs that use +the passive initialization model. + + +Hotplug initialization model +============================ +In this model an LLD controls when SCSI hosts are introduced and removed +from the SCSI subsystem. Hosts can be introduced as early as driver +initialization and removed as late as driver shutdown. Typically a driver +will respond to a sysfs probe() callback that indicates an HBA has been +detected. After confirming that the new device is one that the LLD wants +to control, the LLD will initialize the HBA and then register a new host +with the SCSI mid level. + +During LLD initialization the driver should register itself with the +appropriate IO bus on which it expects to find HBA(s) (e.g. the PCI bus). +This can probably be done via sysfs. Any driver parameters (especially +those that are writable after the driver is loaded) could also be +registered with sysfs at this point. The SCSI mid level first becomes +aware of an LLD when that LLD registers its first HBA. + +At some later time, the LLD becomes aware of an HBA and what follows +is a typical sequence of calls between the LLD and the mid level. +This example shows the mid level scanning the newly introduced HBA for 3 +scsi devices of which only the first 2 respond: + + HBA PROBE: assume 2 SCSI devices found in scan +LLD mid level LLD +===-------------------=========--------------------===------ +scsi_host_alloc() --> +scsi_add_host() --------+ + | + slave_alloc() + slave_configure() --> scsi_adjust_queue_depth() + | + slave_alloc() + slave_configure() + | + slave_alloc() *** + slave_destroy() *** +------------------------------------------------------------ + +If the LLD wants to adjust the default queue settings, it can invoke +scsi_adjust_queue_depth() in its slave_configure() routine. + +*** For scsi devices that the mid level tries to scan but do not + respond, a slave_alloc(), slave_destroy() pair is called. + +When an HBA is being removed it could be as part of an orderly shutdown +associated with the LLD module being unloaded (e.g. with the "rmmod" +command) or in response to a "hot unplug" indicated by sysfs()'s +remove() callback being invoked. In either case, the sequence is the +same: + + HBA REMOVE: assume 2 SCSI devices attached +LLD mid level LLD +===----------------------=========-----------------===------ +scsi_remove_host() ---------+ + | + slave_destroy() + slave_destroy() +scsi_host_put() +------------------------------------------------------------ + +It may be useful for a LLD to keep track of struct Scsi_Host instances +(a pointer is returned by scsi_host_alloc()). Such instances are "owned" +by the mid-level. struct Scsi_Host instances are freed from +scsi_host_put() when the reference count hits zero. + +Hot unplugging an HBA that controls a disk which is processing SCSI +commands on a mounted file system is an interesting situation. Reference +counting logic is being introduced into the mid level to cope with many +of the issues involved. See the section on reference counting below. + + +The hotplug concept may be extended to SCSI devices. Currently, when an +HBA is added, the scsi_add_host() function causes a scan for SCSI devices +attached to the HBA's SCSI transport. On newer SCSI transports the HBA +may become aware of a new SCSI device _after_ the scan has completed. +An LLD can use this sequence to make the mid level aware of a SCSI device: + + SCSI DEVICE hotplug +LLD mid level LLD +===-------------------=========--------------------===------ +scsi_add_device() ------+ + | + slave_alloc() + slave_configure() [--> scsi_adjust_queue_depth()] +------------------------------------------------------------ + +In a similar fashion, an LLD may become aware that a SCSI device has been +removed (unplugged) or the connection to it has been interrupted. Some +existing SCSI transports (e.g. SPI) may not become aware that a SCSI +device has been removed until a subsequent SCSI command fails which will +probably cause that device to be set offline by the mid level. An LLD that +detects the removal of a SCSI device can instigate its removal from +upper layers with this sequence: + + SCSI DEVICE hot unplug +LLD mid level LLD +===----------------------=========-----------------===------ +scsi_remove_device() -------+ + | + slave_destroy() +------------------------------------------------------------ + +It may be useful for an LLD to keep track of struct scsi_device instances +(a pointer is passed as the parameter to slave_alloc() and +slave_configure() callbacks). Such instances are "owned" by the mid-level. +struct scsi_device instances are freed after slave_destroy(). + + +Passive initialization model +============================ +These older LLDs include a file called "scsi_module.c" [yes the ".c" is a +little surprising] in their source code. For that file to work an +instance of struct scsi_host_template with the name "driver_template" +needs to be defined. Here is a typical code sequence used in this model: + static struct scsi_host_template driver_template = { + ... + }; + #include "scsi_module.c" + +The scsi_module.c file contains two functions: + - init_this_scsi_driver() which is executed when the LLD is + initialized (i.e. boot time or module load time) + - exit_this_scsi_driver() which is executed when the LLD is shut + down (i.e. module unload time) +Note: since these functions are tagged with __init and __exit qualifiers +an LLD should not call them explicitly (since the kernel does that). + +Here is an example of an initialization sequence when two hosts are +detected (so detect() returns 2) and the SCSI bus scan on each host +finds 1 SCSI device (and a second device does not respond). + +LLD mid level LLD +===----------------------=========-----------------===------ +init_this_scsi_driver() ----+ + | + detect() -----------------+ + | | + | scsi_register() + | scsi_register() + | + slave_alloc() + slave_configure() --> scsi_adjust_queue_depth() + slave_alloc() *** + slave_destroy() *** + | + slave_alloc() + slave_configure() + slave_alloc() *** + slave_destroy() *** +------------------------------------------------------------ + +The mid level invokes scsi_adjust_queue_depth() with tagged queuing off and +"cmd_per_lun" for that host as the queue length. These settings can be +overridden by a slave_configure() supplied by the LLD. + +*** For scsi devices that the mid level tries to scan but do not + respond, a slave_alloc(), slave_destroy() pair is called. + +Here is an LLD shutdown sequence: + +LLD mid level LLD +===----------------------=========-----------------===------ +exit_this_scsi_driver() ----+ + | + slave_destroy() + release() --> scsi_unregister() + | + slave_destroy() + release() --> scsi_unregister() +------------------------------------------------------------ + +An LLD need not define slave_destroy() (i.e. it is optional). + +The shortcoming of the "passive initialization model" is that host +registration and de-registration are (typically) tied to LLD initialization +and shutdown. Once the LLD is initialized then a new host that appears +(e.g. via hotplugging) cannot easily be added without a redundant +driver shutdown and re-initialization. It may be possible to write an LLD +that uses both initialization models. + + +Reference Counting +================== +The Scsi_Host structure has had reference counting infrastructure added. +This effectively spreads the ownership of struct Scsi_Host instances +across the various SCSI layers which use them. Previously such instances +were exclusively owned by the mid level. LLDs would not usually need to +directly manipulate these reference counts but there may be some cases +where they do. + +There are 3 reference counting functions of interest associated with +struct Scsi_Host: + - scsi_host_alloc(): returns a pointer to new instance of struct + Scsi_Host which has its reference count ^^ set to 1 + - scsi_host_get(): adds 1 to the reference count of the given instance + - scsi_host_put(): decrements 1 from the reference count of the given + instance. If the reference count reaches 0 then the given instance + is freed + +The Scsi_device structure has had reference counting infrastructure added. +This effectively spreads the ownership of struct Scsi_device instances +across the various SCSI layers which use them. Previously such instances +were exclusively owned by the mid level. See the access functions declared +towards the end of include/scsi/scsi_device.h . If an LLD wants to keep +a copy of a pointer to a Scsi_device instance it should use scsi_device_get() +to bump its reference count. When it is finished with the pointer it can +use scsi_device_put() to decrement its reference count (and potentially +delete it). + +^^ struct Scsi_Host actually has 2 reference counts which are manipulated +in parallel by these functions. + + +Conventions +=========== +First, Linus Torvalds's thoughts on C coding style can be found in the +Documentation/CodingStyle file. + +Next, there is a movement to "outlaw" typedefs introducing synonyms for +struct tags. Both can be still found in the SCSI subsystem, but +the typedefs have been moved to a single file, scsi_typedefs.h to +make their future removal easier, for example: +"typedef struct scsi_host_template Scsi_Host_Template;" + +Also, most C99 enhancements are encouraged to the extent they are supported +by the relevant gcc compilers. So C99 style structure and array +initializers are encouraged where appropriate. Don't go too far, +VLAs are not properly supported yet. An exception to this is the use of +"//" style comments; /*...*/ comments are still preferred in Linux. + +Well written, tested and documented code, need not be re-formatted to +comply with the above conventions. For example, the aic7xxx driver +comes to Linux from FreeBSD and Adaptec's own labs. No doubt FreeBSD +and Adaptec have their own coding conventions. + + +Mid level supplied functions +============================ +These functions are supplied by the SCSI mid level for use by LLDs. +The names (i.e. entry points) of these functions are exported +so an LLD that is a module can access them. The kernel will +arrange for the SCSI mid level to be loaded and initialized before any LLD +is initialized. The functions below are listed alphabetically and their +names all start with "scsi_". + +Summary: + scsi_activate_tcq - turn on tag command queueing + scsi_add_device - creates new scsi device (lu) instance + scsi_add_host - perform sysfs registration and SCSI bus scan. + scsi_add_timer - (re-)start timer on a SCSI command. + scsi_adjust_queue_depth - change the queue depth on a SCSI device + scsi_assign_lock - replace default host_lock with given lock + scsi_bios_ptable - return copy of block device's partition table + scsi_block_requests - prevent further commands being queued to given host + scsi_deactivate_tcq - turn off tag command queueing + scsi_delete_timer - cancel timer on a SCSI command. + scsi_host_alloc - return a new scsi_host instance whose refcount==1 + scsi_host_get - increments Scsi_Host instance's refcount + scsi_host_put - decrements Scsi_Host instance's refcount (free if 0) + scsi_partsize - parse partition table into cylinders, heads + sectors + scsi_register - create and register a scsi host adapter instance. + scsi_remove_device - detach and remove a SCSI device + scsi_remove_host - detach and remove all SCSI devices owned by host + scsi_report_bus_reset - report scsi _bus_ reset observed + scsi_set_device - place device reference in host structure + scsi_to_pci_dma_dir - convert SCSI subsystem direction flag to PCI + scsi_to_sbus_dma_dir - convert SCSI subsystem direction flag to SBUS + scsi_track_queue_full - track successive QUEUE_FULL events + scsi_unblock_requests - allow further commands to be queued to given host + scsi_unregister - [calls scsi_host_put()] + + +Details: + +/** + * scsi_activate_tcq - turn on tag command queueing ("ordered" task attribute) + * @sdev: device to turn on TCQ for + * @depth: queue depth + * + * Returns nothing + * + * Might block: no + * + * Notes: Eventually, it is hoped depth would be the maximum depth + * the device could cope with and the real queue depth + * would be adjustable from 0 to depth. + * + * Defined (inline) in: include/scsi/scsi_tcq.h + **/ +void scsi_activate_tcq(struct scsi_device *sdev, int depth) + + +/** + * scsi_add_device - creates new scsi device (lu) instance + * @shost: pointer to scsi host instance + * @channel: channel number (rarely other than 0) + * @id: target id number + * @lun: logical unit number + * + * Returns pointer to new struct scsi_device instance or + * ERR_PTR(-ENODEV) (or some other bent pointer) if something is + * wrong (e.g. no lu responds at given address) + * + * Might block: yes + * + * Notes: This call is usually performed internally during a scsi + * bus scan when an HBA is added (i.e. scsi_add_host()). So it + * should only be called if the HBA becomes aware of a new scsi + * device (lu) after scsi_add_host() has completed. If successful + * this call we lead to slave_alloc() and slave_configure() callbacks + * into the LLD. + * + * Defined in: drivers/scsi/scsi_scan.c + **/ +struct scsi_device * scsi_add_device(struct Scsi_Host *shost, + unsigned int channel, + unsigned int id, unsigned int lun) + + +/** + * scsi_add_host - perform sysfs registration and SCSI bus scan. + * @shost: pointer to scsi host instance + * @dev: pointer to struct device of type scsi class + * + * Returns 0 on success, negative errno of failure (e.g. -ENOMEM) + * + * Might block: no + * + * Notes: Only required in "hotplug initialization model" after a + * successful call to scsi_host_alloc(). + * + * Defined in: drivers/scsi/hosts.c + **/ +int scsi_add_host(struct Scsi_Host *shost, struct device * dev) + + +/** + * scsi_add_timer - (re-)start timer on a SCSI command. + * @scmd: pointer to scsi command instance + * @timeout: duration of timeout in "jiffies" + * @complete: pointer to function to call if timeout expires + * + * Returns nothing + * + * Might block: no + * + * Notes: Each scsi command has its own timer, and as it is added + * to the queue, we set up the timer. When the command completes, + * we cancel the timer. An LLD can use this function to change + * the existing timeout value. + * + * Defined in: drivers/scsi/scsi_error.c + **/ +void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, + void (*complete)(struct scsi_cmnd *)) + + +/** + * scsi_adjust_queue_depth - allow LLD to change queue depth on a SCSI device + * @sdev: pointer to SCSI device to change queue depth on + * @tagged: 0 - no tagged queuing + * MSG_SIMPLE_TAG - simple tagged queuing + * MSG_ORDERED_TAG - ordered tagged queuing + * @tags Number of tags allowed if tagged queuing enabled, + * or number of commands the LLD can queue up + * in non-tagged mode (as per cmd_per_lun). + * + * Returns nothing + * + * Might block: no + * + * Notes: Can be invoked any time on a SCSI device controlled by this + * LLD. [Specifically during and after slave_configure() and prior to + * slave_destroy().] Can safely be invoked from interrupt code. Actual + * queue depth change may be delayed until the next command is being + * processed. See also scsi_activate_tcq() and scsi_deactivate_tcq(). + * + * Defined in: drivers/scsi/scsi.c [see source code for more notes] + * + **/ +void scsi_adjust_queue_depth(struct scsi_device * sdev, int tagged, + int tags) + + +/** + * scsi_assign_lock - replace default host_lock with given lock + * @shost: a pointer to a scsi host instance + * @lock: pointer to lock to replace host_lock for this host + * + * Returns nothing + * + * Might block: no + * + * Defined in: include/scsi/scsi_host.h . + **/ +void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) + + +/** + * scsi_bios_ptable - return copy of block device's partition table + * @dev: pointer to block device + * + * Returns pointer to partition table, or NULL for failure + * + * Might block: yes + * + * Notes: Caller owns memory returned (free with kfree() ) + * + * Defined in: drivers/scsi/scsicam.c + **/ +unsigned char *scsi_bios_ptable(struct block_device *dev) + + +/** + * scsi_block_requests - prevent further commands being queued to given host + * + * @shost: pointer to host to block commands on + * + * Returns nothing + * + * Might block: no + * + * Notes: There is no timer nor any other means by which the requests + * get unblocked other than the LLD calling scsi_unblock_requests(). + * + * Defined in: drivers/scsi/scsi_lib.c +**/ +void scsi_block_requests(struct Scsi_Host * shost) + + +/** + * scsi_deactivate_tcq - turn off tag command queueing + * @sdev: device to turn off TCQ for + * @depth: queue depth (stored in sdev) + * + * Returns nothing + * + * Might block: no + * + * Defined (inline) in: include/scsi/scsi_tcq.h + **/ +void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) + + +/** + * scsi_delete_timer - cancel timer on a SCSI command. + * @scmd: pointer to scsi command instance + * + * Returns 1 if able to cancel timer else 0 (i.e. too late or already + * cancelled). + * + * Might block: no [may in the future if it invokes del_timer_sync()] + * + * Notes: All commands issued by upper levels already have a timeout + * associated with them. An LLD can use this function to cancel the + * timer. + * + * Defined in: drivers/scsi/scsi_error.c + **/ +int scsi_delete_timer(struct scsi_cmnd *scmd) + + +/** + * scsi_host_alloc - create a scsi host adapter instance and perform basic + * initialization. + * @sht: pointer to scsi host template + * @privsize: extra bytes to allocate in hostdata array (which is the + * last member of the returned Scsi_Host instance) + * + * Returns pointer to new Scsi_Host instance or NULL on failure + * + * Might block: yes + * + * Notes: When this call returns to the LLD, the SCSI bus scan on + * this host has _not_ yet been done. + * The hostdata array (by default zero length) is a per host scratch + * area for the LLD's exclusive use. + * Both associated refcounting objects have their refcount set to 1. + * Full registration (in sysfs) and a bus scan are performed later when + * scsi_add_host() is called. + * + * Defined in: drivers/scsi/hosts.c . + **/ +struct Scsi_Host * scsi_host_alloc(struct scsi_host_template * sht, + int privsize) + + +/** + * scsi_host_get - increment Scsi_Host instance refcount + * @shost: pointer to struct Scsi_Host instance + * + * Returns nothing + * + * Might block: currently may block but may be changed to not block + * + * Notes: Actually increments the counts in two sub-objects + * + * Defined in: drivers/scsi/hosts.c + **/ +void scsi_host_get(struct Scsi_Host *shost) + + +/** + * scsi_host_put - decrement Scsi_Host instance refcount, free if 0 + * @shost: pointer to struct Scsi_Host instance + * + * Returns nothing + * + * Might block: currently may block but may be changed to not block + * + * Notes: Actually decrements the counts in two sub-objects. If the + * latter refcount reaches 0, the Scsi_Host instance is freed. + * The LLD need not worry exactly when the Scsi_Host instance is + * freed, it just shouldn't access the instance after it has balanced + * out its refcount usage. + * + * Defined in: drivers/scsi/hosts.c + **/ +void scsi_host_put(struct Scsi_Host *shost) + + +/** + * scsi_partsize - parse partition table into cylinders, heads + sectors + * @buf: pointer to partition table + * @capacity: size of (total) disk in 512 byte sectors + * @cyls: outputs number of cylinders calculated via this pointer + * @hds: outputs number of heads calculated via this pointer + * @secs: outputs number of sectors calculated via this pointer + * + * Returns 0 on success, -1 on failure + * + * Might block: no + * + * Notes: Caller owns memory returned (free with kfree() ) + * + * Defined in: drivers/scsi/scsicam.c + **/ +int scsi_partsize(unsigned char *buf, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, unsigned int *secs) + + +/** + * scsi_register - create and register a scsi host adapter instance. + * @sht: pointer to scsi host template + * @privsize: extra bytes to allocate in hostdata array (which is the + * last member of the returned Scsi_Host instance) + * + * Returns pointer to new Scsi_Host instance or NULL on failure + * + * Might block: yes + * + * Notes: When this call returns to the LLD, the SCSI bus scan on + * this host has _not_ yet been done. + * The hostdata array (by default zero length) is a per host scratch + * area for the LLD. + * + * Defined in: drivers/scsi/hosts.c . + **/ +struct Scsi_Host * scsi_register(struct scsi_host_template * sht, + int privsize) + + +/** + * scsi_remove_device - detach and remove a SCSI device + * @sdev: a pointer to a scsi device instance + * + * Returns value: 0 on success, -EINVAL if device not attached + * + * Might block: yes + * + * Notes: If an LLD becomes aware that a scsi device (lu) has + * been removed but its host is still present then it can request + * the removal of that scsi device. If successful this call will + * lead to the slave_destroy() callback being invoked. sdev is an + * invalid pointer after this call. + * + * Defined in: drivers/scsi/scsi_sysfs.c . + **/ +int scsi_remove_device(struct scsi_device *sdev) + + +/** + * scsi_remove_host - detach and remove all SCSI devices owned by host + * @shost: a pointer to a scsi host instance + * + * Returns value: 0 on success, 1 on failure (e.g. LLD busy ??) + * + * Might block: yes + * + * Notes: Should only be invoked if the "hotplug initialization + * model" is being used. It should be called _prior_ to + * scsi_unregister(). + * + * Defined in: drivers/scsi/hosts.c . + **/ +int scsi_remove_host(struct Scsi_Host *shost) + + +/** + * scsi_report_bus_reset - report scsi _bus_ reset observed + * @shost: a pointer to a scsi host involved + * @channel: channel (within) host on which scsi bus reset occurred + * + * Returns nothing + * + * Might block: no + * + * Notes: This only needs to be called if the reset is one which + * originates from an unknown location. Resets originated by the + * mid level itself don't need to call this, but there should be + * no harm. The main purpose of this is to make sure that a + * CHECK_CONDITION is properly treated. + * + * Defined in: drivers/scsi/scsi_error.c . + **/ +void scsi_report_bus_reset(struct Scsi_Host * shost, int channel) + + +/** + * scsi_set_device - place device reference in host structure + * @shost: a pointer to a scsi host instance + * @pdev: pointer to device instance to assign + * + * Returns nothing + * + * Might block: no + * + * Defined in: include/scsi/scsi_host.h . + **/ +void scsi_set_device(struct Scsi_Host * shost, struct device * dev) + + +/** + * scsi_to_pci_dma_dir - convert SCSI subsystem direction flag to PCI + * @scsi_data_direction: SCSI subsystem direction flag + * + * Returns DMA_TO_DEVICE given SCSI_DATA_WRITE, + * DMA_FROM_DEVICE given SCSI_DATA_READ + * DMA_BIDIRECTIONAL given SCSI_DATA_UNKNOWN + * else returns DMA_NONE + * + * Might block: no + * + * Notes: The SCSI subsystem now uses the same values for these + * constants as the PCI subsystem so this function is a nop. + * The recommendation is not to use this conversion function anymore + * (in the 2.6 kernel series) as it is not needed. + * + * Defined in: drivers/scsi/scsi.h . + **/ +int scsi_to_pci_dma_dir(unsigned char scsi_data_direction) + + +/** + * scsi_to_sbus_dma_dir - convert SCSI subsystem direction flag to SBUS + * @scsi_data_direction: SCSI subsystem direction flag + * + * Returns DMA_TO_DEVICE given SCSI_DATA_WRITE, + * FROM_DEVICE given SCSI_DATA_READ + * DMA_BIDIRECTIONAL given SCSI_DATA_UNKNOWN + * else returns DMA_NONE + * + * Notes: The SCSI subsystem now uses the same values for these + * constants as the SBUS subsystem so this function is a nop. + * The recommendation is not to use this conversion function anymore + * (in the 2.6 kernel series) as it is not needed. + * + * Might block: no + * + * Defined in: drivers/scsi/scsi.h . + **/ +int scsi_to_sbus_dma_dir(unsigned char scsi_data_direction) + + +/** + * scsi_track_queue_full - track successive QUEUE_FULL events on given + * device to determine if and when there is a need + * to adjust the queue depth on the device. + * @sdev: pointer to SCSI device instance + * @depth: Current number of outstanding SCSI commands on this device, + * not counting the one returned as QUEUE_FULL. + * + * Returns 0 - no change needed + * >0 - adjust queue depth to this new depth + * -1 - drop back to untagged operation using host->cmd_per_lun + * as the untagged command depth + * + * Might block: no + * + * Notes: LLDs may call this at any time and we will do "The Right + * Thing"; interrupt context safe. + * + * Defined in: drivers/scsi/scsi.c . + **/ +int scsi_track_queue_full(Scsi_Device *sdev, int depth) + + +/** + * scsi_unblock_requests - allow further commands to be queued to given host + * + * @shost: pointer to host to unblock commands on + * + * Returns nothing + * + * Might block: no + * + * Defined in: drivers/scsi/scsi_lib.c . +**/ +void scsi_unblock_requests(struct Scsi_Host * shost) + + +/** + * scsi_unregister - unregister and free memory used by host instance + * @shp: pointer to scsi host instance to unregister. + * + * Returns nothing + * + * Might block: no + * + * Notes: Should not be invoked if the "hotplug initialization + * model" is being used. Called internally by exit_this_scsi_driver() + * in the "passive initialization model". Hence a LLD has no need to + * call this function directly. + * + * Defined in: drivers/scsi/hosts.c . + **/ +void scsi_unregister(struct Scsi_Host * shp) + + + + +Interface Functions +=================== +Interface functions are supplied (defined) by LLDs and their function +pointers are placed in an instance of struct scsi_host_template which +is passed to scsi_host_alloc() [or scsi_register() / init_this_scsi_driver()]. +Some are mandatory. Interface functions should be declared static. The +accepted convention is that driver "xyz" will declare its slave_configure() +function as: + static int xyz_slave_configure(struct scsi_device * sdev); +and so forth for all interface functions listed below. + +A pointer to this function should be placed in the 'slave_configure' member +of a "struct scsi_host_template" instance. A pointer to such an instance +should be passed to the mid level's scsi_host_alloc() [or scsi_register() / +init_this_scsi_driver()]. + +The interface functions are also described in the include/scsi/scsi_host.h +file immediately above their definition point in "struct scsi_host_template". +In some cases more detail is given in scsi_host.h than below. + +The interface functions are listed below in alphabetical order. + +Summary: + bios_param - fetch head, sector, cylinder info for a disk + detect - detects HBAs this driver wants to control + eh_timed_out - notify the host that a command timer expired + eh_abort_handler - abort given command + eh_bus_reset_handler - issue SCSI bus reset + eh_device_reset_handler - issue SCSI device reset + eh_host_reset_handler - reset host (host bus adapter) + eh_strategy_handler - driver supplied alternate to scsi_unjam_host() + info - supply information about given host + ioctl - driver can respond to ioctls + proc_info - supports /proc/scsi/{driver_name}/{host_no} + queuecommand - queue scsi command, invoke 'done' on completion + release - release all resources associated with given host + slave_alloc - prior to any commands being sent to a new device + slave_configure - driver fine tuning for given device after attach + slave_destroy - given device is about to be shut down + + +Details: + +/** + * bios_param - fetch head, sector, cylinder info for a disk + * @sdev: pointer to scsi device context (defined in + * include/scsi/scsi_device.h) + * @bdev: pointer to block device context (defined in fs.h) + * @capacity: device size (in 512 byte sectors) + * @params: three element array to place output: + * params[0] number of heads (max 255) + * params[1] number of sectors (max 63) + * params[2] number of cylinders + * + * Return value is ignored + * + * Locks: none + * + * Calling context: process (sd) + * + * Notes: an arbitrary geometry (based on READ CAPACITY) is used + * if this function is not provided. The params array is + * pre-initialized with made up values just in case this function + * doesn't output anything. + * + * Optionally defined in: LLD + **/ + int bios_param(struct scsi_device * sdev, struct block_device *bdev, + sector_t capacity, int params[3]) + + +/** + * detect - detects HBAs this driver wants to control + * @shtp: host template for this driver. + * + * Returns number of hosts this driver wants to control. 0 means no + * suitable hosts found. + * + * Locks: none held + * + * Calling context: process [invoked from init_this_scsi_driver()] + * + * Notes: First function called from the SCSI mid level on this + * driver. Upper level drivers (e.g. sd) may not (yet) be present. + * For each host found, this method should call scsi_register() + * [see hosts.c]. + * + * Defined in: LLD (required if "passive initialization mode" is used, + * not invoked in "hotplug initialization mode") + **/ + int detect(struct scsi_host_template * shtp) + + +/** + * eh_timed_out - The timer for the command has just fired + * @scp: identifies command timing out + * + * Returns: + * + * EH_HANDLED: I fixed the error, please complete the command + * EH_RESET_TIMER: I need more time, reset the timer and + * begin counting again + * EH_NOT_HANDLED Begin normal error recovery + * + * + * Locks: None held + * + * Calling context: interrupt + * + * Notes: This is to give the LLD an opportunity to do local recovery. + * This recovery is limited to determining if the outstanding command + * will ever complete. You may not abort and restart the command from + * this callback. + * + * Optionally defined in: LLD + **/ + int eh_timed_out(struct scsi_cmnd * scp) + + +/** + * eh_abort_handler - abort command associated with scp + * @scp: identifies command to be aborted + * + * Returns SUCCESS if command aborted else FAILED + * + * Locks: struct Scsi_Host::host_lock held (with irqsave) on entry + * and assumed to be held on return. + * + * Calling context: kernel thread + * + * Notes: Invoked from scsi_eh thread. No other commands will be + * queued on current host during eh. + * + * Optionally defined in: LLD + **/ + int eh_abort_handler(struct scsi_cmnd * scp) + + +/** + * eh_bus_reset_handler - issue SCSI bus reset + * @scp: SCSI bus that contains this device should be reset + * + * Returns SUCCESS if command aborted else FAILED + * + * Locks: struct Scsi_Host::host_lock held (with irqsave) on entry + * and assumed to be held on return. + * + * Calling context: kernel thread + * + * Notes: Invoked from scsi_eh thread. No other commands will be + * queued on current host during eh. + * + * Optionally defined in: LLD + **/ + int eh_bus_reset_handler(struct scsi_cmnd * scp) + + +/** + * eh_device_reset_handler - issue SCSI device reset + * @scp: identifies SCSI device to be reset + * + * Returns SUCCESS if command aborted else FAILED + * + * Locks: struct Scsi_Host::host_lock held (with irqsave) on entry + * and assumed to be held on return. + * + * Calling context: kernel thread + * + * Notes: Invoked from scsi_eh thread. No other commands will be + * queued on current host during eh. + * + * Optionally defined in: LLD + **/ + int eh_device_reset_handler(struct scsi_cmnd * scp) + + +/** + * eh_host_reset_handler - reset host (host bus adapter) + * @scp: SCSI host that contains this device should be reset + * + * Returns SUCCESS if command aborted else FAILED + * + * Locks: struct Scsi_Host::host_lock held (with irqsave) on entry + * and assumed to be held on return. + * + * Calling context: kernel thread + * + * Notes: Invoked from scsi_eh thread. No other commands will be + * queued on current host during eh. + * With the default eh_strategy in place, if none of the _abort_, + * _device_reset_, _bus_reset_ or this eh handler function are + * defined (or they all return FAILED) then the device in question + * will be set offline whenever eh is invoked. + * + * Optionally defined in: LLD + **/ + int eh_host_reset_handler(struct scsi_cmnd * scp) + + +/** + * eh_strategy_handler - driver supplied alternate to scsi_unjam_host() + * @shp: host on which error has occurred + * + * Returns TRUE if host unjammed, else FALSE. + * + * Locks: none + * + * Calling context: kernel thread + * + * Notes: Invoked from scsi_eh thread. LLD supplied alternate to + * scsi_unjam_host() found in scsi_error.c + * + * Optionally defined in: LLD + **/ + int eh_strategy_handler(struct Scsi_Host * shp) + + +/** + * info - supply information about given host: driver name plus data + * to distinguish given host + * @shp: host to supply information about + * + * Return ASCII null terminated string. [This driver is assumed to + * manage the memory pointed to and maintain it, typically for the + * lifetime of this host.] + * + * Locks: none + * + * Calling context: process + * + * Notes: Often supplies PCI or ISA information such as IO addresses + * and interrupt numbers. If not supplied struct Scsi_Host::name used + * instead. It is assumed the returned information fits on one line + * (i.e. does not included embedded newlines). + * The SCSI_IOCTL_PROBE_HOST ioctl yields the string returned by this + * function (or struct Scsi_Host::name if this function is not + * available). + * In a similar manner, init_this_scsi_driver() outputs to the console + * each host's "info" (or name) for the driver it is registering. + * Also if proc_info() is not supplied, the output of this function + * is used instead. + * + * Optionally defined in: LLD + **/ + const char * info(struct Scsi_Host * shp) + + +/** + * ioctl - driver can respond to ioctls + * @sdp: device that ioctl was issued for + * @cmd: ioctl number + * @arg: pointer to read or write data from. Since it points to + * user space, should use appropriate kernel functions + * (e.g. copy_from_user() ). In the Unix style this argument + * can also be viewed as an unsigned long. + * + * Returns negative "errno" value when there is a problem. 0 or a + * positive value indicates success and is returned to the user space. + * + * Locks: none + * + * Calling context: process + * + * Notes: The SCSI subsystem uses a "trickle down" ioctl model. + * The user issues an ioctl() against an upper level driver + * (e.g. /dev/sdc) and if the upper level driver doesn't recognize + * the 'cmd' then it is passed to the SCSI mid level. If the SCSI + * mid level does not recognize it, then the LLD that controls + * the device receives the ioctl. According to recent Unix standards + * unsupported ioctl() 'cmd' numbers should return -ENOTTY. + * + * Optionally defined in: LLD + **/ + int ioctl(struct scsi_device *sdp, int cmd, void *arg) + + +/** + * proc_info - supports /proc/scsi/{driver_name}/{host_no} + * @buffer: anchor point to output to (0==writeto1_read0) or fetch from + * (1==writeto1_read0). + * @start: where "interesting" data is written to. Ignored when + * 1==writeto1_read0. + * @offset: offset within buffer 0==writeto1_read0 is actually + * interested in. Ignored when 1==writeto1_read0 . + * @length: maximum (or actual) extent of buffer + * @host_no: host number of interest (struct Scsi_Host::host_no) + * @writeto1_read0: 1 -> data coming from user space towards driver + * (e.g. "echo some_string > /proc/scsi/xyz/2") + * 0 -> user what data from this driver + * (e.g. "cat /proc/scsi/xyz/2") + * + * Returns length when 1==writeto1_read0. Otherwise number of chars + * output to buffer past offset. + * + * Locks: none held + * + * Calling context: process + * + * Notes: Driven from scsi_proc.c which interfaces to proc_fs. proc_fs + * support can now be configured out of the scsi subsystem. + * + * Optionally defined in: LLD + **/ + int proc_info(char * buffer, char ** start, off_t offset, + int length, int host_no, int writeto1_read0) + + +/** + * queuecommand - queue scsi command, invoke 'done' on completion + * @scp: pointer to scsi command object + * @done: function pointer to be invoked on completion + * + * Returns 0 on success. + * + * If there's a failure, return either: + * + * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or + * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full + * + * On both of these returns, the mid-layer will requeue the I/O + * + * - if the return is SCSI_MLQUEUE_DEVICE_BUSY, only that particular + * device will be paused, and it will be unpaused when a command to + * the device returns (or after a brief delay if there are no more + * outstanding commands to it). Commands to other devices continue + * to be processed normally. + * + * - if the return is SCSI_MLQUEUE_HOST_BUSY, all I/O to the host + * is paused and will be unpaused when any command returns from + * the host (or after a brief delay if there are no outstanding + * commands to the host). + * + * For compatibility with earlier versions of queuecommand, any + * other return value is treated the same as + * SCSI_MLQUEUE_HOST_BUSY. + * + * Other types of errors that are detected immediately may be + * flagged by setting scp->result to an appropriate value, + * invoking the 'done' callback, and then returning 0 from this + * function. If the command is not performed immediately (and the + * LLD is starting (or will start) the given command) then this + * function should place 0 in scp->result and return 0. + * + * Command ownership. If the driver returns zero, it owns the + * command and must take responsibility for ensuring the 'done' + * callback is executed. Note: the driver may call done before + * returning zero, but after it has called done, it may not + * return any value other than zero. If the driver makes a + * non-zero return, it must not execute the command's done + * callback at any time. + * + * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave") + * and is expected to be held on return. + * + * Calling context: in interrupt (soft irq) or process context + * + * Notes: This function should be relatively fast. Normally it will + * not wait for IO to complete. Hence the 'done' callback is invoked + * (often directly from an interrupt service routine) some time after + * this function has returned. In some cases (e.g. pseudo adapter + * drivers that manufacture the response to a SCSI INQUIRY) + * the 'done' callback may be invoked before this function returns. + * If the 'done' callback is not invoked within a certain period + * the SCSI mid level will commence error processing. + * If a status of CHECK CONDITION is placed in "result" when the + * 'done' callback is invoked, then the LLD driver should + * perform autosense and fill in the struct scsi_cmnd::sense_buffer + * array. The scsi_cmnd::sense_buffer array is zeroed prior to + * the mid level queuing a command to an LLD. + * + * Defined in: LLD + **/ + int queuecommand(struct scsi_cmnd * scp, + void (*done)(struct scsi_cmnd *)) + + +/** + * release - release all resources associated with given host + * @shp: host to be released. + * + * Return value ignored (could soon be a function returning void). + * + * Locks: none held + * + * Calling context: process + * + * Notes: Invoked from scsi_module.c's exit_this_scsi_driver(). + * LLD's implementation of this function should call + * scsi_unregister(shp) prior to returning. + * Only needed for old-style host templates. + * + * Defined in: LLD (required in "passive initialization model", + * should not be defined in hotplug model) + **/ + int release(struct Scsi_Host * shp) + + +/** + * slave_alloc - prior to any commands being sent to a new device + * (i.e. just prior to scan) this call is made + * @sdp: pointer to new device (about to be scanned) + * + * Returns 0 if ok. Any other return is assumed to be an error and + * the device is ignored. + * + * Locks: none + * + * Calling context: process + * + * Notes: Allows the driver to allocate any resources for a device + * prior to its initial scan. The corresponding scsi device may not + * exist but the mid level is just about to scan for it (i.e. send + * and INQUIRY command plus ...). If a device is found then + * slave_configure() will be called while if a device is not found + * slave_destroy() is called. + * For more details see the include/scsi/scsi_host.h file. + * + * Optionally defined in: LLD + **/ + int slave_alloc(struct scsi_device *sdp) + + +/** + * slave_configure - driver fine tuning for given device just after it + * has been first scanned (i.e. it responded to an + * INQUIRY) + * @sdp: device that has just been attached + * + * Returns 0 if ok. Any other return is assumed to be an error and + * the device is taken offline. [offline devices will _not_ have + * slave_destroy() called on them so clean up resources.] + * + * Locks: none + * + * Calling context: process + * + * Notes: Allows the driver to inspect the response to the initial + * INQUIRY done by the scanning code and take appropriate action. + * For more details see the include/scsi/scsi_host.h file. + * + * Optionally defined in: LLD + **/ + int slave_configure(struct scsi_device *sdp) + + +/** + * slave_destroy - given device is about to be shut down. All + * activity has ceased on this device. + * @sdp: device that is about to be shut down + * + * Returns nothing + * + * Locks: none + * + * Calling context: process + * + * Notes: Mid level structures for given device are still in place + * but are about to be torn down. Any per device resources allocated + * by this driver for given device should be freed now. No further + * commands will be sent for this sdp instance. [However the device + * could be re-attached in the future in which case a new instance + * of struct scsi_device would be supplied by future slave_alloc() + * and slave_configure() calls.] + * + * Optionally defined in: LLD + **/ + void slave_destroy(struct scsi_device *sdp) + + + +Data Structures +=============== +struct scsi_host_template +------------------------- +There is one "struct scsi_host_template" instance per LLD ***. It is +typically initialized as a file scope static in a driver's header file. That +way members that are not explicitly initialized will be set to 0 or NULL. +Member of interest: + name - name of driver (may contain spaces, please limit to + less than 80 characters) + proc_name - name used in "/proc/scsi/<proc_name>/<host_no>" and + by sysfs in one of its "drivers" directories. Hence + "proc_name" should only contain characters acceptable + to a Unix file name. + (*queuecommand)() - primary callback that the mid level uses to inject + SCSI commands into an LLD. +The structure is defined and commented in include/scsi/scsi_host.h + +*** In extreme situations a single driver may have several instances + if it controls several different classes of hardware (e.g. an LLD + that handles both ISA and PCI cards and has a separate instance of + struct scsi_host_template for each class). + +struct Scsi_Host +---------------- +There is one struct Scsi_Host instance per host (HBA) that an LLD +controls. The struct Scsi_Host structure has many members in common +with "struct scsi_host_template". When a new struct Scsi_Host instance +is created (in scsi_host_alloc() in hosts.c) those common members are +initialized from the driver's struct scsi_host_template instance. Members +of interest: + host_no - system wide unique number that is used for identifying + this host. Issued in ascending order from 0. + can_queue - must be greater than 0; do not send more than can_queue + commands to the adapter. + this_id - scsi id of host (scsi initiator) or -1 if not known + sg_tablesize - maximum scatter gather elements allowed by host. + 0 implies scatter gather not supported by host + max_sectors - maximum number of sectors (usually 512 bytes) allowed + in a single SCSI command. The default value of 0 leads + to a setting of SCSI_DEFAULT_MAX_SECTORS (defined in + scsi_host.h) which is currently set to 1024. So for a + disk the maximum transfer size is 512 KB when max_sectors + is not defined. Note that this size may not be sufficient + for disk firmware uploads. + cmd_per_lun - maximum number of commands that can be queued on devices + controlled by the host. Overridden by LLD calls to + scsi_adjust_queue_depth(). + unchecked_isa_dma - 1=>only use bottom 16 MB of ram (ISA DMA addressing + restriction), 0=>can use full 32 bit (or better) DMA + address space + use_clustering - 1=>SCSI commands in mid level's queue can be merged, + 0=>disallow SCSI command merging + hostt - pointer to driver's struct scsi_host_template from which + this struct Scsi_Host instance was spawned + hostt->proc_name - name of LLD. This is the driver name that sysfs uses + transportt - pointer to driver's struct scsi_transport_template instance + (if any). FC and SPI transports currently supported. + sh_list - a double linked list of pointers to all struct Scsi_Host + instances (currently ordered by ascending host_no) + my_devices - a double linked list of pointers to struct scsi_device + instances that belong to this host. + hostdata[0] - area reserved for LLD at end of struct Scsi_Host. Size + is set by the second argument (named 'xtr_bytes') to + scsi_host_alloc() or scsi_register(). + +The scsi_host structure is defined in include/scsi/scsi_host.h + +struct scsi_device +------------------ +Generally, there is one instance of this structure for each SCSI logical unit +on a host. Scsi devices connected to a host are uniquely identified by a +channel number, target id and logical unit number (lun). +The structure is defined in include/scsi/scsi_device.h + +struct scsi_cmnd +---------------- +Instances of this structure convey SCSI commands to the LLD and responses +back to the mid level. The SCSI mid level will ensure that no more SCSI +commands become queued against the LLD than are indicated by +scsi_adjust_queue_depth() (or struct Scsi_Host::cmd_per_lun). There will +be at least one instance of struct scsi_cmnd available for each SCSI device. +Members of interest: + cmnd - array containing SCSI command + cmnd_len - length (in bytes) of SCSI command + sc_data_direction - direction of data transfer in data phase. See + "enum dma_data_direction" in include/linux/dma-mapping.h + request_bufflen - number of data bytes to transfer (0 if no data phase) + use_sg - ==0 -> no scatter gather list, hence transfer data + to/from request_buffer + - >0 -> scatter gather list (actually an array) in + request_buffer with use_sg elements + request_buffer - either contains data buffer or scatter gather list + depending on the setting of use_sg. Scatter gather + elements are defined by 'struct scatterlist' found + in include/asm/scatterlist.h . + done - function pointer that should be invoked by LLD when the + SCSI command is completed (successfully or otherwise). + Should only be called by an LLD if the LLD has accepted + the command (i.e. queuecommand() returned or will return + 0). The LLD may invoke 'done' prior to queuecommand() + finishing. + result - should be set by LLD prior to calling 'done'. A value + of 0 implies a successfully completed command (and all + data (if any) has been transferred to or from the SCSI + target device). 'result' is a 32 bit unsigned integer that + can be viewed as 4 related bytes. The SCSI status value is + in the LSB. See include/scsi/scsi.h status_byte(), + msg_byte(), host_byte() and driver_byte() macros and + related constants. + sense_buffer - an array (maximum size: SCSI_SENSE_BUFFERSIZE bytes) that + should be written when the SCSI status (LSB of 'result') + is set to CHECK_CONDITION (2). When CHECK_CONDITION is + set, if the top nibble of sense_buffer[0] has the value 7 + then the mid level will assume the sense_buffer array + contains a valid SCSI sense buffer; otherwise the mid + level will issue a REQUEST_SENSE SCSI command to + retrieve the sense buffer. The latter strategy is error + prone in the presence of command queuing so the LLD should + always "auto-sense". + device - pointer to scsi_device object that this command is + associated with. + resid - an LLD should set this signed integer to the requested + transfer length (i.e. 'request_bufflen') less the number + of bytes that are actually transferred. 'resid' is + preset to 0 so an LLD can ignore it if it cannot detect + underruns (overruns should be rare). If possible an LLD + should set 'resid' prior to invoking 'done'. The most + interesting case is data transfers from a SCSI target + device device (i.e. READs) that underrun. + underflow - LLD should place (DID_ERROR << 16) in 'result' if + actual number of bytes transferred is less than this + figure. Not many LLDs implement this check and some that + do just output an error message to the log rather than + report a DID_ERROR. Better for an LLD to implement + 'resid'. + +The scsi_cmnd structure is defined in include/scsi/scsi_cmnd.h + + +Locks +===== +Each struct Scsi_Host instance has a spin_lock called struct +Scsi_Host::default_lock which is initialized in scsi_host_alloc() [found in +hosts.c]. Within the same function the struct Scsi_Host::host_lock pointer +is initialized to point at default_lock with the scsi_assign_lock() function. +Thereafter lock and unlock operations performed by the mid level use the +struct Scsi_Host::host_lock pointer. + +LLDs can override the use of struct Scsi_Host::default_lock by +using scsi_assign_lock(). The earliest opportunity to do this would +be in the detect() function after it has invoked scsi_register(). It +could be replaced by a coarser grain lock (e.g. per driver) or a +lock of equal granularity (i.e. per host). Using finer grain locks +(e.g. per SCSI device) may be possible by juggling locks in +queuecommand(). + +Autosense +========= +Autosense (or auto-sense) is defined in the SAM-2 document as "the +automatic return of sense data to the application client coincident +with the completion of a SCSI command" when a status of CHECK CONDITION +occurs. LLDs should perform autosense. This should be done when the LLD +detects a CHECK CONDITION status by either: + a) instructing the SCSI protocol (e.g. SCSI Parallel Interface (SPI)) + to perform an extra data in phase on such responses + b) or, the LLD issuing a REQUEST SENSE command itself + +Either way, when a status of CHECK CONDITION is detected, the mid level +decides whether the LLD has performed autosense by checking struct +scsi_cmnd::sense_buffer[0] . If this byte has an upper nibble of 7 (or 0xf) +then autosense is assumed to have taken place. If it has another value (and +this byte is initialized to 0 before each command) then the mid level will +issue a REQUEST SENSE command. + +In the presence of queued commands the "nexus" that maintains sense +buffer data from the command that failed until a following REQUEST SENSE +may get out of synchronization. This is why it is best for the LLD +to perform autosense. + + +Changes since lk 2.4 series +=========================== +io_request_lock has been replaced by several finer grained locks. The lock +relevant to LLDs is struct Scsi_Host::host_lock and there is +one per SCSI host. + +The older error handling mechanism has been removed. This means the +LLD interface functions abort() and reset() have been removed. +The struct scsi_host_template::use_new_eh_code flag has been removed. + +In the 2.4 series the SCSI subsystem configuration descriptions were +aggregated with the configuration descriptions from all other Linux +subsystems in the Documentation/Configure.help file. In the 2.6 series, +the SCSI subsystem now has its own (much smaller) drivers/scsi/Kconfig +file that contains both configuration and help information. + +struct SHT has been renamed to struct scsi_host_template. + +Addition of the "hotplug initialization model" and many extra functions +to support it. + + +Credits +======= +The following people have contributed to this document: + Mike Anderson <andmike at us dot ibm dot com> + James Bottomley <James dot Bottomley at steeleye dot com> + Patrick Mansfield <patmans at us dot ibm dot com> + Christoph Hellwig <hch at infradead dot org> + Doug Ledford <dledford at redhat dot com> + Andries Brouwer <Andries dot Brouwer at cwi dot nl> + Randy Dunlap <rddunlap at osdl dot org> + Alan Stern <stern at rowland dot harvard dot edu> + + +Douglas Gilbert +dgilbert at interlog dot com +21st September 2004 |