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 8603702689SYi Zou /** 8703702689SYi Zou * fcoe_link_speed_update() - Update the supported and actual link speeds 8803702689SYi Zou * @lport: The local port to update speeds for 8903702689SYi Zou * 9003702689SYi Zou * Returns: 0 if the ethtool query was successful 9103702689SYi Zou * -1 if the ethtool query failed 9203702689SYi Zou */ 9303702689SYi Zou int fcoe_link_speed_update(struct fc_lport *lport) 9403702689SYi Zou { 9503702689SYi Zou struct net_device *netdev = fcoe_get_netdev(lport); 9603702689SYi Zou struct ethtool_cmd ecmd; 9703702689SYi Zou 9803702689SYi Zou if (!__ethtool_get_settings(netdev, &ecmd)) { 9903702689SYi Zou lport->link_supported_speeds &= 10003702689SYi Zou ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); 10103702689SYi Zou if (ecmd.supported & (SUPPORTED_1000baseT_Half | 10203702689SYi Zou SUPPORTED_1000baseT_Full)) 10303702689SYi Zou lport->link_supported_speeds |= FC_PORTSPEED_1GBIT; 10403702689SYi Zou if (ecmd.supported & SUPPORTED_10000baseT_Full) 10503702689SYi Zou lport->link_supported_speeds |= 10603702689SYi Zou FC_PORTSPEED_10GBIT; 10703702689SYi Zou switch (ethtool_cmd_speed(&ecmd)) { 10803702689SYi Zou case SPEED_1000: 10903702689SYi Zou lport->link_speed = FC_PORTSPEED_1GBIT; 11003702689SYi Zou break; 11103702689SYi Zou case SPEED_10000: 11203702689SYi Zou lport->link_speed = FC_PORTSPEED_10GBIT; 11303702689SYi Zou break; 11403702689SYi Zou } 11503702689SYi Zou return 0; 11603702689SYi Zou } 11703702689SYi Zou return -1; 11803702689SYi Zou } 11903702689SYi Zou EXPORT_SYMBOL_GPL(fcoe_link_speed_update); 12003702689SYi Zou 12157c2728fSYi Zou /** 12257c2728fSYi Zou * __fcoe_get_lesb() - Get the Link Error Status Block (LESB) for a given lport 12357c2728fSYi Zou * @lport: The local port to update speeds for 12457c2728fSYi Zou * @fc_lesb: Pointer to the LESB to be filled up 12557c2728fSYi Zou * @netdev: Pointer to the netdev that is associated with the lport 12657c2728fSYi Zou * 12757c2728fSYi Zou * Note, the Link Error Status Block (LESB) for FCoE is defined in FC-BB-6 12857c2728fSYi Zou * Clause 7.11 in v1.04. 12957c2728fSYi Zou */ 130814740d5SBhanu Prakash Gollapudi void __fcoe_get_lesb(struct fc_lport *lport, 131814740d5SBhanu Prakash Gollapudi struct fc_els_lesb *fc_lesb, 132814740d5SBhanu Prakash Gollapudi struct net_device *netdev) 133814740d5SBhanu Prakash Gollapudi { 134814740d5SBhanu Prakash Gollapudi unsigned int cpu; 135814740d5SBhanu Prakash Gollapudi u32 lfc, vlfc, mdac; 1361bd49b48SVasu Dev struct fc_stats *stats; 137814740d5SBhanu Prakash Gollapudi struct fcoe_fc_els_lesb *lesb; 138814740d5SBhanu Prakash Gollapudi struct rtnl_link_stats64 temp; 139814740d5SBhanu Prakash Gollapudi 140814740d5SBhanu Prakash Gollapudi lfc = 0; 141814740d5SBhanu Prakash Gollapudi vlfc = 0; 142814740d5SBhanu Prakash Gollapudi mdac = 0; 143814740d5SBhanu Prakash Gollapudi lesb = (struct fcoe_fc_els_lesb *)fc_lesb; 144814740d5SBhanu Prakash Gollapudi memset(lesb, 0, sizeof(*lesb)); 145814740d5SBhanu Prakash Gollapudi for_each_possible_cpu(cpu) { 1461bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, cpu); 1471bd49b48SVasu Dev lfc += stats->LinkFailureCount; 1481bd49b48SVasu Dev vlfc += stats->VLinkFailureCount; 1491bd49b48SVasu Dev mdac += stats->MissDiscAdvCount; 150814740d5SBhanu Prakash Gollapudi } 151814740d5SBhanu Prakash Gollapudi lesb->lesb_link_fail = htonl(lfc); 152814740d5SBhanu Prakash Gollapudi lesb->lesb_vlink_fail = htonl(vlfc); 153814740d5SBhanu Prakash Gollapudi lesb->lesb_miss_fka = htonl(mdac); 154814740d5SBhanu Prakash Gollapudi lesb->lesb_fcs_error = 155814740d5SBhanu Prakash Gollapudi htonl(dev_get_stats(netdev, &temp)->rx_crc_errors); 156814740d5SBhanu Prakash Gollapudi } 157814740d5SBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(__fcoe_get_lesb); 158814740d5SBhanu Prakash Gollapudi 15957c2728fSYi Zou /** 16057c2728fSYi Zou * fcoe_get_lesb() - Fill the FCoE Link Error Status Block 16157c2728fSYi Zou * @lport: the local port 16257c2728fSYi Zou * @fc_lesb: the link error status block 16357c2728fSYi Zou */ 16457c2728fSYi Zou void fcoe_get_lesb(struct fc_lport *lport, 16557c2728fSYi Zou struct fc_els_lesb *fc_lesb) 16657c2728fSYi Zou { 16757c2728fSYi Zou struct net_device *netdev = fcoe_get_netdev(lport); 16857c2728fSYi Zou 16957c2728fSYi Zou __fcoe_get_lesb(lport, fc_lesb, netdev); 17057c2728fSYi Zou } 17157c2728fSYi Zou EXPORT_SYMBOL_GPL(fcoe_get_lesb); 17257c2728fSYi Zou 17357c2728fSYi Zou /** 17457c2728fSYi Zou * fcoe_ctlr_get_lesb() - Get the Link Error Status Block (LESB) for a given 17557c2728fSYi Zou * fcoe controller device 17657c2728fSYi Zou * @ctlr_dev: The given fcoe controller device 17757c2728fSYi Zou * 17857c2728fSYi Zou */ 17957c2728fSYi Zou void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev) 18057c2728fSYi Zou { 18157c2728fSYi Zou struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); 18257c2728fSYi Zou struct net_device *netdev = fcoe_get_netdev(fip->lp); 183418a8cfeSYi Zou struct fc_els_lesb *fc_lesb; 18457c2728fSYi Zou 185418a8cfeSYi Zou fc_lesb = (struct fc_els_lesb *)(&ctlr_dev->lesb); 186418a8cfeSYi Zou __fcoe_get_lesb(fip->lp, fc_lesb, netdev); 18757c2728fSYi Zou } 18857c2728fSYi Zou EXPORT_SYMBOL_GPL(fcoe_ctlr_get_lesb); 18957c2728fSYi Zou 190d834895cSBhanu Prakash Gollapudi void fcoe_wwn_to_str(u64 wwn, char *buf, int len) 191d834895cSBhanu Prakash Gollapudi { 192d834895cSBhanu Prakash Gollapudi u8 wwpn[8]; 193d834895cSBhanu Prakash Gollapudi 194d834895cSBhanu Prakash Gollapudi u64_to_wwn(wwn, wwpn); 195d834895cSBhanu Prakash Gollapudi snprintf(buf, len, "%02x%02x%02x%02x%02x%02x%02x%02x", 196d834895cSBhanu Prakash Gollapudi wwpn[0], wwpn[1], wwpn[2], wwpn[3], 197d834895cSBhanu Prakash Gollapudi wwpn[4], wwpn[5], wwpn[6], wwpn[7]); 198d834895cSBhanu Prakash Gollapudi } 199d834895cSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_wwn_to_str); 200d834895cSBhanu Prakash Gollapudi 201d834895cSBhanu Prakash Gollapudi /** 202d834895cSBhanu Prakash Gollapudi * fcoe_validate_vport_create() - Validate a vport before creating it 203d834895cSBhanu Prakash Gollapudi * @vport: NPIV port to be created 204d834895cSBhanu Prakash Gollapudi * 205d834895cSBhanu Prakash Gollapudi * This routine is meant to add validation for a vport before creating it 206d834895cSBhanu Prakash Gollapudi * via fcoe_vport_create(). 207d834895cSBhanu Prakash Gollapudi * Current validations are: 208d834895cSBhanu Prakash Gollapudi * - WWPN supplied is unique for given lport 209d834895cSBhanu Prakash Gollapudi */ 210d834895cSBhanu Prakash Gollapudi int fcoe_validate_vport_create(struct fc_vport *vport) 211d834895cSBhanu Prakash Gollapudi { 212d834895cSBhanu Prakash Gollapudi struct Scsi_Host *shost = vport_to_shost(vport); 213d834895cSBhanu Prakash Gollapudi struct fc_lport *n_port = shost_priv(shost); 214d834895cSBhanu Prakash Gollapudi struct fc_lport *vn_port; 215d834895cSBhanu Prakash Gollapudi int rc = 0; 216d834895cSBhanu Prakash Gollapudi char buf[32]; 217d834895cSBhanu Prakash Gollapudi 218d834895cSBhanu Prakash Gollapudi mutex_lock(&n_port->lp_mutex); 219d834895cSBhanu Prakash Gollapudi 220d834895cSBhanu Prakash Gollapudi fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); 221d834895cSBhanu Prakash Gollapudi /* Check if the wwpn is not same as that of the lport */ 222d834895cSBhanu Prakash Gollapudi if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) { 223d834895cSBhanu Prakash Gollapudi LIBFCOE_TRANSPORT_DBG("vport WWPN 0x%s is same as that of the " 224d834895cSBhanu Prakash Gollapudi "base port WWPN\n", buf); 225d834895cSBhanu Prakash Gollapudi rc = -EINVAL; 226d834895cSBhanu Prakash Gollapudi goto out; 227d834895cSBhanu Prakash Gollapudi } 228d834895cSBhanu Prakash Gollapudi 229d834895cSBhanu Prakash Gollapudi /* Check if there is any existing vport with same wwpn */ 230d834895cSBhanu Prakash Gollapudi list_for_each_entry(vn_port, &n_port->vports, list) { 231d834895cSBhanu Prakash Gollapudi if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) { 232d834895cSBhanu Prakash Gollapudi LIBFCOE_TRANSPORT_DBG("vport with given WWPN 0x%s " 233d834895cSBhanu Prakash Gollapudi "already exists\n", buf); 234d834895cSBhanu Prakash Gollapudi rc = -EINVAL; 235d834895cSBhanu Prakash Gollapudi break; 236d834895cSBhanu Prakash Gollapudi } 237d834895cSBhanu Prakash Gollapudi } 238d834895cSBhanu Prakash Gollapudi out: 239d834895cSBhanu Prakash Gollapudi mutex_unlock(&n_port->lp_mutex); 240d834895cSBhanu Prakash Gollapudi return rc; 241d834895cSBhanu Prakash Gollapudi } 242d834895cSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_validate_vport_create); 243d834895cSBhanu Prakash Gollapudi 244d834895cSBhanu Prakash Gollapudi /** 245d834895cSBhanu Prakash Gollapudi * fcoe_get_wwn() - Get the world wide name from LLD if it supports it 246d834895cSBhanu Prakash Gollapudi * @netdev: the associated net device 247d834895cSBhanu Prakash Gollapudi * @wwn: the output WWN 248d834895cSBhanu Prakash Gollapudi * @type: the type of WWN (WWPN or WWNN) 249d834895cSBhanu Prakash Gollapudi * 250d834895cSBhanu Prakash Gollapudi * Returns: 0 for success 251d834895cSBhanu Prakash Gollapudi */ 252d834895cSBhanu Prakash Gollapudi int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) 253d834895cSBhanu Prakash Gollapudi { 254d834895cSBhanu Prakash Gollapudi const struct net_device_ops *ops = netdev->netdev_ops; 255d834895cSBhanu Prakash Gollapudi 256d834895cSBhanu Prakash Gollapudi if (ops->ndo_fcoe_get_wwn) 257d834895cSBhanu Prakash Gollapudi return ops->ndo_fcoe_get_wwn(netdev, wwn, type); 258d834895cSBhanu Prakash Gollapudi return -EINVAL; 259d834895cSBhanu Prakash Gollapudi } 260d834895cSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_get_wwn); 261d834895cSBhanu Prakash Gollapudi 262fdecf31bSYi Zou /** 2638597ae8bSBhanu Prakash Gollapudi * fcoe_fc_crc() - Calculates the CRC for a given frame 2648597ae8bSBhanu Prakash Gollapudi * @fp: The frame to be checksumed 2658597ae8bSBhanu Prakash Gollapudi * 2668597ae8bSBhanu Prakash Gollapudi * This uses crc32() routine to calculate the CRC for a frame 2678597ae8bSBhanu Prakash Gollapudi * 2688597ae8bSBhanu Prakash Gollapudi * Return: The 32 bit CRC value 2698597ae8bSBhanu Prakash Gollapudi */ 2708597ae8bSBhanu Prakash Gollapudi u32 fcoe_fc_crc(struct fc_frame *fp) 2718597ae8bSBhanu Prakash Gollapudi { 2728597ae8bSBhanu Prakash Gollapudi struct sk_buff *skb = fp_skb(fp); 2738597ae8bSBhanu Prakash Gollapudi struct skb_frag_struct *frag; 2748597ae8bSBhanu Prakash Gollapudi unsigned char *data; 2758597ae8bSBhanu Prakash Gollapudi unsigned long off, len, clen; 2768597ae8bSBhanu Prakash Gollapudi u32 crc; 2778597ae8bSBhanu Prakash Gollapudi unsigned i; 2788597ae8bSBhanu Prakash Gollapudi 2798597ae8bSBhanu Prakash Gollapudi crc = crc32(~0, skb->data, skb_headlen(skb)); 2808597ae8bSBhanu Prakash Gollapudi 2818597ae8bSBhanu Prakash Gollapudi for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 2828597ae8bSBhanu Prakash Gollapudi frag = &skb_shinfo(skb)->frags[i]; 2838597ae8bSBhanu Prakash Gollapudi off = frag->page_offset; 2849e903e08SEric Dumazet len = skb_frag_size(frag); 2858597ae8bSBhanu Prakash Gollapudi while (len > 0) { 2868597ae8bSBhanu Prakash Gollapudi clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); 287165c68d5SIan Campbell data = kmap_atomic( 28877dfce07SCong Wang skb_frag_page(frag) + (off >> PAGE_SHIFT)); 2898597ae8bSBhanu Prakash Gollapudi crc = crc32(crc, data + (off & ~PAGE_MASK), clen); 29077dfce07SCong Wang kunmap_atomic(data); 2918597ae8bSBhanu Prakash Gollapudi off += clen; 2928597ae8bSBhanu Prakash Gollapudi len -= clen; 2938597ae8bSBhanu Prakash Gollapudi } 2948597ae8bSBhanu Prakash Gollapudi } 2958597ae8bSBhanu Prakash Gollapudi return crc; 2968597ae8bSBhanu Prakash Gollapudi } 2978597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_fc_crc); 2988597ae8bSBhanu Prakash Gollapudi 2998597ae8bSBhanu Prakash Gollapudi /** 3008597ae8bSBhanu Prakash Gollapudi * fcoe_start_io() - Start FCoE I/O 3018597ae8bSBhanu Prakash Gollapudi * @skb: The packet to be transmitted 3028597ae8bSBhanu Prakash Gollapudi * 3038597ae8bSBhanu Prakash Gollapudi * This routine is called from the net device to start transmitting 3048597ae8bSBhanu Prakash Gollapudi * FCoE packets. 3058597ae8bSBhanu Prakash Gollapudi * 3068597ae8bSBhanu Prakash Gollapudi * Returns: 0 for success 3078597ae8bSBhanu Prakash Gollapudi */ 3088597ae8bSBhanu Prakash Gollapudi int fcoe_start_io(struct sk_buff *skb) 3098597ae8bSBhanu Prakash Gollapudi { 3108597ae8bSBhanu Prakash Gollapudi struct sk_buff *nskb; 3118597ae8bSBhanu Prakash Gollapudi int rc; 3128597ae8bSBhanu Prakash Gollapudi 3138597ae8bSBhanu Prakash Gollapudi nskb = skb_clone(skb, GFP_ATOMIC); 3148597ae8bSBhanu Prakash Gollapudi if (!nskb) 3158597ae8bSBhanu Prakash Gollapudi return -ENOMEM; 3168597ae8bSBhanu Prakash Gollapudi rc = dev_queue_xmit(nskb); 3178597ae8bSBhanu Prakash Gollapudi if (rc != 0) 3188597ae8bSBhanu Prakash Gollapudi return rc; 3198597ae8bSBhanu Prakash Gollapudi kfree_skb(skb); 3208597ae8bSBhanu Prakash Gollapudi return 0; 3218597ae8bSBhanu Prakash Gollapudi } 3228597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_start_io); 3238597ae8bSBhanu Prakash Gollapudi 3248597ae8bSBhanu Prakash Gollapudi 3258597ae8bSBhanu Prakash Gollapudi /** 3268597ae8bSBhanu Prakash Gollapudi * fcoe_clean_pending_queue() - Dequeue a skb and free it 3278597ae8bSBhanu Prakash Gollapudi * @lport: The local port to dequeue a skb on 3288597ae8bSBhanu Prakash Gollapudi */ 3298597ae8bSBhanu Prakash Gollapudi void fcoe_clean_pending_queue(struct fc_lport *lport) 3308597ae8bSBhanu Prakash Gollapudi { 3318597ae8bSBhanu Prakash Gollapudi struct fcoe_port *port = lport_priv(lport); 3328597ae8bSBhanu Prakash Gollapudi struct sk_buff *skb; 3338597ae8bSBhanu Prakash Gollapudi 3348597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 3358597ae8bSBhanu Prakash Gollapudi while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) { 3368597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 3378597ae8bSBhanu Prakash Gollapudi kfree_skb(skb); 3388597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 3398597ae8bSBhanu Prakash Gollapudi } 3408597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 3418597ae8bSBhanu Prakash Gollapudi } 3428597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); 3438597ae8bSBhanu Prakash Gollapudi 3448597ae8bSBhanu Prakash Gollapudi /** 3458597ae8bSBhanu Prakash Gollapudi * fcoe_check_wait_queue() - Attempt to clear the transmit backlog 3468597ae8bSBhanu Prakash Gollapudi * @lport: The local port whose backlog is to be cleared 3478597ae8bSBhanu Prakash Gollapudi * 3488597ae8bSBhanu Prakash Gollapudi * This empties the wait_queue, dequeues the head of the wait_queue queue 3498597ae8bSBhanu Prakash Gollapudi * and calls fcoe_start_io() for each packet. If all skb have been 3508597ae8bSBhanu Prakash Gollapudi * transmitted it returns the qlen. If an error occurs it restores 3518597ae8bSBhanu Prakash Gollapudi * wait_queue (to try again later) and returns -1. 3528597ae8bSBhanu Prakash Gollapudi * 3538597ae8bSBhanu Prakash Gollapudi * The wait_queue is used when the skb transmit fails. The failed skb 3548597ae8bSBhanu Prakash Gollapudi * will go in the wait_queue which will be emptied by the timer function or 3558597ae8bSBhanu Prakash Gollapudi * by the next skb transmit. 3568597ae8bSBhanu Prakash Gollapudi */ 3578597ae8bSBhanu Prakash Gollapudi void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb) 3588597ae8bSBhanu Prakash Gollapudi { 3598597ae8bSBhanu Prakash Gollapudi struct fcoe_port *port = lport_priv(lport); 3608597ae8bSBhanu Prakash Gollapudi int rc; 3618597ae8bSBhanu Prakash Gollapudi 3628597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 3638597ae8bSBhanu Prakash Gollapudi 3648597ae8bSBhanu Prakash Gollapudi if (skb) 3658597ae8bSBhanu Prakash Gollapudi __skb_queue_tail(&port->fcoe_pending_queue, skb); 3668597ae8bSBhanu Prakash Gollapudi 3678597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue_active) 3688597ae8bSBhanu Prakash Gollapudi goto out; 3698597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue_active = 1; 3708597ae8bSBhanu Prakash Gollapudi 3718597ae8bSBhanu Prakash Gollapudi while (port->fcoe_pending_queue.qlen) { 3728597ae8bSBhanu Prakash Gollapudi /* keep qlen > 0 until fcoe_start_io succeeds */ 3738597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen++; 3748597ae8bSBhanu Prakash Gollapudi skb = __skb_dequeue(&port->fcoe_pending_queue); 3758597ae8bSBhanu Prakash Gollapudi 3768597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 3778597ae8bSBhanu Prakash Gollapudi rc = fcoe_start_io(skb); 3788597ae8bSBhanu Prakash Gollapudi spin_lock_bh(&port->fcoe_pending_queue.lock); 3798597ae8bSBhanu Prakash Gollapudi 3808597ae8bSBhanu Prakash Gollapudi if (rc) { 3818597ae8bSBhanu Prakash Gollapudi __skb_queue_head(&port->fcoe_pending_queue, skb); 3828597ae8bSBhanu Prakash Gollapudi /* undo temporary increment above */ 3838597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen--; 3848597ae8bSBhanu Prakash Gollapudi break; 3858597ae8bSBhanu Prakash Gollapudi } 3868597ae8bSBhanu Prakash Gollapudi /* undo temporary increment above */ 3878597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue.qlen--; 3888597ae8bSBhanu Prakash Gollapudi } 3898597ae8bSBhanu Prakash Gollapudi 3908597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen < port->min_queue_depth) 3918597ae8bSBhanu Prakash Gollapudi lport->qfull = 0; 3928597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer)) 3938597ae8bSBhanu Prakash Gollapudi mod_timer(&port->timer, jiffies + 2); 3948597ae8bSBhanu Prakash Gollapudi port->fcoe_pending_queue_active = 0; 3958597ae8bSBhanu Prakash Gollapudi out: 3968597ae8bSBhanu Prakash Gollapudi if (port->fcoe_pending_queue.qlen > port->max_queue_depth) 3978597ae8bSBhanu Prakash Gollapudi lport->qfull = 1; 3988597ae8bSBhanu Prakash Gollapudi spin_unlock_bh(&port->fcoe_pending_queue.lock); 3998597ae8bSBhanu Prakash Gollapudi } 4008597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_check_wait_queue); 4018597ae8bSBhanu Prakash Gollapudi 4028597ae8bSBhanu Prakash Gollapudi /** 4038597ae8bSBhanu Prakash Gollapudi * fcoe_queue_timer() - The fcoe queue timer 4048597ae8bSBhanu Prakash Gollapudi * @lport: The local port 4058597ae8bSBhanu Prakash Gollapudi * 4068597ae8bSBhanu Prakash Gollapudi * Calls fcoe_check_wait_queue on timeout 4078597ae8bSBhanu Prakash Gollapudi */ 4088597ae8bSBhanu Prakash Gollapudi void fcoe_queue_timer(ulong lport) 4098597ae8bSBhanu Prakash Gollapudi { 4108597ae8bSBhanu Prakash Gollapudi fcoe_check_wait_queue((struct fc_lport *)lport, NULL); 4118597ae8bSBhanu Prakash Gollapudi } 4128597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_queue_timer); 4138597ae8bSBhanu Prakash Gollapudi 4148597ae8bSBhanu Prakash Gollapudi /** 4158597ae8bSBhanu Prakash Gollapudi * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC 4168597ae8bSBhanu Prakash Gollapudi * @skb: The packet to be transmitted 4178597ae8bSBhanu Prakash Gollapudi * @tlen: The total length of the trailer 4188597ae8bSBhanu Prakash Gollapudi * @fps: The fcoe context 4198597ae8bSBhanu Prakash Gollapudi * 4208597ae8bSBhanu Prakash Gollapudi * This routine allocates a page for frame trailers. The page is re-used if 4218597ae8bSBhanu Prakash Gollapudi * there is enough room left on it for the current trailer. If there isn't 4228597ae8bSBhanu Prakash Gollapudi * enough buffer left a new page is allocated for the trailer. Reference to 4238597ae8bSBhanu Prakash Gollapudi * the page from this function as well as the skbs using the page fragments 4248597ae8bSBhanu Prakash Gollapudi * ensure that the page is freed at the appropriate time. 4258597ae8bSBhanu Prakash Gollapudi * 4268597ae8bSBhanu Prakash Gollapudi * Returns: 0 for success 4278597ae8bSBhanu Prakash Gollapudi */ 4288597ae8bSBhanu Prakash Gollapudi int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, 4298597ae8bSBhanu Prakash Gollapudi struct fcoe_percpu_s *fps) 4308597ae8bSBhanu Prakash Gollapudi { 4318597ae8bSBhanu Prakash Gollapudi struct page *page; 4328597ae8bSBhanu Prakash Gollapudi 4338597ae8bSBhanu Prakash Gollapudi page = fps->crc_eof_page; 4348597ae8bSBhanu Prakash Gollapudi if (!page) { 4358597ae8bSBhanu Prakash Gollapudi page = alloc_page(GFP_ATOMIC); 4368597ae8bSBhanu Prakash Gollapudi if (!page) 4378597ae8bSBhanu Prakash Gollapudi return -ENOMEM; 4388597ae8bSBhanu Prakash Gollapudi 4398597ae8bSBhanu Prakash Gollapudi fps->crc_eof_page = page; 4408597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset = 0; 4418597ae8bSBhanu Prakash Gollapudi } 4428597ae8bSBhanu Prakash Gollapudi 4438597ae8bSBhanu Prakash Gollapudi get_page(page); 4448597ae8bSBhanu Prakash Gollapudi skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 4458597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset, tlen); 4468597ae8bSBhanu Prakash Gollapudi skb->len += tlen; 4478597ae8bSBhanu Prakash Gollapudi skb->data_len += tlen; 4488597ae8bSBhanu Prakash Gollapudi skb->truesize += tlen; 4498597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); 4508597ae8bSBhanu Prakash Gollapudi 4518597ae8bSBhanu Prakash Gollapudi if (fps->crc_eof_offset >= PAGE_SIZE) { 4528597ae8bSBhanu Prakash Gollapudi fps->crc_eof_page = NULL; 4538597ae8bSBhanu Prakash Gollapudi fps->crc_eof_offset = 0; 4548597ae8bSBhanu Prakash Gollapudi put_page(page); 4558597ae8bSBhanu Prakash Gollapudi } 4568597ae8bSBhanu Prakash Gollapudi 4578597ae8bSBhanu Prakash Gollapudi return 0; 4588597ae8bSBhanu Prakash Gollapudi } 4598597ae8bSBhanu Prakash Gollapudi EXPORT_SYMBOL_GPL(fcoe_get_paged_crc_eof); 4608597ae8bSBhanu Prakash Gollapudi 4618597ae8bSBhanu Prakash Gollapudi /** 462fdecf31bSYi Zou * fcoe_transport_lookup - find an fcoe transport that matches a netdev 463fdecf31bSYi Zou * @netdev: The netdev to look for from all attached transports 464fdecf31bSYi Zou * 465fdecf31bSYi Zou * Returns : ptr to the fcoe transport that supports this netdev or NULL 466fdecf31bSYi Zou * if not found. 467fdecf31bSYi Zou * 468fdecf31bSYi Zou * The ft_mutex should be held when this is called 469fdecf31bSYi Zou */ 470fdecf31bSYi Zou static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev) 471fdecf31bSYi Zou { 472fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 473fdecf31bSYi Zou 474fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) 475fdecf31bSYi Zou if (ft->match && ft->match(netdev)) 476fdecf31bSYi Zou return ft; 477fdecf31bSYi Zou return NULL; 478fdecf31bSYi Zou } 479fdecf31bSYi Zou 480fdecf31bSYi Zou /** 481fdecf31bSYi Zou * fcoe_transport_attach - Attaches an FCoE transport 482fdecf31bSYi Zou * @ft: The fcoe transport to be attached 483fdecf31bSYi Zou * 484fdecf31bSYi Zou * Returns : 0 for success 485fdecf31bSYi Zou */ 486fdecf31bSYi Zou int fcoe_transport_attach(struct fcoe_transport *ft) 487fdecf31bSYi Zou { 488fdecf31bSYi Zou int rc = 0; 489fdecf31bSYi Zou 490fdecf31bSYi Zou mutex_lock(&ft_mutex); 491fdecf31bSYi Zou if (ft->attached) { 492fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already attached\n", 493fdecf31bSYi Zou ft->name); 494fdecf31bSYi Zou rc = -EEXIST; 495fdecf31bSYi Zou goto out_attach; 496fdecf31bSYi Zou } 497fdecf31bSYi Zou 498fdecf31bSYi Zou /* Add default transport to the tail */ 499fdecf31bSYi Zou if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT)) 500fdecf31bSYi Zou list_add(&ft->list, &fcoe_transports); 501fdecf31bSYi Zou else 502fdecf31bSYi Zou list_add_tail(&ft->list, &fcoe_transports); 503fdecf31bSYi Zou 504fdecf31bSYi Zou ft->attached = true; 505fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name); 506fdecf31bSYi Zou 507fdecf31bSYi Zou out_attach: 508fdecf31bSYi Zou mutex_unlock(&ft_mutex); 509fdecf31bSYi Zou return rc; 510fdecf31bSYi Zou } 511fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_attach); 512fdecf31bSYi Zou 513fdecf31bSYi Zou /** 5144ef7fb15SYi Zou * fcoe_transport_detach - Detaches an FCoE transport 515fdecf31bSYi Zou * @ft: The fcoe transport to be attached 516fdecf31bSYi Zou * 517fdecf31bSYi Zou * Returns : 0 for success 518fdecf31bSYi Zou */ 519fdecf31bSYi Zou int fcoe_transport_detach(struct fcoe_transport *ft) 520fdecf31bSYi Zou { 521fdecf31bSYi Zou int rc = 0; 52269922fcdSYi Zou struct fcoe_netdev_mapping *nm = NULL, *tmp; 523fdecf31bSYi Zou 524fdecf31bSYi Zou mutex_lock(&ft_mutex); 525fdecf31bSYi Zou if (!ft->attached) { 526fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already detached\n", 527fdecf31bSYi Zou ft->name); 528fdecf31bSYi Zou rc = -ENODEV; 529fdecf31bSYi Zou goto out_attach; 530fdecf31bSYi Zou } 531fdecf31bSYi Zou 53269922fcdSYi Zou /* remove netdev mapping for this transport as it is going away */ 53369922fcdSYi Zou mutex_lock(&fn_mutex); 53469922fcdSYi Zou list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { 53569922fcdSYi Zou if (nm->ft == ft) { 53669922fcdSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s going away, " 53769922fcdSYi Zou "remove its netdev mapping for %s\n", 53869922fcdSYi Zou ft->name, nm->netdev->name); 53969922fcdSYi Zou list_del(&nm->list); 54069922fcdSYi Zou kfree(nm); 54169922fcdSYi Zou } 54269922fcdSYi Zou } 54369922fcdSYi Zou mutex_unlock(&fn_mutex); 54469922fcdSYi Zou 545fdecf31bSYi Zou list_del(&ft->list); 546fdecf31bSYi Zou ft->attached = false; 547fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name); 548fdecf31bSYi Zou 549fdecf31bSYi Zou out_attach: 550fdecf31bSYi Zou mutex_unlock(&ft_mutex); 551fdecf31bSYi Zou return rc; 552fdecf31bSYi Zou 553fdecf31bSYi Zou } 554fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_detach); 555fdecf31bSYi Zou 556fdecf31bSYi Zou static int fcoe_transport_show(char *buffer, const struct kernel_param *kp) 557fdecf31bSYi Zou { 558fdecf31bSYi Zou int i, j; 559fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 560fdecf31bSYi Zou 561fdecf31bSYi Zou i = j = sprintf(buffer, "Attached FCoE transports:"); 562fdecf31bSYi Zou mutex_lock(&ft_mutex); 563fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) { 564a01a5a57SYi Zou if (i >= PAGE_SIZE - IFNAMSIZ) 565fdecf31bSYi Zou break; 566a01a5a57SYi Zou i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); 567fdecf31bSYi Zou } 568fdecf31bSYi Zou mutex_unlock(&ft_mutex); 569fdecf31bSYi Zou if (i == j) 570fdecf31bSYi Zou i += snprintf(&buffer[i], IFNAMSIZ, "none"); 571fdecf31bSYi Zou return i; 572fdecf31bSYi Zou } 573fdecf31bSYi Zou 574fdecf31bSYi Zou static int __init fcoe_transport_init(void) 575fdecf31bSYi Zou { 57670be6344SBhanu Prakash Gollapudi register_netdevice_notifier(&libfcoe_notifier); 577fdecf31bSYi Zou return 0; 578fdecf31bSYi Zou } 579fdecf31bSYi Zou 58087098bddSMark Rustad static int fcoe_transport_exit(void) 581fdecf31bSYi Zou { 582fdecf31bSYi Zou struct fcoe_transport *ft; 583fdecf31bSYi Zou 58470be6344SBhanu Prakash Gollapudi unregister_netdevice_notifier(&libfcoe_notifier); 585fdecf31bSYi Zou mutex_lock(&ft_mutex); 586fdecf31bSYi Zou list_for_each_entry(ft, &fcoe_transports, list) 587fdecf31bSYi Zou printk(KERN_ERR "FCoE transport %s is still attached!\n", 588fdecf31bSYi Zou ft->name); 589fdecf31bSYi Zou mutex_unlock(&ft_mutex); 590fdecf31bSYi Zou return 0; 591fdecf31bSYi Zou } 592fdecf31bSYi Zou 593fdecf31bSYi Zou 594fdecf31bSYi Zou static int fcoe_add_netdev_mapping(struct net_device *netdev, 595fdecf31bSYi Zou struct fcoe_transport *ft) 596fdecf31bSYi Zou { 597fdecf31bSYi Zou struct fcoe_netdev_mapping *nm; 598fdecf31bSYi Zou 599fdecf31bSYi Zou nm = kmalloc(sizeof(*nm), GFP_KERNEL); 600fdecf31bSYi Zou if (!nm) { 601fdecf31bSYi Zou printk(KERN_ERR "Unable to allocate netdev_mapping"); 602fdecf31bSYi Zou return -ENOMEM; 603fdecf31bSYi Zou } 604fdecf31bSYi Zou 605fdecf31bSYi Zou nm->netdev = netdev; 606fdecf31bSYi Zou nm->ft = ft; 607fdecf31bSYi Zou 60870be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 609fdecf31bSYi Zou list_add(&nm->list, &fcoe_netdevs); 61070be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 611fdecf31bSYi Zou return 0; 612fdecf31bSYi Zou } 613fdecf31bSYi Zou 614fdecf31bSYi Zou 615fdecf31bSYi Zou static void fcoe_del_netdev_mapping(struct net_device *netdev) 616fdecf31bSYi Zou { 617fdecf31bSYi Zou struct fcoe_netdev_mapping *nm = NULL, *tmp; 618fdecf31bSYi Zou 61970be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 620fdecf31bSYi Zou list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { 621fdecf31bSYi Zou if (nm->netdev == netdev) { 622fdecf31bSYi Zou list_del(&nm->list); 623fdecf31bSYi Zou kfree(nm); 62470be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 625fdecf31bSYi Zou return; 626fdecf31bSYi Zou } 627fdecf31bSYi Zou } 62870be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 629fdecf31bSYi Zou } 630fdecf31bSYi Zou 631fdecf31bSYi Zou 632fdecf31bSYi Zou /** 633fdecf31bSYi Zou * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which 634fdecf31bSYi Zou * it was created 635fdecf31bSYi Zou * 636fdecf31bSYi Zou * Returns : ptr to the fcoe transport that supports this netdev or NULL 637fdecf31bSYi Zou * if not found. 638fdecf31bSYi Zou * 639fdecf31bSYi Zou * The ft_mutex should be held when this is called 640fdecf31bSYi Zou */ 641fdecf31bSYi Zou static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev) 642fdecf31bSYi Zou { 643fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 644fdecf31bSYi Zou struct fcoe_netdev_mapping *nm; 645fdecf31bSYi Zou 64670be6344SBhanu Prakash Gollapudi mutex_lock(&fn_mutex); 647fdecf31bSYi Zou list_for_each_entry(nm, &fcoe_netdevs, list) { 648fdecf31bSYi Zou if (netdev == nm->netdev) { 649fdecf31bSYi Zou ft = nm->ft; 65070be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 651fdecf31bSYi Zou return ft; 652fdecf31bSYi Zou } 653fdecf31bSYi Zou } 654fdecf31bSYi Zou 65570be6344SBhanu Prakash Gollapudi mutex_unlock(&fn_mutex); 656fdecf31bSYi Zou return NULL; 657fdecf31bSYi Zou } 658fdecf31bSYi Zou 659fdecf31bSYi Zou /** 660fdecf31bSYi Zou * fcoe_if_to_netdev() - Parse a name buffer to get a net device 661fdecf31bSYi Zou * @buffer: The name of the net device 662fdecf31bSYi Zou * 663fdecf31bSYi Zou * Returns: NULL or a ptr to net_device 664fdecf31bSYi Zou */ 665fdecf31bSYi Zou static struct net_device *fcoe_if_to_netdev(const char *buffer) 666fdecf31bSYi Zou { 667fdecf31bSYi Zou char *cp; 668fdecf31bSYi Zou char ifname[IFNAMSIZ + 2]; 669fdecf31bSYi Zou 670fdecf31bSYi Zou if (buffer) { 671fdecf31bSYi Zou strlcpy(ifname, buffer, IFNAMSIZ); 672fdecf31bSYi Zou cp = ifname + strlen(ifname); 673fdecf31bSYi Zou while (--cp >= ifname && *cp == '\n') 674fdecf31bSYi Zou *cp = '\0'; 675fdecf31bSYi Zou return dev_get_by_name(&init_net, ifname); 676fdecf31bSYi Zou } 677fdecf31bSYi Zou return NULL; 678fdecf31bSYi Zou } 679fdecf31bSYi Zou 680fdecf31bSYi Zou /** 68170be6344SBhanu Prakash Gollapudi * libfcoe_device_notification() - Handler for net device events 68270be6344SBhanu Prakash Gollapudi * @notifier: The context of the notification 68370be6344SBhanu Prakash Gollapudi * @event: The type of event 68470be6344SBhanu Prakash Gollapudi * @ptr: The net device that the event was on 68570be6344SBhanu Prakash Gollapudi * 68670be6344SBhanu Prakash Gollapudi * This function is called by the Ethernet driver in case of link change event. 68770be6344SBhanu Prakash Gollapudi * 68870be6344SBhanu Prakash Gollapudi * Returns: 0 for success 68970be6344SBhanu Prakash Gollapudi */ 69070be6344SBhanu Prakash Gollapudi static int libfcoe_device_notification(struct notifier_block *notifier, 69170be6344SBhanu Prakash Gollapudi ulong event, void *ptr) 69270be6344SBhanu Prakash Gollapudi { 69370be6344SBhanu Prakash Gollapudi struct net_device *netdev = ptr; 69470be6344SBhanu Prakash Gollapudi 69570be6344SBhanu Prakash Gollapudi switch (event) { 69670be6344SBhanu Prakash Gollapudi case NETDEV_UNREGISTER: 697b99fbf6aSRobert Love LIBFCOE_TRANSPORT_DBG("NETDEV_UNREGISTER %s\n", 69870be6344SBhanu Prakash Gollapudi netdev->name); 69970be6344SBhanu Prakash Gollapudi fcoe_del_netdev_mapping(netdev); 70070be6344SBhanu Prakash Gollapudi break; 70170be6344SBhanu Prakash Gollapudi } 70270be6344SBhanu Prakash Gollapudi return NOTIFY_OK; 70370be6344SBhanu Prakash Gollapudi } 70470be6344SBhanu Prakash Gollapudi 7056a891b07SRobert Love ssize_t fcoe_ctlr_create_store(struct bus_type *bus, 7066a891b07SRobert Love const char *buf, size_t count) 7076a891b07SRobert Love { 7086a891b07SRobert Love struct net_device *netdev = NULL; 7096a891b07SRobert Love struct fcoe_transport *ft = NULL; 7106a891b07SRobert Love int rc = 0; 7116a891b07SRobert Love int err; 7126a891b07SRobert Love 7136a891b07SRobert Love mutex_lock(&ft_mutex); 7146a891b07SRobert Love 7156a891b07SRobert Love netdev = fcoe_if_to_netdev(buf); 7166a891b07SRobert Love if (!netdev) { 7176a891b07SRobert Love LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buf); 7186a891b07SRobert Love rc = -ENODEV; 7196a891b07SRobert Love goto out_nodev; 7206a891b07SRobert Love } 7216a891b07SRobert Love 7226a891b07SRobert Love ft = fcoe_netdev_map_lookup(netdev); 7236a891b07SRobert Love if (ft) { 7246a891b07SRobert Love LIBFCOE_TRANSPORT_DBG("transport %s already has existing " 7256a891b07SRobert Love "FCoE instance on %s.\n", 7266a891b07SRobert Love ft->name, netdev->name); 7276a891b07SRobert Love rc = -EEXIST; 7286a891b07SRobert Love goto out_putdev; 7296a891b07SRobert Love } 7306a891b07SRobert Love 7316a891b07SRobert Love ft = fcoe_transport_lookup(netdev); 7326a891b07SRobert Love if (!ft) { 7336a891b07SRobert Love LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 7346a891b07SRobert Love netdev->name); 7356a891b07SRobert Love rc = -ENODEV; 7366a891b07SRobert Love goto out_putdev; 7376a891b07SRobert Love } 7386a891b07SRobert Love 7396a891b07SRobert Love /* pass to transport create */ 7406a891b07SRobert Love err = ft->alloc ? ft->alloc(netdev) : -ENODEV; 7416a891b07SRobert Love if (err) { 7426a891b07SRobert Love fcoe_del_netdev_mapping(netdev); 7436a891b07SRobert Love rc = -ENOMEM; 7446a891b07SRobert Love goto out_putdev; 7456a891b07SRobert Love } 7466a891b07SRobert Love 7476a891b07SRobert Love err = fcoe_add_netdev_mapping(netdev, ft); 7486a891b07SRobert Love if (err) { 7496a891b07SRobert Love LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping " 7506a891b07SRobert Love "for FCoE transport %s for %s.\n", 7516a891b07SRobert Love ft->name, netdev->name); 7526a891b07SRobert Love rc = -ENODEV; 7536a891b07SRobert Love goto out_putdev; 7546a891b07SRobert Love } 7556a891b07SRobert Love 756a2ceb1fbSRobert Love LIBFCOE_TRANSPORT_DBG("transport %s succeeded to create fcoe on %s.\n", 757a2ceb1fbSRobert Love ft->name, netdev->name); 7586a891b07SRobert Love 7596a891b07SRobert Love out_putdev: 7606a891b07SRobert Love dev_put(netdev); 7616a891b07SRobert Love out_nodev: 7626a891b07SRobert Love mutex_unlock(&ft_mutex); 7636a891b07SRobert Love if (rc) 7646a891b07SRobert Love return rc; 7656a891b07SRobert Love return count; 7666a891b07SRobert Love } 7676a891b07SRobert Love 7686a891b07SRobert Love ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus, 7696a891b07SRobert Love const char *buf, size_t count) 7706a891b07SRobert Love { 7716a891b07SRobert Love int rc = -ENODEV; 7726a891b07SRobert Love struct net_device *netdev = NULL; 7736a891b07SRobert Love struct fcoe_transport *ft = NULL; 7746a891b07SRobert Love 7756a891b07SRobert Love mutex_lock(&ft_mutex); 7766a891b07SRobert Love 7776a891b07SRobert Love netdev = fcoe_if_to_netdev(buf); 7786a891b07SRobert Love if (!netdev) { 7796a891b07SRobert Love LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buf); 7806a891b07SRobert Love goto out_nodev; 7816a891b07SRobert Love } 7826a891b07SRobert Love 7836a891b07SRobert Love ft = fcoe_netdev_map_lookup(netdev); 7846a891b07SRobert Love if (!ft) { 7856a891b07SRobert Love LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 7866a891b07SRobert Love netdev->name); 7876a891b07SRobert Love goto out_putdev; 7886a891b07SRobert Love } 7896a891b07SRobert Love 7906a891b07SRobert Love /* pass to transport destroy */ 7916a891b07SRobert Love rc = ft->destroy(netdev); 7926a891b07SRobert Love if (rc) 7936a891b07SRobert Love goto out_putdev; 7946a891b07SRobert Love 7956a891b07SRobert Love fcoe_del_netdev_mapping(netdev); 7966a891b07SRobert Love LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n", 7976a891b07SRobert Love ft->name, (rc) ? "failed" : "succeeded", 7986a891b07SRobert Love netdev->name); 7996a891b07SRobert Love rc = count; /* required for successful return */ 8006a891b07SRobert Love out_putdev: 8016a891b07SRobert Love dev_put(netdev); 8026a891b07SRobert Love out_nodev: 8036a891b07SRobert Love mutex_unlock(&ft_mutex); 8046a891b07SRobert Love return rc; 8056a891b07SRobert Love } 8066a891b07SRobert Love EXPORT_SYMBOL(fcoe_ctlr_destroy_store); 80770be6344SBhanu Prakash Gollapudi 80870be6344SBhanu Prakash Gollapudi /** 809fdecf31bSYi Zou * fcoe_transport_create() - Create a fcoe interface 810fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to create on 811fdecf31bSYi Zou * @kp: The associated kernel param 812fdecf31bSYi Zou * 813fdecf31bSYi Zou * Called from sysfs. This holds the ft_mutex while calling the 814fdecf31bSYi Zou * registered fcoe transport's create function. 815fdecf31bSYi Zou * 816fdecf31bSYi Zou * Returns: 0 for success 817fdecf31bSYi Zou */ 818fdecf31bSYi Zou static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) 819fdecf31bSYi Zou { 820fdecf31bSYi Zou int rc = -ENODEV; 821fdecf31bSYi Zou struct net_device *netdev = NULL; 822fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 823fdecf31bSYi Zou enum fip_state fip_mode = (enum fip_state)(long)kp->arg; 824fdecf31bSYi Zou 825b3960afeSRobert Love mutex_lock(&ft_mutex); 826b3960afeSRobert Love 827fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 828fdecf31bSYi Zou if (!netdev) { 829fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer); 830fdecf31bSYi Zou goto out_nodev; 831fdecf31bSYi Zou } 832fdecf31bSYi Zou 833fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 834fdecf31bSYi Zou if (ft) { 835fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s already has existing " 836fdecf31bSYi Zou "FCoE instance on %s.\n", 837fdecf31bSYi Zou ft->name, netdev->name); 838fdecf31bSYi Zou rc = -EEXIST; 839fdecf31bSYi Zou goto out_putdev; 840fdecf31bSYi Zou } 841fdecf31bSYi Zou 842fdecf31bSYi Zou ft = fcoe_transport_lookup(netdev); 843fdecf31bSYi Zou if (!ft) { 844fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 845fdecf31bSYi Zou netdev->name); 846fdecf31bSYi Zou goto out_putdev; 847fdecf31bSYi Zou } 848fdecf31bSYi Zou 849fdecf31bSYi Zou rc = fcoe_add_netdev_mapping(netdev, ft); 850fdecf31bSYi Zou if (rc) { 851fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping " 852fdecf31bSYi Zou "for FCoE transport %s for %s.\n", 853fdecf31bSYi Zou ft->name, netdev->name); 854fdecf31bSYi Zou goto out_putdev; 855fdecf31bSYi Zou } 856fdecf31bSYi Zou 857fdecf31bSYi Zou /* pass to transport create */ 858fdecf31bSYi Zou rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV; 859fdecf31bSYi Zou if (rc) 860fdecf31bSYi Zou fcoe_del_netdev_mapping(netdev); 861fdecf31bSYi Zou 862fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n", 863fdecf31bSYi Zou ft->name, (rc) ? "failed" : "succeeded", 864fdecf31bSYi Zou netdev->name); 865fdecf31bSYi Zou 866fdecf31bSYi Zou out_putdev: 867fdecf31bSYi Zou dev_put(netdev); 868fdecf31bSYi Zou out_nodev: 869fdecf31bSYi Zou mutex_unlock(&ft_mutex); 870fdecf31bSYi Zou return rc; 871fdecf31bSYi Zou } 872fdecf31bSYi Zou 873fdecf31bSYi Zou /** 874fdecf31bSYi Zou * fcoe_transport_destroy() - Destroy a FCoE interface 875fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be destroyed 876fdecf31bSYi Zou * @kp: The associated kernel parameter 877fdecf31bSYi Zou * 878fdecf31bSYi Zou * Called from sysfs. This holds the ft_mutex while calling the 879fdecf31bSYi Zou * registered fcoe transport's destroy function. 880fdecf31bSYi Zou * 881fdecf31bSYi Zou * Returns: 0 for success 882fdecf31bSYi Zou */ 883fdecf31bSYi Zou static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) 884fdecf31bSYi Zou { 885fdecf31bSYi Zou int rc = -ENODEV; 886fdecf31bSYi Zou struct net_device *netdev = NULL; 887fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 888fdecf31bSYi Zou 889b3960afeSRobert Love mutex_lock(&ft_mutex); 890b3960afeSRobert Love 891fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 892fdecf31bSYi Zou if (!netdev) { 893fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer); 894fdecf31bSYi Zou goto out_nodev; 895fdecf31bSYi Zou } 896fdecf31bSYi Zou 897fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 898fdecf31bSYi Zou if (!ft) { 899fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", 900fdecf31bSYi Zou netdev->name); 901fdecf31bSYi Zou goto out_putdev; 902fdecf31bSYi Zou } 903fdecf31bSYi Zou 904fdecf31bSYi Zou /* pass to transport destroy */ 905fdecf31bSYi Zou rc = ft->destroy ? ft->destroy(netdev) : -ENODEV; 906fdecf31bSYi Zou fcoe_del_netdev_mapping(netdev); 907fdecf31bSYi Zou LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n", 908fdecf31bSYi Zou ft->name, (rc) ? "failed" : "succeeded", 909fdecf31bSYi Zou netdev->name); 910fdecf31bSYi Zou 911fdecf31bSYi Zou out_putdev: 912fdecf31bSYi Zou dev_put(netdev); 913fdecf31bSYi Zou out_nodev: 914fdecf31bSYi Zou mutex_unlock(&ft_mutex); 915fdecf31bSYi Zou return rc; 916fdecf31bSYi Zou } 917fdecf31bSYi Zou 918fdecf31bSYi Zou /** 919fdecf31bSYi Zou * fcoe_transport_disable() - Disables a FCoE interface 920fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be disabled 921fdecf31bSYi Zou * @kp: The associated kernel parameter 922fdecf31bSYi Zou * 923fdecf31bSYi Zou * Called from sysfs. 924fdecf31bSYi Zou * 925fdecf31bSYi Zou * Returns: 0 for success 926fdecf31bSYi Zou */ 927fdecf31bSYi Zou static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) 928fdecf31bSYi Zou { 929fdecf31bSYi Zou int rc = -ENODEV; 930fdecf31bSYi Zou struct net_device *netdev = NULL; 931fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 932fdecf31bSYi Zou 933b3960afeSRobert Love mutex_lock(&ft_mutex); 934b3960afeSRobert Love 935fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 936fdecf31bSYi Zou if (!netdev) 937fdecf31bSYi Zou goto out_nodev; 938fdecf31bSYi Zou 939fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 940fdecf31bSYi Zou if (!ft) 941fdecf31bSYi Zou goto out_putdev; 942fdecf31bSYi Zou 943fdecf31bSYi Zou rc = ft->disable ? ft->disable(netdev) : -ENODEV; 944fdecf31bSYi Zou 945fdecf31bSYi Zou out_putdev: 946fdecf31bSYi Zou dev_put(netdev); 947fdecf31bSYi Zou out_nodev: 948fdecf31bSYi Zou mutex_unlock(&ft_mutex); 949fdecf31bSYi Zou return rc; 950fdecf31bSYi Zou } 951fdecf31bSYi Zou 952fdecf31bSYi Zou /** 953fdecf31bSYi Zou * fcoe_transport_enable() - Enables a FCoE interface 954fdecf31bSYi Zou * @buffer: The name of the Ethernet interface to be enabled 955fdecf31bSYi Zou * @kp: The associated kernel parameter 956fdecf31bSYi Zou * 957fdecf31bSYi Zou * Called from sysfs. 958fdecf31bSYi Zou * 959fdecf31bSYi Zou * Returns: 0 for success 960fdecf31bSYi Zou */ 961fdecf31bSYi Zou static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) 962fdecf31bSYi Zou { 963fdecf31bSYi Zou int rc = -ENODEV; 964fdecf31bSYi Zou struct net_device *netdev = NULL; 965fdecf31bSYi Zou struct fcoe_transport *ft = NULL; 966fdecf31bSYi Zou 967b3960afeSRobert Love mutex_lock(&ft_mutex); 968b3960afeSRobert Love 969fdecf31bSYi Zou netdev = fcoe_if_to_netdev(buffer); 970fdecf31bSYi Zou if (!netdev) 971fdecf31bSYi Zou goto out_nodev; 972fdecf31bSYi Zou 973fdecf31bSYi Zou ft = fcoe_netdev_map_lookup(netdev); 974fdecf31bSYi Zou if (!ft) 975fdecf31bSYi Zou goto out_putdev; 976fdecf31bSYi Zou 977fdecf31bSYi Zou rc = ft->enable ? ft->enable(netdev) : -ENODEV; 978fdecf31bSYi Zou 979fdecf31bSYi Zou out_putdev: 980fdecf31bSYi Zou dev_put(netdev); 981fdecf31bSYi Zou out_nodev: 982fdecf31bSYi Zou mutex_unlock(&ft_mutex); 983fdecf31bSYi Zou return rc; 984fdecf31bSYi Zou } 985fdecf31bSYi Zou 986fdecf31bSYi Zou /** 987fdecf31bSYi Zou * libfcoe_init() - Initialization routine for libfcoe.ko 988fdecf31bSYi Zou */ 989fdecf31bSYi Zou static int __init libfcoe_init(void) 990fdecf31bSYi Zou { 9919a74e884SRobert Love int rc = 0; 992fdecf31bSYi Zou 9939a74e884SRobert Love rc = fcoe_transport_init(); 9949a74e884SRobert Love if (rc) 9959a74e884SRobert Love return rc; 9969a74e884SRobert Love 9979a74e884SRobert Love rc = fcoe_sysfs_setup(); 9989a74e884SRobert Love if (rc) 9999a74e884SRobert Love fcoe_transport_exit(); 10009a74e884SRobert Love 10019a74e884SRobert Love return rc; 1002fdecf31bSYi Zou } 1003fdecf31bSYi Zou module_init(libfcoe_init); 1004fdecf31bSYi Zou 1005fdecf31bSYi Zou /** 1006fdecf31bSYi Zou * libfcoe_exit() - Tear down libfcoe.ko 1007fdecf31bSYi Zou */ 1008fdecf31bSYi Zou static void __exit libfcoe_exit(void) 1009fdecf31bSYi Zou { 10109a74e884SRobert Love fcoe_sysfs_teardown(); 1011fdecf31bSYi Zou fcoe_transport_exit(); 1012fdecf31bSYi Zou } 1013fdecf31bSYi Zou module_exit(libfcoe_exit); 1014