/**
  * 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;
 }
 
 /**
  */
 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);
 
                                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);
        }
 }
 
                        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) {
        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;