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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * Interfaces for getting device configuration data from kernel 32 * through the devinfo driver. 33 */ 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <stropts.h> 40 #include <fcntl.h> 41 #include <poll.h> 42 #include <synch.h> 43 #include <unistd.h> 44 #include <sys/mkdev.h> 45 #include <sys/obpdefs.h> 46 #include <sys/stat.h> 47 #include <sys/types.h> 48 #include <sys/time.h> 49 #include <sys/autoconf.h> 50 #include <stdarg.h> 51 52 #define NDEBUG 1 53 #include <assert.h> 54 55 #include "libdevinfo.h" 56 57 /* 58 * Debug message levels 59 */ 60 typedef enum { 61 DI_QUIET = 0, /* No debug messages - the default */ 62 DI_ERR = 1, 63 DI_INFO, 64 DI_TRACE, 65 DI_TRACE1, 66 DI_TRACE2 67 } di_debug_t; 68 69 int di_debug = DI_QUIET; 70 71 #define DPRINTF(args) { if (di_debug != DI_QUIET) dprint args; } 72 73 void dprint(di_debug_t msglevel, const char *fmt, ...); 74 75 76 #pragma init(_libdevinfo_init) 77 78 void 79 _libdevinfo_init() 80 { 81 char *debug_str = getenv("_LIBDEVINFO_DEBUG"); 82 83 if (debug_str) { 84 errno = 0; 85 di_debug = atoi(debug_str); 86 if (errno || di_debug < DI_QUIET) 87 di_debug = DI_QUIET; 88 } 89 } 90 91 di_node_t 92 di_init(const char *phys_path, uint_t flag) 93 { 94 return (di_init_impl(phys_path, flag, NULL)); 95 } 96 97 /* 98 * We use blocking_open() to guarantee access to the devinfo device, if open() 99 * is failing with EAGAIN. 100 */ 101 static int 102 blocking_open(const char *path, int oflag) 103 { 104 int fd; 105 106 while ((fd = open(path, oflag)) == -1 && errno == EAGAIN) 107 (void) poll(NULL, 0, 1 * MILLISEC); 108 109 return (fd); 110 } 111 112 /* private interface */ 113 di_node_t 114 di_init_driver(const char *drv_name, uint_t flag) 115 { 116 int fd; 117 char driver[MAXPATHLEN]; 118 119 /* 120 * Don't allow drv_name to exceed MAXPATHLEN - 1, or 1023, 121 * which should be sufficient for any sensible programmer. 122 */ 123 if ((drv_name == NULL) || (strlen(drv_name) >= MAXPATHLEN)) { 124 errno = EINVAL; 125 return (DI_NODE_NIL); 126 } 127 (void) strcpy(driver, drv_name); 128 129 /* 130 * open the devinfo driver 131 */ 132 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo", 133 O_RDONLY)) == -1) { 134 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", errno)); 135 return (DI_NODE_NIL); 136 } 137 138 if (ioctl(fd, DINFOLODRV, driver) != 0) { 139 DPRINTF((DI_ERR, "failed to load driver %s\n", driver)); 140 (void) close(fd); 141 errno = ENXIO; 142 return (DI_NODE_NIL); 143 } 144 (void) close(fd); 145 146 /* 147 * Driver load succeeded, return a snapshot 148 */ 149 return (di_init("/", flag)); 150 } 151 152 di_node_t 153 di_init_impl(const char *phys_path, uint_t flag, 154 struct di_priv_data *priv) 155 { 156 caddr_t pa; 157 int fd, map_size; 158 struct di_all *dap; 159 struct dinfo_io dinfo_io; 160 161 uint_t pageoffset = sysconf(_SC_PAGESIZE) - 1; 162 uint_t pagemask = ~pageoffset; 163 164 DPRINTF((DI_INFO, "di_init: taking a snapshot\n")); 165 166 /* 167 * Make sure there is no minor name in the path 168 * and the path do not start with /devices.... 169 */ 170 if (strchr(phys_path, ':') || 171 (strncmp(phys_path, "/devices", 8) == 0) || 172 (strlen(phys_path) > MAXPATHLEN)) { 173 errno = EINVAL; 174 return (DI_NODE_NIL); 175 } 176 177 if (strlen(phys_path) == 0) 178 (void) sprintf(dinfo_io.root_path, "/"); 179 else if (*phys_path != '/') 180 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path), 181 "/%s", phys_path); 182 else 183 (void) snprintf(dinfo_io.root_path, sizeof (dinfo_io.root_path), 184 "%s", phys_path); 185 186 /* 187 * If private data is requested, copy the format specification 188 */ 189 if (flag & DINFOPRIVDATA & 0xff) { 190 if (priv) 191 bcopy(priv, &dinfo_io.priv, 192 sizeof (struct di_priv_data)); 193 else { 194 errno = EINVAL; 195 return (DI_NODE_NIL); 196 } 197 } 198 199 /* 200 * Attempt to open the devinfo driver. Make a second attempt at the 201 * read-only minor node if we don't have privileges to open the full 202 * version _and_ if we're not requesting operations that the read-only 203 * node can't perform. (Setgid processes would fail an access() test, 204 * of course.) 205 */ 206 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo", 207 O_RDONLY)) == -1) { 208 if ((flag & DINFOFORCE) == DINFOFORCE || 209 (flag & DINFOPRIVDATA) == DINFOPRIVDATA) { 210 /* 211 * We wanted to perform a privileged operation, but the 212 * privileged node isn't available. Don't modify errno 213 * on our way out (but display it if we're running with 214 * di_debug set). 215 */ 216 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", 217 errno)); 218 return (DI_NODE_NIL); 219 } 220 221 if ((fd = blocking_open("/devices/pseudo/devinfo@0:devinfo,ro", 222 O_RDONLY)) == -1) { 223 DPRINTF((DI_ERR, "devinfo open failed: errno = %d\n", 224 errno)); 225 return (DI_NODE_NIL); 226 } 227 } 228 229 /* 230 * Verify that there is no major conflict, i.e., we are indeed opening 231 * the devinfo driver. 232 */ 233 if (ioctl(fd, DINFOIDENT, NULL) != DI_MAGIC) { 234 DPRINTF((DI_ERR, 235 "driver ID failed; check for major conflict\n")); 236 (void) close(fd); 237 return (DI_NODE_NIL); 238 } 239 240 /* 241 * create snapshot 242 */ 243 if ((map_size = ioctl(fd, flag, &dinfo_io)) < 0) { 244 DPRINTF((DI_ERR, "devinfo ioctl failed with " 245 "error: %d\n", errno)); 246 (void) close(fd); 247 return (DI_NODE_NIL); 248 } else if (map_size == 0) { 249 DPRINTF((DI_ERR, "%s not found\n", phys_path)); 250 errno = ENXIO; 251 (void) close(fd); 252 return (DI_NODE_NIL); 253 } 254 255 /* 256 * copy snapshot to userland 257 */ 258 map_size = (map_size + pageoffset) & pagemask; 259 if ((pa = valloc(map_size)) == NULL) { 260 DPRINTF((DI_ERR, "valloc failed for snapshot\n")); 261 (void) close(fd); 262 return (DI_NODE_NIL); 263 } 264 265 if (ioctl(fd, DINFOUSRLD, pa) != map_size) { 266 DPRINTF((DI_ERR, "failed to copy snapshot to usrld\n")); 267 (void) close(fd); 268 free(pa); 269 errno = EFAULT; 270 return (DI_NODE_NIL); 271 } 272 273 (void) close(fd); 274 275 dap = DI_ALL(pa); 276 if (dap->top_devinfo == 0) { /* phys_path not found */ 277 DPRINTF((DI_ERR, "%s not found\n", phys_path)); 278 free(pa); 279 errno = EINVAL; 280 return (DI_NODE_NIL); 281 } 282 283 return (DI_NODE(pa + dap->top_devinfo)); 284 } 285 286 void 287 di_fini(di_node_t root) 288 { 289 caddr_t pa; /* starting address of map */ 290 291 DPRINTF((DI_INFO, "di_fini: freeing a snapshot\n")); 292 293 /* 294 * paranoid checking 295 */ 296 if (root == DI_NODE_NIL) { 297 DPRINTF((DI_ERR, "di_fini called with NIL arg\n")); 298 return; 299 } 300 301 /* 302 * The root contains its own offset--self. 303 * Subtracting it from root address, we get the starting addr. 304 * The map_size is stored at the beginning of snapshot. 305 * Once we have starting address and size, we can free(). 306 */ 307 pa = (caddr_t)root - DI_NODE(root)->self; 308 309 free(pa); 310 } 311 312 di_node_t 313 di_parent_node(di_node_t node) 314 { 315 caddr_t pa; /* starting address of map */ 316 317 if (node == DI_NODE_NIL) { 318 errno = EINVAL; 319 return (DI_NODE_NIL); 320 } 321 322 DPRINTF((DI_TRACE, "Get parent of node %s\n", di_node_name(node))); 323 324 pa = (caddr_t)node - DI_NODE(node)->self; 325 326 if (DI_NODE(node)->parent) { 327 return (DI_NODE(pa + DI_NODE(node)->parent)); 328 } 329 330 /* 331 * Deal with error condition: 332 * If parent doesn't exist and node is not the root, 333 * set errno to ENOTSUP. Otherwise, set errno to ENXIO. 334 */ 335 if (strcmp(DI_ALL(pa)->root_path, "/") != 0) 336 errno = ENOTSUP; 337 else 338 errno = ENXIO; 339 340 return (DI_NODE_NIL); 341 } 342 343 di_node_t 344 di_sibling_node(di_node_t node) 345 { 346 caddr_t pa; /* starting address of map */ 347 348 if (node == DI_NODE_NIL) { 349 errno = EINVAL; 350 return (DI_NODE_NIL); 351 } 352 353 DPRINTF((DI_TRACE, "Get sibling of node %s\n", di_node_name(node))); 354 355 pa = (caddr_t)node - DI_NODE(node)->self; 356 357 if (DI_NODE(node)->sibling) { 358 return (DI_NODE(pa + DI_NODE(node)->sibling)); 359 } 360 361 /* 362 * Deal with error condition: 363 * Sibling doesn't exist, figure out if ioctl command 364 * has DINFOSUBTREE set. If it doesn't, set errno to 365 * ENOTSUP. 366 */ 367 if (!(DI_ALL(pa)->command & DINFOSUBTREE)) 368 errno = ENOTSUP; 369 else 370 errno = ENXIO; 371 372 return (DI_NODE_NIL); 373 } 374 375 di_node_t 376 di_child_node(di_node_t node) 377 { 378 caddr_t pa; /* starting address of map */ 379 380 DPRINTF((DI_TRACE, "Get child of node %s\n", di_node_name(node))); 381 382 if (node == DI_NODE_NIL) { 383 errno = EINVAL; 384 return (DI_NODE_NIL); 385 } 386 387 pa = (caddr_t)node - DI_NODE(node)->self; 388 389 if (DI_NODE(node)->child) { 390 return (DI_NODE(pa + DI_NODE(node)->child)); 391 } 392 393 /* 394 * Deal with error condition: 395 * Child doesn't exist, figure out if DINFOSUBTREE is set. 396 * If it isn't, set errno to ENOTSUP. 397 */ 398 if (!(DI_ALL(pa)->command & DINFOSUBTREE)) 399 errno = ENOTSUP; 400 else 401 errno = ENXIO; 402 403 return (DI_NODE_NIL); 404 } 405 406 di_node_t 407 di_drv_first_node(const char *drv_name, di_node_t root) 408 { 409 caddr_t pa; /* starting address of map */ 410 int major, devcnt; 411 struct di_devnm *devnm; 412 413 DPRINTF((DI_INFO, "Get first node of driver %s\n", drv_name)); 414 415 if (root == DI_NODE_NIL) { 416 errno = EINVAL; 417 return (DI_NODE_NIL); 418 } 419 420 /* 421 * get major number of driver 422 */ 423 pa = (caddr_t)root - DI_NODE(root)->self; 424 devcnt = DI_ALL(pa)->devcnt; 425 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames); 426 427 for (major = 0; major < devcnt; major++) 428 if (devnm[major].name && (strcmp(drv_name, 429 (char *)(pa + devnm[major].name)) == 0)) 430 break; 431 432 if (major >= devcnt) { 433 errno = EINVAL; 434 return (DI_NODE_NIL); 435 } 436 437 if (!(devnm[major].head)) { 438 errno = ENXIO; 439 return (DI_NODE_NIL); 440 } 441 442 return (DI_NODE(pa + devnm[major].head)); 443 } 444 445 di_node_t 446 di_drv_next_node(di_node_t node) 447 { 448 caddr_t pa; /* starting address of map */ 449 450 if (node == DI_NODE_NIL) { 451 errno = EINVAL; 452 return (DI_NODE_NIL); 453 } 454 455 DPRINTF((DI_TRACE, "next node on per driver list:" 456 " current=%s, driver=%s\n", 457 di_node_name(node), di_driver_name(node))); 458 459 if (DI_NODE(node)->next == (di_off_t)-1) { 460 errno = ENOTSUP; 461 return (DI_NODE_NIL); 462 } 463 464 pa = (caddr_t)node - DI_NODE(node)->self; 465 466 if (DI_NODE(node)->next == NULL) { 467 errno = ENXIO; 468 return (DI_NODE_NIL); 469 } 470 471 return (DI_NODE(pa + DI_NODE(node)->next)); 472 } 473 474 /* 475 * Internal library interfaces: 476 * node_list etc. for node walking 477 */ 478 struct node_list { 479 struct node_list *next; 480 di_node_t node; 481 }; 482 483 static void 484 free_node_list(struct node_list **headp) 485 { 486 struct node_list *tmp; 487 488 while (*headp) { 489 tmp = *headp; 490 *headp = (*headp)->next; 491 free(tmp); 492 } 493 } 494 495 static void 496 append_node_list(struct node_list **headp, struct node_list *list) 497 { 498 struct node_list *tmp; 499 500 if (*headp == NULL) { 501 *headp = list; 502 return; 503 } 504 505 if (list == NULL) /* a minor optimization */ 506 return; 507 508 tmp = *headp; 509 while (tmp->next) 510 tmp = tmp->next; 511 512 tmp->next = list; 513 } 514 515 static void 516 prepend_node_list(struct node_list **headp, struct node_list *list) 517 { 518 struct node_list *tmp; 519 520 if (list == NULL) 521 return; 522 523 tmp = *headp; 524 *headp = list; 525 526 if (tmp == NULL) /* a minor optimization */ 527 return; 528 529 while (list->next) 530 list = list->next; 531 532 list->next = tmp; 533 } 534 535 /* 536 * returns 1 if node is a descendant of parent, 0 otherwise 537 */ 538 static int 539 is_descendant(di_node_t node, di_node_t parent) 540 { 541 /* 542 * DI_NODE_NIL is parent of root, so it is 543 * the parent of all nodes. 544 */ 545 if (parent == DI_NODE_NIL) { 546 return (1); 547 } 548 549 do { 550 node = di_parent_node(node); 551 } while ((node != DI_NODE_NIL) && (node != parent)); 552 553 return (node != DI_NODE_NIL); 554 } 555 556 /* 557 * Insert list before the first node which is NOT a descendent of parent. 558 * This is needed to reproduce the exact walking order of link generators. 559 */ 560 static void 561 insert_node_list(struct node_list **headp, struct node_list *list, 562 di_node_t parent) 563 { 564 struct node_list *tmp, *tmp1; 565 566 if (list == NULL) 567 return; 568 569 tmp = *headp; 570 if (tmp == NULL) { /* a minor optimization */ 571 *headp = list; 572 return; 573 } 574 575 if (!is_descendant(tmp->node, parent)) { 576 prepend_node_list(headp, list); 577 return; 578 } 579 580 /* 581 * Find first node which is not a descendant 582 */ 583 while (tmp->next && is_descendant(tmp->next->node, parent)) { 584 tmp = tmp->next; 585 } 586 587 tmp1 = tmp->next; 588 tmp->next = list; 589 append_node_list(headp, tmp1); 590 } 591 592 /* 593 * Get a linked list of handles of all children 594 */ 595 static struct node_list * 596 get_children(di_node_t node) 597 { 598 di_node_t child; 599 struct node_list *result, *tmp; 600 601 DPRINTF((DI_TRACE1, "Get children of node %s\n", di_node_name(node))); 602 603 if ((child = di_child_node(node)) == DI_NODE_NIL) { 604 return (NULL); 605 } 606 607 if ((result = malloc(sizeof (struct node_list))) == NULL) { 608 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 609 return (NULL); 610 } 611 612 result->node = child; 613 tmp = result; 614 615 while ((child = di_sibling_node(tmp->node)) != DI_NODE_NIL) { 616 if ((tmp->next = malloc(sizeof (struct node_list))) == NULL) { 617 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 618 free_node_list(&result); 619 return (NULL); 620 } 621 tmp = tmp->next; 622 tmp->node = child; 623 } 624 625 tmp->next = NULL; 626 627 return (result); 628 } 629 630 /* 631 * Internal library interface: 632 * Delete all siblings of the first node from the node_list, along with 633 * the first node itself. 634 */ 635 static void 636 prune_sib(struct node_list **headp) 637 { 638 di_node_t parent, curr_par, curr_gpar; 639 struct node_list *curr, *prev; 640 641 /* 642 * get handle to parent of first node 643 */ 644 if ((parent = di_parent_node((*headp)->node)) == DI_NODE_NIL) { 645 /* 646 * This must be the root of the snapshot, so can't 647 * have any siblings. 648 * 649 * XXX Put a check here just in case. 650 */ 651 if ((*headp)->next) 652 DPRINTF((DI_ERR, "Unexpected err in di_walk_node.\n")); 653 654 free(*headp); 655 *headp = NULL; 656 return; 657 } 658 659 /* 660 * To be complete, we should also delete the children 661 * of siblings that have already been visited. 662 * This happens for DI_WALK_SIBFIRST when the first node 663 * is NOT the first in the linked list of siblings. 664 * 665 * Hence, we compare parent with BOTH the parent and grandparent 666 * of nodes, and delete node is a match is found. 667 */ 668 prev = *headp; 669 curr = prev->next; 670 while (curr) { 671 if (((curr_par = di_parent_node(curr->node)) != DI_NODE_NIL) && 672 ((curr_par == parent) || ((curr_gpar = 673 di_parent_node(curr_par)) != DI_NODE_NIL) && 674 (curr_gpar == parent))) { 675 /* 676 * match parent/grandparent: delete curr 677 */ 678 prev->next = curr->next; 679 free(curr); 680 curr = prev->next; 681 } else 682 curr = curr->next; 683 } 684 685 /* 686 * delete the first node 687 */ 688 curr = *headp; 689 *headp = curr->next; 690 free(curr); 691 } 692 693 /* 694 * Internal library function: 695 * Update node list based on action (return code from callback) 696 * and flag specifying walking behavior. 697 */ 698 static void 699 update_node_list(int action, uint_t flag, struct node_list **headp) 700 { 701 struct node_list *children, *tmp; 702 di_node_t parent = di_parent_node((*headp)->node); 703 704 switch (action) { 705 case DI_WALK_TERMINATE: 706 /* 707 * free the node list and be done 708 */ 709 children = NULL; 710 free_node_list(headp); 711 break; 712 713 case DI_WALK_PRUNESIB: 714 /* 715 * Get list of children and prune siblings 716 */ 717 children = get_children((*headp)->node); 718 prune_sib(headp); 719 break; 720 721 case DI_WALK_PRUNECHILD: 722 /* 723 * Set children to NULL and pop first node 724 */ 725 children = NULL; 726 tmp = *headp; 727 *headp = tmp->next; 728 free(tmp); 729 break; 730 731 case DI_WALK_CONTINUE: 732 default: 733 /* 734 * Get list of children and pop first node 735 */ 736 children = get_children((*headp)->node); 737 tmp = *headp; 738 *headp = tmp->next; 739 free(tmp); 740 break; 741 } 742 743 /* 744 * insert the list of children 745 */ 746 switch (flag) { 747 case DI_WALK_CLDFIRST: 748 prepend_node_list(headp, children); 749 break; 750 751 case DI_WALK_SIBFIRST: 752 append_node_list(headp, children); 753 break; 754 755 case DI_WALK_LINKGEN: 756 default: 757 insert_node_list(headp, children, parent); 758 break; 759 } 760 } 761 762 /* 763 * Internal library function: 764 * Invoke callback on one node and update the list of nodes to be walked 765 * based on the flag and return code. 766 */ 767 static void 768 walk_one_node(struct node_list **headp, uint_t flag, void *arg, 769 int (*callback)(di_node_t, void *)) 770 { 771 DPRINTF((DI_TRACE, "Walking node %s\n", di_node_name((*headp)->node))); 772 773 update_node_list(callback((*headp)->node, arg), 774 flag & DI_WALK_MASK, headp); 775 } 776 777 int 778 di_walk_node(di_node_t root, uint_t flag, void *arg, 779 int (*node_callback)(di_node_t, void *)) 780 { 781 struct node_list *head; /* node_list for tree walk */ 782 783 if (root == NULL) { 784 errno = EINVAL; 785 return (-1); 786 } 787 788 if ((head = malloc(sizeof (struct node_list))) == NULL) { 789 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 790 return (-1); 791 } 792 793 head->next = NULL; 794 head->node = root; 795 796 DPRINTF((DI_INFO, "Start node walking from node %s\n", 797 di_node_name(root))); 798 799 while (head != NULL) 800 walk_one_node(&head, flag, arg, node_callback); 801 802 return (0); 803 } 804 805 /* 806 * Internal library function: 807 * Invoke callback for each minor on the minor list of first node 808 * on node_list headp, and place children of first node on the list. 809 * 810 * This is similar to walk_one_node, except we only walk in child 811 * first mode. 812 */ 813 static void 814 walk_one_minor_list(struct node_list **headp, const char *desired_type, 815 uint_t flag, void *arg, int (*callback)(di_node_t, di_minor_t, void *)) 816 { 817 int ddm_type; 818 int action = DI_WALK_CONTINUE; 819 char *node_type; 820 di_minor_t minor = DI_MINOR_NIL; 821 di_node_t node = (*headp)->node; 822 823 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 824 ddm_type = di_minor_type(minor); 825 826 if ((ddm_type == DDM_ALIAS) && !(flag & DI_CHECK_ALIAS)) 827 continue; 828 829 if ((ddm_type == DDM_INTERNAL_PATH) && 830 !(flag & DI_CHECK_INTERNAL_PATH)) 831 continue; 832 833 node_type = di_minor_nodetype(minor); 834 if ((desired_type != NULL) && ((node_type == NULL) || 835 strncmp(desired_type, node_type, strlen(desired_type)) 836 != 0)) 837 continue; 838 839 if ((action = callback(node, minor, arg)) == 840 DI_WALK_TERMINATE) { 841 break; 842 } 843 } 844 845 update_node_list(action, DI_WALK_LINKGEN, headp); 846 } 847 848 int 849 di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg, 850 int (*minor_callback)(di_node_t, di_minor_t, void *)) 851 { 852 struct node_list *head; /* node_list for tree walk */ 853 854 #ifdef DEBUG 855 char *path = di_devfs_path(root); 856 DPRINTF((DI_INFO, "walking minor nodes under %s\n", path)); 857 di_devfs_path_free(path); 858 #endif 859 860 if (root == NULL) { 861 errno = EINVAL; 862 return (-1); 863 } 864 865 if ((head = malloc(sizeof (struct node_list))) == NULL) { 866 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 867 return (-1); 868 } 869 870 head->next = NULL; 871 head->node = root; 872 873 DPRINTF((DI_INFO, "Start minor walking from node %s\n", 874 di_node_name(root))); 875 876 while (head != NULL) 877 walk_one_minor_list(&head, minor_type, flag, arg, 878 minor_callback); 879 880 return (0); 881 } 882 883 /* 884 * generic node parameters 885 * Calling these routines always succeeds. 886 */ 887 char * 888 di_node_name(di_node_t node) 889 { 890 return ((caddr_t)node + DI_NODE(node)->node_name - DI_NODE(node)->self); 891 } 892 893 /* returns NULL ptr or a valid ptr to non-NULL string */ 894 char * 895 di_bus_addr(di_node_t node) 896 { 897 caddr_t pa = (caddr_t)node - DI_NODE(node)->self; 898 899 if (DI_NODE(node)->address == 0) 900 return (NULL); 901 902 return ((char *)(pa + DI_NODE(node)->address)); 903 } 904 905 char * 906 di_binding_name(di_node_t node) 907 { 908 caddr_t pa = (caddr_t)node - DI_NODE(node)->self; 909 910 if (DI_NODE(node)->bind_name == 0) 911 return (NULL); 912 913 return ((char *)(pa + DI_NODE(node)->bind_name)); 914 } 915 916 int 917 di_compatible_names(di_node_t node, char **names) 918 { 919 char *c; 920 int len, size, entries = 0; 921 922 if (DI_NODE(node)->compat_names == 0) { 923 *names = NULL; 924 return (0); 925 } 926 927 *names = (caddr_t)node + 928 DI_NODE(node)->compat_names - DI_NODE(node)->self; 929 930 c = *names; 931 len = DI_NODE(node)->compat_length; 932 while (len > 0) { 933 entries++; 934 size = strlen(c) + 1; 935 len -= size; 936 c += size; 937 } 938 939 return (entries); 940 } 941 942 int 943 di_instance(di_node_t node) 944 { 945 return (DI_NODE(node)->instance); 946 } 947 948 /* 949 * XXX: emulate the return value of the old implementation 950 * using info from devi_node_class and devi_node_attributes. 951 */ 952 int 953 di_nodeid(di_node_t node) 954 { 955 if (DI_NODE(node)->node_class == DDI_NC_PROM) 956 return (DI_PROM_NODEID); 957 958 if (DI_NODE(node)->attributes & DDI_PERSISTENT) 959 return (DI_SID_NODEID); 960 961 return (DI_PSEUDO_NODEID); 962 } 963 964 uint_t 965 di_state(di_node_t node) 966 { 967 uint_t result = 0; 968 969 if (di_node_state(node) < DS_ATTACHED) 970 result |= DI_DRIVER_DETACHED; 971 if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE) 972 result |= DI_DEVICE_OFFLINE; 973 if (DI_NODE(node)->state & DEVI_DEVICE_DOWN) 974 result |= DI_DEVICE_OFFLINE; 975 if (DI_NODE(node)->state & DEVI_BUS_QUIESCED) 976 result |= DI_BUS_QUIESCED; 977 if (DI_NODE(node)->state & DEVI_BUS_DOWN) 978 result |= DI_BUS_DOWN; 979 980 return (result); 981 } 982 983 ddi_node_state_t 984 di_node_state(di_node_t node) 985 { 986 return (DI_NODE(node)->node_state); 987 } 988 989 ddi_devid_t 990 di_devid(di_node_t node) 991 { 992 if (DI_NODE(node)->devid == 0) 993 return (NULL); 994 995 return ((ddi_devid_t)((caddr_t)node + 996 DI_NODE(node)->devid - DI_NODE(node)->self)); 997 } 998 999 int 1000 di_driver_major(di_node_t node) 1001 { 1002 int major; 1003 1004 major = DI_NODE(node)->drv_major; 1005 if (major < 0) 1006 return (-1); 1007 return (major); 1008 } 1009 1010 char * 1011 di_driver_name(di_node_t node) 1012 { 1013 int major; 1014 caddr_t pa; 1015 struct di_devnm *devnm; 1016 1017 major = DI_NODE(node)->drv_major; 1018 if (major < 0) 1019 return (NULL); 1020 1021 pa = (caddr_t)node - DI_NODE(node)->self; 1022 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames); 1023 1024 if (devnm[major].name) 1025 return (pa + devnm[major].name); 1026 else 1027 return (NULL); 1028 } 1029 1030 uint_t 1031 di_driver_ops(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 (0); 1040 1041 pa = (caddr_t)node - DI_NODE(node)->self; 1042 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames); 1043 1044 return (devnm[major].ops); 1045 } 1046 1047 /* 1048 * returns the length of the path, caller must free memory 1049 */ 1050 char * 1051 di_devfs_path(di_node_t node) 1052 { 1053 caddr_t pa; 1054 di_node_t parent; 1055 int depth = 0, len = 0; 1056 char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH]; 1057 1058 if (node == DI_NODE_NIL) { 1059 errno = EINVAL; 1060 return (NULL); 1061 } 1062 1063 /* 1064 * trace back to root, note the node_name & address 1065 */ 1066 while ((parent = di_parent_node(node)) != DI_NODE_NIL) { 1067 name[depth] = di_node_name(node); 1068 len += strlen(name[depth]) + 1; /* 1 for '/' */ 1069 1070 if ((addr[depth] = di_bus_addr(node)) != NULL) 1071 len += strlen(addr[depth]) + 1; /* 1 for '@' */ 1072 1073 node = parent; 1074 depth++; 1075 } 1076 1077 /* 1078 * get the path to the root of snapshot 1079 */ 1080 pa = (caddr_t)node - DI_NODE(node)->self; 1081 name[depth] = DI_ALL(pa)->root_path; 1082 len += strlen(name[depth]) + 1; 1083 1084 /* 1085 * allocate buffer and assemble path 1086 */ 1087 if ((buf = malloc(len)) == NULL) { 1088 return (NULL); 1089 } 1090 1091 (void) strcpy(buf, name[depth]); 1092 len = strlen(buf); 1093 if (buf[len - 1] == '/') 1094 len--; /* delete trailing '/' */ 1095 1096 while (depth) { 1097 depth--; 1098 buf[len] = '/'; 1099 (void) strcpy(buf + len + 1, name[depth]); 1100 len += strlen(name[depth]) + 1; 1101 if (addr[depth] && addr[depth][0] != '\0') { 1102 buf[len] = '@'; 1103 (void) strcpy(buf + len + 1, addr[depth]); 1104 len += strlen(addr[depth]) + 1; 1105 } 1106 } 1107 1108 return (buf); 1109 } 1110 1111 char * 1112 di_devfs_minor_path(di_minor_t minor) 1113 { 1114 di_node_t node; 1115 char *full_path, *name, *path; 1116 int full_path_len; 1117 1118 if (minor == DI_MINOR_NIL) { 1119 errno = EINVAL; 1120 return (NULL); 1121 } 1122 1123 name = di_minor_name(minor); 1124 node = di_minor_devinfo(minor); 1125 path = di_devfs_path(node); 1126 if (path == NULL) 1127 return (NULL); 1128 1129 /* make the full path to the device minor node */ 1130 full_path_len = strlen(path) + strlen(name) + 2; 1131 full_path = (char *)calloc(1, full_path_len); 1132 if (full_path != NULL) 1133 (void) snprintf(full_path, full_path_len, "%s:%s", path, name); 1134 1135 di_devfs_path_free(path); 1136 return (full_path); 1137 } 1138 1139 void 1140 di_devfs_path_free(char *buf) 1141 { 1142 if (buf == NULL) { 1143 DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n")); 1144 return; 1145 } 1146 1147 free(buf); 1148 } 1149 1150 /* minor data access */ 1151 di_minor_t 1152 di_minor_next(di_node_t node, di_minor_t minor) 1153 { 1154 caddr_t pa; 1155 1156 /* 1157 * paranoid error checking 1158 */ 1159 if (node == DI_NODE_NIL) { 1160 errno = EINVAL; 1161 return (DI_MINOR_NIL); 1162 } 1163 1164 /* 1165 * minor is not NIL 1166 */ 1167 if (minor != DI_MINOR_NIL) { 1168 if (DI_MINOR(minor)->next != 0) 1169 return ((di_minor_t)((void *)((caddr_t)minor - 1170 DI_MINOR(minor)->self + DI_MINOR(minor)->next))); 1171 else { 1172 errno = ENXIO; 1173 return (DI_MINOR_NIL); 1174 } 1175 } 1176 1177 /* 1178 * minor is NIL-->caller asks for first minor node 1179 */ 1180 if (DI_NODE(node)->minor_data != 0) { 1181 return (DI_MINOR((caddr_t)node - DI_NODE(node)->self + 1182 DI_NODE(node)->minor_data)); 1183 } 1184 1185 /* 1186 * no minor data-->check if snapshot includes minor data 1187 * in order to set the correct errno 1188 */ 1189 pa = (caddr_t)node - DI_NODE(node)->self; 1190 if (DINFOMINOR & DI_ALL(pa)->command) 1191 errno = ENXIO; 1192 else 1193 errno = ENOTSUP; 1194 1195 return (DI_MINOR_NIL); 1196 } 1197 1198 /* private interface for dealing with alias minor link generation */ 1199 di_node_t 1200 di_minor_devinfo(di_minor_t minor) 1201 { 1202 if (minor == DI_MINOR_NIL) { 1203 errno = EINVAL; 1204 return (DI_NODE_NIL); 1205 } 1206 1207 return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self + 1208 DI_MINOR(minor)->node)); 1209 } 1210 1211 ddi_minor_type 1212 di_minor_type(di_minor_t minor) 1213 { 1214 return (DI_MINOR(minor)->type); 1215 } 1216 1217 char * 1218 di_minor_name(di_minor_t minor) 1219 { 1220 if (DI_MINOR(minor)->name == 0) 1221 return (NULL); 1222 1223 return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name); 1224 } 1225 1226 dev_t 1227 di_minor_devt(di_minor_t minor) 1228 { 1229 return (makedev(DI_MINOR(minor)->dev_major, 1230 DI_MINOR(minor)->dev_minor)); 1231 } 1232 1233 int 1234 di_minor_spectype(di_minor_t minor) 1235 { 1236 return (DI_MINOR(minor)->spec_type); 1237 } 1238 1239 char * 1240 di_minor_nodetype(di_minor_t minor) 1241 { 1242 if (DI_MINOR(minor)->node_type == 0) 1243 return (NULL); 1244 1245 return ((caddr_t)minor - 1246 DI_MINOR(minor)->self + DI_MINOR(minor)->node_type); 1247 } 1248 1249 /* 1250 * Single public interface for accessing software properties 1251 */ 1252 di_prop_t 1253 di_prop_next(di_node_t node, di_prop_t prop) 1254 { 1255 int list = DI_PROP_DRV_LIST; 1256 1257 /* 1258 * paranoid check 1259 */ 1260 if (node == DI_NODE_NIL) { 1261 errno = EINVAL; 1262 return (DI_PROP_NIL); 1263 } 1264 1265 /* 1266 * Find which prop list we are at 1267 */ 1268 if (prop != DI_PROP_NIL) 1269 list = DI_PROP(prop)->prop_list; 1270 1271 do { 1272 switch (list++) { 1273 case DI_PROP_DRV_LIST: 1274 prop = di_prop_drv_next(node, prop); 1275 break; 1276 case DI_PROP_SYS_LIST: 1277 prop = di_prop_sys_next(node, prop); 1278 break; 1279 case DI_PROP_GLB_LIST: 1280 prop = di_prop_global_next(node, prop); 1281 break; 1282 case DI_PROP_HW_LIST: 1283 prop = di_prop_hw_next(node, prop); 1284 break; 1285 default: /* shouldn't happen */ 1286 errno = EFAULT; 1287 return (DI_PROP_NIL); 1288 } 1289 } while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST)); 1290 1291 return (prop); 1292 } 1293 1294 dev_t 1295 di_prop_devt(di_prop_t prop) 1296 { 1297 return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor)); 1298 } 1299 1300 char * 1301 di_prop_name(di_prop_t prop) 1302 { 1303 if (DI_PROP(prop)->prop_name == 0) 1304 return (NULL); 1305 1306 return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name); 1307 } 1308 1309 int 1310 di_prop_type(di_prop_t prop) 1311 { 1312 uint_t flags = DI_PROP(prop)->prop_flags; 1313 1314 if (flags & DDI_PROP_UNDEF_IT) 1315 return (DI_PROP_TYPE_UNDEF_IT); 1316 1317 if (DI_PROP(prop)->prop_len == 0) 1318 return (DI_PROP_TYPE_BOOLEAN); 1319 1320 if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY) 1321 return (DI_PROP_TYPE_UNKNOWN); 1322 1323 if (flags & DDI_PROP_TYPE_INT) 1324 return (DI_PROP_TYPE_INT); 1325 1326 if (flags & DDI_PROP_TYPE_INT64) 1327 return (DI_PROP_TYPE_INT64); 1328 1329 if (flags & DDI_PROP_TYPE_STRING) 1330 return (DI_PROP_TYPE_STRING); 1331 1332 if (flags & DDI_PROP_TYPE_BYTE) 1333 return (DI_PROP_TYPE_BYTE); 1334 1335 /* 1336 * Shouldn't get here. In case we do, return unknown type. 1337 * 1338 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need 1339 * to add DI_PROP_TYPE_COMPOSITE. 1340 */ 1341 DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags)); 1342 1343 return (DI_PROP_TYPE_UNKNOWN); 1344 } 1345 1346 /* 1347 * Extract type-specific values of an property 1348 */ 1349 extern int di_prop_decode_common(void *prop_data, int len, 1350 int ddi_type, int prom); 1351 1352 int 1353 di_prop_ints(di_prop_t prop, int **prop_data) 1354 { 1355 if (DI_PROP(prop)->prop_len == 0) 1356 return (0); /* boolean property */ 1357 1358 if ((DI_PROP(prop)->prop_data == 0) || 1359 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1360 errno = EFAULT; 1361 *prop_data = NULL; 1362 return (-1); 1363 } 1364 1365 *prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self 1366 + DI_PROP(prop)->prop_data)); 1367 1368 return (di_prop_decode_common((void *)prop_data, 1369 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0)); 1370 } 1371 1372 int 1373 di_prop_int64(di_prop_t prop, int64_t **prop_data) 1374 { 1375 if (DI_PROP(prop)->prop_len == 0) 1376 return (0); /* boolean property */ 1377 1378 if ((DI_PROP(prop)->prop_data == 0) || 1379 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1380 errno = EFAULT; 1381 *prop_data = NULL; 1382 return (-1); 1383 } 1384 1385 *prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self 1386 + DI_PROP(prop)->prop_data)); 1387 1388 return (di_prop_decode_common((void *)prop_data, 1389 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0)); 1390 } 1391 1392 int 1393 di_prop_strings(di_prop_t prop, char **prop_data) 1394 { 1395 if (DI_PROP(prop)->prop_len == 0) 1396 return (0); /* boolean property */ 1397 1398 if ((DI_PROP(prop)->prop_data == 0) || 1399 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1400 errno = EFAULT; 1401 *prop_data = NULL; 1402 return (-1); 1403 } 1404 1405 *prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self 1406 + DI_PROP(prop)->prop_data); 1407 1408 return (di_prop_decode_common((void *)prop_data, 1409 DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0)); 1410 } 1411 1412 int 1413 di_prop_bytes(di_prop_t prop, uchar_t **prop_data) 1414 { 1415 if (DI_PROP(prop)->prop_len == 0) 1416 return (0); /* boolean property */ 1417 1418 if ((DI_PROP(prop)->prop_data == 0) || 1419 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1420 errno = EFAULT; 1421 *prop_data = NULL; 1422 return (-1); 1423 } 1424 1425 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self 1426 + DI_PROP(prop)->prop_data); 1427 1428 return (di_prop_decode_common((void *)prop_data, 1429 DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0)); 1430 } 1431 1432 /* 1433 * returns 1 for match, 0 for no match 1434 */ 1435 static int 1436 match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type) 1437 { 1438 int prop_type; 1439 1440 #ifdef DEBUG 1441 if (di_prop_name(prop) == NULL) { 1442 DPRINTF((DI_ERR, "libdevinfo: property has no name!\n")); 1443 return (0); 1444 } 1445 #endif /* DEBUG */ 1446 1447 if (strcmp(name, di_prop_name(prop)) != 0) 1448 return (0); 1449 1450 if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev)) 1451 return (0); 1452 1453 /* 1454 * XXX prop_type is different from DDI_*. See PSARC 1997/127. 1455 */ 1456 prop_type = di_prop_type(prop); 1457 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) && 1458 (prop_type != DI_PROP_TYPE_BOOLEAN)) 1459 return (0); 1460 1461 return (1); 1462 } 1463 1464 static di_prop_t 1465 di_prop_search(dev_t match_dev, di_node_t node, const char *name, 1466 int type) 1467 { 1468 di_prop_t prop = DI_PROP_NIL; 1469 1470 /* 1471 * The check on match_dev follows ddi_prop_lookup_common(). 1472 * Other checks are libdevinfo specific implementation. 1473 */ 1474 if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) || 1475 (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) { 1476 errno = EINVAL; 1477 return (DI_PROP_NIL); 1478 } 1479 1480 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) { 1481 DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n", 1482 di_prop_name(prop), di_prop_devt(prop), 1483 di_prop_type(prop))); 1484 if (match_prop(prop, match_dev, name, type)) 1485 return (prop); 1486 } 1487 1488 return (DI_PROP_NIL); 1489 } 1490 1491 int 1492 di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name, 1493 int **prop_data) 1494 { 1495 di_prop_t prop; 1496 1497 if ((prop = di_prop_search(dev, node, prop_name, 1498 DI_PROP_TYPE_INT)) == DI_PROP_NIL) 1499 return (-1); 1500 1501 return (di_prop_ints(prop, (void *)prop_data)); 1502 } 1503 1504 int 1505 di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name, 1506 int64_t **prop_data) 1507 { 1508 di_prop_t prop; 1509 1510 if ((prop = di_prop_search(dev, node, prop_name, 1511 DI_PROP_TYPE_INT64)) == DI_PROP_NIL) 1512 return (-1); 1513 1514 return (di_prop_int64(prop, (void *)prop_data)); 1515 } 1516 1517 int 1518 di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name, 1519 char **prop_data) 1520 { 1521 di_prop_t prop; 1522 1523 if ((prop = di_prop_search(dev, node, prop_name, 1524 DI_PROP_TYPE_STRING)) == DI_PROP_NIL) 1525 return (-1); 1526 1527 return (di_prop_strings(prop, (void *)prop_data)); 1528 } 1529 1530 int 1531 di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name, 1532 uchar_t **prop_data) 1533 { 1534 di_prop_t prop; 1535 1536 if ((prop = di_prop_search(dev, node, prop_name, 1537 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL) 1538 return (-1); 1539 1540 return (di_prop_bytes(prop, (void *)prop_data)); 1541 } 1542 1543 /* 1544 * Consolidation private property access functions 1545 */ 1546 enum prop_type { 1547 PROP_TYPE_DRV, 1548 PROP_TYPE_SYS, 1549 PROP_TYPE_GLOB, 1550 PROP_TYPE_HW 1551 }; 1552 1553 static di_prop_t 1554 di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type) 1555 { 1556 caddr_t pa; 1557 di_off_t prop_off = 0; 1558 1559 if (prop != DI_PROP_NIL) { 1560 if (DI_PROP(prop)->next) { 1561 return (DI_PROP((caddr_t)prop - 1562 DI_PROP(prop)->self + DI_PROP(prop)->next)); 1563 } else { 1564 return (DI_PROP_NIL); 1565 } 1566 } 1567 1568 1569 /* 1570 * prop is NIL, caller asks for first property 1571 */ 1572 pa = (caddr_t)node - DI_NODE(node)->self; 1573 switch (prop_type) { 1574 case PROP_TYPE_DRV: 1575 prop_off = DI_NODE(node)->drv_prop; 1576 break; 1577 case PROP_TYPE_SYS: 1578 prop_off = DI_NODE(node)->sys_prop; 1579 break; 1580 case PROP_TYPE_HW: 1581 prop_off = DI_NODE(node)->hw_prop; 1582 break; 1583 case PROP_TYPE_GLOB: 1584 prop_off = DI_NODE(node)->glob_prop; 1585 if (prop_off == -1) { 1586 /* no global property */ 1587 prop_off = 0; 1588 } else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) { 1589 /* refer to devnames array */ 1590 struct di_devnm *devnm = DI_DEVNM(pa + 1591 DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major * 1592 sizeof (struct di_devnm))); 1593 prop_off = devnm->global_prop; 1594 } 1595 break; 1596 } 1597 1598 if (prop_off) { 1599 return (DI_PROP(pa + prop_off)); 1600 } 1601 1602 /* 1603 * no prop found. Check the reason for not found 1604 */ 1605 if (DINFOPROP & DI_ALL(pa)->command) 1606 errno = ENXIO; 1607 else 1608 errno = ENOTSUP; 1609 1610 return (DI_PROP_NIL); 1611 } 1612 1613 di_prop_t 1614 di_prop_drv_next(di_node_t node, di_prop_t prop) 1615 { 1616 return (di_prop_next_common(node, prop, PROP_TYPE_DRV)); 1617 } 1618 1619 di_prop_t 1620 di_prop_sys_next(di_node_t node, di_prop_t prop) 1621 { 1622 return (di_prop_next_common(node, prop, PROP_TYPE_SYS)); 1623 } 1624 1625 di_prop_t 1626 di_prop_global_next(di_node_t node, di_prop_t prop) 1627 { 1628 return (di_prop_next_common(node, prop, PROP_TYPE_GLOB)); 1629 } 1630 1631 di_prop_t 1632 di_prop_hw_next(di_node_t node, di_prop_t prop) 1633 { 1634 return (di_prop_next_common(node, prop, PROP_TYPE_HW)); 1635 } 1636 1637 int 1638 di_prop_rawdata(di_prop_t prop, uchar_t **prop_data) 1639 { 1640 #ifdef DEBUG 1641 if (prop == DI_PROP_NIL) { 1642 errno = EINVAL; 1643 return (-1); 1644 } 1645 #endif /* DEBUG */ 1646 1647 if (DI_PROP(prop)->prop_len == 0) { 1648 *prop_data = NULL; 1649 return (0); 1650 } 1651 1652 if ((DI_PROP(prop)->prop_data == 0) || 1653 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1654 errno = EFAULT; 1655 *prop_data = NULL; 1656 return (-1); 1657 } 1658 1659 /* 1660 * No memory allocation. 1661 */ 1662 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self + 1663 DI_PROP(prop)->prop_data); 1664 1665 return (DI_PROP(prop)->prop_len); 1666 } 1667 1668 /* 1669 * Consolidation private interfaces for accessing I/O multipathing data 1670 */ 1671 di_path_t 1672 di_path_next_client(di_node_t node, di_path_t path) 1673 { 1674 caddr_t pa; 1675 1676 /* 1677 * path is not NIL 1678 */ 1679 if (path != DI_PATH_NIL) { 1680 if (DI_PATH(path)->path_p_link != 0) 1681 return (DI_PATH((void *)((caddr_t)path - 1682 DI_PATH(path)->self + DI_PATH(path)->path_p_link))); 1683 else { 1684 errno = ENXIO; 1685 return (DI_PATH_NIL); 1686 } 1687 } 1688 1689 /* 1690 * Path is NIL; the caller is asking for the first path info node 1691 */ 1692 if (DI_NODE(node)->multipath_phci != 0) { 1693 DPRINTF((DI_INFO, "phci: returning %p\n", ((caddr_t)node - 1694 DI_NODE(node)->self + DI_NODE(node)->multipath_phci))); 1695 return (DI_PATH((caddr_t)node - DI_NODE(node)->self + 1696 DI_NODE(node)->multipath_phci)); 1697 } 1698 1699 /* 1700 * No pathing data; check if the snapshot includes path data in order 1701 * to set errno properly. 1702 */ 1703 pa = (caddr_t)node - DI_NODE(node)->self; 1704 if (DINFOPATH & (DI_ALL(pa)->command)) 1705 errno = ENXIO; 1706 else 1707 errno = ENOTSUP; 1708 1709 return (DI_PATH_NIL); 1710 } 1711 1712 di_path_t 1713 di_path_next_phci(di_node_t node, di_path_t path) 1714 { 1715 caddr_t pa; 1716 1717 /* 1718 * path is not NIL 1719 */ 1720 if (path != DI_PATH_NIL) { 1721 if (DI_PATH(path)->path_c_link != 0) 1722 return (DI_PATH((caddr_t)path - DI_PATH(path)->self 1723 + DI_PATH(path)->path_c_link)); 1724 else { 1725 errno = ENXIO; 1726 return (DI_PATH_NIL); 1727 } 1728 } 1729 1730 /* 1731 * Path is NIL; the caller is asking for the first path info node 1732 */ 1733 if (DI_NODE(node)->multipath_client != 0) { 1734 DPRINTF((DI_INFO, "client: returning %p\n", ((caddr_t)node - 1735 DI_NODE(node)->self + DI_NODE(node)->multipath_client))); 1736 return (DI_PATH((caddr_t)node - DI_NODE(node)->self + 1737 DI_NODE(node)->multipath_client)); 1738 } 1739 1740 /* 1741 * No pathing data; check if the snapshot includes path data in order 1742 * to set errno properly. 1743 */ 1744 pa = (caddr_t)node - DI_NODE(node)->self; 1745 if (DINFOPATH & (DI_ALL(pa)->command)) 1746 errno = ENXIO; 1747 else 1748 errno = ENOTSUP; 1749 1750 return (DI_PATH_NIL); 1751 } 1752 1753 /* 1754 * XXX Obsolete wrapper to be removed. Won't work under multilevel. 1755 */ 1756 di_path_t 1757 di_path_next(di_node_t node, di_path_t path) 1758 { 1759 if (node == DI_NODE_NIL) { 1760 errno = EINVAL; 1761 return (DI_PATH_NIL); 1762 } 1763 1764 if (DI_NODE(node)->multipath_client) { 1765 return (di_path_next_phci(node, path)); 1766 } else if (DI_NODE(node)->multipath_phci) { 1767 return (di_path_next_client(node, path)); 1768 } else { 1769 /* 1770 * The node had multipathing data but didn't appear to be a 1771 * phci *or* a client; probably a programmer error. 1772 */ 1773 errno = EINVAL; 1774 return (DI_PATH_NIL); 1775 } 1776 } 1777 1778 di_path_state_t 1779 di_path_state(di_path_t path) 1780 { 1781 return ((di_path_state_t)DI_PATH(path)->path_state); 1782 } 1783 1784 char * 1785 di_path_addr(di_path_t path, char *buf) 1786 { 1787 caddr_t pa; /* starting address of map */ 1788 1789 pa = (caddr_t)path - DI_PATH(path)->self; 1790 1791 (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr), 1792 MAXPATHLEN); 1793 return (buf); 1794 } 1795 1796 di_node_t 1797 di_path_client_node(di_path_t path) 1798 { 1799 caddr_t pa; /* starting address of map */ 1800 1801 if (path == DI_PATH_NIL) { 1802 errno = EINVAL; 1803 return (DI_PATH_NIL); 1804 } 1805 1806 DPRINTF((DI_TRACE, "Get client node for path %p\n", path)); 1807 1808 pa = (caddr_t)path - DI_PATH(path)->self; 1809 1810 if (DI_PATH(path)->path_client) { 1811 return (DI_NODE(pa + DI_PATH(path)->path_client)); 1812 } 1813 1814 /* 1815 * Deal with error condition: 1816 * If parent doesn't exist and node is not the root, 1817 * set errno to ENOTSUP. Otherwise, set errno to ENXIO. 1818 */ 1819 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0) 1820 errno = ENOTSUP; 1821 else 1822 errno = ENXIO; 1823 1824 return (DI_NODE_NIL); 1825 } 1826 1827 di_node_t 1828 di_path_phci_node(di_path_t path) 1829 { 1830 caddr_t pa; /* starting address of map */ 1831 1832 if (path == DI_PATH_NIL) { 1833 errno = EINVAL; 1834 return (DI_PATH_NIL); 1835 } 1836 1837 DPRINTF((DI_TRACE, "Get phci node for path %p\n", path)); 1838 1839 pa = (caddr_t)path - DI_PATH(path)->self; 1840 1841 if (DI_PATH(path)->path_phci) { 1842 return (DI_NODE(pa + DI_PATH(path)->path_phci)); 1843 } 1844 1845 /* 1846 * Deal with error condition: 1847 * If parent doesn't exist and node is not the root, 1848 * set errno to ENOTSUP. Otherwise, set errno to ENXIO. 1849 */ 1850 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0) 1851 errno = ENOTSUP; 1852 else 1853 errno = ENXIO; 1854 1855 return (DI_NODE_NIL); 1856 } 1857 1858 di_path_prop_t 1859 di_path_prop_next(di_path_t path, di_path_prop_t prop) 1860 { 1861 caddr_t pa; 1862 1863 if (path == DI_PATH_NIL) { 1864 errno = EINVAL; 1865 return (DI_PROP_NIL); 1866 } 1867 1868 /* 1869 * prop is not NIL 1870 */ 1871 if (prop != DI_PROP_NIL) { 1872 if (DI_PROP(prop)->next != 0) 1873 return (DI_PATHPROP((caddr_t)prop - 1874 DI_PROP(prop)->self + DI_PROP(prop)->next)); 1875 else { 1876 errno = ENXIO; 1877 return (DI_PROP_NIL); 1878 } 1879 } 1880 1881 /* 1882 * prop is NIL-->caller asks for first property 1883 */ 1884 pa = (caddr_t)path - DI_PATH(path)->self; 1885 if (DI_PATH(path)->path_prop != 0) { 1886 return (DI_PATHPROP(pa + DI_PATH(path)->path_prop)); 1887 } 1888 1889 /* 1890 * no property data-->check if snapshot includes props 1891 * in order to set the correct errno 1892 */ 1893 if (DINFOPROP & (DI_ALL(pa)->command)) 1894 errno = ENXIO; 1895 else 1896 errno = ENOTSUP; 1897 1898 return (DI_PROP_NIL); 1899 } 1900 1901 char * 1902 di_path_prop_name(di_path_prop_t prop) 1903 { 1904 caddr_t pa; /* starting address of map */ 1905 pa = (caddr_t)prop - DI_PATHPROP(prop)->self; 1906 return ((char *)(pa + DI_PATHPROP(prop)->prop_name)); 1907 } 1908 1909 int 1910 di_path_prop_len(di_path_prop_t prop) 1911 { 1912 return (DI_PATHPROP(prop)->prop_len); 1913 } 1914 1915 int 1916 di_path_prop_type(di_path_prop_t prop) 1917 { 1918 switch (DI_PATHPROP(prop)->prop_type) { 1919 case DDI_PROP_TYPE_INT: 1920 return (DI_PROP_TYPE_INT); 1921 case DDI_PROP_TYPE_INT64: 1922 return (DI_PROP_TYPE_INT64); 1923 case DDI_PROP_TYPE_BYTE: 1924 return (DI_PROP_TYPE_BYTE); 1925 case DDI_PROP_TYPE_STRING: 1926 return (DI_PROP_TYPE_STRING); 1927 } 1928 return (DI_PROP_TYPE_UNKNOWN); 1929 } 1930 1931 int 1932 di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data) 1933 { 1934 if ((DI_PATHPROP(prop)->prop_data == 0) || 1935 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 1936 errno = EFAULT; 1937 *prop_data = NULL; 1938 return (-1); 1939 } 1940 1941 *prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self 1942 + DI_PATHPROP(prop)->prop_data); 1943 1944 return (di_prop_decode_common((void *)prop_data, 1945 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0)); 1946 } 1947 1948 int 1949 di_path_prop_ints(di_path_prop_t prop, int **prop_data) 1950 { 1951 if (DI_PATHPROP(prop)->prop_len == 0) 1952 return (0); 1953 1954 if ((DI_PATHPROP(prop)->prop_data == 0) || 1955 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 1956 errno = EFAULT; 1957 *prop_data = NULL; 1958 return (-1); 1959 } 1960 1961 *prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self 1962 + DI_PATHPROP(prop)->prop_data)); 1963 1964 return (di_prop_decode_common((void *)prop_data, 1965 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0)); 1966 } 1967 1968 int 1969 di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data) 1970 { 1971 if (DI_PATHPROP(prop)->prop_len == 0) 1972 return (0); 1973 1974 if ((DI_PATHPROP(prop)->prop_data == 0) || 1975 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 1976 errno = EFAULT; 1977 *prop_data = NULL; 1978 return (-1); 1979 } 1980 1981 *prop_data = (int64_t *)((void *)((caddr_t)prop - 1982 DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data)); 1983 1984 return (di_prop_decode_common((void *)prop_data, 1985 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0)); 1986 } 1987 1988 int 1989 di_path_prop_strings(di_path_prop_t prop, char **prop_data) 1990 { 1991 if (DI_PATHPROP(prop)->prop_len == 0) 1992 return (0); 1993 1994 if ((DI_PATHPROP(prop)->prop_data == 0) || 1995 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 1996 errno = EFAULT; 1997 *prop_data = NULL; 1998 return (-1); 1999 } 2000 2001 *prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self 2002 + DI_PATHPROP(prop)->prop_data); 2003 2004 return (di_prop_decode_common((void *)prop_data, 2005 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0)); 2006 } 2007 2008 static di_path_prop_t 2009 di_path_prop_search(di_path_t path, const char *name, int type) 2010 { 2011 di_path_prop_t prop = DI_PROP_NIL; 2012 2013 /* 2014 * Sanity check arguments 2015 */ 2016 if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) || 2017 !DI_PROP_TYPE_VALID(type)) { 2018 errno = EINVAL; 2019 return (DI_PROP_NIL); 2020 } 2021 2022 while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) { 2023 int prop_type = di_path_prop_type(prop); 2024 2025 DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n", 2026 di_path_prop_name(prop), prop_type)); 2027 2028 if (strcmp(name, di_path_prop_name(prop)) != 0) 2029 continue; 2030 2031 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type)) 2032 continue; 2033 2034 return (prop); 2035 } 2036 2037 return (DI_PROP_NIL); 2038 } 2039 2040 int 2041 di_path_prop_lookup_bytes(di_path_t path, const char *prop_name, 2042 uchar_t **prop_data) 2043 { 2044 di_path_prop_t prop; 2045 2046 if ((prop = di_path_prop_search(path, prop_name, 2047 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL) 2048 return (-1); 2049 2050 return (di_path_prop_bytes(prop, prop_data)); 2051 } 2052 2053 int 2054 di_path_prop_lookup_ints(di_path_t path, const char *prop_name, 2055 int **prop_data) 2056 { 2057 di_path_prop_t prop; 2058 2059 if ((prop = di_path_prop_search(path, prop_name, 2060 DI_PROP_TYPE_INT)) == DI_PROP_NIL) 2061 return (-1); 2062 2063 return (di_path_prop_ints(prop, prop_data)); 2064 } 2065 2066 int 2067 di_path_prop_lookup_int64s(di_path_t path, const char *prop_name, 2068 int64_t **prop_data) 2069 { 2070 di_path_prop_t prop; 2071 2072 if ((prop = di_path_prop_search(path, prop_name, 2073 DI_PROP_TYPE_INT64)) == DI_PROP_NIL) 2074 return (-1); 2075 2076 return (di_path_prop_int64s(prop, prop_data)); 2077 } 2078 2079 int di_path_prop_lookup_strings(di_path_t path, const char *prop_name, 2080 char **prop_data) 2081 { 2082 di_path_prop_t prop; 2083 2084 if ((prop = di_path_prop_search(path, prop_name, 2085 DI_PROP_TYPE_STRING)) == DI_PROP_NIL) 2086 return (-1); 2087 2088 return (di_path_prop_strings(prop, prop_data)); 2089 } 2090 2091 /* 2092 * Consolidation private interfaces for traversing vhci nodes. 2093 */ 2094 di_node_t 2095 di_vhci_first_node(di_node_t root) 2096 { 2097 struct di_all *dap; 2098 caddr_t pa; /* starting address of map */ 2099 2100 DPRINTF((DI_INFO, "Get first vhci node\n")); 2101 2102 if (root == DI_NODE_NIL) { 2103 errno = EINVAL; 2104 return (DI_NODE_NIL); 2105 } 2106 2107 pa = (caddr_t)root - DI_NODE(root)->self; 2108 dap = DI_ALL(pa); 2109 2110 if (dap->top_vhci_devinfo == NULL) { 2111 errno = ENXIO; 2112 return (DI_NODE_NIL); 2113 } 2114 2115 return (DI_NODE(pa + dap->top_vhci_devinfo)); 2116 } 2117 2118 di_node_t 2119 di_vhci_next_node(di_node_t node) 2120 { 2121 caddr_t pa; /* starting address of map */ 2122 2123 if (node == DI_NODE_NIL) { 2124 errno = EINVAL; 2125 return (DI_NODE_NIL); 2126 } 2127 2128 DPRINTF((DI_TRACE, "next vhci node on the snap shot:" 2129 " current=%s\n", di_node_name(node))); 2130 2131 if (DI_NODE(node)->next_vhci == NULL) { 2132 errno = ENXIO; 2133 return (DI_NODE_NIL); 2134 } 2135 2136 pa = (caddr_t)node - DI_NODE(node)->self; 2137 2138 return (DI_NODE(pa + DI_NODE(node)->next_vhci)); 2139 } 2140 2141 /* 2142 * Consolidation private interfaces for traversing phci nodes. 2143 */ 2144 di_node_t 2145 di_phci_first_node(di_node_t vhci_node) 2146 { 2147 caddr_t pa; /* starting address of map */ 2148 2149 DPRINTF((DI_INFO, "Get first phci node:\n" 2150 " current=%s", di_node_name(vhci_node))); 2151 2152 if (vhci_node == DI_NODE_NIL) { 2153 errno = EINVAL; 2154 return (DI_NODE_NIL); 2155 } 2156 2157 pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self; 2158 2159 if (DI_NODE(vhci_node)->top_phci == NULL) { 2160 errno = ENXIO; 2161 return (DI_NODE_NIL); 2162 } 2163 2164 return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci)); 2165 } 2166 2167 di_node_t 2168 di_phci_next_node(di_node_t node) 2169 { 2170 caddr_t pa; /* starting address of map */ 2171 2172 if (node == DI_NODE_NIL) { 2173 errno = EINVAL; 2174 return (DI_NODE_NIL); 2175 } 2176 2177 DPRINTF((DI_TRACE, "next phci node on the snap shot:" 2178 " current=%s\n", di_node_name(node))); 2179 2180 if (DI_NODE(node)->next_phci == NULL) { 2181 errno = ENXIO; 2182 return (DI_NODE_NIL); 2183 } 2184 2185 pa = (caddr_t)node - DI_NODE(node)->self; 2186 2187 return (DI_NODE(pa + DI_NODE(node)->next_phci)); 2188 } 2189 2190 /* 2191 * Consolidation private interfaces for private data 2192 */ 2193 void * 2194 di_parent_private_data(di_node_t node) 2195 { 2196 caddr_t pa; 2197 2198 if (DI_NODE(node)->parent_data == 0) { 2199 errno = ENXIO; 2200 return (NULL); 2201 } 2202 2203 if (DI_NODE(node)->parent_data == (di_off_t)-1) { 2204 /* 2205 * Private data requested, but not obtained due to a memory 2206 * error (e.g. wrong format specified) 2207 */ 2208 errno = EFAULT; 2209 return (NULL); 2210 } 2211 2212 pa = (caddr_t)node - DI_NODE(node)->self; 2213 if (DI_NODE(node)->parent_data) 2214 return (pa + DI_NODE(node)->parent_data); 2215 2216 if (DI_ALL(pa)->command & DINFOPRIVDATA) 2217 errno = ENXIO; 2218 else 2219 errno = ENOTSUP; 2220 2221 return (NULL); 2222 } 2223 2224 void * 2225 di_driver_private_data(di_node_t node) 2226 { 2227 caddr_t pa; 2228 2229 if (DI_NODE(node)->driver_data == 0) { 2230 errno = ENXIO; 2231 return (NULL); 2232 } 2233 2234 if (DI_NODE(node)->driver_data == (di_off_t)-1) { 2235 /* 2236 * Private data requested, but not obtained due to a memory 2237 * error (e.g. wrong format specified) 2238 */ 2239 errno = EFAULT; 2240 return (NULL); 2241 } 2242 2243 pa = (caddr_t)node - DI_NODE(node)->self; 2244 if (DI_NODE(node)->driver_data) 2245 return (pa + DI_NODE(node)->driver_data); 2246 2247 if (DI_ALL(pa)->command & DINFOPRIVDATA) 2248 errno = ENXIO; 2249 else 2250 errno = ENOTSUP; 2251 2252 return (NULL); 2253 } 2254 2255 /* 2256 * PROM property access 2257 */ 2258 2259 /* 2260 * openprom driver stuff: 2261 * The maximum property length depends on the buffer size. We use 2262 * OPROMMAXPARAM defined in <sys/openpromio.h> 2263 * 2264 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275 2265 * MAXVALSZ is maximum value size, which is whatever space left in buf 2266 */ 2267 2268 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int) 2269 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME; 2270 2271 struct di_prom_prop { 2272 char *name; 2273 int len; 2274 uchar_t *data; 2275 struct di_prom_prop *next; /* form a linked list */ 2276 }; 2277 2278 struct di_prom_handle { /* handle to prom */ 2279 mutex_t lock; /* synchronize access to openprom fd */ 2280 int fd; /* /dev/openprom file descriptor */ 2281 struct di_prom_prop *list; /* linked list of prop */ 2282 union { 2283 char buf[OPROMMAXPARAM]; 2284 struct openpromio opp; 2285 } oppbuf; 2286 }; 2287 2288 di_prom_handle_t 2289 di_prom_init() 2290 { 2291 struct di_prom_handle *p; 2292 2293 if ((p = malloc(sizeof (struct di_prom_handle))) == NULL) 2294 return (DI_PROM_HANDLE_NIL); 2295 2296 DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p)); 2297 2298 (void) mutex_init(&p->lock, USYNC_THREAD, NULL); 2299 if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) { 2300 free(p); 2301 return (DI_PROM_HANDLE_NIL); 2302 } 2303 p->list = NULL; 2304 2305 return ((di_prom_handle_t)p); 2306 } 2307 2308 static void 2309 di_prom_prop_free(struct di_prom_prop *list) 2310 { 2311 struct di_prom_prop *tmp = list; 2312 2313 while (tmp != NULL) { 2314 list = tmp->next; 2315 if (tmp->name != NULL) { 2316 free(tmp->name); 2317 } 2318 if (tmp->data != NULL) { 2319 free(tmp->data); 2320 } 2321 free(tmp); 2322 tmp = list; 2323 } 2324 } 2325 2326 void 2327 di_prom_fini(di_prom_handle_t ph) 2328 { 2329 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2330 2331 DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p)); 2332 2333 (void) close(p->fd); 2334 (void) mutex_destroy(&p->lock); 2335 di_prom_prop_free(p->list); 2336 2337 free(p); 2338 } 2339 2340 /* 2341 * Internal library interface for locating the property 2342 * XXX: ph->lock must be held for the duration of call. 2343 */ 2344 static di_prom_prop_t 2345 di_prom_prop_found(di_prom_handle_t ph, int nodeid, 2346 di_prom_prop_t prom_prop) 2347 { 2348 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2349 struct openpromio *opp = &p->oppbuf.opp; 2350 int *ip = (int *)((void *)opp->oprom_array); 2351 struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop; 2352 2353 DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid)); 2354 2355 /* 2356 * Set "current" nodeid in the openprom driver 2357 */ 2358 opp->oprom_size = sizeof (int); 2359 *ip = nodeid; 2360 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) { 2361 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid)); 2362 return (DI_PROM_PROP_NIL); 2363 } 2364 2365 DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid)); 2366 2367 bzero(opp, OBP_MAXBUF); 2368 opp->oprom_size = OBP_MAXPROPNAME; 2369 if (prom_prop != DI_PROM_PROP_NIL) 2370 (void) strcpy(opp->oprom_array, prop->name); 2371 2372 if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0)) 2373 return (DI_PROM_PROP_NIL); 2374 2375 /* 2376 * Prom property found. Allocate struct for storing prop 2377 * (reuse variable prop) 2378 */ 2379 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) 2380 return (DI_PROM_PROP_NIL); 2381 2382 /* 2383 * Get a copy of property name 2384 */ 2385 if ((prop->name = strdup(opp->oprom_array)) == NULL) { 2386 free(prop); 2387 return (DI_PROM_PROP_NIL); 2388 } 2389 2390 /* 2391 * get property value and length 2392 */ 2393 opp->oprom_size = OBP_MAXPROPLEN; 2394 2395 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) || 2396 (opp->oprom_size == (uint_t)-1)) { 2397 free(prop->name); 2398 free(prop); 2399 return (DI_PROM_PROP_NIL); 2400 } 2401 2402 /* 2403 * make a copy of the property value 2404 */ 2405 prop->len = opp->oprom_size; 2406 2407 if (prop->len == 0) 2408 prop->data = NULL; 2409 else if ((prop->data = malloc(prop->len)) == NULL) { 2410 free(prop->name); 2411 free(prop); 2412 return (DI_PROM_PROP_NIL); 2413 } 2414 2415 bcopy(opp->oprom_array, prop->data, prop->len); 2416 2417 /* 2418 * Prepend prop to list in prom handle 2419 */ 2420 prop->next = p->list; 2421 p->list = prop; 2422 2423 return ((di_prom_prop_t)prop); 2424 } 2425 2426 di_prom_prop_t 2427 di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop) 2428 { 2429 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2430 2431 DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n", 2432 node, p)); 2433 2434 /* 2435 * paranoid check 2436 */ 2437 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) { 2438 errno = EINVAL; 2439 return (DI_PROM_PROP_NIL); 2440 } 2441 2442 if (di_nodeid(node) != DI_PROM_NODEID) { 2443 errno = ENXIO; 2444 return (DI_PROM_PROP_NIL); 2445 } 2446 2447 /* 2448 * synchronize access to prom file descriptor 2449 */ 2450 (void) mutex_lock(&p->lock); 2451 2452 /* 2453 * look for next property 2454 */ 2455 prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop); 2456 2457 (void) mutex_unlock(&p->lock); 2458 2459 return (prom_prop); 2460 } 2461 2462 char * 2463 di_prom_prop_name(di_prom_prop_t prom_prop) 2464 { 2465 /* 2466 * paranoid check 2467 */ 2468 if (prom_prop == DI_PROM_PROP_NIL) { 2469 errno = EINVAL; 2470 return (NULL); 2471 } 2472 2473 return (((struct di_prom_prop *)prom_prop)->name); 2474 } 2475 2476 int 2477 di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data) 2478 { 2479 /* 2480 * paranoid check 2481 */ 2482 if (prom_prop == DI_PROM_PROP_NIL) { 2483 errno = EINVAL; 2484 return (NULL); 2485 } 2486 2487 *prom_prop_data = ((struct di_prom_prop *)prom_prop)->data; 2488 2489 return (((struct di_prom_prop *)prom_prop)->len); 2490 } 2491 2492 /* 2493 * Internal library interface for locating the property 2494 * Returns length if found, -1 if prop doesn't exist. 2495 */ 2496 static struct di_prom_prop * 2497 di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node, 2498 const char *prom_prop_name) 2499 { 2500 struct openpromio *opp; 2501 struct di_prom_prop *prop; 2502 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2503 2504 /* 2505 * paranoid check 2506 */ 2507 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) { 2508 errno = EINVAL; 2509 return (NULL); 2510 } 2511 2512 if (di_nodeid(node) != DI_PROM_NODEID) { 2513 errno = ENXIO; 2514 return (NULL); 2515 } 2516 2517 opp = &p->oppbuf.opp; 2518 2519 (void) mutex_lock(&p->lock); 2520 2521 opp->oprom_size = sizeof (int); 2522 opp->oprom_node = DI_NODE(node)->nodeid; 2523 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) { 2524 errno = ENXIO; 2525 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", 2526 DI_NODE(node)->nodeid)); 2527 (void) mutex_unlock(&p->lock); 2528 return (NULL); 2529 } 2530 2531 /* 2532 * get property length 2533 */ 2534 bzero(opp, OBP_MAXBUF); 2535 opp->oprom_size = OBP_MAXPROPLEN; 2536 (void) strcpy(opp->oprom_array, prom_prop_name); 2537 2538 if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) || 2539 (opp->oprom_len == -1)) { 2540 /* no such property */ 2541 (void) mutex_unlock(&p->lock); 2542 return (NULL); 2543 } 2544 2545 /* 2546 * Prom property found. Allocate struct for storing prop 2547 */ 2548 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) { 2549 (void) mutex_unlock(&p->lock); 2550 return (NULL); 2551 } 2552 prop->name = NULL; /* we don't need the name */ 2553 prop->len = opp->oprom_len; 2554 2555 if (prop->len == 0) { /* boolean property */ 2556 prop->data = NULL; 2557 prop->next = p->list; 2558 p->list = prop; 2559 (void) mutex_unlock(&p->lock); 2560 return (prop); 2561 } 2562 2563 /* 2564 * retrieve the property value 2565 */ 2566 bzero(opp, OBP_MAXBUF); 2567 opp->oprom_size = OBP_MAXPROPLEN; 2568 (void) strcpy(opp->oprom_array, prom_prop_name); 2569 2570 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) || 2571 (opp->oprom_size == (uint_t)-1)) { 2572 /* error retrieving property value */ 2573 (void) mutex_unlock(&p->lock); 2574 free(prop); 2575 return (NULL); 2576 } 2577 2578 /* 2579 * make a copy of the property value, stick in ph->list 2580 */ 2581 if ((prop->data = malloc(prop->len)) == NULL) { 2582 (void) mutex_unlock(&p->lock); 2583 free(prop); 2584 return (NULL); 2585 } 2586 2587 bcopy(opp->oprom_array, prop->data, prop->len); 2588 2589 prop->next = p->list; 2590 p->list = prop; 2591 (void) mutex_unlock(&p->lock); 2592 2593 return (prop); 2594 } 2595 2596 int 2597 di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node, 2598 const char *prom_prop_name, int **prom_prop_data) 2599 { 2600 int len; 2601 struct di_prom_prop *prop; 2602 2603 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name); 2604 2605 if (prop == NULL) { 2606 *prom_prop_data = NULL; 2607 return (-1); 2608 } 2609 2610 if (prop->len == 0) { /* boolean property */ 2611 *prom_prop_data = NULL; 2612 return (0); 2613 } 2614 2615 len = di_prop_decode_common((void *)&prop->data, prop->len, 2616 DI_PROP_TYPE_INT, 1); 2617 *prom_prop_data = (int *)((void *)prop->data); 2618 2619 return (len); 2620 } 2621 2622 int 2623 di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node, 2624 const char *prom_prop_name, char **prom_prop_data) 2625 { 2626 int len; 2627 struct di_prom_prop *prop; 2628 2629 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name); 2630 2631 if (prop == NULL) { 2632 *prom_prop_data = NULL; 2633 return (-1); 2634 } 2635 2636 if (prop->len == 0) { /* boolean property */ 2637 *prom_prop_data = NULL; 2638 return (0); 2639 } 2640 2641 /* 2642 * Fix an openprom bug (OBP string not NULL terminated). 2643 * XXX This should really be fixed in promif. 2644 */ 2645 if (((char *)prop->data)[prop->len - 1] != '\0') { 2646 uchar_t *tmp; 2647 prop->len++; 2648 if ((tmp = realloc(prop->data, prop->len)) == NULL) 2649 return (-1); 2650 2651 prop->data = tmp; 2652 ((char *)prop->data)[prop->len - 1] = '\0'; 2653 DPRINTF((DI_INFO, "OBP string not NULL terminated: " 2654 "node=%s, prop=%s, val=%s\n", 2655 di_node_name(node), prom_prop_name, prop->data)); 2656 } 2657 2658 len = di_prop_decode_common((void *)&prop->data, prop->len, 2659 DI_PROP_TYPE_STRING, 1); 2660 *prom_prop_data = (char *)prop->data; 2661 2662 return (len); 2663 } 2664 2665 int 2666 di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node, 2667 const char *prom_prop_name, uchar_t **prom_prop_data) 2668 { 2669 int len; 2670 struct di_prom_prop *prop; 2671 2672 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name); 2673 2674 if (prop == NULL) { 2675 *prom_prop_data = NULL; 2676 return (-1); 2677 } 2678 2679 if (prop->len == 0) { /* boolean property */ 2680 *prom_prop_data = NULL; 2681 return (0); 2682 } 2683 2684 len = di_prop_decode_common((void *)&prop->data, prop->len, 2685 DI_PROP_TYPE_BYTE, 1); 2686 *prom_prop_data = prop->data; 2687 2688 return (len); 2689 } 2690 2691 di_lnode_t 2692 di_link_to_lnode(di_link_t link, uint_t endpoint) 2693 { 2694 struct di_all *di_all; 2695 2696 if ((link == DI_LINK_NIL) || 2697 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 2698 errno = EINVAL; 2699 return (DI_LNODE_NIL); 2700 } 2701 2702 di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self); 2703 2704 if (endpoint == DI_LINK_SRC) { 2705 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode)); 2706 } else { 2707 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode)); 2708 } 2709 /* NOTREACHED */ 2710 } 2711 2712 char * 2713 di_lnode_name(di_lnode_t lnode) 2714 { 2715 return (di_driver_name(di_lnode_devinfo(lnode))); 2716 } 2717 2718 di_node_t 2719 di_lnode_devinfo(di_lnode_t lnode) 2720 { 2721 struct di_all *di_all; 2722 2723 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self); 2724 return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node)); 2725 } 2726 2727 int 2728 di_lnode_devt(di_lnode_t lnode, dev_t *devt) 2729 { 2730 if ((lnode == DI_LNODE_NIL) || (devt == NULL)) { 2731 errno = EINVAL; 2732 return (-1); 2733 } 2734 if ((DI_LNODE(lnode)->dev_major == (major_t)-1) && 2735 (DI_LNODE(lnode)->dev_minor == (minor_t)-1)) 2736 return (-1); 2737 2738 *devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor); 2739 return (0); 2740 } 2741 2742 int 2743 di_link_spectype(di_link_t link) 2744 { 2745 return (DI_LINK(link)->spec_type); 2746 } 2747 2748 void 2749 di_minor_private_set(di_minor_t minor, void *data) 2750 { 2751 DI_MINOR(minor)->user_private_data = (uintptr_t)data; 2752 } 2753 2754 void * 2755 di_minor_private_get(di_minor_t minor) 2756 { 2757 return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data); 2758 } 2759 2760 void 2761 di_node_private_set(di_node_t node, void *data) 2762 { 2763 DI_NODE(node)->user_private_data = (uintptr_t)data; 2764 } 2765 2766 void * 2767 di_node_private_get(di_node_t node) 2768 { 2769 return ((void *)(uintptr_t)DI_NODE(node)->user_private_data); 2770 } 2771 2772 void 2773 di_lnode_private_set(di_lnode_t lnode, void *data) 2774 { 2775 DI_LNODE(lnode)->user_private_data = (uintptr_t)data; 2776 } 2777 2778 void * 2779 di_lnode_private_get(di_lnode_t lnode) 2780 { 2781 return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data); 2782 } 2783 2784 void 2785 di_link_private_set(di_link_t link, void *data) 2786 { 2787 DI_LINK(link)->user_private_data = (uintptr_t)data; 2788 } 2789 2790 void * 2791 di_link_private_get(di_link_t link) 2792 { 2793 return ((void *)(uintptr_t)DI_LINK(link)->user_private_data); 2794 } 2795 2796 di_lnode_t 2797 di_lnode_next(di_node_t node, di_lnode_t lnode) 2798 { 2799 struct di_all *di_all; 2800 2801 /* 2802 * paranoid error checking 2803 */ 2804 if (node == DI_NODE_NIL) { 2805 errno = EINVAL; 2806 return (DI_LNODE_NIL); 2807 } 2808 2809 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self); 2810 2811 if (lnode == DI_NODE_NIL) { 2812 if (DI_NODE(node)->lnodes != NULL) 2813 return (DI_LNODE((caddr_t)di_all + 2814 DI_NODE(node)->lnodes)); 2815 } else { 2816 if (DI_LNODE(lnode)->node_next != NULL) 2817 return (DI_LNODE((caddr_t)di_all + 2818 DI_LNODE(lnode)->node_next)); 2819 } 2820 2821 if (DINFOLYR & DI_ALL(di_all)->command) 2822 errno = ENXIO; 2823 else 2824 errno = ENOTSUP; 2825 2826 return (DI_LNODE_NIL); 2827 } 2828 2829 di_link_t 2830 di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint) 2831 { 2832 struct di_all *di_all; 2833 2834 /* 2835 * paranoid error checking 2836 */ 2837 if ((node == DI_NODE_NIL) || 2838 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 2839 errno = EINVAL; 2840 return (DI_LINK_NIL); 2841 } 2842 2843 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self); 2844 2845 if (endpoint == DI_LINK_SRC) { 2846 if (link == DI_LINK_NIL) { 2847 if (DI_NODE(node)->src_links != NULL) 2848 return (DI_LINK((caddr_t)di_all + 2849 DI_NODE(node)->src_links)); 2850 } else { 2851 if (DI_LINK(link)->src_node_next != NULL) 2852 return (DI_LINK((caddr_t)di_all + 2853 DI_LINK(link)->src_node_next)); 2854 } 2855 } else { 2856 if (link == DI_LINK_NIL) { 2857 if (DI_NODE(node)->tgt_links != NULL) 2858 return (DI_LINK((caddr_t)di_all + 2859 DI_NODE(node)->tgt_links)); 2860 } else { 2861 if (DI_LINK(link)->tgt_node_next != NULL) 2862 return (DI_LINK((caddr_t)di_all + 2863 DI_LINK(link)->tgt_node_next)); 2864 } 2865 } 2866 2867 if (DINFOLYR & DI_ALL(di_all)->command) 2868 errno = ENXIO; 2869 else 2870 errno = ENOTSUP; 2871 2872 return (DI_LINK_NIL); 2873 } 2874 2875 di_link_t 2876 di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint) 2877 { 2878 struct di_all *di_all; 2879 2880 /* 2881 * paranoid error checking 2882 */ 2883 if ((lnode == DI_LNODE_NIL) || 2884 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 2885 errno = EINVAL; 2886 return (DI_LINK_NIL); 2887 } 2888 2889 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self); 2890 2891 if (endpoint == DI_LINK_SRC) { 2892 if (link == DI_LINK_NIL) { 2893 if (DI_LNODE(lnode)->link_out == NULL) 2894 return (DI_LINK_NIL); 2895 return (DI_LINK((caddr_t)di_all + 2896 DI_LNODE(lnode)->link_out)); 2897 } else { 2898 if (DI_LINK(link)->src_link_next == NULL) 2899 return (DI_LINK_NIL); 2900 return (DI_LINK((caddr_t)di_all + 2901 DI_LINK(link)->src_link_next)); 2902 } 2903 } else { 2904 if (link == DI_LINK_NIL) { 2905 if (DI_LNODE(lnode)->link_in == NULL) 2906 return (DI_LINK_NIL); 2907 return (DI_LINK((caddr_t)di_all + 2908 DI_LNODE(lnode)->link_in)); 2909 } else { 2910 if (DI_LINK(link)->tgt_link_next == NULL) 2911 return (DI_LINK_NIL); 2912 return (DI_LINK((caddr_t)di_all + 2913 DI_LINK(link)->tgt_link_next)); 2914 } 2915 } 2916 /* NOTREACHED */ 2917 } 2918 2919 /* 2920 * Internal library function: 2921 * Invoke callback for each link data on the link list of first node 2922 * on node_list headp, and place children of first node on the list. 2923 * 2924 * This is similar to walk_one_node, except we only walk in child 2925 * first mode. 2926 */ 2927 static void 2928 walk_one_link(struct node_list **headp, uint_t ep, 2929 void *arg, int (*callback)(di_link_t link, void *arg)) 2930 { 2931 int action = DI_WALK_CONTINUE; 2932 di_link_t link = DI_LINK_NIL; 2933 di_node_t node = (*headp)->node; 2934 2935 while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) { 2936 action = callback(link, arg); 2937 if (action == DI_WALK_TERMINATE) { 2938 break; 2939 } 2940 } 2941 2942 update_node_list(action, DI_WALK_LINKGEN, headp); 2943 } 2944 2945 int 2946 di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg, 2947 int (*link_callback)(di_link_t link, void *arg)) 2948 { 2949 struct node_list *head; /* node_list for tree walk */ 2950 2951 #ifdef DEBUG 2952 char *path = di_devfs_path(root); 2953 DPRINTF((DI_INFO, "walking %s link data under %s\n", 2954 (endpoint == DI_LINK_SRC) ? "src" : "tgt", path)); 2955 di_devfs_path_free(path); 2956 #endif 2957 2958 /* 2959 * paranoid error checking 2960 */ 2961 if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) || 2962 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 2963 errno = EINVAL; 2964 return (-1); 2965 } 2966 2967 if ((head = malloc(sizeof (struct node_list))) == NULL) { 2968 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 2969 return (-1); 2970 } 2971 2972 head->next = NULL; 2973 head->node = root; 2974 2975 DPRINTF((DI_INFO, "Start link data walking from node %s\n", 2976 di_node_name(root))); 2977 2978 while (head != NULL) 2979 walk_one_link(&head, endpoint, arg, link_callback); 2980 2981 return (0); 2982 } 2983 2984 /* 2985 * Internal library function: 2986 * Invoke callback for each link data on the link list of first node 2987 * on node_list headp, and place children of first node on the list. 2988 * 2989 * This is similar to walk_one_node, except we only walk in child 2990 * first mode. 2991 */ 2992 static void 2993 walk_one_lnode(struct node_list **headp, void *arg, 2994 int (*callback)(di_lnode_t lnode, void *arg)) 2995 { 2996 int action = DI_WALK_CONTINUE; 2997 di_lnode_t lnode = DI_LNODE_NIL; 2998 di_node_t node = (*headp)->node; 2999 3000 while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) { 3001 action = callback(lnode, arg); 3002 if (action == DI_WALK_TERMINATE) { 3003 break; 3004 } 3005 } 3006 3007 update_node_list(action, DI_WALK_LINKGEN, headp); 3008 } 3009 3010 int 3011 di_walk_lnode(di_node_t root, uint_t flag, void *arg, 3012 int (*lnode_callback)(di_lnode_t lnode, void *arg)) 3013 { 3014 struct node_list *head; /* node_list for tree walk */ 3015 3016 #ifdef DEBUG 3017 char *path = di_devfs_path(root); 3018 DPRINTF((DI_INFO, "walking lnode data under %s\n", path)); 3019 di_devfs_path_free(path); 3020 #endif 3021 3022 /* 3023 * paranoid error checking 3024 */ 3025 if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) { 3026 errno = EINVAL; 3027 return (-1); 3028 } 3029 3030 if ((head = malloc(sizeof (struct node_list))) == NULL) { 3031 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 3032 return (-1); 3033 } 3034 3035 head->next = NULL; 3036 head->node = root; 3037 3038 DPRINTF((DI_INFO, "Start lnode data walking from node %s\n", 3039 di_node_name(root))); 3040 3041 while (head != NULL) 3042 walk_one_lnode(&head, arg, lnode_callback); 3043 3044 return (0); 3045 } 3046 3047 di_node_t 3048 di_lookup_node(di_node_t root, char *path) 3049 { 3050 struct di_all *dap; 3051 di_node_t node; 3052 char copy[MAXPATHLEN]; 3053 char *slash, *pname, *paddr; 3054 3055 /* 3056 * Path must be absolute and musn't have duplicate slashes 3057 */ 3058 if (*path != '/' || strstr(path, "//")) { 3059 DPRINTF((DI_ERR, "Invalid path: %s\n", path)); 3060 return (DI_NODE_NIL); 3061 } 3062 3063 if (root == DI_NODE_NIL) { 3064 DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n")); 3065 return (DI_NODE_NIL); 3066 } 3067 3068 dap = DI_ALL((caddr_t)root - DI_NODE(root)->self); 3069 if (strcmp(dap->root_path, "/") != 0) { 3070 DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path)); 3071 return (DI_NODE_NIL); 3072 } 3073 3074 if (strlcpy(copy, path, sizeof (copy)) >= sizeof (copy)) { 3075 DPRINTF((DI_ERR, "path too long: %s\n", path)); 3076 return (DI_NODE_NIL); 3077 } 3078 3079 for (slash = copy, node = root; slash; ) { 3080 3081 /* 3082 * Handle path = "/" case as well as trailing '/' 3083 */ 3084 if (*(slash + 1) == '\0') 3085 break; 3086 3087 /* 3088 * More path-components exist. Deal with the next one 3089 */ 3090 pname = slash + 1; 3091 node = di_child_node(node); 3092 3093 if (slash = strchr(pname, '/')) 3094 *slash = '\0'; 3095 if (paddr = strchr(pname, '@')) 3096 *paddr++ = '\0'; 3097 3098 for (; node != DI_NODE_NIL; node = di_sibling_node(node)) { 3099 char *name, *baddr; 3100 3101 name = di_node_name(node); 3102 baddr = di_bus_addr(node); 3103 3104 if (strcmp(pname, name) != 0) 3105 continue; 3106 3107 /* 3108 * Mappings between a "path-address" and bus-addr 3109 * 3110 * paddr baddr 3111 * --------------------- 3112 * NULL NULL 3113 * NULL "" 3114 * "" N/A (invalid paddr) 3115 */ 3116 if (paddr && baddr && strcmp(paddr, baddr) == 0) 3117 break; 3118 if (paddr == NULL && (baddr == NULL || *baddr == '\0')) 3119 break; 3120 } 3121 3122 /* 3123 * No nodes in the sibling list or there was no match 3124 */ 3125 if (node == DI_NODE_NIL) { 3126 DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr)); 3127 return (DI_NODE_NIL); 3128 } 3129 } 3130 3131 assert(node != DI_NODE_NIL); 3132 return (node); 3133 } 3134 3135 static char * 3136 msglevel2str(di_debug_t msglevel) 3137 { 3138 switch (msglevel) { 3139 case DI_ERR: 3140 return ("ERROR"); 3141 case DI_INFO: 3142 return ("Info"); 3143 case DI_TRACE: 3144 return ("Trace"); 3145 case DI_TRACE1: 3146 return ("Trace1"); 3147 case DI_TRACE2: 3148 return ("Trace2"); 3149 default: 3150 return ("UNKNOWN"); 3151 } 3152 } 3153 3154 void 3155 dprint(di_debug_t msglevel, const char *fmt, ...) 3156 { 3157 va_list ap; 3158 char *estr; 3159 3160 if (di_debug <= DI_QUIET) 3161 return; 3162 3163 if (di_debug < msglevel) 3164 return; 3165 3166 estr = msglevel2str(msglevel); 3167 3168 assert(estr); 3169 3170 va_start(ap, fmt); 3171 3172 (void) fprintf(stderr, "libdevinfo[%lu]: %s: ", 3173 (ulong_t)getpid(), estr); 3174 (void) vfprintf(stderr, fmt, ap); 3175 3176 va_end(ap); 3177 } 3178 3179 /* end of devinfo.c */ 3180