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
9 * http://www.opensource.org/licenses/cddl1.txt.
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 (c) 2004-2011 Emulex. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <emlxs.h>
28
29
30/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31EMLXS_MSG_DEF(EMLXS_NODE_C);
32
33static void	emlxs_node_add(emlxs_port_t *, NODELIST *);
34static int	emlxs_node_match_did(emlxs_port_t *, NODELIST *, uint32_t);
35
36/* Timeout == -1 will enable the offline timer */
37/* Timeout not -1 will apply the timeout */
38extern void
39emlxs_node_close(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno,
40    int32_t timeout)
41{
42	emlxs_hba_t *hba = HBA;
43	emlxs_config_t *cfg = &CFG;
44	CHANNEL *cp;
45	NODELIST *prev;
46	uint32_t offline = 0;
47
48
49	/* If node is on a channel service queue, then remove it */
50	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
51
52	/* Return if node destroyed */
53	if (!ndlp || !ndlp->nlp_active) {
54		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
55
56		return;
57	}
58
59	/* Check offline support */
60	if (timeout == -1) {
61		if (cfg[CFG_OFFLINE_TIMEOUT].current) {
62			timeout = cfg[CFG_OFFLINE_TIMEOUT].current;
63			offline = 1;
64		} else {
65			timeout = 0;
66		}
67	}
68
69	if (channelno == hba->channel_ip) {
70		/* Clear IP XRI */
71		ndlp->nlp_Xri = 0;
72	}
73
74	/* Check if node is already closed */
75	if (ndlp->nlp_flag[channelno] & NLP_CLOSED) {
76		if (ndlp->nlp_flag[channelno] & NLP_OFFLINE) {
77			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
78			return;
79		}
80
81		if (offline) {
82			ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
83			ndlp->nlp_flag[channelno] |= NLP_OFFLINE;
84			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
85
86			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
87			    "node=%p did=%06x channel=%d. offline=%d update.",
88			    ndlp, ndlp->nlp_DID, channelno, timeout);
89
90		} else if (timeout) {
91			ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
92			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
93
94			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
95			    "node=%p did=%06x channel=%d. timeout=%d update.",
96			    ndlp, ndlp->nlp_DID, channelno, timeout);
97		} else {
98			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
99		}
100
101		return;
102	}
103
104	/* Set the node closed */
105	ndlp->nlp_flag[channelno] |= NLP_CLOSED;
106
107	if (offline) {
108		ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
109		ndlp->nlp_flag[channelno] |= NLP_OFFLINE;
110
111		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
112		    "node=%p did=%06x channel=%d. offline=%d set.",
113		    ndlp, ndlp->nlp_DID, channelno, timeout);
114
115	} else if (timeout) {
116		ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
117
118		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
119		    "node=%p did=%06x channel=%d. timeout=%d set.",
120		    ndlp, ndlp->nlp_DID, channelno, timeout);
121	} else {
122		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
123		    "node=%p did=%06x channel=%d.",
124		    ndlp, ndlp->nlp_DID, channelno);
125	}
126
127
128	/*
129	 * ndlp->nlp_next[] and cp->nodeq list have to be updated
130	 * simulaneously
131	 */
132	if (ndlp->nlp_next[channelno]) {
133		/* Remove node from channel queue */
134		cp = &hba->chan[channelno];
135
136		/* If this is the only node on list */
137		if (cp->nodeq.q_first == (void *)ndlp &&
138		    cp->nodeq.q_last == (void *)ndlp) {
139			cp->nodeq.q_last = NULL;
140			cp->nodeq.q_first = NULL;
141			cp->nodeq.q_cnt = 0;
142		} else if (cp->nodeq.q_first == (void *)ndlp) {
143			cp->nodeq.q_first = ndlp->nlp_next[channelno];
144			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
145			    cp->nodeq.q_first;
146			cp->nodeq.q_cnt--;
147		} else {	/* This is a little more difficult */
148
149			/* Find the previous node in circular channel queue */
150			prev = ndlp;
151			while (prev->nlp_next[channelno] != ndlp) {
152				prev = prev->nlp_next[channelno];
153			}
154
155			prev->nlp_next[channelno] = ndlp->nlp_next[channelno];
156
157			if (cp->nodeq.q_last == (void *)ndlp) {
158				cp->nodeq.q_last = (void *)prev;
159			}
160			cp->nodeq.q_cnt--;
161
162		}
163
164		/* Clear node */
165		ndlp->nlp_next[channelno] = NULL;
166	}
167
168	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
169
170	return;
171
172} /* emlxs_node_close() */
173
174
175/* Called by emlxs_timer_check_nodes() */
176extern void
177emlxs_node_timeout(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno)
178{
179	emlxs_hba_t *hba = HBA;
180
181	/* If node needs servicing, then add it to the channel queues */
182	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
183
184	/* Return if node destroyed */
185	if (!ndlp || !ndlp->nlp_active) {
186		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
187		return;
188	}
189
190	/* Open the node if not offline */
191	if (!(ndlp->nlp_flag[channelno] & NLP_OFFLINE)) {
192		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
193
194		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg,
195		    "node=%p did=%06x channel=%d Opening.", ndlp, ndlp->nlp_DID,
196		    channelno);
197
198		emlxs_node_open(port, ndlp, channelno);
199		return;
200	}
201
202	/* OFFLINE TIMEOUT OCCURRED! */
203
204	/* Clear the timer */
205	ndlp->nlp_tics[channelno] = 0;
206
207	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
208
209	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg,
210	    "node=%p did=%06x channel=%d. Flushing.", ndlp, ndlp->nlp_DID,
211	    channelno);
212
213	/* Flush tx queue for this channel */
214	(void) emlxs_tx_node_flush(port, ndlp, &hba->chan[channelno], 0, 0);
215
216	/* Flush chip queue for this channel */
217	(void) emlxs_chipq_node_flush(port, &hba->chan[channelno], ndlp, 0);
218
219	return;
220
221} /* emlxs_node_timeout() */
222
223
224extern void
225emlxs_node_open(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno)
226{
227	emlxs_hba_t *hba = HBA;
228	CHANNEL *cp;
229	uint32_t found;
230	NODELIST *nlp;
231	MAILBOXQ *mbox;
232	uint32_t i;
233	int rc;
234
235	/* If node needs servicing, then add it to the channel queues */
236	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
237
238	/* Return if node destroyed */
239	if (!ndlp || !ndlp->nlp_active) {
240		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
241
242		return;
243	}
244
245	/* Return if node already open */
246	if (!(ndlp->nlp_flag[channelno] & NLP_CLOSED)) {
247		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
248
249		return;
250	}
251
252	/* Set the node open (not closed) */
253	ndlp->nlp_flag[channelno] &= ~(NLP_CLOSED|NLP_OFFLINE);
254
255	/* Clear the timer */
256	ndlp->nlp_tics[channelno] = 0;
257
258	/*
259	 * If the ptx or the tx queue needs servicing and
260	 * the node is not already on the channel queue
261	 */
262	if ((ndlp->nlp_ptx[channelno].q_first ||
263	    ndlp->nlp_tx[channelno].q_first) && !ndlp->nlp_next[channelno]) {
264		cp = &hba->chan[channelno];
265
266		/* If so, then add it to the channel queue */
267		if (cp->nodeq.q_first) {
268			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
269			    (uint8_t *)ndlp;
270			ndlp->nlp_next[channelno] = cp->nodeq.q_first;
271
272			/* If this is not the base node then */
273			/* add it to the tail */
274			if (!ndlp->nlp_base) {
275				cp->nodeq.q_last = (uint8_t *)ndlp;
276			} else {	/* Otherwise, add it to the head */
277
278				/* The command node always gets priority */
279				cp->nodeq.q_first = (uint8_t *)ndlp;
280			}
281
282			cp->nodeq.q_cnt++;
283		} else {
284			cp->nodeq.q_first = (uint8_t *)ndlp;
285			cp->nodeq.q_last = (uint8_t *)ndlp;
286			ndlp->nlp_next[channelno] = ndlp;
287			cp->nodeq.q_cnt = 1;
288		}
289	}
290
291	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
292
293	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_opened_msg,
294	    "node=%p did=%06x rpi=%d channel=%d", ndlp, ndlp->nlp_DID,
295	    ndlp->nlp_Rpi, channelno);
296
297	/* If link attention needs to be cleared */
298	if ((hba->state == FC_LINK_UP) && (channelno == hba->channel_fcp)) {
299		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
300			goto done;
301		}
302
303		/* Scan to see if any FCP2 devices are still closed */
304		found = 0;
305		rw_enter(&port->node_rwlock, RW_READER);
306		for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
307			nlp = port->node_table[i];
308			while (nlp != NULL) {
309				if ((nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
310				    (nlp->nlp_flag[hba->channel_fcp] &
311				    NLP_CLOSED)) {
312					found = 1;
313					break;
314
315				}
316				nlp = nlp->nlp_list_next;
317			}
318
319			if (found) {
320				break;
321			}
322		}
323
324		rw_exit(&port->node_rwlock);
325
326		if (!found) {
327			/* Clear link attention */
328			if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba,
329			    MEM_MBOX))) {
330				mutex_enter(&EMLXS_PORT_LOCK);
331
332				/*
333				 * If state is not FC_LINK_UP, then either the
334				 * link has gone down or a FC_CLEAR_LA has
335				 * already been issued
336				 */
337				if (hba->state != FC_LINK_UP) {
338					mutex_exit(&EMLXS_PORT_LOCK);
339					emlxs_mem_put(hba, MEM_MBOX,
340					    (void *)mbox);
341					goto done;
342				}
343
344				EMLXS_STATE_CHANGE_LOCKED(hba, FC_CLEAR_LA);
345				hba->discovery_timer = 0;
346				mutex_exit(&EMLXS_PORT_LOCK);
347
348				emlxs_mb_clear_la(hba, mbox);
349
350				rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba,
351				    mbox, MBX_NOWAIT, 0);
352				if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
353					emlxs_mem_put(hba, MEM_MBOX,
354					    (void *)mbox);
355				}
356			} else {
357				/* Close the node and try again */
358				/* in a few seconds */
359				emlxs_node_close(port, ndlp, channelno, 5);
360				return;
361			}
362		}
363	}
364
365done:
366
367	/* Wake any sleeping threads */
368	mutex_enter(&EMLXS_PKT_LOCK);
369	cv_broadcast(&EMLXS_PKT_CV);
370	mutex_exit(&EMLXS_PKT_LOCK);
371
372	return;
373
374} /* emlxs_node_open() */
375
376
377static int
378emlxs_node_match_did(emlxs_port_t *port, NODELIST *ndlp, uint32_t did)
379{
380	D_ID mydid;
381	D_ID odid;
382	D_ID ndid;
383
384	if (ndlp->nlp_DID == did)
385		return (1);
386
387	/*
388	 * Next check for area/domain == 0 match
389	 */
390	mydid.un.word = port->did;
391	if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
392		goto out;
393	}
394
395	ndid.un.word = did;
396	odid.un.word = ndlp->nlp_DID;
397	if (ndid.un.b.id == odid.un.b.id) {
398		if ((mydid.un.b.domain == ndid.un.b.domain) &&
399		    (mydid.un.b.area == ndid.un.b.area)) {
400			ndid.un.word = ndlp->nlp_DID;
401			odid.un.word = did;
402			if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) {
403				return (1);
404			}
405			goto out;
406		}
407
408		ndid.un.word = ndlp->nlp_DID;
409		if ((mydid.un.b.domain == ndid.un.b.domain) &&
410		    (mydid.un.b.area == ndid.un.b.area)) {
411			odid.un.word = ndlp->nlp_DID;
412			ndid.un.word = did;
413			if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) {
414				return (1);
415			}
416		}
417	}
418
419out:
420
421	return (0);
422
423} /* emlxs_node_match_did() */
424
425
426
427extern NODELIST *
428emlxs_node_find_mac(emlxs_port_t *port, uint8_t *mac)
429{
430	NODELIST *nlp;
431	uint32_t i;
432
433	rw_enter(&port->node_rwlock, RW_READER);
434	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
435		nlp = port->node_table[i];
436		while (nlp != NULL) {
437			/*
438			 * If portname matches mac address,
439			 * return NODELIST entry
440			 */
441			if ((nlp->nlp_portname.IEEE[0] == mac[0])) {
442				if ((nlp->nlp_DID != BCAST_DID) &&
443				    ((nlp->nlp_DID & FABRIC_DID_MASK) ==
444				    FABRIC_DID_MASK)) {
445					nlp = (NODELIST *)nlp->nlp_list_next;
446					continue;
447				}
448
449				if ((nlp->nlp_portname.IEEE[1] == mac[1]) &&
450				    (nlp->nlp_portname.IEEE[2] == mac[2]) &&
451				    (nlp->nlp_portname.IEEE[3] == mac[3]) &&
452				    (nlp->nlp_portname.IEEE[4] == mac[4]) &&
453				    (nlp->nlp_portname.IEEE[5] == mac[5])) {
454					rw_exit(&port->node_rwlock);
455					return (nlp);
456				}
457
458			}
459
460			nlp = (NODELIST *)nlp->nlp_list_next;
461		}
462	}
463	rw_exit(&port->node_rwlock);
464
465	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg,
466	    "find: MAC=%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2],
467	    mac[3], mac[4], mac[5]);
468
469	return (NULL);
470
471} /* emlxs_node_find_mac() */
472
473
474extern NODELIST *
475emlxs_node_find_did(emlxs_port_t *port, uint32_t did, uint32_t lock)
476{
477	emlxs_hba_t *hba = HBA;
478	NODELIST *nlp;
479	uint32_t hash;
480
481	/* Check for invalid node ids  */
482	if ((did == 0) && (!(hba->flag & FC_LOOPBACK_MODE))) {
483		return ((NODELIST *)0);
484	}
485
486	if (did & 0xff000000) {
487		return ((NODELIST *)0);
488	}
489
490	/* Check for bcast node */
491	if (did == BCAST_DID) {
492		/* Use the base node here */
493		return (&port->node_base);
494	}
495#ifdef MENLO_SUPPORT
496	/* Check for menlo node */
497	if (did == EMLXS_MENLO_DID) {
498		/* Use the base node here */
499		return (&port->node_base);
500	}
501#endif /* MENLO_SUPPORT */
502
503	/* Check for host node */
504	if (did == port->did && !(hba->flag & FC_LOOPBACK_MODE)) {
505		/* Use the base node here */
506		return (&port->node_base);
507	}
508
509	/*
510	 * Convert well known fabric addresses to the FABRIC_DID,
511	 * since we don't login to some of them
512	 */
513	if ((did == SCR_DID)) {
514		did = FABRIC_DID;
515	}
516
517	if (lock) {
518		rw_enter(&port->node_rwlock, RW_READER);
519	}
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			if (lock) {
526				rw_exit(&port->node_rwlock);
527			}
528			return (nlp);
529		}
530
531		/* Check for detailed match */
532		else if (emlxs_node_match_did(port, nlp, did)) {
533			if (lock) {
534				rw_exit(&port->node_rwlock);
535			}
536			return (nlp);
537		}
538
539		nlp = (NODELIST *)nlp->nlp_list_next;
540	}
541
542	if (lock) {
543		rw_exit(&port->node_rwlock);
544	}
545
546	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: did=%x",
547	    did);
548
549	/* no match found */
550	return ((NODELIST *)0);
551
552} /* emlxs_node_find_did() */
553
554
555extern NODELIST *
556emlxs_node_find_rpi(emlxs_port_t *port, uint32_t rpi)
557{
558	NODELIST *nlp;
559	uint32_t i;
560
561	rw_enter(&port->node_rwlock, RW_READER);
562	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
563		nlp = port->node_table[i];
564		while (nlp != NULL) {
565			if (nlp->nlp_Rpi == rpi) {
566				rw_exit(&port->node_rwlock);
567				return (nlp);
568			}
569
570			nlp = (NODELIST *)nlp->nlp_list_next;
571		}
572	}
573	rw_exit(&port->node_rwlock);
574
575	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: rpi=%d",
576	    rpi);
577
578	/* no match found */
579	return ((NODELIST *)0);
580
581} /* emlxs_node_find_rpi() */
582
583
584extern NODELIST *
585emlxs_node_find_wwpn(emlxs_port_t *port, uint8_t *wwpn, uint32_t lock)
586{
587	NODELIST *nlp;
588	uint32_t i;
589	uint32_t j;
590	uint8_t *bptr1;
591	uint8_t *bptr2;
592
593	if (lock) {
594		rw_enter(&port->node_rwlock, RW_READER);
595	}
596
597	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
598		nlp = port->node_table[i];
599		while (nlp != NULL) {
600			bptr1 = (uint8_t *)&nlp->nlp_portname;
601			bptr1 += 7;
602			bptr2 = (uint8_t *)wwpn;
603			bptr2 += 7;
604
605			for (j = 0; j < 8; j++) {
606				if (*bptr1-- != *bptr2--) {
607					break;
608				}
609			}
610
611			if (j == 8) {
612				if (lock) {
613					rw_exit(&port->node_rwlock);
614				}
615				return (nlp);
616			}
617
618			nlp = (NODELIST *)nlp->nlp_list_next;
619		}
620	}
621
622	if (lock) {
623		rw_exit(&port->node_rwlock);
624	}
625
626	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg,
627	    "find: wwpn=%02x%02x%02x%02x%02x%02x%02x%02x", wwpn[0], wwpn[1],
628	    wwpn[2], wwpn[3], wwpn[4], wwpn[5], wwpn[6], wwpn[7]);
629
630	/* no match found */
631	return ((NODELIST *)0);
632
633} /* emlxs_node_find_wwpn() */
634
635
636extern NODELIST *
637emlxs_node_find_index(emlxs_port_t *port, uint32_t index,
638    uint32_t nports_only)
639{
640	NODELIST *nlp;
641	uint32_t i;
642	uint32_t count;
643
644	rw_enter(&port->node_rwlock, RW_READER);
645
646	if (index > port->node_count - 1) {
647		rw_exit(&port->node_rwlock);
648		return (NULL);
649	}
650
651	count = 0;
652	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
653		nlp = port->node_table[i];
654		while (nlp != NULL) {
655			/* Skip fabric ports if requested */
656			if (nports_only &&
657			    (nlp->nlp_DID & 0xFFF000) == 0xFFF000) {
658				nlp = (NODELIST *)nlp->nlp_list_next;
659				continue;
660			}
661
662			if (count == index) {
663				rw_exit(&port->node_rwlock);
664				return (nlp);
665			}
666
667			nlp = (NODELIST *)nlp->nlp_list_next;
668			count++;
669		}
670	}
671	rw_exit(&port->node_rwlock);
672
673	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: index=%d",
674	    index);
675
676	/* no match found */
677	return ((NODELIST *)0);
678
679} /* emlxs_node_find_index() */
680
681
682extern uint32_t
683emlxs_nport_count(emlxs_port_t *port)
684{
685	NODELIST *nlp;
686	uint32_t i;
687	uint32_t nport_count = 0;
688
689	rw_enter(&port->node_rwlock, RW_READER);
690	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
691		nlp = port->node_table[i];
692		while (nlp != NULL) {
693			if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) {
694				nport_count++;
695			}
696
697			nlp = (NODELIST *)nlp->nlp_list_next;
698		}
699	}
700	rw_exit(&port->node_rwlock);
701
702	return (nport_count);
703
704} /* emlxs_nport_count() */
705
706
707
708extern void
709emlxs_node_destroy_all(emlxs_port_t *port)
710{
711	emlxs_hba_t *hba = HBA;
712	NODELIST *next;
713	NODELIST *ndlp;
714	RPIobj_t *rpip;
715	uint8_t *wwn;
716	uint32_t i;
717
718	/* Flush and free the nodes */
719	rw_enter(&port->node_rwlock, RW_WRITER);
720	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
721		ndlp = port->node_table[i];
722		port->node_table[i] = 0;
723		while (ndlp != NULL) {
724			next = ndlp->nlp_list_next;
725			ndlp->nlp_list_next = NULL;
726			ndlp->nlp_list_prev = NULL;
727			ndlp->nlp_active = 0;
728
729			if (port->node_count) {
730				port->node_count--;
731			}
732
733			wwn = (uint8_t *)&ndlp->nlp_portname;
734			EMLXS_MSGF(EMLXS_CONTEXT,
735			    &emlxs_node_destroy_msg, "did=%06x "
736			    "rpi=%d wwpn=%02x%02x%02x%02x%02x%02x%02x%02x "
737			    "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
738			    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6],
739			    wwn[7], port->node_count);
740
741			(void) emlxs_tx_node_flush(port, ndlp, 0, 0, 0);
742
743			/* Break Node/RPI binding */
744			if (ndlp->rpip) {
745				rpip = ndlp->rpip;
746
747				ndlp->rpip = NULL;
748				rpip->node = NULL;
749
750				(void) emlxs_rpi_free_notify(port, rpip);
751			}
752
753			emlxs_mem_put(hba, MEM_NLP, (void *)ndlp);
754
755			ndlp = next;
756		}
757	}
758	port->node_count = 0;
759	rw_exit(&port->node_rwlock);
760
761	/* Clean the base node */
762	mutex_enter(&EMLXS_PORT_LOCK);
763	port->node_base.nlp_list_next = NULL;
764	port->node_base.nlp_list_prev = NULL;
765	port->node_base.nlp_active = 1;
766	mutex_exit(&EMLXS_PORT_LOCK);
767
768	/* Flush the base node */
769	(void) emlxs_tx_node_flush(port, &port->node_base, 0, 1, 0);
770	(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
771
772	return;
773
774} /* emlxs_node_destroy_all() */
775
776
777extern NODELIST *
778emlxs_node_create(emlxs_port_t *port, uint32_t did, uint32_t rpi, SERV_PARM *sp)
779{
780	emlxs_hba_t *hba = HBA;
781	NODELIST *ndlp, *ndlp_wwn;
782	uint8_t *wwn;
783	emlxs_vvl_fmt_t vvl;
784	RPIobj_t *rpip;
785
786	rw_enter(&port->node_rwlock, RW_WRITER);
787
788	ndlp = emlxs_node_find_did(port, did, 0);
789	ndlp_wwn = emlxs_node_find_wwpn(port, (uint8_t *)&sp->portName, 0);
790
791	/* Zero out the stale node worldwide names */
792	if (ndlp_wwn && (ndlp != ndlp_wwn)) {
793		bzero((uint8_t *)&ndlp_wwn->nlp_nodename, sizeof (NAME_TYPE));
794		bzero((uint8_t *)&ndlp_wwn->nlp_portname, sizeof (NAME_TYPE));
795	}
796
797	/* Update the node */
798	if (ndlp) {
799		ndlp->nlp_Rpi = (uint16_t)rpi;
800		ndlp->nlp_DID = did;
801
802		bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm,
803		    sizeof (SERV_PARM));
804
805		bcopy((uint8_t *)&sp->nodeName,
806		    (uint8_t *)&ndlp->nlp_nodename,
807		    sizeof (NAME_TYPE));
808
809		bcopy((uint8_t *)&sp->portName,
810		    (uint8_t *)&ndlp->nlp_portname,
811		    sizeof (NAME_TYPE));
812
813		/* Add Node/RPI binding */
814		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
815			rpip = emlxs_rpi_find(port, rpi);
816
817			if (rpip) {
818				rpip->node = ndlp;
819				ndlp->rpip = rpip;
820			} else {
821				ndlp->rpip = NULL;
822
823				EMLXS_MSGF(EMLXS_CONTEXT,
824				    &emlxs_node_create_msg,
825				    "Unable to find RPI. did=%x rpi=%d",
826				    did, rpi);
827			}
828		} else {
829			ndlp->rpip = NULL;
830		}
831
832		wwn = (uint8_t *)&ndlp->nlp_portname;
833		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_update_msg,
834		    "node=%p did=%06x rpi=%d "
835		    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
836		    ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
837		    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
838
839		goto done;
840	}
841
842	/* Allocate a new node */
843	ndlp = (NODELIST *)emlxs_mem_get(hba, MEM_NLP);
844
845	if (ndlp) {
846		ndlp->nlp_Rpi = (uint16_t)rpi;
847		ndlp->nlp_DID = did;
848
849		bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm,
850		    sizeof (SERV_PARM));
851
852		bcopy((uint8_t *)&sp->nodeName,
853		    (uint8_t *)&ndlp->nlp_nodename,
854		    sizeof (NAME_TYPE));
855
856		bcopy((uint8_t *)&sp->portName,
857		    (uint8_t *)&ndlp->nlp_portname,
858		    sizeof (NAME_TYPE));
859
860		ndlp->nlp_active = 1;
861		ndlp->nlp_flag[hba->channel_ct]  |= NLP_CLOSED;
862		ndlp->nlp_flag[hba->channel_els] |= NLP_CLOSED;
863		ndlp->nlp_flag[hba->channel_fcp] |= NLP_CLOSED;
864		ndlp->nlp_flag[hba->channel_ip]  |= NLP_CLOSED;
865
866		/* Add Node/RPI binding */
867		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
868			rpip = emlxs_rpi_find(port, rpi);
869
870			if (rpip) {
871				rpip->node = ndlp;
872				ndlp->rpip = rpip;
873			} else {
874				ndlp->rpip = NULL;
875
876				EMLXS_MSGF(EMLXS_CONTEXT,
877				    &emlxs_node_create_msg,
878				    "Unable to find RPI. did=%x rpi=%d",
879				    did, rpi);
880			}
881		} else {
882			ndlp->rpip = NULL;
883		}
884
885#ifdef NODE_THROTTLE_SUPPORT
886		emlxs_node_throttle_set(port, ndlp);
887#endif /* NODE_THROTTLE_SUPPORT */
888
889		/* Add the node */
890		emlxs_node_add(port, ndlp);
891
892		goto done;
893	}
894
895	rw_exit(&port->node_rwlock);
896	wwn = (uint8_t *)&sp->portName;
897	EMLXS_MSGF(EMLXS_CONTEXT,
898	    &emlxs_node_create_failed_msg,
899	    "Unable to allocate node. did=%06x "
900	    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
901	    did, wwn[0], wwn[1], wwn[2],
902	    wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
903
904	return (NULL);
905
906done:
907	rw_exit(&port->node_rwlock);
908	if (sp->VALID_VENDOR_VERSION) {
909		bcopy((caddr_t *)&sp->vendorVersion[0],
910		    (caddr_t *)&vvl, sizeof (emlxs_vvl_fmt_t));
911
912		vvl.un0.word0 = LE_SWAP32(vvl.un0.word0);
913		vvl.un1.word1 = LE_SWAP32(vvl.un1.word1);
914
915		if ((vvl.un0.w0.oui == 0x0000C9) &&
916		    (vvl.un1.w1.vport)) {
917			ndlp->nlp_fcp_info |= NLP_EMLX_VPORT;
918		}
919	}
920
921	/* Open the node */
922	emlxs_node_open(port, ndlp, hba->channel_ct);
923	emlxs_node_open(port, ndlp, hba->channel_els);
924	emlxs_node_open(port, ndlp, hba->channel_ip);
925	emlxs_node_open(port, ndlp, hba->channel_fcp);
926
927	EMLXS_SET_DFC_STATE(ndlp, NODE_LOGIN);
928
929	return (ndlp);
930
931} /* emlxs_node_create() */
932
933
934/* node_rwlock must be held when calling this routine */
935static void
936emlxs_node_add(emlxs_port_t *port, NODELIST *ndlp)
937{
938	NODELIST *np;
939	uint8_t *wwn;
940	uint32_t hash;
941
942	hash = EMLXS_DID_HASH(ndlp->nlp_DID);
943	np = port->node_table[hash];
944
945	/*
946	 * Insert node pointer to the head
947	 */
948	port->node_table[hash] = ndlp;
949	if (!np) {
950		ndlp->nlp_list_next = NULL;
951	} else {
952		ndlp->nlp_list_next = np;
953	}
954	port->node_count++;
955
956	wwn = (uint8_t *)&ndlp->nlp_portname;
957	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_msg,
958	    "node=%p did=%06x rpi=%d wwpn=%02x%02x%02x%02x%02x%02x%02x%02x "
959	    "count=%d", ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], wwn[1],
960	    wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7], port->node_count);
961
962	return;
963
964} /* emlxs_node_add() */
965
966
967extern void
968emlxs_node_rm(emlxs_port_t *port, NODELIST *ndlp)
969{
970	emlxs_hba_t *hba = HBA;
971	NODELIST *np;
972	NODELIST *prevp;
973	RPIobj_t *rpip;
974	uint8_t *wwn;
975	uint32_t hash;
976
977	rw_enter(&port->node_rwlock, RW_WRITER);
978	hash = EMLXS_DID_HASH(ndlp->nlp_DID);
979	np = port->node_table[hash];
980	prevp = NULL;
981	while (np != NULL) {
982		if (np->nlp_DID == ndlp->nlp_DID) {
983			if (prevp == NULL) {
984				port->node_table[hash] = np->nlp_list_next;
985			} else {
986				prevp->nlp_list_next = np->nlp_list_next;
987			}
988
989			if (port->node_count) {
990				port->node_count--;
991			}
992
993			wwn = (uint8_t *)&ndlp->nlp_portname;
994			EMLXS_MSGF(EMLXS_CONTEXT,
995			    &emlxs_node_destroy_msg, "did=%06x "
996			    "rpi=%d wwpn=%02x%02x%02x%02x%02x%02x%02x%02x "
997			    "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
998			    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6],
999			    wwn[7], port->node_count);
1000
1001			(void) emlxs_tx_node_flush(port, ndlp, 0, 1, 0);
1002
1003			ndlp->nlp_active = 0;
1004
1005			/* Break Node/RPI binding */
1006			if (ndlp->rpip) {
1007				rpip = ndlp->rpip;
1008
1009				ndlp->rpip = NULL;
1010				rpip->node = NULL;
1011
1012				(void) emlxs_rpi_free_notify(port, rpip);
1013			}
1014
1015			emlxs_mem_put(hba, MEM_NLP, (void *)ndlp);
1016
1017			break;
1018		}
1019		prevp = np;
1020		np = np->nlp_list_next;
1021	}
1022	rw_exit(&port->node_rwlock);
1023
1024	return;
1025
1026} /* emlxs_node_rm() */
1027
1028
1029extern void
1030emlxs_node_throttle_set(emlxs_port_t *port, NODELIST *ndlp)
1031{
1032	emlxs_hba_t *hba = HBA;
1033	emlxs_config_t *cfg = &CFG;
1034	char prop[64];
1035	char buf1[32];
1036	uint32_t throttle;
1037
1038	/* Set global default */
1039	throttle = (ndlp->nlp_fcp_info & NLP_FCP_TGT_DEVICE)?
1040	    cfg[CFG_TGT_DEPTH].current:0;
1041
1042	/* Check per wwpn default */
1043	(void) snprintf(prop, sizeof (prop), "w%s-depth",
1044	    emlxs_wwn_xlate(buf1, sizeof (buf1),
1045	    (uint8_t *)&ndlp->nlp_portname));
1046
1047	throttle = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY,
1048	    (void *)hba->dip, DDI_PROP_DONTPASS, prop, throttle);
1049
1050	/* Check per driver/wwpn default */
1051	(void) snprintf(prop, sizeof (prop), "%s%d-w%s-depth", DRIVER_NAME,
1052	    hba->ddiinst, emlxs_wwn_xlate(buf1, sizeof (buf1),
1053	    (uint8_t *)&ndlp->nlp_portname));
1054
1055	throttle = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY,
1056	    (void *)hba->dip, DDI_PROP_DONTPASS, prop, throttle);
1057
1058	/* Check limit */
1059	throttle = MIN(throttle, MAX_NODE_THROTTLE);
1060
1061	ndlp->io_throttle = throttle;
1062
1063	return;
1064
1065} /* emlxs_node_throttle_set() */
1066