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.
26 * Interfaces for getting device configuration data from kernel
27 * through the devinfo driver.
39 #include <sys/mkdev.h>
40 #include <sys/obpdefs.h>
42 #include <sys/types.h>
44 #include <sys/autoconf.h>
46 #include <sys/ddi_hp.h>
51 #include "libdevinfo.h"
54 * Debug message levels
57 DI_QUIET
= 0, /* No debug messages - the default */
65 int di_debug
= DI_QUIET
;
67 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; }
69 void dprint(di_debug_t msglevel
, const char *fmt
, ...);
72 #pragma init(_libdevinfo_init)
77 char *debug_str
= getenv("_LIBDEVINFO_DEBUG");
81 di_debug
= atoi(debug_str
);
82 if (errno
|| di_debug
< DI_QUIET
)
88 di_init(const char *phys_path
, uint_t flag
)
90 return (di_init_impl(phys_path
, flag
, NULL
));
94 * We use blocking_open() to guarantee access to the devinfo device, if open()
95 * is failing with EAGAIN.
98 blocking_open(const char *path
, int oflag
)
102 while ((fd
= open(path
, oflag
)) == -1 && errno
== EAGAIN
)
103 (void) poll(NULL
, 0, 1 * MILLISEC
);
108 /* private interface */
110 di_init_driver(const char *drv_name
, uint_t flag
)
113 char driver
[MAXPATHLEN
];
116 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
117 * which should be sufficient for any sensible programmer.
119 if ((drv_name
== NULL
) || (strlen(drv_name
) >= MAXPATHLEN
)) {
121 return (DI_NODE_NIL
);
123 (void) strcpy(driver
, drv_name
);
126 * open the devinfo driver
128 if ((fd
= blocking_open("/devices/pseudo/devinfo@0:devinfo",
130 DPRINTF((DI_ERR
, "devinfo open failed: errno = %d\n", errno
));
131 return (DI_NODE_NIL
);
134 if (ioctl(fd
, DINFOLODRV
, driver
) != 0) {
135 DPRINTF((DI_ERR
, "failed to load driver %s\n", driver
));
138 return (DI_NODE_NIL
);
143 * Driver load succeeded, return a snapshot
145 return (di_init("/", flag
));
149 di_init_impl(const char *phys_path
, uint_t flag
,
150 struct di_priv_data
*priv
)
155 struct dinfo_io dinfo_io
;
157 uint_t pageoffset
= sysconf(_SC_PAGESIZE
) - 1;
158 uint_t pagemask
= ~pageoffset
;
160 DPRINTF((DI_INFO
, "di_init: taking a snapshot\n"));
163 * Make sure there is no minor name in the path
164 * and the path do not start with /devices....
166 if (strchr(phys_path
, ':') ||
167 (strncmp(phys_path
, "/devices", 8) == 0) ||
168 (strlen(phys_path
) > MAXPATHLEN
)) {
170 return (DI_NODE_NIL
);
173 if (strlen(phys_path
) == 0)
174 (void) sprintf(dinfo_io
.root_path
, "/");
175 else if (*phys_path
!= '/')
176 (void) snprintf(dinfo_io
.root_path
, sizeof (dinfo_io
.root_path
),
179 (void) snprintf(dinfo_io
.root_path
, sizeof (dinfo_io
.root_path
),
183 * If private data is requested, copy the format specification
185 if (flag
& DINFOPRIVDATA
& 0xff) {
187 bcopy(priv
, &dinfo_io
.priv
,
188 sizeof (struct di_priv_data
));
191 return (DI_NODE_NIL
);
196 * Attempt to open the devinfo driver. Make a second attempt at the
197 * read-only minor node if we don't have privileges to open the full
198 * version _and_ if we're not requesting operations that the read-only
199 * node can't perform. (Setgid processes would fail an access() test,
202 if ((fd
= blocking_open("/devices/pseudo/devinfo@0:devinfo",
204 if ((flag
& DINFOFORCE
) == DINFOFORCE
||
205 (flag
& DINFOPRIVDATA
) == DINFOPRIVDATA
) {
207 * We wanted to perform a privileged operation, but the
208 * privileged node isn't available. Don't modify errno
209 * on our way out (but display it if we're running with
212 DPRINTF((DI_ERR
, "devinfo open failed: errno = %d\n",
214 return (DI_NODE_NIL
);
217 if ((fd
= blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
219 DPRINTF((DI_ERR
, "devinfo open failed: errno = %d\n",
221 return (DI_NODE_NIL
);
226 * Verify that there is no major conflict, i.e., we are indeed opening
227 * the devinfo driver.
229 if (ioctl(fd
, DINFOIDENT
, NULL
) != DI_MAGIC
) {
231 "driver ID failed; check for major conflict\n"));
233 return (DI_NODE_NIL
);
239 if ((map_size
= ioctl(fd
, flag
, &dinfo_io
)) < 0) {
240 DPRINTF((DI_ERR
, "devinfo ioctl failed with "
241 "error: %d\n", errno
));
243 return (DI_NODE_NIL
);
244 } else if (map_size
== 0) {
245 DPRINTF((DI_ERR
, "%s not found\n", phys_path
));
248 return (DI_NODE_NIL
);
252 * copy snapshot to userland
254 map_size
= (map_size
+ pageoffset
) & pagemask
;
255 if ((pa
= valloc(map_size
)) == NULL
) {
256 DPRINTF((DI_ERR
, "valloc failed for snapshot\n"));
258 return (DI_NODE_NIL
);
261 if (ioctl(fd
, DINFOUSRLD
, pa
) != map_size
) {
262 DPRINTF((DI_ERR
, "failed to copy snapshot to usrld\n"));
266 return (DI_NODE_NIL
);
272 if (dap
->version
!= DI_SNAPSHOT_VERSION
) {
273 DPRINTF((DI_ERR
, "wrong snapshot version "
274 "(expected=%d, actual=%d)\n",
275 DI_SNAPSHOT_VERSION
, dap
->version
));
278 return (DI_NODE_NIL
);
280 if (dap
->top_devinfo
== 0) { /* phys_path not found */
281 DPRINTF((DI_ERR
, "%s not found\n", phys_path
));
284 return (DI_NODE_NIL
);
287 return (DI_NODE(pa
+ dap
->top_devinfo
));
291 di_fini(di_node_t root
)
293 caddr_t pa
; /* starting address of map */
295 DPRINTF((DI_INFO
, "di_fini: freeing a snapshot\n"));
300 if (root
== DI_NODE_NIL
) {
301 DPRINTF((DI_ERR
, "di_fini called with NIL arg\n"));
306 * The root contains its own offset--self.
307 * Subtracting it from root address, we get the starting addr.
308 * The map_size is stored at the beginning of snapshot.
309 * Once we have starting address and size, we can free().
311 pa
= (caddr_t
)root
- DI_NODE(root
)->self
;
317 di_parent_node(di_node_t node
)
319 caddr_t pa
; /* starting address of map */
321 if (node
== DI_NODE_NIL
) {
323 return (DI_NODE_NIL
);
326 DPRINTF((DI_TRACE
, "Get parent of node %s\n", di_node_name(node
)));
328 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
330 if (DI_NODE(node
)->parent
) {
331 return (DI_NODE(pa
+ DI_NODE(node
)->parent
));
335 * Deal with error condition:
336 * If parent doesn't exist and node is not the root,
337 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
339 if (strcmp(DI_ALL(pa
)->root_path
, "/") != 0)
344 return (DI_NODE_NIL
);
348 di_sibling_node(di_node_t node
)
350 caddr_t pa
; /* starting address of map */
352 if (node
== DI_NODE_NIL
) {
354 return (DI_NODE_NIL
);
357 DPRINTF((DI_TRACE
, "Get sibling of node %s\n", di_node_name(node
)));
359 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
361 if (DI_NODE(node
)->sibling
) {
362 return (DI_NODE(pa
+ DI_NODE(node
)->sibling
));
366 * Deal with error condition:
367 * Sibling doesn't exist, figure out if ioctl command
368 * has DINFOSUBTREE set. If it doesn't, set errno to
371 if (!(DI_ALL(pa
)->command
& DINFOSUBTREE
))
376 return (DI_NODE_NIL
);
380 di_child_node(di_node_t node
)
382 caddr_t pa
; /* starting address of map */
384 DPRINTF((DI_TRACE
, "Get child of node %s\n", di_node_name(node
)));
386 if (node
== DI_NODE_NIL
) {
388 return (DI_NODE_NIL
);
391 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
393 if (DI_NODE(node
)->child
) {
394 return (DI_NODE(pa
+ DI_NODE(node
)->child
));
398 * Deal with error condition:
399 * Child doesn't exist, figure out if DINFOSUBTREE is set.
400 * If it isn't, set errno to ENOTSUP.
402 if (!(DI_ALL(pa
)->command
& DINFOSUBTREE
))
407 return (DI_NODE_NIL
);
411 di_drv_first_node(const char *drv_name
, di_node_t root
)
413 caddr_t pa
; /* starting address of map */
415 struct di_devnm
*devnm
;
417 DPRINTF((DI_INFO
, "Get first node of driver %s\n", drv_name
));
419 if (root
== DI_NODE_NIL
) {
421 return (DI_NODE_NIL
);
425 * get major number of driver
427 pa
= (caddr_t
)root
- DI_NODE(root
)->self
;
428 devcnt
= DI_ALL(pa
)->devcnt
;
429 devnm
= DI_DEVNM(pa
+ DI_ALL(pa
)->devnames
);
431 for (major
= 0; major
< devcnt
; major
++)
432 if (devnm
[major
].name
&& (strcmp(drv_name
,
433 (char *)(pa
+ devnm
[major
].name
)) == 0))
436 if (major
>= devcnt
) {
438 return (DI_NODE_NIL
);
441 if (!(devnm
[major
].head
)) {
443 return (DI_NODE_NIL
);
446 return (DI_NODE(pa
+ devnm
[major
].head
));
450 di_drv_next_node(di_node_t node
)
452 caddr_t pa
; /* starting address of map */
454 if (node
== DI_NODE_NIL
) {
456 return (DI_NODE_NIL
);
459 DPRINTF((DI_TRACE
, "next node on per driver list:"
460 " current=%s, driver=%s\n",
461 di_node_name(node
), di_driver_name(node
)));
463 if (DI_NODE(node
)->next
== (di_off_t
)-1) {
465 return (DI_NODE_NIL
);
468 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
470 if (DI_NODE(node
)->next
== 0) {
472 return (DI_NODE_NIL
);
475 return (DI_NODE(pa
+ DI_NODE(node
)->next
));
479 * Internal library interfaces:
480 * node_list etc. for node walking
483 struct node_list
*next
;
488 free_node_list(struct node_list
**headp
)
490 struct node_list
*tmp
;
494 *headp
= (*headp
)->next
;
500 append_node_list(struct node_list
**headp
, struct node_list
*list
)
502 struct node_list
*tmp
;
504 if (*headp
== NULL
) {
509 if (list
== NULL
) /* a minor optimization */
520 prepend_node_list(struct node_list
**headp
, struct node_list
*list
)
522 struct node_list
*tmp
;
530 if (tmp
== NULL
) /* a minor optimization */
540 * returns 1 if node is a descendant of parent, 0 otherwise
543 is_descendant(di_node_t node
, di_node_t parent
)
546 * DI_NODE_NIL is parent of root, so it is
547 * the parent of all nodes.
549 if (parent
== DI_NODE_NIL
) {
554 node
= di_parent_node(node
);
555 } while ((node
!= DI_NODE_NIL
) && (node
!= parent
));
557 return (node
!= DI_NODE_NIL
);
561 * Insert list before the first node which is NOT a descendent of parent.
562 * This is needed to reproduce the exact walking order of link generators.
565 insert_node_list(struct node_list
**headp
, struct node_list
*list
,
568 struct node_list
*tmp
, *tmp1
;
574 if (tmp
== NULL
) { /* a minor optimization */
579 if (!is_descendant(tmp
->node
, parent
)) {
580 prepend_node_list(headp
, list
);
585 * Find first node which is not a descendant
587 while (tmp
->next
&& is_descendant(tmp
->next
->node
, parent
)) {
593 append_node_list(headp
, tmp1
);
597 * Get a linked list of handles of all children
599 static struct node_list
*
600 get_children(di_node_t node
)
603 struct node_list
*result
, *tmp
;
605 DPRINTF((DI_TRACE1
, "Get children of node %s\n", di_node_name(node
)));
607 if ((child
= di_child_node(node
)) == DI_NODE_NIL
) {
611 if ((result
= malloc(sizeof (struct node_list
))) == NULL
) {
612 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
616 result
->node
= child
;
619 while ((child
= di_sibling_node(tmp
->node
)) != DI_NODE_NIL
) {
620 if ((tmp
->next
= malloc(sizeof (struct node_list
))) == NULL
) {
621 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
622 free_node_list(&result
);
635 * Internal library interface:
636 * Delete all siblings of the first node from the node_list, along with
637 * the first node itself.
640 prune_sib(struct node_list
**headp
)
642 di_node_t parent
, curr_par
, curr_gpar
;
643 struct node_list
*curr
, *prev
;
646 * get handle to parent of first node
648 if ((parent
= di_parent_node((*headp
)->node
)) == DI_NODE_NIL
) {
650 * This must be the root of the snapshot, so can't
653 * XXX Put a check here just in case.
656 DPRINTF((DI_ERR
, "Unexpected err in di_walk_node.\n"));
664 * To be complete, we should also delete the children
665 * of siblings that have already been visited.
666 * This happens for DI_WALK_SIBFIRST when the first node
667 * is NOT the first in the linked list of siblings.
669 * Hence, we compare parent with BOTH the parent and grandparent
670 * of nodes, and delete node is a match is found.
675 if (((curr_par
= di_parent_node(curr
->node
)) != DI_NODE_NIL
) &&
676 ((curr_par
== parent
) || ((curr_gpar
=
677 di_parent_node(curr_par
)) != DI_NODE_NIL
) &&
678 (curr_gpar
== parent
))) {
680 * match parent/grandparent: delete curr
682 prev
->next
= curr
->next
;
690 * delete the first node
698 * Internal library function:
699 * Update node list based on action (return code from callback)
700 * and flag specifying walking behavior.
703 update_node_list(int action
, uint_t flag
, struct node_list
**headp
)
705 struct node_list
*children
, *tmp
;
706 di_node_t parent
= di_parent_node((*headp
)->node
);
709 case DI_WALK_TERMINATE
:
711 * free the node list and be done
714 free_node_list(headp
);
717 case DI_WALK_PRUNESIB
:
719 * Get list of children and prune siblings
721 children
= get_children((*headp
)->node
);
725 case DI_WALK_PRUNECHILD
:
727 * Set children to NULL and pop first node
735 case DI_WALK_CONTINUE
:
738 * Get list of children and pop first node
740 children
= get_children((*headp
)->node
);
748 * insert the list of children
751 case DI_WALK_CLDFIRST
:
752 prepend_node_list(headp
, children
);
755 case DI_WALK_SIBFIRST
:
756 append_node_list(headp
, children
);
759 case DI_WALK_LINKGEN
:
761 insert_node_list(headp
, children
, parent
);
767 * Internal library function:
768 * Invoke callback on one node and update the list of nodes to be walked
769 * based on the flag and return code.
772 walk_one_node(struct node_list
**headp
, uint_t flag
, void *arg
,
773 int (*callback
)(di_node_t
, void *))
775 DPRINTF((DI_TRACE
, "Walking node %s\n", di_node_name((*headp
)->node
)));
777 update_node_list(callback((*headp
)->node
, arg
),
778 flag
& DI_WALK_MASK
, headp
);
782 di_walk_node(di_node_t root
, uint_t flag
, void *arg
,
783 int (*node_callback
)(di_node_t
, void *))
785 struct node_list
*head
; /* node_list for tree walk */
792 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
793 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
800 DPRINTF((DI_INFO
, "Start node walking from node %s\n",
801 di_node_name(root
)));
804 walk_one_node(&head
, flag
, arg
, node_callback
);
810 * Internal library function:
811 * Invoke callback for each minor on the minor list of first node
812 * on node_list headp, and place children of first node on the list.
814 * This is similar to walk_one_node, except we only walk in child
818 walk_one_minor_list(struct node_list
**headp
, const char *desired_type
,
819 uint_t flag
, void *arg
, int (*callback
)(di_node_t
, di_minor_t
, void *))
822 int action
= DI_WALK_CONTINUE
;
824 di_minor_t minor
= DI_MINOR_NIL
;
825 di_node_t node
= (*headp
)->node
;
827 while ((minor
= di_minor_next(node
, minor
)) != DI_MINOR_NIL
) {
828 ddm_type
= di_minor_type(minor
);
830 if ((ddm_type
== DDM_ALIAS
) && !(flag
& DI_CHECK_ALIAS
))
833 if ((ddm_type
== DDM_INTERNAL_PATH
) &&
834 !(flag
& DI_CHECK_INTERNAL_PATH
))
837 node_type
= di_minor_nodetype(minor
);
838 if ((desired_type
!= NULL
) && ((node_type
== NULL
) ||
839 strncmp(desired_type
, node_type
, strlen(desired_type
))
843 if ((action
= callback(node
, minor
, arg
)) ==
849 update_node_list(action
, DI_WALK_LINKGEN
, headp
);
853 di_walk_minor(di_node_t root
, const char *minor_type
, uint_t flag
, void *arg
,
854 int (*minor_callback
)(di_node_t
, di_minor_t
, void *))
856 struct node_list
*head
; /* node_list for tree walk */
859 char *devfspath
= di_devfs_path(root
);
860 DPRINTF((DI_INFO
, "walking minor nodes under %s\n", devfspath
));
861 di_devfs_path_free(devfspath
);
869 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
870 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
877 DPRINTF((DI_INFO
, "Start minor walking from node %s\n",
878 di_node_name(root
)));
881 walk_one_minor_list(&head
, minor_type
, flag
, arg
,
888 * generic node parameters
889 * Calling these routines always succeeds.
892 di_node_name(di_node_t node
)
894 return ((caddr_t
)node
+ DI_NODE(node
)->node_name
- DI_NODE(node
)->self
);
897 /* returns NULL ptr or a valid ptr to non-NULL string */
899 di_bus_addr(di_node_t node
)
901 caddr_t pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
903 if (DI_NODE(node
)->address
== 0)
906 return ((char *)(pa
+ DI_NODE(node
)->address
));
910 di_binding_name(di_node_t node
)
912 caddr_t pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
914 if (DI_NODE(node
)->bind_name
== 0)
917 return ((char *)(pa
+ DI_NODE(node
)->bind_name
));
921 di_compatible_names(di_node_t node
, char **names
)
924 int len
, size
, entries
= 0;
926 if (DI_NODE(node
)->compat_names
== 0) {
931 *names
= (caddr_t
)node
+
932 DI_NODE(node
)->compat_names
- DI_NODE(node
)->self
;
935 len
= DI_NODE(node
)->compat_length
;
938 size
= strlen(c
) + 1;
947 di_instance(di_node_t node
)
949 return (DI_NODE(node
)->instance
);
953 * XXX: emulate the return value of the old implementation
954 * using info from devi_node_class and devi_node_attributes.
957 di_nodeid(di_node_t node
)
959 if (DI_NODE(node
)->node_class
== DDI_NC_PROM
)
960 return (DI_PROM_NODEID
);
962 if (DI_NODE(node
)->attributes
& DDI_PERSISTENT
)
963 return (DI_SID_NODEID
);
965 return (DI_PSEUDO_NODEID
);
969 di_state(di_node_t node
)
973 if (di_node_state(node
) < DS_ATTACHED
)
974 result
|= DI_DRIVER_DETACHED
;
975 if (DI_NODE(node
)->state
& DEVI_DEVICE_OFFLINE
)
976 result
|= DI_DEVICE_OFFLINE
;
977 if (DI_NODE(node
)->state
& DEVI_DEVICE_DOWN
)
978 result
|= DI_DEVICE_DOWN
;
979 if (DI_NODE(node
)->state
& DEVI_DEVICE_DEGRADED
)
980 result
|= DI_DEVICE_DEGRADED
;
981 if (DI_NODE(node
)->state
& DEVI_DEVICE_REMOVED
)
982 result
|= DI_DEVICE_REMOVED
;
983 if (DI_NODE(node
)->state
& DEVI_BUS_QUIESCED
)
984 result
|= DI_BUS_QUIESCED
;
985 if (DI_NODE(node
)->state
& DEVI_BUS_DOWN
)
986 result
|= DI_BUS_DOWN
;
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 pointer to the allocated string, which must be freed by the caller.
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_flags(di_path_t path
)
2034 return (DI_PATH(path
)->path_flags
);
2038 di_path_node_name(di_path_t path
)
2040 di_node_t client_node
;
2042 /* pathinfo gets node_name from client */
2043 if ((client_node
= di_path_client_node(path
)) == NULL
)
2045 return (di_node_name(client_node
));
2049 di_path_bus_addr(di_path_t path
)
2051 caddr_t pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2053 if (DI_PATH(path
)->path_addr
== 0)
2056 return ((char *)(pa
+ DI_PATH(path
)->path_addr
));
2060 di_path_instance(di_path_t path
)
2062 return (DI_PATH(path
)->path_instance
);
2066 di_path_client_node(di_path_t path
)
2068 caddr_t pa
; /* starting address of map */
2070 if (path
== DI_PATH_NIL
) {
2072 return (DI_PATH_NIL
);
2075 DPRINTF((DI_TRACE
, "Get client node for path %p\n", path
));
2077 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2079 if (DI_PATH(path
)->path_client
) {
2080 return (DI_NODE(pa
+ DI_PATH(path
)->path_client
));
2084 * Deal with error condition:
2085 * If parent doesn't exist and node is not the root,
2086 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2088 if ((DI_PATH(path
)->path_snap_state
& DI_PATH_SNAP_NOCLIENT
) == 0)
2093 return (DI_NODE_NIL
);
2097 di_path_phci_node(di_path_t path
)
2099 caddr_t pa
; /* starting address of map */
2101 if (path
== DI_PATH_NIL
) {
2103 return (DI_PATH_NIL
);
2106 DPRINTF((DI_TRACE
, "Get phci node for path %p\n", path
));
2108 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2110 if (DI_PATH(path
)->path_phci
) {
2111 return (DI_NODE(pa
+ DI_PATH(path
)->path_phci
));
2115 * Deal with error condition:
2116 * If parent doesn't exist and node is not the root,
2117 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2119 if ((DI_PATH(path
)->path_snap_state
& DI_PATH_SNAP_NOPHCI
) == 0)
2124 return (DI_NODE_NIL
);
2128 di_path_prop_next(di_path_t path
, di_path_prop_t prop
)
2132 if (path
== DI_PATH_NIL
) {
2134 return (DI_PROP_NIL
);
2140 if (prop
!= DI_PROP_NIL
) {
2141 if (DI_PROP(prop
)->next
!= 0)
2142 return (DI_PATHPROP((caddr_t
)prop
-
2143 DI_PROP(prop
)->self
+ DI_PROP(prop
)->next
));
2146 return (DI_PROP_NIL
);
2151 * prop is NIL-->caller asks for first property
2153 pa
= (caddr_t
)path
- DI_PATH(path
)->self
;
2154 if (DI_PATH(path
)->path_prop
!= 0) {
2155 return (DI_PATHPROP(pa
+ DI_PATH(path
)->path_prop
));
2159 * no property data-->check if snapshot includes props
2160 * in order to set the correct errno
2162 if (DINFOPROP
& (DI_ALL(pa
)->command
))
2167 return (DI_PROP_NIL
);
2171 di_path_prop_name(di_path_prop_t prop
)
2173 caddr_t pa
; /* starting address of map */
2174 pa
= (caddr_t
)prop
- DI_PATHPROP(prop
)->self
;
2175 return ((char *)(pa
+ DI_PATHPROP(prop
)->prop_name
));
2179 di_path_prop_len(di_path_prop_t prop
)
2181 return (DI_PATHPROP(prop
)->prop_len
);
2185 di_path_prop_type(di_path_prop_t prop
)
2187 switch (DI_PATHPROP(prop
)->prop_type
) {
2188 case DDI_PROP_TYPE_INT
:
2189 return (DI_PROP_TYPE_INT
);
2190 case DDI_PROP_TYPE_INT64
:
2191 return (DI_PROP_TYPE_INT64
);
2192 case DDI_PROP_TYPE_BYTE
:
2193 return (DI_PROP_TYPE_BYTE
);
2194 case DDI_PROP_TYPE_STRING
:
2195 return (DI_PROP_TYPE_STRING
);
2197 return (DI_PROP_TYPE_UNKNOWN
);
2201 di_path_prop_bytes(di_path_prop_t prop
, uchar_t
**prop_data
)
2203 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2204 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2210 *prop_data
= (uchar_t
*)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2211 + DI_PATHPROP(prop
)->prop_data
);
2213 return (di_prop_decode_common((void *)prop_data
,
2214 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_BYTE
, 0));
2218 di_path_prop_ints(di_path_prop_t prop
, int **prop_data
)
2220 if (DI_PATHPROP(prop
)->prop_len
== 0)
2223 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2224 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2230 *prop_data
= (int *)((void *)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2231 + DI_PATHPROP(prop
)->prop_data
));
2233 return (di_prop_decode_common((void *)prop_data
,
2234 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_INT
, 0));
2238 di_path_prop_int64s(di_path_prop_t prop
, int64_t **prop_data
)
2240 if (DI_PATHPROP(prop
)->prop_len
== 0)
2243 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2244 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2250 *prop_data
= (int64_t *)((void *)((caddr_t
)prop
-
2251 DI_PATHPROP(prop
)->self
+ DI_PATHPROP(prop
)->prop_data
));
2253 return (di_prop_decode_common((void *)prop_data
,
2254 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_INT64
, 0));
2258 di_path_prop_strings(di_path_prop_t prop
, char **prop_data
)
2260 if (DI_PATHPROP(prop
)->prop_len
== 0)
2263 if ((DI_PATHPROP(prop
)->prop_data
== 0) ||
2264 (DI_PATHPROP(prop
)->prop_data
== (di_off_t
)-1)) {
2270 *prop_data
= (char *)((caddr_t
)prop
- DI_PATHPROP(prop
)->self
2271 + DI_PATHPROP(prop
)->prop_data
);
2273 return (di_prop_decode_common((void *)prop_data
,
2274 DI_PATHPROP(prop
)->prop_len
, DI_PROP_TYPE_STRING
, 0));
2277 static di_path_prop_t
2278 di_path_prop_search(di_path_t path
, const char *name
, int type
)
2280 di_path_prop_t prop
= DI_PROP_NIL
;
2283 * Sanity check arguments
2285 if ((path
== DI_PATH_NIL
) || (name
== NULL
) || (strlen(name
) == 0) ||
2286 !DI_PROP_TYPE_VALID(type
)) {
2288 return (DI_PROP_NIL
);
2291 while ((prop
= di_path_prop_next(path
, prop
)) != DI_PROP_NIL
) {
2292 int prop_type
= di_path_prop_type(prop
);
2294 DPRINTF((DI_TRACE1
, "match path prop name %s, type %d\n",
2295 di_path_prop_name(prop
), prop_type
));
2297 if (strcmp(name
, di_path_prop_name(prop
)) != 0)
2300 if ((prop_type
!= DI_PROP_TYPE_UNKNOWN
) && (prop_type
!= type
))
2306 return (DI_PROP_NIL
);
2310 di_path_prop_lookup_bytes(di_path_t path
, const char *prop_name
,
2311 uchar_t
**prop_data
)
2313 di_path_prop_t prop
;
2315 if ((prop
= di_path_prop_search(path
, prop_name
,
2316 DI_PROP_TYPE_BYTE
)) == DI_PROP_NIL
)
2319 return (di_path_prop_bytes(prop
, prop_data
));
2323 di_path_prop_lookup_ints(di_path_t path
, const char *prop_name
,
2326 di_path_prop_t prop
;
2328 if ((prop
= di_path_prop_search(path
, prop_name
,
2329 DI_PROP_TYPE_INT
)) == DI_PROP_NIL
)
2332 return (di_path_prop_ints(prop
, prop_data
));
2336 di_path_prop_lookup_int64s(di_path_t path
, const char *prop_name
,
2337 int64_t **prop_data
)
2339 di_path_prop_t prop
;
2341 if ((prop
= di_path_prop_search(path
, prop_name
,
2342 DI_PROP_TYPE_INT64
)) == DI_PROP_NIL
)
2345 return (di_path_prop_int64s(prop
, prop_data
));
2348 int di_path_prop_lookup_strings(di_path_t path
, const char *prop_name
,
2351 di_path_prop_t prop
;
2353 if ((prop
= di_path_prop_search(path
, prop_name
,
2354 DI_PROP_TYPE_STRING
)) == DI_PROP_NIL
)
2357 return (di_path_prop_strings(prop
, prop_data
));
2361 * Consolidation private interfaces for traversing vhci nodes.
2364 di_vhci_first_node(di_node_t root
)
2367 caddr_t pa
; /* starting address of map */
2369 DPRINTF((DI_INFO
, "Get first vhci node\n"));
2371 if (root
== DI_NODE_NIL
) {
2373 return (DI_NODE_NIL
);
2376 pa
= (caddr_t
)root
- DI_NODE(root
)->self
;
2379 if (dap
->top_vhci_devinfo
== 0) {
2381 return (DI_NODE_NIL
);
2384 return (DI_NODE(pa
+ dap
->top_vhci_devinfo
));
2388 di_vhci_next_node(di_node_t node
)
2390 caddr_t pa
; /* starting address of map */
2392 if (node
== DI_NODE_NIL
) {
2394 return (DI_NODE_NIL
);
2397 DPRINTF((DI_TRACE
, "next vhci node on the snap shot:"
2398 " current=%s\n", di_node_name(node
)));
2400 if (DI_NODE(node
)->next_vhci
== 0) {
2402 return (DI_NODE_NIL
);
2405 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2407 return (DI_NODE(pa
+ DI_NODE(node
)->next_vhci
));
2411 * Consolidation private interfaces for traversing phci nodes.
2414 di_phci_first_node(di_node_t vhci_node
)
2416 caddr_t pa
; /* starting address of map */
2418 DPRINTF((DI_INFO
, "Get first phci node:\n"
2419 " current=%s", di_node_name(vhci_node
)));
2421 if (vhci_node
== DI_NODE_NIL
) {
2423 return (DI_NODE_NIL
);
2426 pa
= (caddr_t
)vhci_node
- DI_NODE(vhci_node
)->self
;
2428 if (DI_NODE(vhci_node
)->top_phci
== 0) {
2430 return (DI_NODE_NIL
);
2433 return (DI_NODE(pa
+ DI_NODE(vhci_node
)->top_phci
));
2437 di_phci_next_node(di_node_t node
)
2439 caddr_t pa
; /* starting address of map */
2441 if (node
== DI_NODE_NIL
) {
2443 return (DI_NODE_NIL
);
2446 DPRINTF((DI_TRACE
, "next phci node on the snap shot:"
2447 " current=%s\n", di_node_name(node
)));
2449 if (DI_NODE(node
)->next_phci
== 0) {
2451 return (DI_NODE_NIL
);
2454 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2456 return (DI_NODE(pa
+ DI_NODE(node
)->next_phci
));
2460 * Consolidation private interfaces for private data
2463 di_parent_private_data(di_node_t node
)
2467 if (DI_NODE(node
)->parent_data
== 0) {
2472 if (DI_NODE(node
)->parent_data
== (di_off_t
)-1) {
2474 * Private data requested, but not obtained due to a memory
2475 * error (e.g. wrong format specified)
2481 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2482 if (DI_NODE(node
)->parent_data
)
2483 return (pa
+ DI_NODE(node
)->parent_data
);
2485 if (DI_ALL(pa
)->command
& DINFOPRIVDATA
)
2494 di_driver_private_data(di_node_t node
)
2498 if (DI_NODE(node
)->driver_data
== 0) {
2503 if (DI_NODE(node
)->driver_data
== (di_off_t
)-1) {
2505 * Private data requested, but not obtained due to a memory
2506 * error (e.g. wrong format specified)
2512 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2513 if (DI_NODE(node
)->driver_data
)
2514 return (pa
+ DI_NODE(node
)->driver_data
);
2516 if (DI_ALL(pa
)->command
& DINFOPRIVDATA
)
2525 * Hotplug information access
2532 int (*hp_callback
)(di_node_t
, di_hp_t
, void *);
2536 di_walk_hp_callback(di_node_t node
, void *argp
)
2538 di_walk_hp_arg_t
*arg
= (di_walk_hp_arg_t
*)argp
;
2542 for (hp
= DI_HP_NIL
; (hp
= di_hp_next(node
, hp
)) != DI_HP_NIL
; ) {
2544 /* Exclude non-matching types if a type filter is specified */
2545 if (arg
->type
!= NULL
) {
2546 type_str
= di_hp_description(hp
);
2547 if (type_str
&& (strcmp(arg
->type
, type_str
) != 0))
2551 /* Exclude ports if DI_HP_PORT flag not specified */
2552 if (!(arg
->flag
& DI_HP_PORT
) &&
2553 (di_hp_type(hp
) == DDI_HP_CN_TYPE_VIRTUAL_PORT
))
2556 /* Exclude connectors if DI_HP_CONNECTOR flag not specified */
2557 if (!(arg
->flag
& DI_HP_CONNECTOR
) &&
2558 !(di_hp_type(hp
) == DDI_HP_CN_TYPE_VIRTUAL_PORT
))
2561 /* Perform callback */
2562 if (arg
->hp_callback(node
, hp
, arg
->arg
) != DI_WALK_CONTINUE
)
2563 return (DI_WALK_TERMINATE
);
2566 return (DI_WALK_CONTINUE
);
2570 di_walk_hp(di_node_t node
, const char *type
, uint_t flag
, void *arg
,
2571 int (*hp_callback
)(di_node_t node
, di_hp_t hp
, void *arg
))
2573 di_walk_hp_arg_t walk_arg
;
2577 char *devfspath
= di_devfs_path(node
);
2578 DPRINTF((DI_INFO
, "walking hotplug nodes under %s\n", devfspath
));
2579 di_devfs_path_free(devfspath
);
2582 * paranoid error checking
2584 if ((node
== DI_NODE_NIL
) || (hp_callback
== NULL
)) {
2589 /* check if hotplug data is included in snapshot */
2590 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2591 if (!(DI_ALL(pa
)->command
& DINFOHP
)) {
2597 walk_arg
.type
= type
;
2598 walk_arg
.flag
= flag
;
2599 walk_arg
.hp_callback
= hp_callback
;
2600 return (di_walk_node(node
, DI_WALK_CLDFIRST
, &walk_arg
,
2601 di_walk_hp_callback
));
2605 di_hp_next(di_node_t node
, di_hp_t hp
)
2610 * paranoid error checking
2612 if (node
== DI_NODE_NIL
) {
2618 * hotplug node is not NIL
2620 if (hp
!= DI_HP_NIL
) {
2621 if (DI_HP(hp
)->next
!= 0)
2622 return (DI_HP((caddr_t
)hp
- hp
->self
+ hp
->next
));
2630 * hotplug node is NIL-->caller asks for first hotplug node
2632 if (DI_NODE(node
)->hp_data
!= 0) {
2633 return (DI_HP((caddr_t
)node
- DI_NODE(node
)->self
+
2634 DI_NODE(node
)->hp_data
));
2638 * no hotplug data-->check if snapshot includes hotplug data
2639 * in order to set the correct errno
2641 pa
= (caddr_t
)node
- DI_NODE(node
)->self
;
2642 if (DINFOHP
& DI_ALL(pa
)->command
)
2651 di_hp_name(di_hp_t hp
)
2656 * paranoid error checking
2658 if (hp
== DI_HP_NIL
) {
2663 pa
= (caddr_t
)hp
- DI_HP(hp
)->self
;
2665 if (DI_HP(hp
)->hp_name
== 0) {
2670 return ((char *)(pa
+ DI_HP(hp
)->hp_name
));
2674 di_hp_connection(di_hp_t hp
)
2677 * paranoid error checking
2679 if (hp
== DI_HP_NIL
) {
2684 if (DI_HP(hp
)->hp_connection
== -1)
2687 return (DI_HP(hp
)->hp_connection
);
2691 di_hp_depends_on(di_hp_t hp
)
2694 * paranoid error checking
2696 if (hp
== DI_HP_NIL
) {
2701 if (DI_HP(hp
)->hp_depends_on
== -1)
2704 return (DI_HP(hp
)->hp_depends_on
);
2708 di_hp_state(di_hp_t hp
)
2711 * paranoid error checking
2713 if (hp
== DI_HP_NIL
) {
2718 return (DI_HP(hp
)->hp_state
);
2722 di_hp_type(di_hp_t hp
)
2725 * paranoid error checking
2727 if (hp
== DI_HP_NIL
) {
2732 return (DI_HP(hp
)->hp_type
);
2736 di_hp_description(di_hp_t hp
)
2741 * paranoid error checking
2743 if (hp
== DI_HP_NIL
) {
2748 pa
= (caddr_t
)hp
- DI_HP(hp
)->self
;
2750 if (DI_HP(hp
)->hp_type_str
== 0)
2753 return ((char *)(pa
+ DI_HP(hp
)->hp_type_str
));
2757 di_hp_child(di_hp_t hp
)
2759 caddr_t pa
; /* starting address of map */
2762 * paranoid error checking
2764 if (hp
== DI_HP_NIL
) {
2766 return (DI_NODE_NIL
);
2769 pa
= (caddr_t
)hp
- DI_HP(hp
)->self
;
2771 if (DI_HP(hp
)->hp_child
> 0) {
2772 return (DI_NODE(pa
+ DI_HP(hp
)->hp_child
));
2776 * Deal with error condition:
2777 * Child doesn't exist, figure out if DINFOSUBTREE is set.
2778 * If it isn't, set errno to ENOTSUP.
2780 if (!(DINFOSUBTREE
& DI_ALL(pa
)->command
))
2785 return (DI_NODE_NIL
);
2789 di_hp_last_change(di_hp_t hp
)
2792 * paranoid error checking
2794 if (hp
== DI_HP_NIL
) {
2799 return ((time_t)DI_HP(hp
)->hp_last_change
);
2803 * PROM property access
2807 * openprom driver stuff:
2808 * The maximum property length depends on the buffer size. We use
2809 * OPROMMAXPARAM defined in <sys/openpromio.h>
2811 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2812 * MAXVALSZ is maximum value size, which is whatever space left in buf
2815 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int)
2816 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME;
2818 struct di_prom_prop
{
2822 struct di_prom_prop
*next
; /* form a linked list */
2825 struct di_prom_handle
{ /* handle to prom */
2826 mutex_t lock
; /* synchronize access to openprom fd */
2827 int fd
; /* /dev/openprom file descriptor */
2828 struct di_prom_prop
*list
; /* linked list of prop */
2830 char buf
[OPROMMAXPARAM
];
2831 struct openpromio opp
;
2838 struct di_prom_handle
*p
;
2840 if ((p
= malloc(sizeof (struct di_prom_handle
))) == NULL
)
2841 return (DI_PROM_HANDLE_NIL
);
2843 DPRINTF((DI_INFO
, "di_prom_init: get prom handle 0x%p\n", p
));
2845 (void) mutex_init(&p
->lock
, USYNC_THREAD
, NULL
);
2846 if ((p
->fd
= open("/dev/openprom", O_RDONLY
)) < 0) {
2848 return (DI_PROM_HANDLE_NIL
);
2852 return ((di_prom_handle_t
)p
);
2856 di_prom_prop_free(struct di_prom_prop
*list
)
2858 struct di_prom_prop
*tmp
= list
;
2860 while (tmp
!= NULL
) {
2862 if (tmp
->name
!= NULL
) {
2865 if (tmp
->data
!= NULL
) {
2874 di_prom_fini(di_prom_handle_t ph
)
2876 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2878 DPRINTF((DI_INFO
, "di_prom_fini: free prom handle 0x%p\n", p
));
2880 (void) close(p
->fd
);
2881 (void) mutex_destroy(&p
->lock
);
2882 di_prom_prop_free(p
->list
);
2888 * Internal library interface for locating the property
2889 * XXX: ph->lock must be held for the duration of call.
2891 static di_prom_prop_t
2892 di_prom_prop_found(di_prom_handle_t ph
, int nodeid
,
2893 di_prom_prop_t prom_prop
)
2895 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2896 struct openpromio
*opp
= &p
->oppbuf
.opp
;
2897 int *ip
= (int *)((void *)opp
->oprom_array
);
2898 struct di_prom_prop
*prop
= (struct di_prom_prop
*)prom_prop
;
2900 DPRINTF((DI_TRACE1
, "Looking for nodeid 0x%x\n", nodeid
));
2903 * Set "current" nodeid in the openprom driver
2905 opp
->oprom_size
= sizeof (int);
2907 if (ioctl(p
->fd
, OPROMSETNODEID
, opp
) < 0) {
2908 DPRINTF((DI_ERR
, "*** Nodeid not found 0x%x\n", nodeid
));
2909 return (DI_PROM_PROP_NIL
);
2912 DPRINTF((DI_TRACE
, "Found nodeid 0x%x\n", nodeid
));
2914 bzero(opp
, OBP_MAXBUF
);
2915 opp
->oprom_size
= OBP_MAXPROPNAME
;
2916 if (prom_prop
!= DI_PROM_PROP_NIL
)
2917 (void) strcpy(opp
->oprom_array
, prop
->name
);
2919 if ((ioctl(p
->fd
, OPROMNXTPROP
, opp
) < 0) || (opp
->oprom_size
== 0))
2920 return (DI_PROM_PROP_NIL
);
2923 * Prom property found. Allocate struct for storing prop
2924 * (reuse variable prop)
2926 if ((prop
= malloc(sizeof (struct di_prom_prop
))) == NULL
)
2927 return (DI_PROM_PROP_NIL
);
2930 * Get a copy of property name
2932 if ((prop
->name
= strdup(opp
->oprom_array
)) == NULL
) {
2934 return (DI_PROM_PROP_NIL
);
2938 * get property value and length
2940 opp
->oprom_size
= OBP_MAXPROPLEN
;
2942 if ((ioctl(p
->fd
, OPROMGETPROP
, opp
) < 0) ||
2943 (opp
->oprom_size
== (uint_t
)-1)) {
2946 return (DI_PROM_PROP_NIL
);
2950 * make a copy of the property value
2952 prop
->len
= opp
->oprom_size
;
2956 else if ((prop
->data
= malloc(prop
->len
)) == NULL
) {
2959 return (DI_PROM_PROP_NIL
);
2962 bcopy(opp
->oprom_array
, prop
->data
, prop
->len
);
2965 * Prepend prop to list in prom handle
2967 prop
->next
= p
->list
;
2970 return ((di_prom_prop_t
)prop
);
2974 di_prom_prop_next(di_prom_handle_t ph
, di_node_t node
, di_prom_prop_t prom_prop
)
2976 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
2978 DPRINTF((DI_TRACE1
, "Search next prop for node 0x%p with ph 0x%p\n",
2984 if ((ph
== DI_PROM_HANDLE_NIL
) || (node
== DI_NODE_NIL
)) {
2986 return (DI_PROM_PROP_NIL
);
2989 if (di_nodeid(node
) != DI_PROM_NODEID
) {
2991 return (DI_PROM_PROP_NIL
);
2995 * synchronize access to prom file descriptor
2997 (void) mutex_lock(&p
->lock
);
3000 * look for next property
3002 prom_prop
= di_prom_prop_found(ph
, DI_NODE(node
)->nodeid
, prom_prop
);
3004 (void) mutex_unlock(&p
->lock
);
3010 di_prom_prop_name(di_prom_prop_t prom_prop
)
3015 if (prom_prop
== DI_PROM_PROP_NIL
) {
3020 return (((struct di_prom_prop
*)prom_prop
)->name
);
3024 di_prom_prop_data(di_prom_prop_t prom_prop
, uchar_t
**prom_prop_data
)
3029 if (prom_prop
== DI_PROM_PROP_NIL
) {
3034 *prom_prop_data
= ((struct di_prom_prop
*)prom_prop
)->data
;
3036 return (((struct di_prom_prop
*)prom_prop
)->len
);
3040 * Internal library interface for locating the property
3041 * Returns length if found, -1 if prop doesn't exist.
3043 static struct di_prom_prop
*
3044 di_prom_prop_lookup_common(di_prom_handle_t ph
, di_node_t node
,
3045 const char *prom_prop_name
)
3047 struct openpromio
*opp
;
3048 struct di_prom_prop
*prop
;
3049 struct di_prom_handle
*p
= (struct di_prom_handle
*)ph
;
3054 if ((ph
== DI_PROM_HANDLE_NIL
) || (node
== DI_NODE_NIL
)) {
3059 if (di_nodeid(node
) != DI_PROM_NODEID
) {
3064 opp
= &p
->oppbuf
.opp
;
3066 (void) mutex_lock(&p
->lock
);
3068 opp
->oprom_size
= sizeof (int);
3069 opp
->oprom_node
= DI_NODE(node
)->nodeid
;
3070 if (ioctl(p
->fd
, OPROMSETNODEID
, opp
) < 0) {
3072 DPRINTF((DI_ERR
, "*** Nodeid not found 0x%x\n",
3073 DI_NODE(node
)->nodeid
));
3074 (void) mutex_unlock(&p
->lock
);
3079 * get property length
3081 bzero(opp
, OBP_MAXBUF
);
3082 opp
->oprom_size
= OBP_MAXPROPLEN
;
3083 (void) strcpy(opp
->oprom_array
, prom_prop_name
);
3085 if ((ioctl(p
->fd
, OPROMGETPROPLEN
, opp
) < 0) ||
3086 (opp
->oprom_len
== -1)) {
3087 /* no such property */
3088 (void) mutex_unlock(&p
->lock
);
3093 * Prom property found. Allocate struct for storing prop
3095 if ((prop
= malloc(sizeof (struct di_prom_prop
))) == NULL
) {
3096 (void) mutex_unlock(&p
->lock
);
3099 prop
->name
= NULL
; /* we don't need the name */
3100 prop
->len
= opp
->oprom_len
;
3102 if (prop
->len
== 0) { /* boolean property */
3104 prop
->next
= p
->list
;
3106 (void) mutex_unlock(&p
->lock
);
3111 * retrieve the property value
3113 bzero(opp
, OBP_MAXBUF
);
3114 opp
->oprom_size
= OBP_MAXPROPLEN
;
3115 (void) strcpy(opp
->oprom_array
, prom_prop_name
);
3117 if ((ioctl(p
->fd
, OPROMGETPROP
, opp
) < 0) ||
3118 (opp
->oprom_size
== (uint_t
)-1)) {
3119 /* error retrieving property value */
3120 (void) mutex_unlock(&p
->lock
);
3126 * make a copy of the property value, stick in ph->list
3128 if ((prop
->data
= malloc(prop
->len
)) == NULL
) {
3129 (void) mutex_unlock(&p
->lock
);
3134 bcopy(opp
->oprom_array
, prop
->data
, prop
->len
);
3136 prop
->next
= p
->list
;
3138 (void) mutex_unlock(&p
->lock
);
3144 di_prom_prop_lookup_ints(di_prom_handle_t ph
, di_node_t node
,
3145 const char *prom_prop_name
, int **prom_prop_data
)
3148 struct di_prom_prop
*prop
;
3150 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
3153 *prom_prop_data
= NULL
;
3157 if (prop
->len
== 0) { /* boolean property */
3158 *prom_prop_data
= NULL
;
3162 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
3163 DI_PROP_TYPE_INT
, 1);
3164 *prom_prop_data
= (int *)((void *)prop
->data
);
3170 di_prom_prop_lookup_strings(di_prom_handle_t ph
, di_node_t node
,
3171 const char *prom_prop_name
, char **prom_prop_data
)
3174 struct di_prom_prop
*prop
;
3176 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
3179 *prom_prop_data
= NULL
;
3183 if (prop
->len
== 0) { /* boolean property */
3184 *prom_prop_data
= NULL
;
3189 * Fix an openprom bug (OBP string not NULL terminated).
3190 * XXX This should really be fixed in promif.
3192 if (((char *)prop
->data
)[prop
->len
- 1] != '\0') {
3195 if ((tmp
= realloc(prop
->data
, prop
->len
)) == NULL
)
3199 ((char *)prop
->data
)[prop
->len
- 1] = '\0';
3200 DPRINTF((DI_INFO
, "OBP string not NULL terminated: "
3201 "node=%s, prop=%s, val=%s\n",
3202 di_node_name(node
), prom_prop_name
, prop
->data
));
3205 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
3206 DI_PROP_TYPE_STRING
, 1);
3207 *prom_prop_data
= (char *)prop
->data
;
3213 di_prom_prop_lookup_bytes(di_prom_handle_t ph
, di_node_t node
,
3214 const char *prom_prop_name
, uchar_t
**prom_prop_data
)
3217 struct di_prom_prop
*prop
;
3219 prop
= di_prom_prop_lookup_common(ph
, node
, prom_prop_name
);
3222 *prom_prop_data
= NULL
;
3226 if (prop
->len
== 0) { /* boolean property */
3227 *prom_prop_data
= NULL
;
3231 len
= di_prop_decode_common((void *)&prop
->data
, prop
->len
,
3232 DI_PROP_TYPE_BYTE
, 1);
3233 *prom_prop_data
= prop
->data
;
3239 * returns an allocated array through <prop_data> only when its count > 0
3240 * and the number of entries (count) as the function return value;
3241 * use di_slot_names_free() to free the array
3244 di_prop_slot_names(di_prop_t prop
, di_slot_name_t
**prop_data
)
3248 char *nm
= di_prop_name(prop
);
3250 if (nm
== NULL
|| strcmp(DI_PROP_SLOT_NAMES
, nm
) != 0)
3253 rawlen
= di_prop_rawdata(prop
, &rawdata
);
3254 if (rawlen
<= 0 || rawdata
== NULL
)
3257 count
= di_slot_names_decode(rawdata
, rawlen
, prop_data
);
3258 if (count
< 0 || *prop_data
== NULL
)
3270 di_prop_lookup_slot_names(dev_t dev
, di_node_t node
,
3271 di_slot_name_t
**prop_data
)
3276 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
3277 * and slot-names is properly flagged as such
3279 if ((prop
= di_prop_find(dev
, node
, DI_PROP_SLOT_NAMES
)) ==
3285 return (di_prop_slot_names(prop
, (void *)prop_data
));
3289 * returns an allocated array through <prop_data> only when its count > 0
3290 * and the number of entries (count) as the function return value;
3291 * use di_slot_names_free() to free the array
3294 di_prom_prop_slot_names(di_prom_prop_t prom_prop
, di_slot_name_t
**prop_data
)
3299 rawlen
= di_prom_prop_data(prom_prop
, &rawdata
);
3300 if (rawlen
<= 0 || rawdata
== NULL
)
3303 count
= di_slot_names_decode(rawdata
, rawlen
, prop_data
);
3304 if (count
< 0 || *prop_data
== NULL
)
3316 di_prom_prop_lookup_slot_names(di_prom_handle_t ph
, di_node_t node
,
3317 di_slot_name_t
**prop_data
)
3319 struct di_prom_prop
*prom_prop
;
3321 prom_prop
= di_prom_prop_lookup_common(ph
, node
, DI_PROP_SLOT_NAMES
);
3322 if (prom_prop
== NULL
) {
3327 return (di_prom_prop_slot_names(prom_prop
, prop_data
));
3331 di_link_to_lnode(di_link_t link
, uint_t endpoint
)
3333 struct di_all
*di_all
;
3335 if ((link
== DI_LINK_NIL
) ||
3336 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3338 return (DI_LNODE_NIL
);
3341 di_all
= DI_ALL((caddr_t
)link
- DI_LINK(link
)->self
);
3343 if (endpoint
== DI_LINK_SRC
) {
3344 return (DI_LNODE((caddr_t
)di_all
+ DI_LINK(link
)->src_lnode
));
3346 return (DI_LNODE((caddr_t
)di_all
+ DI_LINK(link
)->tgt_lnode
));
3352 di_lnode_name(di_lnode_t lnode
)
3354 return (di_driver_name(di_lnode_devinfo(lnode
)));
3358 di_lnode_devinfo(di_lnode_t lnode
)
3360 struct di_all
*di_all
;
3362 di_all
= DI_ALL((caddr_t
)lnode
- DI_LNODE(lnode
)->self
);
3363 return (DI_NODE((caddr_t
)di_all
+ DI_LNODE(lnode
)->node
));
3367 di_lnode_devt(di_lnode_t lnode
, dev_t
*devt
)
3369 if ((lnode
== DI_LNODE_NIL
) || (devt
== NULL
)) {
3373 if ((DI_LNODE(lnode
)->dev_major
== (major_t
)-1) &&
3374 (DI_LNODE(lnode
)->dev_minor
== (minor_t
)-1))
3377 *devt
= makedev(DI_LNODE(lnode
)->dev_major
, DI_LNODE(lnode
)->dev_minor
);
3382 di_link_spectype(di_link_t link
)
3384 return (DI_LINK(link
)->spec_type
);
3388 di_minor_private_set(di_minor_t minor
, void *data
)
3390 DI_MINOR(minor
)->user_private_data
= (uintptr_t)data
;
3394 di_minor_private_get(di_minor_t minor
)
3396 return ((void *)(uintptr_t)DI_MINOR(minor
)->user_private_data
);
3400 di_node_private_set(di_node_t node
, void *data
)
3402 DI_NODE(node
)->user_private_data
= (uintptr_t)data
;
3406 di_node_private_get(di_node_t node
)
3408 return ((void *)(uintptr_t)DI_NODE(node
)->user_private_data
);
3412 di_path_private_set(di_path_t path
, void *data
)
3414 DI_PATH(path
)->user_private_data
= (uintptr_t)data
;
3418 di_path_private_get(di_path_t path
)
3420 return ((void *)(uintptr_t)DI_PATH(path
)->user_private_data
);
3424 di_lnode_private_set(di_lnode_t lnode
, void *data
)
3426 DI_LNODE(lnode
)->user_private_data
= (uintptr_t)data
;
3430 di_lnode_private_get(di_lnode_t lnode
)
3432 return ((void *)(uintptr_t)DI_LNODE(lnode
)->user_private_data
);
3436 di_link_private_set(di_link_t link
, void *data
)
3438 DI_LINK(link
)->user_private_data
= (uintptr_t)data
;
3442 di_link_private_get(di_link_t link
)
3444 return ((void *)(uintptr_t)DI_LINK(link
)->user_private_data
);
3448 di_lnode_next(di_node_t node
, di_lnode_t lnode
)
3450 struct di_all
*di_all
;
3453 * paranoid error checking
3455 if (node
== DI_NODE_NIL
) {
3457 return (DI_LNODE_NIL
);
3460 di_all
= DI_ALL((caddr_t
)node
- DI_NODE(node
)->self
);
3462 if (lnode
== DI_NODE_NIL
) {
3463 if (DI_NODE(node
)->lnodes
!= 0)
3464 return (DI_LNODE((caddr_t
)di_all
+
3465 DI_NODE(node
)->lnodes
));
3467 if (DI_LNODE(lnode
)->node_next
!= 0)
3468 return (DI_LNODE((caddr_t
)di_all
+
3469 DI_LNODE(lnode
)->node_next
));
3472 if (DINFOLYR
& DI_ALL(di_all
)->command
)
3477 return (DI_LNODE_NIL
);
3481 di_link_next_by_node(di_node_t node
, di_link_t link
, uint_t endpoint
)
3483 struct di_all
*di_all
;
3486 * paranoid error checking
3488 if ((node
== DI_NODE_NIL
) ||
3489 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3491 return (DI_LINK_NIL
);
3494 di_all
= DI_ALL((caddr_t
)node
- DI_NODE(node
)->self
);
3496 if (endpoint
== DI_LINK_SRC
) {
3497 if (link
== DI_LINK_NIL
) {
3498 if (DI_NODE(node
)->src_links
!= 0)
3499 return (DI_LINK((caddr_t
)di_all
+
3500 DI_NODE(node
)->src_links
));
3502 if (DI_LINK(link
)->src_node_next
!= 0)
3503 return (DI_LINK((caddr_t
)di_all
+
3504 DI_LINK(link
)->src_node_next
));
3507 if (link
== DI_LINK_NIL
) {
3508 if (DI_NODE(node
)->tgt_links
!= 0)
3509 return (DI_LINK((caddr_t
)di_all
+
3510 DI_NODE(node
)->tgt_links
));
3512 if (DI_LINK(link
)->tgt_node_next
!= 0)
3513 return (DI_LINK((caddr_t
)di_all
+
3514 DI_LINK(link
)->tgt_node_next
));
3518 if (DINFOLYR
& DI_ALL(di_all
)->command
)
3523 return (DI_LINK_NIL
);
3527 di_link_next_by_lnode(di_lnode_t lnode
, di_link_t link
, uint_t endpoint
)
3529 struct di_all
*di_all
;
3532 * paranoid error checking
3534 if ((lnode
== DI_LNODE_NIL
) ||
3535 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3537 return (DI_LINK_NIL
);
3540 di_all
= DI_ALL((caddr_t
)lnode
- DI_LNODE(lnode
)->self
);
3542 if (endpoint
== DI_LINK_SRC
) {
3543 if (link
== DI_LINK_NIL
) {
3544 if (DI_LNODE(lnode
)->link_out
== 0)
3545 return (DI_LINK_NIL
);
3546 return (DI_LINK((caddr_t
)di_all
+
3547 DI_LNODE(lnode
)->link_out
));
3549 if (DI_LINK(link
)->src_link_next
== 0)
3550 return (DI_LINK_NIL
);
3551 return (DI_LINK((caddr_t
)di_all
+
3552 DI_LINK(link
)->src_link_next
));
3555 if (link
== DI_LINK_NIL
) {
3556 if (DI_LNODE(lnode
)->link_in
== 0)
3557 return (DI_LINK_NIL
);
3558 return (DI_LINK((caddr_t
)di_all
+
3559 DI_LNODE(lnode
)->link_in
));
3561 if (DI_LINK(link
)->tgt_link_next
== 0)
3562 return (DI_LINK_NIL
);
3563 return (DI_LINK((caddr_t
)di_all
+
3564 DI_LINK(link
)->tgt_link_next
));
3571 * Internal library function:
3572 * Invoke callback for each link data on the link list of first node
3573 * on node_list headp, and place children of first node on the list.
3575 * This is similar to walk_one_node, except we only walk in child
3579 walk_one_link(struct node_list
**headp
, uint_t ep
,
3580 void *arg
, int (*callback
)(di_link_t link
, void *arg
))
3582 int action
= DI_WALK_CONTINUE
;
3583 di_link_t link
= DI_LINK_NIL
;
3584 di_node_t node
= (*headp
)->node
;
3586 while ((link
= di_link_next_by_node(node
, link
, ep
)) != DI_LINK_NIL
) {
3587 action
= callback(link
, arg
);
3588 if (action
== DI_WALK_TERMINATE
) {
3593 update_node_list(action
, DI_WALK_LINKGEN
, headp
);
3597 di_walk_link(di_node_t root
, uint_t flag
, uint_t endpoint
, void *arg
,
3598 int (*link_callback
)(di_link_t link
, void *arg
))
3600 struct node_list
*head
; /* node_list for tree walk */
3603 char *devfspath
= di_devfs_path(root
);
3604 DPRINTF((DI_INFO
, "walking %s link data under %s\n",
3605 (endpoint
== DI_LINK_SRC
) ? "src" : "tgt", devfspath
));
3606 di_devfs_path_free(devfspath
);
3610 * paranoid error checking
3612 if ((root
== DI_NODE_NIL
) || (link_callback
== NULL
) || (flag
!= 0) ||
3613 ((endpoint
!= DI_LINK_SRC
) && (endpoint
!= DI_LINK_TGT
))) {
3618 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
3619 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
3626 DPRINTF((DI_INFO
, "Start link data walking from node %s\n",
3627 di_node_name(root
)));
3629 while (head
!= NULL
)
3630 walk_one_link(&head
, endpoint
, arg
, link_callback
);
3636 * Internal library function:
3637 * Invoke callback for each link data on the link list of first node
3638 * on node_list headp, and place children of first node on the list.
3640 * This is similar to walk_one_node, except we only walk in child
3644 walk_one_lnode(struct node_list
**headp
, void *arg
,
3645 int (*callback
)(di_lnode_t lnode
, void *arg
))
3647 int action
= DI_WALK_CONTINUE
;
3648 di_lnode_t lnode
= DI_LNODE_NIL
;
3649 di_node_t node
= (*headp
)->node
;
3651 while ((lnode
= di_lnode_next(node
, lnode
)) != DI_LNODE_NIL
) {
3652 action
= callback(lnode
, arg
);
3653 if (action
== DI_WALK_TERMINATE
) {
3658 update_node_list(action
, DI_WALK_LINKGEN
, headp
);
3662 di_walk_lnode(di_node_t root
, uint_t flag
, void *arg
,
3663 int (*lnode_callback
)(di_lnode_t lnode
, void *arg
))
3665 struct node_list
*head
; /* node_list for tree walk */
3668 char *devfspath
= di_devfs_path(root
);
3669 DPRINTF((DI_INFO
, "walking lnode data under %s\n", devfspath
));
3670 di_devfs_path_free(devfspath
);
3674 * paranoid error checking
3676 if ((root
== DI_NODE_NIL
) || (lnode_callback
== NULL
) || (flag
!= 0)) {
3681 if ((head
= malloc(sizeof (struct node_list
))) == NULL
) {
3682 DPRINTF((DI_ERR
, "malloc of node_list failed\n"));
3689 DPRINTF((DI_INFO
, "Start lnode data walking from node %s\n",
3690 di_node_name(root
)));
3692 while (head
!= NULL
)
3693 walk_one_lnode(&head
, arg
, lnode_callback
);
3699 alias_to_curr(di_node_t anynode
, char *devfspath
, di_node_t
*nodep
)
3703 struct di_alias
*di_alias
;
3709 char buf
[MAXPATHLEN
];
3713 if (anynode
== DI_NODE_NIL
|| devfspath
== NULL
)
3716 pa
= (caddr_t
)anynode
- DI_NODE(anynode
)->self
;
3720 for (off
= all
->aliases
; off
> 0; off
= di_alias
->next
) {
3721 di_alias
= DI_ALIAS(pa
+ off
);
3722 alias
= di_alias
->alias
;
3723 if (strncmp(devfspath
, alias
, strlen(alias
)) == 0) {
3724 cp
= devfspath
+ strlen(alias
);
3725 node
= DI_NODE(pa
+ di_alias
->curroff
);
3726 assert(node
!= DI_NODE_NIL
);
3730 } else if (*cp
== '/') {
3731 curr
= di_devfs_path(node
);
3732 (void) snprintf(buf
, sizeof (buf
), "%s%s",
3734 di_devfs_path_free(curr
);
3745 di_lookup_node_impl(di_node_t root
, char *devfspath
)
3749 char *copy
, *slash
, *pname
, *paddr
;
3752 * Path must be absolute and musn't have duplicate slashes
3754 if (*devfspath
!= '/' || strstr(devfspath
, "//")) {
3755 DPRINTF((DI_ERR
, "Invalid path: %s\n", devfspath
));
3756 return (DI_NODE_NIL
);
3759 if (root
== DI_NODE_NIL
) {
3760 DPRINTF((DI_ERR
, "root node is DI_NODE_NIL\n"));
3761 return (DI_NODE_NIL
);
3764 dap
= DI_ALL((caddr_t
)root
- DI_NODE(root
)->self
);
3765 if (strcmp(dap
->root_path
, "/") != 0) {
3766 DPRINTF((DI_ERR
, "snapshot root not / : %s\n", dap
->root_path
));
3767 return (DI_NODE_NIL
);
3770 if ((copy
= strdup(devfspath
)) == NULL
) {
3771 DPRINTF((DI_ERR
, "strdup failed on: %s\n", devfspath
));
3772 return (DI_NODE_NIL
);
3775 for (slash
= copy
, node
= root
; slash
; ) {
3778 * Handle devfspath = "/" case as well as trailing '/'
3780 if (*(slash
+ 1) == '\0')
3784 * More path-components exist. Deal with the next one
3787 node
= di_child_node(node
);
3789 if (slash
= strchr(pname
, '/'))
3791 if (paddr
= strchr(pname
, '@'))
3794 for (; node
!= DI_NODE_NIL
; node
= di_sibling_node(node
)) {
3797 name
= di_node_name(node
);
3798 baddr
= di_bus_addr(node
);
3800 if (strcmp(pname
, name
) != 0)
3804 * Mappings between a "path-address" and bus-addr
3807 * ---------------------
3810 * "" N/A (invalid paddr)
3812 if (paddr
&& baddr
&& strcmp(paddr
, baddr
) == 0)
3814 if (paddr
== NULL
&& (baddr
== NULL
|| *baddr
== '\0'))
3819 * No nodes in the sibling list or there was no match
3821 if (node
== DI_NODE_NIL
) {
3822 DPRINTF((DI_ERR
, "%s@%s: no node\n", pname
, paddr
));
3824 return (DI_NODE_NIL
);
3828 assert(node
!= DI_NODE_NIL
);
3834 di_lookup_node(di_node_t root
, char *devfspath
)
3839 node
= di_lookup_node_impl(root
, devfspath
);
3840 if (node
!= DI_NODE_NIL
) {
3844 /* node is already set to DI_NODE_NIL */
3845 curr
= alias_to_curr(root
, devfspath
, &node
);
3847 /* node may or may node be DI_NODE_NIL */
3851 node
= di_lookup_node_impl(root
, curr
);
3859 di_alias2curr(di_node_t anynode
, char *alias
)
3861 di_node_t currnode
= DI_NODE_NIL
;
3864 if (anynode
== DI_NODE_NIL
|| alias
== NULL
)
3867 curr
= alias_to_curr(anynode
, alias
, &currnode
);
3868 if (curr
== NULL
&& currnode
!= DI_NODE_NIL
) {
3869 return (di_devfs_path(currnode
));
3870 } else if (curr
== NULL
) {
3871 return (strdup(alias
));
3878 di_lookup_path(di_node_t root
, char *devfspath
)
3880 di_node_t phci_node
;
3881 di_path_t path
= DI_PATH_NIL
;
3882 char *copy
, *lastslash
;
3883 char *pname
, *paddr
;
3884 char *path_name
, *path_addr
;
3886 if ((copy
= strdup(devfspath
)) == NULL
) {
3887 DPRINTF((DI_ERR
, "strdup failed on: %s\n", devfspath
));
3888 return (DI_NODE_NIL
);
3891 if ((lastslash
= strrchr(copy
, '/')) == NULL
) {
3892 DPRINTF((DI_ERR
, "failed to find component: %s\n", devfspath
));
3896 /* stop at pHCI and find the node for the phci */
3898 phci_node
= di_lookup_node(root
, copy
);
3899 if (phci_node
== NULL
) {
3900 DPRINTF((DI_ERR
, "failed to find component: %s\n", devfspath
));
3904 /* set up pname and paddr for last component */
3905 pname
= lastslash
+ 1;
3906 if ((paddr
= strchr(pname
, '@')) == NULL
) {
3907 DPRINTF((DI_ERR
, "failed to find unit-addr: %s\n", devfspath
));
3912 /* walk paths below phci looking for match */
3913 for (path
= di_path_phci_next_path(phci_node
, DI_PATH_NIL
);
3914 path
!= DI_PATH_NIL
;
3915 path
= di_path_phci_next_path(phci_node
, path
)) {
3917 /* get name@addr of path */
3918 path_name
= di_path_node_name(path
);
3919 path_addr
= di_path_bus_addr(path
);
3920 if ((path_name
== NULL
) || (path_addr
== NULL
))
3923 /* break on match */
3924 if ((strcmp(pname
, path_name
) == 0) &&
3925 (strcmp(paddr
, path_addr
) == 0))
3934 msglevel2str(di_debug_t msglevel
)
3953 dprint(di_debug_t msglevel
, const char *fmt
, ...)
3958 if (di_debug
<= DI_QUIET
)
3961 if (di_debug
< msglevel
)
3964 estr
= msglevel2str(msglevel
);
3970 (void) fprintf(stderr
, "libdevinfo[%lu]: %s: ",
3971 (ulong_t
)getpid(), estr
);
3972 (void) vfprintf(stderr
, fmt
, ap
);
3977 /* end of devinfo.c */