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 (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2024 MNX Cloud, Inc.
27 * Interfaces for getting device configuration data from kernel
28 * through the devinfo driver.
40 #include <sys/mkdev.h>
41 #include <sys/obpdefs.h>
43 #include <sys/types.h>
45 #include <sys/autoconf.h>
47 #include <sys/ddi_hp.h>
52 #include "libdevinfo.h"
55 * Debug message levels
58 DI_QUIET
= 0, /* No debug messages - the default */
66 int di_debug
= DI_QUIET
;
68 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; }
70 void dprint(di_debug_t msglevel
, const char *fmt
, ...);
73 #pragma init(_libdevinfo_init)
78 char *debug_str
= getenv("_LIBDEVINFO_DEBUG");
82 di_debug
= atoi(debug_str
);
83 if (errno
|| di_debug
< DI_QUIET
)
89 di_init(const char *phys_path
, uint_t flag
)
91 return (di_init_impl(phys_path
, flag
, NULL
));
95 * We use blocking_open() to guarantee access to the devinfo device, if open()
96 * is failing with EAGAIN.
99 blocking_open(const char *path
, int oflag
)
103 while ((fd
= open(path
, oflag
)) == -1 && errno
== EAGAIN
)
104 (void) poll(NULL
, 0, 1 * MILLISEC
);
109 /* private interface */
111 di_init_driver(const char *drv_name
, uint_t flag
)
114 char driver
[MAXPATHLEN
];
117 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
118 * which should be sufficient for any sensible programmer.
120 if ((drv_name
== NULL
) || (strlen(drv_name
) >= MAXPATHLEN
)) {
122 return (DI_NODE_NIL
);
124 (void) strcpy(driver
, drv_name
);
127 * open the devinfo driver
129 if ((fd
= blocking_open("/devices/pseudo/devinfo@0:devinfo",
131 DPRINTF((DI_ERR
, "devinfo open failed: errno = %d\n", errno
));
132 return (DI_NODE_NIL
);
135 if (ioctl(fd
, DINFOLODRV
, driver
) != 0) {
136 DPRINTF((DI_ERR
, "failed to load driver %s\n", driver
));
139 return (DI_NODE_NIL
);
144 * Driver load succeeded, return a snapshot
146 return (di_init("/", flag
));
150 di_init_impl(const char *phys_path
, uint_t flag
,
151 struct di_priv_data
*priv
)
156 struct dinfo_io dinfo_io
;
158 uint_t pageoffset
= sysconf(_SC_PAGESIZE
) - 1;
159 uint_t pagemask
= ~pageoffset
;
161 DPRINTF((DI_INFO
, "di_init: taking a snapshot\n"));
164 * Make sure there is no minor name in the path
165 * and the path do not start with /devices....
167 if (phys_path
== NULL
||
168 strchr(phys_path
, ':') ||
169 (strncmp(phys_path
, "/devices", 8) == 0) ||
170 (strlen(phys_path
) > MAXPATHLEN
)) {
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
== 0) {
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_DOWN
;
981 if (DI_NODE(node
)->state
& DEVI_DEVICE_DEGRADED
)
982 result
|= DI_DEVICE_DEGRADED
;
983 if (DI_NODE(node
)->state
& DEVI_DEVICE_REMOVED
)
984 result
|= DI_DEVICE_REMOVED
;
985 if (DI_NODE(node
)->state
& DEVI_BUS_QUIESCED
)
986 result
|= DI_BUS_QUIESCED
;
987 if (DI_NODE(node
)->state
& DEVI_BUS_DOWN
)
988 result
|= DI_BUS_DOWN
;
994 di_node_state(di_node_t node
)
996 return (DI_NODE(node
)->node_state
);
1000 di_flags(di_node_t node
)
1002 return (DI_NODE(node
)->flags
);
1006 di_retired(di_node_t node
)
1008 return (di_flags(node
) & DEVI_RETIRED
);
1012 di_devid(di_node_t node
)
1014 if (DI_NODE(node
)->devid
== 0)
1017 return ((ddi_devid_t
)((caddr_t
)node
+
1018 DI_NODE(node
)->devid
- DI_NODE(node
)->self
));
1022 di_driver_major(di_node_t node
)
1026 major
= DI_NODE(node
)->drv_major
;
1033 di_driver_name(di_node_t node
)
1037 struct di_devnm
*devnm
;
1039 major
= DI_NODE(node
)->drv_major
;
1043 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1044 devnm
= DI_DEVNM(pa
+ DI_ALL(pa
)->devnames
);
1046 if (devnm
[major
].name
)
1047 return (pa
+ devnm
[major
].name
);
1053 di_driver_ops(di_node_t node
)
1057 struct di_devnm
*devnm
;
1059 major
= DI_NODE(node
)->drv_major
;
1063 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1064 devnm
= DI_DEVNM(pa
+ DI_ALL(pa
)->devnames
);
1066 return (devnm
[major
].ops
);
1070 * Returns pointer to the allocated string, which must be freed by the caller.
1073 di_devfs_path(di_node_t node
)
1077 int depth
= 0, len
= 0;
1078 char *buf
, *name
[MAX_TREE_DEPTH
], *addr
[MAX_TREE_DEPTH
];
1080 if (node
== DI_NODE_NIL
) {
1086 * trace back to root, note the node_name & address
1088 while ((parent
= di_parent_node(node
)) != DI_NODE_NIL
) {
1089 name
[depth
] = di_node_name(node
);
1090 len
+= strlen(name
[depth
]) + 1; /* 1 for '/' */
1092 if ((addr
[depth
] = di_bus_addr(node
)) != NULL
)
1093 len
+= strlen(addr
[depth
]) + 1; /* 1 for '@' */
1100 * get the path to the root of snapshot
1102 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1103 name
[depth
] = DI_ALL(pa
)->root_path
;
1104 len
+= strlen(name
[depth
]) + 1;
1107 * allocate buffer and assemble path
1109 if ((buf
= malloc(len
)) == NULL
) {
1113 (void) strcpy(buf
, name
[depth
]);
1115 if (buf
[len
- 1] == '/')
1116 len
--; /* delete trailing '/' */
1121 (void) strcpy(buf
+ len
+ 1, name
[depth
]);
1122 len
+= strlen(name
[depth
]) + 1;
1123 if (addr
[depth
] && addr
[depth
][0] != '\0') {
1125 (void) strcpy(buf
+ len
+ 1, addr
[depth
]);
1126 len
+= strlen(addr
[depth
]) + 1;
1134 di_devfs_minor_path(di_minor_t minor
)
1137 char *full_path
, *name
, *devfspath
;
1140 if (minor
== DI_MINOR_NIL
) {
1145 name
= di_minor_name(minor
);
1146 node
= di_minor_devinfo(minor
);
1147 devfspath
= di_devfs_path(node
);
1148 if (devfspath
== NULL
)
1151 /* make the full path to the device minor node */
1152 full_path_len
= strlen(devfspath
) + strlen(name
) + 2;
1153 full_path
= (char *)calloc(1, full_path_len
);
1154 if (full_path
!= NULL
)
1155 (void) snprintf(full_path
, full_path_len
, "%s:%s",
1158 di_devfs_path_free(devfspath
);
1163 * Produce a string representation of path to di_path_t (pathinfo node). This
1164 * string is identical to di_devfs_path had the device been enumerated under
1165 * the pHCI: it has a base path to pHCI, then uses node_name of client, and
1166 * device unit-address of pathinfo node.
1169 di_path_devfs_path(di_path_t path
)
1171 di_node_t phci_node
;
1172 char *phci_path
, *path_name
, *path_addr
;
1176 if (path
== DI_PATH_NIL
) {
1181 /* get name@addr for path */
1182 path_name
= di_path_node_name(path
);
1183 path_addr
= di_path_bus_addr(path
);
1184 if ((path_name
== NULL
) || (path_addr
== NULL
))
1187 /* base path to pHCI devinfo node */
1188 phci_node
= di_path_phci_node(path
);
1189 if (phci_node
== NULL
)
1191 phci_path
= di_devfs_path(phci_node
);
1192 if (phci_path
== NULL
)
1195 /* make the full string representation of path */
1196 full_path_len
= strlen(phci_path
) + 1 + strlen(path_name
) +
1197 1 + strlen(path_addr
) + 1;
1198 full_path
= (char *)calloc(1, full_path_len
);
1200 if (full_path
!= NULL
)
1201 (void) snprintf(full_path
, full_path_len
, "%s/%s@%s",
1202 phci_path
, path_name
, path_addr
);
1203 di_devfs_path_free(phci_path
);
1208 di_path_client_devfs_path(di_path_t path
)
1210 return (di_devfs_path(di_path_client_node(path
)));
1214 di_devfs_path_free(char *buf
)
1217 DPRINTF((DI_ERR
, "di_devfs_path_free NULL arg!\n"));
1225 * Return 1 if name is a IEEE-1275 generic name. If new generic
1226 * names are defined, they should be added to this table
1229 is_generic(const char *name
, int len
)
1233 /* from IEEE-1275 recommended practices section 3 */
1234 static const char *generic_names
[] = {
1245 "interrupt-controller",
1268 for (gp
= generic_names
; *gp
; gp
++) {
1269 if ((strncmp(*gp
, name
, len
) == 0) &&
1270 (strlen(*gp
) == len
))
1277 * Determine if two paths below /devices refer to the same device, ignoring
1278 * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*".
1279 * Return 1 if the paths match.
1282 di_devfs_path_match(const char *dp1
, const char *dp2
)
1284 const char *p1
, *p2
;
1285 const char *ec1
, *ec2
;
1286 const char *at1
, *at2
;
1290 /* progress through both strings */
1291 for (p1
= dp1
, p2
= dp2
; (*p1
== *p2
) && *p1
; p1
++, p2
++) {
1292 /* require match until the start of a component */
1296 /* advance p1 and p2 to start of 'name' in component */
1298 if ((nc
== '\0') || (nc
== '/'))
1299 continue; /* skip trash */
1304 * Both p1 and p2 point to beginning of 'name' in component.
1305 * Determine where current component ends: next '/' or '\0'.
1307 ec1
= strchr(p1
, '/');
1309 ec1
= p1
+ strlen(p1
);
1310 ec2
= strchr(p2
, '/');
1312 ec2
= p2
+ strlen(p2
);
1314 /* Determine where name ends based on whether '@' exists */
1315 at1
= strchr(p1
, '@');
1316 at2
= strchr(p2
, '@');
1317 if (at1
&& (at1
< ec1
))
1319 if (at2
&& (at2
< ec2
))
1323 * At this point p[12] point to beginning of name and
1324 * ec[12] point to character past the end of name. Determine
1325 * if the names are generic.
1327 g1
= is_generic(p1
, ec1
- p1
);
1328 g2
= is_generic(p2
, ec2
- p2
);
1332 * one generic and one non-generic
1333 * skip past the names in the match.
1343 return ((*p1
== *p2
) ? 1 : 0);
1346 /* minor data access */
1348 di_minor_next(di_node_t node
, di_minor_t minor
)
1353 * paranoid error checking
1355 if (node
== DI_NODE_NIL
) {
1357 return (DI_MINOR_NIL
);
1363 if (minor
!= DI_MINOR_NIL
) {
1364 if (DI_MINOR(minor
)->next
!= 0)
1365 return ((di_minor_t
)((void *)((caddr_t
)minor
-
1366 DI_MINOR(minor
)->self
+ DI_MINOR(minor
)->next
)));
1369 return (DI_MINOR_NIL
);
1374 * minor is NIL-->caller asks for first minor node
1376 if (DI_NODE(node
)->minor_data
!= 0) {
1377 return (DI_MINOR((caddr_t
)node
- DI_NODE(node
)->self
+
1378 DI_NODE(node
)->minor_data
));
1382 * no minor data-->check if snapshot includes minor data
1383 * in order to set the correct errno
1385 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1386 if (DINFOMINOR
& DI_ALL(pa
)->command
)
1391 return (DI_MINOR_NIL
);
1394 /* private interface for dealing with alias minor link generation */
1396 di_minor_devinfo(di_minor_t minor
)
1398 if (minor
== DI_MINOR_NIL
) {
1400 return (DI_NODE_NIL
);
1403 return (DI_NODE((caddr_t
)minor
- DI_MINOR(minor
)->self
+
1404 DI_MINOR(minor
)->node
));
1408 di_minor_type(di_minor_t minor
)
1410 return (DI_MINOR(minor
)->type
);
1414 di_minor_name(di_minor_t minor
)
1416 if (DI_MINOR(minor
)->name
== 0)
1419 return ((caddr_t
)minor
- DI_MINOR(minor
)->self
+ DI_MINOR(minor
)->name
);
1423 di_minor_devt(di_minor_t minor
)
1425 return (makedev(DI_MINOR(minor
)->dev_major
,
1426 DI_MINOR(minor
)->dev_minor
));
1430 di_minor_spectype(di_minor_t minor
)
1432 return (DI_MINOR(minor
)->spec_type
);
1436 di_minor_nodetype(di_minor_t minor
)
1438 if (DI_MINOR(minor
)->node_type
== 0)
1441 return ((caddr_t
)minor
-
1442 DI_MINOR(minor
)->self
+ DI_MINOR(minor
)->node_type
);
1446 * Single public interface for accessing software properties
1449 di_prop_next(di_node_t node
, di_prop_t prop
)
1451 int list
= DI_PROP_DRV_LIST
;
1456 if (node
== DI_NODE_NIL
) {
1458 return (DI_PROP_NIL
);
1462 * Find which prop list we are at
1464 if (prop
!= DI_PROP_NIL
)
1465 list
= DI_PROP(prop
)->prop_list
;
1469 case DI_PROP_DRV_LIST
:
1470 prop
= di_prop_drv_next(node
, prop
);
1472 case DI_PROP_SYS_LIST
:
1473 prop
= di_prop_sys_next(node
, prop
);
1475 case DI_PROP_GLB_LIST
:
1476 prop
= di_prop_global_next(node
, prop
);
1478 case DI_PROP_HW_LIST
:
1479 prop
= di_prop_hw_next(node
, prop
);
1481 default: /* shouldn't happen */
1483 return (DI_PROP_NIL
);
1485 } while ((prop
== DI_PROP_NIL
) && (list
<= DI_PROP_HW_LIST
));
1491 di_prop_devt(di_prop_t prop
)
1493 return (makedev(DI_PROP(prop
)->dev_major
, DI_PROP(prop
)->dev_minor
));
1497 di_prop_name(di_prop_t prop
)
1499 if (DI_PROP(prop
)->prop_name
== 0)
1502 return ((caddr_t
)prop
- DI_PROP(prop
)->self
+ DI_PROP(prop
)->prop_name
);
1506 di_prop_type(di_prop_t prop
)
1508 uint_t flags
= DI_PROP(prop
)->prop_flags
;
1510 if (flags
& DDI_PROP_UNDEF_IT
)
1511 return (DI_PROP_TYPE_UNDEF_IT
);
1513 if (DI_PROP(prop
)->prop_len
== 0)
1514 return (DI_PROP_TYPE_BOOLEAN
);
1516 if ((flags
& DDI_PROP_TYPE_MASK
) == DDI_PROP_TYPE_ANY
)
1517 return (DI_PROP_TYPE_UNKNOWN
);
1519 if (flags
& DDI_PROP_TYPE_INT
)
1520 return (DI_PROP_TYPE_INT
);
1522 if (flags
& DDI_PROP_TYPE_INT64
)
1523 return (DI_PROP_TYPE_INT64
);
1525 if (flags
& DDI_PROP_TYPE_STRING
)
1526 return (DI_PROP_TYPE_STRING
);
1528 if (flags
& DDI_PROP_TYPE_BYTE
)
1529 return (DI_PROP_TYPE_BYTE
);
1532 * Shouldn't get here. In case we do, return unknown type.
1534 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
1535 * to add DI_PROP_TYPE_COMPOSITE.
1537 DPRINTF((DI_ERR
, "Unimplemented property type: 0x%x\n", flags
));
1539 return (DI_PROP_TYPE_UNKNOWN
);
1543 * Extract type-specific values of an property
1545 extern int di_prop_decode_common(void *prop_data
, int len
,
1546 int ddi_type
, int prom
);
1549 di_prop_ints(di_prop_t prop
, int **prop_data
)
1551 if (DI_PROP(prop
)->prop_len
== 0)
1552 return (0); /* boolean property */
1554 if ((DI_PROP(prop
)->prop_data
== 0) ||
1555 (DI_PROP(prop
)->prop_data
== (di_off_t
)-1)) {
1561 *prop_data
= (int *)((void *)((caddr_t
)prop
- DI_PROP(prop
)->self
1562 + DI_PROP(prop
)->prop_data
));
1564 return (di_prop_decode_common((void *)prop_data
,
1565 DI_PROP(prop
)->prop_len
, DI_PROP_TYPE_INT
, 0));
1569 di_prop_int64(di_prop_t prop
, int64_t **prop_data
)
1571 if (DI_PROP(prop
)->prop_len
== 0)
1572 return (0); /* boolean property */
1574 if ((DI_PROP(prop
)->prop_data
== 0) ||
1575 (DI_PROP(prop
)->prop_data
== (di_off_t
)-1)) {
1581 *prop_data
= (int64_t *)((void *)((caddr_t
)prop
- DI_PROP(prop
)->self
1582 + DI_PROP(prop
)->prop_data
));
1584 return (di_prop_decode_common((void *)prop_data
,
1585 DI_PROP(prop
)->prop_len
, DI_PROP_TYPE_INT64
, 0));
1589 di_prop_strings(di_prop_t prop
, char **prop_data
)
1591 if (DI_PROP(prop
)->prop_len
== 0)
1592 return (0); /* boolean property */
1594 if ((DI_PROP(prop
)->prop_data
== 0) ||
1595 (DI_PROP(prop
)->prop_data
== (di_off_t
)-1)) {
1601 *prop_data
= (char *)((caddr_t
)prop
- DI_PROP(prop
)->self
1602 + DI_PROP(prop
)->prop_data
);
1604 return (di_prop_decode_common((void *)prop_data
,
1605 DI_PROP(prop
)->prop_len
, DI_PROP_TYPE_STRING
, 0));
1609 di_prop_bytes(di_prop_t prop
, uchar_t
**prop_data
)
1611 if (DI_PROP(prop
)->prop_len
== 0)
1612 return (0); /* boolean property */
1614 if ((DI_PROP(prop
)->prop_data
== 0) ||
1615 (DI_PROP(prop
)->prop_data
== (di_off_t
)-1)) {
1621 *prop_data
= (uchar_t
*)((caddr_t
)prop
- DI_PROP(prop
)->self
1622 + DI_PROP(prop
)->prop_data
);
1624 return (di_prop_decode_common((void *)prop_data
,
1625 DI_PROP(prop
)->prop_len
, DI_PROP_TYPE_BYTE
, 0));
1629 * returns 1 for match, 0 for no match
1632 match_prop(di_prop_t prop
, dev_t match_dev
, const char *name
, int type
)
1637 if (di_prop_name(prop
) == NULL
) {
1638 DPRINTF((DI_ERR
, "libdevinfo: property has no name!\n"));
1643 if (strcmp(name
, di_prop_name(prop
)) != 0)
1646 if ((match_dev
!= DDI_DEV_T_ANY
) && (di_prop_devt(prop
) != match_dev
))
1650 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
1652 prop_type
= di_prop_type(prop
);
1653 if ((prop_type
!= DI_PROP_TYPE_UNKNOWN
) && (prop_type
!= type
) &&
1654 (prop_type
!= DI_PROP_TYPE_BOOLEAN
))
1661 di_prop_search(dev_t match_dev
, di_node_t node
, const char *name
,
1664 di_prop_t prop
= DI_PROP_NIL
;
1667 * The check on match_dev follows ddi_prop_lookup_common().
1668 * Other checks are libdevinfo specific implementation.
1670 if ((node
== DI_NODE_NIL
) || (name
== NULL
) || (strlen(name
) == 0) ||
1671 (match_dev
== DDI_DEV_T_NONE
) || !DI_PROP_TYPE_VALID(type
)) {
1673 return (DI_PROP_NIL
);
1676 while ((prop
= di_prop_next(node
, prop
)) != DI_PROP_NIL
) {
1677 DPRINTF((DI_TRACE1
, "match prop name %s, devt 0x%lx, type %d\n",
1678 di_prop_name(prop
), di_prop_devt(prop
),
1679 di_prop_type(prop
)));
1680 if (match_prop(prop
, match_dev
, name
, type
))
1684 return (DI_PROP_NIL
);
1688 di_prop_find(dev_t match_dev
, di_node_t node
, const char *name
)
1690 di_prop_t prop
= DI_PROP_NIL
;
1692 if ((node
== DI_NODE_NIL
) || (name
== NULL
) || (strlen(name
) == 0) ||
1693 (match_dev
== DDI_DEV_T_NONE
)) {
1695 return (DI_PROP_NIL
);
1698 while ((prop
= di_prop_next(node
, prop
)) != DI_PROP_NIL
) {
1699 DPRINTF((DI_TRACE1
, "found prop name %s, devt 0x%lx, type %d\n",
1700 di_prop_name(prop
), di_prop_devt(prop
),
1701 di_prop_type(prop
)));
1703 if (strcmp(name
, di_prop_name(prop
)) == 0 &&
1704 (match_dev
== DDI_DEV_T_ANY
||
1705 di_prop_devt(prop
) == match_dev
))
1709 return (DI_PROP_NIL
);
1713 di_prop_lookup_ints(dev_t dev
, di_node_t node
, const char *prop_name
,
1718 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1719 DI_PROP_TYPE_INT
)) == DI_PROP_NIL
)
1722 return (di_prop_ints(prop
, (void *)prop_data
));
1726 di_prop_lookup_int64(dev_t dev
, di_node_t node
, const char *prop_name
,
1727 int64_t **prop_data
)
1731 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1732 DI_PROP_TYPE_INT64
)) == DI_PROP_NIL
)
1735 return (di_prop_int64(prop
, (void *)prop_data
));
1739 di_prop_lookup_strings(dev_t dev
, di_node_t node
, const char *prop_name
,
1744 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1745 DI_PROP_TYPE_STRING
)) == DI_PROP_NIL
)
1748 return (di_prop_strings(prop
, (void *)prop_data
));
1752 di_prop_lookup_bytes(dev_t dev
, di_node_t node
, const char *prop_name
,
1753 uchar_t
**prop_data
)
1757 if ((prop
= di_prop_search(dev
, node
, prop_name
,
1758 DI_PROP_TYPE_BYTE
)) == DI_PROP_NIL
)
1761 return (di_prop_bytes(prop
, (void *)prop_data
));
1765 * Consolidation private property access functions
1775 di_prop_next_common(di_node_t node
, di_prop_t prop
, int prop_type
)
1778 di_off_t prop_off
= 0;
1780 if (prop
!= DI_PROP_NIL
) {
1781 if (DI_PROP(prop
)->next
) {
1782 return (DI_PROP((caddr_t
)prop
-
1783 DI_PROP(prop
)->self
+ DI_PROP(prop
)->next
));
1785 return (DI_PROP_NIL
);
1791 * prop is NIL, caller asks for first property
1793 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1794 switch (prop_type
) {
1796 prop_off
= DI_NODE(node
)->drv_prop
;
1799 prop_off
= DI_NODE(node
)->sys_prop
;
1802 prop_off
= DI_NODE(node
)->hw_prop
;
1804 case PROP_TYPE_GLOB
:
1805 prop_off
= DI_NODE(node
)->glob_prop
;
1806 if (prop_off
== -1) {
1807 /* no global property */
1809 } else if ((prop_off
== 0) && (DI_NODE(node
)->drv_major
>= 0)) {
1810 /* refer to devnames array */
1811 struct di_devnm
*devnm
= DI_DEVNM(pa
+
1812 DI_ALL(pa
)->devnames
+ (DI_NODE(node
)->drv_major
*
1813 sizeof (struct di_devnm
)));
1814 prop_off
= devnm
->global_prop
;
1820 return (DI_PROP(pa
+ prop_off
));
1824 * no prop found. Check the reason for not found
1826 if (DINFOPROP
& DI_ALL(pa
)->command
)
1831 return (DI_PROP_NIL
);
1835 di_prop_drv_next(di_node_t node
, di_prop_t prop
)
1837 return (di_prop_next_common(node
, prop
, PROP_TYPE_DRV
));
1841 di_prop_sys_next(di_node_t node
, di_prop_t prop
)
1843 return (di_prop_next_common(node
, prop
, PROP_TYPE_SYS
));
1847 di_prop_global_next(di_node_t node
, di_prop_t prop
)
1849 return (di_prop_next_common(node
, prop
, PROP_TYPE_GLOB
));
1853 di_prop_hw_next(di_node_t node
, di_prop_t prop
)
1855 return (di_prop_next_common(node
, prop
, PROP_TYPE_HW
));
1859 di_prop_rawdata(di_prop_t prop
, uchar_t
**prop_data
)
1862 if (prop
== DI_PROP_NIL
) {
1868 if (DI_PROP(prop
)->prop_len
== 0) {
1873 if ((DI_PROP(prop
)->prop_data
== 0) ||
1874 (DI_PROP(prop
)->prop_data
== (di_off_t
)-1)) {
1881 * No memory allocation.
1883 *prop_data
= (uchar_t
*)((caddr_t
)prop
- DI_PROP(prop
)->self
+
1884 DI_PROP(prop
)->prop_data
);
1886 return (DI_PROP(prop
)->prop_len
);
1890 * Consolidation private interfaces for accessing I/O multipathing data
1893 di_path_phci_next_path(di_node_t node
, di_path_t path
)
1900 if (path
!= DI_PATH_NIL
) {
1901 if (DI_PATH(path
)->path_p_link
!= 0)
1902 return (DI_PATH((void *)((caddr_t
)path
-
1903 DI_PATH(path
)->self
+ DI_PATH(path
)->path_p_link
)));
1906 return (DI_PATH_NIL
);
1911 * Path is NIL; the caller is asking for the first path info node
1913 if (DI_NODE(node
)->multipath_phci
!= 0) {
1914 DPRINTF((DI_INFO
, "phci_next_path: returning %p\n",
1916 DI_NODE(node
)->self
+ DI_NODE(node
)->multipath_phci
)));
1917 return (DI_PATH((caddr_t
)node
- DI_NODE(node
)->self
+
1918 DI_NODE(node
)->multipath_phci
));
1922 * No pathing data; check if the snapshot includes path data in order
1923 * to set errno properly.
1925 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1926 if (DINFOPATH
& (DI_ALL(pa
)->command
))
1931 return (DI_PATH_NIL
);
1935 di_path_client_next_path(di_node_t node
, di_path_t path
)
1942 if (path
!= DI_PATH_NIL
) {
1943 if (DI_PATH(path
)->path_c_link
!= 0)
1944 return (DI_PATH((caddr_t
)path
- DI_PATH(path
)->self
1945 + DI_PATH(path
)->path_c_link
));
1948 return (DI_PATH_NIL
);
1953 * Path is NIL; the caller is asking for the first path info node
1955 if (DI_NODE(node
)->multipath_client
!= 0) {
1956 DPRINTF((DI_INFO
, "client_next_path: returning %p\n",
1958 DI_NODE(node
)->self
+ DI_NODE(node
)->multipath_client
)));
1959 return (DI_PATH((caddr_t
)node
- DI_NODE(node
)->self
+
1960 DI_NODE(node
)->multipath_client
));
1964 * No pathing data; check if the snapshot includes path data in order
1965 * to set errno properly.
1967 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
1968 if (DINFOPATH
& (DI_ALL(pa
)->command
))
1973 return (DI_PATH_NIL
);
1977 * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
1978 * below after NWS consolidation switches to using di_path_bus_addr,
1979 * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
1982 di_path_addr(di_path_t path
, char *buf
)
1984 caddr_t pa
; /* starting address of map */
1986 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
1988 (void) strncpy(buf
, (char *)(pa
+ DI_PATH(path
)->path_addr
),
1993 di_path_next(di_node_t node
, di_path_t path
)
1995 if (node
== DI_NODE_NIL
) {
1997 return (DI_PATH_NIL
);
2000 if (DI_NODE(node
)->multipath_client
) {
2001 return (di_path_client_next_path(node
, path
));
2002 } else if (DI_NODE(node
)->multipath_phci
) {
2003 return (di_path_phci_next_path(node
, path
));
2006 * The node had multipathing data but didn't appear to be a
2007 * phci *or* a client; probably a programmer error.
2010 return (DI_PATH_NIL
);
2014 di_path_next_phci(di_node_t node
, di_path_t path
)
2016 return (di_path_client_next_path(node
, path
));
2019 di_path_next_client(di_node_t node
, di_path_t path
)
2021 return (di_path_phci_next_path(node
, path
));
2028 di_path_state(di_path_t path
)
2030 return ((di_path_state_t
)DI_PATH(path
)->path_state
);
2034 di_path_flags(di_path_t path
)
2036 return (DI_PATH(path
)->path_flags
);
2040 di_path_node_name(di_path_t path
)
2042 di_node_t client_node
;
2044 /* pathinfo gets node_name from client */
2045 if ((client_node
= di_path_client_node(path
)) == NULL
)
2047 return (di_node_name(client_node
));
2051 di_path_bus_addr(di_path_t path
)
2053 caddr_t pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2055 if (DI_PATH(path
)->path_addr
== 0)
2058 return ((char *)(pa
+ DI_PATH(path
)->path_addr
));
2062 di_path_instance(di_path_t path
)
2064 return (DI_PATH(path
)->path_instance
);
2068 di_path_client_node(di_path_t path
)
2070 caddr_t pa
; /* starting address of map */
2072 if (path
== DI_PATH_NIL
) {
2074 return (DI_PATH_NIL
);
2077 DPRINTF((DI_TRACE
, "Get client node for path %p\n", path
));
2079 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2081 if (DI_PATH(path
)->path_client
) {
2082 return (DI_NODE(pa
+ DI_PATH(path
)->path_client
));
2086 * Deal with error condition:
2087 * If parent doesn't exist and node is not the root,
2088 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2090 if ((DI_PATH(path
)->path_snap_state
& DI_PATH_SNAP_NOCLIENT
) == 0)
2095 return (DI_NODE_NIL
);
2099 di_path_phci_node(di_path_t path
)
2101 caddr_t pa
; /* starting address of map */
2103 if (path
== DI_PATH_NIL
) {
2105 return (DI_PATH_NIL
);
2108 DPRINTF((DI_TRACE
, "Get phci node for path %p\n", path
));
2110 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2112 if (DI_PATH(path
)->path_phci
) {
2113 return (DI_NODE(pa
+ DI_PATH(path
)->path_phci
));
2117 * Deal with error condition:
2118 * If parent doesn't exist and node is not the root,
2119 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2121 if ((DI_PATH(path
)->path_snap_state
& DI_PATH_SNAP_NOPHCI
) == 0)
2126 return (DI_NODE_NIL
);
2130 di_path_prop_next(di_path_t path
, di_path_prop_t prop
)
2134 if (path
== DI_PATH_NIL
) {
2136 return (DI_PROP_NIL
);
2142 if (prop
!= DI_PROP_NIL
) {
2143 if (DI_PROP(prop
)->next
!= 0)
2144 return (DI_PATHPROP((caddr_t
)prop
-
2145 DI_PROP(prop
)->self
+ DI_PROP(prop
)->next
));
2148 return (DI_PROP_NIL
);
2153 * prop is NIL-->caller asks for first property
2155 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2156 if (DI_PATH(path
)->path_prop
!= 0) {
2157 return (DI_PATHPROP(pa
+ DI_PATH(path
)->path_prop
));
2161 * no property data-->check if snapshot includes props
2162 * in order to set the correct errno
2164 if (DINFOPROP
& (DI_ALL(pa
)->command
))
2169 return (DI_PROP_NIL
);
2173 di_path_prop_name(di_path_prop_t prop
)
2175 caddr_t pa
; /* starting address of map */
2176 pa
= (caddr_t
)prop
- DI_PATHPROP(prop
)->self
;
2177 return ((char *)(pa
+ DI_PATHPROP(prop
)->prop_name
));
2181 di_path_prop_len(di_path_prop_t prop
)
2183 return (DI_PATHPROP(prop
)->prop_len
);
2187 di_path_prop_type(di_path_prop_t prop
)
2189 switch (DI_PATHPROP(prop
)->prop_type
) {
2190 case DDI_PROP_TYPE_INT
:
2191 return (DI_PROP_TYPE_INT
);
2192 case DDI_PROP_TYPE_INT64
:
2193 return (DI_PROP_TYPE_INT64
);
2194 case DDI_PROP_TYPE_BYTE
:
2195 return (DI_PROP_TYPE_BYTE
);
2196 case DDI_PROP_TYPE_STRING
:
2197 return (DI_PROP_TYPE_STRING
);
2199 return (DI_PROP_TYPE_UNKNOWN
);
2203 di_path_prop_bytes(di_path_prop_t prop
, uchar_t
**prop_data
)
2205 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2206 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2212 *prop_data
= (uchar_t
*)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2213 + DI_PATHPROP(prop
)->prop_data
);
2215 return (di_prop_decode_common((void *)prop_data
,
2216 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_BYTE
, 0));
2220 di_path_prop_ints(di_path_prop_t prop
, int **prop_data
)
2222 if (DI_PATHPROP(prop
)->prop_len
== 0)
2225 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2226 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2232 *prop_data
= (int *)((void *)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2233 + DI_PATHPROP(prop
)->prop_data
));
2235 return (di_prop_decode_common((void *)prop_data
,
2236 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_INT
, 0));
2240 di_path_prop_int64s(di_path_prop_t prop
, int64_t **prop_data
)
2242 if (DI_PATHPROP(prop
)->prop_len
== 0)
2245 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2246 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2252 *prop_data
= (int64_t *)((void *)((caddr_t
)prop
-
2253 DI_PATHPROP(prop
)->self
+ DI_PATHPROP(prop
)->prop_data
));
2255 return (di_prop_decode_common((void *)prop_data
,
2256 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_INT64
, 0));
2260 di_path_prop_strings(di_path_prop_t prop
, char **prop_data
)
2262 if (DI_PATHPROP(prop
)->prop_len
== 0)
2265 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2266 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2272 *prop_data
= (char *)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2273 + DI_PATHPROP(prop
)->prop_data
);
2275 return (di_prop_decode_common((void *)prop_data
,
2276 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_STRING
, 0));
2279 static di_path_prop_t
2280 di_path_prop_search(di_path_t path
, const char *name
, int type
)
2282 di_path_prop_t prop
= DI_PROP_NIL
;
2285 * Sanity check arguments
2287 if ((path
== DI_PATH_NIL
) || (name
== NULL
) || (strlen(name
) == 0) ||
2288 !DI_PROP_TYPE_VALID(type
)) {
2290 return (DI_PROP_NIL
);
2293 while ((prop
= di_path_prop_next(path
, prop
)) != DI_PROP_NIL
) {
2294 int prop_type
= di_path_prop_type(prop
);
2296 DPRINTF((DI_TRACE1
, "match path prop name %s, type %d\n",
2297 di_path_prop_name(prop
), prop_type
));
2299 if (strcmp(name
, di_path_prop_name(prop
)) != 0)
2302 if ((prop_type
!= DI_PROP_TYPE_UNKNOWN
) && (prop_type
!= type
))
2308 return (DI_PROP_NIL
);
2312 di_path_prop_lookup_bytes(di_path_t path
, const char *prop_name
,
2313 uchar_t
**prop_data
)
2315 di_path_prop_t prop
;
2317 if ((prop
= di_path_prop_search(path
, prop_name
,
2318 DI_PROP_TYPE_BYTE
)) == DI_PROP_NIL
)
2321 return (di_path_prop_bytes(prop
, prop_data
));
2325 di_path_prop_lookup_ints(di_path_t path
, const char *prop_name
,
2328 di_path_prop_t prop
;
2330 if ((prop
= di_path_prop_search(path
, prop_name
,
2331 DI_PROP_TYPE_INT
)) == DI_PROP_NIL
)
2334 return (di_path_prop_ints(prop
, prop_data
));
2338 di_path_prop_lookup_int64s(di_path_t path
, const char *prop_name
,
2339 int64_t **prop_data
)
2341 di_path_prop_t prop
;
2343 if ((prop
= di_path_prop_search(path
, prop_name
,
2344 DI_PROP_TYPE_INT64
)) == DI_PROP_NIL
)
2347 return (di_path_prop_int64s(prop
, prop_data
));
2350 int di_path_prop_lookup_strings(di_path_t path
, const char *prop_name
,
2353 di_path_prop_t prop
;
2355 if ((prop
= di_path_prop_search(path
, prop_name
,
2356 DI_PROP_TYPE_STRING
)) == DI_PROP_NIL
)
2359 return (di_path_prop_strings(prop
, prop_data
));
2363 * Consolidation private interfaces for traversing vhci nodes.
2366 di_vhci_first_node(di_node_t root
)
2369 caddr_t pa
; /* starting address of map */
2371 DPRINTF((DI_INFO
, "Get first vhci node\n"));
2373 if (root
== DI_NODE_NIL
) {
2375 return (DI_NODE_NIL
);
2378 pa
= (caddr_t
)root
- DI_NODE(root
)->self
;
2381 if (dap
->top_vhci_devinfo
== 0) {
2383 return (DI_NODE_NIL
);
2386 return (DI_NODE(pa
+ dap
->top_vhci_devinfo
));
2390 di_vhci_next_node(di_node_t node
)
2392 caddr_t pa
; /* starting address of map */
2394 if (node
== DI_NODE_NIL
) {
2396 return (DI_NODE_NIL
);
2399 DPRINTF((DI_TRACE
, "next vhci node on the snap shot:"
2400 " current=%s\n", di_node_name(node
)));
2402 if (DI_NODE(node
)->next_vhci
== 0) {
2404 return (DI_NODE_NIL
);
2407 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2409 return (DI_NODE(pa
+ DI_NODE(node
)->next_vhci
));
2413 * Consolidation private interfaces for traversing phci nodes.
2416 di_phci_first_node(di_node_t vhci_node
)
2418 caddr_t pa
; /* starting address of map */
2420 DPRINTF((DI_INFO
, "Get first phci node:\n"
2421 " current=%s", di_node_name(vhci_node
)));
2423 if (vhci_node
== DI_NODE_NIL
) {
2425 return (DI_NODE_NIL
);
2428 pa
= (caddr_t
)vhci_node
- DI_NODE(vhci_node
)->self
;
2430 if (DI_NODE(vhci_node
)->top_phci
== 0) {
2432 return (DI_NODE_NIL
);
2435 return (DI_NODE(pa
+ DI_NODE(vhci_node
)->top_phci
));
2439 di_phci_next_node(di_node_t node
)
2441 caddr_t pa
; /* starting address of map */
2443 if (node
== DI_NODE_NIL
) {
2445 return (DI_NODE_NIL
);
2448 DPRINTF((DI_TRACE
, "next phci node on the snap shot:"
2449 " current=%s\n", di_node_name(node
)));
2451 if (DI_NODE(node
)->next_phci
== 0) {
2453 return (DI_NODE_NIL
);
2456 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2458 return (DI_NODE(pa
+ DI_NODE(node
)->next_phci
));
2462 * Consolidation private interfaces for private data
2465 di_parent_private_data(di_node_t node
)
2469 if (DI_NODE(node
)->parent_data
== 0) {
2474 if (DI_NODE(node
)->parent_data
== (di_off_t
)-1) {
2476 * Private data requested, but not obtained due to a memory
2477 * error (e.g. wrong format specified)
2483 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2484 if (DI_NODE(node
)->parent_data
)
2485 return (pa
+ DI_NODE(node
)->parent_data
);
2487 if (DI_ALL(pa
)->command
& DINFOPRIVDATA
)
2496 di_driver_private_data(di_node_t node
)
2500 if (DI_NODE(node
)->driver_data
== 0) {
2505 if (DI_NODE(node
)->driver_data
== (di_off_t
)-1) {
2507 * Private data requested, but not obtained due to a memory
2508 * error (e.g. wrong format specified)
2514 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2515 if (DI_NODE(node
)->driver_data
)
2516 return (pa
+ DI_NODE(node
)->driver_data
);
2518 if (DI_ALL(pa
)->command
& DINFOPRIVDATA
)
2527 * Hotplug information access
2534 int (*hp_callback
)(di_node_t
, di_hp_t
, void *);
2538 di_walk_hp_callback(di_node_t node
, void *argp
)
2540 di_walk_hp_arg_t
*arg
= (di_walk_hp_arg_t
*)argp
;
2544 for (hp
= DI_HP_NIL
; (hp
= di_hp_next(node
, hp
)) != DI_HP_NIL
; ) {
2546 /* Exclude non-matching types if a type filter is specified */
2547 if (arg
->type
!= NULL
) {
2548 type_str
= di_hp_description(hp
);
2549 if (type_str
&& (strcmp(arg
->type
, type_str
) != 0))
2553 /* Exclude ports if DI_HP_PORT flag not specified */
2554 if (!(arg
->flag
& DI_HP_PORT
) &&
2555 (di_hp_type(hp
) == DDI_HP_CN_TYPE_VIRTUAL_PORT
))
2558 /* Exclude connectors if DI_HP_CONNECTOR flag not specified */
2559 if (!(arg
->flag
& DI_HP_CONNECTOR
) &&
2560 !(di_hp_type(hp
) == DDI_HP_CN_TYPE_VIRTUAL_PORT
))
2563 /* Perform callback */
2564 if (arg
->hp_callback(node
, hp
, arg
->arg
) != DI_WALK_CONTINUE
)
2565 return (DI_WALK_TERMINATE
);
2568 return (DI_WALK_CONTINUE
);
2572 di_walk_hp(di_node_t node
, const char *type
, uint_t flag
, void *arg
,
2573 int (*hp_callback
)(di_node_t node
, di_hp_t hp
, void *arg
))
2575 di_walk_hp_arg_t walk_arg
;
2579 char *devfspath
= di_devfs_path(node
);
2580 DPRINTF((DI_INFO
, "walking hotplug nodes under %s\n", devfspath
));
2581 di_devfs_path_free(devfspath
);
2584 * paranoid error checking
2586 if ((node
== DI_NODE_NIL
) || (hp_callback
== NULL
)) {
2591 /* check if hotplug data is included in snapshot */
2592 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2593 if (!(DI_ALL(pa
)->command
& DINFOHP
)) {
2599 walk_arg
.type
= type
;
2600 walk_arg
.flag
= flag
;
2601 walk_arg
.hp_callback
= hp_callback
;
2602 return (di_walk_node(node
, DI_WALK_CLDFIRST
, &walk_arg
,
2603 di_walk_hp_callback
));
2607 di_hp_next(di_node_t node
, di_hp_t hp
)
2612 * paranoid error checking
2614 if (node
== DI_NODE_NIL
) {
2620 * hotplug node is not NIL
2622 if (hp
!= DI_HP_NIL
) {
2623 if (DI_HP(hp
)->next
!= 0)
2624 return (DI_HP((caddr_t
)hp
- hp
->self
+ hp
->next
));
2632 * hotplug node is NIL-->caller asks for first hotplug node
2634 if (DI_NODE(node
)->hp_data
!= 0) {
2635 return (DI_HP((caddr_t
)node
- DI_NODE(node
)->self
+
2636 DI_NODE(node
)->hp_data
));
2640 * no hotplug data-->check if snapshot includes hotplug data
2641 * in order to set the correct errno
2643 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2644 if (DINFOHP
& DI_ALL(pa
)->command
)
2653 di_hp_name(di_hp_t hp
)
2658 * paranoid error checking
2660 if (hp
== DI_HP_NIL
) {
2665 pa
= (caddr_t
)hp
- DI_HP(hp
)->self
;
2667 if (DI_HP(hp
)->hp_name
== 0) {
2672 return ((char *)(pa
+ DI_HP(hp
)->hp_name
));
2676 di_hp_connection(di_hp_t hp
)
2679 * paranoid error checking
2681 if (hp
== DI_HP_NIL
) {
2686 if (DI_HP(hp
)->hp_connection
== -1)
2689 return (DI_HP(hp
)->hp_connection
);
2693 di_hp_depends_on(di_hp_t hp
)
2696 * paranoid error checking
2698 if (hp
== DI_HP_NIL
) {
2703 if (DI_HP(hp
)->hp_depends_on
== -1)
2706 return (DI_HP(hp
)->hp_depends_on
);
2710 di_hp_state(di_hp_t hp
)
2713 * paranoid error checking
2715 if (hp
== DI_HP_NIL
) {
2720 return (DI_HP(hp
)->hp_state
);
2724 di_hp_type(di_hp_t hp
)
2727 * paranoid error checking
2729 if (hp
== DI_HP_NIL
) {
2734 return (DI_HP(hp
)->hp_type
);
2738 di_hp_description(di_hp_t hp
)
2743 * paranoid error checking
2745 if (hp
== DI_HP_NIL
) {
2750 pa
= (caddr_t
)hp
- DI_HP(hp
)->self
;
2752 if (DI_HP(hp
)->hp_type_str
== 0)
2755 return ((char *)(pa
+ DI_HP(hp
)->hp_type_str
));
2759 di_hp_child(di_hp_t hp
)
2761 caddr_t pa
; /* starting address of map */
2764 * paranoid error checking
2766 if (hp
== DI_HP_NIL
) {
2768 return (DI_NODE_NIL
);
2771 pa
= (caddr_t
)hp
- DI_HP(hp
)->self
;
2773 if (DI_HP(hp
)->hp_child
> 0) {
2774 return (DI_NODE(pa
+ DI_HP(hp
)->hp_child
));
2778 * Deal with error condition:
2779 * Child doesn't exist, figure out if DINFOSUBTREE is set.
2780 * If it isn't, set errno to ENOTSUP.
2782 if (!(DINFOSUBTREE
& DI_ALL(pa
)->command
))
2787 return (DI_NODE_NIL
);
2791 di_hp_last_change(di_hp_t hp
)
2794 * paranoid error checking
2796 if (hp
== DI_HP_NIL
) {
2801 return ((time_t)DI_HP(hp
)->hp_last_change
);
2805 * PROM property access
2809 * openprom driver stuff:
2810 * The maximum property length depends on the buffer size. We use
2811 * OPROMMAXPARAM defined in <sys/openpromio.h>
2813 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2814 * MAXVALSZ is maximum value size, which is whatever space left in buf
2817 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int)
2818 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME;
2820 struct di_prom_prop
{
2824 struct di_prom_prop
*next
; /* form a linked list */
2827 struct di_prom_handle
{ /* handle to prom */
2828 mutex_t lock
; /* synchronize access to openprom fd */
2829 int fd
; /* /dev/openprom file descriptor */
2830 struct di_prom_prop
*list
; /* linked list of prop */
2832 char buf
[OPROMMAXPARAM
];
2833 struct openpromio opp
;
2840 struct di_prom_handle
*p
;
2842 if ((p
= malloc(sizeof (struct di_prom_handle
))) == NULL
)
2843 return (DI_PROM_HANDLE_NIL
);
2845 DPRINTF((DI_INFO
, "di_prom_init: get prom handle 0x%p\n", p
));
2847 (void) mutex_init(&p
->lock
, USYNC_THREAD
, NULL
);
2848 if ((p
->fd
= open("/dev/openprom", O_RDONLY
)) < 0) {
2850 return (DI_PROM_HANDLE_NIL
);
2854 return ((di_prom_handle_t
)p
);
2858 di_prom_prop_free(struct di_prom_prop
*list
)
2860 struct di_prom_prop
*tmp
= list
;
2862 while (tmp
!= NULL
) {
2864 if (tmp
->name
!= NULL
) {
2867 if (tmp
->data
!= NULL
) {
2876 di_prom_fini(di_prom_handle_t ph
)
2878 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2880 DPRINTF((DI_INFO
, "di_prom_fini: free prom handle 0x%p\n", p
));
2882 (void) close(p
->fd
);
2883 (void) mutex_destroy(&p
->lock
);
2884 di_prom_prop_free(p
->list
);
2890 * Internal library interface for locating the property
2891 * XXX: ph->lock must be held for the duration of call.
2893 static di_prom_prop_t
2894 di_prom_prop_found(di_prom_handle_t ph
, int nodeid
,
2895 di_prom_prop_t prom_prop
)
2897 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2898 struct openpromio
*opp
= &p
->oppbuf
.opp
;
2899 int *ip
= (int *)((void *)opp
->oprom_array
);
2900 struct di_prom_prop
*prop
= (struct di_prom_prop
*)prom_prop
;
2902 DPRINTF((DI_TRACE1
, "Looking for nodeid 0x%x\n", nodeid
));
2905 * Set "current" nodeid in the openprom driver
2907 opp
->oprom_size
= sizeof (int);
2909 if (ioctl(p
->fd
, OPROMSETNODEID
, opp
) < 0) {
2910 DPRINTF((DI_ERR
, "*** Nodeid not found 0x%x\n", nodeid
));
2911 return (DI_PROM_PROP_NIL
);
2914 DPRINTF((DI_TRACE
, "Found nodeid 0x%x\n", nodeid
));
2916 bzero(opp
, OBP_MAXBUF
);
2917 opp
->oprom_size
= OBP_MAXPROPNAME
;
2918 if (prom_prop
!= DI_PROM_PROP_NIL
)
2919 (void) strcpy(opp
->oprom_array
, prop
->name
);
2921 if ((ioctl(p
->fd
, OPROMNXTPROP
, opp
) < 0) || (opp
->oprom_size
== 0))
2922 return (DI_PROM_PROP_NIL
);
2925 * Prom property found. Allocate struct for storing prop
2926 * (reuse variable prop)
2928 if ((prop
= malloc(sizeof (struct di_prom_prop
))) == NULL
)
2929 return (DI_PROM_PROP_NIL
);
2932 * Get a copy of property name
2934 if ((prop
->name
= strdup(opp
->oprom_array
)) == NULL
) {
2936 return (DI_PROM_PROP_NIL
);
2940 * get property value and length
2942 opp
->oprom_size
= OBP_MAXPROPLEN
;
2944 if ((ioctl(p
->fd
, OPROMGETPROP
, opp
) < 0) ||
2945 (opp
->oprom_size
== (uint_t
)-1)) {
2948 return (DI_PROM_PROP_NIL
);
2952 * make a copy of the property value
2954 prop
->len
= opp
->oprom_size
;
2958 else if ((prop
->data
= malloc(prop
->len
)) == NULL
) {
2961 return (DI_PROM_PROP_NIL
);
2964 bcopy(opp
->oprom_array
, prop
->data
, prop
->len
);
2967 * Prepend prop to list in prom handle
2969 prop
->next
= p
->list
;
2972 return ((di_prom_prop_t
)prop
);
2976 di_prom_prop_next(di_prom_handle_t ph
, di_node_t node
, di_prom_prop_t prom_prop
)
2978 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2980 DPRINTF((DI_TRACE1
, "Search next prop for node 0x%p with ph 0x%p\n",
2986 if ((ph
== DI_PROM_HANDLE_NIL
) || (node
== DI_NODE_NIL
)) {
2988 return (DI_PROM_PROP_NIL
);
2991 if (di_nodeid(node
) != DI_PROM_NODEID
) {
2993 return (DI_PROM_PROP_NIL
);
2997 * synchronize access to prom file descriptor
2999 (void) mutex_lock(&p
->lock
);
3002 * look for next property
3004 prom_prop
= di_prom_prop_found(ph
, DI_NODE(node
)->nodeid
, prom_prop
);
3006 (void) mutex_unlock(&p
->lock
);
3012 di_prom_prop_name(di_prom_prop_t prom_prop
)
3017 if (prom_prop
== DI_PROM_PROP_NIL
) {
3022 return (((struct di_prom_prop
*)prom_prop
)->name
);
3026 di_prom_prop_data(di_prom_prop_t prom_prop
, uchar_t
**prom_prop_data
)
3031 if (prom_prop
== DI_PROM_PROP_NIL
) {
3036 *prom_prop_data
= ((struct di_prom_prop
*)prom_prop
)->data
;
3038 return (((struct di_prom_prop
*)prom_prop
)->len
);
3042 * Internal library interface for locating the property
3043 * Returns length if found, -1 if prop doesn't exist.
3045 static struct di_prom_prop
*
3046 di_prom_prop_lookup_common(di_prom_handle_t ph
, di_node_t node
,
3047 const char *prom_prop_name
)
3049 struct openpromio
*opp
;
3050 struct di_prom_prop
*prop
;
3051 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
3056 if ((ph
== DI_PROM_HANDLE_NIL
) || (node
== DI_NODE_NIL
)) {
3061 if (di_nodeid(node
) != DI_PROM_NODEID
) {
3066 opp
= &p
->oppbuf
.opp
;
3068 (void) mutex_lock(&p
->lock
);
3070 opp
->oprom_size
= sizeof (int);
3071 opp
->oprom_node
= DI_NODE(node
)->nodeid
;
3072 if (ioctl(p
->fd
, OPROMSETNODEID
, opp
) < 0) {
3074 DPRINTF((DI_ERR
, "*** Nodeid not found 0x%x\n",
3075 DI_NODE(node
)->nodeid
));
3076 (void) mutex_unlock(&p
->lock
);
3081 * get property length
3083 bzero(opp
, OBP_MAXBUF
);
3084 opp
->oprom_size
= OBP_MAXPROPLEN
;
3085 (void) strcpy(opp
->oprom_array
, prom_prop_name
);
3087 if ((ioctl(p
->fd
, OPROMGETPROPLEN
, opp
) < 0) ||
3088 (opp
->oprom_len
== -1)) {
3089 /* no such property */
3090 (void) mutex_unlock(&p
->lock
);
3095 * Prom property found. Allocate struct for storing prop
3097 if ((prop
= malloc(sizeof (struct di_prom_prop
))) == NULL
) {
3098 (void) mutex_unlock(&p
->lock
);
3101 prop
->name
= NULL
; /* we don't need the name */
3102 prop
->len
= opp
->oprom_len
;
3104 if (prop
->len
== 0) { /* boolean property */
3106 prop
->next
= p
->list
;
3108 (void) mutex_unlock(&p
->lock
);
3113 * retrieve the property value
3115 bzero(opp
, OBP_MAXBUF
);
3116 opp
->oprom_size
= OBP_MAXPROPLEN
;
3117 (void) strcpy(opp
->oprom_array
, prom_prop_name
);
3119 if ((ioctl(p
->fd
, OPROMGETPROP
, opp
) < 0) ||
3120 (opp
->oprom_size
== (uint_t
)-1)) {
3121 /* error retrieving property value */
3122 (void) mutex_unlock(&p
->lock
);
3128 * make a copy of the property value, stick in ph->list
3130 if ((prop
->data
= malloc(prop
->len
)) == NULL
) {
3131 (void) mutex_unlock(&p
->lock
);
3136 bcopy(opp
->oprom_array
, prop
->data
, prop
->len
);
3138 prop
->next
= p
->list
;
3140 (void) mutex_unlock(&p
->lock
);
3146 di_prom_prop_lookup_ints(di_prom_handle_t ph
, di_node_t node
,
3147 const char *prom_prop_name
, int **prom_prop_data
)
3150 struct di_prom_prop
*prop
;
3152 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
3155 *prom_prop_data
= NULL
;
3159 if (prop
->len
== 0) { /* boolean property */
3160 *prom_prop_data
= NULL
;
3164 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
3165 DI_PROP_TYPE_INT
, 1);
3166 *prom_prop_data
= (int *)((void *)prop
->data
);
3172 di_prom_prop_lookup_strings(di_prom_handle_t ph
, di_node_t node
,
3173 const char *prom_prop_name
, char **prom_prop_data
)
3176 struct di_prom_prop
*prop
;
3178 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
3181 *prom_prop_data
= NULL
;
3185 if (prop
->len
== 0) { /* boolean property */
3186 *prom_prop_data
= NULL
;
3191 * Fix an openprom bug (OBP string not NULL terminated).
3192 * XXX This should really be fixed in promif.
3194 if (((char *)prop
->data
)[prop
->len
- 1] != '\0') {
3197 if ((tmp
= realloc(prop
->data
, prop
->len
)) == NULL
)
3201 ((char *)prop
->data
)[prop
->len
- 1] = '\0';
3202 DPRINTF((DI_INFO
, "OBP string not NULL terminated: "
3203 "node=%s, prop=%s, val=%s\n",
3204 di_node_name(node
), prom_prop_name
, prop
->data
));
3207 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
3208 DI_PROP_TYPE_STRING
, 1);
3209 *prom_prop_data
= (char *)prop
->data
;
3215 di_prom_prop_lookup_bytes(di_prom_handle_t ph
, di_node_t node
,
3216 const char *prom_prop_name
, uchar_t
**prom_prop_data
)
3219 struct di_prom_prop
*prop
;
3221 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
3224 *prom_prop_data
= NULL
;
3228 if (prop
->len
== 0) { /* boolean property */
3229 *prom_prop_data
= NULL
;
3233 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
3234 DI_PROP_TYPE_BYTE
, 1);
3235 *prom_prop_data
= prop
->data
;
3241 * returns an allocated array through <prop_data> only when its count > 0
3242 * and the number of entries (count) as the function return value;
3243 * use di_slot_names_free() to free the array
3246 di_prop_slot_names(di_prop_t prop
, di_slot_name_t
**prop_data
)
3250 char *nm
= di_prop_name(prop
);
3252 if (nm
== NULL
|| strcmp(DI_PROP_SLOT_NAMES
, nm
) != 0)
3255 rawlen
= di_prop_rawdata(prop
, &rawdata
);
3256 if (rawlen
<= 0 || rawdata
== NULL
)
3259 count
= di_slot_names_decode(rawdata
, rawlen
, prop_data
);
3260 if (count
< 0 || *prop_data
== NULL
)
3272 di_prop_lookup_slot_names(dev_t dev
, di_node_t node
,
3273 di_slot_name_t
**prop_data
)
3278 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
3279 * and slot-names is properly flagged as such
3281 if ((prop
= di_prop_find(dev
, node
, DI_PROP_SLOT_NAMES
)) ==
3287 return (di_prop_slot_names(prop
, (void *)prop_data
));
3291 * returns an allocated array through <prop_data> only when its count > 0
3292 * and the number of entries (count) as the function return value;
3293 * use di_slot_names_free() to free the array
3296 di_prom_prop_slot_names(di_prom_prop_t prom_prop
, di_slot_name_t
**prop_data
)
3301 rawlen
= di_prom_prop_data(prom_prop
, &rawdata
);
3302 if (rawlen
<= 0 || rawdata
== NULL
)
3305 count
= di_slot_names_decode(rawdata
, rawlen
, prop_data
);
3306 if (count
< 0 || *prop_data
== NULL
)
3318 di_prom_prop_lookup_slot_names(di_prom_handle_t ph
, di_node_t node
,
3319 di_slot_name_t
**prop_data
)
3321 struct di_prom_prop
*prom_prop
;
3323 prom_prop
= di_prom_prop_lookup_common(ph
, node
, DI_PROP_SLOT_NAMES
);
3324 if (prom_prop
== NULL
) {
3329 return (di_prom_prop_slot_names(prom_prop
, prop_data
));
3333 di_link_to_lnode(di_link_t link
, uint_t endpoint
)
3335 struct di_all
*di_all
;
3337 if ((link
== DI_LINK_NIL
) ||
3338 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3340 return (DI_LNODE_NIL
);
3343 di_all
= DI_ALL((caddr_t
)link
- DI_LINK(link
)->self
);
3345 if (endpoint
== DI_LINK_SRC
) {
3346 return (DI_LNODE((caddr_t
)di_all
+ DI_LINK(link
)->src_lnode
));
3348 return (DI_LNODE((caddr_t
)di_all
+ DI_LINK(link
)->tgt_lnode
));
3354 di_lnode_name(di_lnode_t lnode
)
3356 return (di_driver_name(di_lnode_devinfo(lnode
)));
3360 di_lnode_devinfo(di_lnode_t lnode
)
3362 struct di_all
*di_all
;
3364 di_all
= DI_ALL((caddr_t
)lnode
- DI_LNODE(lnode
)->self
);
3365 return (DI_NODE((caddr_t
)di_all
+ DI_LNODE(lnode
)->node
));
3369 di_lnode_devt(di_lnode_t lnode
, dev_t
*devt
)
3371 if ((lnode
== DI_LNODE_NIL
) || (devt
== NULL
)) {
3375 if ((DI_LNODE(lnode
)->dev_major
== (major_t
)-1) &&
3376 (DI_LNODE(lnode
)->dev_minor
== (minor_t
)-1))
3379 *devt
= makedev(DI_LNODE(lnode
)->dev_major
, DI_LNODE(lnode
)->dev_minor
);
3384 di_link_spectype(di_link_t link
)
3386 return (DI_LINK(link
)->spec_type
);
3390 di_minor_private_set(di_minor_t minor
, void *data
)
3392 DI_MINOR(minor
)->user_private_data
= (uintptr_t)data
;
3396 di_minor_private_get(di_minor_t minor
)
3398 return ((void *)(uintptr_t)DI_MINOR(minor
)->user_private_data
);
3402 di_node_private_set(di_node_t node
, void *data
)
3404 DI_NODE(node
)->user_private_data
= (uintptr_t)data
;
3408 di_node_private_get(di_node_t node
)
3410 return ((void *)(uintptr_t)DI_NODE(node
)->user_private_data
);
3414 di_path_private_set(di_path_t path
, void *data
)
3416 DI_PATH(path
)->user_private_data
= (uintptr_t)data
;
3420 di_path_private_get(di_path_t path
)
3422 return ((void *)(uintptr_t)DI_PATH(path
)->user_private_data
);
3426 di_lnode_private_set(di_lnode_t lnode
, void *data
)
3428 DI_LNODE(lnode
)->user_private_data
= (uintptr_t)data
;
3432 di_lnode_private_get(di_lnode_t lnode
)
3434 return ((void *)(uintptr_t)DI_LNODE(lnode
)->user_private_data
);
3438 di_link_private_set(di_link_t link
, void *data
)
3440 DI_LINK(link
)->user_private_data
= (uintptr_t)data
;
3444 di_link_private_get(di_link_t link
)
3446 return ((void *)(uintptr_t)DI_LINK(link
)->user_private_data
);
3450 di_lnode_next(di_node_t node
, di_lnode_t lnode
)
3452 struct di_all
*di_all
;
3455 * paranoid error checking
3457 if (node
== DI_NODE_NIL
) {
3459 return (DI_LNODE_NIL
);
3462 di_all
= DI_ALL((caddr_t
)node
- DI_NODE(node
)->self
);
3464 if (lnode
== DI_NODE_NIL
) {
3465 if (DI_NODE(node
)->lnodes
!= 0)
3466 return (DI_LNODE((caddr_t
)di_all
+
3467 DI_NODE(node
)->lnodes
));
3469 if (DI_LNODE(lnode
)->node_next
!= 0)
3470 return (DI_LNODE((caddr_t
)di_all
+
3471 DI_LNODE(lnode
)->node_next
));
3474 if (DINFOLYR
& DI_ALL(di_all
)->command
)
3479 return (DI_LNODE_NIL
);
3483 di_link_next_by_node(di_node_t node
, di_link_t link
, uint_t endpoint
)
3485 struct di_all
*di_all
;
3488 * paranoid error checking
3490 if ((node
== DI_NODE_NIL
) ||
3491 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3493 return (DI_LINK_NIL
);
3496 di_all
= DI_ALL((caddr_t
)node
- DI_NODE(node
)->self
);
3498 if (endpoint
== DI_LINK_SRC
) {
3499 if (link
== DI_LINK_NIL
) {
3500 if (DI_NODE(node
)->src_links
!= 0)
3501 return (DI_LINK((caddr_t
)di_all
+
3502 DI_NODE(node
)->src_links
));
3504 if (DI_LINK(link
)->src_node_next
!= 0)
3505 return (DI_LINK((caddr_t
)di_all
+
3506 DI_LINK(link
)->src_node_next
));
3509 if (link
== DI_LINK_NIL
) {
3510 if (DI_NODE(node
)->tgt_links
!= 0)
3511 return (DI_LINK((caddr_t
)di_all
+
3512 DI_NODE(node
)->tgt_links
));
3514 if (DI_LINK(link
)->tgt_node_next
!= 0)
3515 return (DI_LINK((caddr_t
)di_all
+
3516 DI_LINK(link
)->tgt_node_next
));
3520 if (DINFOLYR
& DI_ALL(di_all
)->command
)
3525 return (DI_LINK_NIL
);
3529 di_link_next_by_lnode(di_lnode_t lnode
, di_link_t link
, uint_t endpoint
)
3531 struct di_all
*di_all
;
3534 * paranoid error checking
3536 if ((lnode
== DI_LNODE_NIL
) ||
3537 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3539 return (DI_LINK_NIL
);
3542 di_all
= DI_ALL((caddr_t
)lnode
- DI_LNODE(lnode
)->self
);
3544 if (endpoint
== DI_LINK_SRC
) {
3545 if (link
== DI_LINK_NIL
) {
3546 if (DI_LNODE(lnode
)->link_out
== 0)
3547 return (DI_LINK_NIL
);
3548 return (DI_LINK((caddr_t
)di_all
+
3549 DI_LNODE(lnode
)->link_out
));
3551 if (DI_LINK(link
)->src_link_next
== 0)
3552 return (DI_LINK_NIL
);
3553 return (DI_LINK((caddr_t
)di_all
+
3554 DI_LINK(link
)->src_link_next
));
3557 if (link
== DI_LINK_NIL
) {
3558 if (DI_LNODE(lnode
)->link_in
== 0)
3559 return (DI_LINK_NIL
);
3560 return (DI_LINK((caddr_t
)di_all
+
3561 DI_LNODE(lnode
)->link_in
));
3563 if (DI_LINK(link
)->tgt_link_next
== 0)
3564 return (DI_LINK_NIL
);
3565 return (DI_LINK((caddr_t
)di_all
+
3566 DI_LINK(link
)->tgt_link_next
));
3573 * Internal library function:
3574 * Invoke callback for each link data on the link list of first node
3575 * on node_list headp, and place children of first node on the list.
3577 * This is similar to walk_one_node, except we only walk in child
3581 walk_one_link(struct node_list
**headp
, uint_t ep
,
3582 void *arg
, int (*callback
)(di_link_t link
, void *arg
))
3584 int action
= DI_WALK_CONTINUE
;
3585 di_link_t link
= DI_LINK_NIL
;
3586 di_node_t node
= (*headp
)->node
;
3588 while ((link
= di_link_next_by_node(node
, link
, ep
)) != DI_LINK_NIL
) {
3589 action
= callback(link
, arg
);
3590 if (action
== DI_WALK_TERMINATE
) {
3595 update_node_list(action
, DI_WALK_LINKGEN
, headp
);
3599 di_walk_link(di_node_t root
, uint_t flag
, uint_t endpoint
, void *arg
,
3600 int (*link_callback
)(di_link_t link
, void *arg
))
3602 struct node_list
*head
; /* node_list for tree walk */
3605 char *devfspath
= di_devfs_path(root
);
3606 DPRINTF((DI_INFO
, "walking %s link data under %s\n",
3607 (endpoint
== DI_LINK_SRC
) ? "src" : "tgt", devfspath
));
3608 di_devfs_path_free(devfspath
);
3612 * paranoid error checking
3614 if ((root
== DI_NODE_NIL
) || (link_callback
== NULL
) || (flag
!= 0) ||
3615 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3620 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
3621 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
3628 DPRINTF((DI_INFO
, "Start link data walking from node %s\n",
3629 di_node_name(root
)));
3631 while (head
!= NULL
)
3632 walk_one_link(&head
, endpoint
, arg
, link_callback
);
3638 * Internal library function:
3639 * Invoke callback for each link data on the link list of first node
3640 * on node_list headp, and place children of first node on the list.
3642 * This is similar to walk_one_node, except we only walk in child
3646 walk_one_lnode(struct node_list
**headp
, void *arg
,
3647 int (*callback
)(di_lnode_t lnode
, void *arg
))
3649 int action
= DI_WALK_CONTINUE
;
3650 di_lnode_t lnode
= DI_LNODE_NIL
;
3651 di_node_t node
= (*headp
)->node
;
3653 while ((lnode
= di_lnode_next(node
, lnode
)) != DI_LNODE_NIL
) {
3654 action
= callback(lnode
, arg
);
3655 if (action
== DI_WALK_TERMINATE
) {
3660 update_node_list(action
, DI_WALK_LINKGEN
, headp
);
3664 di_walk_lnode(di_node_t root
, uint_t flag
, void *arg
,
3665 int (*lnode_callback
)(di_lnode_t lnode
, void *arg
))
3667 struct node_list
*head
; /* node_list for tree walk */
3670 char *devfspath
= di_devfs_path(root
);
3671 DPRINTF((DI_INFO
, "walking lnode data under %s\n", devfspath
));
3672 di_devfs_path_free(devfspath
);
3676 * paranoid error checking
3678 if ((root
== DI_NODE_NIL
) || (lnode_callback
== NULL
) || (flag
!= 0)) {
3683 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
3684 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
3691 DPRINTF((DI_INFO
, "Start lnode data walking from node %s\n",
3692 di_node_name(root
)));
3694 while (head
!= NULL
)
3695 walk_one_lnode(&head
, arg
, lnode_callback
);
3701 alias_to_curr(di_node_t anynode
, char *devfspath
, di_node_t
*nodep
)
3705 struct di_alias
*di_alias
;
3711 char buf
[MAXPATHLEN
];
3715 if (anynode
== DI_NODE_NIL
|| devfspath
== NULL
)
3718 pa
= (caddr_t
)anynode
- DI_NODE(anynode
)->self
;
3722 for (off
= all
->aliases
; off
> 0; off
= di_alias
->next
) {
3723 di_alias
= DI_ALIAS(pa
+ off
);
3724 alias
= di_alias
->alias
;
3725 if (strncmp(devfspath
, alias
, strlen(alias
)) == 0) {
3726 cp
= devfspath
+ strlen(alias
);
3727 node
= DI_NODE(pa
+ di_alias
->curroff
);
3728 assert(node
!= DI_NODE_NIL
);
3732 } else if (*cp
== '/') {
3733 curr
= di_devfs_path(node
);
3734 (void) snprintf(buf
, sizeof (buf
), "%s%s",
3736 di_devfs_path_free(curr
);
3747 di_lookup_node_impl(di_node_t root
, char *devfspath
)
3751 char *copy
, *slash
, *pname
, *paddr
;
3754 * Path must be absolute and musn't have duplicate slashes
3756 if (*devfspath
!= '/' || strstr(devfspath
, "//")) {
3757 DPRINTF((DI_ERR
, "Invalid path: %s\n", devfspath
));
3758 return (DI_NODE_NIL
);
3761 if (root
== DI_NODE_NIL
) {
3762 DPRINTF((DI_ERR
, "root node is DI_NODE_NIL\n"));
3763 return (DI_NODE_NIL
);
3766 dap
= DI_ALL((caddr_t
)root
- DI_NODE(root
)->self
);
3767 if (strcmp(dap
->root_path
, "/") != 0) {
3768 DPRINTF((DI_ERR
, "snapshot root not / : %s\n", dap
->root_path
));
3769 return (DI_NODE_NIL
);
3772 if ((copy
= strdup(devfspath
)) == NULL
) {
3773 DPRINTF((DI_ERR
, "strdup failed on: %s\n", devfspath
));
3774 return (DI_NODE_NIL
);
3777 for (slash
= copy
, node
= root
; slash
; ) {
3780 * Handle devfspath = "/" case as well as trailing '/'
3782 if (*(slash
+ 1) == '\0')
3786 * More path-components exist. Deal with the next one
3789 node
= di_child_node(node
);
3791 if (slash
= strchr(pname
, '/'))
3793 if (paddr
= strchr(pname
, '@'))
3796 for (; node
!= DI_NODE_NIL
; node
= di_sibling_node(node
)) {
3799 name
= di_node_name(node
);
3800 baddr
= di_bus_addr(node
);
3802 if (strcmp(pname
, name
) != 0)
3806 * Mappings between a "path-address" and bus-addr
3809 * ---------------------
3812 * "" N/A (invalid paddr)
3814 if (paddr
&& baddr
&& strcmp(paddr
, baddr
) == 0)
3816 if (paddr
== NULL
&& (baddr
== NULL
|| *baddr
== '\0'))
3821 * No nodes in the sibling list or there was no match
3823 if (node
== DI_NODE_NIL
) {
3824 DPRINTF((DI_ERR
, "%s@%s: no node\n", pname
, paddr
));
3826 return (DI_NODE_NIL
);
3830 assert(node
!= DI_NODE_NIL
);
3836 di_lookup_node(di_node_t root
, char *devfspath
)
3841 node
= di_lookup_node_impl(root
, devfspath
);
3842 if (node
!= DI_NODE_NIL
) {
3846 /* node is already set to DI_NODE_NIL */
3847 curr
= alias_to_curr(root
, devfspath
, &node
);
3849 /* node may or may node be DI_NODE_NIL */
3853 node
= di_lookup_node_impl(root
, curr
);
3861 di_alias2curr(di_node_t anynode
, char *alias
)
3863 di_node_t currnode
= DI_NODE_NIL
;
3866 if (anynode
== DI_NODE_NIL
|| alias
== NULL
)
3869 curr
= alias_to_curr(anynode
, alias
, &currnode
);
3870 if (curr
== NULL
&& currnode
!= DI_NODE_NIL
) {
3871 return (di_devfs_path(currnode
));
3872 } else if (curr
== NULL
) {
3873 return (strdup(alias
));
3880 di_lookup_path(di_node_t root
, char *devfspath
)
3882 di_node_t phci_node
;
3883 di_path_t path
= DI_PATH_NIL
;
3884 char *copy
, *lastslash
;
3885 char *pname
, *paddr
;
3886 char *path_name
, *path_addr
;
3888 if ((copy
= strdup(devfspath
)) == NULL
) {
3889 DPRINTF((DI_ERR
, "strdup failed on: %s\n", devfspath
));
3890 return (DI_NODE_NIL
);
3893 if ((lastslash
= strrchr(copy
, '/')) == NULL
) {
3894 DPRINTF((DI_ERR
, "failed to find component: %s\n", devfspath
));
3898 /* stop at pHCI and find the node for the phci */
3900 phci_node
= di_lookup_node(root
, copy
);
3901 if (phci_node
== NULL
) {
3902 DPRINTF((DI_ERR
, "failed to find component: %s\n", devfspath
));
3906 /* set up pname and paddr for last component */
3907 pname
= lastslash
+ 1;
3908 if ((paddr
= strchr(pname
, '@')) == NULL
) {
3909 DPRINTF((DI_ERR
, "failed to find unit-addr: %s\n", devfspath
));
3914 /* walk paths below phci looking for match */
3915 for (path
= di_path_phci_next_path(phci_node
, DI_PATH_NIL
);
3916 path
!= DI_PATH_NIL
;
3917 path
= di_path_phci_next_path(phci_node
, path
)) {
3919 /* get name@addr of path */
3920 path_name
= di_path_node_name(path
);
3921 path_addr
= di_path_bus_addr(path
);
3922 if ((path_name
== NULL
) || (path_addr
== NULL
))
3925 /* break on match */
3926 if ((strcmp(pname
, path_name
) == 0) &&
3927 (strcmp(paddr
, path_addr
) == 0))
3936 msglevel2str(di_debug_t msglevel
)
3955 dprint(di_debug_t msglevel
, const char *fmt
, ...)
3960 if (di_debug
<= DI_QUIET
)
3963 if (di_debug
< msglevel
)
3966 estr
= msglevel2str(msglevel
);
3972 (void) fprintf(stderr
, "libdevinfo[%lu]: %s: ",
3973 (ulong_t
)getpid(), estr
);
3974 (void) vfprintf(stderr
, fmt
, ap
);
3979 /* end of devinfo.c */