1 /*- 2 * Copyright (c) 2017 Broadcom. All rights reserved. 3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 /** 35 * @file 36 * 37 * This file implements remote node state machines for: 38 * - Fabric logins. 39 * - Fabric controller events. 40 * - Name/directory services interaction. 41 * - Point-to-point logins. 42 */ 43 44 /*! 45 @defgroup fabric_sm Node State Machine: Fabric States 46 @defgroup ns_sm Node State Machine: Name/Directory Services States 47 @defgroup p2p_sm Node State Machine: Point-to-Point Node States 48 */ 49 50 #include "ocs.h" 51 #include "ocs_fabric.h" 52 #include "ocs_els.h" 53 #include "ocs_device.h" 54 55 static void ocs_fabric_initiate_shutdown(ocs_node_t *node); 56 static void * __ocs_fabric_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg); 57 static int32_t ocs_start_ns_node(ocs_sport_t *sport); 58 static int32_t ocs_start_fabctl_node(ocs_sport_t *sport); 59 static int32_t ocs_process_gidpt_payload(ocs_node_t *node, fcct_gidpt_acc_t *gidpt, uint32_t gidpt_len); 60 static void ocs_process_rscn(ocs_node_t *node, ocs_node_cb_t *cbdata); 61 static uint64_t ocs_get_wwpn(fc_plogi_payload_t *sp); 62 static void gidpt_delay_timer_cb(void *arg); 63 64 /** 65 * @ingroup fabric_sm 66 * @brief Fabric node state machine: Initial state. 67 * 68 * @par Description 69 * Send an FLOGI to a well-known fabric. 70 * 71 * @param ctx Remote node sm context. 72 * @param evt Event to process. 73 * @param arg Per event optional argument. 74 * 75 * @return Returns NULL. 76 */ 77 void * 78 __ocs_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 79 { 80 std_node_state_decl(); 81 82 node_sm_trace(); 83 84 switch(evt) { 85 case OCS_EVT_REENTER: /* not sure why we're getting these ... */ 86 ocs_log_debug(node->ocs, ">>> reenter !!\n"); 87 /* fall through */ 88 case OCS_EVT_ENTER: 89 /* sm: / send FLOGI */ 90 ocs_send_flogi(node, OCS_FC_FLOGI_TIMEOUT_SEC, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 91 ocs_node_transition(node, __ocs_fabric_flogi_wait_rsp, NULL); 92 break; 93 94 default: 95 __ocs_fabric_common(__func__, ctx, evt, arg); 96 break; 97 } 98 99 return NULL; 100 } 101 102 /** 103 * @ingroup fabric_sm 104 * @brief Set sport topology. 105 * 106 * @par Description 107 * Set sport topology. 108 * 109 * @param node Pointer to the node for which the topology is set. 110 * @param topology Topology to set. 111 * 112 * @return Returns NULL. 113 */ 114 void 115 ocs_fabric_set_topology(ocs_node_t *node, ocs_sport_topology_e topology) 116 { 117 node->sport->topology = topology; 118 } 119 120 /** 121 * @ingroup fabric_sm 122 * @brief Notify sport topology. 123 * @par Description 124 * notify sport topology. 125 * @param node Pointer to the node for which the topology is set. 126 * @return Returns NULL. 127 */ 128 void 129 ocs_fabric_notify_topology(ocs_node_t *node) 130 { 131 ocs_node_t *tmp_node; 132 ocs_node_t *next; 133 ocs_sport_topology_e topology = node->sport->topology; 134 135 /* now loop through the nodes in the sport and send topology notification */ 136 ocs_sport_lock(node->sport); 137 ocs_list_foreach_safe(&node->sport->node_list, tmp_node, next) { 138 if (tmp_node != node) { 139 ocs_node_post_event(tmp_node, OCS_EVT_SPORT_TOPOLOGY_NOTIFY, (void *)topology); 140 } 141 } 142 ocs_sport_unlock(node->sport); 143 } 144 145 /** 146 * @ingroup fabric_sm 147 * @brief Fabric node state machine: Wait for an FLOGI response. 148 * 149 * @par Description 150 * Wait for an FLOGI response event. 151 * 152 * @param ctx Remote node state machine context. 153 * @param evt Event to process. 154 * @param arg Per event optional argument. 155 * 156 * @return Returns NULL. 157 */ 158 159 void * 160 __ocs_fabric_flogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 161 { 162 ocs_node_cb_t *cbdata = arg; 163 std_node_state_decl(); 164 165 node_sm_trace(); 166 167 switch(evt) { 168 case OCS_EVT_SRRS_ELS_REQ_OK: { 169 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FLOGI, __ocs_fabric_common, __func__)) { 170 return NULL; 171 } 172 ocs_assert(node->els_req_cnt, NULL); 173 node->els_req_cnt--; 174 175 ocs_domain_save_sparms(node->sport->domain, cbdata->els->els_rsp.virt); 176 177 ocs_display_sparams(node->display_name, "flogi rcvd resp", 0, NULL, 178 ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 179 180 /* Check to see if the fabric is an F_PORT or and N_PORT */ 181 if (ocs_rnode_is_nport(cbdata->els->els_rsp.virt)) { 182 /* sm: if nport and p2p_winner / ocs_domain_attach */ 183 ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_P2P); 184 if (ocs_p2p_setup(node->sport)) { 185 node_printf(node, "p2p setup failed, shutting down node\n"); 186 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 187 ocs_fabric_initiate_shutdown(node); 188 } else { 189 if (node->sport->p2p_winner) { 190 ocs_node_transition(node, __ocs_p2p_wait_domain_attach, NULL); 191 if (!node->sport->domain->attached) { 192 node_printf(node, "p2p winner, domain not attached\n"); 193 ocs_domain_attach(node->sport->domain, node->sport->p2p_port_id); 194 } else { 195 /* already attached, just send ATTACH_OK */ 196 node_printf(node, "p2p winner, domain already attached\n"); 197 ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL); 198 } 199 } else { 200 /* peer is p2p winner; PLOGI will be received on the 201 * remote SID=1 node; this node has served its purpose 202 */ 203 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 204 ocs_fabric_initiate_shutdown(node); 205 } 206 } 207 } else { 208 /* sm: if not nport / ocs_domain_attach */ 209 /* ext_status has the fc_id, attach domain */ 210 ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_FABRIC); 211 ocs_fabric_notify_topology(node); 212 ocs_assert(!node->sport->domain->attached, NULL); 213 ocs_domain_attach(node->sport->domain, cbdata->ext_status); 214 ocs_node_transition(node, __ocs_fabric_wait_domain_attach, NULL); 215 } 216 217 break; 218 } 219 220 case OCS_EVT_ELS_REQ_ABORTED: 221 case OCS_EVT_SRRS_ELS_REQ_RJT: 222 case OCS_EVT_SRRS_ELS_REQ_FAIL: { 223 ocs_sport_t *sport = node->sport; 224 /* 225 * with these errors, we have no recovery, so shutdown the sport, leave the link 226 * up and the domain ready 227 */ 228 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FLOGI, __ocs_fabric_common, __func__)) { 229 return NULL; 230 } 231 node_printf(node, "FLOGI failed evt=%s, shutting down sport [%s]\n", ocs_sm_event_name(evt), 232 sport->display_name); 233 ocs_assert(node->els_req_cnt, NULL); 234 node->els_req_cnt--; 235 ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL); 236 break; 237 } 238 239 default: 240 __ocs_fabric_common(__func__, ctx, evt, arg); 241 break; 242 } 243 244 return NULL; 245 } 246 247 /** 248 * @ingroup fabric_sm 249 * @brief Fabric node state machine: Initial state for a virtual port. 250 * 251 * @par Description 252 * State entered when a virtual port is created. Send FDISC. 253 * 254 * @param ctx Remote node state machine context. 255 * @param evt Event to process. 256 * @param arg Per event optional argument. 257 * 258 * @return Returns NULL. 259 */ 260 void * 261 __ocs_vport_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 262 { 263 std_node_state_decl(); 264 265 node_sm_trace(); 266 267 switch(evt) { 268 case OCS_EVT_ENTER: 269 /* sm: send FDISC */ 270 ocs_send_fdisc(node, OCS_FC_FLOGI_TIMEOUT_SEC, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 271 ocs_node_transition(node, __ocs_fabric_fdisc_wait_rsp, NULL); 272 break; 273 274 default: 275 __ocs_fabric_common(__func__, ctx, evt, arg); 276 break; 277 } 278 279 return NULL; 280 } 281 282 /** 283 * @ingroup fabric_sm 284 * @brief Fabric node state machine: Wait for an FDISC response 285 * 286 * @par Description 287 * Used for a virtual port. Waits for an FDISC response. If OK, issue a HW port attach. 288 * 289 * @param ctx Remote node state machine context. 290 * @param evt Event to process. 291 * @param arg Per event optional argument. 292 * 293 * @return Returns NULL. 294 */ 295 void * 296 __ocs_fabric_fdisc_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 297 { 298 ocs_node_cb_t *cbdata = arg; 299 std_node_state_decl(); 300 301 node_sm_trace(); 302 303 switch(evt) { 304 case OCS_EVT_SRRS_ELS_REQ_OK: { 305 /* fc_id is in ext_status */ 306 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FDISC, __ocs_fabric_common, __func__)) { 307 return NULL; 308 } 309 310 ocs_display_sparams(node->display_name, "fdisc rcvd resp", 0, NULL, 311 ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 312 313 ocs_assert(node->els_req_cnt, NULL); 314 node->els_req_cnt--; 315 /* sm: ocs_sport_attach */ 316 ocs_sport_attach(node->sport, cbdata->ext_status); 317 ocs_node_transition(node, __ocs_fabric_wait_domain_attach, NULL); 318 break; 319 } 320 321 case OCS_EVT_SRRS_ELS_REQ_RJT: 322 case OCS_EVT_SRRS_ELS_REQ_FAIL: { 323 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FDISC, __ocs_fabric_common, __func__)) { 324 return NULL; 325 } 326 ocs_assert(node->els_req_cnt, NULL); 327 node->els_req_cnt--; 328 ocs_log_err(ocs, "FDISC failed, shutting down sport\n"); 329 /* sm: shutdown sport */ 330 ocs_sm_post_event(&node->sport->sm, OCS_EVT_SHUTDOWN, NULL); 331 break; 332 } 333 334 default: 335 __ocs_fabric_common(__func__, ctx, evt, arg); 336 break; 337 } 338 339 return NULL; 340 } 341 342 /** 343 * @ingroup fabric_sm 344 * @brief Fabric node state machine: Wait for a domain/sport attach event. 345 * 346 * @par Description 347 * Waits for a domain/sport attach event. 348 * 349 * @param ctx Remote node state machine context. 350 * @param evt Event to process. 351 * @param arg Per event optional argument. 352 * 353 * @return Returns NULL. 354 */ 355 void * 356 __ocs_fabric_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 357 { 358 std_node_state_decl(); 359 360 node_sm_trace(); 361 362 switch(evt) { 363 case OCS_EVT_ENTER: 364 ocs_node_hold_frames(node); 365 break; 366 367 case OCS_EVT_EXIT: 368 ocs_node_accept_frames(node); 369 break; 370 case OCS_EVT_DOMAIN_ATTACH_OK: 371 case OCS_EVT_SPORT_ATTACH_OK: { 372 int rc; 373 374 rc = ocs_start_ns_node(node->sport); 375 if (rc) 376 return NULL; 377 378 /* sm: if enable_ini / start fabctl node 379 * Instantiate the fabric controller (sends SCR) */ 380 if (node->sport->enable_rscn) { 381 rc = ocs_start_fabctl_node(node->sport); 382 if (rc) 383 return NULL; 384 } 385 ocs_node_transition(node, __ocs_fabric_idle, NULL); 386 break; 387 } 388 default: 389 __ocs_fabric_common(__func__, ctx, evt, arg); 390 return NULL; 391 } 392 393 return NULL; 394 } 395 396 /** 397 * @ingroup fabric_sm 398 * @brief Fabric node state machine: Fabric node is idle. 399 * 400 * @par Description 401 * Wait for fabric node events. 402 * 403 * @param ctx Remote node state machine context. 404 * @param evt Event to process. 405 * @param arg Per event optional argument. 406 * 407 * @return Returns NULL. 408 */ 409 void * 410 __ocs_fabric_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 411 { 412 std_node_state_decl(); 413 414 node_sm_trace(); 415 416 switch(evt) { 417 case OCS_EVT_DOMAIN_ATTACH_OK: 418 break; 419 default: 420 __ocs_fabric_common(__func__, ctx, evt, arg); 421 return NULL; 422 } 423 424 return NULL; 425 } 426 427 /** 428 * @ingroup ns_sm 429 * @brief Name services node state machine: Initialize. 430 * 431 * @par Description 432 * A PLOGI is sent to the well-known name/directory services node. 433 * 434 * @param ctx Remote node state machine context. 435 * @param evt Event to process. 436 * @param arg Per event optional argument. 437 * 438 * @return Returns NULL. 439 */ 440 void * 441 __ocs_ns_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 442 { 443 std_node_state_decl(); 444 445 node_sm_trace(); 446 447 switch(evt) { 448 case OCS_EVT_ENTER: 449 /* sm: send PLOGI */ 450 ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 451 ocs_node_transition(node, __ocs_ns_plogi_wait_rsp, NULL); 452 break; 453 default: 454 __ocs_fabric_common(__func__, ctx, evt, arg); 455 break; 456 } 457 458 return NULL; 459 } 460 461 /** 462 * @ingroup ns_sm 463 * @brief Name services node state machine: Wait for a PLOGI response. 464 * 465 * @par Description 466 * Waits for a response from PLOGI to name services node, then issues a 467 * node attach request to the HW. 468 * 469 * @param ctx Remote node state machine context. 470 * @param evt Event to process. 471 * @param arg Per event optional argument. 472 * 473 * @return Returns NULL. 474 */ 475 void * 476 __ocs_ns_plogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 477 { 478 int32_t rc; 479 ocs_node_cb_t *cbdata = arg; 480 std_node_state_decl(); 481 482 node_sm_trace(); 483 484 switch(evt) { 485 case OCS_EVT_SRRS_ELS_REQ_OK: { 486 /* Save service parameters */ 487 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 488 return NULL; 489 } 490 ocs_assert(node->els_req_cnt, NULL); 491 node->els_req_cnt--; 492 /* sm: save sparams, ocs_node_attach */ 493 ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 494 ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL, 495 ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 496 rc = ocs_node_attach(node); 497 ocs_node_transition(node, __ocs_ns_wait_node_attach, NULL); 498 if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 499 ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 500 } 501 break; 502 } 503 default: 504 __ocs_fabric_common(__func__, ctx, evt, arg); 505 return NULL; 506 } 507 508 return NULL; 509 } 510 511 /** 512 * @ingroup ns_sm 513 * @brief Name services node state machine: Wait for a node attach completion. 514 * 515 * @par Description 516 * Waits for a node attach completion, then issues an RFTID name services 517 * request. 518 * 519 * @param ctx Remote node state machine context. 520 * @param evt Event to process. 521 * @param arg Per event optional argument. 522 * 523 * @return Returns NULL. 524 */ 525 void * 526 __ocs_ns_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 527 { 528 std_node_state_decl(); 529 530 node_sm_trace(); 531 532 switch(evt) { 533 case OCS_EVT_ENTER: 534 ocs_node_hold_frames(node); 535 break; 536 537 case OCS_EVT_EXIT: 538 ocs_node_accept_frames(node); 539 break; 540 541 case OCS_EVT_NODE_ATTACH_OK: 542 node->attached = TRUE; 543 /* sm: send RFTID */ 544 ocs_ns_send_rftid(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 545 OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 546 ocs_node_transition(node, __ocs_ns_rftid_wait_rsp, NULL); 547 break; 548 549 case OCS_EVT_NODE_ATTACH_FAIL: 550 /* node attach failed, shutdown the node */ 551 node->attached = FALSE; 552 node_printf(node, "Node attach failed\n"); 553 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 554 ocs_fabric_initiate_shutdown(node); 555 break; 556 557 case OCS_EVT_SHUTDOWN: 558 node_printf(node, "Shutdown event received\n"); 559 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 560 ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL); 561 break; 562 563 /* if receive RSCN just ignore, 564 * we haven't sent GID_PT yet (ACC sent by fabctl node) */ 565 case OCS_EVT_RSCN_RCVD: 566 break; 567 568 default: 569 __ocs_fabric_common(__func__, ctx, evt, arg); 570 return NULL; 571 } 572 573 return NULL; 574 } 575 576 /** 577 * @ingroup ns_sm 578 * @brief Wait for a domain/sport/node attach completion, then 579 * shutdown. 580 * 581 * @par Description 582 * Waits for a domain/sport/node attach completion, then shuts 583 * node down. 584 * 585 * @param ctx Remote node state machine context. 586 * @param evt Event to process. 587 * @param arg Per event optional argument. 588 * 589 * @return Returns NULL. 590 */ 591 void * 592 __ocs_fabric_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 593 { 594 std_node_state_decl(); 595 596 node_sm_trace(); 597 598 switch(evt) { 599 case OCS_EVT_ENTER: 600 ocs_node_hold_frames(node); 601 break; 602 603 case OCS_EVT_EXIT: 604 ocs_node_accept_frames(node); 605 break; 606 607 /* wait for any of these attach events and then shutdown */ 608 case OCS_EVT_NODE_ATTACH_OK: 609 node->attached = TRUE; 610 node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt)); 611 ocs_fabric_initiate_shutdown(node); 612 break; 613 614 case OCS_EVT_NODE_ATTACH_FAIL: 615 node->attached = FALSE; 616 node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt)); 617 ocs_fabric_initiate_shutdown(node); 618 break; 619 620 /* ignore shutdown event as we're already in shutdown path */ 621 case OCS_EVT_SHUTDOWN: 622 node_printf(node, "Shutdown event received\n"); 623 break; 624 625 default: 626 __ocs_fabric_common(__func__, ctx, evt, arg); 627 return NULL; 628 } 629 630 return NULL; 631 } 632 633 /** 634 * @ingroup ns_sm 635 * @brief Name services node state machine: Wait for an RFTID response event. 636 * 637 * @par Description 638 * Waits for an RFTID response event; if configured for an initiator operation, 639 * a GIDPT name services request is issued. 640 * 641 * @param ctx Remote node state machine context. 642 * @param evt Event to process. 643 * @param arg Per event optional argument. 644 * 645 * @return Returns NULL. 646 */ 647 void * 648 __ocs_ns_rftid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 649 { 650 std_node_state_decl(); 651 652 node_sm_trace(); 653 654 switch(evt) { 655 case OCS_EVT_SRRS_ELS_REQ_OK: 656 if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_RFT_ID, __ocs_fabric_common, __func__)) { 657 return NULL; 658 } 659 ocs_assert(node->els_req_cnt, NULL); 660 node->els_req_cnt--; 661 /*sm: send RFFID */ 662 ocs_ns_send_rffid(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 663 OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 664 ocs_node_transition(node, __ocs_ns_rffid_wait_rsp, NULL); 665 break; 666 667 /* if receive RSCN just ignore, 668 * we haven't sent GID_PT yet (ACC sent by fabctl node) */ 669 case OCS_EVT_RSCN_RCVD: 670 break; 671 672 default: 673 __ocs_fabric_common(__func__, ctx, evt, arg); 674 return NULL; 675 } 676 677 return NULL; 678 } 679 680 /** 681 * @ingroup ns_sm 682 * @brief Fabric node state machine: Wait for RFFID response event. 683 * 684 * @par Description 685 * Waits for an RFFID response event; if configured for an initiator operation, 686 * a GIDPT name services request is issued. 687 * 688 * @param ctx Remote node state machine context. 689 * @param evt Event to process. 690 * @param arg Per event optional argument. 691 * 692 * @return Returns NULL. 693 */ 694 void * 695 __ocs_ns_rffid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 696 { 697 std_node_state_decl(); 698 699 node_sm_trace(); 700 701 switch(evt) { 702 case OCS_EVT_SRRS_ELS_REQ_OK: { 703 if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_RFF_ID, __ocs_fabric_common, __func__)) { 704 return NULL; 705 } 706 ocs_assert(node->els_req_cnt, NULL); 707 node->els_req_cnt--; 708 if (node->sport->enable_rscn) { 709 /* sm: if enable_rscn / send GIDPT */ 710 ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 711 OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 712 ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL); 713 } else { 714 /* if 'T' only, we're done, go to idle */ 715 ocs_node_transition(node, __ocs_ns_idle, NULL); 716 } 717 break; 718 } 719 /* if receive RSCN just ignore, 720 * we haven't sent GID_PT yet (ACC sent by fabctl node) */ 721 case OCS_EVT_RSCN_RCVD: 722 break; 723 724 default: 725 __ocs_fabric_common(__func__, ctx, evt, arg); 726 return NULL; 727 } 728 729 return NULL; 730 } 731 732 /** 733 * @ingroup ns_sm 734 * @brief Name services node state machine: Wait for a GIDPT response. 735 * 736 * @par Description 737 * Wait for a GIDPT response from the name server. Process the FC_IDs that are 738 * reported by creating new remote ports, as needed. 739 * 740 * @param ctx Remote node state machine context. 741 * @param evt Event to process. 742 * @param arg Per event optional argument. 743 * 744 * @return Returns NULL. 745 */ 746 void * 747 __ocs_ns_gidpt_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 748 { 749 ocs_node_cb_t *cbdata = arg; 750 std_node_state_decl(); 751 752 node_sm_trace(); 753 754 switch(evt) { 755 case OCS_EVT_SRRS_ELS_REQ_OK: { 756 if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_GID_PT, __ocs_fabric_common, __func__)) { 757 return NULL; 758 } 759 ocs_assert(node->els_req_cnt, NULL); 760 node->els_req_cnt--; 761 /* sm: / process GIDPT payload */ 762 ocs_process_gidpt_payload(node, cbdata->els->els_rsp.virt, cbdata->els->els_rsp.len); 763 /* TODO: should we logout at this point or just go idle */ 764 ocs_node_transition(node, __ocs_ns_idle, NULL); 765 break; 766 } 767 768 case OCS_EVT_SRRS_ELS_REQ_FAIL: { 769 /* not much we can do; will retry with the next RSCN */ 770 node_printf(node, "GID_PT failed to complete\n"); 771 ocs_assert(node->els_req_cnt, NULL); 772 node->els_req_cnt--; 773 ocs_node_transition(node, __ocs_ns_idle, NULL); 774 break; 775 } 776 777 /* if receive RSCN here, queue up another discovery processing */ 778 case OCS_EVT_RSCN_RCVD: { 779 node_printf(node, "RSCN received during GID_PT processing\n"); 780 node->rscn_pending = 1; 781 break; 782 } 783 784 default: 785 __ocs_fabric_common(__func__, ctx, evt, arg); 786 return NULL; 787 } 788 789 return NULL; 790 } 791 792 /** 793 * @ingroup ns_sm 794 * @brief Name services node state machine: Idle state. 795 * 796 * @par Description 797 * Idle. Waiting for RSCN received events (posted from the fabric controller), and 798 * restarts the GIDPT name services query and processing. 799 * 800 * @param ctx Remote node state machine context. 801 * @param evt Event to process. 802 * @param arg Per event optional argument. 803 * 804 * @return Returns NULL. 805 */ 806 void * 807 __ocs_ns_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 808 { 809 std_node_state_decl(); 810 811 node_sm_trace(); 812 813 switch(evt) { 814 case OCS_EVT_ENTER: 815 if (!node->rscn_pending) { 816 break; 817 } 818 node_printf(node, "RSCN pending, restart discovery\n"); 819 node->rscn_pending = 0; 820 821 /* fall through */ 822 823 case OCS_EVT_RSCN_RCVD: { 824 /* sm: / send GIDPT 825 * If target RSCN processing is enabled, and this is target only 826 * (not initiator), and tgt_rscn_delay is non-zero, 827 * then we delay issuing the GID_PT 828 */ 829 if ((ocs->tgt_rscn_delay_msec != 0) && !node->sport->enable_ini && node->sport->enable_tgt && 830 enable_target_rscn(ocs)) { 831 ocs_node_transition(node, __ocs_ns_gidpt_delay, NULL); 832 } else { 833 ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 834 OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 835 ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL); 836 } 837 break; 838 } 839 840 default: 841 __ocs_fabric_common(__func__, ctx, evt, arg); 842 break; 843 } 844 845 return NULL; 846 } 847 848 /** 849 * @brief Handle GIDPT delay timer callback 850 * 851 * @par Description 852 * Post an OCS_EVT_GIDPT_DEIALY_EXPIRED event to the passed in node. 853 * 854 * @param arg Pointer to node. 855 * 856 * @return None. 857 */ 858 static void 859 gidpt_delay_timer_cb(void *arg) 860 { 861 ocs_node_t *node = arg; 862 int32_t rc; 863 864 ocs_del_timer(&node->gidpt_delay_timer); 865 rc = ocs_xport_control(node->ocs->xport, OCS_XPORT_POST_NODE_EVENT, node, OCS_EVT_GIDPT_DELAY_EXPIRED, NULL); 866 if (rc) { 867 ocs_log_err(node->ocs, "ocs_xport_control(OCS_XPORT_POST_NODE_EVENT) failed: %d\n", rc); 868 } 869 } 870 871 /** 872 * @ingroup ns_sm 873 * @brief Name services node state machine: Delayed GIDPT. 874 * 875 * @par Description 876 * Waiting for GIDPT delay to expire before submitting GIDPT to name server. 877 * 878 * @param ctx Remote node state machine context. 879 * @param evt Event to process. 880 * @param arg Per event optional argument. 881 * 882 * @return Returns NULL. 883 */ 884 void * 885 __ocs_ns_gidpt_delay(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 886 { 887 std_node_state_decl(); 888 889 node_sm_trace(); 890 891 switch(evt) { 892 case OCS_EVT_ENTER: { 893 time_t delay_msec; 894 895 ocs_assert(ocs->tgt_rscn_delay_msec != 0, NULL); 896 897 /* 898 * Compute the delay time. Set to tgt_rscn_delay, if the time since last GIDPT 899 * is less than tgt_rscn_period, then use tgt_rscn_period. 900 */ 901 delay_msec = ocs->tgt_rscn_delay_msec; 902 if ((ocs_msectime() - node->time_last_gidpt_msec) < ocs->tgt_rscn_period_msec) { 903 delay_msec = ocs->tgt_rscn_period_msec; 904 } 905 906 ocs_setup_timer(ocs, &node->gidpt_delay_timer, gidpt_delay_timer_cb, node, delay_msec); 907 908 break; 909 } 910 911 case OCS_EVT_GIDPT_DELAY_EXPIRED: 912 node->time_last_gidpt_msec = ocs_msectime(); 913 ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 914 OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 915 ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL); 916 break; 917 918 case OCS_EVT_RSCN_RCVD: { 919 ocs_log_debug(ocs, "RSCN received while in GIDPT delay - no action\n"); 920 break; 921 } 922 923 default: 924 __ocs_fabric_common(__func__, ctx, evt, arg); 925 break; 926 } 927 928 return NULL; 929 } 930 931 /** 932 * @ingroup fabric_sm 933 * @brief Fabric controller node state machine: Initial state. 934 * 935 * @par Description 936 * Issue a PLOGI to a well-known fabric controller address. 937 * 938 * @param ctx Remote node state machine context. 939 * @param evt Event to process. 940 * @param arg Per event optional argument. 941 * 942 * @return Returns NULL. 943 */ 944 void * 945 __ocs_fabctl_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 946 { 947 ocs_node_t *node = ctx->app; 948 949 node_sm_trace(); 950 951 switch(evt) { 952 case OCS_EVT_ENTER: 953 /* no need to login to fabric controller, just send SCR */ 954 ocs_send_scr(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 955 ocs_node_transition(node, __ocs_fabctl_wait_scr_rsp, NULL); 956 break; 957 958 case OCS_EVT_NODE_ATTACH_OK: 959 node->attached = TRUE; 960 break; 961 962 default: 963 __ocs_fabric_common(__func__, ctx, evt, arg); 964 return NULL; 965 } 966 967 return NULL; 968 } 969 970 /** 971 * @ingroup fabric_sm 972 * @brief Fabric controller node state machine: Wait for a node attach request 973 * to complete. 974 * 975 * @par Description 976 * Wait for a node attach to complete. If successful, issue an SCR 977 * to the fabric controller, subscribing to all RSCN. 978 * 979 * @param ctx Remote node state machine context. 980 * @param evt Event to process. 981 * @param arg Per event optional argument. 982 * 983 * @return Returns NULL. 984 * 985 */ 986 void * 987 __ocs_fabctl_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 988 { 989 std_node_state_decl(); 990 991 node_sm_trace(); 992 993 switch(evt) { 994 case OCS_EVT_ENTER: 995 ocs_node_hold_frames(node); 996 break; 997 998 case OCS_EVT_EXIT: 999 ocs_node_accept_frames(node); 1000 break; 1001 1002 case OCS_EVT_NODE_ATTACH_OK: 1003 node->attached = TRUE; 1004 /* sm: / send SCR */ 1005 ocs_send_scr(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 1006 ocs_node_transition(node, __ocs_fabctl_wait_scr_rsp, NULL); 1007 break; 1008 1009 case OCS_EVT_NODE_ATTACH_FAIL: 1010 /* node attach failed, shutdown the node */ 1011 node->attached = FALSE; 1012 node_printf(node, "Node attach failed\n"); 1013 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1014 ocs_fabric_initiate_shutdown(node); 1015 break; 1016 1017 case OCS_EVT_SHUTDOWN: 1018 node_printf(node, "Shutdown event received\n"); 1019 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1020 ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL); 1021 break; 1022 1023 default: 1024 __ocs_fabric_common(__func__, ctx, evt, arg); 1025 return NULL; 1026 } 1027 1028 return NULL; 1029 } 1030 1031 /** 1032 * @ingroup fabric_sm 1033 * @brief Fabric controller node state machine: Wait for an SCR response from the 1034 * fabric controller. 1035 * 1036 * @par Description 1037 * Waits for an SCR response from the fabric controller. 1038 * 1039 * @param ctx Remote node state machine context. 1040 * @param evt Event to process. 1041 * @param arg Per event optional argument. 1042 * 1043 * @return Returns NULL. 1044 */ 1045 void * 1046 __ocs_fabctl_wait_scr_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1047 { 1048 std_node_state_decl(); 1049 1050 node_sm_trace(); 1051 1052 switch(evt) { 1053 case OCS_EVT_SRRS_ELS_REQ_OK: 1054 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_SCR, __ocs_fabric_common, __func__)) { 1055 return NULL; 1056 } 1057 ocs_assert(node->els_req_cnt, NULL); 1058 node->els_req_cnt--; 1059 ocs_node_transition(node, __ocs_fabctl_ready, NULL); 1060 break; 1061 1062 default: 1063 __ocs_fabric_common(__func__, ctx, evt, arg); 1064 return NULL; 1065 } 1066 1067 return NULL; 1068 } 1069 1070 /** 1071 * @ingroup fabric_sm 1072 * @brief Fabric controller node state machine: Ready. 1073 * 1074 * @par Description 1075 * In this state, the fabric controller sends a RSCN, which is received 1076 * by this node and is forwarded to the name services node object; and 1077 * the RSCN LS_ACC is sent. 1078 * 1079 * @param ctx Remote node state machine context. 1080 * @param evt Event to process. 1081 * @param arg Per event optional argument. 1082 * 1083 * @return Returns NULL. 1084 */ 1085 1086 void * 1087 __ocs_fabctl_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1088 { 1089 ocs_node_cb_t *cbdata = arg; 1090 std_node_state_decl(); 1091 1092 node_sm_trace(); 1093 1094 switch(evt) { 1095 case OCS_EVT_RSCN_RCVD: { 1096 fc_header_t *hdr = cbdata->header->dma.virt; 1097 1098 /* sm: / process RSCN (forward to name services node), 1099 * send LS_ACC */ 1100 ocs_process_rscn(node, cbdata); 1101 ocs_send_ls_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1102 ocs_node_transition(node, __ocs_fabctl_wait_ls_acc_cmpl, NULL); 1103 break; 1104 } 1105 1106 default: 1107 __ocs_fabric_common(__func__, ctx, evt, arg); 1108 return NULL; 1109 } 1110 1111 return NULL; 1112 } 1113 1114 /** 1115 * @ingroup fabric_sm 1116 * @brief Fabric controller node state machine: Wait for LS_ACC. 1117 * 1118 * @par Description 1119 * Waits for the LS_ACC from the fabric controller. 1120 * 1121 * @param ctx Remote node state machine context. 1122 * @param evt Event to process. 1123 * @param arg Per event optional argument. 1124 * 1125 * @return Returns NULL. 1126 */ 1127 1128 void * 1129 __ocs_fabctl_wait_ls_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1130 { 1131 std_node_state_decl(); 1132 1133 node_sm_trace(); 1134 1135 switch(evt) { 1136 case OCS_EVT_ENTER: 1137 ocs_node_hold_frames(node); 1138 break; 1139 1140 case OCS_EVT_EXIT: 1141 ocs_node_accept_frames(node); 1142 break; 1143 1144 case OCS_EVT_SRRS_ELS_CMPL_OK: 1145 ocs_assert(node->els_cmpl_cnt, NULL); 1146 node->els_cmpl_cnt--; 1147 ocs_node_transition(node, __ocs_fabctl_ready, NULL); 1148 break; 1149 1150 default: 1151 __ocs_fabric_common(__func__, ctx, evt, arg); 1152 return NULL; 1153 } 1154 1155 return NULL; 1156 } 1157 1158 /** 1159 * @ingroup fabric_sm 1160 * @brief Initiate fabric node shutdown. 1161 * 1162 * @param node Node for which shutdown is initiated. 1163 * 1164 * @return Returns None. 1165 */ 1166 1167 static void 1168 ocs_fabric_initiate_shutdown(ocs_node_t *node) 1169 { 1170 ocs_hw_rtn_e rc; 1171 ocs_t *ocs = node->ocs; 1172 ocs_scsi_io_alloc_disable(node); 1173 1174 if (node->attached) { 1175 /* issue hw node free; don't care if succeeds right away 1176 * or sometime later, will check node->attached later in 1177 * shutdown process 1178 */ 1179 rc = ocs_hw_node_detach(&ocs->hw, &node->rnode); 1180 if (node->rnode.free_group) { 1181 ocs_remote_node_group_free(node->node_group); 1182 node->node_group = NULL; 1183 node->rnode.free_group = FALSE; 1184 } 1185 if (rc != OCS_HW_RTN_SUCCESS && rc != OCS_HW_RTN_SUCCESS_SYNC) { 1186 node_printf(node, "Failed freeing HW node, rc=%d\n", rc); 1187 } 1188 } 1189 /* 1190 * node has either been detached or is in the process of being detached, 1191 * call common node's initiate cleanup function 1192 */ 1193 ocs_node_initiate_cleanup(node); 1194 } 1195 1196 /** 1197 * @ingroup fabric_sm 1198 * @brief Fabric node state machine: Handle the common fabric node events. 1199 * 1200 * @param funcname Function name text. 1201 * @param ctx Remote node state machine context. 1202 * @param evt Event to process. 1203 * @param arg Per event optional argument. 1204 * 1205 * @return Returns NULL. 1206 */ 1207 1208 static void * 1209 __ocs_fabric_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1210 { 1211 ocs_node_t *node = NULL; 1212 ocs_assert(ctx, NULL); 1213 ocs_assert(ctx->app, NULL); 1214 node = ctx->app; 1215 1216 switch(evt) { 1217 case OCS_EVT_DOMAIN_ATTACH_OK: 1218 break; 1219 case OCS_EVT_SHUTDOWN: 1220 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1221 ocs_fabric_initiate_shutdown(node); 1222 break; 1223 1224 default: 1225 /* call default event handler common to all nodes */ 1226 __ocs_node_common(funcname, ctx, evt, arg); 1227 break; 1228 } 1229 return NULL; 1230 } 1231 1232 /** 1233 * @brief Return TRUE if the remote node is an NPORT. 1234 * 1235 * @par Description 1236 * Examines the service parameters. Returns TRUE if the node reports itself as 1237 * an NPORT. 1238 * 1239 * @param remote_sparms Remote node service parameters. 1240 * 1241 * @return Returns TRUE if NPORT. 1242 */ 1243 1244 int32_t 1245 ocs_rnode_is_nport(fc_plogi_payload_t *remote_sparms) 1246 { 1247 return (ocs_be32toh(remote_sparms->common_service_parameters[1]) & (1U << 28)) == 0; 1248 } 1249 1250 /** 1251 * @brief Return the node's WWPN as an uint64_t. 1252 * 1253 * @par Description 1254 * The WWPN is computed from service parameters, and returned as a uint64_t. 1255 * 1256 * @param sp Pointer to service parameters. 1257 * 1258 * @return Returns WWPN. 1259 * 1260 */ 1261 1262 static uint64_t 1263 ocs_get_wwpn(fc_plogi_payload_t *sp) 1264 { 1265 return (((uint64_t)ocs_be32toh(sp->port_name_hi) << 32ll) | (ocs_be32toh(sp->port_name_lo))); 1266 } 1267 1268 /** 1269 * @brief Return TRUE if the remote node is the point-to-point winner. 1270 * 1271 * @par Description 1272 * Compares WWPNs. Returns TRUE if the remote node's WWPN is numerically 1273 * higher than the local node's WWPN. 1274 * 1275 * @param sport Pointer to the sport object. 1276 * 1277 * @return 1278 * - 0, if the remote node is the loser. 1279 * - 1, if the remote node is the winner. 1280 * - (-1), if remote node is neither the loser nor the winner 1281 * (WWPNs match) 1282 */ 1283 1284 static int32_t 1285 ocs_rnode_is_winner(ocs_sport_t *sport) 1286 { 1287 fc_plogi_payload_t *remote_sparms = (fc_plogi_payload_t*) sport->domain->flogi_service_params; 1288 uint64_t remote_wwpn = ocs_get_wwpn(remote_sparms); 1289 uint64_t local_wwpn = sport->wwpn; 1290 char prop_buf[32]; 1291 uint64_t wwn_bump = 0; 1292 1293 if (ocs_get_property("wwn_bump", prop_buf, sizeof(prop_buf)) == 0) { 1294 wwn_bump = ocs_strtoull(prop_buf, 0, 0); 1295 } 1296 local_wwpn ^= wwn_bump; 1297 1298 remote_wwpn = ocs_get_wwpn(remote_sparms); 1299 1300 ocs_log_debug(sport->ocs, "r: %08x %08x\n", ocs_be32toh(remote_sparms->port_name_hi), ocs_be32toh(remote_sparms->port_name_lo)); 1301 ocs_log_debug(sport->ocs, "l: %08x %08x\n", (uint32_t) (local_wwpn >> 32ll), (uint32_t) local_wwpn); 1302 1303 if (remote_wwpn == local_wwpn) { 1304 ocs_log_warn(sport->ocs, "WWPN of remote node [%08x %08x] matches local WWPN\n", 1305 (uint32_t) (local_wwpn >> 32ll), (uint32_t) local_wwpn); 1306 return (-1); 1307 } 1308 1309 return (remote_wwpn > local_wwpn); 1310 } 1311 1312 /** 1313 * @ingroup p2p_sm 1314 * @brief Point-to-point state machine: Wait for the domain attach to complete. 1315 * 1316 * @par Description 1317 * Once the domain attach has completed, a PLOGI is sent (if we're the 1318 * winning point-to-point node). 1319 * 1320 * @param ctx Remote node state machine context. 1321 * @param evt Event to process. 1322 * @param arg Per event optional argument. 1323 * 1324 * @return Returns NULL. 1325 */ 1326 1327 void * 1328 __ocs_p2p_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1329 { 1330 std_node_state_decl(); 1331 1332 node_sm_trace(); 1333 1334 switch(evt) { 1335 case OCS_EVT_ENTER: 1336 ocs_node_hold_frames(node); 1337 break; 1338 1339 case OCS_EVT_EXIT: 1340 ocs_node_accept_frames(node); 1341 break; 1342 1343 case OCS_EVT_DOMAIN_ATTACH_OK: { 1344 ocs_sport_t *sport = node->sport; 1345 ocs_node_t *rnode; 1346 1347 /* this transient node (SID=0 (recv'd FLOGI) or DID=fabric (sent FLOGI)) 1348 * is the p2p winner, will use a separate node to send PLOGI to peer 1349 */ 1350 ocs_assert (node->sport->p2p_winner, NULL); 1351 1352 rnode = ocs_node_find(sport, node->sport->p2p_remote_port_id); 1353 if (rnode != NULL) { 1354 /* the "other" transient p2p node has already kicked off the 1355 * new node from which PLOGI is sent */ 1356 node_printf(node, "Node with fc_id x%x already exists\n", rnode->rnode.fc_id); 1357 ocs_assert (rnode != node, NULL); 1358 } else { 1359 /* create new node (SID=1, DID=2) from which to send PLOGI */ 1360 rnode = ocs_node_alloc(sport, sport->p2p_remote_port_id, FALSE, FALSE); 1361 if (rnode == NULL) { 1362 ocs_log_err(ocs, "node alloc failed\n"); 1363 return NULL; 1364 } 1365 1366 ocs_fabric_notify_topology(node); 1367 /* sm: allocate p2p remote node */ 1368 ocs_node_transition(rnode, __ocs_p2p_rnode_init, NULL); 1369 } 1370 1371 /* the transient node (SID=0 or DID=fabric) has served its purpose */ 1372 if (node->rnode.fc_id == 0) { 1373 /* if this is the SID=0 node, move to the init state in case peer 1374 * has restarted FLOGI discovery and FLOGI is pending 1375 */ 1376 /* don't send PLOGI on ocs_d_init entry */ 1377 ocs_node_init_device(node, FALSE); 1378 } else { 1379 /* if this is the DID=fabric node (we initiated FLOGI), shut it down */ 1380 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1381 ocs_fabric_initiate_shutdown(node); 1382 } 1383 break; 1384 } 1385 1386 default: 1387 __ocs_fabric_common(__func__, ctx, evt, arg); 1388 return NULL; 1389 } 1390 1391 return NULL; 1392 } 1393 1394 /** 1395 * @ingroup p2p_sm 1396 * @brief Point-to-point state machine: Remote node initialization state. 1397 * 1398 * @par Description 1399 * This state is entered after winning point-to-point, and the remote node 1400 * is instantiated. 1401 * 1402 * @param ctx Remote node state machine context. 1403 * @param evt Event to process. 1404 * @param arg Per event optional argument. 1405 * 1406 * @return Returns NULL. 1407 */ 1408 1409 void * 1410 __ocs_p2p_rnode_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1411 { 1412 ocs_node_cb_t *cbdata = arg; 1413 std_node_state_decl(); 1414 1415 node_sm_trace(); 1416 1417 switch(evt) { 1418 case OCS_EVT_ENTER: 1419 /* sm: / send PLOGI */ 1420 ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 1421 ocs_node_transition(node, __ocs_p2p_wait_plogi_rsp, NULL); 1422 break; 1423 1424 case OCS_EVT_ABTS_RCVD: 1425 /* sm: send BA_ACC */ 1426 ocs_bls_send_acc_hdr(cbdata->io, cbdata->header->dma.virt); 1427 break; 1428 1429 default: 1430 __ocs_fabric_common(__func__, ctx, evt, arg); 1431 return NULL; 1432 } 1433 1434 return NULL; 1435 } 1436 1437 /** 1438 * @ingroup p2p_sm 1439 * @brief Point-to-point node state machine: Wait for the FLOGI accept completion. 1440 * 1441 * @par Description 1442 * Wait for the FLOGI accept completion. 1443 * 1444 * @param ctx Remote node state machine context. 1445 * @param evt Event to process. 1446 * @param arg Per event optional argument. 1447 * 1448 * @return Returns NULL. 1449 */ 1450 1451 void * 1452 __ocs_p2p_wait_flogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1453 { 1454 ocs_node_cb_t *cbdata = arg; 1455 std_node_state_decl(); 1456 1457 node_sm_trace(); 1458 1459 switch(evt) { 1460 case OCS_EVT_ENTER: 1461 ocs_node_hold_frames(node); 1462 break; 1463 1464 case OCS_EVT_EXIT: 1465 ocs_node_accept_frames(node); 1466 break; 1467 1468 case OCS_EVT_SRRS_ELS_CMPL_OK: 1469 ocs_assert(node->els_cmpl_cnt, NULL); 1470 node->els_cmpl_cnt--; 1471 1472 /* sm: if p2p_winner / domain_attach */ 1473 if (node->sport->p2p_winner) { 1474 ocs_node_transition(node, __ocs_p2p_wait_domain_attach, NULL); 1475 if (node->sport->domain->attached && 1476 !(node->sport->domain->domain_notify_pend)) { 1477 node_printf(node, "Domain already attached\n"); 1478 ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL); 1479 } 1480 } else { 1481 /* this node has served its purpose; we'll expect a PLOGI on a separate 1482 * node (remote SID=0x1); return this node to init state in case peer 1483 * restarts discovery -- it may already have (pending frames may exist). 1484 */ 1485 /* don't send PLOGI on ocs_d_init entry */ 1486 ocs_node_init_device(node, FALSE); 1487 } 1488 break; 1489 1490 case OCS_EVT_SRRS_ELS_CMPL_FAIL: 1491 /* LS_ACC failed, possibly due to link down; shutdown node and wait 1492 * for FLOGI discovery to restart */ 1493 node_printf(node, "FLOGI LS_ACC failed, shutting down\n"); 1494 ocs_assert(node->els_cmpl_cnt, NULL); 1495 node->els_cmpl_cnt--; 1496 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1497 ocs_fabric_initiate_shutdown(node); 1498 break; 1499 1500 case OCS_EVT_ABTS_RCVD: { 1501 /* sm: / send BA_ACC */ 1502 ocs_bls_send_acc_hdr(cbdata->io, cbdata->header->dma.virt); 1503 break; 1504 } 1505 1506 default: 1507 __ocs_fabric_common(__func__, ctx, evt, arg); 1508 return NULL; 1509 } 1510 1511 return NULL; 1512 } 1513 1514 /** 1515 * @ingroup p2p_sm 1516 * @brief Point-to-point node state machine: Wait for a PLOGI response 1517 * as a point-to-point winner. 1518 * 1519 * @par Description 1520 * Wait for a PLOGI response from the remote node as a point-to-point winner. 1521 * Submit node attach request to the HW. 1522 * 1523 * @param ctx Remote node state machine context. 1524 * @param evt Event to process. 1525 * @param arg Per event optional argument. 1526 * 1527 * @return Returns NULL. 1528 */ 1529 1530 void * 1531 __ocs_p2p_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1532 { 1533 int32_t rc; 1534 ocs_node_cb_t *cbdata = arg; 1535 std_node_state_decl(); 1536 1537 node_sm_trace(); 1538 1539 switch(evt) { 1540 case OCS_EVT_SRRS_ELS_REQ_OK: { 1541 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1542 return NULL; 1543 } 1544 ocs_assert(node->els_req_cnt, NULL); 1545 node->els_req_cnt--; 1546 /* sm: / save sparams, ocs_node_attach */ 1547 ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 1548 rc = ocs_node_attach(node); 1549 ocs_node_transition(node, __ocs_p2p_wait_node_attach, NULL); 1550 if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1551 ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1552 } 1553 break; 1554 } 1555 case OCS_EVT_SRRS_ELS_REQ_FAIL: { 1556 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1557 return NULL; 1558 } 1559 node_printf(node, "PLOGI failed, shutting down\n"); 1560 ocs_assert(node->els_req_cnt, NULL); 1561 node->els_req_cnt--; 1562 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1563 ocs_fabric_initiate_shutdown(node); 1564 break; 1565 } 1566 1567 case OCS_EVT_PLOGI_RCVD: { 1568 fc_header_t *hdr = cbdata->header->dma.virt; 1569 /* if we're in external loopback mode, just send LS_ACC */ 1570 if (node->ocs->external_loopback) { 1571 ocs_send_plogi_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1572 break; 1573 } else{ 1574 /* if this isn't external loopback, pass to default handler */ 1575 __ocs_fabric_common(__func__, ctx, evt, arg); 1576 } 1577 break; 1578 } 1579 case OCS_EVT_PRLI_RCVD: 1580 /* I, or I+T */ 1581 /* sent PLOGI and before completion was seen, received the 1582 * PRLI from the remote node (WCQEs and RCQEs come in on 1583 * different queues and order of processing cannot be assumed) 1584 * Save OXID so PRLI can be sent after the attach and continue 1585 * to wait for PLOGI response 1586 */ 1587 ocs_process_prli_payload(node, cbdata->payload->dma.virt); 1588 ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI); 1589 ocs_node_transition(node, __ocs_p2p_wait_plogi_rsp_recvd_prli, NULL); 1590 break; 1591 default: 1592 __ocs_fabric_common(__func__, ctx, evt, arg); 1593 return NULL; 1594 } 1595 1596 return NULL; 1597 } 1598 1599 /** 1600 * @ingroup p2p_sm 1601 * @brief Point-to-point node state machine: Waiting on a response for a 1602 * sent PLOGI. 1603 * 1604 * @par Description 1605 * State is entered when the point-to-point winner has sent 1606 * a PLOGI and is waiting for a response. Before receiving the 1607 * response, a PRLI was received, implying that the PLOGI was 1608 * successful. 1609 * 1610 * @param ctx Remote node state machine context. 1611 * @param evt Event to process. 1612 * @param arg Per event optional argument. 1613 * 1614 * @return Returns NULL. 1615 */ 1616 1617 void * 1618 __ocs_p2p_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1619 { 1620 int32_t rc; 1621 ocs_node_cb_t *cbdata = arg; 1622 std_node_state_decl(); 1623 1624 node_sm_trace(); 1625 1626 switch(evt) { 1627 case OCS_EVT_ENTER: 1628 /* 1629 * Since we've received a PRLI, we have a port login and will 1630 * just need to wait for the PLOGI response to do the node 1631 * attach and then we can send the LS_ACC for the PRLI. If, 1632 * during this time, we receive FCP_CMNDs (which is possible 1633 * since we've already sent a PRLI and our peer may have accepted). 1634 * At this time, we are not waiting on any other unsolicited 1635 * frames to continue with the login process. Thus, it will not 1636 * hurt to hold frames here. 1637 */ 1638 ocs_node_hold_frames(node); 1639 break; 1640 1641 case OCS_EVT_EXIT: 1642 ocs_node_accept_frames(node); 1643 break; 1644 1645 case OCS_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */ 1646 /* Completion from PLOGI sent */ 1647 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1648 return NULL; 1649 } 1650 ocs_assert(node->els_req_cnt, NULL); 1651 node->els_req_cnt--; 1652 /* sm: / save sparams, ocs_node_attach */ 1653 ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 1654 ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL, 1655 ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 1656 rc = ocs_node_attach(node); 1657 ocs_node_transition(node, __ocs_p2p_wait_node_attach, NULL); 1658 if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1659 ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1660 } 1661 break; 1662 1663 case OCS_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */ 1664 case OCS_EVT_SRRS_ELS_REQ_RJT: 1665 /* PLOGI failed, shutdown the node */ 1666 if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1667 return NULL; 1668 } 1669 ocs_assert(node->els_req_cnt, NULL); 1670 node->els_req_cnt--; 1671 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1672 ocs_fabric_initiate_shutdown(node); 1673 break; 1674 1675 default: 1676 __ocs_fabric_common(__func__, ctx, evt, arg); 1677 return NULL; 1678 } 1679 1680 return NULL; 1681 } 1682 1683 /** 1684 * @ingroup p2p_sm 1685 * @brief Point-to-point node state machine: Wait for a point-to-point node attach 1686 * to complete. 1687 * 1688 * @par Description 1689 * Waits for the point-to-point node attach to complete. 1690 * 1691 * @param ctx Remote node state machine context. 1692 * @param evt Event to process. 1693 * @param arg Per event optional argument. 1694 * 1695 * @return Returns NULL. 1696 */ 1697 1698 void * 1699 __ocs_p2p_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1700 { 1701 ocs_node_cb_t *cbdata = arg; 1702 std_node_state_decl(); 1703 1704 node_sm_trace(); 1705 1706 switch(evt) { 1707 case OCS_EVT_ENTER: 1708 ocs_node_hold_frames(node); 1709 break; 1710 1711 case OCS_EVT_EXIT: 1712 ocs_node_accept_frames(node); 1713 break; 1714 1715 case OCS_EVT_NODE_ATTACH_OK: 1716 node->attached = TRUE; 1717 switch (node->send_ls_acc) { 1718 case OCS_NODE_SEND_LS_ACC_PRLI: { 1719 ocs_d_send_prli_rsp(node->ls_acc_io, node->ls_acc_oxid); 1720 node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE; 1721 node->ls_acc_io = NULL; 1722 break; 1723 } 1724 case OCS_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */ 1725 case OCS_NODE_SEND_LS_ACC_NONE: 1726 default: 1727 /* Normal case for I */ 1728 /* sm: send_plogi_acc is not set / send PLOGI acc */ 1729 ocs_node_transition(node, __ocs_d_port_logged_in, NULL); 1730 break; 1731 } 1732 break; 1733 1734 case OCS_EVT_NODE_ATTACH_FAIL: 1735 /* node attach failed, shutdown the node */ 1736 node->attached = FALSE; 1737 node_printf(node, "Node attach failed\n"); 1738 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1739 ocs_fabric_initiate_shutdown(node); 1740 break; 1741 1742 case OCS_EVT_SHUTDOWN: 1743 node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1744 node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1745 ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL); 1746 break; 1747 case OCS_EVT_PRLI_RCVD: 1748 node_printf(node, "%s: PRLI received before node is attached\n", ocs_sm_event_name(evt)); 1749 ocs_process_prli_payload(node, cbdata->payload->dma.virt); 1750 ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI); 1751 break; 1752 default: 1753 __ocs_fabric_common(__func__, ctx, evt, arg); 1754 return NULL; 1755 } 1756 1757 return NULL; 1758 } 1759 1760 /** 1761 * @brief Start up the name services node. 1762 * 1763 * @par Description 1764 * Allocates and starts up the name services node. 1765 * 1766 * @param sport Pointer to the sport structure. 1767 * 1768 * @return Returns 0 on success, or a negative error value on failure. 1769 */ 1770 1771 static int32_t 1772 ocs_start_ns_node(ocs_sport_t *sport) 1773 { 1774 ocs_node_t *ns; 1775 1776 /* Instantiate a name services node */ 1777 ns = ocs_node_find(sport, FC_ADDR_NAMESERVER); 1778 if (ns == NULL) { 1779 ns = ocs_node_alloc(sport, FC_ADDR_NAMESERVER, FALSE, FALSE); 1780 if (ns == NULL) { 1781 return -1; 1782 } 1783 } 1784 /* TODO: for found ns, should we be transitioning from here? 1785 * breaks transition only 1. from within state machine or 1786 * 2. if after alloc 1787 */ 1788 if (ns->ocs->nodedb_mask & OCS_NODEDB_PAUSE_NAMESERVER) { 1789 ocs_node_pause(ns, __ocs_ns_init); 1790 } else { 1791 ocs_node_transition(ns, __ocs_ns_init, NULL); 1792 } 1793 return 0; 1794 } 1795 1796 /** 1797 * @brief Start up the fabric controller node. 1798 * 1799 * @par Description 1800 * Allocates and starts up the fabric controller node. 1801 * 1802 * @param sport Pointer to the sport structure. 1803 * 1804 * @return Returns 0 on success, or a negative error value on failure. 1805 */ 1806 1807 static int32_t 1808 ocs_start_fabctl_node(ocs_sport_t *sport) 1809 { 1810 ocs_node_t *fabctl; 1811 1812 fabctl = ocs_node_find(sport, FC_ADDR_CONTROLLER); 1813 if (fabctl == NULL) { 1814 fabctl = ocs_node_alloc(sport, FC_ADDR_CONTROLLER, FALSE, FALSE); 1815 if (fabctl == NULL) { 1816 return -1; 1817 } 1818 } 1819 /* TODO: for found ns, should we be transitioning from here? 1820 * breaks transition only 1. from within state machine or 1821 * 2. if after alloc 1822 */ 1823 ocs_node_transition(fabctl, __ocs_fabctl_init, NULL); 1824 return 0; 1825 } 1826 1827 /** 1828 * @brief Process the GIDPT payload. 1829 * 1830 * @par Description 1831 * The GIDPT payload is parsed, and new nodes are created, as needed. 1832 * 1833 * @param node Pointer to the node structure. 1834 * @param gidpt Pointer to the GIDPT payload. 1835 * @param gidpt_len Payload length 1836 * 1837 * @return Returns 0 on success, or a negative error value on failure. 1838 */ 1839 1840 static int32_t 1841 ocs_process_gidpt_payload(ocs_node_t *node, fcct_gidpt_acc_t *gidpt, uint32_t gidpt_len) 1842 { 1843 uint32_t i; 1844 uint32_t j; 1845 ocs_node_t *newnode; 1846 ocs_sport_t *sport = node->sport; 1847 ocs_t *ocs = node->ocs; 1848 uint32_t port_id; 1849 uint32_t port_count; 1850 ocs_node_t *n; 1851 ocs_node_t **active_nodes; 1852 uint32_t portlist_count; 1853 uint16_t residual; 1854 1855 residual = ocs_be16toh(gidpt->hdr.max_residual_size); 1856 1857 if (residual != 0) { 1858 ocs_log_debug(node->ocs, "residual is %u words\n", residual); 1859 } 1860 1861 if (ocs_be16toh(gidpt->hdr.cmd_rsp_code) == FCCT_HDR_CMDRSP_REJECT) { 1862 node_printf(node, "GIDPT request failed: rsn x%x rsn_expl x%x\n", 1863 gidpt->hdr.reason_code, gidpt->hdr.reason_code_explanation); 1864 return -1; 1865 } 1866 1867 portlist_count = (gidpt_len - sizeof(fcct_iu_header_t)) / sizeof(gidpt->port_list); 1868 1869 /* Count the number of nodes */ 1870 port_count = 0; 1871 ocs_sport_lock(sport); 1872 ocs_list_foreach(&sport->node_list, n) { 1873 port_count ++; 1874 } 1875 1876 /* Allocate a buffer for all nodes */ 1877 active_nodes = ocs_malloc(node->ocs, port_count * sizeof(*active_nodes), OCS_M_NOWAIT | OCS_M_ZERO); 1878 if (active_nodes == NULL) { 1879 node_printf(node, "ocs_malloc failed\n"); 1880 ocs_sport_unlock(sport); 1881 return -1; 1882 } 1883 1884 /* Fill buffer with fc_id of active nodes */ 1885 i = 0; 1886 ocs_list_foreach(&sport->node_list, n) { 1887 port_id = n->rnode.fc_id; 1888 switch (port_id) { 1889 case FC_ADDR_FABRIC: 1890 case FC_ADDR_CONTROLLER: 1891 case FC_ADDR_NAMESERVER: 1892 break; 1893 default: 1894 if (!FC_ADDR_IS_DOMAIN_CTRL(port_id)) { 1895 active_nodes[i++] = n; 1896 } 1897 break; 1898 } 1899 } 1900 1901 /* update the active nodes buffer */ 1902 for (i = 0; i < portlist_count; i ++) { 1903 port_id = fc_be24toh(gidpt->port_list[i].port_id); 1904 1905 for (j = 0; j < port_count; j ++) { 1906 if ((active_nodes[j] != NULL) && (port_id == active_nodes[j]->rnode.fc_id)) { 1907 active_nodes[j] = NULL; 1908 } 1909 } 1910 1911 if (gidpt->port_list[i].ctl & FCCT_GID_PT_LAST_ID) 1912 break; 1913 } 1914 1915 /* Those remaining in the active_nodes[] are now gone ! */ 1916 for (i = 0; i < port_count; i ++) { 1917 /* if we're an initiator and the remote node is a target, then 1918 * post the node missing event. if we're target and we have enabled 1919 * target RSCN, then post the node missing event. 1920 */ 1921 if (active_nodes[i] != NULL) { 1922 if ((node->sport->enable_ini && active_nodes[i]->targ) || 1923 (node->sport->enable_tgt && enable_target_rscn(ocs))) { 1924 ocs_node_post_event(active_nodes[i], OCS_EVT_NODE_MISSING, NULL); 1925 } else { 1926 node_printf(node, "GID_PT: skipping non-tgt port_id x%06x\n", 1927 active_nodes[i]->rnode.fc_id); 1928 } 1929 } 1930 } 1931 ocs_free(ocs, active_nodes, port_count * sizeof(*active_nodes)); 1932 1933 for(i = 0; i < portlist_count; i ++) { 1934 uint32_t port_id = fc_be24toh(gidpt->port_list[i].port_id); 1935 1936 /* node_printf(node, "GID_PT: port_id x%06x\n", port_id); */ 1937 1938 /* Don't create node for ourselves or the associated NPIV ports */ 1939 if (port_id != node->rnode.sport->fc_id && !ocs_sport_find(sport->domain, port_id)) { 1940 newnode = ocs_node_find(sport, port_id); 1941 if (newnode) { 1942 /* TODO: what if node deleted here?? */ 1943 if (node->sport->enable_ini && newnode->targ) { 1944 ocs_node_post_event(newnode, OCS_EVT_NODE_REFOUND, NULL); 1945 } 1946 /* original code sends ADISC, has notion of "refound" */ 1947 } else { 1948 if (node->sport->enable_ini) { 1949 newnode = ocs_node_alloc(sport, port_id, 0, 0); 1950 if (newnode == NULL) { 1951 ocs_log_err(ocs, "ocs_node_alloc() failed\n"); 1952 ocs_sport_unlock(sport); 1953 return -1; 1954 } 1955 /* send PLOGI automatically if initiator */ 1956 ocs_node_init_device(newnode, TRUE); 1957 } 1958 } 1959 } 1960 1961 if (gidpt->port_list[i].ctl & FCCT_GID_PT_LAST_ID) { 1962 break; 1963 } 1964 } 1965 ocs_sport_unlock(sport); 1966 return 0; 1967 } 1968 1969 /** 1970 * @brief Set up the domain point-to-point parameters. 1971 * 1972 * @par Description 1973 * The remote node service parameters are examined, and various point-to-point 1974 * variables are set. 1975 * 1976 * @param sport Pointer to the sport object. 1977 * 1978 * @return Returns 0 on success, or a negative error value on failure. 1979 */ 1980 1981 int32_t 1982 ocs_p2p_setup(ocs_sport_t *sport) 1983 { 1984 ocs_t *ocs = sport->ocs; 1985 int32_t rnode_winner; 1986 rnode_winner = ocs_rnode_is_winner(sport); 1987 1988 /* set sport flags to indicate p2p "winner" */ 1989 if (rnode_winner == 1) { 1990 sport->p2p_remote_port_id = 0; 1991 sport->p2p_port_id = 0; 1992 sport->p2p_winner = FALSE; 1993 } else if (rnode_winner == 0) { 1994 sport->p2p_remote_port_id = 2; 1995 sport->p2p_port_id = 1; 1996 sport->p2p_winner = TRUE; 1997 } else { 1998 /* no winner; only okay if external loopback enabled */ 1999 if (sport->ocs->external_loopback) { 2000 /* 2001 * External loopback mode enabled; local sport and remote node 2002 * will be registered with an NPortID = 1; 2003 */ 2004 ocs_log_debug(ocs, "External loopback mode enabled\n"); 2005 sport->p2p_remote_port_id = 1; 2006 sport->p2p_port_id = 1; 2007 sport->p2p_winner = TRUE; 2008 } else { 2009 ocs_log_warn(ocs, "failed to determine p2p winner\n"); 2010 return rnode_winner; 2011 } 2012 } 2013 return 0; 2014 } 2015 2016 /** 2017 * @brief Process the FABCTL node RSCN. 2018 * 2019 * <h3 class="desc">Description</h3> 2020 * Processes the FABCTL node RSCN payload, simply passes the event to the name server. 2021 * 2022 * @param node Pointer to the node structure. 2023 * @param cbdata Callback data to pass forward. 2024 * 2025 * @return None. 2026 */ 2027 2028 static void 2029 ocs_process_rscn(ocs_node_t *node, ocs_node_cb_t *cbdata) 2030 { 2031 ocs_t *ocs = node->ocs; 2032 ocs_sport_t *sport = node->sport; 2033 ocs_node_t *ns; 2034 2035 /* Forward this event to the name-services node */ 2036 ns = ocs_node_find(sport, FC_ADDR_NAMESERVER); 2037 if (ns != NULL) { 2038 ocs_node_post_event(ns, OCS_EVT_RSCN_RCVD, cbdata); 2039 } else { 2040 ocs_log_warn(ocs, "can't find name server node\n"); 2041 } 2042 } 2043