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