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 6662d57f20SColin Ian King static unsigned int fcoe_e_d_tov = 2 * 1000; 6769aabcceSHannes Reinecke module_param_named(e_d_tov, fcoe_e_d_tov, int, S_IRUGO|S_IWUSR); 6869aabcceSHannes Reinecke MODULE_PARM_DESC(e_d_tov, "E_D_TOV in ms, default 2000"); 6969aabcceSHannes Reinecke 7062d57f20SColin Ian King static unsigned int fcoe_r_a_tov = 2 * 2 * 1000; 7169aabcceSHannes Reinecke module_param_named(r_a_tov, fcoe_r_a_tov, int, S_IRUGO|S_IWUSR); 7269aabcceSHannes Reinecke MODULE_PARM_DESC(r_a_tov, "R_A_TOV in ms, default 4000"); 7369aabcceSHannes Reinecke 747c9c6841SBart Van Assche static DEFINE_MUTEX(fcoe_config_mutex); 75dfc1d0feSChris Leech 762ca32b48STejun Heo static struct workqueue_struct *fcoe_wq; 772ca32b48STejun Heo 78a703e490SVasu Dev /* fcoe host list */ 79090eb6c4SChris Leech /* must only by accessed under the RTNL mutex */ 807c9c6841SBart Van Assche static LIST_HEAD(fcoe_hostlist); 817c9c6841SBart Van Assche static DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); 82a703e490SVasu Dev 83dd3fd72eSChris Leech /* Function Prototypes */ 841875f27eSRobert Love static int fcoe_reset(struct Scsi_Host *); 85fdd78027SVasu Dev static int fcoe_xmit(struct fc_lport *, struct fc_frame *); 86fdd78027SVasu Dev static int fcoe_rcv(struct sk_buff *, struct net_device *, 87fdd78027SVasu Dev struct packet_type *, struct net_device *); 881875f27eSRobert Love static void fcoe_percpu_clean(struct fc_lport *); 891875f27eSRobert Love static int fcoe_link_ok(struct fc_lport *); 90fdd78027SVasu Dev 91fdd78027SVasu Dev static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); 92fdd78027SVasu Dev static int fcoe_hostlist_add(const struct fc_lport *); 93f9184df3SNeil Horman static void fcoe_hostlist_del(const struct fc_lport *); 94fdd78027SVasu Dev 95a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *, ulong, void *); 96a703e490SVasu Dev static void fcoe_dev_setup(void); 97a703e490SVasu Dev static void fcoe_dev_cleanup(void); 981875f27eSRobert Love static struct fcoe_interface 991875f27eSRobert Love *fcoe_hostlist_lookup_port(const struct net_device *); 100a703e490SVasu Dev 1011875f27eSRobert Love static int fcoe_fip_recv(struct sk_buff *, struct net_device *, 1021875f27eSRobert Love struct packet_type *, struct net_device *); 103d242e668SHannes Reinecke static int fcoe_fip_vlan_recv(struct sk_buff *, struct net_device *, 104d242e668SHannes Reinecke struct packet_type *, struct net_device *); 1051875f27eSRobert Love 1061875f27eSRobert Love static void fcoe_fip_send(struct fcoe_ctlr *, struct sk_buff *); 1071875f27eSRobert Love static void fcoe_update_src_mac(struct fc_lport *, u8 *); 1081875f27eSRobert Love static u8 *fcoe_get_src_mac(struct fc_lport *); 1091875f27eSRobert Love static void fcoe_destroy_work(struct work_struct *); 1101875f27eSRobert Love 1111875f27eSRobert Love static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *, 1121875f27eSRobert Love unsigned int); 1131875f27eSRobert Love static int fcoe_ddp_done(struct fc_lport *, u16); 11471f89491SYi Zou static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, 11571f89491SYi Zou unsigned int); 1166f6c2aa3Sjohn fastabend static int fcoe_dcb_app_notification(struct notifier_block *notifier, 1176f6c2aa3Sjohn fastabend ulong event, void *ptr); 1181875f27eSRobert Love 11978a58246SYi Zou static bool fcoe_match(struct net_device *netdev); 1201917d42dSHannes Reinecke static int fcoe_create(struct net_device *netdev, enum fip_mode fip_mode); 12178a58246SYi Zou static int fcoe_destroy(struct net_device *netdev); 12278a58246SYi Zou static int fcoe_enable(struct net_device *netdev); 12378a58246SYi Zou static int fcoe_disable(struct net_device *netdev); 1241875f27eSRobert Love 125435c8667SRobert Love /* fcoe_syfs control interface handlers */ 126435c8667SRobert Love static int fcoe_ctlr_alloc(struct net_device *netdev); 127435c8667SRobert Love static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev); 128a87dccc7SHannes Reinecke static void fcoe_ctlr_mode(struct fcoe_ctlr_device *ctlr_dev); 129435c8667SRobert Love 1301875f27eSRobert Love static struct fc_seq *fcoe_elsct_send(struct fc_lport *, 1311875f27eSRobert Love u32 did, struct fc_frame *, 1321875f27eSRobert Love unsigned int op, 1331875f27eSRobert Love void (*resp)(struct fc_seq *, 1341875f27eSRobert Love struct fc_frame *, 1351875f27eSRobert Love void *), 1361875f27eSRobert Love void *, u32 timeout); 137859b7b64SChris Leech static void fcoe_recv_frame(struct sk_buff *skb); 1381875f27eSRobert Love 1391875f27eSRobert Love /* notification function for packets from net device */ 140a703e490SVasu Dev static struct notifier_block fcoe_notifier = { 141a703e490SVasu Dev .notifier_call = fcoe_device_notification, 142a703e490SVasu Dev }; 143a703e490SVasu Dev 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 *); 1586f7f74abSHannes Reinecke static void fcoe_vport_remove(struct fc_lport *); 159a87dccc7SHannes Reinecke 1608d55e507SRobert Love static struct fcoe_sysfs_function_template fcoe_sysfs_templ = { 161a87dccc7SHannes Reinecke .set_fcoe_ctlr_mode = fcoe_ctlr_mode, 162435c8667SRobert Love .set_fcoe_ctlr_enabled = fcoe_ctlr_enabled, 1638d55e507SRobert Love .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, 1648d55e507SRobert Love .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, 1658d55e507SRobert Love .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb, 1668d55e507SRobert Love .get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb, 1678d55e507SRobert Love .get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb, 1688d55e507SRobert Love .get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb, 1698d55e507SRobert Love 1708d55e507SRobert Love .get_fcoe_fcf_selected = fcoe_fcf_get_selected, 1718d55e507SRobert Love .get_fcoe_fcf_vlan_id = fcoe_fcf_get_vlan_id, 1728d55e507SRobert Love }; 1731875f27eSRobert Love 1741875f27eSRobert Love static struct libfc_function_template fcoe_libfc_fcn_templ = { 1751875f27eSRobert Love .frame_send = fcoe_xmit, 1761875f27eSRobert Love .ddp_setup = fcoe_ddp_setup, 1771875f27eSRobert Love .ddp_done = fcoe_ddp_done, 17871f89491SYi Zou .ddp_target = fcoe_ddp_target, 1791875f27eSRobert Love .elsct_send = fcoe_elsct_send, 180b84056bfSYi Zou .get_lesb = fcoe_get_lesb, 1817d65b0dfSJoe Eykholt .lport_set_port_id = fcoe_set_port_id, 1821875f27eSRobert Love }; 1839a05753bSChris Leech 1847c9c6841SBart Van Assche static struct fc_function_template fcoe_nport_fc_functions = { 185a703e490SVasu Dev .show_host_node_name = 1, 186a703e490SVasu Dev .show_host_port_name = 1, 187a703e490SVasu Dev .show_host_supported_classes = 1, 188a703e490SVasu Dev .show_host_supported_fc4s = 1, 189a703e490SVasu Dev .show_host_active_fc4s = 1, 190a703e490SVasu Dev .show_host_maxframe_size = 1, 1919f71af2fSNeerav Parikh .show_host_serial_number = 1, 1929f71af2fSNeerav Parikh .show_host_manufacturer = 1, 1939f71af2fSNeerav Parikh .show_host_model = 1, 1949f71af2fSNeerav Parikh .show_host_model_description = 1, 1959f71af2fSNeerav Parikh .show_host_hardware_version = 1, 1969f71af2fSNeerav Parikh .show_host_driver_version = 1, 1979f71af2fSNeerav Parikh .show_host_firmware_version = 1, 1989f71af2fSNeerav Parikh .show_host_optionrom_version = 1, 199a703e490SVasu Dev 200a703e490SVasu Dev .show_host_port_id = 1, 201a703e490SVasu Dev .show_host_supported_speeds = 1, 202a703e490SVasu Dev .get_host_speed = fc_get_host_speed, 203a703e490SVasu Dev .show_host_speed = 1, 204a703e490SVasu Dev .show_host_port_type = 1, 205a703e490SVasu Dev .get_host_port_state = fc_get_host_port_state, 206a703e490SVasu Dev .show_host_port_state = 1, 207a703e490SVasu Dev .show_host_symbolic_name = 1, 208a703e490SVasu Dev 209a703e490SVasu Dev .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), 210a703e490SVasu Dev .show_rport_maxframe_size = 1, 211a703e490SVasu Dev .show_rport_supported_classes = 1, 212a703e490SVasu Dev 213a703e490SVasu Dev .show_host_fabric_name = 1, 214a703e490SVasu Dev .show_starget_node_name = 1, 215a703e490SVasu Dev .show_starget_port_name = 1, 216a703e490SVasu Dev .show_starget_port_id = 1, 217a703e490SVasu Dev .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 218a703e490SVasu Dev .show_rport_dev_loss_tmo = 1, 219a703e490SVasu Dev .get_fc_host_stats = fc_get_host_stats, 220a703e490SVasu Dev .issue_fc_host_lip = fcoe_reset, 221a703e490SVasu Dev 222a703e490SVasu Dev .terminate_rport_io = fc_rport_terminate_io, 2239a05753bSChris Leech 2249a05753bSChris Leech .vport_create = fcoe_vport_create, 2259a05753bSChris Leech .vport_delete = fcoe_vport_destroy, 2269a05753bSChris Leech .vport_disable = fcoe_vport_disable, 227dc8596d3SChris Leech .set_vport_symbolic_name = fcoe_set_vport_symbolic_name, 228a51ab396SSteve Ma 229a51ab396SSteve Ma .bsg_request = fc_lport_bsg_request, 230a703e490SVasu Dev }; 231a703e490SVasu Dev 2327c9c6841SBart Van Assche static struct fc_function_template fcoe_vport_fc_functions = { 233e9084bb8SChris Leech .show_host_node_name = 1, 234e9084bb8SChris Leech .show_host_port_name = 1, 235e9084bb8SChris Leech .show_host_supported_classes = 1, 236e9084bb8SChris Leech .show_host_supported_fc4s = 1, 237e9084bb8SChris Leech .show_host_active_fc4s = 1, 238e9084bb8SChris Leech .show_host_maxframe_size = 1, 2397e5adcfbSNeerav Parikh .show_host_serial_number = 1, 2407e5adcfbSNeerav Parikh .show_host_manufacturer = 1, 2417e5adcfbSNeerav Parikh .show_host_model = 1, 2427e5adcfbSNeerav Parikh .show_host_model_description = 1, 2437e5adcfbSNeerav Parikh .show_host_hardware_version = 1, 2447e5adcfbSNeerav Parikh .show_host_driver_version = 1, 2457e5adcfbSNeerav Parikh .show_host_firmware_version = 1, 2467e5adcfbSNeerav Parikh .show_host_optionrom_version = 1, 247e9084bb8SChris Leech 248e9084bb8SChris Leech .show_host_port_id = 1, 249e9084bb8SChris Leech .show_host_supported_speeds = 1, 250e9084bb8SChris Leech .get_host_speed = fc_get_host_speed, 251e9084bb8SChris Leech .show_host_speed = 1, 252e9084bb8SChris Leech .show_host_port_type = 1, 253e9084bb8SChris Leech .get_host_port_state = fc_get_host_port_state, 254e9084bb8SChris Leech .show_host_port_state = 1, 255e9084bb8SChris Leech .show_host_symbolic_name = 1, 256e9084bb8SChris Leech 257e9084bb8SChris Leech .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), 258e9084bb8SChris Leech .show_rport_maxframe_size = 1, 259e9084bb8SChris Leech .show_rport_supported_classes = 1, 260e9084bb8SChris Leech 261e9084bb8SChris Leech .show_host_fabric_name = 1, 262e9084bb8SChris Leech .show_starget_node_name = 1, 263e9084bb8SChris Leech .show_starget_port_name = 1, 264e9084bb8SChris Leech .show_starget_port_id = 1, 265e9084bb8SChris Leech .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 266e9084bb8SChris Leech .show_rport_dev_loss_tmo = 1, 267e9084bb8SChris Leech .get_fc_host_stats = fc_get_host_stats, 268e9084bb8SChris Leech .issue_fc_host_lip = fcoe_reset, 269e9084bb8SChris Leech 270e9084bb8SChris Leech .terminate_rport_io = fc_rport_terminate_io, 271a51ab396SSteve Ma 272a51ab396SSteve Ma .bsg_request = fc_lport_bsg_request, 273e9084bb8SChris Leech }; 274e9084bb8SChris Leech 275a703e490SVasu Dev static struct scsi_host_template fcoe_shost_template = { 276a703e490SVasu Dev .module = THIS_MODULE, 277a703e490SVasu Dev .name = "FCoE Driver", 278a703e490SVasu Dev .proc_name = FCOE_NAME, 279a703e490SVasu Dev .queuecommand = fc_queuecommand, 280b6a05c82SChristoph Hellwig .eh_timed_out = fc_eh_timed_out, 281a703e490SVasu Dev .eh_abort_handler = fc_eh_abort, 282a703e490SVasu Dev .eh_device_reset_handler = fc_eh_device_reset, 283a703e490SVasu Dev .eh_host_reset_handler = fc_eh_host_reset, 284a703e490SVasu Dev .slave_alloc = fc_slave_alloc, 285db5ed4dfSChristoph Hellwig .change_queue_depth = scsi_change_queue_depth, 286a703e490SVasu Dev .this_id = -1, 28714caf44cSVasu Dev .cmd_per_lun = 3, 288a703e490SVasu Dev .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, 289a703e490SVasu Dev .sg_tablesize = SG_ALL, 290a703e490SVasu Dev .max_sectors = 0xffff, 291c40ecc12SChristoph Hellwig .track_queue_depth = 1, 292a703e490SVasu Dev }; 293a703e490SVasu Dev 29454b649f8SChris Leech /** 2951875f27eSRobert Love * fcoe_interface_setup() - Setup a FCoE interface 2961875f27eSRobert Love * @fcoe: The new FCoE interface 2971875f27eSRobert Love * @netdev: The net device that the fcoe interface is on 29854b649f8SChris Leech * 29954b649f8SChris Leech * Returns : 0 for success 3002e70e241SChris Leech * Locking: must be called with the RTNL mutex held 30154b649f8SChris Leech */ 30254b649f8SChris Leech static int fcoe_interface_setup(struct fcoe_interface *fcoe, 30354b649f8SChris Leech struct net_device *netdev) 30454b649f8SChris Leech { 305619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 30654b649f8SChris Leech struct netdev_hw_addr *ha; 3075bab87e6SYi Zou struct net_device *real_dev; 30854b649f8SChris Leech u8 flogi_maddr[ETH_ALEN]; 309b7a727f1SYi Zou const struct net_device_ops *ops; 31054b649f8SChris Leech 31154b649f8SChris Leech fcoe->netdev = netdev; 31254b649f8SChris Leech 313b7a727f1SYi Zou /* Let LLD initialize for FCoE */ 314b7a727f1SYi Zou ops = netdev->netdev_ops; 315b7a727f1SYi Zou if (ops->ndo_fcoe_enable) { 316b7a727f1SYi Zou if (ops->ndo_fcoe_enable(netdev)) 317b7a727f1SYi Zou FCOE_NETDEV_DBG(netdev, "Failed to enable FCoE" 318b7a727f1SYi Zou " specific feature for LLD.\n"); 319b7a727f1SYi Zou } 320b7a727f1SYi Zou 32154b649f8SChris Leech /* Do not support for bonding device */ 322cc8bdf06SJiri Pirko if (netdev->priv_flags & IFF_BONDING && netdev->flags & IFF_MASTER) { 32359d92516Sjohn fastabend FCOE_NETDEV_DBG(netdev, "Bonded interfaces not supported\n"); 32454b649f8SChris Leech return -EOPNOTSUPP; 32554b649f8SChris Leech } 32654b649f8SChris Leech 32754b649f8SChris Leech /* look for SAN MAC address, if multiple SAN MACs exist, only 32854b649f8SChris Leech * use the first one for SPMA */ 329d0d7b10bSParav Pandit real_dev = is_vlan_dev(netdev) ? 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; 366420fa211SVaishali Thakkar fcoe->fcoe_packet_type.type = 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 375d242e668SHannes Reinecke if (netdev != real_dev) { 376d242e668SHannes Reinecke fcoe->fip_vlan_packet_type.func = fcoe_fip_vlan_recv; 377d242e668SHannes Reinecke fcoe->fip_vlan_packet_type.type = htons(ETH_P_FIP); 378d242e668SHannes Reinecke fcoe->fip_vlan_packet_type.dev = real_dev; 379d242e668SHannes Reinecke dev_add_pack(&fcoe->fip_vlan_packet_type); 380d242e668SHannes Reinecke } 38154b649f8SChris Leech return 0; 38254b649f8SChris Leech } 38354b649f8SChris Leech 384a703e490SVasu Dev /** 3851875f27eSRobert Love * fcoe_interface_create() - Create a FCoE interface on a net device 3861875f27eSRobert Love * @netdev: The net device to create the FCoE interface on 3871dd454d9SJoe Eykholt * @fip_mode: The mode to use for FIP 388030f4e00SChris Leech * 389030f4e00SChris Leech * Returns: pointer to a struct fcoe_interface or NULL on error 390030f4e00SChris Leech */ 3911dd454d9SJoe Eykholt static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, 3928beb90aaSSedat Dilek enum fip_mode fip_mode) 393030f4e00SChris Leech { 3948d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev; 395619fe4beSRobert Love struct fcoe_ctlr *ctlr; 396030f4e00SChris Leech struct fcoe_interface *fcoe; 397619fe4beSRobert Love int size; 39859d92516Sjohn fastabend int err; 399030f4e00SChris Leech 4007287fb91SRobert Love if (!try_module_get(THIS_MODULE)) { 4017287fb91SRobert Love FCOE_NETDEV_DBG(netdev, 4027287fb91SRobert Love "Could not get a reference to the module\n"); 4037287fb91SRobert Love fcoe = ERR_PTR(-EBUSY); 4047287fb91SRobert Love goto out; 4057287fb91SRobert Love } 4067287fb91SRobert Love 407619fe4beSRobert Love size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface); 4088d55e507SRobert Love ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &fcoe_sysfs_templ, 4098d55e507SRobert Love size); 4108d55e507SRobert Love if (!ctlr_dev) { 4118d55e507SRobert Love FCOE_DBG("Failed to add fcoe_ctlr_device\n"); 4127287fb91SRobert Love fcoe = ERR_PTR(-ENOMEM); 4136f68794cSRobert Love goto out_putmod; 414030f4e00SChris Leech } 415030f4e00SChris Leech 4168d55e507SRobert Love ctlr = fcoe_ctlr_device_priv(ctlr_dev); 4179d34876fSRobert Love ctlr->cdev = ctlr_dev; 4188d55e507SRobert Love fcoe = fcoe_ctlr_priv(ctlr); 4198d55e507SRobert Love 4202e70e241SChris Leech dev_hold(netdev); 42154b649f8SChris Leech 42254b649f8SChris Leech /* 42354b649f8SChris Leech * Initialize FIP. 42454b649f8SChris Leech */ 425619fe4beSRobert Love fcoe_ctlr_init(ctlr, fip_mode); 426619fe4beSRobert Love ctlr->send = fcoe_fip_send; 427619fe4beSRobert Love ctlr->update_mac = fcoe_update_src_mac; 428619fe4beSRobert Love ctlr->get_src_addr = fcoe_get_src_mac; 42954b649f8SChris Leech 43059d92516Sjohn fastabend err = fcoe_interface_setup(fcoe, netdev); 43159d92516Sjohn fastabend if (err) { 432619fe4beSRobert Love fcoe_ctlr_destroy(ctlr); 4338d55e507SRobert Love fcoe_ctlr_device_delete(ctlr_dev); 43459d92516Sjohn fastabend dev_put(netdev); 4357287fb91SRobert Love fcoe = ERR_PTR(err); 4366f68794cSRobert Love goto out_putmod; 43759d92516Sjohn fastabend } 438030f4e00SChris Leech 4397287fb91SRobert Love goto out; 4407287fb91SRobert Love 4416f68794cSRobert Love out_putmod: 4427287fb91SRobert Love module_put(THIS_MODULE); 4437287fb91SRobert Love out: 444030f4e00SChris Leech return fcoe; 445030f4e00SChris Leech } 446030f4e00SChris Leech 447030f4e00SChris Leech /** 448433eba04SVasu Dev * fcoe_interface_remove() - remove FCoE interface from netdev 449f04ca1b6SVasu Dev * @fcoe: The FCoE interface to be cleaned up 450f04ca1b6SVasu Dev * 451f04ca1b6SVasu Dev * Caller must be holding the RTNL mutex 452f04ca1b6SVasu Dev */ 453433eba04SVasu Dev static void fcoe_interface_remove(struct fcoe_interface *fcoe) 454f04ca1b6SVasu Dev { 455f04ca1b6SVasu Dev struct net_device *netdev = fcoe->netdev; 456619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 457f04ca1b6SVasu Dev u8 flogi_maddr[ETH_ALEN]; 458f04ca1b6SVasu Dev const struct net_device_ops *ops; 459f04ca1b6SVasu Dev 460f04ca1b6SVasu Dev /* 461f04ca1b6SVasu Dev * Don't listen for Ethernet packets anymore. 462f04ca1b6SVasu Dev * synchronize_net() ensures that the packet handlers are not running 463f04ca1b6SVasu Dev * on another CPU. dev_remove_pack() would do that, this calls the 464f04ca1b6SVasu Dev * unsyncronized version __dev_remove_pack() to avoid multiple delays. 465f04ca1b6SVasu Dev */ 466f04ca1b6SVasu Dev __dev_remove_pack(&fcoe->fcoe_packet_type); 467f04ca1b6SVasu Dev __dev_remove_pack(&fcoe->fip_packet_type); 468d242e668SHannes Reinecke if (netdev != fcoe->realdev) 469d242e668SHannes Reinecke __dev_remove_pack(&fcoe->fip_vlan_packet_type); 470f04ca1b6SVasu Dev synchronize_net(); 471f04ca1b6SVasu Dev 472f04ca1b6SVasu Dev /* Delete secondary MAC addresses */ 473f04ca1b6SVasu Dev memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); 474f04ca1b6SVasu Dev dev_uc_del(netdev, flogi_maddr); 475f04ca1b6SVasu Dev if (fip->spma) 476f04ca1b6SVasu Dev dev_uc_del(netdev, fip->ctl_src_addr); 477f04ca1b6SVasu Dev if (fip->mode == FIP_MODE_VN2VN) { 478f04ca1b6SVasu Dev dev_mc_del(netdev, FIP_ALL_VN2VN_MACS); 479f04ca1b6SVasu Dev dev_mc_del(netdev, FIP_ALL_P2P_MACS); 480f04ca1b6SVasu Dev } else 481f04ca1b6SVasu Dev dev_mc_del(netdev, FIP_ALL_ENODE_MACS); 482f04ca1b6SVasu Dev 483f04ca1b6SVasu Dev /* Tell the LLD we are done w/ FCoE */ 484f04ca1b6SVasu Dev ops = netdev->netdev_ops; 485f04ca1b6SVasu Dev if (ops->ndo_fcoe_disable) { 486f04ca1b6SVasu Dev if (ops->ndo_fcoe_disable(netdev)) 487f04ca1b6SVasu Dev FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" 488f04ca1b6SVasu Dev " specific feature for LLD.\n"); 489f04ca1b6SVasu Dev } 490433eba04SVasu Dev fcoe->removed = 1; 491433eba04SVasu Dev } 492b2085a4eSNeerav Parikh 493433eba04SVasu Dev 494433eba04SVasu Dev /** 495433eba04SVasu Dev * fcoe_interface_cleanup() - Clean up a FCoE interface 496433eba04SVasu Dev * @fcoe: The FCoE interface to be cleaned up 497433eba04SVasu Dev */ 498433eba04SVasu Dev static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) 499433eba04SVasu Dev { 500433eba04SVasu Dev struct net_device *netdev = fcoe->netdev; 501619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 502433eba04SVasu Dev 503b2085a4eSNeerav Parikh /* Release the self-reference taken during fcoe_interface_create() */ 5041a8ef414SRobert Love /* tear-down the FCoE controller */ 5051a8ef414SRobert Love fcoe_ctlr_destroy(fip); 506619fe4beSRobert Love scsi_host_put(fip->lp->host); 5071a8ef414SRobert Love dev_put(netdev); 5081a8ef414SRobert Love module_put(THIS_MODULE); 509f04ca1b6SVasu Dev } 510f04ca1b6SVasu Dev 511f04ca1b6SVasu Dev /** 5121875f27eSRobert Love * fcoe_fip_recv() - Handler for received FIP frames 5131875f27eSRobert Love * @skb: The receive skb 5141875f27eSRobert Love * @netdev: The associated net device 5151875f27eSRobert Love * @ptype: The packet_type structure which was used to register this handler 51678cfe97fSMilan P. Gandhi * @orig_dev: The original net_device the skb was received on. 5171875f27eSRobert Love * (in case dev is a bond) 518ab6b85c1SVasu Dev * 519ab6b85c1SVasu Dev * Returns: 0 for success 520ab6b85c1SVasu Dev */ 5211875f27eSRobert Love static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev, 522ab6b85c1SVasu Dev struct packet_type *ptype, 523ab6b85c1SVasu Dev struct net_device *orig_dev) 524ab6b85c1SVasu Dev { 525259ad85dSChris Leech struct fcoe_interface *fcoe; 526619fe4beSRobert Love struct fcoe_ctlr *ctlr; 527ab6b85c1SVasu Dev 528259ad85dSChris Leech fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); 529619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 530619fe4beSRobert Love fcoe_ctlr_recv(ctlr, skb); 531ab6b85c1SVasu Dev return 0; 532ab6b85c1SVasu Dev } 533ab6b85c1SVasu Dev 534ab6b85c1SVasu Dev /** 535d242e668SHannes Reinecke * fcoe_fip_vlan_recv() - Handler for received FIP VLAN discovery frames 536d242e668SHannes Reinecke * @skb: The receive skb 537d242e668SHannes Reinecke * @netdev: The associated net device 538d242e668SHannes Reinecke * @ptype: The packet_type structure which was used to register this handler 53978cfe97fSMilan P. Gandhi * @orig_dev: The original net_device the skb was received on. 540d242e668SHannes Reinecke * (in case dev is a bond) 541d242e668SHannes Reinecke * 542d242e668SHannes Reinecke * Returns: 0 for success 543d242e668SHannes Reinecke */ 544d242e668SHannes Reinecke static int fcoe_fip_vlan_recv(struct sk_buff *skb, struct net_device *netdev, 545d242e668SHannes Reinecke struct packet_type *ptype, 546d242e668SHannes Reinecke struct net_device *orig_dev) 547d242e668SHannes Reinecke { 548d242e668SHannes Reinecke struct fcoe_interface *fcoe; 549d242e668SHannes Reinecke struct fcoe_ctlr *ctlr; 550d242e668SHannes Reinecke 551d242e668SHannes Reinecke fcoe = container_of(ptype, struct fcoe_interface, fip_vlan_packet_type); 552d242e668SHannes Reinecke ctlr = fcoe_to_ctlr(fcoe); 553d242e668SHannes Reinecke fcoe_ctlr_recv(ctlr, skb); 554d242e668SHannes Reinecke return 0; 555d242e668SHannes Reinecke } 556d242e668SHannes Reinecke 557d242e668SHannes Reinecke /** 558980f5156SVasu Dev * fcoe_port_send() - Send an Ethernet-encapsulated FIP/FCoE frame 559980f5156SVasu Dev * @port: The FCoE port 560980f5156SVasu Dev * @skb: The FIP/FCoE packet to be sent 561980f5156SVasu Dev */ 562980f5156SVasu Dev static void fcoe_port_send(struct fcoe_port *port, struct sk_buff *skb) 563980f5156SVasu Dev { 564980f5156SVasu Dev if (port->fcoe_pending_queue.qlen) 565980f5156SVasu Dev fcoe_check_wait_queue(port->lport, skb); 566980f5156SVasu Dev else if (fcoe_start_io(skb)) 567980f5156SVasu Dev fcoe_check_wait_queue(port->lport, skb); 568980f5156SVasu Dev } 569980f5156SVasu Dev 570980f5156SVasu Dev /** 5711875f27eSRobert Love * fcoe_fip_send() - Send an Ethernet-encapsulated FIP frame 5721875f27eSRobert Love * @fip: The FCoE controller 5731875f27eSRobert Love * @skb: The FIP packet to be sent 574ab6b85c1SVasu Dev */ 575ab6b85c1SVasu Dev static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) 576ab6b85c1SVasu Dev { 577d242e668SHannes Reinecke struct fcoe_interface *fcoe = fcoe_from_ctlr(fip); 578d242e668SHannes Reinecke struct fip_frame { 579d242e668SHannes Reinecke struct ethhdr eth; 580d242e668SHannes Reinecke struct fip_header fip; 581d242e668SHannes Reinecke } __packed *frame; 582d242e668SHannes Reinecke 583d242e668SHannes Reinecke /* 584d242e668SHannes Reinecke * Use default VLAN for FIP VLAN discovery protocol 585d242e668SHannes Reinecke */ 586d242e668SHannes Reinecke frame = (struct fip_frame *)skb->data; 587f7e6ed06SHannes Reinecke if (ntohs(frame->eth.h_proto) == ETH_P_FIP && 588f7e6ed06SHannes Reinecke ntohs(frame->fip.fip_op) == FIP_OP_VLAN && 589d242e668SHannes Reinecke fcoe->realdev != fcoe->netdev) 590d242e668SHannes Reinecke skb->dev = fcoe->realdev; 591d242e668SHannes Reinecke else 592d242e668SHannes Reinecke skb->dev = fcoe->netdev; 593980f5156SVasu Dev fcoe_port_send(lport_priv(fip->lp), skb); 594ab6b85c1SVasu Dev } 595ab6b85c1SVasu Dev 596ab6b85c1SVasu Dev /** 5971875f27eSRobert Love * fcoe_update_src_mac() - Update the Ethernet MAC filters 5981875f27eSRobert Love * @lport: The local port to update the source MAC on 5991875f27eSRobert Love * @addr: Unicast MAC address to add 600ab6b85c1SVasu Dev * 601ab6b85c1SVasu Dev * Remove any previously-set unicast MAC filter. 602ab6b85c1SVasu Dev * Add secondary FCoE MAC address filter for our OUI. 603ab6b85c1SVasu Dev */ 60411b56188SChris Leech static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr) 605ab6b85c1SVasu Dev { 60611b56188SChris Leech struct fcoe_port *port = lport_priv(lport); 6078597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 608ab6b85c1SVasu Dev 60911b56188SChris Leech if (!is_zero_ether_addr(port->data_src_addr)) 610a748ee24SJiri Pirko dev_uc_del(fcoe->netdev, port->data_src_addr); 61111b56188SChris Leech if (!is_zero_ether_addr(addr)) 612a748ee24SJiri Pirko dev_uc_add(fcoe->netdev, addr); 61311b56188SChris Leech memcpy(port->data_src_addr, addr, ETH_ALEN); 614ab6b85c1SVasu Dev } 615ab6b85c1SVasu Dev 616ab6b85c1SVasu Dev /** 61711b56188SChris Leech * fcoe_get_src_mac() - return the Ethernet source address for an lport 61811b56188SChris Leech * @lport: libfc lport 61911b56188SChris Leech */ 62011b56188SChris Leech static u8 *fcoe_get_src_mac(struct fc_lport *lport) 62111b56188SChris Leech { 62211b56188SChris Leech struct fcoe_port *port = lport_priv(lport); 62311b56188SChris Leech 62411b56188SChris Leech return port->data_src_addr; 62511b56188SChris Leech } 62611b56188SChris Leech 62711b56188SChris Leech /** 6281875f27eSRobert Love * fcoe_lport_config() - Set up a local port 6291875f27eSRobert Love * @lport: The local port to be setup 630a703e490SVasu Dev * 631a703e490SVasu Dev * Returns: 0 for success 632a703e490SVasu Dev */ 6331875f27eSRobert Love static int fcoe_lport_config(struct fc_lport *lport) 634a703e490SVasu Dev { 6351875f27eSRobert Love lport->link_up = 0; 6361875f27eSRobert Love lport->qfull = 0; 6371875f27eSRobert Love lport->max_retry_count = 3; 6381875f27eSRobert Love lport->max_rport_retry_count = 3; 63969aabcceSHannes Reinecke lport->e_d_tov = fcoe_e_d_tov; 64069aabcceSHannes Reinecke lport->r_a_tov = fcoe_r_a_tov; 6411875f27eSRobert Love lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | 642a703e490SVasu Dev FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); 6431875f27eSRobert Love lport->does_npiv = 1; 644a703e490SVasu Dev 6451875f27eSRobert Love fc_lport_init_stats(lport); 646a703e490SVasu Dev 647a703e490SVasu Dev /* lport fc_lport related configuration */ 6481875f27eSRobert Love fc_lport_config(lport); 649a703e490SVasu Dev 650a703e490SVasu Dev /* offload related configuration */ 6511875f27eSRobert Love lport->crc_offload = 0; 6521875f27eSRobert Love lport->seq_offload = 0; 6531875f27eSRobert Love lport->lro_enabled = 0; 6541875f27eSRobert Love lport->lro_xid = 0; 6551875f27eSRobert Love lport->lso_max = 0; 656a703e490SVasu Dev 657a703e490SVasu Dev return 0; 658a703e490SVasu Dev } 659a703e490SVasu Dev 660a703e490SVasu Dev /** 66154a5b21dSYi Zou * fcoe_netdev_features_change - Updates the lport's offload flags based 66254a5b21dSYi Zou * on the LLD netdev's FCoE feature flags 66354a5b21dSYi Zou */ 66454a5b21dSYi Zou static void fcoe_netdev_features_change(struct fc_lport *lport, 66554a5b21dSYi Zou struct net_device *netdev) 66654a5b21dSYi Zou { 66754a5b21dSYi Zou mutex_lock(&lport->lp_mutex); 66854a5b21dSYi Zou 66954a5b21dSYi Zou if (netdev->features & NETIF_F_SG) 67054a5b21dSYi Zou lport->sg_supp = 1; 67154a5b21dSYi Zou else 67254a5b21dSYi Zou lport->sg_supp = 0; 67354a5b21dSYi Zou 67454a5b21dSYi Zou if (netdev->features & NETIF_F_FCOE_CRC) { 67554a5b21dSYi Zou lport->crc_offload = 1; 67654a5b21dSYi Zou FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); 67754a5b21dSYi Zou } else { 67854a5b21dSYi Zou lport->crc_offload = 0; 67954a5b21dSYi Zou } 68054a5b21dSYi Zou 68154a5b21dSYi Zou if (netdev->features & NETIF_F_FSO) { 68254a5b21dSYi Zou lport->seq_offload = 1; 68354a5b21dSYi Zou lport->lso_max = netdev->gso_max_size; 68454a5b21dSYi Zou FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", 68554a5b21dSYi Zou lport->lso_max); 68654a5b21dSYi Zou } else { 68754a5b21dSYi Zou lport->seq_offload = 0; 68854a5b21dSYi Zou lport->lso_max = 0; 68954a5b21dSYi Zou } 69054a5b21dSYi Zou 69154a5b21dSYi Zou if (netdev->fcoe_ddp_xid) { 69254a5b21dSYi Zou lport->lro_enabled = 1; 69354a5b21dSYi Zou lport->lro_xid = netdev->fcoe_ddp_xid; 69454a5b21dSYi Zou FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", 69554a5b21dSYi Zou lport->lro_xid); 69654a5b21dSYi Zou } else { 69754a5b21dSYi Zou lport->lro_enabled = 0; 69854a5b21dSYi Zou lport->lro_xid = 0; 69954a5b21dSYi Zou } 70054a5b21dSYi Zou 70154a5b21dSYi Zou mutex_unlock(&lport->lp_mutex); 70254a5b21dSYi Zou } 70354a5b21dSYi Zou 70454a5b21dSYi Zou /** 7051875f27eSRobert Love * fcoe_netdev_config() - Set up net devive for SW FCoE 7061875f27eSRobert Love * @lport: The local port that is associated with the net device 7071875f27eSRobert Love * @netdev: The associated net device 708a703e490SVasu Dev * 7091875f27eSRobert Love * Must be called after fcoe_lport_config() as it will use local port mutex 710a703e490SVasu Dev * 711a703e490SVasu Dev * Returns: 0 for success 712a703e490SVasu Dev */ 7131875f27eSRobert Love static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) 714a703e490SVasu Dev { 715a703e490SVasu Dev u32 mfs; 716a703e490SVasu Dev u64 wwnn, wwpn; 71725024989SChris Leech struct fcoe_interface *fcoe; 718619fe4beSRobert Love struct fcoe_ctlr *ctlr; 719014f5c3fSChris Leech struct fcoe_port *port; 720a703e490SVasu Dev 721a703e490SVasu Dev /* Setup lport private data to point to fcoe softc */ 7221875f27eSRobert Love port = lport_priv(lport); 7238597ae8bSBhanu Prakash Gollapudi fcoe = port->priv; 724619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 725a703e490SVasu Dev 7269a6cf881SHannes Reinecke /* Figure out the VLAN ID, if any */ 727d0d7b10bSParav Pandit if (is_vlan_dev(netdev)) 7289a6cf881SHannes Reinecke lport->vlan = vlan_dev_vlan_id(netdev); 7299a6cf881SHannes Reinecke else 7309a6cf881SHannes Reinecke lport->vlan = 0; 7319a6cf881SHannes Reinecke 732a703e490SVasu Dev /* 733a703e490SVasu Dev * Determine max frame size based on underlying device and optional 734a703e490SVasu Dev * user-configured limit. If the MFS is too low, fcoe_link_ok() 735a703e490SVasu Dev * will return 0, so do this first. 736a703e490SVasu Dev */ 7377221d7e5SYi Zou mfs = netdev->mtu; 7387221d7e5SYi Zou if (netdev->features & NETIF_F_FCOE_MTU) { 7397221d7e5SYi Zou mfs = FCOE_MTU; 7407221d7e5SYi Zou FCOE_NETDEV_DBG(netdev, "Supports FCOE_MTU of %d bytes\n", mfs); 7417221d7e5SYi Zou } 7427221d7e5SYi Zou mfs -= (sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof)); 7431875f27eSRobert Love if (fc_set_mfs(lport, mfs)) 744a703e490SVasu Dev return -EINVAL; 745a703e490SVasu Dev 746a703e490SVasu Dev /* offload features support */ 74754a5b21dSYi Zou fcoe_netdev_features_change(lport, netdev); 748a703e490SVasu Dev 749014f5c3fSChris Leech skb_queue_head_init(&port->fcoe_pending_queue); 750014f5c3fSChris Leech port->fcoe_pending_queue_active = 0; 75113059106SKees Cook timer_setup(&port->timer, fcoe_queue_timer, 0); 752a703e490SVasu Dev 7535e4f8fe7SRobert Love fcoe_link_speed_update(lport); 7545e4f8fe7SRobert Love 7551875f27eSRobert Love if (!lport->vport) { 756dcece412SYi Zou if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) 757619fe4beSRobert Love wwnn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 1, 0); 7581875f27eSRobert Love fc_set_wwnn(lport, wwnn); 759dcece412SYi Zou if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) 760619fe4beSRobert Love wwpn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 761cf4aebcaSVasu Dev 2, 0); 7621875f27eSRobert Love fc_set_wwpn(lport, wwpn); 7639a05753bSChris Leech } 764a703e490SVasu Dev 765a703e490SVasu Dev return 0; 766a703e490SVasu Dev } 767a703e490SVasu Dev 768a703e490SVasu Dev /** 7691875f27eSRobert Love * fcoe_shost_config() - Set up the SCSI host associated with a local port 7701875f27eSRobert Love * @lport: The local port 7711875f27eSRobert Love * @dev: The device associated with the SCSI host 772a703e490SVasu Dev * 773a703e490SVasu Dev * Must be called after fcoe_lport_config() and fcoe_netdev_config() 774a703e490SVasu Dev * 775a703e490SVasu Dev * Returns: 0 for success 776a703e490SVasu Dev */ 7778ba00a4bSVasu Dev static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) 778a703e490SVasu Dev { 779a703e490SVasu Dev int rc = 0; 780a703e490SVasu Dev 781a703e490SVasu Dev /* lport scsi host config */ 7821875f27eSRobert Love lport->host->max_lun = FCOE_MAX_LUN; 7831875f27eSRobert Love lport->host->max_id = FCOE_MAX_FCP_TARGET; 7841875f27eSRobert Love lport->host->max_channel = 0; 785da87bfabSVasu Dev lport->host->max_cmd_len = FCOE_MAX_CMD_LEN; 786da87bfabSVasu Dev 7871875f27eSRobert Love if (lport->vport) 7888ca86f84SYi Zou lport->host->transportt = fcoe_vport_scsi_transport; 789e9084bb8SChris Leech else 7908ca86f84SYi Zou lport->host->transportt = fcoe_nport_scsi_transport; 791a703e490SVasu Dev 792a703e490SVasu Dev /* add the new host to the SCSI-ml */ 7931875f27eSRobert Love rc = scsi_add_host(lport->host, dev); 794a703e490SVasu Dev if (rc) { 7951875f27eSRobert Love FCOE_NETDEV_DBG(fcoe_netdev(lport), "fcoe_shost_config: " 796d5488eb9SRobert Love "error on scsi_add_host\n"); 797a703e490SVasu Dev return rc; 798a703e490SVasu Dev } 7999a05753bSChris Leech 8001875f27eSRobert Love if (!lport->vport) 8014be929beSAlexey Dobriyan fc_host_max_npiv_vports(lport->host) = USHRT_MAX; 8029a05753bSChris Leech 8031875f27eSRobert Love snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE, 8045baa17c3SChris Leech "%s v%s over %s", FCOE_NAME, FCOE_VERSION, 8051875f27eSRobert Love fcoe_netdev(lport)->name); 806a703e490SVasu Dev 807a703e490SVasu Dev return 0; 808a703e490SVasu Dev } 809a703e490SVasu Dev 8106fef3902SNeerav Parikh 8116fef3902SNeerav Parikh /** 8126fef3902SNeerav Parikh * fcoe_fdmi_info() - Get FDMI related info from net devive for SW FCoE 8136fef3902SNeerav Parikh * @lport: The local port that is associated with the net device 8146fef3902SNeerav Parikh * @netdev: The associated net device 8156fef3902SNeerav Parikh * 8166fef3902SNeerav Parikh * Must be called after fcoe_shost_config() as it will use local port mutex 8176fef3902SNeerav Parikh * 8186fef3902SNeerav Parikh */ 8196fef3902SNeerav Parikh static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev) 8206fef3902SNeerav Parikh { 8216fef3902SNeerav Parikh struct fcoe_interface *fcoe; 8226fef3902SNeerav Parikh struct fcoe_port *port; 8236fef3902SNeerav Parikh struct net_device *realdev; 8246fef3902SNeerav Parikh int rc; 8256fef3902SNeerav Parikh 8266fef3902SNeerav Parikh port = lport_priv(lport); 8276fef3902SNeerav Parikh fcoe = port->priv; 8286fef3902SNeerav Parikh realdev = fcoe->realdev; 8296fef3902SNeerav Parikh 8306fef3902SNeerav Parikh /* No FDMI state m/c for NPIV ports */ 8316fef3902SNeerav Parikh if (lport->vport) 8326fef3902SNeerav Parikh return; 8336fef3902SNeerav Parikh 8346fef3902SNeerav Parikh if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) { 835f07d46bbSNeerav Parikh struct netdev_fcoe_hbainfo *fdmi; 836f07d46bbSNeerav Parikh fdmi = kzalloc(sizeof(*fdmi), GFP_KERNEL); 837f07d46bbSNeerav Parikh if (!fdmi) 838f07d46bbSNeerav Parikh return; 839f07d46bbSNeerav Parikh 8406fef3902SNeerav Parikh rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev, 841f07d46bbSNeerav Parikh fdmi); 8426fef3902SNeerav Parikh if (rc) { 8436fef3902SNeerav Parikh printk(KERN_INFO "fcoe: Failed to retrieve FDMI " 8446fef3902SNeerav Parikh "information from netdev.\n"); 8456fef3902SNeerav Parikh return; 8466fef3902SNeerav Parikh } 8476fef3902SNeerav Parikh 8486fef3902SNeerav Parikh snprintf(fc_host_serial_number(lport->host), 8496fef3902SNeerav Parikh FC_SERIAL_NUMBER_SIZE, 8506fef3902SNeerav Parikh "%s", 851f07d46bbSNeerav Parikh fdmi->serial_number); 8526fef3902SNeerav Parikh snprintf(fc_host_manufacturer(lport->host), 8536fef3902SNeerav Parikh FC_SERIAL_NUMBER_SIZE, 8546fef3902SNeerav Parikh "%s", 855f07d46bbSNeerav Parikh fdmi->manufacturer); 8566fef3902SNeerav Parikh snprintf(fc_host_model(lport->host), 8576fef3902SNeerav Parikh FC_SYMBOLIC_NAME_SIZE, 8586fef3902SNeerav Parikh "%s", 859f07d46bbSNeerav Parikh fdmi->model); 8606fef3902SNeerav Parikh snprintf(fc_host_model_description(lport->host), 8616fef3902SNeerav Parikh FC_SYMBOLIC_NAME_SIZE, 8626fef3902SNeerav Parikh "%s", 863f07d46bbSNeerav Parikh fdmi->model_description); 8646fef3902SNeerav Parikh snprintf(fc_host_hardware_version(lport->host), 8656fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8666fef3902SNeerav Parikh "%s", 867f07d46bbSNeerav Parikh fdmi->hardware_version); 8686fef3902SNeerav Parikh snprintf(fc_host_driver_version(lport->host), 8696fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8706fef3902SNeerav Parikh "%s", 871f07d46bbSNeerav Parikh fdmi->driver_version); 8726fef3902SNeerav Parikh snprintf(fc_host_optionrom_version(lport->host), 8736fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8746fef3902SNeerav Parikh "%s", 875f07d46bbSNeerav Parikh fdmi->optionrom_version); 8766fef3902SNeerav Parikh snprintf(fc_host_firmware_version(lport->host), 8776fef3902SNeerav Parikh FC_VERSION_STRING_SIZE, 8786fef3902SNeerav Parikh "%s", 879f07d46bbSNeerav Parikh fdmi->firmware_version); 8806fef3902SNeerav Parikh 8816fef3902SNeerav Parikh /* Enable FDMI lport states */ 8826fef3902SNeerav Parikh lport->fdmi_enabled = 1; 883f07d46bbSNeerav Parikh kfree(fdmi); 8846fef3902SNeerav Parikh } else { 8856fef3902SNeerav Parikh lport->fdmi_enabled = 0; 8866fef3902SNeerav Parikh printk(KERN_INFO "fcoe: No FDMI support.\n"); 8876fef3902SNeerav Parikh } 8886fef3902SNeerav Parikh } 8896fef3902SNeerav Parikh 8901875f27eSRobert Love /** 8911875f27eSRobert Love * fcoe_oem_match() - The match routine for the offloaded exchange manager 8921875f27eSRobert Love * @fp: The I/O frame 893d7179680SVasu Dev * 8941875f27eSRobert Love * This routine will be associated with an exchange manager (EM). When 8951875f27eSRobert Love * the libfc exchange handling code is looking for an EM to use it will 8961875f27eSRobert Love * call this routine and pass it the frame that it wishes to send. This 8971875f27eSRobert Love * routine will return True if the associated EM is to be used and False 8981875f27eSRobert Love * if the echange code should continue looking for an EM. 8991875f27eSRobert Love * 9001875f27eSRobert Love * The offload EM that this routine is associated with will handle any 9011875f27eSRobert Love * packets that are for SCSI read requests. 9021875f27eSRobert Love * 9031ff9918bSKiran Patil * This has been enhanced to work when FCoE stack is operating in target 9041ff9918bSKiran Patil * mode. 9051ff9918bSKiran Patil * 9061875f27eSRobert Love * Returns: True for read types I/O, otherwise returns false. 907d7179680SVasu Dev */ 9087c9c6841SBart Van Assche static bool fcoe_oem_match(struct fc_frame *fp) 909d7179680SVasu Dev { 9101ff9918bSKiran Patil struct fc_frame_header *fh = fc_frame_header_get(fp); 9111ff9918bSKiran Patil struct fcp_cmnd *fcp; 9121ff9918bSKiran Patil 9131ff9918bSKiran Patil if (fc_fcp_is_read(fr_fsp(fp)) && 9141ff9918bSKiran Patil (fr_fsp(fp)->data_len > fcoe_ddp_min)) 9151ff9918bSKiran Patil return true; 916a762dce4SYi Zou else if ((fr_fsp(fp) == NULL) && 917a762dce4SYi Zou (fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) && 918a762dce4SYi Zou (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { 9191ff9918bSKiran Patil fcp = fc_frame_payload_get(fp, sizeof(*fcp)); 920a762dce4SYi Zou if ((fcp->fc_flags & FCP_CFL_WRDATA) && 921a762dce4SYi Zou (ntohl(fcp->fc_dl) > fcoe_ddp_min)) 9221ff9918bSKiran Patil return true; 9231ff9918bSKiran Patil } 9241ff9918bSKiran Patil return false; 925d7179680SVasu Dev } 926d7179680SVasu Dev 927a703e490SVasu Dev /** 9281875f27eSRobert Love * fcoe_em_config() - Allocate and configure an exchange manager 9291875f27eSRobert Love * @lport: The local port that the new EM will be associated with 930a703e490SVasu Dev * 931a703e490SVasu Dev * Returns: 0 on success 932a703e490SVasu Dev */ 9331875f27eSRobert Love static inline int fcoe_em_config(struct fc_lport *lport) 934a703e490SVasu Dev { 9351875f27eSRobert Love struct fcoe_port *port = lport_priv(lport); 9368597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 93725024989SChris Leech struct fcoe_interface *oldfcoe = NULL; 9381d1b88dcSVasu Dev struct net_device *old_real_dev, *cur_real_dev; 939d7179680SVasu Dev u16 min_xid = FCOE_MIN_XID; 940d7179680SVasu Dev u16 max_xid = FCOE_MAX_XID; 941d7179680SVasu Dev 942d7179680SVasu Dev /* 943d7179680SVasu Dev * Check if need to allocate an em instance for 944d7179680SVasu Dev * offload exchange ids to be shared across all VN_PORTs/lport. 945d7179680SVasu Dev */ 9461875f27eSRobert Love if (!lport->lro_enabled || !lport->lro_xid || 9471875f27eSRobert Love (lport->lro_xid >= max_xid)) { 9481875f27eSRobert Love lport->lro_xid = 0; 949d7179680SVasu Dev goto skip_oem; 950d7179680SVasu Dev } 951d7179680SVasu Dev 952d7179680SVasu Dev /* 953d7179680SVasu Dev * Reuse existing offload em instance in case 9541d1b88dcSVasu Dev * it is already allocated on real eth device 955d7179680SVasu Dev */ 956d0d7b10bSParav Pandit if (is_vlan_dev(fcoe->netdev)) 95725024989SChris Leech cur_real_dev = vlan_dev_real_dev(fcoe->netdev); 9581d1b88dcSVasu Dev else 95925024989SChris Leech cur_real_dev = fcoe->netdev; 9601d1b88dcSVasu Dev 96125024989SChris Leech list_for_each_entry(oldfcoe, &fcoe_hostlist, list) { 962d0d7b10bSParav Pandit if (is_vlan_dev(oldfcoe->netdev)) 96325024989SChris Leech old_real_dev = vlan_dev_real_dev(oldfcoe->netdev); 9641d1b88dcSVasu Dev else 96525024989SChris Leech old_real_dev = oldfcoe->netdev; 9661d1b88dcSVasu Dev 9671d1b88dcSVasu Dev if (cur_real_dev == old_real_dev) { 968991cbb60SChris Leech fcoe->oem = oldfcoe->oem; 969d7179680SVasu Dev break; 970d7179680SVasu Dev } 971d7179680SVasu Dev } 972d7179680SVasu Dev 973991cbb60SChris Leech if (fcoe->oem) { 9741875f27eSRobert Love if (!fc_exch_mgr_add(lport, fcoe->oem, fcoe_oem_match)) { 975d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to add " 976d7179680SVasu Dev "offload em:%p on interface:%s\n", 977991cbb60SChris Leech fcoe->oem, fcoe->netdev->name); 978a703e490SVasu Dev return -ENOMEM; 979d7179680SVasu Dev } 980d7179680SVasu Dev } else { 9811875f27eSRobert Love fcoe->oem = fc_exch_mgr_alloc(lport, FC_CLASS_3, 9821875f27eSRobert Love FCOE_MIN_XID, lport->lro_xid, 983d7179680SVasu Dev fcoe_oem_match); 984991cbb60SChris Leech if (!fcoe->oem) { 985d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to allocate " 986d7179680SVasu Dev "em for offload exches on interface:%s\n", 98725024989SChris Leech fcoe->netdev->name); 988d7179680SVasu Dev return -ENOMEM; 989d7179680SVasu Dev } 990d7179680SVasu Dev } 991d7179680SVasu Dev 992d7179680SVasu Dev /* 993d7179680SVasu Dev * Exclude offload EM xid range from next EM xid range. 994d7179680SVasu Dev */ 9951875f27eSRobert Love min_xid += lport->lro_xid + 1; 996d7179680SVasu Dev 997d7179680SVasu Dev skip_oem: 9981875f27eSRobert Love if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, min_xid, max_xid, NULL)) { 999d7179680SVasu Dev printk(KERN_ERR "fcoe_em_config: failed to " 100025024989SChris Leech "allocate em on interface %s\n", fcoe->netdev->name); 1001d7179680SVasu Dev return -ENOMEM; 1002d7179680SVasu Dev } 1003a703e490SVasu Dev 1004a703e490SVasu Dev return 0; 1005a703e490SVasu Dev } 1006a703e490SVasu Dev 1007a703e490SVasu Dev /** 10081875f27eSRobert Love * fcoe_if_destroy() - Tear down a SW FCoE instance 10091875f27eSRobert Love * @lport: The local port to be destroyed 101034ce27bcSVasu Dev * 10117eccdf00SHannes Reinecke * Locking: Must be called with the RTNL mutex held. 10127eccdf00SHannes Reinecke * 1013a703e490SVasu Dev */ 1014af7f85d9SChris Leech static void fcoe_if_destroy(struct fc_lport *lport) 1015a703e490SVasu Dev { 1016b2085a4eSNeerav Parikh struct fcoe_port *port = lport_priv(lport); 1017b2085a4eSNeerav Parikh struct fcoe_interface *fcoe = port->priv; 1018b2085a4eSNeerav Parikh struct net_device *netdev = fcoe->netdev; 1019b2085a4eSNeerav Parikh 1020b2085a4eSNeerav Parikh FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); 1021b2085a4eSNeerav Parikh 1022b2085a4eSNeerav Parikh /* Logout of the fabric */ 1023b2085a4eSNeerav Parikh fc_fabric_logoff(lport); 1024b2085a4eSNeerav Parikh 1025b2085a4eSNeerav Parikh /* Cleanup the fc_lport */ 1026b2085a4eSNeerav Parikh fc_lport_destroy(lport); 1027b2085a4eSNeerav Parikh 1028b2085a4eSNeerav Parikh /* Stop the transmit retry timer */ 1029b2085a4eSNeerav Parikh del_timer_sync(&port->timer); 1030b2085a4eSNeerav Parikh 1031b2085a4eSNeerav Parikh /* Free existing transmit skbs */ 1032b2085a4eSNeerav Parikh fcoe_clean_pending_queue(lport); 1033b2085a4eSNeerav Parikh 1034b2085a4eSNeerav Parikh if (!is_zero_ether_addr(port->data_src_addr)) 1035b2085a4eSNeerav Parikh dev_uc_del(netdev, port->data_src_addr); 1036433eba04SVasu Dev if (lport->vport) 1037433eba04SVasu Dev synchronize_net(); 1038433eba04SVasu Dev else 1039433eba04SVasu Dev fcoe_interface_remove(fcoe); 1040b2085a4eSNeerav Parikh 104154b649f8SChris Leech /* Free queued packets for the per-CPU receive threads */ 104254b649f8SChris Leech fcoe_percpu_clean(lport); 104354b649f8SChris Leech 1044a703e490SVasu Dev /* Detach from the scsi-ml */ 1045af7f85d9SChris Leech fc_remove_host(lport->host); 1046af7f85d9SChris Leech scsi_remove_host(lport->host); 1047a703e490SVasu Dev 104880e736f8SYi Zou /* Destroy lport scsi_priv */ 104980e736f8SYi Zou fc_fcp_destroy(lport); 105080e736f8SYi Zou 1051a703e490SVasu Dev /* There are no more rports or I/O, free the EM */ 1052af7f85d9SChris Leech fc_exch_mgr_free(lport); 1053a703e490SVasu Dev 1054a703e490SVasu Dev /* Free memory used by statistical counters */ 1055af7f85d9SChris Leech fc_lport_free_stats(lport); 1056a703e490SVasu Dev 10573cab4468SVasu Dev /* 10583cab4468SVasu Dev * Release the Scsi_Host for vport but hold on to 10593cab4468SVasu Dev * master lport until it fcoe interface fully cleaned-up. 10603cab4468SVasu Dev */ 10613cab4468SVasu Dev if (lport->vport) 1062af7f85d9SChris Leech scsi_host_put(lport->host); 1063a703e490SVasu Dev } 1064a703e490SVasu Dev 10651875f27eSRobert Love /** 10661875f27eSRobert Love * fcoe_ddp_setup() - Call a LLD's ddp_setup through the net device 10671875f27eSRobert Love * @lport: The local port to setup DDP for 10681875f27eSRobert Love * @xid: The exchange ID for this DDP transfer 10691875f27eSRobert Love * @sgl: The scatterlist describing this transfer 10701875f27eSRobert Love * @sgc: The number of sg items 1071a703e490SVasu Dev * 10721875f27eSRobert Love * Returns: 0 if the DDP context was not configured 1073a703e490SVasu Dev */ 10741875f27eSRobert Love static int fcoe_ddp_setup(struct fc_lport *lport, u16 xid, 1075a703e490SVasu Dev struct scatterlist *sgl, unsigned int sgc) 1076a703e490SVasu Dev { 10771875f27eSRobert Love struct net_device *netdev = fcoe_netdev(lport); 1078a703e490SVasu Dev 10791875f27eSRobert Love if (netdev->netdev_ops->ndo_fcoe_ddp_setup) 10801875f27eSRobert Love return netdev->netdev_ops->ndo_fcoe_ddp_setup(netdev, 10811875f27eSRobert Love xid, sgl, 10821875f27eSRobert Love sgc); 1083a703e490SVasu Dev 1084a703e490SVasu Dev return 0; 1085a703e490SVasu Dev } 1086a703e490SVasu Dev 1087a703e490SVasu Dev /** 108871f89491SYi Zou * fcoe_ddp_target() - Call a LLD's ddp_target through the net device 108971f89491SYi Zou * @lport: The local port to setup DDP for 109071f89491SYi Zou * @xid: The exchange ID for this DDP transfer 109171f89491SYi Zou * @sgl: The scatterlist describing this transfer 109271f89491SYi Zou * @sgc: The number of sg items 109371f89491SYi Zou * 109471f89491SYi Zou * Returns: 0 if the DDP context was not configured 109571f89491SYi Zou */ 109671f89491SYi Zou static int fcoe_ddp_target(struct fc_lport *lport, u16 xid, 109771f89491SYi Zou struct scatterlist *sgl, unsigned int sgc) 109871f89491SYi Zou { 109971f89491SYi Zou struct net_device *netdev = fcoe_netdev(lport); 110071f89491SYi Zou 110171f89491SYi Zou if (netdev->netdev_ops->ndo_fcoe_ddp_target) 110271f89491SYi Zou return netdev->netdev_ops->ndo_fcoe_ddp_target(netdev, xid, 110371f89491SYi Zou sgl, sgc); 110471f89491SYi Zou 110571f89491SYi Zou return 0; 110671f89491SYi Zou } 110771f89491SYi Zou 110871f89491SYi Zou 110971f89491SYi Zou /** 11101875f27eSRobert Love * fcoe_ddp_done() - Call a LLD's ddp_done through the net device 11111875f27eSRobert Love * @lport: The local port to complete DDP on 11121875f27eSRobert Love * @xid: The exchange ID for this DDP transfer 1113a703e490SVasu Dev * 11141875f27eSRobert Love * Returns: the length of data that have been completed by DDP 11151875f27eSRobert Love */ 11161875f27eSRobert Love static int fcoe_ddp_done(struct fc_lport *lport, u16 xid) 11171875f27eSRobert Love { 11181875f27eSRobert Love struct net_device *netdev = fcoe_netdev(lport); 11191875f27eSRobert Love 11201875f27eSRobert Love if (netdev->netdev_ops->ndo_fcoe_ddp_done) 11211875f27eSRobert Love return netdev->netdev_ops->ndo_fcoe_ddp_done(netdev, xid); 11221875f27eSRobert Love return 0; 11231875f27eSRobert Love } 11241875f27eSRobert Love 11251875f27eSRobert Love /** 11261875f27eSRobert Love * fcoe_if_create() - Create a FCoE instance on an interface 11271875f27eSRobert Love * @fcoe: The FCoE interface to create a local port on 11281875f27eSRobert Love * @parent: The device pointer to be the parent in sysfs for the SCSI host 11291875f27eSRobert Love * @npiv: Indicates if the port is a vport or not 11301875f27eSRobert Love * 11311875f27eSRobert Love * Creates a fc_lport instance and a Scsi_Host instance and configure them. 1132a703e490SVasu Dev * 1133af7f85d9SChris Leech * Returns: The allocated fc_lport or an error pointer 1134a703e490SVasu Dev */ 1135030f4e00SChris Leech static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, 11369a05753bSChris Leech struct device *parent, int npiv) 1137a703e490SVasu Dev { 1138619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 11391875f27eSRobert Love struct net_device *netdev = fcoe->netdev; 114072fa396bSVasu Dev struct fc_lport *lport, *n_port; 1141014f5c3fSChris Leech struct fcoe_port *port; 114272fa396bSVasu Dev struct Scsi_Host *shost; 11431875f27eSRobert Love int rc; 11449a05753bSChris Leech /* 11459a05753bSChris Leech * parent is only a vport if npiv is 1, 11469a05753bSChris Leech * but we'll only use vport in that case so go ahead and set it 11479a05753bSChris Leech */ 11489a05753bSChris Leech struct fc_vport *vport = dev_to_vport(parent); 1149a703e490SVasu Dev 1150d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Create Interface\n"); 1151a703e490SVasu Dev 115272fa396bSVasu Dev if (!npiv) 115372fa396bSVasu Dev lport = libfc_host_alloc(&fcoe_shost_template, sizeof(*port)); 115472fa396bSVasu Dev else 115572fa396bSVasu Dev lport = libfc_vport_create(vport, sizeof(*port)); 115672fa396bSVasu Dev 115786221969SChris Leech if (!lport) { 1158014f5c3fSChris Leech FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); 1159014f5c3fSChris Leech rc = -ENOMEM; 1160030f4e00SChris Leech goto out; 1161014f5c3fSChris Leech } 1162014f5c3fSChris Leech port = lport_priv(lport); 11632e70e241SChris Leech port->lport = lport; 11648597ae8bSBhanu Prakash Gollapudi port->priv = fcoe; 116566524ec9SYi Zou port->get_netdev = fcoe_netdev; 11668597ae8bSBhanu Prakash Gollapudi port->max_queue_depth = FCOE_MAX_QUEUE_DEPTH; 11678597ae8bSBhanu Prakash Gollapudi port->min_queue_depth = FCOE_MIN_QUEUE_DEPTH; 11682e70e241SChris Leech INIT_WORK(&port->destroy_work, fcoe_destroy_work); 1169a703e490SVasu Dev 1170f9184df3SNeil Horman /* 1171f9184df3SNeil Horman * Need to add the lport to the hostlist 1172f9184df3SNeil Horman * so we catch NETDEV_CHANGE events. 1173f9184df3SNeil Horman */ 1174f9184df3SNeil Horman fcoe_hostlist_add(lport); 1175f9184df3SNeil Horman 11761875f27eSRobert Love /* configure a fc_lport including the exchange manager */ 1177af7f85d9SChris Leech rc = fcoe_lport_config(lport); 1178a703e490SVasu Dev if (rc) { 1179d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure lport for the " 1180d5488eb9SRobert Love "interface\n"); 1181a703e490SVasu Dev goto out_host_put; 1182a703e490SVasu Dev } 1183a703e490SVasu Dev 11849a05753bSChris Leech if (npiv) { 11859f8f3aa6SChris Leech FCOE_NETDEV_DBG(netdev, "Setting vport names, " 11869f8f3aa6SChris Leech "%16.16llx %16.16llx\n", 11879a05753bSChris Leech vport->node_name, vport->port_name); 11889a05753bSChris Leech fc_set_wwnn(lport, vport->node_name); 11899a05753bSChris Leech fc_set_wwpn(lport, vport->port_name); 11909a05753bSChris Leech } 11919a05753bSChris Leech 1192ab6b85c1SVasu Dev /* configure lport network properties */ 1193af7f85d9SChris Leech rc = fcoe_netdev_config(lport, netdev); 1194ab6b85c1SVasu Dev if (rc) { 1195d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " 1196d5488eb9SRobert Love "interface\n"); 119754b649f8SChris Leech goto out_lp_destroy; 1198ab6b85c1SVasu Dev } 119997c8389dSJoe Eykholt 1200a703e490SVasu Dev /* configure lport scsi host properties */ 12018ba00a4bSVasu Dev rc = fcoe_shost_config(lport, parent); 1202a703e490SVasu Dev if (rc) { 1203d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " 1204d5488eb9SRobert Love "interface\n"); 120554b649f8SChris Leech goto out_lp_destroy; 1206a703e490SVasu Dev } 1207a703e490SVasu Dev 1208a703e490SVasu Dev /* Initialize the library */ 1209619fe4beSRobert Love rc = fcoe_libfc_config(lport, ctlr, &fcoe_libfc_fcn_templ, 1); 1210a703e490SVasu Dev if (rc) { 1211d5488eb9SRobert Love FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " 1212d5488eb9SRobert Love "interface\n"); 1213a703e490SVasu Dev goto out_lp_destroy; 1214a703e490SVasu Dev } 1215a703e490SVasu Dev 12166fef3902SNeerav Parikh /* Initialized FDMI information */ 12176fef3902SNeerav Parikh fcoe_fdmi_info(lport, netdev); 12186fef3902SNeerav Parikh 1219e8af4d43SVasu Dev /* 1220e8af4d43SVasu Dev * fcoe_em_alloc() and fcoe_hostlist_add() both 12219a05753bSChris Leech * need to be atomic with respect to other changes to the 12229a05753bSChris Leech * hostlist since fcoe_em_alloc() looks for an existing EM 1223e8af4d43SVasu Dev * instance on host list updated by fcoe_hostlist_add(). 1224c863df33SChris Leech * 12259a05753bSChris Leech * This is currently handled through the fcoe_config_mutex 12269a05753bSChris Leech * begin held. 1227e8af4d43SVasu Dev */ 122872fa396bSVasu Dev if (!npiv) 122996316099SVasu Dev /* lport exch manager allocation */ 1230af7f85d9SChris Leech rc = fcoe_em_config(lport); 123172fa396bSVasu Dev else { 123272fa396bSVasu Dev shost = vport_to_shost(vport); 123372fa396bSVasu Dev n_port = shost_priv(shost); 123472fa396bSVasu Dev rc = fc_exch_mgr_list_clone(n_port, lport); 123596316099SVasu Dev } 123672fa396bSVasu Dev 123772fa396bSVasu Dev if (rc) { 123872fa396bSVasu Dev FCOE_NETDEV_DBG(netdev, "Could not configure the EM\n"); 123972fa396bSVasu Dev goto out_lp_destroy; 12409a05753bSChris Leech } 124196316099SVasu Dev 1242af7f85d9SChris Leech return lport; 1243a703e490SVasu Dev 1244a703e490SVasu Dev out_lp_destroy: 1245af7f85d9SChris Leech fc_exch_mgr_free(lport); 1246a703e490SVasu Dev out_host_put: 1247f9184df3SNeil Horman fcoe_hostlist_del(lport); 1248af7f85d9SChris Leech scsi_host_put(lport->host); 1249af7f85d9SChris Leech out: 1250af7f85d9SChris Leech return ERR_PTR(rc); 1251a703e490SVasu Dev } 1252a703e490SVasu Dev 1253a703e490SVasu Dev /** 12541875f27eSRobert Love * fcoe_if_init() - Initialization routine for fcoe.ko 12551875f27eSRobert Love * 12561875f27eSRobert Love * Attaches the SW FCoE transport to the FC transport 1257a703e490SVasu Dev * 1258a703e490SVasu Dev * Returns: 0 on success 1259a703e490SVasu Dev */ 1260a703e490SVasu Dev static int __init fcoe_if_init(void) 1261a703e490SVasu Dev { 1262a703e490SVasu Dev /* attach to scsi transport */ 12638ca86f84SYi Zou fcoe_nport_scsi_transport = 12648ca86f84SYi Zou fc_attach_transport(&fcoe_nport_fc_functions); 12658ca86f84SYi Zou fcoe_vport_scsi_transport = 12668ca86f84SYi Zou fc_attach_transport(&fcoe_vport_fc_functions); 1267a703e490SVasu Dev 12688ca86f84SYi Zou if (!fcoe_nport_scsi_transport) { 1269d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); 1270a703e490SVasu Dev return -ENODEV; 1271a703e490SVasu Dev } 1272a703e490SVasu Dev 1273a703e490SVasu Dev return 0; 1274a703e490SVasu Dev } 1275a703e490SVasu Dev 1276a703e490SVasu Dev /** 12771875f27eSRobert Love * fcoe_if_exit() - Tear down fcoe.ko 12781875f27eSRobert Love * 12791875f27eSRobert Love * Detaches the SW FCoE transport from the FC transport 1280a703e490SVasu Dev * 1281a703e490SVasu Dev * Returns: 0 on success 1282a703e490SVasu Dev */ 12837c9c6841SBart Van Assche static int __exit fcoe_if_exit(void) 1284a703e490SVasu Dev { 12858ca86f84SYi Zou fc_release_transport(fcoe_nport_scsi_transport); 12868ca86f84SYi Zou fc_release_transport(fcoe_vport_scsi_transport); 12878ca86f84SYi Zou fcoe_nport_scsi_transport = NULL; 12888ca86f84SYi Zou fcoe_vport_scsi_transport = NULL; 1289a703e490SVasu Dev return 0; 1290a703e490SVasu Dev } 1291a703e490SVasu Dev 12924b9bc86dSSebastian Andrzej Siewior static void fcoe_thread_cleanup_local(unsigned int cpu) 1293a703e490SVasu Dev { 1294a703e490SVasu Dev struct page *crc_eof; 12954b9bc86dSSebastian Andrzej Siewior struct fcoe_percpu_s *p; 1296a703e490SVasu Dev 12974b9bc86dSSebastian Andrzej Siewior p = per_cpu_ptr(&fcoe_percpu, cpu); 1298a703e490SVasu Dev spin_lock_bh(&p->fcoe_rx_list.lock); 1299a703e490SVasu Dev crc_eof = p->crc_eof_page; 1300a703e490SVasu Dev p->crc_eof_page = NULL; 1301a703e490SVasu Dev p->crc_eof_offset = 0; 1302a703e490SVasu Dev spin_unlock_bh(&p->fcoe_rx_list.lock); 1303a703e490SVasu Dev 1304a703e490SVasu Dev if (crc_eof) 1305a703e490SVasu Dev put_page(crc_eof); 13064b9bc86dSSebastian Andrzej Siewior flush_work(&p->work); 1307a703e490SVasu Dev } 1308a703e490SVasu Dev 1309a703e490SVasu Dev /** 1310064287eeSKiran Patil * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming 1311064287eeSKiran Patil * command. 1312064287eeSKiran Patil * 1313d272281cSVasu Dev * This routine selects next CPU based on cpumask to distribute 1314d272281cSVasu Dev * incoming requests in round robin. 1315064287eeSKiran Patil * 1316d272281cSVasu Dev * Returns: int CPU number 1317064287eeSKiran Patil */ 1318d272281cSVasu Dev static inline unsigned int fcoe_select_cpu(void) 1319064287eeSKiran Patil { 1320064287eeSKiran Patil static unsigned int selected_cpu; 1321064287eeSKiran Patil 1322064287eeSKiran Patil selected_cpu = cpumask_next(selected_cpu, cpu_online_mask); 1323064287eeSKiran Patil if (selected_cpu >= nr_cpu_ids) 1324064287eeSKiran Patil selected_cpu = cpumask_first(cpu_online_mask); 1325d272281cSVasu Dev 1326064287eeSKiran Patil return selected_cpu; 1327064287eeSKiran Patil } 1328064287eeSKiran Patil 1329064287eeSKiran Patil /** 13301875f27eSRobert Love * fcoe_rcv() - Receive packets from a net device 13311875f27eSRobert Love * @skb: The received packet 13321875f27eSRobert Love * @netdev: The net device that the packet was received on 13331875f27eSRobert Love * @ptype: The packet type context 13341875f27eSRobert Love * @olddev: The last device net device 1335a703e490SVasu Dev * 13361875f27eSRobert Love * This routine is called by NET_RX_SOFTIRQ. It receives a packet, builds a 13371875f27eSRobert Love * FC frame and passes the frame to libfc. 1338a703e490SVasu Dev * 1339a703e490SVasu Dev * Returns: 0 for success 1340a703e490SVasu Dev */ 13417c9c6841SBart Van Assche static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, 1342a703e490SVasu Dev struct packet_type *ptype, struct net_device *olddev) 1343a703e490SVasu Dev { 13441875f27eSRobert Love struct fc_lport *lport; 1345a703e490SVasu Dev struct fcoe_rcv_info *fr; 1346619fe4beSRobert Love struct fcoe_ctlr *ctlr; 1347259ad85dSChris Leech struct fcoe_interface *fcoe; 1348a703e490SVasu Dev struct fc_frame_header *fh; 1349a703e490SVasu Dev struct fcoe_percpu_s *fps; 1350519e5135SVasu Dev struct ethhdr *eh; 1351b2f0091fSVasu Dev unsigned int cpu; 1352a703e490SVasu Dev 1353259ad85dSChris Leech fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); 1354619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1355619fe4beSRobert Love lport = ctlr->lp; 13561875f27eSRobert Love if (unlikely(!lport)) { 1357465b87bfSBart Van Assche FCOE_NETDEV_DBG(netdev, "Cannot find hba structure\n"); 1358a703e490SVasu Dev goto err2; 1359a703e490SVasu Dev } 13601875f27eSRobert Love if (!lport->link_up) 136197c8389dSJoe Eykholt goto err2; 1362a703e490SVasu Dev 1363465b87bfSBart Van Assche FCOE_NETDEV_DBG(netdev, 1364465b87bfSBart Van Assche "skb_info: len:%d data_len:%d head:%p data:%p tail:%p end:%p sum:%d dev:%s\n", 1365d5488eb9SRobert Love skb->len, skb->data_len, skb->head, skb->data, 1366d5488eb9SRobert Love skb_tail_pointer(skb), skb_end_pointer(skb), 1367d5488eb9SRobert Love skb->csum, skb->dev ? skb->dev->name : "<NULL>"); 1368a703e490SVasu Dev 13698b612434SNeil Horman 13708b612434SNeil Horman skb = skb_share_check(skb, GFP_ATOMIC); 13718b612434SNeil Horman 13728b612434SNeil Horman if (skb == NULL) 13738b612434SNeil Horman return NET_RX_DROP; 13748b612434SNeil Horman 1375519e5135SVasu Dev eh = eth_hdr(skb); 1376519e5135SVasu Dev 1377619fe4beSRobert Love if (is_fip_mode(ctlr) && 13786942df7fSJoe Perches !ether_addr_equal(eh->h_source, ctlr->dest_addr)) { 1379519e5135SVasu Dev FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n", 1380519e5135SVasu Dev eh->h_source); 1381a703e490SVasu Dev goto err; 1382a703e490SVasu Dev } 1383a703e490SVasu Dev 1384a703e490SVasu Dev /* 1385a703e490SVasu Dev * Check for minimum frame length, and make sure required FCoE 1386a703e490SVasu Dev * and FC headers are pulled into the linear data area. 1387a703e490SVasu Dev */ 1388a703e490SVasu Dev if (unlikely((skb->len < FCOE_MIN_FRAME) || 1389a703e490SVasu Dev !pskb_may_pull(skb, FCOE_HEADER_LEN))) 1390a703e490SVasu Dev goto err; 1391a703e490SVasu Dev 1392a703e490SVasu Dev skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); 1393a703e490SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 1394a703e490SVasu Dev 13950ee31cb5SRobert Love if (ntoh24(&eh->h_dest[3]) != ntoh24(fh->fh_d_id)) { 13960ee31cb5SRobert Love FCOE_NETDEV_DBG(netdev, "FC frame d_id mismatch with MAC:%pM\n", 13970ee31cb5SRobert Love eh->h_dest); 13980ee31cb5SRobert Love goto err; 13990ee31cb5SRobert Love } 14000ee31cb5SRobert Love 1401a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 14021875f27eSRobert Love fr->fr_dev = lport; 1403a703e490SVasu Dev 1404a703e490SVasu Dev /* 1405b2f0091fSVasu Dev * In case the incoming frame's exchange is originated from 1406b2f0091fSVasu Dev * the initiator, then received frame's exchange id is ANDed 1407b2f0091fSVasu Dev * with fc_cpu_mask bits to get the same cpu on which exchange 1408d272281cSVasu Dev * was originated, otherwise select cpu using rx exchange id 1409d272281cSVasu Dev * or fcoe_select_cpu(). 1410a703e490SVasu Dev */ 1411b2f0091fSVasu Dev if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) 1412b2f0091fSVasu Dev cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; 1413064287eeSKiran Patil else { 1414d272281cSVasu Dev if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN) 1415d272281cSVasu Dev cpu = fcoe_select_cpu(); 1416d272281cSVasu Dev else 141729bdd2bbSKiran Patil cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask; 1418064287eeSKiran Patil } 1419324f6678SVasu Dev 1420324f6678SVasu Dev if (cpu >= nr_cpu_ids) 1421324f6678SVasu Dev goto err; 1422324f6678SVasu Dev 1423a703e490SVasu Dev fps = &per_cpu(fcoe_percpu, cpu); 142494aa29f2SNeil Horman spin_lock(&fps->fcoe_rx_list.lock); 1425a703e490SVasu Dev /* 1426a703e490SVasu Dev * We now have a valid CPU that we're targeting for 1427a703e490SVasu Dev * this skb. We also have this receive thread locked, 1428a703e490SVasu Dev * so we're free to queue skbs into it's queue. 1429a703e490SVasu Dev */ 1430859b7b64SChris Leech 14315e70c4c4SNeil Horman /* 14325e70c4c4SNeil Horman * Note: We used to have a set of conditions under which we would 14335e70c4c4SNeil Horman * call fcoe_recv_frame directly, rather than queuing to the rx list 14345e70c4c4SNeil Horman * as it could save a few cycles, but doing so is prohibited, as 14355e70c4c4SNeil Horman * fcoe_recv_frame has several paths that may sleep, which is forbidden 14365e70c4c4SNeil Horman * in softirq context. 1437859b7b64SChris Leech */ 1438a703e490SVasu Dev __skb_queue_tail(&fps->fcoe_rx_list, skb); 14394b9bc86dSSebastian Andrzej Siewior schedule_work_on(cpu, &fps->work); 144094aa29f2SNeil Horman spin_unlock(&fps->fcoe_rx_list.lock); 1441a703e490SVasu Dev 144234bac2efSNeil Horman return NET_RX_SUCCESS; 1443a703e490SVasu Dev err: 14441bd49b48SVasu Dev per_cpu_ptr(lport->stats, get_cpu())->ErrorFrames++; 1445f018b73aSJoe Eykholt put_cpu(); 1446a703e490SVasu Dev err2: 1447a703e490SVasu Dev kfree_skb(skb); 144834bac2efSNeil Horman return NET_RX_DROP; 1449a703e490SVasu Dev } 1450a703e490SVasu Dev 1451a703e490SVasu Dev /** 14528597ae8bSBhanu Prakash Gollapudi * fcoe_alloc_paged_crc_eof() - Allocate a page to be used for the trailer CRC 14531875f27eSRobert Love * @skb: The packet to be transmitted 14541875f27eSRobert Love * @tlen: The total length of the trailer 14551875f27eSRobert Love * 1456a703e490SVasu Dev * Returns: 0 for success 1457a703e490SVasu Dev */ 14588597ae8bSBhanu Prakash Gollapudi static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen) 1459a703e490SVasu Dev { 1460a703e490SVasu Dev struct fcoe_percpu_s *fps; 14618597ae8bSBhanu Prakash Gollapudi int rc; 1462a703e490SVasu Dev 1463a703e490SVasu Dev fps = &get_cpu_var(fcoe_percpu); 14648597ae8bSBhanu Prakash Gollapudi rc = fcoe_get_paged_crc_eof(skb, tlen, fps); 1465a703e490SVasu Dev put_cpu_var(fcoe_percpu); 1466a703e490SVasu Dev 14678597ae8bSBhanu Prakash Gollapudi return rc; 1468a703e490SVasu Dev } 1469a703e490SVasu Dev 1470a703e490SVasu Dev /** 14711875f27eSRobert Love * fcoe_xmit() - Transmit a FCoE frame 14721875f27eSRobert Love * @lport: The local port that the frame is to be transmitted for 14731875f27eSRobert Love * @fp: The frame to be transmitted 1474a703e490SVasu Dev * 1475a703e490SVasu Dev * Return: 0 for success 1476a703e490SVasu Dev */ 14777c9c6841SBart Van Assche static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) 1478a703e490SVasu Dev { 14794bb6b515SVasu Dev int wlen; 1480a703e490SVasu Dev u32 crc; 1481a703e490SVasu Dev struct ethhdr *eh; 1482a703e490SVasu Dev struct fcoe_crc_eof *cp; 1483a703e490SVasu Dev struct sk_buff *skb; 14841bd49b48SVasu Dev struct fc_stats *stats; 1485a703e490SVasu Dev struct fc_frame_header *fh; 1486a703e490SVasu Dev unsigned int hlen; /* header length implies the version */ 1487a703e490SVasu Dev unsigned int tlen; /* trailer length */ 1488a703e490SVasu Dev unsigned int elen; /* eth header, may include vlan */ 14891875f27eSRobert Love struct fcoe_port *port = lport_priv(lport); 14908597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 1491619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 1492a703e490SVasu Dev u8 sof, eof; 1493a703e490SVasu Dev struct fcoe_hdr *hp; 1494a703e490SVasu Dev 1495a703e490SVasu Dev WARN_ON((fr_len(fp) % sizeof(u32)) != 0); 1496a703e490SVasu Dev 1497a703e490SVasu Dev fh = fc_frame_header_get(fp); 149897c8389dSJoe Eykholt skb = fp_skb(fp); 149997c8389dSJoe Eykholt wlen = skb->len / FCOE_WORD_TO_BYTE; 150097c8389dSJoe Eykholt 15011875f27eSRobert Love if (!lport->link_up) { 15023caf02eeSDan Carpenter kfree_skb(skb); 150397c8389dSJoe Eykholt return 0; 1504a703e490SVasu Dev } 1505a703e490SVasu Dev 15069860eeb4SJoe Eykholt if (unlikely(fh->fh_type == FC_TYPE_ELS) && 1507619fe4beSRobert Love fcoe_ctlr_els_send(ctlr, lport, skb)) 150897c8389dSJoe Eykholt return 0; 150997c8389dSJoe Eykholt 1510a703e490SVasu Dev sof = fr_sof(fp); 1511a703e490SVasu Dev eof = fr_eof(fp); 1512a703e490SVasu Dev 15134e57e1cbSVasu Dev elen = sizeof(struct ethhdr); 1514a703e490SVasu Dev hlen = sizeof(struct fcoe_hdr); 1515a703e490SVasu Dev tlen = sizeof(struct fcoe_crc_eof); 1516a703e490SVasu Dev wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; 1517a703e490SVasu Dev 1518a703e490SVasu Dev /* crc offload */ 15191875f27eSRobert Love if (likely(lport->crc_offload)) { 1520253aab05STom Herbert skb->ip_summed = CHECKSUM_PARTIAL; 1521a703e490SVasu Dev skb->csum_start = skb_headroom(skb); 1522a703e490SVasu Dev skb->csum_offset = skb->len; 1523a703e490SVasu Dev crc = 0; 1524a703e490SVasu Dev } else { 1525a703e490SVasu Dev skb->ip_summed = CHECKSUM_NONE; 1526a703e490SVasu Dev crc = fcoe_fc_crc(fp); 1527a703e490SVasu Dev } 1528a703e490SVasu Dev 1529014f5c3fSChris Leech /* copy port crc and eof to the skb buff */ 1530a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 1531a703e490SVasu Dev skb_frag_t *frag; 15328597ae8bSBhanu Prakash Gollapudi if (fcoe_alloc_paged_crc_eof(skb, tlen)) { 1533a703e490SVasu Dev kfree_skb(skb); 1534a703e490SVasu Dev return -ENOMEM; 1535a703e490SVasu Dev } 1536a703e490SVasu Dev frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; 153777dfce07SCong Wang cp = kmap_atomic(skb_frag_page(frag)) 1538a703e490SVasu Dev + frag->page_offset; 1539a703e490SVasu Dev } else { 15404df864c1SJohannes Berg cp = skb_put(skb, tlen); 1541a703e490SVasu Dev } 1542a703e490SVasu Dev 1543a703e490SVasu Dev memset(cp, 0, sizeof(*cp)); 1544a703e490SVasu Dev cp->fcoe_eof = eof; 1545a703e490SVasu Dev cp->fcoe_crc32 = cpu_to_le32(~crc); 1546a703e490SVasu Dev 1547a703e490SVasu Dev if (skb_is_nonlinear(skb)) { 154877dfce07SCong Wang kunmap_atomic(cp); 1549a703e490SVasu Dev cp = NULL; 1550a703e490SVasu Dev } 1551a703e490SVasu Dev 1552014f5c3fSChris Leech /* adjust skb network/transport offsets to match mac/fcoe/port */ 1553a703e490SVasu Dev skb_push(skb, elen + hlen); 1554a703e490SVasu Dev skb_reset_mac_header(skb); 1555a703e490SVasu Dev skb_reset_network_header(skb); 1556a703e490SVasu Dev skb->mac_len = elen; 1557a703e490SVasu Dev skb->protocol = htons(ETH_P_FCOE); 155831c37a6fSNeerav Parikh skb->priority = fcoe->priority; 15596f6c2aa3Sjohn fastabend 1560d0d7b10bSParav Pandit if (is_vlan_dev(fcoe->netdev) && 1561f646968fSPatrick McHardy fcoe->realdev->features & NETIF_F_HW_VLAN_CTAG_TX) { 15622884d423SRobert Love /* must set skb->dev before calling vlan_put_tag */ 1563d1483bb9SVasu Dev skb->dev = fcoe->realdev; 1564b960a0acSJiri Pirko __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 15652884d423SRobert Love vlan_dev_vlan_id(fcoe->netdev)); 1566d1483bb9SVasu Dev } else 15673fe9a0baSChris Leech skb->dev = fcoe->netdev; 1568a703e490SVasu Dev 1569a703e490SVasu Dev /* fill up mac and fcoe headers */ 1570a703e490SVasu Dev eh = eth_hdr(skb); 1571a703e490SVasu Dev eh->h_proto = htons(ETH_P_FCOE); 1572619fe4beSRobert Love memcpy(eh->h_dest, ctlr->dest_addr, ETH_ALEN); 1573619fe4beSRobert Love if (ctlr->map_dest) 1574cd229e42SJoe Eykholt memcpy(eh->h_dest + 3, fh->fh_d_id, 3); 1575a703e490SVasu Dev 1576619fe4beSRobert Love if (unlikely(ctlr->flogi_oxid != FC_XID_UNKNOWN)) 1577619fe4beSRobert Love memcpy(eh->h_source, ctlr->ctl_src_addr, ETH_ALEN); 1578a703e490SVasu Dev else 157911b56188SChris Leech memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); 1580a703e490SVasu Dev 1581a703e490SVasu Dev hp = (struct fcoe_hdr *)(eh + 1); 1582a703e490SVasu Dev memset(hp, 0, sizeof(*hp)); 1583a703e490SVasu Dev if (FC_FCOE_VER) 1584a703e490SVasu Dev FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); 1585a703e490SVasu Dev hp->fcoe_sof = sof; 1586a703e490SVasu Dev 1587a703e490SVasu Dev /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ 15881875f27eSRobert Love if (lport->seq_offload && fr_max_payload(fp)) { 1589a703e490SVasu Dev skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; 1590a703e490SVasu Dev skb_shinfo(skb)->gso_size = fr_max_payload(fp); 1591a703e490SVasu Dev } else { 1592a703e490SVasu Dev skb_shinfo(skb)->gso_type = 0; 1593a703e490SVasu Dev skb_shinfo(skb)->gso_size = 0; 1594a703e490SVasu Dev } 1595a703e490SVasu Dev /* update tx stats: regardless if LLD fails */ 15961bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 1597a703e490SVasu Dev stats->TxFrames++; 1598a703e490SVasu Dev stats->TxWords += wlen; 1599f018b73aSJoe Eykholt put_cpu(); 1600a703e490SVasu Dev 1601a703e490SVasu Dev /* send down to lld */ 16021875f27eSRobert Love fr_dev(fp) = lport; 1603980f5156SVasu Dev fcoe_port_send(port, skb); 1604a703e490SVasu Dev return 0; 1605a703e490SVasu Dev } 1606a703e490SVasu Dev 1607a703e490SVasu Dev /** 160852ee8321SVasu Dev * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC 160952ee8321SVasu Dev * @lport: The local port the frame was received on 161052ee8321SVasu Dev * @fp: The received frame 161152ee8321SVasu Dev * 161252ee8321SVasu Dev * Return: 0 on passing filtering checks 161352ee8321SVasu Dev */ 161452ee8321SVasu Dev static inline int fcoe_filter_frames(struct fc_lport *lport, 161552ee8321SVasu Dev struct fc_frame *fp) 161652ee8321SVasu Dev { 1617619fe4beSRobert Love struct fcoe_ctlr *ctlr; 161852ee8321SVasu Dev struct fcoe_interface *fcoe; 161952ee8321SVasu Dev struct fc_frame_header *fh; 162052ee8321SVasu Dev struct sk_buff *skb = (struct sk_buff *)fp; 16211bd49b48SVasu Dev struct fc_stats *stats; 162252ee8321SVasu Dev 162352ee8321SVasu Dev /* 162452ee8321SVasu Dev * We only check CRC if no offload is available and if it is 162552ee8321SVasu Dev * it's solicited data, in which case, the FCP layer would 162652ee8321SVasu Dev * check it during the copy. 162752ee8321SVasu Dev */ 162852ee8321SVasu Dev if (lport->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY) 162952ee8321SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 163052ee8321SVasu Dev else 163152ee8321SVasu Dev fr_flags(fp) |= FCPHF_CRC_UNCHECKED; 163252ee8321SVasu Dev 163352ee8321SVasu Dev fh = (struct fc_frame_header *) skb_transport_header(skb); 163452ee8321SVasu Dev fh = fc_frame_header_get(fp); 163552ee8321SVasu Dev if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) 163652ee8321SVasu Dev return 0; 163752ee8321SVasu Dev 16388597ae8bSBhanu Prakash Gollapudi fcoe = ((struct fcoe_port *)lport_priv(lport))->priv; 1639619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1640619fe4beSRobert Love if (is_fip_mode(ctlr) && fc_frame_payload_op(fp) == ELS_LOGO && 164152ee8321SVasu Dev ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { 164252ee8321SVasu Dev FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n"); 164352ee8321SVasu Dev return -EINVAL; 164452ee8321SVasu Dev } 164552ee8321SVasu Dev 1646f2f96d20SDan Carpenter if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED) || 164752ee8321SVasu Dev le32_to_cpu(fr_crc(fp)) == ~crc32(~0, skb->data, skb->len)) { 164852ee8321SVasu Dev fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; 164952ee8321SVasu Dev return 0; 165052ee8321SVasu Dev } 165152ee8321SVasu Dev 16521bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 165352ee8321SVasu Dev stats->InvalidCRCCount++; 165452ee8321SVasu Dev if (stats->InvalidCRCCount < 5) 165552ee8321SVasu Dev printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); 16567e1e7eadSThomas Gleixner put_cpu(); 165752ee8321SVasu Dev return -EINVAL; 165852ee8321SVasu Dev } 165952ee8321SVasu Dev 166052ee8321SVasu Dev /** 1661859b7b64SChris Leech * fcoe_recv_frame() - process a single received frame 1662859b7b64SChris Leech * @skb: frame to process 1663a703e490SVasu Dev */ 1664859b7b64SChris Leech static void fcoe_recv_frame(struct sk_buff *skb) 1665a703e490SVasu Dev { 1666a703e490SVasu Dev u32 fr_len; 16671875f27eSRobert Love struct fc_lport *lport; 1668a703e490SVasu Dev struct fcoe_rcv_info *fr; 16691bd49b48SVasu Dev struct fc_stats *stats; 1670a703e490SVasu Dev struct fcoe_crc_eof crc_eof; 1671a703e490SVasu Dev struct fc_frame *fp; 1672a703e490SVasu Dev struct fcoe_hdr *hp; 1673a703e490SVasu Dev 1674a703e490SVasu Dev fr = fcoe_dev_from_skb(skb); 16751875f27eSRobert Love lport = fr->fr_dev; 16761875f27eSRobert Love if (unlikely(!lport)) { 1677465b87bfSBart Van Assche FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb\n"); 1678a703e490SVasu Dev kfree_skb(skb); 1679859b7b64SChris Leech return; 1680a703e490SVasu Dev } 1681a703e490SVasu Dev 1682465b87bfSBart Van Assche FCOE_NETDEV_DBG(skb->dev, 1683465b87bfSBart Van Assche "skb_info: len:%d data_len:%d head:%p data:%p tail:%p end:%p sum:%d dev:%s\n", 1684a703e490SVasu Dev skb->len, skb->data_len, 1685a703e490SVasu Dev skb->head, skb->data, skb_tail_pointer(skb), 1686a703e490SVasu Dev skb_end_pointer(skb), skb->csum, 1687a703e490SVasu Dev skb->dev ? skb->dev->name : "<NULL>"); 1688a703e490SVasu Dev 1689f1633011SRobert Love skb_linearize(skb); /* check for skb_is_nonlinear is within skb_linearize */ 1690a703e490SVasu Dev 1691a703e490SVasu Dev /* 1692a703e490SVasu Dev * Frame length checks and setting up the header pointers 1693a703e490SVasu Dev * was done in fcoe_rcv already. 1694a703e490SVasu Dev */ 1695a703e490SVasu Dev hp = (struct fcoe_hdr *) skb_network_header(skb); 1696a703e490SVasu Dev 16971bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 1698a703e490SVasu Dev if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { 1699a703e490SVasu Dev if (stats->ErrorFrames < 5) 1700d5488eb9SRobert Love printk(KERN_WARNING "fcoe: FCoE version " 1701a703e490SVasu Dev "mismatch: The frame has " 1702a703e490SVasu Dev "version %x, but the " 1703a703e490SVasu Dev "initiator supports version " 1704a703e490SVasu Dev "%x\n", FC_FCOE_DECAPS_VER(hp), 1705a703e490SVasu Dev FC_FCOE_VER); 1706f018b73aSJoe Eykholt goto drop; 1707a703e490SVasu Dev } 1708a703e490SVasu Dev 1709a703e490SVasu Dev skb_pull(skb, sizeof(struct fcoe_hdr)); 1710a703e490SVasu Dev fr_len = skb->len - sizeof(struct fcoe_crc_eof); 1711a703e490SVasu Dev 1712a703e490SVasu Dev stats->RxFrames++; 1713a703e490SVasu Dev stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; 1714a703e490SVasu Dev 1715a703e490SVasu Dev fp = (struct fc_frame *)skb; 1716a703e490SVasu Dev fc_frame_init(fp); 17171875f27eSRobert Love fr_dev(fp) = lport; 1718a703e490SVasu Dev fr_sof(fp) = hp->fcoe_sof; 1719a703e490SVasu Dev 1720a703e490SVasu Dev /* Copy out the CRC and EOF trailer for access */ 1721f018b73aSJoe Eykholt if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) 1722f018b73aSJoe Eykholt goto drop; 1723a703e490SVasu Dev fr_eof(fp) = crc_eof.fcoe_eof; 1724a703e490SVasu Dev fr_crc(fp) = crc_eof.fcoe_crc32; 1725f018b73aSJoe Eykholt if (pskb_trim(skb, fr_len)) 1726f018b73aSJoe Eykholt goto drop; 1727a703e490SVasu Dev 172852ee8321SVasu Dev if (!fcoe_filter_frames(lport, fp)) { 1729f018b73aSJoe Eykholt put_cpu(); 17301875f27eSRobert Love fc_exch_recv(lport, fp); 1731f018b73aSJoe Eykholt return; 173252ee8321SVasu Dev } 1733f018b73aSJoe Eykholt drop: 1734f018b73aSJoe Eykholt stats->ErrorFrames++; 1735f018b73aSJoe Eykholt put_cpu(); 1736f018b73aSJoe Eykholt kfree_skb(skb); 1737a703e490SVasu Dev } 1738859b7b64SChris Leech 1739859b7b64SChris Leech /** 17404b9bc86dSSebastian Andrzej Siewior * fcoe_receive_work() - The per-CPU worker 17414b9bc86dSSebastian Andrzej Siewior * @work: The work struct 1742859b7b64SChris Leech * 1743859b7b64SChris Leech */ 17444b9bc86dSSebastian Andrzej Siewior static void fcoe_receive_work(struct work_struct *work) 1745859b7b64SChris Leech { 17464b9bc86dSSebastian Andrzej Siewior struct fcoe_percpu_s *p; 1747859b7b64SChris Leech struct sk_buff *skb; 174820dc3811SNeil Horman struct sk_buff_head tmp; 174920dc3811SNeil Horman 17504b9bc86dSSebastian Andrzej Siewior p = container_of(work, struct fcoe_percpu_s, work); 175120dc3811SNeil Horman skb_queue_head_init(&tmp); 1752859b7b64SChris Leech 1753859b7b64SChris Leech spin_lock_bh(&p->fcoe_rx_list.lock); 175420dc3811SNeil Horman skb_queue_splice_init(&p->fcoe_rx_list, &tmp); 175520dc3811SNeil Horman spin_unlock_bh(&p->fcoe_rx_list.lock); 175620dc3811SNeil Horman 17574b9bc86dSSebastian Andrzej Siewior if (!skb_queue_len(&tmp)) 17584b9bc86dSSebastian Andrzej Siewior return; 17594b9bc86dSSebastian Andrzej Siewior 17604b9bc86dSSebastian Andrzej Siewior while ((skb = __skb_dequeue(&tmp))) 176120dc3811SNeil Horman fcoe_recv_frame(skb); 1762a703e490SVasu Dev } 1763a703e490SVasu Dev 1764a703e490SVasu Dev /** 17651875f27eSRobert Love * fcoe_dev_setup() - Setup the link change notification interface 1766a703e490SVasu Dev */ 1767b0d428adSRandy Dunlap static void fcoe_dev_setup(void) 1768a703e490SVasu Dev { 17696f6c2aa3Sjohn fastabend register_dcbevent_notifier(&dcb_notifier); 1770a703e490SVasu Dev register_netdevice_notifier(&fcoe_notifier); 1771a703e490SVasu Dev } 1772a703e490SVasu Dev 1773a703e490SVasu Dev /** 17741875f27eSRobert Love * fcoe_dev_cleanup() - Cleanup the link change notification interface 1775a703e490SVasu Dev */ 1776a703e490SVasu Dev static void fcoe_dev_cleanup(void) 1777a703e490SVasu Dev { 17786f6c2aa3Sjohn fastabend unregister_dcbevent_notifier(&dcb_notifier); 1779a703e490SVasu Dev unregister_netdevice_notifier(&fcoe_notifier); 1780a703e490SVasu Dev } 1781a703e490SVasu Dev 17826f6c2aa3Sjohn fastabend static struct fcoe_interface * 17836f6c2aa3Sjohn fastabend fcoe_hostlist_lookup_realdev_port(struct net_device *netdev) 17846f6c2aa3Sjohn fastabend { 17856f6c2aa3Sjohn fastabend struct fcoe_interface *fcoe; 17866f6c2aa3Sjohn fastabend struct net_device *real_dev; 17876f6c2aa3Sjohn fastabend 17886f6c2aa3Sjohn fastabend list_for_each_entry(fcoe, &fcoe_hostlist, list) { 1789d0d7b10bSParav Pandit if (is_vlan_dev(fcoe->netdev)) 17906f6c2aa3Sjohn fastabend real_dev = vlan_dev_real_dev(fcoe->netdev); 17916f6c2aa3Sjohn fastabend else 17926f6c2aa3Sjohn fastabend real_dev = fcoe->netdev; 17936f6c2aa3Sjohn fastabend 17946f6c2aa3Sjohn fastabend if (netdev == real_dev) 17956f6c2aa3Sjohn fastabend return fcoe; 17966f6c2aa3Sjohn fastabend } 17976f6c2aa3Sjohn fastabend return NULL; 17986f6c2aa3Sjohn fastabend } 17996f6c2aa3Sjohn fastabend 18006f6c2aa3Sjohn fastabend static int fcoe_dcb_app_notification(struct notifier_block *notifier, 18016f6c2aa3Sjohn fastabend ulong event, void *ptr) 18026f6c2aa3Sjohn fastabend { 18036f6c2aa3Sjohn fastabend struct dcb_app_type *entry = ptr; 1804619fe4beSRobert Love struct fcoe_ctlr *ctlr; 18056f6c2aa3Sjohn fastabend struct fcoe_interface *fcoe; 18066f6c2aa3Sjohn fastabend struct net_device *netdev; 18076f6c2aa3Sjohn fastabend int prio; 18086f6c2aa3Sjohn fastabend 18096f6c2aa3Sjohn fastabend if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) 18106f6c2aa3Sjohn fastabend return NOTIFY_OK; 18116f6c2aa3Sjohn fastabend 18126f6c2aa3Sjohn fastabend netdev = dev_get_by_index(&init_net, entry->ifindex); 18136f6c2aa3Sjohn fastabend if (!netdev) 18146f6c2aa3Sjohn fastabend return NOTIFY_OK; 18156f6c2aa3Sjohn fastabend 18166f6c2aa3Sjohn fastabend fcoe = fcoe_hostlist_lookup_realdev_port(netdev); 18176f6c2aa3Sjohn fastabend dev_put(netdev); 18186f6c2aa3Sjohn fastabend if (!fcoe) 18196f6c2aa3Sjohn fastabend return NOTIFY_OK; 18206f6c2aa3Sjohn fastabend 1821619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1822619fe4beSRobert Love 18236f6c2aa3Sjohn fastabend if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) 18246f6c2aa3Sjohn fastabend prio = ffs(entry->app.priority) - 1; 18256f6c2aa3Sjohn fastabend else 18266f6c2aa3Sjohn fastabend prio = entry->app.priority; 18276f6c2aa3Sjohn fastabend 18286f6c2aa3Sjohn fastabend if (prio < 0) 18296f6c2aa3Sjohn fastabend return NOTIFY_OK; 18306f6c2aa3Sjohn fastabend 18316f6c2aa3Sjohn fastabend if (entry->app.protocol == ETH_P_FIP || 18326f6c2aa3Sjohn fastabend entry->app.protocol == ETH_P_FCOE) 1833619fe4beSRobert Love ctlr->priority = prio; 18346f6c2aa3Sjohn fastabend 183531c37a6fSNeerav Parikh if (entry->app.protocol == ETH_P_FCOE) 183631c37a6fSNeerav Parikh fcoe->priority = prio; 18376f6c2aa3Sjohn fastabend 18386f6c2aa3Sjohn fastabend return NOTIFY_OK; 18396f6c2aa3Sjohn fastabend } 18406f6c2aa3Sjohn fastabend 1841a703e490SVasu Dev /** 18421875f27eSRobert Love * fcoe_device_notification() - Handler for net device events 18431875f27eSRobert Love * @notifier: The context of the notification 18441875f27eSRobert Love * @event: The type of event 18451875f27eSRobert Love * @ptr: The net device that the event was on 1846a703e490SVasu Dev * 18471875f27eSRobert Love * This function is called by the Ethernet driver in case of link change event. 1848a703e490SVasu Dev * 1849a703e490SVasu Dev * Returns: 0 for success 1850a703e490SVasu Dev */ 1851a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *notifier, 1852a703e490SVasu Dev ulong event, void *ptr) 1853a703e490SVasu Dev { 1854435c8667SRobert Love struct fcoe_ctlr_device *cdev; 18551875f27eSRobert Love struct fc_lport *lport = NULL; 1856351638e7SJiri Pirko struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 1857619fe4beSRobert Love struct fcoe_ctlr *ctlr; 1858014f5c3fSChris Leech struct fcoe_interface *fcoe; 18591bd49b48SVasu Dev struct fc_stats *stats; 186097c8389dSJoe Eykholt u32 link_possible = 1; 1861a703e490SVasu Dev u32 mfs; 1862a703e490SVasu Dev int rc = NOTIFY_OK; 1863a703e490SVasu Dev 1864014f5c3fSChris Leech list_for_each_entry(fcoe, &fcoe_hostlist, list) { 186525024989SChris Leech if (fcoe->netdev == netdev) { 1866619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1867619fe4beSRobert Love lport = ctlr->lp; 1868a703e490SVasu Dev break; 1869a703e490SVasu Dev } 1870a703e490SVasu Dev } 18711875f27eSRobert Love if (!lport) { 1872a703e490SVasu Dev rc = NOTIFY_DONE; 1873a703e490SVasu Dev goto out; 1874a703e490SVasu Dev } 1875a703e490SVasu Dev 1876a703e490SVasu Dev switch (event) { 1877a703e490SVasu Dev case NETDEV_DOWN: 1878a703e490SVasu Dev case NETDEV_GOING_DOWN: 187997c8389dSJoe Eykholt link_possible = 0; 1880a703e490SVasu Dev break; 1881a703e490SVasu Dev case NETDEV_UP: 1882a703e490SVasu Dev case NETDEV_CHANGE: 1883a703e490SVasu Dev break; 1884a703e490SVasu Dev case NETDEV_CHANGEMTU: 18857221d7e5SYi Zou if (netdev->features & NETIF_F_FCOE_MTU) 18867221d7e5SYi Zou break; 18871d1b88dcSVasu Dev mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + 1888a703e490SVasu Dev sizeof(struct fcoe_crc_eof)); 1889a703e490SVasu Dev if (mfs >= FC_MIN_MAX_FRAME) 18901875f27eSRobert Love fc_set_mfs(lport, mfs); 1891a703e490SVasu Dev break; 1892a703e490SVasu Dev case NETDEV_REGISTER: 1893a703e490SVasu Dev break; 18942e70e241SChris Leech case NETDEV_UNREGISTER: 18952e70e241SChris Leech list_del(&fcoe->list); 18967eccdf00SHannes Reinecke fcoe_vport_remove(lport); 18977eccdf00SHannes Reinecke mutex_lock(&fcoe_config_mutex); 18987eccdf00SHannes Reinecke fcoe_if_destroy(lport); 18997eccdf00SHannes Reinecke if (!fcoe->removed) 19007eccdf00SHannes Reinecke fcoe_interface_remove(fcoe); 19017eccdf00SHannes Reinecke fcoe_interface_cleanup(fcoe); 19027eccdf00SHannes Reinecke mutex_unlock(&fcoe_config_mutex); 19037eccdf00SHannes Reinecke fcoe_ctlr_device_delete(fcoe_ctlr_to_ctlr_dev(ctlr)); 19042e70e241SChris Leech goto out; 19052e70e241SChris Leech break; 190654a5b21dSYi Zou case NETDEV_FEAT_CHANGE: 190754a5b21dSYi Zou fcoe_netdev_features_change(lport, netdev); 190854a5b21dSYi Zou break; 1909a703e490SVasu Dev default: 19101d1b88dcSVasu Dev FCOE_NETDEV_DBG(netdev, "Unknown event %ld " 1911d5488eb9SRobert Love "from netdev netlink\n", event); 1912a703e490SVasu Dev } 19135e4f8fe7SRobert Love 19145e4f8fe7SRobert Love fcoe_link_speed_update(lport); 19155e4f8fe7SRobert Love 1916435c8667SRobert Love cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 1917435c8667SRobert Love 1918435c8667SRobert Love if (link_possible && !fcoe_link_ok(lport)) { 1919435c8667SRobert Love switch (cdev->enabled) { 1920435c8667SRobert Love case FCOE_CTLR_DISABLED: 1921435c8667SRobert Love pr_info("Link up while interface is disabled.\n"); 1922435c8667SRobert Love break; 1923435c8667SRobert Love case FCOE_CTLR_ENABLED: 1924435c8667SRobert Love case FCOE_CTLR_UNUSED: 1925619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 1926435c8667SRobert Love }; 1927435c8667SRobert Love } else if (fcoe_ctlr_link_down(ctlr)) { 1928435c8667SRobert Love switch (cdev->enabled) { 1929435c8667SRobert Love case FCOE_CTLR_DISABLED: 1930435c8667SRobert Love pr_info("Link down while interface is disabled.\n"); 1931435c8667SRobert Love break; 1932435c8667SRobert Love case FCOE_CTLR_ENABLED: 1933435c8667SRobert Love case FCOE_CTLR_UNUSED: 19341bd49b48SVasu Dev stats = per_cpu_ptr(lport->stats, get_cpu()); 1935a703e490SVasu Dev stats->LinkFailureCount++; 1936f018b73aSJoe Eykholt put_cpu(); 19371875f27eSRobert Love fcoe_clean_pending_queue(lport); 1938435c8667SRobert Love }; 1939a703e490SVasu Dev } 1940a703e490SVasu Dev out: 1941a703e490SVasu Dev return rc; 1942a703e490SVasu Dev } 1943a703e490SVasu Dev 1944a703e490SVasu Dev /** 194555a66d3cSVasu Dev * fcoe_disable() - Disables a FCoE interface 194678a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 194755a66d3cSVasu Dev * 194878a58246SYi Zou * Called from fcoe transport. 194955a66d3cSVasu Dev * 195055a66d3cSVasu Dev * Returns: 0 for success 1951435c8667SRobert Love * 1952435c8667SRobert Love * Deprecated: use fcoe_ctlr_enabled() 195355a66d3cSVasu Dev */ 195478a58246SYi Zou static int fcoe_disable(struct net_device *netdev) 195555a66d3cSVasu Dev { 1956619fe4beSRobert Love struct fcoe_ctlr *ctlr; 195755a66d3cSVasu Dev struct fcoe_interface *fcoe; 195855a66d3cSVasu Dev int rc = 0; 195955a66d3cSVasu Dev 196055a66d3cSVasu Dev mutex_lock(&fcoe_config_mutex); 196155a66d3cSVasu Dev 1962ee5df628SRobert Love rtnl_lock(); 196355a66d3cSVasu Dev fcoe = fcoe_hostlist_lookup_port(netdev); 196455a66d3cSVasu Dev rtnl_unlock(); 196555a66d3cSVasu Dev 19669ee50e48SChris Leech if (fcoe) { 1967619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 1968619fe4beSRobert Love fcoe_ctlr_link_down(ctlr); 1969619fe4beSRobert Love fcoe_clean_pending_queue(ctlr->lp); 19709ee50e48SChris Leech } else 197155a66d3cSVasu Dev rc = -ENODEV; 197255a66d3cSVasu Dev 197355a66d3cSVasu Dev mutex_unlock(&fcoe_config_mutex); 197455a66d3cSVasu Dev return rc; 197555a66d3cSVasu Dev } 197655a66d3cSVasu Dev 197755a66d3cSVasu Dev /** 197855a66d3cSVasu Dev * fcoe_enable() - Enables a FCoE interface 197978a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 198055a66d3cSVasu Dev * 198178a58246SYi Zou * Called from fcoe transport. 198255a66d3cSVasu Dev * 198355a66d3cSVasu Dev * Returns: 0 for success 198455a66d3cSVasu Dev */ 198578a58246SYi Zou static int fcoe_enable(struct net_device *netdev) 198655a66d3cSVasu Dev { 1987619fe4beSRobert Love struct fcoe_ctlr *ctlr; 198855a66d3cSVasu Dev struct fcoe_interface *fcoe; 198955a66d3cSVasu Dev int rc = 0; 199055a66d3cSVasu Dev 199155a66d3cSVasu Dev mutex_lock(&fcoe_config_mutex); 1992ee5df628SRobert Love rtnl_lock(); 199355a66d3cSVasu Dev fcoe = fcoe_hostlist_lookup_port(netdev); 199455a66d3cSVasu Dev rtnl_unlock(); 199555a66d3cSVasu Dev 1996619fe4beSRobert Love if (!fcoe) { 199755a66d3cSVasu Dev rc = -ENODEV; 1998619fe4beSRobert Love goto out; 1999619fe4beSRobert Love } 200055a66d3cSVasu Dev 2001619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2002619fe4beSRobert Love 2003619fe4beSRobert Love if (!fcoe_link_ok(ctlr->lp)) 2004619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2005619fe4beSRobert Love 2006619fe4beSRobert Love out: 200755a66d3cSVasu Dev mutex_unlock(&fcoe_config_mutex); 200855a66d3cSVasu Dev return rc; 200955a66d3cSVasu Dev } 201055a66d3cSVasu Dev 201155a66d3cSVasu Dev /** 2012435c8667SRobert Love * fcoe_ctlr_enabled() - Enable or disable an FCoE Controller 2013435c8667SRobert Love * @cdev: The FCoE Controller that is being enabled or disabled 2014435c8667SRobert Love * 2015435c8667SRobert Love * fcoe_sysfs will ensure that the state of 'enabled' has 2016435c8667SRobert Love * changed, so no checking is necessary here. This routine simply 2017435c8667SRobert Love * calls fcoe_enable or fcoe_disable, both of which are deprecated. 2018435c8667SRobert Love * When those routines are removed the functionality can be merged 2019435c8667SRobert Love * here. 2020435c8667SRobert Love */ 2021435c8667SRobert Love static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev) 2022435c8667SRobert Love { 2023435c8667SRobert Love struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(cdev); 2024435c8667SRobert Love struct fc_lport *lport = ctlr->lp; 2025435c8667SRobert Love struct net_device *netdev = fcoe_netdev(lport); 2026435c8667SRobert Love 2027435c8667SRobert Love switch (cdev->enabled) { 2028435c8667SRobert Love case FCOE_CTLR_ENABLED: 2029435c8667SRobert Love return fcoe_enable(netdev); 2030435c8667SRobert Love case FCOE_CTLR_DISABLED: 2031435c8667SRobert Love return fcoe_disable(netdev); 2032435c8667SRobert Love case FCOE_CTLR_UNUSED: 2033435c8667SRobert Love default: 2034435c8667SRobert Love return -ENOTSUPP; 2035435c8667SRobert Love }; 2036435c8667SRobert Love } 2037435c8667SRobert Love 2038435c8667SRobert Love /** 2039a87dccc7SHannes Reinecke * fcoe_ctlr_mode() - Switch FIP mode 2040a87dccc7SHannes Reinecke * @cdev: The FCoE Controller that is being modified 2041a87dccc7SHannes Reinecke * 2042a87dccc7SHannes Reinecke * When the FIP mode has been changed we need to update 2043a87dccc7SHannes Reinecke * the multicast addresses to ensure we get the correct 2044a87dccc7SHannes Reinecke * frames. 2045a87dccc7SHannes Reinecke */ 2046a87dccc7SHannes Reinecke static void fcoe_ctlr_mode(struct fcoe_ctlr_device *ctlr_dev) 2047a87dccc7SHannes Reinecke { 2048a87dccc7SHannes Reinecke struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); 2049a87dccc7SHannes Reinecke struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr); 2050a87dccc7SHannes Reinecke 2051a87dccc7SHannes Reinecke if (ctlr_dev->mode == FIP_CONN_TYPE_VN2VN && 2052a87dccc7SHannes Reinecke ctlr->mode != FIP_MODE_VN2VN) { 2053a87dccc7SHannes Reinecke dev_mc_del(fcoe->netdev, FIP_ALL_ENODE_MACS); 2054a87dccc7SHannes Reinecke dev_mc_add(fcoe->netdev, FIP_ALL_VN2VN_MACS); 2055a87dccc7SHannes Reinecke dev_mc_add(fcoe->netdev, FIP_ALL_P2P_MACS); 2056a87dccc7SHannes Reinecke } else if (ctlr->mode != FIP_MODE_FABRIC) { 2057a87dccc7SHannes Reinecke dev_mc_del(fcoe->netdev, FIP_ALL_VN2VN_MACS); 2058a87dccc7SHannes Reinecke dev_mc_del(fcoe->netdev, FIP_ALL_P2P_MACS); 2059a87dccc7SHannes Reinecke dev_mc_add(fcoe->netdev, FIP_ALL_ENODE_MACS); 2060a87dccc7SHannes Reinecke } 2061a87dccc7SHannes Reinecke fcoe_ctlr_set_fip_mode(ctlr_dev); 2062a87dccc7SHannes Reinecke } 2063a87dccc7SHannes Reinecke 2064a87dccc7SHannes Reinecke /** 20651875f27eSRobert Love * fcoe_destroy() - Destroy a FCoE interface 206678a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 20671875f27eSRobert Love * 206878a58246SYi Zou * Called from fcoe transport 2069a703e490SVasu Dev * 2070a703e490SVasu Dev * Returns: 0 for success 2071a703e490SVasu Dev */ 207278a58246SYi Zou static int fcoe_destroy(struct net_device *netdev) 2073a703e490SVasu Dev { 2074619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2075030f4e00SChris Leech struct fcoe_interface *fcoe; 2076f04ca1b6SVasu Dev struct fc_lport *lport; 2077b2085a4eSNeerav Parikh struct fcoe_port *port; 20788eca355fSMike Christie int rc = 0; 2079a703e490SVasu Dev 2080dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2081ee5df628SRobert Love rtnl_lock(); 20822e70e241SChris Leech fcoe = fcoe_hostlist_lookup_port(netdev); 20832e70e241SChris Leech if (!fcoe) { 2084a703e490SVasu Dev rc = -ENODEV; 208578a58246SYi Zou goto out_nodev; 2086a703e490SVasu Dev } 2087619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2088619fe4beSRobert Love lport = ctlr->lp; 2089b2085a4eSNeerav Parikh port = lport_priv(lport); 209054a5b21dSYi Zou list_del(&fcoe->list); 2091b2085a4eSNeerav Parikh queue_work(fcoe_wq, &port->destroy_work); 2092a703e490SVasu Dev out_nodev: 2093b2085a4eSNeerav Parikh rtnl_unlock(); 2094dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2095a703e490SVasu Dev return rc; 2096a703e490SVasu Dev } 2097a703e490SVasu Dev 20981875f27eSRobert Love /** 20991875f27eSRobert Love * fcoe_destroy_work() - Destroy a FCoE port in a deferred work context 21001875f27eSRobert Love * @work: Handle to the FCoE port to be destroyed 21011875f27eSRobert Love */ 21022e70e241SChris Leech static void fcoe_destroy_work(struct work_struct *work) 21032e70e241SChris Leech { 2104f9c4358eSRobert Love struct fcoe_ctlr_device *cdev; 2105f9c4358eSRobert Love struct fcoe_ctlr *ctlr; 21062e70e241SChris Leech struct fcoe_port *port; 2107b2085a4eSNeerav Parikh struct fcoe_interface *fcoe; 21082e70e241SChris Leech 21092e70e241SChris Leech port = container_of(work, struct fcoe_port, destroy_work); 211094aa743aSNeerav Parikh 21116f7f74abSHannes Reinecke fcoe_vport_remove(port->lport); 211294aa743aSNeerav Parikh 21132e70e241SChris Leech mutex_lock(&fcoe_config_mutex); 2114b2085a4eSNeerav Parikh 2115b2085a4eSNeerav Parikh fcoe = port->priv; 2116f9c4358eSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2117f9c4358eSRobert Love cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2118f9c4358eSRobert Love 21199eed785bSHannes Reinecke rtnl_lock(); 21202e70e241SChris Leech fcoe_if_destroy(port->lport); 21219eed785bSHannes Reinecke if (!fcoe->removed) 21229eed785bSHannes Reinecke fcoe_interface_remove(fcoe); 21239eed785bSHannes Reinecke rtnl_unlock(); 2124b2085a4eSNeerav Parikh fcoe_interface_cleanup(fcoe); 2125b2085a4eSNeerav Parikh 21262e70e241SChris Leech mutex_unlock(&fcoe_config_mutex); 2127f9c4358eSRobert Love 2128f9c4358eSRobert Love fcoe_ctlr_device_delete(cdev); 21292e70e241SChris Leech } 21302e70e241SChris Leech 2131a703e490SVasu Dev /** 213278a58246SYi Zou * fcoe_match() - Check if the FCoE is supported on the given netdevice 213378a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 21341875f27eSRobert Love * 213578a58246SYi Zou * Called from fcoe transport. 213678a58246SYi Zou * 213778a58246SYi Zou * Returns: always returns true as this is the default FCoE transport, 213878a58246SYi Zou * i.e., support all netdevs. 213978a58246SYi Zou */ 214078a58246SYi Zou static bool fcoe_match(struct net_device *netdev) 214178a58246SYi Zou { 214278a58246SYi Zou return true; 214378a58246SYi Zou } 214478a58246SYi Zou 214578a58246SYi Zou /** 21466f6c2aa3Sjohn fastabend * fcoe_dcb_create() - Initialize DCB attributes and hooks 21476f6c2aa3Sjohn fastabend * @netdev: The net_device object of the L2 link that should be queried 21486f6c2aa3Sjohn fastabend * @port: The fcoe_port to bind FCoE APP priority with 21496f6c2aa3Sjohn fastabend * @ 21506f6c2aa3Sjohn fastabend */ 21516f6c2aa3Sjohn fastabend static void fcoe_dcb_create(struct fcoe_interface *fcoe) 21526f6c2aa3Sjohn fastabend { 2153c216e876SHannes Reinecke int ctlr_prio = TC_PRIO_BESTEFFORT; 2154c216e876SHannes Reinecke int fcoe_prio = TC_PRIO_INTERACTIVE; 2155c5969656SHannes Reinecke struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 21566f6c2aa3Sjohn fastabend #ifdef CONFIG_DCB 21576f6c2aa3Sjohn fastabend int dcbx; 21586f6c2aa3Sjohn fastabend u8 fup, up; 21596f6c2aa3Sjohn fastabend struct net_device *netdev = fcoe->realdev; 21606f6c2aa3Sjohn fastabend struct dcb_app app = { 21616f6c2aa3Sjohn fastabend .priority = 0, 21626f6c2aa3Sjohn fastabend .protocol = ETH_P_FCOE 21636f6c2aa3Sjohn fastabend }; 21646f6c2aa3Sjohn fastabend 21656f6c2aa3Sjohn fastabend /* setup DCB priority attributes. */ 21666f6c2aa3Sjohn fastabend if (netdev && netdev->dcbnl_ops && netdev->dcbnl_ops->getdcbx) { 21676f6c2aa3Sjohn fastabend dcbx = netdev->dcbnl_ops->getdcbx(netdev); 21686f6c2aa3Sjohn fastabend 21696f6c2aa3Sjohn fastabend if (dcbx & DCB_CAP_DCBX_VER_IEEE) { 21706f6c2aa3Sjohn fastabend app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; 21716f6c2aa3Sjohn fastabend up = dcb_ieee_getapp_mask(netdev, &app); 21726f6c2aa3Sjohn fastabend app.protocol = ETH_P_FIP; 21736f6c2aa3Sjohn fastabend fup = dcb_ieee_getapp_mask(netdev, &app); 21746f6c2aa3Sjohn fastabend } else { 21756f6c2aa3Sjohn fastabend app.selector = DCB_APP_IDTYPE_ETHTYPE; 21766f6c2aa3Sjohn fastabend up = dcb_getapp(netdev, &app); 21776f6c2aa3Sjohn fastabend app.protocol = ETH_P_FIP; 21786f6c2aa3Sjohn fastabend fup = dcb_getapp(netdev, &app); 21796f6c2aa3Sjohn fastabend } 21806f6c2aa3Sjohn fastabend 2181c216e876SHannes Reinecke fcoe_prio = ffs(up) ? ffs(up) - 1 : 0; 2182c216e876SHannes Reinecke ctlr_prio = ffs(fup) ? ffs(fup) - 1 : fcoe_prio; 21836f6c2aa3Sjohn fastabend } 21846f6c2aa3Sjohn fastabend #endif 2185c216e876SHannes Reinecke fcoe->priority = fcoe_prio; 2186c216e876SHannes Reinecke ctlr->priority = ctlr_prio; 21876f6c2aa3Sjohn fastabend } 21886f6c2aa3Sjohn fastabend 2189435c8667SRobert Love enum fcoe_create_link_state { 2190435c8667SRobert Love FCOE_CREATE_LINK_DOWN, 2191435c8667SRobert Love FCOE_CREATE_LINK_UP, 2192435c8667SRobert Love }; 2193435c8667SRobert Love 21946f6c2aa3Sjohn fastabend /** 2195435c8667SRobert Love * _fcoe_create() - (internal) Create a fcoe interface 219678a58246SYi Zou * @netdev : The net_device object the Ethernet interface to create on 219778a58246SYi Zou * @fip_mode: The FIP mode for this creation 2198435c8667SRobert Love * @link_state: The ctlr link state on creation 219978a58246SYi Zou * 2200435c8667SRobert Love * Called from either the libfcoe 'create' module parameter 2201435c8667SRobert Love * via fcoe_create or from fcoe_syfs's ctlr_create file. 2202a703e490SVasu Dev * 2203435c8667SRobert Love * libfcoe's 'create' module parameter is deprecated so some 2204435c8667SRobert Love * consolidation of code can be done when that interface is 2205435c8667SRobert Love * removed. 2206a703e490SVasu Dev */ 22071917d42dSHannes Reinecke static int _fcoe_create(struct net_device *netdev, enum fip_mode fip_mode, 2208435c8667SRobert Love enum fcoe_create_link_state link_state) 2209a703e490SVasu Dev { 2210b2085a4eSNeerav Parikh int rc = 0; 22118d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev; 2212619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2213030f4e00SChris Leech struct fcoe_interface *fcoe; 2214af7f85d9SChris Leech struct fc_lport *lport; 2215a703e490SVasu Dev 2216dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2217ee5df628SRobert Love rtnl_lock(); 221834ce27bcSVasu Dev 2219a703e490SVasu Dev /* look for existing lport */ 2220a703e490SVasu Dev if (fcoe_hostlist_lookup(netdev)) { 2221a703e490SVasu Dev rc = -EEXIST; 222278a58246SYi Zou goto out_nodev; 2223a703e490SVasu Dev } 2224a703e490SVasu Dev 22251dd454d9SJoe Eykholt fcoe = fcoe_interface_create(netdev, fip_mode); 22267287fb91SRobert Love if (IS_ERR(fcoe)) { 22277287fb91SRobert Love rc = PTR_ERR(fcoe); 222878a58246SYi Zou goto out_nodev; 2229030f4e00SChris Leech } 2230030f4e00SChris Leech 2231619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 22328d55e507SRobert Love ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); 22338d55e507SRobert Love lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0); 2234af7f85d9SChris Leech if (IS_ERR(lport)) { 2235d5488eb9SRobert Love printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", 2236a703e490SVasu Dev netdev->name); 2237a703e490SVasu Dev rc = -EIO; 22389eed785bSHannes Reinecke if (!fcoe->removed) 22399eed785bSHannes Reinecke fcoe_interface_remove(fcoe); 2240848e7d5bSRobert Love rtnl_unlock(); 22412e70e241SChris Leech fcoe_interface_cleanup(fcoe); 2242f9c4358eSRobert Love mutex_unlock(&fcoe_config_mutex); 2243f9c4358eSRobert Love fcoe_ctlr_device_delete(ctlr_dev); 22443011b482SMilan P. Gandhi return rc; 2245a703e490SVasu Dev } 2246030f4e00SChris Leech 224754b649f8SChris Leech /* Make this the "master" N_Port */ 2248619fe4beSRobert Love ctlr->lp = lport; 2249030f4e00SChris Leech 22506f6c2aa3Sjohn fastabend /* setup DCB priority attributes. */ 22516f6c2aa3Sjohn fastabend fcoe_dcb_create(fcoe); 22526f6c2aa3Sjohn fastabend 225354b649f8SChris Leech /* start FIP Discovery and FLOGI */ 225454b649f8SChris Leech lport->boot_time = jiffies; 225554b649f8SChris Leech fc_fabric_login(lport); 2256435c8667SRobert Love 2257435c8667SRobert Love /* 2258435c8667SRobert Love * If the fcoe_ctlr_device is to be set to DISABLED 2259435c8667SRobert Love * it must be done after the lport is added to the 2260435c8667SRobert Love * hostlist, but before the rtnl_lock is released. 2261435c8667SRobert Love * This is because the rtnl_lock protects the 2262435c8667SRobert Love * hostlist that fcoe_device_notification uses. If 2263435c8667SRobert Love * the FCoE Controller is intended to be created 2264435c8667SRobert Love * DISABLED then 'enabled' needs to be considered 2265435c8667SRobert Love * handling link events. 'enabled' must be set 2266435c8667SRobert Love * before the lport can be found in the hostlist 2267435c8667SRobert Love * when a link up event is received. 2268435c8667SRobert Love */ 2269435c8667SRobert Love if (link_state == FCOE_CREATE_LINK_UP) 2270435c8667SRobert Love ctlr_dev->enabled = FCOE_CTLR_ENABLED; 2271435c8667SRobert Love else 2272435c8667SRobert Love ctlr_dev->enabled = FCOE_CTLR_DISABLED; 2273435c8667SRobert Love 2274435c8667SRobert Love if (link_state == FCOE_CREATE_LINK_UP && 2275435c8667SRobert Love !fcoe_link_ok(lport)) { 227622805123SRobert Love rtnl_unlock(); 2277619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 227822805123SRobert Love mutex_unlock(&fcoe_config_mutex); 227922805123SRobert Love return rc; 228022805123SRobert Love } 228154b649f8SChris Leech 2282a703e490SVasu Dev out_nodev: 228334ce27bcSVasu Dev rtnl_unlock(); 2284dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 22853011b482SMilan P. Gandhi 2286a703e490SVasu Dev return rc; 2287a703e490SVasu Dev } 2288a703e490SVasu Dev 2289a703e490SVasu Dev /** 2290435c8667SRobert Love * fcoe_create() - Create a fcoe interface 2291435c8667SRobert Love * @netdev : The net_device object the Ethernet interface to create on 2292435c8667SRobert Love * @fip_mode: The FIP mode for this creation 2293435c8667SRobert Love * 2294435c8667SRobert Love * Called from fcoe transport 2295435c8667SRobert Love * 2296435c8667SRobert Love * Returns: 0 for success 2297435c8667SRobert Love */ 22981917d42dSHannes Reinecke static int fcoe_create(struct net_device *netdev, enum fip_mode fip_mode) 2299435c8667SRobert Love { 2300435c8667SRobert Love return _fcoe_create(netdev, fip_mode, FCOE_CREATE_LINK_UP); 2301435c8667SRobert Love } 2302435c8667SRobert Love 2303435c8667SRobert Love /** 2304435c8667SRobert Love * fcoe_ctlr_alloc() - Allocate a fcoe interface from fcoe_sysfs 2305435c8667SRobert Love * @netdev: The net_device to be used by the allocated FCoE Controller 2306435c8667SRobert Love * 2307435c8667SRobert Love * This routine is called from fcoe_sysfs. It will start the fcoe_ctlr 2308435c8667SRobert Love * in a link_down state. The allows the user an opportunity to configure 2309435c8667SRobert Love * the FCoE Controller from sysfs before enabling the FCoE Controller. 2310435c8667SRobert Love * 2311435c8667SRobert Love * Creating in with this routine starts the FCoE Controller in Fabric 2312435c8667SRobert Love * mode. The user can change to VN2VN or another mode before enabling. 2313435c8667SRobert Love */ 2314435c8667SRobert Love static int fcoe_ctlr_alloc(struct net_device *netdev) 2315435c8667SRobert Love { 2316435c8667SRobert Love return _fcoe_create(netdev, FIP_MODE_FABRIC, 2317435c8667SRobert Love FCOE_CREATE_LINK_DOWN); 2318435c8667SRobert Love } 2319435c8667SRobert Love 2320435c8667SRobert Love /** 23215e4f8fe7SRobert Love * fcoe_link_ok() - Check if the link is OK for a local port 23225e4f8fe7SRobert Love * @lport: The local port to check link on 23235e4f8fe7SRobert Love * 23245e4f8fe7SRobert Love * Returns: 0 if link is UP and OK, -1 if not 23255e4f8fe7SRobert Love * 23265e4f8fe7SRobert Love */ 23277c9c6841SBart Van Assche static int fcoe_link_ok(struct fc_lport *lport) 23285e4f8fe7SRobert Love { 23298597ae8bSBhanu Prakash Gollapudi struct net_device *netdev = fcoe_netdev(lport); 23305e4f8fe7SRobert Love 23315e4f8fe7SRobert Love if (netif_oper_up(netdev)) 23325e4f8fe7SRobert Love return 0; 23335e4f8fe7SRobert Love return -1; 23345e4f8fe7SRobert Love } 23355e4f8fe7SRobert Love 23365e4f8fe7SRobert Love /** 23371875f27eSRobert Love * fcoe_percpu_clean() - Clear all pending skbs for an local port 23381875f27eSRobert Love * @lport: The local port whose skbs are to be cleared 2339e7a51997SJoe Eykholt * 2340e7a51997SJoe Eykholt * Must be called with fcoe_create_mutex held to single-thread completion. 2341e7a51997SJoe Eykholt * 23424b9bc86dSSebastian Andrzej Siewior * This flushes the pending skbs by flush the work item for each CPU. The work 23434b9bc86dSSebastian Andrzej Siewior * item on each possible CPU is flushed because we may have used the per-CPU 23444b9bc86dSSebastian Andrzej Siewior * struct of an offline CPU. 2345a703e490SVasu Dev */ 23467c9c6841SBart Van Assche static void fcoe_percpu_clean(struct fc_lport *lport) 2347a703e490SVasu Dev { 2348a703e490SVasu Dev struct fcoe_percpu_s *pp; 2349a703e490SVasu Dev unsigned int cpu; 2350a703e490SVasu Dev 2351a703e490SVasu Dev for_each_possible_cpu(cpu) { 2352a703e490SVasu Dev pp = &per_cpu(fcoe_percpu, cpu); 2353e7a51997SJoe Eykholt 23544b9bc86dSSebastian Andrzej Siewior flush_work(&pp->work); 2355a703e490SVasu Dev } 2356a703e490SVasu Dev } 2357a703e490SVasu Dev 2358a703e490SVasu Dev /** 23591875f27eSRobert Love * fcoe_reset() - Reset a local port 23601875f27eSRobert Love * @shost: The SCSI host associated with the local port to be reset 2361a703e490SVasu Dev * 23621875f27eSRobert Love * Returns: Always 0 (return value required by FC transport template) 2363a703e490SVasu Dev */ 23647c9c6841SBart Van Assche static int fcoe_reset(struct Scsi_Host *shost) 2365a703e490SVasu Dev { 2366a703e490SVasu Dev struct fc_lport *lport = shost_priv(shost); 2367d2f80952SVasu Dev struct fcoe_port *port = lport_priv(lport); 2368d2f80952SVasu Dev struct fcoe_interface *fcoe = port->priv; 2369619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 2370435c8667SRobert Love struct fcoe_ctlr_device *cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 2371d2f80952SVasu Dev 2372619fe4beSRobert Love fcoe_ctlr_link_down(ctlr); 2373619fe4beSRobert Love fcoe_clean_pending_queue(ctlr->lp); 2374435c8667SRobert Love 2375435c8667SRobert Love if (cdev->enabled != FCOE_CTLR_DISABLED && 2376435c8667SRobert Love !fcoe_link_ok(ctlr->lp)) 2377619fe4beSRobert Love fcoe_ctlr_link_up(ctlr); 2378a703e490SVasu Dev return 0; 2379a703e490SVasu Dev } 2380a703e490SVasu Dev 2381a703e490SVasu Dev /** 23821875f27eSRobert Love * fcoe_hostlist_lookup_port() - Find the FCoE interface associated with a net device 23831875f27eSRobert Love * @netdev: The net device used as a key 2384a703e490SVasu Dev * 23851875f27eSRobert Love * Locking: Must be called with the RNL mutex held. 23861875f27eSRobert Love * 23871875f27eSRobert Love * Returns: NULL or the FCoE interface 2388a703e490SVasu Dev */ 2389014f5c3fSChris Leech static struct fcoe_interface * 23901875f27eSRobert Love fcoe_hostlist_lookup_port(const struct net_device *netdev) 2391a703e490SVasu Dev { 2392014f5c3fSChris Leech struct fcoe_interface *fcoe; 2393a703e490SVasu Dev 2394014f5c3fSChris Leech list_for_each_entry(fcoe, &fcoe_hostlist, list) { 23951875f27eSRobert Love if (fcoe->netdev == netdev) 2396014f5c3fSChris Leech return fcoe; 2397a703e490SVasu Dev } 2398a703e490SVasu Dev return NULL; 2399a703e490SVasu Dev } 2400a703e490SVasu Dev 2401a703e490SVasu Dev /** 24021875f27eSRobert Love * fcoe_hostlist_lookup() - Find the local port associated with a 24031875f27eSRobert Love * given net device 24041875f27eSRobert Love * @netdev: The netdevice used as a key 2405a703e490SVasu Dev * 24061875f27eSRobert Love * Locking: Must be called with the RTNL mutex held 24071875f27eSRobert Love * 24081875f27eSRobert Love * Returns: NULL or the local port 2409a703e490SVasu Dev */ 2410090eb6c4SChris Leech static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) 2411a703e490SVasu Dev { 2412619fe4beSRobert Love struct fcoe_ctlr *ctlr; 2413014f5c3fSChris Leech struct fcoe_interface *fcoe; 2414a703e490SVasu Dev 2415014f5c3fSChris Leech fcoe = fcoe_hostlist_lookup_port(netdev); 2416619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2417619fe4beSRobert Love return (fcoe) ? ctlr->lp : NULL; 2418a703e490SVasu Dev } 2419a703e490SVasu Dev 2420a703e490SVasu Dev /** 24211875f27eSRobert Love * fcoe_hostlist_add() - Add the FCoE interface identified by a local 24221875f27eSRobert Love * port to the hostlist 24231875f27eSRobert Love * @lport: The local port that identifies the FCoE interface to be added 24241875f27eSRobert Love * 24251875f27eSRobert Love * Locking: must be called with the RTNL mutex held 2426a703e490SVasu Dev * 2427a703e490SVasu Dev * Returns: 0 for success 2428a703e490SVasu Dev */ 2429090eb6c4SChris Leech static int fcoe_hostlist_add(const struct fc_lport *lport) 2430a703e490SVasu Dev { 2431014f5c3fSChris Leech struct fcoe_interface *fcoe; 2432014f5c3fSChris Leech struct fcoe_port *port; 2433a703e490SVasu Dev 2434014f5c3fSChris Leech fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); 2435014f5c3fSChris Leech if (!fcoe) { 2436014f5c3fSChris Leech port = lport_priv(lport); 24378597ae8bSBhanu Prakash Gollapudi fcoe = port->priv; 2438014f5c3fSChris Leech list_add_tail(&fcoe->list, &fcoe_hostlist); 2439a703e490SVasu Dev } 2440a703e490SVasu Dev return 0; 2441a703e490SVasu Dev } 2442a703e490SVasu Dev 2443f9184df3SNeil Horman /** 2444f9184df3SNeil Horman * fcoe_hostlist_del() - Remove the FCoE interface identified by a local 2445f9184df3SNeil Horman * port to the hostlist 2446f9184df3SNeil Horman * @lport: The local port that identifies the FCoE interface to be added 2447f9184df3SNeil Horman * 2448f9184df3SNeil Horman * Locking: must be called with the RTNL mutex held 2449f9184df3SNeil Horman * 2450f9184df3SNeil Horman */ 2451f9184df3SNeil Horman static void fcoe_hostlist_del(const struct fc_lport *lport) 2452f9184df3SNeil Horman { 2453f9184df3SNeil Horman struct fcoe_interface *fcoe; 2454f9184df3SNeil Horman struct fcoe_port *port; 2455f9184df3SNeil Horman 2456f9184df3SNeil Horman port = lport_priv(lport); 2457f9184df3SNeil Horman fcoe = port->priv; 2458f9184df3SNeil Horman list_del(&fcoe->list); 2459f9184df3SNeil Horman return; 2460f9184df3SNeil Horman } 246178a58246SYi Zou 246278a58246SYi Zou static struct fcoe_transport fcoe_sw_transport = { 246378a58246SYi Zou .name = {FCOE_TRANSPORT_DEFAULT}, 246478a58246SYi Zou .attached = false, 246578a58246SYi Zou .list = LIST_HEAD_INIT(fcoe_sw_transport.list), 246678a58246SYi Zou .match = fcoe_match, 2467435c8667SRobert Love .alloc = fcoe_ctlr_alloc, 246878a58246SYi Zou .create = fcoe_create, 246978a58246SYi Zou .destroy = fcoe_destroy, 247078a58246SYi Zou .enable = fcoe_enable, 247178a58246SYi Zou .disable = fcoe_disable, 247278a58246SYi Zou }; 247378a58246SYi Zou 2474a703e490SVasu Dev /** 24751875f27eSRobert Love * fcoe_init() - Initialize fcoe.ko 2476a703e490SVasu Dev * 24771875f27eSRobert Love * Returns: 0 on success, or a negative value on failure 2478a703e490SVasu Dev */ 2479a703e490SVasu Dev static int __init fcoe_init(void) 2480a703e490SVasu Dev { 24811875f27eSRobert Love struct fcoe_percpu_s *p; 2482a703e490SVasu Dev unsigned int cpu; 2483a703e490SVasu Dev int rc = 0; 2484a703e490SVasu Dev 24852ca32b48STejun Heo fcoe_wq = alloc_workqueue("fcoe", 0, 0); 24862ca32b48STejun Heo if (!fcoe_wq) 24872ca32b48STejun Heo return -ENOMEM; 24882ca32b48STejun Heo 248978a58246SYi Zou /* register as a fcoe transport */ 249078a58246SYi Zou rc = fcoe_transport_attach(&fcoe_sw_transport); 249178a58246SYi Zou if (rc) { 249278a58246SYi Zou printk(KERN_ERR "failed to register an fcoe transport, check " 249378a58246SYi Zou "if libfcoe is loaded\n"); 2494a561a8eaSWei Yongjun goto out_destroy; 249578a58246SYi Zou } 249678a58246SYi Zou 2497dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2498dfc1d0feSChris Leech 2499a703e490SVasu Dev for_each_possible_cpu(cpu) { 25004b9bc86dSSebastian Andrzej Siewior p = per_cpu_ptr(&fcoe_percpu, cpu); 25014b9bc86dSSebastian Andrzej Siewior INIT_WORK(&p->work, fcoe_receive_work); 2502a703e490SVasu Dev skb_queue_head_init(&p->fcoe_rx_list); 2503a703e490SVasu Dev } 2504a703e490SVasu Dev 2505a703e490SVasu Dev /* Setup link change notification */ 2506a703e490SVasu Dev fcoe_dev_setup(); 2507a703e490SVasu Dev 25085892c32fSChris Leech rc = fcoe_if_init(); 25095892c32fSChris Leech if (rc) 25105892c32fSChris Leech goto out_free; 2511a703e490SVasu Dev 2512dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2513a703e490SVasu Dev return 0; 2514a703e490SVasu Dev 2515a703e490SVasu Dev out_free: 2516dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 2517a561a8eaSWei Yongjun out_destroy: 25182ca32b48STejun Heo destroy_workqueue(fcoe_wq); 2519a703e490SVasu Dev return rc; 2520a703e490SVasu Dev } 2521a703e490SVasu Dev module_init(fcoe_init); 2522a703e490SVasu Dev 2523a703e490SVasu Dev /** 25241875f27eSRobert Love * fcoe_exit() - Clean up fcoe.ko 2525a703e490SVasu Dev * 25261875f27eSRobert Love * Returns: 0 on success or a negative value on failure 2527a703e490SVasu Dev */ 2528a703e490SVasu Dev static void __exit fcoe_exit(void) 2529a703e490SVasu Dev { 2530014f5c3fSChris Leech struct fcoe_interface *fcoe, *tmp; 2531619fe4beSRobert Love struct fcoe_ctlr *ctlr; 25322e70e241SChris Leech struct fcoe_port *port; 25331875f27eSRobert Love unsigned int cpu; 2534a703e490SVasu Dev 2535dfc1d0feSChris Leech mutex_lock(&fcoe_config_mutex); 2536dfc1d0feSChris Leech 2537a703e490SVasu Dev fcoe_dev_cleanup(); 2538a703e490SVasu Dev 2539a703e490SVasu Dev /* releases the associated fcoe hosts */ 2540090eb6c4SChris Leech rtnl_lock(); 2541090eb6c4SChris Leech list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { 2542619fe4beSRobert Love ctlr = fcoe_to_ctlr(fcoe); 2543619fe4beSRobert Love port = lport_priv(ctlr->lp); 2544f9184df3SNeil Horman fcoe_hostlist_del(port->lport); 25452ca32b48STejun Heo queue_work(fcoe_wq, &port->destroy_work); 2546c863df33SChris Leech } 2547090eb6c4SChris Leech rtnl_unlock(); 2548a703e490SVasu Dev 25494b9bc86dSSebastian Andrzej Siewior for_each_possible_cpu(cpu) 25504b9bc86dSSebastian Andrzej Siewior fcoe_thread_cleanup_local(cpu); 2551cd45ae38SSrivatsa S. Bhat 2552dfc1d0feSChris Leech mutex_unlock(&fcoe_config_mutex); 25532e70e241SChris Leech 25542ca32b48STejun Heo /* 25552ca32b48STejun Heo * destroy_work's may be chained but destroy_workqueue() 25562ca32b48STejun Heo * can take care of them. Just kill the fcoe_wq. 25572ca32b48STejun Heo */ 25582ca32b48STejun Heo destroy_workqueue(fcoe_wq); 25592e70e241SChris Leech 25602ca32b48STejun Heo /* 25612ca32b48STejun Heo * Detaching from the scsi transport must happen after all 25622ca32b48STejun Heo * destroys are done on the fcoe_wq. destroy_workqueue will 25632ca32b48STejun Heo * enusre the fcoe_wq is flushed. 25642ca32b48STejun Heo */ 25652e70e241SChris Leech fcoe_if_exit(); 256678a58246SYi Zou 256778a58246SYi Zou /* detach from fcoe transport */ 256878a58246SYi Zou fcoe_transport_detach(&fcoe_sw_transport); 2569a703e490SVasu Dev } 2570a703e490SVasu Dev module_exit(fcoe_exit); 257111b56188SChris Leech 257211b56188SChris Leech /** 257311b56188SChris Leech * fcoe_flogi_resp() - FCoE specific FLOGI and FDISC response handler 257411b56188SChris Leech * @seq: active sequence in the FLOGI or FDISC exchange 257511b56188SChris Leech * @fp: response frame, or error encoded in a pointer (timeout) 257678cfe97fSMilan P. Gandhi * @arg: pointer to the fcoe_ctlr structure 257711b56188SChris Leech * 257865155b37SUwe Kleine-König * This handles MAC address management for FCoE, then passes control on to 257911b56188SChris Leech * the libfc FLOGI response handler. 258011b56188SChris Leech */ 258111b56188SChris Leech static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) 258211b56188SChris Leech { 258311b56188SChris Leech struct fcoe_ctlr *fip = arg; 258411b56188SChris Leech struct fc_exch *exch = fc_seq_exch(seq); 258511b56188SChris Leech struct fc_lport *lport = exch->lp; 258611b56188SChris Leech u8 *mac; 258711b56188SChris Leech 258811b56188SChris Leech if (IS_ERR(fp)) 258911b56188SChris Leech goto done; 259011b56188SChris Leech 259111b56188SChris Leech mac = fr_cb(fp)->granted_mac; 259211b56188SChris Leech /* pre-FIP */ 2593907c07d4SVasu Dev if (is_zero_ether_addr(mac)) 2594907c07d4SVasu Dev fcoe_ctlr_recv_flogi(fip, lport, fp); 2595907c07d4SVasu Dev if (!is_zero_ether_addr(mac)) 2596386309ceSJoe Eykholt fcoe_update_src_mac(lport, mac); 259711b56188SChris Leech done: 259811b56188SChris Leech fc_lport_flogi_resp(seq, fp, lport); 259911b56188SChris Leech } 260011b56188SChris Leech 260111b56188SChris Leech /** 260211b56188SChris Leech * fcoe_logo_resp() - FCoE specific LOGO response handler 260311b56188SChris Leech * @seq: active sequence in the LOGO exchange 260411b56188SChris Leech * @fp: response frame, or error encoded in a pointer (timeout) 260578cfe97fSMilan P. Gandhi * @arg: pointer to the fcoe_ctlr structure 260611b56188SChris Leech * 260765155b37SUwe Kleine-König * This handles MAC address management for FCoE, then passes control on to 260811b56188SChris Leech * the libfc LOGO response handler. 260911b56188SChris Leech */ 261011b56188SChris Leech static void fcoe_logo_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) 261111b56188SChris Leech { 2612386309ceSJoe Eykholt struct fc_lport *lport = arg; 261311b56188SChris Leech static u8 zero_mac[ETH_ALEN] = { 0 }; 261411b56188SChris Leech 261511b56188SChris Leech if (!IS_ERR(fp)) 2616386309ceSJoe Eykholt fcoe_update_src_mac(lport, zero_mac); 261711b56188SChris Leech fc_lport_logo_resp(seq, fp, lport); 261811b56188SChris Leech } 261911b56188SChris Leech 262011b56188SChris Leech /** 262111b56188SChris Leech * fcoe_elsct_send - FCoE specific ELS handler 262211b56188SChris Leech * 262311b56188SChris Leech * This does special case handling of FIP encapsualted ELS exchanges for FCoE, 262411b56188SChris Leech * using FCoE specific response handlers and passing the FIP controller as 262511b56188SChris Leech * the argument (the lport is still available from the exchange). 262611b56188SChris Leech * 262711b56188SChris Leech * Most of the work here is just handed off to the libfc routine. 262811b56188SChris Leech */ 26291875f27eSRobert Love static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did, 26301875f27eSRobert Love struct fc_frame *fp, unsigned int op, 26311875f27eSRobert Love void (*resp)(struct fc_seq *, 26321875f27eSRobert Love struct fc_frame *, 26331875f27eSRobert Love void *), 263411b56188SChris Leech void *arg, u32 timeout) 263511b56188SChris Leech { 263611b56188SChris Leech struct fcoe_port *port = lport_priv(lport); 26378597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 2638619fe4beSRobert Love struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); 263911b56188SChris Leech struct fc_frame_header *fh = fc_frame_header_get(fp); 264011b56188SChris Leech 264111b56188SChris Leech switch (op) { 264211b56188SChris Leech case ELS_FLOGI: 264311b56188SChris Leech case ELS_FDISC: 2644e10f8c66SJoe Eykholt if (lport->point_to_multipoint) 2645e10f8c66SJoe Eykholt break; 264611b56188SChris Leech return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp, 264711b56188SChris Leech fip, timeout); 264811b56188SChris Leech case ELS_LOGO: 264911b56188SChris Leech /* only hook onto fabric logouts, not port logouts */ 265011b56188SChris Leech if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) 265111b56188SChris Leech break; 265211b56188SChris Leech return fc_elsct_send(lport, did, fp, op, fcoe_logo_resp, 2653386309ceSJoe Eykholt lport, timeout); 265411b56188SChris Leech } 265511b56188SChris Leech return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); 265611b56188SChris Leech } 265711b56188SChris Leech 26589a05753bSChris Leech /** 26599a05753bSChris Leech * fcoe_vport_create() - create an fc_host/scsi_host for a vport 26609a05753bSChris Leech * @vport: fc_vport object to create a new fc_host for 26619a05753bSChris Leech * @disabled: start the new fc_host in a disabled state by default? 26629a05753bSChris Leech * 26639a05753bSChris Leech * Returns: 0 for success 26649a05753bSChris Leech */ 26659a05753bSChris Leech static int fcoe_vport_create(struct fc_vport *vport, bool disabled) 26669a05753bSChris Leech { 26679a05753bSChris Leech struct Scsi_Host *shost = vport_to_shost(vport); 26689a05753bSChris Leech struct fc_lport *n_port = shost_priv(shost); 26699a05753bSChris Leech struct fcoe_port *port = lport_priv(n_port); 26708597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 26719a05753bSChris Leech struct net_device *netdev = fcoe->netdev; 26729a05753bSChris Leech struct fc_lport *vn_port; 2673bdf25218SNeerav Parikh int rc; 2674bdf25218SNeerav Parikh char buf[32]; 2675bdf25218SNeerav Parikh 2676bdf25218SNeerav Parikh rc = fcoe_validate_vport_create(vport); 2677bdf25218SNeerav Parikh if (rc) { 2678d834895cSBhanu Prakash Gollapudi fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); 2679bdf25218SNeerav Parikh printk(KERN_ERR "fcoe: Failed to create vport, " 2680bdf25218SNeerav Parikh "WWPN (0x%s) already exists\n", 2681bdf25218SNeerav Parikh buf); 2682bdf25218SNeerav Parikh return rc; 2683bdf25218SNeerav Parikh } 26849a05753bSChris Leech 26859a05753bSChris Leech mutex_lock(&fcoe_config_mutex); 26864bc71cb9SJiri Pirko rtnl_lock(); 26879a05753bSChris Leech vn_port = fcoe_if_create(fcoe, &vport->dev, 1); 26884bc71cb9SJiri Pirko rtnl_unlock(); 26899a05753bSChris Leech mutex_unlock(&fcoe_config_mutex); 26909a05753bSChris Leech 26919a05753bSChris Leech if (IS_ERR(vn_port)) { 26929a05753bSChris Leech printk(KERN_ERR "fcoe: fcoe_vport_create(%s) failed\n", 26939a05753bSChris Leech netdev->name); 26949a05753bSChris Leech return -EIO; 26959a05753bSChris Leech } 26969a05753bSChris Leech 26979a05753bSChris Leech if (disabled) { 26989a05753bSChris Leech fc_vport_set_state(vport, FC_VPORT_DISABLED); 26999a05753bSChris Leech } else { 27009a05753bSChris Leech vn_port->boot_time = jiffies; 27019a05753bSChris Leech fc_fabric_login(vn_port); 27029a05753bSChris Leech fc_vport_setlink(vn_port); 27039a05753bSChris Leech } 27049a05753bSChris Leech return 0; 27059a05753bSChris Leech } 27069a05753bSChris Leech 27079a05753bSChris Leech /** 27089a05753bSChris Leech * fcoe_vport_destroy() - destroy the fc_host/scsi_host for a vport 27099a05753bSChris Leech * @vport: fc_vport object that is being destroyed 27109a05753bSChris Leech * 27119a05753bSChris Leech * Returns: 0 for success 27129a05753bSChris Leech */ 27139a05753bSChris Leech static int fcoe_vport_destroy(struct fc_vport *vport) 27149a05753bSChris Leech { 27159a05753bSChris Leech struct Scsi_Host *shost = vport_to_shost(vport); 27169a05753bSChris Leech struct fc_lport *n_port = shost_priv(shost); 27179a05753bSChris Leech struct fc_lport *vn_port = vport->dd_data; 27189a05753bSChris Leech 27199a05753bSChris Leech mutex_lock(&n_port->lp_mutex); 27209a05753bSChris Leech list_del(&vn_port->list); 27219a05753bSChris Leech mutex_unlock(&n_port->lp_mutex); 2722ccefd23eSRobert Love 2723ccefd23eSRobert Love mutex_lock(&fcoe_config_mutex); 27247eccdf00SHannes Reinecke rtnl_lock(); 2725ccefd23eSRobert Love fcoe_if_destroy(vn_port); 27267eccdf00SHannes Reinecke rtnl_unlock(); 2727ccefd23eSRobert Love mutex_unlock(&fcoe_config_mutex); 2728ccefd23eSRobert Love 27299a05753bSChris Leech return 0; 27309a05753bSChris Leech } 27319a05753bSChris Leech 27329a05753bSChris Leech /** 27336f7f74abSHannes Reinecke * fcoe_vport_remove() - remove attached vports 27346f7f74abSHannes Reinecke * @lport: lport for which the vports should be removed 27356f7f74abSHannes Reinecke */ 27366f7f74abSHannes Reinecke static void fcoe_vport_remove(struct fc_lport *lport) 27376f7f74abSHannes Reinecke { 27386f7f74abSHannes Reinecke struct Scsi_Host *shost; 27396f7f74abSHannes Reinecke struct fc_host_attrs *fc_host; 27406f7f74abSHannes Reinecke unsigned long flags; 27416f7f74abSHannes Reinecke struct fc_vport *vport; 27426f7f74abSHannes Reinecke struct fc_vport *next_vport; 27436f7f74abSHannes Reinecke 27446f7f74abSHannes Reinecke shost = lport->host; 27456f7f74abSHannes Reinecke fc_host = shost_to_fc_host(shost); 27466f7f74abSHannes Reinecke 27476f7f74abSHannes Reinecke /* Loop through all the vports and mark them for deletion */ 27486f7f74abSHannes Reinecke spin_lock_irqsave(shost->host_lock, flags); 27496f7f74abSHannes Reinecke list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) { 27506f7f74abSHannes Reinecke if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) { 27516f7f74abSHannes Reinecke continue; 27526f7f74abSHannes Reinecke } else { 27536f7f74abSHannes Reinecke vport->flags |= FC_VPORT_DELETING; 27546f7f74abSHannes Reinecke queue_work(fc_host_work_q(shost), 27556f7f74abSHannes Reinecke &vport->vport_delete_work); 27566f7f74abSHannes Reinecke } 27576f7f74abSHannes Reinecke } 27586f7f74abSHannes Reinecke spin_unlock_irqrestore(shost->host_lock, flags); 27596f7f74abSHannes Reinecke 27606f7f74abSHannes Reinecke flush_workqueue(fc_host_work_q(shost)); 27616f7f74abSHannes Reinecke } 27626f7f74abSHannes Reinecke 27636f7f74abSHannes Reinecke /** 27649a05753bSChris Leech * fcoe_vport_disable() - change vport state 27659a05753bSChris Leech * @vport: vport to bring online/offline 27669a05753bSChris Leech * @disable: should the vport be disabled? 27679a05753bSChris Leech */ 27689a05753bSChris Leech static int fcoe_vport_disable(struct fc_vport *vport, bool disable) 27699a05753bSChris Leech { 27709a05753bSChris Leech struct fc_lport *lport = vport->dd_data; 27719a05753bSChris Leech 27729a05753bSChris Leech if (disable) { 27739a05753bSChris Leech fc_vport_set_state(vport, FC_VPORT_DISABLED); 27749a05753bSChris Leech fc_fabric_logoff(lport); 27759a05753bSChris Leech } else { 27769a05753bSChris Leech lport->boot_time = jiffies; 27779a05753bSChris Leech fc_fabric_login(lport); 27789a05753bSChris Leech fc_vport_setlink(lport); 27799a05753bSChris Leech } 27809a05753bSChris Leech 27819a05753bSChris Leech return 0; 27829a05753bSChris Leech } 27839a05753bSChris Leech 2784dc8596d3SChris Leech /** 2785dc8596d3SChris Leech * fcoe_vport_set_symbolic_name() - append vport string to symbolic name 2786dc8596d3SChris Leech * @vport: fc_vport with a new symbolic name string 2787dc8596d3SChris Leech * 2788dc8596d3SChris Leech * After generating a new symbolic name string, a new RSPN_ID request is 2789dc8596d3SChris Leech * sent to the name server. There is no response handler, so if it fails 2790dc8596d3SChris Leech * for some reason it will not be retried. 2791dc8596d3SChris Leech */ 2792dc8596d3SChris Leech static void fcoe_set_vport_symbolic_name(struct fc_vport *vport) 2793dc8596d3SChris Leech { 2794dc8596d3SChris Leech struct fc_lport *lport = vport->dd_data; 2795dc8596d3SChris Leech struct fc_frame *fp; 2796dc8596d3SChris Leech size_t len; 2797dc8596d3SChris Leech 2798dc8596d3SChris Leech snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE, 2799dc8596d3SChris Leech "%s v%s over %s : %s", FCOE_NAME, FCOE_VERSION, 2800dc8596d3SChris Leech fcoe_netdev(lport)->name, vport->symbolic_name); 2801dc8596d3SChris Leech 2802dc8596d3SChris Leech if (lport->state != LPORT_ST_READY) 2803dc8596d3SChris Leech return; 2804dc8596d3SChris Leech 2805dc8596d3SChris Leech len = strnlen(fc_host_symbolic_name(lport->host), 255); 2806dc8596d3SChris Leech fp = fc_frame_alloc(lport, 2807dc8596d3SChris Leech sizeof(struct fc_ct_hdr) + 2808dc8596d3SChris Leech sizeof(struct fc_ns_rspn) + len); 2809dc8596d3SChris Leech if (!fp) 2810dc8596d3SChris Leech return; 2811dc8596d3SChris Leech lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RSPN_ID, 2812b94f8951SJoe Eykholt NULL, NULL, 3 * lport->r_a_tov); 2813dc8596d3SChris Leech } 2814b84056bfSYi Zou 28158d55e507SRobert Love static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) 28168d55e507SRobert Love { 28178d55e507SRobert Love struct fcoe_ctlr_device *ctlr_dev = 28188d55e507SRobert Love fcoe_fcf_dev_to_ctlr_dev(fcf_dev); 28198d55e507SRobert Love struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); 28208d55e507SRobert Love struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr); 28218d55e507SRobert Love 28228d55e507SRobert Love fcf_dev->vlan_id = vlan_dev_vlan_id(fcoe->netdev); 28238d55e507SRobert Love } 28248d55e507SRobert Love 28257d65b0dfSJoe Eykholt /** 28267d65b0dfSJoe Eykholt * fcoe_set_port_id() - Callback from libfc when Port_ID is set. 28277d65b0dfSJoe Eykholt * @lport: the local port 28287d65b0dfSJoe Eykholt * @port_id: the port ID 28297d65b0dfSJoe Eykholt * @fp: the received frame, if any, that caused the port_id to be set. 28307d65b0dfSJoe Eykholt * 28317d65b0dfSJoe Eykholt * This routine handles the case where we received a FLOGI and are 28327d65b0dfSJoe Eykholt * entering point-to-point mode. We need to call fcoe_ctlr_recv_flogi() 28337d65b0dfSJoe Eykholt * so it can set the non-mapped mode and gateway address. 28347d65b0dfSJoe Eykholt * 28357d65b0dfSJoe Eykholt * The FLOGI LS_ACC is handled by fcoe_flogi_resp(). 28367d65b0dfSJoe Eykholt */ 28377d65b0dfSJoe Eykholt static void fcoe_set_port_id(struct fc_lport *lport, 28387d65b0dfSJoe Eykholt u32 port_id, struct fc_frame *fp) 28397d65b0dfSJoe Eykholt { 28407d65b0dfSJoe Eykholt struct fcoe_port *port = lport_priv(lport); 28418597ae8bSBhanu Prakash Gollapudi struct fcoe_interface *fcoe = port->priv; 2842619fe4beSRobert Love struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); 28437d65b0dfSJoe Eykholt 28447d65b0dfSJoe Eykholt if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) 2845619fe4beSRobert Love fcoe_ctlr_recv_flogi(ctlr, lport, fp); 28467d65b0dfSJoe Eykholt } 2847