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 86814740d5SBhanu Prakash Gollapudi void __fcoe_get_lesb(struct fc_lport *lport, 87814740d5SBhanu Prakash Gollapudi struct fc_els_lesb *fc_lesb, 88814740d5SBhanu Prakash Gollapudi struct net_device *netdev) 89814740d5SBhanu Prakash Gollapudi { 90814740d5SBhanu Prakash Gollapudi unsigned int cpu; 91814740d5SBhanu Prakash Gollapudi u32 lfc, vlfc, mdac; 921bd49b48SVasu Dev struct fc_stats *stats; 93814740d5SBhanu Prakash Gollapudi struct fcoe_fc_els_lesb *lesb; 94814740d5SBhanu Prakash Gollapudi struct rtnl_link_stats64 temp; 95814740d5SBhanu Prakash Gollapudi 96814740d5SBhanu Prakash Gollapudi lfc = 0; 97814740d5SBhanu Prakash Gollapudi vlfc = 0; 98814740d5SBhanu Prakash Gollapudi mdac = 0; 99814740d5SBhanu Prakash Gollapudi lesb = (struct fcoe_fc_els_lesb *)fc_lesb; 100814740d5SBhanu Prakash Gollapudi memset(lesb, 0, sizeof(*lesb)); 101814740d5SBhanu Prakash Gollapudi for_each_possible_cpu(cpu) { 1021bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, cpu); 1031bd49b48SVasu Dev lfc += stats->LinkFailureCount; 1041bd49b48SVasu Dev vlfc += stats->VLinkFailureCount; 1051bd49b48SVasu Dev mdac += stats->MissDiscAdvCount; 106814740d5SBhanu Prakash Gollapudi } 107814740d5SBhanu Prakash Gollapudi lesb->lesb_link_fail = htonl(lfc); 108814740d5SBhanu Prakash Gollapudi lesb->lesb_vlink_fail = htonl(vlfc); 109814740d5SBhanu Prakash Gollapudi lesb->lesb_miss_fka = htonl(mdac); 110814740d5SBhanu Prakash Gollapudi lesb->lesb_fcs_error = 111814740d5SBhanu Prakash Gollapudi htonl(dev_get_stats(netdev, &temp)->rx_crc_errors); 112814740d5SBhanu Prakash Gollapudi } 113814740d5SBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(__fcoe_get_lesb); 114814740d5SBhanu Prakash Gollapudi 115d834895cSBhanu Prakash Gollapudi void fcoe_wwn_to_str(u64 wwn, char *buf, int len) 116d834895cSBhanu Prakash Gollapudi { 117d834895cSBhanu Prakash Gollapudi u8 wwpn[8]; 118d834895cSBhanu Prakash Gollapudi 119d834895cSBhanu Prakash Gollapudi u64_to_wwn(wwn, wwpn); 120d834895cSBhanu Prakash Gollapudi snprintf(buf, len, "%02x%02x%02x%02x%02x%02x%02x%02x", 121d834895cSBhanu Prakash Gollapudi wwpn[0], wwpn[1], wwpn[2], wwpn[3], 122d834895cSBhanu Prakash Gollapudi wwpn[4], wwpn[5], wwpn[6], wwpn[7]); 123d834895cSBhanu Prakash Gollapudi } 124d834895cSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_wwn_to_str); 125d834895cSBhanu Prakash Gollapudi 126d834895cSBhanu Prakash Gollapudi /** 127d834895cSBhanu Prakash Gollapudi * fcoe_validate_vport_create() - Validate a vport before creating it 128d834895cSBhanu Prakash Gollapudi * @vport: NPIV port to be created 129d834895cSBhanu Prakash Gollapudi * 130d834895cSBhanu Prakash Gollapudi * This routine is meant to add validation for a vport before creating it 131d834895cSBhanu Prakash Gollapudi * via fcoe_vport_create(). 132d834895cSBhanu Prakash Gollapudi * Current validations are: 133d834895cSBhanu Prakash Gollapudi * - WWPN supplied is unique for given lport 134d834895cSBhanu Prakash Gollapudi */ 135d834895cSBhanu Prakash Gollapudi int fcoe_validate_vport_create(struct fc_vport *vport) 136d834895cSBhanu Prakash Gollapudi { 137d834895cSBhanu Prakash Gollapudi struct Scsi_Host *shost = vport_to_shost(vport); 138d834895cSBhanu Prakash Gollapudi struct fc_lport *n_port = shost_priv(shost); 139d834895cSBhanu Prakash Gollapudi struct fc_lport *vn_port; 140d834895cSBhanu Prakash Gollapudi int rc = 0; 141d834895cSBhanu Prakash Gollapudi char buf[32]; 142d834895cSBhanu Prakash Gollapudi 143d834895cSBhanu Prakash Gollapudi mutex_lock(&n_port->lp_mutex); 144d834895cSBhanu Prakash Gollapudi 145d834895cSBhanu Prakash Gollapudi fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); 146d834895cSBhanu Prakash Gollapudi /* Check if the wwpn is not same as that of the lport */ 147d834895cSBhanu Prakash Gollapudi if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) { 148d834895cSBhanu Prakash Gollapudi LIBFCOE_TRANSPORT_DBG("vport WWPN 0x%s is same as that of the " 149d834895cSBhanu Prakash Gollapudi "base port WWPN\n", buf); 150d834895cSBhanu Prakash Gollapudi rc = -EINVAL; 151d834895cSBhanu Prakash Gollapudi goto out; 152d834895cSBhanu Prakash Gollapudi } 153d834895cSBhanu Prakash Gollapudi 154d834895cSBhanu Prakash Gollapudi /* Check if there is any existing vport with same wwpn */ 155d834895cSBhanu Prakash Gollapudi list_for_each_entry(vn_port, &n_port->vports, list) { 156d834895cSBhanu Prakash Gollapudi if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) { 157d834895cSBhanu Prakash Gollapudi LIBFCOE_TRANSPORT_DBG("vport with given WWPN 0x%s " 158d834895cSBhanu Prakash Gollapudi "already exists\n", buf); 159d834895cSBhanu Prakash Gollapudi rc = -EINVAL; 160d834895cSBhanu Prakash Gollapudi break; 161d834895cSBhanu Prakash Gollapudi } 162d834895cSBhanu Prakash Gollapudi } 163d834895cSBhanu Prakash Gollapudi out: 164d834895cSBhanu Prakash Gollapudi mutex_unlock(&n_port->lp_mutex); 165d834895cSBhanu Prakash Gollapudi return rc; 166d834895cSBhanu Prakash Gollapudi } 167d834895cSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_validate_vport_create); 168d834895cSBhanu Prakash Gollapudi 169d834895cSBhanu Prakash Gollapudi /** 170d834895cSBhanu Prakash Gollapudi * fcoe_get_wwn() - Get the world wide name from LLD if it supports it 171d834895cSBhanu Prakash Gollapudi * @netdev: the associated net device 172d834895cSBhanu Prakash Gollapudi * @wwn: the output WWN 173d834895cSBhanu Prakash Gollapudi * @type: the type of WWN (WWPN or WWNN) 174d834895cSBhanu Prakash Gollapudi * 175d834895cSBhanu Prakash Gollapudi * Returns: 0 for success 176d834895cSBhanu Prakash Gollapudi */ 177d834895cSBhanu Prakash Gollapudi int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) 178d834895cSBhanu Prakash Gollapudi { 179d834895cSBhanu Prakash Gollapudi const struct net_device_ops *ops = netdev->netdev_ops; 180d834895cSBhanu Prakash Gollapudi 181d834895cSBhanu Prakash Gollapudi if (ops->ndo_fcoe_get_wwn) 182d834895cSBhanu Prakash Gollapudi return ops->ndo_fcoe_get_wwn(netdev, wwn, type); 183d834895cSBhanu Prakash Gollapudi return -EINVAL; 184d834895cSBhanu Prakash Gollapudi } 185d834895cSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_get_wwn); 186d834895cSBhanu Prakash Gollapudi 187fdecf31bSYi Zou /** 1888597ae8bSBhanu Prakash Gollapudi * fcoe_fc_crc() - Calculates the CRC for a given frame 1898597ae8bSBhanu Prakash Gollapudi * @fp: The frame to be checksumed 1908597ae8bSBhanu Prakash Gollapudi * 1918597ae8bSBhanu Prakash Gollapudi * This uses crc32() routine to calculate the CRC for a frame 1928597ae8bSBhanu Prakash Gollapudi * 1938597ae8bSBhanu Prakash Gollapudi * Return: The 32 bit CRC value 1948597ae8bSBhanu Prakash Gollapudi */ 1958597ae8bSBhanu Prakash Gollapudi u32 fcoe_fc_crc(struct fc_frame *fp) 1968597ae8bSBhanu Prakash Gollapudi { 1978597ae8bSBhanu Prakash Gollapudi struct sk_buff *skb = fp_skb(fp); 1988597ae8bSBhanu Prakash Gollapudi struct skb_frag_struct *frag; 1998597ae8bSBhanu Prakash Gollapudi unsigned char *data; 2008597ae8bSBhanu Prakash Gollapudi unsigned long off, len, clen; 2018597ae8bSBhanu Prakash Gollapudi u32 crc; 2028597ae8bSBhanu Prakash Gollapudi unsigned i; 2038597ae8bSBhanu Prakash Gollapudi 2048597ae8bSBhanu Prakash Gollapudi crc = crc32(~0, skb->data, skb_headlen(skb)); 2058597ae8bSBhanu Prakash Gollapudi 2068597ae8bSBhanu Prakash Gollapudi for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 2078597ae8bSBhanu Prakash Gollapudi frag = &skb_shinfo(skb)->frags[i]; 2088597ae8bSBhanu Prakash Gollapudi off = frag->page_offset; 2099e903e08SEric Dumazet len = skb_frag_size(frag); 2108597ae8bSBhanu Prakash Gollapudi while (len > 0) { 2118597ae8bSBhanu Prakash Gollapudi clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); 212165c68d5SIan Campbell data = kmap_atomic( 21377dfce07SCong Wang skb_frag_page(frag) + (off >> PAGE_SHIFT)); 2148597ae8bSBhanu Prakash Gollapudi crc = crc32(crc, data + (off & ~PAGE_MASK), clen); 21577dfce07SCong Wang kunmap_atomic(data); 2168597ae8bSBhanu Prakash Gollapudi off += clen; 2178597ae8bSBhanu Prakash Gollapudi len -= clen; 2188597ae8bSBhanu Prakash Gollapudi } 2198597ae8bSBhanu Prakash Gollapudi } 2208597ae8bSBhanu Prakash Gollapudi return crc; 2218597ae8bSBhanu Prakash Gollapudi } 2228597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_fc_crc); 2238597ae8bSBhanu Prakash Gollapudi 2248597ae8bSBhanu Prakash Gollapudi /** 2258597ae8bSBhanu Prakash Gollapudi * fcoe_start_io() - Start FCoE I/O 2268597ae8bSBhanu Prakash Gollapudi * @skb: The packet to be transmitted 2278597ae8bSBhanu Prakash Gollapudi * 2288597ae8bSBhanu Prakash Gollapudi * This routine is called from the net device to start transmitting 2298597ae8bSBhanu Prakash Gollapudi * FCoE packets. 2308597ae8bSBhanu Prakash Gollapudi * 2318597ae8bSBhanu Prakash Gollapudi * Returns: 0 for success 2328597ae8bSBhanu Prakash Gollapudi */ 2338597ae8bSBhanu Prakash Gollapudi int fcoe_start_io(struct sk_buff *skb) 2348597ae8bSBhanu Prakash Gollapudi { 2358597ae8bSBhanu Prakash Gollapudi struct sk_buff *nskb; 2368597ae8bSBhanu Prakash Gollapudi int rc; 2378597ae8bSBhanu Prakash Gollapudi 2388597ae8bSBhanu Prakash Gollapudi nskb = skb_clone(skb, GFP_ATOMIC); 2398597ae8bSBhanu Prakash Gollapudi if (!nskb) 2408597ae8bSBhanu Prakash Gollapudi return -ENOMEM; 2418597ae8bSBhanu Prakash Gollapudi rc = dev_queue_xmit(nskb); 2428597ae8bSBhanu Prakash Gollapudi if (rc != 0) 2438597ae8bSBhanu Prakash Gollapudi return rc; 2448597ae8bSBhanu Prakash Gollapudi kfree_skb(skb); 2458597ae8bSBhanu Prakash Gollapudi return 0; 2468597ae8bSBhanu Prakash Gollapudi } 2478597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_start_io); 2488597ae8bSBhanu Prakash Gollapudi 2498597ae8bSBhanu Prakash Gollapudi 2508597ae8bSBhanu Prakash Gollapudi /** 2518597ae8bSBhanu Prakash Gollapudi * fcoe_clean_pending_queue() - Dequeue a skb and free it 2528597ae8bSBhanu Prakash Gollapudi * @lport: The local port to dequeue a skb on 2538597ae8bSBhanu Prakash Gollapudi */ 2548597ae8bSBhanu Prakash Gollapudi void fcoe_clean_pending_queue(struct fc_lport *lport) 2558597ae8bSBhanu Prakash Gollapudi { 2568597ae8bSBhanu Prakash Gollapudi struct fcoe_port *port = lport_priv(lport); 2578597ae8bSBhanu Prakash Gollapudi struct sk_buff *skb; 2588597ae8bSBhanu Prakash Gollapudi 2598597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 2608597ae8bSBhanu Prakash Gollapudi while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) { 2618597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 2628597ae8bSBhanu Prakash Gollapudi kfree_skb(skb); 2638597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 2648597ae8bSBhanu Prakash Gollapudi } 2658597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 2668597ae8bSBhanu Prakash Gollapudi } 2678597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); 2688597ae8bSBhanu Prakash Gollapudi 2698597ae8bSBhanu Prakash Gollapudi /** 2708597ae8bSBhanu Prakash Gollapudi * fcoe_check_wait_queue() - Attempt to clear the transmit backlog 2718597ae8bSBhanu Prakash Gollapudi * @lport: The local port whose backlog is to be cleared 2728597ae8bSBhanu Prakash Gollapudi * 2738597ae8bSBhanu Prakash Gollapudi * This empties the wait_queue, dequeues the head of the wait_queue queue 2748597ae8bSBhanu Prakash Gollapudi * and calls fcoe_start_io() for each packet. If all skb have been 2758597ae8bSBhanu Prakash Gollapudi * transmitted it returns the qlen. If an error occurs it restores 2768597ae8bSBhanu Prakash Gollapudi * wait_queue (to try again later) and returns -1. 2778597ae8bSBhanu Prakash Gollapudi * 2788597ae8bSBhanu Prakash Gollapudi * The wait_queue is used when the skb transmit fails. The failed skb 2798597ae8bSBhanu Prakash Gollapudi * will go in the wait_queue which will be emptied by the timer function or 2808597ae8bSBhanu Prakash Gollapudi * by the next skb transmit. 2818597ae8bSBhanu Prakash Gollapudi */ 2828597ae8bSBhanu Prakash Gollapudi void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb) 2838597ae8bSBhanu Prakash Gollapudi { 2848597ae8bSBhanu Prakash Gollapudi struct fcoe_port *port = lport_priv(lport); 2858597ae8bSBhanu Prakash Gollapudi int rc; 2868597ae8bSBhanu Prakash Gollapudi 2878597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 2888597ae8bSBhanu Prakash Gollapudi 2898597ae8bSBhanu Prakash Gollapudi if (skb) 2908597ae8bSBhanu Prakash Gollapudi __skb_queue_tail(&port->fcoe_pending_queue, skb); 2918597ae8bSBhanu Prakash Gollapudi 2928597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue_active) 2938597ae8bSBhanu Prakash Gollapudi goto out; 2948597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue_active = 1; 2958597ae8bSBhanu Prakash Gollapudi 2968597ae8bSBhanu Prakash Gollapudi while (port->fcoe_pending_queue.qlen) { 2978597ae8bSBhanu Prakash Gollapudi /* keep qlen > 0 until fcoe_start_io succeeds */ 2988597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen++; 2998597ae8bSBhanu Prakash Gollapudi skb = __skb_dequeue(&port->fcoe_pending_queue); 3008597ae8bSBhanu Prakash Gollapudi 3018597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 3028597ae8bSBhanu Prakash Gollapudi rc = fcoe_start_io(skb); 3038597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 3048597ae8bSBhanu Prakash Gollapudi 3058597ae8bSBhanu Prakash Gollapudi if (rc) { 3068597ae8bSBhanu Prakash Gollapudi __skb_queue_head(&port->fcoe_pending_queue, skb); 3078597ae8bSBhanu Prakash Gollapudi /* undo temporary increment above */ 3088597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen--; 3098597ae8bSBhanu Prakash Gollapudi break; 3108597ae8bSBhanu Prakash Gollapudi } 3118597ae8bSBhanu Prakash Gollapudi /* undo temporary increment above */ 3128597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen--; 3138597ae8bSBhanu Prakash Gollapudi } 3148597ae8bSBhanu Prakash Gollapudi 3158597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen < port->min_queue_depth) 3168597ae8bSBhanu Prakash Gollapudi lport->qfull = 0; 3178597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer)) 3188597ae8bSBhanu Prakash Gollapudi mod_timer(&port->timer, jiffies + 2); 3198597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue_active = 0; 3208597ae8bSBhanu Prakash Gollapudi out: 3218597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen > port->max_queue_depth) 3228597ae8bSBhanu Prakash Gollapudi lport->qfull = 1; 3238597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 3248597ae8bSBhanu Prakash Gollapudi } 3258597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_check_wait_queue); 3268597ae8bSBhanu Prakash Gollapudi 3278597ae8bSBhanu Prakash Gollapudi /** 3288597ae8bSBhanu Prakash Gollapudi * fcoe_queue_timer() - The fcoe queue timer 3298597ae8bSBhanu Prakash Gollapudi * @lport: The local port 3308597ae8bSBhanu Prakash Gollapudi * 3318597ae8bSBhanu Prakash Gollapudi * Calls fcoe_check_wait_queue on timeout 3328597ae8bSBhanu Prakash Gollapudi */ 3338597ae8bSBhanu Prakash Gollapudi void fcoe_queue_timer(ulong lport) 3348597ae8bSBhanu Prakash Gollapudi { 3358597ae8bSBhanu Prakash Gollapudi fcoe_check_wait_queue((struct fc_lport *)lport, NULL); 3368597ae8bSBhanu Prakash Gollapudi } 3378597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_queue_timer); 3388597ae8bSBhanu Prakash Gollapudi 3398597ae8bSBhanu Prakash Gollapudi /** 3408597ae8bSBhanu Prakash Gollapudi * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC 3418597ae8bSBhanu Prakash Gollapudi * @skb: The packet to be transmitted 3428597ae8bSBhanu Prakash Gollapudi * @tlen: The total length of the trailer 3438597ae8bSBhanu Prakash Gollapudi * @fps: The fcoe context 3448597ae8bSBhanu Prakash Gollapudi * 3458597ae8bSBhanu Prakash Gollapudi * This routine allocates a page for frame trailers. The page is re-used if 3468597ae8bSBhanu Prakash Gollapudi * there is enough room left on it for the current trailer. If there isn't 3478597ae8bSBhanu Prakash Gollapudi * enough buffer left a new page is allocated for the trailer. Reference to 3488597ae8bSBhanu Prakash Gollapudi * the page from this function as well as the skbs using the page fragments 3498597ae8bSBhanu Prakash Gollapudi * ensure that the page is freed at the appropriate time. 3508597ae8bSBhanu Prakash Gollapudi * 3518597ae8bSBhanu Prakash Gollapudi * Returns: 0 for success 3528597ae8bSBhanu Prakash Gollapudi */ 3538597ae8bSBhanu Prakash Gollapudi int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, 3548597ae8bSBhanu Prakash Gollapudi struct fcoe_percpu_s *fps) 3558597ae8bSBhanu Prakash Gollapudi { 3568597ae8bSBhanu Prakash Gollapudi struct page *page; 3578597ae8bSBhanu Prakash Gollapudi 3588597ae8bSBhanu Prakash Gollapudi page = fps->crc_eof_page; 3598597ae8bSBhanu Prakash Gollapudi if (!page) { 3608597ae8bSBhanu Prakash Gollapudi page = alloc_page(GFP_ATOMIC); 3618597ae8bSBhanu Prakash Gollapudi if (!page) 3628597ae8bSBhanu Prakash Gollapudi return -ENOMEM; 3638597ae8bSBhanu Prakash Gollapudi 3648597ae8bSBhanu Prakash Gollapudi fps->crc_eof_page = page; 3658597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset = 0; 3668597ae8bSBhanu Prakash Gollapudi } 3678597ae8bSBhanu Prakash Gollapudi 3688597ae8bSBhanu Prakash Gollapudi get_page(page); 3698597ae8bSBhanu Prakash Gollapudi skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 3708597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset, tlen); 3718597ae8bSBhanu Prakash Gollapudi skb->len += tlen; 3728597ae8bSBhanu Prakash Gollapudi skb->data_len += tlen; 3738597ae8bSBhanu Prakash Gollapudi skb->truesize += tlen; 3748597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); 3758597ae8bSBhanu Prakash Gollapudi 3768597ae8bSBhanu Prakash Gollapudi if (fps->crc_eof_offset >= PAGE_SIZE) { 3778597ae8bSBhanu Prakash Gollapudi fps->crc_eof_page = NULL; 3788597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset = 0; 3798597ae8bSBhanu Prakash Gollapudi put_page(page); 3808597ae8bSBhanu Prakash Gollapudi } 3818597ae8bSBhanu Prakash Gollapudi 3828597ae8bSBhanu Prakash Gollapudi return 0; 3838597ae8bSBhanu Prakash Gollapudi } 3848597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_get_paged_crc_eof); 3858597ae8bSBhanu Prakash Gollapudi 3868597ae8bSBhanu Prakash Gollapudi /** 387fdecf31bSYi Zou * fcoe_transport_lookup - find an fcoe transport that matches a netdev 388fdecf31bSYi Zou * @netdev: The netdev to look for from all attached transports 389fdecf31bSYi Zou * 390fdecf31bSYi Zou * Returns : ptr to the fcoe transport that supports this netdev or NULL 391fdecf31bSYi Zou * if not found. 392fdecf31bSYi Zou * 393fdecf31bSYi Zou * The ft_mutex should be held when this is called 394fdecf31bSYi Zou */ 395fdecf31bSYi Zou static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev) 396fdecf31bSYi Zou { 397fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 398fdecf31bSYi Zou 399fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) 400fdecf31bSYi Zou if (ft->match && ft->match(netdev)) 401fdecf31bSYi Zou return ft; 402fdecf31bSYi Zou return NULL; 403fdecf31bSYi Zou } 404fdecf31bSYi Zou 405fdecf31bSYi Zou /** 406fdecf31bSYi Zou * fcoe_transport_attach - Attaches an FCoE transport 407fdecf31bSYi Zou * @ft: The fcoe transport to be attached 408fdecf31bSYi Zou * 409fdecf31bSYi Zou * Returns : 0 for success 410fdecf31bSYi Zou */ 411fdecf31bSYi Zou int fcoe_transport_attach(struct fcoe_transport *ft) 412fdecf31bSYi Zou { 413fdecf31bSYi Zou int rc = 0; 414fdecf31bSYi Zou 415fdecf31bSYi Zou mutex_lock(&ft_mutex); 416fdecf31bSYi Zou if (ft->attached) { 417fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already attached\n", 418fdecf31bSYi Zou ft->name); 419fdecf31bSYi Zou rc = -EEXIST; 420fdecf31bSYi Zou goto out_attach; 421fdecf31bSYi Zou } 422fdecf31bSYi Zou 423fdecf31bSYi Zou /* Add default transport to the tail */ 424fdecf31bSYi Zou if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT)) 425fdecf31bSYi Zou list_add(&ft->list, &fcoe_transports); 426fdecf31bSYi Zou else 427fdecf31bSYi Zou list_add_tail(&ft->list, &fcoe_transports); 428fdecf31bSYi Zou 429fdecf31bSYi Zou ft->attached = true; 430fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name); 431fdecf31bSYi Zou 432fdecf31bSYi Zou out_attach: 433fdecf31bSYi Zou mutex_unlock(&ft_mutex); 434fdecf31bSYi Zou return rc; 435fdecf31bSYi Zou } 436fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_attach); 437fdecf31bSYi Zou 438fdecf31bSYi Zou /** 4394ef7fb15SYi Zou * fcoe_transport_detach - Detaches an FCoE transport 440fdecf31bSYi Zou * @ft: The fcoe transport to be attached 441fdecf31bSYi Zou * 442fdecf31bSYi Zou * Returns : 0 for success 443fdecf31bSYi Zou */ 444fdecf31bSYi Zou int fcoe_transport_detach(struct fcoe_transport *ft) 445fdecf31bSYi Zou { 446fdecf31bSYi Zou int rc = 0; 44769922fcdSYi Zou struct fcoe_netdev_mapping *nm = NULL, *tmp; 448fdecf31bSYi Zou 449fdecf31bSYi Zou mutex_lock(&ft_mutex); 450fdecf31bSYi Zou if (!ft->attached) { 451fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already detached\n", 452fdecf31bSYi Zou ft->name); 453fdecf31bSYi Zou rc = -ENODEV; 454fdecf31bSYi Zou goto out_attach; 455fdecf31bSYi Zou } 456fdecf31bSYi Zou 45769922fcdSYi Zou /* remove netdev mapping for this transport as it is going away */ 45869922fcdSYi Zou mutex_lock(&fn_mutex); 45969922fcdSYi Zou list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { 46069922fcdSYi Zou if (nm->ft == ft) { 46169922fcdSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s going away, " 46269922fcdSYi Zou "remove its netdev mapping for %s\n", 46369922fcdSYi Zou ft->name, nm->netdev->name); 46469922fcdSYi Zou list_del(&nm->list); 46569922fcdSYi Zou kfree(nm); 46669922fcdSYi Zou } 46769922fcdSYi Zou } 46869922fcdSYi Zou mutex_unlock(&fn_mutex); 46969922fcdSYi Zou 470fdecf31bSYi Zou list_del(&ft->list); 471fdecf31bSYi Zou ft->attached = false; 472fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name); 473fdecf31bSYi Zou 474fdecf31bSYi Zou out_attach: 475fdecf31bSYi Zou mutex_unlock(&ft_mutex); 476fdecf31bSYi Zou return rc; 477fdecf31bSYi Zou 478fdecf31bSYi Zou } 479fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_detach); 480fdecf31bSYi Zou 481fdecf31bSYi Zou static int fcoe_transport_show(char *buffer, const struct kernel_param *kp) 482fdecf31bSYi Zou { 483fdecf31bSYi Zou int i, j; 484fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 485fdecf31bSYi Zou 486fdecf31bSYi Zou i = j = sprintf(buffer, "Attached FCoE transports:"); 487fdecf31bSYi Zou mutex_lock(&ft_mutex); 488fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) { 489a01a5a57SYi Zou if (i >= PAGE_SIZE - IFNAMSIZ) 490fdecf31bSYi Zou break; 491a01a5a57SYi Zou i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); 492fdecf31bSYi Zou } 493fdecf31bSYi Zou mutex_unlock(&ft_mutex); 494fdecf31bSYi Zou if (i == j) 495fdecf31bSYi Zou i += snprintf(&buffer[i], IFNAMSIZ, "none"); 496fdecf31bSYi Zou return i; 497fdecf31bSYi Zou } 498fdecf31bSYi Zou 499fdecf31bSYi Zou static int __init fcoe_transport_init(void) 500fdecf31bSYi Zou { 50170be6344SBhanu Prakash Gollapudi register_netdevice_notifier(&libfcoe_notifier); 502fdecf31bSYi Zou return 0; 503fdecf31bSYi Zou } 504fdecf31bSYi Zou 505fdecf31bSYi Zou static int __exit fcoe_transport_exit(void) 506fdecf31bSYi Zou { 507fdecf31bSYi Zou struct fcoe_transport *ft; 508fdecf31bSYi Zou 50970be6344SBhanu Prakash Gollapudi unregister_netdevice_notifier(&libfcoe_notifier); 510fdecf31bSYi Zou mutex_lock(&ft_mutex); 511fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) 512fdecf31bSYi Zou printk(KERN_ERR "FCoE transport %s is still attached!\n", 513fdecf31bSYi Zou ft->name); 514fdecf31bSYi Zou mutex_unlock(&ft_mutex); 515fdecf31bSYi Zou return 0; 516fdecf31bSYi Zou } 517fdecf31bSYi Zou 518fdecf31bSYi Zou 519fdecf31bSYi Zou static int fcoe_add_netdev_mapping(struct net_device *netdev, 520fdecf31bSYi Zou struct fcoe_transport *ft) 521fdecf31bSYi Zou { 522fdecf31bSYi Zou struct fcoe_netdev_mapping *nm; 523fdecf31bSYi Zou 524fdecf31bSYi Zou nm = kmalloc(sizeof(*nm), GFP_KERNEL); 525fdecf31bSYi Zou if (!nm) { 526fdecf31bSYi Zou printk(KERN_ERR "Unable to allocate netdev_mapping"); 527fdecf31bSYi Zou return -ENOMEM; 528fdecf31bSYi Zou } 529fdecf31bSYi Zou 530fdecf31bSYi Zou nm->netdev = netdev; 531fdecf31bSYi Zou nm->ft = ft; 532fdecf31bSYi Zou 53370be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 534fdecf31bSYi Zou list_add(&nm->list, &fcoe_netdevs); 53570be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 536fdecf31bSYi Zou return 0; 537fdecf31bSYi Zou } 538fdecf31bSYi Zou 539fdecf31bSYi Zou 540fdecf31bSYi Zou static void fcoe_del_netdev_mapping(struct net_device *netdev) 541fdecf31bSYi Zou { 542fdecf31bSYi Zou struct fcoe_netdev_mapping *nm = NULL, *tmp; 543fdecf31bSYi Zou 54470be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 545fdecf31bSYi Zou list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { 546fdecf31bSYi Zou if (nm->netdev == netdev) { 547fdecf31bSYi Zou list_del(&nm->list); 548fdecf31bSYi Zou kfree(nm); 54970be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 550fdecf31bSYi Zou return; 551fdecf31bSYi Zou } 552fdecf31bSYi Zou } 55370be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 554fdecf31bSYi Zou } 555fdecf31bSYi Zou 556fdecf31bSYi Zou 557fdecf31bSYi Zou /** 558fdecf31bSYi Zou * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which 559fdecf31bSYi Zou * it was created 560fdecf31bSYi Zou * 561fdecf31bSYi Zou * Returns : ptr to the fcoe transport that supports this netdev or NULL 562fdecf31bSYi Zou * if not found. 563fdecf31bSYi Zou * 564fdecf31bSYi Zou * The ft_mutex should be held when this is called 565fdecf31bSYi Zou */ 566fdecf31bSYi Zou static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev) 567fdecf31bSYi Zou { 568fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 569fdecf31bSYi Zou struct fcoe_netdev_mapping *nm; 570fdecf31bSYi Zou 57170be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 572fdecf31bSYi Zou list_for_each_entry(nm, &fcoe_netdevs, list) { 573fdecf31bSYi Zou if (netdev == nm->netdev) { 574fdecf31bSYi Zou ft = nm->ft; 57570be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 576fdecf31bSYi Zou return ft; 577fdecf31bSYi Zou } 578fdecf31bSYi Zou } 579fdecf31bSYi Zou 58070be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 581fdecf31bSYi Zou return NULL; 582fdecf31bSYi Zou } 583fdecf31bSYi Zou 584fdecf31bSYi Zou /** 585fdecf31bSYi Zou * fcoe_if_to_netdev() - Parse a name buffer to get a net device 586fdecf31bSYi Zou * @buffer: The name of the net device 587fdecf31bSYi Zou * 588fdecf31bSYi Zou * Returns: NULL or a ptr to net_device 589fdecf31bSYi Zou */ 590fdecf31bSYi Zou static struct net_device *fcoe_if_to_netdev(const char *buffer) 591fdecf31bSYi Zou { 592fdecf31bSYi Zou char *cp; 593fdecf31bSYi Zou char ifname[IFNAMSIZ + 2]; 594fdecf31bSYi Zou 595fdecf31bSYi Zou if (buffer) { 596fdecf31bSYi Zou strlcpy(ifname, buffer, IFNAMSIZ); 597fdecf31bSYi Zou cp = ifname + strlen(ifname); 598fdecf31bSYi Zou while (--cp >= ifname && *cp == '\n') 599fdecf31bSYi Zou *cp = '\0'; 600fdecf31bSYi Zou return dev_get_by_name(&init_net, ifname); 601fdecf31bSYi Zou } 602fdecf31bSYi Zou return NULL; 603fdecf31bSYi Zou } 604fdecf31bSYi Zou 605fdecf31bSYi Zou /** 60670be6344SBhanu Prakash Gollapudi * libfcoe_device_notification() - Handler for net device events 60770be6344SBhanu Prakash Gollapudi * @notifier: The context of the notification 60870be6344SBhanu Prakash Gollapudi * @event: The type of event 60970be6344SBhanu Prakash Gollapudi * @ptr: The net device that the event was on 61070be6344SBhanu Prakash Gollapudi * 61170be6344SBhanu Prakash Gollapudi * This function is called by the Ethernet driver in case of link change event. 61270be6344SBhanu Prakash Gollapudi * 61370be6344SBhanu Prakash Gollapudi * Returns: 0 for success 61470be6344SBhanu Prakash Gollapudi */ 61570be6344SBhanu Prakash Gollapudi static int libfcoe_device_notification(struct notifier_block *notifier, 61670be6344SBhanu Prakash Gollapudi ulong event, void *ptr) 61770be6344SBhanu Prakash Gollapudi { 61870be6344SBhanu Prakash Gollapudi struct net_device *netdev = ptr; 61970be6344SBhanu Prakash Gollapudi 62070be6344SBhanu Prakash Gollapudi switch (event) { 62170be6344SBhanu Prakash Gollapudi case NETDEV_UNREGISTER: 622b99fbf6aSRobert Love LIBFCOE_TRANSPORT_DBG("NETDEV_UNREGISTER %s\n", 62370be6344SBhanu Prakash Gollapudi netdev->name); 62470be6344SBhanu Prakash Gollapudi fcoe_del_netdev_mapping(netdev); 62570be6344SBhanu Prakash Gollapudi break; 62670be6344SBhanu Prakash Gollapudi } 62770be6344SBhanu Prakash Gollapudi return NOTIFY_OK; 62870be6344SBhanu Prakash Gollapudi } 62970be6344SBhanu Prakash Gollapudi 63070be6344SBhanu Prakash Gollapudi 63170be6344SBhanu Prakash Gollapudi /** 632fdecf31bSYi Zou * fcoe_transport_create() - Create a fcoe interface 633fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to create on 634fdecf31bSYi Zou * @kp: The associated kernel param 635fdecf31bSYi Zou * 636fdecf31bSYi Zou * Called from sysfs. This holds the ft_mutex while calling the 637fdecf31bSYi Zou * registered fcoe transport's create function. 638fdecf31bSYi Zou * 639fdecf31bSYi Zou * Returns: 0 for success 640fdecf31bSYi Zou */ 641fdecf31bSYi Zou static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) 642fdecf31bSYi Zou { 643fdecf31bSYi Zou int rc = -ENODEV; 644fdecf31bSYi Zou struct net_device *netdev = NULL; 645fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 646fdecf31bSYi Zou enum fip_state fip_mode = (enum fip_state)(long)kp->arg; 647fdecf31bSYi Zou 648b3960afeSRobert Love mutex_lock(&ft_mutex); 649b3960afeSRobert Love 650fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 651fdecf31bSYi Zou if (!netdev) { 652fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer); 653fdecf31bSYi Zou goto out_nodev; 654fdecf31bSYi Zou } 655fdecf31bSYi Zou 656fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 657fdecf31bSYi Zou if (ft) { 658fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already has existing " 659fdecf31bSYi Zou "FCoE instance on %s.\n", 660fdecf31bSYi Zou ft->name, netdev->name); 661fdecf31bSYi Zou rc = -EEXIST; 662fdecf31bSYi Zou goto out_putdev; 663fdecf31bSYi Zou } 664fdecf31bSYi Zou 665fdecf31bSYi Zou ft = fcoe_transport_lookup(netdev); 666fdecf31bSYi Zou if (!ft) { 667fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 668fdecf31bSYi Zou netdev->name); 669fdecf31bSYi Zou goto out_putdev; 670fdecf31bSYi Zou } 671fdecf31bSYi Zou 672fdecf31bSYi Zou rc = fcoe_add_netdev_mapping(netdev, ft); 673fdecf31bSYi Zou if (rc) { 674fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping " 675fdecf31bSYi Zou "for FCoE transport %s for %s.\n", 676fdecf31bSYi Zou ft->name, netdev->name); 677fdecf31bSYi Zou goto out_putdev; 678fdecf31bSYi Zou } 679fdecf31bSYi Zou 680fdecf31bSYi Zou /* pass to transport create */ 681fdecf31bSYi Zou rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV; 682fdecf31bSYi Zou if (rc) 683fdecf31bSYi Zou fcoe_del_netdev_mapping(netdev); 684fdecf31bSYi Zou 685fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n", 686fdecf31bSYi Zou ft->name, (rc) ? "failed" : "succeeded", 687fdecf31bSYi Zou netdev->name); 688fdecf31bSYi Zou 689fdecf31bSYi Zou out_putdev: 690fdecf31bSYi Zou dev_put(netdev); 691fdecf31bSYi Zou out_nodev: 692fdecf31bSYi Zou mutex_unlock(&ft_mutex); 693fdecf31bSYi Zou return rc; 694fdecf31bSYi Zou } 695fdecf31bSYi Zou 696fdecf31bSYi Zou /** 697fdecf31bSYi Zou * fcoe_transport_destroy() - Destroy a FCoE interface 698fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be destroyed 699fdecf31bSYi Zou * @kp: The associated kernel parameter 700fdecf31bSYi Zou * 701fdecf31bSYi Zou * Called from sysfs. This holds the ft_mutex while calling the 702fdecf31bSYi Zou * registered fcoe transport's destroy function. 703fdecf31bSYi Zou * 704fdecf31bSYi Zou * Returns: 0 for success 705fdecf31bSYi Zou */ 706fdecf31bSYi Zou static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) 707fdecf31bSYi Zou { 708fdecf31bSYi Zou int rc = -ENODEV; 709fdecf31bSYi Zou struct net_device *netdev = NULL; 710fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 711fdecf31bSYi Zou 712b3960afeSRobert Love mutex_lock(&ft_mutex); 713b3960afeSRobert Love 714fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 715fdecf31bSYi Zou if (!netdev) { 716fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer); 717fdecf31bSYi Zou goto out_nodev; 718fdecf31bSYi Zou } 719fdecf31bSYi Zou 720fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 721fdecf31bSYi Zou if (!ft) { 722fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 723fdecf31bSYi Zou netdev->name); 724fdecf31bSYi Zou goto out_putdev; 725fdecf31bSYi Zou } 726fdecf31bSYi Zou 727fdecf31bSYi Zou /* pass to transport destroy */ 728fdecf31bSYi Zou rc = ft->destroy ? ft->destroy(netdev) : -ENODEV; 729fdecf31bSYi Zou fcoe_del_netdev_mapping(netdev); 730fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n", 731fdecf31bSYi Zou ft->name, (rc) ? "failed" : "succeeded", 732fdecf31bSYi Zou netdev->name); 733fdecf31bSYi Zou 734fdecf31bSYi Zou out_putdev: 735fdecf31bSYi Zou dev_put(netdev); 736fdecf31bSYi Zou out_nodev: 737fdecf31bSYi Zou mutex_unlock(&ft_mutex); 738fdecf31bSYi Zou return rc; 739fdecf31bSYi Zou } 740fdecf31bSYi Zou 741fdecf31bSYi Zou /** 742fdecf31bSYi Zou * fcoe_transport_disable() - Disables a FCoE interface 743fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be disabled 744fdecf31bSYi Zou * @kp: The associated kernel parameter 745fdecf31bSYi Zou * 746fdecf31bSYi Zou * Called from sysfs. 747fdecf31bSYi Zou * 748fdecf31bSYi Zou * Returns: 0 for success 749fdecf31bSYi Zou */ 750fdecf31bSYi Zou static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) 751fdecf31bSYi Zou { 752fdecf31bSYi Zou int rc = -ENODEV; 753fdecf31bSYi Zou struct net_device *netdev = NULL; 754fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 755fdecf31bSYi Zou 756b3960afeSRobert Love mutex_lock(&ft_mutex); 757b3960afeSRobert Love 758fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 759fdecf31bSYi Zou if (!netdev) 760fdecf31bSYi Zou goto out_nodev; 761fdecf31bSYi Zou 762fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 763fdecf31bSYi Zou if (!ft) 764fdecf31bSYi Zou goto out_putdev; 765fdecf31bSYi Zou 766fdecf31bSYi Zou rc = ft->disable ? ft->disable(netdev) : -ENODEV; 767fdecf31bSYi Zou 768fdecf31bSYi Zou out_putdev: 769fdecf31bSYi Zou dev_put(netdev); 770fdecf31bSYi Zou out_nodev: 771fdecf31bSYi Zou mutex_unlock(&ft_mutex); 772fdecf31bSYi Zou 773fdecf31bSYi Zou if (rc == -ERESTARTSYS) 774fdecf31bSYi Zou return restart_syscall(); 775fdecf31bSYi Zou else 776fdecf31bSYi Zou return rc; 777fdecf31bSYi Zou } 778fdecf31bSYi Zou 779fdecf31bSYi Zou /** 780fdecf31bSYi Zou * fcoe_transport_enable() - Enables a FCoE interface 781fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be enabled 782fdecf31bSYi Zou * @kp: The associated kernel parameter 783fdecf31bSYi Zou * 784fdecf31bSYi Zou * Called from sysfs. 785fdecf31bSYi Zou * 786fdecf31bSYi Zou * Returns: 0 for success 787fdecf31bSYi Zou */ 788fdecf31bSYi Zou static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) 789fdecf31bSYi Zou { 790fdecf31bSYi Zou int rc = -ENODEV; 791fdecf31bSYi Zou struct net_device *netdev = NULL; 792fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 793fdecf31bSYi Zou 794b3960afeSRobert Love mutex_lock(&ft_mutex); 795b3960afeSRobert Love 796fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 797fdecf31bSYi Zou if (!netdev) 798fdecf31bSYi Zou goto out_nodev; 799fdecf31bSYi Zou 800fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 801fdecf31bSYi Zou if (!ft) 802fdecf31bSYi Zou goto out_putdev; 803fdecf31bSYi Zou 804fdecf31bSYi Zou rc = ft->enable ? ft->enable(netdev) : -ENODEV; 805fdecf31bSYi Zou 806fdecf31bSYi Zou out_putdev: 807fdecf31bSYi Zou dev_put(netdev); 808fdecf31bSYi Zou out_nodev: 809fdecf31bSYi Zou mutex_unlock(&ft_mutex); 810fdecf31bSYi Zou return rc; 811fdecf31bSYi Zou } 812fdecf31bSYi Zou 813fdecf31bSYi Zou /** 814fdecf31bSYi Zou * libfcoe_init() - Initialization routine for libfcoe.ko 815fdecf31bSYi Zou */ 816fdecf31bSYi Zou static int __init libfcoe_init(void) 817fdecf31bSYi Zou { 8189a74e884SRobert Love int rc = 0; 819fdecf31bSYi Zou 8209a74e884SRobert Love rc = fcoe_transport_init(); 8219a74e884SRobert Love if (rc) 8229a74e884SRobert Love return rc; 8239a74e884SRobert Love 8249a74e884SRobert Love rc = fcoe_sysfs_setup(); 8259a74e884SRobert Love if (rc) 8269a74e884SRobert Love fcoe_transport_exit(); 8279a74e884SRobert Love 8289a74e884SRobert Love return rc; 829fdecf31bSYi Zou } 830fdecf31bSYi Zou module_init(libfcoe_init); 831fdecf31bSYi Zou 832fdecf31bSYi Zou /** 833fdecf31bSYi Zou * libfcoe_exit() - Tear down libfcoe.ko 834fdecf31bSYi Zou */ 835fdecf31bSYi Zou static void __exit libfcoe_exit(void) 836fdecf31bSYi Zou { 8379a74e884SRobert Love fcoe_sysfs_teardown(); 838fdecf31bSYi Zou fcoe_transport_exit(); 839fdecf31bSYi Zou } 840fdecf31bSYi Zou module_exit(libfcoe_exit); 841