123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922 |
- /*
- * This file is part of the Chelsio FCoE driver for Linux.
- *
- * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- #include <linux/string.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_transport_fc.h>
- #include <scsi/fc/fc_els.h>
- #include <scsi/fc/fc_fs.h>
- #include "csio_hw.h"
- #include "csio_lnode.h"
- #include "csio_rnode.h"
- static int csio_rnode_init(struct csio_rnode *, struct csio_lnode *);
- static void csio_rnode_exit(struct csio_rnode *);
- /* Static machine forward declarations */
- static void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev);
- static void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev);
- static void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev);
- static void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev);
- /* RNF event mapping */
- static enum csio_rn_ev fwevt_to_rnevt[] = {
- CSIO_RNFE_NONE, /* None */
- CSIO_RNFE_LOGGED_IN, /* PLOGI_ACC_RCVD */
- CSIO_RNFE_NONE, /* PLOGI_RJT_RCVD */
- CSIO_RNFE_PLOGI_RECV, /* PLOGI_RCVD */
- CSIO_RNFE_LOGO_RECV, /* PLOGO_RCVD */
- CSIO_RNFE_PRLI_DONE, /* PRLI_ACC_RCVD */
- CSIO_RNFE_NONE, /* PRLI_RJT_RCVD */
- CSIO_RNFE_PRLI_RECV, /* PRLI_RCVD */
- CSIO_RNFE_PRLO_RECV, /* PRLO_RCVD */
- CSIO_RNFE_NONE, /* NPORT_ID_CHGD */
- CSIO_RNFE_LOGO_RECV, /* FLOGO_RCVD */
- CSIO_RNFE_NONE, /* CLR_VIRT_LNK_RCVD */
- CSIO_RNFE_LOGGED_IN, /* FLOGI_ACC_RCVD */
- CSIO_RNFE_NONE, /* FLOGI_RJT_RCVD */
- CSIO_RNFE_LOGGED_IN, /* FDISC_ACC_RCVD */
- CSIO_RNFE_NONE, /* FDISC_RJT_RCVD */
- CSIO_RNFE_NONE, /* FLOGI_TMO_MAX_RETRY */
- CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_ACC */
- CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_RJT */
- CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_CNFLT */
- CSIO_RNFE_NONE, /* PRLI_TMO */
- CSIO_RNFE_NONE, /* ADISC_TMO */
- CSIO_RNFE_NAME_MISSING, /* RSCN_DEV_LOST */
- CSIO_RNFE_NONE, /* SCR_ACC_RCVD */
- CSIO_RNFE_NONE, /* ADISC_RJT_RCVD */
- CSIO_RNFE_NONE, /* LOGO_SNT */
- CSIO_RNFE_LOGO_RECV, /* PROTO_ERR_IMPL_LOGO */
- };
- #define CSIO_FWE_TO_RNFE(_evt) ((_evt > PROTO_ERR_IMPL_LOGO) ? \
- CSIO_RNFE_NONE : \
- fwevt_to_rnevt[_evt])
- int
- csio_is_rnode_ready(struct csio_rnode *rn)
- {
- return csio_match_state(rn, csio_rns_ready);
- }
- static int
- csio_is_rnode_uninit(struct csio_rnode *rn)
- {
- return csio_match_state(rn, csio_rns_uninit);
- }
- static int
- csio_is_rnode_wka(uint8_t rport_type)
- {
- if ((rport_type == FLOGI_VFPORT) ||
- (rport_type == FDISC_VFPORT) ||
- (rport_type == NS_VNPORT) ||
- (rport_type == FDMI_VNPORT))
- return 1;
- return 0;
- }
- /*
- * csio_rn_lookup - Finds the rnode with the given flowid
- * @ln - lnode
- * @flowid - flowid.
- *
- * Does the rnode lookup on the given lnode and flowid.If no matching entry
- * found, NULL is returned.
- */
- static struct csio_rnode *
- csio_rn_lookup(struct csio_lnode *ln, uint32_t flowid)
- {
- struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
- struct list_head *tmp;
- struct csio_rnode *rn;
- list_for_each(tmp, &rnhead->sm.sm_list) {
- rn = (struct csio_rnode *) tmp;
- if (rn->flowid == flowid)
- return rn;
- }
- return NULL;
- }
- /*
- * csio_rn_lookup_wwpn - Finds the rnode with the given wwpn
- * @ln: lnode
- * @wwpn: wwpn
- *
- * Does the rnode lookup on the given lnode and wwpn. If no matching entry
- * found, NULL is returned.
- */
- static struct csio_rnode *
- csio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn)
- {
- struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
- struct list_head *tmp;
- struct csio_rnode *rn;
- list_for_each(tmp, &rnhead->sm.sm_list) {
- rn = (struct csio_rnode *) tmp;
- if (!memcmp(csio_rn_wwpn(rn), wwpn, 8))
- return rn;
- }
- return NULL;
- }
- /**
- * csio_rnode_lookup_portid - Finds the rnode with the given portid
- * @ln: lnode
- * @portid: port id
- *
- * Lookup the rnode list for a given portid. If no matching entry
- * found, NULL is returned.
- */
- struct csio_rnode *
- csio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid)
- {
- struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
- struct list_head *tmp;
- struct csio_rnode *rn;
- list_for_each(tmp, &rnhead->sm.sm_list) {
- rn = (struct csio_rnode *) tmp;
- if (rn->nport_id == portid)
- return rn;
- }
- return NULL;
- }
- static int
- csio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid,
- uint32_t *vnp_flowid)
- {
- struct csio_rnode *rnhead;
- struct list_head *tmp, *tmp1;
- struct csio_rnode *rn;
- struct csio_lnode *ln_tmp;
- struct csio_hw *hw = csio_lnode_to_hw(ln);
- list_for_each(tmp1, &hw->sln_head) {
- ln_tmp = (struct csio_lnode *) tmp1;
- if (ln_tmp == ln)
- continue;
- rnhead = (struct csio_rnode *)&ln_tmp->rnhead;
- list_for_each(tmp, &rnhead->sm.sm_list) {
- rn = (struct csio_rnode *) tmp;
- if (csio_is_rnode_ready(rn)) {
- if (rn->flowid == rdev_flowid) {
- *vnp_flowid = csio_ln_flowid(ln_tmp);
- return 1;
- }
- }
- }
- }
- return 0;
- }
- static struct csio_rnode *
- csio_alloc_rnode(struct csio_lnode *ln)
- {
- struct csio_hw *hw = csio_lnode_to_hw(ln);
- struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC);
- if (!rn)
- goto err;
- memset(rn, 0, sizeof(struct csio_rnode));
- if (csio_rnode_init(rn, ln))
- goto err_free;
- CSIO_INC_STATS(ln, n_rnode_alloc);
- return rn;
- err_free:
- mempool_free(rn, hw->rnode_mempool);
- err:
- CSIO_INC_STATS(ln, n_rnode_nomem);
- return NULL;
- }
- static void
- csio_free_rnode(struct csio_rnode *rn)
- {
- struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
- csio_rnode_exit(rn);
- CSIO_INC_STATS(rn->lnp, n_rnode_free);
- mempool_free(rn, hw->rnode_mempool);
- }
- /*
- * csio_get_rnode - Gets rnode with the given flowid
- * @ln - lnode
- * @flowid - flow id.
- *
- * Does the rnode lookup on the given lnode and flowid. If no matching
- * rnode found, then new rnode with given npid is allocated and returned.
- */
- static struct csio_rnode *
- csio_get_rnode(struct csio_lnode *ln, uint32_t flowid)
- {
- struct csio_rnode *rn;
- rn = csio_rn_lookup(ln, flowid);
- if (!rn) {
- rn = csio_alloc_rnode(ln);
- if (!rn)
- return NULL;
- rn->flowid = flowid;
- }
- return rn;
- }
- /*
- * csio_put_rnode - Frees the given rnode
- * @ln - lnode
- * @flowid - flow id.
- *
- * Does the rnode lookup on the given lnode and flowid. If no matching
- * rnode found, then new rnode with given npid is allocated and returned.
- */
- void
- csio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn)
- {
- CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0);
- csio_free_rnode(rn);
- }
- /*
- * csio_confirm_rnode - confirms rnode based on wwpn.
- * @ln: lnode
- * @rdev_flowid: remote device flowid
- * @rdevp: remote device params
- * This routines searches other rnode in list having same wwpn of new rnode.
- * If there is a match, then matched rnode is returned and otherwise new rnode
- * is returned.
- * returns rnode.
- */
- struct csio_rnode *
- csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
- struct fcoe_rdev_entry *rdevp)
- {
- uint8_t rport_type;
- struct csio_rnode *rn, *match_rn;
- uint32_t vnp_flowid = 0;
- __be32 *port_id;
- port_id = (__be32 *)&rdevp->r_id[0];
- rport_type =
- FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
- /* Drop rdev event for cntrl port */
- if (rport_type == FAB_CTLR_VNPORT) {
- csio_ln_dbg(ln,
- "Unhandled rport_type:%d recv in rdev evt "
- "ssni:x%x\n", rport_type, rdev_flowid);
- return NULL;
- }
- /* Lookup on flowid */
- rn = csio_rn_lookup(ln, rdev_flowid);
- if (!rn) {
- /* Drop events with duplicate flowid */
- if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) {
- csio_ln_warn(ln,
- "ssni:%x already active on vnpi:%x",
- rdev_flowid, vnp_flowid);
- return NULL;
- }
- /* Lookup on wwpn for NPORTs */
- rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
- if (!rn)
- goto alloc_rnode;
- } else {
- /* Lookup well-known ports with nport id */
- if (csio_is_rnode_wka(rport_type)) {
- match_rn = csio_rnode_lookup_portid(ln,
- ((ntohl(*port_id) >> 8) & CSIO_DID_MASK));
- if (match_rn == NULL) {
- csio_rn_flowid(rn) = CSIO_INVALID_IDX;
- goto alloc_rnode;
- }
- /*
- * Now compare the wwpn to confirm that
- * same port relogged in. If so update the matched rn.
- * Else, go ahead and alloc a new rnode.
- */
- if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) {
- if (rn == match_rn)
- goto found_rnode;
- csio_ln_dbg(ln,
- "nport_id:x%x and wwpn:%llx"
- " match for ssni:x%x\n",
- rn->nport_id,
- wwn_to_u64(rdevp->wwpn),
- rdev_flowid);
- if (csio_is_rnode_ready(rn)) {
- csio_ln_warn(ln,
- "rnode is already"
- "active ssni:x%x\n",
- rdev_flowid);
- CSIO_ASSERT(0);
- }
- csio_rn_flowid(rn) = CSIO_INVALID_IDX;
- rn = match_rn;
- /* Update rn */
- goto found_rnode;
- }
- csio_rn_flowid(rn) = CSIO_INVALID_IDX;
- goto alloc_rnode;
- }
- /* wwpn match */
- if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8))
- goto found_rnode;
- /* Search for rnode that have same wwpn */
- match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
- if (match_rn != NULL) {
- csio_ln_dbg(ln,
- "ssni:x%x changed for rport name(wwpn):%llx "
- "did:x%x\n", rdev_flowid,
- wwn_to_u64(rdevp->wwpn),
- match_rn->nport_id);
- csio_rn_flowid(rn) = CSIO_INVALID_IDX;
- rn = match_rn;
- } else {
- csio_ln_dbg(ln,
- "rnode wwpn mismatch found ssni:x%x "
- "name(wwpn):%llx\n",
- rdev_flowid,
- wwn_to_u64(csio_rn_wwpn(rn)));
- if (csio_is_rnode_ready(rn)) {
- csio_ln_warn(ln,
- "rnode is already active "
- "wwpn:%llx ssni:x%x\n",
- wwn_to_u64(csio_rn_wwpn(rn)),
- rdev_flowid);
- CSIO_ASSERT(0);
- }
- csio_rn_flowid(rn) = CSIO_INVALID_IDX;
- goto alloc_rnode;
- }
- }
- found_rnode:
- csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n",
- rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
- /* Update flowid */
- csio_rn_flowid(rn) = rdev_flowid;
- /* update rdev entry */
- rn->rdev_entry = rdevp;
- CSIO_INC_STATS(ln, n_rnode_match);
- return rn;
- alloc_rnode:
- rn = csio_get_rnode(ln, rdev_flowid);
- if (!rn)
- return NULL;
- csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n",
- rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
- /* update rdev entry */
- rn->rdev_entry = rdevp;
- return rn;
- }
- /*
- * csio_rn_verify_rparams - verify rparams.
- * @ln: lnode
- * @rn: rnode
- * @rdevp: remote device params
- * returns success if rparams are verified.
- */
- static int
- csio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn,
- struct fcoe_rdev_entry *rdevp)
- {
- uint8_t null[8];
- uint8_t rport_type;
- uint8_t fc_class;
- __be32 *did;
- did = (__be32 *) &rdevp->r_id[0];
- rport_type =
- FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
- switch (rport_type) {
- case FLOGI_VFPORT:
- rn->role = CSIO_RNFR_FABRIC;
- if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) {
- csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
- csio_rn_flowid(rn));
- return -EINVAL;
- }
- /* NPIV support */
- if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos))
- ln->flags |= CSIO_LNF_NPIVSUPP;
- break;
- case NS_VNPORT:
- rn->role = CSIO_RNFR_NS;
- if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) {
- csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
- csio_rn_flowid(rn));
- return -EINVAL;
- }
- break;
- case REG_FC4_VNPORT:
- case REG_VNPORT:
- rn->role = CSIO_RNFR_NPORT;
- if (rdevp->event_cause == PRLI_ACC_RCVD ||
- rdevp->event_cause == PRLI_RCVD) {
- if (FW_RDEV_WR_TASK_RETRY_ID_GET(
- rdevp->enh_disc_to_tgt))
- rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW;
- if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt))
- rn->fcp_flags |= FCP_SPPF_RETRY;
- if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt))
- rn->fcp_flags |= FCP_SPPF_CONF_COMPL;
- if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt))
- rn->role |= CSIO_RNFR_TARGET;
- if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt))
- rn->role |= CSIO_RNFR_INITIATOR;
- }
- break;
- case FDMI_VNPORT:
- case FAB_CTLR_VNPORT:
- rn->role = 0;
- break;
- default:
- csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n",
- csio_rn_flowid(rn), rport_type);
- return -EINVAL;
- }
- /* validate wwpn/wwnn for Name server/remote port */
- if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) {
- memset(null, 0, 8);
- if (!memcmp(rdevp->wwnn, null, 8)) {
- csio_ln_err(ln,
- "ssni:x%x invalid wwnn received from"
- " rport did:x%x\n",
- csio_rn_flowid(rn),
- (ntohl(*did) & CSIO_DID_MASK));
- return -EINVAL;
- }
- if (!memcmp(rdevp->wwpn, null, 8)) {
- csio_ln_err(ln,
- "ssni:x%x invalid wwpn received from"
- " rport did:x%x\n",
- csio_rn_flowid(rn),
- (ntohl(*did) & CSIO_DID_MASK));
- return -EINVAL;
- }
- }
- /* Copy wwnn, wwpn and nport id */
- rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK;
- memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8);
- memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8);
- rn->rn_sparm.csp.sp_bb_data = rdevp->rcv_fr_sz;
- fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos);
- rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID);
- return 0;
- }
- static void
- __csio_reg_rnode(struct csio_rnode *rn)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- struct csio_hw *hw = csio_lnode_to_hw(ln);
- spin_unlock_irq(&hw->lock);
- csio_reg_rnode(rn);
- spin_lock_irq(&hw->lock);
- if (rn->role & CSIO_RNFR_TARGET)
- ln->n_scsi_tgts++;
- if (rn->nport_id == FC_FID_MGMT_SERV)
- csio_ln_fdmi_start(ln, (void *) rn);
- }
- static void
- __csio_unreg_rnode(struct csio_rnode *rn)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- struct csio_hw *hw = csio_lnode_to_hw(ln);
- LIST_HEAD(tmp_q);
- int cmpl = 0;
- if (!list_empty(&rn->host_cmpl_q)) {
- csio_dbg(hw, "Returning completion queue I/Os\n");
- list_splice_tail_init(&rn->host_cmpl_q, &tmp_q);
- cmpl = 1;
- }
- if (rn->role & CSIO_RNFR_TARGET) {
- ln->n_scsi_tgts--;
- ln->last_scan_ntgts--;
- }
- spin_unlock_irq(&hw->lock);
- csio_unreg_rnode(rn);
- spin_lock_irq(&hw->lock);
- /* Cleanup I/Os that were waiting for rnode to unregister */
- if (cmpl)
- csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q);
- }
- /*****************************************************************************/
- /* START: Rnode SM */
- /*****************************************************************************/
- /*
- * csio_rns_uninit -
- * @rn - rnode
- * @evt - SM event.
- *
- */
- static void
- csio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- int ret = 0;
- CSIO_INC_STATS(rn, n_evt_sm[evt]);
- switch (evt) {
- case CSIO_RNFE_LOGGED_IN:
- case CSIO_RNFE_PLOGI_RECV:
- ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
- if (!ret) {
- csio_set_state(&rn->sm, csio_rns_ready);
- __csio_reg_rnode(rn);
- } else {
- CSIO_INC_STATS(rn, n_err_inval);
- }
- break;
- case CSIO_RNFE_LOGO_RECV:
- csio_ln_dbg(ln,
- "ssni:x%x Ignoring event %d recv "
- "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
- CSIO_INC_STATS(rn, n_evt_drop);
- break;
- default:
- csio_ln_dbg(ln,
- "ssni:x%x unexp event %d recv "
- "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
- CSIO_INC_STATS(rn, n_evt_unexp);
- break;
- }
- }
- /*
- * csio_rns_ready -
- * @rn - rnode
- * @evt - SM event.
- *
- */
- static void
- csio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- int ret = 0;
- CSIO_INC_STATS(rn, n_evt_sm[evt]);
- switch (evt) {
- case CSIO_RNFE_LOGGED_IN:
- case CSIO_RNFE_PLOGI_RECV:
- csio_ln_dbg(ln,
- "ssni:x%x Ignoring event %d recv from did:x%x "
- "in rn state[ready]\n", csio_rn_flowid(rn), evt,
- rn->nport_id);
- CSIO_INC_STATS(rn, n_evt_drop);
- break;
- case CSIO_RNFE_PRLI_DONE:
- case CSIO_RNFE_PRLI_RECV:
- ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
- if (!ret)
- __csio_reg_rnode(rn);
- else
- CSIO_INC_STATS(rn, n_err_inval);
- break;
- case CSIO_RNFE_DOWN:
- csio_set_state(&rn->sm, csio_rns_offline);
- __csio_unreg_rnode(rn);
- /* FW expected to internally aborted outstanding SCSI WRs
- * and return all SCSI WRs to host with status "ABORTED".
- */
- break;
- case CSIO_RNFE_LOGO_RECV:
- csio_set_state(&rn->sm, csio_rns_offline);
- __csio_unreg_rnode(rn);
- /* FW expected to internally aborted outstanding SCSI WRs
- * and return all SCSI WRs to host with status "ABORTED".
- */
- break;
- case CSIO_RNFE_CLOSE:
- /*
- * Each rnode receives CLOSE event when driver is removed or
- * device is reset
- * Note: All outstanding IOs on remote port need to returned
- * to uppper layer with appropriate error before sending
- * CLOSE event
- */
- csio_set_state(&rn->sm, csio_rns_uninit);
- __csio_unreg_rnode(rn);
- break;
- case CSIO_RNFE_NAME_MISSING:
- csio_set_state(&rn->sm, csio_rns_disappeared);
- __csio_unreg_rnode(rn);
- /*
- * FW expected to internally aborted outstanding SCSI WRs
- * and return all SCSI WRs to host with status "ABORTED".
- */
- break;
- default:
- csio_ln_dbg(ln,
- "ssni:x%x unexp event %d recv from did:x%x "
- "in rn state[uninit]\n", csio_rn_flowid(rn), evt,
- rn->nport_id);
- CSIO_INC_STATS(rn, n_evt_unexp);
- break;
- }
- }
- /*
- * csio_rns_offline -
- * @rn - rnode
- * @evt - SM event.
- *
- */
- static void
- csio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- int ret = 0;
- CSIO_INC_STATS(rn, n_evt_sm[evt]);
- switch (evt) {
- case CSIO_RNFE_LOGGED_IN:
- case CSIO_RNFE_PLOGI_RECV:
- ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
- if (!ret) {
- csio_set_state(&rn->sm, csio_rns_ready);
- __csio_reg_rnode(rn);
- } else {
- CSIO_INC_STATS(rn, n_err_inval);
- csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
- }
- break;
- case CSIO_RNFE_DOWN:
- csio_ln_dbg(ln,
- "ssni:x%x Ignoring event %d recv from did:x%x "
- "in rn state[offline]\n", csio_rn_flowid(rn), evt,
- rn->nport_id);
- CSIO_INC_STATS(rn, n_evt_drop);
- break;
- case CSIO_RNFE_CLOSE:
- /* Each rnode receives CLOSE event when driver is removed or
- * device is reset
- * Note: All outstanding IOs on remote port need to returned
- * to uppper layer with appropriate error before sending
- * CLOSE event
- */
- csio_set_state(&rn->sm, csio_rns_uninit);
- break;
- case CSIO_RNFE_NAME_MISSING:
- csio_set_state(&rn->sm, csio_rns_disappeared);
- break;
- default:
- csio_ln_dbg(ln,
- "ssni:x%x unexp event %d recv from did:x%x "
- "in rn state[offline]\n", csio_rn_flowid(rn), evt,
- rn->nport_id);
- CSIO_INC_STATS(rn, n_evt_unexp);
- break;
- }
- }
- /*
- * csio_rns_disappeared -
- * @rn - rnode
- * @evt - SM event.
- *
- */
- static void
- csio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- int ret = 0;
- CSIO_INC_STATS(rn, n_evt_sm[evt]);
- switch (evt) {
- case CSIO_RNFE_LOGGED_IN:
- case CSIO_RNFE_PLOGI_RECV:
- ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
- if (!ret) {
- csio_set_state(&rn->sm, csio_rns_ready);
- __csio_reg_rnode(rn);
- } else {
- CSIO_INC_STATS(rn, n_err_inval);
- csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
- }
- break;
- case CSIO_RNFE_CLOSE:
- /* Each rnode receives CLOSE event when driver is removed or
- * device is reset.
- * Note: All outstanding IOs on remote port need to returned
- * to uppper layer with appropriate error before sending
- * CLOSE event
- */
- csio_set_state(&rn->sm, csio_rns_uninit);
- break;
- case CSIO_RNFE_DOWN:
- case CSIO_RNFE_NAME_MISSING:
- csio_ln_dbg(ln,
- "ssni:x%x Ignoring event %d recv from did x%x"
- "in rn state[disappeared]\n", csio_rn_flowid(rn),
- evt, rn->nport_id);
- break;
- default:
- csio_ln_dbg(ln,
- "ssni:x%x unexp event %d recv from did x%x"
- "in rn state[disappeared]\n", csio_rn_flowid(rn),
- evt, rn->nport_id);
- CSIO_INC_STATS(rn, n_evt_unexp);
- break;
- }
- }
- /*****************************************************************************/
- /* END: Rnode SM */
- /*****************************************************************************/
- /*
- * csio_rnode_devloss_handler - Device loss event handler
- * @rn: rnode
- *
- * Post event to close rnode SM and free rnode.
- */
- void
- csio_rnode_devloss_handler(struct csio_rnode *rn)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- /* ignore if same rnode came back as online */
- if (csio_is_rnode_ready(rn))
- return;
- csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
- /* Free rn if in uninit state */
- if (csio_is_rnode_uninit(rn))
- csio_put_rnode(ln, rn);
- }
- /**
- * csio_rnode_fwevt_handler - Event handler for firmware rnode events.
- * @rn: rnode
- *
- */
- void
- csio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt)
- {
- struct csio_lnode *ln = csio_rnode_to_lnode(rn);
- enum csio_rn_ev evt;
- evt = CSIO_FWE_TO_RNFE(fwevt);
- if (!evt) {
- csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n",
- csio_rn_flowid(rn), fwevt);
- CSIO_INC_STATS(rn, n_evt_unexp);
- return;
- }
- CSIO_INC_STATS(rn, n_evt_fw[fwevt]);
- /* Track previous & current events for debugging */
- rn->prev_evt = rn->cur_evt;
- rn->cur_evt = fwevt;
- /* Post event to rnode SM */
- csio_post_event(&rn->sm, evt);
- /* Free rn if in uninit state */
- if (csio_is_rnode_uninit(rn))
- csio_put_rnode(ln, rn);
- }
- /*
- * csio_rnode_init - Initialize rnode.
- * @rn: RNode
- * @ln: Associated lnode
- *
- * Caller is responsible for holding the lock. The lock is required
- * to be held for inserting the rnode in ln->rnhead list.
- */
- static int
- csio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln)
- {
- csio_rnode_to_lnode(rn) = ln;
- csio_init_state(&rn->sm, csio_rns_uninit);
- INIT_LIST_HEAD(&rn->host_cmpl_q);
- csio_rn_flowid(rn) = CSIO_INVALID_IDX;
- /* Add rnode to list of lnodes->rnhead */
- list_add_tail(&rn->sm.sm_list, &ln->rnhead);
- return 0;
- }
- static void
- csio_rnode_exit(struct csio_rnode *rn)
- {
- list_del_init(&rn->sm.sm_list);
- CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q));
- }
|