CAM(4)

πŸ“¦
version 15.1 Β· 2 versions
, in freebsd 15.1

πŸ’… CAM(4) β€” the Common Access Method Storage subsystem, explained by your favorite unix bestie

Okay so picture this: it's CAM(4), the Common Access Method Storage subsystem, and honestly? She's the main character of your storage stack and nobody gives her her flowers. Let me put you on. 🫢


✨ SYNOPSIS ✨

Like, here's the whole vibe in kernel-config form β€” copy it exactly, don't freestyle:

device scbus
device ada
device cd
device ch
device da
device pass
device pt
device sa
options CAMDEBUG
options CAM_DEBUG_BUS=-1
options CAM_DEBUG_TARGET=-1
options CAM_DEBUG_LUN=-1
options CAM_DEBUG_COMPILE=CAM_DEBUG_INFO|CAM_DEBUG_CDB|CAM_DEBUG_PROBE
options CAM_DEBUG_FLAGS=CAM_DEBUG_INFO|CAM_DEBUG_CDB
options CAM_MAX_HIGHPOWER=4
options SCSI_NO_SENSE_STRINGS
options SCSI_NO_OP_STRINGS
options SCSI_DELAY=8000

🌸 DESCRIPTION 🌸

So the CAM subsystem is this uniform, modular lil system for implementing drivers that control all your SCSI, ATA, NVMe, and MMC / SD devices β€” and it also lets you use all different kinds of SCSI, ATA, NVMe, and MMC / SD host adapters through host adapter drivers. Iconic, flexible, no cap. πŸ’…

When the system probes buses, it attaches any devices it finds to the appropriate drivers. And the pass(4) driver β€” if it's configured in the kernel β€” will attach to all the devices. Every single one. She's nosy and we love her for it. πŸ‘‘


πŸŽ€ KERNEL CONFIGURATION πŸŽ€

There's a whole lineup of generic kernel configuration options for CAM. Let's meet the girls:

  • CAM_BOOT_DELAY β€” extra time to wait after the static parts of the kernel have run, so there's room to discover additional devices that might take a while to show up β€” think USB attached storage being slow to connect. She's patient. She waits. πŸ•°οΈ
  • CAM_IOSCHED_DYNAMIC β€” turns on dynamic decisions in the I/O scheduler, based on hints and on how the storage devices are currently performing. Adaptive queen. ✨
  • CAM_IO_STATS β€” enables collection of statistics for periph devices. Numbers! Data! We love to see it. πŸ“Š
  • CAM_TEST_FAILURE β€” enables the ability to simulate I/O failures. Yes, on purpose. For science. πŸ§ͺ
  • CAMDEBUG β€” this one compiles in all the CAM debugging printf code. But lowkey? Including it by itself will not actually cause any debugging information to be printed out. See below for the details, bestie. πŸ”
  • CAM_MAX_HIGHPOWER=4 β€” sets the maximum allowable number of concurrent "high power" commands. A "high power" command is one that takes more electrical power than most to complete β€” classic example: the SCSI START UNIT command. Starting a disk often takes significantly more electrical power than normal operation. This option is literally you telling the system how many concurrent high power commands may be outstanding without overloading the power supply on his computer. Respect the wattage. ⚑
  • SCSI_NO_SENSE_STRINGS β€” this one eliminates the text descriptions of each SCSI Additional Sense Code and Additional Sense Code Qualifier pair. Since that's a fairly large text database, killing it reduces kernel size somewhat. It's primarily necessary for boot floppies and other low disk space or low memory space environments. In most cases, though, this should be enabled, since it speeds the interpretation of SCSI error messages. And the page is very clear: do not let the "kernel bloat" zealots get to you β€” leave the sense descriptions in your kernel! πŸ˜€πŸ’–
  • SCSI_NO_OP_STRINGS β€” disables the text descriptions of each SCSI opcode. This option, like the sense string option above, is primarily useful for environments like a boot floppy where kernel size is critical. Enabling this for normal use is not recommended, since it slows debugging of SCSI problems. So like... don't. πŸ™ˆ
  • SCSI_DELAY=8000 β€” this is the SCSI "bus settle delay." Important: in CAM it's specified in milliseconds, not seconds like the old SCSI layer used to do. (Glow-up, honestly.) When the kernel boots, it sends a bus reset to each SCSI bus, telling each device to reset itself to a default set of transfer negotiations and other settings. Most SCSI devices need some amount of time to recover from a bus reset. Newer disks may need as little as 100ms, while old, slow devices may need way longer. If SCSI_DELAY isn't specified, it defaults to 2 seconds. The minimum allowable value is "100", i.e. 100ms. And one special case: if SCSI_DELAY is set to 0, that's taken to mean the "lowest possible value" β€” in which case SCSI_DELAY gets reset to 100ms. πŸ¦‹

🌈 Device wiring, or: how units get their assigned seats

All devices and buses support dynamic allocation, so you don't need to configure some upper number of devices and controllers β€” device da will suffice for any number of disk drivers. Slay, scalability. πŸ’œ

The devices are either wired so they appear as a particular device unit, or counted so that they appear as the next available unused unit.

Units get wired down by setting kernel environment hints. This is usually done either interactively from loader(8), or automatically via the /boot/device.hints file. The basic syntax is:

hint.device.unit.property="value"

Individual CAM bus numbers can be wired down to specific controllers with a config line similar to this:

hint.scbus.0.at="mpr1"

That assigns CAM bus number 0 to the mpr1 driver instance. And for controllers supporting more than one bus, a particular bus can be assigned like this:

hint.scbus.0.at="ahci1"
hint.scbus.0.bus="1"

Which assigns CAM bus 0 to the bus 1 instance on ahci1. Peripheral drivers can be wired to a specific bus, target, and lun as so:

hint.da.0.at="scbus0"
hint.da.0.target="0"
hint.da.0.lun="0"

That assigns da0 to target 0, unit (lun) 0 of scbus0. Omitting the target or unit hints tells CAM to treat them as wildcards and use the first respective counted instances. And you can combine all these examples together so a peripheral device gets wired to any particular controller, bus, target, and/or unit instance. So many knobs, so little time. πŸŽ›οΈ


🧚 This also works with nvme(4) drives, obviously

hint.nvme.4.at="pci7:0:0"
hint.scbus.10.at="nvme4"
hint.nda.10.at="scbus10"
hint.nda.10.target="1"
hint.nda.10.lun="12"
hint.nda.11.at="scbus10"
hint.nda.11.target="1"
hint.nda.11.lun="2"

So this assigns the NVMe card at PCI bus 7 slot 0 function 1 to scbus10. Two things to remember forever: the target for nda(4) devices is always 1, and the unit is the namespace identifier from the drive. The namespace id 1 is exported as nda10, and namespace id 2 is exported as nda11. iykyk. 🧠


πŸ“ Serial-number wiring, the glow-up

For devices that provide a serial number, units may be wired to that serial number without regard to where the drive is attached:

hint.nda.3.sn="CY0AN07101120B12P"
hint.da.44.sn="143282400011"
hint.ada.2.sn="A065D591"

Which wires nda3, da44, and ada2 to the drives with those specified serial numbers. And the best part? You don't need to specify an at line when serial numbers are used. Match made in heaven. πŸ’•


πŸ”₯ ADAPTERS πŸ”₯

The system allows common device drivers to work through many different types of adapters. The adapters take requests from the upper layers and do all the IO between the SCSI, ATA, NVMe, or MMC / SD bus and the system. The maximum size of a transfer is governed by the adapter β€” most adapters can transfer 1MB in a single operation, however many can transfer larger amounts. Big transfer energy. πŸš€


⭐ TARGET MODE ⭐

Some adapters support target mode, in which the system is capable of operating as a device, responding to operations initiated by another system. Target mode is supported for some adapters, but it's not yet complete for this version of the CAM SCSI subsystem. So like... she's still cooking. Don't expect the full meal yet. 🫢


πŸ—οΈ ARCHITECTURE πŸ—οΈ

So like, CAM is the social glue of your system, fr fr. It connects the upper layers to your storage devices. The PERIPH devices take storage requests from GEOM and other upper layers and translate them into protocol requests. Then XPT (that's the transport layer, bestie) dispatches those protocol requests to a SIM driver. A SIM driver takes those protocol requests and translates them into hardware commands that the host adapter actually understands, so it can transfer the protocol requests β€” and any data β€” over to the storage device. And the CCB? That's the messenger carrying all these requests around. πŸ’Œ

πŸ’… CAM

The Common Access Method was a standard defined in the 1990s for talking to disk drives. FreeBSD is one of the few operating systems that fully implements this model β€” main character energy, honestly. πŸ‘‘

The interface between the different parts of CAM is the CCB (or CAM Control Block). Every single CCB has a standard header, which holds the type of request plus dispatch info, and then a command-specific portion. A CAM Periph generates requests. The XPT layer dispatches them to the appropriate SIM. Some CCBs get sent straight to the SIM for immediate processing, while others get queued up and complete when the I/O finishes. A SIM takes CCBs and translates them into hardware-specific commands β€” pushing the SCSI CDB or other protocol control block out to the peripheral, plus setting up the DMA for the associated data. πŸ¦‹

πŸŽ€ Periph Devices

A periph driver knows how to translate standard requests into protocol messages that a SIM can deliver to hardware. These requests can come from any upper layer source, but mostly they roll in via GEOM as a bio request. They can also come in directly from character device requests for tapes and pass-through commands.

Disk devices β€” direct access (da) in CAM β€” are one type of peripheral. They show themselves to the kernel as a device ending in "da". Each protocol gets its own unique device name:

  • da(4) β€” a SCSI or SAS device, or devices that accept SCSI CDBs for I/O.
  • ada(4) β€” an ATA or SATA device.
  • nda(4) β€” an NVME device.
  • sdda(4) β€” an SD or MMC block storage device.

Tape devices are called serial access (sa(4)) in CAM. They interface to the system via a character device and give you ioctl(2) control for tape drives.

The pass(4) device passes CCB requests from userland straight through to the SIM. You use it to send commands to a device that aren't read, write, trim or flush. The camcontrol(8) command uses this device. πŸ”₯

✨ XPT drivers

The transport driver connects the periph to the SIM. It is not configured separately. It's also the one responsible for device discovery for those SIM drivers that don't enumerate themselves. lowkey doing all the work tbh.

🌸 SIM driver

SIM used to stand for SCSI Interface Module. Now it's just SIM, because it understands protocols other than SCSI. There are two types of SIM drivers: virtual and physical. Physical SIMs are typically called host bus adapters (HBA), but not universally. Virtual SIM drivers are for communicating with network or virtual machine hosts. πŸ’œ


πŸ“ FILES πŸ“

see other CAM device entries. (yes that's it, go look at the others bestie, they got the tea β˜•)


🩺 DIAGNOSTICS 🩺

You can use an XPT_DEBUG CCB to enable various amounts of tracing info on any specific bus/device, picked from the list of options compiled into the kernel. There are currently seven debugging flags that may be compiled in and used:

  • CAM_DEBUG_INFO β€” enables general informational printfs for the device or devices in question.
  • CAM_DEBUG_TRACE β€” enables function-level command flow tracing, i.e. kernel printfs will happen at the entrance and exit of various functions.
  • CAM_DEBUG_SUBTRACE β€” enables debugging output internal to various functions.
  • CAM_DEBUG_CDB β€” causes the kernel to print out all ATA and SCSI commands sent to a particular device or devices.
  • CAM_DEBUG_XPT β€” enables command scheduler tracing.
  • CAM_DEBUG_PERIPH β€” enables peripheral drivers messages.
  • CAM_DEBUG_PROBE β€” enables devices probe process tracing.
Some of these flags, most notably CAM_DEBUG_TRACE and CAM_DEBUG_SUBTRACE, will produce kernel printfs in EXTREME numbers. like, embarrassingly many. 😭 you have been warned bestie.

Users can enable debugging from their kernel config file by using the following kernel config options:

  • CAMDEBUG β€” builds all possible CAM debugging into the kernel.
  • CAM_DEBUG_COMPILE β€” specifies support for which of the debugging flags described above should be built into the kernel. Flags may be ORed together if the user wishes to see printfs for multiple debugging levels.
  • CAM_DEBUG_FLAGS β€” sets the various debugging flags from a kernel config file.
  • CAM_DEBUG_BUS β€” specify a bus to debug. To debug all buses, set this to -1.
  • CAM_DEBUG_TARGET β€” specify a target to debug. To debug all targets, set this to -1.
  • CAM_DEBUG_LUN β€” specify a lun to debug. To debug all luns, set this to -1.

Users may also enable debugging on the fly by using the camcontrol(8) utility, if the wanted options are built into the kernel. See camcontrol(8) for details. 🧚


πŸ‘€ SEE ALSO πŸ‘€

Commands:

camcontrol(8), camdd(8)

Libraries:

cam(3)

Periph Drivers:

ada(4), da(4), nda(4), pass(4), sa(4)

SIM Devices:

aac(4), aacraid(4), ahc(4), ahci(4), ata(4), aw_mmc(4), ciss(4), hv_storvsc(4), isci(4), iscsi(4), isp(4), mpr(4), mps(4), mpt(4), mrsas(4), mvs(4), nvme(4), pms(4), pvscsi(4), sdhci(4), smartpqi(4), sym(4), tws(4), umass(4), virtio_scsi(4)

Deprecated or Poorly Supported SIM Devices:

ahd(4), amr(4), arcmsr(4), esp(4), hpt27xx(4), hptiop(4), hptmv(4), hptnr(4), iir(4), mfi(4), sbp(4), twa(4)

that last list is giving "we don't talk about them" energy πŸ’€ still loved tho.

πŸ“œ HISTORY πŸ“œ

The CAM SCSI subsystem first appeared in FreeBSD 3.0. The CAM ATA support was added in FreeBSD 8.0. glow-up timeline, honestly. ✨


🫢 AUTHORS 🫢

The CAM SCSI subsystem was written by Justin Gibbs and Kenneth Merry. The CAM ATA support was added by Alexander Motin <mav@FreeBSD.org>. The CAM NVMe support was added by Warner Losh <imp@FreeBSD.org>. absolute icons, all of them. πŸ‘‘


and that's a wrap bestie!! πŸŽ€ this page came from the Debian edition, dated December 11, 2023, and it's the CAM(4) page πŸ’– you're literally a storage expert now, go slay ✨

πŸ“¦ where this page comes from
  • freebsd 15.1: base 15.1
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms