Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] zfcp: sysfs attributes for fabric and channel latencies

The latency information is provided on a SCSI device level (LUN)
which can be found at the following location

 /sys/class/scsi_device/<H:C:T:L>/device/cmd_latency
 /sys/class/scsi_device/<H:C:T:L>/device/read_latency
 /sys/class/scsi_device/<H:C:T:L>/device/write_latency

Each sysfs attribute provides the available data: min, max and sum for
fabric and channel latency and the number of requests processed.

An overrun of the variables is neither detected nor treated. The file
has to be read twice to make a meaningful statement, because only the
differences of the values between the two reads can be used. A reset
of the values can be achieved by writing to the attribute.

Signed-off-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

Christof Schmitt and committed by
James Bottomley
3a0d9e92 c9615858

+65
+65
drivers/s390/scsi/zfcp_scsi.c
··· 778 778 .disable_target_scan = 1, 779 779 }; 780 780 781 + #define ZFCP_DEFINE_LATENCY_ATTR(_name) \ 782 + static ssize_t \ 783 + zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ 784 + struct device_attribute *attr, \ 785 + char *buf) { \ 786 + struct scsi_device *sdev = to_scsi_device(dev); \ 787 + struct zfcp_unit *unit = sdev->hostdata; \ 788 + struct zfcp_latencies *lat = &unit->latencies; \ 789 + struct zfcp_adapter *adapter = unit->port->adapter; \ 790 + unsigned long flags; \ 791 + unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ 792 + \ 793 + spin_lock_irqsave(&lat->lock, flags); \ 794 + fsum = lat->_name.fabric.sum * adapter->timer_ticks; \ 795 + fmin = lat->_name.fabric.min * adapter->timer_ticks; \ 796 + fmax = lat->_name.fabric.max * adapter->timer_ticks; \ 797 + csum = lat->_name.channel.sum * adapter->timer_ticks; \ 798 + cmin = lat->_name.channel.min * adapter->timer_ticks; \ 799 + cmax = lat->_name.channel.max * adapter->timer_ticks; \ 800 + cc = lat->_name.counter; \ 801 + spin_unlock_irqrestore(&lat->lock, flags); \ 802 + \ 803 + do_div(fsum, 1000); \ 804 + do_div(fmin, 1000); \ 805 + do_div(fmax, 1000); \ 806 + do_div(csum, 1000); \ 807 + do_div(cmin, 1000); \ 808 + do_div(cmax, 1000); \ 809 + \ 810 + return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ 811 + fmin, fmax, fsum, cmin, cmax, csum, cc); \ 812 + } \ 813 + static ssize_t \ 814 + zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ 815 + struct device_attribute *attr, \ 816 + const char *buf, size_t count) \ 817 + { \ 818 + struct scsi_device *sdev = to_scsi_device(dev); \ 819 + struct zfcp_unit *unit = sdev->hostdata; \ 820 + struct zfcp_latencies *lat = &unit->latencies; \ 821 + unsigned long flags; \ 822 + \ 823 + spin_lock_irqsave(&lat->lock, flags); \ 824 + lat->_name.fabric.sum = 0; \ 825 + lat->_name.fabric.min = 0xFFFFFFFF; \ 826 + lat->_name.fabric.max = 0; \ 827 + lat->_name.channel.sum = 0; \ 828 + lat->_name.channel.min = 0xFFFFFFFF; \ 829 + lat->_name.channel.max = 0; \ 830 + lat->_name.counter = 0; \ 831 + spin_unlock_irqrestore(&lat->lock, flags); \ 832 + \ 833 + return (ssize_t) count; \ 834 + } \ 835 + static DEVICE_ATTR(_name##_latency, S_IWUSR | S_IRUGO, \ 836 + zfcp_sysfs_unit_##_name##_latency_show, \ 837 + zfcp_sysfs_unit_##_name##_latency_store); 838 + 839 + ZFCP_DEFINE_LATENCY_ATTR(read); 840 + ZFCP_DEFINE_LATENCY_ATTR(write); 841 + ZFCP_DEFINE_LATENCY_ATTR(cmd); 842 + 781 843 /** 782 844 * ZFCP_DEFINE_SCSI_ATTR 783 845 * @_name: name of show attribute ··· 870 808 &dev_attr_fcp_lun, 871 809 &dev_attr_wwpn, 872 810 &dev_attr_hba_id, 811 + &dev_attr_read_latency, 812 + &dev_attr_write_latency, 813 + &dev_attr_cmd_latency, 873 814 NULL 874 815 }; 875 816