aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2009-11-24 10:54:07 -0500
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:02:09 -0500
commit8830271c4819d86d8e87202a1fe8da0bb58912a2 (patch)
tree95069a94b64fc94ca24fec6d040b037097ef42ce
parent9eae07ef6bb5988163d8bb82cd952905db47b721 (diff)
[SCSI] zfcp: Dont fail SCSI commands when transitioning to blocked fc_rport
If an error occurs that triggers the call to fc_remote_port_delete, ideally this call would happen before any I/O is passed back to the SCSI midlayer through scsi_done. The SCSI midlayer will retry the commands and fc_remote_port_chkready will return the correct status code. But with the delay between calling scsi_done in softirq context and the call to fc_remote_port_delete from the workqueue, there is a window where zfcp returns DID_ERROR. This leads to SCSI error recovery which then leads to offline SCSI devices since all recovery actions will fail with the rport now being blocked. In this window, zfcp has to return DID_IMM_RETRY just as the FC transport class would do in fc_remote_port_chkready for the blocked fc_rport. As soon as the fc_rport is BLOCKED, fc_remote_port_chkready will do the right thing. Additionally, there are two more cases to catch in zfcp_scsi_queuecommand: - After the port has been opened, the unit has to be opened. During this period I/O has to be retried. This can also be handled with DID_IMM_RETRY. - If the access to the unit fails, but the port is good, then this single unit cannot be accessed and I/O to this unit has to fail without involving the FC transport class. Reviewed-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 39a621d729e9..0ecec9c1b490 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -112,12 +112,26 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
112 } 112 }
113 113
114 status = atomic_read(&unit->status); 114 status = atomic_read(&unit->status);
115 if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || 115 if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) &&
116 !(status & ZFCP_STATUS_COMMON_RUNNING))) { 116 !(atomic_read(&unit->port->status) &
117 ZFCP_STATUS_COMMON_ERP_FAILED)) {
118 /* only unit access denied, but port is good
119 * not covered by FC transport, have to fail here */
117 zfcp_scsi_command_fail(scpnt, DID_ERROR); 120 zfcp_scsi_command_fail(scpnt, DID_ERROR);
118 return 0; 121 return 0;
119 } 122 }
120 123
124 if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) {
125 /* This could be either
126 * open unit pending: this is temporary, will result in
127 * open unit or ERP_FAILED, so retry command
128 * call to rport_delete pending: mimic retry from
129 * fc_remote_port_chkready until rport is BLOCKED
130 */
131 zfcp_scsi_command_fail(scpnt, DID_IMM_RETRY);
132 return 0;
133 }
134
121 ret = zfcp_fsf_send_fcp_command_task(unit, scpnt); 135 ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
122 if (unlikely(ret == -EBUSY)) 136 if (unlikely(ret == -EBUSY))
123 return SCSI_MLQUEUE_DEVICE_BUSY; 137 return SCSI_MLQUEUE_DEVICE_BUSY;