xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_node.c (revision 8f23e9fa8abcb5857661066b954e63400d589b65)
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 */
31 EMLXS_MSG_DEF(EMLXS_NODE_C);
32 
33 static void	emlxs_node_add(emlxs_port_t *, NODELIST *);
34 static 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 */
38 extern void
emlxs_node_close(emlxs_port_t * port,NODELIST * ndlp,uint32_t channelno,int32_t timeout)39 emlxs_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() */
176 extern void
emlxs_node_timeout(emlxs_port_t * port,NODELIST * ndlp,uint32_t channelno)177 emlxs_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 
224 extern void
emlxs_node_open(emlxs_port_t * port,NODELIST * ndlp,uint32_t channelno)225 emlxs_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 
365 done:
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 
377 static int
emlxs_node_match_did(emlxs_port_t * port,NODELIST * ndlp,uint32_t did)378 emlxs_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 
419 out:
420 
421 	return (0);
422 
423 } /* emlxs_node_match_did() */
424 
425 
426 
427 extern NODELIST *
emlxs_node_find_mac(emlxs_port_t * port,uint8_t * mac)428 emlxs_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 
474 extern NODELIST *
emlxs_node_find_did(emlxs_port_t * port,uint32_t did,uint32_t lock)475 emlxs_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 
555 extern NODELIST *
emlxs_node_find_rpi(emlxs_port_t * port,uint32_t rpi)556 emlxs_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 
584 extern NODELIST *
emlxs_node_find_wwpn(emlxs_port_t * port,uint8_t * wwpn,uint32_t lock)585 emlxs_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 
636 extern NODELIST *
emlxs_node_find_index(emlxs_port_t * port,uint32_t index,uint32_t nports_only)637 emlxs_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 
682 extern uint32_t
emlxs_nport_count(emlxs_port_t * port)683 emlxs_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 
708 extern void
emlxs_node_destroy_all(emlxs_port_t * port)709 emlxs_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 
777 extern NODELIST *
emlxs_node_create(emlxs_port_t * port,uint32_t did,uint32_t rpi,SERV_PARM * sp)778 emlxs_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 
906 done:
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 */
935 static void
emlxs_node_add(emlxs_port_t * port,NODELIST * ndlp)936 emlxs_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 
967 extern void
emlxs_node_rm(emlxs_port_t * port,NODELIST * ndlp)968 emlxs_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 
1029 extern void
emlxs_node_throttle_set(emlxs_port_t * port,NODELIST * ndlp)1030 emlxs_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