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