xref: /onnv-gate/usr/src/uts/common/os/retire_store.c (revision 4845:357e8e7542af)
1*4845Svikram /*
2*4845Svikram  * CDDL HEADER START
3*4845Svikram  *
4*4845Svikram  * The contents of this file are subject to the terms of the
5*4845Svikram  * Common Development and Distribution License (the "License").
6*4845Svikram  * You may not use this file except in compliance with the License.
7*4845Svikram  *
8*4845Svikram  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4845Svikram  * or http://www.opensolaris.org/os/licensing.
10*4845Svikram  * See the License for the specific language governing permissions
11*4845Svikram  * and limitations under the License.
12*4845Svikram  *
13*4845Svikram  * When distributing Covered Code, include this CDDL HEADER in each
14*4845Svikram  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4845Svikram  * If applicable, add the following below this CDDL HEADER, with the
16*4845Svikram  * fields enclosed by brackets "[]" replaced with your own identifying
17*4845Svikram  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4845Svikram  *
19*4845Svikram  * CDDL HEADER END
20*4845Svikram  */
21*4845Svikram /*
22*4845Svikram  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*4845Svikram  * Use is subject to license terms.
24*4845Svikram  */
25*4845Svikram 
26*4845Svikram #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*4845Svikram 
28*4845Svikram #include <sys/ddi.h>
29*4845Svikram #include <sys/sunddi.h>
30*4845Svikram #include <sys/sunndi.h>
31*4845Svikram #include <sys/ddi_impldefs.h>
32*4845Svikram #include <sys/ddi_implfuncs.h>
33*4845Svikram #include <sys/list.h>
34*4845Svikram #include <sys/reboot.h>
35*4845Svikram #include <sys/sysmacros.h>
36*4845Svikram #include <sys/console.h>
37*4845Svikram #include <sys/devcache.h>
38*4845Svikram 
39*4845Svikram /*
40*4845Svikram  * The nvpair name in the I/O retire specific sub-nvlist
41*4845Svikram  */
42*4845Svikram #define	RIO_STORE_VERSION_STR	"rio-store-version"
43*4845Svikram #define	RIO_STORE_MAGIC_STR	"rio-store-magic"
44*4845Svikram #define	RIO_STORE_FLAGS_STR	"rio-store-flags"
45*4845Svikram 
46*4845Svikram #define	RIO_STORE_VERSION_1	1
47*4845Svikram #define	RIO_STORE_VERSION	RIO_STORE_VERSION_1
48*4845Svikram 
49*4845Svikram /*
50*4845Svikram  * decoded retire list element
51*4845Svikram  */
52*4845Svikram 
53*4845Svikram typedef enum rio_store_flags {
54*4845Svikram 	RIO_STORE_F_INVAL = 0,
55*4845Svikram 	RIO_STORE_F_RETIRED = 1,
56*4845Svikram 	RIO_STORE_F_BYPASS = 2
57*4845Svikram } rio_store_flags_t;
58*4845Svikram 
59*4845Svikram typedef struct rio_store {
60*4845Svikram 	char			*rst_devpath;
61*4845Svikram 	rio_store_flags_t	rst_flags;
62*4845Svikram 	list_node_t		rst_next;
63*4845Svikram } rio_store_t;
64*4845Svikram 
65*4845Svikram #define	RIO_STORE_MAGIC		0x601fcace	/* retire */
66*4845Svikram 
67*4845Svikram static int rio_store_decode(nvf_handle_t nvfh, nvlist_t *line_nvl, char *name);
68*4845Svikram static int rio_store_encode(nvf_handle_t nvfh, nvlist_t **ret_nvl);
69*4845Svikram static void retire_list_free(nvf_handle_t  nvfh);
70*4845Svikram 
71*4845Svikram 
72*4845Svikram /*
73*4845Svikram  * Retire I/O persistent store registration info
74*4845Svikram  */
75*4845Svikram static nvf_ops_t rio_store_ops = {
76*4845Svikram 	"/etc/devices/retire_store",	/* path to store */
77*4845Svikram 	rio_store_decode,		/* decode nvlist into retire_list */
78*4845Svikram 	rio_store_encode,		/* encode retire_list into nvlist */
79*4845Svikram 	retire_list_free,		/* free retire_list */
80*4845Svikram 	NULL				/* write complete callback */
81*4845Svikram };
82*4845Svikram 
83*4845Svikram static nvf_handle_t	rio_store_handle;
84*4845Svikram static char		store_path[MAXPATHLEN];
85*4845Svikram static int		store_debug = 0;
86*4845Svikram static int		bypass_msg = 0;
87*4845Svikram static int		retire_msg = 0;
88*4845Svikram 
89*4845Svikram #define	STORE_DEBUG	0x0001
90*4845Svikram #define	STORE_TRACE	0x0002
91*4845Svikram 
92*4845Svikram #define	STORE_DBG(args)		if (store_debug & STORE_DEBUG)	cmn_err args
93*4845Svikram #define	STORE_TRC(args)		if (store_debug & STORE_TRACE)	cmn_err args
94*4845Svikram 
95*4845Svikram /*
96*4845Svikram  * We don't use the simple read disable offered by the
97*4845Svikram  * caching framework (see devcache.c) as it will not
98*4845Svikram  * have the desired effect of bypassing the persistent
99*4845Svikram  * store. A simple read disable will
100*4845Svikram  *
101*4845Svikram  *	1. cause any additions to the cache to destroy the
102*4845Svikram  *	   existing on-disk cache
103*4845Svikram  *
104*4845Svikram  *	2. prevent deletions from the existing on-disk
105*4845Svikram  *	   cache which is needed for recovery from bad
106*4845Svikram  *	   retire decisions.
107*4845Svikram  *
108*4845Svikram  * Use the following tunable instead
109*4845Svikram  *
110*4845Svikram  */
111*4845Svikram int	ddi_retire_store_bypass = 0;
112*4845Svikram 
113*4845Svikram 
114*4845Svikram 
115*4845Svikram /*
116*4845Svikram  * Initialize retire store data structures
117*4845Svikram  */
118*4845Svikram void
retire_store_init(void)119*4845Svikram retire_store_init(void)
120*4845Svikram {
121*4845Svikram 	if (boothowto & RB_ASKNAME) {
122*4845Svikram 
123*4845Svikram 		printf("Retire store [%s] (/dev/null to bypass): ",
124*4845Svikram 		    rio_store_ops.nvfr_cache_path);
125*4845Svikram 		console_gets(store_path, sizeof (store_path) - 1);
126*4845Svikram 		store_path[sizeof (store_path) - 1] = '\0';
127*4845Svikram 
128*4845Svikram 		if (strcmp(store_path, "/dev/null") == 0) {
129*4845Svikram 			ddi_retire_store_bypass = 1;
130*4845Svikram 		} else if (store_path[0] != '\0') {
131*4845Svikram 			if (store_path[0] != '/') {
132*4845Svikram 				printf("Invalid store path: %s. Using default"
133*4845Svikram 				    "\n", store_path);
134*4845Svikram 			} else {
135*4845Svikram 				rio_store_ops.nvfr_cache_path = store_path;
136*4845Svikram 			}
137*4845Svikram 		}
138*4845Svikram 	}
139*4845Svikram 
140*4845Svikram 	rio_store_handle = nvf_register_file(&rio_store_ops);
141*4845Svikram 
142*4845Svikram 	list_create(nvf_list(rio_store_handle), sizeof (rio_store_t),
143*4845Svikram 	    offsetof(rio_store_t, rst_next));
144*4845Svikram }
145*4845Svikram 
146*4845Svikram /*
147*4845Svikram  * Read and populate the in-core retire store
148*4845Svikram  */
149*4845Svikram void
retire_store_read(void)150*4845Svikram retire_store_read(void)
151*4845Svikram {
152*4845Svikram 	rw_enter(nvf_lock(rio_store_handle), RW_WRITER);
153*4845Svikram 	ASSERT(list_head(nvf_list(rio_store_handle)) == NULL);
154*4845Svikram 	(void) nvf_read_file(rio_store_handle);
155*4845Svikram 	rw_exit(nvf_lock(rio_store_handle));
156*4845Svikram 	STORE_DBG((CE_NOTE, "Read on-disk retire store"));
157*4845Svikram }
158*4845Svikram 
159*4845Svikram static void
rio_store_free(rio_store_t * rsp)160*4845Svikram rio_store_free(rio_store_t *rsp)
161*4845Svikram {
162*4845Svikram 	int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
163*4845Svikram 
164*4845Svikram 	ASSERT(rsp);
165*4845Svikram 	ASSERT(rsp->rst_devpath);
166*4845Svikram 	ASSERT(rsp->rst_flags & RIO_STORE_F_RETIRED);
167*4845Svikram 	ASSERT(!(rsp->rst_flags & ~flag_mask));
168*4845Svikram 
169*4845Svikram 	STORE_TRC((CE_NOTE, "store: freed path: %s", rsp->rst_devpath));
170*4845Svikram 
171*4845Svikram 	kmem_free(rsp->rst_devpath, strlen(rsp->rst_devpath) + 1);
172*4845Svikram 	kmem_free(rsp, sizeof (*rsp));
173*4845Svikram }
174*4845Svikram 
175*4845Svikram static void
retire_list_free(nvf_handle_t nvfh)176*4845Svikram retire_list_free(nvf_handle_t  nvfh)
177*4845Svikram {
178*4845Svikram 	list_t		*listp;
179*4845Svikram 	rio_store_t	*rsp;
180*4845Svikram 
181*4845Svikram 	ASSERT(nvfh == rio_store_handle);
182*4845Svikram 	ASSERT(RW_WRITE_HELD(nvf_lock(nvfh)));
183*4845Svikram 
184*4845Svikram 	listp = nvf_list(nvfh);
185*4845Svikram 	while (rsp = list_head(listp)) {
186*4845Svikram 		list_remove(listp, rsp);
187*4845Svikram 		rio_store_free(rsp);
188*4845Svikram 	}
189*4845Svikram 
190*4845Svikram 	STORE_DBG((CE_NOTE, "store: freed retire list"));
191*4845Svikram }
192*4845Svikram 
193*4845Svikram static int
rio_store_decode(nvf_handle_t nvfh,nvlist_t * line_nvl,char * name)194*4845Svikram rio_store_decode(nvf_handle_t nvfh, nvlist_t *line_nvl, char *name)
195*4845Svikram {
196*4845Svikram 	rio_store_t	*rsp;
197*4845Svikram 	int32_t		version;
198*4845Svikram 	int32_t		magic;
199*4845Svikram 	int32_t		flags;
200*4845Svikram 	int		rval;
201*4845Svikram 
202*4845Svikram 	ASSERT(nvfh == rio_store_handle);
203*4845Svikram 	ASSERT(RW_WRITE_HELD(nvf_lock(nvfh)));
204*4845Svikram 	ASSERT(name);
205*4845Svikram 
206*4845Svikram 	version = 0;
207*4845Svikram 	rval = nvlist_lookup_int32(line_nvl, RIO_STORE_VERSION_STR, &version);
208*4845Svikram 	if (rval != 0 || version != RIO_STORE_VERSION) {
209*4845Svikram 		return (EINVAL);
210*4845Svikram 	}
211*4845Svikram 
212*4845Svikram 	magic = 0;
213*4845Svikram 	rval = nvlist_lookup_int32(line_nvl, RIO_STORE_MAGIC_STR, &magic);
214*4845Svikram 	if (rval != 0 || magic != RIO_STORE_MAGIC) {
215*4845Svikram 		return (EINVAL);
216*4845Svikram 	}
217*4845Svikram 
218*4845Svikram 	flags = 0;
219*4845Svikram 	rval = nvlist_lookup_int32(line_nvl, RIO_STORE_FLAGS_STR, &flags);
220*4845Svikram 	if (rval != 0 || flags != RIO_STORE_F_RETIRED) {
221*4845Svikram 		return (EINVAL);
222*4845Svikram 	}
223*4845Svikram 
224*4845Svikram 	if (ddi_retire_store_bypass) {
225*4845Svikram 		flags |= RIO_STORE_F_BYPASS;
226*4845Svikram 		if (!bypass_msg) {
227*4845Svikram 			bypass_msg = 1;
228*4845Svikram 			cmn_err(CE_WARN,
229*4845Svikram 			    "Bypassing retire store /etc/devices/retire_store");
230*4845Svikram 		}
231*4845Svikram 	}
232*4845Svikram 
233*4845Svikram 	rsp = kmem_zalloc(sizeof (rio_store_t), KM_SLEEP);
234*4845Svikram 	rsp->rst_devpath = i_ddi_strdup(name, KM_SLEEP);
235*4845Svikram 	rsp->rst_flags = flags;
236*4845Svikram 	list_insert_tail(nvf_list(nvfh), rsp);
237*4845Svikram 
238*4845Svikram 	STORE_TRC((CE_NOTE, "store: added to retire list: %s", name));
239*4845Svikram 	if (!retire_msg) {
240*4845Svikram 		retire_msg = 1;
241*4845Svikram 		cmn_err(CE_NOTE, "One or more I/O devices have been retired");
242*4845Svikram 	}
243*4845Svikram 
244*4845Svikram 	return (0);
245*4845Svikram }
246*4845Svikram 
247*4845Svikram static int
rio_store_encode(nvf_handle_t nvfh,nvlist_t ** ret_nvl)248*4845Svikram rio_store_encode(nvf_handle_t nvfh, nvlist_t **ret_nvl)
249*4845Svikram {
250*4845Svikram 	nvlist_t	*nvl;
251*4845Svikram 	nvlist_t	*line_nvl;
252*4845Svikram 	list_t		*listp;
253*4845Svikram 	rio_store_t	*rsp;
254*4845Svikram 	int		rval;
255*4845Svikram 
256*4845Svikram 	ASSERT(nvfh == rio_store_handle);
257*4845Svikram 	ASSERT(RW_WRITE_HELD(nvf_lock(nvfh)));
258*4845Svikram 
259*4845Svikram 	*ret_nvl = NULL;
260*4845Svikram 
261*4845Svikram 	nvl = NULL;
262*4845Svikram 	rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
263*4845Svikram 	if (rval != 0) {
264*4845Svikram 		return (DDI_FAILURE);
265*4845Svikram 	}
266*4845Svikram 
267*4845Svikram 	listp = nvf_list(nvfh);
268*4845Svikram 	for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) {
269*4845Svikram 		int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
270*4845Svikram 		int flags;
271*4845Svikram 		ASSERT(rsp->rst_devpath);
272*4845Svikram 		ASSERT(!(rsp->rst_flags & ~flag_mask));
273*4845Svikram 
274*4845Svikram 		line_nvl = NULL;
275*4845Svikram 		rval = nvlist_alloc(&line_nvl, NV_UNIQUE_NAME, KM_SLEEP);
276*4845Svikram 		if (rval != 0) {
277*4845Svikram 			line_nvl = NULL;
278*4845Svikram 			goto error;
279*4845Svikram 		}
280*4845Svikram 
281*4845Svikram 		rval = nvlist_add_int32(line_nvl, RIO_STORE_VERSION_STR,
282*4845Svikram 			RIO_STORE_VERSION);
283*4845Svikram 		if (rval != 0) {
284*4845Svikram 			goto error;
285*4845Svikram 		}
286*4845Svikram 		rval = nvlist_add_int32(line_nvl, RIO_STORE_MAGIC_STR,
287*4845Svikram 			RIO_STORE_MAGIC);
288*4845Svikram 		if (rval != 0) {
289*4845Svikram 			goto error;
290*4845Svikram 		}
291*4845Svikram 
292*4845Svikram 		/* don't save the bypass flag */
293*4845Svikram 		flags = RIO_STORE_F_RETIRED;
294*4845Svikram 		rval = nvlist_add_int32(line_nvl, RIO_STORE_FLAGS_STR,
295*4845Svikram 			flags);
296*4845Svikram 		if (rval != 0) {
297*4845Svikram 			goto error;
298*4845Svikram 		}
299*4845Svikram 
300*4845Svikram 		rval = nvlist_add_nvlist(nvl, rsp->rst_devpath, line_nvl);
301*4845Svikram 		if (rval != 0) {
302*4845Svikram 			goto error;
303*4845Svikram 		}
304*4845Svikram 		nvlist_free(line_nvl);
305*4845Svikram 		line_nvl = NULL;
306*4845Svikram 	}
307*4845Svikram 
308*4845Svikram 	*ret_nvl = nvl;
309*4845Svikram 	STORE_DBG((CE_NOTE, "packed retire list into nvlist"));
310*4845Svikram 	return (DDI_SUCCESS);
311*4845Svikram 
312*4845Svikram error:
313*4845Svikram 	if (line_nvl)
314*4845Svikram 		nvlist_free(line_nvl);
315*4845Svikram 	ASSERT(nvl);
316*4845Svikram 	nvlist_free(nvl);
317*4845Svikram 	return (DDI_FAILURE);
318*4845Svikram }
319*4845Svikram 
320*4845Svikram int
e_ddi_retire_persist(char * devpath)321*4845Svikram e_ddi_retire_persist(char *devpath)
322*4845Svikram {
323*4845Svikram 	rio_store_t	*rsp;
324*4845Svikram 	rio_store_t	*new_rsp;
325*4845Svikram 	list_t		*listp;
326*4845Svikram 	char		*new_path;
327*4845Svikram 
328*4845Svikram 	STORE_DBG((CE_NOTE, "e_ddi_retire_persist: entered: %s", devpath));
329*4845Svikram 
330*4845Svikram 	new_rsp = kmem_zalloc(sizeof (*new_rsp), KM_SLEEP);
331*4845Svikram 	new_rsp->rst_devpath = new_path = i_ddi_strdup(devpath, KM_SLEEP);
332*4845Svikram 	new_rsp->rst_flags = RIO_STORE_F_RETIRED;
333*4845Svikram 
334*4845Svikram 	rw_enter(nvf_lock(rio_store_handle), RW_WRITER);
335*4845Svikram 
336*4845Svikram 	listp = nvf_list(rio_store_handle);
337*4845Svikram 	for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) {
338*4845Svikram 		int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
339*4845Svikram 		ASSERT(!(rsp->rst_flags & ~flag_mask));
340*4845Svikram 
341*4845Svikram 		/* already there */
342*4845Svikram 		if (strcmp(devpath, rsp->rst_devpath) == 0) {
343*4845Svikram 			/* explicit retire, clear bypass flag (if any) */
344*4845Svikram 			rsp->rst_flags &= ~RIO_STORE_F_BYPASS;
345*4845Svikram 			ASSERT(rsp->rst_flags == RIO_STORE_F_RETIRED);
346*4845Svikram 			rw_exit(nvf_lock(rio_store_handle));
347*4845Svikram 			kmem_free(new_path, strlen(new_path) + 1);
348*4845Svikram 			kmem_free(new_rsp, sizeof (*new_rsp));
349*4845Svikram 			STORE_DBG((CE_NOTE, "store: already in. Clear bypass "
350*4845Svikram 			    ": %s", devpath));
351*4845Svikram 			return (0);
352*4845Svikram 		}
353*4845Svikram 
354*4845Svikram 	}
355*4845Svikram 
356*4845Svikram 	ASSERT(rsp == NULL);
357*4845Svikram 	list_insert_tail(listp, new_rsp);
358*4845Svikram 
359*4845Svikram 	nvf_mark_dirty(rio_store_handle);
360*4845Svikram 
361*4845Svikram 	rw_exit(nvf_lock(rio_store_handle));
362*4845Svikram 
363*4845Svikram 	nvf_wake_daemon();
364*4845Svikram 
365*4845Svikram 	STORE_DBG((CE_NOTE, "store: New, added to list, dirty: %s", devpath));
366*4845Svikram 
367*4845Svikram 	return (0);
368*4845Svikram }
369*4845Svikram 
370*4845Svikram int
e_ddi_retire_unpersist(char * devpath)371*4845Svikram e_ddi_retire_unpersist(char *devpath)
372*4845Svikram {
373*4845Svikram 	rio_store_t	*rsp;
374*4845Svikram 	rio_store_t	*next;
375*4845Svikram 	list_t		*listp;
376*4845Svikram 	int		is_dirty = 0;
377*4845Svikram 
378*4845Svikram 	STORE_DBG((CE_NOTE, "e_ddi_retire_unpersist: entered: %s", devpath));
379*4845Svikram 
380*4845Svikram 	rw_enter(nvf_lock(rio_store_handle), RW_WRITER);
381*4845Svikram 
382*4845Svikram 	listp = nvf_list(rio_store_handle);
383*4845Svikram 	for (rsp = list_head(listp); rsp; rsp = next) {
384*4845Svikram 		next = list_next(listp, rsp);
385*4845Svikram 		if (strcmp(devpath, rsp->rst_devpath) != 0)
386*4845Svikram 			continue;
387*4845Svikram 
388*4845Svikram 		list_remove(listp, rsp);
389*4845Svikram 		rio_store_free(rsp);
390*4845Svikram 
391*4845Svikram 		STORE_DBG((CE_NOTE, "store: found in list. Freed: %s",
392*4845Svikram 		    devpath));
393*4845Svikram 
394*4845Svikram 		nvf_mark_dirty(rio_store_handle);
395*4845Svikram 		is_dirty = 1;
396*4845Svikram 	}
397*4845Svikram 
398*4845Svikram 	rw_exit(nvf_lock(rio_store_handle));
399*4845Svikram 
400*4845Svikram 	if (is_dirty)
401*4845Svikram 		nvf_wake_daemon();
402*4845Svikram 
403*4845Svikram 	return (is_dirty);
404*4845Svikram }
405*4845Svikram 
406*4845Svikram int
e_ddi_device_retired(char * devpath)407*4845Svikram e_ddi_device_retired(char *devpath)
408*4845Svikram {
409*4845Svikram 	list_t		*listp;
410*4845Svikram 	rio_store_t	*rsp;
411*4845Svikram 	size_t		len;
412*4845Svikram 	int		retired;
413*4845Svikram 
414*4845Svikram 	retired = 0;
415*4845Svikram 
416*4845Svikram 	rw_enter(nvf_lock(rio_store_handle), RW_READER);
417*4845Svikram 
418*4845Svikram 	listp = nvf_list(rio_store_handle);
419*4845Svikram 	for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) {
420*4845Svikram 		int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS;
421*4845Svikram 		ASSERT(!(rsp->rst_flags & ~flag_mask));
422*4845Svikram 
423*4845Svikram 		/*
424*4845Svikram 		 * If the "bypass" flag is set, then the device
425*4845Svikram 		 * is *not* retired for the current boot of the
426*4845Svikram 		 * system. It indicates that the retire store
427*4845Svikram 		 * was read but the devices in the retire store
428*4845Svikram 		 * were not retired i.e. effectively the store
429*4845Svikram 		 * was bypassed. For why we bother to even read
430*4845Svikram 		 * the store when we bypass it, see the comments
431*4845Svikram 		 * for the tunable ddi_retire_store_bypass.
432*4845Svikram 		 */
433*4845Svikram 		if (rsp->rst_flags & RIO_STORE_F_BYPASS) {
434*4845Svikram 			STORE_TRC((CE_NOTE, "store: found & bypassed: %s",
435*4845Svikram 			    rsp->rst_devpath));
436*4845Svikram 			continue;
437*4845Svikram 		}
438*4845Svikram 
439*4845Svikram 		/*
440*4845Svikram 		 * device is retired, if it or a parent exists
441*4845Svikram 		 * in the in-core list
442*4845Svikram 		 */
443*4845Svikram 		len = strlen(rsp->rst_devpath);
444*4845Svikram 		if (strncmp(devpath, rsp->rst_devpath, len) != 0)
445*4845Svikram 			continue;
446*4845Svikram 		if (devpath[len] == '\0' || devpath[len] == '/') {
447*4845Svikram 			/* exact match or a child */
448*4845Svikram 			retired = 1;
449*4845Svikram 			STORE_TRC((CE_NOTE, "store: found & !bypassed: %s",
450*4845Svikram 			    devpath));
451*4845Svikram 			break;
452*4845Svikram 		}
453*4845Svikram 	}
454*4845Svikram 	rw_exit(nvf_lock(rio_store_handle));
455*4845Svikram 
456*4845Svikram 	return (retired);
457*4845Svikram }
458