aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2009-08-25 14:03:36 -0700
committerJames Bottomley <James.Bottomley@suse.de>2009-09-10 12:08:01 -0500
commitfeab4ae73031699fcf92a88f4b1e4ec1b14157a5 (patch)
tree9552f8c00ec9dfc75e279788d6d079df1caff2e0
parent[SCSI] libfc: fix rport error handling for login-required and invalid ops (diff)
downloadlinux-dev-feab4ae73031699fcf92a88f4b1e4ec1b14157a5.tar.xz
linux-dev-feab4ae73031699fcf92a88f4b1e4ec1b14157a5.zip
[SCSI] libfc: re-login to remote ports that send us LOGO
After a quick link flap, a target was seen to send us a LOGO. Apparently, it saw an RSCN reporting that we had dropped out of the fabric after we had logged back into it. This is likely in larger fabrics (more than 2 FC switches) after a quick link flap at the initiator. Each link transition causes an port-specific RSCN to the target. After the link comes back up, the initiator successfully discovers and does a PLOGI to the target before the target sees the first RSCN reporting the initiator is gone, and it sends a LOGO. The target may see a subsequent RSCN saying the port is back, but probably wouldn't send a PLOGI and leaves it up to the initiator to re-login. An RSCN can be delayed by the switches due to software layers but a PLOGI is forwarded in hardware causing the PLOGI to beat the RSCN. If a remote port is in the discovered set and sends a LOGO, re-login to it. Signed-off-by: Joe Eykholt <jeykholt@cisco.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/libfc/fc_rport.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 04e9846ad1b5..dc97c603744f 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -1340,6 +1340,8 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
struct fc_rport_priv *rdata;
u32 sid;
+ lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+
fh = fc_frame_header_get(fp);
sid = ntoh24(fh->fh_s_id);
@@ -1349,13 +1351,20 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
mutex_lock(&rdata->rp_mutex);
FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
fc_rport_state(rdata));
- fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+
+ /*
+ * If the remote port was created due to discovery,
+ * log back in. It may have seen a stale RSCN about us.
+ */
+ if (rdata->rp_state != RPORT_ST_DELETE && rdata->disc_id)
+ fc_rport_enter_plogi(rdata);
+ else
+ fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
mutex_unlock(&rdata->rp_mutex);
} else
FC_RPORT_ID_DBG(lport, sid,
"Received LOGO from non-logged-in port\n");
mutex_unlock(&lport->disc.disc_mutex);
- lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
fc_frame_free(fp);
}