drm/nouveau: off by one in init_i2c_device_find()
[safe/jmp/linux-2.6] / drivers / scsi / fcoe / libfcoe.c
index 1ea17a3..50aaa4b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/if_vlan.h>
 #include <linux/errno.h>
 #include <linux/bitops.h>
+#include <linux/slab.h>
 #include <net/rtnetlink.h>
 
 #include <scsi/fc/fc_els.h>
@@ -50,7 +51,7 @@ MODULE_LICENSE("GPL v2");
 #define        FCOE_CTLR_DEF_FKA       FIP_DEF_FKA     /* default keep alive (mS) */
 
 static void fcoe_ctlr_timeout(unsigned long);
-static void fcoe_ctlr_link_work(struct work_struct *);
+static void fcoe_ctlr_timer_work(struct work_struct *);
 static void fcoe_ctlr_recv_work(struct work_struct *);
 
 static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
@@ -74,9 +75,10 @@ do {                                                 \
        LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING,                          \
                              printk(KERN_INFO "libfcoe: " fmt, ##args);)
 
-#define LIBFCOE_FIP_DBG(fmt, args...)                                  \
+#define LIBFCOE_FIP_DBG(fip, fmt, args...)                             \
        LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING,                      \
-                             printk(KERN_INFO "fip: " fmt, ##args);)
+                             printk(KERN_INFO "host%d: fip: " fmt,     \
+                                    (fip)->lp->host->host_no, ##args);)
 
 /**
  * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid
@@ -114,7 +116,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)
        spin_lock_init(&fip->lock);
        fip->flogi_oxid = FC_XID_UNKNOWN;
        setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
-       INIT_WORK(&fip->link_work, fcoe_ctlr_link_work);
+       INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
        INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
        skb_queue_head_init(&fip->fip_recv_list);
 }
@@ -155,16 +157,14 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
 void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
 {
        cancel_work_sync(&fip->recv_work);
-       spin_lock_bh(&fip->fip_recv_list.lock);
-       __skb_queue_purge(&fip->fip_recv_list);
-       spin_unlock_bh(&fip->fip_recv_list.lock);
+       skb_queue_purge(&fip->fip_recv_list);
 
        spin_lock_bh(&fip->lock);
        fip->state = FIP_ST_DISABLED;
        fcoe_ctlr_reset_fcfs(fip);
        spin_unlock_bh(&fip->lock);
        del_timer_sync(&fip->timer);
-       cancel_work_sync(&fip->link_work);
+       cancel_work_sync(&fip->timer_work);
 }
 EXPORT_SYMBOL(fcoe_ctlr_destroy);
 
@@ -257,17 +257,13 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
 {
        spin_lock_bh(&fip->lock);
        if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
-               fip->last_link = 1;
-               fip->link = 1;
                spin_unlock_bh(&fip->lock);
                fc_linkup(fip->lp);
        } else if (fip->state == FIP_ST_LINK_WAIT) {
                fip->state = fip->mode;
-               fip->last_link = 1;
-               fip->link = 1;
                spin_unlock_bh(&fip->lock);
                if (fip->state == FIP_ST_AUTO)
-                       LIBFCOE_FIP_DBG("%s", "setting AUTO mode.\n");
+                       LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
                fc_linkup(fip->lp);
                fcoe_ctlr_solicit(fip, NULL);
        } else
@@ -278,38 +274,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;
 }
 
 /**
@@ -323,7 +297,18 @@ 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->state != FIP_ST_LINK_WAIT;
+       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);
 
@@ -358,11 +343,10 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
 
        fcf = fip->sel_fcf;
        lp = fip->lp;
-       if (!fcf || !fc_host_port_id(lp->host))
+       if (!fcf || !lp->port_id)
                return;
 
-       len = fcoe_ctlr_fcoe_size(fip) + sizeof(struct ethhdr);
-       BUG_ON(len < sizeof(*kal) + sizeof(*vn));
+       len = sizeof(*kal) + ports * sizeof(*vn);
        skb = dev_alloc_skb(len);
        if (!skb)
                return;
@@ -390,8 +374,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
                vn->fd_desc.fip_dtype = FIP_DT_VN_ID;
                vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;
                memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-               hton24(vn->fd_fc_id, fc_host_port_id(lp->host));
-               put_unaligned_be64(lp->wwpn, &vn->fd_wwpn);
+               hton24(vn->fd_fc_id, lport->port_id);
+               put_unaligned_be64(lport->wwpn, &vn->fd_wwpn);
        }
        skb_put(skb, len);
        skb->protocol = htons(ETH_P_FIP);
@@ -455,13 +439,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
        cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
 
        mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
-       memset(mac, 0, sizeof(mac));
+       memset(mac, 0, sizeof(*mac));
        mac->fd_desc.fip_dtype = FIP_DT_MAC;
        mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
-       if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC)
+       if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
                memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-       else if (fip->spma)
+       } else if (fip_flags & FIP_FL_SPMA) {
+               LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
                memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
+       } else {
+               LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
+               /* FPMA only FLOGI must leave the MAC desc set to all 0s */
+       }
 
        skb->protocol = htons(ETH_P_FIP);
        skb_reset_mac_header(skb);
@@ -510,6 +499,8 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
 
        if (fip->state == FIP_ST_NON_FIP)
                return 0;
+       if (!fip->sel_fcf)
+               goto drop;
 
        switch (op) {
        case ELS_FLOGI:
@@ -564,21 +555,38 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
  * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller
  * @fip: The FCoE controller to free FCFs on
  *
- * Called with lock held.
+ * Called with lock held and preemption disabled.
  *
  * An FCF is considered old if we have missed three advertisements.
  * That is, there have been no valid advertisement from it for three
  * times its keep-alive period including fuzz.
  *
  * In addition, determine the time when an FCF selection can occur.
+ *
+ * Also, increment the MissDiscAdvCount when no advertisement is received
+ * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
  */
 static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 {
        struct fcoe_fcf *fcf;
        struct fcoe_fcf *next;
        unsigned long sel_time = 0;
+       unsigned long mda_time = 0;
+       struct fcoe_dev_stats *stats;
 
        list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
+               mda_time = fcf->fka_period + (fcf->fka_period >> 1);
+               if ((fip->sel_fcf == fcf) &&
+                   (time_after(jiffies, fcf->time + mda_time))) {
+                       mod_timer(&fip->timer, jiffies + mda_time);
+                       stats = per_cpu_ptr(fip->lp->dev_stats,
+                                           smp_processor_id());
+                       stats->MissDiscAdvCount++;
+                       printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
+                              "Advertisement for fab %16.16llx count %lld\n",
+                              fip->lp->host->host_no, fcf->fabric_name,
+                              stats->MissDiscAdvCount);
+               }
                if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
                               msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
                        if (fip->sel_fcf == fcf)
@@ -587,6 +595,9 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
                        WARN_ON(!fip->fcf_count);
                        fip->fcf_count--;
                        kfree(fcf);
+                       stats = per_cpu_ptr(fip->lp->dev_stats,
+                                           smp_processor_id());
+                       stats->VLinkFailureCount++;
                } else if (fcoe_ctlr_mtu_valid(fcf) &&
                           (!sel_time || time_before(sel_time, fcf->time))) {
                        sel_time = fcf->time;
@@ -604,13 +615,15 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 
 /**
  * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry
+ * @fip: The FCoE controller receiving the advertisement
  * @skb: The received FIP advertisement frame
  * @fcf: The resulting FCF entry
  *
  * Returns zero on a valid parsed advertisement,
  * otherwise returns non zero value.
  */
-static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
+static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
+                              struct sk_buff *skb, struct fcoe_fcf *fcf)
 {
        struct fip_header *fiph;
        struct fip_desc *desc = NULL;
@@ -649,7 +662,7 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
                               ((struct fip_mac_desc *)desc)->fd_mac,
                               ETH_ALEN);
                        if (!is_valid_ether_addr(fcf->fcf_mac)) {
-                               LIBFCOE_FIP_DBG("Invalid MAC address "
+                               LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
                                                "in FIP adv\n");
                                return -EINVAL;
                        }
@@ -672,6 +685,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
                        if (dlen != sizeof(struct fip_fka_desc))
                                goto len_err;
                        fka = (struct fip_fka_desc *)desc;
+                       if (fka->fd_flags & FIP_FKA_ADV_D)
+                               fcf->fd_flags = 1;
                        t = ntohl(fka->fd_fka_period);
                        if (t >= FCOE_CTLR_MIN_FKA)
                                fcf->fka_period = msecs_to_jiffies(t);
@@ -683,7 +698,7 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
                case FIP_DT_LOGO:
                case FIP_DT_ELP:
                default:
-                       LIBFCOE_FIP_DBG("unexpected descriptor type %x "
+                       LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
                                        "in FIP adv\n", desc->fip_dtype);
                        /* standard says ignore unknown descriptors >= 128 */
                        if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
@@ -700,7 +715,7 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
        return 0;
 
 len_err:
-       LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n",
+       LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
                        desc->fip_dtype, dlen);
        return -EINVAL;
 }
@@ -719,7 +734,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
        int first = 0;
        int mtu_valid;
 
-       if (fcoe_ctlr_parse_adv(skb, &new))
+       if (fcoe_ctlr_parse_adv(fip, skb, &new))
                return;
 
        spin_lock_bh(&fip->lock);
@@ -765,7 +780,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
        mtu_valid = fcoe_ctlr_mtu_valid(fcf);
        fcf->time = jiffies;
        if (!found) {
-               LIBFCOE_FIP_DBG("New FCF for fab %llx map %x val %d\n",
+               LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx "
+                               "map %x val %d\n",
                                fcf->fabric_name, fcf->fc_map, mtu_valid);
        }
 
@@ -844,7 +860,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
                               ((struct fip_mac_desc *)desc)->fd_mac,
                               ETH_ALEN);
                        if (!is_valid_ether_addr(granted_mac)) {
-                               LIBFCOE_FIP_DBG("Invalid MAC address "
+                               LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
                                                "in FIP ELS\n");
                                goto drop;
                        }
@@ -864,7 +880,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
                        els_dtype = desc->fip_dtype;
                        break;
                default:
-                       LIBFCOE_FIP_DBG("unexpected descriptor type %x "
+                       LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
                                        "in FIP adv\n", desc->fip_dtype);
                        /* standard says ignore unknown descriptors >= 128 */
                        if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
@@ -895,15 +911,16 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
        fr_eof(fp) = FC_EOF_T;
        fr_dev(fp) = lport;
 
-       stats = fc_lport_get_stats(lport);
+       stats = per_cpu_ptr(lport->dev_stats, get_cpu());
        stats->RxFrames++;
        stats->RxWords += skb->len / FIP_BPW;
+       put_cpu();
 
        fc_exch_recv(lport, fp);
        return;
 
 len_err:
-       LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n",
+       LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
                        desc->fip_dtype, dlen);
 drop:
        kfree_skb(skb);
@@ -930,10 +947,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
        struct fc_lport *lport = fip->lp;
        u32     desc_mask;
 
-       LIBFCOE_FIP_DBG("Clear Virtual Link received\n");
-       if (!fcf)
-               return;
-       if (!fcf || !fc_host_port_id(lport->host))
+       LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
+
+       if (!fcf || !lport->port_id)
                return;
 
        /*
@@ -971,8 +987,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
                        if (compare_ether_addr(vp->fd_mac,
                                               fip->get_src_addr(lport)) == 0 &&
                            get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
-                           ntoh24(vp->fd_fc_id) ==
-                           fc_host_port_id(lport->host))
+                           ntoh24(vp->fd_fc_id) == lport->port_id)
                                desc_mask &= ~BIT(FIP_DT_VN_ID);
                        break;
                default:
@@ -989,10 +1004,19 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
         * reset only if all required descriptors were present and valid.
         */
        if (desc_mask) {
-               LIBFCOE_FIP_DBG("missing descriptors mask %x\n", desc_mask);
+               LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n",
+                               desc_mask);
        } else {
-               LIBFCOE_FIP_DBG("performing Clear Virtual Link\n");
-               fcoe_ctlr_reset(fip, FIP_ST_ENABLED);
+               LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
+
+               spin_lock_bh(&fip->lock);
+               per_cpu_ptr(lport->dev_stats,
+                           smp_processor_id())->VLinkFailureCount++;
+               fcoe_ctlr_reset(fip);
+               spin_unlock_bh(&fip->lock);
+
+               fc_lport_reset(fip->lp);
+               fcoe_ctlr_solicit(fip, NULL);
        }
 }
 
@@ -1001,13 +1025,11 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
  * @fip: The FCoE controller that received the packet
  * @skb: The received FIP packet
  *
- * This is called from NET_RX_SOFTIRQ.
+ * This may be called from either NET_RX_SOFTIRQ or IRQ.
  */
 void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
-       spin_lock_bh(&fip->fip_recv_list.lock);
-       __skb_queue_tail(&fip->fip_recv_list, skb);
-       spin_unlock_bh(&fip->fip_recv_list.lock);
+       skb_queue_tail(&fip->fip_recv_list, skb);
        schedule_work(&fip->recv_work);
 }
 EXPORT_SYMBOL(fcoe_ctlr_recv);
@@ -1050,7 +1072,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
                fip->map_dest = 0;
                fip->state = FIP_ST_ENABLED;
                state = FIP_ST_ENABLED;
-               LIBFCOE_FIP_DBG("Using FIP mode\n");
+               LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
        }
        spin_unlock_bh(&fip->lock);
        if (state != FIP_ST_ENABLED)
@@ -1085,15 +1107,17 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
        struct fcoe_fcf *best = NULL;
 
        list_for_each_entry(fcf, &fip->fcfs, list) {
-               LIBFCOE_FIP_DBG("consider FCF for fab %llx VFID %d map %x "
-                               "val %d\n", fcf->fabric_name, fcf->vfid,
+               LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx "
+                               "VFID %d map %x val %d\n",
+                               fcf->fabric_name, fcf->vfid,
                                fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
                if (!fcoe_ctlr_fcf_usable(fcf)) {
-                       LIBFCOE_FIP_DBG("FCF for fab %llx map %x %svalid "
-                                       "%savailable\n", fcf->fabric_name,
-                                       fcf->fc_map, (fcf->flags & FIP_FL_SOL)
-                                       ? "" : "in", (fcf->flags & FIP_FL_AVAIL)
-                                       ? "" : "un");
+                       LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
+                                       "map %x %svalid %savailable\n",
+                                       fcf->fabric_name, fcf->fc_map,
+                                       (fcf->flags & FIP_FL_SOL) ? "" : "in",
+                                       (fcf->flags & FIP_FL_AVAIL) ?
+                                       "" : "un");
                        continue;
                }
                if (!best) {
@@ -1103,7 +1127,7 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
                if (fcf->fabric_name != best->fabric_name ||
                    fcf->vfid != best->vfid ||
                    fcf->fc_map != best->fc_map) {
-                       LIBFCOE_FIP_DBG("Conflicting fabric, VFID, "
+                       LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
                                        "or FC-MAP\n");
                        return;
                }
@@ -1152,18 +1176,17 @@ 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->timer_work);
                }
-               schedule_work(&fip->link_work);
        }
 
-       if (sel) {
+       if (sel && !sel->fd_flags) {
                if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
                        fip->ctlr_ka_time = jiffies + sel->fka_period;
                        fip->send_ctlr_ka = 1;
@@ -1172,7 +1195,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
                        next_timer = fip->ctlr_ka_time;
 
                if (time_after_eq(jiffies, fip->port_ka_time)) {
-                       fip->port_ka_time += jiffies +
+                       fip->port_ka_time = jiffies +
                                msecs_to_jiffies(FIP_VN_KA_PERIOD);
                        fip->send_port_ka = 1;
                }
@@ -1185,40 +1208,32 @@ static void fcoe_ctlr_timeout(unsigned long arg)
                mod_timer(&fip->timer, next_timer);
        }
        if (fip->send_ctlr_ka || fip->send_port_ka)
-               schedule_work(&fip->link_work);
+               schedule_work(&fip->timer_work);
        spin_unlock_bh(&fip->lock);
 }
 
 /**
- * fcoe_ctlr_link_work() - Worker thread function for link changes
+ * fcoe_ctlr_timer_work() - Worker thread function for timer work
  * @work: Handle to a FCoE controller
  *
- * See if the link status has changed and if so, report it.
- *
- * This is here because fc_linkup() and fc_linkdown() must not
+ * Sends keep-alives and resets which must not
  * be called from the timer directly, since they use a mutex.
  */
-static void fcoe_ctlr_link_work(struct work_struct *work)
+static void fcoe_ctlr_timer_work(struct work_struct *work)
 {
        struct fcoe_ctlr *fip;
        struct fc_lport *vport;
        u8 *mac;
-       int link;
-       int last_link;
+       int reset;
 
-       fip = container_of(work, struct fcoe_ctlr, link_work);
+       fip = container_of(work, struct fcoe_ctlr, timer_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);
-       }
+       if (reset)
+               fc_lport_reset(fip->lp);
 
        if (fip->send_ctlr_ka) {
                fip->send_ctlr_ka = 0;
@@ -1247,20 +1262,14 @@ static void fcoe_ctlr_recv_work(struct work_struct *recv_work)
        struct sk_buff *skb;
 
        fip = container_of(recv_work, struct fcoe_ctlr, recv_work);
-       spin_lock_bh(&fip->fip_recv_list.lock);
-       while ((skb = __skb_dequeue(&fip->fip_recv_list))) {
-               spin_unlock_bh(&fip->fip_recv_list.lock);
+       while ((skb = skb_dequeue(&fip->fip_recv_list)))
                fcoe_ctlr_recv_handler(fip, skb);
-               spin_lock_bh(&fip->fip_recv_list.lock);
-       }
-       spin_unlock_bh(&fip->fip_recv_list.lock);
 }
 
 /**
- * fcoe_ctlr_recv_flogi() - Snoop pre-FIP receipt of FLOGI response or request
+ * fcoe_ctlr_recv_flogi() - Snoop pre-FIP receipt of FLOGI response
  * @fip: The FCoE controller
  * @fp:         The FC frame to snoop
- * @sa:         Ethernet source MAC address from received FCoE frame
  *
  * Snoop potential response to FLOGI or even incoming FLOGI.
  *
@@ -1268,16 +1277,18 @@ static void fcoe_ctlr_recv_work(struct work_struct *recv_work)
  * by fip->flogi_oxid != FC_XID_UNKNOWN.
  *
  * The caller is responsible for freeing the frame.
+ * Fill in the granted_mac address.
  *
  * Return non-zero if the frame should not be delivered to libfc.
  */
 int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
-                        struct fc_frame *fp, u8 *sa)
+                        struct fc_frame *fp)
 {
        struct fc_frame_header *fh;
        u8 op;
-       u8 mac[ETH_ALEN];
+       u8 *sa;
 
+       sa = eth_hdr(&fp->skb)->h_source;
        fh = fc_frame_header_get(fp);
        if (fh->fh_type != FC_TYPE_ELS)
                return 0;
@@ -1292,7 +1303,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
                        return -EINVAL;
                }
                fip->state = FIP_ST_NON_FIP;
-               LIBFCOE_FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n");
+               LIBFCOE_FIP_DBG(fip,
+                               "received FLOGI LS_ACC using non-FIP mode\n");
 
                /*
                 * FLOGI accepted.
@@ -1307,9 +1319,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
                        fip->map_dest = 0;
                }
                fip->flogi_oxid = FC_XID_UNKNOWN;
-               fc_fcoe_set_mac(mac, fh->fh_d_id);
-               fip->update_mac(lport, mac);
                spin_unlock_bh(&fip->lock);
+               fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id);
        } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
                /*
                 * Save source MAC for point-to-point responses.
@@ -1318,9 +1329,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
                if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
                        memcpy(fip->dest_addr, sa, ETH_ALEN);
                        fip->map_dest = 0;
-                       if (fip->state == FIP_ST_NON_FIP)
-                               LIBFCOE_FIP_DBG("received FLOGI REQ, "
-                                               "using non-FIP mode\n");
+                       if (fip->state == FIP_ST_AUTO)
+                               LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
+                                               "Setting non-FIP mode\n");
                        fip->state = FIP_ST_NON_FIP;
                }
                spin_unlock_bh(&fip->lock);