xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_node.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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