xref: /onnv-gate/usr/src/lib/libprtdiag_psr/sparc/tazmo/common/tazmo.c (revision 1708:ea74d8598a3a)
1*1708Sstevel /*
2*1708Sstevel  * CDDL HEADER START
3*1708Sstevel  *
4*1708Sstevel  * The contents of this file are subject to the terms of the
5*1708Sstevel  * Common Development and Distribution License, Version 1.0 only
6*1708Sstevel  * (the "License").  You may not use this file except in compliance
7*1708Sstevel  * with the License.
8*1708Sstevel  *
9*1708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*1708Sstevel  * or http://www.opensolaris.org/os/licensing.
11*1708Sstevel  * See the License for the specific language governing permissions
12*1708Sstevel  * and limitations under the License.
13*1708Sstevel  *
14*1708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
15*1708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*1708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
17*1708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
18*1708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
19*1708Sstevel  *
20*1708Sstevel  * CDDL HEADER END
21*1708Sstevel  */
22*1708Sstevel /*
23*1708Sstevel  * Copyright 1999-2002 Sun Microsystems, Inc.  All rights reserved.
24*1708Sstevel  * Use is subject to license terms.
25*1708Sstevel  *
26*1708Sstevel  * Tazmo Platform specific functions.
27*1708Sstevel  *
28*1708Sstevel  * 	called when :
29*1708Sstevel  * 	machine_type == MTYPE_TAZMO
30*1708Sstevel  *
31*1708Sstevel  */
32*1708Sstevel 
33*1708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*1708Sstevel 
35*1708Sstevel #include <stdio.h>
36*1708Sstevel #include <stdlib.h>
37*1708Sstevel #include <unistd.h>
38*1708Sstevel #include <ctype.h>
39*1708Sstevel #include <string.h>
40*1708Sstevel #include <kvm.h>
41*1708Sstevel #include <varargs.h>
42*1708Sstevel #include <errno.h>
43*1708Sstevel #include <time.h>
44*1708Sstevel #include <dirent.h>
45*1708Sstevel #include <fcntl.h>
46*1708Sstevel #include <sys/param.h>
47*1708Sstevel #include <sys/stat.h>
48*1708Sstevel #include <sys/types.h>
49*1708Sstevel #include <sys/utsname.h>
50*1708Sstevel #include <sys/openpromio.h>
51*1708Sstevel #include <kstat.h>
52*1708Sstevel #include <libintl.h>
53*1708Sstevel #include <syslog.h>
54*1708Sstevel #include <sys/dkio.h>
55*1708Sstevel #include "pdevinfo.h"
56*1708Sstevel #include "display.h"
57*1708Sstevel #include "pdevinfo_sun4u.h"
58*1708Sstevel #include "display_sun4u.h"
59*1708Sstevel #include "libprtdiag.h"
60*1708Sstevel 
61*1708Sstevel #if !defined(TEXT_DOMAIN)
62*1708Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
63*1708Sstevel #endif
64*1708Sstevel 
65*1708Sstevel extern	int	print_flag;
66*1708Sstevel 
67*1708Sstevel /*
68*1708Sstevel  * these functions will overlay the symbol table of libprtdiag
69*1708Sstevel  * at runtime (workgroup server systems only)
70*1708Sstevel  */
71*1708Sstevel int	error_check(Sys_tree *tree, struct system_kstat_data *kstats);
72*1708Sstevel void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
73*1708Sstevel int	disp_fail_parts(Sys_tree *tree);
74*1708Sstevel void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
75*1708Sstevel void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
76*1708Sstevel 				struct system_kstat_data *kstats);
77*1708Sstevel void	display_boardnum(int num);
78*1708Sstevel void 	display_pci(Board_node *);
79*1708Sstevel void	display_io_cards(struct io_card *list);
80*1708Sstevel void 	display_ffb(Board_node *, int);
81*1708Sstevel void	read_platform_kstats(Sys_tree *tree,
82*1708Sstevel 		struct system_kstat_data *sys_kstat,
83*1708Sstevel 		struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep);
84*1708Sstevel 
85*1708Sstevel /* local functions */
86*1708Sstevel static	int disp_envctrl_status(Sys_tree *, struct system_kstat_data *);
87*1708Sstevel static	void check_disk_presence(Sys_tree *, int *, int *, int *);
88*1708Sstevel static	void modify_device_path(char *, char *);
89*1708Sstevel static	int disk_present(char *);
90*1708Sstevel static	void tazjav_disp_asic_revs(Sys_tree *);
91*1708Sstevel static 	int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
92*1708Sstevel static	Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
93*1708Sstevel 
94*1708Sstevel 
95*1708Sstevel int
error_check(Sys_tree * tree,struct system_kstat_data * kstats)96*1708Sstevel error_check(Sys_tree *tree, struct system_kstat_data *kstats)
97*1708Sstevel {
98*1708Sstevel 	int exit_code = 0;	/* init to all OK */
99*1708Sstevel 
100*1708Sstevel #ifdef	lint
101*1708Sstevel 	kstats = kstats;
102*1708Sstevel #endif
103*1708Sstevel 	/*
104*1708Sstevel 	 * silently check for any types of machine errors
105*1708Sstevel 	 */
106*1708Sstevel 	print_flag = 0;
107*1708Sstevel 	if (disp_fail_parts(tree) || disp_envctrl_status(tree, kstats)) {
108*1708Sstevel 		/* set exit_code to show failures */
109*1708Sstevel 		exit_code = 1;
110*1708Sstevel 	}
111*1708Sstevel 	print_flag = 1;
112*1708Sstevel 
113*1708Sstevel 	return (exit_code);
114*1708Sstevel }
115*1708Sstevel 
116*1708Sstevel /* Search for and return the node's sibling */
117*1708Sstevel static Prom_node *
dev_next_node_sibling(Prom_node * root,char * name)118*1708Sstevel dev_next_node_sibling(Prom_node *root, char *name)
119*1708Sstevel {
120*1708Sstevel 	if (root == NULL)
121*1708Sstevel 		return (NULL);
122*1708Sstevel 
123*1708Sstevel 	/* look at your siblings */
124*1708Sstevel 	if (dev_find_node(root->sibling, name) != NULL)
125*1708Sstevel 		return (root->sibling);
126*1708Sstevel 
127*1708Sstevel 	return (NULL);  /* not found */
128*1708Sstevel }
129*1708Sstevel 
130*1708Sstevel /*
131*1708Sstevel  * This function displays memory configurations specific to Tazmo/Javelin.
132*1708Sstevel  * The PROM device tree is read to obtain this information.
133*1708Sstevel  * Some of the information obtained is memory interleave factor,
134*1708Sstevel  * DIMM sizes, DIMM socket names.
135*1708Sstevel  */
136*1708Sstevel void
display_memoryconf(Sys_tree * tree,struct grp_info * grps)137*1708Sstevel display_memoryconf(Sys_tree *tree, struct grp_info *grps)
138*1708Sstevel {
139*1708Sstevel 	Board_node *bnode;
140*1708Sstevel 	Prom_node *memory;
141*1708Sstevel 	Prom_node *bank;
142*1708Sstevel 	Prom_node *dimm;
143*1708Sstevel 	uint_t *preg;
144*1708Sstevel 	uint_t interlv;
145*1708Sstevel 	unsigned long size = 0;
146*1708Sstevel 	int bank_count = 0;
147*1708Sstevel 	char *sock_name;
148*1708Sstevel 	char *status;
149*1708Sstevel 	Prop *status_prop;
150*1708Sstevel 	char interleave[8];
151*1708Sstevel 	int total_size = 0;
152*1708Sstevel #ifdef lint
153*1708Sstevel 	grps = grps;
154*1708Sstevel #endif
155*1708Sstevel 
156*1708Sstevel 	log_printf("\n", 0);
157*1708Sstevel 	log_printf("=========================", 0);
158*1708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
159*1708Sstevel 	log_printf("=========================", 0);
160*1708Sstevel 	log_printf("\n", 0);
161*1708Sstevel 	log_printf("\n", 0);
162*1708Sstevel 	bnode = tree->bd_list;
163*1708Sstevel 	memory = dev_find_node(bnode->nodes, "memory");
164*1708Sstevel 	preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave")));
165*1708Sstevel 	if (preg) {
166*1708Sstevel 		interlv = preg[4];
167*1708Sstevel 		log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0);
168*1708Sstevel 	}
169*1708Sstevel 	log_printf("       Interlv.  Socket   Size\n", 0);
170*1708Sstevel 	log_printf("Bank    Group     Name    (MB)  Status\n", 0);
171*1708Sstevel 	log_printf("----    -----    ------   ----  ------\n", 0);
172*1708Sstevel 
173*1708Sstevel 	dimm = bnode->nodes;
174*1708Sstevel 	for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL;
175*1708Sstevel 		bank = dev_next_node(bank, "bank")) {
176*1708Sstevel 		int bank_size = 0;
177*1708Sstevel 		uint_t *reg_prop;
178*1708Sstevel 
179*1708Sstevel 		preg = (uint_t *)(get_prop_val(
180*1708Sstevel 				find_prop(bank, "bank-interleave")));
181*1708Sstevel 
182*1708Sstevel 		reg_prop = (uint_t *)(get_prop_val(
183*1708Sstevel 				find_prop(bank, "reg")));
184*1708Sstevel 
185*1708Sstevel 		/*
186*1708Sstevel 		 * Skip empty banks
187*1708Sstevel 		 */
188*1708Sstevel 		if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) {
189*1708Sstevel 			bank_count++;
190*1708Sstevel 			continue;
191*1708Sstevel 		}
192*1708Sstevel 
193*1708Sstevel 		if (preg) {
194*1708Sstevel 			interlv = preg[2];
195*1708Sstevel 			(void) sprintf(interleave, " %d ", interlv);
196*1708Sstevel 			bank_size = (preg[0]<<12) + (preg[1]>>20);
197*1708Sstevel 		} else {
198*1708Sstevel 			(void) sprintf(interleave, "%s", "none");
199*1708Sstevel 			preg = (uint_t *)(get_prop_val(find_prop(bank, "reg")));
200*1708Sstevel 			if (preg) {
201*1708Sstevel 				bank_size = (preg[2]<<12) + (preg[3]>>20);
202*1708Sstevel 			}
203*1708Sstevel 		}
204*1708Sstevel 		for (dimm = dev_find_node(bank, "dimm"); dimm != NULL;
205*1708Sstevel 			dimm = dev_next_node_sibling(dimm, "dimm")) {
206*1708Sstevel 			char dimm_status[16];
207*1708Sstevel 
208*1708Sstevel 			sock_name = (char *)(get_prop_val(
209*1708Sstevel 				find_prop(dimm, "socket-name")));
210*1708Sstevel 			preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg")));
211*1708Sstevel 			size = (preg[2]<<12) + (preg[3]>>20);
212*1708Sstevel 			if ((status_prop = find_prop(dimm, "status")) == NULL) {
213*1708Sstevel 				(void) sprintf(dimm_status, "%s", "OK");
214*1708Sstevel 			} else {
215*1708Sstevel 				status = (char *)(get_prop_val(status_prop));
216*1708Sstevel 				(void) sprintf(dimm_status, "%s", status);
217*1708Sstevel 			}
218*1708Sstevel 			log_printf("%3d     %5s    %6s  %4d  %6s\n",
219*1708Sstevel 				bank_count, interleave, sock_name,
220*1708Sstevel 				size, dimm_status, 0);
221*1708Sstevel 		}
222*1708Sstevel 		total_size += bank_size;
223*1708Sstevel 		bank_count++;
224*1708Sstevel 	}
225*1708Sstevel 	log_printf("\n", 0);
226*1708Sstevel }
227*1708Sstevel 
228*1708Sstevel /*
229*1708Sstevel  * disp_fail_parts
230*1708Sstevel  *
231*1708Sstevel  * Display the failed parts in the system. This function looks for
232*1708Sstevel  * the status property in all PROM nodes. On systems where
233*1708Sstevel  * the PROM does not supports passing diagnostic information
234*1708Sstevel  * thruogh the device tree, this routine will be silent.
235*1708Sstevel  */
236*1708Sstevel int
disp_fail_parts(Sys_tree * tree)237*1708Sstevel disp_fail_parts(Sys_tree *tree)
238*1708Sstevel {
239*1708Sstevel 	int exit_code;
240*1708Sstevel 	int system_failed = 0;
241*1708Sstevel 	Board_node *bnode = tree->bd_list;
242*1708Sstevel 	Prom_node *pnode;
243*1708Sstevel 	char *fru;
244*1708Sstevel 	char *sock_name;
245*1708Sstevel 	char slot_str[MAXSTRLEN];
246*1708Sstevel 
247*1708Sstevel 	exit_code = 0;
248*1708Sstevel 
249*1708Sstevel 	/* go through all of the boards looking for failed units. */
250*1708Sstevel 	while (bnode != NULL) {
251*1708Sstevel 		/* find failed chips */
252*1708Sstevel 		pnode = find_failed_node(bnode->nodes);
253*1708Sstevel 		if ((pnode != NULL) && !system_failed) {
254*1708Sstevel 			system_failed = 1;
255*1708Sstevel 			exit_code = 1;
256*1708Sstevel 			if (print_flag == 0) {
257*1708Sstevel 				return (exit_code);
258*1708Sstevel 			}
259*1708Sstevel 			log_printf("\n", 0);
260*1708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
261*1708Sstevel 				"Replaceable Units (FRU) in System:\n"), 0);
262*1708Sstevel 			log_printf("=========================="
263*1708Sstevel 				"====================\n", 0);
264*1708Sstevel 		}
265*1708Sstevel 
266*1708Sstevel 		while (pnode != NULL) {
267*1708Sstevel 			void *value;
268*1708Sstevel 			char *name;		/* node name string */
269*1708Sstevel 			char *type;		/* node type string */
270*1708Sstevel 
271*1708Sstevel 			value = get_prop_val(find_prop(pnode, "status"));
272*1708Sstevel 			name = get_node_name(pnode);
273*1708Sstevel 
274*1708Sstevel 			/* sanity check of data retreived from PROM */
275*1708Sstevel 			if ((value == NULL) || (name == NULL)) {
276*1708Sstevel 				pnode = next_failed_node(pnode);
277*1708Sstevel 				continue;
278*1708Sstevel 			}
279*1708Sstevel 
280*1708Sstevel 
281*1708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"),
282*1708Sstevel 				name, 0);
283*1708Sstevel 
284*1708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
285*1708Sstevel 				"\tPROM fault string: %s\n"),
286*1708Sstevel 				value, 0);
287*1708Sstevel 
288*1708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
289*1708Sstevel 				"\tFailed Field Replaceable Unit is "), 0);
290*1708Sstevel 
291*1708Sstevel 			/*
292*1708Sstevel 			 * Determine whether FRU is CPU module, system
293*1708Sstevel 			 * board, or SBus card.
294*1708Sstevel 			 */
295*1708Sstevel 			if ((name != NULL) && (strstr(name, "sbus"))) {
296*1708Sstevel 
297*1708Sstevel 				log_printf(dgettext(TEXT_DOMAIN, "SBus "
298*1708Sstevel 					"Card %d\n"), get_sbus_slot(pnode), 0);
299*1708Sstevel 
300*1708Sstevel 			} else if (((name = get_node_name(pnode)) !=
301*1708Sstevel 			    NULL) && (strstr(name, "pci"))) {
302*1708Sstevel 
303*1708Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
304*1708Sstevel 					"system board\n"), 0);
305*1708Sstevel 
306*1708Sstevel 			} else if (((name = get_node_name(pnode)) !=
307*1708Sstevel 			    NULL) && (strstr(name, "ffb"))) {
308*1708Sstevel 
309*1708Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
310*1708Sstevel 					"FFB Card %d\n"),
311*1708Sstevel 					tazmo_physical_slot(
312*1708Sstevel 					dev_find_node(bnode->nodes, "slot2dev"),
313*1708Sstevel 					    pnode, -1, slot_str), 0);
314*1708Sstevel 
315*1708Sstevel 			} else if (((name = get_node_name(pnode->parent)) !=
316*1708Sstevel 			    NULL) && (strstr(name, "pci"))) {
317*1708Sstevel 
318*1708Sstevel 				(void) tazmo_physical_slot(
319*1708Sstevel 					NULL,
320*1708Sstevel 					    pnode->parent,
321*1708Sstevel 					    get_pci_device(pnode),
322*1708Sstevel 					    slot_str);
323*1708Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
324*1708Sstevel 					"PCI Card in %s\n"), slot_str, 0);
325*1708Sstevel 
326*1708Sstevel 			} else if (((type = get_node_type(pnode)) != NULL) &&
327*1708Sstevel 			    (strstr(type, "cpu"))) {
328*1708Sstevel 
329*1708Sstevel 				log_printf(
330*1708Sstevel 					dgettext(TEXT_DOMAIN,
331*1708Sstevel 					"UltraSPARC module Module %d\n"),
332*1708Sstevel 						get_id(pnode));
333*1708Sstevel 
334*1708Sstevel 			} else if (((type = get_node_type(pnode)) != NULL) &&
335*1708Sstevel 			    (strstr(type, "memory-module"))) {
336*1708Sstevel 
337*1708Sstevel 				fru = (char *)(get_prop_val(
338*1708Sstevel 					find_prop(pnode, "fru")));
339*1708Sstevel 				sock_name = (char *)(get_prop_val(
340*1708Sstevel 					find_prop(pnode, "socket-name")));
341*1708Sstevel 				log_printf(
342*1708Sstevel 					dgettext(TEXT_DOMAIN,
343*1708Sstevel 						"%s in socket %s\n"),
344*1708Sstevel 						fru, sock_name, 0);
345*1708Sstevel 			}
346*1708Sstevel 			pnode = next_failed_node(pnode);
347*1708Sstevel 		}
348*1708Sstevel 		bnode = bnode->next;
349*1708Sstevel 	}
350*1708Sstevel 
351*1708Sstevel 	if (!system_failed) {
352*1708Sstevel 		log_printf("\n", 0);
353*1708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
354*1708Sstevel 			"No failures found in System\n"), 0);
355*1708Sstevel 		log_printf("===========================\n", 0);
356*1708Sstevel 	}
357*1708Sstevel 
358*1708Sstevel 	if (system_failed)
359*1708Sstevel 		return (1);
360*1708Sstevel 	else
361*1708Sstevel 		return (0);
362*1708Sstevel }
363*1708Sstevel 
364*1708Sstevel void
display_hp_fail_fault(Sys_tree * tree,struct system_kstat_data * kstats)365*1708Sstevel display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
366*1708Sstevel {
367*1708Sstevel #ifdef lint
368*1708Sstevel 	kstats = kstats;
369*1708Sstevel #endif
370*1708Sstevel 	/* Display failed units */
371*1708Sstevel 	(void) disp_fail_parts(tree);
372*1708Sstevel }
373*1708Sstevel 
374*1708Sstevel 
375*1708Sstevel void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)376*1708Sstevel display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
377*1708Sstevel 	struct system_kstat_data *kstats)
378*1708Sstevel {
379*1708Sstevel 	/*
380*1708Sstevel 	 * Now display the last powerfail time and the fatal hardware
381*1708Sstevel 	 * reset information. We do this under a couple of conditions.
382*1708Sstevel 	 * First if the user asks for it. The second is iof the user
383*1708Sstevel 	 * told us to do logging, and we found a system failure.
384*1708Sstevel 	 */
385*1708Sstevel 	if (flag) {
386*1708Sstevel 		/*
387*1708Sstevel 		 * display time of latest powerfail. Not all systems
388*1708Sstevel 		 * have this capability. For those that do not, this
389*1708Sstevel 		 * is just a no-op.
390*1708Sstevel 		 */
391*1708Sstevel 		disp_powerfail(root);
392*1708Sstevel 
393*1708Sstevel 		(void) disp_envctrl_status(tree, kstats);
394*1708Sstevel 
395*1708Sstevel 		tazjav_disp_asic_revs(tree);
396*1708Sstevel 
397*1708Sstevel 		platform_disp_prom_version(tree);
398*1708Sstevel 	}
399*1708Sstevel 	return;
400*1708Sstevel 
401*1708Sstevel }
402*1708Sstevel 
403*1708Sstevel /* ARGSUSED */
404*1708Sstevel void
display_boardnum(int num)405*1708Sstevel display_boardnum(int num)
406*1708Sstevel {
407*1708Sstevel 	log_printf("SYS   ", 0);
408*1708Sstevel }
409*1708Sstevel 
410*1708Sstevel 
411*1708Sstevel 
412*1708Sstevel /*
413*1708Sstevel  * display_pci
414*1708Sstevel  * Display all the PCI IO cards on this board.
415*1708Sstevel  */
416*1708Sstevel 
417*1708Sstevel /* ARGSUSED */
418*1708Sstevel void
display_pci(Board_node * board)419*1708Sstevel display_pci(Board_node *board)
420*1708Sstevel {
421*1708Sstevel 	struct io_card *card_list = NULL;
422*1708Sstevel 	struct io_card card;
423*1708Sstevel 	void *value;
424*1708Sstevel 	Prom_node *pci;
425*1708Sstevel 	Prom_node *card_node;
426*1708Sstevel 
427*1708Sstevel 	if (board == NULL)
428*1708Sstevel 		return;
429*1708Sstevel 
430*1708Sstevel 	/* Initialize all the common information */
431*1708Sstevel 	card.display = 1;
432*1708Sstevel 	card.board = board->board_num;
433*1708Sstevel 	(void) sprintf(card.bus_type, "PCI");
434*1708Sstevel 
435*1708Sstevel 	for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL;
436*1708Sstevel 	    pci = dev_next_node(pci, PCI_NAME)) {
437*1708Sstevel 		char *name;
438*1708Sstevel 		Prom_node *prev_parent = NULL;
439*1708Sstevel 		int prev_device = -1;
440*1708Sstevel 		int pci_pci_bridge = 0;
441*1708Sstevel 
442*1708Sstevel 		/*
443*1708Sstevel 		 * If we have reached a pci-to-pci bridge node,
444*1708Sstevel 		 * we are one level below the 'pci' nodes level
445*1708Sstevel 		 * in the device tree. To get back to that level,
446*1708Sstevel 		 * the search should continue with the sibling of
447*1708Sstevel 		 * the parent or else the remaining 'pci' cards
448*1708Sstevel 		 * will not show up in the output.
449*1708Sstevel 		 */
450*1708Sstevel 		if (find_prop(pci, "upa-portid") == NULL) {
451*1708Sstevel 			if ((pci->parent->sibling != NULL) &&
452*1708Sstevel 				(strcmp(get_prop_val(
453*1708Sstevel 				find_prop(pci->parent->sibling,
454*1708Sstevel 				"name")), PCI_NAME) == 0))
455*1708Sstevel 				pci = pci->parent->sibling;
456*1708Sstevel 			else {
457*1708Sstevel 				pci = pci->parent->sibling;
458*1708Sstevel 				continue;
459*1708Sstevel 			}
460*1708Sstevel 		}
461*1708Sstevel 
462*1708Sstevel 		/* Skip all failed nodes for now */
463*1708Sstevel 		if (node_failed(pci))
464*1708Sstevel 			continue;
465*1708Sstevel 
466*1708Sstevel 		/* Fill in frequency */
467*1708Sstevel 		value = get_prop_val(find_prop(pci, "clock-frequency"));
468*1708Sstevel 		if (value == NULL)
469*1708Sstevel 			card.freq = -1;
470*1708Sstevel 		else
471*1708Sstevel 			card.freq = ((*(int *)value) + 500000) / 1000000;
472*1708Sstevel 
473*1708Sstevel 		/* Walk through the PSYCHO children */
474*1708Sstevel 		card_node = pci->child;
475*1708Sstevel 		while (card_node != NULL) {
476*1708Sstevel 			Prop *compat = NULL;
477*1708Sstevel 
478*1708Sstevel 			/* If it doesn't have a name, skip it */
479*1708Sstevel 			name = (char *)get_prop_val(
480*1708Sstevel 				find_prop(card_node, "name"));
481*1708Sstevel 			if (name == NULL) {
482*1708Sstevel 				card_node = card_node->sibling;
483*1708Sstevel 				continue;
484*1708Sstevel 			}
485*1708Sstevel 
486*1708Sstevel 			/*
487*1708Sstevel 			 * If this is a PCI bridge, then display its
488*1708Sstevel 			 * children.
489*1708Sstevel 			 */
490*1708Sstevel 			if (strcmp(name, "pci") == 0) {
491*1708Sstevel 				card_node = card_node->child;
492*1708Sstevel 				pci_pci_bridge = 1;
493*1708Sstevel 				continue;
494*1708Sstevel 			}
495*1708Sstevel 
496*1708Sstevel 			/* Get the slot number for this card */
497*1708Sstevel 			if (pci_pci_bridge) {
498*1708Sstevel 				card.slot = tazmo_physical_slot(
499*1708Sstevel 					dev_find_node(board->nodes, "slot2dev"),
500*1708Sstevel 					    pci,
501*1708Sstevel 					    get_pci_to_pci_device(
502*1708Sstevel 						card_node->parent),
503*1708Sstevel 						    card.slot_str);
504*1708Sstevel 			} else
505*1708Sstevel 				card.slot = tazmo_physical_slot(
506*1708Sstevel 					dev_find_node(board->nodes,
507*1708Sstevel 					"slot2dev"),
508*1708Sstevel 					    pci,
509*1708Sstevel 					    get_pci_device(card_node),
510*1708Sstevel 					    card.slot_str);
511*1708Sstevel 
512*1708Sstevel 			/*
513*1708Sstevel 			 * Check that duplicate devices are not reported
514*1708Sstevel 			 * on Tazmo.
515*1708Sstevel 			 */
516*1708Sstevel 			if ((card_node->parent == prev_parent) &&
517*1708Sstevel 				(get_pci_device(card_node) == prev_device) &&
518*1708Sstevel 				(pci_pci_bridge == 0))
519*1708Sstevel 					card.slot = -1;
520*1708Sstevel 			prev_parent = card_node->parent;
521*1708Sstevel 			prev_device = get_pci_device(card_node);
522*1708Sstevel 
523*1708Sstevel 
524*1708Sstevel 			if (card.slot == -1 || strstr(name, "ebus")) {
525*1708Sstevel 				card_node = card_node->sibling;
526*1708Sstevel 				continue;
527*1708Sstevel 			}
528*1708Sstevel 
529*1708Sstevel 			/* XXX - Don't know how to get status for PCI cards */
530*1708Sstevel 			card.status[0] = '\0';
531*1708Sstevel 
532*1708Sstevel 			/* Get the model of this card */
533*1708Sstevel 			value = get_prop_val(find_prop(card_node, "model"));
534*1708Sstevel 			if (value == NULL)
535*1708Sstevel 				card.model[0] = '\0';
536*1708Sstevel 			else
537*1708Sstevel 				(void) sprintf(card.model, "%s",
538*1708Sstevel 					(char *)value);
539*1708Sstevel 
540*1708Sstevel 			/*
541*1708Sstevel 			 * Check if further processing is necessary to display
542*1708Sstevel 			 * this card uniquely.
543*1708Sstevel 			 */
544*1708Sstevel 			distinguish_identical_io_cards(name, card_node, &card);
545*1708Sstevel 
546*1708Sstevel 			/*
547*1708Sstevel 			 * If we haven't figured out the frequency yet,
548*1708Sstevel 			 * try and get it from the card.
549*1708Sstevel 			 */
550*1708Sstevel 			value = get_prop_val(find_prop(pci, "clock-frequency"));
551*1708Sstevel 			if (value != NULL && card.freq == -1)
552*1708Sstevel 				card.freq = ((*(int *)value) + 500000)
553*1708Sstevel 					/ 1000000;
554*1708Sstevel 
555*1708Sstevel 
556*1708Sstevel 			value = get_prop_val(find_prop(card_node,
557*1708Sstevel 				"compatible"));
558*1708Sstevel 
559*1708Sstevel 			/*
560*1708Sstevel 			 * On Tazmo, we would like to print out the last
561*1708Sstevel 			 * string of the "compatible" property if it exists.
562*1708Sstevel 			 * The IEEE 1275 spec. states that this last string
563*1708Sstevel 			 * will be the classcode name.
564*1708Sstevel 			 */
565*1708Sstevel 			if (value != NULL) {
566*1708Sstevel 				char *tval;
567*1708Sstevel 				int index;
568*1708Sstevel 				const int always = 1;
569*1708Sstevel 
570*1708Sstevel 				tval = (char *)value;
571*1708Sstevel 				index = 0;
572*1708Sstevel 				compat = find_prop(card_node, "compatible");
573*1708Sstevel 				while (always) {
574*1708Sstevel 					if ((strlen(tval) + 1) ==
575*1708Sstevel 						(compat->size - index))
576*1708Sstevel 						break;
577*1708Sstevel 					index += strlen(tval) + 1;
578*1708Sstevel 					tval += strlen(tval) + 1;
579*1708Sstevel 				}
580*1708Sstevel 				value = (void *)tval;
581*1708Sstevel 			}
582*1708Sstevel 
583*1708Sstevel 			if (value != NULL)
584*1708Sstevel 				(void) sprintf(card.name, "%s-%s",
585*1708Sstevel 					(char *)name, (char *)value);
586*1708Sstevel 			else
587*1708Sstevel 				(void) sprintf(card.name, "%s",
588*1708Sstevel 					(char *)name);
589*1708Sstevel 
590*1708Sstevel 			if (card.freq != -1)
591*1708Sstevel 				card_list = insert_io_card(card_list, &card);
592*1708Sstevel 
593*1708Sstevel 			/*
594*1708Sstevel 			 * If we are done with the children of the pci bridge,
595*1708Sstevel 			 * we must continue with the remaining siblings of
596*1708Sstevel 			 * the pci-to-pci bridge.
597*1708Sstevel 			 */
598*1708Sstevel 			if ((card_node->sibling == NULL) && pci_pci_bridge) {
599*1708Sstevel 				card_node = card_node->parent->sibling;
600*1708Sstevel 				pci_pci_bridge = 0;
601*1708Sstevel 			} else
602*1708Sstevel 				card_node = card_node->sibling;
603*1708Sstevel 		}
604*1708Sstevel 	}
605*1708Sstevel 
606*1708Sstevel 	display_io_cards(card_list);
607*1708Sstevel 	free_io_cards(card_list);
608*1708Sstevel }
609*1708Sstevel 
610*1708Sstevel 
611*1708Sstevel /*
612*1708Sstevel  * Print out all the io cards in the list.  Also print the column
613*1708Sstevel  * headers if told to do so.
614*1708Sstevel  */
615*1708Sstevel void
display_io_cards(struct io_card * list)616*1708Sstevel display_io_cards(struct io_card *list)
617*1708Sstevel {
618*1708Sstevel 	static int banner = 0; /* Have we printed the column headings? */
619*1708Sstevel 	struct io_card *p;
620*1708Sstevel 
621*1708Sstevel 	if (list == NULL)
622*1708Sstevel 		return;
623*1708Sstevel 
624*1708Sstevel 	if (banner == 0) {
625*1708Sstevel 		log_printf("     Bus   Freq\n", 0);
626*1708Sstevel 		log_printf("Brd  Type  MHz   Slot  "
627*1708Sstevel 			"Name                              Model", 0);
628*1708Sstevel 		log_printf("\n", 0);
629*1708Sstevel 		log_printf("---  ----  ----  ----  "
630*1708Sstevel 			"--------------------------------  "
631*1708Sstevel 			"----------------------", 0);
632*1708Sstevel 		log_printf("\n", 0);
633*1708Sstevel 		banner = 1;
634*1708Sstevel 	}
635*1708Sstevel 
636*1708Sstevel 	for (p = list; p != NULL; p = p -> next) {
637*1708Sstevel 		log_printf("SYS   ", p->board, 0);
638*1708Sstevel 		log_printf("%-4s  ", p->bus_type, 0);
639*1708Sstevel 		log_printf("%3d   ", p->freq, 0);
640*1708Sstevel 		log_printf("%3d   ", p->slot, 0);
641*1708Sstevel 		log_printf("%-32.32s", p->name, 0);
642*1708Sstevel 		if (strlen(p->name) > 32)
643*1708Sstevel 			log_printf("+ ", 0);
644*1708Sstevel 		else
645*1708Sstevel 			log_printf("  ", 0);
646*1708Sstevel 		log_printf("%-22.22s", p->model, 0);
647*1708Sstevel 		if (strlen(p->model) > 22)
648*1708Sstevel 			log_printf("+", 0);
649*1708Sstevel 		log_printf("\n", 0);
650*1708Sstevel 	}
651*1708Sstevel }
652*1708Sstevel 
653*1708Sstevel /*
654*1708Sstevel  * display_ffb
655*1708Sstevel  * Display all FFBs on this board.  It can either be in tabular format,
656*1708Sstevel  * or a more verbose format.
657*1708Sstevel  */
658*1708Sstevel void
display_ffb(Board_node * board,int table)659*1708Sstevel display_ffb(Board_node *board, int table)
660*1708Sstevel {
661*1708Sstevel 	Prom_node *ffb;
662*1708Sstevel 	void *value;
663*1708Sstevel 	struct io_card *card_list = NULL;
664*1708Sstevel 	struct io_card card;
665*1708Sstevel 
666*1708Sstevel 	if (board == NULL)
667*1708Sstevel 		return;
668*1708Sstevel 
669*1708Sstevel 	/* Fill in common information */
670*1708Sstevel 	card.display = 1;
671*1708Sstevel 	card.board = board->board_num;
672*1708Sstevel 	(void) sprintf(card.bus_type, "UPA");
673*1708Sstevel 	card.freq = sys_clk;
674*1708Sstevel 
675*1708Sstevel 	for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
676*1708Sstevel 	    ffb = dev_next_node(ffb, FFB_NAME)) {
677*1708Sstevel 		if (table == 1) {
678*1708Sstevel 			/* Print out in table format */
679*1708Sstevel 
680*1708Sstevel 			/* XXX - Get the slot number (hack) */
681*1708Sstevel 			card.slot = tazmo_physical_slot(
682*1708Sstevel 				dev_find_node(board->nodes, "slot2dev"),
683*1708Sstevel 				    ffb,
684*1708Sstevel 				    -1,
685*1708Sstevel 				    card.slot_str);
686*1708Sstevel 
687*1708Sstevel 			/* Find out if it's single or double buffered */
688*1708Sstevel 			(void) sprintf(card.name, "FFB");
689*1708Sstevel 			value = get_prop_val(find_prop(ffb, "board_type"));
690*1708Sstevel 			if (value != NULL)
691*1708Sstevel 				if ((*(int *)value) & FFB_B_BUFF)
692*1708Sstevel 					(void) sprintf(card.name,
693*1708Sstevel 						"FFB, Double Buffered");
694*1708Sstevel 				else
695*1708Sstevel 					(void) sprintf(card.name,
696*1708Sstevel 						"FFB, Single Buffered");
697*1708Sstevel 
698*1708Sstevel 			/* Print model number */
699*1708Sstevel 			card.model[0] = '\0';
700*1708Sstevel 			value = get_prop_val(find_prop(ffb, "model"));
701*1708Sstevel 			if (value != NULL)
702*1708Sstevel 				(void) sprintf(card.model, "%s",
703*1708Sstevel 					(char *)value);
704*1708Sstevel 
705*1708Sstevel 			card_list = insert_io_card(card_list, &card);
706*1708Sstevel 		} else {
707*1708Sstevel 			/* print in long format */
708*1708Sstevel 			char device[MAXSTRLEN];
709*1708Sstevel 			int fd = -1;
710*1708Sstevel 			struct dirent *direntp;
711*1708Sstevel 			DIR *dirp;
712*1708Sstevel 			union strap_un strap;
713*1708Sstevel 			struct ffb_sys_info fsi;
714*1708Sstevel 
715*1708Sstevel 			/* Find the device node using upa address */
716*1708Sstevel 			value = get_prop_val(find_prop(ffb, "upa-portid"));
717*1708Sstevel 			if (value == NULL)
718*1708Sstevel 			    continue;
719*1708Sstevel 
720*1708Sstevel 			(void) sprintf(device, "%s@%x", FFB_NAME,
721*1708Sstevel 				*(int *)value);
722*1708Sstevel 			if ((dirp = opendir("/devices")) == NULL)
723*1708Sstevel 				continue;
724*1708Sstevel 
725*1708Sstevel 			while ((direntp = readdir(dirp)) != NULL) {
726*1708Sstevel 				if (strstr(direntp->d_name, device) != NULL) {
727*1708Sstevel 					(void) sprintf(device, "/devices/%s",
728*1708Sstevel 						direntp->d_name);
729*1708Sstevel 					fd = open(device, O_RDWR, 0666);
730*1708Sstevel 					break;
731*1708Sstevel 				}
732*1708Sstevel 			}
733*1708Sstevel 			(void) closedir(dirp);
734*1708Sstevel 
735*1708Sstevel 			if (fd == -1)
736*1708Sstevel 				continue;
737*1708Sstevel 
738*1708Sstevel 			if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
739*1708Sstevel 				continue;
740*1708Sstevel 
741*1708Sstevel 			log_printf("FFB Hardware Configuration:\n", 0);
742*1708Sstevel 			log_printf("-----------------------------------\n", 0);
743*1708Sstevel 
744*1708Sstevel 			strap.ffb_strap_bits = fsi.ffb_strap_bits;
745*1708Sstevel 			log_printf("\tBoard rev: %d\n",
746*1708Sstevel 				(int)strap.fld.board_rev, 0);
747*1708Sstevel 			log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
748*1708Sstevel 			log_printf("\tDAC: %s\n",
749*1708Sstevel 				fmt_manf_id(fsi.dac_version, device), 0);
750*1708Sstevel 			log_printf("\t3DRAM: %s\n",
751*1708Sstevel 				fmt_manf_id(fsi.fbram_version, device), 0);
752*1708Sstevel 			log_printf("\n", 0);
753*1708Sstevel 		}
754*1708Sstevel 	}
755*1708Sstevel 
756*1708Sstevel 	display_io_cards(card_list);
757*1708Sstevel 	free_io_cards(card_list);
758*1708Sstevel }
759*1708Sstevel 
760*1708Sstevel /*
761*1708Sstevel  * This module does the reading and interpreting of tazmo system
762*1708Sstevel  * kstats. These kstats are created by the environ driver:
763*1708Sstevel  */
764*1708Sstevel void
read_platform_kstats(Sys_tree * tree,struct system_kstat_data * sys_kstat,struct bd_kstat_data * bdp,struct envctrl_kstat_data * ep)765*1708Sstevel read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
766*1708Sstevel 	struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep)
767*1708Sstevel {
768*1708Sstevel 	kstat_ctl_t		*kc;
769*1708Sstevel 	kstat_t			*ksp;
770*1708Sstevel 
771*1708Sstevel 	if ((kc = kstat_open()) == NULL) {
772*1708Sstevel 		return;
773*1708Sstevel 	}
774*1708Sstevel #ifdef lint
775*1708Sstevel 	tree = tree;
776*1708Sstevel 	bdp = bdp;
777*1708Sstevel #endif
778*1708Sstevel 
779*1708Sstevel 	ep = &sys_kstat->env_data;
780*1708Sstevel 
781*1708Sstevel 	/* Read the power supply kstats */
782*1708Sstevel 	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
783*1708Sstevel 		ENVCTRL_KSTAT_PSNAME);
784*1708Sstevel 
785*1708Sstevel 	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
786*1708Sstevel 		(void) memcpy(ep->ps_kstats, ksp->ks_data,
787*1708Sstevel 			MAX_DEVS * sizeof (envctrl_ps_t));
788*1708Sstevel 	} else {
789*1708Sstevel 		sys_kstat->envctrl_kstat_ok = B_FALSE;
790*1708Sstevel 		return;
791*1708Sstevel 	}
792*1708Sstevel 
793*1708Sstevel 	/* Read the fan status kstats */
794*1708Sstevel 	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
795*1708Sstevel 		ENVCTRL_KSTAT_FANSTAT);
796*1708Sstevel 
797*1708Sstevel 	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
798*1708Sstevel 		(void) memcpy(ep->fan_kstats, ksp->ks_data,
799*1708Sstevel 			ksp->ks_ndata * sizeof (envctrl_fan_t));
800*1708Sstevel 	} else {
801*1708Sstevel 		sys_kstat->envctrl_kstat_ok = B_FALSE;
802*1708Sstevel 		return;
803*1708Sstevel 	}
804*1708Sstevel 
805*1708Sstevel 	/* Read the enclosure kstats */
806*1708Sstevel 	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
807*1708Sstevel 		ENVCTRL_KSTAT_ENCL);
808*1708Sstevel 
809*1708Sstevel 	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
810*1708Sstevel 		(void) memcpy(ep->encl_kstats, ksp->ks_data,
811*1708Sstevel 			ksp->ks_ndata * sizeof (envctrl_encl_t));
812*1708Sstevel 	} else {
813*1708Sstevel 		sys_kstat->envctrl_kstat_ok = B_FALSE;
814*1708Sstevel 		return;
815*1708Sstevel 	}
816*1708Sstevel 
817*1708Sstevel 	sys_kstat->envctrl_kstat_ok = B_TRUE;
818*1708Sstevel }
819*1708Sstevel 
820*1708Sstevel /*
821*1708Sstevel  * Walk the PROM device tree and build the system tree and root tree.
822*1708Sstevel  * Nodes that have a board number property are placed in the board
823*1708Sstevel  * structures for easier processing later. Child nodes are placed
824*1708Sstevel  * under their parents. ffb (Fusion Frame Buffer) nodes are handled
825*1708Sstevel  * specially, because they do not contain board number properties.
826*1708Sstevel  * This was requested from OBP, but was not granted. So this code
827*1708Sstevel  * must parse the MID of the FFB to find the board#.
828*1708Sstevel  */
829*1708Sstevel Prom_node *
walk(Sys_tree * tree,Prom_node * root,int id)830*1708Sstevel walk(Sys_tree *tree, Prom_node *root, int id)
831*1708Sstevel {
832*1708Sstevel 	register int curnode;
833*1708Sstevel 	Prom_node *pnode;
834*1708Sstevel 	char *name;
835*1708Sstevel 	char *type;
836*1708Sstevel 	char *model;
837*1708Sstevel 	int board_node = 0;
838*1708Sstevel 
839*1708Sstevel 	/* allocate a node for this level */
840*1708Sstevel 	if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
841*1708Sstevel 	    NULL) {
842*1708Sstevel 		perror("malloc");
843*1708Sstevel 		exit(2);	/* program errors cause exit 2 */
844*1708Sstevel 	}
845*1708Sstevel 
846*1708Sstevel 	/* assign parent Prom_node */
847*1708Sstevel 	pnode->parent = root;
848*1708Sstevel 	pnode->sibling = NULL;
849*1708Sstevel 	pnode->child = NULL;
850*1708Sstevel 
851*1708Sstevel 	/* read properties for this node */
852*1708Sstevel 	dump_node(pnode);
853*1708Sstevel 
854*1708Sstevel 	/*
855*1708Sstevel 	 * Place a node in a 'board' if it has 'board'-ness. The definition
856*1708Sstevel 	 * is that all nodes that are children of root should have a
857*1708Sstevel 	 * board# property. But the PROM tree does not exactly follow
858*1708Sstevel 	 * this. This is where we start hacking. The name 'ffb' can
859*1708Sstevel 	 * change, so watch out for this.
860*1708Sstevel 	 *
861*1708Sstevel 	 * The UltraSPARC, sbus, pci and ffb nodes will exit in
862*1708Sstevel 	 * the desktops and will not have board# properties. These
863*1708Sstevel 	 * cases must be handled here.
864*1708Sstevel 	 *
865*1708Sstevel 	 * PCI to PCI bridges also have the name "pci", but with different
866*1708Sstevel 	 * model property values.  They should not be put under 'board'.
867*1708Sstevel 	 */
868*1708Sstevel 	name = get_node_name(pnode);
869*1708Sstevel 	type = get_node_type(pnode);
870*1708Sstevel 	model = (char *)get_prop_val(find_prop(pnode, "model"));
871*1708Sstevel #ifdef DEBUG
872*1708Sstevel 	if (name != NULL)
873*1708Sstevel 		printf("name=%s ", name);
874*1708Sstevel 	if (type != NULL)
875*1708Sstevel 		printf("type=%s ", type);
876*1708Sstevel 	if (model != NULL)
877*1708Sstevel 		printf("model=%s", model);
878*1708Sstevel 	printf("\n");
879*1708Sstevel 
880*1708Sstevel 	if (model == NULL)
881*1708Sstevel 		model = "";
882*1708Sstevel #endif
883*1708Sstevel 	if (type == NULL)
884*1708Sstevel 		type = "";
885*1708Sstevel 	if (name != NULL) {
886*1708Sstevel 		if (has_board_num(pnode)) {
887*1708Sstevel 			add_node(tree, pnode);
888*1708Sstevel 			board_node = 1;
889*1708Sstevel #ifdef DEBUG
890*1708Sstevel 			printf("ADDED BOARD name=%s type=%s model=%s\n",
891*1708Sstevel 				name, type, model);
892*1708Sstevel #endif
893*1708Sstevel 		} else if ((strcmp(name, FFB_NAME)  == 0)		||
894*1708Sstevel 		    (strcmp(type, "cpu") == 0)				||
895*1708Sstevel 
896*1708Sstevel 		    ((strcmp(name, "pci") == 0) && (model != NULL) &&
897*1708Sstevel 			(strcmp(model, "SUNW,psycho") == 0))		||
898*1708Sstevel 
899*1708Sstevel 		    ((strcmp(name, "pci") == 0) && (model != NULL) &&
900*1708Sstevel 			(strcmp(model, "SUNW,sabre") == 0))		||
901*1708Sstevel 
902*1708Sstevel 		    (strcmp(name, "counter-timer") == 0)		||
903*1708Sstevel 		    (strcmp(name, "sbus") == 0)				||
904*1708Sstevel 		    (strcmp(name, "memory") == 0)			||
905*1708Sstevel 		    (strcmp(name, "mc") == 0)				||
906*1708Sstevel 		    (strcmp(name, "associations") == 0)) {
907*1708Sstevel 			add_node(tree, pnode);
908*1708Sstevel 			board_node = 1;
909*1708Sstevel #ifdef DEBUG
910*1708Sstevel 			printf("ADDED BOARD name=%s type=%s model=%s\n",
911*1708Sstevel 				name, type, model);
912*1708Sstevel #endif
913*1708Sstevel 		}
914*1708Sstevel #ifdef DEBUG
915*1708Sstevel 		else
916*1708Sstevel 			printf("node not added: name=%s type=%s\n", name, type);
917*1708Sstevel #endif
918*1708Sstevel 	}
919*1708Sstevel 
920*1708Sstevel 	if (curnode = child(id)) {
921*1708Sstevel 		pnode->child = walk(tree, pnode, curnode);
922*1708Sstevel 	}
923*1708Sstevel 
924*1708Sstevel 	if (curnode = next(id)) {
925*1708Sstevel 		if (board_node) {
926*1708Sstevel 			return (walk(tree, root, curnode));
927*1708Sstevel 		} else {
928*1708Sstevel 			pnode->sibling = walk(tree, root, curnode);
929*1708Sstevel 		}
930*1708Sstevel 	}
931*1708Sstevel 
932*1708Sstevel 	if (board_node) {
933*1708Sstevel 		return (NULL);
934*1708Sstevel 	} else {
935*1708Sstevel 		return (pnode);
936*1708Sstevel 	}
937*1708Sstevel }
938*1708Sstevel 
939*1708Sstevel /*
940*1708Sstevel  * local functions
941*1708Sstevel  */
942*1708Sstevel 
943*1708Sstevel /*
944*1708Sstevel  * disp_envctrl_status
945*1708Sstevel  *
946*1708Sstevel  * This routine displays the environmental status passed up from
947*1708Sstevel  * device drivers via kstats. The kstat names are defined in
948*1708Sstevel  * kernel header files included by this module.
949*1708Sstevel  */
950*1708Sstevel static int
disp_envctrl_status(Sys_tree * tree,struct system_kstat_data * sys_kstats)951*1708Sstevel disp_envctrl_status(Sys_tree *tree, struct system_kstat_data *sys_kstats)
952*1708Sstevel {
953*1708Sstevel 	int exit_code = 0;
954*1708Sstevel 	int possible_failure;
955*1708Sstevel 	int i;
956*1708Sstevel 	uchar_t val;
957*1708Sstevel 	char fan_type[16];
958*1708Sstevel 	char state[48];
959*1708Sstevel 	char name[16];
960*1708Sstevel 	envctrl_ps_t ps;
961*1708Sstevel 	envctrl_fan_t fan;
962*1708Sstevel 	envctrl_encl_t encl;
963*1708Sstevel 	struct envctrl_kstat_data *ep;
964*1708Sstevel 	uchar_t fsp_value;
965*1708Sstevel 	int i4slot_backplane_value = -1;
966*1708Sstevel 	int i8slot_backplane_value = -1;
967*1708Sstevel 	int j8slot_backplane_value = -1;
968*1708Sstevel 	static int first_8disk_bp = 0;
969*1708Sstevel 	static int second_8disk_bp = 0;
970*1708Sstevel 	static int first_4disk_bp = 0;
971*1708Sstevel 
972*1708Sstevel 	if (sys_kstats->envctrl_kstat_ok == 0) {
973*1708Sstevel 		log_printf("\n", 0);
974*1708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "Environmental information "
975*1708Sstevel 			"is not available\n"), 0);
976*1708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may "
977*1708Sstevel 			"not be installed\n"), 0);
978*1708Sstevel 		log_printf("\n", 0);
979*1708Sstevel 		return (1);
980*1708Sstevel 	}
981*1708Sstevel 
982*1708Sstevel 	ep = &sys_kstats->env_data;
983*1708Sstevel 
984*1708Sstevel 	check_disk_presence(tree, &first_4disk_bp, &first_8disk_bp,
985*1708Sstevel 		&second_8disk_bp);
986*1708Sstevel 
987*1708Sstevel 	log_printf("\n", 0);
988*1708Sstevel 	log_printf("=========================", 0);
989*1708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
990*1708Sstevel 	log_printf("=========================", 0);
991*1708Sstevel 	log_printf("\n", 0);
992*1708Sstevel 	log_printf("\n", 0);
993*1708Sstevel 
994*1708Sstevel 	log_printf("System Temperatures (Celsius):\n", 0);
995*1708Sstevel 	log_printf("------------------------------\n", 0);
996*1708Sstevel 	for (i = 0; i < MAX_DEVS; i++) {
997*1708Sstevel 		encl = ep->encl_kstats[i];
998*1708Sstevel 		switch (encl.type) {
999*1708Sstevel 		case ENVCTRL_ENCL_AMBTEMPR:
1000*1708Sstevel 			if (encl.instance == I2C_NODEV)
1001*1708Sstevel 			    continue;
1002*1708Sstevel 			(void) sprintf(name, "%s", "AMBIENT");
1003*1708Sstevel 			log_printf("%s    %d", name, encl.value);
1004*1708Sstevel 			if (encl.value > MAX_AMB_TEMP) {
1005*1708Sstevel 				log_printf("    WARNING\n", 0);
1006*1708Sstevel 				exit_code = 1;
1007*1708Sstevel 			} else
1008*1708Sstevel 				log_printf("\n", 0);
1009*1708Sstevel 			break;
1010*1708Sstevel 		case ENVCTRL_ENCL_CPUTEMPR:
1011*1708Sstevel 			if (encl.instance == I2C_NODEV)
1012*1708Sstevel 			    continue;
1013*1708Sstevel 			(void) sprintf(name, "%s %d", "CPU", encl.instance);
1014*1708Sstevel 			log_printf("%s      %d", name, encl.value);
1015*1708Sstevel 			if (encl.value > MAX_CPU_TEMP) {
1016*1708Sstevel 				log_printf("    WARNING\n", 0);
1017*1708Sstevel 				exit_code = 1;
1018*1708Sstevel 			} else
1019*1708Sstevel 				log_printf("\n", 0);
1020*1708Sstevel 			break;
1021*1708Sstevel 		case ENVCTRL_ENCL_FSP:
1022*1708Sstevel 			if (encl.instance == I2C_NODEV)
1023*1708Sstevel 			    continue;
1024*1708Sstevel 			val = encl.value & ENVCTRL_FSP_KEYMASK;
1025*1708Sstevel 			fsp_value = encl.value;
1026*1708Sstevel 			switch (val) {
1027*1708Sstevel 			case ENVCTRL_FSP_KEYOFF:
1028*1708Sstevel 				(void) sprintf(state, "%s", "Off");
1029*1708Sstevel 				break;
1030*1708Sstevel 			case ENVCTRL_FSP_KEYON:
1031*1708Sstevel 				(void) sprintf(state, "%s", "On");
1032*1708Sstevel 				break;
1033*1708Sstevel 			case ENVCTRL_FSP_KEYDIAG:
1034*1708Sstevel 				(void) sprintf(state, "%s", "Diagnostic");
1035*1708Sstevel 				break;
1036*1708Sstevel 			case ENVCTRL_FSP_KEYLOCKED:
1037*1708Sstevel 				(void) sprintf(state, "%s", "Secure");
1038*1708Sstevel 				break;
1039*1708Sstevel 			default:
1040*1708Sstevel 				(void) sprintf(state, "%s", "Broken!");
1041*1708Sstevel 				exit_code = 1;
1042*1708Sstevel 				break;
1043*1708Sstevel 			}
1044*1708Sstevel 			break;
1045*1708Sstevel 		case ENVCTRL_ENCL_BACKPLANE4:
1046*1708Sstevel 		case ENVCTRL_ENCL_BACKPLANE8:
1047*1708Sstevel 			if (encl.instance == I2C_NODEV)
1048*1708Sstevel 				continue;
1049*1708Sstevel 			switch (encl.instance) {
1050*1708Sstevel 			case 0:
1051*1708Sstevel 				i4slot_backplane_value =
1052*1708Sstevel 				    encl.value & ENVCTRL_4SLOT_BACKPLANE;
1053*1708Sstevel 				break;
1054*1708Sstevel 			case 1:
1055*1708Sstevel 				i8slot_backplane_value =
1056*1708Sstevel 				    encl.value & ENVCTRL_8SLOT_BACKPLANE;
1057*1708Sstevel 				break;
1058*1708Sstevel 			case 2:
1059*1708Sstevel 				j8slot_backplane_value =
1060*1708Sstevel 				    encl.value & ENVCTRL_8SLOT_BACKPLANE;
1061*1708Sstevel 				break;
1062*1708Sstevel 			}
1063*1708Sstevel 		default:
1064*1708Sstevel 			break;
1065*1708Sstevel 		}
1066*1708Sstevel 	}
1067*1708Sstevel 
1068*1708Sstevel 	log_printf("=================================\n\n", 0);
1069*1708Sstevel 	log_printf("Front Status Panel:\n", 0);
1070*1708Sstevel 	log_printf("-------------------\n", 0);
1071*1708Sstevel 	log_printf("Keyswitch position is in %s mode.\n", state);
1072*1708Sstevel 	log_printf("\n", 0);
1073*1708Sstevel 	val = fsp_value & (ENVCTRL_FSP_DISK_ERR | ENVCTRL_FSP_PS_ERR |
1074*1708Sstevel 		ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_GEN_ERR |
1075*1708Sstevel 		ENVCTRL_FSP_ACTIVE);
1076*1708Sstevel 	log_printf("System LED Status:    POWER     GENERAL ERROR  "
1077*1708Sstevel 		"    ACTIVITY\n", 0);
1078*1708Sstevel 	log_printf("                      [ ON]         [%3s]      "
1079*1708Sstevel 		"     [%3s]\n", val & ENVCTRL_FSP_GEN_ERR ? "ON" : "OFF",
1080*1708Sstevel 		    val & ENVCTRL_FSP_ACTIVE ? "ON" : "OFF");
1081*1708Sstevel 	log_printf("                    DISK ERROR  "
1082*1708Sstevel 			"THERMAL ERROR  POWER SUPPLY ERROR\n", 0);
1083*1708Sstevel 	log_printf("                      [%3s]         [%3s]      "
1084*1708Sstevel 		"     [%3s]\n", val & ENVCTRL_FSP_DISK_ERR ? "ON" : "OFF",
1085*1708Sstevel 		    val & ENVCTRL_FSP_TEMP_ERR ? "ON" : "OFF",
1086*1708Sstevel 		    val & ENVCTRL_FSP_PS_ERR ? "ON" : "OFF");
1087*1708Sstevel 	log_printf("\n", 0);
1088*1708Sstevel 	/* record error conditions */
1089*1708Sstevel 	if (val & (ENVCTRL_FSP_GEN_ERR | ENVCTRL_FSP_DISK_ERR |
1090*1708Sstevel 		ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_PS_ERR)) {
1091*1708Sstevel 		exit_code = 1;
1092*1708Sstevel 	}
1093*1708Sstevel 
1094*1708Sstevel 
1095*1708Sstevel 	log_printf("Disk LED Status:	OK = GREEN	ERROR = YELLOW\n", 0);
1096*1708Sstevel 
1097*1708Sstevel 	if (j8slot_backplane_value != -1) {
1098*1708Sstevel 		log_printf("		DISK 18: %7s	DISK 19: %7s\n",
1099*1708Sstevel 		    second_8disk_bp & ENVCTRL_DISK_6 ?
1100*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]"
1101*1708Sstevel 		: "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_7 ?
1102*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]"
1103*1708Sstevel 		: "[EMPTY]");
1104*1708Sstevel 		log_printf("		DISK 16: %7s	DISK 17: %7s\n",
1105*1708Sstevel 		    second_8disk_bp & ENVCTRL_DISK_4 ?
1106*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]"
1107*1708Sstevel 		: "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_5 ?
1108*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]"
1109*1708Sstevel 		: "[EMPTY]");
1110*1708Sstevel 		log_printf("		DISK 14: %7s	DISK 15: %7s\n",
1111*1708Sstevel 		    second_8disk_bp & ENVCTRL_DISK_2 ?
1112*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
1113*1708Sstevel 		: "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_3 ?
1114*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
1115*1708Sstevel 		: "[EMPTY]");
1116*1708Sstevel 		log_printf("		DISK 12: %7s	DISK 13: %7s\n",
1117*1708Sstevel 		    second_8disk_bp & ENVCTRL_DISK_0 ?
1118*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
1119*1708Sstevel 		: "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_1 ?
1120*1708Sstevel 		    j8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
1121*1708Sstevel 		: "[EMPTY]");
1122*1708Sstevel 	}
1123*1708Sstevel 	if (i8slot_backplane_value != -1) {
1124*1708Sstevel 		log_printf("		DISK 10: %7s	DISK 11: %7s\n",
1125*1708Sstevel 		    first_8disk_bp & ENVCTRL_DISK_6 ?
1126*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]"
1127*1708Sstevel 		: "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_7 ?
1128*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]"
1129*1708Sstevel 		: "[EMPTY]");
1130*1708Sstevel 		log_printf("		DISK  8: %7s	DISK  9: %7s\n",
1131*1708Sstevel 		    first_8disk_bp & ENVCTRL_DISK_4 ?
1132*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]"
1133*1708Sstevel 		: "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_5 ?
1134*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]"
1135*1708Sstevel 		: "[EMPTY]");
1136*1708Sstevel 		log_printf("		DISK  6: %7s	DISK  7: %7s\n",
1137*1708Sstevel 		    first_8disk_bp & ENVCTRL_DISK_2 ?
1138*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
1139*1708Sstevel 		: "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_3 ?
1140*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
1141*1708Sstevel 		: "[EMPTY]");
1142*1708Sstevel 		log_printf("		DISK  4: %7s	DISK  5: %7s\n",
1143*1708Sstevel 		    first_8disk_bp & ENVCTRL_DISK_0 ?
1144*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
1145*1708Sstevel 		: "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_1 ?
1146*1708Sstevel 		    i8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
1147*1708Sstevel 		: "[EMPTY]");
1148*1708Sstevel 	}
1149*1708Sstevel 	if (i4slot_backplane_value != -1) {
1150*1708Sstevel 		log_printf("		DISK  2: %7s	DISK  3: %7s\n",
1151*1708Sstevel 		    first_4disk_bp & ENVCTRL_DISK_2 ?
1152*1708Sstevel 		    i4slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
1153*1708Sstevel 		: "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_3 ?
1154*1708Sstevel 		    i4slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
1155*1708Sstevel 		: "[EMPTY]");
1156*1708Sstevel 		log_printf("		DISK  0: %7s	DISK  1: %7s\n",
1157*1708Sstevel 		    first_4disk_bp & ENVCTRL_DISK_0 ?
1158*1708Sstevel 		    i4slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
1159*1708Sstevel 		: "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_1 ?
1160*1708Sstevel 		    i4slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
1161*1708Sstevel 		: "[EMPTY]");
1162*1708Sstevel 	}
1163*1708Sstevel 
1164*1708Sstevel 	log_printf("=================================\n", 0);
1165*1708Sstevel 	log_printf("\n", 0);
1166*1708Sstevel 
1167*1708Sstevel 	log_printf("Fans:\n", 0);
1168*1708Sstevel 	log_printf("-----\n", 0);
1169*1708Sstevel 
1170*1708Sstevel 	log_printf("Fan Bank   Speed    Status\n", 0);
1171*1708Sstevel 	log_printf("--------   -----    ------\n", 0);
1172*1708Sstevel 
1173*1708Sstevel 	for (i = 0; i < MAX_DEVS; i++) {
1174*1708Sstevel 		fan = ep->fan_kstats[i];
1175*1708Sstevel 
1176*1708Sstevel 		if (fan.instance == I2C_NODEV)
1177*1708Sstevel 			continue;
1178*1708Sstevel 
1179*1708Sstevel 		switch (fan.type) {
1180*1708Sstevel 		case ENVCTRL_FAN_TYPE_CPU:
1181*1708Sstevel 			(void) sprintf(fan_type, "%s", "CPU");
1182*1708Sstevel 			break;
1183*1708Sstevel 		case ENVCTRL_FAN_TYPE_PS:
1184*1708Sstevel 			(void) sprintf(fan_type, "%s", "PWR");
1185*1708Sstevel 			break;
1186*1708Sstevel 		case ENVCTRL_FAN_TYPE_AFB:
1187*1708Sstevel 			(void) sprintf(fan_type, "%s", "AFB");
1188*1708Sstevel 			break;
1189*1708Sstevel 		}
1190*1708Sstevel 		if (fan.fans_ok == B_TRUE) {
1191*1708Sstevel 			(void) sprintf(state, "%s", "  OK  ");
1192*1708Sstevel 		} else {
1193*1708Sstevel 			(void) sprintf(state, "FAILED (FAN# %d)",
1194*1708Sstevel 				fan.fanflt_num);
1195*1708Sstevel 			/* we know fan.instance != I2C_NODEV */
1196*1708Sstevel 			exit_code = 1;
1197*1708Sstevel 		}
1198*1708Sstevel 		if (fan.instance != I2C_NODEV)
1199*1708Sstevel 			log_printf("%s          %d     %s\n", fan_type,
1200*1708Sstevel 				fan.fanspeed, state);
1201*1708Sstevel 	}
1202*1708Sstevel 
1203*1708Sstevel 
1204*1708Sstevel 	log_printf("\n", 0);
1205*1708Sstevel 
1206*1708Sstevel 	log_printf("\n", 0);
1207*1708Sstevel 	log_printf("Power Supplies:\n", 0);
1208*1708Sstevel 	log_printf("---------------\n", 0);
1209*1708Sstevel 	log_printf("Supply     Rating    Temp    Status\n", 0);
1210*1708Sstevel 	log_printf("------     ------    ----    ------\n", 0);
1211*1708Sstevel 	for (i = 0; i < MAX_DEVS; i++) {
1212*1708Sstevel 		ps = ep->ps_kstats[i];
1213*1708Sstevel 		if (ps.curr_share_ok == B_TRUE &&
1214*1708Sstevel 		    ps.limit_ok == B_TRUE && ps.ps_ok == B_TRUE) {
1215*1708Sstevel 			(void) sprintf(state, "%s", "  OK  ");
1216*1708Sstevel 			possible_failure = 0;
1217*1708Sstevel 		} else {
1218*1708Sstevel 			if (ps.ps_ok != B_TRUE) {
1219*1708Sstevel 				(void) sprintf(state, "%s",
1220*1708Sstevel 					"FAILED: DC Power Failure");
1221*1708Sstevel 				possible_failure = 1;
1222*1708Sstevel 			} else if (ps.curr_share_ok != B_TRUE) {
1223*1708Sstevel 				(void) sprintf(state, "%s",
1224*1708Sstevel 					"WARNING: Current Share Imbalance");
1225*1708Sstevel 				possible_failure = 1;
1226*1708Sstevel 			} else if (ps.limit_ok != B_TRUE) {
1227*1708Sstevel 				(void) sprintf(state, "%s",
1228*1708Sstevel 					"WARNING: Current Overload");
1229*1708Sstevel 				possible_failure = 1;
1230*1708Sstevel 			}
1231*1708Sstevel 		}
1232*1708Sstevel 
1233*1708Sstevel 		if (ps.instance != I2C_NODEV && ps.ps_rating != 0) {
1234*1708Sstevel 			log_printf(" %2d        %4d W     %2d     %s\n",
1235*1708Sstevel 			    ps.instance, ps.ps_rating, ps.ps_tempr, state);
1236*1708Sstevel 			if (possible_failure)
1237*1708Sstevel 				exit_code = 1;
1238*1708Sstevel 		}
1239*1708Sstevel 	}
1240*1708Sstevel 
1241*1708Sstevel 	return (exit_code);
1242*1708Sstevel }
1243*1708Sstevel 
1244*1708Sstevel /*
1245*1708Sstevel  * This function will return a bitmask for each of the 4 disk backplane
1246*1708Sstevel  * and the two 8 disk backplanes. It creates this mask by first obtaining
1247*1708Sstevel  * the PROM path of the controller for each slot using the "slot2dev"
1248*1708Sstevel  * node in the PROM tree. It then modifies the PROM path to obtain a
1249*1708Sstevel  * physical device path to the controller. The presence of the controller
1250*1708Sstevel  * is determined by trying to open the controller device and reading
1251*1708Sstevel  * some information from the device. Currently only supported on Tazmo.
1252*1708Sstevel  */
1253*1708Sstevel static void
check_disk_presence(Sys_tree * tree,int * i4disk,int * i8disk,int * j8disk)1254*1708Sstevel check_disk_presence(Sys_tree *tree, int *i4disk, int *i8disk, int *j8disk)
1255*1708Sstevel {
1256*1708Sstevel 	Board_node *bnode;
1257*1708Sstevel 	Prom_node *slot2disk = NULL;
1258*1708Sstevel 	Prop *slotprop;
1259*1708Sstevel 	char *devpath_p;
1260*1708Sstevel 	char devpath[MAXSTRLEN];
1261*1708Sstevel 	char slotx[16] = "";
1262*1708Sstevel 	int slot;
1263*1708Sstevel 	int slot_ptr = 0;
1264*1708Sstevel 
1265*1708Sstevel 	bnode = tree->bd_list;
1266*1708Sstevel 	*i4disk = *i8disk, *j8disk = 0;
1267*1708Sstevel 
1268*1708Sstevel 	slot2disk = dev_find_node(bnode->nodes, "slot2disk");
1269*1708Sstevel 
1270*1708Sstevel 	for (slot = 0; slot < 20; slot++) {
1271*1708Sstevel 		(void) sprintf(slotx, "slot#%d", slot);
1272*1708Sstevel 		if ((slotprop = find_prop(slot2disk, slotx)) != NULL)
1273*1708Sstevel 			if ((devpath_p = (char *)(get_prop_val(slotprop)))
1274*1708Sstevel 				!= NULL) {
1275*1708Sstevel 				modify_device_path(devpath_p, devpath);
1276*1708Sstevel 				if (disk_present(devpath)) {
1277*1708Sstevel 					if (slot < 4)
1278*1708Sstevel 						*i4disk |= 1 << slot_ptr;
1279*1708Sstevel 					else if (slot < 12)
1280*1708Sstevel 						*i8disk |= 1 << slot_ptr;
1281*1708Sstevel 					else if (slot < 20)
1282*1708Sstevel 						*j8disk |= 1 << slot_ptr;
1283*1708Sstevel 				}
1284*1708Sstevel 			}
1285*1708Sstevel 		if ((slot == 3) || (slot == 11))
1286*1708Sstevel 			slot_ptr = 0;
1287*1708Sstevel 		else
1288*1708Sstevel 			slot_ptr++;
1289*1708Sstevel 	}
1290*1708Sstevel }
1291*1708Sstevel 
1292*1708Sstevel 
1293*1708Sstevel 
1294*1708Sstevel /*
1295*1708Sstevel  * modify_device_path
1296*1708Sstevel  *
1297*1708Sstevel  * This function modifies a string from the slot2disk association
1298*1708Sstevel  * PROM node to a physical device path name. For example if the
1299*1708Sstevel  * slot2disk association value is  "/pci@1f,4000/scsi@3/disk@1",
1300*1708Sstevel  * the equivalent physical device path will be
1301*1708Sstevel  * "/devices/pci@1f,4000/scsi@3/sd@1,0:c,raw".
1302*1708Sstevel  * We use this path to attempt to probe the disk to check for its
1303*1708Sstevel  * presence in the enclosure. We access the 'c' partition
1304*1708Sstevel  * which represents the entire disk.
1305*1708Sstevel  */
1306*1708Sstevel static void
modify_device_path(char * oldpath,char * newpath)1307*1708Sstevel modify_device_path(char *oldpath, char *newpath)
1308*1708Sstevel {
1309*1708Sstevel 	char *changeptr;
1310*1708Sstevel 	long target;
1311*1708Sstevel 	char targetstr[16];
1312*1708Sstevel 
1313*1708Sstevel 	(void) strcpy(newpath, "/devices");
1314*1708Sstevel 	changeptr = strstr(oldpath, "disk@");
1315*1708Sstevel 	/*
1316*1708Sstevel 	 * The assumption here is that nothing but the
1317*1708Sstevel 	 * target id follows the disk@ substring.
1318*1708Sstevel 	 */
1319*1708Sstevel 	target = strtol(changeptr+5, NULL, 16);
1320*1708Sstevel 	(void) strncat(newpath, oldpath, changeptr - oldpath);
1321*1708Sstevel 	(void) sprintf(targetstr, "sd@%ld,0:c,raw", target);
1322*1708Sstevel 	(void) strcat(newpath, targetstr);
1323*1708Sstevel }
1324*1708Sstevel 
1325*1708Sstevel /*
1326*1708Sstevel  * Returns 0 if the device at devpath is not *physically* present.  If it is,
1327*1708Sstevel  * then info on that device is placed in the dkinfop buffer, and 1 is returned.
1328*1708Sstevel  * Keep in mind that ioctl(DKIOCINFO)'s CDROMs owned by vold fail, so only
1329*1708Sstevel  * the dki_ctype field is set in that case.
1330*1708Sstevel  */
1331*1708Sstevel static int
disk_present(char * devpath)1332*1708Sstevel disk_present(char *devpath)
1333*1708Sstevel {
1334*1708Sstevel 	int		search_file;
1335*1708Sstevel 	struct stat	stbuf;
1336*1708Sstevel 	struct dk_cinfo dkinfo;
1337*1708Sstevel 
1338*1708Sstevel 	/*
1339*1708Sstevel 	 * Attempt to open the disk.  If it fails, skip it.
1340*1708Sstevel 	 */
1341*1708Sstevel 	if ((search_file = open(devpath, O_RDONLY | O_NDELAY)) < 0)
1342*1708Sstevel 		return (0);
1343*1708Sstevel 
1344*1708Sstevel 	/*
1345*1708Sstevel 	 * Must be a character device
1346*1708Sstevel 	 */
1347*1708Sstevel 	if (fstat(search_file, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
1348*1708Sstevel 		(void) close(search_file);
1349*1708Sstevel 		return (0);
1350*1708Sstevel 	}
1351*1708Sstevel 
1352*1708Sstevel 	/*
1353*1708Sstevel 	 * Attempt to read the configuration info on the disk.
1354*1708Sstevel 	 * If it fails, we assume the disk's not there.
1355*1708Sstevel 	 * Note we must close the file for the disk before we
1356*1708Sstevel 	 * continue.
1357*1708Sstevel 	 */
1358*1708Sstevel 	if (ioctl(search_file, DKIOCINFO, &dkinfo) < 0) {
1359*1708Sstevel 		(void) close(search_file);
1360*1708Sstevel 		return (0);
1361*1708Sstevel 	}
1362*1708Sstevel 	(void) close(search_file);
1363*1708Sstevel 	return (1);
1364*1708Sstevel }
1365*1708Sstevel 
1366*1708Sstevel void
tazjav_disp_asic_revs(Sys_tree * tree)1367*1708Sstevel tazjav_disp_asic_revs(Sys_tree *tree)
1368*1708Sstevel {
1369*1708Sstevel 	Board_node *bnode;
1370*1708Sstevel 	Prom_node *pnode;
1371*1708Sstevel 	char *name;
1372*1708Sstevel 	int *version;
1373*1708Sstevel 	char *model;
1374*1708Sstevel 
1375*1708Sstevel 	/* Print the header */
1376*1708Sstevel 	log_printf("\n", 0);
1377*1708Sstevel 	log_printf("=========================", 0);
1378*1708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
1379*1708Sstevel 	log_printf("=========================", 0);
1380*1708Sstevel 	log_printf("\n", 0);
1381*1708Sstevel 	log_printf("\n", 0);
1382*1708Sstevel 
1383*1708Sstevel 	bnode = tree->bd_list;
1384*1708Sstevel 
1385*1708Sstevel 	log_printf("ASIC Revisions:\n", 0);
1386*1708Sstevel 	log_printf("---------------\n", 0);
1387*1708Sstevel 
1388*1708Sstevel 	/* Find sysio and print rev */
1389*1708Sstevel 	for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
1390*1708Sstevel 	    pnode = dev_next_node(pnode, "sbus")) {
1391*1708Sstevel 		version = (int *)get_prop_val(find_prop(pnode, "version#"));
1392*1708Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
1393*1708Sstevel 
1394*1708Sstevel 		if ((version != NULL) && (name != NULL)) {
1395*1708Sstevel 			log_printf("SBus: %s Rev %d\n",
1396*1708Sstevel 				name, *version, 0);
1397*1708Sstevel 		}
1398*1708Sstevel 	}
1399*1708Sstevel 
1400*1708Sstevel 	/* Find Psycho and print rev */
1401*1708Sstevel 	for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
1402*1708Sstevel 	    pnode = dev_next_node(pnode, "pci")) {
1403*1708Sstevel 		Prom_node *parsib = pnode->parent->sibling;
1404*1708Sstevel 
1405*1708Sstevel 		if (find_prop(pnode, "upa-portid") == NULL) {
1406*1708Sstevel 			if ((parsib != NULL) &&
1407*1708Sstevel 				(strcmp(get_prop_val(
1408*1708Sstevel 				find_prop(parsib, "name")),
1409*1708Sstevel 					PCI_NAME) == 0))
1410*1708Sstevel 				pnode = parsib;
1411*1708Sstevel 			else {
1412*1708Sstevel 				pnode = parsib;
1413*1708Sstevel 				continue;
1414*1708Sstevel 			}
1415*1708Sstevel 		}
1416*1708Sstevel 
1417*1708Sstevel 		version = (int *)get_prop_val(find_prop(pnode, "version#"));
1418*1708Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
1419*1708Sstevel 
1420*1708Sstevel 		if ((version != NULL) && (name != NULL))
1421*1708Sstevel 			if (get_pci_bus(pnode) == 0)
1422*1708Sstevel 				log_printf("STP2223BGA: Rev %d\n", *version, 0);
1423*1708Sstevel 	}
1424*1708Sstevel 
1425*1708Sstevel 	/* Find Cheerio and print rev */
1426*1708Sstevel 	for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
1427*1708Sstevel 	    pnode = dev_next_node(pnode, "ebus")) {
1428*1708Sstevel 		version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
1429*1708Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
1430*1708Sstevel 
1431*1708Sstevel 		if ((version != NULL) && (name != NULL))
1432*1708Sstevel 			log_printf("STP2003QFP: Rev %d\n", *version, 0);
1433*1708Sstevel 	}
1434*1708Sstevel 
1435*1708Sstevel 	/* Find System Controller and print rev */
1436*1708Sstevel 	for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL;
1437*1708Sstevel 	    pnode = dev_next_node(pnode, "sc")) {
1438*1708Sstevel 		version = (int *)get_prop_val(find_prop(pnode, "version#"));
1439*1708Sstevel 		model = (char *)get_prop_val(find_prop(pnode, "model"));
1440*1708Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
1441*1708Sstevel 
1442*1708Sstevel 		if ((version != NULL) && (name != NULL)) {
1443*1708Sstevel 			if ((strcmp(model, "SUNW,sc-marvin") == 0))
1444*1708Sstevel 				log_printf("STP2205BGA: Rev %d\n", *version, 0);
1445*1708Sstevel 		}
1446*1708Sstevel 	}
1447*1708Sstevel 
1448*1708Sstevel 	/* Find the FEPS and print rev */
1449*1708Sstevel 	for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
1450*1708Sstevel 	    pnode = dev_next_node(pnode, "SUNW,hme")) {
1451*1708Sstevel 		version = (int *)get_prop_val(find_prop(pnode,	"hm-rev"));
1452*1708Sstevel 		name = get_prop_val(find_prop(pnode, "name"));
1453*1708Sstevel 
1454*1708Sstevel 		if ((version != NULL) && (name != NULL)) {
1455*1708Sstevel 			log_printf("FEPS: %s Rev ", name);
1456*1708Sstevel 			if (*version == 0xa0) {
1457*1708Sstevel 				log_printf("2.0\n", 0);
1458*1708Sstevel 			} else if (*version == 0x20) {
1459*1708Sstevel 				log_printf("2.1\n", 0);
1460*1708Sstevel 			} else {
1461*1708Sstevel 				log_printf("%x\n", *version, 0);
1462*1708Sstevel 			}
1463*1708Sstevel 		}
1464*1708Sstevel 	}
1465*1708Sstevel 	log_printf("\n", 0);
1466*1708Sstevel 
1467*1708Sstevel 	if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) {
1468*1708Sstevel 		display_ffb(bnode, 0);
1469*1708Sstevel 	}
1470*1708Sstevel }
1471*1708Sstevel 
1472*1708Sstevel 
1473*1708Sstevel /*
1474*1708Sstevel  * Determine the physical PCI slot based on which Psycho is the parent
1475*1708Sstevel  * of the PCI card.
1476*1708Sstevel  */
1477*1708Sstevel static int
tazmo_physical_slot(Prom_node * slotd,Prom_node * parent,int device,char * str)1478*1708Sstevel tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str)
1479*1708Sstevel {
1480*1708Sstevel 	int *upa_id = NULL;
1481*1708Sstevel 	int *reg = NULL;
1482*1708Sstevel 	int offset;
1483*1708Sstevel 	char controller[MAXSTRLEN];
1484*1708Sstevel 	char *name;
1485*1708Sstevel 	Prop *prop;
1486*1708Sstevel 	char *devpath_p;
1487*1708Sstevel 	char slotx[16] = "";
1488*1708Sstevel 	int *slot_names_mask;
1489*1708Sstevel 	char *slot_names;
1490*1708Sstevel 	int shift = 0;
1491*1708Sstevel 	int slot;
1492*1708Sstevel 	int slots, start_slot;
1493*1708Sstevel 
1494*1708Sstevel 	/*
1495*1708Sstevel 	 * If slotd != NULL, then we must return the physical PCI slot
1496*1708Sstevel 	 * number based on the information in the slot2dev associations
1497*1708Sstevel 	 * node. This routine is called from display_pci() with slotd
1498*1708Sstevel 	 * != NULL. If so, we return without obtaining the slot name.
1499*1708Sstevel 	 * If slotd == NULL, we look for the slot name through the
1500*1708Sstevel 	 * slot-names property in the bus node.
1501*1708Sstevel 	 */
1502*1708Sstevel 
1503*1708Sstevel 	if (slotd != NULL) {
1504*1708Sstevel 		(void) strcpy(str, "");
1505*1708Sstevel 		if ((prop = find_prop(parent, "upa-portid")) != NULL)
1506*1708Sstevel 			upa_id = (int *)(get_prop_val(prop));
1507*1708Sstevel 		if ((prop = find_prop(parent, "reg")) != NULL)
1508*1708Sstevel 			reg = (int *)(get_prop_val(prop));
1509*1708Sstevel 		if ((prop = find_prop(parent, "name")) != NULL)
1510*1708Sstevel 			name = (char *)(get_prop_val(prop));
1511*1708Sstevel 		if ((upa_id == NULL) || (reg == NULL)) {
1512*1708Sstevel 			return (-1);
1513*1708Sstevel 		}
1514*1708Sstevel 		offset = reg[1];
1515*1708Sstevel 		if (strcmp(name, "pci") == 0) {
1516*1708Sstevel 			(void) sprintf(controller, "/pci@%x,%x/*@%x,*",
1517*1708Sstevel 				*upa_id, offset, device);
1518*1708Sstevel 			slots = 20;
1519*1708Sstevel 		} else if (strcmp(name, "SUNW,ffb") == 0) {
1520*1708Sstevel 			(void) sprintf(controller, "/*@%x,0", *upa_id);
1521*1708Sstevel 			slots = 2;
1522*1708Sstevel 		}
1523*1708Sstevel 
1524*1708Sstevel 		start_slot = 1;
1525*1708Sstevel 		for (slot = start_slot; slot <= slots; slot++) {
1526*1708Sstevel 			if (strcmp(name, "pci") == 0)
1527*1708Sstevel 				(void) sprintf(slotx, "pci-slot#%d", slot);
1528*1708Sstevel 			else if (strcmp(name, "SUNW,ffb") == 0)
1529*1708Sstevel 				(void) sprintf(slotx, "graphics#%d", slot);
1530*1708Sstevel 			if ((prop = find_prop(slotd, slotx)) != NULL)
1531*1708Sstevel 				if ((devpath_p = (char *)(get_prop_val
1532*1708Sstevel 					(prop))) != NULL)
1533*1708Sstevel 					if (strcmp(devpath_p, controller) ==
1534*1708Sstevel 						NULL)
1535*1708Sstevel 						return (slot);
1536*1708Sstevel 		}
1537*1708Sstevel 		return (-1);
1538*1708Sstevel 	}
1539*1708Sstevel 
1540*1708Sstevel 	/*
1541*1708Sstevel 	 * Get slot-names property from parent node.
1542*1708Sstevel 	 * This property consists of a 32 bit mask indicating which
1543*1708Sstevel 	 * devices are relevant to this bus node. Following are a
1544*1708Sstevel 	 * number of strings depending on how many bits are set in the
1545*1708Sstevel 	 * bit mask; the first string gives the label that is printed
1546*1708Sstevel 	 * on the chassis for the smallest device number, and so on.
1547*1708Sstevel 	 */
1548*1708Sstevel 
1549*1708Sstevel 	prop = find_prop(parent, "slot-names");
1550*1708Sstevel 	if (prop == NULL) {
1551*1708Sstevel 		(void) strcpy(str, "");
1552*1708Sstevel 		return (-1);
1553*1708Sstevel 	}
1554*1708Sstevel 	slot_names_mask = (int *)(get_prop_val(prop));
1555*1708Sstevel 	slot_names = (char *)slot_names_mask;
1556*1708Sstevel 
1557*1708Sstevel 	slot = 1;
1558*1708Sstevel 	slot_names += 4;	/* Skip the 4 byte bitmask */
1559*1708Sstevel 
1560*1708Sstevel 	while (shift < 32) {
1561*1708Sstevel 		/*
1562*1708Sstevel 		 * Shift through the bitmask looking to see if the
1563*1708Sstevel 		 * bit corresponding to "device" is set. If so, copy
1564*1708Sstevel 		 * the correcsponding string to the provided pointer.
1565*1708Sstevel 		 */
1566*1708Sstevel 		if (*slot_names_mask & slot) {
1567*1708Sstevel 			if (shift == device) {
1568*1708Sstevel 				(void) strcpy(str, slot_names);
1569*1708Sstevel 				return (0);
1570*1708Sstevel 			}
1571*1708Sstevel 			slot_names += strlen(slot_names)+1;
1572*1708Sstevel 		}
1573*1708Sstevel 		shift++;
1574*1708Sstevel 		slot = slot << 1;
1575*1708Sstevel 	}
1576*1708Sstevel 	return (-1);
1577*1708Sstevel }
1578