18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/string.h> 368c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 378c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_fc.h> 388c2ecf20Sopenharmony_ci#include <scsi/fc/fc_els.h> 398c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "csio_hw.h" 428c2ecf20Sopenharmony_ci#include "csio_lnode.h" 438c2ecf20Sopenharmony_ci#include "csio_rnode.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int csio_rnode_init(struct csio_rnode *, struct csio_lnode *); 468c2ecf20Sopenharmony_cistatic void csio_rnode_exit(struct csio_rnode *); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Static machine forward declarations */ 498c2ecf20Sopenharmony_cistatic void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev); 508c2ecf20Sopenharmony_cistatic void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev); 518c2ecf20Sopenharmony_cistatic void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev); 528c2ecf20Sopenharmony_cistatic void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* RNF event mapping */ 558c2ecf20Sopenharmony_cistatic enum csio_rn_ev fwevt_to_rnevt[] = { 568c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* None */ 578c2ecf20Sopenharmony_ci CSIO_RNFE_LOGGED_IN, /* PLOGI_ACC_RCVD */ 588c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* PLOGI_RJT_RCVD */ 598c2ecf20Sopenharmony_ci CSIO_RNFE_PLOGI_RECV, /* PLOGI_RCVD */ 608c2ecf20Sopenharmony_ci CSIO_RNFE_LOGO_RECV, /* PLOGO_RCVD */ 618c2ecf20Sopenharmony_ci CSIO_RNFE_PRLI_DONE, /* PRLI_ACC_RCVD */ 628c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* PRLI_RJT_RCVD */ 638c2ecf20Sopenharmony_ci CSIO_RNFE_PRLI_RECV, /* PRLI_RCVD */ 648c2ecf20Sopenharmony_ci CSIO_RNFE_PRLO_RECV, /* PRLO_RCVD */ 658c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* NPORT_ID_CHGD */ 668c2ecf20Sopenharmony_ci CSIO_RNFE_LOGO_RECV, /* FLOGO_RCVD */ 678c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* CLR_VIRT_LNK_RCVD */ 688c2ecf20Sopenharmony_ci CSIO_RNFE_LOGGED_IN, /* FLOGI_ACC_RCVD */ 698c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* FLOGI_RJT_RCVD */ 708c2ecf20Sopenharmony_ci CSIO_RNFE_LOGGED_IN, /* FDISC_ACC_RCVD */ 718c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* FDISC_RJT_RCVD */ 728c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* FLOGI_TMO_MAX_RETRY */ 738c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_ACC */ 748c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_RJT */ 758c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_CNFLT */ 768c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* PRLI_TMO */ 778c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* ADISC_TMO */ 788c2ecf20Sopenharmony_ci CSIO_RNFE_NAME_MISSING, /* RSCN_DEV_LOST */ 798c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* SCR_ACC_RCVD */ 808c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* ADISC_RJT_RCVD */ 818c2ecf20Sopenharmony_ci CSIO_RNFE_NONE, /* LOGO_SNT */ 828c2ecf20Sopenharmony_ci CSIO_RNFE_LOGO_RECV, /* PROTO_ERR_IMPL_LOGO */ 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define CSIO_FWE_TO_RNFE(_evt) ((_evt > PROTO_ERR_IMPL_LOGO) ? \ 868c2ecf20Sopenharmony_ci CSIO_RNFE_NONE : \ 878c2ecf20Sopenharmony_ci fwevt_to_rnevt[_evt]) 888c2ecf20Sopenharmony_ciint 898c2ecf20Sopenharmony_cicsio_is_rnode_ready(struct csio_rnode *rn) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci return csio_match_state(rn, csio_rns_ready); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int 958c2ecf20Sopenharmony_cicsio_is_rnode_uninit(struct csio_rnode *rn) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci return csio_match_state(rn, csio_rns_uninit); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int 1018c2ecf20Sopenharmony_cicsio_is_rnode_wka(uint8_t rport_type) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci if ((rport_type == FLOGI_VFPORT) || 1048c2ecf20Sopenharmony_ci (rport_type == FDISC_VFPORT) || 1058c2ecf20Sopenharmony_ci (rport_type == NS_VNPORT) || 1068c2ecf20Sopenharmony_ci (rport_type == FDMI_VNPORT)) 1078c2ecf20Sopenharmony_ci return 1; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* 1138c2ecf20Sopenharmony_ci * csio_rn_lookup - Finds the rnode with the given flowid 1148c2ecf20Sopenharmony_ci * @ln - lnode 1158c2ecf20Sopenharmony_ci * @flowid - flowid. 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Does the rnode lookup on the given lnode and flowid.If no matching entry 1188c2ecf20Sopenharmony_ci * found, NULL is returned. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistatic struct csio_rnode * 1218c2ecf20Sopenharmony_cicsio_rn_lookup(struct csio_lnode *ln, uint32_t flowid) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 1248c2ecf20Sopenharmony_ci struct list_head *tmp; 1258c2ecf20Sopenharmony_ci struct csio_rnode *rn; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci list_for_each(tmp, &rnhead->sm.sm_list) { 1288c2ecf20Sopenharmony_ci rn = (struct csio_rnode *) tmp; 1298c2ecf20Sopenharmony_ci if (rn->flowid == flowid) 1308c2ecf20Sopenharmony_ci return rn; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return NULL; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * csio_rn_lookup_wwpn - Finds the rnode with the given wwpn 1388c2ecf20Sopenharmony_ci * @ln: lnode 1398c2ecf20Sopenharmony_ci * @wwpn: wwpn 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * Does the rnode lookup on the given lnode and wwpn. If no matching entry 1428c2ecf20Sopenharmony_ci * found, NULL is returned. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cistatic struct csio_rnode * 1458c2ecf20Sopenharmony_cicsio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 1488c2ecf20Sopenharmony_ci struct list_head *tmp; 1498c2ecf20Sopenharmony_ci struct csio_rnode *rn; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci list_for_each(tmp, &rnhead->sm.sm_list) { 1528c2ecf20Sopenharmony_ci rn = (struct csio_rnode *) tmp; 1538c2ecf20Sopenharmony_ci if (!memcmp(csio_rn_wwpn(rn), wwpn, 8)) 1548c2ecf20Sopenharmony_ci return rn; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return NULL; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * csio_rnode_lookup_portid - Finds the rnode with the given portid 1628c2ecf20Sopenharmony_ci * @ln: lnode 1638c2ecf20Sopenharmony_ci * @portid: port id 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Lookup the rnode list for a given portid. If no matching entry 1668c2ecf20Sopenharmony_ci * found, NULL is returned. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistruct csio_rnode * 1698c2ecf20Sopenharmony_cicsio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 1728c2ecf20Sopenharmony_ci struct list_head *tmp; 1738c2ecf20Sopenharmony_ci struct csio_rnode *rn; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci list_for_each(tmp, &rnhead->sm.sm_list) { 1768c2ecf20Sopenharmony_ci rn = (struct csio_rnode *) tmp; 1778c2ecf20Sopenharmony_ci if (rn->nport_id == portid) 1788c2ecf20Sopenharmony_ci return rn; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return NULL; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int 1858c2ecf20Sopenharmony_cicsio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid, 1868c2ecf20Sopenharmony_ci uint32_t *vnp_flowid) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct csio_rnode *rnhead; 1898c2ecf20Sopenharmony_ci struct list_head *tmp, *tmp1; 1908c2ecf20Sopenharmony_ci struct csio_rnode *rn; 1918c2ecf20Sopenharmony_ci struct csio_lnode *ln_tmp; 1928c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci list_for_each(tmp1, &hw->sln_head) { 1958c2ecf20Sopenharmony_ci ln_tmp = (struct csio_lnode *) tmp1; 1968c2ecf20Sopenharmony_ci if (ln_tmp == ln) 1978c2ecf20Sopenharmony_ci continue; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci rnhead = (struct csio_rnode *)&ln_tmp->rnhead; 2008c2ecf20Sopenharmony_ci list_for_each(tmp, &rnhead->sm.sm_list) { 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci rn = (struct csio_rnode *) tmp; 2038c2ecf20Sopenharmony_ci if (csio_is_rnode_ready(rn)) { 2048c2ecf20Sopenharmony_ci if (rn->flowid == rdev_flowid) { 2058c2ecf20Sopenharmony_ci *vnp_flowid = csio_ln_flowid(ln_tmp); 2068c2ecf20Sopenharmony_ci return 1; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic struct csio_rnode * 2168c2ecf20Sopenharmony_cicsio_alloc_rnode(struct csio_lnode *ln) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC); 2218c2ecf20Sopenharmony_ci if (!rn) 2228c2ecf20Sopenharmony_ci goto err; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci memset(rn, 0, sizeof(struct csio_rnode)); 2258c2ecf20Sopenharmony_ci if (csio_rnode_init(rn, ln)) 2268c2ecf20Sopenharmony_ci goto err_free; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_rnode_alloc); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return rn; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cierr_free: 2338c2ecf20Sopenharmony_ci mempool_free(rn, hw->rnode_mempool); 2348c2ecf20Sopenharmony_cierr: 2358c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_rnode_nomem); 2368c2ecf20Sopenharmony_ci return NULL; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void 2408c2ecf20Sopenharmony_cicsio_free_rnode(struct csio_rnode *rn) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn)); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci csio_rnode_exit(rn); 2458c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn->lnp, n_rnode_free); 2468c2ecf20Sopenharmony_ci mempool_free(rn, hw->rnode_mempool); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* 2508c2ecf20Sopenharmony_ci * csio_get_rnode - Gets rnode with the given flowid 2518c2ecf20Sopenharmony_ci * @ln - lnode 2528c2ecf20Sopenharmony_ci * @flowid - flow id. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Does the rnode lookup on the given lnode and flowid. If no matching 2558c2ecf20Sopenharmony_ci * rnode found, then new rnode with given npid is allocated and returned. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic struct csio_rnode * 2588c2ecf20Sopenharmony_cicsio_get_rnode(struct csio_lnode *ln, uint32_t flowid) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct csio_rnode *rn; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci rn = csio_rn_lookup(ln, flowid); 2638c2ecf20Sopenharmony_ci if (!rn) { 2648c2ecf20Sopenharmony_ci rn = csio_alloc_rnode(ln); 2658c2ecf20Sopenharmony_ci if (!rn) 2668c2ecf20Sopenharmony_ci return NULL; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci rn->flowid = flowid; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return rn; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* 2758c2ecf20Sopenharmony_ci * csio_put_rnode - Frees the given rnode 2768c2ecf20Sopenharmony_ci * @ln - lnode 2778c2ecf20Sopenharmony_ci * @flowid - flow id. 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * Does the rnode lookup on the given lnode and flowid. If no matching 2808c2ecf20Sopenharmony_ci * rnode found, then new rnode with given npid is allocated and returned. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_civoid 2838c2ecf20Sopenharmony_cicsio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0); 2868c2ecf20Sopenharmony_ci csio_free_rnode(rn); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci/* 2908c2ecf20Sopenharmony_ci * csio_confirm_rnode - confirms rnode based on wwpn. 2918c2ecf20Sopenharmony_ci * @ln: lnode 2928c2ecf20Sopenharmony_ci * @rdev_flowid: remote device flowid 2938c2ecf20Sopenharmony_ci * @rdevp: remote device params 2948c2ecf20Sopenharmony_ci * This routines searches other rnode in list having same wwpn of new rnode. 2958c2ecf20Sopenharmony_ci * If there is a match, then matched rnode is returned and otherwise new rnode 2968c2ecf20Sopenharmony_ci * is returned. 2978c2ecf20Sopenharmony_ci * returns rnode. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistruct csio_rnode * 3008c2ecf20Sopenharmony_cicsio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid, 3018c2ecf20Sopenharmony_ci struct fcoe_rdev_entry *rdevp) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci uint8_t rport_type; 3048c2ecf20Sopenharmony_ci struct csio_rnode *rn, *match_rn; 3058c2ecf20Sopenharmony_ci uint32_t vnp_flowid = 0; 3068c2ecf20Sopenharmony_ci __be32 *port_id; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci port_id = (__be32 *)&rdevp->r_id[0]; 3098c2ecf20Sopenharmony_ci rport_type = 3108c2ecf20Sopenharmony_ci FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* Drop rdev event for cntrl port */ 3138c2ecf20Sopenharmony_ci if (rport_type == FAB_CTLR_VNPORT) { 3148c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 3158c2ecf20Sopenharmony_ci "Unhandled rport_type:%d recv in rdev evt " 3168c2ecf20Sopenharmony_ci "ssni:x%x\n", rport_type, rdev_flowid); 3178c2ecf20Sopenharmony_ci return NULL; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Lookup on flowid */ 3218c2ecf20Sopenharmony_ci rn = csio_rn_lookup(ln, rdev_flowid); 3228c2ecf20Sopenharmony_ci if (!rn) { 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Drop events with duplicate flowid */ 3258c2ecf20Sopenharmony_ci if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) { 3268c2ecf20Sopenharmony_ci csio_ln_warn(ln, 3278c2ecf20Sopenharmony_ci "ssni:%x already active on vnpi:%x", 3288c2ecf20Sopenharmony_ci rdev_flowid, vnp_flowid); 3298c2ecf20Sopenharmony_ci return NULL; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Lookup on wwpn for NPORTs */ 3338c2ecf20Sopenharmony_ci rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn); 3348c2ecf20Sopenharmony_ci if (!rn) 3358c2ecf20Sopenharmony_ci goto alloc_rnode; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci } else { 3388c2ecf20Sopenharmony_ci /* Lookup well-known ports with nport id */ 3398c2ecf20Sopenharmony_ci if (csio_is_rnode_wka(rport_type)) { 3408c2ecf20Sopenharmony_ci match_rn = csio_rnode_lookup_portid(ln, 3418c2ecf20Sopenharmony_ci ((ntohl(*port_id) >> 8) & CSIO_DID_MASK)); 3428c2ecf20Sopenharmony_ci if (match_rn == NULL) { 3438c2ecf20Sopenharmony_ci csio_rn_flowid(rn) = CSIO_INVALID_IDX; 3448c2ecf20Sopenharmony_ci goto alloc_rnode; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * Now compare the wwpn to confirm that 3498c2ecf20Sopenharmony_ci * same port relogged in. If so update the matched rn. 3508c2ecf20Sopenharmony_ci * Else, go ahead and alloc a new rnode. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) { 3538c2ecf20Sopenharmony_ci if (rn == match_rn) 3548c2ecf20Sopenharmony_ci goto found_rnode; 3558c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 3568c2ecf20Sopenharmony_ci "nport_id:x%x and wwpn:%llx" 3578c2ecf20Sopenharmony_ci " match for ssni:x%x\n", 3588c2ecf20Sopenharmony_ci rn->nport_id, 3598c2ecf20Sopenharmony_ci wwn_to_u64(rdevp->wwpn), 3608c2ecf20Sopenharmony_ci rdev_flowid); 3618c2ecf20Sopenharmony_ci if (csio_is_rnode_ready(rn)) { 3628c2ecf20Sopenharmony_ci csio_ln_warn(ln, 3638c2ecf20Sopenharmony_ci "rnode is already" 3648c2ecf20Sopenharmony_ci "active ssni:x%x\n", 3658c2ecf20Sopenharmony_ci rdev_flowid); 3668c2ecf20Sopenharmony_ci CSIO_ASSERT(0); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci csio_rn_flowid(rn) = CSIO_INVALID_IDX; 3698c2ecf20Sopenharmony_ci rn = match_rn; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Update rn */ 3728c2ecf20Sopenharmony_ci goto found_rnode; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci csio_rn_flowid(rn) = CSIO_INVALID_IDX; 3758c2ecf20Sopenharmony_ci goto alloc_rnode; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* wwpn match */ 3798c2ecf20Sopenharmony_ci if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8)) 3808c2ecf20Sopenharmony_ci goto found_rnode; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Search for rnode that have same wwpn */ 3838c2ecf20Sopenharmony_ci match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn); 3848c2ecf20Sopenharmony_ci if (match_rn != NULL) { 3858c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 3868c2ecf20Sopenharmony_ci "ssni:x%x changed for rport name(wwpn):%llx " 3878c2ecf20Sopenharmony_ci "did:x%x\n", rdev_flowid, 3888c2ecf20Sopenharmony_ci wwn_to_u64(rdevp->wwpn), 3898c2ecf20Sopenharmony_ci match_rn->nport_id); 3908c2ecf20Sopenharmony_ci csio_rn_flowid(rn) = CSIO_INVALID_IDX; 3918c2ecf20Sopenharmony_ci rn = match_rn; 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 3948c2ecf20Sopenharmony_ci "rnode wwpn mismatch found ssni:x%x " 3958c2ecf20Sopenharmony_ci "name(wwpn):%llx\n", 3968c2ecf20Sopenharmony_ci rdev_flowid, 3978c2ecf20Sopenharmony_ci wwn_to_u64(csio_rn_wwpn(rn))); 3988c2ecf20Sopenharmony_ci if (csio_is_rnode_ready(rn)) { 3998c2ecf20Sopenharmony_ci csio_ln_warn(ln, 4008c2ecf20Sopenharmony_ci "rnode is already active " 4018c2ecf20Sopenharmony_ci "wwpn:%llx ssni:x%x\n", 4028c2ecf20Sopenharmony_ci wwn_to_u64(csio_rn_wwpn(rn)), 4038c2ecf20Sopenharmony_ci rdev_flowid); 4048c2ecf20Sopenharmony_ci CSIO_ASSERT(0); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci csio_rn_flowid(rn) = CSIO_INVALID_IDX; 4078c2ecf20Sopenharmony_ci goto alloc_rnode; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cifound_rnode: 4128c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n", 4138c2ecf20Sopenharmony_ci rn, rdev_flowid, wwn_to_u64(rdevp->wwpn)); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Update flowid */ 4168c2ecf20Sopenharmony_ci csio_rn_flowid(rn) = rdev_flowid; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* update rdev entry */ 4198c2ecf20Sopenharmony_ci rn->rdev_entry = rdevp; 4208c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_rnode_match); 4218c2ecf20Sopenharmony_ci return rn; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cialloc_rnode: 4248c2ecf20Sopenharmony_ci rn = csio_get_rnode(ln, rdev_flowid); 4258c2ecf20Sopenharmony_ci if (!rn) 4268c2ecf20Sopenharmony_ci return NULL; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n", 4298c2ecf20Sopenharmony_ci rn, rdev_flowid, wwn_to_u64(rdevp->wwpn)); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* update rdev entry */ 4328c2ecf20Sopenharmony_ci rn->rdev_entry = rdevp; 4338c2ecf20Sopenharmony_ci return rn; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/* 4378c2ecf20Sopenharmony_ci * csio_rn_verify_rparams - verify rparams. 4388c2ecf20Sopenharmony_ci * @ln: lnode 4398c2ecf20Sopenharmony_ci * @rn: rnode 4408c2ecf20Sopenharmony_ci * @rdevp: remote device params 4418c2ecf20Sopenharmony_ci * returns success if rparams are verified. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_cistatic int 4448c2ecf20Sopenharmony_cicsio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn, 4458c2ecf20Sopenharmony_ci struct fcoe_rdev_entry *rdevp) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci uint8_t null[8]; 4488c2ecf20Sopenharmony_ci uint8_t rport_type; 4498c2ecf20Sopenharmony_ci uint8_t fc_class; 4508c2ecf20Sopenharmony_ci __be32 *did; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci did = (__be32 *) &rdevp->r_id[0]; 4538c2ecf20Sopenharmony_ci rport_type = 4548c2ecf20Sopenharmony_ci FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type); 4558c2ecf20Sopenharmony_ci switch (rport_type) { 4568c2ecf20Sopenharmony_ci case FLOGI_VFPORT: 4578c2ecf20Sopenharmony_ci rn->role = CSIO_RNFR_FABRIC; 4588c2ecf20Sopenharmony_ci if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) { 4598c2ecf20Sopenharmony_ci csio_ln_err(ln, "ssni:x%x invalid fabric portid\n", 4608c2ecf20Sopenharmony_ci csio_rn_flowid(rn)); 4618c2ecf20Sopenharmony_ci return -EINVAL; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci /* NPIV support */ 4648c2ecf20Sopenharmony_ci if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos)) 4658c2ecf20Sopenharmony_ci ln->flags |= CSIO_LNF_NPIVSUPP; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci case NS_VNPORT: 4708c2ecf20Sopenharmony_ci rn->role = CSIO_RNFR_NS; 4718c2ecf20Sopenharmony_ci if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) { 4728c2ecf20Sopenharmony_ci csio_ln_err(ln, "ssni:x%x invalid fabric portid\n", 4738c2ecf20Sopenharmony_ci csio_rn_flowid(rn)); 4748c2ecf20Sopenharmony_ci return -EINVAL; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci case REG_FC4_VNPORT: 4798c2ecf20Sopenharmony_ci case REG_VNPORT: 4808c2ecf20Sopenharmony_ci rn->role = CSIO_RNFR_NPORT; 4818c2ecf20Sopenharmony_ci if (rdevp->event_cause == PRLI_ACC_RCVD || 4828c2ecf20Sopenharmony_ci rdevp->event_cause == PRLI_RCVD) { 4838c2ecf20Sopenharmony_ci if (FW_RDEV_WR_TASK_RETRY_ID_GET( 4848c2ecf20Sopenharmony_ci rdevp->enh_disc_to_tgt)) 4858c2ecf20Sopenharmony_ci rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt)) 4888c2ecf20Sopenharmony_ci rn->fcp_flags |= FCP_SPPF_RETRY; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt)) 4918c2ecf20Sopenharmony_ci rn->fcp_flags |= FCP_SPPF_CONF_COMPL; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt)) 4948c2ecf20Sopenharmony_ci rn->role |= CSIO_RNFR_TARGET; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt)) 4978c2ecf20Sopenharmony_ci rn->role |= CSIO_RNFR_INITIATOR; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci case FDMI_VNPORT: 5038c2ecf20Sopenharmony_ci case FAB_CTLR_VNPORT: 5048c2ecf20Sopenharmony_ci rn->role = 0; 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci default: 5088c2ecf20Sopenharmony_ci csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n", 5098c2ecf20Sopenharmony_ci csio_rn_flowid(rn), rport_type); 5108c2ecf20Sopenharmony_ci return -EINVAL; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* validate wwpn/wwnn for Name server/remote port */ 5148c2ecf20Sopenharmony_ci if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) { 5158c2ecf20Sopenharmony_ci memset(null, 0, 8); 5168c2ecf20Sopenharmony_ci if (!memcmp(rdevp->wwnn, null, 8)) { 5178c2ecf20Sopenharmony_ci csio_ln_err(ln, 5188c2ecf20Sopenharmony_ci "ssni:x%x invalid wwnn received from" 5198c2ecf20Sopenharmony_ci " rport did:x%x\n", 5208c2ecf20Sopenharmony_ci csio_rn_flowid(rn), 5218c2ecf20Sopenharmony_ci (ntohl(*did) & CSIO_DID_MASK)); 5228c2ecf20Sopenharmony_ci return -EINVAL; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (!memcmp(rdevp->wwpn, null, 8)) { 5268c2ecf20Sopenharmony_ci csio_ln_err(ln, 5278c2ecf20Sopenharmony_ci "ssni:x%x invalid wwpn received from" 5288c2ecf20Sopenharmony_ci " rport did:x%x\n", 5298c2ecf20Sopenharmony_ci csio_rn_flowid(rn), 5308c2ecf20Sopenharmony_ci (ntohl(*did) & CSIO_DID_MASK)); 5318c2ecf20Sopenharmony_ci return -EINVAL; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* Copy wwnn, wwpn and nport id */ 5378c2ecf20Sopenharmony_ci rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK; 5388c2ecf20Sopenharmony_ci memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8); 5398c2ecf20Sopenharmony_ci memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8); 5408c2ecf20Sopenharmony_ci rn->rn_sparm.csp.sp_bb_data = rdevp->rcv_fr_sz; 5418c2ecf20Sopenharmony_ci fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos); 5428c2ecf20Sopenharmony_ci rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic void 5488c2ecf20Sopenharmony_ci__csio_reg_rnode(struct csio_rnode *rn) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 5518c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 5548c2ecf20Sopenharmony_ci csio_reg_rnode(rn); 5558c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (rn->role & CSIO_RNFR_TARGET) 5588c2ecf20Sopenharmony_ci ln->n_scsi_tgts++; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (rn->nport_id == FC_FID_MGMT_SERV) 5618c2ecf20Sopenharmony_ci csio_ln_fdmi_start(ln, (void *) rn); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic void 5658c2ecf20Sopenharmony_ci__csio_unreg_rnode(struct csio_rnode *rn) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 5688c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 5698c2ecf20Sopenharmony_ci LIST_HEAD(tmp_q); 5708c2ecf20Sopenharmony_ci int cmpl = 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (!list_empty(&rn->host_cmpl_q)) { 5738c2ecf20Sopenharmony_ci csio_dbg(hw, "Returning completion queue I/Os\n"); 5748c2ecf20Sopenharmony_ci list_splice_tail_init(&rn->host_cmpl_q, &tmp_q); 5758c2ecf20Sopenharmony_ci cmpl = 1; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (rn->role & CSIO_RNFR_TARGET) { 5798c2ecf20Sopenharmony_ci ln->n_scsi_tgts--; 5808c2ecf20Sopenharmony_ci ln->last_scan_ntgts--; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 5848c2ecf20Sopenharmony_ci csio_unreg_rnode(rn); 5858c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* Cleanup I/Os that were waiting for rnode to unregister */ 5888c2ecf20Sopenharmony_ci if (cmpl) 5898c2ecf20Sopenharmony_ci csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/*****************************************************************************/ 5948c2ecf20Sopenharmony_ci/* START: Rnode SM */ 5958c2ecf20Sopenharmony_ci/*****************************************************************************/ 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci/* 5988c2ecf20Sopenharmony_ci * csio_rns_uninit - 5998c2ecf20Sopenharmony_ci * @rn - rnode 6008c2ecf20Sopenharmony_ci * @evt - SM event. 6018c2ecf20Sopenharmony_ci * 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_cistatic void 6048c2ecf20Sopenharmony_cicsio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 6078c2ecf20Sopenharmony_ci int ret = 0; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_sm[evt]); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci switch (evt) { 6128c2ecf20Sopenharmony_ci case CSIO_RNFE_LOGGED_IN: 6138c2ecf20Sopenharmony_ci case CSIO_RNFE_PLOGI_RECV: 6148c2ecf20Sopenharmony_ci ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 6158c2ecf20Sopenharmony_ci if (!ret) { 6168c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_ready); 6178c2ecf20Sopenharmony_ci __csio_reg_rnode(rn); 6188c2ecf20Sopenharmony_ci } else { 6198c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_err_inval); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci case CSIO_RNFE_LOGO_RECV: 6238c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 6248c2ecf20Sopenharmony_ci "ssni:x%x Ignoring event %d recv " 6258c2ecf20Sopenharmony_ci "in rn state[uninit]\n", csio_rn_flowid(rn), evt); 6268c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_drop); 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci default: 6298c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 6308c2ecf20Sopenharmony_ci "ssni:x%x unexp event %d recv " 6318c2ecf20Sopenharmony_ci "in rn state[uninit]\n", csio_rn_flowid(rn), evt); 6328c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_unexp); 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/* 6388c2ecf20Sopenharmony_ci * csio_rns_ready - 6398c2ecf20Sopenharmony_ci * @rn - rnode 6408c2ecf20Sopenharmony_ci * @evt - SM event. 6418c2ecf20Sopenharmony_ci * 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_cistatic void 6448c2ecf20Sopenharmony_cicsio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 6478c2ecf20Sopenharmony_ci int ret = 0; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_sm[evt]); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci switch (evt) { 6528c2ecf20Sopenharmony_ci case CSIO_RNFE_LOGGED_IN: 6538c2ecf20Sopenharmony_ci case CSIO_RNFE_PLOGI_RECV: 6548c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 6558c2ecf20Sopenharmony_ci "ssni:x%x Ignoring event %d recv from did:x%x " 6568c2ecf20Sopenharmony_ci "in rn state[ready]\n", csio_rn_flowid(rn), evt, 6578c2ecf20Sopenharmony_ci rn->nport_id); 6588c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_drop); 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci case CSIO_RNFE_PRLI_DONE: 6628c2ecf20Sopenharmony_ci case CSIO_RNFE_PRLI_RECV: 6638c2ecf20Sopenharmony_ci ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 6648c2ecf20Sopenharmony_ci if (!ret) 6658c2ecf20Sopenharmony_ci __csio_reg_rnode(rn); 6668c2ecf20Sopenharmony_ci else 6678c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_err_inval); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci case CSIO_RNFE_DOWN: 6718c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_offline); 6728c2ecf20Sopenharmony_ci __csio_unreg_rnode(rn); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* FW expected to internally aborted outstanding SCSI WRs 6758c2ecf20Sopenharmony_ci * and return all SCSI WRs to host with status "ABORTED". 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_ci break; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci case CSIO_RNFE_LOGO_RECV: 6808c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_offline); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci __csio_unreg_rnode(rn); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* FW expected to internally aborted outstanding SCSI WRs 6858c2ecf20Sopenharmony_ci * and return all SCSI WRs to host with status "ABORTED". 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci case CSIO_RNFE_CLOSE: 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * Each rnode receives CLOSE event when driver is removed or 6928c2ecf20Sopenharmony_ci * device is reset 6938c2ecf20Sopenharmony_ci * Note: All outstanding IOs on remote port need to returned 6948c2ecf20Sopenharmony_ci * to uppper layer with appropriate error before sending 6958c2ecf20Sopenharmony_ci * CLOSE event 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_uninit); 6988c2ecf20Sopenharmony_ci __csio_unreg_rnode(rn); 6998c2ecf20Sopenharmony_ci break; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci case CSIO_RNFE_NAME_MISSING: 7028c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_disappeared); 7038c2ecf20Sopenharmony_ci __csio_unreg_rnode(rn); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* 7068c2ecf20Sopenharmony_ci * FW expected to internally aborted outstanding SCSI WRs 7078c2ecf20Sopenharmony_ci * and return all SCSI WRs to host with status "ABORTED". 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci default: 7138c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 7148c2ecf20Sopenharmony_ci "ssni:x%x unexp event %d recv from did:x%x " 7158c2ecf20Sopenharmony_ci "in rn state[uninit]\n", csio_rn_flowid(rn), evt, 7168c2ecf20Sopenharmony_ci rn->nport_id); 7178c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_unexp); 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci/* 7238c2ecf20Sopenharmony_ci * csio_rns_offline - 7248c2ecf20Sopenharmony_ci * @rn - rnode 7258c2ecf20Sopenharmony_ci * @evt - SM event. 7268c2ecf20Sopenharmony_ci * 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_cistatic void 7298c2ecf20Sopenharmony_cicsio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 7328c2ecf20Sopenharmony_ci int ret = 0; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_sm[evt]); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci switch (evt) { 7378c2ecf20Sopenharmony_ci case CSIO_RNFE_LOGGED_IN: 7388c2ecf20Sopenharmony_ci case CSIO_RNFE_PLOGI_RECV: 7398c2ecf20Sopenharmony_ci ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 7408c2ecf20Sopenharmony_ci if (!ret) { 7418c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_ready); 7428c2ecf20Sopenharmony_ci __csio_reg_rnode(rn); 7438c2ecf20Sopenharmony_ci } else { 7448c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_err_inval); 7458c2ecf20Sopenharmony_ci csio_post_event(&rn->sm, CSIO_RNFE_CLOSE); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci case CSIO_RNFE_DOWN: 7508c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 7518c2ecf20Sopenharmony_ci "ssni:x%x Ignoring event %d recv from did:x%x " 7528c2ecf20Sopenharmony_ci "in rn state[offline]\n", csio_rn_flowid(rn), evt, 7538c2ecf20Sopenharmony_ci rn->nport_id); 7548c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_drop); 7558c2ecf20Sopenharmony_ci break; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci case CSIO_RNFE_CLOSE: 7588c2ecf20Sopenharmony_ci /* Each rnode receives CLOSE event when driver is removed or 7598c2ecf20Sopenharmony_ci * device is reset 7608c2ecf20Sopenharmony_ci * Note: All outstanding IOs on remote port need to returned 7618c2ecf20Sopenharmony_ci * to uppper layer with appropriate error before sending 7628c2ecf20Sopenharmony_ci * CLOSE event 7638c2ecf20Sopenharmony_ci */ 7648c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_uninit); 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci case CSIO_RNFE_NAME_MISSING: 7688c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_disappeared); 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci default: 7728c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 7738c2ecf20Sopenharmony_ci "ssni:x%x unexp event %d recv from did:x%x " 7748c2ecf20Sopenharmony_ci "in rn state[offline]\n", csio_rn_flowid(rn), evt, 7758c2ecf20Sopenharmony_ci rn->nport_id); 7768c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_unexp); 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci/* 7828c2ecf20Sopenharmony_ci * csio_rns_disappeared - 7838c2ecf20Sopenharmony_ci * @rn - rnode 7848c2ecf20Sopenharmony_ci * @evt - SM event. 7858c2ecf20Sopenharmony_ci * 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_cistatic void 7888c2ecf20Sopenharmony_cicsio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 7918c2ecf20Sopenharmony_ci int ret = 0; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_sm[evt]); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci switch (evt) { 7968c2ecf20Sopenharmony_ci case CSIO_RNFE_LOGGED_IN: 7978c2ecf20Sopenharmony_ci case CSIO_RNFE_PLOGI_RECV: 7988c2ecf20Sopenharmony_ci ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 7998c2ecf20Sopenharmony_ci if (!ret) { 8008c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_ready); 8018c2ecf20Sopenharmony_ci __csio_reg_rnode(rn); 8028c2ecf20Sopenharmony_ci } else { 8038c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_err_inval); 8048c2ecf20Sopenharmony_ci csio_post_event(&rn->sm, CSIO_RNFE_CLOSE); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci case CSIO_RNFE_CLOSE: 8098c2ecf20Sopenharmony_ci /* Each rnode receives CLOSE event when driver is removed or 8108c2ecf20Sopenharmony_ci * device is reset. 8118c2ecf20Sopenharmony_ci * Note: All outstanding IOs on remote port need to returned 8128c2ecf20Sopenharmony_ci * to uppper layer with appropriate error before sending 8138c2ecf20Sopenharmony_ci * CLOSE event 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_ci csio_set_state(&rn->sm, csio_rns_uninit); 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci case CSIO_RNFE_DOWN: 8198c2ecf20Sopenharmony_ci case CSIO_RNFE_NAME_MISSING: 8208c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 8218c2ecf20Sopenharmony_ci "ssni:x%x Ignoring event %d recv from did x%x" 8228c2ecf20Sopenharmony_ci "in rn state[disappeared]\n", csio_rn_flowid(rn), 8238c2ecf20Sopenharmony_ci evt, rn->nport_id); 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci default: 8278c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 8288c2ecf20Sopenharmony_ci "ssni:x%x unexp event %d recv from did x%x" 8298c2ecf20Sopenharmony_ci "in rn state[disappeared]\n", csio_rn_flowid(rn), 8308c2ecf20Sopenharmony_ci evt, rn->nport_id); 8318c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_unexp); 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/*****************************************************************************/ 8378c2ecf20Sopenharmony_ci/* END: Rnode SM */ 8388c2ecf20Sopenharmony_ci/*****************************************************************************/ 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/* 8418c2ecf20Sopenharmony_ci * csio_rnode_devloss_handler - Device loss event handler 8428c2ecf20Sopenharmony_ci * @rn: rnode 8438c2ecf20Sopenharmony_ci * 8448c2ecf20Sopenharmony_ci * Post event to close rnode SM and free rnode. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_civoid 8478c2ecf20Sopenharmony_cicsio_rnode_devloss_handler(struct csio_rnode *rn) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* ignore if same rnode came back as online */ 8528c2ecf20Sopenharmony_ci if (csio_is_rnode_ready(rn)) 8538c2ecf20Sopenharmony_ci return; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci csio_post_event(&rn->sm, CSIO_RNFE_CLOSE); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Free rn if in uninit state */ 8588c2ecf20Sopenharmony_ci if (csio_is_rnode_uninit(rn)) 8598c2ecf20Sopenharmony_ci csio_put_rnode(ln, rn); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/** 8638c2ecf20Sopenharmony_ci * csio_rnode_fwevt_handler - Event handler for firmware rnode events. 8648c2ecf20Sopenharmony_ci * @rn: rnode 8658c2ecf20Sopenharmony_ci * @fwevt: firmware event to handle 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_civoid 8688c2ecf20Sopenharmony_cicsio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 8718c2ecf20Sopenharmony_ci enum csio_rn_ev evt; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci evt = CSIO_FWE_TO_RNFE(fwevt); 8748c2ecf20Sopenharmony_ci if (!evt) { 8758c2ecf20Sopenharmony_ci csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n", 8768c2ecf20Sopenharmony_ci csio_rn_flowid(rn), fwevt); 8778c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_unexp); 8788c2ecf20Sopenharmony_ci return; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci CSIO_INC_STATS(rn, n_evt_fw[fwevt]); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Track previous & current events for debugging */ 8838c2ecf20Sopenharmony_ci rn->prev_evt = rn->cur_evt; 8848c2ecf20Sopenharmony_ci rn->cur_evt = fwevt; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* Post event to rnode SM */ 8878c2ecf20Sopenharmony_ci csio_post_event(&rn->sm, evt); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* Free rn if in uninit state */ 8908c2ecf20Sopenharmony_ci if (csio_is_rnode_uninit(rn)) 8918c2ecf20Sopenharmony_ci csio_put_rnode(ln, rn); 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci/* 8958c2ecf20Sopenharmony_ci * csio_rnode_init - Initialize rnode. 8968c2ecf20Sopenharmony_ci * @rn: RNode 8978c2ecf20Sopenharmony_ci * @ln: Associated lnode 8988c2ecf20Sopenharmony_ci * 8998c2ecf20Sopenharmony_ci * Caller is responsible for holding the lock. The lock is required 9008c2ecf20Sopenharmony_ci * to be held for inserting the rnode in ln->rnhead list. 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_cistatic int 9038c2ecf20Sopenharmony_cicsio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci csio_rnode_to_lnode(rn) = ln; 9068c2ecf20Sopenharmony_ci csio_init_state(&rn->sm, csio_rns_uninit); 9078c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rn->host_cmpl_q); 9088c2ecf20Sopenharmony_ci csio_rn_flowid(rn) = CSIO_INVALID_IDX; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* Add rnode to list of lnodes->rnhead */ 9118c2ecf20Sopenharmony_ci list_add_tail(&rn->sm.sm_list, &ln->rnhead); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic void 9178c2ecf20Sopenharmony_cicsio_rnode_exit(struct csio_rnode *rn) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci list_del_init(&rn->sm.sm_list); 9208c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q)); 9218c2ecf20Sopenharmony_ci} 922