meta_hotspares.c revision 1623:7bac4a816ebe
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 2006 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/*
29 * Just in case we're not in a build environment, make sure that
30 * TEXT_DOMAIN gets set to something.
31 */
32#if !defined(TEXT_DOMAIN)
33#define	TEXT_DOMAIN "SYS_TEST"
34#endif
35
36/*
37 * hotspares utilities
38 */
39
40#include <meta.h>
41#include <sys/lvm/md_hotspares.h>
42#include <sys/lvm/md_convert.h>
43
44/*
45 * FUNCTION:	meta_get_hsp_names()
46 * INPUT:	sp	- the set name to get hotspares from
47 *		options	- options from the command line
48 * OUTPUT:	hspnlpp	- list of all hotspare names
49 *		ep	- return error pointer
50 * RETURNS:	int	- -1 if error, 0 success
51 * PURPOSE:	returns a list of all hotspares in the metadb
52 *		for all devices in the specified set
53 */
54/*ARGSUSED*/
55int
56meta_get_hsp_names(
57	mdsetname_t	*sp,
58	mdhspnamelist_t	**hspnlpp,
59	int		options,
60	md_error_t	*ep
61)
62{
63	md_i_getnum_t	gn;		/* MD_IOCGET_NUM params */
64	minor_t		*minors = NULL;
65	minor_t		*m_ptr;
66	int		i;
67
68	/* we must have a set */
69	assert(sp != NULL);
70
71	(void) memset(&gn, 0, sizeof (gn));
72	MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno);
73
74	/* get number of devices */
75	if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
76		if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
77			mdclrerror(&gn.mde);
78		} else {
79			(void) mdstealerror(ep, &gn.mde);
80			return (-1);
81		}
82	}
83
84	if (gn.size > 0) {
85		/* malloc minor number buffer to be filled by ioctl */
86		if ((minors = (minor_t *)malloc(
87				gn.size * sizeof (minor_t))) == 0) {
88			return (ENOMEM);
89		}
90		gn.minors = (uintptr_t)minors;
91		if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
92			(void) mdstealerror(ep, &gn.mde);
93			free(minors);
94			return (-1);
95		}
96		m_ptr = minors;
97		for (i = 0; i < gn.size; i++) {
98			mdhspname_t	*hspnp;
99
100
101			/* get name */
102			if ((hspnp = metahsphspname(&sp, *m_ptr, ep))
103					== NULL)
104				goto out;
105
106			/* append to list */
107			(void) metahspnamelist_append(hspnlpp, hspnp);
108
109			/* next device */
110			m_ptr++;
111		}
112		free(minors);
113	}
114	return (gn.size);
115
116out:
117	if (minors != NULL)
118		free(minors);
119	metafreehspnamelist(*hspnlpp);
120	*hspnlpp = NULL;
121	return (-1);
122}
123
124/*
125 * get information of a specific hotspare pool from driver
126 */
127static get_hsp_t *
128get_hspinfo(
129	mdsetname_t	*sp,
130	mdhspname_t	*hspnp,
131	md_error_t	*ep
132)
133{
134	md_i_get_t	mig;
135
136	/* should have a set */
137	assert(sp != NULL);
138	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
139
140	/* get size of unit structure */
141	(void) memset(&mig, 0, sizeof (mig));
142	MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno);
143	mig.id = hspnp->hsp;
144	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
145		(void) mdstealerror(ep, &mig.mde);
146		return (NULL);
147	}
148
149	/* get actual unit structure */
150	assert(mig.size > 0);
151	mig.mdp = (uintptr_t)Zalloc(mig.size);
152	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
153		(void) mdstealerror(ep, &mig.mde);
154		Free((void *)(uintptr_t)mig.mdp);
155		return (NULL);
156	}
157	return ((get_hsp_t *)(uintptr_t)mig.mdp);
158}
159
160/*
161 * free hotspare pool unit
162 */
163void
164meta_free_hsp(
165	md_hsp_t	*hspp
166)
167{
168	if (hspp->hotspares.hotspares_val != NULL) {
169		assert(hspp->hotspares.hotspares_len > 0);
170		Free(hspp->hotspares.hotspares_val);
171	}
172	Free(hspp);
173}
174
175/*
176 * get hotspare pool unit (common)
177 */
178md_hsp_t *
179meta_get_hsp_common(
180	mdsetname_t	*sp,
181	mdhspname_t	*hspnp,
182	int		fast,
183	md_error_t	*ep
184)
185{
186	get_hsp_t	*ghsp;
187	md_hsp_t	*hspp;
188	uint_t		hsi;
189
190	/* must have set */
191	assert(sp != NULL);
192	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
193
194	/* short circuit */
195	if (hspnp->unitp != NULL)
196		return (hspnp->unitp);
197
198	/* get unit */
199	if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL)
200		return (NULL);
201
202	/* allocate hsp */
203	hspp = Zalloc(sizeof (*hspp));
204
205	/* allocate hotspares */
206	hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares;
207
208	/* if empty hotspare pool, we are done */
209	if (hspp->hotspares.hotspares_len != 0)
210		hspp->hotspares.hotspares_val =
211		    Zalloc(hspp->hotspares.hotspares_len *
212		    sizeof (*hspp->hotspares.hotspares_val));
213
214	/* get name, refcount */
215	hspp->hspnamep = hspnp;
216	hspp->refcount = ghsp->ghsp_refcount;
217
218	/* get hotspares */
219	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
220		mdkey_t		hs_key = ghsp->ghsp_hs_keys[hsi];
221		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
222		get_hs_params_t	ghs;
223
224		/* get hotspare name */
225		hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep);
226		if (hsp->hsnamep == NULL)
227			goto out;
228
229		/* get hotspare state */
230		(void) memset(&ghs, 0, sizeof (ghs));
231		MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno);
232		ghs.ghs_key = hs_key;
233		if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) {
234			(void) mdstealerror(ep, &ghs.mde);
235			goto out;
236		}
237		hsp->state = ghs.ghs_state;
238		hsp->size = ghs.ghs_number_blks;
239		hsp->timestamp = ghs.ghs_timestamp;
240		hsp->revision = ghs.ghs_revision;
241	}
242
243	/* cleanup, return success */
244	Free(ghsp);
245	hspnp->unitp = hspp;
246	return (hspp);
247
248	/* cleanup, return error */
249out:
250	Free(ghsp);
251	meta_free_hsp(hspp);
252	return (NULL);
253}
254
255/*
256 * get hotspare pool unit
257 */
258md_hsp_t *
259meta_get_hsp(
260	mdsetname_t	*sp,
261	mdhspname_t	*hspnp,
262	md_error_t	*ep
263)
264{
265	return (meta_get_hsp_common(sp, hspnp, 0, ep));
266}
267
268/*
269 * check hotspare pool for dev
270 */
271static int
272in_hsp(
273	mdsetname_t	*sp,
274	mdhspname_t	*hspnp,
275	mdname_t	*np,
276	diskaddr_t	slblk,
277	diskaddr_t	nblks,
278	md_error_t	*ep
279)
280{
281	md_hsp_t	*hspp;
282	uint_t		i;
283
284	/* should be in the same set */
285	assert(sp != NULL);
286	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
287
288	/* get unit */
289	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
290		return (-1);
291
292	/* look in hotspares */
293	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
294		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
295		mdname_t	*hsnp = hs->hsnamep;
296
297		/* check overlap */
298		if (metaismeta(hsnp))
299			continue;
300		if (meta_check_overlap(hspnp->hspname, np, slblk, nblks,
301		    hsnp, 0, -1, ep) != 0)
302			return (-1);
303	}
304
305	/* return success */
306	return (0);
307}
308
309/*
310 * check to see if we're in a hotspare pool
311 */
312int
313meta_check_inhsp(
314	mdsetname_t	*sp,
315	mdname_t	*np,
316	diskaddr_t	slblk,
317	diskaddr_t	nblks,
318	md_error_t	*ep
319)
320{
321	mdhspnamelist_t	*hspnlp = NULL;
322	mdhspnamelist_t	*p;
323	int		rval = 0;
324
325	/* should have a set */
326	assert(sp != NULL);
327
328	/* for each hotspare pool */
329	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
330		return (-1);
331	for (p = hspnlp; (p != NULL); p = p->next) {
332		mdhspname_t	*hspnp = p->hspnamep;
333
334		/* check hotspare pool */
335		if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) {
336			rval = -1;
337			break;
338		}
339	}
340
341	/* cleanup, return success */
342	metafreehspnamelist(hspnlp);
343	return (rval);
344}
345
346/*
347 * check hotspare
348 */
349int
350meta_check_hotspare(
351	mdsetname_t	*sp,
352	mdname_t	*np,
353	md_error_t	*ep
354)
355{
356	mdchkopts_t	options = (MDCHK_ALLOW_HS);
357
358	/* make sure we have a disk */
359	if (metachkcomp(np, ep) != 0)
360		return (-1);
361
362	/* check to ensure that it is not already in use */
363	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
364		return (-1);
365	}
366
367	/* make sure it is in the set */
368	if (meta_check_inset(sp, np, ep) != 0)
369		return (-1);
370
371	/* make sure its not in a metadevice */
372	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
373		return (-1);
374
375	/* return success */
376	return (0);
377}
378
379/*
380 * print hsp
381 */
382static int
383hsp_print(
384	md_hsp_t	*hspp,
385	char		*fname,
386	FILE		*fp,
387	md_error_t	*ep
388)
389{
390	uint_t		hsi;
391	int		rval = -1;
392
393	/* print name */
394	if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF)
395		goto out;
396
397	/* print hotspares */
398	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
399		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
400
401		/* print hotspare */
402		/*
403		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
404		 * then just print out the cxtxdxsx or the dx, metainit
405		 * will assume the default, otherwise we need the full
406		 * pathname to make sure this works as we intend.
407		 */
408		if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) &&
409		    (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) &&
410		    (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) {
411			/* not standard path, print full pathname */
412			if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF)
413				goto out;
414		} else {
415			/* standard path, just print ctd or d value */
416			if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF)
417				goto out;
418		}
419	}
420
421	/* terminate last line */
422	if (fprintf(fp, "\n") == EOF)
423		goto out;
424
425	/* success */
426	rval = 0;
427
428	/* cleanup, return error */
429out:
430	if (rval != 0)
431		(void) mdsyserror(ep, errno, fname);
432	return (rval);
433}
434
435/*
436 * hotspare state name
437 */
438char *
439hs_state_to_name(
440	md_hs_t			*hsp,
441	md_timeval32_t		*tvp
442)
443{
444	hotspare_states_t	state = hsp->state;
445
446	/* grab time */
447	if (tvp != NULL)
448		*tvp = hsp->timestamp;
449
450	switch (state) {
451	case HSS_AVAILABLE:
452		return (dgettext(TEXT_DOMAIN, "Available"));
453	case HSS_RESERVED:
454		return (dgettext(TEXT_DOMAIN, "In use"));
455	case HSS_BROKEN:
456		return (dgettext(TEXT_DOMAIN, "Broken"));
457	case HSS_UNUSED:
458	default:
459		return (dgettext(TEXT_DOMAIN, "invalid"));
460	}
461}
462
463/*
464 * report hsp
465 */
466static int
467hsp_report(
468	md_hsp_t	*hspp,
469	mdnamelist_t	**nlpp,
470	char		*fname,
471	FILE		*fp,
472	mdprtopts_t	options,
473	md_error_t	*ep,
474	mdsetname_t	*sp
475)
476{
477	uint_t		hsi;
478	int		rval = -1;
479	char		*devid = "";
480	mdname_t	*didnp = NULL;
481	uint_t		len;
482	int		large_hs_dev_cnt = 0;
483	int		fn_hs_dev_cnt = 0;
484
485	if (options & PRINT_LARGEDEVICES) {
486		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
487			md_hs_t	*hsp = &hspp->hotspares.hotspares_val[hsi];
488			if (hsp->revision & MD_64BIT_META_DEV) {
489				large_hs_dev_cnt += 1;
490				if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
491				    != 0)
492					goto out;
493			}
494		}
495
496		if (large_hs_dev_cnt == 0) {
497			rval = 0;
498			goto out;
499		}
500	}
501
502	if (options & PRINT_FN) {
503		if (!HSP_ID_IS_FN(hspp->hspnamep->hsp)) {
504			rval = 0;
505			goto out;
506		}
507		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
508			md_hs_t	*hsp = &hspp->hotspares.hotspares_val[hsi];
509			fn_hs_dev_cnt += 1;
510			if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
511			    != 0)
512				goto out;
513		}
514	}
515
516	/* print header */
517	if (hspp->hotspares.hotspares_len == 0) {
518		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"),
519		    hspp->hspnamep->hspname) == EOF) {
520			goto out;
521		}
522	} else if (hspp->hotspares.hotspares_len == 1) {
523
524		/*
525		 * This allows the length
526		 * of the ctd to vary from small to large without
527		 * looking horrible.
528		 */
529
530		len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname);
531		/*
532		 * if the length is to short to print out all of the header
533		 * force the matter
534		 */
535		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
536		len += 2;
537		if (options & PRINT_LARGEDEVICES) {
538			if (fprintf(fp,
539			    "%s: 1 hot spare (1 big device)\n\t%-*.*s  "
540			    "%-12.12s%-8.6s\t\t%s\n",
541			    hspp->hspnamep->hspname, len, len,
542			    dgettext(TEXT_DOMAIN, "Device"),
543			    dgettext(TEXT_DOMAIN, "Status"),
544			    dgettext(TEXT_DOMAIN, "Length"),
545			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
546				goto out;
547			}
548		} else {
549			if (fprintf(fp,
550			    "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n",
551			    hspp->hspnamep->hspname, len, len,
552			    dgettext(TEXT_DOMAIN, "Device"),
553			    dgettext(TEXT_DOMAIN, "Status"),
554			    dgettext(TEXT_DOMAIN, "Length"),
555			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
556				goto out;
557			}
558		}
559	} else {
560		/*
561		 * This allows the length
562		 * of the ctd to vary from small to large without
563		 * looking horrible.
564		 */
565		len = 0;
566		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
567			len = max(len, strlen(hspp->
568			    hotspares.hotspares_val[hsi].hsnamep->cname));
569		}
570		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
571		len += 2;
572		if (options & PRINT_LARGEDEVICES) {
573			if (fprintf(fp,
574			    "%s: %u hot spares (%d big device(s))\n\t%-*.*s "
575			    "%-12.12s%-8.6s\t\t%s\n",
576			    hspp->hspnamep->hspname,
577			    hspp->hotspares.hotspares_len,
578			    large_hs_dev_cnt, len, len,
579			    dgettext(TEXT_DOMAIN, "Device"),
580			    dgettext(TEXT_DOMAIN, "Status"),
581			    dgettext(TEXT_DOMAIN, "Length"),
582			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
583				goto out;
584			}
585		} else {
586			if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s "
587			    "%-12.12s%-8.6s\t\t%s\n",
588			    hspp->hspnamep->hspname,
589			    hspp->hotspares.hotspares_len, len, len,
590			    dgettext(TEXT_DOMAIN, "Device"),
591			    dgettext(TEXT_DOMAIN, "Status"),
592			    dgettext(TEXT_DOMAIN, "Length"),
593			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
594				goto out;
595			}
596		}
597	}
598
599	/* print hotspares */
600	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
601		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
602		char		*cname = hsp->hsnamep->cname;
603		char		*hs_state;
604		md_timeval32_t	tv;
605		char		*timep;
606		ddi_devid_t	dtp;
607
608		/* populate the key in the name_p structure */
609		if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) {
610			return (-1);
611		}
612
613		if (options & PRINT_LARGEDEVICES) {
614			if ((hsp->revision & MD_64BIT_META_DEV) == 0)
615				continue;
616		}
617		/* determine if devid does NOT exist */
618		if (options & PRINT_DEVID) {
619		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
620				didnp->key, ep)) == NULL)
621				devid = dgettext(TEXT_DOMAIN, "No ");
622			else {
623				devid = dgettext(TEXT_DOMAIN, "Yes");
624				free(dtp);
625			}
626		}
627		/* print hotspare */
628		hs_state = hs_state_to_name(hsp, &tv);
629		/*
630		 * This allows the length
631		 * of the ctd to vary from small to large without
632		 * looking horrible.
633		 */
634		if (! (options & PRINT_TIMES)) {
635			if (fprintf(fp,
636			    "        %-*s %-12s %lld blocks\t%s\n",
637			    len, cname, hs_state,
638			    hsp->size, devid) == EOF) {
639				goto out;
640			}
641		} else {
642			timep = meta_print_time(&tv);
643
644			if (fprintf(fp,
645			    "        %-*s\t    %-11s %8lld blocks%s\t%s\n",
646			    len, cname, hs_state,
647			    hsp->size, devid, timep) == EOF) {
648				goto out;
649			}
650		}
651	}
652
653	/* add extra line */
654	if (fprintf(fp, "\n") == EOF)
655		goto out;
656
657	/* success */
658	rval = 0;
659
660	/* cleanup, return error */
661out:
662	if (rval != 0)
663		(void) mdsyserror(ep, errno, fname);
664	return (rval);
665}
666
667/*
668 * print/report hsp
669 */
670int
671meta_hsp_print(
672	mdsetname_t	*sp,
673	mdhspname_t	*hspnp,
674	mdnamelist_t	**nlpp,
675	char		*fname,
676	FILE		*fp,
677	mdprtopts_t	options,
678	md_error_t	*ep
679)
680{
681	md_hsp_t	*hspp;
682
683	/* should have same set */
684	assert(sp != NULL);
685	assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
686	    sp->setno == HSP_SET(hspnp->hsp));
687
688	/* print all hsps */
689	if (hspnp == NULL) {
690		mdhspnamelist_t	*hspnlp = NULL;
691		mdhspnamelist_t	*p;
692		int		cnt;
693		int		rval = 0;
694
695		if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0)
696			return (-1);
697		else if (cnt == 0)
698			return (0);
699
700		/* recurse */
701		for (p = hspnlp; (p != NULL); p = p->next) {
702			mdhspname_t	*hspnp = p->hspnamep;
703
704			if (meta_hsp_print(sp, hspnp, nlpp, fname, fp,
705			    options, ep) != 0)
706				rval = -1;
707		}
708
709		/* cleanup, return success */
710		metafreehspnamelist(hspnlp);
711		return (rval);
712	}
713
714	/* get unit structure */
715	if ((hspp = meta_get_hsp_common(sp, hspnp,
716	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
717		return (-1);
718
719	/* print appropriate detail */
720	if (options & PRINT_SHORT)
721		return (hsp_print(hspp, fname, fp, ep));
722	else
723		return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp));
724}
725
726/*
727 * check for valid hotspare pool
728 */
729int
730metachkhsp(
731	mdsetname_t	*sp,
732	mdhspname_t	*hspnp,
733	md_error_t	*ep
734)
735{
736	if (meta_get_hsp(sp, hspnp, ep) == NULL)
737		return (-1);
738	return (0);
739}
740
741/*
742 * invalidate hotspare pool info
743 */
744void
745meta_invalidate_hsp(
746	mdhspname_t	*hspnp
747)
748{
749	md_hsp_t	*hspp = hspnp->unitp;
750
751	/* free it up */
752	if (hspp == NULL)
753		return;
754	meta_free_hsp(hspp);
755
756	/* clear cache */
757	hspnp->unitp = NULL;
758}
759
760/*
761 * FUNCTION:	del_hsp_name_mn_sides()
762 * INPUT:	sp	- set name
763 *		curside	- side of this node
764 *		key	- key of records to delete
765 * OUTPUT:	ep	- error information
766 * RETURNS:	none.
767 * PURPOSE:	There are name records for each side in a set.  This
768 *		function deletes the records associated with the specified
769 *		key for all sides except curside.  This function is used
770 *		when the set is a multinode set.
771 */
772static void
773del_hsp_name_mn_sides(
774	mdsetname_t	*sp,
775	md_set_desc	*sd,
776	side_t		curside,
777	mdkey_t		key,
778	md_error_t	*ep
779)
780{
781	md_error_t	first_error = MDNULLERROR;
782	int		error_seen = FALSE;
783	md_mnnode_desc	*nd;
784
785	for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
786		if (nd->nd_nodeid == curside)
787			continue;
788		if (del_name(sp, nd->nd_nodeid, key, &first_error) == -1) {
789			if (error_seen == FALSE) {
790				error_seen = TRUE;
791				(void) mdstealerror(ep, &first_error);
792			}
793		}
794	}
795}
796
797/*
798 * FUNCTION:	del_hsp_name_trad_sides()
799 * INPUT:	sp	- set name
800 *		curside	- side of this node
801 *		key	- key of records to delete
802 * OUTPUT:	ep	- error information
803 * RETURNS:	none.
804 * PURPOSE:	There are name records for each side in a set.  This
805 *		function deletes the records associated with the specified
806 *		key for all sides except curside.  This function is used
807 *		when the set is a traditional set.
808 */
809static void
810del_hsp_name_trad_sides(
811	mdsetname_t	*sp,
812	md_set_desc	*sd,
813	side_t		curside,
814	mdkey_t		key,
815	md_error_t	*ep
816)
817{
818	int		error_seen = FALSE;
819	md_error_t	first_error = MDNULLERROR;
820	int		i;
821
822	for (i = 0; i < MD_MAXSIDES; i++) {
823		if (i == curside)
824			continue;
825		if (sd->sd_nodes[i][0] != '\0') {
826			if (del_name(sp, i, key, &first_error) == -1) {
827				if (error_seen == FALSE) {
828					error_seen = TRUE;
829					(void) mdstealerror(ep, &first_error);
830				}
831			}
832		}
833	}
834}
835
836/*
837 * FUNCTION:	del_hsp_keys()
838 * INPUT:	sp	- set name
839 *		hspid	- ID of records to delete
840 * OUTPUT:	ep	- error information
841 * RETURNS:	0	- success
842 *		-1	- error
843 * PURPOSE:	Remove the NM records associated with hspid from all sides
844 *		of the set.  Missing records are not considered to be an
845 *		error.  The key associated with the current side is removed
846 *		last.
847 *
848 *		This function is very similar to del_key_name(), except it
849 *		does not require any device look up.  This is because the
850 *		hot spare pool is not a device.
851 */
852static int
853del_hsp_keys(mdsetname_t *sp, hsp_t hspid, md_error_t *ep)
854{
855	md_error_t	first_error = MDNULLERROR;
856	mdkey_t		key = HSP_ID_TO_KEY(hspid);
857	md_set_desc	*sd;
858	side_t		thisside;	/* Side # of this node. */
859
860	/*
861	 * If there is no key, this means that the hot spare was created
862	 * before the introduction of friendly names.  Thus, the is no NM
863	 * record and nothing for us to do in this function.
864	 */
865	if (key == MD_KEYBAD)
866		return (0);
867
868	/* Find our current side */
869	mdclrerror(ep);
870	thisside = getmyside(sp, ep);
871	if (! mdisok(ep))
872		return (-1);
873
874	/*
875	 * If not the local set, we need to process the non-local sides
876	 * first.
877	 */
878	if (!metaislocalset(sp)) {
879		if ((sd = metaget_setdesc(sp, ep)) == NULL)
880			return (-1);
881		if (MD_MNSET_DESC(sd)) {
882			/* Multinode set.  Sides are in a linked list. */
883			del_hsp_name_mn_sides(sp, sd, thisside, key,
884				&first_error);
885		} else {
886			/* Sides are in an array. */
887			del_hsp_name_trad_sides(sp, sd, thisside, key,
888				&first_error);
889		}
890	}
891
892	/* Now delete the name for the current side. */
893	(void) del_name(sp, thisside, key, ep);
894	if (! mdisok(&first_error))
895		(void) mdstealerror(ep, &first_error);
896	return (mdisok(ep) ? 0 : -1);
897}
898
899/*
900 * FUNCTION:	add_hsp_name_mn_sides()
901 * INPUT:	sp	- set name
902 *		curside	- side number for this node
903 *		key	- key to use for the name record
904 *		hsp_name - name of the hot spare
905 * OUTPUT:	ep	- error information
906 * RETURNS:	0 indicates success, and -1 indicates failure.
907 * PURPOSE:	Once the name record has been added for the current side,
908 *		this function adds the record to the remaining sides.  This
909 *		function is to be used when the set is a multinode set.
910 *		The side designated by curside will be ignored when adding
911 *		records.
912 */
913static int
914add_hsp_name_mn_sides(
915	mdsetname_t	*sp,
916	md_set_desc	*sd,
917	side_t		curside,
918	mdkey_t		key,
919	char		*hsp_name,
920	md_error_t	*ep
921)
922{
923	md_mnnode_desc	*nd;
924
925	for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
926		if (nd->nd_nodeid == curside)
927			continue;
928		if (add_name(sp, nd->nd_nodeid, key, MD_HOTSPARES,
929			minor(NODEV), hsp_name, ep) == -1) {
930			return (-1);
931		}
932	}
933	return (0);
934}
935
936/*
937 * FUNCTION:	add_hsp_name_trad_sides()
938 * INPUT:	sp	- set name
939 *		curside	- side number for this node
940 *		key	- key to use for the name record
941 *		hsp_name - name of the hot spare
942 * OUTPUT:	ep	- error information
943 * RETURNS:	0 indicates success, and -1 indicates failure.
944 * PURPOSE:	Once the name record has been added for the current side,
945 *		this function adds the record to the remaining sides.  This
946 *		function is to be used when the set is a traditional set.
947 *		The side designated by curside will be ignored when adding
948 *		records.
949 */
950static int
951add_hsp_name_trad_sides(
952	mdsetname_t	*sp,
953	md_set_desc	*sd,
954	side_t		curside,
955	mdkey_t		key,
956	char		*hsp_name,
957	md_error_t	*ep
958)
959{
960	int		i;
961
962	for (i = 0; i < MD_MAXSIDES; i++) {
963		if (i == curside)
964			continue;
965		if (sd->sd_nodes[i][0] != '\0') {
966			if (add_name(sp, i, key, MD_HOTSPARES, minor(NODEV),
967				hsp_name, ep) == -1) {
968				return (-1);
969			}
970		}
971	}
972	return (0);
973}
974
975/*
976 * FUNCTION:	add_hsp_name()
977 * INPUT:	sp	- Name of the set containing the hsp
978 *		hsp_name - Hot spare pool name to be added
979 * OUTPUT:	ep	- Error information
980 * RETURNS:	If successful the key of the newly added record is
981 *		returned.  MD_KEYBAD is returned to indicate a failure.
982 * PURPOSE:	This function creates a new NM record containing the name
983 *		of the hotspare pool.  A record containing the name is
984 *		added to each active side, but the record is added first to
985 *		the current side.  This function is modeled on
986 *		add_key_name() in meta_namespace.  The difference is that
987 *		there is no device associated with a hot spare pool
988 */
989static hsp_t
990add_hsp_name(
991	mdsetname_t	*sp,
992	char		*hsp_name,
993	md_error_t	*ep
994)
995{
996	md_error_t	ignore_error = MDNULLERROR;
997	mdkey_t		key;
998	md_set_desc	*sd;
999	side_t		thisside;	/* Side # of this node. */
1000
1001	if (sp == NULL) {
1002		(void) mderror(ep, MDE_NO_SET, NULL);
1003		return (MD_KEYBAD);
1004	}
1005	if (hsp_name == NULL) {
1006		(void) mderror(ep, MDE_INVAL_HSOP, NULL);
1007		return (MD_KEYBAD);
1008	}
1009
1010	mdclrerror(ep);
1011	thisside = getmyside(sp, ep);
1012	if (! mdisok(ep))
1013		return (MD_HSPID_WILD);
1014
1015	/* First add the record for the side of the current node. */
1016	key = add_name(sp, thisside, MD_KEYWILD, MD_HOTSPARES, minor(NODEV),
1017		hsp_name, ep);
1018	if (key == -1) {
1019		goto cleanup;
1020	}
1021
1022	/* Make sure that we can use the key */
1023	if (!HSP_KEY_OK(key)) {
1024		(void) mdhsperror(ep, MDE_HSP_CREATE_FAILURE, MD_HSPID_WILD,
1025			hsp_name);
1026		goto cleanup;
1027	}
1028
1029	/*
1030	 * Now that we have a key, we will use it to add a record to the
1031	 * rest of the sides in the set.  For multinode sets, the sides are
1032	 * in a linked list that is anchored on the set descriptor.  For
1033	 * traditional sets the side information is in an array in the set
1034	 * descriptor.
1035	 */
1036	if (!metaislocalset(sp)) {
1037		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1038			goto cleanup;
1039		}
1040		if (MD_MNSET_DESC(sd)) {
1041			/* Multinode set.  Sides are in linked list. */
1042			if (add_hsp_name_mn_sides(sp, sd, thisside, key,
1043				hsp_name, ep) == -1) {
1044				goto cleanup;
1045			}
1046		} else {
1047			/* Traditional set.  Sides are in an array. */
1048			if (add_hsp_name_trad_sides(sp, sd, thisside, key,
1049				hsp_name, ep) == -1) {
1050				goto cleanup;
1051			}
1052		}
1053	}
1054
1055	return (KEY_TO_HSP_ID(sp->setno, key));
1056
1057cleanup:
1058	/* Get rid records that we added. */
1059	(void) del_hsp_keys(sp, KEY_TO_HSP_ID(sp->setno, key), &ignore_error);
1060	return (MD_HSPID_WILD);
1061}
1062
1063/*
1064 * add hotspares and/or hotspare pool
1065 */
1066int
1067meta_hs_add(
1068	mdsetname_t	*sp,
1069	mdhspname_t	*hspnp,
1070	mdnamelist_t	*hsnlp,
1071	mdcmdopts_t	options,
1072	md_error_t	*ep
1073)
1074{
1075	md_error_t	ignore_error = MDNULLERROR;
1076	mdnamelist_t	*p;
1077	set_hs_params_t	shs;
1078	side_t		thisside;
1079
1080	/* should have a set */
1081	assert(sp != NULL);
1082	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1083
1084	/* clear cache */
1085	meta_invalidate_hsp(hspnp);
1086
1087	/* setup hotspare pool info */
1088	(void) memset(&shs, 0, sizeof (shs));
1089	shs.shs_cmd = ADD_HOT_SPARE;
1090	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1091
1092	/* Get key for hot spare pool name record. */
1093	if (options & MDCMD_DOIT) {
1094		/* First see if the name record already exists. */
1095		mdclrerror(ep);
1096		thisside = getmyside(sp, ep);
1097		if (! mdisok(ep))
1098			return (-1);
1099		shs.shs_hot_spare_pool =
1100			meta_gethspnmentbyname(sp->setno, thisside,
1101				hspnp->hspname, ep);
1102		if (! mdisok(ep)) {
1103			/*
1104			 * If the error is ENOENT, then we will create a
1105			 * hot spare pool name records.  For other types of
1106			 * errors, however, we'll bail out.
1107			 */
1108			if (! mdissyserror(ep, ENOENT))
1109				return (-1);
1110			mdclrerror(ep);
1111			/* make sure that the name isn't already in use */
1112			if (is_existing_metadevice(sp, hspnp->hspname))
1113				return (mderror(ep, MDE_NAME_IN_USE,
1114					hspnp->hspname));
1115			if ((shs.shs_hot_spare_pool =
1116				add_hsp_name(sp, hspnp->hspname, ep)) ==
1117				MD_HSPID_WILD) {
1118				return (-1);
1119			}
1120		}
1121	}
1122
1123	/* add empty hotspare pool */
1124	if (hsnlp == NULL) {
1125		shs.shs_options = HS_OPT_POOL;
1126		/* If DOIT is not set, it's a dryrun */
1127		if ((options & MDCMD_DOIT) == 0) {
1128			shs.shs_options |= HS_OPT_DRYRUN;
1129		}
1130		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
1131			hspnp->hspname) != 0) {
1132			if (options & MDCMD_DOIT) {
1133				(void) del_hsp_keys(sp,
1134					shs.shs_hot_spare_pool,
1135					&ignore_error);
1136			}
1137			return (mdstealerror(ep, &shs.mde));
1138		}
1139		goto success;
1140	}
1141
1142	/* add hotspares */
1143	shs.shs_options = HS_OPT_NONE;
1144	/* If DOIT is not set, it's a dryrun */
1145	if ((options & MDCMD_DOIT) == 0) {
1146		shs.shs_options |= HS_OPT_DRYRUN;
1147	}
1148	for (p = hsnlp; (p != NULL); p = p->next) {
1149		mdname_t	*hsnp = p->namep;
1150		diskaddr_t	size, label, start_blk;
1151
1152		/* should be in same set */
1153		assert(hspnp->hsp == MD_HSP_NONE ||
1154		    sp->setno == HSP_SET(hspnp->hsp));
1155
1156		/* check it out */
1157		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1158			return (-1);
1159		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
1160			return (-1);
1161		else if (size == 0)
1162			return (mdsyserror(ep, ENOSPC, hsnp->cname));
1163		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
1164			return (-1);
1165		if ((start_blk = metagetstart(sp, hsnp, ep))
1166		    == MD_DISKADDR_ERROR)
1167			return (-1);
1168
1169		shs.shs_size_option = meta_check_devicesize(size);
1170
1171		/* In dryrun mode (DOIT not set) we must not alter the mddb */
1172		if (options & MDCMD_DOIT) {
1173			/* store name in namespace */
1174			if (add_key_name(sp, hsnp, NULL, ep) != 0)
1175				return (-1);
1176		}
1177
1178		/* add hotspare and/or hotspare pool */
1179		shs.shs_component_old = hsnp->dev;
1180		shs.shs_start_blk = start_blk;
1181		shs.shs_has_label = ((label > 0) ? 1 : 0);
1182		shs.shs_number_blks = size;
1183		shs.shs_key_old = hsnp->key;
1184		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1185			if ((options & MDCMD_DOIT) &&
1186			    (shs.shs_options != HS_OPT_POOL)) {
1187				(void) del_key_name(sp, hsnp, ep);
1188			}
1189			return (mdstealerror(ep, &shs.mde));
1190		}
1191	}
1192
1193	/* print success message */
1194success:
1195	if (options & MDCMD_PRINT) {
1196		if ((options & MDCMD_INIT) || (hsnlp == NULL)) {
1197			(void) printf(dgettext(TEXT_DOMAIN,
1198			    "%s: Hotspare pool is setup\n"),
1199			    hspnp->hspname);
1200		} else if (hsnlp->next == NULL) {
1201			(void) printf(dgettext(TEXT_DOMAIN,
1202			    "%s: Hotspare is added\n"),
1203			    hspnp->hspname);
1204		} else {
1205			(void) printf(dgettext(TEXT_DOMAIN,
1206			    "%s: Hotspares are added\n"),
1207			    hspnp->hspname);
1208		}
1209		(void) fflush(stdout);
1210	}
1211
1212	/* return success */
1213	return (0);
1214}
1215
1216/*
1217 * FUNCTION:	meta_hsp_delete()
1218 * INPUT:	sp	- Name of the set containing the hsp
1219 *		hspnp	- Hot spare pool name information
1220 *		options	- Options from command line
1221 * OUTPUT:	ep	- Error information
1222 * RETURNS:	0 on success and -1 on failure.
1223 * PURPOSE:	Common code to delete an empty hot spare pool.
1224 */
1225static int
1226meta_hsp_delete(
1227	mdsetname_t	*sp,
1228	mdhspname_t	*hspnp,
1229	mdcmdopts_t	options,
1230	md_error_t	*ep
1231)
1232{
1233	set_hs_params_t	shs;
1234
1235	/* setup hotspare pool info */
1236	(void) memset(&shs, 0, sizeof (shs));
1237	shs.shs_hot_spare_pool = hspnp->hsp;
1238	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1239	shs.shs_cmd = DELETE_HOT_SPARE;
1240	shs.shs_options = HS_OPT_POOL;
1241	/* If DOIT is not set, it's a dryrun */
1242	if ((options & MDCMD_DOIT) == 0) {
1243		shs.shs_options |= HS_OPT_DRYRUN;
1244	}
1245
1246	/* Remove hsp record. */
1247	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
1248	    hspnp->hspname) != 0)
1249		return (mdstealerror(ep, &shs.mde));
1250
1251	/* Get rid of hsp NM records */
1252	if ((options & MDCMD_DOIT) &&
1253		(del_hsp_keys(sp, hspnp->hsp, ep) == -1)) {
1254		return (-1);
1255	}
1256	return (0);
1257}
1258
1259/*
1260 * delete hotspares from pool
1261 */
1262int
1263meta_hs_delete(
1264	mdsetname_t	*sp,
1265	mdhspname_t	*hspnp,
1266	mdnamelist_t	*hsnlp,
1267	mdcmdopts_t	options,
1268	md_error_t	*ep
1269)
1270{
1271	mdnamelist_t	*p;
1272	set_hs_params_t	shs;
1273
1274	/* should have a set */
1275	assert(sp != NULL);
1276	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1277
1278	/* clear cache */
1279	meta_invalidate_hsp(hspnp);
1280
1281	/* setup hotspare pool info */
1282	(void) memset(&shs, 0, sizeof (shs));
1283	shs.shs_hot_spare_pool = hspnp->hsp;
1284	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1285	shs.shs_cmd = DELETE_HOT_SPARE;
1286
1287	/* delete empty hotspare pool */
1288	if (hsnlp == NULL) {
1289		if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
1290			return (-1);
1291		goto success;
1292	}
1293
1294	/* delete hotspares */
1295	shs.shs_options = HS_OPT_NONE;
1296	/* If DOIT is not set, it's a dryrun */
1297	if ((options & MDCMD_DOIT) == 0) {
1298		shs.shs_options |= HS_OPT_DRYRUN;
1299	}
1300	for (p = hsnlp; (p != NULL); p = p->next) {
1301		mdname_t	*hsnp = p->namep;
1302
1303		/* should be in same set */
1304		assert(hspnp->hsp == MD_HSP_NONE ||
1305		    sp->setno == HSP_SET(hspnp->hsp));
1306
1307		/* delete hotspare */
1308		shs.shs_component_old = hsnp->dev;
1309		meta_invalidate_name(hsnp);
1310		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0)
1311			return (mdstealerror(ep, &shs.mde));
1312	}
1313
1314	/* print success message */
1315success:
1316	if (options & MDCMD_PRINT) {
1317		if (hsnlp == NULL) {
1318			(void) printf(dgettext(TEXT_DOMAIN,
1319			    "%s: Hotspare pool is cleared\n"),
1320			    hspnp->hspname);
1321		} else if (hsnlp->next == NULL) {
1322			(void) printf(dgettext(TEXT_DOMAIN,
1323			    "%s: Hotspare is deleted\n"),
1324			    hspnp->hspname);
1325		} else {
1326			(void) printf(dgettext(TEXT_DOMAIN,
1327			    "%s: Hotspares are deleted\n"),
1328			    hspnp->hspname);
1329		}
1330		(void) fflush(stdout);
1331	}
1332
1333	/* return success */
1334	return (0);
1335}
1336
1337/*
1338 * replace hotspare in pool
1339 */
1340int
1341meta_hs_replace(
1342	mdsetname_t	*sp,
1343	mdhspname_t	*hspnp,
1344	mdname_t	*oldnp,
1345	mdname_t	*newnp,
1346	mdcmdopts_t	options,
1347	md_error_t	*ep
1348)
1349{
1350	set_hs_params_t	shs;
1351	diskaddr_t	size, label, start_blk;
1352	md_dev64_t	old_dev, new_dev;
1353	diskaddr_t	new_start_blk, new_end_blk;
1354	int		rebind;
1355	char		*new_devidp = NULL;
1356	int		ret;
1357	md_set_desc	*sd;
1358
1359	/* should be in same set */
1360	assert(sp != NULL);
1361	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1362
1363	/* save new binding incase this is a rebind where oldnp==newnp */
1364	new_dev = newnp->dev;
1365	new_start_blk = newnp->start_blk;
1366	new_end_blk = newnp->end_blk;
1367
1368	/* invalidate, then get the hotspare (fill in oldnp from metadb) */
1369	meta_invalidate_hsp(hspnp);
1370	if (meta_get_hsp(sp, hspnp, ep) == NULL)
1371		return (-1);
1372
1373	/* the old device binding is now established */
1374	if ((old_dev = oldnp->dev) == NODEV64)
1375		return (mdsyserror(ep, ENODEV, oldnp->cname));
1376
1377	/*
1378	 * check for the case where oldnp and newnp indicate the same
1379	 * device, but the dev_t of the device has changed between old
1380	 * and new.  This is called a rebind.  On entry the dev_t
1381	 * represents the new device binding determined from the
1382	 * filesystem (meta_getdev). After calling meta_get_hsp
1383	 * oldnp (and maybe newnp if this is a rebind) is updated based
1384	 * to the old binding from the metadb (done by metakeyname).
1385	 */
1386	if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
1387	    (old_dev != new_dev)) {
1388		rebind = 1;
1389	} else {
1390		rebind = 0;
1391	}
1392	if (rebind) {
1393		newnp->dev = new_dev;
1394		newnp->start_blk = new_start_blk;
1395		newnp->end_blk = new_end_blk;
1396	}
1397
1398	/*
1399	 * Save a copy of the devid associated with the new disk, the reason
1400	 * is that the meta_check_hotspare() call could cause the devid to
1401	 * be changed to that of the devid that is currently stored in the
1402	 * replica namespace for the disk in question. This devid could be
1403	 * stale if we are replacing the disk. The function that overwrites
1404	 * the devid is dr2drivedesc().
1405	 */
1406	if (newnp->drivenamep->devid != NULL)
1407		new_devidp = Strdup(newnp->drivenamep->devid);
1408
1409	/* if it's a multi-node diskset clear new_devidp */
1410	if (!metaislocalset(sp)) {
1411		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1412			Free(new_devidp);
1413			return (-1);
1414		}
1415		if (MD_MNSET_DESC(sd)) {
1416			Free(new_devidp);
1417			new_devidp = NULL;
1418		}
1419	}
1420
1421	/* check it out */
1422	if (meta_check_hotspare(sp, newnp, ep) != 0) {
1423		if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
1424			Free(new_devidp);
1425			return (-1);
1426		}
1427		mdclrerror(ep);
1428	}
1429	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
1430		Free(new_devidp);
1431		return (-1);
1432	}
1433	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
1434		Free(new_devidp);
1435		return (-1);
1436	}
1437	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
1438		Free(new_devidp);
1439		return (-1);
1440	}
1441	if (start_blk >= size) {
1442		(void) mdsyserror(ep, ENOSPC, newnp->cname);
1443		Free(new_devidp);
1444		return (-1);
1445	}
1446
1447	/*
1448	 * Copy back the saved devid.
1449	 */
1450	Free(newnp->drivenamep->devid);
1451	if (new_devidp != NULL) {
1452		newnp->drivenamep->devid = new_devidp;
1453		new_devidp = NULL;
1454	}
1455
1456	/* In dryrun mode (DOIT not set) we must not alter the mddb */
1457	if (options & MDCMD_DOIT) {
1458		/* store name in namespace */
1459		if (add_key_name(sp, newnp, NULL, ep) != 0)
1460			return (-1);
1461	}
1462
1463	if (rebind && !metaislocalset(sp)) {
1464		/*
1465		 * We are 'rebind'ing a disk that is in a diskset so as well
1466		 * as updating the diskset's namespace the local set needs
1467		 * to be updated because it also contains a reference to the
1468		 * disk in question.
1469		 */
1470		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
1471		    ep);
1472
1473		if (ret != METADEVADM_SUCCESS) {
1474			md_error_t	xep = mdnullerror;
1475
1476			/*
1477			 * In dryrun mode (DOIT not set) we must not alter
1478			 * the mddb
1479			 */
1480			if (options & MDCMD_DOIT) {
1481				(void) del_key_name(sp, newnp, &xep);
1482				mdclrerror(&xep);
1483				return (-1);
1484			}
1485		}
1486	}
1487
1488	/* replace hotspare */
1489	(void) memset(&shs, 0, sizeof (shs));
1490
1491	shs.shs_size_option = meta_check_devicesize(size);
1492
1493	shs.shs_cmd = REPLACE_HOT_SPARE;
1494	shs.shs_hot_spare_pool = hspnp->hsp;
1495	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1496	shs.shs_component_old = old_dev;
1497	shs.shs_options = HS_OPT_NONE;
1498	/* If DOIT is not set, it's a dryrun */
1499	if ((options & MDCMD_DOIT) == 0) {
1500		shs.shs_options |= HS_OPT_DRYRUN;
1501	}
1502	shs.shs_component_new = new_dev;
1503	shs.shs_start_blk = start_blk;
1504	shs.shs_has_label = ((label > 0) ? 1 : 0);
1505	shs.shs_number_blks = size;
1506	shs.shs_key_new = newnp->key;
1507	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1508		if (options & MDCMD_DOIT) {
1509			(void) del_key_name(sp, newnp, ep);
1510		}
1511		return (mdstealerror(ep, &shs.mde));
1512	}
1513
1514	/* clear cache */
1515	meta_invalidate_name(oldnp);
1516	meta_invalidate_name(newnp);
1517	meta_invalidate_hsp(hspnp);
1518
1519	/* let em know */
1520	if (options & MDCMD_PRINT) {
1521		(void) printf(dgettext(TEXT_DOMAIN,
1522		    "%s: Hotspare %s is replaced with %s\n"),
1523		    hspnp->hspname, oldnp->cname, newnp->cname);
1524		(void) fflush(stdout);
1525	}
1526
1527	/* return success */
1528	return (0);
1529}
1530
1531/*
1532 * enable hotspares
1533 */
1534int
1535meta_hs_enable(
1536	mdsetname_t	*sp,
1537	mdnamelist_t	*hsnlp,
1538	mdcmdopts_t	options,
1539	md_error_t	*ep
1540)
1541{
1542	mdhspnamelist_t	*hspnlp = NULL;
1543	mdhspnamelist_t	*hspnp;
1544	set_hs_params_t	shs;
1545	int		rval = -1;
1546
1547	/* should have a set */
1548	assert(sp != NULL);
1549
1550	/* setup device info */
1551	(void) memset(&shs, 0, sizeof (shs));
1552	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1553	shs.shs_cmd = FIX_HOT_SPARE;
1554	shs.shs_options = HS_OPT_NONE;
1555	/* If DOIT is not set, it's a dryrun */
1556	if ((options & MDCMD_DOIT) == 0) {
1557		shs.shs_options |= HS_OPT_DRYRUN;
1558	}
1559
1560	/* get the list of hotspare names */
1561	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1562		goto out;
1563
1564	/* enable hotspares for each components */
1565	for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
1566		mdname_t	*hsnp = hsnlp->namep;
1567		md_dev64_t	fs_dev;
1568		int		rebind = 0;
1569		diskaddr_t	size, label, start_blk;
1570
1571		/* get the file_system dev binding */
1572		if (meta_getdev(sp, hsnp, ep) != 0)
1573			return (-1);
1574		fs_dev = hsnp->dev;
1575
1576		/*
1577		 * search for the component in each hotspare pool
1578		 * and replace it (instead of enable) if the binding
1579		 * has changed.
1580		 */
1581		for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1582			/*
1583			 * in_hsp will call meta_get_hsp which will fill
1584			 * in hspnp with metadb version of component
1585			 */
1586			meta_invalidate_hsp(hspnp->hspnamep);
1587			if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
1588				/*
1589				 * check for the case where the dev_t has
1590				 * changed between the filesystem and the
1591				 * metadb.  This is called a rebind, and
1592				 * is handled by meta_hs_replace.
1593				 */
1594				if (fs_dev != hsnp->dev) {
1595					/*
1596					 * establish file system binding
1597					 * with invalid start/end
1598					 */
1599					rebind++;
1600					hsnp->dev = fs_dev;
1601					hsnp->start_blk = -1;
1602					hsnp->end_blk = -1;
1603					rval = meta_hs_replace(sp,
1604					    hspnp->hspnamep,
1605					    hsnp, hsnp, options, ep);
1606					if (rval != 0)
1607						goto out;
1608				}
1609			}
1610		}
1611		if (rebind)
1612			continue;
1613
1614		/* enable the component in all hotspares that use it */
1615		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1616			goto out;
1617
1618		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
1619			goto out;
1620		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
1621			goto out;
1622		if ((start_blk = metagetstart(sp, hsnp, ep))
1623		    == MD_DISKADDR_ERROR)
1624			goto out;
1625		if (start_blk >= size) {
1626			(void) mdsyserror(ep, ENOSPC, hsnp->cname);
1627			goto out;
1628		}
1629
1630		/* enable hotspare */
1631		shs.shs_component_old = hsnp->dev;
1632		shs.shs_component_new = hsnp->dev;
1633		shs.shs_start_blk = start_blk;
1634		shs.shs_has_label = ((label > 0) ? 1 : 0);
1635		shs.shs_number_blks = size;
1636		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
1637			rval = mdstealerror(ep, &shs.mde);
1638			goto out;
1639		}
1640
1641		/*
1642		 * Are we dealing with a non-local set? If so need to update
1643		 * the local namespace so that the disk record has the correct
1644		 * devid.
1645		 */
1646		if (!metaislocalset(sp)) {
1647			rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
1648			    hsnp->cname, ep);
1649
1650			if (rval != METADEVADM_SUCCESS) {
1651				/*
1652				 * Failed to update the local set. Nothing to
1653				 * do here apart from report the error. The
1654				 * namespace is most likely broken and some
1655				 * form of remedial recovery is going to
1656				 * be required.
1657				 */
1658				mde_perror(ep, "");
1659				mdclrerror(ep);
1660			}
1661		}
1662
1663		/* clear cache */
1664		meta_invalidate_name(hsnp);
1665
1666		/* let em know */
1667		if (options & MDCMD_PRINT) {
1668			(void) printf(dgettext(TEXT_DOMAIN,
1669			    "hotspare %s is enabled\n"),
1670			    hsnp->cname);
1671			(void) fflush(stdout);
1672		}
1673	}
1674
1675	/* clear whole cache */
1676	for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1677		meta_invalidate_hsp(hspnp->hspnamep);
1678	}
1679
1680
1681	/* return success */
1682	rval = 0;
1683
1684out:
1685	if (hspnlp)
1686		metafreehspnamelist(hspnlp);
1687	return (rval);
1688}
1689
1690/*
1691 * check for dups in the hsp itself
1692 */
1693static int
1694check_twice(
1695	md_hsp_t	*hspp,
1696	uint_t		hsi,
1697	md_error_t	*ep
1698)
1699{
1700	mdhspname_t	*hspnp = hspp->hspnamep;
1701	mdname_t	*thisnp;
1702	uint_t		h;
1703
1704	thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
1705	for (h = 0; (h < hsi); ++h) {
1706		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[h];
1707		mdname_t	*hsnp = hsp->hsnamep;
1708
1709		if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
1710		    hsnp, 0, -1, ep) != 0)
1711			return (-1);
1712	}
1713	return (0);
1714}
1715
1716/*
1717 * check hsp
1718 */
1719/*ARGSUSED2*/
1720int
1721meta_check_hsp(
1722	mdsetname_t	*sp,
1723	md_hsp_t	*hspp,
1724	mdcmdopts_t	options,
1725	md_error_t	*ep
1726)
1727{
1728	mdhspname_t	*hspnp = hspp->hspnamep;
1729	uint_t		hsi;
1730
1731	/* check hotspares */
1732	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1733		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1734		mdname_t	*hsnp = hsp->hsnamep;
1735		diskaddr_t	size;
1736
1737		/* check hotspare */
1738		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1739			return (-1);
1740		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
1741			return (-1);
1742		} else if (size == 0) {
1743			return (mdsyserror(ep, ENOSPC, hspnp->hspname));
1744		}
1745
1746		/* check this hsp too */
1747		if (check_twice(hspp, hsi, ep) != 0)
1748			return (-1);
1749	}
1750
1751	/* return success */
1752	return (0);
1753}
1754
1755/*
1756 * create hsp
1757 */
1758int
1759meta_create_hsp(
1760	mdsetname_t	*sp,
1761	md_hsp_t	*hspp,
1762	mdcmdopts_t	options,
1763	md_error_t	*ep
1764)
1765{
1766	mdhspname_t	*hspnp = hspp->hspnamep;
1767	mdnamelist_t	*hsnlp = NULL;
1768	uint_t		hsi;
1769	int		rval = -1;
1770
1771	/* validate hsp */
1772	if (meta_check_hsp(sp, hspp, options, ep) != 0)
1773		return (-1);
1774
1775	/* if we're not doing anything, return success */
1776	if (! (options & MDCMD_DOIT))
1777		return (0);
1778
1779	/* create hsp */
1780	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1781		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1782		mdname_t	*hsnp = hsp->hsnamep;
1783
1784		(void) metanamelist_append(&hsnlp, hsnp);
1785	}
1786	options |= MDCMD_INIT;
1787	rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
1788
1789	/* cleanup, return success */
1790	metafreenamelist(hsnlp);
1791	return (rval);
1792}
1793
1794/*
1795 * initialize hsp
1796 * NOTE: this functions is metainit(1m)'s command line parser!
1797 */
1798int
1799meta_init_hsp(
1800	mdsetname_t	**spp,
1801	int		argc,
1802	char		*argv[],
1803	mdcmdopts_t	options,
1804	md_error_t	*ep
1805)
1806{
1807	char		*uname = argv[0];
1808	mdhspname_t	*hspnp = NULL;
1809	md_hsp_t	*hspp = NULL;
1810	uint_t		hsi;
1811	int		rval = -1;
1812
1813
1814	/* get hsp name */
1815	assert(argc > 0);
1816	if (argc < 1)
1817		goto syntax;
1818	if ((hspnp = metahspname(spp, uname, ep)) == NULL)
1819		goto out;
1820	assert(*spp != NULL);
1821	uname = hspnp->hspname;
1822
1823	if (!(options & MDCMD_NOLOCK)) {
1824		/* grab set lock */
1825		if (meta_lock(*spp, TRUE, ep))
1826			goto out;
1827
1828		if (meta_check_ownership(*spp, ep) != 0)
1829			goto out;
1830	}
1831
1832	/* see if it exists already */
1833	if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
1834		(void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP,
1835		    hspnp->hsp, uname);
1836		goto out;
1837	} else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
1838		goto out;
1839	} else {
1840		mdclrerror(ep);
1841	}
1842	--argc, ++argv;
1843
1844	/* parse general options */
1845	optind = 0;
1846	opterr = 0;
1847	if (getopt(argc, argv, "") != -1)
1848		goto options;
1849
1850	/* allocate hsp */
1851	hspp = Zalloc(sizeof (*hspp));
1852	hspp->hotspares.hotspares_len = argc;
1853	if (argc > 0) {
1854		hspp->hotspares.hotspares_val =
1855		    Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
1856	}
1857
1858	/* setup pool */
1859	hspp->hspnamep = hspnp;
1860
1861	/* parse hotspares */
1862	for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
1863	    ++hsi) {
1864		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1865		mdname_t	*hsnamep;
1866
1867		/* parse hotspare name */
1868		if ((hsnamep = metaname(spp, argv[0],
1869		    LOGICAL_DEVICE, ep)) == NULL)
1870			goto out;
1871		hsp->hsnamep = hsnamep;
1872		--argc, ++argv;
1873	}
1874
1875	/* we should be at the end */
1876	if (argc != 0)
1877		goto syntax;
1878
1879	/* create hotspare pool */
1880	if (meta_create_hsp(*spp, hspp, options, ep) != 0)
1881		goto out;
1882	rval = 0;	/* success */
1883	goto out;
1884
1885	/* syntax error */
1886syntax:
1887	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
1888	goto out;
1889
1890	/* options error */
1891options:
1892	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
1893	goto out;
1894
1895	/* cleanup, return error */
1896out:
1897	if (hspp != NULL)
1898		meta_free_hsp(hspp);
1899	return (rval);
1900}
1901
1902/*
1903 * reset hotspare pool
1904 */
1905int
1906meta_hsp_reset(
1907	mdsetname_t	*sp,
1908	mdhspname_t	*hspnp,
1909	mdcmdopts_t	options,
1910	md_error_t	*ep
1911)
1912{
1913	md_hsp_t	*hspp;
1914	set_hs_params_t	shs;
1915	uint_t		i;
1916	int		rval = -1;
1917
1918	/* should have the same set */
1919	assert(sp != NULL);
1920	assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
1921	    sp->setno == HSP_SET(hspnp->hsp));
1922
1923	/* reset all hotspares */
1924	if (hspnp == NULL) {
1925		mdhspnamelist_t	*hspnlp = NULL;
1926		mdhspnamelist_t	*p;
1927
1928		/* for each hotspare pool */
1929		rval = 0;
1930		if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1931			return (-1);
1932		for (p = hspnlp; (p != NULL); p = p->next) {
1933			/* reset hotspare pool */
1934			hspnp = p->hspnamep;
1935
1936			/*
1937			 * If this is a multi-node set, we send a series
1938			 * of individual metaclear commands.
1939			 */
1940			if (meta_is_mn_set(sp, ep)) {
1941				if (meta_mn_send_metaclear_command(sp,
1942				    hspnp->hspname, options, 0, ep) != 0) {
1943					rval = -1;
1944					break;
1945				}
1946			} else {
1947				if (meta_hsp_reset(sp, hspnp, options,
1948				    ep) != 0) {
1949					rval = -1;
1950					break;
1951				}
1952			}
1953		}
1954
1955		/* cleanup, return success */
1956		metafreehspnamelist(hspnlp);
1957		return (rval);
1958	}
1959
1960	/* get unit structure */
1961	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
1962		return (-1);
1963
1964	/* make sure nobody owns us */
1965	if (hspp->refcount > 0) {
1966		return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
1967		    hspnp->hspname));
1968	}
1969
1970	/* clear hotspare pool members */
1971	(void) memset(&shs, 0, sizeof (shs));
1972	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1973	shs.shs_cmd = DELETE_HOT_SPARE;
1974	shs.shs_hot_spare_pool = hspnp->hsp;
1975	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
1976		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
1977		mdname_t	*hsnamep = hs->hsnamep;
1978
1979		/* clear cache */
1980		meta_invalidate_name(hsnamep);
1981
1982		/* clear hotspare */
1983		shs.shs_component_old = hsnamep->dev;
1984		shs.shs_options = HS_OPT_FORCE;
1985		/* If DOIT is not set, it's a dryrun */
1986		if ((options & MDCMD_DOIT) == 0) {
1987			shs.shs_options |= HS_OPT_DRYRUN;
1988		}
1989		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1990			(void) mdstealerror(ep, &shs.mde);
1991			goto out;
1992		}
1993	}
1994
1995	/* clear hotspare pool */
1996	if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
1997		goto out;
1998	rval = 0;	/* success */
1999
2000	/* let em know */
2001	if (options & MDCMD_PRINT) {
2002		(void) printf(dgettext(TEXT_DOMAIN,
2003		    "%s: Hotspare pool is cleared\n"),
2004		    hspnp->hspname);
2005		(void) fflush(stdout);
2006	}
2007
2008	/* clear subdevices (nothing to do) */
2009
2010	/* cleanup, return success */
2011out:
2012	meta_invalidate_hsp(hspnp);
2013	return (rval);
2014}
2015