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