18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
78c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
138c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
148c2ecf20Sopenharmony_ci *     conditions are met:
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
178c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
188c2ecf20Sopenharmony_ci *        disclaimer.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
218c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
228c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
238c2ecf20Sopenharmony_ci *        provided with the distribution.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
328c2ecf20Sopenharmony_ci * SOFTWARE.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/kernel.h>
368c2ecf20Sopenharmony_ci#include <linux/delay.h>
378c2ecf20Sopenharmony_ci#include <linux/slab.h>
388c2ecf20Sopenharmony_ci#include <linux/utsname.h>
398c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
408c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_fc.h>
418c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
428c2ecf20Sopenharmony_ci#include <scsi/fc/fc_els.h>
438c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h>
448c2ecf20Sopenharmony_ci#include <scsi/fc/fc_gs.h>
458c2ecf20Sopenharmony_ci#include <scsi/fc/fc_ms.h>
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#include "csio_hw.h"
488c2ecf20Sopenharmony_ci#include "csio_mb.h"
498c2ecf20Sopenharmony_ci#include "csio_lnode.h"
508c2ecf20Sopenharmony_ci#include "csio_rnode.h"
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciint csio_fcoe_rnodes = 1024;
538c2ecf20Sopenharmony_ciint csio_fdmi_enable = 1;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define PORT_ID_PTR(_x)         ((uint8_t *)(&_x) + 1)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* Lnode SM declarations */
588c2ecf20Sopenharmony_cistatic void csio_lns_uninit(struct csio_lnode *, enum csio_ln_ev);
598c2ecf20Sopenharmony_cistatic void csio_lns_online(struct csio_lnode *, enum csio_ln_ev);
608c2ecf20Sopenharmony_cistatic void csio_lns_ready(struct csio_lnode *, enum csio_ln_ev);
618c2ecf20Sopenharmony_cistatic void csio_lns_offline(struct csio_lnode *, enum csio_ln_ev);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic int csio_ln_mgmt_submit_req(struct csio_ioreq *,
648c2ecf20Sopenharmony_ci		void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *),
658c2ecf20Sopenharmony_ci		enum fcoe_cmn_type, struct csio_dma_buf *, uint32_t);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/* LN event mapping */
688c2ecf20Sopenharmony_cistatic enum csio_ln_ev fwevt_to_lnevt[] = {
698c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* None */
708c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PLOGI_ACC_RCVD  */
718c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PLOGI_RJT_RCVD  */
728c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PLOGI_RCVD	   */
738c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PLOGO_RCVD	   */
748c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PRLI_ACC_RCVD   */
758c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PRLI_RJT_RCVD   */
768c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PRLI_RCVD	   */
778c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PRLO_RCVD	   */
788c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* NPORT_ID_CHGD   */
798c2ecf20Sopenharmony_ci	CSIO_LNE_LOGO,		/* FLOGO_RCVD	   */
808c2ecf20Sopenharmony_ci	CSIO_LNE_LOGO,		/* CLR_VIRT_LNK_RCVD */
818c2ecf20Sopenharmony_ci	CSIO_LNE_FAB_INIT_DONE,/* FLOGI_ACC_RCVD   */
828c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* FLOGI_RJT_RCVD   */
838c2ecf20Sopenharmony_ci	CSIO_LNE_FAB_INIT_DONE,/* FDISC_ACC_RCVD   */
848c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* FDISC_RJT_RCVD   */
858c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* FLOGI_TMO_MAX_RETRY */
868c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* IMPL_LOGO_ADISC_ACC */
878c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* IMPL_LOGO_ADISC_RJT */
888c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* IMPL_LOGO_ADISC_CNFLT */
898c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PRLI_TMO		*/
908c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* ADISC_TMO		*/
918c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* RSCN_DEV_LOST */
928c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* SCR_ACC_RCVD */
938c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* ADISC_RJT_RCVD */
948c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* LOGO_SNT */
958c2ecf20Sopenharmony_ci	CSIO_LNE_NONE,		/* PROTO_ERR_IMPL_LOGO */
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define CSIO_FWE_TO_LNE(_evt)	((_evt > PROTO_ERR_IMPL_LOGO) ?		\
998c2ecf20Sopenharmony_ci						CSIO_LNE_NONE :	\
1008c2ecf20Sopenharmony_ci						fwevt_to_lnevt[_evt])
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci#define csio_ct_rsp(cp)		(((struct fc_ct_hdr *)cp)->ct_cmd)
1038c2ecf20Sopenharmony_ci#define csio_ct_reason(cp)	(((struct fc_ct_hdr *)cp)->ct_reason)
1048c2ecf20Sopenharmony_ci#define csio_ct_expl(cp)	(((struct fc_ct_hdr *)cp)->ct_explan)
1058c2ecf20Sopenharmony_ci#define csio_ct_get_pld(cp)	((void *)(((uint8_t *)cp) + FC_CT_HDR_LEN))
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/*
1088c2ecf20Sopenharmony_ci * csio_ln_match_by_portid - lookup lnode using given portid.
1098c2ecf20Sopenharmony_ci * @hw: HW module
1108c2ecf20Sopenharmony_ci * @portid: port-id.
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci * If found, returns lnode matching given portid otherwise returns NULL.
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_cistatic struct csio_lnode *
1158c2ecf20Sopenharmony_cicsio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct csio_lnode *ln;
1188c2ecf20Sopenharmony_ci	struct list_head *tmp;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/* Match siblings lnode with portid */
1218c2ecf20Sopenharmony_ci	list_for_each(tmp, &hw->sln_head) {
1228c2ecf20Sopenharmony_ci		ln = (struct csio_lnode *) tmp;
1238c2ecf20Sopenharmony_ci		if (ln->portid == portid)
1248c2ecf20Sopenharmony_ci			return ln;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return NULL;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/*
1318c2ecf20Sopenharmony_ci * csio_ln_lookup_by_vnpi - Lookup lnode using given vnp id.
1328c2ecf20Sopenharmony_ci * @hw - HW module
1338c2ecf20Sopenharmony_ci * @vnpi - vnp index.
1348c2ecf20Sopenharmony_ci * Returns - If found, returns lnode matching given vnp id
1358c2ecf20Sopenharmony_ci * otherwise returns NULL.
1368c2ecf20Sopenharmony_ci */
1378c2ecf20Sopenharmony_cistatic struct csio_lnode *
1388c2ecf20Sopenharmony_cicsio_ln_lookup_by_vnpi(struct csio_hw *hw, uint32_t vnp_id)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct list_head *tmp1, *tmp2;
1418c2ecf20Sopenharmony_ci	struct csio_lnode *sln = NULL, *cln = NULL;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (list_empty(&hw->sln_head)) {
1448c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_lnlkup_miss);
1458c2ecf20Sopenharmony_ci		return NULL;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	/* Traverse sibling lnodes */
1488c2ecf20Sopenharmony_ci	list_for_each(tmp1, &hw->sln_head) {
1498c2ecf20Sopenharmony_ci		sln = (struct csio_lnode *) tmp1;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		/* Match sibling lnode */
1528c2ecf20Sopenharmony_ci		if (sln->vnp_flowid == vnp_id)
1538c2ecf20Sopenharmony_ci			return sln;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		if (list_empty(&sln->cln_head))
1568c2ecf20Sopenharmony_ci			continue;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		/* Traverse children lnodes */
1598c2ecf20Sopenharmony_ci		list_for_each(tmp2, &sln->cln_head) {
1608c2ecf20Sopenharmony_ci			cln = (struct csio_lnode *) tmp2;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci			if (cln->vnp_flowid == vnp_id)
1638c2ecf20Sopenharmony_ci				return cln;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci	CSIO_INC_STATS(hw, n_lnlkup_miss);
1678c2ecf20Sopenharmony_ci	return NULL;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/**
1718c2ecf20Sopenharmony_ci * csio_lnode_lookup_by_wwpn - Lookup lnode using given wwpn.
1728c2ecf20Sopenharmony_ci * @hw:		HW module.
1738c2ecf20Sopenharmony_ci * @wwpn:	WWPN.
1748c2ecf20Sopenharmony_ci *
1758c2ecf20Sopenharmony_ci * If found, returns lnode matching given wwpn, returns NULL otherwise.
1768c2ecf20Sopenharmony_ci */
1778c2ecf20Sopenharmony_cistruct csio_lnode *
1788c2ecf20Sopenharmony_cicsio_lnode_lookup_by_wwpn(struct csio_hw *hw, uint8_t *wwpn)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct list_head *tmp1, *tmp2;
1818c2ecf20Sopenharmony_ci	struct csio_lnode *sln = NULL, *cln = NULL;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (list_empty(&hw->sln_head)) {
1848c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_lnlkup_miss);
1858c2ecf20Sopenharmony_ci		return NULL;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci	/* Traverse sibling lnodes */
1888c2ecf20Sopenharmony_ci	list_for_each(tmp1, &hw->sln_head) {
1898c2ecf20Sopenharmony_ci		sln = (struct csio_lnode *) tmp1;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		/* Match sibling lnode */
1928c2ecf20Sopenharmony_ci		if (!memcmp(csio_ln_wwpn(sln), wwpn, 8))
1938c2ecf20Sopenharmony_ci			return sln;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		if (list_empty(&sln->cln_head))
1968c2ecf20Sopenharmony_ci			continue;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		/* Traverse children lnodes */
1998c2ecf20Sopenharmony_ci		list_for_each(tmp2, &sln->cln_head) {
2008c2ecf20Sopenharmony_ci			cln = (struct csio_lnode *) tmp2;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci			if (!memcmp(csio_ln_wwpn(cln), wwpn, 8))
2038c2ecf20Sopenharmony_ci				return cln;
2048c2ecf20Sopenharmony_ci		}
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci	return NULL;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/* FDMI */
2108c2ecf20Sopenharmony_cistatic void
2118c2ecf20Sopenharmony_cicsio_fill_ct_iu(void *buf, uint8_t type, uint8_t sub_type, uint16_t op)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct fc_ct_hdr *cmd = (struct fc_ct_hdr *)buf;
2148c2ecf20Sopenharmony_ci	cmd->ct_rev = FC_CT_REV;
2158c2ecf20Sopenharmony_ci	cmd->ct_fs_type = type;
2168c2ecf20Sopenharmony_ci	cmd->ct_fs_subtype = sub_type;
2178c2ecf20Sopenharmony_ci	cmd->ct_cmd = htons(op);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic int
2218c2ecf20Sopenharmony_cicsio_hostname(uint8_t *buf, size_t buf_len)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	if (snprintf(buf, buf_len, "%s", init_utsname()->nodename) > 0)
2248c2ecf20Sopenharmony_ci		return 0;
2258c2ecf20Sopenharmony_ci	return -1;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int
2298c2ecf20Sopenharmony_cicsio_osname(uint8_t *buf, size_t buf_len)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	if (snprintf(buf, buf_len, "%s %s %s",
2328c2ecf20Sopenharmony_ci		     init_utsname()->sysname,
2338c2ecf20Sopenharmony_ci		     init_utsname()->release,
2348c2ecf20Sopenharmony_ci		     init_utsname()->version) > 0)
2358c2ecf20Sopenharmony_ci		return 0;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return -1;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic inline void
2418c2ecf20Sopenharmony_cicsio_append_attrib(uint8_t **ptr, uint16_t type, void *val, size_t val_len)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	uint16_t len;
2448c2ecf20Sopenharmony_ci	struct fc_fdmi_attr_entry *ae = (struct fc_fdmi_attr_entry *)*ptr;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (WARN_ON(val_len > U16_MAX))
2478c2ecf20Sopenharmony_ci		return;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	len = val_len;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	ae->type = htons(type);
2528c2ecf20Sopenharmony_ci	len += 4;		/* includes attribute type and length */
2538c2ecf20Sopenharmony_ci	len = (len + 3) & ~3;	/* should be multiple of 4 bytes */
2548c2ecf20Sopenharmony_ci	ae->len = htons(len);
2558c2ecf20Sopenharmony_ci	memcpy(ae->value, val, val_len);
2568c2ecf20Sopenharmony_ci	if (len > val_len)
2578c2ecf20Sopenharmony_ci		memset(ae->value + val_len, 0, len - val_len);
2588c2ecf20Sopenharmony_ci	*ptr += len;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/*
2628c2ecf20Sopenharmony_ci * csio_ln_fdmi_done - FDMI registeration completion
2638c2ecf20Sopenharmony_ci * @hw: HW context
2648c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request
2658c2ecf20Sopenharmony_ci */
2668c2ecf20Sopenharmony_cistatic void
2678c2ecf20Sopenharmony_cicsio_ln_fdmi_done(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	void *cmd;
2708c2ecf20Sopenharmony_ci	struct csio_lnode *ln = fdmi_req->lnode;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (fdmi_req->wr_status != FW_SUCCESS) {
2738c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "WR error:%x in processing fdmi rpa cmd\n",
2748c2ecf20Sopenharmony_ci			    fdmi_req->wr_status);
2758c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	cmd = fdmi_req->dma_buf.vaddr;
2798c2ecf20Sopenharmony_ci	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
2808c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "fdmi rpa cmd rejected reason %x expl %x\n",
2818c2ecf20Sopenharmony_ci			    csio_ct_reason(cmd), csio_ct_expl(cmd));
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/*
2868c2ecf20Sopenharmony_ci * csio_ln_fdmi_rhba_cbfn - RHBA completion
2878c2ecf20Sopenharmony_ci * @hw: HW context
2888c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_cistatic void
2918c2ecf20Sopenharmony_cicsio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	void *cmd;
2948c2ecf20Sopenharmony_ci	uint8_t *pld;
2958c2ecf20Sopenharmony_ci	uint32_t len = 0;
2968c2ecf20Sopenharmony_ci	__be32 val;
2978c2ecf20Sopenharmony_ci	__be16 mfs;
2988c2ecf20Sopenharmony_ci	uint32_t numattrs = 0;
2998c2ecf20Sopenharmony_ci	struct csio_lnode *ln = fdmi_req->lnode;
3008c2ecf20Sopenharmony_ci	struct fs_fdmi_attrs *attrib_blk;
3018c2ecf20Sopenharmony_ci	struct fc_fdmi_port_name *port_name;
3028c2ecf20Sopenharmony_ci	uint8_t buf[64];
3038c2ecf20Sopenharmony_ci	uint8_t *fc4_type;
3048c2ecf20Sopenharmony_ci	unsigned long flags;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (fdmi_req->wr_status != FW_SUCCESS) {
3078c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "WR error:%x in processing fdmi rhba cmd\n",
3088c2ecf20Sopenharmony_ci			    fdmi_req->wr_status);
3098c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	cmd = fdmi_req->dma_buf.vaddr;
3138c2ecf20Sopenharmony_ci	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
3148c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "fdmi rhba cmd rejected reason %x expl %x\n",
3158c2ecf20Sopenharmony_ci			    csio_ct_reason(cmd), csio_ct_expl(cmd));
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (!csio_is_rnode_ready(fdmi_req->rnode)) {
3198c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
3208c2ecf20Sopenharmony_ci		return;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	/* Prepare CT hdr for RPA cmd */
3248c2ecf20Sopenharmony_ci	memset(cmd, 0, FC_CT_HDR_LEN);
3258c2ecf20Sopenharmony_ci	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_RPA);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Prepare RPA payload */
3288c2ecf20Sopenharmony_ci	pld = (uint8_t *)csio_ct_get_pld(cmd);
3298c2ecf20Sopenharmony_ci	port_name = (struct fc_fdmi_port_name *)pld;
3308c2ecf20Sopenharmony_ci	memcpy(&port_name->portname, csio_ln_wwpn(ln), 8);
3318c2ecf20Sopenharmony_ci	pld += sizeof(*port_name);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* Start appending Port attributes */
3348c2ecf20Sopenharmony_ci	attrib_blk = (struct fs_fdmi_attrs *)pld;
3358c2ecf20Sopenharmony_ci	attrib_blk->numattrs = 0;
3368c2ecf20Sopenharmony_ci	len += sizeof(attrib_blk->numattrs);
3378c2ecf20Sopenharmony_ci	pld += sizeof(attrib_blk->numattrs);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	fc4_type = &buf[0];
3408c2ecf20Sopenharmony_ci	memset(fc4_type, 0, FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
3418c2ecf20Sopenharmony_ci	fc4_type[2] = 1;
3428c2ecf20Sopenharmony_ci	fc4_type[7] = 1;
3438c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_FC4TYPES,
3448c2ecf20Sopenharmony_ci			   fc4_type, FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
3458c2ecf20Sopenharmony_ci	numattrs++;
3468c2ecf20Sopenharmony_ci	val = htonl(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
3478c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_SUPPORTEDSPEED,
3488c2ecf20Sopenharmony_ci			   &val,
3498c2ecf20Sopenharmony_ci			   FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN);
3508c2ecf20Sopenharmony_ci	numattrs++;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_1G)
3538c2ecf20Sopenharmony_ci		val = htonl(FC_PORTSPEED_1GBIT);
3548c2ecf20Sopenharmony_ci	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_10G)
3558c2ecf20Sopenharmony_ci		val = htonl(FC_PORTSPEED_10GBIT);
3568c2ecf20Sopenharmony_ci	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_25G)
3578c2ecf20Sopenharmony_ci		val = htonl(FC_PORTSPEED_25GBIT);
3588c2ecf20Sopenharmony_ci	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_40G)
3598c2ecf20Sopenharmony_ci		val = htonl(FC_PORTSPEED_40GBIT);
3608c2ecf20Sopenharmony_ci	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_50G)
3618c2ecf20Sopenharmony_ci		val = htonl(FC_PORTSPEED_50GBIT);
3628c2ecf20Sopenharmony_ci	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_100G)
3638c2ecf20Sopenharmony_ci		val = htonl(FC_PORTSPEED_100GBIT);
3648c2ecf20Sopenharmony_ci	else
3658c2ecf20Sopenharmony_ci		val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN);
3668c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
3678c2ecf20Sopenharmony_ci			   &val, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
3688c2ecf20Sopenharmony_ci	numattrs++;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	mfs = ln->ln_sparm.csp.sp_bb_data;
3718c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_MAXFRAMESIZE,
3728c2ecf20Sopenharmony_ci			   &mfs, sizeof(mfs));
3738c2ecf20Sopenharmony_ci	numattrs++;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	strcpy(buf, "csiostor");
3768c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_OSDEVICENAME, buf,
3778c2ecf20Sopenharmony_ci			   strlen(buf));
3788c2ecf20Sopenharmony_ci	numattrs++;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (!csio_hostname(buf, sizeof(buf))) {
3818c2ecf20Sopenharmony_ci		csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_HOSTNAME,
3828c2ecf20Sopenharmony_ci				   buf, strlen(buf));
3838c2ecf20Sopenharmony_ci		numattrs++;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci	attrib_blk->numattrs = htonl(numattrs);
3868c2ecf20Sopenharmony_ci	len = (uint32_t)(pld - (uint8_t *)cmd);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/* Submit FDMI RPA request */
3898c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hw->lock, flags);
3908c2ecf20Sopenharmony_ci	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_done,
3918c2ecf20Sopenharmony_ci				FCOE_CT, &fdmi_req->dma_buf, len)) {
3928c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
3938c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "Failed to issue fdmi rpa req\n");
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hw->lock, flags);
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci/*
3998c2ecf20Sopenharmony_ci * csio_ln_fdmi_dprt_cbfn - DPRT completion
4008c2ecf20Sopenharmony_ci * @hw: HW context
4018c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request
4028c2ecf20Sopenharmony_ci */
4038c2ecf20Sopenharmony_cistatic void
4048c2ecf20Sopenharmony_cicsio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	void *cmd;
4078c2ecf20Sopenharmony_ci	uint8_t *pld;
4088c2ecf20Sopenharmony_ci	uint32_t len = 0;
4098c2ecf20Sopenharmony_ci	uint32_t numattrs = 0;
4108c2ecf20Sopenharmony_ci	__be32  maxpayload = htonl(65536);
4118c2ecf20Sopenharmony_ci	struct fc_fdmi_hba_identifier *hbaid;
4128c2ecf20Sopenharmony_ci	struct csio_lnode *ln = fdmi_req->lnode;
4138c2ecf20Sopenharmony_ci	struct fc_fdmi_rpl *reg_pl;
4148c2ecf20Sopenharmony_ci	struct fs_fdmi_attrs *attrib_blk;
4158c2ecf20Sopenharmony_ci	uint8_t buf[64];
4168c2ecf20Sopenharmony_ci	unsigned long flags;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (fdmi_req->wr_status != FW_SUCCESS) {
4198c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "WR error:%x in processing fdmi dprt cmd\n",
4208c2ecf20Sopenharmony_ci			    fdmi_req->wr_status);
4218c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (!csio_is_rnode_ready(fdmi_req->rnode)) {
4258c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
4268c2ecf20Sopenharmony_ci		return;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci	cmd = fdmi_req->dma_buf.vaddr;
4298c2ecf20Sopenharmony_ci	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
4308c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "fdmi dprt cmd rejected reason %x expl %x\n",
4318c2ecf20Sopenharmony_ci			    csio_ct_reason(cmd), csio_ct_expl(cmd));
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* Prepare CT hdr for RHBA cmd */
4358c2ecf20Sopenharmony_ci	memset(cmd, 0, FC_CT_HDR_LEN);
4368c2ecf20Sopenharmony_ci	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_RHBA);
4378c2ecf20Sopenharmony_ci	len = FC_CT_HDR_LEN;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* Prepare RHBA payload */
4408c2ecf20Sopenharmony_ci	pld = (uint8_t *)csio_ct_get_pld(cmd);
4418c2ecf20Sopenharmony_ci	hbaid = (struct fc_fdmi_hba_identifier *)pld;
4428c2ecf20Sopenharmony_ci	memcpy(&hbaid->id, csio_ln_wwpn(ln), 8); /* HBA identifer */
4438c2ecf20Sopenharmony_ci	pld += sizeof(*hbaid);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* Register one port per hba */
4468c2ecf20Sopenharmony_ci	reg_pl = (struct fc_fdmi_rpl *)pld;
4478c2ecf20Sopenharmony_ci	reg_pl->numport = htonl(1);
4488c2ecf20Sopenharmony_ci	memcpy(&reg_pl->port[0].portname, csio_ln_wwpn(ln), 8);
4498c2ecf20Sopenharmony_ci	pld += sizeof(*reg_pl);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/* Start appending HBA attributes hba */
4528c2ecf20Sopenharmony_ci	attrib_blk = (struct fs_fdmi_attrs *)pld;
4538c2ecf20Sopenharmony_ci	attrib_blk->numattrs = 0;
4548c2ecf20Sopenharmony_ci	len += sizeof(attrib_blk->numattrs);
4558c2ecf20Sopenharmony_ci	pld += sizeof(attrib_blk->numattrs);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_NODENAME, csio_ln_wwnn(ln),
4588c2ecf20Sopenharmony_ci			   FC_FDMI_HBA_ATTR_NODENAME_LEN);
4598c2ecf20Sopenharmony_ci	numattrs++;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	memset(buf, 0, sizeof(buf));
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	strcpy(buf, "Chelsio Communications");
4648c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MANUFACTURER, buf,
4658c2ecf20Sopenharmony_ci			   strlen(buf));
4668c2ecf20Sopenharmony_ci	numattrs++;
4678c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_SERIALNUMBER,
4688c2ecf20Sopenharmony_ci			   hw->vpd.sn, sizeof(hw->vpd.sn));
4698c2ecf20Sopenharmony_ci	numattrs++;
4708c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODEL, hw->vpd.id,
4718c2ecf20Sopenharmony_ci			   sizeof(hw->vpd.id));
4728c2ecf20Sopenharmony_ci	numattrs++;
4738c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODELDESCRIPTION,
4748c2ecf20Sopenharmony_ci			   hw->model_desc, strlen(hw->model_desc));
4758c2ecf20Sopenharmony_ci	numattrs++;
4768c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_HARDWAREVERSION,
4778c2ecf20Sopenharmony_ci			   hw->hw_ver, sizeof(hw->hw_ver));
4788c2ecf20Sopenharmony_ci	numattrs++;
4798c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_FIRMWAREVERSION,
4808c2ecf20Sopenharmony_ci			   hw->fwrev_str, strlen(hw->fwrev_str));
4818c2ecf20Sopenharmony_ci	numattrs++;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (!csio_osname(buf, sizeof(buf))) {
4848c2ecf20Sopenharmony_ci		csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_OSNAMEVERSION,
4858c2ecf20Sopenharmony_ci				   buf, strlen(buf));
4868c2ecf20Sopenharmony_ci		numattrs++;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD,
4908c2ecf20Sopenharmony_ci			   &maxpayload, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN);
4918c2ecf20Sopenharmony_ci	len = (uint32_t)(pld - (uint8_t *)cmd);
4928c2ecf20Sopenharmony_ci	numattrs++;
4938c2ecf20Sopenharmony_ci	attrib_blk->numattrs = htonl(numattrs);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	/* Submit FDMI RHBA request */
4968c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hw->lock, flags);
4978c2ecf20Sopenharmony_ci	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_rhba_cbfn,
4988c2ecf20Sopenharmony_ci				FCOE_CT, &fdmi_req->dma_buf, len)) {
4998c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
5008c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "Failed to issue fdmi rhba req\n");
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hw->lock, flags);
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci/*
5068c2ecf20Sopenharmony_ci * csio_ln_fdmi_dhba_cbfn - DHBA completion
5078c2ecf20Sopenharmony_ci * @hw: HW context
5088c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request
5098c2ecf20Sopenharmony_ci */
5108c2ecf20Sopenharmony_cistatic void
5118c2ecf20Sopenharmony_cicsio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	struct csio_lnode *ln = fdmi_req->lnode;
5148c2ecf20Sopenharmony_ci	void *cmd;
5158c2ecf20Sopenharmony_ci	struct fc_fdmi_port_name *port_name;
5168c2ecf20Sopenharmony_ci	uint32_t len;
5178c2ecf20Sopenharmony_ci	unsigned long flags;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (fdmi_req->wr_status != FW_SUCCESS) {
5208c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "WR error:%x in processing fdmi dhba cmd\n",
5218c2ecf20Sopenharmony_ci			    fdmi_req->wr_status);
5228c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (!csio_is_rnode_ready(fdmi_req->rnode)) {
5268c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
5278c2ecf20Sopenharmony_ci		return;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci	cmd = fdmi_req->dma_buf.vaddr;
5308c2ecf20Sopenharmony_ci	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
5318c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "fdmi dhba cmd rejected reason %x expl %x\n",
5328c2ecf20Sopenharmony_ci			    csio_ct_reason(cmd), csio_ct_expl(cmd));
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* Send FDMI cmd to de-register any Port attributes if registered
5368c2ecf20Sopenharmony_ci	 * before
5378c2ecf20Sopenharmony_ci	 */
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	/* Prepare FDMI DPRT cmd */
5408c2ecf20Sopenharmony_ci	memset(cmd, 0, FC_CT_HDR_LEN);
5418c2ecf20Sopenharmony_ci	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_DPRT);
5428c2ecf20Sopenharmony_ci	len = FC_CT_HDR_LEN;
5438c2ecf20Sopenharmony_ci	port_name = (struct fc_fdmi_port_name *)csio_ct_get_pld(cmd);
5448c2ecf20Sopenharmony_ci	memcpy(&port_name->portname, csio_ln_wwpn(ln), 8);
5458c2ecf20Sopenharmony_ci	len += sizeof(*port_name);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* Submit FDMI request */
5488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hw->lock, flags);
5498c2ecf20Sopenharmony_ci	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dprt_cbfn,
5508c2ecf20Sopenharmony_ci				FCOE_CT, &fdmi_req->dma_buf, len)) {
5518c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
5528c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "Failed to issue fdmi dprt req\n");
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hw->lock, flags);
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci/**
5588c2ecf20Sopenharmony_ci * csio_ln_fdmi_start - Start an FDMI request.
5598c2ecf20Sopenharmony_ci * @ln:		lnode
5608c2ecf20Sopenharmony_ci * @context:	session context
5618c2ecf20Sopenharmony_ci *
5628c2ecf20Sopenharmony_ci * Issued with lock held.
5638c2ecf20Sopenharmony_ci */
5648c2ecf20Sopenharmony_ciint
5658c2ecf20Sopenharmony_cicsio_ln_fdmi_start(struct csio_lnode *ln, void *context)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct csio_ioreq *fdmi_req;
5688c2ecf20Sopenharmony_ci	struct csio_rnode *fdmi_rn = (struct csio_rnode *)context;
5698c2ecf20Sopenharmony_ci	void *cmd;
5708c2ecf20Sopenharmony_ci	struct fc_fdmi_hba_identifier *hbaid;
5718c2ecf20Sopenharmony_ci	uint32_t len;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	if (!(ln->flags & CSIO_LNF_FDMI_ENABLE))
5748c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (!csio_is_rnode_ready(fdmi_rn))
5778c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* Send FDMI cmd to de-register any HBA attributes if registered
5808c2ecf20Sopenharmony_ci	 * before
5818c2ecf20Sopenharmony_ci	 */
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	fdmi_req = ln->mgmt_req;
5848c2ecf20Sopenharmony_ci	fdmi_req->lnode = ln;
5858c2ecf20Sopenharmony_ci	fdmi_req->rnode = fdmi_rn;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	/* Prepare FDMI DHBA cmd */
5888c2ecf20Sopenharmony_ci	cmd = fdmi_req->dma_buf.vaddr;
5898c2ecf20Sopenharmony_ci	memset(cmd, 0, FC_CT_HDR_LEN);
5908c2ecf20Sopenharmony_ci	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_DHBA);
5918c2ecf20Sopenharmony_ci	len = FC_CT_HDR_LEN;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	hbaid = (struct fc_fdmi_hba_identifier *)csio_ct_get_pld(cmd);
5948c2ecf20Sopenharmony_ci	memcpy(&hbaid->id, csio_ln_wwpn(ln), 8);
5958c2ecf20Sopenharmony_ci	len += sizeof(*hbaid);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* Submit FDMI request */
5988c2ecf20Sopenharmony_ci	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dhba_cbfn,
5998c2ecf20Sopenharmony_ci					FCOE_CT, &fdmi_req->dma_buf, len)) {
6008c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_fdmi_err);
6018c2ecf20Sopenharmony_ci		csio_ln_dbg(ln, "Failed to issue fdmi dhba req\n");
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	return 0;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci/*
6088c2ecf20Sopenharmony_ci * csio_ln_vnp_read_cbfn - vnp read completion handler.
6098c2ecf20Sopenharmony_ci * @hw: HW lnode
6108c2ecf20Sopenharmony_ci * @cbfn: Completion handler.
6118c2ecf20Sopenharmony_ci *
6128c2ecf20Sopenharmony_ci * Reads vnp response and updates ln parameters.
6138c2ecf20Sopenharmony_ci */
6148c2ecf20Sopenharmony_cistatic void
6158c2ecf20Sopenharmony_cicsio_ln_vnp_read_cbfn(struct csio_hw *hw, struct csio_mb *mbp)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	struct csio_lnode *ln = ((struct csio_lnode *)mbp->priv);
6188c2ecf20Sopenharmony_ci	struct fw_fcoe_vnp_cmd *rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
6198c2ecf20Sopenharmony_ci	struct fc_els_csp *csp;
6208c2ecf20Sopenharmony_ci	struct fc_els_cssp *clsp;
6218c2ecf20Sopenharmony_ci	enum fw_retval retval;
6228c2ecf20Sopenharmony_ci	__be32 nport_id = 0;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	retval = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
6258c2ecf20Sopenharmony_ci	if (retval != FW_SUCCESS) {
6268c2ecf20Sopenharmony_ci		csio_err(hw, "FCOE VNP read cmd returned error:0x%x\n", retval);
6278c2ecf20Sopenharmony_ci		mempool_free(mbp, hw->mb_mempool);
6288c2ecf20Sopenharmony_ci		return;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	spin_lock_irq(&hw->lock);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	memcpy(ln->mac, rsp->vnport_mac, sizeof(ln->mac));
6348c2ecf20Sopenharmony_ci	memcpy(&nport_id, &rsp->vnport_mac[3], sizeof(uint8_t)*3);
6358c2ecf20Sopenharmony_ci	ln->nport_id = ntohl(nport_id);
6368c2ecf20Sopenharmony_ci	ln->nport_id = ln->nport_id >> 8;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* Update WWNs */
6398c2ecf20Sopenharmony_ci	/*
6408c2ecf20Sopenharmony_ci	 * This may look like a duplication of what csio_fcoe_enable_link()
6418c2ecf20Sopenharmony_ci	 * does, but is absolutely necessary if the vnpi changes between
6428c2ecf20Sopenharmony_ci	 * a FCOE LINK UP and FCOE LINK DOWN.
6438c2ecf20Sopenharmony_ci	 */
6448c2ecf20Sopenharmony_ci	memcpy(csio_ln_wwnn(ln), rsp->vnport_wwnn, 8);
6458c2ecf20Sopenharmony_ci	memcpy(csio_ln_wwpn(ln), rsp->vnport_wwpn, 8);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	/* Copy common sparam */
6488c2ecf20Sopenharmony_ci	csp = (struct fc_els_csp *)rsp->cmn_srv_parms;
6498c2ecf20Sopenharmony_ci	ln->ln_sparm.csp.sp_hi_ver = csp->sp_hi_ver;
6508c2ecf20Sopenharmony_ci	ln->ln_sparm.csp.sp_lo_ver = csp->sp_lo_ver;
6518c2ecf20Sopenharmony_ci	ln->ln_sparm.csp.sp_bb_cred = csp->sp_bb_cred;
6528c2ecf20Sopenharmony_ci	ln->ln_sparm.csp.sp_features = csp->sp_features;
6538c2ecf20Sopenharmony_ci	ln->ln_sparm.csp.sp_bb_data = csp->sp_bb_data;
6548c2ecf20Sopenharmony_ci	ln->ln_sparm.csp.sp_r_a_tov = csp->sp_r_a_tov;
6558c2ecf20Sopenharmony_ci	ln->ln_sparm.csp.sp_e_d_tov = csp->sp_e_d_tov;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/* Copy word 0 & word 1 of class sparam */
6588c2ecf20Sopenharmony_ci	clsp = (struct fc_els_cssp *)rsp->clsp_word_0_1;
6598c2ecf20Sopenharmony_ci	ln->ln_sparm.clsp[2].cp_class = clsp->cp_class;
6608c2ecf20Sopenharmony_ci	ln->ln_sparm.clsp[2].cp_init = clsp->cp_init;
6618c2ecf20Sopenharmony_ci	ln->ln_sparm.clsp[2].cp_recip = clsp->cp_recip;
6628c2ecf20Sopenharmony_ci	ln->ln_sparm.clsp[2].cp_rdfs = clsp->cp_rdfs;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	spin_unlock_irq(&hw->lock);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	mempool_free(mbp, hw->mb_mempool);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	/* Send an event to update local attribs */
6698c2ecf20Sopenharmony_ci	csio_lnode_async_event(ln, CSIO_LN_FC_ATTRIB_UPDATE);
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci/*
6738c2ecf20Sopenharmony_ci * csio_ln_vnp_read - Read vnp params.
6748c2ecf20Sopenharmony_ci * @ln: lnode
6758c2ecf20Sopenharmony_ci * @cbfn: Completion handler.
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * Issued with lock held.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_cistatic int
6808c2ecf20Sopenharmony_cicsio_ln_vnp_read(struct csio_lnode *ln,
6818c2ecf20Sopenharmony_ci		void (*cbfn) (struct csio_hw *, struct csio_mb *))
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	struct csio_hw *hw = ln->hwp;
6848c2ecf20Sopenharmony_ci	struct csio_mb  *mbp;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	/* Allocate Mbox request */
6878c2ecf20Sopenharmony_ci	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
6888c2ecf20Sopenharmony_ci	if (!mbp) {
6898c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_err_nomem);
6908c2ecf20Sopenharmony_ci		return -ENOMEM;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	/* Prepare VNP Command */
6948c2ecf20Sopenharmony_ci	csio_fcoe_vnp_read_init_mb(ln, mbp,
6958c2ecf20Sopenharmony_ci				    CSIO_MB_DEFAULT_TMO,
6968c2ecf20Sopenharmony_ci				    ln->fcf_flowid,
6978c2ecf20Sopenharmony_ci				    ln->vnp_flowid,
6988c2ecf20Sopenharmony_ci				    cbfn);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* Issue MBOX cmd */
7018c2ecf20Sopenharmony_ci	if (csio_mb_issue(hw, mbp)) {
7028c2ecf20Sopenharmony_ci		csio_err(hw, "Failed to issue mbox FCoE VNP command\n");
7038c2ecf20Sopenharmony_ci		mempool_free(mbp, hw->mb_mempool);
7048c2ecf20Sopenharmony_ci		return -EINVAL;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	return 0;
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci/*
7118c2ecf20Sopenharmony_ci * csio_fcoe_enable_link - Enable fcoe link.
7128c2ecf20Sopenharmony_ci * @ln: lnode
7138c2ecf20Sopenharmony_ci * @enable: enable/disable
7148c2ecf20Sopenharmony_ci * Issued with lock held.
7158c2ecf20Sopenharmony_ci * Issues mbox cmd to bring up FCOE link on port associated with given ln.
7168c2ecf20Sopenharmony_ci */
7178c2ecf20Sopenharmony_cistatic int
7188c2ecf20Sopenharmony_cicsio_fcoe_enable_link(struct csio_lnode *ln, bool enable)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	struct csio_hw *hw = ln->hwp;
7218c2ecf20Sopenharmony_ci	struct csio_mb  *mbp;
7228c2ecf20Sopenharmony_ci	enum fw_retval retval;
7238c2ecf20Sopenharmony_ci	uint8_t portid;
7248c2ecf20Sopenharmony_ci	uint8_t sub_op;
7258c2ecf20Sopenharmony_ci	struct fw_fcoe_link_cmd *lcmd;
7268c2ecf20Sopenharmony_ci	int i;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
7298c2ecf20Sopenharmony_ci	if (!mbp) {
7308c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_err_nomem);
7318c2ecf20Sopenharmony_ci		return -ENOMEM;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	portid = ln->portid;
7358c2ecf20Sopenharmony_ci	sub_op = enable ? FCOE_LINK_UP : FCOE_LINK_DOWN;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	csio_dbg(hw, "bringing FCOE LINK %s on Port:%d\n",
7388c2ecf20Sopenharmony_ci		 sub_op ? "UP" : "DOWN", portid);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	csio_write_fcoe_link_cond_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
7418c2ecf20Sopenharmony_ci					  portid, sub_op, 0, 0, 0, NULL);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	if (csio_mb_issue(hw, mbp)) {
7448c2ecf20Sopenharmony_ci		csio_err(hw, "failed to issue FCOE LINK cmd on port[%d]\n",
7458c2ecf20Sopenharmony_ci			portid);
7468c2ecf20Sopenharmony_ci		mempool_free(mbp, hw->mb_mempool);
7478c2ecf20Sopenharmony_ci		return -EINVAL;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	retval = csio_mb_fw_retval(mbp);
7518c2ecf20Sopenharmony_ci	if (retval != FW_SUCCESS) {
7528c2ecf20Sopenharmony_ci		csio_err(hw,
7538c2ecf20Sopenharmony_ci			 "FCOE LINK %s cmd on port[%d] failed with "
7548c2ecf20Sopenharmony_ci			 "ret:x%x\n", sub_op ? "UP" : "DOWN", portid, retval);
7558c2ecf20Sopenharmony_ci		mempool_free(mbp, hw->mb_mempool);
7568c2ecf20Sopenharmony_ci		return -EINVAL;
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (!enable)
7608c2ecf20Sopenharmony_ci		goto out;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	lcmd = (struct fw_fcoe_link_cmd *)mbp->mb;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	memcpy(csio_ln_wwnn(ln), lcmd->vnport_wwnn, 8);
7658c2ecf20Sopenharmony_ci	memcpy(csio_ln_wwpn(ln), lcmd->vnport_wwpn, 8);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	for (i = 0; i < CSIO_MAX_PPORTS; i++)
7688c2ecf20Sopenharmony_ci		if (hw->pport[i].portid == portid)
7698c2ecf20Sopenharmony_ci			memcpy(hw->pport[i].mac, lcmd->phy_mac, 6);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ciout:
7728c2ecf20Sopenharmony_ci	mempool_free(mbp, hw->mb_mempool);
7738c2ecf20Sopenharmony_ci	return 0;
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci/*
7778c2ecf20Sopenharmony_ci * csio_ln_read_fcf_cbfn - Read fcf parameters
7788c2ecf20Sopenharmony_ci * @ln: lnode
7798c2ecf20Sopenharmony_ci *
7808c2ecf20Sopenharmony_ci * read fcf response and Update ln fcf information.
7818c2ecf20Sopenharmony_ci */
7828c2ecf20Sopenharmony_cistatic void
7838c2ecf20Sopenharmony_cicsio_ln_read_fcf_cbfn(struct csio_hw *hw, struct csio_mb *mbp)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	struct csio_lnode *ln = (struct csio_lnode *)mbp->priv;
7868c2ecf20Sopenharmony_ci	struct csio_fcf_info	*fcf_info;
7878c2ecf20Sopenharmony_ci	struct fw_fcoe_fcf_cmd *rsp =
7888c2ecf20Sopenharmony_ci				(struct fw_fcoe_fcf_cmd *)(mbp->mb);
7898c2ecf20Sopenharmony_ci	enum fw_retval retval;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
7928c2ecf20Sopenharmony_ci	if (retval != FW_SUCCESS) {
7938c2ecf20Sopenharmony_ci		csio_ln_err(ln, "FCOE FCF cmd failed with ret x%x\n",
7948c2ecf20Sopenharmony_ci				retval);
7958c2ecf20Sopenharmony_ci		mempool_free(mbp, hw->mb_mempool);
7968c2ecf20Sopenharmony_ci		return;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	spin_lock_irq(&hw->lock);
8008c2ecf20Sopenharmony_ci	fcf_info = ln->fcfinfo;
8018c2ecf20Sopenharmony_ci	fcf_info->priority = FW_FCOE_FCF_CMD_PRIORITY_GET(
8028c2ecf20Sopenharmony_ci					ntohs(rsp->priority_pkd));
8038c2ecf20Sopenharmony_ci	fcf_info->vf_id = ntohs(rsp->vf_id);
8048c2ecf20Sopenharmony_ci	fcf_info->vlan_id = rsp->vlan_id;
8058c2ecf20Sopenharmony_ci	fcf_info->max_fcoe_size = ntohs(rsp->max_fcoe_size);
8068c2ecf20Sopenharmony_ci	fcf_info->fka_adv = be32_to_cpu(rsp->fka_adv);
8078c2ecf20Sopenharmony_ci	fcf_info->fcfi = FW_FCOE_FCF_CMD_FCFI_GET(ntohl(rsp->op_to_fcfi));
8088c2ecf20Sopenharmony_ci	fcf_info->fpma = FW_FCOE_FCF_CMD_FPMA_GET(rsp->fpma_to_portid);
8098c2ecf20Sopenharmony_ci	fcf_info->spma = FW_FCOE_FCF_CMD_SPMA_GET(rsp->fpma_to_portid);
8108c2ecf20Sopenharmony_ci	fcf_info->login = FW_FCOE_FCF_CMD_LOGIN_GET(rsp->fpma_to_portid);
8118c2ecf20Sopenharmony_ci	fcf_info->portid = FW_FCOE_FCF_CMD_PORTID_GET(rsp->fpma_to_portid);
8128c2ecf20Sopenharmony_ci	memcpy(fcf_info->fc_map, rsp->fc_map, sizeof(fcf_info->fc_map));
8138c2ecf20Sopenharmony_ci	memcpy(fcf_info->mac, rsp->mac, sizeof(fcf_info->mac));
8148c2ecf20Sopenharmony_ci	memcpy(fcf_info->name_id, rsp->name_id, sizeof(fcf_info->name_id));
8158c2ecf20Sopenharmony_ci	memcpy(fcf_info->fabric, rsp->fabric, sizeof(fcf_info->fabric));
8168c2ecf20Sopenharmony_ci	memcpy(fcf_info->spma_mac, rsp->spma_mac, sizeof(fcf_info->spma_mac));
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	spin_unlock_irq(&hw->lock);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	mempool_free(mbp, hw->mb_mempool);
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci/*
8248c2ecf20Sopenharmony_ci * csio_ln_read_fcf_entry - Read fcf entry.
8258c2ecf20Sopenharmony_ci * @ln: lnode
8268c2ecf20Sopenharmony_ci * @cbfn: Completion handler.
8278c2ecf20Sopenharmony_ci *
8288c2ecf20Sopenharmony_ci * Issued with lock held.
8298c2ecf20Sopenharmony_ci */
8308c2ecf20Sopenharmony_cistatic int
8318c2ecf20Sopenharmony_cicsio_ln_read_fcf_entry(struct csio_lnode *ln,
8328c2ecf20Sopenharmony_ci			void (*cbfn) (struct csio_hw *, struct csio_mb *))
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	struct csio_hw *hw = ln->hwp;
8358c2ecf20Sopenharmony_ci	struct csio_mb  *mbp;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
8388c2ecf20Sopenharmony_ci	if (!mbp) {
8398c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_err_nomem);
8408c2ecf20Sopenharmony_ci		return -ENOMEM;
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	/* Get FCoE FCF information */
8448c2ecf20Sopenharmony_ci	csio_fcoe_read_fcf_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
8458c2ecf20Sopenharmony_ci				      ln->portid, ln->fcf_flowid, cbfn);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (csio_mb_issue(hw, mbp)) {
8488c2ecf20Sopenharmony_ci		csio_err(hw, "failed to issue FCOE FCF cmd\n");
8498c2ecf20Sopenharmony_ci		mempool_free(mbp, hw->mb_mempool);
8508c2ecf20Sopenharmony_ci		return -EINVAL;
8518c2ecf20Sopenharmony_ci	}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	return 0;
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci/*
8578c2ecf20Sopenharmony_ci * csio_handle_link_up - Logical Linkup event.
8588c2ecf20Sopenharmony_ci * @hw - HW module.
8598c2ecf20Sopenharmony_ci * @portid - Physical port number
8608c2ecf20Sopenharmony_ci * @fcfi - FCF index.
8618c2ecf20Sopenharmony_ci * @vnpi - VNP index.
8628c2ecf20Sopenharmony_ci * Returns - none.
8638c2ecf20Sopenharmony_ci *
8648c2ecf20Sopenharmony_ci * This event is received from FW, when virtual link is established between
8658c2ecf20Sopenharmony_ci * Physical port[ENode] and FCF. If its new vnpi, then local node object is
8668c2ecf20Sopenharmony_ci * created on this FCF and set to [ONLINE] state.
8678c2ecf20Sopenharmony_ci * Lnode waits for FW_RDEV_CMD event to be received indicating that
8688c2ecf20Sopenharmony_ci * Fabric login is completed and lnode moves to [READY] state.
8698c2ecf20Sopenharmony_ci *
8708c2ecf20Sopenharmony_ci * This called with hw lock held
8718c2ecf20Sopenharmony_ci */
8728c2ecf20Sopenharmony_cistatic void
8738c2ecf20Sopenharmony_cicsio_handle_link_up(struct csio_hw *hw, uint8_t portid, uint32_t fcfi,
8748c2ecf20Sopenharmony_ci		    uint32_t vnpi)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	struct csio_lnode *ln = NULL;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* Lookup lnode based on vnpi */
8798c2ecf20Sopenharmony_ci	ln = csio_ln_lookup_by_vnpi(hw, vnpi);
8808c2ecf20Sopenharmony_ci	if (!ln) {
8818c2ecf20Sopenharmony_ci		/* Pick lnode based on portid */
8828c2ecf20Sopenharmony_ci		ln = csio_ln_lookup_by_portid(hw, portid);
8838c2ecf20Sopenharmony_ci		if (!ln) {
8848c2ecf20Sopenharmony_ci			csio_err(hw, "failed to lookup fcoe lnode on port:%d\n",
8858c2ecf20Sopenharmony_ci				portid);
8868c2ecf20Sopenharmony_ci			CSIO_DB_ASSERT(0);
8878c2ecf20Sopenharmony_ci			return;
8888c2ecf20Sopenharmony_ci		}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci		/* Check if lnode has valid vnp flowid */
8918c2ecf20Sopenharmony_ci		if (ln->vnp_flowid != CSIO_INVALID_IDX) {
8928c2ecf20Sopenharmony_ci			/* New VN-Port */
8938c2ecf20Sopenharmony_ci			spin_unlock_irq(&hw->lock);
8948c2ecf20Sopenharmony_ci			csio_lnode_alloc(hw);
8958c2ecf20Sopenharmony_ci			spin_lock_irq(&hw->lock);
8968c2ecf20Sopenharmony_ci			if (!ln) {
8978c2ecf20Sopenharmony_ci				csio_err(hw,
8988c2ecf20Sopenharmony_ci					 "failed to allocate fcoe lnode"
8998c2ecf20Sopenharmony_ci					 "for port:%d vnpi:x%x\n",
9008c2ecf20Sopenharmony_ci					 portid, vnpi);
9018c2ecf20Sopenharmony_ci				CSIO_DB_ASSERT(0);
9028c2ecf20Sopenharmony_ci				return;
9038c2ecf20Sopenharmony_ci			}
9048c2ecf20Sopenharmony_ci			ln->portid = portid;
9058c2ecf20Sopenharmony_ci		}
9068c2ecf20Sopenharmony_ci		ln->vnp_flowid = vnpi;
9078c2ecf20Sopenharmony_ci		ln->dev_num &= ~0xFFFF;
9088c2ecf20Sopenharmony_ci		ln->dev_num |= vnpi;
9098c2ecf20Sopenharmony_ci	}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	/*Initialize fcfi */
9128c2ecf20Sopenharmony_ci	ln->fcf_flowid = fcfi;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	csio_info(hw, "Port:%d - FCOE LINK UP\n", portid);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	CSIO_INC_STATS(ln, n_link_up);
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	/* Send LINKUP event to SM */
9198c2ecf20Sopenharmony_ci	csio_post_event(&ln->sm, CSIO_LNE_LINKUP);
9208c2ecf20Sopenharmony_ci}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci/*
9238c2ecf20Sopenharmony_ci * csio_post_event_rns
9248c2ecf20Sopenharmony_ci * @ln - FCOE lnode
9258c2ecf20Sopenharmony_ci * @evt - Given rnode event
9268c2ecf20Sopenharmony_ci * Returns - none
9278c2ecf20Sopenharmony_ci *
9288c2ecf20Sopenharmony_ci * Posts given rnode event to all FCOE rnodes connected with given Lnode.
9298c2ecf20Sopenharmony_ci * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE
9308c2ecf20Sopenharmony_ci * event.
9318c2ecf20Sopenharmony_ci *
9328c2ecf20Sopenharmony_ci * This called with hw lock held
9338c2ecf20Sopenharmony_ci */
9348c2ecf20Sopenharmony_cistatic void
9358c2ecf20Sopenharmony_cicsio_post_event_rns(struct csio_lnode *ln, enum csio_rn_ev evt)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
9388c2ecf20Sopenharmony_ci	struct list_head *tmp, *next;
9398c2ecf20Sopenharmony_ci	struct csio_rnode *rn;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	list_for_each_safe(tmp, next, &rnhead->sm.sm_list) {
9428c2ecf20Sopenharmony_ci		rn = (struct csio_rnode *) tmp;
9438c2ecf20Sopenharmony_ci		csio_post_event(&rn->sm, evt);
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci/*
9488c2ecf20Sopenharmony_ci * csio_cleanup_rns
9498c2ecf20Sopenharmony_ci * @ln - FCOE lnode
9508c2ecf20Sopenharmony_ci * Returns - none
9518c2ecf20Sopenharmony_ci *
9528c2ecf20Sopenharmony_ci * Frees all FCOE rnodes connected with given Lnode.
9538c2ecf20Sopenharmony_ci *
9548c2ecf20Sopenharmony_ci * This called with hw lock held
9558c2ecf20Sopenharmony_ci */
9568c2ecf20Sopenharmony_cistatic void
9578c2ecf20Sopenharmony_cicsio_cleanup_rns(struct csio_lnode *ln)
9588c2ecf20Sopenharmony_ci{
9598c2ecf20Sopenharmony_ci	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
9608c2ecf20Sopenharmony_ci	struct list_head *tmp, *next_rn;
9618c2ecf20Sopenharmony_ci	struct csio_rnode *rn;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	list_for_each_safe(tmp, next_rn, &rnhead->sm.sm_list) {
9648c2ecf20Sopenharmony_ci		rn = (struct csio_rnode *) tmp;
9658c2ecf20Sopenharmony_ci		csio_put_rnode(ln, rn);
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci/*
9718c2ecf20Sopenharmony_ci * csio_post_event_lns
9728c2ecf20Sopenharmony_ci * @ln - FCOE lnode
9738c2ecf20Sopenharmony_ci * @evt - Given lnode event
9748c2ecf20Sopenharmony_ci * Returns - none
9758c2ecf20Sopenharmony_ci *
9768c2ecf20Sopenharmony_ci * Posts given lnode event to all FCOE lnodes connected with given Lnode.
9778c2ecf20Sopenharmony_ci * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE
9788c2ecf20Sopenharmony_ci * event.
9798c2ecf20Sopenharmony_ci *
9808c2ecf20Sopenharmony_ci * This called with hw lock held
9818c2ecf20Sopenharmony_ci */
9828c2ecf20Sopenharmony_cistatic void
9838c2ecf20Sopenharmony_cicsio_post_event_lns(struct csio_lnode *ln, enum csio_ln_ev evt)
9848c2ecf20Sopenharmony_ci{
9858c2ecf20Sopenharmony_ci	struct list_head *tmp;
9868c2ecf20Sopenharmony_ci	struct csio_lnode *cln, *sln;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	/* If NPIV lnode, send evt only to that and return */
9898c2ecf20Sopenharmony_ci	if (csio_is_npiv_ln(ln)) {
9908c2ecf20Sopenharmony_ci		csio_post_event(&ln->sm, evt);
9918c2ecf20Sopenharmony_ci		return;
9928c2ecf20Sopenharmony_ci	}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	sln = ln;
9958c2ecf20Sopenharmony_ci	/* Traverse children lnodes list and send evt */
9968c2ecf20Sopenharmony_ci	list_for_each(tmp, &sln->cln_head) {
9978c2ecf20Sopenharmony_ci		cln = (struct csio_lnode *) tmp;
9988c2ecf20Sopenharmony_ci		csio_post_event(&cln->sm, evt);
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	/* Send evt to parent lnode */
10028c2ecf20Sopenharmony_ci	csio_post_event(&ln->sm, evt);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci/*
10068c2ecf20Sopenharmony_ci * csio_ln_down - Lcoal nport is down
10078c2ecf20Sopenharmony_ci * @ln - FCOE Lnode
10088c2ecf20Sopenharmony_ci * Returns - none
10098c2ecf20Sopenharmony_ci *
10108c2ecf20Sopenharmony_ci * Sends LINK_DOWN events to Lnode and its associated NPIVs lnodes.
10118c2ecf20Sopenharmony_ci *
10128c2ecf20Sopenharmony_ci * This called with hw lock held
10138c2ecf20Sopenharmony_ci */
10148c2ecf20Sopenharmony_cistatic void
10158c2ecf20Sopenharmony_cicsio_ln_down(struct csio_lnode *ln)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	csio_post_event_lns(ln, CSIO_LNE_LINK_DOWN);
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci/*
10218c2ecf20Sopenharmony_ci * csio_handle_link_down - Logical Linkdown event.
10228c2ecf20Sopenharmony_ci * @hw - HW module.
10238c2ecf20Sopenharmony_ci * @portid - Physical port number
10248c2ecf20Sopenharmony_ci * @fcfi - FCF index.
10258c2ecf20Sopenharmony_ci * @vnpi - VNP index.
10268c2ecf20Sopenharmony_ci * Returns - none
10278c2ecf20Sopenharmony_ci *
10288c2ecf20Sopenharmony_ci * This event is received from FW, when virtual link goes down between
10298c2ecf20Sopenharmony_ci * Physical port[ENode] and FCF. Lnode and its associated NPIVs lnode hosted on
10308c2ecf20Sopenharmony_ci * this vnpi[VN-Port] will be de-instantiated.
10318c2ecf20Sopenharmony_ci *
10328c2ecf20Sopenharmony_ci * This called with hw lock held
10338c2ecf20Sopenharmony_ci */
10348c2ecf20Sopenharmony_cistatic void
10358c2ecf20Sopenharmony_cicsio_handle_link_down(struct csio_hw *hw, uint8_t portid, uint32_t fcfi,
10368c2ecf20Sopenharmony_ci		      uint32_t vnpi)
10378c2ecf20Sopenharmony_ci{
10388c2ecf20Sopenharmony_ci	struct csio_fcf_info *fp;
10398c2ecf20Sopenharmony_ci	struct csio_lnode *ln;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	/* Lookup lnode based on vnpi */
10428c2ecf20Sopenharmony_ci	ln = csio_ln_lookup_by_vnpi(hw, vnpi);
10438c2ecf20Sopenharmony_ci	if (ln) {
10448c2ecf20Sopenharmony_ci		fp = ln->fcfinfo;
10458c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_link_down);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci		/*Warn if linkdown received if lnode is not in ready state */
10488c2ecf20Sopenharmony_ci		if (!csio_is_lnode_ready(ln)) {
10498c2ecf20Sopenharmony_ci			csio_ln_warn(ln,
10508c2ecf20Sopenharmony_ci				"warn: FCOE link is already in offline "
10518c2ecf20Sopenharmony_ci				"Ignoring Fcoe linkdown event on portid %d\n",
10528c2ecf20Sopenharmony_ci				 portid);
10538c2ecf20Sopenharmony_ci			CSIO_INC_STATS(ln, n_evt_drop);
10548c2ecf20Sopenharmony_ci			return;
10558c2ecf20Sopenharmony_ci		}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci		/* Verify portid */
10588c2ecf20Sopenharmony_ci		if (fp->portid != portid) {
10598c2ecf20Sopenharmony_ci			csio_ln_warn(ln,
10608c2ecf20Sopenharmony_ci				"warn: FCOE linkdown recv with "
10618c2ecf20Sopenharmony_ci				"invalid port %d\n", portid);
10628c2ecf20Sopenharmony_ci			CSIO_INC_STATS(ln, n_evt_drop);
10638c2ecf20Sopenharmony_ci			return;
10648c2ecf20Sopenharmony_ci		}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci		/* verify fcfi */
10678c2ecf20Sopenharmony_ci		if (ln->fcf_flowid != fcfi) {
10688c2ecf20Sopenharmony_ci			csio_ln_warn(ln,
10698c2ecf20Sopenharmony_ci				"warn: FCOE linkdown recv with "
10708c2ecf20Sopenharmony_ci				"invalid fcfi x%x\n", fcfi);
10718c2ecf20Sopenharmony_ci			CSIO_INC_STATS(ln, n_evt_drop);
10728c2ecf20Sopenharmony_ci			return;
10738c2ecf20Sopenharmony_ci		}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci		csio_info(hw, "Port:%d - FCOE LINK DOWN\n", portid);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		/* Send LINK_DOWN event to lnode s/m */
10788c2ecf20Sopenharmony_ci		csio_ln_down(ln);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci		return;
10818c2ecf20Sopenharmony_ci	} else {
10828c2ecf20Sopenharmony_ci		csio_warn(hw,
10838c2ecf20Sopenharmony_ci			  "warn: FCOE linkdown recv with invalid vnpi x%x\n",
10848c2ecf20Sopenharmony_ci			  vnpi);
10858c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_evt_drop);
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci/*
10908c2ecf20Sopenharmony_ci * csio_is_lnode_ready - Checks FCOE lnode is in ready state.
10918c2ecf20Sopenharmony_ci * @ln: Lnode module
10928c2ecf20Sopenharmony_ci *
10938c2ecf20Sopenharmony_ci * Returns True if FCOE lnode is in ready state.
10948c2ecf20Sopenharmony_ci */
10958c2ecf20Sopenharmony_ciint
10968c2ecf20Sopenharmony_cicsio_is_lnode_ready(struct csio_lnode *ln)
10978c2ecf20Sopenharmony_ci{
10988c2ecf20Sopenharmony_ci	return (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready));
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci/*****************************************************************************/
11028c2ecf20Sopenharmony_ci/* START: Lnode SM                                                           */
11038c2ecf20Sopenharmony_ci/*****************************************************************************/
11048c2ecf20Sopenharmony_ci/*
11058c2ecf20Sopenharmony_ci * csio_lns_uninit - The request in uninit state.
11068c2ecf20Sopenharmony_ci * @ln - FCOE lnode.
11078c2ecf20Sopenharmony_ci * @evt - Event to be processed.
11088c2ecf20Sopenharmony_ci *
11098c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "uninit" state.
11108c2ecf20Sopenharmony_ci * Invoked with HW lock held.
11118c2ecf20Sopenharmony_ci * Return - none.
11128c2ecf20Sopenharmony_ci */
11138c2ecf20Sopenharmony_cistatic void
11148c2ecf20Sopenharmony_cicsio_lns_uninit(struct csio_lnode *ln, enum csio_ln_ev evt)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
11178c2ecf20Sopenharmony_ci	struct csio_lnode *rln = hw->rln;
11188c2ecf20Sopenharmony_ci	int rv;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	CSIO_INC_STATS(ln, n_evt_sm[evt]);
11218c2ecf20Sopenharmony_ci	switch (evt) {
11228c2ecf20Sopenharmony_ci	case CSIO_LNE_LINKUP:
11238c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_online);
11248c2ecf20Sopenharmony_ci		/* Read FCF only for physical lnode */
11258c2ecf20Sopenharmony_ci		if (csio_is_phys_ln(ln)) {
11268c2ecf20Sopenharmony_ci			rv = csio_ln_read_fcf_entry(ln,
11278c2ecf20Sopenharmony_ci					csio_ln_read_fcf_cbfn);
11288c2ecf20Sopenharmony_ci			if (rv != 0) {
11298c2ecf20Sopenharmony_ci				/* TODO: Send HW RESET event */
11308c2ecf20Sopenharmony_ci				CSIO_INC_STATS(ln, n_err);
11318c2ecf20Sopenharmony_ci				break;
11328c2ecf20Sopenharmony_ci			}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci			/* Add FCF record */
11358c2ecf20Sopenharmony_ci			list_add_tail(&ln->fcfinfo->list, &rln->fcf_lsthead);
11368c2ecf20Sopenharmony_ci		}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci		rv = csio_ln_vnp_read(ln, csio_ln_vnp_read_cbfn);
11398c2ecf20Sopenharmony_ci		if (rv != 0) {
11408c2ecf20Sopenharmony_ci			/* TODO: Send HW RESET event */
11418c2ecf20Sopenharmony_ci			CSIO_INC_STATS(ln, n_err);
11428c2ecf20Sopenharmony_ci		}
11438c2ecf20Sopenharmony_ci		break;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	case CSIO_LNE_DOWN_LINK:
11468c2ecf20Sopenharmony_ci		break;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	default:
11498c2ecf20Sopenharmony_ci		csio_ln_dbg(ln,
11508c2ecf20Sopenharmony_ci			    "unexp ln event %d recv from did:x%x in "
11518c2ecf20Sopenharmony_ci			    "ln state[uninit].\n", evt, ln->nport_id);
11528c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_evt_unexp);
11538c2ecf20Sopenharmony_ci		break;
11548c2ecf20Sopenharmony_ci	} /* switch event */
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci/*
11588c2ecf20Sopenharmony_ci * csio_lns_online - The request in online state.
11598c2ecf20Sopenharmony_ci * @ln - FCOE lnode.
11608c2ecf20Sopenharmony_ci * @evt - Event to be processed.
11618c2ecf20Sopenharmony_ci *
11628c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "online" state.
11638c2ecf20Sopenharmony_ci * Invoked with HW lock held.
11648c2ecf20Sopenharmony_ci * Return - none.
11658c2ecf20Sopenharmony_ci */
11668c2ecf20Sopenharmony_cistatic void
11678c2ecf20Sopenharmony_cicsio_lns_online(struct csio_lnode *ln, enum csio_ln_ev evt)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	CSIO_INC_STATS(ln, n_evt_sm[evt]);
11728c2ecf20Sopenharmony_ci	switch (evt) {
11738c2ecf20Sopenharmony_ci	case CSIO_LNE_LINKUP:
11748c2ecf20Sopenharmony_ci		csio_ln_warn(ln,
11758c2ecf20Sopenharmony_ci			     "warn: FCOE link is up already "
11768c2ecf20Sopenharmony_ci			     "Ignoring linkup on port:%d\n", ln->portid);
11778c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_evt_drop);
11788c2ecf20Sopenharmony_ci		break;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	case CSIO_LNE_FAB_INIT_DONE:
11818c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_ready);
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci		spin_unlock_irq(&hw->lock);
11848c2ecf20Sopenharmony_ci		csio_lnode_async_event(ln, CSIO_LN_FC_LINKUP);
11858c2ecf20Sopenharmony_ci		spin_lock_irq(&hw->lock);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci		break;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	case CSIO_LNE_LINK_DOWN:
11908c2ecf20Sopenharmony_ci	case CSIO_LNE_DOWN_LINK:
11918c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_uninit);
11928c2ecf20Sopenharmony_ci		if (csio_is_phys_ln(ln)) {
11938c2ecf20Sopenharmony_ci			/* Remove FCF entry */
11948c2ecf20Sopenharmony_ci			list_del_init(&ln->fcfinfo->list);
11958c2ecf20Sopenharmony_ci		}
11968c2ecf20Sopenharmony_ci		break;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	default:
11998c2ecf20Sopenharmony_ci		csio_ln_dbg(ln,
12008c2ecf20Sopenharmony_ci			    "unexp ln event %d recv from did:x%x in "
12018c2ecf20Sopenharmony_ci			    "ln state[uninit].\n", evt, ln->nport_id);
12028c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_evt_unexp);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci		break;
12058c2ecf20Sopenharmony_ci	} /* switch event */
12068c2ecf20Sopenharmony_ci}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci/*
12098c2ecf20Sopenharmony_ci * csio_lns_ready - The request in ready state.
12108c2ecf20Sopenharmony_ci * @ln - FCOE lnode.
12118c2ecf20Sopenharmony_ci * @evt - Event to be processed.
12128c2ecf20Sopenharmony_ci *
12138c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "ready" state.
12148c2ecf20Sopenharmony_ci * Invoked with HW lock held.
12158c2ecf20Sopenharmony_ci * Return - none.
12168c2ecf20Sopenharmony_ci */
12178c2ecf20Sopenharmony_cistatic void
12188c2ecf20Sopenharmony_cicsio_lns_ready(struct csio_lnode *ln, enum csio_ln_ev evt)
12198c2ecf20Sopenharmony_ci{
12208c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	CSIO_INC_STATS(ln, n_evt_sm[evt]);
12238c2ecf20Sopenharmony_ci	switch (evt) {
12248c2ecf20Sopenharmony_ci	case CSIO_LNE_FAB_INIT_DONE:
12258c2ecf20Sopenharmony_ci		csio_ln_dbg(ln,
12268c2ecf20Sopenharmony_ci			    "ignoring event %d recv from did x%x"
12278c2ecf20Sopenharmony_ci			    "in ln state[ready].\n", evt, ln->nport_id);
12288c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_evt_drop);
12298c2ecf20Sopenharmony_ci		break;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	case CSIO_LNE_LINK_DOWN:
12328c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_offline);
12338c2ecf20Sopenharmony_ci		csio_post_event_rns(ln, CSIO_RNFE_DOWN);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci		spin_unlock_irq(&hw->lock);
12368c2ecf20Sopenharmony_ci		csio_lnode_async_event(ln, CSIO_LN_FC_LINKDOWN);
12378c2ecf20Sopenharmony_ci		spin_lock_irq(&hw->lock);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci		if (csio_is_phys_ln(ln)) {
12408c2ecf20Sopenharmony_ci			/* Remove FCF entry */
12418c2ecf20Sopenharmony_ci			list_del_init(&ln->fcfinfo->list);
12428c2ecf20Sopenharmony_ci		}
12438c2ecf20Sopenharmony_ci		break;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	case CSIO_LNE_DOWN_LINK:
12468c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_offline);
12478c2ecf20Sopenharmony_ci		csio_post_event_rns(ln, CSIO_RNFE_DOWN);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci		/* Host need to issue aborts in case if FW has not returned
12508c2ecf20Sopenharmony_ci		 * WRs with status "ABORTED"
12518c2ecf20Sopenharmony_ci		 */
12528c2ecf20Sopenharmony_ci		spin_unlock_irq(&hw->lock);
12538c2ecf20Sopenharmony_ci		csio_lnode_async_event(ln, CSIO_LN_FC_LINKDOWN);
12548c2ecf20Sopenharmony_ci		spin_lock_irq(&hw->lock);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci		if (csio_is_phys_ln(ln)) {
12578c2ecf20Sopenharmony_ci			/* Remove FCF entry */
12588c2ecf20Sopenharmony_ci			list_del_init(&ln->fcfinfo->list);
12598c2ecf20Sopenharmony_ci		}
12608c2ecf20Sopenharmony_ci		break;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	case CSIO_LNE_CLOSE:
12638c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_uninit);
12648c2ecf20Sopenharmony_ci		csio_post_event_rns(ln, CSIO_RNFE_CLOSE);
12658c2ecf20Sopenharmony_ci		break;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	case CSIO_LNE_LOGO:
12688c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_offline);
12698c2ecf20Sopenharmony_ci		csio_post_event_rns(ln, CSIO_RNFE_DOWN);
12708c2ecf20Sopenharmony_ci		break;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	default:
12738c2ecf20Sopenharmony_ci		csio_ln_dbg(ln,
12748c2ecf20Sopenharmony_ci			    "unexp ln event %d recv from did:x%x in "
12758c2ecf20Sopenharmony_ci			    "ln state[uninit].\n", evt, ln->nport_id);
12768c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_evt_unexp);
12778c2ecf20Sopenharmony_ci		CSIO_DB_ASSERT(0);
12788c2ecf20Sopenharmony_ci		break;
12798c2ecf20Sopenharmony_ci	} /* switch event */
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci/*
12838c2ecf20Sopenharmony_ci * csio_lns_offline - The request in offline state.
12848c2ecf20Sopenharmony_ci * @ln - FCOE lnode.
12858c2ecf20Sopenharmony_ci * @evt - Event to be processed.
12868c2ecf20Sopenharmony_ci *
12878c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "offline" state.
12888c2ecf20Sopenharmony_ci * Invoked with HW lock held.
12898c2ecf20Sopenharmony_ci * Return - none.
12908c2ecf20Sopenharmony_ci */
12918c2ecf20Sopenharmony_cistatic void
12928c2ecf20Sopenharmony_cicsio_lns_offline(struct csio_lnode *ln, enum csio_ln_ev evt)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
12958c2ecf20Sopenharmony_ci	struct csio_lnode *rln = hw->rln;
12968c2ecf20Sopenharmony_ci	int rv;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	CSIO_INC_STATS(ln, n_evt_sm[evt]);
12998c2ecf20Sopenharmony_ci	switch (evt) {
13008c2ecf20Sopenharmony_ci	case CSIO_LNE_LINKUP:
13018c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_online);
13028c2ecf20Sopenharmony_ci		/* Read FCF only for physical lnode */
13038c2ecf20Sopenharmony_ci		if (csio_is_phys_ln(ln)) {
13048c2ecf20Sopenharmony_ci			rv = csio_ln_read_fcf_entry(ln,
13058c2ecf20Sopenharmony_ci					csio_ln_read_fcf_cbfn);
13068c2ecf20Sopenharmony_ci			if (rv != 0) {
13078c2ecf20Sopenharmony_ci				/* TODO: Send HW RESET event */
13088c2ecf20Sopenharmony_ci				CSIO_INC_STATS(ln, n_err);
13098c2ecf20Sopenharmony_ci				break;
13108c2ecf20Sopenharmony_ci			}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci			/* Add FCF record */
13138c2ecf20Sopenharmony_ci			list_add_tail(&ln->fcfinfo->list, &rln->fcf_lsthead);
13148c2ecf20Sopenharmony_ci		}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci		rv = csio_ln_vnp_read(ln, csio_ln_vnp_read_cbfn);
13178c2ecf20Sopenharmony_ci		if (rv != 0) {
13188c2ecf20Sopenharmony_ci			/* TODO: Send HW RESET event */
13198c2ecf20Sopenharmony_ci			CSIO_INC_STATS(ln, n_err);
13208c2ecf20Sopenharmony_ci		}
13218c2ecf20Sopenharmony_ci		break;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	case CSIO_LNE_LINK_DOWN:
13248c2ecf20Sopenharmony_ci	case CSIO_LNE_DOWN_LINK:
13258c2ecf20Sopenharmony_ci	case CSIO_LNE_LOGO:
13268c2ecf20Sopenharmony_ci		csio_ln_dbg(ln,
13278c2ecf20Sopenharmony_ci			    "ignoring event %d recv from did x%x"
13288c2ecf20Sopenharmony_ci			    "in ln state[offline].\n", evt, ln->nport_id);
13298c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_evt_drop);
13308c2ecf20Sopenharmony_ci		break;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	case CSIO_LNE_CLOSE:
13338c2ecf20Sopenharmony_ci		csio_set_state(&ln->sm, csio_lns_uninit);
13348c2ecf20Sopenharmony_ci		csio_post_event_rns(ln, CSIO_RNFE_CLOSE);
13358c2ecf20Sopenharmony_ci		break;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	default:
13388c2ecf20Sopenharmony_ci		csio_ln_dbg(ln,
13398c2ecf20Sopenharmony_ci			    "unexp ln event %d recv from did:x%x in "
13408c2ecf20Sopenharmony_ci			    "ln state[offline]\n", evt, ln->nport_id);
13418c2ecf20Sopenharmony_ci		CSIO_INC_STATS(ln, n_evt_unexp);
13428c2ecf20Sopenharmony_ci		CSIO_DB_ASSERT(0);
13438c2ecf20Sopenharmony_ci		break;
13448c2ecf20Sopenharmony_ci	} /* switch event */
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci/*****************************************************************************/
13488c2ecf20Sopenharmony_ci/* END: Lnode SM                                                             */
13498c2ecf20Sopenharmony_ci/*****************************************************************************/
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_cistatic void
13528c2ecf20Sopenharmony_cicsio_free_fcfinfo(struct kref *kref)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	struct csio_fcf_info *fcfinfo = container_of(kref,
13558c2ecf20Sopenharmony_ci						struct csio_fcf_info, kref);
13568c2ecf20Sopenharmony_ci	kfree(fcfinfo);
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci/* Helper routines for attributes  */
13608c2ecf20Sopenharmony_ci/*
13618c2ecf20Sopenharmony_ci * csio_lnode_state_to_str - Get current state of FCOE lnode.
13628c2ecf20Sopenharmony_ci * @ln - lnode
13638c2ecf20Sopenharmony_ci * @str - state of lnode.
13648c2ecf20Sopenharmony_ci *
13658c2ecf20Sopenharmony_ci */
13668c2ecf20Sopenharmony_civoid
13678c2ecf20Sopenharmony_cicsio_lnode_state_to_str(struct csio_lnode *ln, int8_t *str)
13688c2ecf20Sopenharmony_ci{
13698c2ecf20Sopenharmony_ci	if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_uninit)) {
13708c2ecf20Sopenharmony_ci		strcpy(str, "UNINIT");
13718c2ecf20Sopenharmony_ci		return;
13728c2ecf20Sopenharmony_ci	}
13738c2ecf20Sopenharmony_ci	if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)) {
13748c2ecf20Sopenharmony_ci		strcpy(str, "READY");
13758c2ecf20Sopenharmony_ci		return;
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci	if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_offline)) {
13788c2ecf20Sopenharmony_ci		strcpy(str, "OFFLINE");
13798c2ecf20Sopenharmony_ci		return;
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci	strcpy(str, "UNKNOWN");
13828c2ecf20Sopenharmony_ci} /* csio_lnode_state_to_str */
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ciint
13868c2ecf20Sopenharmony_cicsio_get_phy_port_stats(struct csio_hw *hw, uint8_t portid,
13878c2ecf20Sopenharmony_ci			struct fw_fcoe_port_stats *port_stats)
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	struct csio_mb  *mbp;
13908c2ecf20Sopenharmony_ci	struct fw_fcoe_port_cmd_params portparams;
13918c2ecf20Sopenharmony_ci	enum fw_retval retval;
13928c2ecf20Sopenharmony_ci	int idx;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
13958c2ecf20Sopenharmony_ci	if (!mbp) {
13968c2ecf20Sopenharmony_ci		csio_err(hw, "FCoE FCF PARAMS command out of memory!\n");
13978c2ecf20Sopenharmony_ci		return -EINVAL;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci	portparams.portid = portid;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	for (idx = 1; idx <= 3; idx++) {
14028c2ecf20Sopenharmony_ci		portparams.idx = (idx-1)*6 + 1;
14038c2ecf20Sopenharmony_ci		portparams.nstats = 6;
14048c2ecf20Sopenharmony_ci		if (idx == 3)
14058c2ecf20Sopenharmony_ci			portparams.nstats = 4;
14068c2ecf20Sopenharmony_ci		csio_fcoe_read_portparams_init_mb(hw, mbp, CSIO_MB_DEFAULT_TMO,
14078c2ecf20Sopenharmony_ci							&portparams, NULL);
14088c2ecf20Sopenharmony_ci		if (csio_mb_issue(hw, mbp)) {
14098c2ecf20Sopenharmony_ci			csio_err(hw, "Issue of FCoE port params failed!\n");
14108c2ecf20Sopenharmony_ci			mempool_free(mbp, hw->mb_mempool);
14118c2ecf20Sopenharmony_ci			return -EINVAL;
14128c2ecf20Sopenharmony_ci		}
14138c2ecf20Sopenharmony_ci		csio_mb_process_portparams_rsp(hw, mbp, &retval,
14148c2ecf20Sopenharmony_ci						&portparams, port_stats);
14158c2ecf20Sopenharmony_ci	}
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	mempool_free(mbp, hw->mb_mempool);
14188c2ecf20Sopenharmony_ci	return 0;
14198c2ecf20Sopenharmony_ci}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci/*
14228c2ecf20Sopenharmony_ci * csio_ln_mgmt_wr_handler -Mgmt Work Request handler.
14238c2ecf20Sopenharmony_ci * @wr - WR.
14248c2ecf20Sopenharmony_ci * @len - WR len.
14258c2ecf20Sopenharmony_ci * This handler is invoked when an outstanding mgmt WR is completed.
14268c2ecf20Sopenharmony_ci * Its invoked in the context of FW event worker thread for every
14278c2ecf20Sopenharmony_ci * mgmt event received.
14288c2ecf20Sopenharmony_ci * Return - none.
14298c2ecf20Sopenharmony_ci */
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_cistatic void
14328c2ecf20Sopenharmony_cicsio_ln_mgmt_wr_handler(struct csio_hw *hw, void *wr, uint32_t len)
14338c2ecf20Sopenharmony_ci{
14348c2ecf20Sopenharmony_ci	struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw);
14358c2ecf20Sopenharmony_ci	struct csio_ioreq *io_req = NULL;
14368c2ecf20Sopenharmony_ci	struct fw_fcoe_els_ct_wr *wr_cmd;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	wr_cmd = (struct fw_fcoe_els_ct_wr *) wr;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	if (len < sizeof(struct fw_fcoe_els_ct_wr)) {
14428c2ecf20Sopenharmony_ci		csio_err(mgmtm->hw,
14438c2ecf20Sopenharmony_ci			 "Invalid ELS CT WR length recvd, len:%x\n", len);
14448c2ecf20Sopenharmony_ci		mgmtm->stats.n_err++;
14458c2ecf20Sopenharmony_ci		return;
14468c2ecf20Sopenharmony_ci	}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	io_req = (struct csio_ioreq *) ((uintptr_t) wr_cmd->cookie);
14498c2ecf20Sopenharmony_ci	io_req->wr_status = csio_wr_status(wr_cmd);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	/* lookup ioreq exists in our active Q */
14528c2ecf20Sopenharmony_ci	spin_lock_irq(&hw->lock);
14538c2ecf20Sopenharmony_ci	if (csio_mgmt_req_lookup(mgmtm, io_req) != 0) {
14548c2ecf20Sopenharmony_ci		csio_err(mgmtm->hw,
14558c2ecf20Sopenharmony_ci			"Error- Invalid IO handle recv in WR. handle: %p\n",
14568c2ecf20Sopenharmony_ci			io_req);
14578c2ecf20Sopenharmony_ci		mgmtm->stats.n_err++;
14588c2ecf20Sopenharmony_ci		spin_unlock_irq(&hw->lock);
14598c2ecf20Sopenharmony_ci		return;
14608c2ecf20Sopenharmony_ci	}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	mgmtm = csio_hw_to_mgmtm(hw);
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	/* Dequeue from active queue */
14658c2ecf20Sopenharmony_ci	list_del_init(&io_req->sm.sm_list);
14668c2ecf20Sopenharmony_ci	mgmtm->stats.n_active--;
14678c2ecf20Sopenharmony_ci	spin_unlock_irq(&hw->lock);
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	/* io_req will be freed by completion handler */
14708c2ecf20Sopenharmony_ci	if (io_req->io_cbfn)
14718c2ecf20Sopenharmony_ci		io_req->io_cbfn(hw, io_req);
14728c2ecf20Sopenharmony_ci}
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci/**
14758c2ecf20Sopenharmony_ci * csio_fcoe_fwevt_handler - Event handler for Firmware FCoE events.
14768c2ecf20Sopenharmony_ci * @hw:		HW module
14778c2ecf20Sopenharmony_ci * @cpl_op:	CPL opcode
14788c2ecf20Sopenharmony_ci * @cmd:	FW cmd/WR.
14798c2ecf20Sopenharmony_ci *
14808c2ecf20Sopenharmony_ci * Process received FCoE cmd/WR event from FW.
14818c2ecf20Sopenharmony_ci */
14828c2ecf20Sopenharmony_civoid
14838c2ecf20Sopenharmony_cicsio_fcoe_fwevt_handler(struct csio_hw *hw, __u8 cpl_op, __be64 *cmd)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	struct csio_lnode *ln;
14868c2ecf20Sopenharmony_ci	struct csio_rnode *rn;
14878c2ecf20Sopenharmony_ci	uint8_t portid, opcode = *(uint8_t *)cmd;
14888c2ecf20Sopenharmony_ci	struct fw_fcoe_link_cmd *lcmd;
14898c2ecf20Sopenharmony_ci	struct fw_wr_hdr *wr;
14908c2ecf20Sopenharmony_ci	struct fw_rdev_wr *rdev_wr;
14918c2ecf20Sopenharmony_ci	enum fw_fcoe_link_status lstatus;
14928c2ecf20Sopenharmony_ci	uint32_t fcfi, rdev_flowid, vnpi;
14938c2ecf20Sopenharmony_ci	enum csio_ln_ev evt;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	if (cpl_op == CPL_FW6_MSG && opcode == FW_FCOE_LINK_CMD) {
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci		lcmd = (struct fw_fcoe_link_cmd *)cmd;
14988c2ecf20Sopenharmony_ci		lstatus = lcmd->lstatus;
14998c2ecf20Sopenharmony_ci		portid = FW_FCOE_LINK_CMD_PORTID_GET(
15008c2ecf20Sopenharmony_ci					ntohl(lcmd->op_to_portid));
15018c2ecf20Sopenharmony_ci		fcfi = FW_FCOE_LINK_CMD_FCFI_GET(ntohl(lcmd->sub_opcode_fcfi));
15028c2ecf20Sopenharmony_ci		vnpi = FW_FCOE_LINK_CMD_VNPI_GET(ntohl(lcmd->vnpi_pkd));
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci		if (lstatus == FCOE_LINKUP) {
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci			/* HW lock here */
15078c2ecf20Sopenharmony_ci			spin_lock_irq(&hw->lock);
15088c2ecf20Sopenharmony_ci			csio_handle_link_up(hw, portid, fcfi, vnpi);
15098c2ecf20Sopenharmony_ci			spin_unlock_irq(&hw->lock);
15108c2ecf20Sopenharmony_ci			/* HW un lock here */
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci		} else if (lstatus == FCOE_LINKDOWN) {
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci			/* HW lock here */
15158c2ecf20Sopenharmony_ci			spin_lock_irq(&hw->lock);
15168c2ecf20Sopenharmony_ci			csio_handle_link_down(hw, portid, fcfi, vnpi);
15178c2ecf20Sopenharmony_ci			spin_unlock_irq(&hw->lock);
15188c2ecf20Sopenharmony_ci			/* HW un lock here */
15198c2ecf20Sopenharmony_ci		} else {
15208c2ecf20Sopenharmony_ci			csio_warn(hw, "Unexpected FCOE LINK status:0x%x\n",
15218c2ecf20Sopenharmony_ci				  lcmd->lstatus);
15228c2ecf20Sopenharmony_ci			CSIO_INC_STATS(hw, n_cpl_unexp);
15238c2ecf20Sopenharmony_ci		}
15248c2ecf20Sopenharmony_ci	} else if (cpl_op == CPL_FW6_PLD) {
15258c2ecf20Sopenharmony_ci		wr = (struct fw_wr_hdr *) (cmd + 4);
15268c2ecf20Sopenharmony_ci		if (FW_WR_OP_G(be32_to_cpu(wr->hi))
15278c2ecf20Sopenharmony_ci			== FW_RDEV_WR) {
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci			rdev_wr = (struct fw_rdev_wr *) (cmd + 4);
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci			rdev_flowid = FW_RDEV_WR_FLOWID_GET(
15328c2ecf20Sopenharmony_ci					ntohl(rdev_wr->alloc_to_len16));
15338c2ecf20Sopenharmony_ci			vnpi = FW_RDEV_WR_ASSOC_FLOWID_GET(
15348c2ecf20Sopenharmony_ci				    ntohl(rdev_wr->flags_to_assoc_flowid));
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci			csio_dbg(hw,
15378c2ecf20Sopenharmony_ci				"FW_RDEV_WR: flowid:x%x ev_cause:x%x "
15388c2ecf20Sopenharmony_ci				"vnpi:0x%x\n", rdev_flowid,
15398c2ecf20Sopenharmony_ci				rdev_wr->event_cause, vnpi);
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci			if (rdev_wr->protocol != PROT_FCOE) {
15428c2ecf20Sopenharmony_ci				csio_err(hw,
15438c2ecf20Sopenharmony_ci					"FW_RDEV_WR: invalid proto:x%x "
15448c2ecf20Sopenharmony_ci					"received with flowid:x%x\n",
15458c2ecf20Sopenharmony_ci					rdev_wr->protocol,
15468c2ecf20Sopenharmony_ci					rdev_flowid);
15478c2ecf20Sopenharmony_ci				CSIO_INC_STATS(hw, n_evt_drop);
15488c2ecf20Sopenharmony_ci				return;
15498c2ecf20Sopenharmony_ci			}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci			/* HW lock here */
15528c2ecf20Sopenharmony_ci			spin_lock_irq(&hw->lock);
15538c2ecf20Sopenharmony_ci			ln = csio_ln_lookup_by_vnpi(hw, vnpi);
15548c2ecf20Sopenharmony_ci			if (!ln) {
15558c2ecf20Sopenharmony_ci				csio_err(hw,
15568c2ecf20Sopenharmony_ci					"FW_DEV_WR: invalid vnpi:x%x received "
15578c2ecf20Sopenharmony_ci					"with flowid:x%x\n", vnpi, rdev_flowid);
15588c2ecf20Sopenharmony_ci				CSIO_INC_STATS(hw, n_evt_drop);
15598c2ecf20Sopenharmony_ci				goto out_pld;
15608c2ecf20Sopenharmony_ci			}
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci			rn = csio_confirm_rnode(ln, rdev_flowid,
15638c2ecf20Sopenharmony_ci					&rdev_wr->u.fcoe_rdev);
15648c2ecf20Sopenharmony_ci			if (!rn) {
15658c2ecf20Sopenharmony_ci				csio_ln_dbg(ln,
15668c2ecf20Sopenharmony_ci					"Failed to confirm rnode "
15678c2ecf20Sopenharmony_ci					"for flowid:x%x\n", rdev_flowid);
15688c2ecf20Sopenharmony_ci				CSIO_INC_STATS(hw, n_evt_drop);
15698c2ecf20Sopenharmony_ci				goto out_pld;
15708c2ecf20Sopenharmony_ci			}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci			/* save previous event for debugging */
15738c2ecf20Sopenharmony_ci			ln->prev_evt = ln->cur_evt;
15748c2ecf20Sopenharmony_ci			ln->cur_evt = rdev_wr->event_cause;
15758c2ecf20Sopenharmony_ci			CSIO_INC_STATS(ln, n_evt_fw[rdev_wr->event_cause]);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci			/* Translate all the fabric events to lnode SM events */
15788c2ecf20Sopenharmony_ci			evt = CSIO_FWE_TO_LNE(rdev_wr->event_cause);
15798c2ecf20Sopenharmony_ci			if (evt) {
15808c2ecf20Sopenharmony_ci				csio_ln_dbg(ln,
15818c2ecf20Sopenharmony_ci					"Posting event to lnode event:%d "
15828c2ecf20Sopenharmony_ci					"cause:%d flowid:x%x\n", evt,
15838c2ecf20Sopenharmony_ci					rdev_wr->event_cause, rdev_flowid);
15848c2ecf20Sopenharmony_ci				csio_post_event(&ln->sm, evt);
15858c2ecf20Sopenharmony_ci			}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci			/* Handover event to rn SM here. */
15888c2ecf20Sopenharmony_ci			csio_rnode_fwevt_handler(rn, rdev_wr->event_cause);
15898c2ecf20Sopenharmony_ciout_pld:
15908c2ecf20Sopenharmony_ci			spin_unlock_irq(&hw->lock);
15918c2ecf20Sopenharmony_ci			return;
15928c2ecf20Sopenharmony_ci		} else {
15938c2ecf20Sopenharmony_ci			csio_warn(hw, "unexpected WR op(0x%x) recv\n",
15948c2ecf20Sopenharmony_ci				  FW_WR_OP_G(be32_to_cpu((wr->hi))));
15958c2ecf20Sopenharmony_ci			CSIO_INC_STATS(hw, n_cpl_unexp);
15968c2ecf20Sopenharmony_ci		}
15978c2ecf20Sopenharmony_ci	} else if (cpl_op == CPL_FW6_MSG) {
15988c2ecf20Sopenharmony_ci		wr = (struct fw_wr_hdr *) (cmd);
15998c2ecf20Sopenharmony_ci		if (FW_WR_OP_G(be32_to_cpu(wr->hi)) == FW_FCOE_ELS_CT_WR) {
16008c2ecf20Sopenharmony_ci			csio_ln_mgmt_wr_handler(hw, wr,
16018c2ecf20Sopenharmony_ci					sizeof(struct fw_fcoe_els_ct_wr));
16028c2ecf20Sopenharmony_ci		} else {
16038c2ecf20Sopenharmony_ci			csio_warn(hw, "unexpected WR op(0x%x) recv\n",
16048c2ecf20Sopenharmony_ci				  FW_WR_OP_G(be32_to_cpu((wr->hi))));
16058c2ecf20Sopenharmony_ci			CSIO_INC_STATS(hw, n_cpl_unexp);
16068c2ecf20Sopenharmony_ci		}
16078c2ecf20Sopenharmony_ci	} else {
16088c2ecf20Sopenharmony_ci		csio_warn(hw, "unexpected CPL op(0x%x) recv\n", opcode);
16098c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_cpl_unexp);
16108c2ecf20Sopenharmony_ci	}
16118c2ecf20Sopenharmony_ci}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci/**
16148c2ecf20Sopenharmony_ci * csio_lnode_start - Kickstart lnode discovery.
16158c2ecf20Sopenharmony_ci * @ln:		lnode
16168c2ecf20Sopenharmony_ci *
16178c2ecf20Sopenharmony_ci * This routine kickstarts the discovery by issuing an FCOE_LINK (up) command.
16188c2ecf20Sopenharmony_ci */
16198c2ecf20Sopenharmony_ciint
16208c2ecf20Sopenharmony_cicsio_lnode_start(struct csio_lnode *ln)
16218c2ecf20Sopenharmony_ci{
16228c2ecf20Sopenharmony_ci	int rv = 0;
16238c2ecf20Sopenharmony_ci	if (csio_is_phys_ln(ln) && !(ln->flags & CSIO_LNF_LINK_ENABLE)) {
16248c2ecf20Sopenharmony_ci		rv = csio_fcoe_enable_link(ln, 1);
16258c2ecf20Sopenharmony_ci		ln->flags |= CSIO_LNF_LINK_ENABLE;
16268c2ecf20Sopenharmony_ci	}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	return rv;
16298c2ecf20Sopenharmony_ci}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci/**
16328c2ecf20Sopenharmony_ci * csio_lnode_stop - Stop the lnode.
16338c2ecf20Sopenharmony_ci * @ln:		lnode
16348c2ecf20Sopenharmony_ci *
16358c2ecf20Sopenharmony_ci * This routine is invoked by HW module to stop lnode and its associated NPIV
16368c2ecf20Sopenharmony_ci * lnodes.
16378c2ecf20Sopenharmony_ci */
16388c2ecf20Sopenharmony_civoid
16398c2ecf20Sopenharmony_cicsio_lnode_stop(struct csio_lnode *ln)
16408c2ecf20Sopenharmony_ci{
16418c2ecf20Sopenharmony_ci	csio_post_event_lns(ln, CSIO_LNE_DOWN_LINK);
16428c2ecf20Sopenharmony_ci	if (csio_is_phys_ln(ln) && (ln->flags & CSIO_LNF_LINK_ENABLE)) {
16438c2ecf20Sopenharmony_ci		csio_fcoe_enable_link(ln, 0);
16448c2ecf20Sopenharmony_ci		ln->flags &= ~CSIO_LNF_LINK_ENABLE;
16458c2ecf20Sopenharmony_ci	}
16468c2ecf20Sopenharmony_ci	csio_ln_dbg(ln, "stopping ln :%p\n", ln);
16478c2ecf20Sopenharmony_ci}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci/**
16508c2ecf20Sopenharmony_ci * csio_lnode_close - Close an lnode.
16518c2ecf20Sopenharmony_ci * @ln:		lnode
16528c2ecf20Sopenharmony_ci *
16538c2ecf20Sopenharmony_ci * This routine is invoked by HW module to close an lnode and its
16548c2ecf20Sopenharmony_ci * associated NPIV lnodes. Lnode and its associated NPIV lnodes are
16558c2ecf20Sopenharmony_ci * set to uninitialized state.
16568c2ecf20Sopenharmony_ci */
16578c2ecf20Sopenharmony_civoid
16588c2ecf20Sopenharmony_cicsio_lnode_close(struct csio_lnode *ln)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci	csio_post_event_lns(ln, CSIO_LNE_CLOSE);
16618c2ecf20Sopenharmony_ci	if (csio_is_phys_ln(ln))
16628c2ecf20Sopenharmony_ci		ln->vnp_flowid = CSIO_INVALID_IDX;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	csio_ln_dbg(ln, "closed ln :%p\n", ln);
16658c2ecf20Sopenharmony_ci}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci/*
16688c2ecf20Sopenharmony_ci * csio_ln_prep_ecwr - Prepare ELS/CT WR.
16698c2ecf20Sopenharmony_ci * @io_req - IO request.
16708c2ecf20Sopenharmony_ci * @wr_len - WR len
16718c2ecf20Sopenharmony_ci * @immd_len - WR immediate data
16728c2ecf20Sopenharmony_ci * @sub_op - Sub opcode
16738c2ecf20Sopenharmony_ci * @sid - source portid.
16748c2ecf20Sopenharmony_ci * @did - destination portid
16758c2ecf20Sopenharmony_ci * @flow_id - flowid
16768c2ecf20Sopenharmony_ci * @fw_wr - ELS/CT WR to be prepared.
16778c2ecf20Sopenharmony_ci * Returns: 0 - on success
16788c2ecf20Sopenharmony_ci */
16798c2ecf20Sopenharmony_cistatic int
16808c2ecf20Sopenharmony_cicsio_ln_prep_ecwr(struct csio_ioreq *io_req, uint32_t wr_len,
16818c2ecf20Sopenharmony_ci		      uint32_t immd_len, uint8_t sub_op, uint32_t sid,
16828c2ecf20Sopenharmony_ci		      uint32_t did, uint32_t flow_id, uint8_t *fw_wr)
16838c2ecf20Sopenharmony_ci{
16848c2ecf20Sopenharmony_ci	struct fw_fcoe_els_ct_wr *wr;
16858c2ecf20Sopenharmony_ci	__be32 port_id;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	wr  = (struct fw_fcoe_els_ct_wr *)fw_wr;
16888c2ecf20Sopenharmony_ci	wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_FCOE_ELS_CT_WR) |
16898c2ecf20Sopenharmony_ci				     FW_FCOE_ELS_CT_WR_IMMDLEN(immd_len));
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	wr_len =  DIV_ROUND_UP(wr_len, 16);
16928c2ecf20Sopenharmony_ci	wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(flow_id) |
16938c2ecf20Sopenharmony_ci				       FW_WR_LEN16_V(wr_len));
16948c2ecf20Sopenharmony_ci	wr->els_ct_type = sub_op;
16958c2ecf20Sopenharmony_ci	wr->ctl_pri = 0;
16968c2ecf20Sopenharmony_ci	wr->cp_en_class = 0;
16978c2ecf20Sopenharmony_ci	wr->cookie = io_req->fw_handle;
16988c2ecf20Sopenharmony_ci	wr->iqid = cpu_to_be16(csio_q_physiqid(
16998c2ecf20Sopenharmony_ci					io_req->lnode->hwp, io_req->iq_idx));
17008c2ecf20Sopenharmony_ci	wr->fl_to_sp =  FW_FCOE_ELS_CT_WR_SP(1);
17018c2ecf20Sopenharmony_ci	wr->tmo_val = (uint8_t) io_req->tmo;
17028c2ecf20Sopenharmony_ci	port_id = htonl(sid);
17038c2ecf20Sopenharmony_ci	memcpy(wr->l_id, PORT_ID_PTR(port_id), 3);
17048c2ecf20Sopenharmony_ci	port_id = htonl(did);
17058c2ecf20Sopenharmony_ci	memcpy(wr->r_id, PORT_ID_PTR(port_id), 3);
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	/* Prepare RSP SGL */
17088c2ecf20Sopenharmony_ci	wr->rsp_dmalen = cpu_to_be32(io_req->dma_buf.len);
17098c2ecf20Sopenharmony_ci	wr->rsp_dmaaddr = cpu_to_be64(io_req->dma_buf.paddr);
17108c2ecf20Sopenharmony_ci	return 0;
17118c2ecf20Sopenharmony_ci}
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci/*
17148c2ecf20Sopenharmony_ci * csio_ln_mgmt_submit_wr - Post elsct work request.
17158c2ecf20Sopenharmony_ci * @mgmtm - mgmtm
17168c2ecf20Sopenharmony_ci * @io_req - io request.
17178c2ecf20Sopenharmony_ci * @sub_op - ELS or CT request type
17188c2ecf20Sopenharmony_ci * @pld - Dma Payload buffer
17198c2ecf20Sopenharmony_ci * @pld_len - Payload len
17208c2ecf20Sopenharmony_ci * Prepares ELSCT Work request and sents it to FW.
17218c2ecf20Sopenharmony_ci * Returns: 0 - on success
17228c2ecf20Sopenharmony_ci */
17238c2ecf20Sopenharmony_cistatic int
17248c2ecf20Sopenharmony_cicsio_ln_mgmt_submit_wr(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req,
17258c2ecf20Sopenharmony_ci		uint8_t sub_op, struct csio_dma_buf *pld,
17268c2ecf20Sopenharmony_ci		uint32_t pld_len)
17278c2ecf20Sopenharmony_ci{
17288c2ecf20Sopenharmony_ci	struct csio_wr_pair wrp;
17298c2ecf20Sopenharmony_ci	struct csio_lnode *ln = io_req->lnode;
17308c2ecf20Sopenharmony_ci	struct csio_rnode *rn = io_req->rnode;
17318c2ecf20Sopenharmony_ci	struct	csio_hw	*hw = mgmtm->hw;
17328c2ecf20Sopenharmony_ci	uint8_t fw_wr[64];
17338c2ecf20Sopenharmony_ci	struct ulptx_sgl dsgl;
17348c2ecf20Sopenharmony_ci	uint32_t wr_size = 0;
17358c2ecf20Sopenharmony_ci	uint8_t im_len = 0;
17368c2ecf20Sopenharmony_ci	uint32_t wr_off = 0;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	int ret = 0;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	/* Calculate WR Size for this ELS REQ */
17418c2ecf20Sopenharmony_ci	wr_size = sizeof(struct fw_fcoe_els_ct_wr);
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	/* Send as immediate data if pld < 256 */
17448c2ecf20Sopenharmony_ci	if (pld_len < 256) {
17458c2ecf20Sopenharmony_ci		wr_size += ALIGN(pld_len, 8);
17468c2ecf20Sopenharmony_ci		im_len = (uint8_t)pld_len;
17478c2ecf20Sopenharmony_ci	} else
17488c2ecf20Sopenharmony_ci		wr_size += sizeof(struct ulptx_sgl);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	/* Roundup WR size in units of 16 bytes */
17518c2ecf20Sopenharmony_ci	wr_size = ALIGN(wr_size, 16);
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	/* Get WR to send ELS REQ */
17548c2ecf20Sopenharmony_ci	ret = csio_wr_get(hw, mgmtm->eq_idx, wr_size, &wrp);
17558c2ecf20Sopenharmony_ci	if (ret != 0) {
17568c2ecf20Sopenharmony_ci		csio_err(hw, "Failed to get WR for ec_req %p ret:%d\n",
17578c2ecf20Sopenharmony_ci			io_req, ret);
17588c2ecf20Sopenharmony_ci		return ret;
17598c2ecf20Sopenharmony_ci	}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	/* Prepare Generic WR used by all ELS/CT cmd */
17628c2ecf20Sopenharmony_ci	csio_ln_prep_ecwr(io_req, wr_size, im_len, sub_op,
17638c2ecf20Sopenharmony_ci				ln->nport_id, rn->nport_id,
17648c2ecf20Sopenharmony_ci				csio_rn_flowid(rn),
17658c2ecf20Sopenharmony_ci				&fw_wr[0]);
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	/* Copy ELS/CT WR CMD */
17688c2ecf20Sopenharmony_ci	csio_wr_copy_to_wrp(&fw_wr[0], &wrp, wr_off,
17698c2ecf20Sopenharmony_ci			sizeof(struct fw_fcoe_els_ct_wr));
17708c2ecf20Sopenharmony_ci	wr_off += sizeof(struct fw_fcoe_els_ct_wr);
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	/* Copy payload to Immediate section of WR */
17738c2ecf20Sopenharmony_ci	if (im_len)
17748c2ecf20Sopenharmony_ci		csio_wr_copy_to_wrp(pld->vaddr, &wrp, wr_off, im_len);
17758c2ecf20Sopenharmony_ci	else {
17768c2ecf20Sopenharmony_ci		/* Program DSGL to dma payload */
17778c2ecf20Sopenharmony_ci		dsgl.cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
17788c2ecf20Sopenharmony_ci					ULPTX_MORE_F | ULPTX_NSGE_V(1));
17798c2ecf20Sopenharmony_ci		dsgl.len0 = cpu_to_be32(pld_len);
17808c2ecf20Sopenharmony_ci		dsgl.addr0 = cpu_to_be64(pld->paddr);
17818c2ecf20Sopenharmony_ci		csio_wr_copy_to_wrp(&dsgl, &wrp, ALIGN(wr_off, 8),
17828c2ecf20Sopenharmony_ci				   sizeof(struct ulptx_sgl));
17838c2ecf20Sopenharmony_ci	}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	/* Issue work request to xmit ELS/CT req to FW */
17868c2ecf20Sopenharmony_ci	csio_wr_issue(mgmtm->hw, mgmtm->eq_idx, false);
17878c2ecf20Sopenharmony_ci	return ret;
17888c2ecf20Sopenharmony_ci}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci/*
17918c2ecf20Sopenharmony_ci * csio_ln_mgmt_submit_req - Submit FCOE Mgmt request.
17928c2ecf20Sopenharmony_ci * @io_req - IO Request
17938c2ecf20Sopenharmony_ci * @io_cbfn - Completion handler.
17948c2ecf20Sopenharmony_ci * @req_type - ELS or CT request type
17958c2ecf20Sopenharmony_ci * @pld - Dma Payload buffer
17968c2ecf20Sopenharmony_ci * @pld_len - Payload len
17978c2ecf20Sopenharmony_ci *
17988c2ecf20Sopenharmony_ci *
17998c2ecf20Sopenharmony_ci * This API used submit managment ELS/CT request.
18008c2ecf20Sopenharmony_ci * This called with hw lock held
18018c2ecf20Sopenharmony_ci * Returns: 0 - on success
18028c2ecf20Sopenharmony_ci *	    -ENOMEM	- on error.
18038c2ecf20Sopenharmony_ci */
18048c2ecf20Sopenharmony_cistatic int
18058c2ecf20Sopenharmony_cicsio_ln_mgmt_submit_req(struct csio_ioreq *io_req,
18068c2ecf20Sopenharmony_ci		void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *),
18078c2ecf20Sopenharmony_ci		enum fcoe_cmn_type req_type, struct csio_dma_buf *pld,
18088c2ecf20Sopenharmony_ci		uint32_t pld_len)
18098c2ecf20Sopenharmony_ci{
18108c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(io_req->lnode);
18118c2ecf20Sopenharmony_ci	struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw);
18128c2ecf20Sopenharmony_ci	int rv;
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	BUG_ON(pld_len > pld->len);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	io_req->io_cbfn = io_cbfn;	/* Upper layer callback handler */
18178c2ecf20Sopenharmony_ci	io_req->fw_handle = (uintptr_t) (io_req);
18188c2ecf20Sopenharmony_ci	io_req->eq_idx = mgmtm->eq_idx;
18198c2ecf20Sopenharmony_ci	io_req->iq_idx = mgmtm->iq_idx;
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	rv = csio_ln_mgmt_submit_wr(mgmtm, io_req, req_type, pld, pld_len);
18228c2ecf20Sopenharmony_ci	if (rv == 0) {
18238c2ecf20Sopenharmony_ci		list_add_tail(&io_req->sm.sm_list, &mgmtm->active_q);
18248c2ecf20Sopenharmony_ci		mgmtm->stats.n_active++;
18258c2ecf20Sopenharmony_ci	}
18268c2ecf20Sopenharmony_ci	return rv;
18278c2ecf20Sopenharmony_ci}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci/*
18308c2ecf20Sopenharmony_ci * csio_ln_fdmi_init - FDMI Init entry point.
18318c2ecf20Sopenharmony_ci * @ln: lnode
18328c2ecf20Sopenharmony_ci */
18338c2ecf20Sopenharmony_cistatic int
18348c2ecf20Sopenharmony_cicsio_ln_fdmi_init(struct csio_lnode *ln)
18358c2ecf20Sopenharmony_ci{
18368c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
18378c2ecf20Sopenharmony_ci	struct csio_dma_buf	*dma_buf;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	/* Allocate MGMT request required for FDMI */
18408c2ecf20Sopenharmony_ci	ln->mgmt_req = kzalloc(sizeof(struct csio_ioreq), GFP_KERNEL);
18418c2ecf20Sopenharmony_ci	if (!ln->mgmt_req) {
18428c2ecf20Sopenharmony_ci		csio_ln_err(ln, "Failed to alloc ioreq for FDMI\n");
18438c2ecf20Sopenharmony_ci		CSIO_INC_STATS(hw, n_err_nomem);
18448c2ecf20Sopenharmony_ci		return -ENOMEM;
18458c2ecf20Sopenharmony_ci	}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	/* Allocate Dma buffers for FDMI response Payload */
18488c2ecf20Sopenharmony_ci	dma_buf = &ln->mgmt_req->dma_buf;
18498c2ecf20Sopenharmony_ci	dma_buf->len = 2048;
18508c2ecf20Sopenharmony_ci	dma_buf->vaddr = dma_alloc_coherent(&hw->pdev->dev, dma_buf->len,
18518c2ecf20Sopenharmony_ci						&dma_buf->paddr, GFP_KERNEL);
18528c2ecf20Sopenharmony_ci	if (!dma_buf->vaddr) {
18538c2ecf20Sopenharmony_ci		csio_err(hw, "Failed to alloc DMA buffer for FDMI!\n");
18548c2ecf20Sopenharmony_ci		kfree(ln->mgmt_req);
18558c2ecf20Sopenharmony_ci		ln->mgmt_req = NULL;
18568c2ecf20Sopenharmony_ci		return -ENOMEM;
18578c2ecf20Sopenharmony_ci	}
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	ln->flags |= CSIO_LNF_FDMI_ENABLE;
18608c2ecf20Sopenharmony_ci	return 0;
18618c2ecf20Sopenharmony_ci}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci/*
18648c2ecf20Sopenharmony_ci * csio_ln_fdmi_exit - FDMI exit entry point.
18658c2ecf20Sopenharmony_ci * @ln: lnode
18668c2ecf20Sopenharmony_ci */
18678c2ecf20Sopenharmony_cistatic int
18688c2ecf20Sopenharmony_cicsio_ln_fdmi_exit(struct csio_lnode *ln)
18698c2ecf20Sopenharmony_ci{
18708c2ecf20Sopenharmony_ci	struct csio_dma_buf *dma_buf;
18718c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	if (!ln->mgmt_req)
18748c2ecf20Sopenharmony_ci		return 0;
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	dma_buf = &ln->mgmt_req->dma_buf;
18778c2ecf20Sopenharmony_ci	if (dma_buf->vaddr)
18788c2ecf20Sopenharmony_ci		dma_free_coherent(&hw->pdev->dev, dma_buf->len, dma_buf->vaddr,
18798c2ecf20Sopenharmony_ci				    dma_buf->paddr);
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	kfree(ln->mgmt_req);
18828c2ecf20Sopenharmony_ci	return 0;
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ciint
18868c2ecf20Sopenharmony_cicsio_scan_done(struct csio_lnode *ln, unsigned long ticks,
18878c2ecf20Sopenharmony_ci		unsigned long time, unsigned long max_scan_ticks,
18888c2ecf20Sopenharmony_ci		unsigned long delta_scan_ticks)
18898c2ecf20Sopenharmony_ci{
18908c2ecf20Sopenharmony_ci	int rv = 0;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	if (time >= max_scan_ticks)
18938c2ecf20Sopenharmony_ci		return 1;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	if (!ln->tgt_scan_tick)
18968c2ecf20Sopenharmony_ci		ln->tgt_scan_tick = ticks;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	if (((ticks - ln->tgt_scan_tick) >= delta_scan_ticks)) {
18998c2ecf20Sopenharmony_ci		if (!ln->last_scan_ntgts)
19008c2ecf20Sopenharmony_ci			ln->last_scan_ntgts = ln->n_scsi_tgts;
19018c2ecf20Sopenharmony_ci		else {
19028c2ecf20Sopenharmony_ci			if (ln->last_scan_ntgts == ln->n_scsi_tgts)
19038c2ecf20Sopenharmony_ci				return 1;
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci			ln->last_scan_ntgts = ln->n_scsi_tgts;
19068c2ecf20Sopenharmony_ci		}
19078c2ecf20Sopenharmony_ci		ln->tgt_scan_tick = ticks;
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci	return rv;
19108c2ecf20Sopenharmony_ci}
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci/*
19138c2ecf20Sopenharmony_ci * csio_notify_lnodes:
19148c2ecf20Sopenharmony_ci * @hw: HW module
19158c2ecf20Sopenharmony_ci * @note: Notification
19168c2ecf20Sopenharmony_ci *
19178c2ecf20Sopenharmony_ci * Called from the HW SM to fan out notifications to the
19188c2ecf20Sopenharmony_ci * Lnode SM. Since the HW SM is entered with lock held,
19198c2ecf20Sopenharmony_ci * there is no need to hold locks here.
19208c2ecf20Sopenharmony_ci *
19218c2ecf20Sopenharmony_ci */
19228c2ecf20Sopenharmony_civoid
19238c2ecf20Sopenharmony_cicsio_notify_lnodes(struct csio_hw *hw, enum csio_ln_notify note)
19248c2ecf20Sopenharmony_ci{
19258c2ecf20Sopenharmony_ci	struct list_head *tmp;
19268c2ecf20Sopenharmony_ci	struct csio_lnode *ln;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	csio_dbg(hw, "Notifying all nodes of event %d\n", note);
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	/* Traverse children lnodes list and send evt */
19318c2ecf20Sopenharmony_ci	list_for_each(tmp, &hw->sln_head) {
19328c2ecf20Sopenharmony_ci		ln = (struct csio_lnode *) tmp;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci		switch (note) {
19358c2ecf20Sopenharmony_ci		case CSIO_LN_NOTIFY_HWREADY:
19368c2ecf20Sopenharmony_ci			csio_lnode_start(ln);
19378c2ecf20Sopenharmony_ci			break;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci		case CSIO_LN_NOTIFY_HWRESET:
19408c2ecf20Sopenharmony_ci		case CSIO_LN_NOTIFY_HWREMOVE:
19418c2ecf20Sopenharmony_ci			csio_lnode_close(ln);
19428c2ecf20Sopenharmony_ci			break;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci		case CSIO_LN_NOTIFY_HWSTOP:
19458c2ecf20Sopenharmony_ci			csio_lnode_stop(ln);
19468c2ecf20Sopenharmony_ci			break;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci		default:
19498c2ecf20Sopenharmony_ci			break;
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci		}
19528c2ecf20Sopenharmony_ci	}
19538c2ecf20Sopenharmony_ci}
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci/*
19568c2ecf20Sopenharmony_ci * csio_disable_lnodes:
19578c2ecf20Sopenharmony_ci * @hw: HW module
19588c2ecf20Sopenharmony_ci * @portid:port id
19598c2ecf20Sopenharmony_ci * @disable: disable/enable flag.
19608c2ecf20Sopenharmony_ci * If disable=1, disables all lnode hosted on given physical port.
19618c2ecf20Sopenharmony_ci * otherwise enables all the lnodes on given phsysical port.
19628c2ecf20Sopenharmony_ci * This routine need to called with hw lock held.
19638c2ecf20Sopenharmony_ci */
19648c2ecf20Sopenharmony_civoid
19658c2ecf20Sopenharmony_cicsio_disable_lnodes(struct csio_hw *hw, uint8_t portid, bool disable)
19668c2ecf20Sopenharmony_ci{
19678c2ecf20Sopenharmony_ci	struct list_head *tmp;
19688c2ecf20Sopenharmony_ci	struct csio_lnode *ln;
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	csio_dbg(hw, "Notifying event to all nodes of port:%d\n", portid);
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	/* Traverse sibling lnodes list and send evt */
19738c2ecf20Sopenharmony_ci	list_for_each(tmp, &hw->sln_head) {
19748c2ecf20Sopenharmony_ci		ln = (struct csio_lnode *) tmp;
19758c2ecf20Sopenharmony_ci		if (ln->portid != portid)
19768c2ecf20Sopenharmony_ci			continue;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci		if (disable)
19798c2ecf20Sopenharmony_ci			csio_lnode_stop(ln);
19808c2ecf20Sopenharmony_ci		else
19818c2ecf20Sopenharmony_ci			csio_lnode_start(ln);
19828c2ecf20Sopenharmony_ci	}
19838c2ecf20Sopenharmony_ci}
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci/*
19868c2ecf20Sopenharmony_ci * csio_ln_init - Initialize an lnode.
19878c2ecf20Sopenharmony_ci * @ln:		lnode
19888c2ecf20Sopenharmony_ci *
19898c2ecf20Sopenharmony_ci */
19908c2ecf20Sopenharmony_cistatic int
19918c2ecf20Sopenharmony_cicsio_ln_init(struct csio_lnode *ln)
19928c2ecf20Sopenharmony_ci{
19938c2ecf20Sopenharmony_ci	int rv = -EINVAL;
19948c2ecf20Sopenharmony_ci	struct csio_lnode *pln;
19958c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	csio_init_state(&ln->sm, csio_lns_uninit);
19988c2ecf20Sopenharmony_ci	ln->vnp_flowid = CSIO_INVALID_IDX;
19998c2ecf20Sopenharmony_ci	ln->fcf_flowid = CSIO_INVALID_IDX;
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci	if (csio_is_root_ln(ln)) {
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci		/* This is the lnode used during initialization */
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci		ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info), GFP_KERNEL);
20068c2ecf20Sopenharmony_ci		if (!ln->fcfinfo) {
20078c2ecf20Sopenharmony_ci			csio_ln_err(ln, "Failed to alloc FCF record\n");
20088c2ecf20Sopenharmony_ci			CSIO_INC_STATS(hw, n_err_nomem);
20098c2ecf20Sopenharmony_ci			goto err;
20108c2ecf20Sopenharmony_ci		}
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ln->fcf_lsthead);
20138c2ecf20Sopenharmony_ci		kref_init(&ln->fcfinfo->kref);
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci		if (csio_fdmi_enable && csio_ln_fdmi_init(ln))
20168c2ecf20Sopenharmony_ci			goto err;
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	} else { /* Either a non-root physical or a virtual lnode */
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci		/*
20218c2ecf20Sopenharmony_ci		 * THe rest is common for non-root physical and NPIV lnodes.
20228c2ecf20Sopenharmony_ci		 * Just get references to all other modules
20238c2ecf20Sopenharmony_ci		 */
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci		if (csio_is_npiv_ln(ln)) {
20268c2ecf20Sopenharmony_ci			/* NPIV */
20278c2ecf20Sopenharmony_ci			pln = csio_parent_lnode(ln);
20288c2ecf20Sopenharmony_ci			kref_get(&pln->fcfinfo->kref);
20298c2ecf20Sopenharmony_ci			ln->fcfinfo = pln->fcfinfo;
20308c2ecf20Sopenharmony_ci		} else {
20318c2ecf20Sopenharmony_ci			/* Another non-root physical lnode (FCF) */
20328c2ecf20Sopenharmony_ci			ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info),
20338c2ecf20Sopenharmony_ci								GFP_KERNEL);
20348c2ecf20Sopenharmony_ci			if (!ln->fcfinfo) {
20358c2ecf20Sopenharmony_ci				csio_ln_err(ln, "Failed to alloc FCF info\n");
20368c2ecf20Sopenharmony_ci				CSIO_INC_STATS(hw, n_err_nomem);
20378c2ecf20Sopenharmony_ci				goto err;
20388c2ecf20Sopenharmony_ci			}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci			kref_init(&ln->fcfinfo->kref);
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci			if (csio_fdmi_enable && csio_ln_fdmi_init(ln))
20438c2ecf20Sopenharmony_ci				goto err;
20448c2ecf20Sopenharmony_ci		}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	} /* if (!csio_is_root_ln(ln)) */
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	return 0;
20498c2ecf20Sopenharmony_cierr:
20508c2ecf20Sopenharmony_ci	return rv;
20518c2ecf20Sopenharmony_ci}
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_cistatic void
20548c2ecf20Sopenharmony_cicsio_ln_exit(struct csio_lnode *ln)
20558c2ecf20Sopenharmony_ci{
20568c2ecf20Sopenharmony_ci	struct csio_lnode *pln;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	csio_cleanup_rns(ln);
20598c2ecf20Sopenharmony_ci	if (csio_is_npiv_ln(ln)) {
20608c2ecf20Sopenharmony_ci		pln = csio_parent_lnode(ln);
20618c2ecf20Sopenharmony_ci		kref_put(&pln->fcfinfo->kref, csio_free_fcfinfo);
20628c2ecf20Sopenharmony_ci	} else {
20638c2ecf20Sopenharmony_ci		kref_put(&ln->fcfinfo->kref, csio_free_fcfinfo);
20648c2ecf20Sopenharmony_ci		if (csio_fdmi_enable)
20658c2ecf20Sopenharmony_ci			csio_ln_fdmi_exit(ln);
20668c2ecf20Sopenharmony_ci	}
20678c2ecf20Sopenharmony_ci	ln->fcfinfo = NULL;
20688c2ecf20Sopenharmony_ci}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci/*
20718c2ecf20Sopenharmony_ci * csio_lnode_init - Initialize the members of an lnode.
20728c2ecf20Sopenharmony_ci * @ln:		lnode
20738c2ecf20Sopenharmony_ci */
20748c2ecf20Sopenharmony_ciint
20758c2ecf20Sopenharmony_cicsio_lnode_init(struct csio_lnode *ln, struct csio_hw *hw,
20768c2ecf20Sopenharmony_ci		struct csio_lnode *pln)
20778c2ecf20Sopenharmony_ci{
20788c2ecf20Sopenharmony_ci	int rv = -EINVAL;
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	/* Link this lnode to hw */
20818c2ecf20Sopenharmony_ci	csio_lnode_to_hw(ln)	= hw;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	/* Link child to parent if child lnode */
20848c2ecf20Sopenharmony_ci	if (pln)
20858c2ecf20Sopenharmony_ci		ln->pln = pln;
20868c2ecf20Sopenharmony_ci	else
20878c2ecf20Sopenharmony_ci		ln->pln = NULL;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	/* Initialize scsi_tgt and timers to zero */
20908c2ecf20Sopenharmony_ci	ln->n_scsi_tgts = 0;
20918c2ecf20Sopenharmony_ci	ln->last_scan_ntgts = 0;
20928c2ecf20Sopenharmony_ci	ln->tgt_scan_tick = 0;
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	/* Initialize rnode list */
20958c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ln->rnhead);
20968c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ln->cln_head);
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	/* Initialize log level for debug */
20998c2ecf20Sopenharmony_ci	ln->params.log_level	= hw->params.log_level;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	if (csio_ln_init(ln))
21028c2ecf20Sopenharmony_ci		goto err;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	/* Add lnode to list of sibling or children lnodes */
21058c2ecf20Sopenharmony_ci	spin_lock_irq(&hw->lock);
21068c2ecf20Sopenharmony_ci	list_add_tail(&ln->sm.sm_list, pln ? &pln->cln_head : &hw->sln_head);
21078c2ecf20Sopenharmony_ci	if (pln)
21088c2ecf20Sopenharmony_ci		pln->num_vports++;
21098c2ecf20Sopenharmony_ci	spin_unlock_irq(&hw->lock);
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	hw->num_lns++;
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	return 0;
21148c2ecf20Sopenharmony_cierr:
21158c2ecf20Sopenharmony_ci	csio_lnode_to_hw(ln) = NULL;
21168c2ecf20Sopenharmony_ci	return rv;
21178c2ecf20Sopenharmony_ci}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci/**
21208c2ecf20Sopenharmony_ci * csio_lnode_exit - De-instantiate an lnode.
21218c2ecf20Sopenharmony_ci * @ln:		lnode
21228c2ecf20Sopenharmony_ci *
21238c2ecf20Sopenharmony_ci */
21248c2ecf20Sopenharmony_civoid
21258c2ecf20Sopenharmony_cicsio_lnode_exit(struct csio_lnode *ln)
21268c2ecf20Sopenharmony_ci{
21278c2ecf20Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	csio_ln_exit(ln);
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	/* Remove this lnode from hw->sln_head */
21328c2ecf20Sopenharmony_ci	spin_lock_irq(&hw->lock);
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	list_del_init(&ln->sm.sm_list);
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	/* If it is children lnode, decrement the
21378c2ecf20Sopenharmony_ci	 * counter in its parent lnode
21388c2ecf20Sopenharmony_ci	 */
21398c2ecf20Sopenharmony_ci	if (ln->pln)
21408c2ecf20Sopenharmony_ci		ln->pln->num_vports--;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	/* Update root lnode pointer */
21438c2ecf20Sopenharmony_ci	if (list_empty(&hw->sln_head))
21448c2ecf20Sopenharmony_ci		hw->rln = NULL;
21458c2ecf20Sopenharmony_ci	else
21468c2ecf20Sopenharmony_ci		hw->rln = (struct csio_lnode *)csio_list_next(&hw->sln_head);
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	spin_unlock_irq(&hw->lock);
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	csio_lnode_to_hw(ln)	= NULL;
21518c2ecf20Sopenharmony_ci	hw->num_lns--;
21528c2ecf20Sopenharmony_ci}
2153