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