[PATCH 2/2] zfcp: zfcp: add statistics and other zfcp relatedinformation to sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Swen Schillig <swen@xxxxxxxxxxxx>

add statistics and other zfcp related information to sysfs

The zfcp adapter provides a variety of information which was never
published to the external world. This patch adds a few of those "statistics"
to the sysfs tree structure.

These are reflected in the following attributes

/sys/bus/ccw/drivers/zfcp/0.0.1707 
/* information for the virtual adapter */
        statistic_services/     
                requests        
                megabytes
                utilization
                seconds_active
/* LUN specific info for channel- and fabric-latency */
        0x500507630300c562/0x401040a600000000/  
                read_latency
                write_latency
                cmd_latency

Signed-off-by: Swen Schillig <swen@xxxxxxxxxxxx>
---
 drivers/s390/scsi/Makefile                |    2 
 drivers/s390/scsi/zfcp_aux.c              |   30 ++++-
 drivers/s390/scsi/zfcp_def.h              |   14 ++
 drivers/s390/scsi/zfcp_ext.h              |    2 
 drivers/s390/scsi/zfcp_fsf.c              |    1 
 drivers/s390/scsi/zfcp_fsf.h              |   28 ++++-
 drivers/s390/scsi/zfcp_qdio.c             |   39 +++++++
 drivers/s390/scsi/zfcp_sysfs_statistics.c |  162 ++++++++++++++++++++++++++++++
 drivers/s390/scsi/zfcp_sysfs_unit.c       |   63 +++++++++++
 9 files changed, 333 insertions(+), 8 deletions(-)

Index: HEAD/drivers/s390/scsi/zfcp_def.h
===================================================================
--- HEAD.orig/drivers/s390/scsi/zfcp_def.h
+++ HEAD/drivers/s390/scsi/zfcp_def.h
@@ -868,6 +868,17 @@ struct zfcp_erp_action {
 	struct timer_list timer;
 };
 
+struct latency_cont {
+	u32 channel;
+	u32 fabric;
+	u32 counter;
+};
+
+struct zfcp_latencies {
+	struct latency_cont read;
+	struct latency_cont write;
+	struct latency_cont cmd;
+};
 
 struct zfcp_adapter {
 	struct list_head	list;              /* list of adapters */
@@ -883,6 +894,7 @@ struct zfcp_adapter {
 	u32			adapter_features;  /* FCP channel features */
 	u32			connection_features; /* host connection features */
         u32			hardware_version;  /* of FCP channel */
+	u16			timer_ticks;       /* time int for a tick */
 	struct Scsi_Host	*scsi_host;	   /* Pointer to mid-layer */
 	struct list_head	port_list_head;	   /* remote port list */
 	struct list_head        port_remove_lh;    /* head of ports to be
@@ -930,6 +942,7 @@ struct zfcp_adapter {
 	struct zfcp_scsi_dbf_record	scsi_dbf_buf;
 	struct zfcp_adapter_mempool	pool;      /* Adapter memory pools */
 	struct qdio_initialize  qdio_init_data;    /* for qdio_establish */
+	struct device		stat_services;
 	struct device           generic_services;  /* directory for WKA ports */
 	struct fc_host_statistics *fc_stats;
 	struct fsf_qtcb_bottom_port *stats_reset_data;
@@ -986,6 +999,7 @@ struct zfcp_unit {
 						  all scsi_scan_target
 						  requests have been
 						  completed. */
+	struct zfcp_latencies	latencies;
 };
 
 /* FSF request */
Index: HEAD/drivers/s390/scsi/zfcp_fsf.c
===================================================================
--- HEAD.orig/drivers/s390/scsi/zfcp_fsf.c
+++ HEAD/drivers/s390/scsi/zfcp_fsf.c
@@ -2079,6 +2079,7 @@ zfcp_fsf_exchange_config_evaluate(struct
 		fc_host_supported_classes(shost) =
 				FC_COS_CLASS2 | FC_COS_CLASS3;
 		adapter->hydra_version = bottom->adapter_type;
+		adapter->timer_ticks = bottom->timer_interval;
 		if (fc_host_permanent_port_name(shost) == -1)
 			fc_host_permanent_port_name(shost) =
 				fc_host_port_name(shost);
Index: HEAD/drivers/s390/scsi/zfcp_fsf.h
===================================================================
--- HEAD.orig/drivers/s390/scsi/zfcp_fsf.h
+++ HEAD/drivers/s390/scsi/zfcp_fsf.h
@@ -322,11 +322,18 @@ struct fsf_link_down_info {
 	u8 vendor_specific_code;
 } __attribute__ ((packed));
 
+struct fsf_qual_latency_info {
+	u32 channel_lat;
+	u32 fabric_lat;
+	u8 res1[8];
+} __attribute__ ((packed));
+
 union fsf_prot_status_qual {
 	u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)];
 	struct fsf_qual_version_error   version_error;
 	struct fsf_qual_sequence_error  sequence_error;
 	struct fsf_link_down_info link_down_info;
+	struct fsf_qual_latency_info latency_info;
 } __attribute__ ((packed));
 
 struct fsf_qtcb_prefix {
@@ -340,6 +347,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)];
@@ -427,7 +443,9 @@ struct fsf_qtcb_bottom_config {
 	u32 fc_link_speed;
 	u32 adapter_type;
 	u32 peer_d_id;
-	u8 res2[12];
+	u8 res1[2];
+	u16 timer_interval;
+	u8 res2[8];
 	u32 s_id;
 	struct fsf_nport_serv_param nport_serv_param;
 	u8 reserved_nport_serv_param[16];
@@ -436,7 +454,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 +488,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 {
Index: HEAD/drivers/s390/scsi/zfcp_qdio.c
===================================================================
--- HEAD.orig/drivers/s390/scsi/zfcp_qdio.c
+++ HEAD/drivers/s390/scsi/zfcp_qdio.c
@@ -232,6 +232,40 @@ zfcp_qdio_request_handler(struct ccw_dev
 	return;
 }
 
+static void zfcp_qdio_fsf_req_latency(struct zfcp_fsf_req *fsf_req)
+{
+	struct fsf_qual_latency_info *lat_inf;
+	struct zfcp_unit *unit;
+
+	lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
+	unit = fsf_req->unit;
+
+	switch (fsf_req->qtcb->bottom.io.data_direction) {
+	case FSF_DATADIR_READ:
+		unit->latencies.read.channel +=
+				lat_inf->channel_lat;
+		unit->latencies.read.fabric +=
+				lat_inf->fabric_lat;
+		unit->latencies.read.counter++;
+		break;
+	case FSF_DATADIR_WRITE:
+		unit->latencies.write.channel +=
+				lat_inf->channel_lat;
+		unit->latencies.write.fabric +=
+				lat_inf->fabric_lat;
+		unit->latencies.write.counter++;
+		break;
+	case FSF_DATADIR_CMND:
+		unit->latencies.cmd.channel +=
+				lat_inf->channel_lat;
+		unit->latencies.cmd.fabric +=
+				lat_inf->fabric_lat;
+		unit->latencies.cmd.counter++;
+		break;
+	}
+}
+
+
 /**
  * zfcp_qdio_reqid_check - checks for valid reqids.
  */
@@ -254,6 +288,11 @@ static void zfcp_qdio_reqid_check(struct
 		panic("error: unknown request id (%ld) on adapter %s.\n",
 		      req_id, zfcp_get_busid_by_adapter(adapter));
 
+	if ((fsf_req->fsf_command == FSF_QTCB_FCP_CMND) &&
+	    (fsf_req->qtcb->prefix.prot_status &
+	    (FSF_PROT_GOOD | FSF_PROT_FSF_STATUS_PRESENTED)))
+		zfcp_qdio_fsf_req_latency(fsf_req);
+
 	zfcp_reqlist_remove(adapter, fsf_req);
 	atomic_dec(&adapter->reqs_active);
 	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
Index: HEAD/drivers/s390/scsi/zfcp_sysfs_unit.c
===================================================================
--- HEAD.orig/drivers/s390/scsi/zfcp_sysfs_unit.c
+++ HEAD/drivers/s390/scsi/zfcp_sysfs_unit.c
@@ -125,6 +125,66 @@ zfcp_sysfs_unit_failed_show(struct devic
 static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_unit_failed_show,
 		   zfcp_sysfs_unit_failed_store);
 
+static ssize_t
+zfcp_sysfs_unit_read_latency_show(struct device *dev,
+				  struct device_attribute *attr, char *buf) {
+	struct zfcp_unit *unit;
+	struct zfcp_latencies *lat;
+	struct zfcp_adapter *adapter;
+
+	unit = dev_get_drvdata(dev);
+	lat = &unit->latencies;
+	adapter = unit->port->adapter;
+
+	return sprintf(buf, "%u %u %u\n",
+			lat->read.fabric * adapter->timer_ticks / 1000,
+			lat->read.channel * adapter->timer_ticks / 1000,
+			lat->read.counter);
+}
+
+static DEVICE_ATTR(read_latency, S_IRUGO, zfcp_sysfs_unit_read_latency_show,
+		   NULL);
+
+static ssize_t
+zfcp_sysfs_unit_write_latency_show(struct device *dev,
+				   struct device_attribute *attr, char *buf) {
+	struct zfcp_unit *unit;
+	struct zfcp_latencies *lat;
+	struct zfcp_adapter *adapter;
+
+	unit = dev_get_drvdata(dev);
+	lat = &unit->latencies;
+	adapter = unit->port->adapter;
+
+	return sprintf(buf, "%u %u %u\n",
+		       lat->write.fabric * adapter->timer_ticks / 1000,
+		       lat->write.channel * adapter->timer_ticks / 1000,
+		       lat->write.counter);
+}
+
+static DEVICE_ATTR(write_latency, S_IRUGO, zfcp_sysfs_unit_write_latency_show,
+		   NULL);
+
+static ssize_t
+zfcp_sysfs_unit_cmd_latency_show(struct device *dev,
+				 struct device_attribute *attr, char *buf) {
+	struct zfcp_unit *unit;
+	struct zfcp_latencies *lat;
+	struct zfcp_adapter *adapter;
+
+	unit = dev_get_drvdata(dev);
+	lat = &unit->latencies;
+	adapter = unit->port->adapter;
+
+	return sprintf(buf, "%u %u %u\n",
+		       lat->cmd.fabric * adapter->timer_ticks / 1000,
+		       lat->cmd.channel * adapter->timer_ticks / 1000,
+		       lat->cmd.counter);
+}
+
+static DEVICE_ATTR(cmd_latency, S_IRUGO, zfcp_sysfs_unit_cmd_latency_show,
+		   NULL);
+
 static struct attribute *zfcp_unit_attrs[] = {
 	&dev_attr_failed.attr,
 	&dev_attr_in_recovery.attr,
@@ -132,6 +192,9 @@ static struct attribute *zfcp_unit_attrs
 	&dev_attr_access_denied.attr,
 	&dev_attr_access_shared.attr,
 	&dev_attr_access_readonly.attr,
+	&dev_attr_read_latency.attr,
+	&dev_attr_write_latency.attr,
+	&dev_attr_cmd_latency.attr,
 	NULL
 };
 
Index: HEAD/drivers/s390/scsi/zfcp_ext.h
===================================================================
--- HEAD.orig/drivers/s390/scsi/zfcp_ext.h
+++ HEAD/drivers/s390/scsi/zfcp_ext.h
@@ -37,6 +37,8 @@ extern int  zfcp_sysfs_unit_create_files
 extern void zfcp_sysfs_unit_remove_files(struct device *);
 extern void zfcp_sysfs_port_release(struct device *);
 extern void zfcp_sysfs_unit_release(struct device *);
+extern int  zfcp_sysfs_statistic_services_create_files(struct device *);
+extern void zfcp_sysfs_statistic_services_remove_files(struct device *);
 
 /**************************** CONFIGURATION  *********************************/
 extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t);
Index: HEAD/drivers/s390/scsi/zfcp_aux.c
===================================================================
--- HEAD.orig/drivers/s390/scsi/zfcp_aux.c
+++ HEAD/drivers/s390/scsi/zfcp_aux.c
@@ -1067,13 +1067,32 @@ zfcp_adapter_enqueue(struct ccw_device *
 	if (zfcp_sysfs_adapter_create_files(&ccw_device->dev))
 		goto sysfs_failed;
 
+	adapter->stat_services.parent = &adapter->ccw_device->dev;
+	adapter->stat_services.release = zfcp_dummy_release;
+	snprintf(adapter->stat_services.bus_id, BUS_ID_SIZE,
+		 "statistic_services");
+	dev_set_drvdata(&adapter->stat_services, adapter);
+
+	if (device_register(&adapter->stat_services))
+		goto services_failed;
+
+	if (zfcp_sysfs_statistic_services_create_files(&adapter->stat_services))
+	{
+		device_unregister(&adapter->stat_services);
+		goto services_failed;
+	}
+
 	adapter->generic_services.parent = &adapter->ccw_device->dev;
 	adapter->generic_services.release = zfcp_dummy_release;
 	snprintf(adapter->generic_services.bus_id, BUS_ID_SIZE,
 		 "generic_services");
 
-	if (device_register(&adapter->generic_services))
-		goto generic_services_failed;
+	if (device_register(&adapter->generic_services)) {
+		zfcp_sysfs_statistic_services_remove_files(&adapter->
+							   stat_services);
+		device_unregister(&adapter->stat_services);
+		goto services_failed;
+	}
 
 	/* put allocated adapter at list tail */
 	write_lock_irq(&zfcp_data.config_lock);
@@ -1085,7 +1104,7 @@ zfcp_adapter_enqueue(struct ccw_device *
 
 	goto out;
 
- generic_services_failed:
+ services_failed:
 	zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
  sysfs_failed:
 	zfcp_adapter_debug_unregister(adapter);
@@ -1118,9 +1137,11 @@ zfcp_adapter_dequeue(struct zfcp_adapter
 	int retval = 0;
 	unsigned long flags;
 
-	zfcp_adapter_scsi_unregister(adapter);
 	device_unregister(&adapter->generic_services);
+	zfcp_sysfs_statistic_services_remove_files(&adapter->stat_services);
+	device_unregister(&adapter->stat_services);
 	zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
+	zfcp_adapter_scsi_unregister(adapter);
 	dev_set_drvdata(&adapter->ccw_device->dev, NULL);
 	/* sanity check: no pending FSF requests */
 	spin_lock_irqsave(&adapter->req_list_lock, flags);
@@ -1264,6 +1285,7 @@ zfcp_port_enqueue(struct zfcp_adapter *a
 
 	if (zfcp_sysfs_port_create_files(&port->sysfs_device, status)) {
 		device_unregister(&port->sysfs_device);
+		kfree(port);
 		return NULL;
 	}
 
Index: HEAD/drivers/s390/scsi/Makefile
===================================================================
--- HEAD.orig/drivers/s390/scsi/Makefile
+++ HEAD/drivers/s390/scsi/Makefile
@@ -4,6 +4,6 @@
 
 zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \
 	     zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \
-	     zfcp_sysfs_unit.o zfcp_sysfs_driver.o
+	     zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_sysfs_statistics.o
 
 obj-$(CONFIG_ZFCP) += zfcp.o
Index: HEAD/drivers/s390/scsi/zfcp_sysfs_statistics.c
===================================================================
--- /dev/null
+++ HEAD/drivers/s390/scsi/zfcp_sysfs_statistics.c
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the zfcp device driver for
+ * FCP adapters for IBM System z9 and zSeries.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "zfcp_ext.h"
+
+#define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
+
+
+static ssize_t
+zfcp_sysfs_adapter_utilization_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct zfcp_adapter *adapter;
+	struct fsf_qtcb_bottom_port *qtcb_port;
+	int retval;
+
+	adapter = dev_get_drvdata(dev);
+
+	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 DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_utilization_show,
+		   NULL);
+
+static ssize_t
+zfcp_sysfs_adapter_request_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct zfcp_adapter *adapter;
+	struct fsf_qtcb_bottom_config *qtcb_config;
+	int retval;
+
+	adapter = dev_get_drvdata(dev);
+
+	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)
+		retval = sprintf(buf, "%lu %lu %lu\n",
+				 qtcb_config->stat_info.input_req,
+				 qtcb_config->stat_info.output_req,
+				 qtcb_config->stat_info.control_req);
+
+	kfree(qtcb_config);
+	return retval;
+}
+
+static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL);
+
+static ssize_t
+zfcp_sysfs_adapter_mb_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct zfcp_adapter *adapter;
+	struct fsf_qtcb_bottom_config *qtcb_config;
+	int retval;
+
+	adapter = dev_get_drvdata(dev);
+
+	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)
+		retval = sprintf(buf, "%lu %lu\n",
+				 qtcb_config->stat_info.input_mb,
+				 qtcb_config->stat_info.output_mb);
+
+	kfree(qtcb_config);
+	return retval;
+}
+
+static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL);
+
+static ssize_t
+zfcp_sysfs_adapter_seconds_active_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct zfcp_adapter *adapter;
+	struct fsf_qtcb_bottom_config *qtcb_config;
+	int retval;
+
+	adapter = dev_get_drvdata(dev);
+
+	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)
+		retval = sprintf(buf, "%lu\n",
+				 qtcb_config->stat_info.seconds_act);
+
+	kfree(qtcb_config);
+	return retval;
+}
+
+static DEVICE_ATTR(seconds_active, S_IRUGO,
+		   zfcp_sysfs_adapter_seconds_active_show, NULL);
+
+static struct attribute *zfcp_statistic_services_attrs[] = {
+	&dev_attr_utilization.attr,
+	&dev_attr_requests.attr,
+	&dev_attr_megabytes.attr,
+	&dev_attr_seconds_active.attr,
+	NULL
+};
+
+static struct attribute_group zfcp_statistic_services_attr_group = {
+	.attrs = zfcp_statistic_services_attrs,
+};
+
+int
+zfcp_sysfs_statistic_services_create_files(struct device *dev)
+{
+	return sysfs_create_group(&dev->kobj,
+				  &zfcp_statistic_services_attr_group);
+}
+
+void
+zfcp_sysfs_statistic_services_remove_files(struct device *dev)
+{
+	sysfs_remove_group(&dev->kobj, &zfcp_statistic_services_attr_group);
+}
+
+#undef ZFCP_LOG_AREA
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux