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