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