aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_rport.c
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 /drivers/scsi/libfc/fc_rport.c
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 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r--drivers/scsi/libfc/fc_rport.c75
1 files changed, 31 insertions, 44 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index df85e19079f..d385efc68c1 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -89,7 +89,6 @@ static const char *fc_rport_state_names[] = {
89 [RPORT_ST_LOGO] = "LOGO", 89 [RPORT_ST_LOGO] = "LOGO",
90 [RPORT_ST_ADISC] = "ADISC", 90 [RPORT_ST_ADISC] = "ADISC",
91 [RPORT_ST_DELETE] = "Delete", 91 [RPORT_ST_DELETE] = "Delete",
92 [RPORT_ST_RESTART] = "Restart",
93}; 92};
94 93
95/** 94/**
@@ -246,7 +245,6 @@ static void fc_rport_work(struct work_struct *work)
246 struct fc_rport_operations *rport_ops; 245 struct fc_rport_operations *rport_ops;
247 struct fc_rport_identifiers ids; 246 struct fc_rport_identifiers ids;
248 struct fc_rport *rport; 247 struct fc_rport *rport;
249 int restart = 0;
250 248
251 mutex_lock(&rdata->rp_mutex); 249 mutex_lock(&rdata->rp_mutex);
252 event = rdata->event; 250 event = rdata->event;
@@ -298,24 +296,6 @@ static void fc_rport_work(struct work_struct *work)
298 port_id = rdata->ids.port_id; 296 port_id = rdata->ids.port_id;
299 mutex_unlock(&rdata->rp_mutex); 297 mutex_unlock(&rdata->rp_mutex);
300 298
301 if (port_id != FC_FID_DIR_SERV) {
302 /*
303 * We must drop rp_mutex before taking disc_mutex.
304 * Re-evaluate state to allow for restart.
305 * A transition to RESTART state must only happen
306 * while disc_mutex is held and rdata is on the list.
307 */
308 mutex_lock(&lport->disc.disc_mutex);
309 mutex_lock(&rdata->rp_mutex);
310 if (rdata->rp_state == RPORT_ST_RESTART)
311 restart = 1;
312 else
313 list_del(&rdata->peers);
314 rdata->event = RPORT_EV_NONE;
315 mutex_unlock(&rdata->rp_mutex);
316 mutex_unlock(&lport->disc.disc_mutex);
317 }
318
319 if (rport_ops && rport_ops->event_callback) { 299 if (rport_ops && rport_ops->event_callback) {
320 FC_RPORT_DBG(rdata, "callback ev %d\n", event); 300 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
321 rport_ops->event_callback(lport, rdata, event); 301 rport_ops->event_callback(lport, rdata, event);
@@ -336,13 +316,34 @@ static void fc_rport_work(struct work_struct *work)
336 mutex_unlock(&rdata->rp_mutex); 316 mutex_unlock(&rdata->rp_mutex);
337 fc_remote_port_delete(rport); 317 fc_remote_port_delete(rport);
338 } 318 }
339 if (restart) { 319
340 mutex_lock(&rdata->rp_mutex); 320 mutex_lock(&lport->disc.disc_mutex);
341 FC_RPORT_DBG(rdata, "work restart\n"); 321 mutex_lock(&rdata->rp_mutex);
342 fc_rport_enter_plogi(rdata); 322 if (rdata->rp_state == RPORT_ST_DELETE) {
323 if (port_id == FC_FID_DIR_SERV) {
324 rdata->event = RPORT_EV_NONE;
325 mutex_unlock(&rdata->rp_mutex);
326 } else if (rdata->flags & FC_RP_STARTED) {
327 rdata->event = RPORT_EV_NONE;
328 FC_RPORT_DBG(rdata, "work restart\n");
329 fc_rport_enter_plogi(rdata);
330 mutex_unlock(&rdata->rp_mutex);
331 } else {
332 FC_RPORT_DBG(rdata, "work delete\n");
333 list_del(&rdata->peers);
334 mutex_unlock(&rdata->rp_mutex);
335 kref_put(&rdata->kref, lport->tt.rport_destroy);
336 }
337 } else {
338 /*
339 * Re-open for events. Reissue READY event if ready.
340 */
341 rdata->event = RPORT_EV_NONE;
342 if (rdata->rp_state == RPORT_ST_READY)
343 fc_rport_enter_ready(rdata);
343 mutex_unlock(&rdata->rp_mutex); 344 mutex_unlock(&rdata->rp_mutex);
344 } else 345 }
345 kref_put(&rdata->kref, lport->tt.rport_destroy); 346 mutex_unlock(&lport->disc.disc_mutex);
346 break; 347 break;
347 348
348 default: 349 default:
@@ -367,16 +368,14 @@ int fc_rport_login(struct fc_rport_priv *rdata)
367{ 368{
368 mutex_lock(&rdata->rp_mutex); 369 mutex_lock(&rdata->rp_mutex);
369 370
371 rdata->flags |= FC_RP_STARTED;
370 switch (rdata->rp_state) { 372 switch (rdata->rp_state) {
371 case RPORT_ST_READY: 373 case RPORT_ST_READY:
372 FC_RPORT_DBG(rdata, "ADISC port\n"); 374 FC_RPORT_DBG(rdata, "ADISC port\n");
373 fc_rport_enter_adisc(rdata); 375 fc_rport_enter_adisc(rdata);
374 break; 376 break;
375 case RPORT_ST_RESTART:
376 break;
377 case RPORT_ST_DELETE: 377 case RPORT_ST_DELETE:
378 FC_RPORT_DBG(rdata, "Restart deleted port\n"); 378 FC_RPORT_DBG(rdata, "Restart deleted port\n");
379 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
380 break; 379 break;
381 default: 380 default:
382 FC_RPORT_DBG(rdata, "Login to port\n"); 381 FC_RPORT_DBG(rdata, "Login to port\n");
@@ -431,15 +430,12 @@ int fc_rport_logoff(struct fc_rport_priv *rdata)
431 430
432 FC_RPORT_DBG(rdata, "Remove port\n"); 431 FC_RPORT_DBG(rdata, "Remove port\n");
433 432
433 rdata->flags &= ~FC_RP_STARTED;
434 if (rdata->rp_state == RPORT_ST_DELETE) { 434 if (rdata->rp_state == RPORT_ST_DELETE) {
435 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); 435 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
436 goto out; 436 goto out;
437 } 437 }
438 438 fc_rport_enter_logo(rdata);
439 if (rdata->rp_state == RPORT_ST_RESTART)
440 FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
441 else
442 fc_rport_enter_logo(rdata);
443 439
444 /* 440 /*
445 * Change the state to Delete so that we discard 441 * Change the state to Delete so that we discard
@@ -503,7 +499,6 @@ static void fc_rport_timeout(struct work_struct *work)
503 case RPORT_ST_READY: 499 case RPORT_ST_READY:
504 case RPORT_ST_INIT: 500 case RPORT_ST_INIT:
505 case RPORT_ST_DELETE: 501 case RPORT_ST_DELETE:
506 case RPORT_ST_RESTART:
507 break; 502 break;
508 } 503 }
509 504
@@ -527,6 +522,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
527 switch (rdata->rp_state) { 522 switch (rdata->rp_state) {
528 case RPORT_ST_PLOGI: 523 case RPORT_ST_PLOGI:
529 case RPORT_ST_LOGO: 524 case RPORT_ST_LOGO:
525 rdata->flags &= ~FC_RP_STARTED;
530 fc_rport_enter_delete(rdata, RPORT_EV_FAILED); 526 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
531 break; 527 break;
532 case RPORT_ST_RTV: 528 case RPORT_ST_RTV:
@@ -537,7 +533,6 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
537 fc_rport_enter_logo(rdata); 533 fc_rport_enter_logo(rdata);
538 break; 534 break;
539 case RPORT_ST_DELETE: 535 case RPORT_ST_DELETE:
540 case RPORT_ST_RESTART:
541 case RPORT_ST_READY: 536 case RPORT_ST_READY:
542 case RPORT_ST_INIT: 537 case RPORT_ST_INIT:
543 break; 538 break;
@@ -1392,7 +1387,6 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
1392 break; 1387 break;
1393 case RPORT_ST_DELETE: 1388 case RPORT_ST_DELETE:
1394 case RPORT_ST_LOGO: 1389 case RPORT_ST_LOGO:
1395 case RPORT_ST_RESTART:
1396 FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", 1390 FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
1397 fc_rport_state(rdata)); 1391 fc_rport_state(rdata));
1398 mutex_unlock(&rdata->rp_mutex); 1392 mutex_unlock(&rdata->rp_mutex);
@@ -1684,13 +1678,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
1684 fc_rport_state(rdata)); 1678 fc_rport_state(rdata));
1685 1679
1686 fc_rport_enter_delete(rdata, RPORT_EV_LOGO); 1680 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
1687
1688 /*
1689 * If the remote port was created due to discovery, set state
1690 * to log back in. It may have seen a stale RSCN about us.
1691 */
1692 if (rdata->disc_id)
1693 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
1694 mutex_unlock(&rdata->rp_mutex); 1681 mutex_unlock(&rdata->rp_mutex);
1695 } else 1682 } else
1696 FC_RPORT_ID_DBG(lport, sid, 1683 FC_RPORT_ID_DBG(lport, sid,