English Chinese (Traditional) (zh_TW)
Chapter 12. Common Access Method SCSI Controllers
Common Access Method SCSI Controllers
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:
ncr ([.filename]#/sys/pci/ncr.c#) by Wolfgang Stanglmeier and Stefan Esser
sym ([.filename]#/sys/dev/sym/sym_hipd.c#) by Gerard Roudier
aic7xxx ([.filename]#/sys/dev/aic7xxx/aic7xxx.c#) by Justin T. Gibbs
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".
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.
General Architecture
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:
_Peripheral Modules_ - a driver for peripheral devices (disk, tape, CD-ROM, etc.)
_SCSI Interface Modules_ (SIM) - a Host Bus Adapter drivers for connecting to an I/O bus such as SCSI or IDE.
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).
As we are interested in writing a SCSI adapter driver here, from this point on we will consider everything from the SIM standpoint.
A typical SIM driver needs to include the following CAM-related header files:
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_debug.h>
#include <cam/scsi/scsi_all.h>
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.
This is achieved in multiple steps: first it is necessary to allocate the queue of requests associated with this SIM:
struct cam_devq *devq;
if(( devq = cam_simq_alloc(SIZE) )==NULL) {
error; /* some code to handle the error */