4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
30 * For machines that support the openprom, fetch and print the list
31 * of devices that the kernel has fetched from the prom or conjured up.
42 #include <sys/types.h>
43 #include <sys/mkdev.h>
44 #include <sys/sunddi.h>
45 #include <sys/openpromio.h>
46 #include <sys/modctl.h>
49 #include <libnvpair.h>
54 typedef char *(*dump_propname_t
)(void *);
55 typedef int (*dump_proptype_t
)(void *);
56 typedef int (*dump_propints_t
)(void *, int **);
57 typedef int (*dump_propint64_t
)(void *, int64_t **);
58 typedef int (*dump_propstrings_t
)(void *, char **);
59 typedef int (*dump_propbytes_t
)(void *, uchar_t
**);
60 typedef int (*dump_proprawdata_t
)(void *, uchar_t
**);
62 typedef struct dumpops_common
{
63 dump_propname_t doc_propname
;
64 dump_proptype_t doc_proptype
;
65 dump_propints_t doc_propints
;
66 dump_propint64_t doc_propint64
;
67 dump_propstrings_t doc_propstrings
;
68 dump_propbytes_t doc_propbytes
;
69 dump_proprawdata_t doc_proprawdata
;
72 static const dumpops_common_t prop_dumpops
= {
73 (dump_propname_t
)di_prop_name
,
74 (dump_proptype_t
)di_prop_type
,
75 (dump_propints_t
)di_prop_ints
,
76 (dump_propint64_t
)di_prop_int64
,
77 (dump_propstrings_t
)di_prop_strings
,
78 (dump_propbytes_t
)di_prop_bytes
,
79 (dump_proprawdata_t
)di_prop_rawdata
80 }, pathprop_common_dumpops
= {
81 (dump_propname_t
)di_path_prop_name
,
82 (dump_proptype_t
)di_path_prop_type
,
83 (dump_propints_t
)di_path_prop_ints
,
84 (dump_propint64_t
)di_path_prop_int64s
,
85 (dump_propstrings_t
)di_path_prop_strings
,
86 (dump_propbytes_t
)di_path_prop_bytes
,
87 (dump_proprawdata_t
)di_path_prop_bytes
90 typedef void *(*dump_nextprop_t
)(void *, void *);
91 typedef dev_t (*dump_propdevt_t
)(void *);
93 typedef struct dumpops
{
94 const dumpops_common_t
*dop_common
;
95 dump_nextprop_t dop_nextprop
;
96 dump_propdevt_t dop_propdevt
;
99 typedef struct di_args
{
100 di_prom_handle_t prom_hdl
;
101 di_devlink_handle_t devlink_hdl
;
102 pcidb_hdl_t
*pcidb_hdl
;
105 static const dumpops_t sysprop_dumpops
= {
107 (dump_nextprop_t
)di_prop_sys_next
,
109 }, globprop_dumpops
= {
111 (dump_nextprop_t
)di_prop_global_next
,
113 }, drvprop_dumpops
= {
115 (dump_nextprop_t
)di_prop_drv_next
,
116 (dump_propdevt_t
)di_prop_devt
117 }, hwprop_dumpops
= {
119 (dump_nextprop_t
)di_prop_hw_next
,
121 }, pathprop_dumpops
= {
122 &pathprop_common_dumpops
,
123 (dump_nextprop_t
)di_path_prop_next
,
127 #define PROPNAME(ops) (ops->dop_common->doc_propname)
128 #define PROPTYPE(ops) (ops->dop_common->doc_proptype)
129 #define PROPINTS(ops) (ops->dop_common->doc_propints)
130 #define PROPINT64(ops) (ops->dop_common->doc_propint64)
131 #define PROPSTRINGS(ops) (ops->dop_common->doc_propstrings)
132 #define PROPBYTES(ops) (ops->dop_common->doc_propbytes)
133 #define PROPRAWDATA(ops) (ops->dop_common->doc_proprawdata)
134 #define NEXTPROP(ops) (ops->dop_nextprop)
135 #define PROPDEVT(ops) (ops->dop_propdevt)
136 #define NUM_ELEMENTS(A) (sizeof (A) / sizeof (A[0]))
138 static int prop_type_guess(const dumpops_t
*, void *, void **, int *);
139 static void walk_driver(di_node_t
, di_arg_t
*);
140 static int dump_devs(di_node_t
, void *);
141 static int dump_prop_list(const dumpops_t
*, const char *,
142 int, void *, dev_t
, int *);
143 static int _error(const char *, ...);
144 static int is_openprom();
145 static void walk(uchar_t
*, uint_t
, int);
146 static void dump_node(nvlist_t
*, int);
147 static void dump_prodinfo(di_prom_handle_t
, di_node_t
, const char **,
149 static di_node_t
find_node_by_name(di_prom_handle_t
, di_node_t
, char *);
150 static int get_propval_by_name(di_prom_handle_t
, di_node_t
,
151 const char *, uchar_t
**);
152 static int dump_compatible(char *, int, di_node_t
);
153 static void dump_pathing_data(int, di_node_t
);
154 static void dump_minor_data(int, di_node_t
, di_devlink_handle_t
);
155 static void dump_link_data(int, di_node_t
, di_devlink_handle_t
);
156 static int print_composite_string(const char *, char *, int);
157 static void print_one(nvpair_t
*, int);
158 static int unprintable(char *, int);
159 static int promopen(int);
160 static void promclose();
161 static di_node_t
find_target_node(di_node_t
);
162 static void node_display_set(di_node_t
);
163 static int dump_pciid(char *, int, di_node_t
, pcidb_hdl_t
*);
166 prtconf_devinfo(void)
168 struct di_priv_data fetch
;
170 di_prom_handle_t prom_hdl
= DI_PROM_HANDLE_NIL
;
171 di_devlink_handle_t devlink_hdl
= NULL
;
172 pcidb_hdl_t
*pcidb_hdl
= NULL
;
177 dprintf("verbosemode %s\n", opts
.o_verbose
? "on" : "off");
179 /* determine what info we need to get from kernel */
184 flag
|= (DINFOMINOR
| DINFOPATH
);
189 if ((prom_hdl
= di_prom_init()) == DI_PROM_HANDLE_NIL
)
190 exit(_error("di_prom_init() failed."));
193 if (opts
.o_forcecache
) {
194 if (dbg
.d_forceload
) {
195 exit(_error(NULL
, "option combination not supported"));
197 if (strcmp(rootpath
, "/") != 0) {
198 exit(_error(NULL
, "invalid root path for option"));
201 } else if (opts
.o_verbose
) {
202 flag
|= (DINFOPROP
| DINFOMINOR
|
203 DINFOPRIVDATA
| DINFOPATH
| DINFOLYR
);
206 if (dbg
.d_forceload
) {
210 if (opts
.o_verbose
) {
211 init_priv_data(&fetch
);
212 root_node
= di_init_impl(rootpath
, flag
, &fetch
);
214 /* get devlink (aka aliases) data */
215 if ((devlink_hdl
= di_devlink_init(NULL
, 0)) == NULL
)
216 exit(_error("di_devlink_init() failed."));
218 root_node
= di_init(rootpath
, flag
);
220 if (root_node
== DI_NODE_NIL
) {
221 (void) _error(NULL
, "devinfo facility not available");
222 /* not an error if this isn't the global zone */
223 if (getzoneid() == GLOBAL_ZONEID
)
229 if (opts
.o_verbose
|| opts
.o_pciid
) {
230 pcidb_hdl
= pcidb_open(PCIDB_VERSION
);
231 if (pcidb_hdl
== NULL
)
232 (void) _error(NULL
, "pcidb facility not available, "
233 "continuing anyways");
236 di_arg
.prom_hdl
= prom_hdl
;
237 di_arg
.devlink_hdl
= devlink_hdl
;
238 di_arg
.pcidb_hdl
= pcidb_hdl
;
241 * ...and walk all nodes to report them out...
243 if (dbg
.d_bydriver
) {
245 walk_driver(root_node
, &di_arg
);
246 if (prom_hdl
!= DI_PROM_HANDLE_NIL
)
247 di_prom_fini(prom_hdl
);
248 if (devlink_hdl
!= NULL
)
249 (void) di_devlink_fini(&devlink_hdl
);
255 di_node_t target_node
, node
;
257 target_node
= find_target_node(root_node
);
258 if (target_node
== DI_NODE_NIL
) {
259 (void) fprintf(stderr
, "%s: "
260 "invalid device path specified\n",
265 /* mark the target node so we display it */
266 node_display_set(target_node
);
268 if (opts
.o_ancestors
) {
270 * mark the ancestors of this node so we display
274 while (node
= di_parent_node(node
))
275 node_display_set(node
);
278 * when we display device tree nodes the indentation
279 * level is based off of tree depth.
281 * here we increment o_target to reflect the
282 * depth of the target node in the tree. we do
283 * this so that when we calculate the indentation
284 * level we can subtract o_target so that the
285 * target node starts with an indentation of zero.
288 while (node
= di_parent_node(node
))
292 if (opts
.o_children
) {
294 * mark the children of this node so we display
297 (void) di_walk_node(target_node
, DI_WALK_CLDFIRST
,
299 (int (*)(di_node_t
, void *))
304 (void) di_walk_node(root_node
, DI_WALK_CLDFIRST
, &di_arg
,
307 if (prom_hdl
!= DI_PROM_HANDLE_NIL
)
308 di_prom_fini(prom_hdl
);
309 if (devlink_hdl
!= NULL
)
310 (void) di_devlink_fini(&devlink_hdl
);
311 if (pcidb_hdl
!= NULL
)
312 pcidb_close(pcidb_hdl
);
320 i_find_target_node(di_node_t node
, void *arg
)
322 di_node_t
*target
= (di_node_t
*)arg
;
324 if (opts
.o_devices_path
!= NULL
) {
327 if ((path
= di_devfs_path(node
)) == NULL
)
328 exit(_error("failed to allocate memory"));
330 if (strcmp(opts
.o_devices_path
, path
) == 0) {
331 di_devfs_path_free(path
);
333 return (DI_WALK_TERMINATE
);
336 di_devfs_path_free(path
);
337 } else if (opts
.o_devt
!= DDI_DEV_T_NONE
) {
338 di_minor_t minor
= DI_MINOR_NIL
;
340 while ((minor
= di_minor_next(node
, minor
)) != DI_MINOR_NIL
) {
341 if (opts
.o_devt
== di_minor_devt(minor
)) {
343 return (DI_WALK_TERMINATE
);
347 /* we should never get here */
348 exit(_error(NULL
, "internal error"));
350 return (DI_WALK_CONTINUE
);
354 find_target_node(di_node_t root_node
)
356 di_node_t target
= DI_NODE_NIL
;
358 /* special case to allow displaying of the root node */
359 if (opts
.o_devices_path
!= NULL
) {
360 if (strlen(opts
.o_devices_path
) == 0)
362 if (strcmp(opts
.o_devices_path
, ".") == 0)
366 (void) di_walk_node(root_node
, DI_WALK_CLDFIRST
, &target
,
371 #define NODE_DISPLAY (1<<0)
374 node_display(di_node_t node
)
376 long data
= (long)di_node_private_get(node
);
377 return (data
& NODE_DISPLAY
);
381 node_display_set(di_node_t node
)
383 long data
= (long)di_node_private_get(node
);
384 data
|= NODE_DISPLAY
;
385 di_node_private_set(node
, (void *)data
);
388 #define LNODE_DISPLAYED (1<<0)
391 lnode_displayed(di_lnode_t lnode
)
393 long data
= (long)di_lnode_private_get(lnode
);
394 return (data
& LNODE_DISPLAYED
);
398 lnode_displayed_set(di_lnode_t lnode
)
400 long data
= (long)di_lnode_private_get(lnode
);
401 data
|= LNODE_DISPLAYED
;
402 di_lnode_private_set(lnode
, (void *)data
);
406 lnode_displayed_clear(di_lnode_t lnode
)
408 long data
= (long)di_lnode_private_get(lnode
);
409 data
&= ~LNODE_DISPLAYED
;
410 di_lnode_private_set(lnode
, (void *)data
);
413 #define MINOR_DISPLAYED (1<<0)
414 #define MINOR_PTR (~(0x3))
417 minor_displayed(di_minor_t minor
)
419 long data
= (long)di_minor_private_get(minor
);
420 return (data
& MINOR_DISPLAYED
);
424 minor_displayed_set(di_minor_t minor
)
426 long data
= (long)di_minor_private_get(minor
);
427 data
|= MINOR_DISPLAYED
;
428 di_minor_private_set(minor
, (void *)data
);
432 minor_displayed_clear(di_minor_t minor
)
434 long data
= (long)di_minor_private_get(minor
);
435 data
&= ~MINOR_DISPLAYED
;
436 di_minor_private_set(minor
, (void *)data
);
440 minor_ptr(di_minor_t minor
)
442 long data
= (long)di_minor_private_get(minor
);
443 return ((void *)(data
& MINOR_PTR
));
447 minor_ptr_set(di_minor_t minor
, void *ptr
)
449 long data
= (long)di_minor_private_get(minor
);
450 data
= (data
& ~MINOR_PTR
) | (((long)ptr
) & MINOR_PTR
);
451 di_minor_private_set(minor
, (void *)data
);
455 * In this comment typed properties are those of type DI_PROP_TYPE_UNDEF_IT,
456 * DI_PROP_TYPE_BOOLEAN, DI_PROP_TYPE_INT, DI_PROP_TYPE_INT64,
457 * DI_PROP_TYPE_BYTE, and DI_PROP_TYPE_STRING.
459 * The guessing algorithm is:
460 * 1. If the property is typed and the type is consistent with the value of
461 * the property, then the property is of that type. If the type is not
462 * consistent with value of the property, then the type is treated as
464 * 2. If the property is of type DI_PROP_TYPE_UNKNOWN the following steps
466 * a. If the value of the property is consistent with a string property,
467 * the type of the property is DI_PROP_TYPE_STRING.
468 * b. Otherwise, if the value of the property is consistent with an integer
469 * property, the type of the property is DI_PROP_TYPE_INT.
470 * c. Otherwise, the property type is treated as alien to prtconf.
471 * 3. If the property type is alien to prtconf, then the property value is
472 * read by the appropriate routine for untyped properties and the following
473 * steps are carried out.
474 * a. If the length that the property routine returned is zero, the
475 * property is of type DI_PROP_TYPE_BOOLEAN.
476 * b. Otherwise, if the length that the property routine returned is
477 * positive, then the property value is treated as raw data of type
478 * DI_PROP_TYPE_UNKNOWN.
479 * c. Otherwise, if the length that the property routine returned is
480 * negative, then there is some internal inconsistency and this is
481 * treated as an error and no type is determined.
484 prop_type_guess(const dumpops_t
*propops
, void *prop
, void **prop_data
,
489 type
= PROPTYPE(propops
)(prop
);
491 case DI_PROP_TYPE_UNDEF_IT
:
492 case DI_PROP_TYPE_BOOLEAN
:
496 case DI_PROP_TYPE_INT
:
497 len
= PROPINTS(propops
)(prop
, (int **)prop_data
);
499 case DI_PROP_TYPE_INT64
:
500 len
= PROPINT64(propops
)(prop
, (int64_t **)prop_data
);
502 case DI_PROP_TYPE_BYTE
:
503 len
= PROPBYTES(propops
)(prop
, (uchar_t
**)prop_data
);
505 case DI_PROP_TYPE_STRING
:
506 len
= PROPSTRINGS(propops
)(prop
, (char **)prop_data
);
508 case DI_PROP_TYPE_UNKNOWN
:
509 len
= PROPSTRINGS(propops
)(prop
, (char **)prop_data
);
510 if ((len
> 0) && ((*(char **)prop_data
)[0] != 0)) {
511 *prop_type
= DI_PROP_TYPE_STRING
;
515 len
= PROPINTS(propops
)(prop
, (int **)prop_data
);
516 type
= DI_PROP_TYPE_INT
;
528 len
= PROPRAWDATA(propops
)(prop
, (uchar_t
**)prop_data
);
531 } else if (len
== 0) {
532 *prop_type
= DI_PROP_TYPE_BOOLEAN
;
536 *prop_type
= DI_PROP_TYPE_UNKNOWN
;
541 * Returns 0 if nothing is printed, 1 otherwise
544 dump_prop_list(const dumpops_t
*dumpops
, const char *name
, int ilev
,
545 void *node
, dev_t dev
, int *compat_printed
)
547 void *prop
= DI_PROP_NIL
, *prop_data
;
550 int i
, prop_type
, nitems
;
557 while ((prop
= NEXTPROP(dumpops
)(node
, prop
)) != DI_PROP_NIL
) {
559 /* Skip properties a dev_t oriented caller is not requesting */
560 if (PROPDEVT(dumpops
)) {
561 pdev
= PROPDEVT(dumpops
)(prop
);
563 if (dev
== DDI_DEV_T_ANY
) {
565 * Caller requesting print all properties
568 } else if (dev
== DDI_DEV_T_NONE
) {
570 * Caller requesting print of properties
571 * associated with devinfo (not minor).
573 if ((pdev
== DDI_DEV_T_ANY
) ||
574 (pdev
== DDI_DEV_T_NONE
))
578 * Property has a minor association, see if
579 * we have a minor with this dev_t. If there
580 * is no such minor we print the property now
581 * so it gets displayed.
583 minor
= DI_MINOR_NIL
;
584 while ((minor
= di_minor_next((di_node_t
)node
,
585 minor
)) != DI_MINOR_NIL
) {
586 if (di_minor_devt(minor
) == pdev
)
589 if (minor
== DI_MINOR_NIL
)
591 } else if (dev
== pdev
) {
593 * Caller requesting print of properties
594 * associated with a specific matching minor
600 /* otherwise skip print */
604 print
: nitems
= prop_type_guess(dumpops
, prop
, &prop_data
, &prop_type
);
610 indent_to_level(ilev
);
611 (void) printf("%s properties:\n", name
);
617 indent_to_level(ilev
);
618 (void) printf("name='%s' type=", PROPNAME(dumpops
)(prop
));
620 /* report 'compatible' as processed */
621 if (compat_printed
&&
622 (strcmp(PROPNAME(dumpops
)(prop
), "compatible") == 0))
626 case DI_PROP_TYPE_UNDEF_IT
:
627 (void) printf("undef");
629 case DI_PROP_TYPE_BOOLEAN
:
630 (void) printf("boolean");
632 case DI_PROP_TYPE_INT
:
633 (void) printf("int");
635 case DI_PROP_TYPE_INT64
:
636 (void) printf("int64");
638 case DI_PROP_TYPE_BYTE
:
639 (void) printf("byte");
641 case DI_PROP_TYPE_STRING
:
642 (void) printf("string");
644 case DI_PROP_TYPE_UNKNOWN
:
645 (void) printf("unknown");
648 /* Should never be here */
649 (void) printf("0x%x", prop_type
);
653 (void) printf(" items=%i", nitems
);
655 /* print the major and minor numbers for a device property */
656 if (PROPDEVT(dumpops
)) {
657 if ((pdev
== DDI_DEV_T_NONE
) ||
658 (pdev
== DDI_DEV_T_ANY
)) {
659 (void) printf(" dev=none");
661 (void) printf(" dev=(%u,%u)",
662 (uint_t
)major(pdev
), (uint_t
)minor(pdev
));
666 (void) putchar('\n');
671 indent_to_level(ilev
);
673 (void) printf(" value=");
676 case DI_PROP_TYPE_INT
:
677 for (i
= 0; i
< nitems
- 1; i
++)
678 (void) printf("%8.8x.", ((int *)prop_data
)[i
]);
679 (void) printf("%8.8x", ((int *)prop_data
)[i
]);
681 case DI_PROP_TYPE_INT64
:
682 for (i
= 0; i
< nitems
- 1; i
++)
683 (void) printf("%16.16llx.",
684 ((long long *)prop_data
)[i
]);
685 (void) printf("%16.16llx", ((long long *)prop_data
)[i
]);
687 case DI_PROP_TYPE_STRING
:
688 p
= (char *)prop_data
;
689 for (i
= 0; i
< nitems
- 1; i
++) {
690 (void) printf("'%s' + ", p
);
693 (void) printf("'%s'", p
);
696 for (i
= 0; i
< nitems
- 1; i
++)
697 (void) printf("%2.2x.",
698 ((uint8_t *)prop_data
)[i
]);
699 (void) printf("%2.2x", ((uint8_t *)prop_data
)[i
]);
702 (void) putchar('\n');
705 return (nprop
? 1 : 0);
709 * walk_driver is a debugging facility.
712 walk_driver(di_node_t root
, di_arg_t
*di_arg
)
716 node
= di_drv_first_node(dbg
.d_drivername
, root
);
718 while (node
!= DI_NODE_NIL
) {
719 (void) dump_devs(node
, di_arg
);
720 node
= di_drv_next_node(node
);
725 * print out information about this node, returns appropriate code.
729 dump_devs(di_node_t node
, void *arg
)
731 di_arg_t
*di_arg
= arg
;
732 di_devlink_handle_t devlink_hdl
= di_arg
->devlink_hdl
;
733 int ilev
= 0; /* indentation level */
735 di_node_t root_node
, tmp
;
740 char *path
= di_devfs_path(node
);
741 dprintf("Dump node %s\n", path
);
742 di_devfs_path_free(path
);
745 if (dbg
.d_bydriver
) {
748 /* figure out indentation level */
750 while ((tmp
= di_parent_node(tmp
)) != DI_NODE_NIL
)
753 if (opts
.o_target
&& !opts
.o_ancestors
) {
754 ilev
-= opts
.o_target
- 1;
758 if (opts
.o_target
&& !node_display(node
)) {
760 * if we're only displaying certain nodes and this one
761 * isn't flagged, skip it.
763 return (DI_WALK_CONTINUE
);
766 indent_to_level(ilev
);
768 (void) printf("%s", di_node_name(node
));
770 (void) print_pciid(node
, di_arg
->prom_hdl
, di_arg
->pcidb_hdl
);
773 * if this node does not have an instance number or is the
774 * root node (1229946), we don't print an instance number
776 root_node
= tmp
= node
;
777 while ((tmp
= di_parent_node(tmp
)) != DI_NODE_NIL
)
779 if ((di_instance(node
) >= 0) && (node
!= root_node
))
780 (void) printf(", instance #%d", di_instance(node
));
782 if (opts
.o_drv_name
) {
783 driver_name
= di_driver_name(node
);
784 if (driver_name
!= NULL
)
785 (void) printf(" (driver name: %s)", driver_name
);
786 } else if (di_retired(node
)) {
787 (void) printf(" (retired)");
788 } else if (di_state(node
) & DI_DRIVER_DETACHED
)
789 (void) printf(" (driver not attached)");
792 if (opts
.o_verbose
) {
793 if (dump_prop_list(&sysprop_dumpops
, "System", ilev
+ 1,
794 node
, DDI_DEV_T_ANY
, NULL
)) {
795 (void) dump_prop_list(&globprop_dumpops
, NULL
, ilev
+ 1,
796 node
, DDI_DEV_T_ANY
, NULL
);
798 (void) dump_prop_list(&globprop_dumpops
,
799 "System software", ilev
+ 1,
800 node
, DDI_DEV_T_ANY
, NULL
);
802 (void) dump_prop_list(&drvprop_dumpops
, "Driver", ilev
+ 1,
803 node
, DDI_DEV_T_NONE
, NULL
);
805 printed
= dump_prop_list(&hwprop_dumpops
, "Hardware",
806 ilev
+ 1, node
, DDI_DEV_T_ANY
, &compat_printed
);
808 /* Ensure that 'compatible' is printed under Hardware header */
810 printed
|= dump_compatible(printed
? NULL
: "Hardware",
813 /* Ensure that pci id information is printed under Hardware */
814 (void) dump_pciid(printed
? NULL
: "Hardware",
815 ilev
+ 1, node
, di_arg
->pcidb_hdl
);
817 dump_priv_data(ilev
+ 1, node
);
818 dump_pathing_data(ilev
+ 1, node
);
819 dump_link_data(ilev
+ 1, node
, devlink_hdl
);
820 dump_minor_data(ilev
+ 1, node
, devlink_hdl
);
824 return (DI_WALK_CONTINUE
);
826 if (!opts
.o_pseudodevs
&& (strcmp(di_node_name(node
), "pseudo") == 0))
827 return (DI_WALK_PRUNECHILD
);
829 return (DI_WALK_CONTINUE
);
832 /* _error([no_perror, ] fmt [, arg ...]) */
834 _error(const char *opt_noperror
, ...)
843 (void) fprintf(stderr
, "%s: ", opts
.o_progname
);
845 va_start(ap
, opt_noperror
);
846 if (opt_noperror
== NULL
) {
848 fmt
= va_arg(ap
, char *);
851 (void) vfprintf(stderr
, fmt
, ap
);
855 (void) fprintf(stderr
, "\n");
857 (void) fprintf(stderr
, ": ");
867 * The rest of the routines handle printing the raw prom devinfo (-p option).
869 * 128 is the size of the largest (currently) property name
870 * 16k - MAXNAMESZ - sizeof (int) is the size of the largest
871 * (currently) property value that is allowed.
872 * the sizeof (uint_t) is from struct openpromio
875 #define MAXNAMESZ 128
876 #define MAXVALSIZE (16384 - MAXNAMESZ - sizeof (uint_t))
877 #define BUFSIZE (MAXNAMESZ + MAXVALSIZE + sizeof (uint_t))
880 struct openpromio opp
;
884 static uchar_t
*prom_snapshot
;
890 struct openpromio
*opp
= &(oppbuf
.opp
);
893 opp
->oprom_size
= MAXVALSIZE
;
894 if (ioctl(prom_fd
, OPROMGETCONS
, opp
) < 0)
895 exit(_error("OPROMGETCONS"));
897 i
= (unsigned int)((unsigned char)opp
->oprom_array
[0]);
898 return ((i
& OPROMCONS_OPENPROM
) == OPROMCONS_OPENPROM
);
904 uint_t arg
= opts
.o_verbose
;
906 if (promopen(O_RDONLY
)) {
907 exit(_error("openeepr device open failed"));
910 if (is_openprom() == 0) {
911 (void) fprintf(stderr
, "System architecture does not "
912 "support this option of this command.\n");
916 /* OPROMSNAPSHOT returns size in arg */
917 if (ioctl(prom_fd
, OPROMSNAPSHOT
, &arg
) < 0)
918 exit(_error("OPROMSNAPSHOT"));
923 if ((prom_snapshot
= malloc(arg
)) == NULL
)
924 exit(_error("failed to allocate memory"));
926 /* copy out the snapshot for printing */
928 *(uint_t
*)prom_snapshot
= arg
;
929 if (ioctl(prom_fd
, OPROMCOPYOUT
, prom_snapshot
) < 0)
930 exit(_error("OPROMCOPYOUT"));
934 /* print out information */
935 walk(prom_snapshot
, arg
, 0);
942 walk(uchar_t
*buf
, uint_t size
, int level
)
945 nvlist_t
*nvl
, *cnvl
;
946 nvpair_t
*child
= NULL
;
947 uchar_t
*cbuf
= NULL
;
950 /* Expand to an nvlist */
951 if (nvlist_unpack((char *)buf
, size
, &nvl
, 0))
952 exit(_error("error processing snapshot"));
954 /* print current node */
955 dump_node(nvl
, level
);
958 error
= nvlist_lookup_byte_array(nvl
, "@child", &cbuf
, &csize
);
959 if ((error
== ENOENT
) || (cbuf
== NULL
))
960 return; /* no child exists */
962 if (error
|| nvlist_unpack((char *)cbuf
, csize
, &cnvl
, 0))
963 exit(_error("error processing snapshot"));
965 while (child
= nvlist_next_nvpair(cnvl
, child
)) {
966 char *name
= nvpair_name(child
);
967 data_type_t type
= nvpair_type(child
);
970 if (strcmp("node", name
) != 0) {
971 dprintf("unexpected nvpair name %s != name\n", name
);
974 if (type
!= DATA_TYPE_BYTE_ARRAY
) {
975 dprintf("unexpected nvpair type %d, not byte array \n",
980 (void) nvpair_value_byte_array(child
,
981 (uchar_t
**)&nodebuf
, &nodesize
);
982 walk(nodebuf
, nodesize
, level
+ 1);
989 * Print all properties and values
992 dump_node(nvlist_t
*nvl
, int level
)
996 nvpair_t
*nvp
= NULL
;
998 indent_to_level(level
);
999 (void) printf("Node");
1000 if (!opts
.o_verbose
) {
1001 if (nvlist_lookup_string(nvl
, "name", &name
))
1002 (void) printf("data not available");
1004 (void) printf(" '%s'", name
);
1005 (void) putchar('\n');
1008 (void) nvlist_lookup_int32(nvl
, "@nodeid", &id
);
1009 (void) printf(" %#08x\n", id
);
1011 while (nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
1012 name
= nvpair_name(nvp
);
1016 print_one(nvp
, level
+ 1);
1018 (void) putchar('\n');
1022 path_state_name(di_path_state_t st
)
1025 case DI_PATH_STATE_ONLINE
:
1027 case DI_PATH_STATE_STANDBY
:
1029 case DI_PATH_STATE_OFFLINE
:
1031 case DI_PATH_STATE_FAULT
:
1038 * Print all phci's each client is connected to.
1041 dump_pathing_data(int ilev
, di_node_t node
)
1043 di_path_t pi
= DI_PATH_NIL
;
1044 di_node_t phci_node
;
1049 if (node
== DI_PATH_NIL
)
1052 while ((pi
= di_path_client_next_path(node
, pi
)) != DI_PATH_NIL
) {
1054 /* It is not really a path if we failed to capture the pHCI */
1055 phci_node
= di_path_phci_node(pi
);
1056 if (phci_node
== DI_NODE_NIL
)
1059 /* Print header for the first path */
1061 indent_to_level(ilev
);
1064 (void) printf("Paths from multipath bus adapters:\n");
1068 * Print the path instance and full "pathinfo" path, which is
1069 * the same as the /devices devifo path had the device been
1070 * enumerated under pHCI.
1072 phci_path
= di_devfs_path(phci_node
);
1074 path_instance
= di_path_instance(pi
);
1075 if (path_instance
> 0) {
1076 indent_to_level(ilev
);
1077 (void) printf("Path %d: %s/%s@%s\n",
1078 path_instance
, phci_path
,
1080 di_path_bus_addr(pi
));
1082 di_devfs_path_free(phci_path
);
1085 /* print phci driver, instance, and path state information */
1086 indent_to_level(ilev
);
1087 (void) printf("%s#%d (%s)\n", di_driver_name(phci_node
),
1088 di_instance(phci_node
), path_state_name(di_path_state(pi
)));
1090 (void) dump_prop_list(&pathprop_dumpops
, NULL
, ilev
+ 1,
1091 pi
, DDI_DEV_T_ANY
, NULL
);
1096 dump_minor_data_links(di_devlink_t devlink
, void *arg
)
1098 int ilev
= (intptr_t)arg
;
1099 indent_to_level(ilev
);
1100 (void) printf("dev_link=%s\n", di_devlink_path(devlink
));
1101 return (DI_WALK_CONTINUE
);
1105 dump_minor_data_paths(int ilev
, di_minor_t minor
,
1106 di_devlink_handle_t devlink_hdl
)
1111 /* get the path to the device and the minor node name */
1112 if ((path
= di_devfs_minor_path(minor
)) == NULL
)
1113 exit(_error("failed to allocate memory"));
1115 /* display the path to this minor node */
1116 indent_to_level(ilev
);
1117 (void) printf("dev_path=%s\n", path
);
1119 if (devlink_hdl
!= NULL
) {
1121 /* get the device minor node information */
1122 spec_type
= di_minor_spectype(minor
);
1123 switch (di_minor_type(minor
)) {
1133 case DDM_INTERNAL_PATH
:
1141 /* display the device minor node information */
1142 indent_to_level(ilev
+ 1);
1143 (void) printf("spectype=%s type=%s\n",
1144 (spec_type
== S_IFBLK
) ? "blk" : "chr", type
);
1146 /* display all the devlinks for this device minor node */
1147 (void) di_devlink_walk(devlink_hdl
, NULL
, path
,
1148 0, (void *)(intptr_t)(ilev
+ 1), dump_minor_data_links
);
1151 di_devfs_path_free(path
);
1155 create_minor_list(di_node_t node
)
1157 di_minor_t minor
, minor_head
, minor_tail
, minor_prev
, minor_walk
;
1160 /* if there are no minor nodes, bail */
1161 if (di_minor_next(node
, DI_MINOR_NIL
) == DI_MINOR_NIL
)
1165 * here we want to create lists of minor nodes with the same
1166 * dev_t. to do this we first sort all the minor nodes by devt.
1168 * the algorithm used here is a bubble sort, so performance sucks.
1169 * but it's probably ok here because most device instances don't
1170 * have that many minor nodes. also we're doing this as we're
1171 * displaying each node so it doesn't look like we're pausing
1172 * output for a long time.
1174 major
= di_driver_major(node
);
1175 minor_head
= minor_tail
= minor
= DI_MINOR_NIL
;
1176 while ((minor
= di_minor_next(node
, minor
)) != DI_MINOR_NIL
) {
1177 dev_t dev
= di_minor_devt(minor
);
1179 /* skip /pseudo/clone@0 minor nodes */
1180 if (major
!= major(dev
))
1183 minor_ptr_set(minor
, DI_MINOR_NIL
);
1184 if (minor_head
== DI_MINOR_NIL
) {
1185 /* this is the first minor node we're looking at */
1186 minor_head
= minor_tail
= minor
;
1191 * if the new dev is less than the old dev, update minor_head
1192 * so it points to the beginning of the list. ie it points
1193 * to the node with the lowest dev value
1195 if (dev
<= di_minor_devt(minor_head
)) {
1196 minor_ptr_set(minor
, minor_head
);
1201 minor_prev
= minor_head
;
1202 minor_walk
= minor_ptr(minor_head
);
1203 while ((minor_walk
!= DI_MINOR_NIL
) &&
1204 (dev
> di_minor_devt(minor_walk
))) {
1205 minor_prev
= minor_walk
;
1206 minor_walk
= minor_ptr(minor_walk
);
1208 minor_ptr_set(minor
, minor_walk
);
1209 minor_ptr_set(minor_prev
, minor
);
1210 if (minor_walk
== NULL
)
1214 /* check if there were any non /pseudo/clone@0 nodes. if not, bail */
1215 if (minor_head
== DI_MINOR_NIL
)
1219 * now that we have a list of minor nodes sorted by devt
1220 * we walk through the list and break apart the entire list
1221 * to create circular lists of minor nodes with matching devts.
1223 minor_prev
= minor_head
;
1224 minor_walk
= minor_ptr(minor_head
);
1225 while (minor_walk
!= DI_MINOR_NIL
) {
1226 if (di_minor_devt(minor_prev
) != di_minor_devt(minor_walk
)) {
1227 minor_ptr_set(minor_prev
, minor_head
);
1228 minor_head
= minor_walk
;
1230 minor_prev
= minor_walk
;
1231 minor_walk
= minor_ptr(minor_walk
);
1233 minor_ptr_set(minor_tail
, minor_head
);
1237 link_lnode_disp(di_link_t link
, uint_t endpoint
, int ilev
,
1238 di_devlink_handle_t devlink_hdl
)
1242 int displayed_path
, spec_type
;
1243 di_node_t node
= DI_NODE_NIL
;
1244 dev_t devt
= DDI_DEV_T_NONE
;
1246 lnode
= di_link_to_lnode(link
, endpoint
);
1248 indent_to_level(ilev
);
1249 name
= di_lnode_name(lnode
);
1250 spec_type
= di_link_spectype(link
);
1252 (void) printf("mod=%s", name
);
1255 * if we're displaying the source of a link, we should display
1256 * the target access mode. (either block or char.)
1258 if (endpoint
== DI_LINK_SRC
)
1259 (void) printf(" accesstype=%s",
1260 (spec_type
== S_IFBLK
) ? "blk" : "chr");
1263 * check if the lnode is bound to a specific device
1264 * minor node (i.e. if it's bound to a dev_t) and
1265 * if so display the dev_t value and any possible
1266 * minor node pathing information.
1269 if (di_lnode_devt(lnode
, &devt
) == 0) {
1270 di_minor_t minor
= DI_MINOR_NIL
;
1272 (void) printf(" dev=(%u,%u)\n",
1273 (uint_t
)major(devt
), (uint_t
)minor(devt
));
1275 /* display paths to the src devt minor node */
1276 while (minor
= di_minor_next(node
, minor
)) {
1277 if (devt
!= di_minor_devt(minor
))
1280 if ((endpoint
== DI_LINK_TGT
) &&
1281 (spec_type
!= di_minor_spectype(minor
)))
1284 dump_minor_data_paths(ilev
+ 1, minor
, devlink_hdl
);
1288 (void) printf("\n");
1295 * This device lnode is not did not have any minor node
1296 * pathing information so display the path to device node.
1298 node
= di_lnode_devinfo(lnode
);
1299 if ((path
= di_devfs_path(node
)) == NULL
)
1300 exit(_error("failed to allocate memory"));
1302 indent_to_level(ilev
+ 1);
1303 (void) printf("dev_path=%s\n", path
);
1304 di_devfs_path_free(path
);
1308 dump_minor_link_data(int ilev
, di_node_t node
, dev_t devt
,
1309 di_devlink_handle_t devlink_hdl
)
1315 while (link
= di_link_next_by_node(node
, link
, DI_LINK_TGT
)) {
1316 di_lnode_t tgt_lnode
;
1317 dev_t tgt_devt
= DDI_DEV_T_NONE
;
1319 tgt_lnode
= di_link_to_lnode(link
, DI_LINK_TGT
);
1321 if (di_lnode_devt(tgt_lnode
, &tgt_devt
) != 0)
1324 if (devt
!= tgt_devt
)
1329 indent_to_level(ilev
);
1330 (void) printf("Device Minor Layered Under:\n");
1333 /* displayed this lnode */
1334 lnode_displayed_set(tgt_lnode
);
1335 link_lnode_disp(link
, DI_LINK_SRC
, ilev
+ 1, devlink_hdl
);
1339 while (link
= di_link_next_by_node(node
, link
, DI_LINK_SRC
)) {
1340 di_lnode_t src_lnode
;
1341 dev_t src_devt
= DDI_DEV_T_NONE
;
1343 src_lnode
= di_link_to_lnode(link
, DI_LINK_SRC
);
1345 if (di_lnode_devt(src_lnode
, &src_devt
) != 0)
1348 if (devt
!= src_devt
)
1353 indent_to_level(ilev
);
1354 (void) printf("Device Minor Layered Over:\n");
1357 /* displayed this lnode */
1358 lnode_displayed_set(src_lnode
);
1359 link_lnode_disp(link
, DI_LINK_TGT
, ilev
+ 1, devlink_hdl
);
1364 dump_minor_data(int ilev
, di_node_t node
, di_devlink_handle_t devlink_hdl
)
1366 di_minor_t minor
, minor_next
;
1369 int major
, firstminor
= 1;
1372 * first go through and mark all lnodes and minor nodes for this
1373 * node as undisplayed
1375 lnode
= DI_LNODE_NIL
;
1376 while (lnode
= di_lnode_next(node
, lnode
))
1377 lnode_displayed_clear(lnode
);
1378 minor
= DI_MINOR_NIL
;
1379 while (minor
= di_minor_next(node
, minor
)) {
1380 minor_displayed_clear(minor
);
1384 * when we display the minor nodes we want to coalesce nodes
1385 * that have the same dev_t. we do this by creating circular
1386 * lists of minor nodes with the same devt.
1388 create_minor_list(node
);
1390 /* now we display the driver defined minor nodes */
1391 major
= di_driver_major(node
);
1392 minor
= DI_MINOR_NIL
;
1393 while ((minor
= di_minor_next(node
, minor
)) != DI_MINOR_NIL
) {
1397 * skip /pseudo/clone@0 minor nodes.
1398 * these are only created for DLPIv2 network devices.
1399 * since these minor nodes are associated with a driver
1400 * and are only bound to a device instance after they
1401 * are opened and attached we don't print them out
1404 devt
= di_minor_devt(minor
);
1405 if (major
!= major(devt
))
1408 /* skip nodes that may have already been displayed */
1409 if (minor_displayed(minor
))
1414 indent_to_level(ilev
++);
1415 (void) printf("Device Minor Nodes:\n");
1418 /* display the device minor node information */
1419 indent_to_level(ilev
);
1420 (void) printf("dev=(%u,%u)\n",
1421 (uint_t
)major(devt
), (uint_t
)minor(devt
));
1425 /* display device minor node path info */
1426 minor_displayed_set(minor_next
);
1427 dump_minor_data_paths(ilev
+ 1, minor_next
,
1430 /* get a pointer to the next node */
1431 minor_next
= minor_ptr(minor_next
);
1432 } while (minor_next
!= minor
);
1434 /* display who has this device minor node open */
1435 dump_minor_link_data(ilev
+ 1, node
, devt
, devlink_hdl
);
1437 /* display properties associated with this devt */
1438 (void) dump_prop_list(&drvprop_dumpops
, "Minor",
1439 ilev
+ 1, node
, devt
, NULL
);
1443 * now go through all the target lnodes for this node and
1444 * if they haven't yet been displayed, display them now.
1446 * this happens in the case of clone opens when an "official"
1447 * minor node does not exist for the opened devt
1450 while (link
= di_link_next_by_node(node
, link
, DI_LINK_TGT
)) {
1453 lnode
= di_link_to_lnode(link
, DI_LINK_TGT
);
1455 /* if we've already displayed this target lnode, skip it */
1456 if (lnode_displayed(lnode
))
1461 indent_to_level(ilev
++);
1462 (void) printf("Device Minor Nodes:\n");
1465 /* display the device minor node information */
1466 indent_to_level(ilev
);
1467 (void) di_lnode_devt(lnode
, &devt
);
1468 (void) printf("dev=(%u,%u)\n",
1469 (uint_t
)major(devt
), (uint_t
)minor(devt
));
1471 indent_to_level(ilev
+ 1);
1472 (void) printf("dev_path=<clone>\n");
1474 /* display who has this cloned device minor node open */
1475 dump_minor_link_data(ilev
+ 1, node
, devt
, devlink_hdl
);
1477 /* mark node as displayed */
1478 lnode_displayed_set(lnode
);
1483 dump_link_data(int ilev
, di_node_t node
, di_devlink_handle_t devlink_hdl
)
1489 while (link
= di_link_next_by_node(node
, link
, DI_LINK_SRC
)) {
1490 di_lnode_t src_lnode
;
1491 dev_t src_devt
= DDI_DEV_T_NONE
;
1493 src_lnode
= di_link_to_lnode(link
, DI_LINK_SRC
);
1496 * here we only want to print out layering information
1497 * if we are the source and our source lnode is not
1498 * associated with any particular dev_t. (which means
1499 * we won't display this link while dumping minor node
1502 if (di_lnode_devt(src_lnode
, &src_devt
) != -1)
1507 indent_to_level(ilev
);
1508 (void) printf("Device Layered Over:\n");
1511 /* displayed this lnode */
1512 link_lnode_disp(link
, DI_LINK_TGT
, ilev
+ 1, devlink_hdl
);
1517 * certain 'known' property names may contain 'composite' strings.
1518 * Handle them here, and print them as 'string1' + 'string2' ...
1521 print_composite_string(const char *var
, char *value
, int size
)
1526 if ((strcmp(var
, "version") != 0) &&
1527 (strcmp(var
, "compatible") != 0))
1528 return (0); /* Not a known composite string */
1531 * Verify that each string in the composite string is non-NULL,
1532 * is within the bounds of the property length, and contains
1533 * printable characters or white space. Otherwise let the
1534 * caller deal with it.
1536 for (firstp
= p
= value
; p
< (value
+ size
); p
+= strlen(p
) + 1) {
1538 return (0); /* NULL string */
1539 for (q
= p
; *q
; q
++) {
1540 if (!(isascii(*q
) && (isprint(*q
) || isspace(*q
))))
1541 return (0); /* Not printable or space */
1543 if (q
> (firstp
+ size
))
1544 return (0); /* Out of bounds */
1547 for (firstp
= p
= value
; p
< (value
+ size
); p
+= strlen(p
) + 1) {
1549 (void) printf("'%s'", p
);
1551 (void) printf(" + '%s'", p
);
1553 (void) putchar('\n');
1558 * Print one property and its value. Handle the verbose case.
1561 print_one(nvpair_t
*nvp
, int level
)
1567 char *var
= nvpair_name(nvp
);
1569 indent_to_level(level
);
1570 (void) printf("%s: ", var
);
1572 switch (nvpair_type(nvp
)) {
1573 case DATA_TYPE_BOOLEAN
:
1574 (void) printf(" \n");
1576 case DATA_TYPE_BYTE_ARRAY
:
1577 if (nvpair_value_byte_array(nvp
, (uchar_t
**)&value
,
1579 (void) printf("data not available.\n");
1582 valsize
--; /* take out null added by driver */
1585 * Do not print valsize > MAXVALSIZE, to be compatible
1586 * with old behavior. E.g. intel's eisa-nvram property
1587 * has a size of 65 K.
1589 if (valsize
> MAXVALSIZE
) {
1590 (void) printf(" \n");
1595 (void) printf("data type unexpected.\n");
1600 * Handle printing verbosely
1602 if (print_composite_string(var
, value
, valsize
)) {
1606 if (!unprintable(value
, valsize
)) {
1607 (void) printf(" '%s'\n", value
);
1614 * Due to backwards compatibility constraints x86 int
1615 * properties are not in big-endian (ieee 1275) byte order.
1616 * If we have a property that is a multiple of 4 bytes,
1617 * let's assume it is an array of ints and print the bytes
1618 * in little endian order to make things look nicer for
1621 endswap
= (valsize
% 4) == 0;
1623 for (i
= 0; i
< valsize
; i
++) {
1625 if (i
&& (i
% 4 == 0))
1626 (void) putchar('.');
1628 out
= value
[i
+ (3 - 2 * (i
% 4))] & 0xff;
1630 out
= value
[i
] & 0xff;
1632 (void) printf("%02x", out
);
1634 (void) putchar('\n');
1638 unprintable(char *value
, int size
)
1643 * Is this just a zero?
1645 if (size
== 0 || value
[0] == '\0')
1648 * If any character is unprintable, or if a null appears
1649 * anywhere except at the end of a string, the whole
1650 * property is "unprintable".
1652 for (i
= 0; i
< size
; ++i
) {
1653 if (value
[i
] == '\0')
1654 return (i
!= (size
- 1));
1655 if (!isascii(value
[i
]) || iscntrl(value
[i
]))
1665 if ((prom_fd
= open(opts
.o_promdev
, oflag
)) < 0) {
1666 if (errno
== EAGAIN
) {
1672 if (getzoneid() == GLOBAL_ZONEID
) {
1673 _exit(_error("cannot open %s",
1676 /* not an error if this isn't the global zone */
1677 (void) _error(NULL
, "openprom facility not available");
1687 if (close(prom_fd
) < 0)
1688 exit(_error("close error on %s", opts
.o_promdev
));
1692 * Get and print the name of the frame buffer device.
1698 char fbuf_path
[MAXPATHLEN
];
1700 retval
= modctl(MODGETFBNAME
, (caddr_t
)fbuf_path
);
1703 (void) printf("%s\n", fbuf_path
);
1705 if (retval
== EFAULT
) {
1706 (void) fprintf(stderr
,
1707 "Error copying fb path to userland\n");
1709 (void) fprintf(stderr
,
1710 "Console output device is not a frame buffer\n");
1718 * Get and print the PROM version.
1721 do_promversion(void)
1724 struct openpromio
*opp
= &(oppbuf
.opp
);
1726 if (promopen(O_RDONLY
)) {
1727 (void) fprintf(stderr
, "Cannot open openprom device\n");
1731 opp
->oprom_size
= MAXVALSIZE
;
1732 if (ioctl(prom_fd
, OPROMGETVERSION
, opp
) < 0)
1733 exit(_error("OPROMGETVERSION"));
1735 (void) printf("%s\n", opp
->oprom_array
);
1741 do_prom_version64(void)
1745 struct openpromio
*opp
= &(oppbuf
.opp
);
1747 struct openprom_opr64
*opr
= (struct openprom_opr64
*)opp
->oprom_array
;
1749 static const char msg
[] =
1750 "NOTICE: The firmware on this system does not support the "
1752 "\tPlease upgrade to at least the following version:\n"
1755 if (promopen(O_RDONLY
)) {
1756 (void) fprintf(stderr
, "Cannot open openprom device\n");
1760 opp
->oprom_size
= MAXVALSIZE
;
1761 if (ioctl(prom_fd
, OPROMREADY64
, opp
) < 0)
1762 exit(_error("OPROMREADY64"));
1764 if (opr
->return_code
== 0)
1767 (void) printf(msg
, opr
->message
);
1770 return (opr
->return_code
);
1777 do_productinfo(void)
1779 di_node_t root
, next_node
;
1780 di_prom_handle_t promh
;
1781 static const char *root_prop
[] = { "name", "model", "banner-name",
1783 static const char *root_propv
[] = { "name", "model", "banner-name",
1784 "compatible", "idprom" };
1785 static const char *oprom_prop
[] = { "model", "version" };
1788 root
= di_init("/", DINFOCPYALL
);
1790 if (root
== DI_NODE_NIL
) {
1791 (void) fprintf(stderr
, "di_init() failed\n");
1795 promh
= di_prom_init();
1797 if (promh
== DI_PROM_HANDLE_NIL
) {
1798 (void) fprintf(stderr
, "di_prom_init() failed\n");
1802 if (opts
.o_verbose
) {
1803 dump_prodinfo(promh
, root
, root_propv
, "root",
1804 NUM_ELEMENTS(root_propv
));
1806 /* Get model and version properties under node "openprom" */
1807 next_node
= find_node_by_name(promh
, root
, "openprom");
1808 if (next_node
!= DI_NODE_NIL
)
1809 dump_prodinfo(promh
, next_node
, oprom_prop
,
1810 "openprom", NUM_ELEMENTS(oprom_prop
));
1813 dump_prodinfo(promh
, root
, root_prop
, "root",
1814 NUM_ELEMENTS(root_prop
));
1815 di_prom_fini(promh
);
1821 find_node_by_name(di_prom_handle_t promh
, di_node_t parent
,
1824 di_node_t next_node
;
1827 for (next_node
= di_child_node(parent
); next_node
!= DI_NODE_NIL
;
1828 next_node
= di_sibling_node(next_node
)) {
1831 len
= get_propval_by_name(promh
, next_node
, "name", &prop_valp
);
1832 if ((len
!= -1) && (strcmp((char *)prop_valp
, node_name
) == 0))
1835 return (DI_NODE_NIL
);
1840 get_propval_by_name(di_prom_handle_t promh
, di_node_t node
, const char *name
,
1846 len
= di_prom_prop_lookup_bytes(promh
, node
, name
,
1849 *valp
= (uchar_t
*)malloc(len
);
1850 (void) memcpy(*valp
, bufp
, len
);
1857 dump_prodinfo(di_prom_handle_t promh
, di_node_t node
, const char **propstr
,
1858 char *node_name
, int num
)
1860 int out
, len
, index1
, index
, endswap
= 0;
1863 for (index1
= 0; index1
< num
; index1
++) {
1864 len
= get_propval_by_name(promh
, node
, propstr
[index1
],
1867 if (strcmp(node_name
, "root"))
1868 (void) printf("%s ", node_name
);
1870 (void) printf("%s: ", propstr
[index1
]);
1872 if (print_composite_string((const char *)
1873 propstr
[index1
], (char *)prop_valp
, len
)) {
1878 if (!unprintable((char *)prop_valp
, len
)) {
1879 (void) printf(" %s\n", (char *)prop_valp
);
1886 endswap
= (len
% 4) == 0;
1888 for (index
= 0; index
< len
; index
++) {
1889 if (index
&& (index
% 4 == 0))
1890 (void) putchar('.');
1892 out
= prop_valp
[index
+
1893 (3 - 2 * (index
% 4))] & 0xff;
1895 out
= prop_valp
[index
] & 0xff;
1896 (void) printf("%02x", out
);
1898 (void) putchar('\n');
1905 dump_compatible(char *name
, int ilev
, di_node_t node
)
1912 if (node
== DI_PATH_NIL
)
1915 ncompat
= di_compatible_names(node
, &compat_array
);
1917 return (0); /* no 'compatible' available */
1919 /* verify integrety of compat_array */
1920 for (i
= 0, p
= compat_array
; i
< ncompat
; i
++, p
+= strlen(p
) + 1) {
1922 return (0); /* NULL string */
1923 for (q
= p
; *q
; q
++) {
1924 if (!(isascii(*q
) && (isprint(*q
) || isspace(*q
))))
1925 return (0); /* Not printable or space */
1929 /* If name is non-NULL, produce header */
1931 indent_to_level(ilev
);
1932 (void) printf("%s properties:\n", name
);
1936 /* process like a string array property */
1937 indent_to_level(ilev
);
1938 (void) printf("name='compatible' type=string items=%d\n", ncompat
);
1939 indent_to_level(ilev
);
1940 (void) printf(" value=");
1941 for (i
= 0, p
= compat_array
; i
< (ncompat
- 1);
1942 i
++, p
+= strlen(p
) + 1)
1943 (void) printf("'%s' + ", p
);
1944 (void) printf("'%s'", p
);
1945 (void) putchar('\n');
1950 dump_pciid(char *name
, int ilev
, di_node_t node
, pcidb_hdl_t
*pci
)
1953 int *vid
, *did
, *svid
, *sdid
;
1954 const char *vname
, *dname
, *sname
;
1955 pcidb_vendor_t
*pciv
;
1956 pcidb_device_t
*pcid
;
1957 pcidb_subvd_t
*pcis
;
1958 di_node_t pnode
= di_parent_node(node
);
1960 const char *unov
= "unknown vendor";
1961 const char *unod
= "unknown device";
1962 const char *unos
= "unknown subsystem";
1971 if (di_prop_lookup_strings(DDI_DEV_T_ANY
, pnode
,
1972 "device_type", &t
) <= 0)
1975 if (t
== NULL
|| (strcmp(t
, "pci") != 0 &&
1976 strcmp(t
, "pciex") != 0))
1980 * All devices should have a vendor and device id, if we fail to find
1981 * one, then we're going to return right here and not print anything.
1983 * We're going to also check for the subsystem-vendor-id and
1984 * subsystem-id. If we don't find one of them, we're going to assume
1985 * that this device does not have one. In that case, we will never
1986 * attempt to try and print anything related to that. If it does have
1987 * both, then we are going to look them up and print the appropriate
1988 * string if we find it or not.
1990 if (di_prop_lookup_ints(DDI_DEV_T_ANY
, node
, "vendor-id", &vid
) <= 0)
1993 if (di_prop_lookup_ints(DDI_DEV_T_ANY
, node
, "device-id", &did
) <= 0)
1996 if (di_prop_lookup_ints(DDI_DEV_T_ANY
, node
, "subsystem-vendor-id",
1997 &svid
) <= 0 || di_prop_lookup_ints(DDI_DEV_T_ANY
, node
,
1998 "subsystem-id", &sdid
) <= 0) {
2004 pciv
= pcidb_lookup_vendor(pci
, vid
[0]);
2007 vname
= pcidb_vendor_name(pciv
);
2009 pcid
= pcidb_lookup_device_by_vendor(pciv
, did
[0]);
2012 dname
= pcidb_device_name(pcid
);
2015 pcis
= pcidb_lookup_subvd_by_device(pcid
, svid
[0], sdid
[0]);
2018 sname
= pcidb_subvd_name(pcis
);
2022 /* If name is non-NULL, produce header */
2024 indent_to_level(ilev
);
2025 (void) printf("%s properties:\n", name
);
2029 /* These are all going to be single string properties */
2030 indent_to_level(ilev
);
2031 (void) printf("name='vendor-name' type=string items=1\n");
2032 indent_to_level(ilev
);
2033 (void) printf(" value='%s'\n", vname
);
2035 indent_to_level(ilev
);
2036 (void) printf("name='device-name' type=string items=1\n");
2037 indent_to_level(ilev
);
2038 (void) printf(" value='%s'\n", dname
);
2040 if (sname
!= NULL
) {
2041 indent_to_level(ilev
);
2042 (void) printf("name='subsystem-name' type=string items=1\n");
2043 indent_to_level(ilev
);
2044 (void) printf(" value='%s'\n", sname
);