efc_domain.c (26485B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2021 Broadcom. All Rights Reserved. The term 4 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 */ 6 7/* 8 * domain_sm Domain State Machine: States 9 */ 10 11#include "efc.h" 12 13int 14efc_domain_cb(void *arg, int event, void *data) 15{ 16 struct efc *efc = arg; 17 struct efc_domain *domain = NULL; 18 int rc = 0; 19 unsigned long flags = 0; 20 21 if (event != EFC_HW_DOMAIN_FOUND) 22 domain = data; 23 24 /* Accept domain callback events from the user driver */ 25 spin_lock_irqsave(&efc->lock, flags); 26 switch (event) { 27 case EFC_HW_DOMAIN_FOUND: { 28 u64 fcf_wwn = 0; 29 struct efc_domain_record *drec = data; 30 31 /* extract the fcf_wwn */ 32 fcf_wwn = be64_to_cpu(*((__be64 *)drec->wwn)); 33 34 efc_log_debug(efc, "Domain found: wwn %016llX\n", fcf_wwn); 35 36 /* lookup domain, or allocate a new one */ 37 domain = efc->domain; 38 if (!domain) { 39 domain = efc_domain_alloc(efc, fcf_wwn); 40 if (!domain) { 41 efc_log_err(efc, "efc_domain_alloc() failed\n"); 42 rc = -1; 43 break; 44 } 45 efc_sm_transition(&domain->drvsm, __efc_domain_init, 46 NULL); 47 } 48 efc_domain_post_event(domain, EFC_EVT_DOMAIN_FOUND, drec); 49 break; 50 } 51 52 case EFC_HW_DOMAIN_LOST: 53 domain_trace(domain, "EFC_HW_DOMAIN_LOST:\n"); 54 efc->hold_frames = true; 55 efc_domain_post_event(domain, EFC_EVT_DOMAIN_LOST, NULL); 56 break; 57 58 case EFC_HW_DOMAIN_ALLOC_OK: 59 domain_trace(domain, "EFC_HW_DOMAIN_ALLOC_OK:\n"); 60 efc_domain_post_event(domain, EFC_EVT_DOMAIN_ALLOC_OK, NULL); 61 break; 62 63 case EFC_HW_DOMAIN_ALLOC_FAIL: 64 domain_trace(domain, "EFC_HW_DOMAIN_ALLOC_FAIL:\n"); 65 efc_domain_post_event(domain, EFC_EVT_DOMAIN_ALLOC_FAIL, 66 NULL); 67 break; 68 69 case EFC_HW_DOMAIN_ATTACH_OK: 70 domain_trace(domain, "EFC_HW_DOMAIN_ATTACH_OK:\n"); 71 efc_domain_post_event(domain, EFC_EVT_DOMAIN_ATTACH_OK, NULL); 72 break; 73 74 case EFC_HW_DOMAIN_ATTACH_FAIL: 75 domain_trace(domain, "EFC_HW_DOMAIN_ATTACH_FAIL:\n"); 76 efc_domain_post_event(domain, 77 EFC_EVT_DOMAIN_ATTACH_FAIL, NULL); 78 break; 79 80 case EFC_HW_DOMAIN_FREE_OK: 81 domain_trace(domain, "EFC_HW_DOMAIN_FREE_OK:\n"); 82 efc_domain_post_event(domain, EFC_EVT_DOMAIN_FREE_OK, NULL); 83 break; 84 85 case EFC_HW_DOMAIN_FREE_FAIL: 86 domain_trace(domain, "EFC_HW_DOMAIN_FREE_FAIL:\n"); 87 efc_domain_post_event(domain, EFC_EVT_DOMAIN_FREE_FAIL, NULL); 88 break; 89 90 default: 91 efc_log_warn(efc, "unsupported event %#x\n", event); 92 } 93 spin_unlock_irqrestore(&efc->lock, flags); 94 95 if (efc->domain && domain->req_accept_frames) { 96 domain->req_accept_frames = false; 97 efc->hold_frames = false; 98 } 99 100 return rc; 101} 102 103static void 104_efc_domain_free(struct kref *arg) 105{ 106 struct efc_domain *domain = container_of(arg, struct efc_domain, ref); 107 struct efc *efc = domain->efc; 108 109 if (efc->domain_free_cb) 110 (*efc->domain_free_cb)(efc, efc->domain_free_cb_arg); 111 112 kfree(domain); 113} 114 115void 116efc_domain_free(struct efc_domain *domain) 117{ 118 struct efc *efc; 119 120 efc = domain->efc; 121 122 /* Hold frames to clear the domain pointer from the xport lookup */ 123 efc->hold_frames = false; 124 125 efc_log_debug(efc, "Domain free: wwn %016llX\n", domain->fcf_wwn); 126 127 xa_destroy(&domain->lookup); 128 efc->domain = NULL; 129 kref_put(&domain->ref, domain->release); 130} 131 132struct efc_domain * 133efc_domain_alloc(struct efc *efc, uint64_t fcf_wwn) 134{ 135 struct efc_domain *domain; 136 137 domain = kzalloc(sizeof(*domain), GFP_ATOMIC); 138 if (!domain) 139 return NULL; 140 141 domain->efc = efc; 142 domain->drvsm.app = domain; 143 144 /* initialize refcount */ 145 kref_init(&domain->ref); 146 domain->release = _efc_domain_free; 147 148 xa_init(&domain->lookup); 149 150 INIT_LIST_HEAD(&domain->nport_list); 151 efc->domain = domain; 152 domain->fcf_wwn = fcf_wwn; 153 efc_log_debug(efc, "Domain allocated: wwn %016llX\n", domain->fcf_wwn); 154 155 return domain; 156} 157 158void 159efc_register_domain_free_cb(struct efc *efc, 160 void (*callback)(struct efc *efc, void *arg), 161 void *arg) 162{ 163 /* Register a callback to be called when the domain is freed */ 164 efc->domain_free_cb = callback; 165 efc->domain_free_cb_arg = arg; 166 if (!efc->domain && callback) 167 (*callback)(efc, arg); 168} 169 170static void 171__efc_domain_common(const char *funcname, struct efc_sm_ctx *ctx, 172 enum efc_sm_event evt, void *arg) 173{ 174 struct efc_domain *domain = ctx->app; 175 176 switch (evt) { 177 case EFC_EVT_ENTER: 178 case EFC_EVT_REENTER: 179 case EFC_EVT_EXIT: 180 case EFC_EVT_ALL_CHILD_NODES_FREE: 181 /* 182 * this can arise if an FLOGI fails on the NPORT, 183 * and the NPORT is shutdown 184 */ 185 break; 186 default: 187 efc_log_warn(domain->efc, "%-20s %-20s not handled\n", 188 funcname, efc_sm_event_name(evt)); 189 } 190} 191 192static void 193__efc_domain_common_shutdown(const char *funcname, struct efc_sm_ctx *ctx, 194 enum efc_sm_event evt, void *arg) 195{ 196 struct efc_domain *domain = ctx->app; 197 198 switch (evt) { 199 case EFC_EVT_ENTER: 200 case EFC_EVT_REENTER: 201 case EFC_EVT_EXIT: 202 break; 203 case EFC_EVT_DOMAIN_FOUND: 204 /* save drec, mark domain_found_pending */ 205 memcpy(&domain->pending_drec, arg, 206 sizeof(domain->pending_drec)); 207 domain->domain_found_pending = true; 208 break; 209 case EFC_EVT_DOMAIN_LOST: 210 /* unmark domain_found_pending */ 211 domain->domain_found_pending = false; 212 break; 213 214 default: 215 efc_log_warn(domain->efc, "%-20s %-20s not handled\n", 216 funcname, efc_sm_event_name(evt)); 217 } 218} 219 220#define std_domain_state_decl(...)\ 221 struct efc_domain *domain = NULL;\ 222 struct efc *efc = NULL;\ 223 \ 224 WARN_ON(!ctx || !ctx->app);\ 225 domain = ctx->app;\ 226 WARN_ON(!domain->efc);\ 227 efc = domain->efc 228 229void 230__efc_domain_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, 231 void *arg) 232{ 233 std_domain_state_decl(); 234 235 domain_sm_trace(domain); 236 237 switch (evt) { 238 case EFC_EVT_ENTER: 239 domain->attached = false; 240 break; 241 242 case EFC_EVT_DOMAIN_FOUND: { 243 u32 i; 244 struct efc_domain_record *drec = arg; 245 struct efc_nport *nport; 246 247 u64 my_wwnn = efc->req_wwnn; 248 u64 my_wwpn = efc->req_wwpn; 249 __be64 bewwpn; 250 251 if (my_wwpn == 0 || my_wwnn == 0) { 252 efc_log_debug(efc, "using default hardware WWN config\n"); 253 my_wwpn = efc->def_wwpn; 254 my_wwnn = efc->def_wwnn; 255 } 256 257 efc_log_debug(efc, "Create nport WWPN %016llX WWNN %016llX\n", 258 my_wwpn, my_wwnn); 259 260 /* Allocate a nport and transition to __efc_nport_allocated */ 261 nport = efc_nport_alloc(domain, my_wwpn, my_wwnn, U32_MAX, 262 efc->enable_ini, efc->enable_tgt); 263 264 if (!nport) { 265 efc_log_err(efc, "efc_nport_alloc() failed\n"); 266 break; 267 } 268 efc_sm_transition(&nport->sm, __efc_nport_allocated, NULL); 269 270 bewwpn = cpu_to_be64(nport->wwpn); 271 272 /* allocate struct efc_nport object for local port 273 * Note: drec->fc_id is ALPA from read_topology only if loop 274 */ 275 if (efc_cmd_nport_alloc(efc, nport, NULL, (uint8_t *)&bewwpn)) { 276 efc_log_err(efc, "Can't allocate port\n"); 277 efc_nport_free(nport); 278 break; 279 } 280 281 domain->is_loop = drec->is_loop; 282 283 /* 284 * If the loop position map includes ALPA == 0, 285 * then we are in a public loop (NL_PORT) 286 * Note that the first element of the loopmap[] 287 * contains the count of elements, and if 288 * ALPA == 0 is present, it will occupy the first 289 * location after the count. 290 */ 291 domain->is_nlport = drec->map.loop[1] == 0x00; 292 293 if (!domain->is_loop) { 294 /* Initiate HW domain alloc */ 295 if (efc_cmd_domain_alloc(efc, domain, drec->index)) { 296 efc_log_err(efc, 297 "Failed to initiate HW domain allocation\n"); 298 break; 299 } 300 efc_sm_transition(ctx, __efc_domain_wait_alloc, arg); 301 break; 302 } 303 304 efc_log_debug(efc, "%s fc_id=%#x speed=%d\n", 305 drec->is_loop ? 306 (domain->is_nlport ? 307 "public-loop" : "loop") : "other", 308 drec->fc_id, drec->speed); 309 310 nport->fc_id = drec->fc_id; 311 nport->topology = EFC_NPORT_TOPO_FC_AL; 312 snprintf(nport->display_name, sizeof(nport->display_name), 313 "s%06x", drec->fc_id); 314 315 if (efc->enable_ini) { 316 u32 count = drec->map.loop[0]; 317 318 efc_log_debug(efc, "%d position map entries\n", 319 count); 320 for (i = 1; i <= count; i++) { 321 if (drec->map.loop[i] != drec->fc_id) { 322 struct efc_node *node; 323 324 efc_log_debug(efc, "%#x -> %#x\n", 325 drec->fc_id, 326 drec->map.loop[i]); 327 node = efc_node_alloc(nport, 328 drec->map.loop[i], 329 false, true); 330 if (!node) { 331 efc_log_err(efc, 332 "efc_node_alloc() failed\n"); 333 break; 334 } 335 efc_node_transition(node, 336 __efc_d_wait_loop, 337 NULL); 338 } 339 } 340 } 341 342 /* Initiate HW domain alloc */ 343 if (efc_cmd_domain_alloc(efc, domain, drec->index)) { 344 efc_log_err(efc, 345 "Failed to initiate HW domain allocation\n"); 346 break; 347 } 348 efc_sm_transition(ctx, __efc_domain_wait_alloc, arg); 349 break; 350 } 351 default: 352 __efc_domain_common(__func__, ctx, evt, arg); 353 } 354} 355 356void 357__efc_domain_wait_alloc(struct efc_sm_ctx *ctx, 358 enum efc_sm_event evt, void *arg) 359{ 360 std_domain_state_decl(); 361 362 domain_sm_trace(domain); 363 364 switch (evt) { 365 case EFC_EVT_DOMAIN_ALLOC_OK: { 366 struct fc_els_flogi *sp; 367 struct efc_nport *nport; 368 369 nport = domain->nport; 370 if (WARN_ON(!nport)) 371 return; 372 373 sp = (struct fc_els_flogi *)nport->service_params; 374 375 /* Save the domain service parameters */ 376 memcpy(domain->service_params + 4, domain->dma.virt, 377 sizeof(struct fc_els_flogi) - 4); 378 memcpy(nport->service_params + 4, domain->dma.virt, 379 sizeof(struct fc_els_flogi) - 4); 380 381 /* 382 * Update the nport's service parameters, 383 * user might have specified non-default names 384 */ 385 sp->fl_wwpn = cpu_to_be64(nport->wwpn); 386 sp->fl_wwnn = cpu_to_be64(nport->wwnn); 387 388 /* 389 * Take the loop topology path, 390 * unless we are an NL_PORT (public loop) 391 */ 392 if (domain->is_loop && !domain->is_nlport) { 393 /* 394 * For loop, we already have our FC ID 395 * and don't need fabric login. 396 * Transition to the allocated state and 397 * post an event to attach to 398 * the domain. Note that this breaks the 399 * normal action/transition 400 * pattern here to avoid a race with the 401 * domain attach callback. 402 */ 403 /* sm: is_loop / domain_attach */ 404 efc_sm_transition(ctx, __efc_domain_allocated, NULL); 405 __efc_domain_attach_internal(domain, nport->fc_id); 406 break; 407 } 408 { 409 struct efc_node *node; 410 411 /* alloc fabric node, send FLOGI */ 412 node = efc_node_find(nport, FC_FID_FLOGI); 413 if (node) { 414 efc_log_err(efc, 415 "Fabric Controller node already exists\n"); 416 break; 417 } 418 node = efc_node_alloc(nport, FC_FID_FLOGI, 419 false, false); 420 if (!node) { 421 efc_log_err(efc, 422 "Error: efc_node_alloc() failed\n"); 423 } else { 424 efc_node_transition(node, 425 __efc_fabric_init, NULL); 426 } 427 /* Accept frames */ 428 domain->req_accept_frames = true; 429 } 430 /* sm: / start fabric logins */ 431 efc_sm_transition(ctx, __efc_domain_allocated, NULL); 432 break; 433 } 434 435 case EFC_EVT_DOMAIN_ALLOC_FAIL: 436 efc_log_err(efc, "%s recv'd waiting for DOMAIN_ALLOC_OK;", 437 efc_sm_event_name(evt)); 438 efc_log_err(efc, "shutting down domain\n"); 439 domain->req_domain_free = true; 440 break; 441 442 case EFC_EVT_DOMAIN_FOUND: 443 /* Should not happen */ 444 break; 445 446 case EFC_EVT_DOMAIN_LOST: 447 efc_log_debug(efc, 448 "%s received while waiting for hw_domain_alloc()\n", 449 efc_sm_event_name(evt)); 450 efc_sm_transition(ctx, __efc_domain_wait_domain_lost, NULL); 451 break; 452 453 default: 454 __efc_domain_common(__func__, ctx, evt, arg); 455 } 456} 457 458void 459__efc_domain_allocated(struct efc_sm_ctx *ctx, 460 enum efc_sm_event evt, void *arg) 461{ 462 std_domain_state_decl(); 463 464 domain_sm_trace(domain); 465 466 switch (evt) { 467 case EFC_EVT_DOMAIN_REQ_ATTACH: { 468 int rc = 0; 469 u32 fc_id; 470 471 if (WARN_ON(!arg)) 472 return; 473 474 fc_id = *((u32 *)arg); 475 efc_log_debug(efc, "Requesting hw domain attach fc_id x%x\n", 476 fc_id); 477 /* Update nport lookup */ 478 rc = xa_err(xa_store(&domain->lookup, fc_id, domain->nport, 479 GFP_ATOMIC)); 480 if (rc) { 481 efc_log_err(efc, "Sport lookup store failed: %d\n", rc); 482 return; 483 } 484 485 /* Update display name for the nport */ 486 efc_node_fcid_display(fc_id, domain->nport->display_name, 487 sizeof(domain->nport->display_name)); 488 489 /* Issue domain attach call */ 490 rc = efc_cmd_domain_attach(efc, domain, fc_id); 491 if (rc) { 492 efc_log_err(efc, "efc_hw_domain_attach failed: %d\n", 493 rc); 494 return; 495 } 496 /* sm: / domain_attach */ 497 efc_sm_transition(ctx, __efc_domain_wait_attach, NULL); 498 break; 499 } 500 501 case EFC_EVT_DOMAIN_FOUND: 502 /* Should not happen */ 503 efc_log_err(efc, "%s: evt: %d should not happen\n", 504 __func__, evt); 505 break; 506 507 case EFC_EVT_DOMAIN_LOST: { 508 efc_log_debug(efc, 509 "%s received while in EFC_EVT_DOMAIN_REQ_ATTACH\n", 510 efc_sm_event_name(evt)); 511 if (!list_empty(&domain->nport_list)) { 512 /* 513 * if there are nports, transition to 514 * wait state and send shutdown to each 515 * nport 516 */ 517 struct efc_nport *nport = NULL, *nport_next = NULL; 518 519 efc_sm_transition(ctx, __efc_domain_wait_nports_free, 520 NULL); 521 list_for_each_entry_safe(nport, nport_next, 522 &domain->nport_list, 523 list_entry) { 524 efc_sm_post_event(&nport->sm, 525 EFC_EVT_SHUTDOWN, NULL); 526 } 527 } else { 528 /* no nports exist, free domain */ 529 efc_sm_transition(ctx, __efc_domain_wait_shutdown, 530 NULL); 531 if (efc_cmd_domain_free(efc, domain)) 532 efc_log_err(efc, "hw_domain_free failed\n"); 533 } 534 535 break; 536 } 537 538 default: 539 __efc_domain_common(__func__, ctx, evt, arg); 540 } 541} 542 543void 544__efc_domain_wait_attach(struct efc_sm_ctx *ctx, 545 enum efc_sm_event evt, void *arg) 546{ 547 std_domain_state_decl(); 548 549 domain_sm_trace(domain); 550 551 switch (evt) { 552 case EFC_EVT_DOMAIN_ATTACH_OK: { 553 struct efc_node *node = NULL; 554 struct efc_nport *nport, *next_nport; 555 unsigned long index; 556 557 /* 558 * Set domain notify pending state to avoid 559 * duplicate domain event post 560 */ 561 domain->domain_notify_pend = true; 562 563 /* Mark as attached */ 564 domain->attached = true; 565 566 /* Transition to ready */ 567 /* sm: / forward event to all nports and nodes */ 568 efc_sm_transition(ctx, __efc_domain_ready, NULL); 569 570 /* We have an FCFI, so we can accept frames */ 571 domain->req_accept_frames = true; 572 573 /* 574 * Notify all nodes that the domain attach request 575 * has completed 576 * Note: nport will have already received notification 577 * of nport attached as a result of the HW's port attach. 578 */ 579 list_for_each_entry_safe(nport, next_nport, 580 &domain->nport_list, list_entry) { 581 xa_for_each(&nport->lookup, index, node) { 582 efc_node_post_event(node, 583 EFC_EVT_DOMAIN_ATTACH_OK, 584 NULL); 585 } 586 } 587 domain->domain_notify_pend = false; 588 break; 589 } 590 591 case EFC_EVT_DOMAIN_ATTACH_FAIL: 592 efc_log_debug(efc, 593 "%s received while waiting for hw attach\n", 594 efc_sm_event_name(evt)); 595 break; 596 597 case EFC_EVT_DOMAIN_FOUND: 598 /* Should not happen */ 599 efc_log_err(efc, "%s: evt: %d should not happen\n", 600 __func__, evt); 601 break; 602 603 case EFC_EVT_DOMAIN_LOST: 604 /* 605 * Domain lost while waiting for an attach to complete, 606 * go to a state that waits for the domain attach to 607 * complete, then handle domain lost 608 */ 609 efc_sm_transition(ctx, __efc_domain_wait_domain_lost, NULL); 610 break; 611 612 case EFC_EVT_DOMAIN_REQ_ATTACH: 613 /* 614 * In P2P we can get an attach request from 615 * the other FLOGI path, so drop this one 616 */ 617 break; 618 619 default: 620 __efc_domain_common(__func__, ctx, evt, arg); 621 } 622} 623 624void 625__efc_domain_ready(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg) 626{ 627 std_domain_state_decl(); 628 629 domain_sm_trace(domain); 630 631 switch (evt) { 632 case EFC_EVT_ENTER: { 633 /* start any pending vports */ 634 if (efc_vport_start(domain)) { 635 efc_log_debug(domain->efc, 636 "efc_vport_start didn't start vports\n"); 637 } 638 break; 639 } 640 case EFC_EVT_DOMAIN_LOST: { 641 if (!list_empty(&domain->nport_list)) { 642 /* 643 * if there are nports, transition to wait state 644 * and send shutdown to each nport 645 */ 646 struct efc_nport *nport = NULL, *nport_next = NULL; 647 648 efc_sm_transition(ctx, __efc_domain_wait_nports_free, 649 NULL); 650 list_for_each_entry_safe(nport, nport_next, 651 &domain->nport_list, 652 list_entry) { 653 efc_sm_post_event(&nport->sm, 654 EFC_EVT_SHUTDOWN, NULL); 655 } 656 } else { 657 /* no nports exist, free domain */ 658 efc_sm_transition(ctx, __efc_domain_wait_shutdown, 659 NULL); 660 if (efc_cmd_domain_free(efc, domain)) 661 efc_log_err(efc, "hw_domain_free failed\n"); 662 } 663 break; 664 } 665 666 case EFC_EVT_DOMAIN_FOUND: 667 /* Should not happen */ 668 efc_log_err(efc, "%s: evt: %d should not happen\n", 669 __func__, evt); 670 break; 671 672 case EFC_EVT_DOMAIN_REQ_ATTACH: { 673 /* can happen during p2p */ 674 u32 fc_id; 675 676 fc_id = *((u32 *)arg); 677 678 /* Assume that the domain is attached */ 679 WARN_ON(!domain->attached); 680 681 /* 682 * Verify that the requested FC_ID 683 * is the same as the one we're working with 684 */ 685 WARN_ON(domain->nport->fc_id != fc_id); 686 break; 687 } 688 689 default: 690 __efc_domain_common(__func__, ctx, evt, arg); 691 } 692} 693 694void 695__efc_domain_wait_nports_free(struct efc_sm_ctx *ctx, enum efc_sm_event evt, 696 void *arg) 697{ 698 std_domain_state_decl(); 699 700 domain_sm_trace(domain); 701 702 /* Wait for nodes to free prior to the domain shutdown */ 703 switch (evt) { 704 case EFC_EVT_ALL_CHILD_NODES_FREE: { 705 int rc; 706 707 /* sm: / efc_hw_domain_free */ 708 efc_sm_transition(ctx, __efc_domain_wait_shutdown, NULL); 709 710 /* Request efc_hw_domain_free and wait for completion */ 711 rc = efc_cmd_domain_free(efc, domain); 712 if (rc) { 713 efc_log_err(efc, "efc_hw_domain_free() failed: %d\n", 714 rc); 715 } 716 break; 717 } 718 default: 719 __efc_domain_common_shutdown(__func__, ctx, evt, arg); 720 } 721} 722 723void 724__efc_domain_wait_shutdown(struct efc_sm_ctx *ctx, 725 enum efc_sm_event evt, void *arg) 726{ 727 std_domain_state_decl(); 728 729 domain_sm_trace(domain); 730 731 switch (evt) { 732 case EFC_EVT_DOMAIN_FREE_OK: 733 /* sm: / domain_free */ 734 if (domain->domain_found_pending) { 735 /* 736 * save fcf_wwn and drec from this domain, 737 * free current domain and allocate 738 * a new one with the same fcf_wwn 739 * could use a SLI-4 "re-register VPI" 740 * operation here? 741 */ 742 u64 fcf_wwn = domain->fcf_wwn; 743 struct efc_domain_record drec = domain->pending_drec; 744 745 efc_log_debug(efc, "Reallocating domain\n"); 746 domain->req_domain_free = true; 747 domain = efc_domain_alloc(efc, fcf_wwn); 748 749 if (!domain) { 750 efc_log_err(efc, 751 "efc_domain_alloc() failed\n"); 752 return; 753 } 754 /* 755 * got a new domain; at this point, 756 * there are at least two domains 757 * once the req_domain_free flag is processed, 758 * the associated domain will be removed. 759 */ 760 efc_sm_transition(&domain->drvsm, __efc_domain_init, 761 NULL); 762 efc_sm_post_event(&domain->drvsm, 763 EFC_EVT_DOMAIN_FOUND, &drec); 764 } else { 765 domain->req_domain_free = true; 766 } 767 break; 768 default: 769 __efc_domain_common_shutdown(__func__, ctx, evt, arg); 770 } 771} 772 773void 774__efc_domain_wait_domain_lost(struct efc_sm_ctx *ctx, 775 enum efc_sm_event evt, void *arg) 776{ 777 std_domain_state_decl(); 778 779 domain_sm_trace(domain); 780 781 /* 782 * Wait for the domain alloc/attach completion 783 * after receiving a domain lost. 784 */ 785 switch (evt) { 786 case EFC_EVT_DOMAIN_ALLOC_OK: 787 case EFC_EVT_DOMAIN_ATTACH_OK: { 788 if (!list_empty(&domain->nport_list)) { 789 /* 790 * if there are nports, transition to 791 * wait state and send shutdown to each nport 792 */ 793 struct efc_nport *nport = NULL, *nport_next = NULL; 794 795 efc_sm_transition(ctx, __efc_domain_wait_nports_free, 796 NULL); 797 list_for_each_entry_safe(nport, nport_next, 798 &domain->nport_list, 799 list_entry) { 800 efc_sm_post_event(&nport->sm, 801 EFC_EVT_SHUTDOWN, NULL); 802 } 803 } else { 804 /* no nports exist, free domain */ 805 efc_sm_transition(ctx, __efc_domain_wait_shutdown, 806 NULL); 807 if (efc_cmd_domain_free(efc, domain)) 808 efc_log_err(efc, "hw_domain_free() failed\n"); 809 } 810 break; 811 } 812 case EFC_EVT_DOMAIN_ALLOC_FAIL: 813 case EFC_EVT_DOMAIN_ATTACH_FAIL: 814 efc_log_err(efc, "[domain] %-20s: failed\n", 815 efc_sm_event_name(evt)); 816 break; 817 818 default: 819 __efc_domain_common_shutdown(__func__, ctx, evt, arg); 820 } 821} 822 823void 824__efc_domain_attach_internal(struct efc_domain *domain, u32 s_id) 825{ 826 memcpy(domain->dma.virt, 827 ((uint8_t *)domain->flogi_service_params) + 4, 828 sizeof(struct fc_els_flogi) - 4); 829 (void)efc_sm_post_event(&domain->drvsm, EFC_EVT_DOMAIN_REQ_ATTACH, 830 &s_id); 831} 832 833void 834efc_domain_attach(struct efc_domain *domain, u32 s_id) 835{ 836 __efc_domain_attach_internal(domain, s_id); 837} 838 839int 840efc_domain_post_event(struct efc_domain *domain, 841 enum efc_sm_event event, void *arg) 842{ 843 int rc; 844 bool req_domain_free; 845 846 rc = efc_sm_post_event(&domain->drvsm, event, arg); 847 848 req_domain_free = domain->req_domain_free; 849 domain->req_domain_free = false; 850 851 if (req_domain_free) 852 efc_domain_free(domain); 853 854 return rc; 855} 856 857static void 858efct_domain_process_pending(struct efc_domain *domain) 859{ 860 struct efc *efc = domain->efc; 861 struct efc_hw_sequence *seq = NULL; 862 u32 processed = 0; 863 unsigned long flags = 0; 864 865 for (;;) { 866 /* need to check for hold frames condition after each frame 867 * processed because any given frame could cause a transition 868 * to a state that holds frames 869 */ 870 if (efc->hold_frames) 871 break; 872 873 /* Get next frame/sequence */ 874 spin_lock_irqsave(&efc->pend_frames_lock, flags); 875 876 if (!list_empty(&efc->pend_frames)) { 877 seq = list_first_entry(&efc->pend_frames, 878 struct efc_hw_sequence, list_entry); 879 list_del(&seq->list_entry); 880 } 881 882 if (!seq) { 883 processed = efc->pend_frames_processed; 884 efc->pend_frames_processed = 0; 885 spin_unlock_irqrestore(&efc->pend_frames_lock, flags); 886 break; 887 } 888 efc->pend_frames_processed++; 889 890 spin_unlock_irqrestore(&efc->pend_frames_lock, flags); 891 892 /* now dispatch frame(s) to dispatch function */ 893 if (efc_domain_dispatch_frame(domain, seq)) 894 efc->tt.hw_seq_free(efc, seq); 895 896 seq = NULL; 897 } 898 899 if (processed != 0) 900 efc_log_debug(efc, "%u domain frames held and processed\n", 901 processed); 902} 903 904void 905efc_dispatch_frame(struct efc *efc, struct efc_hw_sequence *seq) 906{ 907 struct efc_domain *domain = efc->domain; 908 909 /* 910 * If we are holding frames or the domain is not yet registered or 911 * there's already frames on the pending list, 912 * then add the new frame to pending list 913 */ 914 if (!domain || efc->hold_frames || !list_empty(&efc->pend_frames)) { 915 unsigned long flags = 0; 916 917 spin_lock_irqsave(&efc->pend_frames_lock, flags); 918 INIT_LIST_HEAD(&seq->list_entry); 919 list_add_tail(&seq->list_entry, &efc->pend_frames); 920 spin_unlock_irqrestore(&efc->pend_frames_lock, flags); 921 922 if (domain) { 923 /* immediately process pending frames */ 924 efct_domain_process_pending(domain); 925 } 926 } else { 927 /* 928 * We are not holding frames and pending list is empty, 929 * just process frame. A non-zero return means the frame 930 * was not handled - so cleanup 931 */ 932 if (efc_domain_dispatch_frame(domain, seq)) 933 efc->tt.hw_seq_free(efc, seq); 934 } 935} 936 937int 938efc_domain_dispatch_frame(void *arg, struct efc_hw_sequence *seq) 939{ 940 struct efc_domain *domain = (struct efc_domain *)arg; 941 struct efc *efc = domain->efc; 942 struct fc_frame_header *hdr; 943 struct efc_node *node = NULL; 944 struct efc_nport *nport = NULL; 945 unsigned long flags = 0; 946 u32 s_id, d_id, rc = EFC_HW_SEQ_FREE; 947 948 if (!seq->header || !seq->header->dma.virt || !seq->payload->dma.virt) { 949 efc_log_err(efc, "Sequence header or payload is null\n"); 950 return rc; 951 } 952 953 hdr = seq->header->dma.virt; 954 955 /* extract the s_id and d_id */ 956 s_id = ntoh24(hdr->fh_s_id); 957 d_id = ntoh24(hdr->fh_d_id); 958 959 spin_lock_irqsave(&efc->lock, flags); 960 961 nport = efc_nport_find(domain, d_id); 962 if (!nport) { 963 if (hdr->fh_type == FC_TYPE_FCP) { 964 /* Drop frame */ 965 efc_log_warn(efc, "FCP frame with invalid d_id x%x\n", 966 d_id); 967 goto out; 968 } 969 970 /* p2p will use this case */ 971 nport = domain->nport; 972 if (!nport || !kref_get_unless_zero(&nport->ref)) { 973 efc_log_err(efc, "Physical nport is NULL\n"); 974 goto out; 975 } 976 } 977 978 /* Lookup the node given the remote s_id */ 979 node = efc_node_find(nport, s_id); 980 981 /* If not found, then create a new node */ 982 if (!node) { 983 /* 984 * If this is solicited data or control based on R_CTL and 985 * there is no node context, then we can drop the frame 986 */ 987 if ((hdr->fh_r_ctl == FC_RCTL_DD_SOL_DATA) || 988 (hdr->fh_r_ctl == FC_RCTL_DD_SOL_CTL)) { 989 efc_log_debug(efc, "sol data/ctrl frame without node\n"); 990 goto out_release; 991 } 992 993 node = efc_node_alloc(nport, s_id, false, false); 994 if (!node) { 995 efc_log_err(efc, "efc_node_alloc() failed\n"); 996 goto out_release; 997 } 998 /* don't send PLOGI on efc_d_init entry */ 999 efc_node_init_device(node, false); 1000 } 1001 1002 if (node->hold_frames || !list_empty(&node->pend_frames)) { 1003 /* add frame to node's pending list */ 1004 spin_lock(&node->pend_frames_lock); 1005 INIT_LIST_HEAD(&seq->list_entry); 1006 list_add_tail(&seq->list_entry, &node->pend_frames); 1007 spin_unlock(&node->pend_frames_lock); 1008 rc = EFC_HW_SEQ_HOLD; 1009 goto out_release; 1010 } 1011 1012 /* now dispatch frame to the node frame handler */ 1013 efc_node_dispatch_frame(node, seq); 1014 1015out_release: 1016 kref_put(&nport->ref, nport->release); 1017out: 1018 spin_unlock_irqrestore(&efc->lock, flags); 1019 return rc; 1020} 1021 1022void 1023efc_node_dispatch_frame(void *arg, struct efc_hw_sequence *seq) 1024{ 1025 struct fc_frame_header *hdr = seq->header->dma.virt; 1026 u32 port_id; 1027 struct efc_node *node = (struct efc_node *)arg; 1028 struct efc *efc = node->efc; 1029 1030 port_id = ntoh24(hdr->fh_s_id); 1031 1032 if (WARN_ON(port_id != node->rnode.fc_id)) 1033 return; 1034 1035 if ((!(ntoh24(hdr->fh_f_ctl) & FC_FC_END_SEQ)) || 1036 !(ntoh24(hdr->fh_f_ctl) & FC_FC_SEQ_INIT)) { 1037 node_printf(node, 1038 "Drop frame hdr = %08x %08x %08x %08x %08x %08x\n", 1039 cpu_to_be32(((u32 *)hdr)[0]), 1040 cpu_to_be32(((u32 *)hdr)[1]), 1041 cpu_to_be32(((u32 *)hdr)[2]), 1042 cpu_to_be32(((u32 *)hdr)[3]), 1043 cpu_to_be32(((u32 *)hdr)[4]), 1044 cpu_to_be32(((u32 *)hdr)[5])); 1045 return; 1046 } 1047 1048 switch (hdr->fh_r_ctl) { 1049 case FC_RCTL_ELS_REQ: 1050 case FC_RCTL_ELS_REP: 1051 efc_node_recv_els_frame(node, seq); 1052 break; 1053 1054 case FC_RCTL_BA_ABTS: 1055 case FC_RCTL_BA_ACC: 1056 case FC_RCTL_BA_RJT: 1057 case FC_RCTL_BA_NOP: 1058 efc_log_err(efc, "Received ABTS:\n"); 1059 break; 1060 1061 case FC_RCTL_DD_UNSOL_CMD: 1062 case FC_RCTL_DD_UNSOL_CTL: 1063 switch (hdr->fh_type) { 1064 case FC_TYPE_FCP: 1065 if ((hdr->fh_r_ctl & 0xf) == FC_RCTL_DD_UNSOL_CMD) { 1066 if (!node->fcp_enabled) { 1067 efc_node_recv_fcp_cmd(node, seq); 1068 break; 1069 } 1070 efc_log_err(efc, "Recvd FCP CMD. Drop IO\n"); 1071 } else if ((hdr->fh_r_ctl & 0xf) == 1072 FC_RCTL_DD_SOL_DATA) { 1073 node_printf(node, 1074 "solicited data recvd. Drop IO\n"); 1075 } 1076 break; 1077 1078 case FC_TYPE_CT: 1079 efc_node_recv_ct_frame(node, seq); 1080 break; 1081 default: 1082 break; 1083 } 1084 break; 1085 default: 1086 efc_log_err(efc, "Unhandled frame rctl: %02x\n", hdr->fh_r_ctl); 1087 } 1088}