xref: /illumos-gate/usr/src/lib/libdevinfo/devinfo.c (revision 3ebafc43f8c876353693c0e5a9e759edd91165b6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3ebafc43Sjveta  * Common Development and Distribution License (the "License").
6*3ebafc43Sjveta  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*3ebafc43Sjveta  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Interfaces for getting device configuration data from kernel
307c478bd9Sstevel@tonic-gate  * through the devinfo driver.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate #include <stropts.h>
387c478bd9Sstevel@tonic-gate #include <fcntl.h>
397c478bd9Sstevel@tonic-gate #include <poll.h>
407c478bd9Sstevel@tonic-gate #include <synch.h>
417c478bd9Sstevel@tonic-gate #include <unistd.h>
427c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
437c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
447c478bd9Sstevel@tonic-gate #include <sys/stat.h>
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <sys/time.h>
477c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
487c478bd9Sstevel@tonic-gate #include <stdarg.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #define	NDEBUG 1
517c478bd9Sstevel@tonic-gate #include <assert.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include "libdevinfo.h"
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * Debug message levels
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate typedef enum {
597c478bd9Sstevel@tonic-gate 	DI_QUIET = 0,	/* No debug messages - the default */
607c478bd9Sstevel@tonic-gate 	DI_ERR = 1,
617c478bd9Sstevel@tonic-gate 	DI_INFO,
627c478bd9Sstevel@tonic-gate 	DI_TRACE,
637c478bd9Sstevel@tonic-gate 	DI_TRACE1,
647c478bd9Sstevel@tonic-gate 	DI_TRACE2
657c478bd9Sstevel@tonic-gate } di_debug_t;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate int di_debug = DI_QUIET;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #define	DPRINTF(args)	{ if (di_debug != DI_QUIET) dprint args; }
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate void dprint(di_debug_t msglevel, const char *fmt, ...);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #pragma init(_libdevinfo_init)
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate void
777c478bd9Sstevel@tonic-gate _libdevinfo_init()
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	char	*debug_str = getenv("_LIBDEVINFO_DEBUG");
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	if (debug_str) {
827c478bd9Sstevel@tonic-gate 		errno = 0;
837c478bd9Sstevel@tonic-gate 		di_debug = atoi(debug_str);
847c478bd9Sstevel@tonic-gate 		if (errno || di_debug < DI_QUIET)
857c478bd9Sstevel@tonic-gate 			di_debug = DI_QUIET;
867c478bd9Sstevel@tonic-gate 	}
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate di_node_t
907c478bd9Sstevel@tonic-gate di_init(const char *phys_path, uint_t flag)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	return (di_init_impl(phys_path, flag, NULL));
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * We use blocking_open() to guarantee access to the devinfo device, if open()
977c478bd9Sstevel@tonic-gate  * is failing with EAGAIN.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate static int
1007c478bd9Sstevel@tonic-gate blocking_open(const char *path, int oflag)
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate 	int fd;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
1057c478bd9Sstevel@tonic-gate 		(void) poll(NULL, 0, 1 * MILLISEC);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	return (fd);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /* private interface */
1117c478bd9Sstevel@tonic-gate di_node_t
1127c478bd9Sstevel@tonic-gate di_init_driver(const char *drv_name, uint_t flag)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate 	int fd;
1157c478bd9Sstevel@tonic-gate 	char driver[MAXPATHLEN];
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	/*
1187c478bd9Sstevel@tonic-gate 	 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
1197c478bd9Sstevel@tonic-gate 	 * which should be sufficient for any sensible programmer.
1207c478bd9Sstevel@tonic-gate 	 */
1217c478bd9Sstevel@tonic-gate 	if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
1227c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1237c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 	(void) strcpy(driver, drv_name);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	/*
1287c478bd9Sstevel@tonic-gate 	 * open the devinfo driver
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
1317c478bd9Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
1327c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
1337c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOLODRV, driver) != 0) {
1377c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
1387c478bd9Sstevel@tonic-gate 		(void) close(fd);
1397c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1407c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 	(void) close(fd);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	/*
1457c478bd9Sstevel@tonic-gate 	 * Driver load succeeded, return a snapshot
1467c478bd9Sstevel@tonic-gate 	 */
1477c478bd9Sstevel@tonic-gate 	return (di_init("/", flag));
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate di_node_t
1517c478bd9Sstevel@tonic-gate di_init_impl(const char *phys_path, uint_t flag,
1527c478bd9Sstevel@tonic-gate 	struct di_priv_data *priv)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	caddr_t pa;
1557c478bd9Sstevel@tonic-gate 	int fd, map_size;
1567c478bd9Sstevel@tonic-gate 	struct di_all *dap;
1577c478bd9Sstevel@tonic-gate 	struct dinfo_io dinfo_io;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
1607c478bd9Sstevel@tonic-gate 	uint_t pagemask = ~pageoffset;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/*
1657c478bd9Sstevel@tonic-gate 	 * Make sure there is no minor name in the path
1667c478bd9Sstevel@tonic-gate 	 * and the path do not start with /devices....
1677c478bd9Sstevel@tonic-gate 	 */
1687c478bd9Sstevel@tonic-gate 	if (strchr(phys_path, ':') ||
1697c478bd9Sstevel@tonic-gate 	    (strncmp(phys_path, "/devices", 8) == 0) ||
1707c478bd9Sstevel@tonic-gate 	    (strlen(phys_path) > MAXPATHLEN)) {
1717c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1727c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if (strlen(phys_path) == 0)
1767c478bd9Sstevel@tonic-gate 		(void) sprintf(dinfo_io.root_path, "/");
1777c478bd9Sstevel@tonic-gate 	else if (*phys_path != '/')
1787c478bd9Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
1797c478bd9Sstevel@tonic-gate 		    "/%s", phys_path);
1807c478bd9Sstevel@tonic-gate 	else
1817c478bd9Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
1827c478bd9Sstevel@tonic-gate 		    "%s", phys_path);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/*
1857c478bd9Sstevel@tonic-gate 	 * If private data is requested, copy the format specification
1867c478bd9Sstevel@tonic-gate 	 */
1877c478bd9Sstevel@tonic-gate 	if (flag & DINFOPRIVDATA & 0xff) {
1887c478bd9Sstevel@tonic-gate 		if (priv)
1897c478bd9Sstevel@tonic-gate 			bcopy(priv, &dinfo_io.priv,
1907c478bd9Sstevel@tonic-gate 			    sizeof (struct di_priv_data));
1917c478bd9Sstevel@tonic-gate 		else {
1927c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1937c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
1947c478bd9Sstevel@tonic-gate 		}
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	/*
1987c478bd9Sstevel@tonic-gate 	 * Attempt to open the devinfo driver.  Make a second attempt at the
1997c478bd9Sstevel@tonic-gate 	 * read-only minor node if we don't have privileges to open the full
2007c478bd9Sstevel@tonic-gate 	 * version _and_ if we're not requesting operations that the read-only
2017c478bd9Sstevel@tonic-gate 	 * node can't perform.  (Setgid processes would fail an access() test,
2027c478bd9Sstevel@tonic-gate 	 * of course.)
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
2057c478bd9Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
2067c478bd9Sstevel@tonic-gate 		if ((flag & DINFOFORCE) == DINFOFORCE ||
2077c478bd9Sstevel@tonic-gate 		    (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
2087c478bd9Sstevel@tonic-gate 			/*
2097c478bd9Sstevel@tonic-gate 			 * We wanted to perform a privileged operation, but the
2107c478bd9Sstevel@tonic-gate 			 * privileged node isn't available.  Don't modify errno
2117c478bd9Sstevel@tonic-gate 			 * on our way out (but display it if we're running with
2127c478bd9Sstevel@tonic-gate 			 * di_debug set).
2137c478bd9Sstevel@tonic-gate 			 */
2147c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
2157c478bd9Sstevel@tonic-gate 			    errno));
2167c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
2177c478bd9Sstevel@tonic-gate 		}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
2207c478bd9Sstevel@tonic-gate 		    O_RDONLY)) == -1) {
2217c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
2227c478bd9Sstevel@tonic-gate 			    errno));
2237c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/*
2287c478bd9Sstevel@tonic-gate 	 * Verify that there is no major conflict, i.e., we are indeed opening
2297c478bd9Sstevel@tonic-gate 	 * the devinfo driver.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
2327c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR,
2337c478bd9Sstevel@tonic-gate 		    "driver ID failed; check for major conflict\n"));
2347c478bd9Sstevel@tonic-gate 		(void) close(fd);
2357c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * create snapshot
2407c478bd9Sstevel@tonic-gate 	 */
2417c478bd9Sstevel@tonic-gate 	if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
2427c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo ioctl failed with "
2437c478bd9Sstevel@tonic-gate 		    "error: %d\n", errno));
2447c478bd9Sstevel@tonic-gate 		(void) close(fd);
2457c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2467c478bd9Sstevel@tonic-gate 	} else if (map_size == 0) {
2477c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
2487c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2497c478bd9Sstevel@tonic-gate 		(void) close(fd);
2507c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	/*
2547c478bd9Sstevel@tonic-gate 	 * copy snapshot to userland
2557c478bd9Sstevel@tonic-gate 	 */
2567c478bd9Sstevel@tonic-gate 	map_size = (map_size + pageoffset) & pagemask;
2577c478bd9Sstevel@tonic-gate 	if ((pa = valloc(map_size)) == NULL) {
2587c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
2597c478bd9Sstevel@tonic-gate 		(void) close(fd);
2607c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
2647c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
2657c478bd9Sstevel@tonic-gate 		(void) close(fd);
2667c478bd9Sstevel@tonic-gate 		free(pa);
2677c478bd9Sstevel@tonic-gate 		errno = EFAULT;
2687c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	(void) close(fd);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	dap = DI_ALL(pa);
2747c478bd9Sstevel@tonic-gate 	if (dap->top_devinfo == 0) {	/* phys_path not found */
2757c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
2767c478bd9Sstevel@tonic-gate 		free(pa);
2777c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2787c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + dap->top_devinfo));
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate void
2857c478bd9Sstevel@tonic-gate di_fini(di_node_t root)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * paranoid checking
2937c478bd9Sstevel@tonic-gate 	 */
2947c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
2957c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
2967c478bd9Sstevel@tonic-gate 		return;
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/*
3007c478bd9Sstevel@tonic-gate 	 * The root contains its own offset--self.
3017c478bd9Sstevel@tonic-gate 	 * Subtracting it from root address, we get the starting addr.
3027c478bd9Sstevel@tonic-gate 	 * The map_size is stored at the beginning of snapshot.
3037c478bd9Sstevel@tonic-gate 	 * Once we have starting address and size, we can free().
3047c478bd9Sstevel@tonic-gate 	 */
3057c478bd9Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	free(pa);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate di_node_t
3117c478bd9Sstevel@tonic-gate di_parent_node(di_node_t node)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3167c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3177c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent) {
3257c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->parent));
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
3307c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
3317c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
3327c478bd9Sstevel@tonic-gate 	 */
3337c478bd9Sstevel@tonic-gate 	if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
3347c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
3357c478bd9Sstevel@tonic-gate 	else
3367c478bd9Sstevel@tonic-gate 		errno = ENXIO;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate di_node_t
3427c478bd9Sstevel@tonic-gate di_sibling_node(di_node_t node)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3477c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3487c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->sibling) {
3567c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->sibling));
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/*
3607c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
3617c478bd9Sstevel@tonic-gate 	 *   Sibling doesn't exist, figure out if ioctl command
3627c478bd9Sstevel@tonic-gate 	 *   has DINFOSUBTREE set. If it doesn't, set errno to
3637c478bd9Sstevel@tonic-gate 	 *   ENOTSUP.
3647c478bd9Sstevel@tonic-gate 	 */
3657c478bd9Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
3667c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
3677c478bd9Sstevel@tonic-gate 	else
3687c478bd9Sstevel@tonic-gate 		errno = ENXIO;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate di_node_t
3747c478bd9Sstevel@tonic-gate di_child_node(di_node_t node)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3817c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3827c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->child) {
3887c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->child));
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/*
3927c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
3937c478bd9Sstevel@tonic-gate 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
3947c478bd9Sstevel@tonic-gate 	 *   If it isn't, set errno to ENOTSUP.
3957c478bd9Sstevel@tonic-gate 	 */
3967c478bd9Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
3977c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
3987c478bd9Sstevel@tonic-gate 	else
3997c478bd9Sstevel@tonic-gate 		errno = ENXIO;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate di_node_t
4057c478bd9Sstevel@tonic-gate di_drv_first_node(const char *drv_name, di_node_t root)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
4087c478bd9Sstevel@tonic-gate 	int		major, devcnt;
4097c478bd9Sstevel@tonic-gate 	struct di_devnm	*devnm;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
4147c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4157c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	/*
4197c478bd9Sstevel@tonic-gate 	 * get major number of driver
4207c478bd9Sstevel@tonic-gate 	 */
4217c478bd9Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
4227c478bd9Sstevel@tonic-gate 	devcnt = DI_ALL(pa)->devcnt;
4237c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	for (major = 0; major < devcnt; major++)
4267c478bd9Sstevel@tonic-gate 		if (devnm[major].name && (strcmp(drv_name,
4277c478bd9Sstevel@tonic-gate 		    (char *)(pa + devnm[major].name)) == 0))
4287c478bd9Sstevel@tonic-gate 			break;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	if (major >= devcnt) {
4317c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4327c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (!(devnm[major].head)) {
4367c478bd9Sstevel@tonic-gate 		errno = ENXIO;
4377c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + devnm[major].head));
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate di_node_t
4447c478bd9Sstevel@tonic-gate di_drv_next_node(di_node_t node)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
4497c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4507c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "next node on per driver list:"
4547c478bd9Sstevel@tonic-gate 	    " current=%s, driver=%s\n",
4557c478bd9Sstevel@tonic-gate 	    di_node_name(node), di_driver_name(node)));
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->next == (di_off_t)-1) {
4587c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
4597c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->next == NULL) {
4657c478bd9Sstevel@tonic-gate 		errno = ENXIO;
4667c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + DI_NODE(node)->next));
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate /*
4737c478bd9Sstevel@tonic-gate  * Internal library interfaces:
4747c478bd9Sstevel@tonic-gate  *   node_list etc. for node walking
4757c478bd9Sstevel@tonic-gate  */
4767c478bd9Sstevel@tonic-gate struct node_list {
4777c478bd9Sstevel@tonic-gate 	struct node_list *next;
4787c478bd9Sstevel@tonic-gate 	di_node_t node;
4797c478bd9Sstevel@tonic-gate };
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate static void
4827c478bd9Sstevel@tonic-gate free_node_list(struct node_list **headp)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	while (*headp) {
4877c478bd9Sstevel@tonic-gate 		tmp = *headp;
4887c478bd9Sstevel@tonic-gate 		*headp = (*headp)->next;
4897c478bd9Sstevel@tonic-gate 		free(tmp);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate static void
4947c478bd9Sstevel@tonic-gate append_node_list(struct node_list **headp, struct node_list *list)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	if (*headp == NULL) {
4997c478bd9Sstevel@tonic-gate 		*headp = list;
5007c478bd9Sstevel@tonic-gate 		return;
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	if (list == NULL)	/* a minor optimization */
5047c478bd9Sstevel@tonic-gate 		return;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	tmp = *headp;
5077c478bd9Sstevel@tonic-gate 	while (tmp->next)
5087c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	tmp->next = list;
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate static void
5147c478bd9Sstevel@tonic-gate prepend_node_list(struct node_list **headp, struct node_list *list)
5157c478bd9Sstevel@tonic-gate {
5167c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if (list == NULL)
5197c478bd9Sstevel@tonic-gate 		return;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	tmp = *headp;
5227c478bd9Sstevel@tonic-gate 	*headp = list;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (tmp == NULL)	/* a minor optimization */
5257c478bd9Sstevel@tonic-gate 		return;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	while (list->next)
5287c478bd9Sstevel@tonic-gate 		list = list->next;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	list->next = tmp;
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate  * returns 1 if node is a descendant of parent, 0 otherwise
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate static int
5377c478bd9Sstevel@tonic-gate is_descendant(di_node_t node, di_node_t parent)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	/*
5407c478bd9Sstevel@tonic-gate 	 * DI_NODE_NIL is parent of root, so it is
5417c478bd9Sstevel@tonic-gate 	 * the parent of all nodes.
5427c478bd9Sstevel@tonic-gate 	 */
5437c478bd9Sstevel@tonic-gate 	if (parent == DI_NODE_NIL) {
5447c478bd9Sstevel@tonic-gate 		return (1);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	do {
5487c478bd9Sstevel@tonic-gate 		node = di_parent_node(node);
5497c478bd9Sstevel@tonic-gate 	} while ((node != DI_NODE_NIL) && (node != parent));
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	return (node != DI_NODE_NIL);
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate /*
5557c478bd9Sstevel@tonic-gate  * Insert list before the first node which is NOT a descendent of parent.
5567c478bd9Sstevel@tonic-gate  * This is needed to reproduce the exact walking order of link generators.
5577c478bd9Sstevel@tonic-gate  */
5587c478bd9Sstevel@tonic-gate static void
5597c478bd9Sstevel@tonic-gate insert_node_list(struct node_list **headp, struct node_list *list,
5607c478bd9Sstevel@tonic-gate     di_node_t parent)
5617c478bd9Sstevel@tonic-gate {
5627c478bd9Sstevel@tonic-gate 	struct node_list *tmp, *tmp1;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	if (list == NULL)
5657c478bd9Sstevel@tonic-gate 		return;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	tmp = *headp;
5687c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {	/* a minor optimization */
5697c478bd9Sstevel@tonic-gate 		*headp = list;
5707c478bd9Sstevel@tonic-gate 		return;
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (!is_descendant(tmp->node, parent)) {
5747c478bd9Sstevel@tonic-gate 		prepend_node_list(headp, list);
5757c478bd9Sstevel@tonic-gate 		return;
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/*
5797c478bd9Sstevel@tonic-gate 	 * Find first node which is not a descendant
5807c478bd9Sstevel@tonic-gate 	 */
5817c478bd9Sstevel@tonic-gate 	while (tmp->next && is_descendant(tmp->next->node, parent)) {
5827c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	tmp1 = tmp->next;
5867c478bd9Sstevel@tonic-gate 	tmp->next = list;
5877c478bd9Sstevel@tonic-gate 	append_node_list(headp, tmp1);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate  *   Get a linked list of handles of all children
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate static struct node_list *
5947c478bd9Sstevel@tonic-gate get_children(di_node_t node)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate 	di_node_t child;
5977c478bd9Sstevel@tonic-gate 	struct node_list *result, *tmp;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if ((child = di_child_node(node)) == DI_NODE_NIL) {
6027c478bd9Sstevel@tonic-gate 		return (NULL);
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if ((result = malloc(sizeof (struct node_list))) == NULL) {
6067c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
6077c478bd9Sstevel@tonic-gate 		return (NULL);
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	result->node = child;
6117c478bd9Sstevel@tonic-gate 	tmp = result;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
6147c478bd9Sstevel@tonic-gate 		if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
6157c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "malloc of node_list failed\n"));
6167c478bd9Sstevel@tonic-gate 			free_node_list(&result);
6177c478bd9Sstevel@tonic-gate 			return (NULL);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
6207c478bd9Sstevel@tonic-gate 		tmp->node = child;
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	tmp->next = NULL;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	return (result);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate /*
6297c478bd9Sstevel@tonic-gate  * Internal library interface:
6307c478bd9Sstevel@tonic-gate  *   Delete all siblings of the first node from the node_list, along with
6317c478bd9Sstevel@tonic-gate  *   the first node itself.
6327c478bd9Sstevel@tonic-gate  */
6337c478bd9Sstevel@tonic-gate static void
6347c478bd9Sstevel@tonic-gate prune_sib(struct node_list **headp)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	di_node_t parent, curr_par, curr_gpar;
6377c478bd9Sstevel@tonic-gate 	struct node_list *curr, *prev;
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	/*
6407c478bd9Sstevel@tonic-gate 	 * get handle to parent of first node
6417c478bd9Sstevel@tonic-gate 	 */
6427c478bd9Sstevel@tonic-gate 	if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
6437c478bd9Sstevel@tonic-gate 		/*
6447c478bd9Sstevel@tonic-gate 		 * This must be the root of the snapshot, so can't
6457c478bd9Sstevel@tonic-gate 		 * have any siblings.
6467c478bd9Sstevel@tonic-gate 		 *
6477c478bd9Sstevel@tonic-gate 		 * XXX Put a check here just in case.
6487c478bd9Sstevel@tonic-gate 		 */
6497c478bd9Sstevel@tonic-gate 		if ((*headp)->next)
6507c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		free(*headp);
6537c478bd9Sstevel@tonic-gate 		*headp = NULL;
6547c478bd9Sstevel@tonic-gate 		return;
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/*
6587c478bd9Sstevel@tonic-gate 	 * To be complete, we should also delete the children
6597c478bd9Sstevel@tonic-gate 	 * of siblings that have already been visited.
6607c478bd9Sstevel@tonic-gate 	 * This happens for DI_WALK_SIBFIRST when the first node
6617c478bd9Sstevel@tonic-gate 	 * is NOT the first in the linked list of siblings.
6627c478bd9Sstevel@tonic-gate 	 *
6637c478bd9Sstevel@tonic-gate 	 * Hence, we compare parent with BOTH the parent and grandparent
6647c478bd9Sstevel@tonic-gate 	 * of nodes, and delete node is a match is found.
6657c478bd9Sstevel@tonic-gate 	 */
6667c478bd9Sstevel@tonic-gate 	prev = *headp;
6677c478bd9Sstevel@tonic-gate 	curr = prev->next;
6687c478bd9Sstevel@tonic-gate 	while (curr) {
6697c478bd9Sstevel@tonic-gate 		if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) &&
6707c478bd9Sstevel@tonic-gate 		    ((curr_par == parent) || ((curr_gpar =
6717c478bd9Sstevel@tonic-gate 		    di_parent_node(curr_par)) != DI_NODE_NIL) &&
6727c478bd9Sstevel@tonic-gate 		    (curr_gpar == parent))) {
6737c478bd9Sstevel@tonic-gate 			/*
6747c478bd9Sstevel@tonic-gate 			 * match parent/grandparent: delete curr
6757c478bd9Sstevel@tonic-gate 			 */
6767c478bd9Sstevel@tonic-gate 			prev->next = curr->next;
6777c478bd9Sstevel@tonic-gate 			free(curr);
6787c478bd9Sstevel@tonic-gate 			curr = prev->next;
6797c478bd9Sstevel@tonic-gate 		} else
6807c478bd9Sstevel@tonic-gate 			curr = curr->next;
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/*
6847c478bd9Sstevel@tonic-gate 	 * delete the first node
6857c478bd9Sstevel@tonic-gate 	 */
6867c478bd9Sstevel@tonic-gate 	curr = *headp;
6877c478bd9Sstevel@tonic-gate 	*headp = curr->next;
6887c478bd9Sstevel@tonic-gate 	free(curr);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate  * Internal library function:
6937c478bd9Sstevel@tonic-gate  *	Update node list based on action (return code from callback)
6947c478bd9Sstevel@tonic-gate  *	and flag specifying walking behavior.
6957c478bd9Sstevel@tonic-gate  */
6967c478bd9Sstevel@tonic-gate static void
6977c478bd9Sstevel@tonic-gate update_node_list(int action, uint_t flag, struct node_list **headp)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	struct node_list *children, *tmp;
7007c478bd9Sstevel@tonic-gate 	di_node_t parent = di_parent_node((*headp)->node);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	switch (action) {
7037c478bd9Sstevel@tonic-gate 	case DI_WALK_TERMINATE:
7047c478bd9Sstevel@tonic-gate 		/*
7057c478bd9Sstevel@tonic-gate 		 * free the node list and be done
7067c478bd9Sstevel@tonic-gate 		 */
7077c478bd9Sstevel@tonic-gate 		children = NULL;
7087c478bd9Sstevel@tonic-gate 		free_node_list(headp);
7097c478bd9Sstevel@tonic-gate 		break;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	case DI_WALK_PRUNESIB:
7127c478bd9Sstevel@tonic-gate 		/*
7137c478bd9Sstevel@tonic-gate 		 * Get list of children and prune siblings
7147c478bd9Sstevel@tonic-gate 		 */
7157c478bd9Sstevel@tonic-gate 		children = get_children((*headp)->node);
7167c478bd9Sstevel@tonic-gate 		prune_sib(headp);
7177c478bd9Sstevel@tonic-gate 		break;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	case DI_WALK_PRUNECHILD:
7207c478bd9Sstevel@tonic-gate 		/*
7217c478bd9Sstevel@tonic-gate 		 * Set children to NULL and pop first node
7227c478bd9Sstevel@tonic-gate 		 */
7237c478bd9Sstevel@tonic-gate 		children = NULL;
7247c478bd9Sstevel@tonic-gate 		tmp = *headp;
7257c478bd9Sstevel@tonic-gate 		*headp = tmp->next;
7267c478bd9Sstevel@tonic-gate 		free(tmp);
7277c478bd9Sstevel@tonic-gate 		break;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	case DI_WALK_CONTINUE:
7307c478bd9Sstevel@tonic-gate 	default:
7317c478bd9Sstevel@tonic-gate 		/*
7327c478bd9Sstevel@tonic-gate 		 * Get list of children and pop first node
7337c478bd9Sstevel@tonic-gate 		 */
7347c478bd9Sstevel@tonic-gate 		children = get_children((*headp)->node);
7357c478bd9Sstevel@tonic-gate 		tmp = *headp;
7367c478bd9Sstevel@tonic-gate 		*headp = tmp->next;
7377c478bd9Sstevel@tonic-gate 		free(tmp);
7387c478bd9Sstevel@tonic-gate 		break;
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	/*
7427c478bd9Sstevel@tonic-gate 	 * insert the list of children
7437c478bd9Sstevel@tonic-gate 	 */
7447c478bd9Sstevel@tonic-gate 	switch (flag) {
7457c478bd9Sstevel@tonic-gate 	case DI_WALK_CLDFIRST:
7467c478bd9Sstevel@tonic-gate 		prepend_node_list(headp, children);
7477c478bd9Sstevel@tonic-gate 		break;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	case DI_WALK_SIBFIRST:
7507c478bd9Sstevel@tonic-gate 		append_node_list(headp, children);
7517c478bd9Sstevel@tonic-gate 		break;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	case DI_WALK_LINKGEN:
7547c478bd9Sstevel@tonic-gate 	default:
7557c478bd9Sstevel@tonic-gate 		insert_node_list(headp, children, parent);
7567c478bd9Sstevel@tonic-gate 		break;
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate /*
7617c478bd9Sstevel@tonic-gate  * Internal library function:
7627c478bd9Sstevel@tonic-gate  *   Invoke callback on one node and update the list of nodes to be walked
7637c478bd9Sstevel@tonic-gate  *   based on the flag and return code.
7647c478bd9Sstevel@tonic-gate  */
7657c478bd9Sstevel@tonic-gate static void
7667c478bd9Sstevel@tonic-gate walk_one_node(struct node_list **headp, uint_t flag, void *arg,
7677c478bd9Sstevel@tonic-gate 	int (*callback)(di_node_t, void *))
7687c478bd9Sstevel@tonic-gate {
7697c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	update_node_list(callback((*headp)->node, arg),
7727c478bd9Sstevel@tonic-gate 	    flag & DI_WALK_MASK, headp);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate int
7767c478bd9Sstevel@tonic-gate di_walk_node(di_node_t root, uint_t flag, void *arg,
7777c478bd9Sstevel@tonic-gate 	int (*node_callback)(di_node_t, void *))
7787c478bd9Sstevel@tonic-gate {
7797c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	if (root == NULL) {
7827c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7837c478bd9Sstevel@tonic-gate 		return (-1);
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
7877c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
7887c478bd9Sstevel@tonic-gate 		return (-1);
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	head->next = NULL;
7927c478bd9Sstevel@tonic-gate 	head->node = root;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start node walking from node %s\n",
7957c478bd9Sstevel@tonic-gate 	    di_node_name(root)));
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	while (head != NULL)
7987c478bd9Sstevel@tonic-gate 		walk_one_node(&head, flag, arg, node_callback);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	return (0);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate /*
8047c478bd9Sstevel@tonic-gate  * Internal library function:
8057c478bd9Sstevel@tonic-gate  *   Invoke callback for each minor on the minor list of first node
8067c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
8077c478bd9Sstevel@tonic-gate  *
8087c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
8097c478bd9Sstevel@tonic-gate  *   first mode.
8107c478bd9Sstevel@tonic-gate  */
8117c478bd9Sstevel@tonic-gate static void
8127c478bd9Sstevel@tonic-gate walk_one_minor_list(struct node_list **headp, const char *desired_type,
8137c478bd9Sstevel@tonic-gate 	uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate 	int ddm_type;
8167c478bd9Sstevel@tonic-gate 	int action = DI_WALK_CONTINUE;
8177c478bd9Sstevel@tonic-gate 	char *node_type;
8187c478bd9Sstevel@tonic-gate 	di_minor_t minor = DI_MINOR_NIL;
8197c478bd9Sstevel@tonic-gate 	di_node_t node = (*headp)->node;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
8227c478bd9Sstevel@tonic-gate 		ddm_type = di_minor_type(minor);
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 		if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
8257c478bd9Sstevel@tonic-gate 			continue;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 		if ((ddm_type == DDM_INTERNAL_PATH) &&
8287c478bd9Sstevel@tonic-gate 		    !(flag & DI_CHECK_INTERNAL_PATH))
8297c478bd9Sstevel@tonic-gate 			continue;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		node_type = di_minor_nodetype(minor);
8327c478bd9Sstevel@tonic-gate 		if ((desired_type != NULL) && ((node_type == NULL) ||
8337c478bd9Sstevel@tonic-gate 		    strncmp(desired_type, node_type, strlen(desired_type))
8347c478bd9Sstevel@tonic-gate 		    != 0))
8357c478bd9Sstevel@tonic-gate 			continue;
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 		if ((action = callback(node, minor, arg)) ==
8387c478bd9Sstevel@tonic-gate 		    DI_WALK_TERMINATE) {
8397c478bd9Sstevel@tonic-gate 			break;
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate int
8477c478bd9Sstevel@tonic-gate di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
8487c478bd9Sstevel@tonic-gate 	int (*minor_callback)(di_node_t, di_minor_t, void *))
8497c478bd9Sstevel@tonic-gate {
8507c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate #ifdef DEBUG
8537c478bd9Sstevel@tonic-gate 	char *path = di_devfs_path(root);
8547c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking minor nodes under %s\n", path));
8557c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
8567c478bd9Sstevel@tonic-gate #endif
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	if (root == NULL) {
8597c478bd9Sstevel@tonic-gate 		errno = EINVAL;
8607c478bd9Sstevel@tonic-gate 		return (-1);
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
8647c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
8657c478bd9Sstevel@tonic-gate 		return (-1);
8667c478bd9Sstevel@tonic-gate 	}
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	head->next = NULL;
8697c478bd9Sstevel@tonic-gate 	head->node = root;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start minor walking from node %s\n",
8727c478bd9Sstevel@tonic-gate 		di_node_name(root)));
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	while (head != NULL)
8757c478bd9Sstevel@tonic-gate 		walk_one_minor_list(&head, minor_type, flag, arg,
8767c478bd9Sstevel@tonic-gate 		    minor_callback);
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	return (0);
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate /*
8827c478bd9Sstevel@tonic-gate  * generic node parameters
8837c478bd9Sstevel@tonic-gate  *   Calling these routines always succeeds.
8847c478bd9Sstevel@tonic-gate  */
8857c478bd9Sstevel@tonic-gate char *
8867c478bd9Sstevel@tonic-gate di_node_name(di_node_t node)
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate 	return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate /* returns NULL ptr or a valid ptr to non-NULL string */
8927c478bd9Sstevel@tonic-gate char *
8937c478bd9Sstevel@tonic-gate di_bus_addr(di_node_t node)
8947c478bd9Sstevel@tonic-gate {
8957c478bd9Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->address == 0)
8987c478bd9Sstevel@tonic-gate 		return (NULL);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->address));
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate char *
9047c478bd9Sstevel@tonic-gate di_binding_name(di_node_t node)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->bind_name == 0)
9097c478bd9Sstevel@tonic-gate 		return (NULL);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->bind_name));
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate int
9157c478bd9Sstevel@tonic-gate di_compatible_names(di_node_t node, char **names)
9167c478bd9Sstevel@tonic-gate {
9177c478bd9Sstevel@tonic-gate 	char *c;
9187c478bd9Sstevel@tonic-gate 	int len, size, entries = 0;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->compat_names == 0) {
9217c478bd9Sstevel@tonic-gate 		*names = NULL;
9227c478bd9Sstevel@tonic-gate 		return (0);
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	*names = (caddr_t)node +
9267c478bd9Sstevel@tonic-gate 		DI_NODE(node)->compat_names - DI_NODE(node)->self;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	c = *names;
9297c478bd9Sstevel@tonic-gate 	len = DI_NODE(node)->compat_length;
9307c478bd9Sstevel@tonic-gate 	while (len > 0) {
9317c478bd9Sstevel@tonic-gate 		entries++;
9327c478bd9Sstevel@tonic-gate 		size = strlen(c) + 1;
9337c478bd9Sstevel@tonic-gate 		len -= size;
9347c478bd9Sstevel@tonic-gate 		c += size;
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	return (entries);
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate int
9417c478bd9Sstevel@tonic-gate di_instance(di_node_t node)
9427c478bd9Sstevel@tonic-gate {
9437c478bd9Sstevel@tonic-gate 	return (DI_NODE(node)->instance);
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate /*
9477c478bd9Sstevel@tonic-gate  * XXX: emulate the return value of the old implementation
9487c478bd9Sstevel@tonic-gate  * using info from devi_node_class and devi_node_attributes.
9497c478bd9Sstevel@tonic-gate  */
9507c478bd9Sstevel@tonic-gate int
9517c478bd9Sstevel@tonic-gate di_nodeid(di_node_t node)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->node_class == DDI_NC_PROM)
9547c478bd9Sstevel@tonic-gate 		return (DI_PROM_NODEID);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->attributes & DDI_PERSISTENT)
9577c478bd9Sstevel@tonic-gate 		return (DI_SID_NODEID);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	return (DI_PSEUDO_NODEID);
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate uint_t
9637c478bd9Sstevel@tonic-gate di_state(di_node_t node)
9647c478bd9Sstevel@tonic-gate {
9657c478bd9Sstevel@tonic-gate 	uint_t result = 0;
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	if (di_node_state(node) < DS_ATTACHED)
9687c478bd9Sstevel@tonic-gate 		result |= DI_DRIVER_DETACHED;
9697c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
9707c478bd9Sstevel@tonic-gate 		result |= DI_DEVICE_OFFLINE;
9717c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
9727c478bd9Sstevel@tonic-gate 		result |= DI_DEVICE_OFFLINE;
9737c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
9747c478bd9Sstevel@tonic-gate 		result |= DI_BUS_QUIESCED;
9757c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_DOWN)
9767c478bd9Sstevel@tonic-gate 		result |= DI_BUS_DOWN;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	return (result);
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate ddi_node_state_t
9827c478bd9Sstevel@tonic-gate di_node_state(di_node_t node)
9837c478bd9Sstevel@tonic-gate {
9847c478bd9Sstevel@tonic-gate 	return (DI_NODE(node)->node_state);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate ddi_devid_t
9887c478bd9Sstevel@tonic-gate di_devid(di_node_t node)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->devid == 0)
9917c478bd9Sstevel@tonic-gate 		return (NULL);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	return ((ddi_devid_t)((caddr_t)node +
9947c478bd9Sstevel@tonic-gate 	    DI_NODE(node)->devid - DI_NODE(node)->self));
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate int
9987c478bd9Sstevel@tonic-gate di_driver_major(di_node_t node)
9997c478bd9Sstevel@tonic-gate {
10007c478bd9Sstevel@tonic-gate 	int major;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10037c478bd9Sstevel@tonic-gate 	if (major < 0)
10047c478bd9Sstevel@tonic-gate 		return (-1);
10057c478bd9Sstevel@tonic-gate 	return (major);
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate char *
10097c478bd9Sstevel@tonic-gate di_driver_name(di_node_t node)
10107c478bd9Sstevel@tonic-gate {
10117c478bd9Sstevel@tonic-gate 	int major;
10127c478bd9Sstevel@tonic-gate 	caddr_t pa;
10137c478bd9Sstevel@tonic-gate 	struct di_devnm *devnm;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10167c478bd9Sstevel@tonic-gate 	if (major < 0)
10177c478bd9Sstevel@tonic-gate 		return (NULL);
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
10207c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	if (devnm[major].name)
10237c478bd9Sstevel@tonic-gate 		return (pa + devnm[major].name);
10247c478bd9Sstevel@tonic-gate 	else
10257c478bd9Sstevel@tonic-gate 		return (NULL);
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate uint_t
10297c478bd9Sstevel@tonic-gate di_driver_ops(di_node_t node)
10307c478bd9Sstevel@tonic-gate {
10317c478bd9Sstevel@tonic-gate 	int major;
10327c478bd9Sstevel@tonic-gate 	caddr_t pa;
10337c478bd9Sstevel@tonic-gate 	struct di_devnm *devnm;
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10367c478bd9Sstevel@tonic-gate 	if (major < 0)
10377c478bd9Sstevel@tonic-gate 		return (0);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
10407c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	return (devnm[major].ops);
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate  * returns the length of the path, caller must free memory
10477c478bd9Sstevel@tonic-gate  */
10487c478bd9Sstevel@tonic-gate char *
10497c478bd9Sstevel@tonic-gate di_devfs_path(di_node_t node)
10507c478bd9Sstevel@tonic-gate {
10517c478bd9Sstevel@tonic-gate 	caddr_t pa;
10527c478bd9Sstevel@tonic-gate 	di_node_t parent;
10537c478bd9Sstevel@tonic-gate 	int depth = 0, len = 0;
10547c478bd9Sstevel@tonic-gate 	char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH];
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
10577c478bd9Sstevel@tonic-gate 		errno = EINVAL;
10587c478bd9Sstevel@tonic-gate 		return (NULL);
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	/*
10627c478bd9Sstevel@tonic-gate 	 * trace back to root, note the node_name & address
10637c478bd9Sstevel@tonic-gate 	 */
10647c478bd9Sstevel@tonic-gate 	while ((parent = di_parent_node(node)) != DI_NODE_NIL) {
10657c478bd9Sstevel@tonic-gate 		name[depth] = di_node_name(node);
10667c478bd9Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;		/* 1 for '/' */
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		if ((addr[depth] = di_bus_addr(node)) != NULL)
10697c478bd9Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;	/* 1 for '@' */
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 		node = parent;
10727c478bd9Sstevel@tonic-gate 		depth++;
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/*
10767c478bd9Sstevel@tonic-gate 	 * get the path to the root of snapshot
10777c478bd9Sstevel@tonic-gate 	 */
10787c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
10797c478bd9Sstevel@tonic-gate 	name[depth] = DI_ALL(pa)->root_path;
10807c478bd9Sstevel@tonic-gate 	len += strlen(name[depth]) + 1;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	/*
10837c478bd9Sstevel@tonic-gate 	 * allocate buffer and assemble path
10847c478bd9Sstevel@tonic-gate 	 */
10857c478bd9Sstevel@tonic-gate 	if ((buf = malloc(len)) == NULL) {
10867c478bd9Sstevel@tonic-gate 		return (NULL);
10877c478bd9Sstevel@tonic-gate 	}
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, name[depth]);
10907c478bd9Sstevel@tonic-gate 	len = strlen(buf);
10917c478bd9Sstevel@tonic-gate 	if (buf[len - 1] == '/')
10927c478bd9Sstevel@tonic-gate 		len--;	/* delete trailing '/' */
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	while (depth) {
10957c478bd9Sstevel@tonic-gate 		depth--;
10967c478bd9Sstevel@tonic-gate 		buf[len] = '/';
10977c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, name[depth]);
10987c478bd9Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;
10997c478bd9Sstevel@tonic-gate 		if (addr[depth] && addr[depth][0] != '\0') {
11007c478bd9Sstevel@tonic-gate 			buf[len] = '@';
11017c478bd9Sstevel@tonic-gate 			(void) strcpy(buf + len + 1, addr[depth]);
11027c478bd9Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;
11037c478bd9Sstevel@tonic-gate 		}
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	return (buf);
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate char *
11107c478bd9Sstevel@tonic-gate di_devfs_minor_path(di_minor_t minor)
11117c478bd9Sstevel@tonic-gate {
11127c478bd9Sstevel@tonic-gate 	di_node_t	node;
11137c478bd9Sstevel@tonic-gate 	char		*full_path, *name, *path;
11147c478bd9Sstevel@tonic-gate 	int		full_path_len;
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
11177c478bd9Sstevel@tonic-gate 		errno = EINVAL;
11187c478bd9Sstevel@tonic-gate 		return (NULL);
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	name = di_minor_name(minor);
11227c478bd9Sstevel@tonic-gate 	node = di_minor_devinfo(minor);
11237c478bd9Sstevel@tonic-gate 	path = di_devfs_path(node);
11247c478bd9Sstevel@tonic-gate 	if (path == NULL)
11257c478bd9Sstevel@tonic-gate 		return (NULL);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	/* make the full path to the device minor node */
11287c478bd9Sstevel@tonic-gate 	full_path_len = strlen(path) + strlen(name) + 2;
11297c478bd9Sstevel@tonic-gate 	full_path = (char *)calloc(1, full_path_len);
11307c478bd9Sstevel@tonic-gate 	if (full_path != NULL)
11317c478bd9Sstevel@tonic-gate 		(void) snprintf(full_path, full_path_len, "%s:%s", path, name);
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
11347c478bd9Sstevel@tonic-gate 	return (full_path);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate void
11387c478bd9Sstevel@tonic-gate di_devfs_path_free(char *buf)
11397c478bd9Sstevel@tonic-gate {
11407c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
11417c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
11427c478bd9Sstevel@tonic-gate 		return;
11437c478bd9Sstevel@tonic-gate 	}
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	free(buf);
11467c478bd9Sstevel@tonic-gate }
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate /* minor data access */
11497c478bd9Sstevel@tonic-gate di_minor_t
11507c478bd9Sstevel@tonic-gate di_minor_next(di_node_t node, di_minor_t minor)
11517c478bd9Sstevel@tonic-gate {
11527c478bd9Sstevel@tonic-gate 	caddr_t pa;
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	/*
11557c478bd9Sstevel@tonic-gate 	 * paranoid error checking
11567c478bd9Sstevel@tonic-gate 	 */
11577c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
11587c478bd9Sstevel@tonic-gate 		errno = EINVAL;
11597c478bd9Sstevel@tonic-gate 		return (DI_MINOR_NIL);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	/*
11637c478bd9Sstevel@tonic-gate 	 * minor is not NIL
11647c478bd9Sstevel@tonic-gate 	 */
11657c478bd9Sstevel@tonic-gate 	if (minor != DI_MINOR_NIL) {
11667c478bd9Sstevel@tonic-gate 		if (DI_MINOR(minor)->next != 0)
11677c478bd9Sstevel@tonic-gate 			return ((di_minor_t)((void *)((caddr_t)minor -
11687c478bd9Sstevel@tonic-gate 			    DI_MINOR(minor)->self + DI_MINOR(minor)->next)));
11697c478bd9Sstevel@tonic-gate 		else {
11707c478bd9Sstevel@tonic-gate 			errno = ENXIO;
11717c478bd9Sstevel@tonic-gate 			return (DI_MINOR_NIL);
11727c478bd9Sstevel@tonic-gate 		}
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	/*
11767c478bd9Sstevel@tonic-gate 	 * minor is NIL-->caller asks for first minor node
11777c478bd9Sstevel@tonic-gate 	 */
11787c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->minor_data != 0) {
11797c478bd9Sstevel@tonic-gate 		return (DI_MINOR((caddr_t)node - DI_NODE(node)->self +
11807c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->minor_data));
11817c478bd9Sstevel@tonic-gate 	}
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	/*
11847c478bd9Sstevel@tonic-gate 	 * no minor data-->check if snapshot includes minor data
11857c478bd9Sstevel@tonic-gate 	 *	in order to set the correct errno
11867c478bd9Sstevel@tonic-gate 	 */
11877c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
11887c478bd9Sstevel@tonic-gate 	if (DINFOMINOR & DI_ALL(pa)->command)
11897c478bd9Sstevel@tonic-gate 		errno = ENXIO;
11907c478bd9Sstevel@tonic-gate 	else
11917c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	return (DI_MINOR_NIL);
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate /* private interface for dealing with alias minor link generation */
11977c478bd9Sstevel@tonic-gate di_node_t
11987c478bd9Sstevel@tonic-gate di_minor_devinfo(di_minor_t minor)
11997c478bd9Sstevel@tonic-gate {
12007c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
12017c478bd9Sstevel@tonic-gate 		errno = EINVAL;
12027c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
12067c478bd9Sstevel@tonic-gate 	    DI_MINOR(minor)->node));
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate ddi_minor_type
12107c478bd9Sstevel@tonic-gate di_minor_type(di_minor_t minor)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate 	return (DI_MINOR(minor)->type);
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate char *
12167c478bd9Sstevel@tonic-gate di_minor_name(di_minor_t minor)
12177c478bd9Sstevel@tonic-gate {
12187c478bd9Sstevel@tonic-gate 	if (DI_MINOR(minor)->name == 0)
12197c478bd9Sstevel@tonic-gate 		return (NULL);
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
12227c478bd9Sstevel@tonic-gate }
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate dev_t
12257c478bd9Sstevel@tonic-gate di_minor_devt(di_minor_t minor)
12267c478bd9Sstevel@tonic-gate {
12277c478bd9Sstevel@tonic-gate 	return (makedev(DI_MINOR(minor)->dev_major,
12287c478bd9Sstevel@tonic-gate 		DI_MINOR(minor)->dev_minor));
12297c478bd9Sstevel@tonic-gate }
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate int
12327c478bd9Sstevel@tonic-gate di_minor_spectype(di_minor_t minor)
12337c478bd9Sstevel@tonic-gate {
12347c478bd9Sstevel@tonic-gate 	return (DI_MINOR(minor)->spec_type);
12357c478bd9Sstevel@tonic-gate }
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate char *
12387c478bd9Sstevel@tonic-gate di_minor_nodetype(di_minor_t minor)
12397c478bd9Sstevel@tonic-gate {
12407c478bd9Sstevel@tonic-gate 	if (DI_MINOR(minor)->node_type == 0)
12417c478bd9Sstevel@tonic-gate 		return (NULL);
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	return ((caddr_t)minor -
12447c478bd9Sstevel@tonic-gate 		DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate /*
12487c478bd9Sstevel@tonic-gate  * Single public interface for accessing software properties
12497c478bd9Sstevel@tonic-gate  */
12507c478bd9Sstevel@tonic-gate di_prop_t
12517c478bd9Sstevel@tonic-gate di_prop_next(di_node_t node, di_prop_t prop)
12527c478bd9Sstevel@tonic-gate {
12537c478bd9Sstevel@tonic-gate 	int list = DI_PROP_DRV_LIST;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	/*
12567c478bd9Sstevel@tonic-gate 	 * paranoid check
12577c478bd9Sstevel@tonic-gate 	 */
12587c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
12597c478bd9Sstevel@tonic-gate 		errno = EINVAL;
12607c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
12617c478bd9Sstevel@tonic-gate 	}
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 	/*
12647c478bd9Sstevel@tonic-gate 	 * Find which prop list we are at
12657c478bd9Sstevel@tonic-gate 	 */
12667c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL)
12677c478bd9Sstevel@tonic-gate 		list = DI_PROP(prop)->prop_list;
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	do {
12707c478bd9Sstevel@tonic-gate 		switch (list++) {
12717c478bd9Sstevel@tonic-gate 		case DI_PROP_DRV_LIST:
12727c478bd9Sstevel@tonic-gate 			prop = di_prop_drv_next(node, prop);
12737c478bd9Sstevel@tonic-gate 			break;
12747c478bd9Sstevel@tonic-gate 		case DI_PROP_SYS_LIST:
12757c478bd9Sstevel@tonic-gate 			prop = di_prop_sys_next(node, prop);
12767c478bd9Sstevel@tonic-gate 			break;
12777c478bd9Sstevel@tonic-gate 		case DI_PROP_GLB_LIST:
12787c478bd9Sstevel@tonic-gate 			prop = di_prop_global_next(node, prop);
12797c478bd9Sstevel@tonic-gate 			break;
12807c478bd9Sstevel@tonic-gate 		case DI_PROP_HW_LIST:
12817c478bd9Sstevel@tonic-gate 			prop = di_prop_hw_next(node, prop);
12827c478bd9Sstevel@tonic-gate 			break;
12837c478bd9Sstevel@tonic-gate 		default:	/* shouldn't happen */
12847c478bd9Sstevel@tonic-gate 			errno = EFAULT;
12857c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
12867c478bd9Sstevel@tonic-gate 		}
12877c478bd9Sstevel@tonic-gate 	} while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	return (prop);
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate dev_t
12937c478bd9Sstevel@tonic-gate di_prop_devt(di_prop_t prop)
12947c478bd9Sstevel@tonic-gate {
12957c478bd9Sstevel@tonic-gate 	return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate char *
12997c478bd9Sstevel@tonic-gate di_prop_name(di_prop_t prop)
13007c478bd9Sstevel@tonic-gate {
13017c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_name == 0)
13027c478bd9Sstevel@tonic-gate 		return (NULL);
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate int
13087c478bd9Sstevel@tonic-gate di_prop_type(di_prop_t prop)
13097c478bd9Sstevel@tonic-gate {
13107c478bd9Sstevel@tonic-gate 	uint_t flags = DI_PROP(prop)->prop_flags;
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_UNDEF_IT)
13137c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNDEF_IT);
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
13167c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_BOOLEAN);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
13197c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNKNOWN);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT)
13227c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT);
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT64)
13257c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT64);
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_STRING)
13287c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_STRING);
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_BYTE)
13317c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_BYTE);
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	/*
13347c478bd9Sstevel@tonic-gate 	 * Shouldn't get here. In case we do, return unknown type.
13357c478bd9Sstevel@tonic-gate 	 *
13367c478bd9Sstevel@tonic-gate 	 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
13377c478bd9Sstevel@tonic-gate 	 *	to add DI_PROP_TYPE_COMPOSITE.
13387c478bd9Sstevel@tonic-gate 	 */
13397c478bd9Sstevel@tonic-gate 	DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
13427c478bd9Sstevel@tonic-gate }
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate /*
13457c478bd9Sstevel@tonic-gate  * Extract type-specific values of an property
13467c478bd9Sstevel@tonic-gate  */
13477c478bd9Sstevel@tonic-gate extern int di_prop_decode_common(void *prop_data, int len,
13487c478bd9Sstevel@tonic-gate 	int ddi_type, int prom);
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate int
13517c478bd9Sstevel@tonic-gate di_prop_ints(di_prop_t prop, int **prop_data)
13527c478bd9Sstevel@tonic-gate {
13537c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
13547c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
13577c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
13587c478bd9Sstevel@tonic-gate 		errno = EFAULT;
13597c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
13607c478bd9Sstevel@tonic-gate 		return (-1);
13617c478bd9Sstevel@tonic-gate 	}
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
13647c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
13677c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
13687c478bd9Sstevel@tonic-gate }
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate int
13717c478bd9Sstevel@tonic-gate di_prop_int64(di_prop_t prop, int64_t **prop_data)
13727c478bd9Sstevel@tonic-gate {
13737c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
13747c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
13777c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
13787c478bd9Sstevel@tonic-gate 		errno = EFAULT;
13797c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
13807c478bd9Sstevel@tonic-gate 		return (-1);
13817c478bd9Sstevel@tonic-gate 	}
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
13847c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
13877c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate int
13917c478bd9Sstevel@tonic-gate di_prop_strings(di_prop_t prop, char **prop_data)
13927c478bd9Sstevel@tonic-gate {
13937c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
13947c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
13977c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
13987c478bd9Sstevel@tonic-gate 		errno = EFAULT;
13997c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
14007c478bd9Sstevel@tonic-gate 		return (-1);
14017c478bd9Sstevel@tonic-gate 	}
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
14047c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
14077c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate int
14117c478bd9Sstevel@tonic-gate di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
14127c478bd9Sstevel@tonic-gate {
14137c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
14147c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
14177c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
14187c478bd9Sstevel@tonic-gate 		errno = EFAULT;
14197c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
14207c478bd9Sstevel@tonic-gate 		return (-1);
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
14247c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
14277c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate /*
14317c478bd9Sstevel@tonic-gate  * returns 1 for match, 0 for no match
14327c478bd9Sstevel@tonic-gate  */
14337c478bd9Sstevel@tonic-gate static int
14347c478bd9Sstevel@tonic-gate match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
14357c478bd9Sstevel@tonic-gate {
14367c478bd9Sstevel@tonic-gate 	int prop_type;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate #ifdef DEBUG
14397c478bd9Sstevel@tonic-gate 	if (di_prop_name(prop) == NULL) {
14407c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
14417c478bd9Sstevel@tonic-gate 		return (0);
14427c478bd9Sstevel@tonic-gate 	}
14437c478bd9Sstevel@tonic-gate #endif /* DEBUG */
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	if (strcmp(name, di_prop_name(prop)) != 0)
14467c478bd9Sstevel@tonic-gate 		return (0);
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
14497c478bd9Sstevel@tonic-gate 		return (0);
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	/*
14527c478bd9Sstevel@tonic-gate 	 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
14537c478bd9Sstevel@tonic-gate 	 */
14547c478bd9Sstevel@tonic-gate 	prop_type = di_prop_type(prop);
14557c478bd9Sstevel@tonic-gate 	if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) &&
14567c478bd9Sstevel@tonic-gate 	    (prop_type != DI_PROP_TYPE_BOOLEAN))
14577c478bd9Sstevel@tonic-gate 		return (0);
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	return (1);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate static di_prop_t
14637c478bd9Sstevel@tonic-gate di_prop_search(dev_t match_dev, di_node_t node, const char *name,
14647c478bd9Sstevel@tonic-gate     int type)
14657c478bd9Sstevel@tonic-gate {
14667c478bd9Sstevel@tonic-gate 	di_prop_t prop = DI_PROP_NIL;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	/*
14697c478bd9Sstevel@tonic-gate 	 * The check on match_dev follows ddi_prop_lookup_common().
14707c478bd9Sstevel@tonic-gate 	 * Other checks are libdevinfo specific implementation.
14717c478bd9Sstevel@tonic-gate 	 */
14727c478bd9Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
14737c478bd9Sstevel@tonic-gate 	    (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) {
14747c478bd9Sstevel@tonic-gate 		errno = EINVAL;
14757c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
14767c478bd9Sstevel@tonic-gate 	}
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
14797c478bd9Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n",
14807c478bd9Sstevel@tonic-gate 		    di_prop_name(prop), di_prop_devt(prop),
14817c478bd9Sstevel@tonic-gate 		    di_prop_type(prop)));
14827c478bd9Sstevel@tonic-gate 		if (match_prop(prop, match_dev, name, type))
14837c478bd9Sstevel@tonic-gate 			return (prop);
14847c478bd9Sstevel@tonic-gate 	}
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate 
1489*3ebafc43Sjveta di_prop_t
1490*3ebafc43Sjveta di_prop_find(dev_t match_dev, di_node_t node, const char *name)
1491*3ebafc43Sjveta {
1492*3ebafc43Sjveta 	di_prop_t prop = DI_PROP_NIL;
1493*3ebafc43Sjveta 
1494*3ebafc43Sjveta 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
1495*3ebafc43Sjveta 	    (match_dev == DDI_DEV_T_NONE)) {
1496*3ebafc43Sjveta 		errno = EINVAL;
1497*3ebafc43Sjveta 		return (DI_PROP_NIL);
1498*3ebafc43Sjveta 	}
1499*3ebafc43Sjveta 
1500*3ebafc43Sjveta 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
1501*3ebafc43Sjveta 		DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n",
1502*3ebafc43Sjveta 		    di_prop_name(prop), di_prop_devt(prop),
1503*3ebafc43Sjveta 		    di_prop_type(prop)));
1504*3ebafc43Sjveta 
1505*3ebafc43Sjveta 		if (strcmp(name, di_prop_name(prop)) == 0 &&
1506*3ebafc43Sjveta 		    (match_dev == DDI_DEV_T_ANY ||
1507*3ebafc43Sjveta 		    di_prop_devt(prop) == match_dev))
1508*3ebafc43Sjveta 			return (prop);
1509*3ebafc43Sjveta 	}
1510*3ebafc43Sjveta 
1511*3ebafc43Sjveta 	return (DI_PROP_NIL);
1512*3ebafc43Sjveta }
1513*3ebafc43Sjveta 
15147c478bd9Sstevel@tonic-gate int
15157c478bd9Sstevel@tonic-gate di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
15167c478bd9Sstevel@tonic-gate 	int **prop_data)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate 	di_prop_t prop;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
15217c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
15227c478bd9Sstevel@tonic-gate 		return (-1);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	return (di_prop_ints(prop, (void *)prop_data));
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate int
15287c478bd9Sstevel@tonic-gate di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
15297c478bd9Sstevel@tonic-gate 	int64_t **prop_data)
15307c478bd9Sstevel@tonic-gate {
15317c478bd9Sstevel@tonic-gate 	di_prop_t prop;
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
15347c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
15357c478bd9Sstevel@tonic-gate 		return (-1);
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	return (di_prop_int64(prop, (void *)prop_data));
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate int
15417c478bd9Sstevel@tonic-gate di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
15427c478bd9Sstevel@tonic-gate     char **prop_data)
15437c478bd9Sstevel@tonic-gate {
15447c478bd9Sstevel@tonic-gate 	di_prop_t prop;
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
15477c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
15487c478bd9Sstevel@tonic-gate 		return (-1);
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	return (di_prop_strings(prop, (void *)prop_data));
15517c478bd9Sstevel@tonic-gate }
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate int
15547c478bd9Sstevel@tonic-gate di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
15557c478bd9Sstevel@tonic-gate 	uchar_t **prop_data)
15567c478bd9Sstevel@tonic-gate {
15577c478bd9Sstevel@tonic-gate 	di_prop_t prop;
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
15607c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
15617c478bd9Sstevel@tonic-gate 		return (-1);
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	return (di_prop_bytes(prop, (void *)prop_data));
15647c478bd9Sstevel@tonic-gate }
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate /*
15677c478bd9Sstevel@tonic-gate  * Consolidation private property access functions
15687c478bd9Sstevel@tonic-gate  */
15697c478bd9Sstevel@tonic-gate enum prop_type {
15707c478bd9Sstevel@tonic-gate 	PROP_TYPE_DRV,
15717c478bd9Sstevel@tonic-gate 	PROP_TYPE_SYS,
15727c478bd9Sstevel@tonic-gate 	PROP_TYPE_GLOB,
15737c478bd9Sstevel@tonic-gate 	PROP_TYPE_HW
15747c478bd9Sstevel@tonic-gate };
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate static di_prop_t
15777c478bd9Sstevel@tonic-gate di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
15787c478bd9Sstevel@tonic-gate {
15797c478bd9Sstevel@tonic-gate 	caddr_t pa;
15807c478bd9Sstevel@tonic-gate 	di_off_t prop_off = 0;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
15837c478bd9Sstevel@tonic-gate 		if (DI_PROP(prop)->next) {
15847c478bd9Sstevel@tonic-gate 			return (DI_PROP((caddr_t)prop -
15857c478bd9Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
15867c478bd9Sstevel@tonic-gate 		} else {
15877c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
15887c478bd9Sstevel@tonic-gate 		}
15897c478bd9Sstevel@tonic-gate 	}
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	/*
15937c478bd9Sstevel@tonic-gate 	 * prop is NIL, caller asks for first property
15947c478bd9Sstevel@tonic-gate 	 */
15957c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
15967c478bd9Sstevel@tonic-gate 	switch (prop_type) {
15977c478bd9Sstevel@tonic-gate 	case PROP_TYPE_DRV:
15987c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->drv_prop;
15997c478bd9Sstevel@tonic-gate 		break;
16007c478bd9Sstevel@tonic-gate 	case PROP_TYPE_SYS:
16017c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->sys_prop;
16027c478bd9Sstevel@tonic-gate 		break;
16037c478bd9Sstevel@tonic-gate 	case PROP_TYPE_HW:
16047c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->hw_prop;
16057c478bd9Sstevel@tonic-gate 		break;
16067c478bd9Sstevel@tonic-gate 	case PROP_TYPE_GLOB:
16077c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->glob_prop;
16087c478bd9Sstevel@tonic-gate 		if (prop_off == -1) {
16097c478bd9Sstevel@tonic-gate 			/* no global property */
16107c478bd9Sstevel@tonic-gate 			prop_off = 0;
16117c478bd9Sstevel@tonic-gate 		} else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) {
16127c478bd9Sstevel@tonic-gate 			/* refer to devnames array */
16137c478bd9Sstevel@tonic-gate 			struct di_devnm *devnm = DI_DEVNM(pa +
16147c478bd9Sstevel@tonic-gate 			    DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major *
16157c478bd9Sstevel@tonic-gate 			    sizeof (struct di_devnm)));
16167c478bd9Sstevel@tonic-gate 			prop_off = devnm->global_prop;
16177c478bd9Sstevel@tonic-gate 		}
16187c478bd9Sstevel@tonic-gate 		break;
16197c478bd9Sstevel@tonic-gate 	}
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 	if (prop_off) {
16227c478bd9Sstevel@tonic-gate 		return (DI_PROP(pa + prop_off));
16237c478bd9Sstevel@tonic-gate 	}
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 	/*
16267c478bd9Sstevel@tonic-gate 	 * no prop found. Check the reason for not found
16277c478bd9Sstevel@tonic-gate 	 */
16287c478bd9Sstevel@tonic-gate 	if (DINFOPROP & DI_ALL(pa)->command)
16297c478bd9Sstevel@tonic-gate 		errno = ENXIO;
16307c478bd9Sstevel@tonic-gate 	else
16317c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate di_prop_t
16377c478bd9Sstevel@tonic-gate di_prop_drv_next(di_node_t node, di_prop_t prop)
16387c478bd9Sstevel@tonic-gate {
16397c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate di_prop_t
16437c478bd9Sstevel@tonic-gate di_prop_sys_next(di_node_t node, di_prop_t prop)
16447c478bd9Sstevel@tonic-gate {
16457c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate di_prop_t
16497c478bd9Sstevel@tonic-gate di_prop_global_next(di_node_t node, di_prop_t prop)
16507c478bd9Sstevel@tonic-gate {
16517c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate di_prop_t
16557c478bd9Sstevel@tonic-gate di_prop_hw_next(di_node_t node, di_prop_t prop)
16567c478bd9Sstevel@tonic-gate {
16577c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_HW));
16587c478bd9Sstevel@tonic-gate }
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate int
16617c478bd9Sstevel@tonic-gate di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
16627c478bd9Sstevel@tonic-gate {
16637c478bd9Sstevel@tonic-gate #ifdef DEBUG
16647c478bd9Sstevel@tonic-gate 	if (prop == DI_PROP_NIL) {
16657c478bd9Sstevel@tonic-gate 		errno = EINVAL;
16667c478bd9Sstevel@tonic-gate 		return (-1);
16677c478bd9Sstevel@tonic-gate 	}
16687c478bd9Sstevel@tonic-gate #endif /* DEBUG */
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0) {
16717c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
16727c478bd9Sstevel@tonic-gate 		return (0);
16737c478bd9Sstevel@tonic-gate 	}
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
16767c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
16777c478bd9Sstevel@tonic-gate 		errno = EFAULT;
16787c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
16797c478bd9Sstevel@tonic-gate 		return (-1);
16807c478bd9Sstevel@tonic-gate 	}
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	/*
16837c478bd9Sstevel@tonic-gate 	 * No memory allocation.
16847c478bd9Sstevel@tonic-gate 	 */
16857c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
16867c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_data);
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	return (DI_PROP(prop)->prop_len);
16897c478bd9Sstevel@tonic-gate }
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate /*
16927c478bd9Sstevel@tonic-gate  * Consolidation private interfaces for accessing I/O multipathing data
16937c478bd9Sstevel@tonic-gate  */
16947c478bd9Sstevel@tonic-gate di_path_t
16957c478bd9Sstevel@tonic-gate di_path_next_client(di_node_t node, di_path_t path)
16967c478bd9Sstevel@tonic-gate {
16977c478bd9Sstevel@tonic-gate 	caddr_t pa;
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	/*
17007c478bd9Sstevel@tonic-gate 	 * path is not NIL
17017c478bd9Sstevel@tonic-gate 	 */
17027c478bd9Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
17037c478bd9Sstevel@tonic-gate 		if (DI_PATH(path)->path_p_link != 0)
17047c478bd9Sstevel@tonic-gate 			return (DI_PATH((void *)((caddr_t)path -
17057c478bd9Sstevel@tonic-gate 			    DI_PATH(path)->self + DI_PATH(path)->path_p_link)));
17067c478bd9Sstevel@tonic-gate 		else {
17077c478bd9Sstevel@tonic-gate 			errno = ENXIO;
17087c478bd9Sstevel@tonic-gate 			return (DI_PATH_NIL);
17097c478bd9Sstevel@tonic-gate 		}
17107c478bd9Sstevel@tonic-gate 	}
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 	/*
17137c478bd9Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
17147c478bd9Sstevel@tonic-gate 	 */
17157c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_phci != 0) {
17167c478bd9Sstevel@tonic-gate 		DPRINTF((DI_INFO, "phci: returning %p\n", ((caddr_t)node -
17177c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
17187c478bd9Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
17197c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->multipath_phci));
17207c478bd9Sstevel@tonic-gate 	}
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 	/*
17237c478bd9Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
17247c478bd9Sstevel@tonic-gate 	 * to set errno properly.
17257c478bd9Sstevel@tonic-gate 	 */
17267c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
17277c478bd9Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
17287c478bd9Sstevel@tonic-gate 		errno = ENXIO;
17297c478bd9Sstevel@tonic-gate 	else
17307c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	return (DI_PATH_NIL);
17337c478bd9Sstevel@tonic-gate }
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate di_path_t
17367c478bd9Sstevel@tonic-gate di_path_next_phci(di_node_t node, di_path_t path)
17377c478bd9Sstevel@tonic-gate {
17387c478bd9Sstevel@tonic-gate 	caddr_t pa;
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 	/*
17417c478bd9Sstevel@tonic-gate 	 * path is not NIL
17427c478bd9Sstevel@tonic-gate 	 */
17437c478bd9Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
17447c478bd9Sstevel@tonic-gate 		if (DI_PATH(path)->path_c_link != 0)
17457c478bd9Sstevel@tonic-gate 			return (DI_PATH((caddr_t)path - DI_PATH(path)->self
17467c478bd9Sstevel@tonic-gate 			    + DI_PATH(path)->path_c_link));
17477c478bd9Sstevel@tonic-gate 		else {
17487c478bd9Sstevel@tonic-gate 			errno = ENXIO;
17497c478bd9Sstevel@tonic-gate 			return (DI_PATH_NIL);
17507c478bd9Sstevel@tonic-gate 		}
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	/*
17547c478bd9Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
17557c478bd9Sstevel@tonic-gate 	 */
17567c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_client != 0) {
17577c478bd9Sstevel@tonic-gate 		DPRINTF((DI_INFO, "client: returning %p\n", ((caddr_t)node -
17587c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
17597c478bd9Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
17607c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->multipath_client));
17617c478bd9Sstevel@tonic-gate 	}
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 	/*
17647c478bd9Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
17657c478bd9Sstevel@tonic-gate 	 * to set errno properly.
17667c478bd9Sstevel@tonic-gate 	 */
17677c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
17687c478bd9Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
17697c478bd9Sstevel@tonic-gate 		errno = ENXIO;
17707c478bd9Sstevel@tonic-gate 	else
17717c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	return (DI_PATH_NIL);
17747c478bd9Sstevel@tonic-gate }
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate /*
17777c478bd9Sstevel@tonic-gate  * XXX Obsolete wrapper to be removed. Won't work under multilevel.
17787c478bd9Sstevel@tonic-gate  */
17797c478bd9Sstevel@tonic-gate di_path_t
17807c478bd9Sstevel@tonic-gate di_path_next(di_node_t node, di_path_t path)
17817c478bd9Sstevel@tonic-gate {
17827c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
17837c478bd9Sstevel@tonic-gate 		errno = EINVAL;
17847c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
17857c478bd9Sstevel@tonic-gate 	}
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_client) {
17887c478bd9Sstevel@tonic-gate 		return (di_path_next_phci(node, path));
17897c478bd9Sstevel@tonic-gate 	} else if (DI_NODE(node)->multipath_phci) {
17907c478bd9Sstevel@tonic-gate 		return (di_path_next_client(node, path));
17917c478bd9Sstevel@tonic-gate 	} else {
17927c478bd9Sstevel@tonic-gate 		/*
17937c478bd9Sstevel@tonic-gate 		 * The node had multipathing data but didn't appear to be a
17947c478bd9Sstevel@tonic-gate 		 * phci *or* a client; probably a programmer error.
17957c478bd9Sstevel@tonic-gate 		 */
17967c478bd9Sstevel@tonic-gate 		errno = EINVAL;
17977c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
17987c478bd9Sstevel@tonic-gate 	}
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate di_path_state_t
18027c478bd9Sstevel@tonic-gate di_path_state(di_path_t path)
18037c478bd9Sstevel@tonic-gate {
18047c478bd9Sstevel@tonic-gate 	return ((di_path_state_t)DI_PATH(path)->path_state);
18057c478bd9Sstevel@tonic-gate }
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate char *
18087c478bd9Sstevel@tonic-gate di_path_addr(di_path_t path, char *buf)
18097c478bd9Sstevel@tonic-gate {
18107c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
18157c478bd9Sstevel@tonic-gate 	    MAXPATHLEN);
18167c478bd9Sstevel@tonic-gate 	return (buf);
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate di_node_t
18207c478bd9Sstevel@tonic-gate di_path_client_node(di_path_t path)
18217c478bd9Sstevel@tonic-gate {
18227c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
18257c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18267c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
18277c478bd9Sstevel@tonic-gate 	}
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_client) {
18347c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_client));
18357c478bd9Sstevel@tonic-gate 	}
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	/*
18387c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
18397c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
18407c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
18417c478bd9Sstevel@tonic-gate 	 */
18427c478bd9Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
18437c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
18447c478bd9Sstevel@tonic-gate 	else
18457c478bd9Sstevel@tonic-gate 		errno = ENXIO;
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate di_node_t
18517c478bd9Sstevel@tonic-gate di_path_phci_node(di_path_t path)
18527c478bd9Sstevel@tonic-gate {
18537c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
18567c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18577c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_phci) {
18657c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_phci));
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	/*
18697c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
18707c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
18717c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
18727c478bd9Sstevel@tonic-gate 	 */
18737c478bd9Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
18747c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
18757c478bd9Sstevel@tonic-gate 	else
18767c478bd9Sstevel@tonic-gate 		errno = ENXIO;
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
18797c478bd9Sstevel@tonic-gate }
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate di_path_prop_t
18827c478bd9Sstevel@tonic-gate di_path_prop_next(di_path_t path, di_path_prop_t prop)
18837c478bd9Sstevel@tonic-gate {
18847c478bd9Sstevel@tonic-gate 	caddr_t pa;
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
18877c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18887c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
18897c478bd9Sstevel@tonic-gate 	}
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	/*
18927c478bd9Sstevel@tonic-gate 	 * prop is not NIL
18937c478bd9Sstevel@tonic-gate 	 */
18947c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
18957c478bd9Sstevel@tonic-gate 		if (DI_PROP(prop)->next != 0)
18967c478bd9Sstevel@tonic-gate 			return (DI_PATHPROP((caddr_t)prop -
18977c478bd9Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
18987c478bd9Sstevel@tonic-gate 		else {
18997c478bd9Sstevel@tonic-gate 			errno = ENXIO;
19007c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
19017c478bd9Sstevel@tonic-gate 		}
19027c478bd9Sstevel@tonic-gate 	}
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	/*
19057c478bd9Sstevel@tonic-gate 	 * prop is NIL-->caller asks for first property
19067c478bd9Sstevel@tonic-gate 	 */
19077c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
19087c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_prop != 0) {
19097c478bd9Sstevel@tonic-gate 		return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	/*
19137c478bd9Sstevel@tonic-gate 	 * no property data-->check if snapshot includes props
19147c478bd9Sstevel@tonic-gate 	 *	in order to set the correct errno
19157c478bd9Sstevel@tonic-gate 	 */
19167c478bd9Sstevel@tonic-gate 	if (DINFOPROP & (DI_ALL(pa)->command))
19177c478bd9Sstevel@tonic-gate 		errno = ENXIO;
19187c478bd9Sstevel@tonic-gate 	else
19197c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
19227c478bd9Sstevel@tonic-gate }
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate char *
19257c478bd9Sstevel@tonic-gate di_path_prop_name(di_path_prop_t prop)
19267c478bd9Sstevel@tonic-gate {
19277c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
19287c478bd9Sstevel@tonic-gate 	pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
19297c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
19307c478bd9Sstevel@tonic-gate }
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate int
19337c478bd9Sstevel@tonic-gate di_path_prop_len(di_path_prop_t prop)
19347c478bd9Sstevel@tonic-gate {
19357c478bd9Sstevel@tonic-gate 	return (DI_PATHPROP(prop)->prop_len);
19367c478bd9Sstevel@tonic-gate }
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate int
19397c478bd9Sstevel@tonic-gate di_path_prop_type(di_path_prop_t prop)
19407c478bd9Sstevel@tonic-gate {
19417c478bd9Sstevel@tonic-gate 	switch (DI_PATHPROP(prop)->prop_type) {
19427c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT:
19437c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT);
19447c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT64:
19457c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT64);
19467c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_BYTE:
19477c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_BYTE);
19487c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_STRING:
19497c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_STRING);
19507c478bd9Sstevel@tonic-gate 	}
19517c478bd9Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
19527c478bd9Sstevel@tonic-gate }
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate int
19557c478bd9Sstevel@tonic-gate di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
19567c478bd9Sstevel@tonic-gate {
19577c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
19587c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
19597c478bd9Sstevel@tonic-gate 		errno = EFAULT;
19607c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
19617c478bd9Sstevel@tonic-gate 		return (-1);
19627c478bd9Sstevel@tonic-gate 	}
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
19657c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
19687c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
19697c478bd9Sstevel@tonic-gate }
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate int
19727c478bd9Sstevel@tonic-gate di_path_prop_ints(di_path_prop_t prop, int **prop_data)
19737c478bd9Sstevel@tonic-gate {
19747c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
19757c478bd9Sstevel@tonic-gate 		return (0);
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
19787c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
19797c478bd9Sstevel@tonic-gate 		errno = EFAULT;
19807c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
19817c478bd9Sstevel@tonic-gate 		return (-1);
19827c478bd9Sstevel@tonic-gate 	}
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
19857c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data));
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
19887c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
19897c478bd9Sstevel@tonic-gate }
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate int
19927c478bd9Sstevel@tonic-gate di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
19937c478bd9Sstevel@tonic-gate {
19947c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
19957c478bd9Sstevel@tonic-gate 		return (0);
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
19987c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
19997c478bd9Sstevel@tonic-gate 		errno = EFAULT;
20007c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
20017c478bd9Sstevel@tonic-gate 		return (-1);
20027c478bd9Sstevel@tonic-gate 	}
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop -
20057c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
20087c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
20097c478bd9Sstevel@tonic-gate }
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate int
20127c478bd9Sstevel@tonic-gate di_path_prop_strings(di_path_prop_t prop, char **prop_data)
20137c478bd9Sstevel@tonic-gate {
20147c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
20157c478bd9Sstevel@tonic-gate 		return (0);
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
20187c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
20197c478bd9Sstevel@tonic-gate 		errno = EFAULT;
20207c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
20217c478bd9Sstevel@tonic-gate 		return (-1);
20227c478bd9Sstevel@tonic-gate 	}
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
20257c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
20287c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate static di_path_prop_t
20327c478bd9Sstevel@tonic-gate di_path_prop_search(di_path_t path, const char *name, int type)
20337c478bd9Sstevel@tonic-gate {
20347c478bd9Sstevel@tonic-gate 	di_path_prop_t prop = DI_PROP_NIL;
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	/*
20377c478bd9Sstevel@tonic-gate 	 * Sanity check arguments
20387c478bd9Sstevel@tonic-gate 	 */
20397c478bd9Sstevel@tonic-gate 	if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
20407c478bd9Sstevel@tonic-gate 	    !DI_PROP_TYPE_VALID(type)) {
20417c478bd9Sstevel@tonic-gate 		errno = EINVAL;
20427c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
20437c478bd9Sstevel@tonic-gate 	}
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
20467c478bd9Sstevel@tonic-gate 		int prop_type = di_path_prop_type(prop);
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
20497c478bd9Sstevel@tonic-gate 		    di_path_prop_name(prop), prop_type));
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 		if (strcmp(name, di_path_prop_name(prop)) != 0)
20527c478bd9Sstevel@tonic-gate 			continue;
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 		if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
20557c478bd9Sstevel@tonic-gate 			continue;
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 		return (prop);
20587c478bd9Sstevel@tonic-gate 	}
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
20617c478bd9Sstevel@tonic-gate }
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate int
20647c478bd9Sstevel@tonic-gate di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
20657c478bd9Sstevel@tonic-gate     uchar_t **prop_data)
20667c478bd9Sstevel@tonic-gate {
20677c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
20707c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
20717c478bd9Sstevel@tonic-gate 		return (-1);
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	return (di_path_prop_bytes(prop, prop_data));
20747c478bd9Sstevel@tonic-gate }
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate int
20777c478bd9Sstevel@tonic-gate di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
20787c478bd9Sstevel@tonic-gate     int **prop_data)
20797c478bd9Sstevel@tonic-gate {
20807c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
20837c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
20847c478bd9Sstevel@tonic-gate 		return (-1);
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	return (di_path_prop_ints(prop, prop_data));
20877c478bd9Sstevel@tonic-gate }
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate int
20907c478bd9Sstevel@tonic-gate di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
20917c478bd9Sstevel@tonic-gate     int64_t **prop_data)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
20967c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
20977c478bd9Sstevel@tonic-gate 		return (-1);
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	return (di_path_prop_int64s(prop, prop_data));
21007c478bd9Sstevel@tonic-gate }
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
21037c478bd9Sstevel@tonic-gate     char **prop_data)
21047c478bd9Sstevel@tonic-gate {
21057c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
21087c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
21097c478bd9Sstevel@tonic-gate 		return (-1);
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	return (di_path_prop_strings(prop, prop_data));
21127c478bd9Sstevel@tonic-gate }
21137c478bd9Sstevel@tonic-gate 
21148c4f8890Srs135747 /*
21158c4f8890Srs135747  * Consolidation private interfaces for traversing vhci nodes.
21168c4f8890Srs135747  */
21178c4f8890Srs135747 di_node_t
21188c4f8890Srs135747 di_vhci_first_node(di_node_t root)
21198c4f8890Srs135747 {
21208c4f8890Srs135747 	struct di_all *dap;
21218c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
21228c4f8890Srs135747 
21238c4f8890Srs135747 	DPRINTF((DI_INFO, "Get first vhci node\n"));
21248c4f8890Srs135747 
21258c4f8890Srs135747 	if (root == DI_NODE_NIL) {
21268c4f8890Srs135747 		errno = EINVAL;
21278c4f8890Srs135747 		return (DI_NODE_NIL);
21288c4f8890Srs135747 	}
21298c4f8890Srs135747 
21308c4f8890Srs135747 	pa = (caddr_t)root - DI_NODE(root)->self;
21318c4f8890Srs135747 	dap = DI_ALL(pa);
21328c4f8890Srs135747 
21338c4f8890Srs135747 	if (dap->top_vhci_devinfo == NULL) {
21348c4f8890Srs135747 		errno = ENXIO;
21358c4f8890Srs135747 		return (DI_NODE_NIL);
21368c4f8890Srs135747 	}
21378c4f8890Srs135747 
21388c4f8890Srs135747 	return (DI_NODE(pa + dap->top_vhci_devinfo));
21398c4f8890Srs135747 }
21408c4f8890Srs135747 
21418c4f8890Srs135747 di_node_t
21428c4f8890Srs135747 di_vhci_next_node(di_node_t node)
21438c4f8890Srs135747 {
21448c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
21458c4f8890Srs135747 
21468c4f8890Srs135747 	if (node == DI_NODE_NIL) {
21478c4f8890Srs135747 		errno = EINVAL;
21488c4f8890Srs135747 		return (DI_NODE_NIL);
21498c4f8890Srs135747 	}
21508c4f8890Srs135747 
21518c4f8890Srs135747 	DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
21528c4f8890Srs135747 	    " current=%s\n", di_node_name(node)));
21538c4f8890Srs135747 
21548c4f8890Srs135747 	if (DI_NODE(node)->next_vhci == NULL) {
21558c4f8890Srs135747 		errno = ENXIO;
21568c4f8890Srs135747 		return (DI_NODE_NIL);
21578c4f8890Srs135747 	}
21588c4f8890Srs135747 
21598c4f8890Srs135747 	pa = (caddr_t)node - DI_NODE(node)->self;
21608c4f8890Srs135747 
21618c4f8890Srs135747 	return (DI_NODE(pa + DI_NODE(node)->next_vhci));
21628c4f8890Srs135747 }
21638c4f8890Srs135747 
21648c4f8890Srs135747 /*
21658c4f8890Srs135747  * Consolidation private interfaces for traversing phci nodes.
21668c4f8890Srs135747  */
21678c4f8890Srs135747 di_node_t
21688c4f8890Srs135747 di_phci_first_node(di_node_t vhci_node)
21698c4f8890Srs135747 {
21708c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
21718c4f8890Srs135747 
21728c4f8890Srs135747 	DPRINTF((DI_INFO, "Get first phci node:\n"
21738c4f8890Srs135747 	    " current=%s", di_node_name(vhci_node)));
21748c4f8890Srs135747 
21758c4f8890Srs135747 	if (vhci_node == DI_NODE_NIL) {
21768c4f8890Srs135747 		errno = EINVAL;
21778c4f8890Srs135747 		return (DI_NODE_NIL);
21788c4f8890Srs135747 	}
21798c4f8890Srs135747 
21808c4f8890Srs135747 	pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
21818c4f8890Srs135747 
21828c4f8890Srs135747 	if (DI_NODE(vhci_node)->top_phci == NULL) {
21838c4f8890Srs135747 		errno = ENXIO;
21848c4f8890Srs135747 		return (DI_NODE_NIL);
21858c4f8890Srs135747 	}
21868c4f8890Srs135747 
21878c4f8890Srs135747 	return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
21888c4f8890Srs135747 }
21898c4f8890Srs135747 
21908c4f8890Srs135747 di_node_t
21918c4f8890Srs135747 di_phci_next_node(di_node_t node)
21928c4f8890Srs135747 {
21938c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
21948c4f8890Srs135747 
21958c4f8890Srs135747 	if (node == DI_NODE_NIL) {
21968c4f8890Srs135747 		errno = EINVAL;
21978c4f8890Srs135747 		return (DI_NODE_NIL);
21988c4f8890Srs135747 	}
21998c4f8890Srs135747 
22008c4f8890Srs135747 	DPRINTF((DI_TRACE, "next phci node on the snap shot:"
22018c4f8890Srs135747 	    " current=%s\n", di_node_name(node)));
22028c4f8890Srs135747 
22038c4f8890Srs135747 	if (DI_NODE(node)->next_phci == NULL) {
22048c4f8890Srs135747 		errno = ENXIO;
22058c4f8890Srs135747 		return (DI_NODE_NIL);
22068c4f8890Srs135747 	}
22078c4f8890Srs135747 
22088c4f8890Srs135747 	pa = (caddr_t)node - DI_NODE(node)->self;
22098c4f8890Srs135747 
22108c4f8890Srs135747 	return (DI_NODE(pa + DI_NODE(node)->next_phci));
22118c4f8890Srs135747 }
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate /*
22147c478bd9Sstevel@tonic-gate  * Consolidation private interfaces for private data
22157c478bd9Sstevel@tonic-gate  */
22167c478bd9Sstevel@tonic-gate void *
22177c478bd9Sstevel@tonic-gate di_parent_private_data(di_node_t node)
22187c478bd9Sstevel@tonic-gate {
22197c478bd9Sstevel@tonic-gate 	caddr_t pa;
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == 0) {
22227c478bd9Sstevel@tonic-gate 		errno = ENXIO;
22237c478bd9Sstevel@tonic-gate 		return (NULL);
22247c478bd9Sstevel@tonic-gate 	}
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == (di_off_t)-1) {
22277c478bd9Sstevel@tonic-gate 		/*
22287c478bd9Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
22297c478bd9Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
22307c478bd9Sstevel@tonic-gate 		 */
22317c478bd9Sstevel@tonic-gate 		errno = EFAULT;
22327c478bd9Sstevel@tonic-gate 		return (NULL);
22337c478bd9Sstevel@tonic-gate 	}
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
22367c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data)
22377c478bd9Sstevel@tonic-gate 		return (pa + DI_NODE(node)->parent_data);
22387c478bd9Sstevel@tonic-gate 
22397c478bd9Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
22407c478bd9Sstevel@tonic-gate 		errno = ENXIO;
22417c478bd9Sstevel@tonic-gate 	else
22427c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	return (NULL);
22457c478bd9Sstevel@tonic-gate }
22467c478bd9Sstevel@tonic-gate 
22477c478bd9Sstevel@tonic-gate void *
22487c478bd9Sstevel@tonic-gate di_driver_private_data(di_node_t node)
22497c478bd9Sstevel@tonic-gate {
22507c478bd9Sstevel@tonic-gate 	caddr_t pa;
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == 0) {
22537c478bd9Sstevel@tonic-gate 		errno = ENXIO;
22547c478bd9Sstevel@tonic-gate 		return (NULL);
22557c478bd9Sstevel@tonic-gate 	}
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == (di_off_t)-1) {
22587c478bd9Sstevel@tonic-gate 		/*
22597c478bd9Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
22607c478bd9Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
22617c478bd9Sstevel@tonic-gate 		 */
22627c478bd9Sstevel@tonic-gate 		errno = EFAULT;
22637c478bd9Sstevel@tonic-gate 		return (NULL);
22647c478bd9Sstevel@tonic-gate 	}
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
22677c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data)
22687c478bd9Sstevel@tonic-gate 		return (pa + DI_NODE(node)->driver_data);
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
22717c478bd9Sstevel@tonic-gate 		errno = ENXIO;
22727c478bd9Sstevel@tonic-gate 	else
22737c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	return (NULL);
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate /*
22797c478bd9Sstevel@tonic-gate  * PROM property access
22807c478bd9Sstevel@tonic-gate  */
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate /*
22837c478bd9Sstevel@tonic-gate  * openprom driver stuff:
22847c478bd9Sstevel@tonic-gate  *	The maximum property length depends on the buffer size. We use
22857c478bd9Sstevel@tonic-gate  *	OPROMMAXPARAM defined in <sys/openpromio.h>
22867c478bd9Sstevel@tonic-gate  *
22877c478bd9Sstevel@tonic-gate  *	MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
22887c478bd9Sstevel@tonic-gate  *	MAXVALSZ is maximum value size, which is whatever space left in buf
22897c478bd9Sstevel@tonic-gate  */
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate #define	OBP_MAXBUF	OPROMMAXPARAM - sizeof (int)
22927c478bd9Sstevel@tonic-gate #define	OBP_MAXPROPLEN	OBP_MAXBUF - OBP_MAXPROPNAME;
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate struct di_prom_prop {
22957c478bd9Sstevel@tonic-gate 	char *name;
22967c478bd9Sstevel@tonic-gate 	int len;
22977c478bd9Sstevel@tonic-gate 	uchar_t *data;
22987c478bd9Sstevel@tonic-gate 	struct di_prom_prop *next;	/* form a linked list */
22997c478bd9Sstevel@tonic-gate };
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate struct di_prom_handle { /* handle to prom */
23027c478bd9Sstevel@tonic-gate 	mutex_t lock;	/* synchronize access to openprom fd */
23037c478bd9Sstevel@tonic-gate 	int	fd;	/* /dev/openprom file descriptor */
23047c478bd9Sstevel@tonic-gate 	struct di_prom_prop *list;	/* linked list of prop */
23057c478bd9Sstevel@tonic-gate 	union {
23067c478bd9Sstevel@tonic-gate 		char buf[OPROMMAXPARAM];
23077c478bd9Sstevel@tonic-gate 		struct openpromio opp;
23087c478bd9Sstevel@tonic-gate 	} oppbuf;
23097c478bd9Sstevel@tonic-gate };
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate di_prom_handle_t
23127c478bd9Sstevel@tonic-gate di_prom_init()
23137c478bd9Sstevel@tonic-gate {
23147c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p;
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
23177c478bd9Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
23207c478bd9Sstevel@tonic-gate 
23217c478bd9Sstevel@tonic-gate 	(void) mutex_init(&p->lock, USYNC_THREAD, NULL);
23227c478bd9Sstevel@tonic-gate 	if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
23237c478bd9Sstevel@tonic-gate 		free(p);
23247c478bd9Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
23257c478bd9Sstevel@tonic-gate 	}
23267c478bd9Sstevel@tonic-gate 	p->list = NULL;
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 	return ((di_prom_handle_t)p);
23297c478bd9Sstevel@tonic-gate }
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate static void
23327c478bd9Sstevel@tonic-gate di_prom_prop_free(struct di_prom_prop *list)
23337c478bd9Sstevel@tonic-gate {
23347c478bd9Sstevel@tonic-gate 	struct di_prom_prop *tmp = list;
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 	while (tmp != NULL) {
23377c478bd9Sstevel@tonic-gate 		list = tmp->next;
23387c478bd9Sstevel@tonic-gate 		if (tmp->name != NULL) {
23397c478bd9Sstevel@tonic-gate 			free(tmp->name);
23407c478bd9Sstevel@tonic-gate 		}
23417c478bd9Sstevel@tonic-gate 		if (tmp->data != NULL) {
23427c478bd9Sstevel@tonic-gate 			free(tmp->data);
23437c478bd9Sstevel@tonic-gate 		}
23447c478bd9Sstevel@tonic-gate 		free(tmp);
23457c478bd9Sstevel@tonic-gate 		tmp = list;
23467c478bd9Sstevel@tonic-gate 	}
23477c478bd9Sstevel@tonic-gate }
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate void
23507c478bd9Sstevel@tonic-gate di_prom_fini(di_prom_handle_t ph)
23517c478bd9Sstevel@tonic-gate {
23527c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 	(void) close(p->fd);
23577c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&p->lock);
23587c478bd9Sstevel@tonic-gate 	di_prom_prop_free(p->list);
23597c478bd9Sstevel@tonic-gate 
23607c478bd9Sstevel@tonic-gate 	free(p);
23617c478bd9Sstevel@tonic-gate }
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate /*
23647c478bd9Sstevel@tonic-gate  * Internal library interface for locating the property
23657c478bd9Sstevel@tonic-gate  * XXX: ph->lock must be held for the duration of call.
23667c478bd9Sstevel@tonic-gate  */
23677c478bd9Sstevel@tonic-gate static di_prom_prop_t
23687c478bd9Sstevel@tonic-gate di_prom_prop_found(di_prom_handle_t ph, int nodeid,
23697c478bd9Sstevel@tonic-gate 	di_prom_prop_t prom_prop)
23707c478bd9Sstevel@tonic-gate {
23717c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
23727c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &p->oppbuf.opp;
23737c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
23747c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 	/*
23797c478bd9Sstevel@tonic-gate 	 * Set "current" nodeid in the openprom driver
23807c478bd9Sstevel@tonic-gate 	 */
23817c478bd9Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
23827c478bd9Sstevel@tonic-gate 	*ip = nodeid;
23837c478bd9Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
23847c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
23857c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
23867c478bd9Sstevel@tonic-gate 	}
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
23917c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPNAME;
23927c478bd9Sstevel@tonic-gate 	if (prom_prop != DI_PROM_PROP_NIL)
23937c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, prop->name);
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
23967c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
23977c478bd9Sstevel@tonic-gate 
23987c478bd9Sstevel@tonic-gate 	/*
23997c478bd9Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
24007c478bd9Sstevel@tonic-gate 	 *   (reuse variable prop)
24017c478bd9Sstevel@tonic-gate 	 */
24027c478bd9Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
24037c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	/*
24067c478bd9Sstevel@tonic-gate 	 * Get a copy of property name
24077c478bd9Sstevel@tonic-gate 	 */
24087c478bd9Sstevel@tonic-gate 	if ((prop->name = strdup(opp->oprom_array)) == NULL) {
24097c478bd9Sstevel@tonic-gate 		free(prop);
24107c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
24117c478bd9Sstevel@tonic-gate 	}
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 	/*
24147c478bd9Sstevel@tonic-gate 	 * get property value and length
24157c478bd9Sstevel@tonic-gate 	 */
24167c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
24197c478bd9Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
24207c478bd9Sstevel@tonic-gate 		free(prop->name);
24217c478bd9Sstevel@tonic-gate 		free(prop);
24227c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
24237c478bd9Sstevel@tonic-gate 	}
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	/*
24267c478bd9Sstevel@tonic-gate 	 * make a copy of the property value
24277c478bd9Sstevel@tonic-gate 	 */
24287c478bd9Sstevel@tonic-gate 	prop->len = opp->oprom_size;
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 	if (prop->len == 0)
24317c478bd9Sstevel@tonic-gate 		prop->data = NULL;
24327c478bd9Sstevel@tonic-gate 	else if ((prop->data = malloc(prop->len)) == NULL) {
24337c478bd9Sstevel@tonic-gate 		free(prop->name);
24347c478bd9Sstevel@tonic-gate 		free(prop);
24357c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
24367c478bd9Sstevel@tonic-gate 	}
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	/*
24417c478bd9Sstevel@tonic-gate 	 * Prepend prop to list in prom handle
24427c478bd9Sstevel@tonic-gate 	 */
24437c478bd9Sstevel@tonic-gate 	prop->next = p->list;
24447c478bd9Sstevel@tonic-gate 	p->list = prop;
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 	return ((di_prom_prop_t)prop);
24477c478bd9Sstevel@tonic-gate }
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate di_prom_prop_t
24507c478bd9Sstevel@tonic-gate di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
24517c478bd9Sstevel@tonic-gate {
24527c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
24557c478bd9Sstevel@tonic-gate 		node, p));
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 	/*
24587c478bd9Sstevel@tonic-gate 	 * paranoid check
24597c478bd9Sstevel@tonic-gate 	 */
24607c478bd9Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
24617c478bd9Sstevel@tonic-gate 		errno = EINVAL;
24627c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
24667c478bd9Sstevel@tonic-gate 		errno = ENXIO;
24677c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
24687c478bd9Sstevel@tonic-gate 	}
24697c478bd9Sstevel@tonic-gate 
24707c478bd9Sstevel@tonic-gate 	/*
24717c478bd9Sstevel@tonic-gate 	 * synchronize access to prom file descriptor
24727c478bd9Sstevel@tonic-gate 	 */
24737c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	/*
24767c478bd9Sstevel@tonic-gate 	 * look for next property
24777c478bd9Sstevel@tonic-gate 	 */
24787c478bd9Sstevel@tonic-gate 	prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	return (prom_prop);
24837c478bd9Sstevel@tonic-gate }
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate char *
24867c478bd9Sstevel@tonic-gate di_prom_prop_name(di_prom_prop_t prom_prop)
24877c478bd9Sstevel@tonic-gate {
24887c478bd9Sstevel@tonic-gate 	/*
24897c478bd9Sstevel@tonic-gate 	 * paranoid check
24907c478bd9Sstevel@tonic-gate 	 */
24917c478bd9Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
24927c478bd9Sstevel@tonic-gate 		errno = EINVAL;
24937c478bd9Sstevel@tonic-gate 		return (NULL);
24947c478bd9Sstevel@tonic-gate 	}
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->name);
24977c478bd9Sstevel@tonic-gate }
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate int
25007c478bd9Sstevel@tonic-gate di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
25017c478bd9Sstevel@tonic-gate {
25027c478bd9Sstevel@tonic-gate 	/*
25037c478bd9Sstevel@tonic-gate 	 * paranoid check
25047c478bd9Sstevel@tonic-gate 	 */
25057c478bd9Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
25067c478bd9Sstevel@tonic-gate 		errno = EINVAL;
25077c478bd9Sstevel@tonic-gate 		return (NULL);
25087c478bd9Sstevel@tonic-gate 	}
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	*prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->len);
25137c478bd9Sstevel@tonic-gate }
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate /*
25167c478bd9Sstevel@tonic-gate  * Internal library interface for locating the property
25177c478bd9Sstevel@tonic-gate  *    Returns length if found, -1 if prop doesn't exist.
25187c478bd9Sstevel@tonic-gate  */
25197c478bd9Sstevel@tonic-gate static struct di_prom_prop *
25207c478bd9Sstevel@tonic-gate di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
25217c478bd9Sstevel@tonic-gate 	const char *prom_prop_name)
25227c478bd9Sstevel@tonic-gate {
25237c478bd9Sstevel@tonic-gate 	struct openpromio *opp;
25247c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
25257c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	/*
25287c478bd9Sstevel@tonic-gate 	 * paranoid check
25297c478bd9Sstevel@tonic-gate 	 */
25307c478bd9Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
25317c478bd9Sstevel@tonic-gate 		errno = EINVAL;
25327c478bd9Sstevel@tonic-gate 		return (NULL);
25337c478bd9Sstevel@tonic-gate 	}
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
25367c478bd9Sstevel@tonic-gate 		errno = ENXIO;
25377c478bd9Sstevel@tonic-gate 		return (NULL);
25387c478bd9Sstevel@tonic-gate 	}
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	opp = &p->oppbuf.opp;
25417c478bd9Sstevel@tonic-gate 
25427c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
25457c478bd9Sstevel@tonic-gate 	opp->oprom_node = DI_NODE(node)->nodeid;
25467c478bd9Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
25477c478bd9Sstevel@tonic-gate 		errno = ENXIO;
25487c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
25497c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->nodeid));
25507c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
25517c478bd9Sstevel@tonic-gate 		return (NULL);
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	/*
25557c478bd9Sstevel@tonic-gate 	 * get property length
25567c478bd9Sstevel@tonic-gate 	 */
25577c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
25587c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
25597c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
25627c478bd9Sstevel@tonic-gate 	    (opp->oprom_len == -1)) {
25637c478bd9Sstevel@tonic-gate 		/* no such property */
25647c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
25657c478bd9Sstevel@tonic-gate 		return (NULL);
25667c478bd9Sstevel@tonic-gate 	}
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 	/*
25697c478bd9Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
25707c478bd9Sstevel@tonic-gate 	 */
25717c478bd9Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
25727c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
25737c478bd9Sstevel@tonic-gate 		return (NULL);
25747c478bd9Sstevel@tonic-gate 	}
25757c478bd9Sstevel@tonic-gate 	prop->name = NULL;	/* we don't need the name */
25767c478bd9Sstevel@tonic-gate 	prop->len = opp->oprom_len;
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
25797c478bd9Sstevel@tonic-gate 		prop->data = NULL;
25807c478bd9Sstevel@tonic-gate 		prop->next = p->list;
25817c478bd9Sstevel@tonic-gate 		p->list = prop;
25827c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
25837c478bd9Sstevel@tonic-gate 		return (prop);
25847c478bd9Sstevel@tonic-gate 	}
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	/*
25877c478bd9Sstevel@tonic-gate 	 * retrieve the property value
25887c478bd9Sstevel@tonic-gate 	 */
25897c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
25907c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
25917c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
25947c478bd9Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
25957c478bd9Sstevel@tonic-gate 		/* error retrieving property value */
25967c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
25977c478bd9Sstevel@tonic-gate 		free(prop);
25987c478bd9Sstevel@tonic-gate 		return (NULL);
25997c478bd9Sstevel@tonic-gate 	}
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 	/*
26027c478bd9Sstevel@tonic-gate 	 * make a copy of the property value, stick in ph->list
26037c478bd9Sstevel@tonic-gate 	 */
26047c478bd9Sstevel@tonic-gate 	if ((prop->data = malloc(prop->len)) == NULL) {
26057c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
26067c478bd9Sstevel@tonic-gate 		free(prop);
26077c478bd9Sstevel@tonic-gate 		return (NULL);
26087c478bd9Sstevel@tonic-gate 	}
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate 	prop->next = p->list;
26137c478bd9Sstevel@tonic-gate 	p->list = prop;
26147c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	return (prop);
26177c478bd9Sstevel@tonic-gate }
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate int
26207c478bd9Sstevel@tonic-gate di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
26217c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, int **prom_prop_data)
26227c478bd9Sstevel@tonic-gate {
26237c478bd9Sstevel@tonic-gate 	int len;
26247c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
26297c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
26307c478bd9Sstevel@tonic-gate 		return (-1);
26317c478bd9Sstevel@tonic-gate 	}
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
26347c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
26357c478bd9Sstevel@tonic-gate 		return (0);
26367c478bd9Sstevel@tonic-gate 	}
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
26397c478bd9Sstevel@tonic-gate 		DI_PROP_TYPE_INT, 1);
26407c478bd9Sstevel@tonic-gate 	*prom_prop_data = (int *)((void *)prop->data);
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 	return (len);
26437c478bd9Sstevel@tonic-gate }
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate int
26467c478bd9Sstevel@tonic-gate di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
26477c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, char **prom_prop_data)
26487c478bd9Sstevel@tonic-gate {
26497c478bd9Sstevel@tonic-gate 	int len;
26507c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
26557c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
26567c478bd9Sstevel@tonic-gate 		return (-1);
26577c478bd9Sstevel@tonic-gate 	}
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
26607c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
26617c478bd9Sstevel@tonic-gate 		return (0);
26627c478bd9Sstevel@tonic-gate 	}
26637c478bd9Sstevel@tonic-gate 
26647c478bd9Sstevel@tonic-gate 	/*
26657c478bd9Sstevel@tonic-gate 	 * Fix an openprom bug (OBP string not NULL terminated).
26667c478bd9Sstevel@tonic-gate 	 * XXX This should really be fixed in promif.
26677c478bd9Sstevel@tonic-gate 	 */
26687c478bd9Sstevel@tonic-gate 	if (((char *)prop->data)[prop->len - 1] != '\0') {
26697c478bd9Sstevel@tonic-gate 		uchar_t *tmp;
26707c478bd9Sstevel@tonic-gate 		prop->len++;
26717c478bd9Sstevel@tonic-gate 		if ((tmp = realloc(prop->data, prop->len)) == NULL)
26727c478bd9Sstevel@tonic-gate 			return (-1);
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 		prop->data = tmp;
26757c478bd9Sstevel@tonic-gate 		((char *)prop->data)[prop->len - 1] = '\0';
26767c478bd9Sstevel@tonic-gate 		DPRINTF((DI_INFO, "OBP string not NULL terminated: "
26777c478bd9Sstevel@tonic-gate 		    "node=%s, prop=%s, val=%s\n",
26787c478bd9Sstevel@tonic-gate 		    di_node_name(node), prom_prop_name, prop->data));
26797c478bd9Sstevel@tonic-gate 	}
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
26827c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING, 1);
26837c478bd9Sstevel@tonic-gate 	*prom_prop_data = (char *)prop->data;
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	return (len);
26867c478bd9Sstevel@tonic-gate }
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate int
26897c478bd9Sstevel@tonic-gate di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
26907c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, uchar_t **prom_prop_data)
26917c478bd9Sstevel@tonic-gate {
26927c478bd9Sstevel@tonic-gate 	int len;
26937c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
26987c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
26997c478bd9Sstevel@tonic-gate 		return (-1);
27007c478bd9Sstevel@tonic-gate 	}
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
27037c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
27047c478bd9Sstevel@tonic-gate 		return (0);
27057c478bd9Sstevel@tonic-gate 	}
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
27087c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE, 1);
27097c478bd9Sstevel@tonic-gate 	*prom_prop_data = prop->data;
27107c478bd9Sstevel@tonic-gate 
27117c478bd9Sstevel@tonic-gate 	return (len);
27127c478bd9Sstevel@tonic-gate }
27137c478bd9Sstevel@tonic-gate 
2714*3ebafc43Sjveta /*
2715*3ebafc43Sjveta  * returns an allocated array through <prop_data> only when its count > 0
2716*3ebafc43Sjveta  * and the number of entries (count) as the function return value;
2717*3ebafc43Sjveta  * use di_slot_names_free() to free the array
2718*3ebafc43Sjveta  */
2719*3ebafc43Sjveta int
2720*3ebafc43Sjveta di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
2721*3ebafc43Sjveta {
2722*3ebafc43Sjveta 	int rawlen, count;
2723*3ebafc43Sjveta 	uchar_t *rawdata;
2724*3ebafc43Sjveta 	char *nm = di_prop_name(prop);
2725*3ebafc43Sjveta 
2726*3ebafc43Sjveta 	if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
2727*3ebafc43Sjveta 		goto ERROUT;
2728*3ebafc43Sjveta 
2729*3ebafc43Sjveta 	rawlen = di_prop_rawdata(prop, &rawdata);
2730*3ebafc43Sjveta 	if (rawlen <= 0 || rawdata == NULL)
2731*3ebafc43Sjveta 		goto ERROUT;
2732*3ebafc43Sjveta 
2733*3ebafc43Sjveta 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
2734*3ebafc43Sjveta 	if (count < 0 || *prop_data == NULL)
2735*3ebafc43Sjveta 		goto ERROUT;
2736*3ebafc43Sjveta 
2737*3ebafc43Sjveta 	return (count);
2738*3ebafc43Sjveta 	/*NOTREACHED*/
2739*3ebafc43Sjveta ERROUT:
2740*3ebafc43Sjveta 	errno = EFAULT;
2741*3ebafc43Sjveta 	*prop_data = NULL;
2742*3ebafc43Sjveta 	return (-1);
2743*3ebafc43Sjveta }
2744*3ebafc43Sjveta 
2745*3ebafc43Sjveta int
2746*3ebafc43Sjveta di_prop_lookup_slot_names(dev_t dev, di_node_t node,
2747*3ebafc43Sjveta     di_slot_name_t **prop_data)
2748*3ebafc43Sjveta {
2749*3ebafc43Sjveta 	di_prop_t prop;
2750*3ebafc43Sjveta 
2751*3ebafc43Sjveta 	/*
2752*3ebafc43Sjveta 	 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
2753*3ebafc43Sjveta 	 * and slot-names is properly flagged as such
2754*3ebafc43Sjveta 	 */
2755*3ebafc43Sjveta 	if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
2756*3ebafc43Sjveta 	    DI_PROP_NIL) {
2757*3ebafc43Sjveta 		*prop_data = NULL;
2758*3ebafc43Sjveta 		return (-1);
2759*3ebafc43Sjveta 	}
2760*3ebafc43Sjveta 
2761*3ebafc43Sjveta 	return (di_prop_slot_names(prop, (void *)prop_data));
2762*3ebafc43Sjveta }
2763*3ebafc43Sjveta 
2764*3ebafc43Sjveta /*
2765*3ebafc43Sjveta  * returns an allocated array through <prop_data> only when its count > 0
2766*3ebafc43Sjveta  * and the number of entries (count) as the function return value;
2767*3ebafc43Sjveta  * use di_slot_names_free() to free the array
2768*3ebafc43Sjveta  */
2769*3ebafc43Sjveta int
2770*3ebafc43Sjveta di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
2771*3ebafc43Sjveta {
2772*3ebafc43Sjveta 	int rawlen, count;
2773*3ebafc43Sjveta 	uchar_t *rawdata;
2774*3ebafc43Sjveta 
2775*3ebafc43Sjveta 	rawlen = di_prom_prop_data(prom_prop, &rawdata);
2776*3ebafc43Sjveta 	if (rawlen <= 0 || rawdata == NULL)
2777*3ebafc43Sjveta 		goto ERROUT;
2778*3ebafc43Sjveta 
2779*3ebafc43Sjveta 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
2780*3ebafc43Sjveta 	if (count < 0 || *prop_data == NULL)
2781*3ebafc43Sjveta 		goto ERROUT;
2782*3ebafc43Sjveta 
2783*3ebafc43Sjveta 	return (count);
2784*3ebafc43Sjveta 	/*NOTREACHED*/
2785*3ebafc43Sjveta ERROUT:
2786*3ebafc43Sjveta 	errno = EFAULT;
2787*3ebafc43Sjveta 	*prop_data = NULL;
2788*3ebafc43Sjveta 	return (-1);
2789*3ebafc43Sjveta }
2790*3ebafc43Sjveta 
2791*3ebafc43Sjveta int
2792*3ebafc43Sjveta di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
2793*3ebafc43Sjveta     di_slot_name_t **prop_data)
2794*3ebafc43Sjveta {
2795*3ebafc43Sjveta 	struct di_prom_prop *prom_prop;
2796*3ebafc43Sjveta 
2797*3ebafc43Sjveta 	prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
2798*3ebafc43Sjveta 	if (prom_prop == NULL) {
2799*3ebafc43Sjveta 		*prop_data = NULL;
2800*3ebafc43Sjveta 		return (-1);
2801*3ebafc43Sjveta 	}
2802*3ebafc43Sjveta 
2803*3ebafc43Sjveta 	return (di_prom_prop_slot_names(prom_prop, prop_data));
2804*3ebafc43Sjveta }
2805*3ebafc43Sjveta 
28067c478bd9Sstevel@tonic-gate di_lnode_t
28077c478bd9Sstevel@tonic-gate di_link_to_lnode(di_link_t link, uint_t endpoint)
28087c478bd9Sstevel@tonic-gate {
28097c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate 	if ((link == DI_LINK_NIL) ||
28127c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
28137c478bd9Sstevel@tonic-gate 		errno = EINVAL;
28147c478bd9Sstevel@tonic-gate 		return (DI_LNODE_NIL);
28157c478bd9Sstevel@tonic-gate 	}
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
28187c478bd9Sstevel@tonic-gate 
28197c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
28207c478bd9Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
28217c478bd9Sstevel@tonic-gate 	} else {
28227c478bd9Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
28237c478bd9Sstevel@tonic-gate 	}
28247c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
28257c478bd9Sstevel@tonic-gate }
28267c478bd9Sstevel@tonic-gate 
28277c478bd9Sstevel@tonic-gate char *
28287c478bd9Sstevel@tonic-gate di_lnode_name(di_lnode_t lnode)
28297c478bd9Sstevel@tonic-gate {
28307c478bd9Sstevel@tonic-gate 	return (di_driver_name(di_lnode_devinfo(lnode)));
28317c478bd9Sstevel@tonic-gate }
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate di_node_t
28347c478bd9Sstevel@tonic-gate di_lnode_devinfo(di_lnode_t lnode)
28357c478bd9Sstevel@tonic-gate {
28367c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
28377c478bd9Sstevel@tonic-gate 
28387c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
28397c478bd9Sstevel@tonic-gate 	return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
28407c478bd9Sstevel@tonic-gate }
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate int
28437c478bd9Sstevel@tonic-gate di_lnode_devt(di_lnode_t lnode, dev_t *devt)
28447c478bd9Sstevel@tonic-gate {
28457c478bd9Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
28467c478bd9Sstevel@tonic-gate 		errno = EINVAL;
28477c478bd9Sstevel@tonic-gate 		return (-1);
28487c478bd9Sstevel@tonic-gate 	}
28497c478bd9Sstevel@tonic-gate 	if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
28507c478bd9Sstevel@tonic-gate 	    (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
28517c478bd9Sstevel@tonic-gate 		return (-1);
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 	*devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
28547c478bd9Sstevel@tonic-gate 	return (0);
28557c478bd9Sstevel@tonic-gate }
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate int
28587c478bd9Sstevel@tonic-gate di_link_spectype(di_link_t link)
28597c478bd9Sstevel@tonic-gate {
28607c478bd9Sstevel@tonic-gate 	return (DI_LINK(link)->spec_type);
28617c478bd9Sstevel@tonic-gate }
28627c478bd9Sstevel@tonic-gate 
28637c478bd9Sstevel@tonic-gate void
28647c478bd9Sstevel@tonic-gate di_minor_private_set(di_minor_t minor, void *data)
28657c478bd9Sstevel@tonic-gate {
28667c478bd9Sstevel@tonic-gate 	DI_MINOR(minor)->user_private_data = (uintptr_t)data;
28677c478bd9Sstevel@tonic-gate }
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate void *
28707c478bd9Sstevel@tonic-gate di_minor_private_get(di_minor_t minor)
28717c478bd9Sstevel@tonic-gate {
28728309866bSanish 	return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
28737c478bd9Sstevel@tonic-gate }
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate void
28767c478bd9Sstevel@tonic-gate di_node_private_set(di_node_t node, void *data)
28777c478bd9Sstevel@tonic-gate {
28787c478bd9Sstevel@tonic-gate 	DI_NODE(node)->user_private_data = (uintptr_t)data;
28797c478bd9Sstevel@tonic-gate }
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate void *
28827c478bd9Sstevel@tonic-gate di_node_private_get(di_node_t node)
28837c478bd9Sstevel@tonic-gate {
28848309866bSanish 	return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
28857c478bd9Sstevel@tonic-gate }
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate void
28887c478bd9Sstevel@tonic-gate di_lnode_private_set(di_lnode_t lnode, void *data)
28897c478bd9Sstevel@tonic-gate {
28907c478bd9Sstevel@tonic-gate 	DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
28917c478bd9Sstevel@tonic-gate }
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate void *
28947c478bd9Sstevel@tonic-gate di_lnode_private_get(di_lnode_t lnode)
28957c478bd9Sstevel@tonic-gate {
28968309866bSanish 	return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
28977c478bd9Sstevel@tonic-gate }
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate void
29007c478bd9Sstevel@tonic-gate di_link_private_set(di_link_t link, void *data)
29017c478bd9Sstevel@tonic-gate {
29027c478bd9Sstevel@tonic-gate 	DI_LINK(link)->user_private_data = (uintptr_t)data;
29037c478bd9Sstevel@tonic-gate }
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate void *
29067c478bd9Sstevel@tonic-gate di_link_private_get(di_link_t link)
29077c478bd9Sstevel@tonic-gate {
29088309866bSanish 	return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
29097c478bd9Sstevel@tonic-gate }
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate di_lnode_t
29127c478bd9Sstevel@tonic-gate di_lnode_next(di_node_t node, di_lnode_t lnode)
29137c478bd9Sstevel@tonic-gate {
29147c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	/*
29177c478bd9Sstevel@tonic-gate 	 * paranoid error checking
29187c478bd9Sstevel@tonic-gate 	 */
29197c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
29207c478bd9Sstevel@tonic-gate 		errno = EINVAL;
29217c478bd9Sstevel@tonic-gate 		return (DI_LNODE_NIL);
29227c478bd9Sstevel@tonic-gate 	}
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate 	if (lnode == DI_NODE_NIL) {
29277c478bd9Sstevel@tonic-gate 		if (DI_NODE(node)->lnodes != NULL)
29287c478bd9Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
29297c478bd9Sstevel@tonic-gate 			    DI_NODE(node)->lnodes));
29307c478bd9Sstevel@tonic-gate 	} else {
29317c478bd9Sstevel@tonic-gate 		if (DI_LNODE(lnode)->node_next != NULL)
29327c478bd9Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
29337c478bd9Sstevel@tonic-gate 			    DI_LNODE(lnode)->node_next));
29347c478bd9Sstevel@tonic-gate 	}
29357c478bd9Sstevel@tonic-gate 
29367c478bd9Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
29377c478bd9Sstevel@tonic-gate 		errno = ENXIO;
29387c478bd9Sstevel@tonic-gate 	else
29397c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
29407c478bd9Sstevel@tonic-gate 
29417c478bd9Sstevel@tonic-gate 	return (DI_LNODE_NIL);
29427c478bd9Sstevel@tonic-gate }
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate di_link_t
29457c478bd9Sstevel@tonic-gate di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
29467c478bd9Sstevel@tonic-gate {
29477c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
29487c478bd9Sstevel@tonic-gate 
29497c478bd9Sstevel@tonic-gate 	/*
29507c478bd9Sstevel@tonic-gate 	 * paranoid error checking
29517c478bd9Sstevel@tonic-gate 	 */
29527c478bd9Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) ||
29537c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
29547c478bd9Sstevel@tonic-gate 		errno = EINVAL;
29557c478bd9Sstevel@tonic-gate 		return (DI_LINK_NIL);
29567c478bd9Sstevel@tonic-gate 	}
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
29597c478bd9Sstevel@tonic-gate 
29607c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
29617c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
29627c478bd9Sstevel@tonic-gate 			if (DI_NODE(node)->src_links != NULL)
29637c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
29647c478bd9Sstevel@tonic-gate 				    DI_NODE(node)->src_links));
29657c478bd9Sstevel@tonic-gate 		} else {
29667c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->src_node_next != NULL)
29677c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
29687c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->src_node_next));
29697c478bd9Sstevel@tonic-gate 		}
29707c478bd9Sstevel@tonic-gate 	} else {
29717c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
29727c478bd9Sstevel@tonic-gate 			if (DI_NODE(node)->tgt_links != NULL)
29737c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
29747c478bd9Sstevel@tonic-gate 				    DI_NODE(node)->tgt_links));
29757c478bd9Sstevel@tonic-gate 		} else {
29767c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_node_next != NULL)
29777c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
29787c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->tgt_node_next));
29797c478bd9Sstevel@tonic-gate 		}
29807c478bd9Sstevel@tonic-gate 	}
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
29837c478bd9Sstevel@tonic-gate 		errno = ENXIO;
29847c478bd9Sstevel@tonic-gate 	else
29857c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate 	return (DI_LINK_NIL);
29887c478bd9Sstevel@tonic-gate }
29897c478bd9Sstevel@tonic-gate 
29907c478bd9Sstevel@tonic-gate di_link_t
29917c478bd9Sstevel@tonic-gate di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
29927c478bd9Sstevel@tonic-gate {
29937c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
29947c478bd9Sstevel@tonic-gate 
29957c478bd9Sstevel@tonic-gate 	/*
29967c478bd9Sstevel@tonic-gate 	 * paranoid error checking
29977c478bd9Sstevel@tonic-gate 	 */
29987c478bd9Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) ||
29997c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
30007c478bd9Sstevel@tonic-gate 		errno = EINVAL;
30017c478bd9Sstevel@tonic-gate 		return (DI_LINK_NIL);
30027c478bd9Sstevel@tonic-gate 	}
30037c478bd9Sstevel@tonic-gate 
30047c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
30077c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
30087c478bd9Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_out == NULL)
30097c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
30107c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
30117c478bd9Sstevel@tonic-gate 				    DI_LNODE(lnode)->link_out));
30127c478bd9Sstevel@tonic-gate 		} else {
30137c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->src_link_next == NULL)
30147c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
30157c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
30167c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->src_link_next));
30177c478bd9Sstevel@tonic-gate 		}
30187c478bd9Sstevel@tonic-gate 	} else {
30197c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
30207c478bd9Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_in == NULL)
30217c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
30227c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
30237c478bd9Sstevel@tonic-gate 				    DI_LNODE(lnode)->link_in));
30247c478bd9Sstevel@tonic-gate 		} else {
30257c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_link_next == NULL)
30267c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
30277c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
30287c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->tgt_link_next));
30297c478bd9Sstevel@tonic-gate 		}
30307c478bd9Sstevel@tonic-gate 	}
30317c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
30327c478bd9Sstevel@tonic-gate }
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate /*
30357c478bd9Sstevel@tonic-gate  * Internal library function:
30367c478bd9Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
30377c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
30387c478bd9Sstevel@tonic-gate  *
30397c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
30407c478bd9Sstevel@tonic-gate  *   first mode.
30417c478bd9Sstevel@tonic-gate  */
30427c478bd9Sstevel@tonic-gate static void
30437c478bd9Sstevel@tonic-gate walk_one_link(struct node_list **headp, uint_t ep,
30447c478bd9Sstevel@tonic-gate     void *arg, int (*callback)(di_link_t link, void *arg))
30457c478bd9Sstevel@tonic-gate {
30467c478bd9Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
30477c478bd9Sstevel@tonic-gate 	di_link_t	link = DI_LINK_NIL;
30487c478bd9Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate 	while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
30517c478bd9Sstevel@tonic-gate 		action = callback(link, arg);
30527c478bd9Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
30537c478bd9Sstevel@tonic-gate 			break;
30547c478bd9Sstevel@tonic-gate 		}
30557c478bd9Sstevel@tonic-gate 	}
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
30587c478bd9Sstevel@tonic-gate }
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate int
30617c478bd9Sstevel@tonic-gate di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
30627c478bd9Sstevel@tonic-gate     int (*link_callback)(di_link_t link, void *arg))
30637c478bd9Sstevel@tonic-gate {
30647c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate #ifdef DEBUG
30677c478bd9Sstevel@tonic-gate 	char *path = di_devfs_path(root);
30687c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking %s link data under %s\n",
30697c478bd9Sstevel@tonic-gate 		    (endpoint == DI_LINK_SRC) ? "src" : "tgt", path));
30707c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
30717c478bd9Sstevel@tonic-gate #endif
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate 	/*
30747c478bd9Sstevel@tonic-gate 	 * paranoid error checking
30757c478bd9Sstevel@tonic-gate 	 */
30767c478bd9Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
30777c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
30787c478bd9Sstevel@tonic-gate 		errno = EINVAL;
30797c478bd9Sstevel@tonic-gate 		return (-1);
30807c478bd9Sstevel@tonic-gate 	}
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
30837c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
30847c478bd9Sstevel@tonic-gate 		return (-1);
30857c478bd9Sstevel@tonic-gate 	}
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate 	head->next = NULL;
30887c478bd9Sstevel@tonic-gate 	head->node = root;
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start link data walking from node %s\n",
30917c478bd9Sstevel@tonic-gate 		di_node_name(root)));
30927c478bd9Sstevel@tonic-gate 
30937c478bd9Sstevel@tonic-gate 	while (head != NULL)
30947c478bd9Sstevel@tonic-gate 		walk_one_link(&head, endpoint, arg, link_callback);
30957c478bd9Sstevel@tonic-gate 
30967c478bd9Sstevel@tonic-gate 	return (0);
30977c478bd9Sstevel@tonic-gate }
30987c478bd9Sstevel@tonic-gate 
30997c478bd9Sstevel@tonic-gate /*
31007c478bd9Sstevel@tonic-gate  * Internal library function:
31017c478bd9Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
31027c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
31037c478bd9Sstevel@tonic-gate  *
31047c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
31057c478bd9Sstevel@tonic-gate  *   first mode.
31067c478bd9Sstevel@tonic-gate  */
31077c478bd9Sstevel@tonic-gate static void
31087c478bd9Sstevel@tonic-gate walk_one_lnode(struct node_list **headp, void *arg,
31097c478bd9Sstevel@tonic-gate     int (*callback)(di_lnode_t lnode, void *arg))
31107c478bd9Sstevel@tonic-gate {
31117c478bd9Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
31127c478bd9Sstevel@tonic-gate 	di_lnode_t	lnode = DI_LNODE_NIL;
31137c478bd9Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
31147c478bd9Sstevel@tonic-gate 
31157c478bd9Sstevel@tonic-gate 	while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
31167c478bd9Sstevel@tonic-gate 		action = callback(lnode, arg);
31177c478bd9Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
31187c478bd9Sstevel@tonic-gate 			break;
31197c478bd9Sstevel@tonic-gate 		}
31207c478bd9Sstevel@tonic-gate 	}
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
31237c478bd9Sstevel@tonic-gate }
31247c478bd9Sstevel@tonic-gate 
31257c478bd9Sstevel@tonic-gate int
31267c478bd9Sstevel@tonic-gate di_walk_lnode(di_node_t root, uint_t flag, void *arg,
31277c478bd9Sstevel@tonic-gate     int (*lnode_callback)(di_lnode_t lnode, void *arg))
31287c478bd9Sstevel@tonic-gate {
31297c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
31307c478bd9Sstevel@tonic-gate 
31317c478bd9Sstevel@tonic-gate #ifdef DEBUG
31327c478bd9Sstevel@tonic-gate 	char *path = di_devfs_path(root);
31337c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking lnode data under %s\n", path));
31347c478bd9Sstevel@tonic-gate 	di_devfs_path_free(path);
31357c478bd9Sstevel@tonic-gate #endif
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	/*
31387c478bd9Sstevel@tonic-gate 	 * paranoid error checking
31397c478bd9Sstevel@tonic-gate 	 */
31407c478bd9Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
31417c478bd9Sstevel@tonic-gate 		errno = EINVAL;
31427c478bd9Sstevel@tonic-gate 		return (-1);
31437c478bd9Sstevel@tonic-gate 	}
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
31467c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
31477c478bd9Sstevel@tonic-gate 		return (-1);
31487c478bd9Sstevel@tonic-gate 	}
31497c478bd9Sstevel@tonic-gate 
31507c478bd9Sstevel@tonic-gate 	head->next = NULL;
31517c478bd9Sstevel@tonic-gate 	head->node = root;
31527c478bd9Sstevel@tonic-gate 
31537c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
31547c478bd9Sstevel@tonic-gate 		di_node_name(root)));
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 	while (head != NULL)
31577c478bd9Sstevel@tonic-gate 		walk_one_lnode(&head, arg, lnode_callback);
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate 	return (0);
31607c478bd9Sstevel@tonic-gate }
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate di_node_t
31637c478bd9Sstevel@tonic-gate di_lookup_node(di_node_t root, char *path)
31647c478bd9Sstevel@tonic-gate {
31657c478bd9Sstevel@tonic-gate 	struct di_all *dap;
31667c478bd9Sstevel@tonic-gate 	di_node_t node;
31677c478bd9Sstevel@tonic-gate 	char copy[MAXPATHLEN];
31687c478bd9Sstevel@tonic-gate 	char *slash, *pname, *paddr;
31697c478bd9Sstevel@tonic-gate 
31707c478bd9Sstevel@tonic-gate 	/*
31717c478bd9Sstevel@tonic-gate 	 * Path must be absolute and musn't have duplicate slashes
31727c478bd9Sstevel@tonic-gate 	 */
31737c478bd9Sstevel@tonic-gate 	if (*path != '/' || strstr(path, "//")) {
31747c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "Invalid path: %s\n", path));
31757c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
31767c478bd9Sstevel@tonic-gate 	}
31777c478bd9Sstevel@tonic-gate 
31787c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
31797c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
31807c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
31817c478bd9Sstevel@tonic-gate 	}
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 	dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
31847c478bd9Sstevel@tonic-gate 	if (strcmp(dap->root_path, "/") != 0) {
31857c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
31867c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
31877c478bd9Sstevel@tonic-gate 	}
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 	if (strlcpy(copy, path, sizeof (copy)) >= sizeof (copy)) {
31907c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "path too long: %s\n", path));
31917c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
31927c478bd9Sstevel@tonic-gate 	}
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 	for (slash = copy, node = root; slash; ) {
31957c478bd9Sstevel@tonic-gate 
31967c478bd9Sstevel@tonic-gate 		/*
31977c478bd9Sstevel@tonic-gate 		 * Handle path = "/" case as well as trailing '/'
31987c478bd9Sstevel@tonic-gate 		 */
31997c478bd9Sstevel@tonic-gate 		if (*(slash + 1) == '\0')
32007c478bd9Sstevel@tonic-gate 			break;
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate 		/*
32037c478bd9Sstevel@tonic-gate 		 * More path-components exist. Deal with the next one
32047c478bd9Sstevel@tonic-gate 		 */
32057c478bd9Sstevel@tonic-gate 		pname = slash + 1;
32067c478bd9Sstevel@tonic-gate 		node = di_child_node(node);
32077c478bd9Sstevel@tonic-gate 
32087c478bd9Sstevel@tonic-gate 		if (slash = strchr(pname, '/'))
32097c478bd9Sstevel@tonic-gate 			*slash = '\0';
32107c478bd9Sstevel@tonic-gate 		if (paddr = strchr(pname, '@'))
32117c478bd9Sstevel@tonic-gate 			*paddr++ = '\0';
32127c478bd9Sstevel@tonic-gate 
32137c478bd9Sstevel@tonic-gate 		for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
32147c478bd9Sstevel@tonic-gate 			char *name, *baddr;
32157c478bd9Sstevel@tonic-gate 
32167c478bd9Sstevel@tonic-gate 			name = di_node_name(node);
32177c478bd9Sstevel@tonic-gate 			baddr = di_bus_addr(node);
32187c478bd9Sstevel@tonic-gate 
32197c478bd9Sstevel@tonic-gate 			if (strcmp(pname, name) != 0)
32207c478bd9Sstevel@tonic-gate 				continue;
32217c478bd9Sstevel@tonic-gate 
32227c478bd9Sstevel@tonic-gate 			/*
32237c478bd9Sstevel@tonic-gate 			 * Mappings between a "path-address" and bus-addr
32247c478bd9Sstevel@tonic-gate 			 *
32257c478bd9Sstevel@tonic-gate 			 *	paddr		baddr
32267c478bd9Sstevel@tonic-gate 			 *	---------------------
32277c478bd9Sstevel@tonic-gate 			 *	NULL		NULL
32287c478bd9Sstevel@tonic-gate 			 *	NULL		""
32297c478bd9Sstevel@tonic-gate 			 *	""		N/A	(invalid paddr)
32307c478bd9Sstevel@tonic-gate 			 */
32317c478bd9Sstevel@tonic-gate 			if (paddr && baddr && strcmp(paddr, baddr) == 0)
32327c478bd9Sstevel@tonic-gate 				break;
32337c478bd9Sstevel@tonic-gate 			if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
32347c478bd9Sstevel@tonic-gate 				break;
32357c478bd9Sstevel@tonic-gate 		}
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate 		/*
32387c478bd9Sstevel@tonic-gate 		 * No nodes in the sibling list or there was no match
32397c478bd9Sstevel@tonic-gate 		 */
32407c478bd9Sstevel@tonic-gate 		if (node == DI_NODE_NIL) {
32417c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
32427c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
32437c478bd9Sstevel@tonic-gate 		}
32447c478bd9Sstevel@tonic-gate 	}
32457c478bd9Sstevel@tonic-gate 
32467c478bd9Sstevel@tonic-gate 	assert(node != DI_NODE_NIL);
32477c478bd9Sstevel@tonic-gate 	return (node);
32487c478bd9Sstevel@tonic-gate }
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate static char *
32517c478bd9Sstevel@tonic-gate msglevel2str(di_debug_t msglevel)
32527c478bd9Sstevel@tonic-gate {
32537c478bd9Sstevel@tonic-gate 	switch (msglevel) {
32547c478bd9Sstevel@tonic-gate 		case DI_ERR:
32557c478bd9Sstevel@tonic-gate 			return ("ERROR");
32567c478bd9Sstevel@tonic-gate 		case DI_INFO:
32577c478bd9Sstevel@tonic-gate 			return ("Info");
32587c478bd9Sstevel@tonic-gate 		case DI_TRACE:
32597c478bd9Sstevel@tonic-gate 			return ("Trace");
32607c478bd9Sstevel@tonic-gate 		case DI_TRACE1:
32617c478bd9Sstevel@tonic-gate 			return ("Trace1");
32627c478bd9Sstevel@tonic-gate 		case DI_TRACE2:
32637c478bd9Sstevel@tonic-gate 			return ("Trace2");
32647c478bd9Sstevel@tonic-gate 		default:
32657c478bd9Sstevel@tonic-gate 			return ("UNKNOWN");
32667c478bd9Sstevel@tonic-gate 	}
32677c478bd9Sstevel@tonic-gate }
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate void
32707c478bd9Sstevel@tonic-gate dprint(di_debug_t msglevel, const char *fmt, ...)
32717c478bd9Sstevel@tonic-gate {
32727c478bd9Sstevel@tonic-gate 	va_list	ap;
32737c478bd9Sstevel@tonic-gate 	char	*estr;
32747c478bd9Sstevel@tonic-gate 
32757c478bd9Sstevel@tonic-gate 	if (di_debug <= DI_QUIET)
32767c478bd9Sstevel@tonic-gate 		return;
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate 	if (di_debug < msglevel)
32797c478bd9Sstevel@tonic-gate 		return;
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate 	estr = msglevel2str(msglevel);
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate 	assert(estr);
32847c478bd9Sstevel@tonic-gate 
32857c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
32867c478bd9Sstevel@tonic-gate 
32877c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
32887c478bd9Sstevel@tonic-gate 	    (ulong_t)getpid(), estr);
32897c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
32907c478bd9Sstevel@tonic-gate 
32917c478bd9Sstevel@tonic-gate 	va_end(ap);
32927c478bd9Sstevel@tonic-gate }
32937c478bd9Sstevel@tonic-gate 
32947c478bd9Sstevel@tonic-gate /* end of devinfo.c */
3295