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