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