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