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