[PATCH] qla2xxx: Close window on race between rport removal and fcport transition.

Fcport visibility is recognized during interrupt time, but,
rport removal can only occur during a process
(sleeping)-context.  Return a DID_IMM_RETRY status for
commands submitted within this window to insure I/Os do not
prematurely run-out of retries.

Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 495ccbc..9b5a10a 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -366,6 +366,12 @@
 		goto qc_fail_command;
 	}
 
+	/* Close window on fcport/rport state-transitioning. */
+	if (!*(fc_port_t **)rport->dd_data) {
+		cmd->result = DID_IMM_RETRY << 16;
+		goto qc_fail_command;
+	}
+
 	if (atomic_read(&fcport->state) != FCS_ONLINE) {
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
 		    atomic_read(&ha->loop_state) == LOOP_DEAD) {
@@ -421,6 +427,12 @@
 		goto qc24_fail_command;
 	}
 
+	/* Close window on fcport/rport state-transitioning. */
+	if (!*(fc_port_t **)rport->dd_data) {
+		cmd->result = DID_IMM_RETRY << 16;
+		goto qc24_fail_command;
+	}
+
 	if (atomic_read(&fcport->state) != FCS_ONLINE) {
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
 		    atomic_read(&ha->loop_state) == LOOP_DEAD) {
@@ -1675,11 +1687,13 @@
 		spin_lock_irqsave(&fcport->rport_lock, flags);
 		fcport->drport = rport;
 		fcport->rport = NULL;
+		*(fc_port_t **)rport->dd_data = NULL;
 		spin_unlock_irqrestore(&fcport->rport_lock, flags);
 		set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
 	} else {
 		spin_lock_irqsave(&fcport->rport_lock, flags);
 		fcport->rport = NULL;
+		*(fc_port_t **)rport->dd_data = NULL;
 		spin_unlock_irqrestore(&fcport->rport_lock, flags);
 		fc_remote_port_delete(rport);
 	}