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