SCSI-4
Home Up SCSI-1 SCSI-2 SCSI-3 SCSI-5 SCSI-6 SCSI-4 SCSI-7 SCSI-8 SCSI-9 SCSI-10 SCSI-13 SCSI-12 SCSI-11

 

 

4. SCSI Middle layer

 

4.0 Introduction

 

The middle layer is sort of a nebulous name for an object that has lots of different functions. I tend to view the middle layer as containing everything that goes into the SCSI core module that is loaded when the entire SCSI subsystem is loaded as a module. As such, it can be described as having the following subcomponents:
The module-related glue itself. Only used when SCSI is used as a module, and even then only when modules are being added and removed.
Proc filesystem support.
Bus scan support.
Other misc initializations, both boot time and module related.
Error handling.
Queueing of commands.
Bottom half handler.
Utility functions.

Each one of these will be discussed in turn - some of these are important enough that they will be discussed in their own section.

4.1 Boot time Initialization

At boot time, the SCSI core must be initialized before any other parts of the SCSI subsystem - in fact, the SCSI core itself initializes the other components at the appropriate times.

The main entrypoint is scsi_dev_init, which is called from outside of the SCSI subsystem when the rest of the kernel is prepared for SCSI to come online.

Initially we start with some simple stuff. Registering /proc/scsi. Registering the bottom half handler.

4.1.1 scsi_init

Once this is done, then the function scsi_init is called - this function has the job of running through all of the low-level drivers that were compiled into the system, and calling the detect function to see whether the cards are actually present. During this stage the Scsi_Host objects are allocated and initialized. The error handler threads are launched at this point, if the drivers use the new error handling code, and finally the information is displayed to the console about which cards have been located.

This function also registers the top level devices that are compiled into the system, mainly by sticking them in the scsi_devicelist linked list.

Once this is complete, we move on to the bus scan (discussed below).

After the bus scan, the init entrypoint is called for all upper level drivers - this will allocate internal datastructures (mainly arrays indexable by minor number). Finally, for all detected devices the attach entrypoint is called to insert the pointer to the Scsi_Device into the internal tables of the upper level driver. We also call scsi_build_commandblocks which will allocate all of the Scsi_Cmnd objects that will be used.

At this point we have a complete list of all devices attached to the system. Then we call resize_dma_pool to allocate memory for the DMA pool - this will be used for bounce buffers during actual I/O transactions.

The last step of initialization is to call the finish method for all of the registered upper level drivers. This will go through and do spin-up, read-capacity, and other initializations.

4.2 Module load Initialization

This is a more restricted version of the initialization of the boot time initialization. In the case where we are loading the SCSI core as a module, we know that there are not yet any low-level or upper-level drivers present in the system, so initialization merely consists of setting up enough information such that those modules can be loaded later.

4.3 Bus scan

The bus scan is where commands are sent out to each host adapter on the system to inquire as to what devices, if any, are present on each bus. The general theory is simple - loop over all SCSI id's, all of the channels, and see what's out there.

This is done by first sending a TEST_UNIT_READY. Any response which indicates the presence of a real device is taken as an affirmative. Note that simply testing for success/failure isn't good enough as there might be disks out there which aren't spun up and hence not ready. We really need to look at the sense data and see what the actual response is.

Next, an inquiry is performed. This SCSI command retrieves a lot of information about the device - device type, manufacturer, plus a whole lot more.

When we get a response back from the inquiry, then the Scsi_Device object is initialized, largely based upon data returned from the INQUIRY command. This is the point where the printed message appears on the console describing the device.

Once we have found a device, we check to see what high level drivers might be willing to drive it. This is accomplished by calling the detect entrypoint for all of the registered upper level drivers.

One of the ugly hacks in the kernel is the blacklist - this is essentially a hardcoded list in the kernel of all of all known devices that misbehave in one way or another. Many people express shock that such an ugly hack is used, however firmware bugs are common enough that there is no other acceptable option. One of the more annoying firmware bugs is where a device will respond to queries on all luns, thereby making it look like there are 8 devices when in fact there is only one.

The implementation of the bus scan code is in scan_scsis and scan_scsis_single.

4.4 Command queueing

4.5 Bottom half handler

4.6 Utility functions

4.6.1 scsi_allocate_device

4.6.2 scsi_request_queueable

4.6.3 scsi_release_command

4.6.3 scsi_do_cmd

4.6.3 internal_cmnd

4.6.3 scsi_done

4.6.3 scsi_bottom_half_handler

4.6.3 scsi_finish_command

If you have comments or suggestions, you can email me by clicking here

Last updated: 4/99.