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