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