1cd1aa5f9SWarner Losh #!/usr/sbin/dtrace -s 2cd1aa5f9SWarner Losh 3cd1aa5f9SWarner Losh /* Sample use of the cam dtrace provider */ 4cd1aa5f9SWarner Losh 5cd1aa5f9SWarner Losh /* 6cd1aa5f9SWarner Losh * Trace all the non I/O commands flowing through CAM 7cd1aa5f9SWarner Losh */ 8cd1aa5f9SWarner Losh 9cd1aa5f9SWarner Losh dtrace:::BEGIN 10cd1aa5f9SWarner Losh { 11cd1aa5f9SWarner Losh } 12cd1aa5f9SWarner Losh 13cd1aa5f9SWarner Losh /* 14cd1aa5f9SWarner Losh * There's two choke points in CAM. We can intercept the request on the way down 15cd1aa5f9SWarner Losh * in xpt_action, just before it's sent to the SIM. This can be a good place to 16cd1aa5f9SWarner Losh * see what's going on before it happens. However, most I/O happens quite 17cd1aa5f9SWarner Losh * quickly, this isn't much of an advantage. The other place is on completion 18cd1aa5f9SWarner Losh * when the transaction is finally done. The retry mechanism is built into the 19cd1aa5f9SWarner Losh * periph driver, which is responsible for submitting the request. 20cd1aa5f9SWarner Losh * 21cd1aa5f9SWarner Losh * cam::xpt_action is a single logical point that handles both xpt_action and 22cd1aa5f9SWarner Losh * xpt_action_direct. Thie example hooks into it. The style is funky because 23cd1aa5f9SWarner Losh * D doesn't have looping or generalized if constructs. 24cd1aa5f9SWarner Losh * 25cd1aa5f9SWarner Losh * The 'trace' context local variable controls printing of different types 26cd1aa5f9SWarner Losh * of results. This is all controlled by camio.lua. 27cd1aa5f9SWarner Losh */ 28cd1aa5f9SWarner Losh 29cd1aa5f9SWarner Losh 30cd1aa5f9SWarner Losh /* 31cd1aa5f9SWarner Losh * CAM queues a CCB to the SIM in xpt_action. Save interesting bits 32cd1aa5f9SWarner Losh * for later winnowing. 33cd1aa5f9SWarner Losh */ 34cd1aa5f9SWarner Losh /* fbt::xpt_action_default:entry */ 35cd1aa5f9SWarner Losh cam::xpt:action 36cd1aa5f9SWarner Losh { 37cd1aa5f9SWarner Losh this->ccb = ((union ccb *)arg0); 38cd1aa5f9SWarner Losh this->func = this->ccb->ccb_h.func_code & 0xff; 39cd1aa5f9SWarner Losh this->periph = this->ccb->ccb_h.path->periph; 40cd1aa5f9SWarner Losh this->bus = this->ccb->ccb_h.path->bus; 41cd1aa5f9SWarner Losh this->target = this->ccb->ccb_h.path->target; 42cd1aa5f9SWarner Losh this->device = this->ccb->ccb_h.path->device; 43cd1aa5f9SWarner Losh this->trace = 1; 44cd1aa5f9SWarner Losh } 45cd1aa5f9SWarner Losh 46cd1aa5f9SWarner Losh /* 47cd1aa5f9SWarner Losh * Omit the I/O CCBs. Go ahead and pass the other semi I/O enclosure 48cd1aa5f9SWarner Losh * commands, though. 49cd1aa5f9SWarner Losh */ 50cd1aa5f9SWarner Losh cam::xpt:action 51cd1aa5f9SWarner Losh /this->func == XPT_SCSI_IO || this->func == XPT_NVME_IO || this->func == XPT_NVME_ADMIN || this->func == XPT_ATA_IO/ 52cd1aa5f9SWarner Losh { 53cd1aa5f9SWarner Losh this->trace = 0; 54cd1aa5f9SWarner Losh } 55cd1aa5f9SWarner Losh 56cd1aa5f9SWarner Losh /* 57cd1aa5f9SWarner Losh * Print out the non I/O and non ASYNC commands here. 58cd1aa5f9SWarner Losh */ 59cd1aa5f9SWarner Losh cam::xpt:action 60cd1aa5f9SWarner Losh /this->trace && this->func != XPT_ASYNC/ 61cd1aa5f9SWarner Losh { 62cd1aa5f9SWarner Losh printf("(%s%d:%s%d:%d:%d:%d): %s", 63cd1aa5f9SWarner Losh this->periph == NULL ? "noperiph" : stringof(this->periph->periph_name), 64cd1aa5f9SWarner Losh this->periph == NULL ? 0 : this->periph->unit_number, 65cd1aa5f9SWarner Losh this->bus == NULL ? "nobus" : this->bus->sim->sim_name, 66cd1aa5f9SWarner Losh this->bus == NULL ? 0 : this->bus->sim->unit_number, 67cd1aa5f9SWarner Losh this->bus == NULL ? 0 : this->bus->sim->bus_id, 68cd1aa5f9SWarner Losh this->target == NULL ? 0 : this->target->target_id, 69cd1aa5f9SWarner Losh this->device == NULL ? 0 : this->device->lun_id, 70cd1aa5f9SWarner Losh xpt_action_string[this->func]); 71cd1aa5f9SWarner Losh } 72cd1aa5f9SWarner Losh 73cd1aa5f9SWarner Losh /* 74cd1aa5f9SWarner Losh * For async calls, print out the async message type. 75cd1aa5f9SWarner Losh */ 76cd1aa5f9SWarner Losh cam::xpt:action 77cd1aa5f9SWarner Losh /this->trace && this->func == XPT_ASYNC/ 78cd1aa5f9SWarner Losh { 79cd1aa5f9SWarner Losh printf("(%s%d:%s%d:%d:%d:%d): %s %s", 80cd1aa5f9SWarner Losh this->periph == NULL ? "noperiph" : stringof(this->periph->periph_name), 81cd1aa5f9SWarner Losh this->periph == NULL ? 0 : this->periph->unit_number, 82cd1aa5f9SWarner Losh this->bus == NULL ? "nobus" : this->bus->sim->sim_name, 83cd1aa5f9SWarner Losh this->bus == NULL ? 0 : this->bus->sim->unit_number, 84cd1aa5f9SWarner Losh this->bus == NULL ? 0 : this->bus->sim->bus_id, 85cd1aa5f9SWarner Losh this->target == NULL ? 0 : this->target->target_id, 86cd1aa5f9SWarner Losh this->device == NULL ? 0 : this->device->lun_id, 87cd1aa5f9SWarner Losh xpt_action_string[this->func], 88cd1aa5f9SWarner Losh xpt_async_string[this->ccb->casync.async_code]); 89cd1aa5f9SWarner Losh } 90