Unleashed v1.4
[unleashed.git] / usr / src / lib / libdevinfo / devinfo.c
blob1b900eb5c7a387a1f1bffeb582def70da0251049
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.
26 * Interfaces for getting device configuration data from kernel
27 * through the devinfo driver.
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stropts.h>
35 #include <fcntl.h>
36 #include <poll.h>
37 #include <synch.h>
38 #include <unistd.h>
39 #include <sys/mkdev.h>
40 #include <sys/obpdefs.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <sys/autoconf.h>
45 #include <stdarg.h>
46 #include <sys/ddi_hp.h>
48 #define NDEBUG 1
49 #include <assert.h>
51 #include "libdevinfo.h"
54 * Debug message levels
56 typedef enum {
57 DI_QUIET = 0, /* No debug messages - the default */
58 DI_ERR = 1,
59 DI_INFO,
60 DI_TRACE,
61 DI_TRACE1,
62 DI_TRACE2
63 } di_debug_t;
65 int di_debug = DI_QUIET;
67 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; }
69 void dprint(di_debug_t msglevel, const char *fmt, ...);
72 #pragma init(_libdevinfo_init)
74 void
75 _libdevinfo_init()
77 char *debug_str = getenv("_LIBDEVINFO_DEBUG");
79 if (debug_str) {
80 errno = 0;
81 di_debug = atoi(debug_str);
82 if (errno || di_debug < DI_QUIET)
83 di_debug = DI_QUIET;
87 di_node_t
88 di_init(const char *phys_path, uint_t flag)
90 return (di_init_impl(phys_path, flag, NULL));
94 * We use blocking_open() to guarantee access to the devinfo device, if open()
95 * is failing with EAGAIN.
97 static int
98 blocking_open(const char *path, int oflag)
100 int fd;
102 while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
103 (void) poll(NULL, 0, 1 * MILLISEC);
105 return (fd);
108 /* private interface */
109 di_node_t
110 di_init_driver(const char *drv_name, uint_t flag)
112 int fd;
113 char driver[MAXPATHLEN];
116 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
117 * which should be sufficient for any sensible programmer.
119 if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
120 errno = EINVAL;
121 return (DI_NODE_NIL);
123 (void) strcpy(driver, drv_name);
126 * open the devinfo driver
128 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
129 O_RDONLY)) == -1) {
130 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
131 return (DI_NODE_NIL);
134 if (ioctl(fd, DINFOLODRV, driver) != 0) {
135 DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
136 (void) close(fd);
137 errno = ENXIO;
138 return (DI_NODE_NIL);
140 (void) close(fd);
143 * Driver load succeeded, return a snapshot
145 return (di_init("/", flag));
148 di_node_t
149 di_init_impl(const char *phys_path, uint_t flag,
150 struct di_priv_data *priv)
152 caddr_t pa;
153 int fd, map_size;
154 struct di_all *dap;
155 struct dinfo_io dinfo_io;
157 uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
158 uint_t pagemask = ~pageoffset;
160 DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
163 * Make sure there is no minor name in the path
164 * and the path do not start with /devices....
166 if (strchr(phys_path, ':') ||
167 (strncmp(phys_path, "/devices", 8) == 0) ||
168 (strlen(phys_path) > MAXPATHLEN)) {
169 errno = EINVAL;
170 return (DI_NODE_NIL);
173 if (strlen(phys_path) == 0)
174 (void) sprintf(dinfo_io.root_path, "/");
175 else if (*phys_path != '/')
176 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
177 "/%s", phys_path);
178 else
179 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
180 "%s", phys_path);
183 * If private data is requested, copy the format specification
185 if (flag & DINFOPRIVDATA & 0xff) {
186 if (priv)
187 bcopy(priv, &dinfo_io.priv,
188 sizeof (struct di_priv_data));
189 else {
190 errno = EINVAL;
191 return (DI_NODE_NIL);
196 * Attempt to open the devinfo driver. Make a second attempt at the
197 * read-only minor node if we don't have privileges to open the full
198 * version _and_ if we're not requesting operations that the read-only
199 * node can't perform. (Setgid processes would fail an access() test,
200 * of course.)
202 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
203 O_RDONLY)) == -1) {
204 if ((flag & DINFOFORCE) == DINFOFORCE ||
205 (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
207 * We wanted to perform a privileged operation, but the
208 * privileged node isn't available. Don't modify errno
209 * on our way out (but display it if we're running with
210 * di_debug set).
212 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
213 errno));
214 return (DI_NODE_NIL);
217 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
218 O_RDONLY)) == -1) {
219 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
220 errno));
221 return (DI_NODE_NIL);
226 * Verify that there is no major conflict, i.e., we are indeed opening
227 * the devinfo driver.
229 if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
230 DPRINTF((DI_ERR,
231 "driver ID failed; check for major conflict\n"));
232 (void) close(fd);
233 return (DI_NODE_NIL);
237 * create snapshot
239 if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
240 DPRINTF((DI_ERR, "devinfo ioctl failed with "
241 "error: %d\n", errno));
242 (void) close(fd);
243 return (DI_NODE_NIL);
244 } else if (map_size == 0) {
245 DPRINTF((DI_ERR, "%s not found\n", phys_path));
246 errno = ENXIO;
247 (void) close(fd);
248 return (DI_NODE_NIL);
252 * copy snapshot to userland
254 map_size = (map_size + pageoffset) & pagemask;
255 if ((pa = valloc(map_size)) == NULL) {
256 DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
257 (void) close(fd);
258 return (DI_NODE_NIL);
261 if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
262 DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
263 (void) close(fd);
264 free(pa);
265 errno = EFAULT;
266 return (DI_NODE_NIL);
269 (void) close(fd);
271 dap = DI_ALL(pa);
272 if (dap->version != DI_SNAPSHOT_VERSION) {
273 DPRINTF((DI_ERR, "wrong snapshot version "
274 "(expected=%d, actual=%d)\n",
275 DI_SNAPSHOT_VERSION, dap->version));
276 free(pa);
277 errno = ESTALE;
278 return (DI_NODE_NIL);
280 if (dap->top_devinfo == 0) { /* phys_path not found */
281 DPRINTF((DI_ERR, "%s not found\n", phys_path));
282 free(pa);
283 errno = EINVAL;
284 return (DI_NODE_NIL);
287 return (DI_NODE(pa + dap->top_devinfo));
290 void
291 di_fini(di_node_t root)
293 caddr_t pa; /* starting address of map */
295 DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
298 * paranoid checking
300 if (root == DI_NODE_NIL) {
301 DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
302 return;
306 * The root contains its own offset--self.
307 * Subtracting it from root address, we get the starting addr.
308 * The map_size is stored at the beginning of snapshot.
309 * Once we have starting address and size, we can free().
311 pa = (caddr_t)root - DI_NODE(root)->self;
313 free(pa);
316 di_node_t
317 di_parent_node(di_node_t node)
319 caddr_t pa; /* starting address of map */
321 if (node == DI_NODE_NIL) {
322 errno = EINVAL;
323 return (DI_NODE_NIL);
326 DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
328 pa = (caddr_t)node - DI_NODE(node)->self;
330 if (DI_NODE(node)->parent) {
331 return (DI_NODE(pa + DI_NODE(node)->parent));
335 * Deal with error condition:
336 * If parent doesn't exist and node is not the root,
337 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
339 if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
340 errno = ENOTSUP;
341 else
342 errno = ENXIO;
344 return (DI_NODE_NIL);
347 di_node_t
348 di_sibling_node(di_node_t node)
350 caddr_t pa; /* starting address of map */
352 if (node == DI_NODE_NIL) {
353 errno = EINVAL;
354 return (DI_NODE_NIL);
357 DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
359 pa = (caddr_t)node - DI_NODE(node)->self;
361 if (DI_NODE(node)->sibling) {
362 return (DI_NODE(pa + DI_NODE(node)->sibling));
366 * Deal with error condition:
367 * Sibling doesn't exist, figure out if ioctl command
368 * has DINFOSUBTREE set. If it doesn't, set errno to
369 * ENOTSUP.
371 if (!(DI_ALL(pa)->command & DINFOSUBTREE))
372 errno = ENOTSUP;
373 else
374 errno = ENXIO;
376 return (DI_NODE_NIL);
379 di_node_t
380 di_child_node(di_node_t node)
382 caddr_t pa; /* starting address of map */
384 DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
386 if (node == DI_NODE_NIL) {
387 errno = EINVAL;
388 return (DI_NODE_NIL);
391 pa = (caddr_t)node - DI_NODE(node)->self;
393 if (DI_NODE(node)->child) {
394 return (DI_NODE(pa + DI_NODE(node)->child));
398 * Deal with error condition:
399 * Child doesn't exist, figure out if DINFOSUBTREE is set.
400 * If it isn't, set errno to ENOTSUP.
402 if (!(DI_ALL(pa)->command & DINFOSUBTREE))
403 errno = ENOTSUP;
404 else
405 errno = ENXIO;
407 return (DI_NODE_NIL);
410 di_node_t
411 di_drv_first_node(const char *drv_name, di_node_t root)
413 caddr_t pa; /* starting address of map */
414 int major, devcnt;
415 struct di_devnm *devnm;
417 DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
419 if (root == DI_NODE_NIL) {
420 errno = EINVAL;
421 return (DI_NODE_NIL);
425 * get major number of driver
427 pa = (caddr_t)root - DI_NODE(root)->self;
428 devcnt = DI_ALL(pa)->devcnt;
429 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
431 for (major = 0; major < devcnt; major++)
432 if (devnm[major].name && (strcmp(drv_name,
433 (char *)(pa + devnm[major].name)) == 0))
434 break;
436 if (major >= devcnt) {
437 errno = EINVAL;
438 return (DI_NODE_NIL);
441 if (!(devnm[major].head)) {
442 errno = ENXIO;
443 return (DI_NODE_NIL);
446 return (DI_NODE(pa + devnm[major].head));
449 di_node_t
450 di_drv_next_node(di_node_t node)
452 caddr_t pa; /* starting address of map */
454 if (node == DI_NODE_NIL) {
455 errno = EINVAL;
456 return (DI_NODE_NIL);
459 DPRINTF((DI_TRACE, "next node on per driver list:"
460 " current=%s, driver=%s\n",
461 di_node_name(node), di_driver_name(node)));
463 if (DI_NODE(node)->next == (di_off_t)-1) {
464 errno = ENOTSUP;
465 return (DI_NODE_NIL);
468 pa = (caddr_t)node - DI_NODE(node)->self;
470 if (DI_NODE(node)->next == 0) {
471 errno = ENXIO;
472 return (DI_NODE_NIL);
475 return (DI_NODE(pa + DI_NODE(node)->next));
479 * Internal library interfaces:
480 * node_list etc. for node walking
482 struct node_list {
483 struct node_list *next;
484 di_node_t node;
487 static void
488 free_node_list(struct node_list **headp)
490 struct node_list *tmp;
492 while (*headp) {
493 tmp = *headp;
494 *headp = (*headp)->next;
495 free(tmp);
499 static void
500 append_node_list(struct node_list **headp, struct node_list *list)
502 struct node_list *tmp;
504 if (*headp == NULL) {
505 *headp = list;
506 return;
509 if (list == NULL) /* a minor optimization */
510 return;
512 tmp = *headp;
513 while (tmp->next)
514 tmp = tmp->next;
516 tmp->next = list;
519 static void
520 prepend_node_list(struct node_list **headp, struct node_list *list)
522 struct node_list *tmp;
524 if (list == NULL)
525 return;
527 tmp = *headp;
528 *headp = list;
530 if (tmp == NULL) /* a minor optimization */
531 return;
533 while (list->next)
534 list = list->next;
536 list->next = tmp;
540 * returns 1 if node is a descendant of parent, 0 otherwise
542 static int
543 is_descendant(di_node_t node, di_node_t parent)
546 * DI_NODE_NIL is parent of root, so it is
547 * the parent of all nodes.
549 if (parent == DI_NODE_NIL) {
550 return (1);
553 do {
554 node = di_parent_node(node);
555 } while ((node != DI_NODE_NIL) && (node != parent));
557 return (node != DI_NODE_NIL);
561 * Insert list before the first node which is NOT a descendent of parent.
562 * This is needed to reproduce the exact walking order of link generators.
564 static void
565 insert_node_list(struct node_list **headp, struct node_list *list,
566 di_node_t parent)
568 struct node_list *tmp, *tmp1;
570 if (list == NULL)
571 return;
573 tmp = *headp;
574 if (tmp == NULL) { /* a minor optimization */
575 *headp = list;
576 return;
579 if (!is_descendant(tmp->node, parent)) {
580 prepend_node_list(headp, list);
581 return;
585 * Find first node which is not a descendant
587 while (tmp->next && is_descendant(tmp->next->node, parent)) {
588 tmp = tmp->next;
591 tmp1 = tmp->next;
592 tmp->next = list;
593 append_node_list(headp, tmp1);
597 * Get a linked list of handles of all children
599 static struct node_list *
600 get_children(di_node_t node)
602 di_node_t child;
603 struct node_list *result, *tmp;
605 DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
607 if ((child = di_child_node(node)) == DI_NODE_NIL) {
608 return (NULL);
611 if ((result = malloc(sizeof (struct node_list))) == NULL) {
612 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
613 return (NULL);
616 result->node = child;
617 tmp = result;
619 while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
620 if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
621 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
622 free_node_list(&result);
623 return (NULL);
625 tmp = tmp->next;
626 tmp->node = child;
629 tmp->next = NULL;
631 return (result);
635 * Internal library interface:
636 * Delete all siblings of the first node from the node_list, along with
637 * the first node itself.
639 static void
640 prune_sib(struct node_list **headp)
642 di_node_t parent, curr_par, curr_gpar;
643 struct node_list *curr, *prev;
646 * get handle to parent of first node
648 if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
650 * This must be the root of the snapshot, so can't
651 * have any siblings.
653 * XXX Put a check here just in case.
655 if ((*headp)->next)
656 DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
658 free(*headp);
659 *headp = NULL;
660 return;
664 * To be complete, we should also delete the children
665 * of siblings that have already been visited.
666 * This happens for DI_WALK_SIBFIRST when the first node
667 * is NOT the first in the linked list of siblings.
669 * Hence, we compare parent with BOTH the parent and grandparent
670 * of nodes, and delete node is a match is found.
672 prev = *headp;
673 curr = prev->next;
674 while (curr) {
675 if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) &&
676 ((curr_par == parent) || ((curr_gpar =
677 di_parent_node(curr_par)) != DI_NODE_NIL) &&
678 (curr_gpar == parent))) {
680 * match parent/grandparent: delete curr
682 prev->next = curr->next;
683 free(curr);
684 curr = prev->next;
685 } else
686 curr = curr->next;
690 * delete the first node
692 curr = *headp;
693 *headp = curr->next;
694 free(curr);
698 * Internal library function:
699 * Update node list based on action (return code from callback)
700 * and flag specifying walking behavior.
702 static void
703 update_node_list(int action, uint_t flag, struct node_list **headp)
705 struct node_list *children, *tmp;
706 di_node_t parent = di_parent_node((*headp)->node);
708 switch (action) {
709 case DI_WALK_TERMINATE:
711 * free the node list and be done
713 children = NULL;
714 free_node_list(headp);
715 break;
717 case DI_WALK_PRUNESIB:
719 * Get list of children and prune siblings
721 children = get_children((*headp)->node);
722 prune_sib(headp);
723 break;
725 case DI_WALK_PRUNECHILD:
727 * Set children to NULL and pop first node
729 children = NULL;
730 tmp = *headp;
731 *headp = tmp->next;
732 free(tmp);
733 break;
735 case DI_WALK_CONTINUE:
736 default:
738 * Get list of children and pop first node
740 children = get_children((*headp)->node);
741 tmp = *headp;
742 *headp = tmp->next;
743 free(tmp);
744 break;
748 * insert the list of children
750 switch (flag) {
751 case DI_WALK_CLDFIRST:
752 prepend_node_list(headp, children);
753 break;
755 case DI_WALK_SIBFIRST:
756 append_node_list(headp, children);
757 break;
759 case DI_WALK_LINKGEN:
760 default:
761 insert_node_list(headp, children, parent);
762 break;
767 * Internal library function:
768 * Invoke callback on one node and update the list of nodes to be walked
769 * based on the flag and return code.
771 static void
772 walk_one_node(struct node_list **headp, uint_t flag, void *arg,
773 int (*callback)(di_node_t, void *))
775 DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
777 update_node_list(callback((*headp)->node, arg),
778 flag & DI_WALK_MASK, headp);
782 di_walk_node(di_node_t root, uint_t flag, void *arg,
783 int (*node_callback)(di_node_t, void *))
785 struct node_list *head; /* node_list for tree walk */
787 if (root == NULL) {
788 errno = EINVAL;
789 return (-1);
792 if ((head = malloc(sizeof (struct node_list))) == NULL) {
793 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
794 return (-1);
797 head->next = NULL;
798 head->node = root;
800 DPRINTF((DI_INFO, "Start node walking from node %s\n",
801 di_node_name(root)));
803 while (head != NULL)
804 walk_one_node(&head, flag, arg, node_callback);
806 return (0);
810 * Internal library function:
811 * Invoke callback for each minor on the minor list of first node
812 * on node_list headp, and place children of first node on the list.
814 * This is similar to walk_one_node, except we only walk in child
815 * first mode.
817 static void
818 walk_one_minor_list(struct node_list **headp, const char *desired_type,
819 uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
821 int ddm_type;
822 int action = DI_WALK_CONTINUE;
823 char *node_type;
824 di_minor_t minor = DI_MINOR_NIL;
825 di_node_t node = (*headp)->node;
827 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
828 ddm_type = di_minor_type(minor);
830 if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
831 continue;
833 if ((ddm_type == DDM_INTERNAL_PATH) &&
834 !(flag & DI_CHECK_INTERNAL_PATH))
835 continue;
837 node_type = di_minor_nodetype(minor);
838 if ((desired_type != NULL) && ((node_type == NULL) ||
839 strncmp(desired_type, node_type, strlen(desired_type))
840 != 0))
841 continue;
843 if ((action = callback(node, minor, arg)) ==
844 DI_WALK_TERMINATE) {
845 break;
849 update_node_list(action, DI_WALK_LINKGEN, headp);
853 di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
854 int (*minor_callback)(di_node_t, di_minor_t, void *))
856 struct node_list *head; /* node_list for tree walk */
858 #ifdef DEBUG
859 char *devfspath = di_devfs_path(root);
860 DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath));
861 di_devfs_path_free(devfspath);
862 #endif
864 if (root == NULL) {
865 errno = EINVAL;
866 return (-1);
869 if ((head = malloc(sizeof (struct node_list))) == NULL) {
870 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
871 return (-1);
874 head->next = NULL;
875 head->node = root;
877 DPRINTF((DI_INFO, "Start minor walking from node %s\n",
878 di_node_name(root)));
880 while (head != NULL)
881 walk_one_minor_list(&head, minor_type, flag, arg,
882 minor_callback);
884 return (0);
888 * generic node parameters
889 * Calling these routines always succeeds.
891 char *
892 di_node_name(di_node_t node)
894 return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
897 /* returns NULL ptr or a valid ptr to non-NULL string */
898 char *
899 di_bus_addr(di_node_t node)
901 caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
903 if (DI_NODE(node)->address == 0)
904 return (NULL);
906 return ((char *)(pa + DI_NODE(node)->address));
909 char *
910 di_binding_name(di_node_t node)
912 caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
914 if (DI_NODE(node)->bind_name == 0)
915 return (NULL);
917 return ((char *)(pa + DI_NODE(node)->bind_name));
921 di_compatible_names(di_node_t node, char **names)
923 char *c;
924 int len, size, entries = 0;
926 if (DI_NODE(node)->compat_names == 0) {
927 *names = NULL;
928 return (0);
931 *names = (caddr_t)node +
932 DI_NODE(node)->compat_names - DI_NODE(node)->self;
934 c = *names;
935 len = DI_NODE(node)->compat_length;
936 while (len > 0) {
937 entries++;
938 size = strlen(c) + 1;
939 len -= size;
940 c += size;
943 return (entries);
947 di_instance(di_node_t node)
949 return (DI_NODE(node)->instance);
953 * XXX: emulate the return value of the old implementation
954 * using info from devi_node_class and devi_node_attributes.
957 di_nodeid(di_node_t node)
959 if (DI_NODE(node)->node_class == DDI_NC_PROM)
960 return (DI_PROM_NODEID);
962 if (DI_NODE(node)->attributes & DDI_PERSISTENT)
963 return (DI_SID_NODEID);
965 return (DI_PSEUDO_NODEID);
968 uint_t
969 di_state(di_node_t node)
971 uint_t result = 0;
973 if (di_node_state(node) < DS_ATTACHED)
974 result |= DI_DRIVER_DETACHED;
975 if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
976 result |= DI_DEVICE_OFFLINE;
977 if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
978 result |= DI_DEVICE_DOWN;
979 if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
980 result |= DI_DEVICE_DEGRADED;
981 if (DI_NODE(node)->state & DEVI_DEVICE_REMOVED)
982 result |= DI_DEVICE_REMOVED;
983 if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
984 result |= DI_BUS_QUIESCED;
985 if (DI_NODE(node)->state & DEVI_BUS_DOWN)
986 result |= DI_BUS_DOWN;
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 pointer to the allocated string, which must be freed by the caller.
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 uint_t
2032 di_path_flags(di_path_t path)
2034 return (DI_PATH(path)->path_flags);
2037 char *
2038 di_path_node_name(di_path_t path)
2040 di_node_t client_node;
2042 /* pathinfo gets node_name from client */
2043 if ((client_node = di_path_client_node(path)) == NULL)
2044 return (NULL);
2045 return (di_node_name(client_node));
2048 char *
2049 di_path_bus_addr(di_path_t path)
2051 caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
2053 if (DI_PATH(path)->path_addr == 0)
2054 return (NULL);
2056 return ((char *)(pa + DI_PATH(path)->path_addr));
2060 di_path_instance(di_path_t path)
2062 return (DI_PATH(path)->path_instance);
2065 di_node_t
2066 di_path_client_node(di_path_t path)
2068 caddr_t pa; /* starting address of map */
2070 if (path == DI_PATH_NIL) {
2071 errno = EINVAL;
2072 return (DI_PATH_NIL);
2075 DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
2077 pa = (caddr_t)path - DI_PATH(path)->self;
2079 if (DI_PATH(path)->path_client) {
2080 return (DI_NODE(pa + DI_PATH(path)->path_client));
2084 * Deal with error condition:
2085 * If parent doesn't exist and node is not the root,
2086 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2088 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
2089 errno = ENOTSUP;
2090 else
2091 errno = ENXIO;
2093 return (DI_NODE_NIL);
2096 di_node_t
2097 di_path_phci_node(di_path_t path)
2099 caddr_t pa; /* starting address of map */
2101 if (path == DI_PATH_NIL) {
2102 errno = EINVAL;
2103 return (DI_PATH_NIL);
2106 DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
2108 pa = (caddr_t)path - DI_PATH(path)->self;
2110 if (DI_PATH(path)->path_phci) {
2111 return (DI_NODE(pa + DI_PATH(path)->path_phci));
2115 * Deal with error condition:
2116 * If parent doesn't exist and node is not the root,
2117 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2119 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
2120 errno = ENOTSUP;
2121 else
2122 errno = ENXIO;
2124 return (DI_NODE_NIL);
2127 di_path_prop_t
2128 di_path_prop_next(di_path_t path, di_path_prop_t prop)
2130 caddr_t pa;
2132 if (path == DI_PATH_NIL) {
2133 errno = EINVAL;
2134 return (DI_PROP_NIL);
2138 * prop is not NIL
2140 if (prop != DI_PROP_NIL) {
2141 if (DI_PROP(prop)->next != 0)
2142 return (DI_PATHPROP((caddr_t)prop -
2143 DI_PROP(prop)->self + DI_PROP(prop)->next));
2144 else {
2145 errno = ENXIO;
2146 return (DI_PROP_NIL);
2151 * prop is NIL-->caller asks for first property
2153 pa = (caddr_t)path - DI_PATH(path)->self;
2154 if (DI_PATH(path)->path_prop != 0) {
2155 return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
2159 * no property data-->check if snapshot includes props
2160 * in order to set the correct errno
2162 if (DINFOPROP & (DI_ALL(pa)->command))
2163 errno = ENXIO;
2164 else
2165 errno = ENOTSUP;
2167 return (DI_PROP_NIL);
2170 char *
2171 di_path_prop_name(di_path_prop_t prop)
2173 caddr_t pa; /* starting address of map */
2174 pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
2175 return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
2179 di_path_prop_len(di_path_prop_t prop)
2181 return (DI_PATHPROP(prop)->prop_len);
2185 di_path_prop_type(di_path_prop_t prop)
2187 switch (DI_PATHPROP(prop)->prop_type) {
2188 case DDI_PROP_TYPE_INT:
2189 return (DI_PROP_TYPE_INT);
2190 case DDI_PROP_TYPE_INT64:
2191 return (DI_PROP_TYPE_INT64);
2192 case DDI_PROP_TYPE_BYTE:
2193 return (DI_PROP_TYPE_BYTE);
2194 case DDI_PROP_TYPE_STRING:
2195 return (DI_PROP_TYPE_STRING);
2197 return (DI_PROP_TYPE_UNKNOWN);
2201 di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
2203 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2204 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2205 errno = EFAULT;
2206 *prop_data = NULL;
2207 return (-1);
2210 *prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
2211 + DI_PATHPROP(prop)->prop_data);
2213 return (di_prop_decode_common((void *)prop_data,
2214 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
2218 di_path_prop_ints(di_path_prop_t prop, int **prop_data)
2220 if (DI_PATHPROP(prop)->prop_len == 0)
2221 return (0);
2223 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2224 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2225 errno = EFAULT;
2226 *prop_data = NULL;
2227 return (-1);
2230 *prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
2231 + DI_PATHPROP(prop)->prop_data));
2233 return (di_prop_decode_common((void *)prop_data,
2234 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
2238 di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
2240 if (DI_PATHPROP(prop)->prop_len == 0)
2241 return (0);
2243 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2244 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2245 errno = EFAULT;
2246 *prop_data = NULL;
2247 return (-1);
2250 *prop_data = (int64_t *)((void *)((caddr_t)prop -
2251 DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
2253 return (di_prop_decode_common((void *)prop_data,
2254 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
2258 di_path_prop_strings(di_path_prop_t prop, char **prop_data)
2260 if (DI_PATHPROP(prop)->prop_len == 0)
2261 return (0);
2263 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2264 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2265 errno = EFAULT;
2266 *prop_data = NULL;
2267 return (-1);
2270 *prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
2271 + DI_PATHPROP(prop)->prop_data);
2273 return (di_prop_decode_common((void *)prop_data,
2274 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
2277 static di_path_prop_t
2278 di_path_prop_search(di_path_t path, const char *name, int type)
2280 di_path_prop_t prop = DI_PROP_NIL;
2283 * Sanity check arguments
2285 if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
2286 !DI_PROP_TYPE_VALID(type)) {
2287 errno = EINVAL;
2288 return (DI_PROP_NIL);
2291 while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
2292 int prop_type = di_path_prop_type(prop);
2294 DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
2295 di_path_prop_name(prop), prop_type));
2297 if (strcmp(name, di_path_prop_name(prop)) != 0)
2298 continue;
2300 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
2301 continue;
2303 return (prop);
2306 return (DI_PROP_NIL);
2310 di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
2311 uchar_t **prop_data)
2313 di_path_prop_t prop;
2315 if ((prop = di_path_prop_search(path, prop_name,
2316 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
2317 return (-1);
2319 return (di_path_prop_bytes(prop, prop_data));
2323 di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
2324 int **prop_data)
2326 di_path_prop_t prop;
2328 if ((prop = di_path_prop_search(path, prop_name,
2329 DI_PROP_TYPE_INT)) == DI_PROP_NIL)
2330 return (-1);
2332 return (di_path_prop_ints(prop, prop_data));
2336 di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
2337 int64_t **prop_data)
2339 di_path_prop_t prop;
2341 if ((prop = di_path_prop_search(path, prop_name,
2342 DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
2343 return (-1);
2345 return (di_path_prop_int64s(prop, prop_data));
2348 int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
2349 char **prop_data)
2351 di_path_prop_t prop;
2353 if ((prop = di_path_prop_search(path, prop_name,
2354 DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
2355 return (-1);
2357 return (di_path_prop_strings(prop, prop_data));
2361 * Consolidation private interfaces for traversing vhci nodes.
2363 di_node_t
2364 di_vhci_first_node(di_node_t root)
2366 struct di_all *dap;
2367 caddr_t pa; /* starting address of map */
2369 DPRINTF((DI_INFO, "Get first vhci node\n"));
2371 if (root == DI_NODE_NIL) {
2372 errno = EINVAL;
2373 return (DI_NODE_NIL);
2376 pa = (caddr_t)root - DI_NODE(root)->self;
2377 dap = DI_ALL(pa);
2379 if (dap->top_vhci_devinfo == 0) {
2380 errno = ENXIO;
2381 return (DI_NODE_NIL);
2384 return (DI_NODE(pa + dap->top_vhci_devinfo));
2387 di_node_t
2388 di_vhci_next_node(di_node_t node)
2390 caddr_t pa; /* starting address of map */
2392 if (node == DI_NODE_NIL) {
2393 errno = EINVAL;
2394 return (DI_NODE_NIL);
2397 DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
2398 " current=%s\n", di_node_name(node)));
2400 if (DI_NODE(node)->next_vhci == 0) {
2401 errno = ENXIO;
2402 return (DI_NODE_NIL);
2405 pa = (caddr_t)node - DI_NODE(node)->self;
2407 return (DI_NODE(pa + DI_NODE(node)->next_vhci));
2411 * Consolidation private interfaces for traversing phci nodes.
2413 di_node_t
2414 di_phci_first_node(di_node_t vhci_node)
2416 caddr_t pa; /* starting address of map */
2418 DPRINTF((DI_INFO, "Get first phci node:\n"
2419 " current=%s", di_node_name(vhci_node)));
2421 if (vhci_node == DI_NODE_NIL) {
2422 errno = EINVAL;
2423 return (DI_NODE_NIL);
2426 pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
2428 if (DI_NODE(vhci_node)->top_phci == 0) {
2429 errno = ENXIO;
2430 return (DI_NODE_NIL);
2433 return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
2436 di_node_t
2437 di_phci_next_node(di_node_t node)
2439 caddr_t pa; /* starting address of map */
2441 if (node == DI_NODE_NIL) {
2442 errno = EINVAL;
2443 return (DI_NODE_NIL);
2446 DPRINTF((DI_TRACE, "next phci node on the snap shot:"
2447 " current=%s\n", di_node_name(node)));
2449 if (DI_NODE(node)->next_phci == 0) {
2450 errno = ENXIO;
2451 return (DI_NODE_NIL);
2454 pa = (caddr_t)node - DI_NODE(node)->self;
2456 return (DI_NODE(pa + DI_NODE(node)->next_phci));
2460 * Consolidation private interfaces for private data
2462 void *
2463 di_parent_private_data(di_node_t node)
2465 caddr_t pa;
2467 if (DI_NODE(node)->parent_data == 0) {
2468 errno = ENXIO;
2469 return (NULL);
2472 if (DI_NODE(node)->parent_data == (di_off_t)-1) {
2474 * Private data requested, but not obtained due to a memory
2475 * error (e.g. wrong format specified)
2477 errno = EFAULT;
2478 return (NULL);
2481 pa = (caddr_t)node - DI_NODE(node)->self;
2482 if (DI_NODE(node)->parent_data)
2483 return (pa + DI_NODE(node)->parent_data);
2485 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2486 errno = ENXIO;
2487 else
2488 errno = ENOTSUP;
2490 return (NULL);
2493 void *
2494 di_driver_private_data(di_node_t node)
2496 caddr_t pa;
2498 if (DI_NODE(node)->driver_data == 0) {
2499 errno = ENXIO;
2500 return (NULL);
2503 if (DI_NODE(node)->driver_data == (di_off_t)-1) {
2505 * Private data requested, but not obtained due to a memory
2506 * error (e.g. wrong format specified)
2508 errno = EFAULT;
2509 return (NULL);
2512 pa = (caddr_t)node - DI_NODE(node)->self;
2513 if (DI_NODE(node)->driver_data)
2514 return (pa + DI_NODE(node)->driver_data);
2516 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2517 errno = ENXIO;
2518 else
2519 errno = ENOTSUP;
2521 return (NULL);
2525 * Hotplug information access
2528 typedef struct {
2529 void *arg;
2530 const char *type;
2531 uint_t flag;
2532 int (*hp_callback)(di_node_t, di_hp_t, void *);
2533 } di_walk_hp_arg_t;
2535 static int
2536 di_walk_hp_callback(di_node_t node, void *argp)
2538 di_walk_hp_arg_t *arg = (di_walk_hp_arg_t *)argp;
2539 di_hp_t hp;
2540 char *type_str;
2542 for (hp = DI_HP_NIL; (hp = di_hp_next(node, hp)) != DI_HP_NIL; ) {
2544 /* Exclude non-matching types if a type filter is specified */
2545 if (arg->type != NULL) {
2546 type_str = di_hp_description(hp);
2547 if (type_str && (strcmp(arg->type, type_str) != 0))
2548 continue;
2551 /* Exclude ports if DI_HP_PORT flag not specified */
2552 if (!(arg->flag & DI_HP_PORT) &&
2553 (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2554 continue;
2556 /* Exclude connectors if DI_HP_CONNECTOR flag not specified */
2557 if (!(arg->flag & DI_HP_CONNECTOR) &&
2558 !(di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2559 continue;
2561 /* Perform callback */
2562 if (arg->hp_callback(node, hp, arg->arg) != DI_WALK_CONTINUE)
2563 return (DI_WALK_TERMINATE);
2566 return (DI_WALK_CONTINUE);
2570 di_walk_hp(di_node_t node, const char *type, uint_t flag, void *arg,
2571 int (*hp_callback)(di_node_t node, di_hp_t hp, void *arg))
2573 di_walk_hp_arg_t walk_arg;
2574 caddr_t pa;
2576 #ifdef DEBUG
2577 char *devfspath = di_devfs_path(node);
2578 DPRINTF((DI_INFO, "walking hotplug nodes under %s\n", devfspath));
2579 di_devfs_path_free(devfspath);
2580 #endif
2582 * paranoid error checking
2584 if ((node == DI_NODE_NIL) || (hp_callback == NULL)) {
2585 errno = EINVAL;
2586 return (-1);
2589 /* check if hotplug data is included in snapshot */
2590 pa = (caddr_t)node - DI_NODE(node)->self;
2591 if (!(DI_ALL(pa)->command & DINFOHP)) {
2592 errno = ENOTSUP;
2593 return (-1);
2596 walk_arg.arg = arg;
2597 walk_arg.type = type;
2598 walk_arg.flag = flag;
2599 walk_arg.hp_callback = hp_callback;
2600 return (di_walk_node(node, DI_WALK_CLDFIRST, &walk_arg,
2601 di_walk_hp_callback));
2604 di_hp_t
2605 di_hp_next(di_node_t node, di_hp_t hp)
2607 caddr_t pa;
2610 * paranoid error checking
2612 if (node == DI_NODE_NIL) {
2613 errno = EINVAL;
2614 return (DI_HP_NIL);
2618 * hotplug node is not NIL
2620 if (hp != DI_HP_NIL) {
2621 if (DI_HP(hp)->next != 0)
2622 return (DI_HP((caddr_t)hp - hp->self + hp->next));
2623 else {
2624 errno = ENXIO;
2625 return (DI_HP_NIL);
2630 * hotplug node is NIL-->caller asks for first hotplug node
2632 if (DI_NODE(node)->hp_data != 0) {
2633 return (DI_HP((caddr_t)node - DI_NODE(node)->self +
2634 DI_NODE(node)->hp_data));
2638 * no hotplug data-->check if snapshot includes hotplug data
2639 * in order to set the correct errno
2641 pa = (caddr_t)node - DI_NODE(node)->self;
2642 if (DINFOHP & DI_ALL(pa)->command)
2643 errno = ENXIO;
2644 else
2645 errno = ENOTSUP;
2647 return (DI_HP_NIL);
2650 char *
2651 di_hp_name(di_hp_t hp)
2653 caddr_t pa;
2656 * paranoid error checking
2658 if (hp == DI_HP_NIL) {
2659 errno = EINVAL;
2660 return (NULL);
2663 pa = (caddr_t)hp - DI_HP(hp)->self;
2665 if (DI_HP(hp)->hp_name == 0) {
2666 errno = ENXIO;
2667 return (NULL);
2670 return ((char *)(pa + DI_HP(hp)->hp_name));
2674 di_hp_connection(di_hp_t hp)
2677 * paranoid error checking
2679 if (hp == DI_HP_NIL) {
2680 errno = EINVAL;
2681 return (-1);
2684 if (DI_HP(hp)->hp_connection == -1)
2685 errno = ENOENT;
2687 return (DI_HP(hp)->hp_connection);
2691 di_hp_depends_on(di_hp_t hp)
2694 * paranoid error checking
2696 if (hp == DI_HP_NIL) {
2697 errno = EINVAL;
2698 return (-1);
2701 if (DI_HP(hp)->hp_depends_on == -1)
2702 errno = ENOENT;
2704 return (DI_HP(hp)->hp_depends_on);
2708 di_hp_state(di_hp_t hp)
2711 * paranoid error checking
2713 if (hp == DI_HP_NIL) {
2714 errno = EINVAL;
2715 return (-1);
2718 return (DI_HP(hp)->hp_state);
2722 di_hp_type(di_hp_t hp)
2725 * paranoid error checking
2727 if (hp == DI_HP_NIL) {
2728 errno = EINVAL;
2729 return (-1);
2732 return (DI_HP(hp)->hp_type);
2735 char *
2736 di_hp_description(di_hp_t hp)
2738 caddr_t pa;
2741 * paranoid error checking
2743 if (hp == DI_HP_NIL) {
2744 errno = EINVAL;
2745 return (NULL);
2748 pa = (caddr_t)hp - DI_HP(hp)->self;
2750 if (DI_HP(hp)->hp_type_str == 0)
2751 return (NULL);
2753 return ((char *)(pa + DI_HP(hp)->hp_type_str));
2756 di_node_t
2757 di_hp_child(di_hp_t hp)
2759 caddr_t pa; /* starting address of map */
2762 * paranoid error checking
2764 if (hp == DI_HP_NIL) {
2765 errno = EINVAL;
2766 return (DI_NODE_NIL);
2769 pa = (caddr_t)hp - DI_HP(hp)->self;
2771 if (DI_HP(hp)->hp_child > 0) {
2772 return (DI_NODE(pa + DI_HP(hp)->hp_child));
2776 * Deal with error condition:
2777 * Child doesn't exist, figure out if DINFOSUBTREE is set.
2778 * If it isn't, set errno to ENOTSUP.
2780 if (!(DINFOSUBTREE & DI_ALL(pa)->command))
2781 errno = ENOTSUP;
2782 else
2783 errno = ENXIO;
2785 return (DI_NODE_NIL);
2788 time_t
2789 di_hp_last_change(di_hp_t hp)
2792 * paranoid error checking
2794 if (hp == DI_HP_NIL) {
2795 errno = EINVAL;
2796 return ((time_t)0);
2799 return ((time_t)DI_HP(hp)->hp_last_change);
2803 * PROM property access
2807 * openprom driver stuff:
2808 * The maximum property length depends on the buffer size. We use
2809 * OPROMMAXPARAM defined in <sys/openpromio.h>
2811 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2812 * MAXVALSZ is maximum value size, which is whatever space left in buf
2815 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int)
2816 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME;
2818 struct di_prom_prop {
2819 char *name;
2820 int len;
2821 uchar_t *data;
2822 struct di_prom_prop *next; /* form a linked list */
2825 struct di_prom_handle { /* handle to prom */
2826 mutex_t lock; /* synchronize access to openprom fd */
2827 int fd; /* /dev/openprom file descriptor */
2828 struct di_prom_prop *list; /* linked list of prop */
2829 union {
2830 char buf[OPROMMAXPARAM];
2831 struct openpromio opp;
2832 } oppbuf;
2835 di_prom_handle_t
2836 di_prom_init()
2838 struct di_prom_handle *p;
2840 if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
2841 return (DI_PROM_HANDLE_NIL);
2843 DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
2845 (void) mutex_init(&p->lock, USYNC_THREAD, NULL);
2846 if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
2847 free(p);
2848 return (DI_PROM_HANDLE_NIL);
2850 p->list = NULL;
2852 return ((di_prom_handle_t)p);
2855 static void
2856 di_prom_prop_free(struct di_prom_prop *list)
2858 struct di_prom_prop *tmp = list;
2860 while (tmp != NULL) {
2861 list = tmp->next;
2862 if (tmp->name != NULL) {
2863 free(tmp->name);
2865 if (tmp->data != NULL) {
2866 free(tmp->data);
2868 free(tmp);
2869 tmp = list;
2873 void
2874 di_prom_fini(di_prom_handle_t ph)
2876 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2878 DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
2880 (void) close(p->fd);
2881 (void) mutex_destroy(&p->lock);
2882 di_prom_prop_free(p->list);
2884 free(p);
2888 * Internal library interface for locating the property
2889 * XXX: ph->lock must be held for the duration of call.
2891 static di_prom_prop_t
2892 di_prom_prop_found(di_prom_handle_t ph, int nodeid,
2893 di_prom_prop_t prom_prop)
2895 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2896 struct openpromio *opp = &p->oppbuf.opp;
2897 int *ip = (int *)((void *)opp->oprom_array);
2898 struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
2900 DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
2903 * Set "current" nodeid in the openprom driver
2905 opp->oprom_size = sizeof (int);
2906 *ip = nodeid;
2907 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
2908 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
2909 return (DI_PROM_PROP_NIL);
2912 DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
2914 bzero(opp, OBP_MAXBUF);
2915 opp->oprom_size = OBP_MAXPROPNAME;
2916 if (prom_prop != DI_PROM_PROP_NIL)
2917 (void) strcpy(opp->oprom_array, prop->name);
2919 if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
2920 return (DI_PROM_PROP_NIL);
2923 * Prom property found. Allocate struct for storing prop
2924 * (reuse variable prop)
2926 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
2927 return (DI_PROM_PROP_NIL);
2930 * Get a copy of property name
2932 if ((prop->name = strdup(opp->oprom_array)) == NULL) {
2933 free(prop);
2934 return (DI_PROM_PROP_NIL);
2938 * get property value and length
2940 opp->oprom_size = OBP_MAXPROPLEN;
2942 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
2943 (opp->oprom_size == (uint_t)-1)) {
2944 free(prop->name);
2945 free(prop);
2946 return (DI_PROM_PROP_NIL);
2950 * make a copy of the property value
2952 prop->len = opp->oprom_size;
2954 if (prop->len == 0)
2955 prop->data = NULL;
2956 else if ((prop->data = malloc(prop->len)) == NULL) {
2957 free(prop->name);
2958 free(prop);
2959 return (DI_PROM_PROP_NIL);
2962 bcopy(opp->oprom_array, prop->data, prop->len);
2965 * Prepend prop to list in prom handle
2967 prop->next = p->list;
2968 p->list = prop;
2970 return ((di_prom_prop_t)prop);
2973 di_prom_prop_t
2974 di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
2976 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2978 DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
2979 node, p));
2982 * paranoid check
2984 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
2985 errno = EINVAL;
2986 return (DI_PROM_PROP_NIL);
2989 if (di_nodeid(node) != DI_PROM_NODEID) {
2990 errno = ENXIO;
2991 return (DI_PROM_PROP_NIL);
2995 * synchronize access to prom file descriptor
2997 (void) mutex_lock(&p->lock);
3000 * look for next property
3002 prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
3004 (void) mutex_unlock(&p->lock);
3006 return (prom_prop);
3009 char *
3010 di_prom_prop_name(di_prom_prop_t prom_prop)
3013 * paranoid check
3015 if (prom_prop == DI_PROM_PROP_NIL) {
3016 errno = EINVAL;
3017 return (NULL);
3020 return (((struct di_prom_prop *)prom_prop)->name);
3024 di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
3027 * paranoid check
3029 if (prom_prop == DI_PROM_PROP_NIL) {
3030 errno = EINVAL;
3031 return (0);
3034 *prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
3036 return (((struct di_prom_prop *)prom_prop)->len);
3040 * Internal library interface for locating the property
3041 * Returns length if found, -1 if prop doesn't exist.
3043 static struct di_prom_prop *
3044 di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
3045 const char *prom_prop_name)
3047 struct openpromio *opp;
3048 struct di_prom_prop *prop;
3049 struct di_prom_handle *p = (struct di_prom_handle *)ph;
3052 * paranoid check
3054 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
3055 errno = EINVAL;
3056 return (NULL);
3059 if (di_nodeid(node) != DI_PROM_NODEID) {
3060 errno = ENXIO;
3061 return (NULL);
3064 opp = &p->oppbuf.opp;
3066 (void) mutex_lock(&p->lock);
3068 opp->oprom_size = sizeof (int);
3069 opp->oprom_node = DI_NODE(node)->nodeid;
3070 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
3071 errno = ENXIO;
3072 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
3073 DI_NODE(node)->nodeid));
3074 (void) mutex_unlock(&p->lock);
3075 return (NULL);
3079 * get property length
3081 bzero(opp, OBP_MAXBUF);
3082 opp->oprom_size = OBP_MAXPROPLEN;
3083 (void) strcpy(opp->oprom_array, prom_prop_name);
3085 if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
3086 (opp->oprom_len == -1)) {
3087 /* no such property */
3088 (void) mutex_unlock(&p->lock);
3089 return (NULL);
3093 * Prom property found. Allocate struct for storing prop
3095 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
3096 (void) mutex_unlock(&p->lock);
3097 return (NULL);
3099 prop->name = NULL; /* we don't need the name */
3100 prop->len = opp->oprom_len;
3102 if (prop->len == 0) { /* boolean property */
3103 prop->data = NULL;
3104 prop->next = p->list;
3105 p->list = prop;
3106 (void) mutex_unlock(&p->lock);
3107 return (prop);
3111 * retrieve the property value
3113 bzero(opp, OBP_MAXBUF);
3114 opp->oprom_size = OBP_MAXPROPLEN;
3115 (void) strcpy(opp->oprom_array, prom_prop_name);
3117 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
3118 (opp->oprom_size == (uint_t)-1)) {
3119 /* error retrieving property value */
3120 (void) mutex_unlock(&p->lock);
3121 free(prop);
3122 return (NULL);
3126 * make a copy of the property value, stick in ph->list
3128 if ((prop->data = malloc(prop->len)) == NULL) {
3129 (void) mutex_unlock(&p->lock);
3130 free(prop);
3131 return (NULL);
3134 bcopy(opp->oprom_array, prop->data, prop->len);
3136 prop->next = p->list;
3137 p->list = prop;
3138 (void) mutex_unlock(&p->lock);
3140 return (prop);
3144 di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
3145 const char *prom_prop_name, int **prom_prop_data)
3147 int len;
3148 struct di_prom_prop *prop;
3150 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3152 if (prop == NULL) {
3153 *prom_prop_data = NULL;
3154 return (-1);
3157 if (prop->len == 0) { /* boolean property */
3158 *prom_prop_data = NULL;
3159 return (0);
3162 len = di_prop_decode_common((void *)&prop->data, prop->len,
3163 DI_PROP_TYPE_INT, 1);
3164 *prom_prop_data = (int *)((void *)prop->data);
3166 return (len);
3170 di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
3171 const char *prom_prop_name, char **prom_prop_data)
3173 int len;
3174 struct di_prom_prop *prop;
3176 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3178 if (prop == NULL) {
3179 *prom_prop_data = NULL;
3180 return (-1);
3183 if (prop->len == 0) { /* boolean property */
3184 *prom_prop_data = NULL;
3185 return (0);
3189 * Fix an openprom bug (OBP string not NULL terminated).
3190 * XXX This should really be fixed in promif.
3192 if (((char *)prop->data)[prop->len - 1] != '\0') {
3193 uchar_t *tmp;
3194 prop->len++;
3195 if ((tmp = realloc(prop->data, prop->len)) == NULL)
3196 return (-1);
3198 prop->data = tmp;
3199 ((char *)prop->data)[prop->len - 1] = '\0';
3200 DPRINTF((DI_INFO, "OBP string not NULL terminated: "
3201 "node=%s, prop=%s, val=%s\n",
3202 di_node_name(node), prom_prop_name, prop->data));
3205 len = di_prop_decode_common((void *)&prop->data, prop->len,
3206 DI_PROP_TYPE_STRING, 1);
3207 *prom_prop_data = (char *)prop->data;
3209 return (len);
3213 di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
3214 const char *prom_prop_name, uchar_t **prom_prop_data)
3216 int len;
3217 struct di_prom_prop *prop;
3219 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3221 if (prop == NULL) {
3222 *prom_prop_data = NULL;
3223 return (-1);
3226 if (prop->len == 0) { /* boolean property */
3227 *prom_prop_data = NULL;
3228 return (0);
3231 len = di_prop_decode_common((void *)&prop->data, prop->len,
3232 DI_PROP_TYPE_BYTE, 1);
3233 *prom_prop_data = prop->data;
3235 return (len);
3239 * returns an allocated array through <prop_data> only when its count > 0
3240 * and the number of entries (count) as the function return value;
3241 * use di_slot_names_free() to free the array
3244 di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
3246 int rawlen, count;
3247 uchar_t *rawdata;
3248 char *nm = di_prop_name(prop);
3250 if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
3251 goto ERROUT;
3253 rawlen = di_prop_rawdata(prop, &rawdata);
3254 if (rawlen <= 0 || rawdata == NULL)
3255 goto ERROUT;
3257 count = di_slot_names_decode(rawdata, rawlen, prop_data);
3258 if (count < 0 || *prop_data == NULL)
3259 goto ERROUT;
3261 return (count);
3262 /*NOTREACHED*/
3263 ERROUT:
3264 errno = EFAULT;
3265 *prop_data = NULL;
3266 return (-1);
3270 di_prop_lookup_slot_names(dev_t dev, di_node_t node,
3271 di_slot_name_t **prop_data)
3273 di_prop_t prop;
3276 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
3277 * and slot-names is properly flagged as such
3279 if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
3280 DI_PROP_NIL) {
3281 *prop_data = NULL;
3282 return (-1);
3285 return (di_prop_slot_names(prop, (void *)prop_data));
3289 * returns an allocated array through <prop_data> only when its count > 0
3290 * and the number of entries (count) as the function return value;
3291 * use di_slot_names_free() to free the array
3294 di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
3296 int rawlen, count;
3297 uchar_t *rawdata;
3299 rawlen = di_prom_prop_data(prom_prop, &rawdata);
3300 if (rawlen <= 0 || rawdata == NULL)
3301 goto ERROUT;
3303 count = di_slot_names_decode(rawdata, rawlen, prop_data);
3304 if (count < 0 || *prop_data == NULL)
3305 goto ERROUT;
3307 return (count);
3308 /*NOTREACHED*/
3309 ERROUT:
3310 errno = EFAULT;
3311 *prop_data = NULL;
3312 return (-1);
3316 di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
3317 di_slot_name_t **prop_data)
3319 struct di_prom_prop *prom_prop;
3321 prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
3322 if (prom_prop == NULL) {
3323 *prop_data = NULL;
3324 return (-1);
3327 return (di_prom_prop_slot_names(prom_prop, prop_data));
3330 di_lnode_t
3331 di_link_to_lnode(di_link_t link, uint_t endpoint)
3333 struct di_all *di_all;
3335 if ((link == DI_LINK_NIL) ||
3336 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3337 errno = EINVAL;
3338 return (DI_LNODE_NIL);
3341 di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
3343 if (endpoint == DI_LINK_SRC) {
3344 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
3345 } else {
3346 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
3348 /* NOTREACHED */
3351 char *
3352 di_lnode_name(di_lnode_t lnode)
3354 return (di_driver_name(di_lnode_devinfo(lnode)));
3357 di_node_t
3358 di_lnode_devinfo(di_lnode_t lnode)
3360 struct di_all *di_all;
3362 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3363 return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
3367 di_lnode_devt(di_lnode_t lnode, dev_t *devt)
3369 if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
3370 errno = EINVAL;
3371 return (-1);
3373 if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
3374 (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
3375 return (-1);
3377 *devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
3378 return (0);
3382 di_link_spectype(di_link_t link)
3384 return (DI_LINK(link)->spec_type);
3387 void
3388 di_minor_private_set(di_minor_t minor, void *data)
3390 DI_MINOR(minor)->user_private_data = (uintptr_t)data;
3393 void *
3394 di_minor_private_get(di_minor_t minor)
3396 return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
3399 void
3400 di_node_private_set(di_node_t node, void *data)
3402 DI_NODE(node)->user_private_data = (uintptr_t)data;
3405 void *
3406 di_node_private_get(di_node_t node)
3408 return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
3411 void
3412 di_path_private_set(di_path_t path, void *data)
3414 DI_PATH(path)->user_private_data = (uintptr_t)data;
3417 void *
3418 di_path_private_get(di_path_t path)
3420 return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
3423 void
3424 di_lnode_private_set(di_lnode_t lnode, void *data)
3426 DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
3429 void *
3430 di_lnode_private_get(di_lnode_t lnode)
3432 return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
3435 void
3436 di_link_private_set(di_link_t link, void *data)
3438 DI_LINK(link)->user_private_data = (uintptr_t)data;
3441 void *
3442 di_link_private_get(di_link_t link)
3444 return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
3447 di_lnode_t
3448 di_lnode_next(di_node_t node, di_lnode_t lnode)
3450 struct di_all *di_all;
3453 * paranoid error checking
3455 if (node == DI_NODE_NIL) {
3456 errno = EINVAL;
3457 return (DI_LNODE_NIL);
3460 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3462 if (lnode == DI_NODE_NIL) {
3463 if (DI_NODE(node)->lnodes != 0)
3464 return (DI_LNODE((caddr_t)di_all +
3465 DI_NODE(node)->lnodes));
3466 } else {
3467 if (DI_LNODE(lnode)->node_next != 0)
3468 return (DI_LNODE((caddr_t)di_all +
3469 DI_LNODE(lnode)->node_next));
3472 if (DINFOLYR & DI_ALL(di_all)->command)
3473 errno = ENXIO;
3474 else
3475 errno = ENOTSUP;
3477 return (DI_LNODE_NIL);
3480 di_link_t
3481 di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
3483 struct di_all *di_all;
3486 * paranoid error checking
3488 if ((node == DI_NODE_NIL) ||
3489 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3490 errno = EINVAL;
3491 return (DI_LINK_NIL);
3494 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3496 if (endpoint == DI_LINK_SRC) {
3497 if (link == DI_LINK_NIL) {
3498 if (DI_NODE(node)->src_links != 0)
3499 return (DI_LINK((caddr_t)di_all +
3500 DI_NODE(node)->src_links));
3501 } else {
3502 if (DI_LINK(link)->src_node_next != 0)
3503 return (DI_LINK((caddr_t)di_all +
3504 DI_LINK(link)->src_node_next));
3506 } else {
3507 if (link == DI_LINK_NIL) {
3508 if (DI_NODE(node)->tgt_links != 0)
3509 return (DI_LINK((caddr_t)di_all +
3510 DI_NODE(node)->tgt_links));
3511 } else {
3512 if (DI_LINK(link)->tgt_node_next != 0)
3513 return (DI_LINK((caddr_t)di_all +
3514 DI_LINK(link)->tgt_node_next));
3518 if (DINFOLYR & DI_ALL(di_all)->command)
3519 errno = ENXIO;
3520 else
3521 errno = ENOTSUP;
3523 return (DI_LINK_NIL);
3526 di_link_t
3527 di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
3529 struct di_all *di_all;
3532 * paranoid error checking
3534 if ((lnode == DI_LNODE_NIL) ||
3535 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3536 errno = EINVAL;
3537 return (DI_LINK_NIL);
3540 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3542 if (endpoint == DI_LINK_SRC) {
3543 if (link == DI_LINK_NIL) {
3544 if (DI_LNODE(lnode)->link_out == 0)
3545 return (DI_LINK_NIL);
3546 return (DI_LINK((caddr_t)di_all +
3547 DI_LNODE(lnode)->link_out));
3548 } else {
3549 if (DI_LINK(link)->src_link_next == 0)
3550 return (DI_LINK_NIL);
3551 return (DI_LINK((caddr_t)di_all +
3552 DI_LINK(link)->src_link_next));
3554 } else {
3555 if (link == DI_LINK_NIL) {
3556 if (DI_LNODE(lnode)->link_in == 0)
3557 return (DI_LINK_NIL);
3558 return (DI_LINK((caddr_t)di_all +
3559 DI_LNODE(lnode)->link_in));
3560 } else {
3561 if (DI_LINK(link)->tgt_link_next == 0)
3562 return (DI_LINK_NIL);
3563 return (DI_LINK((caddr_t)di_all +
3564 DI_LINK(link)->tgt_link_next));
3567 /* NOTREACHED */
3571 * Internal library function:
3572 * Invoke callback for each link data on the link list of first node
3573 * on node_list headp, and place children of first node on the list.
3575 * This is similar to walk_one_node, except we only walk in child
3576 * first mode.
3578 static void
3579 walk_one_link(struct node_list **headp, uint_t ep,
3580 void *arg, int (*callback)(di_link_t link, void *arg))
3582 int action = DI_WALK_CONTINUE;
3583 di_link_t link = DI_LINK_NIL;
3584 di_node_t node = (*headp)->node;
3586 while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
3587 action = callback(link, arg);
3588 if (action == DI_WALK_TERMINATE) {
3589 break;
3593 update_node_list(action, DI_WALK_LINKGEN, headp);
3597 di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
3598 int (*link_callback)(di_link_t link, void *arg))
3600 struct node_list *head; /* node_list for tree walk */
3602 #ifdef DEBUG
3603 char *devfspath = di_devfs_path(root);
3604 DPRINTF((DI_INFO, "walking %s link data under %s\n",
3605 (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
3606 di_devfs_path_free(devfspath);
3607 #endif
3610 * paranoid error checking
3612 if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
3613 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3614 errno = EINVAL;
3615 return (-1);
3618 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3619 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3620 return (-1);
3623 head->next = NULL;
3624 head->node = root;
3626 DPRINTF((DI_INFO, "Start link data walking from node %s\n",
3627 di_node_name(root)));
3629 while (head != NULL)
3630 walk_one_link(&head, endpoint, arg, link_callback);
3632 return (0);
3636 * Internal library function:
3637 * Invoke callback for each link data on the link list of first node
3638 * on node_list headp, and place children of first node on the list.
3640 * This is similar to walk_one_node, except we only walk in child
3641 * first mode.
3643 static void
3644 walk_one_lnode(struct node_list **headp, void *arg,
3645 int (*callback)(di_lnode_t lnode, void *arg))
3647 int action = DI_WALK_CONTINUE;
3648 di_lnode_t lnode = DI_LNODE_NIL;
3649 di_node_t node = (*headp)->node;
3651 while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
3652 action = callback(lnode, arg);
3653 if (action == DI_WALK_TERMINATE) {
3654 break;
3658 update_node_list(action, DI_WALK_LINKGEN, headp);
3662 di_walk_lnode(di_node_t root, uint_t flag, void *arg,
3663 int (*lnode_callback)(di_lnode_t lnode, void *arg))
3665 struct node_list *head; /* node_list for tree walk */
3667 #ifdef DEBUG
3668 char *devfspath = di_devfs_path(root);
3669 DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
3670 di_devfs_path_free(devfspath);
3671 #endif
3674 * paranoid error checking
3676 if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
3677 errno = EINVAL;
3678 return (-1);
3681 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3682 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3683 return (-1);
3686 head->next = NULL;
3687 head->node = root;
3689 DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
3690 di_node_name(root)));
3692 while (head != NULL)
3693 walk_one_lnode(&head, arg, lnode_callback);
3695 return (0);
3698 static char *
3699 alias_to_curr(di_node_t anynode, char *devfspath, di_node_t *nodep)
3701 caddr_t pa;
3702 struct di_all *all;
3703 struct di_alias *di_alias;
3704 di_node_t node;
3705 char *curr;
3706 char *cp;
3707 char *alias;
3708 di_off_t off;
3709 char buf[MAXPATHLEN];
3711 *nodep = NULL;
3713 if (anynode == DI_NODE_NIL || devfspath == NULL)
3714 return (NULL);
3716 pa = (caddr_t)anynode - DI_NODE(anynode)->self;
3717 all = DI_ALL(pa);
3719 di_alias = NULL;
3720 for (off = all->aliases; off > 0; off = di_alias->next) {
3721 di_alias = DI_ALIAS(pa + off);
3722 alias = di_alias->alias;
3723 if (strncmp(devfspath, alias, strlen(alias)) == 0) {
3724 cp = devfspath + strlen(alias);
3725 node = DI_NODE(pa + di_alias->curroff);
3726 assert(node != DI_NODE_NIL);
3727 if (*cp == '\0') {
3728 *nodep = node;
3729 return (NULL);
3730 } else if (*cp == '/') {
3731 curr = di_devfs_path(node);
3732 (void) snprintf(buf, sizeof (buf), "%s%s",
3733 curr, cp);
3734 di_devfs_path_free(curr);
3735 curr = strdup(buf);
3736 return (curr);
3741 return (NULL);
3744 static di_node_t
3745 di_lookup_node_impl(di_node_t root, char *devfspath)
3747 struct di_all *dap;
3748 di_node_t node;
3749 char *copy, *slash, *pname, *paddr;
3752 * Path must be absolute and musn't have duplicate slashes
3754 if (*devfspath != '/' || strstr(devfspath, "//")) {
3755 DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
3756 return (DI_NODE_NIL);
3759 if (root == DI_NODE_NIL) {
3760 DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
3761 return (DI_NODE_NIL);
3764 dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
3765 if (strcmp(dap->root_path, "/") != 0) {
3766 DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
3767 return (DI_NODE_NIL);
3770 if ((copy = strdup(devfspath)) == NULL) {
3771 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3772 return (DI_NODE_NIL);
3775 for (slash = copy, node = root; slash; ) {
3778 * Handle devfspath = "/" case as well as trailing '/'
3780 if (*(slash + 1) == '\0')
3781 break;
3784 * More path-components exist. Deal with the next one
3786 pname = slash + 1;
3787 node = di_child_node(node);
3789 if (slash = strchr(pname, '/'))
3790 *slash = '\0';
3791 if (paddr = strchr(pname, '@'))
3792 *paddr++ = '\0';
3794 for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
3795 char *name, *baddr;
3797 name = di_node_name(node);
3798 baddr = di_bus_addr(node);
3800 if (strcmp(pname, name) != 0)
3801 continue;
3804 * Mappings between a "path-address" and bus-addr
3806 * paddr baddr
3807 * ---------------------
3808 * NULL NULL
3809 * NULL ""
3810 * "" N/A (invalid paddr)
3812 if (paddr && baddr && strcmp(paddr, baddr) == 0)
3813 break;
3814 if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
3815 break;
3819 * No nodes in the sibling list or there was no match
3821 if (node == DI_NODE_NIL) {
3822 DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
3823 free(copy);
3824 return (DI_NODE_NIL);
3828 assert(node != DI_NODE_NIL);
3829 free(copy);
3830 return (node);
3833 di_node_t
3834 di_lookup_node(di_node_t root, char *devfspath)
3836 di_node_t node;
3837 char *curr;
3839 node = di_lookup_node_impl(root, devfspath);
3840 if (node != DI_NODE_NIL) {
3841 return (node);
3844 /* node is already set to DI_NODE_NIL */
3845 curr = alias_to_curr(root, devfspath, &node);
3846 if (curr == NULL) {
3847 /* node may or may node be DI_NODE_NIL */
3848 return (node);
3851 node = di_lookup_node_impl(root, curr);
3853 free(curr);
3855 return (node);
3858 char *
3859 di_alias2curr(di_node_t anynode, char *alias)
3861 di_node_t currnode = DI_NODE_NIL;
3862 char *curr;
3864 if (anynode == DI_NODE_NIL || alias == NULL)
3865 return (NULL);
3867 curr = alias_to_curr(anynode, alias, &currnode);
3868 if (curr == NULL && currnode != DI_NODE_NIL) {
3869 return (di_devfs_path(currnode));
3870 } else if (curr == NULL) {
3871 return (strdup(alias));
3874 return (curr);
3877 di_path_t
3878 di_lookup_path(di_node_t root, char *devfspath)
3880 di_node_t phci_node;
3881 di_path_t path = DI_PATH_NIL;
3882 char *copy, *lastslash;
3883 char *pname, *paddr;
3884 char *path_name, *path_addr;
3886 if ((copy = strdup(devfspath)) == NULL) {
3887 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3888 return (DI_NODE_NIL);
3891 if ((lastslash = strrchr(copy, '/')) == NULL) {
3892 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3893 goto out;
3896 /* stop at pHCI and find the node for the phci */
3897 *lastslash = '\0';
3898 phci_node = di_lookup_node(root, copy);
3899 if (phci_node == NULL) {
3900 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3901 goto out;
3904 /* set up pname and paddr for last component */
3905 pname = lastslash + 1;
3906 if ((paddr = strchr(pname, '@')) == NULL) {
3907 DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
3908 goto out;
3910 *paddr++ = '\0';
3912 /* walk paths below phci looking for match */
3913 for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
3914 path != DI_PATH_NIL;
3915 path = di_path_phci_next_path(phci_node, path)) {
3917 /* get name@addr of path */
3918 path_name = di_path_node_name(path);
3919 path_addr = di_path_bus_addr(path);
3920 if ((path_name == NULL) || (path_addr == NULL))
3921 continue;
3923 /* break on match */
3924 if ((strcmp(pname, path_name) == 0) &&
3925 (strcmp(paddr, path_addr) == 0))
3926 break;
3929 out: free(copy);
3930 return (path);
3933 static char *
3934 msglevel2str(di_debug_t msglevel)
3936 switch (msglevel) {
3937 case DI_ERR:
3938 return ("ERROR");
3939 case DI_INFO:
3940 return ("Info");
3941 case DI_TRACE:
3942 return ("Trace");
3943 case DI_TRACE1:
3944 return ("Trace1");
3945 case DI_TRACE2:
3946 return ("Trace2");
3947 default:
3948 return ("UNKNOWN");
3952 void
3953 dprint(di_debug_t msglevel, const char *fmt, ...)
3955 va_list ap;
3956 char *estr;
3958 if (di_debug <= DI_QUIET)
3959 return;
3961 if (di_debug < msglevel)
3962 return;
3964 estr = msglevel2str(msglevel);
3966 assert(estr);
3968 va_start(ap, fmt);
3970 (void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
3971 (ulong_t)getpid(), estr);
3972 (void) vfprintf(stderr, fmt, ap);
3974 va_end(ap);
3977 /* end of devinfo.c */