xref: /illumos-gate/usr/src/lib/libdevinfo/devinfo.c (revision 269473047d747f7815af570197e4ef7322d3632c)
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
53ebafc43Sjveta  * Common Development and Distribution License (the "License").
63ebafc43Sjveta  * 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 /*
224c06356bSdh142964  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Interfaces for getting device configuration data from kernel
287c478bd9Sstevel@tonic-gate  * through the devinfo driver.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <strings.h>
357c478bd9Sstevel@tonic-gate #include <stropts.h>
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <poll.h>
387c478bd9Sstevel@tonic-gate #include <synch.h>
397c478bd9Sstevel@tonic-gate #include <unistd.h>
407c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
417c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <sys/time.h>
457c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
467c478bd9Sstevel@tonic-gate #include <stdarg.h>
47*26947304SEvan Yan #include <sys/ddi_hp.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #define	NDEBUG 1
507c478bd9Sstevel@tonic-gate #include <assert.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include "libdevinfo.h"
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * Debug message levels
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate typedef enum {
587c478bd9Sstevel@tonic-gate 	DI_QUIET = 0,	/* No debug messages - the default */
597c478bd9Sstevel@tonic-gate 	DI_ERR = 1,
607c478bd9Sstevel@tonic-gate 	DI_INFO,
617c478bd9Sstevel@tonic-gate 	DI_TRACE,
627c478bd9Sstevel@tonic-gate 	DI_TRACE1,
637c478bd9Sstevel@tonic-gate 	DI_TRACE2
647c478bd9Sstevel@tonic-gate } di_debug_t;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate int di_debug = DI_QUIET;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	DPRINTF(args)	{ if (di_debug != DI_QUIET) dprint args; }
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate void dprint(di_debug_t msglevel, const char *fmt, ...);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #pragma init(_libdevinfo_init)
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate void
767c478bd9Sstevel@tonic-gate _libdevinfo_init()
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	char	*debug_str = getenv("_LIBDEVINFO_DEBUG");
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	if (debug_str) {
817c478bd9Sstevel@tonic-gate 		errno = 0;
827c478bd9Sstevel@tonic-gate 		di_debug = atoi(debug_str);
837c478bd9Sstevel@tonic-gate 		if (errno || di_debug < DI_QUIET)
847c478bd9Sstevel@tonic-gate 			di_debug = DI_QUIET;
857c478bd9Sstevel@tonic-gate 	}
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate di_node_t
897c478bd9Sstevel@tonic-gate di_init(const char *phys_path, uint_t flag)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	return (di_init_impl(phys_path, flag, NULL));
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * We use blocking_open() to guarantee access to the devinfo device, if open()
967c478bd9Sstevel@tonic-gate  * is failing with EAGAIN.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate static int
997c478bd9Sstevel@tonic-gate blocking_open(const char *path, int oflag)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	int fd;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
1047c478bd9Sstevel@tonic-gate 		(void) poll(NULL, 0, 1 * MILLISEC);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	return (fd);
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /* private interface */
1107c478bd9Sstevel@tonic-gate di_node_t
1117c478bd9Sstevel@tonic-gate di_init_driver(const char *drv_name, uint_t flag)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	int fd;
1147c478bd9Sstevel@tonic-gate 	char driver[MAXPATHLEN];
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/*
1177c478bd9Sstevel@tonic-gate 	 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
1187c478bd9Sstevel@tonic-gate 	 * which should be sufficient for any sensible programmer.
1197c478bd9Sstevel@tonic-gate 	 */
1207c478bd9Sstevel@tonic-gate 	if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
1217c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1227c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 	(void) strcpy(driver, drv_name);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/*
1277c478bd9Sstevel@tonic-gate 	 * open the devinfo driver
1287c478bd9Sstevel@tonic-gate 	 */
1297c478bd9Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
1307c478bd9Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
1317c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
1327c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOLODRV, driver) != 0) {
1367c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
1377c478bd9Sstevel@tonic-gate 		(void) close(fd);
1387c478bd9Sstevel@tonic-gate 		errno = ENXIO;
1397c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 	(void) close(fd);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	/*
1447c478bd9Sstevel@tonic-gate 	 * Driver load succeeded, return a snapshot
1457c478bd9Sstevel@tonic-gate 	 */
1467c478bd9Sstevel@tonic-gate 	return (di_init("/", flag));
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate di_node_t
1507c478bd9Sstevel@tonic-gate di_init_impl(const char *phys_path, uint_t flag,
1517c478bd9Sstevel@tonic-gate 	struct di_priv_data *priv)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	caddr_t pa;
1547c478bd9Sstevel@tonic-gate 	int fd, map_size;
1557c478bd9Sstevel@tonic-gate 	struct di_all *dap;
1567c478bd9Sstevel@tonic-gate 	struct dinfo_io dinfo_io;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
1597c478bd9Sstevel@tonic-gate 	uint_t pagemask = ~pageoffset;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * Make sure there is no minor name in the path
1657c478bd9Sstevel@tonic-gate 	 * and the path do not start with /devices....
1667c478bd9Sstevel@tonic-gate 	 */
1677c478bd9Sstevel@tonic-gate 	if (strchr(phys_path, ':') ||
1687c478bd9Sstevel@tonic-gate 	    (strncmp(phys_path, "/devices", 8) == 0) ||
1697c478bd9Sstevel@tonic-gate 	    (strlen(phys_path) > MAXPATHLEN)) {
1707c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1717c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (strlen(phys_path) == 0)
1757c478bd9Sstevel@tonic-gate 		(void) sprintf(dinfo_io.root_path, "/");
1767c478bd9Sstevel@tonic-gate 	else if (*phys_path != '/')
1777c478bd9Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
1787c478bd9Sstevel@tonic-gate 		    "/%s", phys_path);
1797c478bd9Sstevel@tonic-gate 	else
1807c478bd9Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
1817c478bd9Sstevel@tonic-gate 		    "%s", phys_path);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/*
1847c478bd9Sstevel@tonic-gate 	 * If private data is requested, copy the format specification
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 	if (flag & DINFOPRIVDATA & 0xff) {
1877c478bd9Sstevel@tonic-gate 		if (priv)
1887c478bd9Sstevel@tonic-gate 			bcopy(priv, &dinfo_io.priv,
1897c478bd9Sstevel@tonic-gate 			    sizeof (struct di_priv_data));
1907c478bd9Sstevel@tonic-gate 		else {
1917c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1927c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
1937c478bd9Sstevel@tonic-gate 		}
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/*
1977c478bd9Sstevel@tonic-gate 	 * Attempt to open the devinfo driver.  Make a second attempt at the
1987c478bd9Sstevel@tonic-gate 	 * read-only minor node if we don't have privileges to open the full
1997c478bd9Sstevel@tonic-gate 	 * version _and_ if we're not requesting operations that the read-only
2007c478bd9Sstevel@tonic-gate 	 * node can't perform.  (Setgid processes would fail an access() test,
2017c478bd9Sstevel@tonic-gate 	 * of course.)
2027c478bd9Sstevel@tonic-gate 	 */
2037c478bd9Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
2047c478bd9Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
2057c478bd9Sstevel@tonic-gate 		if ((flag & DINFOFORCE) == DINFOFORCE ||
2067c478bd9Sstevel@tonic-gate 		    (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
2077c478bd9Sstevel@tonic-gate 			/*
2087c478bd9Sstevel@tonic-gate 			 * We wanted to perform a privileged operation, but the
2097c478bd9Sstevel@tonic-gate 			 * privileged node isn't available.  Don't modify errno
2107c478bd9Sstevel@tonic-gate 			 * on our way out (but display it if we're running with
2117c478bd9Sstevel@tonic-gate 			 * di_debug set).
2127c478bd9Sstevel@tonic-gate 			 */
2137c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
2147c478bd9Sstevel@tonic-gate 			    errno));
2157c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 		if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
2197c478bd9Sstevel@tonic-gate 		    O_RDONLY)) == -1) {
2207c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
2217c478bd9Sstevel@tonic-gate 			    errno));
2227c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/*
2277c478bd9Sstevel@tonic-gate 	 * Verify that there is no major conflict, i.e., we are indeed opening
2287c478bd9Sstevel@tonic-gate 	 * the devinfo driver.
2297c478bd9Sstevel@tonic-gate 	 */
2307c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
2317c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR,
2327c478bd9Sstevel@tonic-gate 		    "driver ID failed; check for major conflict\n"));
2337c478bd9Sstevel@tonic-gate 		(void) close(fd);
2347c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/*
2387c478bd9Sstevel@tonic-gate 	 * create snapshot
2397c478bd9Sstevel@tonic-gate 	 */
2407c478bd9Sstevel@tonic-gate 	if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
2417c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo ioctl failed with "
2427c478bd9Sstevel@tonic-gate 		    "error: %d\n", errno));
2437c478bd9Sstevel@tonic-gate 		(void) close(fd);
2447c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2457c478bd9Sstevel@tonic-gate 	} else if (map_size == 0) {
2467c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
2477c478bd9Sstevel@tonic-gate 		errno = ENXIO;
2487c478bd9Sstevel@tonic-gate 		(void) close(fd);
2497c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/*
2537c478bd9Sstevel@tonic-gate 	 * copy snapshot to userland
2547c478bd9Sstevel@tonic-gate 	 */
2557c478bd9Sstevel@tonic-gate 	map_size = (map_size + pageoffset) & pagemask;
2567c478bd9Sstevel@tonic-gate 	if ((pa = valloc(map_size)) == NULL) {
2577c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
2587c478bd9Sstevel@tonic-gate 		(void) close(fd);
2597c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
2637c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
2647c478bd9Sstevel@tonic-gate 		(void) close(fd);
2657c478bd9Sstevel@tonic-gate 		free(pa);
2667c478bd9Sstevel@tonic-gate 		errno = EFAULT;
2677c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	(void) close(fd);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	dap = DI_ALL(pa);
2733e2676e0Svikram 	if (dap->version != DI_SNAPSHOT_VERSION) {
2743e2676e0Svikram 		DPRINTF((DI_ERR, "wrong snapshot version "
2753e2676e0Svikram 		    "(expected=%d, actual=%d)\n",
2763e2676e0Svikram 		    DI_SNAPSHOT_VERSION, dap->version));
2773e2676e0Svikram 		free(pa);
2783e2676e0Svikram 		errno = ESTALE;
2793e2676e0Svikram 		return (DI_NODE_NIL);
2803e2676e0Svikram 	}
2817c478bd9Sstevel@tonic-gate 	if (dap->top_devinfo == 0) {	/* phys_path not found */
2827c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
2837c478bd9Sstevel@tonic-gate 		free(pa);
2847c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2857c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + dap->top_devinfo));
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate void
2927c478bd9Sstevel@tonic-gate di_fini(di_node_t root)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/*
2997c478bd9Sstevel@tonic-gate 	 * paranoid checking
3007c478bd9Sstevel@tonic-gate 	 */
3017c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
3027c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
3037c478bd9Sstevel@tonic-gate 		return;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	/*
3077c478bd9Sstevel@tonic-gate 	 * The root contains its own offset--self.
3087c478bd9Sstevel@tonic-gate 	 * Subtracting it from root address, we get the starting addr.
3097c478bd9Sstevel@tonic-gate 	 * The map_size is stored at the beginning of snapshot.
3107c478bd9Sstevel@tonic-gate 	 * Once we have starting address and size, we can free().
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	free(pa);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate di_node_t
3187c478bd9Sstevel@tonic-gate di_parent_node(di_node_t node)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3237c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3247c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent) {
3327c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->parent));
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
3377c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
3387c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
3397c478bd9Sstevel@tonic-gate 	 */
3407c478bd9Sstevel@tonic-gate 	if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
3417c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
3427c478bd9Sstevel@tonic-gate 	else
3437c478bd9Sstevel@tonic-gate 		errno = ENXIO;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate di_node_t
3497c478bd9Sstevel@tonic-gate di_sibling_node(di_node_t node)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3547c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3557c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->sibling) {
3637c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->sibling));
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
3687c478bd9Sstevel@tonic-gate 	 *   Sibling doesn't exist, figure out if ioctl command
3697c478bd9Sstevel@tonic-gate 	 *   has DINFOSUBTREE set. If it doesn't, set errno to
3707c478bd9Sstevel@tonic-gate 	 *   ENOTSUP.
3717c478bd9Sstevel@tonic-gate 	 */
3727c478bd9Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
3737c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
3747c478bd9Sstevel@tonic-gate 	else
3757c478bd9Sstevel@tonic-gate 		errno = ENXIO;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate di_node_t
3817c478bd9Sstevel@tonic-gate di_child_node(di_node_t node)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3887c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3897c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->child) {
3957c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->child));
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	/*
3997c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
4007c478bd9Sstevel@tonic-gate 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
4017c478bd9Sstevel@tonic-gate 	 *   If it isn't, set errno to ENOTSUP.
4027c478bd9Sstevel@tonic-gate 	 */
4037c478bd9Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
4047c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
4057c478bd9Sstevel@tonic-gate 	else
4067c478bd9Sstevel@tonic-gate 		errno = ENXIO;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate di_node_t
4127c478bd9Sstevel@tonic-gate di_drv_first_node(const char *drv_name, di_node_t root)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
4157c478bd9Sstevel@tonic-gate 	int		major, devcnt;
4167c478bd9Sstevel@tonic-gate 	struct di_devnm	*devnm;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
4217c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4227c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * get major number of driver
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
4297c478bd9Sstevel@tonic-gate 	devcnt = DI_ALL(pa)->devcnt;
4307c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	for (major = 0; major < devcnt; major++)
4337c478bd9Sstevel@tonic-gate 		if (devnm[major].name && (strcmp(drv_name,
4347c478bd9Sstevel@tonic-gate 		    (char *)(pa + devnm[major].name)) == 0))
4357c478bd9Sstevel@tonic-gate 			break;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (major >= devcnt) {
4387c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4397c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	if (!(devnm[major].head)) {
4437c478bd9Sstevel@tonic-gate 		errno = ENXIO;
4447c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + devnm[major].head));
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate di_node_t
4517c478bd9Sstevel@tonic-gate di_drv_next_node(di_node_t node)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
4567c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4577c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "next node on per driver list:"
4617c478bd9Sstevel@tonic-gate 	    " current=%s, driver=%s\n",
4627c478bd9Sstevel@tonic-gate 	    di_node_name(node), di_driver_name(node)));
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->next == (di_off_t)-1) {
4657c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
4667c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->next == NULL) {
4727c478bd9Sstevel@tonic-gate 		errno = ENXIO;
4737c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	return (DI_NODE(pa + DI_NODE(node)->next));
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * Internal library interfaces:
4817c478bd9Sstevel@tonic-gate  *   node_list etc. for node walking
4827c478bd9Sstevel@tonic-gate  */
4837c478bd9Sstevel@tonic-gate struct node_list {
4847c478bd9Sstevel@tonic-gate 	struct node_list *next;
4857c478bd9Sstevel@tonic-gate 	di_node_t node;
4867c478bd9Sstevel@tonic-gate };
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate static void
4897c478bd9Sstevel@tonic-gate free_node_list(struct node_list **headp)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	while (*headp) {
4947c478bd9Sstevel@tonic-gate 		tmp = *headp;
4957c478bd9Sstevel@tonic-gate 		*headp = (*headp)->next;
4967c478bd9Sstevel@tonic-gate 		free(tmp);
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate static void
5017c478bd9Sstevel@tonic-gate append_node_list(struct node_list **headp, struct node_list *list)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if (*headp == NULL) {
5067c478bd9Sstevel@tonic-gate 		*headp = list;
5077c478bd9Sstevel@tonic-gate 		return;
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	if (list == NULL)	/* a minor optimization */
5117c478bd9Sstevel@tonic-gate 		return;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	tmp = *headp;
5147c478bd9Sstevel@tonic-gate 	while (tmp->next)
5157c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	tmp->next = list;
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static void
5217c478bd9Sstevel@tonic-gate prepend_node_list(struct node_list **headp, struct node_list *list)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	struct node_list *tmp;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (list == NULL)
5267c478bd9Sstevel@tonic-gate 		return;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	tmp = *headp;
5297c478bd9Sstevel@tonic-gate 	*headp = list;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (tmp == NULL)	/* a minor optimization */
5327c478bd9Sstevel@tonic-gate 		return;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	while (list->next)
5357c478bd9Sstevel@tonic-gate 		list = list->next;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	list->next = tmp;
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * returns 1 if node is a descendant of parent, 0 otherwise
5427c478bd9Sstevel@tonic-gate  */
5437c478bd9Sstevel@tonic-gate static int
5447c478bd9Sstevel@tonic-gate is_descendant(di_node_t node, di_node_t parent)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	/*
5477c478bd9Sstevel@tonic-gate 	 * DI_NODE_NIL is parent of root, so it is
5487c478bd9Sstevel@tonic-gate 	 * the parent of all nodes.
5497c478bd9Sstevel@tonic-gate 	 */
5507c478bd9Sstevel@tonic-gate 	if (parent == DI_NODE_NIL) {
5517c478bd9Sstevel@tonic-gate 		return (1);
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	do {
5557c478bd9Sstevel@tonic-gate 		node = di_parent_node(node);
5567c478bd9Sstevel@tonic-gate 	} while ((node != DI_NODE_NIL) && (node != parent));
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	return (node != DI_NODE_NIL);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate /*
5627c478bd9Sstevel@tonic-gate  * Insert list before the first node which is NOT a descendent of parent.
5637c478bd9Sstevel@tonic-gate  * This is needed to reproduce the exact walking order of link generators.
5647c478bd9Sstevel@tonic-gate  */
5657c478bd9Sstevel@tonic-gate static void
5667c478bd9Sstevel@tonic-gate insert_node_list(struct node_list **headp, struct node_list *list,
5677c478bd9Sstevel@tonic-gate     di_node_t parent)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	struct node_list *tmp, *tmp1;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (list == NULL)
5727c478bd9Sstevel@tonic-gate 		return;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	tmp = *headp;
5757c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {	/* a minor optimization */
5767c478bd9Sstevel@tonic-gate 		*headp = list;
5777c478bd9Sstevel@tonic-gate 		return;
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	if (!is_descendant(tmp->node, parent)) {
5817c478bd9Sstevel@tonic-gate 		prepend_node_list(headp, list);
5827c478bd9Sstevel@tonic-gate 		return;
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	/*
5867c478bd9Sstevel@tonic-gate 	 * Find first node which is not a descendant
5877c478bd9Sstevel@tonic-gate 	 */
5887c478bd9Sstevel@tonic-gate 	while (tmp->next && is_descendant(tmp->next->node, parent)) {
5897c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	tmp1 = tmp->next;
5937c478bd9Sstevel@tonic-gate 	tmp->next = list;
5947c478bd9Sstevel@tonic-gate 	append_node_list(headp, tmp1);
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate  *   Get a linked list of handles of all children
5997c478bd9Sstevel@tonic-gate  */
6007c478bd9Sstevel@tonic-gate static struct node_list *
6017c478bd9Sstevel@tonic-gate get_children(di_node_t node)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate 	di_node_t child;
6047c478bd9Sstevel@tonic-gate 	struct node_list *result, *tmp;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	if ((child = di_child_node(node)) == DI_NODE_NIL) {
6097c478bd9Sstevel@tonic-gate 		return (NULL);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	if ((result = malloc(sizeof (struct node_list))) == NULL) {
6137c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
6147c478bd9Sstevel@tonic-gate 		return (NULL);
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	result->node = child;
6187c478bd9Sstevel@tonic-gate 	tmp = result;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
6217c478bd9Sstevel@tonic-gate 		if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
6227c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "malloc of node_list failed\n"));
6237c478bd9Sstevel@tonic-gate 			free_node_list(&result);
6247c478bd9Sstevel@tonic-gate 			return (NULL);
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
6277c478bd9Sstevel@tonic-gate 		tmp->node = child;
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	tmp->next = NULL;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	return (result);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate /*
6367c478bd9Sstevel@tonic-gate  * Internal library interface:
6377c478bd9Sstevel@tonic-gate  *   Delete all siblings of the first node from the node_list, along with
6387c478bd9Sstevel@tonic-gate  *   the first node itself.
6397c478bd9Sstevel@tonic-gate  */
6407c478bd9Sstevel@tonic-gate static void
6417c478bd9Sstevel@tonic-gate prune_sib(struct node_list **headp)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	di_node_t parent, curr_par, curr_gpar;
6447c478bd9Sstevel@tonic-gate 	struct node_list *curr, *prev;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/*
6477c478bd9Sstevel@tonic-gate 	 * get handle to parent of first node
6487c478bd9Sstevel@tonic-gate 	 */
6497c478bd9Sstevel@tonic-gate 	if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
6507c478bd9Sstevel@tonic-gate 		/*
6517c478bd9Sstevel@tonic-gate 		 * This must be the root of the snapshot, so can't
6527c478bd9Sstevel@tonic-gate 		 * have any siblings.
6537c478bd9Sstevel@tonic-gate 		 *
6547c478bd9Sstevel@tonic-gate 		 * XXX Put a check here just in case.
6557c478bd9Sstevel@tonic-gate 		 */
6567c478bd9Sstevel@tonic-gate 		if ((*headp)->next)
6577c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		free(*headp);
6607c478bd9Sstevel@tonic-gate 		*headp = NULL;
6617c478bd9Sstevel@tonic-gate 		return;
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	/*
6657c478bd9Sstevel@tonic-gate 	 * To be complete, we should also delete the children
6667c478bd9Sstevel@tonic-gate 	 * of siblings that have already been visited.
6677c478bd9Sstevel@tonic-gate 	 * This happens for DI_WALK_SIBFIRST when the first node
6687c478bd9Sstevel@tonic-gate 	 * is NOT the first in the linked list of siblings.
6697c478bd9Sstevel@tonic-gate 	 *
6707c478bd9Sstevel@tonic-gate 	 * Hence, we compare parent with BOTH the parent and grandparent
6717c478bd9Sstevel@tonic-gate 	 * of nodes, and delete node is a match is found.
6727c478bd9Sstevel@tonic-gate 	 */
6737c478bd9Sstevel@tonic-gate 	prev = *headp;
6747c478bd9Sstevel@tonic-gate 	curr = prev->next;
6757c478bd9Sstevel@tonic-gate 	while (curr) {
6767c478bd9Sstevel@tonic-gate 		if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) &&
6777c478bd9Sstevel@tonic-gate 		    ((curr_par == parent) || ((curr_gpar =
6787c478bd9Sstevel@tonic-gate 		    di_parent_node(curr_par)) != DI_NODE_NIL) &&
6797c478bd9Sstevel@tonic-gate 		    (curr_gpar == parent))) {
6807c478bd9Sstevel@tonic-gate 			/*
6817c478bd9Sstevel@tonic-gate 			 * match parent/grandparent: delete curr
6827c478bd9Sstevel@tonic-gate 			 */
6837c478bd9Sstevel@tonic-gate 			prev->next = curr->next;
6847c478bd9Sstevel@tonic-gate 			free(curr);
6857c478bd9Sstevel@tonic-gate 			curr = prev->next;
6867c478bd9Sstevel@tonic-gate 		} else
6877c478bd9Sstevel@tonic-gate 			curr = curr->next;
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	/*
6917c478bd9Sstevel@tonic-gate 	 * delete the first node
6927c478bd9Sstevel@tonic-gate 	 */
6937c478bd9Sstevel@tonic-gate 	curr = *headp;
6947c478bd9Sstevel@tonic-gate 	*headp = curr->next;
6957c478bd9Sstevel@tonic-gate 	free(curr);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate /*
6997c478bd9Sstevel@tonic-gate  * Internal library function:
7007c478bd9Sstevel@tonic-gate  *	Update node list based on action (return code from callback)
7017c478bd9Sstevel@tonic-gate  *	and flag specifying walking behavior.
7027c478bd9Sstevel@tonic-gate  */
7037c478bd9Sstevel@tonic-gate static void
7047c478bd9Sstevel@tonic-gate update_node_list(int action, uint_t flag, struct node_list **headp)
7057c478bd9Sstevel@tonic-gate {
7067c478bd9Sstevel@tonic-gate 	struct node_list *children, *tmp;
7077c478bd9Sstevel@tonic-gate 	di_node_t parent = di_parent_node((*headp)->node);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	switch (action) {
7107c478bd9Sstevel@tonic-gate 	case DI_WALK_TERMINATE:
7117c478bd9Sstevel@tonic-gate 		/*
7127c478bd9Sstevel@tonic-gate 		 * free the node list and be done
7137c478bd9Sstevel@tonic-gate 		 */
7147c478bd9Sstevel@tonic-gate 		children = NULL;
7157c478bd9Sstevel@tonic-gate 		free_node_list(headp);
7167c478bd9Sstevel@tonic-gate 		break;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	case DI_WALK_PRUNESIB:
7197c478bd9Sstevel@tonic-gate 		/*
7207c478bd9Sstevel@tonic-gate 		 * Get list of children and prune siblings
7217c478bd9Sstevel@tonic-gate 		 */
7227c478bd9Sstevel@tonic-gate 		children = get_children((*headp)->node);
7237c478bd9Sstevel@tonic-gate 		prune_sib(headp);
7247c478bd9Sstevel@tonic-gate 		break;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	case DI_WALK_PRUNECHILD:
7277c478bd9Sstevel@tonic-gate 		/*
7287c478bd9Sstevel@tonic-gate 		 * Set children to NULL and pop first node
7297c478bd9Sstevel@tonic-gate 		 */
7307c478bd9Sstevel@tonic-gate 		children = NULL;
7317c478bd9Sstevel@tonic-gate 		tmp = *headp;
7327c478bd9Sstevel@tonic-gate 		*headp = tmp->next;
7337c478bd9Sstevel@tonic-gate 		free(tmp);
7347c478bd9Sstevel@tonic-gate 		break;
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	case DI_WALK_CONTINUE:
7377c478bd9Sstevel@tonic-gate 	default:
7387c478bd9Sstevel@tonic-gate 		/*
7397c478bd9Sstevel@tonic-gate 		 * Get list of children and pop first node
7407c478bd9Sstevel@tonic-gate 		 */
7417c478bd9Sstevel@tonic-gate 		children = get_children((*headp)->node);
7427c478bd9Sstevel@tonic-gate 		tmp = *headp;
7437c478bd9Sstevel@tonic-gate 		*headp = tmp->next;
7447c478bd9Sstevel@tonic-gate 		free(tmp);
7457c478bd9Sstevel@tonic-gate 		break;
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	/*
7497c478bd9Sstevel@tonic-gate 	 * insert the list of children
7507c478bd9Sstevel@tonic-gate 	 */
7517c478bd9Sstevel@tonic-gate 	switch (flag) {
7527c478bd9Sstevel@tonic-gate 	case DI_WALK_CLDFIRST:
7537c478bd9Sstevel@tonic-gate 		prepend_node_list(headp, children);
7547c478bd9Sstevel@tonic-gate 		break;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	case DI_WALK_SIBFIRST:
7577c478bd9Sstevel@tonic-gate 		append_node_list(headp, children);
7587c478bd9Sstevel@tonic-gate 		break;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	case DI_WALK_LINKGEN:
7617c478bd9Sstevel@tonic-gate 	default:
7627c478bd9Sstevel@tonic-gate 		insert_node_list(headp, children, parent);
7637c478bd9Sstevel@tonic-gate 		break;
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate /*
7687c478bd9Sstevel@tonic-gate  * Internal library function:
7697c478bd9Sstevel@tonic-gate  *   Invoke callback on one node and update the list of nodes to be walked
7707c478bd9Sstevel@tonic-gate  *   based on the flag and return code.
7717c478bd9Sstevel@tonic-gate  */
7727c478bd9Sstevel@tonic-gate static void
7737c478bd9Sstevel@tonic-gate walk_one_node(struct node_list **headp, uint_t flag, void *arg,
7747c478bd9Sstevel@tonic-gate 	int (*callback)(di_node_t, void *))
7757c478bd9Sstevel@tonic-gate {
7767c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	update_node_list(callback((*headp)->node, arg),
7797c478bd9Sstevel@tonic-gate 	    flag & DI_WALK_MASK, headp);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate int
7837c478bd9Sstevel@tonic-gate di_walk_node(di_node_t root, uint_t flag, void *arg,
7847c478bd9Sstevel@tonic-gate 	int (*node_callback)(di_node_t, void *))
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	if (root == NULL) {
7897c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7907c478bd9Sstevel@tonic-gate 		return (-1);
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
7947c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
7957c478bd9Sstevel@tonic-gate 		return (-1);
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	head->next = NULL;
7997c478bd9Sstevel@tonic-gate 	head->node = root;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start node walking from node %s\n",
8027c478bd9Sstevel@tonic-gate 	    di_node_name(root)));
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	while (head != NULL)
8057c478bd9Sstevel@tonic-gate 		walk_one_node(&head, flag, arg, node_callback);
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	return (0);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /*
8117c478bd9Sstevel@tonic-gate  * Internal library function:
8127c478bd9Sstevel@tonic-gate  *   Invoke callback for each minor on the minor list of first node
8137c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
8147c478bd9Sstevel@tonic-gate  *
8157c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
8167c478bd9Sstevel@tonic-gate  *   first mode.
8177c478bd9Sstevel@tonic-gate  */
8187c478bd9Sstevel@tonic-gate static void
8197c478bd9Sstevel@tonic-gate walk_one_minor_list(struct node_list **headp, const char *desired_type,
8207c478bd9Sstevel@tonic-gate 	uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	int ddm_type;
8237c478bd9Sstevel@tonic-gate 	int action = DI_WALK_CONTINUE;
8247c478bd9Sstevel@tonic-gate 	char *node_type;
8257c478bd9Sstevel@tonic-gate 	di_minor_t minor = DI_MINOR_NIL;
8267c478bd9Sstevel@tonic-gate 	di_node_t node = (*headp)->node;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
8297c478bd9Sstevel@tonic-gate 		ddm_type = di_minor_type(minor);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
8327c478bd9Sstevel@tonic-gate 			continue;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		if ((ddm_type == DDM_INTERNAL_PATH) &&
8357c478bd9Sstevel@tonic-gate 		    !(flag & DI_CHECK_INTERNAL_PATH))
8367c478bd9Sstevel@tonic-gate 			continue;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		node_type = di_minor_nodetype(minor);
8397c478bd9Sstevel@tonic-gate 		if ((desired_type != NULL) && ((node_type == NULL) ||
8407c478bd9Sstevel@tonic-gate 		    strncmp(desired_type, node_type, strlen(desired_type))
8417c478bd9Sstevel@tonic-gate 		    != 0))
8427c478bd9Sstevel@tonic-gate 			continue;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 		if ((action = callback(node, minor, arg)) ==
8457c478bd9Sstevel@tonic-gate 		    DI_WALK_TERMINATE) {
8467c478bd9Sstevel@tonic-gate 			break;
8477c478bd9Sstevel@tonic-gate 		}
8487c478bd9Sstevel@tonic-gate 	}
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate int
8547c478bd9Sstevel@tonic-gate di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
8557c478bd9Sstevel@tonic-gate 	int (*minor_callback)(di_node_t, di_minor_t, void *))
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate 	struct node_list	*head;	/* node_list for tree walk */
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate #ifdef DEBUG
860602ca9eaScth 	char	*devfspath = di_devfs_path(root);
861602ca9eaScth 	DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath));
862602ca9eaScth 	di_devfs_path_free(devfspath);
8637c478bd9Sstevel@tonic-gate #endif
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	if (root == NULL) {
8667c478bd9Sstevel@tonic-gate 		errno = EINVAL;
8677c478bd9Sstevel@tonic-gate 		return (-1);
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
8717c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
8727c478bd9Sstevel@tonic-gate 		return (-1);
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	head->next = NULL;
8767c478bd9Sstevel@tonic-gate 	head->node = root;
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start minor walking from node %s\n",
8797c478bd9Sstevel@tonic-gate 	    di_node_name(root)));
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	while (head != NULL)
8827c478bd9Sstevel@tonic-gate 		walk_one_minor_list(&head, minor_type, flag, arg,
8837c478bd9Sstevel@tonic-gate 		    minor_callback);
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	return (0);
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate /*
8897c478bd9Sstevel@tonic-gate  * generic node parameters
8907c478bd9Sstevel@tonic-gate  *   Calling these routines always succeeds.
8917c478bd9Sstevel@tonic-gate  */
8927c478bd9Sstevel@tonic-gate char *
8937c478bd9Sstevel@tonic-gate di_node_name(di_node_t node)
8947c478bd9Sstevel@tonic-gate {
8957c478bd9Sstevel@tonic-gate 	return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate /* returns NULL ptr or a valid ptr to non-NULL string */
8997c478bd9Sstevel@tonic-gate char *
9007c478bd9Sstevel@tonic-gate di_bus_addr(di_node_t node)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->address == 0)
9057c478bd9Sstevel@tonic-gate 		return (NULL);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->address));
9087c478bd9Sstevel@tonic-gate }
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate char *
9117c478bd9Sstevel@tonic-gate di_binding_name(di_node_t node)
9127c478bd9Sstevel@tonic-gate {
9137c478bd9Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->bind_name == 0)
9167c478bd9Sstevel@tonic-gate 		return (NULL);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->bind_name));
9197c478bd9Sstevel@tonic-gate }
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate int
9227c478bd9Sstevel@tonic-gate di_compatible_names(di_node_t node, char **names)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	char *c;
9257c478bd9Sstevel@tonic-gate 	int len, size, entries = 0;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->compat_names == 0) {
9287c478bd9Sstevel@tonic-gate 		*names = NULL;
9297c478bd9Sstevel@tonic-gate 		return (0);
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	*names = (caddr_t)node +
9337c478bd9Sstevel@tonic-gate 	    DI_NODE(node)->compat_names - DI_NODE(node)->self;
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	c = *names;
9367c478bd9Sstevel@tonic-gate 	len = DI_NODE(node)->compat_length;
9377c478bd9Sstevel@tonic-gate 	while (len > 0) {
9387c478bd9Sstevel@tonic-gate 		entries++;
9397c478bd9Sstevel@tonic-gate 		size = strlen(c) + 1;
9407c478bd9Sstevel@tonic-gate 		len -= size;
9417c478bd9Sstevel@tonic-gate 		c += size;
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	return (entries);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate int
9487c478bd9Sstevel@tonic-gate di_instance(di_node_t node)
9497c478bd9Sstevel@tonic-gate {
9507c478bd9Sstevel@tonic-gate 	return (DI_NODE(node)->instance);
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate /*
9547c478bd9Sstevel@tonic-gate  * XXX: emulate the return value of the old implementation
9557c478bd9Sstevel@tonic-gate  * using info from devi_node_class and devi_node_attributes.
9567c478bd9Sstevel@tonic-gate  */
9577c478bd9Sstevel@tonic-gate int
9587c478bd9Sstevel@tonic-gate di_nodeid(di_node_t node)
9597c478bd9Sstevel@tonic-gate {
9607c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->node_class == DDI_NC_PROM)
9617c478bd9Sstevel@tonic-gate 		return (DI_PROM_NODEID);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->attributes & DDI_PERSISTENT)
9647c478bd9Sstevel@tonic-gate 		return (DI_SID_NODEID);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	return (DI_PSEUDO_NODEID);
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate uint_t
9707c478bd9Sstevel@tonic-gate di_state(di_node_t node)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate 	uint_t result = 0;
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	if (di_node_state(node) < DS_ATTACHED)
9757c478bd9Sstevel@tonic-gate 		result |= DI_DRIVER_DETACHED;
9767c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
9777c478bd9Sstevel@tonic-gate 		result |= DI_DEVICE_OFFLINE;
9787c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
9794c06356bSdh142964 		result |= DI_DEVICE_DOWN;
98025c6ff4bSstephh 	if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
98125c6ff4bSstephh 		result |= DI_DEVICE_DEGRADED;
9824c06356bSdh142964 	if (DI_NODE(node)->state & DEVI_DEVICE_REMOVED)
9834c06356bSdh142964 		result |= DI_DEVICE_REMOVED;
9847c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
9857c478bd9Sstevel@tonic-gate 		result |= DI_BUS_QUIESCED;
9867c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_DOWN)
9877c478bd9Sstevel@tonic-gate 		result |= DI_BUS_DOWN;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	return (result);
9907c478bd9Sstevel@tonic-gate }
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate ddi_node_state_t
9937c478bd9Sstevel@tonic-gate di_node_state(di_node_t node)
9947c478bd9Sstevel@tonic-gate {
9957c478bd9Sstevel@tonic-gate 	return (DI_NODE(node)->node_state);
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate 
9983e2676e0Svikram uint_t
9993e2676e0Svikram di_flags(di_node_t node)
10003e2676e0Svikram {
10013e2676e0Svikram 	return (DI_NODE(node)->flags);
10023e2676e0Svikram }
10033e2676e0Svikram 
100425e8c5aaSvikram uint_t
100525e8c5aaSvikram di_retired(di_node_t node)
100625e8c5aaSvikram {
100725e8c5aaSvikram 	return (di_flags(node) & DEVI_RETIRED);
100825e8c5aaSvikram }
100925e8c5aaSvikram 
10107c478bd9Sstevel@tonic-gate ddi_devid_t
10117c478bd9Sstevel@tonic-gate di_devid(di_node_t node)
10127c478bd9Sstevel@tonic-gate {
10137c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->devid == 0)
10147c478bd9Sstevel@tonic-gate 		return (NULL);
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	return ((ddi_devid_t)((caddr_t)node +
10177c478bd9Sstevel@tonic-gate 	    DI_NODE(node)->devid - DI_NODE(node)->self));
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate int
10217c478bd9Sstevel@tonic-gate di_driver_major(di_node_t node)
10227c478bd9Sstevel@tonic-gate {
10237c478bd9Sstevel@tonic-gate 	int major;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10267c478bd9Sstevel@tonic-gate 	if (major < 0)
10277c478bd9Sstevel@tonic-gate 		return (-1);
10287c478bd9Sstevel@tonic-gate 	return (major);
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate char *
10327c478bd9Sstevel@tonic-gate di_driver_name(di_node_t node)
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate 	int major;
10357c478bd9Sstevel@tonic-gate 	caddr_t pa;
10367c478bd9Sstevel@tonic-gate 	struct di_devnm *devnm;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10397c478bd9Sstevel@tonic-gate 	if (major < 0)
10407c478bd9Sstevel@tonic-gate 		return (NULL);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
10437c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	if (devnm[major].name)
10467c478bd9Sstevel@tonic-gate 		return (pa + devnm[major].name);
10477c478bd9Sstevel@tonic-gate 	else
10487c478bd9Sstevel@tonic-gate 		return (NULL);
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate uint_t
10527c478bd9Sstevel@tonic-gate di_driver_ops(di_node_t node)
10537c478bd9Sstevel@tonic-gate {
10547c478bd9Sstevel@tonic-gate 	int major;
10557c478bd9Sstevel@tonic-gate 	caddr_t pa;
10567c478bd9Sstevel@tonic-gate 	struct di_devnm *devnm;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10597c478bd9Sstevel@tonic-gate 	if (major < 0)
10607c478bd9Sstevel@tonic-gate 		return (0);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
10637c478bd9Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	return (devnm[major].ops);
10667c478bd9Sstevel@tonic-gate }
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate /*
10697c478bd9Sstevel@tonic-gate  * returns the length of the path, caller must free memory
10707c478bd9Sstevel@tonic-gate  */
10717c478bd9Sstevel@tonic-gate char *
10727c478bd9Sstevel@tonic-gate di_devfs_path(di_node_t node)
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate 	caddr_t pa;
10757c478bd9Sstevel@tonic-gate 	di_node_t parent;
10767c478bd9Sstevel@tonic-gate 	int depth = 0, len = 0;
10777c478bd9Sstevel@tonic-gate 	char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH];
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
10807c478bd9Sstevel@tonic-gate 		errno = EINVAL;
10817c478bd9Sstevel@tonic-gate 		return (NULL);
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	/*
10857c478bd9Sstevel@tonic-gate 	 * trace back to root, note the node_name & address
10867c478bd9Sstevel@tonic-gate 	 */
10877c478bd9Sstevel@tonic-gate 	while ((parent = di_parent_node(node)) != DI_NODE_NIL) {
10887c478bd9Sstevel@tonic-gate 		name[depth] = di_node_name(node);
10897c478bd9Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;		/* 1 for '/' */
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 		if ((addr[depth] = di_bus_addr(node)) != NULL)
10927c478bd9Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;	/* 1 for '@' */
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		node = parent;
10957c478bd9Sstevel@tonic-gate 		depth++;
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	/*
10997c478bd9Sstevel@tonic-gate 	 * get the path to the root of snapshot
11007c478bd9Sstevel@tonic-gate 	 */
11017c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
11027c478bd9Sstevel@tonic-gate 	name[depth] = DI_ALL(pa)->root_path;
11037c478bd9Sstevel@tonic-gate 	len += strlen(name[depth]) + 1;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	/*
11067c478bd9Sstevel@tonic-gate 	 * allocate buffer and assemble path
11077c478bd9Sstevel@tonic-gate 	 */
11087c478bd9Sstevel@tonic-gate 	if ((buf = malloc(len)) == NULL) {
11097c478bd9Sstevel@tonic-gate 		return (NULL);
11107c478bd9Sstevel@tonic-gate 	}
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, name[depth]);
11137c478bd9Sstevel@tonic-gate 	len = strlen(buf);
11147c478bd9Sstevel@tonic-gate 	if (buf[len - 1] == '/')
11157c478bd9Sstevel@tonic-gate 		len--;	/* delete trailing '/' */
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	while (depth) {
11187c478bd9Sstevel@tonic-gate 		depth--;
11197c478bd9Sstevel@tonic-gate 		buf[len] = '/';
11207c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, name[depth]);
11217c478bd9Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;
11227c478bd9Sstevel@tonic-gate 		if (addr[depth] && addr[depth][0] != '\0') {
11237c478bd9Sstevel@tonic-gate 			buf[len] = '@';
11247c478bd9Sstevel@tonic-gate 			(void) strcpy(buf + len + 1, addr[depth]);
11257c478bd9Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;
11267c478bd9Sstevel@tonic-gate 		}
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	return (buf);
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate char *
11337c478bd9Sstevel@tonic-gate di_devfs_minor_path(di_minor_t minor)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate 	di_node_t	node;
1136602ca9eaScth 	char		*full_path, *name, *devfspath;
11377c478bd9Sstevel@tonic-gate 	int		full_path_len;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
11407c478bd9Sstevel@tonic-gate 		errno = EINVAL;
11417c478bd9Sstevel@tonic-gate 		return (NULL);
11427c478bd9Sstevel@tonic-gate 	}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	name = di_minor_name(minor);
11457c478bd9Sstevel@tonic-gate 	node = di_minor_devinfo(minor);
1146602ca9eaScth 	devfspath = di_devfs_path(node);
1147602ca9eaScth 	if (devfspath == NULL)
11487c478bd9Sstevel@tonic-gate 		return (NULL);
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	/* make the full path to the device minor node */
1151602ca9eaScth 	full_path_len = strlen(devfspath) + strlen(name) + 2;
11527c478bd9Sstevel@tonic-gate 	full_path = (char *)calloc(1, full_path_len);
11537c478bd9Sstevel@tonic-gate 	if (full_path != NULL)
1154602ca9eaScth 		(void) snprintf(full_path, full_path_len, "%s:%s",
1155602ca9eaScth 		    devfspath, name);
11567c478bd9Sstevel@tonic-gate 
1157602ca9eaScth 	di_devfs_path_free(devfspath);
11587c478bd9Sstevel@tonic-gate 	return (full_path);
11597c478bd9Sstevel@tonic-gate }
11607c478bd9Sstevel@tonic-gate 
1161602ca9eaScth /*
1162602ca9eaScth  * Produce a string representation of path to di_path_t (pathinfo node). This
1163602ca9eaScth  * string is identical to di_devfs_path had the device been enumerated under
1164602ca9eaScth  * the pHCI: it has a base path to pHCI, then uses node_name of client, and
1165602ca9eaScth  * device unit-address of pathinfo node.
1166602ca9eaScth  */
1167602ca9eaScth char *
1168602ca9eaScth di_path_devfs_path(di_path_t path)
1169602ca9eaScth {
1170602ca9eaScth 	di_node_t	phci_node;
1171602ca9eaScth 	char		*phci_path, *path_name, *path_addr;
1172602ca9eaScth 	char		*full_path;
1173602ca9eaScth 	int		full_path_len;
1174602ca9eaScth 
1175602ca9eaScth 	if (path == DI_PATH_NIL) {
1176602ca9eaScth 		errno = EINVAL;
1177602ca9eaScth 		return (NULL);
1178602ca9eaScth 	}
1179602ca9eaScth 
1180602ca9eaScth 	/* get name@addr for path */
1181602ca9eaScth 	path_name = di_path_node_name(path);
1182602ca9eaScth 	path_addr = di_path_bus_addr(path);
1183602ca9eaScth 	if ((path_name == NULL) || (path_addr == NULL))
1184602ca9eaScth 		return (NULL);
1185602ca9eaScth 
1186602ca9eaScth 	/* base path to pHCI devinfo node */
1187602ca9eaScth 	phci_node = di_path_phci_node(path);
1188602ca9eaScth 	if (phci_node == NULL)
1189602ca9eaScth 		return (NULL);
1190602ca9eaScth 	phci_path = di_devfs_path(phci_node);
1191602ca9eaScth 	if (phci_path == NULL)
1192602ca9eaScth 		return (NULL);
1193602ca9eaScth 
1194602ca9eaScth 	/* make the full string representation of path */
1195602ca9eaScth 	full_path_len = strlen(phci_path) + 1 + strlen(path_name) +
1196602ca9eaScth 	    1 + strlen(path_addr) + 1;
1197602ca9eaScth 	full_path = (char *)calloc(1, full_path_len);
1198602ca9eaScth 
1199602ca9eaScth 	if (full_path != NULL)
1200602ca9eaScth 		(void) snprintf(full_path, full_path_len, "%s/%s@%s",
1201602ca9eaScth 		    phci_path, path_name, path_addr);
1202602ca9eaScth 	di_devfs_path_free(phci_path);
1203602ca9eaScth 	return (full_path);
1204602ca9eaScth }
1205602ca9eaScth 
1206602ca9eaScth char *
1207602ca9eaScth di_path_client_devfs_path(di_path_t path)
1208602ca9eaScth {
1209602ca9eaScth 	return (di_devfs_path(di_path_client_node(path)));
1210602ca9eaScth }
1211602ca9eaScth 
12127c478bd9Sstevel@tonic-gate void
12137c478bd9Sstevel@tonic-gate di_devfs_path_free(char *buf)
12147c478bd9Sstevel@tonic-gate {
12157c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
12167c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
12177c478bd9Sstevel@tonic-gate 		return;
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	free(buf);
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate 
1223602ca9eaScth /*
1224602ca9eaScth  * Return 1 if name is a IEEE-1275 generic name. If new generic
1225602ca9eaScth  * names are defined, they should be added to this table
1226602ca9eaScth  */
1227602ca9eaScth static int
1228602ca9eaScth is_generic(const char *name, int len)
1229602ca9eaScth {
1230602ca9eaScth 	const char	**gp;
1231602ca9eaScth 
1232602ca9eaScth 	/* from IEEE-1275 recommended practices section 3 */
1233602ca9eaScth 	static const char *generic_names[] = {
1234602ca9eaScth 	    "atm",
1235602ca9eaScth 	    "disk",
1236602ca9eaScth 	    "display",
1237602ca9eaScth 	    "dma-controller",
1238602ca9eaScth 	    "ethernet",
1239602ca9eaScth 	    "fcs",
1240602ca9eaScth 	    "fdc",
1241602ca9eaScth 	    "fddi",
1242602ca9eaScth 	    "fibre-channel",
1243602ca9eaScth 	    "ide",
1244602ca9eaScth 	    "interrupt-controller",
1245602ca9eaScth 	    "isa",
1246602ca9eaScth 	    "keyboard",
1247602ca9eaScth 	    "memory",
1248602ca9eaScth 	    "mouse",
1249602ca9eaScth 	    "nvram",
1250602ca9eaScth 	    "pc-card",
1251602ca9eaScth 	    "pci",
1252602ca9eaScth 	    "printer",
1253602ca9eaScth 	    "rtc",
1254602ca9eaScth 	    "sbus",
1255602ca9eaScth 	    "scanner",
1256602ca9eaScth 	    "scsi",
1257602ca9eaScth 	    "serial",
1258602ca9eaScth 	    "sound",
1259602ca9eaScth 	    "ssa",
1260602ca9eaScth 	    "tape",
1261602ca9eaScth 	    "timer",
1262602ca9eaScth 	    "token-ring",
1263602ca9eaScth 	    "vme",
1264602ca9eaScth 	    0
1265602ca9eaScth 	};
1266602ca9eaScth 
1267602ca9eaScth 	for (gp = generic_names; *gp; gp++) {
1268602ca9eaScth 		if ((strncmp(*gp, name, len) == 0) &&
1269602ca9eaScth 		    (strlen(*gp) == len))
1270602ca9eaScth 			return (1);
1271602ca9eaScth 	}
1272602ca9eaScth 	return (0);
1273602ca9eaScth }
1274602ca9eaScth 
1275602ca9eaScth /*
1276602ca9eaScth  * Determine if two paths below /devices refer to the same device, ignoring
1277602ca9eaScth  * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*".
1278602ca9eaScth  * Return 1 if the paths match.
1279602ca9eaScth  */
1280602ca9eaScth int
1281602ca9eaScth di_devfs_path_match(const char *dp1, const char *dp2)
1282602ca9eaScth {
1283602ca9eaScth 	const char	*p1, *p2;
1284602ca9eaScth 	const char	*ec1, *ec2;
1285602ca9eaScth 	const char	*at1, *at2;
1286602ca9eaScth 	char		nc;
1287602ca9eaScth 	int		g1, g2;
1288602ca9eaScth 
1289602ca9eaScth 	/* progress through both strings */
1290602ca9eaScth 	for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) {
1291602ca9eaScth 		/* require match until the start of a component */
1292602ca9eaScth 		if (*p1 != '/')
1293602ca9eaScth 			continue;
1294602ca9eaScth 
1295602ca9eaScth 		/* advance p1 and p2 to start of 'name' in component */
1296602ca9eaScth 		nc = *(p1 + 1);
1297602ca9eaScth 		if ((nc == '\0') || (nc == '/'))
1298602ca9eaScth 			continue;		/* skip trash */
1299602ca9eaScth 		p1++;
1300602ca9eaScth 		p2++;
1301602ca9eaScth 
1302602ca9eaScth 		/*
1303602ca9eaScth 		 * Both p1 and p2 point to beginning of 'name' in component.
1304602ca9eaScth 		 * Determine where current component ends: next '/' or '\0'.
1305602ca9eaScth 		 */
1306602ca9eaScth 		ec1 = strchr(p1, '/');
1307602ca9eaScth 		if (ec1 == NULL)
1308602ca9eaScth 			ec1 = p1 + strlen(p1);
1309602ca9eaScth 		ec2 = strchr(p2, '/');
1310602ca9eaScth 		if (ec2 == NULL)
1311602ca9eaScth 			ec2 = p2 + strlen(p2);
1312602ca9eaScth 
1313602ca9eaScth 		/* Determine where name ends based on whether '@' exists */
1314602ca9eaScth 		at1 = strchr(p1, '@');
1315602ca9eaScth 		at2 = strchr(p2, '@');
1316602ca9eaScth 		if (at1 && (at1 < ec1))
1317602ca9eaScth 			ec1 = at1;
1318602ca9eaScth 		if (at2 && (at2 < ec2))
1319602ca9eaScth 			ec2 = at2;
1320602ca9eaScth 
1321602ca9eaScth 		/*
1322602ca9eaScth 		 * At this point p[12] point to beginning of name and
1323602ca9eaScth 		 * ec[12] point to character past the end of name. Determine
1324602ca9eaScth 		 * if the names are generic.
1325602ca9eaScth 		 */
1326602ca9eaScth 		g1 = is_generic(p1, ec1 - p1);
1327602ca9eaScth 		g2 = is_generic(p2, ec2 - p2);
1328602ca9eaScth 
1329602ca9eaScth 		if (g1 != g2) {
1330602ca9eaScth 			/*
1331602ca9eaScth 			 * one generic and one non-generic
1332602ca9eaScth 			 * skip past the names in the match.
1333602ca9eaScth 			 */
1334602ca9eaScth 			p1 = ec1;
1335602ca9eaScth 			p2 = ec2;
1336602ca9eaScth 		} else {
1337602ca9eaScth 			if (*p1 != *p2)
1338602ca9eaScth 				break;
1339602ca9eaScth 		}
1340602ca9eaScth 	}
1341602ca9eaScth 
1342602ca9eaScth 	return ((*p1 == *p2) ? 1 : 0);
1343602ca9eaScth }
1344602ca9eaScth 
13457c478bd9Sstevel@tonic-gate /* minor data access */
13467c478bd9Sstevel@tonic-gate di_minor_t
13477c478bd9Sstevel@tonic-gate di_minor_next(di_node_t node, di_minor_t minor)
13487c478bd9Sstevel@tonic-gate {
13497c478bd9Sstevel@tonic-gate 	caddr_t pa;
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	/*
13527c478bd9Sstevel@tonic-gate 	 * paranoid error checking
13537c478bd9Sstevel@tonic-gate 	 */
13547c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
13557c478bd9Sstevel@tonic-gate 		errno = EINVAL;
13567c478bd9Sstevel@tonic-gate 		return (DI_MINOR_NIL);
13577c478bd9Sstevel@tonic-gate 	}
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	/*
13607c478bd9Sstevel@tonic-gate 	 * minor is not NIL
13617c478bd9Sstevel@tonic-gate 	 */
13627c478bd9Sstevel@tonic-gate 	if (minor != DI_MINOR_NIL) {
13637c478bd9Sstevel@tonic-gate 		if (DI_MINOR(minor)->next != 0)
13647c478bd9Sstevel@tonic-gate 			return ((di_minor_t)((void *)((caddr_t)minor -
13657c478bd9Sstevel@tonic-gate 			    DI_MINOR(minor)->self + DI_MINOR(minor)->next)));
13667c478bd9Sstevel@tonic-gate 		else {
13677c478bd9Sstevel@tonic-gate 			errno = ENXIO;
13687c478bd9Sstevel@tonic-gate 			return (DI_MINOR_NIL);
13697c478bd9Sstevel@tonic-gate 		}
13707c478bd9Sstevel@tonic-gate 	}
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	/*
13737c478bd9Sstevel@tonic-gate 	 * minor is NIL-->caller asks for first minor node
13747c478bd9Sstevel@tonic-gate 	 */
13757c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->minor_data != 0) {
13767c478bd9Sstevel@tonic-gate 		return (DI_MINOR((caddr_t)node - DI_NODE(node)->self +
13777c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->minor_data));
13787c478bd9Sstevel@tonic-gate 	}
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	/*
13817c478bd9Sstevel@tonic-gate 	 * no minor data-->check if snapshot includes minor data
13827c478bd9Sstevel@tonic-gate 	 *	in order to set the correct errno
13837c478bd9Sstevel@tonic-gate 	 */
13847c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
13857c478bd9Sstevel@tonic-gate 	if (DINFOMINOR & DI_ALL(pa)->command)
13867c478bd9Sstevel@tonic-gate 		errno = ENXIO;
13877c478bd9Sstevel@tonic-gate 	else
13887c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	return (DI_MINOR_NIL);
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate /* private interface for dealing with alias minor link generation */
13947c478bd9Sstevel@tonic-gate di_node_t
13957c478bd9Sstevel@tonic-gate di_minor_devinfo(di_minor_t minor)
13967c478bd9Sstevel@tonic-gate {
13977c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
13987c478bd9Sstevel@tonic-gate 		errno = EINVAL;
13997c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
14007c478bd9Sstevel@tonic-gate 	}
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
14037c478bd9Sstevel@tonic-gate 	    DI_MINOR(minor)->node));
14047c478bd9Sstevel@tonic-gate }
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate ddi_minor_type
14077c478bd9Sstevel@tonic-gate di_minor_type(di_minor_t minor)
14087c478bd9Sstevel@tonic-gate {
14097c478bd9Sstevel@tonic-gate 	return (DI_MINOR(minor)->type);
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate char *
14137c478bd9Sstevel@tonic-gate di_minor_name(di_minor_t minor)
14147c478bd9Sstevel@tonic-gate {
14157c478bd9Sstevel@tonic-gate 	if (DI_MINOR(minor)->name == 0)
14167c478bd9Sstevel@tonic-gate 		return (NULL);
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate dev_t
14227c478bd9Sstevel@tonic-gate di_minor_devt(di_minor_t minor)
14237c478bd9Sstevel@tonic-gate {
14247c478bd9Sstevel@tonic-gate 	return (makedev(DI_MINOR(minor)->dev_major,
14257c478bd9Sstevel@tonic-gate 	    DI_MINOR(minor)->dev_minor));
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate int
14297c478bd9Sstevel@tonic-gate di_minor_spectype(di_minor_t minor)
14307c478bd9Sstevel@tonic-gate {
14317c478bd9Sstevel@tonic-gate 	return (DI_MINOR(minor)->spec_type);
14327c478bd9Sstevel@tonic-gate }
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate char *
14357c478bd9Sstevel@tonic-gate di_minor_nodetype(di_minor_t minor)
14367c478bd9Sstevel@tonic-gate {
14377c478bd9Sstevel@tonic-gate 	if (DI_MINOR(minor)->node_type == 0)
14387c478bd9Sstevel@tonic-gate 		return (NULL);
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 	return ((caddr_t)minor -
14417c478bd9Sstevel@tonic-gate 	    DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
14427c478bd9Sstevel@tonic-gate }
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate /*
14457c478bd9Sstevel@tonic-gate  * Single public interface for accessing software properties
14467c478bd9Sstevel@tonic-gate  */
14477c478bd9Sstevel@tonic-gate di_prop_t
14487c478bd9Sstevel@tonic-gate di_prop_next(di_node_t node, di_prop_t prop)
14497c478bd9Sstevel@tonic-gate {
14507c478bd9Sstevel@tonic-gate 	int list = DI_PROP_DRV_LIST;
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	/*
14537c478bd9Sstevel@tonic-gate 	 * paranoid check
14547c478bd9Sstevel@tonic-gate 	 */
14557c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
14567c478bd9Sstevel@tonic-gate 		errno = EINVAL;
14577c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
14587c478bd9Sstevel@tonic-gate 	}
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	/*
14617c478bd9Sstevel@tonic-gate 	 * Find which prop list we are at
14627c478bd9Sstevel@tonic-gate 	 */
14637c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL)
14647c478bd9Sstevel@tonic-gate 		list = DI_PROP(prop)->prop_list;
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	do {
14677c478bd9Sstevel@tonic-gate 		switch (list++) {
14687c478bd9Sstevel@tonic-gate 		case DI_PROP_DRV_LIST:
14697c478bd9Sstevel@tonic-gate 			prop = di_prop_drv_next(node, prop);
14707c478bd9Sstevel@tonic-gate 			break;
14717c478bd9Sstevel@tonic-gate 		case DI_PROP_SYS_LIST:
14727c478bd9Sstevel@tonic-gate 			prop = di_prop_sys_next(node, prop);
14737c478bd9Sstevel@tonic-gate 			break;
14747c478bd9Sstevel@tonic-gate 		case DI_PROP_GLB_LIST:
14757c478bd9Sstevel@tonic-gate 			prop = di_prop_global_next(node, prop);
14767c478bd9Sstevel@tonic-gate 			break;
14777c478bd9Sstevel@tonic-gate 		case DI_PROP_HW_LIST:
14787c478bd9Sstevel@tonic-gate 			prop = di_prop_hw_next(node, prop);
14797c478bd9Sstevel@tonic-gate 			break;
14807c478bd9Sstevel@tonic-gate 		default:	/* shouldn't happen */
14817c478bd9Sstevel@tonic-gate 			errno = EFAULT;
14827c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
14837c478bd9Sstevel@tonic-gate 		}
14847c478bd9Sstevel@tonic-gate 	} while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	return (prop);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate dev_t
14907c478bd9Sstevel@tonic-gate di_prop_devt(di_prop_t prop)
14917c478bd9Sstevel@tonic-gate {
14927c478bd9Sstevel@tonic-gate 	return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
14937c478bd9Sstevel@tonic-gate }
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate char *
14967c478bd9Sstevel@tonic-gate di_prop_name(di_prop_t prop)
14977c478bd9Sstevel@tonic-gate {
14987c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_name == 0)
14997c478bd9Sstevel@tonic-gate 		return (NULL);
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 	return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
15027c478bd9Sstevel@tonic-gate }
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate int
15057c478bd9Sstevel@tonic-gate di_prop_type(di_prop_t prop)
15067c478bd9Sstevel@tonic-gate {
15077c478bd9Sstevel@tonic-gate 	uint_t flags = DI_PROP(prop)->prop_flags;
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_UNDEF_IT)
15107c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNDEF_IT);
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15137c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_BOOLEAN);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
15167c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNKNOWN);
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT)
15197c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT);
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT64)
15227c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT64);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_STRING)
15257c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_STRING);
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_BYTE)
15287c478bd9Sstevel@tonic-gate 		return (DI_PROP_TYPE_BYTE);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	/*
15317c478bd9Sstevel@tonic-gate 	 * Shouldn't get here. In case we do, return unknown type.
15327c478bd9Sstevel@tonic-gate 	 *
15337c478bd9Sstevel@tonic-gate 	 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
15347c478bd9Sstevel@tonic-gate 	 *	to add DI_PROP_TYPE_COMPOSITE.
15357c478bd9Sstevel@tonic-gate 	 */
15367c478bd9Sstevel@tonic-gate 	DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate /*
15427c478bd9Sstevel@tonic-gate  * Extract type-specific values of an property
15437c478bd9Sstevel@tonic-gate  */
15447c478bd9Sstevel@tonic-gate extern int di_prop_decode_common(void *prop_data, int len,
15457c478bd9Sstevel@tonic-gate 	int ddi_type, int prom);
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate int
15487c478bd9Sstevel@tonic-gate di_prop_ints(di_prop_t prop, int **prop_data)
15497c478bd9Sstevel@tonic-gate {
15507c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15517c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
15547c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
15557c478bd9Sstevel@tonic-gate 		errno = EFAULT;
15567c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
15577c478bd9Sstevel@tonic-gate 		return (-1);
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
15617c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
15647c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
15657c478bd9Sstevel@tonic-gate }
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate int
15687c478bd9Sstevel@tonic-gate di_prop_int64(di_prop_t prop, int64_t **prop_data)
15697c478bd9Sstevel@tonic-gate {
15707c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15717c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
15747c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
15757c478bd9Sstevel@tonic-gate 		errno = EFAULT;
15767c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
15777c478bd9Sstevel@tonic-gate 		return (-1);
15787c478bd9Sstevel@tonic-gate 	}
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
15817c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
15847c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
15857c478bd9Sstevel@tonic-gate }
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate int
15887c478bd9Sstevel@tonic-gate di_prop_strings(di_prop_t prop, char **prop_data)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15917c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
15947c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
15957c478bd9Sstevel@tonic-gate 		errno = EFAULT;
15967c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
15977c478bd9Sstevel@tonic-gate 		return (-1);
15987c478bd9Sstevel@tonic-gate 	}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
16017c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
16047c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
16057c478bd9Sstevel@tonic-gate }
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate int
16087c478bd9Sstevel@tonic-gate di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
16097c478bd9Sstevel@tonic-gate {
16107c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
16117c478bd9Sstevel@tonic-gate 		return (0);	/* boolean property */
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
16147c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
16157c478bd9Sstevel@tonic-gate 		errno = EFAULT;
16167c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
16177c478bd9Sstevel@tonic-gate 		return (-1);
16187c478bd9Sstevel@tonic-gate 	}
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
16217c478bd9Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
16247c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate /*
16287c478bd9Sstevel@tonic-gate  * returns 1 for match, 0 for no match
16297c478bd9Sstevel@tonic-gate  */
16307c478bd9Sstevel@tonic-gate static int
16317c478bd9Sstevel@tonic-gate match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
16327c478bd9Sstevel@tonic-gate {
16337c478bd9Sstevel@tonic-gate 	int prop_type;
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate #ifdef DEBUG
16367c478bd9Sstevel@tonic-gate 	if (di_prop_name(prop) == NULL) {
16377c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
16387c478bd9Sstevel@tonic-gate 		return (0);
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate #endif /* DEBUG */
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	if (strcmp(name, di_prop_name(prop)) != 0)
16437c478bd9Sstevel@tonic-gate 		return (0);
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
16467c478bd9Sstevel@tonic-gate 		return (0);
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	/*
16497c478bd9Sstevel@tonic-gate 	 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
16507c478bd9Sstevel@tonic-gate 	 */
16517c478bd9Sstevel@tonic-gate 	prop_type = di_prop_type(prop);
16527c478bd9Sstevel@tonic-gate 	if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) &&
16537c478bd9Sstevel@tonic-gate 	    (prop_type != DI_PROP_TYPE_BOOLEAN))
16547c478bd9Sstevel@tonic-gate 		return (0);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	return (1);
16577c478bd9Sstevel@tonic-gate }
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate static di_prop_t
16607c478bd9Sstevel@tonic-gate di_prop_search(dev_t match_dev, di_node_t node, const char *name,
16617c478bd9Sstevel@tonic-gate     int type)
16627c478bd9Sstevel@tonic-gate {
16637c478bd9Sstevel@tonic-gate 	di_prop_t prop = DI_PROP_NIL;
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 	/*
16667c478bd9Sstevel@tonic-gate 	 * The check on match_dev follows ddi_prop_lookup_common().
16677c478bd9Sstevel@tonic-gate 	 * Other checks are libdevinfo specific implementation.
16687c478bd9Sstevel@tonic-gate 	 */
16697c478bd9Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
16707c478bd9Sstevel@tonic-gate 	    (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) {
16717c478bd9Sstevel@tonic-gate 		errno = EINVAL;
16727c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
16737c478bd9Sstevel@tonic-gate 	}
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
16767c478bd9Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n",
16777c478bd9Sstevel@tonic-gate 		    di_prop_name(prop), di_prop_devt(prop),
16787c478bd9Sstevel@tonic-gate 		    di_prop_type(prop)));
16797c478bd9Sstevel@tonic-gate 		if (match_prop(prop, match_dev, name, type))
16807c478bd9Sstevel@tonic-gate 			return (prop);
16817c478bd9Sstevel@tonic-gate 	}
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
16847c478bd9Sstevel@tonic-gate }
16857c478bd9Sstevel@tonic-gate 
16863ebafc43Sjveta di_prop_t
16873ebafc43Sjveta di_prop_find(dev_t match_dev, di_node_t node, const char *name)
16883ebafc43Sjveta {
16893ebafc43Sjveta 	di_prop_t prop = DI_PROP_NIL;
16903ebafc43Sjveta 
16913ebafc43Sjveta 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
16923ebafc43Sjveta 	    (match_dev == DDI_DEV_T_NONE)) {
16933ebafc43Sjveta 		errno = EINVAL;
16943ebafc43Sjveta 		return (DI_PROP_NIL);
16953ebafc43Sjveta 	}
16963ebafc43Sjveta 
16973ebafc43Sjveta 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
16983ebafc43Sjveta 		DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n",
16993ebafc43Sjveta 		    di_prop_name(prop), di_prop_devt(prop),
17003ebafc43Sjveta 		    di_prop_type(prop)));
17013ebafc43Sjveta 
17023ebafc43Sjveta 		if (strcmp(name, di_prop_name(prop)) == 0 &&
17033ebafc43Sjveta 		    (match_dev == DDI_DEV_T_ANY ||
17043ebafc43Sjveta 		    di_prop_devt(prop) == match_dev))
17053ebafc43Sjveta 			return (prop);
17063ebafc43Sjveta 	}
17073ebafc43Sjveta 
17083ebafc43Sjveta 	return (DI_PROP_NIL);
17093ebafc43Sjveta }
17103ebafc43Sjveta 
17117c478bd9Sstevel@tonic-gate int
17127c478bd9Sstevel@tonic-gate di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
17137c478bd9Sstevel@tonic-gate 	int **prop_data)
17147c478bd9Sstevel@tonic-gate {
17157c478bd9Sstevel@tonic-gate 	di_prop_t prop;
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17187c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
17197c478bd9Sstevel@tonic-gate 		return (-1);
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	return (di_prop_ints(prop, (void *)prop_data));
17227c478bd9Sstevel@tonic-gate }
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate int
17257c478bd9Sstevel@tonic-gate di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
17267c478bd9Sstevel@tonic-gate 	int64_t **prop_data)
17277c478bd9Sstevel@tonic-gate {
17287c478bd9Sstevel@tonic-gate 	di_prop_t prop;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17317c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
17327c478bd9Sstevel@tonic-gate 		return (-1);
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	return (di_prop_int64(prop, (void *)prop_data));
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate int
17387c478bd9Sstevel@tonic-gate di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
17397c478bd9Sstevel@tonic-gate     char **prop_data)
17407c478bd9Sstevel@tonic-gate {
17417c478bd9Sstevel@tonic-gate 	di_prop_t prop;
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17447c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
17457c478bd9Sstevel@tonic-gate 		return (-1);
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	return (di_prop_strings(prop, (void *)prop_data));
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate int
17517c478bd9Sstevel@tonic-gate di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
17527c478bd9Sstevel@tonic-gate 	uchar_t **prop_data)
17537c478bd9Sstevel@tonic-gate {
17547c478bd9Sstevel@tonic-gate 	di_prop_t prop;
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17577c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
17587c478bd9Sstevel@tonic-gate 		return (-1);
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	return (di_prop_bytes(prop, (void *)prop_data));
17617c478bd9Sstevel@tonic-gate }
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate /*
17647c478bd9Sstevel@tonic-gate  * Consolidation private property access functions
17657c478bd9Sstevel@tonic-gate  */
17667c478bd9Sstevel@tonic-gate enum prop_type {
17677c478bd9Sstevel@tonic-gate 	PROP_TYPE_DRV,
17687c478bd9Sstevel@tonic-gate 	PROP_TYPE_SYS,
17697c478bd9Sstevel@tonic-gate 	PROP_TYPE_GLOB,
17707c478bd9Sstevel@tonic-gate 	PROP_TYPE_HW
17717c478bd9Sstevel@tonic-gate };
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate static di_prop_t
17747c478bd9Sstevel@tonic-gate di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
17757c478bd9Sstevel@tonic-gate {
17767c478bd9Sstevel@tonic-gate 	caddr_t pa;
17777c478bd9Sstevel@tonic-gate 	di_off_t prop_off = 0;
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
17807c478bd9Sstevel@tonic-gate 		if (DI_PROP(prop)->next) {
17817c478bd9Sstevel@tonic-gate 			return (DI_PROP((caddr_t)prop -
17827c478bd9Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
17837c478bd9Sstevel@tonic-gate 		} else {
17847c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
17857c478bd9Sstevel@tonic-gate 		}
17867c478bd9Sstevel@tonic-gate 	}
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	/*
17907c478bd9Sstevel@tonic-gate 	 * prop is NIL, caller asks for first property
17917c478bd9Sstevel@tonic-gate 	 */
17927c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
17937c478bd9Sstevel@tonic-gate 	switch (prop_type) {
17947c478bd9Sstevel@tonic-gate 	case PROP_TYPE_DRV:
17957c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->drv_prop;
17967c478bd9Sstevel@tonic-gate 		break;
17977c478bd9Sstevel@tonic-gate 	case PROP_TYPE_SYS:
17987c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->sys_prop;
17997c478bd9Sstevel@tonic-gate 		break;
18007c478bd9Sstevel@tonic-gate 	case PROP_TYPE_HW:
18017c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->hw_prop;
18027c478bd9Sstevel@tonic-gate 		break;
18037c478bd9Sstevel@tonic-gate 	case PROP_TYPE_GLOB:
18047c478bd9Sstevel@tonic-gate 		prop_off = DI_NODE(node)->glob_prop;
18057c478bd9Sstevel@tonic-gate 		if (prop_off == -1) {
18067c478bd9Sstevel@tonic-gate 			/* no global property */
18077c478bd9Sstevel@tonic-gate 			prop_off = 0;
18087c478bd9Sstevel@tonic-gate 		} else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) {
18097c478bd9Sstevel@tonic-gate 			/* refer to devnames array */
18107c478bd9Sstevel@tonic-gate 			struct di_devnm *devnm = DI_DEVNM(pa +
18117c478bd9Sstevel@tonic-gate 			    DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major *
18127c478bd9Sstevel@tonic-gate 			    sizeof (struct di_devnm)));
18137c478bd9Sstevel@tonic-gate 			prop_off = devnm->global_prop;
18147c478bd9Sstevel@tonic-gate 		}
18157c478bd9Sstevel@tonic-gate 		break;
18167c478bd9Sstevel@tonic-gate 	}
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	if (prop_off) {
18197c478bd9Sstevel@tonic-gate 		return (DI_PROP(pa + prop_off));
18207c478bd9Sstevel@tonic-gate 	}
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	/*
18237c478bd9Sstevel@tonic-gate 	 * no prop found. Check the reason for not found
18247c478bd9Sstevel@tonic-gate 	 */
18257c478bd9Sstevel@tonic-gate 	if (DINFOPROP & DI_ALL(pa)->command)
18267c478bd9Sstevel@tonic-gate 		errno = ENXIO;
18277c478bd9Sstevel@tonic-gate 	else
18287c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate di_prop_t
18347c478bd9Sstevel@tonic-gate di_prop_drv_next(di_node_t node, di_prop_t prop)
18357c478bd9Sstevel@tonic-gate {
18367c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate di_prop_t
18407c478bd9Sstevel@tonic-gate di_prop_sys_next(di_node_t node, di_prop_t prop)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate di_prop_t
18467c478bd9Sstevel@tonic-gate di_prop_global_next(di_node_t node, di_prop_t prop)
18477c478bd9Sstevel@tonic-gate {
18487c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate di_prop_t
18527c478bd9Sstevel@tonic-gate di_prop_hw_next(di_node_t node, di_prop_t prop)
18537c478bd9Sstevel@tonic-gate {
18547c478bd9Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_HW));
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate int
18587c478bd9Sstevel@tonic-gate di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
18597c478bd9Sstevel@tonic-gate {
18607c478bd9Sstevel@tonic-gate #ifdef DEBUG
18617c478bd9Sstevel@tonic-gate 	if (prop == DI_PROP_NIL) {
18627c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18637c478bd9Sstevel@tonic-gate 		return (-1);
18647c478bd9Sstevel@tonic-gate 	}
18657c478bd9Sstevel@tonic-gate #endif /* DEBUG */
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0) {
18687c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
18697c478bd9Sstevel@tonic-gate 		return (0);
18707c478bd9Sstevel@tonic-gate 	}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
18737c478bd9Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
18747c478bd9Sstevel@tonic-gate 		errno = EFAULT;
18757c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
18767c478bd9Sstevel@tonic-gate 		return (-1);
18777c478bd9Sstevel@tonic-gate 	}
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	/*
18807c478bd9Sstevel@tonic-gate 	 * No memory allocation.
18817c478bd9Sstevel@tonic-gate 	 */
18827c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
18837c478bd9Sstevel@tonic-gate 	    DI_PROP(prop)->prop_data);
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	return (DI_PROP(prop)->prop_len);
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate /*
18897c478bd9Sstevel@tonic-gate  * Consolidation private interfaces for accessing I/O multipathing data
18907c478bd9Sstevel@tonic-gate  */
18917c478bd9Sstevel@tonic-gate di_path_t
1892602ca9eaScth di_path_phci_next_path(di_node_t node, di_path_t path)
18937c478bd9Sstevel@tonic-gate {
18947c478bd9Sstevel@tonic-gate 	caddr_t pa;
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 	/*
18977c478bd9Sstevel@tonic-gate 	 * path is not NIL
18987c478bd9Sstevel@tonic-gate 	 */
18997c478bd9Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
19007c478bd9Sstevel@tonic-gate 		if (DI_PATH(path)->path_p_link != 0)
19017c478bd9Sstevel@tonic-gate 			return (DI_PATH((void *)((caddr_t)path -
19027c478bd9Sstevel@tonic-gate 			    DI_PATH(path)->self + DI_PATH(path)->path_p_link)));
19037c478bd9Sstevel@tonic-gate 		else {
19047c478bd9Sstevel@tonic-gate 			errno = ENXIO;
19057c478bd9Sstevel@tonic-gate 			return (DI_PATH_NIL);
19067c478bd9Sstevel@tonic-gate 		}
19077c478bd9Sstevel@tonic-gate 	}
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	/*
19107c478bd9Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
19117c478bd9Sstevel@tonic-gate 	 */
19127c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_phci != 0) {
1913602ca9eaScth 		DPRINTF((DI_INFO, "phci_next_path: returning %p\n",
1914602ca9eaScth 		    ((caddr_t)node -
19157c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
19167c478bd9Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
19177c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->multipath_phci));
19187c478bd9Sstevel@tonic-gate 	}
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	/*
19217c478bd9Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
19227c478bd9Sstevel@tonic-gate 	 * to set errno properly.
19237c478bd9Sstevel@tonic-gate 	 */
19247c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
19257c478bd9Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
19267c478bd9Sstevel@tonic-gate 		errno = ENXIO;
19277c478bd9Sstevel@tonic-gate 	else
19287c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	return (DI_PATH_NIL);
19317c478bd9Sstevel@tonic-gate }
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate di_path_t
1934602ca9eaScth di_path_client_next_path(di_node_t node, di_path_t path)
19357c478bd9Sstevel@tonic-gate {
19367c478bd9Sstevel@tonic-gate 	caddr_t pa;
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	/*
19397c478bd9Sstevel@tonic-gate 	 * path is not NIL
19407c478bd9Sstevel@tonic-gate 	 */
19417c478bd9Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
19427c478bd9Sstevel@tonic-gate 		if (DI_PATH(path)->path_c_link != 0)
19437c478bd9Sstevel@tonic-gate 			return (DI_PATH((caddr_t)path - DI_PATH(path)->self
19447c478bd9Sstevel@tonic-gate 			    + DI_PATH(path)->path_c_link));
19457c478bd9Sstevel@tonic-gate 		else {
19467c478bd9Sstevel@tonic-gate 			errno = ENXIO;
19477c478bd9Sstevel@tonic-gate 			return (DI_PATH_NIL);
19487c478bd9Sstevel@tonic-gate 		}
19497c478bd9Sstevel@tonic-gate 	}
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	/*
19527c478bd9Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
19537c478bd9Sstevel@tonic-gate 	 */
19547c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_client != 0) {
1955602ca9eaScth 		DPRINTF((DI_INFO, "client_next_path: returning %p\n",
1956602ca9eaScth 		    ((caddr_t)node -
19577c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
19587c478bd9Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
19597c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->multipath_client));
19607c478bd9Sstevel@tonic-gate 	}
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	/*
19637c478bd9Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
19647c478bd9Sstevel@tonic-gate 	 * to set errno properly.
19657c478bd9Sstevel@tonic-gate 	 */
19667c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
19677c478bd9Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
19687c478bd9Sstevel@tonic-gate 		errno = ENXIO;
19697c478bd9Sstevel@tonic-gate 	else
19707c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	return (DI_PATH_NIL);
19737c478bd9Sstevel@tonic-gate }
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate /*
1976602ca9eaScth  * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
1977602ca9eaScth  * below after NWS consolidation switches to using di_path_bus_addr,
1978602ca9eaScth  * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
19797c478bd9Sstevel@tonic-gate  */
19807c478bd9Sstevel@tonic-gate char *
19817c478bd9Sstevel@tonic-gate di_path_addr(di_path_t path, char *buf)
19827c478bd9Sstevel@tonic-gate {
19837c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
19887c478bd9Sstevel@tonic-gate 	    MAXPATHLEN);
19897c478bd9Sstevel@tonic-gate 	return (buf);
19907c478bd9Sstevel@tonic-gate }
1991602ca9eaScth di_path_t
1992602ca9eaScth di_path_next(di_node_t node, di_path_t path)
1993602ca9eaScth {
1994602ca9eaScth 	if (node == DI_NODE_NIL) {
1995602ca9eaScth 		errno = EINVAL;
1996602ca9eaScth 		return (DI_PATH_NIL);
1997602ca9eaScth 	}
1998602ca9eaScth 
1999602ca9eaScth 	if (DI_NODE(node)->multipath_client) {
2000602ca9eaScth 		return (di_path_client_next_path(node, path));
2001602ca9eaScth 	} else if (DI_NODE(node)->multipath_phci) {
2002602ca9eaScth 		return (di_path_phci_next_path(node, path));
2003602ca9eaScth 	} else {
2004602ca9eaScth 		/*
2005602ca9eaScth 		 * The node had multipathing data but didn't appear to be a
2006602ca9eaScth 		 * phci *or* a client; probably a programmer error.
2007602ca9eaScth 		 */
2008602ca9eaScth 		errno = EINVAL;
2009602ca9eaScth 		return (DI_PATH_NIL);
2010602ca9eaScth 	}
2011602ca9eaScth }
2012602ca9eaScth di_path_t
2013602ca9eaScth di_path_next_phci(di_node_t node, di_path_t path)
2014602ca9eaScth {
2015602ca9eaScth 	return (di_path_client_next_path(node, path));
2016602ca9eaScth }
2017602ca9eaScth di_path_t
2018602ca9eaScth di_path_next_client(di_node_t node, di_path_t path)
2019602ca9eaScth {
2020602ca9eaScth 	return (di_path_phci_next_path(node, path));
2021602ca9eaScth }
2022602ca9eaScth 
2023602ca9eaScth 
2024602ca9eaScth 
2025602ca9eaScth 
2026602ca9eaScth di_path_state_t
2027602ca9eaScth di_path_state(di_path_t path)
2028602ca9eaScth {
2029602ca9eaScth 	return ((di_path_state_t)DI_PATH(path)->path_state);
2030602ca9eaScth }
2031602ca9eaScth 
20324c06356bSdh142964 uint_t
20334c06356bSdh142964 di_path_flags(di_path_t path)
20344c06356bSdh142964 {
20354c06356bSdh142964 	return (DI_PATH(path)->path_flags);
20364c06356bSdh142964 }
20374c06356bSdh142964 
2038602ca9eaScth char *
2039602ca9eaScth di_path_node_name(di_path_t path)
2040602ca9eaScth {
2041602ca9eaScth 	di_node_t	client_node;
2042602ca9eaScth 
2043602ca9eaScth 	/* pathinfo gets node_name from client */
2044602ca9eaScth 	if ((client_node = di_path_client_node(path)) == NULL)
2045602ca9eaScth 		return (NULL);
2046602ca9eaScth 	return (di_node_name(client_node));
2047602ca9eaScth }
2048602ca9eaScth 
2049602ca9eaScth char *
2050602ca9eaScth di_path_bus_addr(di_path_t path)
2051602ca9eaScth {
2052602ca9eaScth 	caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
2053602ca9eaScth 
2054602ca9eaScth 	if (DI_PATH(path)->path_addr == 0)
2055602ca9eaScth 		return (NULL);
2056602ca9eaScth 
2057602ca9eaScth 	return ((char *)(pa + DI_PATH(path)->path_addr));
2058602ca9eaScth }
2059602ca9eaScth 
2060602ca9eaScth int
2061602ca9eaScth di_path_instance(di_path_t path)
2062602ca9eaScth {
2063602ca9eaScth 	return (DI_PATH(path)->path_instance);
2064602ca9eaScth }
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate di_node_t
20677c478bd9Sstevel@tonic-gate di_path_client_node(di_path_t path)
20687c478bd9Sstevel@tonic-gate {
20697c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
20727c478bd9Sstevel@tonic-gate 		errno = EINVAL;
20737c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
20747c478bd9Sstevel@tonic-gate 	}
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_client) {
20817c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_client));
20827c478bd9Sstevel@tonic-gate 	}
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	/*
20857c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
20867c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
20877c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
20887c478bd9Sstevel@tonic-gate 	 */
20897c478bd9Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
20907c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
20917c478bd9Sstevel@tonic-gate 	else
20927c478bd9Sstevel@tonic-gate 		errno = ENXIO;
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
20957c478bd9Sstevel@tonic-gate }
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate di_node_t
20987c478bd9Sstevel@tonic-gate di_path_phci_node(di_path_t path)
20997c478bd9Sstevel@tonic-gate {
21007c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
21037c478bd9Sstevel@tonic-gate 		errno = EINVAL;
21047c478bd9Sstevel@tonic-gate 		return (DI_PATH_NIL);
21057c478bd9Sstevel@tonic-gate 	}
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_phci) {
21127c478bd9Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_phci));
21137c478bd9Sstevel@tonic-gate 	}
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	/*
21167c478bd9Sstevel@tonic-gate 	 * Deal with error condition:
21177c478bd9Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
21187c478bd9Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
21197c478bd9Sstevel@tonic-gate 	 */
21207c478bd9Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
21217c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
21227c478bd9Sstevel@tonic-gate 	else
21237c478bd9Sstevel@tonic-gate 		errno = ENXIO;
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	return (DI_NODE_NIL);
21267c478bd9Sstevel@tonic-gate }
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate di_path_prop_t
21297c478bd9Sstevel@tonic-gate di_path_prop_next(di_path_t path, di_path_prop_t prop)
21307c478bd9Sstevel@tonic-gate {
21317c478bd9Sstevel@tonic-gate 	caddr_t pa;
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
21347c478bd9Sstevel@tonic-gate 		errno = EINVAL;
21357c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
21367c478bd9Sstevel@tonic-gate 	}
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	/*
21397c478bd9Sstevel@tonic-gate 	 * prop is not NIL
21407c478bd9Sstevel@tonic-gate 	 */
21417c478bd9Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
21427c478bd9Sstevel@tonic-gate 		if (DI_PROP(prop)->next != 0)
21437c478bd9Sstevel@tonic-gate 			return (DI_PATHPROP((caddr_t)prop -
21447c478bd9Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
21457c478bd9Sstevel@tonic-gate 		else {
21467c478bd9Sstevel@tonic-gate 			errno = ENXIO;
21477c478bd9Sstevel@tonic-gate 			return (DI_PROP_NIL);
21487c478bd9Sstevel@tonic-gate 		}
21497c478bd9Sstevel@tonic-gate 	}
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	/*
21527c478bd9Sstevel@tonic-gate 	 * prop is NIL-->caller asks for first property
21537c478bd9Sstevel@tonic-gate 	 */
21547c478bd9Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
21557c478bd9Sstevel@tonic-gate 	if (DI_PATH(path)->path_prop != 0) {
21567c478bd9Sstevel@tonic-gate 		return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
21577c478bd9Sstevel@tonic-gate 	}
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	/*
21607c478bd9Sstevel@tonic-gate 	 * no property data-->check if snapshot includes props
21617c478bd9Sstevel@tonic-gate 	 *	in order to set the correct errno
21627c478bd9Sstevel@tonic-gate 	 */
21637c478bd9Sstevel@tonic-gate 	if (DINFOPROP & (DI_ALL(pa)->command))
21647c478bd9Sstevel@tonic-gate 		errno = ENXIO;
21657c478bd9Sstevel@tonic-gate 	else
21667c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
21697c478bd9Sstevel@tonic-gate }
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate char *
21727c478bd9Sstevel@tonic-gate di_path_prop_name(di_path_prop_t prop)
21737c478bd9Sstevel@tonic-gate {
21747c478bd9Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
21757c478bd9Sstevel@tonic-gate 	pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
21767c478bd9Sstevel@tonic-gate 	return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
21777c478bd9Sstevel@tonic-gate }
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate int
21807c478bd9Sstevel@tonic-gate di_path_prop_len(di_path_prop_t prop)
21817c478bd9Sstevel@tonic-gate {
21827c478bd9Sstevel@tonic-gate 	return (DI_PATHPROP(prop)->prop_len);
21837c478bd9Sstevel@tonic-gate }
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate int
21867c478bd9Sstevel@tonic-gate di_path_prop_type(di_path_prop_t prop)
21877c478bd9Sstevel@tonic-gate {
21887c478bd9Sstevel@tonic-gate 	switch (DI_PATHPROP(prop)->prop_type) {
21897c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT:
21907c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT);
21917c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT64:
21927c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT64);
21937c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_BYTE:
21947c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_BYTE);
21957c478bd9Sstevel@tonic-gate 		case DDI_PROP_TYPE_STRING:
21967c478bd9Sstevel@tonic-gate 			return (DI_PROP_TYPE_STRING);
21977c478bd9Sstevel@tonic-gate 	}
21987c478bd9Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
21997c478bd9Sstevel@tonic-gate }
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate int
22027c478bd9Sstevel@tonic-gate di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
22037c478bd9Sstevel@tonic-gate {
22047c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22057c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22067c478bd9Sstevel@tonic-gate 		errno = EFAULT;
22077c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
22087c478bd9Sstevel@tonic-gate 		return (-1);
22097c478bd9Sstevel@tonic-gate 	}
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
22127c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22157c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
22167c478bd9Sstevel@tonic-gate }
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate int
22197c478bd9Sstevel@tonic-gate di_path_prop_ints(di_path_prop_t prop, int **prop_data)
22207c478bd9Sstevel@tonic-gate {
22217c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
22227c478bd9Sstevel@tonic-gate 		return (0);
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22257c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22267c478bd9Sstevel@tonic-gate 		errno = EFAULT;
22277c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
22287c478bd9Sstevel@tonic-gate 		return (-1);
22297c478bd9Sstevel@tonic-gate 	}
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
22327c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data));
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22357c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate int
22397c478bd9Sstevel@tonic-gate di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
22407c478bd9Sstevel@tonic-gate {
22417c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
22427c478bd9Sstevel@tonic-gate 		return (0);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22457c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22467c478bd9Sstevel@tonic-gate 		errno = EFAULT;
22477c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
22487c478bd9Sstevel@tonic-gate 		return (-1);
22497c478bd9Sstevel@tonic-gate 	}
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop -
22527c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22557c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
22567c478bd9Sstevel@tonic-gate }
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate int
22597c478bd9Sstevel@tonic-gate di_path_prop_strings(di_path_prop_t prop, char **prop_data)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
22627c478bd9Sstevel@tonic-gate 		return (0);
22637c478bd9Sstevel@tonic-gate 
22647c478bd9Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22657c478bd9Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22667c478bd9Sstevel@tonic-gate 		errno = EFAULT;
22677c478bd9Sstevel@tonic-gate 		*prop_data = NULL;
22687c478bd9Sstevel@tonic-gate 		return (-1);
22697c478bd9Sstevel@tonic-gate 	}
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
22727c478bd9Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
22737c478bd9Sstevel@tonic-gate 
22747c478bd9Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22757c478bd9Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate static di_path_prop_t
22797c478bd9Sstevel@tonic-gate di_path_prop_search(di_path_t path, const char *name, int type)
22807c478bd9Sstevel@tonic-gate {
22817c478bd9Sstevel@tonic-gate 	di_path_prop_t prop = DI_PROP_NIL;
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 	/*
22847c478bd9Sstevel@tonic-gate 	 * Sanity check arguments
22857c478bd9Sstevel@tonic-gate 	 */
22867c478bd9Sstevel@tonic-gate 	if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
22877c478bd9Sstevel@tonic-gate 	    !DI_PROP_TYPE_VALID(type)) {
22887c478bd9Sstevel@tonic-gate 		errno = EINVAL;
22897c478bd9Sstevel@tonic-gate 		return (DI_PROP_NIL);
22907c478bd9Sstevel@tonic-gate 	}
22917c478bd9Sstevel@tonic-gate 
22927c478bd9Sstevel@tonic-gate 	while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
22937c478bd9Sstevel@tonic-gate 		int prop_type = di_path_prop_type(prop);
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
22967c478bd9Sstevel@tonic-gate 		    di_path_prop_name(prop), prop_type));
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 		if (strcmp(name, di_path_prop_name(prop)) != 0)
22997c478bd9Sstevel@tonic-gate 			continue;
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 		if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
23027c478bd9Sstevel@tonic-gate 			continue;
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 		return (prop);
23057c478bd9Sstevel@tonic-gate 	}
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 	return (DI_PROP_NIL);
23087c478bd9Sstevel@tonic-gate }
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate int
23117c478bd9Sstevel@tonic-gate di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
23127c478bd9Sstevel@tonic-gate     uchar_t **prop_data)
23137c478bd9Sstevel@tonic-gate {
23147c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23177c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
23187c478bd9Sstevel@tonic-gate 		return (-1);
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 	return (di_path_prop_bytes(prop, prop_data));
23217c478bd9Sstevel@tonic-gate }
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate int
23247c478bd9Sstevel@tonic-gate di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
23257c478bd9Sstevel@tonic-gate     int **prop_data)
23267c478bd9Sstevel@tonic-gate {
23277c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23307c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
23317c478bd9Sstevel@tonic-gate 		return (-1);
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 	return (di_path_prop_ints(prop, prop_data));
23347c478bd9Sstevel@tonic-gate }
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate int
23377c478bd9Sstevel@tonic-gate di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
23387c478bd9Sstevel@tonic-gate     int64_t **prop_data)
23397c478bd9Sstevel@tonic-gate {
23407c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23437c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
23447c478bd9Sstevel@tonic-gate 		return (-1);
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	return (di_path_prop_int64s(prop, prop_data));
23477c478bd9Sstevel@tonic-gate }
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
23507c478bd9Sstevel@tonic-gate     char **prop_data)
23517c478bd9Sstevel@tonic-gate {
23527c478bd9Sstevel@tonic-gate 	di_path_prop_t prop;
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23557c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
23567c478bd9Sstevel@tonic-gate 		return (-1);
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	return (di_path_prop_strings(prop, prop_data));
23597c478bd9Sstevel@tonic-gate }
23607c478bd9Sstevel@tonic-gate 
23618c4f8890Srs135747 /*
23628c4f8890Srs135747  * Consolidation private interfaces for traversing vhci nodes.
23638c4f8890Srs135747  */
23648c4f8890Srs135747 di_node_t
23658c4f8890Srs135747 di_vhci_first_node(di_node_t root)
23668c4f8890Srs135747 {
23678c4f8890Srs135747 	struct di_all *dap;
23688c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
23698c4f8890Srs135747 
23708c4f8890Srs135747 	DPRINTF((DI_INFO, "Get first vhci node\n"));
23718c4f8890Srs135747 
23728c4f8890Srs135747 	if (root == DI_NODE_NIL) {
23738c4f8890Srs135747 		errno = EINVAL;
23748c4f8890Srs135747 		return (DI_NODE_NIL);
23758c4f8890Srs135747 	}
23768c4f8890Srs135747 
23778c4f8890Srs135747 	pa = (caddr_t)root - DI_NODE(root)->self;
23788c4f8890Srs135747 	dap = DI_ALL(pa);
23798c4f8890Srs135747 
23808c4f8890Srs135747 	if (dap->top_vhci_devinfo == NULL) {
23818c4f8890Srs135747 		errno = ENXIO;
23828c4f8890Srs135747 		return (DI_NODE_NIL);
23838c4f8890Srs135747 	}
23848c4f8890Srs135747 
23858c4f8890Srs135747 	return (DI_NODE(pa + dap->top_vhci_devinfo));
23868c4f8890Srs135747 }
23878c4f8890Srs135747 
23888c4f8890Srs135747 di_node_t
23898c4f8890Srs135747 di_vhci_next_node(di_node_t node)
23908c4f8890Srs135747 {
23918c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
23928c4f8890Srs135747 
23938c4f8890Srs135747 	if (node == DI_NODE_NIL) {
23948c4f8890Srs135747 		errno = EINVAL;
23958c4f8890Srs135747 		return (DI_NODE_NIL);
23968c4f8890Srs135747 	}
23978c4f8890Srs135747 
23988c4f8890Srs135747 	DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
23998c4f8890Srs135747 	    " current=%s\n", di_node_name(node)));
24008c4f8890Srs135747 
24018c4f8890Srs135747 	if (DI_NODE(node)->next_vhci == NULL) {
24028c4f8890Srs135747 		errno = ENXIO;
24038c4f8890Srs135747 		return (DI_NODE_NIL);
24048c4f8890Srs135747 	}
24058c4f8890Srs135747 
24068c4f8890Srs135747 	pa = (caddr_t)node - DI_NODE(node)->self;
24078c4f8890Srs135747 
24088c4f8890Srs135747 	return (DI_NODE(pa + DI_NODE(node)->next_vhci));
24098c4f8890Srs135747 }
24108c4f8890Srs135747 
24118c4f8890Srs135747 /*
24128c4f8890Srs135747  * Consolidation private interfaces for traversing phci nodes.
24138c4f8890Srs135747  */
24148c4f8890Srs135747 di_node_t
24158c4f8890Srs135747 di_phci_first_node(di_node_t vhci_node)
24168c4f8890Srs135747 {
24178c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
24188c4f8890Srs135747 
24198c4f8890Srs135747 	DPRINTF((DI_INFO, "Get first phci node:\n"
24208c4f8890Srs135747 	    " current=%s", di_node_name(vhci_node)));
24218c4f8890Srs135747 
24228c4f8890Srs135747 	if (vhci_node == DI_NODE_NIL) {
24238c4f8890Srs135747 		errno = EINVAL;
24248c4f8890Srs135747 		return (DI_NODE_NIL);
24258c4f8890Srs135747 	}
24268c4f8890Srs135747 
24278c4f8890Srs135747 	pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
24288c4f8890Srs135747 
24298c4f8890Srs135747 	if (DI_NODE(vhci_node)->top_phci == NULL) {
24308c4f8890Srs135747 		errno = ENXIO;
24318c4f8890Srs135747 		return (DI_NODE_NIL);
24328c4f8890Srs135747 	}
24338c4f8890Srs135747 
24348c4f8890Srs135747 	return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
24358c4f8890Srs135747 }
24368c4f8890Srs135747 
24378c4f8890Srs135747 di_node_t
24388c4f8890Srs135747 di_phci_next_node(di_node_t node)
24398c4f8890Srs135747 {
24408c4f8890Srs135747 	caddr_t		pa;		/* starting address of map */
24418c4f8890Srs135747 
24428c4f8890Srs135747 	if (node == DI_NODE_NIL) {
24438c4f8890Srs135747 		errno = EINVAL;
24448c4f8890Srs135747 		return (DI_NODE_NIL);
24458c4f8890Srs135747 	}
24468c4f8890Srs135747 
24478c4f8890Srs135747 	DPRINTF((DI_TRACE, "next phci node on the snap shot:"
24488c4f8890Srs135747 	    " current=%s\n", di_node_name(node)));
24498c4f8890Srs135747 
24508c4f8890Srs135747 	if (DI_NODE(node)->next_phci == NULL) {
24518c4f8890Srs135747 		errno = ENXIO;
24528c4f8890Srs135747 		return (DI_NODE_NIL);
24538c4f8890Srs135747 	}
24548c4f8890Srs135747 
24558c4f8890Srs135747 	pa = (caddr_t)node - DI_NODE(node)->self;
24568c4f8890Srs135747 
24578c4f8890Srs135747 	return (DI_NODE(pa + DI_NODE(node)->next_phci));
24588c4f8890Srs135747 }
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate /*
24617c478bd9Sstevel@tonic-gate  * Consolidation private interfaces for private data
24627c478bd9Sstevel@tonic-gate  */
24637c478bd9Sstevel@tonic-gate void *
24647c478bd9Sstevel@tonic-gate di_parent_private_data(di_node_t node)
24657c478bd9Sstevel@tonic-gate {
24667c478bd9Sstevel@tonic-gate 	caddr_t pa;
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == 0) {
24697c478bd9Sstevel@tonic-gate 		errno = ENXIO;
24707c478bd9Sstevel@tonic-gate 		return (NULL);
24717c478bd9Sstevel@tonic-gate 	}
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == (di_off_t)-1) {
24747c478bd9Sstevel@tonic-gate 		/*
24757c478bd9Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
24767c478bd9Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
24777c478bd9Sstevel@tonic-gate 		 */
24787c478bd9Sstevel@tonic-gate 		errno = EFAULT;
24797c478bd9Sstevel@tonic-gate 		return (NULL);
24807c478bd9Sstevel@tonic-gate 	}
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
24837c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data)
24847c478bd9Sstevel@tonic-gate 		return (pa + DI_NODE(node)->parent_data);
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
24877c478bd9Sstevel@tonic-gate 		errno = ENXIO;
24887c478bd9Sstevel@tonic-gate 	else
24897c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	return (NULL);
24927c478bd9Sstevel@tonic-gate }
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate void *
24957c478bd9Sstevel@tonic-gate di_driver_private_data(di_node_t node)
24967c478bd9Sstevel@tonic-gate {
24977c478bd9Sstevel@tonic-gate 	caddr_t pa;
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == 0) {
25007c478bd9Sstevel@tonic-gate 		errno = ENXIO;
25017c478bd9Sstevel@tonic-gate 		return (NULL);
25027c478bd9Sstevel@tonic-gate 	}
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == (di_off_t)-1) {
25057c478bd9Sstevel@tonic-gate 		/*
25067c478bd9Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
25077c478bd9Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
25087c478bd9Sstevel@tonic-gate 		 */
25097c478bd9Sstevel@tonic-gate 		errno = EFAULT;
25107c478bd9Sstevel@tonic-gate 		return (NULL);
25117c478bd9Sstevel@tonic-gate 	}
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
25147c478bd9Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data)
25157c478bd9Sstevel@tonic-gate 		return (pa + DI_NODE(node)->driver_data);
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
25187c478bd9Sstevel@tonic-gate 		errno = ENXIO;
25197c478bd9Sstevel@tonic-gate 	else
25207c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 	return (NULL);
25237c478bd9Sstevel@tonic-gate }
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate /*
2526*26947304SEvan Yan  * Hotplug information access
2527*26947304SEvan Yan  */
2528*26947304SEvan Yan 
2529*26947304SEvan Yan typedef struct {
2530*26947304SEvan Yan 	void		*arg;
2531*26947304SEvan Yan 	const char	*type;
2532*26947304SEvan Yan 	uint_t		flag;
2533*26947304SEvan Yan 	int		(*hp_callback)(di_node_t, di_hp_t, void *);
2534*26947304SEvan Yan } di_walk_hp_arg_t;
2535*26947304SEvan Yan 
2536*26947304SEvan Yan static int
2537*26947304SEvan Yan di_walk_hp_callback(di_node_t node, void *argp)
2538*26947304SEvan Yan {
2539*26947304SEvan Yan 	di_walk_hp_arg_t 	*arg = (di_walk_hp_arg_t *)argp;
2540*26947304SEvan Yan 	di_hp_t			hp;
2541*26947304SEvan Yan 	char			*type_str;
2542*26947304SEvan Yan 
2543*26947304SEvan Yan 	for (hp = DI_HP_NIL; (hp = di_hp_next(node, hp)) != DI_HP_NIL; ) {
2544*26947304SEvan Yan 
2545*26947304SEvan Yan 		/* Exclude non-matching types if a type filter is specified */
2546*26947304SEvan Yan 		if (arg->type != NULL) {
2547*26947304SEvan Yan 			type_str = di_hp_description(hp);
2548*26947304SEvan Yan 			if (type_str && (strcmp(arg->type, type_str) != 0))
2549*26947304SEvan Yan 				continue;
2550*26947304SEvan Yan 		}
2551*26947304SEvan Yan 
2552*26947304SEvan Yan 		/* Exclude ports if DI_HP_PORT flag not specified */
2553*26947304SEvan Yan 		if (!(arg->flag & DI_HP_PORT) &&
2554*26947304SEvan Yan 		    (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2555*26947304SEvan Yan 			continue;
2556*26947304SEvan Yan 
2557*26947304SEvan Yan 		/* Exclude connectors if DI_HP_CONNECTOR flag not specified */
2558*26947304SEvan Yan 		if (!(arg->flag & DI_HP_CONNECTOR) &&
2559*26947304SEvan Yan 		    !(di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2560*26947304SEvan Yan 			continue;
2561*26947304SEvan Yan 
2562*26947304SEvan Yan 		/* Perform callback */
2563*26947304SEvan Yan 		if (arg->hp_callback(node, hp, arg->arg) != DI_WALK_CONTINUE)
2564*26947304SEvan Yan 			return (DI_WALK_TERMINATE);
2565*26947304SEvan Yan 	}
2566*26947304SEvan Yan 
2567*26947304SEvan Yan 	return (DI_WALK_CONTINUE);
2568*26947304SEvan Yan }
2569*26947304SEvan Yan 
2570*26947304SEvan Yan int
2571*26947304SEvan Yan di_walk_hp(di_node_t node, const char *type, uint_t flag, void *arg,
2572*26947304SEvan Yan     int (*hp_callback)(di_node_t node, di_hp_t hp, void *arg))
2573*26947304SEvan Yan {
2574*26947304SEvan Yan 	di_walk_hp_arg_t	walk_arg;
2575*26947304SEvan Yan 	caddr_t			pa;
2576*26947304SEvan Yan 
2577*26947304SEvan Yan #ifdef DEBUG
2578*26947304SEvan Yan 	char	*devfspath = di_devfs_path(node);
2579*26947304SEvan Yan 	DPRINTF((DI_INFO, "walking hotplug nodes under %s\n", devfspath));
2580*26947304SEvan Yan 	di_devfs_path_free(devfspath);
2581*26947304SEvan Yan #endif
2582*26947304SEvan Yan 	/*
2583*26947304SEvan Yan 	 * paranoid error checking
2584*26947304SEvan Yan 	 */
2585*26947304SEvan Yan 	if ((node == DI_NODE_NIL) || (hp_callback == NULL)) {
2586*26947304SEvan Yan 		errno = EINVAL;
2587*26947304SEvan Yan 		return (-1);
2588*26947304SEvan Yan 	}
2589*26947304SEvan Yan 
2590*26947304SEvan Yan 	/* check if hotplug data is included in snapshot */
2591*26947304SEvan Yan 	pa = (caddr_t)node - DI_NODE(node)->self;
2592*26947304SEvan Yan 	if (!(DI_ALL(pa)->command & DINFOHP)) {
2593*26947304SEvan Yan 		errno = ENOTSUP;
2594*26947304SEvan Yan 		return (-1);
2595*26947304SEvan Yan 	}
2596*26947304SEvan Yan 
2597*26947304SEvan Yan 	walk_arg.arg = arg;
2598*26947304SEvan Yan 	walk_arg.type = type;
2599*26947304SEvan Yan 	walk_arg.flag = flag;
2600*26947304SEvan Yan 	walk_arg.hp_callback = hp_callback;
2601*26947304SEvan Yan 	return (di_walk_node(node, DI_WALK_CLDFIRST, &walk_arg,
2602*26947304SEvan Yan 	    di_walk_hp_callback));
2603*26947304SEvan Yan }
2604*26947304SEvan Yan 
2605*26947304SEvan Yan di_hp_t
2606*26947304SEvan Yan di_hp_next(di_node_t node, di_hp_t hp)
2607*26947304SEvan Yan {
2608*26947304SEvan Yan 	caddr_t pa;
2609*26947304SEvan Yan 
2610*26947304SEvan Yan 	/*
2611*26947304SEvan Yan 	 * paranoid error checking
2612*26947304SEvan Yan 	 */
2613*26947304SEvan Yan 	if (node == DI_NODE_NIL) {
2614*26947304SEvan Yan 		errno = EINVAL;
2615*26947304SEvan Yan 		return (DI_HP_NIL);
2616*26947304SEvan Yan 	}
2617*26947304SEvan Yan 
2618*26947304SEvan Yan 	/*
2619*26947304SEvan Yan 	 * hotplug node is not NIL
2620*26947304SEvan Yan 	 */
2621*26947304SEvan Yan 	if (hp != DI_HP_NIL) {
2622*26947304SEvan Yan 		if (DI_HP(hp)->next != 0)
2623*26947304SEvan Yan 			return (DI_HP((caddr_t)hp - hp->self + hp->next));
2624*26947304SEvan Yan 		else {
2625*26947304SEvan Yan 			errno = ENXIO;
2626*26947304SEvan Yan 			return (DI_HP_NIL);
2627*26947304SEvan Yan 		}
2628*26947304SEvan Yan 	}
2629*26947304SEvan Yan 
2630*26947304SEvan Yan 	/*
2631*26947304SEvan Yan 	 * hotplug node is NIL-->caller asks for first hotplug node
2632*26947304SEvan Yan 	 */
2633*26947304SEvan Yan 	if (DI_NODE(node)->hp_data != 0) {
2634*26947304SEvan Yan 		return (DI_HP((caddr_t)node - DI_NODE(node)->self +
2635*26947304SEvan Yan 		    DI_NODE(node)->hp_data));
2636*26947304SEvan Yan 	}
2637*26947304SEvan Yan 
2638*26947304SEvan Yan 	/*
2639*26947304SEvan Yan 	 * no hotplug data-->check if snapshot includes hotplug data
2640*26947304SEvan Yan 	 *	in order to set the correct errno
2641*26947304SEvan Yan 	 */
2642*26947304SEvan Yan 	pa = (caddr_t)node - DI_NODE(node)->self;
2643*26947304SEvan Yan 	if (DINFOHP & DI_ALL(pa)->command)
2644*26947304SEvan Yan 		errno = ENXIO;
2645*26947304SEvan Yan 	else
2646*26947304SEvan Yan 		errno = ENOTSUP;
2647*26947304SEvan Yan 
2648*26947304SEvan Yan 	return (DI_HP_NIL);
2649*26947304SEvan Yan }
2650*26947304SEvan Yan 
2651*26947304SEvan Yan char *
2652*26947304SEvan Yan di_hp_name(di_hp_t hp)
2653*26947304SEvan Yan {
2654*26947304SEvan Yan 	caddr_t pa;
2655*26947304SEvan Yan 
2656*26947304SEvan Yan 	/*
2657*26947304SEvan Yan 	 * paranoid error checking
2658*26947304SEvan Yan 	 */
2659*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2660*26947304SEvan Yan 		errno = EINVAL;
2661*26947304SEvan Yan 		return (NULL);
2662*26947304SEvan Yan 	}
2663*26947304SEvan Yan 
2664*26947304SEvan Yan 	pa = (caddr_t)hp - DI_HP(hp)->self;
2665*26947304SEvan Yan 
2666*26947304SEvan Yan 	if (DI_HP(hp)->hp_name == 0) {
2667*26947304SEvan Yan 		errno = ENXIO;
2668*26947304SEvan Yan 		return (NULL);
2669*26947304SEvan Yan 	}
2670*26947304SEvan Yan 
2671*26947304SEvan Yan 	return ((char *)(pa + DI_HP(hp)->hp_name));
2672*26947304SEvan Yan }
2673*26947304SEvan Yan 
2674*26947304SEvan Yan int
2675*26947304SEvan Yan di_hp_connection(di_hp_t hp)
2676*26947304SEvan Yan {
2677*26947304SEvan Yan 	/*
2678*26947304SEvan Yan 	 * paranoid error checking
2679*26947304SEvan Yan 	 */
2680*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2681*26947304SEvan Yan 		errno = EINVAL;
2682*26947304SEvan Yan 		return (-1);
2683*26947304SEvan Yan 	}
2684*26947304SEvan Yan 
2685*26947304SEvan Yan 	if (DI_HP(hp)->hp_connection == -1)
2686*26947304SEvan Yan 		errno = ENOENT;
2687*26947304SEvan Yan 
2688*26947304SEvan Yan 	return (DI_HP(hp)->hp_connection);
2689*26947304SEvan Yan }
2690*26947304SEvan Yan 
2691*26947304SEvan Yan int
2692*26947304SEvan Yan di_hp_depends_on(di_hp_t hp)
2693*26947304SEvan Yan {
2694*26947304SEvan Yan 	/*
2695*26947304SEvan Yan 	 * paranoid error checking
2696*26947304SEvan Yan 	 */
2697*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2698*26947304SEvan Yan 		errno = EINVAL;
2699*26947304SEvan Yan 		return (-1);
2700*26947304SEvan Yan 	}
2701*26947304SEvan Yan 
2702*26947304SEvan Yan 	if (DI_HP(hp)->hp_depends_on == -1)
2703*26947304SEvan Yan 		errno = ENOENT;
2704*26947304SEvan Yan 
2705*26947304SEvan Yan 	return (DI_HP(hp)->hp_depends_on);
2706*26947304SEvan Yan }
2707*26947304SEvan Yan 
2708*26947304SEvan Yan int
2709*26947304SEvan Yan di_hp_state(di_hp_t hp)
2710*26947304SEvan Yan {
2711*26947304SEvan Yan 	/*
2712*26947304SEvan Yan 	 * paranoid error checking
2713*26947304SEvan Yan 	 */
2714*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2715*26947304SEvan Yan 		errno = EINVAL;
2716*26947304SEvan Yan 		return (-1);
2717*26947304SEvan Yan 	}
2718*26947304SEvan Yan 
2719*26947304SEvan Yan 	return (DI_HP(hp)->hp_state);
2720*26947304SEvan Yan }
2721*26947304SEvan Yan 
2722*26947304SEvan Yan int
2723*26947304SEvan Yan di_hp_type(di_hp_t hp)
2724*26947304SEvan Yan {
2725*26947304SEvan Yan 	/*
2726*26947304SEvan Yan 	 * paranoid error checking
2727*26947304SEvan Yan 	 */
2728*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2729*26947304SEvan Yan 		errno = EINVAL;
2730*26947304SEvan Yan 		return (-1);
2731*26947304SEvan Yan 	}
2732*26947304SEvan Yan 
2733*26947304SEvan Yan 	return (DI_HP(hp)->hp_type);
2734*26947304SEvan Yan }
2735*26947304SEvan Yan 
2736*26947304SEvan Yan char *
2737*26947304SEvan Yan di_hp_description(di_hp_t hp)
2738*26947304SEvan Yan {
2739*26947304SEvan Yan 	caddr_t pa;
2740*26947304SEvan Yan 
2741*26947304SEvan Yan 	/*
2742*26947304SEvan Yan 	 * paranoid error checking
2743*26947304SEvan Yan 	 */
2744*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2745*26947304SEvan Yan 		errno = EINVAL;
2746*26947304SEvan Yan 		return (NULL);
2747*26947304SEvan Yan 	}
2748*26947304SEvan Yan 
2749*26947304SEvan Yan 	pa = (caddr_t)hp - DI_HP(hp)->self;
2750*26947304SEvan Yan 
2751*26947304SEvan Yan 	if (DI_HP(hp)->hp_type_str == 0)
2752*26947304SEvan Yan 		return (NULL);
2753*26947304SEvan Yan 
2754*26947304SEvan Yan 	return ((char *)(pa + DI_HP(hp)->hp_type_str));
2755*26947304SEvan Yan }
2756*26947304SEvan Yan 
2757*26947304SEvan Yan di_node_t
2758*26947304SEvan Yan di_hp_child(di_hp_t hp)
2759*26947304SEvan Yan {
2760*26947304SEvan Yan 	caddr_t pa;		/* starting address of map */
2761*26947304SEvan Yan 
2762*26947304SEvan Yan 	/*
2763*26947304SEvan Yan 	 * paranoid error checking
2764*26947304SEvan Yan 	 */
2765*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2766*26947304SEvan Yan 		errno = EINVAL;
2767*26947304SEvan Yan 		return (DI_NODE_NIL);
2768*26947304SEvan Yan 	}
2769*26947304SEvan Yan 
2770*26947304SEvan Yan 	pa = (caddr_t)hp - DI_HP(hp)->self;
2771*26947304SEvan Yan 
2772*26947304SEvan Yan 	if (DI_HP(hp)->hp_child > 0) {
2773*26947304SEvan Yan 		return (DI_NODE(pa + DI_HP(hp)->hp_child));
2774*26947304SEvan Yan 	}
2775*26947304SEvan Yan 
2776*26947304SEvan Yan 	/*
2777*26947304SEvan Yan 	 * Deal with error condition:
2778*26947304SEvan Yan 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
2779*26947304SEvan Yan 	 *   If it isn't, set errno to ENOTSUP.
2780*26947304SEvan Yan 	 */
2781*26947304SEvan Yan 	if (!(DINFOSUBTREE & DI_ALL(pa)->command))
2782*26947304SEvan Yan 		errno = ENOTSUP;
2783*26947304SEvan Yan 	else
2784*26947304SEvan Yan 		errno = ENXIO;
2785*26947304SEvan Yan 
2786*26947304SEvan Yan 	return (DI_NODE_NIL);
2787*26947304SEvan Yan }
2788*26947304SEvan Yan 
2789*26947304SEvan Yan time_t
2790*26947304SEvan Yan di_hp_last_change(di_hp_t hp)
2791*26947304SEvan Yan {
2792*26947304SEvan Yan 	/*
2793*26947304SEvan Yan 	 * paranoid error checking
2794*26947304SEvan Yan 	 */
2795*26947304SEvan Yan 	if (hp == DI_HP_NIL) {
2796*26947304SEvan Yan 		errno = EINVAL;
2797*26947304SEvan Yan 		return ((time_t)0);
2798*26947304SEvan Yan 	}
2799*26947304SEvan Yan 
2800*26947304SEvan Yan 	return ((time_t)DI_HP(hp)->hp_last_change);
2801*26947304SEvan Yan }
2802*26947304SEvan Yan 
2803*26947304SEvan Yan /*
28047c478bd9Sstevel@tonic-gate  * PROM property access
28057c478bd9Sstevel@tonic-gate  */
28067c478bd9Sstevel@tonic-gate 
28077c478bd9Sstevel@tonic-gate /*
28087c478bd9Sstevel@tonic-gate  * openprom driver stuff:
28097c478bd9Sstevel@tonic-gate  *	The maximum property length depends on the buffer size. We use
28107c478bd9Sstevel@tonic-gate  *	OPROMMAXPARAM defined in <sys/openpromio.h>
28117c478bd9Sstevel@tonic-gate  *
28127c478bd9Sstevel@tonic-gate  *	MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
28137c478bd9Sstevel@tonic-gate  *	MAXVALSZ is maximum value size, which is whatever space left in buf
28147c478bd9Sstevel@tonic-gate  */
28157c478bd9Sstevel@tonic-gate 
28167c478bd9Sstevel@tonic-gate #define	OBP_MAXBUF	OPROMMAXPARAM - sizeof (int)
28177c478bd9Sstevel@tonic-gate #define	OBP_MAXPROPLEN	OBP_MAXBUF - OBP_MAXPROPNAME;
28187c478bd9Sstevel@tonic-gate 
28197c478bd9Sstevel@tonic-gate struct di_prom_prop {
28207c478bd9Sstevel@tonic-gate 	char *name;
28217c478bd9Sstevel@tonic-gate 	int len;
28227c478bd9Sstevel@tonic-gate 	uchar_t *data;
28237c478bd9Sstevel@tonic-gate 	struct di_prom_prop *next;	/* form a linked list */
28247c478bd9Sstevel@tonic-gate };
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate struct di_prom_handle { /* handle to prom */
28277c478bd9Sstevel@tonic-gate 	mutex_t lock;	/* synchronize access to openprom fd */
28287c478bd9Sstevel@tonic-gate 	int	fd;	/* /dev/openprom file descriptor */
28297c478bd9Sstevel@tonic-gate 	struct di_prom_prop *list;	/* linked list of prop */
28307c478bd9Sstevel@tonic-gate 	union {
28317c478bd9Sstevel@tonic-gate 		char buf[OPROMMAXPARAM];
28327c478bd9Sstevel@tonic-gate 		struct openpromio opp;
28337c478bd9Sstevel@tonic-gate 	} oppbuf;
28347c478bd9Sstevel@tonic-gate };
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate di_prom_handle_t
28377c478bd9Sstevel@tonic-gate di_prom_init()
28387c478bd9Sstevel@tonic-gate {
28397c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p;
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate 	if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
28427c478bd9Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
28437c478bd9Sstevel@tonic-gate 
28447c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 	(void) mutex_init(&p->lock, USYNC_THREAD, NULL);
28477c478bd9Sstevel@tonic-gate 	if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
28487c478bd9Sstevel@tonic-gate 		free(p);
28497c478bd9Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
28507c478bd9Sstevel@tonic-gate 	}
28517c478bd9Sstevel@tonic-gate 	p->list = NULL;
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 	return ((di_prom_handle_t)p);
28547c478bd9Sstevel@tonic-gate }
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate static void
28577c478bd9Sstevel@tonic-gate di_prom_prop_free(struct di_prom_prop *list)
28587c478bd9Sstevel@tonic-gate {
28597c478bd9Sstevel@tonic-gate 	struct di_prom_prop *tmp = list;
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate 	while (tmp != NULL) {
28627c478bd9Sstevel@tonic-gate 		list = tmp->next;
28637c478bd9Sstevel@tonic-gate 		if (tmp->name != NULL) {
28647c478bd9Sstevel@tonic-gate 			free(tmp->name);
28657c478bd9Sstevel@tonic-gate 		}
28667c478bd9Sstevel@tonic-gate 		if (tmp->data != NULL) {
28677c478bd9Sstevel@tonic-gate 			free(tmp->data);
28687c478bd9Sstevel@tonic-gate 		}
28697c478bd9Sstevel@tonic-gate 		free(tmp);
28707c478bd9Sstevel@tonic-gate 		tmp = list;
28717c478bd9Sstevel@tonic-gate 	}
28727c478bd9Sstevel@tonic-gate }
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate void
28757c478bd9Sstevel@tonic-gate di_prom_fini(di_prom_handle_t ph)
28767c478bd9Sstevel@tonic-gate {
28777c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate 	(void) close(p->fd);
28827c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&p->lock);
28837c478bd9Sstevel@tonic-gate 	di_prom_prop_free(p->list);
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate 	free(p);
28867c478bd9Sstevel@tonic-gate }
28877c478bd9Sstevel@tonic-gate 
28887c478bd9Sstevel@tonic-gate /*
28897c478bd9Sstevel@tonic-gate  * Internal library interface for locating the property
28907c478bd9Sstevel@tonic-gate  * XXX: ph->lock must be held for the duration of call.
28917c478bd9Sstevel@tonic-gate  */
28927c478bd9Sstevel@tonic-gate static di_prom_prop_t
28937c478bd9Sstevel@tonic-gate di_prom_prop_found(di_prom_handle_t ph, int nodeid,
28947c478bd9Sstevel@tonic-gate 	di_prom_prop_t prom_prop)
28957c478bd9Sstevel@tonic-gate {
28967c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
28977c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &p->oppbuf.opp;
28987c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
28997c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	/*
29047c478bd9Sstevel@tonic-gate 	 * Set "current" nodeid in the openprom driver
29057c478bd9Sstevel@tonic-gate 	 */
29067c478bd9Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
29077c478bd9Sstevel@tonic-gate 	*ip = nodeid;
29087c478bd9Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
29097c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
29107c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29117c478bd9Sstevel@tonic-gate 	}
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
29147c478bd9Sstevel@tonic-gate 
29157c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
29167c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPNAME;
29177c478bd9Sstevel@tonic-gate 	if (prom_prop != DI_PROM_PROP_NIL)
29187c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, prop->name);
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
29217c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate 	/*
29247c478bd9Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
29257c478bd9Sstevel@tonic-gate 	 *   (reuse variable prop)
29267c478bd9Sstevel@tonic-gate 	 */
29277c478bd9Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
29287c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29297c478bd9Sstevel@tonic-gate 
29307c478bd9Sstevel@tonic-gate 	/*
29317c478bd9Sstevel@tonic-gate 	 * Get a copy of property name
29327c478bd9Sstevel@tonic-gate 	 */
29337c478bd9Sstevel@tonic-gate 	if ((prop->name = strdup(opp->oprom_array)) == NULL) {
29347c478bd9Sstevel@tonic-gate 		free(prop);
29357c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29367c478bd9Sstevel@tonic-gate 	}
29377c478bd9Sstevel@tonic-gate 
29387c478bd9Sstevel@tonic-gate 	/*
29397c478bd9Sstevel@tonic-gate 	 * get property value and length
29407c478bd9Sstevel@tonic-gate 	 */
29417c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
29427c478bd9Sstevel@tonic-gate 
29437c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
29447c478bd9Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
29457c478bd9Sstevel@tonic-gate 		free(prop->name);
29467c478bd9Sstevel@tonic-gate 		free(prop);
29477c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29487c478bd9Sstevel@tonic-gate 	}
29497c478bd9Sstevel@tonic-gate 
29507c478bd9Sstevel@tonic-gate 	/*
29517c478bd9Sstevel@tonic-gate 	 * make a copy of the property value
29527c478bd9Sstevel@tonic-gate 	 */
29537c478bd9Sstevel@tonic-gate 	prop->len = opp->oprom_size;
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 	if (prop->len == 0)
29567c478bd9Sstevel@tonic-gate 		prop->data = NULL;
29577c478bd9Sstevel@tonic-gate 	else if ((prop->data = malloc(prop->len)) == NULL) {
29587c478bd9Sstevel@tonic-gate 		free(prop->name);
29597c478bd9Sstevel@tonic-gate 		free(prop);
29607c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29617c478bd9Sstevel@tonic-gate 	}
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate 	/*
29667c478bd9Sstevel@tonic-gate 	 * Prepend prop to list in prom handle
29677c478bd9Sstevel@tonic-gate 	 */
29687c478bd9Sstevel@tonic-gate 	prop->next = p->list;
29697c478bd9Sstevel@tonic-gate 	p->list = prop;
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	return ((di_prom_prop_t)prop);
29727c478bd9Sstevel@tonic-gate }
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate di_prom_prop_t
29757c478bd9Sstevel@tonic-gate di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
29767c478bd9Sstevel@tonic-gate {
29777c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
29807c478bd9Sstevel@tonic-gate 	    node, p));
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	/*
29837c478bd9Sstevel@tonic-gate 	 * paranoid check
29847c478bd9Sstevel@tonic-gate 	 */
29857c478bd9Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
29867c478bd9Sstevel@tonic-gate 		errno = EINVAL;
29877c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29887c478bd9Sstevel@tonic-gate 	}
29897c478bd9Sstevel@tonic-gate 
29907c478bd9Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
29917c478bd9Sstevel@tonic-gate 		errno = ENXIO;
29927c478bd9Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29937c478bd9Sstevel@tonic-gate 	}
29947c478bd9Sstevel@tonic-gate 
29957c478bd9Sstevel@tonic-gate 	/*
29967c478bd9Sstevel@tonic-gate 	 * synchronize access to prom file descriptor
29977c478bd9Sstevel@tonic-gate 	 */
29987c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 	/*
30017c478bd9Sstevel@tonic-gate 	 * look for next property
30027c478bd9Sstevel@tonic-gate 	 */
30037c478bd9Sstevel@tonic-gate 	prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	return (prom_prop);
30087c478bd9Sstevel@tonic-gate }
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate char *
30117c478bd9Sstevel@tonic-gate di_prom_prop_name(di_prom_prop_t prom_prop)
30127c478bd9Sstevel@tonic-gate {
30137c478bd9Sstevel@tonic-gate 	/*
30147c478bd9Sstevel@tonic-gate 	 * paranoid check
30157c478bd9Sstevel@tonic-gate 	 */
30167c478bd9Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
30177c478bd9Sstevel@tonic-gate 		errno = EINVAL;
30187c478bd9Sstevel@tonic-gate 		return (NULL);
30197c478bd9Sstevel@tonic-gate 	}
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->name);
30227c478bd9Sstevel@tonic-gate }
30237c478bd9Sstevel@tonic-gate 
30247c478bd9Sstevel@tonic-gate int
30257c478bd9Sstevel@tonic-gate di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
30267c478bd9Sstevel@tonic-gate {
30277c478bd9Sstevel@tonic-gate 	/*
30287c478bd9Sstevel@tonic-gate 	 * paranoid check
30297c478bd9Sstevel@tonic-gate 	 */
30307c478bd9Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
30317c478bd9Sstevel@tonic-gate 		errno = EINVAL;
30327c478bd9Sstevel@tonic-gate 		return (NULL);
30337c478bd9Sstevel@tonic-gate 	}
30347c478bd9Sstevel@tonic-gate 
30357c478bd9Sstevel@tonic-gate 	*prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->len);
30387c478bd9Sstevel@tonic-gate }
30397c478bd9Sstevel@tonic-gate 
30407c478bd9Sstevel@tonic-gate /*
30417c478bd9Sstevel@tonic-gate  * Internal library interface for locating the property
30427c478bd9Sstevel@tonic-gate  *    Returns length if found, -1 if prop doesn't exist.
30437c478bd9Sstevel@tonic-gate  */
30447c478bd9Sstevel@tonic-gate static struct di_prom_prop *
30457c478bd9Sstevel@tonic-gate di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
30467c478bd9Sstevel@tonic-gate 	const char *prom_prop_name)
30477c478bd9Sstevel@tonic-gate {
30487c478bd9Sstevel@tonic-gate 	struct openpromio *opp;
30497c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
30507c478bd9Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
30517c478bd9Sstevel@tonic-gate 
30527c478bd9Sstevel@tonic-gate 	/*
30537c478bd9Sstevel@tonic-gate 	 * paranoid check
30547c478bd9Sstevel@tonic-gate 	 */
30557c478bd9Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
30567c478bd9Sstevel@tonic-gate 		errno = EINVAL;
30577c478bd9Sstevel@tonic-gate 		return (NULL);
30587c478bd9Sstevel@tonic-gate 	}
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
30617c478bd9Sstevel@tonic-gate 		errno = ENXIO;
30627c478bd9Sstevel@tonic-gate 		return (NULL);
30637c478bd9Sstevel@tonic-gate 	}
30647c478bd9Sstevel@tonic-gate 
30657c478bd9Sstevel@tonic-gate 	opp = &p->oppbuf.opp;
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
30687c478bd9Sstevel@tonic-gate 
30697c478bd9Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
30707c478bd9Sstevel@tonic-gate 	opp->oprom_node = DI_NODE(node)->nodeid;
30717c478bd9Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
30727c478bd9Sstevel@tonic-gate 		errno = ENXIO;
30737c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
30747c478bd9Sstevel@tonic-gate 		    DI_NODE(node)->nodeid));
30757c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
30767c478bd9Sstevel@tonic-gate 		return (NULL);
30777c478bd9Sstevel@tonic-gate 	}
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 	/*
30807c478bd9Sstevel@tonic-gate 	 * get property length
30817c478bd9Sstevel@tonic-gate 	 */
30827c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
30837c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
30847c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
30857c478bd9Sstevel@tonic-gate 
30867c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
30877c478bd9Sstevel@tonic-gate 	    (opp->oprom_len == -1)) {
30887c478bd9Sstevel@tonic-gate 		/* no such property */
30897c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
30907c478bd9Sstevel@tonic-gate 		return (NULL);
30917c478bd9Sstevel@tonic-gate 	}
30927c478bd9Sstevel@tonic-gate 
30937c478bd9Sstevel@tonic-gate 	/*
30947c478bd9Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
30957c478bd9Sstevel@tonic-gate 	 */
30967c478bd9Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
30977c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
30987c478bd9Sstevel@tonic-gate 		return (NULL);
30997c478bd9Sstevel@tonic-gate 	}
31007c478bd9Sstevel@tonic-gate 	prop->name = NULL;	/* we don't need the name */
31017c478bd9Sstevel@tonic-gate 	prop->len = opp->oprom_len;
31027c478bd9Sstevel@tonic-gate 
31037c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
31047c478bd9Sstevel@tonic-gate 		prop->data = NULL;
31057c478bd9Sstevel@tonic-gate 		prop->next = p->list;
31067c478bd9Sstevel@tonic-gate 		p->list = prop;
31077c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
31087c478bd9Sstevel@tonic-gate 		return (prop);
31097c478bd9Sstevel@tonic-gate 	}
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 	/*
31127c478bd9Sstevel@tonic-gate 	 * retrieve the property value
31137c478bd9Sstevel@tonic-gate 	 */
31147c478bd9Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
31157c478bd9Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
31167c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
31177c478bd9Sstevel@tonic-gate 
31187c478bd9Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
31197c478bd9Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
31207c478bd9Sstevel@tonic-gate 		/* error retrieving property value */
31217c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
31227c478bd9Sstevel@tonic-gate 		free(prop);
31237c478bd9Sstevel@tonic-gate 		return (NULL);
31247c478bd9Sstevel@tonic-gate 	}
31257c478bd9Sstevel@tonic-gate 
31267c478bd9Sstevel@tonic-gate 	/*
31277c478bd9Sstevel@tonic-gate 	 * make a copy of the property value, stick in ph->list
31287c478bd9Sstevel@tonic-gate 	 */
31297c478bd9Sstevel@tonic-gate 	if ((prop->data = malloc(prop->len)) == NULL) {
31307c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
31317c478bd9Sstevel@tonic-gate 		free(prop);
31327c478bd9Sstevel@tonic-gate 		return (NULL);
31337c478bd9Sstevel@tonic-gate 	}
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	prop->next = p->list;
31387c478bd9Sstevel@tonic-gate 	p->list = prop;
31397c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate 	return (prop);
31427c478bd9Sstevel@tonic-gate }
31437c478bd9Sstevel@tonic-gate 
31447c478bd9Sstevel@tonic-gate int
31457c478bd9Sstevel@tonic-gate di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
31467c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, int **prom_prop_data)
31477c478bd9Sstevel@tonic-gate {
31487c478bd9Sstevel@tonic-gate 	int len;
31497c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
31527c478bd9Sstevel@tonic-gate 
31537c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
31547c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
31557c478bd9Sstevel@tonic-gate 		return (-1);
31567c478bd9Sstevel@tonic-gate 	}
31577c478bd9Sstevel@tonic-gate 
31587c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
31597c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
31607c478bd9Sstevel@tonic-gate 		return (0);
31617c478bd9Sstevel@tonic-gate 	}
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
31647c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_INT, 1);
31657c478bd9Sstevel@tonic-gate 	*prom_prop_data = (int *)((void *)prop->data);
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 	return (len);
31687c478bd9Sstevel@tonic-gate }
31697c478bd9Sstevel@tonic-gate 
31707c478bd9Sstevel@tonic-gate int
31717c478bd9Sstevel@tonic-gate di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
31727c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, char **prom_prop_data)
31737c478bd9Sstevel@tonic-gate {
31747c478bd9Sstevel@tonic-gate 	int len;
31757c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
31767c478bd9Sstevel@tonic-gate 
31777c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
31787c478bd9Sstevel@tonic-gate 
31797c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
31807c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
31817c478bd9Sstevel@tonic-gate 		return (-1);
31827c478bd9Sstevel@tonic-gate 	}
31837c478bd9Sstevel@tonic-gate 
31847c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
31857c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
31867c478bd9Sstevel@tonic-gate 		return (0);
31877c478bd9Sstevel@tonic-gate 	}
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 	/*
31907c478bd9Sstevel@tonic-gate 	 * Fix an openprom bug (OBP string not NULL terminated).
31917c478bd9Sstevel@tonic-gate 	 * XXX This should really be fixed in promif.
31927c478bd9Sstevel@tonic-gate 	 */
31937c478bd9Sstevel@tonic-gate 	if (((char *)prop->data)[prop->len - 1] != '\0') {
31947c478bd9Sstevel@tonic-gate 		uchar_t *tmp;
31957c478bd9Sstevel@tonic-gate 		prop->len++;
31967c478bd9Sstevel@tonic-gate 		if ((tmp = realloc(prop->data, prop->len)) == NULL)
31977c478bd9Sstevel@tonic-gate 			return (-1);
31987c478bd9Sstevel@tonic-gate 
31997c478bd9Sstevel@tonic-gate 		prop->data = tmp;
32007c478bd9Sstevel@tonic-gate 		((char *)prop->data)[prop->len - 1] = '\0';
32017c478bd9Sstevel@tonic-gate 		DPRINTF((DI_INFO, "OBP string not NULL terminated: "
32027c478bd9Sstevel@tonic-gate 		    "node=%s, prop=%s, val=%s\n",
32037c478bd9Sstevel@tonic-gate 		    di_node_name(node), prom_prop_name, prop->data));
32047c478bd9Sstevel@tonic-gate 	}
32057c478bd9Sstevel@tonic-gate 
32067c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
32077c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING, 1);
32087c478bd9Sstevel@tonic-gate 	*prom_prop_data = (char *)prop->data;
32097c478bd9Sstevel@tonic-gate 
32107c478bd9Sstevel@tonic-gate 	return (len);
32117c478bd9Sstevel@tonic-gate }
32127c478bd9Sstevel@tonic-gate 
32137c478bd9Sstevel@tonic-gate int
32147c478bd9Sstevel@tonic-gate di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
32157c478bd9Sstevel@tonic-gate 	const char *prom_prop_name, uchar_t **prom_prop_data)
32167c478bd9Sstevel@tonic-gate {
32177c478bd9Sstevel@tonic-gate 	int len;
32187c478bd9Sstevel@tonic-gate 	struct di_prom_prop *prop;
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
32217c478bd9Sstevel@tonic-gate 
32227c478bd9Sstevel@tonic-gate 	if (prop == NULL) {
32237c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
32247c478bd9Sstevel@tonic-gate 		return (-1);
32257c478bd9Sstevel@tonic-gate 	}
32267c478bd9Sstevel@tonic-gate 
32277c478bd9Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
32287c478bd9Sstevel@tonic-gate 		*prom_prop_data = NULL;
32297c478bd9Sstevel@tonic-gate 		return (0);
32307c478bd9Sstevel@tonic-gate 	}
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
32337c478bd9Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE, 1);
32347c478bd9Sstevel@tonic-gate 	*prom_prop_data = prop->data;
32357c478bd9Sstevel@tonic-gate 
32367c478bd9Sstevel@tonic-gate 	return (len);
32377c478bd9Sstevel@tonic-gate }
32387c478bd9Sstevel@tonic-gate 
32393ebafc43Sjveta /*
32403ebafc43Sjveta  * returns an allocated array through <prop_data> only when its count > 0
32413ebafc43Sjveta  * and the number of entries (count) as the function return value;
32423ebafc43Sjveta  * use di_slot_names_free() to free the array
32433ebafc43Sjveta  */
32443ebafc43Sjveta int
32453ebafc43Sjveta di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
32463ebafc43Sjveta {
32473ebafc43Sjveta 	int rawlen, count;
32483ebafc43Sjveta 	uchar_t *rawdata;
32493ebafc43Sjveta 	char *nm = di_prop_name(prop);
32503ebafc43Sjveta 
32513ebafc43Sjveta 	if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
32523ebafc43Sjveta 		goto ERROUT;
32533ebafc43Sjveta 
32543ebafc43Sjveta 	rawlen = di_prop_rawdata(prop, &rawdata);
32553ebafc43Sjveta 	if (rawlen <= 0 || rawdata == NULL)
32563ebafc43Sjveta 		goto ERROUT;
32573ebafc43Sjveta 
32583ebafc43Sjveta 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
32593ebafc43Sjveta 	if (count < 0 || *prop_data == NULL)
32603ebafc43Sjveta 		goto ERROUT;
32613ebafc43Sjveta 
32623ebafc43Sjveta 	return (count);
32633ebafc43Sjveta 	/*NOTREACHED*/
32643ebafc43Sjveta ERROUT:
32653ebafc43Sjveta 	errno = EFAULT;
32663ebafc43Sjveta 	*prop_data = NULL;
32673ebafc43Sjveta 	return (-1);
32683ebafc43Sjveta }
32693ebafc43Sjveta 
32703ebafc43Sjveta int
32713ebafc43Sjveta di_prop_lookup_slot_names(dev_t dev, di_node_t node,
32723ebafc43Sjveta     di_slot_name_t **prop_data)
32733ebafc43Sjveta {
32743ebafc43Sjveta 	di_prop_t prop;
32753ebafc43Sjveta 
32763ebafc43Sjveta 	/*
32773ebafc43Sjveta 	 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
32783ebafc43Sjveta 	 * and slot-names is properly flagged as such
32793ebafc43Sjveta 	 */
32803ebafc43Sjveta 	if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
32813ebafc43Sjveta 	    DI_PROP_NIL) {
32823ebafc43Sjveta 		*prop_data = NULL;
32833ebafc43Sjveta 		return (-1);
32843ebafc43Sjveta 	}
32853ebafc43Sjveta 
32863ebafc43Sjveta 	return (di_prop_slot_names(prop, (void *)prop_data));
32873ebafc43Sjveta }
32883ebafc43Sjveta 
32893ebafc43Sjveta /*
32903ebafc43Sjveta  * returns an allocated array through <prop_data> only when its count > 0
32913ebafc43Sjveta  * and the number of entries (count) as the function return value;
32923ebafc43Sjveta  * use di_slot_names_free() to free the array
32933ebafc43Sjveta  */
32943ebafc43Sjveta int
32953ebafc43Sjveta di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
32963ebafc43Sjveta {
32973ebafc43Sjveta 	int rawlen, count;
32983ebafc43Sjveta 	uchar_t *rawdata;
32993ebafc43Sjveta 
33003ebafc43Sjveta 	rawlen = di_prom_prop_data(prom_prop, &rawdata);
33013ebafc43Sjveta 	if (rawlen <= 0 || rawdata == NULL)
33023ebafc43Sjveta 		goto ERROUT;
33033ebafc43Sjveta 
33043ebafc43Sjveta 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
33053ebafc43Sjveta 	if (count < 0 || *prop_data == NULL)
33063ebafc43Sjveta 		goto ERROUT;
33073ebafc43Sjveta 
33083ebafc43Sjveta 	return (count);
33093ebafc43Sjveta 	/*NOTREACHED*/
33103ebafc43Sjveta ERROUT:
33113ebafc43Sjveta 	errno = EFAULT;
33123ebafc43Sjveta 	*prop_data = NULL;
33133ebafc43Sjveta 	return (-1);
33143ebafc43Sjveta }
33153ebafc43Sjveta 
33163ebafc43Sjveta int
33173ebafc43Sjveta di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
33183ebafc43Sjveta     di_slot_name_t **prop_data)
33193ebafc43Sjveta {
33203ebafc43Sjveta 	struct di_prom_prop *prom_prop;
33213ebafc43Sjveta 
33223ebafc43Sjveta 	prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
33233ebafc43Sjveta 	if (prom_prop == NULL) {
33243ebafc43Sjveta 		*prop_data = NULL;
33253ebafc43Sjveta 		return (-1);
33263ebafc43Sjveta 	}
33273ebafc43Sjveta 
33283ebafc43Sjveta 	return (di_prom_prop_slot_names(prom_prop, prop_data));
33293ebafc43Sjveta }
33303ebafc43Sjveta 
33317c478bd9Sstevel@tonic-gate di_lnode_t
33327c478bd9Sstevel@tonic-gate di_link_to_lnode(di_link_t link, uint_t endpoint)
33337c478bd9Sstevel@tonic-gate {
33347c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate 	if ((link == DI_LINK_NIL) ||
33377c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
33387c478bd9Sstevel@tonic-gate 		errno = EINVAL;
33397c478bd9Sstevel@tonic-gate 		return (DI_LNODE_NIL);
33407c478bd9Sstevel@tonic-gate 	}
33417c478bd9Sstevel@tonic-gate 
33427c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
33457c478bd9Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
33467c478bd9Sstevel@tonic-gate 	} else {
33477c478bd9Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
33487c478bd9Sstevel@tonic-gate 	}
33497c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
33507c478bd9Sstevel@tonic-gate }
33517c478bd9Sstevel@tonic-gate 
33527c478bd9Sstevel@tonic-gate char *
33537c478bd9Sstevel@tonic-gate di_lnode_name(di_lnode_t lnode)
33547c478bd9Sstevel@tonic-gate {
33557c478bd9Sstevel@tonic-gate 	return (di_driver_name(di_lnode_devinfo(lnode)));
33567c478bd9Sstevel@tonic-gate }
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate di_node_t
33597c478bd9Sstevel@tonic-gate di_lnode_devinfo(di_lnode_t lnode)
33607c478bd9Sstevel@tonic-gate {
33617c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
33647c478bd9Sstevel@tonic-gate 	return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
33657c478bd9Sstevel@tonic-gate }
33667c478bd9Sstevel@tonic-gate 
33677c478bd9Sstevel@tonic-gate int
33687c478bd9Sstevel@tonic-gate di_lnode_devt(di_lnode_t lnode, dev_t *devt)
33697c478bd9Sstevel@tonic-gate {
33707c478bd9Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
33717c478bd9Sstevel@tonic-gate 		errno = EINVAL;
33727c478bd9Sstevel@tonic-gate 		return (-1);
33737c478bd9Sstevel@tonic-gate 	}
33747c478bd9Sstevel@tonic-gate 	if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
33757c478bd9Sstevel@tonic-gate 	    (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
33767c478bd9Sstevel@tonic-gate 		return (-1);
33777c478bd9Sstevel@tonic-gate 
33787c478bd9Sstevel@tonic-gate 	*devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
33797c478bd9Sstevel@tonic-gate 	return (0);
33807c478bd9Sstevel@tonic-gate }
33817c478bd9Sstevel@tonic-gate 
33827c478bd9Sstevel@tonic-gate int
33837c478bd9Sstevel@tonic-gate di_link_spectype(di_link_t link)
33847c478bd9Sstevel@tonic-gate {
33857c478bd9Sstevel@tonic-gate 	return (DI_LINK(link)->spec_type);
33867c478bd9Sstevel@tonic-gate }
33877c478bd9Sstevel@tonic-gate 
33887c478bd9Sstevel@tonic-gate void
33897c478bd9Sstevel@tonic-gate di_minor_private_set(di_minor_t minor, void *data)
33907c478bd9Sstevel@tonic-gate {
33917c478bd9Sstevel@tonic-gate 	DI_MINOR(minor)->user_private_data = (uintptr_t)data;
33927c478bd9Sstevel@tonic-gate }
33937c478bd9Sstevel@tonic-gate 
33947c478bd9Sstevel@tonic-gate void *
33957c478bd9Sstevel@tonic-gate di_minor_private_get(di_minor_t minor)
33967c478bd9Sstevel@tonic-gate {
33978309866bSanish 	return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
33987c478bd9Sstevel@tonic-gate }
33997c478bd9Sstevel@tonic-gate 
34007c478bd9Sstevel@tonic-gate void
34017c478bd9Sstevel@tonic-gate di_node_private_set(di_node_t node, void *data)
34027c478bd9Sstevel@tonic-gate {
34037c478bd9Sstevel@tonic-gate 	DI_NODE(node)->user_private_data = (uintptr_t)data;
34047c478bd9Sstevel@tonic-gate }
34057c478bd9Sstevel@tonic-gate 
34067c478bd9Sstevel@tonic-gate void *
34077c478bd9Sstevel@tonic-gate di_node_private_get(di_node_t node)
34087c478bd9Sstevel@tonic-gate {
34098309866bSanish 	return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
34107c478bd9Sstevel@tonic-gate }
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate void
3413602ca9eaScth di_path_private_set(di_path_t path, void *data)
3414602ca9eaScth {
3415602ca9eaScth 	DI_PATH(path)->user_private_data = (uintptr_t)data;
3416602ca9eaScth }
3417602ca9eaScth 
3418602ca9eaScth void *
3419602ca9eaScth di_path_private_get(di_path_t path)
3420602ca9eaScth {
3421602ca9eaScth 	return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
3422602ca9eaScth }
3423602ca9eaScth 
3424602ca9eaScth void
34257c478bd9Sstevel@tonic-gate di_lnode_private_set(di_lnode_t lnode, void *data)
34267c478bd9Sstevel@tonic-gate {
34277c478bd9Sstevel@tonic-gate 	DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
34287c478bd9Sstevel@tonic-gate }
34297c478bd9Sstevel@tonic-gate 
34307c478bd9Sstevel@tonic-gate void *
34317c478bd9Sstevel@tonic-gate di_lnode_private_get(di_lnode_t lnode)
34327c478bd9Sstevel@tonic-gate {
34338309866bSanish 	return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
34347c478bd9Sstevel@tonic-gate }
34357c478bd9Sstevel@tonic-gate 
34367c478bd9Sstevel@tonic-gate void
34377c478bd9Sstevel@tonic-gate di_link_private_set(di_link_t link, void *data)
34387c478bd9Sstevel@tonic-gate {
34397c478bd9Sstevel@tonic-gate 	DI_LINK(link)->user_private_data = (uintptr_t)data;
34407c478bd9Sstevel@tonic-gate }
34417c478bd9Sstevel@tonic-gate 
34427c478bd9Sstevel@tonic-gate void *
34437c478bd9Sstevel@tonic-gate di_link_private_get(di_link_t link)
34447c478bd9Sstevel@tonic-gate {
34458309866bSanish 	return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
34467c478bd9Sstevel@tonic-gate }
34477c478bd9Sstevel@tonic-gate 
34487c478bd9Sstevel@tonic-gate di_lnode_t
34497c478bd9Sstevel@tonic-gate di_lnode_next(di_node_t node, di_lnode_t lnode)
34507c478bd9Sstevel@tonic-gate {
34517c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate 	/*
34547c478bd9Sstevel@tonic-gate 	 * paranoid error checking
34557c478bd9Sstevel@tonic-gate 	 */
34567c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
34577c478bd9Sstevel@tonic-gate 		errno = EINVAL;
34587c478bd9Sstevel@tonic-gate 		return (DI_LNODE_NIL);
34597c478bd9Sstevel@tonic-gate 	}
34607c478bd9Sstevel@tonic-gate 
34617c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate 	if (lnode == DI_NODE_NIL) {
34647c478bd9Sstevel@tonic-gate 		if (DI_NODE(node)->lnodes != NULL)
34657c478bd9Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
34667c478bd9Sstevel@tonic-gate 			    DI_NODE(node)->lnodes));
34677c478bd9Sstevel@tonic-gate 	} else {
34687c478bd9Sstevel@tonic-gate 		if (DI_LNODE(lnode)->node_next != NULL)
34697c478bd9Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
34707c478bd9Sstevel@tonic-gate 			    DI_LNODE(lnode)->node_next));
34717c478bd9Sstevel@tonic-gate 	}
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
34747c478bd9Sstevel@tonic-gate 		errno = ENXIO;
34757c478bd9Sstevel@tonic-gate 	else
34767c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
34777c478bd9Sstevel@tonic-gate 
34787c478bd9Sstevel@tonic-gate 	return (DI_LNODE_NIL);
34797c478bd9Sstevel@tonic-gate }
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate di_link_t
34827c478bd9Sstevel@tonic-gate di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
34837c478bd9Sstevel@tonic-gate {
34847c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
34857c478bd9Sstevel@tonic-gate 
34867c478bd9Sstevel@tonic-gate 	/*
34877c478bd9Sstevel@tonic-gate 	 * paranoid error checking
34887c478bd9Sstevel@tonic-gate 	 */
34897c478bd9Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) ||
34907c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
34917c478bd9Sstevel@tonic-gate 		errno = EINVAL;
34927c478bd9Sstevel@tonic-gate 		return (DI_LINK_NIL);
34937c478bd9Sstevel@tonic-gate 	}
34947c478bd9Sstevel@tonic-gate 
34957c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
34967c478bd9Sstevel@tonic-gate 
34977c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
34987c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
34997c478bd9Sstevel@tonic-gate 			if (DI_NODE(node)->src_links != NULL)
35007c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35017c478bd9Sstevel@tonic-gate 				    DI_NODE(node)->src_links));
35027c478bd9Sstevel@tonic-gate 		} else {
35037c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->src_node_next != NULL)
35047c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35057c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->src_node_next));
35067c478bd9Sstevel@tonic-gate 		}
35077c478bd9Sstevel@tonic-gate 	} else {
35087c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
35097c478bd9Sstevel@tonic-gate 			if (DI_NODE(node)->tgt_links != NULL)
35107c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35117c478bd9Sstevel@tonic-gate 				    DI_NODE(node)->tgt_links));
35127c478bd9Sstevel@tonic-gate 		} else {
35137c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_node_next != NULL)
35147c478bd9Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35157c478bd9Sstevel@tonic-gate 				    DI_LINK(link)->tgt_node_next));
35167c478bd9Sstevel@tonic-gate 		}
35177c478bd9Sstevel@tonic-gate 	}
35187c478bd9Sstevel@tonic-gate 
35197c478bd9Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
35207c478bd9Sstevel@tonic-gate 		errno = ENXIO;
35217c478bd9Sstevel@tonic-gate 	else
35227c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
35237c478bd9Sstevel@tonic-gate 
35247c478bd9Sstevel@tonic-gate 	return (DI_LINK_NIL);
35257c478bd9Sstevel@tonic-gate }
35267c478bd9Sstevel@tonic-gate 
35277c478bd9Sstevel@tonic-gate di_link_t
35287c478bd9Sstevel@tonic-gate di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
35297c478bd9Sstevel@tonic-gate {
35307c478bd9Sstevel@tonic-gate 	struct di_all *di_all;
35317c478bd9Sstevel@tonic-gate 
35327c478bd9Sstevel@tonic-gate 	/*
35337c478bd9Sstevel@tonic-gate 	 * paranoid error checking
35347c478bd9Sstevel@tonic-gate 	 */
35357c478bd9Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) ||
35367c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
35377c478bd9Sstevel@tonic-gate 		errno = EINVAL;
35387c478bd9Sstevel@tonic-gate 		return (DI_LINK_NIL);
35397c478bd9Sstevel@tonic-gate 	}
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
35427c478bd9Sstevel@tonic-gate 
35437c478bd9Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
35447c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
35457c478bd9Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_out == NULL)
35467c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
35477c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35487c478bd9Sstevel@tonic-gate 			    DI_LNODE(lnode)->link_out));
35497c478bd9Sstevel@tonic-gate 		} else {
35507c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->src_link_next == NULL)
35517c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
35527c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35537c478bd9Sstevel@tonic-gate 			    DI_LINK(link)->src_link_next));
35547c478bd9Sstevel@tonic-gate 		}
35557c478bd9Sstevel@tonic-gate 	} else {
35567c478bd9Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
35577c478bd9Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_in == NULL)
35587c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
35597c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35607c478bd9Sstevel@tonic-gate 			    DI_LNODE(lnode)->link_in));
35617c478bd9Sstevel@tonic-gate 		} else {
35627c478bd9Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_link_next == NULL)
35637c478bd9Sstevel@tonic-gate 				return (DI_LINK_NIL);
35647c478bd9Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35657c478bd9Sstevel@tonic-gate 			    DI_LINK(link)->tgt_link_next));
35667c478bd9Sstevel@tonic-gate 		}
35677c478bd9Sstevel@tonic-gate 	}
35687c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
35697c478bd9Sstevel@tonic-gate }
35707c478bd9Sstevel@tonic-gate 
35717c478bd9Sstevel@tonic-gate /*
35727c478bd9Sstevel@tonic-gate  * Internal library function:
35737c478bd9Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
35747c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
35757c478bd9Sstevel@tonic-gate  *
35767c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
35777c478bd9Sstevel@tonic-gate  *   first mode.
35787c478bd9Sstevel@tonic-gate  */
35797c478bd9Sstevel@tonic-gate static void
35807c478bd9Sstevel@tonic-gate walk_one_link(struct node_list **headp, uint_t ep,
35817c478bd9Sstevel@tonic-gate     void *arg, int (*callback)(di_link_t link, void *arg))
35827c478bd9Sstevel@tonic-gate {
35837c478bd9Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
35847c478bd9Sstevel@tonic-gate 	di_link_t	link = DI_LINK_NIL;
35857c478bd9Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
35867c478bd9Sstevel@tonic-gate 
35877c478bd9Sstevel@tonic-gate 	while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
35887c478bd9Sstevel@tonic-gate 		action = callback(link, arg);
35897c478bd9Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
35907c478bd9Sstevel@tonic-gate 			break;
35917c478bd9Sstevel@tonic-gate 		}
35927c478bd9Sstevel@tonic-gate 	}
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
35957c478bd9Sstevel@tonic-gate }
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate int
35987c478bd9Sstevel@tonic-gate di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
35997c478bd9Sstevel@tonic-gate     int (*link_callback)(di_link_t link, void *arg))
36007c478bd9Sstevel@tonic-gate {
36017c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
36027c478bd9Sstevel@tonic-gate 
36037c478bd9Sstevel@tonic-gate #ifdef DEBUG
3604602ca9eaScth 	char *devfspath = di_devfs_path(root);
36057c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking %s link data under %s\n",
3606602ca9eaScth 	    (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
3607602ca9eaScth 	di_devfs_path_free(devfspath);
36087c478bd9Sstevel@tonic-gate #endif
36097c478bd9Sstevel@tonic-gate 
36107c478bd9Sstevel@tonic-gate 	/*
36117c478bd9Sstevel@tonic-gate 	 * paranoid error checking
36127c478bd9Sstevel@tonic-gate 	 */
36137c478bd9Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
36147c478bd9Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
36157c478bd9Sstevel@tonic-gate 		errno = EINVAL;
36167c478bd9Sstevel@tonic-gate 		return (-1);
36177c478bd9Sstevel@tonic-gate 	}
36187c478bd9Sstevel@tonic-gate 
36197c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
36207c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
36217c478bd9Sstevel@tonic-gate 		return (-1);
36227c478bd9Sstevel@tonic-gate 	}
36237c478bd9Sstevel@tonic-gate 
36247c478bd9Sstevel@tonic-gate 	head->next = NULL;
36257c478bd9Sstevel@tonic-gate 	head->node = root;
36267c478bd9Sstevel@tonic-gate 
36277c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start link data walking from node %s\n",
36287c478bd9Sstevel@tonic-gate 	    di_node_name(root)));
36297c478bd9Sstevel@tonic-gate 
36307c478bd9Sstevel@tonic-gate 	while (head != NULL)
36317c478bd9Sstevel@tonic-gate 		walk_one_link(&head, endpoint, arg, link_callback);
36327c478bd9Sstevel@tonic-gate 
36337c478bd9Sstevel@tonic-gate 	return (0);
36347c478bd9Sstevel@tonic-gate }
36357c478bd9Sstevel@tonic-gate 
36367c478bd9Sstevel@tonic-gate /*
36377c478bd9Sstevel@tonic-gate  * Internal library function:
36387c478bd9Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
36397c478bd9Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
36407c478bd9Sstevel@tonic-gate  *
36417c478bd9Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
36427c478bd9Sstevel@tonic-gate  *   first mode.
36437c478bd9Sstevel@tonic-gate  */
36447c478bd9Sstevel@tonic-gate static void
36457c478bd9Sstevel@tonic-gate walk_one_lnode(struct node_list **headp, void *arg,
36467c478bd9Sstevel@tonic-gate     int (*callback)(di_lnode_t lnode, void *arg))
36477c478bd9Sstevel@tonic-gate {
36487c478bd9Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
36497c478bd9Sstevel@tonic-gate 	di_lnode_t	lnode = DI_LNODE_NIL;
36507c478bd9Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
36517c478bd9Sstevel@tonic-gate 
36527c478bd9Sstevel@tonic-gate 	while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
36537c478bd9Sstevel@tonic-gate 		action = callback(lnode, arg);
36547c478bd9Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
36557c478bd9Sstevel@tonic-gate 			break;
36567c478bd9Sstevel@tonic-gate 		}
36577c478bd9Sstevel@tonic-gate 	}
36587c478bd9Sstevel@tonic-gate 
36597c478bd9Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
36607c478bd9Sstevel@tonic-gate }
36617c478bd9Sstevel@tonic-gate 
36627c478bd9Sstevel@tonic-gate int
36637c478bd9Sstevel@tonic-gate di_walk_lnode(di_node_t root, uint_t flag, void *arg,
36647c478bd9Sstevel@tonic-gate     int (*lnode_callback)(di_lnode_t lnode, void *arg))
36657c478bd9Sstevel@tonic-gate {
36667c478bd9Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
36677c478bd9Sstevel@tonic-gate 
36687c478bd9Sstevel@tonic-gate #ifdef DEBUG
3669602ca9eaScth 	char *devfspath = di_devfs_path(root);
3670602ca9eaScth 	DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
3671602ca9eaScth 	di_devfs_path_free(devfspath);
36727c478bd9Sstevel@tonic-gate #endif
36737c478bd9Sstevel@tonic-gate 
36747c478bd9Sstevel@tonic-gate 	/*
36757c478bd9Sstevel@tonic-gate 	 * paranoid error checking
36767c478bd9Sstevel@tonic-gate 	 */
36777c478bd9Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
36787c478bd9Sstevel@tonic-gate 		errno = EINVAL;
36797c478bd9Sstevel@tonic-gate 		return (-1);
36807c478bd9Sstevel@tonic-gate 	}
36817c478bd9Sstevel@tonic-gate 
36827c478bd9Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
36837c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
36847c478bd9Sstevel@tonic-gate 		return (-1);
36857c478bd9Sstevel@tonic-gate 	}
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 	head->next = NULL;
36887c478bd9Sstevel@tonic-gate 	head->node = root;
36897c478bd9Sstevel@tonic-gate 
36907c478bd9Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
36917c478bd9Sstevel@tonic-gate 	    di_node_name(root)));
36927c478bd9Sstevel@tonic-gate 
36937c478bd9Sstevel@tonic-gate 	while (head != NULL)
36947c478bd9Sstevel@tonic-gate 		walk_one_lnode(&head, arg, lnode_callback);
36957c478bd9Sstevel@tonic-gate 
36967c478bd9Sstevel@tonic-gate 	return (0);
36977c478bd9Sstevel@tonic-gate }
36987c478bd9Sstevel@tonic-gate 
36997c478bd9Sstevel@tonic-gate di_node_t
3700602ca9eaScth di_lookup_node(di_node_t root, char *devfspath)
37017c478bd9Sstevel@tonic-gate {
37027c478bd9Sstevel@tonic-gate 	struct di_all *dap;
37037c478bd9Sstevel@tonic-gate 	di_node_t node;
3704602ca9eaScth 	char *copy, *slash, *pname, *paddr;
37057c478bd9Sstevel@tonic-gate 
37067c478bd9Sstevel@tonic-gate 	/*
37077c478bd9Sstevel@tonic-gate 	 * Path must be absolute and musn't have duplicate slashes
37087c478bd9Sstevel@tonic-gate 	 */
3709602ca9eaScth 	if (*devfspath != '/' || strstr(devfspath, "//")) {
3710602ca9eaScth 		DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
37117c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
37127c478bd9Sstevel@tonic-gate 	}
37137c478bd9Sstevel@tonic-gate 
37147c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
37157c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
37167c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
37177c478bd9Sstevel@tonic-gate 	}
37187c478bd9Sstevel@tonic-gate 
37197c478bd9Sstevel@tonic-gate 	dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
37207c478bd9Sstevel@tonic-gate 	if (strcmp(dap->root_path, "/") != 0) {
37217c478bd9Sstevel@tonic-gate 		DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
37227c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
37237c478bd9Sstevel@tonic-gate 	}
37247c478bd9Sstevel@tonic-gate 
3725602ca9eaScth 	if ((copy = strdup(devfspath)) == NULL) {
3726602ca9eaScth 		DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
37277c478bd9Sstevel@tonic-gate 		return (DI_NODE_NIL);
37287c478bd9Sstevel@tonic-gate 	}
37297c478bd9Sstevel@tonic-gate 
37307c478bd9Sstevel@tonic-gate 	for (slash = copy, node = root; slash; ) {
37317c478bd9Sstevel@tonic-gate 
37327c478bd9Sstevel@tonic-gate 		/*
3733602ca9eaScth 		 * Handle devfspath = "/" case as well as trailing '/'
37347c478bd9Sstevel@tonic-gate 		 */
37357c478bd9Sstevel@tonic-gate 		if (*(slash + 1) == '\0')
37367c478bd9Sstevel@tonic-gate 			break;
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 		/*
37397c478bd9Sstevel@tonic-gate 		 * More path-components exist. Deal with the next one
37407c478bd9Sstevel@tonic-gate 		 */
37417c478bd9Sstevel@tonic-gate 		pname = slash + 1;
37427c478bd9Sstevel@tonic-gate 		node = di_child_node(node);
37437c478bd9Sstevel@tonic-gate 
37447c478bd9Sstevel@tonic-gate 		if (slash = strchr(pname, '/'))
37457c478bd9Sstevel@tonic-gate 			*slash = '\0';
37467c478bd9Sstevel@tonic-gate 		if (paddr = strchr(pname, '@'))
37477c478bd9Sstevel@tonic-gate 			*paddr++ = '\0';
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate 		for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
37507c478bd9Sstevel@tonic-gate 			char *name, *baddr;
37517c478bd9Sstevel@tonic-gate 
37527c478bd9Sstevel@tonic-gate 			name = di_node_name(node);
37537c478bd9Sstevel@tonic-gate 			baddr = di_bus_addr(node);
37547c478bd9Sstevel@tonic-gate 
37557c478bd9Sstevel@tonic-gate 			if (strcmp(pname, name) != 0)
37567c478bd9Sstevel@tonic-gate 				continue;
37577c478bd9Sstevel@tonic-gate 
37587c478bd9Sstevel@tonic-gate 			/*
37597c478bd9Sstevel@tonic-gate 			 * Mappings between a "path-address" and bus-addr
37607c478bd9Sstevel@tonic-gate 			 *
37617c478bd9Sstevel@tonic-gate 			 *	paddr		baddr
37627c478bd9Sstevel@tonic-gate 			 *	---------------------
37637c478bd9Sstevel@tonic-gate 			 *	NULL		NULL
37647c478bd9Sstevel@tonic-gate 			 *	NULL		""
37657c478bd9Sstevel@tonic-gate 			 *	""		N/A	(invalid paddr)
37667c478bd9Sstevel@tonic-gate 			 */
37677c478bd9Sstevel@tonic-gate 			if (paddr && baddr && strcmp(paddr, baddr) == 0)
37687c478bd9Sstevel@tonic-gate 				break;
37697c478bd9Sstevel@tonic-gate 			if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
37707c478bd9Sstevel@tonic-gate 				break;
37717c478bd9Sstevel@tonic-gate 		}
37727c478bd9Sstevel@tonic-gate 
37737c478bd9Sstevel@tonic-gate 		/*
37747c478bd9Sstevel@tonic-gate 		 * No nodes in the sibling list or there was no match
37757c478bd9Sstevel@tonic-gate 		 */
37767c478bd9Sstevel@tonic-gate 		if (node == DI_NODE_NIL) {
37777c478bd9Sstevel@tonic-gate 			DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
3778602ca9eaScth 			free(copy);
37797c478bd9Sstevel@tonic-gate 			return (DI_NODE_NIL);
37807c478bd9Sstevel@tonic-gate 		}
37817c478bd9Sstevel@tonic-gate 	}
37827c478bd9Sstevel@tonic-gate 
37837c478bd9Sstevel@tonic-gate 	assert(node != DI_NODE_NIL);
3784602ca9eaScth 	free(copy);
37857c478bd9Sstevel@tonic-gate 	return (node);
37867c478bd9Sstevel@tonic-gate }
37877c478bd9Sstevel@tonic-gate 
3788602ca9eaScth di_path_t
3789602ca9eaScth di_lookup_path(di_node_t root, char *devfspath)
3790602ca9eaScth {
3791602ca9eaScth 	di_node_t	phci_node;
3792602ca9eaScth 	di_path_t	path = DI_PATH_NIL;
3793602ca9eaScth 	char		*copy, *lastslash;
3794602ca9eaScth 	char		*pname, *paddr;
3795602ca9eaScth 	char		*path_name, *path_addr;
3796602ca9eaScth 
3797602ca9eaScth 	if ((copy = strdup(devfspath)) == NULL) {
3798602ca9eaScth 		DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3799602ca9eaScth 		return (DI_NODE_NIL);
3800602ca9eaScth 	}
3801602ca9eaScth 
3802602ca9eaScth 	if ((lastslash = strrchr(copy, '/')) == NULL) {
3803602ca9eaScth 		DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3804602ca9eaScth 		goto out;
3805602ca9eaScth 	}
3806602ca9eaScth 
3807602ca9eaScth 	/* stop at pHCI and find the node for the phci */
3808602ca9eaScth 	*lastslash = '\0';
3809602ca9eaScth 	phci_node = di_lookup_node(root, copy);
3810602ca9eaScth 	if (phci_node == NULL) {
3811602ca9eaScth 		DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3812602ca9eaScth 		goto out;
3813602ca9eaScth 	}
3814602ca9eaScth 
3815602ca9eaScth 	/* set up pname and paddr for last component */
3816602ca9eaScth 	pname = lastslash + 1;
3817602ca9eaScth 	if ((paddr = strchr(pname, '@')) == NULL) {
3818602ca9eaScth 		DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
3819602ca9eaScth 		goto out;
3820602ca9eaScth 	}
3821602ca9eaScth 	*paddr++ = '\0';
3822602ca9eaScth 
3823602ca9eaScth 	/* walk paths below phci looking for match */
3824602ca9eaScth 	for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
3825602ca9eaScth 	    path != DI_PATH_NIL;
3826602ca9eaScth 	    path = di_path_phci_next_path(phci_node, path)) {
3827602ca9eaScth 
3828602ca9eaScth 		/* get name@addr of path */
3829602ca9eaScth 		path_name = di_path_node_name(path);
3830602ca9eaScth 		path_addr = di_path_bus_addr(path);
3831602ca9eaScth 		if ((path_name == NULL) || (path_addr == NULL))
3832602ca9eaScth 			continue;
3833602ca9eaScth 
3834602ca9eaScth 		/* break on match */
3835602ca9eaScth 		if ((strcmp(pname, path_name) == 0) &&
3836602ca9eaScth 		    (strcmp(paddr, path_addr) == 0))
3837602ca9eaScth 			break;
3838602ca9eaScth 	}
3839602ca9eaScth 
3840602ca9eaScth out:	free(copy);
3841602ca9eaScth 	return (path);
3842602ca9eaScth }
3843602ca9eaScth 
38447c478bd9Sstevel@tonic-gate static char *
38457c478bd9Sstevel@tonic-gate msglevel2str(di_debug_t msglevel)
38467c478bd9Sstevel@tonic-gate {
38477c478bd9Sstevel@tonic-gate 	switch (msglevel) {
38487c478bd9Sstevel@tonic-gate 		case DI_ERR:
38497c478bd9Sstevel@tonic-gate 			return ("ERROR");
38507c478bd9Sstevel@tonic-gate 		case DI_INFO:
38517c478bd9Sstevel@tonic-gate 			return ("Info");
38527c478bd9Sstevel@tonic-gate 		case DI_TRACE:
38537c478bd9Sstevel@tonic-gate 			return ("Trace");
38547c478bd9Sstevel@tonic-gate 		case DI_TRACE1:
38557c478bd9Sstevel@tonic-gate 			return ("Trace1");
38567c478bd9Sstevel@tonic-gate 		case DI_TRACE2:
38577c478bd9Sstevel@tonic-gate 			return ("Trace2");
38587c478bd9Sstevel@tonic-gate 		default:
38597c478bd9Sstevel@tonic-gate 			return ("UNKNOWN");
38607c478bd9Sstevel@tonic-gate 	}
38617c478bd9Sstevel@tonic-gate }
38627c478bd9Sstevel@tonic-gate 
38637c478bd9Sstevel@tonic-gate void
38647c478bd9Sstevel@tonic-gate dprint(di_debug_t msglevel, const char *fmt, ...)
38657c478bd9Sstevel@tonic-gate {
38667c478bd9Sstevel@tonic-gate 	va_list	ap;
38677c478bd9Sstevel@tonic-gate 	char	*estr;
38687c478bd9Sstevel@tonic-gate 
38697c478bd9Sstevel@tonic-gate 	if (di_debug <= DI_QUIET)
38707c478bd9Sstevel@tonic-gate 		return;
38717c478bd9Sstevel@tonic-gate 
38727c478bd9Sstevel@tonic-gate 	if (di_debug < msglevel)
38737c478bd9Sstevel@tonic-gate 		return;
38747c478bd9Sstevel@tonic-gate 
38757c478bd9Sstevel@tonic-gate 	estr = msglevel2str(msglevel);
38767c478bd9Sstevel@tonic-gate 
38777c478bd9Sstevel@tonic-gate 	assert(estr);
38787c478bd9Sstevel@tonic-gate 
38797c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
38807c478bd9Sstevel@tonic-gate 
38817c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
38827c478bd9Sstevel@tonic-gate 	    (ulong_t)getpid(), estr);
38837c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
38847c478bd9Sstevel@tonic-gate 
38857c478bd9Sstevel@tonic-gate 	va_end(ap);
38867c478bd9Sstevel@tonic-gate }
38877c478bd9Sstevel@tonic-gate 
38887c478bd9Sstevel@tonic-gate /* end of devinfo.c */
3889