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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <kvm.h>
35 #include <varargs.h>
36 #include <errno.h>
37 #include <time.h>
38 #include <dirent.h>
39 #include <fcntl.h>
40 #include <sys/param.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <sys/utsname.h>
44 #include <sys/openpromio.h>
45 #include <sys/systeminfo.h>
46 #include <kstat.h>
47 #include <libintl.h>
48 #include <syslog.h>
49 #include <sys/dkio.h>
50 #include "pdevinfo.h"
51 #include "display.h"
52 #include "pdevinfo_sun4u.h"
53 #include "display_sun4u.h"
54 #include "libprtdiag.h"
55
56 #if !defined(TEXT_DOMAIN)
57 #define TEXT_DOMAIN "SYS_TEST"
58 #endif
59
60 Prom_node *
find_pci_bus(Prom_node * node,int id,int bus)61 find_pci_bus(Prom_node *node, int id, int bus)
62 {
63 Prom_node *pnode;
64
65 /* find the first pci node */
66 pnode = dev_find_node(node, "pci");
67
68 while (pnode != NULL) {
69 int tmp_id;
70 int tmp_bus;
71
72 tmp_id = get_id(pnode);
73 tmp_bus = get_pci_bus(pnode);
74
75 if ((tmp_id == id) &&
76 (tmp_bus == bus)) {
77 break;
78 }
79
80 pnode = dev_next_node(pnode, "pci");
81 }
82 return (pnode);
83 }
84
85 /*
86 * get_pci_bus
87 *
88 * Determines the PCI bus, either A (0) or B (1). If the function cannot
89 * find the bus-ranges property, it returns -1.
90 */
91 int
get_pci_bus(Prom_node * pnode)92 get_pci_bus(Prom_node *pnode)
93 {
94 int *value;
95
96 /* look up the bus-range property */
97 if ((value = (int *)get_prop_val(find_prop(pnode, "bus-range"))) ==
98 NULL) {
99 return (-1);
100 }
101
102 if (*value == 0) {
103 return (1); /* B bus has a bus-range value = 0 */
104 } else {
105 return (0);
106 }
107 }
108
109
110
111 /*
112 * Find the PCI device number of this PCI device. If no device number can
113 * be determined, then return -1.
114 */
115 int
get_pci_device(Prom_node * pnode)116 get_pci_device(Prom_node *pnode)
117 {
118 void *value;
119
120 if ((value = get_prop_val(find_prop(pnode, "assigned-addresses"))) !=
121 NULL) {
122 return (PCI_DEVICE(*(int *)value));
123 } else {
124 return (-1);
125 }
126 }
127
128 /*
129 * Find the PCI device number of this PCI device. If no device number can
130 * be determined, then return -1.
131 */
132 int
get_pci_to_pci_device(Prom_node * pnode)133 get_pci_to_pci_device(Prom_node *pnode)
134 {
135 void *value;
136
137 if ((value = get_prop_val(find_prop(pnode, "reg"))) !=
138 NULL) {
139 return (PCI_DEVICE(*(int *)value));
140 } else {
141 return (-1);
142 }
143 }
144
145 /*
146 * free_io_cards
147 * Frees the memory allocated for an io card list.
148 */
149 void
free_io_cards(struct io_card * card_list)150 free_io_cards(struct io_card *card_list)
151 {
152 /* Free the list */
153 if (card_list != NULL) {
154 struct io_card *p, *q;
155
156 for (p = card_list, q = NULL; p != NULL; p = q) {
157 q = p->next;
158 free(p);
159 }
160 }
161 }
162
163
164 /*
165 * insert_io_card
166 * Inserts an io_card structure into the list. The list is maintained
167 * in order based on board number and slot number. Also, the storage
168 * for the "card" argument is assumed to be handled by the caller,
169 * so we won't touch it.
170 */
171 struct io_card *
insert_io_card(struct io_card * list,struct io_card * card)172 insert_io_card(struct io_card *list, struct io_card *card)
173 {
174 struct io_card *newcard;
175 struct io_card *p, *q;
176
177 if (card == NULL)
178 return (list);
179
180 /* Copy the card to be added into new storage */
181 newcard = (struct io_card *)malloc(sizeof (struct io_card));
182 if (newcard == NULL) {
183 perror("malloc");
184 exit(2);
185 }
186 (void) memcpy(newcard, card, sizeof (struct io_card));
187 newcard->next = NULL;
188
189 if (list == NULL)
190 return (newcard);
191
192 /* Find the proper place in the list for the new card */
193 for (p = list, q = NULL; p != NULL; q = p, p = p->next) {
194 if (newcard->board < p->board)
195 break;
196 if ((newcard->board == p->board) && (newcard->slot < p->slot))
197 break;
198 }
199
200 /* Insert the new card into the list */
201 if (q == NULL) {
202 newcard->next = p;
203 return (newcard);
204 } else {
205 newcard->next = p;
206 q->next = newcard;
207 return (list);
208 }
209 }
210
211
212 char *
fmt_manf_id(unsigned int encoded_id,char * outbuf)213 fmt_manf_id(unsigned int encoded_id, char *outbuf)
214 {
215 union manuf manuf;
216
217 /*
218 * Format the manufacturer's info. Note a small inconsistency we
219 * have to work around - Brooktree has it's part number in decimal,
220 * while Mitsubishi has it's part number in hex.
221 */
222 manuf.encoded_id = encoded_id;
223 switch (manuf.fld.manf) {
224 case MANF_BROOKTREE:
225 (void) sprintf(outbuf, "%s %d, version %d", "Brooktree",
226 manuf.fld.partno, manuf.fld.version);
227 break;
228
229 case MANF_MITSUBISHI:
230 (void) sprintf(outbuf, "%s %x, version %d", "Mitsubishi",
231 manuf.fld.partno, manuf.fld.version);
232 break;
233
234 default:
235 (void) sprintf(outbuf, "JED code %d, Part num 0x%x, version %d",
236 manuf.fld.manf, manuf.fld.partno, manuf.fld.version);
237 }
238 return (outbuf);
239 }
240
241
242 /*
243 * Find the sbus slot number of this Sbus device. If no slot number can
244 * be determined, then return -1.
245 */
246 int
get_sbus_slot(Prom_node * pnode)247 get_sbus_slot(Prom_node *pnode)
248 {
249 void *value;
250
251 if ((value = get_prop_val(find_prop(pnode, "reg"))) != NULL) {
252 return (*(int *)value);
253 } else {
254 return (-1);
255 }
256 }
257
258
259 /*
260 * This routine is the generic link into displaying system IO
261 * configuration. It displays the table header, then displays
262 * all the SBus cards, then displays all fo the PCI IO cards.
263 */
264 void
display_io_devices(Sys_tree * tree)265 display_io_devices(Sys_tree *tree)
266 {
267 Board_node *bnode;
268
269 /*
270 * TRANSLATION_NOTE
271 * Following string is used as a table header.
272 * Please maintain the current alignment in
273 * translation.
274 */
275 log_printf("\n", 0);
276 log_printf("=========================", 0);
277 log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0);
278 log_printf("=========================", 0);
279 log_printf("\n", 0);
280 log_printf("\n", 0);
281 bnode = tree->bd_list;
282 while (bnode != NULL) {
283 display_sbus(bnode);
284 display_pci(bnode);
285 display_ffb(bnode, 1);
286 bnode = bnode->next;
287 }
288 }
289
290 void
display_pci(Board_node * bnode)291 display_pci(Board_node *bnode)
292 {
293 #ifdef lint
294 bnode = bnode;
295 #endif
296 /*
297 * This function is intentionally empty
298 */
299 }
300
301
302 /*
303 * Print out all the io cards in the list. Also print the column
304 * headers if told to do so.
305 */
306 void
display_io_cards(struct io_card * list)307 display_io_cards(struct io_card *list)
308 {
309 static int banner = 0; /* Have we printed the column headings? */
310 struct io_card *p;
311
312 if (list == NULL)
313 return;
314
315 if (banner == 0) {
316 log_printf(" Bus Freq\n", 0);
317 log_printf("Brd Type MHz Slot "
318 "Name "
319 "Model", 0);
320 log_printf("\n", 0);
321 log_printf("--- ---- ---- ---------- "
322 "---------------------------- "
323 "--------------------", 0);
324 log_printf("\n", 0);
325 banner = 1;
326 }
327
328 for (p = list; p != NULL; p = p -> next) {
329 log_printf("%2d ", p->board, 0);
330 log_printf("%-4s ", p->bus_type, 0);
331 log_printf("%3d ", p->freq, 0);
332 /*
333 * We check to see if it's an int or
334 * a char string to display for slot.
335 */
336 if (p->slot == PCI_SLOT_IS_STRING)
337 log_printf("%10s ", p->slot_str, 0);
338 else
339 log_printf("%10d ", p->slot, 0);
340
341 log_printf("%-28.28s", p->name, 0);
342 if (strlen(p->name) > 28)
343 log_printf("+ ", 0);
344 else
345 log_printf(" ", 0);
346 log_printf("%-19.19s", p->model, 0);
347 if (strlen(p->model) > 19)
348 log_printf("+", 0);
349 log_printf("\n", 0);
350 }
351 }
352
353 /*
354 * Display all FFBs on this board. It can either be in tabular format,
355 * or a more verbose format.
356 */
357 void
display_ffb(Board_node * board,int table)358 display_ffb(Board_node *board, int table)
359 {
360 Prom_node *fb;
361 void *value;
362 struct io_card *card_list = NULL;
363 struct io_card card;
364 char *type;
365 char *label;
366
367 if (board == NULL)
368 return;
369
370 /* Fill in common information */
371 card.display = 1;
372 card.board = board->board_num;
373 (void) sprintf(card.bus_type, BUS_TYPE);
374 card.freq = sys_clk;
375
376 for (fb = dev_find_node_by_type(board->nodes, "device_type", "display");
377 fb != NULL;
378 fb = dev_next_node_by_type(fb, "device_type", "display")) {
379 value = get_prop_val(find_prop(fb, "name"));
380 if (value != NULL) {
381 if ((strcmp(FFB_NAME, value)) == 0) {
382 type = FFB_NAME;
383 label = "FFB";
384 } else if ((strcmp(AFB_NAME, value)) == 0) {
385 type = AFB_NAME;
386 label = "AFB";
387 } else
388 continue;
389 } else
390 continue;
391 if (table == 1) {
392 /* Print out in table format */
393
394 /* XXX - Get the slot number (hack) */
395 card.slot = get_id(fb);
396
397 /* Find out if it's single or double buffered */
398 (void) sprintf(card.name, "%s", label);
399 value = get_prop_val(find_prop(fb, "board_type"));
400 if (value != NULL)
401 if ((*(int *)value) & FFB_B_BUFF)
402 (void) sprintf(card.name,
403 "%s, Double Buffered", label);
404 else
405 (void) sprintf(card.name,
406 "%s, Single Buffered", label);
407
408 /*
409 * Print model number only if board_type bit 2
410 * is not set and it is not SUNW,XXX-XXXX.
411 */
412 card.model[0] = '\0';
413
414 if (strcmp(type, AFB_NAME) == 0) {
415 if (((*(int *)value) & 0x4) != 0x4) {
416 value = get_prop_val(find_prop(fb,
417 "model"));
418 if ((value != NULL) &&
419 (strcmp(value,
420 "SUNW,XXX-XXXX") != 0)) {
421 (void) sprintf(card.model, "%s",
422 (char *)value);
423 }
424 }
425 } else {
426 value = get_prop_val(find_prop(fb, "model"));
427 if (value != NULL)
428 (void) sprintf(card.model, "%s",
429 (char *)value);
430 }
431
432 card_list = insert_io_card(card_list, &card);
433 } else {
434 /* print in long format */
435 char device[MAXSTRLEN];
436 int fd = -1;
437 struct dirent *direntp;
438 DIR *dirp;
439 union strap_un strap;
440 struct ffb_sys_info fsi;
441
442 /* Find the device node using upa-portid/portid */
443 value = get_prop_val(find_prop(fb, "upa-portid"));
444 if (value == NULL)
445 value = get_prop_val(find_prop(fb, "portid"));
446
447 if (value == NULL)
448 continue;
449
450 (void) sprintf(device, "%s@%x", type,
451 *(int *)value);
452 if ((dirp = opendir("/devices")) == NULL)
453 continue;
454
455 while ((direntp = readdir(dirp)) != NULL) {
456 if (strstr(direntp->d_name, device) != NULL) {
457 (void) sprintf(device, "/devices/%s",
458 direntp->d_name);
459 fd = open(device, O_RDWR, 0666);
460 break;
461 }
462 }
463 (void) closedir(dirp);
464
465 if (fd == -1)
466 continue;
467
468 if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
469 continue;
470
471 log_printf("%s Hardware Configuration:\n", label, 0);
472 log_printf("-----------------------------------\n", 0);
473
474 strap.ffb_strap_bits = fsi.ffb_strap_bits;
475 log_printf("\tBoard rev: %d\n",
476 (int)strap.fld.board_rev, 0);
477 log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
478 log_printf("\tDAC: %s\n",
479 fmt_manf_id(fsi.dac_version, device), 0);
480 log_printf("\t3DRAM: %s\n",
481 fmt_manf_id(fsi.fbram_version, device), 0);
482 log_printf("\n", 0);
483 }
484
485 }
486 display_io_cards(card_list);
487 free_io_cards(card_list);
488 }
489
490
491 /*
492 * Display all the SBus IO cards on this board.
493 */
494 void
display_sbus(Board_node * board)495 display_sbus(Board_node *board)
496 {
497 struct io_card card;
498 struct io_card *card_list = NULL;
499 int freq;
500 int card_num;
501 void *value;
502 Prom_node *sbus;
503 Prom_node *card_node;
504
505 if (board == NULL)
506 return;
507
508 for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL;
509 sbus = dev_next_node(sbus, SBUS_NAME)) {
510
511 /* Skip failed nodes for now */
512 if (node_failed(sbus))
513 continue;
514
515 /* Calculate SBus frequency in MHz */
516 value = get_prop_val(find_prop(sbus, "clock-frequency"));
517 if (value != NULL)
518 freq = ((*(int *)value) + 500000) / 1000000;
519 else
520 freq = -1;
521
522 for (card_node = sbus->child; card_node != NULL;
523 card_node = card_node->sibling) {
524 char *model;
525 char *name;
526 char *child_name;
527
528 card_num = get_sbus_slot(card_node);
529 if (card_num == -1)
530 continue;
531
532 /* Fill in card information */
533 card.display = 1;
534 card.freq = freq;
535 card.board = board->board_num;
536 (void) sprintf(card.bus_type, "SBus");
537 card.slot = card_num;
538 card.status[0] = '\0';
539
540 /* Try and get card status */
541 value = get_prop_val(find_prop(card_node, "status"));
542 if (value != NULL)
543 (void) strncpy(card.status, (char *)value,
544 MAXSTRLEN);
545
546 /* XXX - For now, don't display failed cards */
547 if (strstr(card.status, "fail") != NULL)
548 continue;
549
550 /* Now gather all of the node names for that card */
551 model = (char *)get_prop_val(find_prop(card_node,
552 "model"));
553 name = get_node_name(card_node);
554
555 if (name == NULL)
556 continue;
557
558 card.name[0] = '\0';
559 card.model[0] = '\0';
560
561 /* Figure out how we want to display the name */
562 child_name = get_node_name(card_node->child);
563 if ((card_node->child != NULL) &&
564 (child_name != NULL)) {
565 value = get_prop_val(find_prop(card_node->child,
566 "device_type"));
567 if (value != NULL)
568 (void) sprintf(card.name, "%s/%s (%s)",
569 name, child_name,
570 (char *)value);
571 else
572 (void) sprintf(card.name, "%s/%s", name,
573 child_name);
574 } else {
575 (void) strncpy(card.name, name, MAXSTRLEN);
576 }
577
578 if (model != NULL)
579 (void) strncpy(card.model, model, MAXSTRLEN);
580
581 card_list = insert_io_card(card_list, &card);
582 }
583 }
584
585 /* We're all done gathering card info, now print it out */
586 display_io_cards(card_list);
587 free_io_cards(card_list);
588 }
589
590
591 /*
592 * Get slot-names properties from parent node and
593 * store them in an array.
594 */
595 int
populate_slot_name_arr(Prom_node * pci,int * slot_name_bits,char ** slot_name_arr,int num_slots)596 populate_slot_name_arr(Prom_node *pci, int *slot_name_bits,
597 char **slot_name_arr, int num_slots)
598 {
599 int i, j, bit_mask;
600 char *value;
601
602 value = (char *)get_prop_val(find_prop(pci, "slot-names"));
603 D_PRINTF("\n populate_slot_name_arr: value = [0x%x]\n", value);
604
605 if (value != NULL) {
606 char *strings_arr[MAX_SLOTS_PER_IO_BD];
607 bit_mask = *slot_name_bits = *(int *)value;
608 D_PRINTF("\nslot_names 1st integer = [0x%x]", *slot_name_bits);
609
610 /* array starts after first int */
611 strings_arr[0] = value + sizeof (int);
612
613 /*
614 * break the array out into num_slots number of strings
615 */
616 for (i = 1; i < num_slots; i++) {
617 strings_arr[i] = (char *)strings_arr[i - 1]
618 + strlen(strings_arr[i - 1]) + 1;
619 }
620
621 /*
622 * process array of slot_names to remove blanks
623 */
624 j = 0;
625 for (i = 0; i < num_slots; i++) {
626 if ((bit_mask >> i) & 0x1)
627 slot_name_arr[i] = strings_arr[j++];
628 else
629 slot_name_arr[i] = "";
630
631 D_PRINTF("\nslot_name_arr[%d] = [%s]", i,
632 slot_name_arr[i]);
633 }
634 return (0);
635 } else {
636 D_PRINTF("\n populate_slot_name_arr: - psycho with no "
637 "slot-names\n");
638 return (0);
639 }
640 }
641
642 int
get_card_frequency(Prom_node * pci)643 get_card_frequency(Prom_node *pci)
644 {
645 char *value = get_prop_val(find_prop(pci, "clock-frequency"));
646
647 if (value == NULL)
648 return (-1);
649 else
650 return (int)(((*(int *)value) + 500000) / 1000000);
651
652 }
653
654 void
get_dev_func_num(Prom_node * card_node,int * dev_no,int * func_no)655 get_dev_func_num(Prom_node *card_node, int *dev_no, int *func_no)
656 {
657
658 void *value = get_prop_val(find_prop(card_node, "reg"));
659
660 if (value != NULL) {
661 int int_val = *(int *)value;
662 *dev_no = PCI_REG_TO_DEV(int_val);
663 *func_no = PCI_REG_TO_FUNC(int_val);
664 } else {
665 *dev_no = -1;
666 *func_no = -1;
667 }
668 }
669
670 void
get_pci_class_codes(Prom_node * card_node,int * class_code,int * subclass_code)671 get_pci_class_codes(Prom_node *card_node, int *class_code, int *subclass_code)
672 {
673 int class_code_reg = get_pci_class_code_reg(card_node);
674
675 *class_code = CLASS_REG_TO_CLASS(class_code_reg);
676 *subclass_code = CLASS_REG_TO_SUBCLASS(class_code_reg);
677 }
678
679 int
is_pci_bridge(Prom_node * card_node,char * name)680 is_pci_bridge(Prom_node *card_node, char *name)
681 {
682 int class_code, subclass_code;
683
684 if (card_node == NULL)
685 return (FALSE);
686
687 get_pci_class_codes(card_node, &class_code, &subclass_code);
688
689 if ((strncmp(name, "pci", 3) == 0) &&
690 (class_code == PCI_BRIDGE_CLASS) &&
691 (subclass_code == PCI_PCI_BRIDGE_SUBCLASS))
692 return (TRUE);
693 else
694 return (FALSE);
695 }
696
697 int
is_pci_bridge_other(Prom_node * card_node,char * name)698 is_pci_bridge_other(Prom_node *card_node, char *name)
699 {
700 int class_code, subclass_code;
701
702 if (card_node == NULL)
703 return (FALSE);
704
705 get_pci_class_codes(card_node, &class_code, &subclass_code);
706
707 if ((strncmp(name, "pci", 3) == 0) &&
708 (class_code == PCI_BRIDGE_CLASS) &&
709 (subclass_code == PCI_SUBCLASS_OTHER))
710 return (TRUE);
711 else
712 return (FALSE);
713 }
714 void
get_pci_card_model(Prom_node * card_node,char * model)715 get_pci_card_model(Prom_node *card_node, char *model)
716 {
717 char *name = get_prop_val(find_prop(card_node, "name"));
718 char *value = get_prop_val(find_prop(card_node, "model"));
719 int pci_bridge = is_pci_bridge(card_node, name);
720
721 if (value == NULL)
722 model[0] = '\0';
723 else
724 (void) sprintf(model, "%s",
725 (char *)value);
726
727 if (pci_bridge) {
728 if (strlen(model) == 0)
729 (void) sprintf(model,
730 "%s", "pci-bridge");
731 else
732 (void) sprintf(model,
733 "%s/pci-bridge", model);
734 }
735 }
736
737 void
create_io_card_name(Prom_node * card_node,char * name,char * card_name)738 create_io_card_name(Prom_node *card_node, char *name, char *card_name)
739 {
740 char *value = get_prop_val(find_prop(card_node, "compatible"));
741 char *child_name;
742 char buf[MAXSTRLEN];
743
744 if (value != NULL) {
745 (void) sprintf(buf, "%s-%s", name,
746 (char *)value);
747 } else
748 (void) sprintf(buf, "%s", name);
749
750 name = buf;
751
752 child_name = (char *)get_node_name(card_node->child);
753
754 if ((card_node->child != NULL) &&
755 (child_name != NULL)) {
756 value = get_prop_val(find_prop(card_node->child,
757 "device_type"));
758 if (value != NULL)
759 (void) sprintf(card_name, "%s/%s (%s)",
760 name, child_name,
761 (char *)value);
762 else
763 (void) sprintf(card_name, "%s/%s", name,
764 child_name);
765 } else {
766 (void) sprintf(card_name, "%s", (char *)name);
767 }
768 }
769
770
771 /*
772 * Desktop display_psycho_pci
773 * Display all the psycho based PCI IO cards on this board.
774 */
775
776 /* ARGSUSED */
777 void
display_psycho_pci(Board_node * board)778 display_psycho_pci(Board_node *board)
779 {
780 struct io_card *card_list = NULL;
781 struct io_card card;
782 void *value;
783
784 Prom_node *pci, *card_node, *pci_bridge_node = NULL;
785 char *name;
786 int slot_name_bits, pci_bridge_dev_no,
787 class_code, subclass_code,
788 pci_pci_bridge;
789 char *slot_name_arr[MAX_SLOTS_PER_IO_BD];
790
791 if (board == NULL)
792 return;
793
794 /* Initialize all the common information */
795 card.display = 1;
796 card.board = board->board_num;
797 (void) sprintf(card.bus_type, "PCI");
798
799 for (pci = dev_find_node_by_type(board->nodes, "model", "SUNW,psycho");
800 pci != NULL;
801 pci = dev_next_node_by_type(pci, "model", "SUNW,psycho")) {
802
803 /*
804 * If we have reached a pci-to-pci bridge node,
805 * we are one level below the 'pci' nodes level
806 * in the device tree. To get back to that level,
807 * the search should continue with the sibling of
808 * the parent or else the remaining 'pci' cards
809 * will not show up in the output.
810 */
811 if (find_prop(pci, "upa-portid") == NULL) {
812 if ((pci->parent->sibling != NULL) &&
813 (strcmp(get_prop_val(
814 find_prop(pci->parent->sibling,
815 "name")), PCI_NAME) == 0))
816 pci = pci->parent->sibling;
817 else {
818 pci = pci->parent->sibling;
819 continue;
820 }
821 }
822
823 D_PRINTF("\n\n------->Looking at device [%s][%d] - [%s]\n",
824 PCI_NAME, *((int *)get_prop_val(find_prop(
825 pci, "upa-portid"))),
826 get_prop_val(find_prop(pci, "model")));
827
828 /* Skip all failed nodes for now */
829 if (node_failed(pci))
830 continue;
831
832 /* Fill in frequency */
833 card.freq = get_card_frequency(pci);
834
835 /*
836 * Each PSYCHO device has a slot-names property that can be
837 * used to determine the slot-name string for each IO
838 * device under this node. We get this array now and use
839 * it later when looking at the children of this PSYCHO.
840 */
841 if ((populate_slot_name_arr(pci, &slot_name_bits,
842 (char **)&slot_name_arr, MAX_SLOTS_PER_IO_BD)) != 0)
843 goto next_card;
844
845 /* Walk through the PSYCHO children */
846 card_node = pci->child;
847 while (card_node != NULL) {
848
849 pci_pci_bridge = FALSE;
850
851 /* If it doesn't have a name, skip it */
852 name = (char *)get_prop_val(
853 find_prop(card_node, "name"));
854 if (name == NULL)
855 goto next_card;
856
857 /* get dev# and func# for this card. */
858 get_dev_func_num(card_node, &card.dev_no,
859 &card.func_no);
860
861 /* get class/subclass code for this card. */
862 get_pci_class_codes(card_node, &class_code,
863 &subclass_code);
864
865 D_PRINTF("\nName [%s] - ", name);
866 D_PRINTF("device no [%d] - ", card.dev_no);
867 D_PRINTF("class_code [%d] subclass_code [%d] - ",
868 class_code, subclass_code);
869
870 /*
871 * Weed out PCI Bridge, subclass 'other' and
872 * ebus nodes.
873 */
874 if (((class_code == PCI_BRIDGE_CLASS) &&
875 (subclass_code == PCI_SUBCLASS_OTHER)) ||
876 (strstr(name, "ebus"))) {
877 D_PRINTF("\nSkip ebus/class-other nodes [%s]",
878 name);
879 goto next_card;
880 }
881
882 /*
883 * If this is a PCI bridge, then we store it's dev_no
884 * so that it's children can use it for getting at
885 * the slot_name.
886 */
887 if (is_pci_bridge(card_node, name)) {
888 pci_bridge_dev_no = card.dev_no;
889 pci_bridge_node = card_node;
890 pci_pci_bridge = TRUE;
891 D_PRINTF("\nPCI Bridge detected\n");
892 }
893
894 /*
895 * If we are the child of a pci_bridge we use the
896 * dev# of the pci_bridge as an index to get
897 * the slot number. We know that we are a child of
898 * a pci-bridge if our parent is the same as the last
899 * pci_bridge node found above.
900 */
901 if (card_node->parent == pci_bridge_node)
902 card.dev_no = pci_bridge_dev_no;
903
904 /* Get slot-names property from slot_names_arr. */
905 get_slot_number_str(&card, (char **)slot_name_arr,
906 slot_name_bits);
907
908 if (slot_name_bits)
909 D_PRINTF("\nIO Card [%s] dev_no [%d] SlotStr "
910 "[%s] slot [%s]", name, card.dev_no,
911 slot_name_arr[card.dev_no],
912 card.slot_str);
913
914 /* XXX - Don't know how to get status for PCI cards */
915 card.status[0] = '\0';
916
917 /* Get the model of this card */
918 get_pci_card_model(card_node, (char *)&card.model);
919
920 /*
921 * If we haven't figured out the frequency yet,
922 * try and get it from the card.
923 */
924 value = get_prop_val(find_prop(pci, "clock-frequency"));
925 if (value != NULL && card.freq == -1)
926 card.freq = ((*(int *)value) + 500000)
927 / 1000000;
928
929
930 /* Figure out how we want to display the name */
931 create_io_card_name(card_node, name,
932 (char *)&card.name);
933
934 if (card.freq != -1)
935 card_list = insert_io_card(card_list, &card);
936
937 next_card:
938 /*
939 * If we are done with the children of the pci bridge,
940 * we must continue with the remaining siblings of
941 * the pci-to-pci bridge - otherwise we move onto our
942 * own sibling.
943 */
944 if (pci_pci_bridge) {
945 if (card_node->child != NULL)
946 card_node = card_node->child;
947 else
948 card_node = card_node->sibling;
949 } else {
950 if ((card_node->parent == pci_bridge_node) &&
951 (card_node->sibling == NULL))
952 card_node = pci_bridge_node->sibling;
953 else
954 card_node = card_node->sibling;
955 }
956 } /* end-while */
957 } /* end-for */
958
959 D_PRINTF("\n\n");
960
961 display_io_cards(card_list);
962 free_io_cards(card_list);
963 }
964
965 void
get_slot_number_str(struct io_card * card,char ** slot_name_arr,int slot_name_bits)966 get_slot_number_str(struct io_card *card, char **slot_name_arr,
967 int slot_name_bits)
968 {
969 if (card->dev_no != -1) {
970 char *slot;
971 /*
972 * slot_name_bits is a mask of the plug-in slots so if our
973 * dev_no does not appear in this mask we must be an
974 * on_board device so set the slot to 'On-Board'
975 */
976 if (slot_name_bits & (1 << card->dev_no)) {
977 /* we are a plug-in card */
978 slot = slot_name_arr[card->dev_no];
979 if (strlen(slot) != 0) {
980 (void) sprintf(card->slot_str, "%s",
981 slot);
982 } else
983 (void) sprintf(card->slot_str, "-");
984 } else {
985 /* this is an on-board dev. */
986 sprintf(card->slot_str, "On-Board");
987 }
988
989 } else {
990 (void) sprintf(card->slot_str, "%c", '-');
991 }
992
993 /* Informs display_io_cards to print slot_str instead of slot */
994 card->slot = PCI_SLOT_IS_STRING;
995 }
996
997
998 /*
999 * The output of a number of I/O cards are identical so we need to
1000 * differentiate between them.
1001 *
1002 * This function is called by the platform specific code and it decides
1003 * if the card needs further processing.
1004 *
1005 * It can be extended in the future if card types other than QLC have
1006 * the same problems.
1007 */
1008 void
distinguish_identical_io_cards(char * name,Prom_node * node,struct io_card * card)1009 distinguish_identical_io_cards(char *name, Prom_node *node,
1010 struct io_card *card)
1011 {
1012 if ((name == NULL) || (node == NULL))
1013 return;
1014
1015 if (strcmp(name, "SUNW,qlc") == 0)
1016 decode_qlc_card_model_prop(node, card);
1017 }
1018
1019
1020 /*
1021 * The name/model properties for a number of the QLC FCAL PCI cards are
1022 * identical (*), so we need to distinguish them using the subsystem-id
1023 * and modify the model string to be more informative.
1024 *
1025 * (*) Currently the problem cards are:
1026 * Amber
1027 * Crystal+
1028 */
1029 void
decode_qlc_card_model_prop(Prom_node * card_node,struct io_card * card)1030 decode_qlc_card_model_prop(Prom_node *card_node, struct io_card *card)
1031 {
1032 void *value = NULL;
1033
1034 if (card_node == NULL)
1035 return;
1036
1037 value = get_prop_val(find_prop(card_node, "subsystem-id"));
1038 if (value != NULL) {
1039 int id = *(int *)value;
1040
1041 switch (id) {
1042 case AMBER_SUBSYSTEM_ID:
1043 (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
1044 AMBER_CARD_NAME);
1045 break;
1046
1047 case CRYSTAL_SUBSYSTEM_ID:
1048 (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
1049 CRYSTAL_CARD_NAME);
1050 break;
1051
1052 default:
1053 /*
1054 * If information has been saved into the model field
1055 * before this function was called we will keep it as
1056 * it probably will be more meaningful that the
1057 * subsystem-id, otherwise we save the subsystem-id in
1058 * the hope that it will distinguish the cards.
1059 */
1060 if (strcmp(card->model, "") == 0) {
1061 (void) snprintf(card->model, MAX_QLC_MODEL_LEN,
1062 "0x%x", id);
1063 }
1064 break;
1065 }
1066 }
1067 }
1068