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