1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2024 MNX Cloud, Inc.
24 * Copyright 2026 Oxide Computer Company
25 */
26
27 /*
28 * Interfaces for getting device configuration data from kernel
29 * through the devinfo driver.
30 */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <stropts.h>
37 #include <fcntl.h>
38 #include <poll.h>
39 #include <synch.h>
40 #include <unistd.h>
41 #include <sys/mkdev.h>
42 #include <sys/obpdefs.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/time.h>
46 #include <sys/autoconf.h>
47 #include <stdarg.h>
48 #include <sys/ddi_hp.h>
49
50 #define NDEBUG 1
51 #include <assert.h>
52
53 #include "libdevinfo.h"
54
55 /*
56 * Debug message levels
57 */
58 typedef enum {
59 DI_QUIET = 0, /* No debug messages - the default */
60 DI_ERR = 1,
61 DI_INFO,
62 DI_TRACE,
63 DI_TRACE1,
64 DI_TRACE2
65 } di_debug_t;
66
67 int di_debug = DI_QUIET;
68
69 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; }
70
71 void dprint(di_debug_t msglevel, const char *fmt, ...);
72
73
74 #pragma init(_libdevinfo_init)
75
76 void
_libdevinfo_init()77 _libdevinfo_init()
78 {
79 char *debug_str = getenv("_LIBDEVINFO_DEBUG");
80
81 if (debug_str) {
82 errno = 0;
83 di_debug = atoi(debug_str);
84 if (errno || di_debug < DI_QUIET)
85 di_debug = DI_QUIET;
86 }
87 }
88
89 di_node_t
di_init(const char * phys_path,uint_t flag)90 di_init(const char *phys_path, uint_t flag)
91 {
92 return (di_init_impl(phys_path, flag, NULL));
93 }
94
95 /*
96 * We use blocking_open() to guarantee access to the devinfo device, if open()
97 * is failing with EAGAIN.
98 */
99 static int
blocking_open(const char * path,int oflag)100 blocking_open(const char *path, int oflag)
101 {
102 int fd;
103
104 while ((fd = open(path, oflag)) == -1 && errno == EAGAIN)
105 (void) poll(NULL, 0, 1 * MILLISEC);
106
107 return (fd);
108 }
109
110 /* private interface */
111 di_node_t
di_init_driver(const char * drv_name,uint_t flag)112 di_init_driver(const char *drv_name, uint_t flag)
113 {
114 int fd;
115 char driver[MAXPATHLEN];
116
117 /*
118 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023,
119 * which should be sufficient for any sensible programmer.
120 */
121 if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) {
122 errno = EINVAL;
123 return (DI_NODE_NIL);
124 }
125 (void) strcpy(driver, drv_name);
126
127 /*
128 * open the devinfo driver
129 */
130 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
131 O_RDONLY)) == -1) {
132 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno));
133 return (DI_NODE_NIL);
134 }
135
136 if (ioctl(fd, DINFOLODRV, driver) != 0) {
137 DPRINTF((DI_ERR, "failed to load driver %s\n", driver));
138 (void) close(fd);
139 errno = ENXIO;
140 return (DI_NODE_NIL);
141 }
142 (void) close(fd);
143
144 /*
145 * Driver load succeeded, return a snapshot
146 */
147 return (di_init("/", flag));
148 }
149
150 di_node_t
di_init_impl(const char * phys_path,uint_t flag,struct di_priv_data * priv)151 di_init_impl(const char *phys_path, uint_t flag,
152 struct di_priv_data *priv)
153 {
154 caddr_t pa;
155 int fd, map_size;
156 struct di_all *dap;
157 struct dinfo_io dinfo_io;
158
159 uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1;
160 uint_t pagemask = ~pageoffset;
161
162 DPRINTF((DI_INFO, "di_init: taking a snapshot\n"));
163
164 /*
165 * Make sure there is no minor name in the path
166 * and the path does not start with /devices.
167 * The length check accounts for a '/' prefix and NUL terminator.
168 */
169 if (phys_path == NULL ||
170 strchr(phys_path, ':') ||
171 (strncmp(phys_path, "/devices", 8) == 0) ||
172 (strlen(phys_path) > sizeof (dinfo_io.root_path) - 2)) {
173 errno = EINVAL;
174 return (DI_NODE_NIL);
175 }
176
177 if (strlen(phys_path) == 0)
178 (void) sprintf(dinfo_io.root_path, "/");
179 else if (*phys_path != '/')
180 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
181 "/%s", phys_path);
182 else
183 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path),
184 "%s", phys_path);
185
186 /*
187 * If private data is requested, copy the format specification
188 */
189 if (flag & DINFOPRIVDATA & 0xff) {
190 if (priv)
191 bcopy(priv, &dinfo_io.priv,
192 sizeof (struct di_priv_data));
193 else {
194 errno = EINVAL;
195 return (DI_NODE_NIL);
196 }
197 }
198
199 /*
200 * Attempt to open the devinfo driver. Make a second attempt at the
201 * read-only minor node if we don't have privileges to open the full
202 * version _and_ if we're not requesting operations that the read-only
203 * node can't perform. (Setgid processes would fail an access() test,
204 * of course.)
205 */
206 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo",
207 O_RDONLY)) == -1) {
208 if ((flag & DINFOFORCE) == DINFOFORCE ||
209 (flag & DINFOPRIVDATA) == DINFOPRIVDATA) {
210 /*
211 * We wanted to perform a privileged operation, but the
212 * privileged node isn't available. Don't modify errno
213 * on our way out (but display it if we're running with
214 * di_debug set).
215 */
216 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
217 errno));
218 return (DI_NODE_NIL);
219 }
220
221 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro",
222 O_RDONLY)) == -1) {
223 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n",
224 errno));
225 return (DI_NODE_NIL);
226 }
227 }
228
229 /*
230 * Verify that there is no major conflict, i.e., we are indeed opening
231 * the devinfo driver.
232 */
233 if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) {
234 DPRINTF((DI_ERR,
235 "driver ID failed; check for major conflict\n"));
236 (void) close(fd);
237 return (DI_NODE_NIL);
238 }
239
240 /*
241 * create snapshot
242 */
243 if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) {
244 DPRINTF((DI_ERR, "devinfo ioctl failed with "
245 "error: %d\n", errno));
246 (void) close(fd);
247 return (DI_NODE_NIL);
248 } else if (map_size == 0) {
249 DPRINTF((DI_ERR, "%s not found\n", phys_path));
250 errno = ENXIO;
251 (void) close(fd);
252 return (DI_NODE_NIL);
253 }
254
255 /*
256 * copy snapshot to userland
257 */
258 map_size = (map_size + pageoffset) & pagemask;
259 if ((pa = valloc(map_size)) == NULL) {
260 DPRINTF((DI_ERR, "valloc failed for snapshot\n"));
261 (void) close(fd);
262 return (DI_NODE_NIL);
263 }
264
265 if (ioctl(fd, DINFOUSRLD, pa) != map_size) {
266 DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n"));
267 (void) close(fd);
268 free(pa);
269 errno = EFAULT;
270 return (DI_NODE_NIL);
271 }
272
273 (void) close(fd);
274
275 dap = DI_ALL(pa);
276 if (dap->version != DI_SNAPSHOT_VERSION) {
277 DPRINTF((DI_ERR, "wrong snapshot version "
278 "(expected=%d, actual=%d)\n",
279 DI_SNAPSHOT_VERSION, dap->version));
280 free(pa);
281 errno = ESTALE;
282 return (DI_NODE_NIL);
283 }
284 if (dap->top_devinfo == 0) { /* phys_path not found */
285 DPRINTF((DI_ERR, "%s not found\n", phys_path));
286 free(pa);
287 errno = EINVAL;
288 return (DI_NODE_NIL);
289 }
290
291 return (DI_NODE(pa + dap->top_devinfo));
292 }
293
294 void
di_fini(di_node_t root)295 di_fini(di_node_t root)
296 {
297 caddr_t pa; /* starting address of map */
298
299 DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n"));
300
301 /*
302 * paranoid checking
303 */
304 if (root == DI_NODE_NIL) {
305 DPRINTF((DI_ERR, "di_fini called with NIL arg\n"));
306 return;
307 }
308
309 /*
310 * The root contains its own offset--self.
311 * Subtracting it from root address, we get the starting addr.
312 * The map_size is stored at the beginning of snapshot.
313 * Once we have starting address and size, we can free().
314 */
315 pa = (caddr_t)root - DI_NODE(root)->self;
316
317 free(pa);
318 }
319
320 di_node_t
di_parent_node(di_node_t node)321 di_parent_node(di_node_t node)
322 {
323 caddr_t pa; /* starting address of map */
324
325 if (node == DI_NODE_NIL) {
326 errno = EINVAL;
327 return (DI_NODE_NIL);
328 }
329
330 DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node)));
331
332 pa = (caddr_t)node - DI_NODE(node)->self;
333
334 if (DI_NODE(node)->parent) {
335 return (DI_NODE(pa + DI_NODE(node)->parent));
336 }
337
338 /*
339 * Deal with error condition:
340 * If parent doesn't exist and node is not the root,
341 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
342 */
343 if (strcmp(DI_ALL(pa)->root_path, "/") != 0)
344 errno = ENOTSUP;
345 else
346 errno = ENXIO;
347
348 return (DI_NODE_NIL);
349 }
350
351 di_node_t
di_sibling_node(di_node_t node)352 di_sibling_node(di_node_t node)
353 {
354 caddr_t pa; /* starting address of map */
355
356 if (node == DI_NODE_NIL) {
357 errno = EINVAL;
358 return (DI_NODE_NIL);
359 }
360
361 DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node)));
362
363 pa = (caddr_t)node - DI_NODE(node)->self;
364
365 if (DI_NODE(node)->sibling) {
366 return (DI_NODE(pa + DI_NODE(node)->sibling));
367 }
368
369 /*
370 * Deal with error condition:
371 * Sibling doesn't exist, figure out if ioctl command
372 * has DINFOSUBTREE set. If it doesn't, set errno to
373 * ENOTSUP.
374 */
375 if (!(DI_ALL(pa)->command & DINFOSUBTREE))
376 errno = ENOTSUP;
377 else
378 errno = ENXIO;
379
380 return (DI_NODE_NIL);
381 }
382
383 di_node_t
di_child_node(di_node_t node)384 di_child_node(di_node_t node)
385 {
386 caddr_t pa; /* starting address of map */
387
388 DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node)));
389
390 if (node == DI_NODE_NIL) {
391 errno = EINVAL;
392 return (DI_NODE_NIL);
393 }
394
395 pa = (caddr_t)node - DI_NODE(node)->self;
396
397 if (DI_NODE(node)->child) {
398 return (DI_NODE(pa + DI_NODE(node)->child));
399 }
400
401 /*
402 * Deal with error condition:
403 * Child doesn't exist, figure out if DINFOSUBTREE is set.
404 * If it isn't, set errno to ENOTSUP.
405 */
406 if (!(DI_ALL(pa)->command & DINFOSUBTREE))
407 errno = ENOTSUP;
408 else
409 errno = ENXIO;
410
411 return (DI_NODE_NIL);
412 }
413
414 di_node_t
di_drv_first_node(const char * drv_name,di_node_t root)415 di_drv_first_node(const char *drv_name, di_node_t root)
416 {
417 caddr_t pa; /* starting address of map */
418 int major, devcnt;
419 struct di_devnm *devnm;
420
421 DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name));
422
423 if (root == DI_NODE_NIL) {
424 errno = EINVAL;
425 return (DI_NODE_NIL);
426 }
427
428 /*
429 * get major number of driver
430 */
431 pa = (caddr_t)root - DI_NODE(root)->self;
432 devcnt = DI_ALL(pa)->devcnt;
433 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
434
435 for (major = 0; major < devcnt; major++)
436 if (devnm[major].name && (strcmp(drv_name,
437 (char *)(pa + devnm[major].name)) == 0))
438 break;
439
440 if (major >= devcnt) {
441 errno = EINVAL;
442 return (DI_NODE_NIL);
443 }
444
445 if (!(devnm[major].head)) {
446 errno = ENXIO;
447 return (DI_NODE_NIL);
448 }
449
450 return (DI_NODE(pa + devnm[major].head));
451 }
452
453 di_node_t
di_drv_next_node(di_node_t node)454 di_drv_next_node(di_node_t node)
455 {
456 caddr_t pa; /* starting address of map */
457
458 if (node == DI_NODE_NIL) {
459 errno = EINVAL;
460 return (DI_NODE_NIL);
461 }
462
463 DPRINTF((DI_TRACE, "next node on per driver list:"
464 " current=%s, driver=%s\n",
465 di_node_name(node), di_driver_name(node)));
466
467 if (DI_NODE(node)->next == (di_off_t)-1) {
468 errno = ENOTSUP;
469 return (DI_NODE_NIL);
470 }
471
472 pa = (caddr_t)node - DI_NODE(node)->self;
473
474 if (DI_NODE(node)->next == 0) {
475 errno = ENXIO;
476 return (DI_NODE_NIL);
477 }
478
479 return (DI_NODE(pa + DI_NODE(node)->next));
480 }
481
482 /*
483 * Internal library interfaces:
484 * node_list etc. for node walking
485 */
486 struct node_list {
487 struct node_list *next;
488 di_node_t node;
489 };
490
491 static void
free_node_list(struct node_list ** headp)492 free_node_list(struct node_list **headp)
493 {
494 struct node_list *tmp;
495
496 while (*headp) {
497 tmp = *headp;
498 *headp = (*headp)->next;
499 free(tmp);
500 }
501 }
502
503 static void
append_node_list(struct node_list ** headp,struct node_list * list)504 append_node_list(struct node_list **headp, struct node_list *list)
505 {
506 struct node_list *tmp;
507
508 if (*headp == NULL) {
509 *headp = list;
510 return;
511 }
512
513 if (list == NULL) /* a minor optimization */
514 return;
515
516 tmp = *headp;
517 while (tmp->next)
518 tmp = tmp->next;
519
520 tmp->next = list;
521 }
522
523 static void
prepend_node_list(struct node_list ** headp,struct node_list * list)524 prepend_node_list(struct node_list **headp, struct node_list *list)
525 {
526 struct node_list *tmp;
527
528 if (list == NULL)
529 return;
530
531 tmp = *headp;
532 *headp = list;
533
534 if (tmp == NULL) /* a minor optimization */
535 return;
536
537 while (list->next)
538 list = list->next;
539
540 list->next = tmp;
541 }
542
543 /*
544 * returns 1 if node is a descendant of parent, 0 otherwise
545 */
546 static int
is_descendant(di_node_t node,di_node_t parent)547 is_descendant(di_node_t node, di_node_t parent)
548 {
549 /*
550 * DI_NODE_NIL is parent of root, so it is
551 * the parent of all nodes.
552 */
553 if (parent == DI_NODE_NIL) {
554 return (1);
555 }
556
557 do {
558 node = di_parent_node(node);
559 } while ((node != DI_NODE_NIL) && (node != parent));
560
561 return (node != DI_NODE_NIL);
562 }
563
564 /*
565 * Insert list before the first node which is NOT a descendent of parent.
566 * This is needed to reproduce the exact walking order of link generators.
567 */
568 static void
insert_node_list(struct node_list ** headp,struct node_list * list,di_node_t parent)569 insert_node_list(struct node_list **headp, struct node_list *list,
570 di_node_t parent)
571 {
572 struct node_list *tmp, *tmp1;
573
574 if (list == NULL)
575 return;
576
577 tmp = *headp;
578 if (tmp == NULL) { /* a minor optimization */
579 *headp = list;
580 return;
581 }
582
583 if (!is_descendant(tmp->node, parent)) {
584 prepend_node_list(headp, list);
585 return;
586 }
587
588 /*
589 * Find first node which is not a descendant
590 */
591 while (tmp->next && is_descendant(tmp->next->node, parent)) {
592 tmp = tmp->next;
593 }
594
595 tmp1 = tmp->next;
596 tmp->next = list;
597 append_node_list(headp, tmp1);
598 }
599
600 /*
601 * Get a linked list of handles of all children
602 */
603 static struct node_list *
get_children(di_node_t node)604 get_children(di_node_t node)
605 {
606 di_node_t child;
607 struct node_list *result, *tmp;
608
609 DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node)));
610
611 if ((child = di_child_node(node)) == DI_NODE_NIL) {
612 return (NULL);
613 }
614
615 if ((result = malloc(sizeof (struct node_list))) == NULL) {
616 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
617 return (NULL);
618 }
619
620 result->node = child;
621 tmp = result;
622
623 while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) {
624 if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) {
625 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
626 free_node_list(&result);
627 return (NULL);
628 }
629 tmp = tmp->next;
630 tmp->node = child;
631 }
632
633 tmp->next = NULL;
634
635 return (result);
636 }
637
638 /*
639 * Internal library interface:
640 * Delete all siblings of the first node from the node_list, along with
641 * the first node itself.
642 */
643 static void
prune_sib(struct node_list ** headp)644 prune_sib(struct node_list **headp)
645 {
646 di_node_t parent, curr_par, curr_gpar;
647 struct node_list *curr, *prev;
648
649 /*
650 * get handle to parent of first node
651 */
652 if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) {
653 /*
654 * This must be the root of the snapshot, so can't
655 * have any siblings.
656 *
657 * XXX Put a check here just in case.
658 */
659 if ((*headp)->next)
660 DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n"));
661
662 free(*headp);
663 *headp = NULL;
664 return;
665 }
666
667 /*
668 * To be complete, we should also delete the children
669 * of siblings that have already been visited.
670 * This happens for DI_WALK_SIBFIRST when the first node
671 * is NOT the first in the linked list of siblings.
672 *
673 * Hence, we compare parent with BOTH the parent and grandparent
674 * of nodes, and delete node is a match is found.
675 */
676 prev = *headp;
677 curr = prev->next;
678 while (curr) {
679 if ((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL &&
680 (curr_par == parent ||
681 ((curr_gpar = di_parent_node(curr_par)) != DI_NODE_NIL &&
682 curr_gpar == parent))) {
683 /*
684 * match parent/grandparent: delete curr
685 */
686 prev->next = curr->next;
687 free(curr);
688 curr = prev->next;
689 } else
690 curr = curr->next;
691 }
692
693 /*
694 * delete the first node
695 */
696 curr = *headp;
697 *headp = curr->next;
698 free(curr);
699 }
700
701 /*
702 * Internal library function:
703 * Update node list based on action (return code from callback)
704 * and flag specifying walking behavior.
705 */
706 static void
update_node_list(int action,uint_t flag,struct node_list ** headp)707 update_node_list(int action, uint_t flag, struct node_list **headp)
708 {
709 struct node_list *children, *tmp;
710 di_node_t parent = di_parent_node((*headp)->node);
711
712 switch (action) {
713 case DI_WALK_TERMINATE:
714 /*
715 * free the node list and be done
716 */
717 children = NULL;
718 free_node_list(headp);
719 break;
720
721 case DI_WALK_PRUNESIB:
722 /*
723 * Get list of children and prune siblings
724 */
725 children = get_children((*headp)->node);
726 prune_sib(headp);
727 break;
728
729 case DI_WALK_PRUNECHILD:
730 /*
731 * Set children to NULL and pop first node
732 */
733 children = NULL;
734 tmp = *headp;
735 *headp = tmp->next;
736 free(tmp);
737 break;
738
739 case DI_WALK_CONTINUE:
740 default:
741 /*
742 * Get list of children and pop first node
743 */
744 children = get_children((*headp)->node);
745 tmp = *headp;
746 *headp = tmp->next;
747 free(tmp);
748 break;
749 }
750
751 /*
752 * insert the list of children
753 */
754 switch (flag) {
755 case DI_WALK_CLDFIRST:
756 prepend_node_list(headp, children);
757 break;
758
759 case DI_WALK_SIBFIRST:
760 append_node_list(headp, children);
761 break;
762
763 case DI_WALK_LINKGEN:
764 default:
765 insert_node_list(headp, children, parent);
766 break;
767 }
768 }
769
770 /*
771 * Internal library function:
772 * Invoke callback on one node and update the list of nodes to be walked
773 * based on the flag and return code.
774 */
775 static void
walk_one_node(struct node_list ** headp,uint_t flag,void * arg,int (* callback)(di_node_t,void *))776 walk_one_node(struct node_list **headp, uint_t flag, void *arg,
777 int (*callback)(di_node_t, void *))
778 {
779 DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node)));
780
781 update_node_list(callback((*headp)->node, arg),
782 flag & DI_WALK_MASK, headp);
783 }
784
785 int
di_walk_node(di_node_t root,uint_t flag,void * arg,int (* node_callback)(di_node_t,void *))786 di_walk_node(di_node_t root, uint_t flag, void *arg,
787 int (*node_callback)(di_node_t, void *))
788 {
789 struct node_list *head; /* node_list for tree walk */
790
791 if (root == NULL) {
792 errno = EINVAL;
793 return (-1);
794 }
795
796 if ((head = malloc(sizeof (struct node_list))) == NULL) {
797 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
798 return (-1);
799 }
800
801 head->next = NULL;
802 head->node = root;
803
804 DPRINTF((DI_INFO, "Start node walking from node %s\n",
805 di_node_name(root)));
806
807 while (head != NULL)
808 walk_one_node(&head, flag, arg, node_callback);
809
810 return (0);
811 }
812
813 /*
814 * Internal library function:
815 * Invoke callback for each minor on the minor list of first node
816 * on node_list headp, and place children of first node on the list.
817 *
818 * This is similar to walk_one_node, except we only walk in child
819 * first mode.
820 */
821 static void
walk_one_minor_list(struct node_list ** headp,const char * desired_type,uint_t flag,void * arg,int (* callback)(di_node_t,di_minor_t,void *))822 walk_one_minor_list(struct node_list **headp, const char *desired_type,
823 uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *))
824 {
825 int ddm_type;
826 int action = DI_WALK_CONTINUE;
827 char *node_type;
828 di_minor_t minor = DI_MINOR_NIL;
829 di_node_t node = (*headp)->node;
830
831 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
832 ddm_type = di_minor_type(minor);
833
834 if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS))
835 continue;
836
837 if ((ddm_type == DDM_INTERNAL_PATH) &&
838 !(flag & DI_CHECK_INTERNAL_PATH))
839 continue;
840
841 node_type = di_minor_nodetype(minor);
842 if ((desired_type != NULL) && ((node_type == NULL) ||
843 strncmp(desired_type, node_type, strlen(desired_type))
844 != 0))
845 continue;
846
847 if ((action = callback(node, minor, arg)) ==
848 DI_WALK_TERMINATE) {
849 break;
850 }
851 }
852
853 update_node_list(action, DI_WALK_LINKGEN, headp);
854 }
855
856 int
di_walk_minor(di_node_t root,const char * minor_type,uint_t flag,void * arg,int (* minor_callback)(di_node_t,di_minor_t,void *))857 di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg,
858 int (*minor_callback)(di_node_t, di_minor_t, void *))
859 {
860 struct node_list *head; /* node_list for tree walk */
861
862 #ifdef DEBUG
863 char *devfspath = di_devfs_path(root);
864 DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath));
865 di_devfs_path_free(devfspath);
866 #endif
867
868 if (root == NULL) {
869 errno = EINVAL;
870 return (-1);
871 }
872
873 if ((head = malloc(sizeof (struct node_list))) == NULL) {
874 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
875 return (-1);
876 }
877
878 head->next = NULL;
879 head->node = root;
880
881 DPRINTF((DI_INFO, "Start minor walking from node %s\n",
882 di_node_name(root)));
883
884 while (head != NULL)
885 walk_one_minor_list(&head, minor_type, flag, arg,
886 minor_callback);
887
888 return (0);
889 }
890
891 /*
892 * generic node parameters
893 * Calling these routines always succeeds.
894 */
895 char *
di_node_name(di_node_t node)896 di_node_name(di_node_t node)
897 {
898 return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self);
899 }
900
901 /* returns NULL ptr or a valid ptr to non-NULL string */
902 char *
di_bus_addr(di_node_t node)903 di_bus_addr(di_node_t node)
904 {
905 caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
906
907 if (DI_NODE(node)->address == 0)
908 return (NULL);
909
910 return ((char *)(pa + DI_NODE(node)->address));
911 }
912
913 char *
di_binding_name(di_node_t node)914 di_binding_name(di_node_t node)
915 {
916 caddr_t pa = (caddr_t)node - DI_NODE(node)->self;
917
918 if (DI_NODE(node)->bind_name == 0)
919 return (NULL);
920
921 return ((char *)(pa + DI_NODE(node)->bind_name));
922 }
923
924 int
di_compatible_names(di_node_t node,char ** names)925 di_compatible_names(di_node_t node, char **names)
926 {
927 char *c;
928 int len, size, entries = 0;
929
930 if (DI_NODE(node)->compat_names == 0) {
931 *names = NULL;
932 return (0);
933 }
934
935 *names = (caddr_t)node +
936 DI_NODE(node)->compat_names - DI_NODE(node)->self;
937
938 c = *names;
939 len = DI_NODE(node)->compat_length;
940 while (len > 0) {
941 entries++;
942 size = strlen(c) + 1;
943 len -= size;
944 c += size;
945 }
946
947 return (entries);
948 }
949
950 int
di_instance(di_node_t node)951 di_instance(di_node_t node)
952 {
953 return (DI_NODE(node)->instance);
954 }
955
956 /*
957 * XXX: emulate the return value of the old implementation
958 * using info from devi_node_class and devi_node_attributes.
959 */
960 int
di_nodeid(di_node_t node)961 di_nodeid(di_node_t node)
962 {
963 if (DI_NODE(node)->node_class == DDI_NC_PROM)
964 return (DI_PROM_NODEID);
965
966 if (DI_NODE(node)->attributes & DDI_PERSISTENT)
967 return (DI_SID_NODEID);
968
969 return (DI_PSEUDO_NODEID);
970 }
971
972 uint_t
di_state(di_node_t node)973 di_state(di_node_t node)
974 {
975 uint_t result = 0;
976
977 if (di_node_state(node) < DS_ATTACHED)
978 result |= DI_DRIVER_DETACHED;
979 if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
980 result |= DI_DEVICE_OFFLINE;
981 if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
982 result |= DI_DEVICE_DOWN;
983 if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
984 result |= DI_DEVICE_DEGRADED;
985 if (DI_NODE(node)->state & DEVI_DEVICE_REMOVED)
986 result |= DI_DEVICE_REMOVED;
987 if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
988 result |= DI_BUS_QUIESCED;
989 if (DI_NODE(node)->state & DEVI_BUS_DOWN)
990 result |= DI_BUS_DOWN;
991
992 return (result);
993 }
994
995 ddi_node_state_t
di_node_state(di_node_t node)996 di_node_state(di_node_t node)
997 {
998 return (DI_NODE(node)->node_state);
999 }
1000
1001 uint_t
di_flags(di_node_t node)1002 di_flags(di_node_t node)
1003 {
1004 return (DI_NODE(node)->flags);
1005 }
1006
1007 uint_t
di_retired(di_node_t node)1008 di_retired(di_node_t node)
1009 {
1010 return (di_flags(node) & DEVI_RETIRED);
1011 }
1012
1013 ddi_devid_t
di_devid(di_node_t node)1014 di_devid(di_node_t node)
1015 {
1016 if (DI_NODE(node)->devid == 0)
1017 return (NULL);
1018
1019 return ((ddi_devid_t)((caddr_t)node +
1020 DI_NODE(node)->devid - DI_NODE(node)->self));
1021 }
1022
1023 int
di_driver_major(di_node_t node)1024 di_driver_major(di_node_t node)
1025 {
1026 int major;
1027
1028 major = DI_NODE(node)->drv_major;
1029 if (major < 0)
1030 return (-1);
1031 return (major);
1032 }
1033
1034 char *
di_driver_name(di_node_t node)1035 di_driver_name(di_node_t node)
1036 {
1037 int major;
1038 caddr_t pa;
1039 struct di_devnm *devnm;
1040
1041 major = DI_NODE(node)->drv_major;
1042 if (major < 0)
1043 return (NULL);
1044
1045 pa = (caddr_t)node - DI_NODE(node)->self;
1046 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1047
1048 if (devnm[major].name)
1049 return (pa + devnm[major].name);
1050 else
1051 return (NULL);
1052 }
1053
1054 uint_t
di_driver_ops(di_node_t node)1055 di_driver_ops(di_node_t node)
1056 {
1057 int major;
1058 caddr_t pa;
1059 struct di_devnm *devnm;
1060
1061 major = DI_NODE(node)->drv_major;
1062 if (major < 0)
1063 return (0);
1064
1065 pa = (caddr_t)node - DI_NODE(node)->self;
1066 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames);
1067
1068 return (devnm[major].ops);
1069 }
1070
1071 /*
1072 * Returns pointer to the allocated string, which must be freed by the caller.
1073 */
1074 char *
di_devfs_path(di_node_t node)1075 di_devfs_path(di_node_t node)
1076 {
1077 caddr_t pa;
1078 di_node_t parent;
1079 int depth = 0, len = 0;
1080 char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH];
1081
1082 if (node == DI_NODE_NIL) {
1083 errno = EINVAL;
1084 return (NULL);
1085 }
1086
1087 /*
1088 * trace back to root, note the node_name & address
1089 */
1090 while ((parent = di_parent_node(node)) != DI_NODE_NIL) {
1091 name[depth] = di_node_name(node);
1092 len += strlen(name[depth]) + 1; /* 1 for '/' */
1093
1094 if ((addr[depth] = di_bus_addr(node)) != NULL)
1095 len += strlen(addr[depth]) + 1; /* 1 for '@' */
1096
1097 node = parent;
1098 depth++;
1099 }
1100
1101 /*
1102 * get the path to the root of snapshot
1103 */
1104 pa = (caddr_t)node - DI_NODE(node)->self;
1105 name[depth] = DI_ALL(pa)->root_path;
1106 len += strlen(name[depth]) + 1;
1107
1108 /*
1109 * allocate buffer and assemble path
1110 */
1111 if ((buf = malloc(len)) == NULL) {
1112 return (NULL);
1113 }
1114
1115 (void) strcpy(buf, name[depth]);
1116 len = strlen(buf);
1117 if (buf[len - 1] == '/')
1118 len--; /* delete trailing '/' */
1119
1120 while (depth) {
1121 depth--;
1122 buf[len] = '/';
1123 (void) strcpy(buf + len + 1, name[depth]);
1124 len += strlen(name[depth]) + 1;
1125 if (addr[depth] && addr[depth][0] != '\0') {
1126 buf[len] = '@';
1127 (void) strcpy(buf + len + 1, addr[depth]);
1128 len += strlen(addr[depth]) + 1;
1129 }
1130 }
1131
1132 return (buf);
1133 }
1134
1135 char *
di_devfs_minor_path(di_minor_t minor)1136 di_devfs_minor_path(di_minor_t minor)
1137 {
1138 di_node_t node;
1139 char *full_path, *name, *devfspath;
1140 int full_path_len;
1141
1142 if (minor == DI_MINOR_NIL) {
1143 errno = EINVAL;
1144 return (NULL);
1145 }
1146
1147 name = di_minor_name(minor);
1148 node = di_minor_devinfo(minor);
1149 devfspath = di_devfs_path(node);
1150 if (devfspath == NULL)
1151 return (NULL);
1152
1153 /* make the full path to the device minor node */
1154 full_path_len = strlen(devfspath) + strlen(name) + 2;
1155 full_path = (char *)calloc(1, full_path_len);
1156 if (full_path != NULL)
1157 (void) snprintf(full_path, full_path_len, "%s:%s",
1158 devfspath, name);
1159
1160 di_devfs_path_free(devfspath);
1161 return (full_path);
1162 }
1163
1164 /*
1165 * Produce a string representation of path to di_path_t (pathinfo node). This
1166 * string is identical to di_devfs_path had the device been enumerated under
1167 * the pHCI: it has a base path to pHCI, then uses node_name of client, and
1168 * device unit-address of pathinfo node.
1169 */
1170 char *
di_path_devfs_path(di_path_t path)1171 di_path_devfs_path(di_path_t path)
1172 {
1173 di_node_t phci_node;
1174 char *phci_path, *path_name, *path_addr;
1175 char *full_path;
1176 int full_path_len;
1177
1178 if (path == DI_PATH_NIL) {
1179 errno = EINVAL;
1180 return (NULL);
1181 }
1182
1183 /* get name@addr for path */
1184 path_name = di_path_node_name(path);
1185 path_addr = di_path_bus_addr(path);
1186 if ((path_name == NULL) || (path_addr == NULL))
1187 return (NULL);
1188
1189 /* base path to pHCI devinfo node */
1190 phci_node = di_path_phci_node(path);
1191 if (phci_node == NULL)
1192 return (NULL);
1193 phci_path = di_devfs_path(phci_node);
1194 if (phci_path == NULL)
1195 return (NULL);
1196
1197 /* make the full string representation of path */
1198 full_path_len = strlen(phci_path) + 1 + strlen(path_name) +
1199 1 + strlen(path_addr) + 1;
1200 full_path = (char *)calloc(1, full_path_len);
1201
1202 if (full_path != NULL)
1203 (void) snprintf(full_path, full_path_len, "%s/%s@%s",
1204 phci_path, path_name, path_addr);
1205 di_devfs_path_free(phci_path);
1206 return (full_path);
1207 }
1208
1209 char *
di_path_client_devfs_path(di_path_t path)1210 di_path_client_devfs_path(di_path_t path)
1211 {
1212 return (di_devfs_path(di_path_client_node(path)));
1213 }
1214
1215 void
di_devfs_path_free(char * buf)1216 di_devfs_path_free(char *buf)
1217 {
1218 if (buf == NULL) {
1219 DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n"));
1220 return;
1221 }
1222
1223 free(buf);
1224 }
1225
1226 /*
1227 * Return 1 if name is a IEEE-1275 generic name. If new generic
1228 * names are defined, they should be added to this table
1229 */
1230 static int
is_generic(const char * name,int len)1231 is_generic(const char *name, int len)
1232 {
1233 const char **gp;
1234
1235 /* from IEEE-1275 recommended practices section 3 */
1236 static const char *generic_names[] = {
1237 "atm",
1238 "disk",
1239 "display",
1240 "dma-controller",
1241 "ethernet",
1242 "fcs",
1243 "fdc",
1244 "fddi",
1245 "fibre-channel",
1246 "ide",
1247 "interrupt-controller",
1248 "isa",
1249 "keyboard",
1250 "memory",
1251 "mouse",
1252 "nvram",
1253 "pc-card",
1254 "pci",
1255 "printer",
1256 "rtc",
1257 "sbus",
1258 "scanner",
1259 "scsi",
1260 "serial",
1261 "sound",
1262 "ssa",
1263 "tape",
1264 "timer",
1265 "token-ring",
1266 "vme",
1267 0
1268 };
1269
1270 for (gp = generic_names; *gp; gp++) {
1271 if ((strncmp(*gp, name, len) == 0) &&
1272 (strlen(*gp) == len))
1273 return (1);
1274 }
1275 return (0);
1276 }
1277
1278 /*
1279 * Determine if two paths below /devices refer to the same device, ignoring
1280 * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*".
1281 * Return 1 if the paths match.
1282 */
1283 int
di_devfs_path_match(const char * dp1,const char * dp2)1284 di_devfs_path_match(const char *dp1, const char *dp2)
1285 {
1286 const char *p1, *p2;
1287 const char *ec1, *ec2;
1288 const char *at1, *at2;
1289 char nc;
1290 int g1, g2;
1291
1292 /* progress through both strings */
1293 for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) {
1294 /* require match until the start of a component */
1295 if (*p1 != '/')
1296 continue;
1297
1298 /* advance p1 and p2 to start of 'name' in component */
1299 nc = *(p1 + 1);
1300 if ((nc == '\0') || (nc == '/'))
1301 continue; /* skip trash */
1302 p1++;
1303 p2++;
1304
1305 /*
1306 * Both p1 and p2 point to beginning of 'name' in component.
1307 * Determine where current component ends: next '/' or '\0'.
1308 */
1309 ec1 = strchr(p1, '/');
1310 if (ec1 == NULL)
1311 ec1 = p1 + strlen(p1);
1312 ec2 = strchr(p2, '/');
1313 if (ec2 == NULL)
1314 ec2 = p2 + strlen(p2);
1315
1316 /* Determine where name ends based on whether '@' exists */
1317 at1 = strchr(p1, '@');
1318 at2 = strchr(p2, '@');
1319 if (at1 && (at1 < ec1))
1320 ec1 = at1;
1321 if (at2 && (at2 < ec2))
1322 ec2 = at2;
1323
1324 /*
1325 * At this point p[12] point to beginning of name and
1326 * ec[12] point to character past the end of name. Determine
1327 * if the names are generic.
1328 */
1329 g1 = is_generic(p1, ec1 - p1);
1330 g2 = is_generic(p2, ec2 - p2);
1331
1332 if (g1 != g2) {
1333 /*
1334 * one generic and one non-generic
1335 * skip past the names in the match.
1336 */
1337 p1 = ec1;
1338 p2 = ec2;
1339 } else {
1340 if (*p1 != *p2)
1341 break;
1342 }
1343 }
1344
1345 return ((*p1 == *p2) ? 1 : 0);
1346 }
1347
1348 /* minor data access */
1349 di_minor_t
di_minor_next(di_node_t node,di_minor_t minor)1350 di_minor_next(di_node_t node, di_minor_t minor)
1351 {
1352 caddr_t pa;
1353
1354 /*
1355 * paranoid error checking
1356 */
1357 if (node == DI_NODE_NIL) {
1358 errno = EINVAL;
1359 return (DI_MINOR_NIL);
1360 }
1361
1362 /*
1363 * minor is not NIL
1364 */
1365 if (minor != DI_MINOR_NIL) {
1366 if (DI_MINOR(minor)->next != 0)
1367 return ((di_minor_t)((void *)((caddr_t)minor -
1368 DI_MINOR(minor)->self + DI_MINOR(minor)->next)));
1369 else {
1370 errno = ENXIO;
1371 return (DI_MINOR_NIL);
1372 }
1373 }
1374
1375 /*
1376 * minor is NIL-->caller asks for first minor node
1377 */
1378 if (DI_NODE(node)->minor_data != 0) {
1379 return (DI_MINOR((caddr_t)node - DI_NODE(node)->self +
1380 DI_NODE(node)->minor_data));
1381 }
1382
1383 /*
1384 * no minor data-->check if snapshot includes minor data
1385 * in order to set the correct errno
1386 */
1387 pa = (caddr_t)node - DI_NODE(node)->self;
1388 if (DINFOMINOR & DI_ALL(pa)->command)
1389 errno = ENXIO;
1390 else
1391 errno = ENOTSUP;
1392
1393 return (DI_MINOR_NIL);
1394 }
1395
1396 /* private interface for dealing with alias minor link generation */
1397 di_node_t
di_minor_devinfo(di_minor_t minor)1398 di_minor_devinfo(di_minor_t minor)
1399 {
1400 if (minor == DI_MINOR_NIL) {
1401 errno = EINVAL;
1402 return (DI_NODE_NIL);
1403 }
1404
1405 return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self +
1406 DI_MINOR(minor)->node));
1407 }
1408
1409 ddi_minor_type
di_minor_type(di_minor_t minor)1410 di_minor_type(di_minor_t minor)
1411 {
1412 return (DI_MINOR(minor)->type);
1413 }
1414
1415 char *
di_minor_name(di_minor_t minor)1416 di_minor_name(di_minor_t minor)
1417 {
1418 if (DI_MINOR(minor)->name == 0)
1419 return (NULL);
1420
1421 return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name);
1422 }
1423
1424 dev_t
di_minor_devt(di_minor_t minor)1425 di_minor_devt(di_minor_t minor)
1426 {
1427 return (makedev(DI_MINOR(minor)->dev_major,
1428 DI_MINOR(minor)->dev_minor));
1429 }
1430
1431 int
di_minor_spectype(di_minor_t minor)1432 di_minor_spectype(di_minor_t minor)
1433 {
1434 return (DI_MINOR(minor)->spec_type);
1435 }
1436
1437 char *
di_minor_nodetype(di_minor_t minor)1438 di_minor_nodetype(di_minor_t minor)
1439 {
1440 if (DI_MINOR(minor)->node_type == 0)
1441 return (NULL);
1442
1443 return ((caddr_t)minor -
1444 DI_MINOR(minor)->self + DI_MINOR(minor)->node_type);
1445 }
1446
1447 /*
1448 * Single public interface for accessing software properties
1449 */
1450 di_prop_t
di_prop_next(di_node_t node,di_prop_t prop)1451 di_prop_next(di_node_t node, di_prop_t prop)
1452 {
1453 int list = DI_PROP_DRV_LIST;
1454
1455 /*
1456 * paranoid check
1457 */
1458 if (node == DI_NODE_NIL) {
1459 errno = EINVAL;
1460 return (DI_PROP_NIL);
1461 }
1462
1463 /*
1464 * Find which prop list we are at
1465 */
1466 if (prop != DI_PROP_NIL)
1467 list = DI_PROP(prop)->prop_list;
1468
1469 do {
1470 switch (list++) {
1471 case DI_PROP_DRV_LIST:
1472 prop = di_prop_drv_next(node, prop);
1473 break;
1474 case DI_PROP_SYS_LIST:
1475 prop = di_prop_sys_next(node, prop);
1476 break;
1477 case DI_PROP_GLB_LIST:
1478 prop = di_prop_global_next(node, prop);
1479 break;
1480 case DI_PROP_HW_LIST:
1481 prop = di_prop_hw_next(node, prop);
1482 break;
1483 default: /* shouldn't happen */
1484 errno = EFAULT;
1485 return (DI_PROP_NIL);
1486 }
1487 } while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST));
1488
1489 return (prop);
1490 }
1491
1492 dev_t
di_prop_devt(di_prop_t prop)1493 di_prop_devt(di_prop_t prop)
1494 {
1495 return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor));
1496 }
1497
1498 char *
di_prop_name(di_prop_t prop)1499 di_prop_name(di_prop_t prop)
1500 {
1501 if (DI_PROP(prop)->prop_name == 0)
1502 return (NULL);
1503
1504 return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name);
1505 }
1506
1507 int
di_prop_type(di_prop_t prop)1508 di_prop_type(di_prop_t prop)
1509 {
1510 uint_t flags = DI_PROP(prop)->prop_flags;
1511
1512 if (flags & DDI_PROP_UNDEF_IT)
1513 return (DI_PROP_TYPE_UNDEF_IT);
1514
1515 if (DI_PROP(prop)->prop_len == 0)
1516 return (DI_PROP_TYPE_BOOLEAN);
1517
1518 if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY)
1519 return (DI_PROP_TYPE_UNKNOWN);
1520
1521 if (flags & DDI_PROP_TYPE_INT)
1522 return (DI_PROP_TYPE_INT);
1523
1524 if (flags & DDI_PROP_TYPE_INT64)
1525 return (DI_PROP_TYPE_INT64);
1526
1527 if (flags & DDI_PROP_TYPE_STRING)
1528 return (DI_PROP_TYPE_STRING);
1529
1530 if (flags & DDI_PROP_TYPE_BYTE)
1531 return (DI_PROP_TYPE_BYTE);
1532
1533 /*
1534 * Shouldn't get here. In case we do, return unknown type.
1535 *
1536 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need
1537 * to add DI_PROP_TYPE_COMPOSITE.
1538 */
1539 DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags));
1540
1541 return (DI_PROP_TYPE_UNKNOWN);
1542 }
1543
1544 /*
1545 * Extract type-specific values of an property
1546 */
1547 extern int di_prop_decode_common(void *prop_data, int len,
1548 int ddi_type, int prom);
1549
1550 int
di_prop_ints(di_prop_t prop,int ** prop_data)1551 di_prop_ints(di_prop_t prop, int **prop_data)
1552 {
1553 if (DI_PROP(prop)->prop_len == 0)
1554 return (0); /* boolean property */
1555
1556 if ((DI_PROP(prop)->prop_data == 0) ||
1557 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1558 errno = EFAULT;
1559 *prop_data = NULL;
1560 return (-1);
1561 }
1562
1563 *prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1564 + DI_PROP(prop)->prop_data));
1565
1566 return (di_prop_decode_common((void *)prop_data,
1567 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
1568 }
1569
1570 int
di_prop_int64(di_prop_t prop,int64_t ** prop_data)1571 di_prop_int64(di_prop_t prop, int64_t **prop_data)
1572 {
1573 if (DI_PROP(prop)->prop_len == 0)
1574 return (0); /* boolean property */
1575
1576 if ((DI_PROP(prop)->prop_data == 0) ||
1577 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1578 errno = EFAULT;
1579 *prop_data = NULL;
1580 return (-1);
1581 }
1582
1583 *prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self
1584 + DI_PROP(prop)->prop_data));
1585
1586 return (di_prop_decode_common((void *)prop_data,
1587 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
1588 }
1589
1590 int
di_prop_strings(di_prop_t prop,char ** prop_data)1591 di_prop_strings(di_prop_t prop, char **prop_data)
1592 {
1593 if (DI_PROP(prop)->prop_len == 0)
1594 return (0); /* boolean property */
1595
1596 if ((DI_PROP(prop)->prop_data == 0) ||
1597 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1598 errno = EFAULT;
1599 *prop_data = NULL;
1600 return (-1);
1601 }
1602
1603 *prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self
1604 + DI_PROP(prop)->prop_data);
1605
1606 return (di_prop_decode_common((void *)prop_data,
1607 DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
1608 }
1609
1610 int
di_prop_bytes(di_prop_t prop,uchar_t ** prop_data)1611 di_prop_bytes(di_prop_t prop, uchar_t **prop_data)
1612 {
1613 if (DI_PROP(prop)->prop_len == 0)
1614 return (0); /* boolean property */
1615
1616 if ((DI_PROP(prop)->prop_data == 0) ||
1617 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1618 errno = EFAULT;
1619 *prop_data = NULL;
1620 return (-1);
1621 }
1622
1623 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self
1624 + DI_PROP(prop)->prop_data);
1625
1626 return (di_prop_decode_common((void *)prop_data,
1627 DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
1628 }
1629
1630 /*
1631 * returns 1 for match, 0 for no match
1632 */
1633 static int
match_prop(di_prop_t prop,dev_t match_dev,const char * name,int type)1634 match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type)
1635 {
1636 int prop_type;
1637
1638 #ifdef DEBUG
1639 if (di_prop_name(prop) == NULL) {
1640 DPRINTF((DI_ERR, "libdevinfo: property has no name!\n"));
1641 return (0);
1642 }
1643 #endif /* DEBUG */
1644
1645 if (strcmp(name, di_prop_name(prop)) != 0)
1646 return (0);
1647
1648 if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev))
1649 return (0);
1650
1651 /*
1652 * XXX prop_type is different from DDI_*. See PSARC 1997/127.
1653 */
1654 prop_type = di_prop_type(prop);
1655 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) &&
1656 (prop_type != DI_PROP_TYPE_BOOLEAN))
1657 return (0);
1658
1659 return (1);
1660 }
1661
1662 static di_prop_t
di_prop_search(dev_t match_dev,di_node_t node,const char * name,int type)1663 di_prop_search(dev_t match_dev, di_node_t node, const char *name,
1664 int type)
1665 {
1666 di_prop_t prop = DI_PROP_NIL;
1667
1668 /*
1669 * The check on match_dev follows ddi_prop_lookup_common().
1670 * Other checks are libdevinfo specific implementation.
1671 */
1672 if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
1673 (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) {
1674 errno = EINVAL;
1675 return (DI_PROP_NIL);
1676 }
1677
1678 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
1679 DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n",
1680 di_prop_name(prop), di_prop_devt(prop),
1681 di_prop_type(prop)));
1682 if (match_prop(prop, match_dev, name, type))
1683 return (prop);
1684 }
1685
1686 return (DI_PROP_NIL);
1687 }
1688
1689 di_prop_t
di_prop_find(dev_t match_dev,di_node_t node,const char * name)1690 di_prop_find(dev_t match_dev, di_node_t node, const char *name)
1691 {
1692 di_prop_t prop = DI_PROP_NIL;
1693
1694 if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) ||
1695 (match_dev == DDI_DEV_T_NONE)) {
1696 errno = EINVAL;
1697 return (DI_PROP_NIL);
1698 }
1699
1700 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
1701 DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n",
1702 di_prop_name(prop), di_prop_devt(prop),
1703 di_prop_type(prop)));
1704
1705 if (strcmp(name, di_prop_name(prop)) == 0 &&
1706 (match_dev == DDI_DEV_T_ANY ||
1707 di_prop_devt(prop) == match_dev))
1708 return (prop);
1709 }
1710
1711 return (DI_PROP_NIL);
1712 }
1713
1714 int
di_prop_lookup_ints(dev_t dev,di_node_t node,const char * prop_name,int ** prop_data)1715 di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name,
1716 int **prop_data)
1717 {
1718 di_prop_t prop;
1719
1720 if ((prop = di_prop_search(dev, node, prop_name,
1721 DI_PROP_TYPE_INT)) == DI_PROP_NIL)
1722 return (-1);
1723
1724 return (di_prop_ints(prop, (void *)prop_data));
1725 }
1726
1727 int
di_prop_lookup_int64(dev_t dev,di_node_t node,const char * prop_name,int64_t ** prop_data)1728 di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name,
1729 int64_t **prop_data)
1730 {
1731 di_prop_t prop;
1732
1733 if ((prop = di_prop_search(dev, node, prop_name,
1734 DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
1735 return (-1);
1736
1737 return (di_prop_int64(prop, (void *)prop_data));
1738 }
1739
1740 int
di_prop_lookup_strings(dev_t dev,di_node_t node,const char * prop_name,char ** prop_data)1741 di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name,
1742 char **prop_data)
1743 {
1744 di_prop_t prop;
1745
1746 if ((prop = di_prop_search(dev, node, prop_name,
1747 DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
1748 return (-1);
1749
1750 return (di_prop_strings(prop, (void *)prop_data));
1751 }
1752
1753 int
di_prop_lookup_bytes(dev_t dev,di_node_t node,const char * prop_name,uchar_t ** prop_data)1754 di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name,
1755 uchar_t **prop_data)
1756 {
1757 di_prop_t prop;
1758
1759 if ((prop = di_prop_search(dev, node, prop_name,
1760 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
1761 return (-1);
1762
1763 return (di_prop_bytes(prop, (void *)prop_data));
1764 }
1765
1766 /*
1767 * Consolidation private property access functions
1768 */
1769 enum prop_type {
1770 PROP_TYPE_DRV,
1771 PROP_TYPE_SYS,
1772 PROP_TYPE_GLOB,
1773 PROP_TYPE_HW
1774 };
1775
1776 static di_prop_t
di_prop_next_common(di_node_t node,di_prop_t prop,int prop_type)1777 di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type)
1778 {
1779 caddr_t pa;
1780 di_off_t prop_off = 0;
1781
1782 if (prop != DI_PROP_NIL) {
1783 if (DI_PROP(prop)->next) {
1784 return (DI_PROP((caddr_t)prop -
1785 DI_PROP(prop)->self + DI_PROP(prop)->next));
1786 } else {
1787 return (DI_PROP_NIL);
1788 }
1789 }
1790
1791
1792 /*
1793 * prop is NIL, caller asks for first property
1794 */
1795 pa = (caddr_t)node - DI_NODE(node)->self;
1796 switch (prop_type) {
1797 case PROP_TYPE_DRV:
1798 prop_off = DI_NODE(node)->drv_prop;
1799 break;
1800 case PROP_TYPE_SYS:
1801 prop_off = DI_NODE(node)->sys_prop;
1802 break;
1803 case PROP_TYPE_HW:
1804 prop_off = DI_NODE(node)->hw_prop;
1805 break;
1806 case PROP_TYPE_GLOB:
1807 prop_off = DI_NODE(node)->glob_prop;
1808 if (prop_off == -1) {
1809 /* no global property */
1810 prop_off = 0;
1811 } else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) {
1812 /* refer to devnames array */
1813 struct di_devnm *devnm = DI_DEVNM(pa +
1814 DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major *
1815 sizeof (struct di_devnm)));
1816 prop_off = devnm->global_prop;
1817 }
1818 break;
1819 }
1820
1821 if (prop_off) {
1822 return (DI_PROP(pa + prop_off));
1823 }
1824
1825 /*
1826 * no prop found. Check the reason for not found
1827 */
1828 if (DINFOPROP & DI_ALL(pa)->command)
1829 errno = ENXIO;
1830 else
1831 errno = ENOTSUP;
1832
1833 return (DI_PROP_NIL);
1834 }
1835
1836 di_prop_t
di_prop_drv_next(di_node_t node,di_prop_t prop)1837 di_prop_drv_next(di_node_t node, di_prop_t prop)
1838 {
1839 return (di_prop_next_common(node, prop, PROP_TYPE_DRV));
1840 }
1841
1842 di_prop_t
di_prop_sys_next(di_node_t node,di_prop_t prop)1843 di_prop_sys_next(di_node_t node, di_prop_t prop)
1844 {
1845 return (di_prop_next_common(node, prop, PROP_TYPE_SYS));
1846 }
1847
1848 di_prop_t
di_prop_global_next(di_node_t node,di_prop_t prop)1849 di_prop_global_next(di_node_t node, di_prop_t prop)
1850 {
1851 return (di_prop_next_common(node, prop, PROP_TYPE_GLOB));
1852 }
1853
1854 di_prop_t
di_prop_hw_next(di_node_t node,di_prop_t prop)1855 di_prop_hw_next(di_node_t node, di_prop_t prop)
1856 {
1857 return (di_prop_next_common(node, prop, PROP_TYPE_HW));
1858 }
1859
1860 int
di_prop_rawdata(di_prop_t prop,uchar_t ** prop_data)1861 di_prop_rawdata(di_prop_t prop, uchar_t **prop_data)
1862 {
1863 #ifdef DEBUG
1864 if (prop == DI_PROP_NIL) {
1865 errno = EINVAL;
1866 return (-1);
1867 }
1868 #endif /* DEBUG */
1869
1870 if (DI_PROP(prop)->prop_len == 0) {
1871 *prop_data = NULL;
1872 return (0);
1873 }
1874
1875 if ((DI_PROP(prop)->prop_data == 0) ||
1876 (DI_PROP(prop)->prop_data == (di_off_t)-1)) {
1877 errno = EFAULT;
1878 *prop_data = NULL;
1879 return (-1);
1880 }
1881
1882 /*
1883 * No memory allocation.
1884 */
1885 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self +
1886 DI_PROP(prop)->prop_data);
1887
1888 return (DI_PROP(prop)->prop_len);
1889 }
1890
1891 /*
1892 * Consolidation private interfaces for accessing I/O multipathing data
1893 */
1894 di_path_t
di_path_phci_next_path(di_node_t node,di_path_t path)1895 di_path_phci_next_path(di_node_t node, di_path_t path)
1896 {
1897 caddr_t pa;
1898
1899 /*
1900 * path is not NIL
1901 */
1902 if (path != DI_PATH_NIL) {
1903 if (DI_PATH(path)->path_p_link != 0)
1904 return (DI_PATH((void *)((caddr_t)path -
1905 DI_PATH(path)->self + DI_PATH(path)->path_p_link)));
1906 else {
1907 errno = ENXIO;
1908 return (DI_PATH_NIL);
1909 }
1910 }
1911
1912 /*
1913 * Path is NIL; the caller is asking for the first path info node
1914 */
1915 if (DI_NODE(node)->multipath_phci != 0) {
1916 DPRINTF((DI_INFO, "phci_next_path: returning %p\n",
1917 ((caddr_t)node -
1918 DI_NODE(node)->self + DI_NODE(node)->multipath_phci)));
1919 return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
1920 DI_NODE(node)->multipath_phci));
1921 }
1922
1923 /*
1924 * No pathing data; check if the snapshot includes path data in order
1925 * to set errno properly.
1926 */
1927 pa = (caddr_t)node - DI_NODE(node)->self;
1928 if (DINFOPATH & (DI_ALL(pa)->command))
1929 errno = ENXIO;
1930 else
1931 errno = ENOTSUP;
1932
1933 return (DI_PATH_NIL);
1934 }
1935
1936 di_path_t
di_path_client_next_path(di_node_t node,di_path_t path)1937 di_path_client_next_path(di_node_t node, di_path_t path)
1938 {
1939 caddr_t pa;
1940
1941 /*
1942 * path is not NIL
1943 */
1944 if (path != DI_PATH_NIL) {
1945 if (DI_PATH(path)->path_c_link != 0)
1946 return (DI_PATH((caddr_t)path - DI_PATH(path)->self
1947 + DI_PATH(path)->path_c_link));
1948 else {
1949 errno = ENXIO;
1950 return (DI_PATH_NIL);
1951 }
1952 }
1953
1954 /*
1955 * Path is NIL; the caller is asking for the first path info node
1956 */
1957 if (DI_NODE(node)->multipath_client != 0) {
1958 DPRINTF((DI_INFO, "client_next_path: returning %p\n",
1959 ((caddr_t)node -
1960 DI_NODE(node)->self + DI_NODE(node)->multipath_client)));
1961 return (DI_PATH((caddr_t)node - DI_NODE(node)->self +
1962 DI_NODE(node)->multipath_client));
1963 }
1964
1965 /*
1966 * No pathing data; check if the snapshot includes path data in order
1967 * to set errno properly.
1968 */
1969 pa = (caddr_t)node - DI_NODE(node)->self;
1970 if (DINFOPATH & (DI_ALL(pa)->command))
1971 errno = ENXIO;
1972 else
1973 errno = ENOTSUP;
1974
1975 return (DI_PATH_NIL);
1976 }
1977
1978 /*
1979 * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces
1980 * below after NWS consolidation switches to using di_path_bus_addr,
1981 * di_path_phci_next_path, and di_path_client_next_path per CR6638521.
1982 */
1983 char *
di_path_addr(di_path_t path,char * buf)1984 di_path_addr(di_path_t path, char *buf)
1985 {
1986 caddr_t pa; /* starting address of map */
1987
1988 pa = (caddr_t)path - DI_PATH(path)->self;
1989
1990 (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr),
1991 MAXPATHLEN);
1992 return (buf);
1993 }
1994 di_path_t
di_path_next(di_node_t node,di_path_t path)1995 di_path_next(di_node_t node, di_path_t path)
1996 {
1997 if (node == DI_NODE_NIL) {
1998 errno = EINVAL;
1999 return (DI_PATH_NIL);
2000 }
2001
2002 if (DI_NODE(node)->multipath_client) {
2003 return (di_path_client_next_path(node, path));
2004 } else if (DI_NODE(node)->multipath_phci) {
2005 return (di_path_phci_next_path(node, path));
2006 } else {
2007 /*
2008 * The node had multipathing data but didn't appear to be a
2009 * phci *or* a client; probably a programmer error.
2010 */
2011 errno = EINVAL;
2012 return (DI_PATH_NIL);
2013 }
2014 }
2015 di_path_t
di_path_next_phci(di_node_t node,di_path_t path)2016 di_path_next_phci(di_node_t node, di_path_t path)
2017 {
2018 return (di_path_client_next_path(node, path));
2019 }
2020 di_path_t
di_path_next_client(di_node_t node,di_path_t path)2021 di_path_next_client(di_node_t node, di_path_t path)
2022 {
2023 return (di_path_phci_next_path(node, path));
2024 }
2025
2026
2027
2028
2029 di_path_state_t
di_path_state(di_path_t path)2030 di_path_state(di_path_t path)
2031 {
2032 return ((di_path_state_t)DI_PATH(path)->path_state);
2033 }
2034
2035 uint_t
di_path_flags(di_path_t path)2036 di_path_flags(di_path_t path)
2037 {
2038 return (DI_PATH(path)->path_flags);
2039 }
2040
2041 char *
di_path_node_name(di_path_t path)2042 di_path_node_name(di_path_t path)
2043 {
2044 di_node_t client_node;
2045
2046 /* pathinfo gets node_name from client */
2047 if ((client_node = di_path_client_node(path)) == NULL)
2048 return (NULL);
2049 return (di_node_name(client_node));
2050 }
2051
2052 char *
di_path_bus_addr(di_path_t path)2053 di_path_bus_addr(di_path_t path)
2054 {
2055 caddr_t pa = (caddr_t)path - DI_PATH(path)->self;
2056
2057 if (DI_PATH(path)->path_addr == 0)
2058 return (NULL);
2059
2060 return ((char *)(pa + DI_PATH(path)->path_addr));
2061 }
2062
2063 int
di_path_instance(di_path_t path)2064 di_path_instance(di_path_t path)
2065 {
2066 return (DI_PATH(path)->path_instance);
2067 }
2068
2069 di_node_t
di_path_client_node(di_path_t path)2070 di_path_client_node(di_path_t path)
2071 {
2072 caddr_t pa; /* starting address of map */
2073
2074 if (path == DI_PATH_NIL) {
2075 errno = EINVAL;
2076 return (DI_PATH_NIL);
2077 }
2078
2079 DPRINTF((DI_TRACE, "Get client node for path %p\n", path));
2080
2081 pa = (caddr_t)path - DI_PATH(path)->self;
2082
2083 if (DI_PATH(path)->path_client) {
2084 return (DI_NODE(pa + DI_PATH(path)->path_client));
2085 }
2086
2087 /*
2088 * Deal with error condition:
2089 * If parent doesn't exist and node is not the root,
2090 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2091 */
2092 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0)
2093 errno = ENOTSUP;
2094 else
2095 errno = ENXIO;
2096
2097 return (DI_NODE_NIL);
2098 }
2099
2100 di_node_t
di_path_phci_node(di_path_t path)2101 di_path_phci_node(di_path_t path)
2102 {
2103 caddr_t pa; /* starting address of map */
2104
2105 if (path == DI_PATH_NIL) {
2106 errno = EINVAL;
2107 return (DI_PATH_NIL);
2108 }
2109
2110 DPRINTF((DI_TRACE, "Get phci node for path %p\n", path));
2111
2112 pa = (caddr_t)path - DI_PATH(path)->self;
2113
2114 if (DI_PATH(path)->path_phci) {
2115 return (DI_NODE(pa + DI_PATH(path)->path_phci));
2116 }
2117
2118 /*
2119 * Deal with error condition:
2120 * If parent doesn't exist and node is not the root,
2121 * set errno to ENOTSUP. Otherwise, set errno to ENXIO.
2122 */
2123 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0)
2124 errno = ENOTSUP;
2125 else
2126 errno = ENXIO;
2127
2128 return (DI_NODE_NIL);
2129 }
2130
2131 di_path_prop_t
di_path_prop_next(di_path_t path,di_path_prop_t prop)2132 di_path_prop_next(di_path_t path, di_path_prop_t prop)
2133 {
2134 caddr_t pa;
2135
2136 if (path == DI_PATH_NIL) {
2137 errno = EINVAL;
2138 return (DI_PROP_NIL);
2139 }
2140
2141 /*
2142 * prop is not NIL
2143 */
2144 if (prop != DI_PROP_NIL) {
2145 if (DI_PROP(prop)->next != 0)
2146 return (DI_PATHPROP((caddr_t)prop -
2147 DI_PROP(prop)->self + DI_PROP(prop)->next));
2148 else {
2149 errno = ENXIO;
2150 return (DI_PROP_NIL);
2151 }
2152 }
2153
2154 /*
2155 * prop is NIL-->caller asks for first property
2156 */
2157 pa = (caddr_t)path - DI_PATH(path)->self;
2158 if (DI_PATH(path)->path_prop != 0) {
2159 return (DI_PATHPROP(pa + DI_PATH(path)->path_prop));
2160 }
2161
2162 /*
2163 * no property data-->check if snapshot includes props
2164 * in order to set the correct errno
2165 */
2166 if (DINFOPROP & (DI_ALL(pa)->command))
2167 errno = ENXIO;
2168 else
2169 errno = ENOTSUP;
2170
2171 return (DI_PROP_NIL);
2172 }
2173
2174 char *
di_path_prop_name(di_path_prop_t prop)2175 di_path_prop_name(di_path_prop_t prop)
2176 {
2177 caddr_t pa; /* starting address of map */
2178 pa = (caddr_t)prop - DI_PATHPROP(prop)->self;
2179 return ((char *)(pa + DI_PATHPROP(prop)->prop_name));
2180 }
2181
2182 int
di_path_prop_len(di_path_prop_t prop)2183 di_path_prop_len(di_path_prop_t prop)
2184 {
2185 return (DI_PATHPROP(prop)->prop_len);
2186 }
2187
2188 int
di_path_prop_type(di_path_prop_t prop)2189 di_path_prop_type(di_path_prop_t prop)
2190 {
2191 switch (DI_PATHPROP(prop)->prop_type) {
2192 case DDI_PROP_TYPE_INT:
2193 return (DI_PROP_TYPE_INT);
2194 case DDI_PROP_TYPE_INT64:
2195 return (DI_PROP_TYPE_INT64);
2196 case DDI_PROP_TYPE_BYTE:
2197 return (DI_PROP_TYPE_BYTE);
2198 case DDI_PROP_TYPE_STRING:
2199 return (DI_PROP_TYPE_STRING);
2200 }
2201 return (DI_PROP_TYPE_UNKNOWN);
2202 }
2203
2204 int
di_path_prop_bytes(di_path_prop_t prop,uchar_t ** prop_data)2205 di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data)
2206 {
2207 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2208 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2209 errno = EFAULT;
2210 *prop_data = NULL;
2211 return (-1);
2212 }
2213
2214 *prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self
2215 + DI_PATHPROP(prop)->prop_data);
2216
2217 return (di_prop_decode_common((void *)prop_data,
2218 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0));
2219 }
2220
2221 int
di_path_prop_ints(di_path_prop_t prop,int ** prop_data)2222 di_path_prop_ints(di_path_prop_t prop, int **prop_data)
2223 {
2224 if (DI_PATHPROP(prop)->prop_len == 0)
2225 return (0);
2226
2227 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2228 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2229 errno = EFAULT;
2230 *prop_data = NULL;
2231 return (-1);
2232 }
2233
2234 *prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self
2235 + DI_PATHPROP(prop)->prop_data));
2236
2237 return (di_prop_decode_common((void *)prop_data,
2238 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0));
2239 }
2240
2241 int
di_path_prop_int64s(di_path_prop_t prop,int64_t ** prop_data)2242 di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data)
2243 {
2244 if (DI_PATHPROP(prop)->prop_len == 0)
2245 return (0);
2246
2247 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2248 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2249 errno = EFAULT;
2250 *prop_data = NULL;
2251 return (-1);
2252 }
2253
2254 *prop_data = (int64_t *)((void *)((caddr_t)prop -
2255 DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data));
2256
2257 return (di_prop_decode_common((void *)prop_data,
2258 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0));
2259 }
2260
2261 int
di_path_prop_strings(di_path_prop_t prop,char ** prop_data)2262 di_path_prop_strings(di_path_prop_t prop, char **prop_data)
2263 {
2264 if (DI_PATHPROP(prop)->prop_len == 0)
2265 return (0);
2266
2267 if ((DI_PATHPROP(prop)->prop_data == 0) ||
2268 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) {
2269 errno = EFAULT;
2270 *prop_data = NULL;
2271 return (-1);
2272 }
2273
2274 *prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self
2275 + DI_PATHPROP(prop)->prop_data);
2276
2277 return (di_prop_decode_common((void *)prop_data,
2278 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0));
2279 }
2280
2281 static di_path_prop_t
di_path_prop_search(di_path_t path,const char * name,int type)2282 di_path_prop_search(di_path_t path, const char *name, int type)
2283 {
2284 di_path_prop_t prop = DI_PROP_NIL;
2285
2286 /*
2287 * Sanity check arguments
2288 */
2289 if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) ||
2290 !DI_PROP_TYPE_VALID(type)) {
2291 errno = EINVAL;
2292 return (DI_PROP_NIL);
2293 }
2294
2295 while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) {
2296 int prop_type = di_path_prop_type(prop);
2297
2298 DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n",
2299 di_path_prop_name(prop), prop_type));
2300
2301 if (strcmp(name, di_path_prop_name(prop)) != 0)
2302 continue;
2303
2304 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type))
2305 continue;
2306
2307 return (prop);
2308 }
2309
2310 return (DI_PROP_NIL);
2311 }
2312
2313 int
di_path_prop_lookup_bytes(di_path_t path,const char * prop_name,uchar_t ** prop_data)2314 di_path_prop_lookup_bytes(di_path_t path, const char *prop_name,
2315 uchar_t **prop_data)
2316 {
2317 di_path_prop_t prop;
2318
2319 if ((prop = di_path_prop_search(path, prop_name,
2320 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL)
2321 return (-1);
2322
2323 return (di_path_prop_bytes(prop, prop_data));
2324 }
2325
2326 int
di_path_prop_lookup_ints(di_path_t path,const char * prop_name,int ** prop_data)2327 di_path_prop_lookup_ints(di_path_t path, const char *prop_name,
2328 int **prop_data)
2329 {
2330 di_path_prop_t prop;
2331
2332 if ((prop = di_path_prop_search(path, prop_name,
2333 DI_PROP_TYPE_INT)) == DI_PROP_NIL)
2334 return (-1);
2335
2336 return (di_path_prop_ints(prop, prop_data));
2337 }
2338
2339 int
di_path_prop_lookup_int64s(di_path_t path,const char * prop_name,int64_t ** prop_data)2340 di_path_prop_lookup_int64s(di_path_t path, const char *prop_name,
2341 int64_t **prop_data)
2342 {
2343 di_path_prop_t prop;
2344
2345 if ((prop = di_path_prop_search(path, prop_name,
2346 DI_PROP_TYPE_INT64)) == DI_PROP_NIL)
2347 return (-1);
2348
2349 return (di_path_prop_int64s(prop, prop_data));
2350 }
2351
di_path_prop_lookup_strings(di_path_t path,const char * prop_name,char ** prop_data)2352 int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
2353 char **prop_data)
2354 {
2355 di_path_prop_t prop;
2356
2357 if ((prop = di_path_prop_search(path, prop_name,
2358 DI_PROP_TYPE_STRING)) == DI_PROP_NIL)
2359 return (-1);
2360
2361 return (di_path_prop_strings(prop, prop_data));
2362 }
2363
2364 /*
2365 * Consolidation private interfaces for traversing vhci nodes.
2366 */
2367 di_node_t
di_vhci_first_node(di_node_t root)2368 di_vhci_first_node(di_node_t root)
2369 {
2370 struct di_all *dap;
2371 caddr_t pa; /* starting address of map */
2372
2373 DPRINTF((DI_INFO, "Get first vhci node\n"));
2374
2375 if (root == DI_NODE_NIL) {
2376 errno = EINVAL;
2377 return (DI_NODE_NIL);
2378 }
2379
2380 pa = (caddr_t)root - DI_NODE(root)->self;
2381 dap = DI_ALL(pa);
2382
2383 if (dap->top_vhci_devinfo == 0) {
2384 errno = ENXIO;
2385 return (DI_NODE_NIL);
2386 }
2387
2388 return (DI_NODE(pa + dap->top_vhci_devinfo));
2389 }
2390
2391 di_node_t
di_vhci_next_node(di_node_t node)2392 di_vhci_next_node(di_node_t node)
2393 {
2394 caddr_t pa; /* starting address of map */
2395
2396 if (node == DI_NODE_NIL) {
2397 errno = EINVAL;
2398 return (DI_NODE_NIL);
2399 }
2400
2401 DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
2402 " current=%s\n", di_node_name(node)));
2403
2404 if (DI_NODE(node)->next_vhci == 0) {
2405 errno = ENXIO;
2406 return (DI_NODE_NIL);
2407 }
2408
2409 pa = (caddr_t)node - DI_NODE(node)->self;
2410
2411 return (DI_NODE(pa + DI_NODE(node)->next_vhci));
2412 }
2413
2414 /*
2415 * Consolidation private interfaces for traversing phci nodes.
2416 */
2417 di_node_t
di_phci_first_node(di_node_t vhci_node)2418 di_phci_first_node(di_node_t vhci_node)
2419 {
2420 caddr_t pa; /* starting address of map */
2421
2422 DPRINTF((DI_INFO, "Get first phci node:\n"
2423 " current=%s", di_node_name(vhci_node)));
2424
2425 if (vhci_node == DI_NODE_NIL) {
2426 errno = EINVAL;
2427 return (DI_NODE_NIL);
2428 }
2429
2430 pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
2431
2432 if (DI_NODE(vhci_node)->top_phci == 0) {
2433 errno = ENXIO;
2434 return (DI_NODE_NIL);
2435 }
2436
2437 return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
2438 }
2439
2440 di_node_t
di_phci_next_node(di_node_t node)2441 di_phci_next_node(di_node_t node)
2442 {
2443 caddr_t pa; /* starting address of map */
2444
2445 if (node == DI_NODE_NIL) {
2446 errno = EINVAL;
2447 return (DI_NODE_NIL);
2448 }
2449
2450 DPRINTF((DI_TRACE, "next phci node on the snap shot:"
2451 " current=%s\n", di_node_name(node)));
2452
2453 if (DI_NODE(node)->next_phci == 0) {
2454 errno = ENXIO;
2455 return (DI_NODE_NIL);
2456 }
2457
2458 pa = (caddr_t)node - DI_NODE(node)->self;
2459
2460 return (DI_NODE(pa + DI_NODE(node)->next_phci));
2461 }
2462
2463 /*
2464 * Consolidation private interfaces for private data
2465 */
2466 void *
di_parent_private_data(di_node_t node)2467 di_parent_private_data(di_node_t node)
2468 {
2469 caddr_t pa;
2470
2471 if (DI_NODE(node)->parent_data == 0) {
2472 errno = ENXIO;
2473 return (NULL);
2474 }
2475
2476 if (DI_NODE(node)->parent_data == (di_off_t)-1) {
2477 /*
2478 * Private data requested, but not obtained due to a memory
2479 * error (e.g. wrong format specified)
2480 */
2481 errno = EFAULT;
2482 return (NULL);
2483 }
2484
2485 pa = (caddr_t)node - DI_NODE(node)->self;
2486 if (DI_NODE(node)->parent_data)
2487 return (pa + DI_NODE(node)->parent_data);
2488
2489 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2490 errno = ENXIO;
2491 else
2492 errno = ENOTSUP;
2493
2494 return (NULL);
2495 }
2496
2497 void *
di_driver_private_data(di_node_t node)2498 di_driver_private_data(di_node_t node)
2499 {
2500 caddr_t pa;
2501
2502 if (DI_NODE(node)->driver_data == 0) {
2503 errno = ENXIO;
2504 return (NULL);
2505 }
2506
2507 if (DI_NODE(node)->driver_data == (di_off_t)-1) {
2508 /*
2509 * Private data requested, but not obtained due to a memory
2510 * error (e.g. wrong format specified)
2511 */
2512 errno = EFAULT;
2513 return (NULL);
2514 }
2515
2516 pa = (caddr_t)node - DI_NODE(node)->self;
2517 if (DI_NODE(node)->driver_data)
2518 return (pa + DI_NODE(node)->driver_data);
2519
2520 if (DI_ALL(pa)->command & DINFOPRIVDATA)
2521 errno = ENXIO;
2522 else
2523 errno = ENOTSUP;
2524
2525 return (NULL);
2526 }
2527
2528 /*
2529 * Hotplug information access
2530 */
2531
2532 typedef struct {
2533 void *arg;
2534 const char *type;
2535 uint_t flag;
2536 int (*hp_callback)(di_node_t, di_hp_t, void *);
2537 } di_walk_hp_arg_t;
2538
2539 static int
di_walk_hp_callback(di_node_t node,void * argp)2540 di_walk_hp_callback(di_node_t node, void *argp)
2541 {
2542 di_walk_hp_arg_t *arg = (di_walk_hp_arg_t *)argp;
2543 di_hp_t hp;
2544 char *type_str;
2545
2546 for (hp = DI_HP_NIL; (hp = di_hp_next(node, hp)) != DI_HP_NIL; ) {
2547
2548 /* Exclude non-matching types if a type filter is specified */
2549 if (arg->type != NULL) {
2550 type_str = di_hp_description(hp);
2551 if (type_str && (strcmp(arg->type, type_str) != 0))
2552 continue;
2553 }
2554
2555 /* Exclude ports if DI_HP_PORT flag not specified */
2556 if (!(arg->flag & DI_HP_PORT) &&
2557 (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2558 continue;
2559
2560 /* Exclude connectors if DI_HP_CONNECTOR flag not specified */
2561 if (!(arg->flag & DI_HP_CONNECTOR) &&
2562 !(di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT))
2563 continue;
2564
2565 /* Perform callback */
2566 if (arg->hp_callback(node, hp, arg->arg) != DI_WALK_CONTINUE)
2567 return (DI_WALK_TERMINATE);
2568 }
2569
2570 return (DI_WALK_CONTINUE);
2571 }
2572
2573 int
di_walk_hp(di_node_t node,const char * type,uint_t flag,void * arg,int (* hp_callback)(di_node_t node,di_hp_t hp,void * arg))2574 di_walk_hp(di_node_t node, const char *type, uint_t flag, void *arg,
2575 int (*hp_callback)(di_node_t node, di_hp_t hp, void *arg))
2576 {
2577 di_walk_hp_arg_t walk_arg;
2578 caddr_t pa;
2579
2580 #ifdef DEBUG
2581 char *devfspath = di_devfs_path(node);
2582 DPRINTF((DI_INFO, "walking hotplug nodes under %s\n", devfspath));
2583 di_devfs_path_free(devfspath);
2584 #endif
2585 /*
2586 * paranoid error checking
2587 */
2588 if ((node == DI_NODE_NIL) || (hp_callback == NULL)) {
2589 errno = EINVAL;
2590 return (-1);
2591 }
2592
2593 /* check if hotplug data is included in snapshot */
2594 pa = (caddr_t)node - DI_NODE(node)->self;
2595 if (!(DI_ALL(pa)->command & DINFOHP)) {
2596 errno = ENOTSUP;
2597 return (-1);
2598 }
2599
2600 walk_arg.arg = arg;
2601 walk_arg.type = type;
2602 walk_arg.flag = flag;
2603 walk_arg.hp_callback = hp_callback;
2604 return (di_walk_node(node, DI_WALK_CLDFIRST, &walk_arg,
2605 di_walk_hp_callback));
2606 }
2607
2608 di_hp_t
di_hp_next(di_node_t node,di_hp_t hp)2609 di_hp_next(di_node_t node, di_hp_t hp)
2610 {
2611 caddr_t pa;
2612
2613 /*
2614 * paranoid error checking
2615 */
2616 if (node == DI_NODE_NIL) {
2617 errno = EINVAL;
2618 return (DI_HP_NIL);
2619 }
2620
2621 /*
2622 * hotplug node is not NIL
2623 */
2624 if (hp != DI_HP_NIL) {
2625 if (DI_HP(hp)->next != 0)
2626 return (DI_HP((caddr_t)hp - hp->self + hp->next));
2627 else {
2628 errno = ENXIO;
2629 return (DI_HP_NIL);
2630 }
2631 }
2632
2633 /*
2634 * hotplug node is NIL-->caller asks for first hotplug node
2635 */
2636 if (DI_NODE(node)->hp_data != 0) {
2637 return (DI_HP((caddr_t)node - DI_NODE(node)->self +
2638 DI_NODE(node)->hp_data));
2639 }
2640
2641 /*
2642 * no hotplug data-->check if snapshot includes hotplug data
2643 * in order to set the correct errno
2644 */
2645 pa = (caddr_t)node - DI_NODE(node)->self;
2646 if (DINFOHP & DI_ALL(pa)->command)
2647 errno = ENXIO;
2648 else
2649 errno = ENOTSUP;
2650
2651 return (DI_HP_NIL);
2652 }
2653
2654 char *
di_hp_name(di_hp_t hp)2655 di_hp_name(di_hp_t hp)
2656 {
2657 caddr_t pa;
2658
2659 /*
2660 * paranoid error checking
2661 */
2662 if (hp == DI_HP_NIL) {
2663 errno = EINVAL;
2664 return (NULL);
2665 }
2666
2667 pa = (caddr_t)hp - DI_HP(hp)->self;
2668
2669 if (DI_HP(hp)->hp_name == 0) {
2670 errno = ENXIO;
2671 return (NULL);
2672 }
2673
2674 return ((char *)(pa + DI_HP(hp)->hp_name));
2675 }
2676
2677 int
di_hp_connection(di_hp_t hp)2678 di_hp_connection(di_hp_t hp)
2679 {
2680 /*
2681 * paranoid error checking
2682 */
2683 if (hp == DI_HP_NIL) {
2684 errno = EINVAL;
2685 return (-1);
2686 }
2687
2688 if (DI_HP(hp)->hp_connection == -1)
2689 errno = ENOENT;
2690
2691 return (DI_HP(hp)->hp_connection);
2692 }
2693
2694 int
di_hp_depends_on(di_hp_t hp)2695 di_hp_depends_on(di_hp_t hp)
2696 {
2697 /*
2698 * paranoid error checking
2699 */
2700 if (hp == DI_HP_NIL) {
2701 errno = EINVAL;
2702 return (-1);
2703 }
2704
2705 if (DI_HP(hp)->hp_depends_on == -1)
2706 errno = ENOENT;
2707
2708 return (DI_HP(hp)->hp_depends_on);
2709 }
2710
2711 int
di_hp_state(di_hp_t hp)2712 di_hp_state(di_hp_t hp)
2713 {
2714 /*
2715 * paranoid error checking
2716 */
2717 if (hp == DI_HP_NIL) {
2718 errno = EINVAL;
2719 return (-1);
2720 }
2721
2722 return (DI_HP(hp)->hp_state);
2723 }
2724
2725 int
di_hp_type(di_hp_t hp)2726 di_hp_type(di_hp_t hp)
2727 {
2728 /*
2729 * paranoid error checking
2730 */
2731 if (hp == DI_HP_NIL) {
2732 errno = EINVAL;
2733 return (-1);
2734 }
2735
2736 return (DI_HP(hp)->hp_type);
2737 }
2738
2739 char *
di_hp_description(di_hp_t hp)2740 di_hp_description(di_hp_t hp)
2741 {
2742 caddr_t pa;
2743
2744 /*
2745 * paranoid error checking
2746 */
2747 if (hp == DI_HP_NIL) {
2748 errno = EINVAL;
2749 return (NULL);
2750 }
2751
2752 pa = (caddr_t)hp - DI_HP(hp)->self;
2753
2754 if (DI_HP(hp)->hp_type_str == 0)
2755 return (NULL);
2756
2757 return ((char *)(pa + DI_HP(hp)->hp_type_str));
2758 }
2759
2760 di_node_t
di_hp_child(di_hp_t hp)2761 di_hp_child(di_hp_t hp)
2762 {
2763 caddr_t pa; /* starting address of map */
2764
2765 /*
2766 * paranoid error checking
2767 */
2768 if (hp == DI_HP_NIL) {
2769 errno = EINVAL;
2770 return (DI_NODE_NIL);
2771 }
2772
2773 pa = (caddr_t)hp - DI_HP(hp)->self;
2774
2775 if (DI_HP(hp)->hp_child > 0) {
2776 return (DI_NODE(pa + DI_HP(hp)->hp_child));
2777 }
2778
2779 /*
2780 * Deal with error condition:
2781 * Child doesn't exist, figure out if DINFOSUBTREE is set.
2782 * If it isn't, set errno to ENOTSUP.
2783 */
2784 if (!(DINFOSUBTREE & DI_ALL(pa)->command))
2785 errno = ENOTSUP;
2786 else
2787 errno = ENXIO;
2788
2789 return (DI_NODE_NIL);
2790 }
2791
2792 time_t
di_hp_last_change(di_hp_t hp)2793 di_hp_last_change(di_hp_t hp)
2794 {
2795 /*
2796 * paranoid error checking
2797 */
2798 if (hp == DI_HP_NIL) {
2799 errno = EINVAL;
2800 return ((time_t)0);
2801 }
2802
2803 return ((time_t)DI_HP(hp)->hp_last_change);
2804 }
2805
2806 /*
2807 * PROM property access
2808 */
2809
2810 /*
2811 * openprom driver stuff:
2812 * The maximum property length depends on the buffer size. We use
2813 * OPROMMAXPARAM defined in <sys/openpromio.h>
2814 *
2815 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275
2816 * MAXVALSZ is maximum value size, which is whatever space left in buf
2817 */
2818
2819 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int)
2820 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME;
2821
2822 struct di_prom_prop {
2823 char *name;
2824 int len;
2825 uchar_t *data;
2826 struct di_prom_prop *next; /* form a linked list */
2827 };
2828
2829 struct di_prom_handle { /* handle to prom */
2830 mutex_t lock; /* synchronize access to openprom fd */
2831 int fd; /* /dev/openprom file descriptor */
2832 struct di_prom_prop *list; /* linked list of prop */
2833 union {
2834 char buf[OPROMMAXPARAM];
2835 struct openpromio opp;
2836 } oppbuf;
2837 };
2838
2839 di_prom_handle_t
di_prom_init()2840 di_prom_init()
2841 {
2842 struct di_prom_handle *p;
2843
2844 if ((p = malloc(sizeof (struct di_prom_handle))) == NULL)
2845 return (DI_PROM_HANDLE_NIL);
2846
2847 DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p));
2848
2849 (void) mutex_init(&p->lock, USYNC_THREAD, NULL);
2850 if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) {
2851 free(p);
2852 return (DI_PROM_HANDLE_NIL);
2853 }
2854 p->list = NULL;
2855
2856 return ((di_prom_handle_t)p);
2857 }
2858
2859 static void
di_prom_prop_free(struct di_prom_prop * list)2860 di_prom_prop_free(struct di_prom_prop *list)
2861 {
2862 struct di_prom_prop *tmp = list;
2863
2864 while (tmp != NULL) {
2865 list = tmp->next;
2866 if (tmp->name != NULL) {
2867 free(tmp->name);
2868 }
2869 if (tmp->data != NULL) {
2870 free(tmp->data);
2871 }
2872 free(tmp);
2873 tmp = list;
2874 }
2875 }
2876
2877 void
di_prom_fini(di_prom_handle_t ph)2878 di_prom_fini(di_prom_handle_t ph)
2879 {
2880 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2881
2882 DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p));
2883
2884 (void) close(p->fd);
2885 (void) mutex_destroy(&p->lock);
2886 di_prom_prop_free(p->list);
2887
2888 free(p);
2889 }
2890
2891 /*
2892 * Internal library interface for locating the property
2893 * XXX: ph->lock must be held for the duration of call.
2894 */
2895 static di_prom_prop_t
di_prom_prop_found(di_prom_handle_t ph,int nodeid,di_prom_prop_t prom_prop)2896 di_prom_prop_found(di_prom_handle_t ph, int nodeid,
2897 di_prom_prop_t prom_prop)
2898 {
2899 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2900 struct openpromio *opp = &p->oppbuf.opp;
2901 int *ip = (int *)((void *)opp->oprom_array);
2902 struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop;
2903
2904 DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid));
2905
2906 /*
2907 * Set "current" nodeid in the openprom driver
2908 */
2909 opp->oprom_size = sizeof (int);
2910 *ip = nodeid;
2911 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
2912 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid));
2913 return (DI_PROM_PROP_NIL);
2914 }
2915
2916 DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid));
2917
2918 bzero(opp, OBP_MAXBUF);
2919 opp->oprom_size = OBP_MAXPROPNAME;
2920 if (prom_prop != DI_PROM_PROP_NIL)
2921 (void) strcpy(opp->oprom_array, prop->name);
2922
2923 if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0))
2924 return (DI_PROM_PROP_NIL);
2925
2926 /*
2927 * Prom property found. Allocate struct for storing prop
2928 * (reuse variable prop)
2929 */
2930 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL)
2931 return (DI_PROM_PROP_NIL);
2932
2933 /*
2934 * Get a copy of property name
2935 */
2936 if ((prop->name = strdup(opp->oprom_array)) == NULL) {
2937 free(prop);
2938 return (DI_PROM_PROP_NIL);
2939 }
2940
2941 /*
2942 * get property value and length
2943 */
2944 opp->oprom_size = OBP_MAXPROPLEN;
2945
2946 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
2947 (opp->oprom_size == (uint_t)-1)) {
2948 free(prop->name);
2949 free(prop);
2950 return (DI_PROM_PROP_NIL);
2951 }
2952
2953 /*
2954 * make a copy of the property value
2955 */
2956 prop->len = opp->oprom_size;
2957
2958 if (prop->len == 0)
2959 prop->data = NULL;
2960 else if ((prop->data = malloc(prop->len)) == NULL) {
2961 free(prop->name);
2962 free(prop);
2963 return (DI_PROM_PROP_NIL);
2964 }
2965
2966 bcopy(opp->oprom_array, prop->data, prop->len);
2967
2968 /*
2969 * Prepend prop to list in prom handle
2970 */
2971 prop->next = p->list;
2972 p->list = prop;
2973
2974 return ((di_prom_prop_t)prop);
2975 }
2976
2977 di_prom_prop_t
di_prom_prop_next(di_prom_handle_t ph,di_node_t node,di_prom_prop_t prom_prop)2978 di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop)
2979 {
2980 struct di_prom_handle *p = (struct di_prom_handle *)ph;
2981
2982 DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n",
2983 node, p));
2984
2985 /*
2986 * paranoid check
2987 */
2988 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
2989 errno = EINVAL;
2990 return (DI_PROM_PROP_NIL);
2991 }
2992
2993 if (di_nodeid(node) != DI_PROM_NODEID) {
2994 errno = ENXIO;
2995 return (DI_PROM_PROP_NIL);
2996 }
2997
2998 /*
2999 * synchronize access to prom file descriptor
3000 */
3001 (void) mutex_lock(&p->lock);
3002
3003 /*
3004 * look for next property
3005 */
3006 prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop);
3007
3008 (void) mutex_unlock(&p->lock);
3009
3010 return (prom_prop);
3011 }
3012
3013 char *
di_prom_prop_name(di_prom_prop_t prom_prop)3014 di_prom_prop_name(di_prom_prop_t prom_prop)
3015 {
3016 /*
3017 * paranoid check
3018 */
3019 if (prom_prop == DI_PROM_PROP_NIL) {
3020 errno = EINVAL;
3021 return (NULL);
3022 }
3023
3024 return (((struct di_prom_prop *)prom_prop)->name);
3025 }
3026
3027 int
di_prom_prop_data(di_prom_prop_t prom_prop,uchar_t ** prom_prop_data)3028 di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data)
3029 {
3030 /*
3031 * paranoid check
3032 */
3033 if (prom_prop == DI_PROM_PROP_NIL) {
3034 errno = EINVAL;
3035 return (0);
3036 }
3037
3038 *prom_prop_data = ((struct di_prom_prop *)prom_prop)->data;
3039
3040 return (((struct di_prom_prop *)prom_prop)->len);
3041 }
3042
3043 /*
3044 * Internal library interface for locating the property
3045 * Returns length if found, -1 if prop doesn't exist.
3046 */
3047 static struct di_prom_prop *
di_prom_prop_lookup_common(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name)3048 di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node,
3049 const char *prom_prop_name)
3050 {
3051 struct openpromio *opp;
3052 struct di_prom_prop *prop;
3053 struct di_prom_handle *p = (struct di_prom_handle *)ph;
3054
3055 /*
3056 * paranoid check
3057 */
3058 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) {
3059 errno = EINVAL;
3060 return (NULL);
3061 }
3062
3063 if (di_nodeid(node) != DI_PROM_NODEID) {
3064 errno = ENXIO;
3065 return (NULL);
3066 }
3067
3068 opp = &p->oppbuf.opp;
3069
3070 (void) mutex_lock(&p->lock);
3071
3072 opp->oprom_size = sizeof (int);
3073 opp->oprom_node = DI_NODE(node)->nodeid;
3074 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) {
3075 errno = ENXIO;
3076 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n",
3077 DI_NODE(node)->nodeid));
3078 (void) mutex_unlock(&p->lock);
3079 return (NULL);
3080 }
3081
3082 /*
3083 * get property length
3084 */
3085 bzero(opp, OBP_MAXBUF);
3086 opp->oprom_size = OBP_MAXPROPLEN;
3087 (void) strcpy(opp->oprom_array, prom_prop_name);
3088
3089 if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) ||
3090 (opp->oprom_len == -1)) {
3091 /* no such property */
3092 (void) mutex_unlock(&p->lock);
3093 return (NULL);
3094 }
3095
3096 /*
3097 * Prom property found. Allocate struct for storing prop
3098 */
3099 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) {
3100 (void) mutex_unlock(&p->lock);
3101 return (NULL);
3102 }
3103 prop->name = NULL; /* we don't need the name */
3104 prop->len = opp->oprom_len;
3105
3106 if (prop->len == 0) { /* boolean property */
3107 prop->data = NULL;
3108 prop->next = p->list;
3109 p->list = prop;
3110 (void) mutex_unlock(&p->lock);
3111 return (prop);
3112 }
3113
3114 /*
3115 * retrieve the property value
3116 */
3117 bzero(opp, OBP_MAXBUF);
3118 opp->oprom_size = OBP_MAXPROPLEN;
3119 (void) strcpy(opp->oprom_array, prom_prop_name);
3120
3121 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) ||
3122 (opp->oprom_size == (uint_t)-1)) {
3123 /* error retrieving property value */
3124 (void) mutex_unlock(&p->lock);
3125 free(prop);
3126 return (NULL);
3127 }
3128
3129 /*
3130 * make a copy of the property value, stick in ph->list
3131 */
3132 if ((prop->data = malloc(prop->len)) == NULL) {
3133 (void) mutex_unlock(&p->lock);
3134 free(prop);
3135 return (NULL);
3136 }
3137
3138 bcopy(opp->oprom_array, prop->data, prop->len);
3139
3140 prop->next = p->list;
3141 p->list = prop;
3142 (void) mutex_unlock(&p->lock);
3143
3144 return (prop);
3145 }
3146
3147 int
di_prom_prop_lookup_ints(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name,int ** prom_prop_data)3148 di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node,
3149 const char *prom_prop_name, int **prom_prop_data)
3150 {
3151 int len;
3152 struct di_prom_prop *prop;
3153
3154 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3155
3156 if (prop == NULL) {
3157 *prom_prop_data = NULL;
3158 return (-1);
3159 }
3160
3161 if (prop->len == 0) { /* boolean property */
3162 *prom_prop_data = NULL;
3163 return (0);
3164 }
3165
3166 len = di_prop_decode_common((void *)&prop->data, prop->len,
3167 DI_PROP_TYPE_INT, 1);
3168 *prom_prop_data = (int *)((void *)prop->data);
3169
3170 return (len);
3171 }
3172
3173 int
di_prom_prop_lookup_strings(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name,char ** prom_prop_data)3174 di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node,
3175 const char *prom_prop_name, char **prom_prop_data)
3176 {
3177 int len;
3178 struct di_prom_prop *prop;
3179
3180 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3181
3182 if (prop == NULL) {
3183 *prom_prop_data = NULL;
3184 return (-1);
3185 }
3186
3187 if (prop->len == 0) { /* boolean property */
3188 *prom_prop_data = NULL;
3189 return (0);
3190 }
3191
3192 /*
3193 * Fix an openprom bug (OBP string not NULL terminated).
3194 * XXX This should really be fixed in promif.
3195 */
3196 if (((char *)prop->data)[prop->len - 1] != '\0') {
3197 uchar_t *tmp;
3198 prop->len++;
3199 if ((tmp = realloc(prop->data, prop->len)) == NULL)
3200 return (-1);
3201
3202 prop->data = tmp;
3203 ((char *)prop->data)[prop->len - 1] = '\0';
3204 DPRINTF((DI_INFO, "OBP string not NULL terminated: "
3205 "node=%s, prop=%s, val=%s\n",
3206 di_node_name(node), prom_prop_name, prop->data));
3207 }
3208
3209 len = di_prop_decode_common((void *)&prop->data, prop->len,
3210 DI_PROP_TYPE_STRING, 1);
3211 *prom_prop_data = (char *)prop->data;
3212
3213 return (len);
3214 }
3215
3216 int
di_prom_prop_lookup_bytes(di_prom_handle_t ph,di_node_t node,const char * prom_prop_name,uchar_t ** prom_prop_data)3217 di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node,
3218 const char *prom_prop_name, uchar_t **prom_prop_data)
3219 {
3220 int len;
3221 struct di_prom_prop *prop;
3222
3223 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name);
3224
3225 if (prop == NULL) {
3226 *prom_prop_data = NULL;
3227 return (-1);
3228 }
3229
3230 if (prop->len == 0) { /* boolean property */
3231 *prom_prop_data = NULL;
3232 return (0);
3233 }
3234
3235 len = di_prop_decode_common((void *)&prop->data, prop->len,
3236 DI_PROP_TYPE_BYTE, 1);
3237 *prom_prop_data = prop->data;
3238
3239 return (len);
3240 }
3241
3242 /*
3243 * returns an allocated array through <prop_data> only when its count > 0
3244 * and the number of entries (count) as the function return value;
3245 * use di_slot_names_free() to free the array
3246 */
3247 int
di_prop_slot_names(di_prop_t prop,di_slot_name_t ** prop_data)3248 di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data)
3249 {
3250 int rawlen, count;
3251 uchar_t *rawdata;
3252 char *nm = di_prop_name(prop);
3253
3254 if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0)
3255 goto ERROUT;
3256
3257 rawlen = di_prop_rawdata(prop, &rawdata);
3258 if (rawlen <= 0 || rawdata == NULL)
3259 goto ERROUT;
3260
3261 count = di_slot_names_decode(rawdata, rawlen, prop_data);
3262 if (count < 0 || *prop_data == NULL)
3263 goto ERROUT;
3264
3265 return (count);
3266 /*NOTREACHED*/
3267 ERROUT:
3268 errno = EFAULT;
3269 *prop_data = NULL;
3270 return (-1);
3271 }
3272
3273 int
di_prop_lookup_slot_names(dev_t dev,di_node_t node,di_slot_name_t ** prop_data)3274 di_prop_lookup_slot_names(dev_t dev, di_node_t node,
3275 di_slot_name_t **prop_data)
3276 {
3277 di_prop_t prop;
3278
3279 /*
3280 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented
3281 * and slot-names is properly flagged as such
3282 */
3283 if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) ==
3284 DI_PROP_NIL) {
3285 *prop_data = NULL;
3286 return (-1);
3287 }
3288
3289 return (di_prop_slot_names(prop, (void *)prop_data));
3290 }
3291
3292 /*
3293 * returns an allocated array through <prop_data> only when its count > 0
3294 * and the number of entries (count) as the function return value;
3295 * use di_slot_names_free() to free the array
3296 */
3297 int
di_prom_prop_slot_names(di_prom_prop_t prom_prop,di_slot_name_t ** prop_data)3298 di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data)
3299 {
3300 int rawlen, count;
3301 uchar_t *rawdata;
3302
3303 rawlen = di_prom_prop_data(prom_prop, &rawdata);
3304 if (rawlen <= 0 || rawdata == NULL)
3305 goto ERROUT;
3306
3307 count = di_slot_names_decode(rawdata, rawlen, prop_data);
3308 if (count < 0 || *prop_data == NULL)
3309 goto ERROUT;
3310
3311 return (count);
3312 /*NOTREACHED*/
3313 ERROUT:
3314 errno = EFAULT;
3315 *prop_data = NULL;
3316 return (-1);
3317 }
3318
3319 int
di_prom_prop_lookup_slot_names(di_prom_handle_t ph,di_node_t node,di_slot_name_t ** prop_data)3320 di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node,
3321 di_slot_name_t **prop_data)
3322 {
3323 struct di_prom_prop *prom_prop;
3324
3325 prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES);
3326 if (prom_prop == NULL) {
3327 *prop_data = NULL;
3328 return (-1);
3329 }
3330
3331 return (di_prom_prop_slot_names(prom_prop, prop_data));
3332 }
3333
3334 di_lnode_t
di_link_to_lnode(di_link_t link,uint_t endpoint)3335 di_link_to_lnode(di_link_t link, uint_t endpoint)
3336 {
3337 struct di_all *di_all;
3338
3339 if ((link == DI_LINK_NIL) ||
3340 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3341 errno = EINVAL;
3342 return (DI_LNODE_NIL);
3343 }
3344
3345 di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self);
3346
3347 if (endpoint == DI_LINK_SRC) {
3348 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode));
3349 } else {
3350 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode));
3351 }
3352 /* NOTREACHED */
3353 }
3354
3355 char *
di_lnode_name(di_lnode_t lnode)3356 di_lnode_name(di_lnode_t lnode)
3357 {
3358 return (di_driver_name(di_lnode_devinfo(lnode)));
3359 }
3360
3361 di_node_t
di_lnode_devinfo(di_lnode_t lnode)3362 di_lnode_devinfo(di_lnode_t lnode)
3363 {
3364 struct di_all *di_all;
3365
3366 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3367 return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node));
3368 }
3369
3370 int
di_lnode_devt(di_lnode_t lnode,dev_t * devt)3371 di_lnode_devt(di_lnode_t lnode, dev_t *devt)
3372 {
3373 if ((lnode == DI_LNODE_NIL) || (devt == NULL)) {
3374 errno = EINVAL;
3375 return (-1);
3376 }
3377 if ((DI_LNODE(lnode)->dev_major == (major_t)-1) &&
3378 (DI_LNODE(lnode)->dev_minor == (minor_t)-1))
3379 return (-1);
3380
3381 *devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor);
3382 return (0);
3383 }
3384
3385 int
di_link_spectype(di_link_t link)3386 di_link_spectype(di_link_t link)
3387 {
3388 return (DI_LINK(link)->spec_type);
3389 }
3390
3391 void
di_minor_private_set(di_minor_t minor,void * data)3392 di_minor_private_set(di_minor_t minor, void *data)
3393 {
3394 DI_MINOR(minor)->user_private_data = (uintptr_t)data;
3395 }
3396
3397 void *
di_minor_private_get(di_minor_t minor)3398 di_minor_private_get(di_minor_t minor)
3399 {
3400 return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data);
3401 }
3402
3403 void
di_node_private_set(di_node_t node,void * data)3404 di_node_private_set(di_node_t node, void *data)
3405 {
3406 DI_NODE(node)->user_private_data = (uintptr_t)data;
3407 }
3408
3409 void *
di_node_private_get(di_node_t node)3410 di_node_private_get(di_node_t node)
3411 {
3412 return ((void *)(uintptr_t)DI_NODE(node)->user_private_data);
3413 }
3414
3415 void
di_path_private_set(di_path_t path,void * data)3416 di_path_private_set(di_path_t path, void *data)
3417 {
3418 DI_PATH(path)->user_private_data = (uintptr_t)data;
3419 }
3420
3421 void *
di_path_private_get(di_path_t path)3422 di_path_private_get(di_path_t path)
3423 {
3424 return ((void *)(uintptr_t)DI_PATH(path)->user_private_data);
3425 }
3426
3427 void
di_lnode_private_set(di_lnode_t lnode,void * data)3428 di_lnode_private_set(di_lnode_t lnode, void *data)
3429 {
3430 DI_LNODE(lnode)->user_private_data = (uintptr_t)data;
3431 }
3432
3433 void *
di_lnode_private_get(di_lnode_t lnode)3434 di_lnode_private_get(di_lnode_t lnode)
3435 {
3436 return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data);
3437 }
3438
3439 void
di_link_private_set(di_link_t link,void * data)3440 di_link_private_set(di_link_t link, void *data)
3441 {
3442 DI_LINK(link)->user_private_data = (uintptr_t)data;
3443 }
3444
3445 void *
di_link_private_get(di_link_t link)3446 di_link_private_get(di_link_t link)
3447 {
3448 return ((void *)(uintptr_t)DI_LINK(link)->user_private_data);
3449 }
3450
3451 di_lnode_t
di_lnode_next(di_node_t node,di_lnode_t lnode)3452 di_lnode_next(di_node_t node, di_lnode_t lnode)
3453 {
3454 struct di_all *di_all;
3455
3456 /*
3457 * paranoid error checking
3458 */
3459 if (node == DI_NODE_NIL) {
3460 errno = EINVAL;
3461 return (DI_LNODE_NIL);
3462 }
3463
3464 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3465
3466 if (lnode == DI_NODE_NIL) {
3467 if (DI_NODE(node)->lnodes != 0)
3468 return (DI_LNODE((caddr_t)di_all +
3469 DI_NODE(node)->lnodes));
3470 } else {
3471 if (DI_LNODE(lnode)->node_next != 0)
3472 return (DI_LNODE((caddr_t)di_all +
3473 DI_LNODE(lnode)->node_next));
3474 }
3475
3476 if (DINFOLYR & DI_ALL(di_all)->command)
3477 errno = ENXIO;
3478 else
3479 errno = ENOTSUP;
3480
3481 return (DI_LNODE_NIL);
3482 }
3483
3484 di_link_t
di_link_next_by_node(di_node_t node,di_link_t link,uint_t endpoint)3485 di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint)
3486 {
3487 struct di_all *di_all;
3488
3489 /*
3490 * paranoid error checking
3491 */
3492 if ((node == DI_NODE_NIL) ||
3493 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3494 errno = EINVAL;
3495 return (DI_LINK_NIL);
3496 }
3497
3498 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self);
3499
3500 if (endpoint == DI_LINK_SRC) {
3501 if (link == DI_LINK_NIL) {
3502 if (DI_NODE(node)->src_links != 0)
3503 return (DI_LINK((caddr_t)di_all +
3504 DI_NODE(node)->src_links));
3505 } else {
3506 if (DI_LINK(link)->src_node_next != 0)
3507 return (DI_LINK((caddr_t)di_all +
3508 DI_LINK(link)->src_node_next));
3509 }
3510 } else {
3511 if (link == DI_LINK_NIL) {
3512 if (DI_NODE(node)->tgt_links != 0)
3513 return (DI_LINK((caddr_t)di_all +
3514 DI_NODE(node)->tgt_links));
3515 } else {
3516 if (DI_LINK(link)->tgt_node_next != 0)
3517 return (DI_LINK((caddr_t)di_all +
3518 DI_LINK(link)->tgt_node_next));
3519 }
3520 }
3521
3522 if (DINFOLYR & DI_ALL(di_all)->command)
3523 errno = ENXIO;
3524 else
3525 errno = ENOTSUP;
3526
3527 return (DI_LINK_NIL);
3528 }
3529
3530 di_link_t
di_link_next_by_lnode(di_lnode_t lnode,di_link_t link,uint_t endpoint)3531 di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint)
3532 {
3533 struct di_all *di_all;
3534
3535 /*
3536 * paranoid error checking
3537 */
3538 if ((lnode == DI_LNODE_NIL) ||
3539 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3540 errno = EINVAL;
3541 return (DI_LINK_NIL);
3542 }
3543
3544 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self);
3545
3546 if (endpoint == DI_LINK_SRC) {
3547 if (link == DI_LINK_NIL) {
3548 if (DI_LNODE(lnode)->link_out == 0)
3549 return (DI_LINK_NIL);
3550 return (DI_LINK((caddr_t)di_all +
3551 DI_LNODE(lnode)->link_out));
3552 } else {
3553 if (DI_LINK(link)->src_link_next == 0)
3554 return (DI_LINK_NIL);
3555 return (DI_LINK((caddr_t)di_all +
3556 DI_LINK(link)->src_link_next));
3557 }
3558 } else {
3559 if (link == DI_LINK_NIL) {
3560 if (DI_LNODE(lnode)->link_in == 0)
3561 return (DI_LINK_NIL);
3562 return (DI_LINK((caddr_t)di_all +
3563 DI_LNODE(lnode)->link_in));
3564 } else {
3565 if (DI_LINK(link)->tgt_link_next == 0)
3566 return (DI_LINK_NIL);
3567 return (DI_LINK((caddr_t)di_all +
3568 DI_LINK(link)->tgt_link_next));
3569 }
3570 }
3571 /* NOTREACHED */
3572 }
3573
3574 /*
3575 * Internal library function:
3576 * Invoke callback for each link data on the link list of first node
3577 * on node_list headp, and place children of first node on the list.
3578 *
3579 * This is similar to walk_one_node, except we only walk in child
3580 * first mode.
3581 */
3582 static void
walk_one_link(struct node_list ** headp,uint_t ep,void * arg,int (* callback)(di_link_t link,void * arg))3583 walk_one_link(struct node_list **headp, uint_t ep,
3584 void *arg, int (*callback)(di_link_t link, void *arg))
3585 {
3586 int action = DI_WALK_CONTINUE;
3587 di_link_t link = DI_LINK_NIL;
3588 di_node_t node = (*headp)->node;
3589
3590 while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) {
3591 action = callback(link, arg);
3592 if (action == DI_WALK_TERMINATE) {
3593 break;
3594 }
3595 }
3596
3597 update_node_list(action, DI_WALK_LINKGEN, headp);
3598 }
3599
3600 int
di_walk_link(di_node_t root,uint_t flag,uint_t endpoint,void * arg,int (* link_callback)(di_link_t link,void * arg))3601 di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg,
3602 int (*link_callback)(di_link_t link, void *arg))
3603 {
3604 struct node_list *head; /* node_list for tree walk */
3605
3606 #ifdef DEBUG
3607 char *devfspath = di_devfs_path(root);
3608 DPRINTF((DI_INFO, "walking %s link data under %s\n",
3609 (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath));
3610 di_devfs_path_free(devfspath);
3611 #endif
3612
3613 /*
3614 * paranoid error checking
3615 */
3616 if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) ||
3617 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) {
3618 errno = EINVAL;
3619 return (-1);
3620 }
3621
3622 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3623 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3624 return (-1);
3625 }
3626
3627 head->next = NULL;
3628 head->node = root;
3629
3630 DPRINTF((DI_INFO, "Start link data walking from node %s\n",
3631 di_node_name(root)));
3632
3633 while (head != NULL)
3634 walk_one_link(&head, endpoint, arg, link_callback);
3635
3636 return (0);
3637 }
3638
3639 /*
3640 * Internal library function:
3641 * Invoke callback for each link data on the link list of first node
3642 * on node_list headp, and place children of first node on the list.
3643 *
3644 * This is similar to walk_one_node, except we only walk in child
3645 * first mode.
3646 */
3647 static void
walk_one_lnode(struct node_list ** headp,void * arg,int (* callback)(di_lnode_t lnode,void * arg))3648 walk_one_lnode(struct node_list **headp, void *arg,
3649 int (*callback)(di_lnode_t lnode, void *arg))
3650 {
3651 int action = DI_WALK_CONTINUE;
3652 di_lnode_t lnode = DI_LNODE_NIL;
3653 di_node_t node = (*headp)->node;
3654
3655 while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) {
3656 action = callback(lnode, arg);
3657 if (action == DI_WALK_TERMINATE) {
3658 break;
3659 }
3660 }
3661
3662 update_node_list(action, DI_WALK_LINKGEN, headp);
3663 }
3664
3665 int
di_walk_lnode(di_node_t root,uint_t flag,void * arg,int (* lnode_callback)(di_lnode_t lnode,void * arg))3666 di_walk_lnode(di_node_t root, uint_t flag, void *arg,
3667 int (*lnode_callback)(di_lnode_t lnode, void *arg))
3668 {
3669 struct node_list *head; /* node_list for tree walk */
3670
3671 #ifdef DEBUG
3672 char *devfspath = di_devfs_path(root);
3673 DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath));
3674 di_devfs_path_free(devfspath);
3675 #endif
3676
3677 /*
3678 * paranoid error checking
3679 */
3680 if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) {
3681 errno = EINVAL;
3682 return (-1);
3683 }
3684
3685 if ((head = malloc(sizeof (struct node_list))) == NULL) {
3686 DPRINTF((DI_ERR, "malloc of node_list failed\n"));
3687 return (-1);
3688 }
3689
3690 head->next = NULL;
3691 head->node = root;
3692
3693 DPRINTF((DI_INFO, "Start lnode data walking from node %s\n",
3694 di_node_name(root)));
3695
3696 while (head != NULL)
3697 walk_one_lnode(&head, arg, lnode_callback);
3698
3699 return (0);
3700 }
3701
3702 static char *
alias_to_curr(di_node_t anynode,char * devfspath,di_node_t * nodep)3703 alias_to_curr(di_node_t anynode, char *devfspath, di_node_t *nodep)
3704 {
3705 caddr_t pa;
3706 struct di_all *all;
3707 struct di_alias *di_alias;
3708 di_node_t node;
3709 char *curr;
3710 char *cp;
3711 char *alias;
3712 di_off_t off;
3713 char buf[MAXPATHLEN];
3714
3715 *nodep = NULL;
3716
3717 if (anynode == DI_NODE_NIL || devfspath == NULL)
3718 return (NULL);
3719
3720 pa = (caddr_t)anynode - DI_NODE(anynode)->self;
3721 all = DI_ALL(pa);
3722
3723 di_alias = NULL;
3724 for (off = all->aliases; off > 0; off = di_alias->next) {
3725 di_alias = DI_ALIAS(pa + off);
3726 alias = di_alias->alias;
3727 if (strncmp(devfspath, alias, strlen(alias)) == 0) {
3728 cp = devfspath + strlen(alias);
3729 node = DI_NODE(pa + di_alias->curroff);
3730 assert(node != DI_NODE_NIL);
3731 if (*cp == '\0') {
3732 *nodep = node;
3733 return (NULL);
3734 } else if (*cp == '/') {
3735 curr = di_devfs_path(node);
3736 (void) snprintf(buf, sizeof (buf), "%s%s",
3737 curr, cp);
3738 di_devfs_path_free(curr);
3739 curr = strdup(buf);
3740 return (curr);
3741 }
3742 }
3743 }
3744
3745 return (NULL);
3746 }
3747
3748 static di_node_t
di_lookup_node_impl(di_node_t root,char * devfspath)3749 di_lookup_node_impl(di_node_t root, char *devfspath)
3750 {
3751 struct di_all *dap;
3752 di_node_t node;
3753 char *copy, *slash, *pname, *paddr;
3754
3755 /*
3756 * Path must be absolute and musn't have duplicate slashes
3757 */
3758 if (*devfspath != '/' || strstr(devfspath, "//")) {
3759 DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath));
3760 return (DI_NODE_NIL);
3761 }
3762
3763 if (root == DI_NODE_NIL) {
3764 DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n"));
3765 return (DI_NODE_NIL);
3766 }
3767
3768 dap = DI_ALL((caddr_t)root - DI_NODE(root)->self);
3769 if (strcmp(dap->root_path, "/") != 0) {
3770 DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path));
3771 return (DI_NODE_NIL);
3772 }
3773
3774 if ((copy = strdup(devfspath)) == NULL) {
3775 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3776 return (DI_NODE_NIL);
3777 }
3778
3779 for (slash = copy, node = root; slash; ) {
3780
3781 /*
3782 * Handle devfspath = "/" case as well as trailing '/'
3783 */
3784 if (*(slash + 1) == '\0')
3785 break;
3786
3787 /*
3788 * More path-components exist. Deal with the next one
3789 */
3790 pname = slash + 1;
3791 node = di_child_node(node);
3792
3793 if ((slash = strchr(pname, '/')) != NULL)
3794 *slash = '\0';
3795 if ((paddr = strchr(pname, '@')) != NULL)
3796 *paddr++ = '\0';
3797
3798 for (; node != DI_NODE_NIL; node = di_sibling_node(node)) {
3799 char *name, *baddr;
3800
3801 name = di_node_name(node);
3802 baddr = di_bus_addr(node);
3803
3804 if (strcmp(pname, name) != 0)
3805 continue;
3806
3807 /*
3808 * Mappings between a "path-address" and bus-addr
3809 *
3810 * paddr baddr
3811 * ---------------------
3812 * NULL NULL
3813 * NULL ""
3814 * "" N/A (invalid paddr)
3815 */
3816 if (paddr && baddr && strcmp(paddr, baddr) == 0)
3817 break;
3818 if (paddr == NULL && (baddr == NULL || *baddr == '\0'))
3819 break;
3820 }
3821
3822 /*
3823 * No nodes in the sibling list or there was no match
3824 */
3825 if (node == DI_NODE_NIL) {
3826 DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr));
3827 free(copy);
3828 return (DI_NODE_NIL);
3829 }
3830 }
3831
3832 assert(node != DI_NODE_NIL);
3833 free(copy);
3834 return (node);
3835 }
3836
3837 di_node_t
di_lookup_node(di_node_t root,char * devfspath)3838 di_lookup_node(di_node_t root, char *devfspath)
3839 {
3840 di_node_t node;
3841 char *curr;
3842
3843 node = di_lookup_node_impl(root, devfspath);
3844 if (node != DI_NODE_NIL) {
3845 return (node);
3846 }
3847
3848 /* node is already set to DI_NODE_NIL */
3849 curr = alias_to_curr(root, devfspath, &node);
3850 if (curr == NULL) {
3851 /* node may or may node be DI_NODE_NIL */
3852 return (node);
3853 }
3854
3855 node = di_lookup_node_impl(root, curr);
3856
3857 free(curr);
3858
3859 return (node);
3860 }
3861
3862 char *
di_alias2curr(di_node_t anynode,char * alias)3863 di_alias2curr(di_node_t anynode, char *alias)
3864 {
3865 di_node_t currnode = DI_NODE_NIL;
3866 char *curr;
3867
3868 if (anynode == DI_NODE_NIL || alias == NULL)
3869 return (NULL);
3870
3871 curr = alias_to_curr(anynode, alias, &currnode);
3872 if (curr == NULL && currnode != DI_NODE_NIL) {
3873 return (di_devfs_path(currnode));
3874 } else if (curr == NULL) {
3875 return (strdup(alias));
3876 }
3877
3878 return (curr);
3879 }
3880
3881 di_path_t
di_lookup_path(di_node_t root,char * devfspath)3882 di_lookup_path(di_node_t root, char *devfspath)
3883 {
3884 di_node_t phci_node;
3885 di_path_t path = DI_PATH_NIL;
3886 char *copy, *lastslash;
3887 char *pname, *paddr;
3888 char *path_name, *path_addr;
3889
3890 if ((copy = strdup(devfspath)) == NULL) {
3891 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath));
3892 return (DI_NODE_NIL);
3893 }
3894
3895 if ((lastslash = strrchr(copy, '/')) == NULL) {
3896 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3897 goto out;
3898 }
3899
3900 /* stop at pHCI and find the node for the phci */
3901 *lastslash = '\0';
3902 phci_node = di_lookup_node(root, copy);
3903 if (phci_node == NULL) {
3904 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath));
3905 goto out;
3906 }
3907
3908 /* set up pname and paddr for last component */
3909 pname = lastslash + 1;
3910 if ((paddr = strchr(pname, '@')) == NULL) {
3911 DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath));
3912 goto out;
3913 }
3914 *paddr++ = '\0';
3915
3916 /* walk paths below phci looking for match */
3917 for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL);
3918 path != DI_PATH_NIL;
3919 path = di_path_phci_next_path(phci_node, path)) {
3920
3921 /* get name@addr of path */
3922 path_name = di_path_node_name(path);
3923 path_addr = di_path_bus_addr(path);
3924 if ((path_name == NULL) || (path_addr == NULL))
3925 continue;
3926
3927 /* break on match */
3928 if ((strcmp(pname, path_name) == 0) &&
3929 (strcmp(paddr, path_addr) == 0))
3930 break;
3931 }
3932
3933 out: free(copy);
3934 return (path);
3935 }
3936
3937 static char *
msglevel2str(di_debug_t msglevel)3938 msglevel2str(di_debug_t msglevel)
3939 {
3940 switch (msglevel) {
3941 case DI_ERR:
3942 return ("ERROR");
3943 case DI_INFO:
3944 return ("Info");
3945 case DI_TRACE:
3946 return ("Trace");
3947 case DI_TRACE1:
3948 return ("Trace1");
3949 case DI_TRACE2:
3950 return ("Trace2");
3951 default:
3952 return ("UNKNOWN");
3953 }
3954 }
3955
3956 void
dprint(di_debug_t msglevel,const char * fmt,...)3957 dprint(di_debug_t msglevel, const char *fmt, ...)
3958 {
3959 va_list ap;
3960 char *estr;
3961
3962 if (di_debug <= DI_QUIET)
3963 return;
3964
3965 if (di_debug < msglevel)
3966 return;
3967
3968 estr = msglevel2str(msglevel);
3969
3970 assert(estr);
3971
3972 va_start(ap, fmt);
3973
3974 (void) fprintf(stderr, "libdevinfo[%lu]: %s: ",
3975 (ulong_t)getpid(), estr);
3976 (void) vfprintf(stderr, fmt, ap);
3977
3978 va_end(ap);
3979 }
3980
3981 /* end of devinfo.c */
3982