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/spinlock.h> 22a703e490SVasu Dev #include <linux/netdevice.h> 23a703e490SVasu Dev #include <linux/etherdevice.h> 24a703e490SVasu Dev #include <linux/ethtool.h> 25a703e490SVasu Dev #include <linux/if_ether.h> 26a703e490SVasu Dev #include <linux/if_vlan.h> 27a703e490SVasu Dev #include <linux/crc32.h> 285a0e3ad6STejun Heo #include <linux/slab.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> 332ca32b48STejun Heo #include <linux/workqueue.h> 346f6c2aa3Sjohn fastabend #include <net/dcbnl.h> 356f6c2aa3Sjohn fastabend #include <net/dcbevent.h> 36a703e490SVasu Dev #include <scsi/scsi_tcq.h> 37a703e490SVasu Dev #include <scsi/scsicam.h> 38a703e490SVasu Dev #include <scsi/scsi_transport.h> 39a703e490SVasu Dev #include <scsi/scsi_transport_fc.h> 40a703e490SVasu Dev #include <net/rtnetlink.h> 41a703e490SVasu Dev 42a703e490SVasu Dev #include <scsi/fc/fc_encaps.h> 4397c8389dSJoe Eykholt #include <scsi/fc/fc_fip.h> 448d55e507SRobert Love #include <scsi/fc/fc_fcoe.h> 45a703e490SVasu Dev 46a703e490SVasu Dev #include <scsi/libfc.h> 47a703e490SVasu Dev #include <scsi/fc_frame.h> 48a703e490SVasu Dev #include <scsi/libfcoe.h> 49a703e490SVasu Dev 50fdd78027SVasu Dev #include "fcoe.h" 51fdd78027SVasu Dev 52a703e490SVasu Dev MODULE_AUTHOR("Open-FCoE.org"); 53a703e490SVasu Dev MODULE_DESCRIPTION("FCoE"); 549b34ecffSVasu Dev MODULE_LICENSE("GPL v2"); 55a703e490SVasu Dev 5605cc7390SYi Zou /* Performance tuning parameters for fcoe */ 57860eca2bSVasu Dev static unsigned int fcoe_ddp_min = 4096; 5805cc7390SYi Zou module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR); 5905cc7390SYi Zou MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ 6005cc7390SYi Zou "Direct Data Placement (DDP)."); 6105cc7390SYi Zou 627c9c6841SBart Van Assche unsigned int fcoe_debug_logging; 637c9c6841SBart Van Assche module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); 647c9c6841SBart Van Assche MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); 657c9c6841SBart Van Assche 667c9c6841SBart Van Assche static DEFINE_MUTEX(fcoe_config_mutex); 67dfc1d0feSChris Leech 682ca32b48STejun Heo static struct workqueue_struct *fcoe_wq; 692ca32b48STejun Heo 70e7a51997SJoe Eykholt /* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */ 71e7a51997SJoe Eykholt static DECLARE_COMPLETION(fcoe_flush_completion); 72e7a51997SJoe Eykholt 73a703e490SVasu Dev /* fcoe host list */ 74090eb6c4SChris Leech /* must only by accessed under the RTNL mutex */ 757c9c6841SBart Van Assche static LIST_HEAD(fcoe_hostlist); 767c9c6841SBart Van Assche static DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); 77a703e490SVasu Dev 78dd3fd72eSChris Leech /* Function Prototypes */ 791875f27eSRobert Love static int fcoe_reset(struct Scsi_Host *); 80fdd78027SVasu Dev static int fcoe_xmit(struct fc_lport *, struct fc_frame *); 81fdd78027SVasu Dev static int fcoe_rcv(struct sk_buff *, struct net_device *, 82fdd78027SVasu Dev struct packet_type *, struct net_device *); 831875f27eSRobert Love static int fcoe_percpu_receive_thread(void *); 841875f27eSRobert Love static void fcoe_percpu_clean(struct fc_lport *); 851875f27eSRobert Love static int fcoe_link_ok(struct fc_lport *); 86fdd78027SVasu Dev 87fdd78027SVasu Dev static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); 88fdd78027SVasu Dev static int fcoe_hostlist_add(const struct fc_lport *); 89f9184df3SNeil Horman static void fcoe_hostlist_del(const struct fc_lport *); 90fdd78027SVasu Dev 91a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *, ulong, void *); 92a703e490SVasu Dev static void fcoe_dev_setup(void); 93a703e490SVasu Dev static void fcoe_dev_cleanup(void); 941875f27eSRobert Love static struct fcoe_interface 951875f27eSRobert Love *fcoe_hostlist_lookup_port(const struct net_device *); 96a703e490SVasu Dev 971875f27eSRobert Love static int fcoe_fip_recv(struct sk_buff *, struct net_device *, 981875f27eSRobert Love struct packet_type *, struct net_device *); 991875f27eSRobert Love 1001875f27eSRobert Love static void fcoe_fip_send(struct fcoe_ctlr *, struct sk_buff *); 1011875f27eSRobert Love static void fcoe_update_src_mac(struct fc_lport *, u8 *); 1021875f27eSRobert Love static u8 *fcoe_get_src_mac(struct fc_lport *); 1031875f27eSRobert Love static void fcoe_destroy_work(struct work_struct *); 1041875f27eSRobert Love 1051875f27eSRobert Love static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *, 1061875f27eSRobert Love unsigned int); 1071875f27eSRobert Love static int fcoe_ddp_done(struct fc_lport *, u16); 10871f89491SYi Zou static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, 10971f89491SYi Zou unsigned int); 1101875f27eSRobert Love static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); 1116f6c2aa3Sjohn fastabend static int fcoe_dcb_app_notification(struct notifier_block *notifier, 1126f6c2aa3Sjohn fastabend ulong event, void *ptr); 1131875f27eSRobert Love 11478a58246SYi Zou static bool fcoe_match(struct net_device *netdev); 11578a58246SYi Zou static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode); 11678a58246SYi Zou static int fcoe_destroy(struct net_device *netdev); 11778a58246SYi Zou static int fcoe_enable(struct net_device *netdev); 11878a58246SYi Zou static int fcoe_disable(struct net_device *netdev); 1191875f27eSRobert Love 120435c8667SRobert Love /* fcoe_syfs control interface handlers */ 121435c8667SRobert Love static int fcoe_ctlr_alloc(struct net_device *netdev); 122435c8667SRobert Love static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev); 123435c8667SRobert Love 124435c8667SRobert Love 1251875f27eSRobert Love static struct fc_seq *fcoe_elsct_send(struct fc_lport *, 1261875f27eSRobert Love u32 did, struct fc_frame *, 1271875f27eSRobert Love unsigned int op, 1281875f27eSRobert Love void (*resp)(struct fc_seq *, 1291875f27eSRobert Love struct fc_frame *, 1301875f27eSRobert Love void *), 1311875f27eSRobert Love void *, u32 timeout); 132859b7b64SChris Leech static void fcoe_recv_frame(struct sk_buff *skb); 1331875f27eSRobert Love 1341875f27eSRobert Love /* notification function for packets from net device */ 135a703e490SVasu Dev static struct notifier_block fcoe_notifier = { 136a703e490SVasu Dev .notifier_call = fcoe_device_notification, 137a703e490SVasu Dev }; 138a703e490SVasu Dev 1391875f27eSRobert Love /* notification function for CPU hotplug events */ 1401875f27eSRobert Love static struct notifier_block fcoe_cpu_notifier = { 1411875f27eSRobert Love .notifier_call = fcoe_cpu_callback, 1421875f27eSRobert Love }; 1431875f27eSRobert Love 1446f6c2aa3Sjohn fastabend /* notification function for DCB events */ 1456f6c2aa3Sjohn fastabend static struct notifier_block dcb_notifier = { 1466f6c2aa3Sjohn fastabend .notifier_call = fcoe_dcb_app_notification, 1476f6c2aa3Sjohn fastabend }; 1486f6c2aa3Sjohn fastabend 1498ca86f84SYi Zou static struct scsi_transport_template *fcoe_nport_scsi_transport; 1508ca86f84SYi Zou static struct scsi_transport_template *fcoe_vport_scsi_transport; 151a703e490SVasu Dev 1521875f27eSRobert Love static int fcoe_vport_destroy(struct fc_vport *); 1531875f27eSRobert Love static int fcoe_vport_create(struct fc_vport *, bool disabled); 1541875f27eSRobert Love static int fcoe_vport_disable(struct fc_vport *, bool disable); 1551875f27eSRobert Love static void fcoe_set_vport_symbolic_name(struct fc_vport *); 1567d65b0dfSJoe Eykholt static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); 1578d55e507SRobert Love static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *); 1588d55e507SRobert Love 1598d55e507SRobert Love static struct fcoe_sysfs_function_template fcoe_sysfs_templ = { 160435c8667SRobert Love .set_fcoe_ctlr_mode = fcoe_ctlr_set_fip_mode, 161435c8667SRobert Love .set_fcoe_ctlr_enabled = fcoe_ctlr_enabled, 1628d55e507SRobert Love .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, 1638d55e507SRobert Love .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, 1648d55e507SRobert Love .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb, 1658d55e507SRobert Love .get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb, 1668d55e507SRobert Love .get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb, 1678d55e507SRobert Love .get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb, 1688d55e507SRobert Love 1698d55e507SRobert Love .get_fcoe_fcf_selected = fcoe_fcf_get_selected, 1708d55e507SRobert Love .get_fcoe_fcf_vlan_id = fcoe_fcf_get_vlan_id, 1718d55e507SRobert Love }; 1721875f27eSRobert Love 1731875f27eSRobert Love static struct libfc_function_template fcoe_libfc_fcn_templ = { 1741875f27eSRobert Love .frame_send = fcoe_xmit, 1751875f27eSRobert Love .ddp_setup = fcoe_ddp_setup, 1761875f27eSRobert Love .ddp_done = fcoe_ddp_done, 17771f89491SYi Zou .ddp_target = fcoe_ddp_target, 1781875f27eSRobert Love .elsct_send = fcoe_elsct_send, 179b84056bfSYi Zou .get_lesb = fcoe_get_lesb, 1807d65b0dfSJoe Eykholt .lport_set_port_id = fcoe_set_port_id, 1811875f27eSRobert Love }; 1829a05753bSChris Leech 1837c9c6841SBart Van Assche static struct fc_function_template fcoe_nport_fc_functions = { 184a703e490SVasu Dev .show_host_node_name = 1, 185a703e490SVasu Dev .show_host_port_name = 1, 186a703e490SVasu Dev .show_host_supported_classes = 1, 187a703e490SVasu Dev .show_host_supported_fc4s = 1, 188a703e490SVasu Dev .show_host_active_fc4s = 1, 189a703e490SVasu Dev .show_host_maxframe_size = 1, 1909f71af2fSNeerav Parikh .show_host_serial_number = 1, 1919f71af2fSNeerav Parikh .show_host_manufacturer = 1, 1929f71af2fSNeerav Parikh .show_host_model = 1, 1939f71af2fSNeerav Parikh .show_host_model_description = 1, 1949f71af2fSNeerav Parikh .show_host_hardware_version = 1, 1959f71af2fSNeerav Parikh .show_host_driver_version = 1, 1969f71af2fSNeerav Parikh .show_host_firmware_version = 1, 1979f71af2fSNeerav Parikh .show_host_optionrom_version = 1, 198a703e490SVasu Dev 199a703e490SVasu Dev .show_host_port_id = 1, 200a703e490SVasu Dev .show_host_supported_speeds = 1, 201a703e490SVasu Dev .get_host_speed = fc_get_host_speed, 202a703e490SVasu Dev .show_host_speed = 1, 203a703e490SVasu Dev .show_host_port_type = 1, 204a703e490SVasu Dev .get_host_port_state = fc_get_host_port_state, 205a703e490SVasu Dev .show_host_port_state = 1, 206a703e490SVasu Dev .show_host_symbolic_name = 1, 207a703e490SVasu Dev 208a703e490SVasu Dev .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), 209a703e490SVasu Dev .show_rport_maxframe_size = 1, 210a703e490SVasu Dev .show_rport_supported_classes = 1, 211a703e490SVasu Dev 212a703e490SVasu Dev .show_host_fabric_name = 1, 213a703e490SVasu Dev .show_starget_node_name = 1, 214a703e490SVasu Dev .show_starget_port_name = 1, 215a703e490SVasu Dev .show_starget_port_id = 1, 216a703e490SVasu Dev .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 217a703e490SVasu Dev .show_rport_dev_loss_tmo = 1, 218a703e490SVasu Dev .get_fc_host_stats = fc_get_host_stats, 219a703e490SVasu Dev .issue_fc_host_lip = fcoe_reset, 220a703e490SVasu Dev 221a703e490SVasu Dev .terminate_rport_io = fc_rport_terminate_io, 2229a05753bSChris Leech 2239a05753bSChris Leech .vport_create = fcoe_vport_create, 2249a05753bSChris Leech .vport_delete = fcoe_vport_destroy, 2259a05753bSChris Leech .vport_disable = fcoe_vport_disable, 226dc8596d3SChris Leech .set_vport_symbolic_name = fcoe_set_vport_symbolic_name, 227a51ab396SSteve Ma 228a51ab396SSteve Ma .bsg_request = fc_lport_bsg_request, 229a703e490SVasu Dev }; 230a703e490SVasu Dev 2317c9c6841SBart Van Assche static struct fc_function_template fcoe_vport_fc_functions = { 232e9084bb8SChris Leech .show_host_node_name = 1, 233e9084bb8SChris Leech .show_host_port_name = 1, 234e9084bb8SChris Leech .show_host_supported_classes = 1, 235e9084bb8SChris Leech .show_host_supported_fc4s = 1, 236e9084bb8SChris Leech .show_host_active_fc4s = 1, 237e9084bb8SChris Leech .show_host_maxframe_size = 1, 2387e5adcfbSNeerav Parikh .show_host_serial_number = 1, 2397e5adcfbSNeerav Parikh .show_host_manufacturer = 1, 2407e5adcfbSNeerav Parikh .show_host_model = 1, 2417e5adcfbSNeerav Parikh .show_host_model_description = 1, 2427e5adcfbSNeerav Parikh .show_host_hardware_version = 1, 2437e5adcfbSNeerav Parikh .show_host_driver_version = 1, 2447e5adcfbSNeerav Parikh .show_host_firmware_version = 1, 2457e5adcfbSNeerav Parikh .show_host_optionrom_version = 1, 246e9084bb8SChris Leech 247e9084bb8SChris Leech .show_host_port_id = 1, 248e9084bb8SChris Leech .show_host_supported_speeds = 1, 249e9084bb8SChris Leech .get_host_speed = fc_get_host_speed, 250e9084bb8SChris Leech .show_host_speed = 1, 251e9084bb8SChris Leech .show_host_port_type = 1, 252e9084bb8SChris Leech .get_host_port_state = fc_get_host_port_state, 253e9084bb8SChris Leech .show_host_port_state = 1, 254e9084bb8SChris Leech .show_host_symbolic_name = 1, 255e9084bb8SChris Leech 256e9084bb8SChris Leech .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), 257e9084bb8SChris Leech .show_rport_maxframe_size = 1, 258e9084bb8SChris Leech .show_rport_supported_classes = 1, 259e9084bb8SChris Leech 260e9084bb8SChris Leech .show_host_fabric_name = 1, 261e9084bb8SChris Leech .show_starget_node_name = 1, 262e9084bb8SChris Leech .show_starget_port_name = 1, 263e9084bb8SChris Leech .show_starget_port_id = 1, 264e9084bb8SChris Leech .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 265e9084bb8SChris Leech .show_rport_dev_loss_tmo = 1, 266e9084bb8SChris Leech .get_fc_host_stats = fc_get_host_stats, 267e9084bb8SChris Leech .issue_fc_host_lip = fcoe_reset, 268e9084bb8SChris Leech 269e9084bb8SChris Leech .terminate_rport_io = fc_rport_terminate_io, 270a51ab396SSteve Ma 271a51ab396SSteve Ma .bsg_request = fc_lport_bsg_request, 272e9084bb8SChris Leech }; 273e9084bb8SChris Leech 274a703e490SVasu Dev static struct scsi_host_template fcoe_shost_template = { 275a703e490SVasu Dev .module = THIS_MODULE, 276a703e490SVasu Dev .name = "FCoE Driver", 277a703e490SVasu Dev .proc_name = FCOE_NAME, 278a703e490SVasu Dev .queuecommand = fc_queuecommand, 279a703e490SVasu Dev .eh_abort_handler = fc_eh_abort, 280a703e490SVasu Dev .eh_device_reset_handler = fc_eh_device_reset, 281a703e490SVasu Dev .eh_host_reset_handler = fc_eh_host_reset, 282a703e490SVasu Dev .slave_alloc = fc_slave_alloc, 283a703e490SVasu Dev .change_queue_depth = fc_change_queue_depth, 284a703e490SVasu Dev .change_queue_type = fc_change_queue_type, 285a703e490SVasu Dev .this_id = -1, 28614caf44cSVasu Dev .cmd_per_lun = 3, 287a703e490SVasu Dev .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, 288a703e490SVasu Dev .use_clustering = ENABLE_CLUSTERING, 289a703e490SVasu Dev .sg_tablesize = SG_ALL, 290a703e490SVasu Dev .max_sectors = 0xffff, 291a703e490SVasu Dev }; 292a703e490SVasu Dev 29354b649f8SChris Leech /** 2941875f27eSRobert Love * fcoe_interface_setup() - Setup a FCoE interface 2951875f27eSRobert Love * @fcoe: The new FCoE interface 2961875f27eSRobert Love * @netdev: The net device that the fcoe interface is on 29754b649f8SChris Leech * 29854b649f8SChris Leech * Returns : 0 for success 2992e70e241SChris Leech * Locking: must be called with the RTNL mutex held 30054b649f8SChris Leech */ 30154b649f8SChris Leech static int fcoe_interface_setup(struct fcoe_interface *fcoe, 30254b649f8SChris Leech struct net_device *netdev) 30354b649f8SChris Leech { 304619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 30554b649f8SChris Leech struct netdev_hw_addr *ha; 3065bab87e6SYi Zou struct net_device *real_dev; 30754b649f8SChris Leech u8 flogi_maddr[ETH_ALEN]; 308b7a727f1SYi Zou const struct net_device_ops *ops; 30954b649f8SChris Leech 31054b649f8SChris Leech fcoe->netdev = netdev; 31154b649f8SChris Leech 312b7a727f1SYi Zou /* Let LLD initialize for FCoE */ 313b7a727f1SYi Zou ops = netdev->netdev_ops; 314b7a727f1SYi Zou if (ops->ndo_fcoe_enable) { 315b7a727f1SYi Zou if (ops->ndo_fcoe_enable(netdev)) 316b7a727f1SYi Zou FCOE_NETDEV_DBG(netdev, "Failed to enable FCoE" 317b7a727f1SYi Zou " specific feature for LLD.\n"); 318b7a727f1SYi Zou } 319b7a727f1SYi Zou 32054b649f8SChris Leech /* Do not support for bonding device */ 321cc8bdf06SJiri Pirko if (netdev->priv_flags & IFF_BONDING && netdev->flags & IFF_MASTER) { 32259d92516Sjohn fastabend FCOE_NETDEV_DBG(netdev, "Bonded interfaces not supported\n"); 32354b649f8SChris Leech return -EOPNOTSUPP; 32454b649f8SChris Leech } 32554b649f8SChris Leech 32654b649f8SChris Leech /* look for SAN MAC address, if multiple SAN MACs exist, only 32754b649f8SChris Leech * use the first one for SPMA */ 3285bab87e6SYi Zou real_dev = (netdev->priv_flags & IFF_802_1Q_VLAN) ? 3295bab87e6SYi Zou vlan_dev_real_dev(netdev) : netdev; 330d1483bb9SVasu Dev fcoe->realdev = real_dev; 33154b649f8SChris Leech rcu_read_lock(); 3325bab87e6SYi Zou for_each_dev_addr(real_dev, ha) { 33354b649f8SChris Leech if ((ha->type == NETDEV_HW_ADDR_T_SAN) && 334bf361707SYi Zou (is_valid_ether_addr(ha->addr))) { 33554b649f8SChris Leech memcpy(fip->ctl_src_addr, ha->addr, ETH_ALEN); 33654b649f8SChris Leech fip->spma = 1; 33754b649f8SChris Leech break; 33854b649f8SChris Leech } 33954b649f8SChris Leech } 34054b649f8SChris Leech rcu_read_unlock(); 34154b649f8SChris Leech 34254b649f8SChris Leech /* setup Source Mac Address */ 34354b649f8SChris Leech if (!fip->spma) 34454b649f8SChris Leech memcpy(fip->ctl_src_addr, netdev->dev_addr, netdev->addr_len); 34554b649f8SChris Leech 34654b649f8SChris Leech /* 34754b649f8SChris Leech * Add FCoE MAC address as second unicast MAC address 34854b649f8SChris Leech * or enter promiscuous mode if not capable of listening 34954b649f8SChris Leech * for multiple unicast MACs. 35054b649f8SChris Leech */ 35154b649f8SChris Leech memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); 352a748ee24SJiri Pirko dev_uc_add(netdev, flogi_maddr); 35354b649f8SChris Leech if (fip->spma) 354a748ee24SJiri Pirko dev_uc_add(netdev, fip->ctl_src_addr); 355e10f8c66SJoe Eykholt if (fip->mode == FIP_MODE_VN2VN) { 356e10f8c66SJoe Eykholt dev_mc_add(netdev, FIP_ALL_VN2VN_MACS); 357e10f8c66SJoe Eykholt dev_mc_add(netdev, FIP_ALL_P2P_MACS); 358e10f8c66SJoe Eykholt } else 35922bedad3SJiri Pirko dev_mc_add(netdev, FIP_ALL_ENODE_MACS); 36054b649f8SChris Leech 36154b649f8SChris Leech /* 36254b649f8SChris Leech * setup the receive function from ethernet driver 36354b649f8SChris Leech * on the ethertype for the given device 36454b649f8SChris Leech */ 36554b649f8SChris Leech fcoe->fcoe_packet_type.func = fcoe_rcv; 36654b649f8SChris Leech fcoe->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); 36754b649f8SChris Leech fcoe->fcoe_packet_type.dev = netdev; 36854b649f8SChris Leech dev_add_pack(&fcoe->fcoe_packet_type); 36954b649f8SChris Leech 37054b649f8SChris Leech fcoe->fip_packet_type.func = fcoe_fip_recv; 37154b649f8SChris Leech fcoe->fip_packet_type.type = htons(ETH_P_FIP); 37254b649f8SChris Leech fcoe->fip_packet_type.dev = netdev; 37354b649f8SChris Leech dev_add_pack(&fcoe->fip_packet_type); 37454b649f8SChris Leech 37554b649f8SChris Leech return 0; 37654b649f8SChris Leech } 37754b649f8SChris Leech 378a703e490SVasu Dev /** 3791875f27eSRobert Love * fcoe_interface_create() - Create a FCoE interface on a net device 3801875f27eSRobert Love * @netdev: The net device to create the FCoE interface on 3811dd454d9SJoe Eykholt * @fip_mode: The mode to use for FIP 382030f4e00SChris Leech * 383030f4e00SChris Leech * Returns: pointer to a struct fcoe_interface or NULL on error 384030f4e00SChris Leech */ 3851dd454d9SJoe Eykholt static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, 3861dd454d9SJoe Eykholt enum fip_state fip_mode) 387030f4e00SChris Leech { 3888d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev; 389619fe4beSRobert Love struct fcoe_ctlr *ctlr; 390030f4e00SChris Leech struct fcoe_interface *fcoe; 391619fe4beSRobert Love int size; 39259d92516Sjohn fastabend int err; 393030f4e00SChris Leech 3947287fb91SRobert Love if (!try_module_get(THIS_MODULE)) { 3957287fb91SRobert Love FCOE_NETDEV_DBG(netdev, 3967287fb91SRobert Love "Could not get a reference to the module\n"); 3977287fb91SRobert Love fcoe = ERR_PTR(-EBUSY); 3987287fb91SRobert Love goto out; 3997287fb91SRobert Love } 4007287fb91SRobert Love 401619fe4beSRobert Love size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface); 4028d55e507SRobert Love ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &fcoe_sysfs_templ, 4038d55e507SRobert Love size); 4048d55e507SRobert Love if (!ctlr_dev) { 4058d55e507SRobert Love FCOE_DBG("Failed to add fcoe_ctlr_device\n"); 4067287fb91SRobert Love fcoe = ERR_PTR(-ENOMEM); 4076f68794cSRobert Love goto out_putmod; 408030f4e00SChris Leech } 409030f4e00SChris Leech 4108d55e507SRobert Love ctlr = fcoe_ctlr_device_priv(ctlr_dev); 4118d55e507SRobert Love fcoe = fcoe_ctlr_priv(ctlr); 4128d55e507SRobert Love 4132e70e241SChris Leech dev_hold(netdev); 41454b649f8SChris Leech 41554b649f8SChris Leech /* 41654b649f8SChris Leech * Initialize FIP. 41754b649f8SChris Leech */ 418619fe4beSRobert Love fcoe_ctlr_init(ctlr, fip_mode); 419619fe4beSRobert Love ctlr->send = fcoe_fip_send; 420619fe4beSRobert Love ctlr->update_mac = fcoe_update_src_mac; 421619fe4beSRobert Love ctlr->get_src_addr = fcoe_get_src_mac; 42254b649f8SChris Leech 42359d92516Sjohn fastabend err = fcoe_interface_setup(fcoe, netdev); 42459d92516Sjohn fastabend if (err) { 425619fe4beSRobert Love fcoe_ctlr_destroy(ctlr); 4268d55e507SRobert Love fcoe_ctlr_device_delete(ctlr_dev); 42759d92516Sjohn fastabend dev_put(netdev); 4287287fb91SRobert Love fcoe = ERR_PTR(err); 4296f68794cSRobert Love goto out_putmod; 43059d92516Sjohn fastabend } 431030f4e00SChris Leech 4327287fb91SRobert Love goto out; 4337287fb91SRobert Love 4346f68794cSRobert Love out_putmod: 4357287fb91SRobert Love module_put(THIS_MODULE); 4367287fb91SRobert Love out: 437030f4e00SChris Leech return fcoe; 438030f4e00SChris Leech } 439030f4e00SChris Leech 440030f4e00SChris Leech /** 441433eba04SVasu Dev * fcoe_interface_remove() - remove FCoE interface from netdev 442f04ca1b6SVasu Dev * @fcoe: The FCoE interface to be cleaned up 443f04ca1b6SVasu Dev * 444f04ca1b6SVasu Dev * Caller must be holding the RTNL mutex 445f04ca1b6SVasu Dev */ 446433eba04SVasu Dev static void fcoe_interface_remove(struct fcoe_interface *fcoe) 447f04ca1b6SVasu Dev { 448f04ca1b6SVasu Dev struct net_device *netdev = fcoe->netdev; 449619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 450f04ca1b6SVasu Dev u8 flogi_maddr[ETH_ALEN]; 451f04ca1b6SVasu Dev const struct net_device_ops *ops; 452f04ca1b6SVasu Dev 453f04ca1b6SVasu Dev /* 454f04ca1b6SVasu Dev * Don't listen for Ethernet packets anymore. 455f04ca1b6SVasu Dev * synchronize_net() ensures that the packet handlers are not running 456f04ca1b6SVasu Dev * on another CPU. dev_remove_pack() would do that, this calls the 457f04ca1b6SVasu Dev * unsyncronized version __dev_remove_pack() to avoid multiple delays. 458f04ca1b6SVasu Dev */ 459f04ca1b6SVasu Dev __dev_remove_pack(&fcoe->fcoe_packet_type); 460f04ca1b6SVasu Dev __dev_remove_pack(&fcoe->fip_packet_type); 461f04ca1b6SVasu Dev synchronize_net(); 462f04ca1b6SVasu Dev 463f04ca1b6SVasu Dev /* Delete secondary MAC addresses */ 464f04ca1b6SVasu Dev memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); 465f04ca1b6SVasu Dev dev_uc_del(netdev, flogi_maddr); 466f04ca1b6SVasu Dev if (fip->spma) 467f04ca1b6SVasu Dev dev_uc_del(netdev, fip->ctl_src_addr); 468f04ca1b6SVasu Dev if (fip->mode == FIP_MODE_VN2VN) { 469f04ca1b6SVasu Dev dev_mc_del(netdev, FIP_ALL_VN2VN_MACS); 470f04ca1b6SVasu Dev dev_mc_del(netdev, FIP_ALL_P2P_MACS); 471f04ca1b6SVasu Dev } else 472f04ca1b6SVasu Dev dev_mc_del(netdev, FIP_ALL_ENODE_MACS); 473f04ca1b6SVasu Dev 474f04ca1b6SVasu Dev /* Tell the LLD we are done w/ FCoE */ 475f04ca1b6SVasu Dev ops = netdev->netdev_ops; 476f04ca1b6SVasu Dev if (ops->ndo_fcoe_disable) { 477f04ca1b6SVasu Dev if (ops->ndo_fcoe_disable(netdev)) 478f04ca1b6SVasu Dev FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" 479f04ca1b6SVasu Dev " specific feature for LLD.\n"); 480f04ca1b6SVasu Dev } 481433eba04SVasu Dev fcoe->removed = 1; 482433eba04SVasu Dev } 483b2085a4eSNeerav Parikh 484433eba04SVasu Dev 485433eba04SVasu Dev /** 486433eba04SVasu Dev * fcoe_interface_cleanup() - Clean up a FCoE interface 487433eba04SVasu Dev * @fcoe: The FCoE interface to be cleaned up 488433eba04SVasu Dev */ 489433eba04SVasu Dev static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) 490433eba04SVasu Dev { 491433eba04SVasu Dev struct net_device *netdev = fcoe->netdev; 492619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 493433eba04SVasu Dev 494433eba04SVasu Dev rtnl_lock(); 495433eba04SVasu Dev if (!fcoe->removed) 496433eba04SVasu Dev fcoe_interface_remove(fcoe); 497848e7d5bSRobert Love rtnl_unlock(); 498848e7d5bSRobert Love 499b2085a4eSNeerav Parikh /* Release the self-reference taken during fcoe_interface_create() */ 5001a8ef414SRobert Love /* tear-down the FCoE controller */ 5011a8ef414SRobert Love fcoe_ctlr_destroy(fip); 502619fe4beSRobert Love scsi_host_put(fip->lp->host); 5031a8ef414SRobert Love dev_put(netdev); 5041a8ef414SRobert Love module_put(THIS_MODULE); 505f04ca1b6SVasu Dev } 506f04ca1b6SVasu Dev 507f04ca1b6SVasu Dev /** 5081875f27eSRobert Love * fcoe_fip_recv() - Handler for received FIP frames 5091875f27eSRobert Love * @skb: The receive skb 5101875f27eSRobert Love * @netdev: The associated net device 5111875f27eSRobert Love * @ptype: The packet_type structure which was used to register this handler 5121875f27eSRobert Love * @orig_dev: The original net_device the the skb was received on. 5131875f27eSRobert Love * (in case dev is a bond) 514ab6b85c1SVasu Dev * 515ab6b85c1SVasu Dev * Returns: 0 for success 516ab6b85c1SVasu Dev */ 5171875f27eSRobert Love static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev, 518ab6b85c1SVasu Dev struct packet_type *ptype, 519ab6b85c1SVasu Dev struct net_device *orig_dev) 520ab6b85c1SVasu Dev { 521259ad85dSChris Leech struct fcoe_interface *fcoe; 522619fe4beSRobert Love struct fcoe_ctlr *ctlr; 523ab6b85c1SVasu Dev 524259ad85dSChris Leech fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); 525619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 526619fe4beSRobert Love fcoe_ctlr_recv(ctlr, skb); 527ab6b85c1SVasu Dev return 0; 528ab6b85c1SVasu Dev } 529ab6b85c1SVasu Dev 530ab6b85c1SVasu Dev /** 531980f5156SVasu Dev * fcoe_port_send() - Send an Ethernet-encapsulated FIP/FCoE frame 532980f5156SVasu Dev * @port: The FCoE port 533980f5156SVasu Dev * @skb: The FIP/FCoE packet to be sent 534980f5156SVasu Dev */ 535980f5156SVasu Dev static void fcoe_port_send(struct fcoe_port *port, struct sk_buff *skb) 536980f5156SVasu Dev { 537980f5156SVasu Dev if (port->fcoe_pending_queue.qlen) 538980f5156SVasu Dev fcoe_check_wait_queue(port->lport, skb); 539980f5156SVasu Dev else if (fcoe_start_io(skb)) 540980f5156SVasu Dev fcoe_check_wait_queue(port->lport, skb); 541980f5156SVasu Dev } 542980f5156SVasu Dev 543980f5156SVasu Dev /** 5441875f27eSRobert Love * fcoe_fip_send() - Send an Ethernet-encapsulated FIP frame 5451875f27eSRobert Love * @fip: The FCoE controller 5461875f27eSRobert Love * @skb: The FIP packet to be sent 547ab6b85c1SVasu Dev */ 548ab6b85c1SVasu Dev static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) 549ab6b85c1SVasu Dev { 5503fe9a0baSChris Leech skb->dev = fcoe_from_ctlr(fip)->netdev; 551980f5156SVasu Dev fcoe_port_send(lport_priv(fip->lp), skb); 552ab6b85c1SVasu Dev } 553ab6b85c1SVasu Dev 554ab6b85c1SVasu Dev /** 5551875f27eSRobert Love * fcoe_update_src_mac() - Update the Ethernet MAC filters 5561875f27eSRobert Love * @lport: The local port to update the source MAC on 5571875f27eSRobert Love * @addr: Unicast MAC address to add 558ab6b85c1SVasu Dev * 559ab6b85c1SVasu Dev * Remove any previously-set unicast MAC filter. 560ab6b85c1SVasu Dev * Add secondary FCoE MAC address filter for our OUI. 561ab6b85c1SVasu Dev */ 56211b56188SChris Leech static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr) 563ab6b85c1SVasu Dev { 56411b56188SChris Leech struct fcoe_port *port = lport_priv(lport); 5658597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 566ab6b85c1SVasu Dev 56711b56188SChris Leech if (!is_zero_ether_addr(port->data_src_addr)) 568a748ee24SJiri Pirko dev_uc_del(fcoe->netdev, port->data_src_addr); 56911b56188SChris Leech if (!is_zero_ether_addr(addr)) 570a748ee24SJiri Pirko dev_uc_add(fcoe->netdev, addr); 57111b56188SChris Leech memcpy(port->data_src_addr, addr, ETH_ALEN); 572ab6b85c1SVasu Dev } 573ab6b85c1SVasu Dev 574ab6b85c1SVasu Dev /** 57511b56188SChris Leech * fcoe_get_src_mac() - return the Ethernet source address for an lport 57611b56188SChris Leech * @lport: libfc lport 57711b56188SChris Leech */ 57811b56188SChris Leech static u8 *fcoe_get_src_mac(struct fc_lport *lport) 57911b56188SChris Leech { 58011b56188SChris Leech struct fcoe_port *port = lport_priv(lport); 58111b56188SChris Leech 58211b56188SChris Leech return port->data_src_addr; 58311b56188SChris Leech } 58411b56188SChris Leech 58511b56188SChris Leech /** 5861875f27eSRobert Love * fcoe_lport_config() - Set up a local port 5871875f27eSRobert Love * @lport: The local port to be setup 588a703e490SVasu Dev * 589a703e490SVasu Dev * Returns: 0 for success 590a703e490SVasu Dev */ 5911875f27eSRobert Love static int fcoe_lport_config(struct fc_lport *lport) 592a703e490SVasu Dev { 5931875f27eSRobert Love lport->link_up = 0; 5941875f27eSRobert Love lport->qfull = 0; 5951875f27eSRobert Love lport->max_retry_count = 3; 5961875f27eSRobert Love lport->max_rport_retry_count = 3; 5971875f27eSRobert Love lport->e_d_tov = 2 * 1000; /* FC-FS default */ 5981875f27eSRobert Love lport->r_a_tov = 2 * 2 * 1000; 5991875f27eSRobert Love lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | 600a703e490SVasu Dev FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); 6011875f27eSRobert Love lport->does_npiv = 1; 602a703e490SVasu Dev 6031875f27eSRobert Love fc_lport_init_stats(lport); 604a703e490SVasu Dev 605a703e490SVasu Dev /* lport fc_lport related configuration */ 6061875f27eSRobert Love fc_lport_config(lport); 607a703e490SVasu Dev 608a703e490SVasu Dev /* offload related configuration */ 6091875f27eSRobert Love lport->crc_offload = 0; 6101875f27eSRobert Love lport->seq_offload = 0; 6111875f27eSRobert Love lport->lro_enabled = 0; 6121875f27eSRobert Love lport->lro_xid = 0; 6131875f27eSRobert Love lport->lso_max = 0; 614a703e490SVasu Dev 615a703e490SVasu Dev return 0; 616a703e490SVasu Dev } 617a703e490SVasu Dev 618a703e490SVasu Dev /** 61954a5b21dSYi Zou * fcoe_netdev_features_change - Updates the lport's offload flags based 62054a5b21dSYi Zou * on the LLD netdev's FCoE feature flags 62154a5b21dSYi Zou */ 62254a5b21dSYi Zou static void fcoe_netdev_features_change(struct fc_lport *lport, 62354a5b21dSYi Zou struct net_device *netdev) 62454a5b21dSYi Zou { 62554a5b21dSYi Zou mutex_lock(&lport->lp_mutex); 62654a5b21dSYi Zou 62754a5b21dSYi Zou if (netdev->features & NETIF_F_SG) 62854a5b21dSYi Zou lport->sg_supp = 1; 62954a5b21dSYi Zou else 63054a5b21dSYi Zou lport->sg_supp = 0; 63154a5b21dSYi Zou 63254a5b21dSYi Zou if (netdev->features & NETIF_F_FCOE_CRC) { 63354a5b21dSYi Zou lport->crc_offload = 1; 63454a5b21dSYi Zou FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); 63554a5b21dSYi Zou } else { 63654a5b21dSYi Zou lport->crc_offload = 0; 63754a5b21dSYi Zou } 63854a5b21dSYi Zou 63954a5b21dSYi Zou if (netdev->features & NETIF_F_FSO) { 64054a5b21dSYi Zou lport->seq_offload = 1; 64154a5b21dSYi Zou lport->lso_max = netdev->gso_max_size; 64254a5b21dSYi Zou FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", 64354a5b21dSYi Zou lport->lso_max); 64454a5b21dSYi Zou } else { 64554a5b21dSYi Zou lport->seq_offload = 0; 64654a5b21dSYi Zou lport->lso_max = 0; 64754a5b21dSYi Zou } 64854a5b21dSYi Zou 64954a5b21dSYi Zou if (netdev->fcoe_ddp_xid) { 65054a5b21dSYi Zou lport->lro_enabled = 1; 65154a5b21dSYi Zou lport->lro_xid = netdev->fcoe_ddp_xid; 65254a5b21dSYi Zou FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", 65354a5b21dSYi Zou lport->lro_xid); 65454a5b21dSYi Zou } else { 65554a5b21dSYi Zou lport->lro_enabled = 0; 65654a5b21dSYi Zou lport->lro_xid = 0; 65754a5b21dSYi Zou } 65854a5b21dSYi Zou 65954a5b21dSYi Zou mutex_unlock(&lport->lp_mutex); 66054a5b21dSYi Zou } 66154a5b21dSYi Zou 66254a5b21dSYi Zou /** 6631875f27eSRobert Love * fcoe_netdev_config() - Set up net devive for SW FCoE 6641875f27eSRobert Love * @lport: The local port that is associated with the net device 6651875f27eSRobert Love * @netdev: The associated net device 666a703e490SVasu Dev * 6671875f27eSRobert Love * Must be called after fcoe_lport_config() as it will use local port mutex 668a703e490SVasu Dev * 669a703e490SVasu Dev * Returns: 0 for success 670a703e490SVasu Dev */ 6711875f27eSRobert Love static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) 672a703e490SVasu Dev { 673a703e490SVasu Dev u32 mfs; 674a703e490SVasu Dev u64 wwnn, wwpn; 67525024989SChris Leech struct fcoe_interface *fcoe; 676619fe4beSRobert Love struct fcoe_ctlr *ctlr; 677014f5c3fSChris Leech struct fcoe_port *port; 678a703e490SVasu Dev 679a703e490SVasu Dev /* Setup lport private data to point to fcoe softc */ 6801875f27eSRobert Love port = lport_priv(lport); 6818597ae8bSBhanu Prakash Gollapudi fcoe = port->priv; 682619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 683a703e490SVasu Dev 684a703e490SVasu Dev /* 685a703e490SVasu Dev * Determine max frame size based on underlying device and optional 686a703e490SVasu Dev * user-configured limit. If the MFS is too low, fcoe_link_ok() 687a703e490SVasu Dev * will return 0, so do this first. 688a703e490SVasu Dev */ 6897221d7e5SYi Zou mfs = netdev->mtu; 6907221d7e5SYi Zou if (netdev->features & NETIF_F_FCOE_MTU) { 6917221d7e5SYi Zou mfs = FCOE_MTU; 6927221d7e5SYi Zou FCOE_NETDEV_DBG(netdev, "Supports FCOE_MTU of %d bytes\n", mfs); 6937221d7e5SYi Zou } 6947221d7e5SYi Zou mfs -= (sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof)); 6951875f27eSRobert Love if (fc_set_mfs(lport, mfs)) 696a703e490SVasu Dev return -EINVAL; 697a703e490SVasu Dev 698a703e490SVasu Dev /* offload features support */ 69954a5b21dSYi Zou fcoe_netdev_features_change(lport, netdev); 700a703e490SVasu Dev 701014f5c3fSChris Leech skb_queue_head_init(&port->fcoe_pending_queue); 702014f5c3fSChris Leech port->fcoe_pending_queue_active = 0; 7031875f27eSRobert Love setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport); 704a703e490SVasu Dev 7055e4f8fe7SRobert Love fcoe_link_speed_update(lport); 7065e4f8fe7SRobert Love 7071875f27eSRobert Love if (!lport->vport) { 708dcece412SYi Zou if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) 709619fe4beSRobert Love wwnn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 1, 0); 7101875f27eSRobert Love fc_set_wwnn(lport, wwnn); 711dcece412SYi Zou if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) 712619fe4beSRobert Love wwpn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 713cf4aebcaSVasu Dev 2, 0); 7141875f27eSRobert Love fc_set_wwpn(lport, wwpn); 7159a05753bSChris Leech } 716a703e490SVasu Dev 717a703e490SVasu Dev return 0; 718a703e490SVasu Dev } 719a703e490SVasu Dev 720a703e490SVasu Dev /** 7211875f27eSRobert Love * fcoe_shost_config() - Set up the SCSI host associated with a local port 7221875f27eSRobert Love * @lport: The local port 7231875f27eSRobert Love * @dev: The device associated with the SCSI host 724a703e490SVasu Dev * 725a703e490SVasu Dev * Must be called after fcoe_lport_config() and fcoe_netdev_config() 726a703e490SVasu Dev * 727a703e490SVasu Dev * Returns: 0 for success 728a703e490SVasu Dev */ 7298ba00a4bSVasu Dev static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) 730a703e490SVasu Dev { 731a703e490SVasu Dev int rc = 0; 732a703e490SVasu Dev 733a703e490SVasu Dev /* lport scsi host config */ 7341875f27eSRobert Love lport->host->max_lun = FCOE_MAX_LUN; 7351875f27eSRobert Love lport->host->max_id = FCOE_MAX_FCP_TARGET; 7361875f27eSRobert Love lport->host->max_channel = 0; 737da87bfabSVasu Dev lport->host->max_cmd_len = FCOE_MAX_CMD_LEN; 738da87bfabSVasu Dev 7391875f27eSRobert Love if (lport->vport) 7408ca86f84SYi Zou lport->host->transportt = fcoe_vport_scsi_transport; 741e9084bb8SChris Leech else 7428ca86f84SYi Zou lport->host->transportt = fcoe_nport_scsi_transport; 743a703e490SVasu Dev 744a703e490SVasu Dev /* add the new host to the SCSI-ml */ 7451875f27eSRobert Love rc = scsi_add_host(lport->host, dev); 746a703e490SVasu Dev if (rc) { 7471875f27eSRobert Love FCOE_NETDEV_DBG(fcoe_netdev(lport), "fcoe_shost_config: " 748d5488eb9SRobert Love "error on scsi_add_host\n"); 749a703e490SVasu Dev return rc; 750a703e490SVasu Dev } 7519a05753bSChris Leech 7521875f27eSRobert Love if (!lport->vport) 7534be929beSAlexey Dobriyan fc_host_max_npiv_vports(lport->host) = USHRT_MAX; 7549a05753bSChris Leech 7551875f27eSRobert Love snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE, 7565baa17c3SChris Leech "%s v%s over %s", FCOE_NAME, FCOE_VERSION, 7571875f27eSRobert Love fcoe_netdev(lport)->name); 758a703e490SVasu Dev 759a703e490SVasu Dev return 0; 760a703e490SVasu Dev } 761a703e490SVasu Dev 7626fef3902SNeerav Parikh 7636fef3902SNeerav Parikh /** 7646fef3902SNeerav Parikh * fcoe_fdmi_info() - Get FDMI related info from net devive for SW FCoE 7656fef3902SNeerav Parikh * @lport: The local port that is associated with the net device 7666fef3902SNeerav Parikh * @netdev: The associated net device 7676fef3902SNeerav Parikh * 7686fef3902SNeerav Parikh * Must be called after fcoe_shost_config() as it will use local port mutex 7696fef3902SNeerav Parikh * 7706fef3902SNeerav Parikh */ 7716fef3902SNeerav Parikh static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev) 7726fef3902SNeerav Parikh { 7736fef3902SNeerav Parikh struct fcoe_interface *fcoe; 7746fef3902SNeerav Parikh struct fcoe_port *port; 7756fef3902SNeerav Parikh struct net_device *realdev; 7766fef3902SNeerav Parikh int rc; 7776fef3902SNeerav Parikh struct netdev_fcoe_hbainfo fdmi; 7786fef3902SNeerav Parikh 7796fef3902SNeerav Parikh port = lport_priv(lport); 7806fef3902SNeerav Parikh fcoe = port->priv; 7816fef3902SNeerav Parikh realdev = fcoe->realdev; 7826fef3902SNeerav Parikh 7836fef3902SNeerav Parikh if (!realdev) 7846fef3902SNeerav Parikh return; 7856fef3902SNeerav Parikh 7866fef3902SNeerav Parikh /* No FDMI state m/c for NPIV ports */ 7876fef3902SNeerav Parikh if (lport->vport) 7886fef3902SNeerav Parikh return; 7896fef3902SNeerav Parikh 7906fef3902SNeerav Parikh if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) { 7916fef3902SNeerav Parikh memset(&fdmi, 0, sizeof(fdmi)); 7926fef3902SNeerav Parikh rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev, 7936fef3902SNeerav Parikh &fdmi); 7946fef3902SNeerav Parikh if (rc) { 7956fef3902SNeerav Parikh printk(KERN_INFO "fcoe: Failed to retrieve FDMI " 7966fef3902SNeerav Parikh "information from netdev.\n"); 7976fef3902SNeerav Parikh return; 7986fef3902SNeerav Parikh } 7996fef3902SNeerav Parikh 8006fef3902SNeerav Parikh snprintf(fc_host_serial_number(lport->host), 8016fef3902SNeerav Parikh FC_SERIAL_NUMBER_SIZE, 8026fef3902SNeerav Parikh "%s", 8036fef3902SNeerav Parikh fdmi.serial_number); 8046fef3902SNeerav Parikh snprintf(fc_host_manufacturer(lport->host), 8056fef3902SNeerav Parikh FC_SERIAL_NUMBER_SIZE, 8066fef3902SNeerav Parikh "%s", 8076fef3902SNeerav Parikh fdmi.manufacturer); 8086fef3902SNeerav Parikh snprintf(fc_host_model(lport->host), 8096fef3902SNeerav Parikh FC_SYMBOLIC_NAME_SIZE, 8106fef3902SNeerav Parikh "%s", 8116fef3902SNeerav Parikh fdmi.model); 8126fef3902SNeerav Parikh snprintf(fc_host_model_description(lport->host), 8136fef3902SNeerav Parikh FC_SYMBOLIC_NAME_SIZE, 8146fef3902SNeerav Parikh "%s", 8156fef3902SNeerav Parikh fdmi.model_description); 8166fef3902SNeerav Parikh snprintf(fc_host_hardware_version(lport->host), 8176fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8186fef3902SNeerav Parikh "%s", 8196fef3902SNeerav Parikh fdmi.hardware_version); 8206fef3902SNeerav Parikh snprintf(fc_host_driver_version(lport->host), 8216fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8226fef3902SNeerav Parikh "%s", 8236fef3902SNeerav Parikh fdmi.driver_version); 8246fef3902SNeerav Parikh snprintf(fc_host_optionrom_version(lport->host), 8256fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8266fef3902SNeerav Parikh "%s", 8276fef3902SNeerav Parikh fdmi.optionrom_version); 8286fef3902SNeerav Parikh snprintf(fc_host_firmware_version(lport->host), 8296fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8306fef3902SNeerav Parikh "%s", 8316fef3902SNeerav Parikh fdmi.firmware_version); 8326fef3902SNeerav Parikh 8336fef3902SNeerav Parikh /* Enable FDMI lport states */ 8346fef3902SNeerav Parikh lport->fdmi_enabled = 1; 8356fef3902SNeerav Parikh } else { 8366fef3902SNeerav Parikh lport->fdmi_enabled = 0; 8376fef3902SNeerav Parikh printk(KERN_INFO "fcoe: No FDMI support.\n"); 8386fef3902SNeerav Parikh } 8396fef3902SNeerav Parikh } 8406fef3902SNeerav Parikh 8411875f27eSRobert Love /** 8421875f27eSRobert Love * fcoe_oem_match() - The match routine for the offloaded exchange manager 8431875f27eSRobert Love * @fp: The I/O frame 844d7179680SVasu Dev * 8451875f27eSRobert Love * This routine will be associated with an exchange manager (EM). When 8461875f27eSRobert Love * the libfc exchange handling code is looking for an EM to use it will 8471875f27eSRobert Love * call this routine and pass it the frame that it wishes to send. This 8481875f27eSRobert Love * routine will return True if the associated EM is to be used and False 8491875f27eSRobert Love * if the echange code should continue looking for an EM. 8501875f27eSRobert Love * 8511875f27eSRobert Love * The offload EM that this routine is associated with will handle any 8521875f27eSRobert Love * packets that are for SCSI read requests. 8531875f27eSRobert Love * 8541ff9918bSKiran Patil * This has been enhanced to work when FCoE stack is operating in target 8551ff9918bSKiran Patil * mode. 8561ff9918bSKiran Patil * 8571875f27eSRobert Love * Returns: True for read types I/O, otherwise returns false. 858d7179680SVasu Dev */ 8597c9c6841SBart Van Assche static bool fcoe_oem_match(struct fc_frame *fp) 860d7179680SVasu Dev { 8611ff9918bSKiran Patil struct fc_frame_header *fh = fc_frame_header_get(fp); 8621ff9918bSKiran Patil struct fcp_cmnd *fcp; 8631ff9918bSKiran Patil 8641ff9918bSKiran Patil if (fc_fcp_is_read(fr_fsp(fp)) && 8651ff9918bSKiran Patil (fr_fsp(fp)->data_len > fcoe_ddp_min)) 8661ff9918bSKiran Patil return true; 867a762dce4SYi Zou else if ((fr_fsp(fp) == NULL) && 868a762dce4SYi Zou (fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) && 869a762dce4SYi Zou (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { 8701ff9918bSKiran Patil fcp = fc_frame_payload_get(fp, sizeof(*fcp)); 871a762dce4SYi Zou if ((fcp->fc_flags & FCP_CFL_WRDATA) && 872a762dce4SYi Zou (ntohl(fcp->fc_dl) > fcoe_ddp_min)) 8731ff9918bSKiran Patil return true; 8741ff9918bSKiran Patil } 8751ff9918bSKiran Patil return false; 876d7179680SVasu Dev } 877d7179680SVasu Dev 878a703e490SVasu Dev /** 8791875f27eSRobert Love * fcoe_em_config() - Allocate and configure an exchange manager 8801875f27eSRobert Love * @lport: The local port that the new EM will be associated with 881a703e490SVasu Dev * 882a703e490SVasu Dev * Returns: 0 on success 883a703e490SVasu Dev */ 8841875f27eSRobert Love static inline int fcoe_em_config(struct fc_lport *lport) 885a703e490SVasu Dev { 8861875f27eSRobert Love struct fcoe_port *port = lport_priv(lport); 8878597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 88825024989SChris Leech struct fcoe_interface *oldfcoe = NULL; 8891d1b88dcSVasu Dev struct net_device *old_real_dev, *cur_real_dev; 890d7179680SVasu Dev u16 min_xid = FCOE_MIN_XID; 891d7179680SVasu Dev u16 max_xid = FCOE_MAX_XID; 892d7179680SVasu Dev 893d7179680SVasu Dev /* 894d7179680SVasu Dev * Check if need to allocate an em instance for 895d7179680SVasu Dev * offload exchange ids to be shared across all VN_PORTs/lport. 896d7179680SVasu Dev */ 8971875f27eSRobert Love if (!lport->lro_enabled || !lport->lro_xid || 8981875f27eSRobert Love (lport->lro_xid >= max_xid)) { 8991875f27eSRobert Love lport->lro_xid = 0; 900d7179680SVasu Dev goto skip_oem; 901d7179680SVasu Dev } 902d7179680SVasu Dev 903d7179680SVasu Dev /* 904d7179680SVasu Dev * Reuse existing offload em instance in case 9051d1b88dcSVasu Dev * it is already allocated on real eth device 906d7179680SVasu Dev */ 90725024989SChris Leech if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) 90825024989SChris Leech cur_real_dev = vlan_dev_real_dev(fcoe->netdev); 9091d1b88dcSVasu Dev else 91025024989SChris Leech cur_real_dev = fcoe->netdev; 9111d1b88dcSVasu Dev 91225024989SChris Leech list_for_each_entry(oldfcoe, &fcoe_hostlist, list) { 91325024989SChris Leech if (oldfcoe->netdev->priv_flags & IFF_802_1Q_VLAN) 91425024989SChris Leech old_real_dev = vlan_dev_real_dev(oldfcoe->netdev); 9151d1b88dcSVasu Dev else 91625024989SChris Leech old_real_dev = oldfcoe->netdev; 9171d1b88dcSVasu Dev 9181d1b88dcSVasu Dev if (cur_real_dev == old_real_dev) { 919991cbb60SChris Leech fcoe->oem = oldfcoe->oem; 920d7179680SVasu Dev break; 921d7179680SVasu Dev } 922d7179680SVasu Dev } 923d7179680SVasu Dev 924991cbb60SChris Leech if (fcoe->oem) { 9251875f27eSRobert Love if (!fc_exch_mgr_add(lport, fcoe->oem, fcoe_oem_match)) { 926d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to add " 927d7179680SVasu Dev "offload em:%p on interface:%s\n", 928991cbb60SChris Leech fcoe->oem, fcoe->netdev->name); 929a703e490SVasu Dev return -ENOMEM; 930d7179680SVasu Dev } 931d7179680SVasu Dev } else { 9321875f27eSRobert Love fcoe->oem = fc_exch_mgr_alloc(lport, FC_CLASS_3, 9331875f27eSRobert Love FCOE_MIN_XID, lport->lro_xid, 934d7179680SVasu Dev fcoe_oem_match); 935991cbb60SChris Leech if (!fcoe->oem) { 936d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to allocate " 937d7179680SVasu Dev "em for offload exches on interface:%s\n", 93825024989SChris Leech fcoe->netdev->name); 939d7179680SVasu Dev return -ENOMEM; 940d7179680SVasu Dev } 941d7179680SVasu Dev } 942d7179680SVasu Dev 943d7179680SVasu Dev /* 944d7179680SVasu Dev * Exclude offload EM xid range from next EM xid range. 945d7179680SVasu Dev */ 9461875f27eSRobert Love min_xid += lport->lro_xid + 1; 947d7179680SVasu Dev 948d7179680SVasu Dev skip_oem: 9491875f27eSRobert Love if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, min_xid, max_xid, NULL)) { 950d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to " 95125024989SChris Leech "allocate em on interface %s\n", fcoe->netdev->name); 952d7179680SVasu Dev return -ENOMEM; 953d7179680SVasu Dev } 954a703e490SVasu Dev 955a703e490SVasu Dev return 0; 956a703e490SVasu Dev } 957a703e490SVasu Dev 958a703e490SVasu Dev /** 9591875f27eSRobert Love * fcoe_if_destroy() - Tear down a SW FCoE instance 9601875f27eSRobert Love * @lport: The local port to be destroyed 96134ce27bcSVasu Dev * 962a703e490SVasu Dev */ 963af7f85d9SChris Leech static void fcoe_if_destroy(struct fc_lport *lport) 964a703e490SVasu Dev { 965b2085a4eSNeerav Parikh struct fcoe_port *port = lport_priv(lport); 966b2085a4eSNeerav Parikh struct fcoe_interface *fcoe = port->priv; 967b2085a4eSNeerav Parikh struct net_device *netdev = fcoe->netdev; 968b2085a4eSNeerav Parikh 969b2085a4eSNeerav Parikh FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); 970b2085a4eSNeerav Parikh 971b2085a4eSNeerav Parikh /* Logout of the fabric */ 972b2085a4eSNeerav Parikh fc_fabric_logoff(lport); 973b2085a4eSNeerav Parikh 974b2085a4eSNeerav Parikh /* Cleanup the fc_lport */ 975b2085a4eSNeerav Parikh fc_lport_destroy(lport); 976b2085a4eSNeerav Parikh 977b2085a4eSNeerav Parikh /* Stop the transmit retry timer */ 978b2085a4eSNeerav Parikh del_timer_sync(&port->timer); 979b2085a4eSNeerav Parikh 980b2085a4eSNeerav Parikh /* Free existing transmit skbs */ 981b2085a4eSNeerav Parikh fcoe_clean_pending_queue(lport); 982b2085a4eSNeerav Parikh 983b2085a4eSNeerav Parikh rtnl_lock(); 984b2085a4eSNeerav Parikh if (!is_zero_ether_addr(port->data_src_addr)) 985b2085a4eSNeerav Parikh dev_uc_del(netdev, port->data_src_addr); 986433eba04SVasu Dev if (lport->vport) 987433eba04SVasu Dev synchronize_net(); 988433eba04SVasu Dev else 989433eba04SVasu Dev fcoe_interface_remove(fcoe); 990b2085a4eSNeerav Parikh rtnl_unlock(); 991b2085a4eSNeerav Parikh 99254b649f8SChris Leech /* Free queued packets for the per-CPU receive threads */ 99354b649f8SChris Leech fcoe_percpu_clean(lport); 99454b649f8SChris Leech 995a703e490SVasu Dev /* Detach from the scsi-ml */ 996af7f85d9SChris Leech fc_remove_host(lport->host); 997af7f85d9SChris Leech scsi_remove_host(lport->host); 998a703e490SVasu Dev 99980e736f8SYi Zou /* Destroy lport scsi_priv */ 100080e736f8SYi Zou fc_fcp_destroy(lport); 100180e736f8SYi Zou 1002a703e490SVasu Dev /* There are no more rports or I/O, free the EM */ 1003af7f85d9SChris Leech fc_exch_mgr_free(lport); 1004a703e490SVasu Dev 1005a703e490SVasu Dev /* Free memory used by statistical counters */ 1006af7f85d9SChris Leech fc_lport_free_stats(lport); 1007a703e490SVasu Dev 10083cab4468SVasu Dev /* 10093cab4468SVasu Dev * Release the Scsi_Host for vport but hold on to 10103cab4468SVasu Dev * master lport until it fcoe interface fully cleaned-up. 10113cab4468SVasu Dev */ 10123cab4468SVasu Dev if (lport->vport) 1013af7f85d9SChris Leech scsi_host_put(lport->host); 1014a703e490SVasu Dev } 1015a703e490SVasu Dev 10161875f27eSRobert Love /** 10171875f27eSRobert Love * fcoe_ddp_setup() - Call a LLD's ddp_setup through the net device 10181875f27eSRobert Love * @lport: The local port to setup DDP for 10191875f27eSRobert Love * @xid: The exchange ID for this DDP transfer 10201875f27eSRobert Love * @sgl: The scatterlist describing this transfer 10211875f27eSRobert Love * @sgc: The number of sg items 1022a703e490SVasu Dev * 10231875f27eSRobert Love * Returns: 0 if the DDP context was not configured 1024a703e490SVasu Dev */ 10251875f27eSRobert Love static int fcoe_ddp_setup(struct fc_lport *lport, u16 xid, 1026a703e490SVasu Dev struct scatterlist *sgl, unsigned int sgc) 1027a703e490SVasu Dev { 10281875f27eSRobert Love struct net_device *netdev = fcoe_netdev(lport); 1029a703e490SVasu Dev 10301875f27eSRobert Love if (netdev->netdev_ops->ndo_fcoe_ddp_setup) 10311875f27eSRobert Love return netdev->netdev_ops->ndo_fcoe_ddp_setup(netdev, 10321875f27eSRobert Love xid, sgl, 10331875f27eSRobert Love sgc); 1034a703e490SVasu Dev 1035a703e490SVasu Dev return 0; 1036a703e490SVasu Dev } 1037a703e490SVasu Dev 1038a703e490SVasu Dev /** 103971f89491SYi Zou * fcoe_ddp_target() - Call a LLD's ddp_target through the net device 104071f89491SYi Zou * @lport: The local port to setup DDP for 104171f89491SYi Zou * @xid: The exchange ID for this DDP transfer 104271f89491SYi Zou * @sgl: The scatterlist describing this transfer 104371f89491SYi Zou * @sgc: The number of sg items 104471f89491SYi Zou * 104571f89491SYi Zou * Returns: 0 if the DDP context was not configured 104671f89491SYi Zou */ 104771f89491SYi Zou static int fcoe_ddp_target(struct fc_lport *lport, u16 xid, 104871f89491SYi Zou struct scatterlist *sgl, unsigned int sgc) 104971f89491SYi Zou { 105071f89491SYi Zou struct net_device *netdev = fcoe_netdev(lport); 105171f89491SYi Zou 105271f89491SYi Zou if (netdev->netdev_ops->ndo_fcoe_ddp_target) 105371f89491SYi Zou return netdev->netdev_ops->ndo_fcoe_ddp_target(netdev, xid, 105471f89491SYi Zou sgl, sgc); 105571f89491SYi Zou 105671f89491SYi Zou return 0; 105771f89491SYi Zou } 105871f89491SYi Zou 105971f89491SYi Zou 106071f89491SYi Zou /** 10611875f27eSRobert Love * fcoe_ddp_done() - Call a LLD's ddp_done through the net device 10621875f27eSRobert Love * @lport: The local port to complete DDP on 10631875f27eSRobert Love * @xid: The exchange ID for this DDP transfer 1064a703e490SVasu Dev * 10651875f27eSRobert Love * Returns: the length of data that have been completed by DDP 10661875f27eSRobert Love */ 10671875f27eSRobert Love static int fcoe_ddp_done(struct fc_lport *lport, u16 xid) 10681875f27eSRobert Love { 10691875f27eSRobert Love struct net_device *netdev = fcoe_netdev(lport); 10701875f27eSRobert Love 10711875f27eSRobert Love if (netdev->netdev_ops->ndo_fcoe_ddp_done) 10721875f27eSRobert Love return netdev->netdev_ops->ndo_fcoe_ddp_done(netdev, xid); 10731875f27eSRobert Love return 0; 10741875f27eSRobert Love } 10751875f27eSRobert Love 10761875f27eSRobert Love /** 10771875f27eSRobert Love * fcoe_if_create() - Create a FCoE instance on an interface 10781875f27eSRobert Love * @fcoe: The FCoE interface to create a local port on 10791875f27eSRobert Love * @parent: The device pointer to be the parent in sysfs for the SCSI host 10801875f27eSRobert Love * @npiv: Indicates if the port is a vport or not 10811875f27eSRobert Love * 10821875f27eSRobert Love * Creates a fc_lport instance and a Scsi_Host instance and configure them. 1083a703e490SVasu Dev * 1084af7f85d9SChris Leech * Returns: The allocated fc_lport or an error pointer 1085a703e490SVasu Dev */ 1086030f4e00SChris Leech static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, 10879a05753bSChris Leech struct device *parent, int npiv) 1088a703e490SVasu Dev { 1089619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 10901875f27eSRobert Love struct net_device *netdev = fcoe->netdev; 109172fa396bSVasu Dev struct fc_lport *lport, *n_port; 1092014f5c3fSChris Leech struct fcoe_port *port; 109372fa396bSVasu Dev struct Scsi_Host *shost; 10941875f27eSRobert Love int rc; 10959a05753bSChris Leech /* 10969a05753bSChris Leech * parent is only a vport if npiv is 1, 10979a05753bSChris Leech * but we'll only use vport in that case so go ahead and set it 10989a05753bSChris Leech */ 10999a05753bSChris Leech struct fc_vport *vport = dev_to_vport(parent); 1100a703e490SVasu Dev 1101d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Create Interface\n"); 1102a703e490SVasu Dev 110372fa396bSVasu Dev if (!npiv) 110472fa396bSVasu Dev lport = libfc_host_alloc(&fcoe_shost_template, sizeof(*port)); 110572fa396bSVasu Dev else 110672fa396bSVasu Dev lport = libfc_vport_create(vport, sizeof(*port)); 110772fa396bSVasu Dev 110886221969SChris Leech if (!lport) { 1109014f5c3fSChris Leech FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); 1110014f5c3fSChris Leech rc = -ENOMEM; 1111030f4e00SChris Leech goto out; 1112014f5c3fSChris Leech } 1113014f5c3fSChris Leech port = lport_priv(lport); 11142e70e241SChris Leech port->lport = lport; 11158597ae8bSBhanu Prakash Gollapudi port->priv = fcoe; 111666524ec9SYi Zou port->get_netdev = fcoe_netdev; 11178597ae8bSBhanu Prakash Gollapudi port->max_queue_depth = FCOE_MAX_QUEUE_DEPTH; 11188597ae8bSBhanu Prakash Gollapudi port->min_queue_depth = FCOE_MIN_QUEUE_DEPTH; 11192e70e241SChris Leech INIT_WORK(&port->destroy_work, fcoe_destroy_work); 1120a703e490SVasu Dev 1121f9184df3SNeil Horman /* 1122f9184df3SNeil Horman * Need to add the lport to the hostlist 1123f9184df3SNeil Horman * so we catch NETDEV_CHANGE events. 1124f9184df3SNeil Horman */ 1125f9184df3SNeil Horman fcoe_hostlist_add(lport); 1126f9184df3SNeil Horman 11271875f27eSRobert Love /* configure a fc_lport including the exchange manager */ 1128af7f85d9SChris Leech rc = fcoe_lport_config(lport); 1129a703e490SVasu Dev if (rc) { 1130d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure lport for the " 1131d5488eb9SRobert Love "interface\n"); 1132a703e490SVasu Dev goto out_host_put; 1133a703e490SVasu Dev } 1134a703e490SVasu Dev 11359a05753bSChris Leech if (npiv) { 11369f8f3aa6SChris Leech FCOE_NETDEV_DBG(netdev, "Setting vport names, " 11379f8f3aa6SChris Leech "%16.16llx %16.16llx\n", 11389a05753bSChris Leech vport->node_name, vport->port_name); 11399a05753bSChris Leech fc_set_wwnn(lport, vport->node_name); 11409a05753bSChris Leech fc_set_wwpn(lport, vport->port_name); 11419a05753bSChris Leech } 11429a05753bSChris Leech 1143ab6b85c1SVasu Dev /* configure lport network properties */ 1144af7f85d9SChris Leech rc = fcoe_netdev_config(lport, netdev); 1145ab6b85c1SVasu Dev if (rc) { 1146d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " 1147d5488eb9SRobert Love "interface\n"); 114854b649f8SChris Leech goto out_lp_destroy; 1149ab6b85c1SVasu Dev } 115097c8389dSJoe Eykholt 1151a703e490SVasu Dev /* configure lport scsi host properties */ 11528ba00a4bSVasu Dev rc = fcoe_shost_config(lport, parent); 1153a703e490SVasu Dev if (rc) { 1154d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " 1155d5488eb9SRobert Love "interface\n"); 115654b649f8SChris Leech goto out_lp_destroy; 1157a703e490SVasu Dev } 1158a703e490SVasu Dev 1159a703e490SVasu Dev /* Initialize the library */ 1160619fe4beSRobert Love rc = fcoe_libfc_config(lport, ctlr, &fcoe_libfc_fcn_templ, 1); 1161a703e490SVasu Dev if (rc) { 1162d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " 1163d5488eb9SRobert Love "interface\n"); 1164a703e490SVasu Dev goto out_lp_destroy; 1165a703e490SVasu Dev } 1166a703e490SVasu Dev 11676fef3902SNeerav Parikh /* Initialized FDMI information */ 11686fef3902SNeerav Parikh fcoe_fdmi_info(lport, netdev); 11696fef3902SNeerav Parikh 1170e8af4d43SVasu Dev /* 1171e8af4d43SVasu Dev * fcoe_em_alloc() and fcoe_hostlist_add() both 11729a05753bSChris Leech * need to be atomic with respect to other changes to the 11739a05753bSChris Leech * hostlist since fcoe_em_alloc() looks for an existing EM 1174e8af4d43SVasu Dev * instance on host list updated by fcoe_hostlist_add(). 1175c863df33SChris Leech * 11769a05753bSChris Leech * This is currently handled through the fcoe_config_mutex 11779a05753bSChris Leech * begin held. 1178e8af4d43SVasu Dev */ 117972fa396bSVasu Dev if (!npiv) 118096316099SVasu Dev /* lport exch manager allocation */ 1181af7f85d9SChris Leech rc = fcoe_em_config(lport); 118272fa396bSVasu Dev else { 118372fa396bSVasu Dev shost = vport_to_shost(vport); 118472fa396bSVasu Dev n_port = shost_priv(shost); 118572fa396bSVasu Dev rc = fc_exch_mgr_list_clone(n_port, lport); 118696316099SVasu Dev } 118772fa396bSVasu Dev 118872fa396bSVasu Dev if (rc) { 118972fa396bSVasu Dev FCOE_NETDEV_DBG(netdev, "Could not configure the EM\n"); 119072fa396bSVasu Dev goto out_lp_destroy; 11919a05753bSChris Leech } 119296316099SVasu Dev 1193af7f85d9SChris Leech return lport; 1194a703e490SVasu Dev 1195a703e490SVasu Dev out_lp_destroy: 1196af7f85d9SChris Leech fc_exch_mgr_free(lport); 1197a703e490SVasu Dev out_host_put: 1198f9184df3SNeil Horman fcoe_hostlist_del(lport); 1199af7f85d9SChris Leech scsi_host_put(lport->host); 1200af7f85d9SChris Leech out: 1201af7f85d9SChris Leech return ERR_PTR(rc); 1202a703e490SVasu Dev } 1203a703e490SVasu Dev 1204a703e490SVasu Dev /** 12051875f27eSRobert Love * fcoe_if_init() - Initialization routine for fcoe.ko 12061875f27eSRobert Love * 12071875f27eSRobert Love * Attaches the SW FCoE transport to the FC transport 1208a703e490SVasu Dev * 1209a703e490SVasu Dev * Returns: 0 on success 1210a703e490SVasu Dev */ 1211a703e490SVasu Dev static int __init fcoe_if_init(void) 1212a703e490SVasu Dev { 1213a703e490SVasu Dev /* attach to scsi transport */ 12148ca86f84SYi Zou fcoe_nport_scsi_transport = 12158ca86f84SYi Zou fc_attach_transport(&fcoe_nport_fc_functions); 12168ca86f84SYi Zou fcoe_vport_scsi_transport = 12178ca86f84SYi Zou fc_attach_transport(&fcoe_vport_fc_functions); 1218a703e490SVasu Dev 12198ca86f84SYi Zou if (!fcoe_nport_scsi_transport) { 1220d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); 1221a703e490SVasu Dev return -ENODEV; 1222a703e490SVasu Dev } 1223a703e490SVasu Dev 1224a703e490SVasu Dev return 0; 1225a703e490SVasu Dev } 1226a703e490SVasu Dev 1227a703e490SVasu Dev /** 12281875f27eSRobert Love * fcoe_if_exit() - Tear down fcoe.ko 12291875f27eSRobert Love * 12301875f27eSRobert Love * Detaches the SW FCoE transport from the FC transport 1231a703e490SVasu Dev * 1232a703e490SVasu Dev * Returns: 0 on success 1233a703e490SVasu Dev */ 12347c9c6841SBart Van Assche static int __exit fcoe_if_exit(void) 1235a703e490SVasu Dev { 12368ca86f84SYi Zou fc_release_transport(fcoe_nport_scsi_transport); 12378ca86f84SYi Zou fc_release_transport(fcoe_vport_scsi_transport); 12388ca86f84SYi Zou fcoe_nport_scsi_transport = NULL; 12398ca86f84SYi Zou fcoe_vport_scsi_transport = NULL; 1240a703e490SVasu Dev return 0; 1241a703e490SVasu Dev } 1242a703e490SVasu Dev 1243a703e490SVasu Dev /** 12441875f27eSRobert Love * fcoe_percpu_thread_create() - Create a receive thread for an online CPU 12451875f27eSRobert Love * @cpu: The CPU index of the CPU to create a receive thread for 1246a703e490SVasu Dev */ 1247a703e490SVasu Dev static void fcoe_percpu_thread_create(unsigned int cpu) 1248a703e490SVasu Dev { 1249a703e490SVasu Dev struct fcoe_percpu_s *p; 1250a703e490SVasu Dev struct task_struct *thread; 1251a703e490SVasu Dev 1252a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 1253a703e490SVasu Dev 12545c609ff9SEric Dumazet thread = kthread_create_on_node(fcoe_percpu_receive_thread, 12555c609ff9SEric Dumazet (void *)p, cpu_to_node(cpu), 12565c609ff9SEric Dumazet "fcoethread/%d", cpu); 1257a703e490SVasu Dev 1258e7a51997SJoe Eykholt if (likely(!IS_ERR(thread))) { 1259a703e490SVasu Dev kthread_bind(thread, cpu); 1260a703e490SVasu Dev wake_up_process(thread); 1261a703e490SVasu Dev 1262a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1263a703e490SVasu Dev p->thread = thread; 1264a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1265a703e490SVasu Dev } 1266a703e490SVasu Dev } 1267a703e490SVasu Dev 1268a703e490SVasu Dev /** 12691875f27eSRobert Love * fcoe_percpu_thread_destroy() - Remove the receive thread of a CPU 12701875f27eSRobert Love * @cpu: The CPU index of the CPU whose receive thread is to be destroyed 1271a703e490SVasu Dev * 1272a703e490SVasu Dev * Destroys a per-CPU Rx thread. Any pending skbs are moved to the 1273a703e490SVasu Dev * current CPU's Rx thread. If the thread being destroyed is bound to 1274a703e490SVasu Dev * the CPU processing this context the skbs will be freed. 1275a703e490SVasu Dev */ 1276a703e490SVasu Dev static void fcoe_percpu_thread_destroy(unsigned int cpu) 1277a703e490SVasu Dev { 1278a703e490SVasu Dev struct fcoe_percpu_s *p; 1279a703e490SVasu Dev struct task_struct *thread; 1280a703e490SVasu Dev struct page *crc_eof; 1281a703e490SVasu Dev struct sk_buff *skb; 1282a703e490SVasu Dev #ifdef CONFIG_SMP 1283a703e490SVasu Dev struct fcoe_percpu_s *p0; 1284f018b73aSJoe Eykholt unsigned targ_cpu = get_cpu(); 1285a703e490SVasu Dev #endif /* CONFIG_SMP */ 1286a703e490SVasu Dev 1287d5488eb9SRobert Love FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); 1288a703e490SVasu Dev 1289a703e490SVasu Dev /* Prevent any new skbs from being queued for this CPU. */ 1290a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 1291a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1292a703e490SVasu Dev thread = p->thread; 1293a703e490SVasu Dev p->thread = NULL; 1294a703e490SVasu Dev crc_eof = p->crc_eof_page; 1295a703e490SVasu Dev p->crc_eof_page = NULL; 1296a703e490SVasu Dev p->crc_eof_offset = 0; 1297a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1298a703e490SVasu Dev 1299a703e490SVasu Dev #ifdef CONFIG_SMP 1300a703e490SVasu Dev /* 1301a703e490SVasu Dev * Don't bother moving the skb's if this context is running 1302a703e490SVasu Dev * on the same CPU that is having its thread destroyed. This 1303a703e490SVasu Dev * can easily happen when the module is removed. 1304a703e490SVasu Dev */ 1305a703e490SVasu Dev if (cpu != targ_cpu) { 1306a703e490SVasu Dev p0 = &per_cpu(fcoe_percpu, targ_cpu); 1307a703e490SVasu Dev spin_lock_bh(&p0->fcoe_rx_list.lock); 1308a703e490SVasu Dev if (p0->thread) { 1309d5488eb9SRobert Love FCOE_DBG("Moving frames from CPU %d to CPU %d\n", 1310a703e490SVasu Dev cpu, targ_cpu); 1311a703e490SVasu Dev 1312a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1313a703e490SVasu Dev __skb_queue_tail(&p0->fcoe_rx_list, skb); 1314a703e490SVasu Dev spin_unlock_bh(&p0->fcoe_rx_list.lock); 1315a703e490SVasu Dev } else { 1316a703e490SVasu Dev /* 1317a703e490SVasu Dev * The targeted CPU is not initialized and cannot accept 1318a703e490SVasu Dev * new skbs. Unlock the targeted CPU and drop the skbs 1319a703e490SVasu Dev * on the CPU that is going offline. 1320a703e490SVasu Dev */ 1321a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1322a703e490SVasu Dev kfree_skb(skb); 1323a703e490SVasu Dev spin_unlock_bh(&p0->fcoe_rx_list.lock); 1324a703e490SVasu Dev } 1325a703e490SVasu Dev } else { 1326a703e490SVasu Dev /* 1327a703e490SVasu Dev * This scenario occurs when the module is being removed 1328a703e490SVasu Dev * and all threads are being destroyed. skbs will continue 1329a703e490SVasu Dev * to be shifted from the CPU thread that is being removed 1330a703e490SVasu Dev * to the CPU thread associated with the CPU that is processing 1331a703e490SVasu Dev * the module removal. Once there is only one CPU Rx thread it 1332a703e490SVasu Dev * will reach this case and we will drop all skbs and later 1333a703e490SVasu Dev * stop the thread. 1334a703e490SVasu Dev */ 1335a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1336a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1337a703e490SVasu Dev kfree_skb(skb); 1338a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1339a703e490SVasu Dev } 1340f018b73aSJoe Eykholt put_cpu(); 1341a703e490SVasu Dev #else 1342a703e490SVasu Dev /* 1343dd3fd72eSChris Leech * This a non-SMP scenario where the singular Rx thread is 1344a703e490SVasu Dev * being removed. Free all skbs and stop the thread. 1345a703e490SVasu Dev */ 1346a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1347a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1348a703e490SVasu Dev kfree_skb(skb); 1349a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1350a703e490SVasu Dev #endif 1351a703e490SVasu Dev 1352a703e490SVasu Dev if (thread) 1353a703e490SVasu Dev kthread_stop(thread); 1354a703e490SVasu Dev 1355a703e490SVasu Dev if (crc_eof) 1356a703e490SVasu Dev put_page(crc_eof); 1357a703e490SVasu Dev } 1358a703e490SVasu Dev 1359a703e490SVasu Dev /** 13601875f27eSRobert Love * fcoe_cpu_callback() - Handler for CPU hotplug events 13611875f27eSRobert Love * @nfb: The callback data block 13621875f27eSRobert Love * @action: The event triggering the callback 13631875f27eSRobert Love * @hcpu: The index of the CPU that the event is for 1364a703e490SVasu Dev * 13651875f27eSRobert Love * This creates or destroys per-CPU data for fcoe 1366a703e490SVasu Dev * 1367a703e490SVasu Dev * Returns NOTIFY_OK always. 1368a703e490SVasu Dev */ 1369a703e490SVasu Dev static int fcoe_cpu_callback(struct notifier_block *nfb, 1370a703e490SVasu Dev unsigned long action, void *hcpu) 1371a703e490SVasu Dev { 1372a703e490SVasu Dev unsigned cpu = (unsigned long)hcpu; 1373a703e490SVasu Dev 1374a703e490SVasu Dev switch (action) { 1375a703e490SVasu Dev case CPU_ONLINE: 1376a703e490SVasu Dev case CPU_ONLINE_FROZEN: 1377d5488eb9SRobert Love FCOE_DBG("CPU %x online: Create Rx thread\n", cpu); 1378a703e490SVasu Dev fcoe_percpu_thread_create(cpu); 1379a703e490SVasu Dev break; 1380a703e490SVasu Dev case CPU_DEAD: 1381a703e490SVasu Dev case CPU_DEAD_FROZEN: 1382d5488eb9SRobert Love FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu); 1383a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 1384a703e490SVasu Dev break; 1385a703e490SVasu Dev default: 1386a703e490SVasu Dev break; 1387a703e490SVasu Dev } 1388a703e490SVasu Dev return NOTIFY_OK; 1389a703e490SVasu Dev } 1390a703e490SVasu Dev 1391a703e490SVasu Dev /** 1392064287eeSKiran Patil * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming 1393064287eeSKiran Patil * command. 1394064287eeSKiran Patil * 1395d272281cSVasu Dev * This routine selects next CPU based on cpumask to distribute 1396d272281cSVasu Dev * incoming requests in round robin. 1397064287eeSKiran Patil * 1398d272281cSVasu Dev * Returns: int CPU number 1399064287eeSKiran Patil */ 1400d272281cSVasu Dev static inline unsigned int fcoe_select_cpu(void) 1401064287eeSKiran Patil { 1402064287eeSKiran Patil static unsigned int selected_cpu; 1403064287eeSKiran Patil 1404064287eeSKiran Patil selected_cpu = cpumask_next(selected_cpu, cpu_online_mask); 1405064287eeSKiran Patil if (selected_cpu >= nr_cpu_ids) 1406064287eeSKiran Patil selected_cpu = cpumask_first(cpu_online_mask); 1407d272281cSVasu Dev 1408064287eeSKiran Patil return selected_cpu; 1409064287eeSKiran Patil } 1410064287eeSKiran Patil 1411064287eeSKiran Patil /** 14121875f27eSRobert Love * fcoe_rcv() - Receive packets from a net device 14131875f27eSRobert Love * @skb: The received packet 14141875f27eSRobert Love * @netdev: The net device that the packet was received on 14151875f27eSRobert Love * @ptype: The packet type context 14161875f27eSRobert Love * @olddev: The last device net device 1417a703e490SVasu Dev * 14181875f27eSRobert Love * This routine is called by NET_RX_SOFTIRQ. It receives a packet, builds a 14191875f27eSRobert Love * FC frame and passes the frame to libfc. 1420a703e490SVasu Dev * 1421a703e490SVasu Dev * Returns: 0 for success 1422a703e490SVasu Dev */ 14237c9c6841SBart Van Assche static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, 1424a703e490SVasu Dev struct packet_type *ptype, struct net_device *olddev) 1425a703e490SVasu Dev { 14261875f27eSRobert Love struct fc_lport *lport; 1427a703e490SVasu Dev struct fcoe_rcv_info *fr; 1428619fe4beSRobert Love struct fcoe_ctlr *ctlr; 1429259ad85dSChris Leech struct fcoe_interface *fcoe; 1430a703e490SVasu Dev struct fc_frame_header *fh; 1431a703e490SVasu Dev struct fcoe_percpu_s *fps; 1432519e5135SVasu Dev struct ethhdr *eh; 1433b2f0091fSVasu Dev unsigned int cpu; 1434a703e490SVasu Dev 1435259ad85dSChris Leech fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); 1436619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1437619fe4beSRobert Love lport = ctlr->lp; 14381875f27eSRobert Love if (unlikely(!lport)) { 14391875f27eSRobert Love FCOE_NETDEV_DBG(netdev, "Cannot find hba structure"); 1440a703e490SVasu Dev goto err2; 1441a703e490SVasu Dev } 14421875f27eSRobert Love if (!lport->link_up) 144397c8389dSJoe Eykholt goto err2; 1444a703e490SVasu Dev 14451875f27eSRobert Love FCOE_NETDEV_DBG(netdev, "skb_info: len:%d data_len:%d head:%p " 1446d5488eb9SRobert Love "data:%p tail:%p end:%p sum:%d dev:%s", 1447d5488eb9SRobert Love skb->len, skb->data_len, skb->head, skb->data, 1448d5488eb9SRobert Love skb_tail_pointer(skb), skb_end_pointer(skb), 1449d5488eb9SRobert Love skb->csum, skb->dev ? skb->dev->name : "<NULL>"); 1450a703e490SVasu Dev 1451519e5135SVasu Dev eh = eth_hdr(skb); 1452519e5135SVasu Dev 1453619fe4beSRobert Love if (is_fip_mode(ctlr) && 1454619fe4beSRobert Love compare_ether_addr(eh->h_source, ctlr->dest_addr)) { 1455519e5135SVasu Dev FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n", 1456519e5135SVasu Dev eh->h_source); 1457a703e490SVasu Dev goto err; 1458a703e490SVasu Dev } 1459a703e490SVasu Dev 1460a703e490SVasu Dev /* 1461a703e490SVasu Dev * Check for minimum frame length, and make sure required FCoE 1462a703e490SVasu Dev * and FC headers are pulled into the linear data area. 1463a703e490SVasu Dev */ 1464a703e490SVasu Dev if (unlikely((skb->len < FCOE_MIN_FRAME) || 1465a703e490SVasu Dev !pskb_may_pull(skb, FCOE_HEADER_LEN))) 1466a703e490SVasu Dev goto err; 1467a703e490SVasu Dev 1468a703e490SVasu Dev skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); 1469a703e490SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 1470a703e490SVasu Dev 14710ee31cb5SRobert Love if (ntoh24(&eh->h_dest[3]) != ntoh24(fh->fh_d_id)) { 14720ee31cb5SRobert Love FCOE_NETDEV_DBG(netdev, "FC frame d_id mismatch with MAC:%pM\n", 14730ee31cb5SRobert Love eh->h_dest); 14740ee31cb5SRobert Love goto err; 14750ee31cb5SRobert Love } 14760ee31cb5SRobert Love 1477a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 14781875f27eSRobert Love fr->fr_dev = lport; 1479a703e490SVasu Dev 1480a703e490SVasu Dev /* 1481b2f0091fSVasu Dev * In case the incoming frame's exchange is originated from 1482b2f0091fSVasu Dev * the initiator, then received frame's exchange id is ANDed 1483b2f0091fSVasu Dev * with fc_cpu_mask bits to get the same cpu on which exchange 1484d272281cSVasu Dev * was originated, otherwise select cpu using rx exchange id 1485d272281cSVasu Dev * or fcoe_select_cpu(). 1486a703e490SVasu Dev */ 1487b2f0091fSVasu Dev if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) 1488b2f0091fSVasu Dev cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; 1489064287eeSKiran Patil else { 1490d272281cSVasu Dev if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN) 1491d272281cSVasu Dev cpu = fcoe_select_cpu(); 1492d272281cSVasu Dev else 149329bdd2bbSKiran Patil cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask; 1494064287eeSKiran Patil } 1495324f6678SVasu Dev 1496324f6678SVasu Dev if (cpu >= nr_cpu_ids) 1497324f6678SVasu Dev goto err; 1498324f6678SVasu Dev 1499a703e490SVasu Dev fps = &per_cpu(fcoe_percpu, cpu); 150094aa29f2SNeil Horman spin_lock(&fps->fcoe_rx_list.lock); 1501a703e490SVasu Dev if (unlikely(!fps->thread)) { 1502a703e490SVasu Dev /* 1503a703e490SVasu Dev * The targeted CPU is not ready, let's target 1504a703e490SVasu Dev * the first CPU now. For non-SMP systems this 1505a703e490SVasu Dev * will check the same CPU twice. 1506a703e490SVasu Dev */ 15071875f27eSRobert Love FCOE_NETDEV_DBG(netdev, "CPU is online, but no receive thread " 1508d5488eb9SRobert Love "ready for incoming skb- using first online " 1509d5488eb9SRobert Love "CPU.\n"); 1510a703e490SVasu Dev 151194aa29f2SNeil Horman spin_unlock(&fps->fcoe_rx_list.lock); 15126957177fSRusty Russell cpu = cpumask_first(cpu_online_mask); 1513a703e490SVasu Dev fps = &per_cpu(fcoe_percpu, cpu); 151494aa29f2SNeil Horman spin_lock(&fps->fcoe_rx_list.lock); 1515a703e490SVasu Dev if (!fps->thread) { 151694aa29f2SNeil Horman spin_unlock(&fps->fcoe_rx_list.lock); 1517a703e490SVasu Dev goto err; 1518a703e490SVasu Dev } 1519a703e490SVasu Dev } 1520a703e490SVasu Dev 1521a703e490SVasu Dev /* 1522a703e490SVasu Dev * We now have a valid CPU that we're targeting for 1523a703e490SVasu Dev * this skb. We also have this receive thread locked, 1524a703e490SVasu Dev * so we're free to queue skbs into it's queue. 1525a703e490SVasu Dev */ 1526859b7b64SChris Leech 15275e70c4c4SNeil Horman /* 15285e70c4c4SNeil Horman * Note: We used to have a set of conditions under which we would 15295e70c4c4SNeil Horman * call fcoe_recv_frame directly, rather than queuing to the rx list 15305e70c4c4SNeil Horman * as it could save a few cycles, but doing so is prohibited, as 15315e70c4c4SNeil Horman * fcoe_recv_frame has several paths that may sleep, which is forbidden 15325e70c4c4SNeil Horman * in softirq context. 1533859b7b64SChris Leech */ 1534a703e490SVasu Dev __skb_queue_tail(&fps->fcoe_rx_list, skb); 153520dc3811SNeil Horman if (fps->thread->state == TASK_INTERRUPTIBLE) 1536a703e490SVasu Dev wake_up_process(fps->thread); 153794aa29f2SNeil Horman spin_unlock(&fps->fcoe_rx_list.lock); 1538a703e490SVasu Dev 1539a703e490SVasu Dev return 0; 1540a703e490SVasu Dev err: 15411bd49b48SVasu Dev per_cpu_ptr(lport->stats, get_cpu())->ErrorFrames++; 1542f018b73aSJoe Eykholt put_cpu(); 1543a703e490SVasu Dev err2: 1544a703e490SVasu Dev kfree_skb(skb); 1545a703e490SVasu Dev return -1; 1546a703e490SVasu Dev } 1547a703e490SVasu Dev 1548a703e490SVasu Dev /** 15498597ae8bSBhanu Prakash Gollapudi * fcoe_alloc_paged_crc_eof() - Allocate a page to be used for the trailer CRC 15501875f27eSRobert Love * @skb: The packet to be transmitted 15511875f27eSRobert Love * @tlen: The total length of the trailer 15521875f27eSRobert Love * 1553a703e490SVasu Dev * Returns: 0 for success 1554a703e490SVasu Dev */ 15558597ae8bSBhanu Prakash Gollapudi static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen) 1556a703e490SVasu Dev { 1557a703e490SVasu Dev struct fcoe_percpu_s *fps; 15588597ae8bSBhanu Prakash Gollapudi int rc; 1559a703e490SVasu Dev 1560a703e490SVasu Dev fps = &get_cpu_var(fcoe_percpu); 15618597ae8bSBhanu Prakash Gollapudi rc = fcoe_get_paged_crc_eof(skb, tlen, fps); 1562a703e490SVasu Dev put_cpu_var(fcoe_percpu); 1563a703e490SVasu Dev 15648597ae8bSBhanu Prakash Gollapudi return rc; 1565a703e490SVasu Dev } 1566a703e490SVasu Dev 1567a703e490SVasu Dev /** 15681875f27eSRobert Love * fcoe_xmit() - Transmit a FCoE frame 15691875f27eSRobert Love * @lport: The local port that the frame is to be transmitted for 15701875f27eSRobert Love * @fp: The frame to be transmitted 1571a703e490SVasu Dev * 1572a703e490SVasu Dev * Return: 0 for success 1573a703e490SVasu Dev */ 15747c9c6841SBart Van Assche static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) 1575a703e490SVasu Dev { 15764bb6b515SVasu Dev int wlen; 1577a703e490SVasu Dev u32 crc; 1578a703e490SVasu Dev struct ethhdr *eh; 1579a703e490SVasu Dev struct fcoe_crc_eof *cp; 1580a703e490SVasu Dev struct sk_buff *skb; 15811bd49b48SVasu Dev struct fc_stats *stats; 1582a703e490SVasu Dev struct fc_frame_header *fh; 1583a703e490SVasu Dev unsigned int hlen; /* header length implies the version */ 1584a703e490SVasu Dev unsigned int tlen; /* trailer length */ 1585a703e490SVasu Dev unsigned int elen; /* eth header, may include vlan */ 15861875f27eSRobert Love struct fcoe_port *port = lport_priv(lport); 15878597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 1588619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 1589a703e490SVasu Dev u8 sof, eof; 1590a703e490SVasu Dev struct fcoe_hdr *hp; 1591a703e490SVasu Dev 1592a703e490SVasu Dev WARN_ON((fr_len(fp) % sizeof(u32)) != 0); 1593a703e490SVasu Dev 1594a703e490SVasu Dev fh = fc_frame_header_get(fp); 159597c8389dSJoe Eykholt skb = fp_skb(fp); 159697c8389dSJoe Eykholt wlen = skb->len / FCOE_WORD_TO_BYTE; 159797c8389dSJoe Eykholt 15981875f27eSRobert Love if (!lport->link_up) { 15993caf02eeSDan Carpenter kfree_skb(skb); 160097c8389dSJoe Eykholt return 0; 1601a703e490SVasu Dev } 1602a703e490SVasu Dev 16039860eeb4SJoe Eykholt if (unlikely(fh->fh_type == FC_TYPE_ELS) && 1604619fe4beSRobert Love fcoe_ctlr_els_send(ctlr, lport, skb)) 160597c8389dSJoe Eykholt return 0; 160697c8389dSJoe Eykholt 1607a703e490SVasu Dev sof = fr_sof(fp); 1608a703e490SVasu Dev eof = fr_eof(fp); 1609a703e490SVasu Dev 16104e57e1cbSVasu Dev elen = sizeof(struct ethhdr); 1611a703e490SVasu Dev hlen = sizeof(struct fcoe_hdr); 1612a703e490SVasu Dev tlen = sizeof(struct fcoe_crc_eof); 1613a703e490SVasu Dev wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; 1614a703e490SVasu Dev 1615a703e490SVasu Dev /* crc offload */ 16161875f27eSRobert Love if (likely(lport->crc_offload)) { 1617cf64bc8fSYi Zou skb->ip_summed = CHECKSUM_UNNECESSARY; 1618a703e490SVasu Dev skb->csum_start = skb_headroom(skb); 1619a703e490SVasu Dev skb->csum_offset = skb->len; 1620a703e490SVasu Dev crc = 0; 1621a703e490SVasu Dev } else { 1622a703e490SVasu Dev skb->ip_summed = CHECKSUM_NONE; 1623a703e490SVasu Dev crc = fcoe_fc_crc(fp); 1624a703e490SVasu Dev } 1625a703e490SVasu Dev 1626014f5c3fSChris Leech /* copy port crc and eof to the skb buff */ 1627a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 1628a703e490SVasu Dev skb_frag_t *frag; 16298597ae8bSBhanu Prakash Gollapudi if (fcoe_alloc_paged_crc_eof(skb, tlen)) { 1630a703e490SVasu Dev kfree_skb(skb); 1631a703e490SVasu Dev return -ENOMEM; 1632a703e490SVasu Dev } 1633a703e490SVasu Dev frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; 163477dfce07SCong Wang cp = kmap_atomic(skb_frag_page(frag)) 1635a703e490SVasu Dev + frag->page_offset; 1636a703e490SVasu Dev } else { 1637a703e490SVasu Dev cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); 1638a703e490SVasu Dev } 1639a703e490SVasu Dev 1640a703e490SVasu Dev memset(cp, 0, sizeof(*cp)); 1641a703e490SVasu Dev cp->fcoe_eof = eof; 1642a703e490SVasu Dev cp->fcoe_crc32 = cpu_to_le32(~crc); 1643a703e490SVasu Dev 1644a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 164577dfce07SCong Wang kunmap_atomic(cp); 1646a703e490SVasu Dev cp = NULL; 1647a703e490SVasu Dev } 1648a703e490SVasu Dev 1649014f5c3fSChris Leech /* adjust skb network/transport offsets to match mac/fcoe/port */ 1650a703e490SVasu Dev skb_push(skb, elen + hlen); 1651a703e490SVasu Dev skb_reset_mac_header(skb); 1652a703e490SVasu Dev skb_reset_network_header(skb); 1653a703e490SVasu Dev skb->mac_len = elen; 1654a703e490SVasu Dev skb->protocol = htons(ETH_P_FCOE); 165531c37a6fSNeerav Parikh skb->priority = fcoe->priority; 16566f6c2aa3Sjohn fastabend 1657d1483bb9SVasu Dev if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN && 1658f646968fSPatrick McHardy fcoe->realdev->features & NETIF_F_HW_VLAN_CTAG_TX) { 1659d1483bb9SVasu Dev skb->vlan_tci = VLAN_TAG_PRESENT | 1660d1483bb9SVasu Dev vlan_dev_vlan_id(fcoe->netdev); 1661d1483bb9SVasu Dev skb->dev = fcoe->realdev; 1662d1483bb9SVasu Dev } else 16633fe9a0baSChris Leech skb->dev = fcoe->netdev; 1664a703e490SVasu Dev 1665a703e490SVasu Dev /* fill up mac and fcoe headers */ 1666a703e490SVasu Dev eh = eth_hdr(skb); 1667a703e490SVasu Dev eh->h_proto = htons(ETH_P_FCOE); 1668619fe4beSRobert Love memcpy(eh->h_dest, ctlr->dest_addr, ETH_ALEN); 1669619fe4beSRobert Love if (ctlr->map_dest) 1670cd229e42SJoe Eykholt memcpy(eh->h_dest + 3, fh->fh_d_id, 3); 1671a703e490SVasu Dev 1672619fe4beSRobert Love if (unlikely(ctlr->flogi_oxid != FC_XID_UNKNOWN)) 1673619fe4beSRobert Love memcpy(eh->h_source, ctlr->ctl_src_addr, ETH_ALEN); 1674a703e490SVasu Dev else 167511b56188SChris Leech memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); 1676a703e490SVasu Dev 1677a703e490SVasu Dev hp = (struct fcoe_hdr *)(eh + 1); 1678a703e490SVasu Dev memset(hp, 0, sizeof(*hp)); 1679a703e490SVasu Dev if (FC_FCOE_VER) 1680a703e490SVasu Dev FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); 1681a703e490SVasu Dev hp->fcoe_sof = sof; 1682a703e490SVasu Dev 1683a703e490SVasu Dev /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ 16841875f27eSRobert Love if (lport->seq_offload && fr_max_payload(fp)) { 1685a703e490SVasu Dev skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; 1686a703e490SVasu Dev skb_shinfo(skb)->gso_size = fr_max_payload(fp); 1687a703e490SVasu Dev } else { 1688a703e490SVasu Dev skb_shinfo(skb)->gso_type = 0; 1689a703e490SVasu Dev skb_shinfo(skb)->gso_size = 0; 1690a703e490SVasu Dev } 1691a703e490SVasu Dev /* update tx stats: regardless if LLD fails */ 16921bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 1693a703e490SVasu Dev stats->TxFrames++; 1694a703e490SVasu Dev stats->TxWords += wlen; 1695f018b73aSJoe Eykholt put_cpu(); 1696a703e490SVasu Dev 1697a703e490SVasu Dev /* send down to lld */ 16981875f27eSRobert Love fr_dev(fp) = lport; 1699980f5156SVasu Dev fcoe_port_send(port, skb); 1700a703e490SVasu Dev return 0; 1701a703e490SVasu Dev } 1702a703e490SVasu Dev 1703a703e490SVasu Dev /** 17041875f27eSRobert Love * fcoe_percpu_flush_done() - Indicate per-CPU queue flush completion 17051875f27eSRobert Love * @skb: The completed skb (argument required by destructor) 1706e7a51997SJoe Eykholt */ 1707e7a51997SJoe Eykholt static void fcoe_percpu_flush_done(struct sk_buff *skb) 1708e7a51997SJoe Eykholt { 1709e7a51997SJoe Eykholt complete(&fcoe_flush_completion); 1710e7a51997SJoe Eykholt } 1711e7a51997SJoe Eykholt 1712e7a51997SJoe Eykholt /** 171352ee8321SVasu Dev * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC 171452ee8321SVasu Dev * @lport: The local port the frame was received on 171552ee8321SVasu Dev * @fp: The received frame 171652ee8321SVasu Dev * 171752ee8321SVasu Dev * Return: 0 on passing filtering checks 171852ee8321SVasu Dev */ 171952ee8321SVasu Dev static inline int fcoe_filter_frames(struct fc_lport *lport, 172052ee8321SVasu Dev struct fc_frame *fp) 172152ee8321SVasu Dev { 1722619fe4beSRobert Love struct fcoe_ctlr *ctlr; 172352ee8321SVasu Dev struct fcoe_interface *fcoe; 172452ee8321SVasu Dev struct fc_frame_header *fh; 172552ee8321SVasu Dev struct sk_buff *skb = (struct sk_buff *)fp; 17261bd49b48SVasu Dev struct fc_stats *stats; 172752ee8321SVasu Dev 172852ee8321SVasu Dev /* 172952ee8321SVasu Dev * We only check CRC if no offload is available and if it is 173052ee8321SVasu Dev * it's solicited data, in which case, the FCP layer would 173152ee8321SVasu Dev * check it during the copy. 173252ee8321SVasu Dev */ 173352ee8321SVasu Dev if (lport->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY) 173452ee8321SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 173552ee8321SVasu Dev else 173652ee8321SVasu Dev fr_flags(fp) |= FCPHF_CRC_UNCHECKED; 173752ee8321SVasu Dev 173852ee8321SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 173952ee8321SVasu Dev fh = fc_frame_header_get(fp); 174052ee8321SVasu Dev if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) 174152ee8321SVasu Dev return 0; 174252ee8321SVasu Dev 17438597ae8bSBhanu Prakash Gollapudi fcoe = ((struct fcoe_port *)lport_priv(lport))->priv; 1744619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1745619fe4beSRobert Love if (is_fip_mode(ctlr) && fc_frame_payload_op(fp) == ELS_LOGO && 174652ee8321SVasu Dev ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { 174752ee8321SVasu Dev FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n"); 174852ee8321SVasu Dev return -EINVAL; 174952ee8321SVasu Dev } 175052ee8321SVasu Dev 1751f2f96d20SDan Carpenter if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED) || 175252ee8321SVasu Dev le32_to_cpu(fr_crc(fp)) == ~crc32(~0, skb->data, skb->len)) { 175352ee8321SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 175452ee8321SVasu Dev return 0; 175552ee8321SVasu Dev } 175652ee8321SVasu Dev 17571bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 175852ee8321SVasu Dev stats->InvalidCRCCount++; 175952ee8321SVasu Dev if (stats->InvalidCRCCount < 5) 176052ee8321SVasu Dev printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); 17617e1e7eadSThomas Gleixner put_cpu(); 176252ee8321SVasu Dev return -EINVAL; 176352ee8321SVasu Dev } 176452ee8321SVasu Dev 176552ee8321SVasu Dev /** 1766859b7b64SChris Leech * fcoe_recv_frame() - process a single received frame 1767859b7b64SChris Leech * @skb: frame to process 1768a703e490SVasu Dev */ 1769859b7b64SChris Leech static void fcoe_recv_frame(struct sk_buff *skb) 1770a703e490SVasu Dev { 1771a703e490SVasu Dev u32 fr_len; 17721875f27eSRobert Love struct fc_lport *lport; 1773a703e490SVasu Dev struct fcoe_rcv_info *fr; 17741bd49b48SVasu Dev struct fc_stats *stats; 1775a703e490SVasu Dev struct fcoe_crc_eof crc_eof; 1776a703e490SVasu Dev struct fc_frame *fp; 1777014f5c3fSChris Leech struct fcoe_port *port; 1778a703e490SVasu Dev struct fcoe_hdr *hp; 1779a703e490SVasu Dev 1780a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 17811875f27eSRobert Love lport = fr->fr_dev; 17821875f27eSRobert Love if (unlikely(!lport)) { 1783e7a51997SJoe Eykholt if (skb->destructor != fcoe_percpu_flush_done) 1784e7a51997SJoe Eykholt FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb"); 1785a703e490SVasu Dev kfree_skb(skb); 1786859b7b64SChris Leech return; 1787a703e490SVasu Dev } 1788a703e490SVasu Dev 1789d5488eb9SRobert Love FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d " 1790d5488eb9SRobert Love "head:%p data:%p tail:%p end:%p sum:%d dev:%s", 1791a703e490SVasu Dev skb->len, skb->data_len, 1792a703e490SVasu Dev skb->head, skb->data, skb_tail_pointer(skb), 1793a703e490SVasu Dev skb_end_pointer(skb), skb->csum, 1794a703e490SVasu Dev skb->dev ? skb->dev->name : "<NULL>"); 1795a703e490SVasu Dev 17961875f27eSRobert Love port = lport_priv(lport); 1797f1633011SRobert Love skb_linearize(skb); /* check for skb_is_nonlinear is within skb_linearize */ 1798a703e490SVasu Dev 1799a703e490SVasu Dev /* 1800a703e490SVasu Dev * Frame length checks and setting up the header pointers 1801a703e490SVasu Dev * was done in fcoe_rcv already. 1802a703e490SVasu Dev */ 1803a703e490SVasu Dev hp = (struct fcoe_hdr *) skb_network_header(skb); 1804a703e490SVasu Dev 18051bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 1806a703e490SVasu Dev if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { 1807a703e490SVasu Dev if (stats->ErrorFrames < 5) 1808d5488eb9SRobert Love printk(KERN_WARNING "fcoe: FCoE version " 1809a703e490SVasu Dev "mismatch: The frame has " 1810a703e490SVasu Dev "version %x, but the " 1811a703e490SVasu Dev "initiator supports version " 1812a703e490SVasu Dev "%x\n", FC_FCOE_DECAPS_VER(hp), 1813a703e490SVasu Dev FC_FCOE_VER); 1814f018b73aSJoe Eykholt goto drop; 1815a703e490SVasu Dev } 1816a703e490SVasu Dev 1817a703e490SVasu Dev skb_pull(skb, sizeof(struct fcoe_hdr)); 1818a703e490SVasu Dev fr_len = skb->len - sizeof(struct fcoe_crc_eof); 1819a703e490SVasu Dev 1820a703e490SVasu Dev stats->RxFrames++; 1821a703e490SVasu Dev stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; 1822a703e490SVasu Dev 1823a703e490SVasu Dev fp = (struct fc_frame *)skb; 1824a703e490SVasu Dev fc_frame_init(fp); 18251875f27eSRobert Love fr_dev(fp) = lport; 1826a703e490SVasu Dev fr_sof(fp) = hp->fcoe_sof; 1827a703e490SVasu Dev 1828a703e490SVasu Dev /* Copy out the CRC and EOF trailer for access */ 1829f018b73aSJoe Eykholt if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) 1830f018b73aSJoe Eykholt goto drop; 1831a703e490SVasu Dev fr_eof(fp) = crc_eof.fcoe_eof; 1832a703e490SVasu Dev fr_crc(fp) = crc_eof.fcoe_crc32; 1833f018b73aSJoe Eykholt if (pskb_trim(skb, fr_len)) 1834f018b73aSJoe Eykholt goto drop; 1835a703e490SVasu Dev 183652ee8321SVasu Dev if (!fcoe_filter_frames(lport, fp)) { 1837f018b73aSJoe Eykholt put_cpu(); 18381875f27eSRobert Love fc_exch_recv(lport, fp); 1839f018b73aSJoe Eykholt return; 184052ee8321SVasu Dev } 1841f018b73aSJoe Eykholt drop: 1842f018b73aSJoe Eykholt stats->ErrorFrames++; 1843f018b73aSJoe Eykholt put_cpu(); 1844f018b73aSJoe Eykholt kfree_skb(skb); 1845a703e490SVasu Dev } 1846859b7b64SChris Leech 1847859b7b64SChris Leech /** 1848859b7b64SChris Leech * fcoe_percpu_receive_thread() - The per-CPU packet receive thread 1849859b7b64SChris Leech * @arg: The per-CPU context 1850859b7b64SChris Leech * 1851859b7b64SChris Leech * Return: 0 for success 1852859b7b64SChris Leech */ 18537c9c6841SBart Van Assche static int fcoe_percpu_receive_thread(void *arg) 1854859b7b64SChris Leech { 1855859b7b64SChris Leech struct fcoe_percpu_s *p = arg; 1856859b7b64SChris Leech struct sk_buff *skb; 185720dc3811SNeil Horman struct sk_buff_head tmp; 185820dc3811SNeil Horman 185920dc3811SNeil Horman skb_queue_head_init(&tmp); 1860859b7b64SChris Leech 1861859b7b64SChris Leech set_user_nice(current, -20); 1862859b7b64SChris Leech 186395fdd5e9SNeil Horman retry: 1864859b7b64SChris Leech while (!kthread_should_stop()) { 1865859b7b64SChris Leech 1866859b7b64SChris Leech spin_lock_bh(&p->fcoe_rx_list.lock); 186720dc3811SNeil Horman skb_queue_splice_init(&p->fcoe_rx_list, &tmp); 186895fdd5e9SNeil Horman 186995fdd5e9SNeil Horman if (!skb_queue_len(&tmp)) { 187095fdd5e9SNeil Horman set_current_state(TASK_INTERRUPTIBLE); 187195fdd5e9SNeil Horman spin_unlock_bh(&p->fcoe_rx_list.lock); 187295fdd5e9SNeil Horman schedule(); 187395fdd5e9SNeil Horman set_current_state(TASK_RUNNING); 187495fdd5e9SNeil Horman goto retry; 187595fdd5e9SNeil Horman } 187695fdd5e9SNeil Horman 187720dc3811SNeil Horman spin_unlock_bh(&p->fcoe_rx_list.lock); 187820dc3811SNeil Horman 187920dc3811SNeil Horman while ((skb = __skb_dequeue(&tmp)) != NULL) 188020dc3811SNeil Horman fcoe_recv_frame(skb); 188120dc3811SNeil Horman 1882859b7b64SChris Leech } 1883a703e490SVasu Dev return 0; 1884a703e490SVasu Dev } 1885a703e490SVasu Dev 1886a703e490SVasu Dev /** 18871875f27eSRobert Love * fcoe_dev_setup() - Setup the link change notification interface 1888a703e490SVasu Dev */ 1889b0d428adSRandy Dunlap static void fcoe_dev_setup(void) 1890a703e490SVasu Dev { 18916f6c2aa3Sjohn fastabend register_dcbevent_notifier(&dcb_notifier); 1892a703e490SVasu Dev register_netdevice_notifier(&fcoe_notifier); 1893a703e490SVasu Dev } 1894a703e490SVasu Dev 1895a703e490SVasu Dev /** 18961875f27eSRobert Love * fcoe_dev_cleanup() - Cleanup the link change notification interface 1897a703e490SVasu Dev */ 1898a703e490SVasu Dev static void fcoe_dev_cleanup(void) 1899a703e490SVasu Dev { 19006f6c2aa3Sjohn fastabend unregister_dcbevent_notifier(&dcb_notifier); 1901a703e490SVasu Dev unregister_netdevice_notifier(&fcoe_notifier); 1902a703e490SVasu Dev } 1903a703e490SVasu Dev 19046f6c2aa3Sjohn fastabend static struct fcoe_interface * 19056f6c2aa3Sjohn fastabend fcoe_hostlist_lookup_realdev_port(struct net_device *netdev) 19066f6c2aa3Sjohn fastabend { 19076f6c2aa3Sjohn fastabend struct fcoe_interface *fcoe; 19086f6c2aa3Sjohn fastabend struct net_device *real_dev; 19096f6c2aa3Sjohn fastabend 19106f6c2aa3Sjohn fastabend list_for_each_entry(fcoe, &fcoe_hostlist, list) { 19116f6c2aa3Sjohn fastabend if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) 19126f6c2aa3Sjohn fastabend real_dev = vlan_dev_real_dev(fcoe->netdev); 19136f6c2aa3Sjohn fastabend else 19146f6c2aa3Sjohn fastabend real_dev = fcoe->netdev; 19156f6c2aa3Sjohn fastabend 19166f6c2aa3Sjohn fastabend if (netdev == real_dev) 19176f6c2aa3Sjohn fastabend return fcoe; 19186f6c2aa3Sjohn fastabend } 19196f6c2aa3Sjohn fastabend return NULL; 19206f6c2aa3Sjohn fastabend } 19216f6c2aa3Sjohn fastabend 19226f6c2aa3Sjohn fastabend static int fcoe_dcb_app_notification(struct notifier_block *notifier, 19236f6c2aa3Sjohn fastabend ulong event, void *ptr) 19246f6c2aa3Sjohn fastabend { 19256f6c2aa3Sjohn fastabend struct dcb_app_type *entry = ptr; 1926619fe4beSRobert Love struct fcoe_ctlr *ctlr; 19276f6c2aa3Sjohn fastabend struct fcoe_interface *fcoe; 19286f6c2aa3Sjohn fastabend struct net_device *netdev; 19296f6c2aa3Sjohn fastabend int prio; 19306f6c2aa3Sjohn fastabend 19316f6c2aa3Sjohn fastabend if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) 19326f6c2aa3Sjohn fastabend return NOTIFY_OK; 19336f6c2aa3Sjohn fastabend 19346f6c2aa3Sjohn fastabend netdev = dev_get_by_index(&init_net, entry->ifindex); 19356f6c2aa3Sjohn fastabend if (!netdev) 19366f6c2aa3Sjohn fastabend return NOTIFY_OK; 19376f6c2aa3Sjohn fastabend 19386f6c2aa3Sjohn fastabend fcoe = fcoe_hostlist_lookup_realdev_port(netdev); 19396f6c2aa3Sjohn fastabend dev_put(netdev); 19406f6c2aa3Sjohn fastabend if (!fcoe) 19416f6c2aa3Sjohn fastabend return NOTIFY_OK; 19426f6c2aa3Sjohn fastabend 1943619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1944619fe4beSRobert Love 19456f6c2aa3Sjohn fastabend if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) 19466f6c2aa3Sjohn fastabend prio = ffs(entry->app.priority) - 1; 19476f6c2aa3Sjohn fastabend else 19486f6c2aa3Sjohn fastabend prio = entry->app.priority; 19496f6c2aa3Sjohn fastabend 19506f6c2aa3Sjohn fastabend if (prio < 0) 19516f6c2aa3Sjohn fastabend return NOTIFY_OK; 19526f6c2aa3Sjohn fastabend 19536f6c2aa3Sjohn fastabend if (entry->app.protocol == ETH_P_FIP || 19546f6c2aa3Sjohn fastabend entry->app.protocol == ETH_P_FCOE) 1955619fe4beSRobert Love ctlr->priority = prio; 19566f6c2aa3Sjohn fastabend 195731c37a6fSNeerav Parikh if (entry->app.protocol == ETH_P_FCOE) 195831c37a6fSNeerav Parikh fcoe->priority = prio; 19596f6c2aa3Sjohn fastabend 19606f6c2aa3Sjohn fastabend return NOTIFY_OK; 19616f6c2aa3Sjohn fastabend } 19626f6c2aa3Sjohn fastabend 1963a703e490SVasu Dev /** 19641875f27eSRobert Love * fcoe_device_notification() - Handler for net device events 19651875f27eSRobert Love * @notifier: The context of the notification 19661875f27eSRobert Love * @event: The type of event 19671875f27eSRobert Love * @ptr: The net device that the event was on 1968a703e490SVasu Dev * 19691875f27eSRobert Love * This function is called by the Ethernet driver in case of link change event. 1970a703e490SVasu Dev * 1971a703e490SVasu Dev * Returns: 0 for success 1972a703e490SVasu Dev */ 1973a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *notifier, 1974a703e490SVasu Dev ulong event, void *ptr) 1975a703e490SVasu Dev { 1976435c8667SRobert Love struct fcoe_ctlr_device *cdev; 19771875f27eSRobert Love struct fc_lport *lport = NULL; 1978351638e7SJiri Pirko struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 1979619fe4beSRobert Love struct fcoe_ctlr *ctlr; 1980014f5c3fSChris Leech struct fcoe_interface *fcoe; 19812e70e241SChris Leech struct fcoe_port *port; 19821bd49b48SVasu Dev struct fc_stats *stats; 198397c8389dSJoe Eykholt u32 link_possible = 1; 1984a703e490SVasu Dev u32 mfs; 1985a703e490SVasu Dev int rc = NOTIFY_OK; 1986a703e490SVasu Dev 1987014f5c3fSChris Leech list_for_each_entry(fcoe, &fcoe_hostlist, list) { 198825024989SChris Leech if (fcoe->netdev == netdev) { 1989619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1990619fe4beSRobert Love lport = ctlr->lp; 1991a703e490SVasu Dev break; 1992a703e490SVasu Dev } 1993a703e490SVasu Dev } 19941875f27eSRobert Love if (!lport) { 1995a703e490SVasu Dev rc = NOTIFY_DONE; 1996a703e490SVasu Dev goto out; 1997a703e490SVasu Dev } 1998a703e490SVasu Dev 1999a703e490SVasu Dev switch (event) { 2000a703e490SVasu Dev case NETDEV_DOWN: 2001a703e490SVasu Dev case NETDEV_GOING_DOWN: 200297c8389dSJoe Eykholt link_possible = 0; 2003a703e490SVasu Dev break; 2004a703e490SVasu Dev case NETDEV_UP: 2005a703e490SVasu Dev case NETDEV_CHANGE: 2006a703e490SVasu Dev break; 2007a703e490SVasu Dev case NETDEV_CHANGEMTU: 20087221d7e5SYi Zou if (netdev->features & NETIF_F_FCOE_MTU) 20097221d7e5SYi Zou break; 20101d1b88dcSVasu Dev mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + 2011a703e490SVasu Dev sizeof(struct fcoe_crc_eof)); 2012a703e490SVasu Dev if (mfs >= FC_MIN_MAX_FRAME) 20131875f27eSRobert Love fc_set_mfs(lport, mfs); 2014a703e490SVasu Dev break; 2015a703e490SVasu Dev case NETDEV_REGISTER: 2016a703e490SVasu Dev break; 20172e70e241SChris Leech case NETDEV_UNREGISTER: 20182e70e241SChris Leech list_del(&fcoe->list); 2019619fe4beSRobert Love port = lport_priv(ctlr->lp); 20202ca32b48STejun Heo queue_work(fcoe_wq, &port->destroy_work); 20212e70e241SChris Leech goto out; 20222e70e241SChris Leech break; 202354a5b21dSYi Zou case NETDEV_FEAT_CHANGE: 202454a5b21dSYi Zou fcoe_netdev_features_change(lport, netdev); 202554a5b21dSYi Zou break; 2026a703e490SVasu Dev default: 20271d1b88dcSVasu Dev FCOE_NETDEV_DBG(netdev, "Unknown event %ld " 2028d5488eb9SRobert Love "from netdev netlink\n", event); 2029a703e490SVasu Dev } 20305e4f8fe7SRobert Love 20315e4f8fe7SRobert Love fcoe_link_speed_update(lport); 20325e4f8fe7SRobert Love 2033435c8667SRobert Love cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2034435c8667SRobert Love 2035435c8667SRobert Love if (link_possible && !fcoe_link_ok(lport)) { 2036435c8667SRobert Love switch (cdev->enabled) { 2037435c8667SRobert Love case FCOE_CTLR_DISABLED: 2038435c8667SRobert Love pr_info("Link up while interface is disabled.\n"); 2039435c8667SRobert Love break; 2040435c8667SRobert Love case FCOE_CTLR_ENABLED: 2041435c8667SRobert Love case FCOE_CTLR_UNUSED: 2042619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2043435c8667SRobert Love }; 2044435c8667SRobert Love } else if (fcoe_ctlr_link_down(ctlr)) { 2045435c8667SRobert Love switch (cdev->enabled) { 2046435c8667SRobert Love case FCOE_CTLR_DISABLED: 2047435c8667SRobert Love pr_info("Link down while interface is disabled.\n"); 2048435c8667SRobert Love break; 2049435c8667SRobert Love case FCOE_CTLR_ENABLED: 2050435c8667SRobert Love case FCOE_CTLR_UNUSED: 20511bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 2052a703e490SVasu Dev stats->LinkFailureCount++; 2053f018b73aSJoe Eykholt put_cpu(); 20541875f27eSRobert Love fcoe_clean_pending_queue(lport); 2055435c8667SRobert Love }; 2056a703e490SVasu Dev } 2057a703e490SVasu Dev out: 2058a703e490SVasu Dev return rc; 2059a703e490SVasu Dev } 2060a703e490SVasu Dev 2061a703e490SVasu Dev /** 206255a66d3cSVasu Dev * fcoe_disable() - Disables a FCoE interface 206378a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 206455a66d3cSVasu Dev * 206578a58246SYi Zou * Called from fcoe transport. 206655a66d3cSVasu Dev * 206755a66d3cSVasu Dev * Returns: 0 for success 2068435c8667SRobert Love * 2069435c8667SRobert Love * Deprecated: use fcoe_ctlr_enabled() 207055a66d3cSVasu Dev */ 207178a58246SYi Zou static int fcoe_disable(struct net_device *netdev) 207255a66d3cSVasu Dev { 2073619fe4beSRobert Love struct fcoe_ctlr *ctlr; 207455a66d3cSVasu Dev struct fcoe_interface *fcoe; 207555a66d3cSVasu Dev int rc = 0; 207655a66d3cSVasu Dev 207755a66d3cSVasu Dev mutex_lock(&fcoe_config_mutex); 207855a66d3cSVasu Dev 2079ee5df628SRobert Love rtnl_lock(); 208055a66d3cSVasu Dev fcoe = fcoe_hostlist_lookup_port(netdev); 208155a66d3cSVasu Dev rtnl_unlock(); 208255a66d3cSVasu Dev 20839ee50e48SChris Leech if (fcoe) { 2084619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2085619fe4beSRobert Love fcoe_ctlr_link_down(ctlr); 2086619fe4beSRobert Love fcoe_clean_pending_queue(ctlr->lp); 20879ee50e48SChris Leech } else 208855a66d3cSVasu Dev rc = -ENODEV; 208955a66d3cSVasu Dev 209055a66d3cSVasu Dev mutex_unlock(&fcoe_config_mutex); 209155a66d3cSVasu Dev return rc; 209255a66d3cSVasu Dev } 209355a66d3cSVasu Dev 209455a66d3cSVasu Dev /** 209555a66d3cSVasu Dev * fcoe_enable() - Enables a FCoE interface 209678a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 209755a66d3cSVasu Dev * 209878a58246SYi Zou * Called from fcoe transport. 209955a66d3cSVasu Dev * 210055a66d3cSVasu Dev * Returns: 0 for success 210155a66d3cSVasu Dev */ 210278a58246SYi Zou static int fcoe_enable(struct net_device *netdev) 210355a66d3cSVasu Dev { 2104619fe4beSRobert Love struct fcoe_ctlr *ctlr; 210555a66d3cSVasu Dev struct fcoe_interface *fcoe; 210655a66d3cSVasu Dev int rc = 0; 210755a66d3cSVasu Dev 210855a66d3cSVasu Dev mutex_lock(&fcoe_config_mutex); 2109ee5df628SRobert Love rtnl_lock(); 211055a66d3cSVasu Dev fcoe = fcoe_hostlist_lookup_port(netdev); 211155a66d3cSVasu Dev rtnl_unlock(); 211255a66d3cSVasu Dev 2113619fe4beSRobert Love if (!fcoe) { 211455a66d3cSVasu Dev rc = -ENODEV; 2115619fe4beSRobert Love goto out; 2116619fe4beSRobert Love } 211755a66d3cSVasu Dev 2118619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2119619fe4beSRobert Love 2120619fe4beSRobert Love if (!fcoe_link_ok(ctlr->lp)) 2121619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2122619fe4beSRobert Love 2123619fe4beSRobert Love out: 212455a66d3cSVasu Dev mutex_unlock(&fcoe_config_mutex); 212555a66d3cSVasu Dev return rc; 212655a66d3cSVasu Dev } 212755a66d3cSVasu Dev 212855a66d3cSVasu Dev /** 2129435c8667SRobert Love * fcoe_ctlr_enabled() - Enable or disable an FCoE Controller 2130435c8667SRobert Love * @cdev: The FCoE Controller that is being enabled or disabled 2131435c8667SRobert Love * 2132435c8667SRobert Love * fcoe_sysfs will ensure that the state of 'enabled' has 2133435c8667SRobert Love * changed, so no checking is necessary here. This routine simply 2134435c8667SRobert Love * calls fcoe_enable or fcoe_disable, both of which are deprecated. 2135435c8667SRobert Love * When those routines are removed the functionality can be merged 2136435c8667SRobert Love * here. 2137435c8667SRobert Love */ 2138435c8667SRobert Love static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev) 2139435c8667SRobert Love { 2140435c8667SRobert Love struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(cdev); 2141435c8667SRobert Love struct fc_lport *lport = ctlr->lp; 2142435c8667SRobert Love struct net_device *netdev = fcoe_netdev(lport); 2143435c8667SRobert Love 2144435c8667SRobert Love switch (cdev->enabled) { 2145435c8667SRobert Love case FCOE_CTLR_ENABLED: 2146435c8667SRobert Love return fcoe_enable(netdev); 2147435c8667SRobert Love case FCOE_CTLR_DISABLED: 2148435c8667SRobert Love return fcoe_disable(netdev); 2149435c8667SRobert Love case FCOE_CTLR_UNUSED: 2150435c8667SRobert Love default: 2151435c8667SRobert Love return -ENOTSUPP; 2152435c8667SRobert Love }; 2153435c8667SRobert Love } 2154435c8667SRobert Love 2155435c8667SRobert Love /** 21561875f27eSRobert Love * fcoe_destroy() - Destroy a FCoE interface 215778a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 21581875f27eSRobert Love * 215978a58246SYi Zou * Called from fcoe transport 2160a703e490SVasu Dev * 2161a703e490SVasu Dev * Returns: 0 for success 2162a703e490SVasu Dev */ 216378a58246SYi Zou static int fcoe_destroy(struct net_device *netdev) 2164a703e490SVasu Dev { 2165619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2166030f4e00SChris Leech struct fcoe_interface *fcoe; 2167f04ca1b6SVasu Dev struct fc_lport *lport; 2168b2085a4eSNeerav Parikh struct fcoe_port *port; 21698eca355fSMike Christie int rc = 0; 2170a703e490SVasu Dev 2171dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2172ee5df628SRobert Love rtnl_lock(); 21732e70e241SChris Leech fcoe = fcoe_hostlist_lookup_port(netdev); 21742e70e241SChris Leech if (!fcoe) { 2175a703e490SVasu Dev rc = -ENODEV; 217678a58246SYi Zou goto out_nodev; 2177a703e490SVasu Dev } 2178619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2179619fe4beSRobert Love lport = ctlr->lp; 2180b2085a4eSNeerav Parikh port = lport_priv(lport); 218154a5b21dSYi Zou list_del(&fcoe->list); 2182b2085a4eSNeerav Parikh queue_work(fcoe_wq, &port->destroy_work); 2183a703e490SVasu Dev out_nodev: 2184b2085a4eSNeerav Parikh rtnl_unlock(); 2185dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2186a703e490SVasu Dev return rc; 2187a703e490SVasu Dev } 2188a703e490SVasu Dev 21891875f27eSRobert Love /** 21901875f27eSRobert Love * fcoe_destroy_work() - Destroy a FCoE port in a deferred work context 21911875f27eSRobert Love * @work: Handle to the FCoE port to be destroyed 21921875f27eSRobert Love */ 21932e70e241SChris Leech static void fcoe_destroy_work(struct work_struct *work) 21942e70e241SChris Leech { 2195f9c4358eSRobert Love struct fcoe_ctlr_device *cdev; 2196f9c4358eSRobert Love struct fcoe_ctlr *ctlr; 21972e70e241SChris Leech struct fcoe_port *port; 2198b2085a4eSNeerav Parikh struct fcoe_interface *fcoe; 219994aa743aSNeerav Parikh struct Scsi_Host *shost; 220094aa743aSNeerav Parikh struct fc_host_attrs *fc_host; 220194aa743aSNeerav Parikh unsigned long flags; 220294aa743aSNeerav Parikh struct fc_vport *vport; 220394aa743aSNeerav Parikh struct fc_vport *next_vport; 22042e70e241SChris Leech 22052e70e241SChris Leech port = container_of(work, struct fcoe_port, destroy_work); 220694aa743aSNeerav Parikh shost = port->lport->host; 220794aa743aSNeerav Parikh fc_host = shost_to_fc_host(shost); 220894aa743aSNeerav Parikh 220994aa743aSNeerav Parikh /* Loop through all the vports and mark them for deletion */ 221094aa743aSNeerav Parikh spin_lock_irqsave(shost->host_lock, flags); 221194aa743aSNeerav Parikh list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) { 221294aa743aSNeerav Parikh if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) { 221394aa743aSNeerav Parikh continue; 221494aa743aSNeerav Parikh } else { 221594aa743aSNeerav Parikh vport->flags |= FC_VPORT_DELETING; 221694aa743aSNeerav Parikh queue_work(fc_host_work_q(shost), 221794aa743aSNeerav Parikh &vport->vport_delete_work); 221894aa743aSNeerav Parikh } 221994aa743aSNeerav Parikh } 222094aa743aSNeerav Parikh spin_unlock_irqrestore(shost->host_lock, flags); 222194aa743aSNeerav Parikh 222294aa743aSNeerav Parikh flush_workqueue(fc_host_work_q(shost)); 222394aa743aSNeerav Parikh 22242e70e241SChris Leech mutex_lock(&fcoe_config_mutex); 2225b2085a4eSNeerav Parikh 2226b2085a4eSNeerav Parikh fcoe = port->priv; 2227f9c4358eSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2228f9c4358eSRobert Love cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2229f9c4358eSRobert Love 22302e70e241SChris Leech fcoe_if_destroy(port->lport); 2231b2085a4eSNeerav Parikh fcoe_interface_cleanup(fcoe); 2232b2085a4eSNeerav Parikh 22332e70e241SChris Leech mutex_unlock(&fcoe_config_mutex); 2234f9c4358eSRobert Love 2235f9c4358eSRobert Love fcoe_ctlr_device_delete(cdev); 22362e70e241SChris Leech } 22372e70e241SChris Leech 2238a703e490SVasu Dev /** 223978a58246SYi Zou * fcoe_match() - Check if the FCoE is supported on the given netdevice 224078a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 22411875f27eSRobert Love * 224278a58246SYi Zou * Called from fcoe transport. 224378a58246SYi Zou * 224478a58246SYi Zou * Returns: always returns true as this is the default FCoE transport, 224578a58246SYi Zou * i.e., support all netdevs. 224678a58246SYi Zou */ 224778a58246SYi Zou static bool fcoe_match(struct net_device *netdev) 224878a58246SYi Zou { 224978a58246SYi Zou return true; 225078a58246SYi Zou } 225178a58246SYi Zou 225278a58246SYi Zou /** 22536f6c2aa3Sjohn fastabend * fcoe_dcb_create() - Initialize DCB attributes and hooks 22546f6c2aa3Sjohn fastabend * @netdev: The net_device object of the L2 link that should be queried 22556f6c2aa3Sjohn fastabend * @port: The fcoe_port to bind FCoE APP priority with 22566f6c2aa3Sjohn fastabend * @ 22576f6c2aa3Sjohn fastabend */ 22586f6c2aa3Sjohn fastabend static void fcoe_dcb_create(struct fcoe_interface *fcoe) 22596f6c2aa3Sjohn fastabend { 22606f6c2aa3Sjohn fastabend #ifdef CONFIG_DCB 22616f6c2aa3Sjohn fastabend int dcbx; 22626f6c2aa3Sjohn fastabend u8 fup, up; 22636f6c2aa3Sjohn fastabend struct net_device *netdev = fcoe->realdev; 2264619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 22656f6c2aa3Sjohn fastabend struct dcb_app app = { 22666f6c2aa3Sjohn fastabend .priority = 0, 22676f6c2aa3Sjohn fastabend .protocol = ETH_P_FCOE 22686f6c2aa3Sjohn fastabend }; 22696f6c2aa3Sjohn fastabend 22706f6c2aa3Sjohn fastabend /* setup DCB priority attributes. */ 22716f6c2aa3Sjohn fastabend if (netdev && netdev->dcbnl_ops && netdev->dcbnl_ops->getdcbx) { 22726f6c2aa3Sjohn fastabend dcbx = netdev->dcbnl_ops->getdcbx(netdev); 22736f6c2aa3Sjohn fastabend 22746f6c2aa3Sjohn fastabend if (dcbx & DCB_CAP_DCBX_VER_IEEE) { 22756f6c2aa3Sjohn fastabend app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; 22766f6c2aa3Sjohn fastabend up = dcb_ieee_getapp_mask(netdev, &app); 22776f6c2aa3Sjohn fastabend app.protocol = ETH_P_FIP; 22786f6c2aa3Sjohn fastabend fup = dcb_ieee_getapp_mask(netdev, &app); 22796f6c2aa3Sjohn fastabend } else { 22806f6c2aa3Sjohn fastabend app.selector = DCB_APP_IDTYPE_ETHTYPE; 22816f6c2aa3Sjohn fastabend up = dcb_getapp(netdev, &app); 22826f6c2aa3Sjohn fastabend app.protocol = ETH_P_FIP; 22836f6c2aa3Sjohn fastabend fup = dcb_getapp(netdev, &app); 22846f6c2aa3Sjohn fastabend } 22856f6c2aa3Sjohn fastabend 228631c37a6fSNeerav Parikh fcoe->priority = ffs(up) ? ffs(up) - 1 : 0; 228731c37a6fSNeerav Parikh ctlr->priority = ffs(fup) ? ffs(fup) - 1 : fcoe->priority; 22886f6c2aa3Sjohn fastabend } 22896f6c2aa3Sjohn fastabend #endif 22906f6c2aa3Sjohn fastabend } 22916f6c2aa3Sjohn fastabend 2292435c8667SRobert Love enum fcoe_create_link_state { 2293435c8667SRobert Love FCOE_CREATE_LINK_DOWN, 2294435c8667SRobert Love FCOE_CREATE_LINK_UP, 2295435c8667SRobert Love }; 2296435c8667SRobert Love 22976f6c2aa3Sjohn fastabend /** 2298435c8667SRobert Love * _fcoe_create() - (internal) Create a fcoe interface 229978a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 230078a58246SYi Zou * @fip_mode: The FIP mode for this creation 2301435c8667SRobert Love * @link_state: The ctlr link state on creation 230278a58246SYi Zou * 2303435c8667SRobert Love * Called from either the libfcoe 'create' module parameter 2304435c8667SRobert Love * via fcoe_create or from fcoe_syfs's ctlr_create file. 2305a703e490SVasu Dev * 2306435c8667SRobert Love * libfcoe's 'create' module parameter is deprecated so some 2307435c8667SRobert Love * consolidation of code can be done when that interface is 2308435c8667SRobert Love * removed. 2309a703e490SVasu Dev */ 2310435c8667SRobert Love static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode, 2311435c8667SRobert Love enum fcoe_create_link_state link_state) 2312a703e490SVasu Dev { 2313b2085a4eSNeerav Parikh int rc = 0; 23148d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev; 2315619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2316030f4e00SChris Leech struct fcoe_interface *fcoe; 2317af7f85d9SChris Leech struct fc_lport *lport; 2318a703e490SVasu Dev 2319dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2320ee5df628SRobert Love rtnl_lock(); 232134ce27bcSVasu Dev 2322a703e490SVasu Dev /* look for existing lport */ 2323a703e490SVasu Dev if (fcoe_hostlist_lookup(netdev)) { 2324a703e490SVasu Dev rc = -EEXIST; 232578a58246SYi Zou goto out_nodev; 2326a703e490SVasu Dev } 2327a703e490SVasu Dev 23281dd454d9SJoe Eykholt fcoe = fcoe_interface_create(netdev, fip_mode); 23297287fb91SRobert Love if (IS_ERR(fcoe)) { 23307287fb91SRobert Love rc = PTR_ERR(fcoe); 233178a58246SYi Zou goto out_nodev; 2332030f4e00SChris Leech } 2333030f4e00SChris Leech 2334619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 23358d55e507SRobert Love ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); 23368d55e507SRobert Love lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0); 2337af7f85d9SChris Leech if (IS_ERR(lport)) { 2338d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", 2339a703e490SVasu Dev netdev->name); 2340a703e490SVasu Dev rc = -EIO; 2341848e7d5bSRobert Love rtnl_unlock(); 23422e70e241SChris Leech fcoe_interface_cleanup(fcoe); 2343f9c4358eSRobert Love mutex_unlock(&fcoe_config_mutex); 2344f9c4358eSRobert Love fcoe_ctlr_device_delete(ctlr_dev); 2345f9c4358eSRobert Love goto out; 2346a703e490SVasu Dev } 2347030f4e00SChris Leech 234854b649f8SChris Leech /* Make this the "master" N_Port */ 2349619fe4beSRobert Love ctlr->lp = lport; 2350030f4e00SChris Leech 23516f6c2aa3Sjohn fastabend /* setup DCB priority attributes. */ 23526f6c2aa3Sjohn fastabend fcoe_dcb_create(fcoe); 23536f6c2aa3Sjohn fastabend 235454b649f8SChris Leech /* start FIP Discovery and FLOGI */ 235554b649f8SChris Leech lport->boot_time = jiffies; 235654b649f8SChris Leech fc_fabric_login(lport); 2357435c8667SRobert Love 2358435c8667SRobert Love /* 2359435c8667SRobert Love * If the fcoe_ctlr_device is to be set to DISABLED 2360435c8667SRobert Love * it must be done after the lport is added to the 2361435c8667SRobert Love * hostlist, but before the rtnl_lock is released. 2362435c8667SRobert Love * This is because the rtnl_lock protects the 2363435c8667SRobert Love * hostlist that fcoe_device_notification uses. If 2364435c8667SRobert Love * the FCoE Controller is intended to be created 2365435c8667SRobert Love * DISABLED then 'enabled' needs to be considered 2366435c8667SRobert Love * handling link events. 'enabled' must be set 2367435c8667SRobert Love * before the lport can be found in the hostlist 2368435c8667SRobert Love * when a link up event is received. 2369435c8667SRobert Love */ 2370435c8667SRobert Love if (link_state == FCOE_CREATE_LINK_UP) 2371435c8667SRobert Love ctlr_dev->enabled = FCOE_CTLR_ENABLED; 2372435c8667SRobert Love else 2373435c8667SRobert Love ctlr_dev->enabled = FCOE_CTLR_DISABLED; 2374435c8667SRobert Love 2375435c8667SRobert Love if (link_state == FCOE_CREATE_LINK_UP && 2376435c8667SRobert Love !fcoe_link_ok(lport)) { 237722805123SRobert Love rtnl_unlock(); 2378619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 237922805123SRobert Love mutex_unlock(&fcoe_config_mutex); 238022805123SRobert Love return rc; 238122805123SRobert Love } 238254b649f8SChris Leech 2383a703e490SVasu Dev out_nodev: 238434ce27bcSVasu Dev rtnl_unlock(); 2385dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2386f9c4358eSRobert Love out: 2387a703e490SVasu Dev return rc; 2388a703e490SVasu Dev } 2389a703e490SVasu Dev 2390a703e490SVasu Dev /** 2391435c8667SRobert Love * fcoe_create() - Create a fcoe interface 2392435c8667SRobert Love * @netdev : The net_device object the Ethernet interface to create on 2393435c8667SRobert Love * @fip_mode: The FIP mode for this creation 2394435c8667SRobert Love * 2395435c8667SRobert Love * Called from fcoe transport 2396435c8667SRobert Love * 2397435c8667SRobert Love * Returns: 0 for success 2398435c8667SRobert Love */ 2399435c8667SRobert Love static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) 2400435c8667SRobert Love { 2401435c8667SRobert Love return _fcoe_create(netdev, fip_mode, FCOE_CREATE_LINK_UP); 2402435c8667SRobert Love } 2403435c8667SRobert Love 2404435c8667SRobert Love /** 2405435c8667SRobert Love * fcoe_ctlr_alloc() - Allocate a fcoe interface from fcoe_sysfs 2406435c8667SRobert Love * @netdev: The net_device to be used by the allocated FCoE Controller 2407435c8667SRobert Love * 2408435c8667SRobert Love * This routine is called from fcoe_sysfs. It will start the fcoe_ctlr 2409435c8667SRobert Love * in a link_down state. The allows the user an opportunity to configure 2410435c8667SRobert Love * the FCoE Controller from sysfs before enabling the FCoE Controller. 2411435c8667SRobert Love * 2412435c8667SRobert Love * Creating in with this routine starts the FCoE Controller in Fabric 2413435c8667SRobert Love * mode. The user can change to VN2VN or another mode before enabling. 2414435c8667SRobert Love */ 2415435c8667SRobert Love static int fcoe_ctlr_alloc(struct net_device *netdev) 2416435c8667SRobert Love { 2417435c8667SRobert Love return _fcoe_create(netdev, FIP_MODE_FABRIC, 2418435c8667SRobert Love FCOE_CREATE_LINK_DOWN); 2419435c8667SRobert Love } 2420435c8667SRobert Love 2421435c8667SRobert Love /** 24225e4f8fe7SRobert Love * fcoe_link_ok() - Check if the link is OK for a local port 24235e4f8fe7SRobert Love * @lport: The local port to check link on 24245e4f8fe7SRobert Love * 24255e4f8fe7SRobert Love * Returns: 0 if link is UP and OK, -1 if not 24265e4f8fe7SRobert Love * 24275e4f8fe7SRobert Love */ 24287c9c6841SBart Van Assche static int fcoe_link_ok(struct fc_lport *lport) 24295e4f8fe7SRobert Love { 24308597ae8bSBhanu Prakash Gollapudi struct net_device *netdev = fcoe_netdev(lport); 24315e4f8fe7SRobert Love 24325e4f8fe7SRobert Love if (netif_oper_up(netdev)) 24335e4f8fe7SRobert Love return 0; 24345e4f8fe7SRobert Love return -1; 24355e4f8fe7SRobert Love } 24365e4f8fe7SRobert Love 24375e4f8fe7SRobert Love /** 24381875f27eSRobert Love * fcoe_percpu_clean() - Clear all pending skbs for an local port 24391875f27eSRobert Love * @lport: The local port whose skbs are to be cleared 2440e7a51997SJoe Eykholt * 2441e7a51997SJoe Eykholt * Must be called with fcoe_create_mutex held to single-thread completion. 2442e7a51997SJoe Eykholt * 2443e7a51997SJoe Eykholt * This flushes the pending skbs by adding a new skb to each queue and 2444e7a51997SJoe Eykholt * waiting until they are all freed. This assures us that not only are 2445e7a51997SJoe Eykholt * there no packets that will be handled by the lport, but also that any 2446e7a51997SJoe Eykholt * threads already handling packet have returned. 2447a703e490SVasu Dev */ 24487c9c6841SBart Van Assche static void fcoe_percpu_clean(struct fc_lport *lport) 2449a703e490SVasu Dev { 2450a703e490SVasu Dev struct fcoe_percpu_s *pp; 2451dd060e74SNeil Horman struct sk_buff *skb; 2452a703e490SVasu Dev unsigned int cpu; 2453a703e490SVasu Dev 2454a703e490SVasu Dev for_each_possible_cpu(cpu) { 2455a703e490SVasu Dev pp = &per_cpu(fcoe_percpu, cpu); 2456e7a51997SJoe Eykholt 2457dd060e74SNeil Horman if (!pp->thread || !cpu_online(cpu)) 2458e7a51997SJoe Eykholt continue; 2459e7a51997SJoe Eykholt 2460e7a51997SJoe Eykholt skb = dev_alloc_skb(0); 2461b3b8abd8SDan Carpenter if (!skb) 2462e7a51997SJoe Eykholt continue; 2463b3b8abd8SDan Carpenter 2464e7a51997SJoe Eykholt skb->destructor = fcoe_percpu_flush_done; 2465e7a51997SJoe Eykholt 2466dd060e74SNeil Horman spin_lock_bh(&pp->fcoe_rx_list.lock); 2467e7a51997SJoe Eykholt __skb_queue_tail(&pp->fcoe_rx_list, skb); 2468e7a51997SJoe Eykholt if (pp->fcoe_rx_list.qlen == 1) 2469e7a51997SJoe Eykholt wake_up_process(pp->thread); 2470e7a51997SJoe Eykholt spin_unlock_bh(&pp->fcoe_rx_list.lock); 2471e7a51997SJoe Eykholt 2472e7a51997SJoe Eykholt wait_for_completion(&fcoe_flush_completion); 2473a703e490SVasu Dev } 2474a703e490SVasu Dev } 2475a703e490SVasu Dev 2476a703e490SVasu Dev /** 24771875f27eSRobert Love * fcoe_reset() - Reset a local port 24781875f27eSRobert Love * @shost: The SCSI host associated with the local port to be reset 2479a703e490SVasu Dev * 24801875f27eSRobert Love * Returns: Always 0 (return value required by FC transport template) 2481a703e490SVasu Dev */ 24827c9c6841SBart Van Assche static int fcoe_reset(struct Scsi_Host *shost) 2483a703e490SVasu Dev { 2484a703e490SVasu Dev struct fc_lport *lport = shost_priv(shost); 2485d2f80952SVasu Dev struct fcoe_port *port = lport_priv(lport); 2486d2f80952SVasu Dev struct fcoe_interface *fcoe = port->priv; 2487619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 2488435c8667SRobert Love struct fcoe_ctlr_device *cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2489d2f80952SVasu Dev 2490619fe4beSRobert Love fcoe_ctlr_link_down(ctlr); 2491619fe4beSRobert Love fcoe_clean_pending_queue(ctlr->lp); 2492435c8667SRobert Love 2493435c8667SRobert Love if (cdev->enabled != FCOE_CTLR_DISABLED && 2494435c8667SRobert Love !fcoe_link_ok(ctlr->lp)) 2495619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2496a703e490SVasu Dev return 0; 2497a703e490SVasu Dev } 2498a703e490SVasu Dev 2499a703e490SVasu Dev /** 25001875f27eSRobert Love * fcoe_hostlist_lookup_port() - Find the FCoE interface associated with a net device 25011875f27eSRobert Love * @netdev: The net device used as a key 2502a703e490SVasu Dev * 25031875f27eSRobert Love * Locking: Must be called with the RNL mutex held. 25041875f27eSRobert Love * 25051875f27eSRobert Love * Returns: NULL or the FCoE interface 2506a703e490SVasu Dev */ 2507014f5c3fSChris Leech static struct fcoe_interface * 25081875f27eSRobert Love fcoe_hostlist_lookup_port(const struct net_device *netdev) 2509a703e490SVasu Dev { 2510014f5c3fSChris Leech struct fcoe_interface *fcoe; 2511a703e490SVasu Dev 2512014f5c3fSChris Leech list_for_each_entry(fcoe, &fcoe_hostlist, list) { 25131875f27eSRobert Love if (fcoe->netdev == netdev) 2514014f5c3fSChris Leech return fcoe; 2515a703e490SVasu Dev } 2516a703e490SVasu Dev return NULL; 2517a703e490SVasu Dev } 2518a703e490SVasu Dev 2519a703e490SVasu Dev /** 25201875f27eSRobert Love * fcoe_hostlist_lookup() - Find the local port associated with a 25211875f27eSRobert Love * given net device 25221875f27eSRobert Love * @netdev: The netdevice used as a key 2523a703e490SVasu Dev * 25241875f27eSRobert Love * Locking: Must be called with the RTNL mutex held 25251875f27eSRobert Love * 25261875f27eSRobert Love * Returns: NULL or the local port 2527a703e490SVasu Dev */ 2528090eb6c4SChris Leech static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) 2529a703e490SVasu Dev { 2530619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2531014f5c3fSChris Leech struct fcoe_interface *fcoe; 2532a703e490SVasu Dev 2533014f5c3fSChris Leech fcoe = fcoe_hostlist_lookup_port(netdev); 2534619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2535619fe4beSRobert Love return (fcoe) ? ctlr->lp : NULL; 2536a703e490SVasu Dev } 2537a703e490SVasu Dev 2538a703e490SVasu Dev /** 25391875f27eSRobert Love * fcoe_hostlist_add() - Add the FCoE interface identified by a local 25401875f27eSRobert Love * port to the hostlist 25411875f27eSRobert Love * @lport: The local port that identifies the FCoE interface to be added 25421875f27eSRobert Love * 25431875f27eSRobert Love * Locking: must be called with the RTNL mutex held 2544a703e490SVasu Dev * 2545a703e490SVasu Dev * Returns: 0 for success 2546a703e490SVasu Dev */ 2547090eb6c4SChris Leech static int fcoe_hostlist_add(const struct fc_lport *lport) 2548a703e490SVasu Dev { 2549014f5c3fSChris Leech struct fcoe_interface *fcoe; 2550014f5c3fSChris Leech struct fcoe_port *port; 2551a703e490SVasu Dev 2552014f5c3fSChris Leech fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); 2553014f5c3fSChris Leech if (!fcoe) { 2554014f5c3fSChris Leech port = lport_priv(lport); 25558597ae8bSBhanu Prakash Gollapudi fcoe = port->priv; 2556014f5c3fSChris Leech list_add_tail(&fcoe->list, &fcoe_hostlist); 2557a703e490SVasu Dev } 2558a703e490SVasu Dev return 0; 2559a703e490SVasu Dev } 2560a703e490SVasu Dev 2561f9184df3SNeil Horman /** 2562f9184df3SNeil Horman * fcoe_hostlist_del() - Remove the FCoE interface identified by a local 2563f9184df3SNeil Horman * port to the hostlist 2564f9184df3SNeil Horman * @lport: The local port that identifies the FCoE interface to be added 2565f9184df3SNeil Horman * 2566f9184df3SNeil Horman * Locking: must be called with the RTNL mutex held 2567f9184df3SNeil Horman * 2568f9184df3SNeil Horman */ 2569f9184df3SNeil Horman static void fcoe_hostlist_del(const struct fc_lport *lport) 2570f9184df3SNeil Horman { 2571f9184df3SNeil Horman struct fcoe_interface *fcoe; 2572f9184df3SNeil Horman struct fcoe_port *port; 2573f9184df3SNeil Horman 2574f9184df3SNeil Horman port = lport_priv(lport); 2575f9184df3SNeil Horman fcoe = port->priv; 2576f9184df3SNeil Horman list_del(&fcoe->list); 2577f9184df3SNeil Horman return; 2578f9184df3SNeil Horman } 257978a58246SYi Zou 258078a58246SYi Zou static struct fcoe_transport fcoe_sw_transport = { 258178a58246SYi Zou .name = {FCOE_TRANSPORT_DEFAULT}, 258278a58246SYi Zou .attached = false, 258378a58246SYi Zou .list = LIST_HEAD_INIT(fcoe_sw_transport.list), 258478a58246SYi Zou .match = fcoe_match, 2585435c8667SRobert Love .alloc = fcoe_ctlr_alloc, 258678a58246SYi Zou .create = fcoe_create, 258778a58246SYi Zou .destroy = fcoe_destroy, 258878a58246SYi Zou .enable = fcoe_enable, 258978a58246SYi Zou .disable = fcoe_disable, 259078a58246SYi Zou }; 259178a58246SYi Zou 2592a703e490SVasu Dev /** 25931875f27eSRobert Love * fcoe_init() - Initialize fcoe.ko 2594a703e490SVasu Dev * 25951875f27eSRobert Love * Returns: 0 on success, or a negative value on failure 2596a703e490SVasu Dev */ 2597a703e490SVasu Dev static int __init fcoe_init(void) 2598a703e490SVasu Dev { 25991875f27eSRobert Love struct fcoe_percpu_s *p; 2600a703e490SVasu Dev unsigned int cpu; 2601a703e490SVasu Dev int rc = 0; 2602a703e490SVasu Dev 26032ca32b48STejun Heo fcoe_wq = alloc_workqueue("fcoe", 0, 0); 26042ca32b48STejun Heo if (!fcoe_wq) 26052ca32b48STejun Heo return -ENOMEM; 26062ca32b48STejun Heo 260778a58246SYi Zou /* register as a fcoe transport */ 260878a58246SYi Zou rc = fcoe_transport_attach(&fcoe_sw_transport); 260978a58246SYi Zou if (rc) { 261078a58246SYi Zou printk(KERN_ERR "failed to register an fcoe transport, check " 261178a58246SYi Zou "if libfcoe is loaded\n"); 261278a58246SYi Zou return rc; 261378a58246SYi Zou } 261478a58246SYi Zou 2615dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2616dfc1d0feSChris Leech 2617a703e490SVasu Dev for_each_possible_cpu(cpu) { 2618a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 2619a703e490SVasu Dev skb_queue_head_init(&p->fcoe_rx_list); 2620a703e490SVasu Dev } 2621a703e490SVasu Dev 2622a703e490SVasu Dev for_each_online_cpu(cpu) 2623a703e490SVasu Dev fcoe_percpu_thread_create(cpu); 2624a703e490SVasu Dev 2625a703e490SVasu Dev /* Initialize per CPU interrupt thread */ 2626a703e490SVasu Dev rc = register_hotcpu_notifier(&fcoe_cpu_notifier); 2627a703e490SVasu Dev if (rc) 2628a703e490SVasu Dev goto out_free; 2629a703e490SVasu Dev 2630a703e490SVasu Dev /* Setup link change notification */ 2631a703e490SVasu Dev fcoe_dev_setup(); 2632a703e490SVasu Dev 26335892c32fSChris Leech rc = fcoe_if_init(); 26345892c32fSChris Leech if (rc) 26355892c32fSChris Leech goto out_free; 2636a703e490SVasu Dev 2637dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2638a703e490SVasu Dev return 0; 2639a703e490SVasu Dev 2640a703e490SVasu Dev out_free: 2641a703e490SVasu Dev for_each_online_cpu(cpu) { 2642a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 2643a703e490SVasu Dev } 2644dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 26452ca32b48STejun Heo destroy_workqueue(fcoe_wq); 2646a703e490SVasu Dev return rc; 2647a703e490SVasu Dev } 2648a703e490SVasu Dev module_init(fcoe_init); 2649a703e490SVasu Dev 2650a703e490SVasu Dev /** 26511875f27eSRobert Love * fcoe_exit() - Clean up fcoe.ko 2652a703e490SVasu Dev * 26531875f27eSRobert Love * Returns: 0 on success or a negative value on failure 2654a703e490SVasu Dev */ 2655a703e490SVasu Dev static void __exit fcoe_exit(void) 2656a703e490SVasu Dev { 2657014f5c3fSChris Leech struct fcoe_interface *fcoe, *tmp; 2658619fe4beSRobert Love struct fcoe_ctlr *ctlr; 26592e70e241SChris Leech struct fcoe_port *port; 26601875f27eSRobert Love unsigned int cpu; 2661a703e490SVasu Dev 2662dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2663dfc1d0feSChris Leech 2664a703e490SVasu Dev fcoe_dev_cleanup(); 2665a703e490SVasu Dev 2666a703e490SVasu Dev /* releases the associated fcoe hosts */ 2667090eb6c4SChris Leech rtnl_lock(); 2668090eb6c4SChris Leech list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { 2669619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2670619fe4beSRobert Love port = lport_priv(ctlr->lp); 2671f9184df3SNeil Horman fcoe_hostlist_del(port->lport); 26722ca32b48STejun Heo queue_work(fcoe_wq, &port->destroy_work); 2673c863df33SChris Leech } 2674090eb6c4SChris Leech rtnl_unlock(); 2675a703e490SVasu Dev 2676a703e490SVasu Dev unregister_hotcpu_notifier(&fcoe_cpu_notifier); 2677a703e490SVasu Dev 2678014f5c3fSChris Leech for_each_online_cpu(cpu) 2679a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 2680a703e490SVasu Dev 2681dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 26822e70e241SChris Leech 26832ca32b48STejun Heo /* 26842ca32b48STejun Heo * destroy_work's may be chained but destroy_workqueue() 26852ca32b48STejun Heo * can take care of them. Just kill the fcoe_wq. 26862ca32b48STejun Heo */ 26872ca32b48STejun Heo destroy_workqueue(fcoe_wq); 26882e70e241SChris Leech 26892ca32b48STejun Heo /* 26902ca32b48STejun Heo * Detaching from the scsi transport must happen after all 26912ca32b48STejun Heo * destroys are done on the fcoe_wq. destroy_workqueue will 26922ca32b48STejun Heo * enusre the fcoe_wq is flushed. 26932ca32b48STejun Heo */ 26942e70e241SChris Leech fcoe_if_exit(); 269578a58246SYi Zou 269678a58246SYi Zou /* detach from fcoe transport */ 269778a58246SYi Zou fcoe_transport_detach(&fcoe_sw_transport); 2698a703e490SVasu Dev } 2699a703e490SVasu Dev module_exit(fcoe_exit); 270011b56188SChris Leech 270111b56188SChris Leech /** 270211b56188SChris Leech * fcoe_flogi_resp() - FCoE specific FLOGI and FDISC response handler 270311b56188SChris Leech * @seq: active sequence in the FLOGI or FDISC exchange 270411b56188SChris Leech * @fp: response frame, or error encoded in a pointer (timeout) 270511b56188SChris Leech * @arg: pointer the the fcoe_ctlr structure 270611b56188SChris Leech * 270765155b37SUwe Kleine-König * This handles MAC address management for FCoE, then passes control on to 270811b56188SChris Leech * the libfc FLOGI response handler. 270911b56188SChris Leech */ 271011b56188SChris Leech static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) 271111b56188SChris Leech { 271211b56188SChris Leech struct fcoe_ctlr *fip = arg; 271311b56188SChris Leech struct fc_exch *exch = fc_seq_exch(seq); 271411b56188SChris Leech struct fc_lport *lport = exch->lp; 271511b56188SChris Leech u8 *mac; 271611b56188SChris Leech 271711b56188SChris Leech if (IS_ERR(fp)) 271811b56188SChris Leech goto done; 271911b56188SChris Leech 272011b56188SChris Leech mac = fr_cb(fp)->granted_mac; 272111b56188SChris Leech /* pre-FIP */ 2722907c07d4SVasu Dev if (is_zero_ether_addr(mac)) 2723907c07d4SVasu Dev fcoe_ctlr_recv_flogi(fip, lport, fp); 2724907c07d4SVasu Dev if (!is_zero_ether_addr(mac)) 2725386309ceSJoe Eykholt fcoe_update_src_mac(lport, mac); 272611b56188SChris Leech done: 272711b56188SChris Leech fc_lport_flogi_resp(seq, fp, lport); 272811b56188SChris Leech } 272911b56188SChris Leech 273011b56188SChris Leech /** 273111b56188SChris Leech * fcoe_logo_resp() - FCoE specific LOGO response handler 273211b56188SChris Leech * @seq: active sequence in the LOGO exchange 273311b56188SChris Leech * @fp: response frame, or error encoded in a pointer (timeout) 273411b56188SChris Leech * @arg: pointer the the fcoe_ctlr structure 273511b56188SChris Leech * 273665155b37SUwe Kleine-König * This handles MAC address management for FCoE, then passes control on to 273711b56188SChris Leech * the libfc LOGO response handler. 273811b56188SChris Leech */ 273911b56188SChris Leech static void fcoe_logo_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) 274011b56188SChris Leech { 2741386309ceSJoe Eykholt struct fc_lport *lport = arg; 274211b56188SChris Leech static u8 zero_mac[ETH_ALEN] = { 0 }; 274311b56188SChris Leech 274411b56188SChris Leech if (!IS_ERR(fp)) 2745386309ceSJoe Eykholt fcoe_update_src_mac(lport, zero_mac); 274611b56188SChris Leech fc_lport_logo_resp(seq, fp, lport); 274711b56188SChris Leech } 274811b56188SChris Leech 274911b56188SChris Leech /** 275011b56188SChris Leech * fcoe_elsct_send - FCoE specific ELS handler 275111b56188SChris Leech * 275211b56188SChris Leech * This does special case handling of FIP encapsualted ELS exchanges for FCoE, 275311b56188SChris Leech * using FCoE specific response handlers and passing the FIP controller as 275411b56188SChris Leech * the argument (the lport is still available from the exchange). 275511b56188SChris Leech * 275611b56188SChris Leech * Most of the work here is just handed off to the libfc routine. 275711b56188SChris Leech */ 27581875f27eSRobert Love static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did, 27591875f27eSRobert Love struct fc_frame *fp, unsigned int op, 27601875f27eSRobert Love void (*resp)(struct fc_seq *, 27611875f27eSRobert Love struct fc_frame *, 27621875f27eSRobert Love void *), 276311b56188SChris Leech void *arg, u32 timeout) 276411b56188SChris Leech { 276511b56188SChris Leech struct fcoe_port *port = lport_priv(lport); 27668597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 2767619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 276811b56188SChris Leech struct fc_frame_header *fh = fc_frame_header_get(fp); 276911b56188SChris Leech 277011b56188SChris Leech switch (op) { 277111b56188SChris Leech case ELS_FLOGI: 277211b56188SChris Leech case ELS_FDISC: 2773e10f8c66SJoe Eykholt if (lport->point_to_multipoint) 2774e10f8c66SJoe Eykholt break; 277511b56188SChris Leech return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp, 277611b56188SChris Leech fip, timeout); 277711b56188SChris Leech case ELS_LOGO: 277811b56188SChris Leech /* only hook onto fabric logouts, not port logouts */ 277911b56188SChris Leech if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) 278011b56188SChris Leech break; 278111b56188SChris Leech return fc_elsct_send(lport, did, fp, op, fcoe_logo_resp, 2782386309ceSJoe Eykholt lport, timeout); 278311b56188SChris Leech } 278411b56188SChris Leech return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); 278511b56188SChris Leech } 278611b56188SChris Leech 27879a05753bSChris Leech /** 27889a05753bSChris Leech * fcoe_vport_create() - create an fc_host/scsi_host for a vport 27899a05753bSChris Leech * @vport: fc_vport object to create a new fc_host for 27909a05753bSChris Leech * @disabled: start the new fc_host in a disabled state by default? 27919a05753bSChris Leech * 27929a05753bSChris Leech * Returns: 0 for success 27939a05753bSChris Leech */ 27949a05753bSChris Leech static int fcoe_vport_create(struct fc_vport *vport, bool disabled) 27959a05753bSChris Leech { 27969a05753bSChris Leech struct Scsi_Host *shost = vport_to_shost(vport); 27979a05753bSChris Leech struct fc_lport *n_port = shost_priv(shost); 27989a05753bSChris Leech struct fcoe_port *port = lport_priv(n_port); 27998597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 28009a05753bSChris Leech struct net_device *netdev = fcoe->netdev; 28019a05753bSChris Leech struct fc_lport *vn_port; 2802bdf25218SNeerav Parikh int rc; 2803bdf25218SNeerav Parikh char buf[32]; 2804bdf25218SNeerav Parikh 2805bdf25218SNeerav Parikh rc = fcoe_validate_vport_create(vport); 2806bdf25218SNeerav Parikh if (rc) { 2807d834895cSBhanu Prakash Gollapudi fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); 2808bdf25218SNeerav Parikh printk(KERN_ERR "fcoe: Failed to create vport, " 2809bdf25218SNeerav Parikh "WWPN (0x%s) already exists\n", 2810bdf25218SNeerav Parikh buf); 2811bdf25218SNeerav Parikh return rc; 2812bdf25218SNeerav Parikh } 28139a05753bSChris Leech 28149a05753bSChris Leech mutex_lock(&fcoe_config_mutex); 28154bc71cb9SJiri Pirko rtnl_lock(); 28169a05753bSChris Leech vn_port = fcoe_if_create(fcoe, &vport->dev, 1); 28174bc71cb9SJiri Pirko rtnl_unlock(); 28189a05753bSChris Leech mutex_unlock(&fcoe_config_mutex); 28199a05753bSChris Leech 28209a05753bSChris Leech if (IS_ERR(vn_port)) { 28219a05753bSChris Leech printk(KERN_ERR "fcoe: fcoe_vport_create(%s) failed\n", 28229a05753bSChris Leech netdev->name); 28239a05753bSChris Leech return -EIO; 28249a05753bSChris Leech } 28259a05753bSChris Leech 28269a05753bSChris Leech if (disabled) { 28279a05753bSChris Leech fc_vport_set_state(vport, FC_VPORT_DISABLED); 28289a05753bSChris Leech } else { 28299a05753bSChris Leech vn_port->boot_time = jiffies; 28309a05753bSChris Leech fc_fabric_login(vn_port); 28319a05753bSChris Leech fc_vport_setlink(vn_port); 28329a05753bSChris Leech } 28339a05753bSChris Leech return 0; 28349a05753bSChris Leech } 28359a05753bSChris Leech 28369a05753bSChris Leech /** 28379a05753bSChris Leech * fcoe_vport_destroy() - destroy the fc_host/scsi_host for a vport 28389a05753bSChris Leech * @vport: fc_vport object that is being destroyed 28399a05753bSChris Leech * 28409a05753bSChris Leech * Returns: 0 for success 28419a05753bSChris Leech */ 28429a05753bSChris Leech static int fcoe_vport_destroy(struct fc_vport *vport) 28439a05753bSChris Leech { 28449a05753bSChris Leech struct Scsi_Host *shost = vport_to_shost(vport); 28459a05753bSChris Leech struct fc_lport *n_port = shost_priv(shost); 28469a05753bSChris Leech struct fc_lport *vn_port = vport->dd_data; 28479a05753bSChris Leech 28489a05753bSChris Leech mutex_lock(&n_port->lp_mutex); 28499a05753bSChris Leech list_del(&vn_port->list); 28509a05753bSChris Leech mutex_unlock(&n_port->lp_mutex); 2851ccefd23eSRobert Love 2852ccefd23eSRobert Love mutex_lock(&fcoe_config_mutex); 2853ccefd23eSRobert Love fcoe_if_destroy(vn_port); 2854ccefd23eSRobert Love mutex_unlock(&fcoe_config_mutex); 2855ccefd23eSRobert Love 28569a05753bSChris Leech return 0; 28579a05753bSChris Leech } 28589a05753bSChris Leech 28599a05753bSChris Leech /** 28609a05753bSChris Leech * fcoe_vport_disable() - change vport state 28619a05753bSChris Leech * @vport: vport to bring online/offline 28629a05753bSChris Leech * @disable: should the vport be disabled? 28639a05753bSChris Leech */ 28649a05753bSChris Leech static int fcoe_vport_disable(struct fc_vport *vport, bool disable) 28659a05753bSChris Leech { 28669a05753bSChris Leech struct fc_lport *lport = vport->dd_data; 28679a05753bSChris Leech 28689a05753bSChris Leech if (disable) { 28699a05753bSChris Leech fc_vport_set_state(vport, FC_VPORT_DISABLED); 28709a05753bSChris Leech fc_fabric_logoff(lport); 28719a05753bSChris Leech } else { 28729a05753bSChris Leech lport->boot_time = jiffies; 28739a05753bSChris Leech fc_fabric_login(lport); 28749a05753bSChris Leech fc_vport_setlink(lport); 28759a05753bSChris Leech } 28769a05753bSChris Leech 28779a05753bSChris Leech return 0; 28789a05753bSChris Leech } 28799a05753bSChris Leech 2880dc8596d3SChris Leech /** 2881dc8596d3SChris Leech * fcoe_vport_set_symbolic_name() - append vport string to symbolic name 2882dc8596d3SChris Leech * @vport: fc_vport with a new symbolic name string 2883dc8596d3SChris Leech * 2884dc8596d3SChris Leech * After generating a new symbolic name string, a new RSPN_ID request is 2885dc8596d3SChris Leech * sent to the name server. There is no response handler, so if it fails 2886dc8596d3SChris Leech * for some reason it will not be retried. 2887dc8596d3SChris Leech */ 2888dc8596d3SChris Leech static void fcoe_set_vport_symbolic_name(struct fc_vport *vport) 2889dc8596d3SChris Leech { 2890dc8596d3SChris Leech struct fc_lport *lport = vport->dd_data; 2891dc8596d3SChris Leech struct fc_frame *fp; 2892dc8596d3SChris Leech size_t len; 2893dc8596d3SChris Leech 2894dc8596d3SChris Leech snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE, 2895dc8596d3SChris Leech "%s v%s over %s : %s", FCOE_NAME, FCOE_VERSION, 2896dc8596d3SChris Leech fcoe_netdev(lport)->name, vport->symbolic_name); 2897dc8596d3SChris Leech 2898dc8596d3SChris Leech if (lport->state != LPORT_ST_READY) 2899dc8596d3SChris Leech return; 2900dc8596d3SChris Leech 2901dc8596d3SChris Leech len = strnlen(fc_host_symbolic_name(lport->host), 255); 2902dc8596d3SChris Leech fp = fc_frame_alloc(lport, 2903dc8596d3SChris Leech sizeof(struct fc_ct_hdr) + 2904dc8596d3SChris Leech sizeof(struct fc_ns_rspn) + len); 2905dc8596d3SChris Leech if (!fp) 2906dc8596d3SChris Leech return; 2907dc8596d3SChris Leech lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RSPN_ID, 2908b94f8951SJoe Eykholt NULL, NULL, 3 * lport->r_a_tov); 2909dc8596d3SChris Leech } 2910b84056bfSYi Zou 29118d55e507SRobert Love static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) 29128d55e507SRobert Love { 29138d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev = 29148d55e507SRobert Love fcoe_fcf_dev_to_ctlr_dev(fcf_dev); 29158d55e507SRobert Love struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); 29168d55e507SRobert Love struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr); 29178d55e507SRobert Love 29188d55e507SRobert Love fcf_dev->vlan_id = vlan_dev_vlan_id(fcoe->netdev); 29198d55e507SRobert Love } 29208d55e507SRobert Love 29217d65b0dfSJoe Eykholt /** 29227d65b0dfSJoe Eykholt * fcoe_set_port_id() - Callback from libfc when Port_ID is set. 29237d65b0dfSJoe Eykholt * @lport: the local port 29247d65b0dfSJoe Eykholt * @port_id: the port ID 29257d65b0dfSJoe Eykholt * @fp: the received frame, if any, that caused the port_id to be set. 29267d65b0dfSJoe Eykholt * 29277d65b0dfSJoe Eykholt * This routine handles the case where we received a FLOGI and are 29287d65b0dfSJoe Eykholt * entering point-to-point mode. We need to call fcoe_ctlr_recv_flogi() 29297d65b0dfSJoe Eykholt * so it can set the non-mapped mode and gateway address. 29307d65b0dfSJoe Eykholt * 29317d65b0dfSJoe Eykholt * The FLOGI LS_ACC is handled by fcoe_flogi_resp(). 29327d65b0dfSJoe Eykholt */ 29337d65b0dfSJoe Eykholt static void fcoe_set_port_id(struct fc_lport *lport, 29347d65b0dfSJoe Eykholt u32 port_id, struct fc_frame *fp) 29357d65b0dfSJoe Eykholt { 29367d65b0dfSJoe Eykholt struct fcoe_port *port = lport_priv(lport); 29378597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 2938619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 29397d65b0dfSJoe Eykholt 29407d65b0dfSJoe Eykholt if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) 2941619fe4beSRobert Love fcoe_ctlr_recv_flogi(ctlr, lport, fp); 29427d65b0dfSJoe Eykholt } 2943