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