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