1564 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2021 Broadcom. All Rights Reserved. The term4 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.5 */6 7/*8 * This file implements remote node state machines for:9 * - Fabric logins.10 * - Fabric controller events.11 * - Name/directory services interaction.12 * - Point-to-point logins.13 */14 15/*16 * fabric_sm Node State Machine: Fabric States17 * ns_sm Node State Machine: Name/Directory Services States18 * p2p_sm Node State Machine: Point-to-Point Node States19 */20 21#include "efc.h"22 23static void24efc_fabric_initiate_shutdown(struct efc_node *node)25{26 struct efc *efc = node->efc;27 28 node->els_io_enabled = false;29 30 if (node->attached) {31 int rc;32 33 /* issue hw node free; don't care if succeeds right away34 * or sometime later, will check node->attached later in35 * shutdown process36 */37 rc = efc_cmd_node_detach(efc, &node->rnode);38 if (rc < 0) {39 node_printf(node, "Failed freeing HW node, rc=%d\n",40 rc);41 }42 }43 /*44 * node has either been detached or is in the process of being detached,45 * call common node's initiate cleanup function46 */47 efc_node_initiate_cleanup(node);48}49 50static void51__efc_fabric_common(const char *funcname, struct efc_sm_ctx *ctx,52 enum efc_sm_event evt, void *arg)53{54 struct efc_node *node = NULL;55 56 node = ctx->app;57 58 switch (evt) {59 case EFC_EVT_DOMAIN_ATTACH_OK:60 break;61 case EFC_EVT_SHUTDOWN:62 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;63 efc_fabric_initiate_shutdown(node);64 break;65 66 default:67 /* call default event handler common to all nodes */68 __efc_node_common(funcname, ctx, evt, arg);69 }70}71 72void73__efc_fabric_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt,74 void *arg)75{76 struct efc_node *node = ctx->app;77 struct efc *efc = node->efc;78 79 efc_node_evt_set(ctx, evt, __func__);80 81 node_sm_trace();82 83 switch (evt) {84 case EFC_EVT_REENTER:85 efc_log_debug(efc, ">>> reenter !!\n");86 fallthrough;87 88 case EFC_EVT_ENTER:89 /* send FLOGI */90 efc_send_flogi(node);91 efc_node_transition(node, __efc_fabric_flogi_wait_rsp, NULL);92 break;93 94 default:95 __efc_fabric_common(__func__, ctx, evt, arg);96 }97}98 99void100efc_fabric_set_topology(struct efc_node *node,101 enum efc_nport_topology topology)102{103 node->nport->topology = topology;104}105 106void107efc_fabric_notify_topology(struct efc_node *node)108{109 struct efc_node *tmp_node;110 unsigned long index;111 112 /*113 * now loop through the nodes in the nport114 * and send topology notification115 */116 xa_for_each(&node->nport->lookup, index, tmp_node) {117 if (tmp_node != node) {118 efc_node_post_event(tmp_node,119 EFC_EVT_NPORT_TOPOLOGY_NOTIFY,120 &node->nport->topology);121 }122 }123}124 125static bool efc_rnode_is_nport(struct fc_els_flogi *rsp)126{127 return !(ntohs(rsp->fl_csp.sp_features) & FC_SP_FT_FPORT);128}129 130void131__efc_fabric_flogi_wait_rsp(struct efc_sm_ctx *ctx,132 enum efc_sm_event evt, void *arg)133{134 struct efc_node_cb *cbdata = arg;135 struct efc_node *node = ctx->app;136 137 efc_node_evt_set(ctx, evt, __func__);138 139 node_sm_trace();140 141 switch (evt) {142 case EFC_EVT_SRRS_ELS_REQ_OK: {143 if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,144 __efc_fabric_common, __func__)) {145 return;146 }147 WARN_ON(!node->els_req_cnt);148 node->els_req_cnt--;149 150 memcpy(node->nport->domain->flogi_service_params,151 cbdata->els_rsp.virt,152 sizeof(struct fc_els_flogi));153 154 /* Check to see if the fabric is an F_PORT or and N_PORT */155 if (!efc_rnode_is_nport(cbdata->els_rsp.virt)) {156 /* sm: if not nport / efc_domain_attach */157 /* ext_status has the fc_id, attach domain */158 efc_fabric_set_topology(node, EFC_NPORT_TOPO_FABRIC);159 efc_fabric_notify_topology(node);160 WARN_ON(node->nport->domain->attached);161 efc_domain_attach(node->nport->domain,162 cbdata->ext_status);163 efc_node_transition(node,164 __efc_fabric_wait_domain_attach,165 NULL);166 break;167 }168 169 /* sm: if nport and p2p_winner / efc_domain_attach */170 efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P);171 if (efc_p2p_setup(node->nport)) {172 node_printf(node,173 "p2p setup failed, shutting down node\n");174 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;175 efc_fabric_initiate_shutdown(node);176 break;177 }178 179 if (node->nport->p2p_winner) {180 efc_node_transition(node,181 __efc_p2p_wait_domain_attach,182 NULL);183 if (node->nport->domain->attached &&184 !node->nport->domain->domain_notify_pend) {185 /*186 * already attached,187 * just send ATTACH_OK188 */189 node_printf(node,190 "p2p winner, domain already attached\n");191 efc_node_post_event(node,192 EFC_EVT_DOMAIN_ATTACH_OK,193 NULL);194 }195 } else {196 /*197 * peer is p2p winner;198 * PLOGI will be received on the199 * remote SID=1 node;200 * this node has served its purpose201 */202 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;203 efc_fabric_initiate_shutdown(node);204 }205 206 break;207 }208 209 case EFC_EVT_ELS_REQ_ABORTED:210 case EFC_EVT_SRRS_ELS_REQ_RJT:211 case EFC_EVT_SRRS_ELS_REQ_FAIL: {212 struct efc_nport *nport = node->nport;213 /*214 * with these errors, we have no recovery,215 * so shutdown the nport, leave the link216 * up and the domain ready217 */218 if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,219 __efc_fabric_common, __func__)) {220 return;221 }222 node_printf(node,223 "FLOGI failed evt=%s, shutting down nport [%s]\n",224 efc_sm_event_name(evt), nport->display_name);225 WARN_ON(!node->els_req_cnt);226 node->els_req_cnt--;227 efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL);228 break;229 }230 231 default:232 __efc_fabric_common(__func__, ctx, evt, arg);233 }234}235 236void237__efc_vport_fabric_init(struct efc_sm_ctx *ctx,238 enum efc_sm_event evt, void *arg)239{240 struct efc_node *node = ctx->app;241 242 efc_node_evt_set(ctx, evt, __func__);243 244 node_sm_trace();245 246 switch (evt) {247 case EFC_EVT_ENTER:248 /* sm: / send FDISC */249 efc_send_fdisc(node);250 efc_node_transition(node, __efc_fabric_fdisc_wait_rsp, NULL);251 break;252 253 default:254 __efc_fabric_common(__func__, ctx, evt, arg);255 }256}257 258void259__efc_fabric_fdisc_wait_rsp(struct efc_sm_ctx *ctx,260 enum efc_sm_event evt, void *arg)261{262 struct efc_node_cb *cbdata = arg;263 struct efc_node *node = ctx->app;264 265 efc_node_evt_set(ctx, evt, __func__);266 267 node_sm_trace();268 269 switch (evt) {270 case EFC_EVT_SRRS_ELS_REQ_OK: {271 /* fc_id is in ext_status */272 if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,273 __efc_fabric_common, __func__)) {274 return;275 }276 277 WARN_ON(!node->els_req_cnt);278 node->els_req_cnt--;279 /* sm: / efc_nport_attach */280 efc_nport_attach(node->nport, cbdata->ext_status);281 efc_node_transition(node, __efc_fabric_wait_domain_attach,282 NULL);283 break;284 }285 286 case EFC_EVT_SRRS_ELS_REQ_RJT:287 case EFC_EVT_SRRS_ELS_REQ_FAIL: {288 if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,289 __efc_fabric_common, __func__)) {290 return;291 }292 WARN_ON(!node->els_req_cnt);293 node->els_req_cnt--;294 efc_log_err(node->efc, "FDISC failed, shutting down nport\n");295 /* sm: / shutdown nport */296 efc_sm_post_event(&node->nport->sm, EFC_EVT_SHUTDOWN, NULL);297 break;298 }299 300 default:301 __efc_fabric_common(__func__, ctx, evt, arg);302 }303}304 305static int306efc_start_ns_node(struct efc_nport *nport)307{308 struct efc_node *ns;309 310 /* Instantiate a name services node */311 ns = efc_node_find(nport, FC_FID_DIR_SERV);312 if (!ns) {313 ns = efc_node_alloc(nport, FC_FID_DIR_SERV, false, false);314 if (!ns)315 return -EIO;316 }317 /*318 * for found ns, should we be transitioning from here?319 * breaks transition only320 * 1. from within state machine or321 * 2. if after alloc322 */323 if (ns->efc->nodedb_mask & EFC_NODEDB_PAUSE_NAMESERVER)324 efc_node_pause(ns, __efc_ns_init);325 else326 efc_node_transition(ns, __efc_ns_init, NULL);327 return 0;328}329 330static int331efc_start_fabctl_node(struct efc_nport *nport)332{333 struct efc_node *fabctl;334 335 fabctl = efc_node_find(nport, FC_FID_FCTRL);336 if (!fabctl) {337 fabctl = efc_node_alloc(nport, FC_FID_FCTRL,338 false, false);339 if (!fabctl)340 return -EIO;341 }342 /*343 * for found ns, should we be transitioning from here?344 * breaks transition only345 * 1. from within state machine or346 * 2. if after alloc347 */348 efc_node_transition(fabctl, __efc_fabctl_init, NULL);349 return 0;350}351 352void353__efc_fabric_wait_domain_attach(struct efc_sm_ctx *ctx,354 enum efc_sm_event evt, void *arg)355{356 struct efc_node *node = ctx->app;357 358 efc_node_evt_set(ctx, evt, __func__);359 360 node_sm_trace();361 362 switch (evt) {363 case EFC_EVT_ENTER:364 efc_node_hold_frames(node);365 break;366 367 case EFC_EVT_EXIT:368 efc_node_accept_frames(node);369 break;370 case EFC_EVT_DOMAIN_ATTACH_OK:371 case EFC_EVT_NPORT_ATTACH_OK: {372 int rc;373 374 rc = efc_start_ns_node(node->nport);375 if (rc)376 return;377 378 /* sm: if enable_ini / start fabctl node */379 /* Instantiate the fabric controller (sends SCR) */380 if (node->nport->enable_rscn) {381 rc = efc_start_fabctl_node(node->nport);382 if (rc)383 return;384 }385 efc_node_transition(node, __efc_fabric_idle, NULL);386 break;387 }388 default:389 __efc_fabric_common(__func__, ctx, evt, arg);390 }391}392 393void394__efc_fabric_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt,395 void *arg)396{397 struct efc_node *node = ctx->app;398 399 efc_node_evt_set(ctx, evt, __func__);400 401 node_sm_trace();402 403 switch (evt) {404 case EFC_EVT_DOMAIN_ATTACH_OK:405 break;406 default:407 __efc_fabric_common(__func__, ctx, evt, arg);408 }409}410 411void412__efc_ns_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)413{414 struct efc_node *node = ctx->app;415 416 efc_node_evt_set(ctx, evt, __func__);417 418 node_sm_trace();419 420 switch (evt) {421 case EFC_EVT_ENTER:422 /* sm: / send PLOGI */423 efc_send_plogi(node);424 efc_node_transition(node, __efc_ns_plogi_wait_rsp, NULL);425 break;426 default:427 __efc_fabric_common(__func__, ctx, evt, arg);428 }429}430 431void432__efc_ns_plogi_wait_rsp(struct efc_sm_ctx *ctx,433 enum efc_sm_event evt, void *arg)434{435 struct efc_node_cb *cbdata = arg;436 struct efc_node *node = ctx->app;437 438 efc_node_evt_set(ctx, evt, __func__);439 440 node_sm_trace();441 442 switch (evt) {443 case EFC_EVT_SRRS_ELS_REQ_OK: {444 int rc;445 446 /* Save service parameters */447 if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,448 __efc_fabric_common, __func__)) {449 return;450 }451 WARN_ON(!node->els_req_cnt);452 node->els_req_cnt--;453 /* sm: / save sparams, efc_node_attach */454 efc_node_save_sparms(node, cbdata->els_rsp.virt);455 rc = efc_node_attach(node);456 efc_node_transition(node, __efc_ns_wait_node_attach, NULL);457 if (rc < 0)458 efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,459 NULL);460 break;461 }462 default:463 __efc_fabric_common(__func__, ctx, evt, arg);464 }465}466 467void468__efc_ns_wait_node_attach(struct efc_sm_ctx *ctx,469 enum efc_sm_event evt, void *arg)470{471 struct efc_node *node = ctx->app;472 473 efc_node_evt_set(ctx, evt, __func__);474 475 node_sm_trace();476 477 switch (evt) {478 case EFC_EVT_ENTER:479 efc_node_hold_frames(node);480 break;481 482 case EFC_EVT_EXIT:483 efc_node_accept_frames(node);484 break;485 486 case EFC_EVT_NODE_ATTACH_OK:487 node->attached = true;488 /* sm: / send RFTID */489 efc_ns_send_rftid(node);490 efc_node_transition(node, __efc_ns_rftid_wait_rsp, NULL);491 break;492 493 case EFC_EVT_NODE_ATTACH_FAIL:494 /* node attach failed, shutdown the node */495 node->attached = false;496 node_printf(node, "Node attach failed\n");497 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;498 efc_fabric_initiate_shutdown(node);499 break;500 501 case EFC_EVT_SHUTDOWN:502 node_printf(node, "Shutdown event received\n");503 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;504 efc_node_transition(node,505 __efc_fabric_wait_attach_evt_shutdown,506 NULL);507 break;508 509 /*510 * if receive RSCN just ignore,511 * we haven't sent GID_PT yet (ACC sent by fabctl node)512 */513 case EFC_EVT_RSCN_RCVD:514 break;515 516 default:517 __efc_fabric_common(__func__, ctx, evt, arg);518 }519}520 521void522__efc_fabric_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,523 enum efc_sm_event evt, void *arg)524{525 struct efc_node *node = ctx->app;526 527 efc_node_evt_set(ctx, evt, __func__);528 529 node_sm_trace();530 531 switch (evt) {532 case EFC_EVT_ENTER:533 efc_node_hold_frames(node);534 break;535 536 case EFC_EVT_EXIT:537 efc_node_accept_frames(node);538 break;539 540 /* wait for any of these attach events and then shutdown */541 case EFC_EVT_NODE_ATTACH_OK:542 node->attached = true;543 node_printf(node, "Attach evt=%s, proceed to shutdown\n",544 efc_sm_event_name(evt));545 efc_fabric_initiate_shutdown(node);546 break;547 548 case EFC_EVT_NODE_ATTACH_FAIL:549 node->attached = false;550 node_printf(node, "Attach evt=%s, proceed to shutdown\n",551 efc_sm_event_name(evt));552 efc_fabric_initiate_shutdown(node);553 break;554 555 /* ignore shutdown event as we're already in shutdown path */556 case EFC_EVT_SHUTDOWN:557 node_printf(node, "Shutdown event received\n");558 break;559 560 default:561 __efc_fabric_common(__func__, ctx, evt, arg);562 }563}564 565void566__efc_ns_rftid_wait_rsp(struct efc_sm_ctx *ctx,567 enum efc_sm_event evt, void *arg)568{569 struct efc_node *node = ctx->app;570 571 efc_node_evt_set(ctx, evt, __func__);572 573 node_sm_trace();574 575 switch (evt) {576 case EFC_EVT_SRRS_ELS_REQ_OK:577 if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFT_ID,578 __efc_fabric_common, __func__)) {579 return;580 }581 WARN_ON(!node->els_req_cnt);582 node->els_req_cnt--;583 /* sm: / send RFFID */584 efc_ns_send_rffid(node);585 efc_node_transition(node, __efc_ns_rffid_wait_rsp, NULL);586 break;587 588 /*589 * if receive RSCN just ignore,590 * we haven't sent GID_PT yet (ACC sent by fabctl node)591 */592 case EFC_EVT_RSCN_RCVD:593 break;594 595 default:596 __efc_fabric_common(__func__, ctx, evt, arg);597 }598}599 600void601__efc_ns_rffid_wait_rsp(struct efc_sm_ctx *ctx,602 enum efc_sm_event evt, void *arg)603{604 struct efc_node *node = ctx->app;605 606 efc_node_evt_set(ctx, evt, __func__);607 608 node_sm_trace();609 610 /*611 * Waits for an RFFID response event;612 * if rscn enabled, a GIDPT name services request is issued.613 */614 switch (evt) {615 case EFC_EVT_SRRS_ELS_REQ_OK: {616 if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFF_ID,617 __efc_fabric_common, __func__)) {618 return;619 }620 WARN_ON(!node->els_req_cnt);621 node->els_req_cnt--;622 if (node->nport->enable_rscn) {623 /* sm: if enable_rscn / send GIDPT */624 efc_ns_send_gidpt(node);625 626 efc_node_transition(node, __efc_ns_gidpt_wait_rsp,627 NULL);628 } else {629 /* if 'T' only, we're done, go to idle */630 efc_node_transition(node, __efc_ns_idle, NULL);631 }632 break;633 }634 /*635 * if receive RSCN just ignore,636 * we haven't sent GID_PT yet (ACC sent by fabctl node)637 */638 case EFC_EVT_RSCN_RCVD:639 break;640 641 default:642 __efc_fabric_common(__func__, ctx, evt, arg);643 }644}645 646static int647efc_process_gidpt_payload(struct efc_node *node,648 void *data, u32 gidpt_len)649{650 u32 i, j;651 struct efc_node *newnode;652 struct efc_nport *nport = node->nport;653 struct efc *efc = node->efc;654 u32 port_id = 0, port_count, plist_count;655 struct efc_node *n;656 struct efc_node **active_nodes;657 int residual;658 struct {659 struct fc_ct_hdr hdr;660 struct fc_gid_pn_resp pn_rsp;661 } *rsp;662 struct fc_gid_pn_resp *gidpt;663 unsigned long index;664 665 rsp = data;666 gidpt = &rsp->pn_rsp;667 residual = be16_to_cpu(rsp->hdr.ct_mr_size);668 669 if (residual != 0)670 efc_log_debug(node->efc, "residual is %u words\n", residual);671 672 if (be16_to_cpu(rsp->hdr.ct_cmd) == FC_FS_RJT) {673 node_printf(node,674 "GIDPT request failed: rsn x%x rsn_expl x%x\n",675 rsp->hdr.ct_reason, rsp->hdr.ct_explan);676 return -EIO;677 }678 679 plist_count = (gidpt_len - sizeof(struct fc_ct_hdr)) / sizeof(*gidpt);680 681 /* Count the number of nodes */682 port_count = 0;683 xa_for_each(&nport->lookup, index, n) {684 port_count++;685 }686 687 /* Allocate a buffer for all nodes */688 active_nodes = kcalloc(port_count, sizeof(*active_nodes), GFP_ATOMIC);689 if (!active_nodes) {690 node_printf(node, "efc_malloc failed\n");691 return -EIO;692 }693 694 /* Fill buffer with fc_id of active nodes */695 i = 0;696 xa_for_each(&nport->lookup, index, n) {697 port_id = n->rnode.fc_id;698 switch (port_id) {699 case FC_FID_FLOGI:700 case FC_FID_FCTRL:701 case FC_FID_DIR_SERV:702 break;703 default:704 if (port_id != FC_FID_DOM_MGR)705 active_nodes[i++] = n;706 break;707 }708 }709 710 /* update the active nodes buffer */711 for (i = 0; i < plist_count; i++) {712 hton24(gidpt[i].fp_fid, port_id);713 714 for (j = 0; j < port_count; j++) {715 if (active_nodes[j] &&716 port_id == active_nodes[j]->rnode.fc_id) {717 active_nodes[j] = NULL;718 }719 }720 721 if (gidpt[i].fp_resvd & FC_NS_FID_LAST)722 break;723 }724 725 /* Those remaining in the active_nodes[] are now gone ! */726 for (i = 0; i < port_count; i++) {727 /*728 * if we're an initiator and the remote node729 * is a target, then post the node missing event.730 * if we're target and we have enabled731 * target RSCN, then post the node missing event.732 */733 if (!active_nodes[i])734 continue;735 736 if ((node->nport->enable_ini && active_nodes[i]->targ) ||737 (node->nport->enable_tgt && enable_target_rscn(efc))) {738 efc_node_post_event(active_nodes[i],739 EFC_EVT_NODE_MISSING, NULL);740 } else {741 node_printf(node,742 "GID_PT: skipping non-tgt port_id x%06x\n",743 active_nodes[i]->rnode.fc_id);744 }745 }746 kfree(active_nodes);747 748 for (i = 0; i < plist_count; i++) {749 hton24(gidpt[i].fp_fid, port_id);750 751 /* Don't create node for ourselves */752 if (port_id == node->rnode.nport->fc_id) {753 if (gidpt[i].fp_resvd & FC_NS_FID_LAST)754 break;755 continue;756 }757 758 newnode = efc_node_find(nport, port_id);759 if (!newnode) {760 if (!node->nport->enable_ini)761 continue;762 763 newnode = efc_node_alloc(nport, port_id, false, false);764 if (!newnode) {765 efc_log_err(efc, "efc_node_alloc() failed\n");766 return -EIO;767 }768 /*769 * send PLOGI automatically770 * if initiator771 */772 efc_node_init_device(newnode, true);773 }774 775 if (node->nport->enable_ini && newnode->targ) {776 efc_node_post_event(newnode, EFC_EVT_NODE_REFOUND,777 NULL);778 }779 780 if (gidpt[i].fp_resvd & FC_NS_FID_LAST)781 break;782 }783 return 0;784}785 786void787__efc_ns_gidpt_wait_rsp(struct efc_sm_ctx *ctx,788 enum efc_sm_event evt, void *arg)789{790 struct efc_node_cb *cbdata = arg;791 struct efc_node *node = ctx->app;792 793 efc_node_evt_set(ctx, evt, __func__);794 795 node_sm_trace();796 /*797 * Wait for a GIDPT response from the name server. Process the FC_IDs798 * that are reported by creating new remote ports, as needed.799 */800 801 switch (evt) {802 case EFC_EVT_SRRS_ELS_REQ_OK: {803 if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_GID_PT,804 __efc_fabric_common, __func__)) {805 return;806 }807 WARN_ON(!node->els_req_cnt);808 node->els_req_cnt--;809 /* sm: / process GIDPT payload */810 efc_process_gidpt_payload(node, cbdata->els_rsp.virt,811 cbdata->els_rsp.len);812 efc_node_transition(node, __efc_ns_idle, NULL);813 break;814 }815 816 case EFC_EVT_SRRS_ELS_REQ_FAIL: {817 /* not much we can do; will retry with the next RSCN */818 node_printf(node, "GID_PT failed to complete\n");819 WARN_ON(!node->els_req_cnt);820 node->els_req_cnt--;821 efc_node_transition(node, __efc_ns_idle, NULL);822 break;823 }824 825 /* if receive RSCN here, queue up another discovery processing */826 case EFC_EVT_RSCN_RCVD: {827 node_printf(node, "RSCN received during GID_PT processing\n");828 node->rscn_pending = true;829 break;830 }831 832 default:833 __efc_fabric_common(__func__, ctx, evt, arg);834 }835}836 837void838__efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)839{840 struct efc_node *node = ctx->app;841 struct efc *efc = node->efc;842 843 efc_node_evt_set(ctx, evt, __func__);844 845 node_sm_trace();846 847 /*848 * Wait for RSCN received events (posted from the fabric controller)849 * and restart the GIDPT name services query and processing.850 */851 852 switch (evt) {853 case EFC_EVT_ENTER:854 if (!node->rscn_pending)855 break;856 857 node_printf(node, "RSCN pending, restart discovery\n");858 node->rscn_pending = false;859 fallthrough;860 861 case EFC_EVT_RSCN_RCVD: {862 /* sm: / send GIDPT */863 /*864 * If target RSCN processing is enabled,865 * and this is target only (not initiator),866 * and tgt_rscn_delay is non-zero,867 * then we delay issuing the GID_PT868 */869 if (efc->tgt_rscn_delay_msec != 0 &&870 !node->nport->enable_ini && node->nport->enable_tgt &&871 enable_target_rscn(efc)) {872 efc_node_transition(node, __efc_ns_gidpt_delay, NULL);873 } else {874 efc_ns_send_gidpt(node);875 efc_node_transition(node, __efc_ns_gidpt_wait_rsp,876 NULL);877 }878 break;879 }880 881 default:882 __efc_fabric_common(__func__, ctx, evt, arg);883 }884}885 886static void887gidpt_delay_timer_cb(struct timer_list *t)888{889 struct efc_node *node = from_timer(node, t, gidpt_delay_timer);890 891 del_timer(&node->gidpt_delay_timer);892 893 efc_node_post_event(node, EFC_EVT_GIDPT_DELAY_EXPIRED, NULL);894}895 896void897__efc_ns_gidpt_delay(struct efc_sm_ctx *ctx,898 enum efc_sm_event evt, void *arg)899{900 struct efc_node *node = ctx->app;901 struct efc *efc = node->efc;902 903 efc_node_evt_set(ctx, evt, __func__);904 905 node_sm_trace();906 907 switch (evt) {908 case EFC_EVT_ENTER: {909 u64 delay_msec, tmp;910 911 /*912 * Compute the delay time.913 * Set to tgt_rscn_delay, if the time since last GIDPT914 * is less than tgt_rscn_period, then use tgt_rscn_period.915 */916 delay_msec = efc->tgt_rscn_delay_msec;917 tmp = jiffies_to_msecs(jiffies) - node->time_last_gidpt_msec;918 if (tmp < efc->tgt_rscn_period_msec)919 delay_msec = efc->tgt_rscn_period_msec;920 921 timer_setup(&node->gidpt_delay_timer, &gidpt_delay_timer_cb,922 0);923 mod_timer(&node->gidpt_delay_timer,924 jiffies + msecs_to_jiffies(delay_msec));925 926 break;927 }928 929 case EFC_EVT_GIDPT_DELAY_EXPIRED:930 node->time_last_gidpt_msec = jiffies_to_msecs(jiffies);931 932 efc_ns_send_gidpt(node);933 efc_node_transition(node, __efc_ns_gidpt_wait_rsp, NULL);934 break;935 936 case EFC_EVT_RSCN_RCVD: {937 efc_log_debug(efc,938 "RSCN received while in GIDPT delay - no action\n");939 break;940 }941 942 default:943 __efc_fabric_common(__func__, ctx, evt, arg);944 }945}946 947void948__efc_fabctl_init(struct efc_sm_ctx *ctx,949 enum efc_sm_event evt, void *arg)950{951 struct efc_node *node = ctx->app;952 953 node_sm_trace();954 955 switch (evt) {956 case EFC_EVT_ENTER:957 /* no need to login to fabric controller, just send SCR */958 efc_send_scr(node);959 efc_node_transition(node, __efc_fabctl_wait_scr_rsp, NULL);960 break;961 962 case EFC_EVT_NODE_ATTACH_OK:963 node->attached = true;964 break;965 966 default:967 __efc_fabric_common(__func__, ctx, evt, arg);968 }969}970 971void972__efc_fabctl_wait_scr_rsp(struct efc_sm_ctx *ctx,973 enum efc_sm_event evt, void *arg)974{975 struct efc_node *node = ctx->app;976 977 efc_node_evt_set(ctx, evt, __func__);978 979 node_sm_trace();980 981 /*982 * Fabric controller node state machine:983 * Wait for an SCR response from the fabric controller.984 */985 switch (evt) {986 case EFC_EVT_SRRS_ELS_REQ_OK:987 if (efc_node_check_els_req(ctx, evt, arg, ELS_SCR,988 __efc_fabric_common, __func__)) {989 return;990 }991 WARN_ON(!node->els_req_cnt);992 node->els_req_cnt--;993 efc_node_transition(node, __efc_fabctl_ready, NULL);994 break;995 996 default:997 __efc_fabric_common(__func__, ctx, evt, arg);998 }999}1000 1001static void1002efc_process_rscn(struct efc_node *node, struct efc_node_cb *cbdata)1003{1004 struct efc *efc = node->efc;1005 struct efc_nport *nport = node->nport;1006 struct efc_node *ns;1007 1008 /* Forward this event to the name-services node */1009 ns = efc_node_find(nport, FC_FID_DIR_SERV);1010 if (ns)1011 efc_node_post_event(ns, EFC_EVT_RSCN_RCVD, cbdata);1012 else1013 efc_log_warn(efc, "can't find name server node\n");1014}1015 1016void1017__efc_fabctl_ready(struct efc_sm_ctx *ctx,1018 enum efc_sm_event evt, void *arg)1019{1020 struct efc_node_cb *cbdata = arg;1021 struct efc_node *node = ctx->app;1022 1023 efc_node_evt_set(ctx, evt, __func__);1024 1025 node_sm_trace();1026 1027 /*1028 * Fabric controller node state machine: Ready.1029 * In this state, the fabric controller sends a RSCN, which is received1030 * by this node and is forwarded to the name services node object; and1031 * the RSCN LS_ACC is sent.1032 */1033 switch (evt) {1034 case EFC_EVT_RSCN_RCVD: {1035 struct fc_frame_header *hdr = cbdata->header->dma.virt;1036 1037 /*1038 * sm: / process RSCN (forward to name services node),1039 * send LS_ACC1040 */1041 efc_process_rscn(node, cbdata);1042 efc_send_ls_acc(node, be16_to_cpu(hdr->fh_ox_id));1043 efc_node_transition(node, __efc_fabctl_wait_ls_acc_cmpl,1044 NULL);1045 break;1046 }1047 1048 default:1049 __efc_fabric_common(__func__, ctx, evt, arg);1050 }1051}1052 1053void1054__efc_fabctl_wait_ls_acc_cmpl(struct efc_sm_ctx *ctx,1055 enum efc_sm_event evt, void *arg)1056{1057 struct efc_node *node = ctx->app;1058 1059 efc_node_evt_set(ctx, evt, __func__);1060 1061 node_sm_trace();1062 1063 switch (evt) {1064 case EFC_EVT_ENTER:1065 efc_node_hold_frames(node);1066 break;1067 1068 case EFC_EVT_EXIT:1069 efc_node_accept_frames(node);1070 break;1071 1072 case EFC_EVT_SRRS_ELS_CMPL_OK:1073 WARN_ON(!node->els_cmpl_cnt);1074 node->els_cmpl_cnt--;1075 efc_node_transition(node, __efc_fabctl_ready, NULL);1076 break;1077 1078 default:1079 __efc_fabric_common(__func__, ctx, evt, arg);1080 }1081}1082 1083static uint64_t1084efc_get_wwpn(struct fc_els_flogi *sp)1085{1086 return be64_to_cpu(sp->fl_wwnn);1087}1088 1089static int1090efc_rnode_is_winner(struct efc_nport *nport)1091{1092 struct fc_els_flogi *remote_sp;1093 u64 remote_wwpn;1094 u64 local_wwpn = nport->wwpn;1095 u64 wwn_bump = 0;1096 1097 remote_sp = (struct fc_els_flogi *)nport->domain->flogi_service_params;1098 remote_wwpn = efc_get_wwpn(remote_sp);1099 1100 local_wwpn ^= wwn_bump;1101 1102 efc_log_debug(nport->efc, "r: %llx\n",1103 be64_to_cpu(remote_sp->fl_wwpn));1104 efc_log_debug(nport->efc, "l: %llx\n", local_wwpn);1105 1106 if (remote_wwpn == local_wwpn) {1107 efc_log_warn(nport->efc,1108 "WWPN of remote node [%08x %08x] matches local WWPN\n",1109 (u32)(local_wwpn >> 32ll),1110 (u32)local_wwpn);1111 return -1;1112 }1113 1114 return (remote_wwpn > local_wwpn);1115}1116 1117void1118__efc_p2p_wait_domain_attach(struct efc_sm_ctx *ctx,1119 enum efc_sm_event evt, void *arg)1120{1121 struct efc_node *node = ctx->app;1122 struct efc *efc = node->efc;1123 1124 efc_node_evt_set(ctx, evt, __func__);1125 1126 node_sm_trace();1127 1128 switch (evt) {1129 case EFC_EVT_ENTER:1130 efc_node_hold_frames(node);1131 break;1132 1133 case EFC_EVT_EXIT:1134 efc_node_accept_frames(node);1135 break;1136 1137 case EFC_EVT_DOMAIN_ATTACH_OK: {1138 struct efc_nport *nport = node->nport;1139 struct efc_node *rnode;1140 1141 /*1142 * this transient node (SID=0 (recv'd FLOGI)1143 * or DID=fabric (sent FLOGI))1144 * is the p2p winner, will use a separate node1145 * to send PLOGI to peer1146 */1147 WARN_ON(!node->nport->p2p_winner);1148 1149 rnode = efc_node_find(nport, node->nport->p2p_remote_port_id);1150 if (rnode) {1151 /*1152 * the "other" transient p2p node has1153 * already kicked off the1154 * new node from which PLOGI is sent1155 */1156 node_printf(node,1157 "Node with fc_id x%x already exists\n",1158 rnode->rnode.fc_id);1159 } else {1160 /*1161 * create new node (SID=1, DID=2)1162 * from which to send PLOGI1163 */1164 rnode = efc_node_alloc(nport,1165 nport->p2p_remote_port_id,1166 false, false);1167 if (!rnode) {1168 efc_log_err(efc, "node alloc failed\n");1169 return;1170 }1171 1172 efc_fabric_notify_topology(node);1173 /* sm: / allocate p2p remote node */1174 efc_node_transition(rnode, __efc_p2p_rnode_init,1175 NULL);1176 }1177 1178 /*1179 * the transient node (SID=0 or DID=fabric)1180 * has served its purpose1181 */1182 if (node->rnode.fc_id == 0) {1183 /*1184 * if this is the SID=0 node,1185 * move to the init state in case peer1186 * has restarted FLOGI discovery and FLOGI is pending1187 */1188 /* don't send PLOGI on efc_d_init entry */1189 efc_node_init_device(node, false);1190 } else {1191 /*1192 * if this is the DID=fabric node1193 * (we initiated FLOGI), shut it down1194 */1195 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;1196 efc_fabric_initiate_shutdown(node);1197 }1198 break;1199 }1200 1201 default:1202 __efc_fabric_common(__func__, ctx, evt, arg);1203 }1204}1205 1206void1207__efc_p2p_rnode_init(struct efc_sm_ctx *ctx,1208 enum efc_sm_event evt, void *arg)1209{1210 struct efc_node_cb *cbdata = arg;1211 struct efc_node *node = ctx->app;1212 1213 efc_node_evt_set(ctx, evt, __func__);1214 1215 node_sm_trace();1216 1217 switch (evt) {1218 case EFC_EVT_ENTER:1219 /* sm: / send PLOGI */1220 efc_send_plogi(node);1221 efc_node_transition(node, __efc_p2p_wait_plogi_rsp, NULL);1222 break;1223 1224 case EFC_EVT_ABTS_RCVD:1225 /* sm: send BA_ACC */1226 efc_send_bls_acc(node, cbdata->header->dma.virt);1227 1228 break;1229 1230 default:1231 __efc_fabric_common(__func__, ctx, evt, arg);1232 }1233}1234 1235void1236__efc_p2p_wait_flogi_acc_cmpl(struct efc_sm_ctx *ctx,1237 enum efc_sm_event evt, void *arg)1238{1239 struct efc_node_cb *cbdata = arg;1240 struct efc_node *node = ctx->app;1241 1242 efc_node_evt_set(ctx, evt, __func__);1243 1244 node_sm_trace();1245 1246 switch (evt) {1247 case EFC_EVT_ENTER:1248 efc_node_hold_frames(node);1249 break;1250 1251 case EFC_EVT_EXIT:1252 efc_node_accept_frames(node);1253 break;1254 1255 case EFC_EVT_SRRS_ELS_CMPL_OK:1256 WARN_ON(!node->els_cmpl_cnt);1257 node->els_cmpl_cnt--;1258 1259 /* sm: if p2p_winner / domain_attach */1260 if (node->nport->p2p_winner) {1261 efc_node_transition(node,1262 __efc_p2p_wait_domain_attach,1263 NULL);1264 if (!node->nport->domain->attached) {1265 node_printf(node, "Domain not attached\n");1266 efc_domain_attach(node->nport->domain,1267 node->nport->p2p_port_id);1268 } else {1269 node_printf(node, "Domain already attached\n");1270 efc_node_post_event(node,1271 EFC_EVT_DOMAIN_ATTACH_OK,1272 NULL);1273 }1274 } else {1275 /* this node has served its purpose;1276 * we'll expect a PLOGI on a separate1277 * node (remote SID=0x1); return this node1278 * to init state in case peer1279 * restarts discovery -- it may already1280 * have (pending frames may exist).1281 */1282 /* don't send PLOGI on efc_d_init entry */1283 efc_node_init_device(node, false);1284 }1285 break;1286 1287 case EFC_EVT_SRRS_ELS_CMPL_FAIL:1288 /*1289 * LS_ACC failed, possibly due to link down;1290 * shutdown node and wait1291 * for FLOGI discovery to restart1292 */1293 node_printf(node, "FLOGI LS_ACC failed, shutting down\n");1294 WARN_ON(!node->els_cmpl_cnt);1295 node->els_cmpl_cnt--;1296 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;1297 efc_fabric_initiate_shutdown(node);1298 break;1299 1300 case EFC_EVT_ABTS_RCVD: {1301 /* sm: / send BA_ACC */1302 efc_send_bls_acc(node, cbdata->header->dma.virt);1303 break;1304 }1305 1306 default:1307 __efc_fabric_common(__func__, ctx, evt, arg);1308 }1309}1310 1311void1312__efc_p2p_wait_plogi_rsp(struct efc_sm_ctx *ctx,1313 enum efc_sm_event evt, void *arg)1314{1315 struct efc_node_cb *cbdata = arg;1316 struct efc_node *node = ctx->app;1317 1318 efc_node_evt_set(ctx, evt, __func__);1319 1320 node_sm_trace();1321 1322 switch (evt) {1323 case EFC_EVT_SRRS_ELS_REQ_OK: {1324 int rc;1325 1326 if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,1327 __efc_fabric_common, __func__)) {1328 return;1329 }1330 WARN_ON(!node->els_req_cnt);1331 node->els_req_cnt--;1332 /* sm: / save sparams, efc_node_attach */1333 efc_node_save_sparms(node, cbdata->els_rsp.virt);1334 rc = efc_node_attach(node);1335 efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);1336 if (rc < 0)1337 efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,1338 NULL);1339 break;1340 }1341 case EFC_EVT_SRRS_ELS_REQ_FAIL: {1342 if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,1343 __efc_fabric_common, __func__)) {1344 return;1345 }1346 node_printf(node, "PLOGI failed, shutting down\n");1347 WARN_ON(!node->els_req_cnt);1348 node->els_req_cnt--;1349 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;1350 efc_fabric_initiate_shutdown(node);1351 break;1352 }1353 1354 case EFC_EVT_PLOGI_RCVD: {1355 struct fc_frame_header *hdr = cbdata->header->dma.virt;1356 /* if we're in external loopback mode, just send LS_ACC */1357 if (node->efc->external_loopback) {1358 efc_send_plogi_acc(node, be16_to_cpu(hdr->fh_ox_id));1359 } else {1360 /*1361 * if this isn't external loopback,1362 * pass to default handler1363 */1364 __efc_fabric_common(__func__, ctx, evt, arg);1365 }1366 break;1367 }1368 case EFC_EVT_PRLI_RCVD:1369 /* I, or I+T */1370 /* sent PLOGI and before completion was seen, received the1371 * PRLI from the remote node (WCQEs and RCQEs come in on1372 * different queues and order of processing cannot be assumed)1373 * Save OXID so PRLI can be sent after the attach and continue1374 * to wait for PLOGI response1375 */1376 efc_process_prli_payload(node, cbdata->payload->dma.virt);1377 efc_send_ls_acc_after_attach(node,1378 cbdata->header->dma.virt,1379 EFC_NODE_SEND_LS_ACC_PRLI);1380 efc_node_transition(node, __efc_p2p_wait_plogi_rsp_recvd_prli,1381 NULL);1382 break;1383 default:1384 __efc_fabric_common(__func__, ctx, evt, arg);1385 }1386}1387 1388void1389__efc_p2p_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,1390 enum efc_sm_event evt, void *arg)1391{1392 struct efc_node_cb *cbdata = arg;1393 struct efc_node *node = ctx->app;1394 1395 efc_node_evt_set(ctx, evt, __func__);1396 1397 node_sm_trace();1398 1399 switch (evt) {1400 case EFC_EVT_ENTER:1401 /*1402 * Since we've received a PRLI, we have a port login and will1403 * just need to wait for the PLOGI response to do the node1404 * attach and then we can send the LS_ACC for the PRLI. If,1405 * during this time, we receive FCP_CMNDs (which is possible1406 * since we've already sent a PRLI and our peer may have1407 * accepted).1408 * At this time, we are not waiting on any other unsolicited1409 * frames to continue with the login process. Thus, it will not1410 * hurt to hold frames here.1411 */1412 efc_node_hold_frames(node);1413 break;1414 1415 case EFC_EVT_EXIT:1416 efc_node_accept_frames(node);1417 break;1418 1419 case EFC_EVT_SRRS_ELS_REQ_OK: { /* PLOGI response received */1420 int rc;1421 1422 /* Completion from PLOGI sent */1423 if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,1424 __efc_fabric_common, __func__)) {1425 return;1426 }1427 WARN_ON(!node->els_req_cnt);1428 node->els_req_cnt--;1429 /* sm: / save sparams, efc_node_attach */1430 efc_node_save_sparms(node, cbdata->els_rsp.virt);1431 rc = efc_node_attach(node);1432 efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);1433 if (rc < 0)1434 efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,1435 NULL);1436 break;1437 }1438 case EFC_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */1439 case EFC_EVT_SRRS_ELS_REQ_RJT:1440 /* PLOGI failed, shutdown the node */1441 if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,1442 __efc_fabric_common, __func__)) {1443 return;1444 }1445 WARN_ON(!node->els_req_cnt);1446 node->els_req_cnt--;1447 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;1448 efc_fabric_initiate_shutdown(node);1449 break;1450 1451 default:1452 __efc_fabric_common(__func__, ctx, evt, arg);1453 }1454}1455 1456void1457__efc_p2p_wait_node_attach(struct efc_sm_ctx *ctx,1458 enum efc_sm_event evt, void *arg)1459{1460 struct efc_node_cb *cbdata = arg;1461 struct efc_node *node = ctx->app;1462 1463 efc_node_evt_set(ctx, evt, __func__);1464 1465 node_sm_trace();1466 1467 switch (evt) {1468 case EFC_EVT_ENTER:1469 efc_node_hold_frames(node);1470 break;1471 1472 case EFC_EVT_EXIT:1473 efc_node_accept_frames(node);1474 break;1475 1476 case EFC_EVT_NODE_ATTACH_OK:1477 node->attached = true;1478 switch (node->send_ls_acc) {1479 case EFC_NODE_SEND_LS_ACC_PRLI: {1480 efc_d_send_prli_rsp(node->ls_acc_io,1481 node->ls_acc_oxid);1482 node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;1483 node->ls_acc_io = NULL;1484 break;1485 }1486 case EFC_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */1487 case EFC_NODE_SEND_LS_ACC_NONE:1488 default:1489 /* Normal case for I */1490 /* sm: send_plogi_acc is not set / send PLOGI acc */1491 efc_node_transition(node, __efc_d_port_logged_in,1492 NULL);1493 break;1494 }1495 break;1496 1497 case EFC_EVT_NODE_ATTACH_FAIL:1498 /* node attach failed, shutdown the node */1499 node->attached = false;1500 node_printf(node, "Node attach failed\n");1501 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;1502 efc_fabric_initiate_shutdown(node);1503 break;1504 1505 case EFC_EVT_SHUTDOWN:1506 node_printf(node, "%s received\n", efc_sm_event_name(evt));1507 node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;1508 efc_node_transition(node,1509 __efc_fabric_wait_attach_evt_shutdown,1510 NULL);1511 break;1512 case EFC_EVT_PRLI_RCVD:1513 node_printf(node, "%s: PRLI received before node is attached\n",1514 efc_sm_event_name(evt));1515 efc_process_prli_payload(node, cbdata->payload->dma.virt);1516 efc_send_ls_acc_after_attach(node,1517 cbdata->header->dma.virt,1518 EFC_NODE_SEND_LS_ACC_PRLI);1519 break;1520 1521 default:1522 __efc_fabric_common(__func__, ctx, evt, arg);1523 }1524}1525 1526int1527efc_p2p_setup(struct efc_nport *nport)1528{1529 struct efc *efc = nport->efc;1530 int rnode_winner;1531 1532 rnode_winner = efc_rnode_is_winner(nport);1533 1534 /* set nport flags to indicate p2p "winner" */1535 if (rnode_winner == 1) {1536 nport->p2p_remote_port_id = 0;1537 nport->p2p_port_id = 0;1538 nport->p2p_winner = false;1539 } else if (rnode_winner == 0) {1540 nport->p2p_remote_port_id = 2;1541 nport->p2p_port_id = 1;1542 nport->p2p_winner = true;1543 } else {1544 /* no winner; only okay if external loopback enabled */1545 if (nport->efc->external_loopback) {1546 /*1547 * External loopback mode enabled;1548 * local nport and remote node1549 * will be registered with an NPortID = 1;1550 */1551 efc_log_debug(efc,1552 "External loopback mode enabled\n");1553 nport->p2p_remote_port_id = 1;1554 nport->p2p_port_id = 1;1555 nport->p2p_winner = true;1556 } else {1557 efc_log_warn(efc,1558 "failed to determine p2p winner\n");1559 return rnode_winner;1560 }1561 }1562 return 0;1563}1564