--- /dev/null
+From: Gerald Schaefer <geraldsc@de.ibm.com>
+Subject: (kernel):FCP - Performance Data colletion & analysis
+References: bnc#417243
+
+This patch writes the channel and fabric latencies in nanoseconds per
+request via blktrace for later analysis. The utilization of the inbound
+and outbound adapter queue is also reported.
+
+Signed-off-by: Stefan Raspl <raspl@linux.vnet.ibm.com>
+Signed-off-by: Martin Peschke <mp3@de.ibm.com>
+Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
+
+Acked-by: John Jolly <jjolly@suse.de>
+
+---
+ drivers/s390/scsi/zfcp_def.h | 2 ++
+ drivers/s390/scsi/zfcp_fsf.c | 34 ++++++++++++++++++++++++++++++++++
+ drivers/s390/scsi/zfcp_fsf.h | 12 ++++++++++++
+ drivers/s390/scsi/zfcp_qdio.c | 1 +
+ 4 files changed, 49 insertions(+)
+
+--- a/drivers/s390/scsi/zfcp_fsf.c
++++ b/drivers/s390/scsi/zfcp_fsf.c
+@@ -6,6 +6,7 @@
+ * Copyright IBM Corporation 2002, 2008
+ */
+
++#include <linux/blktrace_api.h>
+ #include "zfcp_ext.h"
+
+ static void zfcp_fsf_request_timeout_handler(unsigned long data)
+@@ -834,6 +835,7 @@ static int zfcp_fsf_req_send(struct zfcp
+ list_add_tail(&req->list, &adapter->req_list[idx]);
+ spin_unlock(&adapter->req_list_lock);
+
++ req->qdio_outb_usage = atomic_read(&req_q->count);
+ req->issued = get_clock();
+ if (zfcp_qdio_send(req)) {
+ /* Queues are down..... */
+@@ -2036,6 +2038,36 @@ static void zfcp_fsf_req_latency(struct
+ spin_unlock_irqrestore(&unit->latencies.lock, flags);
+ }
+
++#ifdef CONFIG_BLK_DEV_IO_TRACE
++static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
++{
++ struct fsf_qual_latency_info *lat_inf;
++ struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
++ struct request *req = scsi_cmnd->request;
++ struct zfcp_blk_drv_data trace;
++ int ticks = fsf_req->adapter->timer_ticks;
++
++ trace.flags = 0;
++ trace.magic = ZFCP_BLK_DRV_DATA_MAGIC;
++ if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
++ trace.flags |= ZFCP_BLK_LAT_VALID;
++ lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
++ trace.channel_lat = lat_inf->channel_lat * ticks;
++ trace.fabric_lat = lat_inf->fabric_lat * ticks;
++ }
++ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
++ trace.flags |= ZFCP_BLK_REQ_ERROR;
++ trace.inb_usage = fsf_req->qdio_inb_usage;
++ trace.outb_usage = fsf_req->qdio_outb_usage;
++
++ blk_add_driver_data(req->q, req, &trace, sizeof(trace));
++}
++#else
++static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
++{
++}
++#endif
++
+ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
+ {
+ struct scsi_cmnd *scpnt = req->data;
+@@ -2068,6 +2100,8 @@ static void zfcp_fsf_send_fcp_command_ta
+ if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
+ zfcp_fsf_req_latency(req);
+
++ zfcp_fsf_trace_latency(req);
++
+ if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
+ if (fcp_rsp_info[3] == RSP_CODE_GOOD)
+ set_host_byte(scpnt, DID_OK);
+--- a/drivers/s390/scsi/zfcp_def.h
++++ b/drivers/s390/scsi/zfcp_def.h
+@@ -638,6 +638,8 @@ struct zfcp_fsf_req {
+ unsigned long long issued; /* request sent time (STCK) */
+ struct zfcp_unit *unit;
+ void (*handler)(struct zfcp_fsf_req *);
++ u16 qdio_outb_usage;/* usage of outbound queue */
++ u16 qdio_inb_usage; /* usage of inbound queue */
+ };
+
+ /* driver data */
+--- a/drivers/s390/scsi/zfcp_qdio.c
++++ b/drivers/s390/scsi/zfcp_qdio.c
+@@ -115,6 +115,7 @@ static void zfcp_qdio_reqid_check(struct
+ spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+
+ fsf_req->sbal_response = sbal_idx;
++ fsf_req->qdio_inb_usage = atomic_read(&adapter->resp_q.count);
+ zfcp_fsf_req_complete(fsf_req);
+ }
+
+--- a/drivers/s390/scsi/zfcp_fsf.h
++++ b/drivers/s390/scsi/zfcp_fsf.h
+@@ -514,4 +514,16 @@ struct fsf_qtcb {
+ u8 log[FSF_QTCB_LOG_SIZE];
+ } __attribute__ ((packed));
+
++struct zfcp_blk_drv_data {
++#define ZFCP_BLK_DRV_DATA_MAGIC 0x1
++ u32 magic;
++#define ZFCP_BLK_LAT_VALID 0x1
++#define ZFCP_BLK_REQ_ERROR 0x2
++ u16 flags;
++ u8 inb_usage;
++ u8 outb_usage;
++ u64 channel_lat;
++ u64 fabric_lat;
++} __attribute__ ((packed));
++
+ #endif /* FSF_H */