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_DEVICE_DEGRADED) 982 result |= DI_DEVICE_DEGRADED; 983 if (DI_NODE(node)->state & DEVI_BUS_QUIESCED) 984 result |= DI_BUS_QUIESCED; 985 if (DI_NODE(node)->state & DEVI_BUS_DOWN) 986 result |= DI_BUS_DOWN; 987 988 return (result); 989 } 990 991 ddi_node_state_t 992 di_node_state(di_node_t node) 993 { 994 return (DI_NODE(node)->node_state); 995 } 996 997 uint_t 998 di_flags(di_node_t node) 999 { 1000 return (DI_NODE(node)->flags); 1001 } 1002 1003 uint_t 1004 di_retired(di_node_t node) 1005 { 1006 return (di_flags(node) & DEVI_RETIRED); 1007 } 1008 1009 ddi_devid_t 1010 di_devid(di_node_t node) 1011 { 1012 if (DI_NODE(node)->devid == 0) 1013 return (NULL); 1014 1015 return ((ddi_devid_t)((caddr_t)node + 1016 DI_NODE(node)->devid - DI_NODE(node)->self)); 1017 } 1018 1019 int 1020 di_driver_major(di_node_t node) 1021 { 1022 int major; 1023 1024 major = DI_NODE(node)->drv_major; 1025 if (major < 0) 1026 return (-1); 1027 return (major); 1028 } 1029 1030 char * 1031 di_driver_name(di_node_t node) 1032 { 1033 int major; 1034 caddr_t pa; 1035 struct di_devnm *devnm; 1036 1037 major = DI_NODE(node)->drv_major; 1038 if (major < 0) 1039 return (NULL); 1040 1041 pa = (caddr_t)node - DI_NODE(node)->self; 1042 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames); 1043 1044 if (devnm[major].name) 1045 return (pa + devnm[major].name); 1046 else 1047 return (NULL); 1048 } 1049 1050 uint_t 1051 di_driver_ops(di_node_t node) 1052 { 1053 int major; 1054 caddr_t pa; 1055 struct di_devnm *devnm; 1056 1057 major = DI_NODE(node)->drv_major; 1058 if (major < 0) 1059 return (0); 1060 1061 pa = (caddr_t)node - DI_NODE(node)->self; 1062 devnm = DI_DEVNM(pa + DI_ALL(pa)->devnames); 1063 1064 return (devnm[major].ops); 1065 } 1066 1067 /* 1068 * returns the length of the path, caller must free memory 1069 */ 1070 char * 1071 di_devfs_path(di_node_t node) 1072 { 1073 caddr_t pa; 1074 di_node_t parent; 1075 int depth = 0, len = 0; 1076 char *buf, *name[MAX_TREE_DEPTH], *addr[MAX_TREE_DEPTH]; 1077 1078 if (node == DI_NODE_NIL) { 1079 errno = EINVAL; 1080 return (NULL); 1081 } 1082 1083 /* 1084 * trace back to root, note the node_name & address 1085 */ 1086 while ((parent = di_parent_node(node)) != DI_NODE_NIL) { 1087 name[depth] = di_node_name(node); 1088 len += strlen(name[depth]) + 1; /* 1 for '/' */ 1089 1090 if ((addr[depth] = di_bus_addr(node)) != NULL) 1091 len += strlen(addr[depth]) + 1; /* 1 for '@' */ 1092 1093 node = parent; 1094 depth++; 1095 } 1096 1097 /* 1098 * get the path to the root of snapshot 1099 */ 1100 pa = (caddr_t)node - DI_NODE(node)->self; 1101 name[depth] = DI_ALL(pa)->root_path; 1102 len += strlen(name[depth]) + 1; 1103 1104 /* 1105 * allocate buffer and assemble path 1106 */ 1107 if ((buf = malloc(len)) == NULL) { 1108 return (NULL); 1109 } 1110 1111 (void) strcpy(buf, name[depth]); 1112 len = strlen(buf); 1113 if (buf[len - 1] == '/') 1114 len--; /* delete trailing '/' */ 1115 1116 while (depth) { 1117 depth--; 1118 buf[len] = '/'; 1119 (void) strcpy(buf + len + 1, name[depth]); 1120 len += strlen(name[depth]) + 1; 1121 if (addr[depth] && addr[depth][0] != '\0') { 1122 buf[len] = '@'; 1123 (void) strcpy(buf + len + 1, addr[depth]); 1124 len += strlen(addr[depth]) + 1; 1125 } 1126 } 1127 1128 return (buf); 1129 } 1130 1131 char * 1132 di_devfs_minor_path(di_minor_t minor) 1133 { 1134 di_node_t node; 1135 char *full_path, *name, *devfspath; 1136 int full_path_len; 1137 1138 if (minor == DI_MINOR_NIL) { 1139 errno = EINVAL; 1140 return (NULL); 1141 } 1142 1143 name = di_minor_name(minor); 1144 node = di_minor_devinfo(minor); 1145 devfspath = di_devfs_path(node); 1146 if (devfspath == NULL) 1147 return (NULL); 1148 1149 /* make the full path to the device minor node */ 1150 full_path_len = strlen(devfspath) + strlen(name) + 2; 1151 full_path = (char *)calloc(1, full_path_len); 1152 if (full_path != NULL) 1153 (void) snprintf(full_path, full_path_len, "%s:%s", 1154 devfspath, name); 1155 1156 di_devfs_path_free(devfspath); 1157 return (full_path); 1158 } 1159 1160 /* 1161 * Produce a string representation of path to di_path_t (pathinfo node). This 1162 * string is identical to di_devfs_path had the device been enumerated under 1163 * the pHCI: it has a base path to pHCI, then uses node_name of client, and 1164 * device unit-address of pathinfo node. 1165 */ 1166 char * 1167 di_path_devfs_path(di_path_t path) 1168 { 1169 di_node_t phci_node; 1170 char *phci_path, *path_name, *path_addr; 1171 char *full_path; 1172 int full_path_len; 1173 1174 if (path == DI_PATH_NIL) { 1175 errno = EINVAL; 1176 return (NULL); 1177 } 1178 1179 /* get name@addr for path */ 1180 path_name = di_path_node_name(path); 1181 path_addr = di_path_bus_addr(path); 1182 if ((path_name == NULL) || (path_addr == NULL)) 1183 return (NULL); 1184 1185 /* base path to pHCI devinfo node */ 1186 phci_node = di_path_phci_node(path); 1187 if (phci_node == NULL) 1188 return (NULL); 1189 phci_path = di_devfs_path(phci_node); 1190 if (phci_path == NULL) 1191 return (NULL); 1192 1193 /* make the full string representation of path */ 1194 full_path_len = strlen(phci_path) + 1 + strlen(path_name) + 1195 1 + strlen(path_addr) + 1; 1196 full_path = (char *)calloc(1, full_path_len); 1197 1198 if (full_path != NULL) 1199 (void) snprintf(full_path, full_path_len, "%s/%s@%s", 1200 phci_path, path_name, path_addr); 1201 di_devfs_path_free(phci_path); 1202 return (full_path); 1203 } 1204 1205 char * 1206 di_path_client_devfs_path(di_path_t path) 1207 { 1208 return (di_devfs_path(di_path_client_node(path))); 1209 } 1210 1211 void 1212 di_devfs_path_free(char *buf) 1213 { 1214 if (buf == NULL) { 1215 DPRINTF((DI_ERR, "di_devfs_path_free NULL arg!\n")); 1216 return; 1217 } 1218 1219 free(buf); 1220 } 1221 1222 /* 1223 * Return 1 if name is a IEEE-1275 generic name. If new generic 1224 * names are defined, they should be added to this table 1225 */ 1226 static int 1227 is_generic(const char *name, int len) 1228 { 1229 const char **gp; 1230 1231 /* from IEEE-1275 recommended practices section 3 */ 1232 static const char *generic_names[] = { 1233 "atm", 1234 "disk", 1235 "display", 1236 "dma-controller", 1237 "ethernet", 1238 "fcs", 1239 "fdc", 1240 "fddi", 1241 "fibre-channel", 1242 "ide", 1243 "interrupt-controller", 1244 "isa", 1245 "keyboard", 1246 "memory", 1247 "mouse", 1248 "nvram", 1249 "pc-card", 1250 "pci", 1251 "printer", 1252 "rtc", 1253 "sbus", 1254 "scanner", 1255 "scsi", 1256 "serial", 1257 "sound", 1258 "ssa", 1259 "tape", 1260 "timer", 1261 "token-ring", 1262 "vme", 1263 0 1264 }; 1265 1266 for (gp = generic_names; *gp; gp++) { 1267 if ((strncmp(*gp, name, len) == 0) && 1268 (strlen(*gp) == len)) 1269 return (1); 1270 } 1271 return (0); 1272 } 1273 1274 /* 1275 * Determine if two paths below /devices refer to the same device, ignoring 1276 * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*". 1277 * Return 1 if the paths match. 1278 */ 1279 int 1280 di_devfs_path_match(const char *dp1, const char *dp2) 1281 { 1282 const char *p1, *p2; 1283 const char *ec1, *ec2; 1284 const char *at1, *at2; 1285 char nc; 1286 int g1, g2; 1287 1288 /* progress through both strings */ 1289 for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) { 1290 /* require match until the start of a component */ 1291 if (*p1 != '/') 1292 continue; 1293 1294 /* advance p1 and p2 to start of 'name' in component */ 1295 nc = *(p1 + 1); 1296 if ((nc == '\0') || (nc == '/')) 1297 continue; /* skip trash */ 1298 p1++; 1299 p2++; 1300 1301 /* 1302 * Both p1 and p2 point to beginning of 'name' in component. 1303 * Determine where current component ends: next '/' or '\0'. 1304 */ 1305 ec1 = strchr(p1, '/'); 1306 if (ec1 == NULL) 1307 ec1 = p1 + strlen(p1); 1308 ec2 = strchr(p2, '/'); 1309 if (ec2 == NULL) 1310 ec2 = p2 + strlen(p2); 1311 1312 /* Determine where name ends based on whether '@' exists */ 1313 at1 = strchr(p1, '@'); 1314 at2 = strchr(p2, '@'); 1315 if (at1 && (at1 < ec1)) 1316 ec1 = at1; 1317 if (at2 && (at2 < ec2)) 1318 ec2 = at2; 1319 1320 /* 1321 * At this point p[12] point to beginning of name and 1322 * ec[12] point to character past the end of name. Determine 1323 * if the names are generic. 1324 */ 1325 g1 = is_generic(p1, ec1 - p1); 1326 g2 = is_generic(p2, ec2 - p2); 1327 1328 if (g1 != g2) { 1329 /* 1330 * one generic and one non-generic 1331 * skip past the names in the match. 1332 */ 1333 p1 = ec1; 1334 p2 = ec2; 1335 } else { 1336 if (*p1 != *p2) 1337 break; 1338 } 1339 } 1340 1341 return ((*p1 == *p2) ? 1 : 0); 1342 } 1343 1344 /* minor data access */ 1345 di_minor_t 1346 di_minor_next(di_node_t node, di_minor_t minor) 1347 { 1348 caddr_t pa; 1349 1350 /* 1351 * paranoid error checking 1352 */ 1353 if (node == DI_NODE_NIL) { 1354 errno = EINVAL; 1355 return (DI_MINOR_NIL); 1356 } 1357 1358 /* 1359 * minor is not NIL 1360 */ 1361 if (minor != DI_MINOR_NIL) { 1362 if (DI_MINOR(minor)->next != 0) 1363 return ((di_minor_t)((void *)((caddr_t)minor - 1364 DI_MINOR(minor)->self + DI_MINOR(minor)->next))); 1365 else { 1366 errno = ENXIO; 1367 return (DI_MINOR_NIL); 1368 } 1369 } 1370 1371 /* 1372 * minor is NIL-->caller asks for first minor node 1373 */ 1374 if (DI_NODE(node)->minor_data != 0) { 1375 return (DI_MINOR((caddr_t)node - DI_NODE(node)->self + 1376 DI_NODE(node)->minor_data)); 1377 } 1378 1379 /* 1380 * no minor data-->check if snapshot includes minor data 1381 * in order to set the correct errno 1382 */ 1383 pa = (caddr_t)node - DI_NODE(node)->self; 1384 if (DINFOMINOR & DI_ALL(pa)->command) 1385 errno = ENXIO; 1386 else 1387 errno = ENOTSUP; 1388 1389 return (DI_MINOR_NIL); 1390 } 1391 1392 /* private interface for dealing with alias minor link generation */ 1393 di_node_t 1394 di_minor_devinfo(di_minor_t minor) 1395 { 1396 if (minor == DI_MINOR_NIL) { 1397 errno = EINVAL; 1398 return (DI_NODE_NIL); 1399 } 1400 1401 return (DI_NODE((caddr_t)minor - DI_MINOR(minor)->self + 1402 DI_MINOR(minor)->node)); 1403 } 1404 1405 ddi_minor_type 1406 di_minor_type(di_minor_t minor) 1407 { 1408 return (DI_MINOR(minor)->type); 1409 } 1410 1411 char * 1412 di_minor_name(di_minor_t minor) 1413 { 1414 if (DI_MINOR(minor)->name == 0) 1415 return (NULL); 1416 1417 return ((caddr_t)minor - DI_MINOR(minor)->self + DI_MINOR(minor)->name); 1418 } 1419 1420 dev_t 1421 di_minor_devt(di_minor_t minor) 1422 { 1423 return (makedev(DI_MINOR(minor)->dev_major, 1424 DI_MINOR(minor)->dev_minor)); 1425 } 1426 1427 int 1428 di_minor_spectype(di_minor_t minor) 1429 { 1430 return (DI_MINOR(minor)->spec_type); 1431 } 1432 1433 char * 1434 di_minor_nodetype(di_minor_t minor) 1435 { 1436 if (DI_MINOR(minor)->node_type == 0) 1437 return (NULL); 1438 1439 return ((caddr_t)minor - 1440 DI_MINOR(minor)->self + DI_MINOR(minor)->node_type); 1441 } 1442 1443 /* 1444 * Single public interface for accessing software properties 1445 */ 1446 di_prop_t 1447 di_prop_next(di_node_t node, di_prop_t prop) 1448 { 1449 int list = DI_PROP_DRV_LIST; 1450 1451 /* 1452 * paranoid check 1453 */ 1454 if (node == DI_NODE_NIL) { 1455 errno = EINVAL; 1456 return (DI_PROP_NIL); 1457 } 1458 1459 /* 1460 * Find which prop list we are at 1461 */ 1462 if (prop != DI_PROP_NIL) 1463 list = DI_PROP(prop)->prop_list; 1464 1465 do { 1466 switch (list++) { 1467 case DI_PROP_DRV_LIST: 1468 prop = di_prop_drv_next(node, prop); 1469 break; 1470 case DI_PROP_SYS_LIST: 1471 prop = di_prop_sys_next(node, prop); 1472 break; 1473 case DI_PROP_GLB_LIST: 1474 prop = di_prop_global_next(node, prop); 1475 break; 1476 case DI_PROP_HW_LIST: 1477 prop = di_prop_hw_next(node, prop); 1478 break; 1479 default: /* shouldn't happen */ 1480 errno = EFAULT; 1481 return (DI_PROP_NIL); 1482 } 1483 } while ((prop == DI_PROP_NIL) && (list <= DI_PROP_HW_LIST)); 1484 1485 return (prop); 1486 } 1487 1488 dev_t 1489 di_prop_devt(di_prop_t prop) 1490 { 1491 return (makedev(DI_PROP(prop)->dev_major, DI_PROP(prop)->dev_minor)); 1492 } 1493 1494 char * 1495 di_prop_name(di_prop_t prop) 1496 { 1497 if (DI_PROP(prop)->prop_name == 0) 1498 return (NULL); 1499 1500 return ((caddr_t)prop - DI_PROP(prop)->self + DI_PROP(prop)->prop_name); 1501 } 1502 1503 int 1504 di_prop_type(di_prop_t prop) 1505 { 1506 uint_t flags = DI_PROP(prop)->prop_flags; 1507 1508 if (flags & DDI_PROP_UNDEF_IT) 1509 return (DI_PROP_TYPE_UNDEF_IT); 1510 1511 if (DI_PROP(prop)->prop_len == 0) 1512 return (DI_PROP_TYPE_BOOLEAN); 1513 1514 if ((flags & DDI_PROP_TYPE_MASK) == DDI_PROP_TYPE_ANY) 1515 return (DI_PROP_TYPE_UNKNOWN); 1516 1517 if (flags & DDI_PROP_TYPE_INT) 1518 return (DI_PROP_TYPE_INT); 1519 1520 if (flags & DDI_PROP_TYPE_INT64) 1521 return (DI_PROP_TYPE_INT64); 1522 1523 if (flags & DDI_PROP_TYPE_STRING) 1524 return (DI_PROP_TYPE_STRING); 1525 1526 if (flags & DDI_PROP_TYPE_BYTE) 1527 return (DI_PROP_TYPE_BYTE); 1528 1529 /* 1530 * Shouldn't get here. In case we do, return unknown type. 1531 * 1532 * XXX--When DDI_PROP_TYPE_COMPOSITE is implemented, we need 1533 * to add DI_PROP_TYPE_COMPOSITE. 1534 */ 1535 DPRINTF((DI_ERR, "Unimplemented property type: 0x%x\n", flags)); 1536 1537 return (DI_PROP_TYPE_UNKNOWN); 1538 } 1539 1540 /* 1541 * Extract type-specific values of an property 1542 */ 1543 extern int di_prop_decode_common(void *prop_data, int len, 1544 int ddi_type, int prom); 1545 1546 int 1547 di_prop_ints(di_prop_t prop, int **prop_data) 1548 { 1549 if (DI_PROP(prop)->prop_len == 0) 1550 return (0); /* boolean property */ 1551 1552 if ((DI_PROP(prop)->prop_data == 0) || 1553 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1554 errno = EFAULT; 1555 *prop_data = NULL; 1556 return (-1); 1557 } 1558 1559 *prop_data = (int *)((void *)((caddr_t)prop - DI_PROP(prop)->self 1560 + DI_PROP(prop)->prop_data)); 1561 1562 return (di_prop_decode_common((void *)prop_data, 1563 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT, 0)); 1564 } 1565 1566 int 1567 di_prop_int64(di_prop_t prop, int64_t **prop_data) 1568 { 1569 if (DI_PROP(prop)->prop_len == 0) 1570 return (0); /* boolean property */ 1571 1572 if ((DI_PROP(prop)->prop_data == 0) || 1573 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1574 errno = EFAULT; 1575 *prop_data = NULL; 1576 return (-1); 1577 } 1578 1579 *prop_data = (int64_t *)((void *)((caddr_t)prop - DI_PROP(prop)->self 1580 + DI_PROP(prop)->prop_data)); 1581 1582 return (di_prop_decode_common((void *)prop_data, 1583 DI_PROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0)); 1584 } 1585 1586 int 1587 di_prop_strings(di_prop_t prop, char **prop_data) 1588 { 1589 if (DI_PROP(prop)->prop_len == 0) 1590 return (0); /* boolean property */ 1591 1592 if ((DI_PROP(prop)->prop_data == 0) || 1593 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1594 errno = EFAULT; 1595 *prop_data = NULL; 1596 return (-1); 1597 } 1598 1599 *prop_data = (char *)((caddr_t)prop - DI_PROP(prop)->self 1600 + DI_PROP(prop)->prop_data); 1601 1602 return (di_prop_decode_common((void *)prop_data, 1603 DI_PROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0)); 1604 } 1605 1606 int 1607 di_prop_bytes(di_prop_t prop, uchar_t **prop_data) 1608 { 1609 if (DI_PROP(prop)->prop_len == 0) 1610 return (0); /* boolean property */ 1611 1612 if ((DI_PROP(prop)->prop_data == 0) || 1613 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1614 errno = EFAULT; 1615 *prop_data = NULL; 1616 return (-1); 1617 } 1618 1619 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self 1620 + DI_PROP(prop)->prop_data); 1621 1622 return (di_prop_decode_common((void *)prop_data, 1623 DI_PROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0)); 1624 } 1625 1626 /* 1627 * returns 1 for match, 0 for no match 1628 */ 1629 static int 1630 match_prop(di_prop_t prop, dev_t match_dev, const char *name, int type) 1631 { 1632 int prop_type; 1633 1634 #ifdef DEBUG 1635 if (di_prop_name(prop) == NULL) { 1636 DPRINTF((DI_ERR, "libdevinfo: property has no name!\n")); 1637 return (0); 1638 } 1639 #endif /* DEBUG */ 1640 1641 if (strcmp(name, di_prop_name(prop)) != 0) 1642 return (0); 1643 1644 if ((match_dev != DDI_DEV_T_ANY) && (di_prop_devt(prop) != match_dev)) 1645 return (0); 1646 1647 /* 1648 * XXX prop_type is different from DDI_*. See PSARC 1997/127. 1649 */ 1650 prop_type = di_prop_type(prop); 1651 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type) && 1652 (prop_type != DI_PROP_TYPE_BOOLEAN)) 1653 return (0); 1654 1655 return (1); 1656 } 1657 1658 static di_prop_t 1659 di_prop_search(dev_t match_dev, di_node_t node, const char *name, 1660 int type) 1661 { 1662 di_prop_t prop = DI_PROP_NIL; 1663 1664 /* 1665 * The check on match_dev follows ddi_prop_lookup_common(). 1666 * Other checks are libdevinfo specific implementation. 1667 */ 1668 if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) || 1669 (match_dev == DDI_DEV_T_NONE) || !DI_PROP_TYPE_VALID(type)) { 1670 errno = EINVAL; 1671 return (DI_PROP_NIL); 1672 } 1673 1674 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) { 1675 DPRINTF((DI_TRACE1, "match prop name %s, devt 0x%lx, type %d\n", 1676 di_prop_name(prop), di_prop_devt(prop), 1677 di_prop_type(prop))); 1678 if (match_prop(prop, match_dev, name, type)) 1679 return (prop); 1680 } 1681 1682 return (DI_PROP_NIL); 1683 } 1684 1685 di_prop_t 1686 di_prop_find(dev_t match_dev, di_node_t node, const char *name) 1687 { 1688 di_prop_t prop = DI_PROP_NIL; 1689 1690 if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) || 1691 (match_dev == DDI_DEV_T_NONE)) { 1692 errno = EINVAL; 1693 return (DI_PROP_NIL); 1694 } 1695 1696 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) { 1697 DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n", 1698 di_prop_name(prop), di_prop_devt(prop), 1699 di_prop_type(prop))); 1700 1701 if (strcmp(name, di_prop_name(prop)) == 0 && 1702 (match_dev == DDI_DEV_T_ANY || 1703 di_prop_devt(prop) == match_dev)) 1704 return (prop); 1705 } 1706 1707 return (DI_PROP_NIL); 1708 } 1709 1710 int 1711 di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name, 1712 int **prop_data) 1713 { 1714 di_prop_t prop; 1715 1716 if ((prop = di_prop_search(dev, node, prop_name, 1717 DI_PROP_TYPE_INT)) == DI_PROP_NIL) 1718 return (-1); 1719 1720 return (di_prop_ints(prop, (void *)prop_data)); 1721 } 1722 1723 int 1724 di_prop_lookup_int64(dev_t dev, di_node_t node, const char *prop_name, 1725 int64_t **prop_data) 1726 { 1727 di_prop_t prop; 1728 1729 if ((prop = di_prop_search(dev, node, prop_name, 1730 DI_PROP_TYPE_INT64)) == DI_PROP_NIL) 1731 return (-1); 1732 1733 return (di_prop_int64(prop, (void *)prop_data)); 1734 } 1735 1736 int 1737 di_prop_lookup_strings(dev_t dev, di_node_t node, const char *prop_name, 1738 char **prop_data) 1739 { 1740 di_prop_t prop; 1741 1742 if ((prop = di_prop_search(dev, node, prop_name, 1743 DI_PROP_TYPE_STRING)) == DI_PROP_NIL) 1744 return (-1); 1745 1746 return (di_prop_strings(prop, (void *)prop_data)); 1747 } 1748 1749 int 1750 di_prop_lookup_bytes(dev_t dev, di_node_t node, const char *prop_name, 1751 uchar_t **prop_data) 1752 { 1753 di_prop_t prop; 1754 1755 if ((prop = di_prop_search(dev, node, prop_name, 1756 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL) 1757 return (-1); 1758 1759 return (di_prop_bytes(prop, (void *)prop_data)); 1760 } 1761 1762 /* 1763 * Consolidation private property access functions 1764 */ 1765 enum prop_type { 1766 PROP_TYPE_DRV, 1767 PROP_TYPE_SYS, 1768 PROP_TYPE_GLOB, 1769 PROP_TYPE_HW 1770 }; 1771 1772 static di_prop_t 1773 di_prop_next_common(di_node_t node, di_prop_t prop, int prop_type) 1774 { 1775 caddr_t pa; 1776 di_off_t prop_off = 0; 1777 1778 if (prop != DI_PROP_NIL) { 1779 if (DI_PROP(prop)->next) { 1780 return (DI_PROP((caddr_t)prop - 1781 DI_PROP(prop)->self + DI_PROP(prop)->next)); 1782 } else { 1783 return (DI_PROP_NIL); 1784 } 1785 } 1786 1787 1788 /* 1789 * prop is NIL, caller asks for first property 1790 */ 1791 pa = (caddr_t)node - DI_NODE(node)->self; 1792 switch (prop_type) { 1793 case PROP_TYPE_DRV: 1794 prop_off = DI_NODE(node)->drv_prop; 1795 break; 1796 case PROP_TYPE_SYS: 1797 prop_off = DI_NODE(node)->sys_prop; 1798 break; 1799 case PROP_TYPE_HW: 1800 prop_off = DI_NODE(node)->hw_prop; 1801 break; 1802 case PROP_TYPE_GLOB: 1803 prop_off = DI_NODE(node)->glob_prop; 1804 if (prop_off == -1) { 1805 /* no global property */ 1806 prop_off = 0; 1807 } else if ((prop_off == 0) && (DI_NODE(node)->drv_major >= 0)) { 1808 /* refer to devnames array */ 1809 struct di_devnm *devnm = DI_DEVNM(pa + 1810 DI_ALL(pa)->devnames + (DI_NODE(node)->drv_major * 1811 sizeof (struct di_devnm))); 1812 prop_off = devnm->global_prop; 1813 } 1814 break; 1815 } 1816 1817 if (prop_off) { 1818 return (DI_PROP(pa + prop_off)); 1819 } 1820 1821 /* 1822 * no prop found. Check the reason for not found 1823 */ 1824 if (DINFOPROP & DI_ALL(pa)->command) 1825 errno = ENXIO; 1826 else 1827 errno = ENOTSUP; 1828 1829 return (DI_PROP_NIL); 1830 } 1831 1832 di_prop_t 1833 di_prop_drv_next(di_node_t node, di_prop_t prop) 1834 { 1835 return (di_prop_next_common(node, prop, PROP_TYPE_DRV)); 1836 } 1837 1838 di_prop_t 1839 di_prop_sys_next(di_node_t node, di_prop_t prop) 1840 { 1841 return (di_prop_next_common(node, prop, PROP_TYPE_SYS)); 1842 } 1843 1844 di_prop_t 1845 di_prop_global_next(di_node_t node, di_prop_t prop) 1846 { 1847 return (di_prop_next_common(node, prop, PROP_TYPE_GLOB)); 1848 } 1849 1850 di_prop_t 1851 di_prop_hw_next(di_node_t node, di_prop_t prop) 1852 { 1853 return (di_prop_next_common(node, prop, PROP_TYPE_HW)); 1854 } 1855 1856 int 1857 di_prop_rawdata(di_prop_t prop, uchar_t **prop_data) 1858 { 1859 #ifdef DEBUG 1860 if (prop == DI_PROP_NIL) { 1861 errno = EINVAL; 1862 return (-1); 1863 } 1864 #endif /* DEBUG */ 1865 1866 if (DI_PROP(prop)->prop_len == 0) { 1867 *prop_data = NULL; 1868 return (0); 1869 } 1870 1871 if ((DI_PROP(prop)->prop_data == 0) || 1872 (DI_PROP(prop)->prop_data == (di_off_t)-1)) { 1873 errno = EFAULT; 1874 *prop_data = NULL; 1875 return (-1); 1876 } 1877 1878 /* 1879 * No memory allocation. 1880 */ 1881 *prop_data = (uchar_t *)((caddr_t)prop - DI_PROP(prop)->self + 1882 DI_PROP(prop)->prop_data); 1883 1884 return (DI_PROP(prop)->prop_len); 1885 } 1886 1887 /* 1888 * Consolidation private interfaces for accessing I/O multipathing data 1889 */ 1890 di_path_t 1891 di_path_phci_next_path(di_node_t node, di_path_t path) 1892 { 1893 caddr_t pa; 1894 1895 /* 1896 * path is not NIL 1897 */ 1898 if (path != DI_PATH_NIL) { 1899 if (DI_PATH(path)->path_p_link != 0) 1900 return (DI_PATH((void *)((caddr_t)path - 1901 DI_PATH(path)->self + DI_PATH(path)->path_p_link))); 1902 else { 1903 errno = ENXIO; 1904 return (DI_PATH_NIL); 1905 } 1906 } 1907 1908 /* 1909 * Path is NIL; the caller is asking for the first path info node 1910 */ 1911 if (DI_NODE(node)->multipath_phci != 0) { 1912 DPRINTF((DI_INFO, "phci_next_path: returning %p\n", 1913 ((caddr_t)node - 1914 DI_NODE(node)->self + DI_NODE(node)->multipath_phci))); 1915 return (DI_PATH((caddr_t)node - DI_NODE(node)->self + 1916 DI_NODE(node)->multipath_phci)); 1917 } 1918 1919 /* 1920 * No pathing data; check if the snapshot includes path data in order 1921 * to set errno properly. 1922 */ 1923 pa = (caddr_t)node - DI_NODE(node)->self; 1924 if (DINFOPATH & (DI_ALL(pa)->command)) 1925 errno = ENXIO; 1926 else 1927 errno = ENOTSUP; 1928 1929 return (DI_PATH_NIL); 1930 } 1931 1932 di_path_t 1933 di_path_client_next_path(di_node_t node, di_path_t path) 1934 { 1935 caddr_t pa; 1936 1937 /* 1938 * path is not NIL 1939 */ 1940 if (path != DI_PATH_NIL) { 1941 if (DI_PATH(path)->path_c_link != 0) 1942 return (DI_PATH((caddr_t)path - DI_PATH(path)->self 1943 + DI_PATH(path)->path_c_link)); 1944 else { 1945 errno = ENXIO; 1946 return (DI_PATH_NIL); 1947 } 1948 } 1949 1950 /* 1951 * Path is NIL; the caller is asking for the first path info node 1952 */ 1953 if (DI_NODE(node)->multipath_client != 0) { 1954 DPRINTF((DI_INFO, "client_next_path: returning %p\n", 1955 ((caddr_t)node - 1956 DI_NODE(node)->self + DI_NODE(node)->multipath_client))); 1957 return (DI_PATH((caddr_t)node - DI_NODE(node)->self + 1958 DI_NODE(node)->multipath_client)); 1959 } 1960 1961 /* 1962 * No pathing data; check if the snapshot includes path data in order 1963 * to set errno properly. 1964 */ 1965 pa = (caddr_t)node - DI_NODE(node)->self; 1966 if (DINFOPATH & (DI_ALL(pa)->command)) 1967 errno = ENXIO; 1968 else 1969 errno = ENOTSUP; 1970 1971 return (DI_PATH_NIL); 1972 } 1973 1974 /* 1975 * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces 1976 * below after NWS consolidation switches to using di_path_bus_addr, 1977 * di_path_phci_next_path, and di_path_client_next_path per CR6638521. 1978 */ 1979 char * 1980 di_path_addr(di_path_t path, char *buf) 1981 { 1982 caddr_t pa; /* starting address of map */ 1983 1984 pa = (caddr_t)path - DI_PATH(path)->self; 1985 1986 (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr), 1987 MAXPATHLEN); 1988 return (buf); 1989 } 1990 di_path_t 1991 di_path_next(di_node_t node, di_path_t path) 1992 { 1993 if (node == DI_NODE_NIL) { 1994 errno = EINVAL; 1995 return (DI_PATH_NIL); 1996 } 1997 1998 if (DI_NODE(node)->multipath_client) { 1999 return (di_path_client_next_path(node, path)); 2000 } else if (DI_NODE(node)->multipath_phci) { 2001 return (di_path_phci_next_path(node, path)); 2002 } else { 2003 /* 2004 * The node had multipathing data but didn't appear to be a 2005 * phci *or* a client; probably a programmer error. 2006 */ 2007 errno = EINVAL; 2008 return (DI_PATH_NIL); 2009 } 2010 } 2011 di_path_t 2012 di_path_next_phci(di_node_t node, di_path_t path) 2013 { 2014 return (di_path_client_next_path(node, path)); 2015 } 2016 di_path_t 2017 di_path_next_client(di_node_t node, di_path_t path) 2018 { 2019 return (di_path_phci_next_path(node, path)); 2020 } 2021 2022 2023 2024 2025 di_path_state_t 2026 di_path_state(di_path_t path) 2027 { 2028 return ((di_path_state_t)DI_PATH(path)->path_state); 2029 } 2030 2031 char * 2032 di_path_node_name(di_path_t path) 2033 { 2034 di_node_t client_node; 2035 2036 /* pathinfo gets node_name from client */ 2037 if ((client_node = di_path_client_node(path)) == NULL) 2038 return (NULL); 2039 return (di_node_name(client_node)); 2040 } 2041 2042 char * 2043 di_path_bus_addr(di_path_t path) 2044 { 2045 caddr_t pa = (caddr_t)path - DI_PATH(path)->self; 2046 2047 if (DI_PATH(path)->path_addr == 0) 2048 return (NULL); 2049 2050 return ((char *)(pa + DI_PATH(path)->path_addr)); 2051 } 2052 2053 int 2054 di_path_instance(di_path_t path) 2055 { 2056 return (DI_PATH(path)->path_instance); 2057 } 2058 2059 di_node_t 2060 di_path_client_node(di_path_t path) 2061 { 2062 caddr_t pa; /* starting address of map */ 2063 2064 if (path == DI_PATH_NIL) { 2065 errno = EINVAL; 2066 return (DI_PATH_NIL); 2067 } 2068 2069 DPRINTF((DI_TRACE, "Get client node for path %p\n", path)); 2070 2071 pa = (caddr_t)path - DI_PATH(path)->self; 2072 2073 if (DI_PATH(path)->path_client) { 2074 return (DI_NODE(pa + DI_PATH(path)->path_client)); 2075 } 2076 2077 /* 2078 * Deal with error condition: 2079 * If parent doesn't exist and node is not the root, 2080 * set errno to ENOTSUP. Otherwise, set errno to ENXIO. 2081 */ 2082 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOCLIENT) == 0) 2083 errno = ENOTSUP; 2084 else 2085 errno = ENXIO; 2086 2087 return (DI_NODE_NIL); 2088 } 2089 2090 di_node_t 2091 di_path_phci_node(di_path_t path) 2092 { 2093 caddr_t pa; /* starting address of map */ 2094 2095 if (path == DI_PATH_NIL) { 2096 errno = EINVAL; 2097 return (DI_PATH_NIL); 2098 } 2099 2100 DPRINTF((DI_TRACE, "Get phci node for path %p\n", path)); 2101 2102 pa = (caddr_t)path - DI_PATH(path)->self; 2103 2104 if (DI_PATH(path)->path_phci) { 2105 return (DI_NODE(pa + DI_PATH(path)->path_phci)); 2106 } 2107 2108 /* 2109 * Deal with error condition: 2110 * If parent doesn't exist and node is not the root, 2111 * set errno to ENOTSUP. Otherwise, set errno to ENXIO. 2112 */ 2113 if ((DI_PATH(path)->path_snap_state & DI_PATH_SNAP_NOPHCI) == 0) 2114 errno = ENOTSUP; 2115 else 2116 errno = ENXIO; 2117 2118 return (DI_NODE_NIL); 2119 } 2120 2121 di_path_prop_t 2122 di_path_prop_next(di_path_t path, di_path_prop_t prop) 2123 { 2124 caddr_t pa; 2125 2126 if (path == DI_PATH_NIL) { 2127 errno = EINVAL; 2128 return (DI_PROP_NIL); 2129 } 2130 2131 /* 2132 * prop is not NIL 2133 */ 2134 if (prop != DI_PROP_NIL) { 2135 if (DI_PROP(prop)->next != 0) 2136 return (DI_PATHPROP((caddr_t)prop - 2137 DI_PROP(prop)->self + DI_PROP(prop)->next)); 2138 else { 2139 errno = ENXIO; 2140 return (DI_PROP_NIL); 2141 } 2142 } 2143 2144 /* 2145 * prop is NIL-->caller asks for first property 2146 */ 2147 pa = (caddr_t)path - DI_PATH(path)->self; 2148 if (DI_PATH(path)->path_prop != 0) { 2149 return (DI_PATHPROP(pa + DI_PATH(path)->path_prop)); 2150 } 2151 2152 /* 2153 * no property data-->check if snapshot includes props 2154 * in order to set the correct errno 2155 */ 2156 if (DINFOPROP & (DI_ALL(pa)->command)) 2157 errno = ENXIO; 2158 else 2159 errno = ENOTSUP; 2160 2161 return (DI_PROP_NIL); 2162 } 2163 2164 char * 2165 di_path_prop_name(di_path_prop_t prop) 2166 { 2167 caddr_t pa; /* starting address of map */ 2168 pa = (caddr_t)prop - DI_PATHPROP(prop)->self; 2169 return ((char *)(pa + DI_PATHPROP(prop)->prop_name)); 2170 } 2171 2172 int 2173 di_path_prop_len(di_path_prop_t prop) 2174 { 2175 return (DI_PATHPROP(prop)->prop_len); 2176 } 2177 2178 int 2179 di_path_prop_type(di_path_prop_t prop) 2180 { 2181 switch (DI_PATHPROP(prop)->prop_type) { 2182 case DDI_PROP_TYPE_INT: 2183 return (DI_PROP_TYPE_INT); 2184 case DDI_PROP_TYPE_INT64: 2185 return (DI_PROP_TYPE_INT64); 2186 case DDI_PROP_TYPE_BYTE: 2187 return (DI_PROP_TYPE_BYTE); 2188 case DDI_PROP_TYPE_STRING: 2189 return (DI_PROP_TYPE_STRING); 2190 } 2191 return (DI_PROP_TYPE_UNKNOWN); 2192 } 2193 2194 int 2195 di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data) 2196 { 2197 if ((DI_PATHPROP(prop)->prop_data == 0) || 2198 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 2199 errno = EFAULT; 2200 *prop_data = NULL; 2201 return (-1); 2202 } 2203 2204 *prop_data = (uchar_t *)((caddr_t)prop - DI_PATHPROP(prop)->self 2205 + DI_PATHPROP(prop)->prop_data); 2206 2207 return (di_prop_decode_common((void *)prop_data, 2208 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_BYTE, 0)); 2209 } 2210 2211 int 2212 di_path_prop_ints(di_path_prop_t prop, int **prop_data) 2213 { 2214 if (DI_PATHPROP(prop)->prop_len == 0) 2215 return (0); 2216 2217 if ((DI_PATHPROP(prop)->prop_data == 0) || 2218 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 2219 errno = EFAULT; 2220 *prop_data = NULL; 2221 return (-1); 2222 } 2223 2224 *prop_data = (int *)((void *)((caddr_t)prop - DI_PATHPROP(prop)->self 2225 + DI_PATHPROP(prop)->prop_data)); 2226 2227 return (di_prop_decode_common((void *)prop_data, 2228 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT, 0)); 2229 } 2230 2231 int 2232 di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data) 2233 { 2234 if (DI_PATHPROP(prop)->prop_len == 0) 2235 return (0); 2236 2237 if ((DI_PATHPROP(prop)->prop_data == 0) || 2238 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 2239 errno = EFAULT; 2240 *prop_data = NULL; 2241 return (-1); 2242 } 2243 2244 *prop_data = (int64_t *)((void *)((caddr_t)prop - 2245 DI_PATHPROP(prop)->self + DI_PATHPROP(prop)->prop_data)); 2246 2247 return (di_prop_decode_common((void *)prop_data, 2248 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_INT64, 0)); 2249 } 2250 2251 int 2252 di_path_prop_strings(di_path_prop_t prop, char **prop_data) 2253 { 2254 if (DI_PATHPROP(prop)->prop_len == 0) 2255 return (0); 2256 2257 if ((DI_PATHPROP(prop)->prop_data == 0) || 2258 (DI_PATHPROP(prop)->prop_data == (di_off_t)-1)) { 2259 errno = EFAULT; 2260 *prop_data = NULL; 2261 return (-1); 2262 } 2263 2264 *prop_data = (char *)((caddr_t)prop - DI_PATHPROP(prop)->self 2265 + DI_PATHPROP(prop)->prop_data); 2266 2267 return (di_prop_decode_common((void *)prop_data, 2268 DI_PATHPROP(prop)->prop_len, DI_PROP_TYPE_STRING, 0)); 2269 } 2270 2271 static di_path_prop_t 2272 di_path_prop_search(di_path_t path, const char *name, int type) 2273 { 2274 di_path_prop_t prop = DI_PROP_NIL; 2275 2276 /* 2277 * Sanity check arguments 2278 */ 2279 if ((path == DI_PATH_NIL) || (name == NULL) || (strlen(name) == 0) || 2280 !DI_PROP_TYPE_VALID(type)) { 2281 errno = EINVAL; 2282 return (DI_PROP_NIL); 2283 } 2284 2285 while ((prop = di_path_prop_next(path, prop)) != DI_PROP_NIL) { 2286 int prop_type = di_path_prop_type(prop); 2287 2288 DPRINTF((DI_TRACE1, "match path prop name %s, type %d\n", 2289 di_path_prop_name(prop), prop_type)); 2290 2291 if (strcmp(name, di_path_prop_name(prop)) != 0) 2292 continue; 2293 2294 if ((prop_type != DI_PROP_TYPE_UNKNOWN) && (prop_type != type)) 2295 continue; 2296 2297 return (prop); 2298 } 2299 2300 return (DI_PROP_NIL); 2301 } 2302 2303 int 2304 di_path_prop_lookup_bytes(di_path_t path, const char *prop_name, 2305 uchar_t **prop_data) 2306 { 2307 di_path_prop_t prop; 2308 2309 if ((prop = di_path_prop_search(path, prop_name, 2310 DI_PROP_TYPE_BYTE)) == DI_PROP_NIL) 2311 return (-1); 2312 2313 return (di_path_prop_bytes(prop, prop_data)); 2314 } 2315 2316 int 2317 di_path_prop_lookup_ints(di_path_t path, const char *prop_name, 2318 int **prop_data) 2319 { 2320 di_path_prop_t prop; 2321 2322 if ((prop = di_path_prop_search(path, prop_name, 2323 DI_PROP_TYPE_INT)) == DI_PROP_NIL) 2324 return (-1); 2325 2326 return (di_path_prop_ints(prop, prop_data)); 2327 } 2328 2329 int 2330 di_path_prop_lookup_int64s(di_path_t path, const char *prop_name, 2331 int64_t **prop_data) 2332 { 2333 di_path_prop_t prop; 2334 2335 if ((prop = di_path_prop_search(path, prop_name, 2336 DI_PROP_TYPE_INT64)) == DI_PROP_NIL) 2337 return (-1); 2338 2339 return (di_path_prop_int64s(prop, prop_data)); 2340 } 2341 2342 int di_path_prop_lookup_strings(di_path_t path, const char *prop_name, 2343 char **prop_data) 2344 { 2345 di_path_prop_t prop; 2346 2347 if ((prop = di_path_prop_search(path, prop_name, 2348 DI_PROP_TYPE_STRING)) == DI_PROP_NIL) 2349 return (-1); 2350 2351 return (di_path_prop_strings(prop, prop_data)); 2352 } 2353 2354 /* 2355 * Consolidation private interfaces for traversing vhci nodes. 2356 */ 2357 di_node_t 2358 di_vhci_first_node(di_node_t root) 2359 { 2360 struct di_all *dap; 2361 caddr_t pa; /* starting address of map */ 2362 2363 DPRINTF((DI_INFO, "Get first vhci node\n")); 2364 2365 if (root == DI_NODE_NIL) { 2366 errno = EINVAL; 2367 return (DI_NODE_NIL); 2368 } 2369 2370 pa = (caddr_t)root - DI_NODE(root)->self; 2371 dap = DI_ALL(pa); 2372 2373 if (dap->top_vhci_devinfo == NULL) { 2374 errno = ENXIO; 2375 return (DI_NODE_NIL); 2376 } 2377 2378 return (DI_NODE(pa + dap->top_vhci_devinfo)); 2379 } 2380 2381 di_node_t 2382 di_vhci_next_node(di_node_t node) 2383 { 2384 caddr_t pa; /* starting address of map */ 2385 2386 if (node == DI_NODE_NIL) { 2387 errno = EINVAL; 2388 return (DI_NODE_NIL); 2389 } 2390 2391 DPRINTF((DI_TRACE, "next vhci node on the snap shot:" 2392 " current=%s\n", di_node_name(node))); 2393 2394 if (DI_NODE(node)->next_vhci == NULL) { 2395 errno = ENXIO; 2396 return (DI_NODE_NIL); 2397 } 2398 2399 pa = (caddr_t)node - DI_NODE(node)->self; 2400 2401 return (DI_NODE(pa + DI_NODE(node)->next_vhci)); 2402 } 2403 2404 /* 2405 * Consolidation private interfaces for traversing phci nodes. 2406 */ 2407 di_node_t 2408 di_phci_first_node(di_node_t vhci_node) 2409 { 2410 caddr_t pa; /* starting address of map */ 2411 2412 DPRINTF((DI_INFO, "Get first phci node:\n" 2413 " current=%s", di_node_name(vhci_node))); 2414 2415 if (vhci_node == DI_NODE_NIL) { 2416 errno = EINVAL; 2417 return (DI_NODE_NIL); 2418 } 2419 2420 pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self; 2421 2422 if (DI_NODE(vhci_node)->top_phci == NULL) { 2423 errno = ENXIO; 2424 return (DI_NODE_NIL); 2425 } 2426 2427 return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci)); 2428 } 2429 2430 di_node_t 2431 di_phci_next_node(di_node_t node) 2432 { 2433 caddr_t pa; /* starting address of map */ 2434 2435 if (node == DI_NODE_NIL) { 2436 errno = EINVAL; 2437 return (DI_NODE_NIL); 2438 } 2439 2440 DPRINTF((DI_TRACE, "next phci node on the snap shot:" 2441 " current=%s\n", di_node_name(node))); 2442 2443 if (DI_NODE(node)->next_phci == NULL) { 2444 errno = ENXIO; 2445 return (DI_NODE_NIL); 2446 } 2447 2448 pa = (caddr_t)node - DI_NODE(node)->self; 2449 2450 return (DI_NODE(pa + DI_NODE(node)->next_phci)); 2451 } 2452 2453 /* 2454 * Consolidation private interfaces for private data 2455 */ 2456 void * 2457 di_parent_private_data(di_node_t node) 2458 { 2459 caddr_t pa; 2460 2461 if (DI_NODE(node)->parent_data == 0) { 2462 errno = ENXIO; 2463 return (NULL); 2464 } 2465 2466 if (DI_NODE(node)->parent_data == (di_off_t)-1) { 2467 /* 2468 * Private data requested, but not obtained due to a memory 2469 * error (e.g. wrong format specified) 2470 */ 2471 errno = EFAULT; 2472 return (NULL); 2473 } 2474 2475 pa = (caddr_t)node - DI_NODE(node)->self; 2476 if (DI_NODE(node)->parent_data) 2477 return (pa + DI_NODE(node)->parent_data); 2478 2479 if (DI_ALL(pa)->command & DINFOPRIVDATA) 2480 errno = ENXIO; 2481 else 2482 errno = ENOTSUP; 2483 2484 return (NULL); 2485 } 2486 2487 void * 2488 di_driver_private_data(di_node_t node) 2489 { 2490 caddr_t pa; 2491 2492 if (DI_NODE(node)->driver_data == 0) { 2493 errno = ENXIO; 2494 return (NULL); 2495 } 2496 2497 if (DI_NODE(node)->driver_data == (di_off_t)-1) { 2498 /* 2499 * Private data requested, but not obtained due to a memory 2500 * error (e.g. wrong format specified) 2501 */ 2502 errno = EFAULT; 2503 return (NULL); 2504 } 2505 2506 pa = (caddr_t)node - DI_NODE(node)->self; 2507 if (DI_NODE(node)->driver_data) 2508 return (pa + DI_NODE(node)->driver_data); 2509 2510 if (DI_ALL(pa)->command & DINFOPRIVDATA) 2511 errno = ENXIO; 2512 else 2513 errno = ENOTSUP; 2514 2515 return (NULL); 2516 } 2517 2518 /* 2519 * PROM property access 2520 */ 2521 2522 /* 2523 * openprom driver stuff: 2524 * The maximum property length depends on the buffer size. We use 2525 * OPROMMAXPARAM defined in <sys/openpromio.h> 2526 * 2527 * MAXNAMESZ is max property name. obpdefs.h defines it as 32 based on 1275 2528 * MAXVALSZ is maximum value size, which is whatever space left in buf 2529 */ 2530 2531 #define OBP_MAXBUF OPROMMAXPARAM - sizeof (int) 2532 #define OBP_MAXPROPLEN OBP_MAXBUF - OBP_MAXPROPNAME; 2533 2534 struct di_prom_prop { 2535 char *name; 2536 int len; 2537 uchar_t *data; 2538 struct di_prom_prop *next; /* form a linked list */ 2539 }; 2540 2541 struct di_prom_handle { /* handle to prom */ 2542 mutex_t lock; /* synchronize access to openprom fd */ 2543 int fd; /* /dev/openprom file descriptor */ 2544 struct di_prom_prop *list; /* linked list of prop */ 2545 union { 2546 char buf[OPROMMAXPARAM]; 2547 struct openpromio opp; 2548 } oppbuf; 2549 }; 2550 2551 di_prom_handle_t 2552 di_prom_init() 2553 { 2554 struct di_prom_handle *p; 2555 2556 if ((p = malloc(sizeof (struct di_prom_handle))) == NULL) 2557 return (DI_PROM_HANDLE_NIL); 2558 2559 DPRINTF((DI_INFO, "di_prom_init: get prom handle 0x%p\n", p)); 2560 2561 (void) mutex_init(&p->lock, USYNC_THREAD, NULL); 2562 if ((p->fd = open("/dev/openprom", O_RDONLY)) < 0) { 2563 free(p); 2564 return (DI_PROM_HANDLE_NIL); 2565 } 2566 p->list = NULL; 2567 2568 return ((di_prom_handle_t)p); 2569 } 2570 2571 static void 2572 di_prom_prop_free(struct di_prom_prop *list) 2573 { 2574 struct di_prom_prop *tmp = list; 2575 2576 while (tmp != NULL) { 2577 list = tmp->next; 2578 if (tmp->name != NULL) { 2579 free(tmp->name); 2580 } 2581 if (tmp->data != NULL) { 2582 free(tmp->data); 2583 } 2584 free(tmp); 2585 tmp = list; 2586 } 2587 } 2588 2589 void 2590 di_prom_fini(di_prom_handle_t ph) 2591 { 2592 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2593 2594 DPRINTF((DI_INFO, "di_prom_fini: free prom handle 0x%p\n", p)); 2595 2596 (void) close(p->fd); 2597 (void) mutex_destroy(&p->lock); 2598 di_prom_prop_free(p->list); 2599 2600 free(p); 2601 } 2602 2603 /* 2604 * Internal library interface for locating the property 2605 * XXX: ph->lock must be held for the duration of call. 2606 */ 2607 static di_prom_prop_t 2608 di_prom_prop_found(di_prom_handle_t ph, int nodeid, 2609 di_prom_prop_t prom_prop) 2610 { 2611 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2612 struct openpromio *opp = &p->oppbuf.opp; 2613 int *ip = (int *)((void *)opp->oprom_array); 2614 struct di_prom_prop *prop = (struct di_prom_prop *)prom_prop; 2615 2616 DPRINTF((DI_TRACE1, "Looking for nodeid 0x%x\n", nodeid)); 2617 2618 /* 2619 * Set "current" nodeid in the openprom driver 2620 */ 2621 opp->oprom_size = sizeof (int); 2622 *ip = nodeid; 2623 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) { 2624 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", nodeid)); 2625 return (DI_PROM_PROP_NIL); 2626 } 2627 2628 DPRINTF((DI_TRACE, "Found nodeid 0x%x\n", nodeid)); 2629 2630 bzero(opp, OBP_MAXBUF); 2631 opp->oprom_size = OBP_MAXPROPNAME; 2632 if (prom_prop != DI_PROM_PROP_NIL) 2633 (void) strcpy(opp->oprom_array, prop->name); 2634 2635 if ((ioctl(p->fd, OPROMNXTPROP, opp) < 0) || (opp->oprom_size == 0)) 2636 return (DI_PROM_PROP_NIL); 2637 2638 /* 2639 * Prom property found. Allocate struct for storing prop 2640 * (reuse variable prop) 2641 */ 2642 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) 2643 return (DI_PROM_PROP_NIL); 2644 2645 /* 2646 * Get a copy of property name 2647 */ 2648 if ((prop->name = strdup(opp->oprom_array)) == NULL) { 2649 free(prop); 2650 return (DI_PROM_PROP_NIL); 2651 } 2652 2653 /* 2654 * get property value and length 2655 */ 2656 opp->oprom_size = OBP_MAXPROPLEN; 2657 2658 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) || 2659 (opp->oprom_size == (uint_t)-1)) { 2660 free(prop->name); 2661 free(prop); 2662 return (DI_PROM_PROP_NIL); 2663 } 2664 2665 /* 2666 * make a copy of the property value 2667 */ 2668 prop->len = opp->oprom_size; 2669 2670 if (prop->len == 0) 2671 prop->data = NULL; 2672 else if ((prop->data = malloc(prop->len)) == NULL) { 2673 free(prop->name); 2674 free(prop); 2675 return (DI_PROM_PROP_NIL); 2676 } 2677 2678 bcopy(opp->oprom_array, prop->data, prop->len); 2679 2680 /* 2681 * Prepend prop to list in prom handle 2682 */ 2683 prop->next = p->list; 2684 p->list = prop; 2685 2686 return ((di_prom_prop_t)prop); 2687 } 2688 2689 di_prom_prop_t 2690 di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop) 2691 { 2692 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2693 2694 DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n", 2695 node, p)); 2696 2697 /* 2698 * paranoid check 2699 */ 2700 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) { 2701 errno = EINVAL; 2702 return (DI_PROM_PROP_NIL); 2703 } 2704 2705 if (di_nodeid(node) != DI_PROM_NODEID) { 2706 errno = ENXIO; 2707 return (DI_PROM_PROP_NIL); 2708 } 2709 2710 /* 2711 * synchronize access to prom file descriptor 2712 */ 2713 (void) mutex_lock(&p->lock); 2714 2715 /* 2716 * look for next property 2717 */ 2718 prom_prop = di_prom_prop_found(ph, DI_NODE(node)->nodeid, prom_prop); 2719 2720 (void) mutex_unlock(&p->lock); 2721 2722 return (prom_prop); 2723 } 2724 2725 char * 2726 di_prom_prop_name(di_prom_prop_t prom_prop) 2727 { 2728 /* 2729 * paranoid check 2730 */ 2731 if (prom_prop == DI_PROM_PROP_NIL) { 2732 errno = EINVAL; 2733 return (NULL); 2734 } 2735 2736 return (((struct di_prom_prop *)prom_prop)->name); 2737 } 2738 2739 int 2740 di_prom_prop_data(di_prom_prop_t prom_prop, uchar_t **prom_prop_data) 2741 { 2742 /* 2743 * paranoid check 2744 */ 2745 if (prom_prop == DI_PROM_PROP_NIL) { 2746 errno = EINVAL; 2747 return (NULL); 2748 } 2749 2750 *prom_prop_data = ((struct di_prom_prop *)prom_prop)->data; 2751 2752 return (((struct di_prom_prop *)prom_prop)->len); 2753 } 2754 2755 /* 2756 * Internal library interface for locating the property 2757 * Returns length if found, -1 if prop doesn't exist. 2758 */ 2759 static struct di_prom_prop * 2760 di_prom_prop_lookup_common(di_prom_handle_t ph, di_node_t node, 2761 const char *prom_prop_name) 2762 { 2763 struct openpromio *opp; 2764 struct di_prom_prop *prop; 2765 struct di_prom_handle *p = (struct di_prom_handle *)ph; 2766 2767 /* 2768 * paranoid check 2769 */ 2770 if ((ph == DI_PROM_HANDLE_NIL) || (node == DI_NODE_NIL)) { 2771 errno = EINVAL; 2772 return (NULL); 2773 } 2774 2775 if (di_nodeid(node) != DI_PROM_NODEID) { 2776 errno = ENXIO; 2777 return (NULL); 2778 } 2779 2780 opp = &p->oppbuf.opp; 2781 2782 (void) mutex_lock(&p->lock); 2783 2784 opp->oprom_size = sizeof (int); 2785 opp->oprom_node = DI_NODE(node)->nodeid; 2786 if (ioctl(p->fd, OPROMSETNODEID, opp) < 0) { 2787 errno = ENXIO; 2788 DPRINTF((DI_ERR, "*** Nodeid not found 0x%x\n", 2789 DI_NODE(node)->nodeid)); 2790 (void) mutex_unlock(&p->lock); 2791 return (NULL); 2792 } 2793 2794 /* 2795 * get property length 2796 */ 2797 bzero(opp, OBP_MAXBUF); 2798 opp->oprom_size = OBP_MAXPROPLEN; 2799 (void) strcpy(opp->oprom_array, prom_prop_name); 2800 2801 if ((ioctl(p->fd, OPROMGETPROPLEN, opp) < 0) || 2802 (opp->oprom_len == -1)) { 2803 /* no such property */ 2804 (void) mutex_unlock(&p->lock); 2805 return (NULL); 2806 } 2807 2808 /* 2809 * Prom property found. Allocate struct for storing prop 2810 */ 2811 if ((prop = malloc(sizeof (struct di_prom_prop))) == NULL) { 2812 (void) mutex_unlock(&p->lock); 2813 return (NULL); 2814 } 2815 prop->name = NULL; /* we don't need the name */ 2816 prop->len = opp->oprom_len; 2817 2818 if (prop->len == 0) { /* boolean property */ 2819 prop->data = NULL; 2820 prop->next = p->list; 2821 p->list = prop; 2822 (void) mutex_unlock(&p->lock); 2823 return (prop); 2824 } 2825 2826 /* 2827 * retrieve the property value 2828 */ 2829 bzero(opp, OBP_MAXBUF); 2830 opp->oprom_size = OBP_MAXPROPLEN; 2831 (void) strcpy(opp->oprom_array, prom_prop_name); 2832 2833 if ((ioctl(p->fd, OPROMGETPROP, opp) < 0) || 2834 (opp->oprom_size == (uint_t)-1)) { 2835 /* error retrieving property value */ 2836 (void) mutex_unlock(&p->lock); 2837 free(prop); 2838 return (NULL); 2839 } 2840 2841 /* 2842 * make a copy of the property value, stick in ph->list 2843 */ 2844 if ((prop->data = malloc(prop->len)) == NULL) { 2845 (void) mutex_unlock(&p->lock); 2846 free(prop); 2847 return (NULL); 2848 } 2849 2850 bcopy(opp->oprom_array, prop->data, prop->len); 2851 2852 prop->next = p->list; 2853 p->list = prop; 2854 (void) mutex_unlock(&p->lock); 2855 2856 return (prop); 2857 } 2858 2859 int 2860 di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node, 2861 const char *prom_prop_name, int **prom_prop_data) 2862 { 2863 int len; 2864 struct di_prom_prop *prop; 2865 2866 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name); 2867 2868 if (prop == NULL) { 2869 *prom_prop_data = NULL; 2870 return (-1); 2871 } 2872 2873 if (prop->len == 0) { /* boolean property */ 2874 *prom_prop_data = NULL; 2875 return (0); 2876 } 2877 2878 len = di_prop_decode_common((void *)&prop->data, prop->len, 2879 DI_PROP_TYPE_INT, 1); 2880 *prom_prop_data = (int *)((void *)prop->data); 2881 2882 return (len); 2883 } 2884 2885 int 2886 di_prom_prop_lookup_strings(di_prom_handle_t ph, di_node_t node, 2887 const char *prom_prop_name, char **prom_prop_data) 2888 { 2889 int len; 2890 struct di_prom_prop *prop; 2891 2892 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name); 2893 2894 if (prop == NULL) { 2895 *prom_prop_data = NULL; 2896 return (-1); 2897 } 2898 2899 if (prop->len == 0) { /* boolean property */ 2900 *prom_prop_data = NULL; 2901 return (0); 2902 } 2903 2904 /* 2905 * Fix an openprom bug (OBP string not NULL terminated). 2906 * XXX This should really be fixed in promif. 2907 */ 2908 if (((char *)prop->data)[prop->len - 1] != '\0') { 2909 uchar_t *tmp; 2910 prop->len++; 2911 if ((tmp = realloc(prop->data, prop->len)) == NULL) 2912 return (-1); 2913 2914 prop->data = tmp; 2915 ((char *)prop->data)[prop->len - 1] = '\0'; 2916 DPRINTF((DI_INFO, "OBP string not NULL terminated: " 2917 "node=%s, prop=%s, val=%s\n", 2918 di_node_name(node), prom_prop_name, prop->data)); 2919 } 2920 2921 len = di_prop_decode_common((void *)&prop->data, prop->len, 2922 DI_PROP_TYPE_STRING, 1); 2923 *prom_prop_data = (char *)prop->data; 2924 2925 return (len); 2926 } 2927 2928 int 2929 di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node, 2930 const char *prom_prop_name, uchar_t **prom_prop_data) 2931 { 2932 int len; 2933 struct di_prom_prop *prop; 2934 2935 prop = di_prom_prop_lookup_common(ph, node, prom_prop_name); 2936 2937 if (prop == NULL) { 2938 *prom_prop_data = NULL; 2939 return (-1); 2940 } 2941 2942 if (prop->len == 0) { /* boolean property */ 2943 *prom_prop_data = NULL; 2944 return (0); 2945 } 2946 2947 len = di_prop_decode_common((void *)&prop->data, prop->len, 2948 DI_PROP_TYPE_BYTE, 1); 2949 *prom_prop_data = prop->data; 2950 2951 return (len); 2952 } 2953 2954 /* 2955 * returns an allocated array through <prop_data> only when its count > 0 2956 * and the number of entries (count) as the function return value; 2957 * use di_slot_names_free() to free the array 2958 */ 2959 int 2960 di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data) 2961 { 2962 int rawlen, count; 2963 uchar_t *rawdata; 2964 char *nm = di_prop_name(prop); 2965 2966 if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0) 2967 goto ERROUT; 2968 2969 rawlen = di_prop_rawdata(prop, &rawdata); 2970 if (rawlen <= 0 || rawdata == NULL) 2971 goto ERROUT; 2972 2973 count = di_slot_names_decode(rawdata, rawlen, prop_data); 2974 if (count < 0 || *prop_data == NULL) 2975 goto ERROUT; 2976 2977 return (count); 2978 /*NOTREACHED*/ 2979 ERROUT: 2980 errno = EFAULT; 2981 *prop_data = NULL; 2982 return (-1); 2983 } 2984 2985 int 2986 di_prop_lookup_slot_names(dev_t dev, di_node_t node, 2987 di_slot_name_t **prop_data) 2988 { 2989 di_prop_t prop; 2990 2991 /* 2992 * change this if and when DI_PROP_TYPE_COMPOSITE is implemented 2993 * and slot-names is properly flagged as such 2994 */ 2995 if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) == 2996 DI_PROP_NIL) { 2997 *prop_data = NULL; 2998 return (-1); 2999 } 3000 3001 return (di_prop_slot_names(prop, (void *)prop_data)); 3002 } 3003 3004 /* 3005 * returns an allocated array through <prop_data> only when its count > 0 3006 * and the number of entries (count) as the function return value; 3007 * use di_slot_names_free() to free the array 3008 */ 3009 int 3010 di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data) 3011 { 3012 int rawlen, count; 3013 uchar_t *rawdata; 3014 3015 rawlen = di_prom_prop_data(prom_prop, &rawdata); 3016 if (rawlen <= 0 || rawdata == NULL) 3017 goto ERROUT; 3018 3019 count = di_slot_names_decode(rawdata, rawlen, prop_data); 3020 if (count < 0 || *prop_data == NULL) 3021 goto ERROUT; 3022 3023 return (count); 3024 /*NOTREACHED*/ 3025 ERROUT: 3026 errno = EFAULT; 3027 *prop_data = NULL; 3028 return (-1); 3029 } 3030 3031 int 3032 di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node, 3033 di_slot_name_t **prop_data) 3034 { 3035 struct di_prom_prop *prom_prop; 3036 3037 prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES); 3038 if (prom_prop == NULL) { 3039 *prop_data = NULL; 3040 return (-1); 3041 } 3042 3043 return (di_prom_prop_slot_names(prom_prop, prop_data)); 3044 } 3045 3046 di_lnode_t 3047 di_link_to_lnode(di_link_t link, uint_t endpoint) 3048 { 3049 struct di_all *di_all; 3050 3051 if ((link == DI_LINK_NIL) || 3052 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 3053 errno = EINVAL; 3054 return (DI_LNODE_NIL); 3055 } 3056 3057 di_all = DI_ALL((caddr_t)link - DI_LINK(link)->self); 3058 3059 if (endpoint == DI_LINK_SRC) { 3060 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->src_lnode)); 3061 } else { 3062 return (DI_LNODE((caddr_t)di_all + DI_LINK(link)->tgt_lnode)); 3063 } 3064 /* NOTREACHED */ 3065 } 3066 3067 char * 3068 di_lnode_name(di_lnode_t lnode) 3069 { 3070 return (di_driver_name(di_lnode_devinfo(lnode))); 3071 } 3072 3073 di_node_t 3074 di_lnode_devinfo(di_lnode_t lnode) 3075 { 3076 struct di_all *di_all; 3077 3078 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self); 3079 return (DI_NODE((caddr_t)di_all + DI_LNODE(lnode)->node)); 3080 } 3081 3082 int 3083 di_lnode_devt(di_lnode_t lnode, dev_t *devt) 3084 { 3085 if ((lnode == DI_LNODE_NIL) || (devt == NULL)) { 3086 errno = EINVAL; 3087 return (-1); 3088 } 3089 if ((DI_LNODE(lnode)->dev_major == (major_t)-1) && 3090 (DI_LNODE(lnode)->dev_minor == (minor_t)-1)) 3091 return (-1); 3092 3093 *devt = makedev(DI_LNODE(lnode)->dev_major, DI_LNODE(lnode)->dev_minor); 3094 return (0); 3095 } 3096 3097 int 3098 di_link_spectype(di_link_t link) 3099 { 3100 return (DI_LINK(link)->spec_type); 3101 } 3102 3103 void 3104 di_minor_private_set(di_minor_t minor, void *data) 3105 { 3106 DI_MINOR(minor)->user_private_data = (uintptr_t)data; 3107 } 3108 3109 void * 3110 di_minor_private_get(di_minor_t minor) 3111 { 3112 return ((void *)(uintptr_t)DI_MINOR(minor)->user_private_data); 3113 } 3114 3115 void 3116 di_node_private_set(di_node_t node, void *data) 3117 { 3118 DI_NODE(node)->user_private_data = (uintptr_t)data; 3119 } 3120 3121 void * 3122 di_node_private_get(di_node_t node) 3123 { 3124 return ((void *)(uintptr_t)DI_NODE(node)->user_private_data); 3125 } 3126 3127 void 3128 di_path_private_set(di_path_t path, void *data) 3129 { 3130 DI_PATH(path)->user_private_data = (uintptr_t)data; 3131 } 3132 3133 void * 3134 di_path_private_get(di_path_t path) 3135 { 3136 return ((void *)(uintptr_t)DI_PATH(path)->user_private_data); 3137 } 3138 3139 void 3140 di_lnode_private_set(di_lnode_t lnode, void *data) 3141 { 3142 DI_LNODE(lnode)->user_private_data = (uintptr_t)data; 3143 } 3144 3145 void * 3146 di_lnode_private_get(di_lnode_t lnode) 3147 { 3148 return ((void *)(uintptr_t)DI_LNODE(lnode)->user_private_data); 3149 } 3150 3151 void 3152 di_link_private_set(di_link_t link, void *data) 3153 { 3154 DI_LINK(link)->user_private_data = (uintptr_t)data; 3155 } 3156 3157 void * 3158 di_link_private_get(di_link_t link) 3159 { 3160 return ((void *)(uintptr_t)DI_LINK(link)->user_private_data); 3161 } 3162 3163 di_lnode_t 3164 di_lnode_next(di_node_t node, di_lnode_t lnode) 3165 { 3166 struct di_all *di_all; 3167 3168 /* 3169 * paranoid error checking 3170 */ 3171 if (node == DI_NODE_NIL) { 3172 errno = EINVAL; 3173 return (DI_LNODE_NIL); 3174 } 3175 3176 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self); 3177 3178 if (lnode == DI_NODE_NIL) { 3179 if (DI_NODE(node)->lnodes != NULL) 3180 return (DI_LNODE((caddr_t)di_all + 3181 DI_NODE(node)->lnodes)); 3182 } else { 3183 if (DI_LNODE(lnode)->node_next != NULL) 3184 return (DI_LNODE((caddr_t)di_all + 3185 DI_LNODE(lnode)->node_next)); 3186 } 3187 3188 if (DINFOLYR & DI_ALL(di_all)->command) 3189 errno = ENXIO; 3190 else 3191 errno = ENOTSUP; 3192 3193 return (DI_LNODE_NIL); 3194 } 3195 3196 di_link_t 3197 di_link_next_by_node(di_node_t node, di_link_t link, uint_t endpoint) 3198 { 3199 struct di_all *di_all; 3200 3201 /* 3202 * paranoid error checking 3203 */ 3204 if ((node == DI_NODE_NIL) || 3205 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 3206 errno = EINVAL; 3207 return (DI_LINK_NIL); 3208 } 3209 3210 di_all = DI_ALL((caddr_t)node - DI_NODE(node)->self); 3211 3212 if (endpoint == DI_LINK_SRC) { 3213 if (link == DI_LINK_NIL) { 3214 if (DI_NODE(node)->src_links != NULL) 3215 return (DI_LINK((caddr_t)di_all + 3216 DI_NODE(node)->src_links)); 3217 } else { 3218 if (DI_LINK(link)->src_node_next != NULL) 3219 return (DI_LINK((caddr_t)di_all + 3220 DI_LINK(link)->src_node_next)); 3221 } 3222 } else { 3223 if (link == DI_LINK_NIL) { 3224 if (DI_NODE(node)->tgt_links != NULL) 3225 return (DI_LINK((caddr_t)di_all + 3226 DI_NODE(node)->tgt_links)); 3227 } else { 3228 if (DI_LINK(link)->tgt_node_next != NULL) 3229 return (DI_LINK((caddr_t)di_all + 3230 DI_LINK(link)->tgt_node_next)); 3231 } 3232 } 3233 3234 if (DINFOLYR & DI_ALL(di_all)->command) 3235 errno = ENXIO; 3236 else 3237 errno = ENOTSUP; 3238 3239 return (DI_LINK_NIL); 3240 } 3241 3242 di_link_t 3243 di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint) 3244 { 3245 struct di_all *di_all; 3246 3247 /* 3248 * paranoid error checking 3249 */ 3250 if ((lnode == DI_LNODE_NIL) || 3251 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 3252 errno = EINVAL; 3253 return (DI_LINK_NIL); 3254 } 3255 3256 di_all = DI_ALL((caddr_t)lnode - DI_LNODE(lnode)->self); 3257 3258 if (endpoint == DI_LINK_SRC) { 3259 if (link == DI_LINK_NIL) { 3260 if (DI_LNODE(lnode)->link_out == NULL) 3261 return (DI_LINK_NIL); 3262 return (DI_LINK((caddr_t)di_all + 3263 DI_LNODE(lnode)->link_out)); 3264 } else { 3265 if (DI_LINK(link)->src_link_next == NULL) 3266 return (DI_LINK_NIL); 3267 return (DI_LINK((caddr_t)di_all + 3268 DI_LINK(link)->src_link_next)); 3269 } 3270 } else { 3271 if (link == DI_LINK_NIL) { 3272 if (DI_LNODE(lnode)->link_in == NULL) 3273 return (DI_LINK_NIL); 3274 return (DI_LINK((caddr_t)di_all + 3275 DI_LNODE(lnode)->link_in)); 3276 } else { 3277 if (DI_LINK(link)->tgt_link_next == NULL) 3278 return (DI_LINK_NIL); 3279 return (DI_LINK((caddr_t)di_all + 3280 DI_LINK(link)->tgt_link_next)); 3281 } 3282 } 3283 /* NOTREACHED */ 3284 } 3285 3286 /* 3287 * Internal library function: 3288 * Invoke callback for each link data on the link list of first node 3289 * on node_list headp, and place children of first node on the list. 3290 * 3291 * This is similar to walk_one_node, except we only walk in child 3292 * first mode. 3293 */ 3294 static void 3295 walk_one_link(struct node_list **headp, uint_t ep, 3296 void *arg, int (*callback)(di_link_t link, void *arg)) 3297 { 3298 int action = DI_WALK_CONTINUE; 3299 di_link_t link = DI_LINK_NIL; 3300 di_node_t node = (*headp)->node; 3301 3302 while ((link = di_link_next_by_node(node, link, ep)) != DI_LINK_NIL) { 3303 action = callback(link, arg); 3304 if (action == DI_WALK_TERMINATE) { 3305 break; 3306 } 3307 } 3308 3309 update_node_list(action, DI_WALK_LINKGEN, headp); 3310 } 3311 3312 int 3313 di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg, 3314 int (*link_callback)(di_link_t link, void *arg)) 3315 { 3316 struct node_list *head; /* node_list for tree walk */ 3317 3318 #ifdef DEBUG 3319 char *devfspath = di_devfs_path(root); 3320 DPRINTF((DI_INFO, "walking %s link data under %s\n", 3321 (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath)); 3322 di_devfs_path_free(devfspath); 3323 #endif 3324 3325 /* 3326 * paranoid error checking 3327 */ 3328 if ((root == DI_NODE_NIL) || (link_callback == NULL) || (flag != 0) || 3329 ((endpoint != DI_LINK_SRC) && (endpoint != DI_LINK_TGT))) { 3330 errno = EINVAL; 3331 return (-1); 3332 } 3333 3334 if ((head = malloc(sizeof (struct node_list))) == NULL) { 3335 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 3336 return (-1); 3337 } 3338 3339 head->next = NULL; 3340 head->node = root; 3341 3342 DPRINTF((DI_INFO, "Start link data walking from node %s\n", 3343 di_node_name(root))); 3344 3345 while (head != NULL) 3346 walk_one_link(&head, endpoint, arg, link_callback); 3347 3348 return (0); 3349 } 3350 3351 /* 3352 * Internal library function: 3353 * Invoke callback for each link data on the link list of first node 3354 * on node_list headp, and place children of first node on the list. 3355 * 3356 * This is similar to walk_one_node, except we only walk in child 3357 * first mode. 3358 */ 3359 static void 3360 walk_one_lnode(struct node_list **headp, void *arg, 3361 int (*callback)(di_lnode_t lnode, void *arg)) 3362 { 3363 int action = DI_WALK_CONTINUE; 3364 di_lnode_t lnode = DI_LNODE_NIL; 3365 di_node_t node = (*headp)->node; 3366 3367 while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL) { 3368 action = callback(lnode, arg); 3369 if (action == DI_WALK_TERMINATE) { 3370 break; 3371 } 3372 } 3373 3374 update_node_list(action, DI_WALK_LINKGEN, headp); 3375 } 3376 3377 int 3378 di_walk_lnode(di_node_t root, uint_t flag, void *arg, 3379 int (*lnode_callback)(di_lnode_t lnode, void *arg)) 3380 { 3381 struct node_list *head; /* node_list for tree walk */ 3382 3383 #ifdef DEBUG 3384 char *devfspath = di_devfs_path(root); 3385 DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath)); 3386 di_devfs_path_free(devfspath); 3387 #endif 3388 3389 /* 3390 * paranoid error checking 3391 */ 3392 if ((root == DI_NODE_NIL) || (lnode_callback == NULL) || (flag != 0)) { 3393 errno = EINVAL; 3394 return (-1); 3395 } 3396 3397 if ((head = malloc(sizeof (struct node_list))) == NULL) { 3398 DPRINTF((DI_ERR, "malloc of node_list failed\n")); 3399 return (-1); 3400 } 3401 3402 head->next = NULL; 3403 head->node = root; 3404 3405 DPRINTF((DI_INFO, "Start lnode data walking from node %s\n", 3406 di_node_name(root))); 3407 3408 while (head != NULL) 3409 walk_one_lnode(&head, arg, lnode_callback); 3410 3411 return (0); 3412 } 3413 3414 di_node_t 3415 di_lookup_node(di_node_t root, char *devfspath) 3416 { 3417 struct di_all *dap; 3418 di_node_t node; 3419 char *copy, *slash, *pname, *paddr; 3420 3421 /* 3422 * Path must be absolute and musn't have duplicate slashes 3423 */ 3424 if (*devfspath != '/' || strstr(devfspath, "//")) { 3425 DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath)); 3426 return (DI_NODE_NIL); 3427 } 3428 3429 if (root == DI_NODE_NIL) { 3430 DPRINTF((DI_ERR, "root node is DI_NODE_NIL\n")); 3431 return (DI_NODE_NIL); 3432 } 3433 3434 dap = DI_ALL((caddr_t)root - DI_NODE(root)->self); 3435 if (strcmp(dap->root_path, "/") != 0) { 3436 DPRINTF((DI_ERR, "snapshot root not / : %s\n", dap->root_path)); 3437 return (DI_NODE_NIL); 3438 } 3439 3440 if ((copy = strdup(devfspath)) == NULL) { 3441 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath)); 3442 return (DI_NODE_NIL); 3443 } 3444 3445 for (slash = copy, node = root; slash; ) { 3446 3447 /* 3448 * Handle devfspath = "/" case as well as trailing '/' 3449 */ 3450 if (*(slash + 1) == '\0') 3451 break; 3452 3453 /* 3454 * More path-components exist. Deal with the next one 3455 */ 3456 pname = slash + 1; 3457 node = di_child_node(node); 3458 3459 if (slash = strchr(pname, '/')) 3460 *slash = '\0'; 3461 if (paddr = strchr(pname, '@')) 3462 *paddr++ = '\0'; 3463 3464 for (; node != DI_NODE_NIL; node = di_sibling_node(node)) { 3465 char *name, *baddr; 3466 3467 name = di_node_name(node); 3468 baddr = di_bus_addr(node); 3469 3470 if (strcmp(pname, name) != 0) 3471 continue; 3472 3473 /* 3474 * Mappings between a "path-address" and bus-addr 3475 * 3476 * paddr baddr 3477 * --------------------- 3478 * NULL NULL 3479 * NULL "" 3480 * "" N/A (invalid paddr) 3481 */ 3482 if (paddr && baddr && strcmp(paddr, baddr) == 0) 3483 break; 3484 if (paddr == NULL && (baddr == NULL || *baddr == '\0')) 3485 break; 3486 } 3487 3488 /* 3489 * No nodes in the sibling list or there was no match 3490 */ 3491 if (node == DI_NODE_NIL) { 3492 DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr)); 3493 free(copy); 3494 return (DI_NODE_NIL); 3495 } 3496 } 3497 3498 assert(node != DI_NODE_NIL); 3499 free(copy); 3500 return (node); 3501 } 3502 3503 di_path_t 3504 di_lookup_path(di_node_t root, char *devfspath) 3505 { 3506 di_node_t phci_node; 3507 di_path_t path = DI_PATH_NIL; 3508 char *copy, *lastslash; 3509 char *pname, *paddr; 3510 char *path_name, *path_addr; 3511 3512 if ((copy = strdup(devfspath)) == NULL) { 3513 DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath)); 3514 return (DI_NODE_NIL); 3515 } 3516 3517 if ((lastslash = strrchr(copy, '/')) == NULL) { 3518 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath)); 3519 goto out; 3520 } 3521 3522 /* stop at pHCI and find the node for the phci */ 3523 *lastslash = '\0'; 3524 phci_node = di_lookup_node(root, copy); 3525 if (phci_node == NULL) { 3526 DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath)); 3527 goto out; 3528 } 3529 3530 /* set up pname and paddr for last component */ 3531 pname = lastslash + 1; 3532 if ((paddr = strchr(pname, '@')) == NULL) { 3533 DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath)); 3534 goto out; 3535 } 3536 *paddr++ = '\0'; 3537 3538 /* walk paths below phci looking for match */ 3539 for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL); 3540 path != DI_PATH_NIL; 3541 path = di_path_phci_next_path(phci_node, path)) { 3542 3543 /* get name@addr of path */ 3544 path_name = di_path_node_name(path); 3545 path_addr = di_path_bus_addr(path); 3546 if ((path_name == NULL) || (path_addr == NULL)) 3547 continue; 3548 3549 /* break on match */ 3550 if ((strcmp(pname, path_name) == 0) && 3551 (strcmp(paddr, path_addr) == 0)) 3552 break; 3553 } 3554 3555 out: free(copy); 3556 return (path); 3557 } 3558 3559 static char * 3560 msglevel2str(di_debug_t msglevel) 3561 { 3562 switch (msglevel) { 3563 case DI_ERR: 3564 return ("ERROR"); 3565 case DI_INFO: 3566 return ("Info"); 3567 case DI_TRACE: 3568 return ("Trace"); 3569 case DI_TRACE1: 3570 return ("Trace1"); 3571 case DI_TRACE2: 3572 return ("Trace2"); 3573 default: 3574 return ("UNKNOWN"); 3575 } 3576 } 3577 3578 void 3579 dprint(di_debug_t msglevel, const char *fmt, ...) 3580 { 3581 va_list ap; 3582 char *estr; 3583 3584 if (di_debug <= DI_QUIET) 3585 return; 3586 3587 if (di_debug < msglevel) 3588 return; 3589 3590 estr = msglevel2str(msglevel); 3591 3592 assert(estr); 3593 3594 va_start(ap, fmt); 3595 3596 (void) fprintf(stderr, "libdevinfo[%lu]: %s: ", 3597 (ulong_t)getpid(), estr); 3598 (void) vfprintf(stderr, fmt, ap); 3599 3600 va_end(ap); 3601 } 3602 3603 /* end of devinfo.c */ 3604