xref: /onnv-gate/usr/src/cmd/hotplugd/hotplugd_impl.c (revision 10923:df470fd79c3c)
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 /*
23*10923SEvan.Yan@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*10923SEvan.Yan@Sun.COM  * Use is subject to license terms.
25*10923SEvan.Yan@Sun.COM  */
26*10923SEvan.Yan@Sun.COM 
27*10923SEvan.Yan@Sun.COM #include <stdio.h>
28*10923SEvan.Yan@Sun.COM #include <stdlib.h>
29*10923SEvan.Yan@Sun.COM #include <unistd.h>
30*10923SEvan.Yan@Sun.COM #include <errno.h>
31*10923SEvan.Yan@Sun.COM #include <string.h>
32*10923SEvan.Yan@Sun.COM #include <pthread.h>
33*10923SEvan.Yan@Sun.COM #include <alloca.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/types.h>
38*10923SEvan.Yan@Sun.COM #include <sys/sunddi.h>
39*10923SEvan.Yan@Sun.COM #include <sys/ddi_hp.h>
40*10923SEvan.Yan@Sun.COM #include <sys/modctl.h>
41*10923SEvan.Yan@Sun.COM #include "hotplugd_impl.h"
42*10923SEvan.Yan@Sun.COM 
43*10923SEvan.Yan@Sun.COM /*
44*10923SEvan.Yan@Sun.COM  * All operations affecting kernel state are serialized.
45*10923SEvan.Yan@Sun.COM  */
46*10923SEvan.Yan@Sun.COM static pthread_mutex_t	hotplug_lock = PTHREAD_MUTEX_INITIALIZER;
47*10923SEvan.Yan@Sun.COM 
48*10923SEvan.Yan@Sun.COM /*
49*10923SEvan.Yan@Sun.COM  * Local functions.
50*10923SEvan.Yan@Sun.COM  */
51*10923SEvan.Yan@Sun.COM static boolean_t	check_rcm_required(hp_node_t, int);
52*10923SEvan.Yan@Sun.COM static int		pack_properties(const char *, ddi_hp_property_t *);
53*10923SEvan.Yan@Sun.COM static void		unpack_properties(ddi_hp_property_t *, char **);
54*10923SEvan.Yan@Sun.COM static void		free_properties(ddi_hp_property_t *);
55*10923SEvan.Yan@Sun.COM 
56*10923SEvan.Yan@Sun.COM /*
57*10923SEvan.Yan@Sun.COM  * changestate()
58*10923SEvan.Yan@Sun.COM  *
59*10923SEvan.Yan@Sun.COM  *	Perform a state change operation.
60*10923SEvan.Yan@Sun.COM  *
61*10923SEvan.Yan@Sun.COM  *	NOTE: all operations are serialized, using a global lock.
62*10923SEvan.Yan@Sun.COM  */
63*10923SEvan.Yan@Sun.COM int
changestate(const char * path,const char * connection,int state,uint_t flags,int * old_statep,hp_node_t * resultsp)64*10923SEvan.Yan@Sun.COM changestate(const char *path, const char *connection, int state, uint_t flags,
65*10923SEvan.Yan@Sun.COM     int *old_statep, hp_node_t *resultsp)
66*10923SEvan.Yan@Sun.COM {
67*10923SEvan.Yan@Sun.COM 	hp_node_t	root = NULL;
68*10923SEvan.Yan@Sun.COM 	char		**rsrcs = NULL;
69*10923SEvan.Yan@Sun.COM 	boolean_t	use_rcm = B_FALSE;
70*10923SEvan.Yan@Sun.COM 	int		rv;
71*10923SEvan.Yan@Sun.COM 
72*10923SEvan.Yan@Sun.COM 	dprintf("changestate(path=%s, connection=%s, state=0x%x, flags=0x%x)\n",
73*10923SEvan.Yan@Sun.COM 	    path, connection, state, flags);
74*10923SEvan.Yan@Sun.COM 
75*10923SEvan.Yan@Sun.COM 	/* Initialize results */
76*10923SEvan.Yan@Sun.COM 	*resultsp = NULL;
77*10923SEvan.Yan@Sun.COM 	*old_statep = -1;
78*10923SEvan.Yan@Sun.COM 
79*10923SEvan.Yan@Sun.COM 	(void) pthread_mutex_lock(&hotplug_lock);
80*10923SEvan.Yan@Sun.COM 
81*10923SEvan.Yan@Sun.COM 	/* Get an information snapshot, without usage details */
82*10923SEvan.Yan@Sun.COM 	if ((rv = getinfo(path, connection, 0, &root)) != 0) {
83*10923SEvan.Yan@Sun.COM 		(void) pthread_mutex_unlock(&hotplug_lock);
84*10923SEvan.Yan@Sun.COM 		dprintf("changestate: getinfo() failed (%s)\n", strerror(rv));
85*10923SEvan.Yan@Sun.COM 		return (rv);
86*10923SEvan.Yan@Sun.COM 	}
87*10923SEvan.Yan@Sun.COM 
88*10923SEvan.Yan@Sun.COM 	/* Record current state (used in hotplugd_door.c for auditing) */
89*10923SEvan.Yan@Sun.COM 	*old_statep = hp_state(root);
90*10923SEvan.Yan@Sun.COM 
91*10923SEvan.Yan@Sun.COM 	/* Check if RCM interactions are required */
92*10923SEvan.Yan@Sun.COM 	use_rcm = check_rcm_required(root, state);
93*10923SEvan.Yan@Sun.COM 
94*10923SEvan.Yan@Sun.COM 	/* If RCM is required, perform RCM offline */
95*10923SEvan.Yan@Sun.COM 	if (use_rcm) {
96*10923SEvan.Yan@Sun.COM 
97*10923SEvan.Yan@Sun.COM 		dprintf("changestate: RCM offline is required.\n");
98*10923SEvan.Yan@Sun.COM 
99*10923SEvan.Yan@Sun.COM 		/* Get RCM resources */
100*10923SEvan.Yan@Sun.COM 		if ((rv = rcm_resources(root, &rsrcs)) != 0) {
101*10923SEvan.Yan@Sun.COM 			dprintf("changestate: rcm_resources() failed.\n");
102*10923SEvan.Yan@Sun.COM 			(void) pthread_mutex_unlock(&hotplug_lock);
103*10923SEvan.Yan@Sun.COM 			hp_fini(root);
104*10923SEvan.Yan@Sun.COM 			return (rv);
105*10923SEvan.Yan@Sun.COM 		}
106*10923SEvan.Yan@Sun.COM 
107*10923SEvan.Yan@Sun.COM 		/* Request RCM offline */
108*10923SEvan.Yan@Sun.COM 		if ((rsrcs != NULL) &&
109*10923SEvan.Yan@Sun.COM 		    ((rv = rcm_offline(rsrcs, flags, root)) != 0)) {
110*10923SEvan.Yan@Sun.COM 			dprintf("changestate: rcm_offline() failed.\n");
111*10923SEvan.Yan@Sun.COM 			rcm_online(rsrcs);
112*10923SEvan.Yan@Sun.COM 			(void) pthread_mutex_unlock(&hotplug_lock);
113*10923SEvan.Yan@Sun.COM 			free_rcm_resources(rsrcs);
114*10923SEvan.Yan@Sun.COM 			*resultsp = root;
115*10923SEvan.Yan@Sun.COM 			return (rv);
116*10923SEvan.Yan@Sun.COM 		}
117*10923SEvan.Yan@Sun.COM 	}
118*10923SEvan.Yan@Sun.COM 
119*10923SEvan.Yan@Sun.COM 	/* The information snapshot is no longer needed */
120*10923SEvan.Yan@Sun.COM 	hp_fini(root);
121*10923SEvan.Yan@Sun.COM 
122*10923SEvan.Yan@Sun.COM 	/* Stop now if QUERY flag was specified */
123*10923SEvan.Yan@Sun.COM 	if (flags & HPQUERY) {
124*10923SEvan.Yan@Sun.COM 		dprintf("changestate: operation was QUERY only.\n");
125*10923SEvan.Yan@Sun.COM 		rcm_online(rsrcs);
126*10923SEvan.Yan@Sun.COM 		(void) pthread_mutex_unlock(&hotplug_lock);
127*10923SEvan.Yan@Sun.COM 		free_rcm_resources(rsrcs);
128*10923SEvan.Yan@Sun.COM 		return (0);
129*10923SEvan.Yan@Sun.COM 	}
130*10923SEvan.Yan@Sun.COM 
131*10923SEvan.Yan@Sun.COM 	/* Do state change in kernel */
132*10923SEvan.Yan@Sun.COM 	rv = 0;
133*10923SEvan.Yan@Sun.COM 	if (modctl(MODHPOPS, MODHPOPS_CHANGE_STATE, path, connection, state))
134*10923SEvan.Yan@Sun.COM 		rv = errno;
135*10923SEvan.Yan@Sun.COM 	dprintf("changestate: modctl(MODHPOPS_CHANGE_STATE) = %d.\n", rv);
136*10923SEvan.Yan@Sun.COM 
137*10923SEvan.Yan@Sun.COM 	/*
138*10923SEvan.Yan@Sun.COM 	 * If RCM is required, then perform an RCM online or RCM remove
139*10923SEvan.Yan@Sun.COM 	 * operation.  Which depends upon if modctl succeeded or failed.
140*10923SEvan.Yan@Sun.COM 	 */
141*10923SEvan.Yan@Sun.COM 	if (use_rcm && (rsrcs != NULL)) {
142*10923SEvan.Yan@Sun.COM 
143*10923SEvan.Yan@Sun.COM 		/* RCM online if failure, or RCM remove if successful */
144*10923SEvan.Yan@Sun.COM 		if (rv == 0)
145*10923SEvan.Yan@Sun.COM 			rcm_remove(rsrcs);
146*10923SEvan.Yan@Sun.COM 		else
147*10923SEvan.Yan@Sun.COM 			rcm_online(rsrcs);
148*10923SEvan.Yan@Sun.COM 
149*10923SEvan.Yan@Sun.COM 		/* RCM resources no longer required */
150*10923SEvan.Yan@Sun.COM 		free_rcm_resources(rsrcs);
151*10923SEvan.Yan@Sun.COM 	}
152*10923SEvan.Yan@Sun.COM 
153*10923SEvan.Yan@Sun.COM 	(void) pthread_mutex_unlock(&hotplug_lock);
154*10923SEvan.Yan@Sun.COM 
155*10923SEvan.Yan@Sun.COM 	*resultsp = NULL;
156*10923SEvan.Yan@Sun.COM 	return (rv);
157*10923SEvan.Yan@Sun.COM }
158*10923SEvan.Yan@Sun.COM 
159*10923SEvan.Yan@Sun.COM /*
160*10923SEvan.Yan@Sun.COM  * private_options()
161*10923SEvan.Yan@Sun.COM  *
162*10923SEvan.Yan@Sun.COM  *	Implement set/get of bus private options.
163*10923SEvan.Yan@Sun.COM  */
164*10923SEvan.Yan@Sun.COM int
private_options(const char * path,const char * connection,hp_cmd_t cmd,const char * options,char ** resultsp)165*10923SEvan.Yan@Sun.COM private_options(const char *path, const char *connection, hp_cmd_t cmd,
166*10923SEvan.Yan@Sun.COM     const char *options, char **resultsp)
167*10923SEvan.Yan@Sun.COM {
168*10923SEvan.Yan@Sun.COM 	ddi_hp_property_t	prop;
169*10923SEvan.Yan@Sun.COM 	ddi_hp_property_t	results;
170*10923SEvan.Yan@Sun.COM 	char			*values = NULL;
171*10923SEvan.Yan@Sun.COM 	int			rv;
172*10923SEvan.Yan@Sun.COM 
173*10923SEvan.Yan@Sun.COM 	dprintf("private_options(path=%s, connection=%s, options='%s')\n",
174*10923SEvan.Yan@Sun.COM 	    path, connection, options);
175*10923SEvan.Yan@Sun.COM 
176*10923SEvan.Yan@Sun.COM 	/* Initialize property arguments */
177*10923SEvan.Yan@Sun.COM 	if ((rv = pack_properties(options, &prop)) != 0) {
178*10923SEvan.Yan@Sun.COM 		dprintf("private_options: failed to pack properties.\n");
179*10923SEvan.Yan@Sun.COM 		return (rv);
180*10923SEvan.Yan@Sun.COM 	}
181*10923SEvan.Yan@Sun.COM 
182*10923SEvan.Yan@Sun.COM 	/* Initialize results */
183*10923SEvan.Yan@Sun.COM 	(void) memset(&results, 0, sizeof (ddi_hp_property_t));
184*10923SEvan.Yan@Sun.COM 	results.buf_size = HP_PRIVATE_BUF_SZ;
185*10923SEvan.Yan@Sun.COM 	results.nvlist_buf = (char *)calloc(1, HP_PRIVATE_BUF_SZ);
186*10923SEvan.Yan@Sun.COM 	if (results.nvlist_buf == NULL) {
187*10923SEvan.Yan@Sun.COM 		dprintf("private_options: failed to allocate buffer.\n");
188*10923SEvan.Yan@Sun.COM 		free_properties(&prop);
189*10923SEvan.Yan@Sun.COM 		return (ENOMEM);
190*10923SEvan.Yan@Sun.COM 	}
191*10923SEvan.Yan@Sun.COM 
192*10923SEvan.Yan@Sun.COM 	/* Lock hotplug */
193*10923SEvan.Yan@Sun.COM 	(void) pthread_mutex_lock(&hotplug_lock);
194*10923SEvan.Yan@Sun.COM 
195*10923SEvan.Yan@Sun.COM 	/* Perform the command */
196*10923SEvan.Yan@Sun.COM 	rv = 0;
197*10923SEvan.Yan@Sun.COM 	if (cmd == HP_CMD_GETPRIVATE) {
198*10923SEvan.Yan@Sun.COM 		if (modctl(MODHPOPS, MODHPOPS_BUS_GET, path, connection,
199*10923SEvan.Yan@Sun.COM 		    &prop, &results))
200*10923SEvan.Yan@Sun.COM 			rv = errno;
201*10923SEvan.Yan@Sun.COM 		dprintf("private_options: modctl(MODHPOPS_BUS_GET) = %d\n", rv);
202*10923SEvan.Yan@Sun.COM 	} else {
203*10923SEvan.Yan@Sun.COM 		if (modctl(MODHPOPS, MODHPOPS_BUS_SET, path, connection,
204*10923SEvan.Yan@Sun.COM 		    &prop, &results))
205*10923SEvan.Yan@Sun.COM 			rv = errno;
206*10923SEvan.Yan@Sun.COM 		dprintf("private_options: modctl(MODHPOPS_BUS_SET) = %d\n", rv);
207*10923SEvan.Yan@Sun.COM 	}
208*10923SEvan.Yan@Sun.COM 
209*10923SEvan.Yan@Sun.COM 	/* Unlock hotplug */
210*10923SEvan.Yan@Sun.COM 	(void) pthread_mutex_unlock(&hotplug_lock);
211*10923SEvan.Yan@Sun.COM 
212*10923SEvan.Yan@Sun.COM 	/* Parse results */
213*10923SEvan.Yan@Sun.COM 	if (rv == 0) {
214*10923SEvan.Yan@Sun.COM 		unpack_properties(&results, &values);
215*10923SEvan.Yan@Sun.COM 		*resultsp = values;
216*10923SEvan.Yan@Sun.COM 	}
217*10923SEvan.Yan@Sun.COM 
218*10923SEvan.Yan@Sun.COM 	/* Cleanup */
219*10923SEvan.Yan@Sun.COM 	free_properties(&prop);
220*10923SEvan.Yan@Sun.COM 	free_properties(&results);
221*10923SEvan.Yan@Sun.COM 
222*10923SEvan.Yan@Sun.COM 	return (rv);
223*10923SEvan.Yan@Sun.COM }
224*10923SEvan.Yan@Sun.COM 
225*10923SEvan.Yan@Sun.COM /*
226*10923SEvan.Yan@Sun.COM  * check_rcm_required()
227*10923SEvan.Yan@Sun.COM  *
228*10923SEvan.Yan@Sun.COM  *	Given the root of a changestate operation and the target
229*10923SEvan.Yan@Sun.COM  *	state, determine if RCM interactions will be required.
230*10923SEvan.Yan@Sun.COM  */
231*10923SEvan.Yan@Sun.COM static boolean_t
check_rcm_required(hp_node_t root,int target_state)232*10923SEvan.Yan@Sun.COM check_rcm_required(hp_node_t root, int target_state)
233*10923SEvan.Yan@Sun.COM {
234*10923SEvan.Yan@Sun.COM 	/*
235*10923SEvan.Yan@Sun.COM 	 * RCM is required when transitioning an ENABLED
236*10923SEvan.Yan@Sun.COM 	 * connector to a non-ENABLED state.
237*10923SEvan.Yan@Sun.COM 	 */
238*10923SEvan.Yan@Sun.COM 	if ((root->hp_type == HP_NODE_CONNECTOR) &&
239*10923SEvan.Yan@Sun.COM 	    HP_IS_ENABLED(root->hp_state) && !HP_IS_ENABLED(target_state))
240*10923SEvan.Yan@Sun.COM 		return (B_TRUE);
241*10923SEvan.Yan@Sun.COM 
242*10923SEvan.Yan@Sun.COM 	/*
243*10923SEvan.Yan@Sun.COM 	 * RCM is required when transitioning an OPERATIONAL
244*10923SEvan.Yan@Sun.COM 	 * port to a non-OPERATIONAL state.
245*10923SEvan.Yan@Sun.COM 	 */
246*10923SEvan.Yan@Sun.COM 	if ((root->hp_type == HP_NODE_PORT) &&
247*10923SEvan.Yan@Sun.COM 	    HP_IS_ONLINE(root->hp_state) && HP_IS_OFFLINE(target_state))
248*10923SEvan.Yan@Sun.COM 		return (B_TRUE);
249*10923SEvan.Yan@Sun.COM 
250*10923SEvan.Yan@Sun.COM 	/* RCM is not required in other cases */
251*10923SEvan.Yan@Sun.COM 	return (B_FALSE);
252*10923SEvan.Yan@Sun.COM }
253*10923SEvan.Yan@Sun.COM 
254*10923SEvan.Yan@Sun.COM /*
255*10923SEvan.Yan@Sun.COM  * pack_properties()
256*10923SEvan.Yan@Sun.COM  *
257*10923SEvan.Yan@Sun.COM  *	Given a specified set/get command and an options string,
258*10923SEvan.Yan@Sun.COM  *	construct the structure containing a packed nvlist that
259*10923SEvan.Yan@Sun.COM  *	contains the specified options.
260*10923SEvan.Yan@Sun.COM  */
261*10923SEvan.Yan@Sun.COM static int
pack_properties(const char * options,ddi_hp_property_t * prop)262*10923SEvan.Yan@Sun.COM pack_properties(const char *options, ddi_hp_property_t *prop)
263*10923SEvan.Yan@Sun.COM {
264*10923SEvan.Yan@Sun.COM 	nvlist_t	*nvl;
265*10923SEvan.Yan@Sun.COM 	char		*buf, *tmp, *name, *value, *next;
266*10923SEvan.Yan@Sun.COM 	size_t		len;
267*10923SEvan.Yan@Sun.COM 
268*10923SEvan.Yan@Sun.COM 	/* Initialize results */
269*10923SEvan.Yan@Sun.COM 	(void) memset(prop, 0, sizeof (ddi_hp_property_t));
270*10923SEvan.Yan@Sun.COM 
271*10923SEvan.Yan@Sun.COM 	/* Do nothing if options string is empty */
272*10923SEvan.Yan@Sun.COM 	if ((len = strlen(options)) == 0) {
273*10923SEvan.Yan@Sun.COM 		dprintf("pack_properties: options string is empty.\n");
274*10923SEvan.Yan@Sun.COM 		return (ENOENT);
275*10923SEvan.Yan@Sun.COM 	}
276*10923SEvan.Yan@Sun.COM 
277*10923SEvan.Yan@Sun.COM 	/* Avoid modifying the input string by using a copy on the stack */
278*10923SEvan.Yan@Sun.COM 	if ((tmp = (char *)alloca(len + 1)) == NULL) {
279*10923SEvan.Yan@Sun.COM 		log_err("Failed to allocate buffer for private options.\n");
280*10923SEvan.Yan@Sun.COM 		return (ENOMEM);
281*10923SEvan.Yan@Sun.COM 	}
282*10923SEvan.Yan@Sun.COM 	(void) strlcpy(tmp, options, len + 1);
283*10923SEvan.Yan@Sun.COM 
284*10923SEvan.Yan@Sun.COM 	/* Allocate the nvlist */
285*10923SEvan.Yan@Sun.COM 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
286*10923SEvan.Yan@Sun.COM 		log_err("Failed to allocate private options nvlist.\n");
287*10923SEvan.Yan@Sun.COM 		return (ENOMEM);
288*10923SEvan.Yan@Sun.COM 	}
289*10923SEvan.Yan@Sun.COM 
290*10923SEvan.Yan@Sun.COM 	/* Add each option from the string */
291*10923SEvan.Yan@Sun.COM 	for (name = tmp; name != NULL; name = next) {
292*10923SEvan.Yan@Sun.COM 
293*10923SEvan.Yan@Sun.COM 		/* Isolate current name/value, and locate the next */
294*10923SEvan.Yan@Sun.COM 		if ((next = strchr(name, ',')) != NULL) {
295*10923SEvan.Yan@Sun.COM 			*next = '\0';
296*10923SEvan.Yan@Sun.COM 			next++;
297*10923SEvan.Yan@Sun.COM 		}
298*10923SEvan.Yan@Sun.COM 
299*10923SEvan.Yan@Sun.COM 		/* Split current name/value pair */
300*10923SEvan.Yan@Sun.COM 		if ((value = strchr(name, '=')) != NULL) {
301*10923SEvan.Yan@Sun.COM 			*value = '\0';
302*10923SEvan.Yan@Sun.COM 			value++;
303*10923SEvan.Yan@Sun.COM 		} else {
304*10923SEvan.Yan@Sun.COM 			value = "";
305*10923SEvan.Yan@Sun.COM 		}
306*10923SEvan.Yan@Sun.COM 
307*10923SEvan.Yan@Sun.COM 		/* Add the option to the nvlist */
308*10923SEvan.Yan@Sun.COM 		if (nvlist_add_string(nvl, name, value) != 0) {
309*10923SEvan.Yan@Sun.COM 			log_err("Failed to add private option to nvlist.\n");
310*10923SEvan.Yan@Sun.COM 			nvlist_free(nvl);
311*10923SEvan.Yan@Sun.COM 			return (EFAULT);
312*10923SEvan.Yan@Sun.COM 		}
313*10923SEvan.Yan@Sun.COM 	}
314*10923SEvan.Yan@Sun.COM 
315*10923SEvan.Yan@Sun.COM 	/* Pack the nvlist */
316*10923SEvan.Yan@Sun.COM 	len = 0;
317*10923SEvan.Yan@Sun.COM 	buf = NULL;
318*10923SEvan.Yan@Sun.COM 	if (nvlist_pack(nvl, &buf, &len, NV_ENCODE_NATIVE, 0) != 0) {
319*10923SEvan.Yan@Sun.COM 		log_err("Failed to pack private options nvlist.\n");
320*10923SEvan.Yan@Sun.COM 		nvlist_free(nvl);
321*10923SEvan.Yan@Sun.COM 		return (EFAULT);
322*10923SEvan.Yan@Sun.COM 	}
323*10923SEvan.Yan@Sun.COM 
324*10923SEvan.Yan@Sun.COM 	/* Save results */
325*10923SEvan.Yan@Sun.COM 	prop->nvlist_buf = buf;
326*10923SEvan.Yan@Sun.COM 	prop->buf_size = len;
327*10923SEvan.Yan@Sun.COM 
328*10923SEvan.Yan@Sun.COM 	/* The nvlist is no longer needed */
329*10923SEvan.Yan@Sun.COM 	nvlist_free(nvl);
330*10923SEvan.Yan@Sun.COM 
331*10923SEvan.Yan@Sun.COM 	return (0);
332*10923SEvan.Yan@Sun.COM }
333*10923SEvan.Yan@Sun.COM 
334*10923SEvan.Yan@Sun.COM /*
335*10923SEvan.Yan@Sun.COM  * unpack_properties()
336*10923SEvan.Yan@Sun.COM  *
337*10923SEvan.Yan@Sun.COM  *	Given a structure possibly containing a packed nvlist of
338*10923SEvan.Yan@Sun.COM  *	bus private options, unpack the nvlist and expand its
339*10923SEvan.Yan@Sun.COM  *	contents into an options string.
340*10923SEvan.Yan@Sun.COM  */
341*10923SEvan.Yan@Sun.COM static void
unpack_properties(ddi_hp_property_t * prop,char ** optionsp)342*10923SEvan.Yan@Sun.COM unpack_properties(ddi_hp_property_t *prop, char **optionsp)
343*10923SEvan.Yan@Sun.COM {
344*10923SEvan.Yan@Sun.COM 	nvlist_t	*nvl = NULL;
345*10923SEvan.Yan@Sun.COM 	nvpair_t	*nvp;
346*10923SEvan.Yan@Sun.COM 	boolean_t	first_flag;
347*10923SEvan.Yan@Sun.COM 	char		*name, *value, *options;
348*10923SEvan.Yan@Sun.COM 	size_t		len;
349*10923SEvan.Yan@Sun.COM 
350*10923SEvan.Yan@Sun.COM 	/* Initialize results */
351*10923SEvan.Yan@Sun.COM 	*optionsp = NULL;
352*10923SEvan.Yan@Sun.COM 
353*10923SEvan.Yan@Sun.COM 	/* Do nothing if properties do not exist */
354*10923SEvan.Yan@Sun.COM 	if ((prop->nvlist_buf == NULL) || (prop->buf_size == 0)) {
355*10923SEvan.Yan@Sun.COM 		dprintf("unpack_properties: no properties exist.\n");
356*10923SEvan.Yan@Sun.COM 		return;
357*10923SEvan.Yan@Sun.COM 	}
358*10923SEvan.Yan@Sun.COM 
359*10923SEvan.Yan@Sun.COM 	/* Unpack the nvlist */
360*10923SEvan.Yan@Sun.COM 	if (nvlist_unpack(prop->nvlist_buf, prop->buf_size, &nvl, 0) != 0) {
361*10923SEvan.Yan@Sun.COM 		log_err("Failed to unpack private options nvlist.\n");
362*10923SEvan.Yan@Sun.COM 		return;
363*10923SEvan.Yan@Sun.COM 	}
364*10923SEvan.Yan@Sun.COM 
365*10923SEvan.Yan@Sun.COM 	/* Compute the size of the options string */
366*10923SEvan.Yan@Sun.COM 	for (len = 0, nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
367*10923SEvan.Yan@Sun.COM 
368*10923SEvan.Yan@Sun.COM 		name = nvpair_name(nvp);
369*10923SEvan.Yan@Sun.COM 
370*10923SEvan.Yan@Sun.COM 		/* Skip the command, and anything not a string */
371*10923SEvan.Yan@Sun.COM 		if ((strcmp(name, "cmd") == 0) ||
372*10923SEvan.Yan@Sun.COM 		    (nvpair_type(nvp) != DATA_TYPE_STRING))
373*10923SEvan.Yan@Sun.COM 			continue;
374*10923SEvan.Yan@Sun.COM 
375*10923SEvan.Yan@Sun.COM 		(void) nvpair_value_string(nvp, &value);
376*10923SEvan.Yan@Sun.COM 
377*10923SEvan.Yan@Sun.COM 		/* Account for '=' signs, commas, and terminating NULL */
378*10923SEvan.Yan@Sun.COM 		len += (strlen(name) + strlen(value) + 2);
379*10923SEvan.Yan@Sun.COM 	}
380*10923SEvan.Yan@Sun.COM 
381*10923SEvan.Yan@Sun.COM 	/* Allocate the resulting options string */
382*10923SEvan.Yan@Sun.COM 	if ((options = (char *)calloc(len, sizeof (char))) == NULL) {
383*10923SEvan.Yan@Sun.COM 		log_err("Failed to allocate private options string.\n");
384*10923SEvan.Yan@Sun.COM 		nvlist_free(nvl);
385*10923SEvan.Yan@Sun.COM 		return;
386*10923SEvan.Yan@Sun.COM 	}
387*10923SEvan.Yan@Sun.COM 
388*10923SEvan.Yan@Sun.COM 	/* Copy name/value pairs into the options string */
389*10923SEvan.Yan@Sun.COM 	first_flag = B_TRUE;
390*10923SEvan.Yan@Sun.COM 	for (nvp = NULL; nvp = nvlist_next_nvpair(nvl, nvp); ) {
391*10923SEvan.Yan@Sun.COM 
392*10923SEvan.Yan@Sun.COM 		name = nvpair_name(nvp);
393*10923SEvan.Yan@Sun.COM 
394*10923SEvan.Yan@Sun.COM 		/* Skip the command, and anything not a string */
395*10923SEvan.Yan@Sun.COM 		if ((strcmp(name, "cmd") == 0) ||
396*10923SEvan.Yan@Sun.COM 		    (nvpair_type(nvp) != DATA_TYPE_STRING))
397*10923SEvan.Yan@Sun.COM 			continue;
398*10923SEvan.Yan@Sun.COM 
399*10923SEvan.Yan@Sun.COM 		if (!first_flag)
400*10923SEvan.Yan@Sun.COM 			(void) strlcat(options, ",", len);
401*10923SEvan.Yan@Sun.COM 
402*10923SEvan.Yan@Sun.COM 		(void) strlcat(options, name, len);
403*10923SEvan.Yan@Sun.COM 
404*10923SEvan.Yan@Sun.COM 		(void) nvpair_value_string(nvp, &value);
405*10923SEvan.Yan@Sun.COM 
406*10923SEvan.Yan@Sun.COM 		if (strlen(value) > 0) {
407*10923SEvan.Yan@Sun.COM 			(void) strlcat(options, "=", len);
408*10923SEvan.Yan@Sun.COM 			(void) strlcat(options, value, len);
409*10923SEvan.Yan@Sun.COM 		}
410*10923SEvan.Yan@Sun.COM 
411*10923SEvan.Yan@Sun.COM 		first_flag = B_FALSE;
412*10923SEvan.Yan@Sun.COM 	}
413*10923SEvan.Yan@Sun.COM 
414*10923SEvan.Yan@Sun.COM 	/* The unpacked nvlist is no longer needed */
415*10923SEvan.Yan@Sun.COM 	nvlist_free(nvl);
416*10923SEvan.Yan@Sun.COM 
417*10923SEvan.Yan@Sun.COM 	/* Save results */
418*10923SEvan.Yan@Sun.COM 	*optionsp = options;
419*10923SEvan.Yan@Sun.COM }
420*10923SEvan.Yan@Sun.COM 
421*10923SEvan.Yan@Sun.COM /*
422*10923SEvan.Yan@Sun.COM  * free_properties()
423*10923SEvan.Yan@Sun.COM  *
424*10923SEvan.Yan@Sun.COM  *	Destroy a structure containing a packed nvlist of bus
425*10923SEvan.Yan@Sun.COM  *	private properties.
426*10923SEvan.Yan@Sun.COM  */
427*10923SEvan.Yan@Sun.COM static void
free_properties(ddi_hp_property_t * prop)428*10923SEvan.Yan@Sun.COM free_properties(ddi_hp_property_t *prop)
429*10923SEvan.Yan@Sun.COM {
430*10923SEvan.Yan@Sun.COM 	if (prop) {
431*10923SEvan.Yan@Sun.COM 		if (prop->nvlist_buf)
432*10923SEvan.Yan@Sun.COM 			free(prop->nvlist_buf);
433*10923SEvan.Yan@Sun.COM 		(void) memset(prop, 0, sizeof (ddi_hp_property_t));
434*10923SEvan.Yan@Sun.COM 	}
435*10923SEvan.Yan@Sun.COM }
436