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