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