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