123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
- * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
- */
- /*
- * device_sm Node State Machine: Remote Device States
- */
- #include "efc.h"
- #include "efc_device.h"
- #include "efc_fabric.h"
- void
- efc_d_send_prli_rsp(struct efc_node *node, u16 ox_id)
- {
- int rc = EFC_SCSI_CALL_COMPLETE;
- struct efc *efc = node->efc;
- node->ls_acc_oxid = ox_id;
- node->send_ls_acc = EFC_NODE_SEND_LS_ACC_PRLI;
- /*
- * Wait for backend session registration
- * to complete before sending PRLI resp
- */
- if (node->init) {
- efc_log_info(efc, "[%s] found(initiator) WWPN:%s WWNN:%s\n",
- node->display_name, node->wwpn, node->wwnn);
- if (node->nport->enable_tgt)
- rc = efc->tt.scsi_new_node(efc, node);
- }
- if (rc < 0)
- efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_FAIL, NULL);
- if (rc == EFC_SCSI_CALL_COMPLETE)
- efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_OK, NULL);
- }
- static void
- __efc_d_common(const char *funcname, struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node *node = NULL;
- struct efc *efc = NULL;
- node = ctx->app;
- efc = node->efc;
- switch (evt) {
- /* Handle shutdown events */
- case EFC_EVT_SHUTDOWN:
- efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
- funcname, efc_sm_event_name(evt));
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
- break;
- case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
- efc_log_debug(efc, "[%s] %-20s %-20s\n",
- node->display_name, funcname,
- efc_sm_event_name(evt));
- node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
- efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
- break;
- case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
- efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
- funcname, efc_sm_event_name(evt));
- node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
- efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
- break;
- default:
- /* call default event handler common to all nodes */
- __efc_node_common(funcname, ctx, evt, arg);
- }
- }
- static void
- __efc_d_wait_del_node(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__);
- /*
- * State is entered when a node sends a delete initiator/target call
- * to the target-server/initiator-client and needs to wait for that
- * work to complete.
- */
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- efc_node_hold_frames(node);
- fallthrough;
- case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
- case EFC_EVT_ALL_CHILD_NODES_FREE:
- /* These are expected events. */
- break;
- case EFC_EVT_NODE_DEL_INI_COMPLETE:
- case EFC_EVT_NODE_DEL_TGT_COMPLETE:
- /*
- * 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);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_SRRS_ELS_REQ_FAIL:
- /* Can happen as ELS IO IO's complete */
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- break;
- /* ignore shutdown events as we're already in shutdown path */
- case EFC_EVT_SHUTDOWN:
- /* have default shutdown event take precedence */
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- fallthrough;
- case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
- case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
- node_printf(node, "%s received\n", efc_sm_event_name(evt));
- break;
- case EFC_EVT_DOMAIN_ATTACH_OK:
- /* don't care about domain_attach_ok */
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- static void
- __efc_d_wait_del_ini_tgt(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);
- fallthrough;
- case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
- case EFC_EVT_ALL_CHILD_NODES_FREE:
- /* These are expected events. */
- break;
- case EFC_EVT_NODE_DEL_INI_COMPLETE:
- case EFC_EVT_NODE_DEL_TGT_COMPLETE:
- efc_node_transition(node, __efc_d_wait_del_node, NULL);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_SRRS_ELS_REQ_FAIL:
- /* Can happen as ELS IO IO's complete */
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- break;
- /* ignore shutdown events as we're already in shutdown path */
- case EFC_EVT_SHUTDOWN:
- /* have default shutdown event take precedence */
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- fallthrough;
- case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
- case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
- node_printf(node, "%s received\n", efc_sm_event_name(evt));
- break;
- case EFC_EVT_DOMAIN_ATTACH_OK:
- /* don't care about domain_attach_ok */
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_initiate_shutdown(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: {
- int rc = EFC_SCSI_CALL_COMPLETE;
- /* assume no wait needed */
- node->els_io_enabled = false;
- /* make necessary delete upcall(s) */
- if (node->init && !node->targ) {
- efc_log_info(node->efc,
- "[%s] delete (initiator) WWPN %s WWNN %s\n",
- node->display_name,
- node->wwpn, node->wwnn);
- efc_node_transition(node,
- __efc_d_wait_del_node,
- NULL);
- if (node->nport->enable_tgt)
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_INITIATOR_DELETED);
- if (rc == EFC_SCSI_CALL_COMPLETE || rc < 0)
- efc_node_post_event(node,
- EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
- } else if (node->targ && !node->init) {
- efc_log_info(node->efc,
- "[%s] delete (target) WWPN %s WWNN %s\n",
- node->display_name,
- node->wwpn, node->wwnn);
- efc_node_transition(node,
- __efc_d_wait_del_node,
- NULL);
- if (node->nport->enable_ini)
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_TARGET_DELETED);
- if (rc == EFC_SCSI_CALL_COMPLETE)
- efc_node_post_event(node,
- EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
- } else if (node->init && node->targ) {
- efc_log_info(node->efc,
- "[%s] delete (I+T) WWPN %s WWNN %s\n",
- node->display_name, node->wwpn, node->wwnn);
- efc_node_transition(node, __efc_d_wait_del_ini_tgt,
- NULL);
- if (node->nport->enable_tgt)
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_INITIATOR_DELETED);
- if (rc == EFC_SCSI_CALL_COMPLETE)
- efc_node_post_event(node,
- EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
- /* assume no wait needed */
- rc = EFC_SCSI_CALL_COMPLETE;
- if (node->nport->enable_ini)
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_TARGET_DELETED);
- if (rc == EFC_SCSI_CALL_COMPLETE)
- efc_node_post_event(node,
- EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
- }
- /* we've initiated the upcalls as needed, now kick off the node
- * detach to precipitate the aborting of outstanding exchanges
- * associated with said node
- *
- * Beware: if we've made upcall(s), we've already transitioned
- * to a new state by the time we execute this.
- * consider doing this before the upcalls?
- */
- if (node->attached) {
- /* 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);
- }
- /* if neither initiator nor target, proceed to cleanup */
- if (!node->init && !node->targ) {
- /*
- * 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);
- }
- break;
- }
- case EFC_EVT_ALL_CHILD_NODES_FREE:
- /* Ignore, this can happen if an ELS is
- * aborted while in a delay/retry state
- */
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_loop(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: {
- /* send PLOGI automatically if initiator */
- efc_node_init_device(node, true);
- break;
- }
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- efc_send_ls_acc_after_attach(struct efc_node *node,
- struct fc_frame_header *hdr,
- enum efc_node_send_ls_acc ls)
- {
- u16 ox_id = be16_to_cpu(hdr->fh_ox_id);
- /* Save the OX_ID for sending LS_ACC sometime later */
- WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_NONE);
- node->ls_acc_oxid = ox_id;
- node->send_ls_acc = ls;
- node->ls_acc_did = ntoh24(hdr->fh_d_id);
- }
- void
- efc_process_prli_payload(struct efc_node *node, void *prli)
- {
- struct {
- struct fc_els_prli prli;
- struct fc_els_spp sp;
- } *pp;
- pp = prli;
- node->init = (pp->sp.spp_flags & FCP_SPPF_INIT_FCN) != 0;
- node->targ = (pp->sp.spp_flags & FCP_SPPF_TARG_FCN) != 0;
- }
- void
- __efc_d_wait_plogi_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_FAIL:
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
- break;
- case EFC_EVT_SRRS_ELS_CMPL_OK: /* PLOGI ACC completions */
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- efc_node_transition(node, __efc_d_port_logged_in, NULL);
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_logo_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_ENTER:
- efc_node_hold_frames(node);
- break;
- case EFC_EVT_EXIT:
- efc_node_accept_frames(node);
- break;
- case EFC_EVT_SRRS_ELS_REQ_OK:
- case EFC_EVT_SRRS_ELS_REQ_RJT:
- case EFC_EVT_SRRS_ELS_REQ_FAIL:
- /* LOGO response received, sent shutdown */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_LOGO,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- node_printf(node,
- "LOGO sent (evt=%s), shutdown node\n",
- efc_sm_event_name(evt));
- /* sm: / post explicit logout */
- efc_node_post_event(node, EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
- NULL);
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- efc_node_init_device(struct efc_node *node, bool send_plogi)
- {
- node->send_plogi = send_plogi;
- if ((node->efc->nodedb_mask & EFC_NODEDB_PAUSE_NEW_NODES) &&
- (node->rnode.fc_id != FC_FID_DOM_MGR)) {
- node->nodedb_state = __efc_d_init;
- efc_node_transition(node, __efc_node_paused, NULL);
- } else {
- efc_node_transition(node, __efc_d_init, NULL);
- }
- }
- static void
- efc_d_check_plogi_topology(struct efc_node *node, u32 d_id)
- {
- switch (node->nport->topology) {
- case EFC_NPORT_TOPO_P2P:
- /* we're not attached and nport is p2p,
- * need to attach
- */
- efc_domain_attach(node->nport->domain, d_id);
- efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
- break;
- case EFC_NPORT_TOPO_FABRIC:
- /* we're not attached and nport is fabric, domain
- * attach should have already been requested as part
- * of the fabric state machine, wait for it
- */
- efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
- break;
- case EFC_NPORT_TOPO_UNKNOWN:
- /* Two possibilities:
- * 1. received a PLOGI before our FLOGI has completed
- * (possible since completion comes in on another
- * CQ), thus we don't know what we're connected to
- * yet; transition to a state to wait for the
- * fabric node to tell us;
- * 2. PLOGI received before link went down and we
- * haven't performed domain attach yet.
- * Note: we cannot distinguish between 1. and 2.
- * so have to assume PLOGI
- * was received after link back up.
- */
- node_printf(node, "received PLOGI, unknown topology did=0x%x\n",
- d_id);
- efc_node_transition(node, __efc_d_wait_topology_notify, NULL);
- break;
- default:
- node_printf(node, "received PLOGI, unexpected topology %d\n",
- node->nport->topology);
- }
- }
- void
- __efc_d_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();
- /*
- * This state is entered when a node is instantiated,
- * either having been discovered from a name services query,
- * or having received a PLOGI/FLOGI.
- */
- switch (evt) {
- case EFC_EVT_ENTER:
- if (!node->send_plogi)
- break;
- /* only send if we have initiator capability,
- * and domain is attached
- */
- if (node->nport->enable_ini &&
- node->nport->domain->attached) {
- efc_send_plogi(node);
- efc_node_transition(node, __efc_d_wait_plogi_rsp, NULL);
- } else {
- node_printf(node, "not sending plogi nport.ini=%d,",
- node->nport->enable_ini);
- node_printf(node, "domain attached=%d\n",
- node->nport->domain->attached);
- }
- break;
- case EFC_EVT_PLOGI_RCVD: {
- /* T, or I+T */
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- int rc;
- efc_node_save_sparms(node, cbdata->payload->dma.virt);
- efc_send_ls_acc_after_attach(node,
- cbdata->header->dma.virt,
- EFC_NODE_SEND_LS_ACC_PLOGI);
- /* domain not attached; several possibilities: */
- if (!node->nport->domain->attached) {
- efc_d_check_plogi_topology(node, ntoh24(hdr->fh_d_id));
- break;
- }
- /* domain already attached */
- rc = efc_node_attach(node);
- efc_node_transition(node, __efc_d_wait_node_attach, NULL);
- if (rc < 0)
- efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, NULL);
- break;
- }
- case EFC_EVT_FDISC_RCVD: {
- __efc_d_common(__func__, ctx, evt, arg);
- break;
- }
- case EFC_EVT_FLOGI_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- u32 d_id = ntoh24(hdr->fh_d_id);
- /* sm: / save sparams, send FLOGI acc */
- memcpy(node->nport->domain->flogi_service_params,
- cbdata->payload->dma.virt,
- sizeof(struct fc_els_flogi));
- /* send FC LS_ACC response, override s_id */
- efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P);
- efc_send_flogi_p2p_acc(node, be16_to_cpu(hdr->fh_ox_id), d_id);
- if (efc_p2p_setup(node->nport)) {
- node_printf(node, "p2p failed, shutting down node\n");
- efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
- break;
- }
- efc_node_transition(node, __efc_p2p_wait_flogi_acc_cmpl, NULL);
- break;
- }
- case EFC_EVT_LOGO_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- if (!node->nport->domain->attached) {
- /* most likely a frame left over from before a link
- * down; drop and
- * shut node down w/ "explicit logout" so pending
- * frames are processed
- */
- node_printf(node, "%s domain not attached, dropping\n",
- efc_sm_event_name(evt));
- efc_node_post_event(node,
- EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
- break;
- }
- efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
- efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
- break;
- }
- case EFC_EVT_PRLI_RCVD:
- case EFC_EVT_PRLO_RCVD:
- case EFC_EVT_PDISC_RCVD:
- case EFC_EVT_ADISC_RCVD:
- case EFC_EVT_RSCN_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- if (!node->nport->domain->attached) {
- /* most likely a frame left over from before a link
- * down; drop and shut node down w/ "explicit logout"
- * so pending frames are processed
- */
- node_printf(node, "%s domain not attached, dropping\n",
- efc_sm_event_name(evt));
- efc_node_post_event(node,
- EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
- NULL);
- break;
- }
- node_printf(node, "%s received, sending reject\n",
- efc_sm_event_name(evt));
- efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
- ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
- break;
- }
- case EFC_EVT_FCP_CMD_RCVD: {
- /* note: problem, we're now expecting an ELS REQ completion
- * from both the LOGO and PLOGI
- */
- if (!node->nport->domain->attached) {
- /* most likely a frame left over from before a
- * link down; drop and
- * shut node down w/ "explicit logout" so pending
- * frames are processed
- */
- node_printf(node, "%s domain not attached, dropping\n",
- efc_sm_event_name(evt));
- efc_node_post_event(node,
- EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
- NULL);
- break;
- }
- /* Send LOGO */
- node_printf(node, "FCP_CMND received, send LOGO\n");
- if (efc_send_logo(node)) {
- /*
- * failed to send LOGO, go ahead and cleanup node
- * anyways
- */
- node_printf(node, "Failed to send LOGO\n");
- efc_node_post_event(node,
- EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
- NULL);
- } else {
- /* sent LOGO, wait for response */
- efc_node_transition(node,
- __efc_d_wait_logo_rsp, NULL);
- }
- break;
- }
- case EFC_EVT_DOMAIN_ATTACH_OK:
- /* don't care about domain_attach_ok */
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_plogi_rsp(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- int rc;
- 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_PLOGI_RCVD: {
- /* T, or I+T */
- /* received PLOGI with svc parms, go ahead and attach node
- * when PLOGI that was sent ultimately completes, it'll be a
- * no-op
- *
- * If there is an outstanding PLOGI sent, can we set a flag
- * to indicate that we don't want to retry it if it times out?
- */
- efc_node_save_sparms(node, cbdata->payload->dma.virt);
- efc_send_ls_acc_after_attach(node,
- cbdata->header->dma.virt,
- EFC_NODE_SEND_LS_ACC_PLOGI);
- /* sm: domain->attached / efc_node_attach */
- rc = efc_node_attach(node);
- efc_node_transition(node, __efc_d_wait_node_attach, NULL);
- if (rc < 0)
- efc_node_post_event(node,
- EFC_EVT_NODE_ATTACH_FAIL, NULL);
- 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_d_wait_plogi_rsp_recvd_prli,
- NULL);
- break;
- case EFC_EVT_LOGO_RCVD: /* why don't we do a shutdown here?? */
- case EFC_EVT_PRLO_RCVD:
- case EFC_EVT_PDISC_RCVD:
- case EFC_EVT_FDISC_RCVD:
- case EFC_EVT_ADISC_RCVD:
- case EFC_EVT_RSCN_RCVD:
- case EFC_EVT_SCR_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- node_printf(node, "%s received, sending reject\n",
- efc_sm_event_name(evt));
- efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
- ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
- break;
- }
- case EFC_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */
- /* Completion from PLOGI sent */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_d_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_d_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 */
- /* PLOGI failed, shutdown the node */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
- break;
- case EFC_EVT_SRRS_ELS_REQ_RJT:
- /* Our PLOGI was rejected, this is ok in some cases */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- break;
- case EFC_EVT_FCP_CMD_RCVD: {
- /* not logged in yet and outstanding PLOGI so don't send LOGO,
- * just drop
- */
- node_printf(node, "FCP_CMND received, drop\n");
- break;
- }
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- int rc;
- 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 */
- /* Completion from PLOGI sent */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
- __efc_d_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_d_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_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_domain_attach(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- int rc;
- 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:
- WARN_ON(!node->nport->domain->attached);
- /* sm: / efc_node_attach */
- rc = efc_node_attach(node);
- efc_node_transition(node, __efc_d_wait_node_attach, NULL);
- if (rc < 0)
- efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
- NULL);
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_topology_notify(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- int rc;
- 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_NPORT_TOPOLOGY_NOTIFY: {
- enum efc_nport_topology *topology = arg;
- WARN_ON(node->nport->domain->attached);
- WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_PLOGI);
- node_printf(node, "topology notification, topology=%d\n",
- *topology);
- /* At the time the PLOGI was received, the topology was unknown,
- * so we didn't know which node would perform the domain attach:
- * 1. The node from which the PLOGI was sent (p2p) or
- * 2. The node to which the FLOGI was sent (fabric).
- */
- if (*topology == EFC_NPORT_TOPO_P2P) {
- /* if this is p2p, need to attach to the domain using
- * the d_id from the PLOGI received
- */
- efc_domain_attach(node->nport->domain,
- node->ls_acc_did);
- }
- /* else, if this is fabric, the domain attach
- * should be performed by the fabric node (node sending FLOGI);
- * just wait for attach to complete
- */
- efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
- break;
- }
- case EFC_EVT_DOMAIN_ATTACH_OK:
- WARN_ON(!node->nport->domain->attached);
- node_printf(node, "domain attach ok\n");
- /* sm: / efc_node_attach */
- rc = efc_node_attach(node);
- efc_node_transition(node, __efc_d_wait_node_attach, NULL);
- if (rc < 0)
- efc_node_post_event(node,
- EFC_EVT_NODE_ATTACH_FAIL, NULL);
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_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;
- switch (node->send_ls_acc) {
- case EFC_NODE_SEND_LS_ACC_PLOGI: {
- /* sm: send_plogi_acc is set / send PLOGI acc */
- /* Normal case for T, or I+T */
- efc_send_plogi_acc(node, node->ls_acc_oxid);
- efc_node_transition(node, __efc_d_wait_plogi_acc_cmpl,
- NULL);
- node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
- node->ls_acc_io = NULL;
- break;
- }
- case EFC_NODE_SEND_LS_ACC_PRLI: {
- efc_d_send_prli_rsp(node, 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_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_node_transition(node, __efc_d_initiate_shutdown, NULL);
- break;
- /* Handle shutdown events */
- 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_d_wait_attach_evt_shutdown,
- NULL);
- break;
- case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
- node_printf(node, "%s received\n", efc_sm_event_name(evt));
- node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
- efc_node_transition(node, __efc_d_wait_attach_evt_shutdown,
- NULL);
- break;
- case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
- node_printf(node, "%s received\n", efc_sm_event_name(evt));
- node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
- efc_node_transition(node,
- __efc_d_wait_attach_evt_shutdown, NULL);
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_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_node_transition(node, __efc_d_initiate_shutdown, NULL);
- break;
- case EFC_EVT_NODE_ATTACH_FAIL:
- /* node attach failed, shutdown the node */
- node->attached = false;
- node_printf(node, "Attach evt=%s, proceed to shutdown\n",
- efc_sm_event_name(evt));
- efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
- break;
- /* ignore shutdown events as we're already in shutdown path */
- case EFC_EVT_SHUTDOWN:
- /* have default shutdown event take precedence */
- node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
- fallthrough;
- case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
- case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
- node_printf(node, "%s received\n", efc_sm_event_name(evt));
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_port_logged_in(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:
- /* Normal case for I or I+T */
- if (node->nport->enable_ini &&
- !(node->rnode.fc_id != FC_FID_DOM_MGR)) {
- /* sm: if enable_ini / send PRLI */
- efc_send_prli(node);
- /* can now expect ELS_REQ_OK/FAIL/RJT */
- }
- break;
- case EFC_EVT_FCP_CMD_RCVD: {
- break;
- }
- case EFC_EVT_PRLI_RCVD: {
- /* Normal case for T or I+T */
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- struct {
- struct fc_els_prli prli;
- struct fc_els_spp sp;
- } *pp;
- pp = cbdata->payload->dma.virt;
- if (pp->sp.spp_type != FC_TYPE_FCP) {
- /*Only FCP is supported*/
- efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
- ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
- break;
- }
- efc_process_prli_payload(node, cbdata->payload->dma.virt);
- efc_d_send_prli_rsp(node, be16_to_cpu(hdr->fh_ox_id));
- break;
- }
- case EFC_EVT_NODE_SESS_REG_OK:
- if (node->send_ls_acc == EFC_NODE_SEND_LS_ACC_PRLI)
- efc_send_prli_acc(node, node->ls_acc_oxid);
- node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
- efc_node_transition(node, __efc_d_device_ready, NULL);
- break;
- case EFC_EVT_NODE_SESS_REG_FAIL:
- efc_send_ls_rjt(node, node->ls_acc_oxid, ELS_RJT_UNAB,
- ELS_EXPL_UNSUPR, 0);
- node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
- break;
- case EFC_EVT_SRRS_ELS_REQ_OK: { /* PRLI response */
- /* Normal case for I or I+T */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / process PRLI payload */
- efc_process_prli_payload(node, cbdata->els_rsp.virt);
- efc_node_transition(node, __efc_d_device_ready, NULL);
- break;
- }
- case EFC_EVT_SRRS_ELS_REQ_FAIL: { /* PRLI response failed */
- /* I, I+T, assume some link failure, shutdown node */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
- break;
- }
- case EFC_EVT_SRRS_ELS_REQ_RJT: {
- /* PRLI rejected by remote
- * Normal for I, I+T (connected to an I)
- * Node doesn't want to be a target, stay here and wait for a
- * PRLI from the remote node
- * if it really wants to connect to us as target
- */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- break;
- }
- case EFC_EVT_SRRS_ELS_CMPL_OK: {
- /* Normal T, I+T, target-server rejected the process login */
- /* This would be received only in the case where we sent
- * LS_RJT for the PRLI, so
- * do nothing. (note: as T only we could shutdown the node)
- */
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- break;
- }
- case EFC_EVT_PLOGI_RCVD: {
- /*sm: / save sparams, set send_plogi_acc,
- *post implicit logout
- * Save plogi parameters
- */
- efc_node_save_sparms(node, cbdata->payload->dma.virt);
- efc_send_ls_acc_after_attach(node,
- cbdata->header->dma.virt,
- EFC_NODE_SEND_LS_ACC_PLOGI);
- /* Restart node attach with new service parameters,
- * and send ACC
- */
- efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
- NULL);
- break;
- }
- case EFC_EVT_LOGO_RCVD: {
- /* I, T, I+T */
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- node_printf(node, "%s received attached=%d\n",
- efc_sm_event_name(evt),
- node->attached);
- /* sm: / send LOGO acc */
- efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
- efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
- break;
- }
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_logo_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:
- case EFC_EVT_SRRS_ELS_CMPL_FAIL:
- /* sm: / post explicit logout */
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- efc_node_post_event(node,
- EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_device_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;
- struct efc *efc = node->efc;
- efc_node_evt_set(ctx, evt, __func__);
- if (evt != EFC_EVT_FCP_CMD_RCVD)
- node_sm_trace();
- switch (evt) {
- case EFC_EVT_ENTER:
- node->fcp_enabled = true;
- if (node->targ) {
- efc_log_info(efc,
- "[%s] found (target) WWPN %s WWNN %s\n",
- node->display_name,
- node->wwpn, node->wwnn);
- if (node->nport->enable_ini)
- efc->tt.scsi_new_node(efc, node);
- }
- break;
- case EFC_EVT_EXIT:
- node->fcp_enabled = false;
- break;
- case EFC_EVT_PLOGI_RCVD: {
- /* sm: / save sparams, set send_plogi_acc, post implicit
- * logout
- * Save plogi parameters
- */
- efc_node_save_sparms(node, cbdata->payload->dma.virt);
- efc_send_ls_acc_after_attach(node,
- cbdata->header->dma.virt,
- EFC_NODE_SEND_LS_ACC_PLOGI);
- /*
- * Restart node attach with new service parameters,
- * and send ACC
- */
- efc_node_post_event(node,
- EFC_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
- break;
- }
- case EFC_EVT_PRLI_RCVD: {
- /* T, I+T: remote initiator is slow to get started */
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- struct {
- struct fc_els_prli prli;
- struct fc_els_spp sp;
- } *pp;
- pp = cbdata->payload->dma.virt;
- if (pp->sp.spp_type != FC_TYPE_FCP) {
- /*Only FCP is supported*/
- efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
- ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
- break;
- }
- efc_process_prli_payload(node, cbdata->payload->dma.virt);
- efc_send_prli_acc(node, be16_to_cpu(hdr->fh_ox_id));
- break;
- }
- case EFC_EVT_PRLO_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- /* sm: / send PRLO acc */
- efc_send_prlo_acc(node, be16_to_cpu(hdr->fh_ox_id));
- /* need implicit logout? */
- break;
- }
- case EFC_EVT_LOGO_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- node_printf(node, "%s received attached=%d\n",
- efc_sm_event_name(evt), node->attached);
- /* sm: / send LOGO acc */
- efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
- efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
- break;
- }
- case EFC_EVT_ADISC_RCVD: {
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- /* sm: / send ADISC acc */
- efc_send_adisc_acc(node, be16_to_cpu(hdr->fh_ox_id));
- break;
- }
- case EFC_EVT_ABTS_RCVD:
- /* sm: / process ABTS */
- efc_log_err(efc, "Unexpected event:%s\n",
- efc_sm_event_name(evt));
- break;
- case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
- break;
- case EFC_EVT_NODE_REFOUND:
- break;
- case EFC_EVT_NODE_MISSING:
- if (node->nport->enable_rscn)
- efc_node_transition(node, __efc_d_device_gone, NULL);
- break;
- case EFC_EVT_SRRS_ELS_CMPL_OK:
- /* T, or I+T, PRLI accept completed ok */
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- break;
- case EFC_EVT_SRRS_ELS_CMPL_FAIL:
- /* T, or I+T, PRLI accept failed to complete */
- WARN_ON(!node->els_cmpl_cnt);
- node->els_cmpl_cnt--;
- node_printf(node, "Failed to send PRLI LS_ACC\n");
- break;
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_device_gone(struct efc_sm_ctx *ctx,
- enum efc_sm_event evt, void *arg)
- {
- struct efc_node_cb *cbdata = 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: {
- int rc = EFC_SCSI_CALL_COMPLETE;
- int rc_2 = EFC_SCSI_CALL_COMPLETE;
- static const char * const labels[] = {
- "none", "initiator", "target", "initiator+target"
- };
- efc_log_info(efc, "[%s] missing (%s) WWPN %s WWNN %s\n",
- node->display_name,
- labels[(node->targ << 1) | (node->init)],
- node->wwpn, node->wwnn);
- switch (efc_node_get_enable(node)) {
- case EFC_NODE_ENABLE_T_TO_T:
- case EFC_NODE_ENABLE_I_TO_T:
- case EFC_NODE_ENABLE_IT_TO_T:
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_TARGET_MISSING);
- break;
- case EFC_NODE_ENABLE_T_TO_I:
- case EFC_NODE_ENABLE_I_TO_I:
- case EFC_NODE_ENABLE_IT_TO_I:
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_INITIATOR_MISSING);
- break;
- case EFC_NODE_ENABLE_T_TO_IT:
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_INITIATOR_MISSING);
- break;
- case EFC_NODE_ENABLE_I_TO_IT:
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_TARGET_MISSING);
- break;
- case EFC_NODE_ENABLE_IT_TO_IT:
- rc = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_INITIATOR_MISSING);
- rc_2 = efc->tt.scsi_del_node(efc, node,
- EFC_SCSI_TARGET_MISSING);
- break;
- default:
- rc = EFC_SCSI_CALL_COMPLETE;
- break;
- }
- if (rc == EFC_SCSI_CALL_COMPLETE &&
- rc_2 == EFC_SCSI_CALL_COMPLETE)
- efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
- break;
- }
- case EFC_EVT_NODE_REFOUND:
- /* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
- /* reauthenticate with PLOGI/PRLI */
- /* efc_node_transition(node, __efc_d_discovered, NULL); */
- /* reauthenticate with ADISC */
- /* sm: / send ADISC */
- efc_send_adisc(node);
- efc_node_transition(node, __efc_d_wait_adisc_rsp, NULL);
- break;
- case EFC_EVT_PLOGI_RCVD: {
- /* sm: / save sparams, set send_plogi_acc, post implicit
- * logout
- * Save plogi parameters
- */
- efc_node_save_sparms(node, cbdata->payload->dma.virt);
- efc_send_ls_acc_after_attach(node,
- cbdata->header->dma.virt,
- EFC_NODE_SEND_LS_ACC_PLOGI);
- /*
- * Restart node attach with new service parameters, and send
- * ACC
- */
- efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
- NULL);
- break;
- }
- case EFC_EVT_FCP_CMD_RCVD: {
- /* most likely a stale frame (received prior to link down),
- * if attempt to send LOGO, will probably timeout and eat
- * up 20s; thus, drop FCP_CMND
- */
- node_printf(node, "FCP_CMND received, drop\n");
- break;
- }
- case EFC_EVT_LOGO_RCVD: {
- /* I, T, I+T */
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- node_printf(node, "%s received attached=%d\n",
- efc_sm_event_name(evt), node->attached);
- /* sm: / send LOGO acc */
- efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
- efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
- break;
- }
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
- void
- __efc_d_wait_adisc_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_ADISC,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- efc_node_transition(node, __efc_d_device_ready, NULL);
- break;
- case EFC_EVT_SRRS_ELS_REQ_RJT:
- /* received an LS_RJT, in this case, send shutdown
- * (explicit logo) event which will unregister the node,
- * and start over with PLOGI
- */
- if (efc_node_check_els_req(ctx, evt, arg, ELS_ADISC,
- __efc_d_common, __func__))
- return;
- WARN_ON(!node->els_req_cnt);
- node->els_req_cnt--;
- /* sm: / post explicit logout */
- efc_node_post_event(node,
- EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
- NULL);
- break;
- case EFC_EVT_LOGO_RCVD: {
- /* In this case, we have the equivalent of an LS_RJT for
- * the ADISC, so we need to abort the ADISC, and re-login
- * with PLOGI
- */
- /* sm: / request abort, send LOGO acc */
- struct fc_frame_header *hdr = cbdata->header->dma.virt;
- node_printf(node, "%s received attached=%d\n",
- efc_sm_event_name(evt), node->attached);
- efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
- efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
- break;
- }
- default:
- __efc_d_common(__func__, ctx, evt, arg);
- }
- }
|