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