This blog post presents a gist of Free BSD’s doc on CAM(here) and chapter 14 of the book FreeBSD device driver- A guide for intrepid. It gives an introduction to the CAM(Common access method), it’s applications, it’s working and it’s organization in FreeBSD. It is written to get myself a really good understanding of mmccam stack which is nothing but SDHC/SDIO protocols wired within the CAM framework.
COMMON ACCESS METHOD
CAM is a method for separating HBA adapters from storage adapters and is primarily used for SCSI. By separating these drivers it reduces the complexity of both the drivers.Furthermore, this separation enables storage drivers (such as CD-ROM and tape drivers) to control their devices on any I/O bus (such as IDE, SCSI, and so on) as long as an appropriate HBA driver is available.
Note: HBA(Host Bus Adapters) are devices (IC/Card) that connects the host to other devices. For example, USB HBA allows host OS to communicate to USB.
In CAM terminology, HBA drivers are called SIMs(Software Interface Modules) and storage drivers are called peripheral modules. The CAM layer handles the device-independent tasks of resource allocation and command routing. These tasks include the tracking of requests and notifications between the controller and its clients. They also include the routing of requests across the many I/O buses to get the request to the correct controller.
The CAM layer leaves to the device driver the device-specific operations such as the setup and teardown of the DMA (Direct Memory Access) maps needed to do the I/O.
FreeBSD CAM implementation contains SIMs for: SCSI parallel interface(SPI) Fibre channel, USB Mass storage, FireWire, ATAPI etc. Supported peripheral modules are: disks(da), cd roms(cd), tapes(sa), processor type devices(pt) used in scanners, tape changers(ch) etc. Further, It provides a pass through interface that allows user applications to do I/O on on any CAM-controlled device.
CAM usually consists of 3 layers: CAM SIM layer, CAM transport layer(xpt), CAM peripheral module layer.
- The CAM peripheral layer that provides open, close, strategy, attach, and detach operations for the supported SCSI devices. CAM supported devices includes direct access (da)—disk drives, cdrom (cd)—CD-ROM drives, sequential access (sa)—tape drives, and changer (ch)—jukeboxes.
- The CAM transport layer that builds, executes, and interprets results of SCSI commands. CAM starts by building a generic I/O command using a CCB (CAM Control Block). The CCB contains a CDB (Command Descriptor Block) composed of a 6-16 byte SCSI command. For example, the command “READ_10, block_offset, count” gets back a status of success or various error codes. If there is an error, the drive may also include sense data to give more information about the cause of the error.
- The CAM SIM (Software Interface Module) or HBA (Host Bus Adapter) interface layer provides bus routing to devices. Its job is to allocate a path to the requested device, send a CCB action request to the device, and then collect notification of the I/O completion from the device.
To understand the working deeply, let’s trace an I/O request to the da(4) peripheral module.
So, the first function to handle I/O request from OS dastrategy(in this case) from the CAM peripheral module layer. dastrategy then puts the I/O request into the queue with the help of bioq_disksort and then handover the execution to xpt_schedule. xpt_schedule schedules/prepares the peripheral module to recieve the CAM control block (CCB). It then calls xpt_run_dev_allocq which allocates and constructs the CCB. Note that CCB here consists of the location(path) of the device, I/O command to be performed etc. It then calls the peripheral module’s start routine(dastart here) which takes the I/O command and convert it into the SCSI command. This command is stored in CCB made by xpt_run_dev_allocq. dastart ends by calling xpt_action which reads the CCB to determine the SIM’s path and then call it’s initialization function(ahc_action in our case).
ahc_action receives the CCB and translates the SCSI command into the hardware specific command. It returns back to the caller of dastrategy. Now the device will execute the given job and interrupt when the job is completed. On interrupt ahc_done routine is called which executes the ISR and append the status(successful/unsuccessful) to the CCB and pass it on to xpt_done, which processes the CCB and hand over the the execution to CAM ISR(camisr here). camisr executes peripheral specific routine and then it hands over to dadone which signals the completion of the task by calling biodone.
After having discussed an overview of CAM working let’s have deeper look into mmc implementation in CAM framework. Head on to my next post.