1890 Updated emlxs driver from Emulex
[unleashed.git] / usr / src / uts / common / io / fibre-channel / fca / emlxs / emlxs_node.c
blob6da42b02bddc17f284cdf95c644c7c55230ac91c
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Emulex. All rights reserved.
24 * Use is subject to license terms.
28 #include <emlxs.h>
31 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
32 EMLXS_MSG_DEF(EMLXS_NODE_C);
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)
40 emlxs_hba_t *hba = HBA;
41 emlxs_config_t *cfg = &CFG;
42 CHANNEL *cp;
43 NODELIST *prev;
44 uint32_t offline = 0;
47 /* If node is on a channel service queue, then remove it */
48 mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
50 /* Return if node destroyed */
51 if (!ndlp || !ndlp->nlp_active) {
52 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
54 return;
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;
67 if (channelno == hba->channel_ip) {
68 /* Clear IP XRI */
69 ndlp->nlp_Xri = 0;
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;
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);
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);
88 } else if (timeout) {
89 ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
90 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
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);
99 return;
102 /* Set the node closed */
103 ndlp->nlp_flag[channelno] |= NLP_CLOSED;
105 if (offline) {
106 ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
107 ndlp->nlp_flag[channelno] |= NLP_OFFLINE;
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);
113 } else if (timeout) {
114 ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
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);
127 * ndlp->nlp_next[] and cp->nodeq list have to be updated
128 * simulaneously
130 if (ndlp->nlp_next[channelno]) {
131 /* Remove node from channel queue */
132 cp = &hba->chan[channelno];
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 */
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];
153 prev->nlp_next[channelno] = ndlp->nlp_next[channelno];
155 if (cp->nodeq.q_last == (void *)ndlp) {
156 cp->nodeq.q_last = (void *)prev;
158 cp->nodeq.q_cnt--;
162 /* Clear node */
163 ndlp->nlp_next[channelno] = NULL;
166 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
168 return;
170 } /* emlxs_node_close() */
173 /* Called by emlxs_timer_check_nodes() */
174 extern void
175 emlxs_node_timeout(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno)
177 emlxs_hba_t *hba = HBA;
179 /* If node needs servicing, then add it to the channel queues */
180 mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
182 /* Return if node destroyed */
183 if (!ndlp || !ndlp->nlp_active) {
184 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
185 return;
188 /* Open the node if not offline */
189 if (!(ndlp->nlp_flag[channelno] & NLP_OFFLINE)) {
190 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
192 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg,
193 "node=%p did=%06x channel=%d Opening.", ndlp, ndlp->nlp_DID,
194 channelno);
196 emlxs_node_open(port, ndlp, channelno);
197 return;
200 /* OFFLINE TIMEOUT OCCURRED! */
202 /* Clear the timer */
203 ndlp->nlp_tics[channelno] = 0;
205 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
207 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg,
208 "node=%p did=%06x channel=%d. Flushing.", ndlp, ndlp->nlp_DID,
209 channelno);
211 /* Flush tx queue for this channel */
212 (void) emlxs_tx_node_flush(port, ndlp, &hba->chan[channelno], 0, 0);
214 /* Flush chip queue for this channel */
215 (void) emlxs_chipq_node_flush(port, &hba->chan[channelno], ndlp, 0);
217 return;
219 } /* emlxs_node_timeout() */
222 extern void
223 emlxs_node_open(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno)
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;
233 /* If node needs servicing, then add it to the channel queues */
234 mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
236 /* Return if node destroyed */
237 if (!ndlp || !ndlp->nlp_active) {
238 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
240 return;
243 /* Return if node already open */
244 if (!(ndlp->nlp_flag[channelno] & NLP_CLOSED)) {
245 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
247 return;
250 /* Set the node open (not closed) */
251 ndlp->nlp_flag[channelno] &= ~(NLP_CLOSED|NLP_OFFLINE);
253 /* Clear the timer */
254 ndlp->nlp_tics[channelno] = 0;
257 * If the ptx or the tx queue needs servicing and
258 * the node is not already on the channel queue
260 if ((ndlp->nlp_ptx[channelno].q_first ||
261 ndlp->nlp_tx[channelno].q_first) && !ndlp->nlp_next[channelno]) {
262 cp = &hba->chan[channelno];
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;
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 */
276 /* The command node always gets priority */
277 cp->nodeq.q_first = (uint8_t *)ndlp;
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;
289 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
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);
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;
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;
314 nlp = nlp->nlp_list_next;
317 if (found) {
318 break;
322 rw_exit(&port->node_rwlock);
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);
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
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;
342 EMLXS_STATE_CHANGE_LOCKED(hba, FC_CLEAR_LA);
343 hba->discovery_timer = 0;
344 mutex_exit(&EMLXS_PORT_LOCK);
346 emlxs_mb_clear_la(hba, mbox);
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);
354 } else {
355 /* Close the node and try again */
356 /* in a few seconds */
357 emlxs_node_close(port, ndlp, channelno, 5);
358 return;
363 done:
365 /* Wake any sleeping threads */
366 mutex_enter(&EMLXS_PKT_LOCK);
367 cv_broadcast(&EMLXS_PKT_CV);
368 mutex_exit(&EMLXS_PKT_LOCK);
370 return;
372 } /* emlxs_node_open() */
375 static int
376 emlxs_node_match_did(emlxs_port_t *port, NODELIST *ndlp, uint32_t did)
378 D_ID mydid;
379 D_ID odid;
380 D_ID ndid;
382 if (ndlp->nlp_DID == did)
383 return (1);
386 * Next check for area/domain == 0 match
388 mydid.un.word = port->did;
389 if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
390 goto out;
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);
403 goto out;
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);
417 out:
419 return (0);
421 } /* End emlxs_node_match_did */
425 extern NODELIST *
426 emlxs_node_find_mac(emlxs_port_t *port, uint8_t *mac)
428 NODELIST *nlp;
429 uint32_t i;
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) {
436 * If portname matches mac address,
437 * return NODELIST entry
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;
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);
458 nlp = (NODELIST *)nlp->nlp_list_next;
461 rw_exit(&port->node_rwlock);
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]);
467 return (NULL);
469 } /* emlxs_node_find_mac() */
472 extern NODELIST *
473 emlxs_node_find_did(emlxs_port_t *port, uint32_t did)
475 emlxs_hba_t *hba = HBA;
476 NODELIST *nlp;
477 uint32_t hash;
479 /* Check for invalid node ids */
480 if ((did == 0) && (!(hba->flag & FC_LOOPBACK_MODE))) {
481 return ((NODELIST *)0);
484 if (did & 0xff000000) {
485 return ((NODELIST *)0);
488 /* Check for bcast node */
489 if (did == BCAST_DID) {
490 /* Use the base node here */
491 return (&port->node_base);
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);
499 #endif /* MENLO_SUPPORT */
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);
508 * Convert well known fabric addresses to the FABRIC_DID,
509 * since we don't login to some of them
511 if ((did == SCR_DID)) {
512 did = FABRIC_DID;
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);
525 /* Check for detailed match */
526 else if (emlxs_node_match_did(port, nlp, did)) {
527 rw_exit(&port->node_rwlock);
528 return (nlp);
531 nlp = (NODELIST *)nlp->nlp_list_next;
533 rw_exit(&port->node_rwlock);
535 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: did=%x",
536 did);
538 /* no match found */
539 return ((NODELIST *)0);
541 } /* emlxs_node_find_did() */
544 extern NODELIST *
545 emlxs_node_find_rpi(emlxs_port_t *port, uint32_t rpi)
547 NODELIST *nlp;
548 uint32_t i;
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);
559 nlp = (NODELIST *)nlp->nlp_list_next;
562 rw_exit(&port->node_rwlock);
564 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: rpi=%x",
565 rpi);
567 /* no match found */
568 return ((NODELIST *)0);
570 } /* emlxs_node_find_rpi() */
573 extern NODELIST *
574 emlxs_node_find_wwpn(emlxs_port_t *port, uint8_t *wwpn)
576 NODELIST *nlp;
577 uint32_t i;
578 uint32_t j;
579 uint8_t *bptr1;
580 uint8_t *bptr2;
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;
591 for (j = 0; j < 8; j++) {
592 if (*bptr1-- != *bptr2--) {
593 break;
597 if (j == 8) {
598 rw_exit(&port->node_rwlock);
599 return (nlp);
602 nlp = (NODELIST *)nlp->nlp_list_next;
605 rw_exit(&port->node_rwlock);
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]);
611 /* no match found */
612 return ((NODELIST *)0);
614 } /* emlxs_node_find_wwpn() */
617 extern NODELIST *
618 emlxs_node_find_index(emlxs_port_t *port, uint32_t index,
619 uint32_t nports_only)
621 NODELIST *nlp;
622 uint32_t i;
623 uint32_t count;
625 rw_enter(&port->node_rwlock, RW_READER);
627 if (index > port->node_count - 1) {
628 rw_exit(&port->node_rwlock);
629 return (NULL);
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;
643 if (count == index) {
644 rw_exit(&port->node_rwlock);
645 return (nlp);
648 nlp = (NODELIST *)nlp->nlp_list_next;
649 count++;
652 rw_exit(&port->node_rwlock);
654 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: index=%d",
655 index);
657 /* no match found */
658 return ((NODELIST *)0);
660 } /* emlxs_node_find_index() */
663 extern uint32_t
664 emlxs_nport_count(emlxs_port_t *port)
666 NODELIST *nlp;
667 uint32_t i;
668 uint32_t nport_count = 0;
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++;
678 nlp = (NODELIST *)nlp->nlp_list_next;
681 rw_exit(&port->node_rwlock);
683 return (nport_count);
685 } /* emlxs_nport_count() */
689 extern void
690 emlxs_node_destroy_all(emlxs_port_t *port)
692 emlxs_hba_t *hba = HBA;
693 NODELIST *next;
694 NODELIST *ndlp;
695 RPIobj_t *rpip;
696 uint8_t *wwn;
697 uint32_t i;
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;
710 if (port->node_count) {
711 port->node_count--;
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);
722 (void) emlxs_tx_node_flush(port, ndlp, 0, 0, 0);
724 /* Break Node/RPI binding */
725 if (ndlp->rpip) {
726 rpip = ndlp->rpip;
728 ndlp->rpip = NULL;
729 rpip->node = NULL;
731 (void) emlxs_rpi_free_notify(port, rpip);
734 emlxs_mem_put(hba, MEM_NLP, (void *)ndlp);
736 ndlp = next;
739 port->node_count = 0;
740 rw_exit(&port->node_rwlock);
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);
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);
753 return;
755 } /* emlxs_node_destroy_all() */
758 extern NODELIST *
759 emlxs_node_create(emlxs_port_t *port, uint32_t did, uint32_t rpi, SERV_PARM *sp)
761 emlxs_hba_t *hba = HBA;
762 NODELIST *ndlp;
763 uint8_t *wwn;
764 emlxs_vvl_fmt_t vvl;
765 RPIobj_t *rpip;
767 ndlp = emlxs_node_find_did(port, did);
769 /* Update the node */
770 if (ndlp) {
771 rw_enter(&port->node_rwlock, RW_WRITER);
773 ndlp->nlp_Rpi = (uint16_t)rpi;
774 ndlp->nlp_DID = did;
776 bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm,
777 sizeof (SERV_PARM));
779 bcopy((uint8_t *)&sp->nodeName,
780 (uint8_t *)&ndlp->nlp_nodename,
781 sizeof (NAME_TYPE));
783 bcopy((uint8_t *)&sp->portName,
784 (uint8_t *)&ndlp->nlp_portname,
785 sizeof (NAME_TYPE));
787 /* Add Node/RPI binding */
788 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
789 rpip = emlxs_rpi_find(port, rpi);
791 if (rpip) {
792 rpip->node = ndlp;
793 ndlp->rpip = rpip;
794 } else {
795 ndlp->rpip = NULL;
797 EMLXS_MSGF(EMLXS_CONTEXT,
798 &emlxs_node_create_msg,
799 "Unable to find RPI. did=%x rpi=%x",
800 did, rpi);
802 } else {
803 ndlp->rpip = NULL;
805 rw_exit(&port->node_rwlock);
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]);
814 goto done;
817 /* Allocate a new node */
818 ndlp = (NODELIST *)emlxs_mem_get(hba, MEM_NLP, 0);
820 if (ndlp) {
821 rw_enter(&port->node_rwlock, RW_WRITER);
823 ndlp->nlp_Rpi = (uint16_t)rpi;
824 ndlp->nlp_DID = did;
826 bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm,
827 sizeof (SERV_PARM));
829 bcopy((uint8_t *)&sp->nodeName,
830 (uint8_t *)&ndlp->nlp_nodename,
831 sizeof (NAME_TYPE));
833 bcopy((uint8_t *)&sp->portName,
834 (uint8_t *)&ndlp->nlp_portname,
835 sizeof (NAME_TYPE));
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;
843 /* Add Node/RPI binding */
844 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
845 rpip = emlxs_rpi_find(port, rpi);
847 if (rpip) {
848 rpip->node = ndlp;
849 ndlp->rpip = rpip;
850 } else {
851 ndlp->rpip = NULL;
853 EMLXS_MSGF(EMLXS_CONTEXT,
854 &emlxs_node_create_msg,
855 "Unable to find RPI. did=%x rpi=%x",
856 did, rpi);
858 } else {
859 ndlp->rpip = NULL;
861 rw_exit(&port->node_rwlock);
863 /* Add the node */
864 emlxs_node_add(port, ndlp);
866 goto done;
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]);
877 return (NULL);
879 done:
880 if (sp->VALID_VENDOR_VERSION) {
881 bcopy((caddr_t *)&sp->vendorVersion[0],
882 (caddr_t *)&vvl, sizeof (emlxs_vvl_fmt_t));
884 vvl.un0.word0 = LE_SWAP32(vvl.un0.word0);
885 vvl.un1.word1 = LE_SWAP32(vvl.un1.word1);
887 if ((vvl.un0.w0.oui == 0x0000C9) &&
888 (vvl.un1.w1.vport)) {
889 ndlp->nlp_fcp_info |= NLP_EMLX_VPORT;
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);
899 return (ndlp);
901 } /* emlxs_node_create() */
904 extern void
905 emlxs_node_add(emlxs_port_t *port, NODELIST *ndlp)
907 NODELIST *np;
908 uint8_t *wwn;
909 uint32_t hash;
911 rw_enter(&port->node_rwlock, RW_WRITER);
912 hash = EMLXS_DID_HASH(ndlp->nlp_DID);
913 np = port->node_table[hash];
916 * Insert node pointer to the head
918 port->node_table[hash] = ndlp;
919 if (!np) {
920 ndlp->nlp_list_next = NULL;
921 } else {
922 ndlp->nlp_list_next = np;
924 port->node_count++;
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);
932 rw_exit(&port->node_rwlock);
934 return;
936 } /* emlxs_node_add() */
939 extern void
940 emlxs_node_rm(emlxs_port_t *port, NODELIST *ndlp)
942 emlxs_hba_t *hba = HBA;
943 NODELIST *np;
944 NODELIST *prevp;
945 RPIobj_t *rpip;
946 uint8_t *wwn;
947 uint32_t hash;
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;
961 if (port->node_count) {
962 port->node_count--;
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);
973 (void) emlxs_tx_node_flush(port, ndlp, 0, 1, 0);
975 ndlp->nlp_active = 0;
977 /* Break Node/RPI binding */
978 if (ndlp->rpip) {
979 rpip = ndlp->rpip;
981 ndlp->rpip = NULL;
982 rpip->node = NULL;
984 (void) emlxs_rpi_free_notify(port, rpip);
987 emlxs_mem_put(hba, MEM_NLP, (void *)ndlp);
989 break;
991 prevp = np;
992 np = np->nlp_list_next;
994 rw_exit(&port->node_rwlock);
996 return;
998 } /* emlxs_node_rm() */