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 * device_sm Node State Machine: Remote Device States
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "efc.h"
1262306a36Sopenharmony_ci#include "efc_device.h"
1362306a36Sopenharmony_ci#include "efc_fabric.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_civoid
1662306a36Sopenharmony_ciefc_d_send_prli_rsp(struct efc_node *node, u16 ox_id)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	int rc = EFC_SCSI_CALL_COMPLETE;
1962306a36Sopenharmony_ci	struct efc *efc = node->efc;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	node->ls_acc_oxid = ox_id;
2262306a36Sopenharmony_ci	node->send_ls_acc = EFC_NODE_SEND_LS_ACC_PRLI;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/*
2562306a36Sopenharmony_ci	 * Wait for backend session registration
2662306a36Sopenharmony_ci	 * to complete before sending PRLI resp
2762306a36Sopenharmony_ci	 */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (node->init) {
3062306a36Sopenharmony_ci		efc_log_info(efc, "[%s] found(initiator) WWPN:%s WWNN:%s\n",
3162306a36Sopenharmony_ci			     node->display_name, node->wwpn, node->wwnn);
3262306a36Sopenharmony_ci		if (node->nport->enable_tgt)
3362306a36Sopenharmony_ci			rc = efc->tt.scsi_new_node(efc, node);
3462306a36Sopenharmony_ci	}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (rc < 0)
3762306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_FAIL, NULL);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (rc == EFC_SCSI_CALL_COMPLETE)
4062306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_OK, NULL);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void
4462306a36Sopenharmony_ci__efc_d_common(const char *funcname, struct efc_sm_ctx *ctx,
4562306a36Sopenharmony_ci	       enum efc_sm_event evt, void *arg)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct efc_node *node = NULL;
4862306a36Sopenharmony_ci	struct efc *efc = NULL;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	node = ctx->app;
5162306a36Sopenharmony_ci	efc = node->efc;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	switch (evt) {
5462306a36Sopenharmony_ci	/* Handle shutdown events */
5562306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN:
5662306a36Sopenharmony_ci		efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
5762306a36Sopenharmony_ci			      funcname, efc_sm_event_name(evt));
5862306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
5962306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
6062306a36Sopenharmony_ci		break;
6162306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
6262306a36Sopenharmony_ci		efc_log_debug(efc, "[%s] %-20s %-20s\n",
6362306a36Sopenharmony_ci			      node->display_name, funcname,
6462306a36Sopenharmony_ci				efc_sm_event_name(evt));
6562306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
6662306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
6762306a36Sopenharmony_ci		break;
6862306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
6962306a36Sopenharmony_ci		efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
7062306a36Sopenharmony_ci			      funcname, efc_sm_event_name(evt));
7162306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
7262306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
7362306a36Sopenharmony_ci		break;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	default:
7662306a36Sopenharmony_ci		/* call default event handler common to all nodes */
7762306a36Sopenharmony_ci		__efc_node_common(funcname, ctx, evt, arg);
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void
8262306a36Sopenharmony_ci__efc_d_wait_del_node(struct efc_sm_ctx *ctx,
8362306a36Sopenharmony_ci		      enum efc_sm_event evt, void *arg)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/*
9062306a36Sopenharmony_ci	 * State is entered when a node sends a delete initiator/target call
9162306a36Sopenharmony_ci	 * to the target-server/initiator-client and needs to wait for that
9262306a36Sopenharmony_ci	 * work to complete.
9362306a36Sopenharmony_ci	 */
9462306a36Sopenharmony_ci	node_sm_trace();
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	switch (evt) {
9762306a36Sopenharmony_ci	case EFC_EVT_ENTER:
9862306a36Sopenharmony_ci		efc_node_hold_frames(node);
9962306a36Sopenharmony_ci		fallthrough;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
10262306a36Sopenharmony_ci	case EFC_EVT_ALL_CHILD_NODES_FREE:
10362306a36Sopenharmony_ci		/* These are expected events. */
10462306a36Sopenharmony_ci		break;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	case EFC_EVT_NODE_DEL_INI_COMPLETE:
10762306a36Sopenharmony_ci	case EFC_EVT_NODE_DEL_TGT_COMPLETE:
10862306a36Sopenharmony_ci		/*
10962306a36Sopenharmony_ci		 * node has either been detached or is in the process
11062306a36Sopenharmony_ci		 * of being detached,
11162306a36Sopenharmony_ci		 * call common node's initiate cleanup function
11262306a36Sopenharmony_ci		 */
11362306a36Sopenharmony_ci		efc_node_initiate_cleanup(node);
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	case EFC_EVT_EXIT:
11762306a36Sopenharmony_ci		efc_node_accept_frames(node);
11862306a36Sopenharmony_ci		break;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_FAIL:
12162306a36Sopenharmony_ci		/* Can happen as ELS IO IO's complete */
12262306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
12362306a36Sopenharmony_ci		node->els_req_cnt--;
12462306a36Sopenharmony_ci		break;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* ignore shutdown events as we're already in shutdown path */
12762306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN:
12862306a36Sopenharmony_ci		/* have default shutdown event take precedence */
12962306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
13062306a36Sopenharmony_ci		fallthrough;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
13362306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
13462306a36Sopenharmony_ci		node_printf(node, "%s received\n", efc_sm_event_name(evt));
13562306a36Sopenharmony_ci		break;
13662306a36Sopenharmony_ci	case EFC_EVT_DOMAIN_ATTACH_OK:
13762306a36Sopenharmony_ci		/* don't care about domain_attach_ok */
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci	default:
14062306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic void
14562306a36Sopenharmony_ci__efc_d_wait_del_ini_tgt(struct efc_sm_ctx *ctx,
14662306a36Sopenharmony_ci			 enum efc_sm_event evt, void *arg)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	node_sm_trace();
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	switch (evt) {
15562306a36Sopenharmony_ci	case EFC_EVT_ENTER:
15662306a36Sopenharmony_ci		efc_node_hold_frames(node);
15762306a36Sopenharmony_ci		fallthrough;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
16062306a36Sopenharmony_ci	case EFC_EVT_ALL_CHILD_NODES_FREE:
16162306a36Sopenharmony_ci		/* These are expected events. */
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	case EFC_EVT_NODE_DEL_INI_COMPLETE:
16562306a36Sopenharmony_ci	case EFC_EVT_NODE_DEL_TGT_COMPLETE:
16662306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_del_node, NULL);
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	case EFC_EVT_EXIT:
17062306a36Sopenharmony_ci		efc_node_accept_frames(node);
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_FAIL:
17462306a36Sopenharmony_ci		/* Can happen as ELS IO IO's complete */
17562306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
17662306a36Sopenharmony_ci		node->els_req_cnt--;
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* ignore shutdown events as we're already in shutdown path */
18062306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN:
18162306a36Sopenharmony_ci		/* have default shutdown event take precedence */
18262306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
18362306a36Sopenharmony_ci		fallthrough;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
18662306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
18762306a36Sopenharmony_ci		node_printf(node, "%s received\n", efc_sm_event_name(evt));
18862306a36Sopenharmony_ci		break;
18962306a36Sopenharmony_ci	case EFC_EVT_DOMAIN_ATTACH_OK:
19062306a36Sopenharmony_ci		/* don't care about domain_attach_ok */
19162306a36Sopenharmony_ci		break;
19262306a36Sopenharmony_ci	default:
19362306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_civoid
19862306a36Sopenharmony_ci__efc_d_initiate_shutdown(struct efc_sm_ctx *ctx,
19962306a36Sopenharmony_ci			  enum efc_sm_event evt, void *arg)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
20262306a36Sopenharmony_ci	struct efc *efc = node->efc;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	node_sm_trace();
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	switch (evt) {
20962306a36Sopenharmony_ci	case EFC_EVT_ENTER: {
21062306a36Sopenharmony_ci		int rc = EFC_SCSI_CALL_COMPLETE;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		/* assume no wait needed */
21362306a36Sopenharmony_ci		node->els_io_enabled = false;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		/* make necessary delete upcall(s) */
21662306a36Sopenharmony_ci		if (node->init && !node->targ) {
21762306a36Sopenharmony_ci			efc_log_info(node->efc,
21862306a36Sopenharmony_ci				     "[%s] delete (initiator) WWPN %s WWNN %s\n",
21962306a36Sopenharmony_ci				node->display_name,
22062306a36Sopenharmony_ci				node->wwpn, node->wwnn);
22162306a36Sopenharmony_ci			efc_node_transition(node,
22262306a36Sopenharmony_ci					    __efc_d_wait_del_node,
22362306a36Sopenharmony_ci					     NULL);
22462306a36Sopenharmony_ci			if (node->nport->enable_tgt)
22562306a36Sopenharmony_ci				rc = efc->tt.scsi_del_node(efc, node,
22662306a36Sopenharmony_ci					EFC_SCSI_INITIATOR_DELETED);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci			if (rc == EFC_SCSI_CALL_COMPLETE || rc < 0)
22962306a36Sopenharmony_ci				efc_node_post_event(node,
23062306a36Sopenharmony_ci					EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		} else if (node->targ && !node->init) {
23362306a36Sopenharmony_ci			efc_log_info(node->efc,
23462306a36Sopenharmony_ci				     "[%s] delete (target) WWPN %s WWNN %s\n",
23562306a36Sopenharmony_ci				node->display_name,
23662306a36Sopenharmony_ci				node->wwpn, node->wwnn);
23762306a36Sopenharmony_ci			efc_node_transition(node,
23862306a36Sopenharmony_ci					    __efc_d_wait_del_node,
23962306a36Sopenharmony_ci					     NULL);
24062306a36Sopenharmony_ci			if (node->nport->enable_ini)
24162306a36Sopenharmony_ci				rc = efc->tt.scsi_del_node(efc, node,
24262306a36Sopenharmony_ci					EFC_SCSI_TARGET_DELETED);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci			if (rc == EFC_SCSI_CALL_COMPLETE)
24562306a36Sopenharmony_ci				efc_node_post_event(node,
24662306a36Sopenharmony_ci					EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		} else if (node->init && node->targ) {
24962306a36Sopenharmony_ci			efc_log_info(node->efc,
25062306a36Sopenharmony_ci				     "[%s] delete (I+T) WWPN %s WWNN %s\n",
25162306a36Sopenharmony_ci				node->display_name, node->wwpn, node->wwnn);
25262306a36Sopenharmony_ci			efc_node_transition(node, __efc_d_wait_del_ini_tgt,
25362306a36Sopenharmony_ci					    NULL);
25462306a36Sopenharmony_ci			if (node->nport->enable_tgt)
25562306a36Sopenharmony_ci				rc = efc->tt.scsi_del_node(efc, node,
25662306a36Sopenharmony_ci						EFC_SCSI_INITIATOR_DELETED);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci			if (rc == EFC_SCSI_CALL_COMPLETE)
25962306a36Sopenharmony_ci				efc_node_post_event(node,
26062306a36Sopenharmony_ci					EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
26162306a36Sopenharmony_ci			/* assume no wait needed */
26262306a36Sopenharmony_ci			rc = EFC_SCSI_CALL_COMPLETE;
26362306a36Sopenharmony_ci			if (node->nport->enable_ini)
26462306a36Sopenharmony_ci				rc = efc->tt.scsi_del_node(efc, node,
26562306a36Sopenharmony_ci						EFC_SCSI_TARGET_DELETED);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci			if (rc == EFC_SCSI_CALL_COMPLETE)
26862306a36Sopenharmony_ci				efc_node_post_event(node,
26962306a36Sopenharmony_ci					EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		/* we've initiated the upcalls as needed, now kick off the node
27362306a36Sopenharmony_ci		 * detach to precipitate the aborting of outstanding exchanges
27462306a36Sopenharmony_ci		 * associated with said node
27562306a36Sopenharmony_ci		 *
27662306a36Sopenharmony_ci		 * Beware: if we've made upcall(s), we've already transitioned
27762306a36Sopenharmony_ci		 * to a new state by the time we execute this.
27862306a36Sopenharmony_ci		 * consider doing this before the upcalls?
27962306a36Sopenharmony_ci		 */
28062306a36Sopenharmony_ci		if (node->attached) {
28162306a36Sopenharmony_ci			/* issue hw node free; don't care if succeeds right
28262306a36Sopenharmony_ci			 * away or sometime later, will check node->attached
28362306a36Sopenharmony_ci			 * later in shutdown process
28462306a36Sopenharmony_ci			 */
28562306a36Sopenharmony_ci			rc = efc_cmd_node_detach(efc, &node->rnode);
28662306a36Sopenharmony_ci			if (rc < 0)
28762306a36Sopenharmony_ci				node_printf(node,
28862306a36Sopenharmony_ci					    "Failed freeing HW node, rc=%d\n",
28962306a36Sopenharmony_ci					rc);
29062306a36Sopenharmony_ci		}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		/* if neither initiator nor target, proceed to cleanup */
29362306a36Sopenharmony_ci		if (!node->init && !node->targ) {
29462306a36Sopenharmony_ci			/*
29562306a36Sopenharmony_ci			 * node has either been detached or is in
29662306a36Sopenharmony_ci			 * the process of being detached,
29762306a36Sopenharmony_ci			 * call common node's initiate cleanup function
29862306a36Sopenharmony_ci			 */
29962306a36Sopenharmony_ci			efc_node_initiate_cleanup(node);
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci	case EFC_EVT_ALL_CHILD_NODES_FREE:
30462306a36Sopenharmony_ci		/* Ignore, this can happen if an ELS is
30562306a36Sopenharmony_ci		 * aborted while in a delay/retry state
30662306a36Sopenharmony_ci		 */
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	default:
30962306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_civoid
31462306a36Sopenharmony_ci__efc_d_wait_loop(struct efc_sm_ctx *ctx,
31562306a36Sopenharmony_ci		  enum efc_sm_event evt, void *arg)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	node_sm_trace();
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	switch (evt) {
32462306a36Sopenharmony_ci	case EFC_EVT_ENTER:
32562306a36Sopenharmony_ci		efc_node_hold_frames(node);
32662306a36Sopenharmony_ci		break;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	case EFC_EVT_EXIT:
32962306a36Sopenharmony_ci		efc_node_accept_frames(node);
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	case EFC_EVT_DOMAIN_ATTACH_OK: {
33362306a36Sopenharmony_ci		/* send PLOGI automatically if initiator */
33462306a36Sopenharmony_ci		efc_node_init_device(node, true);
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci	default:
33862306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_civoid
34362306a36Sopenharmony_ciefc_send_ls_acc_after_attach(struct efc_node *node,
34462306a36Sopenharmony_ci			     struct fc_frame_header *hdr,
34562306a36Sopenharmony_ci			     enum efc_node_send_ls_acc ls)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	u16 ox_id = be16_to_cpu(hdr->fh_ox_id);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* Save the OX_ID for sending LS_ACC sometime later */
35062306a36Sopenharmony_ci	WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_NONE);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	node->ls_acc_oxid = ox_id;
35362306a36Sopenharmony_ci	node->send_ls_acc = ls;
35462306a36Sopenharmony_ci	node->ls_acc_did = ntoh24(hdr->fh_d_id);
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_civoid
35862306a36Sopenharmony_ciefc_process_prli_payload(struct efc_node *node, void *prli)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct {
36162306a36Sopenharmony_ci		struct fc_els_prli prli;
36262306a36Sopenharmony_ci		struct fc_els_spp sp;
36362306a36Sopenharmony_ci	} *pp;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	pp = prli;
36662306a36Sopenharmony_ci	node->init = (pp->sp.spp_flags & FCP_SPPF_INIT_FCN) != 0;
36762306a36Sopenharmony_ci	node->targ = (pp->sp.spp_flags & FCP_SPPF_TARG_FCN) != 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid
37162306a36Sopenharmony_ci__efc_d_wait_plogi_acc_cmpl(struct efc_sm_ctx *ctx,
37262306a36Sopenharmony_ci			    enum efc_sm_event evt, void *arg)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	node_sm_trace();
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	switch (evt) {
38162306a36Sopenharmony_ci	case EFC_EVT_ENTER:
38262306a36Sopenharmony_ci		efc_node_hold_frames(node);
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	case EFC_EVT_EXIT:
38662306a36Sopenharmony_ci		efc_node_accept_frames(node);
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_CMPL_FAIL:
39062306a36Sopenharmony_ci		WARN_ON(!node->els_cmpl_cnt);
39162306a36Sopenharmony_ci		node->els_cmpl_cnt--;
39262306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
39362306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
39462306a36Sopenharmony_ci		break;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_CMPL_OK:	/* PLOGI ACC completions */
39762306a36Sopenharmony_ci		WARN_ON(!node->els_cmpl_cnt);
39862306a36Sopenharmony_ci		node->els_cmpl_cnt--;
39962306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_port_logged_in, NULL);
40062306a36Sopenharmony_ci		break;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	default:
40362306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_civoid
40862306a36Sopenharmony_ci__efc_d_wait_logo_rsp(struct efc_sm_ctx *ctx,
40962306a36Sopenharmony_ci		      enum efc_sm_event evt, void *arg)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	node_sm_trace();
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	switch (evt) {
41862306a36Sopenharmony_ci	case EFC_EVT_ENTER:
41962306a36Sopenharmony_ci		efc_node_hold_frames(node);
42062306a36Sopenharmony_ci		break;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	case EFC_EVT_EXIT:
42362306a36Sopenharmony_ci		efc_node_accept_frames(node);
42462306a36Sopenharmony_ci		break;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_OK:
42762306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_RJT:
42862306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_FAIL:
42962306a36Sopenharmony_ci		/* LOGO response received, sent shutdown */
43062306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_LOGO,
43162306a36Sopenharmony_ci					   __efc_d_common, __func__))
43262306a36Sopenharmony_ci			return;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
43562306a36Sopenharmony_ci		node->els_req_cnt--;
43662306a36Sopenharmony_ci		node_printf(node,
43762306a36Sopenharmony_ci			    "LOGO sent (evt=%s), shutdown node\n",
43862306a36Sopenharmony_ci			efc_sm_event_name(evt));
43962306a36Sopenharmony_ci		/* sm: / post explicit logout */
44062306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
44162306a36Sopenharmony_ci				    NULL);
44262306a36Sopenharmony_ci		break;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	default:
44562306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_civoid
45062306a36Sopenharmony_ciefc_node_init_device(struct efc_node *node, bool send_plogi)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	node->send_plogi = send_plogi;
45362306a36Sopenharmony_ci	if ((node->efc->nodedb_mask & EFC_NODEDB_PAUSE_NEW_NODES) &&
45462306a36Sopenharmony_ci	    (node->rnode.fc_id != FC_FID_DOM_MGR)) {
45562306a36Sopenharmony_ci		node->nodedb_state = __efc_d_init;
45662306a36Sopenharmony_ci		efc_node_transition(node, __efc_node_paused, NULL);
45762306a36Sopenharmony_ci	} else {
45862306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_init, NULL);
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic void
46362306a36Sopenharmony_ciefc_d_check_plogi_topology(struct efc_node *node, u32 d_id)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	switch (node->nport->topology) {
46662306a36Sopenharmony_ci	case EFC_NPORT_TOPO_P2P:
46762306a36Sopenharmony_ci		/* we're not attached and nport is p2p,
46862306a36Sopenharmony_ci		 * need to attach
46962306a36Sopenharmony_ci		 */
47062306a36Sopenharmony_ci		efc_domain_attach(node->nport->domain, d_id);
47162306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
47262306a36Sopenharmony_ci		break;
47362306a36Sopenharmony_ci	case EFC_NPORT_TOPO_FABRIC:
47462306a36Sopenharmony_ci		/* we're not attached and nport is fabric, domain
47562306a36Sopenharmony_ci		 * attach should have already been requested as part
47662306a36Sopenharmony_ci		 * of the fabric state machine, wait for it
47762306a36Sopenharmony_ci		 */
47862306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
47962306a36Sopenharmony_ci		break;
48062306a36Sopenharmony_ci	case EFC_NPORT_TOPO_UNKNOWN:
48162306a36Sopenharmony_ci		/* Two possibilities:
48262306a36Sopenharmony_ci		 * 1. received a PLOGI before our FLOGI has completed
48362306a36Sopenharmony_ci		 *    (possible since completion comes in on another
48462306a36Sopenharmony_ci		 *    CQ), thus we don't know what we're connected to
48562306a36Sopenharmony_ci		 *    yet; transition to a state to wait for the
48662306a36Sopenharmony_ci		 *    fabric node to tell us;
48762306a36Sopenharmony_ci		 * 2. PLOGI received before link went down and we
48862306a36Sopenharmony_ci		 * haven't performed domain attach yet.
48962306a36Sopenharmony_ci		 * Note: we cannot distinguish between 1. and 2.
49062306a36Sopenharmony_ci		 * so have to assume PLOGI
49162306a36Sopenharmony_ci		 * was received after link back up.
49262306a36Sopenharmony_ci		 */
49362306a36Sopenharmony_ci		node_printf(node, "received PLOGI, unknown topology did=0x%x\n",
49462306a36Sopenharmony_ci			    d_id);
49562306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_topology_notify, NULL);
49662306a36Sopenharmony_ci		break;
49762306a36Sopenharmony_ci	default:
49862306a36Sopenharmony_ci		node_printf(node, "received PLOGI, unexpected topology %d\n",
49962306a36Sopenharmony_ci			    node->nport->topology);
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_civoid
50462306a36Sopenharmony_ci__efc_d_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct efc_node_cb *cbdata = arg;
50762306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	node_sm_trace();
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/*
51462306a36Sopenharmony_ci	 * This state is entered when a node is instantiated,
51562306a36Sopenharmony_ci	 * either having been discovered from a name services query,
51662306a36Sopenharmony_ci	 * or having received a PLOGI/FLOGI.
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	switch (evt) {
51962306a36Sopenharmony_ci	case EFC_EVT_ENTER:
52062306a36Sopenharmony_ci		if (!node->send_plogi)
52162306a36Sopenharmony_ci			break;
52262306a36Sopenharmony_ci		/* only send if we have initiator capability,
52362306a36Sopenharmony_ci		 * and domain is attached
52462306a36Sopenharmony_ci		 */
52562306a36Sopenharmony_ci		if (node->nport->enable_ini &&
52662306a36Sopenharmony_ci		    node->nport->domain->attached) {
52762306a36Sopenharmony_ci			efc_send_plogi(node);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci			efc_node_transition(node, __efc_d_wait_plogi_rsp, NULL);
53062306a36Sopenharmony_ci		} else {
53162306a36Sopenharmony_ci			node_printf(node, "not sending plogi nport.ini=%d,",
53262306a36Sopenharmony_ci				    node->nport->enable_ini);
53362306a36Sopenharmony_ci			node_printf(node, "domain attached=%d\n",
53462306a36Sopenharmony_ci				    node->nport->domain->attached);
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci		break;
53762306a36Sopenharmony_ci	case EFC_EVT_PLOGI_RCVD: {
53862306a36Sopenharmony_ci		/* T, or I+T */
53962306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
54062306a36Sopenharmony_ci		int rc;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		efc_node_save_sparms(node, cbdata->payload->dma.virt);
54362306a36Sopenharmony_ci		efc_send_ls_acc_after_attach(node,
54462306a36Sopenharmony_ci					     cbdata->header->dma.virt,
54562306a36Sopenharmony_ci					     EFC_NODE_SEND_LS_ACC_PLOGI);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/* domain not attached; several possibilities: */
54862306a36Sopenharmony_ci		if (!node->nport->domain->attached) {
54962306a36Sopenharmony_ci			efc_d_check_plogi_topology(node, ntoh24(hdr->fh_d_id));
55062306a36Sopenharmony_ci			break;
55162306a36Sopenharmony_ci		}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		/* domain already attached */
55462306a36Sopenharmony_ci		rc = efc_node_attach(node);
55562306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
55662306a36Sopenharmony_ci		if (rc < 0)
55762306a36Sopenharmony_ci			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, NULL);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		break;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	case EFC_EVT_FDISC_RCVD: {
56362306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
56462306a36Sopenharmony_ci		break;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	case EFC_EVT_FLOGI_RCVD: {
56862306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
56962306a36Sopenharmony_ci		u32 d_id = ntoh24(hdr->fh_d_id);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		/* sm: / save sparams, send FLOGI acc */
57262306a36Sopenharmony_ci		memcpy(node->nport->domain->flogi_service_params,
57362306a36Sopenharmony_ci		       cbdata->payload->dma.virt,
57462306a36Sopenharmony_ci		       sizeof(struct fc_els_flogi));
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		/* send FC LS_ACC response, override s_id */
57762306a36Sopenharmony_ci		efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		efc_send_flogi_p2p_acc(node, be16_to_cpu(hdr->fh_ox_id), d_id);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		if (efc_p2p_setup(node->nport)) {
58262306a36Sopenharmony_ci			node_printf(node, "p2p failed, shutting down node\n");
58362306a36Sopenharmony_ci			efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
58462306a36Sopenharmony_ci			break;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci		efc_node_transition(node,  __efc_p2p_wait_flogi_acc_cmpl, NULL);
58862306a36Sopenharmony_ci		break;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	case EFC_EVT_LOGO_RCVD: {
59262306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		if (!node->nport->domain->attached) {
59562306a36Sopenharmony_ci			/* most likely a frame left over from before a link
59662306a36Sopenharmony_ci			 * down; drop and
59762306a36Sopenharmony_ci			 * shut node down w/ "explicit logout" so pending
59862306a36Sopenharmony_ci			 * frames are processed
59962306a36Sopenharmony_ci			 */
60062306a36Sopenharmony_ci			node_printf(node, "%s domain not attached, dropping\n",
60162306a36Sopenharmony_ci				    efc_sm_event_name(evt));
60262306a36Sopenharmony_ci			efc_node_post_event(node,
60362306a36Sopenharmony_ci					EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
60462306a36Sopenharmony_ci			break;
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
60862306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	case EFC_EVT_PRLI_RCVD:
61362306a36Sopenharmony_ci	case EFC_EVT_PRLO_RCVD:
61462306a36Sopenharmony_ci	case EFC_EVT_PDISC_RCVD:
61562306a36Sopenharmony_ci	case EFC_EVT_ADISC_RCVD:
61662306a36Sopenharmony_ci	case EFC_EVT_RSCN_RCVD: {
61762306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		if (!node->nport->domain->attached) {
62062306a36Sopenharmony_ci			/* most likely a frame left over from before a link
62162306a36Sopenharmony_ci			 * down; drop and shut node down w/ "explicit logout"
62262306a36Sopenharmony_ci			 * so pending frames are processed
62362306a36Sopenharmony_ci			 */
62462306a36Sopenharmony_ci			node_printf(node, "%s domain not attached, dropping\n",
62562306a36Sopenharmony_ci				    efc_sm_event_name(evt));
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci			efc_node_post_event(node,
62862306a36Sopenharmony_ci					    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
62962306a36Sopenharmony_ci					    NULL);
63062306a36Sopenharmony_ci			break;
63162306a36Sopenharmony_ci		}
63262306a36Sopenharmony_ci		node_printf(node, "%s received, sending reject\n",
63362306a36Sopenharmony_ci			    efc_sm_event_name(evt));
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
63662306a36Sopenharmony_ci				ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci		break;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	case EFC_EVT_FCP_CMD_RCVD: {
64262306a36Sopenharmony_ci		/* note: problem, we're now expecting an ELS REQ completion
64362306a36Sopenharmony_ci		 * from both the LOGO and PLOGI
64462306a36Sopenharmony_ci		 */
64562306a36Sopenharmony_ci		if (!node->nport->domain->attached) {
64662306a36Sopenharmony_ci			/* most likely a frame left over from before a
64762306a36Sopenharmony_ci			 * link down; drop and
64862306a36Sopenharmony_ci			 * shut node down w/ "explicit logout" so pending
64962306a36Sopenharmony_ci			 * frames are processed
65062306a36Sopenharmony_ci			 */
65162306a36Sopenharmony_ci			node_printf(node, "%s domain not attached, dropping\n",
65262306a36Sopenharmony_ci				    efc_sm_event_name(evt));
65362306a36Sopenharmony_ci			efc_node_post_event(node,
65462306a36Sopenharmony_ci					    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
65562306a36Sopenharmony_ci					    NULL);
65662306a36Sopenharmony_ci			break;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		/* Send LOGO */
66062306a36Sopenharmony_ci		node_printf(node, "FCP_CMND received, send LOGO\n");
66162306a36Sopenharmony_ci		if (efc_send_logo(node)) {
66262306a36Sopenharmony_ci			/*
66362306a36Sopenharmony_ci			 * failed to send LOGO, go ahead and cleanup node
66462306a36Sopenharmony_ci			 * anyways
66562306a36Sopenharmony_ci			 */
66662306a36Sopenharmony_ci			node_printf(node, "Failed to send LOGO\n");
66762306a36Sopenharmony_ci			efc_node_post_event(node,
66862306a36Sopenharmony_ci					    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
66962306a36Sopenharmony_ci					    NULL);
67062306a36Sopenharmony_ci		} else {
67162306a36Sopenharmony_ci			/* sent LOGO, wait for response */
67262306a36Sopenharmony_ci			efc_node_transition(node,
67362306a36Sopenharmony_ci					    __efc_d_wait_logo_rsp, NULL);
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci		break;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	case EFC_EVT_DOMAIN_ATTACH_OK:
67862306a36Sopenharmony_ci		/* don't care about domain_attach_ok */
67962306a36Sopenharmony_ci		break;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	default:
68262306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_civoid
68762306a36Sopenharmony_ci__efc_d_wait_plogi_rsp(struct efc_sm_ctx *ctx,
68862306a36Sopenharmony_ci		       enum efc_sm_event evt, void *arg)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	int rc;
69162306a36Sopenharmony_ci	struct efc_node_cb *cbdata = arg;
69262306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	node_sm_trace();
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	switch (evt) {
69962306a36Sopenharmony_ci	case EFC_EVT_PLOGI_RCVD: {
70062306a36Sopenharmony_ci		/* T, or I+T */
70162306a36Sopenharmony_ci		/* received PLOGI with svc parms, go ahead and attach node
70262306a36Sopenharmony_ci		 * when PLOGI that was sent ultimately completes, it'll be a
70362306a36Sopenharmony_ci		 * no-op
70462306a36Sopenharmony_ci		 *
70562306a36Sopenharmony_ci		 * If there is an outstanding PLOGI sent, can we set a flag
70662306a36Sopenharmony_ci		 * to indicate that we don't want to retry it if it times out?
70762306a36Sopenharmony_ci		 */
70862306a36Sopenharmony_ci		efc_node_save_sparms(node, cbdata->payload->dma.virt);
70962306a36Sopenharmony_ci		efc_send_ls_acc_after_attach(node,
71062306a36Sopenharmony_ci					     cbdata->header->dma.virt,
71162306a36Sopenharmony_ci				EFC_NODE_SEND_LS_ACC_PLOGI);
71262306a36Sopenharmony_ci		/* sm: domain->attached / efc_node_attach */
71362306a36Sopenharmony_ci		rc = efc_node_attach(node);
71462306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
71562306a36Sopenharmony_ci		if (rc < 0)
71662306a36Sopenharmony_ci			efc_node_post_event(node,
71762306a36Sopenharmony_ci					    EFC_EVT_NODE_ATTACH_FAIL, NULL);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci		break;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	case EFC_EVT_PRLI_RCVD:
72362306a36Sopenharmony_ci		/* I, or I+T */
72462306a36Sopenharmony_ci		/* sent PLOGI and before completion was seen, received the
72562306a36Sopenharmony_ci		 * PRLI from the remote node (WCQEs and RCQEs come in on
72662306a36Sopenharmony_ci		 * different queues and order of processing cannot be assumed)
72762306a36Sopenharmony_ci		 * Save OXID so PRLI can be sent after the attach and continue
72862306a36Sopenharmony_ci		 * to wait for PLOGI response
72962306a36Sopenharmony_ci		 */
73062306a36Sopenharmony_ci		efc_process_prli_payload(node, cbdata->payload->dma.virt);
73162306a36Sopenharmony_ci		efc_send_ls_acc_after_attach(node,
73262306a36Sopenharmony_ci					     cbdata->header->dma.virt,
73362306a36Sopenharmony_ci				EFC_NODE_SEND_LS_ACC_PRLI);
73462306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_plogi_rsp_recvd_prli,
73562306a36Sopenharmony_ci				    NULL);
73662306a36Sopenharmony_ci		break;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	case EFC_EVT_LOGO_RCVD: /* why don't we do a shutdown here?? */
73962306a36Sopenharmony_ci	case EFC_EVT_PRLO_RCVD:
74062306a36Sopenharmony_ci	case EFC_EVT_PDISC_RCVD:
74162306a36Sopenharmony_ci	case EFC_EVT_FDISC_RCVD:
74262306a36Sopenharmony_ci	case EFC_EVT_ADISC_RCVD:
74362306a36Sopenharmony_ci	case EFC_EVT_RSCN_RCVD:
74462306a36Sopenharmony_ci	case EFC_EVT_SCR_RCVD: {
74562306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		node_printf(node, "%s received, sending reject\n",
74862306a36Sopenharmony_ci			    efc_sm_event_name(evt));
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
75162306a36Sopenharmony_ci				ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		break;
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
75762306a36Sopenharmony_ci		/* Completion from PLOGI sent */
75862306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
75962306a36Sopenharmony_ci					   __efc_d_common, __func__))
76062306a36Sopenharmony_ci			return;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
76362306a36Sopenharmony_ci		node->els_req_cnt--;
76462306a36Sopenharmony_ci		/* sm: / save sparams, efc_node_attach */
76562306a36Sopenharmony_ci		efc_node_save_sparms(node, cbdata->els_rsp.virt);
76662306a36Sopenharmony_ci		rc = efc_node_attach(node);
76762306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
76862306a36Sopenharmony_ci		if (rc < 0)
76962306a36Sopenharmony_ci			efc_node_post_event(node,
77062306a36Sopenharmony_ci					    EFC_EVT_NODE_ATTACH_FAIL, NULL);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		break;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
77562306a36Sopenharmony_ci		/* PLOGI failed, shutdown the node */
77662306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
77762306a36Sopenharmony_ci					   __efc_d_common, __func__))
77862306a36Sopenharmony_ci			return;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
78162306a36Sopenharmony_ci		node->els_req_cnt--;
78262306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
78362306a36Sopenharmony_ci		break;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_RJT:
78662306a36Sopenharmony_ci		/* Our PLOGI was rejected, this is ok in some cases */
78762306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
78862306a36Sopenharmony_ci					   __efc_d_common, __func__))
78962306a36Sopenharmony_ci			return;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
79262306a36Sopenharmony_ci		node->els_req_cnt--;
79362306a36Sopenharmony_ci		break;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	case EFC_EVT_FCP_CMD_RCVD: {
79662306a36Sopenharmony_ci		/* not logged in yet and outstanding PLOGI so don't send LOGO,
79762306a36Sopenharmony_ci		 * just drop
79862306a36Sopenharmony_ci		 */
79962306a36Sopenharmony_ci		node_printf(node, "FCP_CMND received, drop\n");
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	default:
80462306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_civoid
80962306a36Sopenharmony_ci__efc_d_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
81062306a36Sopenharmony_ci				  enum efc_sm_event evt, void *arg)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	int rc;
81362306a36Sopenharmony_ci	struct efc_node_cb *cbdata = arg;
81462306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	node_sm_trace();
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	switch (evt) {
82162306a36Sopenharmony_ci	case EFC_EVT_ENTER:
82262306a36Sopenharmony_ci		/*
82362306a36Sopenharmony_ci		 * Since we've received a PRLI, we have a port login and will
82462306a36Sopenharmony_ci		 * just need to wait for the PLOGI response to do the node
82562306a36Sopenharmony_ci		 * attach and then we can send the LS_ACC for the PRLI. If,
82662306a36Sopenharmony_ci		 * during this time, we receive FCP_CMNDs (which is possible
82762306a36Sopenharmony_ci		 * since we've already sent a PRLI and our peer may have
82862306a36Sopenharmony_ci		 * accepted). At this time, we are not waiting on any other
82962306a36Sopenharmony_ci		 * unsolicited frames to continue with the login process. Thus,
83062306a36Sopenharmony_ci		 * it will not hurt to hold frames here.
83162306a36Sopenharmony_ci		 */
83262306a36Sopenharmony_ci		efc_node_hold_frames(node);
83362306a36Sopenharmony_ci		break;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	case EFC_EVT_EXIT:
83662306a36Sopenharmony_ci		efc_node_accept_frames(node);
83762306a36Sopenharmony_ci		break;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
84062306a36Sopenharmony_ci		/* Completion from PLOGI sent */
84162306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
84262306a36Sopenharmony_ci					   __efc_d_common, __func__))
84362306a36Sopenharmony_ci			return;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
84662306a36Sopenharmony_ci		node->els_req_cnt--;
84762306a36Sopenharmony_ci		/* sm: / save sparams, efc_node_attach */
84862306a36Sopenharmony_ci		efc_node_save_sparms(node, cbdata->els_rsp.virt);
84962306a36Sopenharmony_ci		rc = efc_node_attach(node);
85062306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
85162306a36Sopenharmony_ci		if (rc < 0)
85262306a36Sopenharmony_ci			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
85362306a36Sopenharmony_ci					    NULL);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci		break;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
85862306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_RJT:
85962306a36Sopenharmony_ci		/* PLOGI failed, shutdown the node */
86062306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
86162306a36Sopenharmony_ci					   __efc_d_common, __func__))
86262306a36Sopenharmony_ci			return;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
86562306a36Sopenharmony_ci		node->els_req_cnt--;
86662306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
86762306a36Sopenharmony_ci		break;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	default:
87062306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_civoid
87562306a36Sopenharmony_ci__efc_d_wait_domain_attach(struct efc_sm_ctx *ctx,
87662306a36Sopenharmony_ci			   enum efc_sm_event evt, void *arg)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	int rc;
87962306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	node_sm_trace();
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	switch (evt) {
88662306a36Sopenharmony_ci	case EFC_EVT_ENTER:
88762306a36Sopenharmony_ci		efc_node_hold_frames(node);
88862306a36Sopenharmony_ci		break;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	case EFC_EVT_EXIT:
89162306a36Sopenharmony_ci		efc_node_accept_frames(node);
89262306a36Sopenharmony_ci		break;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	case EFC_EVT_DOMAIN_ATTACH_OK:
89562306a36Sopenharmony_ci		WARN_ON(!node->nport->domain->attached);
89662306a36Sopenharmony_ci		/* sm: / efc_node_attach */
89762306a36Sopenharmony_ci		rc = efc_node_attach(node);
89862306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
89962306a36Sopenharmony_ci		if (rc < 0)
90062306a36Sopenharmony_ci			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
90162306a36Sopenharmony_ci					    NULL);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		break;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	default:
90662306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_civoid
91162306a36Sopenharmony_ci__efc_d_wait_topology_notify(struct efc_sm_ctx *ctx,
91262306a36Sopenharmony_ci			     enum efc_sm_event evt, void *arg)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	int rc;
91562306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	node_sm_trace();
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	switch (evt) {
92262306a36Sopenharmony_ci	case EFC_EVT_ENTER:
92362306a36Sopenharmony_ci		efc_node_hold_frames(node);
92462306a36Sopenharmony_ci		break;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	case EFC_EVT_EXIT:
92762306a36Sopenharmony_ci		efc_node_accept_frames(node);
92862306a36Sopenharmony_ci		break;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	case EFC_EVT_NPORT_TOPOLOGY_NOTIFY: {
93162306a36Sopenharmony_ci		enum efc_nport_topology *topology = arg;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		WARN_ON(node->nport->domain->attached);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci		WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_PLOGI);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		node_printf(node, "topology notification, topology=%d\n",
93862306a36Sopenharmony_ci			    *topology);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		/* At the time the PLOGI was received, the topology was unknown,
94162306a36Sopenharmony_ci		 * so we didn't know which node would perform the domain attach:
94262306a36Sopenharmony_ci		 * 1. The node from which the PLOGI was sent (p2p) or
94362306a36Sopenharmony_ci		 * 2. The node to which the FLOGI was sent (fabric).
94462306a36Sopenharmony_ci		 */
94562306a36Sopenharmony_ci		if (*topology == EFC_NPORT_TOPO_P2P) {
94662306a36Sopenharmony_ci			/* if this is p2p, need to attach to the domain using
94762306a36Sopenharmony_ci			 * the d_id from the PLOGI received
94862306a36Sopenharmony_ci			 */
94962306a36Sopenharmony_ci			efc_domain_attach(node->nport->domain,
95062306a36Sopenharmony_ci					  node->ls_acc_did);
95162306a36Sopenharmony_ci		}
95262306a36Sopenharmony_ci		/* else, if this is fabric, the domain attach
95362306a36Sopenharmony_ci		 * should be performed by the fabric node (node sending FLOGI);
95462306a36Sopenharmony_ci		 * just wait for attach to complete
95562306a36Sopenharmony_ci		 */
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
95862306a36Sopenharmony_ci		break;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci	case EFC_EVT_DOMAIN_ATTACH_OK:
96162306a36Sopenharmony_ci		WARN_ON(!node->nport->domain->attached);
96262306a36Sopenharmony_ci		node_printf(node, "domain attach ok\n");
96362306a36Sopenharmony_ci		/* sm: / efc_node_attach */
96462306a36Sopenharmony_ci		rc = efc_node_attach(node);
96562306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
96662306a36Sopenharmony_ci		if (rc < 0)
96762306a36Sopenharmony_ci			efc_node_post_event(node,
96862306a36Sopenharmony_ci					    EFC_EVT_NODE_ATTACH_FAIL, NULL);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci		break;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	default:
97362306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_civoid
97862306a36Sopenharmony_ci__efc_d_wait_node_attach(struct efc_sm_ctx *ctx,
97962306a36Sopenharmony_ci			 enum efc_sm_event evt, void *arg)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	node_sm_trace();
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	switch (evt) {
98862306a36Sopenharmony_ci	case EFC_EVT_ENTER:
98962306a36Sopenharmony_ci		efc_node_hold_frames(node);
99062306a36Sopenharmony_ci		break;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	case EFC_EVT_EXIT:
99362306a36Sopenharmony_ci		efc_node_accept_frames(node);
99462306a36Sopenharmony_ci		break;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	case EFC_EVT_NODE_ATTACH_OK:
99762306a36Sopenharmony_ci		node->attached = true;
99862306a36Sopenharmony_ci		switch (node->send_ls_acc) {
99962306a36Sopenharmony_ci		case EFC_NODE_SEND_LS_ACC_PLOGI: {
100062306a36Sopenharmony_ci			/* sm: send_plogi_acc is set / send PLOGI acc */
100162306a36Sopenharmony_ci			/* Normal case for T, or I+T */
100262306a36Sopenharmony_ci			efc_send_plogi_acc(node, node->ls_acc_oxid);
100362306a36Sopenharmony_ci			efc_node_transition(node, __efc_d_wait_plogi_acc_cmpl,
100462306a36Sopenharmony_ci					    NULL);
100562306a36Sopenharmony_ci			node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
100662306a36Sopenharmony_ci			node->ls_acc_io = NULL;
100762306a36Sopenharmony_ci			break;
100862306a36Sopenharmony_ci		}
100962306a36Sopenharmony_ci		case EFC_NODE_SEND_LS_ACC_PRLI: {
101062306a36Sopenharmony_ci			efc_d_send_prli_rsp(node, node->ls_acc_oxid);
101162306a36Sopenharmony_ci			node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
101262306a36Sopenharmony_ci			node->ls_acc_io = NULL;
101362306a36Sopenharmony_ci			break;
101462306a36Sopenharmony_ci		}
101562306a36Sopenharmony_ci		case EFC_NODE_SEND_LS_ACC_NONE:
101662306a36Sopenharmony_ci		default:
101762306a36Sopenharmony_ci			/* Normal case for I */
101862306a36Sopenharmony_ci			/* sm: send_plogi_acc is not set / send PLOGI acc */
101962306a36Sopenharmony_ci			efc_node_transition(node,
102062306a36Sopenharmony_ci					    __efc_d_port_logged_in, NULL);
102162306a36Sopenharmony_ci			break;
102262306a36Sopenharmony_ci		}
102362306a36Sopenharmony_ci		break;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	case EFC_EVT_NODE_ATTACH_FAIL:
102662306a36Sopenharmony_ci		/* node attach failed, shutdown the node */
102762306a36Sopenharmony_ci		node->attached = false;
102862306a36Sopenharmony_ci		node_printf(node, "node attach failed\n");
102962306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
103062306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
103162306a36Sopenharmony_ci		break;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	/* Handle shutdown events */
103462306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN:
103562306a36Sopenharmony_ci		node_printf(node, "%s received\n", efc_sm_event_name(evt));
103662306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
103762306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_attach_evt_shutdown,
103862306a36Sopenharmony_ci				    NULL);
103962306a36Sopenharmony_ci		break;
104062306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
104162306a36Sopenharmony_ci		node_printf(node, "%s received\n", efc_sm_event_name(evt));
104262306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
104362306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_attach_evt_shutdown,
104462306a36Sopenharmony_ci				    NULL);
104562306a36Sopenharmony_ci		break;
104662306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
104762306a36Sopenharmony_ci		node_printf(node, "%s received\n", efc_sm_event_name(evt));
104862306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
104962306a36Sopenharmony_ci		efc_node_transition(node,
105062306a36Sopenharmony_ci				    __efc_d_wait_attach_evt_shutdown, NULL);
105162306a36Sopenharmony_ci		break;
105262306a36Sopenharmony_ci	default:
105362306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_civoid
105862306a36Sopenharmony_ci__efc_d_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
105962306a36Sopenharmony_ci				 enum efc_sm_event evt, void *arg)
106062306a36Sopenharmony_ci{
106162306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	node_sm_trace();
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	switch (evt) {
106862306a36Sopenharmony_ci	case EFC_EVT_ENTER:
106962306a36Sopenharmony_ci		efc_node_hold_frames(node);
107062306a36Sopenharmony_ci		break;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	case EFC_EVT_EXIT:
107362306a36Sopenharmony_ci		efc_node_accept_frames(node);
107462306a36Sopenharmony_ci		break;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	/* wait for any of these attach events and then shutdown */
107762306a36Sopenharmony_ci	case EFC_EVT_NODE_ATTACH_OK:
107862306a36Sopenharmony_ci		node->attached = true;
107962306a36Sopenharmony_ci		node_printf(node, "Attach evt=%s, proceed to shutdown\n",
108062306a36Sopenharmony_ci			    efc_sm_event_name(evt));
108162306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
108262306a36Sopenharmony_ci		break;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	case EFC_EVT_NODE_ATTACH_FAIL:
108562306a36Sopenharmony_ci		/* node attach failed, shutdown the node */
108662306a36Sopenharmony_ci		node->attached = false;
108762306a36Sopenharmony_ci		node_printf(node, "Attach evt=%s, proceed to shutdown\n",
108862306a36Sopenharmony_ci			    efc_sm_event_name(evt));
108962306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
109062306a36Sopenharmony_ci		break;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	/* ignore shutdown events as we're already in shutdown path */
109362306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN:
109462306a36Sopenharmony_ci		/* have default shutdown event take precedence */
109562306a36Sopenharmony_ci		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
109662306a36Sopenharmony_ci		fallthrough;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
109962306a36Sopenharmony_ci	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
110062306a36Sopenharmony_ci		node_printf(node, "%s received\n", efc_sm_event_name(evt));
110162306a36Sopenharmony_ci		break;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	default:
110462306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_civoid
110962306a36Sopenharmony_ci__efc_d_port_logged_in(struct efc_sm_ctx *ctx,
111062306a36Sopenharmony_ci		       enum efc_sm_event evt, void *arg)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	struct efc_node_cb *cbdata = arg;
111362306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	node_sm_trace();
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	switch (evt) {
112062306a36Sopenharmony_ci	case EFC_EVT_ENTER:
112162306a36Sopenharmony_ci		/* Normal case for I or I+T */
112262306a36Sopenharmony_ci		if (node->nport->enable_ini &&
112362306a36Sopenharmony_ci		    !(node->rnode.fc_id != FC_FID_DOM_MGR)) {
112462306a36Sopenharmony_ci			/* sm: if enable_ini / send PRLI */
112562306a36Sopenharmony_ci			efc_send_prli(node);
112662306a36Sopenharmony_ci			/* can now expect ELS_REQ_OK/FAIL/RJT */
112762306a36Sopenharmony_ci		}
112862306a36Sopenharmony_ci		break;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	case EFC_EVT_FCP_CMD_RCVD: {
113162306a36Sopenharmony_ci		break;
113262306a36Sopenharmony_ci	}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	case EFC_EVT_PRLI_RCVD: {
113562306a36Sopenharmony_ci		/* Normal case for T or I+T */
113662306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
113762306a36Sopenharmony_ci		struct {
113862306a36Sopenharmony_ci			struct fc_els_prli prli;
113962306a36Sopenharmony_ci			struct fc_els_spp sp;
114062306a36Sopenharmony_ci		} *pp;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		pp = cbdata->payload->dma.virt;
114362306a36Sopenharmony_ci		if (pp->sp.spp_type != FC_TYPE_FCP) {
114462306a36Sopenharmony_ci			/*Only FCP is supported*/
114562306a36Sopenharmony_ci			efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
114662306a36Sopenharmony_ci					ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
114762306a36Sopenharmony_ci			break;
114862306a36Sopenharmony_ci		}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci		efc_process_prli_payload(node, cbdata->payload->dma.virt);
115162306a36Sopenharmony_ci		efc_d_send_prli_rsp(node, be16_to_cpu(hdr->fh_ox_id));
115262306a36Sopenharmony_ci		break;
115362306a36Sopenharmony_ci	}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	case EFC_EVT_NODE_SESS_REG_OK:
115662306a36Sopenharmony_ci		if (node->send_ls_acc == EFC_NODE_SEND_LS_ACC_PRLI)
115762306a36Sopenharmony_ci			efc_send_prli_acc(node, node->ls_acc_oxid);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci		node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
116062306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_device_ready, NULL);
116162306a36Sopenharmony_ci		break;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	case EFC_EVT_NODE_SESS_REG_FAIL:
116462306a36Sopenharmony_ci		efc_send_ls_rjt(node, node->ls_acc_oxid, ELS_RJT_UNAB,
116562306a36Sopenharmony_ci				ELS_EXPL_UNSUPR, 0);
116662306a36Sopenharmony_ci		node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
116762306a36Sopenharmony_ci		break;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_OK: {	/* PRLI response */
117062306a36Sopenharmony_ci		/* Normal case for I or I+T */
117162306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
117262306a36Sopenharmony_ci					   __efc_d_common, __func__))
117362306a36Sopenharmony_ci			return;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
117662306a36Sopenharmony_ci		node->els_req_cnt--;
117762306a36Sopenharmony_ci		/* sm: / process PRLI payload */
117862306a36Sopenharmony_ci		efc_process_prli_payload(node, cbdata->els_rsp.virt);
117962306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_device_ready, NULL);
118062306a36Sopenharmony_ci		break;
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_FAIL: {	/* PRLI response failed */
118462306a36Sopenharmony_ci		/* I, I+T, assume some link failure, shutdown node */
118562306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
118662306a36Sopenharmony_ci					   __efc_d_common, __func__))
118762306a36Sopenharmony_ci			return;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
119062306a36Sopenharmony_ci		node->els_req_cnt--;
119162306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
119262306a36Sopenharmony_ci		break;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_RJT: {
119662306a36Sopenharmony_ci		/* PRLI rejected by remote
119762306a36Sopenharmony_ci		 * Normal for I, I+T (connected to an I)
119862306a36Sopenharmony_ci		 * Node doesn't want to be a target, stay here and wait for a
119962306a36Sopenharmony_ci		 * PRLI from the remote node
120062306a36Sopenharmony_ci		 * if it really wants to connect to us as target
120162306a36Sopenharmony_ci		 */
120262306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
120362306a36Sopenharmony_ci					   __efc_d_common, __func__))
120462306a36Sopenharmony_ci			return;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
120762306a36Sopenharmony_ci		node->els_req_cnt--;
120862306a36Sopenharmony_ci		break;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_CMPL_OK: {
121262306a36Sopenharmony_ci		/* Normal T, I+T, target-server rejected the process login */
121362306a36Sopenharmony_ci		/* This would be received only in the case where we sent
121462306a36Sopenharmony_ci		 * LS_RJT for the PRLI, so
121562306a36Sopenharmony_ci		 * do nothing.   (note: as T only we could shutdown the node)
121662306a36Sopenharmony_ci		 */
121762306a36Sopenharmony_ci		WARN_ON(!node->els_cmpl_cnt);
121862306a36Sopenharmony_ci		node->els_cmpl_cnt--;
121962306a36Sopenharmony_ci		break;
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	case EFC_EVT_PLOGI_RCVD: {
122362306a36Sopenharmony_ci		/*sm: / save sparams, set send_plogi_acc,
122462306a36Sopenharmony_ci		 *post implicit logout
122562306a36Sopenharmony_ci		 * Save plogi parameters
122662306a36Sopenharmony_ci		 */
122762306a36Sopenharmony_ci		efc_node_save_sparms(node, cbdata->payload->dma.virt);
122862306a36Sopenharmony_ci		efc_send_ls_acc_after_attach(node,
122962306a36Sopenharmony_ci					     cbdata->header->dma.virt,
123062306a36Sopenharmony_ci				EFC_NODE_SEND_LS_ACC_PLOGI);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci		/* Restart node attach with new service parameters,
123362306a36Sopenharmony_ci		 * and send ACC
123462306a36Sopenharmony_ci		 */
123562306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
123662306a36Sopenharmony_ci				    NULL);
123762306a36Sopenharmony_ci		break;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	case EFC_EVT_LOGO_RCVD: {
124162306a36Sopenharmony_ci		/* I, T, I+T */
124262306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci		node_printf(node, "%s received attached=%d\n",
124562306a36Sopenharmony_ci			    efc_sm_event_name(evt),
124662306a36Sopenharmony_ci					node->attached);
124762306a36Sopenharmony_ci		/* sm: / send LOGO acc */
124862306a36Sopenharmony_ci		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
124962306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
125062306a36Sopenharmony_ci		break;
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	default:
125462306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_civoid
125962306a36Sopenharmony_ci__efc_d_wait_logo_acc_cmpl(struct efc_sm_ctx *ctx,
126062306a36Sopenharmony_ci			   enum efc_sm_event evt, void *arg)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	node_sm_trace();
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	switch (evt) {
126962306a36Sopenharmony_ci	case EFC_EVT_ENTER:
127062306a36Sopenharmony_ci		efc_node_hold_frames(node);
127162306a36Sopenharmony_ci		break;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	case EFC_EVT_EXIT:
127462306a36Sopenharmony_ci		efc_node_accept_frames(node);
127562306a36Sopenharmony_ci		break;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_CMPL_OK:
127862306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_CMPL_FAIL:
127962306a36Sopenharmony_ci		/* sm: / post explicit logout */
128062306a36Sopenharmony_ci		WARN_ON(!node->els_cmpl_cnt);
128162306a36Sopenharmony_ci		node->els_cmpl_cnt--;
128262306a36Sopenharmony_ci		efc_node_post_event(node,
128362306a36Sopenharmony_ci				    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
128462306a36Sopenharmony_ci		break;
128562306a36Sopenharmony_ci	default:
128662306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_civoid
129162306a36Sopenharmony_ci__efc_d_device_ready(struct efc_sm_ctx *ctx,
129262306a36Sopenharmony_ci		     enum efc_sm_event evt, void *arg)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct efc_node_cb *cbdata = arg;
129562306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
129662306a36Sopenharmony_ci	struct efc *efc = node->efc;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	if (evt != EFC_EVT_FCP_CMD_RCVD)
130162306a36Sopenharmony_ci		node_sm_trace();
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	switch (evt) {
130462306a36Sopenharmony_ci	case EFC_EVT_ENTER:
130562306a36Sopenharmony_ci		node->fcp_enabled = true;
130662306a36Sopenharmony_ci		if (node->targ) {
130762306a36Sopenharmony_ci			efc_log_info(efc,
130862306a36Sopenharmony_ci				     "[%s] found (target) WWPN %s WWNN %s\n",
130962306a36Sopenharmony_ci				node->display_name,
131062306a36Sopenharmony_ci				node->wwpn, node->wwnn);
131162306a36Sopenharmony_ci			if (node->nport->enable_ini)
131262306a36Sopenharmony_ci				efc->tt.scsi_new_node(efc, node);
131362306a36Sopenharmony_ci		}
131462306a36Sopenharmony_ci		break;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	case EFC_EVT_EXIT:
131762306a36Sopenharmony_ci		node->fcp_enabled = false;
131862306a36Sopenharmony_ci		break;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	case EFC_EVT_PLOGI_RCVD: {
132162306a36Sopenharmony_ci		/* sm: / save sparams, set send_plogi_acc, post implicit
132262306a36Sopenharmony_ci		 * logout
132362306a36Sopenharmony_ci		 * Save plogi parameters
132462306a36Sopenharmony_ci		 */
132562306a36Sopenharmony_ci		efc_node_save_sparms(node, cbdata->payload->dma.virt);
132662306a36Sopenharmony_ci		efc_send_ls_acc_after_attach(node,
132762306a36Sopenharmony_ci					     cbdata->header->dma.virt,
132862306a36Sopenharmony_ci				EFC_NODE_SEND_LS_ACC_PLOGI);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		/*
133162306a36Sopenharmony_ci		 * Restart node attach with new service parameters,
133262306a36Sopenharmony_ci		 * and send ACC
133362306a36Sopenharmony_ci		 */
133462306a36Sopenharmony_ci		efc_node_post_event(node,
133562306a36Sopenharmony_ci				    EFC_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
133662306a36Sopenharmony_ci		break;
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	case EFC_EVT_PRLI_RCVD: {
134062306a36Sopenharmony_ci		/* T, I+T: remote initiator is slow to get started */
134162306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
134262306a36Sopenharmony_ci		struct {
134362306a36Sopenharmony_ci			struct fc_els_prli prli;
134462306a36Sopenharmony_ci			struct fc_els_spp sp;
134562306a36Sopenharmony_ci		} *pp;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci		pp = cbdata->payload->dma.virt;
134862306a36Sopenharmony_ci		if (pp->sp.spp_type != FC_TYPE_FCP) {
134962306a36Sopenharmony_ci			/*Only FCP is supported*/
135062306a36Sopenharmony_ci			efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
135162306a36Sopenharmony_ci					ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
135262306a36Sopenharmony_ci			break;
135362306a36Sopenharmony_ci		}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci		efc_process_prli_payload(node, cbdata->payload->dma.virt);
135662306a36Sopenharmony_ci		efc_send_prli_acc(node, be16_to_cpu(hdr->fh_ox_id));
135762306a36Sopenharmony_ci		break;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	case EFC_EVT_PRLO_RCVD: {
136162306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
136262306a36Sopenharmony_ci		/* sm: / send PRLO acc */
136362306a36Sopenharmony_ci		efc_send_prlo_acc(node, be16_to_cpu(hdr->fh_ox_id));
136462306a36Sopenharmony_ci		/* need implicit logout? */
136562306a36Sopenharmony_ci		break;
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	case EFC_EVT_LOGO_RCVD: {
136962306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci		node_printf(node, "%s received attached=%d\n",
137262306a36Sopenharmony_ci			    efc_sm_event_name(evt), node->attached);
137362306a36Sopenharmony_ci		/* sm: / send LOGO acc */
137462306a36Sopenharmony_ci		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
137562306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
137662306a36Sopenharmony_ci		break;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	case EFC_EVT_ADISC_RCVD: {
138062306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
138162306a36Sopenharmony_ci		/* sm: / send ADISC acc */
138262306a36Sopenharmony_ci		efc_send_adisc_acc(node, be16_to_cpu(hdr->fh_ox_id));
138362306a36Sopenharmony_ci		break;
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	case EFC_EVT_ABTS_RCVD:
138762306a36Sopenharmony_ci		/* sm: / process ABTS */
138862306a36Sopenharmony_ci		efc_log_err(efc, "Unexpected event:%s\n",
138962306a36Sopenharmony_ci			    efc_sm_event_name(evt));
139062306a36Sopenharmony_ci		break;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
139362306a36Sopenharmony_ci		break;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	case EFC_EVT_NODE_REFOUND:
139662306a36Sopenharmony_ci		break;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	case EFC_EVT_NODE_MISSING:
139962306a36Sopenharmony_ci		if (node->nport->enable_rscn)
140062306a36Sopenharmony_ci			efc_node_transition(node, __efc_d_device_gone, NULL);
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci		break;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_CMPL_OK:
140562306a36Sopenharmony_ci		/* T, or I+T, PRLI accept completed ok */
140662306a36Sopenharmony_ci		WARN_ON(!node->els_cmpl_cnt);
140762306a36Sopenharmony_ci		node->els_cmpl_cnt--;
140862306a36Sopenharmony_ci		break;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_CMPL_FAIL:
141162306a36Sopenharmony_ci		/* T, or I+T, PRLI accept failed to complete */
141262306a36Sopenharmony_ci		WARN_ON(!node->els_cmpl_cnt);
141362306a36Sopenharmony_ci		node->els_cmpl_cnt--;
141462306a36Sopenharmony_ci		node_printf(node, "Failed to send PRLI LS_ACC\n");
141562306a36Sopenharmony_ci		break;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	default:
141862306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_civoid
142362306a36Sopenharmony_ci__efc_d_device_gone(struct efc_sm_ctx *ctx,
142462306a36Sopenharmony_ci		    enum efc_sm_event evt, void *arg)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	struct efc_node_cb *cbdata = arg;
142762306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
142862306a36Sopenharmony_ci	struct efc *efc = node->efc;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	node_sm_trace();
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	switch (evt) {
143562306a36Sopenharmony_ci	case EFC_EVT_ENTER: {
143662306a36Sopenharmony_ci		int rc = EFC_SCSI_CALL_COMPLETE;
143762306a36Sopenharmony_ci		int rc_2 = EFC_SCSI_CALL_COMPLETE;
143862306a36Sopenharmony_ci		static const char * const labels[] = {
143962306a36Sopenharmony_ci			"none", "initiator", "target", "initiator+target"
144062306a36Sopenharmony_ci		};
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci		efc_log_info(efc, "[%s] missing (%s)    WWPN %s WWNN %s\n",
144362306a36Sopenharmony_ci			     node->display_name,
144462306a36Sopenharmony_ci				labels[(node->targ << 1) | (node->init)],
144562306a36Sopenharmony_ci						node->wwpn, node->wwnn);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci		switch (efc_node_get_enable(node)) {
144862306a36Sopenharmony_ci		case EFC_NODE_ENABLE_T_TO_T:
144962306a36Sopenharmony_ci		case EFC_NODE_ENABLE_I_TO_T:
145062306a36Sopenharmony_ci		case EFC_NODE_ENABLE_IT_TO_T:
145162306a36Sopenharmony_ci			rc = efc->tt.scsi_del_node(efc, node,
145262306a36Sopenharmony_ci				EFC_SCSI_TARGET_MISSING);
145362306a36Sopenharmony_ci			break;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		case EFC_NODE_ENABLE_T_TO_I:
145662306a36Sopenharmony_ci		case EFC_NODE_ENABLE_I_TO_I:
145762306a36Sopenharmony_ci		case EFC_NODE_ENABLE_IT_TO_I:
145862306a36Sopenharmony_ci			rc = efc->tt.scsi_del_node(efc, node,
145962306a36Sopenharmony_ci				EFC_SCSI_INITIATOR_MISSING);
146062306a36Sopenharmony_ci			break;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci		case EFC_NODE_ENABLE_T_TO_IT:
146362306a36Sopenharmony_ci			rc = efc->tt.scsi_del_node(efc, node,
146462306a36Sopenharmony_ci				EFC_SCSI_INITIATOR_MISSING);
146562306a36Sopenharmony_ci			break;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		case EFC_NODE_ENABLE_I_TO_IT:
146862306a36Sopenharmony_ci			rc = efc->tt.scsi_del_node(efc, node,
146962306a36Sopenharmony_ci						  EFC_SCSI_TARGET_MISSING);
147062306a36Sopenharmony_ci			break;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci		case EFC_NODE_ENABLE_IT_TO_IT:
147362306a36Sopenharmony_ci			rc = efc->tt.scsi_del_node(efc, node,
147462306a36Sopenharmony_ci				EFC_SCSI_INITIATOR_MISSING);
147562306a36Sopenharmony_ci			rc_2 = efc->tt.scsi_del_node(efc, node,
147662306a36Sopenharmony_ci				EFC_SCSI_TARGET_MISSING);
147762306a36Sopenharmony_ci			break;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		default:
148062306a36Sopenharmony_ci			rc = EFC_SCSI_CALL_COMPLETE;
148162306a36Sopenharmony_ci			break;
148262306a36Sopenharmony_ci		}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci		if (rc == EFC_SCSI_CALL_COMPLETE &&
148562306a36Sopenharmony_ci		    rc_2 == EFC_SCSI_CALL_COMPLETE)
148662306a36Sopenharmony_ci			efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci		break;
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci	case EFC_EVT_NODE_REFOUND:
149162306a36Sopenharmony_ci		/* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		/* reauthenticate with PLOGI/PRLI */
149462306a36Sopenharmony_ci		/* efc_node_transition(node, __efc_d_discovered, NULL); */
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci		/* reauthenticate with ADISC */
149762306a36Sopenharmony_ci		/* sm: / send ADISC */
149862306a36Sopenharmony_ci		efc_send_adisc(node);
149962306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_adisc_rsp, NULL);
150062306a36Sopenharmony_ci		break;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	case EFC_EVT_PLOGI_RCVD: {
150362306a36Sopenharmony_ci		/* sm: / save sparams, set send_plogi_acc, post implicit
150462306a36Sopenharmony_ci		 * logout
150562306a36Sopenharmony_ci		 * Save plogi parameters
150662306a36Sopenharmony_ci		 */
150762306a36Sopenharmony_ci		efc_node_save_sparms(node, cbdata->payload->dma.virt);
150862306a36Sopenharmony_ci		efc_send_ls_acc_after_attach(node,
150962306a36Sopenharmony_ci					     cbdata->header->dma.virt,
151062306a36Sopenharmony_ci				EFC_NODE_SEND_LS_ACC_PLOGI);
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci		/*
151362306a36Sopenharmony_ci		 * Restart node attach with new service parameters, and send
151462306a36Sopenharmony_ci		 * ACC
151562306a36Sopenharmony_ci		 */
151662306a36Sopenharmony_ci		efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
151762306a36Sopenharmony_ci				    NULL);
151862306a36Sopenharmony_ci		break;
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	case EFC_EVT_FCP_CMD_RCVD: {
152262306a36Sopenharmony_ci		/* most likely a stale frame (received prior to link down),
152362306a36Sopenharmony_ci		 * if attempt to send LOGO, will probably timeout and eat
152462306a36Sopenharmony_ci		 * up 20s; thus, drop FCP_CMND
152562306a36Sopenharmony_ci		 */
152662306a36Sopenharmony_ci		node_printf(node, "FCP_CMND received, drop\n");
152762306a36Sopenharmony_ci		break;
152862306a36Sopenharmony_ci	}
152962306a36Sopenharmony_ci	case EFC_EVT_LOGO_RCVD: {
153062306a36Sopenharmony_ci		/* I, T, I+T */
153162306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci		node_printf(node, "%s received attached=%d\n",
153462306a36Sopenharmony_ci			    efc_sm_event_name(evt), node->attached);
153562306a36Sopenharmony_ci		/* sm: / send LOGO acc */
153662306a36Sopenharmony_ci		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
153762306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
153862306a36Sopenharmony_ci		break;
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci	default:
154162306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_civoid
154662306a36Sopenharmony_ci__efc_d_wait_adisc_rsp(struct efc_sm_ctx *ctx,
154762306a36Sopenharmony_ci		       enum efc_sm_event evt, void *arg)
154862306a36Sopenharmony_ci{
154962306a36Sopenharmony_ci	struct efc_node_cb *cbdata = arg;
155062306a36Sopenharmony_ci	struct efc_node *node = ctx->app;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	efc_node_evt_set(ctx, evt, __func__);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	node_sm_trace();
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	switch (evt) {
155762306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_OK:
155862306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_ADISC,
155962306a36Sopenharmony_ci					   __efc_d_common, __func__))
156062306a36Sopenharmony_ci			return;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
156362306a36Sopenharmony_ci		node->els_req_cnt--;
156462306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_device_ready, NULL);
156562306a36Sopenharmony_ci		break;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	case EFC_EVT_SRRS_ELS_REQ_RJT:
156862306a36Sopenharmony_ci		/* received an LS_RJT, in this case, send shutdown
156962306a36Sopenharmony_ci		 * (explicit logo) event which will unregister the node,
157062306a36Sopenharmony_ci		 * and start over with PLOGI
157162306a36Sopenharmony_ci		 */
157262306a36Sopenharmony_ci		if (efc_node_check_els_req(ctx, evt, arg, ELS_ADISC,
157362306a36Sopenharmony_ci					   __efc_d_common, __func__))
157462306a36Sopenharmony_ci			return;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		WARN_ON(!node->els_req_cnt);
157762306a36Sopenharmony_ci		node->els_req_cnt--;
157862306a36Sopenharmony_ci		/* sm: / post explicit logout */
157962306a36Sopenharmony_ci		efc_node_post_event(node,
158062306a36Sopenharmony_ci				    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
158162306a36Sopenharmony_ci				     NULL);
158262306a36Sopenharmony_ci		break;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	case EFC_EVT_LOGO_RCVD: {
158562306a36Sopenharmony_ci		/* In this case, we have the equivalent of an LS_RJT for
158662306a36Sopenharmony_ci		 * the ADISC, so we need to abort the ADISC, and re-login
158762306a36Sopenharmony_ci		 * with PLOGI
158862306a36Sopenharmony_ci		 */
158962306a36Sopenharmony_ci		/* sm: / request abort, send LOGO acc */
159062306a36Sopenharmony_ci		struct fc_frame_header *hdr = cbdata->header->dma.virt;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci		node_printf(node, "%s received attached=%d\n",
159362306a36Sopenharmony_ci			    efc_sm_event_name(evt), node->attached);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
159662306a36Sopenharmony_ci		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
159762306a36Sopenharmony_ci		break;
159862306a36Sopenharmony_ci	}
159962306a36Sopenharmony_ci	default:
160062306a36Sopenharmony_ci		__efc_d_common(__func__, ctx, evt, arg);
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci}
1603