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 2000-2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <sys/systeminfo.h>
34 #include <sys/utsname.h>
35 #include <sys/openpromio.h>
36 #include <libdevinfo.h>
39 #include "pdevinfo_sun4u.h"
41 #include "display_sun4u.h"
42 #include "libprtdiag.h"
45 * This file contains the functions that are to be called when
46 * a platform wants to use libdevinfo for it's device information
47 * instead of OBP. This will allow prtdiag to support hot-plug
48 * events on platforms whose OBP doesn't get updated to reflect
49 * the hot-plug changes to the system.
52 int do_devinfo(int syserrlog
, char *pgname
, int log_flag
,
54 static void dump_di_node(Prom_node
*pnode
, di_node_t di_node
);
55 static Prom_node
*walk_di_tree(Sys_tree
*tree
, Prom_node
*root
,
57 static int match_compatible_name(char *, int, char *);
62 di_prom_handle_t ph
; /* Handle for using di_prom interface */
63 extern char *progname
;
68 * Used instead of the walk() function when a platform wants to
69 * walk libdevinfo's device tree instead of walking OBP's
73 walk_di_tree(Sys_tree
*tree
, Prom_node
*root
, di_node_t di_node
)
77 char *name
, *type
, *model
, *compatible_array
;
81 int is_schizo
= 0, n_names
;
83 /* allocate a node for this level */
84 if ((pnode
= (Prom_node
*) malloc(sizeof (struct prom_node
))) ==
90 /* assign parent Prom_node */
92 pnode
->sibling
= NULL
;
95 /* read properties for this node */
96 dump_di_node(pnode
, di_node
);
98 name
= get_node_name(pnode
);
99 type
= get_node_type(pnode
);
102 model
= (char *)get_prop_val(find_prop(pnode
, "model"));
107 * For identifying Schizo nodes we need to check if the
108 * compatible property contains the string 'pci108e,8001'.
109 * This property contains an array of strings so we need
110 * search all strings.
112 if ((n_names
= di_compatible_names(di_node
, &compatible_array
)) > 0) {
113 if (match_compatible_name(compatible_array
, n_names
,
118 if (int_val
= (int *)get_prop_val(find_prop(pnode
, "portid")))
120 else if ((strcmp(type
, "cpu") == 0) &&
121 (int_val
= (int *)get_prop_val(find_prop(pnode
->parent
, "portid"))))
128 printf("name=%s\n", name
);
130 printf("type=%s\n", type
);
132 printf("model=%s\n", model
);
133 printf("portid=%d\n", portid
);
137 if (has_board_num(pnode
)) {
138 add_node(tree
, pnode
);
140 D_PRINTF("\n---\nnodename = %s [ %s ] \n",
141 di_node_name(di_node
), di_devfs_path(di_node
));
142 D_PRINTF("ADDED BOARD name=%s type=%s model=%s "
143 "portid =%d\n", name
, type
, model
, portid
);
144 } else if ((strcmp(name
, FFB_NAME
) == 0) ||
145 (strcmp(type
, "cpu") == 0) ||
147 ((strcmp(type
, "memory-controller") == 0) &&
148 (strcmp(name
, "ac") != 0)) ||
150 ((strcmp(name
, "pci") == 0) &&
151 (strcmp(model
, "SUNW,psycho") == 0)) ||
153 ((strcmp(name
, "pci") == 0) &&
154 (strcmp(model
, "SUNW,sabre") == 0)) ||
156 ((strcmp(name
, "pci") == 0) && (is_schizo
)) ||
158 (strcmp(name
, "counter-timer") == 0) ||
159 (strcmp(name
, "sbus") == 0)) {
160 add_node(tree
, pnode
);
162 D_PRINTF("\n---\nnodename = %s [ %s ] \n",
163 di_node_name(di_node
), di_devfs_path(di_node
));
164 D_PRINTF("ADDED BOARD name=%s type=%s model=%s\n",
168 D_PRINTF("node not added: type=%s portid =%d\n", type
, portid
);
171 if (curnode
= di_child_node(di_node
)) {
172 pnode
->child
= walk_di_tree(tree
, pnode
, curnode
);
175 if (curnode
= di_sibling_node(di_node
)) {
177 return (walk_di_tree(tree
, root
, curnode
));
179 pnode
->sibling
= walk_di_tree(tree
, root
, curnode
);
184 * This check is needed in case the "board node" occurs at the
185 * end of the sibling chain as opposed to the middle or front.
194 * Dump all the devinfo properties and then the obp properties for
195 * the specified devinfo node into the Prom_node structure.
198 dump_di_node(Prom_node
*pnode
, di_node_t di_node
)
200 Prop
*prop
= NULL
; /* tail of properties list */
202 Prop
*temp
; /* newly allocated property */
204 di_prom_prop_t p_prop
;
208 /* clear out pointers in pnode */
211 D_PRINTF("\n\n ------- Dumping devinfo properties for node ------\n");
214 * get all the devinfo properties first
216 for (di_prop
= di_prop_next(di_node
, DI_PROP_NIL
);
217 di_prop
!= DI_PROP_NIL
;
218 di_prop
= di_prop_next(di_node
, di_prop
)) {
224 di_name
= di_prop_name(di_prop
);
228 di_ptype
= di_prop_type(di_prop
);
229 D_PRINTF("DEVINFO Properties %s: ", di_name
);
234 case DI_PROP_TYPE_INT
:
235 retval
= di_prop_lookup_ints(DDI_DEV_T_ANY
,
236 di_node
, di_name
, (int **)&di_data
);
238 int_val
= (int *)di_data
;
239 D_PRINTF("0x%x\n", *int_val
);
242 case DI_PROP_TYPE_STRING
:
243 retval
= di_prop_lookup_strings(DDI_DEV_T_ANY
,
244 di_node
, di_name
, (char **)&di_data
);
246 char_val
= (char *)di_data
;
247 D_PRINTF("%s\n", char_val
);
250 case DI_PROP_TYPE_BYTE
:
251 retval
= di_prop_lookup_bytes(DDI_DEV_T_ANY
,
252 di_node
, di_name
, (uchar_t
**)&di_data
);
254 char_val
= (char *)di_data
;
255 D_PRINTF("%s\n", char_val
);
258 case DI_PROP_TYPE_UNKNOWN
:
259 retval
= di_prop_lookup_bytes(DDI_DEV_T_ANY
,
260 di_node
, di_name
, (uchar_t
**)&di_data
);
262 char_val
= (char *)di_data
;
263 D_PRINTF("%s\n", char_val
);
266 case DI_PROP_TYPE_BOOLEAN
:
271 D_PRINTF(" Skipping property\n");
278 /* allocate space for the property */
279 if ((temp
= (Prop
*) malloc(sizeof (Prop
))) == NULL
) {
285 * Given that we're using libdevinfo rather than OBP,
286 * the chances are that future accesses to di_name and
287 * di_data will be via temp->name.val_ptr and
288 * temp->value.val_ptr respectively. However, this may
289 * not be the case, so we have to suitably fill in
290 * temp->name.opp and temp->value.opp.
292 * di_name is char * and non-NULL if we've made it to
293 * here, so we can simply point
294 * temp->name.opp.oprom_array to temp->name.val_ptr.
296 * di_data could be NULL, char * or int * at this point.
297 * If it's non-NULL, a 1st char of '\0' indicates int *.
298 * We thus set temp->value.opp.oprom_node[] (although
299 * interest in any element other than 0 is rare, all
300 * elements must be set to ensure compatibility with
301 * OBP), and holds_array is set to 0.
303 * If di_data is NULL, or the 1st char is not '\0', we set
304 * temp->value.opp.oprom_array. If di_ptype is
305 * DI_PROP_TYPE_BOOLEAN, holds_array is set to 0, else it
308 temp
->name
.val_ptr
= (void *)di_name
;
309 temp
->name
.opp
.oprom_array
= temp
->name
.val_ptr
;
310 temp
->name
.opp
.holds_array
= 1;
312 temp
->value
.val_ptr
= (void *)di_data
;
313 if ((di_data
!= NULL
) && (*((char *)di_data
) == '\0')) {
314 for (i
= 0; i
< OPROM_NODE_SIZE
; i
++)
315 temp
->value
.opp
.oprom_node
[i
] = *((int *)di_data
+i
);
317 temp
->value
.opp
.holds_array
= 0;
319 temp
->value
.opp
.oprom_array
= temp
->value
.val_ptr
;
320 if (di_ptype
== DI_PROP_TYPE_BOOLEAN
)
321 temp
->value
.opp
.holds_array
= 0;
323 temp
->value
.opp
.holds_array
= 1;
328 /* everything worked so link the property list */
329 if (pnode
->props
== NULL
)
331 else if (prop
!= NULL
)
338 * Then get all the OBP properties.
340 for (p_prop
= di_prom_prop_next(ph
, di_node
, DI_PROM_PROP_NIL
);
341 p_prop
!= DI_PROM_PROP_NIL
;
342 p_prop
= di_prom_prop_next(ph
, di_node
, p_prop
)) {
345 unsigned char *p_data
;
347 p_name
= di_prom_prop_name(p_prop
);
351 retval
= di_prom_prop_data(p_prop
, &p_data
);
356 /* allocate space for the property */
357 if ((temp
= (Prop
*) malloc(sizeof (Prop
))) == NULL
) {
363 * As above, p_name is char * and non-NULL if we've made
364 * it to here, so we can simply point
365 * temp->name.opp.oprom_array to temp->name.val_ptr.
367 * p_data could be NULL, a character or a number at this
368 * point. If it's non-NULL, a 1st char of '\0' indicates a
369 * number, so we set temp->value.opp.oprom_node[] (again
370 * setting every element to ensure OBP compatibility).
371 * These assignments create a lint error, hence the LINTED
374 * If p_data is NULL, or the 1st char is not '\0', we set
375 * temp->value.opp.oprom_array.
377 temp
->name
.val_ptr
= (void *)p_name
;
378 temp
->name
.opp
.oprom_array
= temp
->name
.val_ptr
;
379 temp
->name
.opp
.holds_array
= 1;
381 temp
->value
.val_ptr
= (void *)p_data
;
382 if ((p_data
!= NULL
) && (*p_data
== '\0')) {
383 for (i
= 0; i
< OPROM_NODE_SIZE
; i
++)
385 temp
->value
.opp
.oprom_node
[i
] = *((int *)p_data
+i
);
387 temp
->value
.opp
.holds_array
= 0;
389 temp
->value
.opp
.oprom_array
= temp
->value
.val_ptr
;
390 temp
->value
.opp
.holds_array
= 1;
395 /* everything worked so link the property list */
396 if (pnode
->props
== NULL
) {
398 } else if (prop
!= NULL
) {
407 * Used in place of do_prominfo() when a platform wants to use
408 * libdevinfo for getting the device tree instead of OBP.
411 do_devinfo(int syserrlog
, char *pgname
, int log_flag
, int prt_flag
)
413 Sys_tree sys_tree
; /* system information */
414 Prom_node
*root_node
; /* root node of OBP device tree */
415 di_node_t di_root_node
; /* root of the devinfo tree */
416 struct system_kstat_data sys_kstat
; /* kstats for non-OBP data */
419 /* set the global flags */
422 print_flag
= prt_flag
;
424 /* set the the system tree fields */
425 sys_tree
.sys_mem
= NULL
;
426 sys_tree
.boards
= NULL
;
427 sys_tree
.bd_list
= NULL
;
428 sys_tree
.board_cnt
= 0;
431 * create a snapshot of the kernel device tree
432 * and return a handle to it.
434 if ((di_root_node
= di_init("/", DINFOCPYALL
)) == DI_NODE_NIL
) {
435 exit(_error("di_init() failed"));
439 * create a handle to the PROM device tree.
441 if ((ph
= di_prom_init()) == NULL
) {
442 exit(_error("di_prom_init() failed"));
446 * walk the devinfo tree and build up a list of all
447 * nodes and properties.
449 root_node
= walk_di_tree(&sys_tree
, NULL
, di_root_node
);
451 /* resolve the board types now */
452 resolve_board_types(&sys_tree
);
454 read_sun4u_kstats(&sys_tree
, &sys_kstat
);
455 retval
= display(&sys_tree
, root_node
, &sys_kstat
, syserrlog
);
457 di_fini(di_root_node
);
463 * check to see if the name shows up in the compatible array
466 match_compatible_name(char *compatible_array
, int n_names
, char *name
)
470 /* parse the compatible list */
471 for (i
= 0; i
< n_names
; i
++) {
472 if (strcmp(compatible_array
, name
) == 0) {
476 compatible_array
+= strlen(compatible_array
) + 1;