cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

csio_rnode.c (23181B)


      1/*
      2 * This file is part of the Chelsio FCoE driver for Linux.
      3 *
      4 * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
      5 *
      6 * This software is available to you under a choice of one of two
      7 * licenses.  You may choose to be licensed under the terms of the GNU
      8 * General Public License (GPL) Version 2, available from the file
      9 * COPYING in the main directory of this source tree, or the
     10 * OpenIB.org BSD license below:
     11 *
     12 *     Redistribution and use in source and binary forms, with or
     13 *     without modification, are permitted provided that the following
     14 *     conditions are met:
     15 *
     16 *      - Redistributions of source code must retain the above
     17 *        copyright notice, this list of conditions and the following
     18 *        disclaimer.
     19 *
     20 *      - Redistributions in binary form must reproduce the above
     21 *        copyright notice, this list of conditions and the following
     22 *        disclaimer in the documentation and/or other materials
     23 *        provided with the distribution.
     24 *
     25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     32 * SOFTWARE.
     33 */
     34
     35#include <linux/string.h>
     36#include <scsi/scsi_device.h>
     37#include <scsi/scsi_transport_fc.h>
     38#include <scsi/fc/fc_els.h>
     39#include <scsi/fc/fc_fs.h>
     40
     41#include "csio_hw.h"
     42#include "csio_lnode.h"
     43#include "csio_rnode.h"
     44
     45static int csio_rnode_init(struct csio_rnode *, struct csio_lnode *);
     46static void csio_rnode_exit(struct csio_rnode *);
     47
     48/* Static machine forward declarations */
     49static void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev);
     50static void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev);
     51static void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev);
     52static void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev);
     53
     54/* RNF event mapping */
     55static enum csio_rn_ev fwevt_to_rnevt[] = {
     56	CSIO_RNFE_NONE,		/* None */
     57	CSIO_RNFE_LOGGED_IN,	/* PLOGI_ACC_RCVD  */
     58	CSIO_RNFE_NONE,		/* PLOGI_RJT_RCVD  */
     59	CSIO_RNFE_PLOGI_RECV,	/* PLOGI_RCVD	   */
     60	CSIO_RNFE_LOGO_RECV,	/* PLOGO_RCVD	   */
     61	CSIO_RNFE_PRLI_DONE,	/* PRLI_ACC_RCVD   */
     62	CSIO_RNFE_NONE,		/* PRLI_RJT_RCVD   */
     63	CSIO_RNFE_PRLI_RECV,	/* PRLI_RCVD	   */
     64	CSIO_RNFE_PRLO_RECV,	/* PRLO_RCVD	   */
     65	CSIO_RNFE_NONE,		/* NPORT_ID_CHGD   */
     66	CSIO_RNFE_LOGO_RECV,	/* FLOGO_RCVD	   */
     67	CSIO_RNFE_NONE,		/* CLR_VIRT_LNK_RCVD */
     68	CSIO_RNFE_LOGGED_IN,	/* FLOGI_ACC_RCVD   */
     69	CSIO_RNFE_NONE,		/* FLOGI_RJT_RCVD   */
     70	CSIO_RNFE_LOGGED_IN,	/* FDISC_ACC_RCVD   */
     71	CSIO_RNFE_NONE,		/* FDISC_RJT_RCVD   */
     72	CSIO_RNFE_NONE,		/* FLOGI_TMO_MAX_RETRY */
     73	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_ACC */
     74	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_RJT */
     75	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_CNFLT */
     76	CSIO_RNFE_NONE,		/* PRLI_TMO		*/
     77	CSIO_RNFE_NONE,		/* ADISC_TMO		*/
     78	CSIO_RNFE_NAME_MISSING,	/* RSCN_DEV_LOST  */
     79	CSIO_RNFE_NONE,		/* SCR_ACC_RCVD	*/
     80	CSIO_RNFE_NONE,		/* ADISC_RJT_RCVD */
     81	CSIO_RNFE_NONE,		/* LOGO_SNT */
     82	CSIO_RNFE_LOGO_RECV,	/* PROTO_ERR_IMPL_LOGO */
     83};
     84
     85#define CSIO_FWE_TO_RNFE(_evt)	((_evt > PROTO_ERR_IMPL_LOGO) ?		\
     86						CSIO_RNFE_NONE :	\
     87						fwevt_to_rnevt[_evt])
     88int
     89csio_is_rnode_ready(struct csio_rnode *rn)
     90{
     91	return csio_match_state(rn, csio_rns_ready);
     92}
     93
     94static int
     95csio_is_rnode_uninit(struct csio_rnode *rn)
     96{
     97	return csio_match_state(rn, csio_rns_uninit);
     98}
     99
    100static int
    101csio_is_rnode_wka(uint8_t rport_type)
    102{
    103	if ((rport_type == FLOGI_VFPORT) ||
    104	    (rport_type == FDISC_VFPORT) ||
    105	    (rport_type == NS_VNPORT) ||
    106	    (rport_type == FDMI_VNPORT))
    107		return 1;
    108
    109	return 0;
    110}
    111
    112/*
    113 * csio_rn_lookup - Finds the rnode with the given flowid
    114 * @ln - lnode
    115 * @flowid - flowid.
    116 *
    117 * Does the rnode lookup on the given lnode and flowid.If no matching entry
    118 * found, NULL is returned.
    119 */
    120static struct csio_rnode *
    121csio_rn_lookup(struct csio_lnode *ln, uint32_t flowid)
    122{
    123	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
    124	struct list_head *tmp;
    125	struct csio_rnode *rn;
    126
    127	list_for_each(tmp, &rnhead->sm.sm_list) {
    128		rn = (struct csio_rnode *) tmp;
    129		if (rn->flowid == flowid)
    130			return rn;
    131	}
    132
    133	return NULL;
    134}
    135
    136/*
    137 * csio_rn_lookup_wwpn - Finds the rnode with the given wwpn
    138 * @ln: lnode
    139 * @wwpn: wwpn
    140 *
    141 * Does the rnode lookup on the given lnode and wwpn. If no matching entry
    142 * found, NULL is returned.
    143 */
    144static struct csio_rnode *
    145csio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn)
    146{
    147	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
    148	struct list_head *tmp;
    149	struct csio_rnode *rn;
    150
    151	list_for_each(tmp, &rnhead->sm.sm_list) {
    152		rn = (struct csio_rnode *) tmp;
    153		if (!memcmp(csio_rn_wwpn(rn), wwpn, 8))
    154			return rn;
    155	}
    156
    157	return NULL;
    158}
    159
    160/**
    161 * csio_rnode_lookup_portid - Finds the rnode with the given portid
    162 * @ln:		lnode
    163 * @portid:	port id
    164 *
    165 * Lookup the rnode list for a given portid. If no matching entry
    166 * found, NULL is returned.
    167 */
    168struct csio_rnode *
    169csio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid)
    170{
    171	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
    172	struct list_head *tmp;
    173	struct csio_rnode *rn;
    174
    175	list_for_each(tmp, &rnhead->sm.sm_list) {
    176		rn = (struct csio_rnode *) tmp;
    177		if (rn->nport_id == portid)
    178			return rn;
    179	}
    180
    181	return NULL;
    182}
    183
    184static int
    185csio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid,
    186		    uint32_t *vnp_flowid)
    187{
    188	struct csio_rnode *rnhead;
    189	struct list_head *tmp, *tmp1;
    190	struct csio_rnode *rn;
    191	struct csio_lnode *ln_tmp;
    192	struct csio_hw *hw = csio_lnode_to_hw(ln);
    193
    194	list_for_each(tmp1, &hw->sln_head) {
    195		ln_tmp = (struct csio_lnode *) tmp1;
    196		if (ln_tmp == ln)
    197			continue;
    198
    199		rnhead = (struct csio_rnode *)&ln_tmp->rnhead;
    200		list_for_each(tmp, &rnhead->sm.sm_list) {
    201
    202			rn = (struct csio_rnode *) tmp;
    203			if (csio_is_rnode_ready(rn)) {
    204				if (rn->flowid == rdev_flowid) {
    205					*vnp_flowid = csio_ln_flowid(ln_tmp);
    206					return 1;
    207				}
    208			}
    209		}
    210	}
    211
    212	return 0;
    213}
    214
    215static struct csio_rnode *
    216csio_alloc_rnode(struct csio_lnode *ln)
    217{
    218	struct csio_hw *hw = csio_lnode_to_hw(ln);
    219
    220	struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC);
    221	if (!rn)
    222		goto err;
    223
    224	memset(rn, 0, sizeof(struct csio_rnode));
    225	if (csio_rnode_init(rn, ln))
    226		goto err_free;
    227
    228	CSIO_INC_STATS(ln, n_rnode_alloc);
    229
    230	return rn;
    231
    232err_free:
    233	mempool_free(rn, hw->rnode_mempool);
    234err:
    235	CSIO_INC_STATS(ln, n_rnode_nomem);
    236	return NULL;
    237}
    238
    239static void
    240csio_free_rnode(struct csio_rnode *rn)
    241{
    242	struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
    243
    244	csio_rnode_exit(rn);
    245	CSIO_INC_STATS(rn->lnp, n_rnode_free);
    246	mempool_free(rn, hw->rnode_mempool);
    247}
    248
    249/*
    250 * csio_get_rnode - Gets rnode with the given flowid
    251 * @ln - lnode
    252 * @flowid - flow id.
    253 *
    254 * Does the rnode lookup on the given lnode and flowid. If no matching
    255 * rnode found, then new rnode with given npid is allocated and returned.
    256 */
    257static struct csio_rnode *
    258csio_get_rnode(struct csio_lnode *ln, uint32_t flowid)
    259{
    260	struct csio_rnode *rn;
    261
    262	rn = csio_rn_lookup(ln, flowid);
    263	if (!rn) {
    264		rn = csio_alloc_rnode(ln);
    265		if (!rn)
    266			return NULL;
    267
    268		rn->flowid = flowid;
    269	}
    270
    271	return rn;
    272}
    273
    274/*
    275 * csio_put_rnode - Frees the given rnode
    276 * @ln - lnode
    277 * @flowid - flow id.
    278 *
    279 * Does the rnode lookup on the given lnode and flowid. If no matching
    280 * rnode found, then new rnode with given npid is allocated and returned.
    281 */
    282void
    283csio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn)
    284{
    285	CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0);
    286	csio_free_rnode(rn);
    287}
    288
    289/*
    290 * csio_confirm_rnode - confirms rnode based on wwpn.
    291 * @ln: lnode
    292 * @rdev_flowid: remote device flowid
    293 * @rdevp: remote device params
    294 * This routines searches other rnode in list having same wwpn of new rnode.
    295 * If there is a match, then matched rnode is returned and otherwise new rnode
    296 * is returned.
    297 * returns rnode.
    298 */
    299struct csio_rnode *
    300csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
    301		   struct fcoe_rdev_entry *rdevp)
    302{
    303	uint8_t rport_type;
    304	struct csio_rnode *rn, *match_rn;
    305	uint32_t vnp_flowid = 0;
    306	__be32 *port_id;
    307
    308	port_id = (__be32 *)&rdevp->r_id[0];
    309	rport_type =
    310		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
    311
    312	/* Drop rdev event for cntrl port */
    313	if (rport_type == FAB_CTLR_VNPORT) {
    314		csio_ln_dbg(ln,
    315			    "Unhandled rport_type:%d recv in rdev evt "
    316			    "ssni:x%x\n", rport_type, rdev_flowid);
    317		return NULL;
    318	}
    319
    320	/* Lookup on flowid */
    321	rn = csio_rn_lookup(ln, rdev_flowid);
    322	if (!rn) {
    323
    324		/* Drop events with duplicate flowid */
    325		if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) {
    326			csio_ln_warn(ln,
    327				     "ssni:%x already active on vnpi:%x",
    328				     rdev_flowid, vnp_flowid);
    329			return NULL;
    330		}
    331
    332		/* Lookup on wwpn for NPORTs */
    333		rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
    334		if (!rn)
    335			goto alloc_rnode;
    336
    337	} else {
    338		/* Lookup well-known ports with nport id */
    339		if (csio_is_rnode_wka(rport_type)) {
    340			match_rn = csio_rnode_lookup_portid(ln,
    341				      ((ntohl(*port_id) >> 8) & CSIO_DID_MASK));
    342			if (match_rn == NULL) {
    343				csio_rn_flowid(rn) = CSIO_INVALID_IDX;
    344				goto alloc_rnode;
    345			}
    346
    347			/*
    348			 * Now compare the wwpn to confirm that
    349			 * same port relogged in. If so update the matched rn.
    350			 * Else, go ahead and alloc a new rnode.
    351			 */
    352			if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) {
    353				if (rn == match_rn)
    354					goto found_rnode;
    355				csio_ln_dbg(ln,
    356					    "nport_id:x%x and wwpn:%llx"
    357					    " match for ssni:x%x\n",
    358					    rn->nport_id,
    359					    wwn_to_u64(rdevp->wwpn),
    360					    rdev_flowid);
    361				if (csio_is_rnode_ready(rn)) {
    362					csio_ln_warn(ln,
    363						     "rnode is already"
    364						     "active ssni:x%x\n",
    365						     rdev_flowid);
    366					CSIO_ASSERT(0);
    367				}
    368				csio_rn_flowid(rn) = CSIO_INVALID_IDX;
    369				rn = match_rn;
    370
    371				/* Update rn */
    372				goto found_rnode;
    373			}
    374			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
    375			goto alloc_rnode;
    376		}
    377
    378		/* wwpn match */
    379		if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8))
    380			goto found_rnode;
    381
    382		/* Search for rnode that have same wwpn */
    383		match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
    384		if (match_rn != NULL) {
    385			csio_ln_dbg(ln,
    386				"ssni:x%x changed for rport name(wwpn):%llx "
    387				"did:x%x\n", rdev_flowid,
    388				wwn_to_u64(rdevp->wwpn),
    389				match_rn->nport_id);
    390			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
    391			rn = match_rn;
    392		} else {
    393			csio_ln_dbg(ln,
    394				"rnode wwpn mismatch found ssni:x%x "
    395				"name(wwpn):%llx\n",
    396				rdev_flowid,
    397				wwn_to_u64(csio_rn_wwpn(rn)));
    398			if (csio_is_rnode_ready(rn)) {
    399				csio_ln_warn(ln,
    400					     "rnode is already active "
    401					     "wwpn:%llx ssni:x%x\n",
    402					     wwn_to_u64(csio_rn_wwpn(rn)),
    403					     rdev_flowid);
    404				CSIO_ASSERT(0);
    405			}
    406			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
    407			goto alloc_rnode;
    408		}
    409	}
    410
    411found_rnode:
    412	csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n",
    413		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
    414
    415	/* Update flowid */
    416	csio_rn_flowid(rn) = rdev_flowid;
    417
    418	/* update rdev entry */
    419	rn->rdev_entry = rdevp;
    420	CSIO_INC_STATS(ln, n_rnode_match);
    421	return rn;
    422
    423alloc_rnode:
    424	rn = csio_get_rnode(ln, rdev_flowid);
    425	if (!rn)
    426		return NULL;
    427
    428	csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n",
    429		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
    430
    431	/* update rdev entry */
    432	rn->rdev_entry = rdevp;
    433	return rn;
    434}
    435
    436/*
    437 * csio_rn_verify_rparams - verify rparams.
    438 * @ln: lnode
    439 * @rn: rnode
    440 * @rdevp: remote device params
    441 * returns success if rparams are verified.
    442 */
    443static int
    444csio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn,
    445			struct fcoe_rdev_entry *rdevp)
    446{
    447	uint8_t null[8];
    448	uint8_t rport_type;
    449	uint8_t fc_class;
    450	__be32 *did;
    451
    452	did = (__be32 *) &rdevp->r_id[0];
    453	rport_type =
    454		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
    455	switch (rport_type) {
    456	case FLOGI_VFPORT:
    457		rn->role = CSIO_RNFR_FABRIC;
    458		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) {
    459			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
    460				csio_rn_flowid(rn));
    461			return -EINVAL;
    462		}
    463		/* NPIV support */
    464		if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos))
    465			ln->flags |= CSIO_LNF_NPIVSUPP;
    466
    467		break;
    468
    469	case NS_VNPORT:
    470		rn->role = CSIO_RNFR_NS;
    471		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) {
    472			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
    473				csio_rn_flowid(rn));
    474			return -EINVAL;
    475		}
    476		break;
    477
    478	case REG_FC4_VNPORT:
    479	case REG_VNPORT:
    480		rn->role = CSIO_RNFR_NPORT;
    481		if (rdevp->event_cause == PRLI_ACC_RCVD ||
    482			rdevp->event_cause == PRLI_RCVD) {
    483			if (FW_RDEV_WR_TASK_RETRY_ID_GET(
    484							rdevp->enh_disc_to_tgt))
    485				rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW;
    486
    487			if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt))
    488				rn->fcp_flags |= FCP_SPPF_RETRY;
    489
    490			if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt))
    491				rn->fcp_flags |= FCP_SPPF_CONF_COMPL;
    492
    493			if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt))
    494				rn->role |= CSIO_RNFR_TARGET;
    495
    496			if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt))
    497				rn->role |= CSIO_RNFR_INITIATOR;
    498		}
    499
    500		break;
    501
    502	case FDMI_VNPORT:
    503	case FAB_CTLR_VNPORT:
    504		rn->role = 0;
    505		break;
    506
    507	default:
    508		csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n",
    509			csio_rn_flowid(rn), rport_type);
    510		return -EINVAL;
    511	}
    512
    513	/* validate wwpn/wwnn for Name server/remote port */
    514	if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) {
    515		memset(null, 0, 8);
    516		if (!memcmp(rdevp->wwnn, null, 8)) {
    517			csio_ln_err(ln,
    518				    "ssni:x%x invalid wwnn received from"
    519				    " rport did:x%x\n",
    520				    csio_rn_flowid(rn),
    521				    (ntohl(*did) & CSIO_DID_MASK));
    522			return -EINVAL;
    523		}
    524
    525		if (!memcmp(rdevp->wwpn, null, 8)) {
    526			csio_ln_err(ln,
    527				    "ssni:x%x invalid wwpn received from"
    528				    " rport did:x%x\n",
    529				    csio_rn_flowid(rn),
    530				    (ntohl(*did) & CSIO_DID_MASK));
    531			return -EINVAL;
    532		}
    533
    534	}
    535
    536	/* Copy wwnn, wwpn and nport id */
    537	rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK;
    538	memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8);
    539	memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8);
    540	rn->rn_sparm.csp.sp_bb_data = rdevp->rcv_fr_sz;
    541	fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos);
    542	rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID);
    543
    544	return 0;
    545}
    546
    547static void
    548__csio_reg_rnode(struct csio_rnode *rn)
    549{
    550	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    551	struct csio_hw *hw = csio_lnode_to_hw(ln);
    552
    553	spin_unlock_irq(&hw->lock);
    554	csio_reg_rnode(rn);
    555	spin_lock_irq(&hw->lock);
    556
    557	if (rn->role & CSIO_RNFR_TARGET)
    558		ln->n_scsi_tgts++;
    559
    560	if (rn->nport_id == FC_FID_MGMT_SERV)
    561		csio_ln_fdmi_start(ln, (void *) rn);
    562}
    563
    564static void
    565__csio_unreg_rnode(struct csio_rnode *rn)
    566{
    567	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    568	struct csio_hw *hw = csio_lnode_to_hw(ln);
    569	LIST_HEAD(tmp_q);
    570	int cmpl = 0;
    571
    572	if (!list_empty(&rn->host_cmpl_q)) {
    573		csio_dbg(hw, "Returning completion queue I/Os\n");
    574		list_splice_tail_init(&rn->host_cmpl_q, &tmp_q);
    575		cmpl = 1;
    576	}
    577
    578	if (rn->role & CSIO_RNFR_TARGET) {
    579		ln->n_scsi_tgts--;
    580		ln->last_scan_ntgts--;
    581	}
    582
    583	spin_unlock_irq(&hw->lock);
    584	csio_unreg_rnode(rn);
    585	spin_lock_irq(&hw->lock);
    586
    587	/* Cleanup I/Os that were waiting for rnode to unregister */
    588	if (cmpl)
    589		csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q);
    590
    591}
    592
    593/*****************************************************************************/
    594/* START: Rnode SM                                                           */
    595/*****************************************************************************/
    596
    597/*
    598 * csio_rns_uninit -
    599 * @rn - rnode
    600 * @evt - SM event.
    601 *
    602 */
    603static void
    604csio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt)
    605{
    606	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    607	int ret = 0;
    608
    609	CSIO_INC_STATS(rn, n_evt_sm[evt]);
    610
    611	switch (evt) {
    612	case CSIO_RNFE_LOGGED_IN:
    613	case CSIO_RNFE_PLOGI_RECV:
    614		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
    615		if (!ret) {
    616			csio_set_state(&rn->sm, csio_rns_ready);
    617			__csio_reg_rnode(rn);
    618		} else {
    619			CSIO_INC_STATS(rn, n_err_inval);
    620		}
    621		break;
    622	case CSIO_RNFE_LOGO_RECV:
    623		csio_ln_dbg(ln,
    624			    "ssni:x%x Ignoring event %d recv "
    625			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
    626		CSIO_INC_STATS(rn, n_evt_drop);
    627		break;
    628	default:
    629		csio_ln_dbg(ln,
    630			    "ssni:x%x unexp event %d recv "
    631			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
    632		CSIO_INC_STATS(rn, n_evt_unexp);
    633		break;
    634	}
    635}
    636
    637/*
    638 * csio_rns_ready -
    639 * @rn - rnode
    640 * @evt - SM event.
    641 *
    642 */
    643static void
    644csio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt)
    645{
    646	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    647	int ret = 0;
    648
    649	CSIO_INC_STATS(rn, n_evt_sm[evt]);
    650
    651	switch (evt) {
    652	case CSIO_RNFE_LOGGED_IN:
    653	case CSIO_RNFE_PLOGI_RECV:
    654		csio_ln_dbg(ln,
    655			"ssni:x%x Ignoring event %d recv from did:x%x "
    656			"in rn state[ready]\n", csio_rn_flowid(rn), evt,
    657			rn->nport_id);
    658		CSIO_INC_STATS(rn, n_evt_drop);
    659		break;
    660
    661	case CSIO_RNFE_PRLI_DONE:
    662	case CSIO_RNFE_PRLI_RECV:
    663		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
    664		if (!ret)
    665			__csio_reg_rnode(rn);
    666		else
    667			CSIO_INC_STATS(rn, n_err_inval);
    668
    669		break;
    670	case CSIO_RNFE_DOWN:
    671		csio_set_state(&rn->sm, csio_rns_offline);
    672		__csio_unreg_rnode(rn);
    673
    674		/* FW expected to internally aborted outstanding SCSI WRs
    675		 * and return all SCSI WRs to host with status "ABORTED".
    676		 */
    677		break;
    678
    679	case CSIO_RNFE_LOGO_RECV:
    680		csio_set_state(&rn->sm, csio_rns_offline);
    681
    682		__csio_unreg_rnode(rn);
    683
    684		/* FW expected to internally aborted outstanding SCSI WRs
    685		 * and return all SCSI WRs to host with status "ABORTED".
    686		 */
    687		break;
    688
    689	case CSIO_RNFE_CLOSE:
    690		/*
    691		 * Each rnode receives CLOSE event when driver is removed or
    692		 * device is reset
    693		 * Note: All outstanding IOs on remote port need to returned
    694		 * to uppper layer with appropriate error before sending
    695		 * CLOSE event
    696		 */
    697		csio_set_state(&rn->sm, csio_rns_uninit);
    698		__csio_unreg_rnode(rn);
    699		break;
    700
    701	case CSIO_RNFE_NAME_MISSING:
    702		csio_set_state(&rn->sm, csio_rns_disappeared);
    703		__csio_unreg_rnode(rn);
    704
    705		/*
    706		 * FW expected to internally aborted outstanding SCSI WRs
    707		 * and return all SCSI WRs to host with status "ABORTED".
    708		 */
    709
    710		break;
    711
    712	default:
    713		csio_ln_dbg(ln,
    714			"ssni:x%x unexp event %d recv from did:x%x "
    715			"in rn state[uninit]\n", csio_rn_flowid(rn), evt,
    716			rn->nport_id);
    717		CSIO_INC_STATS(rn, n_evt_unexp);
    718		break;
    719	}
    720}
    721
    722/*
    723 * csio_rns_offline -
    724 * @rn - rnode
    725 * @evt - SM event.
    726 *
    727 */
    728static void
    729csio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt)
    730{
    731	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    732	int ret = 0;
    733
    734	CSIO_INC_STATS(rn, n_evt_sm[evt]);
    735
    736	switch (evt) {
    737	case CSIO_RNFE_LOGGED_IN:
    738	case CSIO_RNFE_PLOGI_RECV:
    739		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
    740		if (!ret) {
    741			csio_set_state(&rn->sm, csio_rns_ready);
    742			__csio_reg_rnode(rn);
    743		} else {
    744			CSIO_INC_STATS(rn, n_err_inval);
    745			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
    746		}
    747		break;
    748
    749	case CSIO_RNFE_DOWN:
    750		csio_ln_dbg(ln,
    751			"ssni:x%x Ignoring event %d recv from did:x%x "
    752			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
    753			rn->nport_id);
    754		CSIO_INC_STATS(rn, n_evt_drop);
    755		break;
    756
    757	case CSIO_RNFE_CLOSE:
    758		/* Each rnode receives CLOSE event when driver is removed or
    759		 * device is reset
    760		 * Note: All outstanding IOs on remote port need to returned
    761		 * to uppper layer with appropriate error before sending
    762		 * CLOSE event
    763		 */
    764		csio_set_state(&rn->sm, csio_rns_uninit);
    765		break;
    766
    767	case CSIO_RNFE_NAME_MISSING:
    768		csio_set_state(&rn->sm, csio_rns_disappeared);
    769		break;
    770
    771	default:
    772		csio_ln_dbg(ln,
    773			"ssni:x%x unexp event %d recv from did:x%x "
    774			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
    775			rn->nport_id);
    776		CSIO_INC_STATS(rn, n_evt_unexp);
    777		break;
    778	}
    779}
    780
    781/*
    782 * csio_rns_disappeared -
    783 * @rn - rnode
    784 * @evt - SM event.
    785 *
    786 */
    787static void
    788csio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt)
    789{
    790	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    791	int ret = 0;
    792
    793	CSIO_INC_STATS(rn, n_evt_sm[evt]);
    794
    795	switch (evt) {
    796	case CSIO_RNFE_LOGGED_IN:
    797	case CSIO_RNFE_PLOGI_RECV:
    798		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
    799		if (!ret) {
    800			csio_set_state(&rn->sm, csio_rns_ready);
    801			__csio_reg_rnode(rn);
    802		} else {
    803			CSIO_INC_STATS(rn, n_err_inval);
    804			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
    805		}
    806		break;
    807
    808	case CSIO_RNFE_CLOSE:
    809		/* Each rnode receives CLOSE event when driver is removed or
    810		 * device is reset.
    811		 * Note: All outstanding IOs on remote port need to returned
    812		 * to uppper layer with appropriate error before sending
    813		 * CLOSE event
    814		 */
    815		csio_set_state(&rn->sm, csio_rns_uninit);
    816		break;
    817
    818	case CSIO_RNFE_DOWN:
    819	case CSIO_RNFE_NAME_MISSING:
    820		csio_ln_dbg(ln,
    821			"ssni:x%x Ignoring event %d recv from did x%x"
    822			"in rn state[disappeared]\n", csio_rn_flowid(rn),
    823			evt, rn->nport_id);
    824		break;
    825
    826	default:
    827		csio_ln_dbg(ln,
    828			"ssni:x%x unexp event %d recv from did x%x"
    829			"in rn state[disappeared]\n", csio_rn_flowid(rn),
    830			evt, rn->nport_id);
    831		CSIO_INC_STATS(rn, n_evt_unexp);
    832		break;
    833	}
    834}
    835
    836/*****************************************************************************/
    837/* END: Rnode SM                                                             */
    838/*****************************************************************************/
    839
    840/*
    841 * csio_rnode_devloss_handler - Device loss event handler
    842 * @rn: rnode
    843 *
    844 * Post event to close rnode SM and free rnode.
    845 */
    846void
    847csio_rnode_devloss_handler(struct csio_rnode *rn)
    848{
    849	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    850
    851	/* ignore if same rnode came back as online */
    852	if (csio_is_rnode_ready(rn))
    853		return;
    854
    855	csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
    856
    857	/* Free rn if in uninit state */
    858	if (csio_is_rnode_uninit(rn))
    859		csio_put_rnode(ln, rn);
    860}
    861
    862/**
    863 * csio_rnode_fwevt_handler - Event handler for firmware rnode events.
    864 * @rn:		rnode
    865 * @fwevt:	firmware event to handle
    866 */
    867void
    868csio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt)
    869{
    870	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
    871	enum csio_rn_ev evt;
    872
    873	evt = CSIO_FWE_TO_RNFE(fwevt);
    874	if (!evt) {
    875		csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n",
    876			    csio_rn_flowid(rn), fwevt);
    877		CSIO_INC_STATS(rn, n_evt_unexp);
    878		return;
    879	}
    880	CSIO_INC_STATS(rn, n_evt_fw[fwevt]);
    881
    882	/* Track previous & current events for debugging */
    883	rn->prev_evt = rn->cur_evt;
    884	rn->cur_evt = fwevt;
    885
    886	/* Post event to rnode SM */
    887	csio_post_event(&rn->sm, evt);
    888
    889	/* Free rn if in uninit state */
    890	if (csio_is_rnode_uninit(rn))
    891		csio_put_rnode(ln, rn);
    892}
    893
    894/*
    895 * csio_rnode_init - Initialize rnode.
    896 * @rn: RNode
    897 * @ln: Associated lnode
    898 *
    899 * Caller is responsible for holding the lock. The lock is required
    900 * to be held for inserting the rnode in ln->rnhead list.
    901 */
    902static int
    903csio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln)
    904{
    905	csio_rnode_to_lnode(rn) = ln;
    906	csio_init_state(&rn->sm, csio_rns_uninit);
    907	INIT_LIST_HEAD(&rn->host_cmpl_q);
    908	csio_rn_flowid(rn) = CSIO_INVALID_IDX;
    909
    910	/* Add rnode to list of lnodes->rnhead */
    911	list_add_tail(&rn->sm.sm_list, &ln->rnhead);
    912
    913	return 0;
    914}
    915
    916static void
    917csio_rnode_exit(struct csio_rnode *rn)
    918{
    919	list_del_init(&rn->sm.sm_list);
    920	CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q));
    921}