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