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