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