1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #include <emlxs.h> 29 30 31 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 32 EMLXS_MSG_DEF(EMLXS_NODE_C); 33 34 /* Timeout == -1 will enable the offline timer */ 35 /* Timeout not -1 will apply the timeout */ 36 extern void 37 emlxs_node_close(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno, 38 int32_t timeout) 39 { 40 emlxs_hba_t *hba = HBA; 41 emlxs_config_t *cfg = &CFG; 42 CHANNEL *cp; 43 NODELIST *prev; 44 uint32_t offline = 0; 45 46 47 /* If node is on a channel service queue, then remove it */ 48 mutex_enter(&EMLXS_TX_CHANNEL_LOCK); 49 50 /* Return if node destroyed */ 51 if (!ndlp || !ndlp->nlp_active) { 52 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 53 54 return; 55 } 56 57 /* Check offline support */ 58 if (timeout == -1) { 59 if (cfg[CFG_OFFLINE_TIMEOUT].current) { 60 timeout = cfg[CFG_OFFLINE_TIMEOUT].current; 61 offline = 1; 62 } else { 63 timeout = 0; 64 } 65 } 66 67 if (channelno == hba->channel_ip) { 68 /* Clear IP XRI */ 69 ndlp->nlp_Xri = 0; 70 } 71 72 /* Check if node is already closed */ 73 if (ndlp->nlp_flag[channelno] & NLP_CLOSED) { 74 if (ndlp->nlp_flag[channelno] & NLP_OFFLINE) { 75 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 76 return; 77 } 78 79 if (offline) { 80 ndlp->nlp_tics[channelno] = hba->timer_tics + timeout; 81 ndlp->nlp_flag[channelno] |= NLP_OFFLINE; 82 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 83 84 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg, 85 "node=%p did=%06x channel=%d. offline=%d set.", 86 ndlp, ndlp->nlp_DID, channelno, timeout); 87 88 } else if (timeout) { 89 ndlp->nlp_tics[channelno] = hba->timer_tics + timeout; 90 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 91 92 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg, 93 "node=%p did=%06x channel=%d. timeout=%d set.", 94 ndlp, ndlp->nlp_DID, channelno, timeout); 95 } else { 96 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 97 } 98 99 return; 100 } 101 102 /* Set the node closed */ 103 ndlp->nlp_flag[channelno] |= NLP_CLOSED; 104 105 if (offline) { 106 ndlp->nlp_tics[channelno] = hba->timer_tics + timeout; 107 ndlp->nlp_flag[channelno] |= NLP_OFFLINE; 108 109 } else if (timeout) { 110 ndlp->nlp_tics[channelno] = hba->timer_tics + timeout; 111 } 112 113 114 /* 115 * ndlp->nlp_next[] and cp->nodeq list have to be updated 116 * simulaneously 117 */ 118 if (ndlp->nlp_next[channelno]) { 119 /* Remove node from channel queue */ 120 cp = &hba->chan[channelno]; 121 122 /* If this is the only node on list */ 123 if (cp->nodeq.q_first == (void *)ndlp && 124 cp->nodeq.q_last == (void *)ndlp) { 125 cp->nodeq.q_last = NULL; 126 cp->nodeq.q_first = NULL; 127 cp->nodeq.q_cnt = 0; 128 } else if (cp->nodeq.q_first == (void *)ndlp) { 129 cp->nodeq.q_first = ndlp->nlp_next[channelno]; 130 ((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] = 131 cp->nodeq.q_first; 132 cp->nodeq.q_cnt--; 133 } else { /* This is a little more difficult */ 134 135 /* Find the previous node in circular channel queue */ 136 prev = ndlp; 137 while (prev->nlp_next[channelno] != ndlp) { 138 prev = prev->nlp_next[channelno]; 139 } 140 141 prev->nlp_next[channelno] = ndlp->nlp_next[channelno]; 142 143 if (cp->nodeq.q_last == (void *)ndlp) { 144 cp->nodeq.q_last = (void *)prev; 145 } 146 cp->nodeq.q_cnt--; 147 148 } 149 150 /* Clear node */ 151 ndlp->nlp_next[channelno] = NULL; 152 } 153 154 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 155 156 return; 157 158 } /* emlxs_node_close() */ 159 160 161 /* Called by emlxs_timer_check_nodes() */ 162 extern void 163 emlxs_node_timeout(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno) 164 { 165 emlxs_hba_t *hba = HBA; 166 167 /* If node needs servicing, then add it to the channel queues */ 168 mutex_enter(&EMLXS_TX_CHANNEL_LOCK); 169 170 /* Return if node destroyed */ 171 if (!ndlp || !ndlp->nlp_active) { 172 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 173 return; 174 } 175 176 /* Open the node if not offline */ 177 if (!(ndlp->nlp_flag[channelno] & NLP_OFFLINE)) { 178 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 179 180 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg, 181 "node=%p did=%06x channel=%d Opening.", ndlp, ndlp->nlp_DID, 182 channelno); 183 184 emlxs_node_open(port, ndlp, channelno); 185 return; 186 } 187 188 /* OFFLINE TIMEOUT OCCURRED! */ 189 190 /* Clear the timer */ 191 ndlp->nlp_tics[channelno] = 0; 192 193 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 194 195 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg, 196 "node=%p did=%06x %s. Flushing.", ndlp, ndlp->nlp_DID, 197 channelno); 198 199 /* Flush tx queue for this channel */ 200 (void) emlxs_tx_node_flush(port, ndlp, &hba->chan[channelno], 0, 0); 201 202 /* Flush chip queue for this channel */ 203 (void) emlxs_chipq_node_flush(port, &hba->chan[channelno], ndlp, 0); 204 205 return; 206 207 } /* emlxs_node_timeout() */ 208 209 210 extern void 211 emlxs_node_open(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno) 212 { 213 emlxs_hba_t *hba = HBA; 214 CHANNEL *cp; 215 uint32_t found; 216 NODELIST *nlp; 217 MAILBOXQ *mbox; 218 uint32_t i; 219 int rc; 220 221 /* If node needs servicing, then add it to the channel queues */ 222 mutex_enter(&EMLXS_TX_CHANNEL_LOCK); 223 224 /* Return if node destroyed */ 225 if (!ndlp || !ndlp->nlp_active) { 226 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 227 228 return; 229 } 230 231 /* Return if node already open */ 232 if (!(ndlp->nlp_flag[channelno] & NLP_CLOSED)) { 233 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 234 235 return; 236 } 237 238 /* Set the node open (not closed) */ 239 ndlp->nlp_flag[channelno] &= ~(NLP_CLOSED|NLP_OFFLINE); 240 241 /* Clear the timer */ 242 ndlp->nlp_tics[channelno] = 0; 243 244 /* 245 * If the ptx or the tx queue needs servicing and 246 * the node is not already on the channel queue 247 */ 248 if ((ndlp->nlp_ptx[channelno].q_first || 249 ndlp->nlp_tx[channelno].q_first) && !ndlp->nlp_next[channelno]) { 250 cp = &hba->chan[channelno]; 251 252 /* If so, then add it to the channel queue */ 253 if (cp->nodeq.q_first) { 254 ((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] = 255 (uint8_t *)ndlp; 256 ndlp->nlp_next[channelno] = cp->nodeq.q_first; 257 258 /* If this is not the base node then */ 259 /* add it to the tail */ 260 if (!ndlp->nlp_base) { 261 cp->nodeq.q_last = (uint8_t *)ndlp; 262 } else { /* Otherwise, add it to the head */ 263 264 /* The command node always gets priority */ 265 cp->nodeq.q_first = (uint8_t *)ndlp; 266 } 267 268 cp->nodeq.q_cnt++; 269 } else { 270 cp->nodeq.q_first = (uint8_t *)ndlp; 271 cp->nodeq.q_last = (uint8_t *)ndlp; 272 ndlp->nlp_next[channelno] = ndlp; 273 cp->nodeq.q_cnt = 1; 274 } 275 } 276 277 mutex_exit(&EMLXS_TX_CHANNEL_LOCK); 278 279 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_opened_msg, 280 "node=%p did=%06x channel=%d", ndlp, ndlp->nlp_DID, channelno); 281 282 /* If link attention needs to be cleared */ 283 if ((hba->state == FC_LINK_UP) && (channelno == hba->channel_fcp)) { 284 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { 285 /* re Think this code path. For SLI4 channel fcp == els */ 286 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, 287 "ADD CODE to RESUME RPIs node=%p did=%06x chan=%d", 288 ndlp, ndlp->nlp_DID, channelno); 289 290 goto done; 291 } 292 293 /* Scan to see if any FCP2 devices are still closed */ 294 found = 0; 295 rw_enter(&port->node_rwlock, RW_READER); 296 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 297 nlp = port->node_table[i]; 298 while (nlp != NULL) { 299 if ((nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && 300 (nlp->nlp_flag[hba->channel_fcp] & 301 NLP_CLOSED)) { 302 found = 1; 303 break; 304 305 } 306 nlp = nlp->nlp_list_next; 307 } 308 309 if (found) { 310 break; 311 } 312 } 313 314 rw_exit(&port->node_rwlock); 315 316 if (!found) { 317 /* Clear link attention */ 318 if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba, 319 MEM_MBOX, 1))) { 320 mutex_enter(&EMLXS_PORT_LOCK); 321 322 /* 323 * If state is not FC_LINK_UP, then either the 324 * link has gone down or a FC_CLEAR_LA has 325 * already been issued 326 */ 327 if (hba->state != FC_LINK_UP) { 328 mutex_exit(&EMLXS_PORT_LOCK); 329 (void) emlxs_mem_put(hba, MEM_MBOX, 330 (uint8_t *)mbox); 331 goto done; 332 } 333 334 EMLXS_STATE_CHANGE_LOCKED(hba, FC_CLEAR_LA); 335 hba->discovery_timer = 0; 336 mutex_exit(&EMLXS_PORT_LOCK); 337 338 emlxs_mb_clear_la(hba, mbox); 339 340 rc = EMLXS_SLI_ISSUE_MBOX_CMD(hba, 341 mbox, MBX_NOWAIT, 0); 342 if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { 343 (void) emlxs_mem_put(hba, MEM_MBOX, 344 (uint8_t *)mbox); 345 } 346 } else { 347 /* Close the node and try again */ 348 /* in a few seconds */ 349 emlxs_node_close(port, ndlp, channelno, 5); 350 return; 351 } 352 } 353 } 354 355 done: 356 357 /* Wake any sleeping threads */ 358 mutex_enter(&EMLXS_PKT_LOCK); 359 cv_broadcast(&EMLXS_PKT_CV); 360 mutex_exit(&EMLXS_PKT_LOCK); 361 362 return; 363 364 } /* emlxs_node_open() */ 365 366 367 static int 368 emlxs_node_match_did(emlxs_port_t *port, NODELIST *ndlp, uint32_t did) 369 { 370 D_ID mydid; 371 D_ID odid; 372 D_ID ndid; 373 374 if (ndlp->nlp_DID == did) 375 return (1); 376 377 /* 378 * Next check for area/domain == 0 match 379 */ 380 mydid.un.word = port->did; 381 if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) { 382 goto out; 383 } 384 385 ndid.un.word = did; 386 odid.un.word = ndlp->nlp_DID; 387 if (ndid.un.b.id == odid.un.b.id) { 388 if ((mydid.un.b.domain == ndid.un.b.domain) && 389 (mydid.un.b.area == ndid.un.b.area)) { 390 ndid.un.word = ndlp->nlp_DID; 391 odid.un.word = did; 392 if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) { 393 return (1); 394 } 395 goto out; 396 } 397 398 ndid.un.word = ndlp->nlp_DID; 399 if ((mydid.un.b.domain == ndid.un.b.domain) && 400 (mydid.un.b.area == ndid.un.b.area)) { 401 odid.un.word = ndlp->nlp_DID; 402 ndid.un.word = did; 403 if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) { 404 return (1); 405 } 406 } 407 } 408 409 out: 410 411 return (0); 412 413 } /* End emlxs_node_match_did */ 414 415 416 417 extern NODELIST * 418 emlxs_node_find_mac(emlxs_port_t *port, uint8_t *mac) 419 { 420 NODELIST *nlp; 421 uint32_t i; 422 423 rw_enter(&port->node_rwlock, RW_READER); 424 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 425 nlp = port->node_table[i]; 426 while (nlp != NULL) { 427 /* 428 * If portname matches mac address, 429 * return NODELIST entry 430 */ 431 if ((nlp->nlp_portname.IEEE[0] == mac[0])) { 432 if ((nlp->nlp_DID != BCAST_DID) && 433 ((nlp->nlp_DID & FABRIC_DID_MASK) == 434 FABRIC_DID_MASK)) { 435 nlp = (NODELIST *)nlp->nlp_list_next; 436 continue; 437 } 438 439 if ((nlp->nlp_portname.IEEE[1] == mac[1]) && 440 (nlp->nlp_portname.IEEE[2] == mac[2]) && 441 (nlp->nlp_portname.IEEE[3] == mac[3]) && 442 (nlp->nlp_portname.IEEE[4] == mac[4]) && 443 (nlp->nlp_portname.IEEE[5] == mac[5])) { 444 rw_exit(&port->node_rwlock); 445 return (nlp); 446 } 447 448 } 449 450 nlp = (NODELIST *)nlp->nlp_list_next; 451 } 452 } 453 rw_exit(&port->node_rwlock); 454 455 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, 456 "find: MAC=%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], 457 mac[3], mac[4], mac[5]); 458 459 return (NULL); 460 461 } /* emlxs_node_find_mac() */ 462 463 464 extern NODELIST * 465 emlxs_node_find_did(emlxs_port_t *port, uint32_t did) 466 { 467 emlxs_hba_t *hba = HBA; 468 NODELIST *nlp; 469 uint32_t hash; 470 471 /* Check for invalid node ids */ 472 if ((did == 0) && (!(hba->flag & FC_LOOPBACK_MODE))) { 473 return ((NODELIST *)0); 474 } 475 476 if (did & 0xff000000) { 477 return ((NODELIST *)0); 478 } 479 480 /* Check for bcast node */ 481 if (did == BCAST_DID) { 482 /* Use the base node here */ 483 return (&port->node_base); 484 } 485 #ifdef MENLO_SUPPORT 486 /* Check for menlo node */ 487 if (did == EMLXS_MENLO_DID) { 488 /* Use the base node here */ 489 return (&port->node_base); 490 } 491 #endif /* MENLO_SUPPORT */ 492 493 /* Check for host node */ 494 if (did == port->did && !(hba->flag & FC_LOOPBACK_MODE)) { 495 /* Use the base node here */ 496 return (&port->node_base); 497 } 498 499 /* 500 * Convert well known fabric addresses to the FABRIC_DID, 501 * since we don't login to some of them 502 */ 503 if ((did == SCR_DID)) { 504 did = FABRIC_DID; 505 } 506 507 rw_enter(&port->node_rwlock, RW_READER); 508 hash = EMLXS_DID_HASH(did); 509 nlp = port->node_table[hash]; 510 while (nlp != NULL) { 511 /* Check for obvious match */ 512 if (nlp->nlp_DID == did) { 513 rw_exit(&port->node_rwlock); 514 return (nlp); 515 } 516 517 /* Check for detailed match */ 518 else if (emlxs_node_match_did(port, nlp, did)) { 519 rw_exit(&port->node_rwlock); 520 return (nlp); 521 } 522 523 nlp = (NODELIST *)nlp->nlp_list_next; 524 } 525 rw_exit(&port->node_rwlock); 526 527 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: did=%x", 528 did); 529 530 /* no match found */ 531 return ((NODELIST *)0); 532 533 } /* emlxs_node_find_did() */ 534 535 536 extern NODELIST * 537 emlxs_node_find_rpi(emlxs_port_t *port, uint32_t rpi) 538 { 539 NODELIST *nlp; 540 uint32_t i; 541 542 rw_enter(&port->node_rwlock, RW_READER); 543 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 544 nlp = port->node_table[i]; 545 while (nlp != NULL) { 546 if (nlp->nlp_Rpi == rpi) { 547 rw_exit(&port->node_rwlock); 548 return (nlp); 549 } 550 551 nlp = (NODELIST *)nlp->nlp_list_next; 552 } 553 } 554 rw_exit(&port->node_rwlock); 555 556 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: rpi=%x", 557 rpi); 558 559 /* no match found */ 560 return ((NODELIST *)0); 561 562 } /* emlxs_node_find_rpi() */ 563 564 565 extern NODELIST * 566 emlxs_node_find_wwpn(emlxs_port_t *port, uint8_t *wwpn) 567 { 568 NODELIST *nlp; 569 uint32_t i; 570 uint32_t j; 571 uint8_t *bptr1; 572 uint8_t *bptr2; 573 574 rw_enter(&port->node_rwlock, RW_READER); 575 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 576 nlp = port->node_table[i]; 577 while (nlp != NULL) { 578 bptr1 = (uint8_t *)&nlp->nlp_portname; 579 bptr1 += 7; 580 bptr2 = (uint8_t *)wwpn; 581 bptr2 += 7; 582 583 for (j = 0; j < 8; j++) { 584 if (*bptr1-- != *bptr2--) { 585 break; 586 } 587 } 588 589 if (j == 8) { 590 rw_exit(&port->node_rwlock); 591 return (nlp); 592 } 593 594 nlp = (NODELIST *)nlp->nlp_list_next; 595 } 596 } 597 rw_exit(&port->node_rwlock); 598 599 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, 600 "find: wwpn=%02x%02x%02x%02x%02x%02x%02x%02x", wwpn[0], wwpn[1], 601 wwpn[2], wwpn[3], wwpn[4], wwpn[5], wwpn[6], wwpn[7]); 602 603 /* no match found */ 604 return ((NODELIST *)0); 605 606 } /* emlxs_node_find_wwpn() */ 607 608 609 extern NODELIST * 610 emlxs_node_find_index(emlxs_port_t *port, uint32_t index, 611 uint32_t nports_only) 612 { 613 NODELIST *nlp; 614 uint32_t i; 615 uint32_t count; 616 617 rw_enter(&port->node_rwlock, RW_READER); 618 619 if (index > port->node_count - 1) { 620 rw_exit(&port->node_rwlock); 621 return (NULL); 622 } 623 624 count = 0; 625 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 626 nlp = port->node_table[i]; 627 while (nlp != NULL) { 628 /* Skip fabric ports if requested */ 629 if (nports_only && 630 (nlp->nlp_DID & 0xFFF000) == 0xFFF000) { 631 nlp = (NODELIST *)nlp->nlp_list_next; 632 continue; 633 } 634 635 if (count == index) { 636 rw_exit(&port->node_rwlock); 637 return (nlp); 638 } 639 640 nlp = (NODELIST *)nlp->nlp_list_next; 641 count++; 642 } 643 } 644 rw_exit(&port->node_rwlock); 645 646 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: index=%d", 647 index); 648 649 /* no match found */ 650 return ((NODELIST *)0); 651 652 } /* emlxs_node_find_wwpn() */ 653 654 655 extern uint32_t 656 emlxs_nport_count(emlxs_port_t *port) 657 { 658 NODELIST *nlp; 659 uint32_t i; 660 uint32_t nport_count = 0; 661 662 rw_enter(&port->node_rwlock, RW_READER); 663 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 664 nlp = port->node_table[i]; 665 while (nlp != NULL) { 666 if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) { 667 nport_count++; 668 } 669 670 nlp = (NODELIST *)nlp->nlp_list_next; 671 } 672 } 673 rw_exit(&port->node_rwlock); 674 675 return (nport_count); 676 677 } /* emlxs_nport_count() */ 678 679 680 681 extern void 682 emlxs_node_destroy_all(emlxs_port_t *port) 683 { 684 emlxs_hba_t *hba = HBA; 685 NODELIST *next; 686 NODELIST *ndlp; 687 RPIobj_t *rp; 688 uint8_t *wwn; 689 uint32_t i; 690 691 /* Flush and free the nodes */ 692 rw_enter(&port->node_rwlock, RW_WRITER); 693 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 694 ndlp = port->node_table[i]; 695 port->node_table[i] = 0; 696 while (ndlp != NULL) { 697 next = ndlp->nlp_list_next; 698 ndlp->nlp_list_next = NULL; 699 ndlp->nlp_list_prev = NULL; 700 ndlp->nlp_active = 0; 701 702 if (port->node_count) { 703 port->node_count--; 704 } 705 706 wwn = (uint8_t *)&ndlp->nlp_portname; 707 EMLXS_MSGF(EMLXS_CONTEXT, 708 &emlxs_node_destroy_msg, "did=%06x " 709 "rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x " 710 "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], 711 wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], 712 wwn[7], port->node_count); 713 714 (void) emlxs_tx_node_flush(port, ndlp, 0, 0, 0); 715 716 /* Break Node/RPI binding */ 717 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { 718 rp = EMLXS_NODE_TO_RPI(hba, ndlp); 719 ndlp->RPIp = NULL; 720 721 if (rp) { 722 rp->node = NULL; 723 (void) emlxs_sli4_free_rpi(hba, rp); 724 } 725 } 726 727 (void) emlxs_mem_put(hba, MEM_NLP, (uint8_t *)ndlp); 728 729 ndlp = next; 730 } 731 } 732 port->node_count = 0; 733 rw_exit(&port->node_rwlock); 734 735 /* Clean the base node */ 736 mutex_enter(&EMLXS_PORT_LOCK); 737 port->node_base.nlp_list_next = NULL; 738 port->node_base.nlp_list_prev = NULL; 739 port->node_base.nlp_active = 1; 740 mutex_exit(&EMLXS_PORT_LOCK); 741 742 /* Flush the base node */ 743 (void) emlxs_tx_node_flush(port, &port->node_base, 0, 1, 0); 744 (void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0); 745 746 return; 747 748 } /* emlxs_node_destroy_all() */ 749 750 751 extern void 752 emlxs_node_add(emlxs_port_t *port, NODELIST *ndlp) 753 { 754 emlxs_hba_t *hba = HBA; 755 NODELIST *np; 756 uint8_t *wwn; 757 uint32_t hash; 758 RPIobj_t *rp; 759 760 rw_enter(&port->node_rwlock, RW_WRITER); 761 hash = EMLXS_DID_HASH(ndlp->nlp_DID); 762 np = port->node_table[hash]; 763 764 /* 765 * Insert node pointer to the head 766 */ 767 port->node_table[hash] = ndlp; 768 if (!np) { 769 ndlp->nlp_list_next = NULL; 770 } else { 771 ndlp->nlp_list_next = np; 772 } 773 port->node_count++; 774 775 wwn = (uint8_t *)&ndlp->nlp_portname; 776 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_msg, 777 "node=%p did=%06x rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x " 778 "count=%d", ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], wwn[1], 779 wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7], port->node_count); 780 781 /* Add Node/RPI binding */ 782 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { 783 rp = emlxs_sli4_find_rpi(hba, ndlp->nlp_Rpi); 784 785 if (rp) { 786 rp->node = ndlp; 787 ndlp->RPIp = rp; 788 } else { 789 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_msg, 790 "Unable to find RPI! did=%x rpi=%x", 791 ndlp->nlp_DID, ndlp->nlp_Rpi); 792 } 793 } 794 795 rw_exit(&port->node_rwlock); 796 797 return; 798 799 } /* emlxs_node_add() */ 800 801 802 extern void 803 emlxs_node_rm(emlxs_port_t *port, NODELIST *ndlp) 804 { 805 emlxs_hba_t *hba = HBA; 806 NODELIST *np; 807 NODELIST *prevp; 808 RPIobj_t *rp; 809 uint8_t *wwn; 810 uint32_t hash; 811 812 rw_enter(&port->node_rwlock, RW_WRITER); 813 hash = EMLXS_DID_HASH(ndlp->nlp_DID); 814 np = port->node_table[hash]; 815 prevp = NULL; 816 while (np != NULL) { 817 if (np->nlp_DID == ndlp->nlp_DID) { 818 if (prevp == NULL) { 819 port->node_table[hash] = np->nlp_list_next; 820 } else { 821 prevp->nlp_list_next = np->nlp_list_next; 822 } 823 824 if (port->node_count) { 825 port->node_count--; 826 } 827 828 wwn = (uint8_t *)&ndlp->nlp_portname; 829 EMLXS_MSGF(EMLXS_CONTEXT, 830 &emlxs_node_destroy_msg, "did=%06x " 831 "rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x " 832 "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], 833 wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], 834 wwn[7], port->node_count); 835 836 (void) emlxs_tx_node_flush(port, ndlp, 0, 1, 0); 837 838 ndlp->nlp_active = 0; 839 840 /* Break Node/RPI binding */ 841 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { 842 rp = EMLXS_NODE_TO_RPI(hba, ndlp); 843 ndlp->RPIp = NULL; 844 845 if (rp) { 846 rp->node = NULL; 847 (void) emlxs_sli4_free_rpi(hba, rp); 848 } 849 } 850 851 (void) emlxs_mem_put(hba, MEM_NLP, (uint8_t *)ndlp); 852 853 break; 854 } 855 prevp = np; 856 np = np->nlp_list_next; 857 } 858 rw_exit(&port->node_rwlock); 859 860 return; 861 862 } /* emlxs_node_rm() */ 863