xref: /titanic_41/usr/src/cmd/rcm_daemon/common/svm_rcm.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <errno.h>
34 #include <meta.h>
35 #include <sys/lvm/mdio.h>
36 #include <sys/lvm/md_sp.h>
37 #include <sdssc.h>
38 
39 #include "rcm_module.h"
40 
41 /*
42  * This module is the RCM Module for SVM. The policy adopted by this module
43  * is to block offline requests for any SVM resource that is in use. A
44  * resource is considered to be in use if it contains a metadb or if it is
45  * a non-errored component of a metadevice that is open.
46  *
47  * The module uses the library libmeta to access the current state of the
48  * metadevices. On entry, and when svm_register() is called, the module
49  * builds a cache of all of the SVM resources and their dependencies. Each
50  * metadevice has an entry of type deventry_t which is accessed by a hash
51  * function. When the cache is built each SVM resource is registered with
52  * the RCM framework.  The check_device code path uses meta_invalidate_name to
53  * ensure that the caching in libmeta will not conflict with the cache
54  * we build within this code.
55  *
56  * When an RCM operation occurs that affects a registered SVM resource, the RCM
57  * framework will call the appropriate routine in this module. The cache
58  * entry will be found and if the resource has dependants, a callback will
59  * be made into the RCM framework to pass the request on to the dependants,
60  * which may themselves by SVM resources.
61  *
62  * Locking:
63  *      The cache is protected by a mutex
64  */
65 
66 /*
67  * Private constants
68  */
69 
70 /*
71  * Generic Messages
72  */
73 #define	MSG_UNRECOGNIZED	gettext("SVM: \"%s\" is not a SVM resource")
74 #define	MSG_NODEPS		gettext("SVM: can't find dependents")
75 #define	MSG_OPENERR		gettext("SVM: can't open \"%s\"")
76 #define	MSG_CACHEFAIL		gettext("SVM: can't malloc cache")
77 
78 #define	ERR_UNRECOGNIZED	gettext("unrecognized SVM resource")
79 #define	ERR_NODEPS		gettext("can't find SVM resource dependents")
80 
81 /*
82  * Macros to produce a quoted string containing the value of a preprocessor
83  * macro. For example, if SIZE is defined to be 256, VAL2STR(SIZE) is "256".
84  * This is used to construct format strings for scanf-family functions below.
85  */
86 #define	QUOTE(x)	#x
87 #define	VAL2STR(x)	QUOTE(x)
88 
89 typedef enum {
90     SVM_SLICE = 0,
91     SVM_STRIPE,
92     SVM_CONCAT,
93     SVM_MIRROR,
94     SVM_RAID,
95     SVM_TRANS,
96     SVM_SOFTPART,
97     SVM_HS
98 } svm_type_t;
99 
100 /* Hash table parameters */
101 #define	HASH_DEFAULT	251
102 
103 /* Hot spare pool users */
104 typedef struct hspuser {
105 	struct hspuser  *next;		/* next user */
106 	char		*hspusername;	/* name */
107 	dev_t		hspuserkey;	/* key */
108 } hspuser_t;
109 
110 /* Hot spare pool entry */
111 typedef struct hspentry {
112 	struct hspentry *link;		/* link through all hsp entries */
113 	struct hspentry *next;		/* next hsp entry for a slice */
114 	char		*hspname;	/* name */
115 	hspuser_t	*hspuser;	/* first hsp user */
116 } hspentry_t;
117 
118 /* Hash table entry */
119 typedef struct deventry {
120 	struct deventry		*next;		/* next entry with same hash */
121 	svm_type_t		devtype;	/* device type */
122 	dev_t			devkey;		/* key */
123 	char			*devname;	/* name */
124 	struct deventry		*dependent;	/* 1st dependent */
125 	struct deventry		*next_dep;	/* next dependent */
126 	struct deventry		*antecedent;	/* antecedent */
127 	hspentry_t		*hsp_list;	/* list of hot spare pools */
128 	int			flags;		/* flags */
129 } deventry_t;
130 
131 /* flag values */
132 #define	 REMOVED	0x1
133 #define	 IN_HSP		0x2
134 #define	 TRANS_LOG	0x4
135 #define	 CONT_SOFTPART	0x8
136 #define	 CONT_METADB	0x10
137 
138 /*
139  * Device redundancy flags. If the device can be removed from the
140  * metadevice configuration then it is considered a redundant device,
141  * otherwise not.
142  */
143 #define	NOTINDEVICE	-1
144 #define	NOTREDUNDANT	0
145 #define	REDUNDANT	1
146 
147 /* Cache */
148 typedef struct cache {
149 	deventry_t	**hashline;	/* hash table */
150 	int32_t		size;		/* sizer of hash table */
151 	uint32_t	registered;	/* cache regsitered */
152 } cache_t;
153 
154 /*
155  * Forward declarations of private functions
156  */
157 
158 static int svm_register(rcm_handle_t *hd);
159 static int svm_unregister(rcm_handle_t *hd);
160 static deventry_t *cache_dependent(cache_t *cache, char *devname, int devflags,
161     deventry_t *dependents);
162 static deventry_t *cache_device(cache_t *cache, char *devname,
163     svm_type_t devtype, md_dev64_t devkey, int devflags);
164 static hspentry_t *find_hsp(char *hspname);
165 static hspuser_t *add_hsp_user(char *hspname, deventry_t *deventry);
166 static hspentry_t *add_hsp(char *hspname, deventry_t *deventry);
167 static void free_names(mdnamelist_t *nlp);
168 static int cache_all_devices(cache_t *cache);
169 static int cache_hsp(cache_t *cache, mdhspnamelist_t *nlp, md_hsp_t *hsp);
170 static int cache_trans(cache_t *cache, mdnamelist_t *nlp, md_trans_t *trans);
171 static int cache_mirror(cache_t *cache, mdnamelist_t *nlp,
172     md_mirror_t *mirror);
173 static int cache_raid(cache_t *cache, mdnamelist_t *nlp, md_raid_t *raid);
174 static int cache_stripe(cache_t *cache, mdnamelist_t *nlp,
175     md_stripe_t *stripe);
176 static int cache_sp(cache_t *cache, mdnamelist_t *nlp, md_sp_t *soft_part);
177 static int cache_all_devices_in_set(cache_t *cache, mdsetname_t *sp);
178 static cache_t  *create_cache();
179 static deventry_t *create_deventry(char *devname, svm_type_t devtype,
180     md_dev64_t devkey, int devflags);
181 static void cache_remove(cache_t *cache, deventry_t *deventry);
182 static deventry_t *cache_lookup(cache_t *cache, char *devname);
183 static void cache_sync(rcm_handle_t *hd, cache_t **cachep);
184 static char *cache_walk(cache_t *cache, uint32_t *i, deventry_t **hashline);
185 static void free_cache(cache_t **cache);
186 static void free_deventry(deventry_t **deventry);
187 static uint32_t hash(uint32_t h, char *s);
188 static void register_device(rcm_handle_t *hd, char *devname);
189 static int add_dep(int *ndeps, char ***depsp, deventry_t *deventry);
190 static int get_dependents(deventry_t *deventry, char *** dependentsp);
191 char *add_to_usage(char ** usagep, char *string);
192 char *add_to_usage_fmt(char **usagep, char *fmt, char *string);
193 static int is_open(dev_t devkey);
194 static int svm_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
195     char **errorp, rcm_info_t **infop);
196 static int svm_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
197     char **errorp, rcm_info_t **infop);
198 static int svm_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
199     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **infop);
200 static int svm_suspend(rcm_handle_t *hd, char *rsrc, id_t id,
201     timespec_t *interval, uint_t flags, char **errorp,
202     rcm_info_t **infop);
203 static int svm_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
204     char **errorp, rcm_info_t **infop);
205 static int svm_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
206     char **errorp, rcm_info_t **infop);
207 static int check_device(deventry_t *deventry);
208 static int check_mirror(mdsetname_t *sp, mdname_t *np, md_error_t *ep);
209 
210 /*
211  * Module-Private data
212  */
213 static struct rcm_mod_ops svm_ops =
214 {
215 	RCM_MOD_OPS_VERSION,
216 	svm_register,
217 	svm_unregister,
218 	svm_get_info,
219 	svm_suspend,
220 	svm_resume,
221 	svm_offline,
222 	svm_online,
223 	svm_remove,
224 	NULL,
225 	NULL,
226 	NULL
227 };
228 
229 static cache_t *svm_cache = NULL;
230 static mutex_t svm_cache_lock;
231 static hspentry_t *hsp_head = NULL;
232 
233 /*
234  * Module Interface Routines
235  */
236 
237 /*
238  *      rcm_mod_init()
239  *
240  *      Create a cache, and return the ops structure.
241  *      Input: None
242  *      Return: rcm_mod_ops structure
243  */
244 struct rcm_mod_ops *
245 rcm_mod_init()
246 {
247 	/* initialize the lock mutex */
248 	if (mutex_init(&svm_cache_lock, USYNC_THREAD, NULL)) {
249 		rcm_log_message(RCM_ERROR,
250 		    gettext("SVM: can't init mutex"));
251 		return (NULL);
252 	}
253 
254 	/* need to initialize the cluster library to avoid seg faults */
255 	if (sdssc_bind_library() == SDSSC_ERROR) {
256 		rcm_log_message(RCM_ERROR,
257 			gettext("SVM: Interface error with libsds_sc.so,"
258 			    " aborting."));
259 		return (NULL);
260 	}
261 
262 	/* Create a cache */
263 	if ((svm_cache = create_cache()) == NULL) {
264 		rcm_log_message(RCM_ERROR,
265 			gettext("SVM: module can't function, aborting."));
266 		return (NULL);
267 	}
268 
269 	/* Return the ops vectors */
270 	return (&svm_ops);
271 }
272 
273 /*
274  *	rcm_mod_info()
275  *
276  *	Return a string describing this module.
277  *	Input: None
278  *	Return: String
279  *	Locking: None
280  */
281 const char *
282 rcm_mod_info()
283 {
284 	return (gettext("Solaris Volume Manager module %I%"));
285 }
286 
287 /*
288  *	rcm_mod_fini()
289  *
290  *	Destroy the cache and mutex
291  *	Input: None
292  *	Return: RCM_SUCCESS
293  *	Locking: None
294  */
295 int
296 rcm_mod_fini()
297 {
298 	(void) mutex_lock(&svm_cache_lock);
299 	if (svm_cache) {
300 		free_cache(&svm_cache);
301 	}
302 	(void) mutex_unlock(&svm_cache_lock);
303 	(void) mutex_destroy(&svm_cache_lock);
304 	return (RCM_SUCCESS);
305 }
306 
307 /*
308  *	svm_register()
309  *
310  *	Make sure the cache is properly sync'ed, and its registrations are in
311  *	order.
312  *
313  *	Input:
314  *		rcm_handle_t	*hd
315  *	Return:
316  *		RCM_SUCCESS
317  *      Locking: the cache is locked throughout the execution of this routine
318  *      because it reads and possibly modifies cache links continuously.
319  */
320 static int
321 svm_register(rcm_handle_t *hd)
322 {
323 	uint32_t i = 0;
324 	deventry_t *l = NULL;
325 	char    *devicename;
326 
327 
328 	rcm_log_message(RCM_TRACE1, "SVM: register\n");
329 	/* Guard against bad arguments */
330 	assert(hd != NULL);
331 
332 	/* Lock the cache */
333 	(void) mutex_lock(&svm_cache_lock);
334 
335 	/* If the cache has already been registered, then just sync it.  */
336 	if (svm_cache && svm_cache->registered) {
337 		cache_sync(hd, &svm_cache);
338 		(void) mutex_unlock(&svm_cache_lock);
339 		return (RCM_SUCCESS);
340 	}
341 
342 	/* If not, register the whole cache and mark it as registered. */
343 	while ((devicename = cache_walk(svm_cache, &i, &l)) != NULL) {
344 			register_device(hd, devicename);
345 	}
346 	svm_cache->registered = 1;
347 
348 	/* Unlock the cache */
349 	(void) mutex_unlock(&svm_cache_lock);
350 
351 	return (RCM_SUCCESS);
352 }
353 
354 /*
355  *	svm_unregister()
356  *
357  *	Manually walk through the cache, unregistering all the special files and
358  *	mount points.
359  *
360  *	Input:
361  *		rcm_handle_t	*hd
362  *	Return:
363  *		RCM_SUCCESS
364  *      Locking: the cache is locked throughout the execution of this routine
365  *      because it reads and modifies cache links continuously.
366  */
367 static int
368 svm_unregister(rcm_handle_t *hd)
369 {
370 	deventry_t *l = NULL;
371 	uint32_t i = 0;
372 	char	    *devicename;
373 
374 	rcm_log_message(RCM_TRACE1, "SVM: unregister\n");
375 	/* Guard against bad arguments */
376 	assert(hd != NULL);
377 
378 	/* Walk the cache, unregistering everything */
379 	(void) mutex_lock(&svm_cache_lock);
380 	if (svm_cache != NULL) {
381 		while ((devicename = cache_walk(svm_cache, &i, &l)) != NULL) {
382 			(void) rcm_unregister_interest(hd, devicename, 0);
383 		}
384 		svm_cache->registered = 0;
385 	}
386 	(void) mutex_unlock(&svm_cache_lock);
387 	return (RCM_SUCCESS);
388 }
389 
390 /*
391  *      svm_offline()
392  *
393  *      Determine dependents of the resource being offlined, and offline
394  *      them all.
395  *
396  *      Input:
397  *		rcm_handle_t	*hd		handle
398  *		char*		*rsrc		resource name
399  *		id_t		id		0
400  *		char		**errorp	ptr to error message
401  *		rcm_info_t	**infop		ptr to info string
402  *      Output:
403  *		char		**errorp	pass back error message
404  *      Return:
405  *		int		RCM_SUCCESS or RCM_FAILURE
406  *      Locking: the cache is locked for most of this routine, except while
407  *      processing dependents.
408  */
409 /*ARGSUSED*/
410 static int
411 svm_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
412     char **errorp, rcm_info_t **infop)
413 {
414 	int		rv = RCM_SUCCESS;
415 	int		ret;
416 	char		**dependents;
417 	deventry_t	*deventry;
418 	hspentry_t	*hspentry;
419 	hspuser_t	*hspuser;
420 
421 	/* Guard against bad arguments */
422 	assert(hd != NULL);
423 	assert(rsrc != NULL);
424 	assert(id == (id_t)0);
425 	assert(errorp != NULL);
426 
427 	/* Trace */
428 	rcm_log_message(RCM_TRACE1, "SVM: offline(%s), flags(%d)\n",
429 	    rsrc, flags);
430 
431 	/* Lock the cache */
432 	(void) mutex_lock(&svm_cache_lock);
433 
434 	/* Lookup the resource in the cache. */
435 	if ((deventry = cache_lookup(svm_cache, rsrc)) == NULL) {
436 		rcm_log_message(RCM_ERROR, MSG_UNRECOGNIZED);
437 		*errorp = strdup(ERR_UNRECOGNIZED);
438 		(void) mutex_unlock(&svm_cache_lock);
439 		rv = RCM_FAILURE;
440 		rcm_log_message(RCM_TRACE1, "SVM: svm_offline(%s) exit %d\n",
441 		    rsrc, rv);
442 		return (rv);
443 	}
444 	/* If it is a TRANS device, do not allow the offline */
445 	if (deventry->devtype == SVM_TRANS) {
446 		rv = RCM_FAILURE;
447 		(void) mutex_unlock(&svm_cache_lock);
448 		goto exit;
449 	}
450 
451 	if (deventry->flags&IN_HSP) {
452 		/*
453 		 * If this is in a hot spare pool, check to see
454 		 * if any of the hot spare pool users are open
455 		 */
456 		hspentry = deventry->hsp_list;
457 		while (hspentry) {
458 			hspuser = hspentry->hspuser;
459 			while (hspuser) {
460 				/* Check if open */
461 				if (is_open(hspuser->hspuserkey)) {
462 					rv = RCM_FAILURE;
463 					(void) mutex_unlock(&svm_cache_lock);
464 					goto exit;
465 				}
466 				hspuser = hspuser->next;
467 			}
468 			hspentry = hspentry->next;
469 		}
470 	}
471 
472 	/* Fail if the device contains a metadb replica */
473 	if (deventry->flags&CONT_METADB) {
474 		/*
475 		 * The user should delete the replica before continuing,
476 		 * so force the error.
477 		 */
478 		rcm_log_message(RCM_TRACE1, "SVM: %s has a replica\n",
479 		    deventry->devname);
480 		rv = RCM_FAILURE;
481 		(void) mutex_unlock(&svm_cache_lock);
482 		goto exit;
483 	}
484 
485 	/* Get dependents */
486 	if (get_dependents(deventry, &dependents) != 0) {
487 		rcm_log_message(RCM_ERROR, MSG_NODEPS);
488 		rv = RCM_FAILURE;
489 		(void) mutex_unlock(&svm_cache_lock);
490 		goto exit;
491 	}
492 
493 	if (dependents) {
494 		/* Check if the device is broken (needs maintanence). */
495 		if (check_device(deventry) == REDUNDANT) {
496 			/*
497 			 * The device is broken, the offline request should
498 			 * succeed, so ignore any of the dependents.
499 			 */
500 			rcm_log_message(RCM_TRACE1,
501 			    "SVM: ignoring dependents\n");
502 			(void) mutex_unlock(&svm_cache_lock);
503 			free(dependents);
504 			goto exit;
505 		}
506 		(void) mutex_unlock(&svm_cache_lock);
507 		ret = rcm_request_offline_list(hd, dependents, flags, infop);
508 		if (ret != RCM_SUCCESS) {
509 			rv = ret;
510 		}
511 		free(dependents);
512 	} else {
513 		/* If no dependents, check if the metadevice is open */
514 		if ((deventry->devkey) && (is_open(deventry->devkey))) {
515 			rv = RCM_FAILURE;
516 			(void) mutex_unlock(&svm_cache_lock);
517 			goto exit;
518 		}
519 		(void) mutex_unlock(&svm_cache_lock);
520 	}
521 exit:
522 	rcm_log_message(RCM_TRACE1, "SVM: svm_offline(%s) exit %d\n", rsrc, rv);
523 	if (rv != RCM_SUCCESS)
524 		*errorp = strdup(gettext("unable to offline"));
525 	return (rv);
526 }
527 
528 /*
529  *      svm_online()
530  *
531  *      Just pass the online notification on to the dependents of this resource
532  *
533  *      Input:
534  *		rcm_handle_t	*hd		handle
535  *		char*		*rsrc		resource name
536  *		id_t		id		0
537  *		char		**errorp	ptr to error message
538  *		rcm_info_t	**infop		ptr to info string
539  *      Output:
540  *		char		**errorp	pass back error message
541  *      Return:
542  *		int		RCM_SUCCESS or RCM_FAILURE
543  *      Locking: the cache is locked for most of this routine, except while
544  *      processing dependents.
545  */
546 /*ARGSUSED*/
547 static int
548 svm_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, char **errorp,
549     rcm_info_t **infop)
550 {
551 	int		rv = RCM_SUCCESS;
552 	char		**dependents;
553 	deventry_t	*deventry;
554 
555 	/* Guard against bad arguments */
556 	assert(hd != NULL);
557 	assert(rsrc != NULL);
558 	assert(id == (id_t)0);
559 
560 	/* Trace */
561 	rcm_log_message(RCM_TRACE1, "SVM: online(%s)\n", rsrc);
562 
563 	/* Lookup this resource in the cache (cache gets locked) */
564 	(void) mutex_lock(&svm_cache_lock);
565 	deventry = cache_lookup(svm_cache, rsrc);
566 	if (deventry == NULL) {
567 		(void) mutex_unlock(&svm_cache_lock);
568 		rcm_log_message(RCM_ERROR, MSG_UNRECOGNIZED, rsrc);
569 		*errorp = strdup(ERR_UNRECOGNIZED);
570 		return (RCM_FAILURE);
571 	}
572 
573 	/* Get dependents */
574 	if (get_dependents(deventry, &dependents) != 0) {
575 		(void) mutex_unlock(&svm_cache_lock);
576 		rcm_log_message(RCM_ERROR, MSG_NODEPS);
577 		*errorp = strdup(ERR_NODEPS);
578 		return (RCM_FAILURE);
579 	}
580 	(void) mutex_unlock(&svm_cache_lock);
581 
582 	if (dependents) {
583 		rv = rcm_notify_online_list(hd, dependents, flags, infop);
584 		if (rv != RCM_SUCCESS)
585 			*errorp = strdup(gettext("unable to online"));
586 		free(dependents);
587 	}
588 
589 	return (rv);
590 }
591 
592 /*
593  *      svm_get_info()
594  *
595  *      Gather usage information for this resource.
596  *
597  *      Input:
598  *		rcm_handle_t	*hd		handle
599  *		char*		*rsrc		resource name
600  *		id_t		id		0
601  *		char		**errorp	ptr to error message
602  *		nvlist_t	*props		Not used
603  *		rcm_info_t	**infop		ptr to info string
604  *      Output:
605  *		char		**infop		pass back info string
606  *      Return:
607  *		int		RCM_SUCCESS or RCM_FAILURE
608  *      Locking: the cache is locked  throughout the whole function
609  */
610 /*ARGSUSED*/
611 static int
612 svm_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, char **usagep,
613     char **errorp, nvlist_t *props, rcm_info_t **infop)
614 {
615 	int 		rv = RCM_SUCCESS;
616 	deventry_t	*deventry;
617 	deventry_t	*dependent;
618 	hspentry_t	*hspentry;
619 	char		**dependents;
620 
621 	/* Guard against bad arguments */
622 	assert(hd != NULL);
623 	assert(rsrc != NULL);
624 	assert(id == (id_t)0);
625 	assert(usagep != NULL);
626 	assert(errorp != NULL);
627 
628 	/* Trace */
629 	rcm_log_message(RCM_TRACE1, "SVM: get_info(%s)\n", rsrc);
630 
631 	/* Lookup this resource in the cache (cache gets locked) */
632 	(void) mutex_lock(&svm_cache_lock);
633 	deventry = cache_lookup(svm_cache, rsrc);
634 	if (deventry == NULL) {
635 		(void) mutex_unlock(&svm_cache_lock);
636 		rcm_log_message(RCM_ERROR, MSG_UNRECOGNIZED, rsrc);
637 		*errorp = strdup(ERR_UNRECOGNIZED);
638 		return (RCM_FAILURE);
639 	}
640 
641 	*usagep = NULL; /* Initialise usage string */
642 	if (deventry->flags&CONT_METADB) {
643 		*usagep = add_to_usage(usagep, gettext("contains metadb(s)"));
644 	}
645 	if (deventry->flags&CONT_SOFTPART) {
646 		*usagep = add_to_usage(usagep,
647 		    gettext("contains soft partition(s)"));
648 	}
649 	if (deventry->devtype == SVM_SOFTPART) {
650 		*usagep = add_to_usage_fmt(usagep,
651 		    gettext("soft partition based on \"%s\""),
652 		    deventry->antecedent->devname);
653 	}
654 
655 	if (deventry->flags&IN_HSP) {
656 		int	hspflag = 0;
657 		hspentry = deventry->hsp_list;
658 		while (hspentry) {
659 			if (hspflag == 0) {
660 				*usagep = add_to_usage(usagep,
661 				    gettext("member of hot spare pool"));
662 				hspflag = 1;
663 			}
664 			*usagep = add_to_usage_fmt(usagep, "\"%s\"",
665 			    hspentry->hspname);
666 			hspentry = hspentry->next;
667 		}
668 	} else {
669 		dependent = deventry->dependent;
670 		while (dependent) {
671 			/* Resource has dependents */
672 			switch (dependent->devtype) {
673 			case SVM_STRIPE:
674 				*usagep = add_to_usage_fmt(usagep,
675 				    gettext("component of stripe \"%s\""),
676 				    dependent->devname);
677 				break;
678 			case SVM_CONCAT:
679 				*usagep = add_to_usage_fmt(usagep,
680 				    gettext("component of concat \"%s\""),
681 				    dependent->devname);
682 				break;
683 			case SVM_MIRROR:
684 				*usagep = add_to_usage_fmt(usagep,
685 				    gettext("submirror of \"%s\""),
686 				    dependent->devname);
687 				break;
688 			case SVM_RAID:
689 				*usagep = add_to_usage_fmt(usagep,
690 				    gettext("component of RAID \"%s\""),
691 				    dependent->devname);
692 				break;
693 			case SVM_TRANS:
694 				if (deventry->flags&TRANS_LOG) {
695 					*usagep = add_to_usage_fmt(usagep,
696 					    gettext("trans log for \"%s\""),
697 					    dependent->devname);
698 				} else {
699 					*usagep = add_to_usage_fmt(usagep,
700 					    gettext("trans master for \"%s\""),
701 					    dependent->devname);
702 				}
703 				break;
704 			case SVM_SOFTPART:
705 				/* Contains soft parts, already processed */
706 				break;
707 			default:
708 				rcm_log_message(RCM_ERROR,
709 				    gettext("Unknown type %d\n"),
710 				    dependent->devtype);
711 			}
712 			dependent = dependent->next_dep;
713 		}
714 	}
715 
716 	/* Get dependents  and recurse if necessary */
717 	if (get_dependents(deventry, &dependents) != 0) {
718 		(void) mutex_unlock(&svm_cache_lock);
719 		rcm_log_message(RCM_ERROR, MSG_NODEPS);
720 		*errorp = strdup(ERR_NODEPS);
721 		return (RCM_FAILURE);
722 	}
723 	(void) mutex_unlock(&svm_cache_lock);
724 
725 	if ((flags & RCM_INCLUDE_DEPENDENT) && (dependents != NULL)) {
726 		rv = rcm_get_info_list(hd, dependents, flags, infop);
727 		if (rv != RCM_SUCCESS)
728 			*errorp = strdup(gettext("unable to get info"));
729 	}
730 	free(dependents);
731 
732 	if (*usagep != NULL)
733 		rcm_log_message(RCM_TRACE1, "SVM: usage = %s\n", *usagep);
734 	return (rv);
735 }
736 
737 /*
738  *      svm_suspend()
739  *
740  *      Notify all dependents that the resource is being suspended.
741  *      Since no real operation is involved, QUERY or not doesn't matter.
742  *
743  *      Input:
744  *		rcm_handle_t	*hd		handle
745  *		char*		*rsrc		resource name
746  *		id_t		id		0
747  *		char		**errorp	ptr to error message
748  *		rcm_info_t	**infop		ptr to info string
749  *      Output:
750  *		char		**errorp	pass back error message
751  *      Return:
752  *		int		RCM_SUCCESS or RCM_FAILURE
753  *      Locking: the cache is locked for most of this routine, except while
754  *      processing dependents.
755  */
756 static int
757 svm_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
758     uint_t flags, char **errorp, rcm_info_t **infop)
759 {
760 	int		rv = RCM_SUCCESS;
761 	deventry_t	*deventry;
762 	char		**dependents;
763 
764 	/* Guard against bad arguments */
765 	assert(hd != NULL);
766 	assert(rsrc != NULL);
767 	assert(id == (id_t)0);
768 	assert(interval != NULL);
769 	assert(errorp != NULL);
770 
771 	/* Trace */
772 	rcm_log_message(RCM_TRACE1, "SVM: suspend(%s)\n", rsrc);
773 
774 	/* Lock the cache and extract information about this resource.  */
775 	(void) mutex_lock(&svm_cache_lock);
776 	if ((deventry = cache_lookup(svm_cache, rsrc)) == NULL) {
777 		(void) mutex_unlock(&svm_cache_lock);
778 		rcm_log_message(RCM_ERROR, MSG_UNRECOGNIZED, rsrc);
779 		*errorp = strdup(ERR_UNRECOGNIZED);
780 		return (RCM_SUCCESS);
781 	}
782 
783 	/* Get dependents */
784 	if (get_dependents(deventry, &dependents) != 0) {
785 		(void) mutex_unlock(&svm_cache_lock);
786 		rcm_log_message(RCM_ERROR, MSG_NODEPS);
787 		*errorp = strdup(ERR_NODEPS);
788 		return (RCM_FAILURE);
789 	}
790 	(void) mutex_unlock(&svm_cache_lock);
791 
792 	if (dependents) {
793 		rv = rcm_request_suspend_list(hd, dependents, flags,
794 		    interval, infop);
795 		if (rv != RCM_SUCCESS)
796 			*errorp = strdup(gettext("unable to suspend"));
797 		free(dependents);
798 	}
799 
800 	return (rv);
801 }
802 
803 /*
804  *      svm_resume()
805  *
806  *      Notify all dependents that the resource is being resumed.
807  *
808  *      Input:
809  *		rcm_handle_t	*hd		handle
810  *		char*		*rsrc		resource name
811  *		id_t		id		0
812  *		char		**errorp	ptr to error message
813  *		rcm_info_t	**infop		ptr to info string
814  *      Output:
815  *		char		**errorp	pass back error message
816  *      Return:
817  *		int		RCM_SUCCESS or RCM_FAILURE
818  *      Locking: the cache is locked for most of this routine, except while
819  *      processing dependents.
820  *
821  */
822 static int
823 svm_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, char **errorp,
824     rcm_info_t **infop)
825 {
826 	int		rv = RCM_SUCCESS;
827 	deventry_t	*deventry;
828 	char		**dependents;
829 
830 	/* Guard against bad arguments */
831 	assert(hd != NULL);
832 	assert(rsrc != NULL);
833 	assert(id == (id_t)0);
834 	assert(errorp != NULL);
835 
836 	/* Trace */
837 	rcm_log_message(RCM_TRACE1, "SVM: resume(%s)\n", rsrc);
838 
839 	/*
840 	 * Lock the cache just long enough to extract information about this
841 	 * resource.
842 	 */
843 	(void) mutex_lock(&svm_cache_lock);
844 	if ((deventry = cache_lookup(svm_cache, rsrc)) == NULL) {
845 		(void) mutex_unlock(&svm_cache_lock);
846 		rcm_log_message(RCM_ERROR, MSG_UNRECOGNIZED, rsrc);
847 		*errorp = strdup(ERR_UNRECOGNIZED);
848 		return (RCM_SUCCESS);
849 	}
850 
851 	/* Get dependents */
852 
853 	if (get_dependents(deventry, &dependents) != 0) {
854 		(void) mutex_unlock(&svm_cache_lock);
855 		rcm_log_message(RCM_ERROR, MSG_NODEPS);
856 		*errorp = strdup(ERR_NODEPS);
857 		return (RCM_FAILURE);
858 	}
859 
860 	(void) mutex_unlock(&svm_cache_lock);
861 	if (dependents) {
862 		rv = rcm_notify_resume_list(hd, dependents, flags, infop);
863 		if (rv != RCM_SUCCESS)
864 			*errorp = strdup(gettext("unable to resume"));
865 		free(dependents);
866 	}
867 
868 	return (rv);
869 }
870 
871 
872 /*
873  *	svm_remove()
874  *
875  *      Remove the resource from the cache and notify all dependents that
876  *      the resource has been removed.
877  *
878  *      Input:
879  *		rcm_handle_t	*hd		handle
880  *		char*		*rsrc		resource name
881  *		id_t		id		0
882  *		char		**errorp	ptr to error message
883  *		rcm_info_t	**infop		ptr to info string
884  *      Output:
885  *		char		**errorp	pass back error message
886  *      Return:
887  *		int		RCM_SUCCESS or RCM_FAILURE
888  *      Locking: the cache is locked for most of this routine, except while
889  *      processing dependents.
890  */
891 static int
892 svm_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, char **errorp,
893     rcm_info_t **infop)
894 {
895 	int		rv = RCM_SUCCESS;
896 	char		**dependents;
897 	deventry_t	*deventry;
898 
899 	/* Guard against bad arguments */
900 	assert(hd != NULL);
901 	assert(rsrc != NULL);
902 	assert(id == (id_t)0);
903 
904 	/* Trace */
905 	rcm_log_message(RCM_TRACE1, "SVM: svm_remove(%s)\n", rsrc);
906 
907 	/* Lock the cache while removing resource */
908 	(void) mutex_lock(&svm_cache_lock);
909 	if ((deventry = cache_lookup(svm_cache, rsrc)) == NULL) {
910 		(void) mutex_unlock(&svm_cache_lock);
911 		return (RCM_SUCCESS);
912 	}
913 
914 	/* Get dependents */
915 	if (get_dependents(deventry, &dependents) != 0) {
916 		(void) mutex_unlock(&svm_cache_lock);
917 		rcm_log_message(RCM_ERROR, MSG_NODEPS);
918 		deventry->flags |= REMOVED;
919 		*errorp = strdup(ERR_NODEPS);
920 		return (RCM_FAILURE);
921 	}
922 
923 	if (dependents) {
924 		(void) mutex_unlock(&svm_cache_lock);
925 		rv = rcm_notify_remove_list(hd, dependents, flags, infop);
926 		(void) mutex_lock(&svm_cache_lock);
927 		if (rv != RCM_SUCCESS)
928 			*errorp = strdup(gettext("unable to remove"));
929 		free(dependents);
930 	}
931 
932 	/* Mark entry as removed */
933 	deventry->flags |= REMOVED;
934 
935 	(void) mutex_unlock(&svm_cache_lock);
936 	rcm_log_message(RCM_TRACE1, "SVM: exit svm_remove(%s)\n", rsrc);
937 	/* Clean up and return success */
938 	return (RCM_SUCCESS);
939 }
940 
941 /*
942  * Definitions of private functions
943  *
944  */
945 
946 /*
947  *	find_hsp()
948  *
949  *	Find the hot spare entry from the linked list of all hotspare pools
950  *
951  *	Input:
952  *		char		*hspname	name of hot spare pool
953  *	Return:
954  *		hspentry_t	hot spare entry
955  */
956 static hspentry_t *
957 find_hsp(char *hspname)
958 {
959 	hspentry_t	*hspentry = hsp_head;
960 
961 	while (hspentry) {
962 		if (strcmp(hspname, hspentry->hspname) == 0)
963 			return (hspentry);
964 		hspentry = hspentry->link;
965 	}
966 	return (NULL);
967 }
968 
969 /*
970  *      add_hsp_user()
971  *
972  *      Add a hot spare pool user to the list for the hsp specfied by
973  *	hspname. The memory allocated here will be freed by free_cache()
974  *
975  *      Input:
976  *		char		*hspname	hot spare pool name
977  *		deventry_t	*deventry	specified hsp user
978  *      Return:
979  *		hspuser_t	entry in hsp user list
980  */
981 static hspuser_t *
982 add_hsp_user(char *hspname, deventry_t *deventry)
983 {
984 	hspuser_t	*newhspuser;
985 	char		*newhspusername;
986 	hspuser_t	*previous;
987 	hspentry_t	*hspentry;
988 
989 	hspentry = find_hsp(hspname);
990 	if (hspentry == NULL)
991 		return (NULL);
992 	rcm_log_message(RCM_TRACE1, "SVM: Enter add_hsp_user %s, %x, %x\n",
993 	    hspname, hspentry, hspentry->hspuser);
994 
995 	newhspuser = (hspuser_t *)malloc(sizeof (*newhspuser));
996 	if (newhspuser == NULL) {
997 		rcm_log_message(RCM_ERROR,
998 		    gettext("SVM: can't malloc hspuser"));
999 		return (NULL);
1000 	}
1001 	(void) memset((char *)newhspuser, 0, sizeof (*newhspuser));
1002 
1003 	newhspusername = strdup(deventry->devname);
1004 	if (newhspusername == NULL) {
1005 		rcm_log_message(RCM_ERROR,
1006 		    gettext("SVM: can't malloc hspusername"));
1007 		free(newhspuser);
1008 		return (NULL);
1009 	}
1010 	newhspuser->hspusername = newhspusername;
1011 	newhspuser->hspuserkey = deventry->devkey;
1012 
1013 	if ((previous = hspentry->hspuser) == NULL) {
1014 		hspentry->hspuser = newhspuser;
1015 	} else {
1016 		hspuser_t	*temp = previous->next;
1017 		previous->next = newhspuser;
1018 		newhspuser->next = temp;
1019 	}
1020 	rcm_log_message(RCM_TRACE1, "SVM: Added hsp_user %s (dev %x) to %s\n",
1021 	    newhspusername, newhspuser->hspuserkey, hspname);
1022 	return (newhspuser);
1023 }
1024 
1025 /*
1026  *      add_hsp()
1027  *
1028  *      Add a hot spare pool entry to the list for the slice, deventry.
1029  *      Also add to the linked list of all hsp pools
1030  *	The memory alllocated here will be freed by free_cache()
1031  *
1032  *      Input:
1033  *		char		*hspname	name of hsp pool entry
1034  *		deventry_t	*deventry	device entry for the slice
1035  *      Return:
1036  *		hspentry_t	end of hsp list
1037  *      Locking: None
1038  */
1039 static hspentry_t *
1040 add_hsp(char *hspname, deventry_t *deventry)
1041 {
1042 	hspentry_t	*newhspentry;
1043 	hspentry_t	*previous;
1044 	char		*newhspname;
1045 
1046 	rcm_log_message(RCM_TRACE1, "SVM: Enter add_hsp %s\n",
1047 	    hspname);
1048 	newhspentry = (hspentry_t *)malloc(sizeof (*newhspentry));
1049 	if (newhspentry == NULL) {
1050 		rcm_log_message(RCM_ERROR,
1051 		    gettext("SVM: can't malloc hspentry"));
1052 		return (NULL);
1053 	}
1054 	(void) memset((char *)newhspentry, 0, sizeof (*newhspentry));
1055 
1056 	newhspname = strdup(hspname);
1057 	if (newhspname == NULL) {
1058 		rcm_log_message(RCM_ERROR,
1059 		    gettext("SVM: can't malloc hspname"));
1060 		free(newhspentry);
1061 		return (NULL);
1062 	}
1063 	newhspentry->hspname = newhspname;
1064 
1065 	/* Add to linked list of all hotspare pools */
1066 	newhspentry->link = hsp_head;
1067 	hsp_head = newhspentry;
1068 
1069 	/* Add to list of hotspare pools containing this slice */
1070 	if ((previous = deventry->hsp_list) == NULL) {
1071 		deventry->hsp_list = newhspentry;
1072 	} else {
1073 		hspentry_t	*temp = previous->next;
1074 		previous->next = newhspentry;
1075 		newhspentry->next = temp;
1076 	}
1077 	rcm_log_message(RCM_TRACE1, "SVM: Exit add_hsp %s\n",
1078 	    hspname);
1079 	return (newhspentry);
1080 }
1081 
1082 /*
1083  *      cache_dependent()
1084  *
1085  *      Add a dependent for a deventry to the cache and return the cache entry
1086  *	If the name is not in the cache, we assume that it a SLICE. If it
1087  *	turns out to be any other type of metadevice, when it is processed
1088  *	in cache_all_devices_in_set(), cache_device() will be called to
1089  *	set the type to the actual value.
1090  *
1091  *      Input:
1092  *		cache_t		*cache		cache
1093  *		char		*devname	metadevice name
1094  *		int		devflags	metadevice flags
1095  *		deventry_t	*dependent	dependent of this metadevice
1096  *      Return:
1097  *		deventry_t	metadevice entry added to cache
1098  *      Locking: None
1099  */
1100 static deventry_t *
1101 cache_dependent(cache_t *cache, char *devname, int devflags,
1102     deventry_t *dependent)
1103 {
1104 
1105 	deventry_t	*newdeventry = NULL;
1106 	deventry_t	*hashprev = NULL;
1107 	deventry_t	*deventry = NULL;
1108 	deventry_t	*previous = NULL;
1109 	uint32_t	hash_index;
1110 	int		comp;
1111 
1112 	rcm_log_message(RCM_TRACE1, "SVM: Enter cache_dep %s, %x, %s\n",
1113 	    devname, devflags, dependent->devname);
1114 
1115 	hash_index = hash(cache->size, devname);
1116 	if (hash_index >= cache->size) {
1117 		rcm_log_message(RCM_ERROR,
1118 		    gettext("SVM: can't hash device."));
1119 		return (NULL);
1120 	}
1121 
1122 	deventry = cache->hashline[hash_index];
1123 
1124 	/* if the hash table slot is empty, then this is easy */
1125 	if (deventry == NULL) {
1126 		deventry = create_deventry(devname, SVM_SLICE, 0, devflags);
1127 		cache->hashline[hash_index] = deventry;
1128 	} else {
1129 	/* if the hash table slot isn't empty, find the immediate successor */
1130 		hashprev = NULL;
1131 		while ((comp = strcmp(deventry->devname, devname)) < 0 &&
1132 		    deventry->next != NULL) {
1133 			hashprev = deventry;
1134 			deventry = deventry->next;
1135 		}
1136 
1137 		if (comp == 0) {
1138 			/* if already in cache, just update the flags */
1139 			deventry->flags |= devflags;
1140 		} else {
1141 			/* insert the entry if it's not already there */
1142 			if ((newdeventry = create_deventry(devname,
1143 			    SVM_SLICE, 0, devflags)) == NULL) {
1144 				rcm_log_message(RCM_ERROR,
1145 				    gettext("SVM: can't create hash line."));
1146 				return (NULL);
1147 			}
1148 			if (comp > 0) {
1149 				newdeventry->next = deventry;
1150 				if (hashprev)
1151 					hashprev->next = newdeventry;
1152 				else
1153 					cache->hashline[hash_index] =
1154 					    newdeventry;
1155 			} else if (comp < 0) {
1156 				newdeventry->next = deventry->next;
1157 				deventry->next = newdeventry;
1158 			}
1159 			deventry = newdeventry;
1160 		}
1161 	}
1162 	/* complete deventry by linking the dependent to it */
1163 	dependent->antecedent = deventry;
1164 	if ((previous = deventry->dependent) != NULL) {
1165 		deventry_t *temp = previous->next_dep;
1166 		previous->next_dep = dependent;
1167 		dependent->next_dep = temp;
1168 	} else deventry->dependent = dependent;
1169 	return (deventry);
1170 
1171 }
1172 
1173 /*
1174  *      cache_device()
1175  *
1176  *      Add an entry to the cache for devname
1177  *
1178  *      Input:
1179  *		cache_t		*cache		cache
1180  *		char		*devname	metadevice named
1181  *		svm_type_t	devtype		metadevice type
1182  *		md_dev64_t	devkey		dev_t of device
1183  *		int		devflags	device flags
1184  *      Return:
1185  *		deventry_t	metadevice added to cache
1186  *      Locking: None
1187  */
1188 static deventry_t *
1189 cache_device(cache_t *cache, char *devname, svm_type_t devtype,
1190     md_dev64_t devkey, int devflags)
1191 {
1192 	deventry_t	*newdeventry = NULL;
1193 	deventry_t	*previous = NULL;
1194 	deventry_t	*deventry = NULL;
1195 	uint32_t	hash_index;
1196 	int		comp;
1197 
1198 	rcm_log_message(RCM_TRACE1, "SVM: Enter cache_device %s, %x, %lx, %x\n",
1199 	    devname, devtype, devkey, devflags);
1200 
1201 	hash_index = hash(cache->size, devname);
1202 	if (hash_index >= cache->size) {
1203 		rcm_log_message(RCM_ERROR,
1204 		    gettext("SVM: can't hash device."));
1205 		return (NULL);
1206 	}
1207 
1208 	deventry = cache->hashline[hash_index];
1209 
1210 	/* if the hash table slot is empty, then this is easy */
1211 	if (deventry == NULL) {
1212 		deventry = create_deventry(devname, devtype, devkey,
1213 		    devflags);
1214 		cache->hashline[hash_index] = deventry;
1215 	} else {
1216 	/* if the hash table slot isn't empty, find the immediate successor */
1217 		previous = NULL;
1218 		while ((comp = strcmp(deventry->devname, devname)) < 0 &&
1219 		    deventry->next != NULL) {
1220 			previous = deventry;
1221 			deventry = deventry->next;
1222 		}
1223 
1224 		if (comp == 0) {
1225 			/*
1226 			 * If entry already exists, just set the type, key
1227 			 * and flags
1228 			 */
1229 			deventry->devtype = devtype;
1230 			deventry->devkey = meta_cmpldev(devkey);
1231 			deventry->flags |= devflags;
1232 		} else {
1233 			/* insert the entry if it's not already there */
1234 			if ((newdeventry = create_deventry(devname, devtype,
1235 			    devkey, devflags)) == NULL) {
1236 				rcm_log_message(RCM_ERROR,
1237 				    gettext("SVM: can't create hash line."));
1238 			}
1239 			if (comp > 0) {
1240 				newdeventry->next = deventry;
1241 				if (previous)
1242 					previous->next = newdeventry;
1243 				else
1244 					cache->hashline[hash_index] =
1245 					    newdeventry;
1246 			} else if (comp < 0) {
1247 				newdeventry->next = deventry->next;
1248 				deventry->next = newdeventry;
1249 			}
1250 			deventry = newdeventry;
1251 		}
1252 	}
1253 	return (deventry);
1254 }
1255 /*
1256  *	free_names()
1257  *
1258  *	Free all name list entries
1259  *
1260  *	Input:
1261  *		mdnamelist_t		*np		namelist pointer
1262  *	Return: None
1263  */
1264 
1265 static void
1266 free_names(mdnamelist_t *nlp)
1267 {
1268 	mdnamelist_t *p;
1269 
1270 	for (p = nlp; p != NULL; p = p->next) {
1271 	    meta_invalidate_name(p->namep);
1272 	    p->namep = NULL;
1273 	}
1274 	metafreenamelist(nlp);
1275 }
1276 
1277 /*
1278  * cache_hsp()
1279  *
1280  *	Add an entry to the cache for each slice in the hot spare
1281  *	pool. Call add_hsp() to add the hot spare pool to the list
1282  *	of all hot spare pools.
1283  *
1284  *	Input:
1285  *		cache_t		*cache	cache
1286  *		mdnamelist_t	*nlp	pointer to hsp name
1287  *		md_hsp_t	*hsp
1288  *	Return:
1289  *		0 if successful or error code
1290  */
1291 static int
1292 cache_hsp(cache_t *cache, mdhspnamelist_t *nlp, md_hsp_t *hsp)
1293 {
1294 	int		i;
1295 	deventry_t	*deventry;
1296 	md_hs_t		*hs;
1297 
1298 	for (i = 0; i < hsp->hotspares.hotspares_len; i++) {
1299 		hs = &hsp->hotspares.hotspares_val[i];
1300 		if ((deventry = cache_device(cache, hs->hsnamep->bname,
1301 		    SVM_SLICE, hs->hsnamep->dev,
1302 		    IN_HSP)) == NULL) {
1303 			return (ENOMEM);
1304 		}
1305 		if (add_hsp(nlp->hspnamep->hspname, deventry) == NULL) {
1306 			return (ENOMEM);
1307 		}
1308 	}
1309 	return (0);
1310 }
1311 
1312 /*
1313  * cache_trans()
1314  *
1315  *	Add an entry to the cache for trans metadevice, the master
1316  *	and the log. Call cache_dependent() to link that master and
1317  *	the log to the trans metadevice.
1318  *
1319  *	Input:
1320  *		cache_t		*cache	cache
1321  *		mdnamelist_t	*nlp	pointer to trans name
1322  *		md_trans_t	*trans
1323  *	Return:
1324  *		0 if successful or error code
1325  *
1326  */
1327 static int
1328 cache_trans(cache_t *cache, mdnamelist_t *nlp, md_trans_t *trans)
1329 {
1330 	deventry_t	*antecedent;
1331 
1332 	if ((antecedent = cache_device(cache, nlp->namep->bname, SVM_TRANS,
1333 	    nlp->namep->dev, 0)) == NULL) {
1334 		return (ENOMEM);
1335 	}
1336 
1337 	if (cache_device(cache, trans->masternamep->bname, SVM_SLICE,
1338 	    trans->masternamep->dev, 0) == NULL) {
1339 		return (ENOMEM);
1340 	}
1341 
1342 	if (cache_dependent(cache, trans->masternamep->bname, 0,
1343 	    antecedent) == NULL) {
1344 		return (ENOMEM);
1345 	}
1346 
1347 	if (trans->lognamep != NULL) {
1348 		if (cache_device(cache, trans->lognamep->bname, SVM_SLICE,
1349 		    trans->lognamep->dev, TRANS_LOG) == NULL) {
1350 			return (ENOMEM);
1351 		}
1352 
1353 		if (cache_dependent(cache, trans->lognamep->bname, 0,
1354 		    antecedent) == NULL) {
1355 			return (ENOMEM);
1356 		}
1357 	}
1358 	return (0);
1359 }
1360 
1361 /*
1362  * cache_mirror()
1363  *
1364  *	Add an entry to the cache for the mirror. For each
1365  *	submirror, call cache_dependent() to add an entry to the
1366  *	cache and to link it to mirror entry.
1367  *
1368  *	Input:
1369  *		cache_t		*cache	cache
1370  *		mdnamelist_t	*nlp	pointer to mirror name
1371  *		md_mirror_t	*mirror
1372  *	Return:
1373  *		0 if successful or error code
1374  *
1375  */
1376 static int
1377 cache_mirror(cache_t *cache, mdnamelist_t *nlp, md_mirror_t *mirror)
1378 {
1379 	int i;
1380 	deventry_t	*antecedent;
1381 
1382 	if ((antecedent = cache_device(cache, nlp->namep->bname, SVM_MIRROR,
1383 	    nlp->namep->dev, 0)) == NULL) {
1384 		return (ENOMEM);
1385 	}
1386 	for (i = 0; i <  NMIRROR; i++) {
1387 		md_submirror_t	*submirror;
1388 
1389 		submirror = &mirror->submirrors[i];
1390 		if (submirror->state == SMS_UNUSED)
1391 			continue;
1392 
1393 		if (!submirror->submirnamep)
1394 			continue;
1395 
1396 		if (cache_dependent(cache, submirror->submirnamep->bname,
1397 		    0, antecedent) == NULL) {
1398 			return (ENOMEM);
1399 		}
1400 	}
1401 	return (0);
1402 }
1403 
1404 /*
1405  * cache_raid()
1406  *
1407  *	Add an entry to the cache for the RAID metadevice. For
1408  *	each component of the RAID call cache_dependent() to add
1409  *	add it to the cache and to link it to the RAID metadevice.
1410  *
1411  *	Input:
1412  *		cache_t		*cache	cache
1413  *		mdnamelist_t	*nlp	pointer to raid name
1414  *		md_raid_t	*raid	mirror
1415  *	Return:
1416  *		0 if successful or error code
1417  */
1418 static int
1419 cache_raid(cache_t *cache, mdnamelist_t *nlp, md_raid_t *raid)
1420 {
1421 	int i;
1422 	deventry_t	*antecedent;
1423 
1424 	if ((antecedent = cache_device(cache, nlp->namep->bname, SVM_RAID,
1425 	    nlp->namep->dev, 0)) == NULL) {
1426 		return (ENOMEM);
1427 	}
1428 	if (raid->hspnamep) {
1429 		if (add_hsp_user(raid->hspnamep->hspname,
1430 		    antecedent) == NULL) {
1431 			return (ENOMEM);
1432 		}
1433 	}
1434 	for (i = 0; i < raid->cols.cols_len; i++) {
1435 		if (cache_dependent(cache,
1436 		    raid->cols.cols_val[i].colnamep->bname, 0,
1437 		    antecedent) == NULL) {
1438 			return (ENOMEM);
1439 		}
1440 	}
1441 	return (0);
1442 }
1443 
1444 /*
1445  * cache_stripe()
1446  *
1447  *	Add a CONCAT or a STRIPE entry entry to the cache for the
1448  *	metadevice and call cache_dependent() to add each
1449  *	component to the cache.
1450  *
1451  *	Input:
1452  *		cache_t		*cache	cache
1453  *		mdnamelist_t	*nlp	pointer to stripe name
1454  *		md_stripe_t	*stripe
1455  *	Return:
1456  *		0 if successful or error code
1457  *
1458  */
1459 static int
1460 cache_stripe(cache_t *cache, mdnamelist_t *nlp, md_stripe_t *stripe)
1461 {
1462 	int i;
1463 	deventry_t	*antecedent;
1464 
1465 	if ((antecedent = cache_device(cache, nlp->namep->bname, SVM_CONCAT,
1466 	    nlp->namep->dev, 0)) == NULL) {
1467 		return (ENOMEM);
1468 	}
1469 
1470 	if (stripe->hspnamep) {
1471 		if (add_hsp_user(stripe->hspnamep->hspname,
1472 		    antecedent) == NULL) {
1473 			return (ENOMEM);
1474 		}
1475 	}
1476 	for (i = 0; i < stripe->rows.rows_len; i++) {
1477 		md_row_t	*rowp;
1478 		int		j;
1479 
1480 		rowp = &stripe->rows.rows_val[i];
1481 		if (stripe->rows.rows_len == 1 && rowp->comps.comps_len > 1) {
1482 			if ((void*) cache_device(cache, nlp->namep->bname,
1483 			    SVM_STRIPE, nlp->namep->dev, 0) == NULL)
1484 				return (ENOMEM);
1485 		}
1486 		for (j = 0; j < rowp->comps.comps_len; j++) {
1487 			md_comp_t	*component;
1488 
1489 			component = &rowp->comps.comps_val[j];
1490 			if (cache_dependent(cache,
1491 			    component->compnamep->bname, 0,
1492 			    antecedent) == NULL) {
1493 				return (ENOMEM);
1494 			}
1495 		}
1496 	}
1497 	return (0);
1498 }
1499 
1500 /*
1501  * cache_sp()
1502  *
1503  *	Add an entry to the cache for the softpart and also call
1504  *	cache_dependent() to set the CONT_SOFTPART flag in the
1505  *	cache entry for the metadevice that contains the softpart.
1506  *
1507  *	Input:
1508  *		cache_t		*cache	cache
1509  *		mdnamelist_t	*nlp	pointer to soft part name
1510  *		md_sp_t		*soft_part
1511  *	Return:
1512  *		0 if successful or error code
1513  *
1514  */
1515 static int
1516 cache_sp(cache_t *cache, mdnamelist_t *nlp, md_sp_t *soft_part)
1517 {
1518 	deventry_t	*antecedent;
1519 
1520 	if ((antecedent = cache_device(cache, nlp->namep->bname,
1521 	    SVM_SOFTPART, nlp->namep->dev, 0)) == NULL) {
1522 			    return (ENOMEM);
1523 	}
1524 	if (cache_dependent(cache, soft_part->compnamep->bname,
1525 	    CONT_SOFTPART, antecedent) == NULL) {
1526 		return (ENOMEM);
1527 	}
1528 	return (0);
1529 }
1530 
1531 /*
1532  *      cache_all_devices_in_set()
1533  *
1534  *      Add all of the metadevices and mddb replicas in the set to the
1535  *	cache
1536  *
1537  *      Input:
1538  *		cache_t		*cache		cache
1539  *		mdsetname_t	*sp		setname
1540  *      Return:
1541  *		0 if successful or error code
1542  */
1543 
1544 static int
1545 cache_all_devices_in_set(cache_t *cache, mdsetname_t *sp)
1546 {
1547 	md_error_t		error = mdnullerror;
1548 	md_replicalist_t	*replica_list = NULL;
1549 	md_replicalist_t	*mdbp;
1550 	mdnamelist_t		*nlp;
1551 	mdnamelist_t		*trans_list = NULL;
1552 	mdnamelist_t		*mirror_list = NULL;
1553 	mdnamelist_t		*raid_list = NULL;
1554 	mdnamelist_t		*stripe_list = NULL;
1555 	mdnamelist_t		*sp_list = NULL;
1556 	mdhspnamelist_t		*hsp_list = NULL;
1557 
1558 	rcm_log_message(RCM_TRACE1, "SVM: cache_all_devices_in_set\n");
1559 
1560 	/* Add each mddb replica to the cache */
1561 	if (metareplicalist(sp, MD_BASICNAME_OK, &replica_list, &error) < 0) {
1562 	    /* there are no metadb's; that is ok, no need to check the rest */
1563 	    mdclrerror(&error);
1564 	    return (0);
1565 	}
1566 
1567 	for (mdbp = replica_list; mdbp != NULL; mdbp = mdbp->rl_next) {
1568 		if (cache_device(cache, mdbp->rl_repp->r_namep->bname,
1569 		    SVM_SLICE, mdbp->rl_repp->r_namep->dev,
1570 		    CONT_METADB) == NULL) {
1571 			metafreereplicalist(replica_list);
1572 			return (ENOMEM);
1573 		}
1574 	}
1575 	metafreereplicalist(replica_list);
1576 
1577 	/* Process Hot Spare pools */
1578 	if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) {
1579 	    mdhspnamelist_t *nlp;
1580 
1581 		for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) {
1582 			md_hsp_t	*hsp;
1583 
1584 			hsp = meta_get_hsp(sp, nlp->hspnamep, &error);
1585 			if (hsp != NULL) {
1586 				if (cache_hsp(cache, nlp, hsp) != 0) {
1587 					metafreehspnamelist(hsp_list);
1588 					return (ENOMEM);
1589 				}
1590 			}
1591 			meta_invalidate_hsp(nlp->hspnamep);
1592 		}
1593 		metafreehspnamelist(hsp_list);
1594 	}
1595 
1596 	/* Process Trans devices */
1597 	if (meta_get_trans_names(sp, &trans_list, 0, &error) >= 0) {
1598 		for (nlp = trans_list; nlp != NULL; nlp = nlp->next) {
1599 			mdname_t	*mdn;
1600 			md_trans_t	*trans;
1601 
1602 			mdn = metaname(&sp, nlp->namep->cname, &error);
1603 			if (mdn == NULL) {
1604 				continue;
1605 			}
1606 
1607 			trans = meta_get_trans(sp, mdn, &error);
1608 
1609 			if (trans != NULL && trans->masternamep != NULL) {
1610 				if (cache_trans(cache, nlp, trans) != NULL) {
1611 					free_names(trans_list);
1612 					return (ENOMEM);
1613 				}
1614 			}
1615 		}
1616 		free_names(trans_list);
1617 	}
1618 
1619 	/* Process Mirrors */
1620 	if (meta_get_mirror_names(sp, &mirror_list, 0, &error) >= 0) {
1621 		for (nlp = mirror_list; nlp != NULL; nlp = nlp->next) {
1622 			mdname_t	*mdn;
1623 			md_mirror_t	*mirror;
1624 
1625 			mdn = metaname(&sp, nlp->namep->cname, &error);
1626 			if (mdn == NULL) {
1627 				continue;
1628 			}
1629 
1630 			mirror = meta_get_mirror(sp, mdn, &error);
1631 
1632 			if (mirror != NULL) {
1633 				if (cache_mirror(cache, nlp, mirror) != 0) {
1634 					free_names(mirror_list);
1635 					return (ENOMEM);
1636 				}
1637 			}
1638 		}
1639 		free_names(mirror_list);
1640 	}
1641 
1642 	/* Process Raid devices */
1643 	if (meta_get_raid_names(sp, &raid_list, 0, &error) >= 0) {
1644 		for (nlp = raid_list; nlp != NULL; nlp = nlp->next) {
1645 			mdname_t	*mdn;
1646 			md_raid_t	*raid;
1647 
1648 			mdn = metaname(&sp, nlp->namep->cname, &error);
1649 			if (mdn == NULL) {
1650 				continue;
1651 			}
1652 
1653 			raid = meta_get_raid(sp, mdn, &error);
1654 
1655 			if (raid != NULL) {
1656 				if (cache_raid(cache, nlp, raid) != 0) {
1657 					free_names(raid_list);
1658 					return (ENOMEM);
1659 				}
1660 			}
1661 		}
1662 		free_names(raid_list);
1663 	}
1664 
1665 	/* Process Slices */
1666 	if (meta_get_stripe_names(sp, &stripe_list, 0, &error) >= 0) {
1667 		for (nlp = stripe_list; nlp != NULL; nlp = nlp->next) {
1668 			mdname_t	*mdn;
1669 			md_stripe_t	*stripe;
1670 
1671 			mdn = metaname(&sp, nlp->namep->cname, &error);
1672 			if (mdn == NULL) {
1673 				continue;
1674 			}
1675 
1676 			stripe = meta_get_stripe(sp, mdn, &error);
1677 
1678 			if (stripe != NULL) {
1679 				if (cache_stripe(cache, nlp, stripe) != 0) {
1680 					free_names(stripe_list);
1681 					return (ENOMEM);
1682 				}
1683 			}
1684 		}
1685 		free_names(stripe_list);
1686 	}
1687 
1688 	/* Process Soft partitions */
1689 	if (meta_get_sp_names(sp, &sp_list, 0, &error) >= 0) {
1690 		for (nlp = sp_list; nlp != NULL; nlp = nlp->next) {
1691 			mdname_t	*mdn;
1692 			md_sp_t		*soft_part;
1693 
1694 			mdn = metaname(&sp, nlp->namep->cname, &error);
1695 			if (mdn == NULL) {
1696 				continue;
1697 			}
1698 
1699 			soft_part = meta_get_sp(sp, mdn, &error);
1700 
1701 			if (soft_part != NULL) {
1702 				if (cache_sp(cache, nlp, soft_part) != 0) {
1703 					free_names(sp_list);
1704 					return (ENOMEM);
1705 				}
1706 			}
1707 		}
1708 		free_names(sp_list);
1709 	}
1710 	mdclrerror(&error);
1711 	return (0);
1712 }
1713 
1714 /*
1715  *      create_all_devices()
1716  *
1717  *      Cache all devices in all sets
1718  *
1719  *      Input:
1720  *		cache_t		cache
1721  *      Return:
1722  *		0 if successful, error code if not
1723  *      Locking: None
1724  */
1725 static int
1726 cache_all_devices(cache_t *cache)
1727 {
1728 	int		max_sets;
1729 	md_error_t	error = mdnullerror;
1730 	int		i;
1731 
1732 	if ((max_sets = get_max_sets(&error)) == 0) {
1733 		return (0);
1734 	}
1735 	if (!mdisok(&error)) {
1736 		mdclrerror(&error);
1737 		return (0);
1738 	}
1739 
1740 	rcm_log_message(RCM_TRACE1,
1741 	    "SVM: cache_all_devices,max sets = %d\n", max_sets);
1742 	/* for each possible set number, see if we really have a diskset */
1743 	for (i = 0; i < max_sets; i++) {
1744 		mdsetname_t	*sp;
1745 
1746 		if ((sp = metasetnosetname(i, &error)) == NULL) {
1747 			rcm_log_message(RCM_TRACE1,
1748 			    "SVM: cache_all_devices no set: setno %d\n", i);
1749 			if (!mdisok(&error) &&
1750 			    ((error.info.errclass == MDEC_RPC) ||
1751 			    (mdiserror(&error, MDE_SMF_NO_SERVICE)))) {
1752 				/*
1753 				 * metad rpc program not available
1754 				 * - no metasets.  metad rpc not available
1755 				 * is indicated either by an RPC error or
1756 				 * the fact that the service is not
1757 				 * enabled.
1758 				 */
1759 				break;
1760 			}
1761 
1762 			continue;
1763 		}
1764 
1765 		if (cache_all_devices_in_set(cache, sp)) {
1766 			metaflushsetname(sp);
1767 			return (ENOMEM);
1768 		}
1769 		metaflushsetname(sp);
1770 	}
1771 	mdclrerror(&error);
1772 	rcm_log_message(RCM_TRACE1, "SVM: exit cache_all_devices\n");
1773 	return (0);
1774 }
1775 
1776 /*
1777  *      create_cache()
1778  *
1779  *      Create an empty cache
1780  *	If the function fails free_cache() will be called to free any
1781  *	allocated memory.
1782  *
1783  *      Input: None
1784  *      Return:
1785  *		cache_t		cache created
1786  *      Locking: None
1787  */
1788 static cache_t *
1789 create_cache()
1790 {
1791 	cache_t		*cache;
1792 	uint32_t	size;
1793 	int		ret;
1794 
1795 	size = HASH_DEFAULT;
1796 	/* try allocating storage for a new, empty cache */
1797 	if ((cache = (cache_t *)malloc(sizeof (cache_t))) == NULL) {
1798 		rcm_log_message(RCM_ERROR, MSG_CACHEFAIL);
1799 		return (NULL);
1800 	}
1801 
1802 	(void) memset((char *)cache, 0, sizeof (*cache));
1803 	cache->hashline = (deventry_t **)calloc(size, sizeof (deventry_t *));
1804 	if (cache->hashline == NULL) {
1805 		rcm_log_message(RCM_ERROR, MSG_CACHEFAIL);
1806 		free(cache);
1807 		return (NULL);
1808 	}
1809 	cache->size = size;
1810 
1811 	/* Initialise linked list of hsp entries */
1812 	hsp_head = NULL;
1813 
1814 	/* add entries to cache */
1815 	ret = cache_all_devices(cache);
1816 	if (ret != 0) {
1817 		free_cache(&cache);
1818 		return (NULL);
1819 	}
1820 
1821 	/* Mark the cache as new */
1822 	cache->registered = 0;
1823 
1824 	/* Finished - return the new cache */
1825 	return (cache);
1826 }
1827 
1828 /*
1829  *      create_deventry()
1830  *
1831  *      Create a new deventry entry for device with name devname
1832  *	The memory alllocated here will be freed by free_cache()
1833  *
1834  *      Input:
1835  *		char		*devname	device name
1836  *		svm_type_t	devtype		metadevice type
1837  *		md_dev64_t	devkey		device key
1838  *		int		devflags	device flags
1839  *      Return:
1840  *		deventry_t	New deventry
1841  *      Locking: None
1842  */
1843 static deventry_t *
1844 create_deventry(char *devname, svm_type_t devtype, md_dev64_t devkey,
1845     int devflags)
1846 {
1847 	deventry_t	*newdeventry;
1848 	char		*newdevname;
1849 
1850 	newdeventry = (deventry_t *)malloc(sizeof (*newdeventry));
1851 	if (newdeventry == NULL) {
1852 		rcm_log_message(RCM_ERROR,
1853 		    gettext("SVM: can't malloc deventrys"));
1854 		return (NULL);
1855 	}
1856 	(void) memset((char *)newdeventry, 0, sizeof (*newdeventry));
1857 
1858 	newdevname = strdup(devname);
1859 	if (newdevname == NULL) {
1860 		rcm_log_message(RCM_ERROR,
1861 		    gettext("SVM: can't malloc devname"));
1862 		free(newdeventry);
1863 		return (NULL);
1864 	}
1865 	newdeventry->devname = newdevname;
1866 	newdeventry->devtype = devtype;
1867 	newdeventry->devkey = meta_cmpldev(devkey);
1868 	newdeventry->flags = devflags;
1869 	rcm_log_message(RCM_TRACE1,
1870 	    "SVM created deventry for %s\n", newdeventry->devname);
1871 	return (newdeventry);
1872 }
1873 
1874 /*
1875  *      cache_remove()
1876  *
1877  *      Given a cache and a deventry, the deventry is
1878  *      removed from the cache's tables and memory for the deventry is
1879  *      free'ed.
1880  *
1881  *      Input:
1882  *		cache_t		*cache		cache
1883  *		deventry_t	*deventry	deventry to be removed
1884  *      Return: None
1885  *      Locking: The cache must be locked by the caller prior to calling
1886  *      this routine.
1887  */
1888 static void
1889 cache_remove(cache_t *cache, deventry_t *deventry)
1890 {
1891 	deventry_t	*olddeventry;
1892 	deventry_t	*previous;
1893 	hspentry_t	*hspentry;
1894 	hspentry_t	*oldhspentry;
1895 	hspuser_t	*hspuser;
1896 	hspuser_t	*oldhspuser;
1897 	uint32_t	hash_index;
1898 
1899 	/* sanity check */
1900 	if (cache == NULL || deventry == NULL || deventry->devname == NULL)
1901 		return;
1902 
1903 
1904 	/* If this is in the hash table, remove it from there */
1905 	hash_index = hash(cache->size, deventry->devname);
1906 	if (hash_index >= cache->size) {
1907 		rcm_log_message(RCM_ERROR,
1908 		    gettext("SVM: can't hash device."));
1909 		return;
1910 	}
1911 	olddeventry = cache->hashline[hash_index];
1912 	previous = NULL;
1913 	while (olddeventry) {
1914 		if (olddeventry->devname &&
1915 		    strcmp(olddeventry->devname, deventry->devname) == 0) {
1916 			break;
1917 		}
1918 		previous = olddeventry;
1919 		olddeventry = olddeventry->next;
1920 	}
1921 	if (olddeventry) {
1922 		if (previous)
1923 			previous->next = olddeventry->next;
1924 		else
1925 			cache->hashline[hash_index] = olddeventry->next;
1926 
1927 		if (olddeventry->flags&IN_HSP) {
1928 			/*
1929 			 * If this is in a hot spare pool, remove the list
1930 			 * of hot spare pools that it is in along with
1931 			 * all of the volumes that are users of the pool
1932 			 */
1933 			hspentry = olddeventry->hsp_list;
1934 			while (hspentry) {
1935 				oldhspentry = hspentry;
1936 				hspuser = hspentry->hspuser;
1937 				while (hspuser) {
1938 					oldhspuser = hspuser;
1939 					free(hspuser->hspusername);
1940 					hspuser = hspuser->next;
1941 					free(oldhspuser);
1942 				}
1943 				free(hspentry->hspname);
1944 				hspentry = hspentry->next;
1945 				free(oldhspentry);
1946 			}
1947 		}
1948 		free(olddeventry->devname);
1949 		free(olddeventry);
1950 	}
1951 
1952 }
1953 
1954 /*
1955  *      cache_lookup()
1956  *
1957  *      Return the deventry corresponding to devname from the cache
1958  *      Input:
1959  *		cache_t		cache		cache
1960  *		char		*devname	name to lookup in cache
1961  *      Return:
1962  *		deventry_t	deventry of name, NULL if not found
1963  *      Locking: cache lock held on entry and on exit
1964  */
1965 static deventry_t *
1966 cache_lookup(cache_t *cache, char *devname)
1967 {
1968 	int		comp;
1969 	uint32_t	hash_index;
1970 	deventry_t	*deventry;
1971 
1972 	hash_index = hash(cache->size, devname);
1973 	if (hash_index >= cache->size) {
1974 		rcm_log_message(RCM_ERROR,
1975 		    gettext("SVM: can't hash resource."));
1976 		return (NULL);
1977 	}
1978 
1979 	deventry = cache->hashline[hash_index];
1980 	while (deventry) {
1981 		comp = strcmp(deventry->devname, devname);
1982 		if (comp == 0)
1983 			return (deventry);
1984 		if (comp > 0)
1985 			return (NULL);
1986 		deventry = deventry->next;
1987 	}
1988 	return (NULL);
1989 }
1990 
1991 /*
1992  *      cache_sync()
1993  *
1994  *      Resync cache with the svm database
1995  *
1996  *      Input:
1997  *		rcm_handle_t	*hd		rcm handle
1998  *		cache_t		**cachep	pointer to cache
1999  *      Return:
2000  *		cache_t		**cachep	pointer to new cache
2001  *      Return: None
2002  *      Locking: The cache must be locked prior to entry
2003  */
2004 static void
2005 cache_sync(rcm_handle_t *hd, cache_t **cachep)
2006 {
2007 	char		*devicename;
2008 	deventry_t	*deventry;
2009 	cache_t		*new_cache;
2010 	cache_t		*old_cache = *cachep;
2011 	deventry_t	*hashline = NULL;
2012 	uint32_t	i = 0;
2013 
2014 	/* Get a new cache */
2015 	if ((new_cache = create_cache()) == NULL) {
2016 		rcm_log_message(RCM_WARNING,
2017 		    gettext("SVM: WARNING: couldn't re-cache."));
2018 		return;
2019 	}
2020 
2021 	/* For every entry in the new cache... */
2022 	while ((devicename = cache_walk(new_cache, &i, &hashline)) != NULL) {
2023 		/* Look for this entry in the old cache */
2024 		deventry = cache_lookup(old_cache, devicename);
2025 		/*
2026 		 * If no entry in old cache, register the resource. If there
2027 		 * is an entry, but it is marked as removed, register it
2028 		 * again and remove it from the old cache
2029 		 */
2030 		if (deventry == NULL) {
2031 			register_device(hd, hashline->devname);
2032 		} else {
2033 			if (deventry->flags&REMOVED)
2034 				register_device(hd, hashline->devname);
2035 			cache_remove(old_cache, deventry);
2036 		}
2037 	}
2038 
2039 	/*
2040 	 * For every device left in the old cache, just unregister if
2041 	 * it has not already been removed
2042 	 */
2043 	i = 0;
2044 	hashline = NULL;
2045 	while ((devicename = cache_walk(old_cache, &i, &hashline)) != NULL) {
2046 		if (!(hashline->flags&REMOVED)) {
2047 			(void) rcm_unregister_interest(hd, devicename, 0);
2048 		}
2049 	}
2050 
2051 	/* Swap pointers */
2052 	*cachep = new_cache;
2053 
2054 	/* Destroy old cache */
2055 	free_cache(&old_cache);
2056 
2057 	/* Mark the new cache as registered */
2058 	new_cache-> registered = 1;
2059 }
2060 
2061 /*
2062  * cache_walk()
2063  *
2064  *      Perform one step of a walk through the cache.  The i and hashline
2065  *      parameters are updated to store progress of the walk for future steps.
2066  *      They must all be initialized for the beginning of the walk
2067  *      (i = 0, line = NULL). Initialize variables to these values for these
2068  *      parameters, and then pass in the address of each of the variables
2069  *      along with the cache.  A NULL return value will be given to indicate
2070  *      when there are no more cached items to be returned.
2071  *
2072  *      Input:
2073  *		cache_t		*cache		cache
2074  *		uint32_t	*i		hash table index of prev entry
2075  *		deventry_t	**line		ptr to previous device entry
2076  *      Output:
2077  *		uint32_t	*i		updated hash table index
2078  *		deventry_t	**line		ptr to device entry
2079  *      Return:
2080  *		char*		device name (NULL for end of cache)
2081  *      Locking: The cache must be locked prior to calling this routine.
2082  */
2083 static char *
2084 cache_walk(cache_t *cache, uint32_t *i, deventry_t **line)
2085 {
2086 	uint32_t	j;
2087 
2088 	/* sanity check */
2089 	if (cache == NULL || i == NULL || line == NULL ||
2090 	    *i >= cache->size)
2091 		return (NULL);
2092 
2093 	/* if initial values were given, look for the first entry */
2094 	if (*i == 0 && *line == NULL) {
2095 		for (j = 0; j < cache->size; j++) {
2096 			if (cache->hashline[j]) {
2097 				*i = j;
2098 				*line = cache->hashline[j];
2099 				return ((*line)->devname);
2100 			}
2101 		}
2102 	} else {
2103 		/* otherwise, look for the next entry for this hash value */
2104 		if (*line && (*line)->next) {
2105 			*line = (*line)->next;
2106 			return ((*line)->devname);
2107 		} else {
2108 		/* next look further down in the hash table */
2109 			for (j = (*i) + 1; j < cache->size; j++) {
2110 				if (cache->hashline[j]) {
2111 					*i = j;
2112 					*line = cache->hashline[j];
2113 					return ((*line)->devname);
2114 				}
2115 			}
2116 		}
2117 	}
2118 
2119 	/*
2120 	 * We would have returned somewhere above if there were any more
2121 	 * entries.  So set the sentinel values and return a NULL.
2122 	 */
2123 	*i = cache->size;
2124 	*line = NULL;
2125 	return (NULL);
2126 }
2127 
2128 /*
2129  *      free_cache()
2130  *
2131  *      Given a pointer to a cache structure, this routine will free all
2132  *      of the memory allocated within the cache.
2133  *
2134  *      Input:
2135  *		cache_t		**cache		ptr to cache
2136  *      Return: None
2137  *      Locking: cache lock held on entry
2138  */
2139 static void
2140 free_cache(cache_t **cache)
2141 {
2142 	uint32_t	index;
2143 	cache_t		*realcache;
2144 
2145 	/* sanity check */
2146 	if (cache == NULL || *cache == NULL)
2147 		return;
2148 
2149 	/* de-reference the cache pointer */
2150 	realcache = *cache;
2151 
2152 	/* free the hash table */
2153 	for (index = 0; index < realcache->size; index++) {
2154 		free_deventry(&realcache->hashline[index]);
2155 	}
2156 	free(realcache->hashline);
2157 	realcache->hashline = NULL;
2158 
2159 	free(realcache);
2160 	*cache = NULL;
2161 }
2162 
2163 /*
2164  *      free_deventry()
2165  *
2166  *      This routine frees all of the memory allocated within a node of a
2167  *      deventry.
2168  *
2169  *      Input:
2170  *		deventry_t	**deventry	ptr to deventry
2171  *      Return: None
2172  *      Locking: cache lock held on entry
2173  */
2174 static void
2175 free_deventry(deventry_t **deventry)
2176 {
2177 	deventry_t	*olddeventry;
2178 	hspentry_t	*hspentry;
2179 	hspentry_t	*oldhspentry;
2180 	hspuser_t	*hspuser;
2181 	hspuser_t	*oldhspuser;
2182 
2183 	if (deventry != NULL) {
2184 		while (*deventry != NULL) {
2185 			olddeventry = (*deventry)->next;
2186 			if ((*deventry)->flags&IN_HSP) {
2187 				/*
2188 				 * If this is in a hot spare pool, remove the
2189 				 * memory allocated to hot spare pools and
2190 				 * the users of the pool
2191 				 */
2192 				hspentry = (*deventry)->hsp_list;
2193 				while (hspentry) {
2194 					oldhspentry = hspentry;
2195 					hspuser = hspentry->hspuser;
2196 					while (hspuser) {
2197 						oldhspuser = hspuser;
2198 						free(hspuser->hspusername);
2199 						hspuser = hspuser->next;
2200 						free(oldhspuser);
2201 					}
2202 					free(hspentry->hspname);
2203 					hspentry = hspentry->next;
2204 					free(oldhspentry);
2205 				}
2206 			}
2207 			free((*deventry)->devname);
2208 			free (*deventry);
2209 			*deventry = olddeventry;
2210 		}
2211 	}
2212 }
2213 
2214 /*
2215  *      hash()
2216  *
2217  *	A rotating hashing function that converts a string 's' to an index
2218  *      in a hash table of size 'h'.
2219  *
2220  *      Input:
2221  *		uint32_t	h		hash table size
2222  *		char		*s		string to be hashed
2223  *      Return:
2224  *		uint32_t	hash value
2225  *      Locking: None
2226  */
2227 static uint32_t
2228 hash(uint32_t h, char *s)
2229 {
2230 
2231 	int	len;
2232 	int	hash, i;
2233 
2234 	len = strlen(s);
2235 
2236 	for (hash = len, i = 0; i < len; ++i) {
2237 		hash = (hash<<4)^(hash>>28)^s[i];
2238 	}
2239 	return (hash % h);
2240 }
2241 
2242 /*
2243  *      register_device()
2244  *
2245  *      Register a device
2246  *
2247  *      Input:
2248  *		rcm_handle_t	*hd		rcm handle
2249  *		char		*devname	device name
2250  *      Return: None
2251  *      Locking: None
2252  */
2253 static void
2254 register_device(rcm_handle_t *hd, char *devname)
2255 {
2256 	/* Sanity check */
2257 	if (devname == NULL)
2258 		return;
2259 
2260 	rcm_log_message(RCM_TRACE1, "SVM: Registering %s(%d)\n", devname,
2261 		devname);
2262 
2263 	if (rcm_register_interest(hd, devname, 0, NULL) != RCM_SUCCESS) {
2264 		rcm_log_message(RCM_ERROR,
2265 		    gettext("SVM: failed to register \"%s\"\n"), devname);
2266 	}
2267 }
2268 
2269 /*
2270  *      add_dep()
2271  *
2272  *      Add an entry to an array of dependent names for a device. Used to
2273  *      build an array to call the rcm framework with when passing on a
2274  *      DR request.
2275  *
2276  *      Input:
2277  *		int		*ndeps		ptr to current number of deps
2278  *		char		***depsp	ptr to current dependent array
2279  *		deventry_t	*deventry	deventry of device to be added
2280  *      Output:
2281  *		int		*ndeps		ptr to updated no of deps
2282  *		char		***depsp	ptr to new dependant array
2283  *      Return:
2284  *		int		0, of ok, -1 if failed to allocate memory
2285  *      Locking: None
2286  */
2287 static int
2288 add_dep(int *ndeps, char ***depsp, deventry_t *deventry)
2289 {
2290 	char	**deps_new;
2291 
2292 	*ndeps += 1;
2293 	deps_new = realloc(*depsp, ((*ndeps) + 1) * sizeof (char  *));
2294 	if (deps_new == NULL) {
2295 		rcm_log_message(RCM_ERROR,
2296 		    gettext("SVM: cannot allocate dependent array (%s).\n"),
2297 		    strerror(errno));
2298 		return (-1);
2299 	}
2300 	deps_new[(*ndeps-1)] = deventry->devname;
2301 	deps_new[(*ndeps)] = NULL;
2302 	*depsp = deps_new;
2303 	return (0);
2304 }
2305 
2306 
2307 /*
2308  *      get_dependent()
2309  *
2310  *      Create a list of all dependents of a device
2311  *      Do not add dependent if it is marked as removed
2312  *
2313  *      Input:
2314  *		deventry_t	*deventry	device entry
2315  *      Output:
2316  *		char		***dependentsp	pty to dependent list
2317  *      Return:
2318  *		int		0, if ok, -1 if failed
2319  *      Locking: None
2320  */
2321 static int
2322 get_dependents(deventry_t *deventry, char *** dependentsp)
2323 {
2324 	int		ndeps = 0;
2325 	deventry_t	*dependent;
2326 	char		**deps = NULL;
2327 
2328 
2329 	dependent = deventry->dependent;
2330 	if (dependent == NULL) {
2331 		*dependentsp = NULL;
2332 		return (0);
2333 	}
2334 	while (dependent != NULL) {
2335 		/*
2336 		 * do not add dependent if we have
2337 		 * already received a remove notifification
2338 		 */
2339 		if (!(dependent->flags&REMOVED))
2340 			if (add_dep(&ndeps, &deps, dependent) < 0)
2341 				return (-1);
2342 		dependent = dependent->next_dep;
2343 	}
2344 	if (ndeps == 0) {
2345 		*dependentsp = NULL;
2346 	} else {
2347 		*dependentsp = deps;
2348 	}
2349 	return (0);
2350 }
2351 
2352 /*
2353  *      add_to_usage()
2354  *      Add string to the usage string pointed at by usagep. Allocate memory
2355  *      for the new usage string and free the memory used by the original
2356  *      usage string
2357  *
2358  *      Input:
2359  *		char	**usagep	ptr to usage string
2360  *		char	*string		string to be added to usage
2361  *      Return:
2362  *		char	ptr to new usage string
2363  *      Locking: None
2364  */
2365 char *
2366 add_to_usage(char ** usagep, char *string)
2367 {
2368 	int	len;
2369 	char	*new_usage = NULL;
2370 
2371 	if (*usagep == NULL) {
2372 		len = 0;
2373 	} else {
2374 		len = strlen(*usagep) + 2; /* allow space for comma */
2375 	}
2376 	len += strlen(string) + 1;
2377 	if (new_usage = calloc(1, len)) {
2378 		if (*usagep) {
2379 			(void) strcpy(new_usage, *usagep);
2380 			free(*usagep);
2381 			(void) strcat(new_usage, ", ");
2382 		}
2383 		(void) strcat(new_usage, string);
2384 	}
2385 	return (new_usage);
2386 }
2387 
2388 /*
2389  *      add_to_usage_fmt()
2390  *
2391  *      Add a formatted string , of the form "blah %s" to the usage string
2392  *      pointed at by usagep. Allocate memory for the new usage string and free
2393  *      the memory used by the original usage string.
2394  *
2395  *      Input:
2396  *		char		**usagep	ptr to current usage string
2397  *		char		*fmt		format string
2398  *		char		*string		string to be added
2399  *      Return:
2400  *		char*		new usage string
2401  *      Locking: None
2402  */
2403 /*PRINTFLIKE2*/
2404 char *
2405 add_to_usage_fmt(char **usagep, char *fmt, char *string)
2406 {
2407 	int	len;
2408 	char	*usage;
2409 	char	*new_usage = NULL;
2410 
2411 	len = strlen(fmt)
2412 	    + strlen(string) + 1;
2413 	if (usage = calloc(1, len)) {
2414 		(void) sprintf(usage, fmt, string);
2415 		new_usage = add_to_usage(usagep, usage);
2416 		free(usage);
2417 	}
2418 	return (new_usage);
2419 }
2420 
2421 /*
2422  *      is_open()
2423  *
2424  *      Make ioctl call to find if a device is open
2425  *
2426  *      Input:
2427  *		dev_t 		devkey	dev_t for device
2428  *      Return:
2429  *		int		0 if not open,  !=0 if open
2430  *      Locking: None
2431  */
2432 static int
2433 is_open(dev_t devkey)
2434 {
2435 	int		fd;
2436 	md_isopen_t	isopen_ioc;
2437 
2438 	/* Open admin device */
2439 	if ((fd = open(ADMSPECIAL, O_RDONLY, 0)) < 0) {
2440 		rcm_log_message(RCM_ERROR, MSG_OPENERR, ADMSPECIAL);
2441 		return (0);
2442 	}
2443 
2444 	(void) memset(&isopen_ioc, 0, sizeof (isopen_ioc));
2445 	isopen_ioc.dev = devkey;
2446 	if (ioctl(fd, MD_IOCISOPEN, &isopen_ioc) < 0) {
2447 		(void) close(fd);
2448 		return (0);
2449 	}
2450 	(void) close(fd);
2451 	return (isopen_ioc.isopen);
2452 }
2453 
2454 /*
2455  *	check_softpart()
2456  *
2457  *	Check the status of the passed in device within the softpartition.
2458  *
2459  *	Input:
2460  *		mdsetname_t *	the name of the set
2461  *		mdname_t *	the softpartition device that is being examined
2462  *		char *		the device which needs to be checked
2463  *		md_error_t *	error pointer (not used)
2464  *	Return:
2465  *		int		REDUNDANT    - device is redundant and can be
2466  *					       removed
2467  *				NOTREDUNDANT - device cannot be removed
2468  *				NOTINDEVICE  - device is not part of this
2469  *					       component
2470  */
2471 static int
2472 check_softpart(mdsetname_t *sp, mdname_t *np, char *uname, md_error_t *ep)
2473 {
2474 	md_sp_t	*softp = NULL;
2475 
2476 	rcm_log_message(RCM_TRACE1, "SVM: softpart checking %s %s\n",
2477 	    np->bname, uname);
2478 
2479 	softp = meta_get_sp(sp, np, ep);
2480 
2481 	/* softp cannot be NULL, if it is then the RCM cache is corrupt */
2482 	assert(softp != NULL);
2483 
2484 	/*
2485 	 * if the softpartition is not a parent then nothing can be done, user
2486 	 * must close the device and then fix the under lying devices.
2487 	 */
2488 	if (!(MD_HAS_PARENT(softp->common.parent))) {
2489 		rcm_log_message(RCM_TRACE1,
2490 		    "SVM: softpart is a top level device\n");
2491 		return (NOTREDUNDANT);
2492 	}
2493 
2494 	if (strcmp(softp->compnamep->bname, uname) != 0) {
2495 		/*
2496 		 * This can occur if this function has been called by the
2497 		 * check_raid5 code as it is cycling through each column
2498 		 * in turn.
2499 		 */
2500 		rcm_log_message(RCM_TRACE1,
2501 		    "SVM: %s is not in softpart (%s)\n",
2502 		    uname, softp->compnamep->bname);
2503 		return (NOTINDEVICE);
2504 	}
2505 
2506 	/*
2507 	 * Check the status of the soft partition this only moves from
2508 	 * an okay state if the underlying devices fails while the soft
2509 	 * partition is open.
2510 	 */
2511 	if (softp->status != MD_SP_OK) {
2512 		rcm_log_message(RCM_TRACE1,
2513 		    "SVM: softpart is broken (state: 0x%x)\n",
2514 		    softp->status);
2515 		return (REDUNDANT);
2516 	}
2517 
2518 	return (NOTREDUNDANT);
2519 }
2520 
2521 /*
2522  *	check_raid5()
2523  *
2524  *	Check the status of the passed in device within the raid5 in question.
2525  *
2526  *	Input:
2527  *		mdsetname_t *	the name of the set
2528  *		mdname_t *	the raid5 device that is being examined
2529  *		char *		the device which needs to be checked
2530  *		md_error_t *	error pointer (not used)
2531  *	Return:
2532  *		int		REDUNDANT    - device is redundant and can be
2533  *					       removed
2534  *				NOTREDUNDANT - device cannot be removed
2535  */
2536 static int
2537 check_raid5(mdsetname_t *sp, mdname_t *np, char *uname, md_error_t *ep)
2538 {
2539 	md_raid_t	*raidp = NULL;
2540 	md_raidcol_t	*colp = NULL;
2541 	int		i;
2542 	int		rval = 0;
2543 
2544 	rcm_log_message(RCM_TRACE1, "SVM: raid5 checking %s %s\n",
2545 	    np->bname, uname);
2546 
2547 	raidp = meta_get_raid(sp, np, ep);
2548 
2549 	/* raidp cannot be NULL, if it is then the RCM cache is corrupt */
2550 	assert(raidp != NULL);
2551 
2552 	/*
2553 	 * Now check each column in the device. We cannot rely upon the state
2554 	 * of the device because if a hotspare is in use all the states are
2555 	 * set to Okay, both at the metadevice layer and the column layer.
2556 	 */
2557 	for (i = 0; (i < raidp->cols.cols_len); i++) {
2558 		colp = &raidp->cols.cols_val[i];
2559 		np = colp->colnamep;
2560 
2561 		rcm_log_message(RCM_TRACE1,
2562 		    "SVM: raid5 checking %s state %s 0x%x\n",
2563 		    np->bname, raid_col_state_to_name(colp, NULL, 0),
2564 		    colp->state);
2565 
2566 		/*
2567 		 * It is possible for the column to be a softpartition,
2568 		 * so need to check the softpartiton if this is the
2569 		 * case. It is *not* valid for the column to be a
2570 		 * stripe/concat/mirror, and so no check to see what
2571 		 * type of metadevice is being used.
2572 		 */
2573 		if (metaismeta(np)) {
2574 			/* this is a metadevice ie a softpartiton */
2575 			rval = check_softpart(sp, np, uname, ep);
2576 			if (rval == REDUNDANT) {
2577 				rcm_log_message(RCM_TRACE1,
2578 				    "SVM: raid5 %s is broken\n", uname);
2579 				meta_invalidate_name(np);
2580 				return (REDUNDANT);
2581 			} else if (rval == NOTREDUNDANT &&
2582 			    colp->hsnamep != NULL) {
2583 				rcm_log_message(RCM_TRACE1,
2584 				    "SVM: raid5 device is broken, hotspared\n");
2585 				meta_invalidate_name(np);
2586 				return (REDUNDANT);
2587 			}
2588 			meta_invalidate_name(np);
2589 			continue;
2590 		}
2591 		meta_invalidate_name(np);
2592 
2593 		if (strcmp(uname, np->bname) != 0)
2594 			continue;
2595 
2596 		/*
2597 		 * Found the device. Check if it is broken or hotspared.
2598 		 */
2599 		if (colp->state & RUS_ERRED) {
2600 			rcm_log_message(RCM_TRACE1,
2601 			    "SVM: raid5 column device is broken\n");
2602 			return (REDUNDANT);
2603 		}
2604 
2605 		if (colp->hsnamep != NULL) {
2606 			rcm_log_message(RCM_TRACE1,
2607 			    "SVM: raid5 column device is broken, hotspared\n");
2608 			return (REDUNDANT);
2609 		}
2610 	}
2611 	return (NOTREDUNDANT);
2612 }
2613 
2614 /*
2615  *	check_stripe()
2616  *
2617  *	Check the status of the passed in device within the stripe in question.
2618  *
2619  *	Input:
2620  *		mdsetname_t *	the name of the set
2621  *		mdname_t *	the stripe that is being examined
2622  *		char *		the device which needs to be checked
2623  *		md_error_t *	error pointer (not used)
2624  *	Return:
2625  *		int		REDUNDANT    - device is redundant and can be
2626  *					       removed
2627  *				NOTREDUNDANT - device cannot be removed
2628  *				NOTINDEVICE  - device is not part of this
2629  *					       component
2630  */
2631 static int
2632 check_stripe(mdsetname_t *sp, mdname_t *np, char *uname, md_error_t *ep)
2633 {
2634 	md_stripe_t	*stripep = NULL;
2635 	md_row_t	*mrp = NULL;
2636 	md_comp_t	*mcp;
2637 	mdname_t	*pnp;
2638 	char		*miscname;
2639 	int		row;
2640 	int		col;
2641 
2642 	rcm_log_message(RCM_TRACE1, "SVM: concat/stripe checking %s %s\n",
2643 	    np->bname, uname);
2644 	stripep = meta_get_stripe(sp, np, ep);
2645 
2646 	/* stripep cannot be NULL, if it is then the RCM cache is corrupt */
2647 	assert(stripep != NULL);
2648 
2649 	/*
2650 	 * If the stripe is not a parent then nothing can be done, user
2651 	 * must close the device and then fix the devices.
2652 	 */
2653 	if (!(MD_HAS_PARENT(stripep->common.parent))) {
2654 		rcm_log_message(RCM_TRACE1,
2655 		    "SVM: stripe is a top level device\n");
2656 		return (NOTREDUNDANT);
2657 	}
2658 
2659 	pnp = metamnumname(&sp, stripep->common.parent, 0, ep);
2660 
2661 	if (pnp == NULL) {
2662 		/*
2663 		 * Only NULL when the replicas are in an inconsistant state
2664 		 * ie the device says it is the parent of X but X does not
2665 		 * exist.
2666 		 */
2667 		rcm_log_message(RCM_TRACE1, "SVM: parent is not configured\n");
2668 		return (NOTREDUNDANT);
2669 	}
2670 
2671 	/*
2672 	 * Get the type of the parent and make sure that it is a mirror,
2673 	 * if it is then need to find out the number of submirrors, and
2674 	 * if it is not a mirror then this is not a REDUNDANT device.
2675 	 */
2676 	if ((miscname = metagetmiscname(pnp, ep)) == NULL) {
2677 		/*
2678 		 * Again something is wrong with the configuration.
2679 		 */
2680 		rcm_log_message(RCM_TRACE1,
2681 		    "SVM: unable to find the type of %s\n", pnp->cname);
2682 		meta_invalidate_name(pnp);
2683 		return (NOTREDUNDANT);
2684 	}
2685 
2686 	if (!(strcmp(miscname, MD_MIRROR) == 0 &&
2687 	    check_mirror(sp, pnp, ep) == REDUNDANT)) {
2688 		rcm_log_message(RCM_TRACE1,
2689 		    "SVM: %s is a %s and not redundant\n",
2690 		    pnp->cname, miscname);
2691 		meta_invalidate_name(pnp);
2692 		return (NOTREDUNDANT);
2693 	}
2694 
2695 	meta_invalidate_name(pnp);
2696 
2697 	for (row = 0; row < stripep->rows.rows_len; row++) {
2698 		mrp = &stripep->rows.rows_val[row];
2699 
2700 		/* now the components in the row */
2701 		for (col = 0; col < mrp->comps.comps_len; col++) {
2702 			mcp = &mrp->comps.comps_val[col];
2703 
2704 			rcm_log_message(RCM_TRACE1,
2705 			    "SVM: stripe comp %s check\n",
2706 			    mcp->compnamep->bname);
2707 
2708 			if (strcmp(mcp->compnamep->bname, uname) != 0)
2709 				continue;
2710 
2711 			rcm_log_message(RCM_TRACE1,
2712 			    "SVM: component state: %s\n",
2713 			    comp_state_to_name(mcp, NULL, 0));
2714 
2715 			if (mcp->hsnamep != NULL) {
2716 				/* device is broken and hotspared */
2717 				rcm_log_message(RCM_TRACE1,
2718 				    "SVM: stripe %s broken, hotspare active\n",
2719 				    uname);
2720 				return (REDUNDANT);
2721 			}
2722 
2723 			/*
2724 			 * LAST_ERRED is a special case.  If the state of a
2725 			 * component is CS_LAST_ERRED then this is the last
2726 			 * copy of the data and we need to keep using it, even
2727 			 * though we had errors.  Thus, we must block the DR
2728 			 * request.  If you follow the documented procedure for
2729 			 * fixing each component (fix devs in maintenance
2730 			 * before last erred) then the mirror will
2731 			 * automatically transition Last Erred components to
2732 			 * the Erred state after which they can be DRed out.
2733 			 */
2734 			if (mcp->state == CS_ERRED) {
2735 				/* device is broken */
2736 				rcm_log_message(RCM_TRACE1,
2737 				    "SVM: stripe %s is broken\n", uname);
2738 				return (REDUNDANT);
2739 			}
2740 
2741 			/*
2742 			 * Short circuit - if here the component has been
2743 			 * found in the column so no further processing is
2744 			 * required here.
2745 			 */
2746 			return (NOTREDUNDANT);
2747 		}
2748 	}
2749 
2750 	/*
2751 	 * Only get to this point if the device (uname) has not been
2752 	 * found in the stripe. This means that there is something
2753 	 * wrong with the device dependency list.
2754 	 */
2755 	rcm_log_message(RCM_TRACE1,
2756 	    "SVM: component %s is not part of %s\n",
2757 	    uname, np->bname);
2758 
2759 	return (NOTINDEVICE);
2760 }
2761 
2762 /*
2763  *	check_mirror()
2764  *
2765  *	Make sure that the mirror > 1 submirror.
2766  *
2767  *	Input:
2768  *		mdsetname_t *	the name of the set
2769  *		mdname_t *	the stripe that is being examined
2770  *	Return:
2771  *		int		REDUNDANT    - mirror > 1 submirrors
2772  *				NOTREDUNDANT - mirror has 1 submirror
2773  */
2774 static int
2775 check_mirror(mdsetname_t *sp, mdname_t *np, md_error_t *ep)
2776 {
2777 	uint_t		nsm = 0;	/* number of submirrors */
2778 	uint_t		smi = 0;	/* index into submirror array */
2779 	md_mirror_t	*mirrorp = NULL;
2780 
2781 	rcm_log_message(RCM_TRACE1, "SVM: mirror checking %s\n", np->bname);
2782 	mirrorp = meta_get_mirror(sp, np, ep);
2783 
2784 	/* mirrorp cannot be NULL, if it is then the RCM cache is corrupt */
2785 	assert(mirrorp != NULL);
2786 
2787 	/*
2788 	 * Need to check how many submirrors that the mirror has.
2789 	 */
2790 	for (smi = 0, nsm = 0; (smi < NMIRROR); ++smi) {
2791 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
2792 		mdname_t	*submirnamep = mdsp->submirnamep;
2793 
2794 		/* Is this submirror being used ?  No, then continue */
2795 		if (submirnamep == NULL)
2796 			continue;
2797 		nsm++;
2798 	}
2799 
2800 	/*
2801 	 * If there is only one submirror then there is no redundancy
2802 	 * in the configuration and the user needs to take some other
2803 	 * action before using cfgadm on the device ie close the metadevice.
2804 	 */
2805 	if (nsm == 1) {
2806 		rcm_log_message(RCM_TRACE1,
2807 		    "SVM: only one submirror unable to allow action\n");
2808 		return (NOTREDUNDANT);
2809 	}
2810 
2811 	return (REDUNDANT);
2812 }
2813 
2814 /*
2815  *	check_device()
2816  *
2817  *	Check the current status of the underlying device.
2818  *
2819  *	Input:
2820  *		deventry_t *	the device that is being checked
2821  *	Return:
2822  *		int		REDUNDANT    - device is redundant and can be
2823  *					       removed
2824  *				NOTREDUNDANT - device cannot be removed
2825  *	Locking:
2826  *		None
2827  *
2828  * The check_device code path (the functions called by check_device) use
2829  * libmeta calls directly to determine if the specified device is
2830  * redundant or not.  The can lead to conflicts between data cached in
2831  * libmeta and data that is being cached by this rcm module.  Since the
2832  * rcm cache is our primary source of information here, we need to make
2833  * sure that we are not getting stale data from the libmeta caches.
2834  * We use meta_invalidate_name throughout this code path to clear the
2835  * cached data in libmeta in order to ensure that we are not using stale data.
2836  */
2837 static int
2838 check_device(deventry_t *deventry)
2839 {
2840 	mdsetname_t	*sp;
2841 	md_error_t	error = mdnullerror;
2842 	char		sname[BUFSIZ+1];
2843 	uint32_t	d;
2844 	mdname_t	*np;
2845 	deventry_t	*dependent;
2846 	int		rval = NOTREDUNDANT;
2847 	int		ret;
2848 
2849 	dependent = deventry->dependent;
2850 
2851 	rcm_log_message(RCM_TRACE1, "SVM: check_device(%s)\n",
2852 	    deventry->devname);
2853 	/*
2854 	 * should not be null because the caller has already figured out
2855 	 * there are dependent devices.
2856 	 */
2857 	assert(dependent != NULL);
2858 
2859 	do {
2860 
2861 		rcm_log_message(RCM_TRACE1, "SVM: check dependent: %s\n",
2862 		    dependent->devname);
2863 
2864 		if (dependent->flags & REMOVED) {
2865 			dependent = dependent->next_dep;
2866 			continue;
2867 		}
2868 
2869 		/*
2870 		 * The device *should* be a metadevice and so need to see if
2871 		 * it contains a setname.
2872 		 */
2873 		ret = sscanf(dependent->devname,
2874 		    "/dev/md/%" VAL2STR(BUFSIZ) "[^/]/dsk/d%u",
2875 		    sname, &d);
2876 
2877 		if (ret != 2)
2878 			(void) strcpy(sname, MD_LOCAL_NAME);
2879 
2880 		if ((sp = metasetname(sname, &error)) == NULL) {
2881 			rcm_log_message(RCM_TRACE1,
2882 			    "SVM: unable to get setname for \"%s\", error %s\n",
2883 			    sname, mde_sperror(&error, ""));
2884 			break;
2885 		}
2886 
2887 		rcm_log_message(RCM_TRACE1, "SVM: processing: %s\n",
2888 		    dependent->devname);
2889 
2890 		np = metaname(&sp, dependent->devname, &error);
2891 
2892 		switch (dependent->devtype) {
2893 		case SVM_TRANS:
2894 			/*
2895 			 * No code to check trans devices because ufs logging
2896 			 * should be being used.
2897 			 */
2898 			rcm_log_message(RCM_TRACE1,
2899 			    "SVM: Use UFS logging instead of trans devices\n");
2900 			break;
2901 		case SVM_SLICE:
2902 		case SVM_STRIPE:
2903 		case SVM_CONCAT:
2904 			rval = check_stripe(sp, np, deventry->devname, &error);
2905 			break;
2906 		case SVM_MIRROR:
2907 			/*
2908 			 * No check here as this is performed by the one
2909 			 * above when the submirror is checked.
2910 			 */
2911 			rcm_log_message(RCM_TRACE1,
2912 			    "SVM: Mirror check is done by the stripe check\n");
2913 			break;
2914 		case SVM_RAID:
2915 			/*
2916 			 * Raid5 devices can be built on soft partitions or
2917 			 * slices and so the check here is for the raid5
2918 			 * device built on top of slices. Note, a raid5 cannot
2919 			 * be built on a stripe/concat.
2920 			 */
2921 			rval = check_raid5(sp, np, deventry->devname, &error);
2922 			break;
2923 		case SVM_SOFTPART:
2924 			/*
2925 			 * Raid5 devices can be built on top of soft partitions
2926 			 * and so they have to be checked.
2927 			 */
2928 			rval = check_softpart(sp, np, deventry->devname,
2929 			    &error);
2930 			break;
2931 		default:
2932 			rcm_log_message(RCM_TRACE1,
2933 			    "SVM: unknown devtype: %d\n", dependent->devtype);
2934 			break;
2935 		}
2936 
2937 		meta_invalidate_name(np);
2938 
2939 		if (rval == REDUNDANT)
2940 			break;
2941 	} while ((dependent = dependent->next_dep) != NULL);
2942 
2943 	rcm_log_message(RCM_TRACE1, "SVM: check_device return %d\n", rval);
2944 	return (rval);
2945 }
2946