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