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