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 2010 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 channel=%d. 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 rpi=%x channel=%d", ndlp, ndlp->nlp_DID, 293 ndlp->nlp_Rpi, channelno); 294 295 /* If link attention needs to be cleared */ 296 if ((hba->state == FC_LINK_UP) && (channelno == hba->channel_fcp)) { 297 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { 298 goto done; 299 } 300 301 /* Scan to see if any FCP2 devices are still closed */ 302 found = 0; 303 rw_enter(&port->node_rwlock, RW_READER); 304 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 305 nlp = port->node_table[i]; 306 while (nlp != NULL) { 307 if ((nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && 308 (nlp->nlp_flag[hba->channel_fcp] & 309 NLP_CLOSED)) { 310 found = 1; 311 break; 312 313 } 314 nlp = nlp->nlp_list_next; 315 } 316 317 if (found) { 318 break; 319 } 320 } 321 322 rw_exit(&port->node_rwlock); 323 324 if (!found) { 325 /* Clear link attention */ 326 if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba, 327 MEM_MBOX, 1))) { 328 mutex_enter(&EMLXS_PORT_LOCK); 329 330 /* 331 * If state is not FC_LINK_UP, then either the 332 * link has gone down or a FC_CLEAR_LA has 333 * already been issued 334 */ 335 if (hba->state != FC_LINK_UP) { 336 mutex_exit(&EMLXS_PORT_LOCK); 337 emlxs_mem_put(hba, MEM_MBOX, 338 (void *)mbox); 339 goto done; 340 } 341 342 EMLXS_STATE_CHANGE_LOCKED(hba, FC_CLEAR_LA); 343 hba->discovery_timer = 0; 344 mutex_exit(&EMLXS_PORT_LOCK); 345 346 emlxs_mb_clear_la(hba, mbox); 347 348 rc = EMLXS_SLI_ISSUE_MBOX_CMD(hba, 349 mbox, MBX_NOWAIT, 0); 350 if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { 351 emlxs_mem_put(hba, MEM_MBOX, 352 (void *)mbox); 353 } 354 } else { 355 /* Close the node and try again */ 356 /* in a few seconds */ 357 emlxs_node_close(port, ndlp, channelno, 5); 358 return; 359 } 360 } 361 } 362 363 done: 364 365 /* Wake any sleeping threads */ 366 mutex_enter(&EMLXS_PKT_LOCK); 367 cv_broadcast(&EMLXS_PKT_CV); 368 mutex_exit(&EMLXS_PKT_LOCK); 369 370 return; 371 372 } /* emlxs_node_open() */ 373 374 375 static int 376 emlxs_node_match_did(emlxs_port_t *port, NODELIST *ndlp, uint32_t did) 377 { 378 D_ID mydid; 379 D_ID odid; 380 D_ID ndid; 381 382 if (ndlp->nlp_DID == did) 383 return (1); 384 385 /* 386 * Next check for area/domain == 0 match 387 */ 388 mydid.un.word = port->did; 389 if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) { 390 goto out; 391 } 392 393 ndid.un.word = did; 394 odid.un.word = ndlp->nlp_DID; 395 if (ndid.un.b.id == odid.un.b.id) { 396 if ((mydid.un.b.domain == ndid.un.b.domain) && 397 (mydid.un.b.area == ndid.un.b.area)) { 398 ndid.un.word = ndlp->nlp_DID; 399 odid.un.word = did; 400 if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) { 401 return (1); 402 } 403 goto out; 404 } 405 406 ndid.un.word = ndlp->nlp_DID; 407 if ((mydid.un.b.domain == ndid.un.b.domain) && 408 (mydid.un.b.area == ndid.un.b.area)) { 409 odid.un.word = ndlp->nlp_DID; 410 ndid.un.word = did; 411 if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) { 412 return (1); 413 } 414 } 415 } 416 417 out: 418 419 return (0); 420 421 } /* End emlxs_node_match_did */ 422 423 424 425 extern NODELIST * 426 emlxs_node_find_mac(emlxs_port_t *port, uint8_t *mac) 427 { 428 NODELIST *nlp; 429 uint32_t i; 430 431 rw_enter(&port->node_rwlock, RW_READER); 432 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 433 nlp = port->node_table[i]; 434 while (nlp != NULL) { 435 /* 436 * If portname matches mac address, 437 * return NODELIST entry 438 */ 439 if ((nlp->nlp_portname.IEEE[0] == mac[0])) { 440 if ((nlp->nlp_DID != BCAST_DID) && 441 ((nlp->nlp_DID & FABRIC_DID_MASK) == 442 FABRIC_DID_MASK)) { 443 nlp = (NODELIST *)nlp->nlp_list_next; 444 continue; 445 } 446 447 if ((nlp->nlp_portname.IEEE[1] == mac[1]) && 448 (nlp->nlp_portname.IEEE[2] == mac[2]) && 449 (nlp->nlp_portname.IEEE[3] == mac[3]) && 450 (nlp->nlp_portname.IEEE[4] == mac[4]) && 451 (nlp->nlp_portname.IEEE[5] == mac[5])) { 452 rw_exit(&port->node_rwlock); 453 return (nlp); 454 } 455 456 } 457 458 nlp = (NODELIST *)nlp->nlp_list_next; 459 } 460 } 461 rw_exit(&port->node_rwlock); 462 463 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, 464 "find: MAC=%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], 465 mac[3], mac[4], mac[5]); 466 467 return (NULL); 468 469 } /* emlxs_node_find_mac() */ 470 471 472 extern NODELIST * 473 emlxs_node_find_did(emlxs_port_t *port, uint32_t did) 474 { 475 emlxs_hba_t *hba = HBA; 476 NODELIST *nlp; 477 uint32_t hash; 478 479 /* Check for invalid node ids */ 480 if ((did == 0) && (!(hba->flag & FC_LOOPBACK_MODE))) { 481 return ((NODELIST *)0); 482 } 483 484 if (did & 0xff000000) { 485 return ((NODELIST *)0); 486 } 487 488 /* Check for bcast node */ 489 if (did == BCAST_DID) { 490 /* Use the base node here */ 491 return (&port->node_base); 492 } 493 #ifdef MENLO_SUPPORT 494 /* Check for menlo node */ 495 if (did == EMLXS_MENLO_DID) { 496 /* Use the base node here */ 497 return (&port->node_base); 498 } 499 #endif /* MENLO_SUPPORT */ 500 501 /* Check for host node */ 502 if (did == port->did && !(hba->flag & FC_LOOPBACK_MODE)) { 503 /* Use the base node here */ 504 return (&port->node_base); 505 } 506 507 /* 508 * Convert well known fabric addresses to the FABRIC_DID, 509 * since we don't login to some of them 510 */ 511 if ((did == SCR_DID)) { 512 did = FABRIC_DID; 513 } 514 515 rw_enter(&port->node_rwlock, RW_READER); 516 hash = EMLXS_DID_HASH(did); 517 nlp = port->node_table[hash]; 518 while (nlp != NULL) { 519 /* Check for obvious match */ 520 if (nlp->nlp_DID == did) { 521 rw_exit(&port->node_rwlock); 522 return (nlp); 523 } 524 525 /* Check for detailed match */ 526 else if (emlxs_node_match_did(port, nlp, did)) { 527 rw_exit(&port->node_rwlock); 528 return (nlp); 529 } 530 531 nlp = (NODELIST *)nlp->nlp_list_next; 532 } 533 rw_exit(&port->node_rwlock); 534 535 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: did=%x", 536 did); 537 538 /* no match found */ 539 return ((NODELIST *)0); 540 541 } /* emlxs_node_find_did() */ 542 543 544 extern NODELIST * 545 emlxs_node_find_rpi(emlxs_port_t *port, uint32_t rpi) 546 { 547 NODELIST *nlp; 548 uint32_t i; 549 550 rw_enter(&port->node_rwlock, RW_READER); 551 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 552 nlp = port->node_table[i]; 553 while (nlp != NULL) { 554 if (nlp->nlp_Rpi == rpi) { 555 rw_exit(&port->node_rwlock); 556 return (nlp); 557 } 558 559 nlp = (NODELIST *)nlp->nlp_list_next; 560 } 561 } 562 rw_exit(&port->node_rwlock); 563 564 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: rpi=%x", 565 rpi); 566 567 /* no match found */ 568 return ((NODELIST *)0); 569 570 } /* emlxs_node_find_rpi() */ 571 572 573 extern NODELIST * 574 emlxs_node_find_wwpn(emlxs_port_t *port, uint8_t *wwpn) 575 { 576 NODELIST *nlp; 577 uint32_t i; 578 uint32_t j; 579 uint8_t *bptr1; 580 uint8_t *bptr2; 581 582 rw_enter(&port->node_rwlock, RW_READER); 583 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 584 nlp = port->node_table[i]; 585 while (nlp != NULL) { 586 bptr1 = (uint8_t *)&nlp->nlp_portname; 587 bptr1 += 7; 588 bptr2 = (uint8_t *)wwpn; 589 bptr2 += 7; 590 591 for (j = 0; j < 8; j++) { 592 if (*bptr1-- != *bptr2--) { 593 break; 594 } 595 } 596 597 if (j == 8) { 598 rw_exit(&port->node_rwlock); 599 return (nlp); 600 } 601 602 nlp = (NODELIST *)nlp->nlp_list_next; 603 } 604 } 605 rw_exit(&port->node_rwlock); 606 607 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, 608 "find: wwpn=%02x%02x%02x%02x%02x%02x%02x%02x", wwpn[0], wwpn[1], 609 wwpn[2], wwpn[3], wwpn[4], wwpn[5], wwpn[6], wwpn[7]); 610 611 /* no match found */ 612 return ((NODELIST *)0); 613 614 } /* emlxs_node_find_wwpn() */ 615 616 617 extern NODELIST * 618 emlxs_node_find_index(emlxs_port_t *port, uint32_t index, 619 uint32_t nports_only) 620 { 621 NODELIST *nlp; 622 uint32_t i; 623 uint32_t count; 624 625 rw_enter(&port->node_rwlock, RW_READER); 626 627 if (index > port->node_count - 1) { 628 rw_exit(&port->node_rwlock); 629 return (NULL); 630 } 631 632 count = 0; 633 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 634 nlp = port->node_table[i]; 635 while (nlp != NULL) { 636 /* Skip fabric ports if requested */ 637 if (nports_only && 638 (nlp->nlp_DID & 0xFFF000) == 0xFFF000) { 639 nlp = (NODELIST *)nlp->nlp_list_next; 640 continue; 641 } 642 643 if (count == index) { 644 rw_exit(&port->node_rwlock); 645 return (nlp); 646 } 647 648 nlp = (NODELIST *)nlp->nlp_list_next; 649 count++; 650 } 651 } 652 rw_exit(&port->node_rwlock); 653 654 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: index=%d", 655 index); 656 657 /* no match found */ 658 return ((NODELIST *)0); 659 660 } /* emlxs_node_find_index() */ 661 662 663 extern uint32_t 664 emlxs_nport_count(emlxs_port_t *port) 665 { 666 NODELIST *nlp; 667 uint32_t i; 668 uint32_t nport_count = 0; 669 670 rw_enter(&port->node_rwlock, RW_READER); 671 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 672 nlp = port->node_table[i]; 673 while (nlp != NULL) { 674 if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) { 675 nport_count++; 676 } 677 678 nlp = (NODELIST *)nlp->nlp_list_next; 679 } 680 } 681 rw_exit(&port->node_rwlock); 682 683 return (nport_count); 684 685 } /* emlxs_nport_count() */ 686 687 688 689 extern void 690 emlxs_node_destroy_all(emlxs_port_t *port) 691 { 692 emlxs_hba_t *hba = HBA; 693 NODELIST *next; 694 NODELIST *ndlp; 695 RPIobj_t *rpip; 696 uint8_t *wwn; 697 uint32_t i; 698 699 /* Flush and free the nodes */ 700 rw_enter(&port->node_rwlock, RW_WRITER); 701 for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 702 ndlp = port->node_table[i]; 703 port->node_table[i] = 0; 704 while (ndlp != NULL) { 705 next = ndlp->nlp_list_next; 706 ndlp->nlp_list_next = NULL; 707 ndlp->nlp_list_prev = NULL; 708 ndlp->nlp_active = 0; 709 710 if (port->node_count) { 711 port->node_count--; 712 } 713 714 wwn = (uint8_t *)&ndlp->nlp_portname; 715 EMLXS_MSGF(EMLXS_CONTEXT, 716 &emlxs_node_destroy_msg, "did=%06x " 717 "rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x " 718 "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], 719 wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], 720 wwn[7], port->node_count); 721 722 (void) emlxs_tx_node_flush(port, ndlp, 0, 0, 0); 723 724 /* Break Node/RPI binding */ 725 if (ndlp->rpip) { 726 rpip = ndlp->rpip; 727 728 ndlp->rpip = NULL; 729 rpip->node = NULL; 730 731 (void) emlxs_rpi_free_notify(port, rpip); 732 } 733 734 emlxs_mem_put(hba, MEM_NLP, (void *)ndlp); 735 736 ndlp = next; 737 } 738 } 739 port->node_count = 0; 740 rw_exit(&port->node_rwlock); 741 742 /* Clean the base node */ 743 mutex_enter(&EMLXS_PORT_LOCK); 744 port->node_base.nlp_list_next = NULL; 745 port->node_base.nlp_list_prev = NULL; 746 port->node_base.nlp_active = 1; 747 mutex_exit(&EMLXS_PORT_LOCK); 748 749 /* Flush the base node */ 750 (void) emlxs_tx_node_flush(port, &port->node_base, 0, 1, 0); 751 (void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0); 752 753 return; 754 755 } /* emlxs_node_destroy_all() */ 756 757 758 extern NODELIST * 759 emlxs_node_create(emlxs_port_t *port, uint32_t did, uint32_t rpi, SERV_PARM *sp) 760 { 761 emlxs_hba_t *hba = HBA; 762 NODELIST *ndlp; 763 uint8_t *wwn; 764 emlxs_vvl_fmt_t vvl; 765 RPIobj_t *rpip; 766 767 ndlp = emlxs_node_find_did(port, did); 768 769 /* Update the node */ 770 if (ndlp) { 771 rw_enter(&port->node_rwlock, RW_WRITER); 772 773 ndlp->nlp_Rpi = (uint16_t)rpi; 774 ndlp->nlp_DID = did; 775 776 bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm, 777 sizeof (SERV_PARM)); 778 779 bcopy((uint8_t *)&sp->nodeName, 780 (uint8_t *)&ndlp->nlp_nodename, 781 sizeof (NAME_TYPE)); 782 783 bcopy((uint8_t *)&sp->portName, 784 (uint8_t *)&ndlp->nlp_portname, 785 sizeof (NAME_TYPE)); 786 787 /* Add Node/RPI binding */ 788 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { 789 rpip = emlxs_rpi_find(port, rpi); 790 791 if (rpip) { 792 rpip->node = ndlp; 793 ndlp->rpip = rpip; 794 } else { 795 ndlp->rpip = NULL; 796 797 EMLXS_MSGF(EMLXS_CONTEXT, 798 &emlxs_node_create_msg, 799 "Unable to find RPI. did=%x rpi=%x", 800 did, rpi); 801 } 802 } else { 803 ndlp->rpip = NULL; 804 } 805 rw_exit(&port->node_rwlock); 806 807 wwn = (uint8_t *)&ndlp->nlp_portname; 808 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_update_msg, 809 "node=%p did=%06x rpi=%x " 810 "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x", 811 ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], 812 wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 813 814 goto done; 815 } 816 817 /* Allocate a new node */ 818 ndlp = (NODELIST *)emlxs_mem_get(hba, MEM_NLP, 0); 819 820 if (ndlp) { 821 rw_enter(&port->node_rwlock, RW_WRITER); 822 823 ndlp->nlp_Rpi = (uint16_t)rpi; 824 ndlp->nlp_DID = did; 825 826 bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm, 827 sizeof (SERV_PARM)); 828 829 bcopy((uint8_t *)&sp->nodeName, 830 (uint8_t *)&ndlp->nlp_nodename, 831 sizeof (NAME_TYPE)); 832 833 bcopy((uint8_t *)&sp->portName, 834 (uint8_t *)&ndlp->nlp_portname, 835 sizeof (NAME_TYPE)); 836 837 ndlp->nlp_active = 1; 838 ndlp->nlp_flag[hba->channel_ct] |= NLP_CLOSED; 839 ndlp->nlp_flag[hba->channel_els] |= NLP_CLOSED; 840 ndlp->nlp_flag[hba->channel_fcp] |= NLP_CLOSED; 841 ndlp->nlp_flag[hba->channel_ip] |= NLP_CLOSED; 842 843 /* Add Node/RPI binding */ 844 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { 845 rpip = emlxs_rpi_find(port, rpi); 846 847 if (rpip) { 848 rpip->node = ndlp; 849 ndlp->rpip = rpip; 850 } else { 851 ndlp->rpip = NULL; 852 853 EMLXS_MSGF(EMLXS_CONTEXT, 854 &emlxs_node_create_msg, 855 "Unable to find RPI. did=%x rpi=%x", 856 did, rpi); 857 } 858 } else { 859 ndlp->rpip = NULL; 860 } 861 rw_exit(&port->node_rwlock); 862 863 /* Add the node */ 864 emlxs_node_add(port, ndlp); 865 866 goto done; 867 } 868 869 wwn = (uint8_t *)&sp->portName; 870 EMLXS_MSGF(EMLXS_CONTEXT, 871 &emlxs_node_create_failed_msg, 872 "Unable to allocate node. did=%06x " 873 "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x", 874 did, wwn[0], wwn[1], wwn[2], 875 wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 876 877 return (NULL); 878 879 done: 880 if (sp->VALID_VENDOR_VERSION) { 881 bcopy((caddr_t *)&sp->vendorVersion[0], 882 (caddr_t *)&vvl, sizeof (emlxs_vvl_fmt_t)); 883 884 vvl.un0.word0 = LE_SWAP32(vvl.un0.word0); 885 vvl.un1.word1 = LE_SWAP32(vvl.un1.word1); 886 887 if ((vvl.un0.w0.oui == 0x0000C9) && 888 (vvl.un1.w1.vport)) { 889 ndlp->nlp_fcp_info |= NLP_EMLX_VPORT; 890 } 891 } 892 893 /* Open the node */ 894 emlxs_node_open(port, ndlp, hba->channel_ct); 895 emlxs_node_open(port, ndlp, hba->channel_els); 896 emlxs_node_open(port, ndlp, hba->channel_ip); 897 emlxs_node_open(port, ndlp, hba->channel_fcp); 898 899 return (ndlp); 900 901 } /* emlxs_node_create() */ 902 903 904 extern void 905 emlxs_node_add(emlxs_port_t *port, NODELIST *ndlp) 906 { 907 NODELIST *np; 908 uint8_t *wwn; 909 uint32_t hash; 910 911 rw_enter(&port->node_rwlock, RW_WRITER); 912 hash = EMLXS_DID_HASH(ndlp->nlp_DID); 913 np = port->node_table[hash]; 914 915 /* 916 * Insert node pointer to the head 917 */ 918 port->node_table[hash] = ndlp; 919 if (!np) { 920 ndlp->nlp_list_next = NULL; 921 } else { 922 ndlp->nlp_list_next = np; 923 } 924 port->node_count++; 925 926 wwn = (uint8_t *)&ndlp->nlp_portname; 927 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_msg, 928 "node=%p did=%06x rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x " 929 "count=%d", ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], wwn[1], 930 wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7], port->node_count); 931 932 rw_exit(&port->node_rwlock); 933 934 return; 935 936 } /* emlxs_node_add() */ 937 938 939 extern void 940 emlxs_node_rm(emlxs_port_t *port, NODELIST *ndlp) 941 { 942 emlxs_hba_t *hba = HBA; 943 NODELIST *np; 944 NODELIST *prevp; 945 RPIobj_t *rpip; 946 uint8_t *wwn; 947 uint32_t hash; 948 949 rw_enter(&port->node_rwlock, RW_WRITER); 950 hash = EMLXS_DID_HASH(ndlp->nlp_DID); 951 np = port->node_table[hash]; 952 prevp = NULL; 953 while (np != NULL) { 954 if (np->nlp_DID == ndlp->nlp_DID) { 955 if (prevp == NULL) { 956 port->node_table[hash] = np->nlp_list_next; 957 } else { 958 prevp->nlp_list_next = np->nlp_list_next; 959 } 960 961 if (port->node_count) { 962 port->node_count--; 963 } 964 965 wwn = (uint8_t *)&ndlp->nlp_portname; 966 EMLXS_MSGF(EMLXS_CONTEXT, 967 &emlxs_node_destroy_msg, "did=%06x " 968 "rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x " 969 "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], 970 wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], 971 wwn[7], port->node_count); 972 973 (void) emlxs_tx_node_flush(port, ndlp, 0, 1, 0); 974 975 ndlp->nlp_active = 0; 976 977 /* Break Node/RPI binding */ 978 if (ndlp->rpip) { 979 rpip = ndlp->rpip; 980 981 ndlp->rpip = NULL; 982 rpip->node = NULL; 983 984 (void) emlxs_rpi_free_notify(port, rpip); 985 } 986 987 emlxs_mem_put(hba, MEM_NLP, (void *)ndlp); 988 989 break; 990 } 991 prevp = np; 992 np = np->nlp_list_next; 993 } 994 rw_exit(&port->node_rwlock); 995 996 return; 997 998 } /* emlxs_node_rm() */ 999