1fdecf31bSYi Zou /* 2fdecf31bSYi Zou * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 3fdecf31bSYi Zou * 4fdecf31bSYi Zou * This program is free software; you can redistribute it and/or modify it 5fdecf31bSYi Zou * under the terms and conditions of the GNU General Public License, 6fdecf31bSYi Zou * version 2, as published by the Free Software Foundation. 7fdecf31bSYi Zou * 8fdecf31bSYi Zou * This program is distributed in the hope it will be useful, but WITHOUT 9fdecf31bSYi Zou * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10fdecf31bSYi Zou * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11fdecf31bSYi Zou * more details. 12fdecf31bSYi Zou * 13fdecf31bSYi Zou * You should have received a copy of the GNU General Public License along with 14fdecf31bSYi Zou * this program; if not, write to the Free Software Foundation, Inc., 15fdecf31bSYi Zou * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16fdecf31bSYi Zou * 17fdecf31bSYi Zou * Maintained at www.Open-FCoE.org 18fdecf31bSYi Zou */ 19fdecf31bSYi Zou 20fdecf31bSYi Zou #include <linux/types.h> 21fdecf31bSYi Zou #include <linux/module.h> 22fdecf31bSYi Zou #include <linux/kernel.h> 23fdecf31bSYi Zou #include <linux/list.h> 24fdecf31bSYi Zou #include <linux/netdevice.h> 25fdecf31bSYi Zou #include <linux/errno.h> 268597ae8bSBhanu Prakash Gollapudi #include <linux/crc32.h> 27fdecf31bSYi Zou #include <scsi/libfcoe.h> 28fdecf31bSYi Zou 29fdecf31bSYi Zou #include "libfcoe.h" 30fdecf31bSYi Zou 31e01efc33SYi Zou MODULE_AUTHOR("Open-FCoE.org"); 32e01efc33SYi Zou MODULE_DESCRIPTION("FIP discovery protocol and FCoE transport for FCoE HBAs"); 33e01efc33SYi Zou MODULE_LICENSE("GPL v2"); 34e01efc33SYi Zou 35fdecf31bSYi Zou static int fcoe_transport_create(const char *, struct kernel_param *); 36fdecf31bSYi Zou static int fcoe_transport_destroy(const char *, struct kernel_param *); 37fdecf31bSYi Zou static int fcoe_transport_show(char *buffer, const struct kernel_param *kp); 38fdecf31bSYi Zou static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device); 39fdecf31bSYi Zou static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device); 40fdecf31bSYi Zou static int fcoe_transport_enable(const char *, struct kernel_param *); 41fdecf31bSYi Zou static int fcoe_transport_disable(const char *, struct kernel_param *); 4270be6344SBhanu Prakash Gollapudi static int libfcoe_device_notification(struct notifier_block *notifier, 4370be6344SBhanu Prakash Gollapudi ulong event, void *ptr); 44fdecf31bSYi Zou 45fdecf31bSYi Zou static LIST_HEAD(fcoe_transports); 46fdecf31bSYi Zou static DEFINE_MUTEX(ft_mutex); 4770be6344SBhanu Prakash Gollapudi static LIST_HEAD(fcoe_netdevs); 4870be6344SBhanu Prakash Gollapudi static DEFINE_MUTEX(fn_mutex); 49fdecf31bSYi Zou 50e01efc33SYi Zou unsigned int libfcoe_debug_logging; 51e01efc33SYi Zou module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR); 52e01efc33SYi Zou MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); 53e01efc33SYi Zou 54fdecf31bSYi Zou module_param_call(show, NULL, fcoe_transport_show, NULL, S_IRUSR); 55fdecf31bSYi Zou __MODULE_PARM_TYPE(show, "string"); 56fdecf31bSYi Zou MODULE_PARM_DESC(show, " Show attached FCoE transports"); 57fdecf31bSYi Zou 58fdecf31bSYi Zou module_param_call(create, fcoe_transport_create, NULL, 59fdecf31bSYi Zou (void *)FIP_MODE_FABRIC, S_IWUSR); 60fdecf31bSYi Zou __MODULE_PARM_TYPE(create, "string"); 61fdecf31bSYi Zou MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface"); 62fdecf31bSYi Zou 63fdecf31bSYi Zou module_param_call(create_vn2vn, fcoe_transport_create, NULL, 64fdecf31bSYi Zou (void *)FIP_MODE_VN2VN, S_IWUSR); 65fdecf31bSYi Zou __MODULE_PARM_TYPE(create_vn2vn, "string"); 66fdecf31bSYi Zou MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance " 67fdecf31bSYi Zou "on an Ethernet interface"); 68fdecf31bSYi Zou 69fdecf31bSYi Zou module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR); 70fdecf31bSYi Zou __MODULE_PARM_TYPE(destroy, "string"); 71fdecf31bSYi Zou MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface"); 72fdecf31bSYi Zou 73fdecf31bSYi Zou module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR); 74fdecf31bSYi Zou __MODULE_PARM_TYPE(enable, "string"); 75fdecf31bSYi Zou MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface."); 76fdecf31bSYi Zou 77fdecf31bSYi Zou module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR); 78fdecf31bSYi Zou __MODULE_PARM_TYPE(disable, "string"); 79fdecf31bSYi Zou MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface."); 80fdecf31bSYi Zou 8170be6344SBhanu Prakash Gollapudi /* notification function for packets from net device */ 8270be6344SBhanu Prakash Gollapudi static struct notifier_block libfcoe_notifier = { 8370be6344SBhanu Prakash Gollapudi .notifier_call = libfcoe_device_notification, 8470be6344SBhanu Prakash Gollapudi }; 8570be6344SBhanu Prakash Gollapudi 86fdecf31bSYi Zou /** 878597ae8bSBhanu Prakash Gollapudi * fcoe_fc_crc() - Calculates the CRC for a given frame 888597ae8bSBhanu Prakash Gollapudi * @fp: The frame to be checksumed 898597ae8bSBhanu Prakash Gollapudi * 908597ae8bSBhanu Prakash Gollapudi * This uses crc32() routine to calculate the CRC for a frame 918597ae8bSBhanu Prakash Gollapudi * 928597ae8bSBhanu Prakash Gollapudi * Return: The 32 bit CRC value 938597ae8bSBhanu Prakash Gollapudi */ 948597ae8bSBhanu Prakash Gollapudi u32 fcoe_fc_crc(struct fc_frame *fp) 958597ae8bSBhanu Prakash Gollapudi { 968597ae8bSBhanu Prakash Gollapudi struct sk_buff *skb = fp_skb(fp); 978597ae8bSBhanu Prakash Gollapudi struct skb_frag_struct *frag; 988597ae8bSBhanu Prakash Gollapudi unsigned char *data; 998597ae8bSBhanu Prakash Gollapudi unsigned long off, len, clen; 1008597ae8bSBhanu Prakash Gollapudi u32 crc; 1018597ae8bSBhanu Prakash Gollapudi unsigned i; 1028597ae8bSBhanu Prakash Gollapudi 1038597ae8bSBhanu Prakash Gollapudi crc = crc32(~0, skb->data, skb_headlen(skb)); 1048597ae8bSBhanu Prakash Gollapudi 1058597ae8bSBhanu Prakash Gollapudi for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 1068597ae8bSBhanu Prakash Gollapudi frag = &skb_shinfo(skb)->frags[i]; 1078597ae8bSBhanu Prakash Gollapudi off = frag->page_offset; 1088597ae8bSBhanu Prakash Gollapudi len = frag->size; 1098597ae8bSBhanu Prakash Gollapudi while (len > 0) { 1108597ae8bSBhanu Prakash Gollapudi clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); 1118597ae8bSBhanu Prakash Gollapudi data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), 1128597ae8bSBhanu Prakash Gollapudi KM_SKB_DATA_SOFTIRQ); 1138597ae8bSBhanu Prakash Gollapudi crc = crc32(crc, data + (off & ~PAGE_MASK), clen); 1148597ae8bSBhanu Prakash Gollapudi kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); 1158597ae8bSBhanu Prakash Gollapudi off += clen; 1168597ae8bSBhanu Prakash Gollapudi len -= clen; 1178597ae8bSBhanu Prakash Gollapudi } 1188597ae8bSBhanu Prakash Gollapudi } 1198597ae8bSBhanu Prakash Gollapudi return crc; 1208597ae8bSBhanu Prakash Gollapudi } 1218597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_fc_crc); 1228597ae8bSBhanu Prakash Gollapudi 1238597ae8bSBhanu Prakash Gollapudi /** 1248597ae8bSBhanu Prakash Gollapudi * fcoe_start_io() - Start FCoE I/O 1258597ae8bSBhanu Prakash Gollapudi * @skb: The packet to be transmitted 1268597ae8bSBhanu Prakash Gollapudi * 1278597ae8bSBhanu Prakash Gollapudi * This routine is called from the net device to start transmitting 1288597ae8bSBhanu Prakash Gollapudi * FCoE packets. 1298597ae8bSBhanu Prakash Gollapudi * 1308597ae8bSBhanu Prakash Gollapudi * Returns: 0 for success 1318597ae8bSBhanu Prakash Gollapudi */ 1328597ae8bSBhanu Prakash Gollapudi int fcoe_start_io(struct sk_buff *skb) 1338597ae8bSBhanu Prakash Gollapudi { 1348597ae8bSBhanu Prakash Gollapudi struct sk_buff *nskb; 1358597ae8bSBhanu Prakash Gollapudi int rc; 1368597ae8bSBhanu Prakash Gollapudi 1378597ae8bSBhanu Prakash Gollapudi nskb = skb_clone(skb, GFP_ATOMIC); 1388597ae8bSBhanu Prakash Gollapudi if (!nskb) 1398597ae8bSBhanu Prakash Gollapudi return -ENOMEM; 1408597ae8bSBhanu Prakash Gollapudi rc = dev_queue_xmit(nskb); 1418597ae8bSBhanu Prakash Gollapudi if (rc != 0) 1428597ae8bSBhanu Prakash Gollapudi return rc; 1438597ae8bSBhanu Prakash Gollapudi kfree_skb(skb); 1448597ae8bSBhanu Prakash Gollapudi return 0; 1458597ae8bSBhanu Prakash Gollapudi } 1468597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_start_io); 1478597ae8bSBhanu Prakash Gollapudi 1488597ae8bSBhanu Prakash Gollapudi 1498597ae8bSBhanu Prakash Gollapudi /** 1508597ae8bSBhanu Prakash Gollapudi * fcoe_clean_pending_queue() - Dequeue a skb and free it 1518597ae8bSBhanu Prakash Gollapudi * @lport: The local port to dequeue a skb on 1528597ae8bSBhanu Prakash Gollapudi */ 1538597ae8bSBhanu Prakash Gollapudi void fcoe_clean_pending_queue(struct fc_lport *lport) 1548597ae8bSBhanu Prakash Gollapudi { 1558597ae8bSBhanu Prakash Gollapudi struct fcoe_port *port = lport_priv(lport); 1568597ae8bSBhanu Prakash Gollapudi struct sk_buff *skb; 1578597ae8bSBhanu Prakash Gollapudi 1588597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 1598597ae8bSBhanu Prakash Gollapudi while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) { 1608597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 1618597ae8bSBhanu Prakash Gollapudi kfree_skb(skb); 1628597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 1638597ae8bSBhanu Prakash Gollapudi } 1648597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 1658597ae8bSBhanu Prakash Gollapudi } 1668597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); 1678597ae8bSBhanu Prakash Gollapudi 1688597ae8bSBhanu Prakash Gollapudi /** 1698597ae8bSBhanu Prakash Gollapudi * fcoe_check_wait_queue() - Attempt to clear the transmit backlog 1708597ae8bSBhanu Prakash Gollapudi * @lport: The local port whose backlog is to be cleared 1718597ae8bSBhanu Prakash Gollapudi * 1728597ae8bSBhanu Prakash Gollapudi * This empties the wait_queue, dequeues the head of the wait_queue queue 1738597ae8bSBhanu Prakash Gollapudi * and calls fcoe_start_io() for each packet. If all skb have been 1748597ae8bSBhanu Prakash Gollapudi * transmitted it returns the qlen. If an error occurs it restores 1758597ae8bSBhanu Prakash Gollapudi * wait_queue (to try again later) and returns -1. 1768597ae8bSBhanu Prakash Gollapudi * 1778597ae8bSBhanu Prakash Gollapudi * The wait_queue is used when the skb transmit fails. The failed skb 1788597ae8bSBhanu Prakash Gollapudi * will go in the wait_queue which will be emptied by the timer function or 1798597ae8bSBhanu Prakash Gollapudi * by the next skb transmit. 1808597ae8bSBhanu Prakash Gollapudi */ 1818597ae8bSBhanu Prakash Gollapudi void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb) 1828597ae8bSBhanu Prakash Gollapudi { 1838597ae8bSBhanu Prakash Gollapudi struct fcoe_port *port = lport_priv(lport); 1848597ae8bSBhanu Prakash Gollapudi int rc; 1858597ae8bSBhanu Prakash Gollapudi 1868597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 1878597ae8bSBhanu Prakash Gollapudi 1888597ae8bSBhanu Prakash Gollapudi if (skb) 1898597ae8bSBhanu Prakash Gollapudi __skb_queue_tail(&port->fcoe_pending_queue, skb); 1908597ae8bSBhanu Prakash Gollapudi 1918597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue_active) 1928597ae8bSBhanu Prakash Gollapudi goto out; 1938597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue_active = 1; 1948597ae8bSBhanu Prakash Gollapudi 1958597ae8bSBhanu Prakash Gollapudi while (port->fcoe_pending_queue.qlen) { 1968597ae8bSBhanu Prakash Gollapudi /* keep qlen > 0 until fcoe_start_io succeeds */ 1978597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen++; 1988597ae8bSBhanu Prakash Gollapudi skb = __skb_dequeue(&port->fcoe_pending_queue); 1998597ae8bSBhanu Prakash Gollapudi 2008597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 2018597ae8bSBhanu Prakash Gollapudi rc = fcoe_start_io(skb); 2028597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 2038597ae8bSBhanu Prakash Gollapudi 2048597ae8bSBhanu Prakash Gollapudi if (rc) { 2058597ae8bSBhanu Prakash Gollapudi __skb_queue_head(&port->fcoe_pending_queue, skb); 2068597ae8bSBhanu Prakash Gollapudi /* undo temporary increment above */ 2078597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen--; 2088597ae8bSBhanu Prakash Gollapudi break; 2098597ae8bSBhanu Prakash Gollapudi } 2108597ae8bSBhanu Prakash Gollapudi /* undo temporary increment above */ 2118597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen--; 2128597ae8bSBhanu Prakash Gollapudi } 2138597ae8bSBhanu Prakash Gollapudi 2148597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen < port->min_queue_depth) 2158597ae8bSBhanu Prakash Gollapudi lport->qfull = 0; 2168597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer)) 2178597ae8bSBhanu Prakash Gollapudi mod_timer(&port->timer, jiffies + 2); 2188597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue_active = 0; 2198597ae8bSBhanu Prakash Gollapudi out: 2208597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen > port->max_queue_depth) 2218597ae8bSBhanu Prakash Gollapudi lport->qfull = 1; 2228597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 2238597ae8bSBhanu Prakash Gollapudi } 2248597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_check_wait_queue); 2258597ae8bSBhanu Prakash Gollapudi 2268597ae8bSBhanu Prakash Gollapudi /** 2278597ae8bSBhanu Prakash Gollapudi * fcoe_queue_timer() - The fcoe queue timer 2288597ae8bSBhanu Prakash Gollapudi * @lport: The local port 2298597ae8bSBhanu Prakash Gollapudi * 2308597ae8bSBhanu Prakash Gollapudi * Calls fcoe_check_wait_queue on timeout 2318597ae8bSBhanu Prakash Gollapudi */ 2328597ae8bSBhanu Prakash Gollapudi void fcoe_queue_timer(ulong lport) 2338597ae8bSBhanu Prakash Gollapudi { 2348597ae8bSBhanu Prakash Gollapudi fcoe_check_wait_queue((struct fc_lport *)lport, NULL); 2358597ae8bSBhanu Prakash Gollapudi } 2368597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_queue_timer); 2378597ae8bSBhanu Prakash Gollapudi 2388597ae8bSBhanu Prakash Gollapudi /** 2398597ae8bSBhanu Prakash Gollapudi * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC 2408597ae8bSBhanu Prakash Gollapudi * @skb: The packet to be transmitted 2418597ae8bSBhanu Prakash Gollapudi * @tlen: The total length of the trailer 2428597ae8bSBhanu Prakash Gollapudi * @fps: The fcoe context 2438597ae8bSBhanu Prakash Gollapudi * 2448597ae8bSBhanu Prakash Gollapudi * This routine allocates a page for frame trailers. The page is re-used if 2458597ae8bSBhanu Prakash Gollapudi * there is enough room left on it for the current trailer. If there isn't 2468597ae8bSBhanu Prakash Gollapudi * enough buffer left a new page is allocated for the trailer. Reference to 2478597ae8bSBhanu Prakash Gollapudi * the page from this function as well as the skbs using the page fragments 2488597ae8bSBhanu Prakash Gollapudi * ensure that the page is freed at the appropriate time. 2498597ae8bSBhanu Prakash Gollapudi * 2508597ae8bSBhanu Prakash Gollapudi * Returns: 0 for success 2518597ae8bSBhanu Prakash Gollapudi */ 2528597ae8bSBhanu Prakash Gollapudi int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, 2538597ae8bSBhanu Prakash Gollapudi struct fcoe_percpu_s *fps) 2548597ae8bSBhanu Prakash Gollapudi { 2558597ae8bSBhanu Prakash Gollapudi struct page *page; 2568597ae8bSBhanu Prakash Gollapudi 2578597ae8bSBhanu Prakash Gollapudi page = fps->crc_eof_page; 2588597ae8bSBhanu Prakash Gollapudi if (!page) { 2598597ae8bSBhanu Prakash Gollapudi page = alloc_page(GFP_ATOMIC); 2608597ae8bSBhanu Prakash Gollapudi if (!page) 2618597ae8bSBhanu Prakash Gollapudi return -ENOMEM; 2628597ae8bSBhanu Prakash Gollapudi 2638597ae8bSBhanu Prakash Gollapudi fps->crc_eof_page = page; 2648597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset = 0; 2658597ae8bSBhanu Prakash Gollapudi } 2668597ae8bSBhanu Prakash Gollapudi 2678597ae8bSBhanu Prakash Gollapudi get_page(page); 2688597ae8bSBhanu Prakash Gollapudi skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 2698597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset, tlen); 2708597ae8bSBhanu Prakash Gollapudi skb->len += tlen; 2718597ae8bSBhanu Prakash Gollapudi skb->data_len += tlen; 2728597ae8bSBhanu Prakash Gollapudi skb->truesize += tlen; 2738597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); 2748597ae8bSBhanu Prakash Gollapudi 2758597ae8bSBhanu Prakash Gollapudi if (fps->crc_eof_offset >= PAGE_SIZE) { 2768597ae8bSBhanu Prakash Gollapudi fps->crc_eof_page = NULL; 2778597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset = 0; 2788597ae8bSBhanu Prakash Gollapudi put_page(page); 2798597ae8bSBhanu Prakash Gollapudi } 2808597ae8bSBhanu Prakash Gollapudi 2818597ae8bSBhanu Prakash Gollapudi return 0; 2828597ae8bSBhanu Prakash Gollapudi } 2838597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_get_paged_crc_eof); 2848597ae8bSBhanu Prakash Gollapudi 2858597ae8bSBhanu Prakash Gollapudi /** 286fdecf31bSYi Zou * fcoe_transport_lookup - find an fcoe transport that matches a netdev 287fdecf31bSYi Zou * @netdev: The netdev to look for from all attached transports 288fdecf31bSYi Zou * 289fdecf31bSYi Zou * Returns : ptr to the fcoe transport that supports this netdev or NULL 290fdecf31bSYi Zou * if not found. 291fdecf31bSYi Zou * 292fdecf31bSYi Zou * The ft_mutex should be held when this is called 293fdecf31bSYi Zou */ 294fdecf31bSYi Zou static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev) 295fdecf31bSYi Zou { 296fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 297fdecf31bSYi Zou 298fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) 299fdecf31bSYi Zou if (ft->match && ft->match(netdev)) 300fdecf31bSYi Zou return ft; 301fdecf31bSYi Zou return NULL; 302fdecf31bSYi Zou } 303fdecf31bSYi Zou 304fdecf31bSYi Zou /** 305fdecf31bSYi Zou * fcoe_transport_attach - Attaches an FCoE transport 306fdecf31bSYi Zou * @ft: The fcoe transport to be attached 307fdecf31bSYi Zou * 308fdecf31bSYi Zou * Returns : 0 for success 309fdecf31bSYi Zou */ 310fdecf31bSYi Zou int fcoe_transport_attach(struct fcoe_transport *ft) 311fdecf31bSYi Zou { 312fdecf31bSYi Zou int rc = 0; 313fdecf31bSYi Zou 314fdecf31bSYi Zou mutex_lock(&ft_mutex); 315fdecf31bSYi Zou if (ft->attached) { 316fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already attached\n", 317fdecf31bSYi Zou ft->name); 318fdecf31bSYi Zou rc = -EEXIST; 319fdecf31bSYi Zou goto out_attach; 320fdecf31bSYi Zou } 321fdecf31bSYi Zou 322fdecf31bSYi Zou /* Add default transport to the tail */ 323fdecf31bSYi Zou if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT)) 324fdecf31bSYi Zou list_add(&ft->list, &fcoe_transports); 325fdecf31bSYi Zou else 326fdecf31bSYi Zou list_add_tail(&ft->list, &fcoe_transports); 327fdecf31bSYi Zou 328fdecf31bSYi Zou ft->attached = true; 329fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name); 330fdecf31bSYi Zou 331fdecf31bSYi Zou out_attach: 332fdecf31bSYi Zou mutex_unlock(&ft_mutex); 333fdecf31bSYi Zou return rc; 334fdecf31bSYi Zou } 335fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_attach); 336fdecf31bSYi Zou 337fdecf31bSYi Zou /** 338fdecf31bSYi Zou * fcoe_transport_attach - Detaches an FCoE transport 339fdecf31bSYi Zou * @ft: The fcoe transport to be attached 340fdecf31bSYi Zou * 341fdecf31bSYi Zou * Returns : 0 for success 342fdecf31bSYi Zou */ 343fdecf31bSYi Zou int fcoe_transport_detach(struct fcoe_transport *ft) 344fdecf31bSYi Zou { 345fdecf31bSYi Zou int rc = 0; 346fdecf31bSYi Zou 347fdecf31bSYi Zou mutex_lock(&ft_mutex); 348fdecf31bSYi Zou if (!ft->attached) { 349fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already detached\n", 350fdecf31bSYi Zou ft->name); 351fdecf31bSYi Zou rc = -ENODEV; 352fdecf31bSYi Zou goto out_attach; 353fdecf31bSYi Zou } 354fdecf31bSYi Zou 355fdecf31bSYi Zou list_del(&ft->list); 356fdecf31bSYi Zou ft->attached = false; 357fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name); 358fdecf31bSYi Zou 359fdecf31bSYi Zou out_attach: 360fdecf31bSYi Zou mutex_unlock(&ft_mutex); 361fdecf31bSYi Zou return rc; 362fdecf31bSYi Zou 363fdecf31bSYi Zou } 364fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_detach); 365fdecf31bSYi Zou 366fdecf31bSYi Zou static int fcoe_transport_show(char *buffer, const struct kernel_param *kp) 367fdecf31bSYi Zou { 368fdecf31bSYi Zou int i, j; 369fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 370fdecf31bSYi Zou 371fdecf31bSYi Zou i = j = sprintf(buffer, "Attached FCoE transports:"); 372fdecf31bSYi Zou mutex_lock(&ft_mutex); 373fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) { 374fdecf31bSYi Zou i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); 375fdecf31bSYi Zou if (i >= PAGE_SIZE) 376fdecf31bSYi Zou break; 377fdecf31bSYi Zou } 378fdecf31bSYi Zou mutex_unlock(&ft_mutex); 379fdecf31bSYi Zou if (i == j) 380fdecf31bSYi Zou i += snprintf(&buffer[i], IFNAMSIZ, "none"); 381fdecf31bSYi Zou return i; 382fdecf31bSYi Zou } 383fdecf31bSYi Zou 384fdecf31bSYi Zou static int __init fcoe_transport_init(void) 385fdecf31bSYi Zou { 38670be6344SBhanu Prakash Gollapudi register_netdevice_notifier(&libfcoe_notifier); 387fdecf31bSYi Zou return 0; 388fdecf31bSYi Zou } 389fdecf31bSYi Zou 390fdecf31bSYi Zou static int __exit fcoe_transport_exit(void) 391fdecf31bSYi Zou { 392fdecf31bSYi Zou struct fcoe_transport *ft; 393fdecf31bSYi Zou 39470be6344SBhanu Prakash Gollapudi unregister_netdevice_notifier(&libfcoe_notifier); 395fdecf31bSYi Zou mutex_lock(&ft_mutex); 396fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) 397fdecf31bSYi Zou printk(KERN_ERR "FCoE transport %s is still attached!\n", 398fdecf31bSYi Zou ft->name); 399fdecf31bSYi Zou mutex_unlock(&ft_mutex); 400fdecf31bSYi Zou return 0; 401fdecf31bSYi Zou } 402fdecf31bSYi Zou 403fdecf31bSYi Zou 404fdecf31bSYi Zou static int fcoe_add_netdev_mapping(struct net_device *netdev, 405fdecf31bSYi Zou struct fcoe_transport *ft) 406fdecf31bSYi Zou { 407fdecf31bSYi Zou struct fcoe_netdev_mapping *nm; 408fdecf31bSYi Zou 409fdecf31bSYi Zou nm = kmalloc(sizeof(*nm), GFP_KERNEL); 410fdecf31bSYi Zou if (!nm) { 411fdecf31bSYi Zou printk(KERN_ERR "Unable to allocate netdev_mapping"); 412fdecf31bSYi Zou return -ENOMEM; 413fdecf31bSYi Zou } 414fdecf31bSYi Zou 415fdecf31bSYi Zou nm->netdev = netdev; 416fdecf31bSYi Zou nm->ft = ft; 417fdecf31bSYi Zou 41870be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 419fdecf31bSYi Zou list_add(&nm->list, &fcoe_netdevs); 42070be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 421fdecf31bSYi Zou return 0; 422fdecf31bSYi Zou } 423fdecf31bSYi Zou 424fdecf31bSYi Zou 425fdecf31bSYi Zou static void fcoe_del_netdev_mapping(struct net_device *netdev) 426fdecf31bSYi Zou { 427fdecf31bSYi Zou struct fcoe_netdev_mapping *nm = NULL, *tmp; 428fdecf31bSYi Zou 42970be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 430fdecf31bSYi Zou list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { 431fdecf31bSYi Zou if (nm->netdev == netdev) { 432fdecf31bSYi Zou list_del(&nm->list); 433fdecf31bSYi Zou kfree(nm); 43470be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 435fdecf31bSYi Zou return; 436fdecf31bSYi Zou } 437fdecf31bSYi Zou } 43870be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 439fdecf31bSYi Zou } 440fdecf31bSYi Zou 441fdecf31bSYi Zou 442fdecf31bSYi Zou /** 443fdecf31bSYi Zou * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which 444fdecf31bSYi Zou * it was created 445fdecf31bSYi Zou * 446fdecf31bSYi Zou * Returns : ptr to the fcoe transport that supports this netdev or NULL 447fdecf31bSYi Zou * if not found. 448fdecf31bSYi Zou * 449fdecf31bSYi Zou * The ft_mutex should be held when this is called 450fdecf31bSYi Zou */ 451fdecf31bSYi Zou static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev) 452fdecf31bSYi Zou { 453fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 454fdecf31bSYi Zou struct fcoe_netdev_mapping *nm; 455fdecf31bSYi Zou 45670be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 457fdecf31bSYi Zou list_for_each_entry(nm, &fcoe_netdevs, list) { 458fdecf31bSYi Zou if (netdev == nm->netdev) { 459fdecf31bSYi Zou ft = nm->ft; 46070be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 461fdecf31bSYi Zou return ft; 462fdecf31bSYi Zou } 463fdecf31bSYi Zou } 464fdecf31bSYi Zou 46570be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 466fdecf31bSYi Zou return NULL; 467fdecf31bSYi Zou } 468fdecf31bSYi Zou 469fdecf31bSYi Zou /** 470fdecf31bSYi Zou * fcoe_if_to_netdev() - Parse a name buffer to get a net device 471fdecf31bSYi Zou * @buffer: The name of the net device 472fdecf31bSYi Zou * 473fdecf31bSYi Zou * Returns: NULL or a ptr to net_device 474fdecf31bSYi Zou */ 475fdecf31bSYi Zou static struct net_device *fcoe_if_to_netdev(const char *buffer) 476fdecf31bSYi Zou { 477fdecf31bSYi Zou char *cp; 478fdecf31bSYi Zou char ifname[IFNAMSIZ + 2]; 479fdecf31bSYi Zou 480fdecf31bSYi Zou if (buffer) { 481fdecf31bSYi Zou strlcpy(ifname, buffer, IFNAMSIZ); 482fdecf31bSYi Zou cp = ifname + strlen(ifname); 483fdecf31bSYi Zou while (--cp >= ifname && *cp == '\n') 484fdecf31bSYi Zou *cp = '\0'; 485fdecf31bSYi Zou return dev_get_by_name(&init_net, ifname); 486fdecf31bSYi Zou } 487fdecf31bSYi Zou return NULL; 488fdecf31bSYi Zou } 489fdecf31bSYi Zou 490fdecf31bSYi Zou /** 49170be6344SBhanu Prakash Gollapudi * libfcoe_device_notification() - Handler for net device events 49270be6344SBhanu Prakash Gollapudi * @notifier: The context of the notification 49370be6344SBhanu Prakash Gollapudi * @event: The type of event 49470be6344SBhanu Prakash Gollapudi * @ptr: The net device that the event was on 49570be6344SBhanu Prakash Gollapudi * 49670be6344SBhanu Prakash Gollapudi * This function is called by the Ethernet driver in case of link change event. 49770be6344SBhanu Prakash Gollapudi * 49870be6344SBhanu Prakash Gollapudi * Returns: 0 for success 49970be6344SBhanu Prakash Gollapudi */ 50070be6344SBhanu Prakash Gollapudi static int libfcoe_device_notification(struct notifier_block *notifier, 50170be6344SBhanu Prakash Gollapudi ulong event, void *ptr) 50270be6344SBhanu Prakash Gollapudi { 50370be6344SBhanu Prakash Gollapudi struct net_device *netdev = ptr; 50470be6344SBhanu Prakash Gollapudi 50570be6344SBhanu Prakash Gollapudi switch (event) { 50670be6344SBhanu Prakash Gollapudi case NETDEV_UNREGISTER: 50770be6344SBhanu Prakash Gollapudi printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n", 50870be6344SBhanu Prakash Gollapudi netdev->name); 50970be6344SBhanu Prakash Gollapudi fcoe_del_netdev_mapping(netdev); 51070be6344SBhanu Prakash Gollapudi break; 51170be6344SBhanu Prakash Gollapudi } 51270be6344SBhanu Prakash Gollapudi return NOTIFY_OK; 51370be6344SBhanu Prakash Gollapudi } 51470be6344SBhanu Prakash Gollapudi 51570be6344SBhanu Prakash Gollapudi 51670be6344SBhanu Prakash Gollapudi /** 517fdecf31bSYi Zou * fcoe_transport_create() - Create a fcoe interface 518fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to create on 519fdecf31bSYi Zou * @kp: The associated kernel param 520fdecf31bSYi Zou * 521fdecf31bSYi Zou * Called from sysfs. This holds the ft_mutex while calling the 522fdecf31bSYi Zou * registered fcoe transport's create function. 523fdecf31bSYi Zou * 524fdecf31bSYi Zou * Returns: 0 for success 525fdecf31bSYi Zou */ 526fdecf31bSYi Zou static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) 527fdecf31bSYi Zou { 528fdecf31bSYi Zou int rc = -ENODEV; 529fdecf31bSYi Zou struct net_device *netdev = NULL; 530fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 531fdecf31bSYi Zou enum fip_state fip_mode = (enum fip_state)(long)kp->arg; 532fdecf31bSYi Zou 533fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE 534fdecf31bSYi Zou /* 535fdecf31bSYi Zou * Make sure the module has been initialized, and is not about to be 536fdecf31bSYi Zou * removed. Module parameter sysfs files are writable before the 537fdecf31bSYi Zou * module_init function is called and after module_exit. 538fdecf31bSYi Zou */ 539fdecf31bSYi Zou if (THIS_MODULE->state != MODULE_STATE_LIVE) 540fdecf31bSYi Zou goto out_nodev; 541fdecf31bSYi Zou #endif 542fdecf31bSYi Zou 543b3960afeSRobert Love mutex_lock(&ft_mutex); 544b3960afeSRobert Love 545fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 546fdecf31bSYi Zou if (!netdev) { 547fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer); 548fdecf31bSYi Zou goto out_nodev; 549fdecf31bSYi Zou } 550fdecf31bSYi Zou 551fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 552fdecf31bSYi Zou if (ft) { 553fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already has existing " 554fdecf31bSYi Zou "FCoE instance on %s.\n", 555fdecf31bSYi Zou ft->name, netdev->name); 556fdecf31bSYi Zou rc = -EEXIST; 557fdecf31bSYi Zou goto out_putdev; 558fdecf31bSYi Zou } 559fdecf31bSYi Zou 560fdecf31bSYi Zou ft = fcoe_transport_lookup(netdev); 561fdecf31bSYi Zou if (!ft) { 562fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 563fdecf31bSYi Zou netdev->name); 564fdecf31bSYi Zou goto out_putdev; 565fdecf31bSYi Zou } 566fdecf31bSYi Zou 567fdecf31bSYi Zou rc = fcoe_add_netdev_mapping(netdev, ft); 568fdecf31bSYi Zou if (rc) { 569fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping " 570fdecf31bSYi Zou "for FCoE transport %s for %s.\n", 571fdecf31bSYi Zou ft->name, netdev->name); 572fdecf31bSYi Zou goto out_putdev; 573fdecf31bSYi Zou } 574fdecf31bSYi Zou 575fdecf31bSYi Zou /* pass to transport create */ 576fdecf31bSYi Zou rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV; 577fdecf31bSYi Zou if (rc) 578fdecf31bSYi Zou fcoe_del_netdev_mapping(netdev); 579fdecf31bSYi Zou 580fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n", 581fdecf31bSYi Zou ft->name, (rc) ? "failed" : "succeeded", 582fdecf31bSYi Zou netdev->name); 583fdecf31bSYi Zou 584fdecf31bSYi Zou out_putdev: 585fdecf31bSYi Zou dev_put(netdev); 586fdecf31bSYi Zou out_nodev: 587fdecf31bSYi Zou mutex_unlock(&ft_mutex); 588fdecf31bSYi Zou return rc; 589fdecf31bSYi Zou } 590fdecf31bSYi Zou 591fdecf31bSYi Zou /** 592fdecf31bSYi Zou * fcoe_transport_destroy() - Destroy a FCoE interface 593fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be destroyed 594fdecf31bSYi Zou * @kp: The associated kernel parameter 595fdecf31bSYi Zou * 596fdecf31bSYi Zou * Called from sysfs. This holds the ft_mutex while calling the 597fdecf31bSYi Zou * registered fcoe transport's destroy function. 598fdecf31bSYi Zou * 599fdecf31bSYi Zou * Returns: 0 for success 600fdecf31bSYi Zou */ 601fdecf31bSYi Zou static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) 602fdecf31bSYi Zou { 603fdecf31bSYi Zou int rc = -ENODEV; 604fdecf31bSYi Zou struct net_device *netdev = NULL; 605fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 606fdecf31bSYi Zou 607fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE 608fdecf31bSYi Zou /* 609fdecf31bSYi Zou * Make sure the module has been initialized, and is not about to be 610fdecf31bSYi Zou * removed. Module parameter sysfs files are writable before the 611fdecf31bSYi Zou * module_init function is called and after module_exit. 612fdecf31bSYi Zou */ 613fdecf31bSYi Zou if (THIS_MODULE->state != MODULE_STATE_LIVE) 614fdecf31bSYi Zou goto out_nodev; 615fdecf31bSYi Zou #endif 616fdecf31bSYi Zou 617b3960afeSRobert Love mutex_lock(&ft_mutex); 618b3960afeSRobert Love 619fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 620fdecf31bSYi Zou if (!netdev) { 621fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer); 622fdecf31bSYi Zou goto out_nodev; 623fdecf31bSYi Zou } 624fdecf31bSYi Zou 625fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 626fdecf31bSYi Zou if (!ft) { 627fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 628fdecf31bSYi Zou netdev->name); 629fdecf31bSYi Zou goto out_putdev; 630fdecf31bSYi Zou } 631fdecf31bSYi Zou 632fdecf31bSYi Zou /* pass to transport destroy */ 633fdecf31bSYi Zou rc = ft->destroy ? ft->destroy(netdev) : -ENODEV; 634fdecf31bSYi Zou fcoe_del_netdev_mapping(netdev); 635fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n", 636fdecf31bSYi Zou ft->name, (rc) ? "failed" : "succeeded", 637fdecf31bSYi Zou netdev->name); 638fdecf31bSYi Zou 639fdecf31bSYi Zou out_putdev: 640fdecf31bSYi Zou dev_put(netdev); 641fdecf31bSYi Zou out_nodev: 642fdecf31bSYi Zou mutex_unlock(&ft_mutex); 643fdecf31bSYi Zou return rc; 644fdecf31bSYi Zou } 645fdecf31bSYi Zou 646fdecf31bSYi Zou /** 647fdecf31bSYi Zou * fcoe_transport_disable() - Disables a FCoE interface 648fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be disabled 649fdecf31bSYi Zou * @kp: The associated kernel parameter 650fdecf31bSYi Zou * 651fdecf31bSYi Zou * Called from sysfs. 652fdecf31bSYi Zou * 653fdecf31bSYi Zou * Returns: 0 for success 654fdecf31bSYi Zou */ 655fdecf31bSYi Zou static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) 656fdecf31bSYi Zou { 657fdecf31bSYi Zou int rc = -ENODEV; 658fdecf31bSYi Zou struct net_device *netdev = NULL; 659fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 660fdecf31bSYi Zou 661fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE 662fdecf31bSYi Zou /* 663fdecf31bSYi Zou * Make sure the module has been initialized, and is not about to be 664fdecf31bSYi Zou * removed. Module parameter sysfs files are writable before the 665fdecf31bSYi Zou * module_init function is called and after module_exit. 666fdecf31bSYi Zou */ 667fdecf31bSYi Zou if (THIS_MODULE->state != MODULE_STATE_LIVE) 668fdecf31bSYi Zou goto out_nodev; 669fdecf31bSYi Zou #endif 670fdecf31bSYi Zou 671b3960afeSRobert Love mutex_lock(&ft_mutex); 672b3960afeSRobert Love 673fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 674fdecf31bSYi Zou if (!netdev) 675fdecf31bSYi Zou goto out_nodev; 676fdecf31bSYi Zou 677fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 678fdecf31bSYi Zou if (!ft) 679fdecf31bSYi Zou goto out_putdev; 680fdecf31bSYi Zou 681fdecf31bSYi Zou rc = ft->disable ? ft->disable(netdev) : -ENODEV; 682fdecf31bSYi Zou 683fdecf31bSYi Zou out_putdev: 684fdecf31bSYi Zou dev_put(netdev); 685fdecf31bSYi Zou out_nodev: 686fdecf31bSYi Zou mutex_unlock(&ft_mutex); 687fdecf31bSYi Zou 688fdecf31bSYi Zou if (rc == -ERESTARTSYS) 689fdecf31bSYi Zou return restart_syscall(); 690fdecf31bSYi Zou else 691fdecf31bSYi Zou return rc; 692fdecf31bSYi Zou } 693fdecf31bSYi Zou 694fdecf31bSYi Zou /** 695fdecf31bSYi Zou * fcoe_transport_enable() - Enables a FCoE interface 696fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be enabled 697fdecf31bSYi Zou * @kp: The associated kernel parameter 698fdecf31bSYi Zou * 699fdecf31bSYi Zou * Called from sysfs. 700fdecf31bSYi Zou * 701fdecf31bSYi Zou * Returns: 0 for success 702fdecf31bSYi Zou */ 703fdecf31bSYi Zou static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) 704fdecf31bSYi Zou { 705fdecf31bSYi Zou int rc = -ENODEV; 706fdecf31bSYi Zou struct net_device *netdev = NULL; 707fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 708fdecf31bSYi Zou 709fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE 710fdecf31bSYi Zou /* 711fdecf31bSYi Zou * Make sure the module has been initialized, and is not about to be 712fdecf31bSYi Zou * removed. Module parameter sysfs files are writable before the 713fdecf31bSYi Zou * module_init function is called and after module_exit. 714fdecf31bSYi Zou */ 715fdecf31bSYi Zou if (THIS_MODULE->state != MODULE_STATE_LIVE) 716fdecf31bSYi Zou goto out_nodev; 717fdecf31bSYi Zou #endif 718fdecf31bSYi Zou 719b3960afeSRobert Love mutex_lock(&ft_mutex); 720b3960afeSRobert Love 721fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 722fdecf31bSYi Zou if (!netdev) 723fdecf31bSYi Zou goto out_nodev; 724fdecf31bSYi Zou 725fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 726fdecf31bSYi Zou if (!ft) 727fdecf31bSYi Zou goto out_putdev; 728fdecf31bSYi Zou 729fdecf31bSYi Zou rc = ft->enable ? ft->enable(netdev) : -ENODEV; 730fdecf31bSYi Zou 731fdecf31bSYi Zou out_putdev: 732fdecf31bSYi Zou dev_put(netdev); 733fdecf31bSYi Zou out_nodev: 734fdecf31bSYi Zou mutex_unlock(&ft_mutex); 735fdecf31bSYi Zou return rc; 736fdecf31bSYi Zou } 737fdecf31bSYi Zou 738fdecf31bSYi Zou /** 739fdecf31bSYi Zou * libfcoe_init() - Initialization routine for libfcoe.ko 740fdecf31bSYi Zou */ 741fdecf31bSYi Zou static int __init libfcoe_init(void) 742fdecf31bSYi Zou { 743fdecf31bSYi Zou fcoe_transport_init(); 744fdecf31bSYi Zou 745fdecf31bSYi Zou return 0; 746fdecf31bSYi Zou } 747fdecf31bSYi Zou module_init(libfcoe_init); 748fdecf31bSYi Zou 749fdecf31bSYi Zou /** 750fdecf31bSYi Zou * libfcoe_exit() - Tear down libfcoe.ko 751fdecf31bSYi Zou */ 752fdecf31bSYi Zou static void __exit libfcoe_exit(void) 753fdecf31bSYi Zou { 754fdecf31bSYi Zou fcoe_transport_exit(); 755fdecf31bSYi Zou } 756fdecf31bSYi Zou module_exit(libfcoe_exit); 757