1*10923SEvan.Yan@Sun.COM /* 2*10923SEvan.Yan@Sun.COM * CDDL HEADER START 3*10923SEvan.Yan@Sun.COM * 4*10923SEvan.Yan@Sun.COM * The contents of this file are subject to the terms of the 5*10923SEvan.Yan@Sun.COM * Common Development and Distribution License (the "License"). 6*10923SEvan.Yan@Sun.COM * You may not use this file except in compliance with the License. 7*10923SEvan.Yan@Sun.COM * 8*10923SEvan.Yan@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10923SEvan.Yan@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10923SEvan.Yan@Sun.COM * See the License for the specific language governing permissions 11*10923SEvan.Yan@Sun.COM * and limitations under the License. 12*10923SEvan.Yan@Sun.COM * 13*10923SEvan.Yan@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10923SEvan.Yan@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10923SEvan.Yan@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10923SEvan.Yan@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10923SEvan.Yan@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10923SEvan.Yan@Sun.COM * 19*10923SEvan.Yan@Sun.COM * CDDL HEADER END 20*10923SEvan.Yan@Sun.COM */ 21*10923SEvan.Yan@Sun.COM /* 22*10923SEvan.Yan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*10923SEvan.Yan@Sun.COM * Use is subject to license terms. 24*10923SEvan.Yan@Sun.COM */ 25*10923SEvan.Yan@Sun.COM 26*10923SEvan.Yan@Sun.COM #include <stdio.h> 27*10923SEvan.Yan@Sun.COM #include <stdlib.h> 28*10923SEvan.Yan@Sun.COM #include <stdarg.h> 29*10923SEvan.Yan@Sun.COM #include <unistd.h> 30*10923SEvan.Yan@Sun.COM #include <fcntl.h> 31*10923SEvan.Yan@Sun.COM #include <errno.h> 32*10923SEvan.Yan@Sun.COM #include <string.h> 33*10923SEvan.Yan@Sun.COM #include <door.h> 34*10923SEvan.Yan@Sun.COM #include <libnvpair.h> 35*10923SEvan.Yan@Sun.COM #include <libhotplug.h> 36*10923SEvan.Yan@Sun.COM #include <libhotplug_impl.h> 37*10923SEvan.Yan@Sun.COM #include <sys/sunddi.h> 38*10923SEvan.Yan@Sun.COM #include <sys/ddi_hp.h> 39*10923SEvan.Yan@Sun.COM 40*10923SEvan.Yan@Sun.COM static void i_hp_dprintf(const char *fmt, ...); 41*10923SEvan.Yan@Sun.COM static int i_hp_pack_branch(hp_node_t, char **, size_t *); 42*10923SEvan.Yan@Sun.COM static int i_hp_pack_node(hp_node_t, char **, size_t *); 43*10923SEvan.Yan@Sun.COM static int i_hp_unpack_node(char *, size_t, hp_node_t, hp_node_t *); 44*10923SEvan.Yan@Sun.COM static int i_hp_unpack_branch(char *, size_t, hp_node_t, hp_node_t *); 45*10923SEvan.Yan@Sun.COM static int i_hp_call_hotplugd(nvlist_t *, nvlist_t **); 46*10923SEvan.Yan@Sun.COM static nvlist_t *i_hp_set_args(hp_cmd_t, const char *, const char *, uint_t, 47*10923SEvan.Yan@Sun.COM const char *, int); 48*10923SEvan.Yan@Sun.COM static int i_hp_parse_results(nvlist_t *, hp_node_t *, char **); 49*10923SEvan.Yan@Sun.COM 50*10923SEvan.Yan@Sun.COM /* 51*10923SEvan.Yan@Sun.COM * Global flag to enable debug features. 52*10923SEvan.Yan@Sun.COM */ 53*10923SEvan.Yan@Sun.COM int libhotplug_debug = 0; 54*10923SEvan.Yan@Sun.COM 55*10923SEvan.Yan@Sun.COM /* 56*10923SEvan.Yan@Sun.COM * hp_init() 57*10923SEvan.Yan@Sun.COM * 58*10923SEvan.Yan@Sun.COM * Initialize a hotplug information snapshot. 59*10923SEvan.Yan@Sun.COM */ 60*10923SEvan.Yan@Sun.COM hp_node_t 61*10923SEvan.Yan@Sun.COM hp_init(const char *path, const char *connection, uint_t flags) 62*10923SEvan.Yan@Sun.COM { 63*10923SEvan.Yan@Sun.COM nvlist_t *args; 64*10923SEvan.Yan@Sun.COM nvlist_t *results; 65*10923SEvan.Yan@Sun.COM hp_node_t root = NULL; 66*10923SEvan.Yan@Sun.COM int rv; 67*10923SEvan.Yan@Sun.COM 68*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_init: path=%p, connection=%p, flags=0x%x\n", 69*10923SEvan.Yan@Sun.COM (void *)path, (void *)connection, flags); 70*10923SEvan.Yan@Sun.COM 71*10923SEvan.Yan@Sun.COM /* Check arguments */ 72*10923SEvan.Yan@Sun.COM if ((path == NULL) || !HP_INIT_FLAGS_VALID(flags)) { 73*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_init: invalid arguments.\n"); 74*10923SEvan.Yan@Sun.COM errno = EINVAL; 75*10923SEvan.Yan@Sun.COM return (NULL); 76*10923SEvan.Yan@Sun.COM } 77*10923SEvan.Yan@Sun.COM 78*10923SEvan.Yan@Sun.COM /* Build arguments for door call */ 79*10923SEvan.Yan@Sun.COM if ((args = i_hp_set_args(HP_CMD_GETINFO, path, connection, flags, 80*10923SEvan.Yan@Sun.COM NULL, 0)) == NULL) { 81*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_init: cannot build arguments nvlist.\n"); 82*10923SEvan.Yan@Sun.COM errno = ENOMEM; 83*10923SEvan.Yan@Sun.COM return (NULL); 84*10923SEvan.Yan@Sun.COM } 85*10923SEvan.Yan@Sun.COM 86*10923SEvan.Yan@Sun.COM /* Make the door call to hotplugd */ 87*10923SEvan.Yan@Sun.COM rv = i_hp_call_hotplugd(args, &results); 88*10923SEvan.Yan@Sun.COM 89*10923SEvan.Yan@Sun.COM /* Arguments no longer needed */ 90*10923SEvan.Yan@Sun.COM nvlist_free(args); 91*10923SEvan.Yan@Sun.COM 92*10923SEvan.Yan@Sun.COM /* Parse additional results, if any */ 93*10923SEvan.Yan@Sun.COM if ((rv == 0) && (results != NULL)) { 94*10923SEvan.Yan@Sun.COM rv = i_hp_parse_results(results, &root, NULL); 95*10923SEvan.Yan@Sun.COM nvlist_free(results); 96*10923SEvan.Yan@Sun.COM } 97*10923SEvan.Yan@Sun.COM 98*10923SEvan.Yan@Sun.COM /* Check for errors */ 99*10923SEvan.Yan@Sun.COM if (rv != 0) { 100*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_init: failure (%s).\n", strerror(rv)); 101*10923SEvan.Yan@Sun.COM if (root) 102*10923SEvan.Yan@Sun.COM hp_fini(root); 103*10923SEvan.Yan@Sun.COM errno = rv; 104*10923SEvan.Yan@Sun.COM return (NULL); 105*10923SEvan.Yan@Sun.COM } 106*10923SEvan.Yan@Sun.COM 107*10923SEvan.Yan@Sun.COM /* Success requires an info snapshot */ 108*10923SEvan.Yan@Sun.COM if (root == NULL) { 109*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_init: missing info snapshot.\n"); 110*10923SEvan.Yan@Sun.COM errno = EFAULT; 111*10923SEvan.Yan@Sun.COM return (NULL); 112*10923SEvan.Yan@Sun.COM } 113*10923SEvan.Yan@Sun.COM 114*10923SEvan.Yan@Sun.COM /* Success */ 115*10923SEvan.Yan@Sun.COM return (root); 116*10923SEvan.Yan@Sun.COM } 117*10923SEvan.Yan@Sun.COM 118*10923SEvan.Yan@Sun.COM /* 119*10923SEvan.Yan@Sun.COM * hp_fini() 120*10923SEvan.Yan@Sun.COM * 121*10923SEvan.Yan@Sun.COM * Terminate and clean-up a hotplug information snapshot. 122*10923SEvan.Yan@Sun.COM */ 123*10923SEvan.Yan@Sun.COM void 124*10923SEvan.Yan@Sun.COM hp_fini(hp_node_t root) 125*10923SEvan.Yan@Sun.COM { 126*10923SEvan.Yan@Sun.COM hp_node_t node; 127*10923SEvan.Yan@Sun.COM hp_node_t sibling; 128*10923SEvan.Yan@Sun.COM char *basepath; 129*10923SEvan.Yan@Sun.COM 130*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_fini: root=%p\n", (void *)root); 131*10923SEvan.Yan@Sun.COM 132*10923SEvan.Yan@Sun.COM if (root == NULL) { 133*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_fini: invalid arguments.\n"); 134*10923SEvan.Yan@Sun.COM return; 135*10923SEvan.Yan@Sun.COM } 136*10923SEvan.Yan@Sun.COM 137*10923SEvan.Yan@Sun.COM /* Extract and free base path */ 138*10923SEvan.Yan@Sun.COM if (root->hp_basepath) { 139*10923SEvan.Yan@Sun.COM basepath = root->hp_basepath; 140*10923SEvan.Yan@Sun.COM for (node = root; node != NULL; node = node->hp_sibling) 141*10923SEvan.Yan@Sun.COM node->hp_basepath = NULL; 142*10923SEvan.Yan@Sun.COM free(basepath); 143*10923SEvan.Yan@Sun.COM } 144*10923SEvan.Yan@Sun.COM 145*10923SEvan.Yan@Sun.COM /* Destroy the nodes */ 146*10923SEvan.Yan@Sun.COM node = root; 147*10923SEvan.Yan@Sun.COM while (node) { 148*10923SEvan.Yan@Sun.COM sibling = node->hp_sibling; 149*10923SEvan.Yan@Sun.COM if (node->hp_child) 150*10923SEvan.Yan@Sun.COM hp_fini(node->hp_child); 151*10923SEvan.Yan@Sun.COM if (node->hp_name) 152*10923SEvan.Yan@Sun.COM free(node->hp_name); 153*10923SEvan.Yan@Sun.COM if (node->hp_usage) 154*10923SEvan.Yan@Sun.COM free(node->hp_usage); 155*10923SEvan.Yan@Sun.COM if (node->hp_description) 156*10923SEvan.Yan@Sun.COM free(node->hp_description); 157*10923SEvan.Yan@Sun.COM free(node); 158*10923SEvan.Yan@Sun.COM node = sibling; 159*10923SEvan.Yan@Sun.COM } 160*10923SEvan.Yan@Sun.COM } 161*10923SEvan.Yan@Sun.COM 162*10923SEvan.Yan@Sun.COM /* 163*10923SEvan.Yan@Sun.COM * hp_traverse() 164*10923SEvan.Yan@Sun.COM * 165*10923SEvan.Yan@Sun.COM * Walk a graph of hotplug nodes, executing a callback on each node. 166*10923SEvan.Yan@Sun.COM */ 167*10923SEvan.Yan@Sun.COM int 168*10923SEvan.Yan@Sun.COM hp_traverse(hp_node_t root, void *arg, int (*hp_callback)(hp_node_t, void *arg)) 169*10923SEvan.Yan@Sun.COM { 170*10923SEvan.Yan@Sun.COM int rv; 171*10923SEvan.Yan@Sun.COM hp_node_t node; 172*10923SEvan.Yan@Sun.COM 173*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n", 174*10923SEvan.Yan@Sun.COM (void *)root, arg, (void *)hp_callback); 175*10923SEvan.Yan@Sun.COM 176*10923SEvan.Yan@Sun.COM /* Check arguments */ 177*10923SEvan.Yan@Sun.COM if ((root == NULL) || (hp_callback == NULL)) { 178*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_traverse: invalid arguments.\n"); 179*10923SEvan.Yan@Sun.COM errno = EINVAL; 180*10923SEvan.Yan@Sun.COM return (-1); 181*10923SEvan.Yan@Sun.COM } 182*10923SEvan.Yan@Sun.COM 183*10923SEvan.Yan@Sun.COM for (node = root; node; node = node->hp_sibling) { 184*10923SEvan.Yan@Sun.COM rv = hp_callback(node, arg); 185*10923SEvan.Yan@Sun.COM 186*10923SEvan.Yan@Sun.COM if (rv == HP_WALK_TERMINATE) { 187*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_traverse: walk terminated.\n"); 188*10923SEvan.Yan@Sun.COM return (HP_WALK_TERMINATE); 189*10923SEvan.Yan@Sun.COM } 190*10923SEvan.Yan@Sun.COM 191*10923SEvan.Yan@Sun.COM if (node->hp_child && (rv != HP_WALK_PRUNECHILD)) 192*10923SEvan.Yan@Sun.COM if (hp_traverse(node->hp_child, arg, hp_callback) == 193*10923SEvan.Yan@Sun.COM HP_WALK_TERMINATE) { 194*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_traverse: walk terminated.\n"); 195*10923SEvan.Yan@Sun.COM return (HP_WALK_TERMINATE); 196*10923SEvan.Yan@Sun.COM } 197*10923SEvan.Yan@Sun.COM 198*10923SEvan.Yan@Sun.COM if (rv == HP_WALK_PRUNESIBLING) 199*10923SEvan.Yan@Sun.COM break; 200*10923SEvan.Yan@Sun.COM } 201*10923SEvan.Yan@Sun.COM 202*10923SEvan.Yan@Sun.COM return (0); 203*10923SEvan.Yan@Sun.COM } 204*10923SEvan.Yan@Sun.COM 205*10923SEvan.Yan@Sun.COM /* 206*10923SEvan.Yan@Sun.COM * hp_type() 207*10923SEvan.Yan@Sun.COM * 208*10923SEvan.Yan@Sun.COM * Return a node's type. 209*10923SEvan.Yan@Sun.COM */ 210*10923SEvan.Yan@Sun.COM int 211*10923SEvan.Yan@Sun.COM hp_type(hp_node_t node) 212*10923SEvan.Yan@Sun.COM { 213*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_type: node=%p\n", (void *)node); 214*10923SEvan.Yan@Sun.COM 215*10923SEvan.Yan@Sun.COM if (node == NULL) { 216*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_type: invalid arguments.\n"); 217*10923SEvan.Yan@Sun.COM errno = EINVAL; 218*10923SEvan.Yan@Sun.COM return (-1); 219*10923SEvan.Yan@Sun.COM } 220*10923SEvan.Yan@Sun.COM 221*10923SEvan.Yan@Sun.COM return (node->hp_type); 222*10923SEvan.Yan@Sun.COM } 223*10923SEvan.Yan@Sun.COM 224*10923SEvan.Yan@Sun.COM /* 225*10923SEvan.Yan@Sun.COM * hp_name() 226*10923SEvan.Yan@Sun.COM * 227*10923SEvan.Yan@Sun.COM * Return a node's name. 228*10923SEvan.Yan@Sun.COM */ 229*10923SEvan.Yan@Sun.COM char * 230*10923SEvan.Yan@Sun.COM hp_name(hp_node_t node) 231*10923SEvan.Yan@Sun.COM { 232*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_name: node=%p\n", (void *)node); 233*10923SEvan.Yan@Sun.COM 234*10923SEvan.Yan@Sun.COM if (node == NULL) { 235*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_name: invalid arguments.\n"); 236*10923SEvan.Yan@Sun.COM errno = EINVAL; 237*10923SEvan.Yan@Sun.COM return (NULL); 238*10923SEvan.Yan@Sun.COM } 239*10923SEvan.Yan@Sun.COM 240*10923SEvan.Yan@Sun.COM if (node->hp_name == NULL) { 241*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_name: missing name value.\n"); 242*10923SEvan.Yan@Sun.COM errno = EFAULT; 243*10923SEvan.Yan@Sun.COM } 244*10923SEvan.Yan@Sun.COM 245*10923SEvan.Yan@Sun.COM return (node->hp_name); 246*10923SEvan.Yan@Sun.COM } 247*10923SEvan.Yan@Sun.COM 248*10923SEvan.Yan@Sun.COM /* 249*10923SEvan.Yan@Sun.COM * hp_state() 250*10923SEvan.Yan@Sun.COM * 251*10923SEvan.Yan@Sun.COM * Return a node's current state. 252*10923SEvan.Yan@Sun.COM */ 253*10923SEvan.Yan@Sun.COM int 254*10923SEvan.Yan@Sun.COM hp_state(hp_node_t node) 255*10923SEvan.Yan@Sun.COM { 256*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_state: node=%p\n", (void *)node); 257*10923SEvan.Yan@Sun.COM 258*10923SEvan.Yan@Sun.COM if (node == NULL) { 259*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_state: invalid arguments.\n"); 260*10923SEvan.Yan@Sun.COM errno = EINVAL; 261*10923SEvan.Yan@Sun.COM return (-1); 262*10923SEvan.Yan@Sun.COM } 263*10923SEvan.Yan@Sun.COM 264*10923SEvan.Yan@Sun.COM if ((node->hp_type != HP_NODE_CONNECTOR) && 265*10923SEvan.Yan@Sun.COM (node->hp_type != HP_NODE_PORT)) { 266*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_state: operation not supported.\n"); 267*10923SEvan.Yan@Sun.COM errno = ENOTSUP; 268*10923SEvan.Yan@Sun.COM return (-1); 269*10923SEvan.Yan@Sun.COM } 270*10923SEvan.Yan@Sun.COM 271*10923SEvan.Yan@Sun.COM return (node->hp_state); 272*10923SEvan.Yan@Sun.COM } 273*10923SEvan.Yan@Sun.COM 274*10923SEvan.Yan@Sun.COM /* 275*10923SEvan.Yan@Sun.COM * hp_usage() 276*10923SEvan.Yan@Sun.COM * 277*10923SEvan.Yan@Sun.COM * Return a usage description for usage nodes. 278*10923SEvan.Yan@Sun.COM */ 279*10923SEvan.Yan@Sun.COM char * 280*10923SEvan.Yan@Sun.COM hp_usage(hp_node_t node) 281*10923SEvan.Yan@Sun.COM { 282*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_usage: node=%p\n", (void *)node); 283*10923SEvan.Yan@Sun.COM 284*10923SEvan.Yan@Sun.COM if (node == NULL) { 285*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_usage: invalid arguments.\n"); 286*10923SEvan.Yan@Sun.COM errno = EINVAL; 287*10923SEvan.Yan@Sun.COM return (NULL); 288*10923SEvan.Yan@Sun.COM } 289*10923SEvan.Yan@Sun.COM 290*10923SEvan.Yan@Sun.COM if (node->hp_type != HP_NODE_USAGE) { 291*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_usage: operation not supported.\n"); 292*10923SEvan.Yan@Sun.COM errno = ENOTSUP; 293*10923SEvan.Yan@Sun.COM return (NULL); 294*10923SEvan.Yan@Sun.COM } 295*10923SEvan.Yan@Sun.COM 296*10923SEvan.Yan@Sun.COM if (node->hp_usage == NULL) { 297*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_usage: missing usage value.\n"); 298*10923SEvan.Yan@Sun.COM errno = EFAULT; 299*10923SEvan.Yan@Sun.COM } 300*10923SEvan.Yan@Sun.COM 301*10923SEvan.Yan@Sun.COM return (node->hp_usage); 302*10923SEvan.Yan@Sun.COM } 303*10923SEvan.Yan@Sun.COM 304*10923SEvan.Yan@Sun.COM /* 305*10923SEvan.Yan@Sun.COM * hp_description() 306*10923SEvan.Yan@Sun.COM * 307*10923SEvan.Yan@Sun.COM * Return a type description (e.g. "PCI slot") for connection nodes. 308*10923SEvan.Yan@Sun.COM */ 309*10923SEvan.Yan@Sun.COM char * 310*10923SEvan.Yan@Sun.COM hp_description(hp_node_t node) 311*10923SEvan.Yan@Sun.COM { 312*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_description: node=%p\n", (void *)node); 313*10923SEvan.Yan@Sun.COM 314*10923SEvan.Yan@Sun.COM if (node == NULL) { 315*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_description: invalid arguments.\n"); 316*10923SEvan.Yan@Sun.COM errno = EINVAL; 317*10923SEvan.Yan@Sun.COM return (NULL); 318*10923SEvan.Yan@Sun.COM } 319*10923SEvan.Yan@Sun.COM 320*10923SEvan.Yan@Sun.COM if ((node->hp_type != HP_NODE_CONNECTOR) && 321*10923SEvan.Yan@Sun.COM (node->hp_type != HP_NODE_PORT)) { 322*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_description: operation not supported.\n"); 323*10923SEvan.Yan@Sun.COM errno = ENOTSUP; 324*10923SEvan.Yan@Sun.COM return (NULL); 325*10923SEvan.Yan@Sun.COM } 326*10923SEvan.Yan@Sun.COM 327*10923SEvan.Yan@Sun.COM if (node->hp_description == NULL) { 328*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_description: missing description value.\n"); 329*10923SEvan.Yan@Sun.COM errno = EFAULT; 330*10923SEvan.Yan@Sun.COM } 331*10923SEvan.Yan@Sun.COM 332*10923SEvan.Yan@Sun.COM return (node->hp_description); 333*10923SEvan.Yan@Sun.COM } 334*10923SEvan.Yan@Sun.COM 335*10923SEvan.Yan@Sun.COM /* 336*10923SEvan.Yan@Sun.COM * hp_last_change() 337*10923SEvan.Yan@Sun.COM * 338*10923SEvan.Yan@Sun.COM * Return when the state of a connection was last changed. 339*10923SEvan.Yan@Sun.COM */ 340*10923SEvan.Yan@Sun.COM time_t 341*10923SEvan.Yan@Sun.COM hp_last_change(hp_node_t node) 342*10923SEvan.Yan@Sun.COM { 343*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_last_change: node=%p\n", (void *)node); 344*10923SEvan.Yan@Sun.COM 345*10923SEvan.Yan@Sun.COM if (node == NULL) { 346*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_last_change: invalid arguments.\n"); 347*10923SEvan.Yan@Sun.COM errno = EINVAL; 348*10923SEvan.Yan@Sun.COM return (NULL); 349*10923SEvan.Yan@Sun.COM } 350*10923SEvan.Yan@Sun.COM 351*10923SEvan.Yan@Sun.COM if ((node->hp_type != HP_NODE_CONNECTOR) && 352*10923SEvan.Yan@Sun.COM (node->hp_type != HP_NODE_PORT)) { 353*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_last_change: operation not supported.\n"); 354*10923SEvan.Yan@Sun.COM errno = ENOTSUP; 355*10923SEvan.Yan@Sun.COM return (NULL); 356*10923SEvan.Yan@Sun.COM } 357*10923SEvan.Yan@Sun.COM 358*10923SEvan.Yan@Sun.COM return (node->hp_last_change); 359*10923SEvan.Yan@Sun.COM } 360*10923SEvan.Yan@Sun.COM 361*10923SEvan.Yan@Sun.COM /* 362*10923SEvan.Yan@Sun.COM * hp_parent() 363*10923SEvan.Yan@Sun.COM * 364*10923SEvan.Yan@Sun.COM * Return a node's parent node. 365*10923SEvan.Yan@Sun.COM */ 366*10923SEvan.Yan@Sun.COM hp_node_t 367*10923SEvan.Yan@Sun.COM hp_parent(hp_node_t node) 368*10923SEvan.Yan@Sun.COM { 369*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_parent: node=%p\n", (void *)node); 370*10923SEvan.Yan@Sun.COM 371*10923SEvan.Yan@Sun.COM if (node == NULL) { 372*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_parent: invalid arguments.\n"); 373*10923SEvan.Yan@Sun.COM errno = EINVAL; 374*10923SEvan.Yan@Sun.COM return (NULL); 375*10923SEvan.Yan@Sun.COM } 376*10923SEvan.Yan@Sun.COM 377*10923SEvan.Yan@Sun.COM if (node->hp_parent == NULL) { 378*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_parent: node has no parent.\n"); 379*10923SEvan.Yan@Sun.COM errno = ENXIO; 380*10923SEvan.Yan@Sun.COM } 381*10923SEvan.Yan@Sun.COM 382*10923SEvan.Yan@Sun.COM return (node->hp_parent); 383*10923SEvan.Yan@Sun.COM } 384*10923SEvan.Yan@Sun.COM 385*10923SEvan.Yan@Sun.COM /* 386*10923SEvan.Yan@Sun.COM * hp_child() 387*10923SEvan.Yan@Sun.COM * 388*10923SEvan.Yan@Sun.COM * Return a node's first child node. 389*10923SEvan.Yan@Sun.COM */ 390*10923SEvan.Yan@Sun.COM hp_node_t 391*10923SEvan.Yan@Sun.COM hp_child(hp_node_t node) 392*10923SEvan.Yan@Sun.COM { 393*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_child: node=%p\n", (void *)node); 394*10923SEvan.Yan@Sun.COM 395*10923SEvan.Yan@Sun.COM if (node == NULL) { 396*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_child: invalid arguments.\n"); 397*10923SEvan.Yan@Sun.COM errno = EINVAL; 398*10923SEvan.Yan@Sun.COM return (NULL); 399*10923SEvan.Yan@Sun.COM } 400*10923SEvan.Yan@Sun.COM 401*10923SEvan.Yan@Sun.COM if (node->hp_child == NULL) { 402*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_child: node has no child.\n"); 403*10923SEvan.Yan@Sun.COM errno = ENXIO; 404*10923SEvan.Yan@Sun.COM } 405*10923SEvan.Yan@Sun.COM 406*10923SEvan.Yan@Sun.COM return (node->hp_child); 407*10923SEvan.Yan@Sun.COM } 408*10923SEvan.Yan@Sun.COM 409*10923SEvan.Yan@Sun.COM /* 410*10923SEvan.Yan@Sun.COM * hp_sibling() 411*10923SEvan.Yan@Sun.COM * 412*10923SEvan.Yan@Sun.COM * Return a node's next sibling node. 413*10923SEvan.Yan@Sun.COM */ 414*10923SEvan.Yan@Sun.COM hp_node_t 415*10923SEvan.Yan@Sun.COM hp_sibling(hp_node_t node) 416*10923SEvan.Yan@Sun.COM { 417*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_sibling: node=%p\n", (void *)node); 418*10923SEvan.Yan@Sun.COM 419*10923SEvan.Yan@Sun.COM if (node == NULL) { 420*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_sibling: invalid arguments.\n"); 421*10923SEvan.Yan@Sun.COM errno = EINVAL; 422*10923SEvan.Yan@Sun.COM return (NULL); 423*10923SEvan.Yan@Sun.COM } 424*10923SEvan.Yan@Sun.COM 425*10923SEvan.Yan@Sun.COM if (node->hp_sibling == NULL) { 426*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_sibling: node has no sibling.\n"); 427*10923SEvan.Yan@Sun.COM errno = ENXIO; 428*10923SEvan.Yan@Sun.COM } 429*10923SEvan.Yan@Sun.COM 430*10923SEvan.Yan@Sun.COM return (node->hp_sibling); 431*10923SEvan.Yan@Sun.COM } 432*10923SEvan.Yan@Sun.COM 433*10923SEvan.Yan@Sun.COM /* 434*10923SEvan.Yan@Sun.COM * hp_path() 435*10923SEvan.Yan@Sun.COM * 436*10923SEvan.Yan@Sun.COM * Return the path (and maybe connection name) of a node. 437*10923SEvan.Yan@Sun.COM * The caller must supply two buffers, each MAXPATHLEN size. 438*10923SEvan.Yan@Sun.COM */ 439*10923SEvan.Yan@Sun.COM int 440*10923SEvan.Yan@Sun.COM hp_path(hp_node_t node, char *path, char *connection) 441*10923SEvan.Yan@Sun.COM { 442*10923SEvan.Yan@Sun.COM hp_node_t root; 443*10923SEvan.Yan@Sun.COM hp_node_t parent; 444*10923SEvan.Yan@Sun.COM int i; 445*10923SEvan.Yan@Sun.COM char *s; 446*10923SEvan.Yan@Sun.COM char components[MAXPATHLEN]; 447*10923SEvan.Yan@Sun.COM 448*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_path: node=%p, path=%p, connection=%p\n", (void *)node, 449*10923SEvan.Yan@Sun.COM (void *)path, (void *)connection); 450*10923SEvan.Yan@Sun.COM 451*10923SEvan.Yan@Sun.COM if ((node == NULL) || (path == NULL) || (connection == NULL)) { 452*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_path: invalid arguments.\n"); 453*10923SEvan.Yan@Sun.COM return (EINVAL); 454*10923SEvan.Yan@Sun.COM } 455*10923SEvan.Yan@Sun.COM 456*10923SEvan.Yan@Sun.COM (void) memset(path, 0, MAXPATHLEN); 457*10923SEvan.Yan@Sun.COM (void) memset(connection, 0, MAXPATHLEN); 458*10923SEvan.Yan@Sun.COM (void) memset(components, 0, MAXPATHLEN); 459*10923SEvan.Yan@Sun.COM 460*10923SEvan.Yan@Sun.COM /* Set 'connection' only for connectors and ports */ 461*10923SEvan.Yan@Sun.COM if ((node->hp_type == HP_NODE_CONNECTOR) || 462*10923SEvan.Yan@Sun.COM (node->hp_type == HP_NODE_PORT)) 463*10923SEvan.Yan@Sun.COM (void) strlcpy(connection, node->hp_name, MAXPATHLEN); 464*10923SEvan.Yan@Sun.COM 465*10923SEvan.Yan@Sun.COM /* Trace back to the root node, accumulating components */ 466*10923SEvan.Yan@Sun.COM for (parent = node; parent != NULL; parent = parent->hp_parent) { 467*10923SEvan.Yan@Sun.COM if (parent->hp_type == HP_NODE_DEVICE) { 468*10923SEvan.Yan@Sun.COM (void) strlcat(components, "/", MAXPATHLEN); 469*10923SEvan.Yan@Sun.COM (void) strlcat(components, parent->hp_name, MAXPATHLEN); 470*10923SEvan.Yan@Sun.COM } 471*10923SEvan.Yan@Sun.COM if (parent->hp_parent == NULL) 472*10923SEvan.Yan@Sun.COM root = parent; 473*10923SEvan.Yan@Sun.COM } 474*10923SEvan.Yan@Sun.COM 475*10923SEvan.Yan@Sun.COM /* Ensure the snapshot actually contains a base path */ 476*10923SEvan.Yan@Sun.COM if (root->hp_basepath == NULL) { 477*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_path: missing base pathname.\n"); 478*10923SEvan.Yan@Sun.COM return (EFAULT); 479*10923SEvan.Yan@Sun.COM } 480*10923SEvan.Yan@Sun.COM 481*10923SEvan.Yan@Sun.COM /* 482*10923SEvan.Yan@Sun.COM * Construct the path. Start with the base path from the root 483*10923SEvan.Yan@Sun.COM * node, then append the accumulated components in reverse order. 484*10923SEvan.Yan@Sun.COM */ 485*10923SEvan.Yan@Sun.COM if (strcmp(root->hp_basepath, "/") != 0) { 486*10923SEvan.Yan@Sun.COM (void) strlcat(path, root->hp_basepath, MAXPATHLEN); 487*10923SEvan.Yan@Sun.COM if ((root->hp_type == HP_NODE_DEVICE) && 488*10923SEvan.Yan@Sun.COM ((s = strrchr(path, '/')) != NULL)) 489*10923SEvan.Yan@Sun.COM *s = '\0'; 490*10923SEvan.Yan@Sun.COM } 491*10923SEvan.Yan@Sun.COM for (i = strlen(components) - 1; i >= 0; i--) { 492*10923SEvan.Yan@Sun.COM if (components[i] == '/') { 493*10923SEvan.Yan@Sun.COM (void) strlcat(path, &components[i], MAXPATHLEN); 494*10923SEvan.Yan@Sun.COM components[i] = '\0'; 495*10923SEvan.Yan@Sun.COM } 496*10923SEvan.Yan@Sun.COM } 497*10923SEvan.Yan@Sun.COM 498*10923SEvan.Yan@Sun.COM return (0); 499*10923SEvan.Yan@Sun.COM } 500*10923SEvan.Yan@Sun.COM 501*10923SEvan.Yan@Sun.COM /* 502*10923SEvan.Yan@Sun.COM * hp_set_state() 503*10923SEvan.Yan@Sun.COM * 504*10923SEvan.Yan@Sun.COM * Initiate a state change operation on a node. 505*10923SEvan.Yan@Sun.COM */ 506*10923SEvan.Yan@Sun.COM int 507*10923SEvan.Yan@Sun.COM hp_set_state(hp_node_t node, uint_t flags, int state, hp_node_t *resultsp) 508*10923SEvan.Yan@Sun.COM { 509*10923SEvan.Yan@Sun.COM hp_node_t root = NULL; 510*10923SEvan.Yan@Sun.COM nvlist_t *args; 511*10923SEvan.Yan@Sun.COM nvlist_t *results; 512*10923SEvan.Yan@Sun.COM int rv; 513*10923SEvan.Yan@Sun.COM char path[MAXPATHLEN]; 514*10923SEvan.Yan@Sun.COM char connection[MAXPATHLEN]; 515*10923SEvan.Yan@Sun.COM 516*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, " 517*10923SEvan.Yan@Sun.COM "resultsp=%p\n", (void *)node, flags, state, (void *)resultsp); 518*10923SEvan.Yan@Sun.COM 519*10923SEvan.Yan@Sun.COM /* Check arguments */ 520*10923SEvan.Yan@Sun.COM if ((node == NULL) || (resultsp == NULL) || 521*10923SEvan.Yan@Sun.COM !HP_SET_STATE_FLAGS_VALID(flags)) { 522*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_state: invalid arguments.\n"); 523*10923SEvan.Yan@Sun.COM return (EINVAL); 524*10923SEvan.Yan@Sun.COM } 525*10923SEvan.Yan@Sun.COM 526*10923SEvan.Yan@Sun.COM /* Check node type */ 527*10923SEvan.Yan@Sun.COM if ((node->hp_type != HP_NODE_CONNECTOR) && 528*10923SEvan.Yan@Sun.COM (node->hp_type != HP_NODE_PORT)) { 529*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_state: operation not supported.\n"); 530*10923SEvan.Yan@Sun.COM return (ENOTSUP); 531*10923SEvan.Yan@Sun.COM } 532*10923SEvan.Yan@Sun.COM 533*10923SEvan.Yan@Sun.COM /* Check that target state is valid */ 534*10923SEvan.Yan@Sun.COM switch (state) { 535*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_PRESENT: 536*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_POWERED: 537*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_ENABLED: 538*10923SEvan.Yan@Sun.COM if (node->hp_type != HP_NODE_CONNECTOR) { 539*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_state: mismatched target.\n"); 540*10923SEvan.Yan@Sun.COM return (ENOTSUP); 541*10923SEvan.Yan@Sun.COM } 542*10923SEvan.Yan@Sun.COM break; 543*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_PORT_PRESENT: 544*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_OFFLINE: 545*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_ONLINE: 546*10923SEvan.Yan@Sun.COM if (node->hp_type != HP_NODE_PORT) { 547*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_state: mismatched target.\n"); 548*10923SEvan.Yan@Sun.COM return (ENOTSUP); 549*10923SEvan.Yan@Sun.COM } 550*10923SEvan.Yan@Sun.COM break; 551*10923SEvan.Yan@Sun.COM default: 552*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_state: invalid target state.\n"); 553*10923SEvan.Yan@Sun.COM return (EINVAL); 554*10923SEvan.Yan@Sun.COM } 555*10923SEvan.Yan@Sun.COM 556*10923SEvan.Yan@Sun.COM /* Get path and connection of specified node */ 557*10923SEvan.Yan@Sun.COM if ((rv = hp_path(node, path, connection)) != 0) 558*10923SEvan.Yan@Sun.COM return (rv); 559*10923SEvan.Yan@Sun.COM 560*10923SEvan.Yan@Sun.COM /* Build arguments for door call */ 561*10923SEvan.Yan@Sun.COM if ((args = i_hp_set_args(HP_CMD_CHANGESTATE, path, connection, flags, 562*10923SEvan.Yan@Sun.COM NULL, state)) == NULL) 563*10923SEvan.Yan@Sun.COM return (ENOMEM); 564*10923SEvan.Yan@Sun.COM 565*10923SEvan.Yan@Sun.COM /* Make the door call to hotplugd */ 566*10923SEvan.Yan@Sun.COM rv = i_hp_call_hotplugd(args, &results); 567*10923SEvan.Yan@Sun.COM 568*10923SEvan.Yan@Sun.COM /* Arguments no longer needed */ 569*10923SEvan.Yan@Sun.COM nvlist_free(args); 570*10923SEvan.Yan@Sun.COM 571*10923SEvan.Yan@Sun.COM /* Parse additional results, if any */ 572*10923SEvan.Yan@Sun.COM if ((rv == 0) && (results != NULL)) { 573*10923SEvan.Yan@Sun.COM rv = i_hp_parse_results(results, &root, NULL); 574*10923SEvan.Yan@Sun.COM nvlist_free(results); 575*10923SEvan.Yan@Sun.COM *resultsp = root; 576*10923SEvan.Yan@Sun.COM } 577*10923SEvan.Yan@Sun.COM 578*10923SEvan.Yan@Sun.COM /* Done */ 579*10923SEvan.Yan@Sun.COM return (rv); 580*10923SEvan.Yan@Sun.COM } 581*10923SEvan.Yan@Sun.COM 582*10923SEvan.Yan@Sun.COM /* 583*10923SEvan.Yan@Sun.COM * hp_set_private() 584*10923SEvan.Yan@Sun.COM * 585*10923SEvan.Yan@Sun.COM * Set bus private options on the hotplug connection 586*10923SEvan.Yan@Sun.COM * indicated by the given hotplug information node. 587*10923SEvan.Yan@Sun.COM */ 588*10923SEvan.Yan@Sun.COM int 589*10923SEvan.Yan@Sun.COM hp_set_private(hp_node_t node, const char *options, char **resultsp) 590*10923SEvan.Yan@Sun.COM { 591*10923SEvan.Yan@Sun.COM int rv; 592*10923SEvan.Yan@Sun.COM nvlist_t *args; 593*10923SEvan.Yan@Sun.COM nvlist_t *results; 594*10923SEvan.Yan@Sun.COM char *values = NULL; 595*10923SEvan.Yan@Sun.COM char path[MAXPATHLEN]; 596*10923SEvan.Yan@Sun.COM char connection[MAXPATHLEN]; 597*10923SEvan.Yan@Sun.COM 598*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n", 599*10923SEvan.Yan@Sun.COM (void *)node, (void *)options, (void *)resultsp); 600*10923SEvan.Yan@Sun.COM 601*10923SEvan.Yan@Sun.COM /* Check arguments */ 602*10923SEvan.Yan@Sun.COM if ((node == NULL) || (options == NULL) || (resultsp == NULL)) { 603*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_private: invalid arguments.\n"); 604*10923SEvan.Yan@Sun.COM return (EINVAL); 605*10923SEvan.Yan@Sun.COM } 606*10923SEvan.Yan@Sun.COM 607*10923SEvan.Yan@Sun.COM /* Check node type */ 608*10923SEvan.Yan@Sun.COM if (node->hp_type != HP_NODE_CONNECTOR) { 609*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_set_private: operation not supported.\n"); 610*10923SEvan.Yan@Sun.COM return (ENOTSUP); 611*10923SEvan.Yan@Sun.COM } 612*10923SEvan.Yan@Sun.COM 613*10923SEvan.Yan@Sun.COM /* Initialize results */ 614*10923SEvan.Yan@Sun.COM *resultsp = NULL; 615*10923SEvan.Yan@Sun.COM 616*10923SEvan.Yan@Sun.COM /* Get path and connection of specified node */ 617*10923SEvan.Yan@Sun.COM if ((rv = hp_path(node, path, connection)) != 0) 618*10923SEvan.Yan@Sun.COM return (rv); 619*10923SEvan.Yan@Sun.COM 620*10923SEvan.Yan@Sun.COM /* Build arguments for door call */ 621*10923SEvan.Yan@Sun.COM if ((args = i_hp_set_args(HP_CMD_SETPRIVATE, path, connection, 0, 622*10923SEvan.Yan@Sun.COM options, 0)) == NULL) 623*10923SEvan.Yan@Sun.COM return (ENOMEM); 624*10923SEvan.Yan@Sun.COM 625*10923SEvan.Yan@Sun.COM /* Make the door call to hotplugd */ 626*10923SEvan.Yan@Sun.COM rv = i_hp_call_hotplugd(args, &results); 627*10923SEvan.Yan@Sun.COM 628*10923SEvan.Yan@Sun.COM /* Arguments no longer needed */ 629*10923SEvan.Yan@Sun.COM nvlist_free(args); 630*10923SEvan.Yan@Sun.COM 631*10923SEvan.Yan@Sun.COM /* Parse additional results, if any */ 632*10923SEvan.Yan@Sun.COM if ((rv == 0) && (results != NULL)) { 633*10923SEvan.Yan@Sun.COM rv = i_hp_parse_results(results, NULL, &values); 634*10923SEvan.Yan@Sun.COM nvlist_free(results); 635*10923SEvan.Yan@Sun.COM *resultsp = values; 636*10923SEvan.Yan@Sun.COM } 637*10923SEvan.Yan@Sun.COM 638*10923SEvan.Yan@Sun.COM /* Done */ 639*10923SEvan.Yan@Sun.COM return (rv); 640*10923SEvan.Yan@Sun.COM } 641*10923SEvan.Yan@Sun.COM 642*10923SEvan.Yan@Sun.COM /* 643*10923SEvan.Yan@Sun.COM * hp_get_private() 644*10923SEvan.Yan@Sun.COM * 645*10923SEvan.Yan@Sun.COM * Get bus private options on the hotplug connection 646*10923SEvan.Yan@Sun.COM * indicated by the given hotplug information node. 647*10923SEvan.Yan@Sun.COM */ 648*10923SEvan.Yan@Sun.COM int 649*10923SEvan.Yan@Sun.COM hp_get_private(hp_node_t node, const char *options, char **resultsp) 650*10923SEvan.Yan@Sun.COM { 651*10923SEvan.Yan@Sun.COM int rv; 652*10923SEvan.Yan@Sun.COM nvlist_t *args; 653*10923SEvan.Yan@Sun.COM nvlist_t *results; 654*10923SEvan.Yan@Sun.COM char *values = NULL; 655*10923SEvan.Yan@Sun.COM char path[MAXPATHLEN]; 656*10923SEvan.Yan@Sun.COM char connection[MAXPATHLEN]; 657*10923SEvan.Yan@Sun.COM 658*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n", 659*10923SEvan.Yan@Sun.COM (void *)node, (void *)options, (void *)resultsp); 660*10923SEvan.Yan@Sun.COM 661*10923SEvan.Yan@Sun.COM /* Check arguments */ 662*10923SEvan.Yan@Sun.COM if ((node == NULL) || (options == NULL) || (resultsp == NULL)) { 663*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_get_private: invalid arguments.\n"); 664*10923SEvan.Yan@Sun.COM return (EINVAL); 665*10923SEvan.Yan@Sun.COM } 666*10923SEvan.Yan@Sun.COM 667*10923SEvan.Yan@Sun.COM /* Check node type */ 668*10923SEvan.Yan@Sun.COM if (node->hp_type != HP_NODE_CONNECTOR) { 669*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_get_private: operation not supported.\n"); 670*10923SEvan.Yan@Sun.COM return (ENOTSUP); 671*10923SEvan.Yan@Sun.COM } 672*10923SEvan.Yan@Sun.COM 673*10923SEvan.Yan@Sun.COM /* Initialize results */ 674*10923SEvan.Yan@Sun.COM *resultsp = NULL; 675*10923SEvan.Yan@Sun.COM 676*10923SEvan.Yan@Sun.COM /* Get path and connection of specified node */ 677*10923SEvan.Yan@Sun.COM if ((rv = hp_path(node, path, connection)) != 0) 678*10923SEvan.Yan@Sun.COM return (rv); 679*10923SEvan.Yan@Sun.COM 680*10923SEvan.Yan@Sun.COM /* Build arguments for door call */ 681*10923SEvan.Yan@Sun.COM if ((args = i_hp_set_args(HP_CMD_GETPRIVATE, path, connection, 0, 682*10923SEvan.Yan@Sun.COM options, 0)) == NULL) 683*10923SEvan.Yan@Sun.COM return (ENOMEM); 684*10923SEvan.Yan@Sun.COM 685*10923SEvan.Yan@Sun.COM /* Make the door call to hotplugd */ 686*10923SEvan.Yan@Sun.COM rv = i_hp_call_hotplugd(args, &results); 687*10923SEvan.Yan@Sun.COM 688*10923SEvan.Yan@Sun.COM /* Arguments no longer needed */ 689*10923SEvan.Yan@Sun.COM nvlist_free(args); 690*10923SEvan.Yan@Sun.COM 691*10923SEvan.Yan@Sun.COM /* Parse additional results, if any */ 692*10923SEvan.Yan@Sun.COM if ((rv == 0) && (results != NULL)) { 693*10923SEvan.Yan@Sun.COM rv = i_hp_parse_results(results, NULL, &values); 694*10923SEvan.Yan@Sun.COM nvlist_free(results); 695*10923SEvan.Yan@Sun.COM *resultsp = values; 696*10923SEvan.Yan@Sun.COM } 697*10923SEvan.Yan@Sun.COM 698*10923SEvan.Yan@Sun.COM /* Done */ 699*10923SEvan.Yan@Sun.COM return (rv); 700*10923SEvan.Yan@Sun.COM } 701*10923SEvan.Yan@Sun.COM 702*10923SEvan.Yan@Sun.COM /* 703*10923SEvan.Yan@Sun.COM * hp_pack() 704*10923SEvan.Yan@Sun.COM * 705*10923SEvan.Yan@Sun.COM * Given the root of a hotplug information snapshot, pack 706*10923SEvan.Yan@Sun.COM * it into a contiguous byte array so that it is suitable 707*10923SEvan.Yan@Sun.COM * for network transport. 708*10923SEvan.Yan@Sun.COM */ 709*10923SEvan.Yan@Sun.COM int 710*10923SEvan.Yan@Sun.COM hp_pack(hp_node_t root, char **bufp, size_t *lenp) 711*10923SEvan.Yan@Sun.COM { 712*10923SEvan.Yan@Sun.COM hp_node_t node; 713*10923SEvan.Yan@Sun.COM nvlist_t *nvl; 714*10923SEvan.Yan@Sun.COM char *buf; 715*10923SEvan.Yan@Sun.COM size_t len; 716*10923SEvan.Yan@Sun.COM int rv; 717*10923SEvan.Yan@Sun.COM 718*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_pack: root=%p, bufp=%p, lenp=%p\n", (void *)root, 719*10923SEvan.Yan@Sun.COM (void *)bufp, (void *)lenp); 720*10923SEvan.Yan@Sun.COM 721*10923SEvan.Yan@Sun.COM if ((root == NULL) || (bufp == NULL) || (lenp == NULL)) { 722*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_pack: invalid arguments.\n"); 723*10923SEvan.Yan@Sun.COM return (EINVAL); 724*10923SEvan.Yan@Sun.COM } 725*10923SEvan.Yan@Sun.COM 726*10923SEvan.Yan@Sun.COM *lenp = 0; 727*10923SEvan.Yan@Sun.COM *bufp = NULL; 728*10923SEvan.Yan@Sun.COM 729*10923SEvan.Yan@Sun.COM if (nvlist_alloc(&nvl, 0, 0) != 0) { 730*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n", 731*10923SEvan.Yan@Sun.COM strerror(errno)); 732*10923SEvan.Yan@Sun.COM return (ENOMEM); 733*10923SEvan.Yan@Sun.COM } 734*10923SEvan.Yan@Sun.COM 735*10923SEvan.Yan@Sun.COM if (root->hp_basepath != NULL) { 736*10923SEvan.Yan@Sun.COM rv = nvlist_add_string(nvl, HP_INFO_BASE, root->hp_basepath); 737*10923SEvan.Yan@Sun.COM if (rv != 0) { 738*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 739*10923SEvan.Yan@Sun.COM return (rv); 740*10923SEvan.Yan@Sun.COM } 741*10923SEvan.Yan@Sun.COM } 742*10923SEvan.Yan@Sun.COM 743*10923SEvan.Yan@Sun.COM for (node = root; node != NULL; node = node->hp_sibling) { 744*10923SEvan.Yan@Sun.COM if ((rv = i_hp_pack_branch(node, &buf, &len)) == 0) { 745*10923SEvan.Yan@Sun.COM rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH, 746*10923SEvan.Yan@Sun.COM (uchar_t *)buf, len); 747*10923SEvan.Yan@Sun.COM free(buf); 748*10923SEvan.Yan@Sun.COM } 749*10923SEvan.Yan@Sun.COM if (rv != 0) { 750*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 751*10923SEvan.Yan@Sun.COM return (rv); 752*10923SEvan.Yan@Sun.COM } 753*10923SEvan.Yan@Sun.COM } 754*10923SEvan.Yan@Sun.COM 755*10923SEvan.Yan@Sun.COM len = 0; 756*10923SEvan.Yan@Sun.COM buf = NULL; 757*10923SEvan.Yan@Sun.COM if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) { 758*10923SEvan.Yan@Sun.COM *lenp = len; 759*10923SEvan.Yan@Sun.COM *bufp = buf; 760*10923SEvan.Yan@Sun.COM } 761*10923SEvan.Yan@Sun.COM 762*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 763*10923SEvan.Yan@Sun.COM 764*10923SEvan.Yan@Sun.COM return (rv); 765*10923SEvan.Yan@Sun.COM } 766*10923SEvan.Yan@Sun.COM 767*10923SEvan.Yan@Sun.COM /* 768*10923SEvan.Yan@Sun.COM * hp_unpack() 769*10923SEvan.Yan@Sun.COM * 770*10923SEvan.Yan@Sun.COM * Unpack a hotplug information snapshot for normal usage. 771*10923SEvan.Yan@Sun.COM */ 772*10923SEvan.Yan@Sun.COM int 773*10923SEvan.Yan@Sun.COM hp_unpack(char *packed_buf, size_t packed_len, hp_node_t *retp) 774*10923SEvan.Yan@Sun.COM { 775*10923SEvan.Yan@Sun.COM hp_node_t root; 776*10923SEvan.Yan@Sun.COM hp_node_t root_list = NULL; 777*10923SEvan.Yan@Sun.COM hp_node_t prev_root = NULL; 778*10923SEvan.Yan@Sun.COM nvlist_t *nvl = NULL; 779*10923SEvan.Yan@Sun.COM nvpair_t *nvp; 780*10923SEvan.Yan@Sun.COM char *basepath = NULL; 781*10923SEvan.Yan@Sun.COM int rv; 782*10923SEvan.Yan@Sun.COM 783*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n", 784*10923SEvan.Yan@Sun.COM (void *)packed_buf, (uint32_t)packed_len, (void *)retp); 785*10923SEvan.Yan@Sun.COM 786*10923SEvan.Yan@Sun.COM if ((packed_buf == NULL) || (packed_len == 0) || (retp == NULL)) { 787*10923SEvan.Yan@Sun.COM i_hp_dprintf("hp_unpack: invalid arguments.\n"); 788*10923SEvan.Yan@Sun.COM return (EINVAL); 789*10923SEvan.Yan@Sun.COM } 790*10923SEvan.Yan@Sun.COM 791*10923SEvan.Yan@Sun.COM if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0) 792*10923SEvan.Yan@Sun.COM return (rv); 793*10923SEvan.Yan@Sun.COM 794*10923SEvan.Yan@Sun.COM if (nvlist_next_nvpair(nvl, NULL) == NULL) { 795*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 796*10923SEvan.Yan@Sun.COM errno = EINVAL; 797*10923SEvan.Yan@Sun.COM return (NULL); 798*10923SEvan.Yan@Sun.COM } 799*10923SEvan.Yan@Sun.COM 800*10923SEvan.Yan@Sun.COM for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) { 801*10923SEvan.Yan@Sun.COM 802*10923SEvan.Yan@Sun.COM rv = EINVAL; 803*10923SEvan.Yan@Sun.COM 804*10923SEvan.Yan@Sun.COM if (strcmp(nvpair_name(nvp), HP_INFO_BASE) == 0) { 805*10923SEvan.Yan@Sun.COM char *val_string; 806*10923SEvan.Yan@Sun.COM 807*10923SEvan.Yan@Sun.COM if ((rv = nvpair_value_string(nvp, &val_string)) == 0) { 808*10923SEvan.Yan@Sun.COM if ((basepath = strdup(val_string)) == NULL) 809*10923SEvan.Yan@Sun.COM rv = ENOMEM; 810*10923SEvan.Yan@Sun.COM } 811*10923SEvan.Yan@Sun.COM 812*10923SEvan.Yan@Sun.COM } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) { 813*10923SEvan.Yan@Sun.COM size_t len = 0; 814*10923SEvan.Yan@Sun.COM char *buf = NULL; 815*10923SEvan.Yan@Sun.COM 816*10923SEvan.Yan@Sun.COM if ((rv = nvpair_value_byte_array(nvp, 817*10923SEvan.Yan@Sun.COM (uchar_t **)&buf, (uint_t *)&len)) == 0) { 818*10923SEvan.Yan@Sun.COM rv = i_hp_unpack_branch(buf, len, NULL, &root); 819*10923SEvan.Yan@Sun.COM } 820*10923SEvan.Yan@Sun.COM 821*10923SEvan.Yan@Sun.COM if (rv == 0) { 822*10923SEvan.Yan@Sun.COM if (prev_root) { 823*10923SEvan.Yan@Sun.COM prev_root->hp_sibling = root; 824*10923SEvan.Yan@Sun.COM } else { 825*10923SEvan.Yan@Sun.COM root_list = root; 826*10923SEvan.Yan@Sun.COM } 827*10923SEvan.Yan@Sun.COM prev_root = root; 828*10923SEvan.Yan@Sun.COM } 829*10923SEvan.Yan@Sun.COM } 830*10923SEvan.Yan@Sun.COM 831*10923SEvan.Yan@Sun.COM if (rv != 0) { 832*10923SEvan.Yan@Sun.COM if (basepath) 833*10923SEvan.Yan@Sun.COM free(basepath); 834*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 835*10923SEvan.Yan@Sun.COM hp_fini(root_list); 836*10923SEvan.Yan@Sun.COM *retp = NULL; 837*10923SEvan.Yan@Sun.COM return (rv); 838*10923SEvan.Yan@Sun.COM } 839*10923SEvan.Yan@Sun.COM } 840*10923SEvan.Yan@Sun.COM 841*10923SEvan.Yan@Sun.COM /* Store the base path in each root node */ 842*10923SEvan.Yan@Sun.COM if (basepath) { 843*10923SEvan.Yan@Sun.COM for (root = root_list; root; root = root->hp_sibling) 844*10923SEvan.Yan@Sun.COM root->hp_basepath = basepath; 845*10923SEvan.Yan@Sun.COM } 846*10923SEvan.Yan@Sun.COM 847*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 848*10923SEvan.Yan@Sun.COM *retp = root_list; 849*10923SEvan.Yan@Sun.COM return (0); 850*10923SEvan.Yan@Sun.COM } 851*10923SEvan.Yan@Sun.COM 852*10923SEvan.Yan@Sun.COM /* 853*10923SEvan.Yan@Sun.COM * i_hp_dprintf() 854*10923SEvan.Yan@Sun.COM * 855*10923SEvan.Yan@Sun.COM * Print debug messages to stderr, but only when the debug flag 856*10923SEvan.Yan@Sun.COM * (libhotplug_debug) is set. 857*10923SEvan.Yan@Sun.COM */ 858*10923SEvan.Yan@Sun.COM /*PRINTFLIKE1*/ 859*10923SEvan.Yan@Sun.COM static void 860*10923SEvan.Yan@Sun.COM i_hp_dprintf(const char *fmt, ...) 861*10923SEvan.Yan@Sun.COM { 862*10923SEvan.Yan@Sun.COM va_list ap; 863*10923SEvan.Yan@Sun.COM 864*10923SEvan.Yan@Sun.COM if (libhotplug_debug) { 865*10923SEvan.Yan@Sun.COM va_start(ap, fmt); 866*10923SEvan.Yan@Sun.COM (void) vfprintf(stderr, fmt, ap); 867*10923SEvan.Yan@Sun.COM va_end(ap); 868*10923SEvan.Yan@Sun.COM } 869*10923SEvan.Yan@Sun.COM } 870*10923SEvan.Yan@Sun.COM 871*10923SEvan.Yan@Sun.COM /* 872*10923SEvan.Yan@Sun.COM * i_hp_pack_branch() 873*10923SEvan.Yan@Sun.COM * 874*10923SEvan.Yan@Sun.COM * Pack an individual branch of a hotplug information snapshot. 875*10923SEvan.Yan@Sun.COM */ 876*10923SEvan.Yan@Sun.COM static int 877*10923SEvan.Yan@Sun.COM i_hp_pack_branch(hp_node_t root, char **bufp, size_t *lenp) 878*10923SEvan.Yan@Sun.COM { 879*10923SEvan.Yan@Sun.COM hp_node_t child; 880*10923SEvan.Yan@Sun.COM nvlist_t *nvl; 881*10923SEvan.Yan@Sun.COM char *buf; 882*10923SEvan.Yan@Sun.COM size_t len; 883*10923SEvan.Yan@Sun.COM int rv; 884*10923SEvan.Yan@Sun.COM 885*10923SEvan.Yan@Sun.COM *lenp = 0; 886*10923SEvan.Yan@Sun.COM *bufp = NULL; 887*10923SEvan.Yan@Sun.COM 888*10923SEvan.Yan@Sun.COM /* Allocate an nvlist for this branch */ 889*10923SEvan.Yan@Sun.COM if (nvlist_alloc(&nvl, 0, 0) != 0) 890*10923SEvan.Yan@Sun.COM return (ENOMEM); 891*10923SEvan.Yan@Sun.COM 892*10923SEvan.Yan@Sun.COM /* Pack the root of the branch and add it to the nvlist */ 893*10923SEvan.Yan@Sun.COM if ((rv = i_hp_pack_node(root, &buf, &len)) == 0) { 894*10923SEvan.Yan@Sun.COM rv = nvlist_add_byte_array(nvl, HP_INFO_NODE, 895*10923SEvan.Yan@Sun.COM (uchar_t *)buf, len); 896*10923SEvan.Yan@Sun.COM free(buf); 897*10923SEvan.Yan@Sun.COM } 898*10923SEvan.Yan@Sun.COM if (rv != 0) { 899*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 900*10923SEvan.Yan@Sun.COM return (rv); 901*10923SEvan.Yan@Sun.COM } 902*10923SEvan.Yan@Sun.COM 903*10923SEvan.Yan@Sun.COM /* Pack each subordinate branch, and add it to the nvlist */ 904*10923SEvan.Yan@Sun.COM for (child = root->hp_child; child != NULL; child = child->hp_sibling) { 905*10923SEvan.Yan@Sun.COM if ((rv = i_hp_pack_branch(child, &buf, &len)) == 0) { 906*10923SEvan.Yan@Sun.COM rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH, 907*10923SEvan.Yan@Sun.COM (uchar_t *)buf, len); 908*10923SEvan.Yan@Sun.COM free(buf); 909*10923SEvan.Yan@Sun.COM } 910*10923SEvan.Yan@Sun.COM if (rv != 0) { 911*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 912*10923SEvan.Yan@Sun.COM return (rv); 913*10923SEvan.Yan@Sun.COM } 914*10923SEvan.Yan@Sun.COM } 915*10923SEvan.Yan@Sun.COM 916*10923SEvan.Yan@Sun.COM /* Pack the resulting nvlist into a single buffer */ 917*10923SEvan.Yan@Sun.COM len = 0; 918*10923SEvan.Yan@Sun.COM buf = NULL; 919*10923SEvan.Yan@Sun.COM if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) { 920*10923SEvan.Yan@Sun.COM *lenp = len; 921*10923SEvan.Yan@Sun.COM *bufp = buf; 922*10923SEvan.Yan@Sun.COM } 923*10923SEvan.Yan@Sun.COM 924*10923SEvan.Yan@Sun.COM /* Free the nvlist */ 925*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 926*10923SEvan.Yan@Sun.COM 927*10923SEvan.Yan@Sun.COM return (rv); 928*10923SEvan.Yan@Sun.COM } 929*10923SEvan.Yan@Sun.COM 930*10923SEvan.Yan@Sun.COM /* 931*10923SEvan.Yan@Sun.COM * i_hp_pack_node() 932*10923SEvan.Yan@Sun.COM * 933*10923SEvan.Yan@Sun.COM * Pack an individual node of a hotplug information snapshot. 934*10923SEvan.Yan@Sun.COM */ 935*10923SEvan.Yan@Sun.COM static int 936*10923SEvan.Yan@Sun.COM i_hp_pack_node(hp_node_t node, char **bufp, size_t *lenp) 937*10923SEvan.Yan@Sun.COM { 938*10923SEvan.Yan@Sun.COM nvlist_t *nvl; 939*10923SEvan.Yan@Sun.COM char *buf = NULL; 940*10923SEvan.Yan@Sun.COM size_t len = 0; 941*10923SEvan.Yan@Sun.COM int rv; 942*10923SEvan.Yan@Sun.COM 943*10923SEvan.Yan@Sun.COM if (nvlist_alloc(&nvl, 0, 0) != 0) 944*10923SEvan.Yan@Sun.COM return (ENOMEM); 945*10923SEvan.Yan@Sun.COM 946*10923SEvan.Yan@Sun.COM if ((rv = nvlist_add_uint32(nvl, HP_INFO_TYPE, 947*10923SEvan.Yan@Sun.COM (uint32_t)node->hp_type)) != 0) 948*10923SEvan.Yan@Sun.COM goto fail; 949*10923SEvan.Yan@Sun.COM 950*10923SEvan.Yan@Sun.COM if ((node->hp_name) && 951*10923SEvan.Yan@Sun.COM ((rv = nvlist_add_string(nvl, HP_INFO_NAME, node->hp_name)) != 0)) 952*10923SEvan.Yan@Sun.COM goto fail; 953*10923SEvan.Yan@Sun.COM 954*10923SEvan.Yan@Sun.COM if ((node->hp_usage) && 955*10923SEvan.Yan@Sun.COM ((rv = nvlist_add_string(nvl, HP_INFO_USAGE, node->hp_usage)) != 0)) 956*10923SEvan.Yan@Sun.COM goto fail; 957*10923SEvan.Yan@Sun.COM 958*10923SEvan.Yan@Sun.COM if ((node->hp_description) && 959*10923SEvan.Yan@Sun.COM ((rv = nvlist_add_string(nvl, HP_INFO_DESC, 960*10923SEvan.Yan@Sun.COM node->hp_description)) != 0)) 961*10923SEvan.Yan@Sun.COM goto fail; 962*10923SEvan.Yan@Sun.COM 963*10923SEvan.Yan@Sun.COM if ((rv = nvlist_add_uint32(nvl, HP_INFO_STATE, node->hp_state)) != 0) 964*10923SEvan.Yan@Sun.COM goto fail; 965*10923SEvan.Yan@Sun.COM 966*10923SEvan.Yan@Sun.COM if ((node->hp_last_change != 0) && 967*10923SEvan.Yan@Sun.COM ((rv = nvlist_add_uint32(nvl, HP_INFO_TIME, 968*10923SEvan.Yan@Sun.COM node->hp_last_change)) != 0)) 969*10923SEvan.Yan@Sun.COM goto fail; 970*10923SEvan.Yan@Sun.COM 971*10923SEvan.Yan@Sun.COM if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0) 972*10923SEvan.Yan@Sun.COM goto fail; 973*10923SEvan.Yan@Sun.COM 974*10923SEvan.Yan@Sun.COM *bufp = buf; 975*10923SEvan.Yan@Sun.COM *lenp = len; 976*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 977*10923SEvan.Yan@Sun.COM return (0); 978*10923SEvan.Yan@Sun.COM 979*10923SEvan.Yan@Sun.COM fail: 980*10923SEvan.Yan@Sun.COM *bufp = NULL; 981*10923SEvan.Yan@Sun.COM *lenp = 0; 982*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 983*10923SEvan.Yan@Sun.COM return (rv); 984*10923SEvan.Yan@Sun.COM } 985*10923SEvan.Yan@Sun.COM 986*10923SEvan.Yan@Sun.COM /* 987*10923SEvan.Yan@Sun.COM * i_hp_unpack_branch() 988*10923SEvan.Yan@Sun.COM * 989*10923SEvan.Yan@Sun.COM * Unpack a branch of hotplug information nodes. 990*10923SEvan.Yan@Sun.COM */ 991*10923SEvan.Yan@Sun.COM static int 992*10923SEvan.Yan@Sun.COM i_hp_unpack_branch(char *packed_buf, size_t packed_len, hp_node_t parent, 993*10923SEvan.Yan@Sun.COM hp_node_t *retp) 994*10923SEvan.Yan@Sun.COM { 995*10923SEvan.Yan@Sun.COM hp_node_t node = NULL; 996*10923SEvan.Yan@Sun.COM hp_node_t child; 997*10923SEvan.Yan@Sun.COM hp_node_t prev_child = NULL; 998*10923SEvan.Yan@Sun.COM nvlist_t *nvl = NULL; 999*10923SEvan.Yan@Sun.COM nvpair_t *nvp; 1000*10923SEvan.Yan@Sun.COM char *buf; 1001*10923SEvan.Yan@Sun.COM size_t len; 1002*10923SEvan.Yan@Sun.COM int rv; 1003*10923SEvan.Yan@Sun.COM 1004*10923SEvan.Yan@Sun.COM /* Initialize results */ 1005*10923SEvan.Yan@Sun.COM *retp = NULL; 1006*10923SEvan.Yan@Sun.COM 1007*10923SEvan.Yan@Sun.COM /* Unpack the nvlist for this branch */ 1008*10923SEvan.Yan@Sun.COM if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0) 1009*10923SEvan.Yan@Sun.COM return (rv); 1010*10923SEvan.Yan@Sun.COM 1011*10923SEvan.Yan@Sun.COM /* 1012*10923SEvan.Yan@Sun.COM * Unpack the branch. The first item in the nvlist is 1013*10923SEvan.Yan@Sun.COM * always the root node. And zero or more subordinate 1014*10923SEvan.Yan@Sun.COM * branches may be packed afterward. 1015*10923SEvan.Yan@Sun.COM */ 1016*10923SEvan.Yan@Sun.COM for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) { 1017*10923SEvan.Yan@Sun.COM 1018*10923SEvan.Yan@Sun.COM len = 0; 1019*10923SEvan.Yan@Sun.COM buf = NULL; 1020*10923SEvan.Yan@Sun.COM 1021*10923SEvan.Yan@Sun.COM if (strcmp(nvpair_name(nvp), HP_INFO_NODE) == 0) { 1022*10923SEvan.Yan@Sun.COM 1023*10923SEvan.Yan@Sun.COM /* Check that there is only one root node */ 1024*10923SEvan.Yan@Sun.COM if (node != NULL) { 1025*10923SEvan.Yan@Sun.COM hp_fini(node); 1026*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 1027*10923SEvan.Yan@Sun.COM return (EFAULT); 1028*10923SEvan.Yan@Sun.COM } 1029*10923SEvan.Yan@Sun.COM 1030*10923SEvan.Yan@Sun.COM if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf, 1031*10923SEvan.Yan@Sun.COM (uint_t *)&len)) == 0) 1032*10923SEvan.Yan@Sun.COM rv = i_hp_unpack_node(buf, len, parent, &node); 1033*10923SEvan.Yan@Sun.COM 1034*10923SEvan.Yan@Sun.COM if (rv != 0) { 1035*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 1036*10923SEvan.Yan@Sun.COM return (rv); 1037*10923SEvan.Yan@Sun.COM } 1038*10923SEvan.Yan@Sun.COM 1039*10923SEvan.Yan@Sun.COM } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) { 1040*10923SEvan.Yan@Sun.COM 1041*10923SEvan.Yan@Sun.COM if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf, 1042*10923SEvan.Yan@Sun.COM (uint_t *)&len)) == 0) 1043*10923SEvan.Yan@Sun.COM rv = i_hp_unpack_branch(buf, len, node, &child); 1044*10923SEvan.Yan@Sun.COM 1045*10923SEvan.Yan@Sun.COM if (rv != 0) { 1046*10923SEvan.Yan@Sun.COM hp_fini(node); 1047*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 1048*10923SEvan.Yan@Sun.COM return (rv); 1049*10923SEvan.Yan@Sun.COM } 1050*10923SEvan.Yan@Sun.COM 1051*10923SEvan.Yan@Sun.COM if (prev_child) { 1052*10923SEvan.Yan@Sun.COM prev_child->hp_sibling = child; 1053*10923SEvan.Yan@Sun.COM } else { 1054*10923SEvan.Yan@Sun.COM node->hp_child = child; 1055*10923SEvan.Yan@Sun.COM } 1056*10923SEvan.Yan@Sun.COM prev_child = child; 1057*10923SEvan.Yan@Sun.COM } 1058*10923SEvan.Yan@Sun.COM } 1059*10923SEvan.Yan@Sun.COM 1060*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 1061*10923SEvan.Yan@Sun.COM *retp = node; 1062*10923SEvan.Yan@Sun.COM return (0); 1063*10923SEvan.Yan@Sun.COM } 1064*10923SEvan.Yan@Sun.COM 1065*10923SEvan.Yan@Sun.COM /* 1066*10923SEvan.Yan@Sun.COM * i_hp_unpack_node() 1067*10923SEvan.Yan@Sun.COM * 1068*10923SEvan.Yan@Sun.COM * Unpack an individual hotplug information node. 1069*10923SEvan.Yan@Sun.COM */ 1070*10923SEvan.Yan@Sun.COM static int 1071*10923SEvan.Yan@Sun.COM i_hp_unpack_node(char *buf, size_t len, hp_node_t parent, hp_node_t *retp) 1072*10923SEvan.Yan@Sun.COM { 1073*10923SEvan.Yan@Sun.COM hp_node_t node; 1074*10923SEvan.Yan@Sun.COM nvlist_t *nvl; 1075*10923SEvan.Yan@Sun.COM nvpair_t *nvp; 1076*10923SEvan.Yan@Sun.COM uint32_t val_uint32; 1077*10923SEvan.Yan@Sun.COM char *val_string; 1078*10923SEvan.Yan@Sun.COM int rv = 0; 1079*10923SEvan.Yan@Sun.COM 1080*10923SEvan.Yan@Sun.COM /* Initialize results */ 1081*10923SEvan.Yan@Sun.COM *retp = NULL; 1082*10923SEvan.Yan@Sun.COM 1083*10923SEvan.Yan@Sun.COM /* Unpack node into an nvlist */ 1084*10923SEvan.Yan@Sun.COM if ((nvlist_unpack(buf, len, &nvl, 0) != 0)) 1085*10923SEvan.Yan@Sun.COM return (EINVAL); 1086*10923SEvan.Yan@Sun.COM 1087*10923SEvan.Yan@Sun.COM /* Allocate the new node */ 1088*10923SEvan.Yan@Sun.COM if ((node = (hp_node_t)calloc(1, sizeof (struct hp_node))) == NULL) { 1089*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 1090*10923SEvan.Yan@Sun.COM return (ENOMEM); 1091*10923SEvan.Yan@Sun.COM } 1092*10923SEvan.Yan@Sun.COM 1093*10923SEvan.Yan@Sun.COM /* Iterate through nvlist, unpacking each field */ 1094*10923SEvan.Yan@Sun.COM for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) { 1095*10923SEvan.Yan@Sun.COM 1096*10923SEvan.Yan@Sun.COM if ((strcmp(nvpair_name(nvp), HP_INFO_TYPE) == 0) && 1097*10923SEvan.Yan@Sun.COM (nvpair_type(nvp) == DATA_TYPE_UINT32)) { 1098*10923SEvan.Yan@Sun.COM 1099*10923SEvan.Yan@Sun.COM (void) nvpair_value_uint32(nvp, &val_uint32); 1100*10923SEvan.Yan@Sun.COM node->hp_type = val_uint32; 1101*10923SEvan.Yan@Sun.COM 1102*10923SEvan.Yan@Sun.COM } else if ((strcmp(nvpair_name(nvp), HP_INFO_NAME) == 0) && 1103*10923SEvan.Yan@Sun.COM (nvpair_type(nvp) == DATA_TYPE_STRING)) { 1104*10923SEvan.Yan@Sun.COM 1105*10923SEvan.Yan@Sun.COM (void) nvpair_value_string(nvp, &val_string); 1106*10923SEvan.Yan@Sun.COM if ((node->hp_name = strdup(val_string)) == NULL) { 1107*10923SEvan.Yan@Sun.COM rv = ENOMEM; 1108*10923SEvan.Yan@Sun.COM break; 1109*10923SEvan.Yan@Sun.COM } 1110*10923SEvan.Yan@Sun.COM 1111*10923SEvan.Yan@Sun.COM } else if ((strcmp(nvpair_name(nvp), HP_INFO_STATE) == 0) && 1112*10923SEvan.Yan@Sun.COM (nvpair_type(nvp) == DATA_TYPE_UINT32)) { 1113*10923SEvan.Yan@Sun.COM 1114*10923SEvan.Yan@Sun.COM (void) nvpair_value_uint32(nvp, &val_uint32); 1115*10923SEvan.Yan@Sun.COM node->hp_state = val_uint32; 1116*10923SEvan.Yan@Sun.COM 1117*10923SEvan.Yan@Sun.COM } else if ((strcmp(nvpair_name(nvp), HP_INFO_USAGE) == 0) && 1118*10923SEvan.Yan@Sun.COM (nvpair_type(nvp) == DATA_TYPE_STRING)) { 1119*10923SEvan.Yan@Sun.COM 1120*10923SEvan.Yan@Sun.COM (void) nvpair_value_string(nvp, &val_string); 1121*10923SEvan.Yan@Sun.COM if ((node->hp_usage = strdup(val_string)) == NULL) { 1122*10923SEvan.Yan@Sun.COM rv = ENOMEM; 1123*10923SEvan.Yan@Sun.COM break; 1124*10923SEvan.Yan@Sun.COM } 1125*10923SEvan.Yan@Sun.COM 1126*10923SEvan.Yan@Sun.COM } else if ((strcmp(nvpair_name(nvp), HP_INFO_DESC) == 0) && 1127*10923SEvan.Yan@Sun.COM (nvpair_type(nvp) == DATA_TYPE_STRING)) { 1128*10923SEvan.Yan@Sun.COM 1129*10923SEvan.Yan@Sun.COM (void) nvpair_value_string(nvp, &val_string); 1130*10923SEvan.Yan@Sun.COM if ((node->hp_description = strdup(val_string)) 1131*10923SEvan.Yan@Sun.COM == NULL) { 1132*10923SEvan.Yan@Sun.COM rv = ENOMEM; 1133*10923SEvan.Yan@Sun.COM break; 1134*10923SEvan.Yan@Sun.COM } 1135*10923SEvan.Yan@Sun.COM 1136*10923SEvan.Yan@Sun.COM } else if ((strcmp(nvpair_name(nvp), HP_INFO_TIME) == 0) && 1137*10923SEvan.Yan@Sun.COM (nvpair_type(nvp) == DATA_TYPE_UINT32)) { 1138*10923SEvan.Yan@Sun.COM 1139*10923SEvan.Yan@Sun.COM (void) nvpair_value_uint32(nvp, &val_uint32); 1140*10923SEvan.Yan@Sun.COM node->hp_last_change = (time_t)val_uint32; 1141*10923SEvan.Yan@Sun.COM 1142*10923SEvan.Yan@Sun.COM } else { 1143*10923SEvan.Yan@Sun.COM i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n", 1144*10923SEvan.Yan@Sun.COM nvpair_name(nvp)); 1145*10923SEvan.Yan@Sun.COM } 1146*10923SEvan.Yan@Sun.COM } 1147*10923SEvan.Yan@Sun.COM 1148*10923SEvan.Yan@Sun.COM /* Unpacked nvlist no longer needed */ 1149*10923SEvan.Yan@Sun.COM nvlist_free(nvl); 1150*10923SEvan.Yan@Sun.COM 1151*10923SEvan.Yan@Sun.COM /* Check for errors */ 1152*10923SEvan.Yan@Sun.COM if (rv != 0) { 1153*10923SEvan.Yan@Sun.COM hp_fini(node); 1154*10923SEvan.Yan@Sun.COM return (rv); 1155*10923SEvan.Yan@Sun.COM } 1156*10923SEvan.Yan@Sun.COM 1157*10923SEvan.Yan@Sun.COM /* Success */ 1158*10923SEvan.Yan@Sun.COM node->hp_parent = parent; 1159*10923SEvan.Yan@Sun.COM *retp = node; 1160*10923SEvan.Yan@Sun.COM return (0); 1161*10923SEvan.Yan@Sun.COM } 1162*10923SEvan.Yan@Sun.COM 1163*10923SEvan.Yan@Sun.COM /* 1164*10923SEvan.Yan@Sun.COM * i_hp_call_hotplugd() 1165*10923SEvan.Yan@Sun.COM * 1166*10923SEvan.Yan@Sun.COM * Perform a door call to the hotplug daemon. 1167*10923SEvan.Yan@Sun.COM */ 1168*10923SEvan.Yan@Sun.COM static int 1169*10923SEvan.Yan@Sun.COM i_hp_call_hotplugd(nvlist_t *args, nvlist_t **resultsp) 1170*10923SEvan.Yan@Sun.COM { 1171*10923SEvan.Yan@Sun.COM door_arg_t door_arg; 1172*10923SEvan.Yan@Sun.COM nvlist_t *results = NULL; 1173*10923SEvan.Yan@Sun.COM char *buf = NULL; 1174*10923SEvan.Yan@Sun.COM size_t len = 0; 1175*10923SEvan.Yan@Sun.COM uint64_t seqnum; 1176*10923SEvan.Yan@Sun.COM int door_fd; 1177*10923SEvan.Yan@Sun.COM int rv; 1178*10923SEvan.Yan@Sun.COM 1179*10923SEvan.Yan@Sun.COM /* Initialize results */ 1180*10923SEvan.Yan@Sun.COM *resultsp = NULL; 1181*10923SEvan.Yan@Sun.COM 1182*10923SEvan.Yan@Sun.COM /* Open door */ 1183*10923SEvan.Yan@Sun.COM if ((door_fd = open(HOTPLUGD_DOOR, O_RDONLY)) < 0) { 1184*10923SEvan.Yan@Sun.COM i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n", 1185*10923SEvan.Yan@Sun.COM strerror(errno)); 1186*10923SEvan.Yan@Sun.COM return (EBADF); 1187*10923SEvan.Yan@Sun.COM } 1188*10923SEvan.Yan@Sun.COM 1189*10923SEvan.Yan@Sun.COM /* Pack the nvlist of arguments */ 1190*10923SEvan.Yan@Sun.COM if ((rv = nvlist_pack(args, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0) { 1191*10923SEvan.Yan@Sun.COM i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n", 1192*10923SEvan.Yan@Sun.COM strerror(rv)); 1193*10923SEvan.Yan@Sun.COM return (rv); 1194*10923SEvan.Yan@Sun.COM } 1195*10923SEvan.Yan@Sun.COM 1196*10923SEvan.Yan@Sun.COM /* Set the door argument using the packed arguments */ 1197*10923SEvan.Yan@Sun.COM door_arg.data_ptr = buf; 1198*10923SEvan.Yan@Sun.COM door_arg.data_size = len; 1199*10923SEvan.Yan@Sun.COM door_arg.desc_ptr = NULL; 1200*10923SEvan.Yan@Sun.COM door_arg.desc_num = 0; 1201*10923SEvan.Yan@Sun.COM door_arg.rbuf = (char *)(uintptr_t)&rv; 1202*10923SEvan.Yan@Sun.COM door_arg.rsize = sizeof (rv); 1203*10923SEvan.Yan@Sun.COM 1204*10923SEvan.Yan@Sun.COM /* Attempt the door call */ 1205*10923SEvan.Yan@Sun.COM if (door_call(door_fd, &door_arg) != 0) { 1206*10923SEvan.Yan@Sun.COM rv = errno; 1207*10923SEvan.Yan@Sun.COM i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n", 1208*10923SEvan.Yan@Sun.COM strerror(rv)); 1209*10923SEvan.Yan@Sun.COM (void) close(door_fd); 1210*10923SEvan.Yan@Sun.COM free(buf); 1211*10923SEvan.Yan@Sun.COM return (rv); 1212*10923SEvan.Yan@Sun.COM } 1213*10923SEvan.Yan@Sun.COM 1214*10923SEvan.Yan@Sun.COM /* The arguments are no longer needed */ 1215*10923SEvan.Yan@Sun.COM free(buf); 1216*10923SEvan.Yan@Sun.COM 1217*10923SEvan.Yan@Sun.COM /* 1218*10923SEvan.Yan@Sun.COM * If results are not in the original buffer provided, 1219*10923SEvan.Yan@Sun.COM * then check and process the new results buffer. 1220*10923SEvan.Yan@Sun.COM */ 1221*10923SEvan.Yan@Sun.COM if (door_arg.rbuf != (char *)(uintptr_t)&rv) { 1222*10923SEvan.Yan@Sun.COM 1223*10923SEvan.Yan@Sun.COM /* 1224*10923SEvan.Yan@Sun.COM * First check that the buffer is valid. Then check for 1225*10923SEvan.Yan@Sun.COM * the simple case where a short result code was sent. 1226*10923SEvan.Yan@Sun.COM * The last case is a packed nvlist was returned, which 1227*10923SEvan.Yan@Sun.COM * needs to be unpacked. 1228*10923SEvan.Yan@Sun.COM */ 1229*10923SEvan.Yan@Sun.COM if ((door_arg.rbuf == NULL) || 1230*10923SEvan.Yan@Sun.COM (door_arg.data_size < sizeof (rv))) { 1231*10923SEvan.Yan@Sun.COM i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n"); 1232*10923SEvan.Yan@Sun.COM rv = EFAULT; 1233*10923SEvan.Yan@Sun.COM 1234*10923SEvan.Yan@Sun.COM } else if (door_arg.data_size == sizeof (rv)) { 1235*10923SEvan.Yan@Sun.COM rv = *(int *)(uintptr_t)door_arg.rbuf; 1236*10923SEvan.Yan@Sun.COM 1237*10923SEvan.Yan@Sun.COM } else if ((rv = nvlist_unpack(door_arg.rbuf, 1238*10923SEvan.Yan@Sun.COM door_arg.data_size, &results, 0)) != 0) { 1239*10923SEvan.Yan@Sun.COM i_hp_dprintf("i_hp_call_hotplugd: " 1240*10923SEvan.Yan@Sun.COM "cannot unpack results (%s).\n", strerror(rv)); 1241*10923SEvan.Yan@Sun.COM results = NULL; 1242*10923SEvan.Yan@Sun.COM rv = EFAULT; 1243*10923SEvan.Yan@Sun.COM } 1244*10923SEvan.Yan@Sun.COM 1245*10923SEvan.Yan@Sun.COM /* Unmap the results buffer */ 1246*10923SEvan.Yan@Sun.COM if (door_arg.rbuf != NULL) 1247*10923SEvan.Yan@Sun.COM (void) munmap(door_arg.rbuf, door_arg.rsize); 1248*10923SEvan.Yan@Sun.COM 1249*10923SEvan.Yan@Sun.COM /* 1250*10923SEvan.Yan@Sun.COM * In the case of a packed nvlist, notify the daemon 1251*10923SEvan.Yan@Sun.COM * that it can free the result buffer from its heap. 1252*10923SEvan.Yan@Sun.COM */ 1253*10923SEvan.Yan@Sun.COM if ((results != NULL) && 1254*10923SEvan.Yan@Sun.COM (nvlist_lookup_uint64(results, HPD_SEQNUM, &seqnum) == 0)) { 1255*10923SEvan.Yan@Sun.COM door_arg.data_ptr = (char *)(uintptr_t)&seqnum; 1256*10923SEvan.Yan@Sun.COM door_arg.data_size = sizeof (seqnum); 1257*10923SEvan.Yan@Sun.COM door_arg.desc_ptr = NULL; 1258*10923SEvan.Yan@Sun.COM door_arg.desc_num = 0; 1259*10923SEvan.Yan@Sun.COM door_arg.rbuf = NULL; 1260*10923SEvan.Yan@Sun.COM door_arg.rsize = 0; 1261*10923SEvan.Yan@Sun.COM (void) door_call(door_fd, &door_arg); 1262*10923SEvan.Yan@Sun.COM if (door_arg.rbuf != NULL) 1263*10923SEvan.Yan@Sun.COM (void) munmap(door_arg.rbuf, door_arg.rsize); 1264*10923SEvan.Yan@Sun.COM } 1265*10923SEvan.Yan@Sun.COM 1266*10923SEvan.Yan@Sun.COM *resultsp = results; 1267*10923SEvan.Yan@Sun.COM } 1268*10923SEvan.Yan@Sun.COM 1269*10923SEvan.Yan@Sun.COM (void) close(door_fd); 1270*10923SEvan.Yan@Sun.COM return (rv); 1271*10923SEvan.Yan@Sun.COM } 1272*10923SEvan.Yan@Sun.COM 1273*10923SEvan.Yan@Sun.COM /* 1274*10923SEvan.Yan@Sun.COM * i_hp_set_args() 1275*10923SEvan.Yan@Sun.COM * 1276*10923SEvan.Yan@Sun.COM * Construct an nvlist of arguments for a hotplugd door call. 1277*10923SEvan.Yan@Sun.COM */ 1278*10923SEvan.Yan@Sun.COM static nvlist_t * 1279*10923SEvan.Yan@Sun.COM i_hp_set_args(hp_cmd_t cmd, const char *path, const char *connection, 1280*10923SEvan.Yan@Sun.COM uint_t flags, const char *options, int state) 1281*10923SEvan.Yan@Sun.COM { 1282*10923SEvan.Yan@Sun.COM nvlist_t *args; 1283*10923SEvan.Yan@Sun.COM 1284*10923SEvan.Yan@Sun.COM /* Allocate a new nvlist */ 1285*10923SEvan.Yan@Sun.COM if (nvlist_alloc(&args, NV_UNIQUE_NAME_TYPE, 0) != 0) 1286*10923SEvan.Yan@Sun.COM return (NULL); 1287*10923SEvan.Yan@Sun.COM 1288*10923SEvan.Yan@Sun.COM /* Add common arguments */ 1289*10923SEvan.Yan@Sun.COM if ((nvlist_add_int32(args, HPD_CMD, cmd) != 0) || 1290*10923SEvan.Yan@Sun.COM (nvlist_add_string(args, HPD_PATH, path) != 0)) { 1291*10923SEvan.Yan@Sun.COM nvlist_free(args); 1292*10923SEvan.Yan@Sun.COM return (NULL); 1293*10923SEvan.Yan@Sun.COM } 1294*10923SEvan.Yan@Sun.COM 1295*10923SEvan.Yan@Sun.COM /* Add connection, but only if defined */ 1296*10923SEvan.Yan@Sun.COM if ((connection != NULL) && (connection[0] != '\0') && 1297*10923SEvan.Yan@Sun.COM (nvlist_add_string(args, HPD_CONNECTION, connection) != 0)) { 1298*10923SEvan.Yan@Sun.COM nvlist_free(args); 1299*10923SEvan.Yan@Sun.COM return (NULL); 1300*10923SEvan.Yan@Sun.COM } 1301*10923SEvan.Yan@Sun.COM 1302*10923SEvan.Yan@Sun.COM /* Add flags, but only if defined */ 1303*10923SEvan.Yan@Sun.COM if ((flags != 0) && (nvlist_add_uint32(args, HPD_FLAGS, flags) != 0)) { 1304*10923SEvan.Yan@Sun.COM nvlist_free(args); 1305*10923SEvan.Yan@Sun.COM return (NULL); 1306*10923SEvan.Yan@Sun.COM } 1307*10923SEvan.Yan@Sun.COM 1308*10923SEvan.Yan@Sun.COM /* Add options, but only if defined */ 1309*10923SEvan.Yan@Sun.COM if ((options != NULL) && 1310*10923SEvan.Yan@Sun.COM (nvlist_add_string(args, HPD_OPTIONS, options) != 0)) { 1311*10923SEvan.Yan@Sun.COM nvlist_free(args); 1312*10923SEvan.Yan@Sun.COM return (NULL); 1313*10923SEvan.Yan@Sun.COM } 1314*10923SEvan.Yan@Sun.COM 1315*10923SEvan.Yan@Sun.COM /* Add state, but only for CHANGESTATE command */ 1316*10923SEvan.Yan@Sun.COM if ((cmd == HP_CMD_CHANGESTATE) && 1317*10923SEvan.Yan@Sun.COM (nvlist_add_int32(args, HPD_STATE, state) != 0)) { 1318*10923SEvan.Yan@Sun.COM nvlist_free(args); 1319*10923SEvan.Yan@Sun.COM return (NULL); 1320*10923SEvan.Yan@Sun.COM } 1321*10923SEvan.Yan@Sun.COM 1322*10923SEvan.Yan@Sun.COM return (args); 1323*10923SEvan.Yan@Sun.COM } 1324*10923SEvan.Yan@Sun.COM 1325*10923SEvan.Yan@Sun.COM /* 1326*10923SEvan.Yan@Sun.COM * i_hp_parse_results() 1327*10923SEvan.Yan@Sun.COM * 1328*10923SEvan.Yan@Sun.COM * Parse out individual fields of an nvlist of results from 1329*10923SEvan.Yan@Sun.COM * a hotplugd door call. 1330*10923SEvan.Yan@Sun.COM */ 1331*10923SEvan.Yan@Sun.COM static int 1332*10923SEvan.Yan@Sun.COM i_hp_parse_results(nvlist_t *results, hp_node_t *rootp, char **optionsp) 1333*10923SEvan.Yan@Sun.COM { 1334*10923SEvan.Yan@Sun.COM int rv; 1335*10923SEvan.Yan@Sun.COM 1336*10923SEvan.Yan@Sun.COM /* Parse an information snapshot */ 1337*10923SEvan.Yan@Sun.COM if (rootp) { 1338*10923SEvan.Yan@Sun.COM char *buf = NULL; 1339*10923SEvan.Yan@Sun.COM size_t len = 0; 1340*10923SEvan.Yan@Sun.COM 1341*10923SEvan.Yan@Sun.COM *rootp = NULL; 1342*10923SEvan.Yan@Sun.COM if (nvlist_lookup_byte_array(results, HPD_INFO, 1343*10923SEvan.Yan@Sun.COM (uchar_t **)&buf, (uint_t *)&len) == 0) { 1344*10923SEvan.Yan@Sun.COM if ((rv = hp_unpack(buf, len, rootp)) != 0) 1345*10923SEvan.Yan@Sun.COM return (rv); 1346*10923SEvan.Yan@Sun.COM } 1347*10923SEvan.Yan@Sun.COM } 1348*10923SEvan.Yan@Sun.COM 1349*10923SEvan.Yan@Sun.COM /* Parse a bus private option string */ 1350*10923SEvan.Yan@Sun.COM if (optionsp) { 1351*10923SEvan.Yan@Sun.COM char *str; 1352*10923SEvan.Yan@Sun.COM 1353*10923SEvan.Yan@Sun.COM *optionsp = NULL; 1354*10923SEvan.Yan@Sun.COM if ((nvlist_lookup_string(results, HPD_OPTIONS, &str) == 0) && 1355*10923SEvan.Yan@Sun.COM ((*optionsp = strdup(str)) == NULL)) { 1356*10923SEvan.Yan@Sun.COM return (ENOMEM); 1357*10923SEvan.Yan@Sun.COM } 1358*10923SEvan.Yan@Sun.COM } 1359*10923SEvan.Yan@Sun.COM 1360*10923SEvan.Yan@Sun.COM /* Parse result code of the operation */ 1361*10923SEvan.Yan@Sun.COM if (nvlist_lookup_int32(results, HPD_STATUS, &rv) != 0) { 1362*10923SEvan.Yan@Sun.COM i_hp_dprintf("i_hp_call_hotplugd: missing status.\n"); 1363*10923SEvan.Yan@Sun.COM return (EFAULT); 1364*10923SEvan.Yan@Sun.COM } 1365*10923SEvan.Yan@Sun.COM 1366*10923SEvan.Yan@Sun.COM return (rv); 1367*10923SEvan.Yan@Sun.COM } 1368