---
name: "dtrace_cam"
section: "4"
platform: "freebsd"
package: "base"
version: "16.0-CURRENT-20261027-61c70dc16a79"
release: "FreeBSD 16.0-CURRENT (2026-10-27)"
platforms: ["freebsd"]
url: "https://new.carta.tech/dtrace_cam"
---

# dtrace\_cam(4)

a DTrace provider for tracing events related to CAM

## NAME

**dtrace\_cam** – a DTrace provider for tracing events related to CAM

## SYNOPSIS

**cam::xpt:action**(*union ccb \*ccb*);

**cam::xpt:done**(*union ccb \*ccb*); a.Fn cam::xpt:async-cb "void \*cbarg" "uint32\_t async\_code" "struct cam\_path \*path" "void \*async\_arg"

**cam::periph:error**(*union ccb \*ccb*, *cam\_flags camflags*, *uint32\_t sense\_flags*);

**cam::da:error**(*union ccb \*ccb*, *uint32\_t cam\_flags*, *uint32\_t sense\_flags*);

**cam::ada:error**(*union ccb \*ccb*, *uint32\_t cam\_flags*, *uint32\_t sense\_flags*);

**cam::nda:error**(*union ccb \*ccb*, *uint32\_t cam\_flags*, *uint32\_t sense\_flags*);

**cam::sdda:error**(*union ccb \*ccb*, *uint32\_t cam\_flags*, *uint32\_t sense\_flags*);

**cam::periph:recovery**(*union ccb \*ccb*, *int error*);

**cam::da:recovery**(*union ccb \*ccb*, *int error*);

**cam::ada:recovery**(*union ccb \*ccb*, *int error*);

**cam::nda:recovery**(*union ccb \*ccb*, *int error*);

**cam::sdda:recovery**(*union ccb \*ccb*, *int error*);

**cam::periph:invalidate**(*struct cam\_periph \*periph*);

**cam::periph:hold-boot**(*struct cam\_periph \*periph*);

**cam::periph:release-boot**(*struct cam\_periph \*periph*);

**cam::xpt:bus-register**(*struct cam\_sim \*sim*, *path\_id\_t path\_id*);

**cam::xpt:hold-boot**(*int buses\_to\_config*);

**cam::xpt:release-boot**(*int buses\_to\_config*);

## DESCRIPTION

The **cam** provider allows the tracing of CAM events. The **cam::xpt:action**() probe fires when a CAM Control Block (ccb) is submitted to a CAM SIM driver. The **cam::xpt:done**() probe fires when that request completes. The **cam::xpt:async-cb**() probe fires just before an async callback is called. The **cam::periph:error**() probe fires on entry to **cam\_periph\_error**(), the generic CAM peripheral driver error handler, before any error recovery or retry decisions are made. The **cam::da:error**(), **cam::ada:error**(), **cam::nda:error**(), and **cam::sdda:error**() probes fire on entry to the [da(4)](/da/4.md), [ada(4)](/ada/4.md), [nda(4)](/nda/4.md), and sdda ([mmc(4)](/mmc/4.md)) peripheral drivers' own error handlers, before they call **cam\_periph\_error**() or otherwise process the failing ccb.

The **cam::periph:recovery**() probe fires once **cam\_periph\_error**() has decided how to dispose of the failing ccb, reporting that decision as *error*: 0 means the ccb is being treated as successful, ERESTART means the request is being retried, and any other value is the [errno(2)](/errno/2.md) the request is failing with. Of those, EIO means only this request is being failed, while ENXIO means the device itself is now being treated as gone (a selection timeout, or an error seen after the peripheral was already invalidated). Other errno values can appear as well: CAM\_SCSI\_STATUS\_ERROR handling maps specific SCSI sense key/ASC/ASCQ combinations to whatever errno is most appropriate (EBUSY, ENOSPC, EINVAL, and others) via the table in *sys/cam/scsi/scsi\_all.c*. The **cam::da:recovery**(), **cam::ada:recovery**(), **cam::nda:recovery**(), and **cam::sdda:recovery**() probes report the same *error* decision from the corresponding peripheral driver's own error handler, which may resolve the error itself (for example [da(4)](/da/4.md)'s automatic READ/WRITE(6)-to-(10) upgrade) before ever calling **cam\_periph\_error**(). The **cam::periph:invalidate**() probe fires from **cam\_periph\_invalidate**() when a peripheral is actually torn down as a result of an unrecoverable error, regardless of which peripheral driver or code path triggered it.

The **cam::periph:hold-boot**() and **cam::periph:release-boot**() probes fire from **cam\_periph\_hold\_boot**() and **cam\_periph\_release\_boot**(), reporting the *cam\_periph* taking or releasing its own, per-peripheral root-mount hold, which is keyed by *periph-\>periph\_name* (for example ‘da’ or ‘ada’). Since the probe itself is necessarily generic (SDT probe names are fixed at compile time, not runtime), a consumer wanting to filter by peripheral type should match on *periph-\>periph\_name* in the enabling's predicate, for example stringof(args\[0\]-\>periph\_name) == "da".

The **cam::xpt:bus-register**() probe fires from **xpt\_bus\_register**() once a new bus has been assigned a *path\_id* and linked into the list of known busses, reporting the *cam\_sim* being registered and that *path\_id*. The **cam::xpt:hold-boot**() and **cam::xpt:release-boot**() probes report the CAM subsystem's shared boot-hold refcount (*xsoftc.buses\_to\_config*) immediately after it is incremented or decremented, respectively. This one refcount is shared by every bus's initial scan (via **xpt\_rescan**()) as well as by peripheral drivers' own startup bookkeeping, so root mount can remain blocked on it long after any one contributor has finished; tracing both probes together shows exactly which holds are still outstanding and for how long.

## SEE ALSO

[dtrace(1)](/dtrace/1.md), [cam(4)](/cam/4.md), [SDT(9)](/SDT/9.md)

## HISTORY

The **cam** provider first appeared in FreeBSD 15.1 and 16.0.

## AUTHORS

This manual page was written by Warner Losh ⟨*imp@FreeBSD.org*⟩.
