1a703e490SVasu Dev /* 2af7f85d9SChris Leech * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. 3a703e490SVasu Dev * 4a703e490SVasu Dev * This program is free software; you can redistribute it and/or modify it 5a703e490SVasu Dev * under the terms and conditions of the GNU General Public License, 6a703e490SVasu Dev * version 2, as published by the Free Software Foundation. 7a703e490SVasu Dev * 8a703e490SVasu Dev * This program is distributed in the hope it will be useful, but WITHOUT 9a703e490SVasu Dev * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10a703e490SVasu Dev * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11a703e490SVasu Dev * more details. 12a703e490SVasu Dev * 13a703e490SVasu Dev * You should have received a copy of the GNU General Public License along with 14a703e490SVasu Dev * this program; if not, write to the Free Software Foundation, Inc., 15a703e490SVasu Dev * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16a703e490SVasu Dev * 17a703e490SVasu Dev * Maintained at www.Open-FCoE.org 18a703e490SVasu Dev */ 19a703e490SVasu Dev 20a703e490SVasu Dev #include <linux/module.h> 21a703e490SVasu Dev #include <linux/version.h> 22a703e490SVasu Dev #include <linux/spinlock.h> 23a703e490SVasu Dev #include <linux/netdevice.h> 24a703e490SVasu Dev #include <linux/etherdevice.h> 25a703e490SVasu Dev #include <linux/ethtool.h> 26a703e490SVasu Dev #include <linux/if_ether.h> 27a703e490SVasu Dev #include <linux/if_vlan.h> 28a703e490SVasu Dev #include <linux/crc32.h> 29a703e490SVasu Dev #include <linux/cpu.h> 30a703e490SVasu Dev #include <linux/fs.h> 31a703e490SVasu Dev #include <linux/sysfs.h> 32a703e490SVasu Dev #include <linux/ctype.h> 33a703e490SVasu Dev #include <scsi/scsi_tcq.h> 34a703e490SVasu Dev #include <scsi/scsicam.h> 35a703e490SVasu Dev #include <scsi/scsi_transport.h> 36a703e490SVasu Dev #include <scsi/scsi_transport_fc.h> 37a703e490SVasu Dev #include <net/rtnetlink.h> 38a703e490SVasu Dev 39a703e490SVasu Dev #include <scsi/fc/fc_encaps.h> 4097c8389dSJoe Eykholt #include <scsi/fc/fc_fip.h> 41a703e490SVasu Dev 42a703e490SVasu Dev #include <scsi/libfc.h> 43a703e490SVasu Dev #include <scsi/fc_frame.h> 44a703e490SVasu Dev #include <scsi/libfcoe.h> 45a703e490SVasu Dev 46fdd78027SVasu Dev #include "fcoe.h" 47fdd78027SVasu Dev 48a703e490SVasu Dev MODULE_AUTHOR("Open-FCoE.org"); 49a703e490SVasu Dev MODULE_DESCRIPTION("FCoE"); 509b34ecffSVasu Dev MODULE_LICENSE("GPL v2"); 51a703e490SVasu Dev 5205cc7390SYi Zou /* Performance tuning parameters for fcoe */ 5305cc7390SYi Zou static unsigned int fcoe_ddp_min; 5405cc7390SYi Zou module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR); 5505cc7390SYi Zou MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ 5605cc7390SYi Zou "Direct Data Placement (DDP)."); 5705cc7390SYi Zou 58a703e490SVasu Dev /* fcoe host list */ 59a703e490SVasu Dev LIST_HEAD(fcoe_hostlist); 60a703e490SVasu Dev DEFINE_RWLOCK(fcoe_hostlist_lock); 61a703e490SVasu Dev DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); 62a703e490SVasu Dev 63dd3fd72eSChris Leech /* Function Prototypes */ 64fdd78027SVasu Dev static int fcoe_reset(struct Scsi_Host *shost); 65fdd78027SVasu Dev static int fcoe_xmit(struct fc_lport *, struct fc_frame *); 66fdd78027SVasu Dev static int fcoe_rcv(struct sk_buff *, struct net_device *, 67fdd78027SVasu Dev struct packet_type *, struct net_device *); 68fdd78027SVasu Dev static int fcoe_percpu_receive_thread(void *arg); 69fdd78027SVasu Dev static void fcoe_clean_pending_queue(struct fc_lport *lp); 70fdd78027SVasu Dev static void fcoe_percpu_clean(struct fc_lport *lp); 71fdd78027SVasu Dev static int fcoe_link_ok(struct fc_lport *lp); 72fdd78027SVasu Dev 73fdd78027SVasu Dev static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); 74fdd78027SVasu Dev static int fcoe_hostlist_add(const struct fc_lport *); 75fdd78027SVasu Dev static int fcoe_hostlist_remove(const struct fc_lport *); 76fdd78027SVasu Dev 774bb6b515SVasu Dev static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *); 78a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *, ulong, void *); 79a703e490SVasu Dev static void fcoe_dev_setup(void); 80a703e490SVasu Dev static void fcoe_dev_cleanup(void); 81a703e490SVasu Dev 82a703e490SVasu Dev /* notification function from net device */ 83a703e490SVasu Dev static struct notifier_block fcoe_notifier = { 84a703e490SVasu Dev .notifier_call = fcoe_device_notification, 85a703e490SVasu Dev }; 86a703e490SVasu Dev 87a703e490SVasu Dev static struct scsi_transport_template *scsi_transport_fcoe_sw; 88a703e490SVasu Dev 89a703e490SVasu Dev struct fc_function_template fcoe_transport_function = { 90a703e490SVasu Dev .show_host_node_name = 1, 91a703e490SVasu Dev .show_host_port_name = 1, 92a703e490SVasu Dev .show_host_supported_classes = 1, 93a703e490SVasu Dev .show_host_supported_fc4s = 1, 94a703e490SVasu Dev .show_host_active_fc4s = 1, 95a703e490SVasu Dev .show_host_maxframe_size = 1, 96a703e490SVasu Dev 97a703e490SVasu Dev .show_host_port_id = 1, 98a703e490SVasu Dev .show_host_supported_speeds = 1, 99a703e490SVasu Dev .get_host_speed = fc_get_host_speed, 100a703e490SVasu Dev .show_host_speed = 1, 101a703e490SVasu Dev .show_host_port_type = 1, 102a703e490SVasu Dev .get_host_port_state = fc_get_host_port_state, 103a703e490SVasu Dev .show_host_port_state = 1, 104a703e490SVasu Dev .show_host_symbolic_name = 1, 105a703e490SVasu Dev 106a703e490SVasu Dev .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), 107a703e490SVasu Dev .show_rport_maxframe_size = 1, 108a703e490SVasu Dev .show_rport_supported_classes = 1, 109a703e490SVasu Dev 110a703e490SVasu Dev .show_host_fabric_name = 1, 111a703e490SVasu Dev .show_starget_node_name = 1, 112a703e490SVasu Dev .show_starget_port_name = 1, 113a703e490SVasu Dev .show_starget_port_id = 1, 114a703e490SVasu Dev .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 115a703e490SVasu Dev .show_rport_dev_loss_tmo = 1, 116a703e490SVasu Dev .get_fc_host_stats = fc_get_host_stats, 117a703e490SVasu Dev .issue_fc_host_lip = fcoe_reset, 118a703e490SVasu Dev 119a703e490SVasu Dev .terminate_rport_io = fc_rport_terminate_io, 120a703e490SVasu Dev }; 121a703e490SVasu Dev 122a703e490SVasu Dev static struct scsi_host_template fcoe_shost_template = { 123a703e490SVasu Dev .module = THIS_MODULE, 124a703e490SVasu Dev .name = "FCoE Driver", 125a703e490SVasu Dev .proc_name = FCOE_NAME, 126a703e490SVasu Dev .queuecommand = fc_queuecommand, 127a703e490SVasu Dev .eh_abort_handler = fc_eh_abort, 128a703e490SVasu Dev .eh_device_reset_handler = fc_eh_device_reset, 129a703e490SVasu Dev .eh_host_reset_handler = fc_eh_host_reset, 130a703e490SVasu Dev .slave_alloc = fc_slave_alloc, 131a703e490SVasu Dev .change_queue_depth = fc_change_queue_depth, 132a703e490SVasu Dev .change_queue_type = fc_change_queue_type, 133a703e490SVasu Dev .this_id = -1, 134a703e490SVasu Dev .cmd_per_lun = 32, 135a703e490SVasu Dev .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, 136a703e490SVasu Dev .use_clustering = ENABLE_CLUSTERING, 137a703e490SVasu Dev .sg_tablesize = SG_ALL, 138a703e490SVasu Dev .max_sectors = 0xffff, 139a703e490SVasu Dev }; 140a703e490SVasu Dev 141a703e490SVasu Dev /** 142ab6b85c1SVasu Dev * fcoe_fip_recv - handle a received FIP frame. 143ab6b85c1SVasu Dev * @skb: the receive skb 144ab6b85c1SVasu Dev * @dev: associated &net_device 145ab6b85c1SVasu Dev * @ptype: the &packet_type structure which was used to register this handler. 146ab6b85c1SVasu Dev * @orig_dev: original receive &net_device, in case @dev is a bond. 147ab6b85c1SVasu Dev * 148ab6b85c1SVasu Dev * Returns: 0 for success 149ab6b85c1SVasu Dev */ 150ab6b85c1SVasu Dev static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, 151ab6b85c1SVasu Dev struct packet_type *ptype, 152ab6b85c1SVasu Dev struct net_device *orig_dev) 153ab6b85c1SVasu Dev { 154ab6b85c1SVasu Dev struct fcoe_softc *fc; 155ab6b85c1SVasu Dev 156ab6b85c1SVasu Dev fc = container_of(ptype, struct fcoe_softc, fip_packet_type); 157ab6b85c1SVasu Dev fcoe_ctlr_recv(&fc->ctlr, skb); 158ab6b85c1SVasu Dev return 0; 159ab6b85c1SVasu Dev } 160ab6b85c1SVasu Dev 161ab6b85c1SVasu Dev /** 162ab6b85c1SVasu Dev * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame. 163ab6b85c1SVasu Dev * @fip: FCoE controller. 164ab6b85c1SVasu Dev * @skb: FIP Packet. 165ab6b85c1SVasu Dev */ 166ab6b85c1SVasu Dev static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) 167ab6b85c1SVasu Dev { 1681d1b88dcSVasu Dev skb->dev = fcoe_from_ctlr(fip)->netdev; 169ab6b85c1SVasu Dev dev_queue_xmit(skb); 170ab6b85c1SVasu Dev } 171ab6b85c1SVasu Dev 172ab6b85c1SVasu Dev /** 173ab6b85c1SVasu Dev * fcoe_update_src_mac() - Update Ethernet MAC filters. 174ab6b85c1SVasu Dev * @fip: FCoE controller. 175ab6b85c1SVasu Dev * @old: Unicast MAC address to delete if the MAC is non-zero. 176ab6b85c1SVasu Dev * @new: Unicast MAC address to add. 177ab6b85c1SVasu Dev * 178ab6b85c1SVasu Dev * Remove any previously-set unicast MAC filter. 179ab6b85c1SVasu Dev * Add secondary FCoE MAC address filter for our OUI. 180ab6b85c1SVasu Dev */ 181ab6b85c1SVasu Dev static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) 182ab6b85c1SVasu Dev { 183ab6b85c1SVasu Dev struct fcoe_softc *fc; 184ab6b85c1SVasu Dev 185ab6b85c1SVasu Dev fc = fcoe_from_ctlr(fip); 186ab6b85c1SVasu Dev rtnl_lock(); 187ab6b85c1SVasu Dev if (!is_zero_ether_addr(old)) 1881d1b88dcSVasu Dev dev_unicast_delete(fc->netdev, old); 1891d1b88dcSVasu Dev dev_unicast_add(fc->netdev, new); 190ab6b85c1SVasu Dev rtnl_unlock(); 191ab6b85c1SVasu Dev } 192ab6b85c1SVasu Dev 193ab6b85c1SVasu Dev /** 194a703e490SVasu Dev * fcoe_lport_config() - sets up the fc_lport 195a703e490SVasu Dev * @lp: ptr to the fc_lport 196a703e490SVasu Dev * 197a703e490SVasu Dev * Returns: 0 for success 198a703e490SVasu Dev */ 199a703e490SVasu Dev static int fcoe_lport_config(struct fc_lport *lp) 200a703e490SVasu Dev { 201a703e490SVasu Dev lp->link_up = 0; 202a703e490SVasu Dev lp->qfull = 0; 203a703e490SVasu Dev lp->max_retry_count = 3; 204a3666955SAbhijeet Joglekar lp->max_rport_retry_count = 3; 205a703e490SVasu Dev lp->e_d_tov = 2 * 1000; /* FC-FS default */ 206a703e490SVasu Dev lp->r_a_tov = 2 * 2 * 1000; 207a703e490SVasu Dev lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | 208a703e490SVasu Dev FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); 209a703e490SVasu Dev 210a703e490SVasu Dev fc_lport_init_stats(lp); 211a703e490SVasu Dev 212a703e490SVasu Dev /* lport fc_lport related configuration */ 213a703e490SVasu Dev fc_lport_config(lp); 214a703e490SVasu Dev 215a703e490SVasu Dev /* offload related configuration */ 216a703e490SVasu Dev lp->crc_offload = 0; 217a703e490SVasu Dev lp->seq_offload = 0; 218a703e490SVasu Dev lp->lro_enabled = 0; 219a703e490SVasu Dev lp->lro_xid = 0; 220a703e490SVasu Dev lp->lso_max = 0; 221a703e490SVasu Dev 222a703e490SVasu Dev return 0; 223a703e490SVasu Dev } 224a703e490SVasu Dev 225a703e490SVasu Dev /** 226ab6b85c1SVasu Dev * fcoe_netdev_cleanup() - clean up netdev configurations 227ab6b85c1SVasu Dev * @fc: ptr to the fcoe_softc 228ab6b85c1SVasu Dev */ 229ab6b85c1SVasu Dev void fcoe_netdev_cleanup(struct fcoe_softc *fc) 230ab6b85c1SVasu Dev { 231ab6b85c1SVasu Dev u8 flogi_maddr[ETH_ALEN]; 232ab6b85c1SVasu Dev 233ab6b85c1SVasu Dev /* Don't listen for Ethernet packets anymore */ 234ab6b85c1SVasu Dev dev_remove_pack(&fc->fcoe_packet_type); 235ab6b85c1SVasu Dev dev_remove_pack(&fc->fip_packet_type); 236ab6b85c1SVasu Dev 237ab6b85c1SVasu Dev /* Delete secondary MAC addresses */ 238ab6b85c1SVasu Dev rtnl_lock(); 239ab6b85c1SVasu Dev memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); 2401d1b88dcSVasu Dev dev_unicast_delete(fc->netdev, flogi_maddr); 241ab6b85c1SVasu Dev if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) 2421d1b88dcSVasu Dev dev_unicast_delete(fc->netdev, fc->ctlr.data_src_addr); 243184dd345SVasu Dev if (fc->ctlr.spma) 2441d1b88dcSVasu Dev dev_unicast_delete(fc->netdev, fc->ctlr.ctl_src_addr); 2451d1b88dcSVasu Dev dev_mc_delete(fc->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); 246ab6b85c1SVasu Dev rtnl_unlock(); 247ab6b85c1SVasu Dev } 248ab6b85c1SVasu Dev 249ab6b85c1SVasu Dev /** 2501047f221SVasu Dev * fcoe_queue_timer() - fcoe queue timer 2511047f221SVasu Dev * @lp: the fc_lport pointer 2521047f221SVasu Dev * 2531047f221SVasu Dev * Calls fcoe_check_wait_queue on timeout 2541047f221SVasu Dev * 2551047f221SVasu Dev */ 2561047f221SVasu Dev static void fcoe_queue_timer(ulong lp) 2571047f221SVasu Dev { 2581047f221SVasu Dev fcoe_check_wait_queue((struct fc_lport *)lp, NULL); 2591047f221SVasu Dev } 2601047f221SVasu Dev 2611047f221SVasu Dev /** 262a703e490SVasu Dev * fcoe_netdev_config() - Set up netdev for SW FCoE 263a703e490SVasu Dev * @lp : ptr to the fc_lport 264a703e490SVasu Dev * @netdev : ptr to the associated netdevice struct 265a703e490SVasu Dev * 266a703e490SVasu Dev * Must be called after fcoe_lport_config() as it will use lport mutex 267a703e490SVasu Dev * 268a703e490SVasu Dev * Returns : 0 for success 269a703e490SVasu Dev */ 270a703e490SVasu Dev static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) 271a703e490SVasu Dev { 272a703e490SVasu Dev u32 mfs; 273a703e490SVasu Dev u64 wwnn, wwpn; 274a703e490SVasu Dev struct fcoe_softc *fc; 275a703e490SVasu Dev u8 flogi_maddr[ETH_ALEN]; 276184dd345SVasu Dev struct netdev_hw_addr *ha; 277a703e490SVasu Dev 278a703e490SVasu Dev /* Setup lport private data to point to fcoe softc */ 279a703e490SVasu Dev fc = lport_priv(lp); 28097c8389dSJoe Eykholt fc->ctlr.lp = lp; 2811d1b88dcSVasu Dev fc->netdev = netdev; 282a703e490SVasu Dev 283a703e490SVasu Dev /* Do not support for bonding device */ 2841d1b88dcSVasu Dev if ((netdev->priv_flags & IFF_MASTER_ALB) || 2851d1b88dcSVasu Dev (netdev->priv_flags & IFF_SLAVE_INACTIVE) || 2861d1b88dcSVasu Dev (netdev->priv_flags & IFF_MASTER_8023AD)) { 287a703e490SVasu Dev return -EOPNOTSUPP; 288a703e490SVasu Dev } 289a703e490SVasu Dev 290a703e490SVasu Dev /* 291a703e490SVasu Dev * Determine max frame size based on underlying device and optional 292a703e490SVasu Dev * user-configured limit. If the MFS is too low, fcoe_link_ok() 293a703e490SVasu Dev * will return 0, so do this first. 294a703e490SVasu Dev */ 2951d1b88dcSVasu Dev mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + 296a703e490SVasu Dev sizeof(struct fcoe_crc_eof)); 297a703e490SVasu Dev if (fc_set_mfs(lp, mfs)) 298a703e490SVasu Dev return -EINVAL; 299a703e490SVasu Dev 300a703e490SVasu Dev /* offload features support */ 3011d1b88dcSVasu Dev if (netdev->features & NETIF_F_SG) 302a703e490SVasu Dev lp->sg_supp = 1; 303a703e490SVasu Dev 304a703e490SVasu Dev if (netdev->features & NETIF_F_FCOE_CRC) { 305a703e490SVasu Dev lp->crc_offload = 1; 306d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); 307a703e490SVasu Dev } 308a703e490SVasu Dev if (netdev->features & NETIF_F_FSO) { 309a703e490SVasu Dev lp->seq_offload = 1; 310a703e490SVasu Dev lp->lso_max = netdev->gso_max_size; 311d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", 312d5488eb9SRobert Love lp->lso_max); 313a703e490SVasu Dev } 314a703e490SVasu Dev if (netdev->fcoe_ddp_xid) { 315a703e490SVasu Dev lp->lro_enabled = 1; 316a703e490SVasu Dev lp->lro_xid = netdev->fcoe_ddp_xid; 317d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", 318d5488eb9SRobert Love lp->lro_xid); 319a703e490SVasu Dev } 320a703e490SVasu Dev skb_queue_head_init(&fc->fcoe_pending_queue); 321a703e490SVasu Dev fc->fcoe_pending_queue_active = 0; 3221047f221SVasu Dev setup_timer(&fc->timer, fcoe_queue_timer, (unsigned long)lp); 323a703e490SVasu Dev 324184dd345SVasu Dev /* look for SAN MAC address, if multiple SAN MACs exist, only 325184dd345SVasu Dev * use the first one for SPMA */ 326184dd345SVasu Dev rcu_read_lock(); 327184dd345SVasu Dev for_each_dev_addr(netdev, ha) { 328184dd345SVasu Dev if ((ha->type == NETDEV_HW_ADDR_T_SAN) && 3297a7f0c7fSYi Zou (is_valid_ether_addr(ha->addr))) { 330184dd345SVasu Dev memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); 331184dd345SVasu Dev fc->ctlr.spma = 1; 332184dd345SVasu Dev break; 333184dd345SVasu Dev } 334184dd345SVasu Dev } 335184dd345SVasu Dev rcu_read_unlock(); 336184dd345SVasu Dev 337a703e490SVasu Dev /* setup Source Mac Address */ 338184dd345SVasu Dev if (!fc->ctlr.spma) 3391d1b88dcSVasu Dev memcpy(fc->ctlr.ctl_src_addr, netdev->dev_addr, 3401d1b88dcSVasu Dev fc->netdev->addr_len); 341a703e490SVasu Dev 3421d1b88dcSVasu Dev wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0); 343a703e490SVasu Dev fc_set_wwnn(lp, wwnn); 344a703e490SVasu Dev /* XXX - 3rd arg needs to be vlan id */ 3451d1b88dcSVasu Dev wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0); 346a703e490SVasu Dev fc_set_wwpn(lp, wwpn); 347a703e490SVasu Dev 348a703e490SVasu Dev /* 349a703e490SVasu Dev * Add FCoE MAC address as second unicast MAC address 350a703e490SVasu Dev * or enter promiscuous mode if not capable of listening 351a703e490SVasu Dev * for multiple unicast MACs. 352a703e490SVasu Dev */ 353a703e490SVasu Dev rtnl_lock(); 354a703e490SVasu Dev memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); 3551d1b88dcSVasu Dev dev_unicast_add(netdev, flogi_maddr); 356184dd345SVasu Dev if (fc->ctlr.spma) 3571d1b88dcSVasu Dev dev_unicast_add(netdev, fc->ctlr.ctl_src_addr); 3581d1b88dcSVasu Dev dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); 359a703e490SVasu Dev rtnl_unlock(); 360a703e490SVasu Dev 361a703e490SVasu Dev /* 362a703e490SVasu Dev * setup the receive function from ethernet driver 363a703e490SVasu Dev * on the ethertype for the given device 364a703e490SVasu Dev */ 365a703e490SVasu Dev fc->fcoe_packet_type.func = fcoe_rcv; 366a703e490SVasu Dev fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); 3671d1b88dcSVasu Dev fc->fcoe_packet_type.dev = netdev; 368a703e490SVasu Dev dev_add_pack(&fc->fcoe_packet_type); 369a703e490SVasu Dev 370ab6b85c1SVasu Dev fc->fip_packet_type.func = fcoe_fip_recv; 371ab6b85c1SVasu Dev fc->fip_packet_type.type = htons(ETH_P_FIP); 3721d1b88dcSVasu Dev fc->fip_packet_type.dev = netdev; 373ab6b85c1SVasu Dev dev_add_pack(&fc->fip_packet_type); 374ab6b85c1SVasu Dev 375a703e490SVasu Dev return 0; 376a703e490SVasu Dev } 377a703e490SVasu Dev 378a703e490SVasu Dev /** 379a703e490SVasu Dev * fcoe_shost_config() - Sets up fc_lport->host 380a703e490SVasu Dev * @lp : ptr to the fc_lport 381a703e490SVasu Dev * @shost : ptr to the associated scsi host 382a703e490SVasu Dev * @dev : device associated to scsi host 383a703e490SVasu Dev * 384a703e490SVasu Dev * Must be called after fcoe_lport_config() and fcoe_netdev_config() 385a703e490SVasu Dev * 386a703e490SVasu Dev * Returns : 0 for success 387a703e490SVasu Dev */ 388a703e490SVasu Dev static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, 389a703e490SVasu Dev struct device *dev) 390a703e490SVasu Dev { 391a703e490SVasu Dev int rc = 0; 392a703e490SVasu Dev 393a703e490SVasu Dev /* lport scsi host config */ 394a703e490SVasu Dev lp->host = shost; 395a703e490SVasu Dev 396a703e490SVasu Dev lp->host->max_lun = FCOE_MAX_LUN; 397a703e490SVasu Dev lp->host->max_id = FCOE_MAX_FCP_TARGET; 398a703e490SVasu Dev lp->host->max_channel = 0; 399a703e490SVasu Dev lp->host->transportt = scsi_transport_fcoe_sw; 400a703e490SVasu Dev 401a703e490SVasu Dev /* add the new host to the SCSI-ml */ 402a703e490SVasu Dev rc = scsi_add_host(lp->host, dev); 403a703e490SVasu Dev if (rc) { 404d5488eb9SRobert Love FCOE_NETDEV_DBG(fcoe_netdev(lp), "fcoe_shost_config: " 405d5488eb9SRobert Love "error on scsi_add_host\n"); 406a703e490SVasu Dev return rc; 407a703e490SVasu Dev } 408a703e490SVasu Dev sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", 409a703e490SVasu Dev FCOE_NAME, FCOE_VERSION, 410a703e490SVasu Dev fcoe_netdev(lp)->name); 411a703e490SVasu Dev 412a703e490SVasu Dev return 0; 413a703e490SVasu Dev } 414a703e490SVasu Dev 415d7179680SVasu Dev /* 416d7179680SVasu Dev * fcoe_oem_match() - match for read types IO 417d7179680SVasu Dev * @fp: the fc_frame for new IO. 418d7179680SVasu Dev * 419d7179680SVasu Dev * Returns : true for read types IO, otherwise returns false. 420d7179680SVasu Dev */ 421d7179680SVasu Dev bool fcoe_oem_match(struct fc_frame *fp) 422d7179680SVasu Dev { 42305cc7390SYi Zou return fc_fcp_is_read(fr_fsp(fp)) && 42405cc7390SYi Zou (fr_fsp(fp)->data_len > fcoe_ddp_min); 425d7179680SVasu Dev } 426d7179680SVasu Dev 427a703e490SVasu Dev /** 428a703e490SVasu Dev * fcoe_em_config() - allocates em for this lport 429a703e490SVasu Dev * @lp: the port that em is to allocated for 430a703e490SVasu Dev * 431e8af4d43SVasu Dev * Called with write fcoe_hostlist_lock held. 432e8af4d43SVasu Dev * 433a703e490SVasu Dev * Returns : 0 on success 434a703e490SVasu Dev */ 435a703e490SVasu Dev static inline int fcoe_em_config(struct fc_lport *lp) 436a703e490SVasu Dev { 437d7179680SVasu Dev struct fcoe_softc *fc = lport_priv(lp); 438d7179680SVasu Dev struct fcoe_softc *oldfc = NULL; 4391d1b88dcSVasu Dev struct net_device *old_real_dev, *cur_real_dev; 440d7179680SVasu Dev u16 min_xid = FCOE_MIN_XID; 441d7179680SVasu Dev u16 max_xid = FCOE_MAX_XID; 442d7179680SVasu Dev 443d7179680SVasu Dev /* 444d7179680SVasu Dev * Check if need to allocate an em instance for 445d7179680SVasu Dev * offload exchange ids to be shared across all VN_PORTs/lport. 446d7179680SVasu Dev */ 447d7179680SVasu Dev if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= max_xid)) { 448d7179680SVasu Dev lp->lro_xid = 0; 449d7179680SVasu Dev goto skip_oem; 450d7179680SVasu Dev } 451d7179680SVasu Dev 452d7179680SVasu Dev /* 453d7179680SVasu Dev * Reuse existing offload em instance in case 4541d1b88dcSVasu Dev * it is already allocated on real eth device 455d7179680SVasu Dev */ 4561d1b88dcSVasu Dev if (fc->netdev->priv_flags & IFF_802_1Q_VLAN) 4571d1b88dcSVasu Dev cur_real_dev = vlan_dev_real_dev(fc->netdev); 4581d1b88dcSVasu Dev else 4591d1b88dcSVasu Dev cur_real_dev = fc->netdev; 4601d1b88dcSVasu Dev 461d7179680SVasu Dev list_for_each_entry(oldfc, &fcoe_hostlist, list) { 4621d1b88dcSVasu Dev if (oldfc->netdev->priv_flags & IFF_802_1Q_VLAN) 4631d1b88dcSVasu Dev old_real_dev = vlan_dev_real_dev(oldfc->netdev); 4641d1b88dcSVasu Dev else 4651d1b88dcSVasu Dev old_real_dev = oldfc->netdev; 4661d1b88dcSVasu Dev 4671d1b88dcSVasu Dev if (cur_real_dev == old_real_dev) { 468d7179680SVasu Dev fc->oem = oldfc->oem; 469d7179680SVasu Dev break; 470d7179680SVasu Dev } 471d7179680SVasu Dev } 472d7179680SVasu Dev 473d7179680SVasu Dev if (fc->oem) { 474d7179680SVasu Dev if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) { 475d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to add " 476d7179680SVasu Dev "offload em:%p on interface:%s\n", 4771d1b88dcSVasu Dev fc->oem, fc->netdev->name); 478a703e490SVasu Dev return -ENOMEM; 479d7179680SVasu Dev } 480d7179680SVasu Dev } else { 481d7179680SVasu Dev fc->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3, 482d7179680SVasu Dev FCOE_MIN_XID, lp->lro_xid, 483d7179680SVasu Dev fcoe_oem_match); 484d7179680SVasu Dev if (!fc->oem) { 485d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to allocate " 486d7179680SVasu Dev "em for offload exches on interface:%s\n", 4871d1b88dcSVasu Dev fc->netdev->name); 488d7179680SVasu Dev return -ENOMEM; 489d7179680SVasu Dev } 490d7179680SVasu Dev } 491d7179680SVasu Dev 492d7179680SVasu Dev /* 493d7179680SVasu Dev * Exclude offload EM xid range from next EM xid range. 494d7179680SVasu Dev */ 495d7179680SVasu Dev min_xid += lp->lro_xid + 1; 496d7179680SVasu Dev 497d7179680SVasu Dev skip_oem: 498d7179680SVasu Dev if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) { 499d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to " 5001d1b88dcSVasu Dev "allocate em on interface %s\n", fc->netdev->name); 501d7179680SVasu Dev return -ENOMEM; 502d7179680SVasu Dev } 503a703e490SVasu Dev 504a703e490SVasu Dev return 0; 505a703e490SVasu Dev } 506a703e490SVasu Dev 507a703e490SVasu Dev /** 508a703e490SVasu Dev * fcoe_if_destroy() - FCoE software HBA tear-down function 509af7f85d9SChris Leech * @lport: fc_lport to destroy 510a703e490SVasu Dev */ 511af7f85d9SChris Leech static void fcoe_if_destroy(struct fc_lport *lport) 512a703e490SVasu Dev { 513af7f85d9SChris Leech struct fcoe_softc *fc = lport_priv(lport); 514af7f85d9SChris Leech struct net_device *netdev = fc->netdev; 515a703e490SVasu Dev 516d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); 517a703e490SVasu Dev 518a703e490SVasu Dev /* Logout of the fabric */ 519af7f85d9SChris Leech fc_fabric_logoff(lport); 520a703e490SVasu Dev 521a703e490SVasu Dev /* Remove the instance from fcoe's list */ 522af7f85d9SChris Leech fcoe_hostlist_remove(lport); 523a703e490SVasu Dev 524ab6b85c1SVasu Dev /* clean up netdev configurations */ 525ab6b85c1SVasu Dev fcoe_netdev_cleanup(fc); 526ab6b85c1SVasu Dev 527ab6b85c1SVasu Dev /* tear-down the FCoE controller */ 52897c8389dSJoe Eykholt fcoe_ctlr_destroy(&fc->ctlr); 529a703e490SVasu Dev 530f161fb72SJoe Eykholt /* Free queued packets for the per-CPU receive threads */ 531af7f85d9SChris Leech fcoe_percpu_clean(lport); 532f161fb72SJoe Eykholt 533a703e490SVasu Dev /* Cleanup the fc_lport */ 534af7f85d9SChris Leech fc_lport_destroy(lport); 535af7f85d9SChris Leech fc_fcp_destroy(lport); 536a703e490SVasu Dev 537a703e490SVasu Dev /* Detach from the scsi-ml */ 538af7f85d9SChris Leech fc_remove_host(lport->host); 539af7f85d9SChris Leech scsi_remove_host(lport->host); 540a703e490SVasu Dev 541a703e490SVasu Dev /* There are no more rports or I/O, free the EM */ 542af7f85d9SChris Leech fc_exch_mgr_free(lport); 543a703e490SVasu Dev 544a703e490SVasu Dev /* Free existing skbs */ 545af7f85d9SChris Leech fcoe_clean_pending_queue(lport); 546a703e490SVasu Dev 5471047f221SVasu Dev /* Stop the timer */ 5481047f221SVasu Dev del_timer_sync(&fc->timer); 5491047f221SVasu Dev 550a703e490SVasu Dev /* Free memory used by statistical counters */ 551af7f85d9SChris Leech fc_lport_free_stats(lport); 552a703e490SVasu Dev 553a703e490SVasu Dev /* Release the net_device and Scsi_Host */ 5541d1b88dcSVasu Dev dev_put(netdev); 555af7f85d9SChris Leech scsi_host_put(lport->host); 556a703e490SVasu Dev } 557a703e490SVasu Dev 558a703e490SVasu Dev /* 559a703e490SVasu Dev * fcoe_ddp_setup - calls LLD's ddp_setup through net_device 560a703e490SVasu Dev * @lp: the corresponding fc_lport 561a703e490SVasu Dev * @xid: the exchange id for this ddp transfer 562a703e490SVasu Dev * @sgl: the scatterlist describing this transfer 563a703e490SVasu Dev * @sgc: number of sg items 564a703e490SVasu Dev * 565a703e490SVasu Dev * Returns : 0 no ddp 566a703e490SVasu Dev */ 567a703e490SVasu Dev static int fcoe_ddp_setup(struct fc_lport *lp, u16 xid, 568a703e490SVasu Dev struct scatterlist *sgl, unsigned int sgc) 569a703e490SVasu Dev { 570a703e490SVasu Dev struct net_device *n = fcoe_netdev(lp); 571a703e490SVasu Dev 572a703e490SVasu Dev if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_setup) 573a703e490SVasu Dev return n->netdev_ops->ndo_fcoe_ddp_setup(n, xid, sgl, sgc); 574a703e490SVasu Dev 575a703e490SVasu Dev return 0; 576a703e490SVasu Dev } 577a703e490SVasu Dev 578a703e490SVasu Dev /* 579a703e490SVasu Dev * fcoe_ddp_done - calls LLD's ddp_done through net_device 580a703e490SVasu Dev * @lp: the corresponding fc_lport 581a703e490SVasu Dev * @xid: the exchange id for this ddp transfer 582a703e490SVasu Dev * 583a703e490SVasu Dev * Returns : the length of data that have been completed by ddp 584a703e490SVasu Dev */ 585a703e490SVasu Dev static int fcoe_ddp_done(struct fc_lport *lp, u16 xid) 586a703e490SVasu Dev { 587a703e490SVasu Dev struct net_device *n = fcoe_netdev(lp); 588a703e490SVasu Dev 589a703e490SVasu Dev if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_done) 590a703e490SVasu Dev return n->netdev_ops->ndo_fcoe_ddp_done(n, xid); 591a703e490SVasu Dev return 0; 592a703e490SVasu Dev } 593a703e490SVasu Dev 594a703e490SVasu Dev static struct libfc_function_template fcoe_libfc_fcn_templ = { 595a703e490SVasu Dev .frame_send = fcoe_xmit, 596a703e490SVasu Dev .ddp_setup = fcoe_ddp_setup, 597a703e490SVasu Dev .ddp_done = fcoe_ddp_done, 598a703e490SVasu Dev }; 599a703e490SVasu Dev 600a703e490SVasu Dev /** 601a703e490SVasu Dev * fcoe_if_create() - this function creates the fcoe interface 602a703e490SVasu Dev * @netdev: pointer the associated netdevice 603af7f85d9SChris Leech * @parent: device pointer to be the parent in sysfs for the SCSI host 604a703e490SVasu Dev * 605a703e490SVasu Dev * Creates fc_lport struct and scsi_host for lport, configures lport 606a703e490SVasu Dev * and starts fabric login. 607a703e490SVasu Dev * 608af7f85d9SChris Leech * Returns : The allocated fc_lport or an error pointer 609a703e490SVasu Dev */ 610af7f85d9SChris Leech static struct fc_lport *fcoe_if_create(struct net_device *netdev, 611af7f85d9SChris Leech struct device *parent) 612a703e490SVasu Dev { 613a703e490SVasu Dev int rc; 614af7f85d9SChris Leech struct fc_lport *lport = NULL; 615a703e490SVasu Dev struct fcoe_softc *fc; 616a703e490SVasu Dev struct Scsi_Host *shost; 617a703e490SVasu Dev 618d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Create Interface\n"); 619a703e490SVasu Dev 620a0a25da2SVasu Dev shost = libfc_host_alloc(&fcoe_shost_template, 621a703e490SVasu Dev sizeof(struct fcoe_softc)); 622a703e490SVasu Dev if (!shost) { 623d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); 624af7f85d9SChris Leech rc = -ENOMEM; 625af7f85d9SChris Leech goto out; 626a703e490SVasu Dev } 627af7f85d9SChris Leech lport = shost_priv(shost); 628af7f85d9SChris Leech fc = lport_priv(lport); 629a703e490SVasu Dev 630a703e490SVasu Dev /* configure fc_lport, e.g., em */ 631af7f85d9SChris Leech rc = fcoe_lport_config(lport); 632a703e490SVasu Dev if (rc) { 633d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure lport for the " 634d5488eb9SRobert Love "interface\n"); 635a703e490SVasu Dev goto out_host_put; 636a703e490SVasu Dev } 637a703e490SVasu Dev 63897c8389dSJoe Eykholt /* 63997c8389dSJoe Eykholt * Initialize FIP. 64097c8389dSJoe Eykholt */ 64197c8389dSJoe Eykholt fcoe_ctlr_init(&fc->ctlr); 64297c8389dSJoe Eykholt fc->ctlr.send = fcoe_fip_send; 64397c8389dSJoe Eykholt fc->ctlr.update_mac = fcoe_update_src_mac; 64497c8389dSJoe Eykholt 645ab6b85c1SVasu Dev /* configure lport network properties */ 646af7f85d9SChris Leech rc = fcoe_netdev_config(lport, netdev); 647ab6b85c1SVasu Dev if (rc) { 648d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " 649d5488eb9SRobert Love "interface\n"); 650ab6b85c1SVasu Dev goto out_netdev_cleanup; 651ab6b85c1SVasu Dev } 65297c8389dSJoe Eykholt 653a703e490SVasu Dev /* configure lport scsi host properties */ 654af7f85d9SChris Leech rc = fcoe_shost_config(lport, shost, parent); 655a703e490SVasu Dev if (rc) { 656d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " 657d5488eb9SRobert Love "interface\n"); 658ab6b85c1SVasu Dev goto out_netdev_cleanup; 659a703e490SVasu Dev } 660a703e490SVasu Dev 661a703e490SVasu Dev /* Initialize the library */ 662af7f85d9SChris Leech rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ); 663a703e490SVasu Dev if (rc) { 664d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " 665d5488eb9SRobert Love "interface\n"); 666a703e490SVasu Dev goto out_lp_destroy; 667a703e490SVasu Dev } 668a703e490SVasu Dev 669e8af4d43SVasu Dev /* 670e8af4d43SVasu Dev * fcoe_em_alloc() and fcoe_hostlist_add() both 671e8af4d43SVasu Dev * need to be atomic under fcoe_hostlist_lock 672e8af4d43SVasu Dev * since fcoe_em_alloc() looks for an existing EM 673e8af4d43SVasu Dev * instance on host list updated by fcoe_hostlist_add(). 674e8af4d43SVasu Dev */ 675e8af4d43SVasu Dev write_lock(&fcoe_hostlist_lock); 67696316099SVasu Dev /* lport exch manager allocation */ 677af7f85d9SChris Leech rc = fcoe_em_config(lport); 67896316099SVasu Dev if (rc) { 67996316099SVasu Dev FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " 68096316099SVasu Dev "interface\n"); 68196316099SVasu Dev goto out_lp_destroy; 68296316099SVasu Dev } 68396316099SVasu Dev 684a703e490SVasu Dev /* add to lports list */ 685af7f85d9SChris Leech fcoe_hostlist_add(lport); 686e8af4d43SVasu Dev write_unlock(&fcoe_hostlist_lock); 687a703e490SVasu Dev 688af7f85d9SChris Leech lport->boot_time = jiffies; 689a703e490SVasu Dev 690af7f85d9SChris Leech fc_fabric_login(lport); 691a703e490SVasu Dev 692af7f85d9SChris Leech if (!fcoe_link_ok(lport)) 69397c8389dSJoe Eykholt fcoe_ctlr_link_up(&fc->ctlr); 69497c8389dSJoe Eykholt 695a703e490SVasu Dev dev_hold(netdev); 696a703e490SVasu Dev 697af7f85d9SChris Leech return lport; 698a703e490SVasu Dev 699a703e490SVasu Dev out_lp_destroy: 700af7f85d9SChris Leech fc_exch_mgr_free(lport); 701ab6b85c1SVasu Dev out_netdev_cleanup: 702ab6b85c1SVasu Dev fcoe_netdev_cleanup(fc); 703a703e490SVasu Dev out_host_put: 704af7f85d9SChris Leech scsi_host_put(lport->host); 705af7f85d9SChris Leech out: 706af7f85d9SChris Leech return ERR_PTR(rc); 707a703e490SVasu Dev } 708a703e490SVasu Dev 709a703e490SVasu Dev /** 710a703e490SVasu Dev * fcoe_if_init() - attach to scsi transport 711a703e490SVasu Dev * 712a703e490SVasu Dev * Returns : 0 on success 713a703e490SVasu Dev */ 714a703e490SVasu Dev static int __init fcoe_if_init(void) 715a703e490SVasu Dev { 716a703e490SVasu Dev /* attach to scsi transport */ 717a703e490SVasu Dev scsi_transport_fcoe_sw = 718a703e490SVasu Dev fc_attach_transport(&fcoe_transport_function); 719a703e490SVasu Dev 720a703e490SVasu Dev if (!scsi_transport_fcoe_sw) { 721d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); 722a703e490SVasu Dev return -ENODEV; 723a703e490SVasu Dev } 724a703e490SVasu Dev 725a703e490SVasu Dev return 0; 726a703e490SVasu Dev } 727a703e490SVasu Dev 728a703e490SVasu Dev /** 729a703e490SVasu Dev * fcoe_if_exit() - detach from scsi transport 730a703e490SVasu Dev * 731a703e490SVasu Dev * Returns : 0 on success 732a703e490SVasu Dev */ 733a703e490SVasu Dev int __exit fcoe_if_exit(void) 734a703e490SVasu Dev { 735a703e490SVasu Dev fc_release_transport(scsi_transport_fcoe_sw); 736a703e490SVasu Dev return 0; 737a703e490SVasu Dev } 738a703e490SVasu Dev 739a703e490SVasu Dev /** 740a703e490SVasu Dev * fcoe_percpu_thread_create() - Create a receive thread for an online cpu 741a703e490SVasu Dev * @cpu: cpu index for the online cpu 742a703e490SVasu Dev */ 743a703e490SVasu Dev static void fcoe_percpu_thread_create(unsigned int cpu) 744a703e490SVasu Dev { 745a703e490SVasu Dev struct fcoe_percpu_s *p; 746a703e490SVasu Dev struct task_struct *thread; 747a703e490SVasu Dev 748a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 749a703e490SVasu Dev 750a703e490SVasu Dev thread = kthread_create(fcoe_percpu_receive_thread, 751a703e490SVasu Dev (void *)p, "fcoethread/%d", cpu); 752a703e490SVasu Dev 753a703e490SVasu Dev if (likely(!IS_ERR(p->thread))) { 754a703e490SVasu Dev kthread_bind(thread, cpu); 755a703e490SVasu Dev wake_up_process(thread); 756a703e490SVasu Dev 757a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 758a703e490SVasu Dev p->thread = thread; 759a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 760a703e490SVasu Dev } 761a703e490SVasu Dev } 762a703e490SVasu Dev 763a703e490SVasu Dev /** 764a703e490SVasu Dev * fcoe_percpu_thread_destroy() - removes the rx thread for the given cpu 765a703e490SVasu Dev * @cpu: cpu index the rx thread is to be removed 766a703e490SVasu Dev * 767a703e490SVasu Dev * Destroys a per-CPU Rx thread. Any pending skbs are moved to the 768a703e490SVasu Dev * current CPU's Rx thread. If the thread being destroyed is bound to 769a703e490SVasu Dev * the CPU processing this context the skbs will be freed. 770a703e490SVasu Dev */ 771a703e490SVasu Dev static void fcoe_percpu_thread_destroy(unsigned int cpu) 772a703e490SVasu Dev { 773a703e490SVasu Dev struct fcoe_percpu_s *p; 774a703e490SVasu Dev struct task_struct *thread; 775a703e490SVasu Dev struct page *crc_eof; 776a703e490SVasu Dev struct sk_buff *skb; 777a703e490SVasu Dev #ifdef CONFIG_SMP 778a703e490SVasu Dev struct fcoe_percpu_s *p0; 779a703e490SVasu Dev unsigned targ_cpu = smp_processor_id(); 780a703e490SVasu Dev #endif /* CONFIG_SMP */ 781a703e490SVasu Dev 782d5488eb9SRobert Love FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); 783a703e490SVasu Dev 784a703e490SVasu Dev /* Prevent any new skbs from being queued for this CPU. */ 785a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 786a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 787a703e490SVasu Dev thread = p->thread; 788a703e490SVasu Dev p->thread = NULL; 789a703e490SVasu Dev crc_eof = p->crc_eof_page; 790a703e490SVasu Dev p->crc_eof_page = NULL; 791a703e490SVasu Dev p->crc_eof_offset = 0; 792a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 793a703e490SVasu Dev 794a703e490SVasu Dev #ifdef CONFIG_SMP 795a703e490SVasu Dev /* 796a703e490SVasu Dev * Don't bother moving the skb's if this context is running 797a703e490SVasu Dev * on the same CPU that is having its thread destroyed. This 798a703e490SVasu Dev * can easily happen when the module is removed. 799a703e490SVasu Dev */ 800a703e490SVasu Dev if (cpu != targ_cpu) { 801a703e490SVasu Dev p0 = &per_cpu(fcoe_percpu, targ_cpu); 802a703e490SVasu Dev spin_lock_bh(&p0->fcoe_rx_list.lock); 803a703e490SVasu Dev if (p0->thread) { 804d5488eb9SRobert Love FCOE_DBG("Moving frames from CPU %d to CPU %d\n", 805a703e490SVasu Dev cpu, targ_cpu); 806a703e490SVasu Dev 807a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 808a703e490SVasu Dev __skb_queue_tail(&p0->fcoe_rx_list, skb); 809a703e490SVasu Dev spin_unlock_bh(&p0->fcoe_rx_list.lock); 810a703e490SVasu Dev } else { 811a703e490SVasu Dev /* 812a703e490SVasu Dev * The targeted CPU is not initialized and cannot accept 813a703e490SVasu Dev * new skbs. Unlock the targeted CPU and drop the skbs 814a703e490SVasu Dev * on the CPU that is going offline. 815a703e490SVasu Dev */ 816a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 817a703e490SVasu Dev kfree_skb(skb); 818a703e490SVasu Dev spin_unlock_bh(&p0->fcoe_rx_list.lock); 819a703e490SVasu Dev } 820a703e490SVasu Dev } else { 821a703e490SVasu Dev /* 822a703e490SVasu Dev * This scenario occurs when the module is being removed 823a703e490SVasu Dev * and all threads are being destroyed. skbs will continue 824a703e490SVasu Dev * to be shifted from the CPU thread that is being removed 825a703e490SVasu Dev * to the CPU thread associated with the CPU that is processing 826a703e490SVasu Dev * the module removal. Once there is only one CPU Rx thread it 827a703e490SVasu Dev * will reach this case and we will drop all skbs and later 828a703e490SVasu Dev * stop the thread. 829a703e490SVasu Dev */ 830a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 831a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 832a703e490SVasu Dev kfree_skb(skb); 833a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 834a703e490SVasu Dev } 835a703e490SVasu Dev #else 836a703e490SVasu Dev /* 837dd3fd72eSChris Leech * This a non-SMP scenario where the singular Rx thread is 838a703e490SVasu Dev * being removed. Free all skbs and stop the thread. 839a703e490SVasu Dev */ 840a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 841a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 842a703e490SVasu Dev kfree_skb(skb); 843a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 844a703e490SVasu Dev #endif 845a703e490SVasu Dev 846a703e490SVasu Dev if (thread) 847a703e490SVasu Dev kthread_stop(thread); 848a703e490SVasu Dev 849a703e490SVasu Dev if (crc_eof) 850a703e490SVasu Dev put_page(crc_eof); 851a703e490SVasu Dev } 852a703e490SVasu Dev 853a703e490SVasu Dev /** 854a703e490SVasu Dev * fcoe_cpu_callback() - fcoe cpu hotplug event callback 855a703e490SVasu Dev * @nfb: callback data block 856a703e490SVasu Dev * @action: event triggering the callback 857a703e490SVasu Dev * @hcpu: index for the cpu of this event 858a703e490SVasu Dev * 859a703e490SVasu Dev * This creates or destroys per cpu data for fcoe 860a703e490SVasu Dev * 861a703e490SVasu Dev * Returns NOTIFY_OK always. 862a703e490SVasu Dev */ 863a703e490SVasu Dev static int fcoe_cpu_callback(struct notifier_block *nfb, 864a703e490SVasu Dev unsigned long action, void *hcpu) 865a703e490SVasu Dev { 866a703e490SVasu Dev unsigned cpu = (unsigned long)hcpu; 867a703e490SVasu Dev 868a703e490SVasu Dev switch (action) { 869a703e490SVasu Dev case CPU_ONLINE: 870a703e490SVasu Dev case CPU_ONLINE_FROZEN: 871d5488eb9SRobert Love FCOE_DBG("CPU %x online: Create Rx thread\n", cpu); 872a703e490SVasu Dev fcoe_percpu_thread_create(cpu); 873a703e490SVasu Dev break; 874a703e490SVasu Dev case CPU_DEAD: 875a703e490SVasu Dev case CPU_DEAD_FROZEN: 876d5488eb9SRobert Love FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu); 877a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 878a703e490SVasu Dev break; 879a703e490SVasu Dev default: 880a703e490SVasu Dev break; 881a703e490SVasu Dev } 882a703e490SVasu Dev return NOTIFY_OK; 883a703e490SVasu Dev } 884a703e490SVasu Dev 885a703e490SVasu Dev static struct notifier_block fcoe_cpu_notifier = { 886a703e490SVasu Dev .notifier_call = fcoe_cpu_callback, 887a703e490SVasu Dev }; 888a703e490SVasu Dev 889a703e490SVasu Dev /** 890a703e490SVasu Dev * fcoe_rcv() - this is the fcoe receive function called by NET_RX_SOFTIRQ 891a703e490SVasu Dev * @skb: the receive skb 892a703e490SVasu Dev * @dev: associated net device 893a703e490SVasu Dev * @ptype: context 894dd3fd72eSChris Leech * @olddev: last device 895a703e490SVasu Dev * 896a703e490SVasu Dev * this function will receive the packet and build fc frame and pass it up 897a703e490SVasu Dev * 898a703e490SVasu Dev * Returns: 0 for success 899a703e490SVasu Dev */ 900a703e490SVasu Dev int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, 901a703e490SVasu Dev struct packet_type *ptype, struct net_device *olddev) 902a703e490SVasu Dev { 903a703e490SVasu Dev struct fc_lport *lp; 904a703e490SVasu Dev struct fcoe_rcv_info *fr; 905a703e490SVasu Dev struct fcoe_softc *fc; 906a703e490SVasu Dev struct fc_frame_header *fh; 907a703e490SVasu Dev struct fcoe_percpu_s *fps; 908b2f0091fSVasu Dev unsigned int cpu; 909a703e490SVasu Dev 910a703e490SVasu Dev fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); 91197c8389dSJoe Eykholt lp = fc->ctlr.lp; 912a703e490SVasu Dev if (unlikely(lp == NULL)) { 913d5488eb9SRobert Love FCOE_NETDEV_DBG(dev, "Cannot find hba structure"); 914a703e490SVasu Dev goto err2; 915a703e490SVasu Dev } 91697c8389dSJoe Eykholt if (!lp->link_up) 91797c8389dSJoe Eykholt goto err2; 918a703e490SVasu Dev 919d5488eb9SRobert Love FCOE_NETDEV_DBG(dev, "skb_info: len:%d data_len:%d head:%p " 920d5488eb9SRobert Love "data:%p tail:%p end:%p sum:%d dev:%s", 921d5488eb9SRobert Love skb->len, skb->data_len, skb->head, skb->data, 922d5488eb9SRobert Love skb_tail_pointer(skb), skb_end_pointer(skb), 923d5488eb9SRobert Love skb->csum, skb->dev ? skb->dev->name : "<NULL>"); 924a703e490SVasu Dev 925a703e490SVasu Dev /* check for FCOE packet type */ 926a703e490SVasu Dev if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { 927d5488eb9SRobert Love FCOE_NETDEV_DBG(dev, "Wrong FC type frame"); 928a703e490SVasu Dev goto err; 929a703e490SVasu Dev } 930a703e490SVasu Dev 931a703e490SVasu Dev /* 932a703e490SVasu Dev * Check for minimum frame length, and make sure required FCoE 933a703e490SVasu Dev * and FC headers are pulled into the linear data area. 934a703e490SVasu Dev */ 935a703e490SVasu Dev if (unlikely((skb->len < FCOE_MIN_FRAME) || 936a703e490SVasu Dev !pskb_may_pull(skb, FCOE_HEADER_LEN))) 937a703e490SVasu Dev goto err; 938a703e490SVasu Dev 939a703e490SVasu Dev skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); 940a703e490SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 941a703e490SVasu Dev 942a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 943a703e490SVasu Dev fr->fr_dev = lp; 944a703e490SVasu Dev fr->ptype = ptype; 945a703e490SVasu Dev 946a703e490SVasu Dev /* 947b2f0091fSVasu Dev * In case the incoming frame's exchange is originated from 948b2f0091fSVasu Dev * the initiator, then received frame's exchange id is ANDed 949b2f0091fSVasu Dev * with fc_cpu_mask bits to get the same cpu on which exchange 950b2f0091fSVasu Dev * was originated, otherwise just use the current cpu. 951a703e490SVasu Dev */ 952b2f0091fSVasu Dev if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) 953b2f0091fSVasu Dev cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; 954b2f0091fSVasu Dev else 955b2f0091fSVasu Dev cpu = smp_processor_id(); 956a703e490SVasu Dev 957a703e490SVasu Dev fps = &per_cpu(fcoe_percpu, cpu); 958a703e490SVasu Dev spin_lock_bh(&fps->fcoe_rx_list.lock); 959a703e490SVasu Dev if (unlikely(!fps->thread)) { 960a703e490SVasu Dev /* 961a703e490SVasu Dev * The targeted CPU is not ready, let's target 962a703e490SVasu Dev * the first CPU now. For non-SMP systems this 963a703e490SVasu Dev * will check the same CPU twice. 964a703e490SVasu Dev */ 965d5488eb9SRobert Love FCOE_NETDEV_DBG(dev, "CPU is online, but no receive thread " 966d5488eb9SRobert Love "ready for incoming skb- using first online " 967d5488eb9SRobert Love "CPU.\n"); 968a703e490SVasu Dev 969a703e490SVasu Dev spin_unlock_bh(&fps->fcoe_rx_list.lock); 970a703e490SVasu Dev cpu = first_cpu(cpu_online_map); 971a703e490SVasu Dev fps = &per_cpu(fcoe_percpu, cpu); 972a703e490SVasu Dev spin_lock_bh(&fps->fcoe_rx_list.lock); 973a703e490SVasu Dev if (!fps->thread) { 974a703e490SVasu Dev spin_unlock_bh(&fps->fcoe_rx_list.lock); 975a703e490SVasu Dev goto err; 976a703e490SVasu Dev } 977a703e490SVasu Dev } 978a703e490SVasu Dev 979a703e490SVasu Dev /* 980a703e490SVasu Dev * We now have a valid CPU that we're targeting for 981a703e490SVasu Dev * this skb. We also have this receive thread locked, 982a703e490SVasu Dev * so we're free to queue skbs into it's queue. 983a703e490SVasu Dev */ 984a703e490SVasu Dev __skb_queue_tail(&fps->fcoe_rx_list, skb); 985a703e490SVasu Dev if (fps->fcoe_rx_list.qlen == 1) 986a703e490SVasu Dev wake_up_process(fps->thread); 987a703e490SVasu Dev 988a703e490SVasu Dev spin_unlock_bh(&fps->fcoe_rx_list.lock); 989a703e490SVasu Dev 990a703e490SVasu Dev return 0; 991a703e490SVasu Dev err: 992a703e490SVasu Dev fc_lport_get_stats(lp)->ErrorFrames++; 993a703e490SVasu Dev 994a703e490SVasu Dev err2: 995a703e490SVasu Dev kfree_skb(skb); 996a703e490SVasu Dev return -1; 997a703e490SVasu Dev } 998a703e490SVasu Dev 999a703e490SVasu Dev /** 1000a703e490SVasu Dev * fcoe_start_io() - pass to netdev to start xmit for fcoe 1001a703e490SVasu Dev * @skb: the skb to be xmitted 1002a703e490SVasu Dev * 1003a703e490SVasu Dev * Returns: 0 for success 1004a703e490SVasu Dev */ 1005a703e490SVasu Dev static inline int fcoe_start_io(struct sk_buff *skb) 1006a703e490SVasu Dev { 1007a703e490SVasu Dev int rc; 1008a703e490SVasu Dev 1009a703e490SVasu Dev skb_get(skb); 1010a703e490SVasu Dev rc = dev_queue_xmit(skb); 1011a703e490SVasu Dev if (rc != 0) 1012a703e490SVasu Dev return rc; 1013a703e490SVasu Dev kfree_skb(skb); 1014a703e490SVasu Dev return 0; 1015a703e490SVasu Dev } 1016a703e490SVasu Dev 1017a703e490SVasu Dev /** 1018dd3fd72eSChris Leech * fcoe_get_paged_crc_eof() - in case we need to alloc a page for crc_eof 1019a703e490SVasu Dev * @skb: the skb to be xmitted 1020a703e490SVasu Dev * @tlen: total len 1021a703e490SVasu Dev * 1022a703e490SVasu Dev * Returns: 0 for success 1023a703e490SVasu Dev */ 1024a703e490SVasu Dev static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) 1025a703e490SVasu Dev { 1026a703e490SVasu Dev struct fcoe_percpu_s *fps; 1027a703e490SVasu Dev struct page *page; 1028a703e490SVasu Dev 1029a703e490SVasu Dev fps = &get_cpu_var(fcoe_percpu); 1030a703e490SVasu Dev page = fps->crc_eof_page; 1031a703e490SVasu Dev if (!page) { 1032a703e490SVasu Dev page = alloc_page(GFP_ATOMIC); 1033a703e490SVasu Dev if (!page) { 1034a703e490SVasu Dev put_cpu_var(fcoe_percpu); 1035a703e490SVasu Dev return -ENOMEM; 1036a703e490SVasu Dev } 1037a703e490SVasu Dev fps->crc_eof_page = page; 1038a703e490SVasu Dev fps->crc_eof_offset = 0; 1039a703e490SVasu Dev } 1040a703e490SVasu Dev 1041a703e490SVasu Dev get_page(page); 1042a703e490SVasu Dev skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 1043a703e490SVasu Dev fps->crc_eof_offset, tlen); 1044a703e490SVasu Dev skb->len += tlen; 1045a703e490SVasu Dev skb->data_len += tlen; 1046a703e490SVasu Dev skb->truesize += tlen; 1047a703e490SVasu Dev fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); 1048a703e490SVasu Dev 1049a703e490SVasu Dev if (fps->crc_eof_offset >= PAGE_SIZE) { 1050a703e490SVasu Dev fps->crc_eof_page = NULL; 1051a703e490SVasu Dev fps->crc_eof_offset = 0; 1052a703e490SVasu Dev put_page(page); 1053a703e490SVasu Dev } 1054a703e490SVasu Dev put_cpu_var(fcoe_percpu); 1055a703e490SVasu Dev return 0; 1056a703e490SVasu Dev } 1057a703e490SVasu Dev 1058a703e490SVasu Dev /** 1059a703e490SVasu Dev * fcoe_fc_crc() - calculates FC CRC in this fcoe skb 1060dd3fd72eSChris Leech * @fp: the fc_frame containing data to be checksummed 1061a703e490SVasu Dev * 1062a703e490SVasu Dev * This uses crc32() to calculate the crc for fc frame 1063a703e490SVasu Dev * Return : 32 bit crc 1064a703e490SVasu Dev */ 1065a703e490SVasu Dev u32 fcoe_fc_crc(struct fc_frame *fp) 1066a703e490SVasu Dev { 1067a703e490SVasu Dev struct sk_buff *skb = fp_skb(fp); 1068a703e490SVasu Dev struct skb_frag_struct *frag; 1069a703e490SVasu Dev unsigned char *data; 1070a703e490SVasu Dev unsigned long off, len, clen; 1071a703e490SVasu Dev u32 crc; 1072a703e490SVasu Dev unsigned i; 1073a703e490SVasu Dev 1074a703e490SVasu Dev crc = crc32(~0, skb->data, skb_headlen(skb)); 1075a703e490SVasu Dev 1076a703e490SVasu Dev for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 1077a703e490SVasu Dev frag = &skb_shinfo(skb)->frags[i]; 1078a703e490SVasu Dev off = frag->page_offset; 1079a703e490SVasu Dev len = frag->size; 1080a703e490SVasu Dev while (len > 0) { 1081a703e490SVasu Dev clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); 1082a703e490SVasu Dev data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), 1083a703e490SVasu Dev KM_SKB_DATA_SOFTIRQ); 1084a703e490SVasu Dev crc = crc32(crc, data + (off & ~PAGE_MASK), clen); 1085a703e490SVasu Dev kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); 1086a703e490SVasu Dev off += clen; 1087a703e490SVasu Dev len -= clen; 1088a703e490SVasu Dev } 1089a703e490SVasu Dev } 1090a703e490SVasu Dev return crc; 1091a703e490SVasu Dev } 1092a703e490SVasu Dev 1093a703e490SVasu Dev /** 1094a703e490SVasu Dev * fcoe_xmit() - FCoE frame transmit function 1095a703e490SVasu Dev * @lp: the associated local port 1096a703e490SVasu Dev * @fp: the fc_frame to be transmitted 1097a703e490SVasu Dev * 1098a703e490SVasu Dev * Return : 0 for success 1099a703e490SVasu Dev */ 1100a703e490SVasu Dev int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) 1101a703e490SVasu Dev { 11024bb6b515SVasu Dev int wlen; 1103a703e490SVasu Dev u32 crc; 1104a703e490SVasu Dev struct ethhdr *eh; 1105a703e490SVasu Dev struct fcoe_crc_eof *cp; 1106a703e490SVasu Dev struct sk_buff *skb; 1107a703e490SVasu Dev struct fcoe_dev_stats *stats; 1108a703e490SVasu Dev struct fc_frame_header *fh; 1109a703e490SVasu Dev unsigned int hlen; /* header length implies the version */ 1110a703e490SVasu Dev unsigned int tlen; /* trailer length */ 1111a703e490SVasu Dev unsigned int elen; /* eth header, may include vlan */ 1112a703e490SVasu Dev struct fcoe_softc *fc; 1113a703e490SVasu Dev u8 sof, eof; 1114a703e490SVasu Dev struct fcoe_hdr *hp; 1115a703e490SVasu Dev 1116a703e490SVasu Dev WARN_ON((fr_len(fp) % sizeof(u32)) != 0); 1117a703e490SVasu Dev 1118a703e490SVasu Dev fc = lport_priv(lp); 1119a703e490SVasu Dev fh = fc_frame_header_get(fp); 112097c8389dSJoe Eykholt skb = fp_skb(fp); 112197c8389dSJoe Eykholt wlen = skb->len / FCOE_WORD_TO_BYTE; 112297c8389dSJoe Eykholt 112397c8389dSJoe Eykholt if (!lp->link_up) { 11243caf02eeSDan Carpenter kfree_skb(skb); 112597c8389dSJoe Eykholt return 0; 1126a703e490SVasu Dev } 1127a703e490SVasu Dev 112897c8389dSJoe Eykholt if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && 112997c8389dSJoe Eykholt fcoe_ctlr_els_send(&fc->ctlr, skb)) 113097c8389dSJoe Eykholt return 0; 113197c8389dSJoe Eykholt 1132a703e490SVasu Dev sof = fr_sof(fp); 1133a703e490SVasu Dev eof = fr_eof(fp); 1134a703e490SVasu Dev 11354e57e1cbSVasu Dev elen = sizeof(struct ethhdr); 1136a703e490SVasu Dev hlen = sizeof(struct fcoe_hdr); 1137a703e490SVasu Dev tlen = sizeof(struct fcoe_crc_eof); 1138a703e490SVasu Dev wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; 1139a703e490SVasu Dev 1140a703e490SVasu Dev /* crc offload */ 1141a703e490SVasu Dev if (likely(lp->crc_offload)) { 1142a703e490SVasu Dev skb->ip_summed = CHECKSUM_PARTIAL; 1143a703e490SVasu Dev skb->csum_start = skb_headroom(skb); 1144a703e490SVasu Dev skb->csum_offset = skb->len; 1145a703e490SVasu Dev crc = 0; 1146a703e490SVasu Dev } else { 1147a703e490SVasu Dev skb->ip_summed = CHECKSUM_NONE; 1148a703e490SVasu Dev crc = fcoe_fc_crc(fp); 1149a703e490SVasu Dev } 1150a703e490SVasu Dev 1151a703e490SVasu Dev /* copy fc crc and eof to the skb buff */ 1152a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 1153a703e490SVasu Dev skb_frag_t *frag; 1154a703e490SVasu Dev if (fcoe_get_paged_crc_eof(skb, tlen)) { 1155a703e490SVasu Dev kfree_skb(skb); 1156a703e490SVasu Dev return -ENOMEM; 1157a703e490SVasu Dev } 1158a703e490SVasu Dev frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; 1159a703e490SVasu Dev cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ) 1160a703e490SVasu Dev + frag->page_offset; 1161a703e490SVasu Dev } else { 1162a703e490SVasu Dev cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); 1163a703e490SVasu Dev } 1164a703e490SVasu Dev 1165a703e490SVasu Dev memset(cp, 0, sizeof(*cp)); 1166a703e490SVasu Dev cp->fcoe_eof = eof; 1167a703e490SVasu Dev cp->fcoe_crc32 = cpu_to_le32(~crc); 1168a703e490SVasu Dev 1169a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 1170a703e490SVasu Dev kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); 1171a703e490SVasu Dev cp = NULL; 1172a703e490SVasu Dev } 1173a703e490SVasu Dev 1174dd3fd72eSChris Leech /* adjust skb network/transport offsets to match mac/fcoe/fc */ 1175a703e490SVasu Dev skb_push(skb, elen + hlen); 1176a703e490SVasu Dev skb_reset_mac_header(skb); 1177a703e490SVasu Dev skb_reset_network_header(skb); 1178a703e490SVasu Dev skb->mac_len = elen; 1179a703e490SVasu Dev skb->protocol = htons(ETH_P_FCOE); 11801d1b88dcSVasu Dev skb->dev = fc->netdev; 1181a703e490SVasu Dev 1182a703e490SVasu Dev /* fill up mac and fcoe headers */ 1183a703e490SVasu Dev eh = eth_hdr(skb); 1184a703e490SVasu Dev eh->h_proto = htons(ETH_P_FCOE); 118597c8389dSJoe Eykholt if (fc->ctlr.map_dest) 1186a703e490SVasu Dev fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); 1187a703e490SVasu Dev else 1188a703e490SVasu Dev /* insert GW address */ 118997c8389dSJoe Eykholt memcpy(eh->h_dest, fc->ctlr.dest_addr, ETH_ALEN); 1190a703e490SVasu Dev 119197c8389dSJoe Eykholt if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN)) 119297c8389dSJoe Eykholt memcpy(eh->h_source, fc->ctlr.ctl_src_addr, ETH_ALEN); 1193a703e490SVasu Dev else 119497c8389dSJoe Eykholt memcpy(eh->h_source, fc->ctlr.data_src_addr, ETH_ALEN); 1195a703e490SVasu Dev 1196a703e490SVasu Dev hp = (struct fcoe_hdr *)(eh + 1); 1197a703e490SVasu Dev memset(hp, 0, sizeof(*hp)); 1198a703e490SVasu Dev if (FC_FCOE_VER) 1199a703e490SVasu Dev FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); 1200a703e490SVasu Dev hp->fcoe_sof = sof; 1201a703e490SVasu Dev 1202a703e490SVasu Dev /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ 1203a703e490SVasu Dev if (lp->seq_offload && fr_max_payload(fp)) { 1204a703e490SVasu Dev skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; 1205a703e490SVasu Dev skb_shinfo(skb)->gso_size = fr_max_payload(fp); 1206a703e490SVasu Dev } else { 1207a703e490SVasu Dev skb_shinfo(skb)->gso_type = 0; 1208a703e490SVasu Dev skb_shinfo(skb)->gso_size = 0; 1209a703e490SVasu Dev } 1210a703e490SVasu Dev /* update tx stats: regardless if LLD fails */ 1211a703e490SVasu Dev stats = fc_lport_get_stats(lp); 1212a703e490SVasu Dev stats->TxFrames++; 1213a703e490SVasu Dev stats->TxWords += wlen; 1214a703e490SVasu Dev 1215a703e490SVasu Dev /* send down to lld */ 1216a703e490SVasu Dev fr_dev(fp) = lp; 1217a703e490SVasu Dev if (fc->fcoe_pending_queue.qlen) 12184bb6b515SVasu Dev fcoe_check_wait_queue(lp, skb); 12194bb6b515SVasu Dev else if (fcoe_start_io(skb)) 12204bb6b515SVasu Dev fcoe_check_wait_queue(lp, skb); 1221a703e490SVasu Dev 1222a703e490SVasu Dev return 0; 1223a703e490SVasu Dev } 1224a703e490SVasu Dev 1225a703e490SVasu Dev /** 1226a703e490SVasu Dev * fcoe_percpu_receive_thread() - recv thread per cpu 1227a703e490SVasu Dev * @arg: ptr to the fcoe per cpu struct 1228a703e490SVasu Dev * 1229a703e490SVasu Dev * Return: 0 for success 1230a703e490SVasu Dev */ 1231a703e490SVasu Dev int fcoe_percpu_receive_thread(void *arg) 1232a703e490SVasu Dev { 1233a703e490SVasu Dev struct fcoe_percpu_s *p = arg; 1234a703e490SVasu Dev u32 fr_len; 1235a703e490SVasu Dev struct fc_lport *lp; 1236a703e490SVasu Dev struct fcoe_rcv_info *fr; 1237a703e490SVasu Dev struct fcoe_dev_stats *stats; 1238a703e490SVasu Dev struct fc_frame_header *fh; 1239a703e490SVasu Dev struct sk_buff *skb; 1240a703e490SVasu Dev struct fcoe_crc_eof crc_eof; 1241a703e490SVasu Dev struct fc_frame *fp; 1242a703e490SVasu Dev u8 *mac = NULL; 1243a703e490SVasu Dev struct fcoe_softc *fc; 1244a703e490SVasu Dev struct fcoe_hdr *hp; 1245a703e490SVasu Dev 1246a703e490SVasu Dev set_user_nice(current, -20); 1247a703e490SVasu Dev 1248a703e490SVasu Dev while (!kthread_should_stop()) { 1249a703e490SVasu Dev 1250a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1251a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) { 1252a703e490SVasu Dev set_current_state(TASK_INTERRUPTIBLE); 1253a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1254a703e490SVasu Dev schedule(); 1255a703e490SVasu Dev set_current_state(TASK_RUNNING); 1256a703e490SVasu Dev if (kthread_should_stop()) 1257a703e490SVasu Dev return 0; 1258a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1259a703e490SVasu Dev } 1260a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1261a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 1262a703e490SVasu Dev lp = fr->fr_dev; 1263a703e490SVasu Dev if (unlikely(lp == NULL)) { 1264d5488eb9SRobert Love FCOE_NETDEV_DBG(skb->dev, "Invalid HBA Structure"); 1265a703e490SVasu Dev kfree_skb(skb); 1266a703e490SVasu Dev continue; 1267a703e490SVasu Dev } 1268a703e490SVasu Dev 1269d5488eb9SRobert Love FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d " 1270d5488eb9SRobert Love "head:%p data:%p tail:%p end:%p sum:%d dev:%s", 1271a703e490SVasu Dev skb->len, skb->data_len, 1272a703e490SVasu Dev skb->head, skb->data, skb_tail_pointer(skb), 1273a703e490SVasu Dev skb_end_pointer(skb), skb->csum, 1274a703e490SVasu Dev skb->dev ? skb->dev->name : "<NULL>"); 1275a703e490SVasu Dev 1276a703e490SVasu Dev /* 1277a703e490SVasu Dev * Save source MAC address before discarding header. 1278a703e490SVasu Dev */ 1279a703e490SVasu Dev fc = lport_priv(lp); 1280a703e490SVasu Dev if (skb_is_nonlinear(skb)) 1281a703e490SVasu Dev skb_linearize(skb); /* not ideal */ 128297c8389dSJoe Eykholt mac = eth_hdr(skb)->h_source; 1283a703e490SVasu Dev 1284a703e490SVasu Dev /* 1285a703e490SVasu Dev * Frame length checks and setting up the header pointers 1286a703e490SVasu Dev * was done in fcoe_rcv already. 1287a703e490SVasu Dev */ 1288a703e490SVasu Dev hp = (struct fcoe_hdr *) skb_network_header(skb); 1289a703e490SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 1290a703e490SVasu Dev 1291a703e490SVasu Dev stats = fc_lport_get_stats(lp); 1292a703e490SVasu Dev if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { 1293a703e490SVasu Dev if (stats->ErrorFrames < 5) 1294d5488eb9SRobert Love printk(KERN_WARNING "fcoe: FCoE version " 1295a703e490SVasu Dev "mismatch: The frame has " 1296a703e490SVasu Dev "version %x, but the " 1297a703e490SVasu Dev "initiator supports version " 1298a703e490SVasu Dev "%x\n", FC_FCOE_DECAPS_VER(hp), 1299a703e490SVasu Dev FC_FCOE_VER); 1300a703e490SVasu Dev stats->ErrorFrames++; 1301a703e490SVasu Dev kfree_skb(skb); 1302a703e490SVasu Dev continue; 1303a703e490SVasu Dev } 1304a703e490SVasu Dev 1305a703e490SVasu Dev skb_pull(skb, sizeof(struct fcoe_hdr)); 1306a703e490SVasu Dev fr_len = skb->len - sizeof(struct fcoe_crc_eof); 1307a703e490SVasu Dev 1308a703e490SVasu Dev stats->RxFrames++; 1309a703e490SVasu Dev stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; 1310a703e490SVasu Dev 1311a703e490SVasu Dev fp = (struct fc_frame *)skb; 1312a703e490SVasu Dev fc_frame_init(fp); 1313a703e490SVasu Dev fr_dev(fp) = lp; 1314a703e490SVasu Dev fr_sof(fp) = hp->fcoe_sof; 1315a703e490SVasu Dev 1316a703e490SVasu Dev /* Copy out the CRC and EOF trailer for access */ 1317a703e490SVasu Dev if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { 1318a703e490SVasu Dev kfree_skb(skb); 1319a703e490SVasu Dev continue; 1320a703e490SVasu Dev } 1321a703e490SVasu Dev fr_eof(fp) = crc_eof.fcoe_eof; 1322a703e490SVasu Dev fr_crc(fp) = crc_eof.fcoe_crc32; 1323a703e490SVasu Dev if (pskb_trim(skb, fr_len)) { 1324a703e490SVasu Dev kfree_skb(skb); 1325a703e490SVasu Dev continue; 1326a703e490SVasu Dev } 1327a703e490SVasu Dev 1328a703e490SVasu Dev /* 1329a703e490SVasu Dev * We only check CRC if no offload is available and if it is 1330a703e490SVasu Dev * it's solicited data, in which case, the FCP layer would 1331a703e490SVasu Dev * check it during the copy. 1332a703e490SVasu Dev */ 1333a703e490SVasu Dev if (lp->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY) 1334a703e490SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 1335a703e490SVasu Dev else 1336a703e490SVasu Dev fr_flags(fp) |= FCPHF_CRC_UNCHECKED; 1337a703e490SVasu Dev 1338a703e490SVasu Dev fh = fc_frame_header_get(fp); 1339a703e490SVasu Dev if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && 1340a703e490SVasu Dev fh->fh_type == FC_TYPE_FCP) { 134152ff878cSVasu Dev fc_exch_recv(lp, fp); 1342a703e490SVasu Dev continue; 1343a703e490SVasu Dev } 1344a703e490SVasu Dev if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { 1345a703e490SVasu Dev if (le32_to_cpu(fr_crc(fp)) != 1346a703e490SVasu Dev ~crc32(~0, skb->data, fr_len)) { 1347d5488eb9SRobert Love if (stats->InvalidCRCCount < 5) 1348a703e490SVasu Dev printk(KERN_WARNING "fcoe: dropping " 1349a703e490SVasu Dev "frame with CRC error\n"); 1350a703e490SVasu Dev stats->InvalidCRCCount++; 1351a703e490SVasu Dev stats->ErrorFrames++; 1352a703e490SVasu Dev fc_frame_free(fp); 1353a703e490SVasu Dev continue; 1354a703e490SVasu Dev } 1355a703e490SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 1356a703e490SVasu Dev } 135797c8389dSJoe Eykholt if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN) && 135897c8389dSJoe Eykholt fcoe_ctlr_recv_flogi(&fc->ctlr, fp, mac)) { 135997c8389dSJoe Eykholt fc_frame_free(fp); 136097c8389dSJoe Eykholt continue; 136197c8389dSJoe Eykholt } 136252ff878cSVasu Dev fc_exch_recv(lp, fp); 1363a703e490SVasu Dev } 1364a703e490SVasu Dev return 0; 1365a703e490SVasu Dev } 1366a703e490SVasu Dev 1367a703e490SVasu Dev /** 1368dd3fd72eSChris Leech * fcoe_check_wait_queue() - attempt to clear the transmit backlog 1369dd3fd72eSChris Leech * @lp: the fc_lport 1370a703e490SVasu Dev * 1371a703e490SVasu Dev * This empties the wait_queue, dequeue the head of the wait_queue queue 1372a703e490SVasu Dev * and calls fcoe_start_io() for each packet, if all skb have been 1373a703e490SVasu Dev * transmitted, return qlen or -1 if a error occurs, then restore 1374a703e490SVasu Dev * wait_queue and try again later. 1375a703e490SVasu Dev * 1376a703e490SVasu Dev * The wait_queue is used when the skb transmit fails. skb will go 1377dd3fd72eSChris Leech * in the wait_queue which will be emptied by the timer function or 1378a703e490SVasu Dev * by the next skb transmit. 1379a703e490SVasu Dev */ 13804bb6b515SVasu Dev static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb) 1381a703e490SVasu Dev { 1382a703e490SVasu Dev struct fcoe_softc *fc = lport_priv(lp); 13834bb6b515SVasu Dev int rc; 1384a703e490SVasu Dev 1385a703e490SVasu Dev spin_lock_bh(&fc->fcoe_pending_queue.lock); 13864bb6b515SVasu Dev 13874bb6b515SVasu Dev if (skb) 13884bb6b515SVasu Dev __skb_queue_tail(&fc->fcoe_pending_queue, skb); 13894bb6b515SVasu Dev 1390a703e490SVasu Dev if (fc->fcoe_pending_queue_active) 1391a703e490SVasu Dev goto out; 1392a703e490SVasu Dev fc->fcoe_pending_queue_active = 1; 1393a703e490SVasu Dev 1394a703e490SVasu Dev while (fc->fcoe_pending_queue.qlen) { 1395a703e490SVasu Dev /* keep qlen > 0 until fcoe_start_io succeeds */ 1396a703e490SVasu Dev fc->fcoe_pending_queue.qlen++; 1397a703e490SVasu Dev skb = __skb_dequeue(&fc->fcoe_pending_queue); 1398a703e490SVasu Dev 1399a703e490SVasu Dev spin_unlock_bh(&fc->fcoe_pending_queue.lock); 1400a703e490SVasu Dev rc = fcoe_start_io(skb); 1401a703e490SVasu Dev spin_lock_bh(&fc->fcoe_pending_queue.lock); 1402a703e490SVasu Dev 1403a703e490SVasu Dev if (rc) { 1404a703e490SVasu Dev __skb_queue_head(&fc->fcoe_pending_queue, skb); 1405a703e490SVasu Dev /* undo temporary increment above */ 1406a703e490SVasu Dev fc->fcoe_pending_queue.qlen--; 1407a703e490SVasu Dev break; 1408a703e490SVasu Dev } 1409a703e490SVasu Dev /* undo temporary increment above */ 1410a703e490SVasu Dev fc->fcoe_pending_queue.qlen--; 1411a703e490SVasu Dev } 1412a703e490SVasu Dev 1413a703e490SVasu Dev if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH) 1414a703e490SVasu Dev lp->qfull = 0; 14151047f221SVasu Dev if (fc->fcoe_pending_queue.qlen && !timer_pending(&fc->timer)) 14161047f221SVasu Dev mod_timer(&fc->timer, jiffies + 2); 1417a703e490SVasu Dev fc->fcoe_pending_queue_active = 0; 1418a703e490SVasu Dev out: 14194bb6b515SVasu Dev if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) 14204bb6b515SVasu Dev lp->qfull = 1; 1421a703e490SVasu Dev spin_unlock_bh(&fc->fcoe_pending_queue.lock); 14224bb6b515SVasu Dev return; 1423a703e490SVasu Dev } 1424a703e490SVasu Dev 1425a703e490SVasu Dev /** 1426a703e490SVasu Dev * fcoe_dev_setup() - setup link change notification interface 1427a703e490SVasu Dev */ 1428b0d428adSRandy Dunlap static void fcoe_dev_setup(void) 1429a703e490SVasu Dev { 1430a703e490SVasu Dev register_netdevice_notifier(&fcoe_notifier); 1431a703e490SVasu Dev } 1432a703e490SVasu Dev 1433a703e490SVasu Dev /** 1434b0d428adSRandy Dunlap * fcoe_dev_cleanup() - cleanup link change notification interface 1435a703e490SVasu Dev */ 1436a703e490SVasu Dev static void fcoe_dev_cleanup(void) 1437a703e490SVasu Dev { 1438a703e490SVasu Dev unregister_netdevice_notifier(&fcoe_notifier); 1439a703e490SVasu Dev } 1440a703e490SVasu Dev 1441a703e490SVasu Dev /** 1442a703e490SVasu Dev * fcoe_device_notification() - netdev event notification callback 1443a703e490SVasu Dev * @notifier: context of the notification 1444a703e490SVasu Dev * @event: type of event 1445a703e490SVasu Dev * @ptr: fixed array for output parsed ifname 1446a703e490SVasu Dev * 1447a703e490SVasu Dev * This function is called by the ethernet driver in case of link change event 1448a703e490SVasu Dev * 1449a703e490SVasu Dev * Returns: 0 for success 1450a703e490SVasu Dev */ 1451a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *notifier, 1452a703e490SVasu Dev ulong event, void *ptr) 1453a703e490SVasu Dev { 1454a703e490SVasu Dev struct fc_lport *lp = NULL; 14551d1b88dcSVasu Dev struct net_device *netdev = ptr; 1456a703e490SVasu Dev struct fcoe_softc *fc; 1457a703e490SVasu Dev struct fcoe_dev_stats *stats; 145897c8389dSJoe Eykholt u32 link_possible = 1; 1459a703e490SVasu Dev u32 mfs; 1460a703e490SVasu Dev int rc = NOTIFY_OK; 1461a703e490SVasu Dev 1462a703e490SVasu Dev read_lock(&fcoe_hostlist_lock); 1463a703e490SVasu Dev list_for_each_entry(fc, &fcoe_hostlist, list) { 14641d1b88dcSVasu Dev if (fc->netdev == netdev) { 146597c8389dSJoe Eykholt lp = fc->ctlr.lp; 1466a703e490SVasu Dev break; 1467a703e490SVasu Dev } 1468a703e490SVasu Dev } 1469a703e490SVasu Dev read_unlock(&fcoe_hostlist_lock); 1470a703e490SVasu Dev if (lp == NULL) { 1471a703e490SVasu Dev rc = NOTIFY_DONE; 1472a703e490SVasu Dev goto out; 1473a703e490SVasu Dev } 1474a703e490SVasu Dev 1475a703e490SVasu Dev switch (event) { 1476a703e490SVasu Dev case NETDEV_DOWN: 1477a703e490SVasu Dev case NETDEV_GOING_DOWN: 147897c8389dSJoe Eykholt link_possible = 0; 1479a703e490SVasu Dev break; 1480a703e490SVasu Dev case NETDEV_UP: 1481a703e490SVasu Dev case NETDEV_CHANGE: 1482a703e490SVasu Dev break; 1483a703e490SVasu Dev case NETDEV_CHANGEMTU: 14841d1b88dcSVasu Dev mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + 1485a703e490SVasu Dev sizeof(struct fcoe_crc_eof)); 1486a703e490SVasu Dev if (mfs >= FC_MIN_MAX_FRAME) 1487a703e490SVasu Dev fc_set_mfs(lp, mfs); 1488a703e490SVasu Dev break; 1489a703e490SVasu Dev case NETDEV_REGISTER: 1490a703e490SVasu Dev break; 1491a703e490SVasu Dev default: 14921d1b88dcSVasu Dev FCOE_NETDEV_DBG(netdev, "Unknown event %ld " 1493d5488eb9SRobert Love "from netdev netlink\n", event); 1494a703e490SVasu Dev } 149597c8389dSJoe Eykholt if (link_possible && !fcoe_link_ok(lp)) 149697c8389dSJoe Eykholt fcoe_ctlr_link_up(&fc->ctlr); 149797c8389dSJoe Eykholt else if (fcoe_ctlr_link_down(&fc->ctlr)) { 1498a703e490SVasu Dev stats = fc_lport_get_stats(lp); 1499a703e490SVasu Dev stats->LinkFailureCount++; 1500a703e490SVasu Dev fcoe_clean_pending_queue(lp); 1501a703e490SVasu Dev } 1502a703e490SVasu Dev out: 1503a703e490SVasu Dev return rc; 1504a703e490SVasu Dev } 1505a703e490SVasu Dev 1506a703e490SVasu Dev /** 1507a703e490SVasu Dev * fcoe_if_to_netdev() - parse a name buffer to get netdev 1508a703e490SVasu Dev * @buffer: incoming buffer to be copied 1509a703e490SVasu Dev * 1510dd3fd72eSChris Leech * Returns: NULL or ptr to net_device 1511a703e490SVasu Dev */ 1512a703e490SVasu Dev static struct net_device *fcoe_if_to_netdev(const char *buffer) 1513a703e490SVasu Dev { 1514a703e490SVasu Dev char *cp; 1515a703e490SVasu Dev char ifname[IFNAMSIZ + 2]; 1516a703e490SVasu Dev 1517a703e490SVasu Dev if (buffer) { 1518a703e490SVasu Dev strlcpy(ifname, buffer, IFNAMSIZ); 1519a703e490SVasu Dev cp = ifname + strlen(ifname); 1520a703e490SVasu Dev while (--cp >= ifname && *cp == '\n') 1521a703e490SVasu Dev *cp = '\0'; 1522a703e490SVasu Dev return dev_get_by_name(&init_net, ifname); 1523a703e490SVasu Dev } 1524a703e490SVasu Dev return NULL; 1525a703e490SVasu Dev } 1526a703e490SVasu Dev 1527a703e490SVasu Dev /** 1528dd3fd72eSChris Leech * fcoe_netdev_to_module_owner() - finds out the driver module of the netdev 1529a703e490SVasu Dev * @netdev: the target netdev 1530a703e490SVasu Dev * 1531a703e490SVasu Dev * Returns: ptr to the struct module, NULL for failure 1532a703e490SVasu Dev */ 1533a703e490SVasu Dev static struct module * 1534a703e490SVasu Dev fcoe_netdev_to_module_owner(const struct net_device *netdev) 1535a703e490SVasu Dev { 1536a703e490SVasu Dev struct device *dev; 1537a703e490SVasu Dev 1538a703e490SVasu Dev if (!netdev) 1539a703e490SVasu Dev return NULL; 1540a703e490SVasu Dev 1541a703e490SVasu Dev dev = netdev->dev.parent; 1542a703e490SVasu Dev if (!dev) 1543a703e490SVasu Dev return NULL; 1544a703e490SVasu Dev 1545a703e490SVasu Dev if (!dev->driver) 1546a703e490SVasu Dev return NULL; 1547a703e490SVasu Dev 1548a703e490SVasu Dev return dev->driver->owner; 1549a703e490SVasu Dev } 1550a703e490SVasu Dev 1551a703e490SVasu Dev /** 1552a703e490SVasu Dev * fcoe_ethdrv_get() - Hold the Ethernet driver 1553a703e490SVasu Dev * @netdev: the target netdev 1554a703e490SVasu Dev * 1555a703e490SVasu Dev * Holds the Ethernet driver module by try_module_get() for 1556a703e490SVasu Dev * the corresponding netdev. 1557a703e490SVasu Dev * 1558dd3fd72eSChris Leech * Returns: 0 for success 1559a703e490SVasu Dev */ 1560a703e490SVasu Dev static int fcoe_ethdrv_get(const struct net_device *netdev) 1561a703e490SVasu Dev { 1562a703e490SVasu Dev struct module *owner; 1563a703e490SVasu Dev 1564a703e490SVasu Dev owner = fcoe_netdev_to_module_owner(netdev); 1565a703e490SVasu Dev if (owner) { 1566d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Hold driver module %s\n", 1567d5488eb9SRobert Love module_name(owner)); 1568a703e490SVasu Dev return try_module_get(owner); 1569a703e490SVasu Dev } 1570a703e490SVasu Dev return -ENODEV; 1571a703e490SVasu Dev } 1572a703e490SVasu Dev 1573a703e490SVasu Dev /** 1574a703e490SVasu Dev * fcoe_ethdrv_put() - Release the Ethernet driver 1575a703e490SVasu Dev * @netdev: the target netdev 1576a703e490SVasu Dev * 1577a703e490SVasu Dev * Releases the Ethernet driver module by module_put for 1578a703e490SVasu Dev * the corresponding netdev. 1579a703e490SVasu Dev * 1580dd3fd72eSChris Leech * Returns: 0 for success 1581a703e490SVasu Dev */ 1582a703e490SVasu Dev static int fcoe_ethdrv_put(const struct net_device *netdev) 1583a703e490SVasu Dev { 1584a703e490SVasu Dev struct module *owner; 1585a703e490SVasu Dev 1586a703e490SVasu Dev owner = fcoe_netdev_to_module_owner(netdev); 1587a703e490SVasu Dev if (owner) { 1588d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Release driver module %s\n", 1589d5488eb9SRobert Love module_name(owner)); 1590a703e490SVasu Dev module_put(owner); 1591a703e490SVasu Dev return 0; 1592a703e490SVasu Dev } 1593a703e490SVasu Dev return -ENODEV; 1594a703e490SVasu Dev } 1595a703e490SVasu Dev 1596a703e490SVasu Dev /** 1597a703e490SVasu Dev * fcoe_destroy() - handles the destroy from sysfs 1598dd3fd72eSChris Leech * @buffer: expected to be an eth if name 1599a703e490SVasu Dev * @kp: associated kernel param 1600a703e490SVasu Dev * 1601a703e490SVasu Dev * Returns: 0 for success 1602a703e490SVasu Dev */ 1603a703e490SVasu Dev static int fcoe_destroy(const char *buffer, struct kernel_param *kp) 1604a703e490SVasu Dev { 1605a703e490SVasu Dev struct net_device *netdev; 1606af7f85d9SChris Leech struct fc_lport *lport; 1607af7f85d9SChris Leech int rc; 1608a703e490SVasu Dev 1609a703e490SVasu Dev netdev = fcoe_if_to_netdev(buffer); 1610a703e490SVasu Dev if (!netdev) { 1611a703e490SVasu Dev rc = -ENODEV; 1612a703e490SVasu Dev goto out_nodev; 1613a703e490SVasu Dev } 1614a703e490SVasu Dev /* look for existing lport */ 1615af7f85d9SChris Leech lport = fcoe_hostlist_lookup(netdev); 1616af7f85d9SChris Leech if (!lport) { 1617a703e490SVasu Dev rc = -ENODEV; 1618a703e490SVasu Dev goto out_putdev; 1619a703e490SVasu Dev } 1620af7f85d9SChris Leech fcoe_if_destroy(lport); 1621a703e490SVasu Dev fcoe_ethdrv_put(netdev); 1622a703e490SVasu Dev rc = 0; 1623a703e490SVasu Dev out_putdev: 1624a703e490SVasu Dev dev_put(netdev); 1625a703e490SVasu Dev out_nodev: 1626a703e490SVasu Dev return rc; 1627a703e490SVasu Dev } 1628a703e490SVasu Dev 1629a703e490SVasu Dev /** 1630a703e490SVasu Dev * fcoe_create() - Handles the create call from sysfs 1631dd3fd72eSChris Leech * @buffer: expected to be an eth if name 1632a703e490SVasu Dev * @kp: associated kernel param 1633a703e490SVasu Dev * 1634a703e490SVasu Dev * Returns: 0 for success 1635a703e490SVasu Dev */ 1636a703e490SVasu Dev static int fcoe_create(const char *buffer, struct kernel_param *kp) 1637a703e490SVasu Dev { 1638a703e490SVasu Dev int rc; 1639af7f85d9SChris Leech struct fc_lport *lport; 1640a703e490SVasu Dev struct net_device *netdev; 1641a703e490SVasu Dev 1642a703e490SVasu Dev netdev = fcoe_if_to_netdev(buffer); 1643a703e490SVasu Dev if (!netdev) { 1644a703e490SVasu Dev rc = -ENODEV; 1645a703e490SVasu Dev goto out_nodev; 1646a703e490SVasu Dev } 1647a703e490SVasu Dev /* look for existing lport */ 1648a703e490SVasu Dev if (fcoe_hostlist_lookup(netdev)) { 1649a703e490SVasu Dev rc = -EEXIST; 1650a703e490SVasu Dev goto out_putdev; 1651a703e490SVasu Dev } 1652a703e490SVasu Dev fcoe_ethdrv_get(netdev); 1653a703e490SVasu Dev 1654af7f85d9SChris Leech lport = fcoe_if_create(netdev, &netdev->dev); 1655af7f85d9SChris Leech if (IS_ERR(lport)) { 1656d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", 1657a703e490SVasu Dev netdev->name); 1658a703e490SVasu Dev fcoe_ethdrv_put(netdev); 1659a703e490SVasu Dev rc = -EIO; 1660a703e490SVasu Dev goto out_putdev; 1661a703e490SVasu Dev } 1662a703e490SVasu Dev rc = 0; 1663a703e490SVasu Dev out_putdev: 1664a703e490SVasu Dev dev_put(netdev); 1665a703e490SVasu Dev out_nodev: 1666a703e490SVasu Dev return rc; 1667a703e490SVasu Dev } 1668a703e490SVasu Dev 1669a703e490SVasu Dev module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); 1670a703e490SVasu Dev __MODULE_PARM_TYPE(create, "string"); 1671a703e490SVasu Dev MODULE_PARM_DESC(create, "Create fcoe port using net device passed in."); 1672a703e490SVasu Dev module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); 1673a703e490SVasu Dev __MODULE_PARM_TYPE(destroy, "string"); 1674a703e490SVasu Dev MODULE_PARM_DESC(destroy, "Destroy fcoe port"); 1675a703e490SVasu Dev 1676a703e490SVasu Dev /** 1677a703e490SVasu Dev * fcoe_link_ok() - Check if link is ok for the fc_lport 1678a703e490SVasu Dev * @lp: ptr to the fc_lport 1679a703e490SVasu Dev * 1680a703e490SVasu Dev * Any permanently-disqualifying conditions have been previously checked. 1681a703e490SVasu Dev * This also updates the speed setting, which may change with link for 100/1000. 1682a703e490SVasu Dev * 1683a703e490SVasu Dev * This function should probably be checking for PAUSE support at some point 1684a703e490SVasu Dev * in the future. Currently Per-priority-pause is not determinable using 1685a703e490SVasu Dev * ethtool, so we shouldn't be restrictive until that problem is resolved. 1686a703e490SVasu Dev * 1687a703e490SVasu Dev * Returns: 0 if link is OK for use by FCoE. 1688a703e490SVasu Dev * 1689a703e490SVasu Dev */ 1690a703e490SVasu Dev int fcoe_link_ok(struct fc_lport *lp) 1691a703e490SVasu Dev { 1692a703e490SVasu Dev struct fcoe_softc *fc = lport_priv(lp); 16931d1b88dcSVasu Dev struct net_device *dev = fc->netdev; 1694a703e490SVasu Dev struct ethtool_cmd ecmd = { ETHTOOL_GSET }; 1695a703e490SVasu Dev 16962f718d64SYi Zou if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && 16972f718d64SYi Zou (!dev_ethtool_get_settings(dev, &ecmd))) { 1698a703e490SVasu Dev lp->link_supported_speeds &= 1699a703e490SVasu Dev ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); 1700a703e490SVasu Dev if (ecmd.supported & (SUPPORTED_1000baseT_Half | 1701a703e490SVasu Dev SUPPORTED_1000baseT_Full)) 1702a703e490SVasu Dev lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; 1703a703e490SVasu Dev if (ecmd.supported & SUPPORTED_10000baseT_Full) 1704a703e490SVasu Dev lp->link_supported_speeds |= 1705a703e490SVasu Dev FC_PORTSPEED_10GBIT; 1706a703e490SVasu Dev if (ecmd.speed == SPEED_1000) 1707a703e490SVasu Dev lp->link_speed = FC_PORTSPEED_1GBIT; 1708a703e490SVasu Dev if (ecmd.speed == SPEED_10000) 1709a703e490SVasu Dev lp->link_speed = FC_PORTSPEED_10GBIT; 1710a703e490SVasu Dev 17112f718d64SYi Zou return 0; 17122f718d64SYi Zou } 17132f718d64SYi Zou return -1; 1714a703e490SVasu Dev } 1715a703e490SVasu Dev 1716a703e490SVasu Dev /** 1717a703e490SVasu Dev * fcoe_percpu_clean() - Clear the pending skbs for an lport 1718a703e490SVasu Dev * @lp: the fc_lport 1719a703e490SVasu Dev */ 1720a703e490SVasu Dev void fcoe_percpu_clean(struct fc_lport *lp) 1721a703e490SVasu Dev { 1722a703e490SVasu Dev struct fcoe_percpu_s *pp; 1723a703e490SVasu Dev struct fcoe_rcv_info *fr; 1724a703e490SVasu Dev struct sk_buff_head *list; 1725a703e490SVasu Dev struct sk_buff *skb, *next; 1726a703e490SVasu Dev struct sk_buff *head; 1727a703e490SVasu Dev unsigned int cpu; 1728a703e490SVasu Dev 1729a703e490SVasu Dev for_each_possible_cpu(cpu) { 1730a703e490SVasu Dev pp = &per_cpu(fcoe_percpu, cpu); 1731a703e490SVasu Dev spin_lock_bh(&pp->fcoe_rx_list.lock); 1732a703e490SVasu Dev list = &pp->fcoe_rx_list; 1733a703e490SVasu Dev head = list->next; 1734a703e490SVasu Dev for (skb = head; skb != (struct sk_buff *)list; 1735a703e490SVasu Dev skb = next) { 1736a703e490SVasu Dev next = skb->next; 1737a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 1738a703e490SVasu Dev if (fr->fr_dev == lp) { 1739a703e490SVasu Dev __skb_unlink(skb, list); 1740a703e490SVasu Dev kfree_skb(skb); 1741a703e490SVasu Dev } 1742a703e490SVasu Dev } 1743a703e490SVasu Dev spin_unlock_bh(&pp->fcoe_rx_list.lock); 1744a703e490SVasu Dev } 1745a703e490SVasu Dev } 1746a703e490SVasu Dev 1747a703e490SVasu Dev /** 1748a703e490SVasu Dev * fcoe_clean_pending_queue() - Dequeue a skb and free it 1749a703e490SVasu Dev * @lp: the corresponding fc_lport 1750a703e490SVasu Dev * 1751a703e490SVasu Dev * Returns: none 1752a703e490SVasu Dev */ 1753a703e490SVasu Dev void fcoe_clean_pending_queue(struct fc_lport *lp) 1754a703e490SVasu Dev { 1755a703e490SVasu Dev struct fcoe_softc *fc = lport_priv(lp); 1756a703e490SVasu Dev struct sk_buff *skb; 1757a703e490SVasu Dev 1758a703e490SVasu Dev spin_lock_bh(&fc->fcoe_pending_queue.lock); 1759a703e490SVasu Dev while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { 1760a703e490SVasu Dev spin_unlock_bh(&fc->fcoe_pending_queue.lock); 1761a703e490SVasu Dev kfree_skb(skb); 1762a703e490SVasu Dev spin_lock_bh(&fc->fcoe_pending_queue.lock); 1763a703e490SVasu Dev } 1764a703e490SVasu Dev spin_unlock_bh(&fc->fcoe_pending_queue.lock); 1765a703e490SVasu Dev } 1766a703e490SVasu Dev 1767a703e490SVasu Dev /** 1768a703e490SVasu Dev * fcoe_reset() - Resets the fcoe 1769a703e490SVasu Dev * @shost: shost the reset is from 1770a703e490SVasu Dev * 1771a703e490SVasu Dev * Returns: always 0 1772a703e490SVasu Dev */ 1773a703e490SVasu Dev int fcoe_reset(struct Scsi_Host *shost) 1774a703e490SVasu Dev { 1775a703e490SVasu Dev struct fc_lport *lport = shost_priv(shost); 1776a703e490SVasu Dev fc_lport_reset(lport); 1777a703e490SVasu Dev return 0; 1778a703e490SVasu Dev } 1779a703e490SVasu Dev 1780a703e490SVasu Dev /** 1781a703e490SVasu Dev * fcoe_hostlist_lookup_softc() - find the corresponding lport by a given device 1782dd3fd72eSChris Leech * @dev: this is currently ptr to net_device 1783a703e490SVasu Dev * 1784e8af4d43SVasu Dev * Called with fcoe_hostlist_lock held. 1785e8af4d43SVasu Dev * 1786a703e490SVasu Dev * Returns: NULL or the located fcoe_softc 1787a703e490SVasu Dev */ 1788a703e490SVasu Dev static struct fcoe_softc * 1789a703e490SVasu Dev fcoe_hostlist_lookup_softc(const struct net_device *dev) 1790a703e490SVasu Dev { 1791a703e490SVasu Dev struct fcoe_softc *fc; 1792a703e490SVasu Dev 1793a703e490SVasu Dev list_for_each_entry(fc, &fcoe_hostlist, list) { 17941d1b88dcSVasu Dev if (fc->netdev == dev) 1795a703e490SVasu Dev return fc; 1796a703e490SVasu Dev } 1797a703e490SVasu Dev return NULL; 1798a703e490SVasu Dev } 1799a703e490SVasu Dev 1800a703e490SVasu Dev /** 1801a703e490SVasu Dev * fcoe_hostlist_lookup() - Find the corresponding lport by netdev 1802a703e490SVasu Dev * @netdev: ptr to net_device 1803a703e490SVasu Dev * 1804a703e490SVasu Dev * Returns: 0 for success 1805a703e490SVasu Dev */ 1806a703e490SVasu Dev struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) 1807a703e490SVasu Dev { 1808a703e490SVasu Dev struct fcoe_softc *fc; 1809a703e490SVasu Dev 1810e8af4d43SVasu Dev read_lock(&fcoe_hostlist_lock); 1811a703e490SVasu Dev fc = fcoe_hostlist_lookup_softc(netdev); 1812e8af4d43SVasu Dev read_unlock(&fcoe_hostlist_lock); 1813a703e490SVasu Dev 181497c8389dSJoe Eykholt return (fc) ? fc->ctlr.lp : NULL; 1815a703e490SVasu Dev } 1816a703e490SVasu Dev 1817a703e490SVasu Dev /** 1818a703e490SVasu Dev * fcoe_hostlist_add() - Add a lport to lports list 1819dd3fd72eSChris Leech * @lp: ptr to the fc_lport to be added 1820a703e490SVasu Dev * 1821e8af4d43SVasu Dev * Called with write fcoe_hostlist_lock held. 1822e8af4d43SVasu Dev * 1823a703e490SVasu Dev * Returns: 0 for success 1824a703e490SVasu Dev */ 1825a703e490SVasu Dev int fcoe_hostlist_add(const struct fc_lport *lp) 1826a703e490SVasu Dev { 1827a703e490SVasu Dev struct fcoe_softc *fc; 1828a703e490SVasu Dev 1829a703e490SVasu Dev fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); 1830a703e490SVasu Dev if (!fc) { 1831a703e490SVasu Dev fc = lport_priv(lp); 1832a703e490SVasu Dev list_add_tail(&fc->list, &fcoe_hostlist); 1833a703e490SVasu Dev } 1834a703e490SVasu Dev return 0; 1835a703e490SVasu Dev } 1836a703e490SVasu Dev 1837a703e490SVasu Dev /** 1838a703e490SVasu Dev * fcoe_hostlist_remove() - remove a lport from lports list 1839dd3fd72eSChris Leech * @lp: ptr to the fc_lport to be removed 1840a703e490SVasu Dev * 1841a703e490SVasu Dev * Returns: 0 for success 1842a703e490SVasu Dev */ 1843a703e490SVasu Dev int fcoe_hostlist_remove(const struct fc_lport *lp) 1844a703e490SVasu Dev { 1845a703e490SVasu Dev struct fcoe_softc *fc; 1846a703e490SVasu Dev 1847e8af4d43SVasu Dev write_lock_bh(&fcoe_hostlist_lock); 1848a703e490SVasu Dev fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); 1849a703e490SVasu Dev BUG_ON(!fc); 1850a703e490SVasu Dev list_del(&fc->list); 1851a703e490SVasu Dev write_unlock_bh(&fcoe_hostlist_lock); 1852a703e490SVasu Dev 1853a703e490SVasu Dev return 0; 1854a703e490SVasu Dev } 1855a703e490SVasu Dev 1856a703e490SVasu Dev /** 1857a703e490SVasu Dev * fcoe_init() - fcoe module loading initialization 1858a703e490SVasu Dev * 1859a703e490SVasu Dev * Returns 0 on success, negative on failure 1860a703e490SVasu Dev */ 1861a703e490SVasu Dev static int __init fcoe_init(void) 1862a703e490SVasu Dev { 1863a703e490SVasu Dev unsigned int cpu; 1864a703e490SVasu Dev int rc = 0; 1865a703e490SVasu Dev struct fcoe_percpu_s *p; 1866a703e490SVasu Dev 1867a703e490SVasu Dev for_each_possible_cpu(cpu) { 1868a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 1869a703e490SVasu Dev skb_queue_head_init(&p->fcoe_rx_list); 1870a703e490SVasu Dev } 1871a703e490SVasu Dev 1872a703e490SVasu Dev for_each_online_cpu(cpu) 1873a703e490SVasu Dev fcoe_percpu_thread_create(cpu); 1874a703e490SVasu Dev 1875a703e490SVasu Dev /* Initialize per CPU interrupt thread */ 1876a703e490SVasu Dev rc = register_hotcpu_notifier(&fcoe_cpu_notifier); 1877a703e490SVasu Dev if (rc) 1878a703e490SVasu Dev goto out_free; 1879a703e490SVasu Dev 1880a703e490SVasu Dev /* Setup link change notification */ 1881a703e490SVasu Dev fcoe_dev_setup(); 1882a703e490SVasu Dev 18835892c32fSChris Leech rc = fcoe_if_init(); 18845892c32fSChris Leech if (rc) 18855892c32fSChris Leech goto out_free; 1886a703e490SVasu Dev 1887a703e490SVasu Dev return 0; 1888a703e490SVasu Dev 1889a703e490SVasu Dev out_free: 1890a703e490SVasu Dev for_each_online_cpu(cpu) { 1891a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 1892a703e490SVasu Dev } 1893a703e490SVasu Dev 1894a703e490SVasu Dev return rc; 1895a703e490SVasu Dev } 1896a703e490SVasu Dev module_init(fcoe_init); 1897a703e490SVasu Dev 1898a703e490SVasu Dev /** 1899a703e490SVasu Dev * fcoe_exit() - fcoe module unloading cleanup 1900a703e490SVasu Dev * 1901a703e490SVasu Dev * Returns 0 on success, negative on failure 1902a703e490SVasu Dev */ 1903a703e490SVasu Dev static void __exit fcoe_exit(void) 1904a703e490SVasu Dev { 1905a703e490SVasu Dev unsigned int cpu; 1906a703e490SVasu Dev struct fcoe_softc *fc, *tmp; 1907a703e490SVasu Dev 1908a703e490SVasu Dev fcoe_dev_cleanup(); 1909a703e490SVasu Dev 1910a703e490SVasu Dev /* releases the associated fcoe hosts */ 1911a703e490SVasu Dev list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) 1912af7f85d9SChris Leech fcoe_if_destroy(fc->ctlr.lp); 1913a703e490SVasu Dev 1914a703e490SVasu Dev unregister_hotcpu_notifier(&fcoe_cpu_notifier); 1915a703e490SVasu Dev 1916a703e490SVasu Dev for_each_online_cpu(cpu) { 1917a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 1918a703e490SVasu Dev } 1919a703e490SVasu Dev 1920a703e490SVasu Dev /* detach from scsi transport */ 1921a703e490SVasu Dev fcoe_if_exit(); 1922a703e490SVasu Dev } 1923a703e490SVasu Dev module_exit(fcoe_exit); 1924