xref: /titanic_52/usr/src/lib/libprtdiag/common/pdevinfo_funcs.c (revision 03831d35f7499c87d51205817c93e9a8d42c4bae)
1*03831d35Sstevel /*
2*03831d35Sstevel  * CDDL HEADER START
3*03831d35Sstevel  *
4*03831d35Sstevel  * The contents of this file are subject to the terms of the
5*03831d35Sstevel  * Common Development and Distribution License, Version 1.0 only
6*03831d35Sstevel  * (the "License").  You may not use this file except in compliance
7*03831d35Sstevel  * with the License.
8*03831d35Sstevel  *
9*03831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*03831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
11*03831d35Sstevel  * See the License for the specific language governing permissions
12*03831d35Sstevel  * and limitations under the License.
13*03831d35Sstevel  *
14*03831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
15*03831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*03831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
17*03831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
18*03831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
19*03831d35Sstevel  *
20*03831d35Sstevel  * CDDL HEADER END
21*03831d35Sstevel  */
22*03831d35Sstevel /*
23*03831d35Sstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*03831d35Sstevel  * Use is subject to license terms.
25*03831d35Sstevel  */
26*03831d35Sstevel 
27*03831d35Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*03831d35Sstevel 
29*03831d35Sstevel #include <stdio.h>
30*03831d35Sstevel #include <stdlib.h>
31*03831d35Sstevel #include <string.h>
32*03831d35Sstevel #include <fcntl.h>
33*03831d35Sstevel #include <stdarg.h>
34*03831d35Sstevel #include <errno.h>
35*03831d35Sstevel #include <unistd.h>
36*03831d35Sstevel #include <sys/utsname.h>
37*03831d35Sstevel #include <sys/openpromio.h>
38*03831d35Sstevel #include <libintl.h>
39*03831d35Sstevel #include "pdevinfo.h"
40*03831d35Sstevel #include "display.h"
41*03831d35Sstevel #include "pdevinfo_sun4u.h"
42*03831d35Sstevel 
43*03831d35Sstevel /*
44*03831d35Sstevel  * For machines that support the openprom, fetch and print the list
45*03831d35Sstevel  * of devices that the kernel has fetched from the prom or conjured up.
46*03831d35Sstevel  *
47*03831d35Sstevel  */
48*03831d35Sstevel 
49*03831d35Sstevel 
50*03831d35Sstevel static int prom_fd;
51*03831d35Sstevel extern char *progname;
52*03831d35Sstevel extern char *promdev;
53*03831d35Sstevel extern void getppdata();
54*03831d35Sstevel extern void printppdata();
55*03831d35Sstevel 
56*03831d35Sstevel /*
57*03831d35Sstevel  * Define DPRINT for run-time debugging printf's...
58*03831d35Sstevel  * #define DPRINT	1
59*03831d35Sstevel  */
60*03831d35Sstevel 
61*03831d35Sstevel #ifdef	DPRINT
62*03831d35Sstevel static	char    vdebug_flag = 1;
63*03831d35Sstevel #define	dprintf	if (vdebug_flag) printf
64*03831d35Sstevel static void dprint_dev_info(caddr_t, dev_info_t *);
65*03831d35Sstevel #endif	/* DPRINT */
66*03831d35Sstevel 
67*03831d35Sstevel #if !defined(TEXT_DOMAIN)
68*03831d35Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
69*03831d35Sstevel #endif
70*03831d35Sstevel 
71*03831d35Sstevel /*VARARGS1*/
72*03831d35Sstevel int
73*03831d35Sstevel _error(char *fmt, ...)
74*03831d35Sstevel {
75*03831d35Sstevel 	int saved_errno;
76*03831d35Sstevel 	va_list ap;
77*03831d35Sstevel 	extern int errno;
78*03831d35Sstevel 	saved_errno = errno;
79*03831d35Sstevel 
80*03831d35Sstevel 	if (progname)
81*03831d35Sstevel 		(void) fprintf(stderr, "%s: ", progname);
82*03831d35Sstevel 
83*03831d35Sstevel 	va_start(ap, fmt);
84*03831d35Sstevel 
85*03831d35Sstevel 	(void) vfprintf(stderr, fmt, ap);
86*03831d35Sstevel 
87*03831d35Sstevel 	va_end(ap);
88*03831d35Sstevel 
89*03831d35Sstevel 	(void) fprintf(stderr, ": ");
90*03831d35Sstevel 	errno = saved_errno;
91*03831d35Sstevel 	perror("");
92*03831d35Sstevel 
93*03831d35Sstevel 	return (2);
94*03831d35Sstevel }
95*03831d35Sstevel 
96*03831d35Sstevel int
97*03831d35Sstevel is_openprom(void)
98*03831d35Sstevel {
99*03831d35Sstevel 	Oppbuf	oppbuf;
100*03831d35Sstevel 	register struct openpromio *opp = &(oppbuf.opp);
101*03831d35Sstevel 	register unsigned int i;
102*03831d35Sstevel 
103*03831d35Sstevel 	opp->oprom_size = MAXVALSIZE;
104*03831d35Sstevel 	if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
105*03831d35Sstevel 		exit(_error("OPROMGETCONS"));
106*03831d35Sstevel 
107*03831d35Sstevel 	i = (unsigned int)((unsigned char)opp->oprom_array[0]);
108*03831d35Sstevel 	return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
109*03831d35Sstevel }
110*03831d35Sstevel 
111*03831d35Sstevel /*
112*03831d35Sstevel  * Read all properties and values from nodes.
113*03831d35Sstevel  * Copy the properties read into the prom_node passsed in.
114*03831d35Sstevel  */
115*03831d35Sstevel void
116*03831d35Sstevel dump_node(Prom_node *node)
117*03831d35Sstevel {
118*03831d35Sstevel 	Oppbuf oppbuf;
119*03831d35Sstevel 	register struct openpromio *opp = &oppbuf.opp;
120*03831d35Sstevel 	Prop *prop = NULL;	/* tail of properties list */
121*03831d35Sstevel 	StaticProp *temp;
122*03831d35Sstevel 
123*03831d35Sstevel 	/* clear out pointers in pnode */
124*03831d35Sstevel 	node->props = NULL;
125*03831d35Sstevel 
126*03831d35Sstevel 	/* get first prop by asking for null string */
127*03831d35Sstevel 	(void) memset((void *) oppbuf.buf, 0, BUFSIZE);
128*03831d35Sstevel 
129*03831d35Sstevel 	/* allocate space for the property */
130*03831d35Sstevel 	if ((temp = malloc(sizeof (StaticProp))) == NULL) {
131*03831d35Sstevel 		perror("malloc");
132*03831d35Sstevel 		exit(1);
133*03831d35Sstevel 	}
134*03831d35Sstevel 
135*03831d35Sstevel 	opp->oprom_size = MAXPROPSIZE;
136*03831d35Sstevel 	while (opp->oprom_size != 0) {
137*03831d35Sstevel 		Prop *new;
138*03831d35Sstevel 		int i;
139*03831d35Sstevel 		char *tempp, *newp;
140*03831d35Sstevel 
141*03831d35Sstevel 		/*
142*03831d35Sstevel 		 * get property
143*03831d35Sstevel 		 */
144*03831d35Sstevel 		opp->oprom_size = MAXPROPSIZE;
145*03831d35Sstevel 
146*03831d35Sstevel 		if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0)
147*03831d35Sstevel 			exit(_error("OPROMNXTPROP"));
148*03831d35Sstevel 
149*03831d35Sstevel 		if (opp->oprom_size != 0) {
150*03831d35Sstevel 			temp->name.opp.oprom_size = opp->oprom_size;
151*03831d35Sstevel 			(void) strcpy(temp->name.opp.oprom_array,
152*03831d35Sstevel 				opp->oprom_array);
153*03831d35Sstevel 
154*03831d35Sstevel 			(void) strcpy(temp->value.opp.oprom_array,
155*03831d35Sstevel 				temp->name.opp.oprom_array);
156*03831d35Sstevel 			getpropval(&temp->value.opp);
157*03831d35Sstevel 			temp->size = temp->value.opp.oprom_size;
158*03831d35Sstevel 
159*03831d35Sstevel 			/* Now copy over temp's data to new. */
160*03831d35Sstevel 			if ((new = malloc(sizeof (Prop))) == NULL) {
161*03831d35Sstevel 				perror("malloc");
162*03831d35Sstevel 				exit(1);
163*03831d35Sstevel 			}
164*03831d35Sstevel 
165*03831d35Sstevel 			/*
166*03831d35Sstevel 			 * First copy over temp->name's data. The
167*03831d35Sstevel 			 * temp->name.opp.opio_u union always contains char[]
168*03831d35Sstevel 			 * (as opposed to an int or int []).
169*03831d35Sstevel 			 */
170*03831d35Sstevel 			new->name.opp.oprom_size = temp->name.opp.oprom_size;
171*03831d35Sstevel 
172*03831d35Sstevel 			if ((new->name.opp.oprom_array =
173*03831d35Sstevel 			    malloc(new->name.opp.oprom_size)) == NULL) {
174*03831d35Sstevel 				perror("malloc");
175*03831d35Sstevel 				exit(1);
176*03831d35Sstevel 			}
177*03831d35Sstevel 			(void) strcpy(new->name.opp.oprom_array,
178*03831d35Sstevel 			    temp->name.opp.oprom_array);
179*03831d35Sstevel 
180*03831d35Sstevel 			new->name.opp.holds_array = 1;
181*03831d35Sstevel 
182*03831d35Sstevel 			/*
183*03831d35Sstevel 			 * Then copy over temp->value's data.
184*03831d35Sstevel 			 * temp->value.opp.opio_u could contain char[], int or
185*03831d35Sstevel 			 * int []. If *(temp->value.opp.oprom_array) is '\0',
186*03831d35Sstevel 			 * this indicates int or int []. int is the norm, but
187*03831d35Sstevel 			 * to be safe we assume int [] and copy over
188*03831d35Sstevel 			 * OPROM_NODE_SIZE int elements.
189*03831d35Sstevel 			 */
190*03831d35Sstevel 			new->value.opp.oprom_size = temp->value.opp.oprom_size;
191*03831d35Sstevel 
192*03831d35Sstevel 			if (*(temp->value.opp.oprom_array) == '\0') {
193*03831d35Sstevel 				for (i = 0; i < OPROM_NODE_SIZE; i++)
194*03831d35Sstevel 					new->value.opp.oprom_node[i] =
195*03831d35Sstevel 					    *(&temp->value.opp.oprom_node+i);
196*03831d35Sstevel 
197*03831d35Sstevel 				new->value.opp.holds_array = 0;
198*03831d35Sstevel 			} else {
199*03831d35Sstevel 				if ((new->value.opp.oprom_array =
200*03831d35Sstevel 				    malloc(new->value.opp.oprom_size))
201*03831d35Sstevel 				    == NULL) {
202*03831d35Sstevel 					perror("malloc");
203*03831d35Sstevel 					exit(1);
204*03831d35Sstevel 				}
205*03831d35Sstevel 
206*03831d35Sstevel 				/*
207*03831d35Sstevel 				 * temp->value.opp.oprom_array can contain one
208*03831d35Sstevel 				 * or more embedded NULLs. These trip-up the
209*03831d35Sstevel 				 * standard string copying functions, so we do
210*03831d35Sstevel 				 * the copy by hand. temp->value.opp.oprom_array
211*03831d35Sstevel 				 * will be NULL-terminated. oprom_size includes
212*03831d35Sstevel 				 * this terminating NULL.
213*03831d35Sstevel 				 */
214*03831d35Sstevel 				newp = new->value.opp.oprom_array;
215*03831d35Sstevel 				tempp = temp->value.opp.oprom_array;
216*03831d35Sstevel 				for (i = new->value.opp.oprom_size; i > 0; i--)
217*03831d35Sstevel 					*newp++ = *tempp++;
218*03831d35Sstevel 
219*03831d35Sstevel 				new->value.opp.holds_array = 1;
220*03831d35Sstevel 			}
221*03831d35Sstevel 
222*03831d35Sstevel 			new->size = temp->size;
223*03831d35Sstevel 
224*03831d35Sstevel 			/* everything worked so link the property list */
225*03831d35Sstevel 			if (node->props == NULL)
226*03831d35Sstevel 				node->props = new;
227*03831d35Sstevel 			else if (prop != NULL)
228*03831d35Sstevel 				prop->next = new;
229*03831d35Sstevel 			prop = new;
230*03831d35Sstevel 			prop->next = NULL;
231*03831d35Sstevel 		}
232*03831d35Sstevel 	}
233*03831d35Sstevel 	free(temp);
234*03831d35Sstevel }
235*03831d35Sstevel 
236*03831d35Sstevel int
237*03831d35Sstevel promopen(int oflag)
238*03831d35Sstevel {
239*03831d35Sstevel 	/*CONSTCOND*/
240*03831d35Sstevel 	while (1)  {
241*03831d35Sstevel 		if ((prom_fd = open(promdev, oflag)) < 0)  {
242*03831d35Sstevel 			if (errno == EAGAIN)   {
243*03831d35Sstevel 				(void) sleep(5);
244*03831d35Sstevel 				continue;
245*03831d35Sstevel 			}
246*03831d35Sstevel 			if (errno == ENXIO)
247*03831d35Sstevel 				return (-1);
248*03831d35Sstevel 			exit(_error(dgettext(TEXT_DOMAIN, "cannot open %s"),
249*03831d35Sstevel 				promdev));
250*03831d35Sstevel 		} else
251*03831d35Sstevel 			return (0);
252*03831d35Sstevel 	}
253*03831d35Sstevel 	/*NOTREACHED*/
254*03831d35Sstevel }
255*03831d35Sstevel 
256*03831d35Sstevel void
257*03831d35Sstevel promclose(void)
258*03831d35Sstevel {
259*03831d35Sstevel 	if (close(prom_fd) < 0)
260*03831d35Sstevel 		exit(_error(dgettext(TEXT_DOMAIN, "close error on %s"),
261*03831d35Sstevel 			promdev));
262*03831d35Sstevel }
263*03831d35Sstevel 
264*03831d35Sstevel /*
265*03831d35Sstevel  * Read the value of the property from the PROM device tree
266*03831d35Sstevel  */
267*03831d35Sstevel void
268*03831d35Sstevel getpropval(struct openpromio *opp)
269*03831d35Sstevel {
270*03831d35Sstevel 	opp->oprom_size = MAXVALSIZE;
271*03831d35Sstevel 
272*03831d35Sstevel 	if (ioctl(prom_fd, OPROMGETPROP, opp) < 0)
273*03831d35Sstevel 		exit(_error("OPROMGETPROP"));
274*03831d35Sstevel }
275*03831d35Sstevel 
276*03831d35Sstevel int
277*03831d35Sstevel next(int id)
278*03831d35Sstevel {
279*03831d35Sstevel 	Oppbuf	oppbuf;
280*03831d35Sstevel 	register struct openpromio *opp = &(oppbuf.opp);
281*03831d35Sstevel 	/* LINTED */
282*03831d35Sstevel 	int *ip = (int *)(opp->oprom_array);
283*03831d35Sstevel 
284*03831d35Sstevel 	(void) memset((void *) oppbuf.buf, 0, BUFSIZE);
285*03831d35Sstevel 
286*03831d35Sstevel 	opp->oprom_size = MAXVALSIZE;
287*03831d35Sstevel 	*ip = id;
288*03831d35Sstevel 	if (ioctl(prom_fd, OPROMNEXT, opp) < 0)
289*03831d35Sstevel 		return (_error("OPROMNEXT"));
290*03831d35Sstevel 	/* LINTED */
291*03831d35Sstevel 	return (*(int *)opp->oprom_array);
292*03831d35Sstevel }
293*03831d35Sstevel 
294*03831d35Sstevel int
295*03831d35Sstevel child(int id)
296*03831d35Sstevel {
297*03831d35Sstevel 	Oppbuf	oppbuf;
298*03831d35Sstevel 	register struct openpromio *opp = &(oppbuf.opp);
299*03831d35Sstevel 	/* LINTED */
300*03831d35Sstevel 	int *ip = (int *)(opp->oprom_array);
301*03831d35Sstevel 
302*03831d35Sstevel 	(void) memset((void *) oppbuf.buf, 0, BUFSIZE);
303*03831d35Sstevel 	opp->oprom_size = MAXVALSIZE;
304*03831d35Sstevel 	*ip = id;
305*03831d35Sstevel 	if (ioctl(prom_fd, OPROMCHILD, opp) < 0)
306*03831d35Sstevel 		return (_error("OPROMCHILD"));
307*03831d35Sstevel 	/* LINTED */
308*03831d35Sstevel 	return (*(int *)opp->oprom_array);
309*03831d35Sstevel }
310*03831d35Sstevel 
311*03831d35Sstevel /*
312*03831d35Sstevel  * Check if the Prom node passed in contains a property called
313*03831d35Sstevel  * "board#".
314*03831d35Sstevel  */
315*03831d35Sstevel int
316*03831d35Sstevel has_board_num(Prom_node *node)
317*03831d35Sstevel {
318*03831d35Sstevel 	Prop *prop = node->props;
319*03831d35Sstevel 
320*03831d35Sstevel 	/*
321*03831d35Sstevel 	 * walk thru all properties in this PROM node and look for
322*03831d35Sstevel 	 * board# prop
323*03831d35Sstevel 	 */
324*03831d35Sstevel 	while (prop != NULL) {
325*03831d35Sstevel 		if (strcmp(prop->name.opp.oprom_array, "board#") == 0)
326*03831d35Sstevel 		    return (1);
327*03831d35Sstevel 
328*03831d35Sstevel 		prop = prop->next;
329*03831d35Sstevel 	}
330*03831d35Sstevel 
331*03831d35Sstevel 	return (0);
332*03831d35Sstevel }	/* end of has_board_num() */
333*03831d35Sstevel 
334*03831d35Sstevel /*
335*03831d35Sstevel  * Retrieve the value of the board number property from this Prom
336*03831d35Sstevel  * node. It has the type of int.
337*03831d35Sstevel  */
338*03831d35Sstevel int
339*03831d35Sstevel get_board_num(Prom_node *node)
340*03831d35Sstevel {
341*03831d35Sstevel 	Prop *prop = node->props;
342*03831d35Sstevel 
343*03831d35Sstevel 	/*
344*03831d35Sstevel 	 * walk thru all properties in this PROM node and look for
345*03831d35Sstevel 	 * board# prop
346*03831d35Sstevel 	 */
347*03831d35Sstevel 	while (prop != NULL) {
348*03831d35Sstevel 		if (strcmp(prop->name.opp.oprom_array, "board#") == 0)
349*03831d35Sstevel 			return (prop->value.opp.oprom_node[0]);
350*03831d35Sstevel 
351*03831d35Sstevel 		prop = prop->next;
352*03831d35Sstevel 	}
353*03831d35Sstevel 
354*03831d35Sstevel 	return (-1);
355*03831d35Sstevel }	/* end of get_board_num() */
356*03831d35Sstevel 
357*03831d35Sstevel /*
358*03831d35Sstevel  * Find the requested board struct in the system device tree.
359*03831d35Sstevel  */
360*03831d35Sstevel Board_node *
361*03831d35Sstevel find_board(Sys_tree *root, int board)
362*03831d35Sstevel {
363*03831d35Sstevel 	Board_node *bnode = root->bd_list;
364*03831d35Sstevel 
365*03831d35Sstevel 	while ((bnode != NULL) && (board != bnode->board_num))
366*03831d35Sstevel 		bnode = bnode->next;
367*03831d35Sstevel 
368*03831d35Sstevel 	return (bnode);
369*03831d35Sstevel }	/* end of find_board() */
370*03831d35Sstevel 
371*03831d35Sstevel /*
372*03831d35Sstevel  * Add a board to the system list in order. Initialize all pointer
373*03831d35Sstevel  * fields to NULL.
374*03831d35Sstevel  */
375*03831d35Sstevel Board_node *
376*03831d35Sstevel insert_board(Sys_tree *root, int board)
377*03831d35Sstevel {
378*03831d35Sstevel 	Board_node *bnode;
379*03831d35Sstevel 	Board_node *temp = root->bd_list;
380*03831d35Sstevel 
381*03831d35Sstevel 	if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
382*03831d35Sstevel 		perror("malloc");
383*03831d35Sstevel 		exit(1);
384*03831d35Sstevel 	}
385*03831d35Sstevel 	bnode->nodes = NULL;
386*03831d35Sstevel 	bnode->next = NULL;
387*03831d35Sstevel 	bnode->board_num = board;
388*03831d35Sstevel 
389*03831d35Sstevel 	if (temp == NULL)
390*03831d35Sstevel 		root->bd_list = bnode;
391*03831d35Sstevel 	else if (temp->board_num > board) {
392*03831d35Sstevel 		bnode->next = temp;
393*03831d35Sstevel 		root->bd_list = bnode;
394*03831d35Sstevel 	} else {
395*03831d35Sstevel 		while ((temp->next != NULL) && (board > temp->next->board_num))
396*03831d35Sstevel 			temp = temp->next;
397*03831d35Sstevel 		bnode->next = temp->next;
398*03831d35Sstevel 		temp->next = bnode;
399*03831d35Sstevel 	}
400*03831d35Sstevel 	root->board_cnt++;
401*03831d35Sstevel 
402*03831d35Sstevel 	return (bnode);
403*03831d35Sstevel }	/* end of insert_board() */
404*03831d35Sstevel 
405*03831d35Sstevel /*
406*03831d35Sstevel  * This function searches through the properties of the node passed in
407*03831d35Sstevel  * and returns a pointer to the value of the name property.
408*03831d35Sstevel  */
409*03831d35Sstevel char *
410*03831d35Sstevel get_node_name(Prom_node *pnode)
411*03831d35Sstevel {
412*03831d35Sstevel 	Prop *prop;
413*03831d35Sstevel 
414*03831d35Sstevel 	if (pnode == NULL) {
415*03831d35Sstevel 		return (NULL);
416*03831d35Sstevel 	}
417*03831d35Sstevel 
418*03831d35Sstevel 	prop = pnode->props;
419*03831d35Sstevel 	while (prop != NULL) {
420*03831d35Sstevel 		if (strcmp("name", prop->name.opp.oprom_array) == 0)
421*03831d35Sstevel 			return (prop->value.opp.oprom_array);
422*03831d35Sstevel 		prop = prop->next;
423*03831d35Sstevel 	}
424*03831d35Sstevel 	return (NULL);
425*03831d35Sstevel }	/* end of get_node_name() */
426*03831d35Sstevel 
427*03831d35Sstevel /*
428*03831d35Sstevel  * This function searches through the properties of the node passed in
429*03831d35Sstevel  * and returns a pointer to the value of the name property.
430*03831d35Sstevel  */
431*03831d35Sstevel char *
432*03831d35Sstevel get_node_type(Prom_node *pnode)
433*03831d35Sstevel {
434*03831d35Sstevel 	Prop *prop;
435*03831d35Sstevel 
436*03831d35Sstevel 	if (pnode == NULL) {
437*03831d35Sstevel 		return (NULL);
438*03831d35Sstevel 	}
439*03831d35Sstevel 
440*03831d35Sstevel 	prop = pnode->props;
441*03831d35Sstevel 	while (prop != NULL) {
442*03831d35Sstevel 		if (strcmp("device_type", prop->name.opp.oprom_array) == 0)
443*03831d35Sstevel 			return (prop->value.opp.oprom_array);
444*03831d35Sstevel 		prop = prop->next;
445*03831d35Sstevel 	}
446*03831d35Sstevel 	return (NULL);
447*03831d35Sstevel }	/* end of get_node_type() */
448*03831d35Sstevel 
449*03831d35Sstevel /*
450*03831d35Sstevel  * Do a depth-first walk of a device tree and
451*03831d35Sstevel  * return the first node with the name matching.
452*03831d35Sstevel  */
453*03831d35Sstevel 
454*03831d35Sstevel Prom_node *
455*03831d35Sstevel dev_find_node(Prom_node *root, char *name)
456*03831d35Sstevel {
457*03831d35Sstevel 	Prom_node *node;
458*03831d35Sstevel 
459*03831d35Sstevel 	node = dev_find_node_by_type(root, "name", name);
460*03831d35Sstevel 
461*03831d35Sstevel 	return (node);
462*03831d35Sstevel }
463*03831d35Sstevel 
464*03831d35Sstevel Prom_node *
465*03831d35Sstevel dev_next_node(Prom_node *root, char *name)
466*03831d35Sstevel {
467*03831d35Sstevel 	Prom_node *node;
468*03831d35Sstevel 
469*03831d35Sstevel 	node = dev_next_node_by_type(root, "name", name);
470*03831d35Sstevel 
471*03831d35Sstevel 	return (node);
472*03831d35Sstevel }
473*03831d35Sstevel 
474*03831d35Sstevel /*
475*03831d35Sstevel  * Search for and return a node of the required type. If no node is found,
476*03831d35Sstevel  * then return NULL.
477*03831d35Sstevel  */
478*03831d35Sstevel Prom_node *
479*03831d35Sstevel dev_find_type(Prom_node *root, char *type)
480*03831d35Sstevel {
481*03831d35Sstevel 	Prom_node *node;
482*03831d35Sstevel 
483*03831d35Sstevel 	node = dev_find_node_by_type(root, "device_type", type);
484*03831d35Sstevel 
485*03831d35Sstevel 	return (node);  /* not found */
486*03831d35Sstevel }
487*03831d35Sstevel 
488*03831d35Sstevel /*
489*03831d35Sstevel  * Start from the current node and return the next node besides the
490*03831d35Sstevel  * current one which has the requested type property.
491*03831d35Sstevel  */
492*03831d35Sstevel Prom_node *
493*03831d35Sstevel dev_next_type(Prom_node *root, char *type)
494*03831d35Sstevel {
495*03831d35Sstevel 	Prom_node *node;
496*03831d35Sstevel 
497*03831d35Sstevel 	node = dev_next_node_by_type(root, "device_type", type);
498*03831d35Sstevel 
499*03831d35Sstevel 	return (node);  /* not found */
500*03831d35Sstevel }
501*03831d35Sstevel 
502*03831d35Sstevel /*
503*03831d35Sstevel  * Search a device tree and return the first failed node that is found.
504*03831d35Sstevel  * (has a 'status' property)
505*03831d35Sstevel  */
506*03831d35Sstevel Prom_node *
507*03831d35Sstevel find_failed_node(Prom_node * root)
508*03831d35Sstevel {
509*03831d35Sstevel 	Prom_node *pnode;
510*03831d35Sstevel 
511*03831d35Sstevel 	if (root == NULL)
512*03831d35Sstevel 		return (NULL);
513*03831d35Sstevel 
514*03831d35Sstevel 	if (node_failed(root)) {
515*03831d35Sstevel 		return (root);
516*03831d35Sstevel 	}
517*03831d35Sstevel 
518*03831d35Sstevel 	/* search the child */
519*03831d35Sstevel 	if ((pnode = find_failed_node(root->child)) != NULL)
520*03831d35Sstevel 		return (pnode);
521*03831d35Sstevel 
522*03831d35Sstevel 	/* search the siblings */
523*03831d35Sstevel 	if ((pnode = find_failed_node(root->sibling)) != NULL)
524*03831d35Sstevel 		return (pnode);
525*03831d35Sstevel 
526*03831d35Sstevel 	return (NULL);
527*03831d35Sstevel }	/* end of find_failed_node() */
528*03831d35Sstevel 
529*03831d35Sstevel /*
530*03831d35Sstevel  * Start from the current node and return the next node besides
531*03831d35Sstevel  * the current one which is failed. (has a 'status' property)
532*03831d35Sstevel  */
533*03831d35Sstevel Prom_node *
534*03831d35Sstevel next_failed_node(Prom_node * root)
535*03831d35Sstevel {
536*03831d35Sstevel 	Prom_node *pnode;
537*03831d35Sstevel 	Prom_node *parent;
538*03831d35Sstevel 
539*03831d35Sstevel 	if (root == NULL)
540*03831d35Sstevel 		return (NULL);
541*03831d35Sstevel 
542*03831d35Sstevel 	/* search the child */
543*03831d35Sstevel 	if ((pnode = find_failed_node(root->child)) != NULL) {
544*03831d35Sstevel 		return (pnode);
545*03831d35Sstevel 	}
546*03831d35Sstevel 
547*03831d35Sstevel 	/* search the siblings */
548*03831d35Sstevel 	if ((pnode = find_failed_node(root->sibling)) != NULL) {
549*03831d35Sstevel 		return (pnode);
550*03831d35Sstevel 	}
551*03831d35Sstevel 
552*03831d35Sstevel 	/* backtracking the search up through parents' siblings */
553*03831d35Sstevel 	parent = root->parent;
554*03831d35Sstevel 	while (parent != NULL) {
555*03831d35Sstevel 		if ((pnode = find_failed_node(parent->sibling)) != NULL)
556*03831d35Sstevel 			return (pnode);
557*03831d35Sstevel 		else
558*03831d35Sstevel 			parent = parent->parent;
559*03831d35Sstevel 	}
560*03831d35Sstevel 
561*03831d35Sstevel 	return (NULL);
562*03831d35Sstevel }	/* end of find_failed_node() */
563*03831d35Sstevel 
564*03831d35Sstevel /*
565*03831d35Sstevel  * node_failed
566*03831d35Sstevel  *
567*03831d35Sstevel  * This function determines if the current Prom node is failed. This
568*03831d35Sstevel  * is defined by having a status property containing the token 'fail'.
569*03831d35Sstevel  */
570*03831d35Sstevel int
571*03831d35Sstevel node_failed(Prom_node *node)
572*03831d35Sstevel {
573*03831d35Sstevel 	return (node_status(node, "fail"));
574*03831d35Sstevel }
575*03831d35Sstevel 
576*03831d35Sstevel int
577*03831d35Sstevel node_status(Prom_node *node, char *status)
578*03831d35Sstevel {
579*03831d35Sstevel 	void *value;
580*03831d35Sstevel 
581*03831d35Sstevel 	if (status == NULL)
582*03831d35Sstevel 		return (0);
583*03831d35Sstevel 
584*03831d35Sstevel 	/* search the local node */
585*03831d35Sstevel 	if ((value = get_prop_val(find_prop(node, "status"))) != NULL) {
586*03831d35Sstevel 		if ((value != NULL) && strstr((char *)value, status))
587*03831d35Sstevel 			return (1);
588*03831d35Sstevel 	}
589*03831d35Sstevel 	return (0);
590*03831d35Sstevel }
591*03831d35Sstevel 
592*03831d35Sstevel /*
593*03831d35Sstevel  * Get a property's value. Must be void * since the property can
594*03831d35Sstevel  * be any data type. Caller must know the *PROPER* way to use this
595*03831d35Sstevel  * data.
596*03831d35Sstevel  */
597*03831d35Sstevel void *
598*03831d35Sstevel get_prop_val(Prop *prop)
599*03831d35Sstevel {
600*03831d35Sstevel 	if (prop == NULL)
601*03831d35Sstevel 		return (NULL);
602*03831d35Sstevel 
603*03831d35Sstevel 	if (prop->value.opp.holds_array)
604*03831d35Sstevel 		return ((void *)(prop->value.opp.oprom_array));
605*03831d35Sstevel 	else
606*03831d35Sstevel 		return ((void *)(&prop->value.opp.oprom_node[0]));
607*03831d35Sstevel }	/* end of get_prop_val() */
608*03831d35Sstevel 
609*03831d35Sstevel /*
610*03831d35Sstevel  * Search a Prom node and retrieve the property with the correct
611*03831d35Sstevel  * name.
612*03831d35Sstevel  */
613*03831d35Sstevel Prop *
614*03831d35Sstevel find_prop(Prom_node *pnode, char *name)
615*03831d35Sstevel {
616*03831d35Sstevel 	Prop *prop;
617*03831d35Sstevel 
618*03831d35Sstevel 	if (pnode  == NULL) {
619*03831d35Sstevel 		return (NULL);
620*03831d35Sstevel 	}
621*03831d35Sstevel 
622*03831d35Sstevel 	if (pnode->props == NULL) {
623*03831d35Sstevel 		(void) printf("%s", dgettext(TEXT_DOMAIN, "Prom node has "
624*03831d35Sstevel 			"no properties\n"));
625*03831d35Sstevel 		return (NULL);
626*03831d35Sstevel 	}
627*03831d35Sstevel 
628*03831d35Sstevel 	prop = pnode->props;
629*03831d35Sstevel 	while ((prop != NULL) && (strcmp(prop->name.opp.oprom_array, name)))
630*03831d35Sstevel 		prop = prop->next;
631*03831d35Sstevel 
632*03831d35Sstevel 	return (prop);
633*03831d35Sstevel }
634*03831d35Sstevel 
635*03831d35Sstevel /*
636*03831d35Sstevel  * This function adds a board node to the board structure where that
637*03831d35Sstevel  * that node's physical component lives.
638*03831d35Sstevel  */
639*03831d35Sstevel void
640*03831d35Sstevel add_node(Sys_tree *root, Prom_node *pnode)
641*03831d35Sstevel {
642*03831d35Sstevel 	int board;
643*03831d35Sstevel 	Board_node *bnode;
644*03831d35Sstevel 	Prom_node *p;
645*03831d35Sstevel 
646*03831d35Sstevel 	/* add this node to the Board list of the appropriate board */
647*03831d35Sstevel 	if ((board = get_board_num(pnode)) == -1) {
648*03831d35Sstevel 		/* board is 0 if not on Sunfire */
649*03831d35Sstevel 		board = 0;
650*03831d35Sstevel 	}
651*03831d35Sstevel 
652*03831d35Sstevel 	/* find the node with the same board number */
653*03831d35Sstevel 	if ((bnode = find_board(root, board)) == NULL) {
654*03831d35Sstevel 		bnode = insert_board(root, board);
655*03831d35Sstevel 		bnode->board_type = UNKNOWN_BOARD;
656*03831d35Sstevel 	}
657*03831d35Sstevel 
658*03831d35Sstevel 	/* now attach this prom node to the board list */
659*03831d35Sstevel 	/* Insert this node at the end of the list */
660*03831d35Sstevel 	pnode->sibling = NULL;
661*03831d35Sstevel 	if (bnode->nodes == NULL)
662*03831d35Sstevel 		bnode->nodes = pnode;
663*03831d35Sstevel 	else {
664*03831d35Sstevel 		p = bnode->nodes;
665*03831d35Sstevel 		while (p->sibling != NULL)
666*03831d35Sstevel 			p = p->sibling;
667*03831d35Sstevel 		p->sibling = pnode;
668*03831d35Sstevel 	}
669*03831d35Sstevel 
670*03831d35Sstevel }
671*03831d35Sstevel 
672*03831d35Sstevel /*
673*03831d35Sstevel  * Find the device on the current board with the requested device ID
674*03831d35Sstevel  * and name. If this rountine is passed a NULL pointer, it simply returns
675*03831d35Sstevel  * NULL.
676*03831d35Sstevel  */
677*03831d35Sstevel Prom_node *
678*03831d35Sstevel find_device(Board_node *board, int id, char *name)
679*03831d35Sstevel {
680*03831d35Sstevel 	Prom_node *pnode;
681*03831d35Sstevel 	int mask;
682*03831d35Sstevel 
683*03831d35Sstevel 	/* find the first cpu node */
684*03831d35Sstevel 	pnode = dev_find_node(board->nodes, name);
685*03831d35Sstevel 
686*03831d35Sstevel 	mask = 0x1F;
687*03831d35Sstevel 	while (pnode != NULL) {
688*03831d35Sstevel 		if ((get_id(pnode) & mask) == id)
689*03831d35Sstevel 			return (pnode);
690*03831d35Sstevel 
691*03831d35Sstevel 		pnode = dev_next_node(pnode, name);
692*03831d35Sstevel 	}
693*03831d35Sstevel 	return (NULL);
694*03831d35Sstevel }
695*03831d35Sstevel 
696*03831d35Sstevel Prom_node *
697*03831d35Sstevel dev_find_node_by_type(Prom_node *root, char *type, char *property)
698*03831d35Sstevel {
699*03831d35Sstevel 	Prom_node *node;
700*03831d35Sstevel 	char *type_prop;
701*03831d35Sstevel 
702*03831d35Sstevel 	if (root == NULL || property == NULL)
703*03831d35Sstevel 		return (NULL);
704*03831d35Sstevel 
705*03831d35Sstevel 	type_prop = (char *)get_prop_val(find_prop(root, type));
706*03831d35Sstevel 
707*03831d35Sstevel 	if (type_prop != NULL) {
708*03831d35Sstevel 		if (strcmp(type_prop, property) == 0) {
709*03831d35Sstevel 			return (root);
710*03831d35Sstevel 		}
711*03831d35Sstevel 	}
712*03831d35Sstevel 
713*03831d35Sstevel 	/* look at your children first */
714*03831d35Sstevel 	if ((node = dev_find_node_by_type(root->child, type,
715*03831d35Sstevel 	    property)) != NULL)
716*03831d35Sstevel 		return (node);
717*03831d35Sstevel 
718*03831d35Sstevel 	/* now look at your siblings */
719*03831d35Sstevel 	if ((node = dev_find_node_by_type(root->sibling, type,
720*03831d35Sstevel 	    property)) != NULL)
721*03831d35Sstevel 		return (node);
722*03831d35Sstevel 
723*03831d35Sstevel 	return (NULL);	/* not found */
724*03831d35Sstevel }
725*03831d35Sstevel 
726*03831d35Sstevel Prom_node *
727*03831d35Sstevel dev_next_node_by_type(Prom_node *root, char *type, char *property)
728*03831d35Sstevel {
729*03831d35Sstevel 	Prom_node *node;
730*03831d35Sstevel 
731*03831d35Sstevel 	if (root == NULL || property == NULL)
732*03831d35Sstevel 		return (NULL);
733*03831d35Sstevel 
734*03831d35Sstevel 	/* look at your children first */
735*03831d35Sstevel 	if ((node = dev_find_node_by_type(root->child, type,
736*03831d35Sstevel 	    property)) != NULL)
737*03831d35Sstevel 		return (node);
738*03831d35Sstevel 
739*03831d35Sstevel 	/* now look at your siblings */
740*03831d35Sstevel 	if ((node = dev_find_node_by_type(root->sibling, type,
741*03831d35Sstevel 	    property)) != NULL)
742*03831d35Sstevel 		return (node);
743*03831d35Sstevel 
744*03831d35Sstevel 	/* now look at papa's siblings */
745*03831d35Sstevel 	if ((node = dev_find_node_by_type(root->parent->sibling,
746*03831d35Sstevel 	    type, property)) != NULL)
747*03831d35Sstevel 		return (node);
748*03831d35Sstevel 
749*03831d35Sstevel 	return (NULL);  /* not found */
750*03831d35Sstevel }
751*03831d35Sstevel 
752*03831d35Sstevel /*
753*03831d35Sstevel  * Do a depth-first walk of a device tree and
754*03831d35Sstevel  * return the first node with the matching compatible.
755*03831d35Sstevel  */
756*03831d35Sstevel Prom_node *
757*03831d35Sstevel dev_find_node_by_compatible(Prom_node *root, char *compatible)
758*03831d35Sstevel {
759*03831d35Sstevel 	Prom_node *node;
760*03831d35Sstevel 	Prop	*prop;
761*03831d35Sstevel 	char	*compatible_array;
762*03831d35Sstevel 	int	size, nbytes;
763*03831d35Sstevel 
764*03831d35Sstevel 	if (root == NULL || compatible == NULL)
765*03831d35Sstevel 		return (NULL);
766*03831d35Sstevel 
767*03831d35Sstevel 	if ((prop = find_prop(root, "compatible")) != NULL &&
768*03831d35Sstevel 	    (compatible_array = (char *)get_prop_val(prop)) != NULL) {
769*03831d35Sstevel 		/*
770*03831d35Sstevel 		 * The Prop structure returned by find_prop() is supposed
771*03831d35Sstevel 		 * to contain an indication of how big the value of the
772*03831d35Sstevel 		 * compatible property is.  Since it is an array of strings
773*03831d35Sstevel 		 * this is our only means of determining just how many
774*03831d35Sstevel 		 * strings might be in this property.  However, this size
775*03831d35Sstevel 		 * is often left as zero even though there is at least one
776*03831d35Sstevel 		 * string present.  When this is the case, all we can do
777*03831d35Sstevel 		 * is examine the first string in the compatible property.
778*03831d35Sstevel 		 */
779*03831d35Sstevel 
780*03831d35Sstevel 		for (size = prop->size; size >= 0; size -= nbytes) {
781*03831d35Sstevel 			if (strcmp(compatible_array, compatible) == 0)
782*03831d35Sstevel 				return (root);		/* found a match */
783*03831d35Sstevel 
784*03831d35Sstevel 			nbytes = strlen(compatible_array) + 1;
785*03831d35Sstevel 			compatible_array += nbytes;
786*03831d35Sstevel 		}
787*03831d35Sstevel 	}
788*03831d35Sstevel 
789*03831d35Sstevel 	node = dev_find_node_by_compatible(root->child, compatible);
790*03831d35Sstevel 	if (node != NULL)
791*03831d35Sstevel 		return (node);
792*03831d35Sstevel 
793*03831d35Sstevel 	/*
794*03831d35Sstevel 	 * Note the very deliberate use of tail recursion here.	 A good
795*03831d35Sstevel 	 * compiler (such as Sun's) will recognize this and generate code
796*03831d35Sstevel 	 * that does not allocate another stack frame.	Instead, it will
797*03831d35Sstevel 	 * overlay the existing stack frame with the new one, the only change
798*03831d35Sstevel 	 * having been to replace the original root with its sibling.
799*03831d35Sstevel 	 * This has the potential to create some confusion for anyone
800*03831d35Sstevel 	 * trying to debug this code from a core dump, since the stack
801*03831d35Sstevel 	 * trace will not reveal recursion on siblings, only on children.
802*03831d35Sstevel 	 */
803*03831d35Sstevel 
804*03831d35Sstevel 	return (dev_find_node_by_compatible(root->sibling, compatible));
805*03831d35Sstevel }
806*03831d35Sstevel 
807*03831d35Sstevel /*
808*03831d35Sstevel  * Start from the current node and return the next node besides
809*03831d35Sstevel  * the current one which has the requested compatible property.
810*03831d35Sstevel  */
811*03831d35Sstevel Prom_node *
812*03831d35Sstevel dev_next_node_by_compatible(Prom_node *root, char *compatible)
813*03831d35Sstevel {
814*03831d35Sstevel 	Prom_node *node;
815*03831d35Sstevel 
816*03831d35Sstevel 	if (root == NULL || compatible == NULL)
817*03831d35Sstevel 		return (NULL);
818*03831d35Sstevel 
819*03831d35Sstevel 	node = dev_find_node_by_compatible(root->child, compatible);
820*03831d35Sstevel 	if (node != NULL)
821*03831d35Sstevel 		return (node);
822*03831d35Sstevel 
823*03831d35Sstevel 	/*
824*03831d35Sstevel 	 * More tail recursion.	 Even though it is a different function,
825*03831d35Sstevel 	 * this will overlay the current stack frame.  Caveat exterminator.
826*03831d35Sstevel 	 */
827*03831d35Sstevel 
828*03831d35Sstevel 	node = dev_find_node_by_compatible(root->sibling, compatible);
829*03831d35Sstevel 	if (node != NULL)
830*03831d35Sstevel 		return (node);
831*03831d35Sstevel 
832*03831d35Sstevel 	return (dev_find_node_by_compatible(root->parent->sibling, compatible));
833*03831d35Sstevel }
834