summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 745eb9a22d64..258684101bfd 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -39,10 +39,13 @@ static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
static int fcoe_transport_enable(const char *, struct kernel_param *);
static int fcoe_transport_disable(const char *, struct kernel_param *);
+static int libfcoe_device_notification(struct notifier_block *notifier,
+ ulong event, void *ptr);
static LIST_HEAD(fcoe_transports);
-static LIST_HEAD(fcoe_netdevs);
static DEFINE_MUTEX(ft_mutex);
+static LIST_HEAD(fcoe_netdevs);
+static DEFINE_MUTEX(fn_mutex);
unsigned int libfcoe_debug_logging;
module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
@@ -75,6 +78,11 @@ module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
__MODULE_PARM_TYPE(disable, "string");
MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
+/* notification function for packets from net device */
+static struct notifier_block libfcoe_notifier = {
+ .notifier_call = libfcoe_device_notification,
+};
+
/**
* fcoe_fc_crc() - Calculates the CRC for a given frame
* @fp: The frame to be checksumed
@@ -375,6 +383,7 @@ static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
static int __init fcoe_transport_init(void)
{
+ register_netdevice_notifier(&libfcoe_notifier);
return 0;
}
@@ -382,6 +391,7 @@ static int __exit fcoe_transport_exit(void)
{
struct fcoe_transport *ft;
+ unregister_netdevice_notifier(&libfcoe_notifier);
mutex_lock(&ft_mutex);
list_for_each_entry(ft, &fcoe_transports, list)
printk(KERN_ERR "FCoE transport %s is still attached!\n",
@@ -405,7 +415,9 @@ static int fcoe_add_netdev_mapping(struct net_device *netdev,
nm->netdev = netdev;
nm->ft = ft;
+ mutex_lock(&fn_mutex);
list_add(&nm->list, &fcoe_netdevs);
+ mutex_unlock(&fn_mutex);
return 0;
}
@@ -414,13 +426,16 @@ static void fcoe_del_netdev_mapping(struct net_device *netdev)
{
struct fcoe_netdev_mapping *nm = NULL, *tmp;
+ mutex_lock(&fn_mutex);
list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
if (nm->netdev == netdev) {
list_del(&nm->list);
kfree(nm);
+ mutex_unlock(&fn_mutex);
return;
}
}
+ mutex_unlock(&fn_mutex);
}
@@ -438,13 +453,16 @@ static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
struct fcoe_transport *ft = NULL;
struct fcoe_netdev_mapping *nm;
+ mutex_lock(&fn_mutex);
list_for_each_entry(nm, &fcoe_netdevs, list) {
if (netdev == nm->netdev) {
ft = nm->ft;
+ mutex_unlock(&fn_mutex);
return ft;
}
}
+ mutex_unlock(&fn_mutex);
return NULL;
}
@@ -470,6 +488,32 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer)
}
/**
+ * libfcoe_device_notification() - Handler for net device events
+ * @notifier: The context of the notification
+ * @event: The type of event
+ * @ptr: The net device that the event was on
+ *
+ * This function is called by the Ethernet driver in case of link change event.
+ *
+ * Returns: 0 for success
+ */
+static int libfcoe_device_notification(struct notifier_block *notifier,
+ ulong event, void *ptr)
+{
+ struct net_device *netdev = ptr;
+
+ switch (event) {
+ case NETDEV_UNREGISTER:
+ printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n",
+ netdev->name);
+ fcoe_del_netdev_mapping(netdev);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+
+/**
* fcoe_transport_create() - Create a fcoe interface
* @buffer: The name of the Ethernet interface to create on
* @kp: The associated kernel param