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