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