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