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