123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
- * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
- */
- /*
- * This file implements remote node state machines for:
- * - Fabric logins.
- * - Fabric controller events.
- * - Name/directory services interaction.
- * - Point-to-point logins.
- */
- /*
- * fabric_sm Node State Machine: Fabric States
- * ns_sm Node State Machine: Name/Directory Services States
- * p2p_sm Node State Machine: Point-to-Point Node States
- */
- #include "efc.h"
- static void
- efc_fabric_initiate_shutdown(struct efc_node *node)
- {
- struct efc *efc = node->efc;
- node->els_io_enabled = false;
- if (node->attached) {
- int rc;
- /* issue hw node free; don't care if succeeds right away
- * or sometime later, will check node->attached later in
- * shutdown process
- */
- rc = efc_cmd_node_detach(efc, &node->rnode);
- if (rc < 0) {
- node_printf(node, "Failed freeing HW node, rc=%d\n",
- rc);
- }
- }
- /*
- * node has either been detached or is in the process of being detached,
- * call common node's initiate cleanup function
- */
- efc_node_initiate_cleanup(node);
- }
- static void
- __efc_fabric_common(const char *funcname, struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = NULL;
- node = ctx->app;
- switch (evt) {
- case EFC_EVT_DOMAIN_ATTACH_OK:
- break;
- case EFC_EVT_SHUTDOWN:
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- break;
- default:
- /* call default event handler common to all nodes */
- __efc_node_common(funcname, ctx, evt, arg);
- }
- }
- void
- __efc_fabric_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
- void *arg)
- {
- struct efc_node *node = ctx->app;
- struct efc *efc = node->efc;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_REENTER:
- efc_log_debug(efc, ">>> reenter !!\n");
- fallthrough;
- case EFC_EVT_ENTER:
- /* send FLOGI */
- efc_send_flogi(node);
- efc_node_transition(node, __efc_fabric_flogi_wait_rsp, NULL);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- efc_fabric_set_topology(struct efc_node *node,
- enum efc_nport_topology topology)
- {
- node->nport->topology = topology;
- }
- void
- efc_fabric_notify_topology(struct efc_node *node)
- {
- struct efc_node *tmp_node;
- unsigned long index;
- /*
- * now loop through the nodes in the nport
- * and send topology notification
- */
- xa_for_each(&node->nport->lookup, index, tmp_node) {
- if (tmp_node != node) {
- efc_node_post_event(tmp_node,
- EFC_EVT_NPORT_TOPOLOGY_NOTIFY,
- &node->nport->topology);
- }
- }
- }
- static bool efc_rnode_is_nport(struct fc_els_flogi *rsp)
- {
- return !(ntohs(rsp->fl_csp.sp_features) & FC_SP_FT_FPORT);
- }
- void
- __efc_fabric_flogi_wait_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK: {
- if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- memcpy(node->nport->domain->flogi_service_params,
- cbdata->els_rsp.virt,
- sizeof(struct fc_els_flogi));
- /* Check to see if the fabric is an F_PORT or and N_PORT */
- if (!efc_rnode_is_nport(cbdata->els_rsp.virt)) {
- /* sm: if not nport / efc_domain_attach */
- /* ext_status has the fc_id, attach domain */
- efc_fabric_set_topology(node, EFC_NPORT_TOPO_FABRIC);
- efc_fabric_notify_topology(node);
- WARN_ON(node->nport->domain->attached);
- efc_domain_attach(node->nport->domain,
- cbdata->ext_status);
- efc_node_transition(node,
- __efc_fabric_wait_domain_attach,
- NULL);
- break;
- }
- /* sm: if nport and p2p_winner / efc_domain_attach */
- efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P);
- if (efc_p2p_setup(node->nport)) {
- node_printf(node,
- "p2p setup failed, shutting down node\n");
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- break;
- }
- if (node->nport->p2p_winner) {
- efc_node_transition(node,
- __efc_p2p_wait_domain_attach,
- NULL);
- if (node->nport->domain->attached &&
- !node->nport->domain->domain_notify_pend) {
- /*
- * already attached,
- * just send ATTACH_OK
- */
- node_printf(node,
- "p2p winner, domain already attached\n");
- efc_node_post_event(node,
- EFC_EVT_DOMAIN_ATTACH_OK,
- NULL);
- }
- } else {
- /*
- * peer is p2p winner;
- * PLOGI will be received on the
- * remote SID=1 node;
- * this node has served its purpose
- */
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- }
- break;
- }
- case EFC_EVT_ELS_REQ_ABORTED:
- case EFC_EVT_SRRS_ELS_REQ_RJT:
- case EFC_EVT_SRRS_ELS_REQ_FAIL: {
- struct efc_nport *nport = node->nport;
- /*
- * with these errors, we have no recovery,
- * so shutdown the nport, leave the link
- * up and the domain ready
- */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,
- __efc_fabric_common, __func__)) {
- return;
- }
- node_printf(node,
- "FLOGI failed evt=%s, shutting down nport [%s]\n",
- efc_sm_event_name(evt), nport->display_name);
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL);
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_vport_fabric_init(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- /* sm: / send FDISC */
- efc_send_fdisc(node);
- efc_node_transition(node, __efc_fabric_fdisc_wait_rsp, NULL);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_fabric_fdisc_wait_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK: {
- /* fc_id is in ext_status */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / efc_nport_attach */
- efc_nport_attach(node->nport, cbdata->ext_status);
- efc_node_transition(node, __efc_fabric_wait_domain_attach,
- NULL);
- break;
- }
- case EFC_EVT_SRRS_ELS_REQ_RJT:
- case EFC_EVT_SRRS_ELS_REQ_FAIL: {
- if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_log_err(node->efc, "FDISC failed, shutting down nport\n");
- /* sm: / shutdown nport */
- efc_sm_post_event(&node->nport->sm, EFC_EVT_SHUTDOWN, NULL);
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- static int
- efc_start_ns_node(struct efc_nport *nport)
- {
- struct efc_node *ns;
- /* Instantiate a name services node */
- ns = efc_node_find(nport, FC_FID_DIR_SERV);
- if (!ns) {
- ns = efc_node_alloc(nport, FC_FID_DIR_SERV, false, false);
- if (!ns)
- return -EIO;
- }
- /*
- * for found ns, should we be transitioning from here?
- * breaks transition only
- * 1. from within state machine or
- * 2. if after alloc
- */
- if (ns->efc->nodedb_mask & EFC_NODEDB_PAUSE_NAMESERVER)
- efc_node_pause(ns, __efc_ns_init);
- else
- efc_node_transition(ns, __efc_ns_init, NULL);
- return 0;
- }
- static int
- efc_start_fabctl_node(struct efc_nport *nport)
- {
- struct efc_node *fabctl;
- fabctl = efc_node_find(nport, FC_FID_FCTRL);
- if (!fabctl) {
- fabctl = efc_node_alloc(nport, FC_FID_FCTRL,
- false, false);
- if (!fabctl)
- return -EIO;
- }
- /*
- * for found ns, should we be transitioning from here?
- * breaks transition only
- * 1. from within state machine or
- * 2. if after alloc
- */
- efc_node_transition(fabctl, __efc_fabctl_init, NULL);
- return 0;
- }
- void
- __efc_fabric_wait_domain_attach(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_DOMAIN_ATTACH_OK:
- case EFC_EVT_NPORT_ATTACH_OK: {
- int rc;
- rc = efc_start_ns_node(node->nport);
- if (rc)
- return;
- /* sm: if enable_ini / start fabctl node */
- /* Instantiate the fabric controller (sends SCR) */
- if (node->nport->enable_rscn) {
- rc = efc_start_fabctl_node(node->nport);
- if (rc)
- return;
- }
- efc_node_transition(node, __efc_fabric_idle, NULL);
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_fabric_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
- void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_DOMAIN_ATTACH_OK:
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_ns_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- /* sm: / send PLOGI */
- efc_send_plogi(node);
- efc_node_transition(node, __efc_ns_plogi_wait_rsp, NULL);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_ns_plogi_wait_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK: {
- int rc;
- /* Save service parameters */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / save sparams, efc_node_attach */
- efc_node_save_sparms(node, cbdata->els_rsp.virt);
- rc = efc_node_attach(node);
- efc_node_transition(node, __efc_ns_wait_node_attach, NULL);
- if (rc < 0)
- efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
- NULL);
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_ns_wait_node_attach(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_NODE_ATTACH_OK:
- node->attached = true;
- /* sm: / send RFTID */
- efc_ns_send_rftid(node);
- efc_node_transition(node, __efc_ns_rftid_wait_rsp, NULL);
- break;
- case EFC_EVT_NODE_ATTACH_FAIL:
- /* node attach failed, shutdown the node */
- node->attached = false;
- node_printf(node, "Node attach failed\n");
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- break;
- case EFC_EVT_SHUTDOWN:
- node_printf(node, "Shutdown event received\n");
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_node_transition(node,
- __efc_fabric_wait_attach_evt_shutdown,
- NULL);
- break;
- /*
- * if receive RSCN just ignore,
- * we haven't sent GID_PT yet (ACC sent by fabctl node)
- */
- case EFC_EVT_RSCN_RCVD:
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_fabric_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- /* wait for any of these attach events and then shutdown */
- case EFC_EVT_NODE_ATTACH_OK:
- node->attached = true;
- node_printf(node, "Attach evt=%s, proceed to shutdown\n",
- efc_sm_event_name(evt));
- efc_fabric_initiate_shutdown(node);
- break;
- case EFC_EVT_NODE_ATTACH_FAIL:
- node->attached = false;
- node_printf(node, "Attach evt=%s, proceed to shutdown\n",
- efc_sm_event_name(evt));
- efc_fabric_initiate_shutdown(node);
- break;
- /* ignore shutdown event as we're already in shutdown path */
- case EFC_EVT_SHUTDOWN:
- node_printf(node, "Shutdown event received\n");
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_ns_rftid_wait_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK:
- if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFT_ID,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / send RFFID */
- efc_ns_send_rffid(node);
- efc_node_transition(node, __efc_ns_rffid_wait_rsp, NULL);
- break;
- /*
- * if receive RSCN just ignore,
- * we haven't sent GID_PT yet (ACC sent by fabctl node)
- */
- case EFC_EVT_RSCN_RCVD:
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_ns_rffid_wait_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- /*
- * Waits for an RFFID response event;
- * if rscn enabled, a GIDPT name services request is issued.
- */
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK: {
- if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFF_ID,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- if (node->nport->enable_rscn) {
- /* sm: if enable_rscn / send GIDPT */
- efc_ns_send_gidpt(node);
- efc_node_transition(node, __efc_ns_gidpt_wait_rsp,
- NULL);
- } else {
- /* if 'T' only, we're done, go to idle */
- efc_node_transition(node, __efc_ns_idle, NULL);
- }
- break;
- }
- /*
- * if receive RSCN just ignore,
- * we haven't sent GID_PT yet (ACC sent by fabctl node)
- */
- case EFC_EVT_RSCN_RCVD:
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- static int
- efc_process_gidpt_payload(struct efc_node *node,
- void *data, u32 gidpt_len)
- {
- u32 i, j;
- struct efc_node *newnode;
- struct efc_nport *nport = node->nport;
- struct efc *efc = node->efc;
- u32 port_id = 0, port_count, plist_count;
- struct efc_node *n;
- struct efc_node **active_nodes;
- int residual;
- struct {
- struct fc_ct_hdr hdr;
- struct fc_gid_pn_resp pn_rsp;
- } *rsp;
- struct fc_gid_pn_resp *gidpt;
- unsigned long index;
- rsp = data;
- gidpt = &rsp->pn_rsp;
- residual = be16_to_cpu(rsp->hdr.ct_mr_size);
- if (residual != 0)
- efc_log_debug(node->efc, "residual is %u words\n", residual);
- if (be16_to_cpu(rsp->hdr.ct_cmd) == FC_FS_RJT) {
- node_printf(node,
- "GIDPT request failed: rsn x%x rsn_expl x%x\n",
- rsp->hdr.ct_reason, rsp->hdr.ct_explan);
- return -EIO;
- }
- plist_count = (gidpt_len - sizeof(struct fc_ct_hdr)) / sizeof(*gidpt);
- /* Count the number of nodes */
- port_count = 0;
- xa_for_each(&nport->lookup, index, n) {
- port_count++;
- }
- /* Allocate a buffer for all nodes */
- active_nodes = kcalloc(port_count, sizeof(*active_nodes), GFP_ATOMIC);
- if (!active_nodes) {
- node_printf(node, "efc_malloc failed\n");
- return -EIO;
- }
- /* Fill buffer with fc_id of active nodes */
- i = 0;
- xa_for_each(&nport->lookup, index, n) {
- port_id = n->rnode.fc_id;
- switch (port_id) {
- case FC_FID_FLOGI:
- case FC_FID_FCTRL:
- case FC_FID_DIR_SERV:
- break;
- default:
- if (port_id != FC_FID_DOM_MGR)
- active_nodes[i++] = n;
- break;
- }
- }
- /* update the active nodes buffer */
- for (i = 0; i < plist_count; i++) {
- hton24(gidpt[i].fp_fid, port_id);
- for (j = 0; j < port_count; j++) {
- if (active_nodes[j] &&
- port_id == active_nodes[j]->rnode.fc_id) {
- active_nodes[j] = NULL;
- }
- }
- if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
- break;
- }
- /* Those remaining in the active_nodes[] are now gone ! */
- for (i = 0; i < port_count; i++) {
- /*
- * if we're an initiator and the remote node
- * is a target, then post the node missing event.
- * if we're target and we have enabled
- * target RSCN, then post the node missing event.
- */
- if (!active_nodes[i])
- continue;
- if ((node->nport->enable_ini && active_nodes[i]->targ) ||
- (node->nport->enable_tgt && enable_target_rscn(efc))) {
- efc_node_post_event(active_nodes[i],
- EFC_EVT_NODE_MISSING, NULL);
- } else {
- node_printf(node,
- "GID_PT: skipping non-tgt port_id x%06x\n",
- active_nodes[i]->rnode.fc_id);
- }
- }
- kfree(active_nodes);
- for (i = 0; i < plist_count; i++) {
- hton24(gidpt[i].fp_fid, port_id);
- /* Don't create node for ourselves */
- if (port_id == node->rnode.nport->fc_id) {
- if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
- break;
- continue;
- }
- newnode = efc_node_find(nport, port_id);
- if (!newnode) {
- if (!node->nport->enable_ini)
- continue;
- newnode = efc_node_alloc(nport, port_id, false, false);
- if (!newnode) {
- efc_log_err(efc, "efc_node_alloc() failed\n");
- return -EIO;
- }
- /*
- * send PLOGI automatically
- * if initiator
- */
- efc_node_init_device(newnode, true);
- }
- if (node->nport->enable_ini && newnode->targ) {
- efc_node_post_event(newnode, EFC_EVT_NODE_REFOUND,
- NULL);
- }
- if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
- break;
- }
- return 0;
- }
- void
- __efc_ns_gidpt_wait_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- /*
- * Wait for a GIDPT response from the name server. Process the FC_IDs
- * that are reported by creating new remote ports, as needed.
- */
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK: {
- if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_GID_PT,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / process GIDPT payload */
- efc_process_gidpt_payload(node, cbdata->els_rsp.virt,
- cbdata->els_rsp.len);
- efc_node_transition(node, __efc_ns_idle, NULL);
- break;
- }
- case EFC_EVT_SRRS_ELS_REQ_FAIL: {
- /* not much we can do; will retry with the next RSCN */
- node_printf(node, "GID_PT failed to complete\n");
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_node_transition(node, __efc_ns_idle, NULL);
- break;
- }
- /* if receive RSCN here, queue up another discovery processing */
- case EFC_EVT_RSCN_RCVD: {
- node_printf(node, "RSCN received during GID_PT processing\n");
- node->rscn_pending = true;
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- struct efc *efc = node->efc;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- /*
- * Wait for RSCN received events (posted from the fabric controller)
- * and restart the GIDPT name services query and processing.
- */
- switch (evt) {
- case EFC_EVT_ENTER:
- if (!node->rscn_pending)
- break;
- node_printf(node, "RSCN pending, restart discovery\n");
- node->rscn_pending = false;
- fallthrough;
- case EFC_EVT_RSCN_RCVD: {
- /* sm: / send GIDPT */
- /*
- * If target RSCN processing is enabled,
- * and this is target only (not initiator),
- * and tgt_rscn_delay is non-zero,
- * then we delay issuing the GID_PT
- */
- if (efc->tgt_rscn_delay_msec != 0 &&
- !node->nport->enable_ini && node->nport->enable_tgt &&
- enable_target_rscn(efc)) {
- efc_node_transition(node, __efc_ns_gidpt_delay, NULL);
- } else {
- efc_ns_send_gidpt(node);
- efc_node_transition(node, __efc_ns_gidpt_wait_rsp,
- NULL);
- }
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- static void
- gidpt_delay_timer_cb(struct timer_list *t)
- {
- struct efc_node *node = from_timer(node, t, gidpt_delay_timer);
- del_timer(&node->gidpt_delay_timer);
- efc_node_post_event(node, EFC_EVT_GIDPT_DELAY_EXPIRED, NULL);
- }
- void
- __efc_ns_gidpt_delay(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- struct efc *efc = node->efc;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER: {
- u64 delay_msec, tmp;
- /*
- * Compute the delay time.
- * Set to tgt_rscn_delay, if the time since last GIDPT
- * is less than tgt_rscn_period, then use tgt_rscn_period.
- */
- delay_msec = efc->tgt_rscn_delay_msec;
- tmp = jiffies_to_msecs(jiffies) - node->time_last_gidpt_msec;
- if (tmp < efc->tgt_rscn_period_msec)
- delay_msec = efc->tgt_rscn_period_msec;
- timer_setup(&node->gidpt_delay_timer, &gidpt_delay_timer_cb,
- 0);
- mod_timer(&node->gidpt_delay_timer,
- jiffies + msecs_to_jiffies(delay_msec));
- break;
- }
- case EFC_EVT_GIDPT_DELAY_EXPIRED:
- node->time_last_gidpt_msec = jiffies_to_msecs(jiffies);
- efc_ns_send_gidpt(node);
- efc_node_transition(node, __efc_ns_gidpt_wait_rsp, NULL);
- break;
- case EFC_EVT_RSCN_RCVD: {
- efc_log_debug(efc,
- "RSCN received while in GIDPT delay - no action\n");
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_fabctl_init(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- /* no need to login to fabric controller, just send SCR */
- efc_send_scr(node);
- efc_node_transition(node, __efc_fabctl_wait_scr_rsp, NULL);
- break;
- case EFC_EVT_NODE_ATTACH_OK:
- node->attached = true;
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_fabctl_wait_scr_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- /*
- * Fabric controller node state machine:
- * Wait for an SCR response from the fabric controller.
- */
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK:
- if (efc_node_check_els_req(ctx, evt, arg, ELS_SCR,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_node_transition(node, __efc_fabctl_ready, NULL);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- static void
- efc_process_rscn(struct efc_node *node, struct efc_node_cb *cbdata)
- {
- struct efc *efc = node->efc;
- struct efc_nport *nport = node->nport;
- struct efc_node *ns;
- /* Forward this event to the name-services node */
- ns = efc_node_find(nport, FC_FID_DIR_SERV);
- if (ns)
- efc_node_post_event(ns, EFC_EVT_RSCN_RCVD, cbdata);
- else
- efc_log_warn(efc, "can't find name server node\n");
- }
- void
- __efc_fabctl_ready(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- /*
- * Fabric controller node state machine: Ready.
- * In this state, the fabric controller sends a RSCN, which is received
- * by this node and is forwarded to the name services node object; and
- * the RSCN LS_ACC is sent.
- */
- switch (evt) {
- case EFC_EVT_RSCN_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- /*
- * sm: / process RSCN (forward to name services node),
- * send LS_ACC
- */
- efc_process_rscn(node, cbdata);
- efc_send_ls_acc(node, be16_to_cpu(hdr->fh_ox_id));
- efc_node_transition(node, __efc_fabctl_wait_ls_acc_cmpl,
- NULL);
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_fabctl_wait_ls_acc_cmpl(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_SRRS_ELS_CMPL_OK:
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- efc_node_transition(node, __efc_fabctl_ready, NULL);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- static uint64_t
- efc_get_wwpn(struct fc_els_flogi *sp)
- {
- return be64_to_cpu(sp->fl_wwnn);
- }
- static int
- efc_rnode_is_winner(struct efc_nport *nport)
- {
- struct fc_els_flogi *remote_sp;
- u64 remote_wwpn;
- u64 local_wwpn = nport->wwpn;
- u64 wwn_bump = 0;
- remote_sp = (struct fc_els_flogi *)nport->domain->flogi_service_params;
- remote_wwpn = efc_get_wwpn(remote_sp);
- local_wwpn ^= wwn_bump;
- efc_log_debug(nport->efc, "r: %llx\n",
- be64_to_cpu(remote_sp->fl_wwpn));
- efc_log_debug(nport->efc, "l: %llx\n", local_wwpn);
- if (remote_wwpn == local_wwpn) {
- efc_log_warn(nport->efc,
- "WWPN of remote node [%08x %08x] matches local WWPN\n",
- (u32)(local_wwpn >> 32ll),
- (u32)local_wwpn);
- return -1;
- }
- return (remote_wwpn > local_wwpn);
- }
- void
- __efc_p2p_wait_domain_attach(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = ctx->app;
- struct efc *efc = node->efc;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_DOMAIN_ATTACH_OK: {
- struct efc_nport *nport = node->nport;
- struct efc_node *rnode;
- /*
- * this transient node (SID=0 (recv'd FLOGI)
- * or DID=fabric (sent FLOGI))
- * is the p2p winner, will use a separate node
- * to send PLOGI to peer
- */
- WARN_ON(!node->nport->p2p_winner);
- rnode = efc_node_find(nport, node->nport->p2p_remote_port_id);
- if (rnode) {
- /*
- * the "other" transient p2p node has
- * already kicked off the
- * new node from which PLOGI is sent
- */
- node_printf(node,
- "Node with fc_id x%x already exists\n",
- rnode->rnode.fc_id);
- } else {
- /*
- * create new node (SID=1, DID=2)
- * from which to send PLOGI
- */
- rnode = efc_node_alloc(nport,
- nport->p2p_remote_port_id,
- false, false);
- if (!rnode) {
- efc_log_err(efc, "node alloc failed\n");
- return;
- }
- efc_fabric_notify_topology(node);
- /* sm: / allocate p2p remote node */
- efc_node_transition(rnode, __efc_p2p_rnode_init,
- NULL);
- }
- /*
- * the transient node (SID=0 or DID=fabric)
- * has served its purpose
- */
- if (node->rnode.fc_id == 0) {
- /*
- * if this is the SID=0 node,
- * move to the init state in case peer
- * has restarted FLOGI discovery and FLOGI is pending
- */
- /* don't send PLOGI on efc_d_init entry */
- efc_node_init_device(node, false);
- } else {
- /*
- * if this is the DID=fabric node
- * (we initiated FLOGI), shut it down
- */
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- }
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_p2p_rnode_init(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- /* sm: / send PLOGI */
- efc_send_plogi(node);
- efc_node_transition(node, __efc_p2p_wait_plogi_rsp, NULL);
- break;
- case EFC_EVT_ABTS_RCVD:
- /* sm: send BA_ACC */
- efc_send_bls_acc(node, cbdata->header->dma.virt);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_p2p_wait_flogi_acc_cmpl(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_SRRS_ELS_CMPL_OK:
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- /* sm: if p2p_winner / domain_attach */
- if (node->nport->p2p_winner) {
- efc_node_transition(node,
- __efc_p2p_wait_domain_attach,
- NULL);
- if (!node->nport->domain->attached) {
- node_printf(node, "Domain not attached\n");
- efc_domain_attach(node->nport->domain,
- node->nport->p2p_port_id);
- } else {
- node_printf(node, "Domain already attached\n");
- efc_node_post_event(node,
- EFC_EVT_DOMAIN_ATTACH_OK,
- NULL);
- }
- } else {
- /* this node has served its purpose;
- * we'll expect a PLOGI on a separate
- * node (remote SID=0x1); return this node
- * to init state in case peer
- * restarts discovery -- it may already
- * have (pending frames may exist).
- */
- /* don't send PLOGI on efc_d_init entry */
- efc_node_init_device(node, false);
- }
- break;
- case EFC_EVT_SRRS_ELS_CMPL_FAIL:
- /*
- * LS_ACC failed, possibly due to link down;
- * shutdown node and wait
- * for FLOGI discovery to restart
- */
- node_printf(node, "FLOGI LS_ACC failed, shutting down\n");
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- break;
- case EFC_EVT_ABTS_RCVD: {
- /* sm: / send BA_ACC */
- efc_send_bls_acc(node, cbdata->header->dma.virt);
- break;
- }
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_p2p_wait_plogi_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_SRRS_ELS_REQ_OK: {
- int rc;
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / save sparams, efc_node_attach */
- efc_node_save_sparms(node, cbdata->els_rsp.virt);
- rc = efc_node_attach(node);
- efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);
- if (rc < 0)
- efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
- NULL);
- break;
- }
- case EFC_EVT_SRRS_ELS_REQ_FAIL: {
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_fabric_common, __func__)) {
- return;
- }
- node_printf(node, "PLOGI failed, shutting down\n");
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- break;
- }
- case EFC_EVT_PLOGI_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- /* if we're in external loopback mode, just send LS_ACC */
- if (node->efc->external_loopback) {
- efc_send_plogi_acc(node, be16_to_cpu(hdr->fh_ox_id));
- } else {
- /*
- * if this isn't external loopback,
- * pass to default handler
- */
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- break;
- }
- case EFC_EVT_PRLI_RCVD:
- /* I, or I+T */
- /* sent PLOGI and before completion was seen, received the
- * PRLI from the remote node (WCQEs and RCQEs come in on
- * different queues and order of processing cannot be assumed)
- * Save OXID so PRLI can be sent after the attach and continue
- * to wait for PLOGI response
- */
- efc_process_prli_payload(node, cbdata->payload->dma.virt);
- efc_send_ls_acc_after_attach(node,
- cbdata->header->dma.virt,
- EFC_NODE_SEND_LS_ACC_PRLI);
- efc_node_transition(node, __efc_p2p_wait_plogi_rsp_recvd_prli,
- NULL);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_p2p_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- /*
- * Since we've received a PRLI, we have a port login and will
- * just need to wait for the PLOGI response to do the node
- * attach and then we can send the LS_ACC for the PRLI. If,
- * during this time, we receive FCP_CMNDs (which is possible
- * since we've already sent a PRLI and our peer may have
- * accepted).
- * At this time, we are not waiting on any other unsolicited
- * frames to continue with the login process. Thus, it will not
- * hurt to hold frames here.
- */
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_SRRS_ELS_REQ_OK: { /* PLOGI response received */
- int rc;
- /* Completion from PLOGI sent */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / save sparams, efc_node_attach */
- efc_node_save_sparms(node, cbdata->els_rsp.virt);
- rc = efc_node_attach(node);
- efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);
- if (rc < 0)
- efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
- NULL);
- break;
- }
- case EFC_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */
- case EFC_EVT_SRRS_ELS_REQ_RJT:
- /* PLOGI failed, shutdown the node */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_fabric_common, __func__)) {
- return;
- }
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_p2p_wait_node_attach(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = arg;
- struct efc_node *node = ctx->app;
- efc_node_evt_set(ctx, evt, __func__);
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_NODE_ATTACH_OK:
- node->attached = true;
- switch (node->send_ls_acc) {
- case EFC_NODE_SEND_LS_ACC_PRLI: {
- efc_d_send_prli_rsp(node->ls_acc_io,
- node->ls_acc_oxid);
- node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
- node->ls_acc_io = NULL;
- break;
- }
- case EFC_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */
- case EFC_NODE_SEND_LS_ACC_NONE:
- default:
- /* Normal case for I */
- /* sm: send_plogi_acc is not set / send PLOGI acc */
- efc_node_transition(node, __efc_d_port_logged_in,
- NULL);
- break;
- }
- break;
- case EFC_EVT_NODE_ATTACH_FAIL:
- /* node attach failed, shutdown the node */
- node->attached = false;
- node_printf(node, "Node attach failed\n");
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_fabric_initiate_shutdown(node);
- break;
- case EFC_EVT_SHUTDOWN:
- node_printf(node, "%s received\n", efc_sm_event_name(evt));
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_node_transition(node,
- __efc_fabric_wait_attach_evt_shutdown,
- NULL);
- break;
- case EFC_EVT_PRLI_RCVD:
- node_printf(node, "%s: PRLI received before node is attached\n",
- efc_sm_event_name(evt));
- efc_process_prli_payload(node, cbdata->payload->dma.virt);
- efc_send_ls_acc_after_attach(node,
- cbdata->header->dma.virt,
- EFC_NODE_SEND_LS_ACC_PRLI);
- break;
- default:
- __efc_fabric_common(__func__, ctx, evt, arg);
- }
- }
- int
- efc_p2p_setup(struct efc_nport *nport)
- {
- struct efc *efc = nport->efc;
- int rnode_winner;
- rnode_winner = efc_rnode_is_winner(nport);
- /* set nport flags to indicate p2p "winner" */
- if (rnode_winner == 1) {
- nport->p2p_remote_port_id = 0;
- nport->p2p_port_id = 0;
- nport->p2p_winner = false;
- } else if (rnode_winner == 0) {
- nport->p2p_remote_port_id = 2;
- nport->p2p_port_id = 1;
- nport->p2p_winner = true;
- } else {
- /* no winner; only okay if external loopback enabled */
- if (nport->efc->external_loopback) {
- /*
- * External loopback mode enabled;
- * local nport and remote node
- * will be registered with an NPortID = 1;
- */
- efc_log_debug(efc,
- "External loopback mode enabled\n");
- nport->p2p_remote_port_id = 1;
- nport->p2p_port_id = 1;
- nport->p2p_winner = true;
- } else {
- efc_log_warn(efc,
- "failed to determine p2p winner\n");
- return rnode_winner;
- }
- }
- return 0;
- }
|