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
_error(char * fmt,...)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
is_openprom(void)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
dump_node(Prom_node * node)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
promopen(int oflag)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
promclose(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
getpropval(struct openpromio * opp)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
next(int id)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
child(int id)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
has_board_num(Prom_node * node)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
get_board_num(Prom_node * node)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 *
find_board(Sys_tree * root,int board)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 *
insert_board(Sys_tree * root,int board)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 *
get_node_name(Prom_node * pnode)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 *
get_node_type(Prom_node * pnode)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 *
dev_find_node(Prom_node * root,char * name)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 *
dev_next_node(Prom_node * root,char * name)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 *
dev_find_type(Prom_node * root,char * type)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 *
dev_next_type(Prom_node * root,char * type)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 *
find_failed_node(Prom_node * root)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 *
next_failed_node(Prom_node * root)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
node_failed(Prom_node * node)571*03831d35Sstevel node_failed(Prom_node *node)
572*03831d35Sstevel {
573*03831d35Sstevel return (node_status(node, "fail"));
574*03831d35Sstevel }
575*03831d35Sstevel
576*03831d35Sstevel int
node_status(Prom_node * node,char * status)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 *
get_prop_val(Prop * prop)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 *
find_prop(Prom_node * pnode,char * name)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
add_node(Sys_tree * root,Prom_node * pnode)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 *
find_device(Board_node * board,int id,char * name)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 *
dev_find_node_by_type(Prom_node * root,char * type,char * property)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 *
dev_next_node_by_type(Prom_node * root,char * type,char * property)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 *
dev_find_node_by_compatible(Prom_node * root,char * compatible)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 *
dev_next_node_by_compatible(Prom_node * root,char * compatible)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