The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ocs_fc/ocs_fabric.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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                 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 *
  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 *
  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 *
  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 *
  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 *
  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 *
  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 *
  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 *
  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 *
  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 *
  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 *
  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 *
  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
  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 *
  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 *
  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 *
  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 *
 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 *
 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 *
 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
 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 *
 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
 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
 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
 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 *
 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 *
 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 *
 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 *
 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 *
 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 *
 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
 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
 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
 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
 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
 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 }

Cache object: 07b6aced37361af135c4851d631b516f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.