summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2009-11-03 11:48:27 -0800
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 12:01:13 -0600
commitdd42dac4ecd1799077c132aab35d3c36b26d4d8c (patch)
treed3ca67f50eccef31071bfe26e09bf97c686bc088
parent1f4aed818d26eb9ed54520fbeb85d5ee691baa94 (diff)
[SCSI] libfcoe: FIP should report link to libfc whether selected or not
The fnic driver with FIP is reporting link up, even though it's down. When the interface is shut down by the switch, we receive a clear virtual link, and set the state reported to libfc as down, although we still report it up. Clearly wrong. That causes the subsequent link down event not to be reported, and /sys shows the host "Online". Currently, in FIP mode, if an FCF times out, then link to libfc is reported as down, to stop FLOGIs. That interferes with the LLD link down being reported. Users really need to know the physical link information, to diagnose cabling issues, so physical link status should be reported to libfc. If the selected FCF needs to be reported, that should be done separately, in a later patch. 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>
-rw-r--r--drivers/scsi/fcoe/libfcoe.c60
-rw-r--r--include/scsi/libfcoe.h1
2 files changed, 31 insertions, 30 deletions
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 787e7225ddd..4d857c2aef6 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -277,38 +277,16 @@ EXPORT_SYMBOL(fcoe_ctlr_link_up);
/**
* fcoe_ctlr_reset() - Reset a FCoE controller
* @fip: The FCoE controller to reset
- * @new_state: The FIP state to be entered
- *
- * Returns non-zero if the link was up and now isn't.
*/
-static int fcoe_ctlr_reset(struct fcoe_ctlr *fip, enum fip_state new_state)
+static void fcoe_ctlr_reset(struct fcoe_ctlr *fip)
{
- struct fc_lport *lport = fip->lp;
- int link_dropped;
-
- spin_lock_bh(&fip->lock);
fcoe_ctlr_reset_fcfs(fip);
del_timer(&fip->timer);
- fip->state = new_state;
fip->ctlr_ka_time = 0;
fip->port_ka_time = 0;
fip->sol_time = 0;
fip->flogi_oxid = FC_XID_UNKNOWN;
fip->map_dest = 0;
- fip->last_link = 0;
- link_dropped = fip->link;
- fip->link = 0;
- spin_unlock_bh(&fip->lock);
-
- if (link_dropped)
- fc_linkdown(lport);
-
- if (new_state == FIP_ST_ENABLED) {
- fcoe_ctlr_solicit(fip, NULL);
- fc_linkup(lport);
- link_dropped = 0;
- }
- return link_dropped;
}
/**
@@ -322,7 +300,20 @@ static int fcoe_ctlr_reset(struct fcoe_ctlr *fip, enum fip_state new_state)
*/
int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
{
- return fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT);
+ int link_dropped;
+
+ LIBFCOE_FIP_DBG(fip, "link down.\n");
+ spin_lock_bh(&fip->lock);
+ fcoe_ctlr_reset(fip);
+ link_dropped = fip->link;
+ fip->link = 0;
+ fip->last_link = 0;
+ fip->state = FIP_ST_LINK_WAIT;
+ spin_unlock_bh(&fip->lock);
+
+ if (link_dropped)
+ fc_linkdown(fip->lp);
+ return link_dropped;
}
EXPORT_SYMBOL(fcoe_ctlr_link_down);
@@ -994,7 +985,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
desc_mask);
} else {
LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
- fcoe_ctlr_reset(fip, FIP_ST_ENABLED);
+
+ spin_lock_bh(&fip->lock);
+ fcoe_ctlr_reset(fip);
+ spin_unlock_bh(&fip->lock);
+
+ fc_lport_reset(fip->lp);
+ fcoe_ctlr_solicit(fip, NULL);
}
}
@@ -1152,15 +1149,14 @@ static void fcoe_ctlr_timeout(unsigned long arg)
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_KA_PERIOD);
fip->ctlr_ka_time = jiffies + sel->fka_period;
- fip->link = 1;
} else {
printk(KERN_NOTICE "libfcoe: host%d: "
"FIP Fibre-Channel Forwarder timed out. "
"Starting FCF discovery.\n",
fip->lp->host->host_no);
- fip->link = 0;
+ fip->reset_req = 1;
+ schedule_work(&fip->link_work);
}
- schedule_work(&fip->link_work);
}
if (sel) {
@@ -1205,20 +1201,24 @@ static void fcoe_ctlr_link_work(struct work_struct *work)
u8 *mac;
int link;
int last_link;
+ int reset;
fip = container_of(work, struct fcoe_ctlr, link_work);
spin_lock_bh(&fip->lock);
last_link = fip->last_link;
link = fip->link;
fip->last_link = link;
+ reset = fip->reset_req;
+ fip->reset_req = 0;
spin_unlock_bh(&fip->lock);
if (last_link != link) {
if (link)
fc_linkup(fip->lp);
else
- fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT);
- }
+ fc_linkdown(fip->lp);
+ } else if (reset && link)
+ fc_lport_reset(fip->lp);
if (fip->send_ctlr_ka) {
fip->send_ctlr_ka = 0;
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index 2344a00e92e..e38ffa05dc2 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -108,6 +108,7 @@ struct fcoe_ctlr {
u8 flogi_count;
u8 link;
u8 last_link;
+ u8 reset_req;
u8 map_dest;
u8 spma;
u8 send_ctlr_ka;