xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/desktop/common/desktop.c (revision 2bcbf80ce6c8a2fb827428428c350ebe4f91f7ab)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License, Version 1.0 only
603831d35Sstevel  * (the "License").  You may not use this file except in compliance
703831d35Sstevel  * with the License.
803831d35Sstevel  *
903831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1003831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1103831d35Sstevel  * See the License for the specific language governing permissions
1203831d35Sstevel  * and limitations under the License.
1303831d35Sstevel  *
1403831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1503831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1603831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1703831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1803831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1903831d35Sstevel  *
2003831d35Sstevel  * CDDL HEADER END
2103831d35Sstevel  */
2203831d35Sstevel /*
2303831d35Sstevel  * Copyright 1999-2002 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
25*2bcbf80cSPeter Tribble  * Copyright 2020 Peter Tribble.
2603831d35Sstevel  *
2703831d35Sstevel  * Desktop Platform specific functions.
2803831d35Sstevel  *
2903831d35Sstevel  *	Called when:
3003831d35Sstevel  *	machine_type == MTYPE_DARWIN &&
3103831d35Sstevel  *	machine_type == MTYPE_DEFAULT
3203831d35Sstevel  *
3303831d35Sstevel  */
3403831d35Sstevel 
3503831d35Sstevel #include <stdio.h>
3603831d35Sstevel #include <stdlib.h>
3703831d35Sstevel #include <unistd.h>
3803831d35Sstevel #include <ctype.h>
3903831d35Sstevel #include <string.h>
4003831d35Sstevel #include <kvm.h>
4103831d35Sstevel #include <varargs.h>
4203831d35Sstevel #include <errno.h>
4303831d35Sstevel #include <time.h>
4403831d35Sstevel #include <dirent.h>
4503831d35Sstevel #include <fcntl.h>
4603831d35Sstevel #include <sys/param.h>
4703831d35Sstevel #include <sys/stat.h>
4803831d35Sstevel #include <sys/types.h>
4903831d35Sstevel #include <sys/systeminfo.h>
5003831d35Sstevel #include <sys/utsname.h>
5103831d35Sstevel #include <sys/openpromio.h>
5203831d35Sstevel #include <kstat.h>
5303831d35Sstevel #include <libintl.h>
5403831d35Sstevel #include <syslog.h>
5503831d35Sstevel #include <sys/dkio.h>
5603831d35Sstevel #include "pdevinfo.h"
5703831d35Sstevel #include "display.h"
5803831d35Sstevel #include "pdevinfo_sun4u.h"
5903831d35Sstevel #include "display_sun4u.h"
6003831d35Sstevel #include "libprtdiag.h"
6103831d35Sstevel 
6203831d35Sstevel #if !defined(TEXT_DOMAIN)
6303831d35Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
6403831d35Sstevel #endif
6503831d35Sstevel 
6603831d35Sstevel 
6703831d35Sstevel #define	PCI_BUS(x)		((x  >> 16) & 0xff)
6803831d35Sstevel 
6903831d35Sstevel /*
7003831d35Sstevel  * State variable to signify the type of machine we're currently
7103831d35Sstevel  * running on.  Since prtdiag has come to be the dumping ground
7203831d35Sstevel  * for lots of platform-specific routines, and machine architecture
7303831d35Sstevel  * alone is not enough to determine our course of action, we need
7403831d35Sstevel  * to enumerate the different machine types that we should worry
7503831d35Sstevel  * about.
7603831d35Sstevel  */
7703831d35Sstevel enum machine_type {
7803831d35Sstevel 	MTYPE_DEFAULT = 0,  /* Desktop-class machine */
7903831d35Sstevel 	MTYPE_DARWIN = 1
8003831d35Sstevel };
8103831d35Sstevel 
8203831d35Sstevel enum machine_type machine_type = MTYPE_DEFAULT;
8303831d35Sstevel 
8403831d35Sstevel extern	int	print_flag;
8503831d35Sstevel 
8603831d35Sstevel /*
8703831d35Sstevel  * these functions will overlay the symbol table of libprtdiag
8803831d35Sstevel  * at runtime (desktop systems only)
8903831d35Sstevel  */
9003831d35Sstevel int	error_check(Sys_tree *tree, struct system_kstat_data *kstats);
9103831d35Sstevel int	disp_fail_parts(Sys_tree *tree);
9203831d35Sstevel void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
9303831d35Sstevel void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
9403831d35Sstevel 		struct system_kstat_data *kstats);
9503831d35Sstevel void	display_pci(Board_node *bnode);
9603831d35Sstevel void	display_sbus(Board_node *);
9703831d35Sstevel 
9803831d35Sstevel 
9903831d35Sstevel /* local functions */
10003831d35Sstevel static	void dt_disp_asic_revs(Sys_tree *);
10103831d35Sstevel static	void display_sabre_pci(Board_node *);
10203831d35Sstevel static	void display_dev_node(Prom_node *np, int depth);
10303831d35Sstevel static	void get_machine_type(void);
10403831d35Sstevel 
10503831d35Sstevel int
error_check(Sys_tree * tree,struct system_kstat_data * kstats)10603831d35Sstevel error_check(Sys_tree *tree, struct system_kstat_data *kstats)
10703831d35Sstevel {
10803831d35Sstevel 	int exit_code = 0;	/* init to all OK */
10903831d35Sstevel 
11003831d35Sstevel #ifdef lint
11103831d35Sstevel 	kstats = kstats;
11203831d35Sstevel #endif
11303831d35Sstevel 
11403831d35Sstevel 	/*
11503831d35Sstevel 	 * silently check for any types of machine errors
11603831d35Sstevel 	 */
11703831d35Sstevel 	print_flag = 0;
11803831d35Sstevel 	if (disp_fail_parts(tree)) {
11903831d35Sstevel 		/* set exit_code to show failures */
12003831d35Sstevel 		exit_code = 1;
12103831d35Sstevel 	}
12203831d35Sstevel 	print_flag = 1;
12303831d35Sstevel 
12403831d35Sstevel 	return (exit_code);
12503831d35Sstevel }
12603831d35Sstevel 
12703831d35Sstevel 
12803831d35Sstevel /*
12903831d35Sstevel  * disp_fail_parts
13003831d35Sstevel  *
13103831d35Sstevel  * Display the failed parts in the system. This function looks for
13203831d35Sstevel  * the status property in all PROM nodes. On systems where
133*2bcbf80cSPeter Tribble  * the PROM does not support passing diagnostic information
134*2bcbf80cSPeter Tribble  * through the device tree, this routine will be silent.
13503831d35Sstevel  */
13603831d35Sstevel int
disp_fail_parts(Sys_tree * tree)13703831d35Sstevel disp_fail_parts(Sys_tree *tree)
13803831d35Sstevel {
13903831d35Sstevel 	int exit_code;
14003831d35Sstevel 	int system_failed = 0;
14103831d35Sstevel 	Board_node *bnode = tree->bd_list;
14203831d35Sstevel 	Prom_node *pnode;
14303831d35Sstevel 
14403831d35Sstevel 	exit_code = 0;
14503831d35Sstevel 
14603831d35Sstevel 	/* go through all of the boards looking for failed units. */
14703831d35Sstevel 	while (bnode != NULL) {
14803831d35Sstevel 		/* find failed chips */
14903831d35Sstevel 		pnode = find_failed_node(bnode->nodes);
15003831d35Sstevel 		if ((pnode != NULL) && !system_failed) {
15103831d35Sstevel 			system_failed = 1;
15203831d35Sstevel 			exit_code = 1;
15303831d35Sstevel 			if (print_flag == 0) {
15403831d35Sstevel 				return (exit_code);
15503831d35Sstevel 			}
15603831d35Sstevel 			log_printf("\n", 0);
15703831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
15803831d35Sstevel 				"Replaceable Units (FRU) in System:\n"), 0);
15903831d35Sstevel 			log_printf("=========================="
16003831d35Sstevel 				"====================\n", 0);
16103831d35Sstevel 		}
16203831d35Sstevel 
16303831d35Sstevel 		while (pnode != NULL) {
16403831d35Sstevel 			void *value;
16503831d35Sstevel 			char *name;		/* node name string */
16603831d35Sstevel 			char *type;		/* node type string */
16703831d35Sstevel 			char *board_type = NULL;
16803831d35Sstevel 
16903831d35Sstevel 			value = get_prop_val(find_prop(pnode, "status"));
17003831d35Sstevel 			name = get_node_name(pnode);
17103831d35Sstevel 
17203831d35Sstevel 			/* sanity check of data retreived from PROM */
17303831d35Sstevel 			if ((value == NULL) || (name == NULL)) {
17403831d35Sstevel 				pnode = next_failed_node(pnode);
17503831d35Sstevel 				continue;
17603831d35Sstevel 			}
17703831d35Sstevel 
17803831d35Sstevel 			/* Find the board type of this board */
17903831d35Sstevel 			if (bnode->board_type == CPU_BOARD) {
18003831d35Sstevel 				board_type = "CPU";
18103831d35Sstevel 			} else {
18203831d35Sstevel 				board_type = "IO";
18303831d35Sstevel 			}
18403831d35Sstevel 
18503831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "%s unavailable "
18603831d35Sstevel 				"on %s Board #%d\n"), name, board_type,
18703831d35Sstevel 					bnode->board_num, 0);
18803831d35Sstevel 
18903831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
19003831d35Sstevel 				"\tPROM fault string: %s\n"), value, 0);
19103831d35Sstevel 
19203831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
19303831d35Sstevel 				"\tFailed Field Replaceable Unit is "), 0);
19403831d35Sstevel 
19503831d35Sstevel 			/*
19603831d35Sstevel 			 * Determine whether FRU is CPU module, system
19703831d35Sstevel 			 * board, or SBus card.
19803831d35Sstevel 			 */
19903831d35Sstevel 			if ((name != NULL) && (strstr(name, "sbus"))) {
20003831d35Sstevel 
20103831d35Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
20203831d35Sstevel 					"SBus Card %d\n"),
20303831d35Sstevel 					get_sbus_slot(pnode), 0);
20403831d35Sstevel 
20503831d35Sstevel 			} else if (((name = get_node_name(pnode->parent)) !=
20603831d35Sstevel 			    NULL) && (strstr(name, "pci"))) {
20703831d35Sstevel 
20803831d35Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
20903831d35Sstevel 					"PCI Card %d"),
21003831d35Sstevel 					get_pci_device(pnode), 0);
21103831d35Sstevel 
21203831d35Sstevel 			} else if (((type = get_node_type(pnode)) != NULL) &&
21303831d35Sstevel 			    (strstr(type, "cpu"))) {
21403831d35Sstevel 
21503831d35Sstevel 				log_printf(dgettext(TEXT_DOMAIN, "UltraSPARC "
21603831d35Sstevel 					"module Board %d Module %d\n"), 0,
21703831d35Sstevel 						get_id(pnode));
21803831d35Sstevel 
21903831d35Sstevel 			} else {
22003831d35Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
22103831d35Sstevel 					"%s board %d\n"), board_type,
22203831d35Sstevel 					bnode->board_num, 0);
22303831d35Sstevel 			}
22403831d35Sstevel 			pnode = next_failed_node(pnode);
22503831d35Sstevel 		}
22603831d35Sstevel 		bnode = bnode->next;
22703831d35Sstevel 	}
22803831d35Sstevel 
22903831d35Sstevel 	if (!system_failed) {
23003831d35Sstevel 		log_printf("\n", 0);
23103831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
23203831d35Sstevel 			"No failures found in System\n"), 0);
23303831d35Sstevel 		log_printf("===========================\n", 0);
23403831d35Sstevel 	}
23503831d35Sstevel 
23603831d35Sstevel 	if (system_failed)
23703831d35Sstevel 		return (1);
23803831d35Sstevel 	else
23903831d35Sstevel 		return (0);
24003831d35Sstevel }
24103831d35Sstevel 
24203831d35Sstevel 
24303831d35Sstevel void
display_hp_fail_fault(Sys_tree * tree,struct system_kstat_data * kstats)24403831d35Sstevel display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
24503831d35Sstevel {
24603831d35Sstevel 
24703831d35Sstevel #ifdef lint
24803831d35Sstevel 	kstats = kstats;
24903831d35Sstevel #endif
25003831d35Sstevel 	/* Display failed units */
25103831d35Sstevel 	(void) disp_fail_parts(tree);
25203831d35Sstevel }
25303831d35Sstevel 
25403831d35Sstevel void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)25503831d35Sstevel display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
25603831d35Sstevel 	struct system_kstat_data *kstats)
25703831d35Sstevel {
25803831d35Sstevel 
25903831d35Sstevel #ifdef	lint
26003831d35Sstevel 	kstats = kstats;
26103831d35Sstevel #endif
26203831d35Sstevel 	/*
26303831d35Sstevel 	 * Now display the last powerfail time and the fatal hardware
26403831d35Sstevel 	 * reset information. We do this under a couple of conditions.
26503831d35Sstevel 	 * First if the user asks for it. The second is iof the user
26603831d35Sstevel 	 * told us to do logging, and we found a system failure.
26703831d35Sstevel 	 */
26803831d35Sstevel 	if (flag) {
26903831d35Sstevel 		/*
27003831d35Sstevel 		 * display time of latest powerfail. Not all systems
27103831d35Sstevel 		 * have this capability. For those that do not, this
27203831d35Sstevel 		 * is just a no-op.
27303831d35Sstevel 		 */
27403831d35Sstevel 		disp_powerfail(root);
27503831d35Sstevel 
27603831d35Sstevel 		dt_disp_asic_revs(tree);
27703831d35Sstevel 
27803831d35Sstevel 		platform_disp_prom_version(tree);
27903831d35Sstevel 	}
28003831d35Sstevel 	return;
28103831d35Sstevel 
28203831d35Sstevel }
28303831d35Sstevel 
28403831d35Sstevel void
display_pci(Board_node * bnode)28503831d35Sstevel display_pci(Board_node *bnode)
28603831d35Sstevel {
28703831d35Sstevel 	Prom_node	*pci;
28803831d35Sstevel 
28903831d35Sstevel 	/*
29003831d35Sstevel 	 * We have different routines for walking/displaying PCI
29103831d35Sstevel 	 * devices depending on whether the PCI device is a
29203831d35Sstevel 	 * Psycho or a Sabre.
29303831d35Sstevel 	 */
29403831d35Sstevel 	pci = dev_find_node_by_type(bnode->nodes, "model", "SUNW,psycho");
29503831d35Sstevel 	if (pci != NULL) {
29603831d35Sstevel 		display_psycho_pci(bnode);
29703831d35Sstevel 		return;
29803831d35Sstevel 	}
29903831d35Sstevel 
30003831d35Sstevel 	pci = dev_find_node_by_type(bnode->nodes, "model", "SUNW,sabre");
30103831d35Sstevel 	if (pci != NULL) {
30203831d35Sstevel 		display_sabre_pci(bnode);
30303831d35Sstevel 		return;
30403831d35Sstevel 	}
30503831d35Sstevel }
30603831d35Sstevel 
30703831d35Sstevel /*
30803831d35Sstevel  * local functions
30903831d35Sstevel  */
31003831d35Sstevel 
31103831d35Sstevel void
dt_disp_asic_revs(Sys_tree * tree)31203831d35Sstevel dt_disp_asic_revs(Sys_tree *tree)
31303831d35Sstevel {
31403831d35Sstevel 	Board_node *bnode;
31503831d35Sstevel 	Prom_node *pnode;
31603831d35Sstevel 	char *name;
31703831d35Sstevel 	int *version;
31803831d35Sstevel 
31903831d35Sstevel 	/* Print the header */
32003831d35Sstevel 	log_printf("\n", 0);
32103831d35Sstevel 	log_printf("=========================", 0);
32203831d35Sstevel 	log_printf(" HW Revisions ", 0);
32303831d35Sstevel 	log_printf("=========================", 0);
32403831d35Sstevel 	log_printf("\n", 0);
32503831d35Sstevel 	log_printf("\n", 0);
32603831d35Sstevel 
32703831d35Sstevel 	bnode = tree->bd_list;
32803831d35Sstevel 
32903831d35Sstevel 	log_printf("ASIC Revisions:\n", 0);
33003831d35Sstevel 	log_printf("---------------\n", 0);
33103831d35Sstevel 
33203831d35Sstevel 	/* Find sysio and print rev */
33303831d35Sstevel 	for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
33403831d35Sstevel 	    pnode = dev_next_node(pnode, "sbus")) {
33503831d35Sstevel 		version = (int *)get_prop_val(find_prop(pnode, "version#"));
33603831d35Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
33703831d35Sstevel 
33803831d35Sstevel 		if ((version != NULL) && (name != NULL)) {
33903831d35Sstevel 			log_printf("SBus: %s Rev %d\n",
34003831d35Sstevel 				name, *version, 0);
34103831d35Sstevel 		}
34203831d35Sstevel 	}
34303831d35Sstevel 
34403831d35Sstevel 	/* Find Psycho and print rev */
34503831d35Sstevel 	for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
34603831d35Sstevel 	    pnode = dev_next_node(pnode, "pci")) {
34703831d35Sstevel 		version = (int *)get_prop_val(find_prop(pnode, "version#"));
34803831d35Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
34903831d35Sstevel 
35003831d35Sstevel 		if ((version != NULL) && (name != NULL))
35103831d35Sstevel 			log_printf("PCI: %s Rev %d\n",
35203831d35Sstevel 				name, *version, 0);
35303831d35Sstevel 	}
35403831d35Sstevel 
35503831d35Sstevel 	/* Find Cheerio and print rev */
35603831d35Sstevel 	for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
35703831d35Sstevel 	    pnode = dev_next_node(pnode, "ebus")) {
35803831d35Sstevel 		version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
35903831d35Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
36003831d35Sstevel 
36103831d35Sstevel 		if ((version != NULL) && (name != NULL))
36203831d35Sstevel 			log_printf("Cheerio: %s Rev %d\n", name, *version, 0);
36303831d35Sstevel 	}
36403831d35Sstevel 
36503831d35Sstevel 
36603831d35Sstevel 	/* Find the FEPS and print rev */
36703831d35Sstevel 	for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
36803831d35Sstevel 	    pnode = dev_next_node(pnode, "SUNW,hme")) {
36903831d35Sstevel 		version = (int *)get_prop_val(find_prop(pnode,	"hm-rev"));
37003831d35Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
37103831d35Sstevel 
37203831d35Sstevel 		if ((version != NULL) && (name != NULL)) {
37303831d35Sstevel 			log_printf("FEPS: %s Rev ", name);
37403831d35Sstevel 			if (*version == 0xa0) {
37503831d35Sstevel 				log_printf("2.0\n", 0);
37603831d35Sstevel 			} else if (*version == 0x20) {
37703831d35Sstevel 				log_printf("2.1\n", 0);
37803831d35Sstevel 			} else {
37903831d35Sstevel 				log_printf("%x\n", *version, 0);
38003831d35Sstevel 			}
38103831d35Sstevel 		}
38203831d35Sstevel 	}
38303831d35Sstevel 	log_printf("\n", 0);
38403831d35Sstevel 
38503831d35Sstevel 	display_ffb(bnode, 0);
38603831d35Sstevel }
38703831d35Sstevel 
38803831d35Sstevel /*
38903831d35Sstevel  * print the header and call display_dev_node() to walk the device
39003831d35Sstevel  * tree (darwin platform only).
39103831d35Sstevel  */
39203831d35Sstevel static void
display_sabre_pci(Board_node * board)39303831d35Sstevel display_sabre_pci(Board_node *board)
39403831d35Sstevel {
39503831d35Sstevel 	if (board == NULL)
39603831d35Sstevel 		return;
39703831d35Sstevel 
39803831d35Sstevel 	log_printf("     Bus#  Freq\n", 0);
39903831d35Sstevel 	log_printf("Brd  Type  MHz   Slot  "
40003831d35Sstevel 		"Name                              Model", 0);
40103831d35Sstevel 	log_printf("\n", 0);
40203831d35Sstevel 	log_printf("---  ----  ----  ----  "
40303831d35Sstevel 		"--------------------------------  ----------------------", 0);
40403831d35Sstevel 	log_printf("\n", 0);
40503831d35Sstevel 	display_dev_node(board->nodes, 0);
40603831d35Sstevel 	log_printf("\n", 0);
40703831d35Sstevel }
40803831d35Sstevel 
40903831d35Sstevel 
41003831d35Sstevel /*
41103831d35Sstevel  * Recursively traverse the device tree and use tree depth as filter.
41203831d35Sstevel  * called by: display_sabre_pci()
41303831d35Sstevel  */
41403831d35Sstevel static void
display_dev_node(Prom_node * np,int depth)41503831d35Sstevel display_dev_node(Prom_node *np, int depth)
41603831d35Sstevel {
41703831d35Sstevel 	char *name, *model, *compat, *regval;
41803831d35Sstevel 	unsigned int reghi;
41903831d35Sstevel 
42003831d35Sstevel 	if (!np)
42103831d35Sstevel 		return;
42203831d35Sstevel 	if (depth > 2)
42303831d35Sstevel 		return;
42403831d35Sstevel 
42503831d35Sstevel 	name = get_prop_val(find_prop(np, "name"));
42603831d35Sstevel 	model = get_prop_val(find_prop(np, "model"));
42703831d35Sstevel 	compat = get_prop_val(find_prop(np, "compatible"));
42803831d35Sstevel 	regval = get_prop_val(find_prop(np, "reg"));
42903831d35Sstevel 
43003831d35Sstevel 	if (!regval)
43103831d35Sstevel 		return;
43203831d35Sstevel 	else
43303831d35Sstevel 		reghi = *(int *)regval;
43403831d35Sstevel 
43503831d35Sstevel 	if (!model)
43603831d35Sstevel 		model = "";
43703831d35Sstevel 	if (!name)
43803831d35Sstevel 		name = "";
43903831d35Sstevel 
44003831d35Sstevel 	if (depth == 2) {
44103831d35Sstevel 		char buf[256];
44203831d35Sstevel 		if (compat)
44303831d35Sstevel 			(void) sprintf(buf, "%s-%s", name, compat);
44403831d35Sstevel 		else
44503831d35Sstevel 			(void) sprintf(buf, "%s", name);
44603831d35Sstevel 
44703831d35Sstevel 		log_printf(" 0   PCI-%d  33   ", PCI_BUS(reghi), 0);
44803831d35Sstevel 		log_printf("%3d   ", PCI_DEVICE(reghi), 0);
44903831d35Sstevel 		log_printf("%-32.32s", buf, 0);
45003831d35Sstevel 		log_printf(strlen(buf) > 32 ? "+ " : "  ", 0);
45103831d35Sstevel 		log_printf("%-22.22s", model, 0);
45203831d35Sstevel 		log_printf(strlen(model) > 22 ? "+" : "", 0);
45303831d35Sstevel 		log_printf("\n", 0);
45403831d35Sstevel 
45503831d35Sstevel #ifdef DEBUG
45603831d35Sstevel 		if (!compat)
45703831d35Sstevel 			compat = "";
45803831d35Sstevel 		printf("bus=%d slot=%d name=%s model=%s compat=%s\n",
45903831d35Sstevel 			PCI_BUS(reghi), PCI_DEVICE(reghi), name, model, compat);
46003831d35Sstevel #endif
46103831d35Sstevel 	}
46203831d35Sstevel 
46303831d35Sstevel 	if ((!strstr(name, "ebus")) && (!strstr(name, "ide")))
46403831d35Sstevel 		display_dev_node(np->child, depth+1);
46503831d35Sstevel 	display_dev_node(np->sibling, depth);
46603831d35Sstevel }
46703831d35Sstevel 
46803831d35Sstevel /*
46903831d35Sstevel  * display_sbus
47003831d35Sstevel  * Display all the SBus IO cards on this board.
47103831d35Sstevel  */
47203831d35Sstevel void
display_sbus(Board_node * board)47303831d35Sstevel display_sbus(Board_node *board)
47403831d35Sstevel {
47503831d35Sstevel 	struct io_card card;
47603831d35Sstevel 	struct io_card *card_list = NULL;
47703831d35Sstevel 	int freq;
47803831d35Sstevel 	int card_num;
47903831d35Sstevel 	void *value;
48003831d35Sstevel 	Prom_node *sbus;
48103831d35Sstevel 	Prom_node *card_node;
48203831d35Sstevel 
48303831d35Sstevel 	if (board == NULL)
48403831d35Sstevel 		return;
48503831d35Sstevel 
48603831d35Sstevel 	for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL;
48703831d35Sstevel 	    sbus = dev_next_node(sbus, SBUS_NAME)) {
48803831d35Sstevel 
48903831d35Sstevel 		/* Skip failed nodes for now */
49003831d35Sstevel 		if (node_failed(sbus))
49103831d35Sstevel 			continue;
49203831d35Sstevel 
49303831d35Sstevel 		/* Calculate SBus frequency in MHz */
49403831d35Sstevel 		value = get_prop_val(find_prop(sbus, "clock-frequency"));
49503831d35Sstevel 		if (value != NULL)
49603831d35Sstevel 			freq = ((*(int *)value) + 500000) / 1000000;
49703831d35Sstevel 		else
49803831d35Sstevel 			freq = -1;
49903831d35Sstevel 
50003831d35Sstevel 		for (card_node = sbus->child; card_node != NULL;
50103831d35Sstevel 		    card_node = card_node->sibling) {
50203831d35Sstevel 			char *model;
50303831d35Sstevel 			char *name;
50403831d35Sstevel 			char *child_name;
50503831d35Sstevel 
50603831d35Sstevel 			card_num = get_sbus_slot(card_node);
50703831d35Sstevel 			if (card_num == -1)
50803831d35Sstevel 				continue;
50903831d35Sstevel 
51003831d35Sstevel 			/* Fill in card information */
51103831d35Sstevel 			card.display = 1;
51203831d35Sstevel 			card.freq = freq;
51303831d35Sstevel 			card.board = board->board_num;
51403831d35Sstevel 			(void) sprintf(card.bus_type, "SBus");
51503831d35Sstevel 			card.slot = card_num;
51603831d35Sstevel 			card.status[0] = '\0';
51703831d35Sstevel 
51803831d35Sstevel 			/* Try and get card status */
51903831d35Sstevel 			value = get_prop_val(find_prop(card_node, "status"));
52003831d35Sstevel 			if (value != NULL)
52103831d35Sstevel 				(void) strncpy(card.status, (char *)value,
52203831d35Sstevel 					MAXSTRLEN);
52303831d35Sstevel 
52403831d35Sstevel 			/* XXX - For now, don't display failed cards */
52503831d35Sstevel 			if (strstr(card.status, "fail") != NULL)
52603831d35Sstevel 				continue;
52703831d35Sstevel 
52803831d35Sstevel 			/*
52903831d35Sstevel 			 * sets the machine_type var if not already set
53003831d35Sstevel 			 */
53103831d35Sstevel 			get_machine_type();
53203831d35Sstevel 
53303831d35Sstevel 			/*
53403831d35Sstevel 			 * For desktops, the only high slot number that
53503831d35Sstevel 			 * needs to be displayed is the # 14 slot.
53603831d35Sstevel 			 */
53703831d35Sstevel 			if (machine_type == MTYPE_DEFAULT &&
53803831d35Sstevel 			    card_num >= MX_SBUS_SLOTS && card_num != 14) {
53903831d35Sstevel 				continue;
54003831d35Sstevel 			}
54103831d35Sstevel 
54203831d35Sstevel 			/* Now gather all of the node names for that card */
54303831d35Sstevel 			model = (char *)get_prop_val(find_prop(card_node,
54403831d35Sstevel 				"model"));
54503831d35Sstevel 			name = get_node_name(card_node);
54603831d35Sstevel 
54703831d35Sstevel 			if (name == NULL)
54803831d35Sstevel 				continue;
54903831d35Sstevel 
55003831d35Sstevel 			card.name[0] = '\0';
55103831d35Sstevel 			card.model[0] = '\0';
55203831d35Sstevel 
55303831d35Sstevel 			/* Figure out how we want to display the name */
55403831d35Sstevel 			child_name = get_node_name(card_node->child);
55503831d35Sstevel 			if ((card_node->child != NULL) &&
55603831d35Sstevel 			    (child_name != NULL)) {
55703831d35Sstevel 				value = get_prop_val(find_prop(card_node->child,
55803831d35Sstevel 					"device_type"));
55903831d35Sstevel 				if (value != NULL)
56003831d35Sstevel 					(void) sprintf(card.name, "%s/%s (%s)",
56103831d35Sstevel 						name, child_name,
56203831d35Sstevel 						(char *)value);
56303831d35Sstevel 				else
56403831d35Sstevel 					(void) sprintf(card.name, "%s/%s", name,
56503831d35Sstevel 						child_name);
56603831d35Sstevel 			} else {
56703831d35Sstevel 				(void) strncpy(card.name, name, MAXSTRLEN);
56803831d35Sstevel 			}
56903831d35Sstevel 
57003831d35Sstevel 			if (model != NULL)
57103831d35Sstevel 				(void) strncpy(card.model, model, MAXSTRLEN);
57203831d35Sstevel 
57303831d35Sstevel 			card_list = insert_io_card(card_list, &card);
57403831d35Sstevel 		}
57503831d35Sstevel 	}
57603831d35Sstevel 
57703831d35Sstevel 	/* We're all done gathering card info, now print it out */
57803831d35Sstevel 	display_io_cards(card_list);
57903831d35Sstevel 	free_io_cards(card_list);
58003831d35Sstevel }
58103831d35Sstevel 
58203831d35Sstevel static void
get_machine_type(void)58303831d35Sstevel get_machine_type(void)
58403831d35Sstevel {
58503831d35Sstevel 	char name[MAXSTRLEN];
58603831d35Sstevel 
58703831d35Sstevel 	machine_type = MTYPE_DEFAULT;
58803831d35Sstevel 
58903831d35Sstevel 	/* Figure out what kind of machine we're on */
59003831d35Sstevel 	if (sysinfo(SI_PLATFORM, name, MAXSTRLEN) != -1) {
59103831d35Sstevel 		if (strcmp(name, "SUNW,Ultra-5_10") == 0)
59203831d35Sstevel 			machine_type = MTYPE_DARWIN;
59303831d35Sstevel 	}
59403831d35Sstevel }
595