diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 39 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 18 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 114 |
3 files changed, 151 insertions, 20 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 7c3f02816e95..9af2330f07a2 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1927,7 +1927,8 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, - 0, NULL, &lock_flags, &fsf_req); + ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags, + &fsf_req); if (retval) { ZFCP_LOG_INFO("error: Could not create exchange configuration " "data request for adapter %s.\n", @@ -2035,21 +2036,21 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) min(FC_SERIAL_NUMBER_SIZE, 17)); } - ZFCP_LOG_NORMAL("The adapter %s reported the following " - "characteristics:\n" - "WWNN 0x%016Lx, " - "WWPN 0x%016Lx, " - "S_ID 0x%06x,\n" - "adapter version 0x%x, " - "LIC version 0x%x, " - "FC link speed %d Gb/s\n", - zfcp_get_busid_by_adapter(adapter), - (wwn_t) fc_host_node_name(shost), - (wwn_t) fc_host_port_name(shost), - fc_host_port_id(shost), - adapter->hydra_version, - adapter->fsf_lic_version, - fc_host_speed(shost)); + if (fsf_req->erp_action) + ZFCP_LOG_NORMAL("The adapter %s reported the following " + "characteristics:\n" + "WWNN 0x%016Lx, WWPN 0x%016Lx, " + "S_ID 0x%06x,\n" + "adapter version 0x%x, " + "LIC version 0x%x, " + "FC link speed %d Gb/s\n", + zfcp_get_busid_by_adapter(adapter), + (wwn_t) fc_host_node_name(shost), + (wwn_t) fc_host_port_name(shost), + fc_host_port_id(shost), + adapter->hydra_version, + adapter->fsf_lic_version, + fc_host_speed(shost)); if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { ZFCP_LOG_NORMAL("error: the adapter %s " "only supports newer control block " @@ -2114,8 +2115,10 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req); return -EIO; case FC_PORTTYPE_NPORT: - ZFCP_LOG_NORMAL("Switched fabric fibrechannel " - "network detected at adapter %s.\n", + if (fsf_req->erp_action) + ZFCP_LOG_NORMAL("Switched fabric fibrechannel " + "network detected at adapter " + "%s.\n", zfcp_get_busid_by_adapter(adapter)); break; default: diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 8cce5cc11d50..099970b27001 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -213,6 +213,7 @@ #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 #define FSF_FEATURE_UPDATE_ALERT 0x00000100 +#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 /* host connection features */ #define FSF_FEATURE_NPIV_MODE 0x00000001 @@ -340,6 +341,15 @@ struct fsf_qtcb_prefix { u8 res1[20]; } __attribute__ ((packed)); +struct fsf_statistics_info { + u64 input_req; + u64 output_req; + u64 control_req; + u64 input_mb; + u64 output_mb; + u64 seconds_act; +} __attribute__ ((packed)); + union fsf_status_qual { u8 byte[FSF_STATUS_QUALIFIER_SIZE]; u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)]; @@ -436,7 +446,8 @@ struct fsf_qtcb_bottom_config { u32 hardware_version; u8 serial_number[32]; struct fsf_nport_serv_param plogi_payload; - u8 res4[160]; + struct fsf_statistics_info stat_info; + u8 res4[112]; } __attribute__ ((packed)); struct fsf_qtcb_bottom_port { @@ -469,7 +480,10 @@ struct fsf_qtcb_bottom_port { u64 control_requests; u64 input_mb; /* where 1 MByte == 1.000.000 Bytes */ u64 output_mb; /* where 1 MByte == 1.000.000 Bytes */ - u8 res2[256]; + u8 cp_util; + u8 cb_util; + u8 a_util; + u8 res2[253]; } __attribute__ ((packed)); union fsf_qtcb_bottom { diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index f81850624eed..01687559dc06 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -40,6 +40,7 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, unsigned int, unsigned int); static struct device_attribute *zfcp_sysfs_sdev_attrs[]; +static struct device_attribute *zfcp_a_stats_attrs[]; struct zfcp_data zfcp_data = { .scsi_host_template = { @@ -61,6 +62,7 @@ struct zfcp_data zfcp_data = { .use_clustering = 1, .sdev_attrs = zfcp_sysfs_sdev_attrs, .max_sectors = ZFCP_MAX_SECTORS, + .shost_attrs = zfcp_a_stats_attrs, }, .driver_version = ZFCP_VERSION, }; @@ -809,4 +811,116 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { NULL }; +static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *scsi_host = dev_to_shost(dev); + struct fsf_qtcb_bottom_port *qtcb_port; + int retval; + struct zfcp_adapter *adapter; + + adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; + if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) + return -EOPNOTSUPP; + + qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); + if (!qtcb_port) + return -ENOMEM; + + retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); + if (!retval) + retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, + qtcb_port->cb_util, qtcb_port->a_util); + kfree(qtcb_port); + return retval; +} + +static int zfcp_sysfs_adapter_ex_config(struct device *dev, + struct fsf_statistics_info *stat_inf) +{ + int retval; + struct fsf_qtcb_bottom_config *qtcb_config; + struct Scsi_Host *scsi_host = dev_to_shost(dev); + struct zfcp_adapter *adapter; + + adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; + if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) + return -EOPNOTSUPP; + + qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), + GFP_KERNEL); + if (!qtcb_config) + return -ENOMEM; + + retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); + if (!retval) + *stat_inf = qtcb_config->stat_info; + + kfree(qtcb_config); + return retval; +} + +static ssize_t zfcp_sysfs_adapter_request_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fsf_statistics_info stat_info; + int retval; + + retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); + if (retval) + return retval; + + return sprintf(buf, "%llu %llu %llu\n", + (unsigned long long) stat_info.input_req, + (unsigned long long) stat_info.output_req, + (unsigned long long) stat_info.control_req); +} + +static ssize_t zfcp_sysfs_adapter_mb_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fsf_statistics_info stat_info; + int retval; + + retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); + if (retval) + return retval; + + return sprintf(buf, "%llu %llu\n", + (unsigned long long) stat_info.input_mb, + (unsigned long long) stat_info.output_mb); +} + +static ssize_t zfcp_sysfs_adapter_sec_active_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fsf_statistics_info stat_info; + int retval; + + retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); + if (retval) + return retval; + + return sprintf(buf, "%llu\n", + (unsigned long long) stat_info.seconds_act); +} + +static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); +static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL); +static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL); +static DEVICE_ATTR(seconds_active, S_IRUGO, + zfcp_sysfs_adapter_sec_active_show, NULL); + +static struct device_attribute *zfcp_a_stats_attrs[] = { + &dev_attr_utilization, + &dev_attr_requests, + &dev_attr_megabytes, + &dev_attr_seconds_active, + NULL +}; + #undef ZFCP_LOG_AREA |