8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / lib / libprtdiag_psr / sparc / serengeti / common / serengeti.c
blobc1bee1b2936bc9f2a186a465c979827bf223505d
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Serengeti Platform specific functions.
29 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <kstat.h>
35 #include <string.h>
36 #include <assert.h>
37 #include <alloca.h>
38 #include <libintl.h>
39 #include <fcntl.h>
40 #include <varargs.h>
42 #include <sys/openpromio.h>
43 #include <sys/sysmacros.h>
45 #include <sys/serengeti.h>
46 #include <sys/sgfrutypes.h>
48 #include <pdevinfo.h>
49 #include <display.h>
50 #include <pdevinfo_sun4u.h>
51 #include <display_sun4u.h>
52 #include <libprtdiag.h>
54 #include <config_admin.h>
56 #if !defined(TEXT_DOMAIN)
57 #define TEXT_DOMAIN "SYS_TEST"
58 #endif
60 #define SCHIZO_COMPATIBLE "pci108e,8001"
61 #define XMITS_COMPATIBLE "pci108e,8002"
63 #define ACTIVE 0
64 #define INACTIVE 1
65 #define DISPLAY_INFO 40
67 #define EVNT2STR(e) ((e) == CFGA_STAT_NONE ? "none" : \
68 (e) == CFGA_STAT_EMPTY ? "empty" : \
69 (e) == CFGA_STAT_DISCONNECTED ? "disconnected" : \
70 (e) == CFGA_STAT_CONNECTED ? "connected" : \
71 (e) == CFGA_STAT_UNCONFIGURED ? "unconfigured" : \
72 (e) == CFGA_STAT_CONFIGURED ? "configured" : \
73 "unknown")
75 #define COND2STR(c) ((c) == CFGA_COND_UNKNOWN ? "unknown" : \
76 (c) == CFGA_COND_OK ? "ok" : \
77 (c) == CFGA_COND_FAILING ? "failing" : \
78 (c) == CFGA_COND_FAILED ? "failed" : \
79 (c) == CFGA_COND_UNUSABLE ? "unusable" : \
80 "???")
82 #define SG_CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000)
84 #define MAX_STATUS_LEN 8
85 #define SG_FAIL "fail"
86 #define SG_DISABLED "disabled"
87 #define SG_DEGRADED "degraded"
88 #define SG_OK "ok"
90 #define SG_SCHIZO_FAILED 1
91 #define SG_SCHIZO_GOOD 0
93 #define DEFAULT_MAX_FREQ 66 /* 66 MHz */
94 #define PCIX_MAX_FREQ 100 /* 100 MHz */
96 #define CFG_CPU "::cpu"
98 #define CFG_SET_FRU_NAME_NODE(str, num) \
99 { \
100 char tmp_str[MAX_FRU_NAME_LEN]; \
101 sprintf(tmp_str, "/N%d", num); \
102 strncat(str, tmp_str, sizeof (tmp_str)); \
105 #define CFG_SET_FRU_NAME_CPU_BOARD(str, num) \
107 char tmp_str[MAX_FRU_NAME_LEN]; \
108 sprintf(tmp_str, ".%s%d", SG_HPU_TYPE_CPU_BOARD_ID, num); \
109 strncat(str, tmp_str, sizeof (tmp_str)); \
112 #define CFG_SET_FRU_NAME_MODULE(str, num) \
114 char tmp_str[MAX_FRU_NAME_LEN]; \
115 sprintf(tmp_str, "%s%d", CFG_CPU, num); \
116 strncat(str, tmp_str, sizeof (tmp_str)); \
119 extern int print_flag;
122 * these functions will overlay the symbol table of libprtdiag
123 * at runtime (Serengeti systems only)
125 int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
126 void *get_prop_val(Prop *prop);
127 Prop *find_prop(Prom_node *pnode, char *name);
128 char *get_node_name(Prom_node *pnode);
129 char *get_node_type(Prom_node *pnode);
130 void add_node(Sys_tree *, Prom_node *);
131 void display_pci(Board_node *);
132 void display_ffb(Board_node *, int);
133 void display_io_cards(struct io_card *list);
134 void display_cpu_devices(Sys_tree *tree);
135 void display_cpus(Board_node *board);
136 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
137 struct system_kstat_data *kstats);
138 void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
139 void get_failed_parts(void);
140 int display_failed_parts(Sys_tree *tree);
141 void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
142 void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
143 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
145 /* Local Functions */
146 static void serengeti_display_hw_revisions(Prom_node *root,
147 Board_node *bnode);
148 static Board_node *serengeti_find_board(Sys_tree *root, int board, int nodeid);
149 static Board_node *serengeti_insert_board(Sys_tree *root, int board, int nid);
150 static int display_schizo_revisions(Board_node *bdlist, int mode);
151 static void display_sgsbbc_revisions(Board_node *bdlist);
152 static void serengeti_display_board_info(int state);
153 static void serengeti_display_board_info_header(int state);
154 static boolean_t cpu_node_configured(char *const node);
155 static void display_io_max_bus_speed(struct io_card *p);
156 static void display_io_slot_info(struct io_card *p);
157 static void get_slot_name(struct io_card *card, char *slot_name);
159 /* The bus max freq is determined based on board level in use */
160 int board_bus_max_freq = DEFAULT_MAX_FREQ; /* 66MHz default */
163 * Serengeti now uses both the devinfo tree and the OBP tree for it's
164 * prtdiag. The devinfo tree is used for getting the HW config of the
165 * system and the OBP device tree is used for listing the failed HW
166 * in the system. This is because devinfo currently does not include
167 * any PROM nodes with a status of 'fail' so we need to go to OBP to
168 * get a list of failed HW. We use the tree flag to allow the same code
169 * to walk both trees.
171 * We really need to look at having a single tree for all platforms!
173 #define DEVINFO_TREE 1
174 #define OBP_TREE 2
176 static int tree = DEVINFO_TREE;
178 #ifdef DEBUG
179 #define D_PRINTFINDENT printfindent
180 void
181 printfindent(int indent, char *fmt, ...)
183 va_list ap;
184 int i = 0;
185 for (i = 0; i < indent; i ++)
186 printf("\t");
188 va_start(ap);
189 (void) vprintf(fmt, ap);
190 va_end(ap);
192 #else
193 #define D_PRINTFINDENT
194 #endif
197 * display_pci
198 * Display all the PCI IO cards on this board.
200 void
201 display_pci(Board_node *board)
203 struct io_card *card_list = NULL;
204 struct io_card card;
205 void *value;
206 Prom_node *pci;
207 Prom_node *card_node;
208 Prom_node *pci_bridge_node;
209 Prom_node *child_pci_bridge_node;
210 char *slot_name = NULL; /* info in "slot-names" prop */
211 char *child_name;
212 char *name, *type;
213 char *pname, *ptype;
214 char buf[MAXSTRLEN];
215 int *int_val;
216 int pci_bus;
217 int pci_bridge = 0;
218 int pci_bridge_dev_no;
219 char *slot_name_arr[SG_MAX_SLOTS_PER_IO_BD] = {NULL};
220 int i;
221 int portid;
222 int level = 0;
223 int version, *pversion;
224 #ifdef DEBUG
225 int slot_name_bits;
226 #endif
228 if (board == NULL)
229 return;
231 /* Initialize all the common information */
232 card.display = TRUE;
233 card.board = board->board_num;
234 card.node_id = board->node_id;
237 * Search for each schizo and xmits, then find/display all nodes under
238 * each schizo and xmits node found.
240 for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
241 pci != NULL;
242 pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
244 /* set max freq for this board */
245 board_bus_max_freq = DEFAULT_MAX_FREQ;
247 * Find out if this is a PCI or cPCI IO Board.
248 * If "enum-impl" property exists in pci node => cPCI.
250 value = get_prop_val(find_prop(pci, "enum-impl"));
251 if (value == NULL) {
252 (void) sprintf(card.bus_type, "PCI");
253 } else {
254 (void) sprintf(card.bus_type, "cPCI");
257 if (strstr((char *)get_prop_val(
258 find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
259 sprintf(card.notes, "%s", XMITS_COMPATIBLE);
261 * With XMITS 3.X and PCI-X mode, the bus speed
262 * can be higher than 66MHZ.
264 value = (int *)get_prop_val
265 (find_prop(pci, "module-revision#"));
266 if (value) {
267 pversion = (int *)value;
268 version = *pversion;
269 if (version >= 4)
270 board_bus_max_freq = PCIX_MAX_FREQ;
272 } else if (strstr((char *)get_prop_val(
273 find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
274 sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
275 else
276 sprintf(card.notes, " ");
279 * Get slot-name properties from parent node and
280 * store them in an array.
282 value = (char *)get_prop_val(find_prop(pci, "slot-names"));
283 if (value != NULL) {
284 #ifdef DEBUG
285 /* save the 4 byte bitmask */
286 slot_name_bits = *(int *)value;
287 #endif
288 /* array starts after first int */
289 slot_name_arr[0] = (char *)value + sizeof (int);
291 D_PRINTFINDENT(0, "slot_name_arr[0] is [%s]\n",
292 slot_name_arr[0]);
294 for (i = 1; i < SG_MAX_SLOTS_PER_IO_BD; i++) {
295 slot_name_arr[i] = (char *)slot_name_arr[i - 1]
296 + strlen(slot_name_arr[i - 1]) +1;
298 D_PRINTFINDENT(0, "slot_name_arr[%d] is [%s]\n", i,
299 slot_name_arr[i]);
305 * Search for Children of this node ie. Cards.
306 * Note: any of these cards can be a pci-bridge
307 * that itself has children. If we find a
308 * pci-bridge we need to handle it specially.
310 * There can now be the condition of a pci-bridge
311 * being the child of a pci-bridge which create a
312 * two levels of pci-bridges. This special condition
313 * needs to be handled as well. The variable level
314 * is used to track the depth of the tree. This
315 * variable is then used to find instances of this case.
317 level = 0;
318 card_node = pci->child;
319 while (card_node != NULL) {
320 pci_bridge = 0;
322 /* If it doesn't have a name, skip it */
323 name = (char *)get_prop_val(
324 find_prop(card_node, "name"));
325 if (name == NULL) {
326 card_node = card_node->sibling;
327 continue;
329 D_PRINTFINDENT(level, "NAME is %s\n", name);
331 type = (char *)get_prop_val(
332 find_prop(card_node, "device_type"));
335 * get dev# and func# for this card from the
336 * 'reg' property.
338 int_val = (int *)get_prop_val(
339 find_prop(card_node, "reg"));
340 if (int_val != NULL) {
341 card.dev_no = (((*int_val) & 0xF800) >> 11);
342 card.func_no = (((*int_val) & 0x700) >> 8);
343 } else {
344 card.dev_no = -1;
345 card.func_no = -1;
349 * If this is a pci-bridge, then store it's dev#
350 * as it's children nodes need this to get their slot#.
351 * We set the pci_bridge flag so that we know we are
352 * looking at a pci-bridge node. This flag gets reset
353 * every time we enter this while loop.
357 * Check for a PCI-PCI Bridge for PCI and cPCI
358 * IO Boards using the name and type properties.
360 * If level is greater then 0, then check the parent
361 * node to see if it was also a pci-bridge. We do not
362 * this when level is 0 as this will see the schizo or
363 * xmits device as a pci-bridge node. This will mess
364 * up the slot number of child nodes.
366 if ((type != NULL) &&
367 (strncmp(name, "pci", 3) == 0) &&
368 (strcmp(type, "pci") == 0)) {
369 if (level > 0) {
370 pname = (char *)get_prop_val(
371 find_prop(card_node->parent,
372 "name"));
373 ptype = (char *)get_prop_val(
374 find_prop(card_node->parent,
375 "device_type"));
377 if ((ptype != NULL) &&
378 (pname != NULL) &&
379 (strncmp(pname, "pci", 3) == 0) &&
380 (strcmp(ptype, "pci") == 0)) {
381 child_pci_bridge_node =
382 card_node;
383 } else {
384 pci_bridge_dev_no = card.dev_no;
385 pci_bridge_node = card_node;
387 } else {
388 pci_bridge_dev_no = card.dev_no;
389 pci_bridge_node = card_node;
391 pci_bridge = TRUE;
393 D_PRINTFINDENT(level,
394 "pci_bridge_dev_no is [%d]\n",
395 pci_bridge_dev_no);
399 * Get slot-names property from slot_names_arr.
400 * If we are the child of a pci_bridge we use the
401 * dev# of the pci_bridge as an index to get
402 * the slot number. We know that we are a child of
403 * a pci-bridge if our parent is the same as the last
404 * pci_bridge node found above.
406 if (type)
407 D_PRINTFINDENT(level,
408 "*** name is [%s] - type is [%s]\n",
409 name, type);
410 else
411 D_PRINTFINDENT(level,
412 "*** name is [%s]\n", name);
414 if (card.dev_no != -1) {
416 * We compare this cards parent node with the
417 * pci_bridge_node to see if it's a child.
419 if (((level > 0) &&
420 (card_node->parent->parent ==
421 pci_bridge_node)) ||
422 (card_node->parent == pci_bridge_node)) {
423 /* use dev_no of pci_bridge */
424 D_PRINTFINDENT(level,
425 " pci_bridge_dev_no is [%d]\n",
426 pci_bridge_dev_no);
428 slot_name =
429 slot_name_arr[pci_bridge_dev_no -1];
430 } else {
431 /* use cards own dev_no */
432 D_PRINTFINDENT(level,
433 " card.dev_no is [%d]\n",
434 card.dev_no);
436 slot_name =
437 slot_name_arr[card.dev_no - 1];
440 get_slot_name(&card, slot_name);
442 } else {
443 (void) sprintf(card.slot_str, "%c", '-');
447 * Get the portid of the schizo and xmits that this card
448 * lives under.
450 portid = -1;
451 value = get_prop_val(find_prop(pci, "portid"));
452 if (value != NULL) {
453 portid = *(int *)value;
455 card.schizo_portid = portid;
457 #ifdef DEBUG
458 (void) sprintf(card.notes, "%s portid [%d] dev_no[%d]"
459 " slot_name[%s] name_bits[%d]",
460 card.notes,
461 portid,
462 card.dev_no, slot_name,
463 slot_name_bits);
464 #endif
467 * Find out whether this is PCI bus A or B
468 * using the 'reg' property.
470 int_val = (int *)get_prop_val
471 (find_prop(pci, "reg"));
473 if (int_val != NULL) {
474 int_val ++; /* skip over first integer */
475 pci_bus = ((*int_val) & 0x7f0000);
476 if (pci_bus == 0x600000)
477 card.pci_bus = 'A';
478 else if (pci_bus == 0x700000)
479 card.pci_bus = 'B';
480 else
481 card.pci_bus = '-';
482 } else {
483 card.pci_bus = '-';
488 * Check for failed status.
490 if (node_status(card_node, SG_FAIL))
491 strncpy(card.status, SG_FAIL,
492 sizeof (SG_FAIL));
493 else if (node_status(card_node, SG_DISABLED))
494 strncpy(card.status, SG_DISABLED,
495 sizeof (SG_DISABLED));
496 else
497 strncpy(card.status, SG_OK,
498 sizeof (SG_OK));
500 /* Get the model of this card */
501 value = get_prop_val(find_prop(card_node, "model"));
502 if (value == NULL)
503 card.model[0] = '\0';
504 else {
505 (void) sprintf(card.model, "%s",
506 (char *)value);
507 /* Skip sgsbbc nodes, they are not cards */
508 if (strcmp(card.model, "SUNW,sgsbbc") == 0) {
509 card_node = card_node->sibling;
510 continue;
515 * Check if further processing is necessary to display
516 * this card uniquely.
518 distinguish_identical_io_cards(name, card_node, &card);
521 * The card may have a "clock-frequency" but we
522 * are not interested in that. Instead we get the
523 * "clock-frequency" of the PCI Bus that the card
524 * resides on. PCI-A can operate at 33Mhz or 66Mhz
525 * depending on what card is plugged into the Bus.
526 * PCI-B always operates at 33Mhz.
529 int_val = get_prop_val(find_prop(pci,
530 "clock-frequency"));
531 if (int_val != NULL) {
532 card.freq = SG_CLK_FREQ_TO_MHZ(*int_val);
533 } else {
534 card.freq = -1;
538 * Figure out how we want to display the name
540 value = get_prop_val(find_prop(card_node,
541 "compatible"));
542 if (value != NULL) {
543 /* use 'name'-'compatible' */
544 (void) sprintf(buf, "%s-%s", name,
545 (char *)value);
546 } else {
547 /* just use 'name' */
548 (void) sprintf(buf, "%s", name);
550 name = buf;
553 * If this node has children, add the device_type
554 * of the child to the name value of this card.
556 child_name = (char *)get_node_name(card_node->child);
557 if ((card_node->child != NULL) &&
558 (child_name != NULL)) {
559 value = get_prop_val(find_prop(card_node->child,
560 "device_type"));
561 if (value != NULL) {
562 /* add device_type of child to name */
563 (void) sprintf(card.name, "%s/%s (%s)",
564 name, child_name,
565 (char *)value);
566 } else {
567 /* just add childs name */
568 (void) sprintf(card.name, "%s/%s", name,
569 child_name);
571 } else {
572 (void) sprintf(card.name, "%s", (char *)name);
576 * If this is a pci-bridge, then add the word
577 * 'pci-bridge' to it's model.
579 if (pci_bridge) {
580 if (strlen(card.model) == 0)
581 (void) sprintf(card.model,
582 "%s", "pci-bridge");
583 else
584 (void) sprintf(card.model,
585 "%s/pci-bridge", card.model);
588 /* insert this card in the list to be displayed later */
589 card_list = insert_io_card(card_list, &card);
592 * If we are dealing with a pci-bridge, we need to move
593 * down to the children of this bridge if there are any.
595 * If we are not, we are either dealing with a regular
596 * card (in which case we move onto the sibling of this
597 * card) or we are dealing with a child of a pci-bridge
598 * (in which case we move onto the child's siblings or
599 * if there are no more siblings for this child, we
600 * move onto the parents siblings).
602 * Once we reach the last child node of a pci-bridge,
603 * we need to back up the tree to the parents sibling
604 * node. If our parent has no more siblings, we need
605 * to check our grand parent for siblings.
607 * If we have no more siblings, we simply point to
608 * to the child's sibling which moves us onto the next
609 * bus leaf.
611 * The variable level gets adjusted on some of the
612 * conditions as this is used to track level within
613 * the tree we have reached.
615 if (pci_bridge) {
616 if (card_node->child != NULL) {
617 level++;
618 card_node = card_node->child;
619 } else
620 card_node = card_node->sibling;
621 } else {
622 if ((card_node->parent == pci_bridge_node) &&
623 (card_node->sibling == NULL)) {
624 card_node = pci_bridge_node->sibling;
625 if (level > 0)
626 level--;
627 } else if ((card_node->parent ==
628 child_pci_bridge_node) &&
629 (card_node->parent->parent ==
630 pci_bridge_node)) {
631 if ((child_pci_bridge_node->sibling) &&
632 (card_node->sibling == NULL)) {
633 card_node =
634 child_pci_bridge_node-> \
635 sibling;
636 if (level > 0)
637 level--;
638 } else if ((pci_bridge_node->sibling) &&
639 (card_node->sibling == NULL)) {
640 card_node =
641 pci_bridge_node->sibling;
642 if (level > 1)
643 level = level - 2;
644 else if (level > 0)
645 level--;
646 } else
647 card_node = card_node->sibling;
648 } else
649 card_node = card_node->sibling;
651 } /* end-while */
652 } /* end-for */
654 display_io_cards(card_list);
655 free_io_cards(card_list);
659 * display_ffb
661 * There are no FFB's on a Serengeti, however in the generic library,
662 * the display_ffb() function is implemented so we have to define an
663 * empty function here.
665 /*ARGSUSED0*/
666 void
667 display_ffb(Board_node *board, int table)
670 static void
671 serengeti_display_board_info_header(int state)
673 char *fmt = "%-9s %-11s %-12s %-12s %-9s %-40s\n";
675 log_printf("\n", 0);
676 log_printf("=========================", 0);
677 if (state == ACTIVE)
678 log_printf(dgettext(TEXT_DOMAIN,
679 " Active Boards for Domain "), 0);
680 else
681 log_printf(dgettext(TEXT_DOMAIN,
682 " Available Boards/Slots for Domain "), 0);
683 log_printf("===========================", 0);
684 log_printf("\n", 0);
685 log_printf("\n", 0);
687 log_printf(fmt, "", "Board", "Receptacle", "Occupant", "", "", 0);
689 log_printf(fmt, "FRU Name", "Type", "Status", "Status",
690 "Condition", "Info", 0);
692 log_printf(fmt, "---------", "-----------", "-----------",
693 "------------", "---------",
694 "----------------------------------------", 0);
697 static void
698 serengeti_display_board_info(int state)
700 int i, z, ret;
701 int nlist = 0;
702 int available_board_count = 0;
703 struct cfga_list_data *board_cfg = NULL;
704 char *err_string = NULL;
705 char tmp_id[CFGA_LOG_EXT_LEN + 1];
706 char tmp_info[DISPLAY_INFO + 1];
707 const char listops[] = "class=sbd";
708 struct cfga_list_data dat;
709 cfga_flags_t flags = NULL;
711 ret = config_list_ext(0, NULL, &board_cfg, &nlist,
712 NULL, listops,
713 &err_string, flags);
715 if (ret == CFGA_OK) {
716 serengeti_display_board_info_header(state);
717 for (i = 0; i < nlist; i++) {
718 dat = board_cfg[i];
720 if ((state != ACTIVE) &&
721 (dat.ap_o_state == CFGA_STAT_CONFIGURED))
722 continue;
723 else if ((state == ACTIVE) &&
724 (dat.ap_o_state != CFGA_STAT_CONFIGURED))
725 continue;
726 if (state == INACTIVE)
727 available_board_count++;
729 memcpy(tmp_id, dat.ap_log_id, CFGA_LOG_EXT_LEN);
730 tmp_id[CFGA_LOG_EXT_LEN] = '\0';
731 for (z = 0; z < strlen(tmp_id); z++) {
732 if (tmp_id[z] == '.')
733 tmp_id[z] = '/';
735 log_printf("/%-8s ", tmp_id, 0);
736 log_printf("%-11s ", dat.ap_type, 0);
738 log_printf("%-12s ", EVNT2STR(dat.ap_r_state), 0);
739 log_printf("%-12s ", EVNT2STR(dat.ap_o_state), 0);
740 log_printf("%-8s ", COND2STR(dat.ap_cond), 0);
742 memcpy(tmp_info, dat.ap_info, DISPLAY_INFO);
743 tmp_info[DISPLAY_INFO - 1] = '\0';
744 if (strlen(tmp_info) >= (DISPLAY_INFO - 1))
745 tmp_info[DISPLAY_INFO - 2] = '+';
746 log_printf("%-*s\n", (DISPLAY_INFO - 1), tmp_info, 0);
748 if ((state == INACTIVE) &&
749 (available_board_count == 0)) {
750 log_printf(dgettext(TEXT_DOMAIN,
751 "There are currently no "
752 "Boards/Slots available "
753 "to this Domain\n"), 0);
756 if (board_cfg)
757 free(board_cfg);
758 if (err_string)
759 free(err_string);
763 * add_node
765 * This function adds a board node to the board structure where that
766 * that node's physical component lives.
768 void
769 add_node(Sys_tree *root, Prom_node *pnode)
771 int board = -1;
772 int portid = -1;
773 int nodeid = -1;
775 void *value = NULL;
776 Board_node *bnode = NULL;
777 Prom_node *p = NULL;
778 char *type;
780 /* Get the board number of this board from the portid prop */
781 if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
782 if ((type = get_node_type(pnode)) && (strcmp(type, "cpu") == 0))
783 value =
784 get_prop_val(find_prop(pnode->parent, "portid"));
786 if (value != NULL) {
787 portid = *(int *)value;
790 nodeid = SG_PORTID_TO_NODEID(portid);
791 board = SG_PORTID_TO_BOARD_NUM(portid);
793 /* find the board node with the same board number */
794 if ((bnode = serengeti_find_board(root, board, nodeid)) == NULL) {
795 bnode = serengeti_insert_board(root, board, nodeid);
798 /* now attach this prom node to the board list */
799 /* Insert this node at the end of the list */
800 pnode->sibling = NULL;
801 if (bnode->nodes == NULL)
802 bnode->nodes = pnode;
803 else {
804 p = bnode->nodes;
805 while (p->sibling != NULL)
806 p = p->sibling;
807 p->sibling = pnode;
814 * Print out all the io cards in the list. Also print the column
815 * headers if told to do so.
817 void
818 display_io_cards(struct io_card *list)
820 char *fmt = "%-10s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-34s";
822 static int banner = FALSE; /* Have we printed the column headings? */
823 struct io_card *p;
825 if (list == NULL)
826 return;
828 if (banner == FALSE) {
829 log_printf(fmt, "", "", "", "", "", "Bus", "Max",
830 "", "", "", 0);
831 log_printf("\n", 0);
832 log_printf(fmt, "", "IO", "Port", "Bus", "", "Freq", "Bus",
833 "Dev,", "", "", 0);
834 log_printf("\n", 0);
835 log_printf(fmt, "FRU Name", "Type", " ID", "Side", "Slot",
836 "MHz", "Freq", "Func", "State", "Name", 0);
837 #ifdef DEBUG
838 log_printf("Model Notes\n", 0);
839 #else
840 log_printf("Model\n", 0);
841 #endif
843 log_printf(fmt, "----------", "----", "----", "----", "----",
844 "----", "----", "----", "-----",
845 "--------------------------------", 0);
846 #ifdef DEBUG
847 log_printf("---------------------- ", 0);
848 #endif
849 log_printf("----------------------\n", 0);
850 banner = TRUE;
853 for (p = list; p != NULL; p = p -> next) {
855 display_io_slot_info(p);
857 display_io_max_bus_speed(p);
859 log_printf("\n", 0);
863 static void
864 display_io_slot_info(struct io_card *p)
866 char fru_name[MAX_FRU_NAME_LEN] = "";
868 SG_SET_FRU_NAME_NODE(fru_name, p->node_id);
869 SG_SET_FRU_NAME_IO_BOARD(fru_name, p->board);
870 SG_SET_FRU_NAME_MODULE(fru_name, p->schizo_portid % 2);
872 log_printf("%-8s ", fru_name, 0);
873 log_printf("%-4s ", p->bus_type, 0);
874 log_printf("%-3d ", p->schizo_portid, 0);
875 log_printf("%c ", p->pci_bus, 0);
876 log_printf("%-1s ", p->slot_str, 0);
877 log_printf("%-3d ", p->freq, 0);
880 #define BUS_SPEED_PRINT(speed) log_printf(" %d ", speed, 0)
882 static void
883 display_io_max_bus_speed(struct io_card *p)
885 int speed = board_bus_max_freq;
887 switch (p->pci_bus) {
888 case 'A':
889 BUS_SPEED_PRINT(speed);
890 break;
891 case 'B':
892 if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
893 if ((strncmp(p->slot_str, "1", 1) == 0) ||
894 (strncmp(p->slot_str, "0", 1) == 0))
895 BUS_SPEED_PRINT(33);
896 else
897 BUS_SPEED_PRINT(speed);
898 } else
899 BUS_SPEED_PRINT(33);
900 break;
901 default:
902 log_printf(" - ", 0);
903 break;
906 log_printf("%-1d,%-1d ", p->dev_no, p->func_no, 0);
907 log_printf("%-5s ", p->status, 0);
909 log_printf("%-32.32s%c ", p->name,
910 ((strlen(p->name) > 32) ? '+' : ' '), 0);
911 log_printf("%-22.22s%c", p->model,
912 ((strlen(p->model) > 22) ? '+' : ' '), 0);
913 #ifdef DEBUG
914 log_printf(" %s", p->notes, 0);
915 #endif /* DEBUG */
918 void
919 display_cpu_devices(Sys_tree *tree)
921 Board_node *bnode;
923 /* printf formats */
924 char *fmt1 = "%-10s %-7s %-4s %-4s %-7s %-4s\n";
927 * Display the table header for CPUs . Then display the CPU
928 * frequency, cache size, and processor revision of all cpus.
930 log_printf("\n", 0);
931 log_printf("=========================", 0);
932 log_printf(" CPUs ", 0);
933 log_printf("=========================", 0);
934 log_printf("======================", 0);
935 log_printf("\n", 0);
936 log_printf("\n", 0);
938 log_printf(fmt1, "", "CPU ", "Run", " E$", "CPU", "CPU", 0);
940 log_printf(fmt1, "FRU Name", "ID ", "MHz", " MB",
941 "Impl.", "Mask", 0);
943 log_printf(fmt1, "----------", "-------", "----", "----",
944 "-------", "----", 0);
946 /* Now display all of the cpus on each board */
947 bnode = tree->bd_list;
948 while (bnode != NULL) {
949 display_cpus(bnode);
950 bnode = bnode->next;
953 log_printf("\n", 0);
956 static boolean_t
957 cpu_node_configured(char *const node)
959 int ret, i;
960 int nlist = 0;
961 boolean_t rv;
962 char *err_string = NULL;
963 char *const *ap_args = NULL;
964 struct cfga_list_data *statlist = NULL;
965 struct cfga_list_data dat;
966 cfga_flags_t flags = CFGA_FLAG_LIST_ALL;
968 if (node == NULL)
969 return (FALSE);
971 ap_args = &node;
972 ret = config_list_ext(1, &node, &statlist, &nlist,
973 NULL, NULL, &err_string, flags);
975 if (ret == CFGA_OK) {
976 dat = statlist[0];
978 if (dat.ap_o_state == CFGA_STAT_CONFIGURED)
979 rv = TRUE;
980 else
981 rv = FALSE;
982 } else {
983 rv = FALSE;
985 if (statlist)
986 free(statlist);
987 if (err_string)
988 free(err_string);
989 return (rv);
993 * Display the CPUs present on this board.
995 void
996 display_cpus(Board_node *board)
998 Prom_node *cpu;
999 uint_t freq; /* CPU clock frequency */
1000 int ecache_size; /* External cache size */
1001 int board_num = board->board_num;
1002 int *mid;
1003 int *impl;
1004 int *mask;
1005 int decoded_mask;
1006 int *coreid;
1007 int mid_prev = -1;
1008 int ecache_size_prev = 0;
1009 char fru_prev[MAX_FRU_NAME_LEN] = "";
1012 * display the CPUs' operating frequency, cache size, impl. field
1013 * and mask revision.
1015 for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
1016 cpu = dev_next_type(cpu, "cpu")) {
1017 char fru_name[MAX_FRU_NAME_LEN] = "";
1018 char cfg_fru_name[MAX_FRU_NAME_LEN] = "";
1020 mid = (int *)get_prop_val(find_prop(cpu, "portid"));
1021 if (mid == NULL)
1022 mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
1023 freq = SG_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
1024 ecache_size = get_ecache_size(cpu);
1025 impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
1026 mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
1028 /* Do not display a failed CPU node */
1029 if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
1030 continue;
1032 /* FRU Name */
1033 SG_SET_FRU_NAME_NODE(fru_name, board->node_id);
1035 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board_num);
1036 SG_SET_FRU_NAME_MODULE(fru_name, *mid % 4);
1038 if (CPU_IMPL_IS_CMP(*impl)) {
1039 coreid = (int *)get_prop_val(find_prop(cpu,
1040 "reg"));
1041 if (coreid == NULL) {
1042 continue;
1046 * The assumption is made that 2 cores will always be
1047 * listed together in the device tree. If either core
1048 * is "bad" then the FRU will not be listed.
1050 * As display_cpus on Serengeti does actually process
1051 * all cpu's per board a copy of the fru_name needs to
1052 * be made as the following core may not be its
1053 * sibling. If this is the case it is assumed that a
1054 * sibling core has failed, so the fru should not be
1055 * displayed.
1057 * For the first instance of a core, fru_prev is
1058 * expected to be empty. The current values are then
1059 * stored and the next board->nodes is processed. If
1060 * this is a sibling core, the ecache size it tallied
1061 * and the previous value reset and processing
1062 * continues.
1064 * If the following core is not a sibling, the new
1065 * values are stored and the next board->nodes is
1066 * processed.
1068 if (strncmp(fru_prev, "", sizeof (fru_prev)) == 0) {
1069 strncpy(fru_prev, fru_name, sizeof (fru_name));
1070 mid_prev = *mid;
1071 ecache_size_prev = ecache_size;
1072 continue;
1073 } else {
1074 if (strncmp(fru_name, fru_prev,
1075 sizeof (fru_prev)) == 0) {
1077 * Jaguar has a split E$, so the size
1078 * for both cores must be added together
1079 * to get the total size for the entire
1080 * chip.
1082 * Panther E$ (L3) is logically shared,
1083 * so the total size is equal to the
1084 * core size.
1086 if (IS_JAGUAR(*impl)) {
1087 ecache_size += ecache_size_prev;
1090 ecache_size_prev = 0;
1091 strncpy(fru_prev, "",
1092 sizeof (fru_prev));
1093 } else {
1094 mid_prev = *mid;
1095 ecache_size_prev = ecache_size;
1096 strncpy(fru_prev, fru_name,
1097 sizeof (fru_name));
1098 continue;
1104 * If cpu is not configured, do not display it
1106 CFG_SET_FRU_NAME_NODE(cfg_fru_name, board->node_id);
1107 CFG_SET_FRU_NAME_CPU_BOARD(cfg_fru_name, board_num);
1108 CFG_SET_FRU_NAME_MODULE(cfg_fru_name, *mid % 4);
1110 if (!(cpu_node_configured(cfg_fru_name))) {
1111 continue;
1115 log_printf("%-10s ", fru_name, 0);
1117 /* CPU MID */
1118 if (CPU_IMPL_IS_CMP(*impl)) {
1119 log_printf("%3d,%3d ", mid_prev, *mid, 0);
1120 mid_prev = -1;
1121 } else
1122 log_printf("%3d ", *mid, 0);
1124 /* Running frequency */
1125 log_printf(" %4u ", freq, 0);
1127 /* Ecache size */
1128 if (ecache_size == 0)
1129 log_printf("%3s ", "N/A", 0);
1130 else
1131 log_printf("%4.1f ",
1132 (float)ecache_size / (float)(1<<20),
1135 /* Implementation */
1136 if (impl == NULL) {
1137 log_printf("%6s ", " N/A", 0);
1138 } else {
1139 switch (*impl) {
1140 case CHEETAH_IMPL:
1141 log_printf("%-7s ", "US-III", 0);
1142 break;
1143 case CHEETAH_PLUS_IMPL:
1144 log_printf("%-7s ", "US-III+", 0);
1145 break;
1146 case JAGUAR_IMPL:
1147 log_printf("%-7s ", "US-IV", 0);
1148 break;
1149 case PANTHER_IMPL:
1150 log_printf("%-7s ", "US-IV+", 0);
1151 break;
1152 default:
1153 log_printf("%-7x ", *impl, 0);
1154 break;
1158 /* CPU Mask */
1159 if (mask == NULL) {
1160 log_printf(" %3s ", "N/A", 0);
1161 } else {
1162 if (IS_CHEETAH(*impl))
1163 decoded_mask = REMAP_CHEETAH_MASK(*mask);
1164 else
1165 decoded_mask = *mask;
1167 log_printf(" %d.%d ",
1168 (decoded_mask >> 4) & 0xf,
1169 decoded_mask & 0xf, 0);
1172 log_printf("\n", 0);
1177 /*ARGSUSED3*/
1178 void
1179 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
1180 struct system_kstat_data *kstats)
1182 log_printf("\n", 0);
1183 log_printf("=========================", 0);
1184 log_printf(dgettext(TEXT_DOMAIN, " Hardware Failures "), 0);
1185 log_printf("==================================", 0);
1186 log_printf("\n", 0);
1189 * Get a list of failed parts (ie. devices with a status of
1190 * 'fail') from the OBP device tree and display them.
1192 get_failed_parts();
1194 /* return unless -v option specified */
1195 if (!flag) {
1196 log_printf("\n", 0);
1197 return;
1201 * display time of latest powerfail. Not all systems
1202 * have this capability. For those that do not, this
1203 * is just a no-op.
1205 disp_powerfail(root);
1207 /* Print the PROM revisions here */
1208 serengeti_display_hw_revisions(root, tree->bd_list);
1212 * local functions - functions that are only needed inside this library
1215 static void
1216 serengeti_display_hw_revisions(Prom_node *root, Board_node *bdlist)
1218 Prom_node *pnode;
1219 char *value;
1221 /* Print the header */
1222 log_printf("\n", 0);
1223 log_printf("=========================", 0);
1224 log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
1225 log_printf("=======================================", 0);
1226 log_printf("\n", 0);
1227 log_printf("\n", 0);
1229 /* Display Prom revision header */
1230 log_printf("System PROM revisions:\n", 0);
1231 log_printf("----------------------\n", 0);
1234 * Display OBP version info
1236 pnode = dev_find_node(root, "openprom");
1237 if (pnode != NULL) {
1238 value = (char *)get_prop_val(find_prop(pnode, "version"));
1239 log_printf("%s\n\n", value, 0);
1240 } else {
1241 log_printf("OBP ???\n\n", value, 0);
1245 * Display ASIC revisions
1247 log_printf("IO ASIC revisions:\n", 0);
1248 log_printf("------------------\n", 0);
1250 log_printf(" Port\n", 0);
1251 log_printf("FRU Name Model ID Status", 0);
1252 #ifdef DEBUG
1253 log_printf(" Version Notes\n", 0);
1254 #else
1255 log_printf(" Version\n", 0);
1256 #endif
1257 /* ---------FRU Name--Model-----------Port-Status */
1258 log_printf("----------- --------------- ---- ---------- "
1259 #ifdef DEBUG
1260 "------- "
1261 #endif
1262 "-------\n", 0);
1264 * Display SCHIZO version info
1266 display_schizo_revisions(bdlist, SG_SCHIZO_GOOD);
1269 * Display sgsbbc version info
1271 display_sgsbbc_revisions(bdlist);
1275 * This function displays Schizo and Xmits revision of boards
1277 static int
1278 display_schizo_revisions(Board_node *bdlist, int mode)
1280 Prom_node *pnode;
1281 int *int_val;
1282 int portid;
1283 int prev_portid = -1;
1284 char *model;
1285 char *status_a, *status_b;
1286 char status[MAX_STATUS_LEN];
1287 int version;
1288 int node_id;
1289 #ifdef DEBUG
1290 uint32_t a_notes, b_notes;
1291 #endif
1292 int pci_bus;
1294 * rv is used when mode is set to SG_SCHIZO_FAILED.
1295 * We need to signal if a failure is found so that
1296 * the correct headers/footers can be printed.
1298 * rv = 1 implies a failed/disavled schizo device
1299 * rv = 0 implies all other cases
1301 int rv = 0;
1302 Board_node *bnode;
1303 void *value;
1305 bnode = bdlist;
1306 while (bnode != NULL) {
1308 * search this board node for all Schizos
1310 for (pnode = dev_find_node_by_compatible(bnode->nodes,
1311 SCHIZO_COMPATIBLE); pnode != NULL;
1312 pnode = dev_next_node_by_compatible(pnode,
1313 SCHIZO_COMPATIBLE)) {
1315 char fru_name[MAX_FRU_NAME_LEN] = "";
1318 * get the reg property to determine
1319 * whether we are looking at side A or B
1321 int_val = (int *)get_prop_val
1322 (find_prop(pnode, "reg"));
1323 if (int_val != NULL) {
1324 int_val ++; /* second integer in array */
1325 pci_bus = ((*int_val) & 0x7f0000);
1328 /* get portid */
1329 int_val = (int *)get_prop_val
1330 (find_prop(pnode, "portid"));
1331 if (int_val == NULL)
1332 continue;
1334 portid = *int_val;
1337 * If this is a new portid and it is PCI bus B,
1338 * we skip onto the PCI bus A. (PCI-A and PCI-B share
1339 * the same portid)
1341 if ((portid != prev_portid) && (pci_bus == 0x700000)) {
1342 prev_portid = portid;
1343 /* status */
1344 status_b = (char *)get_prop_val
1345 (find_prop(pnode, "status"));
1346 #ifdef DEBUG
1347 b_notes = pci_bus;
1348 #endif
1349 continue; /* skip to the next schizo */
1353 * This must be side A of the same Schizo.
1354 * Gather all its props and display them.
1356 #ifdef DEBUG
1357 a_notes = pci_bus;
1358 #endif
1360 prev_portid = portid;
1362 /* get the node-id */
1363 node_id = SG_PORTID_TO_NODEID(portid);
1365 /* model */
1366 model = (char *)get_prop_val
1367 (find_prop(pnode, "model"));
1369 /* version */
1370 value = (int *)get_prop_val
1371 (find_prop(pnode, "module-revision#"));
1373 if (value)
1374 int_val = (int *)value;
1375 else
1376 int_val = (int *)get_prop_val
1377 (find_prop(pnode, "version#"));
1378 if (int_val != NULL)
1379 version = *int_val;
1380 else
1381 version = -1;
1383 /* status */
1384 status_a = (char *)get_prop_val(find_prop
1385 (pnode, "status"));
1388 * Display the data
1390 /* FRU Name */
1391 SG_SET_FRU_NAME_NODE(fru_name, node_id);
1392 SG_SET_FRU_NAME_IO_BOARD(fru_name,
1393 SG_IO_BD_PORTID_TO_BD_NUM(portid));
1394 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
1396 if (mode == SG_SCHIZO_FAILED) {
1397 if ((status_a != (char *)NULL) &&
1398 ((status_b != (char *)NULL))) {
1399 if ((strcmp
1400 (status_a, SG_DISABLED) == 0) &&
1401 (strcmp(status_b,
1402 SG_DISABLED) == 0)) {
1403 log_printf("\tFRU Type : %s\n ",
1404 model, 0);
1405 log_printf("\tLocation : %s\n",
1406 fru_name, 0);
1407 log_printf
1408 ("\tPROM status: %s\n\n",
1409 SG_DISABLED, 0);
1410 rv = 1;
1413 continue;
1416 * This section of code is executed when displaying
1417 * non-failed schizo devices. If the mode is set to
1418 * SG_SCHIZO_FAILED, then this section of code will
1419 * not be executed
1421 if ((status_a == (char *)NULL) &&
1422 ((status_b == (char *)NULL)))
1423 sprintf(status, " %s ", SG_OK);
1424 else if ((status_a == (char *)NULL) &&
1425 ((strcmp(status_b, SG_DISABLED) == 0)))
1426 sprintf(status, " %s", SG_DEGRADED);
1427 else if ((status_b == (char *)NULL) &&
1428 ((strcmp(status_a, SG_DISABLED) == 0)))
1429 sprintf(status, " %s", SG_DEGRADED);
1430 else
1431 continue;
1433 log_printf("%-12s", fru_name, 0);
1435 /* model */
1437 if (model != NULL)
1438 log_printf("%-15s ", model, 0);
1439 else
1440 log_printf("%-15s ", "unknown", 0);
1441 /* portid */
1442 log_printf("%-3d ", portid, 0);
1444 /* status */
1445 log_printf("%s", status, 0);
1447 /* version */
1448 log_printf(" %-4d ", version, 0);
1449 #ifdef DEBUG
1450 log_printf("0x%x 0x%x", a_notes, b_notes, 0);
1451 log_printf(" %d", portid, 0);
1452 #endif
1453 log_printf("\n", 0);
1455 bnode = bnode->next;
1457 return (rv);
1460 static void
1461 display_sgsbbc_revisions(Board_node *bdlist)
1464 Prom_node *pnode;
1465 int *int_val;
1466 int portid;
1467 char *model;
1468 char *status;
1469 int revision;
1470 int node_id;
1471 Board_node *bnode;
1473 #ifdef DEBUG
1474 char *slot_name;
1475 char notes[30];
1476 char *value;
1477 #endif
1479 bnode = bdlist;
1480 while (bnode != NULL) {
1482 * search this board node for all sgsbbc's
1484 for (pnode = dev_find_node_by_type(bnode->nodes, "model",
1485 "SUNW,sgsbbc"); pnode != NULL;
1486 pnode = dev_next_node_by_type(pnode, "model",
1487 "SUNW,sgsbbc")) {
1489 char fru_name[MAX_FRU_NAME_LEN] = "";
1492 * We need to go to this node's parent to
1493 * get a portid to tell us what board it is on
1495 int_val = (int *)get_prop_val
1496 (find_prop(pnode->parent, "portid"));
1497 if (int_val == NULL)
1498 continue;
1500 portid = *int_val;
1501 /* get the node-id */
1502 node_id = SG_PORTID_TO_NODEID(portid);
1504 /* model */
1505 model = (char *)get_prop_val
1506 (find_prop(pnode, "model"));
1508 /* status */
1509 status = (char *)get_prop_val(find_prop
1510 (pnode, "status"));
1512 /* revision */
1513 int_val = (int *)get_prop_val
1514 (find_prop(pnode, "revision-id"));
1515 if (int_val != NULL)
1516 revision = *int_val;
1517 else
1518 revision = -1;
1520 #ifdef DEBUG
1521 value = (char *)get_prop_val(
1522 find_prop(pnode->parent, "slot-names"));
1523 if (value != NULL) {
1524 /* Skip the 4 byte bitmask */
1525 slot_name = (char *)value + sizeof (int);
1526 } else {
1527 strcpy(slot_name, "not_found");
1529 (void) sprintf(notes, "[%s] portid [%d]", slot_name,
1530 portid);
1531 #endif
1533 * Display the data
1535 /* FRU Name */
1536 SG_SET_FRU_NAME_NODE(fru_name, node_id);
1537 SG_SET_FRU_NAME_IO_BOARD(fru_name,
1538 SG_IO_BD_PORTID_TO_BD_NUM(portid));
1539 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
1540 log_printf("%-12s", fru_name, 0);
1542 /* model */
1543 if (model != NULL)
1544 log_printf("%-15s ", model, 0);
1545 else
1546 log_printf("%-15s ", "unknown", 0);
1547 /* portid */
1548 log_printf("%-3d ", portid, 0);
1549 /* status */
1550 if (status == (char *)NULL)
1551 log_printf(" ok ", 0);
1552 else
1553 log_printf(" fail ", 0);
1554 /* revision */
1555 log_printf(" %-4d ", revision, 0);
1556 #ifdef DEBUG
1557 log_printf("%s", notes, 0);
1558 #endif
1559 log_printf("\n", 0);
1561 bnode = bnode->next;
1565 /*ARGSUSED0*/
1566 void
1567 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
1569 serengeti_display_board_info(ACTIVE);
1570 serengeti_display_board_info(INACTIVE);
1574 * display_failed_parts
1576 * Display the failed parts in the system. This function looks for
1577 * the status property in all PROM nodes contained in the Sys_tree
1578 * passed in.
1581 display_failed_parts(Sys_tree *tree)
1583 int system_failed = 0;
1584 int bank_failed = 0;
1585 int schizo_failed = FALSE;
1586 int portid, nodeid, board;
1587 Board_node *bnode = tree->bd_list;
1588 Prom_node *pnode;
1589 int *coreid, *impl;
1590 print_flag = TRUE;
1593 * go through all of the OBP nodes looking for
1594 * failed units.
1596 while (bnode != NULL) {
1598 pnode = find_failed_node(bnode->nodes);
1599 if ((pnode != NULL) && !system_failed) {
1600 system_failed = TRUE;
1601 log_printf("\n", 0);
1602 log_printf(dgettext(TEXT_DOMAIN,
1603 "Failed Field Replaceable Units (FRU) in "
1604 "System:\n"), 0);
1605 log_printf("=========================="
1606 "====================\n", 0);
1609 while (pnode != NULL) {
1610 void *status;
1611 char *name, *type, *model;
1613 char fru_name[MAX_FRU_NAME_LEN] = "";
1615 status = get_prop_val(find_prop(pnode, "status"));
1616 name = get_node_name(pnode);
1618 /* sanity check of data retreived from PROM */
1619 if ((status == NULL) || (name == NULL)) {
1620 pnode = next_failed_node(pnode);
1621 continue;
1624 type = get_node_type(pnode);
1625 portid = get_id(pnode);
1626 model = (char *)get_prop_val
1627 (find_prop(pnode, "model"));
1630 * Determine whether FRU is CPU module, Mem Controller,
1631 * PCI card, schizo,xmits or sgsbbc.
1633 if ((model != NULL) && strstr(model, "sgsbbc")) {
1635 * sgsbbc / bootbus-controller
1637 portid = get_id(pnode->parent);
1638 nodeid = SG_PORTID_TO_NODEID(portid);
1639 board = SG_PORTID_TO_BOARD_NUM(portid);
1641 SG_SET_FRU_NAME_NODE(fru_name, nodeid);
1642 SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
1643 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
1645 log_printf("\tFailed Device : %s (%s)\n", model,
1646 name, 0);
1647 log_printf("\tLocation : %s\n", fru_name, 0);
1649 } else if (strstr(name, "pci") && (portid == -1)) {
1651 * PCI Bridge if name = pci and it doesn't
1652 * have a portid.
1654 portid = get_id(pnode->parent);
1655 nodeid = SG_PORTID_TO_NODEID(portid);
1656 board = SG_PORTID_TO_BOARD_NUM(portid);
1658 SG_SET_FRU_NAME_NODE(fru_name, nodeid);
1659 SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
1660 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
1662 log_printf("\tFRU type : ", 0);
1663 log_printf("PCI Bridge Device\n", 0);
1664 log_printf("\tLocation : %s\n", fru_name, 0);
1666 } else if ((type != NULL) &&
1667 (strstr(type, "cpu") ||
1668 strstr(type, "memory-controller"))) {
1670 * CPU or memory controller
1672 portid = get_id(pnode);
1674 * For cpu nodes that belong to a CMP, the
1675 * portid is stored in the parent "cmp" node.
1677 if (portid == -1)
1678 portid = get_id(pnode->parent);
1679 nodeid = SG_PORTID_TO_NODEID(portid);
1680 board = SG_PORTID_TO_BOARD_NUM(portid);
1682 SG_SET_FRU_NAME_NODE(fru_name, nodeid);
1683 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
1684 SG_SET_FRU_NAME_MODULE(fru_name, portid % 4);
1686 log_printf("\tFRU type : ", 0);
1688 if (strstr(type, "memory-controller"))
1689 log_printf("Memory Controller on ", 0);
1691 log_printf("UltraSPARC module\n", 0);
1693 log_printf("\tLocation : %s\n", fru_name, 0);
1695 } else {
1697 * It should only be a PCI card if we get to
1698 * here but lets check to be sure.
1700 char *parents_model, *grandparents_model;
1701 Prom_node *parent_pnode;
1702 int pci_card_found = 0;
1704 if (pnode->parent != NULL)
1705 parent_pnode = pnode->parent;
1708 * Is our parent a schizo or xmits
1710 parents_model = (char *)get_prop_val
1711 (find_prop(pnode->parent, "model"));
1712 if ((parents_model != NULL) &&
1713 (strstr(parents_model, "SUNW,schizo") ||
1714 strstr(parents_model, "SUNW,xmits"))) {
1715 portid = get_id(pnode->parent);
1716 pci_card_found = TRUE;
1720 * Is our grandparent a schizo xmits
1722 grandparents_model = (char *)get_prop_val
1723 (find_prop(parent_pnode->parent, "model"));
1724 if ((grandparents_model != NULL) &&
1725 (strstr(grandparents_model,
1726 "SUNW,schizo") ||
1727 strstr(grandparents_model,
1728 "SUNW,xmits"))) {
1729 portid = get_id(parent_pnode->parent);
1730 pci_card_found = TRUE;
1733 if (pci_card_found) {
1734 nodeid = SG_PORTID_TO_NODEID(portid);
1735 board = SG_PORTID_TO_BOARD_NUM(portid);
1737 SG_SET_FRU_NAME_NODE(fru_name, nodeid);
1738 SG_SET_FRU_NAME_IO_BOARD(fru_name,
1739 board);
1740 SG_SET_FRU_NAME_MODULE(fru_name,
1741 portid % 2);
1743 log_printf("\tFRU type :", 0);
1744 log_printf(" PCI Card\n", 0);
1745 log_printf("\tLocation : %s\n",
1746 fru_name, 0);
1749 log_printf("\tPROM status: %s\n\n", status, 0);
1751 pnode = next_failed_node(pnode);
1753 bnode = bnode->next;
1757 bank_failed = display_us3_failed_banks(system_failed);
1758 schizo_failed = display_schizo_revisions(tree->bd_list,
1759 SG_SCHIZO_FAILED);
1760 if (system_failed || bank_failed || schizo_failed)
1761 return (1);
1762 else
1763 return (0);
1768 * This routine displays the memory configuration for all boards in the
1769 * system.
1771 /*ARGSUSED0*/
1772 void
1773 display_memoryconf(Sys_tree *tree, struct grp_info *grps)
1775 Board_node *bnode = tree->bd_list;
1777 log_printf("========================= Memory Configuration"
1778 " ===============================\n", 0);
1779 log_printf("\n Logical Logical Logical ", 0);
1780 log_printf("\n Port Bank Bank Bank "
1781 "DIMM Interleave Interleave", 0);
1782 log_printf("\nFRU Name ID Num Size Status "
1783 "Size Factor Segment", 0);
1784 log_printf("\n------------- ---- ---- ------ ----------- "
1785 "------ ---------- ----------", 0);
1787 while (bnode != NULL) {
1788 if (get_us3_mem_regs(bnode)) {
1789 log_printf(dgettext(TEXT_DOMAIN,
1790 "\nFailed to get memory information.\n"), 0);
1791 return;
1793 bnode = bnode->next;
1796 /* Display what we have found */
1797 display_us3_banks();
1801 * This function provides Serengeti's formatting of the memory config
1802 * information that get_us3_mem_regs() and display_us3_banks() code has
1803 * gathered. It overrides the generic print_us3_memory_line() code
1804 * which prints an error message.
1806 void
1807 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
1808 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
1810 int nodeid, board, mcid;
1811 char fru_name[MAX_FRU_NAME_LEN] = "";
1813 mcid = SG_PORTID_TO_SAFARI_ID(portid);
1814 nodeid = SG_PORTID_TO_NODEID(portid);
1815 board = SG_PORTID_TO_BOARD_NUM(portid);
1817 SG_SET_FRU_NAME_NODE(fru_name, nodeid);
1818 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
1819 SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
1820 SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
1822 log_printf("\n%-13s %2d %2d %4lldMB %11-s %4lldMB "
1823 " %2d-way %d",
1824 fru_name, mcid,
1825 (bank_id % 4), bank_size, bank_status, dimm_size,
1826 intlv, seg_id, 0);
1829 void
1830 print_us3_failed_memory_line(int portid, int bank_id, char *bank_status)
1832 int nodeid, board, mcid;
1833 char fru_name[MAX_FRU_NAME_LEN] = "";
1835 mcid = SG_PORTID_TO_SAFARI_ID(portid);
1836 nodeid = SG_PORTID_TO_NODEID(portid);
1837 board = SG_PORTID_TO_BOARD_NUM(portid);
1839 SG_SET_FRU_NAME_NODE(fru_name, nodeid);
1840 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
1841 SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
1842 SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
1844 log_printf("\tFRU type : ", 0);
1845 log_printf("Physical Memory Bank\n", 0);
1846 log_printf("\tLocation : %s (Logical Bank %2d)\n",
1847 fru_name, (bank_id %4), 0);
1848 log_printf("\tPROM status: %s\n\n", bank_status, 0);
1853 * Find the requested board struct in the system device tree.
1855 * This function overrides the functionality of the generic find_board()
1856 * function in libprtdiag, but since we need to pass another parameter,
1857 * we cannot simply overlay the symbol table.
1859 static Board_node *
1860 serengeti_find_board(Sys_tree *root, int board, int nodeid)
1862 Board_node *bnode = root->bd_list;
1864 while ((bnode != NULL) &&
1865 ((board != bnode->board_num) || (nodeid != bnode->node_id))) {
1866 bnode = bnode->next;
1868 return (bnode);
1873 * Add a board to the system list in order (sorted by NodeID then board#).
1874 * Initialize all pointer fields to NULL.
1876 static Board_node *
1877 serengeti_insert_board(Sys_tree *root, int board, int nodeid)
1879 Board_node *bnode;
1880 Board_node *temp = root->bd_list;
1882 if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
1883 perror("malloc");
1884 exit(1);
1887 bnode->nodes = NULL;
1888 bnode->next = NULL;
1889 bnode->board_num = board;
1890 bnode->node_id = nodeid;
1891 bnode->board_type = UNKNOWN_BOARD;
1893 if (temp == NULL)
1894 root->bd_list = bnode;
1896 else if ((temp->board_num > board) && (temp->node_id >= nodeid)) {
1897 bnode->next = temp;
1898 root->bd_list = bnode;
1900 } else {
1901 while ((temp->next != NULL) &&
1902 ((board > temp->next->board_num) ||
1903 (nodeid > temp->node_id)))
1904 temp = temp->next;
1906 bnode->next = temp->next;
1907 temp->next = bnode;
1909 root->board_cnt++;
1911 return (bnode);
1915 * We call do_devinfo() in order to use the libdevinfo device tree
1916 * instead of OBP's device tree.
1919 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
1922 return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
1927 * return the property value for the Prop passed in depending on
1928 * which tree (OBP/DEVINFO) is being used.
1930 void *
1931 get_prop_val(Prop *prop)
1933 if (prop == NULL)
1934 return (NULL);
1936 /* Check which tree is being used. */
1937 if (tree == DEVINFO_TREE)
1938 return ((void *)(prop->value.val_ptr));
1939 else {
1940 if (prop->value.opp.holds_array)
1941 return ((void *)(prop->value.opp.oprom_array));
1942 else
1943 return ((void *)(&prop->value.opp.oprom_node[0]));
1948 * Search a Prom node and retrieve the property with the correct
1949 * name depending on which tree (OBP/DEVINFO) is being used.
1951 Prop *
1952 find_prop(Prom_node *pnode, char *name)
1954 Prop *prop;
1956 if (pnode == NULL)
1957 return (NULL);
1959 if (pnode->props == NULL)
1960 return (NULL);
1962 prop = pnode->props;
1964 /* Check which tree is being used. */
1965 if (tree == DEVINFO_TREE) {
1966 while ((prop != NULL) &&
1967 (strcmp((char *)(prop->name.val_ptr), name)))
1968 prop = prop->next;
1969 } else {
1970 while ((prop != NULL) && (strcmp((char *)
1971 (prop->name.opp.oprom_array), name)))
1972 prop = prop->next;
1974 return (prop);
1978 * This function searches through the properties of the node passed in
1979 * and returns a pointer to the value of the name property
1980 * depending on which tree (OBP/DEVINFO) is being used.
1982 char *
1983 get_node_name(Prom_node *pnode)
1985 Prop *prop;
1987 if (pnode == NULL)
1988 return (NULL);
1990 prop = pnode->props;
1991 while (prop != NULL) {
1992 /* Check which tree is being used. */
1993 if (tree == DEVINFO_TREE) {
1994 if (strcmp("name", (char *)prop->name.val_ptr) == 0)
1995 return ((char *)prop->value.val_ptr);
1996 } else {
1997 if (strcmp("name", prop->name.opp.oprom_array) == 0)
1998 return (prop->value.opp.oprom_array);
2000 prop = prop->next;
2002 return (NULL);
2006 * This function searches through the properties of the node passed in
2007 * and returns a pointer to the value of the device_type property
2008 * depending on which tree (OBP/DEVINFO) is being used.
2010 char *
2011 get_node_type(Prom_node *pnode)
2013 Prop *prop;
2015 if (pnode == NULL)
2016 return (NULL);
2018 prop = pnode->props;
2019 while (prop != NULL) {
2020 /* Check which tree is being used. */
2021 if (tree == DEVINFO_TREE) {
2022 if (strcmp("device_type", (char *)prop->name.val_ptr)
2023 == 0)
2024 return ((char *)prop->value.val_ptr);
2025 } else {
2026 if (strcmp("device_type", prop->name.opp.oprom_array)
2027 == 0)
2028 return (prop->value.opp.oprom_array);
2030 prop = prop->next;
2032 return (NULL);
2036 * Take a snapshot of the OBP device tree and walk this snapshot
2037 * to find all failed HW (ie. devices with a status property of
2038 * 'fail'). Call display_failed_parts() to display the failed HW.
2040 void
2041 get_failed_parts(void)
2043 int system_failed = 0;
2044 Sys_tree obp_sys_tree; /* system information */
2046 /* set the the system tree fields */
2047 obp_sys_tree.sys_mem = NULL;
2048 obp_sys_tree.boards = NULL;
2049 obp_sys_tree.bd_list = NULL;
2050 obp_sys_tree.board_cnt = 0;
2052 if (promopen(O_RDONLY)) {
2053 (void) fprintf(stderr, "%s",
2054 dgettext(TEXT_DOMAIN, "openprom device "
2055 "open failed"));
2056 return;
2059 if ((is_openprom() == 0) || (next(0) == 0)) {
2060 (void) fprintf(stderr, "%s",
2061 dgettext(TEXT_DOMAIN, "openprom device "
2062 "error encountered."));
2063 return;
2066 tree = OBP_TREE; /* Switch to the OBP tree */
2068 (void) walk(&obp_sys_tree, NULL, next(0));
2070 system_failed = display_failed_parts(&obp_sys_tree);
2072 if (!system_failed) {
2073 log_printf(dgettext(TEXT_DOMAIN,
2074 "No Hardware failures found in System\n"), 0);
2076 promclose();
2077 tree = DEVINFO_TREE; /* Switch back to the DEVINFO tree */
2081 * get_slot_name figures out the slot no. for the card. In the case of
2082 * XMITS slots 2 & 3 and slots 6 & 7 are reversed in slot_name by OBP
2083 * so we need to cater for this to correctly identify the slot no.
2085 static void
2086 get_slot_name(struct io_card *card, char *slot_name)
2088 char tmp_ptr[2];
2090 if (strlen(slot_name) != 0) {
2091 if (strcmp(card->notes, XMITS_COMPATIBLE) == 0) {
2092 (void) sprintf(tmp_ptr, "%c",
2093 slot_name[strlen(slot_name) -1]);
2094 switch (tmp_ptr[0]) {
2095 case '2':
2096 (void) sprintf(card->slot_str, "%c", '3');
2097 break;
2098 case '3':
2099 (void) sprintf(card->slot_str, "%c", '2');
2100 break;
2101 case '6':
2102 (void) sprintf(card->slot_str, "%c", '7');
2103 break;
2104 case '7':
2105 (void) sprintf(card->slot_str, "%c", '6');
2106 break;
2107 default:
2108 (void) sprintf(card->slot_str, "%c",
2109 slot_name[strlen(slot_name) -1]);
2111 } else
2112 (void) sprintf(card->slot_str, "%c",
2113 slot_name[strlen(slot_name) -1]);
2114 } else
2115 (void) sprintf(card->slot_str, "-");