Chapter 14. Common Access Method

image with no caption

Common Access Method (CAM) is an ANSI standard. Although primarily used for SCSI, CAM is a method for separating host bus adapter (HBA) drivers from storage drivers. HBAs are devices (that is, a card or integrated circuit) that connect the host to other devices. For example, USB HBAs allow the host to communicate with USB devices.

By separating HBA drivers from storage drivers, CAM reduces the complexity of individual drivers. Furthermore, this separation enables storage drivers (such as CD-ROM and tape drivers) to control their devices on anyI/O bus (such as IDE, SCSI, and so on) as long as an appropriate HBA driver is available. In other words, CAM modularizes HBA and storage drivers.

In CAM vernacular, HBA drivers are known as software interface modules (SIMs), and storage drivers are known as peripheral modules. Incidentally, the storage drivers discussed in Chapter 13 are not under CAM. To avoid confusion, I’ll refer to storage drivers under CAM as peripheral modules from now on.

The FreeBSD CAM implementation contains SIMs for SCSI Parallel Interface (SPI), Fibre Channel (FC), USB Mass Storage (UMASS), FireWire (IEEE 1394), and Advanced Technology Attachment Packet Interface (ATAPI). It has peripheral modules for disks (da), CD-ROMs (cd), tapes (sa), tape changers (ch), processor type devices (pt), and enclosure services (ses). Also, it provides a “pass-through” interface that allows user applications to send I/O requests directly to any CAM-controlled device (McKusick and Neville-Neil, 2005). This interface is, fundamentally, a SIM (as you’ll soon see).

In this chapter you’ll learn how to manage HBAs using CAM. Of course, before you can do that, you’ll need to know how CAM interfaces peripheral modules with SIMs. Because peripheral modules are just storage drivers with some CAM-related code, they’re only briefly discussed in this chapter.

How CAM Works

CAM is most easily understood by tracing an I/O request through it.

In Figure 14-1,[9] the kernel passes a block-centric I/O request to the da(4) peripheral module. As you would expect, this causes da(4)’s strategy routine (dastrategy) to execute.

The path of an I/O request through the CAM subsystem

Figure 14-1. The path of an I/O request through the CAM subsystem

The dastrategy function gets the block-centric I/O request and inserts it on the appropriate block I/O queue via bioq_disksort. It concludes by calling the xpt_schedule function. (The da(4) peripheral module supports every SCSI disk. Consequently, it manages multiple block I/O queues.)

The xpt_schedule function, by and large, schedules a peripheral module to receive a CAM Control Block (CCB). A CCB describes the location (or path) to the target device (that is, the intended recipient of the I/O request). The xpt_schedule function concludes by calling the xpt_run_dev_allocq function. (Note that my definition of CCB isn’t complete. I’ll expand this definition throughout this chapter.)

The xpt_run_dev_allocq function allocates and constructs a CCB. Afterward, it calls the peripheral module’s start routine (dastart in this example).

The dastart function takes the first block-centric I/O request off the appropriate block I/O queue and converts that into a SCSI command. This command is stored in the CCB constructed by xpt_run_dev_allocq. The dastart function ends by calling the xpt_action function.

The xpt_action function uses the path information stored in the CCB to determine the SIM to which the SCSI command should be sent. It then calls that SIM’s action routine (ahc_action in this case).

Note

A SIM was pseudo-randomly chosen for this example, so the fact that it’s ahc(4) is irrelevant.

The ahc_action function gets the CCB and translates the SCSI command into a hardware-specific command. This hardware-specific command is then passed to the device to be executed. Afterward, ahc_action returns back to the caller of dastrategy.

As soon as the device completes the hardware-specific command (which may involve DMA), it sends an interrupt, which causes ahc(4)’s done routine (ahc_done) to execute.

The ahc_done function appends the completion status (that is, successful or unsuccessful) to the CCB related to the completed hardware-specific command. It then calls the xpt_done function.

The xpt_done function gets the completed CCB and sets it up for processing by camisr, the CAM interrupt service routine. It then schedules camisr to run.

Loosely speaking, the camisr function carries out some “housekeeping” on the CCB. It ends by calling the CCB’s specified completion function (dadone in this example).

The dadone function, more or less, tells the kernel that the block-centric I/O request has been serviced by calling biodone.



[9] Figure 14-1 is adapted from The Design and Implementation of the FreeBSD Operating System by Marshall Kirk McKusick and George V. Neville-Neil (Addison-Wesley, 2005).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.190.156.93