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