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_domain.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  * Handles the domain object callback from the HW.
   37  */
   38 
   39 /*!
   40 @defgroup domain_sm Domain State Machine: States
   41 */
   42 
   43 #include "ocs.h"
   44 
   45 #include "ocs_fabric.h"
   46 #include "ocs_device.h"
   47 
   48 #define domain_sm_trace(domain)  \
   49         do { \
   50                 if (OCS_LOG_ENABLE_DOMAIN_SM_TRACE(domain->ocs)) \
   51                         ocs_log_info(domain->ocs, "[domain] %-20s %-20s\n", __func__, ocs_sm_event_name(evt)); \
   52         } while (0)
   53 
   54 #define domain_trace(domain, fmt, ...) \
   55         do { \
   56                 if (OCS_LOG_ENABLE_DOMAIN_SM_TRACE(domain ? domain->ocs : NULL)) \
   57                         ocs_log_info(domain ? domain->ocs : NULL, fmt, ##__VA_ARGS__); \
   58         } while (0)
   59 
   60 #define domain_printf(domain, fmt, ...) \
   61         do { \
   62                 ocs_log_info(domain ? domain->ocs : NULL, fmt, ##__VA_ARGS__); \
   63         } while (0)
   64 
   65 void ocs_mgmt_domain_list(ocs_textbuf_t *textbuf, void *domain);
   66 void ocs_mgmt_domain_get_all(ocs_textbuf_t *textbuf, void *domain);
   67 int ocs_mgmt_domain_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *domain);
   68 int ocs_mgmt_domain_set(char *parent, char *name, char *value, void *domain);
   69 int ocs_mgmt_domain_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
   70                 void *arg_out, uint32_t arg_out_length, void *domain);
   71 
   72 static ocs_mgmt_functions_t domain_mgmt_functions = {
   73         .get_list_handler = ocs_mgmt_domain_list,
   74         .get_handler = ocs_mgmt_domain_get,
   75         .get_all_handler = ocs_mgmt_domain_get_all,
   76         .set_handler = ocs_mgmt_domain_set,
   77         .exec_handler = ocs_mgmt_domain_exec,
   78 };
   79 
   80 /**
   81  * @brief Accept domain callback events from the HW.
   82  *
   83  * <h3 class="desc">Description</h3>
   84  * HW calls this function with various domain-related events.
   85  *
   86  * @param arg Application-specified argument.
   87  * @param event Domain event.
   88  * @param data Event specific data.
   89  *
   90  * @return Returns 0 on success; or a negative error value on failure.
   91  */
   92 
   93 int32_t
   94 ocs_domain_cb(void *arg, ocs_hw_domain_event_e event, void *data)
   95 {
   96         ocs_t *ocs = arg;
   97         ocs_domain_t *domain = NULL;
   98         int32_t rc = 0;
   99 
  100         ocs_assert(data, -1);
  101 
  102         if (event != OCS_HW_DOMAIN_FOUND) {
  103                 domain = data;
  104         }
  105 
  106         switch (event) {
  107         case OCS_HW_DOMAIN_FOUND: {
  108                 uint64_t fcf_wwn = 0;
  109                 ocs_domain_record_t *drec = data;
  110                 ocs_assert(drec, -1);
  111 
  112                 /* extract the fcf_wwn */
  113                 fcf_wwn = ocs_be64toh(*((uint64_t*)drec->wwn));
  114 
  115                 /* lookup domain, or allocate a new one if one doesn't exist already */
  116                 domain = ocs_domain_find(ocs, fcf_wwn);
  117                 if (domain == NULL) {
  118                         domain = ocs_domain_alloc(ocs, fcf_wwn);
  119                         if (domain == NULL) {
  120                                 ocs_log_err(ocs, "ocs_domain_alloc() failed\n");
  121                                 rc = -1;
  122                                 break;
  123                         }
  124                         ocs_sm_transition(&domain->drvsm, __ocs_domain_init, NULL);
  125                 }
  126                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FOUND, drec);
  127                 break;
  128         }
  129 
  130         case OCS_HW_DOMAIN_LOST:
  131                 domain_trace(domain, "OCS_HW_DOMAIN_LOST:\n");
  132                 ocs_domain_hold_frames(domain);
  133                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_LOST, NULL);
  134                 break;
  135 
  136         case OCS_HW_DOMAIN_ALLOC_OK: {
  137                 domain_trace(domain, "OCS_HW_DOMAIN_ALLOC_OK:\n");
  138                 domain->instance_index = 0;
  139                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ALLOC_OK, NULL);
  140                 break;
  141         }
  142 
  143         case OCS_HW_DOMAIN_ALLOC_FAIL:
  144                 domain_trace(domain, "OCS_HW_DOMAIN_ALLOC_FAIL:\n");
  145                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ALLOC_FAIL, NULL);
  146                 break;
  147 
  148         case OCS_HW_DOMAIN_ATTACH_OK:
  149                 domain_trace(domain, "OCS_HW_DOMAIN_ATTACH_OK:\n");
  150                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
  151                 break;
  152 
  153         case OCS_HW_DOMAIN_ATTACH_FAIL:
  154                 domain_trace(domain, "OCS_HW_DOMAIN_ATTACH_FAIL:\n");
  155                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ATTACH_FAIL, NULL);
  156                 break;
  157 
  158         case OCS_HW_DOMAIN_FREE_OK:
  159                 domain_trace(domain, "OCS_HW_DOMAIN_FREE_OK:\n");
  160                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FREE_OK, NULL);
  161                 break;
  162 
  163         case OCS_HW_DOMAIN_FREE_FAIL:
  164                 domain_trace(domain, "OCS_HW_DOMAIN_FREE_FAIL:\n");
  165                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FREE_FAIL, NULL);
  166                 break;
  167 
  168         default:
  169                 ocs_log_warn(ocs, "unsupported event %#x\n", event);
  170         }
  171 
  172         return rc;
  173 }
  174 
  175 /**
  176  * @brief Find the domain, given its FCF_WWN.
  177  *
  178  * <h3 class="desc">Description</h3>
  179  * Search the domain_list to find a matching domain object.
  180  *
  181  * @param ocs Pointer to the OCS device.
  182  * @param fcf_wwn FCF WWN to find.
  183  *
  184  * @return Returns the pointer to the domain if found; or NULL otherwise.
  185  */
  186 
  187 ocs_domain_t *
  188 ocs_domain_find(ocs_t *ocs, uint64_t fcf_wwn)
  189 {
  190         ocs_domain_t *domain = NULL;
  191 
  192         /* Check to see if this domain is already allocated */
  193         ocs_device_lock(ocs);
  194                 ocs_list_foreach(&ocs->domain_list, domain) {
  195                         if (fcf_wwn == domain->fcf_wwn) {
  196                                 break;
  197                         }
  198                 }
  199         ocs_device_unlock(ocs);
  200         return domain;
  201 }
  202 
  203 /**
  204  * @brief Allocate a domain object.
  205  *
  206  * <h3 class="desc">Description</h3>
  207  * A domain object is allocated and initialized. It is associated with the
  208  * \c ocs argument.
  209  *
  210  * @param ocs Pointer to the OCS device.
  211  * @param fcf_wwn FCF WWN of the domain.
  212  *
  213  * @return Returns a pointer to the ocs_domain_t object; or NULL.
  214  */
  215 
  216 ocs_domain_t *
  217 ocs_domain_alloc(ocs_t *ocs, uint64_t fcf_wwn)
  218 {
  219         ocs_domain_t *domain;
  220 
  221         ocs_assert(ocs, NULL);
  222 
  223         domain = ocs_malloc(ocs, sizeof(*domain), OCS_M_NOWAIT | OCS_M_ZERO);
  224         if (domain) {
  225                 domain->ocs = ocs;
  226                 domain->instance_index = ocs->domain_instance_count++;
  227                 domain->drvsm.app = domain;
  228                 ocs_domain_lock_init(domain);
  229                 ocs_lock_init(ocs, &domain->lookup_lock, "Domain lookup[%d]", domain->instance_index);
  230 
  231                 /* Allocate a sparse vector for sport FC_ID's */
  232                 domain->lookup = spv_new(ocs);
  233                 if (domain->lookup == NULL) {
  234                         ocs_log_err(ocs, "spv_new() failed\n");
  235                         ocs_free(ocs, domain, sizeof(*domain));
  236                         return NULL;
  237                 }
  238 
  239                 ocs_list_init(&domain->sport_list, ocs_sport_t, link);
  240                 domain->fcf_wwn = fcf_wwn;
  241                 ocs_log_debug(ocs, "Domain allocated: wwn %016" PRIX64 "\n", domain->fcf_wwn);
  242                 domain->femul_enable = (ocs->ctrlmask & OCS_CTRLMASK_ENABLE_FABRIC_EMULATION) != 0;
  243 
  244                 ocs_device_lock(ocs);
  245                         /* if this is the first domain, then assign it as the "root" domain */
  246                         if (ocs_list_empty(&ocs->domain_list)) {
  247                                 ocs->domain = domain;
  248                         }
  249                         ocs_list_add_tail(&ocs->domain_list, domain);
  250                 ocs_device_unlock(ocs);
  251 
  252                 domain->mgmt_functions = &domain_mgmt_functions;
  253         } else {
  254                 ocs_log_err(ocs, "domain allocation failed\n");
  255         }
  256 
  257         return domain;
  258 }
  259 
  260 /**
  261  * @brief Free a domain object.
  262  *
  263  * <h3 class="desc">Description</h3>
  264  * The domain object is freed.
  265  *
  266  * @param domain Domain object to free.
  267  *
  268  * @return None.
  269  */
  270 
  271 void
  272 ocs_domain_free(ocs_domain_t *domain)
  273 {
  274         ocs_t *ocs;
  275 
  276         ocs_assert(domain);
  277         ocs_assert(domain->ocs);
  278 
  279         /* Hold frames to clear the domain pointer from the xport lookup */
  280         ocs_domain_hold_frames(domain);
  281 
  282         ocs = domain->ocs;
  283 
  284         ocs_log_debug(ocs, "Domain free: wwn %016" PRIX64 "\n", domain->fcf_wwn);
  285 
  286         spv_del(domain->lookup);
  287         domain->lookup = NULL;
  288 
  289         ocs_device_lock(ocs);
  290                 ocs_list_remove(&ocs->domain_list, domain);
  291                 if (domain == ocs->domain) {
  292                         /* set global domain to the new head */
  293                         ocs->domain = ocs_list_get_head(&ocs->domain_list);
  294                         if (ocs->domain) {
  295                                 ocs_log_debug(ocs, "setting new domain, old=%p new=%p\n",
  296                                                 domain, ocs->domain);
  297                         }
  298                 }
  299 
  300                 if (ocs_list_empty(&ocs->domain_list) && ocs->domain_list_empty_cb ) {
  301                         (*ocs->domain_list_empty_cb)(ocs, ocs->domain_list_empty_cb_arg);
  302                 }
  303         ocs_device_unlock(ocs);
  304 
  305         ocs_lock_free(&domain->lookup_lock);
  306 
  307         ocs_free(ocs, domain, sizeof(*domain));
  308 }
  309 
  310 /**
  311  * @brief Free memory resources of a domain object.
  312  *
  313  * <h3 class="desc">Description</h3>
  314  * After the domain object is freed, its child objects are also freed.
  315  *
  316  * @param domain Pointer to a domain object.
  317  *
  318  * @return None.
  319  */
  320 
  321 void
  322 ocs_domain_force_free(ocs_domain_t *domain)
  323 {
  324         ocs_sport_t *sport;
  325         ocs_sport_t *next;
  326 
  327         /* Shutdown domain sm */
  328         ocs_sm_disable(&domain->drvsm);
  329 
  330         ocs_scsi_notify_domain_force_free(domain);
  331 
  332         ocs_domain_lock(domain);
  333                 ocs_list_foreach_safe(&domain->sport_list, sport, next) {
  334                         ocs_sport_force_free(sport);
  335                 }
  336         ocs_domain_unlock(domain);
  337         ocs_hw_domain_force_free(&domain->ocs->hw, domain);
  338         ocs_domain_free(domain);
  339 }
  340 
  341 /**
  342  * @brief Register a callback when the domain_list goes empty.
  343  *
  344  * <h3 class="desc">Description</h3>
  345  * A function callback may be registered when the domain_list goes empty.
  346  *
  347  * @param ocs Pointer to a device object.
  348  * @param callback Callback function.
  349  * @param arg Callback argument.
  350  *
  351  * @return None.
  352  */
  353 
  354 void
  355 ocs_register_domain_list_empty_cb(ocs_t *ocs, void (*callback)(ocs_t *ocs, void *arg), void *arg)
  356 {
  357         ocs_device_lock(ocs);
  358                 ocs->domain_list_empty_cb = callback;
  359                 ocs->domain_list_empty_cb_arg = arg;
  360                 if (ocs_list_empty(&ocs->domain_list) && callback) {
  361                         (*callback)(ocs, arg);
  362                 }
  363         ocs_device_unlock(ocs);
  364 }
  365 
  366 /**
  367  * @brief Return a pointer to the domain, given the instance index.
  368  *
  369  * <h3 class="desc">Description</h3>
  370  * A pointer to the domain context, given by the index, is returned.
  371  *
  372  * @param ocs Pointer to the driver instance context.
  373  * @param index Instance index.
  374  *
  375  * @return Returns a pointer to the domain; or NULL.
  376  */
  377 
  378 ocs_domain_t *
  379 ocs_domain_get_instance(ocs_t *ocs, uint32_t index)
  380 {
  381         ocs_domain_t *domain = NULL;
  382 
  383         if (index >= OCS_MAX_DOMAINS) {
  384                 ocs_log_err(ocs, "invalid index: %d\n", index);
  385                 return NULL;
  386         }
  387         ocs_device_lock(ocs);
  388                 ocs_list_foreach(&ocs->domain_list, domain) {
  389                         if (domain->instance_index == index) {
  390                                 break;
  391                         }
  392                 }
  393         ocs_device_unlock(ocs);
  394         return domain;
  395 }
  396 
  397 /**
  398  * @ingroup domain_sm
  399  * @brief Domain state machine: Common event handler.
  400  *
  401  * <h3 class="desc">Description</h3>
  402  * Common/shared events are handled here for the domain state machine.
  403  *
  404  * @param funcname Function name text.
  405  * @param ctx Domain state machine context.
  406  * @param evt Event to process.
  407  * @param arg Per event optional argument.
  408  *
  409  * @return Returns NULL.
  410  */
  411 
  412 static void *
  413 __ocs_domain_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
  414 {
  415         ocs_domain_t *domain = ctx->app;
  416 
  417         switch(evt) {
  418         case OCS_EVT_ENTER:
  419         case OCS_EVT_REENTER:
  420         case OCS_EVT_EXIT:
  421         case OCS_EVT_ALL_CHILD_NODES_FREE:
  422                 /* this can arise if an FLOGI fails on the SPORT, and the SPORT is shutdown */
  423                 break;
  424         default:
  425                 ocs_log_warn(domain->ocs, "%-20s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
  426                 break;
  427         }
  428 
  429         return NULL;
  430 }
  431 
  432 /**
  433  * @ingroup domain_sm
  434  * @brief Domain state machine: Common shutdown.
  435  *
  436  * <h3 class="desc">Description</h3>
  437  * Handles common shutdown events.
  438  *
  439  * @param funcname Function name text.
  440  * @param ctx Remote node state machine context.
  441  * @param evt Event to process.
  442  * @param arg Per event optional argument.
  443  *
  444  * @return Returns NULL.
  445  */
  446 
  447 static void *
  448 __ocs_domain_common_shutdown(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
  449 {
  450         ocs_domain_t *domain = ctx->app;
  451 
  452         switch(evt) {
  453         case OCS_EVT_ENTER:
  454         case OCS_EVT_REENTER:
  455         case OCS_EVT_EXIT:
  456                 break;
  457         case OCS_EVT_DOMAIN_FOUND:
  458                 ocs_assert(arg, NULL);
  459                 /* sm: / save drec, mark domain_found_pending */
  460                 ocs_memcpy(&domain->pending_drec, arg, sizeof(domain->pending_drec));
  461                 domain->domain_found_pending = TRUE;
  462                 break;
  463         case OCS_EVT_DOMAIN_LOST: 
  464                 /* clear drec available
  465                  * sm: unmark domain_found_pending */
  466                 domain->domain_found_pending = FALSE;
  467                 break;
  468 
  469         default:
  470                 ocs_log_warn(domain->ocs, "%-20s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
  471                 break;
  472         }
  473 
  474         return NULL;
  475 }
  476 
  477 #define std_domain_state_decl(...) \
  478         ocs_domain_t *domain = NULL; \
  479         ocs_t *ocs = NULL; \
  480         \
  481         ocs_assert(ctx, NULL); \
  482         ocs_assert(ctx->app, NULL); \
  483         domain = ctx->app; \
  484         ocs_assert(domain->ocs, NULL); \
  485         ocs = domain->ocs; \
  486         ocs_assert(ocs->xport, NULL);
  487 
  488 /**
  489  * @ingroup domain_sm
  490  * @brief Domain state machine: Initial state.
  491  *
  492  * <h3 class="desc">Description</h3>
  493  * The initial state for a domain. Each domain is initialized to
  494  * this state at start of day (SOD).
  495  *
  496  * @param ctx Domain state machine context.
  497  * @param evt Event to process.
  498  * @param arg Per event optional argument.
  499  *
  500  * @return Returns NULL.
  501  */
  502 
  503 void *
  504 __ocs_domain_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
  505 {
  506         std_domain_state_decl();
  507 
  508         domain_sm_trace(domain);
  509 
  510         switch(evt) {
  511         case OCS_EVT_ENTER:
  512                 domain->attached = 0;
  513                 break;
  514 
  515         case OCS_EVT_DOMAIN_FOUND: {
  516                 int32_t         vlan = 0;
  517                 uint32_t        i;
  518                 ocs_domain_record_t *drec = arg;
  519                 ocs_sport_t *sport;
  520 
  521                 uint64_t        my_wwnn = ocs->xport->req_wwnn;
  522                 uint64_t        my_wwpn = ocs->xport->req_wwpn;
  523                 uint64_t        be_wwpn;
  524 
  525                 /* For now, user must specify both port name and node name, or we let firmware
  526                  * pick both (same as for vports).
  527                  * TODO: do we want to allow setting only port name or only node name?
  528                  */
  529                 if ((my_wwpn == 0) || (my_wwnn == 0)) {
  530                         ocs_log_debug(ocs, "using default hardware WWN configuration \n");
  531                         my_wwpn = ocs_get_wwn(&ocs->hw, OCS_HW_WWN_PORT);
  532                         my_wwnn = ocs_get_wwn(&ocs->hw, OCS_HW_WWN_NODE);
  533                 }
  534 
  535                 ocs_log_debug(ocs, "Creating base sport using WWPN %016" PRIx64 " WWNN %016" PRIx64 "\n",
  536                         my_wwpn, my_wwnn);
  537 
  538                 /* Allocate a sport and transition to __ocs_sport_allocated */
  539                 sport = ocs_sport_alloc(domain, my_wwpn, my_wwnn, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt);
  540 
  541                 if (sport == NULL) {
  542                         ocs_log_err(ocs, "ocs_sport_alloc() failed\n");
  543                         break;
  544                 }
  545                 ocs_sm_transition(&sport->sm, __ocs_sport_allocated, NULL);
  546 
  547                 /* If domain is ethernet, then fetch the vlan id value */
  548                 if (drec->is_ethernet) {
  549                         vlan = ocs_bitmap_search((void *)drec->map.vlan, TRUE, 512 * 8);
  550                         if (vlan < 0) {
  551                                 ocs_log_err(ocs, "no VLAN id available (FCF=%d)\n",
  552                                                 drec->index);
  553                                 break;
  554                         }
  555                 }
  556 
  557                 be_wwpn = ocs_htobe64(sport->wwpn);
  558 
  559                 /* allocate ocs_sli_port_t object for local port
  560                  * Note: drec->fc_id is ALPA from read_topology only if loop
  561                  */
  562                 if (ocs_hw_port_alloc(&ocs->hw, sport, NULL, (uint8_t *)&be_wwpn)) {
  563                         ocs_log_err(ocs, "Can't allocate port\n");
  564                         ocs_sport_free(sport);
  565                         break;
  566                 }
  567 
  568                 /* initialize domain object */
  569                 domain->is_loop = drec->is_loop;
  570                 domain->is_fc = drec->is_fc;
  571 
  572                 /*
  573                  * If the loop position map includes ALPA == 0, then we are in a public loop (NL_PORT)
  574                  * Note that the first element of the loopmap[] contains the count of elements, and if
  575                  * ALPA == 0 is present, it will occupy the first location after the count.
  576                  */
  577                 domain->is_nlport = drec->map.loop[1] == 0x00;
  578 
  579                 if (domain->is_loop) {
  580                         ocs_log_debug(ocs, "%s fc_id=%#x speed=%d\n",
  581                                         drec->is_loop ? (domain->is_nlport ? "public-loop" : "loop") : "other",
  582                                         drec->fc_id, drec->speed);
  583 
  584                         sport->fc_id = drec->fc_id;
  585                         sport->topology = OCS_SPORT_TOPOLOGY_LOOP;
  586                         ocs_snprintf(sport->display_name, sizeof(sport->display_name), "s%06x", drec->fc_id);
  587 
  588                         if (ocs->enable_ini) {
  589                                 uint32_t count = drec->map.loop[0];
  590                                 ocs_log_debug(ocs, "%d position map entries\n", count);
  591                                 for (i = 1; i <= count; i++) {
  592                                         if (drec->map.loop[i] != drec->fc_id) {
  593                                                 ocs_node_t *node;
  594 
  595                                                 ocs_log_debug(ocs, "%#x -> %#x\n",
  596                                                                 drec->fc_id, drec->map.loop[i]);
  597                                                 node = ocs_node_alloc(sport, drec->map.loop[i], FALSE, TRUE);
  598                                                 if (node == NULL) {
  599                                                         ocs_log_err(ocs, "ocs_node_alloc() failed\n");
  600                                                         break;
  601                                                 }
  602                                                 ocs_node_transition(node, __ocs_d_wait_loop, NULL);
  603                                         }
  604                                 }
  605                         }
  606                 }
  607 
  608                 /* Initiate HW domain alloc */
  609                 if (ocs_hw_domain_alloc(&ocs->hw, domain, drec->index, vlan)) {
  610                         ocs_log_err(ocs, "Failed to initiate HW domain allocation\n");
  611                         break;
  612                 }
  613                 ocs_sm_transition(ctx, __ocs_domain_wait_alloc, arg);
  614                 break;
  615         }
  616         default:
  617                 __ocs_domain_common(__func__, ctx, evt, arg);
  618                 return NULL;
  619         }
  620 
  621         return NULL;
  622 }
  623 
  624 /**
  625  * @ingroup domain_sm
  626  * @brief Domain state machine: Wait for the domain allocation to complete.
  627  *
  628  * <h3 class="desc">Description</h3>
  629  * Waits for the domain state to be allocated. After the HW domain
  630  * allocation process has been initiated, this state waits for
  631  * that process to complete (i.e. a domain-alloc-ok event).
  632  *
  633  * @param ctx Domain state machine context.
  634  * @param evt Event to process.
  635  * @param arg Per event optional argument.
  636  *
  637  * @return Returns NULL.
  638  */
  639 
  640 void *
  641 __ocs_domain_wait_alloc(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
  642 {
  643         ocs_sport_t *sport;
  644         std_domain_state_decl();
  645 
  646         domain_sm_trace(domain);
  647 
  648         switch(evt) {
  649         case OCS_EVT_DOMAIN_ALLOC_OK: {
  650                 char prop_buf[32];
  651                 uint64_t wwn_bump = 0;
  652                 fc_plogi_payload_t *sp;
  653 
  654                 if (ocs_get_property("wwn_bump", prop_buf, sizeof(prop_buf)) == 0) {
  655                         wwn_bump = ocs_strtoull(prop_buf, 0, 0);
  656                 }
  657 
  658                 sport = domain->sport;
  659                 ocs_assert(sport, NULL);
  660                 sp = (fc_plogi_payload_t*) sport->service_params;
  661 
  662                 /* Save the domain service parameters */
  663                 ocs_memcpy(domain->service_params + 4, domain->dma.virt, sizeof(fc_plogi_payload_t) - 4);
  664                 ocs_memcpy(sport->service_params + 4, domain->dma.virt, sizeof(fc_plogi_payload_t) - 4);
  665 
  666                 /* If we're in fabric emulation mode, the flogi service parameters have not been setup yet,
  667                  * so we need some reasonable BB credit value
  668                  */
  669                 if (domain->femul_enable) {
  670                         ocs_memcpy(domain->flogi_service_params + 4, domain->service_params + 4, sizeof(fc_plogi_payload_t) - 4);
  671                 }
  672 
  673                 /* Update the sport's service parameters, user might have specified non-default names */
  674                 sp->port_name_hi = ocs_htobe32((uint32_t) (sport->wwpn >> 32ll));
  675                 sp->port_name_lo = ocs_htobe32((uint32_t) sport->wwpn);
  676                 sp->node_name_hi = ocs_htobe32((uint32_t) (sport->wwnn >> 32ll));
  677                 sp->node_name_lo = ocs_htobe32((uint32_t) sport->wwnn);
  678 
  679                 if (wwn_bump) {
  680                         sp->port_name_lo = ocs_htobe32(ocs_be32toh(sp->port_name_lo) ^ ((uint32_t)(wwn_bump)));
  681                         sp->port_name_hi = ocs_htobe32(ocs_be32toh(sp->port_name_hi) ^ ((uint32_t)(wwn_bump >> 32)));
  682                         sp->node_name_lo = ocs_htobe32(ocs_be32toh(sp->node_name_lo) ^ ((uint32_t)(wwn_bump)));
  683                         sp->node_name_hi = ocs_htobe32(ocs_be32toh(sp->node_name_hi) ^ ((uint32_t)(wwn_bump >> 32)));
  684                         ocs_log_info(ocs, "Overriding WWN\n");
  685                 }
  686 
  687                 /* Take the loop topology path, unless we are an NL_PORT (public loop) */
  688                 if (domain->is_loop && !domain->is_nlport) {
  689                         /*
  690                          * For loop, we already have our FC ID and don't need fabric login.
  691                          * Transition to the allocated state and post an event to attach to
  692                          * the domain. Note that this breaks the normal action/transition
  693                          * pattern here to avoid a race with the domain attach callback.
  694                          */
  695                         /* sm: is_loop / domain_attach */
  696                         ocs_sm_transition(ctx, __ocs_domain_allocated, NULL);
  697                         __ocs_domain_attach_internal(domain, sport->fc_id);
  698                         break;
  699                 } else {
  700                         ocs_node_t *node;
  701 
  702                         /* alloc fabric node, send FLOGI */
  703                         node = ocs_node_find(sport, FC_ADDR_FABRIC);
  704                         if (node) {
  705                                 ocs_log_err(ocs, "Hmmmm ... Fabric Controller node already exists\n");
  706                                 break;
  707                         }
  708                         node = ocs_node_alloc(sport, FC_ADDR_FABRIC, FALSE, FALSE);
  709                         if (!node) {
  710                                 ocs_log_err(ocs, "Error: ocs_node_alloc() failed\n");
  711                         } else {
  712                                 if (ocs->nodedb_mask & OCS_NODEDB_PAUSE_FABRIC_LOGIN) {
  713                                         ocs_node_pause(node, __ocs_fabric_init);
  714                                 } else {
  715                                         ocs_node_transition(node, __ocs_fabric_init, NULL);
  716                                 }
  717                         }
  718                         /* Accept frames */
  719                         domain->req_accept_frames = 1;
  720                 }
  721                 /* sm: start fabric logins */
  722                 ocs_sm_transition(ctx, __ocs_domain_allocated, NULL);
  723                 break;
  724         }
  725 
  726         case OCS_EVT_DOMAIN_ALLOC_FAIL:
  727                 /* TODO: hw/device reset */
  728                 ocs_log_err(ocs, "%s recv'd waiting for DOMAIN_ALLOC_OK; shutting down domain\n",
  729                         ocs_sm_event_name(evt));
  730                 domain->req_domain_free = 1;
  731                 break;
  732 
  733         case OCS_EVT_DOMAIN_FOUND:
  734                 /* Should not happen */
  735                 ocs_assert(evt, NULL);
  736                 break;
  737 
  738         case OCS_EVT_DOMAIN_LOST:
  739                 ocs_log_debug(ocs, "%s received while waiting for ocs_hw_domain_alloc() to complete\n", ocs_sm_event_name(evt));
  740                 ocs_sm_transition(ctx, __ocs_domain_wait_domain_lost, NULL);
  741                 break;
  742 
  743         default:
  744                 __ocs_domain_common(__func__, ctx, evt, arg);
  745                 return NULL;
  746         }
  747 
  748         return NULL;
  749 }
  750 
  751 /**
  752  * @ingroup domain_sm
  753  * @brief Domain state machine: Wait for the domain attach request.
  754  *
  755  * <h3 class="desc">Description</h3>
  756  * In this state, the domain has been allocated and is waiting for a domain attach request.
  757  * The attach request comes from a node instance completing the fabric login,
  758  * or from a point-to-point negotiation and login.
  759  *
  760  * @param ctx Remote node state machine context.
  761  * @param evt Event to process.
  762  * @param arg Per event optional argument.
  763  *
  764  * @return Returns NULL.
  765  */
  766 
  767 void *
  768 __ocs_domain_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
  769 {
  770         int32_t rc = 0;
  771         std_domain_state_decl();
  772 
  773         domain_sm_trace(domain);
  774 
  775         switch(evt) {
  776         case OCS_EVT_DOMAIN_REQ_ATTACH: {
  777                 uint32_t fc_id;
  778 
  779                 ocs_assert(arg, NULL);
  780 
  781                 fc_id = *((uint32_t*)arg);
  782                 ocs_log_debug(ocs, "Requesting hw domain attach fc_id x%x\n", fc_id);
  783                 /* Update sport lookup */
  784                 ocs_lock(&domain->lookup_lock);
  785                         spv_set(domain->lookup, fc_id, domain->sport);
  786                 ocs_unlock(&domain->lookup_lock);
  787 
  788                 /* Update display name for the sport */
  789                 ocs_node_fcid_display(fc_id, domain->sport->display_name, sizeof(domain->sport->display_name));
  790 
  791                 /* Issue domain attach call */
  792                 rc = ocs_hw_domain_attach(&ocs->hw, domain, fc_id);
  793                 if (rc) {
  794                         ocs_log_err(ocs, "ocs_hw_domain_attach failed: %d\n", rc);
  795                         return NULL;
  796                 }
  797                 /* sm: / domain_attach */
  798                 ocs_sm_transition(ctx, __ocs_domain_wait_attach, NULL);
  799                 break;
  800         }
  801 
  802         case OCS_EVT_DOMAIN_FOUND:
  803                 /* Should not happen */
  804                 ocs_assert(evt, NULL);
  805                 break;
  806 
  807         case OCS_EVT_DOMAIN_LOST: {
  808                 int32_t rc;
  809                 ocs_log_debug(ocs, "%s received while waiting for OCS_EVT_DOMAIN_REQ_ATTACH\n",
  810                         ocs_sm_event_name(evt));
  811                 ocs_domain_lock(domain);
  812                 if (!ocs_list_empty(&domain->sport_list)) {
  813                         /* if there are sports, transition to wait state and
  814                          * send shutdown to each sport */
  815                         ocs_sport_t     *sport = NULL;
  816                         ocs_sport_t     *sport_next = NULL;
  817                         ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
  818                         ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
  819                                 ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
  820                         }
  821                         ocs_domain_unlock(domain);
  822                 } else {
  823                         ocs_domain_unlock(domain);
  824                         /* no sports exist, free domain */
  825                         ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
  826                         rc = ocs_hw_domain_free(&ocs->hw, domain);
  827                         if (rc) {
  828                                 ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
  829                                 /* TODO: hw/device reset needed */
  830                         }
  831                 }
  832 
  833                 break;
  834         }
  835 
  836         default:
  837                 __ocs_domain_common(__func__, ctx, evt, arg);
  838                 return NULL;
  839         }
  840 
  841         return NULL;
  842 }
  843 
  844 /**
  845  * @ingroup domain_sm
  846  * @brief Domain state machine: Wait for the HW domain attach to complete.
  847  *
  848  * <h3 class="desc">Description</h3>
  849  * Waits for the HW domain attach to complete. Forwards attach ok event to the
  850  * fabric node state machine.
  851  *
  852  * @param ctx Remote node state machine context.
  853  * @param evt Event to process.
  854  * @param arg Per event optional argument.
  855  *
  856  * @return Returns NULL.
  857  */
  858 
  859 void *
  860 __ocs_domain_wait_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
  861 {
  862         std_domain_state_decl();
  863 
  864         domain_sm_trace(domain);
  865 
  866         switch(evt) {
  867         case OCS_EVT_DOMAIN_ATTACH_OK: {
  868                 ocs_node_t *node = NULL;
  869                 ocs_node_t *next_node = NULL;
  870                 ocs_sport_t *sport;
  871                 ocs_sport_t *next_sport;
  872 
  873                 /* Mark as attached */
  874                 domain->attached = 1;
  875 
  876                 /* Register with SCSI API */
  877                 if (ocs->enable_tgt)
  878                         ocs_scsi_tgt_new_domain(domain);
  879                 if (ocs->enable_ini)
  880                         ocs_scsi_ini_new_domain(domain);
  881 
  882                 /* Transition to ready */
  883                 /* sm: / forward event to all sports and nodes */
  884                 ocs_sm_transition(ctx, __ocs_domain_ready, NULL);
  885 
  886                 /* We have an FCFI, so we can accept frames */
  887                 domain->req_accept_frames = 1;
  888                 /* Set domain notify pending state to avoid duplicate domain event post */
  889                 domain->domain_notify_pend = 1;
  890 
  891                 /* Notify all nodes that the domain attach request has completed
  892                  * Note: sport will have already received notification of sport attached
  893                  * as a result of the HW's port attach.
  894                  */
  895                 ocs_domain_lock(domain);
  896                         ocs_list_foreach_safe(&domain->sport_list, sport, next_sport) {
  897                                 ocs_sport_lock(sport);
  898                                         ocs_list_foreach_safe(&sport->node_list, node, next_node) {
  899                                                 ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
  900                                         }
  901                                 ocs_sport_unlock(sport);
  902                         }
  903                 ocs_domain_unlock(domain);
  904                 domain->domain_notify_pend = 0;
  905                 break;
  906         }
  907 
  908         case OCS_EVT_DOMAIN_ATTACH_FAIL:
  909                 ocs_log_debug(ocs, "%s received while waiting for hw attach to complete\n", ocs_sm_event_name(evt));
  910                 /* TODO: hw/device reset */
  911                 break;
  912 
  913         case OCS_EVT_DOMAIN_FOUND:
  914                 /* Should not happen */
  915                 ocs_assert(evt, NULL);
  916                 break;
  917 
  918         case OCS_EVT_DOMAIN_LOST:
  919                 /* Domain lost while waiting for an attach to complete, go to a state that waits for
  920                  * the domain attach to complete, then handle domain lost
  921                  */
  922                 ocs_sm_transition(ctx, __ocs_domain_wait_domain_lost, NULL);
  923                 break;
  924 
  925         case OCS_EVT_DOMAIN_REQ_ATTACH:
  926                 /* In P2P we can get an attach request from the other FLOGI path, so drop this one */
  927                 break;
  928 
  929         default:
  930                 __ocs_domain_common(__func__, ctx, evt, arg);
  931                 return NULL;
  932         }
  933 
  934         return NULL;
  935 }
  936 
  937 /**
  938  * @ingroup domain_sm
  939  * @brief Domain state machine: Ready state.
  940  *
  941  * <h3 class="desc">Description</h3>
  942  * This is a domain ready state. It waits for a domain-lost event, and initiates shutdown.
  943  *
  944  * @param ctx Remote node state machine context.
  945  * @param evt Event to process.
  946  * @param arg Per event optional argument.
  947  *
  948  * @return Returns NULL.
  949  */
  950 
  951 void *
  952 __ocs_domain_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
  953 {
  954         std_domain_state_decl();
  955 
  956         domain_sm_trace(domain);
  957 
  958         switch(evt) {
  959         case OCS_EVT_ENTER: {
  960                 /* start any pending vports */
  961                 if (ocs_vport_start(domain)) {
  962                         ocs_log_debug(domain->ocs, "ocs_vport_start() did not start all vports\n");
  963                 }
  964                 break;
  965         }
  966         case OCS_EVT_DOMAIN_LOST: {
  967                 int32_t rc;
  968                 ocs_domain_lock(domain);
  969                 if (!ocs_list_empty(&domain->sport_list)) {
  970                         /* if there are sports, transition to wait state and send
  971                         * shutdown to each sport */
  972                         ocs_sport_t     *sport = NULL;
  973                         ocs_sport_t     *sport_next = NULL;
  974                         ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
  975                         ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
  976                                 ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
  977                         }
  978                         ocs_domain_unlock(domain);
  979                 } else {
  980                         ocs_domain_unlock(domain);
  981                         /* no sports exist, free domain */
  982                         ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
  983                         rc = ocs_hw_domain_free(&ocs->hw, domain);
  984                         if (rc) {
  985                                 ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
  986                                 /* TODO: hw/device reset needed */
  987                         }
  988                 }
  989                 break;
  990         }
  991 
  992         case OCS_EVT_DOMAIN_FOUND:
  993                 /* Should not happen */
  994                 ocs_assert(evt, NULL);
  995                 break;
  996 
  997         case OCS_EVT_DOMAIN_REQ_ATTACH: {
  998                 /* can happen during p2p */
  999                 uint32_t fc_id;
 1000 
 1001                 ocs_assert(arg, NULL);
 1002                 fc_id = *((uint32_t*)arg);
 1003 
 1004                 /* Assume that the domain is attached */
 1005                 ocs_assert(domain->attached, NULL);
 1006 
 1007                 /* Verify that the requested FC_ID is the same as the one we're working with */
 1008                 ocs_assert(domain->sport->fc_id == fc_id, NULL);
 1009                 break;
 1010         }
 1011 
 1012         default:
 1013                 __ocs_domain_common(__func__, ctx, evt, arg);
 1014                 return NULL;
 1015         }
 1016 
 1017         return NULL;
 1018 }
 1019 
 1020 /**
 1021  * @ingroup domain_sm
 1022  * @brief Domain state machine: Wait for nodes to free prior to the domain shutdown.
 1023  *
 1024  * <h3 class="desc">Description</h3>
 1025  * All nodes are freed, and ready for a domain shutdown.
 1026  *
 1027  * @param ctx Remote node sm context.
 1028  * @param evt Event to process.
 1029  * @param arg Per event optional argument.
 1030  *
 1031  * @return Returns NULL.
 1032  */
 1033 
 1034 void *
 1035 __ocs_domain_wait_sports_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
 1036 {
 1037         std_domain_state_decl();
 1038 
 1039         domain_sm_trace(domain);
 1040 
 1041         switch(evt) {
 1042         case OCS_EVT_ALL_CHILD_NODES_FREE: {
 1043                 int32_t rc;
 1044 
 1045                 /* sm: ocs_hw_domain_free */
 1046                 ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
 1047 
 1048                 /* Request ocs_hw_domain_free and wait for completion */
 1049                 rc = ocs_hw_domain_free(&ocs->hw, domain);
 1050                 if (rc) {
 1051                         ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
 1052                 }
 1053                 break;
 1054         }
 1055         default:
 1056                 __ocs_domain_common_shutdown(__func__, ctx, evt, arg);
 1057                 return NULL;
 1058         }
 1059 
 1060         return NULL;
 1061 }
 1062 
 1063 /**
 1064  * @ingroup domain_sm
 1065  * @brief Domain state machine: Complete the domain shutdown.
 1066  *
 1067  * <h3 class="desc">Description</h3>
 1068  * Waits for a HW domain free to complete.
 1069  *
 1070  * @param ctx Remote node state machine context.
 1071  * @param evt Event to process.
 1072  * @param arg Per event optional argument.
 1073  *
 1074  * @return Returns NULL.
 1075  */
 1076 
 1077 void *
 1078 __ocs_domain_wait_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
 1079 {
 1080         std_domain_state_decl();
 1081 
 1082         domain_sm_trace(domain);
 1083 
 1084         switch(evt) {
 1085         case OCS_EVT_DOMAIN_FREE_OK: {
 1086                 if (ocs->enable_ini)
 1087                         ocs_scsi_ini_del_domain(domain);
 1088                 if (ocs->enable_tgt)
 1089                         ocs_scsi_tgt_del_domain(domain);
 1090 
 1091                 /* sm: domain_free */
 1092                 if (domain->domain_found_pending) {
 1093                         /* save fcf_wwn and drec from this domain, free current domain and allocate
 1094                          * a new one with the same fcf_wwn
 1095                          * TODO: could use a SLI-4 "re-register VPI" operation here
 1096                          */
 1097                         uint64_t fcf_wwn = domain->fcf_wwn;
 1098                         ocs_domain_record_t drec = domain->pending_drec;
 1099 
 1100                         ocs_log_debug(ocs, "Reallocating domain\n");
 1101                         domain->req_domain_free = 1;
 1102                         domain = ocs_domain_alloc(ocs, fcf_wwn);
 1103 
 1104                         if (domain == NULL) {
 1105                                 ocs_log_err(ocs, "ocs_domain_alloc() failed\n");
 1106                                 /* TODO: hw/device reset needed */
 1107                                 return NULL;
 1108                         }
 1109                         /*
 1110                          * got a new domain; at this point, there are at least two domains
 1111                          * once the req_domain_free flag is processed, the associated domain
 1112                          * will be removed.
 1113                          */
 1114                         ocs_sm_transition(&domain->drvsm, __ocs_domain_init, NULL);
 1115                         ocs_sm_post_event(&domain->drvsm, OCS_EVT_DOMAIN_FOUND, &drec);
 1116                 } else {
 1117                         domain->req_domain_free = 1;
 1118                 }
 1119                 break;
 1120         }
 1121 
 1122         default:
 1123                 __ocs_domain_common_shutdown(__func__, ctx, evt, arg);
 1124                 return NULL;
 1125         }
 1126 
 1127         return NULL;
 1128 }
 1129 
 1130 /**
 1131  * @ingroup domain_sm
 1132  * @brief Domain state machine: Wait for the domain alloc/attach completion
 1133  * after receiving a domain lost.
 1134  *
 1135  * <h3 class="desc">Description</h3>
 1136  * This state is entered when receiving a domain lost while waiting for a domain alloc
 1137  * or a domain attach to complete.
 1138  *
 1139  * @param ctx Remote node state machine context.
 1140  * @param evt Event to process.
 1141  * @param arg Per event optional argument.
 1142  *
 1143  * @return Returns NULL.
 1144  */
 1145 
 1146 void *
 1147 __ocs_domain_wait_domain_lost(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
 1148 {
 1149         std_domain_state_decl();
 1150 
 1151         domain_sm_trace(domain);
 1152 
 1153         switch(evt) {
 1154         case OCS_EVT_DOMAIN_ALLOC_OK:
 1155         case OCS_EVT_DOMAIN_ATTACH_OK: {
 1156                 int32_t rc;
 1157                 ocs_domain_lock(domain);
 1158                 if (!ocs_list_empty(&domain->sport_list)) {
 1159                         /* if there are sports, transition to wait state and send
 1160                         * shutdown to each sport */
 1161                         ocs_sport_t     *sport = NULL;
 1162                         ocs_sport_t     *sport_next = NULL;
 1163                         ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
 1164                         ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
 1165                                 ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
 1166                         }
 1167                         ocs_domain_unlock(domain);
 1168                 } else {
 1169                         ocs_domain_unlock(domain);
 1170                         /* no sports exist, free domain */
 1171                         ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
 1172                         rc = ocs_hw_domain_free(&ocs->hw, domain);
 1173                         if (rc) {
 1174                                 ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
 1175                                 /* TODO: hw/device reset needed */
 1176                         }
 1177                 }
 1178                 break;
 1179         }
 1180         case OCS_EVT_DOMAIN_ALLOC_FAIL:
 1181         case OCS_EVT_DOMAIN_ATTACH_FAIL:
 1182                 ocs_log_err(ocs, "[domain] %-20s: failed\n", ocs_sm_event_name(evt));
 1183                 /* TODO: hw/device reset needed */
 1184                 break;
 1185 
 1186         default:
 1187                 __ocs_domain_common_shutdown(__func__, ctx, evt, arg);
 1188                 return NULL;
 1189         }
 1190 
 1191         return NULL;
 1192 }
 1193 
 1194 /**
 1195  * @brief Save the port's service parameters.
 1196  *
 1197  * <h3 class="desc">Description</h3>
 1198  * Service parameters from the fabric FLOGI are saved in the domain's
 1199  * flogi_service_params array.
 1200  *
 1201  * @param domain Pointer to the domain.
 1202  * @param payload Service parameters to save.
 1203  *
 1204  * @return None.
 1205  */
 1206 
 1207 void
 1208 ocs_domain_save_sparms(ocs_domain_t *domain, void *payload)
 1209 {
 1210         ocs_memcpy(domain->flogi_service_params, payload, sizeof (fc_plogi_payload_t));
 1211 }
 1212 /**
 1213  * @brief Initiator domain attach. (internal call only)
 1214  *
 1215  * Assumes that the domain SM lock is already locked
 1216  *
 1217  * <h3 class="desc">Description</h3>
 1218  * The HW domain attach function is started.
 1219  *
 1220  * @param domain Pointer to the domain object.
 1221  * @param s_id FC_ID of which to register this domain.
 1222  *
 1223  * @return None.
 1224  */
 1225 
 1226 void
 1227 __ocs_domain_attach_internal(ocs_domain_t *domain, uint32_t s_id)
 1228 {
 1229         ocs_memcpy(domain->dma.virt, ((uint8_t*)domain->flogi_service_params)+4, sizeof (fc_plogi_payload_t) - 4);
 1230         (void)ocs_sm_post_event(&domain->drvsm, OCS_EVT_DOMAIN_REQ_ATTACH, &s_id);
 1231 }
 1232 
 1233 /**
 1234  * @brief Initiator domain attach.
 1235  *
 1236  * <h3 class="desc">Description</h3>
 1237  * The HW domain attach function is started.
 1238  *
 1239  * @param domain Pointer to the domain object.
 1240  * @param s_id FC_ID of which to register this domain.
 1241  *
 1242  * @return None.
 1243  */
 1244 
 1245 void
 1246 ocs_domain_attach(ocs_domain_t *domain, uint32_t s_id)
 1247 {
 1248         __ocs_domain_attach_internal(domain, s_id);
 1249 }
 1250 
 1251 int
 1252 ocs_domain_post_event(ocs_domain_t *domain, ocs_sm_event_t event, void *arg)
 1253 {
 1254         int rc;
 1255         int accept_frames;
 1256         int req_domain_free;
 1257 
 1258         rc = ocs_sm_post_event(&domain->drvsm, event, arg);
 1259 
 1260         req_domain_free = domain->req_domain_free;
 1261         domain->req_domain_free = 0;
 1262 
 1263         accept_frames = domain->req_accept_frames;
 1264         domain->req_accept_frames = 0;
 1265 
 1266         if (accept_frames) {
 1267                 ocs_domain_accept_frames(domain);
 1268         }
 1269 
 1270         if (req_domain_free) {
 1271                 ocs_domain_free(domain);
 1272         }
 1273 
 1274         return rc;
 1275 }
 1276 
 1277 /**
 1278  * @brief Return the WWN as a uint64_t.
 1279  *
 1280  * <h3 class="desc">Description</h3>
 1281  * Calls the HW property function for the WWNN or WWPN, and returns the value
 1282  * as a uint64_t.
 1283  *
 1284  * @param hw Pointer to the HW object.
 1285  * @param prop HW property.
 1286  *
 1287  * @return Returns uint64_t request value.
 1288  */
 1289 
 1290 uint64_t
 1291 ocs_get_wwn(ocs_hw_t *hw, ocs_hw_property_e prop)
 1292 {
 1293         uint8_t *p = ocs_hw_get_ptr(hw, prop);
 1294         uint64_t value = 0;
 1295 
 1296         if (p) {
 1297                 uint32_t i;
 1298                 for (i = 0; i < sizeof(value); i++) {
 1299                         value = (value << 8) | p[i];
 1300                 }
 1301         }
 1302         return value;
 1303 }
 1304 
 1305 /**
 1306  * @brief Generate a domain ddump.
 1307  *
 1308  * <h3 class="desc">Description</h3>
 1309  * Generates a domain ddump.
 1310  *
 1311  * @param textbuf Pointer to the text buffer.
 1312  * @param domain Pointer to the domain context.
 1313  *
 1314  * @return Returns 0 on success, or a negative value on failure.
 1315  */
 1316 
 1317 int
 1318 ocs_ddump_domain(ocs_textbuf_t *textbuf, ocs_domain_t *domain)
 1319 {
 1320         ocs_sport_t *sport;
 1321         int retval = 0;
 1322 
 1323         ocs_ddump_section(textbuf, "domain", domain->instance_index);
 1324         ocs_ddump_value(textbuf, "display_name", "%s", domain->display_name);
 1325 
 1326         ocs_ddump_value(textbuf, "fcf", "%#x", domain->fcf);
 1327         ocs_ddump_value(textbuf, "fcf_indicator", "%#x", domain->fcf_indicator);
 1328         ocs_ddump_value(textbuf, "vlan_id", "%#x", domain->vlan_id);
 1329         ocs_ddump_value(textbuf, "indicator", "%#x", domain->indicator);
 1330         ocs_ddump_value(textbuf, "attached", "%d", domain->attached);
 1331         ocs_ddump_value(textbuf, "is_loop", "%d", domain->is_loop);
 1332         ocs_ddump_value(textbuf, "is_nlport", "%d", domain->is_nlport);
 1333 
 1334         ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_DOMAIN, domain);
 1335         ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_DOMAIN, domain);
 1336 
 1337         ocs_display_sparams(NULL, "domain_sparms", 1, textbuf, domain->dma.virt);
 1338 
 1339         if (ocs_domain_lock_try(domain) != TRUE) {
 1340                 /* Didn't get the lock */
 1341                 return -1;
 1342         }
 1343                 ocs_list_foreach(&domain->sport_list, sport) {
 1344                         retval = ocs_ddump_sport(textbuf, sport);
 1345                         if (retval != 0) {
 1346                                 break;
 1347                         }
 1348                 }
 1349 
 1350 #if defined(ENABLE_FABRIC_EMULATION)
 1351                 ocs_ddump_ns(textbuf, domain->ocs_ns);
 1352 #endif
 1353 
 1354         ocs_domain_unlock(domain);
 1355 
 1356         ocs_ddump_endsection(textbuf, "domain", domain->instance_index);
 1357 
 1358         return retval;
 1359 }
 1360 
 1361 void
 1362 ocs_mgmt_domain_list(ocs_textbuf_t *textbuf, void *object)
 1363 {
 1364         ocs_sport_t *sport;
 1365         ocs_domain_t *domain = (ocs_domain_t *)object;
 1366 
 1367         ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
 1368 
 1369         /* Add my status values to textbuf */
 1370         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fcf");
 1371         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fcf_indicator");
 1372         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "vlan_id");
 1373         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "indicator");
 1374         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "attached");
 1375         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "is_loop");
 1376         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
 1377         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "num_sports");
 1378 #if defined(ENABLE_FABRIC_EMULATION)
 1379         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RW, "femul_enable");
 1380 #endif
 1381 
 1382         if (ocs_domain_lock_try(domain) == TRUE) {
 1383                 /* If we get here, then we are holding the domain lock */
 1384                 ocs_list_foreach(&domain->sport_list, sport) {
 1385                         if ((sport->mgmt_functions) && (sport->mgmt_functions->get_list_handler)) {
 1386                                 sport->mgmt_functions->get_list_handler(textbuf, sport);
 1387                         }
 1388                 }
 1389                 ocs_domain_unlock(domain);
 1390         }
 1391 
 1392         ocs_mgmt_end_section(textbuf, "domain", domain->instance_index);
 1393 }
 1394 
 1395 int
 1396 ocs_mgmt_domain_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
 1397 {
 1398         ocs_sport_t *sport;
 1399         ocs_domain_t *domain = (ocs_domain_t *)object;
 1400         char qualifier[80];
 1401         int retval = -1;
 1402 
 1403         ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
 1404 
 1405         snprintf(qualifier, sizeof(qualifier), "%s/domain[%d]", parent, domain->instance_index);
 1406 
 1407         /* If it doesn't start with my qualifier I don't know what to do with it */
 1408         if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
 1409                 char *unqualified_name = name + strlen(qualifier) +1;
 1410 
 1411                 /* See if it's a value I can supply */
 1412                 if (ocs_strcmp(unqualified_name, "display_name") == 0) {
 1413                         ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
 1414                         retval = 0;
 1415                 } else if (ocs_strcmp(unqualified_name, "fcf") == 0) {
 1416                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf", "%#x", domain->fcf);
 1417                         retval = 0;
 1418                 } else if (ocs_strcmp(unqualified_name, "fcf_indicator") == 0) {
 1419                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf_indicator", "%#x", domain->fcf_indicator);
 1420                         retval = 0;
 1421                 } else if (ocs_strcmp(unqualified_name, "vlan_id") == 0) {
 1422                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "vlan_id", "%#x", domain->vlan_id);
 1423                         retval = 0;
 1424                 } else if (ocs_strcmp(unqualified_name, "indicator") == 0) {
 1425                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "%#x", domain->indicator);
 1426                         retval = 0;
 1427                 } else if (ocs_strcmp(unqualified_name, "attached") == 0) {
 1428                         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", domain->attached);
 1429                         retval = 0;
 1430                 } else if (ocs_strcmp(unqualified_name, "is_loop") == 0) {
 1431                         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_loop",  domain->is_loop);
 1432                         retval = 0;
 1433                 } else if (ocs_strcmp(unqualified_name, "is_nlport") == 0) {
 1434                         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_nlport",  domain->is_nlport);
 1435                         retval = 0;
 1436                 } else if (ocs_strcmp(unqualified_name, "display_name") == 0) {
 1437                         ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
 1438                         retval = 0;
 1439 #if defined(ENABLE_FABRIC_EMULATION)
 1440                 } else if (ocs_strcmp(unqualified_name, "femul_enable") == 0) {
 1441                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "femul_enable", "%d", domain->femul_enable);
 1442                         retval = 0;
 1443 #endif
 1444                 } else if (ocs_strcmp(unqualified_name, "num_sports") == 0) {
 1445                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "num_sports", "%d", domain->sport_instance_count);
 1446                         retval = 0;
 1447                 } else {
 1448                         /* If I didn't know the value of this status pass the request to each of my children */
 1449 
 1450                         ocs_domain_lock(domain);
 1451                         ocs_list_foreach(&domain->sport_list, sport) {
 1452                                 if ((sport->mgmt_functions) && (sport->mgmt_functions->get_handler)) {
 1453                                         retval = sport->mgmt_functions->get_handler(textbuf, qualifier, name, sport);
 1454                                 }
 1455 
 1456                                 if (retval == 0) {
 1457                                         break;
 1458                                 }
 1459                         }
 1460                         ocs_domain_unlock(domain);
 1461                 }
 1462         }
 1463 
 1464         ocs_mgmt_end_section(textbuf, "domain", domain->instance_index);
 1465         return retval;
 1466 }
 1467 
 1468 void
 1469 ocs_mgmt_domain_get_all(ocs_textbuf_t *textbuf, void *object)
 1470 {
 1471         ocs_sport_t *sport;
 1472         ocs_domain_t *domain = (ocs_domain_t *)object;
 1473 
 1474         ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
 1475 
 1476         ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
 1477         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf", "%#x", domain->fcf);
 1478         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf_indicator", "%#x", domain->fcf_indicator);
 1479         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "vlan_id", "%#x", domain->vlan_id);
 1480         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "%#x", domain->indicator);
 1481         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", domain->attached);
 1482         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_loop",  domain->is_loop);
 1483         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_nlport",  domain->is_nlport);
 1484 #if defined(ENABLE_FABRIC_EMULATION)
 1485         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "femul_enable", "%d", domain->femul_enable);
 1486 #endif
 1487         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "num_sports",  "%d", domain->sport_instance_count);
 1488 
 1489         ocs_domain_lock(domain);
 1490         ocs_list_foreach(&domain->sport_list, sport) {
 1491                 if ((sport->mgmt_functions) && (sport->mgmt_functions->get_all_handler)) {
 1492                         sport->mgmt_functions->get_all_handler(textbuf, sport);
 1493                 }
 1494         }
 1495         ocs_domain_unlock(domain);
 1496 
 1497         ocs_mgmt_end_unnumbered_section(textbuf, "domain");
 1498 
 1499 }
 1500 
 1501 int
 1502 ocs_mgmt_domain_set(char *parent, char *name, char *value, void *object)
 1503 {
 1504         ocs_sport_t *sport;
 1505         ocs_domain_t *domain = (ocs_domain_t *)object;
 1506         char qualifier[80];
 1507         int retval = -1;
 1508 
 1509         snprintf(qualifier, sizeof(qualifier), "%s/domain[%d]", parent, domain->instance_index);
 1510 
 1511         /* If it doesn't start with my qualifier I don't know what to do with it */
 1512         if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
 1513                 /* See if it's a value I can supply */
 1514 
 1515                 /* if (ocs_strcmp(unqualified_name, "display_name") == 0) {
 1516                 } else */
 1517                 {
 1518                         /* If I didn't know the value of this status pass the request to each of my children */
 1519                         ocs_domain_lock(domain);
 1520                         ocs_list_foreach(&domain->sport_list, sport) {
 1521                                 if ((sport->mgmt_functions) && (sport->mgmt_functions->set_handler)) {
 1522                                         retval = sport->mgmt_functions->set_handler(qualifier, name, value, sport);
 1523                                 }
 1524 
 1525                                 if (retval == 0) {
 1526                                         break;
 1527                                 }
 1528                         }
 1529                         ocs_domain_unlock(domain);
 1530                 }
 1531         }
 1532 
 1533         return retval;
 1534 }
 1535 
 1536 int
 1537 ocs_mgmt_domain_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
 1538                         void *arg_out, uint32_t arg_out_length, void *object)
 1539 {
 1540         ocs_sport_t *sport;
 1541         ocs_domain_t *domain = (ocs_domain_t *)object;
 1542         char qualifier[80];
 1543         int retval = -1;
 1544 
 1545         snprintf(qualifier, sizeof(qualifier), "%s.domain%d", parent, domain->instance_index);
 1546 
 1547         /* If it doesn't start with my qualifier I don't know what to do with it */
 1548         if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
 1549                 {
 1550                         /* If I didn't know how to do this action pass the request to each of my children */
 1551                         ocs_domain_lock(domain);
 1552                         ocs_list_foreach(&domain->sport_list, sport) {
 1553                                 if ((sport->mgmt_functions) && (sport->mgmt_functions->exec_handler)) {
 1554                                         retval = sport->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length, arg_out, arg_out_length, sport);
 1555                                 }
 1556 
 1557                                 if (retval == 0) {
 1558                                         break;
 1559                                 }
 1560                         }
 1561                         ocs_domain_unlock(domain);
 1562                 }
 1563         }
 1564 
 1565         return retval;
 1566 }

Cache object: 554ceefc0ab67b93e02e44392753d3e4


[ 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.