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