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