Home | History | Annotate | Download | only in prtconf
      1      0    stevel /*
      2      0    stevel  * CDDL HEADER START
      3      0    stevel  *
      4      0    stevel  * The contents of this file are subject to the terms of the
      5   4453       cth  * Common Development and Distribution License (the "License").
      6   4453       cth  * You may not use this file except in compliance with the License.
      7      0    stevel  *
      8      0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0    stevel  * or http://www.opensolaris.org/os/licensing.
     10      0    stevel  * See the License for the specific language governing permissions
     11      0    stevel  * and limitations under the License.
     12      0    stevel  *
     13      0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0    stevel  *
     19      0    stevel  * CDDL HEADER END
     20      0    stevel  */
     21      0    stevel /*
     22   9074      Judy  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0    stevel  * Use is subject to license terms.
     24      0    stevel  */
     25      0    stevel 
     26      0    stevel /*
     27      0    stevel  * For machines that support the openprom, fetch and print the list
     28      0    stevel  * of devices that the kernel has fetched from the prom or conjured up.
     29      0    stevel  */
     30      0    stevel 
     31      0    stevel #include <stdio.h>
     32      0    stevel #include <stdarg.h>
     33      0    stevel #include <stdlib.h>
     34      0    stevel #include <fcntl.h>
     35      0    stevel #include <ctype.h>
     36      0    stevel #include <strings.h>
     37      0    stevel #include <unistd.h>
     38      0    stevel #include <stropts.h>
     39      0    stevel #include <sys/types.h>
     40      0    stevel #include <sys/mkdev.h>
     41      0    stevel #include <sys/sunddi.h>
     42      0    stevel #include <sys/openpromio.h>
     43      0    stevel #include <sys/modctl.h>
     44      0    stevel #include <sys/stat.h>
     45      0    stevel #include <zone.h>
     46      0    stevel #include <libnvpair.h>
     47      0    stevel #include "prtconf.h"
     48      0    stevel 
     49      0    stevel 
     50      0    stevel typedef char *(*dump_propname_t)(void *);
     51      0    stevel typedef int (*dump_proptype_t)(void *);
     52      0    stevel typedef int (*dump_propints_t)(void *, int **);
     53      0    stevel typedef int (*dump_propint64_t)(void *, int64_t **);
     54      0    stevel typedef int (*dump_propstrings_t)(void *, char **);
     55      0    stevel typedef int (*dump_propbytes_t)(void *, uchar_t **);
     56      0    stevel typedef int (*dump_proprawdata_t)(void *, uchar_t **);
     57      0    stevel 
     58      0    stevel typedef struct dumpops_common {
     59      0    stevel 	dump_propname_t doc_propname;
     60      0    stevel 	dump_proptype_t doc_proptype;
     61      0    stevel 	dump_propints_t doc_propints;
     62      0    stevel 	dump_propint64_t doc_propint64;
     63      0    stevel 	dump_propstrings_t doc_propstrings;
     64      0    stevel 	dump_propbytes_t doc_propbytes;
     65      0    stevel 	dump_proprawdata_t doc_proprawdata;
     66      0    stevel } dumpops_common_t;
     67      0    stevel 
     68      0    stevel static const dumpops_common_t prop_dumpops = {
     69      0    stevel 	(dump_propname_t)di_prop_name,
     70      0    stevel 	(dump_proptype_t)di_prop_type,
     71      0    stevel 	(dump_propints_t)di_prop_ints,
     72      0    stevel 	(dump_propint64_t)di_prop_int64,
     73      0    stevel 	(dump_propstrings_t)di_prop_strings,
     74      0    stevel 	(dump_propbytes_t)di_prop_bytes,
     75      0    stevel 	(dump_proprawdata_t)di_prop_rawdata
     76      0    stevel }, pathprop_common_dumpops = {
     77      0    stevel 	(dump_propname_t)di_path_prop_name,
     78      0    stevel 	(dump_proptype_t)di_path_prop_type,
     79      0    stevel 	(dump_propints_t)di_path_prop_ints,
     80      0    stevel 	(dump_propint64_t)di_path_prop_int64s,
     81      0    stevel 	(dump_propstrings_t)di_path_prop_strings,
     82      0    stevel 	(dump_propbytes_t)di_path_prop_bytes,
     83      0    stevel 	(dump_proprawdata_t)di_path_prop_bytes
     84      0    stevel };
     85      0    stevel 
     86      0    stevel typedef void *(*dump_nextprop_t)(void *, void *);
     87      0    stevel typedef dev_t (*dump_propdevt_t)(void *);
     88      0    stevel 
     89      0    stevel typedef struct dumpops {
     90      0    stevel 	const dumpops_common_t *dop_common;
     91      0    stevel 	dump_nextprop_t dop_nextprop;
     92      0    stevel 	dump_propdevt_t dop_propdevt;
     93      0    stevel } dumpops_t;
     94      0    stevel 
     95   9074      Judy typedef struct di_args {
     96   9074      Judy 	di_prom_handle_t	prom_hdl;
     97   9074      Judy 	di_devlink_handle_t	devlink_hdl;
     98   9074      Judy } di_arg_t;
     99   9074      Judy 
    100      0    stevel static const dumpops_t sysprop_dumpops = {
    101      0    stevel 	&prop_dumpops,
    102      0    stevel 	(dump_nextprop_t)di_prop_sys_next,
    103      0    stevel 	NULL
    104      0    stevel }, globprop_dumpops = {
    105      0    stevel 	&prop_dumpops,
    106      0    stevel 	(dump_nextprop_t)di_prop_global_next,
    107      0    stevel 	NULL
    108      0    stevel }, drvprop_dumpops = {
    109      0    stevel 	&prop_dumpops,
    110      0    stevel 	(dump_nextprop_t)di_prop_drv_next,
    111      0    stevel 	(dump_propdevt_t)di_prop_devt
    112      0    stevel }, hwprop_dumpops = {
    113      0    stevel 	&prop_dumpops,
    114      0    stevel 	(dump_nextprop_t)di_prop_hw_next,
    115      0    stevel 	NULL
    116      0    stevel }, pathprop_dumpops = {
    117      0    stevel 	&pathprop_common_dumpops,
    118      0    stevel 	(dump_nextprop_t)di_path_prop_next,
    119      0    stevel 	NULL
    120      0    stevel };
    121      0    stevel 
    122      0    stevel #define	PROPNAME(ops) (ops->dop_common->doc_propname)
    123      0    stevel #define	PROPTYPE(ops) (ops->dop_common->doc_proptype)
    124      0    stevel #define	PROPINTS(ops) (ops->dop_common->doc_propints)
    125      0    stevel #define	PROPINT64(ops) (ops->dop_common->doc_propint64)
    126      0    stevel #define	PROPSTRINGS(ops) (ops->dop_common->doc_propstrings)
    127      0    stevel #define	PROPBYTES(ops) (ops->dop_common->doc_propbytes)
    128      0    stevel #define	PROPRAWDATA(ops) (ops->dop_common->doc_proprawdata)
    129      0    stevel #define	NEXTPROP(ops) (ops->dop_nextprop)
    130      0    stevel #define	PROPDEVT(ops) (ops->dop_propdevt)
    131      0    stevel #define	NUM_ELEMENTS(A) (sizeof (A) / sizeof (A[0]))
    132      0    stevel 
    133      0    stevel static int prop_type_guess(const dumpops_t *, void *, void **, int *);
    134   9074      Judy static void walk_driver(di_node_t, di_arg_t *);
    135      0    stevel static int dump_devs(di_node_t, void *);
    136   7224       cth static int dump_prop_list(const dumpops_t *, const char *,
    137   7261       cth 				int, void *, dev_t, int *);
    138      0    stevel static int _error(const char *, ...);
    139      0    stevel static int is_openprom();
    140      0    stevel static void walk(uchar_t *, uint_t, int);
    141      0    stevel static void dump_node(nvlist_t *, int);
    142      0    stevel static void dump_prodinfo(di_prom_handle_t, di_node_t, const char **,
    143      0    stevel 				char *, int);
    144      0    stevel static di_node_t find_node_by_name(di_prom_handle_t, di_node_t, char *);
    145      0    stevel static int get_propval_by_name(di_prom_handle_t, di_node_t,
    146      0    stevel 				const char *, uchar_t **);
    147   7261       cth static int dump_compatible(char *, int, di_node_t);
    148      0    stevel static void dump_pathing_data(int, di_node_t);
    149      0    stevel static void dump_minor_data(int, di_node_t, di_devlink_handle_t);
    150      0    stevel static void dump_link_data(int, di_node_t, di_devlink_handle_t);
    151      0    stevel static int print_composite_string(const char *, char *, int);
    152      0    stevel static void print_one(nvpair_t *, int);
    153      0    stevel static int unprintable(char *, int);
    154      0    stevel static int promopen(int);
    155      0    stevel static void promclose();
    156      0    stevel static di_node_t find_target_node(di_node_t);
    157      0    stevel static void node_display_set(di_node_t);
    158      0    stevel 
    159      0    stevel void
    160      0    stevel prtconf_devinfo(void)
    161      0    stevel {
    162      0    stevel 	struct di_priv_data	fetch;
    163   9074      Judy 	di_arg_t		di_arg;
    164   9074      Judy 	di_prom_handle_t	prom_hdl = DI_PROM_HANDLE_NIL;
    165      0    stevel 	di_devlink_handle_t	devlink_hdl = NULL;
    166      0    stevel 	di_node_t		root_node;
    167      0    stevel 	uint_t			flag;
    168      0    stevel 	char			*rootpath;
    169      0    stevel 
    170      0    stevel 	dprintf("verbosemode %s\n", opts.o_verbose ? "on" : "off");
    171      0    stevel 
    172      0    stevel 	/* determine what info we need to get from kernel */
    173      0    stevel 	flag = DINFOSUBTREE;
    174      0    stevel 	rootpath = "/";
    175      0    stevel 
    176      0    stevel 	if (opts.o_target) {
    177      0    stevel 		flag |= (DINFOMINOR | DINFOPATH);
    178   9074      Judy 	}
    179   9074      Judy 
    180   9074      Judy 	if (opts.o_pciid) {
    181   9074      Judy 		flag |= DINFOPROP;
    182   9074      Judy 		if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL)
    183   9074      Judy 			exit(_error("di_prom_init() failed."));
    184      0    stevel 	}
    185      0    stevel 
    186      0    stevel 	if (opts.o_forcecache) {
    187   4453       cth 		if (dbg.d_forceload) {
    188      0    stevel 			exit(_error(NULL, "option combination not supported"));
    189      0    stevel 		}
    190      0    stevel 		if (strcmp(rootpath, "/") != 0) {
    191      0    stevel 			exit(_error(NULL, "invalid root path for option"));
    192      0    stevel 		}
    193      0    stevel 		flag = DINFOCACHE;
    194   4453       cth 	} else if (opts.o_verbose) {
    195   4453       cth 		flag |= (DINFOPROP | DINFOMINOR |
    196   4453       cth 		    DINFOPRIVDATA | DINFOPATH | DINFOLYR);
    197      0    stevel 	}
    198      0    stevel 
    199      0    stevel 	if (dbg.d_forceload) {
    200      0    stevel 		flag |= DINFOFORCE;
    201      0    stevel 	}
    202      0    stevel 
    203      0    stevel 	if (opts.o_verbose) {
    204      0    stevel 		init_priv_data(&fetch);
    205      0    stevel 		root_node = di_init_impl(rootpath, flag, &fetch);
    206      0    stevel 
    207      0    stevel 		/* get devlink (aka aliases) data */
    208      0    stevel 		if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL)
    209      0    stevel 			exit(_error("di_devlink_init() failed."));
    210      0    stevel 	} else
    211      0    stevel 		root_node = di_init(rootpath, flag);
    212      0    stevel 
    213      0    stevel 	if (root_node == DI_NODE_NIL) {
    214      0    stevel 		(void) _error(NULL, "devinfo facility not available");
    215      0    stevel 		/* not an error if this isn't the global zone */
    216      0    stevel 		if (getzoneid() == GLOBAL_ZONEID)
    217      0    stevel 			exit(-1);
    218      0    stevel 		else
    219      0    stevel 			exit(0);
    220      0    stevel 	}
    221      0    stevel 
    222   9074      Judy 	di_arg.prom_hdl = prom_hdl;
    223   9074      Judy 	di_arg.devlink_hdl = devlink_hdl;
    224   9074      Judy 
    225      0    stevel 	/*
    226      0    stevel 	 * ...and walk all nodes to report them out...
    227      0    stevel 	 */
    228      0    stevel 	if (dbg.d_bydriver) {
    229      0    stevel 		opts.o_target = 0;
    230   9074      Judy 		walk_driver(root_node, &di_arg);
    231   9074      Judy 		if (prom_hdl != DI_PROM_HANDLE_NIL)
    232   9074      Judy 			di_prom_fini(prom_hdl);
    233      0    stevel 		if (devlink_hdl != NULL)
    234      0    stevel 			(void) di_devlink_fini(&devlink_hdl);
    235      0    stevel 		di_fini(root_node);
    236      0    stevel 		return;
    237      0    stevel 	}
    238      0    stevel 
    239      0    stevel 	if (opts.o_target) {
    240      0    stevel 		di_node_t target_node, node;
    241      0    stevel 
    242      0    stevel 		target_node = find_target_node(root_node);
    243      0    stevel 		if (target_node == DI_NODE_NIL) {
    244      0    stevel 			(void) fprintf(stderr, "%s: "
    245   4453       cth 			    "invalid device path specified\n",
    246   4453       cth 			    opts.o_progname);
    247      0    stevel 			exit(1);
    248      0    stevel 		}
    249      0    stevel 
    250      0    stevel 		/* mark the target node so we display it */
    251      0    stevel 		node_display_set(target_node);
    252      0    stevel 
    253      0    stevel 		if (opts.o_ancestors) {
    254      0    stevel 			/*
    255      0    stevel 			 * mark the ancestors of this node so we display
    256      0    stevel 			 * them as well
    257      0    stevel 			 */
    258      0    stevel 			node = target_node;
    259      0    stevel 			while (node = di_parent_node(node))
    260      0    stevel 				node_display_set(node);
    261      0    stevel 		} else {
    262      0    stevel 			/*
    263      0    stevel 			 * when we display device tree nodes the indentation
    264      0    stevel 			 * level is based off of tree depth.
    265      0    stevel 			 *
    266      0    stevel 			 * here we increment o_target to reflect the
    267      0    stevel 			 * depth of the target node in the tree.  we do
    268      0    stevel 			 * this so that when we calculate the indentation
    269      0    stevel 			 * level we can subtract o_target so that the
    270      0    stevel 			 * target node starts with an indentation of zero.
    271      0    stevel 			 */
    272      0    stevel 			node = target_node;
    273      0    stevel 			while (node = di_parent_node(node))
    274      0    stevel 				opts.o_target++;
    275      0    stevel 		}
    276      0    stevel 
    277      0    stevel 		if (opts.o_children) {
    278      0    stevel 			/*
    279      0    stevel 			 * mark the children of this node so we display
    280      0    stevel 			 * them as well
    281      0    stevel 			 */
    282      0    stevel 			(void) di_walk_node(target_node, DI_WALK_CLDFIRST,
    283   4453       cth 			    (void *)1,
    284   4453       cth 			    (int (*)(di_node_t, void *))
    285   4453       cth 			    node_display_set);
    286      0    stevel 		}
    287      0    stevel 	}
    288      0    stevel 
    289   9074      Judy 	(void) di_walk_node(root_node, DI_WALK_CLDFIRST, &di_arg,
    290   4453       cth 	    dump_devs);
    291      0    stevel 
    292   9074      Judy 	if (prom_hdl != DI_PROM_HANDLE_NIL)
    293   9074      Judy 		di_prom_fini(prom_hdl);
    294      0    stevel 	if (devlink_hdl != NULL)
    295      0    stevel 		(void) di_devlink_fini(&devlink_hdl);
    296      0    stevel 	di_fini(root_node);
    297      0    stevel }
    298      0    stevel 
    299      0    stevel /*
    300      0    stevel  * utility routines
    301      0    stevel  */
    302      0    stevel static int
    303      0    stevel i_find_target_node(di_node_t node, void *arg)
    304      0    stevel {
    305      0    stevel 	di_node_t *target = (di_node_t *)arg;
    306      0    stevel 
    307      0    stevel 	if (opts.o_devices_path != NULL) {
    308      0    stevel 		char *path;
    309      0    stevel 
    310      0    stevel 		if ((path = di_devfs_path(node)) == NULL)
    311      0    stevel 			exit(_error("failed to allocate memory"));
    312      0    stevel 
    313      0    stevel 		if (strcmp(opts.o_devices_path, path) == 0) {
    314      0    stevel 			di_devfs_path_free(path);
    315      0    stevel 			*target = node;
    316      0    stevel 			return (DI_WALK_TERMINATE);
    317      0    stevel 		}
    318      0    stevel 
    319      0    stevel 		di_devfs_path_free(path);
    320      0    stevel 	} else if (opts.o_devt != DDI_DEV_T_NONE) {
    321      0    stevel 		di_minor_t	minor = DI_MINOR_NIL;
    322      0    stevel 
    323      0    stevel 		while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
    324      0    stevel 			if (opts.o_devt == di_minor_devt(minor)) {
    325      0    stevel 				*target = node;
    326      0    stevel 				return (DI_WALK_TERMINATE);
    327      0    stevel 			}
    328      0    stevel 		}
    329      0    stevel 	} else {
    330      0    stevel 		/* we should never get here */
    331      0    stevel 		exit(_error(NULL, "internal error"));
    332      0    stevel 	}
    333      0    stevel 	return (DI_WALK_CONTINUE);
    334      0    stevel }
    335      0    stevel 
    336      0    stevel static di_node_t
    337      0    stevel find_target_node(di_node_t root_node)
    338      0    stevel {
    339      0    stevel 	di_node_t target = DI_NODE_NIL;
    340      0    stevel 
    341      0    stevel 	/* special case to allow displaying of the root node */
    342      0    stevel 	if (opts.o_devices_path != NULL) {
    343      0    stevel 		if (strlen(opts.o_devices_path) == 0)
    344      0    stevel 			return (root_node);
    345      0    stevel 		if (strcmp(opts.o_devices_path, ".") == 0)
    346      0    stevel 			return (root_node);
    347      0    stevel 	}
    348      0    stevel 
    349      0    stevel 	(void) di_walk_node(root_node, DI_WALK_CLDFIRST, &target,
    350   4453       cth 	    i_find_target_node);
    351      0    stevel 	return (target);
    352      0    stevel }
    353      0    stevel 
    354      0    stevel #define	NODE_DISPLAY		(1<<0)
    355      0    stevel 
    356      0    stevel static long
    357      0    stevel node_display(di_node_t node)
    358      0    stevel {
    359      0    stevel 	long data = (long)di_node_private_get(node);
    360      0    stevel 	return (data & NODE_DISPLAY);
    361      0    stevel }
    362      0    stevel 
    363      0    stevel static void
    364      0    stevel node_display_set(di_node_t node)
    365      0    stevel {
    366      0    stevel 	long data = (long)di_node_private_get(node);
    367      0    stevel 	data |= NODE_DISPLAY;
    368      0    stevel 	di_node_private_set(node, (void *)data);
    369      0    stevel }
    370      0    stevel 
    371      0    stevel #define	LNODE_DISPLAYED		(1<<0)
    372      0    stevel 
    373      0    stevel static long
    374      0    stevel lnode_displayed(di_lnode_t lnode)
    375      0    stevel {
    376      0    stevel 	long data = (long)di_lnode_private_get(lnode);
    377      0    stevel 	return (data & LNODE_DISPLAYED);
    378      0    stevel }
    379      0    stevel 
    380      0    stevel static void
    381      0    stevel lnode_displayed_set(di_lnode_t lnode)
    382      0    stevel {
    383      0    stevel 	long data = (long)di_lnode_private_get(lnode);
    384      0    stevel 	data |= LNODE_DISPLAYED;
    385      0    stevel 	di_lnode_private_set(lnode, (void *)data);
    386      0    stevel }
    387      0    stevel 
    388      0    stevel static void
    389      0    stevel lnode_displayed_clear(di_lnode_t lnode)
    390      0    stevel {
    391      0    stevel 	long data = (long)di_lnode_private_get(lnode);
    392      0    stevel 	data &= ~LNODE_DISPLAYED;
    393      0    stevel 	di_lnode_private_set(lnode, (void *)data);
    394      0    stevel }
    395      0    stevel 
    396      0    stevel #define	MINOR_DISPLAYED		(1<<0)
    397      0    stevel #define	MINOR_PTR		(~(0x3))
    398      0    stevel 
    399      0    stevel static long
    400      0    stevel minor_displayed(di_minor_t minor)
    401      0    stevel {
    402      0    stevel 	long data = (long)di_minor_private_get(minor);
    403      0    stevel 	return (data & MINOR_DISPLAYED);
    404      0    stevel }
    405      0    stevel 
    406      0    stevel static void
    407      0    stevel minor_displayed_set(di_minor_t minor)
    408      0    stevel {
    409      0    stevel 	long data = (long)di_minor_private_get(minor);
    410      0    stevel 	data |= MINOR_DISPLAYED;
    411      0    stevel 	di_minor_private_set(minor, (void *)data);
    412      0    stevel }
    413      0    stevel 
    414      0    stevel static void
    415      0    stevel minor_displayed_clear(di_minor_t minor)
    416      0    stevel {
    417      0    stevel 	long data = (long)di_minor_private_get(minor);
    418      0    stevel 	data &= ~MINOR_DISPLAYED;
    419      0    stevel 	di_minor_private_set(minor, (void *)data);
    420      0    stevel }
    421      0    stevel 
    422      0    stevel static void *
    423      0    stevel minor_ptr(di_minor_t minor)
    424      0    stevel {
    425      0    stevel 	long data = (long)di_minor_private_get(minor);
    426      0    stevel 	return ((void *)(data & MINOR_PTR));
    427      0    stevel }
    428      0    stevel 
    429      0    stevel static void
    430      0    stevel minor_ptr_set(di_minor_t minor, void *ptr)
    431      0    stevel {
    432      0    stevel 	long data = (long)di_minor_private_get(minor);
    433      0    stevel 	data = (data & ~MINOR_PTR) | (((long)ptr) & MINOR_PTR);
    434      0    stevel 	di_minor_private_set(minor, (void *)data);
    435      0    stevel }
    436      0    stevel 
    437      0    stevel /*
    438      0    stevel  * In this comment typed properties are those of type DI_PROP_TYPE_UNDEF_IT,
    439      0    stevel  * DI_PROP_TYPE_BOOLEAN, DI_PROP_TYPE_INT, DI_PROP_TYPE_INT64,
    440      0    stevel  * DI_PROP_TYPE_BYTE, and DI_PROP_TYPE_STRING.
    441      0    stevel  *
    442      0    stevel  * The guessing algorithm is:
    443      0    stevel  * 1. If the property is typed and the type is consistent with the value of
    444      0    stevel  *    the property, then the property is of that type. If the type is not
    445      0    stevel  *    consistent with value of the property, then the type is treated as
    446      0    stevel  *    alien to prtconf.
    447      0    stevel  * 2. If the property is of type DI_PROP_TYPE_UNKNOWN the following steps
    448      0    stevel  *    are carried out.
    449      0    stevel  *    a. If the value of the property is consistent with a string property,
    450      0    stevel  *       the type of the property is DI_PROP_TYPE_STRING.
    451      0    stevel  *    b. Otherwise, if the value of the property is consistent with an integer
    452      0    stevel  *       property, the type of the property is DI_PROP_TYPE_INT.
    453      0    stevel  *    c. Otherwise, the property type is treated as alien to prtconf.
    454      0    stevel  * 3. If the property type is alien to prtconf, then the property value is
    455      0    stevel  *    read by the appropriate routine for untyped properties and the following
    456      0    stevel  *    steps are carried out.
    457      0    stevel  *    a. If the length that the property routine returned is zero, the
    458      0    stevel  *       property is of type DI_PROP_TYPE_BOOLEAN.
    459      0    stevel  *    b. Otherwise, if the length that the property routine returned is
    460      0    stevel  *       positive, then the property value is treated as raw data of type
    461      0    stevel  *       DI_PROP_TYPE_UNKNOWN.
    462      0    stevel  *    c. Otherwise, if the length that the property routine returned is
    463      0    stevel  *       negative, then there is some internal inconsistency and this is
    464      0    stevel  *       treated as an error and no type is determined.
    465      0    stevel  */
    466      0    stevel static int
    467      0    stevel prop_type_guess(const dumpops_t *propops, void *prop, void **prop_data,
    468      0    stevel     int *prop_type)
    469      0    stevel {
    470      0    stevel 	int len, type;
    471      0    stevel 
    472      0    stevel 	type = PROPTYPE(propops)(prop);
    473      0    stevel 	switch (type) {
    474      0    stevel 	case DI_PROP_TYPE_UNDEF_IT:
    475      0    stevel 	case DI_PROP_TYPE_BOOLEAN:
    476      0    stevel 		*prop_data = NULL;
    477      0    stevel 		*prop_type = type;
    478      0    stevel 		return (0);
    479      0    stevel 	case DI_PROP_TYPE_INT:
    480      0    stevel 		len = PROPINTS(propops)(prop, (int **)prop_data);
    481      0    stevel 		break;
    482      0    stevel 	case DI_PROP_TYPE_INT64:
    483      0    stevel 		len = PROPINT64(propops)(prop, (int64_t **)prop_data);
    484      0    stevel 		break;
    485      0    stevel 	case DI_PROP_TYPE_BYTE:
    486      0    stevel 		len = PROPBYTES(propops)(prop, (uchar_t **)prop_data);
    487      0    stevel 		break;
    488      0    stevel 	case DI_PROP_TYPE_STRING:
    489      0    stevel 		len = PROPSTRINGS(propops)(prop, (char **)prop_data);
    490      0    stevel 		break;
    491      0    stevel 	case DI_PROP_TYPE_UNKNOWN:
    492      0    stevel 		len = PROPSTRINGS(propops)(prop, (char **)prop_data);
    493      0    stevel 		if ((len > 0) && ((*(char **)prop_data)[0] != 0)) {
    494      0    stevel 			*prop_type = DI_PROP_TYPE_STRING;
    495      0    stevel 			return (len);
    496      0    stevel 		}
    497      0    stevel 
    498      0    stevel 		len = PROPINTS(propops)(prop, (int **)prop_data);
    499      0    stevel 		type = DI_PROP_TYPE_INT;
    500      0    stevel 
    501      0    stevel 		break;
    502      0    stevel 	default:
    503      0    stevel 		len = -1;
    504      0    stevel 	}
    505      0    stevel 
    506      0    stevel 	if (len > 0) {
    507      0    stevel 		*prop_type = type;
    508      0    stevel 		return (len);
    509      0    stevel 	}
    510      0    stevel 
    511      0    stevel 	len = PROPRAWDATA(propops)(prop, (uchar_t **)prop_data);
    512      0    stevel 	if (len < 0) {
    513      0    stevel 		return (-1);
    514      0    stevel 	} else if (len == 0) {
    515      0    stevel 		*prop_type = DI_PROP_TYPE_BOOLEAN;
    516      0    stevel 		return (0);
    517      0    stevel 	}
    518      0    stevel 
    519      0    stevel 	*prop_type = DI_PROP_TYPE_UNKNOWN;
    520      0    stevel 	return (len);
    521      0    stevel }
    522      0    stevel 
    523   7224       cth /*
    524   7224       cth  * Returns 0 if nothing is printed, 1 otherwise
    525   7224       cth  */
    526   7224       cth static int
    527   7224       cth dump_prop_list(const dumpops_t *dumpops, const char *name, int ilev,
    528   7261       cth     void *node, dev_t dev, int *compat_printed)
    529      0    stevel {
    530   7224       cth 	void		*prop = DI_PROP_NIL, *prop_data;
    531   7224       cth 	di_minor_t	minor;
    532   7224       cth 	char		*p;
    533   7224       cth 	int		i, prop_type, nitems;
    534   7224       cth 	dev_t		pdev;
    535   7224       cth 	int		nprop = 0;
    536   7261       cth 
    537   7261       cth 	if (compat_printed)
    538   7261       cth 		*compat_printed = 0;
    539      0    stevel 
    540      0    stevel 	while ((prop = NEXTPROP(dumpops)(node, prop)) != DI_PROP_NIL) {
    541   7224       cth 
    542   7224       cth 		/* Skip properties a dev_t oriented caller is not requesting */
    543   7224       cth 		if (PROPDEVT(dumpops)) {
    544   7224       cth 			pdev = PROPDEVT(dumpops)(prop);
    545   7224       cth 
    546   7224       cth 			if (dev == DDI_DEV_T_ANY) {
    547   7224       cth 				/*
    548   7224       cth 				 * Caller requesting print all properties
    549   7224       cth 				 */
    550   7224       cth 				goto print;
    551   7224       cth 			} else if (dev == DDI_DEV_T_NONE) {
    552   7224       cth 				/*
    553   7224       cth 				 * Caller requesting print of properties
    554   7224       cth 				 * associated with devinfo (not minor).
    555   7224       cth 				 */
    556   7224       cth 				if ((pdev == DDI_DEV_T_ANY) ||
    557   7224       cth 				    (pdev == DDI_DEV_T_NONE))
    558   7224       cth 					goto print;
    559   7224       cth 
    560   7224       cth 				/*
    561   7224       cth 				 * Property has a minor association, see if
    562   7224       cth 				 * we have a minor with this dev_t. If there
    563   7224       cth 				 * is no such minor we print the property now
    564   7224       cth 				 * so it gets displayed.
    565   7224       cth 				 */
    566   7224       cth 				minor = DI_MINOR_NIL;
    567   7224       cth 				while ((minor = di_minor_next((di_node_t)node,
    568   7224       cth 				    minor)) != DI_MINOR_NIL) {
    569   7224       cth 					if (di_minor_devt(minor) == pdev)
    570   7224       cth 						break;
    571   7224       cth 				}
    572   7224       cth 				if (minor == DI_MINOR_NIL)
    573   7224       cth 					goto print;
    574   7224       cth 			} else if (dev == pdev) {
    575   7224       cth 				/*
    576   7224       cth 				 * Caller requesting print of properties
    577   7224       cth 				 * associated with a specific matching minor
    578   7224       cth 				 * node.
    579   7224       cth 				 */
    580   7224       cth 				goto print;
    581   7224       cth 			}
    582   7224       cth 
    583   7224       cth 			/* otherwise skip print */
    584   7224       cth 			continue;
    585   7224       cth 		}
    586   7224       cth 
    587   7224       cth print:		nitems = prop_type_guess(dumpops, prop, &prop_data, &prop_type);
    588      0    stevel 		if (nitems < 0)
    589      0    stevel 			continue;
    590   7224       cth 
    591   7224       cth 		if (nprop == 0) {
    592   7224       cth 			if (name) {
    593   7224       cth 				indent_to_level(ilev);
    594   7224       cth 				(void) printf("%s properties:\n", name);
    595   7224       cth 			}
    596   7224       cth 			ilev++;
    597   7224       cth 		}
    598   7224       cth 		nprop++;
    599      0    stevel 
    600      0    stevel 		indent_to_level(ilev);
    601      0    stevel 		(void) printf("name='%s' type=", PROPNAME(dumpops)(prop));
    602   7261       cth 
    603   7261       cth 		/* report 'compatible' as processed */
    604   7261       cth 		if (compat_printed &&
    605   7261       cth 		    (strcmp(PROPNAME(dumpops)(prop), "compatible") == 0))
    606   7261       cth 			*compat_printed = 1;
    607      0    stevel 
    608      0    stevel 		switch (prop_type) {
    609      0    stevel 		case DI_PROP_TYPE_UNDEF_IT:
    610      0    stevel 			(void) printf("undef");
    611      0    stevel 			break;
    612      0    stevel 		case DI_PROP_TYPE_BOOLEAN:
    613      0    stevel 			(void) printf("boolean");
    614      0    stevel 			break;
    615      0    stevel 		case DI_PROP_TYPE_INT:
    616      0    stevel 			(void) printf("int");
    617      0    stevel 			break;
    618      0    stevel 		case DI_PROP_TYPE_INT64:
    619      0    stevel 			(void) printf("int64");
    620      0    stevel 			break;
    621      0    stevel 		case DI_PROP_TYPE_BYTE:
    622      0    stevel 			(void) printf("byte");
    623      0    stevel 			break;
    624      0    stevel 		case DI_PROP_TYPE_STRING:
    625      0    stevel 			(void) printf("string");
    626      0    stevel 			break;
    627      0    stevel 		case DI_PROP_TYPE_UNKNOWN:
    628      0    stevel 			(void) printf("unknown");
    629      0    stevel 			break;
    630      0    stevel 		default:
    631      0    stevel 			/* Should never be here */
    632      0    stevel 			(void) printf("0x%x", prop_type);
    633      0    stevel 		}
    634      0    stevel 
    635      0    stevel 		if (nitems != 0)
    636      0    stevel 			(void) printf(" items=%i", nitems);
    637      0    stevel 
    638      0    stevel 		/* print the major and minor numbers for a device property */
    639   7224       cth 		if (PROPDEVT(dumpops)) {
    640   7224       cth 			if ((pdev == DDI_DEV_T_NONE) ||
    641   7224       cth 			    (pdev == DDI_DEV_T_ANY)) {
    642   7224       cth 				(void) printf(" dev=none");
    643   7224       cth 			} else {
    644      0    stevel 				(void) printf(" dev=(%u,%u)",
    645   7224       cth 				    (uint_t)major(pdev), (uint_t)minor(pdev));
    646      0    stevel 			}
    647      0    stevel 		}
    648      0    stevel 
    649      0    stevel 		(void) putchar('\n');
    650      0    stevel 
    651      0    stevel 		if (nitems == 0)
    652      0    stevel 			continue;
    653      0    stevel 
    654      0    stevel 		indent_to_level(ilev);
    655      0    stevel 
    656      0    stevel 		(void) printf("    value=");
    657      0    stevel 
    658      0    stevel 		switch (prop_type) {
    659      0    stevel 		case DI_PROP_TYPE_INT:
    660      0    stevel 			for (i = 0; i < nitems - 1; i++)
    661      0    stevel 				(void) printf("%8.8x.", ((int *)prop_data)[i]);
    662      0    stevel 			(void) printf("%8.8x", ((int *)prop_data)[i]);
    663      0    stevel 			break;
    664      0    stevel 		case DI_PROP_TYPE_INT64:
    665      0    stevel 			for (i = 0; i < nitems - 1; i++)
    666      0    stevel 				(void) printf("%16.16llx.",
    667      0    stevel 				    ((long long *)prop_data)[i]);
    668      0    stevel 			(void) printf("%16.16llx", ((long long *)prop_data)[i]);
    669      0    stevel 			break;
    670      0    stevel 		case DI_PROP_TYPE_STRING:
    671      0    stevel 			p = (char *)prop_data;
    672      0    stevel 			for (i = 0; i < nitems - 1; i++) {
    673      0    stevel 				(void) printf("'%s' + ", p);
    674      0    stevel 				p += strlen(p) + 1;
    675      0    stevel 			}
    676      0    stevel 			(void) printf("'%s'", p);
    677      0    stevel 			break;
    678      0    stevel 		default:
    679      0    stevel 			for (i = 0; i < nitems - 1; i++)
    680      0    stevel 				(void) printf("%2.2x.",
    681      0    stevel 				    ((uint8_t *)prop_data)[i]);
    682      0    stevel 			(void) printf("%2.2x", ((uint8_t *)prop_data)[i]);
    683      0    stevel 		}
    684      0    stevel 
    685      0    stevel 		(void) putchar('\n');
    686      0    stevel 	}
    687   7224       cth 
    688   7224       cth 	return (nprop ? 1 : 0);
    689      0    stevel }
    690      0    stevel 
    691      0    stevel /*
    692      0    stevel  * walk_driver is a debugging facility.
    693      0    stevel  */
    694      0    stevel static void
    695   9074      Judy walk_driver(di_node_t root, di_arg_t *di_arg)
    696      0    stevel {
    697      0    stevel 	di_node_t node;
    698      0    stevel 
    699      0    stevel 	node = di_drv_first_node(dbg.d_drivername, root);
    700      0    stevel 
    701      0    stevel 	while (node != DI_NODE_NIL) {
    702   9074      Judy 		(void) dump_devs(node, di_arg);
    703      0    stevel 		node = di_drv_next_node(node);
    704      0    stevel 	}
    705      0    stevel }
    706      0    stevel 
    707      0    stevel /*
    708      0    stevel  * print out information about this node, returns appropriate code.
    709      0    stevel  */
    710      0    stevel /*ARGSUSED1*/
    711      0    stevel static int
    712      0    stevel dump_devs(di_node_t node, void *arg)
    713      0    stevel {
    714   9074      Judy 	di_arg_t		*di_arg = arg;
    715   9074      Judy 	di_devlink_handle_t	devlink_hdl = di_arg->devlink_hdl;
    716      0    stevel 	int			ilev = 0;	/* indentation level */
    717      0    stevel 	char			*driver_name;
    718      0    stevel 	di_node_t		root_node, tmp;
    719   7261       cth 	int			compat_printed;
    720   7261       cth 	int			printed;
    721      0    stevel 
    722      0    stevel 	if (dbg.d_debug) {
    723      0    stevel 		char *path = di_devfs_path(node);
    724      0    stevel 		dprintf("Dump node %s\n", path);
    725      0    stevel 		di_devfs_path_free(path);
    726      0    stevel 	}
    727      0    stevel 
    728      0    stevel 	if (dbg.d_bydriver) {
    729      0    stevel 		ilev = 1;
    730      0    stevel 	} else {
    731      0    stevel 		/* figure out indentation level */
    732      0    stevel 		tmp = node;
    733      0    stevel 		while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
    734      0    stevel 			ilev++;
    735      0    stevel 
    736      0    stevel 		if (opts.o_target && !opts.o_ancestors) {
    737      0    stevel 			ilev -= opts.o_target - 1;
    738      0    stevel 		}
    739      0    stevel 	}
    740      0    stevel 
    741      0    stevel 	if (opts.o_target && !node_display(node)) {
    742      0    stevel 		/*
    743      0    stevel 		 * if we're only displaying certain nodes and this one
    744      0    stevel 		 * isn't flagged, skip it.
    745      0    stevel 		 */
    746      0    stevel 		return (DI_WALK_CONTINUE);
    747      0    stevel 	}
    748      0    stevel 
    749      0    stevel 	indent_to_level(ilev);
    750      0    stevel 
    751      0    stevel 	(void) printf("%s", di_node_name(node));
    752   9074      Judy 	if (opts.o_pciid)
    753   9074      Judy 		(void) print_pciid(node, di_arg->prom_hdl);
    754      0    stevel 
    755      0    stevel 	/*
    756      0    stevel 	 * if this node does not have an instance number or is the
    757      0    stevel 	 * root node (1229946), we don't print an instance number
    758      0    stevel 	 */
    759      0    stevel 	root_node = tmp = node;
    760      0    stevel 	while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
    761      0    stevel 		root_node = tmp;
    762      0    stevel 	if ((di_instance(node) >= 0) && (node != root_node))
    763      0    stevel 		(void) printf(", instance #%d", di_instance(node));
    764      0    stevel 
    765      0    stevel 	if (opts.o_drv_name) {
    766      0    stevel 		driver_name = di_driver_name(node);
    767      0    stevel 		if (driver_name != NULL)
    768      0    stevel 			(void) printf(" (driver name: %s)", driver_name);
    769   4845    vikram 	} else if (di_retired(node)) {
    770   4845    vikram 		(void) printf(" (retired)");
    771      0    stevel 	} else if (di_state(node) & DI_DRIVER_DETACHED)
    772      0    stevel 		(void) printf(" (driver not attached)");
    773      0    stevel 	(void) printf("\n");
    774      0    stevel 
    775      0    stevel 	if (opts.o_verbose)  {
    776      0    stevel 		if (dump_prop_list(&sysprop_dumpops, "System", ilev + 1,
    777   7261       cth 		    node, DDI_DEV_T_ANY, NULL)) {
    778      0    stevel 			(void) dump_prop_list(&globprop_dumpops, NULL, ilev + 1,
    779   7261       cth 			    node, DDI_DEV_T_ANY, NULL);
    780      0    stevel 		} else {
    781      0    stevel 			(void) dump_prop_list(&globprop_dumpops,
    782   7261       cth 			    "System software", ilev + 1,
    783   7261       cth 			    node, DDI_DEV_T_ANY, NULL);
    784      0    stevel 		}
    785      0    stevel 		(void) dump_prop_list(&drvprop_dumpops, "Driver", ilev + 1,
    786   7261       cth 		    node, DDI_DEV_T_NONE, NULL);
    787   7261       cth 
    788   7261       cth 		printed = dump_prop_list(&hwprop_dumpops, "Hardware",
    789   7261       cth 		    ilev + 1, node, DDI_DEV_T_ANY, &compat_printed);
    790   7261       cth 
    791   7261       cth 		/* Ensure that 'compatible' is printed under Hardware header */
    792   7261       cth 		if (!compat_printed)
    793   7261       cth 			(void) dump_compatible(printed ? NULL : "Hardware",
    794   7261       cth 			    ilev + 1, node);
    795   7261       cth 
    796      0    stevel 		dump_priv_data(ilev + 1, node);
    797      0    stevel 		dump_pathing_data(ilev + 1, node);
    798      0    stevel 		dump_link_data(ilev + 1, node, devlink_hdl);
    799      0    stevel 		dump_minor_data(ilev + 1, node, devlink_hdl);
    800      0    stevel 	}
    801      0    stevel 
    802      0    stevel 	if (opts.o_target)
    803      0    stevel 		return (DI_WALK_CONTINUE);
    804      0    stevel 
    805      0    stevel 	if (!opts.o_pseudodevs && (strcmp(di_node_name(node), "pseudo") == 0))
    806      0    stevel 		return (DI_WALK_PRUNECHILD);
    807      0    stevel 
    808      0    stevel 	return (DI_WALK_CONTINUE);
    809      0    stevel }
    810      0    stevel 
    811      0    stevel /* _error([no_perror, ] fmt [, arg ...]) */
    812      0    stevel static int
    813      0    stevel _error(const char *opt_noperror, ...)
    814      0    stevel {
    815      0    stevel 	int saved_errno;
    816      0    stevel 	va_list ap;
    817      0    stevel 	int no_perror = 0;
    818      0    stevel 	const char *fmt;
    819      0    stevel 
    820      0    stevel 	saved_errno = errno;
    821      0    stevel 
    822      0    stevel 	(void) fprintf(stderr, "%s: ", opts.o_progname);
    823      0    stevel 
    824      0    stevel 	va_start(ap, opt_noperror);
    825      0    stevel 	if (opt_noperror == NULL) {
    826      0    stevel 		no_perror = 1;
    827      0    stevel 		fmt = va_arg(ap, char *);
    828      0    stevel 	} else
    829      0    stevel 		fmt = opt_noperror;
    830      0    stevel 	(void) vfprintf(stderr, fmt, ap);
    831      0    stevel 	va_end(ap);
    832      0    stevel 
    833      0    stevel 	if (no_perror)
    834      0    stevel 		(void) fprintf(stderr, "\n");
    835      0    stevel 	else {
    836      0    stevel 		(void) fprintf(stderr, ": ");
    837      0    stevel 		errno = saved_errno;
    838      0    stevel 		perror("");
    839      0    stevel 	}
    840      0    stevel 
    841      0    stevel 	return (-1);
    842      0    stevel }
    843      0    stevel 
    844      0    stevel 
    845      0    stevel /*
    846      0    stevel  * The rest of the routines handle printing the raw prom devinfo (-p option).
    847      0    stevel  *
    848      0    stevel  * 128 is the size of the largest (currently) property name
    849      0    stevel  * 16k - MAXNAMESZ - sizeof (int) is the size of the largest
    850      0    stevel  * (currently) property value that is allowed.
    851      0    stevel  * the sizeof (uint_t) is from struct openpromio
    852      0    stevel  */
    853      0    stevel 
    854      0    stevel #define	MAXNAMESZ	128
    855      0    stevel #define	MAXVALSIZE	(16384 - MAXNAMESZ - sizeof (uint_t))
    856      0    stevel #define	BUFSIZE		(MAXNAMESZ + MAXVALSIZE + sizeof (uint_t))
    857      0    stevel typedef union {
    858      0    stevel 	char buf[BUFSIZE];
    859      0    stevel 	struct openpromio opp;
    860      0    stevel } Oppbuf;
    861      0    stevel 
    862      0    stevel static int prom_fd;
    863      0    stevel static uchar_t *prom_snapshot;
    864      0    stevel 
    865      0    stevel static int
    866      0    stevel is_openprom(void)
    867      0    stevel {
    868      0    stevel 	Oppbuf	oppbuf;
    869      0    stevel 	struct openpromio *opp = &(oppbuf.opp);
    870      0    stevel 	unsigned int i;
    871      0    stevel 
    872      0    stevel 	opp->oprom_size = MAXVALSIZE;
    873      0    stevel 	if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
    874      0    stevel 		exit(_error("OPROMGETCONS"));
    875      0    stevel 
    876      0    stevel 	i = (unsigned int)((unsigned char)opp->oprom_array[0]);
    877      0    stevel 	return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
    878      0    stevel }
    879      0    stevel 
    880      0    stevel int
    881      0    stevel do_prominfo(void)
    882      0    stevel {
    883      0    stevel 	uint_t arg = opts.o_verbose;
    884      0    stevel 
    885      0    stevel 	if (promopen(O_RDONLY))  {
    886      0    stevel 		exit(_error("openeepr device open failed"));
    887      0    stevel 	}
    888      0    stevel 
    889      0    stevel 	if (is_openprom() == 0)  {
    890      0    stevel 		(void) fprintf(stderr, "System architecture does not "
    891      0    stevel 		    "support this option of this command.\n");
    892      0    stevel 		return (1);
    893      0    stevel 	}
    894      0    stevel 
    895      0    stevel 	/* OPROMSNAPSHOT returns size in arg */
    896      0    stevel 	if (ioctl(prom_fd, OPROMSNAPSHOT, &arg) < 0)
    897      0    stevel 		exit(_error("OPROMSNAPSHOT"));
    898      0    stevel 
    899      0    stevel 	if (arg == 0)
    900      0    stevel 		return (1);
    901      0    stevel 
    902      0    stevel 	if ((prom_snapshot = malloc(arg)) == NULL)
    903      0    stevel 		exit(_error("failed to allocate memory"));
    904      0    stevel 
    905      0    stevel 	/* copy out the snapshot for printing */
    906      0    stevel 	/*LINTED*/
    907      0    stevel 	*(uint_t *)prom_snapshot = arg;
    908      0    stevel 	if (ioctl(prom_fd, OPROMCOPYOUT, prom_snapshot) < 0)
    909      0    stevel 		exit(_error("OPROMCOPYOUT"));
    910      0    stevel 
    911      0    stevel 	promclose();
    912      0    stevel 
    913      0    stevel 	/* print out information */
    914      0    stevel 	walk(prom_snapshot, arg, 0);
    915      0    stevel 	free(prom_snapshot);
    916      0    stevel 
    917      0    stevel 	return (0);
    918      0    stevel }
    919      0    stevel 
    920      0    stevel static void
    921      0    stevel walk(uchar_t *buf, uint_t size, int level)
    922      0    stevel {
    923      0    stevel 	int error;
    924      0    stevel 	nvlist_t *nvl, *cnvl;
    925      0    stevel 	nvpair_t *child = NULL;
    926      0    stevel 	uchar_t *cbuf = NULL;
    927      0    stevel 	uint_t csize;
    928      0    stevel 
    929      0    stevel 	/* Expand to an nvlist */
    930      0    stevel 	if (nvlist_unpack((char *)buf, size, &nvl, 0))
    931      0    stevel 		exit(_error("error processing snapshot"));
    932      0    stevel 
    933      0    stevel 	/* print current node */
    934      0    stevel 	dump_node(nvl, level);
    935      0    stevel 
    936      0    stevel 	/* print children */
    937      0    stevel 	error = nvlist_lookup_byte_array(nvl, "@child", &cbuf, &csize);
    938      0    stevel 	if ((error == ENOENT) || (cbuf == NULL))
    939      0    stevel 		return;		/* no child exists */
    940      0    stevel 
    941      0    stevel 	if (error || nvlist_unpack((char *)cbuf, csize, &cnvl, 0))
    942      0    stevel 		exit(_error("error processing snapshot"));
    943      0    stevel 
    944      0    stevel 	while (child = nvlist_next_nvpair(cnvl, child)) {
    945      0    stevel 		char *name = nvpair_name(child);
    946      0    stevel 		data_type_t type = nvpair_type(child);
    947      0    stevel 		uchar_t *nodebuf;
    948      0    stevel 		uint_t nodesize;
    949      0    stevel 		if (strcmp("node", name) != 0) {
    950      0    stevel 			dprintf("unexpected nvpair name %s != name\n", name);
    951      0    stevel 			continue;
    952      0    stevel 		}
    953      0    stevel 		if (type != DATA_TYPE_BYTE_ARRAY) {
    954      0    stevel 			dprintf("unexpected nvpair type %d, not byte array \n",
    955      0    stevel 			    type);
    956      0    stevel 			continue;
    957      0    stevel 		}
    958      0    stevel 
    959      0    stevel 		(void) nvpair_value_byte_array(child,
    960      0    stevel 		    (uchar_t **)&nodebuf, &nodesize);
    961      0    stevel 		walk(nodebuf, nodesize, level + 1);
    962      0    stevel 	}
    963      0    stevel 
    964      0    stevel 	nvlist_free(nvl);
    965      0    stevel }
    966      0    stevel 
    967      0    stevel /*
    968      0    stevel  * Print all properties and values
    969      0    stevel  */
    970      0    stevel static void
    971      0    stevel dump_node(nvlist_t *nvl, int level)
    972      0    stevel {
    973      0    stevel 	int id = 0;
    974      0    stevel 	char *name = NULL;
    975      0    stevel 	nvpair_t *nvp = NULL;
    976      0    stevel 
    977      0    stevel 	indent_to_level(level);
    978      0    stevel 	(void) printf("Node");
    979      0    stevel 	if (!opts.o_verbose) {
    980      0    stevel 		if (nvlist_lookup_string(nvl, "name", &name))
    981      0    stevel 			(void) printf("data not available");
    982      0    stevel 		else
    983      0    stevel 			(void) printf(" '%s'", name);
    984      0    stevel 		(void) putchar('\n');
    985      0    stevel 		return;
    986      0    stevel 	}
    987      0    stevel 	(void) nvlist_lookup_int32(nvl, "@nodeid", &id);
    988      0    stevel 	(void) printf(" %#08x\n", id);
    989      0    stevel 
    990      0    stevel 	while (nvp = nvlist_next_nvpair(nvl, nvp)) {
    991      0    stevel 		name = nvpair_name(nvp);
    992      0    stevel 		if (name[0] == '@')
    993      0    stevel 			continue;
    994      0    stevel 
    995      0    stevel 		print_one(nvp, level + 1);
    996      0    stevel 	}
    997      0    stevel 	(void) putchar('\n');
    998      0    stevel }
    999      0    stevel 
   1000      0    stevel static const char *
   1001      0    stevel path_state_name(di_path_state_t st)
   1002      0    stevel {
   1003      0    stevel 	switch (st) {
   1004      0    stevel 		case DI_PATH_STATE_ONLINE:
   1005      0    stevel 			return ("online");
   1006      0    stevel 		case DI_PATH_STATE_STANDBY:
   1007      0    stevel 			return ("standby");
   1008      0    stevel 		case DI_PATH_STATE_OFFLINE:
   1009      0    stevel 			return ("offline");
   1010      0    stevel 		case DI_PATH_STATE_FAULT:
   1011      0    stevel 			return ("faulted");
   1012      0    stevel 	}
   1013      0    stevel 	return ("unknown");
   1014      0    stevel }
   1015      0    stevel 
   1016      0    stevel /*
   1017      0    stevel  * Print all phci's each client is connected to.
   1018      0    stevel  */
   1019      0    stevel static void
   1020      0    stevel dump_pathing_data(int ilev, di_node_t node)
   1021      0    stevel {
   1022   6640       cth 	di_path_t	pi = DI_PATH_NIL;
   1023   6640       cth 	di_node_t	phci_node;
   1024   6640       cth 	char		*phci_path;
   1025   6640       cth 	int		path_instance;
   1026   6640       cth 	int		firsttime = 1;
   1027      0    stevel 
   1028      0    stevel 	if (node == DI_PATH_NIL)
   1029      0    stevel 		return;
   1030      0    stevel 
   1031   6640       cth 	while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) {
   1032  10696     David 
   1033  10696     David 		/* It is not really a path if we failed to capture the pHCI */
   1034  10696     David 		phci_node = di_path_phci_node(pi);
   1035  10696     David 		if (phci_node == DI_NODE_NIL)
   1036  10696     David 			continue;
   1037  10696     David 
   1038  10696     David 		/* Print header for the first path */
   1039      0    stevel 		if (firsttime) {
   1040      0    stevel 			indent_to_level(ilev);
   1041      0    stevel 			firsttime = 0;
   1042      0    stevel 			ilev++;
   1043      0    stevel 			(void) printf("Paths from multipath bus adapters:\n");
   1044      0    stevel 		}
   1045      0    stevel 
   1046   6640       cth 		/*
   1047   6640       cth 		 * Print the path instance and full "pathinfo" path, which is
   1048   6640       cth 		 * the same as the /devices devifo path had the device been
   1049   6640       cth 		 * enumerated under pHCI.
   1050   6640       cth 		 */
   1051   6640       cth 		phci_path = di_devfs_path(phci_node);
   1052   6640       cth 		if (phci_path) {
   1053  10696     David 			path_instance = di_path_instance(pi);
   1054   6640       cth 			if (path_instance > 0) {
   1055   6640       cth 				indent_to_level(ilev);
   1056   6640       cth 				(void) printf("Path %d: %s/%s@%s\n",
   1057   6640       cth 				    path_instance, phci_path,
   1058   6640       cth 				    di_node_name(node),
   1059   6640       cth 				    di_path_bus_addr(pi));
   1060   6640       cth 			}
   1061   6640       cth 			di_devfs_path_free(phci_path);
   1062   6640       cth 		}
   1063   6640       cth 
   1064   6640       cth 		/* print phci driver, instance, and path state information */
   1065      0    stevel 		indent_to_level(ilev);
   1066      0    stevel 		(void) printf("%s#%d (%s)\n", di_driver_name(phci_node),
   1067      0    stevel 		    di_instance(phci_node), path_state_name(di_path_state(pi)));
   1068  10696     David 
   1069   7224       cth 		(void) dump_prop_list(&pathprop_dumpops, NULL, ilev + 1,
   1070   7261       cth 		    pi, DDI_DEV_T_ANY, NULL);
   1071      0    stevel 	}
   1072      0    stevel }
   1073      0    stevel 
   1074      0    stevel static int
   1075      0    stevel dump_minor_data_links(di_devlink_t devlink, void *arg)
   1076      0    stevel {
   1077      0    stevel 	int ilev = (intptr_t)arg;
   1078      0    stevel 	indent_to_level(ilev);
   1079      0    stevel 	(void) printf("dev_link=%s\n", di_devlink_path(devlink));
   1080      0    stevel 	return (DI_WALK_CONTINUE);
   1081      0    stevel }
   1082      0    stevel 
   1083      0    stevel static void
   1084      0    stevel dump_minor_data_paths(int ilev, di_minor_t minor,
   1085      0    stevel     di_devlink_handle_t devlink_hdl)
   1086      0    stevel {
   1087      0    stevel 	char	*path, *type;
   1088      0    stevel 	int	spec_type;
   1089      0    stevel 
   1090      0    stevel 	/* get the path to the device and the minor node name */
   1091      0    stevel 	if ((path = di_devfs_minor_path(minor)) == NULL)
   1092      0    stevel 		exit(_error("failed to allocate memory"));
   1093      0    stevel 
   1094      0    stevel 	/* display the path to this minor node */
   1095      0    stevel 	indent_to_level(ilev);
   1096      0    stevel 	(void) printf("dev_path=%s\n", path);
   1097      0    stevel 
   1098      0    stevel 	if (devlink_hdl != NULL) {
   1099      0    stevel 
   1100      0    stevel 		/* get the device minor node information */
   1101      0    stevel 		spec_type = di_minor_spectype(minor);
   1102      0    stevel 		switch (di_minor_type(minor)) {
   1103      0    stevel 			case DDM_MINOR:
   1104      0    stevel 				type = "minor";
   1105      0    stevel 				break;
   1106      0    stevel 			case DDM_ALIAS:
   1107      0    stevel 				type = "alias";
   1108      0    stevel 				break;
   1109      0    stevel 			case DDM_DEFAULT:
   1110      0    stevel 				type = "default";
   1111      0    stevel 				break;
   1112      0    stevel 			case DDM_INTERNAL_PATH:
   1113      0    stevel 				type = "internal";
   1114      0    stevel 				break;
   1115      0    stevel 			default:
   1116      0    stevel 				type = "unknown";
   1117      0    stevel 				break;
   1118      0    stevel 		}
   1119      0    stevel 
   1120      0    stevel 		/* display the device minor node information */
   1121      0    stevel 		indent_to_level(ilev + 1);
   1122      0    stevel 		(void) printf("spectype=%s type=%s\n",
   1123   4453       cth 		    (spec_type == S_IFBLK) ? "blk" : "chr", type);
   1124      0    stevel 
   1125      0    stevel 		/* display all the devlinks for this device minor node */
   1126      0    stevel 		(void) di_devlink_walk(devlink_hdl, NULL, path,
   1127      0    stevel 		    0, (void *)(intptr_t)(ilev + 1), dump_minor_data_links);
   1128      0    stevel 	}
   1129      0    stevel 
   1130      0    stevel 	di_devfs_path_free(path);
   1131      0    stevel }
   1132      0    stevel 
   1133      0    stevel static void
   1134      0    stevel create_minor_list(di_node_t node)
   1135      0    stevel {
   1136      0    stevel 	di_minor_t	minor, minor_head, minor_tail, minor_prev, minor_walk;
   1137      0    stevel 	int		major;
   1138      0    stevel 
   1139      0    stevel 	/* if there are no minor nodes, bail */
   1140      0    stevel 	if (di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL)
   1141      0    stevel 		return;
   1142      0    stevel 
   1143      0    stevel 	/*
   1144      0    stevel 	 * here we want to create lists of minor nodes with the same
   1145      0    stevel 	 * dev_t.  to do this we first sort all the minor nodes by devt.
   1146      0    stevel 	 *
   1147      0    stevel 	 * the algorithm used here is a bubble sort, so performance sucks.
   1148      0    stevel 	 * but it's probably ok here because most device instances don't
   1149      0    stevel 	 * have that many minor nodes.  also we're doing this as we're
   1150      0    stevel 	 * displaying each node so it doesn't look like we're pausing
   1151      0    stevel 	 * output for a long time.
   1152      0    stevel 	 */
   1153      0    stevel 	major = di_driver_major(node);
   1154      0    stevel 	minor_head = minor_tail = minor = DI_MINOR_NIL;
   1155      0    stevel 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
   1156      0    stevel 		dev_t	dev = di_minor_devt(minor);
   1157      0    stevel 
   1158      0    stevel 		/* skip /pseudo/clone@0 minor nodes */
   1159      0    stevel 		if (major != major(dev))
   1160      0    stevel 			continue;
   1161      0    stevel 
   1162      0    stevel 		minor_ptr_set(minor, DI_MINOR_NIL);
   1163      0    stevel 		if (minor_head == DI_MINOR_NIL) {
   1164      0    stevel 			/* this is the first minor node we're looking at */
   1165      0    stevel 			minor_head = minor_tail = minor;
   1166      0    stevel 			continue;
   1167      0    stevel 		}
   1168      0    stevel 
   1169      0    stevel 		/*
   1170      0    stevel 		 * if the new dev is less than the old dev, update minor_head
   1171      0    stevel 		 * so it points to the beginning of the list.  ie it points
   1172      0    stevel 		 * to the node with the lowest dev value
   1173      0    stevel 		 */
   1174      0    stevel 		if (dev <= di_minor_devt(minor_head)) {
   1175      0    stevel 			minor_ptr_set(minor, minor_head);
   1176      0    stevel 			minor_head = minor;
   1177      0    stevel 			continue;
   1178      0    stevel 		}
   1179      0    stevel 
   1180      0    stevel 		minor_prev = minor_head;
   1181      0    stevel 		minor_walk = minor_ptr(minor_head);
   1182      0    stevel 		while ((minor_walk != DI_MINOR_NIL) &&
   1183   4453       cth 		    (dev > di_minor_devt(minor_walk))) {
   1184      0    stevel 			minor_prev = minor_walk;
   1185      0    stevel 			minor_walk = minor_ptr(minor_walk);
   1186      0    stevel 		}
   1187      0    stevel 		minor_ptr_set(minor, minor_walk);
   1188      0    stevel 		minor_ptr_set(minor_prev, minor);
   1189      0    stevel 		if (minor_walk == NULL)
   1190      0    stevel 			minor_tail = minor;
   1191      0    stevel 	}
   1192      0    stevel 
   1193      0    stevel 	/* check if there were any non /pseudo/clone@0 nodes.  if not, bail */
   1194      0    stevel 	if (minor_head == DI_MINOR_NIL)
   1195      0    stevel 		return;
   1196      0    stevel 
   1197      0    stevel 	/*
   1198      0    stevel 	 * now that we have a list of minor nodes sorted by devt
   1199      0    stevel 	 * we walk through the list and break apart the entire list
   1200      0    stevel 	 * to create circular lists of minor nodes with matching devts.
   1201      0    stevel 	 */
   1202      0    stevel 	minor_prev = minor_head;
   1203      0    stevel 	minor_walk = minor_ptr(minor_head);
   1204      0    stevel 	while (minor_walk != DI_MINOR_NIL) {
   1205      0    stevel 		if (di_minor_devt(minor_prev) != di_minor_devt(minor_walk)) {
   1206      0    stevel 			minor_ptr_set(minor_prev, minor_head);
   1207      0    stevel 			minor_head = minor_walk;
   1208      0    stevel 		}
   1209      0    stevel 		minor_prev = minor_walk;
   1210      0    stevel 		minor_walk = minor_ptr(minor_walk);
   1211      0    stevel 	}
   1212      0    stevel 	minor_ptr_set(minor_tail, minor_head);
   1213      0    stevel }
   1214      0    stevel 
   1215      0    stevel static void
   1216      0    stevel link_lnode_disp(di_link_t link, uint_t endpoint, int ilev,
   1217      0    stevel     di_devlink_handle_t devlink_hdl)
   1218      0    stevel {
   1219      0    stevel 	di_lnode_t	lnode;
   1220      0    stevel 	char		*name, *path;
   1221      0    stevel 	int		displayed_path, spec_type;
   1222      0    stevel 	di_node_t	node = DI_NODE_NIL;
   1223      0    stevel 	dev_t		devt = DDI_DEV_T_NONE;
   1224      0    stevel 
   1225      0    stevel 	lnode = di_link_to_lnode(link, endpoint);
   1226      0    stevel 
   1227      0    stevel 	indent_to_level(ilev);
   1228      0    stevel 	name = di_lnode_name(lnode);
   1229      0    stevel 	spec_type = di_link_spectype(link);
   1230      0    stevel 
   1231      0    stevel 	(void) printf("mod=%s", name);
   1232      0    stevel 
   1233      0    stevel 	/*
   1234      0    stevel 	 * if we're displaying the source of a link, we should display
   1235      0    stevel 	 * the target access mode.  (either block or char.)
   1236      0    stevel 	 */
   1237      0    stevel 	if (endpoint == DI_LINK_SRC)
   1238      0    stevel 		(void) printf(" accesstype=%s",
   1239      0    stevel 		    (spec_type == S_IFBLK) ? "blk" : "chr");
   1240      0    stevel 
   1241      0    stevel 	/*
   1242      0    stevel 	 * check if the lnode is bound to a specific device
   1243      0    stevel 	 * minor node (i.e.  if it's bound to a dev_t) and
   1244      0    stevel 	 * if so display the dev_t value and any possible
   1245      0    stevel 	 * minor node pathing information.
   1246      0    stevel 	 */
   1247      0    stevel 	displayed_path = 0;
   1248      0    stevel 	if (di_lnode_devt(lnode, &devt) == 0) {
   1249      0    stevel 		di_minor_t	minor = DI_MINOR_NIL;
   1250      0    stevel 
   1251      0    stevel 		(void) printf(" dev=(%u,%u)\n",
   1252      0    stevel 		    (uint_t)major(devt), (uint_t)minor(devt));
   1253      0    stevel 
   1254      0    stevel 		/* display paths to the src devt minor node */
   1255      0    stevel 		while (minor = di_minor_next(node, minor)) {
   1256      0    stevel 			if (devt != di_minor_devt(minor))
   1257      0    stevel 				continue;
   1258      0    stevel 
   1259      0    stevel 			if ((endpoint == DI_LINK_TGT) &&
   1260      0    stevel 			    (spec_type != di_minor_spectype(minor)))
   1261      0    stevel 				continue;
   1262      0    stevel 
   1263      0    stevel 			dump_minor_data_paths(ilev + 1, minor, devlink_hdl);
   1264      0    stevel 			displayed_path = 1;
   1265      0    stevel 		}
   1266      0    stevel 	} else {
   1267      0    stevel 		(void) printf("\n");
   1268      0    stevel 	}
   1269      0    stevel 
   1270      0    stevel 	if (displayed_path)
   1271      0    stevel 		return;
   1272      0    stevel 
   1273      0    stevel 	/*
   1274      0    stevel 	 * This device lnode is not did not have any minor node
   1275      0    stevel 	 * pathing information so display the path to device node.
   1276      0    stevel 	 */
   1277      0    stevel 	node = di_lnode_devinfo(lnode);
   1278      0    stevel 	if ((path = di_devfs_path(node)) == NULL)
   1279      0    stevel 		exit(_error("failed to allocate memory"));
   1280      0    stevel 
   1281      0    stevel 	indent_to_level(ilev + 1);
   1282      0    stevel 	(void) printf("dev_path=%s\n", path);
   1283      0    stevel 	di_devfs_path_free(path);
   1284      0    stevel }
   1285      0    stevel 
   1286      0    stevel static void
   1287      0    stevel dump_minor_link_data(int ilev, di_node_t node, dev_t devt,
   1288      0    stevel     di_devlink_handle_t devlink_hdl)
   1289      0    stevel {
   1290      0    stevel 	int		first = 1;
   1291      0    stevel 	di_link_t	link;
   1292      0    stevel 
   1293      0    stevel 	link = DI_LINK_NIL;
   1294      0    stevel 	while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) {
   1295      0    stevel 		di_lnode_t	tgt_lnode;
   1296      0    stevel 		dev_t		tgt_devt = DDI_DEV_T_NONE;
   1297      0    stevel 
   1298      0    stevel 		tgt_lnode = di_link_to_lnode(link, DI_LINK_TGT);
   1299      0    stevel 
   1300      0    stevel 		if (di_lnode_devt(tgt_lnode, &tgt_devt) != 0)
   1301      0    stevel 			continue;
   1302      0    stevel 
   1303      0    stevel 		if (devt != tgt_devt)
   1304      0    stevel 			continue;
   1305      0    stevel 
   1306      0    stevel 		if (first) {
   1307      0    stevel 			first = 0;
   1308      0    stevel 			indent_to_level(ilev);
   1309      0    stevel 			(void) printf("Device Minor Layered Under:\n");
   1310      0    stevel 		}
   1311      0    stevel 
   1312      0    stevel 		/* displayed this lnode */
   1313      0    stevel 		lnode_displayed_set(tgt_lnode);
   1314      0    stevel 		link_lnode_disp(link, DI_LINK_SRC, ilev + 1, devlink_hdl);
   1315      0    stevel 	}
   1316      0    stevel 
   1317      0    stevel 	link = DI_LINK_NIL;
   1318      0    stevel 	while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) {
   1319      0    stevel 		di_lnode_t	src_lnode;
   1320      0    stevel 		dev_t		src_devt = DDI_DEV_T_NONE;
   1321      0    stevel 
   1322      0    stevel 		src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
   1323      0    stevel 
   1324      0    stevel 		if (di_lnode_devt(src_lnode, &src_devt) != 0)
   1325      0    stevel 			continue;
   1326      0    stevel 
   1327      0    stevel 		if (devt != src_devt)
   1328      0    stevel 			continue;
   1329      0    stevel 
   1330      0    stevel 		if (first) {
   1331      0    stevel 			first = 0;
   1332      0    stevel 			indent_to_level(ilev);
   1333      0    stevel 			(void) printf("Device Minor Layered Over:\n");
   1334      0    stevel 		}
   1335      0    stevel 
   1336      0    stevel 		/* displayed this lnode */
   1337      0    stevel 		lnode_displayed_set(src_lnode);
   1338      0    stevel 		link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
   1339      0    stevel 	}
   1340      0    stevel }
   1341      0    stevel 
   1342      0    stevel static void
   1343      0    stevel dump_minor_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
   1344      0    stevel {
   1345      0    stevel 	di_minor_t	minor, minor_next;
   1346      0    stevel 	di_lnode_t	lnode;
   1347      0    stevel 	di_link_t	link;
   1348      0    stevel 	int		major, firstminor = 1;
   1349      0    stevel 
   1350      0    stevel 	/*
   1351      0    stevel 	 * first go through and mark all lnodes and minor nodes for this
   1352      0    stevel 	 * node as undisplayed
   1353      0    stevel 	 */
   1354      0    stevel 	lnode = DI_LNODE_NIL;
   1355      0    stevel 	while (lnode = di_lnode_next(node, lnode))
   1356      0    stevel 		lnode_displayed_clear(lnode);
   1357      0    stevel 	minor = DI_MINOR_NIL;
   1358      0    stevel 	while (minor = di_minor_next(node, minor)) {
   1359      0    stevel 		minor_displayed_clear(minor);
   1360      0    stevel 	}
   1361      0    stevel 
   1362      0    stevel 	/*
   1363      0    stevel 	 * when we display the minor nodes we want to coalesce nodes
   1364      0    stevel 	 * that have the same dev_t.  we do this by creating circular
   1365      0    stevel 	 * lists of minor nodes with the same devt.
   1366      0    stevel 	 */
   1367      0    stevel 	create_minor_list(node);
   1368      0    stevel 
   1369      0    stevel 	/* now we display the driver defined minor nodes */
   1370      0    stevel 	major = di_driver_major(node);
   1371      0    stevel 	minor = DI_MINOR_NIL;
   1372      0    stevel 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
   1373      0    stevel 		dev_t	devt;
   1374      0    stevel 
   1375      0    stevel 		/*
   1376      0    stevel 		 * skip /pseudo/clone@0 minor nodes.
   1377      0    stevel 		 * these are only created for DLPIv2 network devices.
   1378      0    stevel 		 * since these minor nodes are associated with a driver
   1379      0    stevel 		 * and are only bound to a device instance after they
   1380      0    stevel 		 * are opened and attached we don't print them out
   1381      0    stevel 		 * here.
   1382      0    stevel 		 */
   1383      0    stevel 		devt = di_minor_devt(minor);
   1384      0    stevel 		if (major != major(devt))
   1385      0    stevel 			continue;
   1386      0    stevel 
   1387      0    stevel 		/* skip nodes that may have already been displayed */
   1388      0    stevel 		if (minor_displayed(minor))
   1389      0    stevel 			continue;
   1390      0    stevel 
   1391      0    stevel 		if (firstminor) {
   1392      0    stevel 			firstminor = 0;
   1393      0    stevel 			indent_to_level(ilev++);
   1394      0    stevel 			(void) printf("Device Minor Nodes:\n");
   1395      0    stevel 		}
   1396      0    stevel 
   1397      0    stevel 		/* display the device minor node information */
   1398      0    stevel 		indent_to_level(ilev);
   1399      0    stevel 		(void) printf("dev=(%u,%u)\n",
   1400   4453       cth 		    (uint_t)major(devt), (uint_t)minor(devt));
   1401      0    stevel 
   1402      0    stevel 		minor_next = minor;
   1403      0    stevel 		do {
   1404      0    stevel 			/* display device minor node path info */
   1405      0    stevel 			minor_displayed_set(minor_next);
   1406      0    stevel 			dump_minor_data_paths(ilev + 1, minor_next,
   1407   4453       cth 			    devlink_hdl);
   1408      0    stevel 
   1409      0    stevel 			/* get a pointer to the next node */
   1410      0    stevel 			minor_next = minor_ptr(minor_next);
   1411      0    stevel 		} while (minor_next != minor);
   1412      0    stevel 
   1413      0    stevel 		/* display who has this device minor node open */
   1414      0    stevel 		dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
   1415   7224       cth 
   1416   7224       cth 		/* display properties associated with this devt */
   1417   7224       cth 		(void) dump_prop_list(&drvprop_dumpops, "Minor",
   1418   7261       cth 		    ilev + 1, node, devt, NULL);
   1419      0    stevel 	}
   1420      0    stevel 
   1421      0    stevel 	/*
   1422      0    stevel 	 * now go through all the target lnodes for this node and
   1423      0    stevel 	 * if they haven't yet been displayed, display them now.
   1424      0    stevel 	 *
   1425      0    stevel 	 * this happens in the case of clone opens when an "official"
   1426      0    stevel 	 * minor node does not exist for the opened devt
   1427      0    stevel 	 */
   1428      0    stevel 	link = DI_LINK_NIL;
   1429      0    stevel 	while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) {
   1430      0    stevel 		dev_t		devt;
   1431      0    stevel 
   1432      0    stevel 		lnode = di_link_to_lnode(link, DI_LINK_TGT);
   1433      0    stevel 
   1434      0    stevel 		/* if we've already displayed this target lnode, skip it */
   1435      0    stevel 		if (lnode_displayed(lnode))
   1436      0    stevel 			continue;
   1437      0    stevel 
   1438      0    stevel 		if (firstminor) {
   1439      0    stevel 			firstminor = 0;
   1440      0    stevel 			indent_to_level(ilev++);
   1441      0    stevel 			(void) printf("Device Minor Nodes:\n");
   1442      0    stevel 		}
   1443      0    stevel 
   1444      0    stevel 		/* display the device minor node information */
   1445      0    stevel 		indent_to_level(ilev);
   1446      0    stevel 		(void) di_lnode_devt(lnode, &devt);
   1447      0    stevel 		(void) printf("dev=(%u,%u)\n",
   1448   4453       cth 		    (uint_t)major(devt), (uint_t)minor(devt));
   1449      0    stevel 
   1450      0    stevel 		indent_to_level(ilev + 1);
   1451      0    stevel 		(void) printf("dev_path=<clone>\n");
   1452      0    stevel 
   1453      0    stevel 		/* display who has this cloned device minor node open */
   1454      0    stevel 		dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
   1455      0    stevel 
   1456      0    stevel 		/* mark node as displayed */
   1457      0    stevel 		lnode_displayed_set(lnode);
   1458      0    stevel 	}
   1459      0    stevel }
   1460      0    stevel 
   1461      0    stevel static void
   1462      0    stevel dump_link_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
   1463      0    stevel {
   1464      0    stevel 	int		first = 1;
   1465      0    stevel 	di_link_t	link;
   1466      0    stevel 
   1467      0    stevel 	link = DI_LINK_NIL;
   1468      0    stevel 	while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) {
   1469      0    stevel 		di_lnode_t	src_lnode;
   1470      0    stevel 		dev_t		src_devt = DDI_DEV_T_NONE;
   1471      0    stevel 
   1472      0    stevel 		src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
   1473      0    stevel 
   1474      0    stevel 		/*
   1475      0    stevel 		 * here we only want to print out layering information
   1476      0    stevel 		 * if we are the source and our source lnode is not
   1477      0    stevel 		 * associated with any particular dev_t.  (which means
   1478      0    stevel 		 * we won't display this link while dumping minor node
   1479      0    stevel 		 * info.)
   1480      0    stevel 		 */
   1481      0    stevel 		if (di_lnode_devt(src_lnode, &src_devt) != -1)
   1482      0    stevel 			continue;
   1483      0    stevel 
   1484      0    stevel 		if (first) {
   1485      0    stevel 			first = 0;
   1486      0    stevel 			indent_to_level(ilev);
   1487      0    stevel 			(void) printf("Device Layered Over:\n");
   1488      0    stevel 		}
   1489      0    stevel 
   1490      0    stevel 		/* displayed this lnode */
   1491      0    stevel 		link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
   1492      0    stevel 	}
   1493      0    stevel }
   1494      0    stevel 
   1495      0    stevel /*
   1496      0    stevel  * certain 'known' property names may contain 'composite' strings.
   1497      0    stevel  * Handle them here, and print them as 'string1' + 'string2' ...
   1498      0    stevel  */
   1499      0    stevel static int
   1500      0    stevel print_composite_string(const char *var, char *value, int size)
   1501      0    stevel {
   1502      0    stevel 	char *p, *q;
   1503      0    stevel 	char *firstp;
   1504      0    stevel 
   1505      0    stevel 	if ((strcmp(var, "version") != 0) &&
   1506      0    stevel 	    (strcmp(var, "compatible") != 0))
   1507      0    stevel 		return (0);	/* Not a known composite string */
   1508      0    stevel 
   1509      0    stevel 	/*
   1510      0    stevel 	 * Verify that each string in the composite string is non-NULL,
   1511      0    stevel 	 * is within the bounds of the property length, and contains
   1512      0    stevel 	 * printable characters or white space. Otherwise let the
   1513      0    stevel 	 * caller deal with it.
   1514      0    stevel 	 */
   1515      0    stevel 	for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
   1516      0    stevel 		if (strlen(p) == 0)
   1517      0    stevel 			return (0);		/* NULL string */
   1518      0    stevel 		for (q = p; *q; q++) {
   1519      0    stevel 			if (!(isascii(*q) && (isprint(*q) || isspace(*q))))
   1520      0    stevel 				return (0);	/* Not printable or space */
   1521      0    stevel 		}
   1522      0    stevel 		if (q > (firstp + size))
   1523      0    stevel 			return (0);		/* Out of bounds */
   1524      0    stevel 	}
   1525      0    stevel 
   1526      0    stevel 	for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
   1527      0    stevel 		if (p == firstp)
   1528      0    stevel 			(void) printf("'%s'", p);
   1529      0    stevel 		else
   1530      0    stevel 			(void) printf(" + '%s'", p);
   1531      0    stevel 	}
   1532      0    stevel 	(void) putchar('\n');
   1533      0    stevel 	return (1);
   1534      0    stevel }
   1535      0    stevel 
   1536      0    stevel /*
   1537      0    stevel  * Print one property and its value. Handle the verbose case.
   1538      0    stevel  */
   1539      0    stevel static void
   1540      0    stevel print_one(nvpair_t *nvp, int level)
   1541      0    stevel {
   1542      0    stevel 	int i;
   1543      0    stevel 	int endswap = 0;
   1544      0    stevel 	uint_t valsize;
   1545      0    stevel 	char *value;
   1546      0    stevel 	char *var = nvpair_name(nvp);
   1547      0    stevel 
   1548      0    stevel 	indent_to_level(level);
   1549      0    stevel 	(void) printf("%s: ", var);
   1550      0    stevel 
   1551      0    stevel 	switch (nvpair_type(nvp)) {
   1552      0    stevel 	case DATA_TYPE_BOOLEAN:
   1553      0    stevel 		(void) printf(" \n");
   1554      0    stevel 		return;
   1555      0    stevel 	case DATA_TYPE_BYTE_ARRAY:
   1556      0    stevel 		if (nvpair_value_byte_array(nvp, (uchar_t **)&value,
   1557      0    stevel 		    &valsize)) {
   1558      0    stevel 			(void) printf("data not available.\n");
   1559      0    stevel 			return;
   1560      0    stevel 		}
   1561      0    stevel 		valsize--;	/* take out null added by driver */
   1562      0    stevel 
   1563      0    stevel 		/*
   1564      0    stevel 		 * Do not print valsize > MAXVALSIZE, to be compatible
   1565      0    stevel 		 * with old behavior. E.g. intel's eisa-nvram property
   1566      0    stevel 		 * has a size of 65 K.
   1567      0    stevel 		 */
   1568      0    stevel 		if (valsize > MAXVALSIZE) {
   1569      0    stevel 			(void) printf(" \n");
   1570      0    stevel 			return;
   1571      0    stevel 		}
   1572      0    stevel 		break;
   1573      0    stevel 	default:
   1574      0    stevel 		(void) printf("data type unexpected.\n");
   1575      0    stevel 		return;
   1576      0    stevel 	}
   1577      0    stevel 
   1578      0    stevel 	/*
   1579      0    stevel 	 * Handle printing verbosely
   1580      0    stevel 	 */
   1581      0    stevel 	if (print_composite_string(var, value, valsize)) {
   1582      0    stevel 		return;
   1583      0    stevel 	}
   1584      0    stevel 
   1585      0    stevel 	if (!unprintable(value, valsize)) {
   1586      0    stevel 		(void) printf(" '%s'\n", value);
   1587      0    stevel 		return;
   1588      0    stevel 	}
   1589      0    stevel 
   1590      0    stevel 	(void) printf(" ");
   1591      0    stevel #ifdef	__x86
   1592      0    stevel 	/*
   1593      0    stevel 	 * Due to backwards compatibility constraints x86 int
   1594      0    stevel 	 * properties are not in big-endian (ieee 1275) byte order.
   1595      0    stevel 	 * If we have a property that is a multiple of 4 bytes,
   1596      0    stevel 	 * let's assume it is an array of ints and print the bytes
   1597      0    stevel 	 * in little endian order to make things look nicer for
   1598      0    stevel 	 * the user.
   1599      0    stevel 	 */
   1600      0    stevel 	endswap = (valsize % 4) == 0;
   1601      0    stevel #endif	/* __x86 */
   1602      0    stevel 	for (i = 0; i < valsize; i++) {
   1603      0    stevel 		int out;
   1604      0    stevel 		if (i && (i % 4 == 0))
   1605      0    stevel 			(void) putchar('.');
   1606      0    stevel 		if (endswap)
   1607      0    stevel 			out = value[i + (3 - 2 * (i % 4))] & 0xff;
   1608      0    stevel 		else
   1609      0    stevel 			out = value[i] & 0xff;
   1610      0    stevel 
   1611      0    stevel 		(void) printf("%02x", out);
   1612      0    stevel 	}
   1613      0    stevel 	(void) putchar('\n');
   1614      0    stevel }
   1615      0    stevel 
   1616      0    stevel static int
   1617      0    stevel unprintable(char *value, int size)
   1618      0    stevel {
   1619      0    stevel 	int i;
   1620      0    stevel 
   1621      0    stevel 	/*
   1622      0    stevel 	 * Is this just a zero?
   1623      0    stevel 	 */
   1624      0    stevel 	if (size == 0 || value[0] == '\0')
   1625      0    stevel 		return (1);
   1626      0    stevel 	/*
   1627      0    stevel 	 * If any character is unprintable, or if a null appears
   1628      0    stevel 	 * anywhere except at the end of a string, the whole
   1629      0    stevel 	 * property is "unprintable".
   1630      0    stevel 	 */
   1631      0    stevel 	for (i = 0; i < size; ++i) {
   1632      0    stevel 		if (value[i] == '\0')
   1633      0    stevel 			return (i != (size - 1));
   1634      0    stevel 		if (!isascii(value[i]) || iscntrl(value[i]))
   1635      0    stevel 			return (1);
   1636      0    stevel 	}
   1637      0    stevel 	return (0);
   1638      0    stevel }
   1639      0    stevel 
   1640      0    stevel static int
   1641      0    stevel promopen(int oflag)
   1642      0    stevel {
   1643      0    stevel 	for (;;)  {
   1644      0    stevel 		if ((prom_fd = open(opts.o_promdev, oflag)) < 0)  {
   1645      0    stevel 			if (errno == EAGAIN)   {
   1646      0    stevel 				(void) sleep(5);
   1647      0    stevel 				continue;
   1648      0    stevel 			}
   1649      0    stevel 			if (errno == ENXIO)
   1650      0    stevel 				return (-1);
   1651      0    stevel 			if (getzoneid() == GLOBAL_ZONEID) {
   1652      0    stevel 				_exit(_error("cannot open %s",
   1653      0    stevel 				    opts.o_promdev));
   1654      0    stevel 			}
   1655      0    stevel 			/* not an error if this isn't the global zone */
   1656      0    stevel 			(void) _error(NULL, "openprom facility not available");
   1657      0    stevel 			exit(0);
   1658      0    stevel 		} else
   1659      0    stevel 			return (0);
   1660      0    stevel 	}
   1661      0    stevel }
   1662      0    stevel 
   1663      0    stevel static void
   1664      0    stevel promclose(void)
   1665      0    stevel {
   1666      0    stevel 	if (close(prom_fd) < 0)
   1667      0    stevel 		exit(_error("close error on %s", opts.o_promdev));
   1668      0    stevel }
   1669      0    stevel 
   1670      0    stevel /*
   1671      0    stevel  * Get and print the name of the frame buffer device.
   1672      0    stevel  */
   1673      0    stevel int
   1674      0    stevel do_fbname(void)
   1675      0    stevel {
   1676      0    stevel 	int	retval;
   1677      0    stevel 	char fbuf_path[MAXPATHLEN];
   1678      0    stevel 
   1679      0    stevel 	retval =  modctl(MODGETFBNAME, (caddr_t)fbuf_path);
   1680      0    stevel 
   1681      0    stevel 	if (retval == 0) {
   1682      0    stevel 		(void) printf("%s\n", fbuf_path);
   1683      0    stevel 	} else {
   1684      0    stevel 		if (retval == EFAULT) {
   1685      0    stevel 			(void) fprintf(stderr,
   1686      0    stevel 			"Error copying fb path to userland\n");
   1687      0    stevel 		} else {
   1688      0    stevel 			(void) fprintf(stderr,
   1689      0    stevel 			"Console output device is not a frame buffer\n");
   1690      0    stevel 		}
   1691      0    stevel 		return (1);
   1692      0    stevel 	}
   1693      0    stevel 	return (0);
   1694      0    stevel }
   1695      0    stevel 
   1696      0    stevel /*
   1697      0    stevel  * Get and print the PROM version.
   1698      0    stevel  */
   1699      0    stevel int
   1700      0    stevel do_promversion(void)
   1701      0    stevel {
   1702      0    stevel 	Oppbuf	oppbuf;
   1703      0    stevel 	struct openpromio *opp = &(oppbuf.opp);
   1704      0    stevel 
   1705      0    stevel 	if (promopen(O_RDONLY))  {
   1706      0    stevel 		(void) fprintf(stderr, "Cannot open openprom device\n");
   1707      0    stevel 		return (1);
   1708      0    stevel 	}
   1709      0    stevel 
   1710      0    stevel 	opp->oprom_size = MAXVALSIZE;
   1711      0    stevel 	if (ioctl(prom_fd, OPROMGETVERSION, opp) < 0)
   1712      0    stevel 		exit(_error("OPROMGETVERSION"));
   1713      0    stevel 
   1714      0    stevel 	(void) printf("%s\n", opp->oprom_array);
   1715      0    stevel 	promclose();
   1716      0    stevel 	return (0);
   1717      0    stevel }
   1718      0    stevel 
   1719      0    stevel int
   1720      0    stevel do_prom_version64(void)
   1721      0    stevel {
   1722      0    stevel #ifdef	sparc
   1723      0    stevel 	Oppbuf	oppbuf;
   1724      0    stevel 	struct openpromio *opp = &(oppbuf.opp);
   1725      0    stevel 	/*LINTED*/
   1726      0    stevel 	struct openprom_opr64 *opr = (struct openprom_opr64 *)opp->oprom_array;
   1727      0    stevel 
   1728      0    stevel 	static const char msg[] =
   1729   4453       cth 	    "NOTICE: The firmware on this system does not support the "
   1730   4453       cth 	    "64-bit OS.\n"
   1731   4453       cth 	    "\tPlease upgrade to at least the following version:\n"
   1732   4453       cth 	    "\t\t%s\n\n";
   1733      0    stevel 
   1734      0    stevel 	if (promopen(O_RDONLY))  {
   1735      0    stevel 		(void) fprintf(stderr, "Cannot open openprom device\n");
   1736      0    stevel 		return (-1);
   1737      0    stevel 	}
   1738      0    stevel 
   1739      0    stevel 	opp->oprom_size = MAXVALSIZE;
   1740      0    stevel 	if (ioctl(prom_fd, OPROMREADY64, opp) < 0)
   1741      0    stevel 		exit(_error("OPROMREADY64"));
   1742      0    stevel 
   1743      0    stevel 	if (opr->return_code == 0)
   1744      0    stevel 		return (0);
   1745      0    stevel 
   1746      0    stevel 	(void) printf(msg, opr->message);
   1747      0    stevel 
   1748      0    stevel 	promclose();
   1749      0    stevel 	return (opr->return_code);
   1750      0    stevel #else
   1751      0    stevel 	return (0);
   1752      0    stevel #endif
   1753      0    stevel }
   1754      0    stevel 
   1755      0    stevel int
   1756      0    stevel do_productinfo(void)
   1757      0    stevel {
   1758      0    stevel 	di_node_t root, next_node;
   1759      0    stevel 	di_prom_handle_t promh;
   1760      0    stevel 	static const char *root_prop[] = { "name", "model", "banner-name",
   1761      0    stevel 					"compatible" };
   1762      0    stevel 	static const char *root_propv[] = { "name", "model", "banner-name",
   1763      0    stevel 					"compatible", "idprom" };
   1764      0    stevel 	static const char *oprom_prop[] = { "model", "version" };
   1765      0    stevel 
   1766      0    stevel 
   1767      0    stevel 	root = di_init("/", DINFOCPYALL);
   1768      0    stevel 
   1769      0    stevel 	if (root == DI_NODE_NIL) {
   1770      0    stevel 		(void) fprintf(stderr, "di_init() failed\n");
   1771      0    stevel 		return (1);
   1772      0    stevel 	}
   1773      0    stevel 
   1774      0    stevel 	promh = di_prom_init();
   1775      0    stevel 
   1776      0    stevel 	if (promh == DI_PROM_HANDLE_NIL) {
   1777      0    stevel 		(void) fprintf(stderr, "di_prom_init() failed\n");
   1778      0    stevel 		return (1);
   1779      0    stevel 	}
   1780      0    stevel 
   1781      0    stevel 	if (opts.o_verbose) {
   1782      0    stevel 		dump_prodinfo(promh, root, root_propv, "root",
   1783   4453       cth 		    NUM_ELEMENTS(root_propv));
   1784      0    stevel 
   1785      0    stevel 		/* Get model and version properties under node "openprom" */
   1786      0    stevel 		next_node = find_node_by_name(promh, root, "openprom");
   1787      0    stevel 		if (next_node != DI_NODE_NIL)
   1788      0    stevel 			dump_prodinfo(promh, next_node, oprom_prop,
   1789   4453       cth 			    "openprom", NUM_ELEMENTS(oprom_prop));
   1790      0    stevel 
   1791      0    stevel 	} else
   1792      0    stevel 		dump_prodinfo(promh, root, root_prop, "root",
   1793   4453       cth 		    NUM_ELEMENTS(root_prop));
   1794      0    stevel 	di_prom_fini(promh);
   1795      0    stevel 	di_fini(root);
   1796      0    stevel 	return (0);
   1797      0    stevel }
   1798      0    stevel 
   1799      0    stevel di_node_t
   1800      0    stevel find_node_by_name(di_prom_handle_t promh, di_node_t parent,
   1801      0    stevel 		char *node_name)
   1802      0    stevel {
   1803      0    stevel 	di_node_t next_node;
   1804      0    stevel 	uchar_t *prop_valp;
   1805      0    stevel 
   1806   4900  vb160487 	for (next_node = di_child_node(parent); next_node != DI_NODE_NIL;
   1807   4900  vb160487 	    next_node = di_sibling_node(next_node)) {
   1808   4900  vb160487 		int len;
   1809   4900  vb160487 
   1810   4900  vb160487 		len = get_propval_by_name(promh, next_node, "name", &prop_valp);
   1811   4900  vb160487 		if ((len != -1) && (strcmp((char *)prop_valp, node_name) == 0))
   1812      0    stevel 			return (next_node);
   1813      0    stevel 	}
   1814      0    stevel 	return (DI_NODE_NIL);
   1815      0    stevel }
   1816      0    stevel 
   1817      0    stevel 
   1818      0    stevel int
   1819      0    stevel get_propval_by_name(di_prom_handle_t promh, di_node_t node, const char *name,
   1820      0    stevel 			uchar_t **valp)
   1821      0    stevel {
   1822      0    stevel 	int len;
   1823      0    stevel 	uchar_t *bufp;
   1824      0    stevel 
   1825      0    stevel 	len = di_prom_prop_lookup_bytes(promh, node, name,
   1826   4453       cth 	    (uchar_t **)&bufp);
   1827      0    stevel 	if (len != -1) {
   1828      0    stevel 		*valp = (uchar_t *)malloc(len);
   1829      0    stevel 		(void) memcpy(*valp, bufp, len);
   1830      0    stevel 	}
   1831      0    stevel 	return (len);
   1832      0    stevel }
   1833      0    stevel 
   1834      0    stevel 
   1835      0    stevel static void
   1836      0    stevel dump_prodinfo(di_prom_handle_t promh, di_node_t node, const char **propstr,
   1837      0    stevel 		char *node_name, int num)
   1838      0    stevel {
   1839      0    stevel 	int out, len, index1, index, endswap = 0;
   1840      0    stevel 	uchar_t *prop_valp;
   1841      0    stevel 
   1842      0    stevel 	for (index1 = 0; index1 < num; index1++) {
   1843      0    stevel 		len = get_propval_by_name(promh, node, propstr[index1],
   1844   4453       cth 		    &prop_valp);
   1845      0    stevel 		if (len != -1) {
   1846      0    stevel 			if (strcmp(node_name, "root"))
   1847      0    stevel 				(void) printf("%s ", node_name);
   1848      0    stevel 
   1849      0    stevel 			(void) printf("%s: ", propstr[index1]);
   1850      0    stevel 
   1851      0    stevel 			if (print_composite_string((const char *)
   1852   4453       cth 			    propstr[index1], (char *)prop_valp, len)) {
   1853      0    stevel 				free(prop_valp);
   1854      0    stevel 				continue;
   1855      0    stevel 			}
   1856      0    stevel 
   1857      0    stevel 			if (!unprintable((char *)prop_valp, len)) {
   1858      0    stevel 				(void) printf(" %s\n", (char *)prop_valp);
   1859      0    stevel 				free(prop_valp);
   1860      0    stevel 				continue;
   1861      0    stevel 			}
   1862      0    stevel 
   1863      0    stevel 			(void) printf(" ");
   1864      0    stevel #ifdef  __x86
   1865      0    stevel 			endswap = (len % 4) == 0;
   1866      0    stevel #endif  /* __x86 */
   1867      0    stevel 			for (index = 0; index < len; index++) {
   1868      0    stevel 				if (index && (index % 4 == 0))
   1869      0    stevel 					(void) putchar('.');
   1870      0    stevel 				if (endswap)
   1871      0    stevel 					out = prop_valp[index +
   1872   4453       cth 					    (3 - 2 * (index % 4))] & 0xff;
   1873      0    stevel 				else
   1874      0    stevel 					out = prop_valp[index] & 0xff;
   1875      0    stevel 				(void) printf("%02x", out);
   1876      0    stevel 			}
   1877      0    stevel 			(void) putchar('\n');
   1878      0    stevel 			free(prop_valp);
   1879      0    stevel 		}
   1880      0    stevel 	}
   1881      0    stevel }
   1882   7261       cth 
   1883   7261       cth static int
   1884   7261       cth dump_compatible(char *name, int ilev, di_node_t node)
   1885   7261       cth {
   1886   7261       cth 	int	ncompat;
   1887   7261       cth 	char	*compat_array;
   1888   7261       cth 	char	*p, *q;
   1889   7261       cth 	int	i;
   1890   7261       cth 
   1891   7261       cth 	if (node == DI_PATH_NIL)
   1892   7261       cth 		return (0);
   1893   7261       cth 
   1894   7261       cth 	ncompat = di_compatible_names(node, &compat_array);
   1895   7261       cth 	if (ncompat <= 0)
   1896   7261       cth 		return (0);	/* no 'compatible' available */
   1897   7261       cth 
   1898   7261       cth 	/* verify integrety of compat_array */
   1899   7261       cth 	for (i = 0, p = compat_array; i < ncompat; i++, p += strlen(p) + 1) {
   1900   7261       cth 		if (strlen(p) == 0)
   1901   7261       cth 			return (0);		/* NULL string */
   1902   7261       cth 		for (q = p; *q; q++) {
   1903   7261       cth 			if (!(isascii(*q) && (isprint(*q) || isspace(*q))))
   1904   7261       cth 				return (0);	/* Not printable or space */
   1905   7261       cth 		}
   1906   7261       cth 	}
   1907   7261       cth 
   1908   7261       cth 	/* If name is non-NULL, produce header */
   1909   7261       cth 	if (name) {
   1910   7261       cth 		indent_to_level(ilev);
   1911   7261       cth 		(void) printf("%s properties:\n", name);
   1912   7261       cth 	}
   1913   7261       cth 	ilev++;
   1914   7261       cth 
   1915   7261       cth 	/* process like a string array property */
   1916   7261       cth 	indent_to_level(ilev);
   1917   7261       cth 	(void) printf("name='compatible' type=string items=%d\n", ncompat);
   1918   7261       cth 	indent_to_level(ilev);
   1919   7261       cth 	(void) printf("    value=");
   1920   7261       cth 	for (i = 0, p = compat_array; i < (ncompat - 1);
   1921   7261       cth 	    i++, p += strlen(p) + 1)
   1922   7261       cth 		(void) printf("'%s' + ", p);
   1923   7261       cth 	(void) printf("'%s'", p);
   1924   7261       cth 	(void) putchar('\n');
   1925   7261       cth 	return (1);
   1926   7261       cth }
   1927