aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/fcoe
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2010-06-11 19:44:10 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:01:47 -0400
commit8690cb8359d8e9f8d7ca12791ef7ea32b709df8b (patch)
treef5b8d34c3d4648ec3435d98806382850b1902698 /drivers/scsi/fcoe
parentf8fc6c2c99b8085368119d6cf39b997255052826 (diff)
[SCSI] libfcoe: fix lenient aging of FCF advertisements
[This patch has several improvements to the code in the fip timers. It hasn't been tested yet. I'm sending it out for review. Vasu, perhaps you can merge this with your patch and test it together.] The current code allows an advertisement to be used even if it has been 3 times the FCF keep-alive advertisement period (FKA) since one was received from that FCF. The spec. calls for 2.5 times FKA. Fix this and make sure we detect missed keep-alives promptly. 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/fcoe')
-rw-r--r--drivers/scsi/fcoe/libfcoe.c76
1 files changed, 42 insertions, 34 deletions
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 1d5b949d4fd0..3ab3db39fc52 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -557,38 +557,44 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
557 * 557 *
558 * Called with lock held and preemption disabled. 558 * Called with lock held and preemption disabled.
559 * 559 *
560 * An FCF is considered old if we have missed three advertisements. 560 * An FCF is considered old if we have missed two advertisements.
561 * That is, there have been no valid advertisement from it for three 561 * That is, there have been no valid advertisement from it for 2.5
562 * times its keep-alive period including fuzz. 562 * times its keep-alive period.
563 * 563 *
564 * In addition, determine the time when an FCF selection can occur. 564 * In addition, determine the time when an FCF selection can occur.
565 * 565 *
566 * Also, increment the MissDiscAdvCount when no advertisement is received 566 * Also, increment the MissDiscAdvCount when no advertisement is received
567 * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB). 567 * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
568 *
569 * Returns the time in jiffies for the next call.
568 */ 570 */
569static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) 571static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
570{ 572{
571 struct fcoe_fcf *fcf; 573 struct fcoe_fcf *fcf;
572 struct fcoe_fcf *next; 574 struct fcoe_fcf *next;
575 unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
576 unsigned long deadline;
573 unsigned long sel_time = 0; 577 unsigned long sel_time = 0;
574 unsigned long mda_time = 0;
575 struct fcoe_dev_stats *stats; 578 struct fcoe_dev_stats *stats;
576 579
577 list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { 580 list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
578 mda_time = fcf->fka_period + (fcf->fka_period >> 1); 581 deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
579 if ((fip->sel_fcf == fcf) && 582 if (fip->sel_fcf == fcf) {
580 (time_after(jiffies, fcf->time + mda_time))) { 583 if (time_after(jiffies, deadline)) {
581 mod_timer(&fip->timer, jiffies + mda_time); 584 stats = per_cpu_ptr(fip->lp->dev_stats,
582 stats = per_cpu_ptr(fip->lp->dev_stats, 585 smp_processor_id());
583 smp_processor_id()); 586 stats->MissDiscAdvCount++;
584 stats->MissDiscAdvCount++; 587 printk(KERN_INFO "libfcoe: host%d: "
585 printk(KERN_INFO "libfcoe: host%d: Missing Discovery " 588 "Missing Discovery Advertisement "
586 "Advertisement for fab %16.16llx count %lld\n", 589 "for fab %16.16llx count %lld\n",
587 fip->lp->host->host_no, fcf->fabric_name, 590 fip->lp->host->host_no, fcf->fabric_name,
588 stats->MissDiscAdvCount); 591 stats->MissDiscAdvCount);
592 } else if (time_after(next_timer, deadline))
593 next_timer = deadline;
589 } 594 }
590 if (time_after(jiffies, fcf->time + fcf->fka_period * 3 + 595
591 msecs_to_jiffies(FIP_FCF_FUZZ * 3))) { 596 deadline += fcf->fka_period;
597 if (time_after(jiffies, deadline)) {
592 if (fip->sel_fcf == fcf) 598 if (fip->sel_fcf == fcf)
593 fip->sel_fcf = NULL; 599 fip->sel_fcf = NULL;
594 list_del(&fcf->list); 600 list_del(&fcf->list);
@@ -598,19 +604,21 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
598 stats = per_cpu_ptr(fip->lp->dev_stats, 604 stats = per_cpu_ptr(fip->lp->dev_stats,
599 smp_processor_id()); 605 smp_processor_id());
600 stats->VLinkFailureCount++; 606 stats->VLinkFailureCount++;
601 } else if (fcoe_ctlr_mtu_valid(fcf) && 607 } else {
602 (!sel_time || time_before(sel_time, fcf->time))) { 608 if (time_after(next_timer, deadline))
603 sel_time = fcf->time; 609 next_timer = deadline;
610 if (fcoe_ctlr_mtu_valid(fcf) &&
611 (!sel_time || time_before(sel_time, fcf->time)))
612 sel_time = fcf->time;
604 } 613 }
605 } 614 }
606 if (sel_time) { 615 if (sel_time) {
607 sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); 616 sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
608 fip->sel_time = sel_time; 617 fip->sel_time = sel_time;
609 if (time_before(sel_time, fip->timer.expires))
610 mod_timer(&fip->timer, sel_time);
611 } else { 618 } else {
612 fip->sel_time = 0; 619 fip->sel_time = 0;
613 } 620 }
621 return next_timer;
614} 622}
615 623
616/** 624/**
@@ -1148,7 +1156,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
1148 struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg; 1156 struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
1149 struct fcoe_fcf *sel; 1157 struct fcoe_fcf *sel;
1150 struct fcoe_fcf *fcf; 1158 struct fcoe_fcf *fcf;
1151 unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); 1159 unsigned long next_timer;
1152 1160
1153 spin_lock_bh(&fip->lock); 1161 spin_lock_bh(&fip->lock);
1154 if (fip->state == FIP_ST_DISABLED) { 1162 if (fip->state == FIP_ST_DISABLED) {
@@ -1157,13 +1165,16 @@ static void fcoe_ctlr_timeout(unsigned long arg)
1157 } 1165 }
1158 1166
1159 fcf = fip->sel_fcf; 1167 fcf = fip->sel_fcf;
1160 fcoe_ctlr_age_fcfs(fip); 1168 next_timer = fcoe_ctlr_age_fcfs(fip);
1161 1169
1162 sel = fip->sel_fcf; 1170 sel = fip->sel_fcf;
1163 if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) { 1171 if (!sel && fip->sel_time) {
1164 fcoe_ctlr_select(fip); 1172 if (time_after_eq(jiffies, fip->sel_time)) {
1165 sel = fip->sel_fcf; 1173 fcoe_ctlr_select(fip);
1166 fip->sel_time = 0; 1174 sel = fip->sel_fcf;
1175 fip->sel_time = 0;
1176 } else if (time_after(next_timer, fip->sel_time))
1177 next_timer = fip->sel_time;
1167 } 1178 }
1168 1179
1169 if (sel != fcf) { 1180 if (sel != fcf) {
@@ -1201,12 +1212,9 @@ static void fcoe_ctlr_timeout(unsigned long arg)
1201 } 1212 }
1202 if (time_after(next_timer, fip->port_ka_time)) 1213 if (time_after(next_timer, fip->port_ka_time))
1203 next_timer = fip->port_ka_time; 1214 next_timer = fip->port_ka_time;
1204 mod_timer(&fip->timer, next_timer);
1205 } else if (fip->sel_time) {
1206 next_timer = fip->sel_time +
1207 msecs_to_jiffies(FCOE_CTLR_START_DELAY);
1208 mod_timer(&fip->timer, next_timer);
1209 } 1215 }
1216 if (!list_empty(&fip->fcfs))
1217 mod_timer(&fip->timer, next_timer);
1210 if (fip->send_ctlr_ka || fip->send_port_ka) 1218 if (fip->send_ctlr_ka || fip->send_port_ka)
1211 schedule_work(&fip->timer_work); 1219 schedule_work(&fip->timer_work);
1212 spin_unlock_bh(&fip->lock); 1220 spin_unlock_bh(&fip->lock);