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