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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Interfaces for getting device configuration data from kernel
30 * through the devinfo driver.
42 #include <sys/mkdev.h>
43 #include <sys/obpdefs.h>
45 #include <sys/types.h>
47 #include <sys/autoconf.h>
53 #include "libdevinfo.h"
56 * Debug message levels
59 DI_QUIET
= 0, /* No debug messages - the default */
67 int di_debug
= DI_QUIET
;
69 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; }
71 void dprint(di_debug_t msglevel
, const char *fmt
, ...);
74 #pragma init(_libdevinfo_init)
79 char *debug_str
= getenv("_LIBDEVINFO_DEBUG");
83 di_debug
= atoi(debug_str
);
84 if (errno
|| di_debug
< DI_QUIET
)
90 di_init(const char *phys_path
, uint_t flag
)
92 return (di_init_impl(phys_path
, flag
, NULL
));
96 * We use blocking_open() to guarantee access to the devinfo device, if open()
97 * is failing with EAGAIN.
100 blocking_open(const char *path
, int oflag
)
104 while ((fd
= open(path
, oflag
)) == -1 && errno
== EAGAIN
)
105 (void) poll(NULL
, 0, 1 * MILLISEC
);
110 /* private interface */
112 di_init_driver(const char *drv_name
, uint_t flag
)
115 char driver
[MAXPATHLEN
];
118 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
119 * which should be sufficient for any sensible programmer.
121 if ((drv_name
== NULL
) || (strlen(drv_name
) >= MAXPATHLEN
)) {
123 return (DI_NODE_NIL
);
125 (void) strcpy(driver
, drv_name
);
128 * open the devinfo driver
130 if ((fd
= blocking_open("/devices/pseudo/devinfo@0:devinfo",
132 DPRINTF((DI_ERR
, "devinfo open failed: errno = %d\n", errno
));
133 return (DI_NODE_NIL
);
136 if (ioctl(fd
, DINFOLODRV
, driver
) != 0) {
137 DPRINTF((DI_ERR
, "failed to load driver %s\n", driver
));
140 return (DI_NODE_NIL
);
145 * Driver load succeeded, return a snapshot
147 return (di_init("/", flag
));
151 di_init_impl(const char *phys_path
, uint_t flag
,
152 struct di_priv_data
*priv
)
157 struct dinfo_io dinfo_io
;
159 uint_t pageoffset
= sysconf(_SC_PAGESIZE
) - 1;
160 uint_t pagemask
= ~pageoffset
;
162 DPRINTF((DI_INFO
, "di_init: taking a snapshot\n"));
165 * Make sure there is no minor name in the path
166 * and the path do not start with /devices....
168 if (strchr(phys_path
, ':') ||
169 (strncmp(phys_path
, "/devices", 8) == 0) ||
170 (strlen(phys_path
) > MAXPATHLEN
)) {
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
),
181 (void) snprintf(dinfo_io
.root_path
, sizeof (dinfo_io
.root_path
),
185 * If private data is requested, copy the format specification
187 if (flag
& DINFOPRIVDATA
& 0xff) {
189 bcopy(priv
, &dinfo_io
.priv
,
190 sizeof (struct di_priv_data
));
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,
204 if ((fd
= blocking_open("/devices/pseudo/devinfo@0:devinfo",
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
214 DPRINTF((DI_ERR
, "devinfo open failed: errno = %d\n",
216 return (DI_NODE_NIL
);
219 if ((fd
= blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
221 DPRINTF((DI_ERR
, "devinfo open failed: errno = %d\n",
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
) {
233 "driver ID failed; check for major conflict\n"));
235 return (DI_NODE_NIL
);
241 if ((map_size
= ioctl(fd
, flag
, &dinfo_io
)) < 0) {
242 DPRINTF((DI_ERR
, "devinfo ioctl failed with "
243 "error: %d\n", errno
));
245 return (DI_NODE_NIL
);
246 } else if (map_size
== 0) {
247 DPRINTF((DI_ERR
, "%s not found\n", phys_path
));
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"));
260 return (DI_NODE_NIL
);
263 if (ioctl(fd
, DINFOUSRLD
, pa
) != map_size
) {
264 DPRINTF((DI_ERR
, "failed to copy snapshot to usrld\n"));
268 return (DI_NODE_NIL
);
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
));
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
));
286 return (DI_NODE_NIL
);
289 return (DI_NODE(pa
+ dap
->top_devinfo
));
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"));
302 if (root
== DI_NODE_NIL
) {
303 DPRINTF((DI_ERR
, "di_fini called with NIL arg\n"));
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
;
319 di_parent_node(di_node_t node
)
321 caddr_t pa
; /* starting address of map */
323 if (node
== DI_NODE_NIL
) {
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)
346 return (DI_NODE_NIL
);
350 di_sibling_node(di_node_t node
)
352 caddr_t pa
; /* starting address of map */
354 if (node
== DI_NODE_NIL
) {
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
373 if (!(DI_ALL(pa
)->command
& DINFOSUBTREE
))
378 return (DI_NODE_NIL
);
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
) {
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
))
409 return (DI_NODE_NIL
);
413 di_drv_first_node(const char *drv_name
, di_node_t root
)
415 caddr_t pa
; /* starting address of map */
417 struct di_devnm
*devnm
;
419 DPRINTF((DI_INFO
, "Get first node of driver %s\n", drv_name
));
421 if (root
== DI_NODE_NIL
) {
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))
438 if (major
>= devcnt
) {
440 return (DI_NODE_NIL
);
443 if (!(devnm
[major
].head
)) {
445 return (DI_NODE_NIL
);
448 return (DI_NODE(pa
+ devnm
[major
].head
));
452 di_drv_next_node(di_node_t node
)
454 caddr_t pa
; /* starting address of map */
456 if (node
== DI_NODE_NIL
) {
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) {
467 return (DI_NODE_NIL
);
470 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
472 if (DI_NODE(node
)->next
== NULL
) {
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
485 struct node_list
*next
;
490 free_node_list(struct node_list
**headp
)
492 struct node_list
*tmp
;
496 *headp
= (*headp
)->next
;
502 append_node_list(struct node_list
**headp
, struct node_list
*list
)
504 struct node_list
*tmp
;
506 if (*headp
== NULL
) {
511 if (list
== NULL
) /* a minor optimization */
522 prepend_node_list(struct node_list
**headp
, struct node_list
*list
)
524 struct node_list
*tmp
;
532 if (tmp
== NULL
) /* a minor optimization */
542 * returns 1 if node is a descendant of parent, 0 otherwise
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
) {
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.
567 insert_node_list(struct node_list
**headp
, struct node_list
*list
,
570 struct node_list
*tmp
, *tmp1
;
576 if (tmp
== NULL
) { /* a minor optimization */
581 if (!is_descendant(tmp
->node
, parent
)) {
582 prepend_node_list(headp
, list
);
587 * Find first node which is not a descendant
589 while (tmp
->next
&& is_descendant(tmp
->next
->node
, parent
)) {
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
)
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
) {
613 if ((result
= malloc(sizeof (struct node_list
))) == NULL
) {
614 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
618 result
->node
= child
;
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
);
637 * Internal library interface:
638 * Delete all siblings of the first node from the node_list, along with
639 * the first node itself.
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
655 * XXX Put a check here just in case.
658 DPRINTF((DI_ERR
, "Unexpected err in di_walk_node.\n"));
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.
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
;
692 * delete the first node
700 * Internal library function:
701 * Update node list based on action (return code from callback)
702 * and flag specifying walking behavior.
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
);
711 case DI_WALK_TERMINATE
:
713 * free the node list and be done
716 free_node_list(headp
);
719 case DI_WALK_PRUNESIB
:
721 * Get list of children and prune siblings
723 children
= get_children((*headp
)->node
);
727 case DI_WALK_PRUNECHILD
:
729 * Set children to NULL and pop first node
737 case DI_WALK_CONTINUE
:
740 * Get list of children and pop first node
742 children
= get_children((*headp
)->node
);
750 * insert the list of children
753 case DI_WALK_CLDFIRST
:
754 prepend_node_list(headp
, children
);
757 case DI_WALK_SIBFIRST
:
758 append_node_list(headp
, children
);
761 case DI_WALK_LINKGEN
:
763 insert_node_list(headp
, children
, parent
);
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.
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 */
794 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
795 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
802 DPRINTF((DI_INFO
, "Start node walking from node %s\n",
803 di_node_name(root
)));
806 walk_one_node(&head
, flag
, arg
, node_callback
);
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
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 *))
824 int action
= DI_WALK_CONTINUE
;
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
))
835 if ((ddm_type
== DDM_INTERNAL_PATH
) &&
836 !(flag
& DI_CHECK_INTERNAL_PATH
))
839 node_type
= di_minor_nodetype(minor
);
840 if ((desired_type
!= NULL
) && ((node_type
== NULL
) ||
841 strncmp(desired_type
, node_type
, strlen(desired_type
))
845 if ((action
= callback(node
, minor
, arg
)) ==
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 */
861 char *devfspath
= di_devfs_path(root
);
862 DPRINTF((DI_INFO
, "walking minor nodes under %s\n", devfspath
));
863 di_devfs_path_free(devfspath
);
871 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
872 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
879 DPRINTF((DI_INFO
, "Start minor walking from node %s\n",
880 di_node_name(root
)));
883 walk_one_minor_list(&head
, minor_type
, flag
, arg
,
890 * generic node parameters
891 * Calling these routines always succeeds.
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 */
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)
908 return ((char *)(pa
+ DI_NODE(node
)->address
));
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)
919 return ((char *)(pa
+ DI_NODE(node
)->bind_name
));
923 di_compatible_names(di_node_t node
, char **names
)
926 int len
, size
, entries
= 0;
928 if (DI_NODE(node
)->compat_names
== 0) {
933 *names
= (caddr_t
)node
+
934 DI_NODE(node
)->compat_names
- DI_NODE(node
)->self
;
937 len
= DI_NODE(node
)->compat_length
;
940 size
= strlen(c
) + 1;
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
);
971 di_state(di_node_t node
)
975 if (di_node_state(node
) < DS_ATTACHED
)
976 result
|= DI_DRIVER_DETACHED
;
977 if (DI_NODE(node
)->state
& DEVI_DEVICE_OFFLINE
)
978 result
|= DI_DEVICE_OFFLINE
;
979 if (DI_NODE(node
)->state
& DEVI_DEVICE_DOWN
)
980 result
|= DI_DEVICE_OFFLINE
;
981 if (DI_NODE(node
)->state
& DEVI_DEVICE_DEGRADED
)
982 result
|= DI_DEVICE_DEGRADED
;
983 if (DI_NODE(node
)->state
& DEVI_BUS_QUIESCED
)
984 result
|= DI_BUS_QUIESCED
;
985 if (DI_NODE(node
)->state
& DEVI_BUS_DOWN
)
986 result
|= DI_BUS_DOWN
;
992 di_node_state(di_node_t node
)
994 return (DI_NODE(node
)->node_state
);
998 di_flags(di_node_t node
)
1000 return (DI_NODE(node
)->flags
);
1004 di_retired(di_node_t node
)
1006 return (di_flags(node
) & DEVI_RETIRED
);
1010 di_devid(di_node_t node
)
1012 if (DI_NODE(node
)->devid
== 0)
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
)
1024 major
= DI_NODE(node
)->drv_major
;
1031 di_driver_name(di_node_t node
)
1035 struct di_devnm
*devnm
;
1037 major
= DI_NODE(node
)->drv_major
;
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
);
1051 di_driver_ops(di_node_t node
)
1055 struct di_devnm
*devnm
;
1057 major
= DI_NODE(node
)->drv_major
;
1061 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1062 devnm
= DI_DEVNM(pa
+ DI_ALL(pa
)->devnames
);
1064 return (devnm
[major
].ops
);
1068 * returns the length of the path, caller must free memory
1071 di_devfs_path(di_node_t node
)
1075 int depth
= 0, len
= 0;
1076 char *buf
, *name
[MAX_TREE_DEPTH
], *addr
[MAX_TREE_DEPTH
];
1078 if (node
== DI_NODE_NIL
) {
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 '@' */
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
) {
1111 (void) strcpy(buf
, name
[depth
]);
1113 if (buf
[len
- 1] == '/')
1114 len
--; /* delete trailing '/' */
1119 (void) strcpy(buf
+ len
+ 1, name
[depth
]);
1120 len
+= strlen(name
[depth
]) + 1;
1121 if (addr
[depth
] && addr
[depth
][0] != '\0') {
1123 (void) strcpy(buf
+ len
+ 1, addr
[depth
]);
1124 len
+= strlen(addr
[depth
]) + 1;
1132 di_devfs_minor_path(di_minor_t minor
)
1135 char *full_path
, *name
, *devfspath
;
1138 if (minor
== DI_MINOR_NIL
) {
1143 name
= di_minor_name(minor
);
1144 node
= di_minor_devinfo(minor
);
1145 devfspath
= di_devfs_path(node
);
1146 if (devfspath
== 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",
1156 di_devfs_path_free(devfspath
);
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.
1167 di_path_devfs_path(di_path_t path
)
1169 di_node_t phci_node
;
1170 char *phci_path
, *path_name
, *path_addr
;
1174 if (path
== DI_PATH_NIL
) {
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
))
1185 /* base path to pHCI devinfo node */
1186 phci_node
= di_path_phci_node(path
);
1187 if (phci_node
== NULL
)
1189 phci_path
= di_devfs_path(phci_node
);
1190 if (phci_path
== 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
);
1206 di_path_client_devfs_path(di_path_t path
)
1208 return (di_devfs_path(di_path_client_node(path
)));
1212 di_devfs_path_free(char *buf
)
1215 DPRINTF((DI_ERR
, "di_devfs_path_free NULL arg!\n"));
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
1227 is_generic(const char *name
, int len
)
1231 /* from IEEE-1275 recommended practices section 3 */
1232 static const char *generic_names
[] = {
1243 "interrupt-controller",
1266 for (gp
= generic_names
; *gp
; gp
++) {
1267 if ((strncmp(*gp
, name
, len
) == 0) &&
1268 (strlen(*gp
) == len
))
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
;
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 */
1294 /* advance p1 and p2 to start of 'name' in component */
1296 if ((nc
== '\0') || (nc
== '/'))
1297 continue; /* skip trash */
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
, '/');
1307 ec1
= p1
+ strlen(p1
);
1308 ec2
= strchr(p2
, '/');
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
))
1317 if (at2
&& (at2
< ec2
))
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
);
1330 * one generic and one non-generic
1331 * skip past the names in the match.
1341 return ((*p1
== *p2
) ? 1 : 0);
1344 /* minor data access */
1346 di_minor_next(di_node_t node
, di_minor_t minor
)
1351 * paranoid error checking
1353 if (node
== DI_NODE_NIL
) {
1355 return (DI_MINOR_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
)));
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
)
1389 return (DI_MINOR_NIL
);
1392 /* private interface for dealing with alias minor link generation */
1394 di_minor_devinfo(di_minor_t minor
)
1396 if (minor
== DI_MINOR_NIL
) {
1398 return (DI_NODE_NIL
);
1401 return (DI_NODE((caddr_t
)minor
- DI_MINOR(minor
)->self
+
1402 DI_MINOR(minor
)->node
));
1406 di_minor_type(di_minor_t minor
)
1408 return (DI_MINOR(minor
)->type
);
1412 di_minor_name(di_minor_t minor
)
1414 if (DI_MINOR(minor
)->name
== 0)
1417 return ((caddr_t
)minor
- DI_MINOR(minor
)->self
+ DI_MINOR(minor
)->name
);
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
);
1434 di_minor_nodetype(di_minor_t minor
)
1436 if (DI_MINOR(minor
)->node_type
== 0)
1439 return ((caddr_t
)minor
-
1440 DI_MINOR(minor
)->self
+ DI_MINOR(minor
)->node_type
);
1444 * Single public interface for accessing software properties
1447 di_prop_next(di_node_t node
, di_prop_t prop
)
1449 int list
= DI_PROP_DRV_LIST
;
1454 if (node
== DI_NODE_NIL
) {
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
;
1467 case DI_PROP_DRV_LIST
:
1468 prop
= di_prop_drv_next(node
, prop
);
1470 case DI_PROP_SYS_LIST
:
1471 prop
= di_prop_sys_next(node
, prop
);
1473 case DI_PROP_GLB_LIST
:
1474 prop
= di_prop_global_next(node
, prop
);
1476 case DI_PROP_HW_LIST
:
1477 prop
= di_prop_hw_next(node
, prop
);
1479 default: /* shouldn't happen */
1481 return (DI_PROP_NIL
);
1483 } while ((prop
== DI_PROP_NIL
) && (list
<= DI_PROP_HW_LIST
));
1489 di_prop_devt(di_prop_t prop
)
1491 return (makedev(DI_PROP(prop
)->dev_major
, DI_PROP(prop
)->dev_minor
));
1495 di_prop_name(di_prop_t prop
)
1497 if (DI_PROP(prop
)->prop_name
== 0)
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)) {
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)) {
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)) {
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)) {
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
1630 match_prop(di_prop_t prop
, dev_t match_dev
, const char *name
, int type
)
1635 if (di_prop_name(prop
) == NULL
) {
1636 DPRINTF((DI_ERR
, "libdevinfo: property has no name!\n"));
1641 if (strcmp(name
, di_prop_name(prop
)) != 0)
1644 if ((match_dev
!= DDI_DEV_T_ANY
) && (di_prop_devt(prop
) != match_dev
))
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
))
1659 di_prop_search(dev_t match_dev
, di_node_t node
, const char *name
,
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
)) {
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
))
1682 return (DI_PROP_NIL
);
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
)) {
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
))
1707 return (DI_PROP_NIL
);
1711 di_prop_lookup_ints(dev_t dev
, di_node_t node
, const char *prop_name
,
1716 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1717 DI_PROP_TYPE_INT
)) == DI_PROP_NIL
)
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
)
1729 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1730 DI_PROP_TYPE_INT64
)) == DI_PROP_NIL
)
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
,
1742 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1743 DI_PROP_TYPE_STRING
)) == DI_PROP_NIL
)
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
)
1755 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1756 DI_PROP_TYPE_BYTE
)) == DI_PROP_NIL
)
1759 return (di_prop_bytes(prop
, (void *)prop_data
));
1763 * Consolidation private property access functions
1773 di_prop_next_common(di_node_t node
, di_prop_t prop
, int prop_type
)
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
));
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
) {
1794 prop_off
= DI_NODE(node
)->drv_prop
;
1797 prop_off
= DI_NODE(node
)->sys_prop
;
1800 prop_off
= DI_NODE(node
)->hw_prop
;
1802 case PROP_TYPE_GLOB
:
1803 prop_off
= DI_NODE(node
)->glob_prop
;
1804 if (prop_off
== -1) {
1805 /* no global property */
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
;
1818 return (DI_PROP(pa
+ prop_off
));
1822 * no prop found. Check the reason for not found
1824 if (DINFOPROP
& DI_ALL(pa
)->command
)
1829 return (DI_PROP_NIL
);
1833 di_prop_drv_next(di_node_t node
, di_prop_t prop
)
1835 return (di_prop_next_common(node
, prop
, PROP_TYPE_DRV
));
1839 di_prop_sys_next(di_node_t node
, di_prop_t prop
)
1841 return (di_prop_next_common(node
, prop
, PROP_TYPE_SYS
));
1845 di_prop_global_next(di_node_t node
, di_prop_t prop
)
1847 return (di_prop_next_common(node
, prop
, PROP_TYPE_GLOB
));
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
)
1860 if (prop
== DI_PROP_NIL
) {
1866 if (DI_PROP(prop
)->prop_len
== 0) {
1871 if ((DI_PROP(prop
)->prop_data
== 0) ||
1872 (DI_PROP(prop
)->prop_data
== (di_off_t
)-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
1891 di_path_phci_next_path(di_node_t node
, di_path_t path
)
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
)));
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",
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
))
1929 return (DI_PATH_NIL
);
1933 di_path_client_next_path(di_node_t node
, di_path_t path
)
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
));
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",
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
))
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.
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
),
1991 di_path_next(di_node_t node
, di_path_t path
)
1993 if (node
== DI_NODE_NIL
) {
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
));
2004 * The node had multipathing data but didn't appear to be a
2005 * phci *or* a client; probably a programmer error.
2008 return (DI_PATH_NIL
);
2012 di_path_next_phci(di_node_t node
, di_path_t path
)
2014 return (di_path_client_next_path(node
, path
));
2017 di_path_next_client(di_node_t node
, di_path_t path
)
2019 return (di_path_phci_next_path(node
, path
));
2026 di_path_state(di_path_t path
)
2028 return ((di_path_state_t
)DI_PATH(path
)->path_state
);
2032 di_path_node_name(di_path_t path
)
2034 di_node_t client_node
;
2036 /* pathinfo gets node_name from client */
2037 if ((client_node
= di_path_client_node(path
)) == NULL
)
2039 return (di_node_name(client_node
));
2043 di_path_bus_addr(di_path_t path
)
2045 caddr_t pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2047 if (DI_PATH(path
)->path_addr
== 0)
2050 return ((char *)(pa
+ DI_PATH(path
)->path_addr
));
2054 di_path_instance(di_path_t path
)
2056 return (DI_PATH(path
)->path_instance
);
2060 di_path_client_node(di_path_t path
)
2062 caddr_t pa
; /* starting address of map */
2064 if (path
== DI_PATH_NIL
) {
2066 return (DI_PATH_NIL
);
2069 DPRINTF((DI_TRACE
, "Get client node for path %p\n", path
));
2071 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2073 if (DI_PATH(path
)->path_client
) {
2074 return (DI_NODE(pa
+ DI_PATH(path
)->path_client
));
2078 * Deal with error condition:
2079 * If parent doesn't exist and node is not the root,
2080 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2082 if ((DI_PATH(path
)->path_snap_state
& DI_PATH_SNAP_NOCLIENT
) == 0)
2087 return (DI_NODE_NIL
);
2091 di_path_phci_node(di_path_t path
)
2093 caddr_t pa
; /* starting address of map */
2095 if (path
== DI_PATH_NIL
) {
2097 return (DI_PATH_NIL
);
2100 DPRINTF((DI_TRACE
, "Get phci node for path %p\n", path
));
2102 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2104 if (DI_PATH(path
)->path_phci
) {
2105 return (DI_NODE(pa
+ DI_PATH(path
)->path_phci
));
2109 * Deal with error condition:
2110 * If parent doesn't exist and node is not the root,
2111 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2113 if ((DI_PATH(path
)->path_snap_state
& DI_PATH_SNAP_NOPHCI
) == 0)
2118 return (DI_NODE_NIL
);
2122 di_path_prop_next(di_path_t path
, di_path_prop_t prop
)
2126 if (path
== DI_PATH_NIL
) {
2128 return (DI_PROP_NIL
);
2134 if (prop
!= DI_PROP_NIL
) {
2135 if (DI_PROP(prop
)->next
!= 0)
2136 return (DI_PATHPROP((caddr_t
)prop
-
2137 DI_PROP(prop
)->self
+ DI_PROP(prop
)->next
));
2140 return (DI_PROP_NIL
);
2145 * prop is NIL-->caller asks for first property
2147 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2148 if (DI_PATH(path
)->path_prop
!= 0) {
2149 return (DI_PATHPROP(pa
+ DI_PATH(path
)->path_prop
));
2153 * no property data-->check if snapshot includes props
2154 * in order to set the correct errno
2156 if (DINFOPROP
& (DI_ALL(pa
)->command
))
2161 return (DI_PROP_NIL
);
2165 di_path_prop_name(di_path_prop_t prop
)
2167 caddr_t pa
; /* starting address of map */
2168 pa
= (caddr_t
)prop
- DI_PATHPROP(prop
)->self
;
2169 return ((char *)(pa
+ DI_PATHPROP(prop
)->prop_name
));
2173 di_path_prop_len(di_path_prop_t prop
)
2175 return (DI_PATHPROP(prop
)->prop_len
);
2179 di_path_prop_type(di_path_prop_t prop
)
2181 switch (DI_PATHPROP(prop
)->prop_type
) {
2182 case DDI_PROP_TYPE_INT
:
2183 return (DI_PROP_TYPE_INT
);
2184 case DDI_PROP_TYPE_INT64
:
2185 return (DI_PROP_TYPE_INT64
);
2186 case DDI_PROP_TYPE_BYTE
:
2187 return (DI_PROP_TYPE_BYTE
);
2188 case DDI_PROP_TYPE_STRING
:
2189 return (DI_PROP_TYPE_STRING
);
2191 return (DI_PROP_TYPE_UNKNOWN
);
2195 di_path_prop_bytes(di_path_prop_t prop
, uchar_t
**prop_data
)
2197 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2198 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2204 *prop_data
= (uchar_t
*)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2205 + DI_PATHPROP(prop
)->prop_data
);
2207 return (di_prop_decode_common((void *)prop_data
,
2208 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_BYTE
, 0));
2212 di_path_prop_ints(di_path_prop_t prop
, int **prop_data
)
2214 if (DI_PATHPROP(prop
)->prop_len
== 0)
2217 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2218 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2224 *prop_data
= (int *)((void *)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2225 + DI_PATHPROP(prop
)->prop_data
));
2227 return (di_prop_decode_common((void *)prop_data
,
2228 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_INT
, 0));
2232 di_path_prop_int64s(di_path_prop_t prop
, int64_t **prop_data
)
2234 if (DI_PATHPROP(prop
)->prop_len
== 0)
2237 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2238 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2244 *prop_data
= (int64_t *)((void *)((caddr_t
)prop
-
2245 DI_PATHPROP(prop
)->self
+ DI_PATHPROP(prop
)->prop_data
));
2247 return (di_prop_decode_common((void *)prop_data
,
2248 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_INT64
, 0));
2252 di_path_prop_strings(di_path_prop_t prop
, char **prop_data
)
2254 if (DI_PATHPROP(prop
)->prop_len
== 0)
2257 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2258 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2264 *prop_data
= (char *)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2265 + DI_PATHPROP(prop
)->prop_data
);
2267 return (di_prop_decode_common((void *)prop_data
,
2268 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_STRING
, 0));
2271 static di_path_prop_t
2272 di_path_prop_search(di_path_t path
, const char *name
, int type
)
2274 di_path_prop_t prop
= DI_PROP_NIL
;
2277 * Sanity check arguments
2279 if ((path
== DI_PATH_NIL
) || (name
== NULL
) || (strlen(name
) == 0) ||
2280 !DI_PROP_TYPE_VALID(type
)) {
2282 return (DI_PROP_NIL
);
2285 while ((prop
= di_path_prop_next(path
, prop
)) != DI_PROP_NIL
) {
2286 int prop_type
= di_path_prop_type(prop
);
2288 DPRINTF((DI_TRACE1
, "match path prop name %s, type %d\n",
2289 di_path_prop_name(prop
), prop_type
));
2291 if (strcmp(name
, di_path_prop_name(prop
)) != 0)
2294 if ((prop_type
!= DI_PROP_TYPE_UNKNOWN
) && (prop_type
!= type
))
2300 return (DI_PROP_NIL
);
2304 di_path_prop_lookup_bytes(di_path_t path
, const char *prop_name
,
2305 uchar_t
**prop_data
)
2307 di_path_prop_t prop
;
2309 if ((prop
= di_path_prop_search(path
, prop_name
,
2310 DI_PROP_TYPE_BYTE
)) == DI_PROP_NIL
)
2313 return (di_path_prop_bytes(prop
, prop_data
));
2317 di_path_prop_lookup_ints(di_path_t path
, const char *prop_name
,
2320 di_path_prop_t prop
;
2322 if ((prop
= di_path_prop_search(path
, prop_name
,
2323 DI_PROP_TYPE_INT
)) == DI_PROP_NIL
)
2326 return (di_path_prop_ints(prop
, prop_data
));
2330 di_path_prop_lookup_int64s(di_path_t path
, const char *prop_name
,
2331 int64_t **prop_data
)
2333 di_path_prop_t prop
;
2335 if ((prop
= di_path_prop_search(path
, prop_name
,
2336 DI_PROP_TYPE_INT64
)) == DI_PROP_NIL
)
2339 return (di_path_prop_int64s(prop
, prop_data
));
2342 int di_path_prop_lookup_strings(di_path_t path
, const char *prop_name
,
2345 di_path_prop_t prop
;
2347 if ((prop
= di_path_prop_search(path
, prop_name
,
2348 DI_PROP_TYPE_STRING
)) == DI_PROP_NIL
)
2351 return (di_path_prop_strings(prop
, prop_data
));
2355 * Consolidation private interfaces for traversing vhci nodes.
2358 di_vhci_first_node(di_node_t root
)
2361 caddr_t pa
; /* starting address of map */
2363 DPRINTF((DI_INFO
, "Get first vhci node\n"));
2365 if (root
== DI_NODE_NIL
) {
2367 return (DI_NODE_NIL
);
2370 pa
= (caddr_t
)root
- DI_NODE(root
)->self
;
2373 if (dap
->top_vhci_devinfo
== NULL
) {
2375 return (DI_NODE_NIL
);
2378 return (DI_NODE(pa
+ dap
->top_vhci_devinfo
));
2382 di_vhci_next_node(di_node_t node
)
2384 caddr_t pa
; /* starting address of map */
2386 if (node
== DI_NODE_NIL
) {
2388 return (DI_NODE_NIL
);
2391 DPRINTF((DI_TRACE
, "next vhci node on the snap shot:"
2392 " current=%s\n", di_node_name(node
)));
2394 if (DI_NODE(node
)->next_vhci
== NULL
) {
2396 return (DI_NODE_NIL
);
2399 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2401 return (DI_NODE(pa
+ DI_NODE(node
)->next_vhci
));
2405 * Consolidation private interfaces for traversing phci nodes.
2408 di_phci_first_node(di_node_t vhci_node
)
2410 caddr_t pa
; /* starting address of map */
2412 DPRINTF((DI_INFO
, "Get first phci node:\n"
2413 " current=%s", di_node_name(vhci_node
)));
2415 if (vhci_node
== DI_NODE_NIL
) {
2417 return (DI_NODE_NIL
);
2420 pa
= (caddr_t
)vhci_node
- DI_NODE(vhci_node
)->self
;
2422 if (DI_NODE(vhci_node
)->top_phci
== NULL
) {
2424 return (DI_NODE_NIL
);
2427 return (DI_NODE(pa
+ DI_NODE(vhci_node
)->top_phci
));
2431 di_phci_next_node(di_node_t node
)
2433 caddr_t pa
; /* starting address of map */
2435 if (node
== DI_NODE_NIL
) {
2437 return (DI_NODE_NIL
);
2440 DPRINTF((DI_TRACE
, "next phci node on the snap shot:"
2441 " current=%s\n", di_node_name(node
)));
2443 if (DI_NODE(node
)->next_phci
== NULL
) {
2445 return (DI_NODE_NIL
);
2448 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2450 return (DI_NODE(pa
+ DI_NODE(node
)->next_phci
));
2454 * Consolidation private interfaces for private data
2457 di_parent_private_data(di_node_t node
)
2461 if (DI_NODE(node
)->parent_data
== 0) {
2466 if (DI_NODE(node
)->parent_data
== (di_off_t
)-1) {
2468 * Private data requested, but not obtained due to a memory
2469 * error (e.g. wrong format specified)
2475 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2476 if (DI_NODE(node
)->parent_data
)
2477 return (pa
+ DI_NODE(node
)->parent_data
);
2479 if (DI_ALL(pa
)->command
& DINFOPRIVDATA
)
2488 di_driver_private_data(di_node_t node
)
2492 if (DI_NODE(node
)->driver_data
== 0) {
2497 if (DI_NODE(node
)->driver_data
== (di_off_t
)-1) {
2499 * Private data requested, but not obtained due to a memory
2500 * error (e.g. wrong format specified)
2506 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2507 if (DI_NODE(node
)->driver_data
)
2508 return (pa
+ DI_NODE(node
)->driver_data
);
2510 if (DI_ALL(pa
)->command
& DINFOPRIVDATA
)
2519 * PROM property access
2523 * openprom driver stuff:
2524 * The maximum property length depends on the buffer size. We use
2525 * OPROMMAXPARAM defined in <sys/openpromio.h>
2527 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2528 * MAXVALSZ is maximum value size, which is whatever space left in buf
2531 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int)
2532 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME;
2534 struct di_prom_prop
{
2538 struct di_prom_prop
*next
; /* form a linked list */
2541 struct di_prom_handle
{ /* handle to prom */
2542 mutex_t lock
; /* synchronize access to openprom fd */
2543 int fd
; /* /dev/openprom file descriptor */
2544 struct di_prom_prop
*list
; /* linked list of prop */
2546 char buf
[OPROMMAXPARAM
];
2547 struct openpromio opp
;
2554 struct di_prom_handle
*p
;
2556 if ((p
= malloc(sizeof (struct di_prom_handle
))) == NULL
)
2557 return (DI_PROM_HANDLE_NIL
);
2559 DPRINTF((DI_INFO
, "di_prom_init: get prom handle 0x%p\n", p
));
2561 (void) mutex_init(&p
->lock
, USYNC_THREAD
, NULL
);
2562 if ((p
->fd
= open("/dev/openprom", O_RDONLY
)) < 0) {
2564 return (DI_PROM_HANDLE_NIL
);
2568 return ((di_prom_handle_t
)p
);
2572 di_prom_prop_free(struct di_prom_prop
*list
)
2574 struct di_prom_prop
*tmp
= list
;
2576 while (tmp
!= NULL
) {
2578 if (tmp
->name
!= NULL
) {
2581 if (tmp
->data
!= NULL
) {
2590 di_prom_fini(di_prom_handle_t ph
)
2592 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2594 DPRINTF((DI_INFO
, "di_prom_fini: free prom handle 0x%p\n", p
));
2596 (void) close(p
->fd
);
2597 (void) mutex_destroy(&p
->lock
);
2598 di_prom_prop_free(p
->list
);
2604 * Internal library interface for locating the property
2605 * XXX: ph->lock must be held for the duration of call.
2607 static di_prom_prop_t
2608 di_prom_prop_found(di_prom_handle_t ph
, int nodeid
,
2609 di_prom_prop_t prom_prop
)
2611 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2612 struct openpromio
*opp
= &p
->oppbuf
.opp
;
2613 int *ip
= (int *)((void *)opp
->oprom_array
);
2614 struct di_prom_prop
*prop
= (struct di_prom_prop
*)prom_prop
;
2616 DPRINTF((DI_TRACE1
, "Looking for nodeid 0x%x\n", nodeid
));
2619 * Set "current" nodeid in the openprom driver
2621 opp
->oprom_size
= sizeof (int);
2623 if (ioctl(p
->fd
, OPROMSETNODEID
, opp
) < 0) {
2624 DPRINTF((DI_ERR
, "*** Nodeid not found 0x%x\n", nodeid
));
2625 return (DI_PROM_PROP_NIL
);
2628 DPRINTF((DI_TRACE
, "Found nodeid 0x%x\n", nodeid
));
2630 bzero(opp
, OBP_MAXBUF
);
2631 opp
->oprom_size
= OBP_MAXPROPNAME
;
2632 if (prom_prop
!= DI_PROM_PROP_NIL
)
2633 (void) strcpy(opp
->oprom_array
, prop
->name
);
2635 if ((ioctl(p
->fd
, OPROMNXTPROP
, opp
) < 0) || (opp
->oprom_size
== 0))
2636 return (DI_PROM_PROP_NIL
);
2639 * Prom property found. Allocate struct for storing prop
2640 * (reuse variable prop)
2642 if ((prop
= malloc(sizeof (struct di_prom_prop
))) == NULL
)
2643 return (DI_PROM_PROP_NIL
);
2646 * Get a copy of property name
2648 if ((prop
->name
= strdup(opp
->oprom_array
)) == NULL
) {
2650 return (DI_PROM_PROP_NIL
);
2654 * get property value and length
2656 opp
->oprom_size
= OBP_MAXPROPLEN
;
2658 if ((ioctl(p
->fd
, OPROMGETPROP
, opp
) < 0) ||
2659 (opp
->oprom_size
== (uint_t
)-1)) {
2662 return (DI_PROM_PROP_NIL
);
2666 * make a copy of the property value
2668 prop
->len
= opp
->oprom_size
;
2672 else if ((prop
->data
= malloc(prop
->len
)) == NULL
) {
2675 return (DI_PROM_PROP_NIL
);
2678 bcopy(opp
->oprom_array
, prop
->data
, prop
->len
);
2681 * Prepend prop to list in prom handle
2683 prop
->next
= p
->list
;
2686 return ((di_prom_prop_t
)prop
);
2690 di_prom_prop_next(di_prom_handle_t ph
, di_node_t node
, di_prom_prop_t prom_prop
)
2692 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2694 DPRINTF((DI_TRACE1
, "Search next prop for node 0x%p with ph 0x%p\n",
2700 if ((ph
== DI_PROM_HANDLE_NIL
) || (node
== DI_NODE_NIL
)) {
2702 return (DI_PROM_PROP_NIL
);
2705 if (di_nodeid(node
) != DI_PROM_NODEID
) {
2707 return (DI_PROM_PROP_NIL
);
2711 * synchronize access to prom file descriptor
2713 (void) mutex_lock(&p
->lock
);
2716 * look for next property
2718 prom_prop
= di_prom_prop_found(ph
, DI_NODE(node
)->nodeid
, prom_prop
);
2720 (void) mutex_unlock(&p
->lock
);
2726 di_prom_prop_name(di_prom_prop_t prom_prop
)
2731 if (prom_prop
== DI_PROM_PROP_NIL
) {
2736 return (((struct di_prom_prop
*)prom_prop
)->name
);
2740 di_prom_prop_data(di_prom_prop_t prom_prop
, uchar_t
**prom_prop_data
)
2745 if (prom_prop
== DI_PROM_PROP_NIL
) {
2750 *prom_prop_data
= ((struct di_prom_prop
*)prom_prop
)->data
;
2752 return (((struct di_prom_prop
*)prom_prop
)->len
);
2756 * Internal library interface for locating the property
2757 * Returns length if found, -1 if prop doesn't exist.
2759 static struct di_prom_prop
*
2760 di_prom_prop_lookup_common(di_prom_handle_t ph
, di_node_t node
,
2761 const char *prom_prop_name
)
2763 struct openpromio
*opp
;
2764 struct di_prom_prop
*prop
;
2765 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2770 if ((ph
== DI_PROM_HANDLE_NIL
) || (node
== DI_NODE_NIL
)) {
2775 if (di_nodeid(node
) != DI_PROM_NODEID
) {
2780 opp
= &p
->oppbuf
.opp
;
2782 (void) mutex_lock(&p
->lock
);
2784 opp
->oprom_size
= sizeof (int);
2785 opp
->oprom_node
= DI_NODE(node
)->nodeid
;
2786 if (ioctl(p
->fd
, OPROMSETNODEID
, opp
) < 0) {
2788 DPRINTF((DI_ERR
, "*** Nodeid not found 0x%x\n",
2789 DI_NODE(node
)->nodeid
));
2790 (void) mutex_unlock(&p
->lock
);
2795 * get property length
2797 bzero(opp
, OBP_MAXBUF
);
2798 opp
->oprom_size
= OBP_MAXPROPLEN
;
2799 (void) strcpy(opp
->oprom_array
, prom_prop_name
);
2801 if ((ioctl(p
->fd
, OPROMGETPROPLEN
, opp
) < 0) ||
2802 (opp
->oprom_len
== -1)) {
2803 /* no such property */
2804 (void) mutex_unlock(&p
->lock
);
2809 * Prom property found. Allocate struct for storing prop
2811 if ((prop
= malloc(sizeof (struct di_prom_prop
))) == NULL
) {
2812 (void) mutex_unlock(&p
->lock
);
2815 prop
->name
= NULL
; /* we don't need the name */
2816 prop
->len
= opp
->oprom_len
;
2818 if (prop
->len
== 0) { /* boolean property */
2820 prop
->next
= p
->list
;
2822 (void) mutex_unlock(&p
->lock
);
2827 * retrieve the property value
2829 bzero(opp
, OBP_MAXBUF
);
2830 opp
->oprom_size
= OBP_MAXPROPLEN
;
2831 (void) strcpy(opp
->oprom_array
, prom_prop_name
);
2833 if ((ioctl(p
->fd
, OPROMGETPROP
, opp
) < 0) ||
2834 (opp
->oprom_size
== (uint_t
)-1)) {
2835 /* error retrieving property value */
2836 (void) mutex_unlock(&p
->lock
);
2842 * make a copy of the property value, stick in ph->list
2844 if ((prop
->data
= malloc(prop
->len
)) == NULL
) {
2845 (void) mutex_unlock(&p
->lock
);
2850 bcopy(opp
->oprom_array
, prop
->data
, prop
->len
);
2852 prop
->next
= p
->list
;
2854 (void) mutex_unlock(&p
->lock
);
2860 di_prom_prop_lookup_ints(di_prom_handle_t ph
, di_node_t node
,
2861 const char *prom_prop_name
, int **prom_prop_data
)
2864 struct di_prom_prop
*prop
;
2866 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
2869 *prom_prop_data
= NULL
;
2873 if (prop
->len
== 0) { /* boolean property */
2874 *prom_prop_data
= NULL
;
2878 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
2879 DI_PROP_TYPE_INT
, 1);
2880 *prom_prop_data
= (int *)((void *)prop
->data
);
2886 di_prom_prop_lookup_strings(di_prom_handle_t ph
, di_node_t node
,
2887 const char *prom_prop_name
, char **prom_prop_data
)
2890 struct di_prom_prop
*prop
;
2892 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
2895 *prom_prop_data
= NULL
;
2899 if (prop
->len
== 0) { /* boolean property */
2900 *prom_prop_data
= NULL
;
2905 * Fix an openprom bug (OBP string not NULL terminated).
2906 * XXX This should really be fixed in promif.
2908 if (((char *)prop
->data
)[prop
->len
- 1] != '\0') {
2911 if ((tmp
= realloc(prop
->data
, prop
->len
)) == NULL
)
2915 ((char *)prop
->data
)[prop
->len
- 1] = '\0';
2916 DPRINTF((DI_INFO
, "OBP string not NULL terminated: "
2917 "node=%s, prop=%s, val=%s\n",
2918 di_node_name(node
), prom_prop_name
, prop
->data
));
2921 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
2922 DI_PROP_TYPE_STRING
, 1);
2923 *prom_prop_data
= (char *)prop
->data
;
2929 di_prom_prop_lookup_bytes(di_prom_handle_t ph
, di_node_t node
,
2930 const char *prom_prop_name
, uchar_t
**prom_prop_data
)
2933 struct di_prom_prop
*prop
;
2935 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
2938 *prom_prop_data
= NULL
;
2942 if (prop
->len
== 0) { /* boolean property */
2943 *prom_prop_data
= NULL
;
2947 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
2948 DI_PROP_TYPE_BYTE
, 1);
2949 *prom_prop_data
= prop
->data
;
2955 * returns an allocated array through <prop_data> only when its count > 0
2956 * and the number of entries (count) as the function return value;
2957 * use di_slot_names_free() to free the array
2960 di_prop_slot_names(di_prop_t prop
, di_slot_name_t
**prop_data
)
2964 char *nm
= di_prop_name(prop
);
2966 if (nm
== NULL
|| strcmp(DI_PROP_SLOT_NAMES
, nm
) != 0)
2969 rawlen
= di_prop_rawdata(prop
, &rawdata
);
2970 if (rawlen
<= 0 || rawdata
== NULL
)
2973 count
= di_slot_names_decode(rawdata
, rawlen
, prop_data
);
2974 if (count
< 0 || *prop_data
== NULL
)
2986 di_prop_lookup_slot_names(dev_t dev
, di_node_t node
,
2987 di_slot_name_t
**prop_data
)
2992 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
2993 * and slot-names is properly flagged as such
2995 if ((prop
= di_prop_find(dev
, node
, DI_PROP_SLOT_NAMES
)) ==
3001 return (di_prop_slot_names(prop
, (void *)prop_data
));
3005 * returns an allocated array through <prop_data> only when its count > 0
3006 * and the number of entries (count) as the function return value;
3007 * use di_slot_names_free() to free the array
3010 di_prom_prop_slot_names(di_prom_prop_t prom_prop
, di_slot_name_t
**prop_data
)
3015 rawlen
= di_prom_prop_data(prom_prop
, &rawdata
);
3016 if (rawlen
<= 0 || rawdata
== NULL
)
3019 count
= di_slot_names_decode(rawdata
, rawlen
, prop_data
);
3020 if (count
< 0 || *prop_data
== NULL
)
3032 di_prom_prop_lookup_slot_names(di_prom_handle_t ph
, di_node_t node
,
3033 di_slot_name_t
**prop_data
)
3035 struct di_prom_prop
*prom_prop
;
3037 prom_prop
= di_prom_prop_lookup_common(ph
, node
, DI_PROP_SLOT_NAMES
);
3038 if (prom_prop
== NULL
) {
3043 return (di_prom_prop_slot_names(prom_prop
, prop_data
));
3047 di_link_to_lnode(di_link_t link
, uint_t endpoint
)
3049 struct di_all
*di_all
;
3051 if ((link
== DI_LINK_NIL
) ||
3052 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3054 return (DI_LNODE_NIL
);
3057 di_all
= DI_ALL((caddr_t
)link
- DI_LINK(link
)->self
);
3059 if (endpoint
== DI_LINK_SRC
) {
3060 return (DI_LNODE((caddr_t
)di_all
+ DI_LINK(link
)->src_lnode
));
3062 return (DI_LNODE((caddr_t
)di_all
+ DI_LINK(link
)->tgt_lnode
));
3068 di_lnode_name(di_lnode_t lnode
)
3070 return (di_driver_name(di_lnode_devinfo(lnode
)));
3074 di_lnode_devinfo(di_lnode_t lnode
)
3076 struct di_all
*di_all
;
3078 di_all
= DI_ALL((caddr_t
)lnode
- DI_LNODE(lnode
)->self
);
3079 return (DI_NODE((caddr_t
)di_all
+ DI_LNODE(lnode
)->node
));
3083 di_lnode_devt(di_lnode_t lnode
, dev_t
*devt
)
3085 if ((lnode
== DI_LNODE_NIL
) || (devt
== NULL
)) {
3089 if ((DI_LNODE(lnode
)->dev_major
== (major_t
)-1) &&
3090 (DI_LNODE(lnode
)->dev_minor
== (minor_t
)-1))
3093 *devt
= makedev(DI_LNODE(lnode
)->dev_major
, DI_LNODE(lnode
)->dev_minor
);
3098 di_link_spectype(di_link_t link
)
3100 return (DI_LINK(link
)->spec_type
);
3104 di_minor_private_set(di_minor_t minor
, void *data
)
3106 DI_MINOR(minor
)->user_private_data
= (uintptr_t)data
;
3110 di_minor_private_get(di_minor_t minor
)
3112 return ((void *)(uintptr_t)DI_MINOR(minor
)->user_private_data
);
3116 di_node_private_set(di_node_t node
, void *data
)
3118 DI_NODE(node
)->user_private_data
= (uintptr_t)data
;
3122 di_node_private_get(di_node_t node
)
3124 return ((void *)(uintptr_t)DI_NODE(node
)->user_private_data
);
3128 di_path_private_set(di_path_t path
, void *data
)
3130 DI_PATH(path
)->user_private_data
= (uintptr_t)data
;
3134 di_path_private_get(di_path_t path
)
3136 return ((void *)(uintptr_t)DI_PATH(path
)->user_private_data
);
3140 di_lnode_private_set(di_lnode_t lnode
, void *data
)
3142 DI_LNODE(lnode
)->user_private_data
= (uintptr_t)data
;
3146 di_lnode_private_get(di_lnode_t lnode
)
3148 return ((void *)(uintptr_t)DI_LNODE(lnode
)->user_private_data
);
3152 di_link_private_set(di_link_t link
, void *data
)
3154 DI_LINK(link
)->user_private_data
= (uintptr_t)data
;
3158 di_link_private_get(di_link_t link
)
3160 return ((void *)(uintptr_t)DI_LINK(link
)->user_private_data
);
3164 di_lnode_next(di_node_t node
, di_lnode_t lnode
)
3166 struct di_all
*di_all
;
3169 * paranoid error checking
3171 if (node
== DI_NODE_NIL
) {
3173 return (DI_LNODE_NIL
);
3176 di_all
= DI_ALL((caddr_t
)node
- DI_NODE(node
)->self
);
3178 if (lnode
== DI_NODE_NIL
) {
3179 if (DI_NODE(node
)->lnodes
!= NULL
)
3180 return (DI_LNODE((caddr_t
)di_all
+
3181 DI_NODE(node
)->lnodes
));
3183 if (DI_LNODE(lnode
)->node_next
!= NULL
)
3184 return (DI_LNODE((caddr_t
)di_all
+
3185 DI_LNODE(lnode
)->node_next
));
3188 if (DINFOLYR
& DI_ALL(di_all
)->command
)
3193 return (DI_LNODE_NIL
);
3197 di_link_next_by_node(di_node_t node
, di_link_t link
, uint_t endpoint
)
3199 struct di_all
*di_all
;
3202 * paranoid error checking
3204 if ((node
== DI_NODE_NIL
) ||
3205 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3207 return (DI_LINK_NIL
);
3210 di_all
= DI_ALL((caddr_t
)node
- DI_NODE(node
)->self
);
3212 if (endpoint
== DI_LINK_SRC
) {
3213 if (link
== DI_LINK_NIL
) {
3214 if (DI_NODE(node
)->src_links
!= NULL
)
3215 return (DI_LINK((caddr_t
)di_all
+
3216 DI_NODE(node
)->src_links
));
3218 if (DI_LINK(link
)->src_node_next
!= NULL
)
3219 return (DI_LINK((caddr_t
)di_all
+
3220 DI_LINK(link
)->src_node_next
));
3223 if (link
== DI_LINK_NIL
) {
3224 if (DI_NODE(node
)->tgt_links
!= NULL
)
3225 return (DI_LINK((caddr_t
)di_all
+
3226 DI_NODE(node
)->tgt_links
));
3228 if (DI_LINK(link
)->tgt_node_next
!= NULL
)
3229 return (DI_LINK((caddr_t
)di_all
+
3230 DI_LINK(link
)->tgt_node_next
));
3234 if (DINFOLYR
& DI_ALL(di_all
)->command
)
3239 return (DI_LINK_NIL
);
3243 di_link_next_by_lnode(di_lnode_t lnode
, di_link_t link
, uint_t endpoint
)
3245 struct di_all
*di_all
;
3248 * paranoid error checking
3250 if ((lnode
== DI_LNODE_NIL
) ||
3251 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3253 return (DI_LINK_NIL
);
3256 di_all
= DI_ALL((caddr_t
)lnode
- DI_LNODE(lnode
)->self
);
3258 if (endpoint
== DI_LINK_SRC
) {
3259 if (link
== DI_LINK_NIL
) {
3260 if (DI_LNODE(lnode
)->link_out
== NULL
)
3261 return (DI_LINK_NIL
);
3262 return (DI_LINK((caddr_t
)di_all
+
3263 DI_LNODE(lnode
)->link_out
));
3265 if (DI_LINK(link
)->src_link_next
== NULL
)
3266 return (DI_LINK_NIL
);
3267 return (DI_LINK((caddr_t
)di_all
+
3268 DI_LINK(link
)->src_link_next
));
3271 if (link
== DI_LINK_NIL
) {
3272 if (DI_LNODE(lnode
)->link_in
== NULL
)
3273 return (DI_LINK_NIL
);
3274 return (DI_LINK((caddr_t
)di_all
+
3275 DI_LNODE(lnode
)->link_in
));
3277 if (DI_LINK(link
)->tgt_link_next
== NULL
)
3278 return (DI_LINK_NIL
);
3279 return (DI_LINK((caddr_t
)di_all
+
3280 DI_LINK(link
)->tgt_link_next
));
3287 * Internal library function:
3288 * Invoke callback for each link data on the link list of first node
3289 * on node_list headp, and place children of first node on the list.
3291 * This is similar to walk_one_node, except we only walk in child
3295 walk_one_link(struct node_list
**headp
, uint_t ep
,
3296 void *arg
, int (*callback
)(di_link_t link
, void *arg
))
3298 int action
= DI_WALK_CONTINUE
;
3299 di_link_t link
= DI_LINK_NIL
;
3300 di_node_t node
= (*headp
)->node
;
3302 while ((link
= di_link_next_by_node(node
, link
, ep
)) != DI_LINK_NIL
) {
3303 action
= callback(link
, arg
);
3304 if (action
== DI_WALK_TERMINATE
) {
3309 update_node_list(action
, DI_WALK_LINKGEN
, headp
);
3313 di_walk_link(di_node_t root
, uint_t flag
, uint_t endpoint
, void *arg
,
3314 int (*link_callback
)(di_link_t link
, void *arg
))
3316 struct node_list
*head
; /* node_list for tree walk */
3319 char *devfspath
= di_devfs_path(root
);
3320 DPRINTF((DI_INFO
, "walking %s link data under %s\n",
3321 (endpoint
== DI_LINK_SRC
) ? "src" : "tgt", devfspath
));
3322 di_devfs_path_free(devfspath
);
3326 * paranoid error checking
3328 if ((root
== DI_NODE_NIL
) || (link_callback
== NULL
) || (flag
!= 0) ||
3329 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3334 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
3335 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
3342 DPRINTF((DI_INFO
, "Start link data walking from node %s\n",
3343 di_node_name(root
)));
3345 while (head
!= NULL
)
3346 walk_one_link(&head
, endpoint
, arg
, link_callback
);
3352 * Internal library function:
3353 * Invoke callback for each link data on the link list of first node
3354 * on node_list headp, and place children of first node on the list.
3356 * This is similar to walk_one_node, except we only walk in child
3360 walk_one_lnode(struct node_list
**headp
, void *arg
,
3361 int (*callback
)(di_lnode_t lnode
, void *arg
))
3363 int action
= DI_WALK_CONTINUE
;
3364 di_lnode_t lnode
= DI_LNODE_NIL
;
3365 di_node_t node
= (*headp
)->node
;
3367 while ((lnode
= di_lnode_next(node
, lnode
)) != DI_LNODE_NIL
) {
3368 action
= callback(lnode
, arg
);
3369 if (action
== DI_WALK_TERMINATE
) {
3374 update_node_list(action
, DI_WALK_LINKGEN
, headp
);
3378 di_walk_lnode(di_node_t root
, uint_t flag
, void *arg
,
3379 int (*lnode_callback
)(di_lnode_t lnode
, void *arg
))
3381 struct node_list
*head
; /* node_list for tree walk */
3384 char *devfspath
= di_devfs_path(root
);
3385 DPRINTF((DI_INFO
, "walking lnode data under %s\n", devfspath
));
3386 di_devfs_path_free(devfspath
);
3390 * paranoid error checking
3392 if ((root
== DI_NODE_NIL
) || (lnode_callback
== NULL
) || (flag
!= 0)) {
3397 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
3398 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
3405 DPRINTF((DI_INFO
, "Start lnode data walking from node %s\n",
3406 di_node_name(root
)));
3408 while (head
!= NULL
)
3409 walk_one_lnode(&head
, arg
, lnode_callback
);
3415 di_lookup_node(di_node_t root
, char *devfspath
)
3419 char *copy
, *slash
, *pname
, *paddr
;
3422 * Path must be absolute and musn't have duplicate slashes
3424 if (*devfspath
!= '/' || strstr(devfspath
, "//")) {
3425 DPRINTF((DI_ERR
, "Invalid path: %s\n", devfspath
));
3426 return (DI_NODE_NIL
);
3429 if (root
== DI_NODE_NIL
) {
3430 DPRINTF((DI_ERR
, "root node is DI_NODE_NIL\n"));
3431 return (DI_NODE_NIL
);
3434 dap
= DI_ALL((caddr_t
)root
- DI_NODE(root
)->self
);
3435 if (strcmp(dap
->root_path
, "/") != 0) {
3436 DPRINTF((DI_ERR
, "snapshot root not / : %s\n", dap
->root_path
));
3437 return (DI_NODE_NIL
);
3440 if ((copy
= strdup(devfspath
)) == NULL
) {
3441 DPRINTF((DI_ERR
, "strdup failed on: %s\n", devfspath
));
3442 return (DI_NODE_NIL
);
3445 for (slash
= copy
, node
= root
; slash
; ) {
3448 * Handle devfspath = "/" case as well as trailing '/'
3450 if (*(slash
+ 1) == '\0')
3454 * More path-components exist. Deal with the next one
3457 node
= di_child_node(node
);
3459 if (slash
= strchr(pname
, '/'))
3461 if (paddr
= strchr(pname
, '@'))
3464 for (; node
!= DI_NODE_NIL
; node
= di_sibling_node(node
)) {
3467 name
= di_node_name(node
);
3468 baddr
= di_bus_addr(node
);
3470 if (strcmp(pname
, name
) != 0)
3474 * Mappings between a "path-address" and bus-addr
3477 * ---------------------
3480 * "" N/A (invalid paddr)
3482 if (paddr
&& baddr
&& strcmp(paddr
, baddr
) == 0)
3484 if (paddr
== NULL
&& (baddr
== NULL
|| *baddr
== '\0'))
3489 * No nodes in the sibling list or there was no match
3491 if (node
== DI_NODE_NIL
) {
3492 DPRINTF((DI_ERR
, "%s@%s: no node\n", pname
, paddr
));
3494 return (DI_NODE_NIL
);
3498 assert(node
!= DI_NODE_NIL
);
3504 di_lookup_path(di_node_t root
, char *devfspath
)
3506 di_node_t phci_node
;
3507 di_path_t path
= DI_PATH_NIL
;
3508 char *copy
, *lastslash
;
3509 char *pname
, *paddr
;
3510 char *path_name
, *path_addr
;
3512 if ((copy
= strdup(devfspath
)) == NULL
) {
3513 DPRINTF((DI_ERR
, "strdup failed on: %s\n", devfspath
));
3514 return (DI_NODE_NIL
);
3517 if ((lastslash
= strrchr(copy
, '/')) == NULL
) {
3518 DPRINTF((DI_ERR
, "failed to find component: %s\n", devfspath
));
3522 /* stop at pHCI and find the node for the phci */
3524 phci_node
= di_lookup_node(root
, copy
);
3525 if (phci_node
== NULL
) {
3526 DPRINTF((DI_ERR
, "failed to find component: %s\n", devfspath
));
3530 /* set up pname and paddr for last component */
3531 pname
= lastslash
+ 1;
3532 if ((paddr
= strchr(pname
, '@')) == NULL
) {
3533 DPRINTF((DI_ERR
, "failed to find unit-addr: %s\n", devfspath
));
3538 /* walk paths below phci looking for match */
3539 for (path
= di_path_phci_next_path(phci_node
, DI_PATH_NIL
);
3540 path
!= DI_PATH_NIL
;
3541 path
= di_path_phci_next_path(phci_node
, path
)) {
3543 /* get name@addr of path */
3544 path_name
= di_path_node_name(path
);
3545 path_addr
= di_path_bus_addr(path
);
3546 if ((path_name
== NULL
) || (path_addr
== NULL
))
3549 /* break on match */
3550 if ((strcmp(pname
, path_name
) == 0) &&
3551 (strcmp(paddr
, path_addr
) == 0))
3560 msglevel2str(di_debug_t msglevel
)
3579 dprint(di_debug_t msglevel
, const char *fmt
, ...)
3584 if (di_debug
<= DI_QUIET
)
3587 if (di_debug
< msglevel
)
3590 estr
= msglevel2str(msglevel
);
3596 (void) fprintf(stderr
, "libdevinfo[%lu]: %s: ",
3597 (ulong_t
)getpid(), estr
);
3598 (void) vfprintf(stderr
, fmt
, ap
);
3603 /* end of devinfo.c */