126947304SEvan Yan /*
226947304SEvan Yan * CDDL HEADER START
326947304SEvan Yan *
426947304SEvan Yan * The contents of this file are subject to the terms of the
526947304SEvan Yan * Common Development and Distribution License (the "License").
626947304SEvan Yan * You may not use this file except in compliance with the License.
726947304SEvan Yan *
826947304SEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan * See the License for the specific language governing permissions
1126947304SEvan Yan * and limitations under the License.
1226947304SEvan Yan *
1326947304SEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan *
1926947304SEvan Yan * CDDL HEADER END
2026947304SEvan Yan */
2126947304SEvan Yan /*
2226947304SEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2326947304SEvan Yan * Use is subject to license terms.
2426947304SEvan Yan */
2526947304SEvan Yan
2626947304SEvan Yan #include <stdio.h>
2726947304SEvan Yan #include <stdlib.h>
2826947304SEvan Yan #include <stdarg.h>
2926947304SEvan Yan #include <unistd.h>
3026947304SEvan Yan #include <fcntl.h>
3126947304SEvan Yan #include <errno.h>
3226947304SEvan Yan #include <string.h>
3326947304SEvan Yan #include <door.h>
3426947304SEvan Yan #include <libnvpair.h>
3526947304SEvan Yan #include <libhotplug.h>
3626947304SEvan Yan #include <libhotplug_impl.h>
3726947304SEvan Yan #include <sys/sunddi.h>
3826947304SEvan Yan #include <sys/ddi_hp.h>
3926947304SEvan Yan
4026947304SEvan Yan static void i_hp_dprintf(const char *fmt, ...);
4126947304SEvan Yan static int i_hp_pack_branch(hp_node_t, char **, size_t *);
4226947304SEvan Yan static int i_hp_pack_node(hp_node_t, char **, size_t *);
4326947304SEvan Yan static int i_hp_unpack_node(char *, size_t, hp_node_t, hp_node_t *);
4426947304SEvan Yan static int i_hp_unpack_branch(char *, size_t, hp_node_t, hp_node_t *);
4526947304SEvan Yan static int i_hp_call_hotplugd(nvlist_t *, nvlist_t **);
4626947304SEvan Yan static nvlist_t *i_hp_set_args(hp_cmd_t, const char *, const char *, uint_t,
4726947304SEvan Yan const char *, int);
4826947304SEvan Yan static int i_hp_parse_results(nvlist_t *, hp_node_t *, char **);
4926947304SEvan Yan
5026947304SEvan Yan /*
5126947304SEvan Yan * Global flag to enable debug features.
5226947304SEvan Yan */
5326947304SEvan Yan int libhotplug_debug = 0;
5426947304SEvan Yan
5526947304SEvan Yan /*
5626947304SEvan Yan * hp_init()
5726947304SEvan Yan *
5826947304SEvan Yan * Initialize a hotplug information snapshot.
5926947304SEvan Yan */
6026947304SEvan Yan hp_node_t
hp_init(const char * path,const char * connection,uint_t flags)6126947304SEvan Yan hp_init(const char *path, const char *connection, uint_t flags)
6226947304SEvan Yan {
6326947304SEvan Yan nvlist_t *args;
6426947304SEvan Yan nvlist_t *results;
6526947304SEvan Yan hp_node_t root = NULL;
6626947304SEvan Yan int rv;
6726947304SEvan Yan
6826947304SEvan Yan i_hp_dprintf("hp_init: path=%p, connection=%p, flags=0x%x\n",
6926947304SEvan Yan (void *)path, (void *)connection, flags);
7026947304SEvan Yan
7126947304SEvan Yan /* Check arguments */
7226947304SEvan Yan if ((path == NULL) || !HP_INIT_FLAGS_VALID(flags)) {
7326947304SEvan Yan i_hp_dprintf("hp_init: invalid arguments.\n");
7426947304SEvan Yan errno = EINVAL;
7526947304SEvan Yan return (NULL);
7626947304SEvan Yan }
7726947304SEvan Yan
7826947304SEvan Yan /* Build arguments for door call */
7926947304SEvan Yan if ((args = i_hp_set_args(HP_CMD_GETINFO, path, connection, flags,
8026947304SEvan Yan NULL, 0)) == NULL) {
8126947304SEvan Yan i_hp_dprintf("hp_init: cannot build arguments nvlist.\n");
8226947304SEvan Yan errno = ENOMEM;
8326947304SEvan Yan return (NULL);
8426947304SEvan Yan }
8526947304SEvan Yan
8626947304SEvan Yan /* Make the door call to hotplugd */
8726947304SEvan Yan rv = i_hp_call_hotplugd(args, &results);
8826947304SEvan Yan
8926947304SEvan Yan /* Arguments no longer needed */
9026947304SEvan Yan nvlist_free(args);
9126947304SEvan Yan
9226947304SEvan Yan /* Parse additional results, if any */
9326947304SEvan Yan if ((rv == 0) && (results != NULL)) {
9426947304SEvan Yan rv = i_hp_parse_results(results, &root, NULL);
9526947304SEvan Yan nvlist_free(results);
9626947304SEvan Yan }
9726947304SEvan Yan
9826947304SEvan Yan /* Check for errors */
9926947304SEvan Yan if (rv != 0) {
10026947304SEvan Yan i_hp_dprintf("hp_init: failure (%s).\n", strerror(rv));
10126947304SEvan Yan if (root)
10226947304SEvan Yan hp_fini(root);
10326947304SEvan Yan errno = rv;
10426947304SEvan Yan return (NULL);
10526947304SEvan Yan }
10626947304SEvan Yan
10726947304SEvan Yan /* Success requires an info snapshot */
10826947304SEvan Yan if (root == NULL) {
10926947304SEvan Yan i_hp_dprintf("hp_init: missing info snapshot.\n");
11026947304SEvan Yan errno = EFAULT;
11126947304SEvan Yan return (NULL);
11226947304SEvan Yan }
11326947304SEvan Yan
11426947304SEvan Yan /* Success */
11526947304SEvan Yan return (root);
11626947304SEvan Yan }
11726947304SEvan Yan
11826947304SEvan Yan /*
11926947304SEvan Yan * hp_fini()
12026947304SEvan Yan *
12126947304SEvan Yan * Terminate and clean-up a hotplug information snapshot.
12226947304SEvan Yan */
12326947304SEvan Yan void
hp_fini(hp_node_t root)12426947304SEvan Yan hp_fini(hp_node_t root)
12526947304SEvan Yan {
12626947304SEvan Yan hp_node_t node;
12726947304SEvan Yan hp_node_t sibling;
12826947304SEvan Yan char *basepath;
12926947304SEvan Yan
13026947304SEvan Yan i_hp_dprintf("hp_fini: root=%p\n", (void *)root);
13126947304SEvan Yan
13226947304SEvan Yan if (root == NULL) {
13326947304SEvan Yan i_hp_dprintf("hp_fini: invalid arguments.\n");
13426947304SEvan Yan return;
13526947304SEvan Yan }
13626947304SEvan Yan
13726947304SEvan Yan /* Extract and free base path */
13826947304SEvan Yan if (root->hp_basepath) {
13926947304SEvan Yan basepath = root->hp_basepath;
14026947304SEvan Yan for (node = root; node != NULL; node = node->hp_sibling)
14126947304SEvan Yan node->hp_basepath = NULL;
14226947304SEvan Yan free(basepath);
14326947304SEvan Yan }
14426947304SEvan Yan
14526947304SEvan Yan /* Destroy the nodes */
14626947304SEvan Yan node = root;
14726947304SEvan Yan while (node) {
14826947304SEvan Yan sibling = node->hp_sibling;
14926947304SEvan Yan if (node->hp_child)
15026947304SEvan Yan hp_fini(node->hp_child);
15126947304SEvan Yan if (node->hp_name)
15226947304SEvan Yan free(node->hp_name);
15326947304SEvan Yan if (node->hp_usage)
15426947304SEvan Yan free(node->hp_usage);
15526947304SEvan Yan if (node->hp_description)
15626947304SEvan Yan free(node->hp_description);
15726947304SEvan Yan free(node);
15826947304SEvan Yan node = sibling;
15926947304SEvan Yan }
16026947304SEvan Yan }
16126947304SEvan Yan
16226947304SEvan Yan /*
16326947304SEvan Yan * hp_traverse()
16426947304SEvan Yan *
16526947304SEvan Yan * Walk a graph of hotplug nodes, executing a callback on each node.
16626947304SEvan Yan */
16726947304SEvan Yan int
hp_traverse(hp_node_t root,void * arg,int (* hp_callback)(hp_node_t,void * arg))16826947304SEvan Yan hp_traverse(hp_node_t root, void *arg, int (*hp_callback)(hp_node_t, void *arg))
16926947304SEvan Yan {
17026947304SEvan Yan int rv;
17126947304SEvan Yan hp_node_t node;
17226947304SEvan Yan
17326947304SEvan Yan i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n",
17426947304SEvan Yan (void *)root, arg, (void *)hp_callback);
17526947304SEvan Yan
17626947304SEvan Yan /* Check arguments */
17726947304SEvan Yan if ((root == NULL) || (hp_callback == NULL)) {
17826947304SEvan Yan i_hp_dprintf("hp_traverse: invalid arguments.\n");
17926947304SEvan Yan errno = EINVAL;
18026947304SEvan Yan return (-1);
18126947304SEvan Yan }
18226947304SEvan Yan
18326947304SEvan Yan for (node = root; node; node = node->hp_sibling) {
18426947304SEvan Yan rv = hp_callback(node, arg);
18526947304SEvan Yan
18626947304SEvan Yan if (rv == HP_WALK_TERMINATE) {
18726947304SEvan Yan i_hp_dprintf("hp_traverse: walk terminated.\n");
18826947304SEvan Yan return (HP_WALK_TERMINATE);
18926947304SEvan Yan }
19026947304SEvan Yan
19126947304SEvan Yan if (node->hp_child && (rv != HP_WALK_PRUNECHILD))
19226947304SEvan Yan if (hp_traverse(node->hp_child, arg, hp_callback) ==
19326947304SEvan Yan HP_WALK_TERMINATE) {
19426947304SEvan Yan i_hp_dprintf("hp_traverse: walk terminated.\n");
19526947304SEvan Yan return (HP_WALK_TERMINATE);
19626947304SEvan Yan }
19726947304SEvan Yan
19826947304SEvan Yan if (rv == HP_WALK_PRUNESIBLING)
19926947304SEvan Yan break;
20026947304SEvan Yan }
20126947304SEvan Yan
20226947304SEvan Yan return (0);
20326947304SEvan Yan }
20426947304SEvan Yan
20526947304SEvan Yan /*
20626947304SEvan Yan * hp_type()
20726947304SEvan Yan *
20826947304SEvan Yan * Return a node's type.
20926947304SEvan Yan */
21026947304SEvan Yan int
hp_type(hp_node_t node)21126947304SEvan Yan hp_type(hp_node_t node)
21226947304SEvan Yan {
21326947304SEvan Yan i_hp_dprintf("hp_type: node=%p\n", (void *)node);
21426947304SEvan Yan
21526947304SEvan Yan if (node == NULL) {
21626947304SEvan Yan i_hp_dprintf("hp_type: invalid arguments.\n");
21726947304SEvan Yan errno = EINVAL;
21826947304SEvan Yan return (-1);
21926947304SEvan Yan }
22026947304SEvan Yan
22126947304SEvan Yan return (node->hp_type);
22226947304SEvan Yan }
22326947304SEvan Yan
22426947304SEvan Yan /*
22526947304SEvan Yan * hp_name()
22626947304SEvan Yan *
22726947304SEvan Yan * Return a node's name.
22826947304SEvan Yan */
22926947304SEvan Yan char *
hp_name(hp_node_t node)23026947304SEvan Yan hp_name(hp_node_t node)
23126947304SEvan Yan {
23226947304SEvan Yan i_hp_dprintf("hp_name: node=%p\n", (void *)node);
23326947304SEvan Yan
23426947304SEvan Yan if (node == NULL) {
23526947304SEvan Yan i_hp_dprintf("hp_name: invalid arguments.\n");
23626947304SEvan Yan errno = EINVAL;
23726947304SEvan Yan return (NULL);
23826947304SEvan Yan }
23926947304SEvan Yan
24026947304SEvan Yan if (node->hp_name == NULL) {
24126947304SEvan Yan i_hp_dprintf("hp_name: missing name value.\n");
24226947304SEvan Yan errno = EFAULT;
24326947304SEvan Yan }
24426947304SEvan Yan
24526947304SEvan Yan return (node->hp_name);
24626947304SEvan Yan }
24726947304SEvan Yan
24826947304SEvan Yan /*
24926947304SEvan Yan * hp_state()
25026947304SEvan Yan *
25126947304SEvan Yan * Return a node's current state.
25226947304SEvan Yan */
25326947304SEvan Yan int
hp_state(hp_node_t node)25426947304SEvan Yan hp_state(hp_node_t node)
25526947304SEvan Yan {
25626947304SEvan Yan i_hp_dprintf("hp_state: node=%p\n", (void *)node);
25726947304SEvan Yan
25826947304SEvan Yan if (node == NULL) {
25926947304SEvan Yan i_hp_dprintf("hp_state: invalid arguments.\n");
26026947304SEvan Yan errno = EINVAL;
26126947304SEvan Yan return (-1);
26226947304SEvan Yan }
26326947304SEvan Yan
26426947304SEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
26526947304SEvan Yan (node->hp_type != HP_NODE_PORT)) {
26626947304SEvan Yan i_hp_dprintf("hp_state: operation not supported.\n");
26726947304SEvan Yan errno = ENOTSUP;
26826947304SEvan Yan return (-1);
26926947304SEvan Yan }
27026947304SEvan Yan
27126947304SEvan Yan return (node->hp_state);
27226947304SEvan Yan }
27326947304SEvan Yan
27426947304SEvan Yan /*
27526947304SEvan Yan * hp_usage()
27626947304SEvan Yan *
27726947304SEvan Yan * Return a usage description for usage nodes.
27826947304SEvan Yan */
27926947304SEvan Yan char *
hp_usage(hp_node_t node)28026947304SEvan Yan hp_usage(hp_node_t node)
28126947304SEvan Yan {
28226947304SEvan Yan i_hp_dprintf("hp_usage: node=%p\n", (void *)node);
28326947304SEvan Yan
28426947304SEvan Yan if (node == NULL) {
28526947304SEvan Yan i_hp_dprintf("hp_usage: invalid arguments.\n");
28626947304SEvan Yan errno = EINVAL;
28726947304SEvan Yan return (NULL);
28826947304SEvan Yan }
28926947304SEvan Yan
29026947304SEvan Yan if (node->hp_type != HP_NODE_USAGE) {
29126947304SEvan Yan i_hp_dprintf("hp_usage: operation not supported.\n");
29226947304SEvan Yan errno = ENOTSUP;
29326947304SEvan Yan return (NULL);
29426947304SEvan Yan }
29526947304SEvan Yan
29626947304SEvan Yan if (node->hp_usage == NULL) {
29726947304SEvan Yan i_hp_dprintf("hp_usage: missing usage value.\n");
29826947304SEvan Yan errno = EFAULT;
29926947304SEvan Yan }
30026947304SEvan Yan
30126947304SEvan Yan return (node->hp_usage);
30226947304SEvan Yan }
30326947304SEvan Yan
30426947304SEvan Yan /*
30526947304SEvan Yan * hp_description()
30626947304SEvan Yan *
30726947304SEvan Yan * Return a type description (e.g. "PCI slot") for connection nodes.
30826947304SEvan Yan */
30926947304SEvan Yan char *
hp_description(hp_node_t node)31026947304SEvan Yan hp_description(hp_node_t node)
31126947304SEvan Yan {
31226947304SEvan Yan i_hp_dprintf("hp_description: node=%p\n", (void *)node);
31326947304SEvan Yan
31426947304SEvan Yan if (node == NULL) {
31526947304SEvan Yan i_hp_dprintf("hp_description: invalid arguments.\n");
31626947304SEvan Yan errno = EINVAL;
31726947304SEvan Yan return (NULL);
31826947304SEvan Yan }
31926947304SEvan Yan
32026947304SEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
32126947304SEvan Yan (node->hp_type != HP_NODE_PORT)) {
32226947304SEvan Yan i_hp_dprintf("hp_description: operation not supported.\n");
32326947304SEvan Yan errno = ENOTSUP;
32426947304SEvan Yan return (NULL);
32526947304SEvan Yan }
32626947304SEvan Yan
32726947304SEvan Yan if (node->hp_description == NULL) {
32826947304SEvan Yan i_hp_dprintf("hp_description: missing description value.\n");
32926947304SEvan Yan errno = EFAULT;
33026947304SEvan Yan }
33126947304SEvan Yan
33226947304SEvan Yan return (node->hp_description);
33326947304SEvan Yan }
33426947304SEvan Yan
33526947304SEvan Yan /*
33626947304SEvan Yan * hp_last_change()
33726947304SEvan Yan *
33826947304SEvan Yan * Return when the state of a connection was last changed.
33926947304SEvan Yan */
34026947304SEvan Yan time_t
hp_last_change(hp_node_t node)34126947304SEvan Yan hp_last_change(hp_node_t node)
34226947304SEvan Yan {
34326947304SEvan Yan i_hp_dprintf("hp_last_change: node=%p\n", (void *)node);
34426947304SEvan Yan
34526947304SEvan Yan if (node == NULL) {
34626947304SEvan Yan i_hp_dprintf("hp_last_change: invalid arguments.\n");
34726947304SEvan Yan errno = EINVAL;
348*ae7ff7d6SToomas Soome return (0);
34926947304SEvan Yan }
35026947304SEvan Yan
35126947304SEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
35226947304SEvan Yan (node->hp_type != HP_NODE_PORT)) {
35326947304SEvan Yan i_hp_dprintf("hp_last_change: operation not supported.\n");
35426947304SEvan Yan errno = ENOTSUP;
355*ae7ff7d6SToomas Soome return (0);
35626947304SEvan Yan }
35726947304SEvan Yan
35826947304SEvan Yan return (node->hp_last_change);
35926947304SEvan Yan }
36026947304SEvan Yan
36126947304SEvan Yan /*
36226947304SEvan Yan * hp_parent()
36326947304SEvan Yan *
36426947304SEvan Yan * Return a node's parent node.
36526947304SEvan Yan */
36626947304SEvan Yan hp_node_t
hp_parent(hp_node_t node)36726947304SEvan Yan hp_parent(hp_node_t node)
36826947304SEvan Yan {
36926947304SEvan Yan i_hp_dprintf("hp_parent: node=%p\n", (void *)node);
37026947304SEvan Yan
37126947304SEvan Yan if (node == NULL) {
37226947304SEvan Yan i_hp_dprintf("hp_parent: invalid arguments.\n");
37326947304SEvan Yan errno = EINVAL;
37426947304SEvan Yan return (NULL);
37526947304SEvan Yan }
37626947304SEvan Yan
37726947304SEvan Yan if (node->hp_parent == NULL) {
37826947304SEvan Yan i_hp_dprintf("hp_parent: node has no parent.\n");
37926947304SEvan Yan errno = ENXIO;
38026947304SEvan Yan }
38126947304SEvan Yan
38226947304SEvan Yan return (node->hp_parent);
38326947304SEvan Yan }
38426947304SEvan Yan
38526947304SEvan Yan /*
38626947304SEvan Yan * hp_child()
38726947304SEvan Yan *
38826947304SEvan Yan * Return a node's first child node.
38926947304SEvan Yan */
39026947304SEvan Yan hp_node_t
hp_child(hp_node_t node)39126947304SEvan Yan hp_child(hp_node_t node)
39226947304SEvan Yan {
39326947304SEvan Yan i_hp_dprintf("hp_child: node=%p\n", (void *)node);
39426947304SEvan Yan
39526947304SEvan Yan if (node == NULL) {
39626947304SEvan Yan i_hp_dprintf("hp_child: invalid arguments.\n");
39726947304SEvan Yan errno = EINVAL;
39826947304SEvan Yan return (NULL);
39926947304SEvan Yan }
40026947304SEvan Yan
40126947304SEvan Yan if (node->hp_child == NULL) {
40226947304SEvan Yan i_hp_dprintf("hp_child: node has no child.\n");
40326947304SEvan Yan errno = ENXIO;
40426947304SEvan Yan }
40526947304SEvan Yan
40626947304SEvan Yan return (node->hp_child);
40726947304SEvan Yan }
40826947304SEvan Yan
40926947304SEvan Yan /*
41026947304SEvan Yan * hp_sibling()
41126947304SEvan Yan *
41226947304SEvan Yan * Return a node's next sibling node.
41326947304SEvan Yan */
41426947304SEvan Yan hp_node_t
hp_sibling(hp_node_t node)41526947304SEvan Yan hp_sibling(hp_node_t node)
41626947304SEvan Yan {
41726947304SEvan Yan i_hp_dprintf("hp_sibling: node=%p\n", (void *)node);
41826947304SEvan Yan
41926947304SEvan Yan if (node == NULL) {
42026947304SEvan Yan i_hp_dprintf("hp_sibling: invalid arguments.\n");
42126947304SEvan Yan errno = EINVAL;
42226947304SEvan Yan return (NULL);
42326947304SEvan Yan }
42426947304SEvan Yan
42526947304SEvan Yan if (node->hp_sibling == NULL) {
42626947304SEvan Yan i_hp_dprintf("hp_sibling: node has no sibling.\n");
42726947304SEvan Yan errno = ENXIO;
42826947304SEvan Yan }
42926947304SEvan Yan
43026947304SEvan Yan return (node->hp_sibling);
43126947304SEvan Yan }
43226947304SEvan Yan
43326947304SEvan Yan /*
43426947304SEvan Yan * hp_path()
43526947304SEvan Yan *
43626947304SEvan Yan * Return the path (and maybe connection name) of a node.
43726947304SEvan Yan * The caller must supply two buffers, each MAXPATHLEN size.
43826947304SEvan Yan */
43926947304SEvan Yan int
hp_path(hp_node_t node,char * path,char * connection)44026947304SEvan Yan hp_path(hp_node_t node, char *path, char *connection)
44126947304SEvan Yan {
442d598ea2fSToomas Soome hp_node_t root = NULL;
44326947304SEvan Yan hp_node_t parent;
44426947304SEvan Yan int i;
44526947304SEvan Yan char *s;
44626947304SEvan Yan char components[MAXPATHLEN];
44726947304SEvan Yan
44826947304SEvan Yan i_hp_dprintf("hp_path: node=%p, path=%p, connection=%p\n", (void *)node,
44926947304SEvan Yan (void *)path, (void *)connection);
45026947304SEvan Yan
45126947304SEvan Yan if ((node == NULL) || (path == NULL) || (connection == NULL)) {
45226947304SEvan Yan i_hp_dprintf("hp_path: invalid arguments.\n");
45326947304SEvan Yan return (EINVAL);
45426947304SEvan Yan }
45526947304SEvan Yan
45626947304SEvan Yan (void) memset(path, 0, MAXPATHLEN);
45726947304SEvan Yan (void) memset(connection, 0, MAXPATHLEN);
45826947304SEvan Yan (void) memset(components, 0, MAXPATHLEN);
45926947304SEvan Yan
46026947304SEvan Yan /* Set 'connection' only for connectors and ports */
46126947304SEvan Yan if ((node->hp_type == HP_NODE_CONNECTOR) ||
46226947304SEvan Yan (node->hp_type == HP_NODE_PORT))
46326947304SEvan Yan (void) strlcpy(connection, node->hp_name, MAXPATHLEN);
46426947304SEvan Yan
46526947304SEvan Yan /* Trace back to the root node, accumulating components */
46626947304SEvan Yan for (parent = node; parent != NULL; parent = parent->hp_parent) {
46726947304SEvan Yan if (parent->hp_type == HP_NODE_DEVICE) {
46826947304SEvan Yan (void) strlcat(components, "/", MAXPATHLEN);
46926947304SEvan Yan (void) strlcat(components, parent->hp_name, MAXPATHLEN);
47026947304SEvan Yan }
47126947304SEvan Yan if (parent->hp_parent == NULL)
47226947304SEvan Yan root = parent;
47326947304SEvan Yan }
47426947304SEvan Yan
47526947304SEvan Yan /* Ensure the snapshot actually contains a base path */
47626947304SEvan Yan if (root->hp_basepath == NULL) {
47726947304SEvan Yan i_hp_dprintf("hp_path: missing base pathname.\n");
47826947304SEvan Yan return (EFAULT);
47926947304SEvan Yan }
48026947304SEvan Yan
48126947304SEvan Yan /*
48226947304SEvan Yan * Construct the path. Start with the base path from the root
48326947304SEvan Yan * node, then append the accumulated components in reverse order.
48426947304SEvan Yan */
48526947304SEvan Yan if (strcmp(root->hp_basepath, "/") != 0) {
48626947304SEvan Yan (void) strlcat(path, root->hp_basepath, MAXPATHLEN);
48726947304SEvan Yan if ((root->hp_type == HP_NODE_DEVICE) &&
48826947304SEvan Yan ((s = strrchr(path, '/')) != NULL))
48926947304SEvan Yan *s = '\0';
49026947304SEvan Yan }
49126947304SEvan Yan for (i = strlen(components) - 1; i >= 0; i--) {
49226947304SEvan Yan if (components[i] == '/') {
49326947304SEvan Yan (void) strlcat(path, &components[i], MAXPATHLEN);
49426947304SEvan Yan components[i] = '\0';
49526947304SEvan Yan }
49626947304SEvan Yan }
49726947304SEvan Yan
49826947304SEvan Yan return (0);
49926947304SEvan Yan }
50026947304SEvan Yan
50126947304SEvan Yan /*
50226947304SEvan Yan * hp_set_state()
50326947304SEvan Yan *
50426947304SEvan Yan * Initiate a state change operation on a node.
50526947304SEvan Yan */
50626947304SEvan Yan int
hp_set_state(hp_node_t node,uint_t flags,int state,hp_node_t * resultsp)50726947304SEvan Yan hp_set_state(hp_node_t node, uint_t flags, int state, hp_node_t *resultsp)
50826947304SEvan Yan {
50926947304SEvan Yan hp_node_t root = NULL;
51026947304SEvan Yan nvlist_t *args;
51126947304SEvan Yan nvlist_t *results;
51226947304SEvan Yan int rv;
51326947304SEvan Yan char path[MAXPATHLEN];
51426947304SEvan Yan char connection[MAXPATHLEN];
51526947304SEvan Yan
51626947304SEvan Yan i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, "
51726947304SEvan Yan "resultsp=%p\n", (void *)node, flags, state, (void *)resultsp);
51826947304SEvan Yan
51926947304SEvan Yan /* Check arguments */
52026947304SEvan Yan if ((node == NULL) || (resultsp == NULL) ||
52126947304SEvan Yan !HP_SET_STATE_FLAGS_VALID(flags)) {
52226947304SEvan Yan i_hp_dprintf("hp_set_state: invalid arguments.\n");
52326947304SEvan Yan return (EINVAL);
52426947304SEvan Yan }
52526947304SEvan Yan
52626947304SEvan Yan /* Check node type */
52726947304SEvan Yan if ((node->hp_type != HP_NODE_CONNECTOR) &&
52826947304SEvan Yan (node->hp_type != HP_NODE_PORT)) {
52926947304SEvan Yan i_hp_dprintf("hp_set_state: operation not supported.\n");
53026947304SEvan Yan return (ENOTSUP);
53126947304SEvan Yan }
53226947304SEvan Yan
53326947304SEvan Yan /* Check that target state is valid */
53426947304SEvan Yan switch (state) {
53526947304SEvan Yan case DDI_HP_CN_STATE_PRESENT:
53626947304SEvan Yan case DDI_HP_CN_STATE_POWERED:
53726947304SEvan Yan case DDI_HP_CN_STATE_ENABLED:
53826947304SEvan Yan if (node->hp_type != HP_NODE_CONNECTOR) {
53926947304SEvan Yan i_hp_dprintf("hp_set_state: mismatched target.\n");
54026947304SEvan Yan return (ENOTSUP);
54126947304SEvan Yan }
54226947304SEvan Yan break;
54326947304SEvan Yan case DDI_HP_CN_STATE_PORT_PRESENT:
54426947304SEvan Yan case DDI_HP_CN_STATE_OFFLINE:
54526947304SEvan Yan case DDI_HP_CN_STATE_ONLINE:
54626947304SEvan Yan if (node->hp_type != HP_NODE_PORT) {
54726947304SEvan Yan i_hp_dprintf("hp_set_state: mismatched target.\n");
54826947304SEvan Yan return (ENOTSUP);
54926947304SEvan Yan }
55026947304SEvan Yan break;
55126947304SEvan Yan default:
55226947304SEvan Yan i_hp_dprintf("hp_set_state: invalid target state.\n");
55326947304SEvan Yan return (EINVAL);
55426947304SEvan Yan }
55526947304SEvan Yan
55626947304SEvan Yan /* Get path and connection of specified node */
55726947304SEvan Yan if ((rv = hp_path(node, path, connection)) != 0)
55826947304SEvan Yan return (rv);
55926947304SEvan Yan
56026947304SEvan Yan /* Build arguments for door call */
56126947304SEvan Yan if ((args = i_hp_set_args(HP_CMD_CHANGESTATE, path, connection, flags,
56226947304SEvan Yan NULL, state)) == NULL)
56326947304SEvan Yan return (ENOMEM);
56426947304SEvan Yan
56526947304SEvan Yan /* Make the door call to hotplugd */
56626947304SEvan Yan rv = i_hp_call_hotplugd(args, &results);
56726947304SEvan Yan
56826947304SEvan Yan /* Arguments no longer needed */
56926947304SEvan Yan nvlist_free(args);
57026947304SEvan Yan
57126947304SEvan Yan /* Parse additional results, if any */
57226947304SEvan Yan if ((rv == 0) && (results != NULL)) {
57326947304SEvan Yan rv = i_hp_parse_results(results, &root, NULL);
57426947304SEvan Yan nvlist_free(results);
57526947304SEvan Yan *resultsp = root;
57626947304SEvan Yan }
57726947304SEvan Yan
57826947304SEvan Yan /* Done */
57926947304SEvan Yan return (rv);
58026947304SEvan Yan }
58126947304SEvan Yan
58226947304SEvan Yan /*
58326947304SEvan Yan * hp_set_private()
58426947304SEvan Yan *
58526947304SEvan Yan * Set bus private options on the hotplug connection
58626947304SEvan Yan * indicated by the given hotplug information node.
58726947304SEvan Yan */
58826947304SEvan Yan int
hp_set_private(hp_node_t node,const char * options,char ** resultsp)58926947304SEvan Yan hp_set_private(hp_node_t node, const char *options, char **resultsp)
59026947304SEvan Yan {
59126947304SEvan Yan int rv;
59226947304SEvan Yan nvlist_t *args;
59326947304SEvan Yan nvlist_t *results;
59426947304SEvan Yan char *values = NULL;
59526947304SEvan Yan char path[MAXPATHLEN];
59626947304SEvan Yan char connection[MAXPATHLEN];
59726947304SEvan Yan
59826947304SEvan Yan i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n",
59926947304SEvan Yan (void *)node, (void *)options, (void *)resultsp);
60026947304SEvan Yan
60126947304SEvan Yan /* Check arguments */
60226947304SEvan Yan if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
60326947304SEvan Yan i_hp_dprintf("hp_set_private: invalid arguments.\n");
60426947304SEvan Yan return (EINVAL);
60526947304SEvan Yan }
60626947304SEvan Yan
60726947304SEvan Yan /* Check node type */
60826947304SEvan Yan if (node->hp_type != HP_NODE_CONNECTOR) {
60926947304SEvan Yan i_hp_dprintf("hp_set_private: operation not supported.\n");
61026947304SEvan Yan return (ENOTSUP);
61126947304SEvan Yan }
61226947304SEvan Yan
61326947304SEvan Yan /* Initialize results */
61426947304SEvan Yan *resultsp = NULL;
61526947304SEvan Yan
61626947304SEvan Yan /* Get path and connection of specified node */
61726947304SEvan Yan if ((rv = hp_path(node, path, connection)) != 0)
61826947304SEvan Yan return (rv);
61926947304SEvan Yan
62026947304SEvan Yan /* Build arguments for door call */
62126947304SEvan Yan if ((args = i_hp_set_args(HP_CMD_SETPRIVATE, path, connection, 0,
62226947304SEvan Yan options, 0)) == NULL)
62326947304SEvan Yan return (ENOMEM);
62426947304SEvan Yan
62526947304SEvan Yan /* Make the door call to hotplugd */
62626947304SEvan Yan rv = i_hp_call_hotplugd(args, &results);
62726947304SEvan Yan
62826947304SEvan Yan /* Arguments no longer needed */
62926947304SEvan Yan nvlist_free(args);
63026947304SEvan Yan
63126947304SEvan Yan /* Parse additional results, if any */
63226947304SEvan Yan if ((rv == 0) && (results != NULL)) {
63326947304SEvan Yan rv = i_hp_parse_results(results, NULL, &values);
63426947304SEvan Yan nvlist_free(results);
63526947304SEvan Yan *resultsp = values;
63626947304SEvan Yan }
63726947304SEvan Yan
63826947304SEvan Yan /* Done */
63926947304SEvan Yan return (rv);
64026947304SEvan Yan }
64126947304SEvan Yan
64226947304SEvan Yan /*
64326947304SEvan Yan * hp_get_private()
64426947304SEvan Yan *
64526947304SEvan Yan * Get bus private options on the hotplug connection
64626947304SEvan Yan * indicated by the given hotplug information node.
64726947304SEvan Yan */
64826947304SEvan Yan int
hp_get_private(hp_node_t node,const char * options,char ** resultsp)64926947304SEvan Yan hp_get_private(hp_node_t node, const char *options, char **resultsp)
65026947304SEvan Yan {
65126947304SEvan Yan int rv;
65226947304SEvan Yan nvlist_t *args;
65326947304SEvan Yan nvlist_t *results;
65426947304SEvan Yan char *values = NULL;
65526947304SEvan Yan char path[MAXPATHLEN];
65626947304SEvan Yan char connection[MAXPATHLEN];
65726947304SEvan Yan
65826947304SEvan Yan i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n",
65926947304SEvan Yan (void *)node, (void *)options, (void *)resultsp);
66026947304SEvan Yan
66126947304SEvan Yan /* Check arguments */
66226947304SEvan Yan if ((node == NULL) || (options == NULL) || (resultsp == NULL)) {
66326947304SEvan Yan i_hp_dprintf("hp_get_private: invalid arguments.\n");
66426947304SEvan Yan return (EINVAL);
66526947304SEvan Yan }
66626947304SEvan Yan
66726947304SEvan Yan /* Check node type */
66826947304SEvan Yan if (node->hp_type != HP_NODE_CONNECTOR) {
66926947304SEvan Yan i_hp_dprintf("hp_get_private: operation not supported.\n");
67026947304SEvan Yan return (ENOTSUP);
67126947304SEvan Yan }
67226947304SEvan Yan
67326947304SEvan Yan /* Initialize results */
67426947304SEvan Yan *resultsp = NULL;
67526947304SEvan Yan
67626947304SEvan Yan /* Get path and connection of specified node */
67726947304SEvan Yan if ((rv = hp_path(node, path, connection)) != 0)
67826947304SEvan Yan return (rv);
67926947304SEvan Yan
68026947304SEvan Yan /* Build arguments for door call */
68126947304SEvan Yan if ((args = i_hp_set_args(HP_CMD_GETPRIVATE, path, connection, 0,
68226947304SEvan Yan options, 0)) == NULL)
68326947304SEvan Yan return (ENOMEM);
68426947304SEvan Yan
68526947304SEvan Yan /* Make the door call to hotplugd */
68626947304SEvan Yan rv = i_hp_call_hotplugd(args, &results);
68726947304SEvan Yan
68826947304SEvan Yan /* Arguments no longer needed */
68926947304SEvan Yan nvlist_free(args);
69026947304SEvan Yan
69126947304SEvan Yan /* Parse additional results, if any */
69226947304SEvan Yan if ((rv == 0) && (results != NULL)) {
69326947304SEvan Yan rv = i_hp_parse_results(results, NULL, &values);
69426947304SEvan Yan nvlist_free(results);
69526947304SEvan Yan *resultsp = values;
69626947304SEvan Yan }
69726947304SEvan Yan
69826947304SEvan Yan /* Done */
69926947304SEvan Yan return (rv);
70026947304SEvan Yan }
70126947304SEvan Yan
70226947304SEvan Yan /*
70326947304SEvan Yan * hp_pack()
70426947304SEvan Yan *
70526947304SEvan Yan * Given the root of a hotplug information snapshot, pack
70626947304SEvan Yan * it into a contiguous byte array so that it is suitable
70726947304SEvan Yan * for network transport.
70826947304SEvan Yan */
70926947304SEvan Yan int
hp_pack(hp_node_t root,char ** bufp,size_t * lenp)71026947304SEvan Yan hp_pack(hp_node_t root, char **bufp, size_t *lenp)
71126947304SEvan Yan {
71226947304SEvan Yan hp_node_t node;
71326947304SEvan Yan nvlist_t *nvl;
71426947304SEvan Yan char *buf;
71526947304SEvan Yan size_t len;
71626947304SEvan Yan int rv;
71726947304SEvan Yan
71826947304SEvan Yan i_hp_dprintf("hp_pack: root=%p, bufp=%p, lenp=%p\n", (void *)root,
71926947304SEvan Yan (void *)bufp, (void *)lenp);
72026947304SEvan Yan
72126947304SEvan Yan if ((root == NULL) || (bufp == NULL) || (lenp == NULL)) {
72226947304SEvan Yan i_hp_dprintf("hp_pack: invalid arguments.\n");
72326947304SEvan Yan return (EINVAL);
72426947304SEvan Yan }
72526947304SEvan Yan
72626947304SEvan Yan *lenp = 0;
72726947304SEvan Yan *bufp = NULL;
72826947304SEvan Yan
72926947304SEvan Yan if (nvlist_alloc(&nvl, 0, 0) != 0) {
73026947304SEvan Yan i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n",
73126947304SEvan Yan strerror(errno));
73226947304SEvan Yan return (ENOMEM);
73326947304SEvan Yan }
73426947304SEvan Yan
73526947304SEvan Yan if (root->hp_basepath != NULL) {
73626947304SEvan Yan rv = nvlist_add_string(nvl, HP_INFO_BASE, root->hp_basepath);
73726947304SEvan Yan if (rv != 0) {
73826947304SEvan Yan nvlist_free(nvl);
73926947304SEvan Yan return (rv);
74026947304SEvan Yan }
74126947304SEvan Yan }
74226947304SEvan Yan
74326947304SEvan Yan for (node = root; node != NULL; node = node->hp_sibling) {
74426947304SEvan Yan if ((rv = i_hp_pack_branch(node, &buf, &len)) == 0) {
74526947304SEvan Yan rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
74626947304SEvan Yan (uchar_t *)buf, len);
74726947304SEvan Yan free(buf);
74826947304SEvan Yan }
74926947304SEvan Yan if (rv != 0) {
75026947304SEvan Yan nvlist_free(nvl);
75126947304SEvan Yan return (rv);
75226947304SEvan Yan }
75326947304SEvan Yan }
75426947304SEvan Yan
75526947304SEvan Yan len = 0;
75626947304SEvan Yan buf = NULL;
75726947304SEvan Yan if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
75826947304SEvan Yan *lenp = len;
75926947304SEvan Yan *bufp = buf;
76026947304SEvan Yan }
76126947304SEvan Yan
76226947304SEvan Yan nvlist_free(nvl);
76326947304SEvan Yan
76426947304SEvan Yan return (rv);
76526947304SEvan Yan }
76626947304SEvan Yan
76726947304SEvan Yan /*
76826947304SEvan Yan * hp_unpack()
76926947304SEvan Yan *
77026947304SEvan Yan * Unpack a hotplug information snapshot for normal usage.
77126947304SEvan Yan */
77226947304SEvan Yan int
hp_unpack(char * packed_buf,size_t packed_len,hp_node_t * retp)77326947304SEvan Yan hp_unpack(char *packed_buf, size_t packed_len, hp_node_t *retp)
77426947304SEvan Yan {
77526947304SEvan Yan hp_node_t root;
77626947304SEvan Yan hp_node_t root_list = NULL;
77726947304SEvan Yan hp_node_t prev_root = NULL;
77826947304SEvan Yan nvlist_t *nvl = NULL;
77926947304SEvan Yan nvpair_t *nvp;
78026947304SEvan Yan char *basepath = NULL;
78126947304SEvan Yan int rv;
78226947304SEvan Yan
78326947304SEvan Yan i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n",
78426947304SEvan Yan (void *)packed_buf, (uint32_t)packed_len, (void *)retp);
78526947304SEvan Yan
78626947304SEvan Yan if ((packed_buf == NULL) || (packed_len == 0) || (retp == NULL)) {
78726947304SEvan Yan i_hp_dprintf("hp_unpack: invalid arguments.\n");
78826947304SEvan Yan return (EINVAL);
78926947304SEvan Yan }
79026947304SEvan Yan
79126947304SEvan Yan if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
79226947304SEvan Yan return (rv);
79326947304SEvan Yan
79426947304SEvan Yan if (nvlist_next_nvpair(nvl, NULL) == NULL) {
79526947304SEvan Yan nvlist_free(nvl);
79626947304SEvan Yan errno = EINVAL;
797*ae7ff7d6SToomas Soome return (0);
79826947304SEvan Yan }
79926947304SEvan Yan
80026947304SEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
80126947304SEvan Yan
80226947304SEvan Yan rv = EINVAL;
80326947304SEvan Yan
80426947304SEvan Yan if (strcmp(nvpair_name(nvp), HP_INFO_BASE) == 0) {
80526947304SEvan Yan char *val_string;
80626947304SEvan Yan
80726947304SEvan Yan if ((rv = nvpair_value_string(nvp, &val_string)) == 0) {
80826947304SEvan Yan if ((basepath = strdup(val_string)) == NULL)
80926947304SEvan Yan rv = ENOMEM;
81026947304SEvan Yan }
81126947304SEvan Yan
81226947304SEvan Yan } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
81326947304SEvan Yan size_t len = 0;
81426947304SEvan Yan char *buf = NULL;
81526947304SEvan Yan
81626947304SEvan Yan if ((rv = nvpair_value_byte_array(nvp,
81726947304SEvan Yan (uchar_t **)&buf, (uint_t *)&len)) == 0) {
81826947304SEvan Yan rv = i_hp_unpack_branch(buf, len, NULL, &root);
81926947304SEvan Yan }
82026947304SEvan Yan
82126947304SEvan Yan if (rv == 0) {
82226947304SEvan Yan if (prev_root) {
82326947304SEvan Yan prev_root->hp_sibling = root;
82426947304SEvan Yan } else {
82526947304SEvan Yan root_list = root;
82626947304SEvan Yan }
82726947304SEvan Yan prev_root = root;
82826947304SEvan Yan }
82926947304SEvan Yan }
83026947304SEvan Yan
83126947304SEvan Yan if (rv != 0) {
83226947304SEvan Yan if (basepath)
83326947304SEvan Yan free(basepath);
83426947304SEvan Yan nvlist_free(nvl);
83526947304SEvan Yan hp_fini(root_list);
83626947304SEvan Yan *retp = NULL;
83726947304SEvan Yan return (rv);
83826947304SEvan Yan }
83926947304SEvan Yan }
84026947304SEvan Yan
84126947304SEvan Yan /* Store the base path in each root node */
84226947304SEvan Yan if (basepath) {
84326947304SEvan Yan for (root = root_list; root; root = root->hp_sibling)
84426947304SEvan Yan root->hp_basepath = basepath;
84526947304SEvan Yan }
84626947304SEvan Yan
84726947304SEvan Yan nvlist_free(nvl);
84826947304SEvan Yan *retp = root_list;
84926947304SEvan Yan return (0);
85026947304SEvan Yan }
85126947304SEvan Yan
85226947304SEvan Yan /*
85326947304SEvan Yan * i_hp_dprintf()
85426947304SEvan Yan *
85526947304SEvan Yan * Print debug messages to stderr, but only when the debug flag
85626947304SEvan Yan * (libhotplug_debug) is set.
85726947304SEvan Yan */
85826947304SEvan Yan /*PRINTFLIKE1*/
85926947304SEvan Yan static void
i_hp_dprintf(const char * fmt,...)86026947304SEvan Yan i_hp_dprintf(const char *fmt, ...)
86126947304SEvan Yan {
86226947304SEvan Yan va_list ap;
86326947304SEvan Yan
86426947304SEvan Yan if (libhotplug_debug) {
86526947304SEvan Yan va_start(ap, fmt);
86626947304SEvan Yan (void) vfprintf(stderr, fmt, ap);
86726947304SEvan Yan va_end(ap);
86826947304SEvan Yan }
86926947304SEvan Yan }
87026947304SEvan Yan
87126947304SEvan Yan /*
87226947304SEvan Yan * i_hp_pack_branch()
87326947304SEvan Yan *
87426947304SEvan Yan * Pack an individual branch of a hotplug information snapshot.
87526947304SEvan Yan */
87626947304SEvan Yan static int
i_hp_pack_branch(hp_node_t root,char ** bufp,size_t * lenp)87726947304SEvan Yan i_hp_pack_branch(hp_node_t root, char **bufp, size_t *lenp)
87826947304SEvan Yan {
87926947304SEvan Yan hp_node_t child;
88026947304SEvan Yan nvlist_t *nvl;
88126947304SEvan Yan char *buf;
88226947304SEvan Yan size_t len;
88326947304SEvan Yan int rv;
88426947304SEvan Yan
88526947304SEvan Yan *lenp = 0;
88626947304SEvan Yan *bufp = NULL;
88726947304SEvan Yan
88826947304SEvan Yan /* Allocate an nvlist for this branch */
88926947304SEvan Yan if (nvlist_alloc(&nvl, 0, 0) != 0)
89026947304SEvan Yan return (ENOMEM);
89126947304SEvan Yan
89226947304SEvan Yan /* Pack the root of the branch and add it to the nvlist */
89326947304SEvan Yan if ((rv = i_hp_pack_node(root, &buf, &len)) == 0) {
89426947304SEvan Yan rv = nvlist_add_byte_array(nvl, HP_INFO_NODE,
89526947304SEvan Yan (uchar_t *)buf, len);
89626947304SEvan Yan free(buf);
89726947304SEvan Yan }
89826947304SEvan Yan if (rv != 0) {
89926947304SEvan Yan nvlist_free(nvl);
90026947304SEvan Yan return (rv);
90126947304SEvan Yan }
90226947304SEvan Yan
90326947304SEvan Yan /* Pack each subordinate branch, and add it to the nvlist */
90426947304SEvan Yan for (child = root->hp_child; child != NULL; child = child->hp_sibling) {
90526947304SEvan Yan if ((rv = i_hp_pack_branch(child, &buf, &len)) == 0) {
90626947304SEvan Yan rv = nvlist_add_byte_array(nvl, HP_INFO_BRANCH,
90726947304SEvan Yan (uchar_t *)buf, len);
90826947304SEvan Yan free(buf);
90926947304SEvan Yan }
91026947304SEvan Yan if (rv != 0) {
91126947304SEvan Yan nvlist_free(nvl);
91226947304SEvan Yan return (rv);
91326947304SEvan Yan }
91426947304SEvan Yan }
91526947304SEvan Yan
91626947304SEvan Yan /* Pack the resulting nvlist into a single buffer */
91726947304SEvan Yan len = 0;
91826947304SEvan Yan buf = NULL;
91926947304SEvan Yan if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) == 0) {
92026947304SEvan Yan *lenp = len;
92126947304SEvan Yan *bufp = buf;
92226947304SEvan Yan }
92326947304SEvan Yan
92426947304SEvan Yan /* Free the nvlist */
92526947304SEvan Yan nvlist_free(nvl);
92626947304SEvan Yan
92726947304SEvan Yan return (rv);
92826947304SEvan Yan }
92926947304SEvan Yan
93026947304SEvan Yan /*
93126947304SEvan Yan * i_hp_pack_node()
93226947304SEvan Yan *
93326947304SEvan Yan * Pack an individual node of a hotplug information snapshot.
93426947304SEvan Yan */
93526947304SEvan Yan static int
i_hp_pack_node(hp_node_t node,char ** bufp,size_t * lenp)93626947304SEvan Yan i_hp_pack_node(hp_node_t node, char **bufp, size_t *lenp)
93726947304SEvan Yan {
93826947304SEvan Yan nvlist_t *nvl;
93926947304SEvan Yan char *buf = NULL;
94026947304SEvan Yan size_t len = 0;
94126947304SEvan Yan int rv;
94226947304SEvan Yan
94326947304SEvan Yan if (nvlist_alloc(&nvl, 0, 0) != 0)
94426947304SEvan Yan return (ENOMEM);
94526947304SEvan Yan
94626947304SEvan Yan if ((rv = nvlist_add_uint32(nvl, HP_INFO_TYPE,
94726947304SEvan Yan (uint32_t)node->hp_type)) != 0)
94826947304SEvan Yan goto fail;
94926947304SEvan Yan
95026947304SEvan Yan if ((node->hp_name) &&
95126947304SEvan Yan ((rv = nvlist_add_string(nvl, HP_INFO_NAME, node->hp_name)) != 0))
95226947304SEvan Yan goto fail;
95326947304SEvan Yan
95426947304SEvan Yan if ((node->hp_usage) &&
95526947304SEvan Yan ((rv = nvlist_add_string(nvl, HP_INFO_USAGE, node->hp_usage)) != 0))
95626947304SEvan Yan goto fail;
95726947304SEvan Yan
95826947304SEvan Yan if ((node->hp_description) &&
95926947304SEvan Yan ((rv = nvlist_add_string(nvl, HP_INFO_DESC,
96026947304SEvan Yan node->hp_description)) != 0))
96126947304SEvan Yan goto fail;
96226947304SEvan Yan
96326947304SEvan Yan if ((rv = nvlist_add_uint32(nvl, HP_INFO_STATE, node->hp_state)) != 0)
96426947304SEvan Yan goto fail;
96526947304SEvan Yan
96626947304SEvan Yan if ((node->hp_last_change != 0) &&
96726947304SEvan Yan ((rv = nvlist_add_uint32(nvl, HP_INFO_TIME,
96826947304SEvan Yan node->hp_last_change)) != 0))
96926947304SEvan Yan goto fail;
97026947304SEvan Yan
97126947304SEvan Yan if ((rv = nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0)
97226947304SEvan Yan goto fail;
97326947304SEvan Yan
97426947304SEvan Yan *bufp = buf;
97526947304SEvan Yan *lenp = len;
97626947304SEvan Yan nvlist_free(nvl);
97726947304SEvan Yan return (0);
97826947304SEvan Yan
97926947304SEvan Yan fail:
98026947304SEvan Yan *bufp = NULL;
98126947304SEvan Yan *lenp = 0;
98226947304SEvan Yan nvlist_free(nvl);
98326947304SEvan Yan return (rv);
98426947304SEvan Yan }
98526947304SEvan Yan
98626947304SEvan Yan /*
98726947304SEvan Yan * i_hp_unpack_branch()
98826947304SEvan Yan *
98926947304SEvan Yan * Unpack a branch of hotplug information nodes.
99026947304SEvan Yan */
99126947304SEvan Yan static int
i_hp_unpack_branch(char * packed_buf,size_t packed_len,hp_node_t parent,hp_node_t * retp)99226947304SEvan Yan i_hp_unpack_branch(char *packed_buf, size_t packed_len, hp_node_t parent,
99326947304SEvan Yan hp_node_t *retp)
99426947304SEvan Yan {
99526947304SEvan Yan hp_node_t node = NULL;
99626947304SEvan Yan hp_node_t child;
99726947304SEvan Yan hp_node_t prev_child = NULL;
99826947304SEvan Yan nvlist_t *nvl = NULL;
99926947304SEvan Yan nvpair_t *nvp;
100026947304SEvan Yan char *buf;
100126947304SEvan Yan size_t len;
100226947304SEvan Yan int rv;
100326947304SEvan Yan
100426947304SEvan Yan /* Initialize results */
100526947304SEvan Yan *retp = NULL;
100626947304SEvan Yan
100726947304SEvan Yan /* Unpack the nvlist for this branch */
100826947304SEvan Yan if ((rv = nvlist_unpack(packed_buf, packed_len, &nvl, 0)) != 0)
100926947304SEvan Yan return (rv);
101026947304SEvan Yan
101126947304SEvan Yan /*
101226947304SEvan Yan * Unpack the branch. The first item in the nvlist is
101326947304SEvan Yan * always the root node. And zero or more subordinate
101426947304SEvan Yan * branches may be packed afterward.
101526947304SEvan Yan */
101626947304SEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
101726947304SEvan Yan
101826947304SEvan Yan len = 0;
101926947304SEvan Yan buf = NULL;
102026947304SEvan Yan
102126947304SEvan Yan if (strcmp(nvpair_name(nvp), HP_INFO_NODE) == 0) {
102226947304SEvan Yan
102326947304SEvan Yan /* Check that there is only one root node */
102426947304SEvan Yan if (node != NULL) {
102526947304SEvan Yan hp_fini(node);
102626947304SEvan Yan nvlist_free(nvl);
102726947304SEvan Yan return (EFAULT);
102826947304SEvan Yan }
102926947304SEvan Yan
103026947304SEvan Yan if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
103126947304SEvan Yan (uint_t *)&len)) == 0)
103226947304SEvan Yan rv = i_hp_unpack_node(buf, len, parent, &node);
103326947304SEvan Yan
103426947304SEvan Yan if (rv != 0) {
103526947304SEvan Yan nvlist_free(nvl);
103626947304SEvan Yan return (rv);
103726947304SEvan Yan }
103826947304SEvan Yan
103926947304SEvan Yan } else if (strcmp(nvpair_name(nvp), HP_INFO_BRANCH) == 0) {
104026947304SEvan Yan
104126947304SEvan Yan if ((rv = nvpair_value_byte_array(nvp, (uchar_t **)&buf,
104226947304SEvan Yan (uint_t *)&len)) == 0)
104326947304SEvan Yan rv = i_hp_unpack_branch(buf, len, node, &child);
104426947304SEvan Yan
104526947304SEvan Yan if (rv != 0) {
104626947304SEvan Yan hp_fini(node);
104726947304SEvan Yan nvlist_free(nvl);
104826947304SEvan Yan return (rv);
104926947304SEvan Yan }
105026947304SEvan Yan
105126947304SEvan Yan if (prev_child) {
105226947304SEvan Yan prev_child->hp_sibling = child;
105326947304SEvan Yan } else {
105426947304SEvan Yan node->hp_child = child;
105526947304SEvan Yan }
105626947304SEvan Yan prev_child = child;
105726947304SEvan Yan }
105826947304SEvan Yan }
105926947304SEvan Yan
106026947304SEvan Yan nvlist_free(nvl);
106126947304SEvan Yan *retp = node;
106226947304SEvan Yan return (0);
106326947304SEvan Yan }
106426947304SEvan Yan
106526947304SEvan Yan /*
106626947304SEvan Yan * i_hp_unpack_node()
106726947304SEvan Yan *
106826947304SEvan Yan * Unpack an individual hotplug information node.
106926947304SEvan Yan */
107026947304SEvan Yan static int
i_hp_unpack_node(char * buf,size_t len,hp_node_t parent,hp_node_t * retp)107126947304SEvan Yan i_hp_unpack_node(char *buf, size_t len, hp_node_t parent, hp_node_t *retp)
107226947304SEvan Yan {
107326947304SEvan Yan hp_node_t node;
107426947304SEvan Yan nvlist_t *nvl;
107526947304SEvan Yan nvpair_t *nvp;
107626947304SEvan Yan uint32_t val_uint32;
107726947304SEvan Yan char *val_string;
107826947304SEvan Yan int rv = 0;
107926947304SEvan Yan
108026947304SEvan Yan /* Initialize results */
108126947304SEvan Yan *retp = NULL;
108226947304SEvan Yan
108326947304SEvan Yan /* Unpack node into an nvlist */
108426947304SEvan Yan if ((nvlist_unpack(buf, len, &nvl, 0) != 0))
108526947304SEvan Yan return (EINVAL);
108626947304SEvan Yan
108726947304SEvan Yan /* Allocate the new node */
108826947304SEvan Yan if ((node = (hp_node_t)calloc(1, sizeof (struct hp_node))) == NULL) {
108926947304SEvan Yan nvlist_free(nvl);
109026947304SEvan Yan return (ENOMEM);
109126947304SEvan Yan }
109226947304SEvan Yan
109326947304SEvan Yan /* Iterate through nvlist, unpacking each field */
109426947304SEvan Yan for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
109526947304SEvan Yan
109626947304SEvan Yan if ((strcmp(nvpair_name(nvp), HP_INFO_TYPE) == 0) &&
109726947304SEvan Yan (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
109826947304SEvan Yan
109926947304SEvan Yan (void) nvpair_value_uint32(nvp, &val_uint32);
110026947304SEvan Yan node->hp_type = val_uint32;
110126947304SEvan Yan
110226947304SEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_NAME) == 0) &&
110326947304SEvan Yan (nvpair_type(nvp) == DATA_TYPE_STRING)) {
110426947304SEvan Yan
110526947304SEvan Yan (void) nvpair_value_string(nvp, &val_string);
110626947304SEvan Yan if ((node->hp_name = strdup(val_string)) == NULL) {
110726947304SEvan Yan rv = ENOMEM;
110826947304SEvan Yan break;
110926947304SEvan Yan }
111026947304SEvan Yan
111126947304SEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_STATE) == 0) &&
111226947304SEvan Yan (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
111326947304SEvan Yan
111426947304SEvan Yan (void) nvpair_value_uint32(nvp, &val_uint32);
111526947304SEvan Yan node->hp_state = val_uint32;
111626947304SEvan Yan
111726947304SEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_USAGE) == 0) &&
111826947304SEvan Yan (nvpair_type(nvp) == DATA_TYPE_STRING)) {
111926947304SEvan Yan
112026947304SEvan Yan (void) nvpair_value_string(nvp, &val_string);
112126947304SEvan Yan if ((node->hp_usage = strdup(val_string)) == NULL) {
112226947304SEvan Yan rv = ENOMEM;
112326947304SEvan Yan break;
112426947304SEvan Yan }
112526947304SEvan Yan
112626947304SEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_DESC) == 0) &&
112726947304SEvan Yan (nvpair_type(nvp) == DATA_TYPE_STRING)) {
112826947304SEvan Yan
112926947304SEvan Yan (void) nvpair_value_string(nvp, &val_string);
113026947304SEvan Yan if ((node->hp_description = strdup(val_string))
113126947304SEvan Yan == NULL) {
113226947304SEvan Yan rv = ENOMEM;
113326947304SEvan Yan break;
113426947304SEvan Yan }
113526947304SEvan Yan
113626947304SEvan Yan } else if ((strcmp(nvpair_name(nvp), HP_INFO_TIME) == 0) &&
113726947304SEvan Yan (nvpair_type(nvp) == DATA_TYPE_UINT32)) {
113826947304SEvan Yan
113926947304SEvan Yan (void) nvpair_value_uint32(nvp, &val_uint32);
114026947304SEvan Yan node->hp_last_change = (time_t)val_uint32;
114126947304SEvan Yan
114226947304SEvan Yan } else {
114326947304SEvan Yan i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n",
114426947304SEvan Yan nvpair_name(nvp));
114526947304SEvan Yan }
114626947304SEvan Yan }
114726947304SEvan Yan
114826947304SEvan Yan /* Unpacked nvlist no longer needed */
114926947304SEvan Yan nvlist_free(nvl);
115026947304SEvan Yan
115126947304SEvan Yan /* Check for errors */
115226947304SEvan Yan if (rv != 0) {
115326947304SEvan Yan hp_fini(node);
115426947304SEvan Yan return (rv);
115526947304SEvan Yan }
115626947304SEvan Yan
115726947304SEvan Yan /* Success */
115826947304SEvan Yan node->hp_parent = parent;
115926947304SEvan Yan *retp = node;
116026947304SEvan Yan return (0);
116126947304SEvan Yan }
116226947304SEvan Yan
116326947304SEvan Yan /*
116426947304SEvan Yan * i_hp_call_hotplugd()
116526947304SEvan Yan *
116626947304SEvan Yan * Perform a door call to the hotplug daemon.
116726947304SEvan Yan */
116826947304SEvan Yan static int
i_hp_call_hotplugd(nvlist_t * args,nvlist_t ** resultsp)116926947304SEvan Yan i_hp_call_hotplugd(nvlist_t *args, nvlist_t **resultsp)
117026947304SEvan Yan {
117126947304SEvan Yan door_arg_t door_arg;
117226947304SEvan Yan nvlist_t *results = NULL;
117326947304SEvan Yan char *buf = NULL;
117426947304SEvan Yan size_t len = 0;
117526947304SEvan Yan uint64_t seqnum;
117626947304SEvan Yan int door_fd;
117726947304SEvan Yan int rv;
117826947304SEvan Yan
117926947304SEvan Yan /* Initialize results */
118026947304SEvan Yan *resultsp = NULL;
118126947304SEvan Yan
118226947304SEvan Yan /* Open door */
118326947304SEvan Yan if ((door_fd = open(HOTPLUGD_DOOR, O_RDONLY)) < 0) {
118426947304SEvan Yan i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n",
118526947304SEvan Yan strerror(errno));
118626947304SEvan Yan return (EBADF);
118726947304SEvan Yan }
118826947304SEvan Yan
118926947304SEvan Yan /* Pack the nvlist of arguments */
119026947304SEvan Yan if ((rv = nvlist_pack(args, &buf, &len, NV_ENCODE_NATIVE, 0)) != 0) {
119126947304SEvan Yan i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n",
119226947304SEvan Yan strerror(rv));
119326947304SEvan Yan return (rv);
119426947304SEvan Yan }
119526947304SEvan Yan
119626947304SEvan Yan /* Set the door argument using the packed arguments */
119726947304SEvan Yan door_arg.data_ptr = buf;
119826947304SEvan Yan door_arg.data_size = len;
119926947304SEvan Yan door_arg.desc_ptr = NULL;
120026947304SEvan Yan door_arg.desc_num = 0;
120126947304SEvan Yan door_arg.rbuf = (char *)(uintptr_t)&rv;
120226947304SEvan Yan door_arg.rsize = sizeof (rv);
120326947304SEvan Yan
120426947304SEvan Yan /* Attempt the door call */
120526947304SEvan Yan if (door_call(door_fd, &door_arg) != 0) {
120626947304SEvan Yan rv = errno;
120726947304SEvan Yan i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n",
120826947304SEvan Yan strerror(rv));
120926947304SEvan Yan (void) close(door_fd);
121026947304SEvan Yan free(buf);
121126947304SEvan Yan return (rv);
121226947304SEvan Yan }
121326947304SEvan Yan
121426947304SEvan Yan /* The arguments are no longer needed */
121526947304SEvan Yan free(buf);
121626947304SEvan Yan
121726947304SEvan Yan /*
121826947304SEvan Yan * If results are not in the original buffer provided,
121926947304SEvan Yan * then check and process the new results buffer.
122026947304SEvan Yan */
122126947304SEvan Yan if (door_arg.rbuf != (char *)(uintptr_t)&rv) {
122226947304SEvan Yan
122326947304SEvan Yan /*
122426947304SEvan Yan * First check that the buffer is valid. Then check for
122526947304SEvan Yan * the simple case where a short result code was sent.
122626947304SEvan Yan * The last case is a packed nvlist was returned, which
122726947304SEvan Yan * needs to be unpacked.
122826947304SEvan Yan */
122926947304SEvan Yan if ((door_arg.rbuf == NULL) ||
123026947304SEvan Yan (door_arg.data_size < sizeof (rv))) {
123126947304SEvan Yan i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n");
123226947304SEvan Yan rv = EFAULT;
123326947304SEvan Yan
123426947304SEvan Yan } else if (door_arg.data_size == sizeof (rv)) {
123526947304SEvan Yan rv = *(int *)(uintptr_t)door_arg.rbuf;
123626947304SEvan Yan
123726947304SEvan Yan } else if ((rv = nvlist_unpack(door_arg.rbuf,
123826947304SEvan Yan door_arg.data_size, &results, 0)) != 0) {
123926947304SEvan Yan i_hp_dprintf("i_hp_call_hotplugd: "
124026947304SEvan Yan "cannot unpack results (%s).\n", strerror(rv));
124126947304SEvan Yan results = NULL;
124226947304SEvan Yan rv = EFAULT;
124326947304SEvan Yan }
124426947304SEvan Yan
124526947304SEvan Yan /* Unmap the results buffer */
124626947304SEvan Yan if (door_arg.rbuf != NULL)
124726947304SEvan Yan (void) munmap(door_arg.rbuf, door_arg.rsize);
124826947304SEvan Yan
124926947304SEvan Yan /*
125026947304SEvan Yan * In the case of a packed nvlist, notify the daemon
125126947304SEvan Yan * that it can free the result buffer from its heap.
125226947304SEvan Yan */
125326947304SEvan Yan if ((results != NULL) &&
125426947304SEvan Yan (nvlist_lookup_uint64(results, HPD_SEQNUM, &seqnum) == 0)) {
125526947304SEvan Yan door_arg.data_ptr = (char *)(uintptr_t)&seqnum;
125626947304SEvan Yan door_arg.data_size = sizeof (seqnum);
125726947304SEvan Yan door_arg.desc_ptr = NULL;
125826947304SEvan Yan door_arg.desc_num = 0;
125926947304SEvan Yan door_arg.rbuf = NULL;
126026947304SEvan Yan door_arg.rsize = 0;
126126947304SEvan Yan (void) door_call(door_fd, &door_arg);
126226947304SEvan Yan if (door_arg.rbuf != NULL)
126326947304SEvan Yan (void) munmap(door_arg.rbuf, door_arg.rsize);
126426947304SEvan Yan }
126526947304SEvan Yan
126626947304SEvan Yan *resultsp = results;
126726947304SEvan Yan }
126826947304SEvan Yan
126926947304SEvan Yan (void) close(door_fd);
127026947304SEvan Yan return (rv);
127126947304SEvan Yan }
127226947304SEvan Yan
127326947304SEvan Yan /*
127426947304SEvan Yan * i_hp_set_args()
127526947304SEvan Yan *
127626947304SEvan Yan * Construct an nvlist of arguments for a hotplugd door call.
127726947304SEvan Yan */
127826947304SEvan Yan static nvlist_t *
i_hp_set_args(hp_cmd_t cmd,const char * path,const char * connection,uint_t flags,const char * options,int state)127926947304SEvan Yan i_hp_set_args(hp_cmd_t cmd, const char *path, const char *connection,
128026947304SEvan Yan uint_t flags, const char *options, int state)
128126947304SEvan Yan {
128226947304SEvan Yan nvlist_t *args;
128326947304SEvan Yan
128426947304SEvan Yan /* Allocate a new nvlist */
128526947304SEvan Yan if (nvlist_alloc(&args, NV_UNIQUE_NAME_TYPE, 0) != 0)
128626947304SEvan Yan return (NULL);
128726947304SEvan Yan
128826947304SEvan Yan /* Add common arguments */
128926947304SEvan Yan if ((nvlist_add_int32(args, HPD_CMD, cmd) != 0) ||
129026947304SEvan Yan (nvlist_add_string(args, HPD_PATH, path) != 0)) {
129126947304SEvan Yan nvlist_free(args);
129226947304SEvan Yan return (NULL);
129326947304SEvan Yan }
129426947304SEvan Yan
129526947304SEvan Yan /* Add connection, but only if defined */
129626947304SEvan Yan if ((connection != NULL) && (connection[0] != '\0') &&
129726947304SEvan Yan (nvlist_add_string(args, HPD_CONNECTION, connection) != 0)) {
129826947304SEvan Yan nvlist_free(args);
129926947304SEvan Yan return (NULL);
130026947304SEvan Yan }
130126947304SEvan Yan
130226947304SEvan Yan /* Add flags, but only if defined */
130326947304SEvan Yan if ((flags != 0) && (nvlist_add_uint32(args, HPD_FLAGS, flags) != 0)) {
130426947304SEvan Yan nvlist_free(args);
130526947304SEvan Yan return (NULL);
130626947304SEvan Yan }
130726947304SEvan Yan
130826947304SEvan Yan /* Add options, but only if defined */
130926947304SEvan Yan if ((options != NULL) &&
131026947304SEvan Yan (nvlist_add_string(args, HPD_OPTIONS, options) != 0)) {
131126947304SEvan Yan nvlist_free(args);
131226947304SEvan Yan return (NULL);
131326947304SEvan Yan }
131426947304SEvan Yan
131526947304SEvan Yan /* Add state, but only for CHANGESTATE command */
131626947304SEvan Yan if ((cmd == HP_CMD_CHANGESTATE) &&
131726947304SEvan Yan (nvlist_add_int32(args, HPD_STATE, state) != 0)) {
131826947304SEvan Yan nvlist_free(args);
131926947304SEvan Yan return (NULL);
132026947304SEvan Yan }
132126947304SEvan Yan
132226947304SEvan Yan return (args);
132326947304SEvan Yan }
132426947304SEvan Yan
132526947304SEvan Yan /*
132626947304SEvan Yan * i_hp_parse_results()
132726947304SEvan Yan *
132826947304SEvan Yan * Parse out individual fields of an nvlist of results from
132926947304SEvan Yan * a hotplugd door call.
133026947304SEvan Yan */
133126947304SEvan Yan static int
i_hp_parse_results(nvlist_t * results,hp_node_t * rootp,char ** optionsp)133226947304SEvan Yan i_hp_parse_results(nvlist_t *results, hp_node_t *rootp, char **optionsp)
133326947304SEvan Yan {
133426947304SEvan Yan int rv;
133526947304SEvan Yan
133626947304SEvan Yan /* Parse an information snapshot */
133726947304SEvan Yan if (rootp) {
133826947304SEvan Yan char *buf = NULL;
133926947304SEvan Yan size_t len = 0;
134026947304SEvan Yan
134126947304SEvan Yan *rootp = NULL;
134226947304SEvan Yan if (nvlist_lookup_byte_array(results, HPD_INFO,
134326947304SEvan Yan (uchar_t **)&buf, (uint_t *)&len) == 0) {
134426947304SEvan Yan if ((rv = hp_unpack(buf, len, rootp)) != 0)
134526947304SEvan Yan return (rv);
134626947304SEvan Yan }
134726947304SEvan Yan }
134826947304SEvan Yan
134926947304SEvan Yan /* Parse a bus private option string */
135026947304SEvan Yan if (optionsp) {
135126947304SEvan Yan char *str;
135226947304SEvan Yan
135326947304SEvan Yan *optionsp = NULL;
135426947304SEvan Yan if ((nvlist_lookup_string(results, HPD_OPTIONS, &str) == 0) &&
135526947304SEvan Yan ((*optionsp = strdup(str)) == NULL)) {
135626947304SEvan Yan return (ENOMEM);
135726947304SEvan Yan }
135826947304SEvan Yan }
135926947304SEvan Yan
136026947304SEvan Yan /* Parse result code of the operation */
136126947304SEvan Yan if (nvlist_lookup_int32(results, HPD_STATUS, &rv) != 0) {
136226947304SEvan Yan i_hp_dprintf("i_hp_call_hotplugd: missing status.\n");
136326947304SEvan Yan return (EFAULT);
136426947304SEvan Yan }
136526947304SEvan Yan
136626947304SEvan Yan return (rv);
136726947304SEvan Yan }
1368