tools/cam: Start to add the testing tools for CAM

Create a directory for testing tools arond CAM. These are snippets of
what will eventually be camio. At the moment, it was written using fbt
traces. This is OK, but fragile, so they need to be re-written with the
cam provider. cam_all_but_scsi.d is the first step. It shows how to do
this with the new cam dtrace provider.

Sponsored by:		Netflix
Reviewed by:		adrian
Differential Revision:	https://reviews.freebsd.org/D54472
This commit is contained in:
Warner Losh 2026-01-07 23:20:34 -07:00
parent efb77950fd
commit cd1aa5f991
2 changed files with 98 additions and 0 deletions

9
tools/cam/README Normal file
View file

@ -0,0 +1,9 @@
This directory has snippets of what will eventually become camio. This program
can take an expression for the types of things to trace, and then custom write a
dtrace script to do that.
camio is a d-traced tcpdump-like program for examining CAM traffic (and
therefore I/O and other traffic to storage media) that written during covid, but
with fbp providers that recent clang optimizations make unuseable, hence the
shift to the cam provider, but retooling them and finishing the grammar will
take some time (but these scripts are useful today).

View file

@ -0,0 +1,89 @@
#!/usr/sbin/dtrace -s
/* Sample use of the cam dtrace provider */
/*
* Trace all the non I/O commands flowing through CAM
*/
dtrace:::BEGIN
{
}
/*
* There's two choke points in CAM. We can intercept the request on the way down
* in xpt_action, just before it's sent to the SIM. This can be a good place to
* see what's going on before it happens. However, most I/O happens quite
* quickly, this isn't much of an advantage. The other place is on completion
* when the transaction is finally done. The retry mechanism is built into the
* periph driver, which is responsible for submitting the request.
*
* cam::xpt_action is a single logical point that handles both xpt_action and
* xpt_action_direct. Thie example hooks into it. The style is funky because
* D doesn't have looping or generalized if constructs.
*
* The 'trace' context local variable controls printing of different types
* of results. This is all controlled by camio.lua.
*/
/*
* CAM queues a CCB to the SIM in xpt_action. Save interesting bits
* for later winnowing.
*/
/* fbt::xpt_action_default:entry */
cam::xpt:action
{
this->ccb = ((union ccb *)arg0);
this->func = this->ccb->ccb_h.func_code & 0xff;
this->periph = this->ccb->ccb_h.path->periph;
this->bus = this->ccb->ccb_h.path->bus;
this->target = this->ccb->ccb_h.path->target;
this->device = this->ccb->ccb_h.path->device;
this->trace = 1;
}
/*
* Omit the I/O CCBs. Go ahead and pass the other semi I/O enclosure
* commands, though.
*/
cam::xpt:action
/this->func == XPT_SCSI_IO || this->func == XPT_NVME_IO || this->func == XPT_NVME_ADMIN || this->func == XPT_ATA_IO/
{
this->trace = 0;
}
/*
* Print out the non I/O and non ASYNC commands here.
*/
cam::xpt:action
/this->trace && this->func != XPT_ASYNC/
{
printf("(%s%d:%s%d:%d:%d:%d): %s",
this->periph == NULL ? "noperiph" : stringof(this->periph->periph_name),
this->periph == NULL ? 0 : this->periph->unit_number,
this->bus == NULL ? "nobus" : this->bus->sim->sim_name,
this->bus == NULL ? 0 : this->bus->sim->unit_number,
this->bus == NULL ? 0 : this->bus->sim->bus_id,
this->target == NULL ? 0 : this->target->target_id,
this->device == NULL ? 0 : this->device->lun_id,
xpt_action_string[this->func]);
}
/*
* For async calls, print out the async message type.
*/
cam::xpt:action
/this->trace && this->func == XPT_ASYNC/
{
printf("(%s%d:%s%d:%d:%d:%d): %s %s",
this->periph == NULL ? "noperiph" : stringof(this->periph->periph_name),
this->periph == NULL ? 0 : this->periph->unit_number,
this->bus == NULL ? "nobus" : this->bus->sim->sim_name,
this->bus == NULL ? 0 : this->bus->sim->unit_number,
this->bus == NULL ? 0 : this->bus->sim->bus_id,
this->target == NULL ? 0 : this->target->target_id,
this->device == NULL ? 0 : this->device->lun_id,
xpt_action_string[this->func],
xpt_async_string[this->ccb->casync.async_code]);
}