xref: /freebsd/sys/dev/ocs_fc/ocs_fabric.c (revision ef270ab1b656486947b3b4aaec9bc0a6b5d6af21)
1*ef270ab1SKenneth D. Merry /*-
2*ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3*ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4*ef270ab1SKenneth D. Merry  *
5*ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6*ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7*ef270ab1SKenneth D. Merry  *
8*ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9*ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10*ef270ab1SKenneth D. Merry  *
11*ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12*ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13*ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14*ef270ab1SKenneth D. Merry  *
15*ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16*ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17*ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18*ef270ab1SKenneth D. Merry  *
19*ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20*ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23*ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30*ef270ab1SKenneth D. Merry  *
31*ef270ab1SKenneth D. Merry  * $FreeBSD$
32*ef270ab1SKenneth D. Merry  */
33*ef270ab1SKenneth D. Merry 
34*ef270ab1SKenneth D. Merry /**
35*ef270ab1SKenneth D. Merry  * @file
36*ef270ab1SKenneth D. Merry  *
37*ef270ab1SKenneth D. Merry  * This file implements remote node state machines for:
38*ef270ab1SKenneth D. Merry  * - Fabric logins.
39*ef270ab1SKenneth D. Merry  * - Fabric controller events.
40*ef270ab1SKenneth D. Merry  * - Name/directory services interaction.
41*ef270ab1SKenneth D. Merry  * - Point-to-point logins.
42*ef270ab1SKenneth D. Merry  */
43*ef270ab1SKenneth D. Merry 
44*ef270ab1SKenneth D. Merry /*!
45*ef270ab1SKenneth D. Merry @defgroup fabric_sm Node State Machine: Fabric States
46*ef270ab1SKenneth D. Merry @defgroup ns_sm Node State Machine: Name/Directory Services States
47*ef270ab1SKenneth D. Merry @defgroup p2p_sm Node State Machine: Point-to-Point Node States
48*ef270ab1SKenneth D. Merry */
49*ef270ab1SKenneth D. Merry 
50*ef270ab1SKenneth D. Merry #include "ocs.h"
51*ef270ab1SKenneth D. Merry #include "ocs_fabric.h"
52*ef270ab1SKenneth D. Merry #include "ocs_els.h"
53*ef270ab1SKenneth D. Merry #include "ocs_device.h"
54*ef270ab1SKenneth D. Merry 
55*ef270ab1SKenneth D. Merry static void ocs_fabric_initiate_shutdown(ocs_node_t *node);
56*ef270ab1SKenneth D. Merry static void * __ocs_fabric_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
57*ef270ab1SKenneth D. Merry static int32_t ocs_start_ns_node(ocs_sport_t *sport);
58*ef270ab1SKenneth D. Merry static int32_t ocs_start_fabctl_node(ocs_sport_t *sport);
59*ef270ab1SKenneth D. Merry static int32_t ocs_process_gidpt_payload(ocs_node_t *node, fcct_gidpt_acc_t *gidpt, uint32_t gidpt_len);
60*ef270ab1SKenneth D. Merry static void ocs_process_rscn(ocs_node_t *node, ocs_node_cb_t *cbdata);
61*ef270ab1SKenneth D. Merry static uint64_t ocs_get_wwpn(fc_plogi_payload_t *sp);
62*ef270ab1SKenneth D. Merry static void gidpt_delay_timer_cb(void *arg);
63*ef270ab1SKenneth D. Merry 
64*ef270ab1SKenneth D. Merry /**
65*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
66*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Initial state.
67*ef270ab1SKenneth D. Merry  *
68*ef270ab1SKenneth D. Merry  * @par Description
69*ef270ab1SKenneth D. Merry  * Send an FLOGI to a well-known fabric.
70*ef270ab1SKenneth D. Merry  *
71*ef270ab1SKenneth D. Merry  * @param ctx Remote node sm context.
72*ef270ab1SKenneth D. Merry  * @param evt Event to process.
73*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
74*ef270ab1SKenneth D. Merry  *
75*ef270ab1SKenneth D. Merry  * @return Returns NULL.
76*ef270ab1SKenneth D. Merry  */
77*ef270ab1SKenneth D. Merry void *
78*ef270ab1SKenneth D. Merry __ocs_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
79*ef270ab1SKenneth D. Merry {
80*ef270ab1SKenneth D. Merry 	std_node_state_decl();
81*ef270ab1SKenneth D. Merry 
82*ef270ab1SKenneth D. Merry 	node_sm_trace();
83*ef270ab1SKenneth D. Merry 
84*ef270ab1SKenneth D. Merry 	switch(evt) {
85*ef270ab1SKenneth D. Merry 	case OCS_EVT_REENTER:	/* not sure why we're getting these ... */
86*ef270ab1SKenneth D. Merry 		ocs_log_debug(node->ocs, ">>> reenter !!\n");
87*ef270ab1SKenneth D. Merry 		/* fall through */
88*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
89*ef270ab1SKenneth D. Merry 		/* sm: / send FLOGI */
90*ef270ab1SKenneth D. Merry 		ocs_send_flogi(node, OCS_FC_FLOGI_TIMEOUT_SEC, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
91*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabric_flogi_wait_rsp, NULL);
92*ef270ab1SKenneth D. Merry 		break;
93*ef270ab1SKenneth D. Merry 
94*ef270ab1SKenneth D. Merry 	default:
95*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
96*ef270ab1SKenneth D. Merry 		break;
97*ef270ab1SKenneth D. Merry 	}
98*ef270ab1SKenneth D. Merry 
99*ef270ab1SKenneth D. Merry 	return NULL;
100*ef270ab1SKenneth D. Merry }
101*ef270ab1SKenneth D. Merry 
102*ef270ab1SKenneth D. Merry /**
103*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
104*ef270ab1SKenneth D. Merry  * @brief Set sport topology.
105*ef270ab1SKenneth D. Merry  *
106*ef270ab1SKenneth D. Merry  * @par Description
107*ef270ab1SKenneth D. Merry  * Set sport topology.
108*ef270ab1SKenneth D. Merry  *
109*ef270ab1SKenneth D. Merry  * @param node Pointer to the node for which the topology is set.
110*ef270ab1SKenneth D. Merry  * @param topology Topology to set.
111*ef270ab1SKenneth D. Merry  *
112*ef270ab1SKenneth D. Merry  * @return Returns NULL.
113*ef270ab1SKenneth D. Merry  */
114*ef270ab1SKenneth D. Merry void
115*ef270ab1SKenneth D. Merry ocs_fabric_set_topology(ocs_node_t *node, ocs_sport_topology_e topology)
116*ef270ab1SKenneth D. Merry {
117*ef270ab1SKenneth D. Merry 	node->sport->topology = topology;
118*ef270ab1SKenneth D. Merry }
119*ef270ab1SKenneth D. Merry 
120*ef270ab1SKenneth D. Merry /**
121*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
122*ef270ab1SKenneth D. Merry  * @brief Notify sport topology.
123*ef270ab1SKenneth D. Merry  * @par Description
124*ef270ab1SKenneth D. Merry  * notify sport topology.
125*ef270ab1SKenneth D. Merry  * @param node Pointer to the node for which the topology is set.
126*ef270ab1SKenneth D. Merry  * @return Returns NULL.
127*ef270ab1SKenneth D. Merry  */
128*ef270ab1SKenneth D. Merry void
129*ef270ab1SKenneth D. Merry ocs_fabric_notify_topology(ocs_node_t *node)
130*ef270ab1SKenneth D. Merry {
131*ef270ab1SKenneth D. Merry 	ocs_node_t *tmp_node;
132*ef270ab1SKenneth D. Merry 	ocs_node_t *next;
133*ef270ab1SKenneth D. Merry 	ocs_sport_topology_e topology = node->sport->topology;
134*ef270ab1SKenneth D. Merry 
135*ef270ab1SKenneth D. Merry 	/* now loop through the nodes in the sport and send topology notification */
136*ef270ab1SKenneth D. Merry 	ocs_sport_lock(node->sport);
137*ef270ab1SKenneth D. Merry 	ocs_list_foreach_safe(&node->sport->node_list, tmp_node, next) {
138*ef270ab1SKenneth D. Merry 		if (tmp_node != node) {
139*ef270ab1SKenneth D. Merry 			ocs_node_post_event(tmp_node, OCS_EVT_SPORT_TOPOLOGY_NOTIFY, (void *)topology);
140*ef270ab1SKenneth D. Merry 		}
141*ef270ab1SKenneth D. Merry 	}
142*ef270ab1SKenneth D. Merry 	ocs_sport_unlock(node->sport);
143*ef270ab1SKenneth D. Merry }
144*ef270ab1SKenneth D. Merry 
145*ef270ab1SKenneth D. Merry /**
146*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
147*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Wait for an FLOGI response.
148*ef270ab1SKenneth D. Merry  *
149*ef270ab1SKenneth D. Merry  * @par Description
150*ef270ab1SKenneth D. Merry  * Wait for an FLOGI response event.
151*ef270ab1SKenneth D. Merry  *
152*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
153*ef270ab1SKenneth D. Merry  * @param evt Event to process.
154*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
155*ef270ab1SKenneth D. Merry  *
156*ef270ab1SKenneth D. Merry  * @return Returns NULL.
157*ef270ab1SKenneth D. Merry  */
158*ef270ab1SKenneth D. Merry 
159*ef270ab1SKenneth D. Merry void *
160*ef270ab1SKenneth D. Merry __ocs_fabric_flogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
161*ef270ab1SKenneth D. Merry {
162*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
163*ef270ab1SKenneth D. Merry 	std_node_state_decl();
164*ef270ab1SKenneth D. Merry 
165*ef270ab1SKenneth D. Merry 	node_sm_trace();
166*ef270ab1SKenneth D. Merry 
167*ef270ab1SKenneth D. Merry 	switch(evt) {
168*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK: {
169*ef270ab1SKenneth D. Merry 
170*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FLOGI, __ocs_fabric_common, __func__)) {
171*ef270ab1SKenneth D. Merry 			return NULL;
172*ef270ab1SKenneth D. Merry 		}
173*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
174*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
175*ef270ab1SKenneth D. Merry 
176*ef270ab1SKenneth D. Merry 		ocs_domain_save_sparms(node->sport->domain, cbdata->els->els_rsp.virt);
177*ef270ab1SKenneth D. Merry 
178*ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "flogi rcvd resp", 0, NULL,
179*ef270ab1SKenneth D. Merry 			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
180*ef270ab1SKenneth D. Merry 
181*ef270ab1SKenneth D. Merry 		/* Check to see if the fabric is an F_PORT or and N_PORT */
182*ef270ab1SKenneth D. Merry 		if (ocs_rnode_is_nport(cbdata->els->els_rsp.virt)) {
183*ef270ab1SKenneth D. Merry 			/* sm: if nport and p2p_winner / ocs_domain_attach */
184*ef270ab1SKenneth D. Merry 			ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_P2P);
185*ef270ab1SKenneth D. Merry 			if (ocs_p2p_setup(node->sport)) {
186*ef270ab1SKenneth D. Merry 				node_printf(node, "p2p setup failed, shutting down node\n");
187*ef270ab1SKenneth D. Merry 				node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
188*ef270ab1SKenneth D. Merry 				ocs_fabric_initiate_shutdown(node);
189*ef270ab1SKenneth D. Merry 			} else {
190*ef270ab1SKenneth D. Merry 				if (node->sport->p2p_winner) {
191*ef270ab1SKenneth D. Merry 					ocs_node_transition(node, __ocs_p2p_wait_domain_attach, NULL);
192*ef270ab1SKenneth D. Merry 					if (!node->sport->domain->attached) {
193*ef270ab1SKenneth D. Merry 						node_printf(node, "p2p winner, domain not attached\n");
194*ef270ab1SKenneth D. Merry 						ocs_domain_attach(node->sport->domain, node->sport->p2p_port_id);
195*ef270ab1SKenneth D. Merry 					} else {
196*ef270ab1SKenneth D. Merry 						/* already attached, just send ATTACH_OK */
197*ef270ab1SKenneth D. Merry 						node_printf(node, "p2p winner, domain already attached\n");
198*ef270ab1SKenneth D. Merry 						ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
199*ef270ab1SKenneth D. Merry 					}
200*ef270ab1SKenneth D. Merry 				} else {
201*ef270ab1SKenneth D. Merry 					/* peer is p2p winner; PLOGI will be received on the
202*ef270ab1SKenneth D. Merry 					 * remote SID=1 node; this node has served its purpose
203*ef270ab1SKenneth D. Merry 					 */
204*ef270ab1SKenneth D. Merry 					node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
205*ef270ab1SKenneth D. Merry 					ocs_fabric_initiate_shutdown(node);
206*ef270ab1SKenneth D. Merry 				}
207*ef270ab1SKenneth D. Merry 			}
208*ef270ab1SKenneth D. Merry 		} else {
209*ef270ab1SKenneth D. Merry 			/* sm: if not nport / ocs_domain_attach */
210*ef270ab1SKenneth D. Merry 			/* ext_status has the fc_id, attach domain */
211*ef270ab1SKenneth D. Merry 			ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_FABRIC);
212*ef270ab1SKenneth D. Merry 			ocs_fabric_notify_topology(node);
213*ef270ab1SKenneth D. Merry 			ocs_assert(!node->sport->domain->attached, NULL);
214*ef270ab1SKenneth D. Merry 			ocs_domain_attach(node->sport->domain, cbdata->ext_status);
215*ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_fabric_wait_domain_attach, NULL);
216*ef270ab1SKenneth D. Merry 		}
217*ef270ab1SKenneth D. Merry 
218*ef270ab1SKenneth D. Merry 		break;
219*ef270ab1SKenneth D. Merry 	}
220*ef270ab1SKenneth D. Merry 
221*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_ABORTED:
222*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
223*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL: {
224*ef270ab1SKenneth D. Merry 		ocs_sport_t *sport = node->sport;
225*ef270ab1SKenneth D. Merry 		/*
226*ef270ab1SKenneth D. Merry 		 * with these errors, we have no recovery, so shutdown the sport, leave the link
227*ef270ab1SKenneth D. Merry 		 * up and the domain ready
228*ef270ab1SKenneth D. Merry 		 */
229*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FLOGI, __ocs_fabric_common, __func__)) {
230*ef270ab1SKenneth D. Merry 			return NULL;
231*ef270ab1SKenneth D. Merry 		}
232*ef270ab1SKenneth D. Merry 		node_printf(node, "FLOGI failed evt=%s, shutting down sport [%s]\n", ocs_sm_event_name(evt),
233*ef270ab1SKenneth D. Merry 			sport->display_name);
234*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
235*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
236*ef270ab1SKenneth D. Merry 		ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
237*ef270ab1SKenneth D. Merry 		break;
238*ef270ab1SKenneth D. Merry 	}
239*ef270ab1SKenneth D. Merry 
240*ef270ab1SKenneth D. Merry 	default:
241*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
242*ef270ab1SKenneth D. Merry 		break;
243*ef270ab1SKenneth D. Merry 	}
244*ef270ab1SKenneth D. Merry 
245*ef270ab1SKenneth D. Merry 	return NULL;
246*ef270ab1SKenneth D. Merry }
247*ef270ab1SKenneth D. Merry 
248*ef270ab1SKenneth D. Merry /**
249*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
250*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Initial state for a virtual port.
251*ef270ab1SKenneth D. Merry  *
252*ef270ab1SKenneth D. Merry  * @par Description
253*ef270ab1SKenneth D. Merry  * State entered when a virtual port is created. Send FDISC.
254*ef270ab1SKenneth D. Merry  *
255*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
256*ef270ab1SKenneth D. Merry  * @param evt Event to process.
257*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
258*ef270ab1SKenneth D. Merry  *
259*ef270ab1SKenneth D. Merry  * @return Returns NULL.
260*ef270ab1SKenneth D. Merry  */
261*ef270ab1SKenneth D. Merry void *
262*ef270ab1SKenneth D. Merry __ocs_vport_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
263*ef270ab1SKenneth D. Merry {
264*ef270ab1SKenneth D. Merry 	std_node_state_decl();
265*ef270ab1SKenneth D. Merry 
266*ef270ab1SKenneth D. Merry 	node_sm_trace();
267*ef270ab1SKenneth D. Merry 
268*ef270ab1SKenneth D. Merry 	switch(evt) {
269*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
270*ef270ab1SKenneth D. Merry 		/* sm: send FDISC */
271*ef270ab1SKenneth D. Merry 		ocs_send_fdisc(node, OCS_FC_FLOGI_TIMEOUT_SEC, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
272*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabric_fdisc_wait_rsp, NULL);
273*ef270ab1SKenneth D. Merry 		break;
274*ef270ab1SKenneth D. Merry 
275*ef270ab1SKenneth D. Merry 	default:
276*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
277*ef270ab1SKenneth D. Merry 		break;
278*ef270ab1SKenneth D. Merry 	}
279*ef270ab1SKenneth D. Merry 
280*ef270ab1SKenneth D. Merry 	return NULL;
281*ef270ab1SKenneth D. Merry }
282*ef270ab1SKenneth D. Merry 
283*ef270ab1SKenneth D. Merry /**
284*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
285*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Wait for an FDISC response
286*ef270ab1SKenneth D. Merry  *
287*ef270ab1SKenneth D. Merry  * @par Description
288*ef270ab1SKenneth D. Merry  * Used for a virtual port. Waits for an FDISC response. If OK, issue a HW port attach.
289*ef270ab1SKenneth D. Merry  *
290*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
291*ef270ab1SKenneth D. Merry  * @param evt Event to process.
292*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
293*ef270ab1SKenneth D. Merry  *
294*ef270ab1SKenneth D. Merry  * @return Returns NULL.
295*ef270ab1SKenneth D. Merry  */
296*ef270ab1SKenneth D. Merry void *
297*ef270ab1SKenneth D. Merry __ocs_fabric_fdisc_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
298*ef270ab1SKenneth D. Merry {
299*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
300*ef270ab1SKenneth D. Merry 	std_node_state_decl();
301*ef270ab1SKenneth D. Merry 
302*ef270ab1SKenneth D. Merry 	node_sm_trace();
303*ef270ab1SKenneth D. Merry 
304*ef270ab1SKenneth D. Merry 	switch(evt) {
305*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK: {
306*ef270ab1SKenneth D. Merry 		/* fc_id is in ext_status */
307*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FDISC, __ocs_fabric_common, __func__)) {
308*ef270ab1SKenneth D. Merry 			return NULL;
309*ef270ab1SKenneth D. Merry 		}
310*ef270ab1SKenneth D. Merry 
311*ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "fdisc rcvd resp", 0, NULL,
312*ef270ab1SKenneth D. Merry 			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
313*ef270ab1SKenneth D. Merry 
314*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
315*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
316*ef270ab1SKenneth D. Merry 		/* sm: ocs_sport_attach */
317*ef270ab1SKenneth D. Merry 		ocs_sport_attach(node->sport, cbdata->ext_status);
318*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabric_wait_domain_attach, NULL);
319*ef270ab1SKenneth D. Merry 		break;
320*ef270ab1SKenneth D. Merry 
321*ef270ab1SKenneth D. Merry 	}
322*ef270ab1SKenneth D. Merry 
323*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
324*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL: {
325*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FDISC, __ocs_fabric_common, __func__)) {
326*ef270ab1SKenneth D. Merry 			return NULL;
327*ef270ab1SKenneth D. Merry 		}
328*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
329*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
330*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "FDISC failed, shutting down sport\n");
331*ef270ab1SKenneth D. Merry 		/* sm: shutdown sport */
332*ef270ab1SKenneth D. Merry 		ocs_sm_post_event(&node->sport->sm, OCS_EVT_SHUTDOWN, NULL);
333*ef270ab1SKenneth D. Merry 		break;
334*ef270ab1SKenneth D. Merry 	}
335*ef270ab1SKenneth D. Merry 
336*ef270ab1SKenneth D. Merry 	default:
337*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
338*ef270ab1SKenneth D. Merry 		break;
339*ef270ab1SKenneth D. Merry 	}
340*ef270ab1SKenneth D. Merry 
341*ef270ab1SKenneth D. Merry 	return NULL;
342*ef270ab1SKenneth D. Merry }
343*ef270ab1SKenneth D. Merry 
344*ef270ab1SKenneth D. Merry /**
345*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
346*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Wait for a domain/sport attach event.
347*ef270ab1SKenneth D. Merry  *
348*ef270ab1SKenneth D. Merry  * @par Description
349*ef270ab1SKenneth D. Merry  * Waits for a domain/sport attach event.
350*ef270ab1SKenneth D. Merry  *
351*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
352*ef270ab1SKenneth D. Merry  * @param evt Event to process.
353*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
354*ef270ab1SKenneth D. Merry  *
355*ef270ab1SKenneth D. Merry  * @return Returns NULL.
356*ef270ab1SKenneth D. Merry  */
357*ef270ab1SKenneth D. Merry void *
358*ef270ab1SKenneth D. Merry __ocs_fabric_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
359*ef270ab1SKenneth D. Merry {
360*ef270ab1SKenneth D. Merry 	std_node_state_decl();
361*ef270ab1SKenneth D. Merry 
362*ef270ab1SKenneth D. Merry 	node_sm_trace();
363*ef270ab1SKenneth D. Merry 
364*ef270ab1SKenneth D. Merry 	switch(evt) {
365*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
366*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
367*ef270ab1SKenneth D. Merry 		break;
368*ef270ab1SKenneth D. Merry 
369*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
370*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
371*ef270ab1SKenneth D. Merry 		break;
372*ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
373*ef270ab1SKenneth D. Merry 	case OCS_EVT_SPORT_ATTACH_OK: {
374*ef270ab1SKenneth D. Merry 		int rc;
375*ef270ab1SKenneth D. Merry 
376*ef270ab1SKenneth D. Merry 		rc = ocs_start_ns_node(node->sport);
377*ef270ab1SKenneth D. Merry 		if (rc)
378*ef270ab1SKenneth D. Merry 			return NULL;
379*ef270ab1SKenneth D. Merry 
380*ef270ab1SKenneth D. Merry 		/* sm: if enable_ini / start fabctl node
381*ef270ab1SKenneth D. Merry 		 * Instantiate the fabric controller (sends SCR) */
382*ef270ab1SKenneth D. Merry 		if (node->sport->enable_rscn) {
383*ef270ab1SKenneth D. Merry 			rc = ocs_start_fabctl_node(node->sport);
384*ef270ab1SKenneth D. Merry 			if (rc)
385*ef270ab1SKenneth D. Merry 				return NULL;
386*ef270ab1SKenneth D. Merry 		}
387*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabric_idle, NULL);
388*ef270ab1SKenneth D. Merry 		break;
389*ef270ab1SKenneth D. Merry 	}
390*ef270ab1SKenneth D. Merry 	default:
391*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
392*ef270ab1SKenneth D. Merry 		return NULL;
393*ef270ab1SKenneth D. Merry 	}
394*ef270ab1SKenneth D. Merry 
395*ef270ab1SKenneth D. Merry 	return NULL;
396*ef270ab1SKenneth D. Merry }
397*ef270ab1SKenneth D. Merry 
398*ef270ab1SKenneth D. Merry /**
399*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
400*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Fabric node is idle.
401*ef270ab1SKenneth D. Merry  *
402*ef270ab1SKenneth D. Merry  * @par Description
403*ef270ab1SKenneth D. Merry  * Wait for fabric node events.
404*ef270ab1SKenneth D. Merry  *
405*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
406*ef270ab1SKenneth D. Merry  * @param evt Event to process.
407*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
408*ef270ab1SKenneth D. Merry  *
409*ef270ab1SKenneth D. Merry  * @return Returns NULL.
410*ef270ab1SKenneth D. Merry  */
411*ef270ab1SKenneth D. Merry void *
412*ef270ab1SKenneth D. Merry __ocs_fabric_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
413*ef270ab1SKenneth D. Merry {
414*ef270ab1SKenneth D. Merry 	std_node_state_decl();
415*ef270ab1SKenneth D. Merry 
416*ef270ab1SKenneth D. Merry 	node_sm_trace();
417*ef270ab1SKenneth D. Merry 
418*ef270ab1SKenneth D. Merry 	switch(evt) {
419*ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
420*ef270ab1SKenneth D. Merry 		break;
421*ef270ab1SKenneth D. Merry 	default:
422*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
423*ef270ab1SKenneth D. Merry 		return NULL;
424*ef270ab1SKenneth D. Merry 	}
425*ef270ab1SKenneth D. Merry 
426*ef270ab1SKenneth D. Merry 	return NULL;
427*ef270ab1SKenneth D. Merry }
428*ef270ab1SKenneth D. Merry 
429*ef270ab1SKenneth D. Merry /**
430*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
431*ef270ab1SKenneth D. Merry  * @brief Name services node state machine: Initialize.
432*ef270ab1SKenneth D. Merry  *
433*ef270ab1SKenneth D. Merry  * @par Description
434*ef270ab1SKenneth D. Merry  * A PLOGI is sent to the well-known name/directory services node.
435*ef270ab1SKenneth D. Merry  *
436*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
437*ef270ab1SKenneth D. Merry  * @param evt Event to process.
438*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
439*ef270ab1SKenneth D. Merry  *
440*ef270ab1SKenneth D. Merry  * @return Returns NULL.
441*ef270ab1SKenneth D. Merry  */
442*ef270ab1SKenneth D. Merry void *
443*ef270ab1SKenneth D. Merry __ocs_ns_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
444*ef270ab1SKenneth D. Merry {
445*ef270ab1SKenneth D. Merry 	std_node_state_decl();
446*ef270ab1SKenneth D. Merry 
447*ef270ab1SKenneth D. Merry 	node_sm_trace();
448*ef270ab1SKenneth D. Merry 
449*ef270ab1SKenneth D. Merry 	switch(evt) {
450*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
451*ef270ab1SKenneth D. Merry 		/* sm: send PLOGI */
452*ef270ab1SKenneth D. Merry 		ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
453*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_ns_plogi_wait_rsp, NULL);
454*ef270ab1SKenneth D. Merry 		break;
455*ef270ab1SKenneth D. Merry 	default:
456*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
457*ef270ab1SKenneth D. Merry 		break;
458*ef270ab1SKenneth D. Merry 	}
459*ef270ab1SKenneth D. Merry 
460*ef270ab1SKenneth D. Merry 	return NULL;
461*ef270ab1SKenneth D. Merry }
462*ef270ab1SKenneth D. Merry 
463*ef270ab1SKenneth D. Merry /**
464*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
465*ef270ab1SKenneth D. Merry  * @brief Name services node state machine: Wait for a PLOGI response.
466*ef270ab1SKenneth D. Merry  *
467*ef270ab1SKenneth D. Merry  * @par Description
468*ef270ab1SKenneth D. Merry  * Waits for a response from PLOGI to name services node, then issues a
469*ef270ab1SKenneth D. Merry  * node attach request to the HW.
470*ef270ab1SKenneth D. Merry  *
471*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
472*ef270ab1SKenneth D. Merry  * @param evt Event to process.
473*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
474*ef270ab1SKenneth D. Merry  *
475*ef270ab1SKenneth D. Merry  * @return Returns NULL.
476*ef270ab1SKenneth D. Merry  */
477*ef270ab1SKenneth D. Merry void *
478*ef270ab1SKenneth D. Merry __ocs_ns_plogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
479*ef270ab1SKenneth D. Merry {
480*ef270ab1SKenneth D. Merry 	int32_t rc;
481*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
482*ef270ab1SKenneth D. Merry 	std_node_state_decl();
483*ef270ab1SKenneth D. Merry 
484*ef270ab1SKenneth D. Merry 	node_sm_trace();
485*ef270ab1SKenneth D. Merry 
486*ef270ab1SKenneth D. Merry 	switch(evt) {
487*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK: {
488*ef270ab1SKenneth D. Merry 		/* Save service parameters */
489*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) {
490*ef270ab1SKenneth D. Merry 			return NULL;
491*ef270ab1SKenneth D. Merry 		}
492*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
493*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
494*ef270ab1SKenneth D. Merry 		/* sm: save sparams, ocs_node_attach */
495*ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
496*ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
497*ef270ab1SKenneth D. Merry 			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
498*ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
499*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_ns_wait_node_attach, NULL);
500*ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
501*ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
502*ef270ab1SKenneth D. Merry 		}
503*ef270ab1SKenneth D. Merry 		break;
504*ef270ab1SKenneth D. Merry 	}
505*ef270ab1SKenneth D. Merry 	default:
506*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
507*ef270ab1SKenneth D. Merry 		return NULL;
508*ef270ab1SKenneth D. Merry 	}
509*ef270ab1SKenneth D. Merry 
510*ef270ab1SKenneth D. Merry 	return NULL;
511*ef270ab1SKenneth D. Merry }
512*ef270ab1SKenneth D. Merry 
513*ef270ab1SKenneth D. Merry /**
514*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
515*ef270ab1SKenneth D. Merry  * @brief Name services node state machine: Wait for a node attach completion.
516*ef270ab1SKenneth D. Merry  *
517*ef270ab1SKenneth D. Merry  * @par Description
518*ef270ab1SKenneth D. Merry  * Waits for a node attach completion, then issues an RFTID name services
519*ef270ab1SKenneth D. Merry  * request.
520*ef270ab1SKenneth D. Merry  *
521*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
522*ef270ab1SKenneth D. Merry  * @param evt Event to process.
523*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
524*ef270ab1SKenneth D. Merry  *
525*ef270ab1SKenneth D. Merry  * @return Returns NULL.
526*ef270ab1SKenneth D. Merry  */
527*ef270ab1SKenneth D. Merry void *
528*ef270ab1SKenneth D. Merry __ocs_ns_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
529*ef270ab1SKenneth D. Merry {
530*ef270ab1SKenneth D. Merry 	std_node_state_decl();
531*ef270ab1SKenneth D. Merry 
532*ef270ab1SKenneth D. Merry 	node_sm_trace();
533*ef270ab1SKenneth D. Merry 
534*ef270ab1SKenneth D. Merry 	switch(evt) {
535*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
536*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
537*ef270ab1SKenneth D. Merry 		break;
538*ef270ab1SKenneth D. Merry 
539*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
540*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
541*ef270ab1SKenneth D. Merry 		break;
542*ef270ab1SKenneth D. Merry 
543*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
544*ef270ab1SKenneth D. Merry 		node->attached = TRUE;
545*ef270ab1SKenneth D. Merry 		/* sm: send RFTID */
546*ef270ab1SKenneth D. Merry 		ocs_ns_send_rftid(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT,
547*ef270ab1SKenneth D. Merry 				 OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
548*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_ns_rftid_wait_rsp, NULL);
549*ef270ab1SKenneth D. Merry 		break;
550*ef270ab1SKenneth D. Merry 
551*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_FAIL:
552*ef270ab1SKenneth D. Merry 		/* node attach failed, shutdown the node */
553*ef270ab1SKenneth D. Merry 		node->attached = FALSE;
554*ef270ab1SKenneth D. Merry 		node_printf(node, "Node attach failed\n");
555*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
556*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
557*ef270ab1SKenneth D. Merry 		break;
558*ef270ab1SKenneth D. Merry 
559*ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
560*ef270ab1SKenneth D. Merry 		node_printf(node, "Shutdown event received\n");
561*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
562*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL);
563*ef270ab1SKenneth D. Merry 		break;
564*ef270ab1SKenneth D. Merry 
565*ef270ab1SKenneth D. Merry 	/* if receive RSCN just ignore,
566*ef270ab1SKenneth D. Merry 	 * we haven't sent GID_PT yet (ACC sent by fabctl node) */
567*ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD:
568*ef270ab1SKenneth D. Merry 		break;
569*ef270ab1SKenneth D. Merry 
570*ef270ab1SKenneth D. Merry 	default:
571*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
572*ef270ab1SKenneth D. Merry 		return NULL;
573*ef270ab1SKenneth D. Merry 	}
574*ef270ab1SKenneth D. Merry 
575*ef270ab1SKenneth D. Merry 	return NULL;
576*ef270ab1SKenneth D. Merry }
577*ef270ab1SKenneth D. Merry 
578*ef270ab1SKenneth D. Merry /**
579*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
580*ef270ab1SKenneth D. Merry  * @brief Wait for a domain/sport/node attach completion, then
581*ef270ab1SKenneth D. Merry  * shutdown.
582*ef270ab1SKenneth D. Merry  *
583*ef270ab1SKenneth D. Merry  * @par Description
584*ef270ab1SKenneth D. Merry  * Waits for a domain/sport/node attach completion, then shuts
585*ef270ab1SKenneth D. Merry  * node down.
586*ef270ab1SKenneth D. Merry  *
587*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
588*ef270ab1SKenneth D. Merry  * @param evt Event to process.
589*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
590*ef270ab1SKenneth D. Merry  *
591*ef270ab1SKenneth D. Merry  * @return Returns NULL.
592*ef270ab1SKenneth D. Merry  */
593*ef270ab1SKenneth D. Merry void *
594*ef270ab1SKenneth D. Merry __ocs_fabric_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
595*ef270ab1SKenneth D. Merry {
596*ef270ab1SKenneth D. Merry 	std_node_state_decl();
597*ef270ab1SKenneth D. Merry 
598*ef270ab1SKenneth D. Merry 	node_sm_trace();
599*ef270ab1SKenneth D. Merry 
600*ef270ab1SKenneth D. Merry 	switch(evt) {
601*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
602*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
603*ef270ab1SKenneth D. Merry 		break;
604*ef270ab1SKenneth D. Merry 
605*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
606*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
607*ef270ab1SKenneth D. Merry 		break;
608*ef270ab1SKenneth D. Merry 
609*ef270ab1SKenneth D. Merry 	/* wait for any of these attach events and then shutdown */
610*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
611*ef270ab1SKenneth D. Merry 		node->attached = TRUE;
612*ef270ab1SKenneth D. Merry 		node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
613*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
614*ef270ab1SKenneth D. Merry 		break;
615*ef270ab1SKenneth D. Merry 
616*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_FAIL:
617*ef270ab1SKenneth D. Merry 		node->attached = FALSE;
618*ef270ab1SKenneth D. Merry 		node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
619*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
620*ef270ab1SKenneth D. Merry 		break;
621*ef270ab1SKenneth D. Merry 
622*ef270ab1SKenneth D. Merry 	/* ignore shutdown event as we're already in shutdown path */
623*ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
624*ef270ab1SKenneth D. Merry 		node_printf(node, "Shutdown event received\n");
625*ef270ab1SKenneth D. Merry 		break;
626*ef270ab1SKenneth D. Merry 
627*ef270ab1SKenneth D. Merry 	default:
628*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
629*ef270ab1SKenneth D. Merry 		return NULL;
630*ef270ab1SKenneth D. Merry 	}
631*ef270ab1SKenneth D. Merry 
632*ef270ab1SKenneth D. Merry 	return NULL;
633*ef270ab1SKenneth D. Merry }
634*ef270ab1SKenneth D. Merry 
635*ef270ab1SKenneth D. Merry /**
636*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
637*ef270ab1SKenneth D. Merry  * @brief Name services node state machine: Wait for an RFTID response event.
638*ef270ab1SKenneth D. Merry  *
639*ef270ab1SKenneth D. Merry  * @par Description
640*ef270ab1SKenneth D. Merry  * Waits for an RFTID response event; if configured for an initiator operation,
641*ef270ab1SKenneth D. Merry  * a GIDPT name services request is issued.
642*ef270ab1SKenneth D. Merry  *
643*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
644*ef270ab1SKenneth D. Merry  * @param evt Event to process.
645*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
646*ef270ab1SKenneth D. Merry  *
647*ef270ab1SKenneth D. Merry  * @return Returns NULL.
648*ef270ab1SKenneth D. Merry  */
649*ef270ab1SKenneth D. Merry void *
650*ef270ab1SKenneth D. Merry __ocs_ns_rftid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
651*ef270ab1SKenneth D. Merry {
652*ef270ab1SKenneth D. Merry 	std_node_state_decl();
653*ef270ab1SKenneth D. Merry 
654*ef270ab1SKenneth D. Merry 	node_sm_trace();
655*ef270ab1SKenneth D. Merry 
656*ef270ab1SKenneth D. Merry 	switch(evt) {
657*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
658*ef270ab1SKenneth D. Merry 		if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_RFT_ID, __ocs_fabric_common, __func__)) {
659*ef270ab1SKenneth D. Merry 			return NULL;
660*ef270ab1SKenneth D. Merry 		}
661*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
662*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
663*ef270ab1SKenneth D. Merry 		/*sm: send RFFID */
664*ef270ab1SKenneth D. Merry 		ocs_ns_send_rffid(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT,
665*ef270ab1SKenneth D. Merry 				OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
666*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_ns_rffid_wait_rsp, NULL);
667*ef270ab1SKenneth D. Merry 		break;
668*ef270ab1SKenneth D. Merry 
669*ef270ab1SKenneth D. Merry 	/* if receive RSCN just ignore,
670*ef270ab1SKenneth D. Merry 	 * we haven't sent GID_PT yet (ACC sent by fabctl node) */
671*ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD:
672*ef270ab1SKenneth D. Merry 		break;
673*ef270ab1SKenneth D. Merry 
674*ef270ab1SKenneth D. Merry 	default:
675*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
676*ef270ab1SKenneth D. Merry 		return NULL;
677*ef270ab1SKenneth D. Merry 	}
678*ef270ab1SKenneth D. Merry 
679*ef270ab1SKenneth D. Merry 	return NULL;
680*ef270ab1SKenneth D. Merry }
681*ef270ab1SKenneth D. Merry 
682*ef270ab1SKenneth D. Merry /**
683*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
684*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Wait for RFFID response event.
685*ef270ab1SKenneth D. Merry  *
686*ef270ab1SKenneth D. Merry  * @par Description
687*ef270ab1SKenneth D. Merry  * Waits for an RFFID response event; if configured for an initiator operation,
688*ef270ab1SKenneth D. Merry  * a GIDPT name services request is issued.
689*ef270ab1SKenneth D. Merry  *
690*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
691*ef270ab1SKenneth D. Merry  * @param evt Event to process.
692*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
693*ef270ab1SKenneth D. Merry  *
694*ef270ab1SKenneth D. Merry  * @return Returns NULL.
695*ef270ab1SKenneth D. Merry  */
696*ef270ab1SKenneth D. Merry void *
697*ef270ab1SKenneth D. Merry __ocs_ns_rffid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
698*ef270ab1SKenneth D. Merry {
699*ef270ab1SKenneth D. Merry 	std_node_state_decl();
700*ef270ab1SKenneth D. Merry 
701*ef270ab1SKenneth D. Merry 	node_sm_trace();
702*ef270ab1SKenneth D. Merry 
703*ef270ab1SKenneth D. Merry 	switch(evt) {
704*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:	{
705*ef270ab1SKenneth D. Merry 		if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_RFF_ID, __ocs_fabric_common, __func__)) {
706*ef270ab1SKenneth D. Merry 			return NULL;
707*ef270ab1SKenneth D. Merry 		}
708*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
709*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
710*ef270ab1SKenneth D. Merry 		if (node->sport->enable_rscn) {
711*ef270ab1SKenneth D. Merry 			/* sm: if enable_rscn / send GIDPT */
712*ef270ab1SKenneth D. Merry 			ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT,
713*ef270ab1SKenneth D. Merry 					OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
714*ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL);
715*ef270ab1SKenneth D. Merry 		} else {
716*ef270ab1SKenneth D. Merry 			/* if 'T' only, we're done, go to idle */
717*ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_ns_idle, NULL);
718*ef270ab1SKenneth D. Merry 		}
719*ef270ab1SKenneth D. Merry 		break;
720*ef270ab1SKenneth D. Merry 	}
721*ef270ab1SKenneth D. Merry 	/* if receive RSCN just ignore,
722*ef270ab1SKenneth D. Merry 	 * we haven't sent GID_PT yet (ACC sent by fabctl node) */
723*ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD:
724*ef270ab1SKenneth D. Merry 		break;
725*ef270ab1SKenneth D. Merry 
726*ef270ab1SKenneth D. Merry 	default:
727*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
728*ef270ab1SKenneth D. Merry 		return NULL;
729*ef270ab1SKenneth D. Merry 	}
730*ef270ab1SKenneth D. Merry 
731*ef270ab1SKenneth D. Merry 	return NULL;
732*ef270ab1SKenneth D. Merry }
733*ef270ab1SKenneth D. Merry 
734*ef270ab1SKenneth D. Merry /**
735*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
736*ef270ab1SKenneth D. Merry  * @brief Name services node state machine: Wait for a GIDPT response.
737*ef270ab1SKenneth D. Merry  *
738*ef270ab1SKenneth D. Merry  * @par Description
739*ef270ab1SKenneth D. Merry  * Wait for a GIDPT response from the name server. Process the FC_IDs that are
740*ef270ab1SKenneth D. Merry  * reported by creating new remote ports, as needed.
741*ef270ab1SKenneth D. Merry  *
742*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
743*ef270ab1SKenneth D. Merry  * @param evt Event to process.
744*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
745*ef270ab1SKenneth D. Merry  *
746*ef270ab1SKenneth D. Merry  * @return Returns NULL.
747*ef270ab1SKenneth D. Merry  */
748*ef270ab1SKenneth D. Merry void *
749*ef270ab1SKenneth D. Merry __ocs_ns_gidpt_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
750*ef270ab1SKenneth D. Merry {
751*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
752*ef270ab1SKenneth D. Merry 	std_node_state_decl();
753*ef270ab1SKenneth D. Merry 
754*ef270ab1SKenneth D. Merry 	node_sm_trace();
755*ef270ab1SKenneth D. Merry 
756*ef270ab1SKenneth D. Merry 	switch(evt) {
757*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:	{
758*ef270ab1SKenneth D. Merry 		if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_GID_PT, __ocs_fabric_common, __func__)) {
759*ef270ab1SKenneth D. Merry 			return NULL;
760*ef270ab1SKenneth D. Merry 		}
761*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
762*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
763*ef270ab1SKenneth D. Merry 		/* sm: / process GIDPT payload */
764*ef270ab1SKenneth D. Merry 		ocs_process_gidpt_payload(node, cbdata->els->els_rsp.virt, cbdata->els->els_rsp.len);
765*ef270ab1SKenneth D. Merry 		/* TODO: should we logout at this point or just go idle */
766*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_ns_idle, NULL);
767*ef270ab1SKenneth D. Merry 		break;
768*ef270ab1SKenneth D. Merry 	}
769*ef270ab1SKenneth D. Merry 
770*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:	{
771*ef270ab1SKenneth D. Merry 		/* not much we can do; will retry with the next RSCN */
772*ef270ab1SKenneth D. Merry 		node_printf(node, "GID_PT failed to complete\n");
773*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
774*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
775*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_ns_idle, NULL);
776*ef270ab1SKenneth D. Merry 		break;
777*ef270ab1SKenneth D. Merry 	}
778*ef270ab1SKenneth D. Merry 
779*ef270ab1SKenneth D. Merry 	/* if receive RSCN here, queue up another discovery processing */
780*ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD: {
781*ef270ab1SKenneth D. Merry 		node_printf(node, "RSCN received during GID_PT processing\n");
782*ef270ab1SKenneth D. Merry 		node->rscn_pending = 1;
783*ef270ab1SKenneth D. Merry 		break;
784*ef270ab1SKenneth D. Merry 	}
785*ef270ab1SKenneth D. Merry 
786*ef270ab1SKenneth D. Merry 	default:
787*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
788*ef270ab1SKenneth D. Merry 		return NULL;
789*ef270ab1SKenneth D. Merry 	}
790*ef270ab1SKenneth D. Merry 
791*ef270ab1SKenneth D. Merry 	return NULL;
792*ef270ab1SKenneth D. Merry }
793*ef270ab1SKenneth D. Merry 
794*ef270ab1SKenneth D. Merry 
795*ef270ab1SKenneth D. Merry /**
796*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
797*ef270ab1SKenneth D. Merry  * @brief Name services node state machine: Idle state.
798*ef270ab1SKenneth D. Merry  *
799*ef270ab1SKenneth D. Merry  * @par Description
800*ef270ab1SKenneth D. Merry  * Idle. Waiting for RSCN received events (posted from the fabric controller), and
801*ef270ab1SKenneth D. Merry  * restarts the GIDPT name services query and processing.
802*ef270ab1SKenneth D. Merry  *
803*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
804*ef270ab1SKenneth D. Merry  * @param evt Event to process.
805*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
806*ef270ab1SKenneth D. Merry  *
807*ef270ab1SKenneth D. Merry  * @return Returns NULL.
808*ef270ab1SKenneth D. Merry  */
809*ef270ab1SKenneth D. Merry void *
810*ef270ab1SKenneth D. Merry __ocs_ns_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
811*ef270ab1SKenneth D. Merry {
812*ef270ab1SKenneth D. Merry 	std_node_state_decl();
813*ef270ab1SKenneth D. Merry 
814*ef270ab1SKenneth D. Merry 	node_sm_trace();
815*ef270ab1SKenneth D. Merry 
816*ef270ab1SKenneth D. Merry 	switch(evt) {
817*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
818*ef270ab1SKenneth D. Merry 		if (!node->rscn_pending) {
819*ef270ab1SKenneth D. Merry 			break;
820*ef270ab1SKenneth D. Merry 		}
821*ef270ab1SKenneth D. Merry 		node_printf(node, "RSCN pending, restart discovery\n");
822*ef270ab1SKenneth D. Merry 		node->rscn_pending = 0;
823*ef270ab1SKenneth D. Merry 
824*ef270ab1SKenneth D. Merry 			/* fall through */
825*ef270ab1SKenneth D. Merry 
826*ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD: {
827*ef270ab1SKenneth D. Merry 		/* sm: / send GIDPT
828*ef270ab1SKenneth D. Merry 		 * If target RSCN processing is enabled, and this is target only
829*ef270ab1SKenneth D. Merry 		 * (not initiator), and tgt_rscn_delay is non-zero,
830*ef270ab1SKenneth D. Merry 		 * then we delay issuing the GID_PT
831*ef270ab1SKenneth D. Merry 		 */
832*ef270ab1SKenneth D. Merry 		if ((ocs->tgt_rscn_delay_msec != 0) && !node->sport->enable_ini && node->sport->enable_tgt &&
833*ef270ab1SKenneth D. Merry 			enable_target_rscn(ocs)) {
834*ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_ns_gidpt_delay, NULL);
835*ef270ab1SKenneth D. Merry 		} else {
836*ef270ab1SKenneth D. Merry 			ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT,
837*ef270ab1SKenneth D. Merry 					OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
838*ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL);
839*ef270ab1SKenneth D. Merry 		}
840*ef270ab1SKenneth D. Merry 		break;
841*ef270ab1SKenneth D. Merry 	}
842*ef270ab1SKenneth D. Merry 
843*ef270ab1SKenneth D. Merry 	default:
844*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
845*ef270ab1SKenneth D. Merry 		break;
846*ef270ab1SKenneth D. Merry 	}
847*ef270ab1SKenneth D. Merry 
848*ef270ab1SKenneth D. Merry 	return NULL;
849*ef270ab1SKenneth D. Merry }
850*ef270ab1SKenneth D. Merry 
851*ef270ab1SKenneth D. Merry /**
852*ef270ab1SKenneth D. Merry  * @brief Handle GIDPT delay timer callback
853*ef270ab1SKenneth D. Merry  *
854*ef270ab1SKenneth D. Merry  * @par Description
855*ef270ab1SKenneth D. Merry  * Post an OCS_EVT_GIDPT_DEIALY_EXPIRED event to the passed in node.
856*ef270ab1SKenneth D. Merry  *
857*ef270ab1SKenneth D. Merry  * @param arg Pointer to node.
858*ef270ab1SKenneth D. Merry  *
859*ef270ab1SKenneth D. Merry  * @return None.
860*ef270ab1SKenneth D. Merry  */
861*ef270ab1SKenneth D. Merry static void
862*ef270ab1SKenneth D. Merry gidpt_delay_timer_cb(void *arg)
863*ef270ab1SKenneth D. Merry {
864*ef270ab1SKenneth D. Merry 	ocs_node_t *node = arg;
865*ef270ab1SKenneth D. Merry 	int32_t rc;
866*ef270ab1SKenneth D. Merry 
867*ef270ab1SKenneth D. Merry 	ocs_del_timer(&node->gidpt_delay_timer);
868*ef270ab1SKenneth D. Merry 	rc = ocs_xport_control(node->ocs->xport, OCS_XPORT_POST_NODE_EVENT, node, OCS_EVT_GIDPT_DELAY_EXPIRED, NULL);
869*ef270ab1SKenneth D. Merry 	if (rc) {
870*ef270ab1SKenneth D. Merry 		ocs_log_err(node->ocs, "ocs_xport_control(OCS_XPORT_POST_NODE_EVENT) failed: %d\n", rc);
871*ef270ab1SKenneth D. Merry 	}
872*ef270ab1SKenneth D. Merry }
873*ef270ab1SKenneth D. Merry 
874*ef270ab1SKenneth D. Merry /**
875*ef270ab1SKenneth D. Merry  * @ingroup ns_sm
876*ef270ab1SKenneth D. Merry  * @brief Name services node state machine: Delayed GIDPT.
877*ef270ab1SKenneth D. Merry  *
878*ef270ab1SKenneth D. Merry  * @par Description
879*ef270ab1SKenneth D. Merry  * Waiting for GIDPT delay to expire before submitting GIDPT to name server.
880*ef270ab1SKenneth D. Merry  *
881*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
882*ef270ab1SKenneth D. Merry  * @param evt Event to process.
883*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
884*ef270ab1SKenneth D. Merry  *
885*ef270ab1SKenneth D. Merry  * @return Returns NULL.
886*ef270ab1SKenneth D. Merry  */
887*ef270ab1SKenneth D. Merry void *
888*ef270ab1SKenneth D. Merry __ocs_ns_gidpt_delay(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
889*ef270ab1SKenneth D. Merry {
890*ef270ab1SKenneth D. Merry 	std_node_state_decl();
891*ef270ab1SKenneth D. Merry 
892*ef270ab1SKenneth D. Merry 	node_sm_trace();
893*ef270ab1SKenneth D. Merry 
894*ef270ab1SKenneth D. Merry 	switch(evt) {
895*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER: {
896*ef270ab1SKenneth D. Merry 		time_t delay_msec;
897*ef270ab1SKenneth D. Merry 
898*ef270ab1SKenneth D. Merry 		ocs_assert(ocs->tgt_rscn_delay_msec != 0, NULL);
899*ef270ab1SKenneth D. Merry 
900*ef270ab1SKenneth D. Merry 		/*
901*ef270ab1SKenneth D. Merry 		 * Compute the delay time.   Set to tgt_rscn_delay, if the time since last GIDPT
902*ef270ab1SKenneth D. Merry 		 * is less than tgt_rscn_period, then use tgt_rscn_period.
903*ef270ab1SKenneth D. Merry 		 */
904*ef270ab1SKenneth D. Merry 		delay_msec = ocs->tgt_rscn_delay_msec;
905*ef270ab1SKenneth D. Merry 		if ((ocs_msectime() - node->time_last_gidpt_msec) < ocs->tgt_rscn_period_msec) {
906*ef270ab1SKenneth D. Merry 			delay_msec = ocs->tgt_rscn_period_msec;
907*ef270ab1SKenneth D. Merry 		}
908*ef270ab1SKenneth D. Merry 
909*ef270ab1SKenneth D. Merry 		ocs_setup_timer(ocs, &node->gidpt_delay_timer, gidpt_delay_timer_cb, node, delay_msec);
910*ef270ab1SKenneth D. Merry 
911*ef270ab1SKenneth D. Merry 		break;
912*ef270ab1SKenneth D. Merry 	}
913*ef270ab1SKenneth D. Merry 
914*ef270ab1SKenneth D. Merry 	case OCS_EVT_GIDPT_DELAY_EXPIRED:
915*ef270ab1SKenneth D. Merry 		node->time_last_gidpt_msec = ocs_msectime();
916*ef270ab1SKenneth D. Merry 		ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT,
917*ef270ab1SKenneth D. Merry 				OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
918*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL);
919*ef270ab1SKenneth D. Merry 		break;
920*ef270ab1SKenneth D. Merry 
921*ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD: {
922*ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "RSCN received while in GIDPT delay - no action\n");
923*ef270ab1SKenneth D. Merry 		break;
924*ef270ab1SKenneth D. Merry 	}
925*ef270ab1SKenneth D. Merry 
926*ef270ab1SKenneth D. Merry 	default:
927*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
928*ef270ab1SKenneth D. Merry 		break;
929*ef270ab1SKenneth D. Merry 	}
930*ef270ab1SKenneth D. Merry 
931*ef270ab1SKenneth D. Merry 	return NULL;
932*ef270ab1SKenneth D. Merry }
933*ef270ab1SKenneth D. Merry 
934*ef270ab1SKenneth D. Merry /**
935*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
936*ef270ab1SKenneth D. Merry  * @brief Fabric controller node state machine: Initial state.
937*ef270ab1SKenneth D. Merry  *
938*ef270ab1SKenneth D. Merry  * @par Description
939*ef270ab1SKenneth D. Merry  * Issue a PLOGI to a well-known fabric controller address.
940*ef270ab1SKenneth D. Merry  *
941*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
942*ef270ab1SKenneth D. Merry  * @param evt Event to process.
943*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
944*ef270ab1SKenneth D. Merry  *
945*ef270ab1SKenneth D. Merry  * @return Returns NULL.
946*ef270ab1SKenneth D. Merry  */
947*ef270ab1SKenneth D. Merry void *
948*ef270ab1SKenneth D. Merry __ocs_fabctl_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
949*ef270ab1SKenneth D. Merry {
950*ef270ab1SKenneth D. Merry 	ocs_node_t *node = ctx->app;
951*ef270ab1SKenneth D. Merry 
952*ef270ab1SKenneth D. Merry 	node_sm_trace();
953*ef270ab1SKenneth D. Merry 
954*ef270ab1SKenneth D. Merry 	switch(evt) {
955*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
956*ef270ab1SKenneth D. Merry 		/* no need to login to fabric controller, just send SCR */
957*ef270ab1SKenneth D. Merry 		ocs_send_scr(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
958*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabctl_wait_scr_rsp, NULL);
959*ef270ab1SKenneth D. Merry 		break;
960*ef270ab1SKenneth D. Merry 
961*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
962*ef270ab1SKenneth D. Merry 		node->attached = TRUE;
963*ef270ab1SKenneth D. Merry 		break;
964*ef270ab1SKenneth D. Merry 
965*ef270ab1SKenneth D. Merry 	default:
966*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
967*ef270ab1SKenneth D. Merry 		return NULL;
968*ef270ab1SKenneth D. Merry 	}
969*ef270ab1SKenneth D. Merry 
970*ef270ab1SKenneth D. Merry 	return NULL;
971*ef270ab1SKenneth D. Merry }
972*ef270ab1SKenneth D. Merry 
973*ef270ab1SKenneth D. Merry /**
974*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
975*ef270ab1SKenneth D. Merry  * @brief Fabric controller node state machine: Wait for a node attach request
976*ef270ab1SKenneth D. Merry  * to complete.
977*ef270ab1SKenneth D. Merry  *
978*ef270ab1SKenneth D. Merry  * @par Description
979*ef270ab1SKenneth D. Merry  * Wait for a node attach to complete. If successful, issue an SCR
980*ef270ab1SKenneth D. Merry  * to the fabric controller, subscribing to all RSCN.
981*ef270ab1SKenneth D. Merry  *
982*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
983*ef270ab1SKenneth D. Merry  * @param evt Event to process.
984*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
985*ef270ab1SKenneth D. Merry  *
986*ef270ab1SKenneth D. Merry  * @return Returns NULL.
987*ef270ab1SKenneth D. Merry  *
988*ef270ab1SKenneth D. Merry  */
989*ef270ab1SKenneth D. Merry void *
990*ef270ab1SKenneth D. Merry __ocs_fabctl_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
991*ef270ab1SKenneth D. Merry {
992*ef270ab1SKenneth D. Merry 	std_node_state_decl();
993*ef270ab1SKenneth D. Merry 
994*ef270ab1SKenneth D. Merry 	node_sm_trace();
995*ef270ab1SKenneth D. Merry 
996*ef270ab1SKenneth D. Merry 	switch(evt) {
997*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
998*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
999*ef270ab1SKenneth D. Merry 		break;
1000*ef270ab1SKenneth D. Merry 
1001*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1002*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1003*ef270ab1SKenneth D. Merry 		break;
1004*ef270ab1SKenneth D. Merry 
1005*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
1006*ef270ab1SKenneth D. Merry 		node->attached = TRUE;
1007*ef270ab1SKenneth D. Merry 		/* sm: / send SCR */
1008*ef270ab1SKenneth D. Merry 		ocs_send_scr(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
1009*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabctl_wait_scr_rsp, NULL);
1010*ef270ab1SKenneth D. Merry 		break;
1011*ef270ab1SKenneth D. Merry 
1012*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_FAIL:
1013*ef270ab1SKenneth D. Merry 		/* node attach failed, shutdown the node */
1014*ef270ab1SKenneth D. Merry 		node->attached = FALSE;
1015*ef270ab1SKenneth D. Merry 		node_printf(node, "Node attach failed\n");
1016*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1017*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
1018*ef270ab1SKenneth D. Merry 		break;
1019*ef270ab1SKenneth D. Merry 
1020*ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1021*ef270ab1SKenneth D. Merry 		node_printf(node, "Shutdown event received\n");
1022*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1023*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL);
1024*ef270ab1SKenneth D. Merry 		break;
1025*ef270ab1SKenneth D. Merry 
1026*ef270ab1SKenneth D. Merry 	default:
1027*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1028*ef270ab1SKenneth D. Merry 		return NULL;
1029*ef270ab1SKenneth D. Merry 	}
1030*ef270ab1SKenneth D. Merry 
1031*ef270ab1SKenneth D. Merry 	return NULL;
1032*ef270ab1SKenneth D. Merry }
1033*ef270ab1SKenneth D. Merry 
1034*ef270ab1SKenneth D. Merry /**
1035*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
1036*ef270ab1SKenneth D. Merry  * @brief Fabric controller node state machine: Wait for an SCR response from the
1037*ef270ab1SKenneth D. Merry  * fabric controller.
1038*ef270ab1SKenneth D. Merry  *
1039*ef270ab1SKenneth D. Merry  * @par Description
1040*ef270ab1SKenneth D. Merry  * Waits for an SCR response from the fabric controller.
1041*ef270ab1SKenneth D. Merry  *
1042*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1043*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1044*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1045*ef270ab1SKenneth D. Merry  *
1046*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1047*ef270ab1SKenneth D. Merry  */
1048*ef270ab1SKenneth D. Merry void *
1049*ef270ab1SKenneth D. Merry __ocs_fabctl_wait_scr_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1050*ef270ab1SKenneth D. Merry {
1051*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1052*ef270ab1SKenneth D. Merry 
1053*ef270ab1SKenneth D. Merry 	node_sm_trace();
1054*ef270ab1SKenneth D. Merry 
1055*ef270ab1SKenneth D. Merry 	switch(evt) {
1056*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
1057*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_SCR, __ocs_fabric_common, __func__)) {
1058*ef270ab1SKenneth D. Merry 			return NULL;
1059*ef270ab1SKenneth D. Merry 		}
1060*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1061*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1062*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabctl_ready, NULL);
1063*ef270ab1SKenneth D. Merry 		break;
1064*ef270ab1SKenneth D. Merry 
1065*ef270ab1SKenneth D. Merry 	default:
1066*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1067*ef270ab1SKenneth D. Merry 		return NULL;
1068*ef270ab1SKenneth D. Merry 	}
1069*ef270ab1SKenneth D. Merry 
1070*ef270ab1SKenneth D. Merry 	return NULL;
1071*ef270ab1SKenneth D. Merry }
1072*ef270ab1SKenneth D. Merry 
1073*ef270ab1SKenneth D. Merry /**
1074*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
1075*ef270ab1SKenneth D. Merry  * @brief Fabric controller node state machine: Ready.
1076*ef270ab1SKenneth D. Merry  *
1077*ef270ab1SKenneth D. Merry  * @par Description
1078*ef270ab1SKenneth D. Merry  * In this state, the fabric controller sends a RSCN, which is received
1079*ef270ab1SKenneth D. Merry  * by this node and is forwarded to the name services node object; and
1080*ef270ab1SKenneth D. Merry  * the RSCN LS_ACC is sent.
1081*ef270ab1SKenneth D. Merry  *
1082*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1083*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1084*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1085*ef270ab1SKenneth D. Merry  *
1086*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1087*ef270ab1SKenneth D. Merry  */
1088*ef270ab1SKenneth D. Merry 
1089*ef270ab1SKenneth D. Merry void *
1090*ef270ab1SKenneth D. Merry __ocs_fabctl_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1091*ef270ab1SKenneth D. Merry {
1092*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1093*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1094*ef270ab1SKenneth D. Merry 
1095*ef270ab1SKenneth D. Merry 	node_sm_trace();
1096*ef270ab1SKenneth D. Merry 
1097*ef270ab1SKenneth D. Merry 	switch(evt) {
1098*ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD: {
1099*ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1100*ef270ab1SKenneth D. Merry 
1101*ef270ab1SKenneth D. Merry 		/* sm: / process RSCN (forward to name services node),
1102*ef270ab1SKenneth D. Merry 		 * send LS_ACC */
1103*ef270ab1SKenneth D. Merry 		ocs_process_rscn(node, cbdata);
1104*ef270ab1SKenneth D. Merry 		ocs_send_ls_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1105*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabctl_wait_ls_acc_cmpl, NULL);
1106*ef270ab1SKenneth D. Merry 		break;
1107*ef270ab1SKenneth D. Merry 	}
1108*ef270ab1SKenneth D. Merry 
1109*ef270ab1SKenneth D. Merry 	default:
1110*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1111*ef270ab1SKenneth D. Merry 		return NULL;
1112*ef270ab1SKenneth D. Merry 	}
1113*ef270ab1SKenneth D. Merry 
1114*ef270ab1SKenneth D. Merry 	return NULL;
1115*ef270ab1SKenneth D. Merry }
1116*ef270ab1SKenneth D. Merry 
1117*ef270ab1SKenneth D. Merry /**
1118*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
1119*ef270ab1SKenneth D. Merry  * @brief Fabric controller node state machine: Wait for LS_ACC.
1120*ef270ab1SKenneth D. Merry  *
1121*ef270ab1SKenneth D. Merry  * @par Description
1122*ef270ab1SKenneth D. Merry  * Waits for the LS_ACC from the fabric controller.
1123*ef270ab1SKenneth D. Merry  *
1124*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1125*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1126*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1127*ef270ab1SKenneth D. Merry  *
1128*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1129*ef270ab1SKenneth D. Merry  */
1130*ef270ab1SKenneth D. Merry 
1131*ef270ab1SKenneth D. Merry void *
1132*ef270ab1SKenneth D. Merry __ocs_fabctl_wait_ls_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1133*ef270ab1SKenneth D. Merry {
1134*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1135*ef270ab1SKenneth D. Merry 
1136*ef270ab1SKenneth D. Merry 	node_sm_trace();
1137*ef270ab1SKenneth D. Merry 
1138*ef270ab1SKenneth D. Merry 	switch(evt) {
1139*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1140*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1141*ef270ab1SKenneth D. Merry 		break;
1142*ef270ab1SKenneth D. Merry 
1143*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1144*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1145*ef270ab1SKenneth D. Merry 		break;
1146*ef270ab1SKenneth D. Merry 
1147*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK:
1148*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1149*ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1150*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabctl_ready, NULL);
1151*ef270ab1SKenneth D. Merry 		break;
1152*ef270ab1SKenneth D. Merry 
1153*ef270ab1SKenneth D. Merry 	default:
1154*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1155*ef270ab1SKenneth D. Merry 		return NULL;
1156*ef270ab1SKenneth D. Merry 	}
1157*ef270ab1SKenneth D. Merry 
1158*ef270ab1SKenneth D. Merry 	return NULL;
1159*ef270ab1SKenneth D. Merry }
1160*ef270ab1SKenneth D. Merry 
1161*ef270ab1SKenneth D. Merry /**
1162*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
1163*ef270ab1SKenneth D. Merry  * @brief Initiate fabric node shutdown.
1164*ef270ab1SKenneth D. Merry  *
1165*ef270ab1SKenneth D. Merry  * @param node Node for which shutdown is initiated.
1166*ef270ab1SKenneth D. Merry  *
1167*ef270ab1SKenneth D. Merry  * @return Returns None.
1168*ef270ab1SKenneth D. Merry  */
1169*ef270ab1SKenneth D. Merry 
1170*ef270ab1SKenneth D. Merry static void
1171*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(ocs_node_t *node)
1172*ef270ab1SKenneth D. Merry {
1173*ef270ab1SKenneth D. Merry 	ocs_hw_rtn_e rc;
1174*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1175*ef270ab1SKenneth D. Merry 	ocs_scsi_io_alloc_disable(node);
1176*ef270ab1SKenneth D. Merry 
1177*ef270ab1SKenneth D. Merry 	if (node->attached) {
1178*ef270ab1SKenneth D. Merry 		/* issue hw node free; don't care if succeeds right away
1179*ef270ab1SKenneth D. Merry 		 * or sometime later, will check node->attached later in
1180*ef270ab1SKenneth D. Merry 		 * shutdown process
1181*ef270ab1SKenneth D. Merry 		 */
1182*ef270ab1SKenneth D. Merry 		rc = ocs_hw_node_detach(&ocs->hw, &node->rnode);
1183*ef270ab1SKenneth D. Merry 		if (node->rnode.free_group) {
1184*ef270ab1SKenneth D. Merry 			ocs_remote_node_group_free(node->node_group);
1185*ef270ab1SKenneth D. Merry 			node->node_group = NULL;
1186*ef270ab1SKenneth D. Merry 			node->rnode.free_group = FALSE;
1187*ef270ab1SKenneth D. Merry 		}
1188*ef270ab1SKenneth D. Merry 		if (rc != OCS_HW_RTN_SUCCESS && rc != OCS_HW_RTN_SUCCESS_SYNC) {
1189*ef270ab1SKenneth D. Merry 			node_printf(node, "Failed freeing HW node, rc=%d\n", rc);
1190*ef270ab1SKenneth D. Merry 		}
1191*ef270ab1SKenneth D. Merry 	}
1192*ef270ab1SKenneth D. Merry 	/*
1193*ef270ab1SKenneth D. Merry 	 * node has either been detached or is in the process of being detached,
1194*ef270ab1SKenneth D. Merry 	 * call common node's initiate cleanup function
1195*ef270ab1SKenneth D. Merry 	 */
1196*ef270ab1SKenneth D. Merry 	ocs_node_initiate_cleanup(node);
1197*ef270ab1SKenneth D. Merry }
1198*ef270ab1SKenneth D. Merry 
1199*ef270ab1SKenneth D. Merry /**
1200*ef270ab1SKenneth D. Merry  * @ingroup fabric_sm
1201*ef270ab1SKenneth D. Merry  * @brief Fabric node state machine: Handle the common fabric node events.
1202*ef270ab1SKenneth D. Merry  *
1203*ef270ab1SKenneth D. Merry  * @param funcname Function name text.
1204*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1205*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1206*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1207*ef270ab1SKenneth D. Merry  *
1208*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1209*ef270ab1SKenneth D. Merry  */
1210*ef270ab1SKenneth D. Merry 
1211*ef270ab1SKenneth D. Merry static void *
1212*ef270ab1SKenneth D. Merry __ocs_fabric_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1213*ef270ab1SKenneth D. Merry {
1214*ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
1215*ef270ab1SKenneth D. Merry 	ocs_assert(ctx, NULL);
1216*ef270ab1SKenneth D. Merry 	ocs_assert(ctx->app, NULL);
1217*ef270ab1SKenneth D. Merry 	node = ctx->app;
1218*ef270ab1SKenneth D. Merry 
1219*ef270ab1SKenneth D. Merry 	switch(evt) {
1220*ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
1221*ef270ab1SKenneth D. Merry 		break;
1222*ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1223*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1224*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
1225*ef270ab1SKenneth D. Merry 		break;
1226*ef270ab1SKenneth D. Merry 
1227*ef270ab1SKenneth D. Merry 	default:
1228*ef270ab1SKenneth D. Merry 		/* call default event handler common to all nodes */
1229*ef270ab1SKenneth D. Merry 		__ocs_node_common(funcname, ctx, evt, arg);
1230*ef270ab1SKenneth D. Merry 		break;
1231*ef270ab1SKenneth D. Merry 	}
1232*ef270ab1SKenneth D. Merry 	return NULL;
1233*ef270ab1SKenneth D. Merry }
1234*ef270ab1SKenneth D. Merry 
1235*ef270ab1SKenneth D. Merry /**
1236*ef270ab1SKenneth D. Merry  * @brief Return TRUE if the remote node is an NPORT.
1237*ef270ab1SKenneth D. Merry  *
1238*ef270ab1SKenneth D. Merry  * @par Description
1239*ef270ab1SKenneth D. Merry  * Examines the service parameters. Returns TRUE if the node reports itself as
1240*ef270ab1SKenneth D. Merry  * an NPORT.
1241*ef270ab1SKenneth D. Merry  *
1242*ef270ab1SKenneth D. Merry  * @param remote_sparms Remote node service parameters.
1243*ef270ab1SKenneth D. Merry  *
1244*ef270ab1SKenneth D. Merry  * @return Returns TRUE if NPORT.
1245*ef270ab1SKenneth D. Merry  */
1246*ef270ab1SKenneth D. Merry 
1247*ef270ab1SKenneth D. Merry int32_t
1248*ef270ab1SKenneth D. Merry ocs_rnode_is_nport(fc_plogi_payload_t *remote_sparms)
1249*ef270ab1SKenneth D. Merry {
1250*ef270ab1SKenneth D. Merry 	return (ocs_be32toh(remote_sparms->common_service_parameters[1]) & (1U << 28)) == 0;
1251*ef270ab1SKenneth D. Merry }
1252*ef270ab1SKenneth D. Merry 
1253*ef270ab1SKenneth D. Merry /**
1254*ef270ab1SKenneth D. Merry  * @brief Return the node's WWPN as an uint64_t.
1255*ef270ab1SKenneth D. Merry  *
1256*ef270ab1SKenneth D. Merry  * @par Description
1257*ef270ab1SKenneth D. Merry  * The WWPN is computed from service parameters, and returned as a uint64_t.
1258*ef270ab1SKenneth D. Merry  *
1259*ef270ab1SKenneth D. Merry  * @param sp Pointer to service parameters.
1260*ef270ab1SKenneth D. Merry  *
1261*ef270ab1SKenneth D. Merry  * @return Returns WWPN.
1262*ef270ab1SKenneth D. Merry  *
1263*ef270ab1SKenneth D. Merry  */
1264*ef270ab1SKenneth D. Merry 
1265*ef270ab1SKenneth D. Merry static uint64_t
1266*ef270ab1SKenneth D. Merry ocs_get_wwpn(fc_plogi_payload_t *sp)
1267*ef270ab1SKenneth D. Merry {
1268*ef270ab1SKenneth D. Merry 	return (((uint64_t)ocs_be32toh(sp->port_name_hi) << 32ll) | (ocs_be32toh(sp->port_name_lo)));
1269*ef270ab1SKenneth D. Merry }
1270*ef270ab1SKenneth D. Merry 
1271*ef270ab1SKenneth D. Merry /**
1272*ef270ab1SKenneth D. Merry  * @brief Return TRUE if the remote node is the point-to-point winner.
1273*ef270ab1SKenneth D. Merry  *
1274*ef270ab1SKenneth D. Merry  * @par Description
1275*ef270ab1SKenneth D. Merry  * Compares WWPNs. Returns TRUE if the remote node's WWPN is numerically
1276*ef270ab1SKenneth D. Merry  * higher than the local node's WWPN.
1277*ef270ab1SKenneth D. Merry  *
1278*ef270ab1SKenneth D. Merry  * @param sport Pointer to the sport object.
1279*ef270ab1SKenneth D. Merry  *
1280*ef270ab1SKenneth D. Merry  * @return
1281*ef270ab1SKenneth D. Merry  * - 0, if the remote node is the loser.
1282*ef270ab1SKenneth D. Merry  * - 1, if the remote node is the winner.
1283*ef270ab1SKenneth D. Merry  * - (-1), if remote node is neither the loser nor the winner
1284*ef270ab1SKenneth D. Merry  *   (WWPNs match)
1285*ef270ab1SKenneth D. Merry  */
1286*ef270ab1SKenneth D. Merry 
1287*ef270ab1SKenneth D. Merry static int32_t
1288*ef270ab1SKenneth D. Merry ocs_rnode_is_winner(ocs_sport_t *sport)
1289*ef270ab1SKenneth D. Merry {
1290*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *remote_sparms = (fc_plogi_payload_t*) sport->domain->flogi_service_params;
1291*ef270ab1SKenneth D. Merry 	uint64_t remote_wwpn = ocs_get_wwpn(remote_sparms);
1292*ef270ab1SKenneth D. Merry 	uint64_t local_wwpn = sport->wwpn;
1293*ef270ab1SKenneth D. Merry 	char prop_buf[32];
1294*ef270ab1SKenneth D. Merry 	uint64_t wwn_bump = 0;
1295*ef270ab1SKenneth D. Merry 
1296*ef270ab1SKenneth D. Merry 	if (ocs_get_property("wwn_bump", prop_buf, sizeof(prop_buf)) == 0) {
1297*ef270ab1SKenneth D. Merry 		wwn_bump = ocs_strtoull(prop_buf, 0, 0);
1298*ef270ab1SKenneth D. Merry 	}
1299*ef270ab1SKenneth D. Merry 	local_wwpn ^= wwn_bump;
1300*ef270ab1SKenneth D. Merry 
1301*ef270ab1SKenneth D. Merry 	remote_wwpn = ocs_get_wwpn(remote_sparms);
1302*ef270ab1SKenneth D. Merry 
1303*ef270ab1SKenneth D. Merry 	ocs_log_debug(sport->ocs, "r: %08x %08x\n", ocs_be32toh(remote_sparms->port_name_hi), ocs_be32toh(remote_sparms->port_name_lo));
1304*ef270ab1SKenneth D. Merry 	ocs_log_debug(sport->ocs, "l: %08x %08x\n", (uint32_t) (local_wwpn >> 32ll), (uint32_t) local_wwpn);
1305*ef270ab1SKenneth D. Merry 
1306*ef270ab1SKenneth D. Merry 	if (remote_wwpn == local_wwpn) {
1307*ef270ab1SKenneth D. Merry 		ocs_log_warn(sport->ocs, "WWPN of remote node [%08x %08x] matches local WWPN\n",
1308*ef270ab1SKenneth D. Merry 			(uint32_t) (local_wwpn >> 32ll), (uint32_t) local_wwpn);
1309*ef270ab1SKenneth D. Merry 		return (-1);
1310*ef270ab1SKenneth D. Merry 	}
1311*ef270ab1SKenneth D. Merry 
1312*ef270ab1SKenneth D. Merry 	return (remote_wwpn > local_wwpn);
1313*ef270ab1SKenneth D. Merry }
1314*ef270ab1SKenneth D. Merry 
1315*ef270ab1SKenneth D. Merry /**
1316*ef270ab1SKenneth D. Merry  * @ingroup p2p_sm
1317*ef270ab1SKenneth D. Merry  * @brief Point-to-point state machine: Wait for the domain attach to complete.
1318*ef270ab1SKenneth D. Merry  *
1319*ef270ab1SKenneth D. Merry  * @par Description
1320*ef270ab1SKenneth D. Merry  * Once the domain attach has completed, a PLOGI is sent (if we're the
1321*ef270ab1SKenneth D. Merry  * winning point-to-point node).
1322*ef270ab1SKenneth D. Merry  *
1323*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1324*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1325*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1326*ef270ab1SKenneth D. Merry  *
1327*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1328*ef270ab1SKenneth D. Merry  */
1329*ef270ab1SKenneth D. Merry 
1330*ef270ab1SKenneth D. Merry void *
1331*ef270ab1SKenneth D. Merry __ocs_p2p_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1332*ef270ab1SKenneth D. Merry {
1333*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1334*ef270ab1SKenneth D. Merry 
1335*ef270ab1SKenneth D. Merry 	node_sm_trace();
1336*ef270ab1SKenneth D. Merry 
1337*ef270ab1SKenneth D. Merry 	switch(evt) {
1338*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1339*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1340*ef270ab1SKenneth D. Merry 		break;
1341*ef270ab1SKenneth D. Merry 
1342*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1343*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1344*ef270ab1SKenneth D. Merry 		break;
1345*ef270ab1SKenneth D. Merry 
1346*ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK: {
1347*ef270ab1SKenneth D. Merry 		ocs_sport_t *sport = node->sport;
1348*ef270ab1SKenneth D. Merry 		ocs_node_t *rnode;
1349*ef270ab1SKenneth D. Merry 
1350*ef270ab1SKenneth D. Merry 		/* this transient node (SID=0 (recv'd FLOGI) or DID=fabric (sent FLOGI))
1351*ef270ab1SKenneth D. Merry 		 * is the p2p winner, will use a separate node to send PLOGI to peer
1352*ef270ab1SKenneth D. Merry 		 */
1353*ef270ab1SKenneth D. Merry 		ocs_assert (node->sport->p2p_winner, NULL);
1354*ef270ab1SKenneth D. Merry 
1355*ef270ab1SKenneth D. Merry 		rnode = ocs_node_find(sport, node->sport->p2p_remote_port_id);
1356*ef270ab1SKenneth D. Merry 		if (rnode != NULL) {
1357*ef270ab1SKenneth D. Merry 			/* the "other" transient p2p node has already kicked off the
1358*ef270ab1SKenneth D. Merry 			 * new node from which PLOGI is sent */
1359*ef270ab1SKenneth D. Merry 			node_printf(node, "Node with fc_id x%x already exists\n", rnode->rnode.fc_id);
1360*ef270ab1SKenneth D. Merry 			ocs_assert (rnode != node, NULL);
1361*ef270ab1SKenneth D. Merry 		} else {
1362*ef270ab1SKenneth D. Merry 			/* create new node (SID=1, DID=2) from which to send PLOGI */
1363*ef270ab1SKenneth D. Merry 			rnode = ocs_node_alloc(sport, sport->p2p_remote_port_id, FALSE, FALSE);
1364*ef270ab1SKenneth D. Merry 			if (rnode == NULL) {
1365*ef270ab1SKenneth D. Merry 				ocs_log_err(ocs, "node alloc failed\n");
1366*ef270ab1SKenneth D. Merry 				return NULL;
1367*ef270ab1SKenneth D. Merry 			}
1368*ef270ab1SKenneth D. Merry 
1369*ef270ab1SKenneth D. Merry 			ocs_fabric_notify_topology(node);
1370*ef270ab1SKenneth D. Merry 			/* sm: allocate p2p remote node */
1371*ef270ab1SKenneth D. Merry 			ocs_node_transition(rnode, __ocs_p2p_rnode_init, NULL);
1372*ef270ab1SKenneth D. Merry 		}
1373*ef270ab1SKenneth D. Merry 
1374*ef270ab1SKenneth D. Merry 		/* the transient node (SID=0 or DID=fabric) has served its purpose */
1375*ef270ab1SKenneth D. Merry 		if (node->rnode.fc_id == 0) {
1376*ef270ab1SKenneth D. Merry 			/* if this is the SID=0 node, move to the init state in case peer
1377*ef270ab1SKenneth D. Merry 			 * has restarted FLOGI discovery and FLOGI is pending
1378*ef270ab1SKenneth D. Merry 			 */
1379*ef270ab1SKenneth D. Merry 			/* don't send PLOGI on ocs_d_init entry */
1380*ef270ab1SKenneth D. Merry 			ocs_node_init_device(node, FALSE);
1381*ef270ab1SKenneth D. Merry 		} else {
1382*ef270ab1SKenneth D. Merry 			/* if this is the DID=fabric node (we initiated FLOGI), shut it down */
1383*ef270ab1SKenneth D. Merry 			node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1384*ef270ab1SKenneth D. Merry 			ocs_fabric_initiate_shutdown(node);
1385*ef270ab1SKenneth D. Merry 		}
1386*ef270ab1SKenneth D. Merry 		break;
1387*ef270ab1SKenneth D. Merry 	}
1388*ef270ab1SKenneth D. Merry 
1389*ef270ab1SKenneth D. Merry 	default:
1390*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1391*ef270ab1SKenneth D. Merry 		return NULL;
1392*ef270ab1SKenneth D. Merry 	}
1393*ef270ab1SKenneth D. Merry 
1394*ef270ab1SKenneth D. Merry 	return NULL;
1395*ef270ab1SKenneth D. Merry }
1396*ef270ab1SKenneth D. Merry 
1397*ef270ab1SKenneth D. Merry /**
1398*ef270ab1SKenneth D. Merry  * @ingroup p2p_sm
1399*ef270ab1SKenneth D. Merry  * @brief Point-to-point state machine: Remote node initialization state.
1400*ef270ab1SKenneth D. Merry  *
1401*ef270ab1SKenneth D. Merry  * @par Description
1402*ef270ab1SKenneth D. Merry  * This state is entered after winning point-to-point, and the remote node
1403*ef270ab1SKenneth D. Merry  * is instantiated.
1404*ef270ab1SKenneth D. Merry  *
1405*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1406*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1407*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1408*ef270ab1SKenneth D. Merry  *
1409*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1410*ef270ab1SKenneth D. Merry  */
1411*ef270ab1SKenneth D. Merry 
1412*ef270ab1SKenneth D. Merry void *
1413*ef270ab1SKenneth D. Merry __ocs_p2p_rnode_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1414*ef270ab1SKenneth D. Merry {
1415*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1416*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1417*ef270ab1SKenneth D. Merry 
1418*ef270ab1SKenneth D. Merry 	node_sm_trace();
1419*ef270ab1SKenneth D. Merry 
1420*ef270ab1SKenneth D. Merry 	switch(evt) {
1421*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1422*ef270ab1SKenneth D. Merry 		/* sm: / send PLOGI */
1423*ef270ab1SKenneth D. Merry 		ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
1424*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_p2p_wait_plogi_rsp, NULL);
1425*ef270ab1SKenneth D. Merry 		break;
1426*ef270ab1SKenneth D. Merry 
1427*ef270ab1SKenneth D. Merry 	case OCS_EVT_ABTS_RCVD:
1428*ef270ab1SKenneth D. Merry 		/* sm: send BA_ACC */
1429*ef270ab1SKenneth D. Merry 		ocs_bls_send_acc_hdr(cbdata->io, cbdata->header->dma.virt);
1430*ef270ab1SKenneth D. Merry 		break;
1431*ef270ab1SKenneth D. Merry 
1432*ef270ab1SKenneth D. Merry 	default:
1433*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1434*ef270ab1SKenneth D. Merry 		return NULL;
1435*ef270ab1SKenneth D. Merry 	}
1436*ef270ab1SKenneth D. Merry 
1437*ef270ab1SKenneth D. Merry 	return NULL;
1438*ef270ab1SKenneth D. Merry }
1439*ef270ab1SKenneth D. Merry 
1440*ef270ab1SKenneth D. Merry /**
1441*ef270ab1SKenneth D. Merry  * @ingroup p2p_sm
1442*ef270ab1SKenneth D. Merry  * @brief Point-to-point node state machine: Wait for the FLOGI accept completion.
1443*ef270ab1SKenneth D. Merry  *
1444*ef270ab1SKenneth D. Merry  * @par Description
1445*ef270ab1SKenneth D. Merry  * Wait for the FLOGI accept completion.
1446*ef270ab1SKenneth D. Merry  *
1447*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1448*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1449*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1450*ef270ab1SKenneth D. Merry  *
1451*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1452*ef270ab1SKenneth D. Merry  */
1453*ef270ab1SKenneth D. Merry 
1454*ef270ab1SKenneth D. Merry void *
1455*ef270ab1SKenneth D. Merry __ocs_p2p_wait_flogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1456*ef270ab1SKenneth D. Merry {
1457*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1458*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1459*ef270ab1SKenneth D. Merry 
1460*ef270ab1SKenneth D. Merry 	node_sm_trace();
1461*ef270ab1SKenneth D. Merry 
1462*ef270ab1SKenneth D. Merry 	switch(evt) {
1463*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1464*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1465*ef270ab1SKenneth D. Merry 		break;
1466*ef270ab1SKenneth D. Merry 
1467*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1468*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1469*ef270ab1SKenneth D. Merry 		break;
1470*ef270ab1SKenneth D. Merry 
1471*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK:
1472*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1473*ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1474*ef270ab1SKenneth D. Merry 
1475*ef270ab1SKenneth D. Merry 		/* sm: if p2p_winner / domain_attach */
1476*ef270ab1SKenneth D. Merry 		if (node->sport->p2p_winner) {
1477*ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_p2p_wait_domain_attach, NULL);
1478*ef270ab1SKenneth D. Merry 			if (node->sport->domain->attached &&
1479*ef270ab1SKenneth D. Merry 			    !(node->sport->domain->domain_notify_pend)) {
1480*ef270ab1SKenneth D. Merry 				node_printf(node, "Domain already attached\n");
1481*ef270ab1SKenneth D. Merry 				ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
1482*ef270ab1SKenneth D. Merry 			}
1483*ef270ab1SKenneth D. Merry 		} else {
1484*ef270ab1SKenneth D. Merry 			/* this node has served its purpose; we'll expect a PLOGI on a separate
1485*ef270ab1SKenneth D. Merry 			 * node (remote SID=0x1); return this node to init state in case peer
1486*ef270ab1SKenneth D. Merry 			 * restarts discovery -- it may already have (pending frames may exist).
1487*ef270ab1SKenneth D. Merry 			 */
1488*ef270ab1SKenneth D. Merry 			/* don't send PLOGI on ocs_d_init entry */
1489*ef270ab1SKenneth D. Merry 			ocs_node_init_device(node, FALSE);
1490*ef270ab1SKenneth D. Merry 		}
1491*ef270ab1SKenneth D. Merry 		break;
1492*ef270ab1SKenneth D. Merry 
1493*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
1494*ef270ab1SKenneth D. Merry 		/* LS_ACC failed, possibly due to link down; shutdown node and wait
1495*ef270ab1SKenneth D. Merry 		 * for FLOGI discovery to restart */
1496*ef270ab1SKenneth D. Merry 		node_printf(node, "FLOGI LS_ACC failed, shutting down\n");
1497*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1498*ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1499*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1500*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
1501*ef270ab1SKenneth D. Merry 		break;
1502*ef270ab1SKenneth D. Merry 
1503*ef270ab1SKenneth D. Merry 	case OCS_EVT_ABTS_RCVD: {
1504*ef270ab1SKenneth D. Merry 		/* sm: / send BA_ACC */
1505*ef270ab1SKenneth D. Merry 		ocs_bls_send_acc_hdr(cbdata->io, cbdata->header->dma.virt);
1506*ef270ab1SKenneth D. Merry 		break;
1507*ef270ab1SKenneth D. Merry 	}
1508*ef270ab1SKenneth D. Merry 
1509*ef270ab1SKenneth D. Merry 	default:
1510*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1511*ef270ab1SKenneth D. Merry 		return NULL;
1512*ef270ab1SKenneth D. Merry 	}
1513*ef270ab1SKenneth D. Merry 
1514*ef270ab1SKenneth D. Merry 	return NULL;
1515*ef270ab1SKenneth D. Merry }
1516*ef270ab1SKenneth D. Merry 
1517*ef270ab1SKenneth D. Merry 
1518*ef270ab1SKenneth D. Merry /**
1519*ef270ab1SKenneth D. Merry  * @ingroup p2p_sm
1520*ef270ab1SKenneth D. Merry  * @brief Point-to-point node state machine: Wait for a PLOGI response
1521*ef270ab1SKenneth D. Merry  * as a point-to-point winner.
1522*ef270ab1SKenneth D. Merry  *
1523*ef270ab1SKenneth D. Merry  * @par Description
1524*ef270ab1SKenneth D. Merry  * Wait for a PLOGI response from the remote node as a point-to-point winner.
1525*ef270ab1SKenneth D. Merry  * Submit node attach request to the HW.
1526*ef270ab1SKenneth D. Merry  *
1527*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1528*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1529*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1530*ef270ab1SKenneth D. Merry  *
1531*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1532*ef270ab1SKenneth D. Merry  */
1533*ef270ab1SKenneth D. Merry 
1534*ef270ab1SKenneth D. Merry void *
1535*ef270ab1SKenneth D. Merry __ocs_p2p_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1536*ef270ab1SKenneth D. Merry {
1537*ef270ab1SKenneth D. Merry 	int32_t rc;
1538*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1539*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1540*ef270ab1SKenneth D. Merry 
1541*ef270ab1SKenneth D. Merry 	node_sm_trace();
1542*ef270ab1SKenneth D. Merry 
1543*ef270ab1SKenneth D. Merry 	switch(evt) {
1544*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK: {
1545*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) {
1546*ef270ab1SKenneth D. Merry 			return NULL;
1547*ef270ab1SKenneth D. Merry 		}
1548*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1549*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1550*ef270ab1SKenneth D. Merry 		/* sm: / save sparams, ocs_node_attach */
1551*ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1552*ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
1553*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_p2p_wait_node_attach, NULL);
1554*ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1555*ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1556*ef270ab1SKenneth D. Merry 		}
1557*ef270ab1SKenneth D. Merry 		break;
1558*ef270ab1SKenneth D. Merry 	}
1559*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL: {
1560*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) {
1561*ef270ab1SKenneth D. Merry 			return NULL;
1562*ef270ab1SKenneth D. Merry 		}
1563*ef270ab1SKenneth D. Merry 		node_printf(node, "PLOGI failed, shutting down\n");
1564*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1565*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1566*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1567*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
1568*ef270ab1SKenneth D. Merry 		break;
1569*ef270ab1SKenneth D. Merry 	}
1570*ef270ab1SKenneth D. Merry 
1571*ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD: {
1572*ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1573*ef270ab1SKenneth D. Merry 		/* if we're in external loopback mode, just send LS_ACC */
1574*ef270ab1SKenneth D. Merry 		if (node->ocs->external_loopback) {
1575*ef270ab1SKenneth D. Merry 			ocs_send_plogi_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1576*ef270ab1SKenneth D. Merry 			break;
1577*ef270ab1SKenneth D. Merry 		} else{
1578*ef270ab1SKenneth D. Merry 			/* if this isn't external loopback, pass to default handler */
1579*ef270ab1SKenneth D. Merry 			__ocs_fabric_common(__func__, ctx, evt, arg);
1580*ef270ab1SKenneth D. Merry 		}
1581*ef270ab1SKenneth D. Merry 		break;
1582*ef270ab1SKenneth D. Merry 	}
1583*ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLI_RCVD:
1584*ef270ab1SKenneth D. Merry 		/* I, or I+T */
1585*ef270ab1SKenneth D. Merry 		/* sent PLOGI and before completion was seen, received the
1586*ef270ab1SKenneth D. Merry 		 * PRLI from the remote node (WCQEs and RCQEs come in on
1587*ef270ab1SKenneth D. Merry 		 * different queues and order of processing cannot be assumed)
1588*ef270ab1SKenneth D. Merry 		 * Save OXID so PRLI can be sent after the attach and continue
1589*ef270ab1SKenneth D. Merry 		 * to wait for PLOGI response
1590*ef270ab1SKenneth D. Merry 		 */
1591*ef270ab1SKenneth D. Merry 		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1592*ef270ab1SKenneth D. Merry 		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI);
1593*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_p2p_wait_plogi_rsp_recvd_prli, NULL);
1594*ef270ab1SKenneth D. Merry 		break;
1595*ef270ab1SKenneth D. Merry 	default:
1596*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1597*ef270ab1SKenneth D. Merry 		return NULL;
1598*ef270ab1SKenneth D. Merry 	}
1599*ef270ab1SKenneth D. Merry 
1600*ef270ab1SKenneth D. Merry 	return NULL;
1601*ef270ab1SKenneth D. Merry }
1602*ef270ab1SKenneth D. Merry 
1603*ef270ab1SKenneth D. Merry /**
1604*ef270ab1SKenneth D. Merry  * @ingroup p2p_sm
1605*ef270ab1SKenneth D. Merry  * @brief Point-to-point node state machine: Waiting on a response for a
1606*ef270ab1SKenneth D. Merry  *	sent PLOGI.
1607*ef270ab1SKenneth D. Merry  *
1608*ef270ab1SKenneth D. Merry  * @par Description
1609*ef270ab1SKenneth D. Merry  * State is entered when the point-to-point winner has sent
1610*ef270ab1SKenneth D. Merry  * a PLOGI and is waiting for a response. Before receiving the
1611*ef270ab1SKenneth D. Merry  * response, a PRLI was received, implying that the PLOGI was
1612*ef270ab1SKenneth D. Merry  * successful.
1613*ef270ab1SKenneth D. Merry  *
1614*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1615*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1616*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1617*ef270ab1SKenneth D. Merry  *
1618*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1619*ef270ab1SKenneth D. Merry  */
1620*ef270ab1SKenneth D. Merry 
1621*ef270ab1SKenneth D. Merry void *
1622*ef270ab1SKenneth D. Merry __ocs_p2p_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1623*ef270ab1SKenneth D. Merry {
1624*ef270ab1SKenneth D. Merry 	int32_t rc;
1625*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1626*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1627*ef270ab1SKenneth D. Merry 
1628*ef270ab1SKenneth D. Merry 	node_sm_trace();
1629*ef270ab1SKenneth D. Merry 
1630*ef270ab1SKenneth D. Merry 	switch(evt) {
1631*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1632*ef270ab1SKenneth D. Merry 		/*
1633*ef270ab1SKenneth D. Merry 		 * Since we've received a PRLI, we have a port login and will
1634*ef270ab1SKenneth D. Merry 		 * just need to wait for the PLOGI response to do the node
1635*ef270ab1SKenneth D. Merry 		 * attach and then we can send the LS_ACC for the PRLI. If,
1636*ef270ab1SKenneth D. Merry 		 * during this time, we receive FCP_CMNDs (which is possible
1637*ef270ab1SKenneth D. Merry 		 * since we've already sent a PRLI and our peer may have accepted).
1638*ef270ab1SKenneth D. Merry 		 * At this time, we are not waiting on any other unsolicited
1639*ef270ab1SKenneth D. Merry 		 * frames to continue with the login process. Thus, it will not
1640*ef270ab1SKenneth D. Merry 		 * hurt to hold frames here.
1641*ef270ab1SKenneth D. Merry 		 */
1642*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1643*ef270ab1SKenneth D. Merry 		break;
1644*ef270ab1SKenneth D. Merry 
1645*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1646*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1647*ef270ab1SKenneth D. Merry 		break;
1648*ef270ab1SKenneth D. Merry 
1649*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
1650*ef270ab1SKenneth D. Merry 		/* Completion from PLOGI sent */
1651*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) {
1652*ef270ab1SKenneth D. Merry 			return NULL;
1653*ef270ab1SKenneth D. Merry 		}
1654*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1655*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1656*ef270ab1SKenneth D. Merry 		/* sm: / save sparams, ocs_node_attach */
1657*ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1658*ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
1659*ef270ab1SKenneth D. Merry 			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
1660*ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
1661*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_p2p_wait_node_attach, NULL);
1662*ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1663*ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1664*ef270ab1SKenneth D. Merry 		}
1665*ef270ab1SKenneth D. Merry 		break;
1666*ef270ab1SKenneth D. Merry 
1667*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
1668*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
1669*ef270ab1SKenneth D. Merry 		/* PLOGI failed, shutdown the node */
1670*ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) {
1671*ef270ab1SKenneth D. Merry 			return NULL;
1672*ef270ab1SKenneth D. Merry 		}
1673*ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1674*ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1675*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1676*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
1677*ef270ab1SKenneth D. Merry 		break;
1678*ef270ab1SKenneth D. Merry 
1679*ef270ab1SKenneth D. Merry 	default:
1680*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1681*ef270ab1SKenneth D. Merry 		return NULL;
1682*ef270ab1SKenneth D. Merry 	}
1683*ef270ab1SKenneth D. Merry 
1684*ef270ab1SKenneth D. Merry 	return NULL;
1685*ef270ab1SKenneth D. Merry }
1686*ef270ab1SKenneth D. Merry 
1687*ef270ab1SKenneth D. Merry /**
1688*ef270ab1SKenneth D. Merry  * @ingroup p2p_sm
1689*ef270ab1SKenneth D. Merry  * @brief Point-to-point node state machine: Wait for a point-to-point node attach
1690*ef270ab1SKenneth D. Merry  * to complete.
1691*ef270ab1SKenneth D. Merry  *
1692*ef270ab1SKenneth D. Merry  * @par Description
1693*ef270ab1SKenneth D. Merry  * Waits for the point-to-point node attach to complete.
1694*ef270ab1SKenneth D. Merry  *
1695*ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1696*ef270ab1SKenneth D. Merry  * @param evt Event to process.
1697*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1698*ef270ab1SKenneth D. Merry  *
1699*ef270ab1SKenneth D. Merry  * @return Returns NULL.
1700*ef270ab1SKenneth D. Merry  */
1701*ef270ab1SKenneth D. Merry 
1702*ef270ab1SKenneth D. Merry void *
1703*ef270ab1SKenneth D. Merry __ocs_p2p_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1704*ef270ab1SKenneth D. Merry {
1705*ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1706*ef270ab1SKenneth D. Merry 	std_node_state_decl();
1707*ef270ab1SKenneth D. Merry 
1708*ef270ab1SKenneth D. Merry 	node_sm_trace();
1709*ef270ab1SKenneth D. Merry 
1710*ef270ab1SKenneth D. Merry 	switch(evt) {
1711*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1712*ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1713*ef270ab1SKenneth D. Merry 		break;
1714*ef270ab1SKenneth D. Merry 
1715*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1716*ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1717*ef270ab1SKenneth D. Merry 		break;
1718*ef270ab1SKenneth D. Merry 
1719*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
1720*ef270ab1SKenneth D. Merry 		node->attached = TRUE;
1721*ef270ab1SKenneth D. Merry 		switch (node->send_ls_acc) {
1722*ef270ab1SKenneth D. Merry 		case OCS_NODE_SEND_LS_ACC_PRLI: {
1723*ef270ab1SKenneth D. Merry 			ocs_d_send_prli_rsp(node->ls_acc_io, node->ls_acc_oxid);
1724*ef270ab1SKenneth D. Merry 			node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
1725*ef270ab1SKenneth D. Merry 			node->ls_acc_io = NULL;
1726*ef270ab1SKenneth D. Merry 			break;
1727*ef270ab1SKenneth D. Merry 		}
1728*ef270ab1SKenneth D. Merry 		case OCS_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */
1729*ef270ab1SKenneth D. Merry 		case OCS_NODE_SEND_LS_ACC_NONE:
1730*ef270ab1SKenneth D. Merry 		default:
1731*ef270ab1SKenneth D. Merry 			/* Normal case for I */
1732*ef270ab1SKenneth D. Merry 			/* sm: send_plogi_acc is not set / send PLOGI acc */
1733*ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_port_logged_in, NULL);
1734*ef270ab1SKenneth D. Merry 			break;
1735*ef270ab1SKenneth D. Merry 		}
1736*ef270ab1SKenneth D. Merry 		break;
1737*ef270ab1SKenneth D. Merry 
1738*ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_FAIL:
1739*ef270ab1SKenneth D. Merry 		/* node attach failed, shutdown the node */
1740*ef270ab1SKenneth D. Merry 		node->attached = FALSE;
1741*ef270ab1SKenneth D. Merry 		node_printf(node, "Node attach failed\n");
1742*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1743*ef270ab1SKenneth D. Merry 		ocs_fabric_initiate_shutdown(node);
1744*ef270ab1SKenneth D. Merry 		break;
1745*ef270ab1SKenneth D. Merry 
1746*ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1747*ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1748*ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1749*ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL);
1750*ef270ab1SKenneth D. Merry 		break;
1751*ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLI_RCVD:
1752*ef270ab1SKenneth D. Merry 		node_printf(node, "%s: PRLI received before node is attached\n", ocs_sm_event_name(evt));
1753*ef270ab1SKenneth D. Merry 		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1754*ef270ab1SKenneth D. Merry 		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI);
1755*ef270ab1SKenneth D. Merry 		break;
1756*ef270ab1SKenneth D. Merry 	default:
1757*ef270ab1SKenneth D. Merry 		__ocs_fabric_common(__func__, ctx, evt, arg);
1758*ef270ab1SKenneth D. Merry 		return NULL;
1759*ef270ab1SKenneth D. Merry 	}
1760*ef270ab1SKenneth D. Merry 
1761*ef270ab1SKenneth D. Merry 	return NULL;
1762*ef270ab1SKenneth D. Merry }
1763*ef270ab1SKenneth D. Merry 
1764*ef270ab1SKenneth D. Merry /**
1765*ef270ab1SKenneth D. Merry  * @brief Start up the name services node.
1766*ef270ab1SKenneth D. Merry  *
1767*ef270ab1SKenneth D. Merry  * @par Description
1768*ef270ab1SKenneth D. Merry  * Allocates and starts up the name services node.
1769*ef270ab1SKenneth D. Merry  *
1770*ef270ab1SKenneth D. Merry  * @param sport Pointer to the sport structure.
1771*ef270ab1SKenneth D. Merry  *
1772*ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error value on failure.
1773*ef270ab1SKenneth D. Merry  */
1774*ef270ab1SKenneth D. Merry 
1775*ef270ab1SKenneth D. Merry static int32_t
1776*ef270ab1SKenneth D. Merry ocs_start_ns_node(ocs_sport_t *sport)
1777*ef270ab1SKenneth D. Merry {
1778*ef270ab1SKenneth D. Merry 	ocs_node_t *ns;
1779*ef270ab1SKenneth D. Merry 
1780*ef270ab1SKenneth D. Merry 	/* Instantiate a name services node */
1781*ef270ab1SKenneth D. Merry 	ns = ocs_node_find(sport, FC_ADDR_NAMESERVER);
1782*ef270ab1SKenneth D. Merry 	if (ns == NULL) {
1783*ef270ab1SKenneth D. Merry 		ns = ocs_node_alloc(sport, FC_ADDR_NAMESERVER, FALSE, FALSE);
1784*ef270ab1SKenneth D. Merry 		if (ns == NULL) {
1785*ef270ab1SKenneth D. Merry 			return -1;
1786*ef270ab1SKenneth D. Merry 		}
1787*ef270ab1SKenneth D. Merry 	}
1788*ef270ab1SKenneth D. Merry 	/* TODO: for found ns, should we be transitioning from here?
1789*ef270ab1SKenneth D. Merry 	 * breaks transition only 1. from within state machine or
1790*ef270ab1SKenneth D. Merry 	 * 2. if after alloc
1791*ef270ab1SKenneth D. Merry 	 */
1792*ef270ab1SKenneth D. Merry 	if (ns->ocs->nodedb_mask & OCS_NODEDB_PAUSE_NAMESERVER) {
1793*ef270ab1SKenneth D. Merry 		ocs_node_pause(ns, __ocs_ns_init);
1794*ef270ab1SKenneth D. Merry 	} else {
1795*ef270ab1SKenneth D. Merry 		ocs_node_transition(ns, __ocs_ns_init, NULL);
1796*ef270ab1SKenneth D. Merry 	}
1797*ef270ab1SKenneth D. Merry 	return 0;
1798*ef270ab1SKenneth D. Merry }
1799*ef270ab1SKenneth D. Merry 
1800*ef270ab1SKenneth D. Merry /**
1801*ef270ab1SKenneth D. Merry  * @brief Start up the fabric controller node.
1802*ef270ab1SKenneth D. Merry  *
1803*ef270ab1SKenneth D. Merry  * @par Description
1804*ef270ab1SKenneth D. Merry  * Allocates and starts up the fabric controller node.
1805*ef270ab1SKenneth D. Merry  *
1806*ef270ab1SKenneth D. Merry  * @param sport Pointer to the sport structure.
1807*ef270ab1SKenneth D. Merry  *
1808*ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error value on failure.
1809*ef270ab1SKenneth D. Merry  */
1810*ef270ab1SKenneth D. Merry 
1811*ef270ab1SKenneth D. Merry static int32_t
1812*ef270ab1SKenneth D. Merry ocs_start_fabctl_node(ocs_sport_t *sport)
1813*ef270ab1SKenneth D. Merry {
1814*ef270ab1SKenneth D. Merry 	ocs_node_t *fabctl;
1815*ef270ab1SKenneth D. Merry 
1816*ef270ab1SKenneth D. Merry 	fabctl = ocs_node_find(sport, FC_ADDR_CONTROLLER);
1817*ef270ab1SKenneth D. Merry 	if (fabctl == NULL) {
1818*ef270ab1SKenneth D. Merry 		fabctl = ocs_node_alloc(sport, FC_ADDR_CONTROLLER, FALSE, FALSE);
1819*ef270ab1SKenneth D. Merry 		if (fabctl == NULL) {
1820*ef270ab1SKenneth D. Merry 			return -1;
1821*ef270ab1SKenneth D. Merry 		}
1822*ef270ab1SKenneth D. Merry 	}
1823*ef270ab1SKenneth D. Merry 	/* TODO: for found ns, should we be transitioning from here?
1824*ef270ab1SKenneth D. Merry 	 * breaks transition only 1. from within state machine or
1825*ef270ab1SKenneth D. Merry 	 * 2. if after alloc
1826*ef270ab1SKenneth D. Merry 	 */
1827*ef270ab1SKenneth D. Merry 	ocs_node_transition(fabctl, __ocs_fabctl_init, NULL);
1828*ef270ab1SKenneth D. Merry 	return 0;
1829*ef270ab1SKenneth D. Merry }
1830*ef270ab1SKenneth D. Merry 
1831*ef270ab1SKenneth D. Merry /**
1832*ef270ab1SKenneth D. Merry  * @brief Process the GIDPT payload.
1833*ef270ab1SKenneth D. Merry  *
1834*ef270ab1SKenneth D. Merry  * @par Description
1835*ef270ab1SKenneth D. Merry  * The GIDPT payload is parsed, and new nodes are created, as needed.
1836*ef270ab1SKenneth D. Merry  *
1837*ef270ab1SKenneth D. Merry  * @param node Pointer to the node structure.
1838*ef270ab1SKenneth D. Merry  * @param gidpt Pointer to the GIDPT payload.
1839*ef270ab1SKenneth D. Merry  * @param gidpt_len Payload length
1840*ef270ab1SKenneth D. Merry  *
1841*ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error value on failure.
1842*ef270ab1SKenneth D. Merry  */
1843*ef270ab1SKenneth D. Merry 
1844*ef270ab1SKenneth D. Merry static int32_t
1845*ef270ab1SKenneth D. Merry ocs_process_gidpt_payload(ocs_node_t *node, fcct_gidpt_acc_t *gidpt, uint32_t gidpt_len)
1846*ef270ab1SKenneth D. Merry {
1847*ef270ab1SKenneth D. Merry 	uint32_t i;
1848*ef270ab1SKenneth D. Merry 	uint32_t j;
1849*ef270ab1SKenneth D. Merry 	ocs_node_t *newnode;
1850*ef270ab1SKenneth D. Merry 	ocs_sport_t *sport = node->sport;
1851*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1852*ef270ab1SKenneth D. Merry 	uint32_t port_id;
1853*ef270ab1SKenneth D. Merry 	uint32_t port_count;
1854*ef270ab1SKenneth D. Merry 	ocs_node_t *n;
1855*ef270ab1SKenneth D. Merry 	ocs_node_t **active_nodes;
1856*ef270ab1SKenneth D. Merry 	uint32_t portlist_count;
1857*ef270ab1SKenneth D. Merry 	uint16_t residual;
1858*ef270ab1SKenneth D. Merry 
1859*ef270ab1SKenneth D. Merry 	residual = ocs_be16toh(gidpt->hdr.max_residual_size);
1860*ef270ab1SKenneth D. Merry 
1861*ef270ab1SKenneth D. Merry 	if (residual != 0) {
1862*ef270ab1SKenneth D. Merry 		ocs_log_debug(node->ocs, "residual is %u words\n", residual);
1863*ef270ab1SKenneth D. Merry 	}
1864*ef270ab1SKenneth D. Merry 
1865*ef270ab1SKenneth D. Merry 	if (ocs_be16toh(gidpt->hdr.cmd_rsp_code) == FCCT_HDR_CMDRSP_REJECT) {
1866*ef270ab1SKenneth D. Merry 		node_printf(node, "GIDPT request failed: rsn x%x rsn_expl x%x\n",
1867*ef270ab1SKenneth D. Merry 			gidpt->hdr.reason_code, gidpt->hdr.reason_code_explanation);
1868*ef270ab1SKenneth D. Merry 		return -1;
1869*ef270ab1SKenneth D. Merry 	}
1870*ef270ab1SKenneth D. Merry 
1871*ef270ab1SKenneth D. Merry 	portlist_count = (gidpt_len - sizeof(fcct_iu_header_t)) / sizeof(gidpt->port_list);
1872*ef270ab1SKenneth D. Merry 
1873*ef270ab1SKenneth D. Merry 	/* Count the number of nodes */
1874*ef270ab1SKenneth D. Merry 	port_count = 0;
1875*ef270ab1SKenneth D. Merry 	ocs_sport_lock(sport);
1876*ef270ab1SKenneth D. Merry 		ocs_list_foreach(&sport->node_list, n) {
1877*ef270ab1SKenneth D. Merry 			port_count ++;
1878*ef270ab1SKenneth D. Merry 		}
1879*ef270ab1SKenneth D. Merry 
1880*ef270ab1SKenneth D. Merry 		/* Allocate a buffer for all nodes */
1881*ef270ab1SKenneth D. Merry 		active_nodes = ocs_malloc(node->ocs, port_count * sizeof(*active_nodes), OCS_M_NOWAIT | OCS_M_ZERO);
1882*ef270ab1SKenneth D. Merry 		if (active_nodes == NULL) {
1883*ef270ab1SKenneth D. Merry 			node_printf(node, "ocs_malloc failed\n");
1884*ef270ab1SKenneth D. Merry 			ocs_sport_unlock(sport);
1885*ef270ab1SKenneth D. Merry 			return -1;
1886*ef270ab1SKenneth D. Merry 		}
1887*ef270ab1SKenneth D. Merry 
1888*ef270ab1SKenneth D. Merry 		/* Fill buffer with fc_id of active nodes */
1889*ef270ab1SKenneth D. Merry 		i = 0;
1890*ef270ab1SKenneth D. Merry 		ocs_list_foreach(&sport->node_list, n) {
1891*ef270ab1SKenneth D. Merry 			port_id = n->rnode.fc_id;
1892*ef270ab1SKenneth D. Merry 			switch (port_id) {
1893*ef270ab1SKenneth D. Merry 			case FC_ADDR_FABRIC:
1894*ef270ab1SKenneth D. Merry 			case FC_ADDR_CONTROLLER:
1895*ef270ab1SKenneth D. Merry 			case FC_ADDR_NAMESERVER:
1896*ef270ab1SKenneth D. Merry 				break;
1897*ef270ab1SKenneth D. Merry 			default:
1898*ef270ab1SKenneth D. Merry 				if (!FC_ADDR_IS_DOMAIN_CTRL(port_id)) {
1899*ef270ab1SKenneth D. Merry 					active_nodes[i++] = n;
1900*ef270ab1SKenneth D. Merry 				}
1901*ef270ab1SKenneth D. Merry 				break;
1902*ef270ab1SKenneth D. Merry 			}
1903*ef270ab1SKenneth D. Merry 		}
1904*ef270ab1SKenneth D. Merry 
1905*ef270ab1SKenneth D. Merry 		/* update the active nodes buffer */
1906*ef270ab1SKenneth D. Merry 		for (i = 0; i < portlist_count; i ++) {
1907*ef270ab1SKenneth D. Merry 			port_id = fc_be24toh(gidpt->port_list[i].port_id);
1908*ef270ab1SKenneth D. Merry 
1909*ef270ab1SKenneth D. Merry 			for (j = 0; j < port_count; j ++) {
1910*ef270ab1SKenneth D. Merry 				if ((active_nodes[j] != NULL) && (port_id == active_nodes[j]->rnode.fc_id)) {
1911*ef270ab1SKenneth D. Merry 					active_nodes[j] = NULL;
1912*ef270ab1SKenneth D. Merry 				}
1913*ef270ab1SKenneth D. Merry 			}
1914*ef270ab1SKenneth D. Merry 
1915*ef270ab1SKenneth D. Merry 			if (gidpt->port_list[i].ctl & FCCT_GID_PT_LAST_ID)
1916*ef270ab1SKenneth D. Merry 				break;
1917*ef270ab1SKenneth D. Merry 		}
1918*ef270ab1SKenneth D. Merry 
1919*ef270ab1SKenneth D. Merry 		/* Those remaining in the active_nodes[] are now gone ! */
1920*ef270ab1SKenneth D. Merry 		for (i = 0; i < port_count; i ++) {
1921*ef270ab1SKenneth D. Merry 			/* if we're an initiator and the remote node is a target, then
1922*ef270ab1SKenneth D. Merry 			 * post the node missing event.   if we're target and we have enabled
1923*ef270ab1SKenneth D. Merry 			 * target RSCN, then post the node missing event.
1924*ef270ab1SKenneth D. Merry 			 */
1925*ef270ab1SKenneth D. Merry 			if (active_nodes[i] != NULL) {
1926*ef270ab1SKenneth D. Merry 				if ((node->sport->enable_ini && active_nodes[i]->targ) ||
1927*ef270ab1SKenneth D. Merry 				    (node->sport->enable_tgt && enable_target_rscn(ocs))) {
1928*ef270ab1SKenneth D. Merry 					ocs_node_post_event(active_nodes[i], OCS_EVT_NODE_MISSING, NULL);
1929*ef270ab1SKenneth D. Merry 				} else {
1930*ef270ab1SKenneth D. Merry 					node_printf(node, "GID_PT: skipping non-tgt port_id x%06x\n",
1931*ef270ab1SKenneth D. Merry 						active_nodes[i]->rnode.fc_id);
1932*ef270ab1SKenneth D. Merry 				}
1933*ef270ab1SKenneth D. Merry 			}
1934*ef270ab1SKenneth D. Merry 		}
1935*ef270ab1SKenneth D. Merry 		ocs_free(ocs, active_nodes, port_count * sizeof(*active_nodes));
1936*ef270ab1SKenneth D. Merry 
1937*ef270ab1SKenneth D. Merry 		for(i = 0; i < portlist_count; i ++) {
1938*ef270ab1SKenneth D. Merry 			uint32_t port_id = fc_be24toh(gidpt->port_list[i].port_id);
1939*ef270ab1SKenneth D. Merry 
1940*ef270ab1SKenneth D. Merry 			/* node_printf(node, "GID_PT: port_id x%06x\n", port_id); */
1941*ef270ab1SKenneth D. Merry 
1942*ef270ab1SKenneth D. Merry 			/* Don't create node for ourselves or the associated NPIV ports */
1943*ef270ab1SKenneth D. Merry 			if (port_id != node->rnode.sport->fc_id && !ocs_sport_find(sport->domain, port_id)) {
1944*ef270ab1SKenneth D. Merry 				newnode = ocs_node_find(sport, port_id);
1945*ef270ab1SKenneth D. Merry 				if (newnode) {
1946*ef270ab1SKenneth D. Merry 					/* TODO: what if node deleted here?? */
1947*ef270ab1SKenneth D. Merry 					if (node->sport->enable_ini && newnode->targ) {
1948*ef270ab1SKenneth D. Merry 						ocs_node_post_event(newnode, OCS_EVT_NODE_REFOUND, NULL);
1949*ef270ab1SKenneth D. Merry 					}
1950*ef270ab1SKenneth D. Merry 					/* original code sends ADISC, has notion of "refound" */
1951*ef270ab1SKenneth D. Merry 				} else {
1952*ef270ab1SKenneth D. Merry 					if (node->sport->enable_ini) {
1953*ef270ab1SKenneth D. Merry 						newnode = ocs_node_alloc(sport, port_id, 0, 0);
1954*ef270ab1SKenneth D. Merry 						if (newnode == NULL) {
1955*ef270ab1SKenneth D. Merry 							ocs_log_err(ocs, "ocs_node_alloc() failed\n");
1956*ef270ab1SKenneth D. Merry 							ocs_sport_unlock(sport);
1957*ef270ab1SKenneth D. Merry 							return -1;
1958*ef270ab1SKenneth D. Merry 						}
1959*ef270ab1SKenneth D. Merry 						/* send PLOGI automatically if initiator */
1960*ef270ab1SKenneth D. Merry 						ocs_node_init_device(newnode, TRUE);
1961*ef270ab1SKenneth D. Merry 					}
1962*ef270ab1SKenneth D. Merry 				}
1963*ef270ab1SKenneth D. Merry 			}
1964*ef270ab1SKenneth D. Merry 
1965*ef270ab1SKenneth D. Merry 			if (gidpt->port_list[i].ctl & FCCT_GID_PT_LAST_ID) {
1966*ef270ab1SKenneth D. Merry 				break;
1967*ef270ab1SKenneth D. Merry 			}
1968*ef270ab1SKenneth D. Merry 		}
1969*ef270ab1SKenneth D. Merry 	ocs_sport_unlock(sport);
1970*ef270ab1SKenneth D. Merry 	return 0;
1971*ef270ab1SKenneth D. Merry }
1972*ef270ab1SKenneth D. Merry 
1973*ef270ab1SKenneth D. Merry /**
1974*ef270ab1SKenneth D. Merry  * @brief Set up the domain point-to-point parameters.
1975*ef270ab1SKenneth D. Merry  *
1976*ef270ab1SKenneth D. Merry  * @par Description
1977*ef270ab1SKenneth D. Merry  * The remote node service parameters are examined, and various point-to-point
1978*ef270ab1SKenneth D. Merry  * variables are set.
1979*ef270ab1SKenneth D. Merry  *
1980*ef270ab1SKenneth D. Merry  * @param sport Pointer to the sport object.
1981*ef270ab1SKenneth D. Merry  *
1982*ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error value on failure.
1983*ef270ab1SKenneth D. Merry  */
1984*ef270ab1SKenneth D. Merry 
1985*ef270ab1SKenneth D. Merry int32_t
1986*ef270ab1SKenneth D. Merry ocs_p2p_setup(ocs_sport_t *sport)
1987*ef270ab1SKenneth D. Merry {
1988*ef270ab1SKenneth D. Merry 	ocs_t *ocs = sport->ocs;
1989*ef270ab1SKenneth D. Merry 	int32_t rnode_winner;
1990*ef270ab1SKenneth D. Merry 	rnode_winner = ocs_rnode_is_winner(sport);
1991*ef270ab1SKenneth D. Merry 
1992*ef270ab1SKenneth D. Merry 	/* set sport flags to indicate p2p "winner" */
1993*ef270ab1SKenneth D. Merry 	if (rnode_winner == 1) {
1994*ef270ab1SKenneth D. Merry 		sport->p2p_remote_port_id = 0;
1995*ef270ab1SKenneth D. Merry 		sport->p2p_port_id = 0;
1996*ef270ab1SKenneth D. Merry 		sport->p2p_winner = FALSE;
1997*ef270ab1SKenneth D. Merry 	} else if (rnode_winner == 0) {
1998*ef270ab1SKenneth D. Merry 		sport->p2p_remote_port_id = 2;
1999*ef270ab1SKenneth D. Merry 		sport->p2p_port_id = 1;
2000*ef270ab1SKenneth D. Merry 		sport->p2p_winner = TRUE;
2001*ef270ab1SKenneth D. Merry 	} else {
2002*ef270ab1SKenneth D. Merry 		/* no winner; only okay if external loopback enabled */
2003*ef270ab1SKenneth D. Merry 		if (sport->ocs->external_loopback) {
2004*ef270ab1SKenneth D. Merry 			/*
2005*ef270ab1SKenneth D. Merry 			 * External loopback mode enabled; local sport and remote node
2006*ef270ab1SKenneth D. Merry 			 * will be registered with an NPortID = 1;
2007*ef270ab1SKenneth D. Merry 			 */
2008*ef270ab1SKenneth D. Merry 			ocs_log_debug(ocs, "External loopback mode enabled\n");
2009*ef270ab1SKenneth D. Merry 			sport->p2p_remote_port_id = 1;
2010*ef270ab1SKenneth D. Merry 			sport->p2p_port_id = 1;
2011*ef270ab1SKenneth D. Merry 			sport->p2p_winner = TRUE;
2012*ef270ab1SKenneth D. Merry 		} else {
2013*ef270ab1SKenneth D. Merry 			ocs_log_warn(ocs, "failed to determine p2p winner\n");
2014*ef270ab1SKenneth D. Merry 			return rnode_winner;
2015*ef270ab1SKenneth D. Merry 		}
2016*ef270ab1SKenneth D. Merry 	}
2017*ef270ab1SKenneth D. Merry 	return 0;
2018*ef270ab1SKenneth D. Merry }
2019*ef270ab1SKenneth D. Merry 
2020*ef270ab1SKenneth D. Merry /**
2021*ef270ab1SKenneth D. Merry  * @brief Process the FABCTL node RSCN.
2022*ef270ab1SKenneth D. Merry  *
2023*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2024*ef270ab1SKenneth D. Merry  * Processes the FABCTL node RSCN payload, simply passes the event to the name server.
2025*ef270ab1SKenneth D. Merry  *
2026*ef270ab1SKenneth D. Merry  * @param node Pointer to the node structure.
2027*ef270ab1SKenneth D. Merry  * @param cbdata Callback data to pass forward.
2028*ef270ab1SKenneth D. Merry  *
2029*ef270ab1SKenneth D. Merry  * @return None.
2030*ef270ab1SKenneth D. Merry  */
2031*ef270ab1SKenneth D. Merry 
2032*ef270ab1SKenneth D. Merry static void
2033*ef270ab1SKenneth D. Merry ocs_process_rscn(ocs_node_t *node, ocs_node_cb_t *cbdata)
2034*ef270ab1SKenneth D. Merry {
2035*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
2036*ef270ab1SKenneth D. Merry 	ocs_sport_t *sport = node->sport;
2037*ef270ab1SKenneth D. Merry 	ocs_node_t *ns;
2038*ef270ab1SKenneth D. Merry 
2039*ef270ab1SKenneth D. Merry 	/* Forward this event to the name-services node */
2040*ef270ab1SKenneth D. Merry 	ns = ocs_node_find(sport, FC_ADDR_NAMESERVER);
2041*ef270ab1SKenneth D. Merry 	if (ns != NULL)  {
2042*ef270ab1SKenneth D. Merry 		ocs_node_post_event(ns, OCS_EVT_RSCN_RCVD, cbdata);
2043*ef270ab1SKenneth D. Merry 	} else {
2044*ef270ab1SKenneth D. Merry 		ocs_log_warn(ocs, "can't find name server node\n");
2045*ef270ab1SKenneth D. Merry 	}
2046*ef270ab1SKenneth D. Merry }
2047