Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
[deliverable/linux.git] / drivers / scsi / fcoe / fcoe.c
index 03e1926f40b523c231033e809031ad9b1d138ec7..c15878e881570e6ae6344b92869b1457840e7f69 100644 (file)
@@ -54,7 +54,6 @@ MODULE_LICENSE("GPL v2");
 /* fcoe host list */
 LIST_HEAD(fcoe_hostlist);
 DEFINE_RWLOCK(fcoe_hostlist_lock);
-DEFINE_TIMER(fcoe_timer, NULL, 0, 0);
 DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
 
 /* Function Prototypes */
@@ -71,7 +70,7 @@ static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
 static int fcoe_hostlist_add(const struct fc_lport *);
 static int fcoe_hostlist_remove(const struct fc_lport *);
 
-static int fcoe_check_wait_queue(struct fc_lport *);
+static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *);
 static int fcoe_device_notification(struct notifier_block *, ulong, void *);
 static void fcoe_dev_setup(void);
 static void fcoe_dev_cleanup(void);
@@ -135,6 +134,58 @@ static struct scsi_host_template fcoe_shost_template = {
        .max_sectors = 0xffff,
 };
 
+/**
+ * fcoe_fip_recv - handle a received FIP frame.
+ * @skb: the receive skb
+ * @dev: associated &net_device
+ * @ptype: the &packet_type structure which was used to register this handler.
+ * @orig_dev: original receive &net_device, in case @dev is a bond.
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
+                        struct packet_type *ptype,
+                        struct net_device *orig_dev)
+{
+       struct fcoe_softc *fc;
+
+       fc = container_of(ptype, struct fcoe_softc, fip_packet_type);
+       fcoe_ctlr_recv(&fc->ctlr, skb);
+       return 0;
+}
+
+/**
+ * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame.
+ * @fip: FCoE controller.
+ * @skb: FIP Packet.
+ */
+static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
+{
+       skb->dev = fcoe_from_ctlr(fip)->real_dev;
+       dev_queue_xmit(skb);
+}
+
+/**
+ * fcoe_update_src_mac() - Update Ethernet MAC filters.
+ * @fip: FCoE controller.
+ * @old: Unicast MAC address to delete if the MAC is non-zero.
+ * @new: Unicast MAC address to add.
+ *
+ * Remove any previously-set unicast MAC filter.
+ * Add secondary FCoE MAC address filter for our OUI.
+ */
+static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new)
+{
+       struct fcoe_softc *fc;
+
+       fc = fcoe_from_ctlr(fip);
+       rtnl_lock();
+       if (!is_zero_ether_addr(old))
+               dev_unicast_delete(fc->real_dev, old);
+       dev_unicast_add(fc->real_dev, new);
+       rtnl_unlock();
+}
+
 /**
  * fcoe_lport_config() - sets up the fc_lport
  * @lp: ptr to the fc_lport
@@ -146,6 +197,7 @@ static int fcoe_lport_config(struct fc_lport *lp)
        lp->link_up = 0;
        lp->qfull = 0;
        lp->max_retry_count = 3;
+       lp->max_rport_retry_count = 3;
        lp->e_d_tov = 2 * 1000; /* FC-FS default */
        lp->r_a_tov = 2 * 2 * 1000;
        lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
@@ -166,6 +218,42 @@ static int fcoe_lport_config(struct fc_lport *lp)
        return 0;
 }
 
+/**
+ * fcoe_netdev_cleanup() - clean up netdev configurations
+ * @fc: ptr to the fcoe_softc
+ */
+void fcoe_netdev_cleanup(struct fcoe_softc *fc)
+{
+       u8 flogi_maddr[ETH_ALEN];
+
+       /* Don't listen for Ethernet packets anymore */
+       dev_remove_pack(&fc->fcoe_packet_type);
+       dev_remove_pack(&fc->fip_packet_type);
+
+       /* Delete secondary MAC addresses */
+       rtnl_lock();
+       memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
+       dev_unicast_delete(fc->real_dev, flogi_maddr);
+       if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
+               dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr);
+       if (fc->ctlr.spma)
+               dev_unicast_delete(fc->real_dev, fc->ctlr.ctl_src_addr);
+       dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
+       rtnl_unlock();
+}
+
+/**
+ * fcoe_queue_timer() - fcoe queue timer
+ * @lp: the fc_lport pointer
+ *
+ * Calls fcoe_check_wait_queue on timeout
+ *
+ */
+static void fcoe_queue_timer(ulong lp)
+{
+       fcoe_check_wait_queue((struct fc_lport *)lp, NULL);
+}
+
 /**
  * fcoe_netdev_config() - Set up netdev for SW FCoE
  * @lp : ptr to the fc_lport
@@ -181,6 +269,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
        u64 wwnn, wwpn;
        struct fcoe_softc *fc;
        u8 flogi_maddr[ETH_ALEN];
+       struct netdev_hw_addr *ha;
 
        /* Setup lport private data to point to fcoe softc */
        fc = lport_priv(lp);
@@ -236,10 +325,25 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
        }
        skb_queue_head_init(&fc->fcoe_pending_queue);
        fc->fcoe_pending_queue_active = 0;
+       setup_timer(&fc->timer, fcoe_queue_timer, (unsigned long)lp);
+
+       /* look for SAN MAC address, if multiple SAN MACs exist, only
+        * use the first one for SPMA */
+       rcu_read_lock();
+       for_each_dev_addr(netdev, ha) {
+               if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
+                   (is_valid_ether_addr(fc->ctlr.ctl_src_addr))) {
+                       memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN);
+                       fc->ctlr.spma = 1;
+                       break;
+               }
+       }
+       rcu_read_unlock();
 
        /* setup Source Mac Address */
-       memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr,
-              fc->real_dev->addr_len);
+       if (!fc->ctlr.spma)
+               memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr,
+                      fc->real_dev->addr_len);
 
        wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0);
        fc_set_wwnn(lp, wwnn);
@@ -254,7 +358,9 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
         */
        rtnl_lock();
        memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-       dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN);
+       dev_unicast_add(fc->real_dev, flogi_maddr);
+       if (fc->ctlr.spma)
+               dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr);
        dev_mc_add(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
        rtnl_unlock();
 
@@ -267,6 +373,11 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
        fc->fcoe_packet_type.dev = fc->real_dev;
        dev_add_pack(&fc->fcoe_packet_type);
 
+       fc->fip_packet_type.func = fcoe_fip_recv;
+       fc->fip_packet_type.type = htons(ETH_P_FIP);
+       fc->fip_packet_type.dev = fc->real_dev;
+       dev_add_pack(&fc->fip_packet_type);
+
        return 0;
 }
 
@@ -334,7 +445,6 @@ static int fcoe_if_destroy(struct net_device *netdev)
 {
        struct fc_lport *lp = NULL;
        struct fcoe_softc *fc;
-       u8 flogi_maddr[ETH_ALEN];
 
        BUG_ON(!netdev);
 
@@ -353,9 +463,10 @@ static int fcoe_if_destroy(struct net_device *netdev)
        /* Remove the instance from fcoe's list */
        fcoe_hostlist_remove(lp);
 
-       /* Don't listen for Ethernet packets anymore */
-       dev_remove_pack(&fc->fcoe_packet_type);
-       dev_remove_pack(&fc->fip_packet_type);
+       /* clean up netdev configurations */
+       fcoe_netdev_cleanup(fc);
+
+       /* tear-down the FCoE controller */
        fcoe_ctlr_destroy(&fc->ctlr);
 
        /* Cleanup the fc_lport */
@@ -370,22 +481,15 @@ static int fcoe_if_destroy(struct net_device *netdev)
        if (lp->emp)
                fc_exch_mgr_free(lp->emp);
 
-       /* Delete secondary MAC addresses */
-       rtnl_lock();
-       memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-       dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN);
-       if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
-               dev_unicast_delete(fc->real_dev,
-                                  fc->ctlr.data_src_addr, ETH_ALEN);
-       dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
-       rtnl_unlock();
-
        /* Free the per-CPU receive threads */
        fcoe_percpu_clean(lp);
 
        /* Free existing skbs */
        fcoe_clean_pending_queue(lp);
 
+       /* Stop the timer */
+       del_timer_sync(&fc->timer);
+
        /* Free memory used by statistical counters */
        fc_lport_free_stats(lp);
 
@@ -438,58 +542,6 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {
        .ddp_done = fcoe_ddp_done,
 };
 
-/**
- * fcoe_fip_recv - handle a received FIP frame.
- * @skb: the receive skb
- * @dev: associated &net_device
- * @ptype: the &packet_type structure which was used to register this handler.
- * @orig_dev: original receive &net_device, in case @dev is a bond.
- *
- * Returns: 0 for success
- */
-static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
-                        struct packet_type *ptype,
-                        struct net_device *orig_dev)
-{
-       struct fcoe_softc *fc;
-
-       fc = container_of(ptype, struct fcoe_softc, fip_packet_type);
-       fcoe_ctlr_recv(&fc->ctlr, skb);
-       return 0;
-}
-
-/**
- * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame.
- * @fip: FCoE controller.
- * @skb: FIP Packet.
- */
-static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
-{
-       skb->dev = fcoe_from_ctlr(fip)->real_dev;
-       dev_queue_xmit(skb);
-}
-
-/**
- * fcoe_update_src_mac() - Update Ethernet MAC filters.
- * @fip: FCoE controller.
- * @old: Unicast MAC address to delete if the MAC is non-zero.
- * @new: Unicast MAC address to add.
- *
- * Remove any previously-set unicast MAC filter.
- * Add secondary FCoE MAC address filter for our OUI.
- */
-static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new)
-{
-       struct fcoe_softc *fc;
-
-       fc = fcoe_from_ctlr(fip);
-       rtnl_lock();
-       if (!is_zero_ether_addr(old))
-               dev_unicast_delete(fc->real_dev, old, ETH_ALEN);
-       dev_unicast_add(fc->real_dev, new, ETH_ALEN);
-       rtnl_unlock();
-}
-
 /**
  * fcoe_if_create() - this function creates the fcoe interface
  * @netdev: pointer the associated netdevice
@@ -531,13 +583,6 @@ static int fcoe_if_create(struct net_device *netdev)
                goto out_host_put;
        }
 
-       /* configure lport network properties */
-       rc = fcoe_netdev_config(lp, netdev);
-       if (rc) {
-               FC_DBG("Could not configure netdev for lport\n");
-               goto out_host_put;
-       }
-
        /*
         * Initialize FIP.
         */
@@ -545,23 +590,25 @@ static int fcoe_if_create(struct net_device *netdev)
        fc->ctlr.send = fcoe_fip_send;
        fc->ctlr.update_mac = fcoe_update_src_mac;
 
-       fc->fip_packet_type.func = fcoe_fip_recv;
-       fc->fip_packet_type.type = htons(ETH_P_FIP);
-       fc->fip_packet_type.dev = fc->real_dev;
-       dev_add_pack(&fc->fip_packet_type);
+       /* configure lport network properties */
+       rc = fcoe_netdev_config(lp, netdev);
+       if (rc) {
+               FC_DBG("Could not configure netdev for the interface\n");
+               goto out_netdev_cleanup;
+       }
 
        /* configure lport scsi host properties */
        rc = fcoe_shost_config(lp, shost, &netdev->dev);
        if (rc) {
                FC_DBG("Could not configure shost for lport\n");
-               goto out_host_put;
+               goto out_netdev_cleanup;
        }
 
        /* lport exch manager allocation */
        rc = fcoe_em_config(lp);
        if (rc) {
                FC_DBG("Could not configure em for lport\n");
-               goto out_host_put;
+               goto out_netdev_cleanup;
        }
 
        /* Initialize the library */
@@ -587,6 +634,8 @@ static int fcoe_if_create(struct net_device *netdev)
 
 out_lp_destroy:
        fc_exch_mgr_free(lp->emp); /* Free the EM */
+out_netdev_cleanup:
+       fcoe_netdev_cleanup(fc);
 out_host_put:
        scsi_host_put(lp->host);
        return rc;
@@ -988,7 +1037,7 @@ u32 fcoe_fc_crc(struct fc_frame *fp)
  */
 int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
 {
-       int wlen, rc = 0;
+       int wlen;
        u32 crc;
        struct ethhdr *eh;
        struct fcoe_crc_eof *cp;
@@ -1021,8 +1070,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
        sof = fr_sof(fp);
        eof = fr_eof(fp);
 
-       elen = (fc->real_dev->priv_flags & IFF_802_1Q_VLAN) ?
-               sizeof(struct vlan_ethhdr) : sizeof(struct ethhdr);
+       elen = sizeof(struct ethhdr);
        hlen = sizeof(struct fcoe_hdr);
        tlen = sizeof(struct fcoe_crc_eof);
        wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
@@ -1107,18 +1155,9 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
        /* send down to lld */
        fr_dev(fp) = lp;
        if (fc->fcoe_pending_queue.qlen)
-               rc = fcoe_check_wait_queue(lp);
-
-       if (rc == 0)
-               rc = fcoe_start_io(skb);
-
-       if (rc) {
-               spin_lock_bh(&fc->fcoe_pending_queue.lock);
-               __skb_queue_tail(&fc->fcoe_pending_queue, skb);
-               spin_unlock_bh(&fc->fcoe_pending_queue.lock);
-               if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
-                       lp->qfull = 1;
-       }
+               fcoe_check_wait_queue(lp, skb);
+       else if (fcoe_start_io(skb))
+               fcoe_check_wait_queue(lp, skb);
 
        return 0;
 }
@@ -1267,32 +1306,6 @@ int fcoe_percpu_receive_thread(void *arg)
        return 0;
 }
 
-/**
- * fcoe_watchdog() - fcoe timer callback
- * @vp:
- *
- * This checks the pending queue length for fcoe and set lport qfull
- * if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the
- * fcoe_hostlist.
- *
- * Returns: 0 for success
- */
-void fcoe_watchdog(ulong vp)
-{
-       struct fcoe_softc *fc;
-
-       read_lock(&fcoe_hostlist_lock);
-       list_for_each_entry(fc, &fcoe_hostlist, list) {
-               if (fc->ctlr.lp)
-                       fcoe_check_wait_queue(fc->ctlr.lp);
-       }
-       read_unlock(&fcoe_hostlist_lock);
-
-       fcoe_timer.expires = jiffies + (1 * HZ);
-       add_timer(&fcoe_timer);
-}
-
-
 /**
  * fcoe_check_wait_queue() - attempt to clear the transmit backlog
  * @lp: the fc_lport
@@ -1305,16 +1318,17 @@ void fcoe_watchdog(ulong vp)
  * The wait_queue is used when the skb transmit fails. skb will go
  * in the wait_queue which will be emptied by the timer function or
  * by the next skb transmit.
- *
- * Returns: 0 for success
  */
-static int fcoe_check_wait_queue(struct fc_lport *lp)
+static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb)
 {
        struct fcoe_softc *fc = lport_priv(lp);
-       struct sk_buff *skb;
-       int rc = -1;
+       int rc;
 
        spin_lock_bh(&fc->fcoe_pending_queue.lock);
+
+       if (skb)
+               __skb_queue_tail(&fc->fcoe_pending_queue, skb);
+
        if (fc->fcoe_pending_queue_active)
                goto out;
        fc->fcoe_pending_queue_active = 1;
@@ -1340,23 +1354,26 @@ static int fcoe_check_wait_queue(struct fc_lport *lp)
 
        if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
                lp->qfull = 0;
+       if (fc->fcoe_pending_queue.qlen && !timer_pending(&fc->timer))
+               mod_timer(&fc->timer, jiffies + 2);
        fc->fcoe_pending_queue_active = 0;
-       rc = fc->fcoe_pending_queue.qlen;
 out:
+       if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
+               lp->qfull = 1;
        spin_unlock_bh(&fc->fcoe_pending_queue.lock);
-       return rc;
+       return;
 }
 
 /**
  * fcoe_dev_setup() - setup link change notification interface
  */
-static void fcoe_dev_setup()
+static void fcoe_dev_setup(void)
 {
        register_netdevice_notifier(&fcoe_notifier);
 }
 
 /**
- * fcoe_dev_setup() - cleanup link change notification interface
+ * fcoe_dev_cleanup() - cleanup link change notification interface
  */
 static void fcoe_dev_cleanup(void)
 {
@@ -1815,10 +1832,6 @@ static int __init fcoe_init(void)
        /* Setup link change notification */
        fcoe_dev_setup();
 
-       setup_timer(&fcoe_timer, fcoe_watchdog, 0);
-
-       mod_timer(&fcoe_timer, jiffies + (10 * HZ));
-
        fcoe_if_init();
 
        return 0;
@@ -1844,9 +1857,6 @@ static void __exit fcoe_exit(void)
 
        fcoe_dev_cleanup();
 
-       /* Stop the timer */
-       del_timer_sync(&fcoe_timer);
-
        /* releases the associated fcoe hosts */
        list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list)
                fcoe_if_destroy(fc->real_dev);
This page took 0.11608 seconds and 5 git commands to generate.