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