Home | History | Annotate | Download | only in libdevinfo
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * Interfaces for getting device configuration data from kernel
     28  * through the devinfo driver.
     29  */
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <strings.h>
     35 #include <stropts.h>
     36 #include <fcntl.h>
     37 #include <poll.h>
     38 #include <synch.h>
     39 #include <unistd.h>
     40 #include <sys/mkdev.h>
     41 #include <sys/obpdefs.h>
     42 #include <sys/stat.h>
     43 #include <sys/types.h>
     44 #include <sys/time.h>
     45 #include <sys/autoconf.h>
     46 #include <stdarg.h>
     47 #include <sys/ddi_hp.h>
     48 
     49 #define	NDEBUG 1
     50 #include <assert.h>
     51 
     52 #include "libdevinfo.h"
     53 
     54 /*
     55  * Debug message levels
     56  */
     57 typedef enum {
     58 	DI_QUIET = 0,	/* No debug messages - the default */
     59 	DI_ERR = 1,
     60 	DI_INFO,
     61 	DI_TRACE,
     62 	DI_TRACE1,
     63 	DI_TRACE2
     64 } di_debug_t;
     65 
     66 int di_debug = DI_QUIET;
     67 
     68 #define	DPRINTF(args)	{ if (di_debug != DI_QUIET) dprint args; }
     69 
     70 void dprint(di_debug_t msglevel, const char *fmt, ...);
     71 
     72 
     73 #pragma init(_libdevinfo_init)
     74 
     75 void
     76 _libdevinfo_init()
     77 {
     78 	char	*debug_str = getenv("_LIBDEVINFO_DEBUG");
     79 
     80 	if (debug_str) {
     81 		errno = 0;
     82 		di_debug = atoi(debug_str);
     83 		if (errno || di_debug < DI_QUIET)
     84 			di_debug = DI_QUIET;
     85 	}
     86 }
     87 
     88 di_node_t
     89 di_init(const char *phys_path, uint_t flag)
     90 {
     91 	return (di_init_impl(phys_path, flag, NULL));
     92 }
     93 
     94 /*
     95  * We use blocking_open() to guarantee access to the devinfo device, if open()
     96  * is failing with EAGAIN.
     97  */
     98 static int
     99 blocking_open(const char *path, int oflag)
    100 {
    101 	int fd;
    102 
    103 	while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
    104 		(void) poll(NULL, 0, 1 * MILLISEC);
    105 
    106 	return (fd);
    107 }
    108 
    109 /* private interface */
    110 di_node_t
    111 di_init_driver(const char *drv_name, uint_t flag)
    112 {
    113 	int fd;
    114 	char driver[MAXPATHLEN];
    115 
    116 	/*
    117 	 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
    118 	 * which should be sufficient for any sensible programmer.
    119 	 */
    120 	if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
    121 		errno = EINVAL;
    122 		return (DI_NODE_NIL);
    123 	}
    124 	(void) strcpy(driver, drv_name);
    125 
    126 	/*
    127 	 * open the devinfo driver
    128 	 */
    129 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
    130 	    O_RDONLY)) == -1) {
    131 		DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
    132 		return (DI_NODE_NIL);
    133 	}
    134 
    135 	if (ioctl(fd, DINFOLODRV, driver) != 0) {
    136 		DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
    137 		(void) close(fd);
    138 		errno = ENXIO;
    139 		return (DI_NODE_NIL);
    140 	}
    141 	(void) close(fd);
    142 
    143 	/*
    144 	 * Driver load succeeded, return a snapshot
    145 	 */
    146 	return (di_init("/", flag));
    147 }
    148 
    149 di_node_t
    150 di_init_impl(const char *phys_path, uint_t flag,
    151 	struct di_priv_data *priv)
    152 {
    153 	caddr_t pa;
    154 	int fd, map_size;
    155 	struct di_all *dap;
    156 	struct dinfo_io dinfo_io;
    157 
    158 	uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
    159 	uint_t pagemask = ~pageoffset;
    160 
    161 	DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
    162 
    163 	/*
    164 	 * Make sure there is no minor name in the path
    165 	 * and the path do not start with /devices....
    166 	 */
    167 	if (strchr(phys_path, ':') ||
    168 	    (strncmp(phys_path, "/devices", 8) == 0) ||
    169 	    (strlen(phys_path) > MAXPATHLEN)) {
    170 		errno = EINVAL;
    171 		return (DI_NODE_NIL);
    172 	}
    173 
    174 	if (strlen(phys_path) == 0)
    175 		(void) sprintf(dinfo_io.root_path, "/");
    176 	else if (*phys_path != '/')
    177 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
    178 		    "/%s", phys_path);
    179 	else
    180 		(void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
    181 		    "%s", phys_path);
    182 
    183 	/*
    184 	 * If private data is requested, copy the format specification
    185 	 */
    186 	if (flag & DINFOPRIVDATA & 0xff) {
    187 		if (priv)
    188 			bcopy(priv, &dinfo_io.priv,
    189 			    sizeof (struct di_priv_data));
    190 		else {
    191 			errno = EINVAL;
    192 			return (DI_NODE_NIL);
    193 		}
    194 	}
    195 
    196 	/*
    197 	 * Attempt to open the devinfo driver.  Make a second attempt at the
    198 	 * read-only minor node if we don't have privileges to open the full
    199 	 * version _and_ if we're not requesting operations that the read-only
    200 	 * node can't perform.  (Setgid processes would fail an access() test,
    201 	 * of course.)
    202 	 */
    203 	if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
    204 	    O_RDONLY)) == -1) {
    205 		if ((flag & DINFOFORCE) == DINFOFORCE ||
    206 		    (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
    207 			/*
    208 			 * We wanted to perform a privileged operation, but the
    209 			 * privileged node isn't available.  Don't modify errno
    210 			 * on our way out (but display it if we're running with
    211 			 * di_debug set).
    212 			 */
    213 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
    214 			    errno));
    215 			return (DI_NODE_NIL);
    216 		}
    217 
    218 		if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
    219 		    O_RDONLY)) == -1) {
    220 			DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
    221 			    errno));
    222 			return (DI_NODE_NIL);
    223 		}
    224 	}
    225 
    226 	/*
    227 	 * Verify that there is no major conflict, i.e., we are indeed opening
    228 	 * the devinfo driver.
    229 	 */
    230 	if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
    231 		DPRINTF((DI_ERR,
    232 		    "driver ID failed; check for major conflict\n"));
    233 		(void) close(fd);
    234 		return (DI_NODE_NIL);
    235 	}
    236 
    237 	/*
    238 	 * create snapshot
    239 	 */
    240 	if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
    241 		DPRINTF((DI_ERR, "devinfo ioctl failed with "
    242 		    "error: %d\n", errno));
    243 		(void) close(fd);
    244 		return (DI_NODE_NIL);
    245 	} else if (map_size == 0) {
    246 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
    247 		errno = ENXIO;
    248 		(void) close(fd);
    249 		return (DI_NODE_NIL);
    250 	}
    251 
    252 	/*
    253 	 * copy snapshot to userland
    254 	 */
    255 	map_size = (map_size + pageoffset) & pagemask;
    256 	if ((pa = valloc(map_size)) == NULL) {
    257 		DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
    258 		(void) close(fd);
    259 		return (DI_NODE_NIL);
    260 	}
    261 
    262 	if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
    263 		DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
    264 		(void) close(fd);
    265 		free(pa);
    266 		errno = EFAULT;
    267 		return (DI_NODE_NIL);
    268 	}
    269 
    270 	(void) close(fd);
    271 
    272 	dap = DI_ALL(pa);
    273 	if (dap->version != DI_SNAPSHOT_VERSION) {
    274 		DPRINTF((DI_ERR, "wrong snapshot version "
    275 		    "(expected=%d, actual=%d)\n",
    276 		    DI_SNAPSHOT_VERSION, dap->version));
    277 		free(pa);
    278 		errno = ESTALE;
    279 		return (DI_NODE_NIL);
    280 	}
    281 	if (dap->top_devinfo == 0) {	/* phys_path not found */
    282 		DPRINTF((DI_ERR, "%s not found\n", phys_path));
    283 		free(pa);
    284 		errno = EINVAL;
    285 		return (DI_NODE_NIL);
    286 	}
    287 
    288 	return (DI_NODE(pa + dap->top_devinfo));
    289 }
    290 
    291 void
    292 di_fini(di_node_t root)
    293 {
    294 	caddr_t pa;		/* starting address of map */
    295 
    296 	DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
    297 
    298 	/*
    299 	 * paranoid checking
    300 	 */
    301 	if (root == DI_NODE_NIL) {
    302 		DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
    303 		return;
    304 	}
    305 
    306 	/*
    307 	 * The root contains its own offset--self.
    308 	 * Subtracting it from root address, we get the starting addr.
    309 	 * The map_size is stored at the beginning of snapshot.
    310 	 * Once we have starting address and size, we can free().
    311 	 */
    312 	pa = (caddr_t)root - DI_NODE(root)->self;
    313 
    314 	free(pa);
    315 }
    316 
    317 di_node_t
    318 di_parent_node(di_node_t node)
    319 {
    320 	caddr_t pa;		/* starting address of map */
    321 
    322 	if (node == DI_NODE_NIL) {
    323 		errno = EINVAL;
    324 		return (DI_NODE_NIL);
    325 	}
    326 
    327 	DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
    328 
    329 	pa = (caddr_t)node - DI_NODE(node)->self;
    330 
    331 	if (DI_NODE(node)->parent) {
    332 		return (DI_NODE(pa + DI_NODE(node)->parent));
    333 	}
    334 
    335 	/*
    336 	 * Deal with error condition:
    337 	 *   If parent doesn't exist and node is not the root,
    338 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
    339 	 */
    340 	if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
    341 		errno = ENOTSUP;
    342 	else
    343 		errno = ENXIO;
    344 
    345 	return (DI_NODE_NIL);
    346 }
    347 
    348 di_node_t
    349 di_sibling_node(di_node_t node)
    350 {
    351 	caddr_t pa;		/* starting address of map */
    352 
    353 	if (node == DI_NODE_NIL) {
    354 		errno = EINVAL;
    355 		return (DI_NODE_NIL);
    356 	}
    357 
    358 	DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
    359 
    360 	pa = (caddr_t)node - DI_NODE(node)->self;
    361 
    362 	if (DI_NODE(node)->sibling) {
    363 		return (DI_NODE(pa + DI_NODE(node)->sibling));
    364 	}
    365 
    366 	/*
    367 	 * Deal with error condition:
    368 	 *   Sibling doesn't exist, figure out if ioctl command
    369 	 *   has DINFOSUBTREE set. If it doesn't, set errno to
    370 	 *   ENOTSUP.
    371 	 */
    372 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
    373 		errno = ENOTSUP;
    374 	else
    375 		errno = ENXIO;
    376 
    377 	return (DI_NODE_NIL);
    378 }
    379 
    380 di_node_t
    381 di_child_node(di_node_t node)
    382 {
    383 	caddr_t pa;		/* starting address of map */
    384 
    385 	DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
    386 
    387 	if (node == DI_NODE_NIL) {
    388 		errno = EINVAL;
    389 		return (DI_NODE_NIL);
    390 	}
    391 
    392 	pa = (caddr_t)node - DI_NODE(node)->self;
    393 
    394 	if (DI_NODE(node)->child) {
    395 		return (DI_NODE(pa + DI_NODE(node)->child));
    396 	}
    397 
    398 	/*
    399 	 * Deal with error condition:
    400 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
    401 	 *   If it isn't, set errno to ENOTSUP.
    402 	 */
    403 	if (!(DI_ALL(pa)->command & DINFOSUBTREE))
    404 		errno = ENOTSUP;
    405 	else
    406 		errno = ENXIO;
    407 
    408 	return (DI_NODE_NIL);
    409 }
    410 
    411 di_node_t
    412 di_drv_first_node(const char *drv_name, di_node_t root)
    413 {
    414 	caddr_t		pa;		/* starting address of map */
    415 	int		major, devcnt;
    416 	struct di_devnm	*devnm;
    417 
    418 	DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
    419 
    420 	if (root == DI_NODE_NIL) {
    421 		errno = EINVAL;
    422 		return (DI_NODE_NIL);
    423 	}
    424 
    425 	/*
    426 	 * get major number of driver
    427 	 */
    428 	pa = (caddr_t)root - DI_NODE(root)->self;
    429 	devcnt = DI_ALL(pa)->devcnt;
    430 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
    431 
    432 	for (major = 0; major < devcnt; major++)
    433 		if (devnm[major].name && (strcmp(drv_name,
    434 		    (char *)(pa + devnm[major].name)) == 0))
    435 			break;
    436 
    437 	if (major >= devcnt) {
    438 		errno = EINVAL;
    439 		return (DI_NODE_NIL);
    440 	}
    441 
    442 	if (!(devnm[major].head)) {
    443 		errno = ENXIO;
    444 		return (DI_NODE_NIL);
    445 	}
    446 
    447 	return (DI_NODE(pa + devnm[major].head));
    448 }
    449 
    450 di_node_t
    451 di_drv_next_node(di_node_t node)
    452 {
    453 	caddr_t		pa;		/* starting address of map */
    454 
    455 	if (node == DI_NODE_NIL) {
    456 		errno = EINVAL;
    457 		return (DI_NODE_NIL);
    458 	}
    459 
    460 	DPRINTF((DI_TRACE, "next node on per driver list:"
    461 	    " current=%s, driver=%s\n",
    462 	    di_node_name(node), di_driver_name(node)));
    463 
    464 	if (DI_NODE(node)->next == (di_off_t)-1) {
    465 		errno = ENOTSUP;
    466 		return (DI_NODE_NIL);
    467 	}
    468 
    469 	pa = (caddr_t)node - DI_NODE(node)->self;
    470 
    471 	if (DI_NODE(node)->next == NULL) {
    472 		errno = ENXIO;
    473 		return (DI_NODE_NIL);
    474 	}
    475 
    476 	return (DI_NODE(pa + DI_NODE(node)->next));
    477 }
    478 
    479 /*
    480  * Internal library interfaces:
    481  *   node_list etc. for node walking
    482  */
    483 struct node_list {
    484 	struct node_list *next;
    485 	di_node_t node;
    486 };
    487 
    488 static void
    489 free_node_list(struct node_list **headp)
    490 {
    491 	struct node_list *tmp;
    492 
    493 	while (*headp) {
    494 		tmp = *headp;
    495 		*headp = (*headp)->next;
    496 		free(tmp);
    497 	}
    498 }
    499 
    500 static void
    501 append_node_list(struct node_list **headp, struct node_list *list)
    502 {
    503 	struct node_list *tmp;
    504 
    505 	if (*headp == NULL) {
    506 		*headp = list;
    507 		return;
    508 	}
    509 
    510 	if (list == NULL)	/* a minor optimization */
    511 		return;
    512 
    513 	tmp = *headp;
    514 	while (tmp->next)
    515 		tmp = tmp->next;
    516 
    517 	tmp->next = list;
    518 }
    519 
    520 static void
    521 prepend_node_list(struct node_list **headp, struct node_list *list)
    522 {
    523 	struct node_list *tmp;
    524 
    525 	if (list == NULL)
    526 		return;
    527 
    528 	tmp = *headp;
    529 	*headp = list;
    530 
    531 	if (tmp == NULL)	/* a minor optimization */
    532 		return;
    533 
    534 	while (list->next)
    535 		list = list->next;
    536 
    537 	list->next = tmp;
    538 }
    539 
    540 /*
    541  * returns 1 if node is a descendant of parent, 0 otherwise
    542  */
    543 static int
    544 is_descendant(di_node_t node, di_node_t parent)
    545 {
    546 	/*
    547 	 * DI_NODE_NIL is parent of root, so it is
    548 	 * the parent of all nodes.
    549 	 */
    550 	if (parent == DI_NODE_NIL) {
    551 		return (1);
    552 	}
    553 
    554 	do {
    555 		node = di_parent_node(node);
    556 	} while ((node != DI_NODE_NIL) && (node != parent));
    557 
    558 	return (node != DI_NODE_NIL);
    559 }
    560 
    561 /*
    562  * Insert list before the first node which is NOT a descendent of parent.
    563  * This is needed to reproduce the exact walking order of link generators.
    564  */
    565 static void
    566 insert_node_list(struct node_list **headp, struct node_list *list,
    567     di_node_t parent)
    568 {
    569 	struct node_list *tmp, *tmp1;
    570 
    571 	if (list == NULL)
    572 		return;
    573 
    574 	tmp = *headp;
    575 	if (tmp == NULL) {	/* a minor optimization */
    576 		*headp = list;
    577 		return;
    578 	}
    579 
    580 	if (!is_descendant(tmp->node, parent)) {
    581 		prepend_node_list(headp, list);
    582 		return;
    583 	}
    584 
    585 	/*
    586 	 * Find first node which is not a descendant
    587 	 */
    588 	while (tmp->next && is_descendant(tmp->next->node, parent)) {
    589 		tmp = tmp->next;
    590 	}
    591 
    592 	tmp1 = tmp->next;
    593 	tmp->next = list;
    594 	append_node_list(headp, tmp1);
    595 }
    596 
    597 /*
    598  *   Get a linked list of handles of all children
    599  */
    600 static struct node_list *
    601 get_children(di_node_t node)
    602 {
    603 	di_node_t child;
    604 	struct node_list *result, *tmp;
    605 
    606 	DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
    607 
    608 	if ((child = di_child_node(node)) == DI_NODE_NIL) {
    609 		return (NULL);
    610 	}
    611 
    612 	if ((result = malloc(sizeof (struct node_list))) == NULL) {
    613 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
    614 		return (NULL);
    615 	}
    616 
    617 	result->node = child;
    618 	tmp = result;
    619 
    620 	while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
    621 		if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
    622 			DPRINTF((DI_ERR, "malloc of node_list failed\n"));
    623 			free_node_list(&result);
    624 			return (NULL);
    625 		}
    626 		tmp = tmp->next;
    627 		tmp->node = child;
    628 	}
    629 
    630 	tmp->next = NULL;
    631 
    632 	return (result);
    633 }
    634 
    635 /*
    636  * Internal library interface:
    637  *   Delete all siblings of the first node from the node_list, along with
    638  *   the first node itself.
    639  */
    640 static void
    641 prune_sib(struct node_list **headp)
    642 {
    643 	di_node_t parent, curr_par, curr_gpar;
    644 	struct node_list *curr, *prev;
    645 
    646 	/*
    647 	 * get handle to parent of first node
    648 	 */
    649 	if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
    650 		/*
    651 		 * This must be the root of the snapshot, so can't
    652 		 * have any siblings.
    653 		 *
    654 		 * XXX Put a check here just in case.
    655 		 */
    656 		if ((*headp)->next)
    657 			DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
    658 
    659 		free(*headp);
    660 		*headp = NULL;
    661 		return;
    662 	}
    663 
    664 	/*
    665 	 * To be complete, we should also delete the children
    666 	 * of siblings that have already been visited.
    667 	 * This happens for DI_WALK_SIBFIRST when the first node
    668 	 * is NOT the first in the linked list of siblings.
    669 	 *
    670 	 * Hence, we compare parent with BOTH the parent and grandparent
    671 	 * of nodes, and delete node is a match is found.
    672 	 */
    673 	prev = *headp;
    674 	curr = prev->next;
    675 	while (curr) {
    676 		if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) &&
    677 		    ((curr_par == parent) || ((curr_gpar =
    678 		    di_parent_node(curr_par)) != DI_NODE_NIL) &&
    679 		    (curr_gpar == parent))) {
    680 			/*
    681 			 * match parent/grandparent: delete curr
    682 			 */
    683 			prev->next = curr->next;
    684 			free(curr);
    685 			curr = prev->next;
    686 		} else
    687 			curr = curr->next;
    688 	}
    689 
    690 	/*
    691 	 * delete the first node
    692 	 */
    693 	curr = *headp;
    694 	*headp = curr->next;
    695 	free(curr);
    696 }
    697 
    698 /*
    699  * Internal library function:
    700  *	Update node list based on action (return code from callback)
    701  *	and flag specifying walking behavior.
    702  */
    703 static void
    704 update_node_list(int action, uint_t flag, struct node_list **headp)
    705 {
    706 	struct node_list *children, *tmp;
    707 	di_node_t parent = di_parent_node((*headp)->node);
    708 
    709 	switch (action) {
    710 	case DI_WALK_TERMINATE:
    711 		/*
    712 		 * free the node list and be done
    713 		 */
    714 		children = NULL;
    715 		free_node_list(headp);
    716 		break;
    717 
    718 	case DI_WALK_PRUNESIB:
    719 		/*
    720 		 * Get list of children and prune siblings
    721 		 */
    722 		children = get_children((*headp)->node);
    723 		prune_sib(headp);
    724 		break;
    725 
    726 	case DI_WALK_PRUNECHILD:
    727 		/*
    728 		 * Set children to NULL and pop first node
    729 		 */
    730 		children = NULL;
    731 		tmp = *headp;
    732 		*headp = tmp->next;
    733 		free(tmp);
    734 		break;
    735 
    736 	case DI_WALK_CONTINUE:
    737 	default:
    738 		/*
    739 		 * Get list of children and pop first node
    740 		 */
    741 		children = get_children((*headp)->node);
    742 		tmp = *headp;
    743 		*headp = tmp->next;
    744 		free(tmp);
    745 		break;
    746 	}
    747 
    748 	/*
    749 	 * insert the list of children
    750 	 */
    751 	switch (flag) {
    752 	case DI_WALK_CLDFIRST:
    753 		prepend_node_list(headp, children);
    754 		break;
    755 
    756 	case DI_WALK_SIBFIRST:
    757 		append_node_list(headp, children);
    758 		break;
    759 
    760 	case DI_WALK_LINKGEN:
    761 	default:
    762 		insert_node_list(headp, children, parent);
    763 		break;
    764 	}
    765 }
    766 
    767 /*
    768  * Internal library function:
    769  *   Invoke callback on one node and update the list of nodes to be walked
    770  *   based on the flag and return code.
    771  */
    772 static void
    773 walk_one_node(struct node_list **headp, uint_t flag, void *arg,
    774 	int (*callback)(di_node_t, void *))
    775 {
    776 	DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
    777 
    778 	update_node_list(callback((*headp)->node, arg),
    779 	    flag & DI_WALK_MASK, headp);
    780 }
    781 
    782 int
    783 di_walk_node(di_node_t root, uint_t flag, void *arg,
    784 	int (*node_callback)(di_node_t, void *))
    785 {
    786 	struct node_list  *head;	/* node_list for tree walk */
    787 
    788 	if (root == NULL) {
    789 		errno = EINVAL;
    790 		return (-1);
    791 	}
    792 
    793 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
    794 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
    795 		return (-1);
    796 	}
    797 
    798 	head->next = NULL;
    799 	head->node = root;
    800 
    801 	DPRINTF((DI_INFO, "Start node walking from node %s\n",
    802 	    di_node_name(root)));
    803 
    804 	while (head != NULL)
    805 		walk_one_node(&head, flag, arg, node_callback);
    806 
    807 	return (0);
    808 }
    809 
    810 /*
    811  * Internal library function:
    812  *   Invoke callback for each minor on the minor list of first node
    813  *   on node_list headp, and place children of first node on the list.
    814  *
    815  *   This is similar to walk_one_node, except we only walk in child
    816  *   first mode.
    817  */
    818 static void
    819 walk_one_minor_list(struct node_list **headp, const char *desired_type,
    820 	uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
    821 {
    822 	int ddm_type;
    823 	int action = DI_WALK_CONTINUE;
    824 	char *node_type;
    825 	di_minor_t minor = DI_MINOR_NIL;
    826 	di_node_t node = (*headp)->node;
    827 
    828 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
    829 		ddm_type = di_minor_type(minor);
    830 
    831 		if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
    832 			continue;
    833 
    834 		if ((ddm_type == DDM_INTERNAL_PATH) &&
    835 		    !(flag & DI_CHECK_INTERNAL_PATH))
    836 			continue;
    837 
    838 		node_type = di_minor_nodetype(minor);
    839 		if ((desired_type != NULL) && ((node_type == NULL) ||
    840 		    strncmp(desired_type, node_type, strlen(desired_type))
    841 		    != 0))
    842 			continue;
    843 
    844 		if ((action = callback(node, minor, arg)) ==
    845 		    DI_WALK_TERMINATE) {
    846 			break;
    847 		}
    848 	}
    849 
    850 	update_node_list(action, DI_WALK_LINKGEN, headp);
    851 }
    852 
    853 int
    854 di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
    855 	int (*minor_callback)(di_node_t, di_minor_t, void *))
    856 {
    857 	struct node_list	*head;	/* node_list for tree walk */
    858 
    859 #ifdef DEBUG
    860 	char	*devfspath = di_devfs_path(root);
    861 	DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath));
    862 	di_devfs_path_free(devfspath);
    863 #endif
    864 
    865 	if (root == NULL) {
    866 		errno = EINVAL;
    867 		return (-1);
    868 	}
    869 
    870 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
    871 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
    872 		return (-1);
    873 	}
    874 
    875 	head->next = NULL;
    876 	head->node = root;
    877 
    878 	DPRINTF((DI_INFO, "Start minor walking from node %s\n",
    879 	    di_node_name(root)));
    880 
    881 	while (head != NULL)
    882 		walk_one_minor_list(&head, minor_type, flag, arg,
    883 		    minor_callback);
    884 
    885 	return (0);
    886 }
    887 
    888 /*
    889  * generic node parameters
    890  *   Calling these routines always succeeds.
    891  */
    892 char *
    893 di_node_name(di_node_t node)
    894 {
    895 	return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
    896 }
    897 
    898 /* returns NULL ptr or a valid ptr to non-NULL string */
    899 char *
    900 di_bus_addr(di_node_t node)
    901 {
    902 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
    903 
    904 	if (DI_NODE(node)->address == 0)
    905 		return (NULL);
    906 
    907 	return ((char *)(pa + DI_NODE(node)->address));
    908 }
    909 
    910 char *
    911 di_binding_name(di_node_t node)
    912 {
    913 	caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
    914 
    915 	if (DI_NODE(node)->bind_name == 0)
    916 		return (NULL);
    917 
    918 	return ((char *)(pa + DI_NODE(node)->bind_name));
    919 }
    920 
    921 int
    922 di_compatible_names(di_node_t node, char **names)
    923 {
    924 	char *c;
    925 	int len, size, entries = 0;
    926 
    927 	if (DI_NODE(node)->compat_names == 0) {
    928 		*names = NULL;
    929 		return (0);
    930 	}
    931 
    932 	*names = (caddr_t)node +
    933 	    DI_NODE(node)->compat_names - DI_NODE(node)->self;
    934 
    935 	c = *names;
    936 	len = DI_NODE(node)->compat_length;
    937 	while (len > 0) {
    938 		entries++;
    939 		size = strlen(c) + 1;
    940 		len -= size;
    941 		c += size;
    942 	}
    943 
    944 	return (entries);
    945 }
    946 
    947 int
    948 di_instance(di_node_t node)
    949 {
    950 	return (DI_NODE(node)->instance);
    951 }
    952 
    953 /*
    954  * XXX: emulate the return value of the old implementation
    955  * using info from devi_node_class and devi_node_attributes.
    956  */
    957 int
    958 di_nodeid(di_node_t node)
    959 {
    960 	if (DI_NODE(node)->node_class == DDI_NC_PROM)
    961 		return (DI_PROM_NODEID);
    962 
    963 	if (DI_NODE(node)->attributes & DDI_PERSISTENT)
    964 		return (DI_SID_NODEID);
    965 
    966 	return (DI_PSEUDO_NODEID);
    967 }
    968 
    969 uint_t
    970 di_state(di_node_t node)
    971 {
    972 	uint_t result = 0;
    973 
    974 	if (di_node_state(node) < DS_ATTACHED)
    975 		result |= DI_DRIVER_DETACHED;
    976 	if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
    977 		result |= DI_DEVICE_OFFLINE;
    978 	if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
    979 		result |= DI_DEVICE_DOWN;
    980 	if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
    981 		result |= DI_DEVICE_DEGRADED;
    982 	if (DI_NODE(node)->state & DEVI_DEVICE_REMOVED)
    983 		result |= DI_DEVICE_REMOVED;
    984 	if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
    985 		result |= DI_BUS_QUIESCED;
    986 	if (DI_NODE(node)->state & DEVI_BUS_DOWN)
    987 		result |= DI_BUS_DOWN;
    988 
    989 	return (result);
    990 }
    991 
    992 ddi_node_state_t
    993 di_node_state(di_node_t node)
    994 {
    995 	return (DI_NODE(node)->node_state);
    996 }
    997 
    998 uint_t
    999 di_flags(di_node_t node)
   1000 {
   1001 	return (DI_NODE(node)->flags);
   1002 }
   1003 
   1004 uint_t
   1005 di_retired(di_node_t node)
   1006 {
   1007 	return (di_flags(node) & DEVI_RETIRED);
   1008 }
   1009 
   1010 ddi_devid_t
   1011 di_devid(di_node_t node)
   1012 {
   1013 	if (DI_NODE(node)->devid == 0)
   1014 		return (NULL);
   1015 
   1016 	return ((ddi_devid_t)((caddr_t)node +
   1017 	    DI_NODE(node)->devid - DI_NODE(node)->self));
   1018 }
   1019 
   1020 int
   1021 di_driver_major(di_node_t node)
   1022 {
   1023 	int major;
   1024 
   1025 	major = DI_NODE(node)->drv_major;
   1026 	if (major < 0)
   1027 		return (-1);
   1028 	return (major);
   1029 }
   1030 
   1031 char *
   1032 di_driver_name(di_node_t node)
   1033 {
   1034 	int major;
   1035 	caddr_t pa;
   1036 	struct di_devnm *devnm;
   1037 
   1038 	major = DI_NODE(node)->drv_major;
   1039 	if (major < 0)
   1040 		return (NULL);
   1041 
   1042 	pa = (caddr_t)node - DI_NODE(node)->self;
   1043 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
   1044 
   1045 	if (devnm[major].name)
   1046 		return (pa + devnm[major].name);
   1047 	else
   1048 		return (NULL);
   1049 }
   1050 
   1051 uint_t
   1052 di_driver_ops(di_node_t node)
   1053 {
   1054 	int major;
   1055 	caddr_t pa;
   1056 	struct di_devnm *devnm;
   1057 
   1058 	major = DI_NODE(node)->drv_major;
   1059 	if (major < 0)
   1060 		return (0);
   1061 
   1062 	pa = (caddr_t)node - DI_NODE(node)->self;
   1063 	devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
   1064 
   1065 	return (devnm[major].ops);
   1066 }
   1067 
   1068 /*
   1069  * returns the length of the path, caller must free memory
   1070  */
   1071 char *
   1072 di_devfs_path(di_node_t node)
   1073 {
   1074 	caddr_t pa;
   1075 	di_node_t parent;
   1076 	int depth = 0, len = 0;
   1077 	char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH];
   1078 
   1079 	if (node == DI_NODE_NIL) {
   1080 		errno = EINVAL;
   1081 		return (NULL);
   1082 	}
   1083 
   1084 	/*
   1085 	 * trace back to root, note the node_name & address
   1086 	 */
   1087 	while ((parent = di_parent_node(node)) != DI_NODE_NIL) {
   1088 		name[depth] = di_node_name(node);
   1089 		len += strlen(name[depth]) + 1;		/* 1 for '/' */
   1090 
   1091 		if ((addr[depth] = di_bus_addr(node)) != NULL)
   1092 			len += strlen(addr[depth]) + 1;	/* 1 for '@' */
   1093 
   1094 		node = parent;
   1095 		depth++;
   1096 	}
   1097 
   1098 	/*
   1099 	 * get the path to the root of snapshot
   1100 	 */
   1101 	pa = (caddr_t)node - DI_NODE(node)->self;
   1102 	name[depth] = DI_ALL(pa)->root_path;
   1103 	len += strlen(name[depth]) + 1;
   1104 
   1105 	/*
   1106 	 * allocate buffer and assemble path
   1107 	 */
   1108 	if ((buf = malloc(len)) == NULL) {
   1109 		return (NULL);
   1110 	}
   1111 
   1112 	(void) strcpy(buf, name[depth]);
   1113 	len = strlen(buf);
   1114 	if (buf[len - 1] == '/')
   1115 		len--;	/* delete trailing '/' */
   1116 
   1117 	while (depth) {
   1118 		depth--;
   1119 		buf[len] = '/';
   1120 		(void) strcpy(buf + len + 1, name[depth]);
   1121 		len += strlen(name[depth]) + 1;
   1122 		if (addr[depth] && addr[depth][0] != '\0') {
   1123 			buf[len] = '@';
   1124 			(void) strcpy(buf + len + 1, addr[depth]);
   1125 			len += strlen(addr[depth]) + 1;
   1126 		}
   1127 	}
   1128 
   1129 	return (buf);
   1130 }
   1131 
   1132 char *
   1133 di_devfs_minor_path(di_minor_t minor)
   1134 {
   1135 	di_node_t	node;
   1136 	char		*full_path, *name, *devfspath;
   1137 	int		full_path_len;
   1138 
   1139 	if (minor == DI_MINOR_NIL) {
   1140 		errno = EINVAL;
   1141 		return (NULL);
   1142 	}
   1143 
   1144 	name = di_minor_name(minor);
   1145 	node = di_minor_devinfo(minor);
   1146 	devfspath = di_devfs_path(node);
   1147 	if (devfspath == NULL)
   1148 		return (NULL);
   1149 
   1150 	/* make the full path to the device minor node */
   1151 	full_path_len = strlen(devfspath) + strlen(name) + 2;
   1152 	full_path = (char *)calloc(1, full_path_len);
   1153 	if (full_path != NULL)
   1154 		(void) snprintf(full_path, full_path_len, "%s:%s",
   1155 		    devfspath, name);
   1156 
   1157 	di_devfs_path_free(devfspath);
   1158 	return (full_path);
   1159 }
   1160 
   1161 /*
   1162  * Produce a string representation of path to di_path_t (pathinfo node). This
   1163  * string is identical to di_devfs_path had the device been enumerated under
   1164  * the pHCI: it has a base path to pHCI, then uses node_name of client, and
   1165  * device unit-address of pathinfo node.
   1166  */
   1167 char *
   1168 di_path_devfs_path(di_path_t path)
   1169 {
   1170 	di_node_t	phci_node;
   1171 	char		*phci_path, *path_name, *path_addr;
   1172 	char		*full_path;
   1173 	int		full_path_len;
   1174 
   1175 	if (path == DI_PATH_NIL) {
   1176 		errno = EINVAL;
   1177 		return (NULL);
   1178 	}
   1179 
   1180 	/* get name@addr for path */
   1181 	path_name = di_path_node_name(path);
   1182 	path_addr = di_path_bus_addr(path);
   1183 	if ((path_name == NULL) || (path_addr == NULL))
   1184 		return (NULL);
   1185 
   1186 	/* base path to pHCI devinfo node */
   1187 	phci_node = di_path_phci_node(path);
   1188 	if (phci_node == NULL)
   1189 		return (NULL);
   1190 	phci_path = di_devfs_path(phci_node);
   1191 	if (phci_path == NULL)
   1192 		return (NULL);
   1193 
   1194 	/* make the full string representation of path */
   1195 	full_path_len = strlen(phci_path) + 1 + strlen(path_name) +
   1196 	    1 + strlen(path_addr) + 1;
   1197 	full_path = (char *)calloc(1, full_path_len);
   1198 
   1199 	if (full_path != NULL)
   1200 		(void) snprintf(full_path, full_path_len, "%s/%s@%s",
   1201 		    phci_path, path_name, path_addr);
   1202 	di_devfs_path_free(phci_path);
   1203 	return (full_path);
   1204 }
   1205 
   1206 char *
   1207 di_path_client_devfs_path(di_path_t path)
   1208 {
   1209 	return (di_devfs_path(di_path_client_node(path)));
   1210 }
   1211 
   1212 void
   1213 di_devfs_path_free(char *buf)
   1214 {
   1215 	if (buf == NULL) {
   1216 		DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
   1217 		return;
   1218 	}
   1219 
   1220 	free(buf);
   1221 }
   1222 
   1223 /*
   1224  * Return 1 if name is a IEEE-1275 generic name. If new generic
   1225  * names are defined, they should be added to this table
   1226  */
   1227 static int
   1228 is_generic(const char *name, int len)
   1229 {
   1230 	const char	**gp;
   1231 
   1232 	/* from IEEE-1275 recommended practices section 3 */
   1233 	static const char *generic_names[] = {
   1234 	    "atm",
   1235 	    "disk",
   1236 	    "display",
   1237 	    "dma-controller",
   1238 	    "ethernet",
   1239 	    "fcs",
   1240 	    "fdc",
   1241 	    "fddi",
   1242 	    "fibre-channel",
   1243 	    "ide",
   1244 	    "interrupt-controller",
   1245 	    "isa",
   1246 	    "keyboard",
   1247 	    "memory",
   1248 	    "mouse",
   1249 	    "nvram",
   1250 	    "pc-card",
   1251 	    "pci",
   1252 	    "printer",
   1253 	    "rtc",
   1254 	    "sbus",
   1255 	    "scanner",
   1256 	    "scsi",
   1257 	    "serial",
   1258 	    "sound",
   1259 	    "ssa",
   1260 	    "tape",
   1261 	    "timer",
   1262 	    "token-ring",
   1263 	    "vme",
   1264 	    0
   1265 	};
   1266 
   1267 	for (gp = generic_names; *gp; gp++) {
   1268 		if ((strncmp(*gp, name, len) == 0) &&
   1269 		    (strlen(*gp) == len))
   1270 			return (1);
   1271 	}
   1272 	return (0);
   1273 }
   1274 
   1275 /*
   1276  * Determine if two paths below /devices refer to the same device, ignoring
   1277  * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*".
   1278  * Return 1 if the paths match.
   1279  */
   1280 int
   1281 di_devfs_path_match(const char *dp1, const char *dp2)
   1282 {
   1283 	const char	*p1, *p2;
   1284 	const char	*ec1, *ec2;
   1285 	const char	*at1, *at2;
   1286 	char		nc;
   1287 	int		g1, g2;
   1288 
   1289 	/* progress through both strings */
   1290 	for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) {
   1291 		/* require match until the start of a component */
   1292 		if (*p1 != '/')
   1293 			continue;
   1294 
   1295 		/* advance p1 and p2 to start of 'name' in component */
   1296 		nc = *(p1 + 1);
   1297 		if ((nc == '\0') || (nc == '/'))
   1298 			continue;		/* skip trash */
   1299 		p1++;
   1300 		p2++;
   1301 
   1302 		/*
   1303 		 * Both p1 and p2 point to beginning of 'name' in component.
   1304 		 * Determine where current component ends: next '/' or '\0'.
   1305 		 */
   1306 		ec1 = strchr(p1, '/');
   1307 		if (ec1 == NULL)
   1308 			ec1 = p1 + strlen(p1);
   1309 		ec2 = strchr(p2, '/');
   1310 		if (ec2 == NULL)
   1311 			ec2 = p2 + strlen(p2);
   1312 
   1313 		/* Determine where name ends based on whether '@' exists */
   1314 		at1 = strchr(p1, '@');
   1315 		at2 = strchr(p2, '@');
   1316 		if (at1 && (at1 < ec1))
   1317 			ec1 = at1;
   1318 		if (at2 && (at2 < ec2))
   1319 			ec2 = at2;
   1320 
   1321 		/*
   1322 		 * At this point p[12] point to beginning of name and
   1323 		 * ec[12] point to character past the end of name. Determine
   1324 		 * if the names are generic.
   1325 		 */
   1326 		g1 = is_generic(p1, ec1 - p1);
   1327 		g2 = is_generic(p2, ec2 - p2);
   1328 
   1329 		if (g1 != g2) {
   1330 			/*
   1331 			 * one generic and one non-generic
   1332 			 * skip past the names in the match.
   1333 			 */
   1334 			p1 = ec1;
   1335 			p2 = ec2;
   1336 		} else {
   1337 			if (*p1 != *p2)
   1338 				break;
   1339 		}
   1340 	}
   1341 
   1342 	return ((*p1 == *p2) ? 1 : 0);
   1343 }
   1344 
   1345 /* minor data access */
   1346 di_minor_t
   1347 di_minor_next(di_node_t node, di_minor_t minor)
   1348 {
   1349 	caddr_t pa;
   1350 
   1351 	/*
   1352 	 * paranoid error checking
   1353 	 */
   1354 	if (node == DI_NODE_NIL) {
   1355 		errno = EINVAL;
   1356 		return (DI_MINOR_NIL);
   1357 	}
   1358 
   1359 	/*
   1360 	 * minor is not NIL
   1361 	 */
   1362 	if (minor != DI_MINOR_NIL) {
   1363 		if (DI_MINOR(minor)->next != 0)
   1364 			return ((di_minor_t)((void *)((caddr_t)minor -
   1365 			    DI_MINOR(minor)->self + DI_MINOR(minor)->next)));
   1366 		else {
   1367 			errno = ENXIO;
   1368 			return (DI_MINOR_NIL);
   1369 		}
   1370 	}
   1371 
   1372 	/*
   1373 	 * minor is NIL-->caller asks for first minor node
   1374 	 */
   1375 	if (DI_NODE(node)->minor_data != 0) {
   1376 		return (DI_MINOR((caddr_t)node - DI_NODE(node)->self +
   1377 		    DI_NODE(node)->minor_data));
   1378 	}
   1379 
   1380 	/*
   1381 	 * no minor data-->check if snapshot includes minor data
   1382 	 *	in order to set the correct errno
   1383 	 */
   1384 	pa = (caddr_t)node - DI_NODE(node)->self;
   1385 	if (DINFOMINOR & DI_ALL(pa)->command)
   1386 		errno = ENXIO;
   1387 	else
   1388 		errno = ENOTSUP;
   1389 
   1390 	return (DI_MINOR_NIL);
   1391 }
   1392 
   1393 /* private interface for dealing with alias minor link generation */
   1394 di_node_t
   1395 di_minor_devinfo(di_minor_t minor)
   1396 {
   1397 	if (minor == DI_MINOR_NIL) {
   1398 		errno = EINVAL;
   1399 		return (DI_NODE_NIL);
   1400 	}
   1401 
   1402 	return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
   1403 	    DI_MINOR(minor)->node));
   1404 }
   1405 
   1406 ddi_minor_type
   1407 di_minor_type(di_minor_t minor)
   1408 {
   1409 	return (DI_MINOR(minor)->type);
   1410 }
   1411 
   1412 char *
   1413 di_minor_name(di_minor_t minor)
   1414 {
   1415 	if (DI_MINOR(minor)->name == 0)
   1416 		return (NULL);
   1417 
   1418 	return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
   1419 }
   1420 
   1421 dev_t
   1422 di_minor_devt(di_minor_t minor)
   1423 {
   1424 	return (makedev(DI_MINOR(minor)->dev_major,
   1425 	    DI_MINOR(minor)->dev_minor));
   1426 }
   1427 
   1428 int
   1429 di_minor_spectype(di_minor_t minor)
   1430 {
   1431 	return (DI_MINOR(minor)->spec_type);
   1432 }
   1433 
   1434 char *
   1435 di_minor_nodetype(di_minor_t minor)
   1436 {
   1437 	if (DI_MINOR(minor)->node_type == 0)
   1438 		return (NULL);
   1439 
   1440 	return ((caddr_t)minor -
   1441 	    DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
   1442 }
   1443 
   1444 /*
   1445  * Single public interface for accessing software properties
   1446  */
   1447 di_prop_t
   1448 di_prop_next(di_node_t node, di_prop_t prop)
   1449 {
   1450 	int list = DI_PROP_DRV_LIST;
   1451 
   1452 	/*
   1453 	 * paranoid check
   1454 	 */
   1455 	if (node == DI_NODE_NIL) {
   1456 		errno = EINVAL;
   1457 		return (DI_PROP_NIL);
   1458 	}
   1459 
   1460 	/*
   1461 	 * Find which prop list we are at
   1462 	 */
   1463 	if (prop != DI_PROP_NIL)
   1464 		list = DI_PROP(prop)->prop_list;
   1465 
   1466 	do {
   1467 		switch (list++) {
   1468 		case DI_PROP_DRV_LIST:
   1469 			prop = di_prop_drv_next(node, prop);
   1470 			break;
   1471 		case DI_PROP_SYS_LIST:
   1472 			prop = di_prop_sys_next(node, prop);
   1473 			break;
   1474 		case DI_PROP_GLB_LIST:
   1475 			prop = di_prop_global_next(node, prop);
   1476 			break;
   1477 		case DI_PROP_HW_LIST:
   1478 			prop = di_prop_hw_next(node, prop);
   1479 			break;
   1480 		default:	/* shouldn't happen */
   1481 			errno = EFAULT;
   1482 			return (DI_PROP_NIL);
   1483 		}
   1484 	} while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
   1485 
   1486 	return (prop);
   1487 }
   1488 
   1489 dev_t
   1490 di_prop_devt(di_prop_t prop)
   1491 {
   1492 	return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
   1493 }
   1494 
   1495 char *
   1496 di_prop_name(di_prop_t prop)
   1497 {
   1498 	if (DI_PROP(prop)->prop_name == 0)
   1499 		return (NULL);
   1500 
   1501 	return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
   1502 }
   1503 
   1504 int
   1505 di_prop_type(di_prop_t prop)
   1506 {
   1507 	uint_t flags = DI_PROP(prop)->prop_flags;
   1508 
   1509 	if (flags & DDI_PROP_UNDEF_IT)
   1510 		return (DI_PROP_TYPE_UNDEF_IT);
   1511 
   1512 	if (DI_PROP(prop)->prop_len == 0)
   1513 		return (DI_PROP_TYPE_BOOLEAN);
   1514 
   1515 	if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
   1516 		return (DI_PROP_TYPE_UNKNOWN);
   1517 
   1518 	if (flags & DDI_PROP_TYPE_INT)
   1519 		return (DI_PROP_TYPE_INT);
   1520 
   1521 	if (flags & DDI_PROP_TYPE_INT64)
   1522 		return (DI_PROP_TYPE_INT64);
   1523 
   1524 	if (flags & DDI_PROP_TYPE_STRING)
   1525 		return (DI_PROP_TYPE_STRING);
   1526 
   1527 	if (flags & DDI_PROP_TYPE_BYTE)
   1528 		return (DI_PROP_TYPE_BYTE);
   1529 
   1530 	/*
   1531 	 * Shouldn't get here. In case we do, return unknown type.
   1532 	 *
   1533 	 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
   1534 	 *	to add DI_PROP_TYPE_COMPOSITE.
   1535 	 */
   1536 	DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
   1537 
   1538 	return (DI_PROP_TYPE_UNKNOWN);
   1539 }
   1540 
   1541 /*
   1542  * Extract type-specific values of an property
   1543  */
   1544 extern int di_prop_decode_common(void *prop_data, int len,
   1545 	int ddi_type, int prom);
   1546 
   1547 int
   1548 di_prop_ints(di_prop_t prop, int **prop_data)
   1549 {
   1550 	if (DI_PROP(prop)->prop_len == 0)
   1551 		return (0);	/* boolean property */
   1552 
   1553 	if ((DI_PROP(prop)->prop_data == 0) ||
   1554 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
   1555 		errno = EFAULT;
   1556 		*prop_data = NULL;
   1557 		return (-1);
   1558 	}
   1559 
   1560 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
   1561 	    + DI_PROP(prop)->prop_data));
   1562 
   1563 	return (di_prop_decode_common((void *)prop_data,
   1564 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
   1565 }
   1566 
   1567 int
   1568 di_prop_int64(di_prop_t prop, int64_t **prop_data)
   1569 {
   1570 	if (DI_PROP(prop)->prop_len == 0)
   1571 		return (0);	/* boolean property */
   1572 
   1573 	if ((DI_PROP(prop)->prop_data == 0) ||
   1574 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
   1575 		errno = EFAULT;
   1576 		*prop_data = NULL;
   1577 		return (-1);
   1578 	}
   1579 
   1580 	*prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
   1581 	    + DI_PROP(prop)->prop_data));
   1582 
   1583 	return (di_prop_decode_common((void *)prop_data,
   1584 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
   1585 }
   1586 
   1587 int
   1588 di_prop_strings(di_prop_t prop, char **prop_data)
   1589 {
   1590 	if (DI_PROP(prop)->prop_len == 0)
   1591 		return (0);	/* boolean property */
   1592 
   1593 	if ((DI_PROP(prop)->prop_data == 0) ||
   1594 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
   1595 		errno = EFAULT;
   1596 		*prop_data = NULL;
   1597 		return (-1);
   1598 	}
   1599 
   1600 	*prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
   1601 	    + DI_PROP(prop)->prop_data);
   1602 
   1603 	return (di_prop_decode_common((void *)prop_data,
   1604 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
   1605 }
   1606 
   1607 int
   1608 di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
   1609 {
   1610 	if (DI_PROP(prop)->prop_len == 0)
   1611 		return (0);	/* boolean property */
   1612 
   1613 	if ((DI_PROP(prop)->prop_data == 0) ||
   1614 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
   1615 		errno = EFAULT;
   1616 		*prop_data = NULL;
   1617 		return (-1);
   1618 	}
   1619 
   1620 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
   1621 	    + DI_PROP(prop)->prop_data);
   1622 
   1623 	return (di_prop_decode_common((void *)prop_data,
   1624 	    DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
   1625 }
   1626 
   1627 /*
   1628  * returns 1 for match, 0 for no match
   1629  */
   1630 static int
   1631 match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
   1632 {
   1633 	int prop_type;
   1634 
   1635 #ifdef DEBUG
   1636 	if (di_prop_name(prop) == NULL) {
   1637 		DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
   1638 		return (0);
   1639 	}
   1640 #endif /* DEBUG */
   1641 
   1642 	if (strcmp(name, di_prop_name(prop)) != 0)
   1643 		return (0);
   1644 
   1645 	if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
   1646 		return (0);
   1647 
   1648 	/*
   1649 	 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
   1650 	 */
   1651 	prop_type = di_prop_type(prop);
   1652 	if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) &&
   1653 	    (prop_type != DI_PROP_TYPE_BOOLEAN))
   1654 		return (0);
   1655 
   1656 	return (1);
   1657 }
   1658 
   1659 static di_prop_t
   1660 di_prop_search(dev_t match_dev, di_node_t node, const char *name,
   1661     int type)
   1662 {
   1663 	di_prop_t prop = DI_PROP_NIL;
   1664 
   1665 	/*
   1666 	 * The check on match_dev follows ddi_prop_lookup_common().
   1667 	 * Other checks are libdevinfo specific implementation.
   1668 	 */
   1669 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
   1670 	    (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) {
   1671 		errno = EINVAL;
   1672 		return (DI_PROP_NIL);
   1673 	}
   1674 
   1675 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
   1676 		DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n",
   1677 		    di_prop_name(prop), di_prop_devt(prop),
   1678 		    di_prop_type(prop)));
   1679 		if (match_prop(prop, match_dev, name, type))
   1680 			return (prop);
   1681 	}
   1682 
   1683 	return (DI_PROP_NIL);
   1684 }
   1685 
   1686 di_prop_t
   1687 di_prop_find(dev_t match_dev, di_node_t node, const char *name)
   1688 {
   1689 	di_prop_t prop = DI_PROP_NIL;
   1690 
   1691 	if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
   1692 	    (match_dev == DDI_DEV_T_NONE)) {
   1693 		errno = EINVAL;
   1694 		return (DI_PROP_NIL);
   1695 	}
   1696 
   1697 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
   1698 		DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n",
   1699 		    di_prop_name(prop), di_prop_devt(prop),
   1700 		    di_prop_type(prop)));
   1701 
   1702 		if (strcmp(name, di_prop_name(prop)) == 0 &&
   1703 		    (match_dev == DDI_DEV_T_ANY ||
   1704 		    di_prop_devt(prop) == match_dev))
   1705 			return (prop);
   1706 	}
   1707 
   1708 	return (DI_PROP_NIL);
   1709 }
   1710 
   1711 int
   1712 di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
   1713 	int **prop_data)
   1714 {
   1715 	di_prop_t prop;
   1716 
   1717 	if ((prop = di_prop_search(dev, node, prop_name,
   1718 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
   1719 		return (-1);
   1720 
   1721 	return (di_prop_ints(prop, (void *)prop_data));
   1722 }
   1723 
   1724 int
   1725 di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
   1726 	int64_t **prop_data)
   1727 {
   1728 	di_prop_t prop;
   1729 
   1730 	if ((prop = di_prop_search(dev, node, prop_name,
   1731 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
   1732 		return (-1);
   1733 
   1734 	return (di_prop_int64(prop, (void *)prop_data));
   1735 }
   1736 
   1737 int
   1738 di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
   1739     char **prop_data)
   1740 {
   1741 	di_prop_t prop;
   1742 
   1743 	if ((prop = di_prop_search(dev, node, prop_name,
   1744 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
   1745 		return (-1);
   1746 
   1747 	return (di_prop_strings(prop, (void *)prop_data));
   1748 }
   1749 
   1750 int
   1751 di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
   1752 	uchar_t **prop_data)
   1753 {
   1754 	di_prop_t prop;
   1755 
   1756 	if ((prop = di_prop_search(dev, node, prop_name,
   1757 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
   1758 		return (-1);
   1759 
   1760 	return (di_prop_bytes(prop, (void *)prop_data));
   1761 }
   1762 
   1763 /*
   1764  * Consolidation private property access functions
   1765  */
   1766 enum prop_type {
   1767 	PROP_TYPE_DRV,
   1768 	PROP_TYPE_SYS,
   1769 	PROP_TYPE_GLOB,
   1770 	PROP_TYPE_HW
   1771 };
   1772 
   1773 static di_prop_t
   1774 di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
   1775 {
   1776 	caddr_t pa;
   1777 	di_off_t prop_off = 0;
   1778 
   1779 	if (prop != DI_PROP_NIL) {
   1780 		if (DI_PROP(prop)->next) {
   1781 			return (DI_PROP((caddr_t)prop -
   1782 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
   1783 		} else {
   1784 			return (DI_PROP_NIL);
   1785 		}
   1786 	}
   1787 
   1788 
   1789 	/*
   1790 	 * prop is NIL, caller asks for first property
   1791 	 */
   1792 	pa = (caddr_t)node - DI_NODE(node)->self;
   1793 	switch (prop_type) {
   1794 	case PROP_TYPE_DRV:
   1795 		prop_off = DI_NODE(node)->drv_prop;
   1796 		break;
   1797 	case PROP_TYPE_SYS:
   1798 		prop_off = DI_NODE(node)->sys_prop;
   1799 		break;
   1800 	case PROP_TYPE_HW:
   1801 		prop_off = DI_NODE(node)->hw_prop;
   1802 		break;
   1803 	case PROP_TYPE_GLOB:
   1804 		prop_off = DI_NODE(node)->glob_prop;
   1805 		if (prop_off == -1) {
   1806 			/* no global property */
   1807 			prop_off = 0;
   1808 		} else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) {
   1809 			/* refer to devnames array */
   1810 			struct di_devnm *devnm = DI_DEVNM(pa +
   1811 			    DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major *
   1812 			    sizeof (struct di_devnm)));
   1813 			prop_off = devnm->global_prop;
   1814 		}
   1815 		break;
   1816 	}
   1817 
   1818 	if (prop_off) {
   1819 		return (DI_PROP(pa + prop_off));
   1820 	}
   1821 
   1822 	/*
   1823 	 * no prop found. Check the reason for not found
   1824 	 */
   1825 	if (DINFOPROP & DI_ALL(pa)->command)
   1826 		errno = ENXIO;
   1827 	else
   1828 		errno = ENOTSUP;
   1829 
   1830 	return (DI_PROP_NIL);
   1831 }
   1832 
   1833 di_prop_t
   1834 di_prop_drv_next(di_node_t node, di_prop_t prop)
   1835 {
   1836 	return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
   1837 }
   1838 
   1839 di_prop_t
   1840 di_prop_sys_next(di_node_t node, di_prop_t prop)
   1841 {
   1842 	return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
   1843 }
   1844 
   1845 di_prop_t
   1846 di_prop_global_next(di_node_t node, di_prop_t prop)
   1847 {
   1848 	return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
   1849 }
   1850 
   1851 di_prop_t
   1852 di_prop_hw_next(di_node_t node, di_prop_t prop)
   1853 {
   1854 	return (di_prop_next_common(node, prop, PROP_TYPE_HW));
   1855 }
   1856 
   1857 int
   1858 di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
   1859 {
   1860 #ifdef DEBUG
   1861 	if (prop == DI_PROP_NIL) {
   1862 		errno = EINVAL;
   1863 		return (-1);
   1864 	}
   1865 #endif /* DEBUG */
   1866 
   1867 	if (DI_PROP(prop)->prop_len == 0) {
   1868 		*prop_data = NULL;
   1869 		return (0);
   1870 	}
   1871 
   1872 	if ((DI_PROP(prop)->prop_data == 0) ||
   1873 	    (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
   1874 		errno = EFAULT;
   1875 		*prop_data = NULL;
   1876 		return (-1);
   1877 	}
   1878 
   1879 	/*
   1880 	 * No memory allocation.
   1881 	 */
   1882 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
   1883 	    DI_PROP(prop)->prop_data);
   1884 
   1885 	return (DI_PROP(prop)->prop_len);
   1886 }
   1887 
   1888 /*
   1889  * Consolidation private interfaces for accessing I/O multipathing data
   1890  */
   1891 di_path_t
   1892 di_path_phci_next_path(di_node_t node, di_path_t path)
   1893 {
   1894 	caddr_t pa;
   1895 
   1896 	/*
   1897 	 * path is not NIL
   1898 	 */
   1899 	if (path != DI_PATH_NIL) {
   1900 		if (DI_PATH(path)->path_p_link != 0)
   1901 			return (DI_PATH((void *)((caddr_t)path -
   1902 			    DI_PATH(path)->self + DI_PATH(path)->path_p_link)));
   1903 		else {
   1904 			errno = ENXIO;
   1905 			return (DI_PATH_NIL);
   1906 		}
   1907 	}
   1908 
   1909 	/*
   1910 	 * Path is NIL; the caller is asking for the first path info node
   1911 	 */
   1912 	if (DI_NODE(node)->multipath_phci != 0) {
   1913 		DPRINTF((DI_INFO, "phci_next_path: returning %p\n",
   1914 		    ((caddr_t)node -
   1915 		    DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
   1916 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
   1917 		    DI_NODE(node)->multipath_phci));
   1918 	}
   1919 
   1920 	/*
   1921 	 * No pathing data; check if the snapshot includes path data in order
   1922 	 * to set errno properly.
   1923 	 */
   1924 	pa = (caddr_t)node - DI_NODE(node)->self;
   1925 	if (DINFOPATH & (DI_ALL(pa)->command))
   1926 		errno = ENXIO;
   1927 	else
   1928 		errno = ENOTSUP;
   1929 
   1930 	return (DI_PATH_NIL);
   1931 }
   1932 
   1933 di_path_t
   1934 di_path_client_next_path(di_node_t node, di_path_t path)
   1935 {
   1936 	caddr_t pa;
   1937 
   1938 	/*
   1939 	 * path is not NIL
   1940 	 */
   1941 	if (path != DI_PATH_NIL) {
   1942 		if (DI_PATH(path)->path_c_link != 0)
   1943 			return (DI_PATH((caddr_t)path - DI_PATH(path)->self
   1944 			    + DI_PATH(path)->path_c_link));
   1945 		else {
   1946 			errno = ENXIO;
   1947 			return (DI_PATH_NIL);
   1948 		}
   1949 	}
   1950 
   1951 	/*
   1952 	 * Path is NIL; the caller is asking for the first path info node
   1953 	 */
   1954 	if (DI_NODE(node)->multipath_client != 0) {
   1955 		DPRINTF((DI_INFO, "client_next_path: returning %p\n",
   1956 		    ((caddr_t)node -
   1957 		    DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
   1958 		return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
   1959 		    DI_NODE(node)->multipath_client));
   1960 	}
   1961 
   1962 	/*
   1963 	 * No pathing data; check if the snapshot includes path data in order
   1964 	 * to set errno properly.
   1965 	 */
   1966 	pa = (caddr_t)node - DI_NODE(node)->self;
   1967 	if (DINFOPATH & (DI_ALL(pa)->command))
   1968 		errno = ENXIO;
   1969 	else
   1970 		errno = ENOTSUP;
   1971 
   1972 	return (DI_PATH_NIL);
   1973 }
   1974 
   1975 /*
   1976  * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
   1977  * below after NWS consolidation switches to using di_path_bus_addr,
   1978  * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
   1979  */
   1980 char *
   1981 di_path_addr(di_path_t path, char *buf)
   1982 {
   1983 	caddr_t pa;		/* starting address of map */
   1984 
   1985 	pa = (caddr_t)path - DI_PATH(path)->self;
   1986 
   1987 	(void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
   1988 	    MAXPATHLEN);
   1989 	return (buf);
   1990 }
   1991 di_path_t
   1992 di_path_next(di_node_t node, di_path_t path)
   1993 {
   1994 	if (node == DI_NODE_NIL) {
   1995 		errno = EINVAL;
   1996 		return (DI_PATH_NIL);
   1997 	}
   1998 
   1999 	if (DI_NODE(node)->multipath_client) {
   2000 		return (di_path_client_next_path(node, path));
   2001 	} else if (DI_NODE(node)->multipath_phci) {
   2002 		return (di_path_phci_next_path(node, path));
   2003 	} else {
   2004 		/*
   2005 		 * The node had multipathing data but didn't appear to be a
   2006 		 * phci *or* a client; probably a programmer error.
   2007 		 */
   2008 		errno = EINVAL;
   2009 		return (DI_PATH_NIL);
   2010 	}
   2011 }
   2012 di_path_t
   2013 di_path_next_phci(di_node_t node, di_path_t path)
   2014 {
   2015 	return (di_path_client_next_path(node, path));
   2016 }
   2017 di_path_t
   2018 di_path_next_client(di_node_t node, di_path_t path)
   2019 {
   2020 	return (di_path_phci_next_path(node, path));
   2021 }
   2022 
   2023 
   2024 
   2025 
   2026 di_path_state_t
   2027 di_path_state(di_path_t path)
   2028 {
   2029 	return ((di_path_state_t)DI_PATH(path)->path_state);
   2030 }
   2031 
   2032 uint_t
   2033 di_path_flags(di_path_t path)
   2034 {
   2035 	return (DI_PATH(path)->path_flags);
   2036 }
   2037 
   2038 char *
   2039 di_path_node_name(di_path_t path)
   2040 {
   2041 	di_node_t	client_node;
   2042 
   2043 	/* pathinfo gets node_name from client */
   2044 	if ((client_node = di_path_client_node(path)) == NULL)
   2045 		return (NULL);
   2046 	return (di_node_name(client_node));
   2047 }
   2048 
   2049 char *
   2050 di_path_bus_addr(di_path_t path)
   2051 {
   2052 	caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
   2053 
   2054 	if (DI_PATH(path)->path_addr == 0)
   2055 		return (NULL);
   2056 
   2057 	return ((char *)(pa + DI_PATH(path)->path_addr));
   2058 }
   2059 
   2060 int
   2061 di_path_instance(di_path_t path)
   2062 {
   2063 	return (DI_PATH(path)->path_instance);
   2064 }
   2065 
   2066 di_node_t
   2067 di_path_client_node(di_path_t path)
   2068 {
   2069 	caddr_t pa;		/* starting address of map */
   2070 
   2071 	if (path == DI_PATH_NIL) {
   2072 		errno = EINVAL;
   2073 		return (DI_PATH_NIL);
   2074 	}
   2075 
   2076 	DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
   2077 
   2078 	pa = (caddr_t)path - DI_PATH(path)->self;
   2079 
   2080 	if (DI_PATH(path)->path_client) {
   2081 		return (DI_NODE(pa + DI_PATH(path)->path_client));
   2082 	}
   2083 
   2084 	/*
   2085 	 * Deal with error condition:
   2086 	 *   If parent doesn't exist and node is not the root,
   2087 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
   2088 	 */
   2089 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
   2090 		errno = ENOTSUP;
   2091 	else
   2092 		errno = ENXIO;
   2093 
   2094 	return (DI_NODE_NIL);
   2095 }
   2096 
   2097 di_node_t
   2098 di_path_phci_node(di_path_t path)
   2099 {
   2100 	caddr_t pa;		/* starting address of map */
   2101 
   2102 	if (path == DI_PATH_NIL) {
   2103 		errno = EINVAL;
   2104 		return (DI_PATH_NIL);
   2105 	}
   2106 
   2107 	DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
   2108 
   2109 	pa = (caddr_t)path - DI_PATH(path)->self;
   2110 
   2111 	if (DI_PATH(path)->path_phci) {
   2112 		return (DI_NODE(pa + DI_PATH(path)->path_phci));
   2113 	}
   2114 
   2115 	/*
   2116 	 * Deal with error condition:
   2117 	 *   If parent doesn't exist and node is not the root,
   2118 	 *   set errno to ENOTSUP. Otherwise, set errno to ENXIO.
   2119 	 */
   2120 	if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
   2121 		errno = ENOTSUP;
   2122 	else
   2123 		errno = ENXIO;
   2124 
   2125 	return (DI_NODE_NIL);
   2126 }
   2127 
   2128 di_path_prop_t
   2129 di_path_prop_next(di_path_t path, di_path_prop_t prop)
   2130 {
   2131 	caddr_t pa;
   2132 
   2133 	if (path == DI_PATH_NIL) {
   2134 		errno = EINVAL;
   2135 		return (DI_PROP_NIL);
   2136 	}
   2137 
   2138 	/*
   2139 	 * prop is not NIL
   2140 	 */
   2141 	if (prop != DI_PROP_NIL) {
   2142 		if (DI_PROP(prop)->next != 0)
   2143 			return (DI_PATHPROP((caddr_t)prop -
   2144 			    DI_PROP(prop)->self + DI_PROP(prop)->next));
   2145 		else {
   2146 			errno = ENXIO;
   2147 			return (DI_PROP_NIL);
   2148 		}
   2149 	}
   2150 
   2151 	/*
   2152 	 * prop is NIL-->caller asks for first property
   2153 	 */
   2154 	pa = (caddr_t)path - DI_PATH(path)->self;
   2155 	if (DI_PATH(path)->path_prop != 0) {
   2156 		return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
   2157 	}
   2158 
   2159 	/*
   2160 	 * no property data-->check if snapshot includes props
   2161 	 *	in order to set the correct errno
   2162 	 */
   2163 	if (DINFOPROP & (DI_ALL(pa)->command))
   2164 		errno = ENXIO;
   2165 	else
   2166 		errno = ENOTSUP;
   2167 
   2168 	return (DI_PROP_NIL);
   2169 }
   2170 
   2171 char *
   2172 di_path_prop_name(di_path_prop_t prop)
   2173 {
   2174 	caddr_t pa;		/* starting address of map */
   2175 	pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
   2176 	return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
   2177 }
   2178 
   2179 int
   2180 di_path_prop_len(di_path_prop_t prop)
   2181 {
   2182 	return (DI_PATHPROP(prop)->prop_len);
   2183 }
   2184 
   2185 int
   2186 di_path_prop_type(di_path_prop_t prop)
   2187 {
   2188 	switch (DI_PATHPROP(prop)->prop_type) {
   2189 		case DDI_PROP_TYPE_INT:
   2190 			return (DI_PROP_TYPE_INT);
   2191 		case DDI_PROP_TYPE_INT64:
   2192 			return (DI_PROP_TYPE_INT64);
   2193 		case DDI_PROP_TYPE_BYTE:
   2194 			return (DI_PROP_TYPE_BYTE);
   2195 		case DDI_PROP_TYPE_STRING:
   2196 			return (DI_PROP_TYPE_STRING);
   2197 	}
   2198 	return (DI_PROP_TYPE_UNKNOWN);
   2199 }
   2200 
   2201 int
   2202 di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
   2203 {
   2204 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
   2205 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
   2206 		errno = EFAULT;
   2207 		*prop_data = NULL;
   2208 		return (-1);
   2209 	}
   2210 
   2211 	*prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
   2212 	    + DI_PATHPROP(prop)->prop_data);
   2213 
   2214 	return (di_prop_decode_common((void *)prop_data,
   2215 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
   2216 }
   2217 
   2218 int
   2219 di_path_prop_ints(di_path_prop_t prop, int **prop_data)
   2220 {
   2221 	if (DI_PATHPROP(prop)->prop_len == 0)
   2222 		return (0);
   2223 
   2224 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
   2225 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
   2226 		errno = EFAULT;
   2227 		*prop_data = NULL;
   2228 		return (-1);
   2229 	}
   2230 
   2231 	*prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
   2232 	    + DI_PATHPROP(prop)->prop_data));
   2233 
   2234 	return (di_prop_decode_common((void *)prop_data,
   2235 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
   2236 }
   2237 
   2238 int
   2239 di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
   2240 {
   2241 	if (DI_PATHPROP(prop)->prop_len == 0)
   2242 		return (0);
   2243 
   2244 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
   2245 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
   2246 		errno = EFAULT;
   2247 		*prop_data = NULL;
   2248 		return (-1);
   2249 	}
   2250 
   2251 	*prop_data = (int64_t *)((void *)((caddr_t)prop -
   2252 	    DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
   2253 
   2254 	return (di_prop_decode_common((void *)prop_data,
   2255 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
   2256 }
   2257 
   2258 int
   2259 di_path_prop_strings(di_path_prop_t prop, char **prop_data)
   2260 {
   2261 	if (DI_PATHPROP(prop)->prop_len == 0)
   2262 		return (0);
   2263 
   2264 	if ((DI_PATHPROP(prop)->prop_data == 0) ||
   2265 	    (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
   2266 		errno = EFAULT;
   2267 		*prop_data = NULL;
   2268 		return (-1);
   2269 	}
   2270 
   2271 	*prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
   2272 	    + DI_PATHPROP(prop)->prop_data);
   2273 
   2274 	return (di_prop_decode_common((void *)prop_data,
   2275 	    DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
   2276 }
   2277 
   2278 static di_path_prop_t
   2279 di_path_prop_search(di_path_t path, const char *name, int type)
   2280 {
   2281 	di_path_prop_t prop = DI_PROP_NIL;
   2282 
   2283 	/*
   2284 	 * Sanity check arguments
   2285 	 */
   2286 	if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
   2287 	    !DI_PROP_TYPE_VALID(type)) {
   2288 		errno = EINVAL;
   2289 		return (DI_PROP_NIL);
   2290 	}
   2291 
   2292 	while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
   2293 		int prop_type = di_path_prop_type(prop);
   2294 
   2295 		DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
   2296 		    di_path_prop_name(prop), prop_type));
   2297 
   2298 		if (strcmp(name, di_path_prop_name(prop)) != 0)
   2299 			continue;
   2300 
   2301 		if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
   2302 			continue;
   2303 
   2304 		return (prop);
   2305 	}
   2306 
   2307 	return (DI_PROP_NIL);
   2308 }
   2309 
   2310 int
   2311 di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
   2312     uchar_t **prop_data)
   2313 {
   2314 	di_path_prop_t prop;
   2315 
   2316 	if ((prop = di_path_prop_search(path, prop_name,
   2317 	    DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
   2318 		return (-1);
   2319 
   2320 	return (di_path_prop_bytes(prop, prop_data));
   2321 }
   2322 
   2323 int
   2324 di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
   2325     int **prop_data)
   2326 {
   2327 	di_path_prop_t prop;
   2328 
   2329 	if ((prop = di_path_prop_search(path, prop_name,
   2330 	    DI_PROP_TYPE_INT)) == DI_PROP_NIL)
   2331 		return (-1);
   2332 
   2333 	return (di_path_prop_ints(prop, prop_data));
   2334 }
   2335 
   2336 int
   2337 di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
   2338     int64_t **prop_data)
   2339 {
   2340 	di_path_prop_t prop;
   2341 
   2342 	if ((prop = di_path_prop_search(path, prop_name,
   2343 	    DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
   2344 		return (-1);
   2345 
   2346 	return (di_path_prop_int64s(prop, prop_data));
   2347 }
   2348 
   2349 int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
   2350     char **prop_data)
   2351 {
   2352 	di_path_prop_t prop;
   2353 
   2354 	if ((prop = di_path_prop_search(path, prop_name,
   2355 	    DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
   2356 		return (-1);
   2357 
   2358 	return (di_path_prop_strings(prop, prop_data));
   2359 }
   2360 
   2361 /*
   2362  * Consolidation private interfaces for traversing vhci nodes.
   2363  */
   2364 di_node_t
   2365 di_vhci_first_node(di_node_t root)
   2366 {
   2367 	struct di_all *dap;
   2368 	caddr_t		pa;		/* starting address of map */
   2369 
   2370 	DPRINTF((DI_INFO, "Get first vhci node\n"));
   2371 
   2372 	if (root == DI_NODE_NIL) {
   2373 		errno = EINVAL;
   2374 		return (DI_NODE_NIL);
   2375 	}
   2376 
   2377 	pa = (caddr_t)root - DI_NODE(root)->self;
   2378 	dap = DI_ALL(pa);
   2379 
   2380 	if (dap->top_vhci_devinfo == NULL) {
   2381 		errno = ENXIO;
   2382 		return (DI_NODE_NIL);
   2383 	}
   2384 
   2385 	return (DI_NODE(pa + dap->top_vhci_devinfo));
   2386 }
   2387 
   2388 di_node_t
   2389 di_vhci_next_node(di_node_t node)
   2390 {
   2391 	caddr_t		pa;		/* starting address of map */
   2392 
   2393 	if (node == DI_NODE_NIL) {
   2394 		errno = EINVAL;
   2395 		return (DI_NODE_NIL);
   2396 	}
   2397 
   2398 	DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
   2399 	    " current=%s\n", di_node_name(node)));
   2400 
   2401 	if (DI_NODE(node)->next_vhci == NULL) {
   2402 		errno = ENXIO;
   2403 		return (DI_NODE_NIL);
   2404 	}
   2405 
   2406 	pa = (caddr_t)node - DI_NODE(node)->self;
   2407 
   2408 	return (DI_NODE(pa + DI_NODE(node)->next_vhci));
   2409 }
   2410 
   2411 /*
   2412  * Consolidation private interfaces for traversing phci nodes.
   2413  */
   2414 di_node_t
   2415 di_phci_first_node(di_node_t vhci_node)
   2416 {
   2417 	caddr_t		pa;		/* starting address of map */
   2418 
   2419 	DPRINTF((DI_INFO, "Get first phci node:\n"
   2420 	    " current=%s", di_node_name(vhci_node)));
   2421 
   2422 	if (vhci_node == DI_NODE_NIL) {
   2423 		errno = EINVAL;
   2424 		return (DI_NODE_NIL);
   2425 	}
   2426 
   2427 	pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
   2428 
   2429 	if (DI_NODE(vhci_node)->top_phci == NULL) {
   2430 		errno = ENXIO;
   2431 		return (DI_NODE_NIL);
   2432 	}
   2433 
   2434 	return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
   2435 }
   2436 
   2437 di_node_t
   2438 di_phci_next_node(di_node_t node)
   2439 {
   2440 	caddr_t		pa;		/* starting address of map */
   2441 
   2442 	if (node == DI_NODE_NIL) {
   2443 		errno = EINVAL;
   2444 		return (DI_NODE_NIL);
   2445 	}
   2446 
   2447 	DPRINTF((DI_TRACE, "next phci node on the snap shot:"
   2448 	    " current=%s\n", di_node_name(node)));
   2449 
   2450 	if (DI_NODE(node)->next_phci == NULL) {
   2451 		errno = ENXIO;
   2452 		return (DI_NODE_NIL);
   2453 	}
   2454 
   2455 	pa = (caddr_t)node - DI_NODE(node)->self;
   2456 
   2457 	return (DI_NODE(pa + DI_NODE(node)->next_phci));
   2458 }
   2459 
   2460 /*
   2461  * Consolidation private interfaces for private data
   2462  */
   2463 void *
   2464 di_parent_private_data(di_node_t node)
   2465 {
   2466 	caddr_t pa;
   2467 
   2468 	if (DI_NODE(node)->parent_data == 0) {
   2469 		errno = ENXIO;
   2470 		return (NULL);
   2471 	}
   2472 
   2473 	if (DI_NODE(node)->parent_data == (di_off_t)-1) {
   2474 		/*
   2475 		 * Private data requested, but not obtained due to a memory
   2476 		 * error (e.g. wrong format specified)
   2477 		 */
   2478 		errno = EFAULT;
   2479 		return (NULL);
   2480 	}
   2481 
   2482 	pa = (caddr_t)node - DI_NODE(node)->self;
   2483 	if (DI_NODE(node)->parent_data)
   2484 		return (pa + DI_NODE(node)->parent_data);
   2485 
   2486 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
   2487 		errno = ENXIO;
   2488 	else
   2489 		errno = ENOTSUP;
   2490 
   2491 	return (NULL);
   2492 }
   2493 
   2494 void *
   2495 di_driver_private_data(di_node_t node)
   2496 {
   2497 	caddr_t pa;
   2498 
   2499 	if (DI_NODE(node)->driver_data == 0) {
   2500 		errno = ENXIO;
   2501 		return (NULL);
   2502 	}
   2503 
   2504 	if (DI_NODE(node)->driver_data == (di_off_t)-1) {
   2505 		/*
   2506 		 * Private data requested, but not obtained due to a memory
   2507 		 * error (e.g. wrong format specified)
   2508 		 */
   2509 		errno = EFAULT;
   2510 		return (NULL);
   2511 	}
   2512 
   2513 	pa = (caddr_t)node - DI_NODE(node)->self;
   2514 	if (DI_NODE(node)->driver_data)
   2515 		return (pa + DI_NODE(node)->driver_data);
   2516 
   2517 	if (DI_ALL(pa)->command & DINFOPRIVDATA)
   2518 		errno = ENXIO;
   2519 	else
   2520 		errno = ENOTSUP;
   2521 
   2522 	return (NULL);
   2523 }
   2524 
   2525 /*
   2526  * Hotplug information access
   2527  */
   2528 
   2529 typedef struct {
   2530 	void		*arg;
   2531 	const char	*type;
   2532 	uint_t		flag;
   2533 	int		(*hp_callback)(di_node_t, di_hp_t, void *);
   2534 } di_walk_hp_arg_t;
   2535 
   2536 static int
   2537 di_walk_hp_callback(di_node_t node, void *argp)
   2538 {
   2539 	di_walk_hp_arg_t 	*arg = (di_walk_hp_arg_t *)argp;
   2540 	di_hp_t			hp;
   2541 	char			*type_str;
   2542 
   2543 	for (hp = DI_HP_NIL; (hp = di_hp_next(node, hp)) != DI_HP_NIL; ) {
   2544 
   2545 		/* Exclude non-matching types if a type filter is specified */
   2546 		if (arg->type != NULL) {
   2547 			type_str = di_hp_description(hp);
   2548 			if (type_str && (strcmp(arg->type, type_str) != 0))
   2549 				continue;
   2550 		}
   2551 
   2552 		/* Exclude ports if DI_HP_PORT flag not specified */
   2553 		if (!(arg->flag & DI_HP_PORT) &&
   2554 		    (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
   2555 			continue;
   2556 
   2557 		/* Exclude connectors if DI_HP_CONNECTOR flag not specified */
   2558 		if (!(arg->flag & DI_HP_CONNECTOR) &&
   2559 		    !(di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
   2560 			continue;
   2561 
   2562 		/* Perform callback */
   2563 		if (arg->hp_callback(node, hp, arg->arg) != DI_WALK_CONTINUE)
   2564 			return (DI_WALK_TERMINATE);
   2565 	}
   2566 
   2567 	return (DI_WALK_CONTINUE);
   2568 }
   2569 
   2570 int
   2571 di_walk_hp(di_node_t node, const char *type, uint_t flag, void *arg,
   2572     int (*hp_callback)(di_node_t node, di_hp_t hp, void *arg))
   2573 {
   2574 	di_walk_hp_arg_t	walk_arg;
   2575 	caddr_t			pa;
   2576 
   2577 #ifdef DEBUG
   2578 	char	*devfspath = di_devfs_path(node);
   2579 	DPRINTF((DI_INFO, "walking hotplug nodes under %s\n", devfspath));
   2580 	di_devfs_path_free(devfspath);
   2581 #endif
   2582 	/*
   2583 	 * paranoid error checking
   2584 	 */
   2585 	if ((node == DI_NODE_NIL) || (hp_callback == NULL)) {
   2586 		errno = EINVAL;
   2587 		return (-1);
   2588 	}
   2589 
   2590 	/* check if hotplug data is included in snapshot */
   2591 	pa = (caddr_t)node - DI_NODE(node)->self;
   2592 	if (!(DI_ALL(pa)->command & DINFOHP)) {
   2593 		errno = ENOTSUP;
   2594 		return (-1);
   2595 	}
   2596 
   2597 	walk_arg.arg = arg;
   2598 	walk_arg.type = type;
   2599 	walk_arg.flag = flag;
   2600 	walk_arg.hp_callback = hp_callback;
   2601 	return (di_walk_node(node, DI_WALK_CLDFIRST, &walk_arg,
   2602 	    di_walk_hp_callback));
   2603 }
   2604 
   2605 di_hp_t
   2606 di_hp_next(di_node_t node, di_hp_t hp)
   2607 {
   2608 	caddr_t pa;
   2609 
   2610 	/*
   2611 	 * paranoid error checking
   2612 	 */
   2613 	if (node == DI_NODE_NIL) {
   2614 		errno = EINVAL;
   2615 		return (DI_HP_NIL);
   2616 	}
   2617 
   2618 	/*
   2619 	 * hotplug node is not NIL
   2620 	 */
   2621 	if (hp != DI_HP_NIL) {
   2622 		if (DI_HP(hp)->next != 0)
   2623 			return (DI_HP((caddr_t)hp - hp->self + hp->next));
   2624 		else {
   2625 			errno = ENXIO;
   2626 			return (DI_HP_NIL);
   2627 		}
   2628 	}
   2629 
   2630 	/*
   2631 	 * hotplug node is NIL-->caller asks for first hotplug node
   2632 	 */
   2633 	if (DI_NODE(node)->hp_data != 0) {
   2634 		return (DI_HP((caddr_t)node - DI_NODE(node)->self +
   2635 		    DI_NODE(node)->hp_data));
   2636 	}
   2637 
   2638 	/*
   2639 	 * no hotplug data-->check if snapshot includes hotplug data
   2640 	 *	in order to set the correct errno
   2641 	 */
   2642 	pa = (caddr_t)node - DI_NODE(node)->self;
   2643 	if (DINFOHP & DI_ALL(pa)->command)
   2644 		errno = ENXIO;
   2645 	else
   2646 		errno = ENOTSUP;
   2647 
   2648 	return (DI_HP_NIL);
   2649 }
   2650 
   2651 char *
   2652 di_hp_name(di_hp_t hp)
   2653 {
   2654 	caddr_t pa;
   2655 
   2656 	/*
   2657 	 * paranoid error checking
   2658 	 */
   2659 	if (hp == DI_HP_NIL) {
   2660 		errno = EINVAL;
   2661 		return (NULL);
   2662 	}
   2663 
   2664 	pa = (caddr_t)hp - DI_HP(hp)->self;
   2665 
   2666 	if (DI_HP(hp)->hp_name == 0) {
   2667 		errno = ENXIO;
   2668 		return (NULL);
   2669 	}
   2670 
   2671 	return ((char *)(pa + DI_HP(hp)->hp_name));
   2672 }
   2673 
   2674 int
   2675 di_hp_connection(di_hp_t hp)
   2676 {
   2677 	/*
   2678 	 * paranoid error checking
   2679 	 */
   2680 	if (hp == DI_HP_NIL) {
   2681 		errno = EINVAL;
   2682 		return (-1);
   2683 	}
   2684 
   2685 	if (DI_HP(hp)->hp_connection == -1)
   2686 		errno = ENOENT;
   2687 
   2688 	return (DI_HP(hp)->hp_connection);
   2689 }
   2690 
   2691 int
   2692 di_hp_depends_on(di_hp_t hp)
   2693 {
   2694 	/*
   2695 	 * paranoid error checking
   2696 	 */
   2697 	if (hp == DI_HP_NIL) {
   2698 		errno = EINVAL;
   2699 		return (-1);
   2700 	}
   2701 
   2702 	if (DI_HP(hp)->hp_depends_on == -1)
   2703 		errno = ENOENT;
   2704 
   2705 	return (DI_HP(hp)->hp_depends_on);
   2706 }
   2707 
   2708 int
   2709 di_hp_state(di_hp_t hp)
   2710 {
   2711 	/*
   2712 	 * paranoid error checking
   2713 	 */
   2714 	if (hp == DI_HP_NIL) {
   2715 		errno = EINVAL;
   2716 		return (-1);
   2717 	}
   2718 
   2719 	return (DI_HP(hp)->hp_state);
   2720 }
   2721 
   2722 int
   2723 di_hp_type(di_hp_t hp)
   2724 {
   2725 	/*
   2726 	 * paranoid error checking
   2727 	 */
   2728 	if (hp == DI_HP_NIL) {
   2729 		errno = EINVAL;
   2730 		return (-1);
   2731 	}
   2732 
   2733 	return (DI_HP(hp)->hp_type);
   2734 }
   2735 
   2736 char *
   2737 di_hp_description(di_hp_t hp)
   2738 {
   2739 	caddr_t pa;
   2740 
   2741 	/*
   2742 	 * paranoid error checking
   2743 	 */
   2744 	if (hp == DI_HP_NIL) {
   2745 		errno = EINVAL;
   2746 		return (NULL);
   2747 	}
   2748 
   2749 	pa = (caddr_t)hp - DI_HP(hp)->self;
   2750 
   2751 	if (DI_HP(hp)->hp_type_str == 0)
   2752 		return (NULL);
   2753 
   2754 	return ((char *)(pa + DI_HP(hp)->hp_type_str));
   2755 }
   2756 
   2757 di_node_t
   2758 di_hp_child(di_hp_t hp)
   2759 {
   2760 	caddr_t pa;		/* starting address of map */
   2761 
   2762 	/*
   2763 	 * paranoid error checking
   2764 	 */
   2765 	if (hp == DI_HP_NIL) {
   2766 		errno = EINVAL;
   2767 		return (DI_NODE_NIL);
   2768 	}
   2769 
   2770 	pa = (caddr_t)hp - DI_HP(hp)->self;
   2771 
   2772 	if (DI_HP(hp)->hp_child > 0) {
   2773 		return (DI_NODE(pa + DI_HP(hp)->hp_child));
   2774 	}
   2775 
   2776 	/*
   2777 	 * Deal with error condition:
   2778 	 *   Child doesn't exist, figure out if DINFOSUBTREE is set.
   2779 	 *   If it isn't, set errno to ENOTSUP.
   2780 	 */
   2781 	if (!(DINFOSUBTREE & DI_ALL(pa)->command))
   2782 		errno = ENOTSUP;
   2783 	else
   2784 		errno = ENXIO;
   2785 
   2786 	return (DI_NODE_NIL);
   2787 }
   2788 
   2789 time_t
   2790 di_hp_last_change(di_hp_t hp)
   2791 {
   2792 	/*
   2793 	 * paranoid error checking
   2794 	 */
   2795 	if (hp == DI_HP_NIL) {
   2796 		errno = EINVAL;
   2797 		return ((time_t)0);
   2798 	}
   2799 
   2800 	return ((time_t)DI_HP(hp)->hp_last_change);
   2801 }
   2802 
   2803 /*
   2804  * PROM property access
   2805  */
   2806 
   2807 /*
   2808  * openprom driver stuff:
   2809  *	The maximum property length depends on the buffer size. We use
   2810  *	OPROMMAXPARAM defined in <sys/openpromio.h>
   2811  *
   2812  *	MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
   2813  *	MAXVALSZ is maximum value size, which is whatever space left in buf
   2814  */
   2815 
   2816 #define	OBP_MAXBUF	OPROMMAXPARAM - sizeof (int)
   2817 #define	OBP_MAXPROPLEN	OBP_MAXBUF - OBP_MAXPROPNAME;
   2818 
   2819 struct di_prom_prop {
   2820 	char *name;
   2821 	int len;
   2822 	uchar_t *data;
   2823 	struct di_prom_prop *next;	/* form a linked list */
   2824 };
   2825 
   2826 struct di_prom_handle { /* handle to prom */
   2827 	mutex_t lock;	/* synchronize access to openprom fd */
   2828 	int	fd;	/* /dev/openprom file descriptor */
   2829 	struct di_prom_prop *list;	/* linked list of prop */
   2830 	union {
   2831 		char buf[OPROMMAXPARAM];
   2832 		struct openpromio opp;
   2833 	} oppbuf;
   2834 };
   2835 
   2836 di_prom_handle_t
   2837 di_prom_init()
   2838 {
   2839 	struct di_prom_handle *p;
   2840 
   2841 	if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
   2842 		return (DI_PROM_HANDLE_NIL);
   2843 
   2844 	DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
   2845 
   2846 	(void) mutex_init(&p->lock, USYNC_THREAD, NULL);
   2847 	if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
   2848 		free(p);
   2849 		return (DI_PROM_HANDLE_NIL);
   2850 	}
   2851 	p->list = NULL;
   2852 
   2853 	return ((di_prom_handle_t)p);
   2854 }
   2855 
   2856 static void
   2857 di_prom_prop_free(struct di_prom_prop *list)
   2858 {
   2859 	struct di_prom_prop *tmp = list;
   2860 
   2861 	while (tmp != NULL) {
   2862 		list = tmp->next;
   2863 		if (tmp->name != NULL) {
   2864 			free(tmp->name);
   2865 		}
   2866 		if (tmp->data != NULL) {
   2867 			free(tmp->data);
   2868 		}
   2869 		free(tmp);
   2870 		tmp = list;
   2871 	}
   2872 }
   2873 
   2874 void
   2875 di_prom_fini(di_prom_handle_t ph)
   2876 {
   2877 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
   2878 
   2879 	DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
   2880 
   2881 	(void) close(p->fd);
   2882 	(void) mutex_destroy(&p->lock);
   2883 	di_prom_prop_free(p->list);
   2884 
   2885 	free(p);
   2886 }
   2887 
   2888 /*
   2889  * Internal library interface for locating the property
   2890  * XXX: ph->lock must be held for the duration of call.
   2891  */
   2892 static di_prom_prop_t
   2893 di_prom_prop_found(di_prom_handle_t ph, int nodeid,
   2894 	di_prom_prop_t prom_prop)
   2895 {
   2896 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
   2897 	struct openpromio *opp = &p->oppbuf.opp;
   2898 	int *ip = (int *)((void *)opp->oprom_array);
   2899 	struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
   2900 
   2901 	DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
   2902 
   2903 	/*
   2904 	 * Set "current" nodeid in the openprom driver
   2905 	 */
   2906 	opp->oprom_size = sizeof (int);
   2907 	*ip = nodeid;
   2908 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
   2909 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
   2910 		return (DI_PROM_PROP_NIL);
   2911 	}
   2912 
   2913 	DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
   2914 
   2915 	bzero(opp, OBP_MAXBUF);
   2916 	opp->oprom_size = OBP_MAXPROPNAME;
   2917 	if (prom_prop != DI_PROM_PROP_NIL)
   2918 		(void) strcpy(opp->oprom_array, prop->name);
   2919 
   2920 	if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
   2921 		return (DI_PROM_PROP_NIL);
   2922 
   2923 	/*
   2924 	 * Prom property found. Allocate struct for storing prop
   2925 	 *   (reuse variable prop)
   2926 	 */
   2927 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
   2928 		return (DI_PROM_PROP_NIL);
   2929 
   2930 	/*
   2931 	 * Get a copy of property name
   2932 	 */
   2933 	if ((prop->name = strdup(opp->oprom_array)) == NULL) {
   2934 		free(prop);
   2935 		return (DI_PROM_PROP_NIL);
   2936 	}
   2937 
   2938 	/*
   2939 	 * get property value and length
   2940 	 */
   2941 	opp->oprom_size = OBP_MAXPROPLEN;
   2942 
   2943 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
   2944 	    (opp->oprom_size == (uint_t)-1)) {
   2945 		free(prop->name);
   2946 		free(prop);
   2947 		return (DI_PROM_PROP_NIL);
   2948 	}
   2949 
   2950 	/*
   2951 	 * make a copy of the property value
   2952 	 */
   2953 	prop->len = opp->oprom_size;
   2954 
   2955 	if (prop->len == 0)
   2956 		prop->data = NULL;
   2957 	else if ((prop->data = malloc(prop->len)) == NULL) {
   2958 		free(prop->name);
   2959 		free(prop);
   2960 		return (DI_PROM_PROP_NIL);
   2961 	}
   2962 
   2963 	bcopy(opp->oprom_array, prop->data, prop->len);
   2964 
   2965 	/*
   2966 	 * Prepend prop to list in prom handle
   2967 	 */
   2968 	prop->next = p->list;
   2969 	p->list = prop;
   2970 
   2971 	return ((di_prom_prop_t)prop);
   2972 }
   2973 
   2974 di_prom_prop_t
   2975 di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
   2976 {
   2977 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
   2978 
   2979 	DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
   2980 	    node, p));
   2981 
   2982 	/*
   2983 	 * paranoid check
   2984 	 */
   2985 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
   2986 		errno = EINVAL;
   2987 		return (DI_PROM_PROP_NIL);
   2988 	}
   2989 
   2990 	if (di_nodeid(node) != DI_PROM_NODEID) {
   2991 		errno = ENXIO;
   2992 		return (DI_PROM_PROP_NIL);
   2993 	}
   2994 
   2995 	/*
   2996 	 * synchronize access to prom file descriptor
   2997 	 */
   2998 	(void) mutex_lock(&p->lock);
   2999 
   3000 	/*
   3001 	 * look for next property
   3002 	 */
   3003 	prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
   3004 
   3005 	(void) mutex_unlock(&p->lock);
   3006 
   3007 	return (prom_prop);
   3008 }
   3009 
   3010 char *
   3011 di_prom_prop_name(di_prom_prop_t prom_prop)
   3012 {
   3013 	/*
   3014 	 * paranoid check
   3015 	 */
   3016 	if (prom_prop == DI_PROM_PROP_NIL) {
   3017 		errno = EINVAL;
   3018 		return (NULL);
   3019 	}
   3020 
   3021 	return (((struct di_prom_prop *)prom_prop)->name);
   3022 }
   3023 
   3024 int
   3025 di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
   3026 {
   3027 	/*
   3028 	 * paranoid check
   3029 	 */
   3030 	if (prom_prop == DI_PROM_PROP_NIL) {
   3031 		errno = EINVAL;
   3032 		return (NULL);
   3033 	}
   3034 
   3035 	*prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
   3036 
   3037 	return (((struct di_prom_prop *)prom_prop)->len);
   3038 }
   3039 
   3040 /*
   3041  * Internal library interface for locating the property
   3042  *    Returns length if found, -1 if prop doesn't exist.
   3043  */
   3044 static struct di_prom_prop *
   3045 di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
   3046 	const char *prom_prop_name)
   3047 {
   3048 	struct openpromio *opp;
   3049 	struct di_prom_prop *prop;
   3050 	struct di_prom_handle *p = (struct di_prom_handle *)ph;
   3051 
   3052 	/*
   3053 	 * paranoid check
   3054 	 */
   3055 	if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
   3056 		errno = EINVAL;
   3057 		return (NULL);
   3058 	}
   3059 
   3060 	if (di_nodeid(node) != DI_PROM_NODEID) {
   3061 		errno = ENXIO;
   3062 		return (NULL);
   3063 	}
   3064 
   3065 	opp = &p->oppbuf.opp;
   3066 
   3067 	(void) mutex_lock(&p->lock);
   3068 
   3069 	opp->oprom_size = sizeof (int);
   3070 	opp->oprom_node = DI_NODE(node)->nodeid;
   3071 	if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
   3072 		errno = ENXIO;
   3073 		DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
   3074 		    DI_NODE(node)->nodeid));
   3075 		(void) mutex_unlock(&p->lock);
   3076 		return (NULL);
   3077 	}
   3078 
   3079 	/*
   3080 	 * get property length
   3081 	 */
   3082 	bzero(opp, OBP_MAXBUF);
   3083 	opp->oprom_size = OBP_MAXPROPLEN;
   3084 	(void) strcpy(opp->oprom_array, prom_prop_name);
   3085 
   3086 	if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
   3087 	    (opp->oprom_len == -1)) {
   3088 		/* no such property */
   3089 		(void) mutex_unlock(&p->lock);
   3090 		return (NULL);
   3091 	}
   3092 
   3093 	/*
   3094 	 * Prom property found. Allocate struct for storing prop
   3095 	 */
   3096 	if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
   3097 		(void) mutex_unlock(&p->lock);
   3098 		return (NULL);
   3099 	}
   3100 	prop->name = NULL;	/* we don't need the name */
   3101 	prop->len = opp->oprom_len;
   3102 
   3103 	if (prop->len == 0) {	/* boolean property */
   3104 		prop->data = NULL;
   3105 		prop->next = p->list;
   3106 		p->list = prop;
   3107 		(void) mutex_unlock(&p->lock);
   3108 		return (prop);
   3109 	}
   3110 
   3111 	/*
   3112 	 * retrieve the property value
   3113 	 */
   3114 	bzero(opp, OBP_MAXBUF);
   3115 	opp->oprom_size = OBP_MAXPROPLEN;
   3116 	(void) strcpy(opp->oprom_array, prom_prop_name);
   3117 
   3118 	if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
   3119 	    (opp->oprom_size == (uint_t)-1)) {
   3120 		/* error retrieving property value */
   3121 		(void) mutex_unlock(&p->lock);
   3122 		free(prop);
   3123 		return (NULL);
   3124 	}
   3125 
   3126 	/*
   3127 	 * make a copy of the property value, stick in ph->list
   3128 	 */
   3129 	if ((prop->data = malloc(prop->len)) == NULL) {
   3130 		(void) mutex_unlock(&p->lock);
   3131 		free(prop);
   3132 		return (NULL);
   3133 	}
   3134 
   3135 	bcopy(opp->oprom_array, prop->data, prop->len);
   3136 
   3137 	prop->next = p->list;
   3138 	p->list = prop;
   3139 	(void) mutex_unlock(&p->lock);
   3140 
   3141 	return (prop);
   3142 }
   3143 
   3144 int
   3145 di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
   3146 	const char *prom_prop_name, int **prom_prop_data)
   3147 {
   3148 	int len;
   3149 	struct di_prom_prop *prop;
   3150 
   3151 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
   3152 
   3153 	if (prop == NULL) {
   3154 		*prom_prop_data = NULL;
   3155 		return (-1);
   3156 	}
   3157 
   3158 	if (prop->len == 0) {	/* boolean property */
   3159 		*prom_prop_data = NULL;
   3160 		return (0);
   3161 	}
   3162 
   3163 	len = di_prop_decode_common((void *)&prop->data, prop->len,
   3164 	    DI_PROP_TYPE_INT, 1);
   3165 	*prom_prop_data = (int *)((void *)prop->data);
   3166 
   3167 	return (len);
   3168 }
   3169 
   3170 int
   3171 di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
   3172 	const char *prom_prop_name, char **prom_prop_data)
   3173 {
   3174 	int len;
   3175 	struct di_prom_prop *prop;
   3176 
   3177 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
   3178 
   3179 	if (prop == NULL) {
   3180 		*prom_prop_data = NULL;
   3181 		return (-1);
   3182 	}
   3183 
   3184 	if (prop->len == 0) {	/* boolean property */
   3185 		*prom_prop_data = NULL;
   3186 		return (0);
   3187 	}
   3188 
   3189 	/*
   3190 	 * Fix an openprom bug (OBP string not NULL terminated).
   3191 	 * XXX This should really be fixed in promif.
   3192 	 */
   3193 	if (((char *)prop->data)[prop->len - 1] != '\0') {
   3194 		uchar_t *tmp;
   3195 		prop->len++;
   3196 		if ((tmp = realloc(prop->data, prop->len)) == NULL)
   3197 			return (-1);
   3198 
   3199 		prop->data = tmp;
   3200 		((char *)prop->data)[prop->len - 1] = '\0';
   3201 		DPRINTF((DI_INFO, "OBP string not NULL terminated: "
   3202 		    "node=%s, prop=%s, val=%s\n",
   3203 		    di_node_name(node), prom_prop_name, prop->data));
   3204 	}
   3205 
   3206 	len = di_prop_decode_common((void *)&prop->data, prop->len,
   3207 	    DI_PROP_TYPE_STRING, 1);
   3208 	*prom_prop_data = (char *)prop->data;
   3209 
   3210 	return (len);
   3211 }
   3212 
   3213 int
   3214 di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
   3215 	const char *prom_prop_name, uchar_t **prom_prop_data)
   3216 {
   3217 	int len;
   3218 	struct di_prom_prop *prop;
   3219 
   3220 	prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
   3221 
   3222 	if (prop == NULL) {
   3223 		*prom_prop_data = NULL;
   3224 		return (-1);
   3225 	}
   3226 
   3227 	if (prop->len == 0) {	/* boolean property */
   3228 		*prom_prop_data = NULL;
   3229 		return (0);
   3230 	}
   3231 
   3232 	len = di_prop_decode_common((void *)&prop->data, prop->len,
   3233 	    DI_PROP_TYPE_BYTE, 1);
   3234 	*prom_prop_data = prop->data;
   3235 
   3236 	return (len);
   3237 }
   3238 
   3239 /*
   3240  * returns an allocated array through <prop_data> only when its count > 0
   3241  * and the number of entries (count) as the function return value;
   3242  * use di_slot_names_free() to free the array
   3243  */
   3244 int
   3245 di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
   3246 {
   3247 	int rawlen, count;
   3248 	uchar_t *rawdata;
   3249 	char *nm = di_prop_name(prop);
   3250 
   3251 	if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
   3252 		goto ERROUT;
   3253 
   3254 	rawlen = di_prop_rawdata(prop, &rawdata);
   3255 	if (rawlen <= 0 || rawdata == NULL)
   3256 		goto ERROUT;
   3257 
   3258 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
   3259 	if (count < 0 || *prop_data == NULL)
   3260 		goto ERROUT;
   3261 
   3262 	return (count);
   3263 	/*NOTREACHED*/
   3264 ERROUT:
   3265 	errno = EFAULT;
   3266 	*prop_data = NULL;
   3267 	return (-1);
   3268 }
   3269 
   3270 int
   3271 di_prop_lookup_slot_names(dev_t dev, di_node_t node,
   3272     di_slot_name_t **prop_data)
   3273 {
   3274 	di_prop_t prop;
   3275 
   3276 	/*
   3277 	 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
   3278 	 * and slot-names is properly flagged as such
   3279 	 */
   3280 	if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
   3281 	    DI_PROP_NIL) {
   3282 		*prop_data = NULL;
   3283 		return (-1);
   3284 	}
   3285 
   3286 	return (di_prop_slot_names(prop, (void *)prop_data));
   3287 }
   3288 
   3289 /*
   3290  * returns an allocated array through <prop_data> only when its count > 0
   3291  * and the number of entries (count) as the function return value;
   3292  * use di_slot_names_free() to free the array
   3293  */
   3294 int
   3295 di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
   3296 {
   3297 	int rawlen, count;
   3298 	uchar_t *rawdata;
   3299 
   3300 	rawlen = di_prom_prop_data(prom_prop, &rawdata);
   3301 	if (rawlen <= 0 || rawdata == NULL)
   3302 		goto ERROUT;
   3303 
   3304 	count = di_slot_names_decode(rawdata, rawlen, prop_data);
   3305 	if (count < 0 || *prop_data == NULL)
   3306 		goto ERROUT;
   3307 
   3308 	return (count);
   3309 	/*NOTREACHED*/
   3310 ERROUT:
   3311 	errno = EFAULT;
   3312 	*prop_data = NULL;
   3313 	return (-1);
   3314 }
   3315 
   3316 int
   3317 di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
   3318     di_slot_name_t **prop_data)
   3319 {
   3320 	struct di_prom_prop *prom_prop;
   3321 
   3322 	prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
   3323 	if (prom_prop == NULL) {
   3324 		*prop_data = NULL;
   3325 		return (-1);
   3326 	}
   3327 
   3328 	return (di_prom_prop_slot_names(prom_prop, prop_data));
   3329 }
   3330 
   3331 di_lnode_t
   3332 di_link_to_lnode(di_link_t link, uint_t endpoint)
   3333 {
   3334 	struct di_all *di_all;
   3335 
   3336 	if ((link == DI_LINK_NIL) ||
   3337 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
   3338 		errno = EINVAL;
   3339 		return (DI_LNODE_NIL);
   3340 	}
   3341 
   3342 	di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
   3343 
   3344 	if (endpoint == DI_LINK_SRC) {
   3345 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
   3346 	} else {
   3347 		return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
   3348 	}
   3349 	/* NOTREACHED */
   3350 }
   3351 
   3352 char *
   3353 di_lnode_name(di_lnode_t lnode)
   3354 {
   3355 	return (di_driver_name(di_lnode_devinfo(lnode)));
   3356 }
   3357 
   3358 di_node_t
   3359 di_lnode_devinfo(di_lnode_t lnode)
   3360 {
   3361 	struct di_all *di_all;
   3362 
   3363 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
   3364 	return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
   3365 }
   3366 
   3367 int
   3368 di_lnode_devt(di_lnode_t lnode, dev_t *devt)
   3369 {
   3370 	if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
   3371 		errno = EINVAL;
   3372 		return (-1);
   3373 	}
   3374 	if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
   3375 	    (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
   3376 		return (-1);
   3377 
   3378 	*devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
   3379 	return (0);
   3380 }
   3381 
   3382 int
   3383 di_link_spectype(di_link_t link)
   3384 {
   3385 	return (DI_LINK(link)->spec_type);
   3386 }
   3387 
   3388 void
   3389 di_minor_private_set(di_minor_t minor, void *data)
   3390 {
   3391 	DI_MINOR(minor)->user_private_data = (uintptr_t)data;
   3392 }
   3393 
   3394 void *
   3395 di_minor_private_get(di_minor_t minor)
   3396 {
   3397 	return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
   3398 }
   3399 
   3400 void
   3401 di_node_private_set(di_node_t node, void *data)
   3402 {
   3403 	DI_NODE(node)->user_private_data = (uintptr_t)data;
   3404 }
   3405 
   3406 void *
   3407 di_node_private_get(di_node_t node)
   3408 {
   3409 	return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
   3410 }
   3411 
   3412 void
   3413 di_path_private_set(di_path_t path, void *data)
   3414 {
   3415 	DI_PATH(path)->user_private_data = (uintptr_t)data;
   3416 }
   3417 
   3418 void *
   3419 di_path_private_get(di_path_t path)
   3420 {
   3421 	return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
   3422 }
   3423 
   3424 void
   3425 di_lnode_private_set(di_lnode_t lnode, void *data)
   3426 {
   3427 	DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
   3428 }
   3429 
   3430 void *
   3431 di_lnode_private_get(di_lnode_t lnode)
   3432 {
   3433 	return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
   3434 }
   3435 
   3436 void
   3437 di_link_private_set(di_link_t link, void *data)
   3438 {
   3439 	DI_LINK(link)->user_private_data = (uintptr_t)data;
   3440 }
   3441 
   3442 void *
   3443 di_link_private_get(di_link_t link)
   3444 {
   3445 	return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
   3446 }
   3447 
   3448 di_lnode_t
   3449 di_lnode_next(di_node_t node, di_lnode_t lnode)
   3450 {
   3451 	struct di_all *di_all;
   3452 
   3453 	/*
   3454 	 * paranoid error checking
   3455 	 */
   3456 	if (node == DI_NODE_NIL) {
   3457 		errno = EINVAL;
   3458 		return (DI_LNODE_NIL);
   3459 	}
   3460 
   3461 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
   3462 
   3463 	if (lnode == DI_NODE_NIL) {
   3464 		if (DI_NODE(node)->lnodes != NULL)
   3465 			return (DI_LNODE((caddr_t)di_all +
   3466 			    DI_NODE(node)->lnodes));
   3467 	} else {
   3468 		if (DI_LNODE(lnode)->node_next != NULL)
   3469 			return (DI_LNODE((caddr_t)di_all +
   3470 			    DI_LNODE(lnode)->node_next));
   3471 	}
   3472 
   3473 	if (DINFOLYR & DI_ALL(di_all)->command)
   3474 		errno = ENXIO;
   3475 	else
   3476 		errno = ENOTSUP;
   3477 
   3478 	return (DI_LNODE_NIL);
   3479 }
   3480 
   3481 di_link_t
   3482 di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
   3483 {
   3484 	struct di_all *di_all;
   3485 
   3486 	/*
   3487 	 * paranoid error checking
   3488 	 */
   3489 	if ((node == DI_NODE_NIL) ||
   3490 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
   3491 		errno = EINVAL;
   3492 		return (DI_LINK_NIL);
   3493 	}
   3494 
   3495 	di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
   3496 
   3497 	if (endpoint == DI_LINK_SRC) {
   3498 		if (link == DI_LINK_NIL) {
   3499 			if (DI_NODE(node)->src_links != NULL)
   3500 				return (DI_LINK((caddr_t)di_all +
   3501 				    DI_NODE(node)->src_links));
   3502 		} else {
   3503 			if (DI_LINK(link)->src_node_next != NULL)
   3504 				return (DI_LINK((caddr_t)di_all +
   3505 				    DI_LINK(link)->src_node_next));
   3506 		}
   3507 	} else {
   3508 		if (link == DI_LINK_NIL) {
   3509 			if (DI_NODE(node)->tgt_links != NULL)
   3510 				return (DI_LINK((caddr_t)di_all +
   3511 				    DI_NODE(node)->tgt_links));
   3512 		} else {
   3513 			if (DI_LINK(link)->tgt_node_next != NULL)
   3514 				return (DI_LINK((caddr_t)di_all +
   3515 				    DI_LINK(link)->tgt_node_next));
   3516 		}
   3517 	}
   3518 
   3519 	if (DINFOLYR & DI_ALL(di_all)->command)
   3520 		errno = ENXIO;
   3521 	else
   3522 		errno = ENOTSUP;
   3523 
   3524 	return (DI_LINK_NIL);
   3525 }
   3526 
   3527 di_link_t
   3528 di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
   3529 {
   3530 	struct di_all *di_all;
   3531 
   3532 	/*
   3533 	 * paranoid error checking
   3534 	 */
   3535 	if ((lnode == DI_LNODE_NIL) ||
   3536 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
   3537 		errno = EINVAL;
   3538 		return (DI_LINK_NIL);
   3539 	}
   3540 
   3541 	di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
   3542 
   3543 	if (endpoint == DI_LINK_SRC) {
   3544 		if (link == DI_LINK_NIL) {
   3545 			if (DI_LNODE(lnode)->link_out == NULL)
   3546 				return (DI_LINK_NIL);
   3547 			return (DI_LINK((caddr_t)di_all +
   3548 			    DI_LNODE(lnode)->link_out));
   3549 		} else {
   3550 			if (DI_LINK(link)->src_link_next == NULL)
   3551 				return (DI_LINK_NIL);
   3552 			return (DI_LINK((caddr_t)di_all +
   3553 			    DI_LINK(link)->src_link_next));
   3554 		}
   3555 	} else {
   3556 		if (link == DI_LINK_NIL) {
   3557 			if (DI_LNODE(lnode)->link_in == NULL)
   3558 				return (DI_LINK_NIL);
   3559 			return (DI_LINK((caddr_t)di_all +
   3560 			    DI_LNODE(lnode)->link_in));
   3561 		} else {
   3562 			if (DI_LINK(link)->tgt_link_next == NULL)
   3563 				return (DI_LINK_NIL);
   3564 			return (DI_LINK((caddr_t)di_all +
   3565 			    DI_LINK(link)->tgt_link_next));
   3566 		}
   3567 	}
   3568 	/* NOTREACHED */
   3569 }
   3570 
   3571 /*
   3572  * Internal library function:
   3573  *   Invoke callback for each link data on the link list of first node
   3574  *   on node_list headp, and place children of first node on the list.
   3575  *
   3576  *   This is similar to walk_one_node, except we only walk in child
   3577  *   first mode.
   3578  */
   3579 static void
   3580 walk_one_link(struct node_list **headp, uint_t ep,
   3581     void *arg, int (*callback)(di_link_t link, void *arg))
   3582 {
   3583 	int		action = DI_WALK_CONTINUE;
   3584 	di_link_t	link = DI_LINK_NIL;
   3585 	di_node_t	node = (*headp)->node;
   3586 
   3587 	while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
   3588 		action = callback(link, arg);
   3589 		if (action == DI_WALK_TERMINATE) {
   3590 			break;
   3591 		}
   3592 	}
   3593 
   3594 	update_node_list(action, DI_WALK_LINKGEN, headp);
   3595 }
   3596 
   3597 int
   3598 di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
   3599     int (*link_callback)(di_link_t link, void *arg))
   3600 {
   3601 	struct node_list  *head;	/* node_list for tree walk */
   3602 
   3603 #ifdef DEBUG
   3604 	char *devfspath = di_devfs_path(root);
   3605 	DPRINTF((DI_INFO, "walking %s link data under %s\n",
   3606 	    (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
   3607 	di_devfs_path_free(devfspath);
   3608 #endif
   3609 
   3610 	/*
   3611 	 * paranoid error checking
   3612 	 */
   3613 	if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
   3614 	    ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
   3615 		errno = EINVAL;
   3616 		return (-1);
   3617 	}
   3618 
   3619 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
   3620 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
   3621 		return (-1);
   3622 	}
   3623 
   3624 	head->next = NULL;
   3625 	head->node = root;
   3626 
   3627 	DPRINTF((DI_INFO, "Start link data walking from node %s\n",
   3628 	    di_node_name(root)));
   3629 
   3630 	while (head != NULL)
   3631 		walk_one_link(&head, endpoint, arg, link_callback);
   3632 
   3633 	return (0);
   3634 }
   3635 
   3636 /*
   3637  * Internal library function:
   3638  *   Invoke callback for each link data on the link list of first node
   3639  *   on node_list headp, and place children of first node on the list.
   3640  *
   3641  *   This is similar to walk_one_node, except we only walk in child
   3642  *   first mode.
   3643  */
   3644 static void
   3645 walk_one_lnode(struct node_list **headp, void *arg,
   3646     int (*callback)(di_lnode_t lnode, void *arg))
   3647 {
   3648 	int		action = DI_WALK_CONTINUE;
   3649 	di_lnode_t	lnode = DI_LNODE_NIL;
   3650 	di_node_t	node = (*headp)->node;
   3651 
   3652 	while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
   3653 		action = callback(lnode, arg);
   3654 		if (action == DI_WALK_TERMINATE) {
   3655 			break;
   3656 		}
   3657 	}
   3658 
   3659 	update_node_list(action, DI_WALK_LINKGEN, headp);
   3660 }
   3661 
   3662 int
   3663 di_walk_lnode(di_node_t root, uint_t flag, void *arg,
   3664     int (*lnode_callback)(di_lnode_t lnode, void *arg))
   3665 {
   3666 	struct node_list  *head;	/* node_list for tree walk */
   3667 
   3668 #ifdef DEBUG
   3669 	char *devfspath = di_devfs_path(root);
   3670 	DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
   3671 	di_devfs_path_free(devfspath);
   3672 #endif
   3673 
   3674 	/*
   3675 	 * paranoid error checking
   3676 	 */
   3677 	if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
   3678 		errno = EINVAL;
   3679 		return (-1);
   3680 	}
   3681 
   3682 	if ((head = malloc(sizeof (struct node_list))) == NULL) {
   3683 		DPRINTF((DI_ERR, "malloc of node_list failed\n"));
   3684 		return (-1);
   3685 	}
   3686 
   3687 	head->next = NULL;
   3688 	head->node = root;
   3689 
   3690 	DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
   3691 	    di_node_name(root)));
   3692 
   3693 	while (head != NULL)
   3694 		walk_one_lnode(&head, arg, lnode_callback);
   3695 
   3696 	return (0);
   3697 }
   3698 
   3699 di_node_t
   3700 di_lookup_node(di_node_t root, char *devfspath)
   3701 {
   3702 	struct di_all *dap;
   3703 	di_node_t node;
   3704 	char *copy, *slash, *pname, *paddr;
   3705 
   3706 	/*
   3707 	 * Path must be absolute and musn't have duplicate slashes
   3708 	 */
   3709 	if (*devfspath != '/' || strstr(devfspath, "//")) {
   3710 		DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
   3711 		return (DI_NODE_NIL);
   3712 	}
   3713 
   3714 	if (root == DI_NODE_NIL) {
   3715 		DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
   3716 		return (DI_NODE_NIL);
   3717 	}
   3718 
   3719 	dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
   3720 	if (strcmp(dap->root_path, "/") != 0) {
   3721 		DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
   3722 		return (DI_NODE_NIL);
   3723 	}
   3724 
   3725 	if ((copy = strdup(devfspath)) == NULL) {
   3726 		DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
   3727 		return (DI_NODE_NIL);
   3728 	}
   3729 
   3730 	for (slash = copy, node = root; slash; ) {
   3731 
   3732 		/*
   3733 		 * Handle devfspath = "/" case as well as trailing '/'
   3734 		 */
   3735 		if (*(slash + 1) == '\0')
   3736 			break;
   3737 
   3738 		/*
   3739 		 * More path-components exist. Deal with the next one
   3740 		 */
   3741 		pname = slash + 1;
   3742 		node = di_child_node(node);
   3743 
   3744 		if (slash = strchr(pname, '/'))
   3745 			*slash = '\0';
   3746 		if (paddr = strchr(pname, '@'))
   3747 			*paddr++ = '\0';
   3748 
   3749 		for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
   3750 			char *name, *baddr;
   3751 
   3752 			name = di_node_name(node);
   3753 			baddr = di_bus_addr(node);
   3754 
   3755 			if (strcmp(pname, name) != 0)
   3756 				continue;
   3757 
   3758 			/*
   3759 			 * Mappings between a "path-address" and bus-addr
   3760 			 *
   3761 			 *	paddr		baddr
   3762 			 *	---------------------
   3763 			 *	NULL		NULL
   3764 			 *	NULL		""
   3765 			 *	""		N/A	(invalid paddr)
   3766 			 */
   3767 			if (paddr && baddr && strcmp(paddr, baddr) == 0)
   3768 				break;
   3769 			if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
   3770 				break;
   3771 		}
   3772 
   3773 		/*
   3774 		 * No nodes in the sibling list or there was no match
   3775 		 */
   3776 		if (node == DI_NODE_NIL) {
   3777 			DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
   3778 			free(copy);
   3779 			return (DI_NODE_NIL);
   3780 		}
   3781 	}
   3782 
   3783 	assert(node != DI_NODE_NIL);
   3784 	free(copy);
   3785 	return (node);
   3786 }
   3787 
   3788 di_path_t
   3789 di_lookup_path(di_node_t root, char *devfspath)
   3790 {
   3791 	di_node_t	phci_node;
   3792 	di_path_t	path = DI_PATH_NIL;
   3793 	char		*copy, *lastslash;
   3794 	char		*pname, *paddr;
   3795 	char		*path_name, *path_addr;
   3796 
   3797 	if ((copy = strdup(devfspath)) == NULL) {
   3798 		DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
   3799 		return (DI_NODE_NIL);
   3800 	}
   3801 
   3802 	if ((lastslash = strrchr(copy, '/')) == NULL) {
   3803 		DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
   3804 		goto out;
   3805 	}
   3806 
   3807 	/* stop at pHCI and find the node for the phci */
   3808 	*lastslash = '\0';
   3809 	phci_node = di_lookup_node(root, copy);
   3810 	if (phci_node == NULL) {
   3811 		DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
   3812 		goto out;
   3813 	}
   3814 
   3815 	/* set up pname and paddr for last component */
   3816 	pname = lastslash + 1;
   3817 	if ((paddr = strchr(pname, '@')) == NULL) {
   3818 		DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
   3819 		goto out;
   3820 	}
   3821 	*paddr++ = '\0';
   3822 
   3823 	/* walk paths below phci looking for match */
   3824 	for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
   3825 	    path != DI_PATH_NIL;
   3826 	    path = di_path_phci_next_path(phci_node, path)) {
   3827 
   3828 		/* get name@addr of path */
   3829 		path_name = di_path_node_name(path);
   3830 		path_addr = di_path_bus_addr(path);
   3831 		if ((path_name == NULL) || (path_addr == NULL))
   3832 			continue;
   3833 
   3834 		/* break on match */
   3835 		if ((strcmp(pname, path_name) == 0) &&
   3836 		    (strcmp(paddr, path_addr) == 0))
   3837 			break;
   3838 	}
   3839 
   3840 out:	free(copy);
   3841 	return (path);
   3842 }
   3843 
   3844 static char *
   3845 msglevel2str(di_debug_t msglevel)
   3846 {
   3847 	switch (msglevel) {
   3848 		case DI_ERR:
   3849 			return ("ERROR");
   3850 		case DI_INFO:
   3851 			return ("Info");
   3852 		case DI_TRACE:
   3853 			return ("Trace");
   3854 		case DI_TRACE1:
   3855 			return ("Trace1");
   3856 		case DI_TRACE2:
   3857 			return ("Trace2");
   3858 		default:
   3859 			return ("UNKNOWN");
   3860 	}
   3861 }
   3862 
   3863 void
   3864 dprint(di_debug_t msglevel, const char *fmt, ...)
   3865 {
   3866 	va_list	ap;
   3867 	char	*estr;
   3868 
   3869 	if (di_debug <= DI_QUIET)
   3870 		return;
   3871 
   3872 	if (di_debug < msglevel)
   3873 		return;
   3874 
   3875 	estr = msglevel2str(msglevel);
   3876 
   3877 	assert(estr);
   3878 
   3879 	va_start(ap, fmt);
   3880 
   3881 	(void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
   3882 	    (ulong_t)getpid(), estr);
   3883 	(void) vfprintf(stderr, fmt, ap);
   3884 
   3885 	va_end(ap);
   3886 }
   3887 
   3888 /* end of devinfo.c */
   3889