xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/serengeti/common/serengeti.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
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
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
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
666 display_ffb(Board_node *board, int table)
667 {}
668 
669 static void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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 *
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 *
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 *
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 *
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
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
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