16863 implement C23 stdbit.h
[illumos-gate.git] / usr / src / lib / libdevinfo / devinfo.c
blob718a93235948583ff7e7d6a1ec623cc19eedbe25
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 (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2024 MNX Cloud, Inc.
27 * Interfaces for getting device configuration data from kernel
28 * through the devinfo driver.
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <stropts.h>
36 #include <fcntl.h>
37 #include <poll.h>
38 #include <synch.h>
39 #include <unistd.h>
40 #include <sys/mkdev.h>
41 #include <sys/obpdefs.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <sys/autoconf.h>
46 #include <stdarg.h>
47 #include <sys/ddi_hp.h>
49 #define NDEBUG 1
50 #include <assert.h>
52 #include "libdevinfo.h"
55 * Debug message levels
57 typedef enum {
58 DI_QUIET = 0, /* No debug messages - the default */
59 DI_ERR = 1,
60 DI_INFO,
61 DI_TRACE,
62 DI_TRACE1,
63 DI_TRACE2
64 } di_debug_t;
66 int di_debug = DI_QUIET;
68 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; }
70 void dprint(di_debug_t msglevel, const char *fmt, ...);
73 #pragma init(_libdevinfo_init)
75 void
76 _libdevinfo_init()
78 char *debug_str = getenv("_LIBDEVINFO_DEBUG");
80 if (debug_str) {
81 errno = 0;
82 di_debug = atoi(debug_str);
83 if (errno || di_debug < DI_QUIET)
84 di_debug = DI_QUIET;
88 di_node_t
89 di_init(const char *phys_path, uint_t flag)
91 return (di_init_impl(phys_path, flag, NULL));
95 * We use blocking_open() to guarantee access to the devinfo device, if open()
96 * is failing with EAGAIN.
98 static int
99 blocking_open(const char *path, int oflag)
101 int fd;
103 while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
104 (void) poll(NULL, 0, 1 * MILLISEC);
106 return (fd);
109 /* private interface */
110 di_node_t
111 di_init_driver(const char *drv_name, uint_t flag)
113 int fd;
114 char driver[MAXPATHLEN];
117 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
118 * which should be sufficient for any sensible programmer.
120 if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
121 errno = EINVAL;
122 return (DI_NODE_NIL);
124 (void) strcpy(driver, drv_name);
127 * open the devinfo driver
129 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
130 O_RDONLY)) == -1) {
131 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
132 return (DI_NODE_NIL);
135 if (ioctl(fd, DINFOLODRV, driver) != 0) {
136 DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
137 (void) close(fd);
138 errno = ENXIO;
139 return (DI_NODE_NIL);
141 (void) close(fd);
144 * Driver load succeeded, return a snapshot
146 return (di_init("/", flag));
149 di_node_t
150 di_init_impl(const char *phys_path, uint_t flag,
151 struct di_priv_data *priv)
153 caddr_t pa;
154 int fd, map_size;
155 struct di_all *dap;
156 struct dinfo_io dinfo_io;
158 uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
159 uint_t pagemask = ~pageoffset;
161 DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
164 * Make sure there is no minor name in the path
165 * and the path do not start with /devices....
167 if (phys_path == NULL ||
168 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 == 0) {
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_DOWN;
981 if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
982 result |= DI_DEVICE_DEGRADED;
983 if (DI_NODE(node)->state & DEVI_DEVICE_REMOVED)
984 result |= DI_DEVICE_REMOVED;
985 if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
986 result |= DI_BUS_QUIESCED;
987 if (DI_NODE(node)->state & DEVI_BUS_DOWN)
988 result |= DI_BUS_DOWN;
990 return (result);
993 ddi_node_state_t
994 di_node_state(di_node_t node)
996 return (DI_NODE(node)->node_state);
999 uint_t
1000 di_flags(di_node_t node)
1002 return (DI_NODE(node)->flags);
1005 uint_t
1006 di_retired(di_node_t node)
1008 return (di_flags(node) & DEVI_RETIRED);
1011 ddi_devid_t
1012 di_devid(di_node_t node)
1014 if (DI_NODE(node)->devid == 0)
1015 return (NULL);
1017 return ((ddi_devid_t)((caddr_t)node +
1018 DI_NODE(node)->devid - DI_NODE(node)->self));
1022 di_driver_major(di_node_t node)
1024 int major;
1026 major = DI_NODE(node)->drv_major;
1027 if (major < 0)
1028 return (-1);
1029 return (major);
1032 char *
1033 di_driver_name(di_node_t node)
1035 int major;
1036 caddr_t pa;
1037 struct di_devnm *devnm;
1039 major = DI_NODE(node)->drv_major;
1040 if (major < 0)
1041 return (NULL);
1043 pa = (caddr_t)node - DI_NODE(node)->self;
1044 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1046 if (devnm[major].name)
1047 return (pa + devnm[major].name);
1048 else
1049 return (NULL);
1052 uint_t
1053 di_driver_ops(di_node_t node)
1055 int major;
1056 caddr_t pa;
1057 struct di_devnm *devnm;
1059 major = DI_NODE(node)->drv_major;
1060 if (major < 0)
1061 return (0);
1063 pa = (caddr_t)node - DI_NODE(node)->self;
1064 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1066 return (devnm[major].ops);
1070 * Returns pointer to the allocated string, which must be freed by the caller.
1072 char *
1073 di_devfs_path(di_node_t node)
1075 caddr_t pa;
1076 di_node_t parent;
1077 int depth = 0, len = 0;
1078 char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH];
1080 if (node == DI_NODE_NIL) {
1081 errno = EINVAL;
1082 return (NULL);
1086 * trace back to root, note the node_name & address
1088 while ((parent = di_parent_node(node)) != DI_NODE_NIL) {
1089 name[depth] = di_node_name(node);
1090 len += strlen(name[depth]) + 1; /* 1 for '/' */
1092 if ((addr[depth] = di_bus_addr(node)) != NULL)
1093 len += strlen(addr[depth]) + 1; /* 1 for '@' */
1095 node = parent;
1096 depth++;
1100 * get the path to the root of snapshot
1102 pa = (caddr_t)node - DI_NODE(node)->self;
1103 name[depth] = DI_ALL(pa)->root_path;
1104 len += strlen(name[depth]) + 1;
1107 * allocate buffer and assemble path
1109 if ((buf = malloc(len)) == NULL) {
1110 return (NULL);
1113 (void) strcpy(buf, name[depth]);
1114 len = strlen(buf);
1115 if (buf[len - 1] == '/')
1116 len--; /* delete trailing '/' */
1118 while (depth) {
1119 depth--;
1120 buf[len] = '/';
1121 (void) strcpy(buf + len + 1, name[depth]);
1122 len += strlen(name[depth]) + 1;
1123 if (addr[depth] && addr[depth][0] != '\0') {
1124 buf[len] = '@';
1125 (void) strcpy(buf + len + 1, addr[depth]);
1126 len += strlen(addr[depth]) + 1;
1130 return (buf);
1133 char *
1134 di_devfs_minor_path(di_minor_t minor)
1136 di_node_t node;
1137 char *full_path, *name, *devfspath;
1138 int full_path_len;
1140 if (minor == DI_MINOR_NIL) {
1141 errno = EINVAL;
1142 return (NULL);
1145 name = di_minor_name(minor);
1146 node = di_minor_devinfo(minor);
1147 devfspath = di_devfs_path(node);
1148 if (devfspath == NULL)
1149 return (NULL);
1151 /* make the full path to the device minor node */
1152 full_path_len = strlen(devfspath) + strlen(name) + 2;
1153 full_path = (char *)calloc(1, full_path_len);
1154 if (full_path != NULL)
1155 (void) snprintf(full_path, full_path_len, "%s:%s",
1156 devfspath, name);
1158 di_devfs_path_free(devfspath);
1159 return (full_path);
1163 * Produce a string representation of path to di_path_t (pathinfo node). This
1164 * string is identical to di_devfs_path had the device been enumerated under
1165 * the pHCI: it has a base path to pHCI, then uses node_name of client, and
1166 * device unit-address of pathinfo node.
1168 char *
1169 di_path_devfs_path(di_path_t path)
1171 di_node_t phci_node;
1172 char *phci_path, *path_name, *path_addr;
1173 char *full_path;
1174 int full_path_len;
1176 if (path == DI_PATH_NIL) {
1177 errno = EINVAL;
1178 return (NULL);
1181 /* get name@addr for path */
1182 path_name = di_path_node_name(path);
1183 path_addr = di_path_bus_addr(path);
1184 if ((path_name == NULL) || (path_addr == NULL))
1185 return (NULL);
1187 /* base path to pHCI devinfo node */
1188 phci_node = di_path_phci_node(path);
1189 if (phci_node == NULL)
1190 return (NULL);
1191 phci_path = di_devfs_path(phci_node);
1192 if (phci_path == NULL)
1193 return (NULL);
1195 /* make the full string representation of path */
1196 full_path_len = strlen(phci_path) + 1 + strlen(path_name) +
1197 1 + strlen(path_addr) + 1;
1198 full_path = (char *)calloc(1, full_path_len);
1200 if (full_path != NULL)
1201 (void) snprintf(full_path, full_path_len, "%s/%s@%s",
1202 phci_path, path_name, path_addr);
1203 di_devfs_path_free(phci_path);
1204 return (full_path);
1207 char *
1208 di_path_client_devfs_path(di_path_t path)
1210 return (di_devfs_path(di_path_client_node(path)));
1213 void
1214 di_devfs_path_free(char *buf)
1216 if (buf == NULL) {
1217 DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
1218 return;
1221 free(buf);
1225 * Return 1 if name is a IEEE-1275 generic name. If new generic
1226 * names are defined, they should be added to this table
1228 static int
1229 is_generic(const char *name, int len)
1231 const char **gp;
1233 /* from IEEE-1275 recommended practices section 3 */
1234 static const char *generic_names[] = {
1235 "atm",
1236 "disk",
1237 "display",
1238 "dma-controller",
1239 "ethernet",
1240 "fcs",
1241 "fdc",
1242 "fddi",
1243 "fibre-channel",
1244 "ide",
1245 "interrupt-controller",
1246 "isa",
1247 "keyboard",
1248 "memory",
1249 "mouse",
1250 "nvram",
1251 "pc-card",
1252 "pci",
1253 "printer",
1254 "rtc",
1255 "sbus",
1256 "scanner",
1257 "scsi",
1258 "serial",
1259 "sound",
1260 "ssa",
1261 "tape",
1262 "timer",
1263 "token-ring",
1264 "vme",
1268 for (gp = generic_names; *gp; gp++) {
1269 if ((strncmp(*gp, name, len) == 0) &&
1270 (strlen(*gp) == len))
1271 return (1);
1273 return (0);
1277 * Determine if two paths below /devices refer to the same device, ignoring
1278 * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*".
1279 * Return 1 if the paths match.
1282 di_devfs_path_match(const char *dp1, const char *dp2)
1284 const char *p1, *p2;
1285 const char *ec1, *ec2;
1286 const char *at1, *at2;
1287 char nc;
1288 int g1, g2;
1290 /* progress through both strings */
1291 for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) {
1292 /* require match until the start of a component */
1293 if (*p1 != '/')
1294 continue;
1296 /* advance p1 and p2 to start of 'name' in component */
1297 nc = *(p1 + 1);
1298 if ((nc == '\0') || (nc == '/'))
1299 continue; /* skip trash */
1300 p1++;
1301 p2++;
1304 * Both p1 and p2 point to beginning of 'name' in component.
1305 * Determine where current component ends: next '/' or '\0'.
1307 ec1 = strchr(p1, '/');
1308 if (ec1 == NULL)
1309 ec1 = p1 + strlen(p1);
1310 ec2 = strchr(p2, '/');
1311 if (ec2 == NULL)
1312 ec2 = p2 + strlen(p2);
1314 /* Determine where name ends based on whether '@' exists */
1315 at1 = strchr(p1, '@');
1316 at2 = strchr(p2, '@');
1317 if (at1 && (at1 < ec1))
1318 ec1 = at1;
1319 if (at2 && (at2 < ec2))
1320 ec2 = at2;
1323 * At this point p[12] point to beginning of name and
1324 * ec[12] point to character past the end of name. Determine
1325 * if the names are generic.
1327 g1 = is_generic(p1, ec1 - p1);
1328 g2 = is_generic(p2, ec2 - p2);
1330 if (g1 != g2) {
1332 * one generic and one non-generic
1333 * skip past the names in the match.
1335 p1 = ec1;
1336 p2 = ec2;
1337 } else {
1338 if (*p1 != *p2)
1339 break;
1343 return ((*p1 == *p2) ? 1 : 0);
1346 /* minor data access */
1347 di_minor_t
1348 di_minor_next(di_node_t node, di_minor_t minor)
1350 caddr_t pa;
1353 * paranoid error checking
1355 if (node == DI_NODE_NIL) {
1356 errno = EINVAL;
1357 return (DI_MINOR_NIL);
1361 * minor is not NIL
1363 if (minor != DI_MINOR_NIL) {
1364 if (DI_MINOR(minor)->next != 0)
1365 return ((di_minor_t)((void *)((caddr_t)minor -
1366 DI_MINOR(minor)->self + DI_MINOR(minor)->next)));
1367 else {
1368 errno = ENXIO;
1369 return (DI_MINOR_NIL);
1374 * minor is NIL-->caller asks for first minor node
1376 if (DI_NODE(node)->minor_data != 0) {
1377 return (DI_MINOR((caddr_t)node - DI_NODE(node)->self +
1378 DI_NODE(node)->minor_data));
1382 * no minor data-->check if snapshot includes minor data
1383 * in order to set the correct errno
1385 pa = (caddr_t)node - DI_NODE(node)->self;
1386 if (DINFOMINOR & DI_ALL(pa)->command)
1387 errno = ENXIO;
1388 else
1389 errno = ENOTSUP;
1391 return (DI_MINOR_NIL);
1394 /* private interface for dealing with alias minor link generation */
1395 di_node_t
1396 di_minor_devinfo(di_minor_t minor)
1398 if (minor == DI_MINOR_NIL) {
1399 errno = EINVAL;
1400 return (DI_NODE_NIL);
1403 return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
1404 DI_MINOR(minor)->node));
1407 ddi_minor_type
1408 di_minor_type(di_minor_t minor)
1410 return (DI_MINOR(minor)->type);
1413 char *
1414 di_minor_name(di_minor_t minor)
1416 if (DI_MINOR(minor)->name == 0)
1417 return (NULL);
1419 return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
1422 dev_t
1423 di_minor_devt(di_minor_t minor)
1425 return (makedev(DI_MINOR(minor)->dev_major,
1426 DI_MINOR(minor)->dev_minor));
1430 di_minor_spectype(di_minor_t minor)
1432 return (DI_MINOR(minor)->spec_type);
1435 char *
1436 di_minor_nodetype(di_minor_t minor)
1438 if (DI_MINOR(minor)->node_type == 0)
1439 return (NULL);
1441 return ((caddr_t)minor -
1442 DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
1446 * Single public interface for accessing software properties
1448 di_prop_t
1449 di_prop_next(di_node_t node, di_prop_t prop)
1451 int list = DI_PROP_DRV_LIST;
1454 * paranoid check
1456 if (node == DI_NODE_NIL) {
1457 errno = EINVAL;
1458 return (DI_PROP_NIL);
1462 * Find which prop list we are at
1464 if (prop != DI_PROP_NIL)
1465 list = DI_PROP(prop)->prop_list;
1467 do {
1468 switch (list++) {
1469 case DI_PROP_DRV_LIST:
1470 prop = di_prop_drv_next(node, prop);
1471 break;
1472 case DI_PROP_SYS_LIST:
1473 prop = di_prop_sys_next(node, prop);
1474 break;
1475 case DI_PROP_GLB_LIST:
1476 prop = di_prop_global_next(node, prop);
1477 break;
1478 case DI_PROP_HW_LIST:
1479 prop = di_prop_hw_next(node, prop);
1480 break;
1481 default: /* shouldn't happen */
1482 errno = EFAULT;
1483 return (DI_PROP_NIL);
1485 } while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
1487 return (prop);
1490 dev_t
1491 di_prop_devt(di_prop_t prop)
1493 return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
1496 char *
1497 di_prop_name(di_prop_t prop)
1499 if (DI_PROP(prop)->prop_name == 0)
1500 return (NULL);
1502 return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
1506 di_prop_type(di_prop_t prop)
1508 uint_t flags = DI_PROP(prop)->prop_flags;
1510 if (flags & DDI_PROP_UNDEF_IT)
1511 return (DI_PROP_TYPE_UNDEF_IT);
1513 if (DI_PROP(prop)->prop_len == 0)
1514 return (DI_PROP_TYPE_BOOLEAN);
1516 if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
1517 return (DI_PROP_TYPE_UNKNOWN);
1519 if (flags & DDI_PROP_TYPE_INT)
1520 return (DI_PROP_TYPE_INT);
1522 if (flags & DDI_PROP_TYPE_INT64)
1523 return (DI_PROP_TYPE_INT64);
1525 if (flags & DDI_PROP_TYPE_STRING)
1526 return (DI_PROP_TYPE_STRING);
1528 if (flags & DDI_PROP_TYPE_BYTE)
1529 return (DI_PROP_TYPE_BYTE);
1532 * Shouldn't get here. In case we do, return unknown type.
1534 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
1535 * to add DI_PROP_TYPE_COMPOSITE.
1537 DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
1539 return (DI_PROP_TYPE_UNKNOWN);
1543 * Extract type-specific values of an property
1545 extern int di_prop_decode_common(void *prop_data, int len,
1546 int ddi_type, int prom);
1549 di_prop_ints(di_prop_t prop, int **prop_data)
1551 if (DI_PROP(prop)->prop_len == 0)
1552 return (0); /* boolean property */
1554 if ((DI_PROP(prop)->prop_data == 0) ||
1555 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1556 errno = EFAULT;
1557 *prop_data = NULL;
1558 return (-1);
1561 *prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1562 + DI_PROP(prop)->prop_data));
1564 return (di_prop_decode_common((void *)prop_data,
1565 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
1569 di_prop_int64(di_prop_t prop, int64_t **prop_data)
1571 if (DI_PROP(prop)->prop_len == 0)
1572 return (0); /* boolean property */
1574 if ((DI_PROP(prop)->prop_data == 0) ||
1575 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1576 errno = EFAULT;
1577 *prop_data = NULL;
1578 return (-1);
1581 *prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1582 + DI_PROP(prop)->prop_data));
1584 return (di_prop_decode_common((void *)prop_data,
1585 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
1589 di_prop_strings(di_prop_t prop, char **prop_data)
1591 if (DI_PROP(prop)->prop_len == 0)
1592 return (0); /* boolean property */
1594 if ((DI_PROP(prop)->prop_data == 0) ||
1595 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1596 errno = EFAULT;
1597 *prop_data = NULL;
1598 return (-1);
1601 *prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
1602 + DI_PROP(prop)->prop_data);
1604 return (di_prop_decode_common((void *)prop_data,
1605 DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
1609 di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
1611 if (DI_PROP(prop)->prop_len == 0)
1612 return (0); /* boolean property */
1614 if ((DI_PROP(prop)->prop_data == 0) ||
1615 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1616 errno = EFAULT;
1617 *prop_data = NULL;
1618 return (-1);
1621 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
1622 + DI_PROP(prop)->prop_data);
1624 return (di_prop_decode_common((void *)prop_data,
1625 DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
1629 * returns 1 for match, 0 for no match
1631 static int
1632 match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
1634 int prop_type;
1636 #ifdef DEBUG
1637 if (di_prop_name(prop) == NULL) {
1638 DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
1639 return (0);
1641 #endif /* DEBUG */
1643 if (strcmp(name, di_prop_name(prop)) != 0)
1644 return (0);
1646 if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
1647 return (0);
1650 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
1652 prop_type = di_prop_type(prop);
1653 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) &&
1654 (prop_type != DI_PROP_TYPE_BOOLEAN))
1655 return (0);
1657 return (1);
1660 static di_prop_t
1661 di_prop_search(dev_t match_dev, di_node_t node, const char *name,
1662 int type)
1664 di_prop_t prop = DI_PROP_NIL;
1667 * The check on match_dev follows ddi_prop_lookup_common().
1668 * Other checks are libdevinfo specific implementation.
1670 if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
1671 (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) {
1672 errno = EINVAL;
1673 return (DI_PROP_NIL);
1676 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
1677 DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n",
1678 di_prop_name(prop), di_prop_devt(prop),
1679 di_prop_type(prop)));
1680 if (match_prop(prop, match_dev, name, type))
1681 return (prop);
1684 return (DI_PROP_NIL);
1687 di_prop_t
1688 di_prop_find(dev_t match_dev, di_node_t node, const char *name)
1690 di_prop_t prop = DI_PROP_NIL;
1692 if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
1693 (match_dev == DDI_DEV_T_NONE)) {
1694 errno = EINVAL;
1695 return (DI_PROP_NIL);
1698 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
1699 DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n",
1700 di_prop_name(prop), di_prop_devt(prop),
1701 di_prop_type(prop)));
1703 if (strcmp(name, di_prop_name(prop)) == 0 &&
1704 (match_dev == DDI_DEV_T_ANY ||
1705 di_prop_devt(prop) == match_dev))
1706 return (prop);
1709 return (DI_PROP_NIL);
1713 di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
1714 int **prop_data)
1716 di_prop_t prop;
1718 if ((prop = di_prop_search(dev, node, prop_name,
1719 DI_PROP_TYPE_INT)) == DI_PROP_NIL)
1720 return (-1);
1722 return (di_prop_ints(prop, (void *)prop_data));
1726 di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
1727 int64_t **prop_data)
1729 di_prop_t prop;
1731 if ((prop = di_prop_search(dev, node, prop_name,
1732 DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
1733 return (-1);
1735 return (di_prop_int64(prop, (void *)prop_data));
1739 di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
1740 char **prop_data)
1742 di_prop_t prop;
1744 if ((prop = di_prop_search(dev, node, prop_name,
1745 DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
1746 return (-1);
1748 return (di_prop_strings(prop, (void *)prop_data));
1752 di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
1753 uchar_t **prop_data)
1755 di_prop_t prop;
1757 if ((prop = di_prop_search(dev, node, prop_name,
1758 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
1759 return (-1);
1761 return (di_prop_bytes(prop, (void *)prop_data));
1765 * Consolidation private property access functions
1767 enum prop_type {
1768 PROP_TYPE_DRV,
1769 PROP_TYPE_SYS,
1770 PROP_TYPE_GLOB,
1771 PROP_TYPE_HW
1774 static di_prop_t
1775 di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
1777 caddr_t pa;
1778 di_off_t prop_off = 0;
1780 if (prop != DI_PROP_NIL) {
1781 if (DI_PROP(prop)->next) {
1782 return (DI_PROP((caddr_t)prop -
1783 DI_PROP(prop)->self + DI_PROP(prop)->next));
1784 } else {
1785 return (DI_PROP_NIL);
1791 * prop is NIL, caller asks for first property
1793 pa = (caddr_t)node - DI_NODE(node)->self;
1794 switch (prop_type) {
1795 case PROP_TYPE_DRV:
1796 prop_off = DI_NODE(node)->drv_prop;
1797 break;
1798 case PROP_TYPE_SYS:
1799 prop_off = DI_NODE(node)->sys_prop;
1800 break;
1801 case PROP_TYPE_HW:
1802 prop_off = DI_NODE(node)->hw_prop;
1803 break;
1804 case PROP_TYPE_GLOB:
1805 prop_off = DI_NODE(node)->glob_prop;
1806 if (prop_off == -1) {
1807 /* no global property */
1808 prop_off = 0;
1809 } else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) {
1810 /* refer to devnames array */
1811 struct di_devnm *devnm = DI_DEVNM(pa +
1812 DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major *
1813 sizeof (struct di_devnm)));
1814 prop_off = devnm->global_prop;
1816 break;
1819 if (prop_off) {
1820 return (DI_PROP(pa + prop_off));
1824 * no prop found. Check the reason for not found
1826 if (DINFOPROP & DI_ALL(pa)->command)
1827 errno = ENXIO;
1828 else
1829 errno = ENOTSUP;
1831 return (DI_PROP_NIL);
1834 di_prop_t
1835 di_prop_drv_next(di_node_t node, di_prop_t prop)
1837 return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
1840 di_prop_t
1841 di_prop_sys_next(di_node_t node, di_prop_t prop)
1843 return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
1846 di_prop_t
1847 di_prop_global_next(di_node_t node, di_prop_t prop)
1849 return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
1852 di_prop_t
1853 di_prop_hw_next(di_node_t node, di_prop_t prop)
1855 return (di_prop_next_common(node, prop, PROP_TYPE_HW));
1859 di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
1861 #ifdef DEBUG
1862 if (prop == DI_PROP_NIL) {
1863 errno = EINVAL;
1864 return (-1);
1866 #endif /* DEBUG */
1868 if (DI_PROP(prop)->prop_len == 0) {
1869 *prop_data = NULL;
1870 return (0);
1873 if ((DI_PROP(prop)->prop_data == 0) ||
1874 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1875 errno = EFAULT;
1876 *prop_data = NULL;
1877 return (-1);
1881 * No memory allocation.
1883 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
1884 DI_PROP(prop)->prop_data);
1886 return (DI_PROP(prop)->prop_len);
1890 * Consolidation private interfaces for accessing I/O multipathing data
1892 di_path_t
1893 di_path_phci_next_path(di_node_t node, di_path_t path)
1895 caddr_t pa;
1898 * path is not NIL
1900 if (path != DI_PATH_NIL) {
1901 if (DI_PATH(path)->path_p_link != 0)
1902 return (DI_PATH((void *)((caddr_t)path -
1903 DI_PATH(path)->self + DI_PATH(path)->path_p_link)));
1904 else {
1905 errno = ENXIO;
1906 return (DI_PATH_NIL);
1911 * Path is NIL; the caller is asking for the first path info node
1913 if (DI_NODE(node)->multipath_phci != 0) {
1914 DPRINTF((DI_INFO, "phci_next_path: returning %p\n",
1915 ((caddr_t)node -
1916 DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
1917 return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
1918 DI_NODE(node)->multipath_phci));
1922 * No pathing data; check if the snapshot includes path data in order
1923 * to set errno properly.
1925 pa = (caddr_t)node - DI_NODE(node)->self;
1926 if (DINFOPATH & (DI_ALL(pa)->command))
1927 errno = ENXIO;
1928 else
1929 errno = ENOTSUP;
1931 return (DI_PATH_NIL);
1934 di_path_t
1935 di_path_client_next_path(di_node_t node, di_path_t path)
1937 caddr_t pa;
1940 * path is not NIL
1942 if (path != DI_PATH_NIL) {
1943 if (DI_PATH(path)->path_c_link != 0)
1944 return (DI_PATH((caddr_t)path - DI_PATH(path)->self
1945 + DI_PATH(path)->path_c_link));
1946 else {
1947 errno = ENXIO;
1948 return (DI_PATH_NIL);
1953 * Path is NIL; the caller is asking for the first path info node
1955 if (DI_NODE(node)->multipath_client != 0) {
1956 DPRINTF((DI_INFO, "client_next_path: returning %p\n",
1957 ((caddr_t)node -
1958 DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
1959 return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
1960 DI_NODE(node)->multipath_client));
1964 * No pathing data; check if the snapshot includes path data in order
1965 * to set errno properly.
1967 pa = (caddr_t)node - DI_NODE(node)->self;
1968 if (DINFOPATH & (DI_ALL(pa)->command))
1969 errno = ENXIO;
1970 else
1971 errno = ENOTSUP;
1973 return (DI_PATH_NIL);
1977 * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
1978 * below after NWS consolidation switches to using di_path_bus_addr,
1979 * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
1981 char *
1982 di_path_addr(di_path_t path, char *buf)
1984 caddr_t pa; /* starting address of map */
1986 pa = (caddr_t)path - DI_PATH(path)->self;
1988 (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
1989 MAXPATHLEN);
1990 return (buf);
1992 di_path_t
1993 di_path_next(di_node_t node, di_path_t path)
1995 if (node == DI_NODE_NIL) {
1996 errno = EINVAL;
1997 return (DI_PATH_NIL);
2000 if (DI_NODE(node)->multipath_client) {
2001 return (di_path_client_next_path(node, path));
2002 } else if (DI_NODE(node)->multipath_phci) {
2003 return (di_path_phci_next_path(node, path));
2004 } else {
2006 * The node had multipathing data but didn't appear to be a
2007 * phci *or* a client; probably a programmer error.
2009 errno = EINVAL;
2010 return (DI_PATH_NIL);
2013 di_path_t
2014 di_path_next_phci(di_node_t node, di_path_t path)
2016 return (di_path_client_next_path(node, path));
2018 di_path_t
2019 di_path_next_client(di_node_t node, di_path_t path)
2021 return (di_path_phci_next_path(node, path));
2027 di_path_state_t
2028 di_path_state(di_path_t path)
2030 return ((di_path_state_t)DI_PATH(path)->path_state);
2033 uint_t
2034 di_path_flags(di_path_t path)
2036 return (DI_PATH(path)->path_flags);
2039 char *
2040 di_path_node_name(di_path_t path)
2042 di_node_t client_node;
2044 /* pathinfo gets node_name from client */
2045 if ((client_node = di_path_client_node(path)) == NULL)
2046 return (NULL);
2047 return (di_node_name(client_node));
2050 char *
2051 di_path_bus_addr(di_path_t path)
2053 caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
2055 if (DI_PATH(path)->path_addr == 0)
2056 return (NULL);
2058 return ((char *)(pa + DI_PATH(path)->path_addr));
2062 di_path_instance(di_path_t path)
2064 return (DI_PATH(path)->path_instance);
2067 di_node_t
2068 di_path_client_node(di_path_t path)
2070 caddr_t pa; /* starting address of map */
2072 if (path == DI_PATH_NIL) {
2073 errno = EINVAL;
2074 return (DI_PATH_NIL);
2077 DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
2079 pa = (caddr_t)path - DI_PATH(path)->self;
2081 if (DI_PATH(path)->path_client) {
2082 return (DI_NODE(pa + DI_PATH(path)->path_client));
2086 * Deal with error condition:
2087 * If parent doesn't exist and node is not the root,
2088 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2090 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
2091 errno = ENOTSUP;
2092 else
2093 errno = ENXIO;
2095 return (DI_NODE_NIL);
2098 di_node_t
2099 di_path_phci_node(di_path_t path)
2101 caddr_t pa; /* starting address of map */
2103 if (path == DI_PATH_NIL) {
2104 errno = EINVAL;
2105 return (DI_PATH_NIL);
2108 DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
2110 pa = (caddr_t)path - DI_PATH(path)->self;
2112 if (DI_PATH(path)->path_phci) {
2113 return (DI_NODE(pa + DI_PATH(path)->path_phci));
2117 * Deal with error condition:
2118 * If parent doesn't exist and node is not the root,
2119 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2121 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
2122 errno = ENOTSUP;
2123 else
2124 errno = ENXIO;
2126 return (DI_NODE_NIL);
2129 di_path_prop_t
2130 di_path_prop_next(di_path_t path, di_path_prop_t prop)
2132 caddr_t pa;
2134 if (path == DI_PATH_NIL) {
2135 errno = EINVAL;
2136 return (DI_PROP_NIL);
2140 * prop is not NIL
2142 if (prop != DI_PROP_NIL) {
2143 if (DI_PROP(prop)->next != 0)
2144 return (DI_PATHPROP((caddr_t)prop -
2145 DI_PROP(prop)->self + DI_PROP(prop)->next));
2146 else {
2147 errno = ENXIO;
2148 return (DI_PROP_NIL);
2153 * prop is NIL-->caller asks for first property
2155 pa = (caddr_t)path - DI_PATH(path)->self;
2156 if (DI_PATH(path)->path_prop != 0) {
2157 return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
2161 * no property data-->check if snapshot includes props
2162 * in order to set the correct errno
2164 if (DINFOPROP & (DI_ALL(pa)->command))
2165 errno = ENXIO;
2166 else
2167 errno = ENOTSUP;
2169 return (DI_PROP_NIL);
2172 char *
2173 di_path_prop_name(di_path_prop_t prop)
2175 caddr_t pa; /* starting address of map */
2176 pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
2177 return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
2181 di_path_prop_len(di_path_prop_t prop)
2183 return (DI_PATHPROP(prop)->prop_len);
2187 di_path_prop_type(di_path_prop_t prop)
2189 switch (DI_PATHPROP(prop)->prop_type) {
2190 case DDI_PROP_TYPE_INT:
2191 return (DI_PROP_TYPE_INT);
2192 case DDI_PROP_TYPE_INT64:
2193 return (DI_PROP_TYPE_INT64);
2194 case DDI_PROP_TYPE_BYTE:
2195 return (DI_PROP_TYPE_BYTE);
2196 case DDI_PROP_TYPE_STRING:
2197 return (DI_PROP_TYPE_STRING);
2199 return (DI_PROP_TYPE_UNKNOWN);
2203 di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
2205 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2206 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2207 errno = EFAULT;
2208 *prop_data = NULL;
2209 return (-1);
2212 *prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
2213 + DI_PATHPROP(prop)->prop_data);
2215 return (di_prop_decode_common((void *)prop_data,
2216 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
2220 di_path_prop_ints(di_path_prop_t prop, int **prop_data)
2222 if (DI_PATHPROP(prop)->prop_len == 0)
2223 return (0);
2225 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2226 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2227 errno = EFAULT;
2228 *prop_data = NULL;
2229 return (-1);
2232 *prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
2233 + DI_PATHPROP(prop)->prop_data));
2235 return (di_prop_decode_common((void *)prop_data,
2236 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
2240 di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
2242 if (DI_PATHPROP(prop)->prop_len == 0)
2243 return (0);
2245 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2246 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2247 errno = EFAULT;
2248 *prop_data = NULL;
2249 return (-1);
2252 *prop_data = (int64_t *)((void *)((caddr_t)prop -
2253 DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
2255 return (di_prop_decode_common((void *)prop_data,
2256 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
2260 di_path_prop_strings(di_path_prop_t prop, char **prop_data)
2262 if (DI_PATHPROP(prop)->prop_len == 0)
2263 return (0);
2265 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2266 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2267 errno = EFAULT;
2268 *prop_data = NULL;
2269 return (-1);
2272 *prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
2273 + DI_PATHPROP(prop)->prop_data);
2275 return (di_prop_decode_common((void *)prop_data,
2276 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
2279 static di_path_prop_t
2280 di_path_prop_search(di_path_t path, const char *name, int type)
2282 di_path_prop_t prop = DI_PROP_NIL;
2285 * Sanity check arguments
2287 if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
2288 !DI_PROP_TYPE_VALID(type)) {
2289 errno = EINVAL;
2290 return (DI_PROP_NIL);
2293 while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
2294 int prop_type = di_path_prop_type(prop);
2296 DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
2297 di_path_prop_name(prop), prop_type));
2299 if (strcmp(name, di_path_prop_name(prop)) != 0)
2300 continue;
2302 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
2303 continue;
2305 return (prop);
2308 return (DI_PROP_NIL);
2312 di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
2313 uchar_t **prop_data)
2315 di_path_prop_t prop;
2317 if ((prop = di_path_prop_search(path, prop_name,
2318 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
2319 return (-1);
2321 return (di_path_prop_bytes(prop, prop_data));
2325 di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
2326 int **prop_data)
2328 di_path_prop_t prop;
2330 if ((prop = di_path_prop_search(path, prop_name,
2331 DI_PROP_TYPE_INT)) == DI_PROP_NIL)
2332 return (-1);
2334 return (di_path_prop_ints(prop, prop_data));
2338 di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
2339 int64_t **prop_data)
2341 di_path_prop_t prop;
2343 if ((prop = di_path_prop_search(path, prop_name,
2344 DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
2345 return (-1);
2347 return (di_path_prop_int64s(prop, prop_data));
2350 int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
2351 char **prop_data)
2353 di_path_prop_t prop;
2355 if ((prop = di_path_prop_search(path, prop_name,
2356 DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
2357 return (-1);
2359 return (di_path_prop_strings(prop, prop_data));
2363 * Consolidation private interfaces for traversing vhci nodes.
2365 di_node_t
2366 di_vhci_first_node(di_node_t root)
2368 struct di_all *dap;
2369 caddr_t pa; /* starting address of map */
2371 DPRINTF((DI_INFO, "Get first vhci node\n"));
2373 if (root == DI_NODE_NIL) {
2374 errno = EINVAL;
2375 return (DI_NODE_NIL);
2378 pa = (caddr_t)root - DI_NODE(root)->self;
2379 dap = DI_ALL(pa);
2381 if (dap->top_vhci_devinfo == 0) {
2382 errno = ENXIO;
2383 return (DI_NODE_NIL);
2386 return (DI_NODE(pa + dap->top_vhci_devinfo));
2389 di_node_t
2390 di_vhci_next_node(di_node_t node)
2392 caddr_t pa; /* starting address of map */
2394 if (node == DI_NODE_NIL) {
2395 errno = EINVAL;
2396 return (DI_NODE_NIL);
2399 DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
2400 " current=%s\n", di_node_name(node)));
2402 if (DI_NODE(node)->next_vhci == 0) {
2403 errno = ENXIO;
2404 return (DI_NODE_NIL);
2407 pa = (caddr_t)node - DI_NODE(node)->self;
2409 return (DI_NODE(pa + DI_NODE(node)->next_vhci));
2413 * Consolidation private interfaces for traversing phci nodes.
2415 di_node_t
2416 di_phci_first_node(di_node_t vhci_node)
2418 caddr_t pa; /* starting address of map */
2420 DPRINTF((DI_INFO, "Get first phci node:\n"
2421 " current=%s", di_node_name(vhci_node)));
2423 if (vhci_node == DI_NODE_NIL) {
2424 errno = EINVAL;
2425 return (DI_NODE_NIL);
2428 pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
2430 if (DI_NODE(vhci_node)->top_phci == 0) {
2431 errno = ENXIO;
2432 return (DI_NODE_NIL);
2435 return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
2438 di_node_t
2439 di_phci_next_node(di_node_t node)
2441 caddr_t pa; /* starting address of map */
2443 if (node == DI_NODE_NIL) {
2444 errno = EINVAL;
2445 return (DI_NODE_NIL);
2448 DPRINTF((DI_TRACE, "next phci node on the snap shot:"
2449 " current=%s\n", di_node_name(node)));
2451 if (DI_NODE(node)->next_phci == 0) {
2452 errno = ENXIO;
2453 return (DI_NODE_NIL);
2456 pa = (caddr_t)node - DI_NODE(node)->self;
2458 return (DI_NODE(pa + DI_NODE(node)->next_phci));
2462 * Consolidation private interfaces for private data
2464 void *
2465 di_parent_private_data(di_node_t node)
2467 caddr_t pa;
2469 if (DI_NODE(node)->parent_data == 0) {
2470 errno = ENXIO;
2471 return (NULL);
2474 if (DI_NODE(node)->parent_data == (di_off_t)-1) {
2476 * Private data requested, but not obtained due to a memory
2477 * error (e.g. wrong format specified)
2479 errno = EFAULT;
2480 return (NULL);
2483 pa = (caddr_t)node - DI_NODE(node)->self;
2484 if (DI_NODE(node)->parent_data)
2485 return (pa + DI_NODE(node)->parent_data);
2487 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2488 errno = ENXIO;
2489 else
2490 errno = ENOTSUP;
2492 return (NULL);
2495 void *
2496 di_driver_private_data(di_node_t node)
2498 caddr_t pa;
2500 if (DI_NODE(node)->driver_data == 0) {
2501 errno = ENXIO;
2502 return (NULL);
2505 if (DI_NODE(node)->driver_data == (di_off_t)-1) {
2507 * Private data requested, but not obtained due to a memory
2508 * error (e.g. wrong format specified)
2510 errno = EFAULT;
2511 return (NULL);
2514 pa = (caddr_t)node - DI_NODE(node)->self;
2515 if (DI_NODE(node)->driver_data)
2516 return (pa + DI_NODE(node)->driver_data);
2518 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2519 errno = ENXIO;
2520 else
2521 errno = ENOTSUP;
2523 return (NULL);
2527 * Hotplug information access
2530 typedef struct {
2531 void *arg;
2532 const char *type;
2533 uint_t flag;
2534 int (*hp_callback)(di_node_t, di_hp_t, void *);
2535 } di_walk_hp_arg_t;
2537 static int
2538 di_walk_hp_callback(di_node_t node, void *argp)
2540 di_walk_hp_arg_t *arg = (di_walk_hp_arg_t *)argp;
2541 di_hp_t hp;
2542 char *type_str;
2544 for (hp = DI_HP_NIL; (hp = di_hp_next(node, hp)) != DI_HP_NIL; ) {
2546 /* Exclude non-matching types if a type filter is specified */
2547 if (arg->type != NULL) {
2548 type_str = di_hp_description(hp);
2549 if (type_str && (strcmp(arg->type, type_str) != 0))
2550 continue;
2553 /* Exclude ports if DI_HP_PORT flag not specified */
2554 if (!(arg->flag & DI_HP_PORT) &&
2555 (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2556 continue;
2558 /* Exclude connectors if DI_HP_CONNECTOR flag not specified */
2559 if (!(arg->flag & DI_HP_CONNECTOR) &&
2560 !(di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2561 continue;
2563 /* Perform callback */
2564 if (arg->hp_callback(node, hp, arg->arg) != DI_WALK_CONTINUE)
2565 return (DI_WALK_TERMINATE);
2568 return (DI_WALK_CONTINUE);
2572 di_walk_hp(di_node_t node, const char *type, uint_t flag, void *arg,
2573 int (*hp_callback)(di_node_t node, di_hp_t hp, void *arg))
2575 di_walk_hp_arg_t walk_arg;
2576 caddr_t pa;
2578 #ifdef DEBUG
2579 char *devfspath = di_devfs_path(node);
2580 DPRINTF((DI_INFO, "walking hotplug nodes under %s\n", devfspath));
2581 di_devfs_path_free(devfspath);
2582 #endif
2584 * paranoid error checking
2586 if ((node == DI_NODE_NIL) || (hp_callback == NULL)) {
2587 errno = EINVAL;
2588 return (-1);
2591 /* check if hotplug data is included in snapshot */
2592 pa = (caddr_t)node - DI_NODE(node)->self;
2593 if (!(DI_ALL(pa)->command & DINFOHP)) {
2594 errno = ENOTSUP;
2595 return (-1);
2598 walk_arg.arg = arg;
2599 walk_arg.type = type;
2600 walk_arg.flag = flag;
2601 walk_arg.hp_callback = hp_callback;
2602 return (di_walk_node(node, DI_WALK_CLDFIRST, &walk_arg,
2603 di_walk_hp_callback));
2606 di_hp_t
2607 di_hp_next(di_node_t node, di_hp_t hp)
2609 caddr_t pa;
2612 * paranoid error checking
2614 if (node == DI_NODE_NIL) {
2615 errno = EINVAL;
2616 return (DI_HP_NIL);
2620 * hotplug node is not NIL
2622 if (hp != DI_HP_NIL) {
2623 if (DI_HP(hp)->next != 0)
2624 return (DI_HP((caddr_t)hp - hp->self + hp->next));
2625 else {
2626 errno = ENXIO;
2627 return (DI_HP_NIL);
2632 * hotplug node is NIL-->caller asks for first hotplug node
2634 if (DI_NODE(node)->hp_data != 0) {
2635 return (DI_HP((caddr_t)node - DI_NODE(node)->self +
2636 DI_NODE(node)->hp_data));
2640 * no hotplug data-->check if snapshot includes hotplug data
2641 * in order to set the correct errno
2643 pa = (caddr_t)node - DI_NODE(node)->self;
2644 if (DINFOHP & DI_ALL(pa)->command)
2645 errno = ENXIO;
2646 else
2647 errno = ENOTSUP;
2649 return (DI_HP_NIL);
2652 char *
2653 di_hp_name(di_hp_t hp)
2655 caddr_t pa;
2658 * paranoid error checking
2660 if (hp == DI_HP_NIL) {
2661 errno = EINVAL;
2662 return (NULL);
2665 pa = (caddr_t)hp - DI_HP(hp)->self;
2667 if (DI_HP(hp)->hp_name == 0) {
2668 errno = ENXIO;
2669 return (NULL);
2672 return ((char *)(pa + DI_HP(hp)->hp_name));
2676 di_hp_connection(di_hp_t hp)
2679 * paranoid error checking
2681 if (hp == DI_HP_NIL) {
2682 errno = EINVAL;
2683 return (-1);
2686 if (DI_HP(hp)->hp_connection == -1)
2687 errno = ENOENT;
2689 return (DI_HP(hp)->hp_connection);
2693 di_hp_depends_on(di_hp_t hp)
2696 * paranoid error checking
2698 if (hp == DI_HP_NIL) {
2699 errno = EINVAL;
2700 return (-1);
2703 if (DI_HP(hp)->hp_depends_on == -1)
2704 errno = ENOENT;
2706 return (DI_HP(hp)->hp_depends_on);
2710 di_hp_state(di_hp_t hp)
2713 * paranoid error checking
2715 if (hp == DI_HP_NIL) {
2716 errno = EINVAL;
2717 return (-1);
2720 return (DI_HP(hp)->hp_state);
2724 di_hp_type(di_hp_t hp)
2727 * paranoid error checking
2729 if (hp == DI_HP_NIL) {
2730 errno = EINVAL;
2731 return (-1);
2734 return (DI_HP(hp)->hp_type);
2737 char *
2738 di_hp_description(di_hp_t hp)
2740 caddr_t pa;
2743 * paranoid error checking
2745 if (hp == DI_HP_NIL) {
2746 errno = EINVAL;
2747 return (NULL);
2750 pa = (caddr_t)hp - DI_HP(hp)->self;
2752 if (DI_HP(hp)->hp_type_str == 0)
2753 return (NULL);
2755 return ((char *)(pa + DI_HP(hp)->hp_type_str));
2758 di_node_t
2759 di_hp_child(di_hp_t hp)
2761 caddr_t pa; /* starting address of map */
2764 * paranoid error checking
2766 if (hp == DI_HP_NIL) {
2767 errno = EINVAL;
2768 return (DI_NODE_NIL);
2771 pa = (caddr_t)hp - DI_HP(hp)->self;
2773 if (DI_HP(hp)->hp_child > 0) {
2774 return (DI_NODE(pa + DI_HP(hp)->hp_child));
2778 * Deal with error condition:
2779 * Child doesn't exist, figure out if DINFOSUBTREE is set.
2780 * If it isn't, set errno to ENOTSUP.
2782 if (!(DINFOSUBTREE & DI_ALL(pa)->command))
2783 errno = ENOTSUP;
2784 else
2785 errno = ENXIO;
2787 return (DI_NODE_NIL);
2790 time_t
2791 di_hp_last_change(di_hp_t hp)
2794 * paranoid error checking
2796 if (hp == DI_HP_NIL) {
2797 errno = EINVAL;
2798 return ((time_t)0);
2801 return ((time_t)DI_HP(hp)->hp_last_change);
2805 * PROM property access
2809 * openprom driver stuff:
2810 * The maximum property length depends on the buffer size. We use
2811 * OPROMMAXPARAM defined in <sys/openpromio.h>
2813 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2814 * MAXVALSZ is maximum value size, which is whatever space left in buf
2817 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int)
2818 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME;
2820 struct di_prom_prop {
2821 char *name;
2822 int len;
2823 uchar_t *data;
2824 struct di_prom_prop *next; /* form a linked list */
2827 struct di_prom_handle { /* handle to prom */
2828 mutex_t lock; /* synchronize access to openprom fd */
2829 int fd; /* /dev/openprom file descriptor */
2830 struct di_prom_prop *list; /* linked list of prop */
2831 union {
2832 char buf[OPROMMAXPARAM];
2833 struct openpromio opp;
2834 } oppbuf;
2837 di_prom_handle_t
2838 di_prom_init()
2840 struct di_prom_handle *p;
2842 if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
2843 return (DI_PROM_HANDLE_NIL);
2845 DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
2847 (void) mutex_init(&p->lock, USYNC_THREAD, NULL);
2848 if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
2849 free(p);
2850 return (DI_PROM_HANDLE_NIL);
2852 p->list = NULL;
2854 return ((di_prom_handle_t)p);
2857 static void
2858 di_prom_prop_free(struct di_prom_prop *list)
2860 struct di_prom_prop *tmp = list;
2862 while (tmp != NULL) {
2863 list = tmp->next;
2864 if (tmp->name != NULL) {
2865 free(tmp->name);
2867 if (tmp->data != NULL) {
2868 free(tmp->data);
2870 free(tmp);
2871 tmp = list;
2875 void
2876 di_prom_fini(di_prom_handle_t ph)
2878 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2880 DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
2882 (void) close(p->fd);
2883 (void) mutex_destroy(&p->lock);
2884 di_prom_prop_free(p->list);
2886 free(p);
2890 * Internal library interface for locating the property
2891 * XXX: ph->lock must be held for the duration of call.
2893 static di_prom_prop_t
2894 di_prom_prop_found(di_prom_handle_t ph, int nodeid,
2895 di_prom_prop_t prom_prop)
2897 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2898 struct openpromio *opp = &p->oppbuf.opp;
2899 int *ip = (int *)((void *)opp->oprom_array);
2900 struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
2902 DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
2905 * Set "current" nodeid in the openprom driver
2907 opp->oprom_size = sizeof (int);
2908 *ip = nodeid;
2909 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
2910 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
2911 return (DI_PROM_PROP_NIL);
2914 DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
2916 bzero(opp, OBP_MAXBUF);
2917 opp->oprom_size = OBP_MAXPROPNAME;
2918 if (prom_prop != DI_PROM_PROP_NIL)
2919 (void) strcpy(opp->oprom_array, prop->name);
2921 if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
2922 return (DI_PROM_PROP_NIL);
2925 * Prom property found. Allocate struct for storing prop
2926 * (reuse variable prop)
2928 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
2929 return (DI_PROM_PROP_NIL);
2932 * Get a copy of property name
2934 if ((prop->name = strdup(opp->oprom_array)) == NULL) {
2935 free(prop);
2936 return (DI_PROM_PROP_NIL);
2940 * get property value and length
2942 opp->oprom_size = OBP_MAXPROPLEN;
2944 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
2945 (opp->oprom_size == (uint_t)-1)) {
2946 free(prop->name);
2947 free(prop);
2948 return (DI_PROM_PROP_NIL);
2952 * make a copy of the property value
2954 prop->len = opp->oprom_size;
2956 if (prop->len == 0)
2957 prop->data = NULL;
2958 else if ((prop->data = malloc(prop->len)) == NULL) {
2959 free(prop->name);
2960 free(prop);
2961 return (DI_PROM_PROP_NIL);
2964 bcopy(opp->oprom_array, prop->data, prop->len);
2967 * Prepend prop to list in prom handle
2969 prop->next = p->list;
2970 p->list = prop;
2972 return ((di_prom_prop_t)prop);
2975 di_prom_prop_t
2976 di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
2978 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2980 DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
2981 node, p));
2984 * paranoid check
2986 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
2987 errno = EINVAL;
2988 return (DI_PROM_PROP_NIL);
2991 if (di_nodeid(node) != DI_PROM_NODEID) {
2992 errno = ENXIO;
2993 return (DI_PROM_PROP_NIL);
2997 * synchronize access to prom file descriptor
2999 (void) mutex_lock(&p->lock);
3002 * look for next property
3004 prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
3006 (void) mutex_unlock(&p->lock);
3008 return (prom_prop);
3011 char *
3012 di_prom_prop_name(di_prom_prop_t prom_prop)
3015 * paranoid check
3017 if (prom_prop == DI_PROM_PROP_NIL) {
3018 errno = EINVAL;
3019 return (NULL);
3022 return (((struct di_prom_prop *)prom_prop)->name);
3026 di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
3029 * paranoid check
3031 if (prom_prop == DI_PROM_PROP_NIL) {
3032 errno = EINVAL;
3033 return (0);
3036 *prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
3038 return (((struct di_prom_prop *)prom_prop)->len);
3042 * Internal library interface for locating the property
3043 * Returns length if found, -1 if prop doesn't exist.
3045 static struct di_prom_prop *
3046 di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
3047 const char *prom_prop_name)
3049 struct openpromio *opp;
3050 struct di_prom_prop *prop;
3051 struct di_prom_handle *p = (struct di_prom_handle *)ph;
3054 * paranoid check
3056 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
3057 errno = EINVAL;
3058 return (NULL);
3061 if (di_nodeid(node) != DI_PROM_NODEID) {
3062 errno = ENXIO;
3063 return (NULL);
3066 opp = &p->oppbuf.opp;
3068 (void) mutex_lock(&p->lock);
3070 opp->oprom_size = sizeof (int);
3071 opp->oprom_node = DI_NODE(node)->nodeid;
3072 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
3073 errno = ENXIO;
3074 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
3075 DI_NODE(node)->nodeid));
3076 (void) mutex_unlock(&p->lock);
3077 return (NULL);
3081 * get property length
3083 bzero(opp, OBP_MAXBUF);
3084 opp->oprom_size = OBP_MAXPROPLEN;
3085 (void) strcpy(opp->oprom_array, prom_prop_name);
3087 if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
3088 (opp->oprom_len == -1)) {
3089 /* no such property */
3090 (void) mutex_unlock(&p->lock);
3091 return (NULL);
3095 * Prom property found. Allocate struct for storing prop
3097 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
3098 (void) mutex_unlock(&p->lock);
3099 return (NULL);
3101 prop->name = NULL; /* we don't need the name */
3102 prop->len = opp->oprom_len;
3104 if (prop->len == 0) { /* boolean property */
3105 prop->data = NULL;
3106 prop->next = p->list;
3107 p->list = prop;
3108 (void) mutex_unlock(&p->lock);
3109 return (prop);
3113 * retrieve the property value
3115 bzero(opp, OBP_MAXBUF);
3116 opp->oprom_size = OBP_MAXPROPLEN;
3117 (void) strcpy(opp->oprom_array, prom_prop_name);
3119 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
3120 (opp->oprom_size == (uint_t)-1)) {
3121 /* error retrieving property value */
3122 (void) mutex_unlock(&p->lock);
3123 free(prop);
3124 return (NULL);
3128 * make a copy of the property value, stick in ph->list
3130 if ((prop->data = malloc(prop->len)) == NULL) {
3131 (void) mutex_unlock(&p->lock);
3132 free(prop);
3133 return (NULL);
3136 bcopy(opp->oprom_array, prop->data, prop->len);
3138 prop->next = p->list;
3139 p->list = prop;
3140 (void) mutex_unlock(&p->lock);
3142 return (prop);
3146 di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
3147 const char *prom_prop_name, int **prom_prop_data)
3149 int len;
3150 struct di_prom_prop *prop;
3152 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3154 if (prop == NULL) {
3155 *prom_prop_data = NULL;
3156 return (-1);
3159 if (prop->len == 0) { /* boolean property */
3160 *prom_prop_data = NULL;
3161 return (0);
3164 len = di_prop_decode_common((void *)&prop->data, prop->len,
3165 DI_PROP_TYPE_INT, 1);
3166 *prom_prop_data = (int *)((void *)prop->data);
3168 return (len);
3172 di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
3173 const char *prom_prop_name, char **prom_prop_data)
3175 int len;
3176 struct di_prom_prop *prop;
3178 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3180 if (prop == NULL) {
3181 *prom_prop_data = NULL;
3182 return (-1);
3185 if (prop->len == 0) { /* boolean property */
3186 *prom_prop_data = NULL;
3187 return (0);
3191 * Fix an openprom bug (OBP string not NULL terminated).
3192 * XXX This should really be fixed in promif.
3194 if (((char *)prop->data)[prop->len - 1] != '\0') {
3195 uchar_t *tmp;
3196 prop->len++;
3197 if ((tmp = realloc(prop->data, prop->len)) == NULL)
3198 return (-1);
3200 prop->data = tmp;
3201 ((char *)prop->data)[prop->len - 1] = '\0';
3202 DPRINTF((DI_INFO, "OBP string not NULL terminated: "
3203 "node=%s, prop=%s, val=%s\n",
3204 di_node_name(node), prom_prop_name, prop->data));
3207 len = di_prop_decode_common((void *)&prop->data, prop->len,
3208 DI_PROP_TYPE_STRING, 1);
3209 *prom_prop_data = (char *)prop->data;
3211 return (len);
3215 di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
3216 const char *prom_prop_name, uchar_t **prom_prop_data)
3218 int len;
3219 struct di_prom_prop *prop;
3221 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3223 if (prop == NULL) {
3224 *prom_prop_data = NULL;
3225 return (-1);
3228 if (prop->len == 0) { /* boolean property */
3229 *prom_prop_data = NULL;
3230 return (0);
3233 len = di_prop_decode_common((void *)&prop->data, prop->len,
3234 DI_PROP_TYPE_BYTE, 1);
3235 *prom_prop_data = prop->data;
3237 return (len);
3241 * returns an allocated array through <prop_data> only when its count > 0
3242 * and the number of entries (count) as the function return value;
3243 * use di_slot_names_free() to free the array
3246 di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
3248 int rawlen, count;
3249 uchar_t *rawdata;
3250 char *nm = di_prop_name(prop);
3252 if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
3253 goto ERROUT;
3255 rawlen = di_prop_rawdata(prop, &rawdata);
3256 if (rawlen <= 0 || rawdata == NULL)
3257 goto ERROUT;
3259 count = di_slot_names_decode(rawdata, rawlen, prop_data);
3260 if (count < 0 || *prop_data == NULL)
3261 goto ERROUT;
3263 return (count);
3264 /*NOTREACHED*/
3265 ERROUT:
3266 errno = EFAULT;
3267 *prop_data = NULL;
3268 return (-1);
3272 di_prop_lookup_slot_names(dev_t dev, di_node_t node,
3273 di_slot_name_t **prop_data)
3275 di_prop_t prop;
3278 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
3279 * and slot-names is properly flagged as such
3281 if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
3282 DI_PROP_NIL) {
3283 *prop_data = NULL;
3284 return (-1);
3287 return (di_prop_slot_names(prop, (void *)prop_data));
3291 * returns an allocated array through <prop_data> only when its count > 0
3292 * and the number of entries (count) as the function return value;
3293 * use di_slot_names_free() to free the array
3296 di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
3298 int rawlen, count;
3299 uchar_t *rawdata;
3301 rawlen = di_prom_prop_data(prom_prop, &rawdata);
3302 if (rawlen <= 0 || rawdata == NULL)
3303 goto ERROUT;
3305 count = di_slot_names_decode(rawdata, rawlen, prop_data);
3306 if (count < 0 || *prop_data == NULL)
3307 goto ERROUT;
3309 return (count);
3310 /*NOTREACHED*/
3311 ERROUT:
3312 errno = EFAULT;
3313 *prop_data = NULL;
3314 return (-1);
3318 di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
3319 di_slot_name_t **prop_data)
3321 struct di_prom_prop *prom_prop;
3323 prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
3324 if (prom_prop == NULL) {
3325 *prop_data = NULL;
3326 return (-1);
3329 return (di_prom_prop_slot_names(prom_prop, prop_data));
3332 di_lnode_t
3333 di_link_to_lnode(di_link_t link, uint_t endpoint)
3335 struct di_all *di_all;
3337 if ((link == DI_LINK_NIL) ||
3338 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3339 errno = EINVAL;
3340 return (DI_LNODE_NIL);
3343 di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
3345 if (endpoint == DI_LINK_SRC) {
3346 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
3347 } else {
3348 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
3350 /* NOTREACHED */
3353 char *
3354 di_lnode_name(di_lnode_t lnode)
3356 return (di_driver_name(di_lnode_devinfo(lnode)));
3359 di_node_t
3360 di_lnode_devinfo(di_lnode_t lnode)
3362 struct di_all *di_all;
3364 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3365 return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
3369 di_lnode_devt(di_lnode_t lnode, dev_t *devt)
3371 if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
3372 errno = EINVAL;
3373 return (-1);
3375 if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
3376 (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
3377 return (-1);
3379 *devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
3380 return (0);
3384 di_link_spectype(di_link_t link)
3386 return (DI_LINK(link)->spec_type);
3389 void
3390 di_minor_private_set(di_minor_t minor, void *data)
3392 DI_MINOR(minor)->user_private_data = (uintptr_t)data;
3395 void *
3396 di_minor_private_get(di_minor_t minor)
3398 return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
3401 void
3402 di_node_private_set(di_node_t node, void *data)
3404 DI_NODE(node)->user_private_data = (uintptr_t)data;
3407 void *
3408 di_node_private_get(di_node_t node)
3410 return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
3413 void
3414 di_path_private_set(di_path_t path, void *data)
3416 DI_PATH(path)->user_private_data = (uintptr_t)data;
3419 void *
3420 di_path_private_get(di_path_t path)
3422 return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
3425 void
3426 di_lnode_private_set(di_lnode_t lnode, void *data)
3428 DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
3431 void *
3432 di_lnode_private_get(di_lnode_t lnode)
3434 return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
3437 void
3438 di_link_private_set(di_link_t link, void *data)
3440 DI_LINK(link)->user_private_data = (uintptr_t)data;
3443 void *
3444 di_link_private_get(di_link_t link)
3446 return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
3449 di_lnode_t
3450 di_lnode_next(di_node_t node, di_lnode_t lnode)
3452 struct di_all *di_all;
3455 * paranoid error checking
3457 if (node == DI_NODE_NIL) {
3458 errno = EINVAL;
3459 return (DI_LNODE_NIL);
3462 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3464 if (lnode == DI_NODE_NIL) {
3465 if (DI_NODE(node)->lnodes != 0)
3466 return (DI_LNODE((caddr_t)di_all +
3467 DI_NODE(node)->lnodes));
3468 } else {
3469 if (DI_LNODE(lnode)->node_next != 0)
3470 return (DI_LNODE((caddr_t)di_all +
3471 DI_LNODE(lnode)->node_next));
3474 if (DINFOLYR & DI_ALL(di_all)->command)
3475 errno = ENXIO;
3476 else
3477 errno = ENOTSUP;
3479 return (DI_LNODE_NIL);
3482 di_link_t
3483 di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
3485 struct di_all *di_all;
3488 * paranoid error checking
3490 if ((node == DI_NODE_NIL) ||
3491 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3492 errno = EINVAL;
3493 return (DI_LINK_NIL);
3496 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3498 if (endpoint == DI_LINK_SRC) {
3499 if (link == DI_LINK_NIL) {
3500 if (DI_NODE(node)->src_links != 0)
3501 return (DI_LINK((caddr_t)di_all +
3502 DI_NODE(node)->src_links));
3503 } else {
3504 if (DI_LINK(link)->src_node_next != 0)
3505 return (DI_LINK((caddr_t)di_all +
3506 DI_LINK(link)->src_node_next));
3508 } else {
3509 if (link == DI_LINK_NIL) {
3510 if (DI_NODE(node)->tgt_links != 0)
3511 return (DI_LINK((caddr_t)di_all +
3512 DI_NODE(node)->tgt_links));
3513 } else {
3514 if (DI_LINK(link)->tgt_node_next != 0)
3515 return (DI_LINK((caddr_t)di_all +
3516 DI_LINK(link)->tgt_node_next));
3520 if (DINFOLYR & DI_ALL(di_all)->command)
3521 errno = ENXIO;
3522 else
3523 errno = ENOTSUP;
3525 return (DI_LINK_NIL);
3528 di_link_t
3529 di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
3531 struct di_all *di_all;
3534 * paranoid error checking
3536 if ((lnode == DI_LNODE_NIL) ||
3537 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3538 errno = EINVAL;
3539 return (DI_LINK_NIL);
3542 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3544 if (endpoint == DI_LINK_SRC) {
3545 if (link == DI_LINK_NIL) {
3546 if (DI_LNODE(lnode)->link_out == 0)
3547 return (DI_LINK_NIL);
3548 return (DI_LINK((caddr_t)di_all +
3549 DI_LNODE(lnode)->link_out));
3550 } else {
3551 if (DI_LINK(link)->src_link_next == 0)
3552 return (DI_LINK_NIL);
3553 return (DI_LINK((caddr_t)di_all +
3554 DI_LINK(link)->src_link_next));
3556 } else {
3557 if (link == DI_LINK_NIL) {
3558 if (DI_LNODE(lnode)->link_in == 0)
3559 return (DI_LINK_NIL);
3560 return (DI_LINK((caddr_t)di_all +
3561 DI_LNODE(lnode)->link_in));
3562 } else {
3563 if (DI_LINK(link)->tgt_link_next == 0)
3564 return (DI_LINK_NIL);
3565 return (DI_LINK((caddr_t)di_all +
3566 DI_LINK(link)->tgt_link_next));
3569 /* NOTREACHED */
3573 * Internal library function:
3574 * Invoke callback for each link data on the link list of first node
3575 * on node_list headp, and place children of first node on the list.
3577 * This is similar to walk_one_node, except we only walk in child
3578 * first mode.
3580 static void
3581 walk_one_link(struct node_list **headp, uint_t ep,
3582 void *arg, int (*callback)(di_link_t link, void *arg))
3584 int action = DI_WALK_CONTINUE;
3585 di_link_t link = DI_LINK_NIL;
3586 di_node_t node = (*headp)->node;
3588 while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
3589 action = callback(link, arg);
3590 if (action == DI_WALK_TERMINATE) {
3591 break;
3595 update_node_list(action, DI_WALK_LINKGEN, headp);
3599 di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
3600 int (*link_callback)(di_link_t link, void *arg))
3602 struct node_list *head; /* node_list for tree walk */
3604 #ifdef DEBUG
3605 char *devfspath = di_devfs_path(root);
3606 DPRINTF((DI_INFO, "walking %s link data under %s\n",
3607 (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
3608 di_devfs_path_free(devfspath);
3609 #endif
3612 * paranoid error checking
3614 if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
3615 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3616 errno = EINVAL;
3617 return (-1);
3620 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3621 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3622 return (-1);
3625 head->next = NULL;
3626 head->node = root;
3628 DPRINTF((DI_INFO, "Start link data walking from node %s\n",
3629 di_node_name(root)));
3631 while (head != NULL)
3632 walk_one_link(&head, endpoint, arg, link_callback);
3634 return (0);
3638 * Internal library function:
3639 * Invoke callback for each link data on the link list of first node
3640 * on node_list headp, and place children of first node on the list.
3642 * This is similar to walk_one_node, except we only walk in child
3643 * first mode.
3645 static void
3646 walk_one_lnode(struct node_list **headp, void *arg,
3647 int (*callback)(di_lnode_t lnode, void *arg))
3649 int action = DI_WALK_CONTINUE;
3650 di_lnode_t lnode = DI_LNODE_NIL;
3651 di_node_t node = (*headp)->node;
3653 while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
3654 action = callback(lnode, arg);
3655 if (action == DI_WALK_TERMINATE) {
3656 break;
3660 update_node_list(action, DI_WALK_LINKGEN, headp);
3664 di_walk_lnode(di_node_t root, uint_t flag, void *arg,
3665 int (*lnode_callback)(di_lnode_t lnode, void *arg))
3667 struct node_list *head; /* node_list for tree walk */
3669 #ifdef DEBUG
3670 char *devfspath = di_devfs_path(root);
3671 DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
3672 di_devfs_path_free(devfspath);
3673 #endif
3676 * paranoid error checking
3678 if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
3679 errno = EINVAL;
3680 return (-1);
3683 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3684 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3685 return (-1);
3688 head->next = NULL;
3689 head->node = root;
3691 DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
3692 di_node_name(root)));
3694 while (head != NULL)
3695 walk_one_lnode(&head, arg, lnode_callback);
3697 return (0);
3700 static char *
3701 alias_to_curr(di_node_t anynode, char *devfspath, di_node_t *nodep)
3703 caddr_t pa;
3704 struct di_all *all;
3705 struct di_alias *di_alias;
3706 di_node_t node;
3707 char *curr;
3708 char *cp;
3709 char *alias;
3710 di_off_t off;
3711 char buf[MAXPATHLEN];
3713 *nodep = NULL;
3715 if (anynode == DI_NODE_NIL || devfspath == NULL)
3716 return (NULL);
3718 pa = (caddr_t)anynode - DI_NODE(anynode)->self;
3719 all = DI_ALL(pa);
3721 di_alias = NULL;
3722 for (off = all->aliases; off > 0; off = di_alias->next) {
3723 di_alias = DI_ALIAS(pa + off);
3724 alias = di_alias->alias;
3725 if (strncmp(devfspath, alias, strlen(alias)) == 0) {
3726 cp = devfspath + strlen(alias);
3727 node = DI_NODE(pa + di_alias->curroff);
3728 assert(node != DI_NODE_NIL);
3729 if (*cp == '\0') {
3730 *nodep = node;
3731 return (NULL);
3732 } else if (*cp == '/') {
3733 curr = di_devfs_path(node);
3734 (void) snprintf(buf, sizeof (buf), "%s%s",
3735 curr, cp);
3736 di_devfs_path_free(curr);
3737 curr = strdup(buf);
3738 return (curr);
3743 return (NULL);
3746 static di_node_t
3747 di_lookup_node_impl(di_node_t root, char *devfspath)
3749 struct di_all *dap;
3750 di_node_t node;
3751 char *copy, *slash, *pname, *paddr;
3754 * Path must be absolute and musn't have duplicate slashes
3756 if (*devfspath != '/' || strstr(devfspath, "//")) {
3757 DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
3758 return (DI_NODE_NIL);
3761 if (root == DI_NODE_NIL) {
3762 DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
3763 return (DI_NODE_NIL);
3766 dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
3767 if (strcmp(dap->root_path, "/") != 0) {
3768 DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
3769 return (DI_NODE_NIL);
3772 if ((copy = strdup(devfspath)) == NULL) {
3773 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3774 return (DI_NODE_NIL);
3777 for (slash = copy, node = root; slash; ) {
3780 * Handle devfspath = "/" case as well as trailing '/'
3782 if (*(slash + 1) == '\0')
3783 break;
3786 * More path-components exist. Deal with the next one
3788 pname = slash + 1;
3789 node = di_child_node(node);
3791 if (slash = strchr(pname, '/'))
3792 *slash = '\0';
3793 if (paddr = strchr(pname, '@'))
3794 *paddr++ = '\0';
3796 for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
3797 char *name, *baddr;
3799 name = di_node_name(node);
3800 baddr = di_bus_addr(node);
3802 if (strcmp(pname, name) != 0)
3803 continue;
3806 * Mappings between a "path-address" and bus-addr
3808 * paddr baddr
3809 * ---------------------
3810 * NULL NULL
3811 * NULL ""
3812 * "" N/A (invalid paddr)
3814 if (paddr && baddr && strcmp(paddr, baddr) == 0)
3815 break;
3816 if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
3817 break;
3821 * No nodes in the sibling list or there was no match
3823 if (node == DI_NODE_NIL) {
3824 DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
3825 free(copy);
3826 return (DI_NODE_NIL);
3830 assert(node != DI_NODE_NIL);
3831 free(copy);
3832 return (node);
3835 di_node_t
3836 di_lookup_node(di_node_t root, char *devfspath)
3838 di_node_t node;
3839 char *curr;
3841 node = di_lookup_node_impl(root, devfspath);
3842 if (node != DI_NODE_NIL) {
3843 return (node);
3846 /* node is already set to DI_NODE_NIL */
3847 curr = alias_to_curr(root, devfspath, &node);
3848 if (curr == NULL) {
3849 /* node may or may node be DI_NODE_NIL */
3850 return (node);
3853 node = di_lookup_node_impl(root, curr);
3855 free(curr);
3857 return (node);
3860 char *
3861 di_alias2curr(di_node_t anynode, char *alias)
3863 di_node_t currnode = DI_NODE_NIL;
3864 char *curr;
3866 if (anynode == DI_NODE_NIL || alias == NULL)
3867 return (NULL);
3869 curr = alias_to_curr(anynode, alias, &currnode);
3870 if (curr == NULL && currnode != DI_NODE_NIL) {
3871 return (di_devfs_path(currnode));
3872 } else if (curr == NULL) {
3873 return (strdup(alias));
3876 return (curr);
3879 di_path_t
3880 di_lookup_path(di_node_t root, char *devfspath)
3882 di_node_t phci_node;
3883 di_path_t path = DI_PATH_NIL;
3884 char *copy, *lastslash;
3885 char *pname, *paddr;
3886 char *path_name, *path_addr;
3888 if ((copy = strdup(devfspath)) == NULL) {
3889 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3890 return (DI_NODE_NIL);
3893 if ((lastslash = strrchr(copy, '/')) == NULL) {
3894 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3895 goto out;
3898 /* stop at pHCI and find the node for the phci */
3899 *lastslash = '\0';
3900 phci_node = di_lookup_node(root, copy);
3901 if (phci_node == NULL) {
3902 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3903 goto out;
3906 /* set up pname and paddr for last component */
3907 pname = lastslash + 1;
3908 if ((paddr = strchr(pname, '@')) == NULL) {
3909 DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
3910 goto out;
3912 *paddr++ = '\0';
3914 /* walk paths below phci looking for match */
3915 for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
3916 path != DI_PATH_NIL;
3917 path = di_path_phci_next_path(phci_node, path)) {
3919 /* get name@addr of path */
3920 path_name = di_path_node_name(path);
3921 path_addr = di_path_bus_addr(path);
3922 if ((path_name == NULL) || (path_addr == NULL))
3923 continue;
3925 /* break on match */
3926 if ((strcmp(pname, path_name) == 0) &&
3927 (strcmp(paddr, path_addr) == 0))
3928 break;
3931 out: free(copy);
3932 return (path);
3935 static char *
3936 msglevel2str(di_debug_t msglevel)
3938 switch (msglevel) {
3939 case DI_ERR:
3940 return ("ERROR");
3941 case DI_INFO:
3942 return ("Info");
3943 case DI_TRACE:
3944 return ("Trace");
3945 case DI_TRACE1:
3946 return ("Trace1");
3947 case DI_TRACE2:
3948 return ("Trace2");
3949 default:
3950 return ("UNKNOWN");
3954 void
3955 dprint(di_debug_t msglevel, const char *fmt, ...)
3957 va_list ap;
3958 char *estr;
3960 if (di_debug <= DI_QUIET)
3961 return;
3963 if (di_debug < msglevel)
3964 return;
3966 estr = msglevel2str(msglevel);
3968 assert(estr);
3970 va_start(ap, fmt);
3972 (void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
3973 (ulong_t)getpid(), estr);
3974 (void) vfprintf(stderr, fmt, ap);
3976 va_end(ap);
3979 /* end of devinfo.c */