xref: /titanic_51/usr/src/cmd/prtconf/pdevinfo.c (revision 25e8c5aa2b496d9026e958ac731a610167574f59)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
558c0eeecScth  * Common Development and Distribution License (the "License").
658c0eeecScth  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2258c0eeecScth  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * For machines that support the openprom, fetch and print the list
307c478bd9Sstevel@tonic-gate  * of devices that the kernel has fetched from the prom or conjured up.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdarg.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <unistd.h>
407c478bd9Sstevel@tonic-gate #include <stropts.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/openpromio.h>
457c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <zone.h>
487c478bd9Sstevel@tonic-gate #include <libnvpair.h>
497c478bd9Sstevel@tonic-gate #include "prtconf.h"
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate typedef char *(*dump_propname_t)(void *);
537c478bd9Sstevel@tonic-gate typedef int (*dump_proptype_t)(void *);
547c478bd9Sstevel@tonic-gate typedef int (*dump_propints_t)(void *, int **);
557c478bd9Sstevel@tonic-gate typedef int (*dump_propint64_t)(void *, int64_t **);
567c478bd9Sstevel@tonic-gate typedef int (*dump_propstrings_t)(void *, char **);
577c478bd9Sstevel@tonic-gate typedef int (*dump_propbytes_t)(void *, uchar_t **);
587c478bd9Sstevel@tonic-gate typedef int (*dump_proprawdata_t)(void *, uchar_t **);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate typedef struct dumpops_common {
617c478bd9Sstevel@tonic-gate 	dump_propname_t doc_propname;
627c478bd9Sstevel@tonic-gate 	dump_proptype_t doc_proptype;
637c478bd9Sstevel@tonic-gate 	dump_propints_t doc_propints;
647c478bd9Sstevel@tonic-gate 	dump_propint64_t doc_propint64;
657c478bd9Sstevel@tonic-gate 	dump_propstrings_t doc_propstrings;
667c478bd9Sstevel@tonic-gate 	dump_propbytes_t doc_propbytes;
677c478bd9Sstevel@tonic-gate 	dump_proprawdata_t doc_proprawdata;
687c478bd9Sstevel@tonic-gate } dumpops_common_t;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static const dumpops_common_t prop_dumpops = {
717c478bd9Sstevel@tonic-gate 	(dump_propname_t)di_prop_name,
727c478bd9Sstevel@tonic-gate 	(dump_proptype_t)di_prop_type,
737c478bd9Sstevel@tonic-gate 	(dump_propints_t)di_prop_ints,
747c478bd9Sstevel@tonic-gate 	(dump_propint64_t)di_prop_int64,
757c478bd9Sstevel@tonic-gate 	(dump_propstrings_t)di_prop_strings,
767c478bd9Sstevel@tonic-gate 	(dump_propbytes_t)di_prop_bytes,
777c478bd9Sstevel@tonic-gate 	(dump_proprawdata_t)di_prop_rawdata
787c478bd9Sstevel@tonic-gate }, pathprop_common_dumpops = {
797c478bd9Sstevel@tonic-gate 	(dump_propname_t)di_path_prop_name,
807c478bd9Sstevel@tonic-gate 	(dump_proptype_t)di_path_prop_type,
817c478bd9Sstevel@tonic-gate 	(dump_propints_t)di_path_prop_ints,
827c478bd9Sstevel@tonic-gate 	(dump_propint64_t)di_path_prop_int64s,
837c478bd9Sstevel@tonic-gate 	(dump_propstrings_t)di_path_prop_strings,
847c478bd9Sstevel@tonic-gate 	(dump_propbytes_t)di_path_prop_bytes,
857c478bd9Sstevel@tonic-gate 	(dump_proprawdata_t)di_path_prop_bytes
867c478bd9Sstevel@tonic-gate };
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate typedef void *(*dump_nextprop_t)(void *, void *);
897c478bd9Sstevel@tonic-gate typedef dev_t (*dump_propdevt_t)(void *);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate typedef struct dumpops {
927c478bd9Sstevel@tonic-gate 	const dumpops_common_t *dop_common;
937c478bd9Sstevel@tonic-gate 	dump_nextprop_t dop_nextprop;
947c478bd9Sstevel@tonic-gate 	dump_propdevt_t dop_propdevt;
957c478bd9Sstevel@tonic-gate } dumpops_t;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate static const dumpops_t sysprop_dumpops = {
987c478bd9Sstevel@tonic-gate 	&prop_dumpops,
997c478bd9Sstevel@tonic-gate 	(dump_nextprop_t)di_prop_sys_next,
1007c478bd9Sstevel@tonic-gate 	NULL
1017c478bd9Sstevel@tonic-gate }, globprop_dumpops = {
1027c478bd9Sstevel@tonic-gate 	&prop_dumpops,
1037c478bd9Sstevel@tonic-gate 	(dump_nextprop_t)di_prop_global_next,
1047c478bd9Sstevel@tonic-gate 	NULL
1057c478bd9Sstevel@tonic-gate }, drvprop_dumpops = {
1067c478bd9Sstevel@tonic-gate 	&prop_dumpops,
1077c478bd9Sstevel@tonic-gate 	(dump_nextprop_t)di_prop_drv_next,
1087c478bd9Sstevel@tonic-gate 	(dump_propdevt_t)di_prop_devt
1097c478bd9Sstevel@tonic-gate }, hwprop_dumpops = {
1107c478bd9Sstevel@tonic-gate 	&prop_dumpops,
1117c478bd9Sstevel@tonic-gate 	(dump_nextprop_t)di_prop_hw_next,
1127c478bd9Sstevel@tonic-gate 	NULL
1137c478bd9Sstevel@tonic-gate }, pathprop_dumpops = {
1147c478bd9Sstevel@tonic-gate 	&pathprop_common_dumpops,
1157c478bd9Sstevel@tonic-gate 	(dump_nextprop_t)di_path_prop_next,
1167c478bd9Sstevel@tonic-gate 	NULL
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate #define	PROPNAME(ops) (ops->dop_common->doc_propname)
1207c478bd9Sstevel@tonic-gate #define	PROPTYPE(ops) (ops->dop_common->doc_proptype)
1217c478bd9Sstevel@tonic-gate #define	PROPINTS(ops) (ops->dop_common->doc_propints)
1227c478bd9Sstevel@tonic-gate #define	PROPINT64(ops) (ops->dop_common->doc_propint64)
1237c478bd9Sstevel@tonic-gate #define	PROPSTRINGS(ops) (ops->dop_common->doc_propstrings)
1247c478bd9Sstevel@tonic-gate #define	PROPBYTES(ops) (ops->dop_common->doc_propbytes)
1257c478bd9Sstevel@tonic-gate #define	PROPRAWDATA(ops) (ops->dop_common->doc_proprawdata)
1267c478bd9Sstevel@tonic-gate #define	NEXTPROP(ops) (ops->dop_nextprop)
1277c478bd9Sstevel@tonic-gate #define	PROPDEVT(ops) (ops->dop_propdevt)
1287c478bd9Sstevel@tonic-gate #define	NUM_ELEMENTS(A) (sizeof (A) / sizeof (A[0]))
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static int prop_type_guess(const dumpops_t *, void *, void **, int *);
1317c478bd9Sstevel@tonic-gate static void dump_prop_list_common(const dumpops_t *, int, void *);
1327c478bd9Sstevel@tonic-gate static void walk_driver(di_node_t, di_devlink_handle_t);
1337c478bd9Sstevel@tonic-gate static int dump_devs(di_node_t, void *);
1347c478bd9Sstevel@tonic-gate static int dump_prop_list(const dumpops_t *, const char *, int, di_node_t);
1357c478bd9Sstevel@tonic-gate static int _error(const char *, ...);
1367c478bd9Sstevel@tonic-gate static int is_openprom();
1377c478bd9Sstevel@tonic-gate static void walk(uchar_t *, uint_t, int);
1387c478bd9Sstevel@tonic-gate static void dump_node(nvlist_t *, int);
1397c478bd9Sstevel@tonic-gate static void dump_prodinfo(di_prom_handle_t, di_node_t, const char **,
1407c478bd9Sstevel@tonic-gate 				char *, int);
1417c478bd9Sstevel@tonic-gate static di_node_t find_node_by_name(di_prom_handle_t, di_node_t, char *);
1427c478bd9Sstevel@tonic-gate static int get_propval_by_name(di_prom_handle_t, di_node_t,
1437c478bd9Sstevel@tonic-gate 				const char *, uchar_t **);
1447c478bd9Sstevel@tonic-gate static void dump_pathing_data(int, di_node_t);
1457c478bd9Sstevel@tonic-gate static void dump_minor_data(int, di_node_t, di_devlink_handle_t);
1467c478bd9Sstevel@tonic-gate static void dump_link_data(int, di_node_t, di_devlink_handle_t);
1477c478bd9Sstevel@tonic-gate static int print_composite_string(const char *, char *, int);
1487c478bd9Sstevel@tonic-gate static void print_one(nvpair_t *, int);
1497c478bd9Sstevel@tonic-gate static int unprintable(char *, int);
1507c478bd9Sstevel@tonic-gate static int promopen(int);
1517c478bd9Sstevel@tonic-gate static void promclose();
1527c478bd9Sstevel@tonic-gate static di_node_t find_target_node(di_node_t);
1537c478bd9Sstevel@tonic-gate static void node_display_set(di_node_t);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate void
1567c478bd9Sstevel@tonic-gate prtconf_devinfo(void)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	struct di_priv_data	fetch;
1597c478bd9Sstevel@tonic-gate 	di_devlink_handle_t	devlink_hdl = NULL;
1607c478bd9Sstevel@tonic-gate 	di_node_t		root_node;
1617c478bd9Sstevel@tonic-gate 	uint_t			flag;
1627c478bd9Sstevel@tonic-gate 	char			*rootpath;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	dprintf("verbosemode %s\n", opts.o_verbose ? "on" : "off");
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/* determine what info we need to get from kernel */
1677c478bd9Sstevel@tonic-gate 	flag = DINFOSUBTREE;
1687c478bd9Sstevel@tonic-gate 	rootpath = "/";
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if (opts.o_target) {
1717c478bd9Sstevel@tonic-gate 		flag |= (DINFOMINOR | DINFOPATH);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (opts.o_forcecache) {
17558c0eeecScth 		if (dbg.d_forceload) {
1767c478bd9Sstevel@tonic-gate 			exit(_error(NULL, "option combination not supported"));
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 		if (strcmp(rootpath, "/") != 0) {
1797c478bd9Sstevel@tonic-gate 			exit(_error(NULL, "invalid root path for option"));
1807c478bd9Sstevel@tonic-gate 		}
1817c478bd9Sstevel@tonic-gate 		flag = DINFOCACHE;
18258c0eeecScth 	} else if (opts.o_verbose) {
18358c0eeecScth 		flag |= (DINFOPROP | DINFOMINOR |
18458c0eeecScth 		    DINFOPRIVDATA | DINFOPATH | DINFOLYR);
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	if (dbg.d_forceload) {
1887c478bd9Sstevel@tonic-gate 		flag |= DINFOFORCE;
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (opts.o_verbose) {
1927c478bd9Sstevel@tonic-gate 		init_priv_data(&fetch);
1937c478bd9Sstevel@tonic-gate 		root_node = di_init_impl(rootpath, flag, &fetch);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 		/* get devlink (aka aliases) data */
1967c478bd9Sstevel@tonic-gate 		if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL)
1977c478bd9Sstevel@tonic-gate 			exit(_error("di_devlink_init() failed."));
1987c478bd9Sstevel@tonic-gate 	} else
1997c478bd9Sstevel@tonic-gate 		root_node = di_init(rootpath, flag);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if (root_node == DI_NODE_NIL) {
2027c478bd9Sstevel@tonic-gate 		(void) _error(NULL, "devinfo facility not available");
2037c478bd9Sstevel@tonic-gate 		/* not an error if this isn't the global zone */
2047c478bd9Sstevel@tonic-gate 		if (getzoneid() == GLOBAL_ZONEID)
2057c478bd9Sstevel@tonic-gate 			exit(-1);
2067c478bd9Sstevel@tonic-gate 		else
2077c478bd9Sstevel@tonic-gate 			exit(0);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * ...and walk all nodes to report them out...
2127c478bd9Sstevel@tonic-gate 	 */
2137c478bd9Sstevel@tonic-gate 	if (dbg.d_bydriver) {
2147c478bd9Sstevel@tonic-gate 		opts.o_target = 0;
2157c478bd9Sstevel@tonic-gate 		walk_driver(root_node, devlink_hdl);
2167c478bd9Sstevel@tonic-gate 		if (devlink_hdl != NULL)
2177c478bd9Sstevel@tonic-gate 			(void) di_devlink_fini(&devlink_hdl);
2187c478bd9Sstevel@tonic-gate 		di_fini(root_node);
2197c478bd9Sstevel@tonic-gate 		return;
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	if (opts.o_target) {
2237c478bd9Sstevel@tonic-gate 		di_node_t target_node, node;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		target_node = find_target_node(root_node);
2267c478bd9Sstevel@tonic-gate 		if (target_node == DI_NODE_NIL) {
2277c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: "
2287c478bd9Sstevel@tonic-gate 			    "invalid device path specified\n",
2297c478bd9Sstevel@tonic-gate 			    opts.o_progname);
2307c478bd9Sstevel@tonic-gate 			exit(1);
2317c478bd9Sstevel@tonic-gate 		}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 		/* mark the target node so we display it */
2347c478bd9Sstevel@tonic-gate 		node_display_set(target_node);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		if (opts.o_ancestors) {
2377c478bd9Sstevel@tonic-gate 			/*
2387c478bd9Sstevel@tonic-gate 			 * mark the ancestors of this node so we display
2397c478bd9Sstevel@tonic-gate 			 * them as well
2407c478bd9Sstevel@tonic-gate 			 */
2417c478bd9Sstevel@tonic-gate 			node = target_node;
2427c478bd9Sstevel@tonic-gate 			while (node = di_parent_node(node))
2437c478bd9Sstevel@tonic-gate 				node_display_set(node);
2447c478bd9Sstevel@tonic-gate 		} else {
2457c478bd9Sstevel@tonic-gate 			/*
2467c478bd9Sstevel@tonic-gate 			 * when we display device tree nodes the indentation
2477c478bd9Sstevel@tonic-gate 			 * level is based off of tree depth.
2487c478bd9Sstevel@tonic-gate 			 *
2497c478bd9Sstevel@tonic-gate 			 * here we increment o_target to reflect the
2507c478bd9Sstevel@tonic-gate 			 * depth of the target node in the tree.  we do
2517c478bd9Sstevel@tonic-gate 			 * this so that when we calculate the indentation
2527c478bd9Sstevel@tonic-gate 			 * level we can subtract o_target so that the
2537c478bd9Sstevel@tonic-gate 			 * target node starts with an indentation of zero.
2547c478bd9Sstevel@tonic-gate 			 */
2557c478bd9Sstevel@tonic-gate 			node = target_node;
2567c478bd9Sstevel@tonic-gate 			while (node = di_parent_node(node))
2577c478bd9Sstevel@tonic-gate 				opts.o_target++;
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 		if (opts.o_children) {
2617c478bd9Sstevel@tonic-gate 			/*
2627c478bd9Sstevel@tonic-gate 			 * mark the children of this node so we display
2637c478bd9Sstevel@tonic-gate 			 * them as well
2647c478bd9Sstevel@tonic-gate 			 */
2657c478bd9Sstevel@tonic-gate 			(void) di_walk_node(target_node, DI_WALK_CLDFIRST,
2667c478bd9Sstevel@tonic-gate 			    (void *)1,
2677c478bd9Sstevel@tonic-gate 			    (int (*)(di_node_t, void *))
2687c478bd9Sstevel@tonic-gate 			    node_display_set);
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	(void) di_walk_node(root_node, DI_WALK_CLDFIRST, devlink_hdl,
2737c478bd9Sstevel@tonic-gate 	    dump_devs);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	if (devlink_hdl != NULL)
2767c478bd9Sstevel@tonic-gate 		(void) di_devlink_fini(&devlink_hdl);
2777c478bd9Sstevel@tonic-gate 	di_fini(root_node);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate  * utility routines
2827c478bd9Sstevel@tonic-gate  */
2837c478bd9Sstevel@tonic-gate static int
2847c478bd9Sstevel@tonic-gate i_find_target_node(di_node_t node, void *arg)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	di_node_t *target = (di_node_t *)arg;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	if (opts.o_devices_path != NULL) {
2897c478bd9Sstevel@tonic-gate 		char *path;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		if ((path = di_devfs_path(node)) == NULL)
2927c478bd9Sstevel@tonic-gate 			exit(_error("failed to allocate memory"));
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 		if (strcmp(opts.o_devices_path, path) == 0) {
2957c478bd9Sstevel@tonic-gate 			di_devfs_path_free(path);
2967c478bd9Sstevel@tonic-gate 			*target = node;
2977c478bd9Sstevel@tonic-gate 			return (DI_WALK_TERMINATE);
2987c478bd9Sstevel@tonic-gate 		}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		di_devfs_path_free(path);
3017c478bd9Sstevel@tonic-gate 	} else if (opts.o_devt != DDI_DEV_T_NONE) {
3027c478bd9Sstevel@tonic-gate 		di_minor_t	minor = DI_MINOR_NIL;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 		while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
3057c478bd9Sstevel@tonic-gate 			if (opts.o_devt == di_minor_devt(minor)) {
3067c478bd9Sstevel@tonic-gate 				*target = node;
3077c478bd9Sstevel@tonic-gate 				return (DI_WALK_TERMINATE);
3087c478bd9Sstevel@tonic-gate 			}
3097c478bd9Sstevel@tonic-gate 		}
3107c478bd9Sstevel@tonic-gate 	} else {
3117c478bd9Sstevel@tonic-gate 		/* we should never get here */
3127c478bd9Sstevel@tonic-gate 		exit(_error(NULL, "internal error"));
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate static di_node_t
3187c478bd9Sstevel@tonic-gate find_target_node(di_node_t root_node)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	di_node_t target = DI_NODE_NIL;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/* special case to allow displaying of the root node */
3237c478bd9Sstevel@tonic-gate 	if (opts.o_devices_path != NULL) {
3247c478bd9Sstevel@tonic-gate 		if (strlen(opts.o_devices_path) == 0)
3257c478bd9Sstevel@tonic-gate 			return (root_node);
3267c478bd9Sstevel@tonic-gate 		if (strcmp(opts.o_devices_path, ".") == 0)
3277c478bd9Sstevel@tonic-gate 			return (root_node);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	(void) di_walk_node(root_node, DI_WALK_CLDFIRST, &target,
3317c478bd9Sstevel@tonic-gate 	    i_find_target_node);
3327c478bd9Sstevel@tonic-gate 	return (target);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate #define	NODE_DISPLAY		(1<<0)
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate static long
3387c478bd9Sstevel@tonic-gate node_display(di_node_t node)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	long data = (long)di_node_private_get(node);
3417c478bd9Sstevel@tonic-gate 	return (data & NODE_DISPLAY);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate static void
3457c478bd9Sstevel@tonic-gate node_display_set(di_node_t node)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	long data = (long)di_node_private_get(node);
3487c478bd9Sstevel@tonic-gate 	data |= NODE_DISPLAY;
3497c478bd9Sstevel@tonic-gate 	di_node_private_set(node, (void *)data);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate #define	LNODE_DISPLAYED		(1<<0)
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate static long
3557c478bd9Sstevel@tonic-gate lnode_displayed(di_lnode_t lnode)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	long data = (long)di_lnode_private_get(lnode);
3587c478bd9Sstevel@tonic-gate 	return (data & LNODE_DISPLAYED);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate static void
3627c478bd9Sstevel@tonic-gate lnode_displayed_set(di_lnode_t lnode)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	long data = (long)di_lnode_private_get(lnode);
3657c478bd9Sstevel@tonic-gate 	data |= LNODE_DISPLAYED;
3667c478bd9Sstevel@tonic-gate 	di_lnode_private_set(lnode, (void *)data);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static void
3707c478bd9Sstevel@tonic-gate lnode_displayed_clear(di_lnode_t lnode)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	long data = (long)di_lnode_private_get(lnode);
3737c478bd9Sstevel@tonic-gate 	data &= ~LNODE_DISPLAYED;
3747c478bd9Sstevel@tonic-gate 	di_lnode_private_set(lnode, (void *)data);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate #define	MINOR_DISPLAYED		(1<<0)
3787c478bd9Sstevel@tonic-gate #define	MINOR_PTR		(~(0x3))
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate static long
3817c478bd9Sstevel@tonic-gate minor_displayed(di_minor_t minor)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	long data = (long)di_minor_private_get(minor);
3847c478bd9Sstevel@tonic-gate 	return (data & MINOR_DISPLAYED);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate static void
3887c478bd9Sstevel@tonic-gate minor_displayed_set(di_minor_t minor)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	long data = (long)di_minor_private_get(minor);
3917c478bd9Sstevel@tonic-gate 	data |= MINOR_DISPLAYED;
3927c478bd9Sstevel@tonic-gate 	di_minor_private_set(minor, (void *)data);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate static void
3967c478bd9Sstevel@tonic-gate minor_displayed_clear(di_minor_t minor)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	long data = (long)di_minor_private_get(minor);
3997c478bd9Sstevel@tonic-gate 	data &= ~MINOR_DISPLAYED;
4007c478bd9Sstevel@tonic-gate 	di_minor_private_set(minor, (void *)data);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate static void *
4047c478bd9Sstevel@tonic-gate minor_ptr(di_minor_t minor)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	long data = (long)di_minor_private_get(minor);
4077c478bd9Sstevel@tonic-gate 	return ((void *)(data & MINOR_PTR));
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate static void
4117c478bd9Sstevel@tonic-gate minor_ptr_set(di_minor_t minor, void *ptr)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	long data = (long)di_minor_private_get(minor);
4147c478bd9Sstevel@tonic-gate 	data = (data & ~MINOR_PTR) | (((long)ptr) & MINOR_PTR);
4157c478bd9Sstevel@tonic-gate 	di_minor_private_set(minor, (void *)data);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate  * In this comment typed properties are those of type DI_PROP_TYPE_UNDEF_IT,
4217c478bd9Sstevel@tonic-gate  * DI_PROP_TYPE_BOOLEAN, DI_PROP_TYPE_INT, DI_PROP_TYPE_INT64,
4227c478bd9Sstevel@tonic-gate  * DI_PROP_TYPE_BYTE, and DI_PROP_TYPE_STRING.
4237c478bd9Sstevel@tonic-gate  *
4247c478bd9Sstevel@tonic-gate  * The guessing algorithm is:
4257c478bd9Sstevel@tonic-gate  * 1. If the property is typed and the type is consistent with the value of
4267c478bd9Sstevel@tonic-gate  *    the property, then the property is of that type. If the type is not
4277c478bd9Sstevel@tonic-gate  *    consistent with value of the property, then the type is treated as
4287c478bd9Sstevel@tonic-gate  *    alien to prtconf.
4297c478bd9Sstevel@tonic-gate  * 2. If the property is of type DI_PROP_TYPE_UNKNOWN the following steps
4307c478bd9Sstevel@tonic-gate  *    are carried out.
4317c478bd9Sstevel@tonic-gate  *    a. If the value of the property is consistent with a string property,
4327c478bd9Sstevel@tonic-gate  *       the type of the property is DI_PROP_TYPE_STRING.
4337c478bd9Sstevel@tonic-gate  *    b. Otherwise, if the value of the property is consistent with an integer
4347c478bd9Sstevel@tonic-gate  *       property, the type of the property is DI_PROP_TYPE_INT.
4357c478bd9Sstevel@tonic-gate  *    c. Otherwise, the property type is treated as alien to prtconf.
4367c478bd9Sstevel@tonic-gate  * 3. If the property type is alien to prtconf, then the property value is
4377c478bd9Sstevel@tonic-gate  *    read by the appropriate routine for untyped properties and the following
4387c478bd9Sstevel@tonic-gate  *    steps are carried out.
4397c478bd9Sstevel@tonic-gate  *    a. If the length that the property routine returned is zero, the
4407c478bd9Sstevel@tonic-gate  *       property is of type DI_PROP_TYPE_BOOLEAN.
4417c478bd9Sstevel@tonic-gate  *    b. Otherwise, if the length that the property routine returned is
4427c478bd9Sstevel@tonic-gate  *       positive, then the property value is treated as raw data of type
4437c478bd9Sstevel@tonic-gate  *       DI_PROP_TYPE_UNKNOWN.
4447c478bd9Sstevel@tonic-gate  *    c. Otherwise, if the length that the property routine returned is
4457c478bd9Sstevel@tonic-gate  *       negative, then there is some internal inconsistency and this is
4467c478bd9Sstevel@tonic-gate  *       treated as an error and no type is determined.
4477c478bd9Sstevel@tonic-gate  */
4487c478bd9Sstevel@tonic-gate static int
4497c478bd9Sstevel@tonic-gate prop_type_guess(const dumpops_t *propops, void *prop, void **prop_data,
4507c478bd9Sstevel@tonic-gate     int *prop_type)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	int len, type;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	type = PROPTYPE(propops)(prop);
4557c478bd9Sstevel@tonic-gate 	switch (type) {
4567c478bd9Sstevel@tonic-gate 	case DI_PROP_TYPE_UNDEF_IT:
4577c478bd9Sstevel@tonic-gate 	case DI_PROP_TYPE_BOOLEAN:
4587c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
4597c478bd9Sstevel@tonic-gate 		*prop_type = type;
4607c478bd9Sstevel@tonic-gate 		return (0);
4617c478bd9Sstevel@tonic-gate 	case DI_PROP_TYPE_INT:
4627c478bd9Sstevel@tonic-gate 		len = PROPINTS(propops)(prop, (int **)prop_data);
4637c478bd9Sstevel@tonic-gate 		break;
4647c478bd9Sstevel@tonic-gate 	case DI_PROP_TYPE_INT64:
4657c478bd9Sstevel@tonic-gate 		len = PROPINT64(propops)(prop, (int64_t **)prop_data);
4667c478bd9Sstevel@tonic-gate 		break;
4677c478bd9Sstevel@tonic-gate 	case DI_PROP_TYPE_BYTE:
4687c478bd9Sstevel@tonic-gate 		len = PROPBYTES(propops)(prop, (uchar_t **)prop_data);
4697c478bd9Sstevel@tonic-gate 		break;
4707c478bd9Sstevel@tonic-gate 	case DI_PROP_TYPE_STRING:
4717c478bd9Sstevel@tonic-gate 		len = PROPSTRINGS(propops)(prop, (char **)prop_data);
4727c478bd9Sstevel@tonic-gate 		break;
4737c478bd9Sstevel@tonic-gate 	case DI_PROP_TYPE_UNKNOWN:
4747c478bd9Sstevel@tonic-gate 		len = PROPSTRINGS(propops)(prop, (char **)prop_data);
4757c478bd9Sstevel@tonic-gate 		if ((len > 0) && ((*(char **)prop_data)[0] != 0)) {
4767c478bd9Sstevel@tonic-gate 			*prop_type = DI_PROP_TYPE_STRING;
4777c478bd9Sstevel@tonic-gate 			return (len);
4787c478bd9Sstevel@tonic-gate 		}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 		len = PROPINTS(propops)(prop, (int **)prop_data);
4817c478bd9Sstevel@tonic-gate 		type = DI_PROP_TYPE_INT;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		break;
4847c478bd9Sstevel@tonic-gate 	default:
4857c478bd9Sstevel@tonic-gate 		len = -1;
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (len > 0) {
4897c478bd9Sstevel@tonic-gate 		*prop_type = type;
4907c478bd9Sstevel@tonic-gate 		return (len);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	len = PROPRAWDATA(propops)(prop, (uchar_t **)prop_data);
4947c478bd9Sstevel@tonic-gate 	if (len < 0) {
4957c478bd9Sstevel@tonic-gate 		return (-1);
4967c478bd9Sstevel@tonic-gate 	} else if (len == 0) {
4977c478bd9Sstevel@tonic-gate 		*prop_type = DI_PROP_TYPE_BOOLEAN;
4987c478bd9Sstevel@tonic-gate 		return (0);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	*prop_type = DI_PROP_TYPE_UNKNOWN;
5027c478bd9Sstevel@tonic-gate 	return (len);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate static void
5067c478bd9Sstevel@tonic-gate dump_prop_list_common(const dumpops_t *dumpops, int ilev, void *node)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate 	void *prop = DI_PROP_NIL, *prop_data;
5097c478bd9Sstevel@tonic-gate 	char *p;
5107c478bd9Sstevel@tonic-gate 	int i, prop_type, nitems;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	while ((prop = NEXTPROP(dumpops)(node, prop)) != DI_PROP_NIL) {
5137c478bd9Sstevel@tonic-gate 		nitems = prop_type_guess(dumpops, prop, &prop_data, &prop_type);
5147c478bd9Sstevel@tonic-gate 		if (nitems < 0)
5157c478bd9Sstevel@tonic-gate 			continue;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		indent_to_level(ilev);
5187c478bd9Sstevel@tonic-gate 		(void) printf("name='%s' type=", PROPNAME(dumpops)(prop));
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		switch (prop_type) {
5217c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_UNDEF_IT:
5227c478bd9Sstevel@tonic-gate 			(void) printf("undef");
5237c478bd9Sstevel@tonic-gate 			break;
5247c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_BOOLEAN:
5257c478bd9Sstevel@tonic-gate 			(void) printf("boolean");
5267c478bd9Sstevel@tonic-gate 			break;
5277c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_INT:
5287c478bd9Sstevel@tonic-gate 			(void) printf("int");
5297c478bd9Sstevel@tonic-gate 			break;
5307c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_INT64:
5317c478bd9Sstevel@tonic-gate 			(void) printf("int64");
5327c478bd9Sstevel@tonic-gate 			break;
5337c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_BYTE:
5347c478bd9Sstevel@tonic-gate 			(void) printf("byte");
5357c478bd9Sstevel@tonic-gate 			break;
5367c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_STRING:
5377c478bd9Sstevel@tonic-gate 			(void) printf("string");
5387c478bd9Sstevel@tonic-gate 			break;
5397c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_UNKNOWN:
5407c478bd9Sstevel@tonic-gate 			(void) printf("unknown");
5417c478bd9Sstevel@tonic-gate 			break;
5427c478bd9Sstevel@tonic-gate 		default:
5437c478bd9Sstevel@tonic-gate 			/* Should never be here */
5447c478bd9Sstevel@tonic-gate 			(void) printf("0x%x", prop_type);
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 		if (nitems != 0)
5487c478bd9Sstevel@tonic-gate 			(void) printf(" items=%i", nitems);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		/* print the major and minor numbers for a device property */
5517c478bd9Sstevel@tonic-gate 		if (PROPDEVT(dumpops) != NULL) {
5527c478bd9Sstevel@tonic-gate 			dev_t dev;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 			dev = PROPDEVT(dumpops)(prop);
5557c478bd9Sstevel@tonic-gate 			if (dev != DDI_DEV_T_NONE) {
5567c478bd9Sstevel@tonic-gate 				(void) printf(" dev=(%u,%u)",
5577c478bd9Sstevel@tonic-gate 				    (uint_t)major(dev), (uint_t)minor(dev));
5587c478bd9Sstevel@tonic-gate 			} else {
5597c478bd9Sstevel@tonic-gate 				(void) printf(" dev=none");
5607c478bd9Sstevel@tonic-gate 			}
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 		if (nitems == 0)
5667c478bd9Sstevel@tonic-gate 			continue;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 		indent_to_level(ilev);
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 		(void) printf("    value=");
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 		switch (prop_type) {
5737c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_INT:
5747c478bd9Sstevel@tonic-gate 			for (i = 0; i < nitems - 1; i++)
5757c478bd9Sstevel@tonic-gate 				(void) printf("%8.8x.", ((int *)prop_data)[i]);
5767c478bd9Sstevel@tonic-gate 			(void) printf("%8.8x", ((int *)prop_data)[i]);
5777c478bd9Sstevel@tonic-gate 			break;
5787c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_INT64:
5797c478bd9Sstevel@tonic-gate 			for (i = 0; i < nitems - 1; i++)
5807c478bd9Sstevel@tonic-gate 				(void) printf("%16.16llx.",
5817c478bd9Sstevel@tonic-gate 				    ((long long *)prop_data)[i]);
5827c478bd9Sstevel@tonic-gate 			(void) printf("%16.16llx", ((long long *)prop_data)[i]);
5837c478bd9Sstevel@tonic-gate 			break;
5847c478bd9Sstevel@tonic-gate 		case DI_PROP_TYPE_STRING:
5857c478bd9Sstevel@tonic-gate 			p = (char *)prop_data;
5867c478bd9Sstevel@tonic-gate 			for (i = 0; i < nitems - 1; i++) {
5877c478bd9Sstevel@tonic-gate 				(void) printf("'%s' + ", p);
5887c478bd9Sstevel@tonic-gate 				p += strlen(p) + 1;
5897c478bd9Sstevel@tonic-gate 			}
5907c478bd9Sstevel@tonic-gate 			(void) printf("'%s'", p);
5917c478bd9Sstevel@tonic-gate 			break;
5927c478bd9Sstevel@tonic-gate 		default:
5937c478bd9Sstevel@tonic-gate 			for (i = 0; i < nitems - 1; i++)
5947c478bd9Sstevel@tonic-gate 				(void) printf("%2.2x.",
5957c478bd9Sstevel@tonic-gate 				    ((uint8_t *)prop_data)[i]);
5967c478bd9Sstevel@tonic-gate 			(void) printf("%2.2x", ((uint8_t *)prop_data)[i]);
5977c478bd9Sstevel@tonic-gate 		}
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate /*
6047c478bd9Sstevel@tonic-gate  * walk_driver is a debugging facility.
6057c478bd9Sstevel@tonic-gate  */
6067c478bd9Sstevel@tonic-gate static void
6077c478bd9Sstevel@tonic-gate walk_driver(di_node_t root, di_devlink_handle_t devlink_hdl)
6087c478bd9Sstevel@tonic-gate {
6097c478bd9Sstevel@tonic-gate 	di_node_t node;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	node = di_drv_first_node(dbg.d_drivername, root);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	while (node != DI_NODE_NIL) {
6147c478bd9Sstevel@tonic-gate 		(void) dump_devs(node, devlink_hdl);
6157c478bd9Sstevel@tonic-gate 		node = di_drv_next_node(node);
6167c478bd9Sstevel@tonic-gate 	}
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate  * print out information about this node, returns appropriate code.
6217c478bd9Sstevel@tonic-gate  */
6227c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
6237c478bd9Sstevel@tonic-gate static int
6247c478bd9Sstevel@tonic-gate dump_devs(di_node_t node, void *arg)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate 	di_devlink_handle_t	devlink_hdl = (di_devlink_handle_t)arg;
6277c478bd9Sstevel@tonic-gate 	int			ilev = 0;	/* indentation level */
6287c478bd9Sstevel@tonic-gate 	char			*driver_name;
6297c478bd9Sstevel@tonic-gate 	di_node_t		root_node, tmp;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (dbg.d_debug) {
6327c478bd9Sstevel@tonic-gate 		char *path = di_devfs_path(node);
6337c478bd9Sstevel@tonic-gate 		dprintf("Dump node %s\n", path);
6347c478bd9Sstevel@tonic-gate 		di_devfs_path_free(path);
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if (dbg.d_bydriver) {
6387c478bd9Sstevel@tonic-gate 		ilev = 1;
6397c478bd9Sstevel@tonic-gate 	} else {
6407c478bd9Sstevel@tonic-gate 		/* figure out indentation level */
6417c478bd9Sstevel@tonic-gate 		tmp = node;
6427c478bd9Sstevel@tonic-gate 		while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
6437c478bd9Sstevel@tonic-gate 			ilev++;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 		if (opts.o_target && !opts.o_ancestors) {
6467c478bd9Sstevel@tonic-gate 			ilev -= opts.o_target - 1;
6477c478bd9Sstevel@tonic-gate 		}
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (opts.o_target && !node_display(node)) {
6517c478bd9Sstevel@tonic-gate 		/*
6527c478bd9Sstevel@tonic-gate 		 * if we're only displaying certain nodes and this one
6537c478bd9Sstevel@tonic-gate 		 * isn't flagged, skip it.
6547c478bd9Sstevel@tonic-gate 		 */
6557c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	indent_to_level(ilev);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	(void) printf("%s", di_node_name(node));
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	/*
6637c478bd9Sstevel@tonic-gate 	 * if this node does not have an instance number or is the
6647c478bd9Sstevel@tonic-gate 	 * root node (1229946), we don't print an instance number
6657c478bd9Sstevel@tonic-gate 	 */
6667c478bd9Sstevel@tonic-gate 	root_node = tmp = node;
6677c478bd9Sstevel@tonic-gate 	while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
6687c478bd9Sstevel@tonic-gate 		root_node = tmp;
6697c478bd9Sstevel@tonic-gate 	if ((di_instance(node) >= 0) && (node != root_node))
6707c478bd9Sstevel@tonic-gate 		(void) printf(", instance #%d", di_instance(node));
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (opts.o_drv_name) {
6737c478bd9Sstevel@tonic-gate 		driver_name = di_driver_name(node);
6747c478bd9Sstevel@tonic-gate 		if (driver_name != NULL)
6757c478bd9Sstevel@tonic-gate 			(void) printf(" (driver name: %s)", driver_name);
676*25e8c5aaSvikram 	} else if (di_retired(node)) {
677*25e8c5aaSvikram 		(void) printf(" (retired)");
6787c478bd9Sstevel@tonic-gate 	} else if (di_state(node) & DI_DRIVER_DETACHED)
6797c478bd9Sstevel@tonic-gate 		(void) printf(" (driver not attached)");
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	(void) printf("\n");
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if (opts.o_verbose)  {
6847c478bd9Sstevel@tonic-gate 		if (dump_prop_list(&sysprop_dumpops, "System", ilev + 1,
6857c478bd9Sstevel@tonic-gate 		    node)) {
6867c478bd9Sstevel@tonic-gate 			(void) dump_prop_list(&globprop_dumpops, NULL, ilev + 1,
6877c478bd9Sstevel@tonic-gate 			    node);
6887c478bd9Sstevel@tonic-gate 		} else {
6897c478bd9Sstevel@tonic-gate 			(void) dump_prop_list(&globprop_dumpops,
6907c478bd9Sstevel@tonic-gate 			    "System software", ilev + 1, node);
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 		(void) dump_prop_list(&drvprop_dumpops, "Driver", ilev + 1,
6937c478bd9Sstevel@tonic-gate 		    node);
6947c478bd9Sstevel@tonic-gate 		(void) dump_prop_list(&hwprop_dumpops, "Hardware", ilev + 1,
6957c478bd9Sstevel@tonic-gate 		    node);
6967c478bd9Sstevel@tonic-gate 		dump_priv_data(ilev + 1, node);
6977c478bd9Sstevel@tonic-gate 		dump_pathing_data(ilev + 1, node);
6987c478bd9Sstevel@tonic-gate 		dump_link_data(ilev + 1, node, devlink_hdl);
6997c478bd9Sstevel@tonic-gate 		dump_minor_data(ilev + 1, node, devlink_hdl);
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	if (opts.o_target)
7037c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if (!opts.o_pseudodevs && (strcmp(di_node_name(node), "pseudo") == 0))
7067c478bd9Sstevel@tonic-gate 		return (DI_WALK_PRUNECHILD);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate /*
7127c478bd9Sstevel@tonic-gate  * Returns 0 if nothing is printed, 1 otherwise
7137c478bd9Sstevel@tonic-gate  */
7147c478bd9Sstevel@tonic-gate static int
7157c478bd9Sstevel@tonic-gate dump_prop_list(const dumpops_t *dumpops, const char *name, int ilev,
7167c478bd9Sstevel@tonic-gate     di_node_t node)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	if (NEXTPROP(dumpops)(node, DI_PROP_NIL) == DI_PROP_NIL)
7197c478bd9Sstevel@tonic-gate 		return (0);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	if (name != NULL)  {
7227c478bd9Sstevel@tonic-gate 		indent_to_level(ilev);
7237c478bd9Sstevel@tonic-gate 		(void) printf("%s properties:\n", name);
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	dump_prop_list_common(dumpops, ilev + 1, node);
7277c478bd9Sstevel@tonic-gate 	return (1);
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate /* _error([no_perror, ] fmt [, arg ...]) */
7327c478bd9Sstevel@tonic-gate static int
7337c478bd9Sstevel@tonic-gate _error(const char *opt_noperror, ...)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	int saved_errno;
7367c478bd9Sstevel@tonic-gate 	va_list ap;
7377c478bd9Sstevel@tonic-gate 	int no_perror = 0;
7387c478bd9Sstevel@tonic-gate 	const char *fmt;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	saved_errno = errno;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", opts.o_progname);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	va_start(ap, opt_noperror);
7457c478bd9Sstevel@tonic-gate 	if (opt_noperror == NULL) {
7467c478bd9Sstevel@tonic-gate 		no_perror = 1;
7477c478bd9Sstevel@tonic-gate 		fmt = va_arg(ap, char *);
7487c478bd9Sstevel@tonic-gate 	} else
7497c478bd9Sstevel@tonic-gate 		fmt = opt_noperror;
7507c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
7517c478bd9Sstevel@tonic-gate 	va_end(ap);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if (no_perror)
7547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
7557c478bd9Sstevel@tonic-gate 	else {
7567c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, ": ");
7577c478bd9Sstevel@tonic-gate 		errno = saved_errno;
7587c478bd9Sstevel@tonic-gate 		perror("");
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	return (-1);
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate /*
7667c478bd9Sstevel@tonic-gate  * The rest of the routines handle printing the raw prom devinfo (-p option).
7677c478bd9Sstevel@tonic-gate  *
7687c478bd9Sstevel@tonic-gate  * 128 is the size of the largest (currently) property name
7697c478bd9Sstevel@tonic-gate  * 16k - MAXNAMESZ - sizeof (int) is the size of the largest
7707c478bd9Sstevel@tonic-gate  * (currently) property value that is allowed.
7717c478bd9Sstevel@tonic-gate  * the sizeof (uint_t) is from struct openpromio
7727c478bd9Sstevel@tonic-gate  */
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate #define	MAXNAMESZ	128
7757c478bd9Sstevel@tonic-gate #define	MAXVALSIZE	(16384 - MAXNAMESZ - sizeof (uint_t))
7767c478bd9Sstevel@tonic-gate #define	BUFSIZE		(MAXNAMESZ + MAXVALSIZE + sizeof (uint_t))
7777c478bd9Sstevel@tonic-gate typedef union {
7787c478bd9Sstevel@tonic-gate 	char buf[BUFSIZE];
7797c478bd9Sstevel@tonic-gate 	struct openpromio opp;
7807c478bd9Sstevel@tonic-gate } Oppbuf;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate static int prom_fd;
7837c478bd9Sstevel@tonic-gate static uchar_t *prom_snapshot;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate static int
7867c478bd9Sstevel@tonic-gate is_openprom(void)
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate 	Oppbuf	oppbuf;
7897c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
7907c478bd9Sstevel@tonic-gate 	unsigned int i;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
7937c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
7947c478bd9Sstevel@tonic-gate 		exit(_error("OPROMGETCONS"));
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	i = (unsigned int)((unsigned char)opp->oprom_array[0]);
7977c478bd9Sstevel@tonic-gate 	return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate int
8017c478bd9Sstevel@tonic-gate do_prominfo(void)
8027c478bd9Sstevel@tonic-gate {
8037c478bd9Sstevel@tonic-gate 	uint_t arg = opts.o_verbose;
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	if (promopen(O_RDONLY))  {
8067c478bd9Sstevel@tonic-gate 		exit(_error("openeepr device open failed"));
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	if (is_openprom() == 0)  {
8107c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "System architecture does not "
8117c478bd9Sstevel@tonic-gate 		    "support this option of this command.\n");
8127c478bd9Sstevel@tonic-gate 		return (1);
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	/* OPROMSNAPSHOT returns size in arg */
8167c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMSNAPSHOT, &arg) < 0)
8177c478bd9Sstevel@tonic-gate 		exit(_error("OPROMSNAPSHOT"));
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	if (arg == 0)
8207c478bd9Sstevel@tonic-gate 		return (1);
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	if ((prom_snapshot = malloc(arg)) == NULL)
8237c478bd9Sstevel@tonic-gate 		exit(_error("failed to allocate memory"));
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	/* copy out the snapshot for printing */
8267c478bd9Sstevel@tonic-gate 	/*LINTED*/
8277c478bd9Sstevel@tonic-gate 	*(uint_t *)prom_snapshot = arg;
8287c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMCOPYOUT, prom_snapshot) < 0)
8297c478bd9Sstevel@tonic-gate 		exit(_error("OPROMCOPYOUT"));
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	promclose();
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	/* print out information */
8347c478bd9Sstevel@tonic-gate 	walk(prom_snapshot, arg, 0);
8357c478bd9Sstevel@tonic-gate 	free(prom_snapshot);
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	return (0);
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate static void
8417c478bd9Sstevel@tonic-gate walk(uchar_t *buf, uint_t size, int level)
8427c478bd9Sstevel@tonic-gate {
8437c478bd9Sstevel@tonic-gate 	int error;
8447c478bd9Sstevel@tonic-gate 	nvlist_t *nvl, *cnvl;
8457c478bd9Sstevel@tonic-gate 	nvpair_t *child = NULL;
8467c478bd9Sstevel@tonic-gate 	uchar_t *cbuf = NULL;
8477c478bd9Sstevel@tonic-gate 	uint_t csize;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	/* Expand to an nvlist */
8507c478bd9Sstevel@tonic-gate 	if (nvlist_unpack((char *)buf, size, &nvl, 0))
8517c478bd9Sstevel@tonic-gate 		exit(_error("error processing snapshot"));
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/* print current node */
8547c478bd9Sstevel@tonic-gate 	dump_node(nvl, level);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	/* print children */
8577c478bd9Sstevel@tonic-gate 	error = nvlist_lookup_byte_array(nvl, "@child", &cbuf, &csize);
8587c478bd9Sstevel@tonic-gate 	if ((error == ENOENT) || (cbuf == NULL))
8597c478bd9Sstevel@tonic-gate 		return;		/* no child exists */
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	if (error || nvlist_unpack((char *)cbuf, csize, &cnvl, 0))
8627c478bd9Sstevel@tonic-gate 		exit(_error("error processing snapshot"));
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	while (child = nvlist_next_nvpair(cnvl, child)) {
8657c478bd9Sstevel@tonic-gate 		char *name = nvpair_name(child);
8667c478bd9Sstevel@tonic-gate 		data_type_t type = nvpair_type(child);
8677c478bd9Sstevel@tonic-gate 		uchar_t *nodebuf;
8687c478bd9Sstevel@tonic-gate 		uint_t nodesize;
8697c478bd9Sstevel@tonic-gate 		if (strcmp("node", name) != 0) {
8707c478bd9Sstevel@tonic-gate 			dprintf("unexpected nvpair name %s != name\n", name);
8717c478bd9Sstevel@tonic-gate 			continue;
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 		if (type != DATA_TYPE_BYTE_ARRAY) {
8747c478bd9Sstevel@tonic-gate 			dprintf("unexpected nvpair type %d, not byte array \n",
8757c478bd9Sstevel@tonic-gate 			    type);
8767c478bd9Sstevel@tonic-gate 			continue;
8777c478bd9Sstevel@tonic-gate 		}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		(void) nvpair_value_byte_array(child,
8807c478bd9Sstevel@tonic-gate 		    (uchar_t **)&nodebuf, &nodesize);
8817c478bd9Sstevel@tonic-gate 		walk(nodebuf, nodesize, level + 1);
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate /*
8887c478bd9Sstevel@tonic-gate  * Print all properties and values
8897c478bd9Sstevel@tonic-gate  */
8907c478bd9Sstevel@tonic-gate static void
8917c478bd9Sstevel@tonic-gate dump_node(nvlist_t *nvl, int level)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate 	int id = 0;
8947c478bd9Sstevel@tonic-gate 	char *name = NULL;
8957c478bd9Sstevel@tonic-gate 	nvpair_t *nvp = NULL;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	indent_to_level(level);
8987c478bd9Sstevel@tonic-gate 	(void) printf("Node");
8997c478bd9Sstevel@tonic-gate 	if (!opts.o_verbose) {
9007c478bd9Sstevel@tonic-gate 		if (nvlist_lookup_string(nvl, "name", &name))
9017c478bd9Sstevel@tonic-gate 			(void) printf("data not available");
9027c478bd9Sstevel@tonic-gate 		else
9037c478bd9Sstevel@tonic-gate 			(void) printf(" '%s'", name);
9047c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
9057c478bd9Sstevel@tonic-gate 		return;
9067c478bd9Sstevel@tonic-gate 	}
9077c478bd9Sstevel@tonic-gate 	(void) nvlist_lookup_int32(nvl, "@nodeid", &id);
9087c478bd9Sstevel@tonic-gate 	(void) printf(" %#08x\n", id);
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	while (nvp = nvlist_next_nvpair(nvl, nvp)) {
9117c478bd9Sstevel@tonic-gate 		name = nvpair_name(nvp);
9127c478bd9Sstevel@tonic-gate 		if (name[0] == '@')
9137c478bd9Sstevel@tonic-gate 			continue;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 		print_one(nvp, level + 1);
9167c478bd9Sstevel@tonic-gate 	}
9177c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate static const char *
9217c478bd9Sstevel@tonic-gate path_state_name(di_path_state_t st)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	switch (st) {
9247c478bd9Sstevel@tonic-gate 		case DI_PATH_STATE_ONLINE:
9257c478bd9Sstevel@tonic-gate 			return ("online");
9267c478bd9Sstevel@tonic-gate 		case DI_PATH_STATE_STANDBY:
9277c478bd9Sstevel@tonic-gate 			return ("standby");
9287c478bd9Sstevel@tonic-gate 		case DI_PATH_STATE_OFFLINE:
9297c478bd9Sstevel@tonic-gate 			return ("offline");
9307c478bd9Sstevel@tonic-gate 		case DI_PATH_STATE_FAULT:
9317c478bd9Sstevel@tonic-gate 			return ("faulted");
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate 	return ("unknown");
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate  * Print all phci's each client is connected to.
9387c478bd9Sstevel@tonic-gate  */
9397c478bd9Sstevel@tonic-gate static void
9407c478bd9Sstevel@tonic-gate dump_pathing_data(int ilev, di_node_t node)
9417c478bd9Sstevel@tonic-gate {
9427c478bd9Sstevel@tonic-gate 	di_path_t pi = DI_PATH_NIL;
9437c478bd9Sstevel@tonic-gate 	int firsttime = 1;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	if (node == DI_PATH_NIL)
9467c478bd9Sstevel@tonic-gate 		return;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	while ((pi = di_path_next_phci(node, pi)) != DI_PATH_NIL) {
9497c478bd9Sstevel@tonic-gate 		di_node_t phci_node = di_path_phci_node(pi);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		if (firsttime) {
9527c478bd9Sstevel@tonic-gate 			indent_to_level(ilev);
9537c478bd9Sstevel@tonic-gate 			firsttime = 0;
9547c478bd9Sstevel@tonic-gate 			ilev++;
9557c478bd9Sstevel@tonic-gate 			(void) printf("Paths from multipath bus adapters:\n");
9567c478bd9Sstevel@tonic-gate 		}
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 		indent_to_level(ilev);
9597c478bd9Sstevel@tonic-gate 		(void) printf("%s#%d (%s)\n", di_driver_name(phci_node),
9607c478bd9Sstevel@tonic-gate 		    di_instance(phci_node), path_state_name(di_path_state(pi)));
9617c478bd9Sstevel@tonic-gate 		dump_prop_list_common(&pathprop_dumpops, ilev + 1, pi);
9627c478bd9Sstevel@tonic-gate 	}
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate static int
9667c478bd9Sstevel@tonic-gate dump_minor_data_links(di_devlink_t devlink, void *arg)
9677c478bd9Sstevel@tonic-gate {
9687c478bd9Sstevel@tonic-gate 	int ilev = (intptr_t)arg;
9697c478bd9Sstevel@tonic-gate 	indent_to_level(ilev);
9707c478bd9Sstevel@tonic-gate 	(void) printf("dev_link=%s\n", di_devlink_path(devlink));
9717c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate static void
9757c478bd9Sstevel@tonic-gate dump_minor_data_paths(int ilev, di_minor_t minor,
9767c478bd9Sstevel@tonic-gate     di_devlink_handle_t devlink_hdl)
9777c478bd9Sstevel@tonic-gate {
9787c478bd9Sstevel@tonic-gate 	char	*path, *type;
9797c478bd9Sstevel@tonic-gate 	int	spec_type;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	/* get the path to the device and the minor node name */
9827c478bd9Sstevel@tonic-gate 	if ((path = di_devfs_minor_path(minor)) == NULL)
9837c478bd9Sstevel@tonic-gate 		exit(_error("failed to allocate memory"));
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	/* display the path to this minor node */
9867c478bd9Sstevel@tonic-gate 	indent_to_level(ilev);
9877c478bd9Sstevel@tonic-gate 	(void) printf("dev_path=%s\n", path);
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	if (devlink_hdl != NULL) {
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 		/* get the device minor node information */
9927c478bd9Sstevel@tonic-gate 		spec_type = di_minor_spectype(minor);
9937c478bd9Sstevel@tonic-gate 		switch (di_minor_type(minor)) {
9947c478bd9Sstevel@tonic-gate 			case DDM_MINOR:
9957c478bd9Sstevel@tonic-gate 				type = "minor";
9967c478bd9Sstevel@tonic-gate 				break;
9977c478bd9Sstevel@tonic-gate 			case DDM_ALIAS:
9987c478bd9Sstevel@tonic-gate 				type = "alias";
9997c478bd9Sstevel@tonic-gate 				break;
10007c478bd9Sstevel@tonic-gate 			case DDM_DEFAULT:
10017c478bd9Sstevel@tonic-gate 				type = "default";
10027c478bd9Sstevel@tonic-gate 				break;
10037c478bd9Sstevel@tonic-gate 			case DDM_INTERNAL_PATH:
10047c478bd9Sstevel@tonic-gate 				type = "internal";
10057c478bd9Sstevel@tonic-gate 				break;
10067c478bd9Sstevel@tonic-gate 			default:
10077c478bd9Sstevel@tonic-gate 				type = "unknown";
10087c478bd9Sstevel@tonic-gate 				break;
10097c478bd9Sstevel@tonic-gate 		}
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 		/* display the device minor node information */
10127c478bd9Sstevel@tonic-gate 		indent_to_level(ilev + 1);
10137c478bd9Sstevel@tonic-gate 		(void) printf("spectype=%s type=%s\n",
10147c478bd9Sstevel@tonic-gate 		    (spec_type == S_IFBLK) ? "blk" : "chr", type);
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 		/* display all the devlinks for this device minor node */
10177c478bd9Sstevel@tonic-gate 		(void) di_devlink_walk(devlink_hdl, NULL, path,
10187c478bd9Sstevel@tonic-gate 		    0, (void *)(intptr_t)(ilev + 1), dump_minor_data_links);
10197c478bd9Sstevel@tonic-gate 	}
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate static void
10257c478bd9Sstevel@tonic-gate create_minor_list(di_node_t node)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate 	di_minor_t	minor, minor_head, minor_tail, minor_prev, minor_walk;
10287c478bd9Sstevel@tonic-gate 	int		major;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	/* if there are no minor nodes, bail */
10317c478bd9Sstevel@tonic-gate 	if (di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL)
10327c478bd9Sstevel@tonic-gate 		return;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	/*
10357c478bd9Sstevel@tonic-gate 	 * here we want to create lists of minor nodes with the same
10367c478bd9Sstevel@tonic-gate 	 * dev_t.  to do this we first sort all the minor nodes by devt.
10377c478bd9Sstevel@tonic-gate 	 *
10387c478bd9Sstevel@tonic-gate 	 * the algorithm used here is a bubble sort, so performance sucks.
10397c478bd9Sstevel@tonic-gate 	 * but it's probably ok here because most device instances don't
10407c478bd9Sstevel@tonic-gate 	 * have that many minor nodes.  also we're doing this as we're
10417c478bd9Sstevel@tonic-gate 	 * displaying each node so it doesn't look like we're pausing
10427c478bd9Sstevel@tonic-gate 	 * output for a long time.
10437c478bd9Sstevel@tonic-gate 	 */
10447c478bd9Sstevel@tonic-gate 	major = di_driver_major(node);
10457c478bd9Sstevel@tonic-gate 	minor_head = minor_tail = minor = DI_MINOR_NIL;
10467c478bd9Sstevel@tonic-gate 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
10477c478bd9Sstevel@tonic-gate 		dev_t	dev = di_minor_devt(minor);
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		/* skip /pseudo/clone@0 minor nodes */
10507c478bd9Sstevel@tonic-gate 		if (major != major(dev))
10517c478bd9Sstevel@tonic-gate 			continue;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 		minor_ptr_set(minor, DI_MINOR_NIL);
10547c478bd9Sstevel@tonic-gate 		if (minor_head == DI_MINOR_NIL) {
10557c478bd9Sstevel@tonic-gate 			/* this is the first minor node we're looking at */
10567c478bd9Sstevel@tonic-gate 			minor_head = minor_tail = minor;
10577c478bd9Sstevel@tonic-gate 			continue;
10587c478bd9Sstevel@tonic-gate 		}
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 		/*
10617c478bd9Sstevel@tonic-gate 		 * if the new dev is less than the old dev, update minor_head
10627c478bd9Sstevel@tonic-gate 		 * so it points to the beginning of the list.  ie it points
10637c478bd9Sstevel@tonic-gate 		 * to the node with the lowest dev value
10647c478bd9Sstevel@tonic-gate 		 */
10657c478bd9Sstevel@tonic-gate 		if (dev <= di_minor_devt(minor_head)) {
10667c478bd9Sstevel@tonic-gate 			minor_ptr_set(minor, minor_head);
10677c478bd9Sstevel@tonic-gate 			minor_head = minor;
10687c478bd9Sstevel@tonic-gate 			continue;
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 		minor_prev = minor_head;
10727c478bd9Sstevel@tonic-gate 		minor_walk = minor_ptr(minor_head);
10737c478bd9Sstevel@tonic-gate 		while ((minor_walk != DI_MINOR_NIL) &&
10747c478bd9Sstevel@tonic-gate 		    (dev > di_minor_devt(minor_walk))) {
10757c478bd9Sstevel@tonic-gate 			minor_prev = minor_walk;
10767c478bd9Sstevel@tonic-gate 			minor_walk = minor_ptr(minor_walk);
10777c478bd9Sstevel@tonic-gate 		}
10787c478bd9Sstevel@tonic-gate 		minor_ptr_set(minor, minor_walk);
10797c478bd9Sstevel@tonic-gate 		minor_ptr_set(minor_prev, minor);
10807c478bd9Sstevel@tonic-gate 		if (minor_walk == NULL)
10817c478bd9Sstevel@tonic-gate 			minor_tail = minor;
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	/* check if there were any non /pseudo/clone@0 nodes.  if not, bail */
10857c478bd9Sstevel@tonic-gate 	if (minor_head == DI_MINOR_NIL)
10867c478bd9Sstevel@tonic-gate 		return;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	/*
10897c478bd9Sstevel@tonic-gate 	 * now that we have a list of minor nodes sorted by devt
10907c478bd9Sstevel@tonic-gate 	 * we walk through the list and break apart the entire list
10917c478bd9Sstevel@tonic-gate 	 * to create circular lists of minor nodes with matching devts.
10927c478bd9Sstevel@tonic-gate 	 */
10937c478bd9Sstevel@tonic-gate 	minor_prev = minor_head;
10947c478bd9Sstevel@tonic-gate 	minor_walk = minor_ptr(minor_head);
10957c478bd9Sstevel@tonic-gate 	while (minor_walk != DI_MINOR_NIL) {
10967c478bd9Sstevel@tonic-gate 		if (di_minor_devt(minor_prev) != di_minor_devt(minor_walk)) {
10977c478bd9Sstevel@tonic-gate 			minor_ptr_set(minor_prev, minor_head);
10987c478bd9Sstevel@tonic-gate 			minor_head = minor_walk;
10997c478bd9Sstevel@tonic-gate 		}
11007c478bd9Sstevel@tonic-gate 		minor_prev = minor_walk;
11017c478bd9Sstevel@tonic-gate 		minor_walk = minor_ptr(minor_walk);
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 	minor_ptr_set(minor_tail, minor_head);
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate static void
11077c478bd9Sstevel@tonic-gate link_lnode_disp(di_link_t link, uint_t endpoint, int ilev,
11087c478bd9Sstevel@tonic-gate     di_devlink_handle_t devlink_hdl)
11097c478bd9Sstevel@tonic-gate {
11107c478bd9Sstevel@tonic-gate 	di_lnode_t	lnode;
11117c478bd9Sstevel@tonic-gate 	char		*name, *path;
11127c478bd9Sstevel@tonic-gate 	int		displayed_path, spec_type;
11137c478bd9Sstevel@tonic-gate 	di_node_t	node = DI_NODE_NIL;
11147c478bd9Sstevel@tonic-gate 	dev_t		devt = DDI_DEV_T_NONE;
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	lnode = di_link_to_lnode(link, endpoint);
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	indent_to_level(ilev);
11197c478bd9Sstevel@tonic-gate 	name = di_lnode_name(lnode);
11207c478bd9Sstevel@tonic-gate 	spec_type = di_link_spectype(link);
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	(void) printf("mod=%s", name);
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	/*
11257c478bd9Sstevel@tonic-gate 	 * if we're displaying the source of a link, we should display
11267c478bd9Sstevel@tonic-gate 	 * the target access mode.  (either block or char.)
11277c478bd9Sstevel@tonic-gate 	 */
11287c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC)
11297c478bd9Sstevel@tonic-gate 		(void) printf(" accesstype=%s",
11307c478bd9Sstevel@tonic-gate 		    (spec_type == S_IFBLK) ? "blk" : "chr");
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	/*
11337c478bd9Sstevel@tonic-gate 	 * check if the lnode is bound to a specific device
11347c478bd9Sstevel@tonic-gate 	 * minor node (i.e.  if it's bound to a dev_t) and
11357c478bd9Sstevel@tonic-gate 	 * if so display the dev_t value and any possible
11367c478bd9Sstevel@tonic-gate 	 * minor node pathing information.
11377c478bd9Sstevel@tonic-gate 	 */
11387c478bd9Sstevel@tonic-gate 	displayed_path = 0;
11397c478bd9Sstevel@tonic-gate 	if (di_lnode_devt(lnode, &devt) == 0) {
11407c478bd9Sstevel@tonic-gate 		di_minor_t	minor = DI_MINOR_NIL;
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 		(void) printf(" dev=(%u,%u)\n",
11437c478bd9Sstevel@tonic-gate 		    (uint_t)major(devt), (uint_t)minor(devt));
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 		/* display paths to the src devt minor node */
11467c478bd9Sstevel@tonic-gate 		while (minor = di_minor_next(node, minor)) {
11477c478bd9Sstevel@tonic-gate 			if (devt != di_minor_devt(minor))
11487c478bd9Sstevel@tonic-gate 				continue;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 			if ((endpoint == DI_LINK_TGT) &&
11517c478bd9Sstevel@tonic-gate 			    (spec_type != di_minor_spectype(minor)))
11527c478bd9Sstevel@tonic-gate 				continue;
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 			dump_minor_data_paths(ilev + 1, minor, devlink_hdl);
11557c478bd9Sstevel@tonic-gate 			displayed_path = 1;
11567c478bd9Sstevel@tonic-gate 		}
11577c478bd9Sstevel@tonic-gate 	} else {
11587c478bd9Sstevel@tonic-gate 		(void) printf("\n");
11597c478bd9Sstevel@tonic-gate 	}
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	if (displayed_path)
11627c478bd9Sstevel@tonic-gate 		return;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	/*
11657c478bd9Sstevel@tonic-gate 	 * This device lnode is not did not have any minor node
11667c478bd9Sstevel@tonic-gate 	 * pathing information so display the path to device node.
11677c478bd9Sstevel@tonic-gate 	 */
11687c478bd9Sstevel@tonic-gate 	node = di_lnode_devinfo(lnode);
11697c478bd9Sstevel@tonic-gate 	if ((path = di_devfs_path(node)) == NULL)
11707c478bd9Sstevel@tonic-gate 		exit(_error("failed to allocate memory"));
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	indent_to_level(ilev + 1);
11737c478bd9Sstevel@tonic-gate 	(void) printf("dev_path=%s\n", path);
11747c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate static void
11787c478bd9Sstevel@tonic-gate dump_minor_link_data(int ilev, di_node_t node, dev_t devt,
11797c478bd9Sstevel@tonic-gate     di_devlink_handle_t devlink_hdl)
11807c478bd9Sstevel@tonic-gate {
11817c478bd9Sstevel@tonic-gate 	int		first = 1;
11827c478bd9Sstevel@tonic-gate 	di_link_t	link;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	link = DI_LINK_NIL;
11857c478bd9Sstevel@tonic-gate 	while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) {
11867c478bd9Sstevel@tonic-gate 		di_lnode_t	tgt_lnode;
11877c478bd9Sstevel@tonic-gate 		dev_t		tgt_devt = DDI_DEV_T_NONE;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 		tgt_lnode = di_link_to_lnode(link, DI_LINK_TGT);
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 		if (di_lnode_devt(tgt_lnode, &tgt_devt) != 0)
11927c478bd9Sstevel@tonic-gate 			continue;
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 		if (devt != tgt_devt)
11957c478bd9Sstevel@tonic-gate 			continue;
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 		if (first) {
11987c478bd9Sstevel@tonic-gate 			first = 0;
11997c478bd9Sstevel@tonic-gate 			indent_to_level(ilev);
12007c478bd9Sstevel@tonic-gate 			(void) printf("Device Minor Layered Under:\n");
12017c478bd9Sstevel@tonic-gate 		}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 		/* displayed this lnode */
12047c478bd9Sstevel@tonic-gate 		lnode_displayed_set(tgt_lnode);
12057c478bd9Sstevel@tonic-gate 		link_lnode_disp(link, DI_LINK_SRC, ilev + 1, devlink_hdl);
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	link = DI_LINK_NIL;
12097c478bd9Sstevel@tonic-gate 	while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) {
12107c478bd9Sstevel@tonic-gate 		di_lnode_t	src_lnode;
12117c478bd9Sstevel@tonic-gate 		dev_t		src_devt = DDI_DEV_T_NONE;
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 		src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 		if (di_lnode_devt(src_lnode, &src_devt) != 0)
12167c478bd9Sstevel@tonic-gate 			continue;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 		if (devt != src_devt)
12197c478bd9Sstevel@tonic-gate 			continue;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 		if (first) {
12227c478bd9Sstevel@tonic-gate 			first = 0;
12237c478bd9Sstevel@tonic-gate 			indent_to_level(ilev);
12247c478bd9Sstevel@tonic-gate 			(void) printf("Device Minor Layered Over:\n");
12257c478bd9Sstevel@tonic-gate 		}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 		/* displayed this lnode */
12287c478bd9Sstevel@tonic-gate 		lnode_displayed_set(src_lnode);
12297c478bd9Sstevel@tonic-gate 		link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate static void
12347c478bd9Sstevel@tonic-gate dump_minor_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
12357c478bd9Sstevel@tonic-gate {
12367c478bd9Sstevel@tonic-gate 	di_minor_t	minor, minor_next;
12377c478bd9Sstevel@tonic-gate 	di_lnode_t	lnode;
12387c478bd9Sstevel@tonic-gate 	di_link_t	link;
12397c478bd9Sstevel@tonic-gate 	int		major, firstminor = 1;
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/*
12427c478bd9Sstevel@tonic-gate 	 * first go through and mark all lnodes and minor nodes for this
12437c478bd9Sstevel@tonic-gate 	 * node as undisplayed
12447c478bd9Sstevel@tonic-gate 	 */
12457c478bd9Sstevel@tonic-gate 	lnode = DI_LNODE_NIL;
12467c478bd9Sstevel@tonic-gate 	while (lnode = di_lnode_next(node, lnode))
12477c478bd9Sstevel@tonic-gate 		lnode_displayed_clear(lnode);
12487c478bd9Sstevel@tonic-gate 	minor = DI_MINOR_NIL;
12497c478bd9Sstevel@tonic-gate 	while (minor = di_minor_next(node, minor)) {
12507c478bd9Sstevel@tonic-gate 		minor_displayed_clear(minor);
12517c478bd9Sstevel@tonic-gate 	}
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	/*
12547c478bd9Sstevel@tonic-gate 	 * when we display the minor nodes we want to coalesce nodes
12557c478bd9Sstevel@tonic-gate 	 * that have the same dev_t.  we do this by creating circular
12567c478bd9Sstevel@tonic-gate 	 * lists of minor nodes with the same devt.
12577c478bd9Sstevel@tonic-gate 	 */
12587c478bd9Sstevel@tonic-gate 	create_minor_list(node);
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	/* now we display the driver defined minor nodes */
12617c478bd9Sstevel@tonic-gate 	major = di_driver_major(node);
12627c478bd9Sstevel@tonic-gate 	minor = DI_MINOR_NIL;
12637c478bd9Sstevel@tonic-gate 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
12647c478bd9Sstevel@tonic-gate 		dev_t	devt;
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		/*
12677c478bd9Sstevel@tonic-gate 		 * skip /pseudo/clone@0 minor nodes.
12687c478bd9Sstevel@tonic-gate 		 * these are only created for DLPIv2 network devices.
12697c478bd9Sstevel@tonic-gate 		 * since these minor nodes are associated with a driver
12707c478bd9Sstevel@tonic-gate 		 * and are only bound to a device instance after they
12717c478bd9Sstevel@tonic-gate 		 * are opened and attached we don't print them out
12727c478bd9Sstevel@tonic-gate 		 * here.
12737c478bd9Sstevel@tonic-gate 		 */
12747c478bd9Sstevel@tonic-gate 		devt = di_minor_devt(minor);
12757c478bd9Sstevel@tonic-gate 		if (major != major(devt))
12767c478bd9Sstevel@tonic-gate 			continue;
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 		/* skip nodes that may have already been displayed */
12797c478bd9Sstevel@tonic-gate 		if (minor_displayed(minor))
12807c478bd9Sstevel@tonic-gate 			continue;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 		if (firstminor) {
12837c478bd9Sstevel@tonic-gate 			firstminor = 0;
12847c478bd9Sstevel@tonic-gate 			indent_to_level(ilev++);
12857c478bd9Sstevel@tonic-gate 			(void) printf("Device Minor Nodes:\n");
12867c478bd9Sstevel@tonic-gate 		}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 		/* display the device minor node information */
12897c478bd9Sstevel@tonic-gate 		indent_to_level(ilev);
12907c478bd9Sstevel@tonic-gate 		(void) printf("dev=(%u,%u)\n",
12917c478bd9Sstevel@tonic-gate 		    (uint_t)major(devt), (uint_t)minor(devt));
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 		minor_next = minor;
12947c478bd9Sstevel@tonic-gate 		do {
12957c478bd9Sstevel@tonic-gate 			/* display device minor node path info */
12967c478bd9Sstevel@tonic-gate 			minor_displayed_set(minor_next);
12977c478bd9Sstevel@tonic-gate 			dump_minor_data_paths(ilev + 1, minor_next,
12987c478bd9Sstevel@tonic-gate 			    devlink_hdl);
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 			/* get a pointer to the next node */
13017c478bd9Sstevel@tonic-gate 			minor_next = minor_ptr(minor_next);
13027c478bd9Sstevel@tonic-gate 		} while (minor_next != minor);
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 		/* display who has this device minor node open */
13057c478bd9Sstevel@tonic-gate 		dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
13067c478bd9Sstevel@tonic-gate 	}
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	/*
13097c478bd9Sstevel@tonic-gate 	 * now go through all the target lnodes for this node and
13107c478bd9Sstevel@tonic-gate 	 * if they haven't yet been displayed, display them now.
13117c478bd9Sstevel@tonic-gate 	 *
13127c478bd9Sstevel@tonic-gate 	 * this happens in the case of clone opens when an "official"
13137c478bd9Sstevel@tonic-gate 	 * minor node does not exist for the opened devt
13147c478bd9Sstevel@tonic-gate 	 */
13157c478bd9Sstevel@tonic-gate 	link = DI_LINK_NIL;
13167c478bd9Sstevel@tonic-gate 	while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) {
13177c478bd9Sstevel@tonic-gate 		dev_t		devt;
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 		lnode = di_link_to_lnode(link, DI_LINK_TGT);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 		/* if we've already displayed this target lnode, skip it */
13227c478bd9Sstevel@tonic-gate 		if (lnode_displayed(lnode))
13237c478bd9Sstevel@tonic-gate 			continue;
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 		if (firstminor) {
13267c478bd9Sstevel@tonic-gate 			firstminor = 0;
13277c478bd9Sstevel@tonic-gate 			indent_to_level(ilev++);
13287c478bd9Sstevel@tonic-gate 			(void) printf("Device Minor Nodes:\n");
13297c478bd9Sstevel@tonic-gate 		}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 		/* display the device minor node information */
13327c478bd9Sstevel@tonic-gate 		indent_to_level(ilev);
13337c478bd9Sstevel@tonic-gate 		(void) di_lnode_devt(lnode, &devt);
13347c478bd9Sstevel@tonic-gate 		(void) printf("dev=(%u,%u)\n",
13357c478bd9Sstevel@tonic-gate 		    (uint_t)major(devt), (uint_t)minor(devt));
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 		indent_to_level(ilev + 1);
13387c478bd9Sstevel@tonic-gate 		(void) printf("dev_path=<clone>\n");
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 		/* display who has this cloned device minor node open */
13417c478bd9Sstevel@tonic-gate 		dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 		/* mark node as displayed */
13447c478bd9Sstevel@tonic-gate 		lnode_displayed_set(lnode);
13457c478bd9Sstevel@tonic-gate 	}
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate static void
13497c478bd9Sstevel@tonic-gate dump_link_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
13507c478bd9Sstevel@tonic-gate {
13517c478bd9Sstevel@tonic-gate 	int		first = 1;
13527c478bd9Sstevel@tonic-gate 	di_link_t	link;
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	link = DI_LINK_NIL;
13557c478bd9Sstevel@tonic-gate 	while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) {
13567c478bd9Sstevel@tonic-gate 		di_lnode_t	src_lnode;
13577c478bd9Sstevel@tonic-gate 		dev_t		src_devt = DDI_DEV_T_NONE;
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 		src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 		/*
13627c478bd9Sstevel@tonic-gate 		 * here we only want to print out layering information
13637c478bd9Sstevel@tonic-gate 		 * if we are the source and our source lnode is not
13647c478bd9Sstevel@tonic-gate 		 * associated with any particular dev_t.  (which means
13657c478bd9Sstevel@tonic-gate 		 * we won't display this link while dumping minor node
13667c478bd9Sstevel@tonic-gate 		 * info.)
13677c478bd9Sstevel@tonic-gate 		 */
13687c478bd9Sstevel@tonic-gate 		if (di_lnode_devt(src_lnode, &src_devt) != -1)
13697c478bd9Sstevel@tonic-gate 			continue;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 		if (first) {
13727c478bd9Sstevel@tonic-gate 			first = 0;
13737c478bd9Sstevel@tonic-gate 			indent_to_level(ilev);
13747c478bd9Sstevel@tonic-gate 			(void) printf("Device Layered Over:\n");
13757c478bd9Sstevel@tonic-gate 		}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 		/* displayed this lnode */
13787c478bd9Sstevel@tonic-gate 		link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate /*
13837c478bd9Sstevel@tonic-gate  * certain 'known' property names may contain 'composite' strings.
13847c478bd9Sstevel@tonic-gate  * Handle them here, and print them as 'string1' + 'string2' ...
13857c478bd9Sstevel@tonic-gate  */
13867c478bd9Sstevel@tonic-gate static int
13877c478bd9Sstevel@tonic-gate print_composite_string(const char *var, char *value, int size)
13887c478bd9Sstevel@tonic-gate {
13897c478bd9Sstevel@tonic-gate 	char *p, *q;
13907c478bd9Sstevel@tonic-gate 	char *firstp;
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	if ((strcmp(var, "version") != 0) &&
13937c478bd9Sstevel@tonic-gate 	    (strcmp(var, "compatible") != 0))
13947c478bd9Sstevel@tonic-gate 		return (0);	/* Not a known composite string */
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	/*
13977c478bd9Sstevel@tonic-gate 	 * Verify that each string in the composite string is non-NULL,
13987c478bd9Sstevel@tonic-gate 	 * is within the bounds of the property length, and contains
13997c478bd9Sstevel@tonic-gate 	 * printable characters or white space. Otherwise let the
14007c478bd9Sstevel@tonic-gate 	 * caller deal with it.
14017c478bd9Sstevel@tonic-gate 	 */
14027c478bd9Sstevel@tonic-gate 	for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
14037c478bd9Sstevel@tonic-gate 		if (strlen(p) == 0)
14047c478bd9Sstevel@tonic-gate 			return (0);		/* NULL string */
14057c478bd9Sstevel@tonic-gate 		for (q = p; *q; q++) {
14067c478bd9Sstevel@tonic-gate 			if (!(isascii(*q) && (isprint(*q) || isspace(*q))))
14077c478bd9Sstevel@tonic-gate 				return (0);	/* Not printable or space */
14087c478bd9Sstevel@tonic-gate 		}
14097c478bd9Sstevel@tonic-gate 		if (q > (firstp + size))
14107c478bd9Sstevel@tonic-gate 			return (0);		/* Out of bounds */
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
14147c478bd9Sstevel@tonic-gate 		if (p == firstp)
14157c478bd9Sstevel@tonic-gate 			(void) printf("'%s'", p);
14167c478bd9Sstevel@tonic-gate 		else
14177c478bd9Sstevel@tonic-gate 			(void) printf(" + '%s'", p);
14187c478bd9Sstevel@tonic-gate 	}
14197c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
14207c478bd9Sstevel@tonic-gate 	return (1);
14217c478bd9Sstevel@tonic-gate }
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate /*
14247c478bd9Sstevel@tonic-gate  * Print one property and its value. Handle the verbose case.
14257c478bd9Sstevel@tonic-gate  */
14267c478bd9Sstevel@tonic-gate static void
14277c478bd9Sstevel@tonic-gate print_one(nvpair_t *nvp, int level)
14287c478bd9Sstevel@tonic-gate {
14297c478bd9Sstevel@tonic-gate 	int i;
14307c478bd9Sstevel@tonic-gate 	int endswap = 0;
14317c478bd9Sstevel@tonic-gate 	uint_t valsize;
14327c478bd9Sstevel@tonic-gate 	char *value;
14337c478bd9Sstevel@tonic-gate 	char *var = nvpair_name(nvp);
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	indent_to_level(level);
14367c478bd9Sstevel@tonic-gate 	(void) printf("%s: ", var);
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 	switch (nvpair_type(nvp)) {
14397c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
14407c478bd9Sstevel@tonic-gate 		(void) printf(" \n");
14417c478bd9Sstevel@tonic-gate 		return;
14427c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
14437c478bd9Sstevel@tonic-gate 		if (nvpair_value_byte_array(nvp, (uchar_t **)&value,
14447c478bd9Sstevel@tonic-gate 		    &valsize)) {
14457c478bd9Sstevel@tonic-gate 			(void) printf("data not available.\n");
14467c478bd9Sstevel@tonic-gate 			return;
14477c478bd9Sstevel@tonic-gate 		}
14487c478bd9Sstevel@tonic-gate 		valsize--;	/* take out null added by driver */
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 		/*
14517c478bd9Sstevel@tonic-gate 		 * Do not print valsize > MAXVALSIZE, to be compatible
14527c478bd9Sstevel@tonic-gate 		 * with old behavior. E.g. intel's eisa-nvram property
14537c478bd9Sstevel@tonic-gate 		 * has a size of 65 K.
14547c478bd9Sstevel@tonic-gate 		 */
14557c478bd9Sstevel@tonic-gate 		if (valsize > MAXVALSIZE) {
14567c478bd9Sstevel@tonic-gate 			(void) printf(" \n");
14577c478bd9Sstevel@tonic-gate 			return;
14587c478bd9Sstevel@tonic-gate 		}
14597c478bd9Sstevel@tonic-gate 		break;
14607c478bd9Sstevel@tonic-gate 	default:
14617c478bd9Sstevel@tonic-gate 		(void) printf("data type unexpected.\n");
14627c478bd9Sstevel@tonic-gate 		return;
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	/*
14667c478bd9Sstevel@tonic-gate 	 * Handle printing verbosely
14677c478bd9Sstevel@tonic-gate 	 */
14687c478bd9Sstevel@tonic-gate 	if (print_composite_string(var, value, valsize)) {
14697c478bd9Sstevel@tonic-gate 		return;
14707c478bd9Sstevel@tonic-gate 	}
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	if (!unprintable(value, valsize)) {
14737c478bd9Sstevel@tonic-gate 		(void) printf(" '%s'\n", value);
14747c478bd9Sstevel@tonic-gate 		return;
14757c478bd9Sstevel@tonic-gate 	}
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	(void) printf(" ");
14787c478bd9Sstevel@tonic-gate #ifdef	__x86
14797c478bd9Sstevel@tonic-gate 	/*
14807c478bd9Sstevel@tonic-gate 	 * Due to backwards compatibility constraints x86 int
14817c478bd9Sstevel@tonic-gate 	 * properties are not in big-endian (ieee 1275) byte order.
14827c478bd9Sstevel@tonic-gate 	 * If we have a property that is a multiple of 4 bytes,
14837c478bd9Sstevel@tonic-gate 	 * let's assume it is an array of ints and print the bytes
14847c478bd9Sstevel@tonic-gate 	 * in little endian order to make things look nicer for
14857c478bd9Sstevel@tonic-gate 	 * the user.
14867c478bd9Sstevel@tonic-gate 	 */
14877c478bd9Sstevel@tonic-gate 	endswap = (valsize % 4) == 0;
14887c478bd9Sstevel@tonic-gate #endif	/* __x86 */
14897c478bd9Sstevel@tonic-gate 	for (i = 0; i < valsize; i++) {
14907c478bd9Sstevel@tonic-gate 		int out;
14917c478bd9Sstevel@tonic-gate 		if (i && (i % 4 == 0))
14927c478bd9Sstevel@tonic-gate 			(void) putchar('.');
14937c478bd9Sstevel@tonic-gate 		if (endswap)
14947c478bd9Sstevel@tonic-gate 			out = value[i + (3 - 2 * (i % 4))] & 0xff;
14957c478bd9Sstevel@tonic-gate 		else
14967c478bd9Sstevel@tonic-gate 			out = value[i] & 0xff;
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		(void) printf("%02x", out);
14997c478bd9Sstevel@tonic-gate 	}
15007c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate static int
15047c478bd9Sstevel@tonic-gate unprintable(char *value, int size)
15057c478bd9Sstevel@tonic-gate {
15067c478bd9Sstevel@tonic-gate 	int i;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	/*
15097c478bd9Sstevel@tonic-gate 	 * Is this just a zero?
15107c478bd9Sstevel@tonic-gate 	 */
15117c478bd9Sstevel@tonic-gate 	if (size == 0 || value[0] == '\0')
15127c478bd9Sstevel@tonic-gate 		return (1);
15137c478bd9Sstevel@tonic-gate 	/*
15147c478bd9Sstevel@tonic-gate 	 * If any character is unprintable, or if a null appears
15157c478bd9Sstevel@tonic-gate 	 * anywhere except at the end of a string, the whole
15167c478bd9Sstevel@tonic-gate 	 * property is "unprintable".
15177c478bd9Sstevel@tonic-gate 	 */
15187c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; ++i) {
15197c478bd9Sstevel@tonic-gate 		if (value[i] == '\0')
15207c478bd9Sstevel@tonic-gate 			return (i != (size - 1));
15217c478bd9Sstevel@tonic-gate 		if (!isascii(value[i]) || iscntrl(value[i]))
15227c478bd9Sstevel@tonic-gate 			return (1);
15237c478bd9Sstevel@tonic-gate 	}
15247c478bd9Sstevel@tonic-gate 	return (0);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate static int
15287c478bd9Sstevel@tonic-gate promopen(int oflag)
15297c478bd9Sstevel@tonic-gate {
15307c478bd9Sstevel@tonic-gate 	for (;;)  {
15317c478bd9Sstevel@tonic-gate 		if ((prom_fd = open(opts.o_promdev, oflag)) < 0)  {
15327c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN)   {
15337c478bd9Sstevel@tonic-gate 				(void) sleep(5);
15347c478bd9Sstevel@tonic-gate 				continue;
15357c478bd9Sstevel@tonic-gate 			}
15367c478bd9Sstevel@tonic-gate 			if (errno == ENXIO)
15377c478bd9Sstevel@tonic-gate 				return (-1);
15387c478bd9Sstevel@tonic-gate 			if (getzoneid() == GLOBAL_ZONEID) {
15397c478bd9Sstevel@tonic-gate 				_exit(_error("cannot open %s",
15407c478bd9Sstevel@tonic-gate 				    opts.o_promdev));
15417c478bd9Sstevel@tonic-gate 			}
15427c478bd9Sstevel@tonic-gate 			/* not an error if this isn't the global zone */
15437c478bd9Sstevel@tonic-gate 			(void) _error(NULL, "openprom facility not available");
15447c478bd9Sstevel@tonic-gate 			exit(0);
15457c478bd9Sstevel@tonic-gate 		} else
15467c478bd9Sstevel@tonic-gate 			return (0);
15477c478bd9Sstevel@tonic-gate 	}
15487c478bd9Sstevel@tonic-gate }
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate static void
15517c478bd9Sstevel@tonic-gate promclose(void)
15527c478bd9Sstevel@tonic-gate {
15537c478bd9Sstevel@tonic-gate 	if (close(prom_fd) < 0)
15547c478bd9Sstevel@tonic-gate 		exit(_error("close error on %s", opts.o_promdev));
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate /*
15587c478bd9Sstevel@tonic-gate  * Get and print the name of the frame buffer device.
15597c478bd9Sstevel@tonic-gate  */
15607c478bd9Sstevel@tonic-gate int
15617c478bd9Sstevel@tonic-gate do_fbname(void)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate 	int	retval;
15647c478bd9Sstevel@tonic-gate 	char fbuf_path[MAXPATHLEN];
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	retval =  modctl(MODGETFBNAME, (caddr_t)fbuf_path);
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 	if (retval == 0) {
15697c478bd9Sstevel@tonic-gate 		(void) printf("%s\n", fbuf_path);
15707c478bd9Sstevel@tonic-gate 	} else {
15717c478bd9Sstevel@tonic-gate 		if (retval == EFAULT) {
15727c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
15737c478bd9Sstevel@tonic-gate 			"Error copying fb path to userland\n");
15747c478bd9Sstevel@tonic-gate 		} else {
15757c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
15767c478bd9Sstevel@tonic-gate 			"Console output device is not a frame buffer\n");
15777c478bd9Sstevel@tonic-gate 		}
15787c478bd9Sstevel@tonic-gate 		return (1);
15797c478bd9Sstevel@tonic-gate 	}
15807c478bd9Sstevel@tonic-gate 	return (0);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate /*
15847c478bd9Sstevel@tonic-gate  * Get and print the PROM version.
15857c478bd9Sstevel@tonic-gate  */
15867c478bd9Sstevel@tonic-gate int
15877c478bd9Sstevel@tonic-gate do_promversion(void)
15887c478bd9Sstevel@tonic-gate {
15897c478bd9Sstevel@tonic-gate 	Oppbuf	oppbuf;
15907c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	if (promopen(O_RDONLY))  {
15937c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot open openprom device\n");
15947c478bd9Sstevel@tonic-gate 		return (1);
15957c478bd9Sstevel@tonic-gate 	}
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
15987c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETVERSION, opp) < 0)
15997c478bd9Sstevel@tonic-gate 		exit(_error("OPROMGETVERSION"));
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	(void) printf("%s\n", opp->oprom_array);
16027c478bd9Sstevel@tonic-gate 	promclose();
16037c478bd9Sstevel@tonic-gate 	return (0);
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate int
16077c478bd9Sstevel@tonic-gate do_prom_version64(void)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate #ifdef	sparc
16107c478bd9Sstevel@tonic-gate 	Oppbuf	oppbuf;
16117c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
16127c478bd9Sstevel@tonic-gate 	/*LINTED*/
16137c478bd9Sstevel@tonic-gate 	struct openprom_opr64 *opr = (struct openprom_opr64 *)opp->oprom_array;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	static const char msg[] =
16167c478bd9Sstevel@tonic-gate 	    "NOTICE: The firmware on this system does not support the "
16177c478bd9Sstevel@tonic-gate 	    "64-bit OS.\n"
16187c478bd9Sstevel@tonic-gate 	    "\tPlease upgrade to at least the following version:\n"
16197c478bd9Sstevel@tonic-gate 	    "\t\t%s\n\n";
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 	if (promopen(O_RDONLY))  {
16227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot open openprom device\n");
16237c478bd9Sstevel@tonic-gate 		return (-1);
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
16277c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMREADY64, opp) < 0)
16287c478bd9Sstevel@tonic-gate 		exit(_error("OPROMREADY64"));
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	if (opr->return_code == 0)
16317c478bd9Sstevel@tonic-gate 		return (0);
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	(void) printf(msg, opr->message);
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	promclose();
16367c478bd9Sstevel@tonic-gate 	return (opr->return_code);
16377c478bd9Sstevel@tonic-gate #else
16387c478bd9Sstevel@tonic-gate 	return (0);
16397c478bd9Sstevel@tonic-gate #endif
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate int
16437c478bd9Sstevel@tonic-gate do_productinfo(void)
16447c478bd9Sstevel@tonic-gate {
16457c478bd9Sstevel@tonic-gate 	di_node_t root, next_node;
16467c478bd9Sstevel@tonic-gate 	di_prom_handle_t promh;
16477c478bd9Sstevel@tonic-gate 	static const char *root_prop[] = { "name", "model", "banner-name",
16487c478bd9Sstevel@tonic-gate 					"compatible" };
16497c478bd9Sstevel@tonic-gate 	static const char *root_propv[] = { "name", "model", "banner-name",
16507c478bd9Sstevel@tonic-gate 					"compatible", "idprom" };
16517c478bd9Sstevel@tonic-gate 	static const char *oprom_prop[] = { "model", "version" };
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	root = di_init("/", DINFOCPYALL);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
16577c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_init() failed\n");
16587c478bd9Sstevel@tonic-gate 		return (1);
16597c478bd9Sstevel@tonic-gate 	}
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 	promh = di_prom_init();
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	if (promh == DI_PROM_HANDLE_NIL) {
16647c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_prom_init() failed\n");
16657c478bd9Sstevel@tonic-gate 		return (1);
16667c478bd9Sstevel@tonic-gate 	}
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	if (opts.o_verbose) {
16697c478bd9Sstevel@tonic-gate 		dump_prodinfo(promh, root, root_propv, "root",
16707c478bd9Sstevel@tonic-gate 		    NUM_ELEMENTS(root_propv));
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 		/* Get model and version properties under node "openprom" */
16737c478bd9Sstevel@tonic-gate 		next_node = find_node_by_name(promh, root, "openprom");
16747c478bd9Sstevel@tonic-gate 		if (next_node != DI_NODE_NIL)
16757c478bd9Sstevel@tonic-gate 			dump_prodinfo(promh, next_node, oprom_prop,
16767c478bd9Sstevel@tonic-gate 			    "openprom", NUM_ELEMENTS(oprom_prop));
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	} else
16797c478bd9Sstevel@tonic-gate 		dump_prodinfo(promh, root, root_prop, "root",
16807c478bd9Sstevel@tonic-gate 		    NUM_ELEMENTS(root_prop));
16817c478bd9Sstevel@tonic-gate 	di_prom_fini(promh);
16827c478bd9Sstevel@tonic-gate 	di_fini(root);
16837c478bd9Sstevel@tonic-gate 	return (0);
16847c478bd9Sstevel@tonic-gate }
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate di_node_t
16877c478bd9Sstevel@tonic-gate find_node_by_name(di_prom_handle_t promh, di_node_t parent,
16887c478bd9Sstevel@tonic-gate 		char *node_name)
16897c478bd9Sstevel@tonic-gate {
16907c478bd9Sstevel@tonic-gate 	di_node_t next_node;
16917c478bd9Sstevel@tonic-gate 	uchar_t *prop_valp;
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	next_node = di_child_node(parent);
16947c478bd9Sstevel@tonic-gate 	while (next_node != DI_NODE_NIL) {
16957c478bd9Sstevel@tonic-gate 		next_node = di_sibling_node(next_node);
16967c478bd9Sstevel@tonic-gate 		(void) get_propval_by_name(promh, next_node, "name",
16977c478bd9Sstevel@tonic-gate 		    &prop_valp);
16987c478bd9Sstevel@tonic-gate 		if (strcmp((char *)prop_valp, node_name) == 0)
16997c478bd9Sstevel@tonic-gate 			return (next_node);
17007c478bd9Sstevel@tonic-gate 	}
17017c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate int
17067c478bd9Sstevel@tonic-gate get_propval_by_name(di_prom_handle_t promh, di_node_t node, const char *name,
17077c478bd9Sstevel@tonic-gate 			uchar_t **valp)
17087c478bd9Sstevel@tonic-gate {
17097c478bd9Sstevel@tonic-gate 	int len;
17107c478bd9Sstevel@tonic-gate 	uchar_t *bufp;
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 	len = di_prom_prop_lookup_bytes(promh, node, name,
17137c478bd9Sstevel@tonic-gate 	    (uchar_t **)&bufp);
17147c478bd9Sstevel@tonic-gate 	if (len != -1) {
17157c478bd9Sstevel@tonic-gate 		*valp = (uchar_t *)malloc(len);
17167c478bd9Sstevel@tonic-gate 		(void) memcpy(*valp, bufp, len);
17177c478bd9Sstevel@tonic-gate 	}
17187c478bd9Sstevel@tonic-gate 	return (len);
17197c478bd9Sstevel@tonic-gate }
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate static void
17237c478bd9Sstevel@tonic-gate dump_prodinfo(di_prom_handle_t promh, di_node_t node, const char **propstr,
17247c478bd9Sstevel@tonic-gate 		char *node_name, int num)
17257c478bd9Sstevel@tonic-gate {
17267c478bd9Sstevel@tonic-gate 	int out, len, index1, index, endswap = 0;
17277c478bd9Sstevel@tonic-gate 	uchar_t *prop_valp;
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	for (index1 = 0; index1 < num; index1++) {
17307c478bd9Sstevel@tonic-gate 		len = get_propval_by_name(promh, node, propstr[index1],
17317c478bd9Sstevel@tonic-gate 		    &prop_valp);
17327c478bd9Sstevel@tonic-gate 		if (len != -1) {
17337c478bd9Sstevel@tonic-gate 			if (strcmp(node_name, "root"))
17347c478bd9Sstevel@tonic-gate 				(void) printf("%s ", node_name);
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 			(void) printf("%s: ", propstr[index1]);
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 			if (print_composite_string((const char *)
17397c478bd9Sstevel@tonic-gate 			    propstr[index1], (char *)prop_valp, len)) {
17407c478bd9Sstevel@tonic-gate 				free(prop_valp);
17417c478bd9Sstevel@tonic-gate 				continue;
17427c478bd9Sstevel@tonic-gate 			}
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 			if (!unprintable((char *)prop_valp, len)) {
17457c478bd9Sstevel@tonic-gate 				(void) printf(" %s\n", (char *)prop_valp);
17467c478bd9Sstevel@tonic-gate 				free(prop_valp);
17477c478bd9Sstevel@tonic-gate 				continue;
17487c478bd9Sstevel@tonic-gate 			}
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 			(void) printf(" ");
17517c478bd9Sstevel@tonic-gate #ifdef  __x86
17527c478bd9Sstevel@tonic-gate 			endswap = (len % 4) == 0;
17537c478bd9Sstevel@tonic-gate #endif  /* __x86 */
17547c478bd9Sstevel@tonic-gate 			for (index = 0; index < len; index++) {
17557c478bd9Sstevel@tonic-gate 				if (index && (index % 4 == 0))
17567c478bd9Sstevel@tonic-gate 					(void) putchar('.');
17577c478bd9Sstevel@tonic-gate 				if (endswap)
17587c478bd9Sstevel@tonic-gate 					out = prop_valp[index +
17597c478bd9Sstevel@tonic-gate 					    (3 - 2 * (index % 4))] & 0xff;
17607c478bd9Sstevel@tonic-gate 				else
17617c478bd9Sstevel@tonic-gate 					out = prop_valp[index] & 0xff;
17627c478bd9Sstevel@tonic-gate 				(void) printf("%02x", out);
17637c478bd9Sstevel@tonic-gate 			}
17647c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
17657c478bd9Sstevel@tonic-gate 			free(prop_valp);
17667c478bd9Sstevel@tonic-gate 		}
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate }
1769