162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1062306a36Sopenharmony_ci * OpenIB.org BSD license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1362306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1462306a36Sopenharmony_ci *     conditions are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1762306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1862306a36Sopenharmony_ci *        disclaimer.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2162306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2262306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2362306a36Sopenharmony_ci *        provided with the distribution.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3262306a36Sopenharmony_ci * SOFTWARE.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/string.h>
3662306a36Sopenharmony_ci#include <scsi/scsi_device.h>
3762306a36Sopenharmony_ci#include <scsi/scsi_transport_fc.h>
3862306a36Sopenharmony_ci#include <scsi/fc/fc_els.h>
3962306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "csio_hw.h"
4262306a36Sopenharmony_ci#include "csio_lnode.h"
4362306a36Sopenharmony_ci#include "csio_rnode.h"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int csio_rnode_init(struct csio_rnode *, struct csio_lnode *);
4662306a36Sopenharmony_cistatic void csio_rnode_exit(struct csio_rnode *);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Static machine forward declarations */
4962306a36Sopenharmony_cistatic void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev);
5062306a36Sopenharmony_cistatic void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev);
5162306a36Sopenharmony_cistatic void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev);
5262306a36Sopenharmony_cistatic void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* RNF event mapping */
5562306a36Sopenharmony_cistatic enum csio_rn_ev fwevt_to_rnevt[] = {
5662306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* None */
5762306a36Sopenharmony_ci	CSIO_RNFE_LOGGED_IN,	/* PLOGI_ACC_RCVD  */
5862306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* PLOGI_RJT_RCVD  */
5962306a36Sopenharmony_ci	CSIO_RNFE_PLOGI_RECV,	/* PLOGI_RCVD	   */
6062306a36Sopenharmony_ci	CSIO_RNFE_LOGO_RECV,	/* PLOGO_RCVD	   */
6162306a36Sopenharmony_ci	CSIO_RNFE_PRLI_DONE,	/* PRLI_ACC_RCVD   */
6262306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* PRLI_RJT_RCVD   */
6362306a36Sopenharmony_ci	CSIO_RNFE_PRLI_RECV,	/* PRLI_RCVD	   */
6462306a36Sopenharmony_ci	CSIO_RNFE_PRLO_RECV,	/* PRLO_RCVD	   */
6562306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* NPORT_ID_CHGD   */
6662306a36Sopenharmony_ci	CSIO_RNFE_LOGO_RECV,	/* FLOGO_RCVD	   */
6762306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* CLR_VIRT_LNK_RCVD */
6862306a36Sopenharmony_ci	CSIO_RNFE_LOGGED_IN,	/* FLOGI_ACC_RCVD   */
6962306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* FLOGI_RJT_RCVD   */
7062306a36Sopenharmony_ci	CSIO_RNFE_LOGGED_IN,	/* FDISC_ACC_RCVD   */
7162306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* FDISC_RJT_RCVD   */
7262306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* FLOGI_TMO_MAX_RETRY */
7362306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_ACC */
7462306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_RJT */
7562306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_CNFLT */
7662306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* PRLI_TMO		*/
7762306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* ADISC_TMO		*/
7862306a36Sopenharmony_ci	CSIO_RNFE_NAME_MISSING,	/* RSCN_DEV_LOST  */
7962306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* SCR_ACC_RCVD	*/
8062306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* ADISC_RJT_RCVD */
8162306a36Sopenharmony_ci	CSIO_RNFE_NONE,		/* LOGO_SNT */
8262306a36Sopenharmony_ci	CSIO_RNFE_LOGO_RECV,	/* PROTO_ERR_IMPL_LOGO */
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define CSIO_FWE_TO_RNFE(_evt)	((_evt > PROTO_ERR_IMPL_LOGO) ?		\
8662306a36Sopenharmony_ci						CSIO_RNFE_NONE :	\
8762306a36Sopenharmony_ci						fwevt_to_rnevt[_evt])
8862306a36Sopenharmony_ciint
8962306a36Sopenharmony_cicsio_is_rnode_ready(struct csio_rnode *rn)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	return csio_match_state(rn, csio_rns_ready);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int
9562306a36Sopenharmony_cicsio_is_rnode_uninit(struct csio_rnode *rn)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	return csio_match_state(rn, csio_rns_uninit);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int
10162306a36Sopenharmony_cicsio_is_rnode_wka(uint8_t rport_type)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	if ((rport_type == FLOGI_VFPORT) ||
10462306a36Sopenharmony_ci	    (rport_type == FDISC_VFPORT) ||
10562306a36Sopenharmony_ci	    (rport_type == NS_VNPORT) ||
10662306a36Sopenharmony_ci	    (rport_type == FDMI_VNPORT))
10762306a36Sopenharmony_ci		return 1;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/*
11362306a36Sopenharmony_ci * csio_rn_lookup - Finds the rnode with the given flowid
11462306a36Sopenharmony_ci * @ln - lnode
11562306a36Sopenharmony_ci * @flowid - flowid.
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * Does the rnode lookup on the given lnode and flowid.If no matching entry
11862306a36Sopenharmony_ci * found, NULL is returned.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_cistatic struct csio_rnode *
12162306a36Sopenharmony_cicsio_rn_lookup(struct csio_lnode *ln, uint32_t flowid)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
12462306a36Sopenharmony_ci	struct list_head *tmp;
12562306a36Sopenharmony_ci	struct csio_rnode *rn;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	list_for_each(tmp, &rnhead->sm.sm_list) {
12862306a36Sopenharmony_ci		rn = (struct csio_rnode *) tmp;
12962306a36Sopenharmony_ci		if (rn->flowid == flowid)
13062306a36Sopenharmony_ci			return rn;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return NULL;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/*
13762306a36Sopenharmony_ci * csio_rn_lookup_wwpn - Finds the rnode with the given wwpn
13862306a36Sopenharmony_ci * @ln: lnode
13962306a36Sopenharmony_ci * @wwpn: wwpn
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * Does the rnode lookup on the given lnode and wwpn. If no matching entry
14262306a36Sopenharmony_ci * found, NULL is returned.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_cistatic struct csio_rnode *
14562306a36Sopenharmony_cicsio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
14862306a36Sopenharmony_ci	struct list_head *tmp;
14962306a36Sopenharmony_ci	struct csio_rnode *rn;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	list_for_each(tmp, &rnhead->sm.sm_list) {
15262306a36Sopenharmony_ci		rn = (struct csio_rnode *) tmp;
15362306a36Sopenharmony_ci		if (!memcmp(csio_rn_wwpn(rn), wwpn, 8))
15462306a36Sopenharmony_ci			return rn;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return NULL;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/**
16162306a36Sopenharmony_ci * csio_rnode_lookup_portid - Finds the rnode with the given portid
16262306a36Sopenharmony_ci * @ln:		lnode
16362306a36Sopenharmony_ci * @portid:	port id
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci * Lookup the rnode list for a given portid. If no matching entry
16662306a36Sopenharmony_ci * found, NULL is returned.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistruct csio_rnode *
16962306a36Sopenharmony_cicsio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
17262306a36Sopenharmony_ci	struct list_head *tmp;
17362306a36Sopenharmony_ci	struct csio_rnode *rn;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	list_for_each(tmp, &rnhead->sm.sm_list) {
17662306a36Sopenharmony_ci		rn = (struct csio_rnode *) tmp;
17762306a36Sopenharmony_ci		if (rn->nport_id == portid)
17862306a36Sopenharmony_ci			return rn;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return NULL;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int
18562306a36Sopenharmony_cicsio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid,
18662306a36Sopenharmony_ci		    uint32_t *vnp_flowid)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct csio_rnode *rnhead;
18962306a36Sopenharmony_ci	struct list_head *tmp, *tmp1;
19062306a36Sopenharmony_ci	struct csio_rnode *rn;
19162306a36Sopenharmony_ci	struct csio_lnode *ln_tmp;
19262306a36Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	list_for_each(tmp1, &hw->sln_head) {
19562306a36Sopenharmony_ci		ln_tmp = (struct csio_lnode *) tmp1;
19662306a36Sopenharmony_ci		if (ln_tmp == ln)
19762306a36Sopenharmony_ci			continue;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		rnhead = (struct csio_rnode *)&ln_tmp->rnhead;
20062306a36Sopenharmony_ci		list_for_each(tmp, &rnhead->sm.sm_list) {
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci			rn = (struct csio_rnode *) tmp;
20362306a36Sopenharmony_ci			if (csio_is_rnode_ready(rn)) {
20462306a36Sopenharmony_ci				if (rn->flowid == rdev_flowid) {
20562306a36Sopenharmony_ci					*vnp_flowid = csio_ln_flowid(ln_tmp);
20662306a36Sopenharmony_ci					return 1;
20762306a36Sopenharmony_ci				}
20862306a36Sopenharmony_ci			}
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return 0;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic struct csio_rnode *
21662306a36Sopenharmony_cicsio_alloc_rnode(struct csio_lnode *ln)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC);
22162306a36Sopenharmony_ci	if (!rn)
22262306a36Sopenharmony_ci		goto err;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	memset(rn, 0, sizeof(struct csio_rnode));
22562306a36Sopenharmony_ci	if (csio_rnode_init(rn, ln))
22662306a36Sopenharmony_ci		goto err_free;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	CSIO_INC_STATS(ln, n_rnode_alloc);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return rn;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cierr_free:
23362306a36Sopenharmony_ci	mempool_free(rn, hw->rnode_mempool);
23462306a36Sopenharmony_cierr:
23562306a36Sopenharmony_ci	CSIO_INC_STATS(ln, n_rnode_nomem);
23662306a36Sopenharmony_ci	return NULL;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void
24062306a36Sopenharmony_cicsio_free_rnode(struct csio_rnode *rn)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	csio_rnode_exit(rn);
24562306a36Sopenharmony_ci	CSIO_INC_STATS(rn->lnp, n_rnode_free);
24662306a36Sopenharmony_ci	mempool_free(rn, hw->rnode_mempool);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/*
25062306a36Sopenharmony_ci * csio_get_rnode - Gets rnode with the given flowid
25162306a36Sopenharmony_ci * @ln - lnode
25262306a36Sopenharmony_ci * @flowid - flow id.
25362306a36Sopenharmony_ci *
25462306a36Sopenharmony_ci * Does the rnode lookup on the given lnode and flowid. If no matching
25562306a36Sopenharmony_ci * rnode found, then new rnode with given npid is allocated and returned.
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic struct csio_rnode *
25862306a36Sopenharmony_cicsio_get_rnode(struct csio_lnode *ln, uint32_t flowid)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct csio_rnode *rn;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	rn = csio_rn_lookup(ln, flowid);
26362306a36Sopenharmony_ci	if (!rn) {
26462306a36Sopenharmony_ci		rn = csio_alloc_rnode(ln);
26562306a36Sopenharmony_ci		if (!rn)
26662306a36Sopenharmony_ci			return NULL;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		rn->flowid = flowid;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	return rn;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/*
27562306a36Sopenharmony_ci * csio_put_rnode - Frees the given rnode
27662306a36Sopenharmony_ci * @ln - lnode
27762306a36Sopenharmony_ci * @flowid - flow id.
27862306a36Sopenharmony_ci *
27962306a36Sopenharmony_ci * Does the rnode lookup on the given lnode and flowid. If no matching
28062306a36Sopenharmony_ci * rnode found, then new rnode with given npid is allocated and returned.
28162306a36Sopenharmony_ci */
28262306a36Sopenharmony_civoid
28362306a36Sopenharmony_cicsio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0);
28662306a36Sopenharmony_ci	csio_free_rnode(rn);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/*
29062306a36Sopenharmony_ci * csio_confirm_rnode - confirms rnode based on wwpn.
29162306a36Sopenharmony_ci * @ln: lnode
29262306a36Sopenharmony_ci * @rdev_flowid: remote device flowid
29362306a36Sopenharmony_ci * @rdevp: remote device params
29462306a36Sopenharmony_ci * This routines searches other rnode in list having same wwpn of new rnode.
29562306a36Sopenharmony_ci * If there is a match, then matched rnode is returned and otherwise new rnode
29662306a36Sopenharmony_ci * is returned.
29762306a36Sopenharmony_ci * returns rnode.
29862306a36Sopenharmony_ci */
29962306a36Sopenharmony_cistruct csio_rnode *
30062306a36Sopenharmony_cicsio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
30162306a36Sopenharmony_ci		   struct fcoe_rdev_entry *rdevp)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	uint8_t rport_type;
30462306a36Sopenharmony_ci	struct csio_rnode *rn, *match_rn;
30562306a36Sopenharmony_ci	uint32_t vnp_flowid = 0;
30662306a36Sopenharmony_ci	__be32 *port_id;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	port_id = (__be32 *)&rdevp->r_id[0];
30962306a36Sopenharmony_ci	rport_type =
31062306a36Sopenharmony_ci		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/* Drop rdev event for cntrl port */
31362306a36Sopenharmony_ci	if (rport_type == FAB_CTLR_VNPORT) {
31462306a36Sopenharmony_ci		csio_ln_dbg(ln,
31562306a36Sopenharmony_ci			    "Unhandled rport_type:%d recv in rdev evt "
31662306a36Sopenharmony_ci			    "ssni:x%x\n", rport_type, rdev_flowid);
31762306a36Sopenharmony_ci		return NULL;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Lookup on flowid */
32162306a36Sopenharmony_ci	rn = csio_rn_lookup(ln, rdev_flowid);
32262306a36Sopenharmony_ci	if (!rn) {
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		/* Drop events with duplicate flowid */
32562306a36Sopenharmony_ci		if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) {
32662306a36Sopenharmony_ci			csio_ln_warn(ln,
32762306a36Sopenharmony_ci				     "ssni:%x already active on vnpi:%x",
32862306a36Sopenharmony_ci				     rdev_flowid, vnp_flowid);
32962306a36Sopenharmony_ci			return NULL;
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci		/* Lookup on wwpn for NPORTs */
33362306a36Sopenharmony_ci		rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
33462306a36Sopenharmony_ci		if (!rn)
33562306a36Sopenharmony_ci			goto alloc_rnode;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	} else {
33862306a36Sopenharmony_ci		/* Lookup well-known ports with nport id */
33962306a36Sopenharmony_ci		if (csio_is_rnode_wka(rport_type)) {
34062306a36Sopenharmony_ci			match_rn = csio_rnode_lookup_portid(ln,
34162306a36Sopenharmony_ci				      ((ntohl(*port_id) >> 8) & CSIO_DID_MASK));
34262306a36Sopenharmony_ci			if (match_rn == NULL) {
34362306a36Sopenharmony_ci				csio_rn_flowid(rn) = CSIO_INVALID_IDX;
34462306a36Sopenharmony_ci				goto alloc_rnode;
34562306a36Sopenharmony_ci			}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci			/*
34862306a36Sopenharmony_ci			 * Now compare the wwpn to confirm that
34962306a36Sopenharmony_ci			 * same port relogged in. If so update the matched rn.
35062306a36Sopenharmony_ci			 * Else, go ahead and alloc a new rnode.
35162306a36Sopenharmony_ci			 */
35262306a36Sopenharmony_ci			if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) {
35362306a36Sopenharmony_ci				if (rn == match_rn)
35462306a36Sopenharmony_ci					goto found_rnode;
35562306a36Sopenharmony_ci				csio_ln_dbg(ln,
35662306a36Sopenharmony_ci					    "nport_id:x%x and wwpn:%llx"
35762306a36Sopenharmony_ci					    " match for ssni:x%x\n",
35862306a36Sopenharmony_ci					    rn->nport_id,
35962306a36Sopenharmony_ci					    wwn_to_u64(rdevp->wwpn),
36062306a36Sopenharmony_ci					    rdev_flowid);
36162306a36Sopenharmony_ci				if (csio_is_rnode_ready(rn)) {
36262306a36Sopenharmony_ci					csio_ln_warn(ln,
36362306a36Sopenharmony_ci						     "rnode is already"
36462306a36Sopenharmony_ci						     "active ssni:x%x\n",
36562306a36Sopenharmony_ci						     rdev_flowid);
36662306a36Sopenharmony_ci					CSIO_ASSERT(0);
36762306a36Sopenharmony_ci				}
36862306a36Sopenharmony_ci				csio_rn_flowid(rn) = CSIO_INVALID_IDX;
36962306a36Sopenharmony_ci				rn = match_rn;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci				/* Update rn */
37262306a36Sopenharmony_ci				goto found_rnode;
37362306a36Sopenharmony_ci			}
37462306a36Sopenharmony_ci			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
37562306a36Sopenharmony_ci			goto alloc_rnode;
37662306a36Sopenharmony_ci		}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		/* wwpn match */
37962306a36Sopenharmony_ci		if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8))
38062306a36Sopenharmony_ci			goto found_rnode;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		/* Search for rnode that have same wwpn */
38362306a36Sopenharmony_ci		match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
38462306a36Sopenharmony_ci		if (match_rn != NULL) {
38562306a36Sopenharmony_ci			csio_ln_dbg(ln,
38662306a36Sopenharmony_ci				"ssni:x%x changed for rport name(wwpn):%llx "
38762306a36Sopenharmony_ci				"did:x%x\n", rdev_flowid,
38862306a36Sopenharmony_ci				wwn_to_u64(rdevp->wwpn),
38962306a36Sopenharmony_ci				match_rn->nport_id);
39062306a36Sopenharmony_ci			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
39162306a36Sopenharmony_ci			rn = match_rn;
39262306a36Sopenharmony_ci		} else {
39362306a36Sopenharmony_ci			csio_ln_dbg(ln,
39462306a36Sopenharmony_ci				"rnode wwpn mismatch found ssni:x%x "
39562306a36Sopenharmony_ci				"name(wwpn):%llx\n",
39662306a36Sopenharmony_ci				rdev_flowid,
39762306a36Sopenharmony_ci				wwn_to_u64(csio_rn_wwpn(rn)));
39862306a36Sopenharmony_ci			if (csio_is_rnode_ready(rn)) {
39962306a36Sopenharmony_ci				csio_ln_warn(ln,
40062306a36Sopenharmony_ci					     "rnode is already active "
40162306a36Sopenharmony_ci					     "wwpn:%llx ssni:x%x\n",
40262306a36Sopenharmony_ci					     wwn_to_u64(csio_rn_wwpn(rn)),
40362306a36Sopenharmony_ci					     rdev_flowid);
40462306a36Sopenharmony_ci				CSIO_ASSERT(0);
40562306a36Sopenharmony_ci			}
40662306a36Sopenharmony_ci			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
40762306a36Sopenharmony_ci			goto alloc_rnode;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cifound_rnode:
41262306a36Sopenharmony_ci	csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n",
41362306a36Sopenharmony_ci		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* Update flowid */
41662306a36Sopenharmony_ci	csio_rn_flowid(rn) = rdev_flowid;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* update rdev entry */
41962306a36Sopenharmony_ci	rn->rdev_entry = rdevp;
42062306a36Sopenharmony_ci	CSIO_INC_STATS(ln, n_rnode_match);
42162306a36Sopenharmony_ci	return rn;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cialloc_rnode:
42462306a36Sopenharmony_ci	rn = csio_get_rnode(ln, rdev_flowid);
42562306a36Sopenharmony_ci	if (!rn)
42662306a36Sopenharmony_ci		return NULL;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n",
42962306a36Sopenharmony_ci		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/* update rdev entry */
43262306a36Sopenharmony_ci	rn->rdev_entry = rdevp;
43362306a36Sopenharmony_ci	return rn;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/*
43762306a36Sopenharmony_ci * csio_rn_verify_rparams - verify rparams.
43862306a36Sopenharmony_ci * @ln: lnode
43962306a36Sopenharmony_ci * @rn: rnode
44062306a36Sopenharmony_ci * @rdevp: remote device params
44162306a36Sopenharmony_ci * returns success if rparams are verified.
44262306a36Sopenharmony_ci */
44362306a36Sopenharmony_cistatic int
44462306a36Sopenharmony_cicsio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn,
44562306a36Sopenharmony_ci			struct fcoe_rdev_entry *rdevp)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	uint8_t null[8];
44862306a36Sopenharmony_ci	uint8_t rport_type;
44962306a36Sopenharmony_ci	uint8_t fc_class;
45062306a36Sopenharmony_ci	__be32 *did;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	did = (__be32 *) &rdevp->r_id[0];
45362306a36Sopenharmony_ci	rport_type =
45462306a36Sopenharmony_ci		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
45562306a36Sopenharmony_ci	switch (rport_type) {
45662306a36Sopenharmony_ci	case FLOGI_VFPORT:
45762306a36Sopenharmony_ci		rn->role = CSIO_RNFR_FABRIC;
45862306a36Sopenharmony_ci		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) {
45962306a36Sopenharmony_ci			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
46062306a36Sopenharmony_ci				csio_rn_flowid(rn));
46162306a36Sopenharmony_ci			return -EINVAL;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci		/* NPIV support */
46462306a36Sopenharmony_ci		if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos))
46562306a36Sopenharmony_ci			ln->flags |= CSIO_LNF_NPIVSUPP;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	case NS_VNPORT:
47062306a36Sopenharmony_ci		rn->role = CSIO_RNFR_NS;
47162306a36Sopenharmony_ci		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) {
47262306a36Sopenharmony_ci			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
47362306a36Sopenharmony_ci				csio_rn_flowid(rn));
47462306a36Sopenharmony_ci			return -EINVAL;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci		break;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	case REG_FC4_VNPORT:
47962306a36Sopenharmony_ci	case REG_VNPORT:
48062306a36Sopenharmony_ci		rn->role = CSIO_RNFR_NPORT;
48162306a36Sopenharmony_ci		if (rdevp->event_cause == PRLI_ACC_RCVD ||
48262306a36Sopenharmony_ci			rdevp->event_cause == PRLI_RCVD) {
48362306a36Sopenharmony_ci			if (FW_RDEV_WR_TASK_RETRY_ID_GET(
48462306a36Sopenharmony_ci							rdevp->enh_disc_to_tgt))
48562306a36Sopenharmony_ci				rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci			if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt))
48862306a36Sopenharmony_ci				rn->fcp_flags |= FCP_SPPF_RETRY;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci			if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt))
49162306a36Sopenharmony_ci				rn->fcp_flags |= FCP_SPPF_CONF_COMPL;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci			if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt))
49462306a36Sopenharmony_ci				rn->role |= CSIO_RNFR_TARGET;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci			if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt))
49762306a36Sopenharmony_ci				rn->role |= CSIO_RNFR_INITIATOR;
49862306a36Sopenharmony_ci		}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	case FDMI_VNPORT:
50362306a36Sopenharmony_ci	case FAB_CTLR_VNPORT:
50462306a36Sopenharmony_ci		rn->role = 0;
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	default:
50862306a36Sopenharmony_ci		csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n",
50962306a36Sopenharmony_ci			csio_rn_flowid(rn), rport_type);
51062306a36Sopenharmony_ci		return -EINVAL;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/* validate wwpn/wwnn for Name server/remote port */
51462306a36Sopenharmony_ci	if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) {
51562306a36Sopenharmony_ci		memset(null, 0, 8);
51662306a36Sopenharmony_ci		if (!memcmp(rdevp->wwnn, null, 8)) {
51762306a36Sopenharmony_ci			csio_ln_err(ln,
51862306a36Sopenharmony_ci				    "ssni:x%x invalid wwnn received from"
51962306a36Sopenharmony_ci				    " rport did:x%x\n",
52062306a36Sopenharmony_ci				    csio_rn_flowid(rn),
52162306a36Sopenharmony_ci				    (ntohl(*did) & CSIO_DID_MASK));
52262306a36Sopenharmony_ci			return -EINVAL;
52362306a36Sopenharmony_ci		}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		if (!memcmp(rdevp->wwpn, null, 8)) {
52662306a36Sopenharmony_ci			csio_ln_err(ln,
52762306a36Sopenharmony_ci				    "ssni:x%x invalid wwpn received from"
52862306a36Sopenharmony_ci				    " rport did:x%x\n",
52962306a36Sopenharmony_ci				    csio_rn_flowid(rn),
53062306a36Sopenharmony_ci				    (ntohl(*did) & CSIO_DID_MASK));
53162306a36Sopenharmony_ci			return -EINVAL;
53262306a36Sopenharmony_ci		}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Copy wwnn, wwpn and nport id */
53762306a36Sopenharmony_ci	rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK;
53862306a36Sopenharmony_ci	memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8);
53962306a36Sopenharmony_ci	memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8);
54062306a36Sopenharmony_ci	rn->rn_sparm.csp.sp_bb_data = rdevp->rcv_fr_sz;
54162306a36Sopenharmony_ci	fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos);
54262306a36Sopenharmony_ci	rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	return 0;
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic void
54862306a36Sopenharmony_ci__csio_reg_rnode(struct csio_rnode *rn)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
55162306a36Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	spin_unlock_irq(&hw->lock);
55462306a36Sopenharmony_ci	csio_reg_rnode(rn);
55562306a36Sopenharmony_ci	spin_lock_irq(&hw->lock);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (rn->role & CSIO_RNFR_TARGET)
55862306a36Sopenharmony_ci		ln->n_scsi_tgts++;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (rn->nport_id == FC_FID_MGMT_SERV)
56162306a36Sopenharmony_ci		csio_ln_fdmi_start(ln, (void *) rn);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic void
56562306a36Sopenharmony_ci__csio_unreg_rnode(struct csio_rnode *rn)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
56862306a36Sopenharmony_ci	struct csio_hw *hw = csio_lnode_to_hw(ln);
56962306a36Sopenharmony_ci	LIST_HEAD(tmp_q);
57062306a36Sopenharmony_ci	int cmpl = 0;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	if (!list_empty(&rn->host_cmpl_q)) {
57362306a36Sopenharmony_ci		csio_dbg(hw, "Returning completion queue I/Os\n");
57462306a36Sopenharmony_ci		list_splice_tail_init(&rn->host_cmpl_q, &tmp_q);
57562306a36Sopenharmony_ci		cmpl = 1;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (rn->role & CSIO_RNFR_TARGET) {
57962306a36Sopenharmony_ci		ln->n_scsi_tgts--;
58062306a36Sopenharmony_ci		ln->last_scan_ntgts--;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	spin_unlock_irq(&hw->lock);
58462306a36Sopenharmony_ci	csio_unreg_rnode(rn);
58562306a36Sopenharmony_ci	spin_lock_irq(&hw->lock);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* Cleanup I/Os that were waiting for rnode to unregister */
58862306a36Sopenharmony_ci	if (cmpl)
58962306a36Sopenharmony_ci		csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/*****************************************************************************/
59462306a36Sopenharmony_ci/* START: Rnode SM                                                           */
59562306a36Sopenharmony_ci/*****************************************************************************/
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci/*
59862306a36Sopenharmony_ci * csio_rns_uninit -
59962306a36Sopenharmony_ci * @rn - rnode
60062306a36Sopenharmony_ci * @evt - SM event.
60162306a36Sopenharmony_ci *
60262306a36Sopenharmony_ci */
60362306a36Sopenharmony_cistatic void
60462306a36Sopenharmony_cicsio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
60762306a36Sopenharmony_ci	int ret = 0;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	CSIO_INC_STATS(rn, n_evt_sm[evt]);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	switch (evt) {
61262306a36Sopenharmony_ci	case CSIO_RNFE_LOGGED_IN:
61362306a36Sopenharmony_ci	case CSIO_RNFE_PLOGI_RECV:
61462306a36Sopenharmony_ci		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
61562306a36Sopenharmony_ci		if (!ret) {
61662306a36Sopenharmony_ci			csio_set_state(&rn->sm, csio_rns_ready);
61762306a36Sopenharmony_ci			__csio_reg_rnode(rn);
61862306a36Sopenharmony_ci		} else {
61962306a36Sopenharmony_ci			CSIO_INC_STATS(rn, n_err_inval);
62062306a36Sopenharmony_ci		}
62162306a36Sopenharmony_ci		break;
62262306a36Sopenharmony_ci	case CSIO_RNFE_LOGO_RECV:
62362306a36Sopenharmony_ci		csio_ln_dbg(ln,
62462306a36Sopenharmony_ci			    "ssni:x%x Ignoring event %d recv "
62562306a36Sopenharmony_ci			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
62662306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_drop);
62762306a36Sopenharmony_ci		break;
62862306a36Sopenharmony_ci	default:
62962306a36Sopenharmony_ci		csio_ln_dbg(ln,
63062306a36Sopenharmony_ci			    "ssni:x%x unexp event %d recv "
63162306a36Sopenharmony_ci			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
63262306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_unexp);
63362306a36Sopenharmony_ci		break;
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/*
63862306a36Sopenharmony_ci * csio_rns_ready -
63962306a36Sopenharmony_ci * @rn - rnode
64062306a36Sopenharmony_ci * @evt - SM event.
64162306a36Sopenharmony_ci *
64262306a36Sopenharmony_ci */
64362306a36Sopenharmony_cistatic void
64462306a36Sopenharmony_cicsio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
64762306a36Sopenharmony_ci	int ret = 0;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	CSIO_INC_STATS(rn, n_evt_sm[evt]);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	switch (evt) {
65262306a36Sopenharmony_ci	case CSIO_RNFE_LOGGED_IN:
65362306a36Sopenharmony_ci	case CSIO_RNFE_PLOGI_RECV:
65462306a36Sopenharmony_ci		csio_ln_dbg(ln,
65562306a36Sopenharmony_ci			"ssni:x%x Ignoring event %d recv from did:x%x "
65662306a36Sopenharmony_ci			"in rn state[ready]\n", csio_rn_flowid(rn), evt,
65762306a36Sopenharmony_ci			rn->nport_id);
65862306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_drop);
65962306a36Sopenharmony_ci		break;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	case CSIO_RNFE_PRLI_DONE:
66262306a36Sopenharmony_ci	case CSIO_RNFE_PRLI_RECV:
66362306a36Sopenharmony_ci		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
66462306a36Sopenharmony_ci		if (!ret)
66562306a36Sopenharmony_ci			__csio_reg_rnode(rn);
66662306a36Sopenharmony_ci		else
66762306a36Sopenharmony_ci			CSIO_INC_STATS(rn, n_err_inval);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		break;
67062306a36Sopenharmony_ci	case CSIO_RNFE_DOWN:
67162306a36Sopenharmony_ci		csio_set_state(&rn->sm, csio_rns_offline);
67262306a36Sopenharmony_ci		__csio_unreg_rnode(rn);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		/* FW expected to internally aborted outstanding SCSI WRs
67562306a36Sopenharmony_ci		 * and return all SCSI WRs to host with status "ABORTED".
67662306a36Sopenharmony_ci		 */
67762306a36Sopenharmony_ci		break;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	case CSIO_RNFE_LOGO_RECV:
68062306a36Sopenharmony_ci		csio_set_state(&rn->sm, csio_rns_offline);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		__csio_unreg_rnode(rn);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		/* FW expected to internally aborted outstanding SCSI WRs
68562306a36Sopenharmony_ci		 * and return all SCSI WRs to host with status "ABORTED".
68662306a36Sopenharmony_ci		 */
68762306a36Sopenharmony_ci		break;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	case CSIO_RNFE_CLOSE:
69062306a36Sopenharmony_ci		/*
69162306a36Sopenharmony_ci		 * Each rnode receives CLOSE event when driver is removed or
69262306a36Sopenharmony_ci		 * device is reset
69362306a36Sopenharmony_ci		 * Note: All outstanding IOs on remote port need to returned
69462306a36Sopenharmony_ci		 * to uppper layer with appropriate error before sending
69562306a36Sopenharmony_ci		 * CLOSE event
69662306a36Sopenharmony_ci		 */
69762306a36Sopenharmony_ci		csio_set_state(&rn->sm, csio_rns_uninit);
69862306a36Sopenharmony_ci		__csio_unreg_rnode(rn);
69962306a36Sopenharmony_ci		break;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	case CSIO_RNFE_NAME_MISSING:
70262306a36Sopenharmony_ci		csio_set_state(&rn->sm, csio_rns_disappeared);
70362306a36Sopenharmony_ci		__csio_unreg_rnode(rn);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		/*
70662306a36Sopenharmony_ci		 * FW expected to internally aborted outstanding SCSI WRs
70762306a36Sopenharmony_ci		 * and return all SCSI WRs to host with status "ABORTED".
70862306a36Sopenharmony_ci		 */
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		break;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	default:
71362306a36Sopenharmony_ci		csio_ln_dbg(ln,
71462306a36Sopenharmony_ci			"ssni:x%x unexp event %d recv from did:x%x "
71562306a36Sopenharmony_ci			"in rn state[uninit]\n", csio_rn_flowid(rn), evt,
71662306a36Sopenharmony_ci			rn->nport_id);
71762306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_unexp);
71862306a36Sopenharmony_ci		break;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci/*
72362306a36Sopenharmony_ci * csio_rns_offline -
72462306a36Sopenharmony_ci * @rn - rnode
72562306a36Sopenharmony_ci * @evt - SM event.
72662306a36Sopenharmony_ci *
72762306a36Sopenharmony_ci */
72862306a36Sopenharmony_cistatic void
72962306a36Sopenharmony_cicsio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt)
73062306a36Sopenharmony_ci{
73162306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
73262306a36Sopenharmony_ci	int ret = 0;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	CSIO_INC_STATS(rn, n_evt_sm[evt]);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	switch (evt) {
73762306a36Sopenharmony_ci	case CSIO_RNFE_LOGGED_IN:
73862306a36Sopenharmony_ci	case CSIO_RNFE_PLOGI_RECV:
73962306a36Sopenharmony_ci		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
74062306a36Sopenharmony_ci		if (!ret) {
74162306a36Sopenharmony_ci			csio_set_state(&rn->sm, csio_rns_ready);
74262306a36Sopenharmony_ci			__csio_reg_rnode(rn);
74362306a36Sopenharmony_ci		} else {
74462306a36Sopenharmony_ci			CSIO_INC_STATS(rn, n_err_inval);
74562306a36Sopenharmony_ci			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
74662306a36Sopenharmony_ci		}
74762306a36Sopenharmony_ci		break;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	case CSIO_RNFE_DOWN:
75062306a36Sopenharmony_ci		csio_ln_dbg(ln,
75162306a36Sopenharmony_ci			"ssni:x%x Ignoring event %d recv from did:x%x "
75262306a36Sopenharmony_ci			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
75362306a36Sopenharmony_ci			rn->nport_id);
75462306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_drop);
75562306a36Sopenharmony_ci		break;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	case CSIO_RNFE_CLOSE:
75862306a36Sopenharmony_ci		/* Each rnode receives CLOSE event when driver is removed or
75962306a36Sopenharmony_ci		 * device is reset
76062306a36Sopenharmony_ci		 * Note: All outstanding IOs on remote port need to returned
76162306a36Sopenharmony_ci		 * to uppper layer with appropriate error before sending
76262306a36Sopenharmony_ci		 * CLOSE event
76362306a36Sopenharmony_ci		 */
76462306a36Sopenharmony_ci		csio_set_state(&rn->sm, csio_rns_uninit);
76562306a36Sopenharmony_ci		break;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	case CSIO_RNFE_NAME_MISSING:
76862306a36Sopenharmony_ci		csio_set_state(&rn->sm, csio_rns_disappeared);
76962306a36Sopenharmony_ci		break;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	default:
77262306a36Sopenharmony_ci		csio_ln_dbg(ln,
77362306a36Sopenharmony_ci			"ssni:x%x unexp event %d recv from did:x%x "
77462306a36Sopenharmony_ci			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
77562306a36Sopenharmony_ci			rn->nport_id);
77662306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_unexp);
77762306a36Sopenharmony_ci		break;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/*
78262306a36Sopenharmony_ci * csio_rns_disappeared -
78362306a36Sopenharmony_ci * @rn - rnode
78462306a36Sopenharmony_ci * @evt - SM event.
78562306a36Sopenharmony_ci *
78662306a36Sopenharmony_ci */
78762306a36Sopenharmony_cistatic void
78862306a36Sopenharmony_cicsio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
79162306a36Sopenharmony_ci	int ret = 0;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	CSIO_INC_STATS(rn, n_evt_sm[evt]);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	switch (evt) {
79662306a36Sopenharmony_ci	case CSIO_RNFE_LOGGED_IN:
79762306a36Sopenharmony_ci	case CSIO_RNFE_PLOGI_RECV:
79862306a36Sopenharmony_ci		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
79962306a36Sopenharmony_ci		if (!ret) {
80062306a36Sopenharmony_ci			csio_set_state(&rn->sm, csio_rns_ready);
80162306a36Sopenharmony_ci			__csio_reg_rnode(rn);
80262306a36Sopenharmony_ci		} else {
80362306a36Sopenharmony_ci			CSIO_INC_STATS(rn, n_err_inval);
80462306a36Sopenharmony_ci			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
80562306a36Sopenharmony_ci		}
80662306a36Sopenharmony_ci		break;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	case CSIO_RNFE_CLOSE:
80962306a36Sopenharmony_ci		/* Each rnode receives CLOSE event when driver is removed or
81062306a36Sopenharmony_ci		 * device is reset.
81162306a36Sopenharmony_ci		 * Note: All outstanding IOs on remote port need to returned
81262306a36Sopenharmony_ci		 * to uppper layer with appropriate error before sending
81362306a36Sopenharmony_ci		 * CLOSE event
81462306a36Sopenharmony_ci		 */
81562306a36Sopenharmony_ci		csio_set_state(&rn->sm, csio_rns_uninit);
81662306a36Sopenharmony_ci		break;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	case CSIO_RNFE_DOWN:
81962306a36Sopenharmony_ci	case CSIO_RNFE_NAME_MISSING:
82062306a36Sopenharmony_ci		csio_ln_dbg(ln,
82162306a36Sopenharmony_ci			"ssni:x%x Ignoring event %d recv from did x%x"
82262306a36Sopenharmony_ci			"in rn state[disappeared]\n", csio_rn_flowid(rn),
82362306a36Sopenharmony_ci			evt, rn->nport_id);
82462306a36Sopenharmony_ci		break;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	default:
82762306a36Sopenharmony_ci		csio_ln_dbg(ln,
82862306a36Sopenharmony_ci			"ssni:x%x unexp event %d recv from did x%x"
82962306a36Sopenharmony_ci			"in rn state[disappeared]\n", csio_rn_flowid(rn),
83062306a36Sopenharmony_ci			evt, rn->nport_id);
83162306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_unexp);
83262306a36Sopenharmony_ci		break;
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci/*****************************************************************************/
83762306a36Sopenharmony_ci/* END: Rnode SM                                                             */
83862306a36Sopenharmony_ci/*****************************************************************************/
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/*
84162306a36Sopenharmony_ci * csio_rnode_devloss_handler - Device loss event handler
84262306a36Sopenharmony_ci * @rn: rnode
84362306a36Sopenharmony_ci *
84462306a36Sopenharmony_ci * Post event to close rnode SM and free rnode.
84562306a36Sopenharmony_ci */
84662306a36Sopenharmony_civoid
84762306a36Sopenharmony_cicsio_rnode_devloss_handler(struct csio_rnode *rn)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* ignore if same rnode came back as online */
85262306a36Sopenharmony_ci	if (csio_is_rnode_ready(rn))
85362306a36Sopenharmony_ci		return;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	/* Free rn if in uninit state */
85862306a36Sopenharmony_ci	if (csio_is_rnode_uninit(rn))
85962306a36Sopenharmony_ci		csio_put_rnode(ln, rn);
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci/**
86362306a36Sopenharmony_ci * csio_rnode_fwevt_handler - Event handler for firmware rnode events.
86462306a36Sopenharmony_ci * @rn:		rnode
86562306a36Sopenharmony_ci * @fwevt:	firmware event to handle
86662306a36Sopenharmony_ci */
86762306a36Sopenharmony_civoid
86862306a36Sopenharmony_cicsio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
87162306a36Sopenharmony_ci	enum csio_rn_ev evt;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	evt = CSIO_FWE_TO_RNFE(fwevt);
87462306a36Sopenharmony_ci	if (!evt) {
87562306a36Sopenharmony_ci		csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n",
87662306a36Sopenharmony_ci			    csio_rn_flowid(rn), fwevt);
87762306a36Sopenharmony_ci		CSIO_INC_STATS(rn, n_evt_unexp);
87862306a36Sopenharmony_ci		return;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci	CSIO_INC_STATS(rn, n_evt_fw[fwevt]);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	/* Track previous & current events for debugging */
88362306a36Sopenharmony_ci	rn->prev_evt = rn->cur_evt;
88462306a36Sopenharmony_ci	rn->cur_evt = fwevt;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* Post event to rnode SM */
88762306a36Sopenharmony_ci	csio_post_event(&rn->sm, evt);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* Free rn if in uninit state */
89062306a36Sopenharmony_ci	if (csio_is_rnode_uninit(rn))
89162306a36Sopenharmony_ci		csio_put_rnode(ln, rn);
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci/*
89562306a36Sopenharmony_ci * csio_rnode_init - Initialize rnode.
89662306a36Sopenharmony_ci * @rn: RNode
89762306a36Sopenharmony_ci * @ln: Associated lnode
89862306a36Sopenharmony_ci *
89962306a36Sopenharmony_ci * Caller is responsible for holding the lock. The lock is required
90062306a36Sopenharmony_ci * to be held for inserting the rnode in ln->rnhead list.
90162306a36Sopenharmony_ci */
90262306a36Sopenharmony_cistatic int
90362306a36Sopenharmony_cicsio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	csio_rnode_to_lnode(rn) = ln;
90662306a36Sopenharmony_ci	csio_init_state(&rn->sm, csio_rns_uninit);
90762306a36Sopenharmony_ci	INIT_LIST_HEAD(&rn->host_cmpl_q);
90862306a36Sopenharmony_ci	csio_rn_flowid(rn) = CSIO_INVALID_IDX;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* Add rnode to list of lnodes->rnhead */
91162306a36Sopenharmony_ci	list_add_tail(&rn->sm.sm_list, &ln->rnhead);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	return 0;
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic void
91762306a36Sopenharmony_cicsio_rnode_exit(struct csio_rnode *rn)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	list_del_init(&rn->sm.sm_list);
92062306a36Sopenharmony_ci	CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q));
92162306a36Sopenharmony_ci}
922