[SCSI] fcoe, bnx2fc, libfcoe: SW FCoE and bnx2fc use FCoE Syfs
authorRobert Love <robert.w.love@intel.com>
Wed, 23 May 2012 02:06:26 +0000 (19:06 -0700)
committerJames Bottomley <JBottomley@Parallels.com>
Wed, 23 May 2012 08:43:13 +0000 (09:43 +0100)
This patch has the SW FCoE driver and the bnx2fc
driver make use of the new fcoe_sysfs API added
earlier in this patch series.

After this patch a fcoe_ctlr_device is allocated with
private data in this order.

+------------------+   +------------------+
| fcoe_ctlr_device |   | fcoe_ctlr_device |
+------------------+   +------------------+
| fcoe_ctlr        |   | fcoe_ctlr        |
+------------------+   +------------------+
| fcoe_interface   |   | bnx2fc_interface |
+------------------+   +------------------+

libfcoe also takes part in this new model since it
discovers and manages fcoe_fcf instances. The memory
allocation is different for FCFs. I didn't want to
impact libfcoe's fcoe_fcf processing, so this patch
creates fcoe_fcf_device instances for each discovered
fcoe_fcf. The two are paired using a (void * priv)
member of the fcoe_ctlr_device. This allows libfcoe
to continue maintaining its list of fcoe_fcf instances
and simply attaches and detaches them from existing
or new fcoe_fcf_device instances.

Signed-off-by: Robert Love <robert.w.love@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe_ctlr.c
include/scsi/libfcoe.h

index cb9bf364170bdbb56050bc2ec520aca067e9801d..f52f668fd247b5601e27ac9572c99b6832302ca8 100644 (file)
@@ -54,6 +54,7 @@ static struct cnic_ulp_ops bnx2fc_cnic_cb;
 static struct libfc_function_template bnx2fc_libfc_fcn_templ;
 static struct scsi_host_template bnx2fc_shost_template;
 static struct fc_function_template bnx2fc_transport_function;
+static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ;
 static struct fc_function_template bnx2fc_vport_xport_function;
 static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode);
 static void __bnx2fc_destroy(struct bnx2fc_interface *interface);
@@ -88,6 +89,7 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport);
 static void bnx2fc_stop(struct bnx2fc_interface *interface);
 static int __init bnx2fc_mod_init(void);
 static void __exit bnx2fc_mod_exit(void);
+static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev);
 
 unsigned int bnx2fc_debug_level;
 module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR);
@@ -118,6 +120,41 @@ static void bnx2fc_get_lesb(struct fc_lport *lport,
        __fcoe_get_lesb(lport, fc_lesb, netdev);
 }
 
+static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
+{
+       struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
+       struct net_device *netdev = bnx2fc_netdev(fip->lp);
+       struct fcoe_fc_els_lesb *fcoe_lesb;
+       struct fc_els_lesb fc_lesb;
+
+       __fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
+       fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
+
+       ctlr_dev->lesb.lesb_link_fail =
+               ntohl(fcoe_lesb->lesb_link_fail);
+       ctlr_dev->lesb.lesb_vlink_fail =
+               ntohl(fcoe_lesb->lesb_vlink_fail);
+       ctlr_dev->lesb.lesb_miss_fka =
+               ntohl(fcoe_lesb->lesb_miss_fka);
+       ctlr_dev->lesb.lesb_symb_err =
+               ntohl(fcoe_lesb->lesb_symb_err);
+       ctlr_dev->lesb.lesb_err_block =
+               ntohl(fcoe_lesb->lesb_err_block);
+       ctlr_dev->lesb.lesb_fcs_error =
+               ntohl(fcoe_lesb->lesb_fcs_error);
+}
+EXPORT_SYMBOL(bnx2fc_ctlr_get_lesb);
+
+static void bnx2fc_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev)
+{
+       struct fcoe_ctlr_device *ctlr_dev =
+               fcoe_fcf_dev_to_ctlr_dev(fcf_dev);
+       struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+       struct bnx2fc_interface *fcoe = fcoe_ctlr_priv(ctlr);
+
+       fcf_dev->vlan_id = fcoe->vlan_id;
+}
+
 static void bnx2fc_clean_rx_queue(struct fc_lport *lp)
 {
        struct fcoe_percpu_s *bg;
@@ -1235,6 +1272,7 @@ static void bnx2fc_release_transport(void)
 
 static void bnx2fc_interface_release(struct kref *kref)
 {
+       struct fcoe_ctlr_device *ctlr_dev;
        struct bnx2fc_interface *interface;
        struct fcoe_ctlr *ctlr;
        struct net_device *netdev;
@@ -1243,13 +1281,14 @@ static void bnx2fc_interface_release(struct kref *kref)
        BNX2FC_MISC_DBG("Interface is being released\n");
 
        ctlr = bnx2fc_to_ctlr(interface);
+       ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr);
        netdev = interface->netdev;
 
        /* tear-down FIP controller */
        if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags))
                fcoe_ctlr_destroy(ctlr);
 
-       kfree(ctlr);
+       fcoe_ctlr_device_delete(ctlr_dev);
 
        dev_put(netdev);
        module_put(THIS_MODULE);
@@ -1342,17 +1381,20 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba,
                                      struct net_device *netdev,
                                      enum fip_state fip_mode)
 {
+       struct fcoe_ctlr_device *ctlr_dev;
        struct bnx2fc_interface *interface;
        struct fcoe_ctlr *ctlr;
        int size;
        int rc = 0;
 
        size = (sizeof(*interface) + sizeof(struct fcoe_ctlr));
-       ctlr = kzalloc(size, GFP_KERNEL);
-       if (!ctlr) {
+       ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &bnx2fc_fcoe_sysfs_templ,
+                                        size);
+       if (!ctlr_dev) {
                printk(KERN_ERR PFX "Unable to allocate interface structure\n");
                return NULL;
        }
+       ctlr = fcoe_ctlr_device_priv(ctlr_dev);
        interface = fcoe_ctlr_priv(ctlr);
        dev_hold(netdev);
        kref_init(&interface->kref);
@@ -1372,7 +1414,7 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba,
 
        fcoe_ctlr_destroy(ctlr);
        dev_put(netdev);
-       kfree(ctlr);
+       fcoe_ctlr_device_delete(ctlr_dev);
        return NULL;
 }
 
@@ -2471,6 +2513,19 @@ static void __exit bnx2fc_mod_exit(void)
 module_init(bnx2fc_mod_init);
 module_exit(bnx2fc_mod_exit);
 
+static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = {
+       .get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode,
+       .get_fcoe_ctlr_link_fail = bnx2fc_ctlr_get_lesb,
+       .get_fcoe_ctlr_vlink_fail = bnx2fc_ctlr_get_lesb,
+       .get_fcoe_ctlr_miss_fka = bnx2fc_ctlr_get_lesb,
+       .get_fcoe_ctlr_symb_err = bnx2fc_ctlr_get_lesb,
+       .get_fcoe_ctlr_err_block = bnx2fc_ctlr_get_lesb,
+       .get_fcoe_ctlr_fcs_error = bnx2fc_ctlr_get_lesb,
+
+       .get_fcoe_fcf_selected = fcoe_fcf_get_selected,
+       .get_fcoe_fcf_vlan_id = bnx2fc_fcf_get_vlan_id,
+};
+
 static struct fc_function_template bnx2fc_transport_function = {
        .show_host_node_name = 1,
        .show_host_port_name = 1,
index 4bb42e19d53767c779f6d739796f884eea7142c8..fe30b1b65e1d3ddc879823a79404efdcc60d4982 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <scsi/fc/fc_encaps.h>
 #include <scsi/fc/fc_fip.h>
+#include <scsi/fc/fc_fcoe.h>
 
 #include <scsi/libfc.h>
 #include <scsi/fc_frame.h>
@@ -150,6 +151,21 @@ static int fcoe_vport_create(struct fc_vport *, bool disabled);
 static int fcoe_vport_disable(struct fc_vport *, bool disable);
 static void fcoe_set_vport_symbolic_name(struct fc_vport *);
 static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);
+static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *);
+static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *);
+
+static struct fcoe_sysfs_function_template fcoe_sysfs_templ = {
+       .get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode,
+       .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb,
+       .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb,
+       .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb,
+       .get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb,
+       .get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb,
+       .get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb,
+
+       .get_fcoe_fcf_selected = fcoe_fcf_get_selected,
+       .get_fcoe_fcf_vlan_id = fcoe_fcf_get_vlan_id,
+};
 
 static struct libfc_function_template fcoe_libfc_fcn_templ = {
        .frame_send = fcoe_xmit,
@@ -366,6 +382,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
 static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
                                                    enum fip_state fip_mode)
 {
+       struct fcoe_ctlr_device *ctlr_dev;
        struct fcoe_ctlr *ctlr;
        struct fcoe_interface *fcoe;
        int size;
@@ -379,14 +396,17 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
        }
 
        size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface);
-       ctlr = kzalloc(size, GFP_KERNEL);
-       fcoe = fcoe_ctlr_priv(ctlr);
-       if (!fcoe) {
-               FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n");
+       ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &fcoe_sysfs_templ,
+                                       size);
+       if (!ctlr_dev) {
+               FCOE_DBG("Failed to add fcoe_ctlr_device\n");
                fcoe = ERR_PTR(-ENOMEM);
                goto out_putmod;
        }
 
+       ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+       fcoe = fcoe_ctlr_priv(ctlr);
+
        dev_hold(netdev);
 
        /*
@@ -400,6 +420,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
        err = fcoe_interface_setup(fcoe, netdev);
        if (err) {
                fcoe_ctlr_destroy(ctlr);
+               fcoe_ctlr_device_delete(ctlr_dev);
                dev_put(netdev);
                fcoe = ERR_PTR(err);
                goto out_putmod;
@@ -466,6 +487,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
 {
        struct net_device *netdev = fcoe->netdev;
        struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe);
+       struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
 
        rtnl_lock();
        if (!fcoe->removed)
@@ -476,7 +498,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
        /* tear-down the FCoE controller */
        fcoe_ctlr_destroy(fip);
        scsi_host_put(fip->lp->host);
-       kfree(fip);
+       fcoe_ctlr_device_delete(ctlr_dev);
        dev_put(netdev);
        module_put(THIS_MODULE);
 }
@@ -2196,6 +2218,7 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe)
 static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
 {
        int rc = 0;
+       struct fcoe_ctlr_device *ctlr_dev;
        struct fcoe_ctlr *ctlr;
        struct fcoe_interface *fcoe;
        struct fc_lport *lport;
@@ -2216,8 +2239,8 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
        }
 
        ctlr = fcoe_to_ctlr(fcoe);
-
-       lport = fcoe_if_create(fcoe, &netdev->dev, 0);
+       ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr);
+       lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0);
        if (IS_ERR(lport)) {
                printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
                       netdev->name);
@@ -2768,6 +2791,40 @@ static void fcoe_get_lesb(struct fc_lport *lport,
        __fcoe_get_lesb(lport, fc_lesb, netdev);
 }
 
+static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
+{
+       struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
+       struct net_device *netdev = fcoe_netdev(fip->lp);
+       struct fcoe_fc_els_lesb *fcoe_lesb;
+       struct fc_els_lesb fc_lesb;
+
+       __fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
+       fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
+
+       ctlr_dev->lesb.lesb_link_fail =
+               ntohl(fcoe_lesb->lesb_link_fail);
+       ctlr_dev->lesb.lesb_vlink_fail =
+               ntohl(fcoe_lesb->lesb_vlink_fail);
+       ctlr_dev->lesb.lesb_miss_fka =
+               ntohl(fcoe_lesb->lesb_miss_fka);
+       ctlr_dev->lesb.lesb_symb_err =
+               ntohl(fcoe_lesb->lesb_symb_err);
+       ctlr_dev->lesb.lesb_err_block =
+               ntohl(fcoe_lesb->lesb_err_block);
+       ctlr_dev->lesb.lesb_fcs_error =
+               ntohl(fcoe_lesb->lesb_fcs_error);
+}
+
+static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev)
+{
+       struct fcoe_ctlr_device *ctlr_dev =
+               fcoe_fcf_dev_to_ctlr_dev(fcf_dev);
+       struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+       struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr);
+
+       fcf_dev->vlan_id = vlan_dev_vlan_id(fcoe->netdev);
+}
+
 /**
  * fcoe_set_port_id() - Callback from libfc when Port_ID is set.
  * @lport: the local port
index 5a4c7250aa77abd218ea52c65da31fb514abfd30..d68d57241ee68227703ce1880e52c2ce31b4684d 100644 (file)
@@ -160,6 +160,76 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
 }
 EXPORT_SYMBOL(fcoe_ctlr_init);
 
+static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new)
+{
+       struct fcoe_ctlr *fip = new->fip;
+       struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
+       struct fcoe_fcf_device temp, *fcf_dev;
+       int rc = 0;
+
+       LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n",
+                       new->fabric_name, new->fcf_mac);
+
+       mutex_lock(&ctlr_dev->lock);
+
+       temp.fabric_name = new->fabric_name;
+       temp.switch_name = new->switch_name;
+       temp.fc_map = new->fc_map;
+       temp.vfid = new->vfid;
+       memcpy(temp.mac, new->fcf_mac, ETH_ALEN);
+       temp.priority = new->pri;
+       temp.fka_period = new->fka_period;
+       temp.selected = 0; /* default to unselected */
+
+       fcf_dev = fcoe_fcf_device_add(ctlr_dev, &temp);
+       if (unlikely(!fcf_dev)) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * The fcoe_sysfs layer can return a CONNECTED fcf that
+        * has a priv (fcf was never deleted) or a CONNECTED fcf
+        * that doesn't have a priv (fcf was deleted). However,
+        * libfcoe will always delete FCFs before trying to add
+        * them. This is ensured because both recv_adv and
+        * age_fcfs are protected by the the fcoe_ctlr's mutex.
+        * This means that we should never get a FCF with a
+        * non-NULL priv pointer.
+        */
+       BUG_ON(fcf_dev->priv);
+
+       fcf_dev->priv = new;
+       new->fcf_dev = fcf_dev;
+
+       list_add(&new->list, &fip->fcfs);
+       fip->fcf_count++;
+
+out:
+       mutex_unlock(&ctlr_dev->lock);
+       return rc;
+}
+
+static void fcoe_sysfs_fcf_del(struct fcoe_fcf *new)
+{
+       struct fcoe_ctlr *fip = new->fip;
+       struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
+       struct fcoe_fcf_device *fcf_dev;
+
+       list_del(&new->list);
+       fip->fcf_count--;
+
+       mutex_lock(&ctlr_dev->lock);
+
+       fcf_dev = fcoe_fcf_to_fcf_dev(new);
+       WARN_ON(!fcf_dev);
+       new->fcf_dev = NULL;
+       fcoe_fcf_device_delete(fcf_dev);
+       kfree(new);
+
+       mutex_unlock(&ctlr_dev->lock);
+}
+
 /**
  * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller
  * @fip: The FCoE controller whose FCFs are to be reset
@@ -173,10 +243,10 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
 
        fip->sel_fcf = NULL;
        list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
-               list_del(&fcf->list);
-               kfree(fcf);
+               fcoe_sysfs_fcf_del(fcf);
        }
-       fip->fcf_count = 0;
+       WARN_ON(fip->fcf_count);
+
        fip->sel_time = 0;
 }
 
@@ -717,8 +787,11 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
        unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
        unsigned long deadline;
        unsigned long sel_time = 0;
+       struct list_head del_list;
        struct fcoe_dev_stats *stats;
 
+       INIT_LIST_HEAD(&del_list);
+
        stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
 
        list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
@@ -739,10 +812,13 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
                if (time_after_eq(jiffies, deadline)) {
                        if (fip->sel_fcf == fcf)
                                fip->sel_fcf = NULL;
+                       /*
+                        * Move to delete list so we can call
+                        * fcoe_sysfs_fcf_del (which can sleep)
+                        * after the put_cpu().
+                        */
                        list_del(&fcf->list);
-                       WARN_ON(!fip->fcf_count);
-                       fip->fcf_count--;
-                       kfree(fcf);
+                       list_add(&fcf->list, &del_list);
                        stats->VLinkFailureCount++;
                } else {
                        if (time_after(next_timer, deadline))
@@ -753,6 +829,12 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
                }
        }
        put_cpu();
+
+       list_for_each_entry_safe(fcf, next, &del_list, list) {
+               /* Removes fcf from current list */
+               fcoe_sysfs_fcf_del(fcf);
+       }
+
        if (sel_time && !fip->sel_fcf && !fip->sel_time) {
                sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
                fip->sel_time = sel_time;
@@ -903,23 +985,23 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
        struct fcoe_fcf *fcf;
        struct fcoe_fcf new;
-       struct fcoe_fcf *found;
        unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV);
        int first = 0;
        int mtu_valid;
+       int found = 0;
+       int rc = 0;
 
        if (fcoe_ctlr_parse_adv(fip, skb, &new))
                return;
 
        mutex_lock(&fip->ctlr_mutex);
        first = list_empty(&fip->fcfs);
-       found = NULL;
        list_for_each_entry(fcf, &fip->fcfs, list) {
                if (fcf->switch_name == new.switch_name &&
                    fcf->fabric_name == new.fabric_name &&
                    fcf->fc_map == new.fc_map &&
                    compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) {
-                       found = fcf;
+                       found = 1;
                        break;
                }
        }
@@ -931,9 +1013,16 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
                if (!fcf)
                        goto out;
 
-               fip->fcf_count++;
                memcpy(fcf, &new, sizeof(new));
-               list_add(&fcf->list, &fip->fcfs);
+               fcf->fip = fip;
+               rc = fcoe_sysfs_fcf_add(fcf);
+               if (rc) {
+                       printk(KERN_ERR "Failed to allocate sysfs instance "
+                              "for FCF, fab %16.16llx mac %pM\n",
+                              new.fabric_name, new.fcf_mac);
+                       kfree(fcf);
+                       goto out;
+               }
        } else {
                /*
                 * Update the FCF's keep-alive descriptor flags.
@@ -954,6 +1043,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
                fcf->fka_period = new.fka_period;
                memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
        }
+
        mtu_valid = fcoe_ctlr_mtu_valid(fcf);
        fcf->time = jiffies;
        if (!found)
@@ -996,6 +1086,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
                    time_before(fip->sel_time, fip->timer.expires))
                        mod_timer(&fip->timer, fip->sel_time);
        }
+
 out:
        mutex_unlock(&fip->ctlr_mutex);
 }
@@ -2718,9 +2809,9 @@ unlock:
 
 /**
  * fcoe_libfc_config() - Sets up libfc related properties for local port
- * @lp: The local port to configure libfc for
- * @fip: The FCoE controller in use by the local port
- * @tt: The libfc function template
+ * @lport:    The local port to configure libfc for
+ * @fip:      The FCoE controller in use by the local port
+ * @tt:       The libfc function template
  * @init_fcp: If non-zero, the FCP portion of libfc should be initialized
  *
  * Returns : 0 for success
@@ -2753,3 +2844,43 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
        return 0;
 }
 EXPORT_SYMBOL_GPL(fcoe_libfc_config);
+
+void fcoe_fcf_get_selected(struct fcoe_fcf_device *fcf_dev)
+{
+       struct fcoe_ctlr_device *ctlr_dev = fcoe_fcf_dev_to_ctlr_dev(fcf_dev);
+       struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
+       struct fcoe_fcf *fcf;
+
+       mutex_lock(&fip->ctlr_mutex);
+       mutex_lock(&ctlr_dev->lock);
+
+       fcf = fcoe_fcf_device_priv(fcf_dev);
+       if (fcf)
+               fcf_dev->selected = (fcf == fip->sel_fcf) ? 1 : 0;
+       else
+               fcf_dev->selected = 0;
+
+       mutex_unlock(&ctlr_dev->lock);
+       mutex_unlock(&fip->ctlr_mutex);
+}
+EXPORT_SYMBOL(fcoe_fcf_get_selected);
+
+void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
+{
+       struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+
+       mutex_lock(&ctlr->ctlr_mutex);
+       switch (ctlr->mode) {
+       case FIP_MODE_FABRIC:
+               ctlr_dev->mode = FIP_CONN_TYPE_FABRIC;
+               break;
+       case FIP_MODE_VN2VN:
+               ctlr_dev->mode = FIP_CONN_TYPE_VN2VN;
+               break;
+       default:
+               ctlr_dev->mode = FIP_CONN_TYPE_UNKNOWN;
+               break;
+       }
+       mutex_unlock(&ctlr->ctlr_mutex);
+}
+EXPORT_SYMBOL(fcoe_ctlr_get_fip_mode);
index 7b93f211b9354f5958382f9a3a31b98d5f8e678f..22b07cc99808562c86a3de2728ec0557291e56dc 100644 (file)
@@ -168,9 +168,16 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr)
        return (void *)(ctlr + 1);
 }
 
+#define fcoe_ctlr_to_ctlr_dev(x)                                       \
+       (struct fcoe_ctlr_device *)(((struct fcoe_ctlr_device *)(x)) - 1)
+
 /**
  * struct fcoe_fcf - Fibre-Channel Forwarder
  * @list:       list linkage
+ * @event_work:  Work for FC Transport actions queue
+ * @event:       The event to be processed
+ * @fip:         The controller that the FCF was discovered on
+ * @fcf_dev:     The associated fcoe_fcf_device instance
  * @time:       system time (jiffies) when an advertisement was last received
  * @switch_name: WWN of switch from advertisement
  * @fabric_name: WWN of fabric from advertisement
@@ -192,6 +199,9 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr)
  */
 struct fcoe_fcf {
        struct list_head list;
+       struct work_struct event_work;
+       struct fcoe_ctlr *fip;
+       struct fcoe_fcf_device *fcf_dev;
        unsigned long time;
 
        u64 switch_name;
@@ -208,6 +218,9 @@ struct fcoe_fcf {
        u8 fd_flags:1;
 };
 
+#define fcoe_fcf_to_fcf_dev(x)                 \
+       ((x)->fcf_dev)
+
 /**
  * struct fcoe_rport - VN2VN remote port
  * @time:      time of create or last beacon packet received from node
@@ -343,6 +356,10 @@ void fcoe_queue_timer(ulong lport);
 int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
                           struct fcoe_percpu_s *fps);
 
+/* FCoE Sysfs helpers */
+void fcoe_fcf_get_selected(struct fcoe_fcf_device *);
+void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *);
+
 /**
  * struct netdev_list
  * A mapping from netdevice to fcoe_transport