Commit 8d55e507 authored by Robert Love's avatar Robert Love Committed by James Bottomley

[SCSI] fcoe, bnx2fc, libfcoe: SW FCoE and bnx2fc use FCoE Syfs

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: default avatarRobert Love <robert.w.love@intel.com>
Tested-by: default avatarRoss Brattain <ross.b.brattain@intel.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 9a74e884
...@@ -54,6 +54,7 @@ static struct cnic_ulp_ops bnx2fc_cnic_cb; ...@@ -54,6 +54,7 @@ static struct cnic_ulp_ops bnx2fc_cnic_cb;
static struct libfc_function_template bnx2fc_libfc_fcn_templ; static struct libfc_function_template bnx2fc_libfc_fcn_templ;
static struct scsi_host_template bnx2fc_shost_template; static struct scsi_host_template bnx2fc_shost_template;
static struct fc_function_template bnx2fc_transport_function; 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 struct fc_function_template bnx2fc_vport_xport_function;
static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode);
static void __bnx2fc_destroy(struct bnx2fc_interface *interface); static void __bnx2fc_destroy(struct bnx2fc_interface *interface);
...@@ -88,6 +89,7 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport); ...@@ -88,6 +89,7 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport);
static void bnx2fc_stop(struct bnx2fc_interface *interface); static void bnx2fc_stop(struct bnx2fc_interface *interface);
static int __init bnx2fc_mod_init(void); static int __init bnx2fc_mod_init(void);
static void __exit bnx2fc_mod_exit(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; unsigned int bnx2fc_debug_level;
module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); 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, ...@@ -118,6 +120,41 @@ static void bnx2fc_get_lesb(struct fc_lport *lport,
__fcoe_get_lesb(lport, fc_lesb, netdev); __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) static void bnx2fc_clean_rx_queue(struct fc_lport *lp)
{ {
struct fcoe_percpu_s *bg; struct fcoe_percpu_s *bg;
...@@ -1235,6 +1272,7 @@ static void bnx2fc_release_transport(void) ...@@ -1235,6 +1272,7 @@ static void bnx2fc_release_transport(void)
static void bnx2fc_interface_release(struct kref *kref) static void bnx2fc_interface_release(struct kref *kref)
{ {
struct fcoe_ctlr_device *ctlr_dev;
struct bnx2fc_interface *interface; struct bnx2fc_interface *interface;
struct fcoe_ctlr *ctlr; struct fcoe_ctlr *ctlr;
struct net_device *netdev; struct net_device *netdev;
...@@ -1243,13 +1281,14 @@ static void bnx2fc_interface_release(struct kref *kref) ...@@ -1243,13 +1281,14 @@ static void bnx2fc_interface_release(struct kref *kref)
BNX2FC_MISC_DBG("Interface is being released\n"); BNX2FC_MISC_DBG("Interface is being released\n");
ctlr = bnx2fc_to_ctlr(interface); ctlr = bnx2fc_to_ctlr(interface);
ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr);
netdev = interface->netdev; netdev = interface->netdev;
/* tear-down FIP controller */ /* tear-down FIP controller */
if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags))
fcoe_ctlr_destroy(ctlr); fcoe_ctlr_destroy(ctlr);
kfree(ctlr); fcoe_ctlr_device_delete(ctlr_dev);
dev_put(netdev); dev_put(netdev);
module_put(THIS_MODULE); module_put(THIS_MODULE);
...@@ -1342,17 +1381,20 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, ...@@ -1342,17 +1381,20 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba,
struct net_device *netdev, struct net_device *netdev,
enum fip_state fip_mode) enum fip_state fip_mode)
{ {
struct fcoe_ctlr_device *ctlr_dev;
struct bnx2fc_interface *interface; struct bnx2fc_interface *interface;
struct fcoe_ctlr *ctlr; struct fcoe_ctlr *ctlr;
int size; int size;
int rc = 0; int rc = 0;
size = (sizeof(*interface) + sizeof(struct fcoe_ctlr)); size = (sizeof(*interface) + sizeof(struct fcoe_ctlr));
ctlr = kzalloc(size, GFP_KERNEL); ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &bnx2fc_fcoe_sysfs_templ,
if (!ctlr) { size);
if (!ctlr_dev) {
printk(KERN_ERR PFX "Unable to allocate interface structure\n"); printk(KERN_ERR PFX "Unable to allocate interface structure\n");
return NULL; return NULL;
} }
ctlr = fcoe_ctlr_device_priv(ctlr_dev);
interface = fcoe_ctlr_priv(ctlr); interface = fcoe_ctlr_priv(ctlr);
dev_hold(netdev); dev_hold(netdev);
kref_init(&interface->kref); kref_init(&interface->kref);
...@@ -1372,7 +1414,7 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, ...@@ -1372,7 +1414,7 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba,
fcoe_ctlr_destroy(ctlr); fcoe_ctlr_destroy(ctlr);
dev_put(netdev); dev_put(netdev);
kfree(ctlr); fcoe_ctlr_device_delete(ctlr_dev);
return NULL; return NULL;
} }
...@@ -2471,6 +2513,19 @@ static void __exit bnx2fc_mod_exit(void) ...@@ -2471,6 +2513,19 @@ static void __exit bnx2fc_mod_exit(void)
module_init(bnx2fc_mod_init); module_init(bnx2fc_mod_init);
module_exit(bnx2fc_mod_exit); 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 = { static struct fc_function_template bnx2fc_transport_function = {
.show_host_node_name = 1, .show_host_node_name = 1,
.show_host_port_name = 1, .show_host_port_name = 1,
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <scsi/fc/fc_encaps.h> #include <scsi/fc/fc_encaps.h>
#include <scsi/fc/fc_fip.h> #include <scsi/fc/fc_fip.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/libfc.h> #include <scsi/libfc.h>
#include <scsi/fc_frame.h> #include <scsi/fc_frame.h>
...@@ -150,6 +151,21 @@ static int fcoe_vport_create(struct fc_vport *, bool disabled); ...@@ -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 int fcoe_vport_disable(struct fc_vport *, bool disable);
static void fcoe_set_vport_symbolic_name(struct fc_vport *); 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_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 = { static struct libfc_function_template fcoe_libfc_fcn_templ = {
.frame_send = fcoe_xmit, .frame_send = fcoe_xmit,
...@@ -366,6 +382,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, ...@@ -366,6 +382,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
enum fip_state fip_mode) enum fip_state fip_mode)
{ {
struct fcoe_ctlr_device *ctlr_dev;
struct fcoe_ctlr *ctlr; struct fcoe_ctlr *ctlr;
struct fcoe_interface *fcoe; struct fcoe_interface *fcoe;
int size; int size;
...@@ -379,14 +396,17 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, ...@@ -379,14 +396,17 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
} }
size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface); size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface);
ctlr = kzalloc(size, GFP_KERNEL); ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &fcoe_sysfs_templ,
fcoe = fcoe_ctlr_priv(ctlr); size);
if (!fcoe) { if (!ctlr_dev) {
FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); FCOE_DBG("Failed to add fcoe_ctlr_device\n");
fcoe = ERR_PTR(-ENOMEM); fcoe = ERR_PTR(-ENOMEM);
goto out_putmod; goto out_putmod;
} }
ctlr = fcoe_ctlr_device_priv(ctlr_dev);
fcoe = fcoe_ctlr_priv(ctlr);
dev_hold(netdev); dev_hold(netdev);
/* /*
...@@ -400,6 +420,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, ...@@ -400,6 +420,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
err = fcoe_interface_setup(fcoe, netdev); err = fcoe_interface_setup(fcoe, netdev);
if (err) { if (err) {
fcoe_ctlr_destroy(ctlr); fcoe_ctlr_destroy(ctlr);
fcoe_ctlr_device_delete(ctlr_dev);
dev_put(netdev); dev_put(netdev);
fcoe = ERR_PTR(err); fcoe = ERR_PTR(err);
goto out_putmod; goto out_putmod;
...@@ -466,6 +487,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) ...@@ -466,6 +487,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
{ {
struct net_device *netdev = fcoe->netdev; struct net_device *netdev = fcoe->netdev;
struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe);
struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
rtnl_lock(); rtnl_lock();
if (!fcoe->removed) if (!fcoe->removed)
...@@ -476,7 +498,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) ...@@ -476,7 +498,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
/* tear-down the FCoE controller */ /* tear-down the FCoE controller */
fcoe_ctlr_destroy(fip); fcoe_ctlr_destroy(fip);
scsi_host_put(fip->lp->host); scsi_host_put(fip->lp->host);
kfree(fip); fcoe_ctlr_device_delete(ctlr_dev);
dev_put(netdev); dev_put(netdev);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
...@@ -2196,6 +2218,7 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe) ...@@ -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) static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
{ {
int rc = 0; int rc = 0;
struct fcoe_ctlr_device *ctlr_dev;
struct fcoe_ctlr *ctlr; struct fcoe_ctlr *ctlr;
struct fcoe_interface *fcoe; struct fcoe_interface *fcoe;
struct fc_lport *lport; struct fc_lport *lport;
...@@ -2216,8 +2239,8 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) ...@@ -2216,8 +2239,8 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
} }
ctlr = fcoe_to_ctlr(fcoe); ctlr = fcoe_to_ctlr(fcoe);
ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr);
lport = fcoe_if_create(fcoe, &netdev->dev, 0); lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0);
if (IS_ERR(lport)) { if (IS_ERR(lport)) {
printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
netdev->name); netdev->name);
...@@ -2768,6 +2791,40 @@ static void fcoe_get_lesb(struct fc_lport *lport, ...@@ -2768,6 +2791,40 @@ static void fcoe_get_lesb(struct fc_lport *lport,
__fcoe_get_lesb(lport, fc_lesb, netdev); __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. * fcoe_set_port_id() - Callback from libfc when Port_ID is set.
* @lport: the local port * @lport: the local port
......
...@@ -160,6 +160,76 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) ...@@ -160,6 +160,76 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
} }
EXPORT_SYMBOL(fcoe_ctlr_init); 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 * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller
* @fip: The FCoE controller whose FCFs are to be reset * @fip: The FCoE controller whose FCFs are to be reset
...@@ -173,10 +243,10 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) ...@@ -173,10 +243,10 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
fip->sel_fcf = NULL; fip->sel_fcf = NULL;
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
list_del(&fcf->list); fcoe_sysfs_fcf_del(fcf);
kfree(fcf);
} }
fip->fcf_count = 0; WARN_ON(fip->fcf_count);
fip->sel_time = 0; fip->sel_time = 0;
} }
...@@ -717,8 +787,11 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) ...@@ -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 next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
unsigned long deadline; unsigned long deadline;
unsigned long sel_time = 0; unsigned long sel_time = 0;
struct list_head del_list;
struct fcoe_dev_stats *stats; struct fcoe_dev_stats *stats;
INIT_LIST_HEAD(&del_list);
stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { 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) ...@@ -739,10 +812,13 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
if (time_after_eq(jiffies, deadline)) { if (time_after_eq(jiffies, deadline)) {
if (fip->sel_fcf == fcf) if (fip->sel_fcf == fcf)
fip->sel_fcf = NULL; 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); list_del(&fcf->list);
WARN_ON(!fip->fcf_count); list_add(&fcf->list, &del_list);
fip->fcf_count--;
kfree(fcf);
stats->VLinkFailureCount++; stats->VLinkFailureCount++;
} else { } else {
if (time_after(next_timer, deadline)) if (time_after(next_timer, deadline))
...@@ -753,6 +829,12 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) ...@@ -753,6 +829,12 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
} }
} }
put_cpu(); 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) { if (sel_time && !fip->sel_fcf && !fip->sel_time) {
sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
fip->sel_time = sel_time; fip->sel_time = sel_time;
...@@ -903,23 +985,23 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) ...@@ -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 *fcf;
struct fcoe_fcf new; struct fcoe_fcf new;
struct fcoe_fcf *found;
unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV);
int first = 0; int first = 0;
int mtu_valid; int mtu_valid;
int found = 0;
int rc = 0;
if (fcoe_ctlr_parse_adv(fip, skb, &new)) if (fcoe_ctlr_parse_adv(fip, skb, &new))
return; return;
mutex_lock(&fip->ctlr_mutex); mutex_lock(&fip->ctlr_mutex);
first = list_empty(&fip->fcfs); first = list_empty(&fip->fcfs);
found = NULL;
list_for_each_entry(fcf, &fip->fcfs, list) { list_for_each_entry(fcf, &fip->fcfs, list) {
if (fcf->switch_name == new.switch_name && if (fcf->switch_name == new.switch_name &&
fcf->fabric_name == new.fabric_name && fcf->fabric_name == new.fabric_name &&
fcf->fc_map == new.fc_map && fcf->fc_map == new.fc_map &&
compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) {
found = fcf; found = 1;
break; break;
} }
} }
...@@ -931,9 +1013,16 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) ...@@ -931,9 +1013,16 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
if (!fcf) if (!fcf)
goto out; goto out;
fip->fcf_count++;
memcpy(fcf, &new, sizeof(new)); 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 { } else {
/* /*
* Update the FCF's keep-alive descriptor flags. * 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) ...@@ -954,6 +1043,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
fcf->fka_period = new.fka_period; fcf->fka_period = new.fka_period;
memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
} }
mtu_valid = fcoe_ctlr_mtu_valid(fcf); mtu_valid = fcoe_ctlr_mtu_valid(fcf);
fcf->time = jiffies; fcf->time = jiffies;
if (!found) if (!found)
...@@ -996,6 +1086,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) ...@@ -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)) time_before(fip->sel_time, fip->timer.expires))
mod_timer(&fip->timer, fip->sel_time); mod_timer(&fip->timer, fip->sel_time);
} }
out: out:
mutex_unlock(&fip->ctlr_mutex); mutex_unlock(&fip->ctlr_mutex);
} }
...@@ -2718,7 +2809,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) ...@@ -2718,7 +2809,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
/** /**
* fcoe_libfc_config() - Sets up libfc related properties for local port * fcoe_libfc_config() - Sets up libfc related properties for local port
* @lp: The local port to configure libfc for * @lport: The local port to configure libfc for
* @fip: The FCoE controller in use by the local port * @fip: The FCoE controller in use by the local port
* @tt: The libfc function template * @tt: The libfc function template
* @init_fcp: If non-zero, the FCP portion of libfc should be initialized * @init_fcp: If non-zero, the FCP portion of libfc should be initialized
...@@ -2753,3 +2844,43 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, ...@@ -2753,3 +2844,43 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(fcoe_libfc_config); 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);
...@@ -168,9 +168,16 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr) ...@@ -168,9 +168,16 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr)
return (void *)(ctlr + 1); 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 * struct fcoe_fcf - Fibre-Channel Forwarder
* @list: list linkage * @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 * @time: system time (jiffies) when an advertisement was last received
* @switch_name: WWN of switch from advertisement * @switch_name: WWN of switch from advertisement
* @fabric_name: WWN of fabric from advertisement * @fabric_name: WWN of fabric from advertisement
...@@ -192,6 +199,9 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr) ...@@ -192,6 +199,9 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr)
*/ */
struct fcoe_fcf { struct fcoe_fcf {
struct list_head list; struct list_head list;
struct work_struct event_work;
struct fcoe_ctlr *fip;
struct fcoe_fcf_device *fcf_dev;
unsigned long time; unsigned long time;
u64 switch_name; u64 switch_name;
...@@ -208,6 +218,9 @@ struct fcoe_fcf { ...@@ -208,6 +218,9 @@ struct fcoe_fcf {
u8 fd_flags:1; u8 fd_flags:1;
}; };
#define fcoe_fcf_to_fcf_dev(x) \
((x)->fcf_dev)
/** /**
* struct fcoe_rport - VN2VN remote port * struct fcoe_rport - VN2VN remote port
* @time: time of create or last beacon packet received from node * @time: time of create or last beacon packet received from node
...@@ -343,6 +356,10 @@ void fcoe_queue_timer(ulong lport); ...@@ -343,6 +356,10 @@ void fcoe_queue_timer(ulong lport);
int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
struct fcoe_percpu_s *fps); 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 * struct netdev_list
* A mapping from netdevice to fcoe_transport * A mapping from netdevice to fcoe_transport
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment