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