6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libdevinfo / devinfo.c
blobdb6a62cab15e62ecb90dda857059a1ce401a4a09
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Interfaces for getting device configuration data from kernel
30 * through the devinfo driver.
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <stropts.h>
38 #include <fcntl.h>
39 #include <poll.h>
40 #include <synch.h>
41 #include <unistd.h>
42 #include <sys/mkdev.h>
43 #include <sys/obpdefs.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <sys/time.h>
47 #include <sys/autoconf.h>
48 #include <stdarg.h>
50 #define NDEBUG 1
51 #include <assert.h>
53 #include "libdevinfo.h"
56 * Debug message levels
58 typedef enum {
59 DI_QUIET = 0, /* No debug messages - the default */
60 DI_ERR = 1,
61 DI_INFO,
62 DI_TRACE,
63 DI_TRACE1,
64 DI_TRACE2
65 } di_debug_t;
67 int di_debug = DI_QUIET;
69 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; }
71 void dprint(di_debug_t msglevel, const char *fmt, ...);
74 #pragma init(_libdevinfo_init)
76 void
77 _libdevinfo_init()
79 char *debug_str = getenv("_LIBDEVINFO_DEBUG");
81 if (debug_str) {
82 errno = 0;
83 di_debug = atoi(debug_str);
84 if (errno || di_debug < DI_QUIET)
85 di_debug = DI_QUIET;
89 di_node_t
90 di_init(const char *phys_path, uint_t flag)
92 return (di_init_impl(phys_path, flag, NULL));
96 * We use blocking_open() to guarantee access to the devinfo device, if open()
97 * is failing with EAGAIN.
99 static int
100 blocking_open(const char *path, int oflag)
102 int fd;
104 while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
105 (void) poll(NULL, 0, 1 * MILLISEC);
107 return (fd);
110 /* private interface */
111 di_node_t
112 di_init_driver(const char *drv_name, uint_t flag)
114 int fd;
115 char driver[MAXPATHLEN];
118 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
119 * which should be sufficient for any sensible programmer.
121 if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
122 errno = EINVAL;
123 return (DI_NODE_NIL);
125 (void) strcpy(driver, drv_name);
128 * open the devinfo driver
130 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
131 O_RDONLY)) == -1) {
132 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
133 return (DI_NODE_NIL);
136 if (ioctl(fd, DINFOLODRV, driver) != 0) {
137 DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
138 (void) close(fd);
139 errno = ENXIO;
140 return (DI_NODE_NIL);
142 (void) close(fd);
145 * Driver load succeeded, return a snapshot
147 return (di_init("/", flag));
150 di_node_t
151 di_init_impl(const char *phys_path, uint_t flag,
152 struct di_priv_data *priv)
154 caddr_t pa;
155 int fd, map_size;
156 struct di_all *dap;
157 struct dinfo_io dinfo_io;
159 uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
160 uint_t pagemask = ~pageoffset;
162 DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
165 * Make sure there is no minor name in the path
166 * and the path do not start with /devices....
168 if (strchr(phys_path, ':') ||
169 (strncmp(phys_path, "/devices", 8) == 0) ||
170 (strlen(phys_path) > MAXPATHLEN)) {
171 errno = EINVAL;
172 return (DI_NODE_NIL);
175 if (strlen(phys_path) == 0)
176 (void) sprintf(dinfo_io.root_path, "/");
177 else if (*phys_path != '/')
178 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
179 "/%s", phys_path);
180 else
181 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
182 "%s", phys_path);
185 * If private data is requested, copy the format specification
187 if (flag & DINFOPRIVDATA & 0xff) {
188 if (priv)
189 bcopy(priv, &dinfo_io.priv,
190 sizeof (struct di_priv_data));
191 else {
192 errno = EINVAL;
193 return (DI_NODE_NIL);
198 * Attempt to open the devinfo driver. Make a second attempt at the
199 * read-only minor node if we don't have privileges to open the full
200 * version _and_ if we're not requesting operations that the read-only
201 * node can't perform. (Setgid processes would fail an access() test,
202 * of course.)
204 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
205 O_RDONLY)) == -1) {
206 if ((flag & DINFOFORCE) == DINFOFORCE ||
207 (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
209 * We wanted to perform a privileged operation, but the
210 * privileged node isn't available. Don't modify errno
211 * on our way out (but display it if we're running with
212 * di_debug set).
214 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
215 errno));
216 return (DI_NODE_NIL);
219 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
220 O_RDONLY)) == -1) {
221 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
222 errno));
223 return (DI_NODE_NIL);
228 * Verify that there is no major conflict, i.e., we are indeed opening
229 * the devinfo driver.
231 if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
232 DPRINTF((DI_ERR,
233 "driver ID failed; check for major conflict\n"));
234 (void) close(fd);
235 return (DI_NODE_NIL);
239 * create snapshot
241 if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
242 DPRINTF((DI_ERR, "devinfo ioctl failed with "
243 "error: %d\n", errno));
244 (void) close(fd);
245 return (DI_NODE_NIL);
246 } else if (map_size == 0) {
247 DPRINTF((DI_ERR, "%s not found\n", phys_path));
248 errno = ENXIO;
249 (void) close(fd);
250 return (DI_NODE_NIL);
254 * copy snapshot to userland
256 map_size = (map_size + pageoffset) & pagemask;
257 if ((pa = valloc(map_size)) == NULL) {
258 DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
259 (void) close(fd);
260 return (DI_NODE_NIL);
263 if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
264 DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
265 (void) close(fd);
266 free(pa);
267 errno = EFAULT;
268 return (DI_NODE_NIL);
271 (void) close(fd);
273 dap = DI_ALL(pa);
274 if (dap->version != DI_SNAPSHOT_VERSION) {
275 DPRINTF((DI_ERR, "wrong snapshot version "
276 "(expected=%d, actual=%d)\n",
277 DI_SNAPSHOT_VERSION, dap->version));
278 free(pa);
279 errno = ESTALE;
280 return (DI_NODE_NIL);
282 if (dap->top_devinfo == 0) { /* phys_path not found */
283 DPRINTF((DI_ERR, "%s not found\n", phys_path));
284 free(pa);
285 errno = EINVAL;
286 return (DI_NODE_NIL);
289 return (DI_NODE(pa + dap->top_devinfo));
292 void
293 di_fini(di_node_t root)
295 caddr_t pa; /* starting address of map */
297 DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
300 * paranoid checking
302 if (root == DI_NODE_NIL) {
303 DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
304 return;
308 * The root contains its own offset--self.
309 * Subtracting it from root address, we get the starting addr.
310 * The map_size is stored at the beginning of snapshot.
311 * Once we have starting address and size, we can free().
313 pa = (caddr_t)root - DI_NODE(root)->self;
315 free(pa);
318 di_node_t
319 di_parent_node(di_node_t node)
321 caddr_t pa; /* starting address of map */
323 if (node == DI_NODE_NIL) {
324 errno = EINVAL;
325 return (DI_NODE_NIL);
328 DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
330 pa = (caddr_t)node - DI_NODE(node)->self;
332 if (DI_NODE(node)->parent) {
333 return (DI_NODE(pa + DI_NODE(node)->parent));
337 * Deal with error condition:
338 * If parent doesn't exist and node is not the root,
339 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
341 if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
342 errno = ENOTSUP;
343 else
344 errno = ENXIO;
346 return (DI_NODE_NIL);
349 di_node_t
350 di_sibling_node(di_node_t node)
352 caddr_t pa; /* starting address of map */
354 if (node == DI_NODE_NIL) {
355 errno = EINVAL;
356 return (DI_NODE_NIL);
359 DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
361 pa = (caddr_t)node - DI_NODE(node)->self;
363 if (DI_NODE(node)->sibling) {
364 return (DI_NODE(pa + DI_NODE(node)->sibling));
368 * Deal with error condition:
369 * Sibling doesn't exist, figure out if ioctl command
370 * has DINFOSUBTREE set. If it doesn't, set errno to
371 * ENOTSUP.
373 if (!(DI_ALL(pa)->command & DINFOSUBTREE))
374 errno = ENOTSUP;
375 else
376 errno = ENXIO;
378 return (DI_NODE_NIL);
381 di_node_t
382 di_child_node(di_node_t node)
384 caddr_t pa; /* starting address of map */
386 DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
388 if (node == DI_NODE_NIL) {
389 errno = EINVAL;
390 return (DI_NODE_NIL);
393 pa = (caddr_t)node - DI_NODE(node)->self;
395 if (DI_NODE(node)->child) {
396 return (DI_NODE(pa + DI_NODE(node)->child));
400 * Deal with error condition:
401 * Child doesn't exist, figure out if DINFOSUBTREE is set.
402 * If it isn't, set errno to ENOTSUP.
404 if (!(DI_ALL(pa)->command & DINFOSUBTREE))
405 errno = ENOTSUP;
406 else
407 errno = ENXIO;
409 return (DI_NODE_NIL);
412 di_node_t
413 di_drv_first_node(const char *drv_name, di_node_t root)
415 caddr_t pa; /* starting address of map */
416 int major, devcnt;
417 struct di_devnm *devnm;
419 DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
421 if (root == DI_NODE_NIL) {
422 errno = EINVAL;
423 return (DI_NODE_NIL);
427 * get major number of driver
429 pa = (caddr_t)root - DI_NODE(root)->self;
430 devcnt = DI_ALL(pa)->devcnt;
431 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
433 for (major = 0; major < devcnt; major++)
434 if (devnm[major].name && (strcmp(drv_name,
435 (char *)(pa + devnm[major].name)) == 0))
436 break;
438 if (major >= devcnt) {
439 errno = EINVAL;
440 return (DI_NODE_NIL);
443 if (!(devnm[major].head)) {
444 errno = ENXIO;
445 return (DI_NODE_NIL);
448 return (DI_NODE(pa + devnm[major].head));
451 di_node_t
452 di_drv_next_node(di_node_t node)
454 caddr_t pa; /* starting address of map */
456 if (node == DI_NODE_NIL) {
457 errno = EINVAL;
458 return (DI_NODE_NIL);
461 DPRINTF((DI_TRACE, "next node on per driver list:"
462 " current=%s, driver=%s\n",
463 di_node_name(node), di_driver_name(node)));
465 if (DI_NODE(node)->next == (di_off_t)-1) {
466 errno = ENOTSUP;
467 return (DI_NODE_NIL);
470 pa = (caddr_t)node - DI_NODE(node)->self;
472 if (DI_NODE(node)->next == NULL) {
473 errno = ENXIO;
474 return (DI_NODE_NIL);
477 return (DI_NODE(pa + DI_NODE(node)->next));
481 * Internal library interfaces:
482 * node_list etc. for node walking
484 struct node_list {
485 struct node_list *next;
486 di_node_t node;
489 static void
490 free_node_list(struct node_list **headp)
492 struct node_list *tmp;
494 while (*headp) {
495 tmp = *headp;
496 *headp = (*headp)->next;
497 free(tmp);
501 static void
502 append_node_list(struct node_list **headp, struct node_list *list)
504 struct node_list *tmp;
506 if (*headp == NULL) {
507 *headp = list;
508 return;
511 if (list == NULL) /* a minor optimization */
512 return;
514 tmp = *headp;
515 while (tmp->next)
516 tmp = tmp->next;
518 tmp->next = list;
521 static void
522 prepend_node_list(struct node_list **headp, struct node_list *list)
524 struct node_list *tmp;
526 if (list == NULL)
527 return;
529 tmp = *headp;
530 *headp = list;
532 if (tmp == NULL) /* a minor optimization */
533 return;
535 while (list->next)
536 list = list->next;
538 list->next = tmp;
542 * returns 1 if node is a descendant of parent, 0 otherwise
544 static int
545 is_descendant(di_node_t node, di_node_t parent)
548 * DI_NODE_NIL is parent of root, so it is
549 * the parent of all nodes.
551 if (parent == DI_NODE_NIL) {
552 return (1);
555 do {
556 node = di_parent_node(node);
557 } while ((node != DI_NODE_NIL) && (node != parent));
559 return (node != DI_NODE_NIL);
563 * Insert list before the first node which is NOT a descendent of parent.
564 * This is needed to reproduce the exact walking order of link generators.
566 static void
567 insert_node_list(struct node_list **headp, struct node_list *list,
568 di_node_t parent)
570 struct node_list *tmp, *tmp1;
572 if (list == NULL)
573 return;
575 tmp = *headp;
576 if (tmp == NULL) { /* a minor optimization */
577 *headp = list;
578 return;
581 if (!is_descendant(tmp->node, parent)) {
582 prepend_node_list(headp, list);
583 return;
587 * Find first node which is not a descendant
589 while (tmp->next && is_descendant(tmp->next->node, parent)) {
590 tmp = tmp->next;
593 tmp1 = tmp->next;
594 tmp->next = list;
595 append_node_list(headp, tmp1);
599 * Get a linked list of handles of all children
601 static struct node_list *
602 get_children(di_node_t node)
604 di_node_t child;
605 struct node_list *result, *tmp;
607 DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
609 if ((child = di_child_node(node)) == DI_NODE_NIL) {
610 return (NULL);
613 if ((result = malloc(sizeof (struct node_list))) == NULL) {
614 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
615 return (NULL);
618 result->node = child;
619 tmp = result;
621 while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
622 if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
623 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
624 free_node_list(&result);
625 return (NULL);
627 tmp = tmp->next;
628 tmp->node = child;
631 tmp->next = NULL;
633 return (result);
637 * Internal library interface:
638 * Delete all siblings of the first node from the node_list, along with
639 * the first node itself.
641 static void
642 prune_sib(struct node_list **headp)
644 di_node_t parent, curr_par, curr_gpar;
645 struct node_list *curr, *prev;
648 * get handle to parent of first node
650 if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
652 * This must be the root of the snapshot, so can't
653 * have any siblings.
655 * XXX Put a check here just in case.
657 if ((*headp)->next)
658 DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
660 free(*headp);
661 *headp = NULL;
662 return;
666 * To be complete, we should also delete the children
667 * of siblings that have already been visited.
668 * This happens for DI_WALK_SIBFIRST when the first node
669 * is NOT the first in the linked list of siblings.
671 * Hence, we compare parent with BOTH the parent and grandparent
672 * of nodes, and delete node is a match is found.
674 prev = *headp;
675 curr = prev->next;
676 while (curr) {
677 if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) &&
678 ((curr_par == parent) || ((curr_gpar =
679 di_parent_node(curr_par)) != DI_NODE_NIL) &&
680 (curr_gpar == parent))) {
682 * match parent/grandparent: delete curr
684 prev->next = curr->next;
685 free(curr);
686 curr = prev->next;
687 } else
688 curr = curr->next;
692 * delete the first node
694 curr = *headp;
695 *headp = curr->next;
696 free(curr);
700 * Internal library function:
701 * Update node list based on action (return code from callback)
702 * and flag specifying walking behavior.
704 static void
705 update_node_list(int action, uint_t flag, struct node_list **headp)
707 struct node_list *children, *tmp;
708 di_node_t parent = di_parent_node((*headp)->node);
710 switch (action) {
711 case DI_WALK_TERMINATE:
713 * free the node list and be done
715 children = NULL;
716 free_node_list(headp);
717 break;
719 case DI_WALK_PRUNESIB:
721 * Get list of children and prune siblings
723 children = get_children((*headp)->node);
724 prune_sib(headp);
725 break;
727 case DI_WALK_PRUNECHILD:
729 * Set children to NULL and pop first node
731 children = NULL;
732 tmp = *headp;
733 *headp = tmp->next;
734 free(tmp);
735 break;
737 case DI_WALK_CONTINUE:
738 default:
740 * Get list of children and pop first node
742 children = get_children((*headp)->node);
743 tmp = *headp;
744 *headp = tmp->next;
745 free(tmp);
746 break;
750 * insert the list of children
752 switch (flag) {
753 case DI_WALK_CLDFIRST:
754 prepend_node_list(headp, children);
755 break;
757 case DI_WALK_SIBFIRST:
758 append_node_list(headp, children);
759 break;
761 case DI_WALK_LINKGEN:
762 default:
763 insert_node_list(headp, children, parent);
764 break;
769 * Internal library function:
770 * Invoke callback on one node and update the list of nodes to be walked
771 * based on the flag and return code.
773 static void
774 walk_one_node(struct node_list **headp, uint_t flag, void *arg,
775 int (*callback)(di_node_t, void *))
777 DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
779 update_node_list(callback((*headp)->node, arg),
780 flag & DI_WALK_MASK, headp);
784 di_walk_node(di_node_t root, uint_t flag, void *arg,
785 int (*node_callback)(di_node_t, void *))
787 struct node_list *head; /* node_list for tree walk */
789 if (root == NULL) {
790 errno = EINVAL;
791 return (-1);
794 if ((head = malloc(sizeof (struct node_list))) == NULL) {
795 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
796 return (-1);
799 head->next = NULL;
800 head->node = root;
802 DPRINTF((DI_INFO, "Start node walking from node %s\n",
803 di_node_name(root)));
805 while (head != NULL)
806 walk_one_node(&head, flag, arg, node_callback);
808 return (0);
812 * Internal library function:
813 * Invoke callback for each minor on the minor list of first node
814 * on node_list headp, and place children of first node on the list.
816 * This is similar to walk_one_node, except we only walk in child
817 * first mode.
819 static void
820 walk_one_minor_list(struct node_list **headp, const char *desired_type,
821 uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
823 int ddm_type;
824 int action = DI_WALK_CONTINUE;
825 char *node_type;
826 di_minor_t minor = DI_MINOR_NIL;
827 di_node_t node = (*headp)->node;
829 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
830 ddm_type = di_minor_type(minor);
832 if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
833 continue;
835 if ((ddm_type == DDM_INTERNAL_PATH) &&
836 !(flag & DI_CHECK_INTERNAL_PATH))
837 continue;
839 node_type = di_minor_nodetype(minor);
840 if ((desired_type != NULL) && ((node_type == NULL) ||
841 strncmp(desired_type, node_type, strlen(desired_type))
842 != 0))
843 continue;
845 if ((action = callback(node, minor, arg)) ==
846 DI_WALK_TERMINATE) {
847 break;
851 update_node_list(action, DI_WALK_LINKGEN, headp);
855 di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
856 int (*minor_callback)(di_node_t, di_minor_t, void *))
858 struct node_list *head; /* node_list for tree walk */
860 #ifdef DEBUG
861 char *devfspath = di_devfs_path(root);
862 DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath));
863 di_devfs_path_free(devfspath);
864 #endif
866 if (root == NULL) {
867 errno = EINVAL;
868 return (-1);
871 if ((head = malloc(sizeof (struct node_list))) == NULL) {
872 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
873 return (-1);
876 head->next = NULL;
877 head->node = root;
879 DPRINTF((DI_INFO, "Start minor walking from node %s\n",
880 di_node_name(root)));
882 while (head != NULL)
883 walk_one_minor_list(&head, minor_type, flag, arg,
884 minor_callback);
886 return (0);
890 * generic node parameters
891 * Calling these routines always succeeds.
893 char *
894 di_node_name(di_node_t node)
896 return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
899 /* returns NULL ptr or a valid ptr to non-NULL string */
900 char *
901 di_bus_addr(di_node_t node)
903 caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
905 if (DI_NODE(node)->address == 0)
906 return (NULL);
908 return ((char *)(pa + DI_NODE(node)->address));
911 char *
912 di_binding_name(di_node_t node)
914 caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
916 if (DI_NODE(node)->bind_name == 0)
917 return (NULL);
919 return ((char *)(pa + DI_NODE(node)->bind_name));
923 di_compatible_names(di_node_t node, char **names)
925 char *c;
926 int len, size, entries = 0;
928 if (DI_NODE(node)->compat_names == 0) {
929 *names = NULL;
930 return (0);
933 *names = (caddr_t)node +
934 DI_NODE(node)->compat_names - DI_NODE(node)->self;
936 c = *names;
937 len = DI_NODE(node)->compat_length;
938 while (len > 0) {
939 entries++;
940 size = strlen(c) + 1;
941 len -= size;
942 c += size;
945 return (entries);
949 di_instance(di_node_t node)
951 return (DI_NODE(node)->instance);
955 * XXX: emulate the return value of the old implementation
956 * using info from devi_node_class and devi_node_attributes.
959 di_nodeid(di_node_t node)
961 if (DI_NODE(node)->node_class == DDI_NC_PROM)
962 return (DI_PROM_NODEID);
964 if (DI_NODE(node)->attributes & DDI_PERSISTENT)
965 return (DI_SID_NODEID);
967 return (DI_PSEUDO_NODEID);
970 uint_t
971 di_state(di_node_t node)
973 uint_t result = 0;
975 if (di_node_state(node) < DS_ATTACHED)
976 result |= DI_DRIVER_DETACHED;
977 if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
978 result |= DI_DEVICE_OFFLINE;
979 if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
980 result |= DI_DEVICE_OFFLINE;
981 if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
982 result |= DI_DEVICE_DEGRADED;
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;
988 return (result);
991 ddi_node_state_t
992 di_node_state(di_node_t node)
994 return (DI_NODE(node)->node_state);
997 uint_t
998 di_flags(di_node_t node)
1000 return (DI_NODE(node)->flags);
1003 uint_t
1004 di_retired(di_node_t node)
1006 return (di_flags(node) & DEVI_RETIRED);
1009 ddi_devid_t
1010 di_devid(di_node_t node)
1012 if (DI_NODE(node)->devid == 0)
1013 return (NULL);
1015 return ((ddi_devid_t)((caddr_t)node +
1016 DI_NODE(node)->devid - DI_NODE(node)->self));
1020 di_driver_major(di_node_t node)
1022 int major;
1024 major = DI_NODE(node)->drv_major;
1025 if (major < 0)
1026 return (-1);
1027 return (major);
1030 char *
1031 di_driver_name(di_node_t node)
1033 int major;
1034 caddr_t pa;
1035 struct di_devnm *devnm;
1037 major = DI_NODE(node)->drv_major;
1038 if (major < 0)
1039 return (NULL);
1041 pa = (caddr_t)node - DI_NODE(node)->self;
1042 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1044 if (devnm[major].name)
1045 return (pa + devnm[major].name);
1046 else
1047 return (NULL);
1050 uint_t
1051 di_driver_ops(di_node_t node)
1053 int major;
1054 caddr_t pa;
1055 struct di_devnm *devnm;
1057 major = DI_NODE(node)->drv_major;
1058 if (major < 0)
1059 return (0);
1061 pa = (caddr_t)node - DI_NODE(node)->self;
1062 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1064 return (devnm[major].ops);
1068 * returns the length of the path, caller must free memory
1070 char *
1071 di_devfs_path(di_node_t node)
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];
1078 if (node == DI_NODE_NIL) {
1079 errno = EINVAL;
1080 return (NULL);
1084 * trace back to root, note the node_name & address
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 '/' */
1090 if ((addr[depth] = di_bus_addr(node)) != NULL)
1091 len += strlen(addr[depth]) + 1; /* 1 for '@' */
1093 node = parent;
1094 depth++;
1098 * get the path to the root of snapshot
1100 pa = (caddr_t)node - DI_NODE(node)->self;
1101 name[depth] = DI_ALL(pa)->root_path;
1102 len += strlen(name[depth]) + 1;
1105 * allocate buffer and assemble path
1107 if ((buf = malloc(len)) == NULL) {
1108 return (NULL);
1111 (void) strcpy(buf, name[depth]);
1112 len = strlen(buf);
1113 if (buf[len - 1] == '/')
1114 len--; /* delete trailing '/' */
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;
1128 return (buf);
1131 char *
1132 di_devfs_minor_path(di_minor_t minor)
1134 di_node_t node;
1135 char *full_path, *name, *devfspath;
1136 int full_path_len;
1138 if (minor == DI_MINOR_NIL) {
1139 errno = EINVAL;
1140 return (NULL);
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);
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);
1156 di_devfs_path_free(devfspath);
1157 return (full_path);
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.
1166 char *
1167 di_path_devfs_path(di_path_t path)
1169 di_node_t phci_node;
1170 char *phci_path, *path_name, *path_addr;
1171 char *full_path;
1172 int full_path_len;
1174 if (path == DI_PATH_NIL) {
1175 errno = EINVAL;
1176 return (NULL);
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);
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);
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);
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);
1205 char *
1206 di_path_client_devfs_path(di_path_t path)
1208 return (di_devfs_path(di_path_client_node(path)));
1211 void
1212 di_devfs_path_free(char *buf)
1214 if (buf == NULL) {
1215 DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
1216 return;
1219 free(buf);
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
1226 static int
1227 is_generic(const char *name, int len)
1229 const char **gp;
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",
1266 for (gp = generic_names; *gp; gp++) {
1267 if ((strncmp(*gp, name, len) == 0) &&
1268 (strlen(*gp) == len))
1269 return (1);
1271 return (0);
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.
1280 di_devfs_path_match(const char *dp1, const char *dp2)
1282 const char *p1, *p2;
1283 const char *ec1, *ec2;
1284 const char *at1, *at2;
1285 char nc;
1286 int g1, g2;
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;
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++;
1302 * Both p1 and p2 point to beginning of 'name' in component.
1303 * Determine where current component ends: next '/' or '\0'.
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);
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;
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.
1325 g1 = is_generic(p1, ec1 - p1);
1326 g2 = is_generic(p2, ec2 - p2);
1328 if (g1 != g2) {
1330 * one generic and one non-generic
1331 * skip past the names in the match.
1333 p1 = ec1;
1334 p2 = ec2;
1335 } else {
1336 if (*p1 != *p2)
1337 break;
1341 return ((*p1 == *p2) ? 1 : 0);
1344 /* minor data access */
1345 di_minor_t
1346 di_minor_next(di_node_t node, di_minor_t minor)
1348 caddr_t pa;
1351 * paranoid error checking
1353 if (node == DI_NODE_NIL) {
1354 errno = EINVAL;
1355 return (DI_MINOR_NIL);
1359 * minor is not NIL
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);
1372 * minor is NIL-->caller asks for first minor node
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));
1380 * no minor data-->check if snapshot includes minor data
1381 * in order to set the correct errno
1383 pa = (caddr_t)node - DI_NODE(node)->self;
1384 if (DINFOMINOR & DI_ALL(pa)->command)
1385 errno = ENXIO;
1386 else
1387 errno = ENOTSUP;
1389 return (DI_MINOR_NIL);
1392 /* private interface for dealing with alias minor link generation */
1393 di_node_t
1394 di_minor_devinfo(di_minor_t minor)
1396 if (minor == DI_MINOR_NIL) {
1397 errno = EINVAL;
1398 return (DI_NODE_NIL);
1401 return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
1402 DI_MINOR(minor)->node));
1405 ddi_minor_type
1406 di_minor_type(di_minor_t minor)
1408 return (DI_MINOR(minor)->type);
1411 char *
1412 di_minor_name(di_minor_t minor)
1414 if (DI_MINOR(minor)->name == 0)
1415 return (NULL);
1417 return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
1420 dev_t
1421 di_minor_devt(di_minor_t minor)
1423 return (makedev(DI_MINOR(minor)->dev_major,
1424 DI_MINOR(minor)->dev_minor));
1428 di_minor_spectype(di_minor_t minor)
1430 return (DI_MINOR(minor)->spec_type);
1433 char *
1434 di_minor_nodetype(di_minor_t minor)
1436 if (DI_MINOR(minor)->node_type == 0)
1437 return (NULL);
1439 return ((caddr_t)minor -
1440 DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
1444 * Single public interface for accessing software properties
1446 di_prop_t
1447 di_prop_next(di_node_t node, di_prop_t prop)
1449 int list = DI_PROP_DRV_LIST;
1452 * paranoid check
1454 if (node == DI_NODE_NIL) {
1455 errno = EINVAL;
1456 return (DI_PROP_NIL);
1460 * Find which prop list we are at
1462 if (prop != DI_PROP_NIL)
1463 list = DI_PROP(prop)->prop_list;
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);
1483 } while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
1485 return (prop);
1488 dev_t
1489 di_prop_devt(di_prop_t prop)
1491 return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
1494 char *
1495 di_prop_name(di_prop_t prop)
1497 if (DI_PROP(prop)->prop_name == 0)
1498 return (NULL);
1500 return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
1504 di_prop_type(di_prop_t prop)
1506 uint_t flags = DI_PROP(prop)->prop_flags;
1508 if (flags & DDI_PROP_UNDEF_IT)
1509 return (DI_PROP_TYPE_UNDEF_IT);
1511 if (DI_PROP(prop)->prop_len == 0)
1512 return (DI_PROP_TYPE_BOOLEAN);
1514 if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
1515 return (DI_PROP_TYPE_UNKNOWN);
1517 if (flags & DDI_PROP_TYPE_INT)
1518 return (DI_PROP_TYPE_INT);
1520 if (flags & DDI_PROP_TYPE_INT64)
1521 return (DI_PROP_TYPE_INT64);
1523 if (flags & DDI_PROP_TYPE_STRING)
1524 return (DI_PROP_TYPE_STRING);
1526 if (flags & DDI_PROP_TYPE_BYTE)
1527 return (DI_PROP_TYPE_BYTE);
1530 * Shouldn't get here. In case we do, return unknown type.
1532 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
1533 * to add DI_PROP_TYPE_COMPOSITE.
1535 DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
1537 return (DI_PROP_TYPE_UNKNOWN);
1541 * Extract type-specific values of an property
1543 extern int di_prop_decode_common(void *prop_data, int len,
1544 int ddi_type, int prom);
1547 di_prop_ints(di_prop_t prop, int **prop_data)
1549 if (DI_PROP(prop)->prop_len == 0)
1550 return (0); /* boolean property */
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);
1559 *prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1560 + DI_PROP(prop)->prop_data));
1562 return (di_prop_decode_common((void *)prop_data,
1563 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
1567 di_prop_int64(di_prop_t prop, int64_t **prop_data)
1569 if (DI_PROP(prop)->prop_len == 0)
1570 return (0); /* boolean property */
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);
1579 *prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1580 + DI_PROP(prop)->prop_data));
1582 return (di_prop_decode_common((void *)prop_data,
1583 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
1587 di_prop_strings(di_prop_t prop, char **prop_data)
1589 if (DI_PROP(prop)->prop_len == 0)
1590 return (0); /* boolean property */
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);
1599 *prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
1600 + DI_PROP(prop)->prop_data);
1602 return (di_prop_decode_common((void *)prop_data,
1603 DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
1607 di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
1609 if (DI_PROP(prop)->prop_len == 0)
1610 return (0); /* boolean property */
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);
1619 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
1620 + DI_PROP(prop)->prop_data);
1622 return (di_prop_decode_common((void *)prop_data,
1623 DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
1627 * returns 1 for match, 0 for no match
1629 static int
1630 match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
1632 int prop_type;
1634 #ifdef DEBUG
1635 if (di_prop_name(prop) == NULL) {
1636 DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
1637 return (0);
1639 #endif /* DEBUG */
1641 if (strcmp(name, di_prop_name(prop)) != 0)
1642 return (0);
1644 if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
1645 return (0);
1648 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
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);
1655 return (1);
1658 static di_prop_t
1659 di_prop_search(dev_t match_dev, di_node_t node, const char *name,
1660 int type)
1662 di_prop_t prop = DI_PROP_NIL;
1665 * The check on match_dev follows ddi_prop_lookup_common().
1666 * Other checks are libdevinfo specific implementation.
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);
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);
1682 return (DI_PROP_NIL);
1685 di_prop_t
1686 di_prop_find(dev_t match_dev, di_node_t node, const char *name)
1688 di_prop_t prop = DI_PROP_NIL;
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);
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)));
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);
1707 return (DI_PROP_NIL);
1711 di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
1712 int **prop_data)
1714 di_prop_t prop;
1716 if ((prop = di_prop_search(dev, node, prop_name,
1717 DI_PROP_TYPE_INT)) == DI_PROP_NIL)
1718 return (-1);
1720 return (di_prop_ints(prop, (void *)prop_data));
1724 di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
1725 int64_t **prop_data)
1727 di_prop_t prop;
1729 if ((prop = di_prop_search(dev, node, prop_name,
1730 DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
1731 return (-1);
1733 return (di_prop_int64(prop, (void *)prop_data));
1737 di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
1738 char **prop_data)
1740 di_prop_t prop;
1742 if ((prop = di_prop_search(dev, node, prop_name,
1743 DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
1744 return (-1);
1746 return (di_prop_strings(prop, (void *)prop_data));
1750 di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
1751 uchar_t **prop_data)
1753 di_prop_t prop;
1755 if ((prop = di_prop_search(dev, node, prop_name,
1756 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
1757 return (-1);
1759 return (di_prop_bytes(prop, (void *)prop_data));
1763 * Consolidation private property access functions
1765 enum prop_type {
1766 PROP_TYPE_DRV,
1767 PROP_TYPE_SYS,
1768 PROP_TYPE_GLOB,
1769 PROP_TYPE_HW
1772 static di_prop_t
1773 di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
1775 caddr_t pa;
1776 di_off_t prop_off = 0;
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);
1789 * prop is NIL, caller asks for first property
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;
1814 break;
1817 if (prop_off) {
1818 return (DI_PROP(pa + prop_off));
1822 * no prop found. Check the reason for not found
1824 if (DINFOPROP & DI_ALL(pa)->command)
1825 errno = ENXIO;
1826 else
1827 errno = ENOTSUP;
1829 return (DI_PROP_NIL);
1832 di_prop_t
1833 di_prop_drv_next(di_node_t node, di_prop_t prop)
1835 return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
1838 di_prop_t
1839 di_prop_sys_next(di_node_t node, di_prop_t prop)
1841 return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
1844 di_prop_t
1845 di_prop_global_next(di_node_t node, di_prop_t prop)
1847 return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
1850 di_prop_t
1851 di_prop_hw_next(di_node_t node, di_prop_t prop)
1853 return (di_prop_next_common(node, prop, PROP_TYPE_HW));
1857 di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
1859 #ifdef DEBUG
1860 if (prop == DI_PROP_NIL) {
1861 errno = EINVAL;
1862 return (-1);
1864 #endif /* DEBUG */
1866 if (DI_PROP(prop)->prop_len == 0) {
1867 *prop_data = NULL;
1868 return (0);
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);
1879 * No memory allocation.
1881 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
1882 DI_PROP(prop)->prop_data);
1884 return (DI_PROP(prop)->prop_len);
1888 * Consolidation private interfaces for accessing I/O multipathing data
1890 di_path_t
1891 di_path_phci_next_path(di_node_t node, di_path_t path)
1893 caddr_t pa;
1896 * path is not NIL
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);
1909 * Path is NIL; the caller is asking for the first path info node
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));
1920 * No pathing data; check if the snapshot includes path data in order
1921 * to set errno properly.
1923 pa = (caddr_t)node - DI_NODE(node)->self;
1924 if (DINFOPATH & (DI_ALL(pa)->command))
1925 errno = ENXIO;
1926 else
1927 errno = ENOTSUP;
1929 return (DI_PATH_NIL);
1932 di_path_t
1933 di_path_client_next_path(di_node_t node, di_path_t path)
1935 caddr_t pa;
1938 * path is not NIL
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);
1951 * Path is NIL; the caller is asking for the first path info node
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));
1962 * No pathing data; check if the snapshot includes path data in order
1963 * to set errno properly.
1965 pa = (caddr_t)node - DI_NODE(node)->self;
1966 if (DINFOPATH & (DI_ALL(pa)->command))
1967 errno = ENXIO;
1968 else
1969 errno = ENOTSUP;
1971 return (DI_PATH_NIL);
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.
1979 char *
1980 di_path_addr(di_path_t path, char *buf)
1982 caddr_t pa; /* starting address of map */
1984 pa = (caddr_t)path - DI_PATH(path)->self;
1986 (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
1987 MAXPATHLEN);
1988 return (buf);
1990 di_path_t
1991 di_path_next(di_node_t node, di_path_t path)
1993 if (node == DI_NODE_NIL) {
1994 errno = EINVAL;
1995 return (DI_PATH_NIL);
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 {
2004 * The node had multipathing data but didn't appear to be a
2005 * phci *or* a client; probably a programmer error.
2007 errno = EINVAL;
2008 return (DI_PATH_NIL);
2011 di_path_t
2012 di_path_next_phci(di_node_t node, di_path_t path)
2014 return (di_path_client_next_path(node, path));
2016 di_path_t
2017 di_path_next_client(di_node_t node, di_path_t path)
2019 return (di_path_phci_next_path(node, path));
2025 di_path_state_t
2026 di_path_state(di_path_t path)
2028 return ((di_path_state_t)DI_PATH(path)->path_state);
2031 char *
2032 di_path_node_name(di_path_t path)
2034 di_node_t client_node;
2036 /* pathinfo gets node_name from client */
2037 if ((client_node = di_path_client_node(path)) == NULL)
2038 return (NULL);
2039 return (di_node_name(client_node));
2042 char *
2043 di_path_bus_addr(di_path_t path)
2045 caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
2047 if (DI_PATH(path)->path_addr == 0)
2048 return (NULL);
2050 return ((char *)(pa + DI_PATH(path)->path_addr));
2054 di_path_instance(di_path_t path)
2056 return (DI_PATH(path)->path_instance);
2059 di_node_t
2060 di_path_client_node(di_path_t path)
2062 caddr_t pa; /* starting address of map */
2064 if (path == DI_PATH_NIL) {
2065 errno = EINVAL;
2066 return (DI_PATH_NIL);
2069 DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
2071 pa = (caddr_t)path - DI_PATH(path)->self;
2073 if (DI_PATH(path)->path_client) {
2074 return (DI_NODE(pa + DI_PATH(path)->path_client));
2078 * Deal with error condition:
2079 * If parent doesn't exist and node is not the root,
2080 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2082 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
2083 errno = ENOTSUP;
2084 else
2085 errno = ENXIO;
2087 return (DI_NODE_NIL);
2090 di_node_t
2091 di_path_phci_node(di_path_t path)
2093 caddr_t pa; /* starting address of map */
2095 if (path == DI_PATH_NIL) {
2096 errno = EINVAL;
2097 return (DI_PATH_NIL);
2100 DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
2102 pa = (caddr_t)path - DI_PATH(path)->self;
2104 if (DI_PATH(path)->path_phci) {
2105 return (DI_NODE(pa + DI_PATH(path)->path_phci));
2109 * Deal with error condition:
2110 * If parent doesn't exist and node is not the root,
2111 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2113 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
2114 errno = ENOTSUP;
2115 else
2116 errno = ENXIO;
2118 return (DI_NODE_NIL);
2121 di_path_prop_t
2122 di_path_prop_next(di_path_t path, di_path_prop_t prop)
2124 caddr_t pa;
2126 if (path == DI_PATH_NIL) {
2127 errno = EINVAL;
2128 return (DI_PROP_NIL);
2132 * prop is not NIL
2134 if (prop != DI_PROP_NIL) {
2135 if (DI_PROP(prop)->next != 0)
2136 return (DI_PATHPROP((caddr_t)prop -
2137 DI_PROP(prop)->self + DI_PROP(prop)->next));
2138 else {
2139 errno = ENXIO;
2140 return (DI_PROP_NIL);
2145 * prop is NIL-->caller asks for first property
2147 pa = (caddr_t)path - DI_PATH(path)->self;
2148 if (DI_PATH(path)->path_prop != 0) {
2149 return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
2153 * no property data-->check if snapshot includes props
2154 * in order to set the correct errno
2156 if (DINFOPROP & (DI_ALL(pa)->command))
2157 errno = ENXIO;
2158 else
2159 errno = ENOTSUP;
2161 return (DI_PROP_NIL);
2164 char *
2165 di_path_prop_name(di_path_prop_t prop)
2167 caddr_t pa; /* starting address of map */
2168 pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
2169 return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
2173 di_path_prop_len(di_path_prop_t prop)
2175 return (DI_PATHPROP(prop)->prop_len);
2179 di_path_prop_type(di_path_prop_t prop)
2181 switch (DI_PATHPROP(prop)->prop_type) {
2182 case DDI_PROP_TYPE_INT:
2183 return (DI_PROP_TYPE_INT);
2184 case DDI_PROP_TYPE_INT64:
2185 return (DI_PROP_TYPE_INT64);
2186 case DDI_PROP_TYPE_BYTE:
2187 return (DI_PROP_TYPE_BYTE);
2188 case DDI_PROP_TYPE_STRING:
2189 return (DI_PROP_TYPE_STRING);
2191 return (DI_PROP_TYPE_UNKNOWN);
2195 di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
2197 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2198 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2199 errno = EFAULT;
2200 *prop_data = NULL;
2201 return (-1);
2204 *prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
2205 + DI_PATHPROP(prop)->prop_data);
2207 return (di_prop_decode_common((void *)prop_data,
2208 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
2212 di_path_prop_ints(di_path_prop_t prop, int **prop_data)
2214 if (DI_PATHPROP(prop)->prop_len == 0)
2215 return (0);
2217 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2218 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2219 errno = EFAULT;
2220 *prop_data = NULL;
2221 return (-1);
2224 *prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
2225 + DI_PATHPROP(prop)->prop_data));
2227 return (di_prop_decode_common((void *)prop_data,
2228 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
2232 di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
2234 if (DI_PATHPROP(prop)->prop_len == 0)
2235 return (0);
2237 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2238 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2239 errno = EFAULT;
2240 *prop_data = NULL;
2241 return (-1);
2244 *prop_data = (int64_t *)((void *)((caddr_t)prop -
2245 DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
2247 return (di_prop_decode_common((void *)prop_data,
2248 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
2252 di_path_prop_strings(di_path_prop_t prop, char **prop_data)
2254 if (DI_PATHPROP(prop)->prop_len == 0)
2255 return (0);
2257 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2258 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2259 errno = EFAULT;
2260 *prop_data = NULL;
2261 return (-1);
2264 *prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
2265 + DI_PATHPROP(prop)->prop_data);
2267 return (di_prop_decode_common((void *)prop_data,
2268 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
2271 static di_path_prop_t
2272 di_path_prop_search(di_path_t path, const char *name, int type)
2274 di_path_prop_t prop = DI_PROP_NIL;
2277 * Sanity check arguments
2279 if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
2280 !DI_PROP_TYPE_VALID(type)) {
2281 errno = EINVAL;
2282 return (DI_PROP_NIL);
2285 while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
2286 int prop_type = di_path_prop_type(prop);
2288 DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
2289 di_path_prop_name(prop), prop_type));
2291 if (strcmp(name, di_path_prop_name(prop)) != 0)
2292 continue;
2294 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
2295 continue;
2297 return (prop);
2300 return (DI_PROP_NIL);
2304 di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
2305 uchar_t **prop_data)
2307 di_path_prop_t prop;
2309 if ((prop = di_path_prop_search(path, prop_name,
2310 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
2311 return (-1);
2313 return (di_path_prop_bytes(prop, prop_data));
2317 di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
2318 int **prop_data)
2320 di_path_prop_t prop;
2322 if ((prop = di_path_prop_search(path, prop_name,
2323 DI_PROP_TYPE_INT)) == DI_PROP_NIL)
2324 return (-1);
2326 return (di_path_prop_ints(prop, prop_data));
2330 di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
2331 int64_t **prop_data)
2333 di_path_prop_t prop;
2335 if ((prop = di_path_prop_search(path, prop_name,
2336 DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
2337 return (-1);
2339 return (di_path_prop_int64s(prop, prop_data));
2342 int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
2343 char **prop_data)
2345 di_path_prop_t prop;
2347 if ((prop = di_path_prop_search(path, prop_name,
2348 DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
2349 return (-1);
2351 return (di_path_prop_strings(prop, prop_data));
2355 * Consolidation private interfaces for traversing vhci nodes.
2357 di_node_t
2358 di_vhci_first_node(di_node_t root)
2360 struct di_all *dap;
2361 caddr_t pa; /* starting address of map */
2363 DPRINTF((DI_INFO, "Get first vhci node\n"));
2365 if (root == DI_NODE_NIL) {
2366 errno = EINVAL;
2367 return (DI_NODE_NIL);
2370 pa = (caddr_t)root - DI_NODE(root)->self;
2371 dap = DI_ALL(pa);
2373 if (dap->top_vhci_devinfo == NULL) {
2374 errno = ENXIO;
2375 return (DI_NODE_NIL);
2378 return (DI_NODE(pa + dap->top_vhci_devinfo));
2381 di_node_t
2382 di_vhci_next_node(di_node_t node)
2384 caddr_t pa; /* starting address of map */
2386 if (node == DI_NODE_NIL) {
2387 errno = EINVAL;
2388 return (DI_NODE_NIL);
2391 DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
2392 " current=%s\n", di_node_name(node)));
2394 if (DI_NODE(node)->next_vhci == NULL) {
2395 errno = ENXIO;
2396 return (DI_NODE_NIL);
2399 pa = (caddr_t)node - DI_NODE(node)->self;
2401 return (DI_NODE(pa + DI_NODE(node)->next_vhci));
2405 * Consolidation private interfaces for traversing phci nodes.
2407 di_node_t
2408 di_phci_first_node(di_node_t vhci_node)
2410 caddr_t pa; /* starting address of map */
2412 DPRINTF((DI_INFO, "Get first phci node:\n"
2413 " current=%s", di_node_name(vhci_node)));
2415 if (vhci_node == DI_NODE_NIL) {
2416 errno = EINVAL;
2417 return (DI_NODE_NIL);
2420 pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
2422 if (DI_NODE(vhci_node)->top_phci == NULL) {
2423 errno = ENXIO;
2424 return (DI_NODE_NIL);
2427 return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
2430 di_node_t
2431 di_phci_next_node(di_node_t node)
2433 caddr_t pa; /* starting address of map */
2435 if (node == DI_NODE_NIL) {
2436 errno = EINVAL;
2437 return (DI_NODE_NIL);
2440 DPRINTF((DI_TRACE, "next phci node on the snap shot:"
2441 " current=%s\n", di_node_name(node)));
2443 if (DI_NODE(node)->next_phci == NULL) {
2444 errno = ENXIO;
2445 return (DI_NODE_NIL);
2448 pa = (caddr_t)node - DI_NODE(node)->self;
2450 return (DI_NODE(pa + DI_NODE(node)->next_phci));
2454 * Consolidation private interfaces for private data
2456 void *
2457 di_parent_private_data(di_node_t node)
2459 caddr_t pa;
2461 if (DI_NODE(node)->parent_data == 0) {
2462 errno = ENXIO;
2463 return (NULL);
2466 if (DI_NODE(node)->parent_data == (di_off_t)-1) {
2468 * Private data requested, but not obtained due to a memory
2469 * error (e.g. wrong format specified)
2471 errno = EFAULT;
2472 return (NULL);
2475 pa = (caddr_t)node - DI_NODE(node)->self;
2476 if (DI_NODE(node)->parent_data)
2477 return (pa + DI_NODE(node)->parent_data);
2479 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2480 errno = ENXIO;
2481 else
2482 errno = ENOTSUP;
2484 return (NULL);
2487 void *
2488 di_driver_private_data(di_node_t node)
2490 caddr_t pa;
2492 if (DI_NODE(node)->driver_data == 0) {
2493 errno = ENXIO;
2494 return (NULL);
2497 if (DI_NODE(node)->driver_data == (di_off_t)-1) {
2499 * Private data requested, but not obtained due to a memory
2500 * error (e.g. wrong format specified)
2502 errno = EFAULT;
2503 return (NULL);
2506 pa = (caddr_t)node - DI_NODE(node)->self;
2507 if (DI_NODE(node)->driver_data)
2508 return (pa + DI_NODE(node)->driver_data);
2510 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2511 errno = ENXIO;
2512 else
2513 errno = ENOTSUP;
2515 return (NULL);
2519 * PROM property access
2523 * openprom driver stuff:
2524 * The maximum property length depends on the buffer size. We use
2525 * OPROMMAXPARAM defined in <sys/openpromio.h>
2527 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2528 * MAXVALSZ is maximum value size, which is whatever space left in buf
2531 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int)
2532 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME;
2534 struct di_prom_prop {
2535 char *name;
2536 int len;
2537 uchar_t *data;
2538 struct di_prom_prop *next; /* form a linked list */
2541 struct di_prom_handle { /* handle to prom */
2542 mutex_t lock; /* synchronize access to openprom fd */
2543 int fd; /* /dev/openprom file descriptor */
2544 struct di_prom_prop *list; /* linked list of prop */
2545 union {
2546 char buf[OPROMMAXPARAM];
2547 struct openpromio opp;
2548 } oppbuf;
2551 di_prom_handle_t
2552 di_prom_init()
2554 struct di_prom_handle *p;
2556 if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
2557 return (DI_PROM_HANDLE_NIL);
2559 DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
2561 (void) mutex_init(&p->lock, USYNC_THREAD, NULL);
2562 if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
2563 free(p);
2564 return (DI_PROM_HANDLE_NIL);
2566 p->list = NULL;
2568 return ((di_prom_handle_t)p);
2571 static void
2572 di_prom_prop_free(struct di_prom_prop *list)
2574 struct di_prom_prop *tmp = list;
2576 while (tmp != NULL) {
2577 list = tmp->next;
2578 if (tmp->name != NULL) {
2579 free(tmp->name);
2581 if (tmp->data != NULL) {
2582 free(tmp->data);
2584 free(tmp);
2585 tmp = list;
2589 void
2590 di_prom_fini(di_prom_handle_t ph)
2592 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2594 DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
2596 (void) close(p->fd);
2597 (void) mutex_destroy(&p->lock);
2598 di_prom_prop_free(p->list);
2600 free(p);
2604 * Internal library interface for locating the property
2605 * XXX: ph->lock must be held for the duration of call.
2607 static di_prom_prop_t
2608 di_prom_prop_found(di_prom_handle_t ph, int nodeid,
2609 di_prom_prop_t prom_prop)
2611 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2612 struct openpromio *opp = &p->oppbuf.opp;
2613 int *ip = (int *)((void *)opp->oprom_array);
2614 struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
2616 DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
2619 * Set "current" nodeid in the openprom driver
2621 opp->oprom_size = sizeof (int);
2622 *ip = nodeid;
2623 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
2624 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
2625 return (DI_PROM_PROP_NIL);
2628 DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
2630 bzero(opp, OBP_MAXBUF);
2631 opp->oprom_size = OBP_MAXPROPNAME;
2632 if (prom_prop != DI_PROM_PROP_NIL)
2633 (void) strcpy(opp->oprom_array, prop->name);
2635 if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
2636 return (DI_PROM_PROP_NIL);
2639 * Prom property found. Allocate struct for storing prop
2640 * (reuse variable prop)
2642 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
2643 return (DI_PROM_PROP_NIL);
2646 * Get a copy of property name
2648 if ((prop->name = strdup(opp->oprom_array)) == NULL) {
2649 free(prop);
2650 return (DI_PROM_PROP_NIL);
2654 * get property value and length
2656 opp->oprom_size = OBP_MAXPROPLEN;
2658 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
2659 (opp->oprom_size == (uint_t)-1)) {
2660 free(prop->name);
2661 free(prop);
2662 return (DI_PROM_PROP_NIL);
2666 * make a copy of the property value
2668 prop->len = opp->oprom_size;
2670 if (prop->len == 0)
2671 prop->data = NULL;
2672 else if ((prop->data = malloc(prop->len)) == NULL) {
2673 free(prop->name);
2674 free(prop);
2675 return (DI_PROM_PROP_NIL);
2678 bcopy(opp->oprom_array, prop->data, prop->len);
2681 * Prepend prop to list in prom handle
2683 prop->next = p->list;
2684 p->list = prop;
2686 return ((di_prom_prop_t)prop);
2689 di_prom_prop_t
2690 di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
2692 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2694 DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
2695 node, p));
2698 * paranoid check
2700 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
2701 errno = EINVAL;
2702 return (DI_PROM_PROP_NIL);
2705 if (di_nodeid(node) != DI_PROM_NODEID) {
2706 errno = ENXIO;
2707 return (DI_PROM_PROP_NIL);
2711 * synchronize access to prom file descriptor
2713 (void) mutex_lock(&p->lock);
2716 * look for next property
2718 prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
2720 (void) mutex_unlock(&p->lock);
2722 return (prom_prop);
2725 char *
2726 di_prom_prop_name(di_prom_prop_t prom_prop)
2729 * paranoid check
2731 if (prom_prop == DI_PROM_PROP_NIL) {
2732 errno = EINVAL;
2733 return (NULL);
2736 return (((struct di_prom_prop *)prom_prop)->name);
2740 di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
2743 * paranoid check
2745 if (prom_prop == DI_PROM_PROP_NIL) {
2746 errno = EINVAL;
2747 return (NULL);
2750 *prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
2752 return (((struct di_prom_prop *)prom_prop)->len);
2756 * Internal library interface for locating the property
2757 * Returns length if found, -1 if prop doesn't exist.
2759 static struct di_prom_prop *
2760 di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
2761 const char *prom_prop_name)
2763 struct openpromio *opp;
2764 struct di_prom_prop *prop;
2765 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2768 * paranoid check
2770 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
2771 errno = EINVAL;
2772 return (NULL);
2775 if (di_nodeid(node) != DI_PROM_NODEID) {
2776 errno = ENXIO;
2777 return (NULL);
2780 opp = &p->oppbuf.opp;
2782 (void) mutex_lock(&p->lock);
2784 opp->oprom_size = sizeof (int);
2785 opp->oprom_node = DI_NODE(node)->nodeid;
2786 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
2787 errno = ENXIO;
2788 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
2789 DI_NODE(node)->nodeid));
2790 (void) mutex_unlock(&p->lock);
2791 return (NULL);
2795 * get property length
2797 bzero(opp, OBP_MAXBUF);
2798 opp->oprom_size = OBP_MAXPROPLEN;
2799 (void) strcpy(opp->oprom_array, prom_prop_name);
2801 if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
2802 (opp->oprom_len == -1)) {
2803 /* no such property */
2804 (void) mutex_unlock(&p->lock);
2805 return (NULL);
2809 * Prom property found. Allocate struct for storing prop
2811 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
2812 (void) mutex_unlock(&p->lock);
2813 return (NULL);
2815 prop->name = NULL; /* we don't need the name */
2816 prop->len = opp->oprom_len;
2818 if (prop->len == 0) { /* boolean property */
2819 prop->data = NULL;
2820 prop->next = p->list;
2821 p->list = prop;
2822 (void) mutex_unlock(&p->lock);
2823 return (prop);
2827 * retrieve the property value
2829 bzero(opp, OBP_MAXBUF);
2830 opp->oprom_size = OBP_MAXPROPLEN;
2831 (void) strcpy(opp->oprom_array, prom_prop_name);
2833 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
2834 (opp->oprom_size == (uint_t)-1)) {
2835 /* error retrieving property value */
2836 (void) mutex_unlock(&p->lock);
2837 free(prop);
2838 return (NULL);
2842 * make a copy of the property value, stick in ph->list
2844 if ((prop->data = malloc(prop->len)) == NULL) {
2845 (void) mutex_unlock(&p->lock);
2846 free(prop);
2847 return (NULL);
2850 bcopy(opp->oprom_array, prop->data, prop->len);
2852 prop->next = p->list;
2853 p->list = prop;
2854 (void) mutex_unlock(&p->lock);
2856 return (prop);
2860 di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
2861 const char *prom_prop_name, int **prom_prop_data)
2863 int len;
2864 struct di_prom_prop *prop;
2866 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
2868 if (prop == NULL) {
2869 *prom_prop_data = NULL;
2870 return (-1);
2873 if (prop->len == 0) { /* boolean property */
2874 *prom_prop_data = NULL;
2875 return (0);
2878 len = di_prop_decode_common((void *)&prop->data, prop->len,
2879 DI_PROP_TYPE_INT, 1);
2880 *prom_prop_data = (int *)((void *)prop->data);
2882 return (len);
2886 di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
2887 const char *prom_prop_name, char **prom_prop_data)
2889 int len;
2890 struct di_prom_prop *prop;
2892 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
2894 if (prop == NULL) {
2895 *prom_prop_data = NULL;
2896 return (-1);
2899 if (prop->len == 0) { /* boolean property */
2900 *prom_prop_data = NULL;
2901 return (0);
2905 * Fix an openprom bug (OBP string not NULL terminated).
2906 * XXX This should really be fixed in promif.
2908 if (((char *)prop->data)[prop->len - 1] != '\0') {
2909 uchar_t *tmp;
2910 prop->len++;
2911 if ((tmp = realloc(prop->data, prop->len)) == NULL)
2912 return (-1);
2914 prop->data = tmp;
2915 ((char *)prop->data)[prop->len - 1] = '\0';
2916 DPRINTF((DI_INFO, "OBP string not NULL terminated: "
2917 "node=%s, prop=%s, val=%s\n",
2918 di_node_name(node), prom_prop_name, prop->data));
2921 len = di_prop_decode_common((void *)&prop->data, prop->len,
2922 DI_PROP_TYPE_STRING, 1);
2923 *prom_prop_data = (char *)prop->data;
2925 return (len);
2929 di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
2930 const char *prom_prop_name, uchar_t **prom_prop_data)
2932 int len;
2933 struct di_prom_prop *prop;
2935 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
2937 if (prop == NULL) {
2938 *prom_prop_data = NULL;
2939 return (-1);
2942 if (prop->len == 0) { /* boolean property */
2943 *prom_prop_data = NULL;
2944 return (0);
2947 len = di_prop_decode_common((void *)&prop->data, prop->len,
2948 DI_PROP_TYPE_BYTE, 1);
2949 *prom_prop_data = prop->data;
2951 return (len);
2955 * returns an allocated array through <prop_data> only when its count > 0
2956 * and the number of entries (count) as the function return value;
2957 * use di_slot_names_free() to free the array
2960 di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
2962 int rawlen, count;
2963 uchar_t *rawdata;
2964 char *nm = di_prop_name(prop);
2966 if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
2967 goto ERROUT;
2969 rawlen = di_prop_rawdata(prop, &rawdata);
2970 if (rawlen <= 0 || rawdata == NULL)
2971 goto ERROUT;
2973 count = di_slot_names_decode(rawdata, rawlen, prop_data);
2974 if (count < 0 || *prop_data == NULL)
2975 goto ERROUT;
2977 return (count);
2978 /*NOTREACHED*/
2979 ERROUT:
2980 errno = EFAULT;
2981 *prop_data = NULL;
2982 return (-1);
2986 di_prop_lookup_slot_names(dev_t dev, di_node_t node,
2987 di_slot_name_t **prop_data)
2989 di_prop_t prop;
2992 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
2993 * and slot-names is properly flagged as such
2995 if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
2996 DI_PROP_NIL) {
2997 *prop_data = NULL;
2998 return (-1);
3001 return (di_prop_slot_names(prop, (void *)prop_data));
3005 * returns an allocated array through <prop_data> only when its count > 0
3006 * and the number of entries (count) as the function return value;
3007 * use di_slot_names_free() to free the array
3010 di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
3012 int rawlen, count;
3013 uchar_t *rawdata;
3015 rawlen = di_prom_prop_data(prom_prop, &rawdata);
3016 if (rawlen <= 0 || rawdata == NULL)
3017 goto ERROUT;
3019 count = di_slot_names_decode(rawdata, rawlen, prop_data);
3020 if (count < 0 || *prop_data == NULL)
3021 goto ERROUT;
3023 return (count);
3024 /*NOTREACHED*/
3025 ERROUT:
3026 errno = EFAULT;
3027 *prop_data = NULL;
3028 return (-1);
3032 di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
3033 di_slot_name_t **prop_data)
3035 struct di_prom_prop *prom_prop;
3037 prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
3038 if (prom_prop == NULL) {
3039 *prop_data = NULL;
3040 return (-1);
3043 return (di_prom_prop_slot_names(prom_prop, prop_data));
3046 di_lnode_t
3047 di_link_to_lnode(di_link_t link, uint_t endpoint)
3049 struct di_all *di_all;
3051 if ((link == DI_LINK_NIL) ||
3052 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3053 errno = EINVAL;
3054 return (DI_LNODE_NIL);
3057 di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
3059 if (endpoint == DI_LINK_SRC) {
3060 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
3061 } else {
3062 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
3064 /* NOTREACHED */
3067 char *
3068 di_lnode_name(di_lnode_t lnode)
3070 return (di_driver_name(di_lnode_devinfo(lnode)));
3073 di_node_t
3074 di_lnode_devinfo(di_lnode_t lnode)
3076 struct di_all *di_all;
3078 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3079 return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
3083 di_lnode_devt(di_lnode_t lnode, dev_t *devt)
3085 if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
3086 errno = EINVAL;
3087 return (-1);
3089 if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
3090 (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
3091 return (-1);
3093 *devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
3094 return (0);
3098 di_link_spectype(di_link_t link)
3100 return (DI_LINK(link)->spec_type);
3103 void
3104 di_minor_private_set(di_minor_t minor, void *data)
3106 DI_MINOR(minor)->user_private_data = (uintptr_t)data;
3109 void *
3110 di_minor_private_get(di_minor_t minor)
3112 return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
3115 void
3116 di_node_private_set(di_node_t node, void *data)
3118 DI_NODE(node)->user_private_data = (uintptr_t)data;
3121 void *
3122 di_node_private_get(di_node_t node)
3124 return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
3127 void
3128 di_path_private_set(di_path_t path, void *data)
3130 DI_PATH(path)->user_private_data = (uintptr_t)data;
3133 void *
3134 di_path_private_get(di_path_t path)
3136 return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
3139 void
3140 di_lnode_private_set(di_lnode_t lnode, void *data)
3142 DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
3145 void *
3146 di_lnode_private_get(di_lnode_t lnode)
3148 return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
3151 void
3152 di_link_private_set(di_link_t link, void *data)
3154 DI_LINK(link)->user_private_data = (uintptr_t)data;
3157 void *
3158 di_link_private_get(di_link_t link)
3160 return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
3163 di_lnode_t
3164 di_lnode_next(di_node_t node, di_lnode_t lnode)
3166 struct di_all *di_all;
3169 * paranoid error checking
3171 if (node == DI_NODE_NIL) {
3172 errno = EINVAL;
3173 return (DI_LNODE_NIL);
3176 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3178 if (lnode == DI_NODE_NIL) {
3179 if (DI_NODE(node)->lnodes != NULL)
3180 return (DI_LNODE((caddr_t)di_all +
3181 DI_NODE(node)->lnodes));
3182 } else {
3183 if (DI_LNODE(lnode)->node_next != NULL)
3184 return (DI_LNODE((caddr_t)di_all +
3185 DI_LNODE(lnode)->node_next));
3188 if (DINFOLYR & DI_ALL(di_all)->command)
3189 errno = ENXIO;
3190 else
3191 errno = ENOTSUP;
3193 return (DI_LNODE_NIL);
3196 di_link_t
3197 di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
3199 struct di_all *di_all;
3202 * paranoid error checking
3204 if ((node == DI_NODE_NIL) ||
3205 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3206 errno = EINVAL;
3207 return (DI_LINK_NIL);
3210 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3212 if (endpoint == DI_LINK_SRC) {
3213 if (link == DI_LINK_NIL) {
3214 if (DI_NODE(node)->src_links != NULL)
3215 return (DI_LINK((caddr_t)di_all +
3216 DI_NODE(node)->src_links));
3217 } else {
3218 if (DI_LINK(link)->src_node_next != NULL)
3219 return (DI_LINK((caddr_t)di_all +
3220 DI_LINK(link)->src_node_next));
3222 } else {
3223 if (link == DI_LINK_NIL) {
3224 if (DI_NODE(node)->tgt_links != NULL)
3225 return (DI_LINK((caddr_t)di_all +
3226 DI_NODE(node)->tgt_links));
3227 } else {
3228 if (DI_LINK(link)->tgt_node_next != NULL)
3229 return (DI_LINK((caddr_t)di_all +
3230 DI_LINK(link)->tgt_node_next));
3234 if (DINFOLYR & DI_ALL(di_all)->command)
3235 errno = ENXIO;
3236 else
3237 errno = ENOTSUP;
3239 return (DI_LINK_NIL);
3242 di_link_t
3243 di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
3245 struct di_all *di_all;
3248 * paranoid error checking
3250 if ((lnode == DI_LNODE_NIL) ||
3251 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3252 errno = EINVAL;
3253 return (DI_LINK_NIL);
3256 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3258 if (endpoint == DI_LINK_SRC) {
3259 if (link == DI_LINK_NIL) {
3260 if (DI_LNODE(lnode)->link_out == NULL)
3261 return (DI_LINK_NIL);
3262 return (DI_LINK((caddr_t)di_all +
3263 DI_LNODE(lnode)->link_out));
3264 } else {
3265 if (DI_LINK(link)->src_link_next == NULL)
3266 return (DI_LINK_NIL);
3267 return (DI_LINK((caddr_t)di_all +
3268 DI_LINK(link)->src_link_next));
3270 } else {
3271 if (link == DI_LINK_NIL) {
3272 if (DI_LNODE(lnode)->link_in == NULL)
3273 return (DI_LINK_NIL);
3274 return (DI_LINK((caddr_t)di_all +
3275 DI_LNODE(lnode)->link_in));
3276 } else {
3277 if (DI_LINK(link)->tgt_link_next == NULL)
3278 return (DI_LINK_NIL);
3279 return (DI_LINK((caddr_t)di_all +
3280 DI_LINK(link)->tgt_link_next));
3283 /* NOTREACHED */
3287 * Internal library function:
3288 * Invoke callback for each link data on the link list of first node
3289 * on node_list headp, and place children of first node on the list.
3291 * This is similar to walk_one_node, except we only walk in child
3292 * first mode.
3294 static void
3295 walk_one_link(struct node_list **headp, uint_t ep,
3296 void *arg, int (*callback)(di_link_t link, void *arg))
3298 int action = DI_WALK_CONTINUE;
3299 di_link_t link = DI_LINK_NIL;
3300 di_node_t node = (*headp)->node;
3302 while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
3303 action = callback(link, arg);
3304 if (action == DI_WALK_TERMINATE) {
3305 break;
3309 update_node_list(action, DI_WALK_LINKGEN, headp);
3313 di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
3314 int (*link_callback)(di_link_t link, void *arg))
3316 struct node_list *head; /* node_list for tree walk */
3318 #ifdef DEBUG
3319 char *devfspath = di_devfs_path(root);
3320 DPRINTF((DI_INFO, "walking %s link data under %s\n",
3321 (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
3322 di_devfs_path_free(devfspath);
3323 #endif
3326 * paranoid error checking
3328 if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
3329 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3330 errno = EINVAL;
3331 return (-1);
3334 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3335 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3336 return (-1);
3339 head->next = NULL;
3340 head->node = root;
3342 DPRINTF((DI_INFO, "Start link data walking from node %s\n",
3343 di_node_name(root)));
3345 while (head != NULL)
3346 walk_one_link(&head, endpoint, arg, link_callback);
3348 return (0);
3352 * Internal library function:
3353 * Invoke callback for each link data on the link list of first node
3354 * on node_list headp, and place children of first node on the list.
3356 * This is similar to walk_one_node, except we only walk in child
3357 * first mode.
3359 static void
3360 walk_one_lnode(struct node_list **headp, void *arg,
3361 int (*callback)(di_lnode_t lnode, void *arg))
3363 int action = DI_WALK_CONTINUE;
3364 di_lnode_t lnode = DI_LNODE_NIL;
3365 di_node_t node = (*headp)->node;
3367 while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
3368 action = callback(lnode, arg);
3369 if (action == DI_WALK_TERMINATE) {
3370 break;
3374 update_node_list(action, DI_WALK_LINKGEN, headp);
3378 di_walk_lnode(di_node_t root, uint_t flag, void *arg,
3379 int (*lnode_callback)(di_lnode_t lnode, void *arg))
3381 struct node_list *head; /* node_list for tree walk */
3383 #ifdef DEBUG
3384 char *devfspath = di_devfs_path(root);
3385 DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
3386 di_devfs_path_free(devfspath);
3387 #endif
3390 * paranoid error checking
3392 if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
3393 errno = EINVAL;
3394 return (-1);
3397 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3398 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3399 return (-1);
3402 head->next = NULL;
3403 head->node = root;
3405 DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
3406 di_node_name(root)));
3408 while (head != NULL)
3409 walk_one_lnode(&head, arg, lnode_callback);
3411 return (0);
3414 di_node_t
3415 di_lookup_node(di_node_t root, char *devfspath)
3417 struct di_all *dap;
3418 di_node_t node;
3419 char *copy, *slash, *pname, *paddr;
3422 * Path must be absolute and musn't have duplicate slashes
3424 if (*devfspath != '/' || strstr(devfspath, "//")) {
3425 DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
3426 return (DI_NODE_NIL);
3429 if (root == DI_NODE_NIL) {
3430 DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
3431 return (DI_NODE_NIL);
3434 dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
3435 if (strcmp(dap->root_path, "/") != 0) {
3436 DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
3437 return (DI_NODE_NIL);
3440 if ((copy = strdup(devfspath)) == NULL) {
3441 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3442 return (DI_NODE_NIL);
3445 for (slash = copy, node = root; slash; ) {
3448 * Handle devfspath = "/" case as well as trailing '/'
3450 if (*(slash + 1) == '\0')
3451 break;
3454 * More path-components exist. Deal with the next one
3456 pname = slash + 1;
3457 node = di_child_node(node);
3459 if (slash = strchr(pname, '/'))
3460 *slash = '\0';
3461 if (paddr = strchr(pname, '@'))
3462 *paddr++ = '\0';
3464 for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
3465 char *name, *baddr;
3467 name = di_node_name(node);
3468 baddr = di_bus_addr(node);
3470 if (strcmp(pname, name) != 0)
3471 continue;
3474 * Mappings between a "path-address" and bus-addr
3476 * paddr baddr
3477 * ---------------------
3478 * NULL NULL
3479 * NULL ""
3480 * "" N/A (invalid paddr)
3482 if (paddr && baddr && strcmp(paddr, baddr) == 0)
3483 break;
3484 if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
3485 break;
3489 * No nodes in the sibling list or there was no match
3491 if (node == DI_NODE_NIL) {
3492 DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
3493 free(copy);
3494 return (DI_NODE_NIL);
3498 assert(node != DI_NODE_NIL);
3499 free(copy);
3500 return (node);
3503 di_path_t
3504 di_lookup_path(di_node_t root, char *devfspath)
3506 di_node_t phci_node;
3507 di_path_t path = DI_PATH_NIL;
3508 char *copy, *lastslash;
3509 char *pname, *paddr;
3510 char *path_name, *path_addr;
3512 if ((copy = strdup(devfspath)) == NULL) {
3513 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3514 return (DI_NODE_NIL);
3517 if ((lastslash = strrchr(copy, '/')) == NULL) {
3518 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3519 goto out;
3522 /* stop at pHCI and find the node for the phci */
3523 *lastslash = '\0';
3524 phci_node = di_lookup_node(root, copy);
3525 if (phci_node == NULL) {
3526 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3527 goto out;
3530 /* set up pname and paddr for last component */
3531 pname = lastslash + 1;
3532 if ((paddr = strchr(pname, '@')) == NULL) {
3533 DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
3534 goto out;
3536 *paddr++ = '\0';
3538 /* walk paths below phci looking for match */
3539 for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
3540 path != DI_PATH_NIL;
3541 path = di_path_phci_next_path(phci_node, path)) {
3543 /* get name@addr of path */
3544 path_name = di_path_node_name(path);
3545 path_addr = di_path_bus_addr(path);
3546 if ((path_name == NULL) || (path_addr == NULL))
3547 continue;
3549 /* break on match */
3550 if ((strcmp(pname, path_name) == 0) &&
3551 (strcmp(paddr, path_addr) == 0))
3552 break;
3555 out: free(copy);
3556 return (path);
3559 static char *
3560 msglevel2str(di_debug_t msglevel)
3562 switch (msglevel) {
3563 case DI_ERR:
3564 return ("ERROR");
3565 case DI_INFO:
3566 return ("Info");
3567 case DI_TRACE:
3568 return ("Trace");
3569 case DI_TRACE1:
3570 return ("Trace1");
3571 case DI_TRACE2:
3572 return ("Trace2");
3573 default:
3574 return ("UNKNOWN");
3578 void
3579 dprint(di_debug_t msglevel, const char *fmt, ...)
3581 va_list ap;
3582 char *estr;
3584 if (di_debug <= DI_QUIET)
3585 return;
3587 if (di_debug < msglevel)
3588 return;
3590 estr = msglevel2str(msglevel);
3592 assert(estr);
3594 va_start(ap, fmt);
3596 (void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
3597 (ulong_t)getpid(), estr);
3598 (void) vfprintf(stderr, fmt, ap);
3600 va_end(ap);
3603 /* end of devinfo.c */