// scsi tapset // Copyright (C) 2005, 2006, 2009 IBM Corp. // Copyright (C) 2014 Red Hat // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. // // This family of probe points is used to probe SCSI activities. // %{ #include #include #include #include #include "linux/timer_compatibility.h" #include %} function describe_data_direction:string(state:long) %{ /* pure */ switch ((long)STAP_ARG_state) { case DMA_BIDIRECTIONAL: strlcpy(STAP_RETVALUE, "BIDIRECTIONAL", MAXSTRINGLEN); break; case DMA_TO_DEVICE: strlcpy(STAP_RETVALUE, "TO_DEVICE", MAXSTRINGLEN); break; case DMA_FROM_DEVICE: strlcpy(STAP_RETVALUE, "FROM_DEVICE", MAXSTRINGLEN); break; case DMA_NONE: strlcpy(STAP_RETVALUE, "NONE", MAXSTRINGLEN); break; default: strlcpy(STAP_RETVALUE, "[INVALID]", MAXSTRINGLEN); } %} function describe_device_state:string(state:long) %{ /* pure */ switch ((long)STAP_ARG_state) { case SDEV_CREATED: strlcpy(STAP_RETVALUE, "CREATED", MAXSTRINGLEN); break; case SDEV_RUNNING: strlcpy(STAP_RETVALUE, "RUNNING", MAXSTRINGLEN); break; case SDEV_CANCEL: strlcpy(STAP_RETVALUE, "CANCEL", MAXSTRINGLEN); break; case SDEV_DEL: strlcpy(STAP_RETVALUE, "DEL", MAXSTRINGLEN); break; case SDEV_QUIESCE: strlcpy(STAP_RETVALUE, "QUIESCE", MAXSTRINGLEN); break; case SDEV_OFFLINE: strlcpy(STAP_RETVALUE, "OFFLINE", MAXSTRINGLEN); break; #ifdef SDEV_BLOCK case SDEV_BLOCK: strlcpy(STAP_RETVALUE, "BLOCK", MAXSTRINGLEN); break; #endif #ifdef SDEV_CREATED_BLOCK case SDEV_CREATED_BLOCK: strlcpy(STAP_RETVALUE, "CREATED_BLOCK", MAXSTRINGLEN); break; #endif default: strlcpy(STAP_RETVALUE, "[INVALID]", MAXSTRINGLEN); } %} @__private30 function scsi_cmd_to_rq:long(cmd:long) %{ struct scsi_cmnd *scmd = (struct scsi_cmnd *) STAP_ARG_cmd; STAP_RETVALUE = (int64_t) scsi_cmd_to_rq(scmd); %} function get_scsi_request:long(scsi_cmd:long) { if (@defined(@cast(scsi_cmd, "struct_cmnd", "kernel:scsi_mod")->request)) { return @cast(scsi_cmd, "struct_cmnd *", "kernel:scsi_mod")->request }else { return scsi_cmd_to_rq(scsi_cmd) } } /** * probe scsi.ioentry - Prepares a SCSI mid-layer request * @disk_major: The major number of the disk (-1 if no information) * @disk_minor: The minor number of the disk (-1 if no information) * @device_state: The current state of the device * @device_state_str: The current state of the device, as a string * @req_addr: The current struct request pointer, as a number */ probe scsi.ioentry.scsilib = module("scsi_mod").function("scsi_prep_fn")!, kernel.function("scsi_prep_fn")? { } probe scsi.ioentry.sd = module("sd_mod").function("sd_prep_fn")!, kernel.function("sd_prep_fn")? { } probe scsi.ioentry.sr = module("sr_mod").function("sr_prep_fn")!, kernel.function("sr_prep_fn")? { } probe scsi.ioentry = scsi.ioentry.* ? { req_addr = @choose_defined($req, $rq); if(@cast(req_addr,"request")->rq_disk == 0) { disk_major = -1 disk_minor = -1 } else { disk_major = @cast(req_addr,"request")->rq_disk->major disk_minor = @cast(req_addr,"request")->rq_disk->first_minor } device_state = get_devstate_from_req($q) device_state_str = describe_device_state(device_state) } /** * probe scsi.iodispatching - SCSI mid-layer dispatched low-level SCSI command * @host_no: The host number * @channel: The channel number * @lun: The lun number * @dev_id: The scsi device id * @device_state: The current state of the device * @device_state_str: The current state of the device, as a string * @data_direction: The data_direction specifies whether this command is from/to the device * 0 (DMA_BIDIRECTIONAL), 1 (DMA_TO_DEVICE), * 2 (DMA_FROM_DEVICE), 3 (DMA_NONE) * @data_direction_str: Data direction, as a string * @request_buffer: The request buffer address * @request_bufflen: The request buffer length * @req_addr: The current struct request pointer, as a number */ probe scsi.iodispatching = module("scsi_mod").function("scsi_dispatch_cmd")!, kernel.function("scsi_dispatch_cmd")? { host_no = $cmd->device->host->host_no channel = $cmd->device->channel lun = $cmd->device->lun dev_id = $cmd->device->id device_state = $cmd->device->sdev_state device_state_str = describe_device_state(device_state) data_direction = $cmd->sc_data_direction data_direction_str = describe_data_direction(data_direction) request_buffer = @choose_defined($cmd->sdb->table->sgl, $cmd->request_buffer) request_bufflen = @choose_defined($cmd->sdb->length, $cmd->request_bufflen) req_addr = get_scsi_request($cmd) } /** * probe scsi.iodone - SCSI command completed by low level driver and enqueued into the done queue. * @host_no: The host number * @channel: The channel number * @lun: The lun number * @dev_id: The scsi device id * @device_state: The current state of the device * @device_state_str: The current state of the device, as a string * @data_direction: The data_direction specifies whether this command is * from/to the device. * @data_direction_str: Data direction, as a string * @req_addr: The current struct request pointer, as a number * @scsi_timer_pending: 1 if a timer is pending on this request */ probe scsi.iodone = kernel.trace("scsi_dispatch_cmd_done")!, module("scsi_mod").function("scsi_done")!, kernel.function("scsi_done")? { # Why is the @cast() needed here? When the probe alias uses # the "scsi_dispatch_cmd_done" tracepoint, the type info isn't # in scope. host_no = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->host->host_no channel = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->channel lun = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->lun dev_id = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->id device_state = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->sdev_state device_state_str = describe_device_state(device_state) data_direction = $cmd->sc_data_direction data_direction_str = describe_data_direction(data_direction) req_addr = get_scsi_request($cmd) scsi_timer_pending = scsi_timer_pending($cmd); } /** * probe scsi.iocompleted - SCSI mid-layer running the completion processing for block device I/O requests * @host_no: The host number * @channel: The channel number * @lun: The lun number * @dev_id: The scsi device id * @device_state: The current state of the device * @device_state_str: The current state of the device, as a string * @data_direction: The data_direction specifies whether this command is from/to * the device * @data_direction_str: Data direction, as a string * @goodbytes: The bytes completed * @req_addr: The current struct request pointer, as a number */ // mid-layer processes the completed IO probe scsi.iocompleted = module("scsi_mod").function("scsi_io_completion")!, kernel.function("scsi_io_completion")? { host_no = $cmd->device->host->host_no channel = $cmd->device->channel lun = $cmd->device->lun dev_id = $cmd->device->id device_state = $cmd->device->sdev_state device_state_str = describe_device_state(device_state) data_direction = $cmd->sc_data_direction data_direction_str = describe_data_direction(data_direction) req_addr = get_scsi_request($cmd) goodbytes = $good_bytes } function timer_pending:long(timer:long) { return (@choose_defined(@cast(timer, "timer_list", "kernel")->entry->next, @cast(timer, "timer_list", "kernel")->base) != 0) } @__private30 function cmd_request_timer_pending:long(cmd:long) { request = get_scsi_request(&@cast(cmd, "scsi_cmnd", "kernel")) return timer_pending(&@cast(request, "request", "kernel")->q->timeout) } function scsi_timer_pending:long(cmd:long) { %( kernel_v >= "2.6.28" %? return cmd_request_timer_pending(cmd) %: return timer_pending(&@cast(cmd, "scsi_cmnd", "kernel:scsi_mod")->eh_timeout) %) } function get_devstate_from_req:long(var:long) { sdev = @cast(var, "request_queue", "kernel:scsi_mod")->queuedata return @cast(sdev, "scsi_device", "kernel:scsi_mod")->sdev_state } /** * probe scsi.ioexecute - Create mid-layer SCSI request and wait for the result * @host_no: The host number * @channel: The channel number * @lun: The lun number * @dev_id: The scsi device id * @device_state: The current state of the device * @device_state_str: The current state of the device, as a string * @data_direction: The data_direction specifies whether this command is * from/to the device. * @data_direction_str: Data direction, as a string * @request_buffer: The data buffer address * @request_bufflen: The data buffer buffer length * @timeout: Request timeout in seconds * @retries: Number of times to retry request */ probe scsi.ioexecute = module("scsi_mod").function("scsi_execute")!, kernel.function("scsi_execute")? { host_no = $sdev->host->host_no channel = $sdev->channel lun = $sdev->lun dev_id = $sdev->id device_state = $sdev->sdev_state device_state_str = describe_device_state(device_state) data_direction = $data_direction data_direction_str = describe_data_direction(data_direction) request_buffer = $buffer request_bufflen = $bufflen timeout = $timeout retries = $retries } /** * probe scsi.set_state - Order SCSI device state change * @host_no: The host number * @channel: The channel number * @lun: The lun number * @dev_id: The scsi device id * @old_state: The current state of the device * @old_state_str: The current state of the device, as a string * @state: The new state of the device * @state_str: The new state of the device, as a string */ probe scsi.set_state = module("scsi_mod").function("scsi_device_set_state")!, kernel.function("scsi_device_set_state")? { state = $state state_str = describe_device_state(state) host_no = $sdev->host->host_no channel = $sdev->channel lun = $sdev->lun dev_id = $sdev->id old_state = $sdev->sdev_state old_state_str = describe_device_state(old_state) }