10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
54453Scth * Common Development and Distribution License (the "License").
64453Scth * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
229074SJudy.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * For machines that support the openprom, fetch and print the list
280Sstevel@tonic-gate * of devices that the kernel has fetched from the prom or conjured up.
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdarg.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <fcntl.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <strings.h>
370Sstevel@tonic-gate #include <unistd.h>
380Sstevel@tonic-gate #include <stropts.h>
390Sstevel@tonic-gate #include <sys/types.h>
400Sstevel@tonic-gate #include <sys/mkdev.h>
410Sstevel@tonic-gate #include <sys/sunddi.h>
420Sstevel@tonic-gate #include <sys/openpromio.h>
430Sstevel@tonic-gate #include <sys/modctl.h>
440Sstevel@tonic-gate #include <sys/stat.h>
450Sstevel@tonic-gate #include <zone.h>
460Sstevel@tonic-gate #include <libnvpair.h>
470Sstevel@tonic-gate #include "prtconf.h"
480Sstevel@tonic-gate
490Sstevel@tonic-gate
500Sstevel@tonic-gate typedef char *(*dump_propname_t)(void *);
510Sstevel@tonic-gate typedef int (*dump_proptype_t)(void *);
520Sstevel@tonic-gate typedef int (*dump_propints_t)(void *, int **);
530Sstevel@tonic-gate typedef int (*dump_propint64_t)(void *, int64_t **);
540Sstevel@tonic-gate typedef int (*dump_propstrings_t)(void *, char **);
550Sstevel@tonic-gate typedef int (*dump_propbytes_t)(void *, uchar_t **);
560Sstevel@tonic-gate typedef int (*dump_proprawdata_t)(void *, uchar_t **);
570Sstevel@tonic-gate
580Sstevel@tonic-gate typedef struct dumpops_common {
590Sstevel@tonic-gate dump_propname_t doc_propname;
600Sstevel@tonic-gate dump_proptype_t doc_proptype;
610Sstevel@tonic-gate dump_propints_t doc_propints;
620Sstevel@tonic-gate dump_propint64_t doc_propint64;
630Sstevel@tonic-gate dump_propstrings_t doc_propstrings;
640Sstevel@tonic-gate dump_propbytes_t doc_propbytes;
650Sstevel@tonic-gate dump_proprawdata_t doc_proprawdata;
660Sstevel@tonic-gate } dumpops_common_t;
670Sstevel@tonic-gate
680Sstevel@tonic-gate static const dumpops_common_t prop_dumpops = {
690Sstevel@tonic-gate (dump_propname_t)di_prop_name,
700Sstevel@tonic-gate (dump_proptype_t)di_prop_type,
710Sstevel@tonic-gate (dump_propints_t)di_prop_ints,
720Sstevel@tonic-gate (dump_propint64_t)di_prop_int64,
730Sstevel@tonic-gate (dump_propstrings_t)di_prop_strings,
740Sstevel@tonic-gate (dump_propbytes_t)di_prop_bytes,
750Sstevel@tonic-gate (dump_proprawdata_t)di_prop_rawdata
760Sstevel@tonic-gate }, pathprop_common_dumpops = {
770Sstevel@tonic-gate (dump_propname_t)di_path_prop_name,
780Sstevel@tonic-gate (dump_proptype_t)di_path_prop_type,
790Sstevel@tonic-gate (dump_propints_t)di_path_prop_ints,
800Sstevel@tonic-gate (dump_propint64_t)di_path_prop_int64s,
810Sstevel@tonic-gate (dump_propstrings_t)di_path_prop_strings,
820Sstevel@tonic-gate (dump_propbytes_t)di_path_prop_bytes,
830Sstevel@tonic-gate (dump_proprawdata_t)di_path_prop_bytes
840Sstevel@tonic-gate };
850Sstevel@tonic-gate
860Sstevel@tonic-gate typedef void *(*dump_nextprop_t)(void *, void *);
870Sstevel@tonic-gate typedef dev_t (*dump_propdevt_t)(void *);
880Sstevel@tonic-gate
890Sstevel@tonic-gate typedef struct dumpops {
900Sstevel@tonic-gate const dumpops_common_t *dop_common;
910Sstevel@tonic-gate dump_nextprop_t dop_nextprop;
920Sstevel@tonic-gate dump_propdevt_t dop_propdevt;
930Sstevel@tonic-gate } dumpops_t;
940Sstevel@tonic-gate
959074SJudy.Chen@Sun.COM typedef struct di_args {
969074SJudy.Chen@Sun.COM di_prom_handle_t prom_hdl;
979074SJudy.Chen@Sun.COM di_devlink_handle_t devlink_hdl;
989074SJudy.Chen@Sun.COM } di_arg_t;
999074SJudy.Chen@Sun.COM
1000Sstevel@tonic-gate static const dumpops_t sysprop_dumpops = {
1010Sstevel@tonic-gate &prop_dumpops,
1020Sstevel@tonic-gate (dump_nextprop_t)di_prop_sys_next,
1030Sstevel@tonic-gate NULL
1040Sstevel@tonic-gate }, globprop_dumpops = {
1050Sstevel@tonic-gate &prop_dumpops,
1060Sstevel@tonic-gate (dump_nextprop_t)di_prop_global_next,
1070Sstevel@tonic-gate NULL
1080Sstevel@tonic-gate }, drvprop_dumpops = {
1090Sstevel@tonic-gate &prop_dumpops,
1100Sstevel@tonic-gate (dump_nextprop_t)di_prop_drv_next,
1110Sstevel@tonic-gate (dump_propdevt_t)di_prop_devt
1120Sstevel@tonic-gate }, hwprop_dumpops = {
1130Sstevel@tonic-gate &prop_dumpops,
1140Sstevel@tonic-gate (dump_nextprop_t)di_prop_hw_next,
1150Sstevel@tonic-gate NULL
1160Sstevel@tonic-gate }, pathprop_dumpops = {
1170Sstevel@tonic-gate &pathprop_common_dumpops,
1180Sstevel@tonic-gate (dump_nextprop_t)di_path_prop_next,
1190Sstevel@tonic-gate NULL
1200Sstevel@tonic-gate };
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate #define PROPNAME(ops) (ops->dop_common->doc_propname)
1230Sstevel@tonic-gate #define PROPTYPE(ops) (ops->dop_common->doc_proptype)
1240Sstevel@tonic-gate #define PROPINTS(ops) (ops->dop_common->doc_propints)
1250Sstevel@tonic-gate #define PROPINT64(ops) (ops->dop_common->doc_propint64)
1260Sstevel@tonic-gate #define PROPSTRINGS(ops) (ops->dop_common->doc_propstrings)
1270Sstevel@tonic-gate #define PROPBYTES(ops) (ops->dop_common->doc_propbytes)
1280Sstevel@tonic-gate #define PROPRAWDATA(ops) (ops->dop_common->doc_proprawdata)
1290Sstevel@tonic-gate #define NEXTPROP(ops) (ops->dop_nextprop)
1300Sstevel@tonic-gate #define PROPDEVT(ops) (ops->dop_propdevt)
1310Sstevel@tonic-gate #define NUM_ELEMENTS(A) (sizeof (A) / sizeof (A[0]))
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate static int prop_type_guess(const dumpops_t *, void *, void **, int *);
1349074SJudy.Chen@Sun.COM static void walk_driver(di_node_t, di_arg_t *);
1350Sstevel@tonic-gate static int dump_devs(di_node_t, void *);
1367224Scth static int dump_prop_list(const dumpops_t *, const char *,
1377261Scth int, void *, dev_t, int *);
1380Sstevel@tonic-gate static int _error(const char *, ...);
1390Sstevel@tonic-gate static int is_openprom();
1400Sstevel@tonic-gate static void walk(uchar_t *, uint_t, int);
1410Sstevel@tonic-gate static void dump_node(nvlist_t *, int);
1420Sstevel@tonic-gate static void dump_prodinfo(di_prom_handle_t, di_node_t, const char **,
1430Sstevel@tonic-gate char *, int);
1440Sstevel@tonic-gate static di_node_t find_node_by_name(di_prom_handle_t, di_node_t, char *);
1450Sstevel@tonic-gate static int get_propval_by_name(di_prom_handle_t, di_node_t,
1460Sstevel@tonic-gate const char *, uchar_t **);
1477261Scth static int dump_compatible(char *, int, di_node_t);
1480Sstevel@tonic-gate static void dump_pathing_data(int, di_node_t);
1490Sstevel@tonic-gate static void dump_minor_data(int, di_node_t, di_devlink_handle_t);
1500Sstevel@tonic-gate static void dump_link_data(int, di_node_t, di_devlink_handle_t);
1510Sstevel@tonic-gate static int print_composite_string(const char *, char *, int);
1520Sstevel@tonic-gate static void print_one(nvpair_t *, int);
1530Sstevel@tonic-gate static int unprintable(char *, int);
1540Sstevel@tonic-gate static int promopen(int);
1550Sstevel@tonic-gate static void promclose();
1560Sstevel@tonic-gate static di_node_t find_target_node(di_node_t);
1570Sstevel@tonic-gate static void node_display_set(di_node_t);
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate void
prtconf_devinfo(void)1600Sstevel@tonic-gate prtconf_devinfo(void)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate struct di_priv_data fetch;
1639074SJudy.Chen@Sun.COM di_arg_t di_arg;
1649074SJudy.Chen@Sun.COM di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL;
1650Sstevel@tonic-gate di_devlink_handle_t devlink_hdl = NULL;
1660Sstevel@tonic-gate di_node_t root_node;
1670Sstevel@tonic-gate uint_t flag;
1680Sstevel@tonic-gate char *rootpath;
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate dprintf("verbosemode %s\n", opts.o_verbose ? "on" : "off");
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /* determine what info we need to get from kernel */
1730Sstevel@tonic-gate flag = DINFOSUBTREE;
1740Sstevel@tonic-gate rootpath = "/";
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate if (opts.o_target) {
1770Sstevel@tonic-gate flag |= (DINFOMINOR | DINFOPATH);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate
1809074SJudy.Chen@Sun.COM if (opts.o_pciid) {
1819074SJudy.Chen@Sun.COM flag |= DINFOPROP;
1829074SJudy.Chen@Sun.COM if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL)
1839074SJudy.Chen@Sun.COM exit(_error("di_prom_init() failed."));
1849074SJudy.Chen@Sun.COM }
1859074SJudy.Chen@Sun.COM
1860Sstevel@tonic-gate if (opts.o_forcecache) {
1874453Scth if (dbg.d_forceload) {
1880Sstevel@tonic-gate exit(_error(NULL, "option combination not supported"));
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate if (strcmp(rootpath, "/") != 0) {
1910Sstevel@tonic-gate exit(_error(NULL, "invalid root path for option"));
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate flag = DINFOCACHE;
1944453Scth } else if (opts.o_verbose) {
1954453Scth flag |= (DINFOPROP | DINFOMINOR |
1964453Scth DINFOPRIVDATA | DINFOPATH | DINFOLYR);
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate if (dbg.d_forceload) {
2000Sstevel@tonic-gate flag |= DINFOFORCE;
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate if (opts.o_verbose) {
2040Sstevel@tonic-gate init_priv_data(&fetch);
2050Sstevel@tonic-gate root_node = di_init_impl(rootpath, flag, &fetch);
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /* get devlink (aka aliases) data */
2080Sstevel@tonic-gate if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL)
2090Sstevel@tonic-gate exit(_error("di_devlink_init() failed."));
2100Sstevel@tonic-gate } else
2110Sstevel@tonic-gate root_node = di_init(rootpath, flag);
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate if (root_node == DI_NODE_NIL) {
2140Sstevel@tonic-gate (void) _error(NULL, "devinfo facility not available");
2150Sstevel@tonic-gate /* not an error if this isn't the global zone */
2160Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID)
2170Sstevel@tonic-gate exit(-1);
2180Sstevel@tonic-gate else
2190Sstevel@tonic-gate exit(0);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2229074SJudy.Chen@Sun.COM di_arg.prom_hdl = prom_hdl;
2239074SJudy.Chen@Sun.COM di_arg.devlink_hdl = devlink_hdl;
2249074SJudy.Chen@Sun.COM
2250Sstevel@tonic-gate /*
2260Sstevel@tonic-gate * ...and walk all nodes to report them out...
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate if (dbg.d_bydriver) {
2290Sstevel@tonic-gate opts.o_target = 0;
2309074SJudy.Chen@Sun.COM walk_driver(root_node, &di_arg);
2319074SJudy.Chen@Sun.COM if (prom_hdl != DI_PROM_HANDLE_NIL)
2329074SJudy.Chen@Sun.COM di_prom_fini(prom_hdl);
2330Sstevel@tonic-gate if (devlink_hdl != NULL)
2340Sstevel@tonic-gate (void) di_devlink_fini(&devlink_hdl);
2350Sstevel@tonic-gate di_fini(root_node);
2360Sstevel@tonic-gate return;
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate if (opts.o_target) {
2400Sstevel@tonic-gate di_node_t target_node, node;
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate target_node = find_target_node(root_node);
2430Sstevel@tonic-gate if (target_node == DI_NODE_NIL) {
2440Sstevel@tonic-gate (void) fprintf(stderr, "%s: "
2454453Scth "invalid device path specified\n",
2464453Scth opts.o_progname);
2470Sstevel@tonic-gate exit(1);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate /* mark the target node so we display it */
2510Sstevel@tonic-gate node_display_set(target_node);
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate if (opts.o_ancestors) {
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate * mark the ancestors of this node so we display
2560Sstevel@tonic-gate * them as well
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate node = target_node;
2590Sstevel@tonic-gate while (node = di_parent_node(node))
2600Sstevel@tonic-gate node_display_set(node);
2610Sstevel@tonic-gate } else {
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate * when we display device tree nodes the indentation
2640Sstevel@tonic-gate * level is based off of tree depth.
2650Sstevel@tonic-gate *
2660Sstevel@tonic-gate * here we increment o_target to reflect the
2670Sstevel@tonic-gate * depth of the target node in the tree. we do
2680Sstevel@tonic-gate * this so that when we calculate the indentation
2690Sstevel@tonic-gate * level we can subtract o_target so that the
2700Sstevel@tonic-gate * target node starts with an indentation of zero.
2710Sstevel@tonic-gate */
2720Sstevel@tonic-gate node = target_node;
2730Sstevel@tonic-gate while (node = di_parent_node(node))
2740Sstevel@tonic-gate opts.o_target++;
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate if (opts.o_children) {
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate * mark the children of this node so we display
2800Sstevel@tonic-gate * them as well
2810Sstevel@tonic-gate */
2820Sstevel@tonic-gate (void) di_walk_node(target_node, DI_WALK_CLDFIRST,
2834453Scth (void *)1,
2844453Scth (int (*)(di_node_t, void *))
2854453Scth node_display_set);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2899074SJudy.Chen@Sun.COM (void) di_walk_node(root_node, DI_WALK_CLDFIRST, &di_arg,
2904453Scth dump_devs);
2910Sstevel@tonic-gate
2929074SJudy.Chen@Sun.COM if (prom_hdl != DI_PROM_HANDLE_NIL)
2939074SJudy.Chen@Sun.COM di_prom_fini(prom_hdl);
2940Sstevel@tonic-gate if (devlink_hdl != NULL)
2950Sstevel@tonic-gate (void) di_devlink_fini(&devlink_hdl);
2960Sstevel@tonic-gate di_fini(root_node);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate /*
3000Sstevel@tonic-gate * utility routines
3010Sstevel@tonic-gate */
3020Sstevel@tonic-gate static int
i_find_target_node(di_node_t node,void * arg)3030Sstevel@tonic-gate i_find_target_node(di_node_t node, void *arg)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate di_node_t *target = (di_node_t *)arg;
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate if (opts.o_devices_path != NULL) {
3080Sstevel@tonic-gate char *path;
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate if ((path = di_devfs_path(node)) == NULL)
3110Sstevel@tonic-gate exit(_error("failed to allocate memory"));
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate if (strcmp(opts.o_devices_path, path) == 0) {
3140Sstevel@tonic-gate di_devfs_path_free(path);
3150Sstevel@tonic-gate *target = node;
3160Sstevel@tonic-gate return (DI_WALK_TERMINATE);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate di_devfs_path_free(path);
3200Sstevel@tonic-gate } else if (opts.o_devt != DDI_DEV_T_NONE) {
3210Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL;
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
3240Sstevel@tonic-gate if (opts.o_devt == di_minor_devt(minor)) {
3250Sstevel@tonic-gate *target = node;
3260Sstevel@tonic-gate return (DI_WALK_TERMINATE);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate } else {
3300Sstevel@tonic-gate /* we should never get here */
3310Sstevel@tonic-gate exit(_error(NULL, "internal error"));
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate return (DI_WALK_CONTINUE);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate static di_node_t
find_target_node(di_node_t root_node)3370Sstevel@tonic-gate find_target_node(di_node_t root_node)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate di_node_t target = DI_NODE_NIL;
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate /* special case to allow displaying of the root node */
3420Sstevel@tonic-gate if (opts.o_devices_path != NULL) {
3430Sstevel@tonic-gate if (strlen(opts.o_devices_path) == 0)
3440Sstevel@tonic-gate return (root_node);
3450Sstevel@tonic-gate if (strcmp(opts.o_devices_path, ".") == 0)
3460Sstevel@tonic-gate return (root_node);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate (void) di_walk_node(root_node, DI_WALK_CLDFIRST, &target,
3504453Scth i_find_target_node);
3510Sstevel@tonic-gate return (target);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate #define NODE_DISPLAY (1<<0)
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate static long
node_display(di_node_t node)3570Sstevel@tonic-gate node_display(di_node_t node)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate long data = (long)di_node_private_get(node);
3600Sstevel@tonic-gate return (data & NODE_DISPLAY);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate static void
node_display_set(di_node_t node)3640Sstevel@tonic-gate node_display_set(di_node_t node)
3650Sstevel@tonic-gate {
3660Sstevel@tonic-gate long data = (long)di_node_private_get(node);
3670Sstevel@tonic-gate data |= NODE_DISPLAY;
3680Sstevel@tonic-gate di_node_private_set(node, (void *)data);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate #define LNODE_DISPLAYED (1<<0)
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate static long
lnode_displayed(di_lnode_t lnode)3740Sstevel@tonic-gate lnode_displayed(di_lnode_t lnode)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate long data = (long)di_lnode_private_get(lnode);
3770Sstevel@tonic-gate return (data & LNODE_DISPLAYED);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate static void
lnode_displayed_set(di_lnode_t lnode)3810Sstevel@tonic-gate lnode_displayed_set(di_lnode_t lnode)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate long data = (long)di_lnode_private_get(lnode);
3840Sstevel@tonic-gate data |= LNODE_DISPLAYED;
3850Sstevel@tonic-gate di_lnode_private_set(lnode, (void *)data);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate static void
lnode_displayed_clear(di_lnode_t lnode)3890Sstevel@tonic-gate lnode_displayed_clear(di_lnode_t lnode)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate long data = (long)di_lnode_private_get(lnode);
3920Sstevel@tonic-gate data &= ~LNODE_DISPLAYED;
3930Sstevel@tonic-gate di_lnode_private_set(lnode, (void *)data);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate #define MINOR_DISPLAYED (1<<0)
3970Sstevel@tonic-gate #define MINOR_PTR (~(0x3))
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate static long
minor_displayed(di_minor_t minor)4000Sstevel@tonic-gate minor_displayed(di_minor_t minor)
4010Sstevel@tonic-gate {
4020Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4030Sstevel@tonic-gate return (data & MINOR_DISPLAYED);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate static void
minor_displayed_set(di_minor_t minor)4070Sstevel@tonic-gate minor_displayed_set(di_minor_t minor)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4100Sstevel@tonic-gate data |= MINOR_DISPLAYED;
4110Sstevel@tonic-gate di_minor_private_set(minor, (void *)data);
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate static void
minor_displayed_clear(di_minor_t minor)4150Sstevel@tonic-gate minor_displayed_clear(di_minor_t minor)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4180Sstevel@tonic-gate data &= ~MINOR_DISPLAYED;
4190Sstevel@tonic-gate di_minor_private_set(minor, (void *)data);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate static void *
minor_ptr(di_minor_t minor)4230Sstevel@tonic-gate minor_ptr(di_minor_t minor)
4240Sstevel@tonic-gate {
4250Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4260Sstevel@tonic-gate return ((void *)(data & MINOR_PTR));
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate static void
minor_ptr_set(di_minor_t minor,void * ptr)4300Sstevel@tonic-gate minor_ptr_set(di_minor_t minor, void *ptr)
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4330Sstevel@tonic-gate data = (data & ~MINOR_PTR) | (((long)ptr) & MINOR_PTR);
4340Sstevel@tonic-gate di_minor_private_set(minor, (void *)data);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate * In this comment typed properties are those of type DI_PROP_TYPE_UNDEF_IT,
4390Sstevel@tonic-gate * DI_PROP_TYPE_BOOLEAN, DI_PROP_TYPE_INT, DI_PROP_TYPE_INT64,
4400Sstevel@tonic-gate * DI_PROP_TYPE_BYTE, and DI_PROP_TYPE_STRING.
4410Sstevel@tonic-gate *
4420Sstevel@tonic-gate * The guessing algorithm is:
4430Sstevel@tonic-gate * 1. If the property is typed and the type is consistent with the value of
4440Sstevel@tonic-gate * the property, then the property is of that type. If the type is not
4450Sstevel@tonic-gate * consistent with value of the property, then the type is treated as
4460Sstevel@tonic-gate * alien to prtconf.
4470Sstevel@tonic-gate * 2. If the property is of type DI_PROP_TYPE_UNKNOWN the following steps
4480Sstevel@tonic-gate * are carried out.
4490Sstevel@tonic-gate * a. If the value of the property is consistent with a string property,
4500Sstevel@tonic-gate * the type of the property is DI_PROP_TYPE_STRING.
4510Sstevel@tonic-gate * b. Otherwise, if the value of the property is consistent with an integer
4520Sstevel@tonic-gate * property, the type of the property is DI_PROP_TYPE_INT.
4530Sstevel@tonic-gate * c. Otherwise, the property type is treated as alien to prtconf.
4540Sstevel@tonic-gate * 3. If the property type is alien to prtconf, then the property value is
4550Sstevel@tonic-gate * read by the appropriate routine for untyped properties and the following
4560Sstevel@tonic-gate * steps are carried out.
4570Sstevel@tonic-gate * a. If the length that the property routine returned is zero, the
4580Sstevel@tonic-gate * property is of type DI_PROP_TYPE_BOOLEAN.
4590Sstevel@tonic-gate * b. Otherwise, if the length that the property routine returned is
4600Sstevel@tonic-gate * positive, then the property value is treated as raw data of type
4610Sstevel@tonic-gate * DI_PROP_TYPE_UNKNOWN.
4620Sstevel@tonic-gate * c. Otherwise, if the length that the property routine returned is
4630Sstevel@tonic-gate * negative, then there is some internal inconsistency and this is
4640Sstevel@tonic-gate * treated as an error and no type is determined.
4650Sstevel@tonic-gate */
4660Sstevel@tonic-gate static int
prop_type_guess(const dumpops_t * propops,void * prop,void ** prop_data,int * prop_type)4670Sstevel@tonic-gate prop_type_guess(const dumpops_t *propops, void *prop, void **prop_data,
4680Sstevel@tonic-gate int *prop_type)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate int len, type;
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate type = PROPTYPE(propops)(prop);
4730Sstevel@tonic-gate switch (type) {
4740Sstevel@tonic-gate case DI_PROP_TYPE_UNDEF_IT:
4750Sstevel@tonic-gate case DI_PROP_TYPE_BOOLEAN:
4760Sstevel@tonic-gate *prop_data = NULL;
4770Sstevel@tonic-gate *prop_type = type;
4780Sstevel@tonic-gate return (0);
4790Sstevel@tonic-gate case DI_PROP_TYPE_INT:
4800Sstevel@tonic-gate len = PROPINTS(propops)(prop, (int **)prop_data);
4810Sstevel@tonic-gate break;
4820Sstevel@tonic-gate case DI_PROP_TYPE_INT64:
4830Sstevel@tonic-gate len = PROPINT64(propops)(prop, (int64_t **)prop_data);
4840Sstevel@tonic-gate break;
4850Sstevel@tonic-gate case DI_PROP_TYPE_BYTE:
4860Sstevel@tonic-gate len = PROPBYTES(propops)(prop, (uchar_t **)prop_data);
4870Sstevel@tonic-gate break;
4880Sstevel@tonic-gate case DI_PROP_TYPE_STRING:
4890Sstevel@tonic-gate len = PROPSTRINGS(propops)(prop, (char **)prop_data);
4900Sstevel@tonic-gate break;
4910Sstevel@tonic-gate case DI_PROP_TYPE_UNKNOWN:
4920Sstevel@tonic-gate len = PROPSTRINGS(propops)(prop, (char **)prop_data);
4930Sstevel@tonic-gate if ((len > 0) && ((*(char **)prop_data)[0] != 0)) {
4940Sstevel@tonic-gate *prop_type = DI_PROP_TYPE_STRING;
4950Sstevel@tonic-gate return (len);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate len = PROPINTS(propops)(prop, (int **)prop_data);
4990Sstevel@tonic-gate type = DI_PROP_TYPE_INT;
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate break;
5020Sstevel@tonic-gate default:
5030Sstevel@tonic-gate len = -1;
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate if (len > 0) {
5070Sstevel@tonic-gate *prop_type = type;
5080Sstevel@tonic-gate return (len);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate len = PROPRAWDATA(propops)(prop, (uchar_t **)prop_data);
5120Sstevel@tonic-gate if (len < 0) {
5130Sstevel@tonic-gate return (-1);
5140Sstevel@tonic-gate } else if (len == 0) {
5150Sstevel@tonic-gate *prop_type = DI_PROP_TYPE_BOOLEAN;
5160Sstevel@tonic-gate return (0);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate *prop_type = DI_PROP_TYPE_UNKNOWN;
5200Sstevel@tonic-gate return (len);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate
5237224Scth /*
5247224Scth * Returns 0 if nothing is printed, 1 otherwise
5257224Scth */
5267224Scth static int
dump_prop_list(const dumpops_t * dumpops,const char * name,int ilev,void * node,dev_t dev,int * compat_printed)5277224Scth dump_prop_list(const dumpops_t *dumpops, const char *name, int ilev,
5287261Scth void *node, dev_t dev, int *compat_printed)
5290Sstevel@tonic-gate {
5307224Scth void *prop = DI_PROP_NIL, *prop_data;
5317224Scth di_minor_t minor;
5327224Scth char *p;
5337224Scth int i, prop_type, nitems;
5347224Scth dev_t pdev;
5357224Scth int nprop = 0;
5360Sstevel@tonic-gate
5377261Scth if (compat_printed)
5387261Scth *compat_printed = 0;
5397261Scth
5400Sstevel@tonic-gate while ((prop = NEXTPROP(dumpops)(node, prop)) != DI_PROP_NIL) {
5417224Scth
5427224Scth /* Skip properties a dev_t oriented caller is not requesting */
5437224Scth if (PROPDEVT(dumpops)) {
5447224Scth pdev = PROPDEVT(dumpops)(prop);
5457224Scth
5467224Scth if (dev == DDI_DEV_T_ANY) {
5477224Scth /*
5487224Scth * Caller requesting print all properties
5497224Scth */
5507224Scth goto print;
5517224Scth } else if (dev == DDI_DEV_T_NONE) {
5527224Scth /*
5537224Scth * Caller requesting print of properties
5547224Scth * associated with devinfo (not minor).
5557224Scth */
5567224Scth if ((pdev == DDI_DEV_T_ANY) ||
5577224Scth (pdev == DDI_DEV_T_NONE))
5587224Scth goto print;
5597224Scth
5607224Scth /*
5617224Scth * Property has a minor association, see if
5627224Scth * we have a minor with this dev_t. If there
5637224Scth * is no such minor we print the property now
5647224Scth * so it gets displayed.
5657224Scth */
5667224Scth minor = DI_MINOR_NIL;
5677224Scth while ((minor = di_minor_next((di_node_t)node,
5687224Scth minor)) != DI_MINOR_NIL) {
5697224Scth if (di_minor_devt(minor) == pdev)
5707224Scth break;
5717224Scth }
5727224Scth if (minor == DI_MINOR_NIL)
5737224Scth goto print;
5747224Scth } else if (dev == pdev) {
5757224Scth /*
5767224Scth * Caller requesting print of properties
5777224Scth * associated with a specific matching minor
5787224Scth * node.
5797224Scth */
5807224Scth goto print;
5817224Scth }
5827224Scth
5837224Scth /* otherwise skip print */
5847224Scth continue;
5857224Scth }
5867224Scth
5877224Scth print: nitems = prop_type_guess(dumpops, prop, &prop_data, &prop_type);
5880Sstevel@tonic-gate if (nitems < 0)
5890Sstevel@tonic-gate continue;
5900Sstevel@tonic-gate
5917224Scth if (nprop == 0) {
5927224Scth if (name) {
5937224Scth indent_to_level(ilev);
5947224Scth (void) printf("%s properties:\n", name);
5957224Scth }
5967224Scth ilev++;
5977224Scth }
5987224Scth nprop++;
5997224Scth
6000Sstevel@tonic-gate indent_to_level(ilev);
6010Sstevel@tonic-gate (void) printf("name='%s' type=", PROPNAME(dumpops)(prop));
6020Sstevel@tonic-gate
6037261Scth /* report 'compatible' as processed */
6047261Scth if (compat_printed &&
6057261Scth (strcmp(PROPNAME(dumpops)(prop), "compatible") == 0))
6067261Scth *compat_printed = 1;
6077261Scth
6080Sstevel@tonic-gate switch (prop_type) {
6090Sstevel@tonic-gate case DI_PROP_TYPE_UNDEF_IT:
6100Sstevel@tonic-gate (void) printf("undef");
6110Sstevel@tonic-gate break;
6120Sstevel@tonic-gate case DI_PROP_TYPE_BOOLEAN:
6130Sstevel@tonic-gate (void) printf("boolean");
6140Sstevel@tonic-gate break;
6150Sstevel@tonic-gate case DI_PROP_TYPE_INT:
6160Sstevel@tonic-gate (void) printf("int");
6170Sstevel@tonic-gate break;
6180Sstevel@tonic-gate case DI_PROP_TYPE_INT64:
6190Sstevel@tonic-gate (void) printf("int64");
6200Sstevel@tonic-gate break;
6210Sstevel@tonic-gate case DI_PROP_TYPE_BYTE:
6220Sstevel@tonic-gate (void) printf("byte");
6230Sstevel@tonic-gate break;
6240Sstevel@tonic-gate case DI_PROP_TYPE_STRING:
6250Sstevel@tonic-gate (void) printf("string");
6260Sstevel@tonic-gate break;
6270Sstevel@tonic-gate case DI_PROP_TYPE_UNKNOWN:
6280Sstevel@tonic-gate (void) printf("unknown");
6290Sstevel@tonic-gate break;
6300Sstevel@tonic-gate default:
6310Sstevel@tonic-gate /* Should never be here */
6320Sstevel@tonic-gate (void) printf("0x%x", prop_type);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate if (nitems != 0)
6360Sstevel@tonic-gate (void) printf(" items=%i", nitems);
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate /* print the major and minor numbers for a device property */
6397224Scth if (PROPDEVT(dumpops)) {
6407224Scth if ((pdev == DDI_DEV_T_NONE) ||
6417224Scth (pdev == DDI_DEV_T_ANY)) {
6427224Scth (void) printf(" dev=none");
6437224Scth } else {
6440Sstevel@tonic-gate (void) printf(" dev=(%u,%u)",
6457224Scth (uint_t)major(pdev), (uint_t)minor(pdev));
6460Sstevel@tonic-gate }
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate
6490Sstevel@tonic-gate (void) putchar('\n');
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate if (nitems == 0)
6520Sstevel@tonic-gate continue;
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate indent_to_level(ilev);
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate (void) printf(" value=");
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate switch (prop_type) {
6590Sstevel@tonic-gate case DI_PROP_TYPE_INT:
6600Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++)
6610Sstevel@tonic-gate (void) printf("%8.8x.", ((int *)prop_data)[i]);
6620Sstevel@tonic-gate (void) printf("%8.8x", ((int *)prop_data)[i]);
6630Sstevel@tonic-gate break;
6640Sstevel@tonic-gate case DI_PROP_TYPE_INT64:
6650Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++)
6660Sstevel@tonic-gate (void) printf("%16.16llx.",
6670Sstevel@tonic-gate ((long long *)prop_data)[i]);
6680Sstevel@tonic-gate (void) printf("%16.16llx", ((long long *)prop_data)[i]);
6690Sstevel@tonic-gate break;
6700Sstevel@tonic-gate case DI_PROP_TYPE_STRING:
6710Sstevel@tonic-gate p = (char *)prop_data;
6720Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++) {
6730Sstevel@tonic-gate (void) printf("'%s' + ", p);
6740Sstevel@tonic-gate p += strlen(p) + 1;
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate (void) printf("'%s'", p);
6770Sstevel@tonic-gate break;
6780Sstevel@tonic-gate default:
6790Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++)
6800Sstevel@tonic-gate (void) printf("%2.2x.",
6810Sstevel@tonic-gate ((uint8_t *)prop_data)[i]);
6820Sstevel@tonic-gate (void) printf("%2.2x", ((uint8_t *)prop_data)[i]);
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate (void) putchar('\n');
6860Sstevel@tonic-gate }
6877224Scth
6887224Scth return (nprop ? 1 : 0);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate * walk_driver is a debugging facility.
6930Sstevel@tonic-gate */
6940Sstevel@tonic-gate static void
walk_driver(di_node_t root,di_arg_t * di_arg)6959074SJudy.Chen@Sun.COM walk_driver(di_node_t root, di_arg_t *di_arg)
6960Sstevel@tonic-gate {
6970Sstevel@tonic-gate di_node_t node;
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate node = di_drv_first_node(dbg.d_drivername, root);
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate while (node != DI_NODE_NIL) {
7029074SJudy.Chen@Sun.COM (void) dump_devs(node, di_arg);
7030Sstevel@tonic-gate node = di_drv_next_node(node);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate /*
7080Sstevel@tonic-gate * print out information about this node, returns appropriate code.
7090Sstevel@tonic-gate */
7100Sstevel@tonic-gate /*ARGSUSED1*/
7110Sstevel@tonic-gate static int
dump_devs(di_node_t node,void * arg)7120Sstevel@tonic-gate dump_devs(di_node_t node, void *arg)
7130Sstevel@tonic-gate {
7149074SJudy.Chen@Sun.COM di_arg_t *di_arg = arg;
7159074SJudy.Chen@Sun.COM di_devlink_handle_t devlink_hdl = di_arg->devlink_hdl;
7160Sstevel@tonic-gate int ilev = 0; /* indentation level */
7170Sstevel@tonic-gate char *driver_name;
7180Sstevel@tonic-gate di_node_t root_node, tmp;
7197261Scth int compat_printed;
7207261Scth int printed;
7210Sstevel@tonic-gate
7220Sstevel@tonic-gate if (dbg.d_debug) {
7230Sstevel@tonic-gate char *path = di_devfs_path(node);
7240Sstevel@tonic-gate dprintf("Dump node %s\n", path);
7250Sstevel@tonic-gate di_devfs_path_free(path);
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate if (dbg.d_bydriver) {
7290Sstevel@tonic-gate ilev = 1;
7300Sstevel@tonic-gate } else {
7310Sstevel@tonic-gate /* figure out indentation level */
7320Sstevel@tonic-gate tmp = node;
7330Sstevel@tonic-gate while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
7340Sstevel@tonic-gate ilev++;
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate if (opts.o_target && !opts.o_ancestors) {
7370Sstevel@tonic-gate ilev -= opts.o_target - 1;
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate if (opts.o_target && !node_display(node)) {
7420Sstevel@tonic-gate /*
7430Sstevel@tonic-gate * if we're only displaying certain nodes and this one
7440Sstevel@tonic-gate * isn't flagged, skip it.
7450Sstevel@tonic-gate */
7460Sstevel@tonic-gate return (DI_WALK_CONTINUE);
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate indent_to_level(ilev);
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate (void) printf("%s", di_node_name(node));
7529074SJudy.Chen@Sun.COM if (opts.o_pciid)
7539074SJudy.Chen@Sun.COM (void) print_pciid(node, di_arg->prom_hdl);
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate /*
7560Sstevel@tonic-gate * if this node does not have an instance number or is the
7570Sstevel@tonic-gate * root node (1229946), we don't print an instance number
7580Sstevel@tonic-gate */
7590Sstevel@tonic-gate root_node = tmp = node;
7600Sstevel@tonic-gate while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
7610Sstevel@tonic-gate root_node = tmp;
7620Sstevel@tonic-gate if ((di_instance(node) >= 0) && (node != root_node))
7630Sstevel@tonic-gate (void) printf(", instance #%d", di_instance(node));
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate if (opts.o_drv_name) {
7660Sstevel@tonic-gate driver_name = di_driver_name(node);
7670Sstevel@tonic-gate if (driver_name != NULL)
7680Sstevel@tonic-gate (void) printf(" (driver name: %s)", driver_name);
7694845Svikram } else if (di_retired(node)) {
7704845Svikram (void) printf(" (retired)");
7710Sstevel@tonic-gate } else if (di_state(node) & DI_DRIVER_DETACHED)
7720Sstevel@tonic-gate (void) printf(" (driver not attached)");
7730Sstevel@tonic-gate (void) printf("\n");
7740Sstevel@tonic-gate
7750Sstevel@tonic-gate if (opts.o_verbose) {
7760Sstevel@tonic-gate if (dump_prop_list(&sysprop_dumpops, "System", ilev + 1,
7777261Scth node, DDI_DEV_T_ANY, NULL)) {
7780Sstevel@tonic-gate (void) dump_prop_list(&globprop_dumpops, NULL, ilev + 1,
7797261Scth node, DDI_DEV_T_ANY, NULL);
7800Sstevel@tonic-gate } else {
7810Sstevel@tonic-gate (void) dump_prop_list(&globprop_dumpops,
7827261Scth "System software", ilev + 1,
7837261Scth node, DDI_DEV_T_ANY, NULL);
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate (void) dump_prop_list(&drvprop_dumpops, "Driver", ilev + 1,
7867261Scth node, DDI_DEV_T_NONE, NULL);
7877261Scth
7887261Scth printed = dump_prop_list(&hwprop_dumpops, "Hardware",
7897261Scth ilev + 1, node, DDI_DEV_T_ANY, &compat_printed);
7907261Scth
7917261Scth /* Ensure that 'compatible' is printed under Hardware header */
7927261Scth if (!compat_printed)
7937261Scth (void) dump_compatible(printed ? NULL : "Hardware",
7947261Scth ilev + 1, node);
7957261Scth
7960Sstevel@tonic-gate dump_priv_data(ilev + 1, node);
7970Sstevel@tonic-gate dump_pathing_data(ilev + 1, node);
7980Sstevel@tonic-gate dump_link_data(ilev + 1, node, devlink_hdl);
7990Sstevel@tonic-gate dump_minor_data(ilev + 1, node, devlink_hdl);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate if (opts.o_target)
8030Sstevel@tonic-gate return (DI_WALK_CONTINUE);
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate if (!opts.o_pseudodevs && (strcmp(di_node_name(node), "pseudo") == 0))
8060Sstevel@tonic-gate return (DI_WALK_PRUNECHILD);
8070Sstevel@tonic-gate
8080Sstevel@tonic-gate return (DI_WALK_CONTINUE);
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate /* _error([no_perror, ] fmt [, arg ...]) */
8120Sstevel@tonic-gate static int
_error(const char * opt_noperror,...)8130Sstevel@tonic-gate _error(const char *opt_noperror, ...)
8140Sstevel@tonic-gate {
8150Sstevel@tonic-gate int saved_errno;
8160Sstevel@tonic-gate va_list ap;
8170Sstevel@tonic-gate int no_perror = 0;
8180Sstevel@tonic-gate const char *fmt;
8190Sstevel@tonic-gate
8200Sstevel@tonic-gate saved_errno = errno;
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", opts.o_progname);
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate va_start(ap, opt_noperror);
8250Sstevel@tonic-gate if (opt_noperror == NULL) {
8260Sstevel@tonic-gate no_perror = 1;
8270Sstevel@tonic-gate fmt = va_arg(ap, char *);
8280Sstevel@tonic-gate } else
8290Sstevel@tonic-gate fmt = opt_noperror;
8300Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap);
8310Sstevel@tonic-gate va_end(ap);
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate if (no_perror)
8340Sstevel@tonic-gate (void) fprintf(stderr, "\n");
8350Sstevel@tonic-gate else {
8360Sstevel@tonic-gate (void) fprintf(stderr, ": ");
8370Sstevel@tonic-gate errno = saved_errno;
8380Sstevel@tonic-gate perror("");
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate
8410Sstevel@tonic-gate return (-1);
8420Sstevel@tonic-gate }
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate /*
8460Sstevel@tonic-gate * The rest of the routines handle printing the raw prom devinfo (-p option).
8470Sstevel@tonic-gate *
8480Sstevel@tonic-gate * 128 is the size of the largest (currently) property name
8490Sstevel@tonic-gate * 16k - MAXNAMESZ - sizeof (int) is the size of the largest
8500Sstevel@tonic-gate * (currently) property value that is allowed.
8510Sstevel@tonic-gate * the sizeof (uint_t) is from struct openpromio
8520Sstevel@tonic-gate */
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate #define MAXNAMESZ 128
8550Sstevel@tonic-gate #define MAXVALSIZE (16384 - MAXNAMESZ - sizeof (uint_t))
8560Sstevel@tonic-gate #define BUFSIZE (MAXNAMESZ + MAXVALSIZE + sizeof (uint_t))
8570Sstevel@tonic-gate typedef union {
8580Sstevel@tonic-gate char buf[BUFSIZE];
8590Sstevel@tonic-gate struct openpromio opp;
8600Sstevel@tonic-gate } Oppbuf;
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate static int prom_fd;
8630Sstevel@tonic-gate static uchar_t *prom_snapshot;
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate static int
is_openprom(void)8660Sstevel@tonic-gate is_openprom(void)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate Oppbuf oppbuf;
8690Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
8700Sstevel@tonic-gate unsigned int i;
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
8730Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
8740Sstevel@tonic-gate exit(_error("OPROMGETCONS"));
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate i = (unsigned int)((unsigned char)opp->oprom_array[0]);
8770Sstevel@tonic-gate return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate int
do_prominfo(void)8810Sstevel@tonic-gate do_prominfo(void)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate uint_t arg = opts.o_verbose;
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate if (promopen(O_RDONLY)) {
8860Sstevel@tonic-gate exit(_error("openeepr device open failed"));
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate
8890Sstevel@tonic-gate if (is_openprom() == 0) {
8900Sstevel@tonic-gate (void) fprintf(stderr, "System architecture does not "
8910Sstevel@tonic-gate "support this option of this command.\n");
8920Sstevel@tonic-gate return (1);
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate /* OPROMSNAPSHOT returns size in arg */
8960Sstevel@tonic-gate if (ioctl(prom_fd, OPROMSNAPSHOT, &arg) < 0)
8970Sstevel@tonic-gate exit(_error("OPROMSNAPSHOT"));
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate if (arg == 0)
9000Sstevel@tonic-gate return (1);
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate if ((prom_snapshot = malloc(arg)) == NULL)
9030Sstevel@tonic-gate exit(_error("failed to allocate memory"));
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate /* copy out the snapshot for printing */
9060Sstevel@tonic-gate /*LINTED*/
9070Sstevel@tonic-gate *(uint_t *)prom_snapshot = arg;
9080Sstevel@tonic-gate if (ioctl(prom_fd, OPROMCOPYOUT, prom_snapshot) < 0)
9090Sstevel@tonic-gate exit(_error("OPROMCOPYOUT"));
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate promclose();
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate /* print out information */
9140Sstevel@tonic-gate walk(prom_snapshot, arg, 0);
9150Sstevel@tonic-gate free(prom_snapshot);
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate return (0);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate
9200Sstevel@tonic-gate static void
walk(uchar_t * buf,uint_t size,int level)9210Sstevel@tonic-gate walk(uchar_t *buf, uint_t size, int level)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate int error;
9240Sstevel@tonic-gate nvlist_t *nvl, *cnvl;
9250Sstevel@tonic-gate nvpair_t *child = NULL;
9260Sstevel@tonic-gate uchar_t *cbuf = NULL;
9270Sstevel@tonic-gate uint_t csize;
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate /* Expand to an nvlist */
9300Sstevel@tonic-gate if (nvlist_unpack((char *)buf, size, &nvl, 0))
9310Sstevel@tonic-gate exit(_error("error processing snapshot"));
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate /* print current node */
9340Sstevel@tonic-gate dump_node(nvl, level);
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate /* print children */
9370Sstevel@tonic-gate error = nvlist_lookup_byte_array(nvl, "@child", &cbuf, &csize);
9380Sstevel@tonic-gate if ((error == ENOENT) || (cbuf == NULL))
9390Sstevel@tonic-gate return; /* no child exists */
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate if (error || nvlist_unpack((char *)cbuf, csize, &cnvl, 0))
9420Sstevel@tonic-gate exit(_error("error processing snapshot"));
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate while (child = nvlist_next_nvpair(cnvl, child)) {
9450Sstevel@tonic-gate char *name = nvpair_name(child);
9460Sstevel@tonic-gate data_type_t type = nvpair_type(child);
9470Sstevel@tonic-gate uchar_t *nodebuf;
9480Sstevel@tonic-gate uint_t nodesize;
9490Sstevel@tonic-gate if (strcmp("node", name) != 0) {
9500Sstevel@tonic-gate dprintf("unexpected nvpair name %s != name\n", name);
9510Sstevel@tonic-gate continue;
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate if (type != DATA_TYPE_BYTE_ARRAY) {
9540Sstevel@tonic-gate dprintf("unexpected nvpair type %d, not byte array \n",
9550Sstevel@tonic-gate type);
9560Sstevel@tonic-gate continue;
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate (void) nvpair_value_byte_array(child,
9600Sstevel@tonic-gate (uchar_t **)&nodebuf, &nodesize);
9610Sstevel@tonic-gate walk(nodebuf, nodesize, level + 1);
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate nvlist_free(nvl);
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate /*
9680Sstevel@tonic-gate * Print all properties and values
9690Sstevel@tonic-gate */
9700Sstevel@tonic-gate static void
dump_node(nvlist_t * nvl,int level)9710Sstevel@tonic-gate dump_node(nvlist_t *nvl, int level)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate int id = 0;
9740Sstevel@tonic-gate char *name = NULL;
9750Sstevel@tonic-gate nvpair_t *nvp = NULL;
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate indent_to_level(level);
9780Sstevel@tonic-gate (void) printf("Node");
9790Sstevel@tonic-gate if (!opts.o_verbose) {
9800Sstevel@tonic-gate if (nvlist_lookup_string(nvl, "name", &name))
9810Sstevel@tonic-gate (void) printf("data not available");
9820Sstevel@tonic-gate else
9830Sstevel@tonic-gate (void) printf(" '%s'", name);
9840Sstevel@tonic-gate (void) putchar('\n');
9850Sstevel@tonic-gate return;
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate (void) nvlist_lookup_int32(nvl, "@nodeid", &id);
9880Sstevel@tonic-gate (void) printf(" %#08x\n", id);
9890Sstevel@tonic-gate
9900Sstevel@tonic-gate while (nvp = nvlist_next_nvpair(nvl, nvp)) {
9910Sstevel@tonic-gate name = nvpair_name(nvp);
9920Sstevel@tonic-gate if (name[0] == '@')
9930Sstevel@tonic-gate continue;
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate print_one(nvp, level + 1);
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate (void) putchar('\n');
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate
10000Sstevel@tonic-gate static const char *
path_state_name(di_path_state_t st)10010Sstevel@tonic-gate path_state_name(di_path_state_t st)
10020Sstevel@tonic-gate {
10030Sstevel@tonic-gate switch (st) {
10040Sstevel@tonic-gate case DI_PATH_STATE_ONLINE:
10050Sstevel@tonic-gate return ("online");
10060Sstevel@tonic-gate case DI_PATH_STATE_STANDBY:
10070Sstevel@tonic-gate return ("standby");
10080Sstevel@tonic-gate case DI_PATH_STATE_OFFLINE:
10090Sstevel@tonic-gate return ("offline");
10100Sstevel@tonic-gate case DI_PATH_STATE_FAULT:
10110Sstevel@tonic-gate return ("faulted");
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate return ("unknown");
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate * Print all phci's each client is connected to.
10180Sstevel@tonic-gate */
10190Sstevel@tonic-gate static void
dump_pathing_data(int ilev,di_node_t node)10200Sstevel@tonic-gate dump_pathing_data(int ilev, di_node_t node)
10210Sstevel@tonic-gate {
10226640Scth di_path_t pi = DI_PATH_NIL;
10236640Scth di_node_t phci_node;
10246640Scth char *phci_path;
10256640Scth int path_instance;
10266640Scth int firsttime = 1;
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate if (node == DI_PATH_NIL)
10290Sstevel@tonic-gate return;
10300Sstevel@tonic-gate
10316640Scth while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) {
1032*10696SDavid.Hollister@Sun.COM
1033*10696SDavid.Hollister@Sun.COM /* It is not really a path if we failed to capture the pHCI */
1034*10696SDavid.Hollister@Sun.COM phci_node = di_path_phci_node(pi);
1035*10696SDavid.Hollister@Sun.COM if (phci_node == DI_NODE_NIL)
1036*10696SDavid.Hollister@Sun.COM continue;
1037*10696SDavid.Hollister@Sun.COM
1038*10696SDavid.Hollister@Sun.COM /* Print header for the first path */
10390Sstevel@tonic-gate if (firsttime) {
10400Sstevel@tonic-gate indent_to_level(ilev);
10410Sstevel@tonic-gate firsttime = 0;
10420Sstevel@tonic-gate ilev++;
10430Sstevel@tonic-gate (void) printf("Paths from multipath bus adapters:\n");
10440Sstevel@tonic-gate }
10450Sstevel@tonic-gate
10466640Scth /*
10476640Scth * Print the path instance and full "pathinfo" path, which is
10486640Scth * the same as the /devices devifo path had the device been
10496640Scth * enumerated under pHCI.
10506640Scth */
10516640Scth phci_path = di_devfs_path(phci_node);
10526640Scth if (phci_path) {
1053*10696SDavid.Hollister@Sun.COM path_instance = di_path_instance(pi);
10546640Scth if (path_instance > 0) {
10556640Scth indent_to_level(ilev);
10566640Scth (void) printf("Path %d: %s/%s@%s\n",
10576640Scth path_instance, phci_path,
10586640Scth di_node_name(node),
10596640Scth di_path_bus_addr(pi));
10606640Scth }
10616640Scth di_devfs_path_free(phci_path);
10626640Scth }
10636640Scth
10646640Scth /* print phci driver, instance, and path state information */
10650Sstevel@tonic-gate indent_to_level(ilev);
10660Sstevel@tonic-gate (void) printf("%s#%d (%s)\n", di_driver_name(phci_node),
10670Sstevel@tonic-gate di_instance(phci_node), path_state_name(di_path_state(pi)));
1068*10696SDavid.Hollister@Sun.COM
10697224Scth (void) dump_prop_list(&pathprop_dumpops, NULL, ilev + 1,
10707261Scth pi, DDI_DEV_T_ANY, NULL);
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate static int
dump_minor_data_links(di_devlink_t devlink,void * arg)10750Sstevel@tonic-gate dump_minor_data_links(di_devlink_t devlink, void *arg)
10760Sstevel@tonic-gate {
10770Sstevel@tonic-gate int ilev = (intptr_t)arg;
10780Sstevel@tonic-gate indent_to_level(ilev);
10790Sstevel@tonic-gate (void) printf("dev_link=%s\n", di_devlink_path(devlink));
10800Sstevel@tonic-gate return (DI_WALK_CONTINUE);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate static void
dump_minor_data_paths(int ilev,di_minor_t minor,di_devlink_handle_t devlink_hdl)10840Sstevel@tonic-gate dump_minor_data_paths(int ilev, di_minor_t minor,
10850Sstevel@tonic-gate di_devlink_handle_t devlink_hdl)
10860Sstevel@tonic-gate {
10870Sstevel@tonic-gate char *path, *type;
10880Sstevel@tonic-gate int spec_type;
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate /* get the path to the device and the minor node name */
10910Sstevel@tonic-gate if ((path = di_devfs_minor_path(minor)) == NULL)
10920Sstevel@tonic-gate exit(_error("failed to allocate memory"));
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate /* display the path to this minor node */
10950Sstevel@tonic-gate indent_to_level(ilev);
10960Sstevel@tonic-gate (void) printf("dev_path=%s\n", path);
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate if (devlink_hdl != NULL) {
10990Sstevel@tonic-gate
11000Sstevel@tonic-gate /* get the device minor node information */
11010Sstevel@tonic-gate spec_type = di_minor_spectype(minor);
11020Sstevel@tonic-gate switch (di_minor_type(minor)) {
11030Sstevel@tonic-gate case DDM_MINOR:
11040Sstevel@tonic-gate type = "minor";
11050Sstevel@tonic-gate break;
11060Sstevel@tonic-gate case DDM_ALIAS:
11070Sstevel@tonic-gate type = "alias";
11080Sstevel@tonic-gate break;
11090Sstevel@tonic-gate case DDM_DEFAULT:
11100Sstevel@tonic-gate type = "default";
11110Sstevel@tonic-gate break;
11120Sstevel@tonic-gate case DDM_INTERNAL_PATH:
11130Sstevel@tonic-gate type = "internal";
11140Sstevel@tonic-gate break;
11150Sstevel@tonic-gate default:
11160Sstevel@tonic-gate type = "unknown";
11170Sstevel@tonic-gate break;
11180Sstevel@tonic-gate }
11190Sstevel@tonic-gate
11200Sstevel@tonic-gate /* display the device minor node information */
11210Sstevel@tonic-gate indent_to_level(ilev + 1);
11220Sstevel@tonic-gate (void) printf("spectype=%s type=%s\n",
11234453Scth (spec_type == S_IFBLK) ? "blk" : "chr", type);
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate /* display all the devlinks for this device minor node */
11260Sstevel@tonic-gate (void) di_devlink_walk(devlink_hdl, NULL, path,
11270Sstevel@tonic-gate 0, (void *)(intptr_t)(ilev + 1), dump_minor_data_links);
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate di_devfs_path_free(path);
11310Sstevel@tonic-gate }
11320Sstevel@tonic-gate
11330Sstevel@tonic-gate static void
create_minor_list(di_node_t node)11340Sstevel@tonic-gate create_minor_list(di_node_t node)
11350Sstevel@tonic-gate {
11360Sstevel@tonic-gate di_minor_t minor, minor_head, minor_tail, minor_prev, minor_walk;
11370Sstevel@tonic-gate int major;
11380Sstevel@tonic-gate
11390Sstevel@tonic-gate /* if there are no minor nodes, bail */
11400Sstevel@tonic-gate if (di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL)
11410Sstevel@tonic-gate return;
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate /*
11440Sstevel@tonic-gate * here we want to create lists of minor nodes with the same
11450Sstevel@tonic-gate * dev_t. to do this we first sort all the minor nodes by devt.
11460Sstevel@tonic-gate *
11470Sstevel@tonic-gate * the algorithm used here is a bubble sort, so performance sucks.
11480Sstevel@tonic-gate * but it's probably ok here because most device instances don't
11490Sstevel@tonic-gate * have that many minor nodes. also we're doing this as we're
11500Sstevel@tonic-gate * displaying each node so it doesn't look like we're pausing
11510Sstevel@tonic-gate * output for a long time.
11520Sstevel@tonic-gate */
11530Sstevel@tonic-gate major = di_driver_major(node);
11540Sstevel@tonic-gate minor_head = minor_tail = minor = DI_MINOR_NIL;
11550Sstevel@tonic-gate while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
11560Sstevel@tonic-gate dev_t dev = di_minor_devt(minor);
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate /* skip /pseudo/clone@0 minor nodes */
11590Sstevel@tonic-gate if (major != major(dev))
11600Sstevel@tonic-gate continue;
11610Sstevel@tonic-gate
11620Sstevel@tonic-gate minor_ptr_set(minor, DI_MINOR_NIL);
11630Sstevel@tonic-gate if (minor_head == DI_MINOR_NIL) {
11640Sstevel@tonic-gate /* this is the first minor node we're looking at */
11650Sstevel@tonic-gate minor_head = minor_tail = minor;
11660Sstevel@tonic-gate continue;
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate /*
11700Sstevel@tonic-gate * if the new dev is less than the old dev, update minor_head
11710Sstevel@tonic-gate * so it points to the beginning of the list. ie it points
11720Sstevel@tonic-gate * to the node with the lowest dev value
11730Sstevel@tonic-gate */
11740Sstevel@tonic-gate if (dev <= di_minor_devt(minor_head)) {
11750Sstevel@tonic-gate minor_ptr_set(minor, minor_head);
11760Sstevel@tonic-gate minor_head = minor;
11770Sstevel@tonic-gate continue;
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate
11800Sstevel@tonic-gate minor_prev = minor_head;
11810Sstevel@tonic-gate minor_walk = minor_ptr(minor_head);
11820Sstevel@tonic-gate while ((minor_walk != DI_MINOR_NIL) &&
11834453Scth (dev > di_minor_devt(minor_walk))) {
11840Sstevel@tonic-gate minor_prev = minor_walk;
11850Sstevel@tonic-gate minor_walk = minor_ptr(minor_walk);
11860Sstevel@tonic-gate }
11870Sstevel@tonic-gate minor_ptr_set(minor, minor_walk);
11880Sstevel@tonic-gate minor_ptr_set(minor_prev, minor);
11890Sstevel@tonic-gate if (minor_walk == NULL)
11900Sstevel@tonic-gate minor_tail = minor;
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /* check if there were any non /pseudo/clone@0 nodes. if not, bail */
11940Sstevel@tonic-gate if (minor_head == DI_MINOR_NIL)
11950Sstevel@tonic-gate return;
11960Sstevel@tonic-gate
11970Sstevel@tonic-gate /*
11980Sstevel@tonic-gate * now that we have a list of minor nodes sorted by devt
11990Sstevel@tonic-gate * we walk through the list and break apart the entire list
12000Sstevel@tonic-gate * to create circular lists of minor nodes with matching devts.
12010Sstevel@tonic-gate */
12020Sstevel@tonic-gate minor_prev = minor_head;
12030Sstevel@tonic-gate minor_walk = minor_ptr(minor_head);
12040Sstevel@tonic-gate while (minor_walk != DI_MINOR_NIL) {
12050Sstevel@tonic-gate if (di_minor_devt(minor_prev) != di_minor_devt(minor_walk)) {
12060Sstevel@tonic-gate minor_ptr_set(minor_prev, minor_head);
12070Sstevel@tonic-gate minor_head = minor_walk;
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate minor_prev = minor_walk;
12100Sstevel@tonic-gate minor_walk = minor_ptr(minor_walk);
12110Sstevel@tonic-gate }
12120Sstevel@tonic-gate minor_ptr_set(minor_tail, minor_head);
12130Sstevel@tonic-gate }
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate static void
link_lnode_disp(di_link_t link,uint_t endpoint,int ilev,di_devlink_handle_t devlink_hdl)12160Sstevel@tonic-gate link_lnode_disp(di_link_t link, uint_t endpoint, int ilev,
12170Sstevel@tonic-gate di_devlink_handle_t devlink_hdl)
12180Sstevel@tonic-gate {
12190Sstevel@tonic-gate di_lnode_t lnode;
12200Sstevel@tonic-gate char *name, *path;
12210Sstevel@tonic-gate int displayed_path, spec_type;
12220Sstevel@tonic-gate di_node_t node = DI_NODE_NIL;
12230Sstevel@tonic-gate dev_t devt = DDI_DEV_T_NONE;
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate lnode = di_link_to_lnode(link, endpoint);
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate indent_to_level(ilev);
12280Sstevel@tonic-gate name = di_lnode_name(lnode);
12290Sstevel@tonic-gate spec_type = di_link_spectype(link);
12300Sstevel@tonic-gate
12310Sstevel@tonic-gate (void) printf("mod=%s", name);
12320Sstevel@tonic-gate
12330Sstevel@tonic-gate /*
12340Sstevel@tonic-gate * if we're displaying the source of a link, we should display
12350Sstevel@tonic-gate * the target access mode. (either block or char.)
12360Sstevel@tonic-gate */
12370Sstevel@tonic-gate if (endpoint == DI_LINK_SRC)
12380Sstevel@tonic-gate (void) printf(" accesstype=%s",
12390Sstevel@tonic-gate (spec_type == S_IFBLK) ? "blk" : "chr");
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate /*
12420Sstevel@tonic-gate * check if the lnode is bound to a specific device
12430Sstevel@tonic-gate * minor node (i.e. if it's bound to a dev_t) and
12440Sstevel@tonic-gate * if so display the dev_t value and any possible
12450Sstevel@tonic-gate * minor node pathing information.
12460Sstevel@tonic-gate */
12470Sstevel@tonic-gate displayed_path = 0;
12480Sstevel@tonic-gate if (di_lnode_devt(lnode, &devt) == 0) {
12490Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL;
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate (void) printf(" dev=(%u,%u)\n",
12520Sstevel@tonic-gate (uint_t)major(devt), (uint_t)minor(devt));
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate /* display paths to the src devt minor node */
12550Sstevel@tonic-gate while (minor = di_minor_next(node, minor)) {
12560Sstevel@tonic-gate if (devt != di_minor_devt(minor))
12570Sstevel@tonic-gate continue;
12580Sstevel@tonic-gate
12590Sstevel@tonic-gate if ((endpoint == DI_LINK_TGT) &&
12600Sstevel@tonic-gate (spec_type != di_minor_spectype(minor)))
12610Sstevel@tonic-gate continue;
12620Sstevel@tonic-gate
12630Sstevel@tonic-gate dump_minor_data_paths(ilev + 1, minor, devlink_hdl);
12640Sstevel@tonic-gate displayed_path = 1;
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate } else {
12670Sstevel@tonic-gate (void) printf("\n");
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate
12700Sstevel@tonic-gate if (displayed_path)
12710Sstevel@tonic-gate return;
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate /*
12740Sstevel@tonic-gate * This device lnode is not did not have any minor node
12750Sstevel@tonic-gate * pathing information so display the path to device node.
12760Sstevel@tonic-gate */
12770Sstevel@tonic-gate node = di_lnode_devinfo(lnode);
12780Sstevel@tonic-gate if ((path = di_devfs_path(node)) == NULL)
12790Sstevel@tonic-gate exit(_error("failed to allocate memory"));
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate indent_to_level(ilev + 1);
12820Sstevel@tonic-gate (void) printf("dev_path=%s\n", path);
12830Sstevel@tonic-gate di_devfs_path_free(path);
12840Sstevel@tonic-gate }
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate static void
dump_minor_link_data(int ilev,di_node_t node,dev_t devt,di_devlink_handle_t devlink_hdl)12870Sstevel@tonic-gate dump_minor_link_data(int ilev, di_node_t node, dev_t devt,
12880Sstevel@tonic-gate di_devlink_handle_t devlink_hdl)
12890Sstevel@tonic-gate {
12900Sstevel@tonic-gate int first = 1;
12910Sstevel@tonic-gate di_link_t link;
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate link = DI_LINK_NIL;
12940Sstevel@tonic-gate while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) {
12950Sstevel@tonic-gate di_lnode_t tgt_lnode;
12960Sstevel@tonic-gate dev_t tgt_devt = DDI_DEV_T_NONE;
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate tgt_lnode = di_link_to_lnode(link, DI_LINK_TGT);
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate if (di_lnode_devt(tgt_lnode, &tgt_devt) != 0)
13010Sstevel@tonic-gate continue;
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate if (devt != tgt_devt)
13040Sstevel@tonic-gate continue;
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate if (first) {
13070Sstevel@tonic-gate first = 0;
13080Sstevel@tonic-gate indent_to_level(ilev);
13090Sstevel@tonic-gate (void) printf("Device Minor Layered Under:\n");
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate /* displayed this lnode */
13130Sstevel@tonic-gate lnode_displayed_set(tgt_lnode);
13140Sstevel@tonic-gate link_lnode_disp(link, DI_LINK_SRC, ilev + 1, devlink_hdl);
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate link = DI_LINK_NIL;
13180Sstevel@tonic-gate while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) {
13190Sstevel@tonic-gate di_lnode_t src_lnode;
13200Sstevel@tonic-gate dev_t src_devt = DDI_DEV_T_NONE;
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
13230Sstevel@tonic-gate
13240Sstevel@tonic-gate if (di_lnode_devt(src_lnode, &src_devt) != 0)
13250Sstevel@tonic-gate continue;
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate if (devt != src_devt)
13280Sstevel@tonic-gate continue;
13290Sstevel@tonic-gate
13300Sstevel@tonic-gate if (first) {
13310Sstevel@tonic-gate first = 0;
13320Sstevel@tonic-gate indent_to_level(ilev);
13330Sstevel@tonic-gate (void) printf("Device Minor Layered Over:\n");
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate
13360Sstevel@tonic-gate /* displayed this lnode */
13370Sstevel@tonic-gate lnode_displayed_set(src_lnode);
13380Sstevel@tonic-gate link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate static void
dump_minor_data(int ilev,di_node_t node,di_devlink_handle_t devlink_hdl)13430Sstevel@tonic-gate dump_minor_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
13440Sstevel@tonic-gate {
13450Sstevel@tonic-gate di_minor_t minor, minor_next;
13460Sstevel@tonic-gate di_lnode_t lnode;
13470Sstevel@tonic-gate di_link_t link;
13480Sstevel@tonic-gate int major, firstminor = 1;
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate /*
13510Sstevel@tonic-gate * first go through and mark all lnodes and minor nodes for this
13520Sstevel@tonic-gate * node as undisplayed
13530Sstevel@tonic-gate */
13540Sstevel@tonic-gate lnode = DI_LNODE_NIL;
13550Sstevel@tonic-gate while (lnode = di_lnode_next(node, lnode))
13560Sstevel@tonic-gate lnode_displayed_clear(lnode);
13570Sstevel@tonic-gate minor = DI_MINOR_NIL;
13580Sstevel@tonic-gate while (minor = di_minor_next(node, minor)) {
13590Sstevel@tonic-gate minor_displayed_clear(minor);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate /*
13630Sstevel@tonic-gate * when we display the minor nodes we want to coalesce nodes
13640Sstevel@tonic-gate * that have the same dev_t. we do this by creating circular
13650Sstevel@tonic-gate * lists of minor nodes with the same devt.
13660Sstevel@tonic-gate */
13670Sstevel@tonic-gate create_minor_list(node);
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate /* now we display the driver defined minor nodes */
13700Sstevel@tonic-gate major = di_driver_major(node);
13710Sstevel@tonic-gate minor = DI_MINOR_NIL;
13720Sstevel@tonic-gate while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
13730Sstevel@tonic-gate dev_t devt;
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate /*
13760Sstevel@tonic-gate * skip /pseudo/clone@0 minor nodes.
13770Sstevel@tonic-gate * these are only created for DLPIv2 network devices.
13780Sstevel@tonic-gate * since these minor nodes are associated with a driver
13790Sstevel@tonic-gate * and are only bound to a device instance after they
13800Sstevel@tonic-gate * are opened and attached we don't print them out
13810Sstevel@tonic-gate * here.
13820Sstevel@tonic-gate */
13830Sstevel@tonic-gate devt = di_minor_devt(minor);
13840Sstevel@tonic-gate if (major != major(devt))
13850Sstevel@tonic-gate continue;
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate /* skip nodes that may have already been displayed */
13880Sstevel@tonic-gate if (minor_displayed(minor))
13890Sstevel@tonic-gate continue;
13900Sstevel@tonic-gate
13910Sstevel@tonic-gate if (firstminor) {
13920Sstevel@tonic-gate firstminor = 0;
13930Sstevel@tonic-gate indent_to_level(ilev++);
13940Sstevel@tonic-gate (void) printf("Device Minor Nodes:\n");
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate /* display the device minor node information */
13980Sstevel@tonic-gate indent_to_level(ilev);
13990Sstevel@tonic-gate (void) printf("dev=(%u,%u)\n",
14004453Scth (uint_t)major(devt), (uint_t)minor(devt));
14010Sstevel@tonic-gate
14020Sstevel@tonic-gate minor_next = minor;
14030Sstevel@tonic-gate do {
14040Sstevel@tonic-gate /* display device minor node path info */
14050Sstevel@tonic-gate minor_displayed_set(minor_next);
14060Sstevel@tonic-gate dump_minor_data_paths(ilev + 1, minor_next,
14074453Scth devlink_hdl);
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate /* get a pointer to the next node */
14100Sstevel@tonic-gate minor_next = minor_ptr(minor_next);
14110Sstevel@tonic-gate } while (minor_next != minor);
14120Sstevel@tonic-gate
14130Sstevel@tonic-gate /* display who has this device minor node open */
14140Sstevel@tonic-gate dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
14157224Scth
14167224Scth /* display properties associated with this devt */
14177224Scth (void) dump_prop_list(&drvprop_dumpops, "Minor",
14187261Scth ilev + 1, node, devt, NULL);
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate /*
14220Sstevel@tonic-gate * now go through all the target lnodes for this node and
14230Sstevel@tonic-gate * if they haven't yet been displayed, display them now.
14240Sstevel@tonic-gate *
14250Sstevel@tonic-gate * this happens in the case of clone opens when an "official"
14260Sstevel@tonic-gate * minor node does not exist for the opened devt
14270Sstevel@tonic-gate */
14280Sstevel@tonic-gate link = DI_LINK_NIL;
14290Sstevel@tonic-gate while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) {
14300Sstevel@tonic-gate dev_t devt;
14310Sstevel@tonic-gate
14320Sstevel@tonic-gate lnode = di_link_to_lnode(link, DI_LINK_TGT);
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate /* if we've already displayed this target lnode, skip it */
14350Sstevel@tonic-gate if (lnode_displayed(lnode))
14360Sstevel@tonic-gate continue;
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate if (firstminor) {
14390Sstevel@tonic-gate firstminor = 0;
14400Sstevel@tonic-gate indent_to_level(ilev++);
14410Sstevel@tonic-gate (void) printf("Device Minor Nodes:\n");
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate
14440Sstevel@tonic-gate /* display the device minor node information */
14450Sstevel@tonic-gate indent_to_level(ilev);
14460Sstevel@tonic-gate (void) di_lnode_devt(lnode, &devt);
14470Sstevel@tonic-gate (void) printf("dev=(%u,%u)\n",
14484453Scth (uint_t)major(devt), (uint_t)minor(devt));
14490Sstevel@tonic-gate
14500Sstevel@tonic-gate indent_to_level(ilev + 1);
14510Sstevel@tonic-gate (void) printf("dev_path=<clone>\n");
14520Sstevel@tonic-gate
14530Sstevel@tonic-gate /* display who has this cloned device minor node open */
14540Sstevel@tonic-gate dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate /* mark node as displayed */
14570Sstevel@tonic-gate lnode_displayed_set(lnode);
14580Sstevel@tonic-gate }
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate static void
dump_link_data(int ilev,di_node_t node,di_devlink_handle_t devlink_hdl)14620Sstevel@tonic-gate dump_link_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
14630Sstevel@tonic-gate {
14640Sstevel@tonic-gate int first = 1;
14650Sstevel@tonic-gate di_link_t link;
14660Sstevel@tonic-gate
14670Sstevel@tonic-gate link = DI_LINK_NIL;
14680Sstevel@tonic-gate while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) {
14690Sstevel@tonic-gate di_lnode_t src_lnode;
14700Sstevel@tonic-gate dev_t src_devt = DDI_DEV_T_NONE;
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate /*
14750Sstevel@tonic-gate * here we only want to print out layering information
14760Sstevel@tonic-gate * if we are the source and our source lnode is not
14770Sstevel@tonic-gate * associated with any particular dev_t. (which means
14780Sstevel@tonic-gate * we won't display this link while dumping minor node
14790Sstevel@tonic-gate * info.)
14800Sstevel@tonic-gate */
14810Sstevel@tonic-gate if (di_lnode_devt(src_lnode, &src_devt) != -1)
14820Sstevel@tonic-gate continue;
14830Sstevel@tonic-gate
14840Sstevel@tonic-gate if (first) {
14850Sstevel@tonic-gate first = 0;
14860Sstevel@tonic-gate indent_to_level(ilev);
14870Sstevel@tonic-gate (void) printf("Device Layered Over:\n");
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate /* displayed this lnode */
14910Sstevel@tonic-gate link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate /*
14960Sstevel@tonic-gate * certain 'known' property names may contain 'composite' strings.
14970Sstevel@tonic-gate * Handle them here, and print them as 'string1' + 'string2' ...
14980Sstevel@tonic-gate */
14990Sstevel@tonic-gate static int
print_composite_string(const char * var,char * value,int size)15000Sstevel@tonic-gate print_composite_string(const char *var, char *value, int size)
15010Sstevel@tonic-gate {
15020Sstevel@tonic-gate char *p, *q;
15030Sstevel@tonic-gate char *firstp;
15040Sstevel@tonic-gate
15050Sstevel@tonic-gate if ((strcmp(var, "version") != 0) &&
15060Sstevel@tonic-gate (strcmp(var, "compatible") != 0))
15070Sstevel@tonic-gate return (0); /* Not a known composite string */
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate /*
15100Sstevel@tonic-gate * Verify that each string in the composite string is non-NULL,
15110Sstevel@tonic-gate * is within the bounds of the property length, and contains
15120Sstevel@tonic-gate * printable characters or white space. Otherwise let the
15130Sstevel@tonic-gate * caller deal with it.
15140Sstevel@tonic-gate */
15150Sstevel@tonic-gate for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
15160Sstevel@tonic-gate if (strlen(p) == 0)
15170Sstevel@tonic-gate return (0); /* NULL string */
15180Sstevel@tonic-gate for (q = p; *q; q++) {
15190Sstevel@tonic-gate if (!(isascii(*q) && (isprint(*q) || isspace(*q))))
15200Sstevel@tonic-gate return (0); /* Not printable or space */
15210Sstevel@tonic-gate }
15220Sstevel@tonic-gate if (q > (firstp + size))
15230Sstevel@tonic-gate return (0); /* Out of bounds */
15240Sstevel@tonic-gate }
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
15270Sstevel@tonic-gate if (p == firstp)
15280Sstevel@tonic-gate (void) printf("'%s'", p);
15290Sstevel@tonic-gate else
15300Sstevel@tonic-gate (void) printf(" + '%s'", p);
15310Sstevel@tonic-gate }
15320Sstevel@tonic-gate (void) putchar('\n');
15330Sstevel@tonic-gate return (1);
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate
15360Sstevel@tonic-gate /*
15370Sstevel@tonic-gate * Print one property and its value. Handle the verbose case.
15380Sstevel@tonic-gate */
15390Sstevel@tonic-gate static void
print_one(nvpair_t * nvp,int level)15400Sstevel@tonic-gate print_one(nvpair_t *nvp, int level)
15410Sstevel@tonic-gate {
15420Sstevel@tonic-gate int i;
15430Sstevel@tonic-gate int endswap = 0;
15440Sstevel@tonic-gate uint_t valsize;
15450Sstevel@tonic-gate char *value;
15460Sstevel@tonic-gate char *var = nvpair_name(nvp);
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate indent_to_level(level);
15490Sstevel@tonic-gate (void) printf("%s: ", var);
15500Sstevel@tonic-gate
15510Sstevel@tonic-gate switch (nvpair_type(nvp)) {
15520Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
15530Sstevel@tonic-gate (void) printf(" \n");
15540Sstevel@tonic-gate return;
15550Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
15560Sstevel@tonic-gate if (nvpair_value_byte_array(nvp, (uchar_t **)&value,
15570Sstevel@tonic-gate &valsize)) {
15580Sstevel@tonic-gate (void) printf("data not available.\n");
15590Sstevel@tonic-gate return;
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate valsize--; /* take out null added by driver */
15620Sstevel@tonic-gate
15630Sstevel@tonic-gate /*
15640Sstevel@tonic-gate * Do not print valsize > MAXVALSIZE, to be compatible
15650Sstevel@tonic-gate * with old behavior. E.g. intel's eisa-nvram property
15660Sstevel@tonic-gate * has a size of 65 K.
15670Sstevel@tonic-gate */
15680Sstevel@tonic-gate if (valsize > MAXVALSIZE) {
15690Sstevel@tonic-gate (void) printf(" \n");
15700Sstevel@tonic-gate return;
15710Sstevel@tonic-gate }
15720Sstevel@tonic-gate break;
15730Sstevel@tonic-gate default:
15740Sstevel@tonic-gate (void) printf("data type unexpected.\n");
15750Sstevel@tonic-gate return;
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate * Handle printing verbosely
15800Sstevel@tonic-gate */
15810Sstevel@tonic-gate if (print_composite_string(var, value, valsize)) {
15820Sstevel@tonic-gate return;
15830Sstevel@tonic-gate }
15840Sstevel@tonic-gate
15850Sstevel@tonic-gate if (!unprintable(value, valsize)) {
15860Sstevel@tonic-gate (void) printf(" '%s'\n", value);
15870Sstevel@tonic-gate return;
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate (void) printf(" ");
15910Sstevel@tonic-gate #ifdef __x86
15920Sstevel@tonic-gate /*
15930Sstevel@tonic-gate * Due to backwards compatibility constraints x86 int
15940Sstevel@tonic-gate * properties are not in big-endian (ieee 1275) byte order.
15950Sstevel@tonic-gate * If we have a property that is a multiple of 4 bytes,
15960Sstevel@tonic-gate * let's assume it is an array of ints and print the bytes
15970Sstevel@tonic-gate * in little endian order to make things look nicer for
15980Sstevel@tonic-gate * the user.
15990Sstevel@tonic-gate */
16000Sstevel@tonic-gate endswap = (valsize % 4) == 0;
16010Sstevel@tonic-gate #endif /* __x86 */
16020Sstevel@tonic-gate for (i = 0; i < valsize; i++) {
16030Sstevel@tonic-gate int out;
16040Sstevel@tonic-gate if (i && (i % 4 == 0))
16050Sstevel@tonic-gate (void) putchar('.');
16060Sstevel@tonic-gate if (endswap)
16070Sstevel@tonic-gate out = value[i + (3 - 2 * (i % 4))] & 0xff;
16080Sstevel@tonic-gate else
16090Sstevel@tonic-gate out = value[i] & 0xff;
16100Sstevel@tonic-gate
16110Sstevel@tonic-gate (void) printf("%02x", out);
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate (void) putchar('\n');
16140Sstevel@tonic-gate }
16150Sstevel@tonic-gate
16160Sstevel@tonic-gate static int
unprintable(char * value,int size)16170Sstevel@tonic-gate unprintable(char *value, int size)
16180Sstevel@tonic-gate {
16190Sstevel@tonic-gate int i;
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate /*
16220Sstevel@tonic-gate * Is this just a zero?
16230Sstevel@tonic-gate */
16240Sstevel@tonic-gate if (size == 0 || value[0] == '\0')
16250Sstevel@tonic-gate return (1);
16260Sstevel@tonic-gate /*
16270Sstevel@tonic-gate * If any character is unprintable, or if a null appears
16280Sstevel@tonic-gate * anywhere except at the end of a string, the whole
16290Sstevel@tonic-gate * property is "unprintable".
16300Sstevel@tonic-gate */
16310Sstevel@tonic-gate for (i = 0; i < size; ++i) {
16320Sstevel@tonic-gate if (value[i] == '\0')
16330Sstevel@tonic-gate return (i != (size - 1));
16340Sstevel@tonic-gate if (!isascii(value[i]) || iscntrl(value[i]))
16350Sstevel@tonic-gate return (1);
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate return (0);
16380Sstevel@tonic-gate }
16390Sstevel@tonic-gate
16400Sstevel@tonic-gate static int
promopen(int oflag)16410Sstevel@tonic-gate promopen(int oflag)
16420Sstevel@tonic-gate {
16430Sstevel@tonic-gate for (;;) {
16440Sstevel@tonic-gate if ((prom_fd = open(opts.o_promdev, oflag)) < 0) {
16450Sstevel@tonic-gate if (errno == EAGAIN) {
16460Sstevel@tonic-gate (void) sleep(5);
16470Sstevel@tonic-gate continue;
16480Sstevel@tonic-gate }
16490Sstevel@tonic-gate if (errno == ENXIO)
16500Sstevel@tonic-gate return (-1);
16510Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) {
16520Sstevel@tonic-gate _exit(_error("cannot open %s",
16530Sstevel@tonic-gate opts.o_promdev));
16540Sstevel@tonic-gate }
16550Sstevel@tonic-gate /* not an error if this isn't the global zone */
16560Sstevel@tonic-gate (void) _error(NULL, "openprom facility not available");
16570Sstevel@tonic-gate exit(0);
16580Sstevel@tonic-gate } else
16590Sstevel@tonic-gate return (0);
16600Sstevel@tonic-gate }
16610Sstevel@tonic-gate }
16620Sstevel@tonic-gate
16630Sstevel@tonic-gate static void
promclose(void)16640Sstevel@tonic-gate promclose(void)
16650Sstevel@tonic-gate {
16660Sstevel@tonic-gate if (close(prom_fd) < 0)
16670Sstevel@tonic-gate exit(_error("close error on %s", opts.o_promdev));
16680Sstevel@tonic-gate }
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate /*
16710Sstevel@tonic-gate * Get and print the name of the frame buffer device.
16720Sstevel@tonic-gate */
16730Sstevel@tonic-gate int
do_fbname(void)16740Sstevel@tonic-gate do_fbname(void)
16750Sstevel@tonic-gate {
16760Sstevel@tonic-gate int retval;
16770Sstevel@tonic-gate char fbuf_path[MAXPATHLEN];
16780Sstevel@tonic-gate
16790Sstevel@tonic-gate retval = modctl(MODGETFBNAME, (caddr_t)fbuf_path);
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate if (retval == 0) {
16820Sstevel@tonic-gate (void) printf("%s\n", fbuf_path);
16830Sstevel@tonic-gate } else {
16840Sstevel@tonic-gate if (retval == EFAULT) {
16850Sstevel@tonic-gate (void) fprintf(stderr,
16860Sstevel@tonic-gate "Error copying fb path to userland\n");
16870Sstevel@tonic-gate } else {
16880Sstevel@tonic-gate (void) fprintf(stderr,
16890Sstevel@tonic-gate "Console output device is not a frame buffer\n");
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate return (1);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate return (0);
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate
16960Sstevel@tonic-gate /*
16970Sstevel@tonic-gate * Get and print the PROM version.
16980Sstevel@tonic-gate */
16990Sstevel@tonic-gate int
do_promversion(void)17000Sstevel@tonic-gate do_promversion(void)
17010Sstevel@tonic-gate {
17020Sstevel@tonic-gate Oppbuf oppbuf;
17030Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate if (promopen(O_RDONLY)) {
17060Sstevel@tonic-gate (void) fprintf(stderr, "Cannot open openprom device\n");
17070Sstevel@tonic-gate return (1);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate
17100Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
17110Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETVERSION, opp) < 0)
17120Sstevel@tonic-gate exit(_error("OPROMGETVERSION"));
17130Sstevel@tonic-gate
17140Sstevel@tonic-gate (void) printf("%s\n", opp->oprom_array);
17150Sstevel@tonic-gate promclose();
17160Sstevel@tonic-gate return (0);
17170Sstevel@tonic-gate }
17180Sstevel@tonic-gate
17190Sstevel@tonic-gate int
do_prom_version64(void)17200Sstevel@tonic-gate do_prom_version64(void)
17210Sstevel@tonic-gate {
17220Sstevel@tonic-gate #ifdef sparc
17230Sstevel@tonic-gate Oppbuf oppbuf;
17240Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
17250Sstevel@tonic-gate /*LINTED*/
17260Sstevel@tonic-gate struct openprom_opr64 *opr = (struct openprom_opr64 *)opp->oprom_array;
17270Sstevel@tonic-gate
17280Sstevel@tonic-gate static const char msg[] =
17294453Scth "NOTICE: The firmware on this system does not support the "
17304453Scth "64-bit OS.\n"
17314453Scth "\tPlease upgrade to at least the following version:\n"
17324453Scth "\t\t%s\n\n";
17330Sstevel@tonic-gate
17340Sstevel@tonic-gate if (promopen(O_RDONLY)) {
17350Sstevel@tonic-gate (void) fprintf(stderr, "Cannot open openprom device\n");
17360Sstevel@tonic-gate return (-1);
17370Sstevel@tonic-gate }
17380Sstevel@tonic-gate
17390Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
17400Sstevel@tonic-gate if (ioctl(prom_fd, OPROMREADY64, opp) < 0)
17410Sstevel@tonic-gate exit(_error("OPROMREADY64"));
17420Sstevel@tonic-gate
17430Sstevel@tonic-gate if (opr->return_code == 0)
17440Sstevel@tonic-gate return (0);
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate (void) printf(msg, opr->message);
17470Sstevel@tonic-gate
17480Sstevel@tonic-gate promclose();
17490Sstevel@tonic-gate return (opr->return_code);
17500Sstevel@tonic-gate #else
17510Sstevel@tonic-gate return (0);
17520Sstevel@tonic-gate #endif
17530Sstevel@tonic-gate }
17540Sstevel@tonic-gate
17550Sstevel@tonic-gate int
do_productinfo(void)17560Sstevel@tonic-gate do_productinfo(void)
17570Sstevel@tonic-gate {
17580Sstevel@tonic-gate di_node_t root, next_node;
17590Sstevel@tonic-gate di_prom_handle_t promh;
17600Sstevel@tonic-gate static const char *root_prop[] = { "name", "model", "banner-name",
17610Sstevel@tonic-gate "compatible" };
17620Sstevel@tonic-gate static const char *root_propv[] = { "name", "model", "banner-name",
17630Sstevel@tonic-gate "compatible", "idprom" };
17640Sstevel@tonic-gate static const char *oprom_prop[] = { "model", "version" };
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate root = di_init("/", DINFOCPYALL);
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate if (root == DI_NODE_NIL) {
17700Sstevel@tonic-gate (void) fprintf(stderr, "di_init() failed\n");
17710Sstevel@tonic-gate return (1);
17720Sstevel@tonic-gate }
17730Sstevel@tonic-gate
17740Sstevel@tonic-gate promh = di_prom_init();
17750Sstevel@tonic-gate
17760Sstevel@tonic-gate if (promh == DI_PROM_HANDLE_NIL) {
17770Sstevel@tonic-gate (void) fprintf(stderr, "di_prom_init() failed\n");
17780Sstevel@tonic-gate return (1);
17790Sstevel@tonic-gate }
17800Sstevel@tonic-gate
17810Sstevel@tonic-gate if (opts.o_verbose) {
17820Sstevel@tonic-gate dump_prodinfo(promh, root, root_propv, "root",
17834453Scth NUM_ELEMENTS(root_propv));
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate /* Get model and version properties under node "openprom" */
17860Sstevel@tonic-gate next_node = find_node_by_name(promh, root, "openprom");
17870Sstevel@tonic-gate if (next_node != DI_NODE_NIL)
17880Sstevel@tonic-gate dump_prodinfo(promh, next_node, oprom_prop,
17894453Scth "openprom", NUM_ELEMENTS(oprom_prop));
17900Sstevel@tonic-gate
17910Sstevel@tonic-gate } else
17920Sstevel@tonic-gate dump_prodinfo(promh, root, root_prop, "root",
17934453Scth NUM_ELEMENTS(root_prop));
17940Sstevel@tonic-gate di_prom_fini(promh);
17950Sstevel@tonic-gate di_fini(root);
17960Sstevel@tonic-gate return (0);
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate di_node_t
find_node_by_name(di_prom_handle_t promh,di_node_t parent,char * node_name)18000Sstevel@tonic-gate find_node_by_name(di_prom_handle_t promh, di_node_t parent,
18010Sstevel@tonic-gate char *node_name)
18020Sstevel@tonic-gate {
18030Sstevel@tonic-gate di_node_t next_node;
18040Sstevel@tonic-gate uchar_t *prop_valp;
18050Sstevel@tonic-gate
18064900Svb160487 for (next_node = di_child_node(parent); next_node != DI_NODE_NIL;
18074900Svb160487 next_node = di_sibling_node(next_node)) {
18084900Svb160487 int len;
18094900Svb160487
18104900Svb160487 len = get_propval_by_name(promh, next_node, "name", &prop_valp);
18114900Svb160487 if ((len != -1) && (strcmp((char *)prop_valp, node_name) == 0))
18120Sstevel@tonic-gate return (next_node);
18130Sstevel@tonic-gate }
18140Sstevel@tonic-gate return (DI_NODE_NIL);
18150Sstevel@tonic-gate }
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate int
get_propval_by_name(di_prom_handle_t promh,di_node_t node,const char * name,uchar_t ** valp)18190Sstevel@tonic-gate get_propval_by_name(di_prom_handle_t promh, di_node_t node, const char *name,
18200Sstevel@tonic-gate uchar_t **valp)
18210Sstevel@tonic-gate {
18220Sstevel@tonic-gate int len;
18230Sstevel@tonic-gate uchar_t *bufp;
18240Sstevel@tonic-gate
18250Sstevel@tonic-gate len = di_prom_prop_lookup_bytes(promh, node, name,
18264453Scth (uchar_t **)&bufp);
18270Sstevel@tonic-gate if (len != -1) {
18280Sstevel@tonic-gate *valp = (uchar_t *)malloc(len);
18290Sstevel@tonic-gate (void) memcpy(*valp, bufp, len);
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate return (len);
18320Sstevel@tonic-gate }
18330Sstevel@tonic-gate
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate static void
dump_prodinfo(di_prom_handle_t promh,di_node_t node,const char ** propstr,char * node_name,int num)18360Sstevel@tonic-gate dump_prodinfo(di_prom_handle_t promh, di_node_t node, const char **propstr,
18370Sstevel@tonic-gate char *node_name, int num)
18380Sstevel@tonic-gate {
18390Sstevel@tonic-gate int out, len, index1, index, endswap = 0;
18400Sstevel@tonic-gate uchar_t *prop_valp;
18410Sstevel@tonic-gate
18420Sstevel@tonic-gate for (index1 = 0; index1 < num; index1++) {
18430Sstevel@tonic-gate len = get_propval_by_name(promh, node, propstr[index1],
18444453Scth &prop_valp);
18450Sstevel@tonic-gate if (len != -1) {
18460Sstevel@tonic-gate if (strcmp(node_name, "root"))
18470Sstevel@tonic-gate (void) printf("%s ", node_name);
18480Sstevel@tonic-gate
18490Sstevel@tonic-gate (void) printf("%s: ", propstr[index1]);
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate if (print_composite_string((const char *)
18524453Scth propstr[index1], (char *)prop_valp, len)) {
18530Sstevel@tonic-gate free(prop_valp);
18540Sstevel@tonic-gate continue;
18550Sstevel@tonic-gate }
18560Sstevel@tonic-gate
18570Sstevel@tonic-gate if (!unprintable((char *)prop_valp, len)) {
18580Sstevel@tonic-gate (void) printf(" %s\n", (char *)prop_valp);
18590Sstevel@tonic-gate free(prop_valp);
18600Sstevel@tonic-gate continue;
18610Sstevel@tonic-gate }
18620Sstevel@tonic-gate
18630Sstevel@tonic-gate (void) printf(" ");
18640Sstevel@tonic-gate #ifdef __x86
18650Sstevel@tonic-gate endswap = (len % 4) == 0;
18660Sstevel@tonic-gate #endif /* __x86 */
18670Sstevel@tonic-gate for (index = 0; index < len; index++) {
18680Sstevel@tonic-gate if (index && (index % 4 == 0))
18690Sstevel@tonic-gate (void) putchar('.');
18700Sstevel@tonic-gate if (endswap)
18710Sstevel@tonic-gate out = prop_valp[index +
18724453Scth (3 - 2 * (index % 4))] & 0xff;
18730Sstevel@tonic-gate else
18740Sstevel@tonic-gate out = prop_valp[index] & 0xff;
18750Sstevel@tonic-gate (void) printf("%02x", out);
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate (void) putchar('\n');
18780Sstevel@tonic-gate free(prop_valp);
18790Sstevel@tonic-gate }
18800Sstevel@tonic-gate }
18810Sstevel@tonic-gate }
18827261Scth
18837261Scth static int
dump_compatible(char * name,int ilev,di_node_t node)18847261Scth dump_compatible(char *name, int ilev, di_node_t node)
18857261Scth {
18867261Scth int ncompat;
18877261Scth char *compat_array;
18887261Scth char *p, *q;
18897261Scth int i;
18907261Scth
18917261Scth if (node == DI_PATH_NIL)
18927261Scth return (0);
18937261Scth
18947261Scth ncompat = di_compatible_names(node, &compat_array);
18957261Scth if (ncompat <= 0)
18967261Scth return (0); /* no 'compatible' available */
18977261Scth
18987261Scth /* verify integrety of compat_array */
18997261Scth for (i = 0, p = compat_array; i < ncompat; i++, p += strlen(p) + 1) {
19007261Scth if (strlen(p) == 0)
19017261Scth return (0); /* NULL string */
19027261Scth for (q = p; *q; q++) {
19037261Scth if (!(isascii(*q) && (isprint(*q) || isspace(*q))))
19047261Scth return (0); /* Not printable or space */
19057261Scth }
19067261Scth }
19077261Scth
19087261Scth /* If name is non-NULL, produce header */
19097261Scth if (name) {
19107261Scth indent_to_level(ilev);
19117261Scth (void) printf("%s properties:\n", name);
19127261Scth }
19137261Scth ilev++;
19147261Scth
19157261Scth /* process like a string array property */
19167261Scth indent_to_level(ilev);
19177261Scth (void) printf("name='compatible' type=string items=%d\n", ncompat);
19187261Scth indent_to_level(ilev);
19197261Scth (void) printf(" value=");
19207261Scth for (i = 0, p = compat_array; i < (ncompat - 1);
19217261Scth i++, p += strlen(p) + 1)
19227261Scth (void) printf("'%s' + ", p);
19237261Scth (void) printf("'%s'", p);
19247261Scth (void) putchar('\n');
19257261Scth return (1);
19267261Scth }
1927