xref: /illumos-gate/usr/src/lib/libdevinfo/devinfo.c (revision 7c478bd9)
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 2004 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  * Interfaces for getting device configuration data from kernel
31*7c478bd9Sstevel@tonic-gate  * through the devinfo driver.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <stdio.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <strings.h>
38*7c478bd9Sstevel@tonic-gate #include <stropts.h>
39*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
40*7c478bd9Sstevel@tonic-gate #include <poll.h>
41*7c478bd9Sstevel@tonic-gate #include <synch.h>
42*7c478bd9Sstevel@tonic-gate #include <unistd.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
49*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #define	NDEBUG 1
52*7c478bd9Sstevel@tonic-gate #include <assert.h>
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #include "libdevinfo.h"
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate /*
57*7c478bd9Sstevel@tonic-gate  * Debug message levels
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate typedef enum {
60*7c478bd9Sstevel@tonic-gate 	DI_QUIET = 0,	/* No debug messages - the default */
61*7c478bd9Sstevel@tonic-gate 	DI_ERR = 1,
62*7c478bd9Sstevel@tonic-gate 	DI_INFO,
63*7c478bd9Sstevel@tonic-gate 	DI_TRACE,
64*7c478bd9Sstevel@tonic-gate 	DI_TRACE1,
65*7c478bd9Sstevel@tonic-gate 	DI_TRACE2
66*7c478bd9Sstevel@tonic-gate } di_debug_t;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate int di_debug = DI_QUIET;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate #define	DPRINTF(args)	{ if (di_debug != DI_QUIET) dprint args; }
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate void dprint(di_debug_t msglevel, const char *fmt, ...);
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate #pragma init(_libdevinfo_init)
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate void
78*7c478bd9Sstevel@tonic-gate _libdevinfo_init()
79*7c478bd9Sstevel@tonic-gate {
80*7c478bd9Sstevel@tonic-gate 	char	*debug_str = getenv("_LIBDEVINFO_DEBUG");
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	if (debug_str) {
83*7c478bd9Sstevel@tonic-gate 		errno = 0;
84*7c478bd9Sstevel@tonic-gate 		di_debug = atoi(debug_str);
85*7c478bd9Sstevel@tonic-gate 		if (errno || di_debug < DI_QUIET)
86*7c478bd9Sstevel@tonic-gate 			di_debug = DI_QUIET;
87*7c478bd9Sstevel@tonic-gate 	}
88*7c478bd9Sstevel@tonic-gate }
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate di_node_t
91*7c478bd9Sstevel@tonic-gate di_init(const char *phys_path, uint_t flag)
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	return (di_init_impl(phys_path, flag, NULL));
94*7c478bd9Sstevel@tonic-gate }
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /*
97*7c478bd9Sstevel@tonic-gate  * We use blocking_open() to guarantee access to the devinfo device, if open()
98*7c478bd9Sstevel@tonic-gate  * is failing with EAGAIN.
99*7c478bd9Sstevel@tonic-gate  */
100*7c478bd9Sstevel@tonic-gate static int
101*7c478bd9Sstevel@tonic-gate blocking_open(const char *path, int oflag)
102*7c478bd9Sstevel@tonic-gate {
103*7c478bd9Sstevel@tonic-gate 	int fd;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
106*7c478bd9Sstevel@tonic-gate 		(void) poll(NULL, 0, 1 * MILLISEC);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	return (fd);
109*7c478bd9Sstevel@tonic-gate }
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /* private interface */
112*7c478bd9Sstevel@tonic-gate di_node_t
113*7c478bd9Sstevel@tonic-gate di_init_driver(const char *drv_name, uint_t flag)
114*7c478bd9Sstevel@tonic-gate {
115*7c478bd9Sstevel@tonic-gate 	int fd;
116*7c478bd9Sstevel@tonic-gate 	char driver[MAXPATHLEN];
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	/*
119*7c478bd9Sstevel@tonic-gate 	 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
120*7c478bd9Sstevel@tonic-gate 	 * which should be sufficient for any sensible programmer.
121*7c478bd9Sstevel@tonic-gate 	 */
122*7c478bd9Sstevel@tonic-gate 	if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
123*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
124*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 	(void) strcpy(driver, drv_name);
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	/*
129*7c478bd9Sstevel@tonic-gate 	 * open the devinfo driver
130*7c478bd9Sstevel@tonic-gate 	 */
131*7c478bd9Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
132*7c478bd9Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
133*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
134*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOLODRV, driver) != 0) {
138*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
139*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
140*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
141*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	/*
146*7c478bd9Sstevel@tonic-gate 	 * Driver load succeeded, return a snapshot
147*7c478bd9Sstevel@tonic-gate 	 */
148*7c478bd9Sstevel@tonic-gate 	return (di_init("/", flag));
149*7c478bd9Sstevel@tonic-gate }
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate di_node_t
152*7c478bd9Sstevel@tonic-gate di_init_impl(const char *phys_path, uint_t flag,
153*7c478bd9Sstevel@tonic-gate 	struct di_priv_data *priv)
154*7c478bd9Sstevel@tonic-gate {
155*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
156*7c478bd9Sstevel@tonic-gate 	int fd, map_size;
157*7c478bd9Sstevel@tonic-gate 	struct di_all *dap;
158*7c478bd9Sstevel@tonic-gate 	struct dinfo_io dinfo_io;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
161*7c478bd9Sstevel@tonic-gate 	uint_t pagemask = ~pageoffset;
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	/*
166*7c478bd9Sstevel@tonic-gate 	 * Make sure there is no minor name in the path
167*7c478bd9Sstevel@tonic-gate 	 * and the path do not start with /devices....
168*7c478bd9Sstevel@tonic-gate 	 */
169*7c478bd9Sstevel@tonic-gate 	if (strchr(phys_path, ':') ||
170*7c478bd9Sstevel@tonic-gate 	    (strncmp(phys_path, "/devices", 8) == 0) ||
171*7c478bd9Sstevel@tonic-gate 	    (strlen(phys_path) > MAXPATHLEN)) {
172*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
173*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
174*7c478bd9Sstevel@tonic-gate 	}
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	if (strlen(phys_path) == 0)
177*7c478bd9Sstevel@tonic-gate 		(void) sprintf(dinfo_io.root_path, "/");
178*7c478bd9Sstevel@tonic-gate 	else if (*phys_path != '/')
179*7c478bd9Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
180*7c478bd9Sstevel@tonic-gate 		    "/%s", phys_path);
181*7c478bd9Sstevel@tonic-gate 	else
182*7c478bd9Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
183*7c478bd9Sstevel@tonic-gate 		    "%s", phys_path);
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	/*
186*7c478bd9Sstevel@tonic-gate 	 * If private data is requested, copy the format specification
187*7c478bd9Sstevel@tonic-gate 	 */
188*7c478bd9Sstevel@tonic-gate 	if (flag & DINFOPRIVDATA & 0xff) {
189*7c478bd9Sstevel@tonic-gate 		if (priv)
190*7c478bd9Sstevel@tonic-gate 			bcopy(priv, &dinfo_io.priv,
191*7c478bd9Sstevel@tonic-gate 			    sizeof (struct di_priv_data));
192*7c478bd9Sstevel@tonic-gate 		else {
193*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
194*7c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
195*7c478bd9Sstevel@tonic-gate 		}
196*7c478bd9Sstevel@tonic-gate 	}
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	/*
199*7c478bd9Sstevel@tonic-gate 	 * Attempt to open the devinfo driver.  Make a second attempt at the
200*7c478bd9Sstevel@tonic-gate 	 * read-only minor node if we don't have privileges to open the full
201*7c478bd9Sstevel@tonic-gate 	 * version _and_ if we're not requesting operations that the read-only
202*7c478bd9Sstevel@tonic-gate 	 * node can't perform.  (Setgid processes would fail an access() test,
203*7c478bd9Sstevel@tonic-gate 	 * of course.)
204*7c478bd9Sstevel@tonic-gate 	 */
205*7c478bd9Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
206*7c478bd9Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
207*7c478bd9Sstevel@tonic-gate 		if ((flag & DINFOFORCE) == DINFOFORCE ||
208*7c478bd9Sstevel@tonic-gate 		    (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
209*7c478bd9Sstevel@tonic-gate 			/*
210*7c478bd9Sstevel@tonic-gate 			 * We wanted to perform a privileged operation, but the
211*7c478bd9Sstevel@tonic-gate 			 * privileged node isn't available.  Don't modify errno
212*7c478bd9Sstevel@tonic-gate 			 * on our way out (but display it if we're running with
213*7c478bd9Sstevel@tonic-gate 			 * di_debug set).
214*7c478bd9Sstevel@tonic-gate 			 */
215*7c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
216*7c478bd9Sstevel@tonic-gate 			    errno));
217*7c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
218*7c478bd9Sstevel@tonic-gate 		}
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 		if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
221*7c478bd9Sstevel@tonic-gate 		    O_RDONLY)) == -1) {
222*7c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
223*7c478bd9Sstevel@tonic-gate 			    errno));
224*7c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
225*7c478bd9Sstevel@tonic-gate 		}
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	/*
229*7c478bd9Sstevel@tonic-gate 	 * Verify that there is no major conflict, i.e., we are indeed opening
230*7c478bd9Sstevel@tonic-gate 	 * the devinfo driver.
231*7c478bd9Sstevel@tonic-gate 	 */
232*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
233*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR,
234*7c478bd9Sstevel@tonic-gate 		    "driver ID failed; check for major conflict\n"));
235*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
236*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	/*
240*7c478bd9Sstevel@tonic-gate 	 * create snapshot
241*7c478bd9Sstevel@tonic-gate 	 */
242*7c478bd9Sstevel@tonic-gate 	if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
243*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo ioctl failed with "
244*7c478bd9Sstevel@tonic-gate 		    "error: %d\n", errno));
245*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
246*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
247*7c478bd9Sstevel@tonic-gate 	} else if (map_size == 0) {
248*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
249*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
250*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
251*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	/*
255*7c478bd9Sstevel@tonic-gate 	 * copy snapshot to userland
256*7c478bd9Sstevel@tonic-gate 	 */
257*7c478bd9Sstevel@tonic-gate 	map_size = (map_size + pageoffset) & pagemask;
258*7c478bd9Sstevel@tonic-gate 	if ((pa = valloc(map_size)) == NULL) {
259*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
260*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
261*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
262*7c478bd9Sstevel@tonic-gate 	}
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
265*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
266*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
267*7c478bd9Sstevel@tonic-gate 		free(pa);
268*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
269*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	dap = DI_ALL(pa);
275*7c478bd9Sstevel@tonic-gate 	if (dap->top_devinfo == 0) {	/* phys_path not found */
276*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
277*7c478bd9Sstevel@tonic-gate 		free(pa);
278*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
279*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + dap->top_devinfo));
283*7c478bd9Sstevel@tonic-gate }
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate void
286*7c478bd9Sstevel@tonic-gate di_fini(di_node_t root)
287*7c478bd9Sstevel@tonic-gate {
288*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	/*
293*7c478bd9Sstevel@tonic-gate 	 * paranoid checking
294*7c478bd9Sstevel@tonic-gate 	 */
295*7c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
296*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
297*7c478bd9Sstevel@tonic-gate 		return;
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	/*
301*7c478bd9Sstevel@tonic-gate 	 * The root contains its own offset--self.
302*7c478bd9Sstevel@tonic-gate 	 * Subtracting it from root address, we get the starting addr.
303*7c478bd9Sstevel@tonic-gate 	 * The map_size is stored at the beginning of snapshot.
304*7c478bd9Sstevel@tonic-gate 	 * Once we have starting address and size, we can free().
305*7c478bd9Sstevel@tonic-gate 	 */
306*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	free(pa);
309*7c478bd9Sstevel@tonic-gate }
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate di_node_t
312*7c478bd9Sstevel@tonic-gate di_parent_node(di_node_t node)
313*7c478bd9Sstevel@tonic-gate {
314*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
317*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
318*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent) {
326*7c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->parent));
327*7c478bd9Sstevel@tonic-gate 	}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	/*
330*7c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
331*7c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
332*7c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
333*7c478bd9Sstevel@tonic-gate 	 */
334*7c478bd9Sstevel@tonic-gate 	if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
335*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
336*7c478bd9Sstevel@tonic-gate 	else
337*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate di_node_t
343*7c478bd9Sstevel@tonic-gate di_sibling_node(di_node_t node)
344*7c478bd9Sstevel@tonic-gate {
345*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
348*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
349*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
350*7c478bd9Sstevel@tonic-gate 	}
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->sibling) {
357*7c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->sibling));
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	/*
361*7c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
362*7c478bd9Sstevel@tonic-gate 	 *   Sibling doesn't exist, figure out if ioctl command
363*7c478bd9Sstevel@tonic-gate 	 *   has DINFOSUBTREE set. If it doesn't, set errno to
364*7c478bd9Sstevel@tonic-gate 	 *   ENOTSUP.
365*7c478bd9Sstevel@tonic-gate 	 */
366*7c478bd9Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
367*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
368*7c478bd9Sstevel@tonic-gate 	else
369*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
372*7c478bd9Sstevel@tonic-gate }
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate di_node_t
375*7c478bd9Sstevel@tonic-gate di_child_node(di_node_t node)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
382*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
383*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
384*7c478bd9Sstevel@tonic-gate 	}
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->child) {
389*7c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->child));
390*7c478bd9Sstevel@tonic-gate 	}
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	/*
393*7c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
394*7c478bd9Sstevel@tonic-gate 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
395*7c478bd9Sstevel@tonic-gate 	 *   If it isn't, set errno to ENOTSUP.
396*7c478bd9Sstevel@tonic-gate 	 */
397*7c478bd9Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
398*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
399*7c478bd9Sstevel@tonic-gate 	else
400*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
403*7c478bd9Sstevel@tonic-gate }
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate di_node_t
406*7c478bd9Sstevel@tonic-gate di_drv_first_node(const char *drv_name, di_node_t root)
407*7c478bd9Sstevel@tonic-gate {
408*7c478bd9Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
409*7c478bd9Sstevel@tonic-gate 	int		major, devcnt;
410*7c478bd9Sstevel@tonic-gate 	struct di_devnm	*devnm;
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
415*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
416*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	/*
420*7c478bd9Sstevel@tonic-gate 	 * get major number of driver
421*7c478bd9Sstevel@tonic-gate 	 */
422*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
423*7c478bd9Sstevel@tonic-gate 	devcnt = DI_ALL(pa)->devcnt;
424*7c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	for (major = 0; major < devcnt; major++)
427*7c478bd9Sstevel@tonic-gate 		if (devnm[major].name && (strcmp(drv_name,
428*7c478bd9Sstevel@tonic-gate 		    (char *)(pa + devnm[major].name)) == 0))
429*7c478bd9Sstevel@tonic-gate 			break;
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	if (major >= devcnt) {
432*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
433*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	if (!(devnm[major].head)) {
437*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
438*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + devnm[major].head));
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate di_node_t
445*7c478bd9Sstevel@tonic-gate di_drv_next_node(di_node_t node)
446*7c478bd9Sstevel@tonic-gate {
447*7c478bd9Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
450*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
451*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
452*7c478bd9Sstevel@tonic-gate 	}
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "next node on per driver list:"
455*7c478bd9Sstevel@tonic-gate 	    " current=%s, driver=%s\n",
456*7c478bd9Sstevel@tonic-gate 	    di_node_name(node), di_driver_name(node)));
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->next == (di_off_t)-1) {
459*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
460*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->next == NULL) {
466*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
467*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + DI_NODE(node)->next));
471*7c478bd9Sstevel@tonic-gate }
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate /*
474*7c478bd9Sstevel@tonic-gate  * Internal library interfaces:
475*7c478bd9Sstevel@tonic-gate  *   node_list etc. for node walking
476*7c478bd9Sstevel@tonic-gate  */
477*7c478bd9Sstevel@tonic-gate struct node_list {
478*7c478bd9Sstevel@tonic-gate 	struct node_list *next;
479*7c478bd9Sstevel@tonic-gate 	di_node_t node;
480*7c478bd9Sstevel@tonic-gate };
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate static void
483*7c478bd9Sstevel@tonic-gate free_node_list(struct node_list **headp)
484*7c478bd9Sstevel@tonic-gate {
485*7c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	while (*headp) {
488*7c478bd9Sstevel@tonic-gate 		tmp = *headp;
489*7c478bd9Sstevel@tonic-gate 		*headp = (*headp)->next;
490*7c478bd9Sstevel@tonic-gate 		free(tmp);
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate }
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate static void
495*7c478bd9Sstevel@tonic-gate append_node_list(struct node_list **headp, struct node_list *list)
496*7c478bd9Sstevel@tonic-gate {
497*7c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	if (*headp == NULL) {
500*7c478bd9Sstevel@tonic-gate 		*headp = list;
501*7c478bd9Sstevel@tonic-gate 		return;
502*7c478bd9Sstevel@tonic-gate 	}
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	if (list == NULL)	/* a minor optimization */
505*7c478bd9Sstevel@tonic-gate 		return;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	tmp = *headp;
508*7c478bd9Sstevel@tonic-gate 	while (tmp->next)
509*7c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	tmp->next = list;
512*7c478bd9Sstevel@tonic-gate }
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate static void
515*7c478bd9Sstevel@tonic-gate prepend_node_list(struct node_list **headp, struct node_list *list)
516*7c478bd9Sstevel@tonic-gate {
517*7c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	if (list == NULL)
520*7c478bd9Sstevel@tonic-gate 		return;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	tmp = *headp;
523*7c478bd9Sstevel@tonic-gate 	*headp = list;
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	if (tmp == NULL)	/* a minor optimization */
526*7c478bd9Sstevel@tonic-gate 		return;
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	while (list->next)
529*7c478bd9Sstevel@tonic-gate 		list = list->next;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	list->next = tmp;
532*7c478bd9Sstevel@tonic-gate }
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate /*
535*7c478bd9Sstevel@tonic-gate  * returns 1 if node is a descendant of parent, 0 otherwise
536*7c478bd9Sstevel@tonic-gate  */
537*7c478bd9Sstevel@tonic-gate static int
538*7c478bd9Sstevel@tonic-gate is_descendant(di_node_t node, di_node_t parent)
539*7c478bd9Sstevel@tonic-gate {
540*7c478bd9Sstevel@tonic-gate 	/*
541*7c478bd9Sstevel@tonic-gate 	 * DI_NODE_NIL is parent of root, so it is
542*7c478bd9Sstevel@tonic-gate 	 * the parent of all nodes.
543*7c478bd9Sstevel@tonic-gate 	 */
544*7c478bd9Sstevel@tonic-gate 	if (parent == DI_NODE_NIL) {
545*7c478bd9Sstevel@tonic-gate 		return (1);
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	do {
549*7c478bd9Sstevel@tonic-gate 		node = di_parent_node(node);
550*7c478bd9Sstevel@tonic-gate 	} while ((node != DI_NODE_NIL) && (node != parent));
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	return (node != DI_NODE_NIL);
553*7c478bd9Sstevel@tonic-gate }
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate /*
556*7c478bd9Sstevel@tonic-gate  * Insert list before the first node which is NOT a descendent of parent.
557*7c478bd9Sstevel@tonic-gate  * This is needed to reproduce the exact walking order of link generators.
558*7c478bd9Sstevel@tonic-gate  */
559*7c478bd9Sstevel@tonic-gate static void
560*7c478bd9Sstevel@tonic-gate insert_node_list(struct node_list **headp, struct node_list *list,
561*7c478bd9Sstevel@tonic-gate     di_node_t parent)
562*7c478bd9Sstevel@tonic-gate {
563*7c478bd9Sstevel@tonic-gate 	struct node_list *tmp, *tmp1;
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	if (list == NULL)
566*7c478bd9Sstevel@tonic-gate 		return;
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	tmp = *headp;
569*7c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {	/* a minor optimization */
570*7c478bd9Sstevel@tonic-gate 		*headp = list;
571*7c478bd9Sstevel@tonic-gate 		return;
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	if (!is_descendant(tmp->node, parent)) {
575*7c478bd9Sstevel@tonic-gate 		prepend_node_list(headp, list);
576*7c478bd9Sstevel@tonic-gate 		return;
577*7c478bd9Sstevel@tonic-gate 	}
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	/*
580*7c478bd9Sstevel@tonic-gate 	 * Find first node which is not a descendant
581*7c478bd9Sstevel@tonic-gate 	 */
582*7c478bd9Sstevel@tonic-gate 	while (tmp->next && is_descendant(tmp->next->node, parent)) {
583*7c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	tmp1 = tmp->next;
587*7c478bd9Sstevel@tonic-gate 	tmp->next = list;
588*7c478bd9Sstevel@tonic-gate 	append_node_list(headp, tmp1);
589*7c478bd9Sstevel@tonic-gate }
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate /*
592*7c478bd9Sstevel@tonic-gate  *   Get a linked list of handles of all children
593*7c478bd9Sstevel@tonic-gate  */
594*7c478bd9Sstevel@tonic-gate static struct node_list *
595*7c478bd9Sstevel@tonic-gate get_children(di_node_t node)
596*7c478bd9Sstevel@tonic-gate {
597*7c478bd9Sstevel@tonic-gate 	di_node_t child;
598*7c478bd9Sstevel@tonic-gate 	struct node_list *result, *tmp;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	if ((child = di_child_node(node)) == DI_NODE_NIL) {
603*7c478bd9Sstevel@tonic-gate 		return (NULL);
604*7c478bd9Sstevel@tonic-gate 	}
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	if ((result = malloc(sizeof (struct node_list))) == NULL) {
607*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
608*7c478bd9Sstevel@tonic-gate 		return (NULL);
609*7c478bd9Sstevel@tonic-gate 	}
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	result->node = child;
612*7c478bd9Sstevel@tonic-gate 	tmp = result;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
615*7c478bd9Sstevel@tonic-gate 		if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
616*7c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "malloc of node_list failed\n"));
617*7c478bd9Sstevel@tonic-gate 			free_node_list(&result);
618*7c478bd9Sstevel@tonic-gate 			return (NULL);
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
621*7c478bd9Sstevel@tonic-gate 		tmp->node = child;
622*7c478bd9Sstevel@tonic-gate 	}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	tmp->next = NULL;
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	return (result);
627*7c478bd9Sstevel@tonic-gate }
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate /*
630*7c478bd9Sstevel@tonic-gate  * Internal library interface:
631*7c478bd9Sstevel@tonic-gate  *   Delete all siblings of the first node from the node_list, along with
632*7c478bd9Sstevel@tonic-gate  *   the first node itself.
633*7c478bd9Sstevel@tonic-gate  */
634*7c478bd9Sstevel@tonic-gate static void
635*7c478bd9Sstevel@tonic-gate prune_sib(struct node_list **headp)
636*7c478bd9Sstevel@tonic-gate {
637*7c478bd9Sstevel@tonic-gate 	di_node_t parent, curr_par, curr_gpar;
638*7c478bd9Sstevel@tonic-gate 	struct node_list *curr, *prev;
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	/*
641*7c478bd9Sstevel@tonic-gate 	 * get handle to parent of first node
642*7c478bd9Sstevel@tonic-gate 	 */
643*7c478bd9Sstevel@tonic-gate 	if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
644*7c478bd9Sstevel@tonic-gate 		/*
645*7c478bd9Sstevel@tonic-gate 		 * This must be the root of the snapshot, so can't
646*7c478bd9Sstevel@tonic-gate 		 * have any siblings.
647*7c478bd9Sstevel@tonic-gate 		 *
648*7c478bd9Sstevel@tonic-gate 		 * XXX Put a check here just in case.
649*7c478bd9Sstevel@tonic-gate 		 */
650*7c478bd9Sstevel@tonic-gate 		if ((*headp)->next)
651*7c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 		free(*headp);
654*7c478bd9Sstevel@tonic-gate 		*headp = NULL;
655*7c478bd9Sstevel@tonic-gate 		return;
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	/*
659*7c478bd9Sstevel@tonic-gate 	 * To be complete, we should also delete the children
660*7c478bd9Sstevel@tonic-gate 	 * of siblings that have already been visited.
661*7c478bd9Sstevel@tonic-gate 	 * This happens for DI_WALK_SIBFIRST when the first node
662*7c478bd9Sstevel@tonic-gate 	 * is NOT the first in the linked list of siblings.
663*7c478bd9Sstevel@tonic-gate 	 *
664*7c478bd9Sstevel@tonic-gate 	 * Hence, we compare parent with BOTH the parent and grandparent
665*7c478bd9Sstevel@tonic-gate 	 * of nodes, and delete node is a match is found.
666*7c478bd9Sstevel@tonic-gate 	 */
667*7c478bd9Sstevel@tonic-gate 	prev = *headp;
668*7c478bd9Sstevel@tonic-gate 	curr = prev->next;
669*7c478bd9Sstevel@tonic-gate 	while (curr) {
670*7c478bd9Sstevel@tonic-gate 		if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) &&
671*7c478bd9Sstevel@tonic-gate 		    ((curr_par == parent) || ((curr_gpar =
672*7c478bd9Sstevel@tonic-gate 		    di_parent_node(curr_par)) != DI_NODE_NIL) &&
673*7c478bd9Sstevel@tonic-gate 		    (curr_gpar == parent))) {
674*7c478bd9Sstevel@tonic-gate 			/*
675*7c478bd9Sstevel@tonic-gate 			 * match parent/grandparent: delete curr
676*7c478bd9Sstevel@tonic-gate 			 */
677*7c478bd9Sstevel@tonic-gate 			prev->next = curr->next;
678*7c478bd9Sstevel@tonic-gate 			free(curr);
679*7c478bd9Sstevel@tonic-gate 			curr = prev->next;
680*7c478bd9Sstevel@tonic-gate 		} else
681*7c478bd9Sstevel@tonic-gate 			curr = curr->next;
682*7c478bd9Sstevel@tonic-gate 	}
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 	/*
685*7c478bd9Sstevel@tonic-gate 	 * delete the first node
686*7c478bd9Sstevel@tonic-gate 	 */
687*7c478bd9Sstevel@tonic-gate 	curr = *headp;
688*7c478bd9Sstevel@tonic-gate 	*headp = curr->next;
689*7c478bd9Sstevel@tonic-gate 	free(curr);
690*7c478bd9Sstevel@tonic-gate }
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate /*
693*7c478bd9Sstevel@tonic-gate  * Internal library function:
694*7c478bd9Sstevel@tonic-gate  *	Update node list based on action (return code from callback)
695*7c478bd9Sstevel@tonic-gate  *	and flag specifying walking behavior.
696*7c478bd9Sstevel@tonic-gate  */
697*7c478bd9Sstevel@tonic-gate static void
698*7c478bd9Sstevel@tonic-gate update_node_list(int action, uint_t flag, struct node_list **headp)
699*7c478bd9Sstevel@tonic-gate {
700*7c478bd9Sstevel@tonic-gate 	struct node_list *children, *tmp;
701*7c478bd9Sstevel@tonic-gate 	di_node_t parent = di_parent_node((*headp)->node);
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	switch (action) {
704*7c478bd9Sstevel@tonic-gate 	case DI_WALK_TERMINATE:
705*7c478bd9Sstevel@tonic-gate 		/*
706*7c478bd9Sstevel@tonic-gate 		 * free the node list and be done
707*7c478bd9Sstevel@tonic-gate 		 */
708*7c478bd9Sstevel@tonic-gate 		children = NULL;
709*7c478bd9Sstevel@tonic-gate 		free_node_list(headp);
710*7c478bd9Sstevel@tonic-gate 		break;
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 	case DI_WALK_PRUNESIB:
713*7c478bd9Sstevel@tonic-gate 		/*
714*7c478bd9Sstevel@tonic-gate 		 * Get list of children and prune siblings
715*7c478bd9Sstevel@tonic-gate 		 */
716*7c478bd9Sstevel@tonic-gate 		children = get_children((*headp)->node);
717*7c478bd9Sstevel@tonic-gate 		prune_sib(headp);
718*7c478bd9Sstevel@tonic-gate 		break;
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	case DI_WALK_PRUNECHILD:
721*7c478bd9Sstevel@tonic-gate 		/*
722*7c478bd9Sstevel@tonic-gate 		 * Set children to NULL and pop first node
723*7c478bd9Sstevel@tonic-gate 		 */
724*7c478bd9Sstevel@tonic-gate 		children = NULL;
725*7c478bd9Sstevel@tonic-gate 		tmp = *headp;
726*7c478bd9Sstevel@tonic-gate 		*headp = tmp->next;
727*7c478bd9Sstevel@tonic-gate 		free(tmp);
728*7c478bd9Sstevel@tonic-gate 		break;
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 	case DI_WALK_CONTINUE:
731*7c478bd9Sstevel@tonic-gate 	default:
732*7c478bd9Sstevel@tonic-gate 		/*
733*7c478bd9Sstevel@tonic-gate 		 * Get list of children and pop first node
734*7c478bd9Sstevel@tonic-gate 		 */
735*7c478bd9Sstevel@tonic-gate 		children = get_children((*headp)->node);
736*7c478bd9Sstevel@tonic-gate 		tmp = *headp;
737*7c478bd9Sstevel@tonic-gate 		*headp = tmp->next;
738*7c478bd9Sstevel@tonic-gate 		free(tmp);
739*7c478bd9Sstevel@tonic-gate 		break;
740*7c478bd9Sstevel@tonic-gate 	}
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	/*
743*7c478bd9Sstevel@tonic-gate 	 * insert the list of children
744*7c478bd9Sstevel@tonic-gate 	 */
745*7c478bd9Sstevel@tonic-gate 	switch (flag) {
746*7c478bd9Sstevel@tonic-gate 	case DI_WALK_CLDFIRST:
747*7c478bd9Sstevel@tonic-gate 		prepend_node_list(headp, children);
748*7c478bd9Sstevel@tonic-gate 		break;
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	case DI_WALK_SIBFIRST:
751*7c478bd9Sstevel@tonic-gate 		append_node_list(headp, children);
752*7c478bd9Sstevel@tonic-gate 		break;
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	case DI_WALK_LINKGEN:
755*7c478bd9Sstevel@tonic-gate 	default:
756*7c478bd9Sstevel@tonic-gate 		insert_node_list(headp, children, parent);
757*7c478bd9Sstevel@tonic-gate 		break;
758*7c478bd9Sstevel@tonic-gate 	}
759*7c478bd9Sstevel@tonic-gate }
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate /*
762*7c478bd9Sstevel@tonic-gate  * Internal library function:
763*7c478bd9Sstevel@tonic-gate  *   Invoke callback on one node and update the list of nodes to be walked
764*7c478bd9Sstevel@tonic-gate  *   based on the flag and return code.
765*7c478bd9Sstevel@tonic-gate  */
766*7c478bd9Sstevel@tonic-gate static void
767*7c478bd9Sstevel@tonic-gate walk_one_node(struct node_list **headp, uint_t flag, void *arg,
768*7c478bd9Sstevel@tonic-gate 	int (*callback)(di_node_t, void *))
769*7c478bd9Sstevel@tonic-gate {
770*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 	update_node_list(callback((*headp)->node, arg),
773*7c478bd9Sstevel@tonic-gate 	    flag & DI_WALK_MASK, headp);
774*7c478bd9Sstevel@tonic-gate }
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate int
777*7c478bd9Sstevel@tonic-gate di_walk_node(di_node_t root, uint_t flag, void *arg,
778*7c478bd9Sstevel@tonic-gate 	int (*node_callback)(di_node_t, void *))
779*7c478bd9Sstevel@tonic-gate {
780*7c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 	if (root == NULL) {
783*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
784*7c478bd9Sstevel@tonic-gate 		return (-1);
785*7c478bd9Sstevel@tonic-gate 	}
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
788*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
789*7c478bd9Sstevel@tonic-gate 		return (-1);
790*7c478bd9Sstevel@tonic-gate 	}
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	head->next = NULL;
793*7c478bd9Sstevel@tonic-gate 	head->node = root;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start node walking from node %s\n",
796*7c478bd9Sstevel@tonic-gate 	    di_node_name(root)));
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 	while (head != NULL)
799*7c478bd9Sstevel@tonic-gate 		walk_one_node(&head, flag, arg, node_callback);
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	return (0);
802*7c478bd9Sstevel@tonic-gate }
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate /*
805*7c478bd9Sstevel@tonic-gate  * Internal library function:
806*7c478bd9Sstevel@tonic-gate  *   Invoke callback for each minor on the minor list of first node
807*7c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
808*7c478bd9Sstevel@tonic-gate  *
809*7c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
810*7c478bd9Sstevel@tonic-gate  *   first mode.
811*7c478bd9Sstevel@tonic-gate  */
812*7c478bd9Sstevel@tonic-gate static void
813*7c478bd9Sstevel@tonic-gate walk_one_minor_list(struct node_list **headp, const char *desired_type,
814*7c478bd9Sstevel@tonic-gate 	uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
815*7c478bd9Sstevel@tonic-gate {
816*7c478bd9Sstevel@tonic-gate 	int ddm_type;
817*7c478bd9Sstevel@tonic-gate 	int action = DI_WALK_CONTINUE;
818*7c478bd9Sstevel@tonic-gate 	char *node_type;
819*7c478bd9Sstevel@tonic-gate 	di_minor_t minor = DI_MINOR_NIL;
820*7c478bd9Sstevel@tonic-gate 	di_node_t node = (*headp)->node;
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
823*7c478bd9Sstevel@tonic-gate 		ddm_type = di_minor_type(minor);
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 		if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
826*7c478bd9Sstevel@tonic-gate 			continue;
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 		if ((ddm_type == DDM_INTERNAL_PATH) &&
829*7c478bd9Sstevel@tonic-gate 		    !(flag & DI_CHECK_INTERNAL_PATH))
830*7c478bd9Sstevel@tonic-gate 			continue;
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 		node_type = di_minor_nodetype(minor);
833*7c478bd9Sstevel@tonic-gate 		if ((desired_type != NULL) && ((node_type == NULL) ||
834*7c478bd9Sstevel@tonic-gate 		    strncmp(desired_type, node_type, strlen(desired_type))
835*7c478bd9Sstevel@tonic-gate 		    != 0))
836*7c478bd9Sstevel@tonic-gate 			continue;
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 		if ((action = callback(node, minor, arg)) ==
839*7c478bd9Sstevel@tonic-gate 		    DI_WALK_TERMINATE) {
840*7c478bd9Sstevel@tonic-gate 			break;
841*7c478bd9Sstevel@tonic-gate 		}
842*7c478bd9Sstevel@tonic-gate 	}
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
845*7c478bd9Sstevel@tonic-gate }
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate int
848*7c478bd9Sstevel@tonic-gate di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
849*7c478bd9Sstevel@tonic-gate 	int (*minor_callback)(di_node_t, di_minor_t, void *))
850*7c478bd9Sstevel@tonic-gate {
851*7c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
854*7c478bd9Sstevel@tonic-gate 	char *path = di_devfs_path(root);
855*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking minor nodes under %s\n", path));
856*7c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
857*7c478bd9Sstevel@tonic-gate #endif
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	if (root == NULL) {
860*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
861*7c478bd9Sstevel@tonic-gate 		return (-1);
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
865*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
866*7c478bd9Sstevel@tonic-gate 		return (-1);
867*7c478bd9Sstevel@tonic-gate 	}
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	head->next = NULL;
870*7c478bd9Sstevel@tonic-gate 	head->node = root;
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start minor walking from node %s\n",
873*7c478bd9Sstevel@tonic-gate 		di_node_name(root)));
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 	while (head != NULL)
876*7c478bd9Sstevel@tonic-gate 		walk_one_minor_list(&head, minor_type, flag, arg,
877*7c478bd9Sstevel@tonic-gate 		    minor_callback);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	return (0);
880*7c478bd9Sstevel@tonic-gate }
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate /*
883*7c478bd9Sstevel@tonic-gate  * generic node parameters
884*7c478bd9Sstevel@tonic-gate  *   Calling these routines always succeeds.
885*7c478bd9Sstevel@tonic-gate  */
886*7c478bd9Sstevel@tonic-gate char *
887*7c478bd9Sstevel@tonic-gate di_node_name(di_node_t node)
888*7c478bd9Sstevel@tonic-gate {
889*7c478bd9Sstevel@tonic-gate 	return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
890*7c478bd9Sstevel@tonic-gate }
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate /* returns NULL ptr or a valid ptr to non-NULL string */
893*7c478bd9Sstevel@tonic-gate char *
894*7c478bd9Sstevel@tonic-gate di_bus_addr(di_node_t node)
895*7c478bd9Sstevel@tonic-gate {
896*7c478bd9Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->address == 0)
899*7c478bd9Sstevel@tonic-gate 		return (NULL);
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->address));
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate char *
905*7c478bd9Sstevel@tonic-gate di_binding_name(di_node_t node)
906*7c478bd9Sstevel@tonic-gate {
907*7c478bd9Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->bind_name == 0)
910*7c478bd9Sstevel@tonic-gate 		return (NULL);
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->bind_name));
913*7c478bd9Sstevel@tonic-gate }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate int
916*7c478bd9Sstevel@tonic-gate di_compatible_names(di_node_t node, char **names)
917*7c478bd9Sstevel@tonic-gate {
918*7c478bd9Sstevel@tonic-gate 	char *c;
919*7c478bd9Sstevel@tonic-gate 	int len, size, entries = 0;
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->compat_names == 0) {
922*7c478bd9Sstevel@tonic-gate 		*names = NULL;
923*7c478bd9Sstevel@tonic-gate 		return (0);
924*7c478bd9Sstevel@tonic-gate 	}
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	*names = (caddr_t)node +
927*7c478bd9Sstevel@tonic-gate 		DI_NODE(node)->compat_names - DI_NODE(node)->self;
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	c = *names;
930*7c478bd9Sstevel@tonic-gate 	len = DI_NODE(node)->compat_length;
931*7c478bd9Sstevel@tonic-gate 	while (len > 0) {
932*7c478bd9Sstevel@tonic-gate 		entries++;
933*7c478bd9Sstevel@tonic-gate 		size = strlen(c) + 1;
934*7c478bd9Sstevel@tonic-gate 		len -= size;
935*7c478bd9Sstevel@tonic-gate 		c += size;
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	return (entries);
939*7c478bd9Sstevel@tonic-gate }
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate int
942*7c478bd9Sstevel@tonic-gate di_instance(di_node_t node)
943*7c478bd9Sstevel@tonic-gate {
944*7c478bd9Sstevel@tonic-gate 	return (DI_NODE(node)->instance);
945*7c478bd9Sstevel@tonic-gate }
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate /*
948*7c478bd9Sstevel@tonic-gate  * XXX: emulate the return value of the old implementation
949*7c478bd9Sstevel@tonic-gate  * using info from devi_node_class and devi_node_attributes.
950*7c478bd9Sstevel@tonic-gate  */
951*7c478bd9Sstevel@tonic-gate int
952*7c478bd9Sstevel@tonic-gate di_nodeid(di_node_t node)
953*7c478bd9Sstevel@tonic-gate {
954*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->node_class == DDI_NC_PROM)
955*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_NODEID);
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->attributes & DDI_PERSISTENT)
958*7c478bd9Sstevel@tonic-gate 		return (DI_SID_NODEID);
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	return (DI_PSEUDO_NODEID);
961*7c478bd9Sstevel@tonic-gate }
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate uint_t
964*7c478bd9Sstevel@tonic-gate di_state(di_node_t node)
965*7c478bd9Sstevel@tonic-gate {
966*7c478bd9Sstevel@tonic-gate 	uint_t result = 0;
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	if (di_node_state(node) < DS_ATTACHED)
969*7c478bd9Sstevel@tonic-gate 		result |= DI_DRIVER_DETACHED;
970*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
971*7c478bd9Sstevel@tonic-gate 		result |= DI_DEVICE_OFFLINE;
972*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
973*7c478bd9Sstevel@tonic-gate 		result |= DI_DEVICE_OFFLINE;
974*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
975*7c478bd9Sstevel@tonic-gate 		result |= DI_BUS_QUIESCED;
976*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_DOWN)
977*7c478bd9Sstevel@tonic-gate 		result |= DI_BUS_DOWN;
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	return (result);
980*7c478bd9Sstevel@tonic-gate }
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate ddi_node_state_t
983*7c478bd9Sstevel@tonic-gate di_node_state(di_node_t node)
984*7c478bd9Sstevel@tonic-gate {
985*7c478bd9Sstevel@tonic-gate 	return (DI_NODE(node)->node_state);
986*7c478bd9Sstevel@tonic-gate }
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate ddi_devid_t
989*7c478bd9Sstevel@tonic-gate di_devid(di_node_t node)
990*7c478bd9Sstevel@tonic-gate {
991*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->devid == 0)
992*7c478bd9Sstevel@tonic-gate 		return (NULL);
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	return ((ddi_devid_t)((caddr_t)node +
995*7c478bd9Sstevel@tonic-gate 	    DI_NODE(node)->devid - DI_NODE(node)->self));
996*7c478bd9Sstevel@tonic-gate }
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate int
999*7c478bd9Sstevel@tonic-gate di_driver_major(di_node_t node)
1000*7c478bd9Sstevel@tonic-gate {
1001*7c478bd9Sstevel@tonic-gate 	int major;
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
1004*7c478bd9Sstevel@tonic-gate 	if (major < 0)
1005*7c478bd9Sstevel@tonic-gate 		return (-1);
1006*7c478bd9Sstevel@tonic-gate 	return (major);
1007*7c478bd9Sstevel@tonic-gate }
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate char *
1010*7c478bd9Sstevel@tonic-gate di_driver_name(di_node_t node)
1011*7c478bd9Sstevel@tonic-gate {
1012*7c478bd9Sstevel@tonic-gate 	int major;
1013*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1014*7c478bd9Sstevel@tonic-gate 	struct di_devnm *devnm;
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
1017*7c478bd9Sstevel@tonic-gate 	if (major < 0)
1018*7c478bd9Sstevel@tonic-gate 		return (NULL);
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
1021*7c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	if (devnm[major].name)
1024*7c478bd9Sstevel@tonic-gate 		return (pa + devnm[major].name);
1025*7c478bd9Sstevel@tonic-gate 	else
1026*7c478bd9Sstevel@tonic-gate 		return (NULL);
1027*7c478bd9Sstevel@tonic-gate }
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate uint_t
1030*7c478bd9Sstevel@tonic-gate di_driver_ops(di_node_t node)
1031*7c478bd9Sstevel@tonic-gate {
1032*7c478bd9Sstevel@tonic-gate 	int major;
1033*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1034*7c478bd9Sstevel@tonic-gate 	struct di_devnm *devnm;
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
1037*7c478bd9Sstevel@tonic-gate 	if (major < 0)
1038*7c478bd9Sstevel@tonic-gate 		return (0);
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
1041*7c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	return (devnm[major].ops);
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate /*
1047*7c478bd9Sstevel@tonic-gate  * returns the length of the path, caller must free memory
1048*7c478bd9Sstevel@tonic-gate  */
1049*7c478bd9Sstevel@tonic-gate char *
1050*7c478bd9Sstevel@tonic-gate di_devfs_path(di_node_t node)
1051*7c478bd9Sstevel@tonic-gate {
1052*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1053*7c478bd9Sstevel@tonic-gate 	di_node_t parent;
1054*7c478bd9Sstevel@tonic-gate 	int depth = 0, len = 0;
1055*7c478bd9Sstevel@tonic-gate 	char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH];
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
1058*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1059*7c478bd9Sstevel@tonic-gate 		return (NULL);
1060*7c478bd9Sstevel@tonic-gate 	}
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 	/*
1063*7c478bd9Sstevel@tonic-gate 	 * trace back to root, note the node_name & address
1064*7c478bd9Sstevel@tonic-gate 	 */
1065*7c478bd9Sstevel@tonic-gate 	while ((parent = di_parent_node(node)) != DI_NODE_NIL) {
1066*7c478bd9Sstevel@tonic-gate 		name[depth] = di_node_name(node);
1067*7c478bd9Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;		/* 1 for '/' */
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 		if ((addr[depth] = di_bus_addr(node)) != NULL)
1070*7c478bd9Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;	/* 1 for '@' */
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 		node = parent;
1073*7c478bd9Sstevel@tonic-gate 		depth++;
1074*7c478bd9Sstevel@tonic-gate 	}
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	/*
1077*7c478bd9Sstevel@tonic-gate 	 * get the path to the root of snapshot
1078*7c478bd9Sstevel@tonic-gate 	 */
1079*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
1080*7c478bd9Sstevel@tonic-gate 	name[depth] = DI_ALL(pa)->root_path;
1081*7c478bd9Sstevel@tonic-gate 	len += strlen(name[depth]) + 1;
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 	/*
1084*7c478bd9Sstevel@tonic-gate 	 * allocate buffer and assemble path
1085*7c478bd9Sstevel@tonic-gate 	 */
1086*7c478bd9Sstevel@tonic-gate 	if ((buf = malloc(len)) == NULL) {
1087*7c478bd9Sstevel@tonic-gate 		return (NULL);
1088*7c478bd9Sstevel@tonic-gate 	}
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, name[depth]);
1091*7c478bd9Sstevel@tonic-gate 	len = strlen(buf);
1092*7c478bd9Sstevel@tonic-gate 	if (buf[len - 1] == '/')
1093*7c478bd9Sstevel@tonic-gate 		len--;	/* delete trailing '/' */
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	while (depth) {
1096*7c478bd9Sstevel@tonic-gate 		depth--;
1097*7c478bd9Sstevel@tonic-gate 		buf[len] = '/';
1098*7c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, name[depth]);
1099*7c478bd9Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;
1100*7c478bd9Sstevel@tonic-gate 		if (addr[depth] && addr[depth][0] != '\0') {
1101*7c478bd9Sstevel@tonic-gate 			buf[len] = '@';
1102*7c478bd9Sstevel@tonic-gate 			(void) strcpy(buf + len + 1, addr[depth]);
1103*7c478bd9Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;
1104*7c478bd9Sstevel@tonic-gate 		}
1105*7c478bd9Sstevel@tonic-gate 	}
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 	return (buf);
1108*7c478bd9Sstevel@tonic-gate }
1109*7c478bd9Sstevel@tonic-gate 
1110*7c478bd9Sstevel@tonic-gate char *
1111*7c478bd9Sstevel@tonic-gate di_devfs_minor_path(di_minor_t minor)
1112*7c478bd9Sstevel@tonic-gate {
1113*7c478bd9Sstevel@tonic-gate 	di_node_t	node;
1114*7c478bd9Sstevel@tonic-gate 	char		*full_path, *name, *path;
1115*7c478bd9Sstevel@tonic-gate 	int		full_path_len;
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
1118*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1119*7c478bd9Sstevel@tonic-gate 		return (NULL);
1120*7c478bd9Sstevel@tonic-gate 	}
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	name = di_minor_name(minor);
1123*7c478bd9Sstevel@tonic-gate 	node = di_minor_devinfo(minor);
1124*7c478bd9Sstevel@tonic-gate 	path = di_devfs_path(node);
1125*7c478bd9Sstevel@tonic-gate 	if (path == NULL)
1126*7c478bd9Sstevel@tonic-gate 		return (NULL);
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	/* make the full path to the device minor node */
1129*7c478bd9Sstevel@tonic-gate 	full_path_len = strlen(path) + strlen(name) + 2;
1130*7c478bd9Sstevel@tonic-gate 	full_path = (char *)calloc(1, full_path_len);
1131*7c478bd9Sstevel@tonic-gate 	if (full_path != NULL)
1132*7c478bd9Sstevel@tonic-gate 		(void) snprintf(full_path, full_path_len, "%s:%s", path, name);
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
1135*7c478bd9Sstevel@tonic-gate 	return (full_path);
1136*7c478bd9Sstevel@tonic-gate }
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate void
1139*7c478bd9Sstevel@tonic-gate di_devfs_path_free(char *buf)
1140*7c478bd9Sstevel@tonic-gate {
1141*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
1142*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
1143*7c478bd9Sstevel@tonic-gate 		return;
1144*7c478bd9Sstevel@tonic-gate 	}
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate 	free(buf);
1147*7c478bd9Sstevel@tonic-gate }
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate /* minor data access */
1150*7c478bd9Sstevel@tonic-gate di_minor_t
1151*7c478bd9Sstevel@tonic-gate di_minor_next(di_node_t node, di_minor_t minor)
1152*7c478bd9Sstevel@tonic-gate {
1153*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	/*
1156*7c478bd9Sstevel@tonic-gate 	 * paranoid error checking
1157*7c478bd9Sstevel@tonic-gate 	 */
1158*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
1159*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1160*7c478bd9Sstevel@tonic-gate 		return (DI_MINOR_NIL);
1161*7c478bd9Sstevel@tonic-gate 	}
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 	/*
1164*7c478bd9Sstevel@tonic-gate 	 * minor is not NIL
1165*7c478bd9Sstevel@tonic-gate 	 */
1166*7c478bd9Sstevel@tonic-gate 	if (minor != DI_MINOR_NIL) {
1167*7c478bd9Sstevel@tonic-gate 		if (DI_MINOR(minor)->next != 0)
1168*7c478bd9Sstevel@tonic-gate 			return ((di_minor_t)((void *)((caddr_t)minor -
1169*7c478bd9Sstevel@tonic-gate 			    DI_MINOR(minor)->self + DI_MINOR(minor)->next)));
1170*7c478bd9Sstevel@tonic-gate 		else {
1171*7c478bd9Sstevel@tonic-gate 			errno = ENXIO;
1172*7c478bd9Sstevel@tonic-gate 			return (DI_MINOR_NIL);
1173*7c478bd9Sstevel@tonic-gate 		}
1174*7c478bd9Sstevel@tonic-gate 	}
1175*7c478bd9Sstevel@tonic-gate 
1176*7c478bd9Sstevel@tonic-gate 	/*
1177*7c478bd9Sstevel@tonic-gate 	 * minor is NIL-->caller asks for first minor node
1178*7c478bd9Sstevel@tonic-gate 	 */
1179*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->minor_data != 0) {
1180*7c478bd9Sstevel@tonic-gate 		return (DI_MINOR((caddr_t)node - DI_NODE(node)->self +
1181*7c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->minor_data));
1182*7c478bd9Sstevel@tonic-gate 	}
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	/*
1185*7c478bd9Sstevel@tonic-gate 	 * no minor data-->check if snapshot includes minor data
1186*7c478bd9Sstevel@tonic-gate 	 *	in order to set the correct errno
1187*7c478bd9Sstevel@tonic-gate 	 */
1188*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
1189*7c478bd9Sstevel@tonic-gate 	if (DINFOMINOR & DI_ALL(pa)->command)
1190*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1191*7c478bd9Sstevel@tonic-gate 	else
1192*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 	return (DI_MINOR_NIL);
1195*7c478bd9Sstevel@tonic-gate }
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate /* private interface for dealing with alias minor link generation */
1198*7c478bd9Sstevel@tonic-gate di_node_t
1199*7c478bd9Sstevel@tonic-gate di_minor_devinfo(di_minor_t minor)
1200*7c478bd9Sstevel@tonic-gate {
1201*7c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
1202*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1203*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1204*7c478bd9Sstevel@tonic-gate 	}
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
1207*7c478bd9Sstevel@tonic-gate 	    DI_MINOR(minor)->node));
1208*7c478bd9Sstevel@tonic-gate }
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate ddi_minor_type
1211*7c478bd9Sstevel@tonic-gate di_minor_type(di_minor_t minor)
1212*7c478bd9Sstevel@tonic-gate {
1213*7c478bd9Sstevel@tonic-gate 	return (DI_MINOR(minor)->type);
1214*7c478bd9Sstevel@tonic-gate }
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate char *
1217*7c478bd9Sstevel@tonic-gate di_minor_name(di_minor_t minor)
1218*7c478bd9Sstevel@tonic-gate {
1219*7c478bd9Sstevel@tonic-gate 	if (DI_MINOR(minor)->name == 0)
1220*7c478bd9Sstevel@tonic-gate 		return (NULL);
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
1223*7c478bd9Sstevel@tonic-gate }
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate dev_t
1226*7c478bd9Sstevel@tonic-gate di_minor_devt(di_minor_t minor)
1227*7c478bd9Sstevel@tonic-gate {
1228*7c478bd9Sstevel@tonic-gate 	return (makedev(DI_MINOR(minor)->dev_major,
1229*7c478bd9Sstevel@tonic-gate 		DI_MINOR(minor)->dev_minor));
1230*7c478bd9Sstevel@tonic-gate }
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate int
1233*7c478bd9Sstevel@tonic-gate di_minor_spectype(di_minor_t minor)
1234*7c478bd9Sstevel@tonic-gate {
1235*7c478bd9Sstevel@tonic-gate 	return (DI_MINOR(minor)->spec_type);
1236*7c478bd9Sstevel@tonic-gate }
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate char *
1239*7c478bd9Sstevel@tonic-gate di_minor_nodetype(di_minor_t minor)
1240*7c478bd9Sstevel@tonic-gate {
1241*7c478bd9Sstevel@tonic-gate 	if (DI_MINOR(minor)->node_type == 0)
1242*7c478bd9Sstevel@tonic-gate 		return (NULL);
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	return ((caddr_t)minor -
1245*7c478bd9Sstevel@tonic-gate 		DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
1246*7c478bd9Sstevel@tonic-gate }
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate /*
1249*7c478bd9Sstevel@tonic-gate  * Single public interface for accessing software properties
1250*7c478bd9Sstevel@tonic-gate  */
1251*7c478bd9Sstevel@tonic-gate di_prop_t
1252*7c478bd9Sstevel@tonic-gate di_prop_next(di_node_t node, di_prop_t prop)
1253*7c478bd9Sstevel@tonic-gate {
1254*7c478bd9Sstevel@tonic-gate 	int list = DI_PROP_DRV_LIST;
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	/*
1257*7c478bd9Sstevel@tonic-gate 	 * paranoid check
1258*7c478bd9Sstevel@tonic-gate 	 */
1259*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
1260*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1261*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
1262*7c478bd9Sstevel@tonic-gate 	}
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 	/*
1265*7c478bd9Sstevel@tonic-gate 	 * Find which prop list we are at
1266*7c478bd9Sstevel@tonic-gate 	 */
1267*7c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL)
1268*7c478bd9Sstevel@tonic-gate 		list = DI_PROP(prop)->prop_list;
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 	do {
1271*7c478bd9Sstevel@tonic-gate 		switch (list++) {
1272*7c478bd9Sstevel@tonic-gate 		case DI_PROP_DRV_LIST:
1273*7c478bd9Sstevel@tonic-gate 			prop = di_prop_drv_next(node, prop);
1274*7c478bd9Sstevel@tonic-gate 			break;
1275*7c478bd9Sstevel@tonic-gate 		case DI_PROP_SYS_LIST:
1276*7c478bd9Sstevel@tonic-gate 			prop = di_prop_sys_next(node, prop);
1277*7c478bd9Sstevel@tonic-gate 			break;
1278*7c478bd9Sstevel@tonic-gate 		case DI_PROP_GLB_LIST:
1279*7c478bd9Sstevel@tonic-gate 			prop = di_prop_global_next(node, prop);
1280*7c478bd9Sstevel@tonic-gate 			break;
1281*7c478bd9Sstevel@tonic-gate 		case DI_PROP_HW_LIST:
1282*7c478bd9Sstevel@tonic-gate 			prop = di_prop_hw_next(node, prop);
1283*7c478bd9Sstevel@tonic-gate 			break;
1284*7c478bd9Sstevel@tonic-gate 		default:	/* shouldn't happen */
1285*7c478bd9Sstevel@tonic-gate 			errno = EFAULT;
1286*7c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
1287*7c478bd9Sstevel@tonic-gate 		}
1288*7c478bd9Sstevel@tonic-gate 	} while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	return (prop);
1291*7c478bd9Sstevel@tonic-gate }
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate dev_t
1294*7c478bd9Sstevel@tonic-gate di_prop_devt(di_prop_t prop)
1295*7c478bd9Sstevel@tonic-gate {
1296*7c478bd9Sstevel@tonic-gate 	return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
1297*7c478bd9Sstevel@tonic-gate }
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate char *
1300*7c478bd9Sstevel@tonic-gate di_prop_name(di_prop_t prop)
1301*7c478bd9Sstevel@tonic-gate {
1302*7c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_name == 0)
1303*7c478bd9Sstevel@tonic-gate 		return (NULL);
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
1306*7c478bd9Sstevel@tonic-gate }
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate int
1309*7c478bd9Sstevel@tonic-gate di_prop_type(di_prop_t prop)
1310*7c478bd9Sstevel@tonic-gate {
1311*7c478bd9Sstevel@tonic-gate 	uint_t flags = DI_PROP(prop)->prop_flags;
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_UNDEF_IT)
1314*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNDEF_IT);
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
1317*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_BOOLEAN);
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
1320*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNKNOWN);
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT)
1323*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT);
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT64)
1326*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT64);
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_STRING)
1329*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_STRING);
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_BYTE)
1332*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_BYTE);
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	/*
1335*7c478bd9Sstevel@tonic-gate 	 * Shouldn't get here. In case we do, return unknown type.
1336*7c478bd9Sstevel@tonic-gate 	 *
1337*7c478bd9Sstevel@tonic-gate 	 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
1338*7c478bd9Sstevel@tonic-gate 	 *	to add DI_PROP_TYPE_COMPOSITE.
1339*7c478bd9Sstevel@tonic-gate 	 */
1340*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
1343*7c478bd9Sstevel@tonic-gate }
1344*7c478bd9Sstevel@tonic-gate 
1345*7c478bd9Sstevel@tonic-gate /*
1346*7c478bd9Sstevel@tonic-gate  * Extract type-specific values of an property
1347*7c478bd9Sstevel@tonic-gate  */
1348*7c478bd9Sstevel@tonic-gate extern int di_prop_decode_common(void *prop_data, int len,
1349*7c478bd9Sstevel@tonic-gate 	int ddi_type, int prom);
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate int
1352*7c478bd9Sstevel@tonic-gate di_prop_ints(di_prop_t prop, int **prop_data)
1353*7c478bd9Sstevel@tonic-gate {
1354*7c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
1355*7c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
1358*7c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1359*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1360*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1361*7c478bd9Sstevel@tonic-gate 		return (-1);
1362*7c478bd9Sstevel@tonic-gate 	}
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1365*7c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
1368*7c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
1369*7c478bd9Sstevel@tonic-gate }
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate int
1372*7c478bd9Sstevel@tonic-gate di_prop_int64(di_prop_t prop, int64_t **prop_data)
1373*7c478bd9Sstevel@tonic-gate {
1374*7c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
1375*7c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
1376*7c478bd9Sstevel@tonic-gate 
1377*7c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
1378*7c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1379*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1380*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1381*7c478bd9Sstevel@tonic-gate 		return (-1);
1382*7c478bd9Sstevel@tonic-gate 	}
1383*7c478bd9Sstevel@tonic-gate 
1384*7c478bd9Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1385*7c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
1388*7c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
1389*7c478bd9Sstevel@tonic-gate }
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate int
1392*7c478bd9Sstevel@tonic-gate di_prop_strings(di_prop_t prop, char **prop_data)
1393*7c478bd9Sstevel@tonic-gate {
1394*7c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
1395*7c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
1396*7c478bd9Sstevel@tonic-gate 
1397*7c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
1398*7c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1399*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1400*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1401*7c478bd9Sstevel@tonic-gate 		return (-1);
1402*7c478bd9Sstevel@tonic-gate 	}
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
1405*7c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
1408*7c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
1409*7c478bd9Sstevel@tonic-gate }
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate int
1412*7c478bd9Sstevel@tonic-gate di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
1413*7c478bd9Sstevel@tonic-gate {
1414*7c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
1415*7c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
1418*7c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1419*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1420*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1421*7c478bd9Sstevel@tonic-gate 		return (-1);
1422*7c478bd9Sstevel@tonic-gate 	}
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
1425*7c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
1428*7c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
1429*7c478bd9Sstevel@tonic-gate }
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate /*
1432*7c478bd9Sstevel@tonic-gate  * returns 1 for match, 0 for no match
1433*7c478bd9Sstevel@tonic-gate  */
1434*7c478bd9Sstevel@tonic-gate static int
1435*7c478bd9Sstevel@tonic-gate match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
1436*7c478bd9Sstevel@tonic-gate {
1437*7c478bd9Sstevel@tonic-gate 	int prop_type;
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1440*7c478bd9Sstevel@tonic-gate 	if (di_prop_name(prop) == NULL) {
1441*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
1442*7c478bd9Sstevel@tonic-gate 		return (0);
1443*7c478bd9Sstevel@tonic-gate 	}
1444*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, di_prop_name(prop)) != 0)
1447*7c478bd9Sstevel@tonic-gate 		return (0);
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 	if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
1450*7c478bd9Sstevel@tonic-gate 		return (0);
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 	/*
1453*7c478bd9Sstevel@tonic-gate 	 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
1454*7c478bd9Sstevel@tonic-gate 	 */
1455*7c478bd9Sstevel@tonic-gate 	prop_type = di_prop_type(prop);
1456*7c478bd9Sstevel@tonic-gate 	if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) &&
1457*7c478bd9Sstevel@tonic-gate 	    (prop_type != DI_PROP_TYPE_BOOLEAN))
1458*7c478bd9Sstevel@tonic-gate 		return (0);
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate 	return (1);
1461*7c478bd9Sstevel@tonic-gate }
1462*7c478bd9Sstevel@tonic-gate 
1463*7c478bd9Sstevel@tonic-gate static di_prop_t
1464*7c478bd9Sstevel@tonic-gate di_prop_search(dev_t match_dev, di_node_t node, const char *name,
1465*7c478bd9Sstevel@tonic-gate     int type)
1466*7c478bd9Sstevel@tonic-gate {
1467*7c478bd9Sstevel@tonic-gate 	di_prop_t prop = DI_PROP_NIL;
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 	/*
1470*7c478bd9Sstevel@tonic-gate 	 * The check on match_dev follows ddi_prop_lookup_common().
1471*7c478bd9Sstevel@tonic-gate 	 * Other checks are libdevinfo specific implementation.
1472*7c478bd9Sstevel@tonic-gate 	 */
1473*7c478bd9Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
1474*7c478bd9Sstevel@tonic-gate 	    (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) {
1475*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1476*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
1477*7c478bd9Sstevel@tonic-gate 	}
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
1480*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n",
1481*7c478bd9Sstevel@tonic-gate 		    di_prop_name(prop), di_prop_devt(prop),
1482*7c478bd9Sstevel@tonic-gate 		    di_prop_type(prop)));
1483*7c478bd9Sstevel@tonic-gate 		if (match_prop(prop, match_dev, name, type))
1484*7c478bd9Sstevel@tonic-gate 			return (prop);
1485*7c478bd9Sstevel@tonic-gate 	}
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
1488*7c478bd9Sstevel@tonic-gate }
1489*7c478bd9Sstevel@tonic-gate 
1490*7c478bd9Sstevel@tonic-gate int
1491*7c478bd9Sstevel@tonic-gate di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
1492*7c478bd9Sstevel@tonic-gate 	int **prop_data)
1493*7c478bd9Sstevel@tonic-gate {
1494*7c478bd9Sstevel@tonic-gate 	di_prop_t prop;
1495*7c478bd9Sstevel@tonic-gate 
1496*7c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
1497*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
1498*7c478bd9Sstevel@tonic-gate 		return (-1);
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 	return (di_prop_ints(prop, (void *)prop_data));
1501*7c478bd9Sstevel@tonic-gate }
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate int
1504*7c478bd9Sstevel@tonic-gate di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
1505*7c478bd9Sstevel@tonic-gate 	int64_t **prop_data)
1506*7c478bd9Sstevel@tonic-gate {
1507*7c478bd9Sstevel@tonic-gate 	di_prop_t prop;
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
1510*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
1511*7c478bd9Sstevel@tonic-gate 		return (-1);
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 	return (di_prop_int64(prop, (void *)prop_data));
1514*7c478bd9Sstevel@tonic-gate }
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate int
1517*7c478bd9Sstevel@tonic-gate di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
1518*7c478bd9Sstevel@tonic-gate     char **prop_data)
1519*7c478bd9Sstevel@tonic-gate {
1520*7c478bd9Sstevel@tonic-gate 	di_prop_t prop;
1521*7c478bd9Sstevel@tonic-gate 
1522*7c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
1523*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
1524*7c478bd9Sstevel@tonic-gate 		return (-1);
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 	return (di_prop_strings(prop, (void *)prop_data));
1527*7c478bd9Sstevel@tonic-gate }
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate int
1530*7c478bd9Sstevel@tonic-gate di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
1531*7c478bd9Sstevel@tonic-gate 	uchar_t **prop_data)
1532*7c478bd9Sstevel@tonic-gate {
1533*7c478bd9Sstevel@tonic-gate 	di_prop_t prop;
1534*7c478bd9Sstevel@tonic-gate 
1535*7c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
1536*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
1537*7c478bd9Sstevel@tonic-gate 		return (-1);
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 	return (di_prop_bytes(prop, (void *)prop_data));
1540*7c478bd9Sstevel@tonic-gate }
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate /*
1543*7c478bd9Sstevel@tonic-gate  * Consolidation private property access functions
1544*7c478bd9Sstevel@tonic-gate  */
1545*7c478bd9Sstevel@tonic-gate enum prop_type {
1546*7c478bd9Sstevel@tonic-gate 	PROP_TYPE_DRV,
1547*7c478bd9Sstevel@tonic-gate 	PROP_TYPE_SYS,
1548*7c478bd9Sstevel@tonic-gate 	PROP_TYPE_GLOB,
1549*7c478bd9Sstevel@tonic-gate 	PROP_TYPE_HW
1550*7c478bd9Sstevel@tonic-gate };
1551*7c478bd9Sstevel@tonic-gate 
1552*7c478bd9Sstevel@tonic-gate static di_prop_t
1553*7c478bd9Sstevel@tonic-gate di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
1554*7c478bd9Sstevel@tonic-gate {
1555*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1556*7c478bd9Sstevel@tonic-gate 	di_off_t prop_off = 0;
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
1559*7c478bd9Sstevel@tonic-gate 		if (DI_PROP(prop)->next) {
1560*7c478bd9Sstevel@tonic-gate 			return (DI_PROP((caddr_t)prop -
1561*7c478bd9Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
1562*7c478bd9Sstevel@tonic-gate 		} else {
1563*7c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
1564*7c478bd9Sstevel@tonic-gate 		}
1565*7c478bd9Sstevel@tonic-gate 	}
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 	/*
1569*7c478bd9Sstevel@tonic-gate 	 * prop is NIL, caller asks for first property
1570*7c478bd9Sstevel@tonic-gate 	 */
1571*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
1572*7c478bd9Sstevel@tonic-gate 	switch (prop_type) {
1573*7c478bd9Sstevel@tonic-gate 	case PROP_TYPE_DRV:
1574*7c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->drv_prop;
1575*7c478bd9Sstevel@tonic-gate 		break;
1576*7c478bd9Sstevel@tonic-gate 	case PROP_TYPE_SYS:
1577*7c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->sys_prop;
1578*7c478bd9Sstevel@tonic-gate 		break;
1579*7c478bd9Sstevel@tonic-gate 	case PROP_TYPE_HW:
1580*7c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->hw_prop;
1581*7c478bd9Sstevel@tonic-gate 		break;
1582*7c478bd9Sstevel@tonic-gate 	case PROP_TYPE_GLOB:
1583*7c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->glob_prop;
1584*7c478bd9Sstevel@tonic-gate 		if (prop_off == -1) {
1585*7c478bd9Sstevel@tonic-gate 			/* no global property */
1586*7c478bd9Sstevel@tonic-gate 			prop_off = 0;
1587*7c478bd9Sstevel@tonic-gate 		} else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) {
1588*7c478bd9Sstevel@tonic-gate 			/* refer to devnames array */
1589*7c478bd9Sstevel@tonic-gate 			struct di_devnm *devnm = DI_DEVNM(pa +
1590*7c478bd9Sstevel@tonic-gate 			    DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major *
1591*7c478bd9Sstevel@tonic-gate 			    sizeof (struct di_devnm)));
1592*7c478bd9Sstevel@tonic-gate 			prop_off = devnm->global_prop;
1593*7c478bd9Sstevel@tonic-gate 		}
1594*7c478bd9Sstevel@tonic-gate 		break;
1595*7c478bd9Sstevel@tonic-gate 	}
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate 	if (prop_off) {
1598*7c478bd9Sstevel@tonic-gate 		return (DI_PROP(pa + prop_off));
1599*7c478bd9Sstevel@tonic-gate 	}
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate 	/*
1602*7c478bd9Sstevel@tonic-gate 	 * no prop found. Check the reason for not found
1603*7c478bd9Sstevel@tonic-gate 	 */
1604*7c478bd9Sstevel@tonic-gate 	if (DINFOPROP & DI_ALL(pa)->command)
1605*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1606*7c478bd9Sstevel@tonic-gate 	else
1607*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
1608*7c478bd9Sstevel@tonic-gate 
1609*7c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
1610*7c478bd9Sstevel@tonic-gate }
1611*7c478bd9Sstevel@tonic-gate 
1612*7c478bd9Sstevel@tonic-gate di_prop_t
1613*7c478bd9Sstevel@tonic-gate di_prop_drv_next(di_node_t node, di_prop_t prop)
1614*7c478bd9Sstevel@tonic-gate {
1615*7c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
1616*7c478bd9Sstevel@tonic-gate }
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate di_prop_t
1619*7c478bd9Sstevel@tonic-gate di_prop_sys_next(di_node_t node, di_prop_t prop)
1620*7c478bd9Sstevel@tonic-gate {
1621*7c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
1622*7c478bd9Sstevel@tonic-gate }
1623*7c478bd9Sstevel@tonic-gate 
1624*7c478bd9Sstevel@tonic-gate di_prop_t
1625*7c478bd9Sstevel@tonic-gate di_prop_global_next(di_node_t node, di_prop_t prop)
1626*7c478bd9Sstevel@tonic-gate {
1627*7c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
1628*7c478bd9Sstevel@tonic-gate }
1629*7c478bd9Sstevel@tonic-gate 
1630*7c478bd9Sstevel@tonic-gate di_prop_t
1631*7c478bd9Sstevel@tonic-gate di_prop_hw_next(di_node_t node, di_prop_t prop)
1632*7c478bd9Sstevel@tonic-gate {
1633*7c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_HW));
1634*7c478bd9Sstevel@tonic-gate }
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate int
1637*7c478bd9Sstevel@tonic-gate di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
1638*7c478bd9Sstevel@tonic-gate {
1639*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1640*7c478bd9Sstevel@tonic-gate 	if (prop == DI_PROP_NIL) {
1641*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1642*7c478bd9Sstevel@tonic-gate 		return (-1);
1643*7c478bd9Sstevel@tonic-gate 	}
1644*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1645*7c478bd9Sstevel@tonic-gate 
1646*7c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0) {
1647*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1648*7c478bd9Sstevel@tonic-gate 		return (0);
1649*7c478bd9Sstevel@tonic-gate 	}
1650*7c478bd9Sstevel@tonic-gate 
1651*7c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
1652*7c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1653*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1654*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1655*7c478bd9Sstevel@tonic-gate 		return (-1);
1656*7c478bd9Sstevel@tonic-gate 	}
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate 	/*
1659*7c478bd9Sstevel@tonic-gate 	 * No memory allocation.
1660*7c478bd9Sstevel@tonic-gate 	 */
1661*7c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
1662*7c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_data);
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 	return (DI_PROP(prop)->prop_len);
1665*7c478bd9Sstevel@tonic-gate }
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate /*
1668*7c478bd9Sstevel@tonic-gate  * Consolidation private interfaces for accessing I/O multipathing data
1669*7c478bd9Sstevel@tonic-gate  */
1670*7c478bd9Sstevel@tonic-gate di_path_t
1671*7c478bd9Sstevel@tonic-gate di_path_next_client(di_node_t node, di_path_t path)
1672*7c478bd9Sstevel@tonic-gate {
1673*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1674*7c478bd9Sstevel@tonic-gate 
1675*7c478bd9Sstevel@tonic-gate 	/*
1676*7c478bd9Sstevel@tonic-gate 	 * path is not NIL
1677*7c478bd9Sstevel@tonic-gate 	 */
1678*7c478bd9Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
1679*7c478bd9Sstevel@tonic-gate 		if (DI_PATH(path)->path_p_link != 0)
1680*7c478bd9Sstevel@tonic-gate 			return (DI_PATH((void *)((caddr_t)path -
1681*7c478bd9Sstevel@tonic-gate 			    DI_PATH(path)->self + DI_PATH(path)->path_p_link)));
1682*7c478bd9Sstevel@tonic-gate 		else {
1683*7c478bd9Sstevel@tonic-gate 			errno = ENXIO;
1684*7c478bd9Sstevel@tonic-gate 			return (DI_PATH_NIL);
1685*7c478bd9Sstevel@tonic-gate 		}
1686*7c478bd9Sstevel@tonic-gate 	}
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 	/*
1689*7c478bd9Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
1690*7c478bd9Sstevel@tonic-gate 	 */
1691*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_phci != 0) {
1692*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_INFO, "phci: returning %p\n", ((caddr_t)node -
1693*7c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
1694*7c478bd9Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
1695*7c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->multipath_phci));
1696*7c478bd9Sstevel@tonic-gate 	}
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 	/*
1699*7c478bd9Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
1700*7c478bd9Sstevel@tonic-gate 	 * to set errno properly.
1701*7c478bd9Sstevel@tonic-gate 	 */
1702*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
1703*7c478bd9Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
1704*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1705*7c478bd9Sstevel@tonic-gate 	else
1706*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
1707*7c478bd9Sstevel@tonic-gate 
1708*7c478bd9Sstevel@tonic-gate 	return (DI_PATH_NIL);
1709*7c478bd9Sstevel@tonic-gate }
1710*7c478bd9Sstevel@tonic-gate 
1711*7c478bd9Sstevel@tonic-gate di_path_t
1712*7c478bd9Sstevel@tonic-gate di_path_next_phci(di_node_t node, di_path_t path)
1713*7c478bd9Sstevel@tonic-gate {
1714*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate 	/*
1717*7c478bd9Sstevel@tonic-gate 	 * path is not NIL
1718*7c478bd9Sstevel@tonic-gate 	 */
1719*7c478bd9Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
1720*7c478bd9Sstevel@tonic-gate 		if (DI_PATH(path)->path_c_link != 0)
1721*7c478bd9Sstevel@tonic-gate 			return (DI_PATH((caddr_t)path - DI_PATH(path)->self
1722*7c478bd9Sstevel@tonic-gate 			    + DI_PATH(path)->path_c_link));
1723*7c478bd9Sstevel@tonic-gate 		else {
1724*7c478bd9Sstevel@tonic-gate 			errno = ENXIO;
1725*7c478bd9Sstevel@tonic-gate 			return (DI_PATH_NIL);
1726*7c478bd9Sstevel@tonic-gate 		}
1727*7c478bd9Sstevel@tonic-gate 	}
1728*7c478bd9Sstevel@tonic-gate 
1729*7c478bd9Sstevel@tonic-gate 	/*
1730*7c478bd9Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
1731*7c478bd9Sstevel@tonic-gate 	 */
1732*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_client != 0) {
1733*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_INFO, "client: returning %p\n", ((caddr_t)node -
1734*7c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
1735*7c478bd9Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
1736*7c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->multipath_client));
1737*7c478bd9Sstevel@tonic-gate 	}
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate 	/*
1740*7c478bd9Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
1741*7c478bd9Sstevel@tonic-gate 	 * to set errno properly.
1742*7c478bd9Sstevel@tonic-gate 	 */
1743*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
1744*7c478bd9Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
1745*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1746*7c478bd9Sstevel@tonic-gate 	else
1747*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate 	return (DI_PATH_NIL);
1750*7c478bd9Sstevel@tonic-gate }
1751*7c478bd9Sstevel@tonic-gate 
1752*7c478bd9Sstevel@tonic-gate /*
1753*7c478bd9Sstevel@tonic-gate  * XXX Obsolete wrapper to be removed. Won't work under multilevel.
1754*7c478bd9Sstevel@tonic-gate  */
1755*7c478bd9Sstevel@tonic-gate di_path_t
1756*7c478bd9Sstevel@tonic-gate di_path_next(di_node_t node, di_path_t path)
1757*7c478bd9Sstevel@tonic-gate {
1758*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
1759*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1760*7c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
1761*7c478bd9Sstevel@tonic-gate 	}
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_client) {
1764*7c478bd9Sstevel@tonic-gate 		return (di_path_next_phci(node, path));
1765*7c478bd9Sstevel@tonic-gate 	} else if (DI_NODE(node)->multipath_phci) {
1766*7c478bd9Sstevel@tonic-gate 		return (di_path_next_client(node, path));
1767*7c478bd9Sstevel@tonic-gate 	} else {
1768*7c478bd9Sstevel@tonic-gate 		/*
1769*7c478bd9Sstevel@tonic-gate 		 * The node had multipathing data but didn't appear to be a
1770*7c478bd9Sstevel@tonic-gate 		 * phci *or* a client; probably a programmer error.
1771*7c478bd9Sstevel@tonic-gate 		 */
1772*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1773*7c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
1774*7c478bd9Sstevel@tonic-gate 	}
1775*7c478bd9Sstevel@tonic-gate }
1776*7c478bd9Sstevel@tonic-gate 
1777*7c478bd9Sstevel@tonic-gate di_path_state_t
1778*7c478bd9Sstevel@tonic-gate di_path_state(di_path_t path)
1779*7c478bd9Sstevel@tonic-gate {
1780*7c478bd9Sstevel@tonic-gate 	return ((di_path_state_t)DI_PATH(path)->path_state);
1781*7c478bd9Sstevel@tonic-gate }
1782*7c478bd9Sstevel@tonic-gate 
1783*7c478bd9Sstevel@tonic-gate char *
1784*7c478bd9Sstevel@tonic-gate di_path_addr(di_path_t path, char *buf)
1785*7c478bd9Sstevel@tonic-gate {
1786*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
1791*7c478bd9Sstevel@tonic-gate 	    MAXPATHLEN);
1792*7c478bd9Sstevel@tonic-gate 	return (buf);
1793*7c478bd9Sstevel@tonic-gate }
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate di_node_t
1796*7c478bd9Sstevel@tonic-gate di_path_client_node(di_path_t path)
1797*7c478bd9Sstevel@tonic-gate {
1798*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
1801*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1802*7c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
1803*7c478bd9Sstevel@tonic-gate 	}
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_client) {
1810*7c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_client));
1811*7c478bd9Sstevel@tonic-gate 	}
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate 	/*
1814*7c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
1815*7c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
1816*7c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
1817*7c478bd9Sstevel@tonic-gate 	 */
1818*7c478bd9Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
1819*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
1820*7c478bd9Sstevel@tonic-gate 	else
1821*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
1824*7c478bd9Sstevel@tonic-gate }
1825*7c478bd9Sstevel@tonic-gate 
1826*7c478bd9Sstevel@tonic-gate di_node_t
1827*7c478bd9Sstevel@tonic-gate di_path_phci_node(di_path_t path)
1828*7c478bd9Sstevel@tonic-gate {
1829*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
1832*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1833*7c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
1834*7c478bd9Sstevel@tonic-gate 	}
1835*7c478bd9Sstevel@tonic-gate 
1836*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_phci) {
1841*7c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_phci));
1842*7c478bd9Sstevel@tonic-gate 	}
1843*7c478bd9Sstevel@tonic-gate 
1844*7c478bd9Sstevel@tonic-gate 	/*
1845*7c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
1846*7c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
1847*7c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
1848*7c478bd9Sstevel@tonic-gate 	 */
1849*7c478bd9Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
1850*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
1851*7c478bd9Sstevel@tonic-gate 	else
1852*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
1855*7c478bd9Sstevel@tonic-gate }
1856*7c478bd9Sstevel@tonic-gate 
1857*7c478bd9Sstevel@tonic-gate di_path_prop_t
1858*7c478bd9Sstevel@tonic-gate di_path_prop_next(di_path_t path, di_path_prop_t prop)
1859*7c478bd9Sstevel@tonic-gate {
1860*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
1861*7c478bd9Sstevel@tonic-gate 
1862*7c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
1863*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1864*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
1865*7c478bd9Sstevel@tonic-gate 	}
1866*7c478bd9Sstevel@tonic-gate 
1867*7c478bd9Sstevel@tonic-gate 	/*
1868*7c478bd9Sstevel@tonic-gate 	 * prop is not NIL
1869*7c478bd9Sstevel@tonic-gate 	 */
1870*7c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
1871*7c478bd9Sstevel@tonic-gate 		if (DI_PROP(prop)->next != 0)
1872*7c478bd9Sstevel@tonic-gate 			return (DI_PATHPROP((caddr_t)prop -
1873*7c478bd9Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
1874*7c478bd9Sstevel@tonic-gate 		else {
1875*7c478bd9Sstevel@tonic-gate 			errno = ENXIO;
1876*7c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
1877*7c478bd9Sstevel@tonic-gate 		}
1878*7c478bd9Sstevel@tonic-gate 	}
1879*7c478bd9Sstevel@tonic-gate 
1880*7c478bd9Sstevel@tonic-gate 	/*
1881*7c478bd9Sstevel@tonic-gate 	 * prop is NIL-->caller asks for first property
1882*7c478bd9Sstevel@tonic-gate 	 */
1883*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
1884*7c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_prop != 0) {
1885*7c478bd9Sstevel@tonic-gate 		return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
1886*7c478bd9Sstevel@tonic-gate 	}
1887*7c478bd9Sstevel@tonic-gate 
1888*7c478bd9Sstevel@tonic-gate 	/*
1889*7c478bd9Sstevel@tonic-gate 	 * no property data-->check if snapshot includes props
1890*7c478bd9Sstevel@tonic-gate 	 *	in order to set the correct errno
1891*7c478bd9Sstevel@tonic-gate 	 */
1892*7c478bd9Sstevel@tonic-gate 	if (DINFOPROP & (DI_ALL(pa)->command))
1893*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1894*7c478bd9Sstevel@tonic-gate 	else
1895*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
1896*7c478bd9Sstevel@tonic-gate 
1897*7c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
1898*7c478bd9Sstevel@tonic-gate }
1899*7c478bd9Sstevel@tonic-gate 
1900*7c478bd9Sstevel@tonic-gate char *
1901*7c478bd9Sstevel@tonic-gate di_path_prop_name(di_path_prop_t prop)
1902*7c478bd9Sstevel@tonic-gate {
1903*7c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
1904*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
1905*7c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
1906*7c478bd9Sstevel@tonic-gate }
1907*7c478bd9Sstevel@tonic-gate 
1908*7c478bd9Sstevel@tonic-gate int
1909*7c478bd9Sstevel@tonic-gate di_path_prop_len(di_path_prop_t prop)
1910*7c478bd9Sstevel@tonic-gate {
1911*7c478bd9Sstevel@tonic-gate 	return (DI_PATHPROP(prop)->prop_len);
1912*7c478bd9Sstevel@tonic-gate }
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate int
1915*7c478bd9Sstevel@tonic-gate di_path_prop_type(di_path_prop_t prop)
1916*7c478bd9Sstevel@tonic-gate {
1917*7c478bd9Sstevel@tonic-gate 	switch (DI_PATHPROP(prop)->prop_type) {
1918*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT:
1919*7c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT);
1920*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT64:
1921*7c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT64);
1922*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_BYTE:
1923*7c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_BYTE);
1924*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_STRING:
1925*7c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_STRING);
1926*7c478bd9Sstevel@tonic-gate 	}
1927*7c478bd9Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
1928*7c478bd9Sstevel@tonic-gate }
1929*7c478bd9Sstevel@tonic-gate 
1930*7c478bd9Sstevel@tonic-gate int
1931*7c478bd9Sstevel@tonic-gate di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
1932*7c478bd9Sstevel@tonic-gate {
1933*7c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
1934*7c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
1935*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1936*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1937*7c478bd9Sstevel@tonic-gate 		return (-1);
1938*7c478bd9Sstevel@tonic-gate 	}
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
1941*7c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
1944*7c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
1945*7c478bd9Sstevel@tonic-gate }
1946*7c478bd9Sstevel@tonic-gate 
1947*7c478bd9Sstevel@tonic-gate int
1948*7c478bd9Sstevel@tonic-gate di_path_prop_ints(di_path_prop_t prop, int **prop_data)
1949*7c478bd9Sstevel@tonic-gate {
1950*7c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
1951*7c478bd9Sstevel@tonic-gate 		return (0);
1952*7c478bd9Sstevel@tonic-gate 
1953*7c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
1954*7c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
1955*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1956*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1957*7c478bd9Sstevel@tonic-gate 		return (-1);
1958*7c478bd9Sstevel@tonic-gate 	}
1959*7c478bd9Sstevel@tonic-gate 
1960*7c478bd9Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
1961*7c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data));
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
1964*7c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
1965*7c478bd9Sstevel@tonic-gate }
1966*7c478bd9Sstevel@tonic-gate 
1967*7c478bd9Sstevel@tonic-gate int
1968*7c478bd9Sstevel@tonic-gate di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
1969*7c478bd9Sstevel@tonic-gate {
1970*7c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
1971*7c478bd9Sstevel@tonic-gate 		return (0);
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
1974*7c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
1975*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1976*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1977*7c478bd9Sstevel@tonic-gate 		return (-1);
1978*7c478bd9Sstevel@tonic-gate 	}
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop -
1981*7c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
1982*7c478bd9Sstevel@tonic-gate 
1983*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
1984*7c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
1985*7c478bd9Sstevel@tonic-gate }
1986*7c478bd9Sstevel@tonic-gate 
1987*7c478bd9Sstevel@tonic-gate int
1988*7c478bd9Sstevel@tonic-gate di_path_prop_strings(di_path_prop_t prop, char **prop_data)
1989*7c478bd9Sstevel@tonic-gate {
1990*7c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
1991*7c478bd9Sstevel@tonic-gate 		return (0);
1992*7c478bd9Sstevel@tonic-gate 
1993*7c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
1994*7c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
1995*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1996*7c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
1997*7c478bd9Sstevel@tonic-gate 		return (-1);
1998*7c478bd9Sstevel@tonic-gate 	}
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
2001*7c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
2002*7c478bd9Sstevel@tonic-gate 
2003*7c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
2004*7c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
2005*7c478bd9Sstevel@tonic-gate }
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate static di_path_prop_t
2008*7c478bd9Sstevel@tonic-gate di_path_prop_search(di_path_t path, const char *name, int type)
2009*7c478bd9Sstevel@tonic-gate {
2010*7c478bd9Sstevel@tonic-gate 	di_path_prop_t prop = DI_PROP_NIL;
2011*7c478bd9Sstevel@tonic-gate 
2012*7c478bd9Sstevel@tonic-gate 	/*
2013*7c478bd9Sstevel@tonic-gate 	 * Sanity check arguments
2014*7c478bd9Sstevel@tonic-gate 	 */
2015*7c478bd9Sstevel@tonic-gate 	if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
2016*7c478bd9Sstevel@tonic-gate 	    !DI_PROP_TYPE_VALID(type)) {
2017*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2018*7c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
2019*7c478bd9Sstevel@tonic-gate 	}
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 	while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
2022*7c478bd9Sstevel@tonic-gate 		int prop_type = di_path_prop_type(prop);
2023*7c478bd9Sstevel@tonic-gate 
2024*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
2025*7c478bd9Sstevel@tonic-gate 		    di_path_prop_name(prop), prop_type));
2026*7c478bd9Sstevel@tonic-gate 
2027*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, di_path_prop_name(prop)) != 0)
2028*7c478bd9Sstevel@tonic-gate 			continue;
2029*7c478bd9Sstevel@tonic-gate 
2030*7c478bd9Sstevel@tonic-gate 		if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
2031*7c478bd9Sstevel@tonic-gate 			continue;
2032*7c478bd9Sstevel@tonic-gate 
2033*7c478bd9Sstevel@tonic-gate 		return (prop);
2034*7c478bd9Sstevel@tonic-gate 	}
2035*7c478bd9Sstevel@tonic-gate 
2036*7c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
2037*7c478bd9Sstevel@tonic-gate }
2038*7c478bd9Sstevel@tonic-gate 
2039*7c478bd9Sstevel@tonic-gate int
2040*7c478bd9Sstevel@tonic-gate di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
2041*7c478bd9Sstevel@tonic-gate     uchar_t **prop_data)
2042*7c478bd9Sstevel@tonic-gate {
2043*7c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
2044*7c478bd9Sstevel@tonic-gate 
2045*7c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
2046*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
2047*7c478bd9Sstevel@tonic-gate 		return (-1);
2048*7c478bd9Sstevel@tonic-gate 
2049*7c478bd9Sstevel@tonic-gate 	return (di_path_prop_bytes(prop, prop_data));
2050*7c478bd9Sstevel@tonic-gate }
2051*7c478bd9Sstevel@tonic-gate 
2052*7c478bd9Sstevel@tonic-gate int
2053*7c478bd9Sstevel@tonic-gate di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
2054*7c478bd9Sstevel@tonic-gate     int **prop_data)
2055*7c478bd9Sstevel@tonic-gate {
2056*7c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
2059*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
2060*7c478bd9Sstevel@tonic-gate 		return (-1);
2061*7c478bd9Sstevel@tonic-gate 
2062*7c478bd9Sstevel@tonic-gate 	return (di_path_prop_ints(prop, prop_data));
2063*7c478bd9Sstevel@tonic-gate }
2064*7c478bd9Sstevel@tonic-gate 
2065*7c478bd9Sstevel@tonic-gate int
2066*7c478bd9Sstevel@tonic-gate di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
2067*7c478bd9Sstevel@tonic-gate     int64_t **prop_data)
2068*7c478bd9Sstevel@tonic-gate {
2069*7c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
2072*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
2073*7c478bd9Sstevel@tonic-gate 		return (-1);
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate 	return (di_path_prop_int64s(prop, prop_data));
2076*7c478bd9Sstevel@tonic-gate }
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
2079*7c478bd9Sstevel@tonic-gate     char **prop_data)
2080*7c478bd9Sstevel@tonic-gate {
2081*7c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
2082*7c478bd9Sstevel@tonic-gate 
2083*7c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
2084*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
2085*7c478bd9Sstevel@tonic-gate 		return (-1);
2086*7c478bd9Sstevel@tonic-gate 
2087*7c478bd9Sstevel@tonic-gate 	return (di_path_prop_strings(prop, prop_data));
2088*7c478bd9Sstevel@tonic-gate }
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 
2091*7c478bd9Sstevel@tonic-gate /*
2092*7c478bd9Sstevel@tonic-gate  * Consolidation private interfaces for private data
2093*7c478bd9Sstevel@tonic-gate  */
2094*7c478bd9Sstevel@tonic-gate void *
2095*7c478bd9Sstevel@tonic-gate di_parent_private_data(di_node_t node)
2096*7c478bd9Sstevel@tonic-gate {
2097*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
2098*7c478bd9Sstevel@tonic-gate 
2099*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == 0) {
2100*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2101*7c478bd9Sstevel@tonic-gate 		return (NULL);
2102*7c478bd9Sstevel@tonic-gate 	}
2103*7c478bd9Sstevel@tonic-gate 
2104*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == (di_off_t)-1) {
2105*7c478bd9Sstevel@tonic-gate 		/*
2106*7c478bd9Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
2107*7c478bd9Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
2108*7c478bd9Sstevel@tonic-gate 		 */
2109*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
2110*7c478bd9Sstevel@tonic-gate 		return (NULL);
2111*7c478bd9Sstevel@tonic-gate 	}
2112*7c478bd9Sstevel@tonic-gate 
2113*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
2114*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data)
2115*7c478bd9Sstevel@tonic-gate 		return (pa + DI_NODE(node)->parent_data);
2116*7c478bd9Sstevel@tonic-gate 
2117*7c478bd9Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
2118*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2119*7c478bd9Sstevel@tonic-gate 	else
2120*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
2121*7c478bd9Sstevel@tonic-gate 
2122*7c478bd9Sstevel@tonic-gate 	return (NULL);
2123*7c478bd9Sstevel@tonic-gate }
2124*7c478bd9Sstevel@tonic-gate 
2125*7c478bd9Sstevel@tonic-gate void *
2126*7c478bd9Sstevel@tonic-gate di_driver_private_data(di_node_t node)
2127*7c478bd9Sstevel@tonic-gate {
2128*7c478bd9Sstevel@tonic-gate 	caddr_t pa;
2129*7c478bd9Sstevel@tonic-gate 
2130*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == 0) {
2131*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2132*7c478bd9Sstevel@tonic-gate 		return (NULL);
2133*7c478bd9Sstevel@tonic-gate 	}
2134*7c478bd9Sstevel@tonic-gate 
2135*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == (di_off_t)-1) {
2136*7c478bd9Sstevel@tonic-gate 		/*
2137*7c478bd9Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
2138*7c478bd9Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
2139*7c478bd9Sstevel@tonic-gate 		 */
2140*7c478bd9Sstevel@tonic-gate 		errno = EFAULT;
2141*7c478bd9Sstevel@tonic-gate 		return (NULL);
2142*7c478bd9Sstevel@tonic-gate 	}
2143*7c478bd9Sstevel@tonic-gate 
2144*7c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
2145*7c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data)
2146*7c478bd9Sstevel@tonic-gate 		return (pa + DI_NODE(node)->driver_data);
2147*7c478bd9Sstevel@tonic-gate 
2148*7c478bd9Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
2149*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2150*7c478bd9Sstevel@tonic-gate 	else
2151*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate 	return (NULL);
2154*7c478bd9Sstevel@tonic-gate }
2155*7c478bd9Sstevel@tonic-gate 
2156*7c478bd9Sstevel@tonic-gate /*
2157*7c478bd9Sstevel@tonic-gate  * PROM property access
2158*7c478bd9Sstevel@tonic-gate  */
2159*7c478bd9Sstevel@tonic-gate 
2160*7c478bd9Sstevel@tonic-gate /*
2161*7c478bd9Sstevel@tonic-gate  * openprom driver stuff:
2162*7c478bd9Sstevel@tonic-gate  *	The maximum property length depends on the buffer size. We use
2163*7c478bd9Sstevel@tonic-gate  *	OPROMMAXPARAM defined in <sys/openpromio.h>
2164*7c478bd9Sstevel@tonic-gate  *
2165*7c478bd9Sstevel@tonic-gate  *	MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2166*7c478bd9Sstevel@tonic-gate  *	MAXVALSZ is maximum value size, which is whatever space left in buf
2167*7c478bd9Sstevel@tonic-gate  */
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate #define	OBP_MAXBUF	OPROMMAXPARAM - sizeof (int)
2170*7c478bd9Sstevel@tonic-gate #define	OBP_MAXPROPLEN	OBP_MAXBUF - OBP_MAXPROPNAME;
2171*7c478bd9Sstevel@tonic-gate 
2172*7c478bd9Sstevel@tonic-gate struct di_prom_prop {
2173*7c478bd9Sstevel@tonic-gate 	char *name;
2174*7c478bd9Sstevel@tonic-gate 	int len;
2175*7c478bd9Sstevel@tonic-gate 	uchar_t *data;
2176*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *next;	/* form a linked list */
2177*7c478bd9Sstevel@tonic-gate };
2178*7c478bd9Sstevel@tonic-gate 
2179*7c478bd9Sstevel@tonic-gate struct di_prom_handle { /* handle to prom */
2180*7c478bd9Sstevel@tonic-gate 	mutex_t lock;	/* synchronize access to openprom fd */
2181*7c478bd9Sstevel@tonic-gate 	int	fd;	/* /dev/openprom file descriptor */
2182*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *list;	/* linked list of prop */
2183*7c478bd9Sstevel@tonic-gate 	union {
2184*7c478bd9Sstevel@tonic-gate 		char buf[OPROMMAXPARAM];
2185*7c478bd9Sstevel@tonic-gate 		struct openpromio opp;
2186*7c478bd9Sstevel@tonic-gate 	} oppbuf;
2187*7c478bd9Sstevel@tonic-gate };
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate di_prom_handle_t
2190*7c478bd9Sstevel@tonic-gate di_prom_init()
2191*7c478bd9Sstevel@tonic-gate {
2192*7c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p;
2193*7c478bd9Sstevel@tonic-gate 
2194*7c478bd9Sstevel@tonic-gate 	if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
2195*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
2196*7c478bd9Sstevel@tonic-gate 
2197*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
2198*7c478bd9Sstevel@tonic-gate 
2199*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&p->lock, USYNC_THREAD, NULL);
2200*7c478bd9Sstevel@tonic-gate 	if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
2201*7c478bd9Sstevel@tonic-gate 		free(p);
2202*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
2203*7c478bd9Sstevel@tonic-gate 	}
2204*7c478bd9Sstevel@tonic-gate 	p->list = NULL;
2205*7c478bd9Sstevel@tonic-gate 
2206*7c478bd9Sstevel@tonic-gate 	return ((di_prom_handle_t)p);
2207*7c478bd9Sstevel@tonic-gate }
2208*7c478bd9Sstevel@tonic-gate 
2209*7c478bd9Sstevel@tonic-gate static void
2210*7c478bd9Sstevel@tonic-gate di_prom_prop_free(struct di_prom_prop *list)
2211*7c478bd9Sstevel@tonic-gate {
2212*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *tmp = list;
2213*7c478bd9Sstevel@tonic-gate 
2214*7c478bd9Sstevel@tonic-gate 	while (tmp != NULL) {
2215*7c478bd9Sstevel@tonic-gate 		list = tmp->next;
2216*7c478bd9Sstevel@tonic-gate 		if (tmp->name != NULL) {
2217*7c478bd9Sstevel@tonic-gate 			free(tmp->name);
2218*7c478bd9Sstevel@tonic-gate 		}
2219*7c478bd9Sstevel@tonic-gate 		if (tmp->data != NULL) {
2220*7c478bd9Sstevel@tonic-gate 			free(tmp->data);
2221*7c478bd9Sstevel@tonic-gate 		}
2222*7c478bd9Sstevel@tonic-gate 		free(tmp);
2223*7c478bd9Sstevel@tonic-gate 		tmp = list;
2224*7c478bd9Sstevel@tonic-gate 	}
2225*7c478bd9Sstevel@tonic-gate }
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate void
2228*7c478bd9Sstevel@tonic-gate di_prom_fini(di_prom_handle_t ph)
2229*7c478bd9Sstevel@tonic-gate {
2230*7c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate 	(void) close(p->fd);
2235*7c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&p->lock);
2236*7c478bd9Sstevel@tonic-gate 	di_prom_prop_free(p->list);
2237*7c478bd9Sstevel@tonic-gate 
2238*7c478bd9Sstevel@tonic-gate 	free(p);
2239*7c478bd9Sstevel@tonic-gate }
2240*7c478bd9Sstevel@tonic-gate 
2241*7c478bd9Sstevel@tonic-gate /*
2242*7c478bd9Sstevel@tonic-gate  * Internal library interface for locating the property
2243*7c478bd9Sstevel@tonic-gate  * XXX: ph->lock must be held for the duration of call.
2244*7c478bd9Sstevel@tonic-gate  */
2245*7c478bd9Sstevel@tonic-gate static di_prom_prop_t
2246*7c478bd9Sstevel@tonic-gate di_prom_prop_found(di_prom_handle_t ph, int nodeid,
2247*7c478bd9Sstevel@tonic-gate 	di_prom_prop_t prom_prop)
2248*7c478bd9Sstevel@tonic-gate {
2249*7c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
2250*7c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &p->oppbuf.opp;
2251*7c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
2252*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
2253*7c478bd9Sstevel@tonic-gate 
2254*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
2255*7c478bd9Sstevel@tonic-gate 
2256*7c478bd9Sstevel@tonic-gate 	/*
2257*7c478bd9Sstevel@tonic-gate 	 * Set "current" nodeid in the openprom driver
2258*7c478bd9Sstevel@tonic-gate 	 */
2259*7c478bd9Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
2260*7c478bd9Sstevel@tonic-gate 	*ip = nodeid;
2261*7c478bd9Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
2262*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
2263*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2264*7c478bd9Sstevel@tonic-gate 	}
2265*7c478bd9Sstevel@tonic-gate 
2266*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
2267*7c478bd9Sstevel@tonic-gate 
2268*7c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
2269*7c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPNAME;
2270*7c478bd9Sstevel@tonic-gate 	if (prom_prop != DI_PROM_PROP_NIL)
2271*7c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, prop->name);
2272*7c478bd9Sstevel@tonic-gate 
2273*7c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
2274*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2275*7c478bd9Sstevel@tonic-gate 
2276*7c478bd9Sstevel@tonic-gate 	/*
2277*7c478bd9Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
2278*7c478bd9Sstevel@tonic-gate 	 *   (reuse variable prop)
2279*7c478bd9Sstevel@tonic-gate 	 */
2280*7c478bd9Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
2281*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2282*7c478bd9Sstevel@tonic-gate 
2283*7c478bd9Sstevel@tonic-gate 	/*
2284*7c478bd9Sstevel@tonic-gate 	 * Get a copy of property name
2285*7c478bd9Sstevel@tonic-gate 	 */
2286*7c478bd9Sstevel@tonic-gate 	if ((prop->name = strdup(opp->oprom_array)) == NULL) {
2287*7c478bd9Sstevel@tonic-gate 		free(prop);
2288*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2289*7c478bd9Sstevel@tonic-gate 	}
2290*7c478bd9Sstevel@tonic-gate 
2291*7c478bd9Sstevel@tonic-gate 	/*
2292*7c478bd9Sstevel@tonic-gate 	 * get property value and length
2293*7c478bd9Sstevel@tonic-gate 	 */
2294*7c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
2295*7c478bd9Sstevel@tonic-gate 
2296*7c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
2297*7c478bd9Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
2298*7c478bd9Sstevel@tonic-gate 		free(prop->name);
2299*7c478bd9Sstevel@tonic-gate 		free(prop);
2300*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2301*7c478bd9Sstevel@tonic-gate 	}
2302*7c478bd9Sstevel@tonic-gate 
2303*7c478bd9Sstevel@tonic-gate 	/*
2304*7c478bd9Sstevel@tonic-gate 	 * make a copy of the property value
2305*7c478bd9Sstevel@tonic-gate 	 */
2306*7c478bd9Sstevel@tonic-gate 	prop->len = opp->oprom_size;
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 	if (prop->len == 0)
2309*7c478bd9Sstevel@tonic-gate 		prop->data = NULL;
2310*7c478bd9Sstevel@tonic-gate 	else if ((prop->data = malloc(prop->len)) == NULL) {
2311*7c478bd9Sstevel@tonic-gate 		free(prop->name);
2312*7c478bd9Sstevel@tonic-gate 		free(prop);
2313*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2314*7c478bd9Sstevel@tonic-gate 	}
2315*7c478bd9Sstevel@tonic-gate 
2316*7c478bd9Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
2317*7c478bd9Sstevel@tonic-gate 
2318*7c478bd9Sstevel@tonic-gate 	/*
2319*7c478bd9Sstevel@tonic-gate 	 * Prepend prop to list in prom handle
2320*7c478bd9Sstevel@tonic-gate 	 */
2321*7c478bd9Sstevel@tonic-gate 	prop->next = p->list;
2322*7c478bd9Sstevel@tonic-gate 	p->list = prop;
2323*7c478bd9Sstevel@tonic-gate 
2324*7c478bd9Sstevel@tonic-gate 	return ((di_prom_prop_t)prop);
2325*7c478bd9Sstevel@tonic-gate }
2326*7c478bd9Sstevel@tonic-gate 
2327*7c478bd9Sstevel@tonic-gate di_prom_prop_t
2328*7c478bd9Sstevel@tonic-gate di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
2329*7c478bd9Sstevel@tonic-gate {
2330*7c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
2331*7c478bd9Sstevel@tonic-gate 
2332*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
2333*7c478bd9Sstevel@tonic-gate 		node, p));
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate 	/*
2336*7c478bd9Sstevel@tonic-gate 	 * paranoid check
2337*7c478bd9Sstevel@tonic-gate 	 */
2338*7c478bd9Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
2339*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2340*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2341*7c478bd9Sstevel@tonic-gate 	}
2342*7c478bd9Sstevel@tonic-gate 
2343*7c478bd9Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
2344*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2345*7c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
2346*7c478bd9Sstevel@tonic-gate 	}
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate 	/*
2349*7c478bd9Sstevel@tonic-gate 	 * synchronize access to prom file descriptor
2350*7c478bd9Sstevel@tonic-gate 	 */
2351*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
2352*7c478bd9Sstevel@tonic-gate 
2353*7c478bd9Sstevel@tonic-gate 	/*
2354*7c478bd9Sstevel@tonic-gate 	 * look for next property
2355*7c478bd9Sstevel@tonic-gate 	 */
2356*7c478bd9Sstevel@tonic-gate 	prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
2357*7c478bd9Sstevel@tonic-gate 
2358*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
2359*7c478bd9Sstevel@tonic-gate 
2360*7c478bd9Sstevel@tonic-gate 	return (prom_prop);
2361*7c478bd9Sstevel@tonic-gate }
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate char *
2364*7c478bd9Sstevel@tonic-gate di_prom_prop_name(di_prom_prop_t prom_prop)
2365*7c478bd9Sstevel@tonic-gate {
2366*7c478bd9Sstevel@tonic-gate 	/*
2367*7c478bd9Sstevel@tonic-gate 	 * paranoid check
2368*7c478bd9Sstevel@tonic-gate 	 */
2369*7c478bd9Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
2370*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2371*7c478bd9Sstevel@tonic-gate 		return (NULL);
2372*7c478bd9Sstevel@tonic-gate 	}
2373*7c478bd9Sstevel@tonic-gate 
2374*7c478bd9Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->name);
2375*7c478bd9Sstevel@tonic-gate }
2376*7c478bd9Sstevel@tonic-gate 
2377*7c478bd9Sstevel@tonic-gate int
2378*7c478bd9Sstevel@tonic-gate di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
2379*7c478bd9Sstevel@tonic-gate {
2380*7c478bd9Sstevel@tonic-gate 	/*
2381*7c478bd9Sstevel@tonic-gate 	 * paranoid check
2382*7c478bd9Sstevel@tonic-gate 	 */
2383*7c478bd9Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
2384*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2385*7c478bd9Sstevel@tonic-gate 		return (NULL);
2386*7c478bd9Sstevel@tonic-gate 	}
2387*7c478bd9Sstevel@tonic-gate 
2388*7c478bd9Sstevel@tonic-gate 	*prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->len);
2391*7c478bd9Sstevel@tonic-gate }
2392*7c478bd9Sstevel@tonic-gate 
2393*7c478bd9Sstevel@tonic-gate /*
2394*7c478bd9Sstevel@tonic-gate  * Internal library interface for locating the property
2395*7c478bd9Sstevel@tonic-gate  *    Returns length if found, -1 if prop doesn't exist.
2396*7c478bd9Sstevel@tonic-gate  */
2397*7c478bd9Sstevel@tonic-gate static struct di_prom_prop *
2398*7c478bd9Sstevel@tonic-gate di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
2399*7c478bd9Sstevel@tonic-gate 	const char *prom_prop_name)
2400*7c478bd9Sstevel@tonic-gate {
2401*7c478bd9Sstevel@tonic-gate 	struct openpromio *opp;
2402*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
2403*7c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
2404*7c478bd9Sstevel@tonic-gate 
2405*7c478bd9Sstevel@tonic-gate 	/*
2406*7c478bd9Sstevel@tonic-gate 	 * paranoid check
2407*7c478bd9Sstevel@tonic-gate 	 */
2408*7c478bd9Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
2409*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2410*7c478bd9Sstevel@tonic-gate 		return (NULL);
2411*7c478bd9Sstevel@tonic-gate 	}
2412*7c478bd9Sstevel@tonic-gate 
2413*7c478bd9Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
2414*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2415*7c478bd9Sstevel@tonic-gate 		return (NULL);
2416*7c478bd9Sstevel@tonic-gate 	}
2417*7c478bd9Sstevel@tonic-gate 
2418*7c478bd9Sstevel@tonic-gate 	opp = &p->oppbuf.opp;
2419*7c478bd9Sstevel@tonic-gate 
2420*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
2421*7c478bd9Sstevel@tonic-gate 
2422*7c478bd9Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
2423*7c478bd9Sstevel@tonic-gate 	opp->oprom_node = DI_NODE(node)->nodeid;
2424*7c478bd9Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
2425*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2426*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
2427*7c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->nodeid));
2428*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
2429*7c478bd9Sstevel@tonic-gate 		return (NULL);
2430*7c478bd9Sstevel@tonic-gate 	}
2431*7c478bd9Sstevel@tonic-gate 
2432*7c478bd9Sstevel@tonic-gate 	/*
2433*7c478bd9Sstevel@tonic-gate 	 * get property length
2434*7c478bd9Sstevel@tonic-gate 	 */
2435*7c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
2436*7c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
2437*7c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
2438*7c478bd9Sstevel@tonic-gate 
2439*7c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
2440*7c478bd9Sstevel@tonic-gate 	    (opp->oprom_len == -1)) {
2441*7c478bd9Sstevel@tonic-gate 		/* no such property */
2442*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
2443*7c478bd9Sstevel@tonic-gate 		return (NULL);
2444*7c478bd9Sstevel@tonic-gate 	}
2445*7c478bd9Sstevel@tonic-gate 
2446*7c478bd9Sstevel@tonic-gate 	/*
2447*7c478bd9Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
2448*7c478bd9Sstevel@tonic-gate 	 */
2449*7c478bd9Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
2450*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
2451*7c478bd9Sstevel@tonic-gate 		return (NULL);
2452*7c478bd9Sstevel@tonic-gate 	}
2453*7c478bd9Sstevel@tonic-gate 	prop->name = NULL;	/* we don't need the name */
2454*7c478bd9Sstevel@tonic-gate 	prop->len = opp->oprom_len;
2455*7c478bd9Sstevel@tonic-gate 
2456*7c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
2457*7c478bd9Sstevel@tonic-gate 		prop->data = NULL;
2458*7c478bd9Sstevel@tonic-gate 		prop->next = p->list;
2459*7c478bd9Sstevel@tonic-gate 		p->list = prop;
2460*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
2461*7c478bd9Sstevel@tonic-gate 		return (prop);
2462*7c478bd9Sstevel@tonic-gate 	}
2463*7c478bd9Sstevel@tonic-gate 
2464*7c478bd9Sstevel@tonic-gate 	/*
2465*7c478bd9Sstevel@tonic-gate 	 * retrieve the property value
2466*7c478bd9Sstevel@tonic-gate 	 */
2467*7c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
2468*7c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
2469*7c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
2470*7c478bd9Sstevel@tonic-gate 
2471*7c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
2472*7c478bd9Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
2473*7c478bd9Sstevel@tonic-gate 		/* error retrieving property value */
2474*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
2475*7c478bd9Sstevel@tonic-gate 		free(prop);
2476*7c478bd9Sstevel@tonic-gate 		return (NULL);
2477*7c478bd9Sstevel@tonic-gate 	}
2478*7c478bd9Sstevel@tonic-gate 
2479*7c478bd9Sstevel@tonic-gate 	/*
2480*7c478bd9Sstevel@tonic-gate 	 * make a copy of the property value, stick in ph->list
2481*7c478bd9Sstevel@tonic-gate 	 */
2482*7c478bd9Sstevel@tonic-gate 	if ((prop->data = malloc(prop->len)) == NULL) {
2483*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
2484*7c478bd9Sstevel@tonic-gate 		free(prop);
2485*7c478bd9Sstevel@tonic-gate 		return (NULL);
2486*7c478bd9Sstevel@tonic-gate 	}
2487*7c478bd9Sstevel@tonic-gate 
2488*7c478bd9Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
2489*7c478bd9Sstevel@tonic-gate 
2490*7c478bd9Sstevel@tonic-gate 	prop->next = p->list;
2491*7c478bd9Sstevel@tonic-gate 	p->list = prop;
2492*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
2493*7c478bd9Sstevel@tonic-gate 
2494*7c478bd9Sstevel@tonic-gate 	return (prop);
2495*7c478bd9Sstevel@tonic-gate }
2496*7c478bd9Sstevel@tonic-gate 
2497*7c478bd9Sstevel@tonic-gate int
2498*7c478bd9Sstevel@tonic-gate di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
2499*7c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, int **prom_prop_data)
2500*7c478bd9Sstevel@tonic-gate {
2501*7c478bd9Sstevel@tonic-gate 	int len;
2502*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
2503*7c478bd9Sstevel@tonic-gate 
2504*7c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
2505*7c478bd9Sstevel@tonic-gate 
2506*7c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
2507*7c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
2508*7c478bd9Sstevel@tonic-gate 		return (-1);
2509*7c478bd9Sstevel@tonic-gate 	}
2510*7c478bd9Sstevel@tonic-gate 
2511*7c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
2512*7c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
2513*7c478bd9Sstevel@tonic-gate 		return (0);
2514*7c478bd9Sstevel@tonic-gate 	}
2515*7c478bd9Sstevel@tonic-gate 
2516*7c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
2517*7c478bd9Sstevel@tonic-gate 		DI_PROP_TYPE_INT, 1);
2518*7c478bd9Sstevel@tonic-gate 	*prom_prop_data = (int *)((void *)prop->data);
2519*7c478bd9Sstevel@tonic-gate 
2520*7c478bd9Sstevel@tonic-gate 	return (len);
2521*7c478bd9Sstevel@tonic-gate }
2522*7c478bd9Sstevel@tonic-gate 
2523*7c478bd9Sstevel@tonic-gate int
2524*7c478bd9Sstevel@tonic-gate di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
2525*7c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, char **prom_prop_data)
2526*7c478bd9Sstevel@tonic-gate {
2527*7c478bd9Sstevel@tonic-gate 	int len;
2528*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
2529*7c478bd9Sstevel@tonic-gate 
2530*7c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
2531*7c478bd9Sstevel@tonic-gate 
2532*7c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
2533*7c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
2534*7c478bd9Sstevel@tonic-gate 		return (-1);
2535*7c478bd9Sstevel@tonic-gate 	}
2536*7c478bd9Sstevel@tonic-gate 
2537*7c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
2538*7c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
2539*7c478bd9Sstevel@tonic-gate 		return (0);
2540*7c478bd9Sstevel@tonic-gate 	}
2541*7c478bd9Sstevel@tonic-gate 
2542*7c478bd9Sstevel@tonic-gate 	/*
2543*7c478bd9Sstevel@tonic-gate 	 * Fix an openprom bug (OBP string not NULL terminated).
2544*7c478bd9Sstevel@tonic-gate 	 * XXX This should really be fixed in promif.
2545*7c478bd9Sstevel@tonic-gate 	 */
2546*7c478bd9Sstevel@tonic-gate 	if (((char *)prop->data)[prop->len - 1] != '\0') {
2547*7c478bd9Sstevel@tonic-gate 		uchar_t *tmp;
2548*7c478bd9Sstevel@tonic-gate 		prop->len++;
2549*7c478bd9Sstevel@tonic-gate 		if ((tmp = realloc(prop->data, prop->len)) == NULL)
2550*7c478bd9Sstevel@tonic-gate 			return (-1);
2551*7c478bd9Sstevel@tonic-gate 
2552*7c478bd9Sstevel@tonic-gate 		prop->data = tmp;
2553*7c478bd9Sstevel@tonic-gate 		((char *)prop->data)[prop->len - 1] = '\0';
2554*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_INFO, "OBP string not NULL terminated: "
2555*7c478bd9Sstevel@tonic-gate 		    "node=%s, prop=%s, val=%s\n",
2556*7c478bd9Sstevel@tonic-gate 		    di_node_name(node), prom_prop_name, prop->data));
2557*7c478bd9Sstevel@tonic-gate 	}
2558*7c478bd9Sstevel@tonic-gate 
2559*7c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
2560*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING, 1);
2561*7c478bd9Sstevel@tonic-gate 	*prom_prop_data = (char *)prop->data;
2562*7c478bd9Sstevel@tonic-gate 
2563*7c478bd9Sstevel@tonic-gate 	return (len);
2564*7c478bd9Sstevel@tonic-gate }
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate int
2567*7c478bd9Sstevel@tonic-gate di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
2568*7c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, uchar_t **prom_prop_data)
2569*7c478bd9Sstevel@tonic-gate {
2570*7c478bd9Sstevel@tonic-gate 	int len;
2571*7c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
2572*7c478bd9Sstevel@tonic-gate 
2573*7c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
2574*7c478bd9Sstevel@tonic-gate 
2575*7c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
2576*7c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
2577*7c478bd9Sstevel@tonic-gate 		return (-1);
2578*7c478bd9Sstevel@tonic-gate 	}
2579*7c478bd9Sstevel@tonic-gate 
2580*7c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
2581*7c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
2582*7c478bd9Sstevel@tonic-gate 		return (0);
2583*7c478bd9Sstevel@tonic-gate 	}
2584*7c478bd9Sstevel@tonic-gate 
2585*7c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
2586*7c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE, 1);
2587*7c478bd9Sstevel@tonic-gate 	*prom_prop_data = prop->data;
2588*7c478bd9Sstevel@tonic-gate 
2589*7c478bd9Sstevel@tonic-gate 	return (len);
2590*7c478bd9Sstevel@tonic-gate }
2591*7c478bd9Sstevel@tonic-gate 
2592*7c478bd9Sstevel@tonic-gate di_lnode_t
2593*7c478bd9Sstevel@tonic-gate di_link_to_lnode(di_link_t link, uint_t endpoint)
2594*7c478bd9Sstevel@tonic-gate {
2595*7c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
2596*7c478bd9Sstevel@tonic-gate 
2597*7c478bd9Sstevel@tonic-gate 	if ((link == DI_LINK_NIL) ||
2598*7c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
2599*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2600*7c478bd9Sstevel@tonic-gate 		return (DI_LNODE_NIL);
2601*7c478bd9Sstevel@tonic-gate 	}
2602*7c478bd9Sstevel@tonic-gate 
2603*7c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
2604*7c478bd9Sstevel@tonic-gate 
2605*7c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
2606*7c478bd9Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
2607*7c478bd9Sstevel@tonic-gate 	} else {
2608*7c478bd9Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
2609*7c478bd9Sstevel@tonic-gate 	}
2610*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2611*7c478bd9Sstevel@tonic-gate }
2612*7c478bd9Sstevel@tonic-gate 
2613*7c478bd9Sstevel@tonic-gate char *
2614*7c478bd9Sstevel@tonic-gate di_lnode_name(di_lnode_t lnode)
2615*7c478bd9Sstevel@tonic-gate {
2616*7c478bd9Sstevel@tonic-gate 	return (di_driver_name(di_lnode_devinfo(lnode)));
2617*7c478bd9Sstevel@tonic-gate }
2618*7c478bd9Sstevel@tonic-gate 
2619*7c478bd9Sstevel@tonic-gate di_node_t
2620*7c478bd9Sstevel@tonic-gate di_lnode_devinfo(di_lnode_t lnode)
2621*7c478bd9Sstevel@tonic-gate {
2622*7c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
2625*7c478bd9Sstevel@tonic-gate 	return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
2626*7c478bd9Sstevel@tonic-gate }
2627*7c478bd9Sstevel@tonic-gate 
2628*7c478bd9Sstevel@tonic-gate int
2629*7c478bd9Sstevel@tonic-gate di_lnode_devt(di_lnode_t lnode, dev_t *devt)
2630*7c478bd9Sstevel@tonic-gate {
2631*7c478bd9Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
2632*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2633*7c478bd9Sstevel@tonic-gate 		return (-1);
2634*7c478bd9Sstevel@tonic-gate 	}
2635*7c478bd9Sstevel@tonic-gate 	if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
2636*7c478bd9Sstevel@tonic-gate 	    (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
2637*7c478bd9Sstevel@tonic-gate 		return (-1);
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate 	*devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
2640*7c478bd9Sstevel@tonic-gate 	return (0);
2641*7c478bd9Sstevel@tonic-gate }
2642*7c478bd9Sstevel@tonic-gate 
2643*7c478bd9Sstevel@tonic-gate int
2644*7c478bd9Sstevel@tonic-gate di_link_spectype(di_link_t link)
2645*7c478bd9Sstevel@tonic-gate {
2646*7c478bd9Sstevel@tonic-gate 	return (DI_LINK(link)->spec_type);
2647*7c478bd9Sstevel@tonic-gate }
2648*7c478bd9Sstevel@tonic-gate 
2649*7c478bd9Sstevel@tonic-gate void
2650*7c478bd9Sstevel@tonic-gate di_minor_private_set(di_minor_t minor, void *data)
2651*7c478bd9Sstevel@tonic-gate {
2652*7c478bd9Sstevel@tonic-gate 	DI_MINOR(minor)->user_private_data = (uintptr_t)data;
2653*7c478bd9Sstevel@tonic-gate }
2654*7c478bd9Sstevel@tonic-gate 
2655*7c478bd9Sstevel@tonic-gate void *
2656*7c478bd9Sstevel@tonic-gate di_minor_private_get(di_minor_t minor)
2657*7c478bd9Sstevel@tonic-gate {
2658*7c478bd9Sstevel@tonic-gate 	return ((void *)DI_MINOR(minor)->user_private_data);
2659*7c478bd9Sstevel@tonic-gate }
2660*7c478bd9Sstevel@tonic-gate 
2661*7c478bd9Sstevel@tonic-gate void
2662*7c478bd9Sstevel@tonic-gate di_node_private_set(di_node_t node, void *data)
2663*7c478bd9Sstevel@tonic-gate {
2664*7c478bd9Sstevel@tonic-gate 	DI_NODE(node)->user_private_data = (uintptr_t)data;
2665*7c478bd9Sstevel@tonic-gate }
2666*7c478bd9Sstevel@tonic-gate 
2667*7c478bd9Sstevel@tonic-gate void *
2668*7c478bd9Sstevel@tonic-gate di_node_private_get(di_node_t node)
2669*7c478bd9Sstevel@tonic-gate {
2670*7c478bd9Sstevel@tonic-gate 	return ((void *)DI_NODE(node)->user_private_data);
2671*7c478bd9Sstevel@tonic-gate }
2672*7c478bd9Sstevel@tonic-gate 
2673*7c478bd9Sstevel@tonic-gate void
2674*7c478bd9Sstevel@tonic-gate di_lnode_private_set(di_lnode_t lnode, void *data)
2675*7c478bd9Sstevel@tonic-gate {
2676*7c478bd9Sstevel@tonic-gate 	DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
2677*7c478bd9Sstevel@tonic-gate }
2678*7c478bd9Sstevel@tonic-gate 
2679*7c478bd9Sstevel@tonic-gate void *
2680*7c478bd9Sstevel@tonic-gate di_lnode_private_get(di_lnode_t lnode)
2681*7c478bd9Sstevel@tonic-gate {
2682*7c478bd9Sstevel@tonic-gate 	return ((void *)DI_LNODE(lnode)->user_private_data);
2683*7c478bd9Sstevel@tonic-gate }
2684*7c478bd9Sstevel@tonic-gate 
2685*7c478bd9Sstevel@tonic-gate void
2686*7c478bd9Sstevel@tonic-gate di_link_private_set(di_link_t link, void *data)
2687*7c478bd9Sstevel@tonic-gate {
2688*7c478bd9Sstevel@tonic-gate 	DI_LINK(link)->user_private_data = (uintptr_t)data;
2689*7c478bd9Sstevel@tonic-gate }
2690*7c478bd9Sstevel@tonic-gate 
2691*7c478bd9Sstevel@tonic-gate void *
2692*7c478bd9Sstevel@tonic-gate di_link_private_get(di_link_t link)
2693*7c478bd9Sstevel@tonic-gate {
2694*7c478bd9Sstevel@tonic-gate 	return ((void *)DI_LINK(link)->user_private_data);
2695*7c478bd9Sstevel@tonic-gate }
2696*7c478bd9Sstevel@tonic-gate 
2697*7c478bd9Sstevel@tonic-gate di_lnode_t
2698*7c478bd9Sstevel@tonic-gate di_lnode_next(di_node_t node, di_lnode_t lnode)
2699*7c478bd9Sstevel@tonic-gate {
2700*7c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
2701*7c478bd9Sstevel@tonic-gate 
2702*7c478bd9Sstevel@tonic-gate 	/*
2703*7c478bd9Sstevel@tonic-gate 	 * paranoid error checking
2704*7c478bd9Sstevel@tonic-gate 	 */
2705*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
2706*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2707*7c478bd9Sstevel@tonic-gate 		return (DI_LNODE_NIL);
2708*7c478bd9Sstevel@tonic-gate 	}
2709*7c478bd9Sstevel@tonic-gate 
2710*7c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
2711*7c478bd9Sstevel@tonic-gate 
2712*7c478bd9Sstevel@tonic-gate 	if (lnode == DI_NODE_NIL) {
2713*7c478bd9Sstevel@tonic-gate 		if (DI_NODE(node)->lnodes != NULL)
2714*7c478bd9Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
2715*7c478bd9Sstevel@tonic-gate 			    DI_NODE(node)->lnodes));
2716*7c478bd9Sstevel@tonic-gate 	} else {
2717*7c478bd9Sstevel@tonic-gate 		if (DI_LNODE(lnode)->node_next != NULL)
2718*7c478bd9Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
2719*7c478bd9Sstevel@tonic-gate 			    DI_LNODE(lnode)->node_next));
2720*7c478bd9Sstevel@tonic-gate 	}
2721*7c478bd9Sstevel@tonic-gate 
2722*7c478bd9Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
2723*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2724*7c478bd9Sstevel@tonic-gate 	else
2725*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
2726*7c478bd9Sstevel@tonic-gate 
2727*7c478bd9Sstevel@tonic-gate 	return (DI_LNODE_NIL);
2728*7c478bd9Sstevel@tonic-gate }
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate di_link_t
2731*7c478bd9Sstevel@tonic-gate di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
2732*7c478bd9Sstevel@tonic-gate {
2733*7c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
2734*7c478bd9Sstevel@tonic-gate 
2735*7c478bd9Sstevel@tonic-gate 	/*
2736*7c478bd9Sstevel@tonic-gate 	 * paranoid error checking
2737*7c478bd9Sstevel@tonic-gate 	 */
2738*7c478bd9Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) ||
2739*7c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
2740*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2741*7c478bd9Sstevel@tonic-gate 		return (DI_LINK_NIL);
2742*7c478bd9Sstevel@tonic-gate 	}
2743*7c478bd9Sstevel@tonic-gate 
2744*7c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
2745*7c478bd9Sstevel@tonic-gate 
2746*7c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
2747*7c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
2748*7c478bd9Sstevel@tonic-gate 			if (DI_NODE(node)->src_links != NULL)
2749*7c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
2750*7c478bd9Sstevel@tonic-gate 				    DI_NODE(node)->src_links));
2751*7c478bd9Sstevel@tonic-gate 		} else {
2752*7c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->src_node_next != NULL)
2753*7c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
2754*7c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->src_node_next));
2755*7c478bd9Sstevel@tonic-gate 		}
2756*7c478bd9Sstevel@tonic-gate 	} else {
2757*7c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
2758*7c478bd9Sstevel@tonic-gate 			if (DI_NODE(node)->tgt_links != NULL)
2759*7c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
2760*7c478bd9Sstevel@tonic-gate 				    DI_NODE(node)->tgt_links));
2761*7c478bd9Sstevel@tonic-gate 		} else {
2762*7c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_node_next != NULL)
2763*7c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
2764*7c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->tgt_node_next));
2765*7c478bd9Sstevel@tonic-gate 		}
2766*7c478bd9Sstevel@tonic-gate 	}
2767*7c478bd9Sstevel@tonic-gate 
2768*7c478bd9Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
2769*7c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2770*7c478bd9Sstevel@tonic-gate 	else
2771*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
2772*7c478bd9Sstevel@tonic-gate 
2773*7c478bd9Sstevel@tonic-gate 	return (DI_LINK_NIL);
2774*7c478bd9Sstevel@tonic-gate }
2775*7c478bd9Sstevel@tonic-gate 
2776*7c478bd9Sstevel@tonic-gate di_link_t
2777*7c478bd9Sstevel@tonic-gate di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
2778*7c478bd9Sstevel@tonic-gate {
2779*7c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
2780*7c478bd9Sstevel@tonic-gate 
2781*7c478bd9Sstevel@tonic-gate 	/*
2782*7c478bd9Sstevel@tonic-gate 	 * paranoid error checking
2783*7c478bd9Sstevel@tonic-gate 	 */
2784*7c478bd9Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) ||
2785*7c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
2786*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2787*7c478bd9Sstevel@tonic-gate 		return (DI_LINK_NIL);
2788*7c478bd9Sstevel@tonic-gate 	}
2789*7c478bd9Sstevel@tonic-gate 
2790*7c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
2791*7c478bd9Sstevel@tonic-gate 
2792*7c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
2793*7c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
2794*7c478bd9Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_out == NULL)
2795*7c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
2796*7c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
2797*7c478bd9Sstevel@tonic-gate 				    DI_LNODE(lnode)->link_out));
2798*7c478bd9Sstevel@tonic-gate 		} else {
2799*7c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->src_link_next == NULL)
2800*7c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
2801*7c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
2802*7c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->src_link_next));
2803*7c478bd9Sstevel@tonic-gate 		}
2804*7c478bd9Sstevel@tonic-gate 	} else {
2805*7c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
2806*7c478bd9Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_in == NULL)
2807*7c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
2808*7c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
2809*7c478bd9Sstevel@tonic-gate 				    DI_LNODE(lnode)->link_in));
2810*7c478bd9Sstevel@tonic-gate 		} else {
2811*7c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_link_next == NULL)
2812*7c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
2813*7c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
2814*7c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->tgt_link_next));
2815*7c478bd9Sstevel@tonic-gate 		}
2816*7c478bd9Sstevel@tonic-gate 	}
2817*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2818*7c478bd9Sstevel@tonic-gate }
2819*7c478bd9Sstevel@tonic-gate 
2820*7c478bd9Sstevel@tonic-gate /*
2821*7c478bd9Sstevel@tonic-gate  * Internal library function:
2822*7c478bd9Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
2823*7c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
2824*7c478bd9Sstevel@tonic-gate  *
2825*7c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
2826*7c478bd9Sstevel@tonic-gate  *   first mode.
2827*7c478bd9Sstevel@tonic-gate  */
2828*7c478bd9Sstevel@tonic-gate static void
2829*7c478bd9Sstevel@tonic-gate walk_one_link(struct node_list **headp, uint_t ep,
2830*7c478bd9Sstevel@tonic-gate     void *arg, int (*callback)(di_link_t link, void *arg))
2831*7c478bd9Sstevel@tonic-gate {
2832*7c478bd9Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
2833*7c478bd9Sstevel@tonic-gate 	di_link_t	link = DI_LINK_NIL;
2834*7c478bd9Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
2835*7c478bd9Sstevel@tonic-gate 
2836*7c478bd9Sstevel@tonic-gate 	while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
2837*7c478bd9Sstevel@tonic-gate 		action = callback(link, arg);
2838*7c478bd9Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
2839*7c478bd9Sstevel@tonic-gate 			break;
2840*7c478bd9Sstevel@tonic-gate 		}
2841*7c478bd9Sstevel@tonic-gate 	}
2842*7c478bd9Sstevel@tonic-gate 
2843*7c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
2844*7c478bd9Sstevel@tonic-gate }
2845*7c478bd9Sstevel@tonic-gate 
2846*7c478bd9Sstevel@tonic-gate int
2847*7c478bd9Sstevel@tonic-gate di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
2848*7c478bd9Sstevel@tonic-gate     int (*link_callback)(di_link_t link, void *arg))
2849*7c478bd9Sstevel@tonic-gate {
2850*7c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
2851*7c478bd9Sstevel@tonic-gate 
2852*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2853*7c478bd9Sstevel@tonic-gate 	char *path = di_devfs_path(root);
2854*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking %s link data under %s\n",
2855*7c478bd9Sstevel@tonic-gate 		    (endpoint == DI_LINK_SRC) ? "src" : "tgt", path));
2856*7c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
2857*7c478bd9Sstevel@tonic-gate #endif
2858*7c478bd9Sstevel@tonic-gate 
2859*7c478bd9Sstevel@tonic-gate 	/*
2860*7c478bd9Sstevel@tonic-gate 	 * paranoid error checking
2861*7c478bd9Sstevel@tonic-gate 	 */
2862*7c478bd9Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
2863*7c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
2864*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2865*7c478bd9Sstevel@tonic-gate 		return (-1);
2866*7c478bd9Sstevel@tonic-gate 	}
2867*7c478bd9Sstevel@tonic-gate 
2868*7c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
2869*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
2870*7c478bd9Sstevel@tonic-gate 		return (-1);
2871*7c478bd9Sstevel@tonic-gate 	}
2872*7c478bd9Sstevel@tonic-gate 
2873*7c478bd9Sstevel@tonic-gate 	head->next = NULL;
2874*7c478bd9Sstevel@tonic-gate 	head->node = root;
2875*7c478bd9Sstevel@tonic-gate 
2876*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start link data walking from node %s\n",
2877*7c478bd9Sstevel@tonic-gate 		di_node_name(root)));
2878*7c478bd9Sstevel@tonic-gate 
2879*7c478bd9Sstevel@tonic-gate 	while (head != NULL)
2880*7c478bd9Sstevel@tonic-gate 		walk_one_link(&head, endpoint, arg, link_callback);
2881*7c478bd9Sstevel@tonic-gate 
2882*7c478bd9Sstevel@tonic-gate 	return (0);
2883*7c478bd9Sstevel@tonic-gate }
2884*7c478bd9Sstevel@tonic-gate 
2885*7c478bd9Sstevel@tonic-gate /*
2886*7c478bd9Sstevel@tonic-gate  * Internal library function:
2887*7c478bd9Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
2888*7c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
2889*7c478bd9Sstevel@tonic-gate  *
2890*7c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
2891*7c478bd9Sstevel@tonic-gate  *   first mode.
2892*7c478bd9Sstevel@tonic-gate  */
2893*7c478bd9Sstevel@tonic-gate static void
2894*7c478bd9Sstevel@tonic-gate walk_one_lnode(struct node_list **headp, void *arg,
2895*7c478bd9Sstevel@tonic-gate     int (*callback)(di_lnode_t lnode, void *arg))
2896*7c478bd9Sstevel@tonic-gate {
2897*7c478bd9Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
2898*7c478bd9Sstevel@tonic-gate 	di_lnode_t	lnode = DI_LNODE_NIL;
2899*7c478bd9Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
2900*7c478bd9Sstevel@tonic-gate 
2901*7c478bd9Sstevel@tonic-gate 	while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
2902*7c478bd9Sstevel@tonic-gate 		action = callback(lnode, arg);
2903*7c478bd9Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
2904*7c478bd9Sstevel@tonic-gate 			break;
2905*7c478bd9Sstevel@tonic-gate 		}
2906*7c478bd9Sstevel@tonic-gate 	}
2907*7c478bd9Sstevel@tonic-gate 
2908*7c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
2909*7c478bd9Sstevel@tonic-gate }
2910*7c478bd9Sstevel@tonic-gate 
2911*7c478bd9Sstevel@tonic-gate int
2912*7c478bd9Sstevel@tonic-gate di_walk_lnode(di_node_t root, uint_t flag, void *arg,
2913*7c478bd9Sstevel@tonic-gate     int (*lnode_callback)(di_lnode_t lnode, void *arg))
2914*7c478bd9Sstevel@tonic-gate {
2915*7c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
2916*7c478bd9Sstevel@tonic-gate 
2917*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2918*7c478bd9Sstevel@tonic-gate 	char *path = di_devfs_path(root);
2919*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking lnode data under %s\n", path));
2920*7c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
2921*7c478bd9Sstevel@tonic-gate #endif
2922*7c478bd9Sstevel@tonic-gate 
2923*7c478bd9Sstevel@tonic-gate 	/*
2924*7c478bd9Sstevel@tonic-gate 	 * paranoid error checking
2925*7c478bd9Sstevel@tonic-gate 	 */
2926*7c478bd9Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
2927*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2928*7c478bd9Sstevel@tonic-gate 		return (-1);
2929*7c478bd9Sstevel@tonic-gate 	}
2930*7c478bd9Sstevel@tonic-gate 
2931*7c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
2932*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
2933*7c478bd9Sstevel@tonic-gate 		return (-1);
2934*7c478bd9Sstevel@tonic-gate 	}
2935*7c478bd9Sstevel@tonic-gate 
2936*7c478bd9Sstevel@tonic-gate 	head->next = NULL;
2937*7c478bd9Sstevel@tonic-gate 	head->node = root;
2938*7c478bd9Sstevel@tonic-gate 
2939*7c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
2940*7c478bd9Sstevel@tonic-gate 		di_node_name(root)));
2941*7c478bd9Sstevel@tonic-gate 
2942*7c478bd9Sstevel@tonic-gate 	while (head != NULL)
2943*7c478bd9Sstevel@tonic-gate 		walk_one_lnode(&head, arg, lnode_callback);
2944*7c478bd9Sstevel@tonic-gate 
2945*7c478bd9Sstevel@tonic-gate 	return (0);
2946*7c478bd9Sstevel@tonic-gate }
2947*7c478bd9Sstevel@tonic-gate 
2948*7c478bd9Sstevel@tonic-gate di_node_t
2949*7c478bd9Sstevel@tonic-gate di_lookup_node(di_node_t root, char *path)
2950*7c478bd9Sstevel@tonic-gate {
2951*7c478bd9Sstevel@tonic-gate 	struct di_all *dap;
2952*7c478bd9Sstevel@tonic-gate 	di_node_t node;
2953*7c478bd9Sstevel@tonic-gate 	char copy[MAXPATHLEN];
2954*7c478bd9Sstevel@tonic-gate 	char *slash, *pname, *paddr;
2955*7c478bd9Sstevel@tonic-gate 
2956*7c478bd9Sstevel@tonic-gate 	/*
2957*7c478bd9Sstevel@tonic-gate 	 * Path must be absolute and musn't have duplicate slashes
2958*7c478bd9Sstevel@tonic-gate 	 */
2959*7c478bd9Sstevel@tonic-gate 	if (*path != '/' || strstr(path, "//")) {
2960*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "Invalid path: %s\n", path));
2961*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2962*7c478bd9Sstevel@tonic-gate 	}
2963*7c478bd9Sstevel@tonic-gate 
2964*7c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
2965*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
2966*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2967*7c478bd9Sstevel@tonic-gate 	}
2968*7c478bd9Sstevel@tonic-gate 
2969*7c478bd9Sstevel@tonic-gate 	dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
2970*7c478bd9Sstevel@tonic-gate 	if (strcmp(dap->root_path, "/") != 0) {
2971*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
2972*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2973*7c478bd9Sstevel@tonic-gate 	}
2974*7c478bd9Sstevel@tonic-gate 
2975*7c478bd9Sstevel@tonic-gate 	if (strlcpy(copy, path, sizeof (copy)) >= sizeof (copy)) {
2976*7c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "path too long: %s\n", path));
2977*7c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2978*7c478bd9Sstevel@tonic-gate 	}
2979*7c478bd9Sstevel@tonic-gate 
2980*7c478bd9Sstevel@tonic-gate 	for (slash = copy, node = root; slash; ) {
2981*7c478bd9Sstevel@tonic-gate 
2982*7c478bd9Sstevel@tonic-gate 		/*
2983*7c478bd9Sstevel@tonic-gate 		 * Handle path = "/" case as well as trailing '/'
2984*7c478bd9Sstevel@tonic-gate 		 */
2985*7c478bd9Sstevel@tonic-gate 		if (*(slash + 1) == '\0')
2986*7c478bd9Sstevel@tonic-gate 			break;
2987*7c478bd9Sstevel@tonic-gate 
2988*7c478bd9Sstevel@tonic-gate 		/*
2989*7c478bd9Sstevel@tonic-gate 		 * More path-components exist. Deal with the next one
2990*7c478bd9Sstevel@tonic-gate 		 */
2991*7c478bd9Sstevel@tonic-gate 		pname = slash + 1;
2992*7c478bd9Sstevel@tonic-gate 		node = di_child_node(node);
2993*7c478bd9Sstevel@tonic-gate 
2994*7c478bd9Sstevel@tonic-gate 		if (slash = strchr(pname, '/'))
2995*7c478bd9Sstevel@tonic-gate 			*slash = '\0';
2996*7c478bd9Sstevel@tonic-gate 		if (paddr = strchr(pname, '@'))
2997*7c478bd9Sstevel@tonic-gate 			*paddr++ = '\0';
2998*7c478bd9Sstevel@tonic-gate 
2999*7c478bd9Sstevel@tonic-gate 		for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
3000*7c478bd9Sstevel@tonic-gate 			char *name, *baddr;
3001*7c478bd9Sstevel@tonic-gate 
3002*7c478bd9Sstevel@tonic-gate 			name = di_node_name(node);
3003*7c478bd9Sstevel@tonic-gate 			baddr = di_bus_addr(node);
3004*7c478bd9Sstevel@tonic-gate 
3005*7c478bd9Sstevel@tonic-gate 			if (strcmp(pname, name) != 0)
3006*7c478bd9Sstevel@tonic-gate 				continue;
3007*7c478bd9Sstevel@tonic-gate 
3008*7c478bd9Sstevel@tonic-gate 			/*
3009*7c478bd9Sstevel@tonic-gate 			 * Mappings between a "path-address" and bus-addr
3010*7c478bd9Sstevel@tonic-gate 			 *
3011*7c478bd9Sstevel@tonic-gate 			 *	paddr		baddr
3012*7c478bd9Sstevel@tonic-gate 			 *	---------------------
3013*7c478bd9Sstevel@tonic-gate 			 *	NULL		NULL
3014*7c478bd9Sstevel@tonic-gate 			 *	NULL		""
3015*7c478bd9Sstevel@tonic-gate 			 *	""		N/A	(invalid paddr)
3016*7c478bd9Sstevel@tonic-gate 			 */
3017*7c478bd9Sstevel@tonic-gate 			if (paddr && baddr && strcmp(paddr, baddr) == 0)
3018*7c478bd9Sstevel@tonic-gate 				break;
3019*7c478bd9Sstevel@tonic-gate 			if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
3020*7c478bd9Sstevel@tonic-gate 				break;
3021*7c478bd9Sstevel@tonic-gate 		}
3022*7c478bd9Sstevel@tonic-gate 
3023*7c478bd9Sstevel@tonic-gate 		/*
3024*7c478bd9Sstevel@tonic-gate 		 * No nodes in the sibling list or there was no match
3025*7c478bd9Sstevel@tonic-gate 		 */
3026*7c478bd9Sstevel@tonic-gate 		if (node == DI_NODE_NIL) {
3027*7c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
3028*7c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
3029*7c478bd9Sstevel@tonic-gate 		}
3030*7c478bd9Sstevel@tonic-gate 	}
3031*7c478bd9Sstevel@tonic-gate 
3032*7c478bd9Sstevel@tonic-gate 	assert(node != DI_NODE_NIL);
3033*7c478bd9Sstevel@tonic-gate 	return (node);
3034*7c478bd9Sstevel@tonic-gate }
3035*7c478bd9Sstevel@tonic-gate 
3036*7c478bd9Sstevel@tonic-gate static char *
3037*7c478bd9Sstevel@tonic-gate msglevel2str(di_debug_t msglevel)
3038*7c478bd9Sstevel@tonic-gate {
3039*7c478bd9Sstevel@tonic-gate 	switch (msglevel) {
3040*7c478bd9Sstevel@tonic-gate 		case DI_ERR:
3041*7c478bd9Sstevel@tonic-gate 			return ("ERROR");
3042*7c478bd9Sstevel@tonic-gate 		case DI_INFO:
3043*7c478bd9Sstevel@tonic-gate 			return ("Info");
3044*7c478bd9Sstevel@tonic-gate 		case DI_TRACE:
3045*7c478bd9Sstevel@tonic-gate 			return ("Trace");
3046*7c478bd9Sstevel@tonic-gate 		case DI_TRACE1:
3047*7c478bd9Sstevel@tonic-gate 			return ("Trace1");
3048*7c478bd9Sstevel@tonic-gate 		case DI_TRACE2:
3049*7c478bd9Sstevel@tonic-gate 			return ("Trace2");
3050*7c478bd9Sstevel@tonic-gate 		default:
3051*7c478bd9Sstevel@tonic-gate 			return ("UNKNOWN");
3052*7c478bd9Sstevel@tonic-gate 	}
3053*7c478bd9Sstevel@tonic-gate }
3054*7c478bd9Sstevel@tonic-gate 
3055*7c478bd9Sstevel@tonic-gate void
3056*7c478bd9Sstevel@tonic-gate dprint(di_debug_t msglevel, const char *fmt, ...)
3057*7c478bd9Sstevel@tonic-gate {
3058*7c478bd9Sstevel@tonic-gate 	va_list	ap;
3059*7c478bd9Sstevel@tonic-gate 	char	*estr;
3060*7c478bd9Sstevel@tonic-gate 
3061*7c478bd9Sstevel@tonic-gate 	if (di_debug <= DI_QUIET)
3062*7c478bd9Sstevel@tonic-gate 		return;
3063*7c478bd9Sstevel@tonic-gate 
3064*7c478bd9Sstevel@tonic-gate 	if (di_debug < msglevel)
3065*7c478bd9Sstevel@tonic-gate 		return;
3066*7c478bd9Sstevel@tonic-gate 
3067*7c478bd9Sstevel@tonic-gate 	estr = msglevel2str(msglevel);
3068*7c478bd9Sstevel@tonic-gate 
3069*7c478bd9Sstevel@tonic-gate 	assert(estr);
3070*7c478bd9Sstevel@tonic-gate 
3071*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
3072*7c478bd9Sstevel@tonic-gate 
3073*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
3074*7c478bd9Sstevel@tonic-gate 	    (ulong_t)getpid(), estr);
3075*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
3076*7c478bd9Sstevel@tonic-gate 
3077*7c478bd9Sstevel@tonic-gate 	va_end(ap);
3078*7c478bd9Sstevel@tonic-gate }
3079*7c478bd9Sstevel@tonic-gate 
3080*7c478bd9Sstevel@tonic-gate /* end of devinfo.c */
3081