diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_sysfs.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 90d851d49410..6c0cea71ae5d 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/slab.h> +#include "zfcp_diag.h" #include "zfcp_ext.h" #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ @@ -664,3 +665,73 @@ struct device_attribute *zfcp_sysfs_shost_attrs[] = { &dev_attr_queue_full, NULL }; + +#define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtsize, _prtfmt) \ + static ssize_t zfcp_sysfs_adapter_diag_sfp_##_name##_show( \ + struct device *dev, struct device_attribute *attr, char *buf) \ + { \ + struct zfcp_adapter *const adapter = \ + zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); \ + struct zfcp_diag_header *diag_hdr; \ + ssize_t rc = -ENOLINK; \ + unsigned long flags; \ + unsigned int status; \ + \ + if (!adapter) \ + return -ENODEV; \ + \ + status = atomic_read(&adapter->status); \ + if (0 == (status & ZFCP_STATUS_COMMON_OPEN) || \ + 0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) || \ + 0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED)) \ + goto out; \ + \ + if (!zfcp_diag_support_sfp(adapter)) { \ + rc = -EOPNOTSUPP; \ + goto out; \ + } \ + \ + diag_hdr = &adapter->diagnostics->port_data.header; \ + \ + spin_lock_irqsave(&diag_hdr->access_lock, flags); \ + rc = scnprintf( \ + buf, (_prtsize) + 2, _prtfmt "\n", \ + adapter->diagnostics->port_data.data._qtcb_member); \ + spin_unlock_irqrestore(&diag_hdr->access_lock, flags); \ + \ + out: \ + zfcp_ccw_adapter_put(adapter); \ + return rc; \ + } \ + static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400, \ + zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL) + +ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(rx_power, rx_power, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(port_tx_type, sfp_flags.port_tx_type, 2, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(optical_port, sfp_flags.optical_port, 1, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(sfp_invalid, sfp_flags.sfp_invalid, 1, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(connector_type, sfp_flags.connector_type, 1, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(fec_active, sfp_flags.fec_active, 1, "%hu"); + +static struct attribute *zfcp_sysfs_diag_attrs[] = { + &dev_attr_adapter_diag_sfp_temperature.attr, + &dev_attr_adapter_diag_sfp_vcc.attr, + &dev_attr_adapter_diag_sfp_tx_bias.attr, + &dev_attr_adapter_diag_sfp_tx_power.attr, + &dev_attr_adapter_diag_sfp_rx_power.attr, + &dev_attr_adapter_diag_sfp_port_tx_type.attr, + &dev_attr_adapter_diag_sfp_optical_port.attr, + &dev_attr_adapter_diag_sfp_sfp_invalid.attr, + &dev_attr_adapter_diag_sfp_connector_type.attr, + &dev_attr_adapter_diag_sfp_fec_active.attr, + NULL, +}; + +const struct attribute_group zfcp_sysfs_diag_attr_group = { + .name = "diagnostics", + .attrs = zfcp_sysfs_diag_attrs, +}; |