4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
36 #include <sys/utsname.h>
37 #include <sys/openpromio.h>
41 #include "pdevinfo_sun4u.h"
44 * For machines that support the openprom, fetch and print the list
45 * of devices that the kernel has fetched from the prom or conjured up.
51 extern char *progname
;
53 extern void getppdata();
54 extern void printppdata();
57 * Define DPRINT for run-time debugging printf's...
62 static char vdebug_flag
= 1;
63 #define dprintf if (vdebug_flag) printf
64 static void dprint_dev_info(caddr_t
, dev_info_t
*);
67 #if !defined(TEXT_DOMAIN)
68 #define TEXT_DOMAIN "SYS_TEST"
73 _error(char *fmt
, ...)
81 (void) fprintf(stderr
, "%s: ", progname
);
85 (void) vfprintf(stderr
, fmt
, ap
);
89 (void) fprintf(stderr
, ": ");
100 register struct openpromio
*opp
= &(oppbuf
.opp
);
101 register unsigned int i
;
103 opp
->oprom_size
= MAXVALSIZE
;
104 if (ioctl(prom_fd
, OPROMGETCONS
, opp
) < 0)
105 exit(_error("OPROMGETCONS"));
107 i
= (unsigned int)((unsigned char)opp
->oprom_array
[0]);
108 return ((i
& OPROMCONS_OPENPROM
) == OPROMCONS_OPENPROM
);
112 * Read all properties and values from nodes.
113 * Copy the properties read into the prom_node passsed in.
116 dump_node(Prom_node
*node
)
119 register struct openpromio
*opp
= &oppbuf
.opp
;
120 Prop
*prop
= NULL
; /* tail of properties list */
123 /* clear out pointers in pnode */
126 /* get first prop by asking for null string */
127 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
129 /* allocate space for the property */
130 if ((temp
= malloc(sizeof (StaticProp
))) == NULL
) {
135 opp
->oprom_size
= MAXPROPSIZE
;
136 while (opp
->oprom_size
!= 0) {
144 opp
->oprom_size
= MAXPROPSIZE
;
146 if (ioctl(prom_fd
, OPROMNXTPROP
, opp
) < 0)
147 exit(_error("OPROMNXTPROP"));
149 if (opp
->oprom_size
!= 0) {
150 temp
->name
.opp
.oprom_size
= opp
->oprom_size
;
151 (void) strcpy(temp
->name
.opp
.oprom_array
,
154 (void) strcpy(temp
->value
.opp
.oprom_array
,
155 temp
->name
.opp
.oprom_array
);
156 getpropval(&temp
->value
.opp
);
157 temp
->size
= temp
->value
.opp
.oprom_size
;
159 /* Now copy over temp's data to new. */
160 if ((new = malloc(sizeof (Prop
))) == NULL
) {
166 * First copy over temp->name's data. The
167 * temp->name.opp.opio_u union always contains char[]
168 * (as opposed to an int or int []).
170 new->name
.opp
.oprom_size
= temp
->name
.opp
.oprom_size
;
172 if ((new->name
.opp
.oprom_array
=
173 malloc(new->name
.opp
.oprom_size
)) == NULL
) {
177 (void) strcpy(new->name
.opp
.oprom_array
,
178 temp
->name
.opp
.oprom_array
);
180 new->name
.opp
.holds_array
= 1;
183 * Then copy over temp->value's data.
184 * temp->value.opp.opio_u could contain char[], int or
185 * int []. If *(temp->value.opp.oprom_array) is '\0',
186 * this indicates int or int []. int is the norm, but
187 * to be safe we assume int [] and copy over
188 * OPROM_NODE_SIZE int elements.
190 new->value
.opp
.oprom_size
= temp
->value
.opp
.oprom_size
;
192 if (*(temp
->value
.opp
.oprom_array
) == '\0') {
193 for (i
= 0; i
< OPROM_NODE_SIZE
; i
++)
194 new->value
.opp
.oprom_node
[i
] =
195 *(&temp
->value
.opp
.oprom_node
+i
);
197 new->value
.opp
.holds_array
= 0;
199 if ((new->value
.opp
.oprom_array
=
200 malloc(new->value
.opp
.oprom_size
))
207 * temp->value.opp.oprom_array can contain one
208 * or more embedded NULLs. These trip-up the
209 * standard string copying functions, so we do
210 * the copy by hand. temp->value.opp.oprom_array
211 * will be NULL-terminated. oprom_size includes
212 * this terminating NULL.
214 newp
= new->value
.opp
.oprom_array
;
215 tempp
= temp
->value
.opp
.oprom_array
;
216 for (i
= new->value
.opp
.oprom_size
; i
> 0; i
--)
219 new->value
.opp
.holds_array
= 1;
222 new->size
= temp
->size
;
224 /* everything worked so link the property list */
225 if (node
->props
== NULL
)
227 else if (prop
!= NULL
)
241 if ((prom_fd
= open(promdev
, oflag
)) < 0) {
242 if (errno
== EAGAIN
) {
248 exit(_error(dgettext(TEXT_DOMAIN
, "cannot open %s"),
259 if (close(prom_fd
) < 0)
260 exit(_error(dgettext(TEXT_DOMAIN
, "close error on %s"),
265 * Read the value of the property from the PROM device tree
268 getpropval(struct openpromio
*opp
)
270 opp
->oprom_size
= MAXVALSIZE
;
272 if (ioctl(prom_fd
, OPROMGETPROP
, opp
) < 0)
273 exit(_error("OPROMGETPROP"));
280 register struct openpromio
*opp
= &(oppbuf
.opp
);
282 int *ip
= (int *)(opp
->oprom_array
);
284 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
286 opp
->oprom_size
= MAXVALSIZE
;
288 if (ioctl(prom_fd
, OPROMNEXT
, opp
) < 0)
289 return (_error("OPROMNEXT"));
291 return (*(int *)opp
->oprom_array
);
298 register struct openpromio
*opp
= &(oppbuf
.opp
);
300 int *ip
= (int *)(opp
->oprom_array
);
302 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
303 opp
->oprom_size
= MAXVALSIZE
;
305 if (ioctl(prom_fd
, OPROMCHILD
, opp
) < 0)
306 return (_error("OPROMCHILD"));
308 return (*(int *)opp
->oprom_array
);
312 * Check if the Prom node passed in contains a property called
316 has_board_num(Prom_node
*node
)
318 Prop
*prop
= node
->props
;
321 * walk thru all properties in this PROM node and look for
324 while (prop
!= NULL
) {
325 if (strcmp(prop
->name
.opp
.oprom_array
, "board#") == 0)
332 } /* end of has_board_num() */
335 * Retrieve the value of the board number property from this Prom
336 * node. It has the type of int.
339 get_board_num(Prom_node
*node
)
341 Prop
*prop
= node
->props
;
344 * walk thru all properties in this PROM node and look for
347 while (prop
!= NULL
) {
348 if (strcmp(prop
->name
.opp
.oprom_array
, "board#") == 0)
349 return (prop
->value
.opp
.oprom_node
[0]);
355 } /* end of get_board_num() */
358 * Find the requested board struct in the system device tree.
361 find_board(Sys_tree
*root
, int board
)
363 Board_node
*bnode
= root
->bd_list
;
365 while ((bnode
!= NULL
) && (board
!= bnode
->board_num
))
369 } /* end of find_board() */
372 * Add a board to the system list in order. Initialize all pointer
376 insert_board(Sys_tree
*root
, int board
)
379 Board_node
*temp
= root
->bd_list
;
381 if ((bnode
= (Board_node
*) malloc(sizeof (Board_node
))) == NULL
) {
387 bnode
->board_num
= board
;
390 root
->bd_list
= bnode
;
391 else if (temp
->board_num
> board
) {
393 root
->bd_list
= bnode
;
395 while ((temp
->next
!= NULL
) && (board
> temp
->next
->board_num
))
397 bnode
->next
= temp
->next
;
403 } /* end of insert_board() */
406 * This function searches through the properties of the node passed in
407 * and returns a pointer to the value of the name property.
410 get_node_name(Prom_node
*pnode
)
419 while (prop
!= NULL
) {
420 if (strcmp("name", prop
->name
.opp
.oprom_array
) == 0)
421 return (prop
->value
.opp
.oprom_array
);
425 } /* end of get_node_name() */
428 * This function searches through the properties of the node passed in
429 * and returns a pointer to the value of the name property.
432 get_node_type(Prom_node
*pnode
)
441 while (prop
!= NULL
) {
442 if (strcmp("device_type", prop
->name
.opp
.oprom_array
) == 0)
443 return (prop
->value
.opp
.oprom_array
);
447 } /* end of get_node_type() */
450 * Do a depth-first walk of a device tree and
451 * return the first node with the name matching.
455 dev_find_node(Prom_node
*root
, char *name
)
459 node
= dev_find_node_by_type(root
, "name", name
);
465 dev_next_node(Prom_node
*root
, char *name
)
469 node
= dev_next_node_by_type(root
, "name", name
);
475 * Search for and return a node of the required type. If no node is found,
479 dev_find_type(Prom_node
*root
, char *type
)
483 node
= dev_find_node_by_type(root
, "device_type", type
);
485 return (node
); /* not found */
489 * Start from the current node and return the next node besides the
490 * current one which has the requested type property.
493 dev_next_type(Prom_node
*root
, char *type
)
497 node
= dev_next_node_by_type(root
, "device_type", type
);
499 return (node
); /* not found */
503 * Search a device tree and return the first failed node that is found.
504 * (has a 'status' property)
507 find_failed_node(Prom_node
* root
)
514 if (node_failed(root
)) {
518 /* search the child */
519 if ((pnode
= find_failed_node(root
->child
)) != NULL
)
522 /* search the siblings */
523 if ((pnode
= find_failed_node(root
->sibling
)) != NULL
)
527 } /* end of find_failed_node() */
530 * Start from the current node and return the next node besides
531 * the current one which is failed. (has a 'status' property)
534 next_failed_node(Prom_node
* root
)
542 /* search the child */
543 if ((pnode
= find_failed_node(root
->child
)) != NULL
) {
547 /* search the siblings */
548 if ((pnode
= find_failed_node(root
->sibling
)) != NULL
) {
552 /* backtracking the search up through parents' siblings */
553 parent
= root
->parent
;
554 while (parent
!= NULL
) {
555 if ((pnode
= find_failed_node(parent
->sibling
)) != NULL
)
558 parent
= parent
->parent
;
562 } /* end of find_failed_node() */
567 * This function determines if the current Prom node is failed. This
568 * is defined by having a status property containing the token 'fail'.
571 node_failed(Prom_node
*node
)
573 return (node_status(node
, "fail"));
577 node_status(Prom_node
*node
, char *status
)
584 /* search the local node */
585 if ((value
= get_prop_val(find_prop(node
, "status"))) != NULL
) {
586 if ((value
!= NULL
) && strstr((char *)value
, status
))
593 * Get a property's value. Must be void * since the property can
594 * be any data type. Caller must know the *PROPER* way to use this
598 get_prop_val(Prop
*prop
)
603 if (prop
->value
.opp
.holds_array
)
604 return ((void *)(prop
->value
.opp
.oprom_array
));
606 return ((void *)(&prop
->value
.opp
.oprom_node
[0]));
607 } /* end of get_prop_val() */
610 * Search a Prom node and retrieve the property with the correct
614 find_prop(Prom_node
*pnode
, char *name
)
622 if (pnode
->props
== NULL
) {
623 (void) printf("%s", dgettext(TEXT_DOMAIN
, "Prom node has "
629 while ((prop
!= NULL
) && (strcmp(prop
->name
.opp
.oprom_array
, name
)))
636 * This function adds a board node to the board structure where that
637 * that node's physical component lives.
640 add_node(Sys_tree
*root
, Prom_node
*pnode
)
646 /* add this node to the Board list of the appropriate board */
647 if ((board
= get_board_num(pnode
)) == -1) {
648 /* board is 0 if not on Sunfire */
652 /* find the node with the same board number */
653 if ((bnode
= find_board(root
, board
)) == NULL
) {
654 bnode
= insert_board(root
, board
);
655 bnode
->board_type
= UNKNOWN_BOARD
;
658 /* now attach this prom node to the board list */
659 /* Insert this node at the end of the list */
660 pnode
->sibling
= NULL
;
661 if (bnode
->nodes
== NULL
)
662 bnode
->nodes
= pnode
;
665 while (p
->sibling
!= NULL
)
673 * Find the device on the current board with the requested device ID
674 * and name. If this rountine is passed a NULL pointer, it simply returns
678 find_device(Board_node
*board
, int id
, char *name
)
683 /* find the first cpu node */
684 pnode
= dev_find_node(board
->nodes
, name
);
687 while (pnode
!= NULL
) {
688 if ((get_id(pnode
) & mask
) == id
)
691 pnode
= dev_next_node(pnode
, name
);
697 dev_find_node_by_type(Prom_node
*root
, char *type
, char *property
)
702 if (root
== NULL
|| property
== NULL
)
705 type_prop
= (char *)get_prop_val(find_prop(root
, type
));
707 if (type_prop
!= NULL
) {
708 if (strcmp(type_prop
, property
) == 0) {
713 /* look at your children first */
714 if ((node
= dev_find_node_by_type(root
->child
, type
,
718 /* now look at your siblings */
719 if ((node
= dev_find_node_by_type(root
->sibling
, type
,
723 return (NULL
); /* not found */
727 dev_next_node_by_type(Prom_node
*root
, char *type
, char *property
)
731 if (root
== NULL
|| property
== NULL
)
734 /* look at your children first */
735 if ((node
= dev_find_node_by_type(root
->child
, type
,
739 /* now look at your siblings */
740 if ((node
= dev_find_node_by_type(root
->sibling
, type
,
744 /* now look at papa's siblings */
745 if ((node
= dev_find_node_by_type(root
->parent
->sibling
,
746 type
, property
)) != NULL
)
749 return (NULL
); /* not found */
753 * Do a depth-first walk of a device tree and
754 * return the first node with the matching compatible.
757 dev_find_node_by_compatible(Prom_node
*root
, char *compatible
)
761 char *compatible_array
;
764 if (root
== NULL
|| compatible
== NULL
)
767 if ((prop
= find_prop(root
, "compatible")) != NULL
&&
768 (compatible_array
= (char *)get_prop_val(prop
)) != NULL
) {
770 * The Prop structure returned by find_prop() is supposed
771 * to contain an indication of how big the value of the
772 * compatible property is. Since it is an array of strings
773 * this is our only means of determining just how many
774 * strings might be in this property. However, this size
775 * is often left as zero even though there is at least one
776 * string present. When this is the case, all we can do
777 * is examine the first string in the compatible property.
780 for (size
= prop
->size
; size
>= 0; size
-= nbytes
) {
781 if (strcmp(compatible_array
, compatible
) == 0)
782 return (root
); /* found a match */
784 nbytes
= strlen(compatible_array
) + 1;
785 compatible_array
+= nbytes
;
789 node
= dev_find_node_by_compatible(root
->child
, compatible
);
794 * Note the very deliberate use of tail recursion here. A good
795 * compiler (such as Sun's) will recognize this and generate code
796 * that does not allocate another stack frame. Instead, it will
797 * overlay the existing stack frame with the new one, the only change
798 * having been to replace the original root with its sibling.
799 * This has the potential to create some confusion for anyone
800 * trying to debug this code from a core dump, since the stack
801 * trace will not reveal recursion on siblings, only on children.
804 return (dev_find_node_by_compatible(root
->sibling
, compatible
));
808 * Start from the current node and return the next node besides
809 * the current one which has the requested compatible property.
812 dev_next_node_by_compatible(Prom_node
*root
, char *compatible
)
816 if (root
== NULL
|| compatible
== NULL
)
819 node
= dev_find_node_by_compatible(root
->child
, compatible
);
824 * More tail recursion. Even though it is a different function,
825 * this will overlay the current stack frame. Caveat exterminator.
828 node
= dev_find_node_by_compatible(root
->sibling
, compatible
);
832 return (dev_find_node_by_compatible(root
->parent
->sibling
, compatible
));