xref: /onnv-gate/usr/src/lib/libdevinfo/devinfo.c (revision 12270:eada45a1a0be)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53814Sjveta  * Common Development and Distribution License (the "License").
63814Sjveta  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212116SVikram.Hegde@Sun.COM  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * Interfaces for getting device configuration data from kernel
270Sstevel@tonic-gate  * through the devinfo driver.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <stropts.h>
350Sstevel@tonic-gate #include <fcntl.h>
360Sstevel@tonic-gate #include <poll.h>
370Sstevel@tonic-gate #include <synch.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <sys/mkdev.h>
400Sstevel@tonic-gate #include <sys/obpdefs.h>
410Sstevel@tonic-gate #include <sys/stat.h>
420Sstevel@tonic-gate #include <sys/types.h>
430Sstevel@tonic-gate #include <sys/time.h>
440Sstevel@tonic-gate #include <sys/autoconf.h>
450Sstevel@tonic-gate #include <stdarg.h>
4610923SEvan.Yan@Sun.COM #include <sys/ddi_hp.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	NDEBUG 1
490Sstevel@tonic-gate #include <assert.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include "libdevinfo.h"
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * Debug message levels
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate typedef enum {
570Sstevel@tonic-gate 	DI_QUIET = 0,	/* No debug messages - the default */
580Sstevel@tonic-gate 	DI_ERR = 1,
590Sstevel@tonic-gate 	DI_INFO,
600Sstevel@tonic-gate 	DI_TRACE,
610Sstevel@tonic-gate 	DI_TRACE1,
620Sstevel@tonic-gate 	DI_TRACE2
630Sstevel@tonic-gate } di_debug_t;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate int di_debug = DI_QUIET;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #define	DPRINTF(args)	{ if (di_debug != DI_QUIET) dprint args; }
680Sstevel@tonic-gate 
690Sstevel@tonic-gate void dprint(di_debug_t msglevel, const char *fmt, ...);
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #pragma init(_libdevinfo_init)
730Sstevel@tonic-gate 
740Sstevel@tonic-gate void
_libdevinfo_init()750Sstevel@tonic-gate _libdevinfo_init()
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	char	*debug_str = getenv("_LIBDEVINFO_DEBUG");
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	if (debug_str) {
800Sstevel@tonic-gate 		errno = 0;
810Sstevel@tonic-gate 		di_debug = atoi(debug_str);
820Sstevel@tonic-gate 		if (errno || di_debug < DI_QUIET)
830Sstevel@tonic-gate 			di_debug = DI_QUIET;
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate }
860Sstevel@tonic-gate 
870Sstevel@tonic-gate di_node_t
di_init(const char * phys_path,uint_t flag)880Sstevel@tonic-gate di_init(const char *phys_path, uint_t flag)
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	return (di_init_impl(phys_path, flag, NULL));
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * We use blocking_open() to guarantee access to the devinfo device, if open()
950Sstevel@tonic-gate  * is failing with EAGAIN.
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate static int
blocking_open(const char * path,int oflag)980Sstevel@tonic-gate blocking_open(const char *path, int oflag)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	int fd;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
1030Sstevel@tonic-gate 		(void) poll(NULL, 0, 1 * MILLISEC);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	return (fd);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /* private interface */
1090Sstevel@tonic-gate di_node_t
di_init_driver(const char * drv_name,uint_t flag)1100Sstevel@tonic-gate di_init_driver(const char *drv_name, uint_t flag)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	int fd;
1130Sstevel@tonic-gate 	char driver[MAXPATHLEN];
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	/*
1160Sstevel@tonic-gate 	 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
1170Sstevel@tonic-gate 	 * which should be sufficient for any sensible programmer.
1180Sstevel@tonic-gate 	 */
1190Sstevel@tonic-gate 	if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
1200Sstevel@tonic-gate 		errno = EINVAL;
1210Sstevel@tonic-gate 		return (DI_NODE_NIL);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 	(void) strcpy(driver, drv_name);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	/*
1260Sstevel@tonic-gate 	 * open the devinfo driver
1270Sstevel@tonic-gate 	 */
1280Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
1290Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
1300Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
1310Sstevel@tonic-gate 		return (DI_NODE_NIL);
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	if (ioctl(fd, DINFOLODRV, driver) != 0) {
1350Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
1360Sstevel@tonic-gate 		(void) close(fd);
1370Sstevel@tonic-gate 		errno = ENXIO;
1380Sstevel@tonic-gate 		return (DI_NODE_NIL);
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 	(void) close(fd);
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	/*
1430Sstevel@tonic-gate 	 * Driver load succeeded, return a snapshot
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	return (di_init("/", flag));
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate di_node_t
di_init_impl(const char * phys_path,uint_t flag,struct di_priv_data * priv)1490Sstevel@tonic-gate di_init_impl(const char *phys_path, uint_t flag,
1500Sstevel@tonic-gate 	struct di_priv_data *priv)
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate 	caddr_t pa;
1530Sstevel@tonic-gate 	int fd, map_size;
1540Sstevel@tonic-gate 	struct di_all *dap;
1550Sstevel@tonic-gate 	struct dinfo_io dinfo_io;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
1580Sstevel@tonic-gate 	uint_t pagemask = ~pageoffset;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/*
1630Sstevel@tonic-gate 	 * Make sure there is no minor name in the path
1640Sstevel@tonic-gate 	 * and the path do not start with /devices....
1650Sstevel@tonic-gate 	 */
1660Sstevel@tonic-gate 	if (strchr(phys_path, ':') ||
1670Sstevel@tonic-gate 	    (strncmp(phys_path, "/devices", 8) == 0) ||
1680Sstevel@tonic-gate 	    (strlen(phys_path) > MAXPATHLEN)) {
1690Sstevel@tonic-gate 		errno = EINVAL;
1700Sstevel@tonic-gate 		return (DI_NODE_NIL);
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if (strlen(phys_path) == 0)
1740Sstevel@tonic-gate 		(void) sprintf(dinfo_io.root_path, "/");
1750Sstevel@tonic-gate 	else if (*phys_path != '/')
1760Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
1770Sstevel@tonic-gate 		    "/%s", phys_path);
1780Sstevel@tonic-gate 	else
1790Sstevel@tonic-gate 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
1800Sstevel@tonic-gate 		    "%s", phys_path);
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/*
1830Sstevel@tonic-gate 	 * If private data is requested, copy the format specification
1840Sstevel@tonic-gate 	 */
1850Sstevel@tonic-gate 	if (flag & DINFOPRIVDATA & 0xff) {
1860Sstevel@tonic-gate 		if (priv)
1870Sstevel@tonic-gate 			bcopy(priv, &dinfo_io.priv,
1880Sstevel@tonic-gate 			    sizeof (struct di_priv_data));
1890Sstevel@tonic-gate 		else {
1900Sstevel@tonic-gate 			errno = EINVAL;
1910Sstevel@tonic-gate 			return (DI_NODE_NIL);
1920Sstevel@tonic-gate 		}
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	/*
1960Sstevel@tonic-gate 	 * Attempt to open the devinfo driver.  Make a second attempt at the
1970Sstevel@tonic-gate 	 * read-only minor node if we don't have privileges to open the full
1980Sstevel@tonic-gate 	 * version _and_ if we're not requesting operations that the read-only
1990Sstevel@tonic-gate 	 * node can't perform.  (Setgid processes would fail an access() test,
2000Sstevel@tonic-gate 	 * of course.)
2010Sstevel@tonic-gate 	 */
2020Sstevel@tonic-gate 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
2030Sstevel@tonic-gate 	    O_RDONLY)) == -1) {
2040Sstevel@tonic-gate 		if ((flag & DINFOFORCE) == DINFOFORCE ||
2050Sstevel@tonic-gate 		    (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
2060Sstevel@tonic-gate 			/*
2070Sstevel@tonic-gate 			 * We wanted to perform a privileged operation, but the
2080Sstevel@tonic-gate 			 * privileged node isn't available.  Don't modify errno
2090Sstevel@tonic-gate 			 * on our way out (but display it if we're running with
2100Sstevel@tonic-gate 			 * di_debug set).
2110Sstevel@tonic-gate 			 */
2120Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
2130Sstevel@tonic-gate 			    errno));
2140Sstevel@tonic-gate 			return (DI_NODE_NIL);
2150Sstevel@tonic-gate 		}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 		if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
2180Sstevel@tonic-gate 		    O_RDONLY)) == -1) {
2190Sstevel@tonic-gate 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
2200Sstevel@tonic-gate 			    errno));
2210Sstevel@tonic-gate 			return (DI_NODE_NIL);
2220Sstevel@tonic-gate 		}
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/*
2260Sstevel@tonic-gate 	 * Verify that there is no major conflict, i.e., we are indeed opening
2270Sstevel@tonic-gate 	 * the devinfo driver.
2280Sstevel@tonic-gate 	 */
2290Sstevel@tonic-gate 	if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
2300Sstevel@tonic-gate 		DPRINTF((DI_ERR,
2310Sstevel@tonic-gate 		    "driver ID failed; check for major conflict\n"));
2320Sstevel@tonic-gate 		(void) close(fd);
2330Sstevel@tonic-gate 		return (DI_NODE_NIL);
2340Sstevel@tonic-gate 	}
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * create snapshot
2380Sstevel@tonic-gate 	 */
2390Sstevel@tonic-gate 	if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
2400Sstevel@tonic-gate 		DPRINTF((DI_ERR, "devinfo ioctl failed with "
2410Sstevel@tonic-gate 		    "error: %d\n", errno));
2420Sstevel@tonic-gate 		(void) close(fd);
2430Sstevel@tonic-gate 		return (DI_NODE_NIL);
2440Sstevel@tonic-gate 	} else if (map_size == 0) {
2450Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
2460Sstevel@tonic-gate 		errno = ENXIO;
2470Sstevel@tonic-gate 		(void) close(fd);
2480Sstevel@tonic-gate 		return (DI_NODE_NIL);
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	/*
2520Sstevel@tonic-gate 	 * copy snapshot to userland
2530Sstevel@tonic-gate 	 */
2540Sstevel@tonic-gate 	map_size = (map_size + pageoffset) & pagemask;
2550Sstevel@tonic-gate 	if ((pa = valloc(map_size)) == NULL) {
2560Sstevel@tonic-gate 		DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
2570Sstevel@tonic-gate 		(void) close(fd);
2580Sstevel@tonic-gate 		return (DI_NODE_NIL);
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
2620Sstevel@tonic-gate 		DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
2630Sstevel@tonic-gate 		(void) close(fd);
2640Sstevel@tonic-gate 		free(pa);
2650Sstevel@tonic-gate 		errno = EFAULT;
2660Sstevel@tonic-gate 		return (DI_NODE_NIL);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	(void) close(fd);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	dap = DI_ALL(pa);
2724444Svikram 	if (dap->version != DI_SNAPSHOT_VERSION) {
2734444Svikram 		DPRINTF((DI_ERR, "wrong snapshot version "
2744444Svikram 		    "(expected=%d, actual=%d)\n",
2754444Svikram 		    DI_SNAPSHOT_VERSION, dap->version));
2764444Svikram 		free(pa);
2774444Svikram 		errno = ESTALE;
2784444Svikram 		return (DI_NODE_NIL);
2794444Svikram 	}
2800Sstevel@tonic-gate 	if (dap->top_devinfo == 0) {	/* phys_path not found */
2810Sstevel@tonic-gate 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
2820Sstevel@tonic-gate 		free(pa);
2830Sstevel@tonic-gate 		errno = EINVAL;
2840Sstevel@tonic-gate 		return (DI_NODE_NIL);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	return (DI_NODE(pa + dap->top_devinfo));
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate void
di_fini(di_node_t root)2910Sstevel@tonic-gate di_fini(di_node_t root)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/*
2980Sstevel@tonic-gate 	 * paranoid checking
2990Sstevel@tonic-gate 	 */
3000Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
3010Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
3020Sstevel@tonic-gate 		return;
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	/*
3060Sstevel@tonic-gate 	 * The root contains its own offset--self.
3070Sstevel@tonic-gate 	 * Subtracting it from root address, we get the starting addr.
3080Sstevel@tonic-gate 	 * The map_size is stored at the beginning of snapshot.
3090Sstevel@tonic-gate 	 * Once we have starting address and size, we can free().
3100Sstevel@tonic-gate 	 */
3110Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	free(pa);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate di_node_t
di_parent_node(di_node_t node)3170Sstevel@tonic-gate di_parent_node(di_node_t node)
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3220Sstevel@tonic-gate 		errno = EINVAL;
3230Sstevel@tonic-gate 		return (DI_NODE_NIL);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (DI_NODE(node)->parent) {
3310Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->parent));
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/*
3350Sstevel@tonic-gate 	 * Deal with error condition:
3360Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
3370Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
3380Sstevel@tonic-gate 	 */
3390Sstevel@tonic-gate 	if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
3400Sstevel@tonic-gate 		errno = ENOTSUP;
3410Sstevel@tonic-gate 	else
3420Sstevel@tonic-gate 		errno = ENXIO;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	return (DI_NODE_NIL);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate di_node_t
di_sibling_node(di_node_t node)3480Sstevel@tonic-gate di_sibling_node(di_node_t node)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3530Sstevel@tonic-gate 		errno = EINVAL;
3540Sstevel@tonic-gate 		return (DI_NODE_NIL);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	if (DI_NODE(node)->sibling) {
3620Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->sibling));
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * Deal with error condition:
3670Sstevel@tonic-gate 	 *   Sibling doesn't exist, figure out if ioctl command
3680Sstevel@tonic-gate 	 *   has DINFOSUBTREE set. If it doesn't, set errno to
3690Sstevel@tonic-gate 	 *   ENOTSUP.
3700Sstevel@tonic-gate 	 */
3710Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
3720Sstevel@tonic-gate 		errno = ENOTSUP;
3730Sstevel@tonic-gate 	else
3740Sstevel@tonic-gate 		errno = ENXIO;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	return (DI_NODE_NIL);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate di_node_t
di_child_node(di_node_t node)3800Sstevel@tonic-gate di_child_node(di_node_t node)
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3870Sstevel@tonic-gate 		errno = EINVAL;
3880Sstevel@tonic-gate 		return (DI_NODE_NIL);
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if (DI_NODE(node)->child) {
3940Sstevel@tonic-gate 		return (DI_NODE(pa + DI_NODE(node)->child));
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/*
3980Sstevel@tonic-gate 	 * Deal with error condition:
3990Sstevel@tonic-gate 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
4000Sstevel@tonic-gate 	 *   If it isn't, set errno to ENOTSUP.
4010Sstevel@tonic-gate 	 */
4020Sstevel@tonic-gate 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
4030Sstevel@tonic-gate 		errno = ENOTSUP;
4040Sstevel@tonic-gate 	else
4050Sstevel@tonic-gate 		errno = ENXIO;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	return (DI_NODE_NIL);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate di_node_t
di_drv_first_node(const char * drv_name,di_node_t root)4110Sstevel@tonic-gate di_drv_first_node(const char *drv_name, di_node_t root)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
4140Sstevel@tonic-gate 	int		major, devcnt;
4150Sstevel@tonic-gate 	struct di_devnm	*devnm;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
4200Sstevel@tonic-gate 		errno = EINVAL;
4210Sstevel@tonic-gate 		return (DI_NODE_NIL);
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	/*
4250Sstevel@tonic-gate 	 * get major number of driver
4260Sstevel@tonic-gate 	 */
4270Sstevel@tonic-gate 	pa = (caddr_t)root - DI_NODE(root)->self;
4280Sstevel@tonic-gate 	devcnt = DI_ALL(pa)->devcnt;
4290Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	for (major = 0; major < devcnt; major++)
4320Sstevel@tonic-gate 		if (devnm[major].name && (strcmp(drv_name,
4330Sstevel@tonic-gate 		    (char *)(pa + devnm[major].name)) == 0))
4340Sstevel@tonic-gate 			break;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	if (major >= devcnt) {
4370Sstevel@tonic-gate 		errno = EINVAL;
4380Sstevel@tonic-gate 		return (DI_NODE_NIL);
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if (!(devnm[major].head)) {
4420Sstevel@tonic-gate 		errno = ENXIO;
4430Sstevel@tonic-gate 		return (DI_NODE_NIL);
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (DI_NODE(pa + devnm[major].head));
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate di_node_t
di_drv_next_node(di_node_t node)4500Sstevel@tonic-gate di_drv_next_node(di_node_t node)
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	caddr_t		pa;		/* starting address of map */
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
4550Sstevel@tonic-gate 		errno = EINVAL;
4560Sstevel@tonic-gate 		return (DI_NODE_NIL);
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "next node on per driver list:"
4600Sstevel@tonic-gate 	    " current=%s, driver=%s\n",
4610Sstevel@tonic-gate 	    di_node_name(node), di_driver_name(node)));
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	if (DI_NODE(node)->next == (di_off_t)-1) {
4640Sstevel@tonic-gate 		errno = ENOTSUP;
4650Sstevel@tonic-gate 		return (DI_NODE_NIL);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (DI_NODE(node)->next == NULL) {
4710Sstevel@tonic-gate 		errno = ENXIO;
4720Sstevel@tonic-gate 		return (DI_NODE_NIL);
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	return (DI_NODE(pa + DI_NODE(node)->next));
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate /*
4790Sstevel@tonic-gate  * Internal library interfaces:
4800Sstevel@tonic-gate  *   node_list etc. for node walking
4810Sstevel@tonic-gate  */
4820Sstevel@tonic-gate struct node_list {
4830Sstevel@tonic-gate 	struct node_list *next;
4840Sstevel@tonic-gate 	di_node_t node;
4850Sstevel@tonic-gate };
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate static void
free_node_list(struct node_list ** headp)4880Sstevel@tonic-gate free_node_list(struct node_list **headp)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	struct node_list *tmp;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	while (*headp) {
4930Sstevel@tonic-gate 		tmp = *headp;
4940Sstevel@tonic-gate 		*headp = (*headp)->next;
4950Sstevel@tonic-gate 		free(tmp);
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate static void
append_node_list(struct node_list ** headp,struct node_list * list)5000Sstevel@tonic-gate append_node_list(struct node_list **headp, struct node_list *list)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate 	struct node_list *tmp;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (*headp == NULL) {
5050Sstevel@tonic-gate 		*headp = list;
5060Sstevel@tonic-gate 		return;
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (list == NULL)	/* a minor optimization */
5100Sstevel@tonic-gate 		return;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	tmp = *headp;
5130Sstevel@tonic-gate 	while (tmp->next)
5140Sstevel@tonic-gate 		tmp = tmp->next;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	tmp->next = list;
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate static void
prepend_node_list(struct node_list ** headp,struct node_list * list)5200Sstevel@tonic-gate prepend_node_list(struct node_list **headp, struct node_list *list)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	struct node_list *tmp;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	if (list == NULL)
5250Sstevel@tonic-gate 		return;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	tmp = *headp;
5280Sstevel@tonic-gate 	*headp = list;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if (tmp == NULL)	/* a minor optimization */
5310Sstevel@tonic-gate 		return;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	while (list->next)
5340Sstevel@tonic-gate 		list = list->next;
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	list->next = tmp;
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate /*
5400Sstevel@tonic-gate  * returns 1 if node is a descendant of parent, 0 otherwise
5410Sstevel@tonic-gate  */
5420Sstevel@tonic-gate static int
is_descendant(di_node_t node,di_node_t parent)5430Sstevel@tonic-gate is_descendant(di_node_t node, di_node_t parent)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate 	/*
5460Sstevel@tonic-gate 	 * DI_NODE_NIL is parent of root, so it is
5470Sstevel@tonic-gate 	 * the parent of all nodes.
5480Sstevel@tonic-gate 	 */
5490Sstevel@tonic-gate 	if (parent == DI_NODE_NIL) {
5500Sstevel@tonic-gate 		return (1);
5510Sstevel@tonic-gate 	}
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	do {
5540Sstevel@tonic-gate 		node = di_parent_node(node);
5550Sstevel@tonic-gate 	} while ((node != DI_NODE_NIL) && (node != parent));
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	return (node != DI_NODE_NIL);
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate /*
5610Sstevel@tonic-gate  * Insert list before the first node which is NOT a descendent of parent.
5620Sstevel@tonic-gate  * This is needed to reproduce the exact walking order of link generators.
5630Sstevel@tonic-gate  */
5640Sstevel@tonic-gate static void
insert_node_list(struct node_list ** headp,struct node_list * list,di_node_t parent)5650Sstevel@tonic-gate insert_node_list(struct node_list **headp, struct node_list *list,
5660Sstevel@tonic-gate     di_node_t parent)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	struct node_list *tmp, *tmp1;
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	if (list == NULL)
5710Sstevel@tonic-gate 		return;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	tmp = *headp;
5740Sstevel@tonic-gate 	if (tmp == NULL) {	/* a minor optimization */
5750Sstevel@tonic-gate 		*headp = list;
5760Sstevel@tonic-gate 		return;
5770Sstevel@tonic-gate 	}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	if (!is_descendant(tmp->node, parent)) {
5800Sstevel@tonic-gate 		prepend_node_list(headp, list);
5810Sstevel@tonic-gate 		return;
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	/*
5850Sstevel@tonic-gate 	 * Find first node which is not a descendant
5860Sstevel@tonic-gate 	 */
5870Sstevel@tonic-gate 	while (tmp->next && is_descendant(tmp->next->node, parent)) {
5880Sstevel@tonic-gate 		tmp = tmp->next;
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	tmp1 = tmp->next;
5920Sstevel@tonic-gate 	tmp->next = list;
5930Sstevel@tonic-gate 	append_node_list(headp, tmp1);
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate /*
5970Sstevel@tonic-gate  *   Get a linked list of handles of all children
5980Sstevel@tonic-gate  */
5990Sstevel@tonic-gate static struct node_list *
get_children(di_node_t node)6000Sstevel@tonic-gate get_children(di_node_t node)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate 	di_node_t child;
6030Sstevel@tonic-gate 	struct node_list *result, *tmp;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	if ((child = di_child_node(node)) == DI_NODE_NIL) {
6080Sstevel@tonic-gate 		return (NULL);
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	if ((result = malloc(sizeof (struct node_list))) == NULL) {
6120Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
6130Sstevel@tonic-gate 		return (NULL);
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	result->node = child;
6170Sstevel@tonic-gate 	tmp = result;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
6200Sstevel@tonic-gate 		if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
6210Sstevel@tonic-gate 			DPRINTF((DI_ERR, "malloc of node_list failed\n"));
6220Sstevel@tonic-gate 			free_node_list(&result);
6230Sstevel@tonic-gate 			return (NULL);
6240Sstevel@tonic-gate 		}
6250Sstevel@tonic-gate 		tmp = tmp->next;
6260Sstevel@tonic-gate 		tmp->node = child;
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	tmp->next = NULL;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	return (result);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate /*
6350Sstevel@tonic-gate  * Internal library interface:
6360Sstevel@tonic-gate  *   Delete all siblings of the first node from the node_list, along with
6370Sstevel@tonic-gate  *   the first node itself.
6380Sstevel@tonic-gate  */
6390Sstevel@tonic-gate static void
prune_sib(struct node_list ** headp)6400Sstevel@tonic-gate prune_sib(struct node_list **headp)
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate 	di_node_t parent, curr_par, curr_gpar;
6430Sstevel@tonic-gate 	struct node_list *curr, *prev;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	/*
6460Sstevel@tonic-gate 	 * get handle to parent of first node
6470Sstevel@tonic-gate 	 */
6480Sstevel@tonic-gate 	if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
6490Sstevel@tonic-gate 		/*
6500Sstevel@tonic-gate 		 * This must be the root of the snapshot, so can't
6510Sstevel@tonic-gate 		 * have any siblings.
6520Sstevel@tonic-gate 		 *
6530Sstevel@tonic-gate 		 * XXX Put a check here just in case.
6540Sstevel@tonic-gate 		 */
6550Sstevel@tonic-gate 		if ((*headp)->next)
6560Sstevel@tonic-gate 			DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		free(*headp);
6590Sstevel@tonic-gate 		*headp = NULL;
6600Sstevel@tonic-gate 		return;
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	/*
6640Sstevel@tonic-gate 	 * To be complete, we should also delete the children
6650Sstevel@tonic-gate 	 * of siblings that have already been visited.
6660Sstevel@tonic-gate 	 * This happens for DI_WALK_SIBFIRST when the first node
6670Sstevel@tonic-gate 	 * is NOT the first in the linked list of siblings.
6680Sstevel@tonic-gate 	 *
6690Sstevel@tonic-gate 	 * Hence, we compare parent with BOTH the parent and grandparent
6700Sstevel@tonic-gate 	 * of nodes, and delete node is a match is found.
6710Sstevel@tonic-gate 	 */
6720Sstevel@tonic-gate 	prev = *headp;
6730Sstevel@tonic-gate 	curr = prev->next;
6740Sstevel@tonic-gate 	while (curr) {
6750Sstevel@tonic-gate 		if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) &&
6760Sstevel@tonic-gate 		    ((curr_par == parent) || ((curr_gpar =
6770Sstevel@tonic-gate 		    di_parent_node(curr_par)) != DI_NODE_NIL) &&
6780Sstevel@tonic-gate 		    (curr_gpar == parent))) {
6790Sstevel@tonic-gate 			/*
6800Sstevel@tonic-gate 			 * match parent/grandparent: delete curr
6810Sstevel@tonic-gate 			 */
6820Sstevel@tonic-gate 			prev->next = curr->next;
6830Sstevel@tonic-gate 			free(curr);
6840Sstevel@tonic-gate 			curr = prev->next;
6850Sstevel@tonic-gate 		} else
6860Sstevel@tonic-gate 			curr = curr->next;
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	/*
6900Sstevel@tonic-gate 	 * delete the first node
6910Sstevel@tonic-gate 	 */
6920Sstevel@tonic-gate 	curr = *headp;
6930Sstevel@tonic-gate 	*headp = curr->next;
6940Sstevel@tonic-gate 	free(curr);
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate /*
6980Sstevel@tonic-gate  * Internal library function:
6990Sstevel@tonic-gate  *	Update node list based on action (return code from callback)
7000Sstevel@tonic-gate  *	and flag specifying walking behavior.
7010Sstevel@tonic-gate  */
7020Sstevel@tonic-gate static void
update_node_list(int action,uint_t flag,struct node_list ** headp)7030Sstevel@tonic-gate update_node_list(int action, uint_t flag, struct node_list **headp)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	struct node_list *children, *tmp;
7060Sstevel@tonic-gate 	di_node_t parent = di_parent_node((*headp)->node);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	switch (action) {
7090Sstevel@tonic-gate 	case DI_WALK_TERMINATE:
7100Sstevel@tonic-gate 		/*
7110Sstevel@tonic-gate 		 * free the node list and be done
7120Sstevel@tonic-gate 		 */
7130Sstevel@tonic-gate 		children = NULL;
7140Sstevel@tonic-gate 		free_node_list(headp);
7150Sstevel@tonic-gate 		break;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	case DI_WALK_PRUNESIB:
7180Sstevel@tonic-gate 		/*
7190Sstevel@tonic-gate 		 * Get list of children and prune siblings
7200Sstevel@tonic-gate 		 */
7210Sstevel@tonic-gate 		children = get_children((*headp)->node);
7220Sstevel@tonic-gate 		prune_sib(headp);
7230Sstevel@tonic-gate 		break;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	case DI_WALK_PRUNECHILD:
7260Sstevel@tonic-gate 		/*
7270Sstevel@tonic-gate 		 * Set children to NULL and pop first node
7280Sstevel@tonic-gate 		 */
7290Sstevel@tonic-gate 		children = NULL;
7300Sstevel@tonic-gate 		tmp = *headp;
7310Sstevel@tonic-gate 		*headp = tmp->next;
7320Sstevel@tonic-gate 		free(tmp);
7330Sstevel@tonic-gate 		break;
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	case DI_WALK_CONTINUE:
7360Sstevel@tonic-gate 	default:
7370Sstevel@tonic-gate 		/*
7380Sstevel@tonic-gate 		 * Get list of children and pop first node
7390Sstevel@tonic-gate 		 */
7400Sstevel@tonic-gate 		children = get_children((*headp)->node);
7410Sstevel@tonic-gate 		tmp = *headp;
7420Sstevel@tonic-gate 		*headp = tmp->next;
7430Sstevel@tonic-gate 		free(tmp);
7440Sstevel@tonic-gate 		break;
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	/*
7480Sstevel@tonic-gate 	 * insert the list of children
7490Sstevel@tonic-gate 	 */
7500Sstevel@tonic-gate 	switch (flag) {
7510Sstevel@tonic-gate 	case DI_WALK_CLDFIRST:
7520Sstevel@tonic-gate 		prepend_node_list(headp, children);
7530Sstevel@tonic-gate 		break;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	case DI_WALK_SIBFIRST:
7560Sstevel@tonic-gate 		append_node_list(headp, children);
7570Sstevel@tonic-gate 		break;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	case DI_WALK_LINKGEN:
7600Sstevel@tonic-gate 	default:
7610Sstevel@tonic-gate 		insert_node_list(headp, children, parent);
7620Sstevel@tonic-gate 		break;
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate /*
7670Sstevel@tonic-gate  * Internal library function:
7680Sstevel@tonic-gate  *   Invoke callback on one node and update the list of nodes to be walked
7690Sstevel@tonic-gate  *   based on the flag and return code.
7700Sstevel@tonic-gate  */
7710Sstevel@tonic-gate static void
walk_one_node(struct node_list ** headp,uint_t flag,void * arg,int (* callback)(di_node_t,void *))7720Sstevel@tonic-gate walk_one_node(struct node_list **headp, uint_t flag, void *arg,
7730Sstevel@tonic-gate 	int (*callback)(di_node_t, void *))
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	update_node_list(callback((*headp)->node, arg),
7780Sstevel@tonic-gate 	    flag & DI_WALK_MASK, headp);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate int
di_walk_node(di_node_t root,uint_t flag,void * arg,int (* node_callback)(di_node_t,void *))7820Sstevel@tonic-gate di_walk_node(di_node_t root, uint_t flag, void *arg,
7830Sstevel@tonic-gate 	int (*node_callback)(di_node_t, void *))
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	if (root == NULL) {
7880Sstevel@tonic-gate 		errno = EINVAL;
7890Sstevel@tonic-gate 		return (-1);
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
7930Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
7940Sstevel@tonic-gate 		return (-1);
7950Sstevel@tonic-gate 	}
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	head->next = NULL;
7980Sstevel@tonic-gate 	head->node = root;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start node walking from node %s\n",
8010Sstevel@tonic-gate 	    di_node_name(root)));
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	while (head != NULL)
8040Sstevel@tonic-gate 		walk_one_node(&head, flag, arg, node_callback);
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	return (0);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate /*
8100Sstevel@tonic-gate  * Internal library function:
8110Sstevel@tonic-gate  *   Invoke callback for each minor on the minor list of first node
8120Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
8130Sstevel@tonic-gate  *
8140Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
8150Sstevel@tonic-gate  *   first mode.
8160Sstevel@tonic-gate  */
8170Sstevel@tonic-gate static void
walk_one_minor_list(struct node_list ** headp,const char * desired_type,uint_t flag,void * arg,int (* callback)(di_node_t,di_minor_t,void *))8180Sstevel@tonic-gate walk_one_minor_list(struct node_list **headp, const char *desired_type,
8190Sstevel@tonic-gate 	uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
8200Sstevel@tonic-gate {
8210Sstevel@tonic-gate 	int ddm_type;
8220Sstevel@tonic-gate 	int action = DI_WALK_CONTINUE;
8230Sstevel@tonic-gate 	char *node_type;
8240Sstevel@tonic-gate 	di_minor_t minor = DI_MINOR_NIL;
8250Sstevel@tonic-gate 	di_node_t node = (*headp)->node;
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
8280Sstevel@tonic-gate 		ddm_type = di_minor_type(minor);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 		if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
8310Sstevel@tonic-gate 			continue;
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		if ((ddm_type == DDM_INTERNAL_PATH) &&
8340Sstevel@tonic-gate 		    !(flag & DI_CHECK_INTERNAL_PATH))
8350Sstevel@tonic-gate 			continue;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 		node_type = di_minor_nodetype(minor);
8380Sstevel@tonic-gate 		if ((desired_type != NULL) && ((node_type == NULL) ||
8390Sstevel@tonic-gate 		    strncmp(desired_type, node_type, strlen(desired_type))
8400Sstevel@tonic-gate 		    != 0))
8410Sstevel@tonic-gate 			continue;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		if ((action = callback(node, minor, arg)) ==
8440Sstevel@tonic-gate 		    DI_WALK_TERMINATE) {
8450Sstevel@tonic-gate 			break;
8460Sstevel@tonic-gate 		}
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate int
di_walk_minor(di_node_t root,const char * minor_type,uint_t flag,void * arg,int (* minor_callback)(di_node_t,di_minor_t,void *))8530Sstevel@tonic-gate di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
8540Sstevel@tonic-gate 	int (*minor_callback)(di_node_t, di_minor_t, void *))
8550Sstevel@tonic-gate {
8566640Scth 	struct node_list	*head;	/* node_list for tree walk */
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate #ifdef DEBUG
8596640Scth 	char	*devfspath = di_devfs_path(root);
8606640Scth 	DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath));
8616640Scth 	di_devfs_path_free(devfspath);
8620Sstevel@tonic-gate #endif
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	if (root == NULL) {
8650Sstevel@tonic-gate 		errno = EINVAL;
8660Sstevel@tonic-gate 		return (-1);
8670Sstevel@tonic-gate 	}
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
8700Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
8710Sstevel@tonic-gate 		return (-1);
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	head->next = NULL;
8750Sstevel@tonic-gate 	head->node = root;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start minor walking from node %s\n",
8786640Scth 	    di_node_name(root)));
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	while (head != NULL)
8810Sstevel@tonic-gate 		walk_one_minor_list(&head, minor_type, flag, arg,
8820Sstevel@tonic-gate 		    minor_callback);
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	return (0);
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate /*
8880Sstevel@tonic-gate  * generic node parameters
8890Sstevel@tonic-gate  *   Calling these routines always succeeds.
8900Sstevel@tonic-gate  */
8910Sstevel@tonic-gate char *
di_node_name(di_node_t node)8920Sstevel@tonic-gate di_node_name(di_node_t node)
8930Sstevel@tonic-gate {
8940Sstevel@tonic-gate 	return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate /* returns NULL ptr or a valid ptr to non-NULL string */
8980Sstevel@tonic-gate char *
di_bus_addr(di_node_t node)8990Sstevel@tonic-gate di_bus_addr(di_node_t node)
9000Sstevel@tonic-gate {
9010Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	if (DI_NODE(node)->address == 0)
9040Sstevel@tonic-gate 		return (NULL);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->address));
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate char *
di_binding_name(di_node_t node)9100Sstevel@tonic-gate di_binding_name(di_node_t node)
9110Sstevel@tonic-gate {
9120Sstevel@tonic-gate 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	if (DI_NODE(node)->bind_name == 0)
9150Sstevel@tonic-gate 		return (NULL);
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	return ((char *)(pa + DI_NODE(node)->bind_name));
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate int
di_compatible_names(di_node_t node,char ** names)9210Sstevel@tonic-gate di_compatible_names(di_node_t node, char **names)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 	char *c;
9240Sstevel@tonic-gate 	int len, size, entries = 0;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	if (DI_NODE(node)->compat_names == 0) {
9270Sstevel@tonic-gate 		*names = NULL;
9280Sstevel@tonic-gate 		return (0);
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	*names = (caddr_t)node +
9326640Scth 	    DI_NODE(node)->compat_names - DI_NODE(node)->self;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	c = *names;
9350Sstevel@tonic-gate 	len = DI_NODE(node)->compat_length;
9360Sstevel@tonic-gate 	while (len > 0) {
9370Sstevel@tonic-gate 		entries++;
9380Sstevel@tonic-gate 		size = strlen(c) + 1;
9390Sstevel@tonic-gate 		len -= size;
9400Sstevel@tonic-gate 		c += size;
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	return (entries);
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate int
di_instance(di_node_t node)9470Sstevel@tonic-gate di_instance(di_node_t node)
9480Sstevel@tonic-gate {
9490Sstevel@tonic-gate 	return (DI_NODE(node)->instance);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate /*
9530Sstevel@tonic-gate  * XXX: emulate the return value of the old implementation
9540Sstevel@tonic-gate  * using info from devi_node_class and devi_node_attributes.
9550Sstevel@tonic-gate  */
9560Sstevel@tonic-gate int
di_nodeid(di_node_t node)9570Sstevel@tonic-gate di_nodeid(di_node_t node)
9580Sstevel@tonic-gate {
9590Sstevel@tonic-gate 	if (DI_NODE(node)->node_class == DDI_NC_PROM)
9600Sstevel@tonic-gate 		return (DI_PROM_NODEID);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	if (DI_NODE(node)->attributes & DDI_PERSISTENT)
9630Sstevel@tonic-gate 		return (DI_SID_NODEID);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	return (DI_PSEUDO_NODEID);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate uint_t
di_state(di_node_t node)9690Sstevel@tonic-gate di_state(di_node_t node)
9700Sstevel@tonic-gate {
9710Sstevel@tonic-gate 	uint_t result = 0;
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	if (di_node_state(node) < DS_ATTACHED)
9740Sstevel@tonic-gate 		result |= DI_DRIVER_DETACHED;
9750Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
9760Sstevel@tonic-gate 		result |= DI_DEVICE_OFFLINE;
9770Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
97810696SDavid.Hollister@Sun.COM 		result |= DI_DEVICE_DOWN;
9797275Sstephh 	if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
9807275Sstephh 		result |= DI_DEVICE_DEGRADED;
98110696SDavid.Hollister@Sun.COM 	if (DI_NODE(node)->state & DEVI_DEVICE_REMOVED)
98210696SDavid.Hollister@Sun.COM 		result |= DI_DEVICE_REMOVED;
9830Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
9840Sstevel@tonic-gate 		result |= DI_BUS_QUIESCED;
9850Sstevel@tonic-gate 	if (DI_NODE(node)->state & DEVI_BUS_DOWN)
9860Sstevel@tonic-gate 		result |= DI_BUS_DOWN;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	return (result);
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate ddi_node_state_t
di_node_state(di_node_t node)9920Sstevel@tonic-gate di_node_state(di_node_t node)
9930Sstevel@tonic-gate {
9940Sstevel@tonic-gate 	return (DI_NODE(node)->node_state);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate 
9974444Svikram uint_t
di_flags(di_node_t node)9984444Svikram di_flags(di_node_t node)
9994444Svikram {
10004444Svikram 	return (DI_NODE(node)->flags);
10014444Svikram }
10024444Svikram 
10034845Svikram uint_t
di_retired(di_node_t node)10044845Svikram di_retired(di_node_t node)
10054845Svikram {
10064845Svikram 	return (di_flags(node) & DEVI_RETIRED);
10074845Svikram }
10084845Svikram 
10090Sstevel@tonic-gate ddi_devid_t
di_devid(di_node_t node)10100Sstevel@tonic-gate di_devid(di_node_t node)
10110Sstevel@tonic-gate {
10120Sstevel@tonic-gate 	if (DI_NODE(node)->devid == 0)
10130Sstevel@tonic-gate 		return (NULL);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	return ((ddi_devid_t)((caddr_t)node +
10160Sstevel@tonic-gate 	    DI_NODE(node)->devid - DI_NODE(node)->self));
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate int
di_driver_major(di_node_t node)10200Sstevel@tonic-gate di_driver_major(di_node_t node)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate 	int major;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10250Sstevel@tonic-gate 	if (major < 0)
10260Sstevel@tonic-gate 		return (-1);
10270Sstevel@tonic-gate 	return (major);
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate char *
di_driver_name(di_node_t node)10310Sstevel@tonic-gate di_driver_name(di_node_t node)
10320Sstevel@tonic-gate {
10330Sstevel@tonic-gate 	int major;
10340Sstevel@tonic-gate 	caddr_t pa;
10350Sstevel@tonic-gate 	struct di_devnm *devnm;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10380Sstevel@tonic-gate 	if (major < 0)
10390Sstevel@tonic-gate 		return (NULL);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
10420Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	if (devnm[major].name)
10450Sstevel@tonic-gate 		return (pa + devnm[major].name);
10460Sstevel@tonic-gate 	else
10470Sstevel@tonic-gate 		return (NULL);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate uint_t
di_driver_ops(di_node_t node)10510Sstevel@tonic-gate di_driver_ops(di_node_t node)
10520Sstevel@tonic-gate {
10530Sstevel@tonic-gate 	int major;
10540Sstevel@tonic-gate 	caddr_t pa;
10550Sstevel@tonic-gate 	struct di_devnm *devnm;
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	major = DI_NODE(node)->drv_major;
10580Sstevel@tonic-gate 	if (major < 0)
10590Sstevel@tonic-gate 		return (0);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
10620Sstevel@tonic-gate 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	return (devnm[major].ops);
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate /*
10680Sstevel@tonic-gate  * returns the length of the path, caller must free memory
10690Sstevel@tonic-gate  */
10700Sstevel@tonic-gate char *
di_devfs_path(di_node_t node)10710Sstevel@tonic-gate di_devfs_path(di_node_t node)
10720Sstevel@tonic-gate {
10730Sstevel@tonic-gate 	caddr_t pa;
10740Sstevel@tonic-gate 	di_node_t parent;
10750Sstevel@tonic-gate 	int depth = 0, len = 0;
10760Sstevel@tonic-gate 	char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH];
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
10790Sstevel@tonic-gate 		errno = EINVAL;
10800Sstevel@tonic-gate 		return (NULL);
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	/*
10840Sstevel@tonic-gate 	 * trace back to root, note the node_name & address
10850Sstevel@tonic-gate 	 */
10860Sstevel@tonic-gate 	while ((parent = di_parent_node(node)) != DI_NODE_NIL) {
10870Sstevel@tonic-gate 		name[depth] = di_node_name(node);
10880Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;		/* 1 for '/' */
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 		if ((addr[depth] = di_bus_addr(node)) != NULL)
10910Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;	/* 1 for '@' */
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 		node = parent;
10940Sstevel@tonic-gate 		depth++;
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	/*
10980Sstevel@tonic-gate 	 * get the path to the root of snapshot
10990Sstevel@tonic-gate 	 */
11000Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
11010Sstevel@tonic-gate 	name[depth] = DI_ALL(pa)->root_path;
11020Sstevel@tonic-gate 	len += strlen(name[depth]) + 1;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	/*
11050Sstevel@tonic-gate 	 * allocate buffer and assemble path
11060Sstevel@tonic-gate 	 */
11070Sstevel@tonic-gate 	if ((buf = malloc(len)) == NULL) {
11080Sstevel@tonic-gate 		return (NULL);
11090Sstevel@tonic-gate 	}
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	(void) strcpy(buf, name[depth]);
11120Sstevel@tonic-gate 	len = strlen(buf);
11130Sstevel@tonic-gate 	if (buf[len - 1] == '/')
11140Sstevel@tonic-gate 		len--;	/* delete trailing '/' */
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	while (depth) {
11170Sstevel@tonic-gate 		depth--;
11180Sstevel@tonic-gate 		buf[len] = '/';
11190Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, name[depth]);
11200Sstevel@tonic-gate 		len += strlen(name[depth]) + 1;
11210Sstevel@tonic-gate 		if (addr[depth] && addr[depth][0] != '\0') {
11220Sstevel@tonic-gate 			buf[len] = '@';
11230Sstevel@tonic-gate 			(void) strcpy(buf + len + 1, addr[depth]);
11240Sstevel@tonic-gate 			len += strlen(addr[depth]) + 1;
11250Sstevel@tonic-gate 		}
11260Sstevel@tonic-gate 	}
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	return (buf);
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate char *
di_devfs_minor_path(di_minor_t minor)11320Sstevel@tonic-gate di_devfs_minor_path(di_minor_t minor)
11330Sstevel@tonic-gate {
11340Sstevel@tonic-gate 	di_node_t	node;
11356640Scth 	char		*full_path, *name, *devfspath;
11360Sstevel@tonic-gate 	int		full_path_len;
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
11390Sstevel@tonic-gate 		errno = EINVAL;
11400Sstevel@tonic-gate 		return (NULL);
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	name = di_minor_name(minor);
11440Sstevel@tonic-gate 	node = di_minor_devinfo(minor);
11456640Scth 	devfspath = di_devfs_path(node);
11466640Scth 	if (devfspath == NULL)
11470Sstevel@tonic-gate 		return (NULL);
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	/* make the full path to the device minor node */
11506640Scth 	full_path_len = strlen(devfspath) + strlen(name) + 2;
11510Sstevel@tonic-gate 	full_path = (char *)calloc(1, full_path_len);
11520Sstevel@tonic-gate 	if (full_path != NULL)
11536640Scth 		(void) snprintf(full_path, full_path_len, "%s:%s",
11546640Scth 		    devfspath, name);
11556640Scth 
11566640Scth 	di_devfs_path_free(devfspath);
11570Sstevel@tonic-gate 	return (full_path);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate 
11606640Scth /*
11616640Scth  * Produce a string representation of path to di_path_t (pathinfo node). This
11626640Scth  * string is identical to di_devfs_path had the device been enumerated under
11636640Scth  * the pHCI: it has a base path to pHCI, then uses node_name of client, and
11646640Scth  * device unit-address of pathinfo node.
11656640Scth  */
11666640Scth char *
di_path_devfs_path(di_path_t path)11676640Scth di_path_devfs_path(di_path_t path)
11686640Scth {
11696640Scth 	di_node_t	phci_node;
11706640Scth 	char		*phci_path, *path_name, *path_addr;
11716640Scth 	char		*full_path;
11726640Scth 	int		full_path_len;
11736640Scth 
11746640Scth 	if (path == DI_PATH_NIL) {
11756640Scth 		errno = EINVAL;
11766640Scth 		return (NULL);
11776640Scth 	}
11786640Scth 
11796640Scth 	/* get name@addr for path */
11806640Scth 	path_name = di_path_node_name(path);
11816640Scth 	path_addr = di_path_bus_addr(path);
11826640Scth 	if ((path_name == NULL) || (path_addr == NULL))
11836640Scth 		return (NULL);
11846640Scth 
11856640Scth 	/* base path to pHCI devinfo node */
11866640Scth 	phci_node = di_path_phci_node(path);
11876640Scth 	if (phci_node == NULL)
11886640Scth 		return (NULL);
11896640Scth 	phci_path = di_devfs_path(phci_node);
11906640Scth 	if (phci_path == NULL)
11916640Scth 		return (NULL);
11926640Scth 
11936640Scth 	/* make the full string representation of path */
11946640Scth 	full_path_len = strlen(phci_path) + 1 + strlen(path_name) +
11956640Scth 	    1 + strlen(path_addr) + 1;
11966640Scth 	full_path = (char *)calloc(1, full_path_len);
11976640Scth 
11986640Scth 	if (full_path != NULL)
11996640Scth 		(void) snprintf(full_path, full_path_len, "%s/%s@%s",
12006640Scth 		    phci_path, path_name, path_addr);
12016640Scth 	di_devfs_path_free(phci_path);
12026640Scth 	return (full_path);
12036640Scth }
12046640Scth 
12056640Scth char *
di_path_client_devfs_path(di_path_t path)12066640Scth di_path_client_devfs_path(di_path_t path)
12076640Scth {
12086640Scth 	return (di_devfs_path(di_path_client_node(path)));
12096640Scth }
12106640Scth 
12110Sstevel@tonic-gate void
di_devfs_path_free(char * buf)12120Sstevel@tonic-gate di_devfs_path_free(char *buf)
12130Sstevel@tonic-gate {
12140Sstevel@tonic-gate 	if (buf == NULL) {
12150Sstevel@tonic-gate 		DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
12160Sstevel@tonic-gate 		return;
12170Sstevel@tonic-gate 	}
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	free(buf);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate 
12226640Scth /*
12236640Scth  * Return 1 if name is a IEEE-1275 generic name. If new generic
12246640Scth  * names are defined, they should be added to this table
12256640Scth  */
12266640Scth static int
is_generic(const char * name,int len)12276640Scth is_generic(const char *name, int len)
12286640Scth {
12296640Scth 	const char	**gp;
12306640Scth 
12316640Scth 	/* from IEEE-1275 recommended practices section 3 */
12326640Scth 	static const char *generic_names[] = {
12336640Scth 	    "atm",
12346640Scth 	    "disk",
12356640Scth 	    "display",
12366640Scth 	    "dma-controller",
12376640Scth 	    "ethernet",
12386640Scth 	    "fcs",
12396640Scth 	    "fdc",
12406640Scth 	    "fddi",
12416640Scth 	    "fibre-channel",
12426640Scth 	    "ide",
12436640Scth 	    "interrupt-controller",
12446640Scth 	    "isa",
12456640Scth 	    "keyboard",
12466640Scth 	    "memory",
12476640Scth 	    "mouse",
12486640Scth 	    "nvram",
12496640Scth 	    "pc-card",
12506640Scth 	    "pci",
12516640Scth 	    "printer",
12526640Scth 	    "rtc",
12536640Scth 	    "sbus",
12546640Scth 	    "scanner",
12556640Scth 	    "scsi",
12566640Scth 	    "serial",
12576640Scth 	    "sound",
12586640Scth 	    "ssa",
12596640Scth 	    "tape",
12606640Scth 	    "timer",
12616640Scth 	    "token-ring",
12626640Scth 	    "vme",
12636640Scth 	    0
12646640Scth 	};
12656640Scth 
12666640Scth 	for (gp = generic_names; *gp; gp++) {
12676640Scth 		if ((strncmp(*gp, name, len) == 0) &&
12686640Scth 		    (strlen(*gp) == len))
12696640Scth 			return (1);
12706640Scth 	}
12716640Scth 	return (0);
12726640Scth }
12736640Scth 
12746640Scth /*
12756640Scth  * Determine if two paths below /devices refer to the same device, ignoring
12766640Scth  * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*".
12776640Scth  * Return 1 if the paths match.
12786640Scth  */
12796640Scth int
di_devfs_path_match(const char * dp1,const char * dp2)12806640Scth di_devfs_path_match(const char *dp1, const char *dp2)
12816640Scth {
12826640Scth 	const char	*p1, *p2;
12836640Scth 	const char	*ec1, *ec2;
12846640Scth 	const char	*at1, *at2;
12856640Scth 	char		nc;
12866640Scth 	int		g1, g2;
12876640Scth 
12886640Scth 	/* progress through both strings */
12896640Scth 	for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) {
12906640Scth 		/* require match until the start of a component */
12916640Scth 		if (*p1 != '/')
12926640Scth 			continue;
12936640Scth 
12946640Scth 		/* advance p1 and p2 to start of 'name' in component */
12956640Scth 		nc = *(p1 + 1);
12966640Scth 		if ((nc == '\0') || (nc == '/'))
12976640Scth 			continue;		/* skip trash */
12986640Scth 		p1++;
12996640Scth 		p2++;
13006640Scth 
13016640Scth 		/*
13026640Scth 		 * Both p1 and p2 point to beginning of 'name' in component.
13036640Scth 		 * Determine where current component ends: next '/' or '\0'.
13046640Scth 		 */
13056640Scth 		ec1 = strchr(p1, '/');
13066640Scth 		if (ec1 == NULL)
13076640Scth 			ec1 = p1 + strlen(p1);
13086640Scth 		ec2 = strchr(p2, '/');
13096640Scth 		if (ec2 == NULL)
13106640Scth 			ec2 = p2 + strlen(p2);
13116640Scth 
13126640Scth 		/* Determine where name ends based on whether '@' exists */
13136640Scth 		at1 = strchr(p1, '@');
13146640Scth 		at2 = strchr(p2, '@');
13156640Scth 		if (at1 && (at1 < ec1))
13166640Scth 			ec1 = at1;
13176640Scth 		if (at2 && (at2 < ec2))
13186640Scth 			ec2 = at2;
13196640Scth 
13206640Scth 		/*
13216640Scth 		 * At this point p[12] point to beginning of name and
13226640Scth 		 * ec[12] point to character past the end of name. Determine
13236640Scth 		 * if the names are generic.
13246640Scth 		 */
13256640Scth 		g1 = is_generic(p1, ec1 - p1);
13266640Scth 		g2 = is_generic(p2, ec2 - p2);
13276640Scth 
13286640Scth 		if (g1 != g2) {
13296640Scth 			/*
13306640Scth 			 * one generic and one non-generic
13316640Scth 			 * skip past the names in the match.
13326640Scth 			 */
13336640Scth 			p1 = ec1;
13346640Scth 			p2 = ec2;
13356640Scth 		} else {
13366640Scth 			if (*p1 != *p2)
13376640Scth 				break;
13386640Scth 		}
13396640Scth 	}
13406640Scth 
13416640Scth 	return ((*p1 == *p2) ? 1 : 0);
13426640Scth }
13436640Scth 
13440Sstevel@tonic-gate /* minor data access */
13450Sstevel@tonic-gate di_minor_t
di_minor_next(di_node_t node,di_minor_t minor)13460Sstevel@tonic-gate di_minor_next(di_node_t node, di_minor_t minor)
13470Sstevel@tonic-gate {
13480Sstevel@tonic-gate 	caddr_t pa;
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	/*
13510Sstevel@tonic-gate 	 * paranoid error checking
13520Sstevel@tonic-gate 	 */
13530Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
13540Sstevel@tonic-gate 		errno = EINVAL;
13550Sstevel@tonic-gate 		return (DI_MINOR_NIL);
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	/*
13590Sstevel@tonic-gate 	 * minor is not NIL
13600Sstevel@tonic-gate 	 */
13610Sstevel@tonic-gate 	if (minor != DI_MINOR_NIL) {
13620Sstevel@tonic-gate 		if (DI_MINOR(minor)->next != 0)
13630Sstevel@tonic-gate 			return ((di_minor_t)((void *)((caddr_t)minor -
13640Sstevel@tonic-gate 			    DI_MINOR(minor)->self + DI_MINOR(minor)->next)));
13650Sstevel@tonic-gate 		else {
13660Sstevel@tonic-gate 			errno = ENXIO;
13670Sstevel@tonic-gate 			return (DI_MINOR_NIL);
13680Sstevel@tonic-gate 		}
13690Sstevel@tonic-gate 	}
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	/*
13720Sstevel@tonic-gate 	 * minor is NIL-->caller asks for first minor node
13730Sstevel@tonic-gate 	 */
13740Sstevel@tonic-gate 	if (DI_NODE(node)->minor_data != 0) {
13750Sstevel@tonic-gate 		return (DI_MINOR((caddr_t)node - DI_NODE(node)->self +
13760Sstevel@tonic-gate 		    DI_NODE(node)->minor_data));
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/*
13800Sstevel@tonic-gate 	 * no minor data-->check if snapshot includes minor data
13810Sstevel@tonic-gate 	 *	in order to set the correct errno
13820Sstevel@tonic-gate 	 */
13830Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
13840Sstevel@tonic-gate 	if (DINFOMINOR & DI_ALL(pa)->command)
13850Sstevel@tonic-gate 		errno = ENXIO;
13860Sstevel@tonic-gate 	else
13870Sstevel@tonic-gate 		errno = ENOTSUP;
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	return (DI_MINOR_NIL);
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate /* private interface for dealing with alias minor link generation */
13930Sstevel@tonic-gate di_node_t
di_minor_devinfo(di_minor_t minor)13940Sstevel@tonic-gate di_minor_devinfo(di_minor_t minor)
13950Sstevel@tonic-gate {
13960Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
13970Sstevel@tonic-gate 		errno = EINVAL;
13980Sstevel@tonic-gate 		return (DI_NODE_NIL);
13990Sstevel@tonic-gate 	}
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
14020Sstevel@tonic-gate 	    DI_MINOR(minor)->node));
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate ddi_minor_type
di_minor_type(di_minor_t minor)14060Sstevel@tonic-gate di_minor_type(di_minor_t minor)
14070Sstevel@tonic-gate {
14080Sstevel@tonic-gate 	return (DI_MINOR(minor)->type);
14090Sstevel@tonic-gate }
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate char *
di_minor_name(di_minor_t minor)14120Sstevel@tonic-gate di_minor_name(di_minor_t minor)
14130Sstevel@tonic-gate {
14140Sstevel@tonic-gate 	if (DI_MINOR(minor)->name == 0)
14150Sstevel@tonic-gate 		return (NULL);
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate dev_t
di_minor_devt(di_minor_t minor)14210Sstevel@tonic-gate di_minor_devt(di_minor_t minor)
14220Sstevel@tonic-gate {
14230Sstevel@tonic-gate 	return (makedev(DI_MINOR(minor)->dev_major,
14246640Scth 	    DI_MINOR(minor)->dev_minor));
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate int
di_minor_spectype(di_minor_t minor)14280Sstevel@tonic-gate di_minor_spectype(di_minor_t minor)
14290Sstevel@tonic-gate {
14300Sstevel@tonic-gate 	return (DI_MINOR(minor)->spec_type);
14310Sstevel@tonic-gate }
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate char *
di_minor_nodetype(di_minor_t minor)14340Sstevel@tonic-gate di_minor_nodetype(di_minor_t minor)
14350Sstevel@tonic-gate {
14360Sstevel@tonic-gate 	if (DI_MINOR(minor)->node_type == 0)
14370Sstevel@tonic-gate 		return (NULL);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	return ((caddr_t)minor -
14406640Scth 	    DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate /*
14440Sstevel@tonic-gate  * Single public interface for accessing software properties
14450Sstevel@tonic-gate  */
14460Sstevel@tonic-gate di_prop_t
di_prop_next(di_node_t node,di_prop_t prop)14470Sstevel@tonic-gate di_prop_next(di_node_t node, di_prop_t prop)
14480Sstevel@tonic-gate {
14490Sstevel@tonic-gate 	int list = DI_PROP_DRV_LIST;
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	/*
14520Sstevel@tonic-gate 	 * paranoid check
14530Sstevel@tonic-gate 	 */
14540Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
14550Sstevel@tonic-gate 		errno = EINVAL;
14560Sstevel@tonic-gate 		return (DI_PROP_NIL);
14570Sstevel@tonic-gate 	}
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	/*
14600Sstevel@tonic-gate 	 * Find which prop list we are at
14610Sstevel@tonic-gate 	 */
14620Sstevel@tonic-gate 	if (prop != DI_PROP_NIL)
14630Sstevel@tonic-gate 		list = DI_PROP(prop)->prop_list;
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	do {
14660Sstevel@tonic-gate 		switch (list++) {
14670Sstevel@tonic-gate 		case DI_PROP_DRV_LIST:
14680Sstevel@tonic-gate 			prop = di_prop_drv_next(node, prop);
14690Sstevel@tonic-gate 			break;
14700Sstevel@tonic-gate 		case DI_PROP_SYS_LIST:
14710Sstevel@tonic-gate 			prop = di_prop_sys_next(node, prop);
14720Sstevel@tonic-gate 			break;
14730Sstevel@tonic-gate 		case DI_PROP_GLB_LIST:
14740Sstevel@tonic-gate 			prop = di_prop_global_next(node, prop);
14750Sstevel@tonic-gate 			break;
14760Sstevel@tonic-gate 		case DI_PROP_HW_LIST:
14770Sstevel@tonic-gate 			prop = di_prop_hw_next(node, prop);
14780Sstevel@tonic-gate 			break;
14790Sstevel@tonic-gate 		default:	/* shouldn't happen */
14800Sstevel@tonic-gate 			errno = EFAULT;
14810Sstevel@tonic-gate 			return (DI_PROP_NIL);
14820Sstevel@tonic-gate 		}
14830Sstevel@tonic-gate 	} while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	return (prop);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate dev_t
di_prop_devt(di_prop_t prop)14890Sstevel@tonic-gate di_prop_devt(di_prop_t prop)
14900Sstevel@tonic-gate {
14910Sstevel@tonic-gate 	return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate char *
di_prop_name(di_prop_t prop)14950Sstevel@tonic-gate di_prop_name(di_prop_t prop)
14960Sstevel@tonic-gate {
14970Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_name == 0)
14980Sstevel@tonic-gate 		return (NULL);
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate int
di_prop_type(di_prop_t prop)15040Sstevel@tonic-gate di_prop_type(di_prop_t prop)
15050Sstevel@tonic-gate {
15060Sstevel@tonic-gate 	uint_t flags = DI_PROP(prop)->prop_flags;
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 	if (flags & DDI_PROP_UNDEF_IT)
15090Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNDEF_IT);
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15120Sstevel@tonic-gate 		return (DI_PROP_TYPE_BOOLEAN);
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
15150Sstevel@tonic-gate 		return (DI_PROP_TYPE_UNKNOWN);
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT)
15180Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT);
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_INT64)
15210Sstevel@tonic-gate 		return (DI_PROP_TYPE_INT64);
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_STRING)
15240Sstevel@tonic-gate 		return (DI_PROP_TYPE_STRING);
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	if (flags & DDI_PROP_TYPE_BYTE)
15270Sstevel@tonic-gate 		return (DI_PROP_TYPE_BYTE);
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	/*
15300Sstevel@tonic-gate 	 * Shouldn't get here. In case we do, return unknown type.
15310Sstevel@tonic-gate 	 *
15320Sstevel@tonic-gate 	 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
15330Sstevel@tonic-gate 	 *	to add DI_PROP_TYPE_COMPOSITE.
15340Sstevel@tonic-gate 	 */
15350Sstevel@tonic-gate 	DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate /*
15410Sstevel@tonic-gate  * Extract type-specific values of an property
15420Sstevel@tonic-gate  */
15430Sstevel@tonic-gate extern int di_prop_decode_common(void *prop_data, int len,
15440Sstevel@tonic-gate 	int ddi_type, int prom);
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate int
di_prop_ints(di_prop_t prop,int ** prop_data)15470Sstevel@tonic-gate di_prop_ints(di_prop_t prop, int **prop_data)
15480Sstevel@tonic-gate {
15490Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15500Sstevel@tonic-gate 		return (0);	/* boolean property */
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
15530Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
15540Sstevel@tonic-gate 		errno = EFAULT;
15550Sstevel@tonic-gate 		*prop_data = NULL;
15560Sstevel@tonic-gate 		return (-1);
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
15600Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
15630Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
15640Sstevel@tonic-gate }
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate int
di_prop_int64(di_prop_t prop,int64_t ** prop_data)15670Sstevel@tonic-gate di_prop_int64(di_prop_t prop, int64_t **prop_data)
15680Sstevel@tonic-gate {
15690Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15700Sstevel@tonic-gate 		return (0);	/* boolean property */
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
15730Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
15740Sstevel@tonic-gate 		errno = EFAULT;
15750Sstevel@tonic-gate 		*prop_data = NULL;
15760Sstevel@tonic-gate 		return (-1);
15770Sstevel@tonic-gate 	}
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
15800Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data));
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
15830Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
15840Sstevel@tonic-gate }
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate int
di_prop_strings(di_prop_t prop,char ** prop_data)15870Sstevel@tonic-gate di_prop_strings(di_prop_t prop, char **prop_data)
15880Sstevel@tonic-gate {
15890Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
15900Sstevel@tonic-gate 		return (0);	/* boolean property */
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
15930Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
15940Sstevel@tonic-gate 		errno = EFAULT;
15950Sstevel@tonic-gate 		*prop_data = NULL;
15960Sstevel@tonic-gate 		return (-1);
15970Sstevel@tonic-gate 	}
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
16000Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
16030Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate int
di_prop_bytes(di_prop_t prop,uchar_t ** prop_data)16070Sstevel@tonic-gate di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
16080Sstevel@tonic-gate {
16090Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0)
16100Sstevel@tonic-gate 		return (0);	/* boolean property */
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
16130Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
16140Sstevel@tonic-gate 		errno = EFAULT;
16150Sstevel@tonic-gate 		*prop_data = NULL;
16160Sstevel@tonic-gate 		return (-1);
16170Sstevel@tonic-gate 	}
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
16200Sstevel@tonic-gate 	    + DI_PROP(prop)->prop_data);
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
16230Sstevel@tonic-gate 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
16240Sstevel@tonic-gate }
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate /*
16270Sstevel@tonic-gate  * returns 1 for match, 0 for no match
16280Sstevel@tonic-gate  */
16290Sstevel@tonic-gate static int
match_prop(di_prop_t prop,dev_t match_dev,const char * name,int type)16300Sstevel@tonic-gate match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
16310Sstevel@tonic-gate {
16320Sstevel@tonic-gate 	int prop_type;
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate #ifdef DEBUG
16350Sstevel@tonic-gate 	if (di_prop_name(prop) == NULL) {
16360Sstevel@tonic-gate 		DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
16370Sstevel@tonic-gate 		return (0);
16380Sstevel@tonic-gate 	}
16390Sstevel@tonic-gate #endif /* DEBUG */
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	if (strcmp(name, di_prop_name(prop)) != 0)
16420Sstevel@tonic-gate 		return (0);
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
16450Sstevel@tonic-gate 		return (0);
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	/*
16480Sstevel@tonic-gate 	 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
16490Sstevel@tonic-gate 	 */
16500Sstevel@tonic-gate 	prop_type = di_prop_type(prop);
16510Sstevel@tonic-gate 	if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) &&
16520Sstevel@tonic-gate 	    (prop_type != DI_PROP_TYPE_BOOLEAN))
16530Sstevel@tonic-gate 		return (0);
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 	return (1);
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate static di_prop_t
di_prop_search(dev_t match_dev,di_node_t node,const char * name,int type)16590Sstevel@tonic-gate di_prop_search(dev_t match_dev, di_node_t node, const char *name,
16600Sstevel@tonic-gate     int type)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate 	di_prop_t prop = DI_PROP_NIL;
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 	/*
16650Sstevel@tonic-gate 	 * The check on match_dev follows ddi_prop_lookup_common().
16660Sstevel@tonic-gate 	 * Other checks are libdevinfo specific implementation.
16670Sstevel@tonic-gate 	 */
16680Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
16690Sstevel@tonic-gate 	    (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) {
16700Sstevel@tonic-gate 		errno = EINVAL;
16710Sstevel@tonic-gate 		return (DI_PROP_NIL);
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
16750Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n",
16760Sstevel@tonic-gate 		    di_prop_name(prop), di_prop_devt(prop),
16770Sstevel@tonic-gate 		    di_prop_type(prop)));
16780Sstevel@tonic-gate 		if (match_prop(prop, match_dev, name, type))
16790Sstevel@tonic-gate 			return (prop);
16800Sstevel@tonic-gate 	}
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	return (DI_PROP_NIL);
16830Sstevel@tonic-gate }
16840Sstevel@tonic-gate 
16853814Sjveta di_prop_t
di_prop_find(dev_t match_dev,di_node_t node,const char * name)16863814Sjveta di_prop_find(dev_t match_dev, di_node_t node, const char *name)
16873814Sjveta {
16883814Sjveta 	di_prop_t prop = DI_PROP_NIL;
16893814Sjveta 
16903814Sjveta 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
16913814Sjveta 	    (match_dev == DDI_DEV_T_NONE)) {
16923814Sjveta 		errno = EINVAL;
16933814Sjveta 		return (DI_PROP_NIL);
16943814Sjveta 	}
16953814Sjveta 
16963814Sjveta 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
16973814Sjveta 		DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n",
16983814Sjveta 		    di_prop_name(prop), di_prop_devt(prop),
16993814Sjveta 		    di_prop_type(prop)));
17003814Sjveta 
17013814Sjveta 		if (strcmp(name, di_prop_name(prop)) == 0 &&
17023814Sjveta 		    (match_dev == DDI_DEV_T_ANY ||
17033814Sjveta 		    di_prop_devt(prop) == match_dev))
17043814Sjveta 			return (prop);
17053814Sjveta 	}
17063814Sjveta 
17073814Sjveta 	return (DI_PROP_NIL);
17083814Sjveta }
17093814Sjveta 
17100Sstevel@tonic-gate int
di_prop_lookup_ints(dev_t dev,di_node_t node,const char * prop_name,int ** prop_data)17110Sstevel@tonic-gate di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
17120Sstevel@tonic-gate 	int **prop_data)
17130Sstevel@tonic-gate {
17140Sstevel@tonic-gate 	di_prop_t prop;
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17170Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
17180Sstevel@tonic-gate 		return (-1);
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 	return (di_prop_ints(prop, (void *)prop_data));
17210Sstevel@tonic-gate }
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate int
di_prop_lookup_int64(dev_t dev,di_node_t node,const char * prop_name,int64_t ** prop_data)17240Sstevel@tonic-gate di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
17250Sstevel@tonic-gate 	int64_t **prop_data)
17260Sstevel@tonic-gate {
17270Sstevel@tonic-gate 	di_prop_t prop;
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17300Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
17310Sstevel@tonic-gate 		return (-1);
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 	return (di_prop_int64(prop, (void *)prop_data));
17340Sstevel@tonic-gate }
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate int
di_prop_lookup_strings(dev_t dev,di_node_t node,const char * prop_name,char ** prop_data)17370Sstevel@tonic-gate di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
17380Sstevel@tonic-gate     char **prop_data)
17390Sstevel@tonic-gate {
17400Sstevel@tonic-gate 	di_prop_t prop;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17430Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
17440Sstevel@tonic-gate 		return (-1);
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	return (di_prop_strings(prop, (void *)prop_data));
17470Sstevel@tonic-gate }
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate int
di_prop_lookup_bytes(dev_t dev,di_node_t node,const char * prop_name,uchar_t ** prop_data)17500Sstevel@tonic-gate di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
17510Sstevel@tonic-gate 	uchar_t **prop_data)
17520Sstevel@tonic-gate {
17530Sstevel@tonic-gate 	di_prop_t prop;
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	if ((prop = di_prop_search(dev, node, prop_name,
17560Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
17570Sstevel@tonic-gate 		return (-1);
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 	return (di_prop_bytes(prop, (void *)prop_data));
17600Sstevel@tonic-gate }
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate /*
17630Sstevel@tonic-gate  * Consolidation private property access functions
17640Sstevel@tonic-gate  */
17650Sstevel@tonic-gate enum prop_type {
17660Sstevel@tonic-gate 	PROP_TYPE_DRV,
17670Sstevel@tonic-gate 	PROP_TYPE_SYS,
17680Sstevel@tonic-gate 	PROP_TYPE_GLOB,
17690Sstevel@tonic-gate 	PROP_TYPE_HW
17700Sstevel@tonic-gate };
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate static di_prop_t
di_prop_next_common(di_node_t node,di_prop_t prop,int prop_type)17730Sstevel@tonic-gate di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
17740Sstevel@tonic-gate {
17750Sstevel@tonic-gate 	caddr_t pa;
17760Sstevel@tonic-gate 	di_off_t prop_off = 0;
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
17790Sstevel@tonic-gate 		if (DI_PROP(prop)->next) {
17800Sstevel@tonic-gate 			return (DI_PROP((caddr_t)prop -
17810Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
17820Sstevel@tonic-gate 		} else {
17830Sstevel@tonic-gate 			return (DI_PROP_NIL);
17840Sstevel@tonic-gate 		}
17850Sstevel@tonic-gate 	}
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	/*
17890Sstevel@tonic-gate 	 * prop is NIL, caller asks for first property
17900Sstevel@tonic-gate 	 */
17910Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
17920Sstevel@tonic-gate 	switch (prop_type) {
17930Sstevel@tonic-gate 	case PROP_TYPE_DRV:
17940Sstevel@tonic-gate 		prop_off = DI_NODE(node)->drv_prop;
17950Sstevel@tonic-gate 		break;
17960Sstevel@tonic-gate 	case PROP_TYPE_SYS:
17970Sstevel@tonic-gate 		prop_off = DI_NODE(node)->sys_prop;
17980Sstevel@tonic-gate 		break;
17990Sstevel@tonic-gate 	case PROP_TYPE_HW:
18000Sstevel@tonic-gate 		prop_off = DI_NODE(node)->hw_prop;
18010Sstevel@tonic-gate 		break;
18020Sstevel@tonic-gate 	case PROP_TYPE_GLOB:
18030Sstevel@tonic-gate 		prop_off = DI_NODE(node)->glob_prop;
18040Sstevel@tonic-gate 		if (prop_off == -1) {
18050Sstevel@tonic-gate 			/* no global property */
18060Sstevel@tonic-gate 			prop_off = 0;
18070Sstevel@tonic-gate 		} else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) {
18080Sstevel@tonic-gate 			/* refer to devnames array */
18090Sstevel@tonic-gate 			struct di_devnm *devnm = DI_DEVNM(pa +
18100Sstevel@tonic-gate 			    DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major *
18110Sstevel@tonic-gate 			    sizeof (struct di_devnm)));
18120Sstevel@tonic-gate 			prop_off = devnm->global_prop;
18130Sstevel@tonic-gate 		}
18140Sstevel@tonic-gate 		break;
18150Sstevel@tonic-gate 	}
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 	if (prop_off) {
18180Sstevel@tonic-gate 		return (DI_PROP(pa + prop_off));
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 	/*
18220Sstevel@tonic-gate 	 * no prop found. Check the reason for not found
18230Sstevel@tonic-gate 	 */
18240Sstevel@tonic-gate 	if (DINFOPROP & DI_ALL(pa)->command)
18250Sstevel@tonic-gate 		errno = ENXIO;
18260Sstevel@tonic-gate 	else
18270Sstevel@tonic-gate 		errno = ENOTSUP;
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	return (DI_PROP_NIL);
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate di_prop_t
di_prop_drv_next(di_node_t node,di_prop_t prop)18330Sstevel@tonic-gate di_prop_drv_next(di_node_t node, di_prop_t prop)
18340Sstevel@tonic-gate {
18350Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
18360Sstevel@tonic-gate }
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate di_prop_t
di_prop_sys_next(di_node_t node,di_prop_t prop)18390Sstevel@tonic-gate di_prop_sys_next(di_node_t node, di_prop_t prop)
18400Sstevel@tonic-gate {
18410Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
18420Sstevel@tonic-gate }
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate di_prop_t
di_prop_global_next(di_node_t node,di_prop_t prop)18450Sstevel@tonic-gate di_prop_global_next(di_node_t node, di_prop_t prop)
18460Sstevel@tonic-gate {
18470Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
18480Sstevel@tonic-gate }
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate di_prop_t
di_prop_hw_next(di_node_t node,di_prop_t prop)18510Sstevel@tonic-gate di_prop_hw_next(di_node_t node, di_prop_t prop)
18520Sstevel@tonic-gate {
18530Sstevel@tonic-gate 	return (di_prop_next_common(node, prop, PROP_TYPE_HW));
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate int
di_prop_rawdata(di_prop_t prop,uchar_t ** prop_data)18570Sstevel@tonic-gate di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
18580Sstevel@tonic-gate {
18590Sstevel@tonic-gate #ifdef DEBUG
18600Sstevel@tonic-gate 	if (prop == DI_PROP_NIL) {
18610Sstevel@tonic-gate 		errno = EINVAL;
18620Sstevel@tonic-gate 		return (-1);
18630Sstevel@tonic-gate 	}
18640Sstevel@tonic-gate #endif /* DEBUG */
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	if (DI_PROP(prop)->prop_len == 0) {
18670Sstevel@tonic-gate 		*prop_data = NULL;
18680Sstevel@tonic-gate 		return (0);
18690Sstevel@tonic-gate 	}
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 	if ((DI_PROP(prop)->prop_data == 0) ||
18720Sstevel@tonic-gate 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
18730Sstevel@tonic-gate 		errno = EFAULT;
18740Sstevel@tonic-gate 		*prop_data = NULL;
18750Sstevel@tonic-gate 		return (-1);
18760Sstevel@tonic-gate 	}
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 	/*
18790Sstevel@tonic-gate 	 * No memory allocation.
18800Sstevel@tonic-gate 	 */
18810Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
18820Sstevel@tonic-gate 	    DI_PROP(prop)->prop_data);
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 	return (DI_PROP(prop)->prop_len);
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate /*
18880Sstevel@tonic-gate  * Consolidation private interfaces for accessing I/O multipathing data
18890Sstevel@tonic-gate  */
18900Sstevel@tonic-gate di_path_t
di_path_phci_next_path(di_node_t node,di_path_t path)18916640Scth di_path_phci_next_path(di_node_t node, di_path_t path)
18920Sstevel@tonic-gate {
18930Sstevel@tonic-gate 	caddr_t pa;
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	/*
18960Sstevel@tonic-gate 	 * path is not NIL
18970Sstevel@tonic-gate 	 */
18980Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
18990Sstevel@tonic-gate 		if (DI_PATH(path)->path_p_link != 0)
19000Sstevel@tonic-gate 			return (DI_PATH((void *)((caddr_t)path -
19010Sstevel@tonic-gate 			    DI_PATH(path)->self + DI_PATH(path)->path_p_link)));
19020Sstevel@tonic-gate 		else {
19030Sstevel@tonic-gate 			errno = ENXIO;
19040Sstevel@tonic-gate 			return (DI_PATH_NIL);
19050Sstevel@tonic-gate 		}
19060Sstevel@tonic-gate 	}
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	/*
19090Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
19100Sstevel@tonic-gate 	 */
19110Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_phci != 0) {
19126640Scth 		DPRINTF((DI_INFO, "phci_next_path: returning %p\n",
19136640Scth 		    ((caddr_t)node -
19140Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
19150Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
19160Sstevel@tonic-gate 		    DI_NODE(node)->multipath_phci));
19170Sstevel@tonic-gate 	}
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 	/*
19200Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
19210Sstevel@tonic-gate 	 * to set errno properly.
19220Sstevel@tonic-gate 	 */
19230Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
19240Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
19250Sstevel@tonic-gate 		errno = ENXIO;
19260Sstevel@tonic-gate 	else
19270Sstevel@tonic-gate 		errno = ENOTSUP;
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	return (DI_PATH_NIL);
19300Sstevel@tonic-gate }
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate di_path_t
di_path_client_next_path(di_node_t node,di_path_t path)19336640Scth di_path_client_next_path(di_node_t node, di_path_t path)
19340Sstevel@tonic-gate {
19350Sstevel@tonic-gate 	caddr_t pa;
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 	/*
19380Sstevel@tonic-gate 	 * path is not NIL
19390Sstevel@tonic-gate 	 */
19400Sstevel@tonic-gate 	if (path != DI_PATH_NIL) {
19410Sstevel@tonic-gate 		if (DI_PATH(path)->path_c_link != 0)
19420Sstevel@tonic-gate 			return (DI_PATH((caddr_t)path - DI_PATH(path)->self
19430Sstevel@tonic-gate 			    + DI_PATH(path)->path_c_link));
19440Sstevel@tonic-gate 		else {
19450Sstevel@tonic-gate 			errno = ENXIO;
19460Sstevel@tonic-gate 			return (DI_PATH_NIL);
19470Sstevel@tonic-gate 		}
19480Sstevel@tonic-gate 	}
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 	/*
19510Sstevel@tonic-gate 	 * Path is NIL; the caller is asking for the first path info node
19520Sstevel@tonic-gate 	 */
19530Sstevel@tonic-gate 	if (DI_NODE(node)->multipath_client != 0) {
19546640Scth 		DPRINTF((DI_INFO, "client_next_path: returning %p\n",
19556640Scth 		    ((caddr_t)node -
19560Sstevel@tonic-gate 		    DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
19570Sstevel@tonic-gate 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
19580Sstevel@tonic-gate 		    DI_NODE(node)->multipath_client));
19590Sstevel@tonic-gate 	}
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	/*
19620Sstevel@tonic-gate 	 * No pathing data; check if the snapshot includes path data in order
19630Sstevel@tonic-gate 	 * to set errno properly.
19640Sstevel@tonic-gate 	 */
19650Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
19660Sstevel@tonic-gate 	if (DINFOPATH & (DI_ALL(pa)->command))
19670Sstevel@tonic-gate 		errno = ENXIO;
19680Sstevel@tonic-gate 	else
19690Sstevel@tonic-gate 		errno = ENOTSUP;
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	return (DI_PATH_NIL);
19720Sstevel@tonic-gate }
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate /*
19756640Scth  * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
19766640Scth  * below after NWS consolidation switches to using di_path_bus_addr,
19776640Scth  * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
19780Sstevel@tonic-gate  */
19790Sstevel@tonic-gate char *
di_path_addr(di_path_t path,char * buf)19800Sstevel@tonic-gate di_path_addr(di_path_t path, char *buf)
19810Sstevel@tonic-gate {
19820Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	(void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
19870Sstevel@tonic-gate 	    MAXPATHLEN);
19880Sstevel@tonic-gate 	return (buf);
19890Sstevel@tonic-gate }
19906640Scth di_path_t
di_path_next(di_node_t node,di_path_t path)19916640Scth di_path_next(di_node_t node, di_path_t path)
19926640Scth {
19936640Scth 	if (node == DI_NODE_NIL) {
19946640Scth 		errno = EINVAL;
19956640Scth 		return (DI_PATH_NIL);
19966640Scth 	}
19976640Scth 
19986640Scth 	if (DI_NODE(node)->multipath_client) {
19996640Scth 		return (di_path_client_next_path(node, path));
20006640Scth 	} else if (DI_NODE(node)->multipath_phci) {
20016640Scth 		return (di_path_phci_next_path(node, path));
20026640Scth 	} else {
20036640Scth 		/*
20046640Scth 		 * The node had multipathing data but didn't appear to be a
20056640Scth 		 * phci *or* a client; probably a programmer error.
20066640Scth 		 */
20076640Scth 		errno = EINVAL;
20086640Scth 		return (DI_PATH_NIL);
20096640Scth 	}
20106640Scth }
20116640Scth di_path_t
di_path_next_phci(di_node_t node,di_path_t path)20126640Scth di_path_next_phci(di_node_t node, di_path_t path)
20136640Scth {
20146640Scth 	return (di_path_client_next_path(node, path));
20156640Scth }
20166640Scth di_path_t
di_path_next_client(di_node_t node,di_path_t path)20176640Scth di_path_next_client(di_node_t node, di_path_t path)
20186640Scth {
20196640Scth 	return (di_path_phci_next_path(node, path));
20206640Scth }
20216640Scth 
20226640Scth 
20236640Scth 
20246640Scth 
20256640Scth di_path_state_t
di_path_state(di_path_t path)20266640Scth di_path_state(di_path_t path)
20276640Scth {
20286640Scth 	return ((di_path_state_t)DI_PATH(path)->path_state);
20296640Scth }
20306640Scth 
203110696SDavid.Hollister@Sun.COM uint_t
di_path_flags(di_path_t path)203210696SDavid.Hollister@Sun.COM di_path_flags(di_path_t path)
203310696SDavid.Hollister@Sun.COM {
203410696SDavid.Hollister@Sun.COM 	return (DI_PATH(path)->path_flags);
203510696SDavid.Hollister@Sun.COM }
203610696SDavid.Hollister@Sun.COM 
20376640Scth char *
di_path_node_name(di_path_t path)20386640Scth di_path_node_name(di_path_t path)
20396640Scth {
20406640Scth 	di_node_t	client_node;
20416640Scth 
20426640Scth 	/* pathinfo gets node_name from client */
20436640Scth 	if ((client_node = di_path_client_node(path)) == NULL)
20446640Scth 		return (NULL);
20456640Scth 	return (di_node_name(client_node));
20466640Scth }
20476640Scth 
20486640Scth char *
di_path_bus_addr(di_path_t path)20496640Scth di_path_bus_addr(di_path_t path)
20506640Scth {
20516640Scth 	caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
20526640Scth 
20536640Scth 	if (DI_PATH(path)->path_addr == 0)
20546640Scth 		return (NULL);
20556640Scth 
20566640Scth 	return ((char *)(pa + DI_PATH(path)->path_addr));
20576640Scth }
20586640Scth 
20596640Scth int
di_path_instance(di_path_t path)20606640Scth di_path_instance(di_path_t path)
20616640Scth {
20626640Scth 	return (DI_PATH(path)->path_instance);
20636640Scth }
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate di_node_t
di_path_client_node(di_path_t path)20660Sstevel@tonic-gate di_path_client_node(di_path_t path)
20670Sstevel@tonic-gate {
20680Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
20710Sstevel@tonic-gate 		errno = EINVAL;
20720Sstevel@tonic-gate 		return (DI_PATH_NIL);
20730Sstevel@tonic-gate 	}
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
20780Sstevel@tonic-gate 
20790Sstevel@tonic-gate 	if (DI_PATH(path)->path_client) {
20800Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_client));
20810Sstevel@tonic-gate 	}
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate 	/*
20840Sstevel@tonic-gate 	 * Deal with error condition:
20850Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
20860Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
20870Sstevel@tonic-gate 	 */
20880Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
20890Sstevel@tonic-gate 		errno = ENOTSUP;
20900Sstevel@tonic-gate 	else
20910Sstevel@tonic-gate 		errno = ENXIO;
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 	return (DI_NODE_NIL);
20940Sstevel@tonic-gate }
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate di_node_t
di_path_phci_node(di_path_t path)20970Sstevel@tonic-gate di_path_phci_node(di_path_t path)
20980Sstevel@tonic-gate {
20990Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
21020Sstevel@tonic-gate 		errno = EINVAL;
21030Sstevel@tonic-gate 		return (DI_PATH_NIL);
21040Sstevel@tonic-gate 	}
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 	if (DI_PATH(path)->path_phci) {
21110Sstevel@tonic-gate 		return (DI_NODE(pa + DI_PATH(path)->path_phci));
21120Sstevel@tonic-gate 	}
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate 	/*
21150Sstevel@tonic-gate 	 * Deal with error condition:
21160Sstevel@tonic-gate 	 *   If parent doesn't exist and node is not the root,
21170Sstevel@tonic-gate 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
21180Sstevel@tonic-gate 	 */
21190Sstevel@tonic-gate 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
21200Sstevel@tonic-gate 		errno = ENOTSUP;
21210Sstevel@tonic-gate 	else
21220Sstevel@tonic-gate 		errno = ENXIO;
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 	return (DI_NODE_NIL);
21250Sstevel@tonic-gate }
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate di_path_prop_t
di_path_prop_next(di_path_t path,di_path_prop_t prop)21280Sstevel@tonic-gate di_path_prop_next(di_path_t path, di_path_prop_t prop)
21290Sstevel@tonic-gate {
21300Sstevel@tonic-gate 	caddr_t pa;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 	if (path == DI_PATH_NIL) {
21330Sstevel@tonic-gate 		errno = EINVAL;
21340Sstevel@tonic-gate 		return (DI_PROP_NIL);
21350Sstevel@tonic-gate 	}
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 	/*
21380Sstevel@tonic-gate 	 * prop is not NIL
21390Sstevel@tonic-gate 	 */
21400Sstevel@tonic-gate 	if (prop != DI_PROP_NIL) {
21410Sstevel@tonic-gate 		if (DI_PROP(prop)->next != 0)
21420Sstevel@tonic-gate 			return (DI_PATHPROP((caddr_t)prop -
21430Sstevel@tonic-gate 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
21440Sstevel@tonic-gate 		else {
21450Sstevel@tonic-gate 			errno = ENXIO;
21460Sstevel@tonic-gate 			return (DI_PROP_NIL);
21470Sstevel@tonic-gate 		}
21480Sstevel@tonic-gate 	}
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 	/*
21510Sstevel@tonic-gate 	 * prop is NIL-->caller asks for first property
21520Sstevel@tonic-gate 	 */
21530Sstevel@tonic-gate 	pa = (caddr_t)path - DI_PATH(path)->self;
21540Sstevel@tonic-gate 	if (DI_PATH(path)->path_prop != 0) {
21550Sstevel@tonic-gate 		return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
21560Sstevel@tonic-gate 	}
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 	/*
21590Sstevel@tonic-gate 	 * no property data-->check if snapshot includes props
21600Sstevel@tonic-gate 	 *	in order to set the correct errno
21610Sstevel@tonic-gate 	 */
21620Sstevel@tonic-gate 	if (DINFOPROP & (DI_ALL(pa)->command))
21630Sstevel@tonic-gate 		errno = ENXIO;
21640Sstevel@tonic-gate 	else
21650Sstevel@tonic-gate 		errno = ENOTSUP;
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	return (DI_PROP_NIL);
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate char *
di_path_prop_name(di_path_prop_t prop)21710Sstevel@tonic-gate di_path_prop_name(di_path_prop_t prop)
21720Sstevel@tonic-gate {
21730Sstevel@tonic-gate 	caddr_t pa;		/* starting address of map */
21740Sstevel@tonic-gate 	pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
21750Sstevel@tonic-gate 	return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
21760Sstevel@tonic-gate }
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate int
di_path_prop_len(di_path_prop_t prop)21790Sstevel@tonic-gate di_path_prop_len(di_path_prop_t prop)
21800Sstevel@tonic-gate {
21810Sstevel@tonic-gate 	return (DI_PATHPROP(prop)->prop_len);
21820Sstevel@tonic-gate }
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate int
di_path_prop_type(di_path_prop_t prop)21850Sstevel@tonic-gate di_path_prop_type(di_path_prop_t prop)
21860Sstevel@tonic-gate {
21870Sstevel@tonic-gate 	switch (DI_PATHPROP(prop)->prop_type) {
21880Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT:
21890Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT);
21900Sstevel@tonic-gate 		case DDI_PROP_TYPE_INT64:
21910Sstevel@tonic-gate 			return (DI_PROP_TYPE_INT64);
21920Sstevel@tonic-gate 		case DDI_PROP_TYPE_BYTE:
21930Sstevel@tonic-gate 			return (DI_PROP_TYPE_BYTE);
21940Sstevel@tonic-gate 		case DDI_PROP_TYPE_STRING:
21950Sstevel@tonic-gate 			return (DI_PROP_TYPE_STRING);
21960Sstevel@tonic-gate 	}
21970Sstevel@tonic-gate 	return (DI_PROP_TYPE_UNKNOWN);
21980Sstevel@tonic-gate }
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate int
di_path_prop_bytes(di_path_prop_t prop,uchar_t ** prop_data)22010Sstevel@tonic-gate di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
22020Sstevel@tonic-gate {
22030Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22040Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22050Sstevel@tonic-gate 		errno = EFAULT;
22060Sstevel@tonic-gate 		*prop_data = NULL;
22070Sstevel@tonic-gate 		return (-1);
22080Sstevel@tonic-gate 	}
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
22110Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22140Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
22150Sstevel@tonic-gate }
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate int
di_path_prop_ints(di_path_prop_t prop,int ** prop_data)22180Sstevel@tonic-gate di_path_prop_ints(di_path_prop_t prop, int **prop_data)
22190Sstevel@tonic-gate {
22200Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
22210Sstevel@tonic-gate 		return (0);
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22240Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22250Sstevel@tonic-gate 		errno = EFAULT;
22260Sstevel@tonic-gate 		*prop_data = NULL;
22270Sstevel@tonic-gate 		return (-1);
22280Sstevel@tonic-gate 	}
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
22310Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data));
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22340Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
22350Sstevel@tonic-gate }
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate int
di_path_prop_int64s(di_path_prop_t prop,int64_t ** prop_data)22380Sstevel@tonic-gate di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
22390Sstevel@tonic-gate {
22400Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
22410Sstevel@tonic-gate 		return (0);
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22440Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22450Sstevel@tonic-gate 		errno = EFAULT;
22460Sstevel@tonic-gate 		*prop_data = NULL;
22470Sstevel@tonic-gate 		return (-1);
22480Sstevel@tonic-gate 	}
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 	*prop_data = (int64_t *)((void *)((caddr_t)prop -
22510Sstevel@tonic-gate 	    DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22540Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
22550Sstevel@tonic-gate }
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate int
di_path_prop_strings(di_path_prop_t prop,char ** prop_data)22580Sstevel@tonic-gate di_path_prop_strings(di_path_prop_t prop, char **prop_data)
22590Sstevel@tonic-gate {
22600Sstevel@tonic-gate 	if (DI_PATHPROP(prop)->prop_len == 0)
22610Sstevel@tonic-gate 		return (0);
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
22640Sstevel@tonic-gate 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
22650Sstevel@tonic-gate 		errno = EFAULT;
22660Sstevel@tonic-gate 		*prop_data = NULL;
22670Sstevel@tonic-gate 		return (-1);
22680Sstevel@tonic-gate 	}
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	*prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
22710Sstevel@tonic-gate 	    + DI_PATHPROP(prop)->prop_data);
22720Sstevel@tonic-gate 
22730Sstevel@tonic-gate 	return (di_prop_decode_common((void *)prop_data,
22740Sstevel@tonic-gate 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
22750Sstevel@tonic-gate }
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate static di_path_prop_t
di_path_prop_search(di_path_t path,const char * name,int type)22780Sstevel@tonic-gate di_path_prop_search(di_path_t path, const char *name, int type)
22790Sstevel@tonic-gate {
22800Sstevel@tonic-gate 	di_path_prop_t prop = DI_PROP_NIL;
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 	/*
22830Sstevel@tonic-gate 	 * Sanity check arguments
22840Sstevel@tonic-gate 	 */
22850Sstevel@tonic-gate 	if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
22860Sstevel@tonic-gate 	    !DI_PROP_TYPE_VALID(type)) {
22870Sstevel@tonic-gate 		errno = EINVAL;
22880Sstevel@tonic-gate 		return (DI_PROP_NIL);
22890Sstevel@tonic-gate 	}
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
22920Sstevel@tonic-gate 		int prop_type = di_path_prop_type(prop);
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 		DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
22950Sstevel@tonic-gate 		    di_path_prop_name(prop), prop_type));
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 		if (strcmp(name, di_path_prop_name(prop)) != 0)
22980Sstevel@tonic-gate 			continue;
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 		if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
23010Sstevel@tonic-gate 			continue;
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 		return (prop);
23040Sstevel@tonic-gate 	}
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 	return (DI_PROP_NIL);
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate int
di_path_prop_lookup_bytes(di_path_t path,const char * prop_name,uchar_t ** prop_data)23100Sstevel@tonic-gate di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
23110Sstevel@tonic-gate     uchar_t **prop_data)
23120Sstevel@tonic-gate {
23130Sstevel@tonic-gate 	di_path_prop_t prop;
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23160Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
23170Sstevel@tonic-gate 		return (-1);
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate 	return (di_path_prop_bytes(prop, prop_data));
23200Sstevel@tonic-gate }
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate int
di_path_prop_lookup_ints(di_path_t path,const char * prop_name,int ** prop_data)23230Sstevel@tonic-gate di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
23240Sstevel@tonic-gate     int **prop_data)
23250Sstevel@tonic-gate {
23260Sstevel@tonic-gate 	di_path_prop_t prop;
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23290Sstevel@tonic-gate 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
23300Sstevel@tonic-gate 		return (-1);
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 	return (di_path_prop_ints(prop, prop_data));
23330Sstevel@tonic-gate }
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate int
di_path_prop_lookup_int64s(di_path_t path,const char * prop_name,int64_t ** prop_data)23360Sstevel@tonic-gate di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
23370Sstevel@tonic-gate     int64_t **prop_data)
23380Sstevel@tonic-gate {
23390Sstevel@tonic-gate 	di_path_prop_t prop;
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23420Sstevel@tonic-gate 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
23430Sstevel@tonic-gate 		return (-1);
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 	return (di_path_prop_int64s(prop, prop_data));
23460Sstevel@tonic-gate }
23470Sstevel@tonic-gate 
di_path_prop_lookup_strings(di_path_t path,const char * prop_name,char ** prop_data)23480Sstevel@tonic-gate int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
23490Sstevel@tonic-gate     char **prop_data)
23500Sstevel@tonic-gate {
23510Sstevel@tonic-gate 	di_path_prop_t prop;
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	if ((prop = di_path_prop_search(path, prop_name,
23540Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
23550Sstevel@tonic-gate 		return (-1);
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 	return (di_path_prop_strings(prop, prop_data));
23580Sstevel@tonic-gate }
23590Sstevel@tonic-gate 
2360893Srs135747 /*
2361893Srs135747  * Consolidation private interfaces for traversing vhci nodes.
2362893Srs135747  */
2363893Srs135747 di_node_t
di_vhci_first_node(di_node_t root)2364893Srs135747 di_vhci_first_node(di_node_t root)
2365893Srs135747 {
2366893Srs135747 	struct di_all *dap;
2367893Srs135747 	caddr_t		pa;		/* starting address of map */
2368893Srs135747 
2369893Srs135747 	DPRINTF((DI_INFO, "Get first vhci node\n"));
2370893Srs135747 
2371893Srs135747 	if (root == DI_NODE_NIL) {
2372893Srs135747 		errno = EINVAL;
2373893Srs135747 		return (DI_NODE_NIL);
2374893Srs135747 	}
2375893Srs135747 
2376893Srs135747 	pa = (caddr_t)root - DI_NODE(root)->self;
2377893Srs135747 	dap = DI_ALL(pa);
2378893Srs135747 
2379893Srs135747 	if (dap->top_vhci_devinfo == NULL) {
2380893Srs135747 		errno = ENXIO;
2381893Srs135747 		return (DI_NODE_NIL);
2382893Srs135747 	}
2383893Srs135747 
2384893Srs135747 	return (DI_NODE(pa + dap->top_vhci_devinfo));
2385893Srs135747 }
2386893Srs135747 
2387893Srs135747 di_node_t
di_vhci_next_node(di_node_t node)2388893Srs135747 di_vhci_next_node(di_node_t node)
2389893Srs135747 {
2390893Srs135747 	caddr_t		pa;		/* starting address of map */
2391893Srs135747 
2392893Srs135747 	if (node == DI_NODE_NIL) {
2393893Srs135747 		errno = EINVAL;
2394893Srs135747 		return (DI_NODE_NIL);
2395893Srs135747 	}
2396893Srs135747 
2397893Srs135747 	DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
2398893Srs135747 	    " current=%s\n", di_node_name(node)));
2399893Srs135747 
2400893Srs135747 	if (DI_NODE(node)->next_vhci == NULL) {
2401893Srs135747 		errno = ENXIO;
2402893Srs135747 		return (DI_NODE_NIL);
2403893Srs135747 	}
2404893Srs135747 
2405893Srs135747 	pa = (caddr_t)node - DI_NODE(node)->self;
2406893Srs135747 
2407893Srs135747 	return (DI_NODE(pa + DI_NODE(node)->next_vhci));
2408893Srs135747 }
2409893Srs135747 
2410893Srs135747 /*
2411893Srs135747  * Consolidation private interfaces for traversing phci nodes.
2412893Srs135747  */
2413893Srs135747 di_node_t
di_phci_first_node(di_node_t vhci_node)2414893Srs135747 di_phci_first_node(di_node_t vhci_node)
2415893Srs135747 {
2416893Srs135747 	caddr_t		pa;		/* starting address of map */
2417893Srs135747 
2418893Srs135747 	DPRINTF((DI_INFO, "Get first phci node:\n"
2419893Srs135747 	    " current=%s", di_node_name(vhci_node)));
2420893Srs135747 
2421893Srs135747 	if (vhci_node == DI_NODE_NIL) {
2422893Srs135747 		errno = EINVAL;
2423893Srs135747 		return (DI_NODE_NIL);
2424893Srs135747 	}
2425893Srs135747 
2426893Srs135747 	pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
2427893Srs135747 
2428893Srs135747 	if (DI_NODE(vhci_node)->top_phci == NULL) {
2429893Srs135747 		errno = ENXIO;
2430893Srs135747 		return (DI_NODE_NIL);
2431893Srs135747 	}
2432893Srs135747 
2433893Srs135747 	return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
2434893Srs135747 }
2435893Srs135747 
2436893Srs135747 di_node_t
di_phci_next_node(di_node_t node)2437893Srs135747 di_phci_next_node(di_node_t node)
2438893Srs135747 {
2439893Srs135747 	caddr_t		pa;		/* starting address of map */
2440893Srs135747 
2441893Srs135747 	if (node == DI_NODE_NIL) {
2442893Srs135747 		errno = EINVAL;
2443893Srs135747 		return (DI_NODE_NIL);
2444893Srs135747 	}
2445893Srs135747 
2446893Srs135747 	DPRINTF((DI_TRACE, "next phci node on the snap shot:"
2447893Srs135747 	    " current=%s\n", di_node_name(node)));
2448893Srs135747 
2449893Srs135747 	if (DI_NODE(node)->next_phci == NULL) {
2450893Srs135747 		errno = ENXIO;
2451893Srs135747 		return (DI_NODE_NIL);
2452893Srs135747 	}
2453893Srs135747 
2454893Srs135747 	pa = (caddr_t)node - DI_NODE(node)->self;
2455893Srs135747 
2456893Srs135747 	return (DI_NODE(pa + DI_NODE(node)->next_phci));
2457893Srs135747 }
24580Sstevel@tonic-gate 
24590Sstevel@tonic-gate /*
24600Sstevel@tonic-gate  * Consolidation private interfaces for private data
24610Sstevel@tonic-gate  */
24620Sstevel@tonic-gate void *
di_parent_private_data(di_node_t node)24630Sstevel@tonic-gate di_parent_private_data(di_node_t node)
24640Sstevel@tonic-gate {
24650Sstevel@tonic-gate 	caddr_t pa;
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == 0) {
24680Sstevel@tonic-gate 		errno = ENXIO;
24690Sstevel@tonic-gate 		return (NULL);
24700Sstevel@tonic-gate 	}
24710Sstevel@tonic-gate 
24720Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data == (di_off_t)-1) {
24730Sstevel@tonic-gate 		/*
24740Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
24750Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
24760Sstevel@tonic-gate 		 */
24770Sstevel@tonic-gate 		errno = EFAULT;
24780Sstevel@tonic-gate 		return (NULL);
24790Sstevel@tonic-gate 	}
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
24820Sstevel@tonic-gate 	if (DI_NODE(node)->parent_data)
24830Sstevel@tonic-gate 		return (pa + DI_NODE(node)->parent_data);
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
24860Sstevel@tonic-gate 		errno = ENXIO;
24870Sstevel@tonic-gate 	else
24880Sstevel@tonic-gate 		errno = ENOTSUP;
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate 	return (NULL);
24910Sstevel@tonic-gate }
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate void *
di_driver_private_data(di_node_t node)24940Sstevel@tonic-gate di_driver_private_data(di_node_t node)
24950Sstevel@tonic-gate {
24960Sstevel@tonic-gate 	caddr_t pa;
24970Sstevel@tonic-gate 
24980Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == 0) {
24990Sstevel@tonic-gate 		errno = ENXIO;
25000Sstevel@tonic-gate 		return (NULL);
25010Sstevel@tonic-gate 	}
25020Sstevel@tonic-gate 
25030Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data == (di_off_t)-1) {
25040Sstevel@tonic-gate 		/*
25050Sstevel@tonic-gate 		 * Private data requested, but not obtained due to a memory
25060Sstevel@tonic-gate 		 * error (e.g. wrong format specified)
25070Sstevel@tonic-gate 		 */
25080Sstevel@tonic-gate 		errno = EFAULT;
25090Sstevel@tonic-gate 		return (NULL);
25100Sstevel@tonic-gate 	}
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	pa = (caddr_t)node - DI_NODE(node)->self;
25130Sstevel@tonic-gate 	if (DI_NODE(node)->driver_data)
25140Sstevel@tonic-gate 		return (pa + DI_NODE(node)->driver_data);
25150Sstevel@tonic-gate 
25160Sstevel@tonic-gate 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
25170Sstevel@tonic-gate 		errno = ENXIO;
25180Sstevel@tonic-gate 	else
25190Sstevel@tonic-gate 		errno = ENOTSUP;
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate 	return (NULL);
25220Sstevel@tonic-gate }
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate /*
252510923SEvan.Yan@Sun.COM  * Hotplug information access
252610923SEvan.Yan@Sun.COM  */
252710923SEvan.Yan@Sun.COM 
252810923SEvan.Yan@Sun.COM typedef struct {
252910923SEvan.Yan@Sun.COM 	void		*arg;
253010923SEvan.Yan@Sun.COM 	const char	*type;
253110923SEvan.Yan@Sun.COM 	uint_t		flag;
253210923SEvan.Yan@Sun.COM 	int		(*hp_callback)(di_node_t, di_hp_t, void *);
253310923SEvan.Yan@Sun.COM } di_walk_hp_arg_t;
253410923SEvan.Yan@Sun.COM 
253510923SEvan.Yan@Sun.COM static int
di_walk_hp_callback(di_node_t node,void * argp)253610923SEvan.Yan@Sun.COM di_walk_hp_callback(di_node_t node, void *argp)
253710923SEvan.Yan@Sun.COM {
253810923SEvan.Yan@Sun.COM 	di_walk_hp_arg_t 	*arg = (di_walk_hp_arg_t *)argp;
253910923SEvan.Yan@Sun.COM 	di_hp_t			hp;
254010923SEvan.Yan@Sun.COM 	char			*type_str;
254110923SEvan.Yan@Sun.COM 
254210923SEvan.Yan@Sun.COM 	for (hp = DI_HP_NIL; (hp = di_hp_next(node, hp)) != DI_HP_NIL; ) {
254310923SEvan.Yan@Sun.COM 
254410923SEvan.Yan@Sun.COM 		/* Exclude non-matching types if a type filter is specified */
254510923SEvan.Yan@Sun.COM 		if (arg->type != NULL) {
254610923SEvan.Yan@Sun.COM 			type_str = di_hp_description(hp);
254710923SEvan.Yan@Sun.COM 			if (type_str && (strcmp(arg->type, type_str) != 0))
254810923SEvan.Yan@Sun.COM 				continue;
254910923SEvan.Yan@Sun.COM 		}
255010923SEvan.Yan@Sun.COM 
255110923SEvan.Yan@Sun.COM 		/* Exclude ports if DI_HP_PORT flag not specified */
255210923SEvan.Yan@Sun.COM 		if (!(arg->flag & DI_HP_PORT) &&
255310923SEvan.Yan@Sun.COM 		    (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
255410923SEvan.Yan@Sun.COM 			continue;
255510923SEvan.Yan@Sun.COM 
255610923SEvan.Yan@Sun.COM 		/* Exclude connectors if DI_HP_CONNECTOR flag not specified */
255710923SEvan.Yan@Sun.COM 		if (!(arg->flag & DI_HP_CONNECTOR) &&
255810923SEvan.Yan@Sun.COM 		    !(di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
255910923SEvan.Yan@Sun.COM 			continue;
256010923SEvan.Yan@Sun.COM 
256110923SEvan.Yan@Sun.COM 		/* Perform callback */
256210923SEvan.Yan@Sun.COM 		if (arg->hp_callback(node, hp, arg->arg) != DI_WALK_CONTINUE)
256310923SEvan.Yan@Sun.COM 			return (DI_WALK_TERMINATE);
256410923SEvan.Yan@Sun.COM 	}
256510923SEvan.Yan@Sun.COM 
256610923SEvan.Yan@Sun.COM 	return (DI_WALK_CONTINUE);
256710923SEvan.Yan@Sun.COM }
256810923SEvan.Yan@Sun.COM 
256910923SEvan.Yan@Sun.COM int
di_walk_hp(di_node_t node,const char * type,uint_t flag,void * arg,int (* hp_callback)(di_node_t node,di_hp_t hp,void * arg))257010923SEvan.Yan@Sun.COM di_walk_hp(di_node_t node, const char *type, uint_t flag, void *arg,
257110923SEvan.Yan@Sun.COM     int (*hp_callback)(di_node_t node, di_hp_t hp, void *arg))
257210923SEvan.Yan@Sun.COM {
257310923SEvan.Yan@Sun.COM 	di_walk_hp_arg_t	walk_arg;
257410923SEvan.Yan@Sun.COM 	caddr_t			pa;
257510923SEvan.Yan@Sun.COM 
257610923SEvan.Yan@Sun.COM #ifdef DEBUG
257710923SEvan.Yan@Sun.COM 	char	*devfspath = di_devfs_path(node);
257810923SEvan.Yan@Sun.COM 	DPRINTF((DI_INFO, "walking hotplug nodes under %s\n", devfspath));
257910923SEvan.Yan@Sun.COM 	di_devfs_path_free(devfspath);
258010923SEvan.Yan@Sun.COM #endif
258110923SEvan.Yan@Sun.COM 	/*
258210923SEvan.Yan@Sun.COM 	 * paranoid error checking
258310923SEvan.Yan@Sun.COM 	 */
258410923SEvan.Yan@Sun.COM 	if ((node == DI_NODE_NIL) || (hp_callback == NULL)) {
258510923SEvan.Yan@Sun.COM 		errno = EINVAL;
258610923SEvan.Yan@Sun.COM 		return (-1);
258710923SEvan.Yan@Sun.COM 	}
258810923SEvan.Yan@Sun.COM 
258910923SEvan.Yan@Sun.COM 	/* check if hotplug data is included in snapshot */
259010923SEvan.Yan@Sun.COM 	pa = (caddr_t)node - DI_NODE(node)->self;
259110923SEvan.Yan@Sun.COM 	if (!(DI_ALL(pa)->command & DINFOHP)) {
259210923SEvan.Yan@Sun.COM 		errno = ENOTSUP;
259310923SEvan.Yan@Sun.COM 		return (-1);
259410923SEvan.Yan@Sun.COM 	}
259510923SEvan.Yan@Sun.COM 
259610923SEvan.Yan@Sun.COM 	walk_arg.arg = arg;
259710923SEvan.Yan@Sun.COM 	walk_arg.type = type;
259810923SEvan.Yan@Sun.COM 	walk_arg.flag = flag;
259910923SEvan.Yan@Sun.COM 	walk_arg.hp_callback = hp_callback;
260010923SEvan.Yan@Sun.COM 	return (di_walk_node(node, DI_WALK_CLDFIRST, &walk_arg,
260110923SEvan.Yan@Sun.COM 	    di_walk_hp_callback));
260210923SEvan.Yan@Sun.COM }
260310923SEvan.Yan@Sun.COM 
260410923SEvan.Yan@Sun.COM di_hp_t
di_hp_next(di_node_t node,di_hp_t hp)260510923SEvan.Yan@Sun.COM di_hp_next(di_node_t node, di_hp_t hp)
260610923SEvan.Yan@Sun.COM {
260710923SEvan.Yan@Sun.COM 	caddr_t pa;
260810923SEvan.Yan@Sun.COM 
260910923SEvan.Yan@Sun.COM 	/*
261010923SEvan.Yan@Sun.COM 	 * paranoid error checking
261110923SEvan.Yan@Sun.COM 	 */
261210923SEvan.Yan@Sun.COM 	if (node == DI_NODE_NIL) {
261310923SEvan.Yan@Sun.COM 		errno = EINVAL;
261410923SEvan.Yan@Sun.COM 		return (DI_HP_NIL);
261510923SEvan.Yan@Sun.COM 	}
261610923SEvan.Yan@Sun.COM 
261710923SEvan.Yan@Sun.COM 	/*
261810923SEvan.Yan@Sun.COM 	 * hotplug node is not NIL
261910923SEvan.Yan@Sun.COM 	 */
262010923SEvan.Yan@Sun.COM 	if (hp != DI_HP_NIL) {
262110923SEvan.Yan@Sun.COM 		if (DI_HP(hp)->next != 0)
262210923SEvan.Yan@Sun.COM 			return (DI_HP((caddr_t)hp - hp->self + hp->next));
262310923SEvan.Yan@Sun.COM 		else {
262410923SEvan.Yan@Sun.COM 			errno = ENXIO;
262510923SEvan.Yan@Sun.COM 			return (DI_HP_NIL);
262610923SEvan.Yan@Sun.COM 		}
262710923SEvan.Yan@Sun.COM 	}
262810923SEvan.Yan@Sun.COM 
262910923SEvan.Yan@Sun.COM 	/*
263010923SEvan.Yan@Sun.COM 	 * hotplug node is NIL-->caller asks for first hotplug node
263110923SEvan.Yan@Sun.COM 	 */
263210923SEvan.Yan@Sun.COM 	if (DI_NODE(node)->hp_data != 0) {
263310923SEvan.Yan@Sun.COM 		return (DI_HP((caddr_t)node - DI_NODE(node)->self +
263410923SEvan.Yan@Sun.COM 		    DI_NODE(node)->hp_data));
263510923SEvan.Yan@Sun.COM 	}
263610923SEvan.Yan@Sun.COM 
263710923SEvan.Yan@Sun.COM 	/*
263810923SEvan.Yan@Sun.COM 	 * no hotplug data-->check if snapshot includes hotplug data
263910923SEvan.Yan@Sun.COM 	 *	in order to set the correct errno
264010923SEvan.Yan@Sun.COM 	 */
264110923SEvan.Yan@Sun.COM 	pa = (caddr_t)node - DI_NODE(node)->self;
264210923SEvan.Yan@Sun.COM 	if (DINFOHP & DI_ALL(pa)->command)
264310923SEvan.Yan@Sun.COM 		errno = ENXIO;
264410923SEvan.Yan@Sun.COM 	else
264510923SEvan.Yan@Sun.COM 		errno = ENOTSUP;
264610923SEvan.Yan@Sun.COM 
264710923SEvan.Yan@Sun.COM 	return (DI_HP_NIL);
264810923SEvan.Yan@Sun.COM }
264910923SEvan.Yan@Sun.COM 
265010923SEvan.Yan@Sun.COM char *
di_hp_name(di_hp_t hp)265110923SEvan.Yan@Sun.COM di_hp_name(di_hp_t hp)
265210923SEvan.Yan@Sun.COM {
265310923SEvan.Yan@Sun.COM 	caddr_t pa;
265410923SEvan.Yan@Sun.COM 
265510923SEvan.Yan@Sun.COM 	/*
265610923SEvan.Yan@Sun.COM 	 * paranoid error checking
265710923SEvan.Yan@Sun.COM 	 */
265810923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
265910923SEvan.Yan@Sun.COM 		errno = EINVAL;
266010923SEvan.Yan@Sun.COM 		return (NULL);
266110923SEvan.Yan@Sun.COM 	}
266210923SEvan.Yan@Sun.COM 
266310923SEvan.Yan@Sun.COM 	pa = (caddr_t)hp - DI_HP(hp)->self;
266410923SEvan.Yan@Sun.COM 
266510923SEvan.Yan@Sun.COM 	if (DI_HP(hp)->hp_name == 0) {
266610923SEvan.Yan@Sun.COM 		errno = ENXIO;
266710923SEvan.Yan@Sun.COM 		return (NULL);
266810923SEvan.Yan@Sun.COM 	}
266910923SEvan.Yan@Sun.COM 
267010923SEvan.Yan@Sun.COM 	return ((char *)(pa + DI_HP(hp)->hp_name));
267110923SEvan.Yan@Sun.COM }
267210923SEvan.Yan@Sun.COM 
267310923SEvan.Yan@Sun.COM int
di_hp_connection(di_hp_t hp)267410923SEvan.Yan@Sun.COM di_hp_connection(di_hp_t hp)
267510923SEvan.Yan@Sun.COM {
267610923SEvan.Yan@Sun.COM 	/*
267710923SEvan.Yan@Sun.COM 	 * paranoid error checking
267810923SEvan.Yan@Sun.COM 	 */
267910923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
268010923SEvan.Yan@Sun.COM 		errno = EINVAL;
268110923SEvan.Yan@Sun.COM 		return (-1);
268210923SEvan.Yan@Sun.COM 	}
268310923SEvan.Yan@Sun.COM 
268410923SEvan.Yan@Sun.COM 	if (DI_HP(hp)->hp_connection == -1)
268510923SEvan.Yan@Sun.COM 		errno = ENOENT;
268610923SEvan.Yan@Sun.COM 
268710923SEvan.Yan@Sun.COM 	return (DI_HP(hp)->hp_connection);
268810923SEvan.Yan@Sun.COM }
268910923SEvan.Yan@Sun.COM 
269010923SEvan.Yan@Sun.COM int
di_hp_depends_on(di_hp_t hp)269110923SEvan.Yan@Sun.COM di_hp_depends_on(di_hp_t hp)
269210923SEvan.Yan@Sun.COM {
269310923SEvan.Yan@Sun.COM 	/*
269410923SEvan.Yan@Sun.COM 	 * paranoid error checking
269510923SEvan.Yan@Sun.COM 	 */
269610923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
269710923SEvan.Yan@Sun.COM 		errno = EINVAL;
269810923SEvan.Yan@Sun.COM 		return (-1);
269910923SEvan.Yan@Sun.COM 	}
270010923SEvan.Yan@Sun.COM 
270110923SEvan.Yan@Sun.COM 	if (DI_HP(hp)->hp_depends_on == -1)
270210923SEvan.Yan@Sun.COM 		errno = ENOENT;
270310923SEvan.Yan@Sun.COM 
270410923SEvan.Yan@Sun.COM 	return (DI_HP(hp)->hp_depends_on);
270510923SEvan.Yan@Sun.COM }
270610923SEvan.Yan@Sun.COM 
270710923SEvan.Yan@Sun.COM int
di_hp_state(di_hp_t hp)270810923SEvan.Yan@Sun.COM di_hp_state(di_hp_t hp)
270910923SEvan.Yan@Sun.COM {
271010923SEvan.Yan@Sun.COM 	/*
271110923SEvan.Yan@Sun.COM 	 * paranoid error checking
271210923SEvan.Yan@Sun.COM 	 */
271310923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
271410923SEvan.Yan@Sun.COM 		errno = EINVAL;
271510923SEvan.Yan@Sun.COM 		return (-1);
271610923SEvan.Yan@Sun.COM 	}
271710923SEvan.Yan@Sun.COM 
271810923SEvan.Yan@Sun.COM 	return (DI_HP(hp)->hp_state);
271910923SEvan.Yan@Sun.COM }
272010923SEvan.Yan@Sun.COM 
272110923SEvan.Yan@Sun.COM int
di_hp_type(di_hp_t hp)272210923SEvan.Yan@Sun.COM di_hp_type(di_hp_t hp)
272310923SEvan.Yan@Sun.COM {
272410923SEvan.Yan@Sun.COM 	/*
272510923SEvan.Yan@Sun.COM 	 * paranoid error checking
272610923SEvan.Yan@Sun.COM 	 */
272710923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
272810923SEvan.Yan@Sun.COM 		errno = EINVAL;
272910923SEvan.Yan@Sun.COM 		return (-1);
273010923SEvan.Yan@Sun.COM 	}
273110923SEvan.Yan@Sun.COM 
273210923SEvan.Yan@Sun.COM 	return (DI_HP(hp)->hp_type);
273310923SEvan.Yan@Sun.COM }
273410923SEvan.Yan@Sun.COM 
273510923SEvan.Yan@Sun.COM char *
di_hp_description(di_hp_t hp)273610923SEvan.Yan@Sun.COM di_hp_description(di_hp_t hp)
273710923SEvan.Yan@Sun.COM {
273810923SEvan.Yan@Sun.COM 	caddr_t pa;
273910923SEvan.Yan@Sun.COM 
274010923SEvan.Yan@Sun.COM 	/*
274110923SEvan.Yan@Sun.COM 	 * paranoid error checking
274210923SEvan.Yan@Sun.COM 	 */
274310923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
274410923SEvan.Yan@Sun.COM 		errno = EINVAL;
274510923SEvan.Yan@Sun.COM 		return (NULL);
274610923SEvan.Yan@Sun.COM 	}
274710923SEvan.Yan@Sun.COM 
274810923SEvan.Yan@Sun.COM 	pa = (caddr_t)hp - DI_HP(hp)->self;
274910923SEvan.Yan@Sun.COM 
275010923SEvan.Yan@Sun.COM 	if (DI_HP(hp)->hp_type_str == 0)
275110923SEvan.Yan@Sun.COM 		return (NULL);
275210923SEvan.Yan@Sun.COM 
275310923SEvan.Yan@Sun.COM 	return ((char *)(pa + DI_HP(hp)->hp_type_str));
275410923SEvan.Yan@Sun.COM }
275510923SEvan.Yan@Sun.COM 
275610923SEvan.Yan@Sun.COM di_node_t
di_hp_child(di_hp_t hp)275710923SEvan.Yan@Sun.COM di_hp_child(di_hp_t hp)
275810923SEvan.Yan@Sun.COM {
275910923SEvan.Yan@Sun.COM 	caddr_t pa;		/* starting address of map */
276010923SEvan.Yan@Sun.COM 
276110923SEvan.Yan@Sun.COM 	/*
276210923SEvan.Yan@Sun.COM 	 * paranoid error checking
276310923SEvan.Yan@Sun.COM 	 */
276410923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
276510923SEvan.Yan@Sun.COM 		errno = EINVAL;
276610923SEvan.Yan@Sun.COM 		return (DI_NODE_NIL);
276710923SEvan.Yan@Sun.COM 	}
276810923SEvan.Yan@Sun.COM 
276910923SEvan.Yan@Sun.COM 	pa = (caddr_t)hp - DI_HP(hp)->self;
277010923SEvan.Yan@Sun.COM 
277110923SEvan.Yan@Sun.COM 	if (DI_HP(hp)->hp_child > 0) {
277210923SEvan.Yan@Sun.COM 		return (DI_NODE(pa + DI_HP(hp)->hp_child));
277310923SEvan.Yan@Sun.COM 	}
277410923SEvan.Yan@Sun.COM 
277510923SEvan.Yan@Sun.COM 	/*
277610923SEvan.Yan@Sun.COM 	 * Deal with error condition:
277710923SEvan.Yan@Sun.COM 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
277810923SEvan.Yan@Sun.COM 	 *   If it isn't, set errno to ENOTSUP.
277910923SEvan.Yan@Sun.COM 	 */
278010923SEvan.Yan@Sun.COM 	if (!(DINFOSUBTREE & DI_ALL(pa)->command))
278110923SEvan.Yan@Sun.COM 		errno = ENOTSUP;
278210923SEvan.Yan@Sun.COM 	else
278310923SEvan.Yan@Sun.COM 		errno = ENXIO;
278410923SEvan.Yan@Sun.COM 
278510923SEvan.Yan@Sun.COM 	return (DI_NODE_NIL);
278610923SEvan.Yan@Sun.COM }
278710923SEvan.Yan@Sun.COM 
278810923SEvan.Yan@Sun.COM time_t
di_hp_last_change(di_hp_t hp)278910923SEvan.Yan@Sun.COM di_hp_last_change(di_hp_t hp)
279010923SEvan.Yan@Sun.COM {
279110923SEvan.Yan@Sun.COM 	/*
279210923SEvan.Yan@Sun.COM 	 * paranoid error checking
279310923SEvan.Yan@Sun.COM 	 */
279410923SEvan.Yan@Sun.COM 	if (hp == DI_HP_NIL) {
279510923SEvan.Yan@Sun.COM 		errno = EINVAL;
279610923SEvan.Yan@Sun.COM 		return ((time_t)0);
279710923SEvan.Yan@Sun.COM 	}
279810923SEvan.Yan@Sun.COM 
279910923SEvan.Yan@Sun.COM 	return ((time_t)DI_HP(hp)->hp_last_change);
280010923SEvan.Yan@Sun.COM }
280110923SEvan.Yan@Sun.COM 
280210923SEvan.Yan@Sun.COM /*
28030Sstevel@tonic-gate  * PROM property access
28040Sstevel@tonic-gate  */
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate /*
28070Sstevel@tonic-gate  * openprom driver stuff:
28080Sstevel@tonic-gate  *	The maximum property length depends on the buffer size. We use
28090Sstevel@tonic-gate  *	OPROMMAXPARAM defined in <sys/openpromio.h>
28100Sstevel@tonic-gate  *
28110Sstevel@tonic-gate  *	MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
28120Sstevel@tonic-gate  *	MAXVALSZ is maximum value size, which is whatever space left in buf
28130Sstevel@tonic-gate  */
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate #define	OBP_MAXBUF	OPROMMAXPARAM - sizeof (int)
28160Sstevel@tonic-gate #define	OBP_MAXPROPLEN	OBP_MAXBUF - OBP_MAXPROPNAME;
28170Sstevel@tonic-gate 
28180Sstevel@tonic-gate struct di_prom_prop {
28190Sstevel@tonic-gate 	char *name;
28200Sstevel@tonic-gate 	int len;
28210Sstevel@tonic-gate 	uchar_t *data;
28220Sstevel@tonic-gate 	struct di_prom_prop *next;	/* form a linked list */
28230Sstevel@tonic-gate };
28240Sstevel@tonic-gate 
28250Sstevel@tonic-gate struct di_prom_handle { /* handle to prom */
28260Sstevel@tonic-gate 	mutex_t lock;	/* synchronize access to openprom fd */
28270Sstevel@tonic-gate 	int	fd;	/* /dev/openprom file descriptor */
28280Sstevel@tonic-gate 	struct di_prom_prop *list;	/* linked list of prop */
28290Sstevel@tonic-gate 	union {
28300Sstevel@tonic-gate 		char buf[OPROMMAXPARAM];
28310Sstevel@tonic-gate 		struct openpromio opp;
28320Sstevel@tonic-gate 	} oppbuf;
28330Sstevel@tonic-gate };
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate di_prom_handle_t
di_prom_init()28360Sstevel@tonic-gate di_prom_init()
28370Sstevel@tonic-gate {
28380Sstevel@tonic-gate 	struct di_prom_handle *p;
28390Sstevel@tonic-gate 
28400Sstevel@tonic-gate 	if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
28410Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
28420Sstevel@tonic-gate 
28430Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
28440Sstevel@tonic-gate 
28450Sstevel@tonic-gate 	(void) mutex_init(&p->lock, USYNC_THREAD, NULL);
28460Sstevel@tonic-gate 	if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
28470Sstevel@tonic-gate 		free(p);
28480Sstevel@tonic-gate 		return (DI_PROM_HANDLE_NIL);
28490Sstevel@tonic-gate 	}
28500Sstevel@tonic-gate 	p->list = NULL;
28510Sstevel@tonic-gate 
28520Sstevel@tonic-gate 	return ((di_prom_handle_t)p);
28530Sstevel@tonic-gate }
28540Sstevel@tonic-gate 
28550Sstevel@tonic-gate static void
di_prom_prop_free(struct di_prom_prop * list)28560Sstevel@tonic-gate di_prom_prop_free(struct di_prom_prop *list)
28570Sstevel@tonic-gate {
28580Sstevel@tonic-gate 	struct di_prom_prop *tmp = list;
28590Sstevel@tonic-gate 
28600Sstevel@tonic-gate 	while (tmp != NULL) {
28610Sstevel@tonic-gate 		list = tmp->next;
28620Sstevel@tonic-gate 		if (tmp->name != NULL) {
28630Sstevel@tonic-gate 			free(tmp->name);
28640Sstevel@tonic-gate 		}
28650Sstevel@tonic-gate 		if (tmp->data != NULL) {
28660Sstevel@tonic-gate 			free(tmp->data);
28670Sstevel@tonic-gate 		}
28680Sstevel@tonic-gate 		free(tmp);
28690Sstevel@tonic-gate 		tmp = list;
28700Sstevel@tonic-gate 	}
28710Sstevel@tonic-gate }
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate void
di_prom_fini(di_prom_handle_t ph)28740Sstevel@tonic-gate di_prom_fini(di_prom_handle_t ph)
28750Sstevel@tonic-gate {
28760Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
28770Sstevel@tonic-gate 
28780Sstevel@tonic-gate 	DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
28790Sstevel@tonic-gate 
28800Sstevel@tonic-gate 	(void) close(p->fd);
28810Sstevel@tonic-gate 	(void) mutex_destroy(&p->lock);
28820Sstevel@tonic-gate 	di_prom_prop_free(p->list);
28830Sstevel@tonic-gate 
28840Sstevel@tonic-gate 	free(p);
28850Sstevel@tonic-gate }
28860Sstevel@tonic-gate 
28870Sstevel@tonic-gate /*
28880Sstevel@tonic-gate  * Internal library interface for locating the property
28890Sstevel@tonic-gate  * XXX: ph->lock must be held for the duration of call.
28900Sstevel@tonic-gate  */
28910Sstevel@tonic-gate static di_prom_prop_t
di_prom_prop_found(di_prom_handle_t ph,int nodeid,di_prom_prop_t prom_prop)28920Sstevel@tonic-gate di_prom_prop_found(di_prom_handle_t ph, int nodeid,
28930Sstevel@tonic-gate 	di_prom_prop_t prom_prop)
28940Sstevel@tonic-gate {
28950Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
28960Sstevel@tonic-gate 	struct openpromio *opp = &p->oppbuf.opp;
28970Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
28980Sstevel@tonic-gate 	struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
29010Sstevel@tonic-gate 
29020Sstevel@tonic-gate 	/*
29030Sstevel@tonic-gate 	 * Set "current" nodeid in the openprom driver
29040Sstevel@tonic-gate 	 */
29050Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
29060Sstevel@tonic-gate 	*ip = nodeid;
29070Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
29080Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
29090Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29100Sstevel@tonic-gate 	}
29110Sstevel@tonic-gate 
29120Sstevel@tonic-gate 	DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
29130Sstevel@tonic-gate 
29140Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
29150Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPNAME;
29160Sstevel@tonic-gate 	if (prom_prop != DI_PROM_PROP_NIL)
29170Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, prop->name);
29180Sstevel@tonic-gate 
29190Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
29200Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29210Sstevel@tonic-gate 
29220Sstevel@tonic-gate 	/*
29230Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
29240Sstevel@tonic-gate 	 *   (reuse variable prop)
29250Sstevel@tonic-gate 	 */
29260Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
29270Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29280Sstevel@tonic-gate 
29290Sstevel@tonic-gate 	/*
29300Sstevel@tonic-gate 	 * Get a copy of property name
29310Sstevel@tonic-gate 	 */
29320Sstevel@tonic-gate 	if ((prop->name = strdup(opp->oprom_array)) == NULL) {
29330Sstevel@tonic-gate 		free(prop);
29340Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29350Sstevel@tonic-gate 	}
29360Sstevel@tonic-gate 
29370Sstevel@tonic-gate 	/*
29380Sstevel@tonic-gate 	 * get property value and length
29390Sstevel@tonic-gate 	 */
29400Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
29410Sstevel@tonic-gate 
29420Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
29430Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
29440Sstevel@tonic-gate 		free(prop->name);
29450Sstevel@tonic-gate 		free(prop);
29460Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29470Sstevel@tonic-gate 	}
29480Sstevel@tonic-gate 
29490Sstevel@tonic-gate 	/*
29500Sstevel@tonic-gate 	 * make a copy of the property value
29510Sstevel@tonic-gate 	 */
29520Sstevel@tonic-gate 	prop->len = opp->oprom_size;
29530Sstevel@tonic-gate 
29540Sstevel@tonic-gate 	if (prop->len == 0)
29550Sstevel@tonic-gate 		prop->data = NULL;
29560Sstevel@tonic-gate 	else if ((prop->data = malloc(prop->len)) == NULL) {
29570Sstevel@tonic-gate 		free(prop->name);
29580Sstevel@tonic-gate 		free(prop);
29590Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29600Sstevel@tonic-gate 	}
29610Sstevel@tonic-gate 
29620Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
29630Sstevel@tonic-gate 
29640Sstevel@tonic-gate 	/*
29650Sstevel@tonic-gate 	 * Prepend prop to list in prom handle
29660Sstevel@tonic-gate 	 */
29670Sstevel@tonic-gate 	prop->next = p->list;
29680Sstevel@tonic-gate 	p->list = prop;
29690Sstevel@tonic-gate 
29700Sstevel@tonic-gate 	return ((di_prom_prop_t)prop);
29710Sstevel@tonic-gate }
29720Sstevel@tonic-gate 
29730Sstevel@tonic-gate di_prom_prop_t
di_prom_prop_next(di_prom_handle_t ph,di_node_t node,di_prom_prop_t prom_prop)29740Sstevel@tonic-gate di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
29750Sstevel@tonic-gate {
29760Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate 	DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
29796640Scth 	    node, p));
29800Sstevel@tonic-gate 
29810Sstevel@tonic-gate 	/*
29820Sstevel@tonic-gate 	 * paranoid check
29830Sstevel@tonic-gate 	 */
29840Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
29850Sstevel@tonic-gate 		errno = EINVAL;
29860Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29870Sstevel@tonic-gate 	}
29880Sstevel@tonic-gate 
29890Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
29900Sstevel@tonic-gate 		errno = ENXIO;
29910Sstevel@tonic-gate 		return (DI_PROM_PROP_NIL);
29920Sstevel@tonic-gate 	}
29930Sstevel@tonic-gate 
29940Sstevel@tonic-gate 	/*
29950Sstevel@tonic-gate 	 * synchronize access to prom file descriptor
29960Sstevel@tonic-gate 	 */
29970Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
29980Sstevel@tonic-gate 
29990Sstevel@tonic-gate 	/*
30000Sstevel@tonic-gate 	 * look for next property
30010Sstevel@tonic-gate 	 */
30020Sstevel@tonic-gate 	prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
30050Sstevel@tonic-gate 
30060Sstevel@tonic-gate 	return (prom_prop);
30070Sstevel@tonic-gate }
30080Sstevel@tonic-gate 
30090Sstevel@tonic-gate char *
di_prom_prop_name(di_prom_prop_t prom_prop)30100Sstevel@tonic-gate di_prom_prop_name(di_prom_prop_t prom_prop)
30110Sstevel@tonic-gate {
30120Sstevel@tonic-gate 	/*
30130Sstevel@tonic-gate 	 * paranoid check
30140Sstevel@tonic-gate 	 */
30150Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
30160Sstevel@tonic-gate 		errno = EINVAL;
30170Sstevel@tonic-gate 		return (NULL);
30180Sstevel@tonic-gate 	}
30190Sstevel@tonic-gate 
30200Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->name);
30210Sstevel@tonic-gate }
30220Sstevel@tonic-gate 
30230Sstevel@tonic-gate int
di_prom_prop_data(di_prom_prop_t prom_prop,uchar_t ** prom_prop_data)30240Sstevel@tonic-gate di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
30250Sstevel@tonic-gate {
30260Sstevel@tonic-gate 	/*
30270Sstevel@tonic-gate 	 * paranoid check
30280Sstevel@tonic-gate 	 */
30290Sstevel@tonic-gate 	if (prom_prop == DI_PROM_PROP_NIL) {
30300Sstevel@tonic-gate 		errno = EINVAL;
30310Sstevel@tonic-gate 		return (NULL);
30320Sstevel@tonic-gate 	}
30330Sstevel@tonic-gate 
30340Sstevel@tonic-gate 	*prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
30350Sstevel@tonic-gate 
30360Sstevel@tonic-gate 	return (((struct di_prom_prop *)prom_prop)->len);
30370Sstevel@tonic-gate }
30380Sstevel@tonic-gate 
30390Sstevel@tonic-gate /*
30400Sstevel@tonic-gate  * Internal library interface for locating the property
30410Sstevel@tonic-gate  *    Returns length if found, -1 if prop doesn't exist.
30420Sstevel@tonic-gate  */
30430Sstevel@tonic-gate static struct di_prom_prop *
di_prom_prop_lookup_common(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name)30440Sstevel@tonic-gate di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
30450Sstevel@tonic-gate 	const char *prom_prop_name)
30460Sstevel@tonic-gate {
30470Sstevel@tonic-gate 	struct openpromio *opp;
30480Sstevel@tonic-gate 	struct di_prom_prop *prop;
30490Sstevel@tonic-gate 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
30500Sstevel@tonic-gate 
30510Sstevel@tonic-gate 	/*
30520Sstevel@tonic-gate 	 * paranoid check
30530Sstevel@tonic-gate 	 */
30540Sstevel@tonic-gate 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
30550Sstevel@tonic-gate 		errno = EINVAL;
30560Sstevel@tonic-gate 		return (NULL);
30570Sstevel@tonic-gate 	}
30580Sstevel@tonic-gate 
30590Sstevel@tonic-gate 	if (di_nodeid(node) != DI_PROM_NODEID) {
30600Sstevel@tonic-gate 		errno = ENXIO;
30610Sstevel@tonic-gate 		return (NULL);
30620Sstevel@tonic-gate 	}
30630Sstevel@tonic-gate 
30640Sstevel@tonic-gate 	opp = &p->oppbuf.opp;
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate 	(void) mutex_lock(&p->lock);
30670Sstevel@tonic-gate 
30680Sstevel@tonic-gate 	opp->oprom_size = sizeof (int);
30690Sstevel@tonic-gate 	opp->oprom_node = DI_NODE(node)->nodeid;
30700Sstevel@tonic-gate 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
30710Sstevel@tonic-gate 		errno = ENXIO;
30720Sstevel@tonic-gate 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
30730Sstevel@tonic-gate 		    DI_NODE(node)->nodeid));
30740Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
30750Sstevel@tonic-gate 		return (NULL);
30760Sstevel@tonic-gate 	}
30770Sstevel@tonic-gate 
30780Sstevel@tonic-gate 	/*
30790Sstevel@tonic-gate 	 * get property length
30800Sstevel@tonic-gate 	 */
30810Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
30820Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
30830Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
30840Sstevel@tonic-gate 
30850Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
30860Sstevel@tonic-gate 	    (opp->oprom_len == -1)) {
30870Sstevel@tonic-gate 		/* no such property */
30880Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
30890Sstevel@tonic-gate 		return (NULL);
30900Sstevel@tonic-gate 	}
30910Sstevel@tonic-gate 
30920Sstevel@tonic-gate 	/*
30930Sstevel@tonic-gate 	 * Prom property found. Allocate struct for storing prop
30940Sstevel@tonic-gate 	 */
30950Sstevel@tonic-gate 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
30960Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
30970Sstevel@tonic-gate 		return (NULL);
30980Sstevel@tonic-gate 	}
30990Sstevel@tonic-gate 	prop->name = NULL;	/* we don't need the name */
31000Sstevel@tonic-gate 	prop->len = opp->oprom_len;
31010Sstevel@tonic-gate 
31020Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
31030Sstevel@tonic-gate 		prop->data = NULL;
31040Sstevel@tonic-gate 		prop->next = p->list;
31050Sstevel@tonic-gate 		p->list = prop;
31060Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
31070Sstevel@tonic-gate 		return (prop);
31080Sstevel@tonic-gate 	}
31090Sstevel@tonic-gate 
31100Sstevel@tonic-gate 	/*
31110Sstevel@tonic-gate 	 * retrieve the property value
31120Sstevel@tonic-gate 	 */
31130Sstevel@tonic-gate 	bzero(opp, OBP_MAXBUF);
31140Sstevel@tonic-gate 	opp->oprom_size = OBP_MAXPROPLEN;
31150Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_prop_name);
31160Sstevel@tonic-gate 
31170Sstevel@tonic-gate 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
31180Sstevel@tonic-gate 	    (opp->oprom_size == (uint_t)-1)) {
31190Sstevel@tonic-gate 		/* error retrieving property value */
31200Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
31210Sstevel@tonic-gate 		free(prop);
31220Sstevel@tonic-gate 		return (NULL);
31230Sstevel@tonic-gate 	}
31240Sstevel@tonic-gate 
31250Sstevel@tonic-gate 	/*
31260Sstevel@tonic-gate 	 * make a copy of the property value, stick in ph->list
31270Sstevel@tonic-gate 	 */
31280Sstevel@tonic-gate 	if ((prop->data = malloc(prop->len)) == NULL) {
31290Sstevel@tonic-gate 		(void) mutex_unlock(&p->lock);
31300Sstevel@tonic-gate 		free(prop);
31310Sstevel@tonic-gate 		return (NULL);
31320Sstevel@tonic-gate 	}
31330Sstevel@tonic-gate 
31340Sstevel@tonic-gate 	bcopy(opp->oprom_array, prop->data, prop->len);
31350Sstevel@tonic-gate 
31360Sstevel@tonic-gate 	prop->next = p->list;
31370Sstevel@tonic-gate 	p->list = prop;
31380Sstevel@tonic-gate 	(void) mutex_unlock(&p->lock);
31390Sstevel@tonic-gate 
31400Sstevel@tonic-gate 	return (prop);
31410Sstevel@tonic-gate }
31420Sstevel@tonic-gate 
31430Sstevel@tonic-gate int
di_prom_prop_lookup_ints(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name,int ** prom_prop_data)31440Sstevel@tonic-gate di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
31450Sstevel@tonic-gate 	const char *prom_prop_name, int **prom_prop_data)
31460Sstevel@tonic-gate {
31470Sstevel@tonic-gate 	int len;
31480Sstevel@tonic-gate 	struct di_prom_prop *prop;
31490Sstevel@tonic-gate 
31500Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
31510Sstevel@tonic-gate 
31520Sstevel@tonic-gate 	if (prop == NULL) {
31530Sstevel@tonic-gate 		*prom_prop_data = NULL;
31540Sstevel@tonic-gate 		return (-1);
31550Sstevel@tonic-gate 	}
31560Sstevel@tonic-gate 
31570Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
31580Sstevel@tonic-gate 		*prom_prop_data = NULL;
31590Sstevel@tonic-gate 		return (0);
31600Sstevel@tonic-gate 	}
31610Sstevel@tonic-gate 
31620Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
31636640Scth 	    DI_PROP_TYPE_INT, 1);
31640Sstevel@tonic-gate 	*prom_prop_data = (int *)((void *)prop->data);
31650Sstevel@tonic-gate 
31660Sstevel@tonic-gate 	return (len);
31670Sstevel@tonic-gate }
31680Sstevel@tonic-gate 
31690Sstevel@tonic-gate int
di_prom_prop_lookup_strings(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name,char ** prom_prop_data)31700Sstevel@tonic-gate di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
31710Sstevel@tonic-gate 	const char *prom_prop_name, char **prom_prop_data)
31720Sstevel@tonic-gate {
31730Sstevel@tonic-gate 	int len;
31740Sstevel@tonic-gate 	struct di_prom_prop *prop;
31750Sstevel@tonic-gate 
31760Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
31770Sstevel@tonic-gate 
31780Sstevel@tonic-gate 	if (prop == NULL) {
31790Sstevel@tonic-gate 		*prom_prop_data = NULL;
31800Sstevel@tonic-gate 		return (-1);
31810Sstevel@tonic-gate 	}
31820Sstevel@tonic-gate 
31830Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
31840Sstevel@tonic-gate 		*prom_prop_data = NULL;
31850Sstevel@tonic-gate 		return (0);
31860Sstevel@tonic-gate 	}
31870Sstevel@tonic-gate 
31880Sstevel@tonic-gate 	/*
31890Sstevel@tonic-gate 	 * Fix an openprom bug (OBP string not NULL terminated).
31900Sstevel@tonic-gate 	 * XXX This should really be fixed in promif.
31910Sstevel@tonic-gate 	 */
31920Sstevel@tonic-gate 	if (((char *)prop->data)[prop->len - 1] != '\0') {
31930Sstevel@tonic-gate 		uchar_t *tmp;
31940Sstevel@tonic-gate 		prop->len++;
31950Sstevel@tonic-gate 		if ((tmp = realloc(prop->data, prop->len)) == NULL)
31960Sstevel@tonic-gate 			return (-1);
31970Sstevel@tonic-gate 
31980Sstevel@tonic-gate 		prop->data = tmp;
31990Sstevel@tonic-gate 		((char *)prop->data)[prop->len - 1] = '\0';
32000Sstevel@tonic-gate 		DPRINTF((DI_INFO, "OBP string not NULL terminated: "
32010Sstevel@tonic-gate 		    "node=%s, prop=%s, val=%s\n",
32020Sstevel@tonic-gate 		    di_node_name(node), prom_prop_name, prop->data));
32030Sstevel@tonic-gate 	}
32040Sstevel@tonic-gate 
32050Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
32060Sstevel@tonic-gate 	    DI_PROP_TYPE_STRING, 1);
32070Sstevel@tonic-gate 	*prom_prop_data = (char *)prop->data;
32080Sstevel@tonic-gate 
32090Sstevel@tonic-gate 	return (len);
32100Sstevel@tonic-gate }
32110Sstevel@tonic-gate 
32120Sstevel@tonic-gate int
di_prom_prop_lookup_bytes(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name,uchar_t ** prom_prop_data)32130Sstevel@tonic-gate di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
32140Sstevel@tonic-gate 	const char *prom_prop_name, uchar_t **prom_prop_data)
32150Sstevel@tonic-gate {
32160Sstevel@tonic-gate 	int len;
32170Sstevel@tonic-gate 	struct di_prom_prop *prop;
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
32200Sstevel@tonic-gate 
32210Sstevel@tonic-gate 	if (prop == NULL) {
32220Sstevel@tonic-gate 		*prom_prop_data = NULL;
32230Sstevel@tonic-gate 		return (-1);
32240Sstevel@tonic-gate 	}
32250Sstevel@tonic-gate 
32260Sstevel@tonic-gate 	if (prop->len == 0) {	/* boolean property */
32270Sstevel@tonic-gate 		*prom_prop_data = NULL;
32280Sstevel@tonic-gate 		return (0);
32290Sstevel@tonic-gate 	}
32300Sstevel@tonic-gate 
32310Sstevel@tonic-gate 	len = di_prop_decode_common((void *)&prop->data, prop->len,
32320Sstevel@tonic-gate 	    DI_PROP_TYPE_BYTE, 1);
32330Sstevel@tonic-gate 	*prom_prop_data = prop->data;
32340Sstevel@tonic-gate 
32350Sstevel@tonic-gate 	return (len);
32360Sstevel@tonic-gate }
32370Sstevel@tonic-gate 
32383814Sjveta /*
32393814Sjveta  * returns an allocated array through <prop_data> only when its count > 0
32403814Sjveta  * and the number of entries (count) as the function return value;
32413814Sjveta  * use di_slot_names_free() to free the array
32423814Sjveta  */
32433814Sjveta int
di_prop_slot_names(di_prop_t prop,di_slot_name_t ** prop_data)32443814Sjveta di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
32453814Sjveta {
32463814Sjveta 	int rawlen, count;
32473814Sjveta 	uchar_t *rawdata;
32483814Sjveta 	char *nm = di_prop_name(prop);
32493814Sjveta 
32503814Sjveta 	if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
32513814Sjveta 		goto ERROUT;
32523814Sjveta 
32533814Sjveta 	rawlen = di_prop_rawdata(prop, &rawdata);
32543814Sjveta 	if (rawlen <= 0 || rawdata == NULL)
32553814Sjveta 		goto ERROUT;
32563814Sjveta 
32573814Sjveta 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
32583814Sjveta 	if (count < 0 || *prop_data == NULL)
32593814Sjveta 		goto ERROUT;
32603814Sjveta 
32613814Sjveta 	return (count);
32623814Sjveta 	/*NOTREACHED*/
32633814Sjveta ERROUT:
32643814Sjveta 	errno = EFAULT;
32653814Sjveta 	*prop_data = NULL;
32663814Sjveta 	return (-1);
32673814Sjveta }
32683814Sjveta 
32693814Sjveta int
di_prop_lookup_slot_names(dev_t dev,di_node_t node,di_slot_name_t ** prop_data)32703814Sjveta di_prop_lookup_slot_names(dev_t dev, di_node_t node,
32713814Sjveta     di_slot_name_t **prop_data)
32723814Sjveta {
32733814Sjveta 	di_prop_t prop;
32743814Sjveta 
32753814Sjveta 	/*
32763814Sjveta 	 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
32773814Sjveta 	 * and slot-names is properly flagged as such
32783814Sjveta 	 */
32793814Sjveta 	if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
32803814Sjveta 	    DI_PROP_NIL) {
32813814Sjveta 		*prop_data = NULL;
32823814Sjveta 		return (-1);
32833814Sjveta 	}
32843814Sjveta 
32853814Sjveta 	return (di_prop_slot_names(prop, (void *)prop_data));
32863814Sjveta }
32873814Sjveta 
32883814Sjveta /*
32893814Sjveta  * returns an allocated array through <prop_data> only when its count > 0
32903814Sjveta  * and the number of entries (count) as the function return value;
32913814Sjveta  * use di_slot_names_free() to free the array
32923814Sjveta  */
32933814Sjveta int
di_prom_prop_slot_names(di_prom_prop_t prom_prop,di_slot_name_t ** prop_data)32943814Sjveta di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
32953814Sjveta {
32963814Sjveta 	int rawlen, count;
32973814Sjveta 	uchar_t *rawdata;
32983814Sjveta 
32993814Sjveta 	rawlen = di_prom_prop_data(prom_prop, &rawdata);
33003814Sjveta 	if (rawlen <= 0 || rawdata == NULL)
33013814Sjveta 		goto ERROUT;
33023814Sjveta 
33033814Sjveta 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
33043814Sjveta 	if (count < 0 || *prop_data == NULL)
33053814Sjveta 		goto ERROUT;
33063814Sjveta 
33073814Sjveta 	return (count);
33083814Sjveta 	/*NOTREACHED*/
33093814Sjveta ERROUT:
33103814Sjveta 	errno = EFAULT;
33113814Sjveta 	*prop_data = NULL;
33123814Sjveta 	return (-1);
33133814Sjveta }
33143814Sjveta 
33153814Sjveta int
di_prom_prop_lookup_slot_names(di_prom_handle_t ph,di_node_t node,di_slot_name_t ** prop_data)33163814Sjveta di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
33173814Sjveta     di_slot_name_t **prop_data)
33183814Sjveta {
33193814Sjveta 	struct di_prom_prop *prom_prop;
33203814Sjveta 
33213814Sjveta 	prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
33223814Sjveta 	if (prom_prop == NULL) {
33233814Sjveta 		*prop_data = NULL;
33243814Sjveta 		return (-1);
33253814Sjveta 	}
33263814Sjveta 
33273814Sjveta 	return (di_prom_prop_slot_names(prom_prop, prop_data));
33283814Sjveta }
33293814Sjveta 
33300Sstevel@tonic-gate di_lnode_t
di_link_to_lnode(di_link_t link,uint_t endpoint)33310Sstevel@tonic-gate di_link_to_lnode(di_link_t link, uint_t endpoint)
33320Sstevel@tonic-gate {
33330Sstevel@tonic-gate 	struct di_all *di_all;
33340Sstevel@tonic-gate 
33350Sstevel@tonic-gate 	if ((link == DI_LINK_NIL) ||
33360Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
33370Sstevel@tonic-gate 		errno = EINVAL;
33380Sstevel@tonic-gate 		return (DI_LNODE_NIL);
33390Sstevel@tonic-gate 	}
33400Sstevel@tonic-gate 
33410Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
33420Sstevel@tonic-gate 
33430Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
33440Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
33450Sstevel@tonic-gate 	} else {
33460Sstevel@tonic-gate 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
33470Sstevel@tonic-gate 	}
33480Sstevel@tonic-gate 	/* NOTREACHED */
33490Sstevel@tonic-gate }
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate char *
di_lnode_name(di_lnode_t lnode)33520Sstevel@tonic-gate di_lnode_name(di_lnode_t lnode)
33530Sstevel@tonic-gate {
33540Sstevel@tonic-gate 	return (di_driver_name(di_lnode_devinfo(lnode)));
33550Sstevel@tonic-gate }
33560Sstevel@tonic-gate 
33570Sstevel@tonic-gate di_node_t
di_lnode_devinfo(di_lnode_t lnode)33580Sstevel@tonic-gate di_lnode_devinfo(di_lnode_t lnode)
33590Sstevel@tonic-gate {
33600Sstevel@tonic-gate 	struct di_all *di_all;
33610Sstevel@tonic-gate 
33620Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
33630Sstevel@tonic-gate 	return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
33640Sstevel@tonic-gate }
33650Sstevel@tonic-gate 
33660Sstevel@tonic-gate int
di_lnode_devt(di_lnode_t lnode,dev_t * devt)33670Sstevel@tonic-gate di_lnode_devt(di_lnode_t lnode, dev_t *devt)
33680Sstevel@tonic-gate {
33690Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
33700Sstevel@tonic-gate 		errno = EINVAL;
33710Sstevel@tonic-gate 		return (-1);
33720Sstevel@tonic-gate 	}
33730Sstevel@tonic-gate 	if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
33740Sstevel@tonic-gate 	    (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
33750Sstevel@tonic-gate 		return (-1);
33760Sstevel@tonic-gate 
33770Sstevel@tonic-gate 	*devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
33780Sstevel@tonic-gate 	return (0);
33790Sstevel@tonic-gate }
33800Sstevel@tonic-gate 
33810Sstevel@tonic-gate int
di_link_spectype(di_link_t link)33820Sstevel@tonic-gate di_link_spectype(di_link_t link)
33830Sstevel@tonic-gate {
33840Sstevel@tonic-gate 	return (DI_LINK(link)->spec_type);
33850Sstevel@tonic-gate }
33860Sstevel@tonic-gate 
33870Sstevel@tonic-gate void
di_minor_private_set(di_minor_t minor,void * data)33880Sstevel@tonic-gate di_minor_private_set(di_minor_t minor, void *data)
33890Sstevel@tonic-gate {
33900Sstevel@tonic-gate 	DI_MINOR(minor)->user_private_data = (uintptr_t)data;
33910Sstevel@tonic-gate }
33920Sstevel@tonic-gate 
33930Sstevel@tonic-gate void *
di_minor_private_get(di_minor_t minor)33940Sstevel@tonic-gate di_minor_private_get(di_minor_t minor)
33950Sstevel@tonic-gate {
3396352Sanish 	return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
33970Sstevel@tonic-gate }
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate void
di_node_private_set(di_node_t node,void * data)34000Sstevel@tonic-gate di_node_private_set(di_node_t node, void *data)
34010Sstevel@tonic-gate {
34020Sstevel@tonic-gate 	DI_NODE(node)->user_private_data = (uintptr_t)data;
34030Sstevel@tonic-gate }
34040Sstevel@tonic-gate 
34050Sstevel@tonic-gate void *
di_node_private_get(di_node_t node)34060Sstevel@tonic-gate di_node_private_get(di_node_t node)
34070Sstevel@tonic-gate {
3408352Sanish 	return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
34090Sstevel@tonic-gate }
34100Sstevel@tonic-gate 
34110Sstevel@tonic-gate void
di_path_private_set(di_path_t path,void * data)34126640Scth di_path_private_set(di_path_t path, void *data)
34136640Scth {
34146640Scth 	DI_PATH(path)->user_private_data = (uintptr_t)data;
34156640Scth }
34166640Scth 
34176640Scth void *
di_path_private_get(di_path_t path)34186640Scth di_path_private_get(di_path_t path)
34196640Scth {
34206640Scth 	return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
34216640Scth }
34226640Scth 
34236640Scth void
di_lnode_private_set(di_lnode_t lnode,void * data)34240Sstevel@tonic-gate di_lnode_private_set(di_lnode_t lnode, void *data)
34250Sstevel@tonic-gate {
34260Sstevel@tonic-gate 	DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
34270Sstevel@tonic-gate }
34280Sstevel@tonic-gate 
34290Sstevel@tonic-gate void *
di_lnode_private_get(di_lnode_t lnode)34300Sstevel@tonic-gate di_lnode_private_get(di_lnode_t lnode)
34310Sstevel@tonic-gate {
3432352Sanish 	return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
34330Sstevel@tonic-gate }
34340Sstevel@tonic-gate 
34350Sstevel@tonic-gate void
di_link_private_set(di_link_t link,void * data)34360Sstevel@tonic-gate di_link_private_set(di_link_t link, void *data)
34370Sstevel@tonic-gate {
34380Sstevel@tonic-gate 	DI_LINK(link)->user_private_data = (uintptr_t)data;
34390Sstevel@tonic-gate }
34400Sstevel@tonic-gate 
34410Sstevel@tonic-gate void *
di_link_private_get(di_link_t link)34420Sstevel@tonic-gate di_link_private_get(di_link_t link)
34430Sstevel@tonic-gate {
3444352Sanish 	return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
34450Sstevel@tonic-gate }
34460Sstevel@tonic-gate 
34470Sstevel@tonic-gate di_lnode_t
di_lnode_next(di_node_t node,di_lnode_t lnode)34480Sstevel@tonic-gate di_lnode_next(di_node_t node, di_lnode_t lnode)
34490Sstevel@tonic-gate {
34500Sstevel@tonic-gate 	struct di_all *di_all;
34510Sstevel@tonic-gate 
34520Sstevel@tonic-gate 	/*
34530Sstevel@tonic-gate 	 * paranoid error checking
34540Sstevel@tonic-gate 	 */
34550Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
34560Sstevel@tonic-gate 		errno = EINVAL;
34570Sstevel@tonic-gate 		return (DI_LNODE_NIL);
34580Sstevel@tonic-gate 	}
34590Sstevel@tonic-gate 
34600Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
34610Sstevel@tonic-gate 
34620Sstevel@tonic-gate 	if (lnode == DI_NODE_NIL) {
34630Sstevel@tonic-gate 		if (DI_NODE(node)->lnodes != NULL)
34640Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
34650Sstevel@tonic-gate 			    DI_NODE(node)->lnodes));
34660Sstevel@tonic-gate 	} else {
34670Sstevel@tonic-gate 		if (DI_LNODE(lnode)->node_next != NULL)
34680Sstevel@tonic-gate 			return (DI_LNODE((caddr_t)di_all +
34690Sstevel@tonic-gate 			    DI_LNODE(lnode)->node_next));
34700Sstevel@tonic-gate 	}
34710Sstevel@tonic-gate 
34720Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
34730Sstevel@tonic-gate 		errno = ENXIO;
34740Sstevel@tonic-gate 	else
34750Sstevel@tonic-gate 		errno = ENOTSUP;
34760Sstevel@tonic-gate 
34770Sstevel@tonic-gate 	return (DI_LNODE_NIL);
34780Sstevel@tonic-gate }
34790Sstevel@tonic-gate 
34800Sstevel@tonic-gate di_link_t
di_link_next_by_node(di_node_t node,di_link_t link,uint_t endpoint)34810Sstevel@tonic-gate di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
34820Sstevel@tonic-gate {
34830Sstevel@tonic-gate 	struct di_all *di_all;
34840Sstevel@tonic-gate 
34850Sstevel@tonic-gate 	/*
34860Sstevel@tonic-gate 	 * paranoid error checking
34870Sstevel@tonic-gate 	 */
34880Sstevel@tonic-gate 	if ((node == DI_NODE_NIL) ||
34890Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
34900Sstevel@tonic-gate 		errno = EINVAL;
34910Sstevel@tonic-gate 		return (DI_LINK_NIL);
34920Sstevel@tonic-gate 	}
34930Sstevel@tonic-gate 
34940Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
34950Sstevel@tonic-gate 
34960Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
34970Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
34980Sstevel@tonic-gate 			if (DI_NODE(node)->src_links != NULL)
34990Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35000Sstevel@tonic-gate 				    DI_NODE(node)->src_links));
35010Sstevel@tonic-gate 		} else {
35020Sstevel@tonic-gate 			if (DI_LINK(link)->src_node_next != NULL)
35030Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35040Sstevel@tonic-gate 				    DI_LINK(link)->src_node_next));
35050Sstevel@tonic-gate 		}
35060Sstevel@tonic-gate 	} else {
35070Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
35080Sstevel@tonic-gate 			if (DI_NODE(node)->tgt_links != NULL)
35090Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35100Sstevel@tonic-gate 				    DI_NODE(node)->tgt_links));
35110Sstevel@tonic-gate 		} else {
35120Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_node_next != NULL)
35130Sstevel@tonic-gate 				return (DI_LINK((caddr_t)di_all +
35140Sstevel@tonic-gate 				    DI_LINK(link)->tgt_node_next));
35150Sstevel@tonic-gate 		}
35160Sstevel@tonic-gate 	}
35170Sstevel@tonic-gate 
35180Sstevel@tonic-gate 	if (DINFOLYR & DI_ALL(di_all)->command)
35190Sstevel@tonic-gate 		errno = ENXIO;
35200Sstevel@tonic-gate 	else
35210Sstevel@tonic-gate 		errno = ENOTSUP;
35220Sstevel@tonic-gate 
35230Sstevel@tonic-gate 	return (DI_LINK_NIL);
35240Sstevel@tonic-gate }
35250Sstevel@tonic-gate 
35260Sstevel@tonic-gate di_link_t
di_link_next_by_lnode(di_lnode_t lnode,di_link_t link,uint_t endpoint)35270Sstevel@tonic-gate di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
35280Sstevel@tonic-gate {
35290Sstevel@tonic-gate 	struct di_all *di_all;
35300Sstevel@tonic-gate 
35310Sstevel@tonic-gate 	/*
35320Sstevel@tonic-gate 	 * paranoid error checking
35330Sstevel@tonic-gate 	 */
35340Sstevel@tonic-gate 	if ((lnode == DI_LNODE_NIL) ||
35350Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
35360Sstevel@tonic-gate 		errno = EINVAL;
35370Sstevel@tonic-gate 		return (DI_LINK_NIL);
35380Sstevel@tonic-gate 	}
35390Sstevel@tonic-gate 
35400Sstevel@tonic-gate 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
35410Sstevel@tonic-gate 
35420Sstevel@tonic-gate 	if (endpoint == DI_LINK_SRC) {
35430Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
35440Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_out == NULL)
35450Sstevel@tonic-gate 				return (DI_LINK_NIL);
35460Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35476640Scth 			    DI_LNODE(lnode)->link_out));
35480Sstevel@tonic-gate 		} else {
35490Sstevel@tonic-gate 			if (DI_LINK(link)->src_link_next == NULL)
35500Sstevel@tonic-gate 				return (DI_LINK_NIL);
35510Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35526640Scth 			    DI_LINK(link)->src_link_next));
35530Sstevel@tonic-gate 		}
35540Sstevel@tonic-gate 	} else {
35550Sstevel@tonic-gate 		if (link == DI_LINK_NIL) {
35560Sstevel@tonic-gate 			if (DI_LNODE(lnode)->link_in == NULL)
35570Sstevel@tonic-gate 				return (DI_LINK_NIL);
35580Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35596640Scth 			    DI_LNODE(lnode)->link_in));
35600Sstevel@tonic-gate 		} else {
35610Sstevel@tonic-gate 			if (DI_LINK(link)->tgt_link_next == NULL)
35620Sstevel@tonic-gate 				return (DI_LINK_NIL);
35630Sstevel@tonic-gate 			return (DI_LINK((caddr_t)di_all +
35646640Scth 			    DI_LINK(link)->tgt_link_next));
35650Sstevel@tonic-gate 		}
35660Sstevel@tonic-gate 	}
35670Sstevel@tonic-gate 	/* NOTREACHED */
35680Sstevel@tonic-gate }
35690Sstevel@tonic-gate 
35700Sstevel@tonic-gate /*
35710Sstevel@tonic-gate  * Internal library function:
35720Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
35730Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
35740Sstevel@tonic-gate  *
35750Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
35760Sstevel@tonic-gate  *   first mode.
35770Sstevel@tonic-gate  */
35780Sstevel@tonic-gate static void
walk_one_link(struct node_list ** headp,uint_t ep,void * arg,int (* callback)(di_link_t link,void * arg))35790Sstevel@tonic-gate walk_one_link(struct node_list **headp, uint_t ep,
35800Sstevel@tonic-gate     void *arg, int (*callback)(di_link_t link, void *arg))
35810Sstevel@tonic-gate {
35820Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
35830Sstevel@tonic-gate 	di_link_t	link = DI_LINK_NIL;
35840Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
35850Sstevel@tonic-gate 
35860Sstevel@tonic-gate 	while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
35870Sstevel@tonic-gate 		action = callback(link, arg);
35880Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
35890Sstevel@tonic-gate 			break;
35900Sstevel@tonic-gate 		}
35910Sstevel@tonic-gate 	}
35920Sstevel@tonic-gate 
35930Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
35940Sstevel@tonic-gate }
35950Sstevel@tonic-gate 
35960Sstevel@tonic-gate int
di_walk_link(di_node_t root,uint_t flag,uint_t endpoint,void * arg,int (* link_callback)(di_link_t link,void * arg))35970Sstevel@tonic-gate di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
35980Sstevel@tonic-gate     int (*link_callback)(di_link_t link, void *arg))
35990Sstevel@tonic-gate {
36000Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
36010Sstevel@tonic-gate 
36020Sstevel@tonic-gate #ifdef DEBUG
36036640Scth 	char *devfspath = di_devfs_path(root);
36040Sstevel@tonic-gate 	DPRINTF((DI_INFO, "walking %s link data under %s\n",
36056640Scth 	    (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
36066640Scth 	di_devfs_path_free(devfspath);
36070Sstevel@tonic-gate #endif
36080Sstevel@tonic-gate 
36090Sstevel@tonic-gate 	/*
36100Sstevel@tonic-gate 	 * paranoid error checking
36110Sstevel@tonic-gate 	 */
36120Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
36130Sstevel@tonic-gate 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
36140Sstevel@tonic-gate 		errno = EINVAL;
36150Sstevel@tonic-gate 		return (-1);
36160Sstevel@tonic-gate 	}
36170Sstevel@tonic-gate 
36180Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
36190Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
36200Sstevel@tonic-gate 		return (-1);
36210Sstevel@tonic-gate 	}
36220Sstevel@tonic-gate 
36230Sstevel@tonic-gate 	head->next = NULL;
36240Sstevel@tonic-gate 	head->node = root;
36250Sstevel@tonic-gate 
36260Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start link data walking from node %s\n",
36276640Scth 	    di_node_name(root)));
36280Sstevel@tonic-gate 
36290Sstevel@tonic-gate 	while (head != NULL)
36300Sstevel@tonic-gate 		walk_one_link(&head, endpoint, arg, link_callback);
36310Sstevel@tonic-gate 
36320Sstevel@tonic-gate 	return (0);
36330Sstevel@tonic-gate }
36340Sstevel@tonic-gate 
36350Sstevel@tonic-gate /*
36360Sstevel@tonic-gate  * Internal library function:
36370Sstevel@tonic-gate  *   Invoke callback for each link data on the link list of first node
36380Sstevel@tonic-gate  *   on node_list headp, and place children of first node on the list.
36390Sstevel@tonic-gate  *
36400Sstevel@tonic-gate  *   This is similar to walk_one_node, except we only walk in child
36410Sstevel@tonic-gate  *   first mode.
36420Sstevel@tonic-gate  */
36430Sstevel@tonic-gate static void
walk_one_lnode(struct node_list ** headp,void * arg,int (* callback)(di_lnode_t lnode,void * arg))36440Sstevel@tonic-gate walk_one_lnode(struct node_list **headp, void *arg,
36450Sstevel@tonic-gate     int (*callback)(di_lnode_t lnode, void *arg))
36460Sstevel@tonic-gate {
36470Sstevel@tonic-gate 	int		action = DI_WALK_CONTINUE;
36480Sstevel@tonic-gate 	di_lnode_t	lnode = DI_LNODE_NIL;
36490Sstevel@tonic-gate 	di_node_t	node = (*headp)->node;
36500Sstevel@tonic-gate 
36510Sstevel@tonic-gate 	while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
36520Sstevel@tonic-gate 		action = callback(lnode, arg);
36530Sstevel@tonic-gate 		if (action == DI_WALK_TERMINATE) {
36540Sstevel@tonic-gate 			break;
36550Sstevel@tonic-gate 		}
36560Sstevel@tonic-gate 	}
36570Sstevel@tonic-gate 
36580Sstevel@tonic-gate 	update_node_list(action, DI_WALK_LINKGEN, headp);
36590Sstevel@tonic-gate }
36600Sstevel@tonic-gate 
36610Sstevel@tonic-gate int
di_walk_lnode(di_node_t root,uint_t flag,void * arg,int (* lnode_callback)(di_lnode_t lnode,void * arg))36620Sstevel@tonic-gate di_walk_lnode(di_node_t root, uint_t flag, void *arg,
36630Sstevel@tonic-gate     int (*lnode_callback)(di_lnode_t lnode, void *arg))
36640Sstevel@tonic-gate {
36650Sstevel@tonic-gate 	struct node_list  *head;	/* node_list for tree walk */
36660Sstevel@tonic-gate 
36670Sstevel@tonic-gate #ifdef DEBUG
36686640Scth 	char *devfspath = di_devfs_path(root);
36696640Scth 	DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
36706640Scth 	di_devfs_path_free(devfspath);
36710Sstevel@tonic-gate #endif
36720Sstevel@tonic-gate 
36730Sstevel@tonic-gate 	/*
36740Sstevel@tonic-gate 	 * paranoid error checking
36750Sstevel@tonic-gate 	 */
36760Sstevel@tonic-gate 	if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
36770Sstevel@tonic-gate 		errno = EINVAL;
36780Sstevel@tonic-gate 		return (-1);
36790Sstevel@tonic-gate 	}
36800Sstevel@tonic-gate 
36810Sstevel@tonic-gate 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
36820Sstevel@tonic-gate 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
36830Sstevel@tonic-gate 		return (-1);
36840Sstevel@tonic-gate 	}
36850Sstevel@tonic-gate 
36860Sstevel@tonic-gate 	head->next = NULL;
36870Sstevel@tonic-gate 	head->node = root;
36880Sstevel@tonic-gate 
36890Sstevel@tonic-gate 	DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
36906640Scth 	    di_node_name(root)));
36910Sstevel@tonic-gate 
36920Sstevel@tonic-gate 	while (head != NULL)
36930Sstevel@tonic-gate 		walk_one_lnode(&head, arg, lnode_callback);
36940Sstevel@tonic-gate 
36950Sstevel@tonic-gate 	return (0);
36960Sstevel@tonic-gate }
36970Sstevel@tonic-gate 
369812116SVikram.Hegde@Sun.COM static char *
alias_to_curr(di_node_t anynode,char * devfspath,di_node_t * nodep)369912116SVikram.Hegde@Sun.COM alias_to_curr(di_node_t anynode, char *devfspath, di_node_t *nodep)
370012116SVikram.Hegde@Sun.COM {
370112116SVikram.Hegde@Sun.COM 	caddr_t		pa;
370212116SVikram.Hegde@Sun.COM 	struct di_all	*all;
370312116SVikram.Hegde@Sun.COM 	struct di_alias *di_alias;
370412116SVikram.Hegde@Sun.COM 	di_node_t	node;
370512116SVikram.Hegde@Sun.COM 	char		*curr;
370612116SVikram.Hegde@Sun.COM 	char		*cp;
370712116SVikram.Hegde@Sun.COM 	char		*alias;
370812116SVikram.Hegde@Sun.COM 	di_off_t off;
370912116SVikram.Hegde@Sun.COM 	char buf[MAXPATHLEN];
371012116SVikram.Hegde@Sun.COM 
371112116SVikram.Hegde@Sun.COM 	*nodep = NULL;
371212116SVikram.Hegde@Sun.COM 
3713*12270SJerry.Gilliam@Sun.COM 	if (anynode == DI_NODE_NIL || devfspath == NULL)
3714*12270SJerry.Gilliam@Sun.COM 		return (NULL);
371512116SVikram.Hegde@Sun.COM 
371612116SVikram.Hegde@Sun.COM 	pa = (caddr_t)anynode - DI_NODE(anynode)->self;
371712116SVikram.Hegde@Sun.COM 	all = DI_ALL(pa);
371812116SVikram.Hegde@Sun.COM 
371912116SVikram.Hegde@Sun.COM 	di_alias = NULL;
372012116SVikram.Hegde@Sun.COM 	for (off = all->aliases; off > 0; off = di_alias->next) {
372112116SVikram.Hegde@Sun.COM 		di_alias = DI_ALIAS(pa + off);
372212116SVikram.Hegde@Sun.COM 		alias = di_alias->alias;
372312116SVikram.Hegde@Sun.COM 		if (strncmp(devfspath, alias, strlen(alias)) == 0) {
372412116SVikram.Hegde@Sun.COM 			cp = devfspath + strlen(alias);
372512116SVikram.Hegde@Sun.COM 			node = DI_NODE(pa + di_alias->curroff);
372612116SVikram.Hegde@Sun.COM 			assert(node != DI_NODE_NIL);
372712116SVikram.Hegde@Sun.COM 			if (*cp == '\0') {
372812116SVikram.Hegde@Sun.COM 				*nodep = node;
372912116SVikram.Hegde@Sun.COM 				return (NULL);
373012116SVikram.Hegde@Sun.COM 			} else if (*cp == '/') {
373112116SVikram.Hegde@Sun.COM 				curr = di_devfs_path(node);
373212116SVikram.Hegde@Sun.COM 				(void) snprintf(buf, sizeof (buf), "%s%s",
373312116SVikram.Hegde@Sun.COM 				    curr, cp);
373412116SVikram.Hegde@Sun.COM 				di_devfs_path_free(curr);
373512116SVikram.Hegde@Sun.COM 				curr = strdup(buf);
373612116SVikram.Hegde@Sun.COM 				return (curr);
373712116SVikram.Hegde@Sun.COM 			}
373812116SVikram.Hegde@Sun.COM 		}
373912116SVikram.Hegde@Sun.COM 	}
374012116SVikram.Hegde@Sun.COM 
374112116SVikram.Hegde@Sun.COM 	return (NULL);
374212116SVikram.Hegde@Sun.COM }
374312116SVikram.Hegde@Sun.COM 
374412116SVikram.Hegde@Sun.COM static di_node_t
di_lookup_node_impl(di_node_t root,char * devfspath)374512116SVikram.Hegde@Sun.COM di_lookup_node_impl(di_node_t root, char *devfspath)
37460Sstevel@tonic-gate {
37470Sstevel@tonic-gate 	struct di_all *dap;
37480Sstevel@tonic-gate 	di_node_t node;
37496640Scth 	char *copy, *slash, *pname, *paddr;
37500Sstevel@tonic-gate 
37510Sstevel@tonic-gate 	/*
37520Sstevel@tonic-gate 	 * Path must be absolute and musn't have duplicate slashes
37530Sstevel@tonic-gate 	 */
37546640Scth 	if (*devfspath != '/' || strstr(devfspath, "//")) {
37556640Scth 		DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
37560Sstevel@tonic-gate 		return (DI_NODE_NIL);
37570Sstevel@tonic-gate 	}
37580Sstevel@tonic-gate 
37590Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
37600Sstevel@tonic-gate 		DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
37610Sstevel@tonic-gate 		return (DI_NODE_NIL);
37620Sstevel@tonic-gate 	}
37630Sstevel@tonic-gate 
37640Sstevel@tonic-gate 	dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
37650Sstevel@tonic-gate 	if (strcmp(dap->root_path, "/") != 0) {
37660Sstevel@tonic-gate 		DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
37670Sstevel@tonic-gate 		return (DI_NODE_NIL);
37680Sstevel@tonic-gate 	}
37690Sstevel@tonic-gate 
37706640Scth 	if ((copy = strdup(devfspath)) == NULL) {
37716640Scth 		DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
37720Sstevel@tonic-gate 		return (DI_NODE_NIL);
37730Sstevel@tonic-gate 	}
37740Sstevel@tonic-gate 
37750Sstevel@tonic-gate 	for (slash = copy, node = root; slash; ) {
37760Sstevel@tonic-gate 
37770Sstevel@tonic-gate 		/*
37786640Scth 		 * Handle devfspath = "/" case as well as trailing '/'
37790Sstevel@tonic-gate 		 */
37800Sstevel@tonic-gate 		if (*(slash + 1) == '\0')
37810Sstevel@tonic-gate 			break;
37820Sstevel@tonic-gate 
37830Sstevel@tonic-gate 		/*
37840Sstevel@tonic-gate 		 * More path-components exist. Deal with the next one
37850Sstevel@tonic-gate 		 */
37860Sstevel@tonic-gate 		pname = slash + 1;
37870Sstevel@tonic-gate 		node = di_child_node(node);
37880Sstevel@tonic-gate 
37890Sstevel@tonic-gate 		if (slash = strchr(pname, '/'))
37900Sstevel@tonic-gate 			*slash = '\0';
37910Sstevel@tonic-gate 		if (paddr = strchr(pname, '@'))
37920Sstevel@tonic-gate 			*paddr++ = '\0';
37930Sstevel@tonic-gate 
37940Sstevel@tonic-gate 		for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
37950Sstevel@tonic-gate 			char *name, *baddr;
37960Sstevel@tonic-gate 
37970Sstevel@tonic-gate 			name = di_node_name(node);
37980Sstevel@tonic-gate 			baddr = di_bus_addr(node);
37990Sstevel@tonic-gate 
38000Sstevel@tonic-gate 			if (strcmp(pname, name) != 0)
38010Sstevel@tonic-gate 				continue;
38020Sstevel@tonic-gate 
38030Sstevel@tonic-gate 			/*
38040Sstevel@tonic-gate 			 * Mappings between a "path-address" and bus-addr
38050Sstevel@tonic-gate 			 *
38060Sstevel@tonic-gate 			 *	paddr		baddr
38070Sstevel@tonic-gate 			 *	---------------------
38080Sstevel@tonic-gate 			 *	NULL		NULL
38090Sstevel@tonic-gate 			 *	NULL		""
38100Sstevel@tonic-gate 			 *	""		N/A	(invalid paddr)
38110Sstevel@tonic-gate 			 */
38120Sstevel@tonic-gate 			if (paddr && baddr && strcmp(paddr, baddr) == 0)
38130Sstevel@tonic-gate 				break;
38140Sstevel@tonic-gate 			if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
38150Sstevel@tonic-gate 				break;
38160Sstevel@tonic-gate 		}
38170Sstevel@tonic-gate 
38180Sstevel@tonic-gate 		/*
38190Sstevel@tonic-gate 		 * No nodes in the sibling list or there was no match
38200Sstevel@tonic-gate 		 */
38210Sstevel@tonic-gate 		if (node == DI_NODE_NIL) {
38220Sstevel@tonic-gate 			DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
38236640Scth 			free(copy);
38240Sstevel@tonic-gate 			return (DI_NODE_NIL);
38250Sstevel@tonic-gate 		}
38260Sstevel@tonic-gate 	}
38270Sstevel@tonic-gate 
38280Sstevel@tonic-gate 	assert(node != DI_NODE_NIL);
38296640Scth 	free(copy);
38300Sstevel@tonic-gate 	return (node);
38310Sstevel@tonic-gate }
38320Sstevel@tonic-gate 
383312116SVikram.Hegde@Sun.COM di_node_t
di_lookup_node(di_node_t root,char * devfspath)383412116SVikram.Hegde@Sun.COM di_lookup_node(di_node_t root, char *devfspath)
383512116SVikram.Hegde@Sun.COM {
383612116SVikram.Hegde@Sun.COM 	di_node_t	node;
383712116SVikram.Hegde@Sun.COM 	char		*curr;
383812116SVikram.Hegde@Sun.COM 
383912116SVikram.Hegde@Sun.COM 	node = di_lookup_node_impl(root, devfspath);
384012116SVikram.Hegde@Sun.COM 	if (node != DI_NODE_NIL) {
384112116SVikram.Hegde@Sun.COM 		return (node);
384212116SVikram.Hegde@Sun.COM 	}
384312116SVikram.Hegde@Sun.COM 
384412116SVikram.Hegde@Sun.COM 	/* node is already set to DI_NODE_NIL */
384512116SVikram.Hegde@Sun.COM 	curr = alias_to_curr(root, devfspath, &node);
384612116SVikram.Hegde@Sun.COM 	if (curr == NULL) {
384712116SVikram.Hegde@Sun.COM 		/* node may or may node be DI_NODE_NIL */
384812116SVikram.Hegde@Sun.COM 		return (node);
384912116SVikram.Hegde@Sun.COM 	}
385012116SVikram.Hegde@Sun.COM 
385112116SVikram.Hegde@Sun.COM 	node = di_lookup_node_impl(root, curr);
385212116SVikram.Hegde@Sun.COM 
385312116SVikram.Hegde@Sun.COM 	free(curr);
385412116SVikram.Hegde@Sun.COM 
385512116SVikram.Hegde@Sun.COM 	return (node);
385612116SVikram.Hegde@Sun.COM }
385712116SVikram.Hegde@Sun.COM 
385812116SVikram.Hegde@Sun.COM char *
di_alias2curr(di_node_t anynode,char * alias)385912116SVikram.Hegde@Sun.COM di_alias2curr(di_node_t anynode, char *alias)
386012116SVikram.Hegde@Sun.COM {
386112116SVikram.Hegde@Sun.COM 	di_node_t currnode = DI_NODE_NIL;
3862*12270SJerry.Gilliam@Sun.COM 	char *curr;
3863*12270SJerry.Gilliam@Sun.COM 
3864*12270SJerry.Gilliam@Sun.COM 	if (anynode == DI_NODE_NIL || alias == NULL)
3865*12270SJerry.Gilliam@Sun.COM 		return (NULL);
3866*12270SJerry.Gilliam@Sun.COM 
3867*12270SJerry.Gilliam@Sun.COM 	curr = alias_to_curr(anynode, alias, &currnode);
386812116SVikram.Hegde@Sun.COM 	if (curr == NULL && currnode != DI_NODE_NIL) {
386912116SVikram.Hegde@Sun.COM 		return (di_devfs_path(currnode));
387012116SVikram.Hegde@Sun.COM 	} else if (curr == NULL) {
387112116SVikram.Hegde@Sun.COM 		return (strdup(alias));
387212116SVikram.Hegde@Sun.COM 	}
387312116SVikram.Hegde@Sun.COM 
387412116SVikram.Hegde@Sun.COM 	return (curr);
387512116SVikram.Hegde@Sun.COM }
387612116SVikram.Hegde@Sun.COM 
38776640Scth di_path_t
di_lookup_path(di_node_t root,char * devfspath)38786640Scth di_lookup_path(di_node_t root, char *devfspath)
38796640Scth {
38806640Scth 	di_node_t	phci_node;
38816640Scth 	di_path_t	path = DI_PATH_NIL;
38826640Scth 	char		*copy, *lastslash;
38836640Scth 	char		*pname, *paddr;
38846640Scth 	char		*path_name, *path_addr;
38856640Scth 
38866640Scth 	if ((copy = strdup(devfspath)) == NULL) {
38876640Scth 		DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
38886640Scth 		return (DI_NODE_NIL);
38896640Scth 	}
38906640Scth 
38916640Scth 	if ((lastslash = strrchr(copy, '/')) == NULL) {
38926640Scth 		DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
38936640Scth 		goto out;
38946640Scth 	}
38956640Scth 
38966640Scth 	/* stop at pHCI and find the node for the phci */
38976640Scth 	*lastslash = '\0';
38986640Scth 	phci_node = di_lookup_node(root, copy);
38996640Scth 	if (phci_node == NULL) {
39006640Scth 		DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
39016640Scth 		goto out;
39026640Scth 	}
39036640Scth 
39046640Scth 	/* set up pname and paddr for last component */
39056640Scth 	pname = lastslash + 1;
39066640Scth 	if ((paddr = strchr(pname, '@')) == NULL) {
39076640Scth 		DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
39086640Scth 		goto out;
39096640Scth 	}
39106640Scth 	*paddr++ = '\0';
39116640Scth 
39126640Scth 	/* walk paths below phci looking for match */
39136640Scth 	for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
39146640Scth 	    path != DI_PATH_NIL;
39156640Scth 	    path = di_path_phci_next_path(phci_node, path)) {
39166640Scth 
39176640Scth 		/* get name@addr of path */
39186640Scth 		path_name = di_path_node_name(path);
39196640Scth 		path_addr = di_path_bus_addr(path);
39206640Scth 		if ((path_name == NULL) || (path_addr == NULL))
39216640Scth 			continue;
39226640Scth 
39236640Scth 		/* break on match */
39246640Scth 		if ((strcmp(pname, path_name) == 0) &&
39256640Scth 		    (strcmp(paddr, path_addr) == 0))
39266640Scth 			break;
39276640Scth 	}
39286640Scth 
39296640Scth out:	free(copy);
39306640Scth 	return (path);
39316640Scth }
39326640Scth 
39330Sstevel@tonic-gate static char *
msglevel2str(di_debug_t msglevel)39340Sstevel@tonic-gate msglevel2str(di_debug_t msglevel)
39350Sstevel@tonic-gate {
39360Sstevel@tonic-gate 	switch (msglevel) {
39370Sstevel@tonic-gate 		case DI_ERR:
39380Sstevel@tonic-gate 			return ("ERROR");
39390Sstevel@tonic-gate 		case DI_INFO:
39400Sstevel@tonic-gate 			return ("Info");
39410Sstevel@tonic-gate 		case DI_TRACE:
39420Sstevel@tonic-gate 			return ("Trace");
39430Sstevel@tonic-gate 		case DI_TRACE1:
39440Sstevel@tonic-gate 			return ("Trace1");
39450Sstevel@tonic-gate 		case DI_TRACE2:
39460Sstevel@tonic-gate 			return ("Trace2");
39470Sstevel@tonic-gate 		default:
39480Sstevel@tonic-gate 			return ("UNKNOWN");
39490Sstevel@tonic-gate 	}
39500Sstevel@tonic-gate }
39510Sstevel@tonic-gate 
39520Sstevel@tonic-gate void
dprint(di_debug_t msglevel,const char * fmt,...)39530Sstevel@tonic-gate dprint(di_debug_t msglevel, const char *fmt, ...)
39540Sstevel@tonic-gate {
39550Sstevel@tonic-gate 	va_list	ap;
39560Sstevel@tonic-gate 	char	*estr;
39570Sstevel@tonic-gate 
39580Sstevel@tonic-gate 	if (di_debug <= DI_QUIET)
39590Sstevel@tonic-gate 		return;
39600Sstevel@tonic-gate 
39610Sstevel@tonic-gate 	if (di_debug < msglevel)
39620Sstevel@tonic-gate 		return;
39630Sstevel@tonic-gate 
39640Sstevel@tonic-gate 	estr = msglevel2str(msglevel);
39650Sstevel@tonic-gate 
39660Sstevel@tonic-gate 	assert(estr);
39670Sstevel@tonic-gate 
39680Sstevel@tonic-gate 	va_start(ap, fmt);
39690Sstevel@tonic-gate 
39700Sstevel@tonic-gate 	(void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
39710Sstevel@tonic-gate 	    (ulong_t)getpid(), estr);
39720Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
39730Sstevel@tonic-gate 
39740Sstevel@tonic-gate 	va_end(ap);
39750Sstevel@tonic-gate }
39760Sstevel@tonic-gate 
39770Sstevel@tonic-gate /* end of devinfo.c */
3978