aboutsummaryrefslogtreecommitdiffstats
path: root/include/scsi
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2010-06-11 19:44:51 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:01:52 -0400
commit4b2164d4d212e437c9f080023a67f8f9356d2c4c (patch)
treeaaa86c0e2b1532b87780f568b35921e56342557d /include/scsi
parent0db6f4353d68c0108b5fe0bad8259de0197589c6 (diff)
[SCSI] libfc: Fix remote port restart problem
This patch somewhat combines two fixes to remote port handing in libfc. The first problem was that rport work could be queued on a deleted and freed rport. This is handled by not resetting rdata->event ton NONE if the rdata is about to be deleted. However, that fix led to the second problem, described by Bhanu Gollapudi, as follows: > Here is the sequence of events. T1 is first LOGO receive thread, T2 is > fc_rport_work() scheduled by T1 and T3 is second LOGO receive thread and > T4 is fc_rport_work scheduled by T3. > > 1. (T1)Received 1st LOGO in state Ready > 2. (T1)Delete port & enter to RESTART state. > 3. (T1)schdule event_work, since event is RPORT_EV_NONE. > 4. (T1)set event = RPORT_EV_LOGO > 5. (T1)Enter RESTART state as disc_id is set. > 6. (T2)remember to PLOGI, and set event = RPORT_EV_NONE > 6. (T3)Received 2nd LOGO > 7. (T3)Delete Port & enter to RESTART state. > 8. (T3)schedule event_work, since event is RPORT_EV_NONE. > 9. (T3)Enter RESTART state as disc_id is set. > 9. (T3)set event = RPORT_EV_LOGO > 10.(T2)work restart, enter PLOGI state and issues PLOGI > 11.(T4)Since state is not RESTART anymore, restart is not set, and the > event is not reset to RPORT_EV_NONE. (current event is RPORT_EV_LOGO). > 12. Now, PLOGI succeeds and fc_rport_enter_ready() will not schedule > event_work, and hence the rport will never be created, eventually losing > the target after dev_loss_tmo. So, the problem here is that we were tracking the desire for the rport be restarted by state RESTART, which was otherwise equivalent to DELETE. A contributing factor is that we dropped the lock between steps 6 and 10 in thread T2, which allows the state to change, and we didn't completely re-evaluate then. This is hopefully corrected by the following minor redesign: Simplify the rport restart logic by making the decision to restart after deleting the transport rport. That decision is based on a new STARTED flag that indicates fc_rport_login() has been called and fc_rport_logoff() has not been called since then. This replaces the need for the RESTART state. Only restart if the rdata is still in DELETED state and only if it still has the STARTED flag set. Also now, since we clear the event code much later in the work thread, allow for the possibility that the rport may have become READY again via incoming PLOGI, and if so, queue another event to handle that. In the problem scenario, the second LOGO received will cause the LOGO event to occur again. Reported-by: Bhanu Gollapudi <bprakash@broadcom.com> 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>
Diffstat (limited to 'include/scsi')
-rw-r--r--include/scsi/libfc.h5
1 files changed, 2 insertions, 3 deletions
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 7495c0ba67ee..db54c4a2d14b 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -104,7 +104,6 @@ enum fc_disc_event {
104 * @RPORT_ST_LOGO: Remote port logout (LOGO) sent 104 * @RPORT_ST_LOGO: Remote port logout (LOGO) sent
105 * @RPORT_ST_ADISC: Discover Address sent 105 * @RPORT_ST_ADISC: Discover Address sent
106 * @RPORT_ST_DELETE: Remote port being deleted 106 * @RPORT_ST_DELETE: Remote port being deleted
107 * @RPORT_ST_RESTART: Remote port being deleted and will restart
108*/ 107*/
109enum fc_rport_state { 108enum fc_rport_state {
110 RPORT_ST_INIT, 109 RPORT_ST_INIT,
@@ -115,7 +114,6 @@ enum fc_rport_state {
115 RPORT_ST_LOGO, 114 RPORT_ST_LOGO,
116 RPORT_ST_ADISC, 115 RPORT_ST_ADISC,
117 RPORT_ST_DELETE, 116 RPORT_ST_DELETE,
118 RPORT_ST_RESTART,
119}; 117};
120 118
121/** 119/**
@@ -173,6 +171,7 @@ struct fc_rport_libfc_priv {
173 u16 flags; 171 u16 flags;
174 #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) 172 #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0)
175 #define FC_RP_FLAGS_RETRY (1 << 1) 173 #define FC_RP_FLAGS_RETRY (1 << 1)
174 #define FC_RP_STARTED (1 << 2)
176 unsigned int e_d_tov; 175 unsigned int e_d_tov;
177 unsigned int r_a_tov; 176 unsigned int r_a_tov;
178}; 177};
@@ -185,7 +184,7 @@ struct fc_rport_libfc_priv {
185 * @rp_state: Enumeration that tracks progress of PLOGI, PRLI, 184 * @rp_state: Enumeration that tracks progress of PLOGI, PRLI,
186 * and RTV exchanges 185 * and RTV exchanges
187 * @ids: The remote port identifiers and roles 186 * @ids: The remote port identifiers and roles
188 * @flags: REC and RETRY supported flags 187 * @flags: STARTED, REC and RETRY_SUPPORTED flags
189 * @max_seq: Maximum number of concurrent sequences 188 * @max_seq: Maximum number of concurrent sequences
190 * @disc_id: The discovery identifier 189 * @disc_id: The discovery identifier
191 * @maxframe_size: The maximum frame size 190 * @maxframe_size: The maximum frame size