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 two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * 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 OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * 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]) 88int 89csio_is_rnode_ready(struct csio_rnode *rn) 90{ 91 return csio_match_state(rn, csio_rns_ready); 92} 93 94static int 95csio_is_rnode_uninit(struct csio_rnode *rn) 96{ 97 return csio_match_state(rn, csio_rns_uninit); 98} 99 100static int 101csio_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 flowid 114 * @ln - lnode 115 * @flowid - flowid. 116 * 117 * Does the rnode lookup on the given lnode and flowid.If no matching entry 118 * 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 wwpn 138 * @ln: lnode 139 * @wwpn: wwpn 140 * 141 * Does the rnode lookup on the given lnode and wwpn. If no matching entry 142 * 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 portid 162 * @ln: lnode 163 * @portid: port id 164 * 165 * Lookup the rnode list for a given portid. If no matching entry 166 * 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 int 185csio_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 void 240csio_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 flowid 251 * @ln - lnode 252 * @flowid - flow id. 253 * 254 * Does the rnode lookup on the given lnode and flowid. If no matching 255 * 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 rnode 276 * @ln - lnode 277 * @flowid - flow id. 278 * 279 * Does the rnode lookup on the given lnode and flowid. If no matching 280 * rnode found, then new rnode with given npid is allocated and returned. 281 */ 282void 283csio_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: lnode 292 * @rdev_flowid: remote device flowid 293 * @rdevp: remote device params 294 * 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 rnode 296 * 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 that 349 * 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: lnode 439 * @rn: rnode 440 * @rdevp: remote device params 441 * returns success if rparams are verified. 442 */ 443static int 444csio_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 void 548__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 void 565__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 - rnode 600 * @evt - SM event. 601 * 602 */ 603static void 604csio_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 - rnode 640 * @evt - SM event. 641 * 642 */ 643static void 644csio_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 else 667 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 WRs 675 * 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 WRs 685 * 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 or 692 * device is reset 693 * Note: All outstanding IOs on remote port need to returned 694 * to uppper layer with appropriate error before sending 695 * CLOSE event 696 */ 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 WRs 707 * 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 - rnode 725 * @evt - SM event. 726 * 727 */ 728static void 729csio_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 or 759 * device is reset 760 * Note: All outstanding IOs on remote port need to returned 761 * to uppper layer with appropriate error before sending 762 * CLOSE event 763 */ 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 - rnode 784 * @evt - SM event. 785 * 786 */ 787static void 788csio_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 or 810 * device is reset. 811 * Note: All outstanding IOs on remote port need to returned 812 * to uppper layer with appropriate error before sending 813 * CLOSE event 814 */ 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 handler 842 * @rn: rnode 843 * 844 * Post event to close rnode SM and free rnode. 845 */ 846void 847csio_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: rnode 865 * 866 */ 867void 868csio_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: RNode 897 * @ln: Associated lnode 898 * 899 * Caller is responsible for holding the lock. The lock is required 900 * to be held for inserting the rnode in ln->rnhead list. 901 */ 902static int 903csio_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 void 917csio_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