1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Starcat Platform specific functions.
26 *
27 * called when :
28 * machine_type == MTYPE_STARCAT
29 */
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <kvm.h>
39 #include <varargs.h>
40 #include <time.h>
41 #include <dirent.h>
42 #include <fcntl.h>
43 #include <assert.h>
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <sys/utsname.h>
48 #include <sys/openpromio.h>
49 #include <libintl.h>
50 #include <syslog.h>
51 #include <sys/dkio.h>
52 #include <pdevinfo.h>
53 #include <display.h>
54 #include <pdevinfo_sun4u.h>
55 #include <display_sun4u.h>
56 #include <libprtdiag.h>
57
58 #define HZ_TO_MHZ(x) (((x) + 500000) / 1000000)
59 #define PORTID_TO_EXPANDER(p) (((p) >> 5) & 0x1f)
60 #define PORTID_TO_SLOT(p) (((p) >> 3) & 0x1)
61 #define PORTID_TO_INSTANCE(p) ((p) & 0x3)
62 #define SCHIZO_COMPATIBLE "pci108e,8001"
63 #define XMITS_COMPATIBLE "pci108e,8002"
64 #define SC_BOARD_TYPE(id) (PORTID_TO_SLOT(id) ? "IO" : "SB")
65
66 #ifndef TEXT_DOMAIN
67 #define TEXT_DOMAIN "SYS_TEST"
68 #endif /* TEXT_DOMAIN */
69
70 #define DEFAULT_MAX_FREQ 66 /* 66 MHz */
71 #define PCIX_MAX_FREQ 90 /* 90 MHz */
72
73 /*
74 * these functions will overlay the symbol table of libprtdiag
75 * at runtime (Starcat systems only)
76 */
77
78 int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
79 void *get_prop_val(Prop *prop);
80 Prop *find_prop(Prom_node *pnode, char *name);
81 char *get_node_name(Prom_node *pnode);
82 char *get_node_type(Prom_node *pnode);
83 void add_node(Sys_tree *, Prom_node *);
84 void display_pci(Board_node *);
85 void display_ffb(Board_node *, int);
86 void display_io_cards(struct io_card *list);
87 void display_cpu_devices(Sys_tree *tree);
88 void display_cpus(Board_node *board);
89 void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
90 void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
91 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
92 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
93 struct system_kstat_data *kstats);
94
95 /* Local Functions */
96 static void starcat_disp_hw_revisions(Prom_node *root);
97 static void display_io_max_bus_speed(struct io_card *p);
98 static void display_io_slot_info(struct io_card *p);
99
100 /* The bus max freq is determined based on board level in use */
101 int board_bus_max_freq = DEFAULT_MAX_FREQ; /* 66MHz default */
102
103 /*
104 * display_pci
105 * Display all the PCI IO cards on this board.
106 */
107 void
display_pci(Board_node * board)108 display_pci(Board_node *board)
109 {
110 struct io_card *card_list = NULL;
111 struct io_card card;
112 void *value;
113 Prom_node *pci;
114 Prom_node *card_node;
115 Prom_node *pci_bridge_node = NULL;
116 char *slot_name_arr[MAX_SLOTS_PER_IO_BD] = {NULL};
117 char *slot_name = NULL;
118 int slot_name_bits;
119 int slot_name_offset = 0;
120 char *child_name;
121 char *name, *type;
122 char buf[MAXSTRLEN];
123 int *int_val;
124 int pci_bus;
125 int pci_bridge = 0;
126 int pci_bridge_dev_no;
127 int child_dev_no;
128 int i;
129 int portid;
130 int version, *pversion;
131
132 if (board == NULL)
133 return;
134
135 /* Initialize all the common information */
136 card.display = TRUE;
137 card.board = board->board_num;
138 card.node_id = board->node_id;
139
140 /*
141 * Search for each schizo, then find/display all nodes under
142 * each schizo node found. Since the model property "SUNW,schizo"
143 * is not supported on Starcat, we must match on the compatible
144 * property "pci108e,8001".
145 */
146 for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
147 pci != NULL;
148 pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
149
150 /* set max freq for this board */
151 board_bus_max_freq = DEFAULT_MAX_FREQ;
152 /*
153 * Find out if this is a PCI or cPCI IO Board.
154 * If "enum-impl" property exists in pci node => cPCI.
155 */
156 value = get_prop_val(find_prop(pci, "enum-impl"));
157 if (value == NULL) {
158 (void) sprintf(card.bus_type, "PCI");
159 } else {
160 (void) sprintf(card.bus_type, "cPCI");
161 }
162
163 if (strstr((char *)get_prop_val(
164 find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
165 sprintf(card.notes, "%s", XMITS_COMPATIBLE);
166 /*
167 * With XMITS 3.X and PCI-X mode, the bus speed
168 * can be higher than 66MHZ.
169 */
170 value = (int *)get_prop_val
171 (find_prop(pci, "module-revision#"));
172 if (value) {
173 pversion = (int *)value;
174 version = *pversion;
175 if (version >= 4)
176 board_bus_max_freq = PCIX_MAX_FREQ;
177 }
178 } else if (strstr((char *)get_prop_val(
179 find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
180 sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
181 else
182 sprintf(card.notes, " ");
183
184 /*
185 * Get slot-names property from parent node and
186 * store the individual slot names in an array.
187 * This is more general than Starcat requires, but
188 * it is correct, according to the slot-names property.
189 */
190 value = (char *)get_prop_val(find_prop(pci, "slot-names"));
191 if (value == NULL) {
192 /*
193 * No slot_names property. This could be an Xmits
194 * card, so check the child node for slot-names property
195 */
196 value = (char *)get_prop_val(
197 find_prop(pci->child, "slot-names"));
198 }
199
200 if (value != NULL) {
201 /* Get the 4 byte bitmask and pointer to first name */
202 slot_name_bits = *(int *)value;
203 if (slot_name_bits > 0)
204 slot_name_offset = slot_name_bits - 1;
205 slot_name = (char *)value + sizeof (int);
206
207 for (i = 0; i < MAX_SLOTS_PER_IO_BD; i++) {
208 if (! (slot_name_bits & (1 << i))) {
209 slot_name_arr[i] = (char *)NULL;
210 continue;
211 }
212
213 /*
214 * Save the name pointer into the array
215 * and advance it past the end of this
216 * slot name
217 */
218 slot_name_arr[i] = slot_name;
219 slot_name += strlen(slot_name) + 1;
220 }
221 slot_name = (char *)NULL;
222 }
223
224 /*
225 * Search for Children of this node ie. Cards.
226 * Note: any of these cards can be a pci-bridge
227 * that itself has children. If we find a
228 * pci-bridge we need to handle it specially.
229 */
230 card_node = pci->child;
231 while (card_node != NULL) {
232 pci_bridge = 0;
233
234 /* If it doesn't have a name, skip it */
235 name = (char *)get_prop_val(
236 find_prop(card_node, "name"));
237 if (name == NULL) {
238 card_node = card_node->sibling;
239 continue;
240 }
241
242 /*
243 * get dev# and func# for this card from the
244 * 'reg' property.
245 */
246 int_val = (int *)get_prop_val(
247 find_prop(card_node, "reg"));
248 if (int_val != NULL) {
249 card.dev_no = (((*int_val) & 0xF800) >> 11);
250 card.func_no = (((*int_val) & 0x700) >> 8);
251 } else {
252 card.dev_no = -1;
253 card.func_no = -1;
254 }
255
256 /*
257 * If this is a pci-bridge, then store it's dev#
258 * as its children nodes need this to get their slot#.
259 * We set the pci_bridge flag so that we know we are
260 * looking at a pci-bridge node. This flag gets reset
261 * every time we enter this while loop.
262 */
263
264 /*
265 * Check for a PCI-PCI Bridge for PCI and cPCI
266 * IO Boards using the name and type properties.
267 */
268 type = (char *)get_prop_val(
269 find_prop(card_node, "device_type"));
270 if ((type != NULL) &&
271 (strncmp(name, "pci", 3) == 0) &&
272 (strcmp(type, "pci") == 0)) {
273 pci_bridge_dev_no = card.dev_no;
274 pci_bridge_node = card_node;
275 pci_bridge = TRUE;
276 }
277
278 /*
279 * Get slot-names property from slot_names_arr.
280 * If we are the child of a pci_bridge we use the
281 * dev# of the pci_bridge as an index to get
282 * the slot number. We know that we are a child of
283 * a pci-bridge if our parent is the same as the last
284 * pci_bridge node found above.
285 */
286 if (card.dev_no != -1) {
287 /*
288 * We compare this card's parent node with the
289 * pci_bridge_node to see if it's a child.
290 */
291 if (card_node->parent == pci_bridge_node) {
292 /* use dev_no of pci_bridge */
293 child_dev_no = pci_bridge_dev_no - 1;
294 } else {
295 /* use card's own dev_no */
296 child_dev_no = card.dev_no - 1;
297 }
298
299 if (child_dev_no < MAX_SLOTS_PER_IO_BD &&
300 child_dev_no >= 0 &&
301 slot_name_arr
302 [child_dev_no + slot_name_offset] != NULL) {
303
304 slot_name = slot_name_arr[
305 child_dev_no + slot_name_offset];
306 } else
307 slot_name = (char *)NULL;
308
309 if (slot_name != NULL && slot_name[0] != '\0') {
310 (void) sprintf(card.slot_str, "%s",
311 slot_name);
312 } else {
313 (void) sprintf(card.slot_str, "-");
314 }
315 } else {
316 (void) sprintf(card.slot_str, "%c", '-');
317 }
318
319 /*
320 * Get the portid of the schizo that this card
321 * lives under.
322 */
323 portid = -1;
324 value = get_prop_val(find_prop(pci, "portid"));
325 if (value != NULL) {
326 portid = *(int *)value;
327 }
328 card.schizo_portid = portid;
329
330 #ifdef DEBUG
331 (void) sprintf(card.notes, "%s portid [%d]"
332 " dev_no [%d] slot_name[%s] name_bits[%#x]",
333 card.notes, portid, card.dev_no,
334 ((slot_name != NULL) ? slot_name : "NULL"),
335 slot_name_bits);
336 #endif /* DEBUG */
337
338 /*
339 * Find out whether this is PCI bus A or B
340 * using the 'reg' property.
341 */
342 int_val = (int *)get_prop_val
343 (find_prop(pci, "reg"));
344
345 if (int_val != NULL) {
346 int_val ++; /* skip over first integer */
347 pci_bus = ((*int_val) & 0x7f0000);
348 if (pci_bus == 0x600000)
349 card.pci_bus = 'A';
350 else if (pci_bus == 0x700000)
351 card.pci_bus = 'B';
352 else
353 card.pci_bus = '-';
354 } else {
355 card.pci_bus = '-';
356 }
357
358
359 /*
360 * Check for failed status.
361 */
362 if (node_failed(card_node))
363 strcpy(card.status, "fail");
364 else
365 strcpy(card.status, "ok");
366
367 /* Get the model of this card */
368 value = get_prop_val(find_prop(card_node, "model"));
369 if (value == NULL)
370 card.model[0] = '\0';
371 else {
372 (void) sprintf(card.model, "%s", (char *)value);
373 /*
374 * If we wish to exclude onboard devices
375 * (such as SBBC) then this is the place
376 * and here is how to do it:
377 *
378 * if (strcmp(card.model, "SUNW,sbbc") == 0) {
379 * card_node = card_node->sibling;
380 * continue;
381 * }
382 */
383 }
384
385 /*
386 * The card may have a "clock-frequency" but we
387 * are not interested in that. Instead we get the
388 * "clock-frequency" of the PCI Bus that the card
389 * resides on. PCI-A can operate at 33Mhz or 66Mhz
390 * depending on what card is plugged into the Bus.
391 * PCI-B always operates at 33Mhz.
392 *
393 */
394 int_val = get_prop_val(find_prop(pci,
395 "clock-frequency"));
396 if (int_val != NULL) {
397 card.freq = HZ_TO_MHZ(*int_val);
398 } else {
399 card.freq = -1;
400 }
401
402 /*
403 * Figure out how we want to display the name
404 */
405 value = get_prop_val(find_prop(card_node,
406 "compatible"));
407 if (value != NULL) {
408 /* use 'name'-'compatible' */
409 (void) sprintf(buf, "%s-%s", name,
410 (char *)value);
411 } else {
412 /* just use 'name' */
413 (void) sprintf(buf, "%s", name);
414 }
415 name = buf;
416
417 /*
418 * If this node has children, add the device_type
419 * of the child to the name value of this card.
420 */
421 child_name = (char *)get_node_name(card_node->child);
422 if ((card_node->child != NULL) &&
423 (child_name != NULL)) {
424 value = get_prop_val(find_prop(card_node->child,
425 "device_type"));
426 if (value != NULL) {
427 /* add device_type of child to name */
428 (void) sprintf(card.name, "%s/%s (%s)",
429 name, child_name,
430 (char *)value);
431 } else {
432 /* just add child's name */
433 (void) sprintf(card.name, "%s/%s",
434 name, child_name);
435 }
436 } else {
437 /* childless, just the card's name */
438 (void) sprintf(card.name, "%s", (char *)name);
439 }
440
441 /*
442 * If this is a pci-bridge, then add the word
443 * 'pci-bridge' to its model.
444 */
445 if (pci_bridge) {
446 if (card.model[0] == '\0')
447 (void) sprintf(card.model,
448 "%s", "pci-bridge");
449 else
450 (void) strcat(card.model,
451 "/pci-bridge");
452 }
453
454 /* insert this card in the list to be displayed later */
455 card_list = insert_io_card(card_list, &card);
456
457 /*
458 * If we are dealing with a pci-bridge, we need to move
459 * down to the children of this bridge, if there are
460 * any, otherwise its siblings.
461 *
462 * If not a bridge, we are either dealing with a regular
463 * card (in which case we move onto the sibling of this
464 * card) or we are dealing with a child of a pci-bridge
465 * (in which case we move onto the child's siblings or
466 * if there are no more siblings for this child, we
467 * move onto the parent's siblings). I hope you're
468 * getting all this, there will be an exam later.
469 */
470 if (pci_bridge) {
471 if (card_node->child != NULL)
472 card_node = card_node->child;
473 else
474 card_node = card_node->sibling;
475 } else {
476 /*
477 * If our parent is a pci-bridge but there
478 * are no more of its children to process we
479 * move back up to our parent's sibling,
480 * otherwise we move onto our own sibling.
481 */
482 if ((card_node->parent == pci_bridge_node) &&
483 (card_node->sibling == NULL))
484 card_node =
485 pci_bridge_node->sibling;
486 else
487 card_node = card_node->sibling;
488 }
489
490 } /* end while (card_node ...) loop */
491
492 } /* end for (pci ...) loop */
493
494 display_io_cards(card_list);
495 free_io_cards(card_list);
496 }
497
498 /*
499 * display_ffb
500 *
501 * There are no FFB's on a Starcat, however in the generic library,
502 * the display_ffb() function is implemented so we have to define an
503 * empty function here.
504 */
505 /*ARGSUSED0*/
506 void
display_ffb(Board_node * board,int table)507 display_ffb(Board_node *board, int table)
508 {
509 }
510
511 /*
512 * add_node
513 *
514 * This function adds a board node to the board structure where that
515 * that node's physical component lives.
516 */
517 void
add_node(Sys_tree * root,Prom_node * pnode)518 add_node(Sys_tree *root, Prom_node *pnode)
519 {
520 int portid = -1;
521 int nodeid = -1;
522 void *value;
523 Board_node *bnode;
524 Prom_node *p;
525 char *type;
526
527 /* Get the board number of this board from the portid prop */
528 if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
529 if (type = get_node_type(pnode))
530 if (strcmp(type, "cpu") == 0)
531 value = get_prop_val(find_prop(pnode->parent,
532 "portid"));
533 }
534 if (value != NULL) {
535 portid = *(int *)value;
536 nodeid = PORTID_TO_EXPANDER(portid);
537 }
538
539 /* find the board node with the same board number */
540 if ((bnode = find_board(root, portid)) == NULL) {
541 bnode = insert_board(root, portid);
542 bnode->board_type = UNKNOWN_BOARD;
543 bnode->node_id = nodeid;
544 }
545
546 /* now attach this prom node to the board list */
547 /* Insert this node at the end of the list */
548 pnode->sibling = NULL;
549 if (bnode->nodes == NULL)
550 bnode->nodes = pnode;
551 else {
552 p = bnode->nodes;
553 while (p->sibling != NULL)
554 p = p->sibling;
555 p->sibling = pnode;
556 }
557 }
558
559
560
561 /*
562 * Print out all the io cards in the list. Also print the column
563 * headers if told to do so.
564 */
565 void
display_io_cards(struct io_card * list)566 display_io_cards(struct io_card *list)
567 {
568 char *hdrfmt = "%-10.10s %-4.4s %-4.4s %-4.4s %-4.4s %-4.4s"
569 " %-4.4s %-5.5s %-32.32s %-22.22s"
570 #ifdef DEBUG
571 " %-22.22s"
572 #endif /* DEBUG */
573 "\n";
574
575 static int banner = FALSE; /* Have we printed the column headings? */
576 struct io_card *p;
577
578 if (list == NULL)
579 return;
580
581 (void) textdomain(TEXT_DOMAIN);
582
583 if (banner == FALSE) {
584 log_printf(hdrfmt,
585 "", "", "", "",
586 gettext("Bus"),
587 gettext("Max"),
588 "", "", "", "",
589 #ifdef DEBUG
590 "",
591 #endif /* DEBUG */
592 0);
593
594 log_printf(hdrfmt,
595 "",
596 gettext("IO"),
597 gettext("Port"),
598 gettext("Bus"),
599 gettext("Freq"),
600 gettext("Bus"),
601 gettext("Dev,"),
602 "", "", "",
603 #ifdef DEBUG
604 "",
605 #endif /* DEBUG */
606 0);
607
608 log_printf(hdrfmt,
609 gettext("Slot ID"),
610 gettext("Type"),
611 gettext(" ID"),
612 gettext("Side"),
613 gettext("MHz"),
614 gettext("Freq"),
615 gettext("Func"),
616 gettext("State"),
617 gettext("Name"),
618 gettext("Model"),
619 #ifdef DEBUG
620 gettext("Notes"),
621 #endif /* DEBUG */
622 0);
623
624 log_printf(hdrfmt,
625 "----------", "----", "----", "----", "----", "----",
626 "----", "-----", "--------------------------------",
627 "----------------------",
628 #ifdef DEBUG
629 "----------------------",
630 #endif /* DEBUG */
631 0);
632
633 banner = TRUE;
634 }
635
636 for (p = list; p != NULL; p = p -> next) {
637
638 display_io_slot_info(p);
639
640 display_io_max_bus_speed(p);
641
642 log_printf("\n", 0);
643 }
644 }
645
646
647 static void
display_io_slot_info(struct io_card * p)648 display_io_slot_info(struct io_card *p)
649 {
650 /*
651 * Onboard devices are distinguished by Slot IDs that
652 * indicate only the I/O board. Plug-in cards indicate
653 * their leaf and Schizo.
654 */
655
656 if (p->slot_str[0] == '-') {
657 log_printf("/%-2s%02d ",
658 SC_BOARD_TYPE(p->board),
659 PORTID_TO_EXPANDER(p->board), 0);
660 } else {
661 char c;
662 if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
663 log_printf("/%-2s%02d/%s ",
664 SC_BOARD_TYPE(p->board),
665 PORTID_TO_EXPANDER(p->board),
666 p->slot_str, 0);
667 } else {
668 if (p->pci_bus == 'A')
669 c = '3';
670 else if (p->pci_bus == 'B') {
671 c = '5';
672 } else
673 c = '-';
674 log_printf("/%-2s%02d/C%cV%1d ",
675 SC_BOARD_TYPE(p->board),
676 PORTID_TO_EXPANDER(p->board), c,
677 PORTID_TO_INSTANCE(p->schizo_portid),
678 0);
679 }
680 }
681 log_printf("%-4.4s ", gettext(p->bus_type), 0);
682 log_printf("%3d ", p->schizo_portid, 0);
683 log_printf(" %c ", p->pci_bus, 0);
684 log_printf(" %3d ", p->freq, 0);
685 }
686
687 #define BUS_SPEED_PRINT(speed) log_printf(" %d ", speed, 0)
688
689 static void
display_io_max_bus_speed(struct io_card * p)690 display_io_max_bus_speed(struct io_card *p)
691 {
692 int speed = board_bus_max_freq;
693
694 switch (p->pci_bus) {
695 case 'A':
696 BUS_SPEED_PRINT(speed);
697 break;
698 case 'B':
699 if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
700 if (PORTID_TO_INSTANCE(p->schizo_portid) == 0)
701 BUS_SPEED_PRINT(33);
702 else
703 BUS_SPEED_PRINT(speed);
704 } else
705 BUS_SPEED_PRINT(33);
706 break;
707 default:
708 log_printf(" - ", 0);
709 break;
710 }
711
712 log_printf("%-1d,%-1d ", p->dev_no, p->func_no, 0);
713 log_printf("%-5.5s ", gettext(p->status), 0);
714 log_printf("%-32.32s%c ", p->name,
715 ((strlen(p->name) > 32) ? '+' : ' '), 0);
716 log_printf("%-22.22s%c", p->model,
717 ((strlen(p->model) > 22) ? '+' : ' '), 0);
718 #ifdef DEBUG
719 log_printf(" %s", p->notes, 0);
720 #endif /* DEBUG */
721 }
722
723 void
display_cpu_devices(Sys_tree * tree)724 display_cpu_devices(Sys_tree *tree)
725 {
726 Board_node *bnode;
727 char *hdrfmt = "%-8.8s %-7.7s %-4.4s %-4.4s %-7.7s %-4.4s\n";
728
729 (void) textdomain(TEXT_DOMAIN);
730
731 /*
732 * Display the table header for CPUs . Then display the CPU
733 * frequency, cache size, and processor revision of all cpus.
734 */
735 log_printf("\n", 0);
736 log_printf("=========================", 0);
737 log_printf(gettext(" CPUs "), 0);
738 log_printf("=========================", 0);
739 log_printf("\n\n", 0);
740
741 log_printf(hdrfmt,
742 "",
743 gettext("CPU "),
744 gettext("Run"),
745 gettext(" E$"),
746 gettext(" CPU"),
747 gettext("CPU"), 0);
748
749 log_printf(hdrfmt,
750 gettext("Slot ID"),
751 gettext("ID "),
752 gettext("MHz"),
753 gettext(" MB"),
754 gettext("Impl."),
755 gettext("Mask"), 0);
756
757 log_printf(hdrfmt,
758 "--------", "-------", "----", "----", "-------", "----", 0);
759
760 /* Now display all of the cpus on each board */
761 bnode = tree->bd_list;
762 while (bnode != NULL) {
763 display_cpus(bnode);
764 bnode = bnode->next;
765 }
766
767 log_printf("\n", 0);
768 }
769
770 /*
771 * Display the CPUs present on this board.
772 */
773 void
display_cpus(Board_node * board)774 display_cpus(Board_node *board)
775 {
776 Prom_node *cpu;
777 uint_t freq; /* CPU clock frequency */
778 int ecache_size; /* External cache size */
779 int *impl;
780 int *mask;
781 int decoded_mask;
782 int *cpuid;
783 int *coreid;
784 int cpuid_prev = -1;
785 int ecache_size_prev = 0;
786
787 (void) textdomain(TEXT_DOMAIN);
788 /*
789 * display the CPUs' operating frequency, cache size, impl. field
790 * and mask revision.
791 */
792 for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
793 cpu = dev_next_type(cpu, "cpu")) {
794
795 freq = HZ_TO_MHZ(get_cpu_freq(cpu));
796 ecache_size = get_ecache_size(cpu);
797 impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
798 mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
799 cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
800 if (cpuid == NULL)
801 cpuid = &board->board_num;
802
803 /* Do not display a failed CPU node */
804 if ((freq == 0) || (impl == 0) || (node_failed(cpu)))
805 continue;
806
807 if (CPU_IMPL_IS_CMP(*impl)) {
808 coreid = (int *)get_prop_val(find_prop(cpu,
809 "reg"));
810 if (coreid == NULL) {
811 continue;
812 }
813
814 /*
815 * The assumption is made that 2 cores will always be
816 * listed together in the device tree. If either core
817 * is "bad" then the FRU will not be listed.
818 */
819 if (cpuid_prev == -1) {
820 cpuid_prev = *cpuid;
821 ecache_size_prev = ecache_size;
822 continue;
823 } else {
824 /*
825 * Jaguar has a split E$, so the size for both
826 * cores must be added together to get the total
827 * size for the entire chip.
828 *
829 * Panther E$ (L3) is logically shared, so the
830 * total size is equal to the core size.
831 */
832 if (IS_JAGUAR(*impl)) {
833 ecache_size += ecache_size_prev;
834 }
835
836 ecache_size_prev = 0;
837 }
838 }
839
840 /*
841 * Print out cpu data.
842 *
843 * Slot ID
844 */
845 log_printf("/%-2s%02d/P%1d ",
846 SC_BOARD_TYPE(*cpuid),
847 PORTID_TO_EXPANDER(*cpuid),
848 PORTID_TO_INSTANCE(*cpuid), 0);
849
850 /* CPU ID */
851 if (CPU_IMPL_IS_CMP(*impl)) {
852 log_printf("%3d,%3d ", cpuid_prev,
853 *cpuid, 0);
854 cpuid_prev = -1;
855 } else
856 log_printf("%3d ", *cpuid, 0);
857
858 /* Running frequency */
859 log_printf("%4u ", freq, 0);
860
861 /* Ecache size */
862 if (ecache_size == 0)
863 log_printf("%-4.4s ", gettext("N/A"), 0);
864 else
865 log_printf("%4.1f ",
866 (float)ecache_size / (float)(1<<20),
867 0);
868
869 /* Implementation */
870 switch (*impl) {
871 case CHEETAH_IMPL:
872 log_printf("%-7.7s ",
873 gettext("US-III"), 0);
874 break;
875 case CHEETAH_PLUS_IMPL:
876 log_printf("%-7.7s ",
877 gettext("US-III+"), 0);
878 break;
879 case JAGUAR_IMPL:
880 log_printf("%-7.7s ",
881 gettext("US-IV"), 0);
882 break;
883 case PANTHER_IMPL:
884 log_printf("%-7.7s ",
885 gettext("US-IV+"), 0);
886 break;
887 default:
888 log_printf("%-7x ", *impl, 0);
889 break;
890 }
891
892 /* CPU Mask */
893 if (mask == NULL) {
894 log_printf("%-4.4s", gettext("N/A"), 0);
895 } else {
896 if (IS_CHEETAH(*impl))
897 decoded_mask = REMAP_CHEETAH_MASK(*mask);
898 else
899 decoded_mask = *mask;
900
901 log_printf("%d.%d",
902 (decoded_mask >> 4) & 0xf,
903 decoded_mask & 0xf, 0);
904 }
905
906 log_printf("\n", 0);
907 }
908 }
909
910
911 /*ARGSUSED1*/
912 void
display_memoryconf(Sys_tree * tree,struct grp_info * grps)913 display_memoryconf(Sys_tree *tree, struct grp_info *grps)
914 {
915 Board_node *bnode = tree->bd_list;
916 char *hdrfmt = "\n%-11.11s %-4.4s %-7.7s %-7.7s %-8.8s %-6.6s"
917 " %-10.10s %-10.10s";
918
919 (void) textdomain(TEXT_DOMAIN);
920
921 log_printf("=========================", 0);
922 log_printf(gettext(" Memory Configuration "), 0);
923 log_printf("=========================", 0);
924 log_printf("\n", 0);
925
926 log_printf(hdrfmt,
927 "", "",
928 gettext("Logical"),
929 gettext("Logical"),
930 gettext("Logical"),
931 "", "", "", 0);
932
933 log_printf(hdrfmt,
934 "",
935 gettext("Port"),
936 gettext("Bank"),
937 gettext("Bank"),
938 gettext("Bank"),
939 gettext(" DIMM"),
940 gettext("Interleave"),
941 gettext("Interleave"), 0);
942
943 log_printf(hdrfmt,
944 gettext("Slot ID"),
945 gettext(" ID"),
946 gettext("Number"),
947 gettext("Size"),
948 gettext("Status"),
949 gettext(" Size"),
950 gettext("Factor"),
951 gettext("Segment"), 0);
952
953 log_printf(hdrfmt,
954 "-----------", "----", "-------", "-------", "--------",
955 "------", "----------", "----------", 0);
956
957 while (bnode != NULL) {
958 if (get_us3_mem_regs(bnode)) {
959 log_printf(
960 gettext(
961 "\nFailed to get memory information.\n"),
962 0);
963 return;
964 }
965 bnode = bnode->next;
966 }
967
968 /* Display what we have found */
969 display_us3_banks();
970 }
971
972
973 /*
974 * This function provides Starcat's formatting of the memory config
975 * information that get_us3_mem_regs() and display_us3_banks() code has
976 * gathered. It overrides the generic print_us3_memory_line() code
977 * which prints an error message.
978 */
979 void
print_us3_memory_line(int portid,int bank_id,uint64_t bank_size,char * bank_status,uint64_t dimm_size,uint32_t intlv,int seg_id)980 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
981 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
982 {
983 (void) textdomain(TEXT_DOMAIN);
984
985 /* Slot ID */
986 log_printf("\n/%-2s%02d/P%1d/B%1d ",
987 SC_BOARD_TYPE(portid), PORTID_TO_EXPANDER(portid),
988 PORTID_TO_INSTANCE(portid), (bank_id & 0x1), 0);
989
990 /* Port ID */
991 log_printf("%3d ", portid, 0);
992
993 /* Logical Bank Number */
994 log_printf(" %1d ", (bank_id & 0x3), 0);
995
996 /* Logical Bank Size */
997 log_printf("%4lldMB ", bank_size, 0);
998
999 /* Logical Bank Status */
1000 log_printf("%-8.8s ", gettext(bank_status), 0);
1001
1002 /* DIMM Size */
1003 log_printf("%4lldMB ", dimm_size, 0);
1004
1005 /* Interleave Factor */
1006 log_printf(" %2d-%-3.3s ", intlv, gettext("way"), 0);
1007
1008 /* Interleave Segment */
1009 log_printf(" %3d", seg_id, 0);
1010 }
1011
1012 /*ARGSUSED2*/
1013 void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)1014 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
1015 struct system_kstat_data *kstats)
1016 {
1017 if (flag) {
1018 /*
1019 * display time of latest powerfail. Not all systems
1020 * have this capability. For those that do not, this
1021 * is just a no-op.
1022 */
1023 disp_powerfail(root);
1024
1025 (void) textdomain(TEXT_DOMAIN);
1026
1027 /* Print the header */
1028 log_printf("\n", 0);
1029 log_printf("=========================", 0);
1030 log_printf(gettext(" Diagnostic Information "), 0);
1031 log_printf("=========================", 0);
1032 log_printf("\n\n", 0);
1033 log_printf(gettext("For diagnostic information,"), 0);
1034 log_printf("\n", 0);
1035 log_printf(gettext(
1036 "see /var/opt/SUNWSMS/adm/[A-R]/messages on the SC."),
1037 0);
1038 log_printf("\n", 0);
1039
1040 /* Print the PROM revisions here */
1041 starcat_disp_hw_revisions(root);
1042 }
1043 }
1044
1045 /*
1046 * local functions - functions that are only needed inside this library
1047 */
1048
1049 static void
starcat_disp_hw_revisions(Prom_node * root)1050 starcat_disp_hw_revisions(Prom_node *root)
1051 {
1052 Prom_node *pnode;
1053 char *version;
1054
1055 (void) textdomain(TEXT_DOMAIN);
1056
1057 /* Print the header */
1058 log_printf("\n", 0);
1059 log_printf("=========================", 0);
1060 log_printf(gettext(" Hardware Revisions "), 0);
1061 log_printf("=========================", 0);
1062 log_printf("\n\n", 0);
1063
1064 /* Display Prom revision header */
1065 log_printf(gettext("OpenBoot firmware revision:"), 0);
1066 log_printf("\n---------------------------\n", 0);
1067
1068 /*
1069 * Display OBP version info
1070 */
1071 pnode = dev_find_node(root, "openprom");
1072 if (pnode != NULL) {
1073 version = (char *)get_prop_val(find_prop(pnode, "version"));
1074 log_printf("%s\n\n", version, 0);
1075 }
1076 }
1077
1078 /*
1079 * We call do_devinfo() in order to use the libdevinfo device tree
1080 * instead of OBP's device tree.
1081 */
1082 int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)1083 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
1084 {
1085
1086 return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
1087
1088 }
1089
1090 /*
1091 * return the property value for the Prop
1092 * passed in. (When using libdevinfo)
1093 */
1094 void *
get_prop_val(Prop * prop)1095 get_prop_val(Prop *prop)
1096 {
1097 if (prop == NULL)
1098 return (NULL);
1099
1100 return ((void *)(prop->value.val_ptr));
1101 }
1102
1103 /*
1104 * Search a Prom node and retrieve the property with the correct
1105 * name. (When using libdevinfo)
1106 */
1107 Prop *
find_prop(Prom_node * pnode,char * name)1108 find_prop(Prom_node *pnode, char *name)
1109 {
1110 Prop *prop;
1111
1112 if (pnode == NULL)
1113 return (NULL);
1114
1115 for (prop = pnode->props; prop != NULL; prop = prop->next) {
1116 if (prop->name.val_ptr != NULL &&
1117 strcmp((char *)(prop->name.val_ptr), name) == 0)
1118 break;
1119 }
1120
1121 return (prop);
1122 }
1123
1124 /*
1125 * This function searches through the properties of the node passed in
1126 * and returns a pointer to the value of the name property.
1127 * (When using libdevinfo)
1128 */
1129 char *
get_node_name(Prom_node * pnode)1130 get_node_name(Prom_node *pnode)
1131 {
1132 Prop *prop;
1133
1134 if (pnode == NULL) {
1135 return (NULL);
1136 }
1137
1138 prop = pnode->props;
1139 while (prop != NULL) {
1140 if (strcmp("name", (char *)prop->name.val_ptr) == 0)
1141 return (prop->value.val_ptr);
1142 prop = prop->next;
1143 }
1144 return (NULL);
1145 }
1146
1147 /*
1148 * This function searches through the properties of the node passed in
1149 * and returns a pointer to the value of the device_type property.
1150 * (When using libdevinfo)
1151 */
1152 char *
get_node_type(Prom_node * pnode)1153 get_node_type(Prom_node *pnode)
1154 {
1155 Prop *prop;
1156
1157 if (pnode == NULL) {
1158 return (NULL);
1159 }
1160
1161 prop = pnode->props;
1162 while (prop != NULL) {
1163 if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
1164 return (prop->value.val_ptr);
1165 prop = prop->next;
1166 }
1167 return (NULL);
1168 }
1169