119370Spst/* 219370Spst * This file is part of the Chelsio FCoE driver for Linux. 398944Sobrien * 4130803Smarcel * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. 598944Sobrien * 619370Spst * This software is available to you under a choice of one of two 798944Sobrien * licenses. You may choose to be licensed under the terms of the GNU 819370Spst * General Public License (GPL) Version 2, available from the file 998944Sobrien * COPYING in the main directory of this source tree, or the 1098944Sobrien * OpenIB.org BSD license below: 1198944Sobrien * 1298944Sobrien * Redistribution and use in source and binary forms, with or 1319370Spst * without modification, are permitted provided that the following 1498944Sobrien * conditions are met: 1598944Sobrien * 1698944Sobrien * - Redistributions of source code must retain the above 1798944Sobrien * copyright notice, this list of conditions and the following 1819370Spst * disclaimer. 1998944Sobrien * 2098944Sobrien * - Redistributions in binary form must reproduce the above 2198944Sobrien * copyright notice, this list of conditions and the following 2298944Sobrien * disclaimer in the documentation and/or other materials 2398944Sobrien * provided with the distribution. 2419370Spst * 2519370Spst * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2619370Spst * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2719370Spst * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2819370Spst * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2919370Spst * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3019370Spst * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3119370Spst * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3219370Spst * SOFTWARE. 3319370Spst */ 3419370Spst 3519370Spst#include <linux/string.h> 3619370Spst#include <scsi/scsi_device.h> 3719370Spst#include <scsi/scsi_transport_fc.h> 3819370Spst#include <scsi/fc/fc_els.h> 3998944Sobrien#include <scsi/fc/fc_fs.h> 4098944Sobrien 4198944Sobrien#include "csio_hw.h" 4298944Sobrien#include "csio_lnode.h" 43130803Smarcel#include "csio_rnode.h" 44130803Smarcel 45130803Smarcelstatic int csio_rnode_init(struct csio_rnode *, struct csio_lnode *); 4619370Spststatic void csio_rnode_exit(struct csio_rnode *); 47130803Smarcel 48130803Smarcel/* Static machine forward declarations */ 49130803Smarcelstatic void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev); 50130803Smarcelstatic void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev); 5119370Spststatic void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev); 5219370Spststatic void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev); 5319370Spst 5419370Spst/* RNF event mapping */ 5598944Sobrienstatic enum csio_rn_ev fwevt_to_rnevt[] = { 5698944Sobrien CSIO_RNFE_NONE, /* None */ 5798944Sobrien CSIO_RNFE_LOGGED_IN, /* PLOGI_ACC_RCVD */ 5898944Sobrien CSIO_RNFE_NONE, /* PLOGI_RJT_RCVD */ 5998944Sobrien CSIO_RNFE_PLOGI_RECV, /* PLOGI_RCVD */ 6019370Spst CSIO_RNFE_LOGO_RECV, /* PLOGO_RCVD */ 6119370Spst CSIO_RNFE_PRLI_DONE, /* PRLI_ACC_RCVD */ 6219370Spst CSIO_RNFE_NONE, /* PRLI_RJT_RCVD */ 6319370Spst CSIO_RNFE_PRLI_RECV, /* PRLI_RCVD */ 6419370Spst CSIO_RNFE_PRLO_RECV, /* PRLO_RCVD */ 6519370Spst CSIO_RNFE_NONE, /* NPORT_ID_CHGD */ 6619370Spst CSIO_RNFE_LOGO_RECV, /* FLOGO_RCVD */ 6719370Spst CSIO_RNFE_NONE, /* CLR_VIRT_LNK_RCVD */ 6819370Spst CSIO_RNFE_LOGGED_IN, /* FLOGI_ACC_RCVD */ 6919370Spst CSIO_RNFE_NONE, /* FLOGI_RJT_RCVD */ 7019370Spst CSIO_RNFE_LOGGED_IN, /* FDISC_ACC_RCVD */ 7119370Spst CSIO_RNFE_NONE, /* FDISC_RJT_RCVD */ 7219370Spst CSIO_RNFE_NONE, /* FLOGI_TMO_MAX_RETRY */ 7346283Sdfr CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_ACC */ 7446283Sdfr CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_RJT */ 7546283Sdfr CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_CNFLT */ 7646283Sdfr CSIO_RNFE_NONE, /* PRLI_TMO */ 7719370Spst CSIO_RNFE_NONE, /* ADISC_TMO */ 7819370Spst CSIO_RNFE_NAME_MISSING, /* RSCN_DEV_LOST */ 7919370Spst CSIO_RNFE_NONE, /* SCR_ACC_RCVD */ 8019370Spst CSIO_RNFE_NONE, /* ADISC_RJT_RCVD */ 8119370Spst CSIO_RNFE_NONE, /* LOGO_SNT */ 8219370Spst CSIO_RNFE_LOGO_RECV, /* PROTO_ERR_IMPL_LOGO */ 8319370Spst}; 8498944Sobrien 8519370Spst#define CSIO_FWE_TO_RNFE(_evt) ((_evt > PROTO_ERR_IMPL_LOGO) ? \ 8619370Spst CSIO_RNFE_NONE : \ 8719370Spst fwevt_to_rnevt[_evt]) 8819370Spstint 8919370Spstcsio_is_rnode_ready(struct csio_rnode *rn) 9019370Spst{ 9119370Spst return csio_match_state(rn, csio_rns_ready); 9219370Spst} 9319370Spst 9419370Spststatic int 9519370Spstcsio_is_rnode_uninit(struct csio_rnode *rn) 9619370Spst{ 9719370Spst return csio_match_state(rn, csio_rns_uninit); 9819370Spst} 9919370Spst 10019370Spststatic int 10119370Spstcsio_is_rnode_wka(uint8_t rport_type) 10219370Spst{ 10319370Spst if ((rport_type == FLOGI_VFPORT) || 10419370Spst (rport_type == FDISC_VFPORT) || 10519370Spst (rport_type == NS_VNPORT) || 10619370Spst (rport_type == FDMI_VNPORT)) 10719370Spst return 1; 10819370Spst 10998944Sobrien return 0; 11098944Sobrien} 11198944Sobrien 11298944Sobrien/* 11398944Sobrien * csio_rn_lookup - Finds the rnode with the given flowid 11498944Sobrien * @ln - lnode 11598944Sobrien * @flowid - flowid. 11698944Sobrien * 11798944Sobrien * Does the rnode lookup on the given lnode and flowid.If no matching entry 11898944Sobrien * found, NULL is returned. 11998944Sobrien */ 12098944Sobrienstatic struct csio_rnode * 12198944Sobriencsio_rn_lookup(struct csio_lnode *ln, uint32_t flowid) 12298944Sobrien{ 12319370Spst struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 12419370Spst struct list_head *tmp; 12519370Spst struct csio_rnode *rn; 12619370Spst 12719370Spst list_for_each(tmp, &rnhead->sm.sm_list) { 12819370Spst rn = (struct csio_rnode *) tmp; 12919370Spst if (rn->flowid == flowid) 13019370Spst return rn; 13146283Sdfr } 13219370Spst 13398944Sobrien return NULL; 13419370Spst} 13598944Sobrien 13619370Spst/* 13746283Sdfr * csio_rn_lookup_wwpn - Finds the rnode with the given wwpn 13846283Sdfr * @ln: lnode 13998944Sobrien * @wwpn: wwpn 14019370Spst * 14198944Sobrien * Does the rnode lookup on the given lnode and wwpn. If no matching entry 14219370Spst * found, NULL is returned. 14398944Sobrien */ 14419370Spststatic struct csio_rnode * 14598944Sobriencsio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn) 14619370Spst{ 14798944Sobrien struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 14819370Spst struct list_head *tmp; 14998944Sobrien struct csio_rnode *rn; 15019370Spst 15198944Sobrien list_for_each(tmp, &rnhead->sm.sm_list) { 15219370Spst rn = (struct csio_rnode *) tmp; 15398944Sobrien if (!memcmp(csio_rn_wwpn(rn), wwpn, 8)) 15419370Spst return rn; 15598944Sobrien } 15619370Spst 15798944Sobrien return NULL; 15819370Spst} 15998944Sobrien 16019370Spst/** 16198944Sobrien * csio_rnode_lookup_portid - Finds the rnode with the given portid 16219370Spst * @ln: lnode 16398944Sobrien * @portid: port id 16419370Spst * 16598944Sobrien * Lookup the rnode list for a given portid. If no matching entry 16619370Spst * found, NULL is returned. 16798944Sobrien */ 16819370Spststruct csio_rnode * 16998944Sobriencsio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid) 17019370Spst{ 17198944Sobrien struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 17219370Spst struct list_head *tmp; 17398944Sobrien struct csio_rnode *rn; 17498944Sobrien 17519370Spst list_for_each(tmp, &rnhead->sm.sm_list) { 17698944Sobrien rn = (struct csio_rnode *) tmp; 17719370Spst if (rn->nport_id == portid) 17898944Sobrien return rn; 17919370Spst } 18098944Sobrien 18198944Sobrien return NULL; 18246283Sdfr} 18319370Spst 18419370Spststatic int 18519370Spstcsio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid, 18619370Spst uint32_t *vnp_flowid) 18719370Spst{ 18819370Spst struct csio_rnode *rnhead; 18919370Spst struct list_head *tmp, *tmp1; 19019370Spst struct csio_rnode *rn; 19119370Spst struct csio_lnode *ln_tmp; 19219370Spst struct csio_hw *hw = csio_lnode_to_hw(ln); 19319370Spst 19498944Sobrien list_for_each(tmp1, &hw->sln_head) { 19519370Spst ln_tmp = (struct csio_lnode *) tmp1; 19619370Spst if (ln_tmp == ln) 197130803Smarcel continue; 19819370Spst 19919370Spst rnhead = (struct csio_rnode *)&ln_tmp->rnhead; 20019370Spst list_for_each(tmp, &rnhead->sm.sm_list) { 20119370Spst 20219370Spst rn = (struct csio_rnode *) tmp; 20319370Spst if (csio_is_rnode_ready(rn)) { 20419370Spst if (rn->flowid == rdev_flowid) { 20598944Sobrien *vnp_flowid = csio_ln_flowid(ln_tmp); 20698944Sobrien return 1; 20719370Spst } 20819370Spst } 20919370Spst } 21019370Spst } 21119370Spst 21219370Spst return 0; 21319370Spst} 21419370Spst 21519370Spststatic struct csio_rnode * 21619370Spstcsio_alloc_rnode(struct csio_lnode *ln) 21719370Spst{ 21819370Spst struct csio_hw *hw = csio_lnode_to_hw(ln); 21919370Spst 22098944Sobrien struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC); 22198944Sobrien if (!rn) 22219370Spst goto err; 22319370Spst 22419370Spst memset(rn, 0, sizeof(struct csio_rnode)); 22519370Spst if (csio_rnode_init(rn, ln)) 22619370Spst goto err_free; 22719370Spst 22819370Spst CSIO_INC_STATS(ln, n_rnode_alloc); 22919370Spst 23019370Spst return rn; 23119370Spst 23219370Spsterr_free: 23319370Spst mempool_free(rn, hw->rnode_mempool); 23419370Spsterr: 23519370Spst CSIO_INC_STATS(ln, n_rnode_nomem); 23619370Spst return NULL; 23719370Spst} 23819370Spst 23919370Spststatic void 24019370Spstcsio_free_rnode(struct csio_rnode *rn) 24119370Spst{ 24219370Spst struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn)); 24319370Spst 24419370Spst csio_rnode_exit(rn); 24519370Spst CSIO_INC_STATS(rn->lnp, n_rnode_free); 24619370Spst mempool_free(rn, hw->rnode_mempool); 24719370Spst} 24819370Spst 24919370Spst/* 25019370Spst * csio_get_rnode - Gets rnode with the given flowid 25119370Spst * @ln - lnode 25298944Sobrien * @flowid - flow id. 25319370Spst * 25419370Spst * Does the rnode lookup on the given lnode and flowid. If no matching 25519370Spst * rnode found, then new rnode with given npid is allocated and returned. 25619370Spst */ 25719370Spststatic struct csio_rnode * 25819370Spstcsio_get_rnode(struct csio_lnode *ln, uint32_t flowid) 25919370Spst{ 26019370Spst struct csio_rnode *rn; 26119370Spst 26219370Spst rn = csio_rn_lookup(ln, flowid); 26319370Spst if (!rn) { 26419370Spst rn = csio_alloc_rnode(ln); 26519370Spst if (!rn) 26619370Spst return NULL; 26719370Spst 26819370Spst rn->flowid = flowid; 26919370Spst } 27019370Spst 27119370Spst return rn; 27219370Spst} 27319370Spst 27419370Spst/* 27598944Sobrien * csio_put_rnode - Frees the given rnode 27619370Spst * @ln - lnode 27719370Spst * @flowid - flow id. 27819370Spst * 27919370Spst * Does the rnode lookup on the given lnode and flowid. If no matching 28019370Spst * rnode found, then new rnode with given npid is allocated and returned. 28119370Spst */ 282130803Smarcelvoid 28398944Sobriencsio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn) 28419370Spst{ 28519370Spst CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0); 28619370Spst csio_free_rnode(rn); 28719370Spst} 28819370Spst 28946283Sdfr/* 29046283Sdfr * csio_confirm_rnode - confirms rnode based on wwpn. 29146283Sdfr * @ln: lnode 29246283Sdfr * @rdev_flowid: remote device flowid 29319370Spst * @rdevp: remote device params 29419370Spst * This routines searches other rnode in list having same wwpn of new rnode. 29519370Spst * If there is a match, then matched rnode is returned and otherwise new rnode 29619370Spst * is returned. 29746283Sdfr * returns rnode. 29819370Spst */ 29998944Sobrienstruct csio_rnode * 30046283Sdfrcsio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid, 30119370Spst struct fcoe_rdev_entry *rdevp) 30219370Spst{ 30319370Spst uint8_t rport_type; 30419370Spst struct csio_rnode *rn, *match_rn; 30598944Sobrien uint32_t vnp_flowid = 0; 30698944Sobrien __be32 *port_id; 30798944Sobrien 30898944Sobrien port_id = (__be32 *)&rdevp->r_id[0]; 30946283Sdfr rport_type = 31019370Spst FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type); 31119370Spst 31219370Spst /* Drop rdev event for cntrl port */ 313130803Smarcel if (rport_type == FAB_CTLR_VNPORT) { 31446283Sdfr csio_ln_dbg(ln, 31519370Spst "Unhandled rport_type:%d recv in rdev evt " 31619370Spst "ssni:x%x\n", rport_type, rdev_flowid); 31719370Spst return NULL; 31819370Spst } 31919370Spst 32019370Spst /* Lookup on flowid */ 32119370Spst rn = csio_rn_lookup(ln, rdev_flowid); 322130803Smarcel if (!rn) { 323130803Smarcel 32498944Sobrien /* Drop events with duplicate flowid */ 32598944Sobrien if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) { 32698944Sobrien csio_ln_warn(ln, 32798944Sobrien "ssni:%x already active on vnpi:%x", 32898944Sobrien rdev_flowid, vnp_flowid); 32998944Sobrien return NULL; 33019370Spst } 33198944Sobrien 33298944Sobrien /* Lookup on wwpn for NPORTs */ 33398944Sobrien rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn); 33419370Spst if (!rn) 33598944Sobrien goto alloc_rnode; 33619370Spst 33719370Spst } else { 33819370Spst /* Lookup well-known ports with nport id */ 33919370Spst if (csio_is_rnode_wka(rport_type)) { 34019370Spst match_rn = csio_rnode_lookup_portid(ln, 34119370Spst ((ntohl(*port_id) >> 8) & CSIO_DID_MASK)); 34219370Spst if (match_rn == NULL) { 34319370Spst csio_rn_flowid(rn) = CSIO_INVALID_IDX; 34419370Spst goto alloc_rnode; 34519370Spst } 34619370Spst 347130803Smarcel /* 34898944Sobrien * Now compare the wwpn to confirm that 34919370Spst * same port relogged in. If so update the matched rn. 350130803Smarcel * Else, go ahead and alloc a new rnode. 35119370Spst */ 35219370Spst if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) { 353130803Smarcel if (rn == match_rn) 354130803Smarcel goto found_rnode; 355130803Smarcel csio_ln_dbg(ln, 35619370Spst "nport_id:x%x and wwpn:%llx" 357130803Smarcel " match for ssni:x%x\n", 35819370Spst rn->nport_id, 359130803Smarcel wwn_to_u64(rdevp->wwpn), 360130803Smarcel rdev_flowid); 36119370Spst if (csio_is_rnode_ready(rn)) { 362130803Smarcel csio_ln_warn(ln, 363130803Smarcel "rnode is already" 364130803Smarcel "active ssni:x%x\n", 365130803Smarcel rdev_flowid); 366130803Smarcel CSIO_ASSERT(0); 367130803Smarcel } 368130803Smarcel csio_rn_flowid(rn) = CSIO_INVALID_IDX; 369130803Smarcel rn = match_rn; 370130803Smarcel 371130803Smarcel /* Update rn */ 372130803Smarcel goto found_rnode; 373130803Smarcel } 374130803Smarcel csio_rn_flowid(rn) = CSIO_INVALID_IDX; 375130803Smarcel goto alloc_rnode; 376130803Smarcel } 377130803Smarcel 378130803Smarcel /* wwpn match */ 37919370Spst if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8)) 380130803Smarcel goto found_rnode; 38119370Spst 38219370Spst /* Search for rnode that have same wwpn */ 38398944Sobrien match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn); 384130803Smarcel if (match_rn != NULL) { 385130803Smarcel csio_ln_dbg(ln, 38698944Sobrien "ssni:x%x changed for rport name(wwpn):%llx " 387130803Smarcel "did:x%x\n", rdev_flowid, 38898944Sobrien wwn_to_u64(rdevp->wwpn), 38919370Spst match_rn->nport_id); 39019370Spst csio_rn_flowid(rn) = CSIO_INVALID_IDX; 39119370Spst rn = match_rn; 39219370Spst } else { 39319370Spst csio_ln_dbg(ln, 39419370Spst "rnode wwpn mismatch found ssni:x%x " 39519370Spst "name(wwpn):%llx\n", 39619370Spst rdev_flowid, 39719370Spst wwn_to_u64(csio_rn_wwpn(rn))); 39819370Spst if (csio_is_rnode_ready(rn)) { 39919370Spst csio_ln_warn(ln, 40019370Spst "rnode is already active " 40119370Spst "wwpn:%llx ssni:x%x\n", 40219370Spst wwn_to_u64(csio_rn_wwpn(rn)), 40319370Spst rdev_flowid); 40419370Spst CSIO_ASSERT(0); 40519370Spst } 40619370Spst csio_rn_flowid(rn) = CSIO_INVALID_IDX; 40719370Spst goto alloc_rnode; 40819370Spst } 40919370Spst } 41019370Spst 41119370Spstfound_rnode: 41219370Spst csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n", 41319370Spst rn, rdev_flowid, wwn_to_u64(rdevp->wwpn)); 41419370Spst 41519370Spst /* Update flowid */ 41619370Spst csio_rn_flowid(rn) = rdev_flowid; 41719370Spst 41819370Spst /* update rdev entry */ 41919370Spst rn->rdev_entry = rdevp; 42019370Spst CSIO_INC_STATS(ln, n_rnode_match); 42119370Spst return rn; 42219370Spst 42319370Spstalloc_rnode: 42419370Spst rn = csio_get_rnode(ln, rdev_flowid); 42519370Spst if (!rn) 42619370Spst return NULL; 42719370Spst 42819370Spst csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n", 42919370Spst rn, rdev_flowid, wwn_to_u64(rdevp->wwpn)); 43019370Spst 43119370Spst /* update rdev entry */ 43219370Spst rn->rdev_entry = rdevp; 43319370Spst return rn; 43419370Spst} 43519370Spst 43698944Sobrien/* 43798944Sobrien * csio_rn_verify_rparams - verify rparams. 43898944Sobrien * @ln: lnode 43998944Sobrien * @rn: rnode 44019370Spst * @rdevp: remote device params 44119370Spst * returns success if rparams are verified. 44219370Spst */ 44398944Sobrienstatic int 44498944Sobriencsio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn, 44519370Spst struct fcoe_rdev_entry *rdevp) 44619370Spst{ 44719370Spst uint8_t null[8]; 44898944Sobrien uint8_t rport_type; 44998944Sobrien uint8_t fc_class; 45098944Sobrien __be32 *did; 45198944Sobrien 45298944Sobrien did = (__be32 *) &rdevp->r_id[0]; 45398944Sobrien rport_type = 45419370Spst FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type); 45519370Spst switch (rport_type) { 45619370Spst case FLOGI_VFPORT: 45719370Spst rn->role = CSIO_RNFR_FABRIC; 45898944Sobrien if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) { 45919370Spst csio_ln_err(ln, "ssni:x%x invalid fabric portid\n", 46019370Spst csio_rn_flowid(rn)); 46119370Spst return -EINVAL; 46219370Spst } 46398944Sobrien /* NPIV support */ 46498944Sobrien if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos)) 46519370Spst ln->flags |= CSIO_LNF_NPIVSUPP; 46619370Spst 46719370Spst break; 46898944Sobrien 46998944Sobrien case NS_VNPORT: 47098944Sobrien rn->role = CSIO_RNFR_NS; 47198944Sobrien if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) { 47219370Spst csio_ln_err(ln, "ssni:x%x invalid fabric portid\n", 47319370Spst csio_rn_flowid(rn)); 47419370Spst return -EINVAL; 47519370Spst } 47619370Spst break; 47719370Spst 47819370Spst case REG_FC4_VNPORT: 47919370Spst case REG_VNPORT: 48019370Spst rn->role = CSIO_RNFR_NPORT; 48119370Spst if (rdevp->event_cause == PRLI_ACC_RCVD || 48219370Spst rdevp->event_cause == PRLI_RCVD) { 48319370Spst if (FW_RDEV_WR_TASK_RETRY_ID_GET( 48419370Spst rdevp->enh_disc_to_tgt)) 48519370Spst rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW; 48619370Spst 48719370Spst if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt)) 48819370Spst rn->fcp_flags |= FCP_SPPF_RETRY; 48998944Sobrien 49098944Sobrien if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt)) 49198944Sobrien rn->fcp_flags |= FCP_SPPF_CONF_COMPL; 49298944Sobrien 49398944Sobrien if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt)) 49498944Sobrien rn->role |= CSIO_RNFR_TARGET; 49519370Spst 49619370Spst if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt)) 49719370Spst rn->role |= CSIO_RNFR_INITIATOR; 49819370Spst } 49919370Spst 50019370Spst break; 50119370Spst 50298944Sobrien case FDMI_VNPORT: 50346283Sdfr case FAB_CTLR_VNPORT: 50498944Sobrien rn->role = 0; 505130803Smarcel break; 50619370Spst 50719370Spst default: 50819370Spst csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n", 50919370Spst csio_rn_flowid(rn), rport_type); 51019370Spst return -EINVAL; 51119370Spst } 51219370Spst 51319370Spst /* validate wwpn/wwnn for Name server/remote port */ 51419370Spst if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) { 51519370Spst memset(null, 0, 8); 51619370Spst if (!memcmp(rdevp->wwnn, null, 8)) { 51719370Spst csio_ln_err(ln, 51898944Sobrien "ssni:x%x invalid wwnn received from" 51919370Spst " rport did:x%x\n", 52019370Spst csio_rn_flowid(rn), 52119370Spst (ntohl(*did) & CSIO_DID_MASK)); 52219370Spst return -EINVAL; 52319370Spst } 52498944Sobrien 52598944Sobrien if (!memcmp(rdevp->wwpn, null, 8)) { 52619370Spst csio_ln_err(ln, 52719370Spst "ssni:x%x invalid wwpn received from" 52819370Spst " rport did:x%x\n", 52919370Spst csio_rn_flowid(rn), 53019370Spst (ntohl(*did) & CSIO_DID_MASK)); 53119370Spst return -EINVAL; 53219370Spst } 53319370Spst 53419370Spst } 53519370Spst 53619370Spst /* Copy wwnn, wwpn and nport id */ 53798944Sobrien rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK; 53898944Sobrien memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8); 53919370Spst memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8); 54098944Sobrien rn->rn_sparm.csp.sp_bb_data = rdevp->rcv_fr_sz; 54198944Sobrien fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos); 54298944Sobrien rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID); 54398944Sobrien 54498944Sobrien return 0; 54598944Sobrien} 54698944Sobrien 54798944Sobrienstatic void 54898944Sobrien__csio_reg_rnode(struct csio_rnode *rn) 54998944Sobrien{ 55098944Sobrien struct csio_lnode *ln = csio_rnode_to_lnode(rn); 55198944Sobrien struct csio_hw *hw = csio_lnode_to_hw(ln); 55298944Sobrien 55398944Sobrien spin_unlock_irq(&hw->lock); 55498944Sobrien csio_reg_rnode(rn); 55598944Sobrien spin_lock_irq(&hw->lock); 55698944Sobrien 55798944Sobrien if (rn->role & CSIO_RNFR_TARGET) 55898944Sobrien ln->n_scsi_tgts++; 55998944Sobrien 56098944Sobrien if (rn->nport_id == FC_FID_MGMT_SERV) 56198944Sobrien csio_ln_fdmi_start(ln, (void *) rn); 56298944Sobrien} 56398944Sobrien 56498944Sobrienstatic void 56598944Sobrien__csio_unreg_rnode(struct csio_rnode *rn) 56698944Sobrien{ 56798944Sobrien struct csio_lnode *ln = csio_rnode_to_lnode(rn); 56898944Sobrien struct csio_hw *hw = csio_lnode_to_hw(ln); 56998944Sobrien LIST_HEAD(tmp_q); 57098944Sobrien int cmpl = 0; 57198944Sobrien 57298944Sobrien if (!list_empty(&rn->host_cmpl_q)) { 57398944Sobrien csio_dbg(hw, "Returning completion queue I/Os\n"); 57498944Sobrien list_splice_tail_init(&rn->host_cmpl_q, &tmp_q); 57598944Sobrien cmpl = 1; 57698944Sobrien } 57798944Sobrien 57898944Sobrien if (rn->role & CSIO_RNFR_TARGET) { 57998944Sobrien ln->n_scsi_tgts--; 58098944Sobrien ln->last_scan_ntgts--; 58198944Sobrien } 58298944Sobrien 58398944Sobrien spin_unlock_irq(&hw->lock); 58498944Sobrien csio_unreg_rnode(rn); 58598944Sobrien spin_lock_irq(&hw->lock); 58698944Sobrien 58798944Sobrien /* Cleanup I/Os that were waiting for rnode to unregister */ 58898944Sobrien if (cmpl) 58998944Sobrien csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q); 59098944Sobrien 59198944Sobrien} 59298944Sobrien 59398944Sobrien/*****************************************************************************/ 59498944Sobrien/* START: Rnode SM */ 59598944Sobrien/*****************************************************************************/ 59698944Sobrien 59719370Spst/* 59819370Spst * csio_rns_uninit - 59919370Spst * @rn - rnode 60019370Spst * @evt - SM event. 60146283Sdfr * 60298944Sobrien */ 60398944Sobrienstatic void 60498944Sobriencsio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt) 60598944Sobrien{ 60619370Spst struct csio_lnode *ln = csio_rnode_to_lnode(rn); 60798944Sobrien int ret = 0; 60898944Sobrien 60946283Sdfr CSIO_INC_STATS(rn, n_evt_sm[evt]); 61046283Sdfr 61146283Sdfr switch (evt) { 61246283Sdfr case CSIO_RNFE_LOGGED_IN: 61346283Sdfr case CSIO_RNFE_PLOGI_RECV: 61498944Sobrien ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 61546283Sdfr if (!ret) { 61646283Sdfr csio_set_state(&rn->sm, csio_rns_ready); 61746283Sdfr __csio_reg_rnode(rn); 61846283Sdfr } else { 61919370Spst CSIO_INC_STATS(rn, n_err_inval); 62019370Spst } 62119370Spst break; 62219370Spst case CSIO_RNFE_LOGO_RECV: 62319370Spst csio_ln_dbg(ln, 62419370Spst "ssni:x%x Ignoring event %d recv " 62519370Spst "in rn state[uninit]\n", csio_rn_flowid(rn), evt); 62619370Spst CSIO_INC_STATS(rn, n_evt_drop); 62719370Spst break; 62846283Sdfr default: 62946283Sdfr csio_ln_dbg(ln, 63019370Spst "ssni:x%x unexp event %d recv " 63119370Spst "in rn state[uninit]\n", csio_rn_flowid(rn), evt); 63219370Spst CSIO_INC_STATS(rn, n_evt_unexp); 63346283Sdfr break; 634130803Smarcel } 635130803Smarcel} 63619370Spst 637130803Smarcel/* 63819370Spst * csio_rns_ready - 63919370Spst * @rn - rnode 64019370Spst * @evt - SM event. 64119370Spst * 64219370Spst */ 64319370Spststatic void 64419370Spstcsio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt) 64519370Spst{ 64619370Spst struct csio_lnode *ln = csio_rnode_to_lnode(rn); 64719370Spst int ret = 0; 64819370Spst 649130803Smarcel CSIO_INC_STATS(rn, n_evt_sm[evt]); 650130803Smarcel 65119370Spst switch (evt) { 652130803Smarcel case CSIO_RNFE_LOGGED_IN: 65319370Spst case CSIO_RNFE_PLOGI_RECV: 65419370Spst csio_ln_dbg(ln, 65519370Spst "ssni:x%x Ignoring event %d recv from did:x%x " 65698944Sobrien "in rn state[ready]\n", csio_rn_flowid(rn), evt, 65719370Spst rn->nport_id); 65819370Spst CSIO_INC_STATS(rn, n_evt_drop); 65919370Spst break; 66019370Spst 66119370Spst case CSIO_RNFE_PRLI_DONE: 66219370Spst case CSIO_RNFE_PRLI_RECV: 66319370Spst ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 66419370Spst if (!ret) 66519370Spst __csio_reg_rnode(rn); 66619370Spst else 66798944Sobrien CSIO_INC_STATS(rn, n_err_inval); 66819370Spst 66998944Sobrien break; 67019370Spst case CSIO_RNFE_DOWN: 67198944Sobrien csio_set_state(&rn->sm, csio_rns_offline); 67298944Sobrien __csio_unreg_rnode(rn); 67319370Spst 67419370Spst /* FW expected to internally aborted outstanding SCSI WRs 67519370Spst * and return all SCSI WRs to host with status "ABORTED". 67619370Spst */ 67746283Sdfr break; 67846283Sdfr 67919370Spst case CSIO_RNFE_LOGO_RECV: 68098944Sobrien csio_set_state(&rn->sm, csio_rns_offline); 68198944Sobrien 68298944Sobrien __csio_unreg_rnode(rn); 68398944Sobrien 68419370Spst /* FW expected to internally aborted outstanding SCSI WRs 68598944Sobrien * and return all SCSI WRs to host with status "ABORTED". 68698944Sobrien */ 68798944Sobrien break; 68898944Sobrien 68919370Spst case CSIO_RNFE_CLOSE: 69098944Sobrien /* 69198944Sobrien * Each rnode receives CLOSE event when driver is removed or 69298944Sobrien * device is reset 69398944Sobrien * Note: All outstanding IOs on remote port need to returned 69419370Spst * to uppper layer with appropriate error before sending 69598944Sobrien * CLOSE event 69619370Spst */ 69719370Spst csio_set_state(&rn->sm, csio_rns_uninit); 69819370Spst __csio_unreg_rnode(rn); 69919370Spst break; 70019370Spst 70198944Sobrien case CSIO_RNFE_NAME_MISSING: 70219370Spst csio_set_state(&rn->sm, csio_rns_disappeared); 70398944Sobrien __csio_unreg_rnode(rn); 70498944Sobrien 70598944Sobrien /* 70698944Sobrien * FW expected to internally aborted outstanding SCSI WRs 70798944Sobrien * and return all SCSI WRs to host with status "ABORTED". 70898944Sobrien */ 70998944Sobrien 71098944Sobrien break; 71198944Sobrien 71298944Sobrien default: 71398944Sobrien csio_ln_dbg(ln, 71498944Sobrien "ssni:x%x unexp event %d recv from did:x%x " 71598944Sobrien "in rn state[uninit]\n", csio_rn_flowid(rn), evt, 71646283Sdfr rn->nport_id); 71719370Spst CSIO_INC_STATS(rn, n_evt_unexp); 71819370Spst break; 71919370Spst } 72019370Spst} 72119370Spst 72219370Spst/* 72319370Spst * csio_rns_offline - 72498944Sobrien * @rn - rnode 72519370Spst * @evt - SM event. 72619370Spst * 72719370Spst */ 72819370Spststatic void 72919370Spstcsio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt) 73019370Spst{ 73119370Spst struct csio_lnode *ln = csio_rnode_to_lnode(rn); 73219370Spst int ret = 0; 73319370Spst 73419370Spst CSIO_INC_STATS(rn, n_evt_sm[evt]); 73519370Spst 73698944Sobrien switch (evt) { 73719370Spst case CSIO_RNFE_LOGGED_IN: 73819370Spst case CSIO_RNFE_PLOGI_RECV: 73919370Spst ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 74019370Spst if (!ret) { 74119370Spst csio_set_state(&rn->sm, csio_rns_ready); 74219370Spst __csio_reg_rnode(rn); 74319370Spst } else { 74419370Spst CSIO_INC_STATS(rn, n_err_inval); 74519370Spst csio_post_event(&rn->sm, CSIO_RNFE_CLOSE); 74619370Spst } 74719370Spst break; 74819370Spst 74919370Spst case CSIO_RNFE_DOWN: 75019370Spst csio_ln_dbg(ln, 75119370Spst "ssni:x%x Ignoring event %d recv from did:x%x " 75219370Spst "in rn state[offline]\n", csio_rn_flowid(rn), evt, 75319370Spst rn->nport_id); 75419370Spst CSIO_INC_STATS(rn, n_evt_drop); 75519370Spst break; 75619370Spst 75746283Sdfr case CSIO_RNFE_CLOSE: 75846283Sdfr /* Each rnode receives CLOSE event when driver is removed or 75919370Spst * device is reset 76019370Spst * Note: All outstanding IOs on remote port need to returned 76119370Spst * to uppper layer with appropriate error before sending 76219370Spst * CLOSE event 76319370Spst */ 76419370Spst csio_set_state(&rn->sm, csio_rns_uninit); 76519370Spst break; 76619370Spst 76719370Spst case CSIO_RNFE_NAME_MISSING: 76898944Sobrien csio_set_state(&rn->sm, csio_rns_disappeared); 76919370Spst break; 770130803Smarcel 771130803Smarcel default: 772130803Smarcel csio_ln_dbg(ln, 77319370Spst "ssni:x%x unexp event %d recv from did:x%x " 774130803Smarcel "in rn state[offline]\n", csio_rn_flowid(rn), evt, 775130803Smarcel rn->nport_id); 77619370Spst CSIO_INC_STATS(rn, n_evt_unexp); 77719370Spst break; 77819370Spst } 77919370Spst} 78019370Spst 78146283Sdfr/* 78219370Spst * csio_rns_disappeared - 78319370Spst * @rn - rnode 78419370Spst * @evt - SM event. 78519370Spst * 78619370Spst */ 78719370Spststatic void 78846283Sdfrcsio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt) 78946283Sdfr{ 79046283Sdfr struct csio_lnode *ln = csio_rnode_to_lnode(rn); 79119370Spst int ret = 0; 79219370Spst 79319370Spst CSIO_INC_STATS(rn, n_evt_sm[evt]); 79419370Spst 79519370Spst switch (evt) { 79619370Spst case CSIO_RNFE_LOGGED_IN: 79719370Spst case CSIO_RNFE_PLOGI_RECV: 79819370Spst ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry); 79919370Spst if (!ret) { 80019370Spst csio_set_state(&rn->sm, csio_rns_ready); 80119370Spst __csio_reg_rnode(rn); 80219370Spst } else { 80319370Spst CSIO_INC_STATS(rn, n_err_inval); 80419370Spst csio_post_event(&rn->sm, CSIO_RNFE_CLOSE); 80519370Spst } 80619370Spst break; 80719370Spst 80819370Spst case CSIO_RNFE_CLOSE: 80919370Spst /* Each rnode receives CLOSE event when driver is removed or 81019370Spst * device is reset. 81119370Spst * Note: All outstanding IOs on remote port need to returned 81219370Spst * to uppper layer with appropriate error before sending 81319370Spst * CLOSE event 81419370Spst */ 81519370Spst csio_set_state(&rn->sm, csio_rns_uninit); 81619370Spst break; 81719370Spst 81819370Spst case CSIO_RNFE_DOWN: 81919370Spst case CSIO_RNFE_NAME_MISSING: 82019370Spst csio_ln_dbg(ln, 82119370Spst "ssni:x%x Ignoring event %d recv from did x%x" 82219370Spst "in rn state[disappeared]\n", csio_rn_flowid(rn), 82346283Sdfr evt, rn->nport_id); 82446283Sdfr break; 82546283Sdfr 82646283Sdfr default: 82746283Sdfr csio_ln_dbg(ln, 82898944Sobrien "ssni:x%x unexp event %d recv from did x%x" 82998944Sobrien "in rn state[disappeared]\n", csio_rn_flowid(rn), 83098944Sobrien evt, rn->nport_id); 83198944Sobrien CSIO_INC_STATS(rn, n_evt_unexp); 83298944Sobrien break; 83398944Sobrien } 83498944Sobrien} 83598944Sobrien 83646283Sdfr/*****************************************************************************/ 83746283Sdfr/* END: Rnode SM */ 83846283Sdfr/*****************************************************************************/ 83946283Sdfr 84046283Sdfr/* 84198944Sobrien * csio_rnode_devloss_handler - Device loss event handler 84219370Spst * @rn: rnode 84319370Spst * 84419370Spst * Post event to close rnode SM and free rnode. 84519370Spst */ 84619370Spstvoid 84719370Spstcsio_rnode_devloss_handler(struct csio_rnode *rn) 84819370Spst{ 84998944Sobrien struct csio_lnode *ln = csio_rnode_to_lnode(rn); 85019370Spst 85119370Spst /* ignore if same rnode came back as online */ 85219370Spst if (csio_is_rnode_ready(rn)) 85319370Spst return; 85419370Spst 85519370Spst csio_post_event(&rn->sm, CSIO_RNFE_CLOSE); 85619370Spst 85719370Spst /* Free rn if in uninit state */ 85819370Spst if (csio_is_rnode_uninit(rn)) 85919370Spst csio_put_rnode(ln, rn); 86019370Spst} 86119370Spst 86298944Sobrien/** 86398944Sobrien * csio_rnode_fwevt_handler - Event handler for firmware rnode events. 86498944Sobrien * @rn: rnode 86519370Spst * @fwevt: firmware event to handle 86619370Spst */ 86798944Sobrienvoid 86819370Spstcsio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt) 86919370Spst{ 870130803Smarcel struct csio_lnode *ln = csio_rnode_to_lnode(rn); 871130803Smarcel enum csio_rn_ev evt; 87298944Sobrien 87319370Spst evt = CSIO_FWE_TO_RNFE(fwevt); 87419370Spst if (!evt) { 87519370Spst csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n", 87619370Spst csio_rn_flowid(rn), fwevt); 87719370Spst CSIO_INC_STATS(rn, n_evt_unexp); 87819370Spst return; 87919370Spst } 88019370Spst CSIO_INC_STATS(rn, n_evt_fw[fwevt]); 88119370Spst 88219370Spst /* Track previous & current events for debugging */ 88319370Spst rn->prev_evt = rn->cur_evt; 88419370Spst rn->cur_evt = fwevt; 88519370Spst 88619370Spst /* Post event to rnode SM */ 88719370Spst csio_post_event(&rn->sm, evt); 88819370Spst 88919370Spst /* Free rn if in uninit state */ 89019370Spst if (csio_is_rnode_uninit(rn)) 89119370Spst csio_put_rnode(ln, rn); 89219370Spst} 89319370Spst 89419370Spst/* 89519370Spst * csio_rnode_init - Initialize rnode. 89619370Spst * @rn: RNode 89798944Sobrien * @ln: Associated lnode 89819370Spst * 89919370Spst * Caller is responsible for holding the lock. The lock is required 90019370Spst * to be held for inserting the rnode in ln->rnhead list. 90119370Spst */ 90219370Spststatic int 90319370Spstcsio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln) 90419370Spst{ 90598944Sobrien csio_rnode_to_lnode(rn) = ln; 90619370Spst csio_init_state(&rn->sm, csio_rns_uninit); 90719370Spst INIT_LIST_HEAD(&rn->host_cmpl_q); 90819370Spst csio_rn_flowid(rn) = CSIO_INVALID_IDX; 90919370Spst 91019370Spst /* Add rnode to list of lnodes->rnhead */ 91119370Spst list_add_tail(&rn->sm.sm_list, &ln->rnhead); 91219370Spst 91319370Spst return 0; 91419370Spst} 91519370Spst 91698944Sobrienstatic void 91798944Sobriencsio_rnode_exit(struct csio_rnode *rn) 91819370Spst{ 91919370Spst list_del_init(&rn->sm.sm_list); 92019370Spst CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q)); 92119370Spst} 92298944Sobrien