Skip to contentSkip to conversation

zfcp updates for 2.6.36 merge window

PATCH In review Christof Schmitt 2 participants 13 messages Jul 16, 2010 – Jul 28, 2010

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover zfcp updates for 2.6.36 merge window

James,

here is the series of zfcp updates for the 2.6.36 merge window. The changes include code simplifications, cleanup, FC transport events, experimental DIF/DIX support and logging improvements on errors.

The patches apply cleanly on top of the last series of fixes, i sent last week:
http://marc.info/?l=linux-scsi&m=127857607617662&w=2

The last patch in the series "zfcp: Trigger logging in the FCP channel on qdio error conditions" depends on the patch "[S390] cio: CHSC SIOSL Support" that is already part of the linux-next tree:
http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=commit;h=c5a0bc55f25e0002aaed211aef533e86c9aaff2a

Christof

#1 lore raw

PATCH 1/10 zfcp: Use memdup_user and kstrdup

From: Christof Schmitt <[email protected]>

Use the functions memdup_user and kstrdup to allocate memory and copy the data in one step, saving some lines of code.

---

 drivers/s390/scsi/zfcp_aux.c  |    4 +---
 drivers/s390/scsi/zfcp_cfdc.c |   12 +++---------
 2 files changed, 4 insertions(+), 12 deletions(-)
drivers/s390/scsi/zfcp_aux.c +1 -3
diff -urpN linux-2.6/drivers/s390/scsi/zfcp_aux.c linux-2.6-patched/drivers/s390/scsi/zfcp_aux.c
@@ -98,13 +98,11 @@ static void __init zfcp_init_device_setu
 	u64 wwpn, lun;
 
 	/* duplicate devstr and keep the original for sysfs presentation*/
-	str_saved = kmalloc(strlen(devstr) + 1, GFP_KERNEL);
+	str_saved = kstrdup(devstr, GFP_KERNEL);
 	str = str_saved;
 	if (!str)
 		return;
 
-	strcpy(str, devstr);
-
 	token = strsep(&str, ",");
 	if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE)
 		goto err_out;
drivers/s390/scsi/zfcp_cfdc.c +3 -9
diff -urpN linux-2.6/drivers/s390/scsi/zfcp_cfdc.c linux-2.6-patched/drivers/s390/scsi/zfcp_cfdc.c
@@ -189,18 +189,12 @@ static long zfcp_cfdc_dev_ioctl(struct f
 	if (!fsf_cfdc)
 		return -ENOMEM;
 
-	data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL);
-	if (!data) {
-		retval = -ENOMEM;
+	data = memdup_user(data_user, sizeof(*data_user));
+	if (IS_ERR(data)) {
+		retval = PTR_ERR(data);
 		goto no_mem_sense;
 	}
 
-	retval = copy_from_user(data, data_user, sizeof(*data));
-	if (retval) {
-		retval = -EFAULT;
-		goto free_buffer;
-	}
-
 	if (data->signature != 0xCFDCACDF) {
 		retval = -EINVAL;
 		goto free_buffer;
#2 lore raw

PATCH 2/10 zfcp: Remove SCSI device when removing unit

In reply to Christof Schmitt

From: Christof Schmitt <[email protected]>

Configuring a LUN in zfcp, also creates a SCSI device. For consistency, it makes sense to remove the SCSI device when the LUN is deconfigured. Replace the flush_work with the call to
scsi_remove_device: scsi_remove_device also takes the scan_mutex that synchronizes itself with any long running device discovery.

---

 drivers/s390/scsi/zfcp_def.h   |    1 +
 drivers/s390/scsi/zfcp_scsi.c  |    1 +
 drivers/s390/scsi/zfcp_sysfs.c |   10 ++++++++--
 3 files changed, 10 insertions(+), 2 deletions(-)
drivers/s390/scsi/zfcp_def.h +1 -0
@@ -212,6 +212,7 @@ struct zfcp_port {
 	struct work_struct     test_link_work;
 	struct work_struct     rport_work;
 	enum { RPORT_NONE, RPORT_ADD, RPORT_DEL }  rport_task;
+	unsigned int		starget_id;
 };
 
 struct zfcp_unit {
drivers/s390/scsi/zfcp_scsi.c +1 -0
@@ -564,6 +564,7 @@ static void zfcp_scsi_rport_register(str
 	rport->maxframe_size = port->maxframe_size;
 	rport->supported_classes = port->supported_classes;
 	port->rport = rport;
+	port->starget_id = rport->scsi_target_id;
 
 	zfcp_scsi_queue_unit_register(port);
 }
drivers/s390/scsi/zfcp_sysfs.c +8 -2
@@ -290,6 +290,7 @@ static ssize_t zfcp_sysfs_unit_remove_st
 	struct zfcp_unit *unit;
 	u64 fcp_lun;
 	int retval = -EINVAL;
+	struct scsi_device *sdev;
 
 	if (!(port && get_device(&port->dev)))
 		return -EBUSY;
@@ -303,8 +304,13 @@ static ssize_t zfcp_sysfs_unit_remove_st
 	else
 		retval = 0;
 
-	/* wait for possible timeout during SCSI probe */
-	flush_work(&unit->scsi_work);
+	sdev = scsi_device_lookup(port->adapter->scsi_host, 0,
+				  port->starget_id,
+				  scsilun_to_int((struct scsi_lun *)&fcp_lun));
+	if (sdev) {
+		scsi_remove_device(sdev);
+		scsi_device_put(sdev);
+	}
 
 	write_lock_irq(&port->unit_list_lock);
 	list_del(&unit->list);
#3 lore raw

Re: [patch 02/10] zfcp: Remove SCSI device when removing unit

Quoted 8 lines · Christof Schmitt

plain text document attachment (705-zfcp-unit-removal.diff)
From: Christof Schmitt <[email protected]>

Configuring a LUN in zfcp, also creates a SCSI device. For consistency, it makes sense to remove the SCSI device when the LUN is deconfigured. Replace the flush_work with the call to
scsi_remove_device: scsi_remove_device also takes the scan_mutex that synchronizes itself with any long running device discovery.

This one's rejecting:

jejb@mulgrave:~/git/scsi-misc-2.6> patch -p1 < ~/tmp/tmp/02 patching file drivers/s390/scsi/zfcp_def.h patching file drivers/s390/scsi/zfcp_scsi.c
Hunk #1 FAILED at 564.
1 out of 1 hunk FAILED -- saving rejects to file drivers/s390/scsi/zfcp_scsi.c.rej

It looks like a missing patch somewhere.

Could you check the current state of scsi-misc-2.6 (it includes scsi-rc-fixes-2.6) and see if I've lost something?

Thanks,

James

#4 lore raw

Re: [patch 02/10] zfcp: Remove SCSI device when removing unit

Quoted 19 lines · James Bottomley
Quoted 8 lines · Christof Schmitt

plain text document attachment (705-zfcp-unit-removal.diff)
From: Christof Schmitt <[email protected]>

Configuring a LUN in zfcp, also creates a SCSI device. For consistency, it makes sense to remove the SCSI device when the LUN is deconfigured. Replace the flush_work with the call to
scsi_remove_device: scsi_remove_device also takes the scan_mutex that synchronizes itself with any long running device discovery.

This one's rejecting:

jejb@mulgrave:~/git/scsi-misc-2.6> patch -p1 < ~/tmp/tmp/02 patching file drivers/s390/scsi/zfcp_def.h patching file drivers/s390/scsi/zfcp_scsi.c
Hunk #1 FAILED at 564.
1 out of 1 hunk FAILED -- saving rejects to file drivers/s390/scsi/zfcp_scsi.c.rej

Quoted 4 lines

It looks like a missing patch somewhere.

Could you check the current state of scsi-misc-2.6 (it includes scsi-rc-fixes-2.6) and see if I've lost something?

scsi-misc and scsi-rc-fixes have the three fixes i sent for 2.6.35. I sent them again with six additional fixes here:

http://marc.info/?l=linux-scsi&m=127857607617662&w=2

The six additional patches are missing and this seems to cause the reject. On top of scsi-misc, these patches apply cleanly in this order:

From http://marc.info/?l=linux-scsi&m=127857607617662&w=2
zfcp: Do not unblock rport from REOPEN_PORT_FORCED
zfcp: Do not try "forced close" when port is already closed
zfcp: Register SCSI devices after successful fc_remote_port_add
zfcp: Use forced_reopen in terminate_rport_io callback
zfcp: Fail erp after timeout
zfcp: Fix retry after failed "open port" erp action

From http://marc.info/?l=linux-scsi&m=127928780100336&w=2
zfcp: Use memdup_user and kstrdup
zfcp: Remove SCSI device when removing unit
zfcp: Use correct width for timer_interval field
zfcp: Cleanup function parameters for sbal value.
zfcp: Cleanup QDIO attachment and improve processing.
zfcp: Post events through FC transport class
zfcp: Prevent access on uninitialized memory.
zfcp: Enable data division support for FCP devices
zfcp: Introduce experimental support for DIF/DIX
zfcp: Trigger logging in the FCP channel on qdio error conditions

I can also resend them in one series if this makes things easier.

Christof

#5 lore raw

PATCH 3/10 zfcp: Use correct width for timer_interval field

In reply to Christof Schmitt

From: Christof Schmitt <[email protected]>

The timer_interval is 14 bits in width. Introduce a define for properly masking the value.

---

 drivers/s390/scsi/zfcp_fsf.c |    2 +-
 drivers/s390/scsi/zfcp_fsf.h |    2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_fsf.c +1 -1
@@ -495,7 +495,7 @@ static int zfcp_fsf_exchange_config_eval
 	fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
 
 	adapter->hydra_version = bottom->adapter_type;
-	adapter->timer_ticks = bottom->timer_interval;
+	adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK;
 	adapter->stat_read_buf_num = max(bottom->status_read_buf_num,
 					 (u16)FSF_STATUS_READS_RECOM);
 
drivers/s390/scsi/zfcp_fsf.h +2 -0
@@ -352,6 +352,8 @@ struct fsf_qtcb_bottom_support {
 	u8  els[256];
 } __attribute__ ((packed));
 
+#define ZFCP_FSF_TIMER_INT_MASK	0x3FFF
+
 struct fsf_qtcb_bottom_config {
 	u32 lic_version;
 	u32 feature_selection;
#6 lore raw

PATCH 4/10 zfcp: Cleanup function parameters for sbal value.

In reply to Christof Schmitt

From: Swen Schillig <[email protected]>

A lot of functions require the amount of SBALs as one of their parameter which is most times invariable. Therefore remove this parameter and set the SBAL value explicitly if a non standard value is required. In addition the warning message "oversized data" is replaced with a BUG_ON() statement assuring the limits defined and requested by zfcp.

---

 drivers/s390/scsi/zfcp_ext.h  |    2 +-
 drivers/s390/scsi/zfcp_fsf.c  |   40 ++++++++++++++--------------------------
 drivers/s390/scsi/zfcp_fsf.h  |    8 --------
 drivers/s390/scsi/zfcp_qdio.c |   15 ++-------------
 drivers/s390/scsi/zfcp_qdio.h |   28 ++++++++++++++++++++++++++++
 drivers/s390/scsi/zfcp_scsi.c |    4 ++--
 6 files changed, 47 insertions(+), 50 deletions(-)
drivers/s390/scsi/zfcp_ext.h +1 -1
@@ -146,7 +146,7 @@ extern void zfcp_qdio_destroy(struct zfc
 extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
 extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
 extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
-				   struct scatterlist *, int);
+				   struct scatterlist *);
 extern int zfcp_qdio_open(struct zfcp_qdio *);
 extern void zfcp_qdio_close(struct zfcp_qdio *);
 
drivers/s390/scsi/zfcp_fsf.c +14 -26
@@ -959,8 +959,7 @@ static void zfcp_fsf_setup_ct_els_unchai
 
 static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
 				       struct scatterlist *sg_req,
-				       struct scatterlist *sg_resp,
-				       int max_sbals)
+				       struct scatterlist *sg_resp)
 {
 	struct zfcp_adapter *adapter = req->adapter;
 	u32 feat = adapter->adapter_features;
@@ -983,15 +982,14 @@ static int zfcp_fsf_setup_ct_els_sbals(s
 		return 0;
 	}
 
-	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-					sg_req, max_sbals);
+	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req);
 	if (bytes <= 0)
 		return -EIO;
 	req->qtcb->bottom.support.req_buf_length = bytes;
 	zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
 
 	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-					sg_resp, max_sbals);
+					sg_resp);
 	req->qtcb->bottom.support.resp_buf_length = bytes;
 	if (bytes <= 0)
 		return -EIO;
@@ -1002,11 +1000,11 @@ static int zfcp_fsf_setup_ct_els_sbals(s
 static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
 				 struct scatterlist *sg_req,
 				 struct scatterlist *sg_resp,
-				 int max_sbals, unsigned int timeout)
+				 unsigned int timeout)
 {
 	int ret;
 
-	ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
+	ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp);
 	if (ret)
 		return ret;
 
@@ -1046,8 +1044,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
-				    ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
+	ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout);
 	if (ret)
 		goto failed_send;
 
@@ -1143,7 +1140,10 @@ int zfcp_fsf_send_els(struct zfcp_adapte
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout);
+
+	zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);
+
+	ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout);
 
 	if (ret)
 		goto failed_send;
@@ -2259,20 +2259,9 @@ int zfcp_fsf_send_fcp_command_task(struc
 	zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
 
 	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
-					     scsi_sglist(scsi_cmnd),
-					     ZFCP_FSF_MAX_SBALS_PER_REQ);
-	if (unlikely(real_bytes < 0)) {
-		if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
-			dev_err(&adapter->ccw_device->dev,
-				"Oversize data package, unit 0x%016Lx "
-				"on port 0x%016Lx closed\n",
-				(unsigned long long)unit->fcp_lun,
-				(unsigned long long)unit->port->wwpn);
-			zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
-			retval = -EINVAL;
-		}
+					     scsi_sglist(scsi_cmnd));
+	if (unlikely(real_bytes < 0))
 		goto failed_scsi_cmnd;
-	}
 
 	retval = zfcp_fsf_req_send(req);
 	if (unlikely(retval))
@@ -2391,9 +2380,8 @@ struct zfcp_fsf_req *zfcp_fsf_control_fi
 	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
 	bottom->option = fsf_cfdc->option;
 
-	bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
-					fsf_cfdc->sg,
-					ZFCP_FSF_MAX_SBALS_PER_REQ);
+	bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg);
+
 	if (bytes != ZFCP_CFDC_MAX_SIZE) {
 		zfcp_fsf_req_free(req);
 		goto out;
drivers/s390/scsi/zfcp_fsf.h +0 -8
@@ -151,14 +151,6 @@
 /* fc service class */
 #define FSF_CLASS_3				0x00000003
 
-/* SBAL chaining */
-#define ZFCP_FSF_MAX_SBALS_PER_REQ		36
-
-/* max. number of (data buffer) SBALEs in largest SBAL chain
- * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */
-#define ZFCP_FSF_MAX_SBALES_PER_REQ	\
-	(ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
-
 /* logging space behind QTCB */
 #define FSF_QTCB_LOG_SIZE			1024
 
drivers/s390/scsi/zfcp_qdio.c +2 -13
@@ -141,15 +141,6 @@ static void zfcp_qdio_int_resp(struct cc
 	zfcp_qdio_resp_put_back(qdio, count);
 }
 
-static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
-				 struct zfcp_qdio_req *q_req, int max_sbals)
-{
-	int count = atomic_read(&qdio->req_q.count);
-	count = min(count, max_sbals);
-	q_req->sbal_limit = (q_req->sbal_first + count - 1)
-					% QDIO_MAX_BUFFERS_PER_Q;
-}
-
 static struct qdio_buffer_element *
 zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
@@ -173,6 +164,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *q
 
 	/* keep this requests number of SBALs up-to-date */
 	q_req->sbal_number++;
+	BUG_ON(q_req->sbal_number > ZFCP_QDIO_MAX_SBALS_PER_REQ);
 
 	/* start at first SBALE of new SBAL */
 	q_req->sbale_curr = 0;
@@ -213,14 +205,11 @@ static void zfcp_qdio_undo_sbals(struct 
  * Returns: number of bytes, or error (negativ)
  */
 int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-			    struct scatterlist *sg, int max_sbals)
+			    struct scatterlist *sg)
 {
 	struct qdio_buffer_element *sbale;
 	int bytes = 0;
 
-	/* figure out last allowed SBAL */
-	zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
-
 	/* set storage-block type for this request */
 	sbale = zfcp_qdio_sbale_req(qdio, q_req);
 	sbale->flags |= q_req->sbtype;
drivers/s390/scsi/zfcp_qdio.h +28 -0
@@ -19,6 +19,14 @@
 /* index of last SBALE (with respect to DMQ bug workaround) */
 #define ZFCP_QDIO_LAST_SBALE_PER_SBAL	(ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1)
 
+/* Max SBALS for chaining */
+#define ZFCP_QDIO_MAX_SBALS_PER_REQ	36
+
+/* max. number of (data buffer) SBALEs in largest SBAL chain
+ * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */
+#define ZFCP_QDIO_MAX_SBALES_PER_REQ     \
+	(ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
+
 /**
  * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
  * @sbal: qdio buffers
@@ -134,10 +142,14 @@ void zfcp_qdio_req_init(struct zfcp_qdio
 			unsigned long req_id, u32 sbtype, void *data, u32 len)
 {
 	struct qdio_buffer_element *sbale;
+	int count = min(atomic_read(&qdio->req_q.count),
+			ZFCP_QDIO_MAX_SBALS_PER_REQ);
 
 	q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
 	q_req->sbal_number = 1;
 	q_req->sbtype = sbtype;
+	q_req->sbal_limit = (q_req->sbal_first + count - 1)
+					% QDIO_MAX_BUFFERS_PER_Q;
 
 	sbale = zfcp_qdio_sbale_req(qdio, q_req);
 	sbale->addr = (void *) req_id;
@@ -210,4 +222,20 @@ void zfcp_qdio_skip_to_last_sbale(struct
 	q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
 }
 
+/**
+ * zfcp_qdio_sbal_limit - set the sbal limit for a request in q_req
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @max_sbals: maximum number of SBALs allowed
+ */
+static inline
+void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
+			  struct zfcp_qdio_req *q_req, int max_sbals)
+{
+	int count = min(atomic_read(&qdio->req_q.count), max_sbals);
+
+	q_req->sbal_limit = (q_req->sbal_first + count - 1) %
+				QDIO_MAX_BUFFERS_PER_Q;
+}
+
 #endif /* ZFCP_QDIO_H */
drivers/s390/scsi/zfcp_scsi.c +2 -2
@@ -701,11 +701,11 @@ struct zfcp_data zfcp_data = {
 		.eh_host_reset_handler	 = zfcp_scsi_eh_host_reset_handler,
 		.can_queue		 = 4096,
 		.this_id		 = -1,
-		.sg_tablesize		 = ZFCP_FSF_MAX_SBALES_PER_REQ,
+		.sg_tablesize		 = ZFCP_QDIO_MAX_SBALES_PER_REQ,
 		.cmd_per_lun		 = 1,
 		.use_clustering		 = 1,
 		.sdev_attrs		 = zfcp_sysfs_sdev_attrs,
-		.max_sectors		 = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8),
+		.max_sectors		 = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8),
 		.dma_boundary		 = ZFCP_QDIO_SBALE_LEN - 1,
 		.shost_attrs		 = zfcp_sysfs_shost_attrs,
 	},
#7 lore raw

PATCH 5/10 zfcp: Cleanup QDIO attachment and improve processing.

In reply to Christof Schmitt

From: Swen Schillig <[email protected]>

Some definitions and structures in the zfcp QDIO processing are improved by the removal of not required variables and processing steps. I addition the naming of some variables is changed to make their purpose more clear.

---

 drivers/s390/scsi/zfcp_fsf.c  |   10 +-
 drivers/s390/scsi/zfcp_qdio.c |  141 ++++++++++++++----------------------------
 drivers/s390/scsi/zfcp_qdio.h |   57 +++++-----------
 3 files changed, 69 insertions(+), 139 deletions(-)
drivers/s390/scsi/zfcp_fsf.c +4 -6
@@ -732,7 +732,7 @@ static int zfcp_fsf_req_send(struct zfcp
 
 	zfcp_reqlist_add(adapter->req_list, req);
 
-	req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q.count);
+	req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
 	req->issued = get_clock();
 	if (zfcp_qdio_send(qdio, &req->qdio_req)) {
 		del_timer(&req->timer);
@@ -2025,7 +2025,7 @@ static void zfcp_fsf_req_trace(struct zf
 	blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
 		blktrc.flags |= ZFCP_BLK_REQ_ERROR;
-	blktrc.inb_usage = req->qdio_req.qdio_inb_usage;
+	blktrc.inb_usage = 0;
 	blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
 
 	if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&
@@ -2207,7 +2207,7 @@ int zfcp_fsf_send_fcp_command_task(struc
 		return -EBUSY;
 
 	spin_lock(&qdio->req_q_lock);
-	if (atomic_read(&qdio->req_q.count) <= 0) {
+	if (atomic_read(&qdio->req_q_free) <= 0) {
 		atomic_inc(&qdio->req_q_full);
 		goto out;
 	}
@@ -2407,7 +2407,7 @@ out:
 void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
 {
 	struct zfcp_adapter *adapter = qdio->adapter;
-	struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx];
+	struct qdio_buffer *sbal = qdio->res_q[sbal_idx];
 	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *fsf_req;
 	unsigned long req_id;
@@ -2428,8 +2428,6 @@ void zfcp_fsf_reqid_check(struct zfcp_qd
 			      req_id, dev_name(&adapter->ccw_device->dev));
 
 		fsf_req->qdio_req.sbal_response = sbal_idx;
-		fsf_req->qdio_req.qdio_inb_usage =
-			atomic_read(&qdio->resp_q.count);
 		zfcp_fsf_req_complete(fsf_req);
 
 		if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
drivers/s390/scsi/zfcp_qdio.c +48 -93

292 lines not on this page · raw message

drivers/s390/scsi/zfcp_qdio.h +17 -40

122 lines not on this page · raw message

#8 lore raw

PATCH 6/10 zfcp: Post events through FC transport class

In reply to Christof Schmitt

From: Sven Schuetz <[email protected]>

Post FC transport class netlink events for usage in the userspace, e.g. for HBAAPI. Supported events are those required for the polled events in HBAAPI.
- link up
- link down
- incoming RSCN
(events related to FC-AL are not supported, as zfcp has no support for FC-AL)

---

 drivers/s390/scsi/zfcp_aux.c |    4 +++
 drivers/s390/scsi/zfcp_def.h |    2 +
 drivers/s390/scsi/zfcp_ext.h |    3 ++
 drivers/s390/scsi/zfcp_fc.c  |   54 +++++++++++++++++++++++++++++++++++++++++++
 drivers/s390/scsi/zfcp_fc.h  |   24 +++++++++++++++++++
 drivers/s390/scsi/zfcp_fsf.c |    3 ++
 6 files changed, 90 insertions(+)
drivers/s390/scsi/zfcp_aux.c +4 -0
@@ -524,6 +524,10 @@ struct zfcp_adapter *zfcp_adapter_enqueu
 	rwlock_init(&adapter->port_list_lock);
 	INIT_LIST_HEAD(&adapter->port_list);
 
+	INIT_LIST_HEAD(&adapter->events.list);
+	INIT_WORK(&adapter->events.work, zfcp_fc_post_event);
+	spin_lock_init(&adapter->events.list_lock);
+
 	init_waitqueue_head(&adapter->erp_ready_wq);
 	init_waitqueue_head(&adapter->erp_done_wqh);
 
drivers/s390/scsi/zfcp_def.h +2 -0
@@ -37,6 +37,7 @@
 #include <asm/ebcdic.h>
 #include <asm/sysinfo.h>
 #include "zfcp_fsf.h"
+#include "zfcp_fc.h"
 #include "zfcp_qdio.h"
 
 struct zfcp_reqlist;
@@ -190,6 +191,7 @@ struct zfcp_adapter {
 	struct service_level	service_level;
 	struct workqueue_struct	*work_queue;
 	struct device_dma_parameters dma_parms;
+	struct zfcp_fc_events events;
 };
 
 struct zfcp_port {
drivers/s390/scsi/zfcp_ext.h +3 -0
@@ -96,6 +96,9 @@ extern void zfcp_erp_adapter_access_chan
 extern void zfcp_erp_timeout_handler(unsigned long);
 
 /* zfcp_fc.c */
+extern void zfcp_fc_enqueue_event(struct zfcp_adapter *,
+				enum fc_host_event_code event_code, u32);
+extern void zfcp_fc_post_event(struct work_struct *);
 extern void zfcp_fc_scan_ports(struct work_struct *);
 extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
 extern void zfcp_fc_port_did_lookup(struct work_struct *);
drivers/s390/scsi/zfcp_fc.c +54 -0

66 lines not on this page · raw message

drivers/s390/scsi/zfcp_fc.h +24 -0
@@ -30,6 +30,30 @@
 #define ZFCP_FC_CTELS_TMO	(2 * FC_DEF_R_A_TOV / 1000)
 
 /**
+ * struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context
+ * @code: Event code
+ * @data: Event data
+ * @list: list_head for zfcp_fc_events list
+ */
+struct zfcp_fc_event {
+	enum fc_host_event_code code;
+	u32 data;
+	struct list_head list;
+};
+
+/**
+ * struct zfcp_fc_events - Infrastructure for posting FC events from irq context
+ * @list: List for queueing of events from irq context to workqueue
+ * @list_lock: Lock for event list
+ * @work: work_struct for forwarding events in workqueue
+*/
+struct zfcp_fc_events {
+	struct list_head list;
+	spinlock_t list_lock;
+	struct work_struct work;
+};
+
+/**
  * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
  * @ct_hdr: FC GS common transport header
  * @gid_pn: GID_PN request
drivers/s390/scsi/zfcp_fsf.c +3 -0
@@ -274,6 +274,7 @@ static void zfcp_fsf_status_read_handler
 		break;
 	case FSF_STATUS_READ_LINK_DOWN:
 		zfcp_fsf_status_read_link_down(req);
+		zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0);
 		break;
 	case FSF_STATUS_READ_LINK_UP:
 		dev_info(&adapter->ccw_device->dev,
@@ -286,6 +287,8 @@ static void zfcp_fsf_status_read_handler
 					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
 					ZFCP_STATUS_COMMON_ERP_FAILED,
 					"fssrh_2", req);
+		zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);
+
 		break;
 	case FSF_STATUS_READ_NOTIFICATION_LOST:
 		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
#9 lore raw

PATCH 7/10 zfcp: Prevent access on uninitialized memory.

In reply to Christof Schmitt

From: Swen Schillig <[email protected]>

Initialize allocated memory to zero to prevent access on error. This prevents a possible error in the error handling path.

---

 drivers/s390/scsi/zfcp_dbf.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/scsi/zfcp_dbf.c +1 -1
diff -urpN linux-2.6/drivers/s390/scsi/zfcp_dbf.c linux-2.6-patched/drivers/s390/scsi/zfcp_dbf.c
@@ -1005,7 +1005,7 @@ int zfcp_dbf_adapter_register(struct zfc
 	char dbf_name[DEBUG_MAX_NAME_LEN];
 	struct zfcp_dbf *dbf;
 
-	dbf = kmalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
+	dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
 	if (!dbf)
 		return -ENOMEM;
 
#10 lore raw

PATCH 8/10 zfcp: Enable data division support for FCP devices

In reply to Christof Schmitt

From: Christof Schmitt <[email protected]>

Try to enable data division support for FCP devices and indicate in the adapter status flag if it succeeded.

---
 arch/s390/include/asm/qdio.h  |    6 ++++++
 drivers/s390/cio/qdio_setup.c |    2 ++
 drivers/s390/scsi/zfcp_def.h  |    1 +
 drivers/s390/scsi/zfcp_qdio.c |   11 ++++++++++-
 4 files changed, 19 insertions(+), 1 deletion(-)
arch/s390/include/asm/qdio.h +6 -0
@@ -84,6 +84,7 @@ struct qdr {
 
 #define QIB_AC_OUTBOUND_PCI_SUPPORTED	0x40
 #define QIB_RFLAGS_ENABLE_QEBSM		0x80
+#define QIB_RFLAGS_ENABLE_DATA_DIV	0x02
 
 /**
  * struct qib - queue information block (QIB)
@@ -284,6 +285,9 @@ struct slsb {
 	u8 val[QDIO_MAX_BUFFERS_PER_Q];
 } __attribute__ ((packed, aligned(256)));
 
+#define CHSC_AC2_DATA_DIV_AVAILABLE	0x0010
+#define CHSC_AC2_DATA_DIV_ENABLED	0x0002
+
 struct qdio_ssqd_desc {
 	u8 flags;
 	u8:8;
@@ -332,6 +336,7 @@ typedef void qdio_handler_t(struct ccw_d
  * @adapter_name: name for the adapter
  * @qib_param_field_format: format for qib_parm_field
  * @qib_param_field: pointer to 128 bytes or NULL, if no param field
+ * @qib_rflags: rflags to set
  * @input_slib_elements: pointer to no_input_qs * 128 words of data or NULL
  * @output_slib_elements: pointer to no_output_qs * 128 words of data or NULL
  * @no_input_qs: number of input queues
@@ -348,6 +353,7 @@ struct qdio_initialize {
 	unsigned char adapter_name[8];
 	unsigned int qib_param_field_format;
 	unsigned char *qib_param_field;
+	unsigned char qib_rflags;
 	unsigned long *input_slib_elements;
 	unsigned long *output_slib_elements;
 	unsigned int no_input_qs;
drivers/s390/cio/qdio_setup.c +2 -0
@@ -368,6 +368,8 @@ static void setup_qib(struct qdio_irq *i
 	if (qebsm_possible())
 		irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM;
 
+	irq_ptr->qib.rflags |= init_data->qib_rflags;
+
 	irq_ptr->qib.qfmt = init_data->q_format;
 	if (init_data->no_input_qs)
 		irq_ptr->qib.isliba =
drivers/s390/scsi/zfcp_def.h +1 -0
@@ -77,6 +77,7 @@ struct zfcp_reqlist;
 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT	0x00000010
 #define ZFCP_STATUS_ADAPTER_ERP_PENDING		0x00000100
 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED	0x00000200
+#define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED	0x00000400
 
 /* remote port status */
 #define ZFCP_STATUS_PORT_PHYS_OPEN		0x00000001
drivers/s390/scsi/zfcp_qdio.c +10 -1
@@ -283,6 +283,7 @@ static void zfcp_qdio_setup_init_data(st
 	id->q_format = QDIO_ZFCP_QFMT;
 	memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
 	ASCEBC(id->adapter_name, 8);
+	id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
 	id->qib_param_field_format = 0;
 	id->qib_param_field = NULL;
 	id->input_slib_elements = NULL;
@@ -294,8 +295,8 @@ static void zfcp_qdio_setup_init_data(st
 	id->int_parm = (unsigned long) qdio;
 	id->input_sbal_addr_array = (void **) (qdio->res_q);
 	id->output_sbal_addr_array = (void **) (qdio->req_q);
-
 }
+
 /**
  * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
  * @adapter: pointer to struct zfcp_adapter
@@ -358,6 +359,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdi
 	struct qdio_initialize init_data;
 	struct zfcp_adapter *adapter = qdio->adapter;
 	struct ccw_device *cdev = adapter->ccw_device;
+	struct qdio_ssqd_desc ssqd;
 	int cc;
 
 	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
@@ -368,6 +370,13 @@ int zfcp_qdio_open(struct zfcp_qdio *qdi
 	if (qdio_establish(&init_data))
 		goto failed_establish;
 
+	if (qdio_get_ssqd_desc(init_data.cdev, &ssqd))
+		goto failed_qdio;
+
+	if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
+		atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,
+				&qdio->adapter->status);
+
 	if (qdio_activate(cdev))
 		goto failed_qdio;
 
#11 lore raw

PATCH 9/10 zfcp: Introduce experimental support for DIF/DIX

In reply to Christof Schmitt

From: Felix Beck <[email protected]>

Introduce support for DIF/DIX in zfcp: Report the capabilities for the Scsi_host, map the protection data when issuing I/O requests and handle the new error codes. Also add the fsf data_direction field to the hba trace, it is useful information for debugging in that area. This is an EXPERIMENTAL feature for now.

---
 drivers/s390/scsi/zfcp_dbf.c  |    3 +
 drivers/s390/scsi/zfcp_dbf.h  |    1 
 drivers/s390/scsi/zfcp_ext.h  |    2 
 drivers/s390/scsi/zfcp_fc.h   |    3 +
 drivers/s390/scsi/zfcp_fsf.c  |  109 +++++++++++++++++++++++++++++++++---------
 drivers/s390/scsi/zfcp_fsf.h  |   24 ++++++++-
 drivers/s390/scsi/zfcp_qdio.c |    4 -
 drivers/s390/scsi/zfcp_qdio.h |   16 ++++++
 drivers/s390/scsi/zfcp_scsi.c |   53 ++++++++++++++++++++
 drivers/scsi/Kconfig          |    4 +
 10 files changed, 189 insertions(+), 30 deletions(-)
drivers/s390/scsi/zfcp_dbf.c +3 -0
@@ -155,6 +155,8 @@ void _zfcp_dbf_hba_fsf_response(const ch
 		if (scsi_cmnd) {
 			response->u.fcp.cmnd = (unsigned long)scsi_cmnd;
 			response->u.fcp.serial = scsi_cmnd->serial_number;
+			response->u.fcp.data_dir =
+				qtcb->bottom.io.data_direction;
 		}
 		break;
 
@@ -326,6 +328,7 @@ static void zfcp_dbf_hba_view_response(c
 	case FSF_QTCB_FCP_CMND:
 		if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
 			break;
+		zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir);
 		zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
 		zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
 		*p += sprintf(*p, "\n");
drivers/s390/scsi/zfcp_dbf.h +1 -0
@@ -111,6 +111,7 @@ struct zfcp_dbf_hba_record_response {
 		struct {
 			u64 cmnd;
 			u64 serial;
+			u32 data_dir;
 		} fcp;
 		struct {
 			u64 wwpn;
drivers/s390/scsi/zfcp_ext.h +2 -0
@@ -164,6 +164,8 @@ extern void zfcp_scsi_schedule_rport_blo
 extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
 extern void zfcp_scsi_scan(struct zfcp_unit *);
 extern void zfcp_scsi_scan_work(struct work_struct *);
+extern void zfcp_scsi_set_prot(struct zfcp_adapter *);
+extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);
 
 /* zfcp_sysfs.c */
 extern struct attribute_group zfcp_sysfs_unit_attrs;
drivers/s390/scsi/zfcp_fc.h +3 -0
@@ -220,6 +220,9 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd
 	memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
 
 	fcp->fc_dl = scsi_bufflen(scsi);
+
+	if (scsi_get_prot_type(scsi) == SCSI_PROT_DIF_TYPE1)
+		fcp->fc_dl += fcp->fc_dl / scsi->device->sector_size * 8;
 }
 
 /**
drivers/s390/scsi/zfcp_fsf.c +86 -23

186 lines not on this page · raw message

drivers/s390/scsi/zfcp_fsf.h +21 -3
@@ -80,11 +80,15 @@
 #define FSF_REQUEST_SIZE_TOO_LARGE		0x00000061
 #define FSF_RESPONSE_SIZE_TOO_LARGE		0x00000062
 #define FSF_SBAL_MISMATCH			0x00000063
+#define FSF_INCONSISTENT_PROT_DATA		0x00000070
+#define FSF_INVALID_PROT_PARM			0x00000071
+#define FSF_BLOCK_GUARD_CHECK_FAILURE		0x00000081
+#define FSF_APP_TAG_CHECK_FAILURE		0x00000082
+#define FSF_REF_TAG_CHECK_FAILURE		0x00000083
 #define FSF_ADAPTER_STATUS_AVAILABLE		0x000000AD
 #define FSF_UNKNOWN_COMMAND			0x000000E2
 #define FSF_UNKNOWN_OP_SUBTYPE                  0x000000E3
 #define FSF_INVALID_COMMAND_OPTION              0x000000E5
-/* #define FSF_ERROR                             0x000000FF  */
 
 #define FSF_PROT_STATUS_QUAL_SIZE		16
 #define FSF_STATUS_QUALIFIER_SIZE		16
@@ -147,6 +151,13 @@
 #define FSF_DATADIR_WRITE			0x00000001
 #define FSF_DATADIR_READ			0x00000002
 #define FSF_DATADIR_CMND			0x00000004
+#define FSF_DATADIR_DIF_WRITE_INSERT		0x00000009
+#define FSF_DATADIR_DIF_READ_STRIP		0x0000000a
+#define FSF_DATADIR_DIF_WRITE_CONVERT		0x0000000b
+#define FSF_DATADIR_DIF_READ_CONVERT		0X0000000c
+
+/* data protection control flags */
+#define FSF_APP_TAG_CHECK_ENABLE		0x10
 
 /* fc service class */
 #define FSF_CLASS_3				0x00000003
@@ -162,6 +173,8 @@
 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS	0x00000020
 #define FSF_FEATURE_UPDATE_ALERT		0x00000100
 #define FSF_FEATURE_MEASUREMENT_DATA		0x00000200
+#define FSF_FEATURE_DIF_PROT_TYPE1		0x00010000
+#define FSF_FEATURE_DIX_PROT_TCPIP		0x00020000
 
 /* host connection features */
 #define FSF_FEATURE_NPIV_MODE			0x00000001
@@ -316,9 +329,14 @@ struct fsf_qtcb_header {
 struct fsf_qtcb_bottom_io {
 	u32 data_direction;
 	u32 service_class;
-	u8  res1[8];
+	u8  res1;
+	u8  data_prot_flags;
+	u16 app_tag_value;
+	u32 ref_tag_value;
 	u32 fcp_cmnd_length;
-	u8  res2[12];
+	u32 data_block_length;
+	u32 prot_data_length;
+	u8  res2[4];
 	u8  fcp_cmnd[FSF_FCP_CMND_SIZE];
 	u8  fcp_rsp[FSF_FCP_RSP_SIZE];
 	u8  res3[64];
drivers/s390/scsi/zfcp_qdio.c +0 -4
@@ -193,10 +193,6 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_
 		bytes += sg->length;
 	}
 
-	/* assume that no other SBALEs are to follow in the same SBAL */
-	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-	sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
-
 	return bytes;
 }
 
drivers/s390/scsi/zfcp_qdio.h +16 -0
@@ -215,4 +215,20 @@ void zfcp_qdio_sbal_limit(struct zfcp_qd
 				QDIO_MAX_BUFFERS_PER_Q;
 }
 
+/**
+ * zfcp_qdio_set_data_div - set data division count
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @count: The data division count
+ */
+static inline
+void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,
+			    struct zfcp_qdio_req *q_req, u32 count)
+{
+	struct qdio_buffer_element *sbale;
+
+	sbale = &qdio->req_q[q_req->sbal_first]->element[0];
+	sbale->length = count;
+}
+
 #endif /* ZFCP_QDIO_H */
drivers/s390/scsi/zfcp_scsi.c +53 -0

71 lines not on this page · raw message

drivers/scsi/Kconfig +4 -0
@@ -1847,6 +1847,10 @@ config ZFCP
           called zfcp. If you want to compile it as a module, say M here
           and read <file:Documentation/kbuild/modules.txt>.
 
+config ZFCP_DIF
+	tristate "T10 DIF/DIX support for the zfcp driver (EXPERIMENTAL)"
+	depends on ZFCP && EXPERIMENTAL
+
 config SCSI_PMCRAID
 	tristate "PMC SIERRA Linux MaxRAID adapter support"
 	depends on PCI && SCSI
#12 lore raw

PATCH 10/10 zfcp: Trigger logging in the FCP channel on qdio error conditions

In reply to Christof Schmitt

From: Christof Schmitt <[email protected]>

Exploit the cio siosl function to trigger logging in the FCP channel on qdio error conditions. Add a helper function in zfcp_qdio to ensure that tracing is only triggered once before calling qdio_shutdown.

Trigger in zfcp for hardware logs are:
- timeout for FSF requests to the FCP channel
- "no recommendation" status from FCP channel
- invalid FSF protocol status
- stalled outbound queue
- unknown request id on inbound queue
- QDIO_ERROR_SLSB_STATE

All of the above triggers run from the Linux qdio softirq context, so no additional synchronization is necessary for the handling of the ZFCP_STATUS_ADAPTER_SIOSL_ISSUED flag.

---

 drivers/s390/scsi/zfcp_def.h  |    1 +
 drivers/s390/scsi/zfcp_ext.h  |    1 +
 drivers/s390/scsi/zfcp_fsf.c  |    7 ++++++-
 drivers/s390/scsi/zfcp_qdio.c |   35 ++++++++++++++++++++++++++++++++---
 4 files changed, 40 insertions(+), 4 deletions(-)
drivers/s390/scsi/zfcp_def.h +1 -0
@@ -73,6 +73,7 @@ struct zfcp_reqlist;
 
 /* adapter status */
 #define ZFCP_STATUS_ADAPTER_QDIOUP		0x00000002
+#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED	0x00000004
 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK		0x00000008
 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT	0x00000010
 #define ZFCP_STATUS_ADAPTER_ERP_PENDING		0x00000100
drivers/s390/scsi/zfcp_ext.h +1 -0
@@ -152,6 +152,7 @@ extern int zfcp_qdio_sbals_from_sg(struc
 				   struct scatterlist *);
 extern int zfcp_qdio_open(struct zfcp_qdio *);
 extern void zfcp_qdio_close(struct zfcp_qdio *);
+extern void zfcp_qdio_siosl(struct zfcp_adapter *);
 
 /* zfcp_scsi.c */
 extern struct zfcp_data zfcp_data;
drivers/s390/scsi/zfcp_fsf.c +6 -1
@@ -21,6 +21,7 @@
 static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
+	zfcp_qdio_siosl(adapter);
 	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
 				"fsrth_1", NULL);
 }
@@ -326,6 +327,7 @@ static void zfcp_fsf_fsfstatus_qual_eval
 		dev_err(&req->adapter->ccw_device->dev,
 			"The FCP adapter reported a problem "
 			"that cannot be recovered\n");
+		zfcp_qdio_siosl(req->adapter);
 		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
 		break;
 	}
@@ -416,6 +418,7 @@ static void zfcp_fsf_protstatus_eval(str
 		dev_err(&adapter->ccw_device->dev,
 			"0x%x is not a valid transfer protocol status\n",
 			qtcb->prefix.prot_status);
+		zfcp_qdio_siosl(adapter);
 		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
 	}
 	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -2485,13 +2488,15 @@ void zfcp_fsf_reqid_check(struct zfcp_qd
 		req_id = (unsigned long) sbale->addr;
 		fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
 
-		if (!fsf_req)
+		if (!fsf_req) {
 			/*
 			 * Unknown request means that we have potentially memory
 			 * corruption and must stop the machine immediately.
 			 */
+			zfcp_qdio_siosl(adapter);
 			panic("error: unknown req_id (%lx) on adapter %s.\n",
 			      req_id, dev_name(&adapter->ccw_device->dev));
+		}
 
 		fsf_req->qdio_req.sbal_response = sbal_idx;
 		zfcp_fsf_req_complete(fsf_req);
drivers/s390/scsi/zfcp_qdio.c +32 -3
@@ -30,12 +30,15 @@ static int zfcp_qdio_buffers_enqueue(str
 	return 0;
 }
 
-static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
+static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
+				    unsigned int qdio_err)
 {
 	struct zfcp_adapter *adapter = qdio->adapter;
 
 	dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
 
+	if (qdio_err & QDIO_ERROR_SLSB_STATE)
+		zfcp_qdio_siosl(adapter);
 	zfcp_erp_adapter_reopen(adapter,
 				ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
 				ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
@@ -74,7 +77,7 @@ static void zfcp_qdio_int_req(struct ccw
 
 	if (unlikely(qdio_err)) {
 		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
-		zfcp_qdio_handler_error(qdio, "qdireq1");
+		zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
 		return;
 	}
 
@@ -95,7 +98,7 @@ static void zfcp_qdio_int_resp(struct cc
 
 	if (unlikely(qdio_err)) {
 		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
-		zfcp_qdio_handler_error(qdio, "qdires1");
+		zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
 		return;
 	}
 
@@ -361,6 +364,9 @@ int zfcp_qdio_open(struct zfcp_qdio *qdi
 	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
 		return -EIO;
 
+	atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+			  &qdio->adapter->status);
+
 	zfcp_qdio_setup_init_data(&init_data, qdio);
 
 	if (qdio_establish(&init_data))
@@ -440,3 +446,26 @@ int zfcp_qdio_setup(struct zfcp_adapter 
 	return 0;
 }
 
+/**
+ * zfcp_qdio_siosl - Trigger logging in FCP channel
+ * @adapter: The zfcp_adapter where to trigger logging
+ *
+ * Call the cio siosl function to trigger hardware logging.  This
+ * wrapper function sets a flag to ensure hardware logging is only
+ * triggered once before going through qdio shutdown.
+ *
+ * The triggers are always run from qdio tasklet context, so no
+ * additional synchronization is necessary.
+ */
+void zfcp_qdio_siosl(struct zfcp_adapter *adapter)
+{
+	int rc;
+
+	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED)
+		return;
+
+	rc = ccw_device_siosl(adapter->ccw_device);
+	if (!rc)
+		atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+				&adapter->status);
+}