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