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