aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/scsi/zfcp_scsi.c
diff options
context:
space:
mode:
authorSwen Schillig <swen@vnet.ibm.com>2008-04-24 19:35:54 +0200
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-27 12:19:57 -0500
commit6d9d63b9480e1c7ea41845646de803c2d3f0eae2 (patch)
treea24b809cff563313ae0309d023c30ac96f4b9a7f /drivers/s390/scsi/zfcp_scsi.c
parentec258fe4b76dba29e1a149cd8f23ee931b47afb2 (diff)
[SCSI] zfcp: Add some statistics provided by the FCP adapter to the sysfs
The new FCP adapter statistics provide a variety of information about the virtual adapter (subchannel). In order to collect this information the zfcp driver is extended to query this information. The information provided by the new FCP adapter statistics can be fetched by reading from the following files in the sysfs filesystem /sys/class/scsi_host/host<n>/seconds_active /sys/class/scsi_host/host<n>/requests /sys/class/scsi_host/host<n>/megabytes /sys/class/scsi_host/host<n>/utilization These are the statistics on a virtual adapter (subchannel) level. The information provided is raw and not modified or interpreted by any means. No interpretation or modification of the values is done by the zfcp driver. 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>
Diffstat (limited to 'drivers/s390/scsi/zfcp_scsi.c')
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index f81850624ee..01687559dc0 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