aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Leech <christopher.leech@intel.com>2009-02-27 13:55:02 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-06 16:39:34 -0500
commit6755db1cd4587084be85f860b7aa7c0cc9d776dc (patch)
treecdc50e934f61d73a7aa8f5fdc5c454e0375071b9
parentbc0e17f691085315ae9303eb5b0883fe16dfe6b1 (diff)
[SCSI] libfc: rport retry on LS_RJT from certain ELS
This allows any rport ELS to retry on LS_RJT. The rport error handling would only retry on resource allocation failures and exchange timeouts. I have a target that will occasionally reject PLOGI when we do a quick LOGO/PLOGI. When a critical ELS was rejected, libfc would fail silently leaving the rport in a dead state. The retry count and delay are managed by fc_rport_error_retry. If the retry count is exceeded fc_rport_error will be called. When retrying is not the correct course of action, fc_rport_error can be called directly. Signed-off-by: Chris Leech <christopher.leech@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/libfc/fc_exch.c2
-rw-r--r--drivers/scsi/libfc/fc_rport.c111
-rw-r--r--include/scsi/fc/fc_fs.h5
3 files changed, 69 insertions, 49 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index dd269e5f953e..8c4018956d4c 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -32,8 +32,6 @@
32#include <scsi/libfc.h> 32#include <scsi/libfc.h>
33#include <scsi/fc_encode.h> 33#include <scsi/fc_encode.h>
34 34
35#define FC_DEF_R_A_TOV (10 * 1000) /* resource allocation timeout */
36
37/* 35/*
38 * fc_exch_debug can be set in debugger or at compile time to get more logs. 36 * fc_exch_debug can be set in debugger or at compile time to get more logs.
39 */ 37 */
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 717575934152..600a8fffa940 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -81,6 +81,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *,
81 struct fc_seq *, struct fc_frame *); 81 struct fc_seq *, struct fc_frame *);
82static void fc_rport_timeout(struct work_struct *); 82static void fc_rport_timeout(struct work_struct *);
83static void fc_rport_error(struct fc_rport *, struct fc_frame *); 83static void fc_rport_error(struct fc_rport *, struct fc_frame *);
84static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *);
84static void fc_rport_work(struct work_struct *); 85static void fc_rport_work(struct work_struct *);
85 86
86static const char *fc_rport_state_names[] = { 87static const char *fc_rport_state_names[] = {
@@ -410,58 +411,74 @@ static void fc_rport_timeout(struct work_struct *work)
410} 411}
411 412
412/** 413/**
413 * fc_rport_error - Handler for any errors 414 * fc_rport_error - Error handler, called once retries have been exhausted
414 * @rport: The fc_rport object 415 * @rport: The fc_rport object
415 * @fp: The frame pointer 416 * @fp: The frame pointer
416 * 417 *
417 * If the error was caused by a resource allocation failure
418 * then wait for half a second and retry, otherwise retry
419 * immediately.
420 *
421 * Locking Note: The rport lock is expected to be held before 418 * Locking Note: The rport lock is expected to be held before
422 * calling this routine 419 * calling this routine
423 */ 420 */
424static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) 421static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
425{ 422{
426 struct fc_rport_libfc_priv *rdata = rport->dd_data; 423 struct fc_rport_libfc_priv *rdata = rport->dd_data;
427 unsigned long delay = 0;
428 424
429 FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n", 425 FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n",
430 PTR_ERR(fp), fc_rport_state(rport), rdata->retries); 426 PTR_ERR(fp), fc_rport_state(rport), rdata->retries);
431 427
432 if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { 428 switch (rdata->rp_state) {
433 /* 429 case RPORT_ST_PLOGI:
434 * Memory allocation failure, or the exchange timed out. 430 case RPORT_ST_PRLI:
435 * Retry after delay 431 case RPORT_ST_LOGO:
436 */ 432 rdata->event = RPORT_EV_FAILED;
437 if (rdata->retries < rdata->local_port->max_retry_count) { 433 queue_work(rport_event_queue,
438 rdata->retries++; 434 &rdata->event_work);
439 if (!fp) 435 break;
440 delay = msecs_to_jiffies(500); 436 case RPORT_ST_RTV:
441 get_device(&rport->dev); 437 fc_rport_enter_ready(rport);
442 schedule_delayed_work(&rdata->retry_work, delay); 438 break;
443 } else { 439 case RPORT_ST_NONE:
444 switch (rdata->rp_state) { 440 case RPORT_ST_READY:
445 case RPORT_ST_PLOGI: 441 case RPORT_ST_INIT:
446 case RPORT_ST_PRLI: 442 break;
447 case RPORT_ST_LOGO:
448 rdata->event = RPORT_EV_FAILED;
449 queue_work(rport_event_queue,
450 &rdata->event_work);
451 break;
452 case RPORT_ST_RTV:
453 fc_rport_enter_ready(rport);
454 break;
455 case RPORT_ST_NONE:
456 case RPORT_ST_READY:
457 case RPORT_ST_INIT:
458 break;
459 }
460 }
461 } 443 }
462} 444}
463 445
464/** 446/**
447 * fc_rport_error_retry - Error handler when retries are desired
448 * @rport: The fc_rport object
449 * @fp: The frame pointer
450 *
451 * If the error was an exchange timeout retry immediately,
452 * otherwise wait for E_D_TOV.
453 *
454 * Locking Note: The rport lock is expected to be held before
455 * calling this routine
456 */
457static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)
458{
459 struct fc_rport_libfc_priv *rdata = rport->dd_data;
460 unsigned long delay = FC_DEF_E_D_TOV;
461
462 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
463 if (PTR_ERR(fp) == -FC_EX_CLOSED)
464 return fc_rport_error(rport, fp);
465
466 if (rdata->retries < rdata->local_port->max_retry_count) {
467 FC_DEBUG_RPORT("Error %ld in state %s, retrying\n",
468 PTR_ERR(fp), fc_rport_state(rport));
469 rdata->retries++;
470 /* no additional delay on exchange timeouts */
471 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
472 delay = 0;
473 get_device(&rport->dev);
474 schedule_delayed_work(&rdata->retry_work, delay);
475 return;
476 }
477
478 return fc_rport_error(rport, fp);
479}
480
481/**
465 * fc_rport_plogi_recv_resp - Handle incoming ELS PLOGI response 482 * fc_rport_plogi_recv_resp - Handle incoming ELS PLOGI response
466 * @sp: current sequence in the PLOGI exchange 483 * @sp: current sequence in the PLOGI exchange
467 * @fp: response frame 484 * @fp: response frame
@@ -495,7 +512,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
495 } 512 }
496 513
497 if (IS_ERR(fp)) { 514 if (IS_ERR(fp)) {
498 fc_rport_error(rport, fp); 515 fc_rport_error_retry(rport, fp);
499 goto err; 516 goto err;
500 } 517 }
501 518
@@ -527,7 +544,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
527 else 544 else
528 fc_rport_enter_prli(rport); 545 fc_rport_enter_prli(rport);
529 } else 546 } else
530 fc_rport_error(rport, fp); 547 fc_rport_error_retry(rport, fp);
531 548
532out: 549out:
533 fc_frame_free(fp); 550 fc_frame_free(fp);
@@ -557,14 +574,14 @@ static void fc_rport_enter_plogi(struct fc_rport *rport)
557 rport->maxframe_size = FC_MIN_MAX_PAYLOAD; 574 rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
558 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); 575 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
559 if (!fp) { 576 if (!fp) {
560 fc_rport_error(rport, fp); 577 fc_rport_error_retry(rport, fp);
561 return; 578 return;
562 } 579 }
563 rdata->e_d_tov = lport->e_d_tov; 580 rdata->e_d_tov = lport->e_d_tov;
564 581
565 if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI, 582 if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI,
566 fc_rport_plogi_resp, rport, lport->e_d_tov)) 583 fc_rport_plogi_resp, rport, lport->e_d_tov))
567 fc_rport_error(rport, fp); 584 fc_rport_error_retry(rport, fp);
568 else 585 else
569 get_device(&rport->dev); 586 get_device(&rport->dev);
570} 587}
@@ -604,7 +621,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
604 } 621 }
605 622
606 if (IS_ERR(fp)) { 623 if (IS_ERR(fp)) {
607 fc_rport_error(rport, fp); 624 fc_rport_error_retry(rport, fp);
608 goto err; 625 goto err;
609 } 626 }
610 627
@@ -662,7 +679,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
662 rport->port_id); 679 rport->port_id);
663 680
664 if (IS_ERR(fp)) { 681 if (IS_ERR(fp)) {
665 fc_rport_error(rport, fp); 682 fc_rport_error_retry(rport, fp);
666 goto err; 683 goto err;
667 } 684 }
668 685
@@ -712,13 +729,13 @@ static void fc_rport_enter_prli(struct fc_rport *rport)
712 729
713 fp = fc_frame_alloc(lport, sizeof(*pp)); 730 fp = fc_frame_alloc(lport, sizeof(*pp));
714 if (!fp) { 731 if (!fp) {
715 fc_rport_error(rport, fp); 732 fc_rport_error_retry(rport, fp);
716 return; 733 return;
717 } 734 }
718 735
719 if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI, 736 if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI,
720 fc_rport_prli_resp, rport, lport->e_d_tov)) 737 fc_rport_prli_resp, rport, lport->e_d_tov))
721 fc_rport_error(rport, fp); 738 fc_rport_error_retry(rport, fp);
722 else 739 else
723 get_device(&rport->dev); 740 get_device(&rport->dev);
724} 741}
@@ -809,13 +826,13 @@ static void fc_rport_enter_rtv(struct fc_rport *rport)
809 826
810 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv)); 827 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
811 if (!fp) { 828 if (!fp) {
812 fc_rport_error(rport, fp); 829 fc_rport_error_retry(rport, fp);
813 return; 830 return;
814 } 831 }
815 832
816 if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV, 833 if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV,
817 fc_rport_rtv_resp, rport, lport->e_d_tov)) 834 fc_rport_rtv_resp, rport, lport->e_d_tov))
818 fc_rport_error(rport, fp); 835 fc_rport_error_retry(rport, fp);
819 else 836 else
820 get_device(&rport->dev); 837 get_device(&rport->dev);
821} 838}
@@ -840,13 +857,13 @@ static void fc_rport_enter_logo(struct fc_rport *rport)
840 857
841 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); 858 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
842 if (!fp) { 859 if (!fp) {
843 fc_rport_error(rport, fp); 860 fc_rport_error_retry(rport, fp);
844 return; 861 return;
845 } 862 }
846 863
847 if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO, 864 if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO,
848 fc_rport_logo_resp, rport, lport->e_d_tov)) 865 fc_rport_logo_resp, rport, lport->e_d_tov))
849 fc_rport_error(rport, fp); 866 fc_rport_error_retry(rport, fp);
850 else 867 else
851 get_device(&rport->dev); 868 get_device(&rport->dev);
852} 869}
diff --git a/include/scsi/fc/fc_fs.h b/include/scsi/fc/fc_fs.h
index 3e4801d2bdbb..1b7af3a64c7c 100644
--- a/include/scsi/fc/fc_fs.h
+++ b/include/scsi/fc/fc_fs.h
@@ -337,4 +337,9 @@ enum fc_pf_rjt_reason {
337 FC_RJT_VENDOR = 0xff, /* vendor specific reject */ 337 FC_RJT_VENDOR = 0xff, /* vendor specific reject */
338}; 338};
339 339
340/* default timeout values */
341
342#define FC_DEF_E_D_TOV 2000UL
343#define FC_DEF_R_A_TOV 10000UL
344
340#endif /* _FC_FS_H_ */ 345#endif /* _FC_FS_H_ */