162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2021 Broadcom. All Rights Reserved. The term 462306a36Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * This file implements remote node state machines for: 962306a36Sopenharmony_ci * - Fabric logins. 1062306a36Sopenharmony_ci * - Fabric controller events. 1162306a36Sopenharmony_ci * - Name/directory services interaction. 1262306a36Sopenharmony_ci * - Point-to-point logins. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * fabric_sm Node State Machine: Fabric States 1762306a36Sopenharmony_ci * ns_sm Node State Machine: Name/Directory Services States 1862306a36Sopenharmony_ci * p2p_sm Node State Machine: Point-to-Point Node States 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "efc.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void 2462306a36Sopenharmony_ciefc_fabric_initiate_shutdown(struct efc_node *node) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct efc *efc = node->efc; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci node->els_io_enabled = false; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (node->attached) { 3162306a36Sopenharmony_ci int rc; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* issue hw node free; don't care if succeeds right away 3462306a36Sopenharmony_ci * or sometime later, will check node->attached later in 3562306a36Sopenharmony_ci * shutdown process 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci rc = efc_cmd_node_detach(efc, &node->rnode); 3862306a36Sopenharmony_ci if (rc < 0) { 3962306a36Sopenharmony_ci node_printf(node, "Failed freeing HW node, rc=%d\n", 4062306a36Sopenharmony_ci rc); 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci /* 4462306a36Sopenharmony_ci * node has either been detached or is in the process of being detached, 4562306a36Sopenharmony_ci * call common node's initiate cleanup function 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci efc_node_initiate_cleanup(node); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void 5162306a36Sopenharmony_ci__efc_fabric_common(const char *funcname, struct efc_sm_ctx *ctx, 5262306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct efc_node *node = NULL; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci node = ctx->app; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci switch (evt) { 5962306a36Sopenharmony_ci case EFC_EVT_DOMAIN_ATTACH_OK: 6062306a36Sopenharmony_ci break; 6162306a36Sopenharmony_ci case EFC_EVT_SHUTDOWN: 6262306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 6362306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci default: 6762306a36Sopenharmony_ci /* call default event handler common to all nodes */ 6862306a36Sopenharmony_ci __efc_node_common(funcname, ctx, evt, arg); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_civoid 7362306a36Sopenharmony_ci__efc_fabric_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, 7462306a36Sopenharmony_ci void *arg) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct efc_node *node = ctx->app; 7762306a36Sopenharmony_ci struct efc *efc = node->efc; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci node_sm_trace(); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci switch (evt) { 8462306a36Sopenharmony_ci case EFC_EVT_REENTER: 8562306a36Sopenharmony_ci efc_log_debug(efc, ">>> reenter !!\n"); 8662306a36Sopenharmony_ci fallthrough; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci case EFC_EVT_ENTER: 8962306a36Sopenharmony_ci /* send FLOGI */ 9062306a36Sopenharmony_ci efc_send_flogi(node); 9162306a36Sopenharmony_ci efc_node_transition(node, __efc_fabric_flogi_wait_rsp, NULL); 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci default: 9562306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_civoid 10062306a36Sopenharmony_ciefc_fabric_set_topology(struct efc_node *node, 10162306a36Sopenharmony_ci enum efc_nport_topology topology) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci node->nport->topology = topology; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_civoid 10762306a36Sopenharmony_ciefc_fabric_notify_topology(struct efc_node *node) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct efc_node *tmp_node; 11062306a36Sopenharmony_ci unsigned long index; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * now loop through the nodes in the nport 11462306a36Sopenharmony_ci * and send topology notification 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci xa_for_each(&node->nport->lookup, index, tmp_node) { 11762306a36Sopenharmony_ci if (tmp_node != node) { 11862306a36Sopenharmony_ci efc_node_post_event(tmp_node, 11962306a36Sopenharmony_ci EFC_EVT_NPORT_TOPOLOGY_NOTIFY, 12062306a36Sopenharmony_ci &node->nport->topology); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic bool efc_rnode_is_nport(struct fc_els_flogi *rsp) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci return !(ntohs(rsp->fl_csp.sp_features) & FC_SP_FT_FPORT); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_civoid 13162306a36Sopenharmony_ci__efc_fabric_flogi_wait_rsp(struct efc_sm_ctx *ctx, 13262306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 13562306a36Sopenharmony_ci struct efc_node *node = ctx->app; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci node_sm_trace(); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci switch (evt) { 14262306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: { 14362306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI, 14462306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 14862306a36Sopenharmony_ci node->els_req_cnt--; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci memcpy(node->nport->domain->flogi_service_params, 15162306a36Sopenharmony_ci cbdata->els_rsp.virt, 15262306a36Sopenharmony_ci sizeof(struct fc_els_flogi)); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Check to see if the fabric is an F_PORT or and N_PORT */ 15562306a36Sopenharmony_ci if (!efc_rnode_is_nport(cbdata->els_rsp.virt)) { 15662306a36Sopenharmony_ci /* sm: if not nport / efc_domain_attach */ 15762306a36Sopenharmony_ci /* ext_status has the fc_id, attach domain */ 15862306a36Sopenharmony_ci efc_fabric_set_topology(node, EFC_NPORT_TOPO_FABRIC); 15962306a36Sopenharmony_ci efc_fabric_notify_topology(node); 16062306a36Sopenharmony_ci WARN_ON(node->nport->domain->attached); 16162306a36Sopenharmony_ci efc_domain_attach(node->nport->domain, 16262306a36Sopenharmony_ci cbdata->ext_status); 16362306a36Sopenharmony_ci efc_node_transition(node, 16462306a36Sopenharmony_ci __efc_fabric_wait_domain_attach, 16562306a36Sopenharmony_ci NULL); 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* sm: if nport and p2p_winner / efc_domain_attach */ 17062306a36Sopenharmony_ci efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P); 17162306a36Sopenharmony_ci if (efc_p2p_setup(node->nport)) { 17262306a36Sopenharmony_ci node_printf(node, 17362306a36Sopenharmony_ci "p2p setup failed, shutting down node\n"); 17462306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 17562306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (node->nport->p2p_winner) { 18062306a36Sopenharmony_ci efc_node_transition(node, 18162306a36Sopenharmony_ci __efc_p2p_wait_domain_attach, 18262306a36Sopenharmony_ci NULL); 18362306a36Sopenharmony_ci if (node->nport->domain->attached && 18462306a36Sopenharmony_ci !node->nport->domain->domain_notify_pend) { 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * already attached, 18762306a36Sopenharmony_ci * just send ATTACH_OK 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci node_printf(node, 19062306a36Sopenharmony_ci "p2p winner, domain already attached\n"); 19162306a36Sopenharmony_ci efc_node_post_event(node, 19262306a36Sopenharmony_ci EFC_EVT_DOMAIN_ATTACH_OK, 19362306a36Sopenharmony_ci NULL); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * peer is p2p winner; 19862306a36Sopenharmony_ci * PLOGI will be received on the 19962306a36Sopenharmony_ci * remote SID=1 node; 20062306a36Sopenharmony_ci * this node has served its purpose 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 20362306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci case EFC_EVT_ELS_REQ_ABORTED: 21062306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_RJT: 21162306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_FAIL: { 21262306a36Sopenharmony_ci struct efc_nport *nport = node->nport; 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * with these errors, we have no recovery, 21562306a36Sopenharmony_ci * so shutdown the nport, leave the link 21662306a36Sopenharmony_ci * up and the domain ready 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI, 21962306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 22062306a36Sopenharmony_ci return; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci node_printf(node, 22362306a36Sopenharmony_ci "FLOGI failed evt=%s, shutting down nport [%s]\n", 22462306a36Sopenharmony_ci efc_sm_event_name(evt), nport->display_name); 22562306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 22662306a36Sopenharmony_ci node->els_req_cnt--; 22762306a36Sopenharmony_ci efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci default: 23262306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_civoid 23762306a36Sopenharmony_ci__efc_vport_fabric_init(struct efc_sm_ctx *ctx, 23862306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct efc_node *node = ctx->app; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci node_sm_trace(); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci switch (evt) { 24762306a36Sopenharmony_ci case EFC_EVT_ENTER: 24862306a36Sopenharmony_ci /* sm: / send FDISC */ 24962306a36Sopenharmony_ci efc_send_fdisc(node); 25062306a36Sopenharmony_ci efc_node_transition(node, __efc_fabric_fdisc_wait_rsp, NULL); 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci default: 25462306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_civoid 25962306a36Sopenharmony_ci__efc_fabric_fdisc_wait_rsp(struct efc_sm_ctx *ctx, 26062306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 26362306a36Sopenharmony_ci struct efc_node *node = ctx->app; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci node_sm_trace(); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci switch (evt) { 27062306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: { 27162306a36Sopenharmony_ci /* fc_id is in ext_status */ 27262306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC, 27362306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 27462306a36Sopenharmony_ci return; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 27862306a36Sopenharmony_ci node->els_req_cnt--; 27962306a36Sopenharmony_ci /* sm: / efc_nport_attach */ 28062306a36Sopenharmony_ci efc_nport_attach(node->nport, cbdata->ext_status); 28162306a36Sopenharmony_ci efc_node_transition(node, __efc_fabric_wait_domain_attach, 28262306a36Sopenharmony_ci NULL); 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_RJT: 28762306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_FAIL: { 28862306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC, 28962306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 29062306a36Sopenharmony_ci return; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 29362306a36Sopenharmony_ci node->els_req_cnt--; 29462306a36Sopenharmony_ci efc_log_err(node->efc, "FDISC failed, shutting down nport\n"); 29562306a36Sopenharmony_ci /* sm: / shutdown nport */ 29662306a36Sopenharmony_ci efc_sm_post_event(&node->nport->sm, EFC_EVT_SHUTDOWN, NULL); 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci default: 30162306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int 30662306a36Sopenharmony_ciefc_start_ns_node(struct efc_nport *nport) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct efc_node *ns; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* Instantiate a name services node */ 31162306a36Sopenharmony_ci ns = efc_node_find(nport, FC_FID_DIR_SERV); 31262306a36Sopenharmony_ci if (!ns) { 31362306a36Sopenharmony_ci ns = efc_node_alloc(nport, FC_FID_DIR_SERV, false, false); 31462306a36Sopenharmony_ci if (!ns) 31562306a36Sopenharmony_ci return -EIO; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * for found ns, should we be transitioning from here? 31962306a36Sopenharmony_ci * breaks transition only 32062306a36Sopenharmony_ci * 1. from within state machine or 32162306a36Sopenharmony_ci * 2. if after alloc 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci if (ns->efc->nodedb_mask & EFC_NODEDB_PAUSE_NAMESERVER) 32462306a36Sopenharmony_ci efc_node_pause(ns, __efc_ns_init); 32562306a36Sopenharmony_ci else 32662306a36Sopenharmony_ci efc_node_transition(ns, __efc_ns_init, NULL); 32762306a36Sopenharmony_ci return 0; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic int 33162306a36Sopenharmony_ciefc_start_fabctl_node(struct efc_nport *nport) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct efc_node *fabctl; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci fabctl = efc_node_find(nport, FC_FID_FCTRL); 33662306a36Sopenharmony_ci if (!fabctl) { 33762306a36Sopenharmony_ci fabctl = efc_node_alloc(nport, FC_FID_FCTRL, 33862306a36Sopenharmony_ci false, false); 33962306a36Sopenharmony_ci if (!fabctl) 34062306a36Sopenharmony_ci return -EIO; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci /* 34362306a36Sopenharmony_ci * for found ns, should we be transitioning from here? 34462306a36Sopenharmony_ci * breaks transition only 34562306a36Sopenharmony_ci * 1. from within state machine or 34662306a36Sopenharmony_ci * 2. if after alloc 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci efc_node_transition(fabctl, __efc_fabctl_init, NULL); 34962306a36Sopenharmony_ci return 0; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_civoid 35362306a36Sopenharmony_ci__efc_fabric_wait_domain_attach(struct efc_sm_ctx *ctx, 35462306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct efc_node *node = ctx->app; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci node_sm_trace(); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci switch (evt) { 36362306a36Sopenharmony_ci case EFC_EVT_ENTER: 36462306a36Sopenharmony_ci efc_node_hold_frames(node); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci case EFC_EVT_EXIT: 36862306a36Sopenharmony_ci efc_node_accept_frames(node); 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci case EFC_EVT_DOMAIN_ATTACH_OK: 37162306a36Sopenharmony_ci case EFC_EVT_NPORT_ATTACH_OK: { 37262306a36Sopenharmony_ci int rc; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci rc = efc_start_ns_node(node->nport); 37562306a36Sopenharmony_ci if (rc) 37662306a36Sopenharmony_ci return; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* sm: if enable_ini / start fabctl node */ 37962306a36Sopenharmony_ci /* Instantiate the fabric controller (sends SCR) */ 38062306a36Sopenharmony_ci if (node->nport->enable_rscn) { 38162306a36Sopenharmony_ci rc = efc_start_fabctl_node(node->nport); 38262306a36Sopenharmony_ci if (rc) 38362306a36Sopenharmony_ci return; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci efc_node_transition(node, __efc_fabric_idle, NULL); 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci default: 38962306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_civoid 39462306a36Sopenharmony_ci__efc_fabric_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, 39562306a36Sopenharmony_ci void *arg) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct efc_node *node = ctx->app; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci node_sm_trace(); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci switch (evt) { 40462306a36Sopenharmony_ci case EFC_EVT_DOMAIN_ATTACH_OK: 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci default: 40762306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_civoid 41262306a36Sopenharmony_ci__efc_ns_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct efc_node *node = ctx->app; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci node_sm_trace(); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci switch (evt) { 42162306a36Sopenharmony_ci case EFC_EVT_ENTER: 42262306a36Sopenharmony_ci /* sm: / send PLOGI */ 42362306a36Sopenharmony_ci efc_send_plogi(node); 42462306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_plogi_wait_rsp, NULL); 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci default: 42762306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_civoid 43262306a36Sopenharmony_ci__efc_ns_plogi_wait_rsp(struct efc_sm_ctx *ctx, 43362306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 43662306a36Sopenharmony_ci struct efc_node *node = ctx->app; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci node_sm_trace(); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci switch (evt) { 44362306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: { 44462306a36Sopenharmony_ci int rc; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* Save service parameters */ 44762306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI, 44862306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 44962306a36Sopenharmony_ci return; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 45262306a36Sopenharmony_ci node->els_req_cnt--; 45362306a36Sopenharmony_ci /* sm: / save sparams, efc_node_attach */ 45462306a36Sopenharmony_ci efc_node_save_sparms(node, cbdata->els_rsp.virt); 45562306a36Sopenharmony_ci rc = efc_node_attach(node); 45662306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_wait_node_attach, NULL); 45762306a36Sopenharmony_ci if (rc < 0) 45862306a36Sopenharmony_ci efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, 45962306a36Sopenharmony_ci NULL); 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci default: 46362306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_civoid 46862306a36Sopenharmony_ci__efc_ns_wait_node_attach(struct efc_sm_ctx *ctx, 46962306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct efc_node *node = ctx->app; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci node_sm_trace(); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci switch (evt) { 47862306a36Sopenharmony_ci case EFC_EVT_ENTER: 47962306a36Sopenharmony_ci efc_node_hold_frames(node); 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci case EFC_EVT_EXIT: 48362306a36Sopenharmony_ci efc_node_accept_frames(node); 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci case EFC_EVT_NODE_ATTACH_OK: 48762306a36Sopenharmony_ci node->attached = true; 48862306a36Sopenharmony_ci /* sm: / send RFTID */ 48962306a36Sopenharmony_ci efc_ns_send_rftid(node); 49062306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_rftid_wait_rsp, NULL); 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci case EFC_EVT_NODE_ATTACH_FAIL: 49462306a36Sopenharmony_ci /* node attach failed, shutdown the node */ 49562306a36Sopenharmony_ci node->attached = false; 49662306a36Sopenharmony_ci node_printf(node, "Node attach failed\n"); 49762306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 49862306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci case EFC_EVT_SHUTDOWN: 50262306a36Sopenharmony_ci node_printf(node, "Shutdown event received\n"); 50362306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 50462306a36Sopenharmony_ci efc_node_transition(node, 50562306a36Sopenharmony_ci __efc_fabric_wait_attach_evt_shutdown, 50662306a36Sopenharmony_ci NULL); 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * if receive RSCN just ignore, 51162306a36Sopenharmony_ci * we haven't sent GID_PT yet (ACC sent by fabctl node) 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci case EFC_EVT_RSCN_RCVD: 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci default: 51762306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_civoid 52262306a36Sopenharmony_ci__efc_fabric_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx, 52362306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct efc_node *node = ctx->app; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci node_sm_trace(); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci switch (evt) { 53262306a36Sopenharmony_ci case EFC_EVT_ENTER: 53362306a36Sopenharmony_ci efc_node_hold_frames(node); 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci case EFC_EVT_EXIT: 53762306a36Sopenharmony_ci efc_node_accept_frames(node); 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* wait for any of these attach events and then shutdown */ 54162306a36Sopenharmony_ci case EFC_EVT_NODE_ATTACH_OK: 54262306a36Sopenharmony_ci node->attached = true; 54362306a36Sopenharmony_ci node_printf(node, "Attach evt=%s, proceed to shutdown\n", 54462306a36Sopenharmony_ci efc_sm_event_name(evt)); 54562306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci case EFC_EVT_NODE_ATTACH_FAIL: 54962306a36Sopenharmony_ci node->attached = false; 55062306a36Sopenharmony_ci node_printf(node, "Attach evt=%s, proceed to shutdown\n", 55162306a36Sopenharmony_ci efc_sm_event_name(evt)); 55262306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* ignore shutdown event as we're already in shutdown path */ 55662306a36Sopenharmony_ci case EFC_EVT_SHUTDOWN: 55762306a36Sopenharmony_ci node_printf(node, "Shutdown event received\n"); 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci default: 56162306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_civoid 56662306a36Sopenharmony_ci__efc_ns_rftid_wait_rsp(struct efc_sm_ctx *ctx, 56762306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct efc_node *node = ctx->app; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci node_sm_trace(); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci switch (evt) { 57662306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: 57762306a36Sopenharmony_ci if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFT_ID, 57862306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 58262306a36Sopenharmony_ci node->els_req_cnt--; 58362306a36Sopenharmony_ci /* sm: / send RFFID */ 58462306a36Sopenharmony_ci efc_ns_send_rffid(node); 58562306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_rffid_wait_rsp, NULL); 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * if receive RSCN just ignore, 59062306a36Sopenharmony_ci * we haven't sent GID_PT yet (ACC sent by fabctl node) 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci case EFC_EVT_RSCN_RCVD: 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci default: 59662306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_civoid 60162306a36Sopenharmony_ci__efc_ns_rffid_wait_rsp(struct efc_sm_ctx *ctx, 60262306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct efc_node *node = ctx->app; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci node_sm_trace(); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* 61162306a36Sopenharmony_ci * Waits for an RFFID response event; 61262306a36Sopenharmony_ci * if rscn enabled, a GIDPT name services request is issued. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_ci switch (evt) { 61562306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: { 61662306a36Sopenharmony_ci if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFF_ID, 61762306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 61862306a36Sopenharmony_ci return; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 62162306a36Sopenharmony_ci node->els_req_cnt--; 62262306a36Sopenharmony_ci if (node->nport->enable_rscn) { 62362306a36Sopenharmony_ci /* sm: if enable_rscn / send GIDPT */ 62462306a36Sopenharmony_ci efc_ns_send_gidpt(node); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_gidpt_wait_rsp, 62762306a36Sopenharmony_ci NULL); 62862306a36Sopenharmony_ci } else { 62962306a36Sopenharmony_ci /* if 'T' only, we're done, go to idle */ 63062306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_idle, NULL); 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci /* 63562306a36Sopenharmony_ci * if receive RSCN just ignore, 63662306a36Sopenharmony_ci * we haven't sent GID_PT yet (ACC sent by fabctl node) 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci case EFC_EVT_RSCN_RCVD: 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci default: 64262306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int 64762306a36Sopenharmony_ciefc_process_gidpt_payload(struct efc_node *node, 64862306a36Sopenharmony_ci void *data, u32 gidpt_len) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci u32 i, j; 65162306a36Sopenharmony_ci struct efc_node *newnode; 65262306a36Sopenharmony_ci struct efc_nport *nport = node->nport; 65362306a36Sopenharmony_ci struct efc *efc = node->efc; 65462306a36Sopenharmony_ci u32 port_id = 0, port_count, plist_count; 65562306a36Sopenharmony_ci struct efc_node *n; 65662306a36Sopenharmony_ci struct efc_node **active_nodes; 65762306a36Sopenharmony_ci int residual; 65862306a36Sopenharmony_ci struct { 65962306a36Sopenharmony_ci struct fc_ct_hdr hdr; 66062306a36Sopenharmony_ci struct fc_gid_pn_resp pn_rsp; 66162306a36Sopenharmony_ci } *rsp; 66262306a36Sopenharmony_ci struct fc_gid_pn_resp *gidpt; 66362306a36Sopenharmony_ci unsigned long index; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci rsp = data; 66662306a36Sopenharmony_ci gidpt = &rsp->pn_rsp; 66762306a36Sopenharmony_ci residual = be16_to_cpu(rsp->hdr.ct_mr_size); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (residual != 0) 67062306a36Sopenharmony_ci efc_log_debug(node->efc, "residual is %u words\n", residual); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (be16_to_cpu(rsp->hdr.ct_cmd) == FC_FS_RJT) { 67362306a36Sopenharmony_ci node_printf(node, 67462306a36Sopenharmony_ci "GIDPT request failed: rsn x%x rsn_expl x%x\n", 67562306a36Sopenharmony_ci rsp->hdr.ct_reason, rsp->hdr.ct_explan); 67662306a36Sopenharmony_ci return -EIO; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci plist_count = (gidpt_len - sizeof(struct fc_ct_hdr)) / sizeof(*gidpt); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* Count the number of nodes */ 68262306a36Sopenharmony_ci port_count = 0; 68362306a36Sopenharmony_ci xa_for_each(&nport->lookup, index, n) { 68462306a36Sopenharmony_ci port_count++; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci /* Allocate a buffer for all nodes */ 68862306a36Sopenharmony_ci active_nodes = kcalloc(port_count, sizeof(*active_nodes), GFP_ATOMIC); 68962306a36Sopenharmony_ci if (!active_nodes) { 69062306a36Sopenharmony_ci node_printf(node, "efc_malloc failed\n"); 69162306a36Sopenharmony_ci return -EIO; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* Fill buffer with fc_id of active nodes */ 69562306a36Sopenharmony_ci i = 0; 69662306a36Sopenharmony_ci xa_for_each(&nport->lookup, index, n) { 69762306a36Sopenharmony_ci port_id = n->rnode.fc_id; 69862306a36Sopenharmony_ci switch (port_id) { 69962306a36Sopenharmony_ci case FC_FID_FLOGI: 70062306a36Sopenharmony_ci case FC_FID_FCTRL: 70162306a36Sopenharmony_ci case FC_FID_DIR_SERV: 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci default: 70462306a36Sopenharmony_ci if (port_id != FC_FID_DOM_MGR) 70562306a36Sopenharmony_ci active_nodes[i++] = n; 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* update the active nodes buffer */ 71162306a36Sopenharmony_ci for (i = 0; i < plist_count; i++) { 71262306a36Sopenharmony_ci hton24(gidpt[i].fp_fid, port_id); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci for (j = 0; j < port_count; j++) { 71562306a36Sopenharmony_ci if (active_nodes[j] && 71662306a36Sopenharmony_ci port_id == active_nodes[j]->rnode.fc_id) { 71762306a36Sopenharmony_ci active_nodes[j] = NULL; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (gidpt[i].fp_resvd & FC_NS_FID_LAST) 72262306a36Sopenharmony_ci break; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Those remaining in the active_nodes[] are now gone ! */ 72662306a36Sopenharmony_ci for (i = 0; i < port_count; i++) { 72762306a36Sopenharmony_ci /* 72862306a36Sopenharmony_ci * if we're an initiator and the remote node 72962306a36Sopenharmony_ci * is a target, then post the node missing event. 73062306a36Sopenharmony_ci * if we're target and we have enabled 73162306a36Sopenharmony_ci * target RSCN, then post the node missing event. 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci if (!active_nodes[i]) 73462306a36Sopenharmony_ci continue; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if ((node->nport->enable_ini && active_nodes[i]->targ) || 73762306a36Sopenharmony_ci (node->nport->enable_tgt && enable_target_rscn(efc))) { 73862306a36Sopenharmony_ci efc_node_post_event(active_nodes[i], 73962306a36Sopenharmony_ci EFC_EVT_NODE_MISSING, NULL); 74062306a36Sopenharmony_ci } else { 74162306a36Sopenharmony_ci node_printf(node, 74262306a36Sopenharmony_ci "GID_PT: skipping non-tgt port_id x%06x\n", 74362306a36Sopenharmony_ci active_nodes[i]->rnode.fc_id); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci kfree(active_nodes); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci for (i = 0; i < plist_count; i++) { 74962306a36Sopenharmony_ci hton24(gidpt[i].fp_fid, port_id); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Don't create node for ourselves */ 75262306a36Sopenharmony_ci if (port_id == node->rnode.nport->fc_id) { 75362306a36Sopenharmony_ci if (gidpt[i].fp_resvd & FC_NS_FID_LAST) 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci continue; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci newnode = efc_node_find(nport, port_id); 75962306a36Sopenharmony_ci if (!newnode) { 76062306a36Sopenharmony_ci if (!node->nport->enable_ini) 76162306a36Sopenharmony_ci continue; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci newnode = efc_node_alloc(nport, port_id, false, false); 76462306a36Sopenharmony_ci if (!newnode) { 76562306a36Sopenharmony_ci efc_log_err(efc, "efc_node_alloc() failed\n"); 76662306a36Sopenharmony_ci return -EIO; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci /* 76962306a36Sopenharmony_ci * send PLOGI automatically 77062306a36Sopenharmony_ci * if initiator 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci efc_node_init_device(newnode, true); 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (node->nport->enable_ini && newnode->targ) { 77662306a36Sopenharmony_ci efc_node_post_event(newnode, EFC_EVT_NODE_REFOUND, 77762306a36Sopenharmony_ci NULL); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (gidpt[i].fp_resvd & FC_NS_FID_LAST) 78162306a36Sopenharmony_ci break; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_civoid 78762306a36Sopenharmony_ci__efc_ns_gidpt_wait_rsp(struct efc_sm_ctx *ctx, 78862306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 79162306a36Sopenharmony_ci struct efc_node *node = ctx->app; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci node_sm_trace(); 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * Wait for a GIDPT response from the name server. Process the FC_IDs 79862306a36Sopenharmony_ci * that are reported by creating new remote ports, as needed. 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci switch (evt) { 80262306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: { 80362306a36Sopenharmony_ci if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_GID_PT, 80462306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 80562306a36Sopenharmony_ci return; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 80862306a36Sopenharmony_ci node->els_req_cnt--; 80962306a36Sopenharmony_ci /* sm: / process GIDPT payload */ 81062306a36Sopenharmony_ci efc_process_gidpt_payload(node, cbdata->els_rsp.virt, 81162306a36Sopenharmony_ci cbdata->els_rsp.len); 81262306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_idle, NULL); 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_FAIL: { 81762306a36Sopenharmony_ci /* not much we can do; will retry with the next RSCN */ 81862306a36Sopenharmony_ci node_printf(node, "GID_PT failed to complete\n"); 81962306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 82062306a36Sopenharmony_ci node->els_req_cnt--; 82162306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_idle, NULL); 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* if receive RSCN here, queue up another discovery processing */ 82662306a36Sopenharmony_ci case EFC_EVT_RSCN_RCVD: { 82762306a36Sopenharmony_ci node_printf(node, "RSCN received during GID_PT processing\n"); 82862306a36Sopenharmony_ci node->rscn_pending = true; 82962306a36Sopenharmony_ci break; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci default: 83362306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_civoid 83862306a36Sopenharmony_ci__efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct efc_node *node = ctx->app; 84162306a36Sopenharmony_ci struct efc *efc = node->efc; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci node_sm_trace(); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* 84862306a36Sopenharmony_ci * Wait for RSCN received events (posted from the fabric controller) 84962306a36Sopenharmony_ci * and restart the GIDPT name services query and processing. 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci switch (evt) { 85362306a36Sopenharmony_ci case EFC_EVT_ENTER: 85462306a36Sopenharmony_ci if (!node->rscn_pending) 85562306a36Sopenharmony_ci break; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci node_printf(node, "RSCN pending, restart discovery\n"); 85862306a36Sopenharmony_ci node->rscn_pending = false; 85962306a36Sopenharmony_ci fallthrough; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci case EFC_EVT_RSCN_RCVD: { 86262306a36Sopenharmony_ci /* sm: / send GIDPT */ 86362306a36Sopenharmony_ci /* 86462306a36Sopenharmony_ci * If target RSCN processing is enabled, 86562306a36Sopenharmony_ci * and this is target only (not initiator), 86662306a36Sopenharmony_ci * and tgt_rscn_delay is non-zero, 86762306a36Sopenharmony_ci * then we delay issuing the GID_PT 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_ci if (efc->tgt_rscn_delay_msec != 0 && 87062306a36Sopenharmony_ci !node->nport->enable_ini && node->nport->enable_tgt && 87162306a36Sopenharmony_ci enable_target_rscn(efc)) { 87262306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_gidpt_delay, NULL); 87362306a36Sopenharmony_ci } else { 87462306a36Sopenharmony_ci efc_ns_send_gidpt(node); 87562306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_gidpt_wait_rsp, 87662306a36Sopenharmony_ci NULL); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci break; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci default: 88262306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic void 88762306a36Sopenharmony_cigidpt_delay_timer_cb(struct timer_list *t) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct efc_node *node = from_timer(node, t, gidpt_delay_timer); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci del_timer(&node->gidpt_delay_timer); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci efc_node_post_event(node, EFC_EVT_GIDPT_DELAY_EXPIRED, NULL); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_civoid 89762306a36Sopenharmony_ci__efc_ns_gidpt_delay(struct efc_sm_ctx *ctx, 89862306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct efc_node *node = ctx->app; 90162306a36Sopenharmony_ci struct efc *efc = node->efc; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci node_sm_trace(); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci switch (evt) { 90862306a36Sopenharmony_ci case EFC_EVT_ENTER: { 90962306a36Sopenharmony_ci u64 delay_msec, tmp; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* 91262306a36Sopenharmony_ci * Compute the delay time. 91362306a36Sopenharmony_ci * Set to tgt_rscn_delay, if the time since last GIDPT 91462306a36Sopenharmony_ci * is less than tgt_rscn_period, then use tgt_rscn_period. 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_ci delay_msec = efc->tgt_rscn_delay_msec; 91762306a36Sopenharmony_ci tmp = jiffies_to_msecs(jiffies) - node->time_last_gidpt_msec; 91862306a36Sopenharmony_ci if (tmp < efc->tgt_rscn_period_msec) 91962306a36Sopenharmony_ci delay_msec = efc->tgt_rscn_period_msec; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci timer_setup(&node->gidpt_delay_timer, &gidpt_delay_timer_cb, 92262306a36Sopenharmony_ci 0); 92362306a36Sopenharmony_ci mod_timer(&node->gidpt_delay_timer, 92462306a36Sopenharmony_ci jiffies + msecs_to_jiffies(delay_msec)); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci case EFC_EVT_GIDPT_DELAY_EXPIRED: 93062306a36Sopenharmony_ci node->time_last_gidpt_msec = jiffies_to_msecs(jiffies); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci efc_ns_send_gidpt(node); 93362306a36Sopenharmony_ci efc_node_transition(node, __efc_ns_gidpt_wait_rsp, NULL); 93462306a36Sopenharmony_ci break; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci case EFC_EVT_RSCN_RCVD: { 93762306a36Sopenharmony_ci efc_log_debug(efc, 93862306a36Sopenharmony_ci "RSCN received while in GIDPT delay - no action\n"); 93962306a36Sopenharmony_ci break; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci default: 94362306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_civoid 94862306a36Sopenharmony_ci__efc_fabctl_init(struct efc_sm_ctx *ctx, 94962306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct efc_node *node = ctx->app; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci node_sm_trace(); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci switch (evt) { 95662306a36Sopenharmony_ci case EFC_EVT_ENTER: 95762306a36Sopenharmony_ci /* no need to login to fabric controller, just send SCR */ 95862306a36Sopenharmony_ci efc_send_scr(node); 95962306a36Sopenharmony_ci efc_node_transition(node, __efc_fabctl_wait_scr_rsp, NULL); 96062306a36Sopenharmony_ci break; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci case EFC_EVT_NODE_ATTACH_OK: 96362306a36Sopenharmony_ci node->attached = true; 96462306a36Sopenharmony_ci break; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci default: 96762306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_civoid 97262306a36Sopenharmony_ci__efc_fabctl_wait_scr_rsp(struct efc_sm_ctx *ctx, 97362306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct efc_node *node = ctx->app; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci node_sm_trace(); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* 98262306a36Sopenharmony_ci * Fabric controller node state machine: 98362306a36Sopenharmony_ci * Wait for an SCR response from the fabric controller. 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci switch (evt) { 98662306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: 98762306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_SCR, 98862306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 98962306a36Sopenharmony_ci return; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 99262306a36Sopenharmony_ci node->els_req_cnt--; 99362306a36Sopenharmony_ci efc_node_transition(node, __efc_fabctl_ready, NULL); 99462306a36Sopenharmony_ci break; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci default: 99762306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic void 100262306a36Sopenharmony_ciefc_process_rscn(struct efc_node *node, struct efc_node_cb *cbdata) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct efc *efc = node->efc; 100562306a36Sopenharmony_ci struct efc_nport *nport = node->nport; 100662306a36Sopenharmony_ci struct efc_node *ns; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* Forward this event to the name-services node */ 100962306a36Sopenharmony_ci ns = efc_node_find(nport, FC_FID_DIR_SERV); 101062306a36Sopenharmony_ci if (ns) 101162306a36Sopenharmony_ci efc_node_post_event(ns, EFC_EVT_RSCN_RCVD, cbdata); 101262306a36Sopenharmony_ci else 101362306a36Sopenharmony_ci efc_log_warn(efc, "can't find name server node\n"); 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_civoid 101762306a36Sopenharmony_ci__efc_fabctl_ready(struct efc_sm_ctx *ctx, 101862306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 102162306a36Sopenharmony_ci struct efc_node *node = ctx->app; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci node_sm_trace(); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* 102862306a36Sopenharmony_ci * Fabric controller node state machine: Ready. 102962306a36Sopenharmony_ci * In this state, the fabric controller sends a RSCN, which is received 103062306a36Sopenharmony_ci * by this node and is forwarded to the name services node object; and 103162306a36Sopenharmony_ci * the RSCN LS_ACC is sent. 103262306a36Sopenharmony_ci */ 103362306a36Sopenharmony_ci switch (evt) { 103462306a36Sopenharmony_ci case EFC_EVT_RSCN_RCVD: { 103562306a36Sopenharmony_ci struct fc_frame_header *hdr = cbdata->header->dma.virt; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* 103862306a36Sopenharmony_ci * sm: / process RSCN (forward to name services node), 103962306a36Sopenharmony_ci * send LS_ACC 104062306a36Sopenharmony_ci */ 104162306a36Sopenharmony_ci efc_process_rscn(node, cbdata); 104262306a36Sopenharmony_ci efc_send_ls_acc(node, be16_to_cpu(hdr->fh_ox_id)); 104362306a36Sopenharmony_ci efc_node_transition(node, __efc_fabctl_wait_ls_acc_cmpl, 104462306a36Sopenharmony_ci NULL); 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci default: 104962306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_civoid 105462306a36Sopenharmony_ci__efc_fabctl_wait_ls_acc_cmpl(struct efc_sm_ctx *ctx, 105562306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct efc_node *node = ctx->app; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci node_sm_trace(); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci switch (evt) { 106462306a36Sopenharmony_ci case EFC_EVT_ENTER: 106562306a36Sopenharmony_ci efc_node_hold_frames(node); 106662306a36Sopenharmony_ci break; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci case EFC_EVT_EXIT: 106962306a36Sopenharmony_ci efc_node_accept_frames(node); 107062306a36Sopenharmony_ci break; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_CMPL_OK: 107362306a36Sopenharmony_ci WARN_ON(!node->els_cmpl_cnt); 107462306a36Sopenharmony_ci node->els_cmpl_cnt--; 107562306a36Sopenharmony_ci efc_node_transition(node, __efc_fabctl_ready, NULL); 107662306a36Sopenharmony_ci break; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci default: 107962306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic uint64_t 108462306a36Sopenharmony_ciefc_get_wwpn(struct fc_els_flogi *sp) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci return be64_to_cpu(sp->fl_wwnn); 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cistatic int 109062306a36Sopenharmony_ciefc_rnode_is_winner(struct efc_nport *nport) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci struct fc_els_flogi *remote_sp; 109362306a36Sopenharmony_ci u64 remote_wwpn; 109462306a36Sopenharmony_ci u64 local_wwpn = nport->wwpn; 109562306a36Sopenharmony_ci u64 wwn_bump = 0; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci remote_sp = (struct fc_els_flogi *)nport->domain->flogi_service_params; 109862306a36Sopenharmony_ci remote_wwpn = efc_get_wwpn(remote_sp); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci local_wwpn ^= wwn_bump; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci efc_log_debug(nport->efc, "r: %llx\n", 110362306a36Sopenharmony_ci be64_to_cpu(remote_sp->fl_wwpn)); 110462306a36Sopenharmony_ci efc_log_debug(nport->efc, "l: %llx\n", local_wwpn); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (remote_wwpn == local_wwpn) { 110762306a36Sopenharmony_ci efc_log_warn(nport->efc, 110862306a36Sopenharmony_ci "WWPN of remote node [%08x %08x] matches local WWPN\n", 110962306a36Sopenharmony_ci (u32)(local_wwpn >> 32ll), 111062306a36Sopenharmony_ci (u32)local_wwpn); 111162306a36Sopenharmony_ci return -1; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci return (remote_wwpn > local_wwpn); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_civoid 111862306a36Sopenharmony_ci__efc_p2p_wait_domain_attach(struct efc_sm_ctx *ctx, 111962306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci struct efc_node *node = ctx->app; 112262306a36Sopenharmony_ci struct efc *efc = node->efc; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci node_sm_trace(); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci switch (evt) { 112962306a36Sopenharmony_ci case EFC_EVT_ENTER: 113062306a36Sopenharmony_ci efc_node_hold_frames(node); 113162306a36Sopenharmony_ci break; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci case EFC_EVT_EXIT: 113462306a36Sopenharmony_ci efc_node_accept_frames(node); 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci case EFC_EVT_DOMAIN_ATTACH_OK: { 113862306a36Sopenharmony_ci struct efc_nport *nport = node->nport; 113962306a36Sopenharmony_ci struct efc_node *rnode; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* 114262306a36Sopenharmony_ci * this transient node (SID=0 (recv'd FLOGI) 114362306a36Sopenharmony_ci * or DID=fabric (sent FLOGI)) 114462306a36Sopenharmony_ci * is the p2p winner, will use a separate node 114562306a36Sopenharmony_ci * to send PLOGI to peer 114662306a36Sopenharmony_ci */ 114762306a36Sopenharmony_ci WARN_ON(!node->nport->p2p_winner); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci rnode = efc_node_find(nport, node->nport->p2p_remote_port_id); 115062306a36Sopenharmony_ci if (rnode) { 115162306a36Sopenharmony_ci /* 115262306a36Sopenharmony_ci * the "other" transient p2p node has 115362306a36Sopenharmony_ci * already kicked off the 115462306a36Sopenharmony_ci * new node from which PLOGI is sent 115562306a36Sopenharmony_ci */ 115662306a36Sopenharmony_ci node_printf(node, 115762306a36Sopenharmony_ci "Node with fc_id x%x already exists\n", 115862306a36Sopenharmony_ci rnode->rnode.fc_id); 115962306a36Sopenharmony_ci } else { 116062306a36Sopenharmony_ci /* 116162306a36Sopenharmony_ci * create new node (SID=1, DID=2) 116262306a36Sopenharmony_ci * from which to send PLOGI 116362306a36Sopenharmony_ci */ 116462306a36Sopenharmony_ci rnode = efc_node_alloc(nport, 116562306a36Sopenharmony_ci nport->p2p_remote_port_id, 116662306a36Sopenharmony_ci false, false); 116762306a36Sopenharmony_ci if (!rnode) { 116862306a36Sopenharmony_ci efc_log_err(efc, "node alloc failed\n"); 116962306a36Sopenharmony_ci return; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci efc_fabric_notify_topology(node); 117362306a36Sopenharmony_ci /* sm: / allocate p2p remote node */ 117462306a36Sopenharmony_ci efc_node_transition(rnode, __efc_p2p_rnode_init, 117562306a36Sopenharmony_ci NULL); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* 117962306a36Sopenharmony_ci * the transient node (SID=0 or DID=fabric) 118062306a36Sopenharmony_ci * has served its purpose 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci if (node->rnode.fc_id == 0) { 118362306a36Sopenharmony_ci /* 118462306a36Sopenharmony_ci * if this is the SID=0 node, 118562306a36Sopenharmony_ci * move to the init state in case peer 118662306a36Sopenharmony_ci * has restarted FLOGI discovery and FLOGI is pending 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_ci /* don't send PLOGI on efc_d_init entry */ 118962306a36Sopenharmony_ci efc_node_init_device(node, false); 119062306a36Sopenharmony_ci } else { 119162306a36Sopenharmony_ci /* 119262306a36Sopenharmony_ci * if this is the DID=fabric node 119362306a36Sopenharmony_ci * (we initiated FLOGI), shut it down 119462306a36Sopenharmony_ci */ 119562306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 119662306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci break; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci default: 120262306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_civoid 120762306a36Sopenharmony_ci__efc_p2p_rnode_init(struct efc_sm_ctx *ctx, 120862306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 121162306a36Sopenharmony_ci struct efc_node *node = ctx->app; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci node_sm_trace(); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci switch (evt) { 121862306a36Sopenharmony_ci case EFC_EVT_ENTER: 121962306a36Sopenharmony_ci /* sm: / send PLOGI */ 122062306a36Sopenharmony_ci efc_send_plogi(node); 122162306a36Sopenharmony_ci efc_node_transition(node, __efc_p2p_wait_plogi_rsp, NULL); 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci case EFC_EVT_ABTS_RCVD: 122562306a36Sopenharmony_ci /* sm: send BA_ACC */ 122662306a36Sopenharmony_ci efc_send_bls_acc(node, cbdata->header->dma.virt); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci break; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci default: 123162306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_civoid 123662306a36Sopenharmony_ci__efc_p2p_wait_flogi_acc_cmpl(struct efc_sm_ctx *ctx, 123762306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 124062306a36Sopenharmony_ci struct efc_node *node = ctx->app; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci node_sm_trace(); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci switch (evt) { 124762306a36Sopenharmony_ci case EFC_EVT_ENTER: 124862306a36Sopenharmony_ci efc_node_hold_frames(node); 124962306a36Sopenharmony_ci break; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci case EFC_EVT_EXIT: 125262306a36Sopenharmony_ci efc_node_accept_frames(node); 125362306a36Sopenharmony_ci break; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_CMPL_OK: 125662306a36Sopenharmony_ci WARN_ON(!node->els_cmpl_cnt); 125762306a36Sopenharmony_ci node->els_cmpl_cnt--; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* sm: if p2p_winner / domain_attach */ 126062306a36Sopenharmony_ci if (node->nport->p2p_winner) { 126162306a36Sopenharmony_ci efc_node_transition(node, 126262306a36Sopenharmony_ci __efc_p2p_wait_domain_attach, 126362306a36Sopenharmony_ci NULL); 126462306a36Sopenharmony_ci if (!node->nport->domain->attached) { 126562306a36Sopenharmony_ci node_printf(node, "Domain not attached\n"); 126662306a36Sopenharmony_ci efc_domain_attach(node->nport->domain, 126762306a36Sopenharmony_ci node->nport->p2p_port_id); 126862306a36Sopenharmony_ci } else { 126962306a36Sopenharmony_ci node_printf(node, "Domain already attached\n"); 127062306a36Sopenharmony_ci efc_node_post_event(node, 127162306a36Sopenharmony_ci EFC_EVT_DOMAIN_ATTACH_OK, 127262306a36Sopenharmony_ci NULL); 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci } else { 127562306a36Sopenharmony_ci /* this node has served its purpose; 127662306a36Sopenharmony_ci * we'll expect a PLOGI on a separate 127762306a36Sopenharmony_ci * node (remote SID=0x1); return this node 127862306a36Sopenharmony_ci * to init state in case peer 127962306a36Sopenharmony_ci * restarts discovery -- it may already 128062306a36Sopenharmony_ci * have (pending frames may exist). 128162306a36Sopenharmony_ci */ 128262306a36Sopenharmony_ci /* don't send PLOGI on efc_d_init entry */ 128362306a36Sopenharmony_ci efc_node_init_device(node, false); 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci break; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_CMPL_FAIL: 128862306a36Sopenharmony_ci /* 128962306a36Sopenharmony_ci * LS_ACC failed, possibly due to link down; 129062306a36Sopenharmony_ci * shutdown node and wait 129162306a36Sopenharmony_ci * for FLOGI discovery to restart 129262306a36Sopenharmony_ci */ 129362306a36Sopenharmony_ci node_printf(node, "FLOGI LS_ACC failed, shutting down\n"); 129462306a36Sopenharmony_ci WARN_ON(!node->els_cmpl_cnt); 129562306a36Sopenharmony_ci node->els_cmpl_cnt--; 129662306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 129762306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 129862306a36Sopenharmony_ci break; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci case EFC_EVT_ABTS_RCVD: { 130162306a36Sopenharmony_ci /* sm: / send BA_ACC */ 130262306a36Sopenharmony_ci efc_send_bls_acc(node, cbdata->header->dma.virt); 130362306a36Sopenharmony_ci break; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci default: 130762306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_civoid 131262306a36Sopenharmony_ci__efc_p2p_wait_plogi_rsp(struct efc_sm_ctx *ctx, 131362306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 131662306a36Sopenharmony_ci struct efc_node *node = ctx->app; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci node_sm_trace(); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci switch (evt) { 132362306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: { 132462306a36Sopenharmony_ci int rc; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI, 132762306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 132862306a36Sopenharmony_ci return; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 133162306a36Sopenharmony_ci node->els_req_cnt--; 133262306a36Sopenharmony_ci /* sm: / save sparams, efc_node_attach */ 133362306a36Sopenharmony_ci efc_node_save_sparms(node, cbdata->els_rsp.virt); 133462306a36Sopenharmony_ci rc = efc_node_attach(node); 133562306a36Sopenharmony_ci efc_node_transition(node, __efc_p2p_wait_node_attach, NULL); 133662306a36Sopenharmony_ci if (rc < 0) 133762306a36Sopenharmony_ci efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, 133862306a36Sopenharmony_ci NULL); 133962306a36Sopenharmony_ci break; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_FAIL: { 134262306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI, 134362306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 134462306a36Sopenharmony_ci return; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci node_printf(node, "PLOGI failed, shutting down\n"); 134762306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 134862306a36Sopenharmony_ci node->els_req_cnt--; 134962306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 135062306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 135162306a36Sopenharmony_ci break; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci case EFC_EVT_PLOGI_RCVD: { 135562306a36Sopenharmony_ci struct fc_frame_header *hdr = cbdata->header->dma.virt; 135662306a36Sopenharmony_ci /* if we're in external loopback mode, just send LS_ACC */ 135762306a36Sopenharmony_ci if (node->efc->external_loopback) { 135862306a36Sopenharmony_ci efc_send_plogi_acc(node, be16_to_cpu(hdr->fh_ox_id)); 135962306a36Sopenharmony_ci } else { 136062306a36Sopenharmony_ci /* 136162306a36Sopenharmony_ci * if this isn't external loopback, 136262306a36Sopenharmony_ci * pass to default handler 136362306a36Sopenharmony_ci */ 136462306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci break; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci case EFC_EVT_PRLI_RCVD: 136962306a36Sopenharmony_ci /* I, or I+T */ 137062306a36Sopenharmony_ci /* sent PLOGI and before completion was seen, received the 137162306a36Sopenharmony_ci * PRLI from the remote node (WCQEs and RCQEs come in on 137262306a36Sopenharmony_ci * different queues and order of processing cannot be assumed) 137362306a36Sopenharmony_ci * Save OXID so PRLI can be sent after the attach and continue 137462306a36Sopenharmony_ci * to wait for PLOGI response 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ci efc_process_prli_payload(node, cbdata->payload->dma.virt); 137762306a36Sopenharmony_ci efc_send_ls_acc_after_attach(node, 137862306a36Sopenharmony_ci cbdata->header->dma.virt, 137962306a36Sopenharmony_ci EFC_NODE_SEND_LS_ACC_PRLI); 138062306a36Sopenharmony_ci efc_node_transition(node, __efc_p2p_wait_plogi_rsp_recvd_prli, 138162306a36Sopenharmony_ci NULL); 138262306a36Sopenharmony_ci break; 138362306a36Sopenharmony_ci default: 138462306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_civoid 138962306a36Sopenharmony_ci__efc_p2p_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx, 139062306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 139162306a36Sopenharmony_ci{ 139262306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 139362306a36Sopenharmony_ci struct efc_node *node = ctx->app; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci node_sm_trace(); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci switch (evt) { 140062306a36Sopenharmony_ci case EFC_EVT_ENTER: 140162306a36Sopenharmony_ci /* 140262306a36Sopenharmony_ci * Since we've received a PRLI, we have a port login and will 140362306a36Sopenharmony_ci * just need to wait for the PLOGI response to do the node 140462306a36Sopenharmony_ci * attach and then we can send the LS_ACC for the PRLI. If, 140562306a36Sopenharmony_ci * during this time, we receive FCP_CMNDs (which is possible 140662306a36Sopenharmony_ci * since we've already sent a PRLI and our peer may have 140762306a36Sopenharmony_ci * accepted). 140862306a36Sopenharmony_ci * At this time, we are not waiting on any other unsolicited 140962306a36Sopenharmony_ci * frames to continue with the login process. Thus, it will not 141062306a36Sopenharmony_ci * hurt to hold frames here. 141162306a36Sopenharmony_ci */ 141262306a36Sopenharmony_ci efc_node_hold_frames(node); 141362306a36Sopenharmony_ci break; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci case EFC_EVT_EXIT: 141662306a36Sopenharmony_ci efc_node_accept_frames(node); 141762306a36Sopenharmony_ci break; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_OK: { /* PLOGI response received */ 142062306a36Sopenharmony_ci int rc; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci /* Completion from PLOGI sent */ 142362306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI, 142462306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 142562306a36Sopenharmony_ci return; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 142862306a36Sopenharmony_ci node->els_req_cnt--; 142962306a36Sopenharmony_ci /* sm: / save sparams, efc_node_attach */ 143062306a36Sopenharmony_ci efc_node_save_sparms(node, cbdata->els_rsp.virt); 143162306a36Sopenharmony_ci rc = efc_node_attach(node); 143262306a36Sopenharmony_ci efc_node_transition(node, __efc_p2p_wait_node_attach, NULL); 143362306a36Sopenharmony_ci if (rc < 0) 143462306a36Sopenharmony_ci efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, 143562306a36Sopenharmony_ci NULL); 143662306a36Sopenharmony_ci break; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */ 143962306a36Sopenharmony_ci case EFC_EVT_SRRS_ELS_REQ_RJT: 144062306a36Sopenharmony_ci /* PLOGI failed, shutdown the node */ 144162306a36Sopenharmony_ci if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI, 144262306a36Sopenharmony_ci __efc_fabric_common, __func__)) { 144362306a36Sopenharmony_ci return; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci WARN_ON(!node->els_req_cnt); 144662306a36Sopenharmony_ci node->els_req_cnt--; 144762306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 144862306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 144962306a36Sopenharmony_ci break; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci default: 145262306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_civoid 145762306a36Sopenharmony_ci__efc_p2p_wait_node_attach(struct efc_sm_ctx *ctx, 145862306a36Sopenharmony_ci enum efc_sm_event evt, void *arg) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci struct efc_node_cb *cbdata = arg; 146162306a36Sopenharmony_ci struct efc_node *node = ctx->app; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci efc_node_evt_set(ctx, evt, __func__); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci node_sm_trace(); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci switch (evt) { 146862306a36Sopenharmony_ci case EFC_EVT_ENTER: 146962306a36Sopenharmony_ci efc_node_hold_frames(node); 147062306a36Sopenharmony_ci break; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci case EFC_EVT_EXIT: 147362306a36Sopenharmony_ci efc_node_accept_frames(node); 147462306a36Sopenharmony_ci break; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci case EFC_EVT_NODE_ATTACH_OK: 147762306a36Sopenharmony_ci node->attached = true; 147862306a36Sopenharmony_ci switch (node->send_ls_acc) { 147962306a36Sopenharmony_ci case EFC_NODE_SEND_LS_ACC_PRLI: { 148062306a36Sopenharmony_ci efc_d_send_prli_rsp(node->ls_acc_io, 148162306a36Sopenharmony_ci node->ls_acc_oxid); 148262306a36Sopenharmony_ci node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE; 148362306a36Sopenharmony_ci node->ls_acc_io = NULL; 148462306a36Sopenharmony_ci break; 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci case EFC_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */ 148762306a36Sopenharmony_ci case EFC_NODE_SEND_LS_ACC_NONE: 148862306a36Sopenharmony_ci default: 148962306a36Sopenharmony_ci /* Normal case for I */ 149062306a36Sopenharmony_ci /* sm: send_plogi_acc is not set / send PLOGI acc */ 149162306a36Sopenharmony_ci efc_node_transition(node, __efc_d_port_logged_in, 149262306a36Sopenharmony_ci NULL); 149362306a36Sopenharmony_ci break; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci break; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci case EFC_EVT_NODE_ATTACH_FAIL: 149862306a36Sopenharmony_ci /* node attach failed, shutdown the node */ 149962306a36Sopenharmony_ci node->attached = false; 150062306a36Sopenharmony_ci node_printf(node, "Node attach failed\n"); 150162306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 150262306a36Sopenharmony_ci efc_fabric_initiate_shutdown(node); 150362306a36Sopenharmony_ci break; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci case EFC_EVT_SHUTDOWN: 150662306a36Sopenharmony_ci node_printf(node, "%s received\n", efc_sm_event_name(evt)); 150762306a36Sopenharmony_ci node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT; 150862306a36Sopenharmony_ci efc_node_transition(node, 150962306a36Sopenharmony_ci __efc_fabric_wait_attach_evt_shutdown, 151062306a36Sopenharmony_ci NULL); 151162306a36Sopenharmony_ci break; 151262306a36Sopenharmony_ci case EFC_EVT_PRLI_RCVD: 151362306a36Sopenharmony_ci node_printf(node, "%s: PRLI received before node is attached\n", 151462306a36Sopenharmony_ci efc_sm_event_name(evt)); 151562306a36Sopenharmony_ci efc_process_prli_payload(node, cbdata->payload->dma.virt); 151662306a36Sopenharmony_ci efc_send_ls_acc_after_attach(node, 151762306a36Sopenharmony_ci cbdata->header->dma.virt, 151862306a36Sopenharmony_ci EFC_NODE_SEND_LS_ACC_PRLI); 151962306a36Sopenharmony_ci break; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci default: 152262306a36Sopenharmony_ci __efc_fabric_common(__func__, ctx, evt, arg); 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ciint 152762306a36Sopenharmony_ciefc_p2p_setup(struct efc_nport *nport) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci struct efc *efc = nport->efc; 153062306a36Sopenharmony_ci int rnode_winner; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci rnode_winner = efc_rnode_is_winner(nport); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* set nport flags to indicate p2p "winner" */ 153562306a36Sopenharmony_ci if (rnode_winner == 1) { 153662306a36Sopenharmony_ci nport->p2p_remote_port_id = 0; 153762306a36Sopenharmony_ci nport->p2p_port_id = 0; 153862306a36Sopenharmony_ci nport->p2p_winner = false; 153962306a36Sopenharmony_ci } else if (rnode_winner == 0) { 154062306a36Sopenharmony_ci nport->p2p_remote_port_id = 2; 154162306a36Sopenharmony_ci nport->p2p_port_id = 1; 154262306a36Sopenharmony_ci nport->p2p_winner = true; 154362306a36Sopenharmony_ci } else { 154462306a36Sopenharmony_ci /* no winner; only okay if external loopback enabled */ 154562306a36Sopenharmony_ci if (nport->efc->external_loopback) { 154662306a36Sopenharmony_ci /* 154762306a36Sopenharmony_ci * External loopback mode enabled; 154862306a36Sopenharmony_ci * local nport and remote node 154962306a36Sopenharmony_ci * will be registered with an NPortID = 1; 155062306a36Sopenharmony_ci */ 155162306a36Sopenharmony_ci efc_log_debug(efc, 155262306a36Sopenharmony_ci "External loopback mode enabled\n"); 155362306a36Sopenharmony_ci nport->p2p_remote_port_id = 1; 155462306a36Sopenharmony_ci nport->p2p_port_id = 1; 155562306a36Sopenharmony_ci nport->p2p_winner = true; 155662306a36Sopenharmony_ci } else { 155762306a36Sopenharmony_ci efc_log_warn(efc, 155862306a36Sopenharmony_ci "failed to determine p2p winner\n"); 155962306a36Sopenharmony_ci return rnode_winner; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci return 0; 156362306a36Sopenharmony_ci} 1564