⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_mid_low_api.txt

📁 linux 内核源代码
💻 TXT
📖 第 1 页 / 共 4 页
字号:
                          Linux Kernel 2.6 series                 SCSI mid_level - lower_level driver interface                 =============================================Introduction============This document outlines the interface between the Linux SCSI mid level andSCSI lower level drivers. Lower level drivers (LLDs) are variously called host bus adapter (HBA) drivers and host drivers (HD). A "host" in thiscontext is a bridge between a computer IO bus (e.g. PCI or ISA) and asingle SCSI initiator port on a SCSI transport. An "initiator" port(SCSI terminology, see SAM-3 at http://www.t10.org) sends SCSI commandsto "target" SCSI ports (e.g. disks). There can be many LLDs in a runningsystem, but only one per hardware type. Most LLDs can control one or moreSCSI HBAs. Some HBAs contain multiple hosts.In some cases the SCSI transport is an external bus that already hasits own subsystem in Linux (e.g. USB and ieee1394). In such cases theSCSI subsystem LLD is a software bridge to the other driver subsystem.Examples are the usb-storage driver (found in the drivers/usb/storagedirectory) and the ieee1394/sbp2 driver (found in the drivers/ieee1394directory).For example, the aic7xxx LLD controls Adaptec SCSI parallel interface(SPI) controllers based on that company's 7xxx chip series. The aic7xxxLLD can be built into the kernel or loaded as a module. There can only beone 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 controllersand thus represent two hosts. Like most modern HBAs, each aic7xxx hosthas its own PCI device address. [The one-to-one correspondence betweena SCSI host and a PCI device is common but not required (e.g. withISA or MCA adapters).]The SCSI mid level isolates an LLD from other layers such as the SCSIupper 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 foundat http://www.torque.net/scsi/scsi_mid_low_api.txt.gz . Many LLDs are documented there (e.g. aic7xxx.txt). The SCSI mid-level isbriefly 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 codeor in the same directory as the C source code. For example to find a urlabout the USB mass storage driver see the /usr/src/linux/drivers/usb/storage directory.The Linux kernel source Documentation/DocBook/scsidrivers.tmpl filerefers to this file. With the appropriate DocBook tool-set, this permitsusers to generate html, ps and pdf renderings of information within thisfile (e.g. the interface functions).Driver structure================Traditionally an LLD for the SCSI subsystem has been at least two files inthe drivers/scsi directory. For example, a driver called "xyz" has a headerfile "xyz.h" and a source file "xyz.c". [Actually there is no good reasonwhy this couldn't all be in one file; the header file is superfluous.] Somedrivers that have been ported to several operating systems have more thantwo files. For example the aic7xxx driver has separate files for generic and OS-specific code (e.g. FreeBSD and Linux). Such drivers tend to havetheir own directory under the drivers/scsi directory.When a new LLD is being added to Linux, the following files (found in thedrivers/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 seriesproduction series, changes are being introduced into this interface. Anexample of this is driver initialization code where there are now 2 modelsavailable. 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 bereferred to the "passive" initialization model. The newer model allows HBAsto be hot plugged (and unplugged) during the lifetime of the LLD and willbe referred to as the "hotplug" initialization model. The newer model ispreferred as it can handle both traditional SCSI equipment that ispermanently connected as well as modern "SCSI" devices (e.g. USB orIEEE 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 levelThose functions in group a) are listed in a section entitled "Mid levelsupplied functions" below.Those functions in group b) are listed in a section entitled "Interfacefunctions" below. Their function pointers are placed in the members of"struct scsi_host_template", an instance of which is passed toscsi_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 instancesthat are shared with the mid level and other layers.All functions defined within an LLD and all data defined at file scopeshould be static. For example the slave_alloc() function in an LLDcalled "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 vaguelynamed scsi_register() function in most situations. The scsi_register()and scsi_unregister() functions remain to support legacy LLDs that usethe passive initialization model.Hotplug initialization model============================In this model an LLD controls when SCSI hosts are introduced and removedfrom the SCSI subsystem. Hosts can be introduced as early as driverinitialization and removed as late as driver shutdown. Typically a driverwill respond to a sysfs probe() callback that indicates an HBA has beendetected. After confirming that the new device is one that the LLD wantsto control, the LLD will initialize the HBA and then register a new hostwith the SCSI mid level.During LLD initialization the driver should register itself with theappropriate 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 (especiallythose that are writable after the driver is loaded) could also beregistered with sysfs at this point. The SCSI mid level first becomesaware of an LLD when that LLD registers its first HBA.At some later time, the LLD becomes aware of an HBA and what followsis 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 scanLLD                   mid level                    LLD===-------------------=========--------------------===------scsi_host_alloc()  -->scsi_add_host()  ---->scsi_scan_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 invokescsi_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 shutdownassociated with the LLD module being unloaded (e.g. with the "rmmod"command) or in response to a "hot unplug" indicated by sysfs()'sremove() callback being invoked. In either case, the sequence is thesame:        HBA REMOVE: assume 2 SCSI devices attachedLLD                      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 fromscsi_host_put() when the reference count hits zero.Hot unplugging an HBA that controls a disk which is processing SCSIcommands on a mounted file system is an interesting situation. Referencecounting logic is being introduced into the mid level to cope with manyof the issues involved. See the section on reference counting below.The hotplug concept may be extended to SCSI devices. Currently, when anHBA is added, the scsi_scan_host() function causes a scan for SCSI devicesattached to the HBA's SCSI transport. On newer SCSI transports the HBAmay 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 hotplugLLD                   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 beenremoved (unplugged) or the connection to it has been interrupted. Someexisting SCSI transports (e.g. SPI) may not become aware that a SCSIdevice has been removed until a subsequent SCSI command fails which willprobably cause that device to be set offline by the mid level. An LLD thatdetects the removal of a SCSI device can instigate its removal fromupper layers with this sequence:                  SCSI DEVICE hot unplugLLD                      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() andslave_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 alittle surprising] in their source code. For that file to work aninstance 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 qualifiersan LLD should not call them explicitly (since the kernel does that).Here is an example of an initialization sequence when two hosts aredetected (so detect() returns 2) and the SCSI bus scan on each hostfinds 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 beoverridden 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 hostregistration and de-registration are (typically) tied to LLD initializationand shutdown. Once the LLD is initialized then a new host that appears(e.g. via hotplugging) cannot easily be added without a redundantdriver shutdown and re-initialization. It may be possible to write an LLDthat 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 instancesacross the various SCSI layers which use them. Previously such instanceswere exclusively owned by the mid level. LLDs would not usually need todirectly manipulate these reference counts but there may be some caseswhere they do.There are 3 reference counting functions of interest associated withstruct 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 freedThe Scsi_device structure has had reference counting infrastructure added.This effectively spreads the ownership of struct Scsi_device instancesacross the various SCSI layers which use them. Previously such instanceswere exclusively owned by the mid level. See the access functions declaredtowards the end of include/scsi/scsi_device.h . If an LLD wants to keepa 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 canuse scsi_device_put() to decrement its reference count (and potentiallydelete it).^^ struct Scsi_Host actually has 2 reference counts which are manipulatedin parallel by these functions.Conventions===========First, Linus Torvalds's thoughts on C coding style can be found in theDocumentation/CodingStyle file. Next, there is a movement to "outlaw" typedefs introducing synonyms for struct tags. Both can be still found in the SCSI subsystem, butthe typedefs have been moved to a single file, scsi_typedefs.h tomake their future removal easier, for example: "typedef struct scsi_cmnd Scsi_Cmnd;"Also, most C99 enhancements are encouraged to the extent they are supportedby the relevant gcc compilers. So C99 style structure and arrayinitializers 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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -