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