269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The contents of this file are subject to the terms of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common Development and Distribution License (the "License").
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You may not use this file except in compliance with the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * or http://www.opensolaris.org/os/licensing.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
269473047d747f7815af570197e4ef7322d3632cEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If applicable, add the following below this CDDL HEADER, with the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <stdio.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <stdlib.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <stdarg.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <unistd.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <fcntl.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <errno.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <string.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <door.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libnvpair.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libhotplug.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <libhotplug_impl.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi_hp.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void i_hp_dprintf(const char *fmt, ...);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int i_hp_pack_branch(hp_node_t, char **, size_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int i_hp_pack_node(hp_node_t, char **, size_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int i_hp_unpack_node(char *, size_t, hp_node_t, hp_node_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int i_hp_unpack_branch(char *, size_t, hp_node_t, hp_node_t *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int i_hp_call_hotplugd(nvlist_t *, nvlist_t **);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic nvlist_t *i_hp_set_args(hp_cmd_t, const char *, const char *, uint_t,
269473047d747f7815af570197e4ef7322d3632cEvan Yan const char *, int);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int i_hp_parse_results(nvlist_t *, hp_node_t *, char **);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Global flag to enable debug features.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint libhotplug_debug = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_init()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Initialize a hotplug information snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_node_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_init(const char *path, const char *connection, uint_t flags)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *args;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *results;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t root = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_init: path=%p, connection=%p, flags=0x%x\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)path, (void *)connection, flags);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((path == NULL) || !HP_INIT_FLAGS_VALID(flags)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_init: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Build arguments for door call */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((args = i_hp_set_args(HP_CMD_GETINFO, path, connection, flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan NULL, 0)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_init: cannot build arguments nvlist.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Make the door call to hotplugd */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_call_hotplugd(args, &results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Arguments no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse additional results, if any */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv == 0) && (results != NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_parse_results(results, &root, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check for errors */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_init: failure (%s).\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root)
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Success requires an info snapshot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_init: missing info snapshot.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Success */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_fini()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Terminate and clean-up a hotplug information snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_fini(hp_node_t root)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t sibling;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *basepath;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_fini: root=%p\n", (void *)root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_fini: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Extract and free base path */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root->hp_basepath) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan basepath = root->hp_basepath;
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (node = root; node != NULL; node = node->hp_sibling)
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_basepath = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(basepath);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Destroy the nodes */
269473047d747f7815af570197e4ef7322d3632cEvan Yan node = root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (node) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan sibling = node->hp_sibling;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_child)
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(node->hp_child);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_name)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(node->hp_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_usage)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(node->hp_usage);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_description)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(node->hp_description);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan node = sibling;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_traverse()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Walk a graph of hotplug nodes, executing a callback on each node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_traverse(hp_node_t root, void *arg, int (*hp_callback)(hp_node_t, void *arg))
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)root, arg, (void *)hp_callback);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((root == NULL) || (hp_callback == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_traverse: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (node = root; node; node = node->hp_sibling) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = hp_callback(node, arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv == HP_WALK_TERMINATE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_traverse: walk terminated.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_child && (rv != HP_WALK_PRUNECHILD))
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (hp_traverse(node->hp_child, arg, hp_callback) ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan HP_WALK_TERMINATE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_traverse: walk terminated.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (HP_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv == HP_WALK_PRUNESIBLING)
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_type()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a node's type.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_type(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_type: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_type: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_type);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_name()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a node's name.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanchar *
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_name(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_name: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_name: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_name == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_name: missing name value.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_state()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a node's current state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_state(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_state: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_state: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (node->hp_type != HP_NODE_PORT)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_state: operation not supported.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_usage()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a usage description for usage nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanchar *
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_usage(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_usage: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_usage: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_type != HP_NODE_USAGE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_usage: operation not supported.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_usage == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_usage: missing usage value.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_usage);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_description()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a type description (e.g. "PCI slot") for connection nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanchar *
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_description(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_description: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_description: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (node->hp_type != HP_NODE_PORT)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_description: operation not supported.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_description == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_description: missing description value.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_description);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_last_change()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return when the state of a connection was last changed.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yantime_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_last_change(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_last_change: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_last_change: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (node->hp_type != HP_NODE_PORT)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_last_change: operation not supported.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_last_change);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_parent()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a node's parent node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_node_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_parent(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_parent: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_parent: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_parent == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_parent: node has no parent.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENXIO;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_parent);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_child()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a node's first child node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_node_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_child(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_child: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_child: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_child == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_child: node has no child.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENXIO;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_child);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_sibling()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a node's next sibling node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_node_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_sibling(hp_node_t node)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_sibling: node=%p\n", (void *)node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_sibling: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_sibling == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_sibling: node has no sibling.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = ENXIO;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (node->hp_sibling);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_path()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return the path (and maybe connection name) of a node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The caller must supply two buffers, each MAXPATHLEN size.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_path(hp_node_t node, char *path, char *connection)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t parent;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int i;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *s;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char components[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_path: node=%p, path=%p, connection=%p\n", (void *)node,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)path, (void *)connection);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node == NULL) || (path == NULL) || (connection == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_path: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(path, 0, MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(connection, 0, MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) memset(components, 0, MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Set 'connection' only for connectors and ports */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_type == HP_NODE_CONNECTOR) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (node->hp_type == HP_NODE_PORT))
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcpy(connection, node->hp_name, MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Trace back to the root node, accumulating components */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (parent = node; parent != NULL; parent = parent->hp_parent) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (parent->hp_type == HP_NODE_DEVICE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(components, "/", MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(components, parent->hp_name, MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (parent->hp_parent == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan root = parent;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Ensure the snapshot actually contains a base path */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root->hp_basepath == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_path: missing base pathname.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EFAULT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Construct the path. Start with the base path from the root
269473047d747f7815af570197e4ef7322d3632cEvan Yan * node, then append the accumulated components in reverse order.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(root->hp_basepath, "/") != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(path, root->hp_basepath, MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((root->hp_type == HP_NODE_DEVICE) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((s = strrchr(path, '/')) != NULL))
269473047d747f7815af570197e4ef7322d3632cEvan Yan *s = '\0';
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = strlen(components) - 1; i >= 0; i--) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (components[i] == '/') {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strlcat(path, &components[i], MAXPATHLEN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan components[i] = '\0';
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_set_state()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Initiate a state change operation on a node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_set_state(hp_node_t node, uint_t flags, int state, hp_node_t *resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t root = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *args;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *results;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan char connection[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "resultsp=%p\n", (void *)node, flags, state, (void *)resultsp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node == NULL) || (resultsp == NULL) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan !HP_SET_STATE_FLAGS_VALID(flags)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_state: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check node type */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (node->hp_type != HP_NODE_PORT)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_state: operation not supported.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOTSUP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check that target state is valid */
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_PRESENT:
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_POWERED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_ENABLED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_type != HP_NODE_CONNECTOR) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_state: mismatched target.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOTSUP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_PORT_PRESENT:
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_OFFLINE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_ONLINE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_type != HP_NODE_PORT) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_state: mismatched target.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOTSUP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_state: invalid target state.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get path and connection of specified node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = hp_path(node, path, connection)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Build arguments for door call */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((args = i_hp_set_args(HP_CMD_CHANGESTATE, path, connection, flags,
269473047d747f7815af570197e4ef7322d3632cEvan Yan NULL, state)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Make the door call to hotplugd */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_call_hotplugd(args, &results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Arguments no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse additional results, if any */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv == 0) && (results != NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_parse_results(results, &root, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Done */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_set_private()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Set bus private options on the hotplug connection
269473047d747f7815af570197e4ef7322d3632cEvan Yan * indicated by the given hotplug information node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_set_private(hp_node_t node, const char *options, char **resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *args;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *results;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *values = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan char connection[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)node, (void *)options, (void *)resultsp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_private: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check node type */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_type != HP_NODE_CONNECTOR) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_set_private: operation not supported.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOTSUP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get path and connection of specified node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = hp_path(node, path, connection)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Build arguments for door call */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((args = i_hp_set_args(HP_CMD_SETPRIVATE, path, connection, 0,
269473047d747f7815af570197e4ef7322d3632cEvan Yan options, 0)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Make the door call to hotplugd */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_call_hotplugd(args, &results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Arguments no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse additional results, if any */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv == 0) && (results != NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_parse_results(results, NULL, &values);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = values;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Done */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_get_private()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Get bus private options on the hotplug connection
269473047d747f7815af570197e4ef7322d3632cEvan Yan * indicated by the given hotplug information node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_get_private(hp_node_t node, const char *options, char **resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *args;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *results;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *values = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan char connection[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)node, (void *)options, (void *)resultsp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_get_private: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check node type */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node->hp_type != HP_NODE_CONNECTOR) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_get_private: operation not supported.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOTSUP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get path and connection of specified node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = hp_path(node, path, connection)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Build arguments for door call */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((args = i_hp_set_args(HP_CMD_GETPRIVATE, path, connection, 0,
269473047d747f7815af570197e4ef7322d3632cEvan Yan options, 0)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Make the door call to hotplugd */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_call_hotplugd(args, &results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Arguments no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse additional results, if any */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv == 0) && (results != NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_parse_results(results, NULL, &values);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(results);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = values;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Done */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_pack()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Given the root of a hotplug information snapshot, pack
269473047d747f7815af570197e4ef7322d3632cEvan Yan * it into a contiguous byte array so that it is suitable
269473047d747f7815af570197e4ef7322d3632cEvan Yan * for network transport.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_pack(hp_node_t root, char **bufp, size_t *lenp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_pack: root=%p, bufp=%p, lenp=%p\n", (void *)root,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)bufp, (void *)lenp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((root == NULL) || (bufp == NULL) || (lenp == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_pack: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *lenp = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *bufp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&nvl, 0, 0) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (root->hp_basepath != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = nvlist_add_string(nvl, HP_INFO_BASE, root->hp_basepath);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (node = root; node != NULL; node = node->hp_sibling) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = i_hp_pack_branch(node, &buf, &len)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uchar_t *)buf, len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(buf);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan *lenp = len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *bufp = buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hp_unpack()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unpack a hotplug information snapshot for normal usage.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanhp_unpack(char *packed_buf, size_t packed_len, hp_node_t *retp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t root_list = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t prev_root = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvpair_t *nvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *basepath = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)packed_buf, (uint32_t)packed_len, (void *)retp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((packed_buf == NULL) || (packed_len == 0) || (retp == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("hp_unpack: invalid arguments.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_next_nvpair(nvl, NULL) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan errno = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(nvpair_name(nvp), HP_INFO_BASE) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *val_string;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvpair_value_string(nvp, &val_string)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((basepath = strdup(val_string)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvpair_value_byte_array(nvp,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uchar_t **)&buf, (uint_t *)&len)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_unpack_branch(buf, len, NULL, &root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (prev_root) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev_root->hp_sibling = root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan root_list = root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev_root = root;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (basepath)
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(basepath);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(root_list);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Store the base path in each root node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (basepath) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (root = root_list; root; root = root->hp_sibling)
269473047d747f7815af570197e4ef7322d3632cEvan Yan root->hp_basepath = basepath;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = root_list;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_dprintf()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Print debug messages to stderr, but only when the debug flag
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (libhotplug_debug) is set.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*PRINTFLIKE1*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_dprintf(const char *fmt, ...)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan va_list ap;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (libhotplug_debug) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan va_start(ap, fmt);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) vfprintf(stderr, fmt, ap);
269473047d747f7815af570197e4ef7322d3632cEvan Yan va_end(ap);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_pack_branch()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Pack an individual branch of a hotplug information snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_pack_branch(hp_node_t root, char **bufp, size_t *lenp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *lenp = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *bufp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate an nvlist for this branch */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&nvl, 0, 0) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack the root of the branch and add it to the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = i_hp_pack_node(root, &buf, &len)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = nvlist_add_byte_array(nvl, HP_INFO_NODE,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uchar_t *)buf, len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(buf);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack each subordinate branch, and add it to the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (child = root->hp_child; child != NULL; child = child->hp_sibling) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = i_hp_pack_branch(child, &buf, &len)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uchar_t *)buf, len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(buf);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack the resulting nvlist into a single buffer */
269473047d747f7815af570197e4ef7322d3632cEvan Yan len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan *lenp = len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *bufp = buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Free the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_pack_node()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Pack an individual node of a hotplug information snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_pack_node(hp_node_t node, char **bufp, size_t *lenp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&nvl, 0, 0) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_add_uint32(nvl, HP_INFO_TYPE,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uint32_t)node->hp_type)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_name) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((rv = nvlist_add_string(nvl, HP_INFO_NAME, node->hp_name)) != 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_usage) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((rv = nvlist_add_string(nvl, HP_INFO_USAGE, node->hp_usage)) != 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_description) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((rv = nvlist_add_string(nvl, HP_INFO_DESC,
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_description)) != 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_add_uint32(nvl, HP_INFO_STATE, node->hp_state)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_last_change != 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((rv = nvlist_add_uint32(nvl, HP_INFO_TIME,
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_last_change)) != 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto fail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *bufp = buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *lenp = len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanfail:
269473047d747f7815af570197e4ef7322d3632cEvan Yan *bufp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *lenp = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_unpack_branch()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unpack a branch of hotplug information nodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_unpack_branch(char *packed_buf, size_t packed_len, hp_node_t parent,
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t *retp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t prev_child = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvpair_t *nvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unpack the nvlist for this branch */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unpack the branch. The first item in the nvlist is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * always the root node. And zero or more subordinate
269473047d747f7815af570197e4ef7322d3632cEvan Yan * branches may be packed afterward.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(nvpair_name(nvp), HP_INFO_NODE) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check that there is only one root node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (node != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EFAULT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uint_t *)&len)) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_unpack_node(buf, len, parent, &node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uint_t *)&len)) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = i_hp_unpack_branch(buf, len, node, &child);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (prev_child) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev_child->hp_sibling = child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_child = child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev_child = child;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_unpack_node()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unpack an individual hotplug information node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_unpack_node(char *buf, size_t len, hp_node_t parent, hp_node_t *retp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_node_t node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *nvl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvpair_t *nvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint32_t val_uint32;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *val_string;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unpack node into an nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_unpack(buf, len, &nvl, 0) != 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate the new node */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node = (hp_node_t)calloc(1, sizeof (struct hp_node))) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Iterate through nvlist, unpacking each field */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((strcmp(nvpair_name(nvp), HP_INFO_TYPE) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_uint32(nvp, &val_uint32);
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_type = val_uint32;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_NAME) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) == DATA_TYPE_STRING)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_string(nvp, &val_string);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_name = strdup(val_string)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_STATE) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_uint32(nvp, &val_uint32);
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_state = val_uint32;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_USAGE) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) == DATA_TYPE_STRING)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_string(nvp, &val_string);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_usage = strdup(val_string)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_DESC) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) == DATA_TYPE_STRING)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_string(nvp, &val_string);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node->hp_description = strdup(val_string))
269473047d747f7815af570197e4ef7322d3632cEvan Yan == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_TIME) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvpair_value_uint32(nvp, &val_uint32);
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_last_change = (time_t)val_uint32;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvpair_name(nvp));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unpacked nvlist no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(nvl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check for errors */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan hp_fini(node);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Success */
269473047d747f7815af570197e4ef7322d3632cEvan Yan node->hp_parent = parent;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *retp = node;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_call_hotplugd()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Perform a door call to the hotplug daemon.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_call_hotplugd(nvlist_t *args, nvlist_t **resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg_t door_arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *results = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint64_t seqnum;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int door_fd;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Open door */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((door_fd = open(HOTPLUGD_DOOR, O_RDONLY)) < 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EBADF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack the nvlist of arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = nvlist_pack(args, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Set the door argument using the packed arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.data_ptr = buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.data_size = len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.desc_ptr = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.desc_num = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.rbuf = (char *)(uintptr_t)&rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.rsize = sizeof (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Attempt the door call */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (door_call(door_fd, &door_arg) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = errno;
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) close(door_fd);
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(buf);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The arguments are no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan free(buf);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If results are not in the original buffer provided,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * then check and process the new results buffer.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (door_arg.rbuf != (char *)(uintptr_t)&rv) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * First check that the buffer is valid. Then check for
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the simple case where a short result code was sent.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The last case is a packed nvlist was returned, which
269473047d747f7815af570197e4ef7322d3632cEvan Yan * needs to be unpacked.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((door_arg.rbuf == NULL) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (door_arg.data_size < sizeof (rv))) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (door_arg.data_size == sizeof (rv)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = *(int *)(uintptr_t)door_arg.rbuf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if ((rv = nvlist_unpack(door_arg.rbuf,
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.data_size, &results, 0)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("i_hp_call_hotplugd: "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "cannot unpack results (%s).\n", strerror(rv));
269473047d747f7815af570197e4ef7322d3632cEvan Yan results = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = EFAULT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unmap the results buffer */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (door_arg.rbuf != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) munmap(door_arg.rbuf, door_arg.rsize);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * In the case of a packed nvlist, notify the daemon
269473047d747f7815af570197e4ef7322d3632cEvan Yan * that it can free the result buffer from its heap.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((results != NULL) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_lookup_uint64(results, HPD_SEQNUM, &seqnum) == 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.data_ptr = (char *)(uintptr_t)&seqnum;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.data_size = sizeof (seqnum);
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.desc_ptr = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.desc_num = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.rbuf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan door_arg.rsize = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) door_call(door_fd, &door_arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (door_arg.rbuf != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) munmap(door_arg.rbuf, door_arg.rsize);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *resultsp = results;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) close(door_fd);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_set_args()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Construct an nvlist of arguments for a hotplugd door call.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic nvlist_t *
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_set_args(hp_cmd_t cmd, const char *path, const char *connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t flags, const char *options, int state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *args;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate a new nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&args, NV_UNIQUE_NAME_TYPE, 0) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add common arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_add_int32(args, HPD_CMD, cmd) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_add_string(args, HPD_PATH, path) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add connection, but only if defined */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((connection != NULL) && (connection[0] != '\0') &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_add_string(args, HPD_CONNECTION, connection) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add flags, but only if defined */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((flags != 0) && (nvlist_add_uint32(args, HPD_FLAGS, flags) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add options, but only if defined */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((options != NULL) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_add_string(args, HPD_OPTIONS, options) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add state, but only for CHANGESTATE command */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((cmd == HP_CMD_CHANGESTATE) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_add_int32(args, HPD_STATE, state) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (args);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * i_hp_parse_results()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Parse out individual fields of an nvlist of results from
269473047d747f7815af570197e4ef7322d3632cEvan Yan * a hotplugd door call.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yani_hp_parse_results(nvlist_t *results, hp_node_t *rootp, char **optionsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse an information snapshot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rootp) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t len = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *rootp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_lookup_byte_array(results, HPD_INFO,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uchar_t **)&buf, (uint_t *)&len) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = hp_unpack(buf, len, rootp)) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse a bus private option string */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (optionsp) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *str;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *optionsp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_lookup_string(results, HPD_OPTIONS, &str) == 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((*optionsp = strdup(str)) == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Parse result code of the operation */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_lookup_int32(results, HPD_STATUS, &rv) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan i_hp_dprintf("i_hp_call_hotplugd: missing status.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (EFAULT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}