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]
23 * Copyright 2010 Emulex. All rights reserved.
24 * Use is subject to license terms.
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 */
37 emlxs_node_close(emlxs_port_t
*port
, NODELIST
*ndlp
, uint32_t channelno
,
40 emlxs_hba_t
*hba
= HBA
;
41 emlxs_config_t
*cfg
= &CFG
;
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
);
57 /* Check offline support */
59 if (cfg
[CFG_OFFLINE_TIMEOUT
].current
) {
60 timeout
= cfg
[CFG_OFFLINE_TIMEOUT
].current
;
67 if (channelno
== hba
->channel_ip
) {
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
);
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
);
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
);
96 mutex_exit(&EMLXS_TX_CHANNEL_LOCK
);
102 /* Set the node closed */
103 ndlp
->nlp_flag
[channelno
] |= NLP_CLOSED
;
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
);
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
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
;
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
] =
145 } else { /* This is a little more difficult */
147 /* Find the previous node in circular channel queue */
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
;
163 ndlp
->nlp_next
[channelno
] = NULL
;
166 mutex_exit(&EMLXS_TX_CHANNEL_LOCK
);
170 } /* emlxs_node_close() */
173 /* Called by emlxs_timer_check_nodes() */
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
);
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
,
196 emlxs_node_open(port
, ndlp
, channelno
);
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
,
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);
219 } /* emlxs_node_timeout() */
223 emlxs_node_open(emlxs_port_t
*port
, NODELIST
*ndlp
, uint32_t channelno
)
225 emlxs_hba_t
*hba
= HBA
;
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
);
243 /* Return if node already open */
244 if (!(ndlp
->nlp_flag
[channelno
] & NLP_CLOSED
)) {
245 mutex_exit(&EMLXS_TX_CHANNEL_LOCK
);
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
] =
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
;
282 cp
->nodeq
.q_first
= (uint8_t *)ndlp
;
283 cp
->nodeq
.q_last
= (uint8_t *)ndlp
;
284 ndlp
->nlp_next
[channelno
] = ndlp
;
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
) {
301 /* Scan to see if any FCP2 devices are still closed */
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
] &
314 nlp
= nlp
->nlp_list_next
;
322 rw_exit(&port
->node_rwlock
);
325 /* Clear link attention */
326 if ((mbox
= (MAILBOXQ
*)emlxs_mem_get(hba
,
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
,
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
,
355 /* Close the node and try again */
356 /* in a few seconds */
357 emlxs_node_close(port
, ndlp
, channelno
, 5);
365 /* Wake any sleeping threads */
366 mutex_enter(&EMLXS_PKT_LOCK
);
367 cv_broadcast(&EMLXS_PKT_CV
);
368 mutex_exit(&EMLXS_PKT_LOCK
);
372 } /* emlxs_node_open() */
376 emlxs_node_match_did(emlxs_port_t
*port
, NODELIST
*ndlp
, uint32_t did
)
382 if (ndlp
->nlp_DID
== did
)
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)) {
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
;
400 if ((ndid
.un
.b
.domain
== 0) && (ndid
.un
.b
.area
== 0)) {
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
;
411 if ((ndid
.un
.b
.domain
== 0) && (ndid
.un
.b
.area
== 0)) {
421 } /* End emlxs_node_match_did */
426 emlxs_node_find_mac(emlxs_port_t
*port
, uint8_t *mac
)
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
) ==
443 nlp
= (NODELIST
*)nlp
->nlp_list_next
;
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
);
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]);
469 } /* emlxs_node_find_mac() */
473 emlxs_node_find_did(emlxs_port_t
*port
, uint32_t did
)
475 emlxs_hba_t
*hba
= HBA
;
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
);
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
)) {
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
);
525 /* Check for detailed match */
526 else if (emlxs_node_match_did(port
, nlp
, did
)) {
527 rw_exit(&port
->node_rwlock
);
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",
539 return ((NODELIST
*)0);
541 } /* emlxs_node_find_did() */
545 emlxs_node_find_rpi(emlxs_port_t
*port
, uint32_t rpi
)
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
);
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",
568 return ((NODELIST
*)0);
570 } /* emlxs_node_find_rpi() */
574 emlxs_node_find_wwpn(emlxs_port_t
*port
, uint8_t *wwpn
)
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
;
588 bptr2
= (uint8_t *)wwpn
;
591 for (j
= 0; j
< 8; j
++) {
592 if (*bptr1
-- != *bptr2
--) {
598 rw_exit(&port
->node_rwlock
);
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]);
612 return ((NODELIST
*)0);
614 } /* emlxs_node_find_wwpn() */
618 emlxs_node_find_index(emlxs_port_t
*port
, uint32_t index
,
619 uint32_t nports_only
)
625 rw_enter(&port
->node_rwlock
, RW_READER
);
627 if (index
> port
->node_count
- 1) {
628 rw_exit(&port
->node_rwlock
);
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 */
638 (nlp
->nlp_DID
& 0xFFF000) == 0xFFF000) {
639 nlp
= (NODELIST
*)nlp
->nlp_list_next
;
643 if (count
== index
) {
644 rw_exit(&port
->node_rwlock
);
648 nlp
= (NODELIST
*)nlp
->nlp_list_next
;
652 rw_exit(&port
->node_rwlock
);
654 EMLXS_MSGF(EMLXS_CONTEXT
, &emlxs_node_not_found_msg
, "find: index=%d",
658 return ((NODELIST
*)0);
660 } /* emlxs_node_find_index() */
664 emlxs_nport_count(emlxs_port_t
*port
)
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) {
678 nlp
= (NODELIST
*)nlp
->nlp_list_next
;
681 rw_exit(&port
->node_rwlock
);
683 return (nport_count
);
685 } /* emlxs_nport_count() */
690 emlxs_node_destroy_all(emlxs_port_t
*port
)
692 emlxs_hba_t
*hba
= HBA
;
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
) {
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 */
731 (void) emlxs_rpi_free_notify(port
, rpip
);
734 emlxs_mem_put(hba
, MEM_NLP
, (void *)ndlp
);
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);
755 } /* emlxs_node_destroy_all() */
759 emlxs_node_create(emlxs_port_t
*port
, uint32_t did
, uint32_t rpi
, SERV_PARM
*sp
)
761 emlxs_hba_t
*hba
= HBA
;
767 ndlp
= emlxs_node_find_did(port
, did
);
769 /* Update the node */
771 rw_enter(&port
->node_rwlock
, RW_WRITER
);
773 ndlp
->nlp_Rpi
= (uint16_t)rpi
;
776 bcopy((uint8_t *)sp
, (uint8_t *)&ndlp
->sparm
,
779 bcopy((uint8_t *)&sp
->nodeName
,
780 (uint8_t *)&ndlp
->nlp_nodename
,
783 bcopy((uint8_t *)&sp
->portName
,
784 (uint8_t *)&ndlp
->nlp_portname
,
787 /* Add Node/RPI binding */
788 if (hba
->sli_mode
== EMLXS_HBA_SLI4_MODE
) {
789 rpip
= emlxs_rpi_find(port
, rpi
);
797 EMLXS_MSGF(EMLXS_CONTEXT
,
798 &emlxs_node_create_msg
,
799 "Unable to find RPI. did=%x rpi=%x",
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]);
817 /* Allocate a new node */
818 ndlp
= (NODELIST
*)emlxs_mem_get(hba
, MEM_NLP
, 0);
821 rw_enter(&port
->node_rwlock
, RW_WRITER
);
823 ndlp
->nlp_Rpi
= (uint16_t)rpi
;
826 bcopy((uint8_t *)sp
, (uint8_t *)&ndlp
->sparm
,
829 bcopy((uint8_t *)&sp
->nodeName
,
830 (uint8_t *)&ndlp
->nlp_nodename
,
833 bcopy((uint8_t *)&sp
->portName
,
834 (uint8_t *)&ndlp
->nlp_portname
,
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
);
853 EMLXS_MSGF(EMLXS_CONTEXT
,
854 &emlxs_node_create_msg
,
855 "Unable to find RPI. did=%x rpi=%x",
861 rw_exit(&port
->node_rwlock
);
864 emlxs_node_add(port
, ndlp
);
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]);
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
;
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
);
901 } /* emlxs_node_create() */
905 emlxs_node_add(emlxs_port_t
*port
, NODELIST
*ndlp
)
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
;
920 ndlp
->nlp_list_next
= NULL
;
922 ndlp
->nlp_list_next
= np
;
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
);
936 } /* emlxs_node_add() */
940 emlxs_node_rm(emlxs_port_t
*port
, NODELIST
*ndlp
)
942 emlxs_hba_t
*hba
= HBA
;
949 rw_enter(&port
->node_rwlock
, RW_WRITER
);
950 hash
= EMLXS_DID_HASH(ndlp
->nlp_DID
);
951 np
= port
->node_table
[hash
];
954 if (np
->nlp_DID
== ndlp
->nlp_DID
) {
956 port
->node_table
[hash
] = np
->nlp_list_next
;
958 prevp
->nlp_list_next
= np
->nlp_list_next
;
961 if (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 */
984 (void) emlxs_rpi_free_notify(port
, rpip
);
987 emlxs_mem_put(hba
, MEM_NLP
, (void *)ndlp
);
992 np
= np
->nlp_list_next
;
994 rw_exit(&port
->node_rwlock
);
998 } /* emlxs_node_rm() */