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