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