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