18c2ecf20Sopenharmony_ci/* bnx2fc_fcoe.c: QLogic Linux FCoE offload driver. 28c2ecf20Sopenharmony_ci * This file contains the code that interacts with libfc, libfcoe, 38c2ecf20Sopenharmony_ci * cnic modules to create FCoE instances, send/receive non-offloaded 48c2ecf20Sopenharmony_ci * FIP/FCoE packets, listen to link events etc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2008-2013 Broadcom Corporation 78c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 QLogic Corporation 88c2ecf20Sopenharmony_ci * Copyright (c) 2016-2017 Cavium Inc. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 118c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 128c2ecf20Sopenharmony_ci * the Free Software Foundation. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "bnx2fc.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic struct list_head adapter_list; 208c2ecf20Sopenharmony_cistatic struct list_head if_list; 218c2ecf20Sopenharmony_cistatic u32 adapter_count; 228c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(bnx2fc_dev_lock); 238c2ecf20Sopenharmony_ciDEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME "bnx2fc" 268c2ecf20Sopenharmony_ci#define DRV_MODULE_VERSION BNX2FC_VERSION 278c2ecf20Sopenharmony_ci#define DRV_MODULE_RELDATE "October 15, 2015" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic char version[] = 318c2ecf20Sopenharmony_ci "QLogic FCoE Driver " DRV_MODULE_NAME \ 328c2ecf20Sopenharmony_ci " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bhanu Prakash Gollapudi <bprakash@broadcom.com>"); 368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic FCoE Driver"); 378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 388c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define BNX2FC_MAX_QUEUE_DEPTH 256 418c2ecf20Sopenharmony_ci#define BNX2FC_MIN_QUEUE_DEPTH 32 428c2ecf20Sopenharmony_ci#define FCOE_WORD_TO_BYTE 4 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic struct scsi_transport_template *bnx2fc_transport_template; 458c2ecf20Sopenharmony_cistatic struct scsi_transport_template *bnx2fc_vport_xport_template; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct workqueue_struct *bnx2fc_wq; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* bnx2fc structure needs only one instance of the fcoe_percpu_s structure. 508c2ecf20Sopenharmony_ci * Here the io threads are per cpu but the l2 thread is just one 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistruct fcoe_percpu_s bnx2fc_global; 538c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(bnx2fc_global_lock); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic struct cnic_ulp_ops bnx2fc_cnic_cb; 568c2ecf20Sopenharmony_cistatic struct libfc_function_template bnx2fc_libfc_fcn_templ; 578c2ecf20Sopenharmony_cistatic struct scsi_host_template bnx2fc_shost_template; 588c2ecf20Sopenharmony_cistatic struct fc_function_template bnx2fc_transport_function; 598c2ecf20Sopenharmony_cistatic struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ; 608c2ecf20Sopenharmony_cistatic struct fc_function_template bnx2fc_vport_xport_function; 618c2ecf20Sopenharmony_cistatic int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode); 628c2ecf20Sopenharmony_cistatic void __bnx2fc_destroy(struct bnx2fc_interface *interface); 638c2ecf20Sopenharmony_cistatic int bnx2fc_destroy(struct net_device *net_device); 648c2ecf20Sopenharmony_cistatic int bnx2fc_enable(struct net_device *netdev); 658c2ecf20Sopenharmony_cistatic int bnx2fc_disable(struct net_device *netdev); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* fcoe_syfs control interface handlers */ 688c2ecf20Sopenharmony_cistatic int bnx2fc_ctlr_alloc(struct net_device *netdev); 698c2ecf20Sopenharmony_cistatic int bnx2fc_ctlr_enabled(struct fcoe_ctlr_device *cdev); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void bnx2fc_recv_frame(struct sk_buff *skb); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void bnx2fc_start_disc(struct bnx2fc_interface *interface); 748c2ecf20Sopenharmony_cistatic int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev); 758c2ecf20Sopenharmony_cistatic int bnx2fc_lport_config(struct fc_lport *lport); 768c2ecf20Sopenharmony_cistatic int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba); 778c2ecf20Sopenharmony_cistatic int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba); 788c2ecf20Sopenharmony_cistatic void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba); 798c2ecf20Sopenharmony_cistatic int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba); 808c2ecf20Sopenharmony_cistatic void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba); 818c2ecf20Sopenharmony_cistatic struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, 828c2ecf20Sopenharmony_ci struct device *parent, int npiv); 838c2ecf20Sopenharmony_cistatic void bnx2fc_port_destroy(struct fcoe_port *port); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev); 868c2ecf20Sopenharmony_cistatic struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device 878c2ecf20Sopenharmony_ci *phys_dev); 888c2ecf20Sopenharmony_cistatic inline void bnx2fc_interface_put(struct bnx2fc_interface *interface); 898c2ecf20Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int bnx2fc_fw_init(struct bnx2fc_hba *hba); 928c2ecf20Sopenharmony_cistatic void bnx2fc_fw_destroy(struct bnx2fc_hba *hba); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void bnx2fc_port_shutdown(struct fc_lport *lport); 958c2ecf20Sopenharmony_cistatic void bnx2fc_stop(struct bnx2fc_interface *interface); 968c2ecf20Sopenharmony_cistatic int __init bnx2fc_mod_init(void); 978c2ecf20Sopenharmony_cistatic void __exit bnx2fc_mod_exit(void); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciunsigned int bnx2fc_debug_level; 1008c2ecf20Sopenharmony_cimodule_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); 1018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_logging, 1028c2ecf20Sopenharmony_ci "Option to enable extended logging,\n" 1038c2ecf20Sopenharmony_ci "\t\tDefault is 0 - no logging.\n" 1048c2ecf20Sopenharmony_ci "\t\t0x01 - SCSI cmd error, cleanup.\n" 1058c2ecf20Sopenharmony_ci "\t\t0x02 - Session setup, cleanup, etc.\n" 1068c2ecf20Sopenharmony_ci "\t\t0x04 - lport events, link, mtu, etc.\n" 1078c2ecf20Sopenharmony_ci "\t\t0x08 - ELS logs.\n" 1088c2ecf20Sopenharmony_ci "\t\t0x10 - fcoe L2 fame related logs.\n" 1098c2ecf20Sopenharmony_ci "\t\t0xff - LOG all messages."); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic uint bnx2fc_devloss_tmo; 1128c2ecf20Sopenharmony_cimodule_param_named(devloss_tmo, bnx2fc_devloss_tmo, uint, S_IRUGO); 1138c2ecf20Sopenharmony_ciMODULE_PARM_DESC(devloss_tmo, " Change devloss_tmo for the remote ports " 1148c2ecf20Sopenharmony_ci "attached via bnx2fc."); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic uint bnx2fc_max_luns = BNX2FC_MAX_LUN; 1178c2ecf20Sopenharmony_cimodule_param_named(max_luns, bnx2fc_max_luns, uint, S_IRUGO); 1188c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_luns, " Change the default max_lun per SCSI host. Default " 1198c2ecf20Sopenharmony_ci "0xffff."); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic uint bnx2fc_queue_depth; 1228c2ecf20Sopenharmony_cimodule_param_named(queue_depth, bnx2fc_queue_depth, uint, S_IRUGO); 1238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(queue_depth, " Change the default queue depth of SCSI devices " 1248c2ecf20Sopenharmony_ci "attached via bnx2fc."); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic uint bnx2fc_log_fka; 1278c2ecf20Sopenharmony_cimodule_param_named(log_fka, bnx2fc_log_fka, uint, S_IRUGO|S_IWUSR); 1288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(log_fka, " Print message to kernel log when fcoe is " 1298c2ecf20Sopenharmony_ci "initiating a FIP keep alive when debug logging is enabled."); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline struct net_device *bnx2fc_netdev(const struct fc_lport *lport) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return ((struct bnx2fc_interface *) 1348c2ecf20Sopenharmony_ci ((struct fcoe_port *)lport_priv(lport))->priv)->netdev; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void bnx2fc_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct fcoe_ctlr_device *ctlr_dev = 1408c2ecf20Sopenharmony_ci fcoe_fcf_dev_to_ctlr_dev(fcf_dev); 1418c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); 1428c2ecf20Sopenharmony_ci struct bnx2fc_interface *fcoe = fcoe_ctlr_priv(ctlr); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci fcf_dev->vlan_id = fcoe->vlan_id; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void bnx2fc_clean_rx_queue(struct fc_lport *lp) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct fcoe_percpu_s *bg; 1508c2ecf20Sopenharmony_ci struct fcoe_rcv_info *fr; 1518c2ecf20Sopenharmony_ci struct sk_buff_head *list; 1528c2ecf20Sopenharmony_ci struct sk_buff *skb, *next; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci bg = &bnx2fc_global; 1558c2ecf20Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 1568c2ecf20Sopenharmony_ci list = &bg->fcoe_rx_list; 1578c2ecf20Sopenharmony_ci skb_queue_walk_safe(list, skb, next) { 1588c2ecf20Sopenharmony_ci fr = fcoe_dev_from_skb(skb); 1598c2ecf20Sopenharmony_ci if (fr->fr_dev == lp) { 1608c2ecf20Sopenharmony_ci __skb_unlink(skb, list); 1618c2ecf20Sopenharmony_ci kfree_skb(skb); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciint bnx2fc_get_paged_crc_eof(struct sk_buff *skb, int tlen) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci int rc; 1708c2ecf20Sopenharmony_ci spin_lock(&bnx2fc_global_lock); 1718c2ecf20Sopenharmony_ci rc = fcoe_get_paged_crc_eof(skb, tlen, &bnx2fc_global); 1728c2ecf20Sopenharmony_ci spin_unlock(&bnx2fc_global_lock); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return rc; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void bnx2fc_abort_io(struct fc_lport *lport) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * This function is no-op for bnx2fc, but we do 1818c2ecf20Sopenharmony_ci * not want to leave it as NULL either, as libfc 1828c2ecf20Sopenharmony_ci * can call the default function which is 1838c2ecf20Sopenharmony_ci * fc_fcp_abort_io. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void bnx2fc_cleanup(struct fc_lport *lport) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 1908c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 1918c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 1928c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 1938c2ecf20Sopenharmony_ci int i; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 1968c2ecf20Sopenharmony_ci mutex_lock(&hba->hba_mutex); 1978c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 1988c2ecf20Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { 1998c2ecf20Sopenharmony_ci tgt = hba->tgt_ofld_list[i]; 2008c2ecf20Sopenharmony_ci if (tgt) { 2018c2ecf20Sopenharmony_ci /* Cleanup IOs belonging to requested vport */ 2028c2ecf20Sopenharmony_ci if (tgt->port == port) { 2038c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 2048c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "flush/cleanup\n"); 2058c2ecf20Sopenharmony_ci bnx2fc_flush_active_ios(tgt); 2068c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 2118c2ecf20Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int bnx2fc_xmit_l2_frame(struct bnx2fc_rport *tgt, 2158c2ecf20Sopenharmony_ci struct fc_frame *fp) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata = tgt->rdata; 2188c2ecf20Sopenharmony_ci struct fc_frame_header *fh; 2198c2ecf20Sopenharmony_ci int rc = 0; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci fh = fc_frame_header_get(fp); 2228c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Xmit L2 frame rport = 0x%x, oxid = 0x%x, " 2238c2ecf20Sopenharmony_ci "r_ctl = 0x%x\n", rdata->ids.port_id, 2248c2ecf20Sopenharmony_ci ntohs(fh->fh_ox_id), fh->fh_r_ctl); 2258c2ecf20Sopenharmony_ci if ((fh->fh_type == FC_TYPE_ELS) && 2268c2ecf20Sopenharmony_ci (fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci switch (fc_frame_payload_op(fp)) { 2298c2ecf20Sopenharmony_ci case ELS_ADISC: 2308c2ecf20Sopenharmony_ci rc = bnx2fc_send_adisc(tgt, fp); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case ELS_LOGO: 2338c2ecf20Sopenharmony_ci rc = bnx2fc_send_logo(tgt, fp); 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case ELS_RLS: 2368c2ecf20Sopenharmony_ci rc = bnx2fc_send_rls(tgt, fp); 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci default: 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci } else if ((fh->fh_type == FC_TYPE_BLS) && 2428c2ecf20Sopenharmony_ci (fh->fh_r_ctl == FC_RCTL_BA_ABTS)) 2438c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "ABTS frame\n"); 2448c2ecf20Sopenharmony_ci else { 2458c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Send L2 frame type 0x%x " 2468c2ecf20Sopenharmony_ci "rctl 0x%x thru non-offload path\n", 2478c2ecf20Sopenharmony_ci fh->fh_type, fh->fh_r_ctl); 2488c2ecf20Sopenharmony_ci return -ENODEV; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci if (rc) 2518c2ecf20Sopenharmony_ci return -ENOMEM; 2528c2ecf20Sopenharmony_ci else 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/** 2578c2ecf20Sopenharmony_ci * bnx2fc_xmit - bnx2fc's FCoE frame transmit function 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * @lport: the associated local port 2608c2ecf20Sopenharmony_ci * @fp: the fc_frame to be transmitted 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_cistatic int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct ethhdr *eh; 2658c2ecf20Sopenharmony_ci struct fcoe_crc_eof *cp; 2668c2ecf20Sopenharmony_ci struct sk_buff *skb; 2678c2ecf20Sopenharmony_ci struct fc_frame_header *fh; 2688c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 2698c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 2708c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 2718c2ecf20Sopenharmony_ci struct fcoe_port *port; 2728c2ecf20Sopenharmony_ci struct fcoe_hdr *hp; 2738c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 2748c2ecf20Sopenharmony_ci struct fc_stats *stats; 2758c2ecf20Sopenharmony_ci u8 sof, eof; 2768c2ecf20Sopenharmony_ci u32 crc; 2778c2ecf20Sopenharmony_ci unsigned int hlen, tlen, elen; 2788c2ecf20Sopenharmony_ci int wlen, rc = 0; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci port = (struct fcoe_port *)lport_priv(lport); 2818c2ecf20Sopenharmony_ci interface = port->priv; 2828c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 2838c2ecf20Sopenharmony_ci hba = interface->hba; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci fh = fc_frame_header_get(fp); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci skb = fp_skb(fp); 2888c2ecf20Sopenharmony_ci if (!lport->link_up) { 2898c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "bnx2fc_xmit link down\n"); 2908c2ecf20Sopenharmony_ci kfree_skb(skb); 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { 2958c2ecf20Sopenharmony_ci if (!ctlr->sel_fcf) { 2968c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "FCF not selected yet!\n"); 2978c2ecf20Sopenharmony_ci kfree_skb(skb); 2988c2ecf20Sopenharmony_ci return -EINVAL; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci if (fcoe_ctlr_els_send(ctlr, lport, skb)) 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci sof = fr_sof(fp); 3058c2ecf20Sopenharmony_ci eof = fr_eof(fp); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * Snoop the frame header to check if the frame is for 3098c2ecf20Sopenharmony_ci * an offloaded session 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * tgt_ofld_list access is synchronized using 3138c2ecf20Sopenharmony_ci * both hba mutex and hba lock. Atleast hba mutex or 3148c2ecf20Sopenharmony_ci * hba lock needs to be held for read access. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 3188c2ecf20Sopenharmony_ci tgt = bnx2fc_tgt_lookup(port, ntoh24(fh->fh_d_id)); 3198c2ecf20Sopenharmony_ci if (tgt && (test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) { 3208c2ecf20Sopenharmony_ci /* This frame is for offloaded session */ 3218c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "xmit: Frame is for offloaded session " 3228c2ecf20Sopenharmony_ci "port_id = 0x%x\n", ntoh24(fh->fh_d_id)); 3238c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 3248c2ecf20Sopenharmony_ci rc = bnx2fc_xmit_l2_frame(tgt, fp); 3258c2ecf20Sopenharmony_ci if (rc != -ENODEV) { 3268c2ecf20Sopenharmony_ci kfree_skb(skb); 3278c2ecf20Sopenharmony_ci return rc; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } else { 3308c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci elen = sizeof(struct ethhdr); 3348c2ecf20Sopenharmony_ci hlen = sizeof(struct fcoe_hdr); 3358c2ecf20Sopenharmony_ci tlen = sizeof(struct fcoe_crc_eof); 3368c2ecf20Sopenharmony_ci wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 3398c2ecf20Sopenharmony_ci crc = fcoe_fc_crc(fp); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* copy port crc and eof to the skb buff */ 3428c2ecf20Sopenharmony_ci if (skb_is_nonlinear(skb)) { 3438c2ecf20Sopenharmony_ci skb_frag_t *frag; 3448c2ecf20Sopenharmony_ci if (bnx2fc_get_paged_crc_eof(skb, tlen)) { 3458c2ecf20Sopenharmony_ci kfree_skb(skb); 3468c2ecf20Sopenharmony_ci return -ENOMEM; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; 3498c2ecf20Sopenharmony_ci cp = kmap_atomic(skb_frag_page(frag)) + skb_frag_off(frag); 3508c2ecf20Sopenharmony_ci } else { 3518c2ecf20Sopenharmony_ci cp = skb_put(skb, tlen); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci memset(cp, 0, sizeof(*cp)); 3558c2ecf20Sopenharmony_ci cp->fcoe_eof = eof; 3568c2ecf20Sopenharmony_ci cp->fcoe_crc32 = cpu_to_le32(~crc); 3578c2ecf20Sopenharmony_ci if (skb_is_nonlinear(skb)) { 3588c2ecf20Sopenharmony_ci kunmap_atomic(cp); 3598c2ecf20Sopenharmony_ci cp = NULL; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* adjust skb network/transport offsets to match mac/fcoe/port */ 3638c2ecf20Sopenharmony_ci skb_push(skb, elen + hlen); 3648c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 3658c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 3668c2ecf20Sopenharmony_ci skb->mac_len = elen; 3678c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_FCOE); 3688c2ecf20Sopenharmony_ci skb->dev = interface->netdev; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* fill up mac and fcoe headers */ 3718c2ecf20Sopenharmony_ci eh = eth_hdr(skb); 3728c2ecf20Sopenharmony_ci eh->h_proto = htons(ETH_P_FCOE); 3738c2ecf20Sopenharmony_ci if (ctlr->map_dest) 3748c2ecf20Sopenharmony_ci fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); 3758c2ecf20Sopenharmony_ci else 3768c2ecf20Sopenharmony_ci /* insert GW address */ 3778c2ecf20Sopenharmony_ci memcpy(eh->h_dest, ctlr->dest_addr, ETH_ALEN); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (unlikely(ctlr->flogi_oxid != FC_XID_UNKNOWN)) 3808c2ecf20Sopenharmony_ci memcpy(eh->h_source, ctlr->ctl_src_addr, ETH_ALEN); 3818c2ecf20Sopenharmony_ci else 3828c2ecf20Sopenharmony_ci memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci hp = (struct fcoe_hdr *)(eh + 1); 3858c2ecf20Sopenharmony_ci memset(hp, 0, sizeof(*hp)); 3868c2ecf20Sopenharmony_ci if (FC_FCOE_VER) 3878c2ecf20Sopenharmony_ci FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); 3888c2ecf20Sopenharmony_ci hp->fcoe_sof = sof; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ 3918c2ecf20Sopenharmony_ci if (lport->seq_offload && fr_max_payload(fp)) { 3928c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; 3938c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_size = fr_max_payload(fp); 3948c2ecf20Sopenharmony_ci } else { 3958c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type = 0; 3968c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_size = 0; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /*update tx stats */ 4008c2ecf20Sopenharmony_ci stats = per_cpu_ptr(lport->stats, get_cpu()); 4018c2ecf20Sopenharmony_ci stats->TxFrames++; 4028c2ecf20Sopenharmony_ci stats->TxWords += wlen; 4038c2ecf20Sopenharmony_ci put_cpu(); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* send down to lld */ 4068c2ecf20Sopenharmony_ci fr_dev(fp) = lport; 4078c2ecf20Sopenharmony_ci if (port->fcoe_pending_queue.qlen) 4088c2ecf20Sopenharmony_ci fcoe_check_wait_queue(lport, skb); 4098c2ecf20Sopenharmony_ci else if (fcoe_start_io(skb)) 4108c2ecf20Sopenharmony_ci fcoe_check_wait_queue(lport, skb); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci/** 4168c2ecf20Sopenharmony_ci * bnx2fc_rcv - This is bnx2fc's receive function called by NET_RX_SOFTIRQ 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * @skb: the receive socket buffer 4198c2ecf20Sopenharmony_ci * @dev: associated net device 4208c2ecf20Sopenharmony_ci * @ptype: context 4218c2ecf20Sopenharmony_ci * @olddev: last device 4228c2ecf20Sopenharmony_ci * 4238c2ecf20Sopenharmony_ci * This function receives the packet and builds FC frame and passes it up 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_cistatic int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, 4268c2ecf20Sopenharmony_ci struct packet_type *ptype, struct net_device *olddev) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct fc_lport *lport; 4298c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 4308c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 4318c2ecf20Sopenharmony_ci struct fcoe_rcv_info *fr; 4328c2ecf20Sopenharmony_ci struct fcoe_percpu_s *bg; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci interface = container_of(ptype, struct bnx2fc_interface, 4358c2ecf20Sopenharmony_ci fcoe_packet_type); 4368c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 4378c2ecf20Sopenharmony_ci lport = ctlr->lp; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (unlikely(lport == NULL)) { 4408c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_rcv: lport is NULL\n"); 4418c2ecf20Sopenharmony_ci goto err; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 4458c2ecf20Sopenharmony_ci if (!skb) 4468c2ecf20Sopenharmony_ci return -1; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { 4498c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n"); 4508c2ecf20Sopenharmony_ci goto err; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * Check for minimum frame length, and make sure required FCoE 4558c2ecf20Sopenharmony_ci * and FC headers are pulled into the linear data area. 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_ci if (unlikely((skb->len < FCOE_MIN_FRAME) || 4588c2ecf20Sopenharmony_ci !pskb_may_pull(skb, FCOE_HEADER_LEN))) 4598c2ecf20Sopenharmony_ci goto err; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci fr = fcoe_dev_from_skb(skb); 4648c2ecf20Sopenharmony_ci fr->fr_dev = lport; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci bg = &bnx2fc_global; 4678c2ecf20Sopenharmony_ci spin_lock(&bg->fcoe_rx_list.lock); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci __skb_queue_tail(&bg->fcoe_rx_list, skb); 4708c2ecf20Sopenharmony_ci if (bg->fcoe_rx_list.qlen == 1) 4718c2ecf20Sopenharmony_ci wake_up_process(bg->kthread); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci spin_unlock(&bg->fcoe_rx_list.lock); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_cierr: 4778c2ecf20Sopenharmony_ci kfree_skb(skb); 4788c2ecf20Sopenharmony_ci return -1; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int bnx2fc_l2_rcv_thread(void *arg) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct fcoe_percpu_s *bg = arg; 4848c2ecf20Sopenharmony_ci struct sk_buff *skb; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci set_user_nice(current, MIN_NICE); 4878c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 4888c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 4898c2ecf20Sopenharmony_ci schedule(); 4908c2ecf20Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 4918c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) { 4928c2ecf20Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 4938c2ecf20Sopenharmony_ci bnx2fc_recv_frame(skb); 4948c2ecf20Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci __set_current_state(TASK_INTERRUPTIBLE); 4978c2ecf20Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void bnx2fc_recv_frame(struct sk_buff *skb) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci u64 crc_err; 5078c2ecf20Sopenharmony_ci u32 fr_len, fr_crc; 5088c2ecf20Sopenharmony_ci struct fc_lport *lport; 5098c2ecf20Sopenharmony_ci struct fcoe_rcv_info *fr; 5108c2ecf20Sopenharmony_ci struct fc_stats *stats; 5118c2ecf20Sopenharmony_ci struct fc_frame_header *fh; 5128c2ecf20Sopenharmony_ci struct fcoe_crc_eof crc_eof; 5138c2ecf20Sopenharmony_ci struct fc_frame *fp; 5148c2ecf20Sopenharmony_ci struct fc_lport *vn_port; 5158c2ecf20Sopenharmony_ci struct fcoe_port *port, *phys_port; 5168c2ecf20Sopenharmony_ci u8 *mac = NULL; 5178c2ecf20Sopenharmony_ci u8 *dest_mac = NULL; 5188c2ecf20Sopenharmony_ci struct fcoe_hdr *hp; 5198c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 5208c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci fr = fcoe_dev_from_skb(skb); 5238c2ecf20Sopenharmony_ci lport = fr->fr_dev; 5248c2ecf20Sopenharmony_ci if (unlikely(lport == NULL)) { 5258c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Invalid lport struct\n"); 5268c2ecf20Sopenharmony_ci kfree_skb(skb); 5278c2ecf20Sopenharmony_ci return; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (skb_is_nonlinear(skb)) 5318c2ecf20Sopenharmony_ci skb_linearize(skb); 5328c2ecf20Sopenharmony_ci mac = eth_hdr(skb)->h_source; 5338c2ecf20Sopenharmony_ci dest_mac = eth_hdr(skb)->h_dest; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* Pull the header */ 5368c2ecf20Sopenharmony_ci hp = (struct fcoe_hdr *) skb_network_header(skb); 5378c2ecf20Sopenharmony_ci fh = (struct fc_frame_header *) skb_transport_header(skb); 5388c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct fcoe_hdr)); 5398c2ecf20Sopenharmony_ci fr_len = skb->len - sizeof(struct fcoe_crc_eof); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci stats = per_cpu_ptr(lport->stats, get_cpu()); 5428c2ecf20Sopenharmony_ci stats->RxFrames++; 5438c2ecf20Sopenharmony_ci stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; 5448c2ecf20Sopenharmony_ci put_cpu(); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci fp = (struct fc_frame *)skb; 5478c2ecf20Sopenharmony_ci fc_frame_init(fp); 5488c2ecf20Sopenharmony_ci fr_dev(fp) = lport; 5498c2ecf20Sopenharmony_ci fr_sof(fp) = hp->fcoe_sof; 5508c2ecf20Sopenharmony_ci if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { 5518c2ecf20Sopenharmony_ci kfree_skb(skb); 5528c2ecf20Sopenharmony_ci return; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci fr_eof(fp) = crc_eof.fcoe_eof; 5558c2ecf20Sopenharmony_ci fr_crc(fp) = crc_eof.fcoe_crc32; 5568c2ecf20Sopenharmony_ci if (pskb_trim(skb, fr_len)) { 5578c2ecf20Sopenharmony_ci kfree_skb(skb); 5588c2ecf20Sopenharmony_ci return; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci phys_port = lport_priv(lport); 5628c2ecf20Sopenharmony_ci interface = phys_port->priv; 5638c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci fh = fc_frame_header_get(fp); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (ntoh24(&dest_mac[3]) != ntoh24(fh->fh_d_id)) { 5688c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "FC frame d_id mismatch with MAC %pM.\n", 5698c2ecf20Sopenharmony_ci dest_mac); 5708c2ecf20Sopenharmony_ci kfree_skb(skb); 5718c2ecf20Sopenharmony_ci return; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci vn_port = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id)); 5758c2ecf20Sopenharmony_ci if (vn_port) { 5768c2ecf20Sopenharmony_ci port = lport_priv(vn_port); 5778c2ecf20Sopenharmony_ci if (!ether_addr_equal(port->data_src_addr, dest_mac)) { 5788c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "fpma mismatch\n"); 5798c2ecf20Sopenharmony_ci kfree_skb(skb); 5808c2ecf20Sopenharmony_ci return; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci if (ctlr->state) { 5848c2ecf20Sopenharmony_ci if (!ether_addr_equal(mac, ctlr->dest_addr)) { 5858c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Wrong source address: mac:%pM dest_addr:%pM.\n", 5868c2ecf20Sopenharmony_ci mac, ctlr->dest_addr); 5878c2ecf20Sopenharmony_ci kfree_skb(skb); 5888c2ecf20Sopenharmony_ci return; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && 5928c2ecf20Sopenharmony_ci fh->fh_type == FC_TYPE_FCP) { 5938c2ecf20Sopenharmony_ci /* Drop FCP data. We dont this in L2 path */ 5948c2ecf20Sopenharmony_ci kfree_skb(skb); 5958c2ecf20Sopenharmony_ci return; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && 5988c2ecf20Sopenharmony_ci fh->fh_type == FC_TYPE_ELS) { 5998c2ecf20Sopenharmony_ci switch (fc_frame_payload_op(fp)) { 6008c2ecf20Sopenharmony_ci case ELS_LOGO: 6018c2ecf20Sopenharmony_ci if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { 6028c2ecf20Sopenharmony_ci /* drop non-FIP LOGO */ 6038c2ecf20Sopenharmony_ci kfree_skb(skb); 6048c2ecf20Sopenharmony_ci return; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (fh->fh_r_ctl == FC_RCTL_BA_ABTS) { 6118c2ecf20Sopenharmony_ci /* Drop incoming ABTS */ 6128c2ecf20Sopenharmony_ci kfree_skb(skb); 6138c2ecf20Sopenharmony_ci return; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* 6178c2ecf20Sopenharmony_ci * If the destination ID from the frame header does not match what we 6188c2ecf20Sopenharmony_ci * have on record for lport and the search for a NPIV port came up 6198c2ecf20Sopenharmony_ci * empty then this is not addressed to our port so simply drop it. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_ci if (lport->port_id != ntoh24(fh->fh_d_id) && !vn_port) { 6228c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Dropping frame due to destination mismatch: lport->port_id=%x fh->d_id=%x.\n", 6238c2ecf20Sopenharmony_ci lport->port_id, ntoh24(fh->fh_d_id)); 6248c2ecf20Sopenharmony_ci kfree_skb(skb); 6258c2ecf20Sopenharmony_ci return; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci fr_crc = le32_to_cpu(fr_crc(fp)); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (unlikely(fr_crc != ~crc32(~0, skb->data, fr_len))) { 6318c2ecf20Sopenharmony_ci stats = per_cpu_ptr(lport->stats, get_cpu()); 6328c2ecf20Sopenharmony_ci crc_err = (stats->InvalidCRCCount++); 6338c2ecf20Sopenharmony_ci put_cpu(); 6348c2ecf20Sopenharmony_ci if (crc_err < 5) 6358c2ecf20Sopenharmony_ci printk(KERN_WARNING PFX "dropping frame with " 6368c2ecf20Sopenharmony_ci "CRC error\n"); 6378c2ecf20Sopenharmony_ci kfree_skb(skb); 6388c2ecf20Sopenharmony_ci return; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci fc_exch_recv(lport, fp); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * bnx2fc_percpu_io_thread - thread per cpu for ios 6458c2ecf20Sopenharmony_ci * 6468c2ecf20Sopenharmony_ci * @arg: ptr to bnx2fc_percpu_info structure 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_cistatic int bnx2fc_percpu_io_thread(void *arg) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct bnx2fc_percpu_s *p = arg; 6518c2ecf20Sopenharmony_ci struct bnx2fc_work *work, *tmp; 6528c2ecf20Sopenharmony_ci LIST_HEAD(work_list); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci set_user_nice(current, MIN_NICE); 6558c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 6568c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 6578c2ecf20Sopenharmony_ci schedule(); 6588c2ecf20Sopenharmony_ci spin_lock_bh(&p->fp_work_lock); 6598c2ecf20Sopenharmony_ci while (!list_empty(&p->work_list)) { 6608c2ecf20Sopenharmony_ci list_splice_init(&p->work_list, &work_list); 6618c2ecf20Sopenharmony_ci spin_unlock_bh(&p->fp_work_lock); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci list_for_each_entry_safe(work, tmp, &work_list, list) { 6648c2ecf20Sopenharmony_ci list_del_init(&work->list); 6658c2ecf20Sopenharmony_ci bnx2fc_process_cq_compl(work->tgt, work->wqe, 6668c2ecf20Sopenharmony_ci work->rq_data, 6678c2ecf20Sopenharmony_ci work->num_rq, 6688c2ecf20Sopenharmony_ci work->task); 6698c2ecf20Sopenharmony_ci kfree(work); 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci spin_lock_bh(&p->fp_work_lock); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci __set_current_state(TASK_INTERRUPTIBLE); 6758c2ecf20Sopenharmony_ci spin_unlock_bh(&p->fp_work_lock); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct fc_host_statistics *bnx2fc_stats; 6858c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 6868c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 6878c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 6888c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 6898c2ecf20Sopenharmony_ci struct fcoe_statistics_params *fw_stats; 6908c2ecf20Sopenharmony_ci int rc = 0; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci fw_stats = (struct fcoe_statistics_params *)hba->stats_buffer; 6938c2ecf20Sopenharmony_ci if (!fw_stats) 6948c2ecf20Sopenharmony_ci return NULL; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci mutex_lock(&hba->hba_stats_mutex); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci bnx2fc_stats = fc_get_host_stats(shost); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci init_completion(&hba->stat_req_done); 7018c2ecf20Sopenharmony_ci if (bnx2fc_send_stat_req(hba)) 7028c2ecf20Sopenharmony_ci goto unlock_stats_mutex; 7038c2ecf20Sopenharmony_ci rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ)); 7048c2ecf20Sopenharmony_ci if (!rc) { 7058c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "FW stat req timed out\n"); 7068c2ecf20Sopenharmony_ci goto unlock_stats_mutex; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci BNX2FC_STATS(hba, rx_stat2, fc_crc_cnt); 7098c2ecf20Sopenharmony_ci bnx2fc_stats->invalid_crc_count += hba->bfw_stats.fc_crc_cnt; 7108c2ecf20Sopenharmony_ci BNX2FC_STATS(hba, tx_stat, fcoe_tx_pkt_cnt); 7118c2ecf20Sopenharmony_ci bnx2fc_stats->tx_frames += hba->bfw_stats.fcoe_tx_pkt_cnt; 7128c2ecf20Sopenharmony_ci BNX2FC_STATS(hba, tx_stat, fcoe_tx_byte_cnt); 7138c2ecf20Sopenharmony_ci bnx2fc_stats->tx_words += ((hba->bfw_stats.fcoe_tx_byte_cnt) / 4); 7148c2ecf20Sopenharmony_ci BNX2FC_STATS(hba, rx_stat0, fcoe_rx_pkt_cnt); 7158c2ecf20Sopenharmony_ci bnx2fc_stats->rx_frames += hba->bfw_stats.fcoe_rx_pkt_cnt; 7168c2ecf20Sopenharmony_ci BNX2FC_STATS(hba, rx_stat0, fcoe_rx_byte_cnt); 7178c2ecf20Sopenharmony_ci bnx2fc_stats->rx_words += ((hba->bfw_stats.fcoe_rx_byte_cnt) / 4); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci bnx2fc_stats->dumped_frames = 0; 7208c2ecf20Sopenharmony_ci bnx2fc_stats->lip_count = 0; 7218c2ecf20Sopenharmony_ci bnx2fc_stats->nos_count = 0; 7228c2ecf20Sopenharmony_ci bnx2fc_stats->loss_of_sync_count = 0; 7238c2ecf20Sopenharmony_ci bnx2fc_stats->loss_of_signal_count = 0; 7248c2ecf20Sopenharmony_ci bnx2fc_stats->prim_seq_protocol_err_count = 0; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci memcpy(&hba->prev_stats, hba->stats_buffer, 7278c2ecf20Sopenharmony_ci sizeof(struct fcoe_statistics_params)); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ciunlock_stats_mutex: 7308c2ecf20Sopenharmony_ci mutex_unlock(&hba->hba_stats_mutex); 7318c2ecf20Sopenharmony_ci return bnx2fc_stats; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 7378c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 7388c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 7398c2ecf20Sopenharmony_ci struct Scsi_Host *shost = lport->host; 7408c2ecf20Sopenharmony_ci int rc = 0; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci shost->max_cmd_len = BNX2FC_MAX_CMD_LEN; 7438c2ecf20Sopenharmony_ci shost->max_lun = bnx2fc_max_luns; 7448c2ecf20Sopenharmony_ci shost->max_id = BNX2FC_MAX_FCP_TGT; 7458c2ecf20Sopenharmony_ci shost->max_channel = 0; 7468c2ecf20Sopenharmony_ci if (lport->vport) 7478c2ecf20Sopenharmony_ci shost->transportt = bnx2fc_vport_xport_template; 7488c2ecf20Sopenharmony_ci else 7498c2ecf20Sopenharmony_ci shost->transportt = bnx2fc_transport_template; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Add the new host to SCSI-ml */ 7528c2ecf20Sopenharmony_ci rc = scsi_add_host(lport->host, dev); 7538c2ecf20Sopenharmony_ci if (rc) { 7548c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Error on scsi_add_host\n"); 7558c2ecf20Sopenharmony_ci return rc; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci if (!lport->vport) 7588c2ecf20Sopenharmony_ci fc_host_max_npiv_vports(lport->host) = USHRT_MAX; 7598c2ecf20Sopenharmony_ci snprintf(fc_host_symbolic_name(lport->host), 256, 7608c2ecf20Sopenharmony_ci "%s (QLogic %s) v%s over %s", 7618c2ecf20Sopenharmony_ci BNX2FC_NAME, hba->chip_num, BNX2FC_VERSION, 7628c2ecf20Sopenharmony_ci interface->netdev->name); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic int bnx2fc_link_ok(struct fc_lport *lport) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 7708c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 7718c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 7728c2ecf20Sopenharmony_ci struct net_device *dev = hba->phys_dev; 7738c2ecf20Sopenharmony_ci int rc = 0; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) 7768c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 7778c2ecf20Sopenharmony_ci else { 7788c2ecf20Sopenharmony_ci set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 7798c2ecf20Sopenharmony_ci rc = -1; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci return rc; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci/** 7858c2ecf20Sopenharmony_ci * bnx2fc_get_link_state - get network link state 7868c2ecf20Sopenharmony_ci * 7878c2ecf20Sopenharmony_ci * @hba: adapter instance pointer 7888c2ecf20Sopenharmony_ci * 7898c2ecf20Sopenharmony_ci * updates adapter structure flag based on netdev state 7908c2ecf20Sopenharmony_ci */ 7918c2ecf20Sopenharmony_civoid bnx2fc_get_link_state(struct bnx2fc_hba *hba) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci if (test_bit(__LINK_STATE_NOCARRIER, &hba->phys_dev->state)) 7948c2ecf20Sopenharmony_ci set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 7958c2ecf20Sopenharmony_ci else 7968c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 8028c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 8038c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 8048c2ecf20Sopenharmony_ci struct fcoe_port *port; 8058c2ecf20Sopenharmony_ci u64 wwnn, wwpn; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci port = lport_priv(lport); 8088c2ecf20Sopenharmony_ci interface = port->priv; 8098c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 8108c2ecf20Sopenharmony_ci hba = interface->hba; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* require support for get_pauseparam ethtool op. */ 8138c2ecf20Sopenharmony_ci if (!hba->phys_dev->ethtool_ops || 8148c2ecf20Sopenharmony_ci !hba->phys_dev->ethtool_ops->get_pauseparam) 8158c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (fc_set_mfs(lport, BNX2FC_MFS)) 8188c2ecf20Sopenharmony_ci return -EINVAL; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci skb_queue_head_init(&port->fcoe_pending_queue); 8218c2ecf20Sopenharmony_ci port->fcoe_pending_queue_active = 0; 8228c2ecf20Sopenharmony_ci timer_setup(&port->timer, fcoe_queue_timer, 0); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci fcoe_link_speed_update(lport); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (!lport->vport) { 8278c2ecf20Sopenharmony_ci if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) 8288c2ecf20Sopenharmony_ci wwnn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 8298c2ecf20Sopenharmony_ci 1, 0); 8308c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn); 8318c2ecf20Sopenharmony_ci fc_set_wwnn(lport, wwnn); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) 8348c2ecf20Sopenharmony_ci wwpn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 8358c2ecf20Sopenharmony_ci 2, 0); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn); 8388c2ecf20Sopenharmony_ci fc_set_wwpn(lport, wwpn); 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic void bnx2fc_destroy_timer(struct timer_list *t) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = from_timer(hba, t, destroy_timer); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR:bnx2fc_destroy_timer - " 8498c2ecf20Sopenharmony_ci "Destroy compl not received!!\n"); 8508c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); 8518c2ecf20Sopenharmony_ci wake_up_interruptible(&hba->destroy_wait); 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci/** 8558c2ecf20Sopenharmony_ci * bnx2fc_indicate_netevent - Generic netdev event handler 8568c2ecf20Sopenharmony_ci * 8578c2ecf20Sopenharmony_ci * @context: adapter structure pointer 8588c2ecf20Sopenharmony_ci * @event: event type 8598c2ecf20Sopenharmony_ci * @vlan_id: vlan id - associated vlan id with this event 8608c2ecf20Sopenharmony_ci * 8618c2ecf20Sopenharmony_ci * Handles NETDEV_UP, NETDEV_DOWN, NETDEV_GOING_DOWN,NETDEV_CHANGE and 8628c2ecf20Sopenharmony_ci * NETDEV_CHANGE_MTU events. Handle NETDEV_UNREGISTER only for vlans. 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_cistatic void bnx2fc_indicate_netevent(void *context, unsigned long event, 8658c2ecf20Sopenharmony_ci u16 vlan_id) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; 8688c2ecf20Sopenharmony_ci struct fcoe_ctlr_device *cdev; 8698c2ecf20Sopenharmony_ci struct fc_lport *lport; 8708c2ecf20Sopenharmony_ci struct fc_lport *vport; 8718c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface, *tmp; 8728c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 8738c2ecf20Sopenharmony_ci int wait_for_upload = 0; 8748c2ecf20Sopenharmony_ci u32 link_possible = 1; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (vlan_id != 0 && event != NETDEV_UNREGISTER) 8778c2ecf20Sopenharmony_ci return; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci switch (event) { 8808c2ecf20Sopenharmony_ci case NETDEV_UP: 8818c2ecf20Sopenharmony_ci if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) 8828c2ecf20Sopenharmony_ci printk(KERN_ERR "indicate_netevent: "\ 8838c2ecf20Sopenharmony_ci "hba is not UP!!\n"); 8848c2ecf20Sopenharmony_ci break; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci case NETDEV_DOWN: 8878c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); 8888c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); 8898c2ecf20Sopenharmony_ci link_possible = 0; 8908c2ecf20Sopenharmony_ci break; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci case NETDEV_GOING_DOWN: 8938c2ecf20Sopenharmony_ci set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); 8948c2ecf20Sopenharmony_ci link_possible = 0; 8958c2ecf20Sopenharmony_ci break; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci case NETDEV_CHANGE: 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci case NETDEV_UNREGISTER: 9018c2ecf20Sopenharmony_ci if (!vlan_id) 9028c2ecf20Sopenharmony_ci return; 9038c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 9048c2ecf20Sopenharmony_ci list_for_each_entry_safe(interface, tmp, &if_list, list) { 9058c2ecf20Sopenharmony_ci if (interface->hba == hba && 9068c2ecf20Sopenharmony_ci interface->vlan_id == (vlan_id & VLAN_VID_MASK)) 9078c2ecf20Sopenharmony_ci __bnx2fc_destroy(interface); 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 9108c2ecf20Sopenharmony_ci return; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci default: 9138c2ecf20Sopenharmony_ci return; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 9178c2ecf20Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (interface->hba != hba) 9208c2ecf20Sopenharmony_ci continue; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 9238c2ecf20Sopenharmony_ci lport = ctlr->lp; 9248c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "netevent handler - event=%s %ld\n", 9258c2ecf20Sopenharmony_ci interface->netdev->name, event); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci fcoe_link_speed_update(lport); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (link_possible && !bnx2fc_link_ok(lport)) { 9328c2ecf20Sopenharmony_ci switch (cdev->enabled) { 9338c2ecf20Sopenharmony_ci case FCOE_CTLR_DISABLED: 9348c2ecf20Sopenharmony_ci pr_info("Link up while interface is disabled.\n"); 9358c2ecf20Sopenharmony_ci break; 9368c2ecf20Sopenharmony_ci case FCOE_CTLR_ENABLED: 9378c2ecf20Sopenharmony_ci case FCOE_CTLR_UNUSED: 9388c2ecf20Sopenharmony_ci /* Reset max recv frame size to default */ 9398c2ecf20Sopenharmony_ci fc_set_mfs(lport, BNX2FC_MFS); 9408c2ecf20Sopenharmony_ci /* 9418c2ecf20Sopenharmony_ci * ctlr link up will only be handled during 9428c2ecf20Sopenharmony_ci * enable to avoid sending discovery 9438c2ecf20Sopenharmony_ci * solicitation on a stale vlan 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_ci if (interface->enabled) 9468c2ecf20Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci } else if (fcoe_ctlr_link_down(ctlr)) { 9498c2ecf20Sopenharmony_ci switch (cdev->enabled) { 9508c2ecf20Sopenharmony_ci case FCOE_CTLR_DISABLED: 9518c2ecf20Sopenharmony_ci pr_info("Link down while interface is disabled.\n"); 9528c2ecf20Sopenharmony_ci break; 9538c2ecf20Sopenharmony_ci case FCOE_CTLR_ENABLED: 9548c2ecf20Sopenharmony_ci case FCOE_CTLR_UNUSED: 9558c2ecf20Sopenharmony_ci mutex_lock(&lport->lp_mutex); 9568c2ecf20Sopenharmony_ci list_for_each_entry(vport, &lport->vports, list) 9578c2ecf20Sopenharmony_ci fc_host_port_type(vport->host) = 9588c2ecf20Sopenharmony_ci FC_PORTTYPE_UNKNOWN; 9598c2ecf20Sopenharmony_ci mutex_unlock(&lport->lp_mutex); 9608c2ecf20Sopenharmony_ci fc_host_port_type(lport->host) = 9618c2ecf20Sopenharmony_ci FC_PORTTYPE_UNKNOWN; 9628c2ecf20Sopenharmony_ci per_cpu_ptr(lport->stats, 9638c2ecf20Sopenharmony_ci get_cpu())->LinkFailureCount++; 9648c2ecf20Sopenharmony_ci put_cpu(); 9658c2ecf20Sopenharmony_ci fcoe_clean_pending_queue(lport); 9668c2ecf20Sopenharmony_ci wait_for_upload = 1; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (wait_for_upload) { 9738c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_READY, &hba->adapter_state); 9748c2ecf20Sopenharmony_ci init_waitqueue_head(&hba->shutdown_wait); 9758c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("indicate_netevent " 9768c2ecf20Sopenharmony_ci "num_ofld_sess = %d\n", 9778c2ecf20Sopenharmony_ci hba->num_ofld_sess); 9788c2ecf20Sopenharmony_ci hba->wait_for_link_down = 1; 9798c2ecf20Sopenharmony_ci wait_event_interruptible(hba->shutdown_wait, 9808c2ecf20Sopenharmony_ci (hba->num_ofld_sess == 0)); 9818c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("wakeup - num_ofld_sess = %d\n", 9828c2ecf20Sopenharmony_ci hba->num_ofld_sess); 9838c2ecf20Sopenharmony_ci hba->wait_for_link_down = 0; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (signal_pending(current)) 9868c2ecf20Sopenharmony_ci flush_signals(current); 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic int bnx2fc_libfc_config(struct fc_lport *lport) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* Set the function pointers set by bnx2fc driver */ 9948c2ecf20Sopenharmony_ci memcpy(&lport->tt, &bnx2fc_libfc_fcn_templ, 9958c2ecf20Sopenharmony_ci sizeof(struct libfc_function_template)); 9968c2ecf20Sopenharmony_ci fc_elsct_init(lport); 9978c2ecf20Sopenharmony_ci fc_exch_init(lport); 9988c2ecf20Sopenharmony_ci fc_disc_init(lport); 9998c2ecf20Sopenharmony_ci fc_disc_config(lport, lport); 10008c2ecf20Sopenharmony_ci return 0; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci int fcoe_min_xid, fcoe_max_xid; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci fcoe_min_xid = hba->max_xid + 1; 10088c2ecf20Sopenharmony_ci if (nr_cpu_ids <= 2) 10098c2ecf20Sopenharmony_ci fcoe_max_xid = hba->max_xid + FCOE_XIDS_PER_CPU_OFFSET; 10108c2ecf20Sopenharmony_ci else 10118c2ecf20Sopenharmony_ci fcoe_max_xid = hba->max_xid + FCOE_MAX_XID_OFFSET; 10128c2ecf20Sopenharmony_ci if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, fcoe_min_xid, 10138c2ecf20Sopenharmony_ci fcoe_max_xid, NULL)) { 10148c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n"); 10158c2ecf20Sopenharmony_ci return -ENOMEM; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return 0; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic int bnx2fc_lport_config(struct fc_lport *lport) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci lport->link_up = 0; 10248c2ecf20Sopenharmony_ci lport->qfull = 0; 10258c2ecf20Sopenharmony_ci lport->max_retry_count = BNX2FC_MAX_RETRY_CNT; 10268c2ecf20Sopenharmony_ci lport->max_rport_retry_count = BNX2FC_MAX_RPORT_RETRY_CNT; 10278c2ecf20Sopenharmony_ci lport->e_d_tov = 2 * 1000; 10288c2ecf20Sopenharmony_ci lport->r_a_tov = 10 * 1000; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | 10318c2ecf20Sopenharmony_ci FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); 10328c2ecf20Sopenharmony_ci lport->does_npiv = 1; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci memset(&lport->rnid_gen, 0, sizeof(struct fc_els_rnid_gen)); 10358c2ecf20Sopenharmony_ci lport->rnid_gen.rnid_atype = BNX2FC_RNID_HBA; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* alloc stats structure */ 10388c2ecf20Sopenharmony_ci if (fc_lport_init_stats(lport)) 10398c2ecf20Sopenharmony_ci return -ENOMEM; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Finish fc_lport configuration */ 10428c2ecf20Sopenharmony_ci fc_lport_config(lport); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci/** 10488c2ecf20Sopenharmony_ci * bnx2fc_fip_recv - handle a received FIP frame. 10498c2ecf20Sopenharmony_ci * 10508c2ecf20Sopenharmony_ci * @skb: the received skb 10518c2ecf20Sopenharmony_ci * @dev: associated &net_device 10528c2ecf20Sopenharmony_ci * @ptype: the &packet_type structure which was used to register this handler. 10538c2ecf20Sopenharmony_ci * @orig_dev: original receive &net_device, in case @ dev is a bond. 10548c2ecf20Sopenharmony_ci * 10558c2ecf20Sopenharmony_ci * Returns: 0 for success 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_cistatic int bnx2fc_fip_recv(struct sk_buff *skb, struct net_device *dev, 10588c2ecf20Sopenharmony_ci struct packet_type *ptype, 10598c2ecf20Sopenharmony_ci struct net_device *orig_dev) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 10628c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 10638c2ecf20Sopenharmony_ci interface = container_of(ptype, struct bnx2fc_interface, 10648c2ecf20Sopenharmony_ci fip_packet_type); 10658c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 10668c2ecf20Sopenharmony_ci fcoe_ctlr_recv(ctlr, skb); 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci/** 10718c2ecf20Sopenharmony_ci * bnx2fc_update_src_mac - Update Ethernet MAC filters. 10728c2ecf20Sopenharmony_ci * 10738c2ecf20Sopenharmony_ci * @lport: The local port 10748c2ecf20Sopenharmony_ci * @addr: Location of data to copy 10758c2ecf20Sopenharmony_ci * 10768c2ecf20Sopenharmony_ci * Remove any previously-set unicast MAC filter. 10778c2ecf20Sopenharmony_ci * Add secondary FCoE MAC address filter for our OUI. 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_cistatic void bnx2fc_update_src_mac(struct fc_lport *lport, u8 *addr) 10808c2ecf20Sopenharmony_ci{ 10818c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci memcpy(port->data_src_addr, addr, ETH_ALEN); 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci/** 10878c2ecf20Sopenharmony_ci * bnx2fc_get_src_mac - return the ethernet source address for an lport 10888c2ecf20Sopenharmony_ci * 10898c2ecf20Sopenharmony_ci * @lport: libfc port 10908c2ecf20Sopenharmony_ci */ 10918c2ecf20Sopenharmony_cistatic u8 *bnx2fc_get_src_mac(struct fc_lport *lport) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci struct fcoe_port *port; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci port = (struct fcoe_port *)lport_priv(lport); 10968c2ecf20Sopenharmony_ci return port->data_src_addr; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/** 11008c2ecf20Sopenharmony_ci * bnx2fc_fip_send - send an Ethernet-encapsulated FIP frame. 11018c2ecf20Sopenharmony_ci * 11028c2ecf20Sopenharmony_ci * @fip: FCoE controller. 11038c2ecf20Sopenharmony_ci * @skb: FIP Packet. 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_cistatic void bnx2fc_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci struct fip_header *fiph; 11088c2ecf20Sopenharmony_ci struct ethhdr *eth_hdr; 11098c2ecf20Sopenharmony_ci u16 op; 11108c2ecf20Sopenharmony_ci u8 sub; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); 11138c2ecf20Sopenharmony_ci eth_hdr = (struct ethhdr *)skb_mac_header(skb); 11148c2ecf20Sopenharmony_ci op = ntohs(fiph->fip_op); 11158c2ecf20Sopenharmony_ci sub = fiph->fip_subcode; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (op == FIP_OP_CTRL && sub == FIP_SC_SOL && bnx2fc_log_fka) 11188c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Sending FKA from %pM to %pM.\n", 11198c2ecf20Sopenharmony_ci eth_hdr->h_source, eth_hdr->h_dest); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci skb->dev = bnx2fc_from_ctlr(fip)->netdev; 11228c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic int bnx2fc_vport_create(struct fc_vport *vport, bool disabled) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct Scsi_Host *shost = vport_to_shost(vport); 11288c2ecf20Sopenharmony_ci struct fc_lport *n_port = shost_priv(shost); 11298c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(n_port); 11308c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 11318c2ecf20Sopenharmony_ci struct net_device *netdev = interface->netdev; 11328c2ecf20Sopenharmony_ci struct fc_lport *vn_port; 11338c2ecf20Sopenharmony_ci int rc; 11348c2ecf20Sopenharmony_ci char buf[32]; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci rc = fcoe_validate_vport_create(vport); 11378c2ecf20Sopenharmony_ci if (rc) { 11388c2ecf20Sopenharmony_ci fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); 11398c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Failed to create vport, " 11408c2ecf20Sopenharmony_ci "WWPN (0x%s) already exists\n", 11418c2ecf20Sopenharmony_ci buf); 11428c2ecf20Sopenharmony_ci return rc; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) { 11468c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "vn ports cannot be created on" 11478c2ecf20Sopenharmony_ci "this interface\n"); 11488c2ecf20Sopenharmony_ci return -EIO; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci rtnl_lock(); 11518c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 11528c2ecf20Sopenharmony_ci vn_port = bnx2fc_if_create(interface, &vport->dev, 1); 11538c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 11548c2ecf20Sopenharmony_ci rtnl_unlock(); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (!vn_port) { 11578c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n", 11588c2ecf20Sopenharmony_ci netdev->name); 11598c2ecf20Sopenharmony_ci return -EIO; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (bnx2fc_devloss_tmo) 11638c2ecf20Sopenharmony_ci fc_host_dev_loss_tmo(vn_port->host) = bnx2fc_devloss_tmo; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if (disabled) { 11668c2ecf20Sopenharmony_ci fc_vport_set_state(vport, FC_VPORT_DISABLED); 11678c2ecf20Sopenharmony_ci } else { 11688c2ecf20Sopenharmony_ci vn_port->boot_time = jiffies; 11698c2ecf20Sopenharmony_ci fc_lport_init(vn_port); 11708c2ecf20Sopenharmony_ci fc_fabric_login(vn_port); 11718c2ecf20Sopenharmony_ci fc_vport_setlink(vn_port); 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci return 0; 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic void bnx2fc_free_vport(struct bnx2fc_hba *hba, struct fc_lport *lport) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci struct bnx2fc_lport *blport, *tmp; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 11818c2ecf20Sopenharmony_ci list_for_each_entry_safe(blport, tmp, &hba->vports, list) { 11828c2ecf20Sopenharmony_ci if (blport->lport == lport) { 11838c2ecf20Sopenharmony_ci list_del(&blport->list); 11848c2ecf20Sopenharmony_ci kfree(blport); 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic int bnx2fc_vport_destroy(struct fc_vport *vport) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci struct Scsi_Host *shost = vport_to_shost(vport); 11938c2ecf20Sopenharmony_ci struct fc_lport *n_port = shost_priv(shost); 11948c2ecf20Sopenharmony_ci struct fc_lport *vn_port = vport->dd_data; 11958c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(vn_port); 11968c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 11978c2ecf20Sopenharmony_ci struct fc_lport *v_port; 11988c2ecf20Sopenharmony_ci bool found = false; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci mutex_lock(&n_port->lp_mutex); 12018c2ecf20Sopenharmony_ci list_for_each_entry(v_port, &n_port->vports, list) 12028c2ecf20Sopenharmony_ci if (v_port->vport == vport) { 12038c2ecf20Sopenharmony_ci found = true; 12048c2ecf20Sopenharmony_ci break; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (!found) { 12088c2ecf20Sopenharmony_ci mutex_unlock(&n_port->lp_mutex); 12098c2ecf20Sopenharmony_ci return -ENOENT; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci list_del(&vn_port->list); 12128c2ecf20Sopenharmony_ci mutex_unlock(&n_port->lp_mutex); 12138c2ecf20Sopenharmony_ci bnx2fc_free_vport(interface->hba, port->lport); 12148c2ecf20Sopenharmony_ci bnx2fc_port_shutdown(port->lport); 12158c2ecf20Sopenharmony_ci bnx2fc_port_destroy(port); 12168c2ecf20Sopenharmony_ci bnx2fc_interface_put(interface); 12178c2ecf20Sopenharmony_ci return 0; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic int bnx2fc_vport_disable(struct fc_vport *vport, bool disable) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci struct fc_lport *lport = vport->dd_data; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (disable) { 12258c2ecf20Sopenharmony_ci fc_vport_set_state(vport, FC_VPORT_DISABLED); 12268c2ecf20Sopenharmony_ci fc_fabric_logoff(lport); 12278c2ecf20Sopenharmony_ci } else { 12288c2ecf20Sopenharmony_ci lport->boot_time = jiffies; 12298c2ecf20Sopenharmony_ci fc_fabric_login(lport); 12308c2ecf20Sopenharmony_ci fc_vport_setlink(lport); 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci return 0; 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int bnx2fc_interface_setup(struct bnx2fc_interface *interface) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct net_device *netdev = interface->netdev; 12398c2ecf20Sopenharmony_ci struct net_device *physdev = interface->hba->phys_dev; 12408c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 12418c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 12428c2ecf20Sopenharmony_ci int sel_san_mac = 0; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* setup Source MAC Address */ 12458c2ecf20Sopenharmony_ci rcu_read_lock(); 12468c2ecf20Sopenharmony_ci for_each_dev_addr(physdev, ha) { 12478c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("net_config: ha->type = %d, fip_mac = ", 12488c2ecf20Sopenharmony_ci ha->type); 12498c2ecf20Sopenharmony_ci printk(KERN_INFO "%2x:%2x:%2x:%2x:%2x:%2x\n", ha->addr[0], 12508c2ecf20Sopenharmony_ci ha->addr[1], ha->addr[2], ha->addr[3], 12518c2ecf20Sopenharmony_ci ha->addr[4], ha->addr[5]); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if ((ha->type == NETDEV_HW_ADDR_T_SAN) && 12548c2ecf20Sopenharmony_ci (is_valid_ether_addr(ha->addr))) { 12558c2ecf20Sopenharmony_ci memcpy(ctlr->ctl_src_addr, ha->addr, 12568c2ecf20Sopenharmony_ci ETH_ALEN); 12578c2ecf20Sopenharmony_ci sel_san_mac = 1; 12588c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Found SAN MAC\n"); 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci rcu_read_unlock(); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci if (!sel_san_mac) 12648c2ecf20Sopenharmony_ci return -ENODEV; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci interface->fip_packet_type.func = bnx2fc_fip_recv; 12678c2ecf20Sopenharmony_ci interface->fip_packet_type.type = htons(ETH_P_FIP); 12688c2ecf20Sopenharmony_ci interface->fip_packet_type.dev = netdev; 12698c2ecf20Sopenharmony_ci dev_add_pack(&interface->fip_packet_type); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci interface->fcoe_packet_type.func = bnx2fc_rcv; 12728c2ecf20Sopenharmony_ci interface->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); 12738c2ecf20Sopenharmony_ci interface->fcoe_packet_type.dev = netdev; 12748c2ecf20Sopenharmony_ci dev_add_pack(&interface->fcoe_packet_type); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return 0; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic int bnx2fc_attach_transport(void) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci bnx2fc_transport_template = 12828c2ecf20Sopenharmony_ci fc_attach_transport(&bnx2fc_transport_function); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci if (bnx2fc_transport_template == NULL) { 12858c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Failed to attach FC transport\n"); 12868c2ecf20Sopenharmony_ci return -ENODEV; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci bnx2fc_vport_xport_template = 12908c2ecf20Sopenharmony_ci fc_attach_transport(&bnx2fc_vport_xport_function); 12918c2ecf20Sopenharmony_ci if (bnx2fc_vport_xport_template == NULL) { 12928c2ecf20Sopenharmony_ci printk(KERN_ERR PFX 12938c2ecf20Sopenharmony_ci "Failed to attach FC transport for vport\n"); 12948c2ecf20Sopenharmony_ci fc_release_transport(bnx2fc_transport_template); 12958c2ecf20Sopenharmony_ci bnx2fc_transport_template = NULL; 12968c2ecf20Sopenharmony_ci return -ENODEV; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci return 0; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_cistatic void bnx2fc_release_transport(void) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci fc_release_transport(bnx2fc_transport_template); 13038c2ecf20Sopenharmony_ci fc_release_transport(bnx2fc_vport_xport_template); 13048c2ecf20Sopenharmony_ci bnx2fc_transport_template = NULL; 13058c2ecf20Sopenharmony_ci bnx2fc_vport_xport_template = NULL; 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_cistatic void bnx2fc_interface_release(struct kref *kref) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci struct fcoe_ctlr_device *ctlr_dev; 13118c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 13128c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 13138c2ecf20Sopenharmony_ci struct net_device *netdev; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci interface = container_of(kref, struct bnx2fc_interface, kref); 13168c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Interface is being released\n"); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 13198c2ecf20Sopenharmony_ci ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); 13208c2ecf20Sopenharmony_ci netdev = interface->netdev; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci /* tear-down FIP controller */ 13238c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) 13248c2ecf20Sopenharmony_ci fcoe_ctlr_destroy(ctlr); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci fcoe_ctlr_device_delete(ctlr_dev); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci dev_put(netdev); 13298c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic inline void bnx2fc_interface_get(struct bnx2fc_interface *interface) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci kref_get(&interface->kref); 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic inline void bnx2fc_interface_put(struct bnx2fc_interface *interface) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci kref_put(&interface->kref, bnx2fc_interface_release); 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_cistatic void bnx2fc_hba_destroy(struct bnx2fc_hba *hba) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci /* Free the command manager */ 13448c2ecf20Sopenharmony_ci if (hba->cmd_mgr) { 13458c2ecf20Sopenharmony_ci bnx2fc_cmd_mgr_free(hba->cmd_mgr); 13468c2ecf20Sopenharmony_ci hba->cmd_mgr = NULL; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci kfree(hba->tgt_ofld_list); 13498c2ecf20Sopenharmony_ci bnx2fc_unbind_pcidev(hba); 13508c2ecf20Sopenharmony_ci kfree(hba); 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci/** 13548c2ecf20Sopenharmony_ci * bnx2fc_hba_create - create a new bnx2fc hba 13558c2ecf20Sopenharmony_ci * 13568c2ecf20Sopenharmony_ci * @cnic: pointer to cnic device 13578c2ecf20Sopenharmony_ci * 13588c2ecf20Sopenharmony_ci * Creates a new FCoE hba on the given device. 13598c2ecf20Sopenharmony_ci * 13608c2ecf20Sopenharmony_ci */ 13618c2ecf20Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 13648c2ecf20Sopenharmony_ci struct fcoe_capabilities *fcoe_cap; 13658c2ecf20Sopenharmony_ci int rc; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci hba = kzalloc(sizeof(*hba), GFP_KERNEL); 13688c2ecf20Sopenharmony_ci if (!hba) { 13698c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Unable to allocate hba structure\n"); 13708c2ecf20Sopenharmony_ci return NULL; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci spin_lock_init(&hba->hba_lock); 13738c2ecf20Sopenharmony_ci mutex_init(&hba->hba_mutex); 13748c2ecf20Sopenharmony_ci mutex_init(&hba->hba_stats_mutex); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci hba->cnic = cnic; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci hba->max_tasks = cnic->max_fcoe_exchanges; 13798c2ecf20Sopenharmony_ci hba->elstm_xids = (hba->max_tasks / 2); 13808c2ecf20Sopenharmony_ci hba->max_outstanding_cmds = hba->elstm_xids; 13818c2ecf20Sopenharmony_ci hba->max_xid = (hba->max_tasks - 1); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci rc = bnx2fc_bind_pcidev(hba); 13848c2ecf20Sopenharmony_ci if (rc) { 13858c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "create_adapter: bind error\n"); 13868c2ecf20Sopenharmony_ci goto bind_err; 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci hba->phys_dev = cnic->netdev; 13898c2ecf20Sopenharmony_ci hba->next_conn_id = 0; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci hba->tgt_ofld_list = 13928c2ecf20Sopenharmony_ci kcalloc(BNX2FC_NUM_MAX_SESS, sizeof(struct bnx2fc_rport *), 13938c2ecf20Sopenharmony_ci GFP_KERNEL); 13948c2ecf20Sopenharmony_ci if (!hba->tgt_ofld_list) { 13958c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Unable to allocate tgt offload list\n"); 13968c2ecf20Sopenharmony_ci goto tgtofld_err; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci hba->num_ofld_sess = 0; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba); 14028c2ecf20Sopenharmony_ci if (!hba->cmd_mgr) { 14038c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n"); 14048c2ecf20Sopenharmony_ci goto cmgr_err; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci fcoe_cap = &hba->fcoe_cap; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci fcoe_cap->capability1 = BNX2FC_TM_MAX_SQES << 14098c2ecf20Sopenharmony_ci FCOE_IOS_PER_CONNECTION_SHIFT; 14108c2ecf20Sopenharmony_ci fcoe_cap->capability1 |= BNX2FC_NUM_MAX_SESS << 14118c2ecf20Sopenharmony_ci FCOE_LOGINS_PER_PORT_SHIFT; 14128c2ecf20Sopenharmony_ci fcoe_cap->capability2 = hba->max_outstanding_cmds << 14138c2ecf20Sopenharmony_ci FCOE_NUMBER_OF_EXCHANGES_SHIFT; 14148c2ecf20Sopenharmony_ci fcoe_cap->capability2 |= BNX2FC_MAX_NPIV << 14158c2ecf20Sopenharmony_ci FCOE_NPIV_WWN_PER_PORT_SHIFT; 14168c2ecf20Sopenharmony_ci fcoe_cap->capability3 = BNX2FC_NUM_MAX_SESS << 14178c2ecf20Sopenharmony_ci FCOE_TARGETS_SUPPORTED_SHIFT; 14188c2ecf20Sopenharmony_ci fcoe_cap->capability3 |= hba->max_outstanding_cmds << 14198c2ecf20Sopenharmony_ci FCOE_OUTSTANDING_COMMANDS_SHIFT; 14208c2ecf20Sopenharmony_ci fcoe_cap->capability4 = FCOE_CAPABILITY4_STATEFUL; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci init_waitqueue_head(&hba->shutdown_wait); 14238c2ecf20Sopenharmony_ci init_waitqueue_head(&hba->destroy_wait); 14248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hba->vports); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return hba; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cicmgr_err: 14298c2ecf20Sopenharmony_ci kfree(hba->tgt_ofld_list); 14308c2ecf20Sopenharmony_citgtofld_err: 14318c2ecf20Sopenharmony_ci bnx2fc_unbind_pcidev(hba); 14328c2ecf20Sopenharmony_cibind_err: 14338c2ecf20Sopenharmony_ci kfree(hba); 14348c2ecf20Sopenharmony_ci return NULL; 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic struct bnx2fc_interface * 14388c2ecf20Sopenharmony_cibnx2fc_interface_create(struct bnx2fc_hba *hba, 14398c2ecf20Sopenharmony_ci struct net_device *netdev, 14408c2ecf20Sopenharmony_ci enum fip_mode fip_mode) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct fcoe_ctlr_device *ctlr_dev; 14438c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 14448c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 14458c2ecf20Sopenharmony_ci int size; 14468c2ecf20Sopenharmony_ci int rc = 0; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci size = (sizeof(*interface) + sizeof(struct fcoe_ctlr)); 14498c2ecf20Sopenharmony_ci ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &bnx2fc_fcoe_sysfs_templ, 14508c2ecf20Sopenharmony_ci size); 14518c2ecf20Sopenharmony_ci if (!ctlr_dev) { 14528c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Unable to allocate interface structure\n"); 14538c2ecf20Sopenharmony_ci return NULL; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci ctlr = fcoe_ctlr_device_priv(ctlr_dev); 14568c2ecf20Sopenharmony_ci ctlr->cdev = ctlr_dev; 14578c2ecf20Sopenharmony_ci interface = fcoe_ctlr_priv(ctlr); 14588c2ecf20Sopenharmony_ci dev_hold(netdev); 14598c2ecf20Sopenharmony_ci kref_init(&interface->kref); 14608c2ecf20Sopenharmony_ci interface->hba = hba; 14618c2ecf20Sopenharmony_ci interface->netdev = netdev; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* Initialize FIP */ 14648c2ecf20Sopenharmony_ci fcoe_ctlr_init(ctlr, fip_mode); 14658c2ecf20Sopenharmony_ci ctlr->send = bnx2fc_fip_send; 14668c2ecf20Sopenharmony_ci ctlr->update_mac = bnx2fc_update_src_mac; 14678c2ecf20Sopenharmony_ci ctlr->get_src_addr = bnx2fc_get_src_mac; 14688c2ecf20Sopenharmony_ci set_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci rc = bnx2fc_interface_setup(interface); 14718c2ecf20Sopenharmony_ci if (!rc) 14728c2ecf20Sopenharmony_ci return interface; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci fcoe_ctlr_destroy(ctlr); 14758c2ecf20Sopenharmony_ci dev_put(netdev); 14768c2ecf20Sopenharmony_ci fcoe_ctlr_device_delete(ctlr_dev); 14778c2ecf20Sopenharmony_ci return NULL; 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci/** 14818c2ecf20Sopenharmony_ci * bnx2fc_if_create - Create FCoE instance on a given interface 14828c2ecf20Sopenharmony_ci * 14838c2ecf20Sopenharmony_ci * @interface: FCoE interface to create a local port on 14848c2ecf20Sopenharmony_ci * @parent: Device pointer to be the parent in sysfs for the SCSI host 14858c2ecf20Sopenharmony_ci * @npiv: Indicates if the port is vport or not 14868c2ecf20Sopenharmony_ci * 14878c2ecf20Sopenharmony_ci * Creates a fc_lport instance and a Scsi_Host instance and configure them. 14888c2ecf20Sopenharmony_ci * 14898c2ecf20Sopenharmony_ci * Returns: Allocated fc_lport or an error pointer 14908c2ecf20Sopenharmony_ci */ 14918c2ecf20Sopenharmony_cistatic struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, 14928c2ecf20Sopenharmony_ci struct device *parent, int npiv) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 14958c2ecf20Sopenharmony_ci struct fc_lport *lport, *n_port; 14968c2ecf20Sopenharmony_ci struct fcoe_port *port; 14978c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 14988c2ecf20Sopenharmony_ci struct fc_vport *vport = dev_to_vport(parent); 14998c2ecf20Sopenharmony_ci struct bnx2fc_lport *blport; 15008c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 15018c2ecf20Sopenharmony_ci int rc = 0; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL); 15048c2ecf20Sopenharmony_ci if (!blport) { 15058c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(ctlr->lp, "Unable to alloc blport\n"); 15068c2ecf20Sopenharmony_ci return NULL; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci /* Allocate Scsi_Host structure */ 15108c2ecf20Sopenharmony_ci bnx2fc_shost_template.can_queue = hba->max_outstanding_cmds; 15118c2ecf20Sopenharmony_ci if (!npiv) 15128c2ecf20Sopenharmony_ci lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); 15138c2ecf20Sopenharmony_ci else 15148c2ecf20Sopenharmony_ci lport = libfc_vport_create(vport, sizeof(*port)); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (!lport) { 15178c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "could not allocate scsi host structure\n"); 15188c2ecf20Sopenharmony_ci goto free_blport; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci shost = lport->host; 15218c2ecf20Sopenharmony_ci port = lport_priv(lport); 15228c2ecf20Sopenharmony_ci port->lport = lport; 15238c2ecf20Sopenharmony_ci port->priv = interface; 15248c2ecf20Sopenharmony_ci port->get_netdev = bnx2fc_netdev; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* Configure fcoe_port */ 15278c2ecf20Sopenharmony_ci rc = bnx2fc_lport_config(lport); 15288c2ecf20Sopenharmony_ci if (rc) 15298c2ecf20Sopenharmony_ci goto lp_config_err; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (npiv) { 15328c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n", 15338c2ecf20Sopenharmony_ci vport->node_name, vport->port_name); 15348c2ecf20Sopenharmony_ci fc_set_wwnn(lport, vport->node_name); 15358c2ecf20Sopenharmony_ci fc_set_wwpn(lport, vport->port_name); 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci /* Configure netdev and networking properties of the lport */ 15388c2ecf20Sopenharmony_ci rc = bnx2fc_net_config(lport, interface->netdev); 15398c2ecf20Sopenharmony_ci if (rc) { 15408c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Error on bnx2fc_net_config\n"); 15418c2ecf20Sopenharmony_ci goto lp_config_err; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci rc = bnx2fc_shost_config(lport, parent); 15458c2ecf20Sopenharmony_ci if (rc) { 15468c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Couldn't configure shost for %s\n", 15478c2ecf20Sopenharmony_ci interface->netdev->name); 15488c2ecf20Sopenharmony_ci goto lp_config_err; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci /* Initialize the libfc library */ 15528c2ecf20Sopenharmony_ci rc = bnx2fc_libfc_config(lport); 15538c2ecf20Sopenharmony_ci if (rc) { 15548c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Couldn't configure libfc\n"); 15558c2ecf20Sopenharmony_ci goto shost_err; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (bnx2fc_devloss_tmo) 15608c2ecf20Sopenharmony_ci fc_host_dev_loss_tmo(shost) = bnx2fc_devloss_tmo; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Allocate exchange manager */ 15638c2ecf20Sopenharmony_ci if (!npiv) 15648c2ecf20Sopenharmony_ci rc = bnx2fc_em_config(lport, hba); 15658c2ecf20Sopenharmony_ci else { 15668c2ecf20Sopenharmony_ci shost = vport_to_shost(vport); 15678c2ecf20Sopenharmony_ci n_port = shost_priv(shost); 15688c2ecf20Sopenharmony_ci rc = fc_exch_mgr_list_clone(n_port, lport); 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (rc) { 15728c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); 15738c2ecf20Sopenharmony_ci goto shost_err; 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci bnx2fc_interface_get(interface); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 15798c2ecf20Sopenharmony_ci blport->lport = lport; 15808c2ecf20Sopenharmony_ci list_add_tail(&blport->list, &hba->vports); 15818c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci return lport; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_cishost_err: 15868c2ecf20Sopenharmony_ci scsi_remove_host(shost); 15878c2ecf20Sopenharmony_cilp_config_err: 15888c2ecf20Sopenharmony_ci scsi_host_put(lport->host); 15898c2ecf20Sopenharmony_cifree_blport: 15908c2ecf20Sopenharmony_ci kfree(blport); 15918c2ecf20Sopenharmony_ci return NULL; 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic void bnx2fc_net_cleanup(struct bnx2fc_interface *interface) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci /* Dont listen for Ethernet packets anymore */ 15978c2ecf20Sopenharmony_ci __dev_remove_pack(&interface->fcoe_packet_type); 15988c2ecf20Sopenharmony_ci __dev_remove_pack(&interface->fip_packet_type); 15998c2ecf20Sopenharmony_ci synchronize_net(); 16008c2ecf20Sopenharmony_ci} 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistatic void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 16058c2ecf20Sopenharmony_ci struct fc_lport *lport = ctlr->lp; 16068c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 16078c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci /* Stop the transmit retry timer */ 16108c2ecf20Sopenharmony_ci del_timer_sync(&port->timer); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* Free existing transmit skbs */ 16138c2ecf20Sopenharmony_ci fcoe_clean_pending_queue(lport); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci bnx2fc_net_cleanup(interface); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci bnx2fc_free_vport(hba, lport); 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic void bnx2fc_if_destroy(struct fc_lport *lport) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* Free queued packets for the receive thread */ 16248c2ecf20Sopenharmony_ci bnx2fc_clean_rx_queue(lport); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci /* Detach from scsi-ml */ 16278c2ecf20Sopenharmony_ci fc_remove_host(lport->host); 16288c2ecf20Sopenharmony_ci scsi_remove_host(lport->host); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* 16318c2ecf20Sopenharmony_ci * Note that only the physical lport will have the exchange manager. 16328c2ecf20Sopenharmony_ci * for vports, this function is NOP 16338c2ecf20Sopenharmony_ci */ 16348c2ecf20Sopenharmony_ci fc_exch_mgr_free(lport); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci /* Free memory used by statistical counters */ 16378c2ecf20Sopenharmony_ci fc_lport_free_stats(lport); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* Release Scsi_Host */ 16408c2ecf20Sopenharmony_ci scsi_host_put(lport->host); 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic void __bnx2fc_destroy(struct bnx2fc_interface *interface) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 16468c2ecf20Sopenharmony_ci struct fc_lport *lport = ctlr->lp; 16478c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci bnx2fc_interface_cleanup(interface); 16508c2ecf20Sopenharmony_ci bnx2fc_stop(interface); 16518c2ecf20Sopenharmony_ci list_del(&interface->list); 16528c2ecf20Sopenharmony_ci bnx2fc_port_destroy(port); 16538c2ecf20Sopenharmony_ci bnx2fc_interface_put(interface); 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci/** 16578c2ecf20Sopenharmony_ci * bnx2fc_destroy - Destroy a bnx2fc FCoE interface 16588c2ecf20Sopenharmony_ci * 16598c2ecf20Sopenharmony_ci * @netdev: The net device that the FCoE interface is on 16608c2ecf20Sopenharmony_ci * 16618c2ecf20Sopenharmony_ci * Called from sysfs. 16628c2ecf20Sopenharmony_ci * 16638c2ecf20Sopenharmony_ci * Returns: 0 for success 16648c2ecf20Sopenharmony_ci */ 16658c2ecf20Sopenharmony_cistatic int bnx2fc_destroy(struct net_device *netdev) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = NULL; 16688c2ecf20Sopenharmony_ci struct workqueue_struct *timer_work_queue; 16698c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 16708c2ecf20Sopenharmony_ci int rc = 0; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci rtnl_lock(); 16738c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci interface = bnx2fc_interface_lookup(netdev); 16768c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 16778c2ecf20Sopenharmony_ci if (!interface || !ctlr->lp) { 16788c2ecf20Sopenharmony_ci rc = -ENODEV; 16798c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_destroy: interface or lport not found\n"); 16808c2ecf20Sopenharmony_ci goto netdev_err; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci timer_work_queue = interface->timer_work_queue; 16848c2ecf20Sopenharmony_ci __bnx2fc_destroy(interface); 16858c2ecf20Sopenharmony_ci destroy_workqueue(timer_work_queue); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cinetdev_err: 16888c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 16898c2ecf20Sopenharmony_ci rtnl_unlock(); 16908c2ecf20Sopenharmony_ci return rc; 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_cistatic void bnx2fc_port_destroy(struct fcoe_port *port) 16948c2ecf20Sopenharmony_ci{ 16958c2ecf20Sopenharmony_ci struct fc_lport *lport; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci lport = port->lport; 16988c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Entered %s, destroying lport %p\n", __func__, lport); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci bnx2fc_if_destroy(lport); 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba) 17048c2ecf20Sopenharmony_ci{ 17058c2ecf20Sopenharmony_ci bnx2fc_free_fw_resc(hba); 17068c2ecf20Sopenharmony_ci bnx2fc_free_task_ctx(hba); 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci/** 17108c2ecf20Sopenharmony_ci * bnx2fc_bind_adapter_devices - binds bnx2fc adapter with the associated 17118c2ecf20Sopenharmony_ci * pci structure 17128c2ecf20Sopenharmony_ci * 17138c2ecf20Sopenharmony_ci * @hba: Adapter instance 17148c2ecf20Sopenharmony_ci */ 17158c2ecf20Sopenharmony_cistatic int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba) 17168c2ecf20Sopenharmony_ci{ 17178c2ecf20Sopenharmony_ci if (bnx2fc_setup_task_ctx(hba)) 17188c2ecf20Sopenharmony_ci goto mem_err; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci if (bnx2fc_setup_fw_resc(hba)) 17218c2ecf20Sopenharmony_ci goto mem_err; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci return 0; 17248c2ecf20Sopenharmony_cimem_err: 17258c2ecf20Sopenharmony_ci bnx2fc_unbind_adapter_devices(hba); 17268c2ecf20Sopenharmony_ci return -ENOMEM; 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci struct cnic_dev *cnic; 17328c2ecf20Sopenharmony_ci struct pci_dev *pdev; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (!hba->cnic) { 17358c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "cnic is NULL\n"); 17368c2ecf20Sopenharmony_ci return -ENODEV; 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci cnic = hba->cnic; 17398c2ecf20Sopenharmony_ci pdev = hba->pcidev = cnic->pcidev; 17408c2ecf20Sopenharmony_ci if (!hba->pcidev) 17418c2ecf20Sopenharmony_ci return -ENODEV; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci switch (pdev->device) { 17448c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57710: 17458c2ecf20Sopenharmony_ci strncpy(hba->chip_num, "BCM57710", BCM_CHIP_LEN); 17468c2ecf20Sopenharmony_ci break; 17478c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57711: 17488c2ecf20Sopenharmony_ci strncpy(hba->chip_num, "BCM57711", BCM_CHIP_LEN); 17498c2ecf20Sopenharmony_ci break; 17508c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57712: 17518c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57712_MF: 17528c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57712_VF: 17538c2ecf20Sopenharmony_ci strncpy(hba->chip_num, "BCM57712", BCM_CHIP_LEN); 17548c2ecf20Sopenharmony_ci break; 17558c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57800: 17568c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57800_MF: 17578c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57800_VF: 17588c2ecf20Sopenharmony_ci strncpy(hba->chip_num, "BCM57800", BCM_CHIP_LEN); 17598c2ecf20Sopenharmony_ci break; 17608c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57810: 17618c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57810_MF: 17628c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57810_VF: 17638c2ecf20Sopenharmony_ci strncpy(hba->chip_num, "BCM57810", BCM_CHIP_LEN); 17648c2ecf20Sopenharmony_ci break; 17658c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840: 17668c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_MF: 17678c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_VF: 17688c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_2_20: 17698c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_4_10: 17708c2ecf20Sopenharmony_ci strncpy(hba->chip_num, "BCM57840", BCM_CHIP_LEN); 17718c2ecf20Sopenharmony_ci break; 17728c2ecf20Sopenharmony_ci default: 17738c2ecf20Sopenharmony_ci pr_err(PFX "Unknown device id 0x%x\n", pdev->device); 17748c2ecf20Sopenharmony_ci break; 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci pci_dev_get(hba->pcidev); 17778c2ecf20Sopenharmony_ci return 0; 17788c2ecf20Sopenharmony_ci} 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_cistatic void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba) 17818c2ecf20Sopenharmony_ci{ 17828c2ecf20Sopenharmony_ci if (hba->pcidev) { 17838c2ecf20Sopenharmony_ci hba->chip_num[0] = '\0'; 17848c2ecf20Sopenharmony_ci pci_dev_put(hba->pcidev); 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci hba->pcidev = NULL; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci/** 17908c2ecf20Sopenharmony_ci * bnx2fc_ulp_get_stats - cnic callback to populate FCoE stats 17918c2ecf20Sopenharmony_ci * 17928c2ecf20Sopenharmony_ci * @handle: transport handle pointing to adapter struture 17938c2ecf20Sopenharmony_ci */ 17948c2ecf20Sopenharmony_cistatic int bnx2fc_ulp_get_stats(void *handle) 17958c2ecf20Sopenharmony_ci{ 17968c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = handle; 17978c2ecf20Sopenharmony_ci struct cnic_dev *cnic; 17988c2ecf20Sopenharmony_ci struct fcoe_stats_info *stats_addr; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (!hba) 18018c2ecf20Sopenharmony_ci return -EINVAL; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci cnic = hba->cnic; 18048c2ecf20Sopenharmony_ci stats_addr = &cnic->stats_addr->fcoe_stat; 18058c2ecf20Sopenharmony_ci if (!stats_addr) 18068c2ecf20Sopenharmony_ci return -EINVAL; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci strncpy(stats_addr->version, BNX2FC_VERSION, 18098c2ecf20Sopenharmony_ci sizeof(stats_addr->version)); 18108c2ecf20Sopenharmony_ci stats_addr->txq_size = BNX2FC_SQ_WQES_MAX; 18118c2ecf20Sopenharmony_ci stats_addr->rxq_size = BNX2FC_CQ_WQES_MAX; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci return 0; 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci/** 18188c2ecf20Sopenharmony_ci * bnx2fc_ulp_start - cnic callback to initialize & start adapter instance 18198c2ecf20Sopenharmony_ci * 18208c2ecf20Sopenharmony_ci * @handle: transport handle pointing to adapter structure 18218c2ecf20Sopenharmony_ci * 18228c2ecf20Sopenharmony_ci * This function maps adapter structure to pcidev structure and initiates 18238c2ecf20Sopenharmony_ci * firmware handshake to enable/initialize on-chip FCoE components. 18248c2ecf20Sopenharmony_ci * This bnx2fc - cnic interface api callback is used after following 18258c2ecf20Sopenharmony_ci * conditions are met - 18268c2ecf20Sopenharmony_ci * a) underlying network interface is up (marked by event NETDEV_UP 18278c2ecf20Sopenharmony_ci * from netdev 18288c2ecf20Sopenharmony_ci * b) bnx2fc adatper structure is registered. 18298c2ecf20Sopenharmony_ci */ 18308c2ecf20Sopenharmony_cistatic void bnx2fc_ulp_start(void *handle) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = handle; 18338c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 18348c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 18358c2ecf20Sopenharmony_ci struct fc_lport *lport; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) 18408c2ecf20Sopenharmony_ci bnx2fc_fw_init(hba); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("bnx2fc started.\n"); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 18458c2ecf20Sopenharmony_ci if (interface->hba == hba) { 18468c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 18478c2ecf20Sopenharmony_ci lport = ctlr->lp; 18488c2ecf20Sopenharmony_ci /* Kick off Fabric discovery*/ 18498c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ulp_init: start discovery\n"); 18508c2ecf20Sopenharmony_ci lport->tt.frame_send = bnx2fc_xmit; 18518c2ecf20Sopenharmony_ci bnx2fc_start_disc(interface); 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_cistatic void bnx2fc_port_shutdown(struct fc_lport *lport) 18598c2ecf20Sopenharmony_ci{ 18608c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 18618c2ecf20Sopenharmony_ci fc_fabric_logoff(lport); 18628c2ecf20Sopenharmony_ci fc_lport_destroy(lport); 18638c2ecf20Sopenharmony_ci} 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_cistatic void bnx2fc_stop(struct bnx2fc_interface *interface) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 18688c2ecf20Sopenharmony_ci struct fc_lport *lport; 18698c2ecf20Sopenharmony_ci struct fc_lport *vport; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) 18728c2ecf20Sopenharmony_ci return; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci lport = ctlr->lp; 18758c2ecf20Sopenharmony_ci bnx2fc_port_shutdown(lport); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci mutex_lock(&lport->lp_mutex); 18788c2ecf20Sopenharmony_ci list_for_each_entry(vport, &lport->vports, list) 18798c2ecf20Sopenharmony_ci fc_host_port_type(vport->host) = 18808c2ecf20Sopenharmony_ci FC_PORTTYPE_UNKNOWN; 18818c2ecf20Sopenharmony_ci mutex_unlock(&lport->lp_mutex); 18828c2ecf20Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; 18838c2ecf20Sopenharmony_ci fcoe_ctlr_link_down(ctlr); 18848c2ecf20Sopenharmony_ci fcoe_clean_pending_queue(lport); 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_cistatic int bnx2fc_fw_init(struct bnx2fc_hba *hba) 18888c2ecf20Sopenharmony_ci{ 18898c2ecf20Sopenharmony_ci#define BNX2FC_INIT_POLL_TIME (1000 / HZ) 18908c2ecf20Sopenharmony_ci int rc = -1; 18918c2ecf20Sopenharmony_ci int i = HZ; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci rc = bnx2fc_bind_adapter_devices(hba); 18948c2ecf20Sopenharmony_ci if (rc) { 18958c2ecf20Sopenharmony_ci printk(KERN_ALERT PFX 18968c2ecf20Sopenharmony_ci "bnx2fc_bind_adapter_devices failed - rc = %d\n", rc); 18978c2ecf20Sopenharmony_ci goto err_out; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci rc = bnx2fc_send_fw_fcoe_init_msg(hba); 19018c2ecf20Sopenharmony_ci if (rc) { 19028c2ecf20Sopenharmony_ci printk(KERN_ALERT PFX 19038c2ecf20Sopenharmony_ci "bnx2fc_send_fw_fcoe_init_msg failed - rc = %d\n", rc); 19048c2ecf20Sopenharmony_ci goto err_unbind; 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci /* 19088c2ecf20Sopenharmony_ci * Wait until the adapter init message is complete, and adapter 19098c2ecf20Sopenharmony_ci * state is UP. 19108c2ecf20Sopenharmony_ci */ 19118c2ecf20Sopenharmony_ci while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) 19128c2ecf20Sopenharmony_ci msleep(BNX2FC_INIT_POLL_TIME); 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) { 19158c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_start: %s failed to initialize. " 19168c2ecf20Sopenharmony_ci "Ignoring...\n", 19178c2ecf20Sopenharmony_ci hba->cnic->netdev->name); 19188c2ecf20Sopenharmony_ci rc = -1; 19198c2ecf20Sopenharmony_ci goto err_unbind; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags); 19248c2ecf20Sopenharmony_ci return 0; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_cierr_unbind: 19278c2ecf20Sopenharmony_ci bnx2fc_unbind_adapter_devices(hba); 19288c2ecf20Sopenharmony_cierr_out: 19298c2ecf20Sopenharmony_ci return rc; 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cistatic void bnx2fc_fw_destroy(struct bnx2fc_hba *hba) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) { 19358c2ecf20Sopenharmony_ci if (bnx2fc_send_fw_fcoe_destroy_msg(hba) == 0) { 19368c2ecf20Sopenharmony_ci timer_setup(&hba->destroy_timer, bnx2fc_destroy_timer, 19378c2ecf20Sopenharmony_ci 0); 19388c2ecf20Sopenharmony_ci hba->destroy_timer.expires = BNX2FC_FW_TIMEOUT + 19398c2ecf20Sopenharmony_ci jiffies; 19408c2ecf20Sopenharmony_ci add_timer(&hba->destroy_timer); 19418c2ecf20Sopenharmony_ci wait_event_interruptible(hba->destroy_wait, 19428c2ecf20Sopenharmony_ci test_bit(BNX2FC_FLAG_DESTROY_CMPL, 19438c2ecf20Sopenharmony_ci &hba->flags)); 19448c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); 19458c2ecf20Sopenharmony_ci /* This should never happen */ 19468c2ecf20Sopenharmony_ci if (signal_pending(current)) 19478c2ecf20Sopenharmony_ci flush_signals(current); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci del_timer_sync(&hba->destroy_timer); 19508c2ecf20Sopenharmony_ci } 19518c2ecf20Sopenharmony_ci bnx2fc_unbind_adapter_devices(hba); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci/** 19568c2ecf20Sopenharmony_ci * bnx2fc_ulp_stop - cnic callback to shutdown adapter instance 19578c2ecf20Sopenharmony_ci * 19588c2ecf20Sopenharmony_ci * @handle: transport handle pointing to adapter structure 19598c2ecf20Sopenharmony_ci * 19608c2ecf20Sopenharmony_ci * Driver checks if adapter is already in shutdown mode, if not start 19618c2ecf20Sopenharmony_ci * the shutdown process. 19628c2ecf20Sopenharmony_ci */ 19638c2ecf20Sopenharmony_cistatic void bnx2fc_ulp_stop(void *handle) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = handle; 19668c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci printk(KERN_ERR "ULP_STOP\n"); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 19718c2ecf20Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) 19728c2ecf20Sopenharmony_ci goto exit; 19738c2ecf20Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 19748c2ecf20Sopenharmony_ci if (interface->hba == hba) 19758c2ecf20Sopenharmony_ci bnx2fc_stop(interface); 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci BUG_ON(hba->num_ofld_sess != 0); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci mutex_lock(&hba->hba_mutex); 19808c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); 19818c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_GOING_DOWN, 19828c2ecf20Sopenharmony_ci &hba->adapter_state); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci clear_bit(ADAPTER_STATE_READY, &hba->adapter_state); 19858c2ecf20Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci bnx2fc_fw_destroy(hba); 19888c2ecf20Sopenharmony_ciexit: 19898c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cistatic void bnx2fc_start_disc(struct bnx2fc_interface *interface) 19938c2ecf20Sopenharmony_ci{ 19948c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 19958c2ecf20Sopenharmony_ci struct fc_lport *lport; 19968c2ecf20Sopenharmony_ci int wait_cnt = 0; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 19998c2ecf20Sopenharmony_ci /* Kick off FIP/FLOGI */ 20008c2ecf20Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) { 20018c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Init not done yet\n"); 20028c2ecf20Sopenharmony_ci return; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci lport = ctlr->lp; 20068c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n"); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci if (!bnx2fc_link_ok(lport) && interface->enabled) { 20098c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "ctlr_link_up\n"); 20108c2ecf20Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 20118c2ecf20Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; 20128c2ecf20Sopenharmony_ci set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* wait for the FCF to be selected before issuing FLOGI */ 20168c2ecf20Sopenharmony_ci while (!ctlr->sel_fcf) { 20178c2ecf20Sopenharmony_ci msleep(250); 20188c2ecf20Sopenharmony_ci /* give up after 3 secs */ 20198c2ecf20Sopenharmony_ci if (++wait_cnt > 12) 20208c2ecf20Sopenharmony_ci break; 20218c2ecf20Sopenharmony_ci } 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci /* Reset max receive frame size to default */ 20248c2ecf20Sopenharmony_ci if (fc_set_mfs(lport, BNX2FC_MFS)) 20258c2ecf20Sopenharmony_ci return; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci fc_lport_init(lport); 20288c2ecf20Sopenharmony_ci fc_fabric_login(lport); 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci/** 20338c2ecf20Sopenharmony_ci * bnx2fc_ulp_init - Initialize an adapter instance 20348c2ecf20Sopenharmony_ci * 20358c2ecf20Sopenharmony_ci * @dev : cnic device handle 20368c2ecf20Sopenharmony_ci * Called from cnic_register_driver() context to initialize all 20378c2ecf20Sopenharmony_ci * enumerated cnic devices. This routine allocates adapter structure 20388c2ecf20Sopenharmony_ci * and other device specific resources. 20398c2ecf20Sopenharmony_ci */ 20408c2ecf20Sopenharmony_cistatic void bnx2fc_ulp_init(struct cnic_dev *dev) 20418c2ecf20Sopenharmony_ci{ 20428c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 20438c2ecf20Sopenharmony_ci int rc = 0; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 20468c2ecf20Sopenharmony_ci /* bnx2fc works only when bnx2x is loaded */ 20478c2ecf20Sopenharmony_ci if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) || 20488c2ecf20Sopenharmony_ci (dev->max_fcoe_conn == 0)) { 20498c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc FCoE not supported on %s," 20508c2ecf20Sopenharmony_ci " flags: %lx fcoe_conn: %d\n", 20518c2ecf20Sopenharmony_ci dev->netdev->name, dev->flags, dev->max_fcoe_conn); 20528c2ecf20Sopenharmony_ci return; 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci hba = bnx2fc_hba_create(dev); 20568c2ecf20Sopenharmony_ci if (!hba) { 20578c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "hba initialization failed\n"); 20588c2ecf20Sopenharmony_ci return; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci pr_info(PFX "FCoE initialized for %s.\n", dev->netdev->name); 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci /* Add HBA to the adapter list */ 20648c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 20658c2ecf20Sopenharmony_ci list_add_tail(&hba->list, &adapter_list); 20668c2ecf20Sopenharmony_ci adapter_count++; 20678c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci dev->fcoe_cap = &hba->fcoe_cap; 20708c2ecf20Sopenharmony_ci clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic); 20718c2ecf20Sopenharmony_ci rc = dev->register_device(dev, CNIC_ULP_FCOE, 20728c2ecf20Sopenharmony_ci (void *) hba); 20738c2ecf20Sopenharmony_ci if (rc) 20748c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "register_device failed, rc = %d\n", rc); 20758c2ecf20Sopenharmony_ci else 20768c2ecf20Sopenharmony_ci set_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic); 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci/* Assumes rtnl_lock and the bnx2fc_dev_lock are already taken */ 20808c2ecf20Sopenharmony_cistatic int __bnx2fc_disable(struct fcoe_ctlr *ctlr) 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci if (interface->enabled == true) { 20858c2ecf20Sopenharmony_ci if (!ctlr->lp) { 20868c2ecf20Sopenharmony_ci pr_err(PFX "__bnx2fc_disable: lport not found\n"); 20878c2ecf20Sopenharmony_ci return -ENODEV; 20888c2ecf20Sopenharmony_ci } else { 20898c2ecf20Sopenharmony_ci interface->enabled = false; 20908c2ecf20Sopenharmony_ci fcoe_ctlr_link_down(ctlr); 20918c2ecf20Sopenharmony_ci fcoe_clean_pending_queue(ctlr->lp); 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci return 0; 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci/* 20988c2ecf20Sopenharmony_ci * Deperecated: Use bnx2fc_enabled() 20998c2ecf20Sopenharmony_ci */ 21008c2ecf20Sopenharmony_cistatic int bnx2fc_disable(struct net_device *netdev) 21018c2ecf20Sopenharmony_ci{ 21028c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 21038c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 21048c2ecf20Sopenharmony_ci int rc = 0; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci rtnl_lock(); 21078c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci interface = bnx2fc_interface_lookup(netdev); 21108c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci if (!interface) { 21138c2ecf20Sopenharmony_ci rc = -ENODEV; 21148c2ecf20Sopenharmony_ci pr_err(PFX "bnx2fc_disable: interface not found\n"); 21158c2ecf20Sopenharmony_ci } else { 21168c2ecf20Sopenharmony_ci rc = __bnx2fc_disable(ctlr); 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 21198c2ecf20Sopenharmony_ci rtnl_unlock(); 21208c2ecf20Sopenharmony_ci return rc; 21218c2ecf20Sopenharmony_ci} 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_cistatic uint bnx2fc_npiv_create_vports(struct fc_lport *lport, 21248c2ecf20Sopenharmony_ci struct cnic_fc_npiv_tbl *npiv_tbl) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci struct fc_vport_identifiers vpid; 21278c2ecf20Sopenharmony_ci uint i, created = 0; 21288c2ecf20Sopenharmony_ci u64 wwnn = 0; 21298c2ecf20Sopenharmony_ci char wwpn_str[32]; 21308c2ecf20Sopenharmony_ci char wwnn_str[32]; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci if (npiv_tbl->count > MAX_NPIV_ENTRIES) { 21338c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Exceeded count max of npiv table\n"); 21348c2ecf20Sopenharmony_ci goto done; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci /* Sanity check the first entry to make sure it's not 0 */ 21388c2ecf20Sopenharmony_ci if (wwn_to_u64(npiv_tbl->wwnn[0]) == 0 && 21398c2ecf20Sopenharmony_ci wwn_to_u64(npiv_tbl->wwpn[0]) == 0) { 21408c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "First NPIV table entries invalid.\n"); 21418c2ecf20Sopenharmony_ci goto done; 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci vpid.roles = FC_PORT_ROLE_FCP_INITIATOR; 21458c2ecf20Sopenharmony_ci vpid.vport_type = FC_PORTTYPE_NPIV; 21468c2ecf20Sopenharmony_ci vpid.disable = false; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci for (i = 0; i < npiv_tbl->count; i++) { 21498c2ecf20Sopenharmony_ci wwnn = wwn_to_u64(npiv_tbl->wwnn[i]); 21508c2ecf20Sopenharmony_ci if (wwnn == 0) { 21518c2ecf20Sopenharmony_ci /* 21528c2ecf20Sopenharmony_ci * If we get a 0 element from for the WWNN then assume 21538c2ecf20Sopenharmony_ci * the WWNN should be the same as the physical port. 21548c2ecf20Sopenharmony_ci */ 21558c2ecf20Sopenharmony_ci wwnn = lport->wwnn; 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci vpid.node_name = wwnn; 21588c2ecf20Sopenharmony_ci vpid.port_name = wwn_to_u64(npiv_tbl->wwpn[i]); 21598c2ecf20Sopenharmony_ci scnprintf(vpid.symbolic_name, sizeof(vpid.symbolic_name), 21608c2ecf20Sopenharmony_ci "NPIV[%u]:%016llx-%016llx", 21618c2ecf20Sopenharmony_ci created, vpid.port_name, vpid.node_name); 21628c2ecf20Sopenharmony_ci fcoe_wwn_to_str(vpid.node_name, wwnn_str, sizeof(wwnn_str)); 21638c2ecf20Sopenharmony_ci fcoe_wwn_to_str(vpid.port_name, wwpn_str, sizeof(wwpn_str)); 21648c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Creating vport %s:%s.\n", wwnn_str, 21658c2ecf20Sopenharmony_ci wwpn_str); 21668c2ecf20Sopenharmony_ci if (fc_vport_create(lport->host, 0, &vpid)) 21678c2ecf20Sopenharmony_ci created++; 21688c2ecf20Sopenharmony_ci else 21698c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Failed to create vport\n"); 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_cidone: 21728c2ecf20Sopenharmony_ci return created; 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_cistatic int __bnx2fc_enable(struct fcoe_ctlr *ctlr) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); 21788c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 21798c2ecf20Sopenharmony_ci struct cnic_fc_npiv_tbl *npiv_tbl; 21808c2ecf20Sopenharmony_ci struct fc_lport *lport; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci if (interface->enabled == false) { 21838c2ecf20Sopenharmony_ci if (!ctlr->lp) { 21848c2ecf20Sopenharmony_ci pr_err(PFX "__bnx2fc_enable: lport not found\n"); 21858c2ecf20Sopenharmony_ci return -ENODEV; 21868c2ecf20Sopenharmony_ci } else if (!bnx2fc_link_ok(ctlr->lp)) { 21878c2ecf20Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 21888c2ecf20Sopenharmony_ci interface->enabled = true; 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci /* Create static NPIV ports if any are contained in NVRAM */ 21938c2ecf20Sopenharmony_ci hba = interface->hba; 21948c2ecf20Sopenharmony_ci lport = ctlr->lp; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci if (!hba) 21978c2ecf20Sopenharmony_ci goto done; 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci if (!hba->cnic) 22008c2ecf20Sopenharmony_ci goto done; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci if (!lport) 22038c2ecf20Sopenharmony_ci goto done; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci if (!lport->host) 22068c2ecf20Sopenharmony_ci goto done; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (!hba->cnic->get_fc_npiv_tbl) 22098c2ecf20Sopenharmony_ci goto done; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci npiv_tbl = kzalloc(sizeof(struct cnic_fc_npiv_tbl), GFP_KERNEL); 22128c2ecf20Sopenharmony_ci if (!npiv_tbl) 22138c2ecf20Sopenharmony_ci goto done; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci if (hba->cnic->get_fc_npiv_tbl(hba->cnic, npiv_tbl)) 22168c2ecf20Sopenharmony_ci goto done_free; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci bnx2fc_npiv_create_vports(lport, npiv_tbl); 22198c2ecf20Sopenharmony_cidone_free: 22208c2ecf20Sopenharmony_ci kfree(npiv_tbl); 22218c2ecf20Sopenharmony_cidone: 22228c2ecf20Sopenharmony_ci return 0; 22238c2ecf20Sopenharmony_ci} 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci/* 22268c2ecf20Sopenharmony_ci * Deprecated: Use bnx2fc_enabled() 22278c2ecf20Sopenharmony_ci */ 22288c2ecf20Sopenharmony_cistatic int bnx2fc_enable(struct net_device *netdev) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 22318c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 22328c2ecf20Sopenharmony_ci int rc = 0; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci rtnl_lock(); 22358c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci interface = bnx2fc_interface_lookup(netdev); 22388c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 22398c2ecf20Sopenharmony_ci if (!interface) { 22408c2ecf20Sopenharmony_ci rc = -ENODEV; 22418c2ecf20Sopenharmony_ci pr_err(PFX "bnx2fc_enable: interface not found\n"); 22428c2ecf20Sopenharmony_ci } else { 22438c2ecf20Sopenharmony_ci rc = __bnx2fc_enable(ctlr); 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 22478c2ecf20Sopenharmony_ci rtnl_unlock(); 22488c2ecf20Sopenharmony_ci return rc; 22498c2ecf20Sopenharmony_ci} 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci/** 22528c2ecf20Sopenharmony_ci * bnx2fc_ctlr_enabled() - Enable or disable an FCoE Controller 22538c2ecf20Sopenharmony_ci * @cdev: The FCoE Controller that is being enabled or disabled 22548c2ecf20Sopenharmony_ci * 22558c2ecf20Sopenharmony_ci * fcoe_sysfs will ensure that the state of 'enabled' has 22568c2ecf20Sopenharmony_ci * changed, so no checking is necessary here. This routine simply 22578c2ecf20Sopenharmony_ci * calls fcoe_enable or fcoe_disable, both of which are deprecated. 22588c2ecf20Sopenharmony_ci * When those routines are removed the functionality can be merged 22598c2ecf20Sopenharmony_ci * here. 22608c2ecf20Sopenharmony_ci */ 22618c2ecf20Sopenharmony_cistatic int bnx2fc_ctlr_enabled(struct fcoe_ctlr_device *cdev) 22628c2ecf20Sopenharmony_ci{ 22638c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(cdev); 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci switch (cdev->enabled) { 22668c2ecf20Sopenharmony_ci case FCOE_CTLR_ENABLED: 22678c2ecf20Sopenharmony_ci return __bnx2fc_enable(ctlr); 22688c2ecf20Sopenharmony_ci case FCOE_CTLR_DISABLED: 22698c2ecf20Sopenharmony_ci return __bnx2fc_disable(ctlr); 22708c2ecf20Sopenharmony_ci case FCOE_CTLR_UNUSED: 22718c2ecf20Sopenharmony_ci default: 22728c2ecf20Sopenharmony_ci return -ENOTSUPP; 22738c2ecf20Sopenharmony_ci }; 22748c2ecf20Sopenharmony_ci} 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_cienum bnx2fc_create_link_state { 22778c2ecf20Sopenharmony_ci BNX2FC_CREATE_LINK_DOWN, 22788c2ecf20Sopenharmony_ci BNX2FC_CREATE_LINK_UP, 22798c2ecf20Sopenharmony_ci}; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci/** 22828c2ecf20Sopenharmony_ci * _bnx2fc_create() - Create bnx2fc FCoE interface 22838c2ecf20Sopenharmony_ci * @netdev : The net_device object the Ethernet interface to create on 22848c2ecf20Sopenharmony_ci * @fip_mode: The FIP mode for this creation 22858c2ecf20Sopenharmony_ci * @link_state: The ctlr link state on creation 22868c2ecf20Sopenharmony_ci * 22878c2ecf20Sopenharmony_ci * Called from either the libfcoe 'create' module parameter 22888c2ecf20Sopenharmony_ci * via fcoe_create or from fcoe_syfs's ctlr_create file. 22898c2ecf20Sopenharmony_ci * 22908c2ecf20Sopenharmony_ci * libfcoe's 'create' module parameter is deprecated so some 22918c2ecf20Sopenharmony_ci * consolidation of code can be done when that interface is 22928c2ecf20Sopenharmony_ci * removed. 22938c2ecf20Sopenharmony_ci * 22948c2ecf20Sopenharmony_ci * Returns: 0 for success 22958c2ecf20Sopenharmony_ci */ 22968c2ecf20Sopenharmony_cistatic int _bnx2fc_create(struct net_device *netdev, 22978c2ecf20Sopenharmony_ci enum fip_mode fip_mode, 22988c2ecf20Sopenharmony_ci enum bnx2fc_create_link_state link_state) 22998c2ecf20Sopenharmony_ci{ 23008c2ecf20Sopenharmony_ci struct fcoe_ctlr_device *cdev; 23018c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr; 23028c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 23038c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 23048c2ecf20Sopenharmony_ci struct net_device *phys_dev = netdev; 23058c2ecf20Sopenharmony_ci struct fc_lport *lport; 23068c2ecf20Sopenharmony_ci struct ethtool_drvinfo drvinfo; 23078c2ecf20Sopenharmony_ci int rc = 0; 23088c2ecf20Sopenharmony_ci int vlan_id = 0; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Entered bnx2fc_create\n"); 23118c2ecf20Sopenharmony_ci if (fip_mode != FIP_MODE_FABRIC) { 23128c2ecf20Sopenharmony_ci printk(KERN_ERR "fip mode not FABRIC\n"); 23138c2ecf20Sopenharmony_ci return -EIO; 23148c2ecf20Sopenharmony_ci } 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci rtnl_lock(); 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) { 23218c2ecf20Sopenharmony_ci rc = -EINVAL; 23228c2ecf20Sopenharmony_ci goto mod_err; 23238c2ecf20Sopenharmony_ci } 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci /* obtain physical netdev */ 23268c2ecf20Sopenharmony_ci if (is_vlan_dev(netdev)) 23278c2ecf20Sopenharmony_ci phys_dev = vlan_dev_real_dev(netdev); 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci /* verify if the physical device is a netxtreme2 device */ 23308c2ecf20Sopenharmony_ci if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) { 23318c2ecf20Sopenharmony_ci memset(&drvinfo, 0, sizeof(drvinfo)); 23328c2ecf20Sopenharmony_ci phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo); 23338c2ecf20Sopenharmony_ci if (strncmp(drvinfo.driver, "bnx2x", strlen("bnx2x"))) { 23348c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Not a netxtreme2 device\n"); 23358c2ecf20Sopenharmony_ci rc = -EINVAL; 23368c2ecf20Sopenharmony_ci goto netdev_err; 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci } else { 23398c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to obtain drv_info\n"); 23408c2ecf20Sopenharmony_ci rc = -EINVAL; 23418c2ecf20Sopenharmony_ci goto netdev_err; 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci /* obtain interface and initialize rest of the structure */ 23458c2ecf20Sopenharmony_ci hba = bnx2fc_hba_lookup(phys_dev); 23468c2ecf20Sopenharmony_ci if (!hba) { 23478c2ecf20Sopenharmony_ci rc = -ENODEV; 23488c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_create: hba not found\n"); 23498c2ecf20Sopenharmony_ci goto netdev_err; 23508c2ecf20Sopenharmony_ci } 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci if (bnx2fc_interface_lookup(netdev)) { 23538c2ecf20Sopenharmony_ci rc = -EEXIST; 23548c2ecf20Sopenharmony_ci goto netdev_err; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci interface = bnx2fc_interface_create(hba, netdev, fip_mode); 23588c2ecf20Sopenharmony_ci if (!interface) { 23598c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_interface_create failed\n"); 23608c2ecf20Sopenharmony_ci rc = -ENOMEM; 23618c2ecf20Sopenharmony_ci goto netdev_err; 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci if (is_vlan_dev(netdev)) { 23658c2ecf20Sopenharmony_ci vlan_id = vlan_dev_vlan_id(netdev); 23668c2ecf20Sopenharmony_ci interface->vlan_enabled = 1; 23678c2ecf20Sopenharmony_ci } 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 23708c2ecf20Sopenharmony_ci cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 23718c2ecf20Sopenharmony_ci interface->vlan_id = vlan_id; 23728c2ecf20Sopenharmony_ci interface->tm_timeout = BNX2FC_TM_TIMEOUT; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci interface->timer_work_queue = 23758c2ecf20Sopenharmony_ci create_singlethread_workqueue("bnx2fc_timer_wq"); 23768c2ecf20Sopenharmony_ci if (!interface->timer_work_queue) { 23778c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ulp_init could not create timer_wq\n"); 23788c2ecf20Sopenharmony_ci rc = -EINVAL; 23798c2ecf20Sopenharmony_ci goto ifput_err; 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci lport = bnx2fc_if_create(interface, &cdev->dev, 0); 23838c2ecf20Sopenharmony_ci if (!lport) { 23848c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Failed to create interface (%s)\n", 23858c2ecf20Sopenharmony_ci netdev->name); 23868c2ecf20Sopenharmony_ci rc = -EINVAL; 23878c2ecf20Sopenharmony_ci goto if_create_err; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci /* Add interface to if_list */ 23918c2ecf20Sopenharmony_ci list_add_tail(&interface->list, &if_list); 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci lport->boot_time = jiffies; 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci /* Make this master N_port */ 23968c2ecf20Sopenharmony_ci ctlr->lp = lport; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci if (link_state == BNX2FC_CREATE_LINK_UP) 23998c2ecf20Sopenharmony_ci cdev->enabled = FCOE_CTLR_ENABLED; 24008c2ecf20Sopenharmony_ci else 24018c2ecf20Sopenharmony_ci cdev->enabled = FCOE_CTLR_DISABLED; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci if (link_state == BNX2FC_CREATE_LINK_UP && 24048c2ecf20Sopenharmony_ci !bnx2fc_link_ok(lport)) { 24058c2ecf20Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 24068c2ecf20Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; 24078c2ecf20Sopenharmony_ci set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "create: START DISC\n"); 24118c2ecf20Sopenharmony_ci bnx2fc_start_disc(interface); 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci if (link_state == BNX2FC_CREATE_LINK_UP) 24148c2ecf20Sopenharmony_ci interface->enabled = true; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci /* 24178c2ecf20Sopenharmony_ci * Release from kref_init in bnx2fc_interface_setup, on success 24188c2ecf20Sopenharmony_ci * lport should be holding a reference taken in bnx2fc_if_create 24198c2ecf20Sopenharmony_ci */ 24208c2ecf20Sopenharmony_ci bnx2fc_interface_put(interface); 24218c2ecf20Sopenharmony_ci /* put netdev that was held while calling dev_get_by_name */ 24228c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 24238c2ecf20Sopenharmony_ci rtnl_unlock(); 24248c2ecf20Sopenharmony_ci return 0; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ciif_create_err: 24278c2ecf20Sopenharmony_ci destroy_workqueue(interface->timer_work_queue); 24288c2ecf20Sopenharmony_ciifput_err: 24298c2ecf20Sopenharmony_ci bnx2fc_net_cleanup(interface); 24308c2ecf20Sopenharmony_ci bnx2fc_interface_put(interface); 24318c2ecf20Sopenharmony_ci goto mod_err; 24328c2ecf20Sopenharmony_cinetdev_err: 24338c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 24348c2ecf20Sopenharmony_cimod_err: 24358c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 24368c2ecf20Sopenharmony_ci rtnl_unlock(); 24378c2ecf20Sopenharmony_ci return rc; 24388c2ecf20Sopenharmony_ci} 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci/** 24418c2ecf20Sopenharmony_ci * bnx2fc_create() - Create a bnx2fc interface 24428c2ecf20Sopenharmony_ci * @netdev : The net_device object the Ethernet interface to create on 24438c2ecf20Sopenharmony_ci * @fip_mode: The FIP mode for this creation 24448c2ecf20Sopenharmony_ci * 24458c2ecf20Sopenharmony_ci * Called from fcoe transport 24468c2ecf20Sopenharmony_ci * 24478c2ecf20Sopenharmony_ci * Returns: 0 for success 24488c2ecf20Sopenharmony_ci */ 24498c2ecf20Sopenharmony_cistatic int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode) 24508c2ecf20Sopenharmony_ci{ 24518c2ecf20Sopenharmony_ci return _bnx2fc_create(netdev, fip_mode, BNX2FC_CREATE_LINK_UP); 24528c2ecf20Sopenharmony_ci} 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci/** 24558c2ecf20Sopenharmony_ci * bnx2fc_ctlr_alloc() - Allocate a bnx2fc interface from fcoe_sysfs 24568c2ecf20Sopenharmony_ci * @netdev: The net_device to be used by the allocated FCoE Controller 24578c2ecf20Sopenharmony_ci * 24588c2ecf20Sopenharmony_ci * This routine is called from fcoe_sysfs. It will start the fcoe_ctlr 24598c2ecf20Sopenharmony_ci * in a link_down state. The allows the user an opportunity to configure 24608c2ecf20Sopenharmony_ci * the FCoE Controller from sysfs before enabling the FCoE Controller. 24618c2ecf20Sopenharmony_ci * 24628c2ecf20Sopenharmony_ci * Creating in with this routine starts the FCoE Controller in Fabric 24638c2ecf20Sopenharmony_ci * mode. The user can change to VN2VN or another mode before enabling. 24648c2ecf20Sopenharmony_ci */ 24658c2ecf20Sopenharmony_cistatic int bnx2fc_ctlr_alloc(struct net_device *netdev) 24668c2ecf20Sopenharmony_ci{ 24678c2ecf20Sopenharmony_ci return _bnx2fc_create(netdev, FIP_MODE_FABRIC, 24688c2ecf20Sopenharmony_ci BNX2FC_CREATE_LINK_DOWN); 24698c2ecf20Sopenharmony_ci} 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci/** 24728c2ecf20Sopenharmony_ci * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc hba instance 24738c2ecf20Sopenharmony_ci * 24748c2ecf20Sopenharmony_ci * @cnic: Pointer to cnic device instance 24758c2ecf20Sopenharmony_ci * 24768c2ecf20Sopenharmony_ci **/ 24778c2ecf20Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci /* Called with bnx2fc_dev_lock held */ 24828c2ecf20Sopenharmony_ci list_for_each_entry(hba, &adapter_list, list) { 24838c2ecf20Sopenharmony_ci if (hba->cnic == cnic) 24848c2ecf20Sopenharmony_ci return hba; 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci return NULL; 24878c2ecf20Sopenharmony_ci} 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_cistatic struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device 24908c2ecf20Sopenharmony_ci *netdev) 24918c2ecf20Sopenharmony_ci{ 24928c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci /* Called with bnx2fc_dev_lock held */ 24958c2ecf20Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 24968c2ecf20Sopenharmony_ci if (interface->netdev == netdev) 24978c2ecf20Sopenharmony_ci return interface; 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci return NULL; 25008c2ecf20Sopenharmony_ci} 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device 25038c2ecf20Sopenharmony_ci *phys_dev) 25048c2ecf20Sopenharmony_ci{ 25058c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci /* Called with bnx2fc_dev_lock held */ 25088c2ecf20Sopenharmony_ci list_for_each_entry(hba, &adapter_list, list) { 25098c2ecf20Sopenharmony_ci if (hba->phys_dev == phys_dev) 25108c2ecf20Sopenharmony_ci return hba; 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "adapter_lookup: hba NULL\n"); 25138c2ecf20Sopenharmony_ci return NULL; 25148c2ecf20Sopenharmony_ci} 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci/** 25178c2ecf20Sopenharmony_ci * bnx2fc_ulp_exit - shuts down adapter instance and frees all resources 25188c2ecf20Sopenharmony_ci * 25198c2ecf20Sopenharmony_ci * @dev: cnic device handle 25208c2ecf20Sopenharmony_ci */ 25218c2ecf20Sopenharmony_cistatic void bnx2fc_ulp_exit(struct cnic_dev *dev) 25228c2ecf20Sopenharmony_ci{ 25238c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 25248c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface, *tmp; 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n"); 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { 25298c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc port check: %s, flags: %lx\n", 25308c2ecf20Sopenharmony_ci dev->netdev->name, dev->flags); 25318c2ecf20Sopenharmony_ci return; 25328c2ecf20Sopenharmony_ci } 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 25358c2ecf20Sopenharmony_ci hba = bnx2fc_find_hba_for_cnic(dev); 25368c2ecf20Sopenharmony_ci if (!hba) { 25378c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_ulp_exit: hba not found, dev 0%p\n", 25388c2ecf20Sopenharmony_ci dev); 25398c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 25408c2ecf20Sopenharmony_ci return; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci list_del_init(&hba->list); 25448c2ecf20Sopenharmony_ci adapter_count--; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci list_for_each_entry_safe(interface, tmp, &if_list, list) 25478c2ecf20Sopenharmony_ci /* destroy not called yet, move to quiesced list */ 25488c2ecf20Sopenharmony_ci if (interface->hba == hba) 25498c2ecf20Sopenharmony_ci __bnx2fc_destroy(interface); 25508c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci bnx2fc_ulp_stop(hba); 25538c2ecf20Sopenharmony_ci /* unregister cnic device */ 25548c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic)) 25558c2ecf20Sopenharmony_ci hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE); 25568c2ecf20Sopenharmony_ci bnx2fc_hba_destroy(hba); 25578c2ecf20Sopenharmony_ci} 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_cistatic void bnx2fc_rport_terminate_io(struct fc_rport *rport) 25608c2ecf20Sopenharmony_ci{ 25618c2ecf20Sopenharmony_ci /* This is a no-op */ 25628c2ecf20Sopenharmony_ci} 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci/** 25658c2ecf20Sopenharmony_ci * bnx2fc_fcoe_reset - Resets the fcoe 25668c2ecf20Sopenharmony_ci * 25678c2ecf20Sopenharmony_ci * @shost: shost the reset is from 25688c2ecf20Sopenharmony_ci * 25698c2ecf20Sopenharmony_ci * Returns: always 0 25708c2ecf20Sopenharmony_ci */ 25718c2ecf20Sopenharmony_cistatic int bnx2fc_fcoe_reset(struct Scsi_Host *shost) 25728c2ecf20Sopenharmony_ci{ 25738c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 25748c2ecf20Sopenharmony_ci fc_lport_reset(lport); 25758c2ecf20Sopenharmony_ci return 0; 25768c2ecf20Sopenharmony_ci} 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_cistatic bool bnx2fc_match(struct net_device *netdev) 25808c2ecf20Sopenharmony_ci{ 25818c2ecf20Sopenharmony_ci struct net_device *phys_dev = netdev; 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 25848c2ecf20Sopenharmony_ci if (is_vlan_dev(netdev)) 25858c2ecf20Sopenharmony_ci phys_dev = vlan_dev_real_dev(netdev); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci if (bnx2fc_hba_lookup(phys_dev)) { 25888c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 25898c2ecf20Sopenharmony_ci return true; 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 25938c2ecf20Sopenharmony_ci return false; 25948c2ecf20Sopenharmony_ci} 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_cistatic struct fcoe_transport bnx2fc_transport = { 25988c2ecf20Sopenharmony_ci .name = {"bnx2fc"}, 25998c2ecf20Sopenharmony_ci .attached = false, 26008c2ecf20Sopenharmony_ci .list = LIST_HEAD_INIT(bnx2fc_transport.list), 26018c2ecf20Sopenharmony_ci .alloc = bnx2fc_ctlr_alloc, 26028c2ecf20Sopenharmony_ci .match = bnx2fc_match, 26038c2ecf20Sopenharmony_ci .create = bnx2fc_create, 26048c2ecf20Sopenharmony_ci .destroy = bnx2fc_destroy, 26058c2ecf20Sopenharmony_ci .enable = bnx2fc_enable, 26068c2ecf20Sopenharmony_ci .disable = bnx2fc_disable, 26078c2ecf20Sopenharmony_ci}; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci/** 26108c2ecf20Sopenharmony_ci * bnx2fc_cpu_online - Create a receive thread for an online CPU 26118c2ecf20Sopenharmony_ci * 26128c2ecf20Sopenharmony_ci * @cpu: cpu index for the online cpu 26138c2ecf20Sopenharmony_ci */ 26148c2ecf20Sopenharmony_cistatic int bnx2fc_cpu_online(unsigned int cpu) 26158c2ecf20Sopenharmony_ci{ 26168c2ecf20Sopenharmony_ci struct bnx2fc_percpu_s *p; 26178c2ecf20Sopenharmony_ci struct task_struct *thread; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci p = &per_cpu(bnx2fc_percpu, cpu); 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci thread = kthread_create_on_node(bnx2fc_percpu_io_thread, 26228c2ecf20Sopenharmony_ci (void *)p, cpu_to_node(cpu), 26238c2ecf20Sopenharmony_ci "bnx2fc_thread/%d", cpu); 26248c2ecf20Sopenharmony_ci if (IS_ERR(thread)) 26258c2ecf20Sopenharmony_ci return PTR_ERR(thread); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci /* bind thread to the cpu */ 26288c2ecf20Sopenharmony_ci kthread_bind(thread, cpu); 26298c2ecf20Sopenharmony_ci p->iothread = thread; 26308c2ecf20Sopenharmony_ci wake_up_process(thread); 26318c2ecf20Sopenharmony_ci return 0; 26328c2ecf20Sopenharmony_ci} 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_cistatic int bnx2fc_cpu_offline(unsigned int cpu) 26358c2ecf20Sopenharmony_ci{ 26368c2ecf20Sopenharmony_ci struct bnx2fc_percpu_s *p; 26378c2ecf20Sopenharmony_ci struct task_struct *thread; 26388c2ecf20Sopenharmony_ci struct bnx2fc_work *work, *tmp; 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci BNX2FC_MISC_DBG("destroying io thread for CPU %d\n", cpu); 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci /* Prevent any new work from being queued for this CPU */ 26438c2ecf20Sopenharmony_ci p = &per_cpu(bnx2fc_percpu, cpu); 26448c2ecf20Sopenharmony_ci spin_lock_bh(&p->fp_work_lock); 26458c2ecf20Sopenharmony_ci thread = p->iothread; 26468c2ecf20Sopenharmony_ci p->iothread = NULL; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci /* Free all work in the list */ 26498c2ecf20Sopenharmony_ci list_for_each_entry_safe(work, tmp, &p->work_list, list) { 26508c2ecf20Sopenharmony_ci list_del_init(&work->list); 26518c2ecf20Sopenharmony_ci bnx2fc_process_cq_compl(work->tgt, work->wqe, work->rq_data, 26528c2ecf20Sopenharmony_ci work->num_rq, work->task); 26538c2ecf20Sopenharmony_ci kfree(work); 26548c2ecf20Sopenharmony_ci } 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci spin_unlock_bh(&p->fp_work_lock); 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci if (thread) 26598c2ecf20Sopenharmony_ci kthread_stop(thread); 26608c2ecf20Sopenharmony_ci return 0; 26618c2ecf20Sopenharmony_ci} 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_cistatic int bnx2fc_slave_configure(struct scsi_device *sdev) 26648c2ecf20Sopenharmony_ci{ 26658c2ecf20Sopenharmony_ci if (!bnx2fc_queue_depth) 26668c2ecf20Sopenharmony_ci return 0; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci scsi_change_queue_depth(sdev, bnx2fc_queue_depth); 26698c2ecf20Sopenharmony_ci return 0; 26708c2ecf20Sopenharmony_ci} 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_cistatic enum cpuhp_state bnx2fc_online_state; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci/** 26758c2ecf20Sopenharmony_ci * bnx2fc_mod_init - module init entry point 26768c2ecf20Sopenharmony_ci * 26778c2ecf20Sopenharmony_ci * Initialize driver wide global data structures, and register 26788c2ecf20Sopenharmony_ci * with cnic module 26798c2ecf20Sopenharmony_ci **/ 26808c2ecf20Sopenharmony_cistatic int __init bnx2fc_mod_init(void) 26818c2ecf20Sopenharmony_ci{ 26828c2ecf20Sopenharmony_ci struct fcoe_percpu_s *bg; 26838c2ecf20Sopenharmony_ci struct task_struct *l2_thread; 26848c2ecf20Sopenharmony_ci int rc = 0; 26858c2ecf20Sopenharmony_ci unsigned int cpu = 0; 26868c2ecf20Sopenharmony_ci struct bnx2fc_percpu_s *p; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "%s", version); 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci /* register as a fcoe transport */ 26918c2ecf20Sopenharmony_ci rc = fcoe_transport_attach(&bnx2fc_transport); 26928c2ecf20Sopenharmony_ci if (rc) { 26938c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to register an fcoe transport, check " 26948c2ecf20Sopenharmony_ci "if libfcoe is loaded\n"); 26958c2ecf20Sopenharmony_ci goto out; 26968c2ecf20Sopenharmony_ci } 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter_list); 26998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&if_list); 27008c2ecf20Sopenharmony_ci mutex_init(&bnx2fc_dev_lock); 27018c2ecf20Sopenharmony_ci adapter_count = 0; 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci /* Attach FC transport template */ 27048c2ecf20Sopenharmony_ci rc = bnx2fc_attach_transport(); 27058c2ecf20Sopenharmony_ci if (rc) 27068c2ecf20Sopenharmony_ci goto detach_ft; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci bnx2fc_wq = alloc_workqueue("bnx2fc", 0, 0); 27098c2ecf20Sopenharmony_ci if (!bnx2fc_wq) { 27108c2ecf20Sopenharmony_ci rc = -ENOMEM; 27118c2ecf20Sopenharmony_ci goto release_bt; 27128c2ecf20Sopenharmony_ci } 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci bg = &bnx2fc_global; 27158c2ecf20Sopenharmony_ci skb_queue_head_init(&bg->fcoe_rx_list); 27168c2ecf20Sopenharmony_ci l2_thread = kthread_create(bnx2fc_l2_rcv_thread, 27178c2ecf20Sopenharmony_ci (void *)bg, 27188c2ecf20Sopenharmony_ci "bnx2fc_l2_thread"); 27198c2ecf20Sopenharmony_ci if (IS_ERR(l2_thread)) { 27208c2ecf20Sopenharmony_ci rc = PTR_ERR(l2_thread); 27218c2ecf20Sopenharmony_ci goto free_wq; 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci wake_up_process(l2_thread); 27248c2ecf20Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 27258c2ecf20Sopenharmony_ci bg->kthread = l2_thread; 27268c2ecf20Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 27298c2ecf20Sopenharmony_ci p = &per_cpu(bnx2fc_percpu, cpu); 27308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p->work_list); 27318c2ecf20Sopenharmony_ci spin_lock_init(&p->fp_work_lock); 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/bnx2fc:online", 27358c2ecf20Sopenharmony_ci bnx2fc_cpu_online, bnx2fc_cpu_offline); 27368c2ecf20Sopenharmony_ci if (rc < 0) 27378c2ecf20Sopenharmony_ci goto stop_thread; 27388c2ecf20Sopenharmony_ci bnx2fc_online_state = rc; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci cnic_register_driver(CNIC_ULP_FCOE, &bnx2fc_cnic_cb); 27418c2ecf20Sopenharmony_ci return 0; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_cistop_thread: 27448c2ecf20Sopenharmony_ci kthread_stop(l2_thread); 27458c2ecf20Sopenharmony_cifree_wq: 27468c2ecf20Sopenharmony_ci destroy_workqueue(bnx2fc_wq); 27478c2ecf20Sopenharmony_cirelease_bt: 27488c2ecf20Sopenharmony_ci bnx2fc_release_transport(); 27498c2ecf20Sopenharmony_cidetach_ft: 27508c2ecf20Sopenharmony_ci fcoe_transport_detach(&bnx2fc_transport); 27518c2ecf20Sopenharmony_ciout: 27528c2ecf20Sopenharmony_ci return rc; 27538c2ecf20Sopenharmony_ci} 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_cistatic void __exit bnx2fc_mod_exit(void) 27568c2ecf20Sopenharmony_ci{ 27578c2ecf20Sopenharmony_ci LIST_HEAD(to_be_deleted); 27588c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba, *next; 27598c2ecf20Sopenharmony_ci struct fcoe_percpu_s *bg; 27608c2ecf20Sopenharmony_ci struct task_struct *l2_thread; 27618c2ecf20Sopenharmony_ci struct sk_buff *skb; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci /* 27648c2ecf20Sopenharmony_ci * NOTE: Since cnic calls register_driver routine rtnl_lock, 27658c2ecf20Sopenharmony_ci * it will have higher precedence than bnx2fc_dev_lock. 27668c2ecf20Sopenharmony_ci * unregister_device() cannot be called with bnx2fc_dev_lock 27678c2ecf20Sopenharmony_ci * held. 27688c2ecf20Sopenharmony_ci */ 27698c2ecf20Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 27708c2ecf20Sopenharmony_ci list_splice_init(&adapter_list, &to_be_deleted); 27718c2ecf20Sopenharmony_ci adapter_count = 0; 27728c2ecf20Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci /* Unregister with cnic */ 27758c2ecf20Sopenharmony_ci list_for_each_entry_safe(hba, next, &to_be_deleted, list) { 27768c2ecf20Sopenharmony_ci list_del_init(&hba->list); 27778c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p\n", 27788c2ecf20Sopenharmony_ci hba); 27798c2ecf20Sopenharmony_ci bnx2fc_ulp_stop(hba); 27808c2ecf20Sopenharmony_ci /* unregister cnic device */ 27818c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, 27828c2ecf20Sopenharmony_ci &hba->reg_with_cnic)) 27838c2ecf20Sopenharmony_ci hba->cnic->unregister_device(hba->cnic, 27848c2ecf20Sopenharmony_ci CNIC_ULP_FCOE); 27858c2ecf20Sopenharmony_ci bnx2fc_hba_destroy(hba); 27868c2ecf20Sopenharmony_ci } 27878c2ecf20Sopenharmony_ci cnic_unregister_driver(CNIC_ULP_FCOE); 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci /* Destroy global thread */ 27908c2ecf20Sopenharmony_ci bg = &bnx2fc_global; 27918c2ecf20Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 27928c2ecf20Sopenharmony_ci l2_thread = bg->kthread; 27938c2ecf20Sopenharmony_ci bg->kthread = NULL; 27948c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) 27958c2ecf20Sopenharmony_ci kfree_skb(skb); 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci if (l2_thread) 28008c2ecf20Sopenharmony_ci kthread_stop(l2_thread); 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci cpuhp_remove_state(bnx2fc_online_state); 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci destroy_workqueue(bnx2fc_wq); 28058c2ecf20Sopenharmony_ci /* 28068c2ecf20Sopenharmony_ci * detach from scsi transport 28078c2ecf20Sopenharmony_ci * must happen after all destroys are done 28088c2ecf20Sopenharmony_ci */ 28098c2ecf20Sopenharmony_ci bnx2fc_release_transport(); 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci /* detach from fcoe transport */ 28128c2ecf20Sopenharmony_ci fcoe_transport_detach(&bnx2fc_transport); 28138c2ecf20Sopenharmony_ci} 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_cimodule_init(bnx2fc_mod_init); 28168c2ecf20Sopenharmony_cimodule_exit(bnx2fc_mod_exit); 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_cistatic struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = { 28198c2ecf20Sopenharmony_ci .set_fcoe_ctlr_enabled = bnx2fc_ctlr_enabled, 28208c2ecf20Sopenharmony_ci .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, 28218c2ecf20Sopenharmony_ci .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, 28228c2ecf20Sopenharmony_ci .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb, 28238c2ecf20Sopenharmony_ci .get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb, 28248c2ecf20Sopenharmony_ci .get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb, 28258c2ecf20Sopenharmony_ci .get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb, 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci .get_fcoe_fcf_selected = fcoe_fcf_get_selected, 28288c2ecf20Sopenharmony_ci .get_fcoe_fcf_vlan_id = bnx2fc_fcf_get_vlan_id, 28298c2ecf20Sopenharmony_ci}; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_cistatic struct fc_function_template bnx2fc_transport_function = { 28328c2ecf20Sopenharmony_ci .show_host_node_name = 1, 28338c2ecf20Sopenharmony_ci .show_host_port_name = 1, 28348c2ecf20Sopenharmony_ci .show_host_supported_classes = 1, 28358c2ecf20Sopenharmony_ci .show_host_supported_fc4s = 1, 28368c2ecf20Sopenharmony_ci .show_host_active_fc4s = 1, 28378c2ecf20Sopenharmony_ci .show_host_maxframe_size = 1, 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci .show_host_port_id = 1, 28408c2ecf20Sopenharmony_ci .show_host_supported_speeds = 1, 28418c2ecf20Sopenharmony_ci .get_host_speed = fc_get_host_speed, 28428c2ecf20Sopenharmony_ci .show_host_speed = 1, 28438c2ecf20Sopenharmony_ci .show_host_port_type = 1, 28448c2ecf20Sopenharmony_ci .get_host_port_state = fc_get_host_port_state, 28458c2ecf20Sopenharmony_ci .show_host_port_state = 1, 28468c2ecf20Sopenharmony_ci .show_host_symbolic_name = 1, 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) + 28498c2ecf20Sopenharmony_ci sizeof(struct bnx2fc_rport)), 28508c2ecf20Sopenharmony_ci .show_rport_maxframe_size = 1, 28518c2ecf20Sopenharmony_ci .show_rport_supported_classes = 1, 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci .show_host_fabric_name = 1, 28548c2ecf20Sopenharmony_ci .show_starget_node_name = 1, 28558c2ecf20Sopenharmony_ci .show_starget_port_name = 1, 28568c2ecf20Sopenharmony_ci .show_starget_port_id = 1, 28578c2ecf20Sopenharmony_ci .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 28588c2ecf20Sopenharmony_ci .show_rport_dev_loss_tmo = 1, 28598c2ecf20Sopenharmony_ci .get_fc_host_stats = bnx2fc_get_host_stats, 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci .issue_fc_host_lip = bnx2fc_fcoe_reset, 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci .terminate_rport_io = bnx2fc_rport_terminate_io, 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci .vport_create = bnx2fc_vport_create, 28668c2ecf20Sopenharmony_ci .vport_delete = bnx2fc_vport_destroy, 28678c2ecf20Sopenharmony_ci .vport_disable = bnx2fc_vport_disable, 28688c2ecf20Sopenharmony_ci .bsg_request = fc_lport_bsg_request, 28698c2ecf20Sopenharmony_ci}; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_cistatic struct fc_function_template bnx2fc_vport_xport_function = { 28728c2ecf20Sopenharmony_ci .show_host_node_name = 1, 28738c2ecf20Sopenharmony_ci .show_host_port_name = 1, 28748c2ecf20Sopenharmony_ci .show_host_supported_classes = 1, 28758c2ecf20Sopenharmony_ci .show_host_supported_fc4s = 1, 28768c2ecf20Sopenharmony_ci .show_host_active_fc4s = 1, 28778c2ecf20Sopenharmony_ci .show_host_maxframe_size = 1, 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci .show_host_port_id = 1, 28808c2ecf20Sopenharmony_ci .show_host_supported_speeds = 1, 28818c2ecf20Sopenharmony_ci .get_host_speed = fc_get_host_speed, 28828c2ecf20Sopenharmony_ci .show_host_speed = 1, 28838c2ecf20Sopenharmony_ci .show_host_port_type = 1, 28848c2ecf20Sopenharmony_ci .get_host_port_state = fc_get_host_port_state, 28858c2ecf20Sopenharmony_ci .show_host_port_state = 1, 28868c2ecf20Sopenharmony_ci .show_host_symbolic_name = 1, 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) + 28898c2ecf20Sopenharmony_ci sizeof(struct bnx2fc_rport)), 28908c2ecf20Sopenharmony_ci .show_rport_maxframe_size = 1, 28918c2ecf20Sopenharmony_ci .show_rport_supported_classes = 1, 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci .show_host_fabric_name = 1, 28948c2ecf20Sopenharmony_ci .show_starget_node_name = 1, 28958c2ecf20Sopenharmony_ci .show_starget_port_name = 1, 28968c2ecf20Sopenharmony_ci .show_starget_port_id = 1, 28978c2ecf20Sopenharmony_ci .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 28988c2ecf20Sopenharmony_ci .show_rport_dev_loss_tmo = 1, 28998c2ecf20Sopenharmony_ci .get_fc_host_stats = fc_get_host_stats, 29008c2ecf20Sopenharmony_ci .issue_fc_host_lip = bnx2fc_fcoe_reset, 29018c2ecf20Sopenharmony_ci .terminate_rport_io = fc_rport_terminate_io, 29028c2ecf20Sopenharmony_ci .bsg_request = fc_lport_bsg_request, 29038c2ecf20Sopenharmony_ci}; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci/* 29068c2ecf20Sopenharmony_ci * Additional scsi_host attributes. 29078c2ecf20Sopenharmony_ci */ 29088c2ecf20Sopenharmony_cistatic ssize_t 29098c2ecf20Sopenharmony_cibnx2fc_tm_timeout_show(struct device *dev, struct device_attribute *attr, 29108c2ecf20Sopenharmony_ci char *buf) 29118c2ecf20Sopenharmony_ci{ 29128c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 29138c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 29148c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 29158c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci sprintf(buf, "%u\n", interface->tm_timeout); 29188c2ecf20Sopenharmony_ci return strlen(buf); 29198c2ecf20Sopenharmony_ci} 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_cistatic ssize_t 29228c2ecf20Sopenharmony_cibnx2fc_tm_timeout_store(struct device *dev, 29238c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 29248c2ecf20Sopenharmony_ci{ 29258c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 29268c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 29278c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 29288c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 29298c2ecf20Sopenharmony_ci int rval, val; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci rval = kstrtouint(buf, 10, &val); 29328c2ecf20Sopenharmony_ci if (rval) 29338c2ecf20Sopenharmony_ci return rval; 29348c2ecf20Sopenharmony_ci if (val > 255) 29358c2ecf20Sopenharmony_ci return -ERANGE; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci interface->tm_timeout = (u8)val; 29388c2ecf20Sopenharmony_ci return strlen(buf); 29398c2ecf20Sopenharmony_ci} 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_cistatic DEVICE_ATTR(tm_timeout, S_IRUGO|S_IWUSR, bnx2fc_tm_timeout_show, 29428c2ecf20Sopenharmony_ci bnx2fc_tm_timeout_store); 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_cistatic struct device_attribute *bnx2fc_host_attrs[] = { 29458c2ecf20Sopenharmony_ci &dev_attr_tm_timeout, 29468c2ecf20Sopenharmony_ci NULL, 29478c2ecf20Sopenharmony_ci}; 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci/* 29508c2ecf20Sopenharmony_ci * scsi_host_template structure used while registering with SCSI-ml 29518c2ecf20Sopenharmony_ci */ 29528c2ecf20Sopenharmony_cistatic struct scsi_host_template bnx2fc_shost_template = { 29538c2ecf20Sopenharmony_ci .module = THIS_MODULE, 29548c2ecf20Sopenharmony_ci .name = "QLogic Offload FCoE Initiator", 29558c2ecf20Sopenharmony_ci .queuecommand = bnx2fc_queuecommand, 29568c2ecf20Sopenharmony_ci .eh_timed_out = fc_eh_timed_out, 29578c2ecf20Sopenharmony_ci .eh_abort_handler = bnx2fc_eh_abort, /* abts */ 29588c2ecf20Sopenharmony_ci .eh_device_reset_handler = bnx2fc_eh_device_reset, /* lun reset */ 29598c2ecf20Sopenharmony_ci .eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */ 29608c2ecf20Sopenharmony_ci .eh_host_reset_handler = fc_eh_host_reset, 29618c2ecf20Sopenharmony_ci .slave_alloc = fc_slave_alloc, 29628c2ecf20Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 29638c2ecf20Sopenharmony_ci .this_id = -1, 29648c2ecf20Sopenharmony_ci .cmd_per_lun = 3, 29658c2ecf20Sopenharmony_ci .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, 29668c2ecf20Sopenharmony_ci .dma_boundary = 0x7fff, 29678c2ecf20Sopenharmony_ci .max_sectors = 0x3fbf, 29688c2ecf20Sopenharmony_ci .track_queue_depth = 1, 29698c2ecf20Sopenharmony_ci .slave_configure = bnx2fc_slave_configure, 29708c2ecf20Sopenharmony_ci .shost_attrs = bnx2fc_host_attrs, 29718c2ecf20Sopenharmony_ci}; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_cistatic struct libfc_function_template bnx2fc_libfc_fcn_templ = { 29748c2ecf20Sopenharmony_ci .frame_send = bnx2fc_xmit, 29758c2ecf20Sopenharmony_ci .elsct_send = bnx2fc_elsct_send, 29768c2ecf20Sopenharmony_ci .fcp_abort_io = bnx2fc_abort_io, 29778c2ecf20Sopenharmony_ci .fcp_cleanup = bnx2fc_cleanup, 29788c2ecf20Sopenharmony_ci .get_lesb = fcoe_get_lesb, 29798c2ecf20Sopenharmony_ci .rport_event_callback = bnx2fc_rport_event_handler, 29808c2ecf20Sopenharmony_ci}; 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci/* 29838c2ecf20Sopenharmony_ci * bnx2fc_cnic_cb - global template of bnx2fc - cnic driver interface 29848c2ecf20Sopenharmony_ci * structure carrying callback function pointers 29858c2ecf20Sopenharmony_ci */ 29868c2ecf20Sopenharmony_cistatic struct cnic_ulp_ops bnx2fc_cnic_cb = { 29878c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 29888c2ecf20Sopenharmony_ci .cnic_init = bnx2fc_ulp_init, 29898c2ecf20Sopenharmony_ci .cnic_exit = bnx2fc_ulp_exit, 29908c2ecf20Sopenharmony_ci .cnic_start = bnx2fc_ulp_start, 29918c2ecf20Sopenharmony_ci .cnic_stop = bnx2fc_ulp_stop, 29928c2ecf20Sopenharmony_ci .indicate_kcqes = bnx2fc_indicate_kcqe, 29938c2ecf20Sopenharmony_ci .indicate_netevent = bnx2fc_indicate_netevent, 29948c2ecf20Sopenharmony_ci .cnic_get_stats = bnx2fc_ulp_get_stats, 29958c2ecf20Sopenharmony_ci}; 2996