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