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 7786fef3902SNeerav Parikh port = lport_priv(lport); 7796fef3902SNeerav Parikh fcoe = port->priv; 7806fef3902SNeerav Parikh realdev = fcoe->realdev; 7816fef3902SNeerav Parikh 7826fef3902SNeerav Parikh if (!realdev) 7836fef3902SNeerav Parikh return; 7846fef3902SNeerav Parikh 7856fef3902SNeerav Parikh /* No FDMI state m/c for NPIV ports */ 7866fef3902SNeerav Parikh if (lport->vport) 7876fef3902SNeerav Parikh return; 7886fef3902SNeerav Parikh 7896fef3902SNeerav Parikh if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) { 790f07d46bbSNeerav Parikh struct netdev_fcoe_hbainfo *fdmi; 791f07d46bbSNeerav Parikh fdmi = kzalloc(sizeof(*fdmi), GFP_KERNEL); 792f07d46bbSNeerav Parikh if (!fdmi) 793f07d46bbSNeerav Parikh return; 794f07d46bbSNeerav Parikh 7956fef3902SNeerav Parikh rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev, 796f07d46bbSNeerav Parikh fdmi); 7976fef3902SNeerav Parikh if (rc) { 7986fef3902SNeerav Parikh printk(KERN_INFO "fcoe: Failed to retrieve FDMI " 7996fef3902SNeerav Parikh "information from netdev.\n"); 8006fef3902SNeerav Parikh return; 8016fef3902SNeerav Parikh } 8026fef3902SNeerav Parikh 8036fef3902SNeerav Parikh snprintf(fc_host_serial_number(lport->host), 8046fef3902SNeerav Parikh FC_SERIAL_NUMBER_SIZE, 8056fef3902SNeerav Parikh "%s", 806f07d46bbSNeerav Parikh fdmi->serial_number); 8076fef3902SNeerav Parikh snprintf(fc_host_manufacturer(lport->host), 8086fef3902SNeerav Parikh FC_SERIAL_NUMBER_SIZE, 8096fef3902SNeerav Parikh "%s", 810f07d46bbSNeerav Parikh fdmi->manufacturer); 8116fef3902SNeerav Parikh snprintf(fc_host_model(lport->host), 8126fef3902SNeerav Parikh FC_SYMBOLIC_NAME_SIZE, 8136fef3902SNeerav Parikh "%s", 814f07d46bbSNeerav Parikh fdmi->model); 8156fef3902SNeerav Parikh snprintf(fc_host_model_description(lport->host), 8166fef3902SNeerav Parikh FC_SYMBOLIC_NAME_SIZE, 8176fef3902SNeerav Parikh "%s", 818f07d46bbSNeerav Parikh fdmi->model_description); 8196fef3902SNeerav Parikh snprintf(fc_host_hardware_version(lport->host), 8206fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8216fef3902SNeerav Parikh "%s", 822f07d46bbSNeerav Parikh fdmi->hardware_version); 8236fef3902SNeerav Parikh snprintf(fc_host_driver_version(lport->host), 8246fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8256fef3902SNeerav Parikh "%s", 826f07d46bbSNeerav Parikh fdmi->driver_version); 8276fef3902SNeerav Parikh snprintf(fc_host_optionrom_version(lport->host), 8286fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8296fef3902SNeerav Parikh "%s", 830f07d46bbSNeerav Parikh fdmi->optionrom_version); 8316fef3902SNeerav Parikh snprintf(fc_host_firmware_version(lport->host), 8326fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8336fef3902SNeerav Parikh "%s", 834f07d46bbSNeerav Parikh fdmi->firmware_version); 8356fef3902SNeerav Parikh 8366fef3902SNeerav Parikh /* Enable FDMI lport states */ 8376fef3902SNeerav Parikh lport->fdmi_enabled = 1; 838f07d46bbSNeerav Parikh kfree(fdmi); 8396fef3902SNeerav Parikh } else { 8406fef3902SNeerav Parikh lport->fdmi_enabled = 0; 8416fef3902SNeerav Parikh printk(KERN_INFO "fcoe: No FDMI support.\n"); 8426fef3902SNeerav Parikh } 8436fef3902SNeerav Parikh } 8446fef3902SNeerav Parikh 8451875f27eSRobert Love /** 8461875f27eSRobert Love * fcoe_oem_match() - The match routine for the offloaded exchange manager 8471875f27eSRobert Love * @fp: The I/O frame 848d7179680SVasu Dev * 8491875f27eSRobert Love * This routine will be associated with an exchange manager (EM). When 8501875f27eSRobert Love * the libfc exchange handling code is looking for an EM to use it will 8511875f27eSRobert Love * call this routine and pass it the frame that it wishes to send. This 8521875f27eSRobert Love * routine will return True if the associated EM is to be used and False 8531875f27eSRobert Love * if the echange code should continue looking for an EM. 8541875f27eSRobert Love * 8551875f27eSRobert Love * The offload EM that this routine is associated with will handle any 8561875f27eSRobert Love * packets that are for SCSI read requests. 8571875f27eSRobert Love * 8581ff9918bSKiran Patil * This has been enhanced to work when FCoE stack is operating in target 8591ff9918bSKiran Patil * mode. 8601ff9918bSKiran Patil * 8611875f27eSRobert Love * Returns: True for read types I/O, otherwise returns false. 862d7179680SVasu Dev */ 8637c9c6841SBart Van Assche static bool fcoe_oem_match(struct fc_frame *fp) 864d7179680SVasu Dev { 8651ff9918bSKiran Patil struct fc_frame_header *fh = fc_frame_header_get(fp); 8661ff9918bSKiran Patil struct fcp_cmnd *fcp; 8671ff9918bSKiran Patil 8681ff9918bSKiran Patil if (fc_fcp_is_read(fr_fsp(fp)) && 8691ff9918bSKiran Patil (fr_fsp(fp)->data_len > fcoe_ddp_min)) 8701ff9918bSKiran Patil return true; 871a762dce4SYi Zou else if ((fr_fsp(fp) == NULL) && 872a762dce4SYi Zou (fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) && 873a762dce4SYi Zou (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { 8741ff9918bSKiran Patil fcp = fc_frame_payload_get(fp, sizeof(*fcp)); 875a762dce4SYi Zou if ((fcp->fc_flags & FCP_CFL_WRDATA) && 876a762dce4SYi Zou (ntohl(fcp->fc_dl) > fcoe_ddp_min)) 8771ff9918bSKiran Patil return true; 8781ff9918bSKiran Patil } 8791ff9918bSKiran Patil return false; 880d7179680SVasu Dev } 881d7179680SVasu Dev 882a703e490SVasu Dev /** 8831875f27eSRobert Love * fcoe_em_config() - Allocate and configure an exchange manager 8841875f27eSRobert Love * @lport: The local port that the new EM will be associated with 885a703e490SVasu Dev * 886a703e490SVasu Dev * Returns: 0 on success 887a703e490SVasu Dev */ 8881875f27eSRobert Love static inline int fcoe_em_config(struct fc_lport *lport) 889a703e490SVasu Dev { 8901875f27eSRobert Love struct fcoe_port *port = lport_priv(lport); 8918597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 89225024989SChris Leech struct fcoe_interface *oldfcoe = NULL; 8931d1b88dcSVasu Dev struct net_device *old_real_dev, *cur_real_dev; 894d7179680SVasu Dev u16 min_xid = FCOE_MIN_XID; 895d7179680SVasu Dev u16 max_xid = FCOE_MAX_XID; 896d7179680SVasu Dev 897d7179680SVasu Dev /* 898d7179680SVasu Dev * Check if need to allocate an em instance for 899d7179680SVasu Dev * offload exchange ids to be shared across all VN_PORTs/lport. 900d7179680SVasu Dev */ 9011875f27eSRobert Love if (!lport->lro_enabled || !lport->lro_xid || 9021875f27eSRobert Love (lport->lro_xid >= max_xid)) { 9031875f27eSRobert Love lport->lro_xid = 0; 904d7179680SVasu Dev goto skip_oem; 905d7179680SVasu Dev } 906d7179680SVasu Dev 907d7179680SVasu Dev /* 908d7179680SVasu Dev * Reuse existing offload em instance in case 9091d1b88dcSVasu Dev * it is already allocated on real eth device 910d7179680SVasu Dev */ 91125024989SChris Leech if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) 91225024989SChris Leech cur_real_dev = vlan_dev_real_dev(fcoe->netdev); 9131d1b88dcSVasu Dev else 91425024989SChris Leech cur_real_dev = fcoe->netdev; 9151d1b88dcSVasu Dev 91625024989SChris Leech list_for_each_entry(oldfcoe, &fcoe_hostlist, list) { 91725024989SChris Leech if (oldfcoe->netdev->priv_flags & IFF_802_1Q_VLAN) 91825024989SChris Leech old_real_dev = vlan_dev_real_dev(oldfcoe->netdev); 9191d1b88dcSVasu Dev else 92025024989SChris Leech old_real_dev = oldfcoe->netdev; 9211d1b88dcSVasu Dev 9221d1b88dcSVasu Dev if (cur_real_dev == old_real_dev) { 923991cbb60SChris Leech fcoe->oem = oldfcoe->oem; 924d7179680SVasu Dev break; 925d7179680SVasu Dev } 926d7179680SVasu Dev } 927d7179680SVasu Dev 928991cbb60SChris Leech if (fcoe->oem) { 9291875f27eSRobert Love if (!fc_exch_mgr_add(lport, fcoe->oem, fcoe_oem_match)) { 930d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to add " 931d7179680SVasu Dev "offload em:%p on interface:%s\n", 932991cbb60SChris Leech fcoe->oem, fcoe->netdev->name); 933a703e490SVasu Dev return -ENOMEM; 934d7179680SVasu Dev } 935d7179680SVasu Dev } else { 9361875f27eSRobert Love fcoe->oem = fc_exch_mgr_alloc(lport, FC_CLASS_3, 9371875f27eSRobert Love FCOE_MIN_XID, lport->lro_xid, 938d7179680SVasu Dev fcoe_oem_match); 939991cbb60SChris Leech if (!fcoe->oem) { 940d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to allocate " 941d7179680SVasu Dev "em for offload exches on interface:%s\n", 94225024989SChris Leech fcoe->netdev->name); 943d7179680SVasu Dev return -ENOMEM; 944d7179680SVasu Dev } 945d7179680SVasu Dev } 946d7179680SVasu Dev 947d7179680SVasu Dev /* 948d7179680SVasu Dev * Exclude offload EM xid range from next EM xid range. 949d7179680SVasu Dev */ 9501875f27eSRobert Love min_xid += lport->lro_xid + 1; 951d7179680SVasu Dev 952d7179680SVasu Dev skip_oem: 9531875f27eSRobert Love if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, min_xid, max_xid, NULL)) { 954d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to " 95525024989SChris Leech "allocate em on interface %s\n", fcoe->netdev->name); 956d7179680SVasu Dev return -ENOMEM; 957d7179680SVasu Dev } 958a703e490SVasu Dev 959a703e490SVasu Dev return 0; 960a703e490SVasu Dev } 961a703e490SVasu Dev 962a703e490SVasu Dev /** 9631875f27eSRobert Love * fcoe_if_destroy() - Tear down a SW FCoE instance 9641875f27eSRobert Love * @lport: The local port to be destroyed 96534ce27bcSVasu Dev * 966a703e490SVasu Dev */ 967af7f85d9SChris Leech static void fcoe_if_destroy(struct fc_lport *lport) 968a703e490SVasu Dev { 969b2085a4eSNeerav Parikh struct fcoe_port *port = lport_priv(lport); 970b2085a4eSNeerav Parikh struct fcoe_interface *fcoe = port->priv; 971b2085a4eSNeerav Parikh struct net_device *netdev = fcoe->netdev; 972b2085a4eSNeerav Parikh 973b2085a4eSNeerav Parikh FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); 974b2085a4eSNeerav Parikh 975b2085a4eSNeerav Parikh /* Logout of the fabric */ 976b2085a4eSNeerav Parikh fc_fabric_logoff(lport); 977b2085a4eSNeerav Parikh 978b2085a4eSNeerav Parikh /* Cleanup the fc_lport */ 979b2085a4eSNeerav Parikh fc_lport_destroy(lport); 980b2085a4eSNeerav Parikh 981b2085a4eSNeerav Parikh /* Stop the transmit retry timer */ 982b2085a4eSNeerav Parikh del_timer_sync(&port->timer); 983b2085a4eSNeerav Parikh 984b2085a4eSNeerav Parikh /* Free existing transmit skbs */ 985b2085a4eSNeerav Parikh fcoe_clean_pending_queue(lport); 986b2085a4eSNeerav Parikh 987b2085a4eSNeerav Parikh rtnl_lock(); 988b2085a4eSNeerav Parikh if (!is_zero_ether_addr(port->data_src_addr)) 989b2085a4eSNeerav Parikh dev_uc_del(netdev, port->data_src_addr); 990433eba04SVasu Dev if (lport->vport) 991433eba04SVasu Dev synchronize_net(); 992433eba04SVasu Dev else 993433eba04SVasu Dev fcoe_interface_remove(fcoe); 994b2085a4eSNeerav Parikh rtnl_unlock(); 995b2085a4eSNeerav Parikh 99654b649f8SChris Leech /* Free queued packets for the per-CPU receive threads */ 99754b649f8SChris Leech fcoe_percpu_clean(lport); 99854b649f8SChris Leech 999a703e490SVasu Dev /* Detach from the scsi-ml */ 1000af7f85d9SChris Leech fc_remove_host(lport->host); 1001af7f85d9SChris Leech scsi_remove_host(lport->host); 1002a703e490SVasu Dev 100380e736f8SYi Zou /* Destroy lport scsi_priv */ 100480e736f8SYi Zou fc_fcp_destroy(lport); 100580e736f8SYi Zou 1006a703e490SVasu Dev /* There are no more rports or I/O, free the EM */ 1007af7f85d9SChris Leech fc_exch_mgr_free(lport); 1008a703e490SVasu Dev 1009a703e490SVasu Dev /* Free memory used by statistical counters */ 1010af7f85d9SChris Leech fc_lport_free_stats(lport); 1011a703e490SVasu Dev 10123cab4468SVasu Dev /* 10133cab4468SVasu Dev * Release the Scsi_Host for vport but hold on to 10143cab4468SVasu Dev * master lport until it fcoe interface fully cleaned-up. 10153cab4468SVasu Dev */ 10163cab4468SVasu Dev if (lport->vport) 1017af7f85d9SChris Leech scsi_host_put(lport->host); 1018a703e490SVasu Dev } 1019a703e490SVasu Dev 10201875f27eSRobert Love /** 10211875f27eSRobert Love * fcoe_ddp_setup() - Call a LLD's ddp_setup through the net device 10221875f27eSRobert Love * @lport: The local port to setup DDP for 10231875f27eSRobert Love * @xid: The exchange ID for this DDP transfer 10241875f27eSRobert Love * @sgl: The scatterlist describing this transfer 10251875f27eSRobert Love * @sgc: The number of sg items 1026a703e490SVasu Dev * 10271875f27eSRobert Love * Returns: 0 if the DDP context was not configured 1028a703e490SVasu Dev */ 10291875f27eSRobert Love static int fcoe_ddp_setup(struct fc_lport *lport, u16 xid, 1030a703e490SVasu Dev struct scatterlist *sgl, unsigned int sgc) 1031a703e490SVasu Dev { 10321875f27eSRobert Love struct net_device *netdev = fcoe_netdev(lport); 1033a703e490SVasu Dev 10341875f27eSRobert Love if (netdev->netdev_ops->ndo_fcoe_ddp_setup) 10351875f27eSRobert Love return netdev->netdev_ops->ndo_fcoe_ddp_setup(netdev, 10361875f27eSRobert Love xid, sgl, 10371875f27eSRobert Love sgc); 1038a703e490SVasu Dev 1039a703e490SVasu Dev return 0; 1040a703e490SVasu Dev } 1041a703e490SVasu Dev 1042a703e490SVasu Dev /** 104371f89491SYi Zou * fcoe_ddp_target() - Call a LLD's ddp_target through the net device 104471f89491SYi Zou * @lport: The local port to setup DDP for 104571f89491SYi Zou * @xid: The exchange ID for this DDP transfer 104671f89491SYi Zou * @sgl: The scatterlist describing this transfer 104771f89491SYi Zou * @sgc: The number of sg items 104871f89491SYi Zou * 104971f89491SYi Zou * Returns: 0 if the DDP context was not configured 105071f89491SYi Zou */ 105171f89491SYi Zou static int fcoe_ddp_target(struct fc_lport *lport, u16 xid, 105271f89491SYi Zou struct scatterlist *sgl, unsigned int sgc) 105371f89491SYi Zou { 105471f89491SYi Zou struct net_device *netdev = fcoe_netdev(lport); 105571f89491SYi Zou 105671f89491SYi Zou if (netdev->netdev_ops->ndo_fcoe_ddp_target) 105771f89491SYi Zou return netdev->netdev_ops->ndo_fcoe_ddp_target(netdev, xid, 105871f89491SYi Zou sgl, sgc); 105971f89491SYi Zou 106071f89491SYi Zou return 0; 106171f89491SYi Zou } 106271f89491SYi Zou 106371f89491SYi Zou 106471f89491SYi Zou /** 10651875f27eSRobert Love * fcoe_ddp_done() - Call a LLD's ddp_done through the net device 10661875f27eSRobert Love * @lport: The local port to complete DDP on 10671875f27eSRobert Love * @xid: The exchange ID for this DDP transfer 1068a703e490SVasu Dev * 10691875f27eSRobert Love * Returns: the length of data that have been completed by DDP 10701875f27eSRobert Love */ 10711875f27eSRobert Love static int fcoe_ddp_done(struct fc_lport *lport, u16 xid) 10721875f27eSRobert Love { 10731875f27eSRobert Love struct net_device *netdev = fcoe_netdev(lport); 10741875f27eSRobert Love 10751875f27eSRobert Love if (netdev->netdev_ops->ndo_fcoe_ddp_done) 10761875f27eSRobert Love return netdev->netdev_ops->ndo_fcoe_ddp_done(netdev, xid); 10771875f27eSRobert Love return 0; 10781875f27eSRobert Love } 10791875f27eSRobert Love 10801875f27eSRobert Love /** 10811875f27eSRobert Love * fcoe_if_create() - Create a FCoE instance on an interface 10821875f27eSRobert Love * @fcoe: The FCoE interface to create a local port on 10831875f27eSRobert Love * @parent: The device pointer to be the parent in sysfs for the SCSI host 10841875f27eSRobert Love * @npiv: Indicates if the port is a vport or not 10851875f27eSRobert Love * 10861875f27eSRobert Love * Creates a fc_lport instance and a Scsi_Host instance and configure them. 1087a703e490SVasu Dev * 1088af7f85d9SChris Leech * Returns: The allocated fc_lport or an error pointer 1089a703e490SVasu Dev */ 1090030f4e00SChris Leech static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, 10919a05753bSChris Leech struct device *parent, int npiv) 1092a703e490SVasu Dev { 1093619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 10941875f27eSRobert Love struct net_device *netdev = fcoe->netdev; 109572fa396bSVasu Dev struct fc_lport *lport, *n_port; 1096014f5c3fSChris Leech struct fcoe_port *port; 109772fa396bSVasu Dev struct Scsi_Host *shost; 10981875f27eSRobert Love int rc; 10999a05753bSChris Leech /* 11009a05753bSChris Leech * parent is only a vport if npiv is 1, 11019a05753bSChris Leech * but we'll only use vport in that case so go ahead and set it 11029a05753bSChris Leech */ 11039a05753bSChris Leech struct fc_vport *vport = dev_to_vport(parent); 1104a703e490SVasu Dev 1105d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Create Interface\n"); 1106a703e490SVasu Dev 110772fa396bSVasu Dev if (!npiv) 110872fa396bSVasu Dev lport = libfc_host_alloc(&fcoe_shost_template, sizeof(*port)); 110972fa396bSVasu Dev else 111072fa396bSVasu Dev lport = libfc_vport_create(vport, sizeof(*port)); 111172fa396bSVasu Dev 111286221969SChris Leech if (!lport) { 1113014f5c3fSChris Leech FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); 1114014f5c3fSChris Leech rc = -ENOMEM; 1115030f4e00SChris Leech goto out; 1116014f5c3fSChris Leech } 1117014f5c3fSChris Leech port = lport_priv(lport); 11182e70e241SChris Leech port->lport = lport; 11198597ae8bSBhanu Prakash Gollapudi port->priv = fcoe; 112066524ec9SYi Zou port->get_netdev = fcoe_netdev; 11218597ae8bSBhanu Prakash Gollapudi port->max_queue_depth = FCOE_MAX_QUEUE_DEPTH; 11228597ae8bSBhanu Prakash Gollapudi port->min_queue_depth = FCOE_MIN_QUEUE_DEPTH; 11232e70e241SChris Leech INIT_WORK(&port->destroy_work, fcoe_destroy_work); 1124a703e490SVasu Dev 1125f9184df3SNeil Horman /* 1126f9184df3SNeil Horman * Need to add the lport to the hostlist 1127f9184df3SNeil Horman * so we catch NETDEV_CHANGE events. 1128f9184df3SNeil Horman */ 1129f9184df3SNeil Horman fcoe_hostlist_add(lport); 1130f9184df3SNeil Horman 11311875f27eSRobert Love /* configure a fc_lport including the exchange manager */ 1132af7f85d9SChris Leech rc = fcoe_lport_config(lport); 1133a703e490SVasu Dev if (rc) { 1134d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure lport for the " 1135d5488eb9SRobert Love "interface\n"); 1136a703e490SVasu Dev goto out_host_put; 1137a703e490SVasu Dev } 1138a703e490SVasu Dev 11399a05753bSChris Leech if (npiv) { 11409f8f3aa6SChris Leech FCOE_NETDEV_DBG(netdev, "Setting vport names, " 11419f8f3aa6SChris Leech "%16.16llx %16.16llx\n", 11429a05753bSChris Leech vport->node_name, vport->port_name); 11439a05753bSChris Leech fc_set_wwnn(lport, vport->node_name); 11449a05753bSChris Leech fc_set_wwpn(lport, vport->port_name); 11459a05753bSChris Leech } 11469a05753bSChris Leech 1147ab6b85c1SVasu Dev /* configure lport network properties */ 1148af7f85d9SChris Leech rc = fcoe_netdev_config(lport, netdev); 1149ab6b85c1SVasu Dev if (rc) { 1150d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " 1151d5488eb9SRobert Love "interface\n"); 115254b649f8SChris Leech goto out_lp_destroy; 1153ab6b85c1SVasu Dev } 115497c8389dSJoe Eykholt 1155a703e490SVasu Dev /* configure lport scsi host properties */ 11568ba00a4bSVasu Dev rc = fcoe_shost_config(lport, parent); 1157a703e490SVasu Dev if (rc) { 1158d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " 1159d5488eb9SRobert Love "interface\n"); 116054b649f8SChris Leech goto out_lp_destroy; 1161a703e490SVasu Dev } 1162a703e490SVasu Dev 1163a703e490SVasu Dev /* Initialize the library */ 1164619fe4beSRobert Love rc = fcoe_libfc_config(lport, ctlr, &fcoe_libfc_fcn_templ, 1); 1165a703e490SVasu Dev if (rc) { 1166d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " 1167d5488eb9SRobert Love "interface\n"); 1168a703e490SVasu Dev goto out_lp_destroy; 1169a703e490SVasu Dev } 1170a703e490SVasu Dev 11716fef3902SNeerav Parikh /* Initialized FDMI information */ 11726fef3902SNeerav Parikh fcoe_fdmi_info(lport, netdev); 11736fef3902SNeerav Parikh 1174e8af4d43SVasu Dev /* 1175e8af4d43SVasu Dev * fcoe_em_alloc() and fcoe_hostlist_add() both 11769a05753bSChris Leech * need to be atomic with respect to other changes to the 11779a05753bSChris Leech * hostlist since fcoe_em_alloc() looks for an existing EM 1178e8af4d43SVasu Dev * instance on host list updated by fcoe_hostlist_add(). 1179c863df33SChris Leech * 11809a05753bSChris Leech * This is currently handled through the fcoe_config_mutex 11819a05753bSChris Leech * begin held. 1182e8af4d43SVasu Dev */ 118372fa396bSVasu Dev if (!npiv) 118496316099SVasu Dev /* lport exch manager allocation */ 1185af7f85d9SChris Leech rc = fcoe_em_config(lport); 118672fa396bSVasu Dev else { 118772fa396bSVasu Dev shost = vport_to_shost(vport); 118872fa396bSVasu Dev n_port = shost_priv(shost); 118972fa396bSVasu Dev rc = fc_exch_mgr_list_clone(n_port, lport); 119096316099SVasu Dev } 119172fa396bSVasu Dev 119272fa396bSVasu Dev if (rc) { 119372fa396bSVasu Dev FCOE_NETDEV_DBG(netdev, "Could not configure the EM\n"); 119472fa396bSVasu Dev goto out_lp_destroy; 11959a05753bSChris Leech } 119696316099SVasu Dev 1197af7f85d9SChris Leech return lport; 1198a703e490SVasu Dev 1199a703e490SVasu Dev out_lp_destroy: 1200af7f85d9SChris Leech fc_exch_mgr_free(lport); 1201a703e490SVasu Dev out_host_put: 1202f9184df3SNeil Horman fcoe_hostlist_del(lport); 1203af7f85d9SChris Leech scsi_host_put(lport->host); 1204af7f85d9SChris Leech out: 1205af7f85d9SChris Leech return ERR_PTR(rc); 1206a703e490SVasu Dev } 1207a703e490SVasu Dev 1208a703e490SVasu Dev /** 12091875f27eSRobert Love * fcoe_if_init() - Initialization routine for fcoe.ko 12101875f27eSRobert Love * 12111875f27eSRobert Love * Attaches the SW FCoE transport to the FC transport 1212a703e490SVasu Dev * 1213a703e490SVasu Dev * Returns: 0 on success 1214a703e490SVasu Dev */ 1215a703e490SVasu Dev static int __init fcoe_if_init(void) 1216a703e490SVasu Dev { 1217a703e490SVasu Dev /* attach to scsi transport */ 12188ca86f84SYi Zou fcoe_nport_scsi_transport = 12198ca86f84SYi Zou fc_attach_transport(&fcoe_nport_fc_functions); 12208ca86f84SYi Zou fcoe_vport_scsi_transport = 12218ca86f84SYi Zou fc_attach_transport(&fcoe_vport_fc_functions); 1222a703e490SVasu Dev 12238ca86f84SYi Zou if (!fcoe_nport_scsi_transport) { 1224d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); 1225a703e490SVasu Dev return -ENODEV; 1226a703e490SVasu Dev } 1227a703e490SVasu Dev 1228a703e490SVasu Dev return 0; 1229a703e490SVasu Dev } 1230a703e490SVasu Dev 1231a703e490SVasu Dev /** 12321875f27eSRobert Love * fcoe_if_exit() - Tear down fcoe.ko 12331875f27eSRobert Love * 12341875f27eSRobert Love * Detaches the SW FCoE transport from the FC transport 1235a703e490SVasu Dev * 1236a703e490SVasu Dev * Returns: 0 on success 1237a703e490SVasu Dev */ 12387c9c6841SBart Van Assche static int __exit fcoe_if_exit(void) 1239a703e490SVasu Dev { 12408ca86f84SYi Zou fc_release_transport(fcoe_nport_scsi_transport); 12418ca86f84SYi Zou fc_release_transport(fcoe_vport_scsi_transport); 12428ca86f84SYi Zou fcoe_nport_scsi_transport = NULL; 12438ca86f84SYi Zou fcoe_vport_scsi_transport = NULL; 1244a703e490SVasu Dev return 0; 1245a703e490SVasu Dev } 1246a703e490SVasu Dev 1247a703e490SVasu Dev /** 12481875f27eSRobert Love * fcoe_percpu_thread_create() - Create a receive thread for an online CPU 12491875f27eSRobert Love * @cpu: The CPU index of the CPU to create a receive thread for 1250a703e490SVasu Dev */ 1251a703e490SVasu Dev static void fcoe_percpu_thread_create(unsigned int cpu) 1252a703e490SVasu Dev { 1253a703e490SVasu Dev struct fcoe_percpu_s *p; 1254a703e490SVasu Dev struct task_struct *thread; 1255a703e490SVasu Dev 1256a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 1257a703e490SVasu Dev 12585c609ff9SEric Dumazet thread = kthread_create_on_node(fcoe_percpu_receive_thread, 12595c609ff9SEric Dumazet (void *)p, cpu_to_node(cpu), 12605c609ff9SEric Dumazet "fcoethread/%d", cpu); 1261a703e490SVasu Dev 1262e7a51997SJoe Eykholt if (likely(!IS_ERR(thread))) { 1263a703e490SVasu Dev kthread_bind(thread, cpu); 1264a703e490SVasu Dev wake_up_process(thread); 1265a703e490SVasu Dev 1266a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1267a703e490SVasu Dev p->thread = thread; 1268a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1269a703e490SVasu Dev } 1270a703e490SVasu Dev } 1271a703e490SVasu Dev 1272a703e490SVasu Dev /** 12731875f27eSRobert Love * fcoe_percpu_thread_destroy() - Remove the receive thread of a CPU 12741875f27eSRobert Love * @cpu: The CPU index of the CPU whose receive thread is to be destroyed 1275a703e490SVasu Dev * 1276a703e490SVasu Dev * Destroys a per-CPU Rx thread. Any pending skbs are moved to the 1277a703e490SVasu Dev * current CPU's Rx thread. If the thread being destroyed is bound to 1278a703e490SVasu Dev * the CPU processing this context the skbs will be freed. 1279a703e490SVasu Dev */ 1280a703e490SVasu Dev static void fcoe_percpu_thread_destroy(unsigned int cpu) 1281a703e490SVasu Dev { 1282a703e490SVasu Dev struct fcoe_percpu_s *p; 1283a703e490SVasu Dev struct task_struct *thread; 1284a703e490SVasu Dev struct page *crc_eof; 1285a703e490SVasu Dev struct sk_buff *skb; 1286a703e490SVasu Dev #ifdef CONFIG_SMP 1287a703e490SVasu Dev struct fcoe_percpu_s *p0; 1288f018b73aSJoe Eykholt unsigned targ_cpu = get_cpu(); 1289a703e490SVasu Dev #endif /* CONFIG_SMP */ 1290a703e490SVasu Dev 1291d5488eb9SRobert Love FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); 1292a703e490SVasu Dev 1293a703e490SVasu Dev /* Prevent any new skbs from being queued for this CPU. */ 1294a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 1295a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1296a703e490SVasu Dev thread = p->thread; 1297a703e490SVasu Dev p->thread = NULL; 1298a703e490SVasu Dev crc_eof = p->crc_eof_page; 1299a703e490SVasu Dev p->crc_eof_page = NULL; 1300a703e490SVasu Dev p->crc_eof_offset = 0; 1301a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1302a703e490SVasu Dev 1303a703e490SVasu Dev #ifdef CONFIG_SMP 1304a703e490SVasu Dev /* 1305a703e490SVasu Dev * Don't bother moving the skb's if this context is running 1306a703e490SVasu Dev * on the same CPU that is having its thread destroyed. This 1307a703e490SVasu Dev * can easily happen when the module is removed. 1308a703e490SVasu Dev */ 1309a703e490SVasu Dev if (cpu != targ_cpu) { 1310a703e490SVasu Dev p0 = &per_cpu(fcoe_percpu, targ_cpu); 1311a703e490SVasu Dev spin_lock_bh(&p0->fcoe_rx_list.lock); 1312a703e490SVasu Dev if (p0->thread) { 1313d5488eb9SRobert Love FCOE_DBG("Moving frames from CPU %d to CPU %d\n", 1314a703e490SVasu Dev cpu, targ_cpu); 1315a703e490SVasu Dev 1316a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1317a703e490SVasu Dev __skb_queue_tail(&p0->fcoe_rx_list, skb); 1318a703e490SVasu Dev spin_unlock_bh(&p0->fcoe_rx_list.lock); 1319a703e490SVasu Dev } else { 1320a703e490SVasu Dev /* 1321a703e490SVasu Dev * The targeted CPU is not initialized and cannot accept 1322a703e490SVasu Dev * new skbs. Unlock the targeted CPU and drop the skbs 1323a703e490SVasu Dev * on the CPU that is going offline. 1324a703e490SVasu Dev */ 1325a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1326a703e490SVasu Dev kfree_skb(skb); 1327a703e490SVasu Dev spin_unlock_bh(&p0->fcoe_rx_list.lock); 1328a703e490SVasu Dev } 1329a703e490SVasu Dev } else { 1330a703e490SVasu Dev /* 1331a703e490SVasu Dev * This scenario occurs when the module is being removed 1332a703e490SVasu Dev * and all threads are being destroyed. skbs will continue 1333a703e490SVasu Dev * to be shifted from the CPU thread that is being removed 1334a703e490SVasu Dev * to the CPU thread associated with the CPU that is processing 1335a703e490SVasu Dev * the module removal. Once there is only one CPU Rx thread it 1336a703e490SVasu Dev * will reach this case and we will drop all skbs and later 1337a703e490SVasu Dev * stop the thread. 1338a703e490SVasu Dev */ 1339a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1340a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1341a703e490SVasu Dev kfree_skb(skb); 1342a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1343a703e490SVasu Dev } 1344f018b73aSJoe Eykholt put_cpu(); 1345a703e490SVasu Dev #else 1346a703e490SVasu Dev /* 1347dd3fd72eSChris Leech * This a non-SMP scenario where the singular Rx thread is 1348a703e490SVasu Dev * being removed. Free all skbs and stop the thread. 1349a703e490SVasu Dev */ 1350a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1351a703e490SVasu Dev while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) 1352a703e490SVasu Dev kfree_skb(skb); 1353a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1354a703e490SVasu Dev #endif 1355a703e490SVasu Dev 1356a703e490SVasu Dev if (thread) 1357a703e490SVasu Dev kthread_stop(thread); 1358a703e490SVasu Dev 1359a703e490SVasu Dev if (crc_eof) 1360a703e490SVasu Dev put_page(crc_eof); 1361a703e490SVasu Dev } 1362a703e490SVasu Dev 1363a703e490SVasu Dev /** 13641875f27eSRobert Love * fcoe_cpu_callback() - Handler for CPU hotplug events 13651875f27eSRobert Love * @nfb: The callback data block 13661875f27eSRobert Love * @action: The event triggering the callback 13671875f27eSRobert Love * @hcpu: The index of the CPU that the event is for 1368a703e490SVasu Dev * 13691875f27eSRobert Love * This creates or destroys per-CPU data for fcoe 1370a703e490SVasu Dev * 1371a703e490SVasu Dev * Returns NOTIFY_OK always. 1372a703e490SVasu Dev */ 1373a703e490SVasu Dev static int fcoe_cpu_callback(struct notifier_block *nfb, 1374a703e490SVasu Dev unsigned long action, void *hcpu) 1375a703e490SVasu Dev { 1376a703e490SVasu Dev unsigned cpu = (unsigned long)hcpu; 1377a703e490SVasu Dev 1378a703e490SVasu Dev switch (action) { 1379a703e490SVasu Dev case CPU_ONLINE: 1380a703e490SVasu Dev case CPU_ONLINE_FROZEN: 1381d5488eb9SRobert Love FCOE_DBG("CPU %x online: Create Rx thread\n", cpu); 1382a703e490SVasu Dev fcoe_percpu_thread_create(cpu); 1383a703e490SVasu Dev break; 1384a703e490SVasu Dev case CPU_DEAD: 1385a703e490SVasu Dev case CPU_DEAD_FROZEN: 1386d5488eb9SRobert Love FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu); 1387a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 1388a703e490SVasu Dev break; 1389a703e490SVasu Dev default: 1390a703e490SVasu Dev break; 1391a703e490SVasu Dev } 1392a703e490SVasu Dev return NOTIFY_OK; 1393a703e490SVasu Dev } 1394a703e490SVasu Dev 1395a703e490SVasu Dev /** 1396064287eeSKiran Patil * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming 1397064287eeSKiran Patil * command. 1398064287eeSKiran Patil * 1399d272281cSVasu Dev * This routine selects next CPU based on cpumask to distribute 1400d272281cSVasu Dev * incoming requests in round robin. 1401064287eeSKiran Patil * 1402d272281cSVasu Dev * Returns: int CPU number 1403064287eeSKiran Patil */ 1404d272281cSVasu Dev static inline unsigned int fcoe_select_cpu(void) 1405064287eeSKiran Patil { 1406064287eeSKiran Patil static unsigned int selected_cpu; 1407064287eeSKiran Patil 1408064287eeSKiran Patil selected_cpu = cpumask_next(selected_cpu, cpu_online_mask); 1409064287eeSKiran Patil if (selected_cpu >= nr_cpu_ids) 1410064287eeSKiran Patil selected_cpu = cpumask_first(cpu_online_mask); 1411d272281cSVasu Dev 1412064287eeSKiran Patil return selected_cpu; 1413064287eeSKiran Patil } 1414064287eeSKiran Patil 1415064287eeSKiran Patil /** 14161875f27eSRobert Love * fcoe_rcv() - Receive packets from a net device 14171875f27eSRobert Love * @skb: The received packet 14181875f27eSRobert Love * @netdev: The net device that the packet was received on 14191875f27eSRobert Love * @ptype: The packet type context 14201875f27eSRobert Love * @olddev: The last device net device 1421a703e490SVasu Dev * 14221875f27eSRobert Love * This routine is called by NET_RX_SOFTIRQ. It receives a packet, builds a 14231875f27eSRobert Love * FC frame and passes the frame to libfc. 1424a703e490SVasu Dev * 1425a703e490SVasu Dev * Returns: 0 for success 1426a703e490SVasu Dev */ 14277c9c6841SBart Van Assche static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, 1428a703e490SVasu Dev struct packet_type *ptype, struct net_device *olddev) 1429a703e490SVasu Dev { 14301875f27eSRobert Love struct fc_lport *lport; 1431a703e490SVasu Dev struct fcoe_rcv_info *fr; 1432619fe4beSRobert Love struct fcoe_ctlr *ctlr; 1433259ad85dSChris Leech struct fcoe_interface *fcoe; 1434a703e490SVasu Dev struct fc_frame_header *fh; 1435a703e490SVasu Dev struct fcoe_percpu_s *fps; 1436519e5135SVasu Dev struct ethhdr *eh; 1437b2f0091fSVasu Dev unsigned int cpu; 1438a703e490SVasu Dev 1439259ad85dSChris Leech fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); 1440619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1441619fe4beSRobert Love lport = ctlr->lp; 14421875f27eSRobert Love if (unlikely(!lport)) { 1443465b87bfSBart Van Assche FCOE_NETDEV_DBG(netdev, "Cannot find hba structure\n"); 1444a703e490SVasu Dev goto err2; 1445a703e490SVasu Dev } 14461875f27eSRobert Love if (!lport->link_up) 144797c8389dSJoe Eykholt goto err2; 1448a703e490SVasu Dev 1449465b87bfSBart Van Assche FCOE_NETDEV_DBG(netdev, 1450465b87bfSBart Van Assche "skb_info: len:%d data_len:%d head:%p data:%p tail:%p end:%p sum:%d dev:%s\n", 1451d5488eb9SRobert Love skb->len, skb->data_len, skb->head, skb->data, 1452d5488eb9SRobert Love skb_tail_pointer(skb), skb_end_pointer(skb), 1453d5488eb9SRobert Love skb->csum, skb->dev ? skb->dev->name : "<NULL>"); 1454a703e490SVasu Dev 14558b612434SNeil Horman 14568b612434SNeil Horman skb = skb_share_check(skb, GFP_ATOMIC); 14578b612434SNeil Horman 14588b612434SNeil Horman if (skb == NULL) 14598b612434SNeil Horman return NET_RX_DROP; 14608b612434SNeil Horman 1461519e5135SVasu Dev eh = eth_hdr(skb); 1462519e5135SVasu Dev 1463619fe4beSRobert Love if (is_fip_mode(ctlr) && 1464619fe4beSRobert Love compare_ether_addr(eh->h_source, ctlr->dest_addr)) { 1465519e5135SVasu Dev FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n", 1466519e5135SVasu Dev eh->h_source); 1467a703e490SVasu Dev goto err; 1468a703e490SVasu Dev } 1469a703e490SVasu Dev 1470a703e490SVasu Dev /* 1471a703e490SVasu Dev * Check for minimum frame length, and make sure required FCoE 1472a703e490SVasu Dev * and FC headers are pulled into the linear data area. 1473a703e490SVasu Dev */ 1474a703e490SVasu Dev if (unlikely((skb->len < FCOE_MIN_FRAME) || 1475a703e490SVasu Dev !pskb_may_pull(skb, FCOE_HEADER_LEN))) 1476a703e490SVasu Dev goto err; 1477a703e490SVasu Dev 1478a703e490SVasu Dev skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); 1479a703e490SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 1480a703e490SVasu Dev 14810ee31cb5SRobert Love if (ntoh24(&eh->h_dest[3]) != ntoh24(fh->fh_d_id)) { 14820ee31cb5SRobert Love FCOE_NETDEV_DBG(netdev, "FC frame d_id mismatch with MAC:%pM\n", 14830ee31cb5SRobert Love eh->h_dest); 14840ee31cb5SRobert Love goto err; 14850ee31cb5SRobert Love } 14860ee31cb5SRobert Love 1487a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 14881875f27eSRobert Love fr->fr_dev = lport; 1489a703e490SVasu Dev 1490a703e490SVasu Dev /* 1491b2f0091fSVasu Dev * In case the incoming frame's exchange is originated from 1492b2f0091fSVasu Dev * the initiator, then received frame's exchange id is ANDed 1493b2f0091fSVasu Dev * with fc_cpu_mask bits to get the same cpu on which exchange 1494d272281cSVasu Dev * was originated, otherwise select cpu using rx exchange id 1495d272281cSVasu Dev * or fcoe_select_cpu(). 1496a703e490SVasu Dev */ 1497b2f0091fSVasu Dev if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) 1498b2f0091fSVasu Dev cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; 1499064287eeSKiran Patil else { 1500d272281cSVasu Dev if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN) 1501d272281cSVasu Dev cpu = fcoe_select_cpu(); 1502d272281cSVasu Dev else 150329bdd2bbSKiran Patil cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask; 1504064287eeSKiran Patil } 1505324f6678SVasu Dev 1506324f6678SVasu Dev if (cpu >= nr_cpu_ids) 1507324f6678SVasu Dev goto err; 1508324f6678SVasu Dev 1509a703e490SVasu Dev fps = &per_cpu(fcoe_percpu, cpu); 151094aa29f2SNeil Horman spin_lock(&fps->fcoe_rx_list.lock); 1511a703e490SVasu Dev if (unlikely(!fps->thread)) { 1512a703e490SVasu Dev /* 1513a703e490SVasu Dev * The targeted CPU is not ready, let's target 1514a703e490SVasu Dev * the first CPU now. For non-SMP systems this 1515a703e490SVasu Dev * will check the same CPU twice. 1516a703e490SVasu Dev */ 15171875f27eSRobert Love FCOE_NETDEV_DBG(netdev, "CPU is online, but no receive thread " 1518d5488eb9SRobert Love "ready for incoming skb- using first online " 1519d5488eb9SRobert Love "CPU.\n"); 1520a703e490SVasu Dev 152194aa29f2SNeil Horman spin_unlock(&fps->fcoe_rx_list.lock); 15226957177fSRusty Russell cpu = cpumask_first(cpu_online_mask); 1523a703e490SVasu Dev fps = &per_cpu(fcoe_percpu, cpu); 152494aa29f2SNeil Horman spin_lock(&fps->fcoe_rx_list.lock); 1525a703e490SVasu Dev if (!fps->thread) { 152694aa29f2SNeil Horman spin_unlock(&fps->fcoe_rx_list.lock); 1527a703e490SVasu Dev goto err; 1528a703e490SVasu Dev } 1529a703e490SVasu Dev } 1530a703e490SVasu Dev 1531a703e490SVasu Dev /* 1532a703e490SVasu Dev * We now have a valid CPU that we're targeting for 1533a703e490SVasu Dev * this skb. We also have this receive thread locked, 1534a703e490SVasu Dev * so we're free to queue skbs into it's queue. 1535a703e490SVasu Dev */ 1536859b7b64SChris Leech 15375e70c4c4SNeil Horman /* 15385e70c4c4SNeil Horman * Note: We used to have a set of conditions under which we would 15395e70c4c4SNeil Horman * call fcoe_recv_frame directly, rather than queuing to the rx list 15405e70c4c4SNeil Horman * as it could save a few cycles, but doing so is prohibited, as 15415e70c4c4SNeil Horman * fcoe_recv_frame has several paths that may sleep, which is forbidden 15425e70c4c4SNeil Horman * in softirq context. 1543859b7b64SChris Leech */ 1544a703e490SVasu Dev __skb_queue_tail(&fps->fcoe_rx_list, skb); 154520dc3811SNeil Horman if (fps->thread->state == TASK_INTERRUPTIBLE) 1546a703e490SVasu Dev wake_up_process(fps->thread); 154794aa29f2SNeil Horman spin_unlock(&fps->fcoe_rx_list.lock); 1548a703e490SVasu Dev 154934bac2efSNeil Horman return NET_RX_SUCCESS; 1550a703e490SVasu Dev err: 15511bd49b48SVasu Dev per_cpu_ptr(lport->stats, get_cpu())->ErrorFrames++; 1552f018b73aSJoe Eykholt put_cpu(); 1553a703e490SVasu Dev err2: 1554a703e490SVasu Dev kfree_skb(skb); 155534bac2efSNeil Horman return NET_RX_DROP; 1556a703e490SVasu Dev } 1557a703e490SVasu Dev 1558a703e490SVasu Dev /** 15598597ae8bSBhanu Prakash Gollapudi * fcoe_alloc_paged_crc_eof() - Allocate a page to be used for the trailer CRC 15601875f27eSRobert Love * @skb: The packet to be transmitted 15611875f27eSRobert Love * @tlen: The total length of the trailer 15621875f27eSRobert Love * 1563a703e490SVasu Dev * Returns: 0 for success 1564a703e490SVasu Dev */ 15658597ae8bSBhanu Prakash Gollapudi static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen) 1566a703e490SVasu Dev { 1567a703e490SVasu Dev struct fcoe_percpu_s *fps; 15688597ae8bSBhanu Prakash Gollapudi int rc; 1569a703e490SVasu Dev 1570a703e490SVasu Dev fps = &get_cpu_var(fcoe_percpu); 15718597ae8bSBhanu Prakash Gollapudi rc = fcoe_get_paged_crc_eof(skb, tlen, fps); 1572a703e490SVasu Dev put_cpu_var(fcoe_percpu); 1573a703e490SVasu Dev 15748597ae8bSBhanu Prakash Gollapudi return rc; 1575a703e490SVasu Dev } 1576a703e490SVasu Dev 1577a703e490SVasu Dev /** 15781875f27eSRobert Love * fcoe_xmit() - Transmit a FCoE frame 15791875f27eSRobert Love * @lport: The local port that the frame is to be transmitted for 15801875f27eSRobert Love * @fp: The frame to be transmitted 1581a703e490SVasu Dev * 1582a703e490SVasu Dev * Return: 0 for success 1583a703e490SVasu Dev */ 15847c9c6841SBart Van Assche static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) 1585a703e490SVasu Dev { 15864bb6b515SVasu Dev int wlen; 1587a703e490SVasu Dev u32 crc; 1588a703e490SVasu Dev struct ethhdr *eh; 1589a703e490SVasu Dev struct fcoe_crc_eof *cp; 1590a703e490SVasu Dev struct sk_buff *skb; 15911bd49b48SVasu Dev struct fc_stats *stats; 1592a703e490SVasu Dev struct fc_frame_header *fh; 1593a703e490SVasu Dev unsigned int hlen; /* header length implies the version */ 1594a703e490SVasu Dev unsigned int tlen; /* trailer length */ 1595a703e490SVasu Dev unsigned int elen; /* eth header, may include vlan */ 15961875f27eSRobert Love struct fcoe_port *port = lport_priv(lport); 15978597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 1598619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 1599a703e490SVasu Dev u8 sof, eof; 1600a703e490SVasu Dev struct fcoe_hdr *hp; 1601a703e490SVasu Dev 1602a703e490SVasu Dev WARN_ON((fr_len(fp) % sizeof(u32)) != 0); 1603a703e490SVasu Dev 1604a703e490SVasu Dev fh = fc_frame_header_get(fp); 160597c8389dSJoe Eykholt skb = fp_skb(fp); 160697c8389dSJoe Eykholt wlen = skb->len / FCOE_WORD_TO_BYTE; 160797c8389dSJoe Eykholt 16081875f27eSRobert Love if (!lport->link_up) { 16093caf02eeSDan Carpenter kfree_skb(skb); 161097c8389dSJoe Eykholt return 0; 1611a703e490SVasu Dev } 1612a703e490SVasu Dev 16139860eeb4SJoe Eykholt if (unlikely(fh->fh_type == FC_TYPE_ELS) && 1614619fe4beSRobert Love fcoe_ctlr_els_send(ctlr, lport, skb)) 161597c8389dSJoe Eykholt return 0; 161697c8389dSJoe Eykholt 1617a703e490SVasu Dev sof = fr_sof(fp); 1618a703e490SVasu Dev eof = fr_eof(fp); 1619a703e490SVasu Dev 16204e57e1cbSVasu Dev elen = sizeof(struct ethhdr); 1621a703e490SVasu Dev hlen = sizeof(struct fcoe_hdr); 1622a703e490SVasu Dev tlen = sizeof(struct fcoe_crc_eof); 1623a703e490SVasu Dev wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; 1624a703e490SVasu Dev 1625a703e490SVasu Dev /* crc offload */ 16261875f27eSRobert Love if (likely(lport->crc_offload)) { 1627cf64bc8fSYi Zou skb->ip_summed = CHECKSUM_UNNECESSARY; 1628a703e490SVasu Dev skb->csum_start = skb_headroom(skb); 1629a703e490SVasu Dev skb->csum_offset = skb->len; 1630a703e490SVasu Dev crc = 0; 1631a703e490SVasu Dev } else { 1632a703e490SVasu Dev skb->ip_summed = CHECKSUM_NONE; 1633a703e490SVasu Dev crc = fcoe_fc_crc(fp); 1634a703e490SVasu Dev } 1635a703e490SVasu Dev 1636014f5c3fSChris Leech /* copy port crc and eof to the skb buff */ 1637a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 1638a703e490SVasu Dev skb_frag_t *frag; 16398597ae8bSBhanu Prakash Gollapudi if (fcoe_alloc_paged_crc_eof(skb, tlen)) { 1640a703e490SVasu Dev kfree_skb(skb); 1641a703e490SVasu Dev return -ENOMEM; 1642a703e490SVasu Dev } 1643a703e490SVasu Dev frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; 164477dfce07SCong Wang cp = kmap_atomic(skb_frag_page(frag)) 1645a703e490SVasu Dev + frag->page_offset; 1646a703e490SVasu Dev } else { 1647a703e490SVasu Dev cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); 1648a703e490SVasu Dev } 1649a703e490SVasu Dev 1650a703e490SVasu Dev memset(cp, 0, sizeof(*cp)); 1651a703e490SVasu Dev cp->fcoe_eof = eof; 1652a703e490SVasu Dev cp->fcoe_crc32 = cpu_to_le32(~crc); 1653a703e490SVasu Dev 1654a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 165577dfce07SCong Wang kunmap_atomic(cp); 1656a703e490SVasu Dev cp = NULL; 1657a703e490SVasu Dev } 1658a703e490SVasu Dev 1659014f5c3fSChris Leech /* adjust skb network/transport offsets to match mac/fcoe/port */ 1660a703e490SVasu Dev skb_push(skb, elen + hlen); 1661a703e490SVasu Dev skb_reset_mac_header(skb); 1662a703e490SVasu Dev skb_reset_network_header(skb); 1663a703e490SVasu Dev skb->mac_len = elen; 1664a703e490SVasu Dev skb->protocol = htons(ETH_P_FCOE); 166531c37a6fSNeerav Parikh skb->priority = fcoe->priority; 16666f6c2aa3Sjohn fastabend 1667d1483bb9SVasu Dev if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN && 1668f646968fSPatrick McHardy fcoe->realdev->features & NETIF_F_HW_VLAN_CTAG_TX) { 16692884d423SRobert Love /* must set skb->dev before calling vlan_put_tag */ 1670d1483bb9SVasu Dev skb->dev = fcoe->realdev; 16712884d423SRobert Love skb = __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 16722884d423SRobert Love vlan_dev_vlan_id(fcoe->netdev)); 16732884d423SRobert Love if (!skb) 16742884d423SRobert Love return -ENOMEM; 1675d1483bb9SVasu Dev } else 16763fe9a0baSChris Leech skb->dev = fcoe->netdev; 1677a703e490SVasu Dev 1678a703e490SVasu Dev /* fill up mac and fcoe headers */ 1679a703e490SVasu Dev eh = eth_hdr(skb); 1680a703e490SVasu Dev eh->h_proto = htons(ETH_P_FCOE); 1681619fe4beSRobert Love memcpy(eh->h_dest, ctlr->dest_addr, ETH_ALEN); 1682619fe4beSRobert Love if (ctlr->map_dest) 1683cd229e42SJoe Eykholt memcpy(eh->h_dest + 3, fh->fh_d_id, 3); 1684a703e490SVasu Dev 1685619fe4beSRobert Love if (unlikely(ctlr->flogi_oxid != FC_XID_UNKNOWN)) 1686619fe4beSRobert Love memcpy(eh->h_source, ctlr->ctl_src_addr, ETH_ALEN); 1687a703e490SVasu Dev else 168811b56188SChris Leech memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); 1689a703e490SVasu Dev 1690a703e490SVasu Dev hp = (struct fcoe_hdr *)(eh + 1); 1691a703e490SVasu Dev memset(hp, 0, sizeof(*hp)); 1692a703e490SVasu Dev if (FC_FCOE_VER) 1693a703e490SVasu Dev FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); 1694a703e490SVasu Dev hp->fcoe_sof = sof; 1695a703e490SVasu Dev 1696a703e490SVasu Dev /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ 16971875f27eSRobert Love if (lport->seq_offload && fr_max_payload(fp)) { 1698a703e490SVasu Dev skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; 1699a703e490SVasu Dev skb_shinfo(skb)->gso_size = fr_max_payload(fp); 1700a703e490SVasu Dev } else { 1701a703e490SVasu Dev skb_shinfo(skb)->gso_type = 0; 1702a703e490SVasu Dev skb_shinfo(skb)->gso_size = 0; 1703a703e490SVasu Dev } 1704a703e490SVasu Dev /* update tx stats: regardless if LLD fails */ 17051bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 1706a703e490SVasu Dev stats->TxFrames++; 1707a703e490SVasu Dev stats->TxWords += wlen; 1708f018b73aSJoe Eykholt put_cpu(); 1709a703e490SVasu Dev 1710a703e490SVasu Dev /* send down to lld */ 17111875f27eSRobert Love fr_dev(fp) = lport; 1712980f5156SVasu Dev fcoe_port_send(port, skb); 1713a703e490SVasu Dev return 0; 1714a703e490SVasu Dev } 1715a703e490SVasu Dev 1716a703e490SVasu Dev /** 17171875f27eSRobert Love * fcoe_percpu_flush_done() - Indicate per-CPU queue flush completion 17181875f27eSRobert Love * @skb: The completed skb (argument required by destructor) 1719e7a51997SJoe Eykholt */ 1720e7a51997SJoe Eykholt static void fcoe_percpu_flush_done(struct sk_buff *skb) 1721e7a51997SJoe Eykholt { 1722e7a51997SJoe Eykholt complete(&fcoe_flush_completion); 1723e7a51997SJoe Eykholt } 1724e7a51997SJoe Eykholt 1725e7a51997SJoe Eykholt /** 172652ee8321SVasu Dev * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC 172752ee8321SVasu Dev * @lport: The local port the frame was received on 172852ee8321SVasu Dev * @fp: The received frame 172952ee8321SVasu Dev * 173052ee8321SVasu Dev * Return: 0 on passing filtering checks 173152ee8321SVasu Dev */ 173252ee8321SVasu Dev static inline int fcoe_filter_frames(struct fc_lport *lport, 173352ee8321SVasu Dev struct fc_frame *fp) 173452ee8321SVasu Dev { 1735619fe4beSRobert Love struct fcoe_ctlr *ctlr; 173652ee8321SVasu Dev struct fcoe_interface *fcoe; 173752ee8321SVasu Dev struct fc_frame_header *fh; 173852ee8321SVasu Dev struct sk_buff *skb = (struct sk_buff *)fp; 17391bd49b48SVasu Dev struct fc_stats *stats; 174052ee8321SVasu Dev 174152ee8321SVasu Dev /* 174252ee8321SVasu Dev * We only check CRC if no offload is available and if it is 174352ee8321SVasu Dev * it's solicited data, in which case, the FCP layer would 174452ee8321SVasu Dev * check it during the copy. 174552ee8321SVasu Dev */ 174652ee8321SVasu Dev if (lport->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY) 174752ee8321SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 174852ee8321SVasu Dev else 174952ee8321SVasu Dev fr_flags(fp) |= FCPHF_CRC_UNCHECKED; 175052ee8321SVasu Dev 175152ee8321SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 175252ee8321SVasu Dev fh = fc_frame_header_get(fp); 175352ee8321SVasu Dev if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) 175452ee8321SVasu Dev return 0; 175552ee8321SVasu Dev 17568597ae8bSBhanu Prakash Gollapudi fcoe = ((struct fcoe_port *)lport_priv(lport))->priv; 1757619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1758619fe4beSRobert Love if (is_fip_mode(ctlr) && fc_frame_payload_op(fp) == ELS_LOGO && 175952ee8321SVasu Dev ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { 176052ee8321SVasu Dev FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n"); 176152ee8321SVasu Dev return -EINVAL; 176252ee8321SVasu Dev } 176352ee8321SVasu Dev 1764f2f96d20SDan Carpenter if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED) || 176552ee8321SVasu Dev le32_to_cpu(fr_crc(fp)) == ~crc32(~0, skb->data, skb->len)) { 176652ee8321SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 176752ee8321SVasu Dev return 0; 176852ee8321SVasu Dev } 176952ee8321SVasu Dev 17701bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 177152ee8321SVasu Dev stats->InvalidCRCCount++; 177252ee8321SVasu Dev if (stats->InvalidCRCCount < 5) 177352ee8321SVasu Dev printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); 17747e1e7eadSThomas Gleixner put_cpu(); 177552ee8321SVasu Dev return -EINVAL; 177652ee8321SVasu Dev } 177752ee8321SVasu Dev 177852ee8321SVasu Dev /** 1779859b7b64SChris Leech * fcoe_recv_frame() - process a single received frame 1780859b7b64SChris Leech * @skb: frame to process 1781a703e490SVasu Dev */ 1782859b7b64SChris Leech static void fcoe_recv_frame(struct sk_buff *skb) 1783a703e490SVasu Dev { 1784a703e490SVasu Dev u32 fr_len; 17851875f27eSRobert Love struct fc_lport *lport; 1786a703e490SVasu Dev struct fcoe_rcv_info *fr; 17871bd49b48SVasu Dev struct fc_stats *stats; 1788a703e490SVasu Dev struct fcoe_crc_eof crc_eof; 1789a703e490SVasu Dev struct fc_frame *fp; 1790014f5c3fSChris Leech struct fcoe_port *port; 1791a703e490SVasu Dev struct fcoe_hdr *hp; 1792a703e490SVasu Dev 1793a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 17941875f27eSRobert Love lport = fr->fr_dev; 17951875f27eSRobert Love if (unlikely(!lport)) { 1796e7a51997SJoe Eykholt if (skb->destructor != fcoe_percpu_flush_done) 1797465b87bfSBart Van Assche FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb\n"); 1798a703e490SVasu Dev kfree_skb(skb); 1799859b7b64SChris Leech return; 1800a703e490SVasu Dev } 1801a703e490SVasu Dev 1802465b87bfSBart Van Assche FCOE_NETDEV_DBG(skb->dev, 1803465b87bfSBart Van Assche "skb_info: len:%d data_len:%d head:%p data:%p tail:%p end:%p sum:%d dev:%s\n", 1804a703e490SVasu Dev skb->len, skb->data_len, 1805a703e490SVasu Dev skb->head, skb->data, skb_tail_pointer(skb), 1806a703e490SVasu Dev skb_end_pointer(skb), skb->csum, 1807a703e490SVasu Dev skb->dev ? skb->dev->name : "<NULL>"); 1808a703e490SVasu Dev 18091875f27eSRobert Love port = lport_priv(lport); 1810f1633011SRobert Love skb_linearize(skb); /* check for skb_is_nonlinear is within skb_linearize */ 1811a703e490SVasu Dev 1812a703e490SVasu Dev /* 1813a703e490SVasu Dev * Frame length checks and setting up the header pointers 1814a703e490SVasu Dev * was done in fcoe_rcv already. 1815a703e490SVasu Dev */ 1816a703e490SVasu Dev hp = (struct fcoe_hdr *) skb_network_header(skb); 1817a703e490SVasu Dev 18181bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 1819a703e490SVasu Dev if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { 1820a703e490SVasu Dev if (stats->ErrorFrames < 5) 1821d5488eb9SRobert Love printk(KERN_WARNING "fcoe: FCoE version " 1822a703e490SVasu Dev "mismatch: The frame has " 1823a703e490SVasu Dev "version %x, but the " 1824a703e490SVasu Dev "initiator supports version " 1825a703e490SVasu Dev "%x\n", FC_FCOE_DECAPS_VER(hp), 1826a703e490SVasu Dev FC_FCOE_VER); 1827f018b73aSJoe Eykholt goto drop; 1828a703e490SVasu Dev } 1829a703e490SVasu Dev 1830a703e490SVasu Dev skb_pull(skb, sizeof(struct fcoe_hdr)); 1831a703e490SVasu Dev fr_len = skb->len - sizeof(struct fcoe_crc_eof); 1832a703e490SVasu Dev 1833a703e490SVasu Dev stats->RxFrames++; 1834a703e490SVasu Dev stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; 1835a703e490SVasu Dev 1836a703e490SVasu Dev fp = (struct fc_frame *)skb; 1837a703e490SVasu Dev fc_frame_init(fp); 18381875f27eSRobert Love fr_dev(fp) = lport; 1839a703e490SVasu Dev fr_sof(fp) = hp->fcoe_sof; 1840a703e490SVasu Dev 1841a703e490SVasu Dev /* Copy out the CRC and EOF trailer for access */ 1842f018b73aSJoe Eykholt if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) 1843f018b73aSJoe Eykholt goto drop; 1844a703e490SVasu Dev fr_eof(fp) = crc_eof.fcoe_eof; 1845a703e490SVasu Dev fr_crc(fp) = crc_eof.fcoe_crc32; 1846f018b73aSJoe Eykholt if (pskb_trim(skb, fr_len)) 1847f018b73aSJoe Eykholt goto drop; 1848a703e490SVasu Dev 184952ee8321SVasu Dev if (!fcoe_filter_frames(lport, fp)) { 1850f018b73aSJoe Eykholt put_cpu(); 18511875f27eSRobert Love fc_exch_recv(lport, fp); 1852f018b73aSJoe Eykholt return; 185352ee8321SVasu Dev } 1854f018b73aSJoe Eykholt drop: 1855f018b73aSJoe Eykholt stats->ErrorFrames++; 1856f018b73aSJoe Eykholt put_cpu(); 1857f018b73aSJoe Eykholt kfree_skb(skb); 1858a703e490SVasu Dev } 1859859b7b64SChris Leech 1860859b7b64SChris Leech /** 1861859b7b64SChris Leech * fcoe_percpu_receive_thread() - The per-CPU packet receive thread 1862859b7b64SChris Leech * @arg: The per-CPU context 1863859b7b64SChris Leech * 1864859b7b64SChris Leech * Return: 0 for success 1865859b7b64SChris Leech */ 18667c9c6841SBart Van Assche static int fcoe_percpu_receive_thread(void *arg) 1867859b7b64SChris Leech { 1868859b7b64SChris Leech struct fcoe_percpu_s *p = arg; 1869859b7b64SChris Leech struct sk_buff *skb; 187020dc3811SNeil Horman struct sk_buff_head tmp; 187120dc3811SNeil Horman 187220dc3811SNeil Horman skb_queue_head_init(&tmp); 1873859b7b64SChris Leech 1874859b7b64SChris Leech set_user_nice(current, -20); 1875859b7b64SChris Leech 187695fdd5e9SNeil Horman retry: 1877859b7b64SChris Leech while (!kthread_should_stop()) { 1878859b7b64SChris Leech 1879859b7b64SChris Leech spin_lock_bh(&p->fcoe_rx_list.lock); 188020dc3811SNeil Horman skb_queue_splice_init(&p->fcoe_rx_list, &tmp); 188195fdd5e9SNeil Horman 188295fdd5e9SNeil Horman if (!skb_queue_len(&tmp)) { 188395fdd5e9SNeil Horman set_current_state(TASK_INTERRUPTIBLE); 188495fdd5e9SNeil Horman spin_unlock_bh(&p->fcoe_rx_list.lock); 188595fdd5e9SNeil Horman schedule(); 188695fdd5e9SNeil Horman set_current_state(TASK_RUNNING); 188795fdd5e9SNeil Horman goto retry; 188895fdd5e9SNeil Horman } 188995fdd5e9SNeil Horman 189020dc3811SNeil Horman spin_unlock_bh(&p->fcoe_rx_list.lock); 189120dc3811SNeil Horman 189220dc3811SNeil Horman while ((skb = __skb_dequeue(&tmp)) != NULL) 189320dc3811SNeil Horman fcoe_recv_frame(skb); 189420dc3811SNeil Horman 1895859b7b64SChris Leech } 1896a703e490SVasu Dev return 0; 1897a703e490SVasu Dev } 1898a703e490SVasu Dev 1899a703e490SVasu Dev /** 19001875f27eSRobert Love * fcoe_dev_setup() - Setup the link change notification interface 1901a703e490SVasu Dev */ 1902b0d428adSRandy Dunlap static void fcoe_dev_setup(void) 1903a703e490SVasu Dev { 19046f6c2aa3Sjohn fastabend register_dcbevent_notifier(&dcb_notifier); 1905a703e490SVasu Dev register_netdevice_notifier(&fcoe_notifier); 1906a703e490SVasu Dev } 1907a703e490SVasu Dev 1908a703e490SVasu Dev /** 19091875f27eSRobert Love * fcoe_dev_cleanup() - Cleanup the link change notification interface 1910a703e490SVasu Dev */ 1911a703e490SVasu Dev static void fcoe_dev_cleanup(void) 1912a703e490SVasu Dev { 19136f6c2aa3Sjohn fastabend unregister_dcbevent_notifier(&dcb_notifier); 1914a703e490SVasu Dev unregister_netdevice_notifier(&fcoe_notifier); 1915a703e490SVasu Dev } 1916a703e490SVasu Dev 19176f6c2aa3Sjohn fastabend static struct fcoe_interface * 19186f6c2aa3Sjohn fastabend fcoe_hostlist_lookup_realdev_port(struct net_device *netdev) 19196f6c2aa3Sjohn fastabend { 19206f6c2aa3Sjohn fastabend struct fcoe_interface *fcoe; 19216f6c2aa3Sjohn fastabend struct net_device *real_dev; 19226f6c2aa3Sjohn fastabend 19236f6c2aa3Sjohn fastabend list_for_each_entry(fcoe, &fcoe_hostlist, list) { 19246f6c2aa3Sjohn fastabend if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) 19256f6c2aa3Sjohn fastabend real_dev = vlan_dev_real_dev(fcoe->netdev); 19266f6c2aa3Sjohn fastabend else 19276f6c2aa3Sjohn fastabend real_dev = fcoe->netdev; 19286f6c2aa3Sjohn fastabend 19296f6c2aa3Sjohn fastabend if (netdev == real_dev) 19306f6c2aa3Sjohn fastabend return fcoe; 19316f6c2aa3Sjohn fastabend } 19326f6c2aa3Sjohn fastabend return NULL; 19336f6c2aa3Sjohn fastabend } 19346f6c2aa3Sjohn fastabend 19356f6c2aa3Sjohn fastabend static int fcoe_dcb_app_notification(struct notifier_block *notifier, 19366f6c2aa3Sjohn fastabend ulong event, void *ptr) 19376f6c2aa3Sjohn fastabend { 19386f6c2aa3Sjohn fastabend struct dcb_app_type *entry = ptr; 1939619fe4beSRobert Love struct fcoe_ctlr *ctlr; 19406f6c2aa3Sjohn fastabend struct fcoe_interface *fcoe; 19416f6c2aa3Sjohn fastabend struct net_device *netdev; 19426f6c2aa3Sjohn fastabend int prio; 19436f6c2aa3Sjohn fastabend 19446f6c2aa3Sjohn fastabend if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) 19456f6c2aa3Sjohn fastabend return NOTIFY_OK; 19466f6c2aa3Sjohn fastabend 19476f6c2aa3Sjohn fastabend netdev = dev_get_by_index(&init_net, entry->ifindex); 19486f6c2aa3Sjohn fastabend if (!netdev) 19496f6c2aa3Sjohn fastabend return NOTIFY_OK; 19506f6c2aa3Sjohn fastabend 19516f6c2aa3Sjohn fastabend fcoe = fcoe_hostlist_lookup_realdev_port(netdev); 19526f6c2aa3Sjohn fastabend dev_put(netdev); 19536f6c2aa3Sjohn fastabend if (!fcoe) 19546f6c2aa3Sjohn fastabend return NOTIFY_OK; 19556f6c2aa3Sjohn fastabend 1956619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1957619fe4beSRobert Love 19586f6c2aa3Sjohn fastabend if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) 19596f6c2aa3Sjohn fastabend prio = ffs(entry->app.priority) - 1; 19606f6c2aa3Sjohn fastabend else 19616f6c2aa3Sjohn fastabend prio = entry->app.priority; 19626f6c2aa3Sjohn fastabend 19636f6c2aa3Sjohn fastabend if (prio < 0) 19646f6c2aa3Sjohn fastabend return NOTIFY_OK; 19656f6c2aa3Sjohn fastabend 19666f6c2aa3Sjohn fastabend if (entry->app.protocol == ETH_P_FIP || 19676f6c2aa3Sjohn fastabend entry->app.protocol == ETH_P_FCOE) 1968619fe4beSRobert Love ctlr->priority = prio; 19696f6c2aa3Sjohn fastabend 197031c37a6fSNeerav Parikh if (entry->app.protocol == ETH_P_FCOE) 197131c37a6fSNeerav Parikh fcoe->priority = prio; 19726f6c2aa3Sjohn fastabend 19736f6c2aa3Sjohn fastabend return NOTIFY_OK; 19746f6c2aa3Sjohn fastabend } 19756f6c2aa3Sjohn fastabend 1976a703e490SVasu Dev /** 19771875f27eSRobert Love * fcoe_device_notification() - Handler for net device events 19781875f27eSRobert Love * @notifier: The context of the notification 19791875f27eSRobert Love * @event: The type of event 19801875f27eSRobert Love * @ptr: The net device that the event was on 1981a703e490SVasu Dev * 19821875f27eSRobert Love * This function is called by the Ethernet driver in case of link change event. 1983a703e490SVasu Dev * 1984a703e490SVasu Dev * Returns: 0 for success 1985a703e490SVasu Dev */ 1986a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *notifier, 1987a703e490SVasu Dev ulong event, void *ptr) 1988a703e490SVasu Dev { 1989435c8667SRobert Love struct fcoe_ctlr_device *cdev; 19901875f27eSRobert Love struct fc_lport *lport = NULL; 1991351638e7SJiri Pirko struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 1992619fe4beSRobert Love struct fcoe_ctlr *ctlr; 1993014f5c3fSChris Leech struct fcoe_interface *fcoe; 19942e70e241SChris Leech struct fcoe_port *port; 19951bd49b48SVasu Dev struct fc_stats *stats; 199697c8389dSJoe Eykholt u32 link_possible = 1; 1997a703e490SVasu Dev u32 mfs; 1998a703e490SVasu Dev int rc = NOTIFY_OK; 1999a703e490SVasu Dev 2000014f5c3fSChris Leech list_for_each_entry(fcoe, &fcoe_hostlist, list) { 200125024989SChris Leech if (fcoe->netdev == netdev) { 2002619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2003619fe4beSRobert Love lport = ctlr->lp; 2004a703e490SVasu Dev break; 2005a703e490SVasu Dev } 2006a703e490SVasu Dev } 20071875f27eSRobert Love if (!lport) { 2008a703e490SVasu Dev rc = NOTIFY_DONE; 2009a703e490SVasu Dev goto out; 2010a703e490SVasu Dev } 2011a703e490SVasu Dev 2012a703e490SVasu Dev switch (event) { 2013a703e490SVasu Dev case NETDEV_DOWN: 2014a703e490SVasu Dev case NETDEV_GOING_DOWN: 201597c8389dSJoe Eykholt link_possible = 0; 2016a703e490SVasu Dev break; 2017a703e490SVasu Dev case NETDEV_UP: 2018a703e490SVasu Dev case NETDEV_CHANGE: 2019a703e490SVasu Dev break; 2020a703e490SVasu Dev case NETDEV_CHANGEMTU: 20217221d7e5SYi Zou if (netdev->features & NETIF_F_FCOE_MTU) 20227221d7e5SYi Zou break; 20231d1b88dcSVasu Dev mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + 2024a703e490SVasu Dev sizeof(struct fcoe_crc_eof)); 2025a703e490SVasu Dev if (mfs >= FC_MIN_MAX_FRAME) 20261875f27eSRobert Love fc_set_mfs(lport, mfs); 2027a703e490SVasu Dev break; 2028a703e490SVasu Dev case NETDEV_REGISTER: 2029a703e490SVasu Dev break; 20302e70e241SChris Leech case NETDEV_UNREGISTER: 20312e70e241SChris Leech list_del(&fcoe->list); 2032619fe4beSRobert Love port = lport_priv(ctlr->lp); 20332ca32b48STejun Heo queue_work(fcoe_wq, &port->destroy_work); 20342e70e241SChris Leech goto out; 20352e70e241SChris Leech break; 203654a5b21dSYi Zou case NETDEV_FEAT_CHANGE: 203754a5b21dSYi Zou fcoe_netdev_features_change(lport, netdev); 203854a5b21dSYi Zou break; 2039a703e490SVasu Dev default: 20401d1b88dcSVasu Dev FCOE_NETDEV_DBG(netdev, "Unknown event %ld " 2041d5488eb9SRobert Love "from netdev netlink\n", event); 2042a703e490SVasu Dev } 20435e4f8fe7SRobert Love 20445e4f8fe7SRobert Love fcoe_link_speed_update(lport); 20455e4f8fe7SRobert Love 2046435c8667SRobert Love cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2047435c8667SRobert Love 2048435c8667SRobert Love if (link_possible && !fcoe_link_ok(lport)) { 2049435c8667SRobert Love switch (cdev->enabled) { 2050435c8667SRobert Love case FCOE_CTLR_DISABLED: 2051435c8667SRobert Love pr_info("Link up while interface is disabled.\n"); 2052435c8667SRobert Love break; 2053435c8667SRobert Love case FCOE_CTLR_ENABLED: 2054435c8667SRobert Love case FCOE_CTLR_UNUSED: 2055619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2056435c8667SRobert Love }; 2057435c8667SRobert Love } else if (fcoe_ctlr_link_down(ctlr)) { 2058435c8667SRobert Love switch (cdev->enabled) { 2059435c8667SRobert Love case FCOE_CTLR_DISABLED: 2060435c8667SRobert Love pr_info("Link down while interface is disabled.\n"); 2061435c8667SRobert Love break; 2062435c8667SRobert Love case FCOE_CTLR_ENABLED: 2063435c8667SRobert Love case FCOE_CTLR_UNUSED: 20641bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 2065a703e490SVasu Dev stats->LinkFailureCount++; 2066f018b73aSJoe Eykholt put_cpu(); 20671875f27eSRobert Love fcoe_clean_pending_queue(lport); 2068435c8667SRobert Love }; 2069a703e490SVasu Dev } 2070a703e490SVasu Dev out: 2071a703e490SVasu Dev return rc; 2072a703e490SVasu Dev } 2073a703e490SVasu Dev 2074a703e490SVasu Dev /** 207555a66d3cSVasu Dev * fcoe_disable() - Disables a FCoE interface 207678a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 207755a66d3cSVasu Dev * 207878a58246SYi Zou * Called from fcoe transport. 207955a66d3cSVasu Dev * 208055a66d3cSVasu Dev * Returns: 0 for success 2081435c8667SRobert Love * 2082435c8667SRobert Love * Deprecated: use fcoe_ctlr_enabled() 208355a66d3cSVasu Dev */ 208478a58246SYi Zou static int fcoe_disable(struct net_device *netdev) 208555a66d3cSVasu Dev { 2086619fe4beSRobert Love struct fcoe_ctlr *ctlr; 208755a66d3cSVasu Dev struct fcoe_interface *fcoe; 208855a66d3cSVasu Dev int rc = 0; 208955a66d3cSVasu Dev 209055a66d3cSVasu Dev mutex_lock(&fcoe_config_mutex); 209155a66d3cSVasu Dev 2092ee5df628SRobert Love rtnl_lock(); 209355a66d3cSVasu Dev fcoe = fcoe_hostlist_lookup_port(netdev); 209455a66d3cSVasu Dev rtnl_unlock(); 209555a66d3cSVasu Dev 20969ee50e48SChris Leech if (fcoe) { 2097619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2098619fe4beSRobert Love fcoe_ctlr_link_down(ctlr); 2099619fe4beSRobert Love fcoe_clean_pending_queue(ctlr->lp); 21009ee50e48SChris Leech } else 210155a66d3cSVasu Dev rc = -ENODEV; 210255a66d3cSVasu Dev 210355a66d3cSVasu Dev mutex_unlock(&fcoe_config_mutex); 210455a66d3cSVasu Dev return rc; 210555a66d3cSVasu Dev } 210655a66d3cSVasu Dev 210755a66d3cSVasu Dev /** 210855a66d3cSVasu Dev * fcoe_enable() - Enables a FCoE interface 210978a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 211055a66d3cSVasu Dev * 211178a58246SYi Zou * Called from fcoe transport. 211255a66d3cSVasu Dev * 211355a66d3cSVasu Dev * Returns: 0 for success 211455a66d3cSVasu Dev */ 211578a58246SYi Zou static int fcoe_enable(struct net_device *netdev) 211655a66d3cSVasu Dev { 2117619fe4beSRobert Love struct fcoe_ctlr *ctlr; 211855a66d3cSVasu Dev struct fcoe_interface *fcoe; 211955a66d3cSVasu Dev int rc = 0; 212055a66d3cSVasu Dev 212155a66d3cSVasu Dev mutex_lock(&fcoe_config_mutex); 2122ee5df628SRobert Love rtnl_lock(); 212355a66d3cSVasu Dev fcoe = fcoe_hostlist_lookup_port(netdev); 212455a66d3cSVasu Dev rtnl_unlock(); 212555a66d3cSVasu Dev 2126619fe4beSRobert Love if (!fcoe) { 212755a66d3cSVasu Dev rc = -ENODEV; 2128619fe4beSRobert Love goto out; 2129619fe4beSRobert Love } 213055a66d3cSVasu Dev 2131619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2132619fe4beSRobert Love 2133619fe4beSRobert Love if (!fcoe_link_ok(ctlr->lp)) 2134619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2135619fe4beSRobert Love 2136619fe4beSRobert Love out: 213755a66d3cSVasu Dev mutex_unlock(&fcoe_config_mutex); 213855a66d3cSVasu Dev return rc; 213955a66d3cSVasu Dev } 214055a66d3cSVasu Dev 214155a66d3cSVasu Dev /** 2142435c8667SRobert Love * fcoe_ctlr_enabled() - Enable or disable an FCoE Controller 2143435c8667SRobert Love * @cdev: The FCoE Controller that is being enabled or disabled 2144435c8667SRobert Love * 2145435c8667SRobert Love * fcoe_sysfs will ensure that the state of 'enabled' has 2146435c8667SRobert Love * changed, so no checking is necessary here. This routine simply 2147435c8667SRobert Love * calls fcoe_enable or fcoe_disable, both of which are deprecated. 2148435c8667SRobert Love * When those routines are removed the functionality can be merged 2149435c8667SRobert Love * here. 2150435c8667SRobert Love */ 2151435c8667SRobert Love static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev) 2152435c8667SRobert Love { 2153435c8667SRobert Love struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(cdev); 2154435c8667SRobert Love struct fc_lport *lport = ctlr->lp; 2155435c8667SRobert Love struct net_device *netdev = fcoe_netdev(lport); 2156435c8667SRobert Love 2157435c8667SRobert Love switch (cdev->enabled) { 2158435c8667SRobert Love case FCOE_CTLR_ENABLED: 2159435c8667SRobert Love return fcoe_enable(netdev); 2160435c8667SRobert Love case FCOE_CTLR_DISABLED: 2161435c8667SRobert Love return fcoe_disable(netdev); 2162435c8667SRobert Love case FCOE_CTLR_UNUSED: 2163435c8667SRobert Love default: 2164435c8667SRobert Love return -ENOTSUPP; 2165435c8667SRobert Love }; 2166435c8667SRobert Love } 2167435c8667SRobert Love 2168435c8667SRobert Love /** 21691875f27eSRobert Love * fcoe_destroy() - Destroy a FCoE interface 217078a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 21711875f27eSRobert Love * 217278a58246SYi Zou * Called from fcoe transport 2173a703e490SVasu Dev * 2174a703e490SVasu Dev * Returns: 0 for success 2175a703e490SVasu Dev */ 217678a58246SYi Zou static int fcoe_destroy(struct net_device *netdev) 2177a703e490SVasu Dev { 2178619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2179030f4e00SChris Leech struct fcoe_interface *fcoe; 2180f04ca1b6SVasu Dev struct fc_lport *lport; 2181b2085a4eSNeerav Parikh struct fcoe_port *port; 21828eca355fSMike Christie int rc = 0; 2183a703e490SVasu Dev 2184dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2185ee5df628SRobert Love rtnl_lock(); 21862e70e241SChris Leech fcoe = fcoe_hostlist_lookup_port(netdev); 21872e70e241SChris Leech if (!fcoe) { 2188a703e490SVasu Dev rc = -ENODEV; 218978a58246SYi Zou goto out_nodev; 2190a703e490SVasu Dev } 2191619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2192619fe4beSRobert Love lport = ctlr->lp; 2193b2085a4eSNeerav Parikh port = lport_priv(lport); 219454a5b21dSYi Zou list_del(&fcoe->list); 2195b2085a4eSNeerav Parikh queue_work(fcoe_wq, &port->destroy_work); 2196a703e490SVasu Dev out_nodev: 2197b2085a4eSNeerav Parikh rtnl_unlock(); 2198dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2199a703e490SVasu Dev return rc; 2200a703e490SVasu Dev } 2201a703e490SVasu Dev 22021875f27eSRobert Love /** 22031875f27eSRobert Love * fcoe_destroy_work() - Destroy a FCoE port in a deferred work context 22041875f27eSRobert Love * @work: Handle to the FCoE port to be destroyed 22051875f27eSRobert Love */ 22062e70e241SChris Leech static void fcoe_destroy_work(struct work_struct *work) 22072e70e241SChris Leech { 2208f9c4358eSRobert Love struct fcoe_ctlr_device *cdev; 2209f9c4358eSRobert Love struct fcoe_ctlr *ctlr; 22102e70e241SChris Leech struct fcoe_port *port; 2211b2085a4eSNeerav Parikh struct fcoe_interface *fcoe; 221294aa743aSNeerav Parikh struct Scsi_Host *shost; 221394aa743aSNeerav Parikh struct fc_host_attrs *fc_host; 221494aa743aSNeerav Parikh unsigned long flags; 221594aa743aSNeerav Parikh struct fc_vport *vport; 221694aa743aSNeerav Parikh struct fc_vport *next_vport; 22172e70e241SChris Leech 22182e70e241SChris Leech port = container_of(work, struct fcoe_port, destroy_work); 221994aa743aSNeerav Parikh shost = port->lport->host; 222094aa743aSNeerav Parikh fc_host = shost_to_fc_host(shost); 222194aa743aSNeerav Parikh 222294aa743aSNeerav Parikh /* Loop through all the vports and mark them for deletion */ 222394aa743aSNeerav Parikh spin_lock_irqsave(shost->host_lock, flags); 222494aa743aSNeerav Parikh list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) { 222594aa743aSNeerav Parikh if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) { 222694aa743aSNeerav Parikh continue; 222794aa743aSNeerav Parikh } else { 222894aa743aSNeerav Parikh vport->flags |= FC_VPORT_DELETING; 222994aa743aSNeerav Parikh queue_work(fc_host_work_q(shost), 223094aa743aSNeerav Parikh &vport->vport_delete_work); 223194aa743aSNeerav Parikh } 223294aa743aSNeerav Parikh } 223394aa743aSNeerav Parikh spin_unlock_irqrestore(shost->host_lock, flags); 223494aa743aSNeerav Parikh 223594aa743aSNeerav Parikh flush_workqueue(fc_host_work_q(shost)); 223694aa743aSNeerav Parikh 22372e70e241SChris Leech mutex_lock(&fcoe_config_mutex); 2238b2085a4eSNeerav Parikh 2239b2085a4eSNeerav Parikh fcoe = port->priv; 2240f9c4358eSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2241f9c4358eSRobert Love cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2242f9c4358eSRobert Love 22432e70e241SChris Leech fcoe_if_destroy(port->lport); 2244b2085a4eSNeerav Parikh fcoe_interface_cleanup(fcoe); 2245b2085a4eSNeerav Parikh 22462e70e241SChris Leech mutex_unlock(&fcoe_config_mutex); 2247f9c4358eSRobert Love 2248f9c4358eSRobert Love fcoe_ctlr_device_delete(cdev); 22492e70e241SChris Leech } 22502e70e241SChris Leech 2251a703e490SVasu Dev /** 225278a58246SYi Zou * fcoe_match() - Check if the FCoE is supported on the given netdevice 225378a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 22541875f27eSRobert Love * 225578a58246SYi Zou * Called from fcoe transport. 225678a58246SYi Zou * 225778a58246SYi Zou * Returns: always returns true as this is the default FCoE transport, 225878a58246SYi Zou * i.e., support all netdevs. 225978a58246SYi Zou */ 226078a58246SYi Zou static bool fcoe_match(struct net_device *netdev) 226178a58246SYi Zou { 226278a58246SYi Zou return true; 226378a58246SYi Zou } 226478a58246SYi Zou 226578a58246SYi Zou /** 22666f6c2aa3Sjohn fastabend * fcoe_dcb_create() - Initialize DCB attributes and hooks 22676f6c2aa3Sjohn fastabend * @netdev: The net_device object of the L2 link that should be queried 22686f6c2aa3Sjohn fastabend * @port: The fcoe_port to bind FCoE APP priority with 22696f6c2aa3Sjohn fastabend * @ 22706f6c2aa3Sjohn fastabend */ 22716f6c2aa3Sjohn fastabend static void fcoe_dcb_create(struct fcoe_interface *fcoe) 22726f6c2aa3Sjohn fastabend { 22736f6c2aa3Sjohn fastabend #ifdef CONFIG_DCB 22746f6c2aa3Sjohn fastabend int dcbx; 22756f6c2aa3Sjohn fastabend u8 fup, up; 22766f6c2aa3Sjohn fastabend struct net_device *netdev = fcoe->realdev; 2277619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 22786f6c2aa3Sjohn fastabend struct dcb_app app = { 22796f6c2aa3Sjohn fastabend .priority = 0, 22806f6c2aa3Sjohn fastabend .protocol = ETH_P_FCOE 22816f6c2aa3Sjohn fastabend }; 22826f6c2aa3Sjohn fastabend 22836f6c2aa3Sjohn fastabend /* setup DCB priority attributes. */ 22846f6c2aa3Sjohn fastabend if (netdev && netdev->dcbnl_ops && netdev->dcbnl_ops->getdcbx) { 22856f6c2aa3Sjohn fastabend dcbx = netdev->dcbnl_ops->getdcbx(netdev); 22866f6c2aa3Sjohn fastabend 22876f6c2aa3Sjohn fastabend if (dcbx & DCB_CAP_DCBX_VER_IEEE) { 22886f6c2aa3Sjohn fastabend app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; 22896f6c2aa3Sjohn fastabend up = dcb_ieee_getapp_mask(netdev, &app); 22906f6c2aa3Sjohn fastabend app.protocol = ETH_P_FIP; 22916f6c2aa3Sjohn fastabend fup = dcb_ieee_getapp_mask(netdev, &app); 22926f6c2aa3Sjohn fastabend } else { 22936f6c2aa3Sjohn fastabend app.selector = DCB_APP_IDTYPE_ETHTYPE; 22946f6c2aa3Sjohn fastabend up = dcb_getapp(netdev, &app); 22956f6c2aa3Sjohn fastabend app.protocol = ETH_P_FIP; 22966f6c2aa3Sjohn fastabend fup = dcb_getapp(netdev, &app); 22976f6c2aa3Sjohn fastabend } 22986f6c2aa3Sjohn fastabend 229931c37a6fSNeerav Parikh fcoe->priority = ffs(up) ? ffs(up) - 1 : 0; 230031c37a6fSNeerav Parikh ctlr->priority = ffs(fup) ? ffs(fup) - 1 : fcoe->priority; 23016f6c2aa3Sjohn fastabend } 23026f6c2aa3Sjohn fastabend #endif 23036f6c2aa3Sjohn fastabend } 23046f6c2aa3Sjohn fastabend 2305435c8667SRobert Love enum fcoe_create_link_state { 2306435c8667SRobert Love FCOE_CREATE_LINK_DOWN, 2307435c8667SRobert Love FCOE_CREATE_LINK_UP, 2308435c8667SRobert Love }; 2309435c8667SRobert Love 23106f6c2aa3Sjohn fastabend /** 2311435c8667SRobert Love * _fcoe_create() - (internal) Create a fcoe interface 231278a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 231378a58246SYi Zou * @fip_mode: The FIP mode for this creation 2314435c8667SRobert Love * @link_state: The ctlr link state on creation 231578a58246SYi Zou * 2316435c8667SRobert Love * Called from either the libfcoe 'create' module parameter 2317435c8667SRobert Love * via fcoe_create or from fcoe_syfs's ctlr_create file. 2318a703e490SVasu Dev * 2319435c8667SRobert Love * libfcoe's 'create' module parameter is deprecated so some 2320435c8667SRobert Love * consolidation of code can be done when that interface is 2321435c8667SRobert Love * removed. 2322a703e490SVasu Dev */ 2323435c8667SRobert Love static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode, 2324435c8667SRobert Love enum fcoe_create_link_state link_state) 2325a703e490SVasu Dev { 2326b2085a4eSNeerav Parikh int rc = 0; 23278d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev; 2328619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2329030f4e00SChris Leech struct fcoe_interface *fcoe; 2330af7f85d9SChris Leech struct fc_lport *lport; 2331a703e490SVasu Dev 2332dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2333ee5df628SRobert Love rtnl_lock(); 233434ce27bcSVasu Dev 2335a703e490SVasu Dev /* look for existing lport */ 2336a703e490SVasu Dev if (fcoe_hostlist_lookup(netdev)) { 2337a703e490SVasu Dev rc = -EEXIST; 233878a58246SYi Zou goto out_nodev; 2339a703e490SVasu Dev } 2340a703e490SVasu Dev 23411dd454d9SJoe Eykholt fcoe = fcoe_interface_create(netdev, fip_mode); 23427287fb91SRobert Love if (IS_ERR(fcoe)) { 23437287fb91SRobert Love rc = PTR_ERR(fcoe); 234478a58246SYi Zou goto out_nodev; 2345030f4e00SChris Leech } 2346030f4e00SChris Leech 2347619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 23488d55e507SRobert Love ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); 23498d55e507SRobert Love lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0); 2350af7f85d9SChris Leech if (IS_ERR(lport)) { 2351d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", 2352a703e490SVasu Dev netdev->name); 2353a703e490SVasu Dev rc = -EIO; 2354848e7d5bSRobert Love rtnl_unlock(); 23552e70e241SChris Leech fcoe_interface_cleanup(fcoe); 2356f9c4358eSRobert Love mutex_unlock(&fcoe_config_mutex); 2357f9c4358eSRobert Love fcoe_ctlr_device_delete(ctlr_dev); 2358f9c4358eSRobert Love goto out; 2359a703e490SVasu Dev } 2360030f4e00SChris Leech 236154b649f8SChris Leech /* Make this the "master" N_Port */ 2362619fe4beSRobert Love ctlr->lp = lport; 2363030f4e00SChris Leech 23646f6c2aa3Sjohn fastabend /* setup DCB priority attributes. */ 23656f6c2aa3Sjohn fastabend fcoe_dcb_create(fcoe); 23666f6c2aa3Sjohn fastabend 236754b649f8SChris Leech /* start FIP Discovery and FLOGI */ 236854b649f8SChris Leech lport->boot_time = jiffies; 236954b649f8SChris Leech fc_fabric_login(lport); 2370435c8667SRobert Love 2371435c8667SRobert Love /* 2372435c8667SRobert Love * If the fcoe_ctlr_device is to be set to DISABLED 2373435c8667SRobert Love * it must be done after the lport is added to the 2374435c8667SRobert Love * hostlist, but before the rtnl_lock is released. 2375435c8667SRobert Love * This is because the rtnl_lock protects the 2376435c8667SRobert Love * hostlist that fcoe_device_notification uses. If 2377435c8667SRobert Love * the FCoE Controller is intended to be created 2378435c8667SRobert Love * DISABLED then 'enabled' needs to be considered 2379435c8667SRobert Love * handling link events. 'enabled' must be set 2380435c8667SRobert Love * before the lport can be found in the hostlist 2381435c8667SRobert Love * when a link up event is received. 2382435c8667SRobert Love */ 2383435c8667SRobert Love if (link_state == FCOE_CREATE_LINK_UP) 2384435c8667SRobert Love ctlr_dev->enabled = FCOE_CTLR_ENABLED; 2385435c8667SRobert Love else 2386435c8667SRobert Love ctlr_dev->enabled = FCOE_CTLR_DISABLED; 2387435c8667SRobert Love 2388435c8667SRobert Love if (link_state == FCOE_CREATE_LINK_UP && 2389435c8667SRobert Love !fcoe_link_ok(lport)) { 239022805123SRobert Love rtnl_unlock(); 2391619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 239222805123SRobert Love mutex_unlock(&fcoe_config_mutex); 239322805123SRobert Love return rc; 239422805123SRobert Love } 239554b649f8SChris Leech 2396a703e490SVasu Dev out_nodev: 239734ce27bcSVasu Dev rtnl_unlock(); 2398dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2399f9c4358eSRobert Love out: 2400a703e490SVasu Dev return rc; 2401a703e490SVasu Dev } 2402a703e490SVasu Dev 2403a703e490SVasu Dev /** 2404435c8667SRobert Love * fcoe_create() - Create a fcoe interface 2405435c8667SRobert Love * @netdev : The net_device object the Ethernet interface to create on 2406435c8667SRobert Love * @fip_mode: The FIP mode for this creation 2407435c8667SRobert Love * 2408435c8667SRobert Love * Called from fcoe transport 2409435c8667SRobert Love * 2410435c8667SRobert Love * Returns: 0 for success 2411435c8667SRobert Love */ 2412435c8667SRobert Love static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) 2413435c8667SRobert Love { 2414435c8667SRobert Love return _fcoe_create(netdev, fip_mode, FCOE_CREATE_LINK_UP); 2415435c8667SRobert Love } 2416435c8667SRobert Love 2417435c8667SRobert Love /** 2418435c8667SRobert Love * fcoe_ctlr_alloc() - Allocate a fcoe interface from fcoe_sysfs 2419435c8667SRobert Love * @netdev: The net_device to be used by the allocated FCoE Controller 2420435c8667SRobert Love * 2421435c8667SRobert Love * This routine is called from fcoe_sysfs. It will start the fcoe_ctlr 2422435c8667SRobert Love * in a link_down state. The allows the user an opportunity to configure 2423435c8667SRobert Love * the FCoE Controller from sysfs before enabling the FCoE Controller. 2424435c8667SRobert Love * 2425435c8667SRobert Love * Creating in with this routine starts the FCoE Controller in Fabric 2426435c8667SRobert Love * mode. The user can change to VN2VN or another mode before enabling. 2427435c8667SRobert Love */ 2428435c8667SRobert Love static int fcoe_ctlr_alloc(struct net_device *netdev) 2429435c8667SRobert Love { 2430435c8667SRobert Love return _fcoe_create(netdev, FIP_MODE_FABRIC, 2431435c8667SRobert Love FCOE_CREATE_LINK_DOWN); 2432435c8667SRobert Love } 2433435c8667SRobert Love 2434435c8667SRobert Love /** 24355e4f8fe7SRobert Love * fcoe_link_ok() - Check if the link is OK for a local port 24365e4f8fe7SRobert Love * @lport: The local port to check link on 24375e4f8fe7SRobert Love * 24385e4f8fe7SRobert Love * Returns: 0 if link is UP and OK, -1 if not 24395e4f8fe7SRobert Love * 24405e4f8fe7SRobert Love */ 24417c9c6841SBart Van Assche static int fcoe_link_ok(struct fc_lport *lport) 24425e4f8fe7SRobert Love { 24438597ae8bSBhanu Prakash Gollapudi struct net_device *netdev = fcoe_netdev(lport); 24445e4f8fe7SRobert Love 24455e4f8fe7SRobert Love if (netif_oper_up(netdev)) 24465e4f8fe7SRobert Love return 0; 24475e4f8fe7SRobert Love return -1; 24485e4f8fe7SRobert Love } 24495e4f8fe7SRobert Love 24505e4f8fe7SRobert Love /** 24511875f27eSRobert Love * fcoe_percpu_clean() - Clear all pending skbs for an local port 24521875f27eSRobert Love * @lport: The local port whose skbs are to be cleared 2453e7a51997SJoe Eykholt * 2454e7a51997SJoe Eykholt * Must be called with fcoe_create_mutex held to single-thread completion. 2455e7a51997SJoe Eykholt * 2456e7a51997SJoe Eykholt * This flushes the pending skbs by adding a new skb to each queue and 2457e7a51997SJoe Eykholt * waiting until they are all freed. This assures us that not only are 2458e7a51997SJoe Eykholt * there no packets that will be handled by the lport, but also that any 2459e7a51997SJoe Eykholt * threads already handling packet have returned. 2460a703e490SVasu Dev */ 24617c9c6841SBart Van Assche static void fcoe_percpu_clean(struct fc_lport *lport) 2462a703e490SVasu Dev { 2463a703e490SVasu Dev struct fcoe_percpu_s *pp; 2464dd060e74SNeil Horman struct sk_buff *skb; 2465a703e490SVasu Dev unsigned int cpu; 2466a703e490SVasu Dev 2467a703e490SVasu Dev for_each_possible_cpu(cpu) { 2468a703e490SVasu Dev pp = &per_cpu(fcoe_percpu, cpu); 2469e7a51997SJoe Eykholt 2470dd060e74SNeil Horman if (!pp->thread || !cpu_online(cpu)) 2471e7a51997SJoe Eykholt continue; 2472e7a51997SJoe Eykholt 2473e7a51997SJoe Eykholt skb = dev_alloc_skb(0); 2474b3b8abd8SDan Carpenter if (!skb) 2475e7a51997SJoe Eykholt continue; 2476b3b8abd8SDan Carpenter 2477e7a51997SJoe Eykholt skb->destructor = fcoe_percpu_flush_done; 2478e7a51997SJoe Eykholt 2479dd060e74SNeil Horman spin_lock_bh(&pp->fcoe_rx_list.lock); 2480e7a51997SJoe Eykholt __skb_queue_tail(&pp->fcoe_rx_list, skb); 2481e7a51997SJoe Eykholt if (pp->fcoe_rx_list.qlen == 1) 2482e7a51997SJoe Eykholt wake_up_process(pp->thread); 2483e7a51997SJoe Eykholt spin_unlock_bh(&pp->fcoe_rx_list.lock); 2484e7a51997SJoe Eykholt 2485e7a51997SJoe Eykholt wait_for_completion(&fcoe_flush_completion); 2486a703e490SVasu Dev } 2487a703e490SVasu Dev } 2488a703e490SVasu Dev 2489a703e490SVasu Dev /** 24901875f27eSRobert Love * fcoe_reset() - Reset a local port 24911875f27eSRobert Love * @shost: The SCSI host associated with the local port to be reset 2492a703e490SVasu Dev * 24931875f27eSRobert Love * Returns: Always 0 (return value required by FC transport template) 2494a703e490SVasu Dev */ 24957c9c6841SBart Van Assche static int fcoe_reset(struct Scsi_Host *shost) 2496a703e490SVasu Dev { 2497a703e490SVasu Dev struct fc_lport *lport = shost_priv(shost); 2498d2f80952SVasu Dev struct fcoe_port *port = lport_priv(lport); 2499d2f80952SVasu Dev struct fcoe_interface *fcoe = port->priv; 2500619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 2501435c8667SRobert Love struct fcoe_ctlr_device *cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2502d2f80952SVasu Dev 2503619fe4beSRobert Love fcoe_ctlr_link_down(ctlr); 2504619fe4beSRobert Love fcoe_clean_pending_queue(ctlr->lp); 2505435c8667SRobert Love 2506435c8667SRobert Love if (cdev->enabled != FCOE_CTLR_DISABLED && 2507435c8667SRobert Love !fcoe_link_ok(ctlr->lp)) 2508619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2509a703e490SVasu Dev return 0; 2510a703e490SVasu Dev } 2511a703e490SVasu Dev 2512a703e490SVasu Dev /** 25131875f27eSRobert Love * fcoe_hostlist_lookup_port() - Find the FCoE interface associated with a net device 25141875f27eSRobert Love * @netdev: The net device used as a key 2515a703e490SVasu Dev * 25161875f27eSRobert Love * Locking: Must be called with the RNL mutex held. 25171875f27eSRobert Love * 25181875f27eSRobert Love * Returns: NULL or the FCoE interface 2519a703e490SVasu Dev */ 2520014f5c3fSChris Leech static struct fcoe_interface * 25211875f27eSRobert Love fcoe_hostlist_lookup_port(const struct net_device *netdev) 2522a703e490SVasu Dev { 2523014f5c3fSChris Leech struct fcoe_interface *fcoe; 2524a703e490SVasu Dev 2525014f5c3fSChris Leech list_for_each_entry(fcoe, &fcoe_hostlist, list) { 25261875f27eSRobert Love if (fcoe->netdev == netdev) 2527014f5c3fSChris Leech return fcoe; 2528a703e490SVasu Dev } 2529a703e490SVasu Dev return NULL; 2530a703e490SVasu Dev } 2531a703e490SVasu Dev 2532a703e490SVasu Dev /** 25331875f27eSRobert Love * fcoe_hostlist_lookup() - Find the local port associated with a 25341875f27eSRobert Love * given net device 25351875f27eSRobert Love * @netdev: The netdevice used as a key 2536a703e490SVasu Dev * 25371875f27eSRobert Love * Locking: Must be called with the RTNL mutex held 25381875f27eSRobert Love * 25391875f27eSRobert Love * Returns: NULL or the local port 2540a703e490SVasu Dev */ 2541090eb6c4SChris Leech static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) 2542a703e490SVasu Dev { 2543619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2544014f5c3fSChris Leech struct fcoe_interface *fcoe; 2545a703e490SVasu Dev 2546014f5c3fSChris Leech fcoe = fcoe_hostlist_lookup_port(netdev); 2547619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2548619fe4beSRobert Love return (fcoe) ? ctlr->lp : NULL; 2549a703e490SVasu Dev } 2550a703e490SVasu Dev 2551a703e490SVasu Dev /** 25521875f27eSRobert Love * fcoe_hostlist_add() - Add the FCoE interface identified by a local 25531875f27eSRobert Love * port to the hostlist 25541875f27eSRobert Love * @lport: The local port that identifies the FCoE interface to be added 25551875f27eSRobert Love * 25561875f27eSRobert Love * Locking: must be called with the RTNL mutex held 2557a703e490SVasu Dev * 2558a703e490SVasu Dev * Returns: 0 for success 2559a703e490SVasu Dev */ 2560090eb6c4SChris Leech static int fcoe_hostlist_add(const struct fc_lport *lport) 2561a703e490SVasu Dev { 2562014f5c3fSChris Leech struct fcoe_interface *fcoe; 2563014f5c3fSChris Leech struct fcoe_port *port; 2564a703e490SVasu Dev 2565014f5c3fSChris Leech fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); 2566014f5c3fSChris Leech if (!fcoe) { 2567014f5c3fSChris Leech port = lport_priv(lport); 25688597ae8bSBhanu Prakash Gollapudi fcoe = port->priv; 2569014f5c3fSChris Leech list_add_tail(&fcoe->list, &fcoe_hostlist); 2570a703e490SVasu Dev } 2571a703e490SVasu Dev return 0; 2572a703e490SVasu Dev } 2573a703e490SVasu Dev 2574f9184df3SNeil Horman /** 2575f9184df3SNeil Horman * fcoe_hostlist_del() - Remove the FCoE interface identified by a local 2576f9184df3SNeil Horman * port to the hostlist 2577f9184df3SNeil Horman * @lport: The local port that identifies the FCoE interface to be added 2578f9184df3SNeil Horman * 2579f9184df3SNeil Horman * Locking: must be called with the RTNL mutex held 2580f9184df3SNeil Horman * 2581f9184df3SNeil Horman */ 2582f9184df3SNeil Horman static void fcoe_hostlist_del(const struct fc_lport *lport) 2583f9184df3SNeil Horman { 2584f9184df3SNeil Horman struct fcoe_interface *fcoe; 2585f9184df3SNeil Horman struct fcoe_port *port; 2586f9184df3SNeil Horman 2587f9184df3SNeil Horman port = lport_priv(lport); 2588f9184df3SNeil Horman fcoe = port->priv; 2589f9184df3SNeil Horman list_del(&fcoe->list); 2590f9184df3SNeil Horman return; 2591f9184df3SNeil Horman } 259278a58246SYi Zou 259378a58246SYi Zou static struct fcoe_transport fcoe_sw_transport = { 259478a58246SYi Zou .name = {FCOE_TRANSPORT_DEFAULT}, 259578a58246SYi Zou .attached = false, 259678a58246SYi Zou .list = LIST_HEAD_INIT(fcoe_sw_transport.list), 259778a58246SYi Zou .match = fcoe_match, 2598435c8667SRobert Love .alloc = fcoe_ctlr_alloc, 259978a58246SYi Zou .create = fcoe_create, 260078a58246SYi Zou .destroy = fcoe_destroy, 260178a58246SYi Zou .enable = fcoe_enable, 260278a58246SYi Zou .disable = fcoe_disable, 260378a58246SYi Zou }; 260478a58246SYi Zou 2605a703e490SVasu Dev /** 26061875f27eSRobert Love * fcoe_init() - Initialize fcoe.ko 2607a703e490SVasu Dev * 26081875f27eSRobert Love * Returns: 0 on success, or a negative value on failure 2609a703e490SVasu Dev */ 2610a703e490SVasu Dev static int __init fcoe_init(void) 2611a703e490SVasu Dev { 26121875f27eSRobert Love struct fcoe_percpu_s *p; 2613a703e490SVasu Dev unsigned int cpu; 2614a703e490SVasu Dev int rc = 0; 2615a703e490SVasu Dev 26162ca32b48STejun Heo fcoe_wq = alloc_workqueue("fcoe", 0, 0); 26172ca32b48STejun Heo if (!fcoe_wq) 26182ca32b48STejun Heo return -ENOMEM; 26192ca32b48STejun Heo 262078a58246SYi Zou /* register as a fcoe transport */ 262178a58246SYi Zou rc = fcoe_transport_attach(&fcoe_sw_transport); 262278a58246SYi Zou if (rc) { 262378a58246SYi Zou printk(KERN_ERR "failed to register an fcoe transport, check " 262478a58246SYi Zou "if libfcoe is loaded\n"); 262578a58246SYi Zou return rc; 262678a58246SYi Zou } 262778a58246SYi Zou 2628dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2629dfc1d0feSChris Leech 2630a703e490SVasu Dev for_each_possible_cpu(cpu) { 2631a703e490SVasu Dev p = &per_cpu(fcoe_percpu, cpu); 2632a703e490SVasu Dev skb_queue_head_init(&p->fcoe_rx_list); 2633a703e490SVasu Dev } 2634a703e490SVasu Dev 2635a703e490SVasu Dev for_each_online_cpu(cpu) 2636a703e490SVasu Dev fcoe_percpu_thread_create(cpu); 2637a703e490SVasu Dev 2638a703e490SVasu Dev /* Initialize per CPU interrupt thread */ 2639a703e490SVasu Dev rc = register_hotcpu_notifier(&fcoe_cpu_notifier); 2640a703e490SVasu Dev if (rc) 2641a703e490SVasu Dev goto out_free; 2642a703e490SVasu Dev 2643a703e490SVasu Dev /* Setup link change notification */ 2644a703e490SVasu Dev fcoe_dev_setup(); 2645a703e490SVasu Dev 26465892c32fSChris Leech rc = fcoe_if_init(); 26475892c32fSChris Leech if (rc) 26485892c32fSChris Leech goto out_free; 2649a703e490SVasu Dev 2650dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2651a703e490SVasu Dev return 0; 2652a703e490SVasu Dev 2653a703e490SVasu Dev out_free: 2654a703e490SVasu Dev for_each_online_cpu(cpu) { 2655a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 2656a703e490SVasu Dev } 2657dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 26582ca32b48STejun Heo destroy_workqueue(fcoe_wq); 2659a703e490SVasu Dev return rc; 2660a703e490SVasu Dev } 2661a703e490SVasu Dev module_init(fcoe_init); 2662a703e490SVasu Dev 2663a703e490SVasu Dev /** 26641875f27eSRobert Love * fcoe_exit() - Clean up fcoe.ko 2665a703e490SVasu Dev * 26661875f27eSRobert Love * Returns: 0 on success or a negative value on failure 2667a703e490SVasu Dev */ 2668a703e490SVasu Dev static void __exit fcoe_exit(void) 2669a703e490SVasu Dev { 2670014f5c3fSChris Leech struct fcoe_interface *fcoe, *tmp; 2671619fe4beSRobert Love struct fcoe_ctlr *ctlr; 26722e70e241SChris Leech struct fcoe_port *port; 26731875f27eSRobert Love unsigned int cpu; 2674a703e490SVasu Dev 2675dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2676dfc1d0feSChris Leech 2677a703e490SVasu Dev fcoe_dev_cleanup(); 2678a703e490SVasu Dev 2679a703e490SVasu Dev /* releases the associated fcoe hosts */ 2680090eb6c4SChris Leech rtnl_lock(); 2681090eb6c4SChris Leech list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { 2682619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2683619fe4beSRobert Love port = lport_priv(ctlr->lp); 2684f9184df3SNeil Horman fcoe_hostlist_del(port->lport); 26852ca32b48STejun Heo queue_work(fcoe_wq, &port->destroy_work); 2686c863df33SChris Leech } 2687090eb6c4SChris Leech rtnl_unlock(); 2688a703e490SVasu Dev 2689a703e490SVasu Dev unregister_hotcpu_notifier(&fcoe_cpu_notifier); 2690a703e490SVasu Dev 2691014f5c3fSChris Leech for_each_online_cpu(cpu) 2692a703e490SVasu Dev fcoe_percpu_thread_destroy(cpu); 2693a703e490SVasu Dev 2694dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 26952e70e241SChris Leech 26962ca32b48STejun Heo /* 26972ca32b48STejun Heo * destroy_work's may be chained but destroy_workqueue() 26982ca32b48STejun Heo * can take care of them. Just kill the fcoe_wq. 26992ca32b48STejun Heo */ 27002ca32b48STejun Heo destroy_workqueue(fcoe_wq); 27012e70e241SChris Leech 27022ca32b48STejun Heo /* 27032ca32b48STejun Heo * Detaching from the scsi transport must happen after all 27042ca32b48STejun Heo * destroys are done on the fcoe_wq. destroy_workqueue will 27052ca32b48STejun Heo * enusre the fcoe_wq is flushed. 27062ca32b48STejun Heo */ 27072e70e241SChris Leech fcoe_if_exit(); 270878a58246SYi Zou 270978a58246SYi Zou /* detach from fcoe transport */ 271078a58246SYi Zou fcoe_transport_detach(&fcoe_sw_transport); 2711a703e490SVasu Dev } 2712a703e490SVasu Dev module_exit(fcoe_exit); 271311b56188SChris Leech 271411b56188SChris Leech /** 271511b56188SChris Leech * fcoe_flogi_resp() - FCoE specific FLOGI and FDISC response handler 271611b56188SChris Leech * @seq: active sequence in the FLOGI or FDISC exchange 271711b56188SChris Leech * @fp: response frame, or error encoded in a pointer (timeout) 271811b56188SChris Leech * @arg: pointer the the fcoe_ctlr structure 271911b56188SChris Leech * 272065155b37SUwe Kleine-König * This handles MAC address management for FCoE, then passes control on to 272111b56188SChris Leech * the libfc FLOGI response handler. 272211b56188SChris Leech */ 272311b56188SChris Leech static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) 272411b56188SChris Leech { 272511b56188SChris Leech struct fcoe_ctlr *fip = arg; 272611b56188SChris Leech struct fc_exch *exch = fc_seq_exch(seq); 272711b56188SChris Leech struct fc_lport *lport = exch->lp; 272811b56188SChris Leech u8 *mac; 272911b56188SChris Leech 273011b56188SChris Leech if (IS_ERR(fp)) 273111b56188SChris Leech goto done; 273211b56188SChris Leech 273311b56188SChris Leech mac = fr_cb(fp)->granted_mac; 273411b56188SChris Leech /* pre-FIP */ 2735907c07d4SVasu Dev if (is_zero_ether_addr(mac)) 2736907c07d4SVasu Dev fcoe_ctlr_recv_flogi(fip, lport, fp); 2737907c07d4SVasu Dev if (!is_zero_ether_addr(mac)) 2738386309ceSJoe Eykholt fcoe_update_src_mac(lport, mac); 273911b56188SChris Leech done: 274011b56188SChris Leech fc_lport_flogi_resp(seq, fp, lport); 274111b56188SChris Leech } 274211b56188SChris Leech 274311b56188SChris Leech /** 274411b56188SChris Leech * fcoe_logo_resp() - FCoE specific LOGO response handler 274511b56188SChris Leech * @seq: active sequence in the LOGO exchange 274611b56188SChris Leech * @fp: response frame, or error encoded in a pointer (timeout) 274711b56188SChris Leech * @arg: pointer the the fcoe_ctlr structure 274811b56188SChris Leech * 274965155b37SUwe Kleine-König * This handles MAC address management for FCoE, then passes control on to 275011b56188SChris Leech * the libfc LOGO response handler. 275111b56188SChris Leech */ 275211b56188SChris Leech static void fcoe_logo_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) 275311b56188SChris Leech { 2754386309ceSJoe Eykholt struct fc_lport *lport = arg; 275511b56188SChris Leech static u8 zero_mac[ETH_ALEN] = { 0 }; 275611b56188SChris Leech 275711b56188SChris Leech if (!IS_ERR(fp)) 2758386309ceSJoe Eykholt fcoe_update_src_mac(lport, zero_mac); 275911b56188SChris Leech fc_lport_logo_resp(seq, fp, lport); 276011b56188SChris Leech } 276111b56188SChris Leech 276211b56188SChris Leech /** 276311b56188SChris Leech * fcoe_elsct_send - FCoE specific ELS handler 276411b56188SChris Leech * 276511b56188SChris Leech * This does special case handling of FIP encapsualted ELS exchanges for FCoE, 276611b56188SChris Leech * using FCoE specific response handlers and passing the FIP controller as 276711b56188SChris Leech * the argument (the lport is still available from the exchange). 276811b56188SChris Leech * 276911b56188SChris Leech * Most of the work here is just handed off to the libfc routine. 277011b56188SChris Leech */ 27711875f27eSRobert Love static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did, 27721875f27eSRobert Love struct fc_frame *fp, unsigned int op, 27731875f27eSRobert Love void (*resp)(struct fc_seq *, 27741875f27eSRobert Love struct fc_frame *, 27751875f27eSRobert Love void *), 277611b56188SChris Leech void *arg, u32 timeout) 277711b56188SChris Leech { 277811b56188SChris Leech struct fcoe_port *port = lport_priv(lport); 27798597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 2780619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 278111b56188SChris Leech struct fc_frame_header *fh = fc_frame_header_get(fp); 278211b56188SChris Leech 278311b56188SChris Leech switch (op) { 278411b56188SChris Leech case ELS_FLOGI: 278511b56188SChris Leech case ELS_FDISC: 2786e10f8c66SJoe Eykholt if (lport->point_to_multipoint) 2787e10f8c66SJoe Eykholt break; 278811b56188SChris Leech return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp, 278911b56188SChris Leech fip, timeout); 279011b56188SChris Leech case ELS_LOGO: 279111b56188SChris Leech /* only hook onto fabric logouts, not port logouts */ 279211b56188SChris Leech if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) 279311b56188SChris Leech break; 279411b56188SChris Leech return fc_elsct_send(lport, did, fp, op, fcoe_logo_resp, 2795386309ceSJoe Eykholt lport, timeout); 279611b56188SChris Leech } 279711b56188SChris Leech return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); 279811b56188SChris Leech } 279911b56188SChris Leech 28009a05753bSChris Leech /** 28019a05753bSChris Leech * fcoe_vport_create() - create an fc_host/scsi_host for a vport 28029a05753bSChris Leech * @vport: fc_vport object to create a new fc_host for 28039a05753bSChris Leech * @disabled: start the new fc_host in a disabled state by default? 28049a05753bSChris Leech * 28059a05753bSChris Leech * Returns: 0 for success 28069a05753bSChris Leech */ 28079a05753bSChris Leech static int fcoe_vport_create(struct fc_vport *vport, bool disabled) 28089a05753bSChris Leech { 28099a05753bSChris Leech struct Scsi_Host *shost = vport_to_shost(vport); 28109a05753bSChris Leech struct fc_lport *n_port = shost_priv(shost); 28119a05753bSChris Leech struct fcoe_port *port = lport_priv(n_port); 28128597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 28139a05753bSChris Leech struct net_device *netdev = fcoe->netdev; 28149a05753bSChris Leech struct fc_lport *vn_port; 2815bdf25218SNeerav Parikh int rc; 2816bdf25218SNeerav Parikh char buf[32]; 2817bdf25218SNeerav Parikh 2818bdf25218SNeerav Parikh rc = fcoe_validate_vport_create(vport); 2819bdf25218SNeerav Parikh if (rc) { 2820d834895cSBhanu Prakash Gollapudi fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); 2821bdf25218SNeerav Parikh printk(KERN_ERR "fcoe: Failed to create vport, " 2822bdf25218SNeerav Parikh "WWPN (0x%s) already exists\n", 2823bdf25218SNeerav Parikh buf); 2824bdf25218SNeerav Parikh return rc; 2825bdf25218SNeerav Parikh } 28269a05753bSChris Leech 28279a05753bSChris Leech mutex_lock(&fcoe_config_mutex); 28284bc71cb9SJiri Pirko rtnl_lock(); 28299a05753bSChris Leech vn_port = fcoe_if_create(fcoe, &vport->dev, 1); 28304bc71cb9SJiri Pirko rtnl_unlock(); 28319a05753bSChris Leech mutex_unlock(&fcoe_config_mutex); 28329a05753bSChris Leech 28339a05753bSChris Leech if (IS_ERR(vn_port)) { 28349a05753bSChris Leech printk(KERN_ERR "fcoe: fcoe_vport_create(%s) failed\n", 28359a05753bSChris Leech netdev->name); 28369a05753bSChris Leech return -EIO; 28379a05753bSChris Leech } 28389a05753bSChris Leech 28399a05753bSChris Leech if (disabled) { 28409a05753bSChris Leech fc_vport_set_state(vport, FC_VPORT_DISABLED); 28419a05753bSChris Leech } else { 28429a05753bSChris Leech vn_port->boot_time = jiffies; 28439a05753bSChris Leech fc_fabric_login(vn_port); 28449a05753bSChris Leech fc_vport_setlink(vn_port); 28459a05753bSChris Leech } 28469a05753bSChris Leech return 0; 28479a05753bSChris Leech } 28489a05753bSChris Leech 28499a05753bSChris Leech /** 28509a05753bSChris Leech * fcoe_vport_destroy() - destroy the fc_host/scsi_host for a vport 28519a05753bSChris Leech * @vport: fc_vport object that is being destroyed 28529a05753bSChris Leech * 28539a05753bSChris Leech * Returns: 0 for success 28549a05753bSChris Leech */ 28559a05753bSChris Leech static int fcoe_vport_destroy(struct fc_vport *vport) 28569a05753bSChris Leech { 28579a05753bSChris Leech struct Scsi_Host *shost = vport_to_shost(vport); 28589a05753bSChris Leech struct fc_lport *n_port = shost_priv(shost); 28599a05753bSChris Leech struct fc_lport *vn_port = vport->dd_data; 28609a05753bSChris Leech 28619a05753bSChris Leech mutex_lock(&n_port->lp_mutex); 28629a05753bSChris Leech list_del(&vn_port->list); 28639a05753bSChris Leech mutex_unlock(&n_port->lp_mutex); 2864ccefd23eSRobert Love 2865ccefd23eSRobert Love mutex_lock(&fcoe_config_mutex); 2866ccefd23eSRobert Love fcoe_if_destroy(vn_port); 2867ccefd23eSRobert Love mutex_unlock(&fcoe_config_mutex); 2868ccefd23eSRobert Love 28699a05753bSChris Leech return 0; 28709a05753bSChris Leech } 28719a05753bSChris Leech 28729a05753bSChris Leech /** 28739a05753bSChris Leech * fcoe_vport_disable() - change vport state 28749a05753bSChris Leech * @vport: vport to bring online/offline 28759a05753bSChris Leech * @disable: should the vport be disabled? 28769a05753bSChris Leech */ 28779a05753bSChris Leech static int fcoe_vport_disable(struct fc_vport *vport, bool disable) 28789a05753bSChris Leech { 28799a05753bSChris Leech struct fc_lport *lport = vport->dd_data; 28809a05753bSChris Leech 28819a05753bSChris Leech if (disable) { 28829a05753bSChris Leech fc_vport_set_state(vport, FC_VPORT_DISABLED); 28839a05753bSChris Leech fc_fabric_logoff(lport); 28849a05753bSChris Leech } else { 28859a05753bSChris Leech lport->boot_time = jiffies; 28869a05753bSChris Leech fc_fabric_login(lport); 28879a05753bSChris Leech fc_vport_setlink(lport); 28889a05753bSChris Leech } 28899a05753bSChris Leech 28909a05753bSChris Leech return 0; 28919a05753bSChris Leech } 28929a05753bSChris Leech 2893dc8596d3SChris Leech /** 2894dc8596d3SChris Leech * fcoe_vport_set_symbolic_name() - append vport string to symbolic name 2895dc8596d3SChris Leech * @vport: fc_vport with a new symbolic name string 2896dc8596d3SChris Leech * 2897dc8596d3SChris Leech * After generating a new symbolic name string, a new RSPN_ID request is 2898dc8596d3SChris Leech * sent to the name server. There is no response handler, so if it fails 2899dc8596d3SChris Leech * for some reason it will not be retried. 2900dc8596d3SChris Leech */ 2901dc8596d3SChris Leech static void fcoe_set_vport_symbolic_name(struct fc_vport *vport) 2902dc8596d3SChris Leech { 2903dc8596d3SChris Leech struct fc_lport *lport = vport->dd_data; 2904dc8596d3SChris Leech struct fc_frame *fp; 2905dc8596d3SChris Leech size_t len; 2906dc8596d3SChris Leech 2907dc8596d3SChris Leech snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE, 2908dc8596d3SChris Leech "%s v%s over %s : %s", FCOE_NAME, FCOE_VERSION, 2909dc8596d3SChris Leech fcoe_netdev(lport)->name, vport->symbolic_name); 2910dc8596d3SChris Leech 2911dc8596d3SChris Leech if (lport->state != LPORT_ST_READY) 2912dc8596d3SChris Leech return; 2913dc8596d3SChris Leech 2914dc8596d3SChris Leech len = strnlen(fc_host_symbolic_name(lport->host), 255); 2915dc8596d3SChris Leech fp = fc_frame_alloc(lport, 2916dc8596d3SChris Leech sizeof(struct fc_ct_hdr) + 2917dc8596d3SChris Leech sizeof(struct fc_ns_rspn) + len); 2918dc8596d3SChris Leech if (!fp) 2919dc8596d3SChris Leech return; 2920dc8596d3SChris Leech lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RSPN_ID, 2921b94f8951SJoe Eykholt NULL, NULL, 3 * lport->r_a_tov); 2922dc8596d3SChris Leech } 2923b84056bfSYi Zou 29248d55e507SRobert Love static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) 29258d55e507SRobert Love { 29268d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev = 29278d55e507SRobert Love fcoe_fcf_dev_to_ctlr_dev(fcf_dev); 29288d55e507SRobert Love struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); 29298d55e507SRobert Love struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr); 29308d55e507SRobert Love 29318d55e507SRobert Love fcf_dev->vlan_id = vlan_dev_vlan_id(fcoe->netdev); 29328d55e507SRobert Love } 29338d55e507SRobert Love 29347d65b0dfSJoe Eykholt /** 29357d65b0dfSJoe Eykholt * fcoe_set_port_id() - Callback from libfc when Port_ID is set. 29367d65b0dfSJoe Eykholt * @lport: the local port 29377d65b0dfSJoe Eykholt * @port_id: the port ID 29387d65b0dfSJoe Eykholt * @fp: the received frame, if any, that caused the port_id to be set. 29397d65b0dfSJoe Eykholt * 29407d65b0dfSJoe Eykholt * This routine handles the case where we received a FLOGI and are 29417d65b0dfSJoe Eykholt * entering point-to-point mode. We need to call fcoe_ctlr_recv_flogi() 29427d65b0dfSJoe Eykholt * so it can set the non-mapped mode and gateway address. 29437d65b0dfSJoe Eykholt * 29447d65b0dfSJoe Eykholt * The FLOGI LS_ACC is handled by fcoe_flogi_resp(). 29457d65b0dfSJoe Eykholt */ 29467d65b0dfSJoe Eykholt static void fcoe_set_port_id(struct fc_lport *lport, 29477d65b0dfSJoe Eykholt u32 port_id, struct fc_frame *fp) 29487d65b0dfSJoe Eykholt { 29497d65b0dfSJoe Eykholt struct fcoe_port *port = lport_priv(lport); 29508597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 2951619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 29527d65b0dfSJoe Eykholt 29537d65b0dfSJoe Eykholt if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) 2954619fe4beSRobert Love fcoe_ctlr_recv_flogi(ctlr, lport, fp); 29557d65b0dfSJoe Eykholt } 2956