162306a36Sopenharmony_ci/* bnx2fc_fcoe.c: QLogic Linux FCoE offload driver. 262306a36Sopenharmony_ci * This file contains the code that interacts with libfc, libfcoe, 362306a36Sopenharmony_ci * cnic modules to create FCoE instances, send/receive non-offloaded 462306a36Sopenharmony_ci * FIP/FCoE packets, listen to link events etc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2008-2013 Broadcom Corporation 762306a36Sopenharmony_ci * Copyright (c) 2014-2016 QLogic Corporation 862306a36Sopenharmony_ci * Copyright (c) 2016-2017 Cavium Inc. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1162306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1262306a36Sopenharmony_ci * the Free Software Foundation. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "bnx2fc.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/ethtool.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic struct list_head adapter_list; 2262306a36Sopenharmony_cistatic struct list_head if_list; 2362306a36Sopenharmony_cistatic u32 adapter_count; 2462306a36Sopenharmony_cistatic DEFINE_MUTEX(bnx2fc_dev_lock); 2562306a36Sopenharmony_ciDEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DRV_MODULE_NAME "bnx2fc" 2862306a36Sopenharmony_ci#define DRV_MODULE_VERSION BNX2FC_VERSION 2962306a36Sopenharmony_ci#define DRV_MODULE_RELDATE "October 15, 2015" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic char version[] = 3362306a36Sopenharmony_ci "QLogic FCoE Driver " DRV_MODULE_NAME \ 3462306a36Sopenharmony_ci " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciMODULE_AUTHOR("Bhanu Prakash Gollapudi <bprakash@broadcom.com>"); 3862306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic FCoE Driver"); 3962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4062306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define BNX2FC_MAX_QUEUE_DEPTH 256 4362306a36Sopenharmony_ci#define BNX2FC_MIN_QUEUE_DEPTH 32 4462306a36Sopenharmony_ci#define FCOE_WORD_TO_BYTE 4 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic struct scsi_transport_template *bnx2fc_transport_template; 4762306a36Sopenharmony_cistatic struct scsi_transport_template *bnx2fc_vport_xport_template; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct workqueue_struct *bnx2fc_wq; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* bnx2fc structure needs only one instance of the fcoe_percpu_s structure. 5262306a36Sopenharmony_ci * Here the io threads are per cpu but the l2 thread is just one 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_cistruct fcoe_percpu_s bnx2fc_global; 5562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(bnx2fc_global_lock); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic struct cnic_ulp_ops bnx2fc_cnic_cb; 5862306a36Sopenharmony_cistatic struct libfc_function_template bnx2fc_libfc_fcn_templ; 5962306a36Sopenharmony_cistatic struct scsi_host_template bnx2fc_shost_template; 6062306a36Sopenharmony_cistatic struct fc_function_template bnx2fc_transport_function; 6162306a36Sopenharmony_cistatic struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ; 6262306a36Sopenharmony_cistatic struct fc_function_template bnx2fc_vport_xport_function; 6362306a36Sopenharmony_cistatic int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode); 6462306a36Sopenharmony_cistatic void __bnx2fc_destroy(struct bnx2fc_interface *interface); 6562306a36Sopenharmony_cistatic int bnx2fc_destroy(struct net_device *net_device); 6662306a36Sopenharmony_cistatic int bnx2fc_enable(struct net_device *netdev); 6762306a36Sopenharmony_cistatic int bnx2fc_disable(struct net_device *netdev); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* fcoe_syfs control interface handlers */ 7062306a36Sopenharmony_cistatic int bnx2fc_ctlr_alloc(struct net_device *netdev); 7162306a36Sopenharmony_cistatic int bnx2fc_ctlr_enabled(struct fcoe_ctlr_device *cdev); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void bnx2fc_recv_frame(struct sk_buff *skb); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void bnx2fc_start_disc(struct bnx2fc_interface *interface); 7662306a36Sopenharmony_cistatic int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev); 7762306a36Sopenharmony_cistatic int bnx2fc_lport_config(struct fc_lport *lport); 7862306a36Sopenharmony_cistatic int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba); 7962306a36Sopenharmony_cistatic int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba); 8062306a36Sopenharmony_cistatic void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba); 8162306a36Sopenharmony_cistatic int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba); 8262306a36Sopenharmony_cistatic void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba); 8362306a36Sopenharmony_cistatic struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, 8462306a36Sopenharmony_ci struct device *parent, int npiv); 8562306a36Sopenharmony_cistatic void bnx2fc_port_destroy(struct fcoe_port *port); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev); 8862306a36Sopenharmony_cistatic struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device 8962306a36Sopenharmony_ci *phys_dev); 9062306a36Sopenharmony_cistatic inline void bnx2fc_interface_put(struct bnx2fc_interface *interface); 9162306a36Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int bnx2fc_fw_init(struct bnx2fc_hba *hba); 9462306a36Sopenharmony_cistatic void bnx2fc_fw_destroy(struct bnx2fc_hba *hba); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void bnx2fc_port_shutdown(struct fc_lport *lport); 9762306a36Sopenharmony_cistatic void bnx2fc_stop(struct bnx2fc_interface *interface); 9862306a36Sopenharmony_cistatic int __init bnx2fc_mod_init(void); 9962306a36Sopenharmony_cistatic void __exit bnx2fc_mod_exit(void); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciunsigned int bnx2fc_debug_level; 10262306a36Sopenharmony_cimodule_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); 10362306a36Sopenharmony_ciMODULE_PARM_DESC(debug_logging, 10462306a36Sopenharmony_ci "Option to enable extended logging,\n" 10562306a36Sopenharmony_ci "\t\tDefault is 0 - no logging.\n" 10662306a36Sopenharmony_ci "\t\t0x01 - SCSI cmd error, cleanup.\n" 10762306a36Sopenharmony_ci "\t\t0x02 - Session setup, cleanup, etc.\n" 10862306a36Sopenharmony_ci "\t\t0x04 - lport events, link, mtu, etc.\n" 10962306a36Sopenharmony_ci "\t\t0x08 - ELS logs.\n" 11062306a36Sopenharmony_ci "\t\t0x10 - fcoe L2 fame related logs.\n" 11162306a36Sopenharmony_ci "\t\t0xff - LOG all messages."); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic uint bnx2fc_devloss_tmo; 11462306a36Sopenharmony_cimodule_param_named(devloss_tmo, bnx2fc_devloss_tmo, uint, S_IRUGO); 11562306a36Sopenharmony_ciMODULE_PARM_DESC(devloss_tmo, " Change devloss_tmo for the remote ports " 11662306a36Sopenharmony_ci "attached via bnx2fc."); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic uint bnx2fc_max_luns = BNX2FC_MAX_LUN; 11962306a36Sopenharmony_cimodule_param_named(max_luns, bnx2fc_max_luns, uint, S_IRUGO); 12062306a36Sopenharmony_ciMODULE_PARM_DESC(max_luns, " Change the default max_lun per SCSI host. Default " 12162306a36Sopenharmony_ci "0xffff."); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic uint bnx2fc_queue_depth; 12462306a36Sopenharmony_cimodule_param_named(queue_depth, bnx2fc_queue_depth, uint, S_IRUGO); 12562306a36Sopenharmony_ciMODULE_PARM_DESC(queue_depth, " Change the default queue depth of SCSI devices " 12662306a36Sopenharmony_ci "attached via bnx2fc."); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic uint bnx2fc_log_fka; 12962306a36Sopenharmony_cimodule_param_named(log_fka, bnx2fc_log_fka, uint, S_IRUGO|S_IWUSR); 13062306a36Sopenharmony_ciMODULE_PARM_DESC(log_fka, " Print message to kernel log when fcoe is " 13162306a36Sopenharmony_ci "initiating a FIP keep alive when debug logging is enabled."); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic inline struct net_device *bnx2fc_netdev(const struct fc_lport *lport) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return ((struct bnx2fc_interface *) 13662306a36Sopenharmony_ci ((struct fcoe_port *)lport_priv(lport))->priv)->netdev; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void bnx2fc_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct fcoe_ctlr_device *ctlr_dev = 14262306a36Sopenharmony_ci fcoe_fcf_dev_to_ctlr_dev(fcf_dev); 14362306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); 14462306a36Sopenharmony_ci struct bnx2fc_interface *fcoe = fcoe_ctlr_priv(ctlr); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci fcf_dev->vlan_id = fcoe->vlan_id; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void bnx2fc_clean_rx_queue(struct fc_lport *lp) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct fcoe_percpu_s *bg; 15262306a36Sopenharmony_ci struct fcoe_rcv_info *fr; 15362306a36Sopenharmony_ci struct sk_buff_head *list; 15462306a36Sopenharmony_ci struct sk_buff *skb, *next; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci bg = &bnx2fc_global; 15762306a36Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 15862306a36Sopenharmony_ci list = &bg->fcoe_rx_list; 15962306a36Sopenharmony_ci skb_queue_walk_safe(list, skb, next) { 16062306a36Sopenharmony_ci fr = fcoe_dev_from_skb(skb); 16162306a36Sopenharmony_ci if (fr->fr_dev == lp) { 16262306a36Sopenharmony_ci __skb_unlink(skb, list); 16362306a36Sopenharmony_ci kfree_skb(skb); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciint bnx2fc_get_paged_crc_eof(struct sk_buff *skb, int tlen) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci int rc; 17262306a36Sopenharmony_ci spin_lock(&bnx2fc_global_lock); 17362306a36Sopenharmony_ci rc = fcoe_get_paged_crc_eof(skb, tlen, &bnx2fc_global); 17462306a36Sopenharmony_ci spin_unlock(&bnx2fc_global_lock); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return rc; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic void bnx2fc_abort_io(struct fc_lport *lport) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci /* 18262306a36Sopenharmony_ci * This function is no-op for bnx2fc, but we do 18362306a36Sopenharmony_ci * not want to leave it as NULL either, as libfc 18462306a36Sopenharmony_ci * can call the default function which is 18562306a36Sopenharmony_ci * fc_fcp_abort_io. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void bnx2fc_cleanup(struct fc_lport *lport) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 19262306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 19362306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 19462306a36Sopenharmony_ci struct bnx2fc_rport *tgt; 19562306a36Sopenharmony_ci int i; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 19862306a36Sopenharmony_ci mutex_lock(&hba->hba_mutex); 19962306a36Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 20062306a36Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { 20162306a36Sopenharmony_ci tgt = hba->tgt_ofld_list[i]; 20262306a36Sopenharmony_ci if (tgt) { 20362306a36Sopenharmony_ci /* Cleanup IOs belonging to requested vport */ 20462306a36Sopenharmony_ci if (tgt->port == port) { 20562306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 20662306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "flush/cleanup\n"); 20762306a36Sopenharmony_ci bnx2fc_flush_active_ios(tgt); 20862306a36Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 21362306a36Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int bnx2fc_xmit_l2_frame(struct bnx2fc_rport *tgt, 21762306a36Sopenharmony_ci struct fc_frame *fp) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct fc_rport_priv *rdata = tgt->rdata; 22062306a36Sopenharmony_ci struct fc_frame_header *fh; 22162306a36Sopenharmony_ci int rc = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci fh = fc_frame_header_get(fp); 22462306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Xmit L2 frame rport = 0x%x, oxid = 0x%x, " 22562306a36Sopenharmony_ci "r_ctl = 0x%x\n", rdata->ids.port_id, 22662306a36Sopenharmony_ci ntohs(fh->fh_ox_id), fh->fh_r_ctl); 22762306a36Sopenharmony_ci if ((fh->fh_type == FC_TYPE_ELS) && 22862306a36Sopenharmony_ci (fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci switch (fc_frame_payload_op(fp)) { 23162306a36Sopenharmony_ci case ELS_ADISC: 23262306a36Sopenharmony_ci rc = bnx2fc_send_adisc(tgt, fp); 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci case ELS_LOGO: 23562306a36Sopenharmony_ci rc = bnx2fc_send_logo(tgt, fp); 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci case ELS_RLS: 23862306a36Sopenharmony_ci rc = bnx2fc_send_rls(tgt, fp); 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci default: 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } else if ((fh->fh_type == FC_TYPE_BLS) && 24462306a36Sopenharmony_ci (fh->fh_r_ctl == FC_RCTL_BA_ABTS)) 24562306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "ABTS frame\n"); 24662306a36Sopenharmony_ci else { 24762306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Send L2 frame type 0x%x " 24862306a36Sopenharmony_ci "rctl 0x%x thru non-offload path\n", 24962306a36Sopenharmony_ci fh->fh_type, fh->fh_r_ctl); 25062306a36Sopenharmony_ci return -ENODEV; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci if (rc) 25362306a36Sopenharmony_ci return -ENOMEM; 25462306a36Sopenharmony_ci else 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/** 25962306a36Sopenharmony_ci * bnx2fc_xmit - bnx2fc's FCoE frame transmit function 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * @lport: the associated local port 26262306a36Sopenharmony_ci * @fp: the fc_frame to be transmitted 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_cistatic int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct ethhdr *eh; 26762306a36Sopenharmony_ci struct fcoe_crc_eof *cp; 26862306a36Sopenharmony_ci struct sk_buff *skb; 26962306a36Sopenharmony_ci struct fc_frame_header *fh; 27062306a36Sopenharmony_ci struct bnx2fc_interface *interface; 27162306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 27262306a36Sopenharmony_ci struct bnx2fc_hba *hba; 27362306a36Sopenharmony_ci struct fcoe_port *port; 27462306a36Sopenharmony_ci struct fcoe_hdr *hp; 27562306a36Sopenharmony_ci struct bnx2fc_rport *tgt; 27662306a36Sopenharmony_ci u8 sof, eof; 27762306a36Sopenharmony_ci u32 crc; 27862306a36Sopenharmony_ci unsigned int hlen, tlen, elen; 27962306a36Sopenharmony_ci int wlen, rc = 0; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci port = (struct fcoe_port *)lport_priv(lport); 28262306a36Sopenharmony_ci interface = port->priv; 28362306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 28462306a36Sopenharmony_ci hba = interface->hba; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci fh = fc_frame_header_get(fp); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci skb = fp_skb(fp); 28962306a36Sopenharmony_ci if (!lport->link_up) { 29062306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "bnx2fc_xmit link down\n"); 29162306a36Sopenharmony_ci kfree_skb(skb); 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { 29662306a36Sopenharmony_ci if (!ctlr->sel_fcf) { 29762306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "FCF not selected yet!\n"); 29862306a36Sopenharmony_ci kfree_skb(skb); 29962306a36Sopenharmony_ci return -EINVAL; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci if (fcoe_ctlr_els_send(ctlr, lport, skb)) 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci sof = fr_sof(fp); 30662306a36Sopenharmony_ci eof = fr_eof(fp); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* 30962306a36Sopenharmony_ci * Snoop the frame header to check if the frame is for 31062306a36Sopenharmony_ci * an offloaded session 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * tgt_ofld_list access is synchronized using 31462306a36Sopenharmony_ci * both hba mutex and hba lock. Atleast hba mutex or 31562306a36Sopenharmony_ci * hba lock needs to be held for read access. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 31962306a36Sopenharmony_ci tgt = bnx2fc_tgt_lookup(port, ntoh24(fh->fh_d_id)); 32062306a36Sopenharmony_ci if (tgt && (test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) { 32162306a36Sopenharmony_ci /* This frame is for offloaded session */ 32262306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "xmit: Frame is for offloaded session " 32362306a36Sopenharmony_ci "port_id = 0x%x\n", ntoh24(fh->fh_d_id)); 32462306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 32562306a36Sopenharmony_ci rc = bnx2fc_xmit_l2_frame(tgt, fp); 32662306a36Sopenharmony_ci if (rc != -ENODEV) { 32762306a36Sopenharmony_ci kfree_skb(skb); 32862306a36Sopenharmony_ci return rc; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci } else { 33162306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci elen = sizeof(struct ethhdr); 33562306a36Sopenharmony_ci hlen = sizeof(struct fcoe_hdr); 33662306a36Sopenharmony_ci tlen = sizeof(struct fcoe_crc_eof); 33762306a36Sopenharmony_ci wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 34062306a36Sopenharmony_ci crc = fcoe_fc_crc(fp); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* copy port crc and eof to the skb buff */ 34362306a36Sopenharmony_ci if (skb_is_nonlinear(skb)) { 34462306a36Sopenharmony_ci skb_frag_t *frag; 34562306a36Sopenharmony_ci if (bnx2fc_get_paged_crc_eof(skb, tlen)) { 34662306a36Sopenharmony_ci kfree_skb(skb); 34762306a36Sopenharmony_ci return -ENOMEM; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; 35062306a36Sopenharmony_ci cp = kmap_atomic(skb_frag_page(frag)) + skb_frag_off(frag); 35162306a36Sopenharmony_ci } else { 35262306a36Sopenharmony_ci cp = skb_put(skb, tlen); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci memset(cp, 0, sizeof(*cp)); 35662306a36Sopenharmony_ci cp->fcoe_eof = eof; 35762306a36Sopenharmony_ci cp->fcoe_crc32 = cpu_to_le32(~crc); 35862306a36Sopenharmony_ci if (skb_is_nonlinear(skb)) { 35962306a36Sopenharmony_ci kunmap_atomic(cp); 36062306a36Sopenharmony_ci cp = NULL; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* adjust skb network/transport offsets to match mac/fcoe/port */ 36462306a36Sopenharmony_ci skb_push(skb, elen + hlen); 36562306a36Sopenharmony_ci skb_reset_mac_header(skb); 36662306a36Sopenharmony_ci skb_reset_network_header(skb); 36762306a36Sopenharmony_ci skb->mac_len = elen; 36862306a36Sopenharmony_ci skb->protocol = htons(ETH_P_FCOE); 36962306a36Sopenharmony_ci skb->dev = interface->netdev; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* fill up mac and fcoe headers */ 37262306a36Sopenharmony_ci eh = eth_hdr(skb); 37362306a36Sopenharmony_ci eh->h_proto = htons(ETH_P_FCOE); 37462306a36Sopenharmony_ci if (ctlr->map_dest) 37562306a36Sopenharmony_ci fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); 37662306a36Sopenharmony_ci else 37762306a36Sopenharmony_ci /* insert GW address */ 37862306a36Sopenharmony_ci memcpy(eh->h_dest, ctlr->dest_addr, ETH_ALEN); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (unlikely(ctlr->flogi_oxid != FC_XID_UNKNOWN)) 38162306a36Sopenharmony_ci memcpy(eh->h_source, ctlr->ctl_src_addr, ETH_ALEN); 38262306a36Sopenharmony_ci else 38362306a36Sopenharmony_ci memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci hp = (struct fcoe_hdr *)(eh + 1); 38662306a36Sopenharmony_ci memset(hp, 0, sizeof(*hp)); 38762306a36Sopenharmony_ci if (FC_FCOE_VER) 38862306a36Sopenharmony_ci FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); 38962306a36Sopenharmony_ci hp->fcoe_sof = sof; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ 39262306a36Sopenharmony_ci if (lport->seq_offload && fr_max_payload(fp)) { 39362306a36Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; 39462306a36Sopenharmony_ci skb_shinfo(skb)->gso_size = fr_max_payload(fp); 39562306a36Sopenharmony_ci } else { 39662306a36Sopenharmony_ci skb_shinfo(skb)->gso_type = 0; 39762306a36Sopenharmony_ci skb_shinfo(skb)->gso_size = 0; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /*update tx stats */ 40162306a36Sopenharmony_ci this_cpu_inc(lport->stats->TxFrames); 40262306a36Sopenharmony_ci this_cpu_add(lport->stats->TxWords, wlen); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* send down to lld */ 40562306a36Sopenharmony_ci fr_dev(fp) = lport; 40662306a36Sopenharmony_ci if (port->fcoe_pending_queue.qlen) 40762306a36Sopenharmony_ci fcoe_check_wait_queue(lport, skb); 40862306a36Sopenharmony_ci else if (fcoe_start_io(skb)) 40962306a36Sopenharmony_ci fcoe_check_wait_queue(lport, skb); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/** 41562306a36Sopenharmony_ci * bnx2fc_rcv - This is bnx2fc's receive function called by NET_RX_SOFTIRQ 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci * @skb: the receive socket buffer 41862306a36Sopenharmony_ci * @dev: associated net device 41962306a36Sopenharmony_ci * @ptype: context 42062306a36Sopenharmony_ci * @olddev: last device 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * This function receives the packet and builds FC frame and passes it up 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_cistatic int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, 42562306a36Sopenharmony_ci struct packet_type *ptype, struct net_device *olddev) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct fc_lport *lport; 42862306a36Sopenharmony_ci struct bnx2fc_interface *interface; 42962306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 43062306a36Sopenharmony_ci struct fcoe_rcv_info *fr; 43162306a36Sopenharmony_ci struct fcoe_percpu_s *bg; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci interface = container_of(ptype, struct bnx2fc_interface, 43462306a36Sopenharmony_ci fcoe_packet_type); 43562306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 43662306a36Sopenharmony_ci lport = ctlr->lp; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (unlikely(lport == NULL)) { 43962306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_rcv: lport is NULL\n"); 44062306a36Sopenharmony_ci goto err; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 44462306a36Sopenharmony_ci if (!skb) 44562306a36Sopenharmony_ci return -1; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { 44862306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n"); 44962306a36Sopenharmony_ci goto err; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * Check for minimum frame length, and make sure required FCoE 45462306a36Sopenharmony_ci * and FC headers are pulled into the linear data area. 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_ci if (unlikely((skb->len < FCOE_MIN_FRAME) || 45762306a36Sopenharmony_ci !pskb_may_pull(skb, FCOE_HEADER_LEN))) 45862306a36Sopenharmony_ci goto err; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci fr = fcoe_dev_from_skb(skb); 46362306a36Sopenharmony_ci fr->fr_dev = lport; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci bg = &bnx2fc_global; 46662306a36Sopenharmony_ci spin_lock(&bg->fcoe_rx_list.lock); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci __skb_queue_tail(&bg->fcoe_rx_list, skb); 46962306a36Sopenharmony_ci if (bg->fcoe_rx_list.qlen == 1) 47062306a36Sopenharmony_ci wake_up_process(bg->kthread); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci spin_unlock(&bg->fcoe_rx_list.lock); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_cierr: 47662306a36Sopenharmony_ci kfree_skb(skb); 47762306a36Sopenharmony_ci return -1; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int bnx2fc_l2_rcv_thread(void *arg) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct fcoe_percpu_s *bg = arg; 48362306a36Sopenharmony_ci struct sk_buff *skb; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci set_user_nice(current, MIN_NICE); 48662306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 48762306a36Sopenharmony_ci while (!kthread_should_stop()) { 48862306a36Sopenharmony_ci schedule(); 48962306a36Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 49062306a36Sopenharmony_ci while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) { 49162306a36Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 49262306a36Sopenharmony_ci bnx2fc_recv_frame(skb); 49362306a36Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci __set_current_state(TASK_INTERRUPTIBLE); 49662306a36Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic void bnx2fc_recv_frame(struct sk_buff *skb) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci u64 crc_err; 50662306a36Sopenharmony_ci u32 fr_len, fr_crc; 50762306a36Sopenharmony_ci struct fc_lport *lport; 50862306a36Sopenharmony_ci struct fcoe_rcv_info *fr; 50962306a36Sopenharmony_ci struct fc_frame_header *fh; 51062306a36Sopenharmony_ci struct fcoe_crc_eof crc_eof; 51162306a36Sopenharmony_ci struct fc_frame *fp; 51262306a36Sopenharmony_ci struct fc_lport *vn_port; 51362306a36Sopenharmony_ci struct fcoe_port *port, *phys_port; 51462306a36Sopenharmony_ci u8 *mac = NULL; 51562306a36Sopenharmony_ci u8 *dest_mac = NULL; 51662306a36Sopenharmony_ci struct fcoe_hdr *hp; 51762306a36Sopenharmony_ci struct bnx2fc_interface *interface; 51862306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci fr = fcoe_dev_from_skb(skb); 52162306a36Sopenharmony_ci lport = fr->fr_dev; 52262306a36Sopenharmony_ci if (unlikely(lport == NULL)) { 52362306a36Sopenharmony_ci printk(KERN_ERR PFX "Invalid lport struct\n"); 52462306a36Sopenharmony_ci kfree_skb(skb); 52562306a36Sopenharmony_ci return; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (skb_is_nonlinear(skb)) 52962306a36Sopenharmony_ci skb_linearize(skb); 53062306a36Sopenharmony_ci mac = eth_hdr(skb)->h_source; 53162306a36Sopenharmony_ci dest_mac = eth_hdr(skb)->h_dest; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Pull the header */ 53462306a36Sopenharmony_ci hp = (struct fcoe_hdr *) skb_network_header(skb); 53562306a36Sopenharmony_ci fh = (struct fc_frame_header *) skb_transport_header(skb); 53662306a36Sopenharmony_ci skb_pull(skb, sizeof(struct fcoe_hdr)); 53762306a36Sopenharmony_ci fr_len = skb->len - sizeof(struct fcoe_crc_eof); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci this_cpu_inc(lport->stats->RxFrames); 54062306a36Sopenharmony_ci this_cpu_add(lport->stats->RxWords, fr_len / FCOE_WORD_TO_BYTE); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci fp = (struct fc_frame *)skb; 54362306a36Sopenharmony_ci fc_frame_init(fp); 54462306a36Sopenharmony_ci fr_dev(fp) = lport; 54562306a36Sopenharmony_ci fr_sof(fp) = hp->fcoe_sof; 54662306a36Sopenharmony_ci if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { 54762306a36Sopenharmony_ci kfree_skb(skb); 54862306a36Sopenharmony_ci return; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci fr_eof(fp) = crc_eof.fcoe_eof; 55162306a36Sopenharmony_ci fr_crc(fp) = crc_eof.fcoe_crc32; 55262306a36Sopenharmony_ci if (pskb_trim(skb, fr_len)) { 55362306a36Sopenharmony_ci kfree_skb(skb); 55462306a36Sopenharmony_ci return; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci phys_port = lport_priv(lport); 55862306a36Sopenharmony_ci interface = phys_port->priv; 55962306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci fh = fc_frame_header_get(fp); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (ntoh24(&dest_mac[3]) != ntoh24(fh->fh_d_id)) { 56462306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "FC frame d_id mismatch with MAC %pM.\n", 56562306a36Sopenharmony_ci dest_mac); 56662306a36Sopenharmony_ci kfree_skb(skb); 56762306a36Sopenharmony_ci return; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci vn_port = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id)); 57162306a36Sopenharmony_ci if (vn_port) { 57262306a36Sopenharmony_ci port = lport_priv(vn_port); 57362306a36Sopenharmony_ci if (!ether_addr_equal(port->data_src_addr, dest_mac)) { 57462306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "fpma mismatch\n"); 57562306a36Sopenharmony_ci kfree_skb(skb); 57662306a36Sopenharmony_ci return; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci if (ctlr->state) { 58062306a36Sopenharmony_ci if (!ether_addr_equal(mac, ctlr->dest_addr)) { 58162306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Wrong source address: mac:%pM dest_addr:%pM.\n", 58262306a36Sopenharmony_ci mac, ctlr->dest_addr); 58362306a36Sopenharmony_ci kfree_skb(skb); 58462306a36Sopenharmony_ci return; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && 58862306a36Sopenharmony_ci fh->fh_type == FC_TYPE_FCP) { 58962306a36Sopenharmony_ci /* Drop FCP data. We dont this in L2 path */ 59062306a36Sopenharmony_ci kfree_skb(skb); 59162306a36Sopenharmony_ci return; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && 59462306a36Sopenharmony_ci fh->fh_type == FC_TYPE_ELS) { 59562306a36Sopenharmony_ci switch (fc_frame_payload_op(fp)) { 59662306a36Sopenharmony_ci case ELS_LOGO: 59762306a36Sopenharmony_ci if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { 59862306a36Sopenharmony_ci /* drop non-FIP LOGO */ 59962306a36Sopenharmony_ci kfree_skb(skb); 60062306a36Sopenharmony_ci return; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (fh->fh_r_ctl == FC_RCTL_BA_ABTS) { 60762306a36Sopenharmony_ci /* Drop incoming ABTS */ 60862306a36Sopenharmony_ci kfree_skb(skb); 60962306a36Sopenharmony_ci return; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* 61362306a36Sopenharmony_ci * If the destination ID from the frame header does not match what we 61462306a36Sopenharmony_ci * have on record for lport and the search for a NPIV port came up 61562306a36Sopenharmony_ci * empty then this is not addressed to our port so simply drop it. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci if (lport->port_id != ntoh24(fh->fh_d_id) && !vn_port) { 61862306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Dropping frame due to destination mismatch: lport->port_id=%x fh->d_id=%x.\n", 61962306a36Sopenharmony_ci lport->port_id, ntoh24(fh->fh_d_id)); 62062306a36Sopenharmony_ci kfree_skb(skb); 62162306a36Sopenharmony_ci return; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci fr_crc = le32_to_cpu(fr_crc(fp)); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (unlikely(fr_crc != ~crc32(~0, skb->data, fr_len))) { 62762306a36Sopenharmony_ci crc_err = this_cpu_inc_return(lport->stats->InvalidCRCCount); 62862306a36Sopenharmony_ci if (crc_err < 5) 62962306a36Sopenharmony_ci printk(KERN_WARNING PFX "dropping frame with " 63062306a36Sopenharmony_ci "CRC error\n"); 63162306a36Sopenharmony_ci kfree_skb(skb); 63262306a36Sopenharmony_ci return; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci fc_exch_recv(lport, fp); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/** 63862306a36Sopenharmony_ci * bnx2fc_percpu_io_thread - thread per cpu for ios 63962306a36Sopenharmony_ci * 64062306a36Sopenharmony_ci * @arg: ptr to bnx2fc_percpu_info structure 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_cistatic int bnx2fc_percpu_io_thread(void *arg) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct bnx2fc_percpu_s *p = arg; 64562306a36Sopenharmony_ci struct bnx2fc_work *work, *tmp; 64662306a36Sopenharmony_ci LIST_HEAD(work_list); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci set_user_nice(current, MIN_NICE); 64962306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 65062306a36Sopenharmony_ci while (!kthread_should_stop()) { 65162306a36Sopenharmony_ci schedule(); 65262306a36Sopenharmony_ci spin_lock_bh(&p->fp_work_lock); 65362306a36Sopenharmony_ci while (!list_empty(&p->work_list)) { 65462306a36Sopenharmony_ci list_splice_init(&p->work_list, &work_list); 65562306a36Sopenharmony_ci spin_unlock_bh(&p->fp_work_lock); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci list_for_each_entry_safe(work, tmp, &work_list, list) { 65862306a36Sopenharmony_ci list_del_init(&work->list); 65962306a36Sopenharmony_ci bnx2fc_process_cq_compl(work->tgt, work->wqe, 66062306a36Sopenharmony_ci work->rq_data, 66162306a36Sopenharmony_ci work->num_rq, 66262306a36Sopenharmony_ci work->task); 66362306a36Sopenharmony_ci kfree(work); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci spin_lock_bh(&p->fp_work_lock); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci __set_current_state(TASK_INTERRUPTIBLE); 66962306a36Sopenharmony_ci spin_unlock_bh(&p->fp_work_lock); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return 0; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct fc_host_statistics *bnx2fc_stats; 67962306a36Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 68062306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 68162306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 68262306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 68362306a36Sopenharmony_ci struct fcoe_statistics_params *fw_stats; 68462306a36Sopenharmony_ci int rc = 0; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci fw_stats = (struct fcoe_statistics_params *)hba->stats_buffer; 68762306a36Sopenharmony_ci if (!fw_stats) 68862306a36Sopenharmony_ci return NULL; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci mutex_lock(&hba->hba_stats_mutex); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci bnx2fc_stats = fc_get_host_stats(shost); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci init_completion(&hba->stat_req_done); 69562306a36Sopenharmony_ci if (bnx2fc_send_stat_req(hba)) 69662306a36Sopenharmony_ci goto unlock_stats_mutex; 69762306a36Sopenharmony_ci rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ)); 69862306a36Sopenharmony_ci if (!rc) { 69962306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "FW stat req timed out\n"); 70062306a36Sopenharmony_ci goto unlock_stats_mutex; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci BNX2FC_STATS(hba, rx_stat2, fc_crc_cnt); 70362306a36Sopenharmony_ci bnx2fc_stats->invalid_crc_count += hba->bfw_stats.fc_crc_cnt; 70462306a36Sopenharmony_ci BNX2FC_STATS(hba, tx_stat, fcoe_tx_pkt_cnt); 70562306a36Sopenharmony_ci bnx2fc_stats->tx_frames += hba->bfw_stats.fcoe_tx_pkt_cnt; 70662306a36Sopenharmony_ci BNX2FC_STATS(hba, tx_stat, fcoe_tx_byte_cnt); 70762306a36Sopenharmony_ci bnx2fc_stats->tx_words += ((hba->bfw_stats.fcoe_tx_byte_cnt) / 4); 70862306a36Sopenharmony_ci BNX2FC_STATS(hba, rx_stat0, fcoe_rx_pkt_cnt); 70962306a36Sopenharmony_ci bnx2fc_stats->rx_frames += hba->bfw_stats.fcoe_rx_pkt_cnt; 71062306a36Sopenharmony_ci BNX2FC_STATS(hba, rx_stat0, fcoe_rx_byte_cnt); 71162306a36Sopenharmony_ci bnx2fc_stats->rx_words += ((hba->bfw_stats.fcoe_rx_byte_cnt) / 4); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci bnx2fc_stats->dumped_frames = 0; 71462306a36Sopenharmony_ci bnx2fc_stats->lip_count = 0; 71562306a36Sopenharmony_ci bnx2fc_stats->nos_count = 0; 71662306a36Sopenharmony_ci bnx2fc_stats->loss_of_sync_count = 0; 71762306a36Sopenharmony_ci bnx2fc_stats->loss_of_signal_count = 0; 71862306a36Sopenharmony_ci bnx2fc_stats->prim_seq_protocol_err_count = 0; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci memcpy(&hba->prev_stats, hba->stats_buffer, 72162306a36Sopenharmony_ci sizeof(struct fcoe_statistics_params)); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ciunlock_stats_mutex: 72462306a36Sopenharmony_ci mutex_unlock(&hba->hba_stats_mutex); 72562306a36Sopenharmony_ci return bnx2fc_stats; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 73162306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 73262306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 73362306a36Sopenharmony_ci struct Scsi_Host *shost = lport->host; 73462306a36Sopenharmony_ci int rc = 0; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci shost->max_cmd_len = BNX2FC_MAX_CMD_LEN; 73762306a36Sopenharmony_ci shost->max_lun = bnx2fc_max_luns; 73862306a36Sopenharmony_ci shost->max_id = BNX2FC_MAX_FCP_TGT; 73962306a36Sopenharmony_ci shost->max_channel = 0; 74062306a36Sopenharmony_ci if (lport->vport) 74162306a36Sopenharmony_ci shost->transportt = bnx2fc_vport_xport_template; 74262306a36Sopenharmony_ci else 74362306a36Sopenharmony_ci shost->transportt = bnx2fc_transport_template; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* Add the new host to SCSI-ml */ 74662306a36Sopenharmony_ci rc = scsi_add_host(lport->host, dev); 74762306a36Sopenharmony_ci if (rc) { 74862306a36Sopenharmony_ci printk(KERN_ERR PFX "Error on scsi_add_host\n"); 74962306a36Sopenharmony_ci return rc; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci if (!lport->vport) 75262306a36Sopenharmony_ci fc_host_max_npiv_vports(lport->host) = USHRT_MAX; 75362306a36Sopenharmony_ci snprintf(fc_host_symbolic_name(lport->host), 256, 75462306a36Sopenharmony_ci "%s (QLogic %s) v%s over %s", 75562306a36Sopenharmony_ci BNX2FC_NAME, hba->chip_num, BNX2FC_VERSION, 75662306a36Sopenharmony_ci interface->netdev->name); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci return 0; 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic int bnx2fc_link_ok(struct fc_lport *lport) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 76462306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 76562306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 76662306a36Sopenharmony_ci struct net_device *dev = hba->phys_dev; 76762306a36Sopenharmony_ci int rc = 0; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) 77062306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 77162306a36Sopenharmony_ci else { 77262306a36Sopenharmony_ci set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 77362306a36Sopenharmony_ci rc = -1; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci return rc; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci/** 77962306a36Sopenharmony_ci * bnx2fc_get_link_state - get network link state 78062306a36Sopenharmony_ci * 78162306a36Sopenharmony_ci * @hba: adapter instance pointer 78262306a36Sopenharmony_ci * 78362306a36Sopenharmony_ci * updates adapter structure flag based on netdev state 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_civoid bnx2fc_get_link_state(struct bnx2fc_hba *hba) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci if (test_bit(__LINK_STATE_NOCARRIER, &hba->phys_dev->state)) 78862306a36Sopenharmony_ci set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 78962306a36Sopenharmony_ci else 79062306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct bnx2fc_hba *hba; 79662306a36Sopenharmony_ci struct bnx2fc_interface *interface; 79762306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 79862306a36Sopenharmony_ci struct fcoe_port *port; 79962306a36Sopenharmony_ci u64 wwnn, wwpn; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci port = lport_priv(lport); 80262306a36Sopenharmony_ci interface = port->priv; 80362306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 80462306a36Sopenharmony_ci hba = interface->hba; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* require support for get_pauseparam ethtool op. */ 80762306a36Sopenharmony_ci if (!hba->phys_dev->ethtool_ops || 80862306a36Sopenharmony_ci !hba->phys_dev->ethtool_ops->get_pauseparam) 80962306a36Sopenharmony_ci return -EOPNOTSUPP; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (fc_set_mfs(lport, BNX2FC_MFS)) 81262306a36Sopenharmony_ci return -EINVAL; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci skb_queue_head_init(&port->fcoe_pending_queue); 81562306a36Sopenharmony_ci port->fcoe_pending_queue_active = 0; 81662306a36Sopenharmony_ci timer_setup(&port->timer, fcoe_queue_timer, 0); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci fcoe_link_speed_update(lport); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (!lport->vport) { 82162306a36Sopenharmony_ci if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) 82262306a36Sopenharmony_ci wwnn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 82362306a36Sopenharmony_ci 1, 0); 82462306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn); 82562306a36Sopenharmony_ci fc_set_wwnn(lport, wwnn); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) 82862306a36Sopenharmony_ci wwpn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 82962306a36Sopenharmony_ci 2, 0); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn); 83262306a36Sopenharmony_ci fc_set_wwpn(lport, wwpn); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci return 0; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic void bnx2fc_destroy_timer(struct timer_list *t) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct bnx2fc_hba *hba = from_timer(hba, t, destroy_timer); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci printk(KERN_ERR PFX "ERROR:bnx2fc_destroy_timer - " 84362306a36Sopenharmony_ci "Destroy compl not received!!\n"); 84462306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); 84562306a36Sopenharmony_ci wake_up_interruptible(&hba->destroy_wait); 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci/** 84962306a36Sopenharmony_ci * bnx2fc_indicate_netevent - Generic netdev event handler 85062306a36Sopenharmony_ci * 85162306a36Sopenharmony_ci * @context: adapter structure pointer 85262306a36Sopenharmony_ci * @event: event type 85362306a36Sopenharmony_ci * @vlan_id: vlan id - associated vlan id with this event 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * Handles NETDEV_UP, NETDEV_DOWN, NETDEV_GOING_DOWN,NETDEV_CHANGE and 85662306a36Sopenharmony_ci * NETDEV_CHANGE_MTU events. Handle NETDEV_UNREGISTER only for vlans. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_cistatic void bnx2fc_indicate_netevent(void *context, unsigned long event, 85962306a36Sopenharmony_ci u16 vlan_id) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; 86262306a36Sopenharmony_ci struct fcoe_ctlr_device *cdev; 86362306a36Sopenharmony_ci struct fc_lport *lport; 86462306a36Sopenharmony_ci struct fc_lport *vport; 86562306a36Sopenharmony_ci struct bnx2fc_interface *interface, *tmp; 86662306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 86762306a36Sopenharmony_ci int wait_for_upload = 0; 86862306a36Sopenharmony_ci u32 link_possible = 1; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (vlan_id != 0 && event != NETDEV_UNREGISTER) 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci switch (event) { 87462306a36Sopenharmony_ci case NETDEV_UP: 87562306a36Sopenharmony_ci if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) 87662306a36Sopenharmony_ci printk(KERN_ERR "indicate_netevent: "\ 87762306a36Sopenharmony_ci "hba is not UP!!\n"); 87862306a36Sopenharmony_ci break; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci case NETDEV_DOWN: 88162306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); 88262306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); 88362306a36Sopenharmony_ci link_possible = 0; 88462306a36Sopenharmony_ci break; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci case NETDEV_GOING_DOWN: 88762306a36Sopenharmony_ci set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); 88862306a36Sopenharmony_ci link_possible = 0; 88962306a36Sopenharmony_ci break; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci case NETDEV_CHANGE: 89262306a36Sopenharmony_ci break; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci case NETDEV_UNREGISTER: 89562306a36Sopenharmony_ci if (!vlan_id) 89662306a36Sopenharmony_ci return; 89762306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 89862306a36Sopenharmony_ci list_for_each_entry_safe(interface, tmp, &if_list, list) { 89962306a36Sopenharmony_ci if (interface->hba == hba && 90062306a36Sopenharmony_ci interface->vlan_id == (vlan_id & VLAN_VID_MASK)) 90162306a36Sopenharmony_ci __bnx2fc_destroy(interface); 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 90462306a36Sopenharmony_ci return; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci default: 90762306a36Sopenharmony_ci return; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 91162306a36Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (interface->hba != hba) 91462306a36Sopenharmony_ci continue; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 91762306a36Sopenharmony_ci lport = ctlr->lp; 91862306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "netevent handler - event=%s %ld\n", 91962306a36Sopenharmony_ci interface->netdev->name, event); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci fcoe_link_speed_update(lport); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (link_possible && !bnx2fc_link_ok(lport)) { 92662306a36Sopenharmony_ci switch (cdev->enabled) { 92762306a36Sopenharmony_ci case FCOE_CTLR_DISABLED: 92862306a36Sopenharmony_ci pr_info("Link up while interface is disabled.\n"); 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci case FCOE_CTLR_ENABLED: 93162306a36Sopenharmony_ci case FCOE_CTLR_UNUSED: 93262306a36Sopenharmony_ci /* Reset max recv frame size to default */ 93362306a36Sopenharmony_ci fc_set_mfs(lport, BNX2FC_MFS); 93462306a36Sopenharmony_ci /* 93562306a36Sopenharmony_ci * ctlr link up will only be handled during 93662306a36Sopenharmony_ci * enable to avoid sending discovery 93762306a36Sopenharmony_ci * solicitation on a stale vlan 93862306a36Sopenharmony_ci */ 93962306a36Sopenharmony_ci if (interface->enabled) 94062306a36Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci } else if (fcoe_ctlr_link_down(ctlr)) { 94362306a36Sopenharmony_ci switch (cdev->enabled) { 94462306a36Sopenharmony_ci case FCOE_CTLR_DISABLED: 94562306a36Sopenharmony_ci pr_info("Link down while interface is disabled.\n"); 94662306a36Sopenharmony_ci break; 94762306a36Sopenharmony_ci case FCOE_CTLR_ENABLED: 94862306a36Sopenharmony_ci case FCOE_CTLR_UNUSED: 94962306a36Sopenharmony_ci mutex_lock(&lport->lp_mutex); 95062306a36Sopenharmony_ci list_for_each_entry(vport, &lport->vports, list) 95162306a36Sopenharmony_ci fc_host_port_type(vport->host) = 95262306a36Sopenharmony_ci FC_PORTTYPE_UNKNOWN; 95362306a36Sopenharmony_ci mutex_unlock(&lport->lp_mutex); 95462306a36Sopenharmony_ci fc_host_port_type(lport->host) = 95562306a36Sopenharmony_ci FC_PORTTYPE_UNKNOWN; 95662306a36Sopenharmony_ci this_cpu_inc(lport->stats->LinkFailureCount); 95762306a36Sopenharmony_ci fcoe_clean_pending_queue(lport); 95862306a36Sopenharmony_ci wait_for_upload = 1; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (wait_for_upload) { 96562306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_READY, &hba->adapter_state); 96662306a36Sopenharmony_ci init_waitqueue_head(&hba->shutdown_wait); 96762306a36Sopenharmony_ci BNX2FC_MISC_DBG("indicate_netevent " 96862306a36Sopenharmony_ci "num_ofld_sess = %d\n", 96962306a36Sopenharmony_ci hba->num_ofld_sess); 97062306a36Sopenharmony_ci hba->wait_for_link_down = 1; 97162306a36Sopenharmony_ci wait_event_interruptible(hba->shutdown_wait, 97262306a36Sopenharmony_ci (hba->num_ofld_sess == 0)); 97362306a36Sopenharmony_ci BNX2FC_MISC_DBG("wakeup - num_ofld_sess = %d\n", 97462306a36Sopenharmony_ci hba->num_ofld_sess); 97562306a36Sopenharmony_ci hba->wait_for_link_down = 0; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (signal_pending(current)) 97862306a36Sopenharmony_ci flush_signals(current); 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic int bnx2fc_libfc_config(struct fc_lport *lport) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Set the function pointers set by bnx2fc driver */ 98662306a36Sopenharmony_ci memcpy(&lport->tt, &bnx2fc_libfc_fcn_templ, 98762306a36Sopenharmony_ci sizeof(struct libfc_function_template)); 98862306a36Sopenharmony_ci fc_elsct_init(lport); 98962306a36Sopenharmony_ci fc_exch_init(lport); 99062306a36Sopenharmony_ci fc_disc_init(lport); 99162306a36Sopenharmony_ci fc_disc_config(lport, lport); 99262306a36Sopenharmony_ci return 0; 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci int fcoe_min_xid, fcoe_max_xid; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci fcoe_min_xid = hba->max_xid + 1; 100062306a36Sopenharmony_ci if (nr_cpu_ids <= 2) 100162306a36Sopenharmony_ci fcoe_max_xid = hba->max_xid + FCOE_XIDS_PER_CPU_OFFSET; 100262306a36Sopenharmony_ci else 100362306a36Sopenharmony_ci fcoe_max_xid = hba->max_xid + FCOE_MAX_XID_OFFSET; 100462306a36Sopenharmony_ci if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, fcoe_min_xid, 100562306a36Sopenharmony_ci fcoe_max_xid, NULL)) { 100662306a36Sopenharmony_ci printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n"); 100762306a36Sopenharmony_ci return -ENOMEM; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic int bnx2fc_lport_config(struct fc_lport *lport) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci lport->link_up = 0; 101662306a36Sopenharmony_ci lport->qfull = 0; 101762306a36Sopenharmony_ci lport->max_retry_count = BNX2FC_MAX_RETRY_CNT; 101862306a36Sopenharmony_ci lport->max_rport_retry_count = BNX2FC_MAX_RPORT_RETRY_CNT; 101962306a36Sopenharmony_ci lport->e_d_tov = 2 * 1000; 102062306a36Sopenharmony_ci lport->r_a_tov = 10 * 1000; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | 102362306a36Sopenharmony_ci FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); 102462306a36Sopenharmony_ci lport->does_npiv = 1; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci memset(&lport->rnid_gen, 0, sizeof(struct fc_els_rnid_gen)); 102762306a36Sopenharmony_ci lport->rnid_gen.rnid_atype = BNX2FC_RNID_HBA; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* alloc stats structure */ 103062306a36Sopenharmony_ci if (fc_lport_init_stats(lport)) 103162306a36Sopenharmony_ci return -ENOMEM; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* Finish fc_lport configuration */ 103462306a36Sopenharmony_ci fc_lport_config(lport); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci return 0; 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci/** 104062306a36Sopenharmony_ci * bnx2fc_fip_recv - handle a received FIP frame. 104162306a36Sopenharmony_ci * 104262306a36Sopenharmony_ci * @skb: the received skb 104362306a36Sopenharmony_ci * @dev: associated &net_device 104462306a36Sopenharmony_ci * @ptype: the &packet_type structure which was used to register this handler. 104562306a36Sopenharmony_ci * @orig_dev: original receive &net_device, in case @ dev is a bond. 104662306a36Sopenharmony_ci * 104762306a36Sopenharmony_ci * Returns: 0 for success 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_cistatic int bnx2fc_fip_recv(struct sk_buff *skb, struct net_device *dev, 105062306a36Sopenharmony_ci struct packet_type *ptype, 105162306a36Sopenharmony_ci struct net_device *orig_dev) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci struct bnx2fc_interface *interface; 105462306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 105562306a36Sopenharmony_ci interface = container_of(ptype, struct bnx2fc_interface, 105662306a36Sopenharmony_ci fip_packet_type); 105762306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 105862306a36Sopenharmony_ci fcoe_ctlr_recv(ctlr, skb); 105962306a36Sopenharmony_ci return 0; 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci/** 106362306a36Sopenharmony_ci * bnx2fc_update_src_mac - Update Ethernet MAC filters. 106462306a36Sopenharmony_ci * 106562306a36Sopenharmony_ci * @lport: The local port 106662306a36Sopenharmony_ci * @addr: Location of data to copy 106762306a36Sopenharmony_ci * 106862306a36Sopenharmony_ci * Remove any previously-set unicast MAC filter. 106962306a36Sopenharmony_ci * Add secondary FCoE MAC address filter for our OUI. 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_cistatic void bnx2fc_update_src_mac(struct fc_lport *lport, u8 *addr) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci memcpy(port->data_src_addr, addr, ETH_ALEN); 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/** 107962306a36Sopenharmony_ci * bnx2fc_get_src_mac - return the ethernet source address for an lport 108062306a36Sopenharmony_ci * 108162306a36Sopenharmony_ci * @lport: libfc port 108262306a36Sopenharmony_ci */ 108362306a36Sopenharmony_cistatic u8 *bnx2fc_get_src_mac(struct fc_lport *lport) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci struct fcoe_port *port; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci port = (struct fcoe_port *)lport_priv(lport); 108862306a36Sopenharmony_ci return port->data_src_addr; 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci/** 109262306a36Sopenharmony_ci * bnx2fc_fip_send - send an Ethernet-encapsulated FIP frame. 109362306a36Sopenharmony_ci * 109462306a36Sopenharmony_ci * @fip: FCoE controller. 109562306a36Sopenharmony_ci * @skb: FIP Packet. 109662306a36Sopenharmony_ci */ 109762306a36Sopenharmony_cistatic void bnx2fc_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci struct fip_header *fiph; 110062306a36Sopenharmony_ci struct ethhdr *eth_hdr; 110162306a36Sopenharmony_ci u16 op; 110262306a36Sopenharmony_ci u8 sub; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); 110562306a36Sopenharmony_ci eth_hdr = (struct ethhdr *)skb_mac_header(skb); 110662306a36Sopenharmony_ci op = ntohs(fiph->fip_op); 110762306a36Sopenharmony_ci sub = fiph->fip_subcode; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (op == FIP_OP_CTRL && sub == FIP_SC_SOL && bnx2fc_log_fka) 111062306a36Sopenharmony_ci BNX2FC_MISC_DBG("Sending FKA from %pM to %pM.\n", 111162306a36Sopenharmony_ci eth_hdr->h_source, eth_hdr->h_dest); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci skb->dev = bnx2fc_from_ctlr(fip)->netdev; 111462306a36Sopenharmony_ci dev_queue_xmit(skb); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic int bnx2fc_vport_create(struct fc_vport *vport, bool disabled) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci struct Scsi_Host *shost = vport_to_shost(vport); 112062306a36Sopenharmony_ci struct fc_lport *n_port = shost_priv(shost); 112162306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(n_port); 112262306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 112362306a36Sopenharmony_ci struct net_device *netdev = interface->netdev; 112462306a36Sopenharmony_ci struct fc_lport *vn_port; 112562306a36Sopenharmony_ci int rc; 112662306a36Sopenharmony_ci char buf[32]; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci rc = fcoe_validate_vport_create(vport); 112962306a36Sopenharmony_ci if (rc) { 113062306a36Sopenharmony_ci fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); 113162306a36Sopenharmony_ci printk(KERN_ERR PFX "Failed to create vport, " 113262306a36Sopenharmony_ci "WWPN (0x%s) already exists\n", 113362306a36Sopenharmony_ci buf); 113462306a36Sopenharmony_ci return rc; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) { 113862306a36Sopenharmony_ci printk(KERN_ERR PFX "vn ports cannot be created on" 113962306a36Sopenharmony_ci "this interface\n"); 114062306a36Sopenharmony_ci return -EIO; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci rtnl_lock(); 114362306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 114462306a36Sopenharmony_ci vn_port = bnx2fc_if_create(interface, &vport->dev, 1); 114562306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 114662306a36Sopenharmony_ci rtnl_unlock(); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (!vn_port) { 114962306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n", 115062306a36Sopenharmony_ci netdev->name); 115162306a36Sopenharmony_ci return -EIO; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (bnx2fc_devloss_tmo) 115562306a36Sopenharmony_ci fc_host_dev_loss_tmo(vn_port->host) = bnx2fc_devloss_tmo; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (disabled) { 115862306a36Sopenharmony_ci fc_vport_set_state(vport, FC_VPORT_DISABLED); 115962306a36Sopenharmony_ci } else { 116062306a36Sopenharmony_ci vn_port->boot_time = jiffies; 116162306a36Sopenharmony_ci fc_lport_init(vn_port); 116262306a36Sopenharmony_ci fc_fabric_login(vn_port); 116362306a36Sopenharmony_ci fc_vport_setlink(vn_port); 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci return 0; 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cistatic void bnx2fc_free_vport(struct bnx2fc_hba *hba, struct fc_lport *lport) 116962306a36Sopenharmony_ci{ 117062306a36Sopenharmony_ci struct bnx2fc_lport *blport, *tmp; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 117362306a36Sopenharmony_ci list_for_each_entry_safe(blport, tmp, &hba->vports, list) { 117462306a36Sopenharmony_ci if (blport->lport == lport) { 117562306a36Sopenharmony_ci list_del(&blport->list); 117662306a36Sopenharmony_ci kfree(blport); 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_cistatic int bnx2fc_vport_destroy(struct fc_vport *vport) 118362306a36Sopenharmony_ci{ 118462306a36Sopenharmony_ci struct Scsi_Host *shost = vport_to_shost(vport); 118562306a36Sopenharmony_ci struct fc_lport *n_port = shost_priv(shost); 118662306a36Sopenharmony_ci struct fc_lport *vn_port = vport->dd_data; 118762306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(vn_port); 118862306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 118962306a36Sopenharmony_ci struct fc_lport *v_port; 119062306a36Sopenharmony_ci bool found = false; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci mutex_lock(&n_port->lp_mutex); 119362306a36Sopenharmony_ci list_for_each_entry(v_port, &n_port->vports, list) 119462306a36Sopenharmony_ci if (v_port->vport == vport) { 119562306a36Sopenharmony_ci found = true; 119662306a36Sopenharmony_ci break; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (!found) { 120062306a36Sopenharmony_ci mutex_unlock(&n_port->lp_mutex); 120162306a36Sopenharmony_ci return -ENOENT; 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci list_del(&vn_port->list); 120462306a36Sopenharmony_ci mutex_unlock(&n_port->lp_mutex); 120562306a36Sopenharmony_ci bnx2fc_free_vport(interface->hba, port->lport); 120662306a36Sopenharmony_ci bnx2fc_port_shutdown(port->lport); 120762306a36Sopenharmony_ci bnx2fc_port_destroy(port); 120862306a36Sopenharmony_ci bnx2fc_interface_put(interface); 120962306a36Sopenharmony_ci return 0; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic int bnx2fc_vport_disable(struct fc_vport *vport, bool disable) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct fc_lport *lport = vport->dd_data; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (disable) { 121762306a36Sopenharmony_ci fc_vport_set_state(vport, FC_VPORT_DISABLED); 121862306a36Sopenharmony_ci fc_fabric_logoff(lport); 121962306a36Sopenharmony_ci } else { 122062306a36Sopenharmony_ci lport->boot_time = jiffies; 122162306a36Sopenharmony_ci fc_fabric_login(lport); 122262306a36Sopenharmony_ci fc_vport_setlink(lport); 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci return 0; 122562306a36Sopenharmony_ci} 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int bnx2fc_interface_setup(struct bnx2fc_interface *interface) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct net_device *netdev = interface->netdev; 123162306a36Sopenharmony_ci struct net_device *physdev = interface->hba->phys_dev; 123262306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 123362306a36Sopenharmony_ci struct netdev_hw_addr *ha; 123462306a36Sopenharmony_ci int sel_san_mac = 0; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* setup Source MAC Address */ 123762306a36Sopenharmony_ci rcu_read_lock(); 123862306a36Sopenharmony_ci for_each_dev_addr(physdev, ha) { 123962306a36Sopenharmony_ci BNX2FC_MISC_DBG("net_config: ha->type = %d, fip_mac = ", 124062306a36Sopenharmony_ci ha->type); 124162306a36Sopenharmony_ci printk(KERN_INFO "%2x:%2x:%2x:%2x:%2x:%2x\n", ha->addr[0], 124262306a36Sopenharmony_ci ha->addr[1], ha->addr[2], ha->addr[3], 124362306a36Sopenharmony_ci ha->addr[4], ha->addr[5]); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if ((ha->type == NETDEV_HW_ADDR_T_SAN) && 124662306a36Sopenharmony_ci (is_valid_ether_addr(ha->addr))) { 124762306a36Sopenharmony_ci memcpy(ctlr->ctl_src_addr, ha->addr, 124862306a36Sopenharmony_ci ETH_ALEN); 124962306a36Sopenharmony_ci sel_san_mac = 1; 125062306a36Sopenharmony_ci BNX2FC_MISC_DBG("Found SAN MAC\n"); 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci rcu_read_unlock(); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci if (!sel_san_mac) 125662306a36Sopenharmony_ci return -ENODEV; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci interface->fip_packet_type.func = bnx2fc_fip_recv; 125962306a36Sopenharmony_ci interface->fip_packet_type.type = htons(ETH_P_FIP); 126062306a36Sopenharmony_ci interface->fip_packet_type.dev = netdev; 126162306a36Sopenharmony_ci dev_add_pack(&interface->fip_packet_type); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci interface->fcoe_packet_type.func = bnx2fc_rcv; 126462306a36Sopenharmony_ci interface->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); 126562306a36Sopenharmony_ci interface->fcoe_packet_type.dev = netdev; 126662306a36Sopenharmony_ci dev_add_pack(&interface->fcoe_packet_type); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci return 0; 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cistatic int bnx2fc_attach_transport(void) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci bnx2fc_transport_template = 127462306a36Sopenharmony_ci fc_attach_transport(&bnx2fc_transport_function); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (bnx2fc_transport_template == NULL) { 127762306a36Sopenharmony_ci printk(KERN_ERR PFX "Failed to attach FC transport\n"); 127862306a36Sopenharmony_ci return -ENODEV; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci bnx2fc_vport_xport_template = 128262306a36Sopenharmony_ci fc_attach_transport(&bnx2fc_vport_xport_function); 128362306a36Sopenharmony_ci if (bnx2fc_vport_xport_template == NULL) { 128462306a36Sopenharmony_ci printk(KERN_ERR PFX 128562306a36Sopenharmony_ci "Failed to attach FC transport for vport\n"); 128662306a36Sopenharmony_ci fc_release_transport(bnx2fc_transport_template); 128762306a36Sopenharmony_ci bnx2fc_transport_template = NULL; 128862306a36Sopenharmony_ci return -ENODEV; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci return 0; 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_cistatic void bnx2fc_release_transport(void) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci fc_release_transport(bnx2fc_transport_template); 129562306a36Sopenharmony_ci fc_release_transport(bnx2fc_vport_xport_template); 129662306a36Sopenharmony_ci bnx2fc_transport_template = NULL; 129762306a36Sopenharmony_ci bnx2fc_vport_xport_template = NULL; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic void bnx2fc_interface_release(struct kref *kref) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct fcoe_ctlr_device *ctlr_dev; 130362306a36Sopenharmony_ci struct bnx2fc_interface *interface; 130462306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 130562306a36Sopenharmony_ci struct net_device *netdev; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci interface = container_of(kref, struct bnx2fc_interface, kref); 130862306a36Sopenharmony_ci BNX2FC_MISC_DBG("Interface is being released\n"); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 131162306a36Sopenharmony_ci ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); 131262306a36Sopenharmony_ci netdev = interface->netdev; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* tear-down FIP controller */ 131562306a36Sopenharmony_ci if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) 131662306a36Sopenharmony_ci fcoe_ctlr_destroy(ctlr); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci fcoe_ctlr_device_delete(ctlr_dev); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci dev_put(netdev); 132162306a36Sopenharmony_ci module_put(THIS_MODULE); 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic inline void bnx2fc_interface_get(struct bnx2fc_interface *interface) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci kref_get(&interface->kref); 132762306a36Sopenharmony_ci} 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cistatic inline void bnx2fc_interface_put(struct bnx2fc_interface *interface) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci kref_put(&interface->kref, bnx2fc_interface_release); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_cistatic void bnx2fc_hba_destroy(struct bnx2fc_hba *hba) 133462306a36Sopenharmony_ci{ 133562306a36Sopenharmony_ci /* Free the command manager */ 133662306a36Sopenharmony_ci if (hba->cmd_mgr) { 133762306a36Sopenharmony_ci bnx2fc_cmd_mgr_free(hba->cmd_mgr); 133862306a36Sopenharmony_ci hba->cmd_mgr = NULL; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci kfree(hba->tgt_ofld_list); 134162306a36Sopenharmony_ci bnx2fc_unbind_pcidev(hba); 134262306a36Sopenharmony_ci kfree(hba); 134362306a36Sopenharmony_ci} 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci/** 134662306a36Sopenharmony_ci * bnx2fc_hba_create - create a new bnx2fc hba 134762306a36Sopenharmony_ci * 134862306a36Sopenharmony_ci * @cnic: pointer to cnic device 134962306a36Sopenharmony_ci * 135062306a36Sopenharmony_ci * Creates a new FCoE hba on the given device. 135162306a36Sopenharmony_ci * 135262306a36Sopenharmony_ci */ 135362306a36Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci struct bnx2fc_hba *hba; 135662306a36Sopenharmony_ci struct fcoe_capabilities *fcoe_cap; 135762306a36Sopenharmony_ci int rc; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci hba = kzalloc(sizeof(*hba), GFP_KERNEL); 136062306a36Sopenharmony_ci if (!hba) { 136162306a36Sopenharmony_ci printk(KERN_ERR PFX "Unable to allocate hba structure\n"); 136262306a36Sopenharmony_ci return NULL; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci spin_lock_init(&hba->hba_lock); 136562306a36Sopenharmony_ci mutex_init(&hba->hba_mutex); 136662306a36Sopenharmony_ci mutex_init(&hba->hba_stats_mutex); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci hba->cnic = cnic; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci hba->max_tasks = cnic->max_fcoe_exchanges; 137162306a36Sopenharmony_ci hba->elstm_xids = (hba->max_tasks / 2); 137262306a36Sopenharmony_ci hba->max_outstanding_cmds = hba->elstm_xids; 137362306a36Sopenharmony_ci hba->max_xid = (hba->max_tasks - 1); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci rc = bnx2fc_bind_pcidev(hba); 137662306a36Sopenharmony_ci if (rc) { 137762306a36Sopenharmony_ci printk(KERN_ERR PFX "create_adapter: bind error\n"); 137862306a36Sopenharmony_ci goto bind_err; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci hba->phys_dev = cnic->netdev; 138162306a36Sopenharmony_ci hba->next_conn_id = 0; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci hba->tgt_ofld_list = 138462306a36Sopenharmony_ci kcalloc(BNX2FC_NUM_MAX_SESS, sizeof(struct bnx2fc_rport *), 138562306a36Sopenharmony_ci GFP_KERNEL); 138662306a36Sopenharmony_ci if (!hba->tgt_ofld_list) { 138762306a36Sopenharmony_ci printk(KERN_ERR PFX "Unable to allocate tgt offload list\n"); 138862306a36Sopenharmony_ci goto tgtofld_err; 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci hba->num_ofld_sess = 0; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba); 139462306a36Sopenharmony_ci if (!hba->cmd_mgr) { 139562306a36Sopenharmony_ci printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n"); 139662306a36Sopenharmony_ci goto cmgr_err; 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci fcoe_cap = &hba->fcoe_cap; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci fcoe_cap->capability1 = BNX2FC_TM_MAX_SQES << 140162306a36Sopenharmony_ci FCOE_IOS_PER_CONNECTION_SHIFT; 140262306a36Sopenharmony_ci fcoe_cap->capability1 |= BNX2FC_NUM_MAX_SESS << 140362306a36Sopenharmony_ci FCOE_LOGINS_PER_PORT_SHIFT; 140462306a36Sopenharmony_ci fcoe_cap->capability2 = hba->max_outstanding_cmds << 140562306a36Sopenharmony_ci FCOE_NUMBER_OF_EXCHANGES_SHIFT; 140662306a36Sopenharmony_ci fcoe_cap->capability2 |= BNX2FC_MAX_NPIV << 140762306a36Sopenharmony_ci FCOE_NPIV_WWN_PER_PORT_SHIFT; 140862306a36Sopenharmony_ci fcoe_cap->capability3 = BNX2FC_NUM_MAX_SESS << 140962306a36Sopenharmony_ci FCOE_TARGETS_SUPPORTED_SHIFT; 141062306a36Sopenharmony_ci fcoe_cap->capability3 |= hba->max_outstanding_cmds << 141162306a36Sopenharmony_ci FCOE_OUTSTANDING_COMMANDS_SHIFT; 141262306a36Sopenharmony_ci fcoe_cap->capability4 = FCOE_CAPABILITY4_STATEFUL; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci init_waitqueue_head(&hba->shutdown_wait); 141562306a36Sopenharmony_ci init_waitqueue_head(&hba->destroy_wait); 141662306a36Sopenharmony_ci INIT_LIST_HEAD(&hba->vports); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci return hba; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_cicmgr_err: 142162306a36Sopenharmony_ci kfree(hba->tgt_ofld_list); 142262306a36Sopenharmony_citgtofld_err: 142362306a36Sopenharmony_ci bnx2fc_unbind_pcidev(hba); 142462306a36Sopenharmony_cibind_err: 142562306a36Sopenharmony_ci kfree(hba); 142662306a36Sopenharmony_ci return NULL; 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cistatic struct bnx2fc_interface * 143062306a36Sopenharmony_cibnx2fc_interface_create(struct bnx2fc_hba *hba, 143162306a36Sopenharmony_ci struct net_device *netdev, 143262306a36Sopenharmony_ci enum fip_mode fip_mode) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci struct fcoe_ctlr_device *ctlr_dev; 143562306a36Sopenharmony_ci struct bnx2fc_interface *interface; 143662306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 143762306a36Sopenharmony_ci int size; 143862306a36Sopenharmony_ci int rc = 0; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci size = (sizeof(*interface) + sizeof(struct fcoe_ctlr)); 144162306a36Sopenharmony_ci ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &bnx2fc_fcoe_sysfs_templ, 144262306a36Sopenharmony_ci size); 144362306a36Sopenharmony_ci if (!ctlr_dev) { 144462306a36Sopenharmony_ci printk(KERN_ERR PFX "Unable to allocate interface structure\n"); 144562306a36Sopenharmony_ci return NULL; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci ctlr = fcoe_ctlr_device_priv(ctlr_dev); 144862306a36Sopenharmony_ci ctlr->cdev = ctlr_dev; 144962306a36Sopenharmony_ci interface = fcoe_ctlr_priv(ctlr); 145062306a36Sopenharmony_ci dev_hold(netdev); 145162306a36Sopenharmony_ci kref_init(&interface->kref); 145262306a36Sopenharmony_ci interface->hba = hba; 145362306a36Sopenharmony_ci interface->netdev = netdev; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* Initialize FIP */ 145662306a36Sopenharmony_ci fcoe_ctlr_init(ctlr, fip_mode); 145762306a36Sopenharmony_ci ctlr->send = bnx2fc_fip_send; 145862306a36Sopenharmony_ci ctlr->update_mac = bnx2fc_update_src_mac; 145962306a36Sopenharmony_ci ctlr->get_src_addr = bnx2fc_get_src_mac; 146062306a36Sopenharmony_ci set_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci rc = bnx2fc_interface_setup(interface); 146362306a36Sopenharmony_ci if (!rc) 146462306a36Sopenharmony_ci return interface; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci fcoe_ctlr_destroy(ctlr); 146762306a36Sopenharmony_ci dev_put(netdev); 146862306a36Sopenharmony_ci fcoe_ctlr_device_delete(ctlr_dev); 146962306a36Sopenharmony_ci return NULL; 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci/** 147362306a36Sopenharmony_ci * bnx2fc_if_create - Create FCoE instance on a given interface 147462306a36Sopenharmony_ci * 147562306a36Sopenharmony_ci * @interface: FCoE interface to create a local port on 147662306a36Sopenharmony_ci * @parent: Device pointer to be the parent in sysfs for the SCSI host 147762306a36Sopenharmony_ci * @npiv: Indicates if the port is vport or not 147862306a36Sopenharmony_ci * 147962306a36Sopenharmony_ci * Creates a fc_lport instance and a Scsi_Host instance and configure them. 148062306a36Sopenharmony_ci * 148162306a36Sopenharmony_ci * Returns: Allocated fc_lport or an error pointer 148262306a36Sopenharmony_ci */ 148362306a36Sopenharmony_cistatic struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, 148462306a36Sopenharmony_ci struct device *parent, int npiv) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 148762306a36Sopenharmony_ci struct fc_lport *lport, *n_port; 148862306a36Sopenharmony_ci struct fcoe_port *port; 148962306a36Sopenharmony_ci struct Scsi_Host *shost; 149062306a36Sopenharmony_ci struct fc_vport *vport = dev_to_vport(parent); 149162306a36Sopenharmony_ci struct bnx2fc_lport *blport; 149262306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 149362306a36Sopenharmony_ci int rc = 0; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL); 149662306a36Sopenharmony_ci if (!blport) { 149762306a36Sopenharmony_ci BNX2FC_HBA_DBG(ctlr->lp, "Unable to alloc blport\n"); 149862306a36Sopenharmony_ci return NULL; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci /* Allocate Scsi_Host structure */ 150262306a36Sopenharmony_ci bnx2fc_shost_template.can_queue = hba->max_outstanding_cmds; 150362306a36Sopenharmony_ci if (!npiv) 150462306a36Sopenharmony_ci lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); 150562306a36Sopenharmony_ci else 150662306a36Sopenharmony_ci lport = libfc_vport_create(vport, sizeof(*port)); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (!lport) { 150962306a36Sopenharmony_ci printk(KERN_ERR PFX "could not allocate scsi host structure\n"); 151062306a36Sopenharmony_ci goto free_blport; 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci shost = lport->host; 151362306a36Sopenharmony_ci port = lport_priv(lport); 151462306a36Sopenharmony_ci port->lport = lport; 151562306a36Sopenharmony_ci port->priv = interface; 151662306a36Sopenharmony_ci port->get_netdev = bnx2fc_netdev; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci /* Configure fcoe_port */ 151962306a36Sopenharmony_ci rc = bnx2fc_lport_config(lport); 152062306a36Sopenharmony_ci if (rc) 152162306a36Sopenharmony_ci goto lp_config_err; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (npiv) { 152462306a36Sopenharmony_ci printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n", 152562306a36Sopenharmony_ci vport->node_name, vport->port_name); 152662306a36Sopenharmony_ci fc_set_wwnn(lport, vport->node_name); 152762306a36Sopenharmony_ci fc_set_wwpn(lport, vport->port_name); 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci /* Configure netdev and networking properties of the lport */ 153062306a36Sopenharmony_ci rc = bnx2fc_net_config(lport, interface->netdev); 153162306a36Sopenharmony_ci if (rc) { 153262306a36Sopenharmony_ci printk(KERN_ERR PFX "Error on bnx2fc_net_config\n"); 153362306a36Sopenharmony_ci goto lp_config_err; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci rc = bnx2fc_shost_config(lport, parent); 153762306a36Sopenharmony_ci if (rc) { 153862306a36Sopenharmony_ci printk(KERN_ERR PFX "Couldn't configure shost for %s\n", 153962306a36Sopenharmony_ci interface->netdev->name); 154062306a36Sopenharmony_ci goto lp_config_err; 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci /* Initialize the libfc library */ 154462306a36Sopenharmony_ci rc = bnx2fc_libfc_config(lport); 154562306a36Sopenharmony_ci if (rc) { 154662306a36Sopenharmony_ci printk(KERN_ERR PFX "Couldn't configure libfc\n"); 154762306a36Sopenharmony_ci goto shost_err; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (bnx2fc_devloss_tmo) 155262306a36Sopenharmony_ci fc_host_dev_loss_tmo(shost) = bnx2fc_devloss_tmo; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci /* Allocate exchange manager */ 155562306a36Sopenharmony_ci if (!npiv) 155662306a36Sopenharmony_ci rc = bnx2fc_em_config(lport, hba); 155762306a36Sopenharmony_ci else { 155862306a36Sopenharmony_ci shost = vport_to_shost(vport); 155962306a36Sopenharmony_ci n_port = shost_priv(shost); 156062306a36Sopenharmony_ci rc = fc_exch_mgr_list_clone(n_port, lport); 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci if (rc) { 156462306a36Sopenharmony_ci printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); 156562306a36Sopenharmony_ci goto shost_err; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci bnx2fc_interface_get(interface); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 157162306a36Sopenharmony_ci blport->lport = lport; 157262306a36Sopenharmony_ci list_add_tail(&blport->list, &hba->vports); 157362306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci return lport; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cishost_err: 157862306a36Sopenharmony_ci scsi_remove_host(shost); 157962306a36Sopenharmony_cilp_config_err: 158062306a36Sopenharmony_ci scsi_host_put(lport->host); 158162306a36Sopenharmony_cifree_blport: 158262306a36Sopenharmony_ci kfree(blport); 158362306a36Sopenharmony_ci return NULL; 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_cistatic void bnx2fc_net_cleanup(struct bnx2fc_interface *interface) 158762306a36Sopenharmony_ci{ 158862306a36Sopenharmony_ci /* Dont listen for Ethernet packets anymore */ 158962306a36Sopenharmony_ci __dev_remove_pack(&interface->fcoe_packet_type); 159062306a36Sopenharmony_ci __dev_remove_pack(&interface->fip_packet_type); 159162306a36Sopenharmony_ci synchronize_net(); 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 159762306a36Sopenharmony_ci struct fc_lport *lport = ctlr->lp; 159862306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 159962306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* Stop the transmit retry timer */ 160262306a36Sopenharmony_ci del_timer_sync(&port->timer); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci /* Free existing transmit skbs */ 160562306a36Sopenharmony_ci fcoe_clean_pending_queue(lport); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci bnx2fc_net_cleanup(interface); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci bnx2fc_free_vport(hba, lport); 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_cistatic void bnx2fc_if_destroy(struct fc_lport *lport) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci /* Free queued packets for the receive thread */ 161662306a36Sopenharmony_ci bnx2fc_clean_rx_queue(lport); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci /* Detach from scsi-ml */ 161962306a36Sopenharmony_ci fc_remove_host(lport->host); 162062306a36Sopenharmony_ci scsi_remove_host(lport->host); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* 162362306a36Sopenharmony_ci * Note that only the physical lport will have the exchange manager. 162462306a36Sopenharmony_ci * for vports, this function is NOP 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci fc_exch_mgr_free(lport); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci /* Free memory used by statistical counters */ 162962306a36Sopenharmony_ci fc_lport_free_stats(lport); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci /* Release Scsi_Host */ 163262306a36Sopenharmony_ci scsi_host_put(lport->host); 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic void __bnx2fc_destroy(struct bnx2fc_interface *interface) 163662306a36Sopenharmony_ci{ 163762306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 163862306a36Sopenharmony_ci struct fc_lport *lport = ctlr->lp; 163962306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci bnx2fc_interface_cleanup(interface); 164262306a36Sopenharmony_ci bnx2fc_stop(interface); 164362306a36Sopenharmony_ci list_del(&interface->list); 164462306a36Sopenharmony_ci bnx2fc_port_destroy(port); 164562306a36Sopenharmony_ci bnx2fc_interface_put(interface); 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci/** 164962306a36Sopenharmony_ci * bnx2fc_destroy - Destroy a bnx2fc FCoE interface 165062306a36Sopenharmony_ci * 165162306a36Sopenharmony_ci * @netdev: The net device that the FCoE interface is on 165262306a36Sopenharmony_ci * 165362306a36Sopenharmony_ci * Called from sysfs. 165462306a36Sopenharmony_ci * 165562306a36Sopenharmony_ci * Returns: 0 for success 165662306a36Sopenharmony_ci */ 165762306a36Sopenharmony_cistatic int bnx2fc_destroy(struct net_device *netdev) 165862306a36Sopenharmony_ci{ 165962306a36Sopenharmony_ci struct bnx2fc_interface *interface = NULL; 166062306a36Sopenharmony_ci struct workqueue_struct *timer_work_queue; 166162306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 166262306a36Sopenharmony_ci int rc = 0; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci rtnl_lock(); 166562306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci interface = bnx2fc_interface_lookup(netdev); 166862306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 166962306a36Sopenharmony_ci if (!interface || !ctlr->lp) { 167062306a36Sopenharmony_ci rc = -ENODEV; 167162306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_destroy: interface or lport not found\n"); 167262306a36Sopenharmony_ci goto netdev_err; 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci timer_work_queue = interface->timer_work_queue; 167662306a36Sopenharmony_ci __bnx2fc_destroy(interface); 167762306a36Sopenharmony_ci destroy_workqueue(timer_work_queue); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cinetdev_err: 168062306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 168162306a36Sopenharmony_ci rtnl_unlock(); 168262306a36Sopenharmony_ci return rc; 168362306a36Sopenharmony_ci} 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_cistatic void bnx2fc_port_destroy(struct fcoe_port *port) 168662306a36Sopenharmony_ci{ 168762306a36Sopenharmony_ci struct fc_lport *lport; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci lport = port->lport; 169062306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Entered %s, destroying lport %p\n", __func__, lport); 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci bnx2fc_if_destroy(lport); 169362306a36Sopenharmony_ci} 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_cistatic void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci bnx2fc_free_fw_resc(hba); 169862306a36Sopenharmony_ci bnx2fc_free_task_ctx(hba); 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci/** 170262306a36Sopenharmony_ci * bnx2fc_bind_adapter_devices - binds bnx2fc adapter with the associated 170362306a36Sopenharmony_ci * pci structure 170462306a36Sopenharmony_ci * 170562306a36Sopenharmony_ci * @hba: Adapter instance 170662306a36Sopenharmony_ci */ 170762306a36Sopenharmony_cistatic int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba) 170862306a36Sopenharmony_ci{ 170962306a36Sopenharmony_ci if (bnx2fc_setup_task_ctx(hba)) 171062306a36Sopenharmony_ci goto mem_err; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci if (bnx2fc_setup_fw_resc(hba)) 171362306a36Sopenharmony_ci goto mem_err; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci return 0; 171662306a36Sopenharmony_cimem_err: 171762306a36Sopenharmony_ci bnx2fc_unbind_adapter_devices(hba); 171862306a36Sopenharmony_ci return -ENOMEM; 171962306a36Sopenharmony_ci} 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_cistatic int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci struct cnic_dev *cnic; 172462306a36Sopenharmony_ci struct pci_dev *pdev; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (!hba->cnic) { 172762306a36Sopenharmony_ci printk(KERN_ERR PFX "cnic is NULL\n"); 172862306a36Sopenharmony_ci return -ENODEV; 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci cnic = hba->cnic; 173162306a36Sopenharmony_ci pdev = hba->pcidev = cnic->pcidev; 173262306a36Sopenharmony_ci if (!hba->pcidev) 173362306a36Sopenharmony_ci return -ENODEV; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci switch (pdev->device) { 173662306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57710: 173762306a36Sopenharmony_ci strncpy(hba->chip_num, "BCM57710", BCM_CHIP_LEN); 173862306a36Sopenharmony_ci break; 173962306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57711: 174062306a36Sopenharmony_ci strncpy(hba->chip_num, "BCM57711", BCM_CHIP_LEN); 174162306a36Sopenharmony_ci break; 174262306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57712: 174362306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57712_MF: 174462306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57712_VF: 174562306a36Sopenharmony_ci strncpy(hba->chip_num, "BCM57712", BCM_CHIP_LEN); 174662306a36Sopenharmony_ci break; 174762306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57800: 174862306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57800_MF: 174962306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57800_VF: 175062306a36Sopenharmony_ci strncpy(hba->chip_num, "BCM57800", BCM_CHIP_LEN); 175162306a36Sopenharmony_ci break; 175262306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57810: 175362306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57810_MF: 175462306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57810_VF: 175562306a36Sopenharmony_ci strncpy(hba->chip_num, "BCM57810", BCM_CHIP_LEN); 175662306a36Sopenharmony_ci break; 175762306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840: 175862306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_MF: 175962306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_VF: 176062306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_2_20: 176162306a36Sopenharmony_ci case PCI_DEVICE_ID_NX2_57840_4_10: 176262306a36Sopenharmony_ci strncpy(hba->chip_num, "BCM57840", BCM_CHIP_LEN); 176362306a36Sopenharmony_ci break; 176462306a36Sopenharmony_ci default: 176562306a36Sopenharmony_ci pr_err(PFX "Unknown device id 0x%x\n", pdev->device); 176662306a36Sopenharmony_ci break; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci pci_dev_get(hba->pcidev); 176962306a36Sopenharmony_ci return 0; 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_cistatic void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba) 177362306a36Sopenharmony_ci{ 177462306a36Sopenharmony_ci if (hba->pcidev) { 177562306a36Sopenharmony_ci hba->chip_num[0] = '\0'; 177662306a36Sopenharmony_ci pci_dev_put(hba->pcidev); 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci hba->pcidev = NULL; 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci/** 178262306a36Sopenharmony_ci * bnx2fc_ulp_get_stats - cnic callback to populate FCoE stats 178362306a36Sopenharmony_ci * 178462306a36Sopenharmony_ci * @handle: transport handle pointing to adapter structure 178562306a36Sopenharmony_ci */ 178662306a36Sopenharmony_cistatic int bnx2fc_ulp_get_stats(void *handle) 178762306a36Sopenharmony_ci{ 178862306a36Sopenharmony_ci struct bnx2fc_hba *hba = handle; 178962306a36Sopenharmony_ci struct cnic_dev *cnic; 179062306a36Sopenharmony_ci struct fcoe_stats_info *stats_addr; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci if (!hba) 179362306a36Sopenharmony_ci return -EINVAL; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci cnic = hba->cnic; 179662306a36Sopenharmony_ci stats_addr = &cnic->stats_addr->fcoe_stat; 179762306a36Sopenharmony_ci if (!stats_addr) 179862306a36Sopenharmony_ci return -EINVAL; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci strncpy(stats_addr->version, BNX2FC_VERSION, 180162306a36Sopenharmony_ci sizeof(stats_addr->version)); 180262306a36Sopenharmony_ci stats_addr->txq_size = BNX2FC_SQ_WQES_MAX; 180362306a36Sopenharmony_ci stats_addr->rxq_size = BNX2FC_CQ_WQES_MAX; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci return 0; 180662306a36Sopenharmony_ci} 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci/** 181062306a36Sopenharmony_ci * bnx2fc_ulp_start - cnic callback to initialize & start adapter instance 181162306a36Sopenharmony_ci * 181262306a36Sopenharmony_ci * @handle: transport handle pointing to adapter structure 181362306a36Sopenharmony_ci * 181462306a36Sopenharmony_ci * This function maps adapter structure to pcidev structure and initiates 181562306a36Sopenharmony_ci * firmware handshake to enable/initialize on-chip FCoE components. 181662306a36Sopenharmony_ci * This bnx2fc - cnic interface api callback is used after following 181762306a36Sopenharmony_ci * conditions are met - 181862306a36Sopenharmony_ci * a) underlying network interface is up (marked by event NETDEV_UP 181962306a36Sopenharmony_ci * from netdev 182062306a36Sopenharmony_ci * b) bnx2fc adatper structure is registered. 182162306a36Sopenharmony_ci */ 182262306a36Sopenharmony_cistatic void bnx2fc_ulp_start(void *handle) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci struct bnx2fc_hba *hba = handle; 182562306a36Sopenharmony_ci struct bnx2fc_interface *interface; 182662306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 182762306a36Sopenharmony_ci struct fc_lport *lport; 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) 183262306a36Sopenharmony_ci bnx2fc_fw_init(hba); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci BNX2FC_MISC_DBG("bnx2fc started.\n"); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 183762306a36Sopenharmony_ci if (interface->hba == hba) { 183862306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 183962306a36Sopenharmony_ci lport = ctlr->lp; 184062306a36Sopenharmony_ci /* Kick off Fabric discovery*/ 184162306a36Sopenharmony_ci printk(KERN_ERR PFX "ulp_init: start discovery\n"); 184262306a36Sopenharmony_ci lport->tt.frame_send = bnx2fc_xmit; 184362306a36Sopenharmony_ci bnx2fc_start_disc(interface); 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 184862306a36Sopenharmony_ci} 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_cistatic void bnx2fc_port_shutdown(struct fc_lport *lport) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 185362306a36Sopenharmony_ci fc_fabric_logoff(lport); 185462306a36Sopenharmony_ci fc_lport_destroy(lport); 185562306a36Sopenharmony_ci} 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_cistatic void bnx2fc_stop(struct bnx2fc_interface *interface) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 186062306a36Sopenharmony_ci struct fc_lport *lport; 186162306a36Sopenharmony_ci struct fc_lport *vport; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) 186462306a36Sopenharmony_ci return; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci lport = ctlr->lp; 186762306a36Sopenharmony_ci bnx2fc_port_shutdown(lport); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci mutex_lock(&lport->lp_mutex); 187062306a36Sopenharmony_ci list_for_each_entry(vport, &lport->vports, list) 187162306a36Sopenharmony_ci fc_host_port_type(vport->host) = 187262306a36Sopenharmony_ci FC_PORTTYPE_UNKNOWN; 187362306a36Sopenharmony_ci mutex_unlock(&lport->lp_mutex); 187462306a36Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; 187562306a36Sopenharmony_ci fcoe_ctlr_link_down(ctlr); 187662306a36Sopenharmony_ci fcoe_clean_pending_queue(lport); 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_cistatic int bnx2fc_fw_init(struct bnx2fc_hba *hba) 188062306a36Sopenharmony_ci{ 188162306a36Sopenharmony_ci#define BNX2FC_INIT_POLL_TIME (1000 / HZ) 188262306a36Sopenharmony_ci int rc = -1; 188362306a36Sopenharmony_ci int i = HZ; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci rc = bnx2fc_bind_adapter_devices(hba); 188662306a36Sopenharmony_ci if (rc) { 188762306a36Sopenharmony_ci printk(KERN_ALERT PFX 188862306a36Sopenharmony_ci "bnx2fc_bind_adapter_devices failed - rc = %d\n", rc); 188962306a36Sopenharmony_ci goto err_out; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci rc = bnx2fc_send_fw_fcoe_init_msg(hba); 189362306a36Sopenharmony_ci if (rc) { 189462306a36Sopenharmony_ci printk(KERN_ALERT PFX 189562306a36Sopenharmony_ci "bnx2fc_send_fw_fcoe_init_msg failed - rc = %d\n", rc); 189662306a36Sopenharmony_ci goto err_unbind; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci /* 190062306a36Sopenharmony_ci * Wait until the adapter init message is complete, and adapter 190162306a36Sopenharmony_ci * state is UP. 190262306a36Sopenharmony_ci */ 190362306a36Sopenharmony_ci while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) 190462306a36Sopenharmony_ci msleep(BNX2FC_INIT_POLL_TIME); 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) { 190762306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_start: %s failed to initialize. " 190862306a36Sopenharmony_ci "Ignoring...\n", 190962306a36Sopenharmony_ci hba->cnic->netdev->name); 191062306a36Sopenharmony_ci rc = -1; 191162306a36Sopenharmony_ci goto err_unbind; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags); 191662306a36Sopenharmony_ci return 0; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cierr_unbind: 191962306a36Sopenharmony_ci bnx2fc_unbind_adapter_devices(hba); 192062306a36Sopenharmony_cierr_out: 192162306a36Sopenharmony_ci return rc; 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_cistatic void bnx2fc_fw_destroy(struct bnx2fc_hba *hba) 192562306a36Sopenharmony_ci{ 192662306a36Sopenharmony_ci if (test_and_clear_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) { 192762306a36Sopenharmony_ci if (bnx2fc_send_fw_fcoe_destroy_msg(hba) == 0) { 192862306a36Sopenharmony_ci timer_setup(&hba->destroy_timer, bnx2fc_destroy_timer, 192962306a36Sopenharmony_ci 0); 193062306a36Sopenharmony_ci hba->destroy_timer.expires = BNX2FC_FW_TIMEOUT + 193162306a36Sopenharmony_ci jiffies; 193262306a36Sopenharmony_ci add_timer(&hba->destroy_timer); 193362306a36Sopenharmony_ci wait_event_interruptible(hba->destroy_wait, 193462306a36Sopenharmony_ci test_bit(BNX2FC_FLAG_DESTROY_CMPL, 193562306a36Sopenharmony_ci &hba->flags)); 193662306a36Sopenharmony_ci clear_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); 193762306a36Sopenharmony_ci /* This should never happen */ 193862306a36Sopenharmony_ci if (signal_pending(current)) 193962306a36Sopenharmony_ci flush_signals(current); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci del_timer_sync(&hba->destroy_timer); 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci bnx2fc_unbind_adapter_devices(hba); 194462306a36Sopenharmony_ci } 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci/** 194862306a36Sopenharmony_ci * bnx2fc_ulp_stop - cnic callback to shutdown adapter instance 194962306a36Sopenharmony_ci * 195062306a36Sopenharmony_ci * @handle: transport handle pointing to adapter structure 195162306a36Sopenharmony_ci * 195262306a36Sopenharmony_ci * Driver checks if adapter is already in shutdown mode, if not start 195362306a36Sopenharmony_ci * the shutdown process. 195462306a36Sopenharmony_ci */ 195562306a36Sopenharmony_cistatic void bnx2fc_ulp_stop(void *handle) 195662306a36Sopenharmony_ci{ 195762306a36Sopenharmony_ci struct bnx2fc_hba *hba = handle; 195862306a36Sopenharmony_ci struct bnx2fc_interface *interface; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci printk(KERN_ERR "ULP_STOP\n"); 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 196362306a36Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) 196462306a36Sopenharmony_ci goto exit; 196562306a36Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 196662306a36Sopenharmony_ci if (interface->hba == hba) 196762306a36Sopenharmony_ci bnx2fc_stop(interface); 196862306a36Sopenharmony_ci } 196962306a36Sopenharmony_ci BUG_ON(hba->num_ofld_sess != 0); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci mutex_lock(&hba->hba_mutex); 197262306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); 197362306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_GOING_DOWN, 197462306a36Sopenharmony_ci &hba->adapter_state); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_READY, &hba->adapter_state); 197762306a36Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci bnx2fc_fw_destroy(hba); 198062306a36Sopenharmony_ciexit: 198162306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 198262306a36Sopenharmony_ci} 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_cistatic void bnx2fc_start_disc(struct bnx2fc_interface *interface) 198562306a36Sopenharmony_ci{ 198662306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 198762306a36Sopenharmony_ci struct fc_lport *lport; 198862306a36Sopenharmony_ci int wait_cnt = 0; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 199162306a36Sopenharmony_ci /* Kick off FIP/FLOGI */ 199262306a36Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) { 199362306a36Sopenharmony_ci printk(KERN_ERR PFX "Init not done yet\n"); 199462306a36Sopenharmony_ci return; 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci lport = ctlr->lp; 199862306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n"); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci if (!bnx2fc_link_ok(lport) && interface->enabled) { 200162306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "ctlr_link_up\n"); 200262306a36Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 200362306a36Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; 200462306a36Sopenharmony_ci set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); 200562306a36Sopenharmony_ci } 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci /* wait for the FCF to be selected before issuing FLOGI */ 200862306a36Sopenharmony_ci while (!ctlr->sel_fcf) { 200962306a36Sopenharmony_ci msleep(250); 201062306a36Sopenharmony_ci /* give up after 3 secs */ 201162306a36Sopenharmony_ci if (++wait_cnt > 12) 201262306a36Sopenharmony_ci break; 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci /* Reset max receive frame size to default */ 201662306a36Sopenharmony_ci if (fc_set_mfs(lport, BNX2FC_MFS)) 201762306a36Sopenharmony_ci return; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci fc_lport_init(lport); 202062306a36Sopenharmony_ci fc_fabric_login(lport); 202162306a36Sopenharmony_ci} 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci/** 202562306a36Sopenharmony_ci * bnx2fc_ulp_init - Initialize an adapter instance 202662306a36Sopenharmony_ci * 202762306a36Sopenharmony_ci * @dev : cnic device handle 202862306a36Sopenharmony_ci * Called from cnic_register_driver() context to initialize all 202962306a36Sopenharmony_ci * enumerated cnic devices. This routine allocates adapter structure 203062306a36Sopenharmony_ci * and other device specific resources. 203162306a36Sopenharmony_ci */ 203262306a36Sopenharmony_cistatic void bnx2fc_ulp_init(struct cnic_dev *dev) 203362306a36Sopenharmony_ci{ 203462306a36Sopenharmony_ci struct bnx2fc_hba *hba; 203562306a36Sopenharmony_ci int rc = 0; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci BNX2FC_MISC_DBG("Entered %s\n", __func__); 203862306a36Sopenharmony_ci /* bnx2fc works only when bnx2x is loaded */ 203962306a36Sopenharmony_ci if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) || 204062306a36Sopenharmony_ci (dev->max_fcoe_conn == 0)) { 204162306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc FCoE not supported on %s," 204262306a36Sopenharmony_ci " flags: %lx fcoe_conn: %d\n", 204362306a36Sopenharmony_ci dev->netdev->name, dev->flags, dev->max_fcoe_conn); 204462306a36Sopenharmony_ci return; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci hba = bnx2fc_hba_create(dev); 204862306a36Sopenharmony_ci if (!hba) { 204962306a36Sopenharmony_ci printk(KERN_ERR PFX "hba initialization failed\n"); 205062306a36Sopenharmony_ci return; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci pr_info(PFX "FCoE initialized for %s.\n", dev->netdev->name); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci /* Add HBA to the adapter list */ 205662306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 205762306a36Sopenharmony_ci list_add_tail(&hba->list, &adapter_list); 205862306a36Sopenharmony_ci adapter_count++; 205962306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci dev->fcoe_cap = &hba->fcoe_cap; 206262306a36Sopenharmony_ci clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic); 206362306a36Sopenharmony_ci rc = dev->register_device(dev, CNIC_ULP_FCOE, 206462306a36Sopenharmony_ci (void *) hba); 206562306a36Sopenharmony_ci if (rc) 206662306a36Sopenharmony_ci printk(KERN_ERR PFX "register_device failed, rc = %d\n", rc); 206762306a36Sopenharmony_ci else 206862306a36Sopenharmony_ci set_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic); 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci/* Assumes rtnl_lock and the bnx2fc_dev_lock are already taken */ 207262306a36Sopenharmony_cistatic int __bnx2fc_disable(struct fcoe_ctlr *ctlr) 207362306a36Sopenharmony_ci{ 207462306a36Sopenharmony_ci struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci if (interface->enabled) { 207762306a36Sopenharmony_ci if (!ctlr->lp) { 207862306a36Sopenharmony_ci pr_err(PFX "__bnx2fc_disable: lport not found\n"); 207962306a36Sopenharmony_ci return -ENODEV; 208062306a36Sopenharmony_ci } else { 208162306a36Sopenharmony_ci interface->enabled = false; 208262306a36Sopenharmony_ci fcoe_ctlr_link_down(ctlr); 208362306a36Sopenharmony_ci fcoe_clean_pending_queue(ctlr->lp); 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci return 0; 208762306a36Sopenharmony_ci} 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci/* 209062306a36Sopenharmony_ci * Deperecated: Use bnx2fc_enabled() 209162306a36Sopenharmony_ci */ 209262306a36Sopenharmony_cistatic int bnx2fc_disable(struct net_device *netdev) 209362306a36Sopenharmony_ci{ 209462306a36Sopenharmony_ci struct bnx2fc_interface *interface; 209562306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 209662306a36Sopenharmony_ci int rc = 0; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci rtnl_lock(); 209962306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci interface = bnx2fc_interface_lookup(netdev); 210262306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci if (!interface) { 210562306a36Sopenharmony_ci rc = -ENODEV; 210662306a36Sopenharmony_ci pr_err(PFX "bnx2fc_disable: interface not found\n"); 210762306a36Sopenharmony_ci } else { 210862306a36Sopenharmony_ci rc = __bnx2fc_disable(ctlr); 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 211162306a36Sopenharmony_ci rtnl_unlock(); 211262306a36Sopenharmony_ci return rc; 211362306a36Sopenharmony_ci} 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_cistatic uint bnx2fc_npiv_create_vports(struct fc_lport *lport, 211662306a36Sopenharmony_ci struct cnic_fc_npiv_tbl *npiv_tbl) 211762306a36Sopenharmony_ci{ 211862306a36Sopenharmony_ci struct fc_vport_identifiers vpid; 211962306a36Sopenharmony_ci uint i, created = 0; 212062306a36Sopenharmony_ci u64 wwnn = 0; 212162306a36Sopenharmony_ci char wwpn_str[32]; 212262306a36Sopenharmony_ci char wwnn_str[32]; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci if (npiv_tbl->count > MAX_NPIV_ENTRIES) { 212562306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Exceeded count max of npiv table\n"); 212662306a36Sopenharmony_ci goto done; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci /* Sanity check the first entry to make sure it's not 0 */ 213062306a36Sopenharmony_ci if (wwn_to_u64(npiv_tbl->wwnn[0]) == 0 && 213162306a36Sopenharmony_ci wwn_to_u64(npiv_tbl->wwpn[0]) == 0) { 213262306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "First NPIV table entries invalid.\n"); 213362306a36Sopenharmony_ci goto done; 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci vpid.roles = FC_PORT_ROLE_FCP_INITIATOR; 213762306a36Sopenharmony_ci vpid.vport_type = FC_PORTTYPE_NPIV; 213862306a36Sopenharmony_ci vpid.disable = false; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci for (i = 0; i < npiv_tbl->count; i++) { 214162306a36Sopenharmony_ci wwnn = wwn_to_u64(npiv_tbl->wwnn[i]); 214262306a36Sopenharmony_ci if (wwnn == 0) { 214362306a36Sopenharmony_ci /* 214462306a36Sopenharmony_ci * If we get a 0 element from for the WWNN then assume 214562306a36Sopenharmony_ci * the WWNN should be the same as the physical port. 214662306a36Sopenharmony_ci */ 214762306a36Sopenharmony_ci wwnn = lport->wwnn; 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci vpid.node_name = wwnn; 215062306a36Sopenharmony_ci vpid.port_name = wwn_to_u64(npiv_tbl->wwpn[i]); 215162306a36Sopenharmony_ci scnprintf(vpid.symbolic_name, sizeof(vpid.symbolic_name), 215262306a36Sopenharmony_ci "NPIV[%u]:%016llx-%016llx", 215362306a36Sopenharmony_ci created, vpid.port_name, vpid.node_name); 215462306a36Sopenharmony_ci fcoe_wwn_to_str(vpid.node_name, wwnn_str, sizeof(wwnn_str)); 215562306a36Sopenharmony_ci fcoe_wwn_to_str(vpid.port_name, wwpn_str, sizeof(wwpn_str)); 215662306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Creating vport %s:%s.\n", wwnn_str, 215762306a36Sopenharmony_ci wwpn_str); 215862306a36Sopenharmony_ci if (fc_vport_create(lport->host, 0, &vpid)) 215962306a36Sopenharmony_ci created++; 216062306a36Sopenharmony_ci else 216162306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "Failed to create vport\n"); 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_cidone: 216462306a36Sopenharmony_ci return created; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_cistatic int __bnx2fc_enable(struct fcoe_ctlr *ctlr) 216862306a36Sopenharmony_ci{ 216962306a36Sopenharmony_ci struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); 217062306a36Sopenharmony_ci struct bnx2fc_hba *hba; 217162306a36Sopenharmony_ci struct cnic_fc_npiv_tbl *npiv_tbl; 217262306a36Sopenharmony_ci struct fc_lport *lport; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci if (!interface->enabled) { 217562306a36Sopenharmony_ci if (!ctlr->lp) { 217662306a36Sopenharmony_ci pr_err(PFX "__bnx2fc_enable: lport not found\n"); 217762306a36Sopenharmony_ci return -ENODEV; 217862306a36Sopenharmony_ci } else if (!bnx2fc_link_ok(ctlr->lp)) { 217962306a36Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 218062306a36Sopenharmony_ci interface->enabled = true; 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci /* Create static NPIV ports if any are contained in NVRAM */ 218562306a36Sopenharmony_ci hba = interface->hba; 218662306a36Sopenharmony_ci lport = ctlr->lp; 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci if (!hba) 218962306a36Sopenharmony_ci goto done; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci if (!hba->cnic) 219262306a36Sopenharmony_ci goto done; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci if (!lport) 219562306a36Sopenharmony_ci goto done; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci if (!lport->host) 219862306a36Sopenharmony_ci goto done; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (!hba->cnic->get_fc_npiv_tbl) 220162306a36Sopenharmony_ci goto done; 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci npiv_tbl = kzalloc(sizeof(struct cnic_fc_npiv_tbl), GFP_KERNEL); 220462306a36Sopenharmony_ci if (!npiv_tbl) 220562306a36Sopenharmony_ci goto done; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci if (hba->cnic->get_fc_npiv_tbl(hba->cnic, npiv_tbl)) 220862306a36Sopenharmony_ci goto done_free; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci bnx2fc_npiv_create_vports(lport, npiv_tbl); 221162306a36Sopenharmony_cidone_free: 221262306a36Sopenharmony_ci kfree(npiv_tbl); 221362306a36Sopenharmony_cidone: 221462306a36Sopenharmony_ci return 0; 221562306a36Sopenharmony_ci} 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci/* 221862306a36Sopenharmony_ci * Deprecated: Use bnx2fc_enabled() 221962306a36Sopenharmony_ci */ 222062306a36Sopenharmony_cistatic int bnx2fc_enable(struct net_device *netdev) 222162306a36Sopenharmony_ci{ 222262306a36Sopenharmony_ci struct bnx2fc_interface *interface; 222362306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 222462306a36Sopenharmony_ci int rc = 0; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci rtnl_lock(); 222762306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci interface = bnx2fc_interface_lookup(netdev); 223062306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 223162306a36Sopenharmony_ci if (!interface) { 223262306a36Sopenharmony_ci rc = -ENODEV; 223362306a36Sopenharmony_ci pr_err(PFX "bnx2fc_enable: interface not found\n"); 223462306a36Sopenharmony_ci } else { 223562306a36Sopenharmony_ci rc = __bnx2fc_enable(ctlr); 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 223962306a36Sopenharmony_ci rtnl_unlock(); 224062306a36Sopenharmony_ci return rc; 224162306a36Sopenharmony_ci} 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci/** 224462306a36Sopenharmony_ci * bnx2fc_ctlr_enabled() - Enable or disable an FCoE Controller 224562306a36Sopenharmony_ci * @cdev: The FCoE Controller that is being enabled or disabled 224662306a36Sopenharmony_ci * 224762306a36Sopenharmony_ci * fcoe_sysfs will ensure that the state of 'enabled' has 224862306a36Sopenharmony_ci * changed, so no checking is necessary here. This routine simply 224962306a36Sopenharmony_ci * calls fcoe_enable or fcoe_disable, both of which are deprecated. 225062306a36Sopenharmony_ci * When those routines are removed the functionality can be merged 225162306a36Sopenharmony_ci * here. 225262306a36Sopenharmony_ci */ 225362306a36Sopenharmony_cistatic int bnx2fc_ctlr_enabled(struct fcoe_ctlr_device *cdev) 225462306a36Sopenharmony_ci{ 225562306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(cdev); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci switch (cdev->enabled) { 225862306a36Sopenharmony_ci case FCOE_CTLR_ENABLED: 225962306a36Sopenharmony_ci return __bnx2fc_enable(ctlr); 226062306a36Sopenharmony_ci case FCOE_CTLR_DISABLED: 226162306a36Sopenharmony_ci return __bnx2fc_disable(ctlr); 226262306a36Sopenharmony_ci case FCOE_CTLR_UNUSED: 226362306a36Sopenharmony_ci default: 226462306a36Sopenharmony_ci return -ENOTSUPP; 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci} 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_cienum bnx2fc_create_link_state { 226962306a36Sopenharmony_ci BNX2FC_CREATE_LINK_DOWN, 227062306a36Sopenharmony_ci BNX2FC_CREATE_LINK_UP, 227162306a36Sopenharmony_ci}; 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci/** 227462306a36Sopenharmony_ci * _bnx2fc_create() - Create bnx2fc FCoE interface 227562306a36Sopenharmony_ci * @netdev : The net_device object the Ethernet interface to create on 227662306a36Sopenharmony_ci * @fip_mode: The FIP mode for this creation 227762306a36Sopenharmony_ci * @link_state: The ctlr link state on creation 227862306a36Sopenharmony_ci * 227962306a36Sopenharmony_ci * Called from either the libfcoe 'create' module parameter 228062306a36Sopenharmony_ci * via fcoe_create or from fcoe_syfs's ctlr_create file. 228162306a36Sopenharmony_ci * 228262306a36Sopenharmony_ci * libfcoe's 'create' module parameter is deprecated so some 228362306a36Sopenharmony_ci * consolidation of code can be done when that interface is 228462306a36Sopenharmony_ci * removed. 228562306a36Sopenharmony_ci * 228662306a36Sopenharmony_ci * Returns: 0 for success 228762306a36Sopenharmony_ci */ 228862306a36Sopenharmony_cistatic int _bnx2fc_create(struct net_device *netdev, 228962306a36Sopenharmony_ci enum fip_mode fip_mode, 229062306a36Sopenharmony_ci enum bnx2fc_create_link_state link_state) 229162306a36Sopenharmony_ci{ 229262306a36Sopenharmony_ci struct fcoe_ctlr_device *cdev; 229362306a36Sopenharmony_ci struct fcoe_ctlr *ctlr; 229462306a36Sopenharmony_ci struct bnx2fc_interface *interface; 229562306a36Sopenharmony_ci struct bnx2fc_hba *hba; 229662306a36Sopenharmony_ci struct net_device *phys_dev = netdev; 229762306a36Sopenharmony_ci struct fc_lport *lport; 229862306a36Sopenharmony_ci struct ethtool_drvinfo drvinfo; 229962306a36Sopenharmony_ci int rc = 0; 230062306a36Sopenharmony_ci int vlan_id = 0; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci BNX2FC_MISC_DBG("Entered bnx2fc_create\n"); 230362306a36Sopenharmony_ci if (fip_mode != FIP_MODE_FABRIC) { 230462306a36Sopenharmony_ci printk(KERN_ERR "fip mode not FABRIC\n"); 230562306a36Sopenharmony_ci return -EIO; 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci rtnl_lock(); 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci if (!try_module_get(THIS_MODULE)) { 231362306a36Sopenharmony_ci rc = -EINVAL; 231462306a36Sopenharmony_ci goto mod_err; 231562306a36Sopenharmony_ci } 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci /* obtain physical netdev */ 231862306a36Sopenharmony_ci if (is_vlan_dev(netdev)) 231962306a36Sopenharmony_ci phys_dev = vlan_dev_real_dev(netdev); 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci /* verify if the physical device is a netxtreme2 device */ 232262306a36Sopenharmony_ci if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) { 232362306a36Sopenharmony_ci memset(&drvinfo, 0, sizeof(drvinfo)); 232462306a36Sopenharmony_ci phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo); 232562306a36Sopenharmony_ci if (strncmp(drvinfo.driver, "bnx2x", strlen("bnx2x"))) { 232662306a36Sopenharmony_ci printk(KERN_ERR PFX "Not a netxtreme2 device\n"); 232762306a36Sopenharmony_ci rc = -EINVAL; 232862306a36Sopenharmony_ci goto netdev_err; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci } else { 233162306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to obtain drv_info\n"); 233262306a36Sopenharmony_ci rc = -EINVAL; 233362306a36Sopenharmony_ci goto netdev_err; 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci /* obtain interface and initialize rest of the structure */ 233762306a36Sopenharmony_ci hba = bnx2fc_hba_lookup(phys_dev); 233862306a36Sopenharmony_ci if (!hba) { 233962306a36Sopenharmony_ci rc = -ENODEV; 234062306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_create: hba not found\n"); 234162306a36Sopenharmony_ci goto netdev_err; 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci if (bnx2fc_interface_lookup(netdev)) { 234562306a36Sopenharmony_ci rc = -EEXIST; 234662306a36Sopenharmony_ci goto netdev_err; 234762306a36Sopenharmony_ci } 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci interface = bnx2fc_interface_create(hba, netdev, fip_mode); 235062306a36Sopenharmony_ci if (!interface) { 235162306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_interface_create failed\n"); 235262306a36Sopenharmony_ci rc = -ENOMEM; 235362306a36Sopenharmony_ci goto netdev_err; 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci if (is_vlan_dev(netdev)) { 235762306a36Sopenharmony_ci vlan_id = vlan_dev_vlan_id(netdev); 235862306a36Sopenharmony_ci interface->vlan_enabled = 1; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci ctlr = bnx2fc_to_ctlr(interface); 236262306a36Sopenharmony_ci cdev = fcoe_ctlr_to_ctlr_dev(ctlr); 236362306a36Sopenharmony_ci interface->vlan_id = vlan_id; 236462306a36Sopenharmony_ci interface->tm_timeout = BNX2FC_TM_TIMEOUT; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci interface->timer_work_queue = 236762306a36Sopenharmony_ci create_singlethread_workqueue("bnx2fc_timer_wq"); 236862306a36Sopenharmony_ci if (!interface->timer_work_queue) { 236962306a36Sopenharmony_ci printk(KERN_ERR PFX "ulp_init could not create timer_wq\n"); 237062306a36Sopenharmony_ci rc = -EINVAL; 237162306a36Sopenharmony_ci goto ifput_err; 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci lport = bnx2fc_if_create(interface, &cdev->dev, 0); 237562306a36Sopenharmony_ci if (!lport) { 237662306a36Sopenharmony_ci printk(KERN_ERR PFX "Failed to create interface (%s)\n", 237762306a36Sopenharmony_ci netdev->name); 237862306a36Sopenharmony_ci rc = -EINVAL; 237962306a36Sopenharmony_ci goto if_create_err; 238062306a36Sopenharmony_ci } 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci /* Add interface to if_list */ 238362306a36Sopenharmony_ci list_add_tail(&interface->list, &if_list); 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci lport->boot_time = jiffies; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci /* Make this master N_port */ 238862306a36Sopenharmony_ci ctlr->lp = lport; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci if (link_state == BNX2FC_CREATE_LINK_UP) 239162306a36Sopenharmony_ci cdev->enabled = FCOE_CTLR_ENABLED; 239262306a36Sopenharmony_ci else 239362306a36Sopenharmony_ci cdev->enabled = FCOE_CTLR_DISABLED; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci if (link_state == BNX2FC_CREATE_LINK_UP && 239662306a36Sopenharmony_ci !bnx2fc_link_ok(lport)) { 239762306a36Sopenharmony_ci fcoe_ctlr_link_up(ctlr); 239862306a36Sopenharmony_ci fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; 239962306a36Sopenharmony_ci set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); 240062306a36Sopenharmony_ci } 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "create: START DISC\n"); 240362306a36Sopenharmony_ci bnx2fc_start_disc(interface); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci if (link_state == BNX2FC_CREATE_LINK_UP) 240662306a36Sopenharmony_ci interface->enabled = true; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci /* 240962306a36Sopenharmony_ci * Release from kref_init in bnx2fc_interface_setup, on success 241062306a36Sopenharmony_ci * lport should be holding a reference taken in bnx2fc_if_create 241162306a36Sopenharmony_ci */ 241262306a36Sopenharmony_ci bnx2fc_interface_put(interface); 241362306a36Sopenharmony_ci /* put netdev that was held while calling dev_get_by_name */ 241462306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 241562306a36Sopenharmony_ci rtnl_unlock(); 241662306a36Sopenharmony_ci return 0; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ciif_create_err: 241962306a36Sopenharmony_ci destroy_workqueue(interface->timer_work_queue); 242062306a36Sopenharmony_ciifput_err: 242162306a36Sopenharmony_ci bnx2fc_net_cleanup(interface); 242262306a36Sopenharmony_ci bnx2fc_interface_put(interface); 242362306a36Sopenharmony_ci goto mod_err; 242462306a36Sopenharmony_cinetdev_err: 242562306a36Sopenharmony_ci module_put(THIS_MODULE); 242662306a36Sopenharmony_cimod_err: 242762306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 242862306a36Sopenharmony_ci rtnl_unlock(); 242962306a36Sopenharmony_ci return rc; 243062306a36Sopenharmony_ci} 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci/** 243362306a36Sopenharmony_ci * bnx2fc_create() - Create a bnx2fc interface 243462306a36Sopenharmony_ci * @netdev : The net_device object the Ethernet interface to create on 243562306a36Sopenharmony_ci * @fip_mode: The FIP mode for this creation 243662306a36Sopenharmony_ci * 243762306a36Sopenharmony_ci * Called from fcoe transport 243862306a36Sopenharmony_ci * 243962306a36Sopenharmony_ci * Returns: 0 for success 244062306a36Sopenharmony_ci */ 244162306a36Sopenharmony_cistatic int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode) 244262306a36Sopenharmony_ci{ 244362306a36Sopenharmony_ci return _bnx2fc_create(netdev, fip_mode, BNX2FC_CREATE_LINK_UP); 244462306a36Sopenharmony_ci} 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci/** 244762306a36Sopenharmony_ci * bnx2fc_ctlr_alloc() - Allocate a bnx2fc interface from fcoe_sysfs 244862306a36Sopenharmony_ci * @netdev: The net_device to be used by the allocated FCoE Controller 244962306a36Sopenharmony_ci * 245062306a36Sopenharmony_ci * This routine is called from fcoe_sysfs. It will start the fcoe_ctlr 245162306a36Sopenharmony_ci * in a link_down state. The allows the user an opportunity to configure 245262306a36Sopenharmony_ci * the FCoE Controller from sysfs before enabling the FCoE Controller. 245362306a36Sopenharmony_ci * 245462306a36Sopenharmony_ci * Creating in with this routine starts the FCoE Controller in Fabric 245562306a36Sopenharmony_ci * mode. The user can change to VN2VN or another mode before enabling. 245662306a36Sopenharmony_ci */ 245762306a36Sopenharmony_cistatic int bnx2fc_ctlr_alloc(struct net_device *netdev) 245862306a36Sopenharmony_ci{ 245962306a36Sopenharmony_ci return _bnx2fc_create(netdev, FIP_MODE_FABRIC, 246062306a36Sopenharmony_ci BNX2FC_CREATE_LINK_DOWN); 246162306a36Sopenharmony_ci} 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci/** 246462306a36Sopenharmony_ci * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc hba instance 246562306a36Sopenharmony_ci * 246662306a36Sopenharmony_ci * @cnic: Pointer to cnic device instance 246762306a36Sopenharmony_ci * 246862306a36Sopenharmony_ci **/ 246962306a36Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic) 247062306a36Sopenharmony_ci{ 247162306a36Sopenharmony_ci struct bnx2fc_hba *hba; 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci /* Called with bnx2fc_dev_lock held */ 247462306a36Sopenharmony_ci list_for_each_entry(hba, &adapter_list, list) { 247562306a36Sopenharmony_ci if (hba->cnic == cnic) 247662306a36Sopenharmony_ci return hba; 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci return NULL; 247962306a36Sopenharmony_ci} 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_cistatic struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device 248262306a36Sopenharmony_ci *netdev) 248362306a36Sopenharmony_ci{ 248462306a36Sopenharmony_ci struct bnx2fc_interface *interface; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci /* Called with bnx2fc_dev_lock held */ 248762306a36Sopenharmony_ci list_for_each_entry(interface, &if_list, list) { 248862306a36Sopenharmony_ci if (interface->netdev == netdev) 248962306a36Sopenharmony_ci return interface; 249062306a36Sopenharmony_ci } 249162306a36Sopenharmony_ci return NULL; 249262306a36Sopenharmony_ci} 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_cistatic struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device 249562306a36Sopenharmony_ci *phys_dev) 249662306a36Sopenharmony_ci{ 249762306a36Sopenharmony_ci struct bnx2fc_hba *hba; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci /* Called with bnx2fc_dev_lock held */ 250062306a36Sopenharmony_ci list_for_each_entry(hba, &adapter_list, list) { 250162306a36Sopenharmony_ci if (hba->phys_dev == phys_dev) 250262306a36Sopenharmony_ci return hba; 250362306a36Sopenharmony_ci } 250462306a36Sopenharmony_ci printk(KERN_ERR PFX "adapter_lookup: hba NULL\n"); 250562306a36Sopenharmony_ci return NULL; 250662306a36Sopenharmony_ci} 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci/** 250962306a36Sopenharmony_ci * bnx2fc_ulp_exit - shuts down adapter instance and frees all resources 251062306a36Sopenharmony_ci * 251162306a36Sopenharmony_ci * @dev: cnic device handle 251262306a36Sopenharmony_ci */ 251362306a36Sopenharmony_cistatic void bnx2fc_ulp_exit(struct cnic_dev *dev) 251462306a36Sopenharmony_ci{ 251562306a36Sopenharmony_ci struct bnx2fc_hba *hba; 251662306a36Sopenharmony_ci struct bnx2fc_interface *interface, *tmp; 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n"); 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { 252162306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc port check: %s, flags: %lx\n", 252262306a36Sopenharmony_ci dev->netdev->name, dev->flags); 252362306a36Sopenharmony_ci return; 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 252762306a36Sopenharmony_ci hba = bnx2fc_find_hba_for_cnic(dev); 252862306a36Sopenharmony_ci if (!hba) { 252962306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc_ulp_exit: hba not found, dev 0%p\n", 253062306a36Sopenharmony_ci dev); 253162306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 253262306a36Sopenharmony_ci return; 253362306a36Sopenharmony_ci } 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci list_del_init(&hba->list); 253662306a36Sopenharmony_ci adapter_count--; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci list_for_each_entry_safe(interface, tmp, &if_list, list) 253962306a36Sopenharmony_ci /* destroy not called yet, move to quiesced list */ 254062306a36Sopenharmony_ci if (interface->hba == hba) 254162306a36Sopenharmony_ci __bnx2fc_destroy(interface); 254262306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci bnx2fc_ulp_stop(hba); 254562306a36Sopenharmony_ci /* unregister cnic device */ 254662306a36Sopenharmony_ci if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic)) 254762306a36Sopenharmony_ci hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE); 254862306a36Sopenharmony_ci bnx2fc_hba_destroy(hba); 254962306a36Sopenharmony_ci} 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_cistatic void bnx2fc_rport_terminate_io(struct fc_rport *rport) 255262306a36Sopenharmony_ci{ 255362306a36Sopenharmony_ci /* This is a no-op */ 255462306a36Sopenharmony_ci} 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci/** 255762306a36Sopenharmony_ci * bnx2fc_fcoe_reset - Resets the fcoe 255862306a36Sopenharmony_ci * 255962306a36Sopenharmony_ci * @shost: shost the reset is from 256062306a36Sopenharmony_ci * 256162306a36Sopenharmony_ci * Returns: always 0 256262306a36Sopenharmony_ci */ 256362306a36Sopenharmony_cistatic int bnx2fc_fcoe_reset(struct Scsi_Host *shost) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 256662306a36Sopenharmony_ci fc_lport_reset(lport); 256762306a36Sopenharmony_ci return 0; 256862306a36Sopenharmony_ci} 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_cistatic bool bnx2fc_match(struct net_device *netdev) 257262306a36Sopenharmony_ci{ 257362306a36Sopenharmony_ci struct net_device *phys_dev = netdev; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 257662306a36Sopenharmony_ci if (is_vlan_dev(netdev)) 257762306a36Sopenharmony_ci phys_dev = vlan_dev_real_dev(netdev); 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci if (bnx2fc_hba_lookup(phys_dev)) { 258062306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 258162306a36Sopenharmony_ci return true; 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 258562306a36Sopenharmony_ci return false; 258662306a36Sopenharmony_ci} 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_cistatic struct fcoe_transport bnx2fc_transport = { 259062306a36Sopenharmony_ci .name = {"bnx2fc"}, 259162306a36Sopenharmony_ci .attached = false, 259262306a36Sopenharmony_ci .list = LIST_HEAD_INIT(bnx2fc_transport.list), 259362306a36Sopenharmony_ci .alloc = bnx2fc_ctlr_alloc, 259462306a36Sopenharmony_ci .match = bnx2fc_match, 259562306a36Sopenharmony_ci .create = bnx2fc_create, 259662306a36Sopenharmony_ci .destroy = bnx2fc_destroy, 259762306a36Sopenharmony_ci .enable = bnx2fc_enable, 259862306a36Sopenharmony_ci .disable = bnx2fc_disable, 259962306a36Sopenharmony_ci}; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci/** 260262306a36Sopenharmony_ci * bnx2fc_cpu_online - Create a receive thread for an online CPU 260362306a36Sopenharmony_ci * 260462306a36Sopenharmony_ci * @cpu: cpu index for the online cpu 260562306a36Sopenharmony_ci */ 260662306a36Sopenharmony_cistatic int bnx2fc_cpu_online(unsigned int cpu) 260762306a36Sopenharmony_ci{ 260862306a36Sopenharmony_ci struct bnx2fc_percpu_s *p; 260962306a36Sopenharmony_ci struct task_struct *thread; 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci p = &per_cpu(bnx2fc_percpu, cpu); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci thread = kthread_create_on_node(bnx2fc_percpu_io_thread, 261462306a36Sopenharmony_ci (void *)p, cpu_to_node(cpu), 261562306a36Sopenharmony_ci "bnx2fc_thread/%d", cpu); 261662306a36Sopenharmony_ci if (IS_ERR(thread)) 261762306a36Sopenharmony_ci return PTR_ERR(thread); 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci /* bind thread to the cpu */ 262062306a36Sopenharmony_ci kthread_bind(thread, cpu); 262162306a36Sopenharmony_ci p->iothread = thread; 262262306a36Sopenharmony_ci wake_up_process(thread); 262362306a36Sopenharmony_ci return 0; 262462306a36Sopenharmony_ci} 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_cistatic int bnx2fc_cpu_offline(unsigned int cpu) 262762306a36Sopenharmony_ci{ 262862306a36Sopenharmony_ci struct bnx2fc_percpu_s *p; 262962306a36Sopenharmony_ci struct task_struct *thread; 263062306a36Sopenharmony_ci struct bnx2fc_work *work, *tmp; 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci BNX2FC_MISC_DBG("destroying io thread for CPU %d\n", cpu); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci /* Prevent any new work from being queued for this CPU */ 263562306a36Sopenharmony_ci p = &per_cpu(bnx2fc_percpu, cpu); 263662306a36Sopenharmony_ci spin_lock_bh(&p->fp_work_lock); 263762306a36Sopenharmony_ci thread = p->iothread; 263862306a36Sopenharmony_ci p->iothread = NULL; 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci /* Free all work in the list */ 264162306a36Sopenharmony_ci list_for_each_entry_safe(work, tmp, &p->work_list, list) { 264262306a36Sopenharmony_ci list_del_init(&work->list); 264362306a36Sopenharmony_ci bnx2fc_process_cq_compl(work->tgt, work->wqe, work->rq_data, 264462306a36Sopenharmony_ci work->num_rq, work->task); 264562306a36Sopenharmony_ci kfree(work); 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci spin_unlock_bh(&p->fp_work_lock); 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci if (thread) 265162306a36Sopenharmony_ci kthread_stop(thread); 265262306a36Sopenharmony_ci return 0; 265362306a36Sopenharmony_ci} 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_cistatic int bnx2fc_slave_configure(struct scsi_device *sdev) 265662306a36Sopenharmony_ci{ 265762306a36Sopenharmony_ci if (!bnx2fc_queue_depth) 265862306a36Sopenharmony_ci return 0; 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci scsi_change_queue_depth(sdev, bnx2fc_queue_depth); 266162306a36Sopenharmony_ci return 0; 266262306a36Sopenharmony_ci} 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_cistatic enum cpuhp_state bnx2fc_online_state; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci/** 266762306a36Sopenharmony_ci * bnx2fc_mod_init - module init entry point 266862306a36Sopenharmony_ci * 266962306a36Sopenharmony_ci * Initialize driver wide global data structures, and register 267062306a36Sopenharmony_ci * with cnic module 267162306a36Sopenharmony_ci **/ 267262306a36Sopenharmony_cistatic int __init bnx2fc_mod_init(void) 267362306a36Sopenharmony_ci{ 267462306a36Sopenharmony_ci struct fcoe_percpu_s *bg; 267562306a36Sopenharmony_ci struct task_struct *l2_thread; 267662306a36Sopenharmony_ci int rc = 0; 267762306a36Sopenharmony_ci unsigned int cpu = 0; 267862306a36Sopenharmony_ci struct bnx2fc_percpu_s *p; 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci printk(KERN_INFO PFX "%s", version); 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci /* register as a fcoe transport */ 268362306a36Sopenharmony_ci rc = fcoe_transport_attach(&bnx2fc_transport); 268462306a36Sopenharmony_ci if (rc) { 268562306a36Sopenharmony_ci printk(KERN_ERR "failed to register an fcoe transport, check " 268662306a36Sopenharmony_ci "if libfcoe is loaded\n"); 268762306a36Sopenharmony_ci goto out; 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter_list); 269162306a36Sopenharmony_ci INIT_LIST_HEAD(&if_list); 269262306a36Sopenharmony_ci mutex_init(&bnx2fc_dev_lock); 269362306a36Sopenharmony_ci adapter_count = 0; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci /* Attach FC transport template */ 269662306a36Sopenharmony_ci rc = bnx2fc_attach_transport(); 269762306a36Sopenharmony_ci if (rc) 269862306a36Sopenharmony_ci goto detach_ft; 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci bnx2fc_wq = alloc_workqueue("bnx2fc", 0, 0); 270162306a36Sopenharmony_ci if (!bnx2fc_wq) { 270262306a36Sopenharmony_ci rc = -ENOMEM; 270362306a36Sopenharmony_ci goto release_bt; 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci bg = &bnx2fc_global; 270762306a36Sopenharmony_ci skb_queue_head_init(&bg->fcoe_rx_list); 270862306a36Sopenharmony_ci l2_thread = kthread_run(bnx2fc_l2_rcv_thread, 270962306a36Sopenharmony_ci (void *)bg, 271062306a36Sopenharmony_ci "bnx2fc_l2_thread"); 271162306a36Sopenharmony_ci if (IS_ERR(l2_thread)) { 271262306a36Sopenharmony_ci rc = PTR_ERR(l2_thread); 271362306a36Sopenharmony_ci goto free_wq; 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 271662306a36Sopenharmony_ci bg->kthread = l2_thread; 271762306a36Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 272062306a36Sopenharmony_ci p = &per_cpu(bnx2fc_percpu, cpu); 272162306a36Sopenharmony_ci INIT_LIST_HEAD(&p->work_list); 272262306a36Sopenharmony_ci spin_lock_init(&p->fp_work_lock); 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/bnx2fc:online", 272662306a36Sopenharmony_ci bnx2fc_cpu_online, bnx2fc_cpu_offline); 272762306a36Sopenharmony_ci if (rc < 0) 272862306a36Sopenharmony_ci goto stop_thread; 272962306a36Sopenharmony_ci bnx2fc_online_state = rc; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci cnic_register_driver(CNIC_ULP_FCOE, &bnx2fc_cnic_cb); 273262306a36Sopenharmony_ci return 0; 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_cistop_thread: 273562306a36Sopenharmony_ci kthread_stop(l2_thread); 273662306a36Sopenharmony_cifree_wq: 273762306a36Sopenharmony_ci destroy_workqueue(bnx2fc_wq); 273862306a36Sopenharmony_cirelease_bt: 273962306a36Sopenharmony_ci bnx2fc_release_transport(); 274062306a36Sopenharmony_cidetach_ft: 274162306a36Sopenharmony_ci fcoe_transport_detach(&bnx2fc_transport); 274262306a36Sopenharmony_ciout: 274362306a36Sopenharmony_ci return rc; 274462306a36Sopenharmony_ci} 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_cistatic void __exit bnx2fc_mod_exit(void) 274762306a36Sopenharmony_ci{ 274862306a36Sopenharmony_ci LIST_HEAD(to_be_deleted); 274962306a36Sopenharmony_ci struct bnx2fc_hba *hba, *next; 275062306a36Sopenharmony_ci struct fcoe_percpu_s *bg; 275162306a36Sopenharmony_ci struct task_struct *l2_thread; 275262306a36Sopenharmony_ci struct sk_buff *skb; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci /* 275562306a36Sopenharmony_ci * NOTE: Since cnic calls register_driver routine rtnl_lock, 275662306a36Sopenharmony_ci * it will have higher precedence than bnx2fc_dev_lock. 275762306a36Sopenharmony_ci * unregister_device() cannot be called with bnx2fc_dev_lock 275862306a36Sopenharmony_ci * held. 275962306a36Sopenharmony_ci */ 276062306a36Sopenharmony_ci mutex_lock(&bnx2fc_dev_lock); 276162306a36Sopenharmony_ci list_splice_init(&adapter_list, &to_be_deleted); 276262306a36Sopenharmony_ci adapter_count = 0; 276362306a36Sopenharmony_ci mutex_unlock(&bnx2fc_dev_lock); 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci /* Unregister with cnic */ 276662306a36Sopenharmony_ci list_for_each_entry_safe(hba, next, &to_be_deleted, list) { 276762306a36Sopenharmony_ci list_del_init(&hba->list); 276862306a36Sopenharmony_ci printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p\n", 276962306a36Sopenharmony_ci hba); 277062306a36Sopenharmony_ci bnx2fc_ulp_stop(hba); 277162306a36Sopenharmony_ci /* unregister cnic device */ 277262306a36Sopenharmony_ci if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, 277362306a36Sopenharmony_ci &hba->reg_with_cnic)) 277462306a36Sopenharmony_ci hba->cnic->unregister_device(hba->cnic, 277562306a36Sopenharmony_ci CNIC_ULP_FCOE); 277662306a36Sopenharmony_ci bnx2fc_hba_destroy(hba); 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci cnic_unregister_driver(CNIC_ULP_FCOE); 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci /* Destroy global thread */ 278162306a36Sopenharmony_ci bg = &bnx2fc_global; 278262306a36Sopenharmony_ci spin_lock_bh(&bg->fcoe_rx_list.lock); 278362306a36Sopenharmony_ci l2_thread = bg->kthread; 278462306a36Sopenharmony_ci bg->kthread = NULL; 278562306a36Sopenharmony_ci while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) 278662306a36Sopenharmony_ci kfree_skb(skb); 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci spin_unlock_bh(&bg->fcoe_rx_list.lock); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci if (l2_thread) 279162306a36Sopenharmony_ci kthread_stop(l2_thread); 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci cpuhp_remove_state(bnx2fc_online_state); 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci destroy_workqueue(bnx2fc_wq); 279662306a36Sopenharmony_ci /* 279762306a36Sopenharmony_ci * detach from scsi transport 279862306a36Sopenharmony_ci * must happen after all destroys are done 279962306a36Sopenharmony_ci */ 280062306a36Sopenharmony_ci bnx2fc_release_transport(); 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci /* detach from fcoe transport */ 280362306a36Sopenharmony_ci fcoe_transport_detach(&bnx2fc_transport); 280462306a36Sopenharmony_ci} 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_cimodule_init(bnx2fc_mod_init); 280762306a36Sopenharmony_cimodule_exit(bnx2fc_mod_exit); 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_cistatic struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = { 281062306a36Sopenharmony_ci .set_fcoe_ctlr_enabled = bnx2fc_ctlr_enabled, 281162306a36Sopenharmony_ci .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, 281262306a36Sopenharmony_ci .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, 281362306a36Sopenharmony_ci .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb, 281462306a36Sopenharmony_ci .get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb, 281562306a36Sopenharmony_ci .get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb, 281662306a36Sopenharmony_ci .get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb, 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci .get_fcoe_fcf_selected = fcoe_fcf_get_selected, 281962306a36Sopenharmony_ci .get_fcoe_fcf_vlan_id = bnx2fc_fcf_get_vlan_id, 282062306a36Sopenharmony_ci}; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_cistatic struct fc_function_template bnx2fc_transport_function = { 282362306a36Sopenharmony_ci .show_host_node_name = 1, 282462306a36Sopenharmony_ci .show_host_port_name = 1, 282562306a36Sopenharmony_ci .show_host_supported_classes = 1, 282662306a36Sopenharmony_ci .show_host_supported_fc4s = 1, 282762306a36Sopenharmony_ci .show_host_active_fc4s = 1, 282862306a36Sopenharmony_ci .show_host_maxframe_size = 1, 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci .show_host_port_id = 1, 283162306a36Sopenharmony_ci .show_host_supported_speeds = 1, 283262306a36Sopenharmony_ci .get_host_speed = fc_get_host_speed, 283362306a36Sopenharmony_ci .show_host_speed = 1, 283462306a36Sopenharmony_ci .show_host_port_type = 1, 283562306a36Sopenharmony_ci .get_host_port_state = fc_get_host_port_state, 283662306a36Sopenharmony_ci .show_host_port_state = 1, 283762306a36Sopenharmony_ci .show_host_symbolic_name = 1, 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) + 284062306a36Sopenharmony_ci sizeof(struct bnx2fc_rport)), 284162306a36Sopenharmony_ci .show_rport_maxframe_size = 1, 284262306a36Sopenharmony_ci .show_rport_supported_classes = 1, 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci .show_host_fabric_name = 1, 284562306a36Sopenharmony_ci .show_starget_node_name = 1, 284662306a36Sopenharmony_ci .show_starget_port_name = 1, 284762306a36Sopenharmony_ci .show_starget_port_id = 1, 284862306a36Sopenharmony_ci .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 284962306a36Sopenharmony_ci .show_rport_dev_loss_tmo = 1, 285062306a36Sopenharmony_ci .get_fc_host_stats = bnx2fc_get_host_stats, 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci .issue_fc_host_lip = bnx2fc_fcoe_reset, 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci .terminate_rport_io = bnx2fc_rport_terminate_io, 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci .vport_create = bnx2fc_vport_create, 285762306a36Sopenharmony_ci .vport_delete = bnx2fc_vport_destroy, 285862306a36Sopenharmony_ci .vport_disable = bnx2fc_vport_disable, 285962306a36Sopenharmony_ci .bsg_request = fc_lport_bsg_request, 286062306a36Sopenharmony_ci}; 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_cistatic struct fc_function_template bnx2fc_vport_xport_function = { 286362306a36Sopenharmony_ci .show_host_node_name = 1, 286462306a36Sopenharmony_ci .show_host_port_name = 1, 286562306a36Sopenharmony_ci .show_host_supported_classes = 1, 286662306a36Sopenharmony_ci .show_host_supported_fc4s = 1, 286762306a36Sopenharmony_ci .show_host_active_fc4s = 1, 286862306a36Sopenharmony_ci .show_host_maxframe_size = 1, 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci .show_host_port_id = 1, 287162306a36Sopenharmony_ci .show_host_supported_speeds = 1, 287262306a36Sopenharmony_ci .get_host_speed = fc_get_host_speed, 287362306a36Sopenharmony_ci .show_host_speed = 1, 287462306a36Sopenharmony_ci .show_host_port_type = 1, 287562306a36Sopenharmony_ci .get_host_port_state = fc_get_host_port_state, 287662306a36Sopenharmony_ci .show_host_port_state = 1, 287762306a36Sopenharmony_ci .show_host_symbolic_name = 1, 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) + 288062306a36Sopenharmony_ci sizeof(struct bnx2fc_rport)), 288162306a36Sopenharmony_ci .show_rport_maxframe_size = 1, 288262306a36Sopenharmony_ci .show_rport_supported_classes = 1, 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci .show_host_fabric_name = 1, 288562306a36Sopenharmony_ci .show_starget_node_name = 1, 288662306a36Sopenharmony_ci .show_starget_port_name = 1, 288762306a36Sopenharmony_ci .show_starget_port_id = 1, 288862306a36Sopenharmony_ci .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, 288962306a36Sopenharmony_ci .show_rport_dev_loss_tmo = 1, 289062306a36Sopenharmony_ci .get_fc_host_stats = fc_get_host_stats, 289162306a36Sopenharmony_ci .issue_fc_host_lip = bnx2fc_fcoe_reset, 289262306a36Sopenharmony_ci .terminate_rport_io = fc_rport_terminate_io, 289362306a36Sopenharmony_ci .bsg_request = fc_lport_bsg_request, 289462306a36Sopenharmony_ci}; 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci/* 289762306a36Sopenharmony_ci * Additional scsi_host attributes. 289862306a36Sopenharmony_ci */ 289962306a36Sopenharmony_cistatic ssize_t 290062306a36Sopenharmony_cibnx2fc_tm_timeout_show(struct device *dev, struct device_attribute *attr, 290162306a36Sopenharmony_ci char *buf) 290262306a36Sopenharmony_ci{ 290362306a36Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 290462306a36Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 290562306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 290662306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci sprintf(buf, "%u\n", interface->tm_timeout); 290962306a36Sopenharmony_ci return strlen(buf); 291062306a36Sopenharmony_ci} 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_cistatic ssize_t 291362306a36Sopenharmony_cibnx2fc_tm_timeout_store(struct device *dev, 291462306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 291562306a36Sopenharmony_ci{ 291662306a36Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 291762306a36Sopenharmony_ci struct fc_lport *lport = shost_priv(shost); 291862306a36Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 291962306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 292062306a36Sopenharmony_ci int rval, val; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci rval = kstrtouint(buf, 10, &val); 292362306a36Sopenharmony_ci if (rval) 292462306a36Sopenharmony_ci return rval; 292562306a36Sopenharmony_ci if (val > 255) 292662306a36Sopenharmony_ci return -ERANGE; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci interface->tm_timeout = (u8)val; 292962306a36Sopenharmony_ci return strlen(buf); 293062306a36Sopenharmony_ci} 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_cistatic DEVICE_ATTR(tm_timeout, S_IRUGO|S_IWUSR, bnx2fc_tm_timeout_show, 293362306a36Sopenharmony_ci bnx2fc_tm_timeout_store); 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_cistatic struct attribute *bnx2fc_host_attrs[] = { 293662306a36Sopenharmony_ci &dev_attr_tm_timeout.attr, 293762306a36Sopenharmony_ci NULL, 293862306a36Sopenharmony_ci}; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ciATTRIBUTE_GROUPS(bnx2fc_host); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci/* 294362306a36Sopenharmony_ci * scsi_host_template structure used while registering with SCSI-ml 294462306a36Sopenharmony_ci */ 294562306a36Sopenharmony_cistatic struct scsi_host_template bnx2fc_shost_template = { 294662306a36Sopenharmony_ci .module = THIS_MODULE, 294762306a36Sopenharmony_ci .name = "QLogic Offload FCoE Initiator", 294862306a36Sopenharmony_ci .queuecommand = bnx2fc_queuecommand, 294962306a36Sopenharmony_ci .eh_timed_out = fc_eh_timed_out, 295062306a36Sopenharmony_ci .eh_abort_handler = bnx2fc_eh_abort, /* abts */ 295162306a36Sopenharmony_ci .eh_device_reset_handler = bnx2fc_eh_device_reset, /* lun reset */ 295262306a36Sopenharmony_ci .eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */ 295362306a36Sopenharmony_ci .eh_host_reset_handler = fc_eh_host_reset, 295462306a36Sopenharmony_ci .slave_alloc = fc_slave_alloc, 295562306a36Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 295662306a36Sopenharmony_ci .this_id = -1, 295762306a36Sopenharmony_ci .cmd_per_lun = 3, 295862306a36Sopenharmony_ci .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, 295962306a36Sopenharmony_ci .dma_boundary = 0x7fff, 296062306a36Sopenharmony_ci .max_sectors = 0x3fbf, 296162306a36Sopenharmony_ci .track_queue_depth = 1, 296262306a36Sopenharmony_ci .slave_configure = bnx2fc_slave_configure, 296362306a36Sopenharmony_ci .shost_groups = bnx2fc_host_groups, 296462306a36Sopenharmony_ci .cmd_size = sizeof(struct bnx2fc_priv), 296562306a36Sopenharmony_ci}; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_cistatic struct libfc_function_template bnx2fc_libfc_fcn_templ = { 296862306a36Sopenharmony_ci .frame_send = bnx2fc_xmit, 296962306a36Sopenharmony_ci .elsct_send = bnx2fc_elsct_send, 297062306a36Sopenharmony_ci .fcp_abort_io = bnx2fc_abort_io, 297162306a36Sopenharmony_ci .fcp_cleanup = bnx2fc_cleanup, 297262306a36Sopenharmony_ci .get_lesb = fcoe_get_lesb, 297362306a36Sopenharmony_ci .rport_event_callback = bnx2fc_rport_event_handler, 297462306a36Sopenharmony_ci}; 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci/* 297762306a36Sopenharmony_ci * bnx2fc_cnic_cb - global template of bnx2fc - cnic driver interface 297862306a36Sopenharmony_ci * structure carrying callback function pointers 297962306a36Sopenharmony_ci */ 298062306a36Sopenharmony_cistatic struct cnic_ulp_ops bnx2fc_cnic_cb = { 298162306a36Sopenharmony_ci .owner = THIS_MODULE, 298262306a36Sopenharmony_ci .cnic_init = bnx2fc_ulp_init, 298362306a36Sopenharmony_ci .cnic_exit = bnx2fc_ulp_exit, 298462306a36Sopenharmony_ci .cnic_start = bnx2fc_ulp_start, 298562306a36Sopenharmony_ci .cnic_stop = bnx2fc_ulp_stop, 298662306a36Sopenharmony_ci .indicate_kcqes = bnx2fc_indicate_kcqe, 298762306a36Sopenharmony_ci .indicate_netevent = bnx2fc_indicate_netevent, 298862306a36Sopenharmony_ci .cnic_get_stats = bnx2fc_ulp_get_stats, 298962306a36Sopenharmony_ci}; 2990