Commit 8690cb83 authored by Joe Eykholt's avatar Joe Eykholt Committed by James Bottomley

[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: default avatarJoe Eykholt <jeykholt@cisco.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent f8fc6c2c
...@@ -557,38 +557,44 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send); ...@@ -557,38 +557,44 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
* *
* Called with lock held and preemption disabled. * Called with lock held and preemption disabled.
* *
* An FCF is considered old if we have missed three advertisements. * An FCF is considered old if we have missed two advertisements.
* That is, there have been no valid advertisement from it for three * That is, there have been no valid advertisement from it for 2.5
* times its keep-alive period including fuzz. * times its keep-alive period.
* *
* In addition, determine the time when an FCF selection can occur. * In addition, determine the time when an FCF selection can occur.
* *
* Also, increment the MissDiscAdvCount when no advertisement is received * Also, increment the MissDiscAdvCount when no advertisement is received
* for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB). * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
*
* Returns the time in jiffies for the next call.
*/ */
static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
{ {
struct fcoe_fcf *fcf; struct fcoe_fcf *fcf;
struct fcoe_fcf *next; struct fcoe_fcf *next;
unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
unsigned long deadline;
unsigned long sel_time = 0; unsigned long sel_time = 0;
unsigned long mda_time = 0;
struct fcoe_dev_stats *stats; struct fcoe_dev_stats *stats;
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
mda_time = fcf->fka_period + (fcf->fka_period >> 1); deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
if ((fip->sel_fcf == fcf) && if (fip->sel_fcf == fcf) {
(time_after(jiffies, fcf->time + mda_time))) { if (time_after(jiffies, deadline)) {
mod_timer(&fip->timer, jiffies + mda_time); stats = per_cpu_ptr(fip->lp->dev_stats,
stats = per_cpu_ptr(fip->lp->dev_stats, smp_processor_id());
smp_processor_id()); stats->MissDiscAdvCount++;
stats->MissDiscAdvCount++; printk(KERN_INFO "libfcoe: host%d: "
printk(KERN_INFO "libfcoe: host%d: Missing Discovery " "Missing Discovery Advertisement "
"Advertisement for fab %16.16llx count %lld\n", "for fab %16.16llx count %lld\n",
fip->lp->host->host_no, fcf->fabric_name, fip->lp->host->host_no, fcf->fabric_name,
stats->MissDiscAdvCount); stats->MissDiscAdvCount);
} else if (time_after(next_timer, deadline))
next_timer = deadline;
} }
if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
msecs_to_jiffies(FIP_FCF_FUZZ * 3))) { deadline += fcf->fka_period;
if (time_after(jiffies, deadline)) {
if (fip->sel_fcf == fcf) if (fip->sel_fcf == fcf)
fip->sel_fcf = NULL; fip->sel_fcf = NULL;
list_del(&fcf->list); list_del(&fcf->list);
...@@ -598,19 +604,21 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) ...@@ -598,19 +604,21 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
stats = per_cpu_ptr(fip->lp->dev_stats, stats = per_cpu_ptr(fip->lp->dev_stats,
smp_processor_id()); smp_processor_id());
stats->VLinkFailureCount++; stats->VLinkFailureCount++;
} else if (fcoe_ctlr_mtu_valid(fcf) && } else {
(!sel_time || time_before(sel_time, fcf->time))) { if (time_after(next_timer, deadline))
sel_time = fcf->time; next_timer = deadline;
if (fcoe_ctlr_mtu_valid(fcf) &&
(!sel_time || time_before(sel_time, fcf->time)))
sel_time = fcf->time;
} }
} }
if (sel_time) { if (sel_time) {
sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
fip->sel_time = sel_time; fip->sel_time = sel_time;
if (time_before(sel_time, fip->timer.expires))
mod_timer(&fip->timer, sel_time);
} else { } else {
fip->sel_time = 0; fip->sel_time = 0;
} }
return next_timer;
} }
/** /**
...@@ -1148,7 +1156,7 @@ static void fcoe_ctlr_timeout(unsigned long arg) ...@@ -1148,7 +1156,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg; struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
struct fcoe_fcf *sel; struct fcoe_fcf *sel;
struct fcoe_fcf *fcf; struct fcoe_fcf *fcf;
unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); unsigned long next_timer;
spin_lock_bh(&fip->lock); spin_lock_bh(&fip->lock);
if (fip->state == FIP_ST_DISABLED) { if (fip->state == FIP_ST_DISABLED) {
...@@ -1157,13 +1165,16 @@ static void fcoe_ctlr_timeout(unsigned long arg) ...@@ -1157,13 +1165,16 @@ static void fcoe_ctlr_timeout(unsigned long arg)
} }
fcf = fip->sel_fcf; fcf = fip->sel_fcf;
fcoe_ctlr_age_fcfs(fip); next_timer = fcoe_ctlr_age_fcfs(fip);
sel = fip->sel_fcf; sel = fip->sel_fcf;
if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) { if (!sel && fip->sel_time) {
fcoe_ctlr_select(fip); if (time_after_eq(jiffies, fip->sel_time)) {
sel = fip->sel_fcf; fcoe_ctlr_select(fip);
fip->sel_time = 0; sel = fip->sel_fcf;
fip->sel_time = 0;
} else if (time_after(next_timer, fip->sel_time))
next_timer = fip->sel_time;
} }
if (sel != fcf) { if (sel != fcf) {
...@@ -1201,12 +1212,9 @@ static void fcoe_ctlr_timeout(unsigned long arg) ...@@ -1201,12 +1212,9 @@ static void fcoe_ctlr_timeout(unsigned long arg)
} }
if (time_after(next_timer, fip->port_ka_time)) if (time_after(next_timer, fip->port_ka_time))
next_timer = fip->port_ka_time; next_timer = fip->port_ka_time;
mod_timer(&fip->timer, next_timer);
} else if (fip->sel_time) {
next_timer = fip->sel_time +
msecs_to_jiffies(FCOE_CTLR_START_DELAY);
mod_timer(&fip->timer, next_timer);
} }
if (!list_empty(&fip->fcfs))
mod_timer(&fip->timer, next_timer);
if (fip->send_ctlr_ka || fip->send_port_ka) if (fip->send_ctlr_ka || fip->send_port_ka)
schedule_work(&fip->timer_work); schedule_work(&fip->timer_work);
spin_unlock_bh(&fip->lock); spin_unlock_bh(&fip->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment