xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_hotspares.c (revision 8c777d354122faf889cbe261581bb4974f2b8e4d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Just in case we're not in a build environment, make sure that
31  * TEXT_DOMAIN gets set to something.
32  */
33 #if !defined(TEXT_DOMAIN)
34 #define	TEXT_DOMAIN "SYS_TEST"
35 #endif
36 
37 /*
38  * hotspares utilities
39  */
40 
41 #include <meta.h>
42 #include <sys/lvm/md_hotspares.h>
43 #include <sys/lvm/md_convert.h>
44 
45 
46 /*
47  * FUNCTION:	meta_get_hsp_names()
48  * INPUT:	sp	- the set name to get hotspares from
49  *		options	- options from the command line
50  * OUTPUT:	hspnlpp	- list of all hotspare names
51  *		ep	- return error pointer
52  * RETURNS:	int	- -1 if error, 0 success
53  * PURPOSE:	returns a list of all hotspares in the metadb
54  *		for all devices in the specified set
55  */
56 /*ARGSUSED*/
57 int
58 meta_get_hsp_names(
59 	mdsetname_t	*sp,
60 	mdhspnamelist_t	**hspnlpp,
61 	int		options,
62 	md_error_t	*ep
63 )
64 {
65 	md_i_getnum_t	gn;		/* MD_IOCGET_NUM params */
66 	minor_t		*minors = NULL;
67 	minor_t		*m_ptr;
68 	int		i;
69 
70 	/* we must have a set */
71 	assert(sp != NULL);
72 
73 	(void) memset(&gn, 0, sizeof (gn));
74 	MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno);
75 
76 	/* get number of devices */
77 	if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
78 		if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
79 			mdclrerror(&gn.mde);
80 		} else {
81 			(void) mdstealerror(ep, &gn.mde);
82 			return (-1);
83 		}
84 	}
85 
86 	if (gn.size > 0) {
87 		/* malloc minor number buffer to be filled by ioctl */
88 		if ((minors = (minor_t *)malloc(
89 				gn.size * sizeof (minor_t))) == 0) {
90 			return (ENOMEM);
91 		}
92 		gn.minors = (uintptr_t)minors;
93 		if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
94 			(void) mdstealerror(ep, &gn.mde);
95 			free(minors);
96 			return (-1);
97 		}
98 		m_ptr = minors;
99 		for (i = 0; i < gn.size; i++) {
100 			mdhspname_t	*hspnp;
101 
102 
103 			/* get name */
104 			if ((hspnp = metahsphspname(&sp, *m_ptr, ep))
105 					== NULL)
106 				goto out;
107 
108 			/* append to list */
109 			(void) metahspnamelist_append(hspnlpp, hspnp);
110 
111 			/* next device */
112 			m_ptr++;
113 		}
114 		free(minors);
115 	}
116 	return (gn.size);
117 
118 out:
119 	if (minors != NULL)
120 		free(minors);
121 	metafreehspnamelist(*hspnlpp);
122 	*hspnlpp = NULL;
123 	return (-1);
124 }
125 
126 /*
127  * get information of a specific hotspare pool from driver
128  */
129 static get_hsp_t *
130 get_hspinfo(
131 	mdsetname_t	*sp,
132 	mdhspname_t	*hspnp,
133 	md_error_t	*ep
134 )
135 {
136 	md_i_get_t	mig;
137 
138 	/* should have a set */
139 	assert(sp != NULL);
140 	assert(sp->setno == HSP_SET(hspnp->hsp));
141 
142 	/* get size of unit structure */
143 	(void) memset(&mig, 0, sizeof (mig));
144 	MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno);
145 	mig.id = hspnp->hsp;
146 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
147 		(void) mdstealerror(ep, &mig.mde);
148 		return (NULL);
149 	}
150 
151 	/* get actual unit structure */
152 	assert(mig.size > 0);
153 	mig.mdp = (uintptr_t)Zalloc(mig.size);
154 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
155 		(void) mdstealerror(ep, &mig.mde);
156 		Free((void *)(uintptr_t)mig.mdp);
157 		return (NULL);
158 	}
159 	return ((get_hsp_t *)(uintptr_t)mig.mdp);
160 }
161 
162 /*
163  * free hotspare pool unit
164  */
165 void
166 meta_free_hsp(
167 	md_hsp_t	*hspp
168 )
169 {
170 	if (hspp->hotspares.hotspares_val != NULL) {
171 		assert(hspp->hotspares.hotspares_len > 0);
172 		Free(hspp->hotspares.hotspares_val);
173 	}
174 	Free(hspp);
175 }
176 
177 /*
178  * get hotspare pool unit (common)
179  */
180 md_hsp_t *
181 meta_get_hsp_common(
182 	mdsetname_t	*sp,
183 	mdhspname_t	*hspnp,
184 	int		fast,
185 	md_error_t	*ep
186 )
187 {
188 	get_hsp_t	*ghsp;
189 	md_hsp_t	*hspp;
190 	uint_t		hsi;
191 
192 	/* must have set */
193 	assert(sp != NULL);
194 	assert(sp->setno == HSP_SET(hspnp->hsp));
195 
196 	/* short circuit */
197 	if (hspnp->unitp != NULL)
198 		return (hspnp->unitp);
199 
200 	/* get unit */
201 	if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL)
202 		return (NULL);
203 
204 	/* allocate hsp */
205 	hspp = Zalloc(sizeof (*hspp));
206 
207 	/* allocate hotspares */
208 	hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares;
209 
210 	/* if empty hotspare pool, we are done */
211 	if (hspp->hotspares.hotspares_len != 0)
212 		hspp->hotspares.hotspares_val =
213 		    Zalloc(hspp->hotspares.hotspares_len *
214 		    sizeof (*hspp->hotspares.hotspares_val));
215 
216 	/* get name, refcount */
217 	hspp->hspnamep = hspnp;
218 	hspp->refcount = ghsp->ghsp_refcount;
219 
220 	/* get hotspares */
221 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
222 		mdkey_t		hs_key = ghsp->ghsp_hs_keys[hsi];
223 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
224 		get_hs_params_t	ghs;
225 
226 		/* get hotspare name */
227 		hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep);
228 		if (hsp->hsnamep == NULL)
229 			goto out;
230 
231 		/* get hotspare state */
232 		(void) memset(&ghs, 0, sizeof (ghs));
233 		MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno);
234 		ghs.ghs_key = hs_key;
235 		if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) {
236 			(void) mdstealerror(ep, &ghs.mde);
237 			goto out;
238 		}
239 		hsp->state = ghs.ghs_state;
240 		hsp->size = ghs.ghs_number_blks;
241 		hsp->timestamp = ghs.ghs_timestamp;
242 		hsp->revision = ghs.ghs_revision;
243 	}
244 
245 	/* cleanup, return success */
246 	Free(ghsp);
247 	hspnp->unitp = hspp;
248 	return (hspp);
249 
250 	/* cleanup, return error */
251 out:
252 	Free(ghsp);
253 	meta_free_hsp(hspp);
254 	return (NULL);
255 }
256 
257 /*
258  * get hotspare pool unit
259  */
260 md_hsp_t *
261 meta_get_hsp(
262 	mdsetname_t	*sp,
263 	mdhspname_t	*hspnp,
264 	md_error_t	*ep
265 )
266 {
267 	return (meta_get_hsp_common(sp, hspnp, 0, ep));
268 }
269 
270 /*
271  * check hotspare pool for dev
272  */
273 static int
274 in_hsp(
275 	mdsetname_t	*sp,
276 	mdhspname_t	*hspnp,
277 	mdname_t	*np,
278 	diskaddr_t	slblk,
279 	diskaddr_t	nblks,
280 	md_error_t	*ep
281 )
282 {
283 	md_hsp_t	*hspp;
284 	uint_t		i;
285 
286 	/* should be in the same set */
287 	assert(sp != NULL);
288 	assert(sp->setno == HSP_SET(hspnp->hsp));
289 
290 	/* get unit */
291 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
292 		return (-1);
293 
294 	/* look in hotspares */
295 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
296 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
297 		mdname_t	*hsnp = hs->hsnamep;
298 
299 		/* check overlap */
300 		if (metaismeta(hsnp))
301 			continue;
302 		if (meta_check_overlap(hspnp->hspname, np, slblk, nblks,
303 		    hsnp, 0, -1, ep) != 0)
304 			return (-1);
305 	}
306 
307 	/* return success */
308 	return (0);
309 }
310 
311 /*
312  * check to see if we're in a hotspare pool
313  */
314 int
315 meta_check_inhsp(
316 	mdsetname_t	*sp,
317 	mdname_t	*np,
318 	diskaddr_t	slblk,
319 	diskaddr_t	nblks,
320 	md_error_t	*ep
321 )
322 {
323 	mdhspnamelist_t	*hspnlp = NULL;
324 	mdhspnamelist_t	*p;
325 	int		rval = 0;
326 
327 	/* should have a set */
328 	assert(sp != NULL);
329 
330 	/* for each hotspare pool */
331 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
332 		return (-1);
333 	for (p = hspnlp; (p != NULL); p = p->next) {
334 		mdhspname_t	*hspnp = p->hspnamep;
335 
336 		/* check hotspare pool */
337 		if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) {
338 			rval = -1;
339 			break;
340 		}
341 	}
342 
343 	/* cleanup, return success */
344 	metafreehspnamelist(hspnlp);
345 	return (rval);
346 }
347 
348 /*
349  * check hotspare
350  */
351 int
352 meta_check_hotspare(
353 	mdsetname_t	*sp,
354 	mdname_t	*np,
355 	md_error_t	*ep
356 )
357 {
358 	mdchkopts_t	options = (MDCHK_ALLOW_HS);
359 
360 	/* make sure we have a disk */
361 	if (metachkcomp(np, ep) != 0)
362 		return (-1);
363 
364 	/* check to ensure that it is not already in use */
365 	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
366 		return (-1);
367 	}
368 
369 	/* make sure it is in the set */
370 	if (meta_check_inset(sp, np, ep) != 0)
371 		return (-1);
372 
373 	/* make sure its not in a metadevice */
374 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
375 		return (-1);
376 
377 	/* return success */
378 	return (0);
379 }
380 
381 /*
382  * print hsp
383  */
384 static int
385 hsp_print(
386 	md_hsp_t	*hspp,
387 	char		*fname,
388 	FILE		*fp,
389 	md_error_t	*ep
390 )
391 {
392 	uint_t		hsi;
393 	int		rval = -1;
394 
395 	/* print name */
396 	if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF)
397 		goto out;
398 
399 	/* print hotspares */
400 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
401 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
402 
403 		/* print hotspare */
404 		/*
405 		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
406 		 * then just print out the cxtxdxsx or the dx, metainit
407 		 * will assume the default, otherwise we need the full
408 		 * pathname to make sure this works as we intend.
409 		 */
410 		if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) &&
411 		    (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) &&
412 		    (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) {
413 			/* not standard path, print full pathname */
414 			if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF)
415 				goto out;
416 		} else {
417 			/* standard path, just print ctd or d value */
418 			if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF)
419 				goto out;
420 		}
421 	}
422 
423 	/* terminate last line */
424 	if (fprintf(fp, "\n") == EOF)
425 		goto out;
426 
427 	/* success */
428 	rval = 0;
429 
430 	/* cleanup, return error */
431 out:
432 	if (rval != 0)
433 		(void) mdsyserror(ep, errno, fname);
434 	return (rval);
435 }
436 
437 /*
438  * hotspare state name
439  */
440 char *
441 hs_state_to_name(
442 	md_hs_t			*hsp,
443 	md_timeval32_t		*tvp
444 )
445 {
446 	hotspare_states_t	state = hsp->state;
447 
448 	/* grab time */
449 	if (tvp != NULL)
450 		*tvp = hsp->timestamp;
451 
452 	switch (state) {
453 	case HSS_AVAILABLE:
454 		return (dgettext(TEXT_DOMAIN, "Available"));
455 	case HSS_RESERVED:
456 		return (dgettext(TEXT_DOMAIN, "In use"));
457 	case HSS_BROKEN:
458 		return (dgettext(TEXT_DOMAIN, "Broken"));
459 	case HSS_UNUSED:
460 	default:
461 		return (dgettext(TEXT_DOMAIN, "invalid"));
462 	}
463 }
464 
465 /*
466  * report hsp
467  */
468 static int
469 hsp_report(
470 	md_hsp_t	*hspp,
471 	mdnamelist_t	**nlpp,
472 	char		*fname,
473 	FILE		*fp,
474 	mdprtopts_t	options,
475 	md_error_t	*ep,
476 	mdsetname_t	*sp
477 )
478 {
479 	uint_t		hsi;
480 	int		rval = -1;
481 	char		*devid = "";
482 	mdname_t	*didnp = NULL;
483 	uint_t		len;
484 	int		large_hs_dev_cnt = 0;
485 
486 	if (options & PRINT_LARGEDEVICES) {
487 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
488 			md_hs_t	*hsp = &hspp->hotspares.hotspares_val[hsi];
489 			if (hsp->revision == MD_64BIT_META_DEV) {
490 				large_hs_dev_cnt += 1;
491 				if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
492 				    != 0)
493 					goto out;
494 			}
495 		}
496 
497 		if (large_hs_dev_cnt == 0) {
498 			rval = 0;
499 			goto out;
500 		}
501 	}
502 	/* print header */
503 	if (hspp->hotspares.hotspares_len == 0) {
504 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"),
505 		    hspp->hspnamep->hspname) == EOF) {
506 			goto out;
507 		}
508 	} else if (hspp->hotspares.hotspares_len == 1) {
509 
510 		/*
511 		 * This allows the length
512 		 * of the ctd to vary from small to large without
513 		 * looking horrible.
514 		 */
515 
516 		len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname);
517 		/*
518 		 * if the length is to short to print out all of the header
519 		 * force the matter
520 		 */
521 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
522 		len += 2;
523 		if (options & PRINT_LARGEDEVICES) {
524 			if (fprintf(fp,
525 			    "%s: 1 hot spare (1 big device)\n\t%-*.*s  "
526 			    "%-12.12s%-8.6s\t\t%s\n",
527 			    hspp->hspnamep->hspname, len, len,
528 			    dgettext(TEXT_DOMAIN, "Device"),
529 			    dgettext(TEXT_DOMAIN, "Status"),
530 			    dgettext(TEXT_DOMAIN, "Length"),
531 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
532 				goto out;
533 			}
534 		} else {
535 			if (fprintf(fp,
536 			    "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n",
537 			    hspp->hspnamep->hspname, len, len,
538 			    dgettext(TEXT_DOMAIN, "Device"),
539 			    dgettext(TEXT_DOMAIN, "Status"),
540 			    dgettext(TEXT_DOMAIN, "Length"),
541 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
542 				goto out;
543 			}
544 		}
545 	} else {
546 		/*
547 		 * This allows the length
548 		 * of the ctd to vary from small to large without
549 		 * looking horrible.
550 		 */
551 		len = 0;
552 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
553 			len = max(len, strlen(hspp->
554 			    hotspares.hotspares_val[hsi].hsnamep->cname));
555 		}
556 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
557 		len += 2;
558 		if (options & PRINT_LARGEDEVICES) {
559 			if (fprintf(fp,
560 			    "%s: %u hot spares (%d big device(s))\n\t%-*.*s "
561 			    "%-12.12s%-8.6s\t\t%s\n",
562 			    hspp->hspnamep->hspname,
563 			    hspp->hotspares.hotspares_len,
564 			    large_hs_dev_cnt, len, len,
565 			    dgettext(TEXT_DOMAIN, "Device"),
566 			    dgettext(TEXT_DOMAIN, "Status"),
567 			    dgettext(TEXT_DOMAIN, "Length"),
568 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
569 				goto out;
570 			}
571 		} else {
572 			if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s "
573 			    "%-12.12s%-8.6s\t\t%s\n",
574 			    hspp->hspnamep->hspname,
575 			    hspp->hotspares.hotspares_len, len, len,
576 			    dgettext(TEXT_DOMAIN, "Device"),
577 			    dgettext(TEXT_DOMAIN, "Status"),
578 			    dgettext(TEXT_DOMAIN, "Length"),
579 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
580 				goto out;
581 			}
582 		}
583 	}
584 
585 	/* print hotspares */
586 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
587 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
588 		char		*cname = hsp->hsnamep->cname;
589 		char		*hs_state;
590 		md_timeval32_t	tv;
591 		char		*timep;
592 		ddi_devid_t	dtp;
593 
594 		/* populate the key in the name_p structure */
595 		if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) {
596 			return (-1);
597 		}
598 
599 		if (options & PRINT_LARGEDEVICES) {
600 			if (hsp->revision != MD_64BIT_META_DEV)
601 				continue;
602 		}
603 		/* determine if devid does NOT exist */
604 		if (options & PRINT_DEVID) {
605 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
606 				didnp->key, ep)) == NULL)
607 				devid = dgettext(TEXT_DOMAIN, "No ");
608 			else {
609 				devid = dgettext(TEXT_DOMAIN, "Yes");
610 				free(dtp);
611 			}
612 		}
613 		/* print hotspare */
614 		hs_state = hs_state_to_name(hsp, &tv);
615 		/*
616 		 * This allows the length
617 		 * of the ctd to vary from small to large without
618 		 * looking horrible.
619 		 */
620 		if (! (options & PRINT_TIMES)) {
621 			if (fprintf(fp,
622 			    "        %-*s %-12s %lld blocks\t%s\n",
623 			    len, cname, hs_state,
624 			    hsp->size, devid) == EOF) {
625 				goto out;
626 			}
627 		} else {
628 			timep = meta_print_time(&tv);
629 
630 			if (fprintf(fp,
631 			    "        %-*s\t    %-11s %8lld blocks%s\t%s\n",
632 			    len, cname, hs_state,
633 			    hsp->size, devid, timep) == EOF) {
634 				goto out;
635 			}
636 		}
637 	}
638 
639 	/* add extra line */
640 	if (fprintf(fp, "\n") == EOF)
641 		goto out;
642 
643 	/* success */
644 	rval = 0;
645 
646 	/* cleanup, return error */
647 out:
648 	if (rval != 0)
649 		(void) mdsyserror(ep, errno, fname);
650 	return (rval);
651 }
652 
653 /*
654  * print/report hsp
655  */
656 int
657 meta_hsp_print(
658 	mdsetname_t	*sp,
659 	mdhspname_t	*hspnp,
660 	mdnamelist_t	**nlpp,
661 	char		*fname,
662 	FILE		*fp,
663 	mdprtopts_t	options,
664 	md_error_t	*ep
665 )
666 {
667 	md_hsp_t	*hspp;
668 
669 	/* should have same set */
670 	assert(sp != NULL);
671 	assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp)));
672 
673 	/* print all hsps */
674 	if (hspnp == NULL) {
675 		mdhspnamelist_t	*hspnlp = NULL;
676 		mdhspnamelist_t	*p;
677 		int		cnt;
678 		int		rval = 0;
679 
680 		if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0)
681 			return (-1);
682 		else if (cnt == 0)
683 			return (0);
684 
685 		/* recurse */
686 		for (p = hspnlp; (p != NULL); p = p->next) {
687 			mdhspname_t	*hspnp = p->hspnamep;
688 
689 			if (meta_hsp_print(sp, hspnp, nlpp, fname, fp,
690 			    options, ep) != 0)
691 				rval = -1;
692 		}
693 
694 		/* cleanup, return success */
695 		metafreehspnamelist(hspnlp);
696 		return (rval);
697 	}
698 
699 	/* get unit structure */
700 	if ((hspp = meta_get_hsp_common(sp, hspnp,
701 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
702 		return (-1);
703 
704 	/* print appropriate detail */
705 	if (options & PRINT_SHORT)
706 		return (hsp_print(hspp, fname, fp, ep));
707 	else
708 		return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp));
709 }
710 
711 /*
712  * check for valid hotspare pool
713  */
714 int
715 metachkhsp(
716 	mdsetname_t	*sp,
717 	mdhspname_t	*hspnp,
718 	md_error_t	*ep
719 )
720 {
721 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
722 		return (-1);
723 	return (0);
724 }
725 
726 /*
727  * invalidate hotspare pool info
728  */
729 void
730 meta_invalidate_hsp(
731 	mdhspname_t	*hspnp
732 )
733 {
734 	md_hsp_t	*hspp = hspnp->unitp;
735 
736 	/* free it up */
737 	if (hspp == NULL)
738 		return;
739 	meta_free_hsp(hspp);
740 
741 	/* clear cache */
742 	hspnp->unitp = NULL;
743 }
744 
745 /*
746  * add hotspares and/or hotspare pool
747  */
748 int
749 meta_hs_add(
750 	mdsetname_t	*sp,
751 	mdhspname_t	*hspnp,
752 	mdnamelist_t	*hsnlp,
753 	mdcmdopts_t	options,
754 	md_error_t	*ep
755 )
756 {
757 	mdnamelist_t	*p;
758 	set_hs_params_t	shs;
759 
760 	/* should have a set */
761 	assert(sp != NULL);
762 	assert(sp->setno == HSP_SET(hspnp->hsp));
763 
764 	/* clear cache */
765 	meta_invalidate_hsp(hspnp);
766 
767 	/* setup hotspare pool info */
768 	(void) memset(&shs, 0, sizeof (shs));
769 	shs.shs_cmd = ADD_HOT_SPARE;
770 	shs.shs_hot_spare_pool = hspnp->hsp;
771 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
772 
773 	/* add empty hotspare pool */
774 	if (hsnlp == NULL) {
775 		shs.shs_options = HS_OPT_POOL;
776 		/* If DOIT is not set, it's a dryrun */
777 		if ((options & MDCMD_DOIT) == 0) {
778 			shs.shs_options |= HS_OPT_DRYRUN;
779 		}
780 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
781 		    hspnp->hspname) != 0)
782 			return (mdstealerror(ep, &shs.mde));
783 		goto success;
784 	}
785 
786 	/* add hotspares */
787 	shs.shs_options = HS_OPT_NONE;
788 	/* If DOIT is not set, it's a dryrun */
789 	if ((options & MDCMD_DOIT) == 0) {
790 		shs.shs_options |= HS_OPT_DRYRUN;
791 	}
792 	for (p = hsnlp; (p != NULL); p = p->next) {
793 		mdname_t	*hsnp = p->namep;
794 		diskaddr_t	size, label, start_blk;
795 
796 		/* should be in same set */
797 		assert(sp->setno == HSP_SET(hspnp->hsp));
798 
799 		/* check it out */
800 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
801 			return (-1);
802 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
803 			return (-1);
804 		else if (size == 0)
805 			return (mdsyserror(ep, ENOSPC, hsnp->cname));
806 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
807 			return (-1);
808 		if ((start_blk = metagetstart(sp, hsnp, ep))
809 		    == MD_DISKADDR_ERROR)
810 			return (-1);
811 
812 		shs.shs_size_option = meta_check_devicesize(size);
813 
814 		/* In dryrun mode (DOIT not set) we must not alter the mddb */
815 		if (options & MDCMD_DOIT) {
816 			/* store name in namespace */
817 			if (add_key_name(sp, hsnp, NULL, ep) != 0)
818 				return (-1);
819 		}
820 
821 		/* add hotspare and/or hotspare pool */
822 		shs.shs_component_old = hsnp->dev;
823 		shs.shs_start_blk = start_blk;
824 		shs.shs_has_label = ((label > 0) ? 1 : 0);
825 		shs.shs_number_blks = size;
826 		shs.shs_key_old = hsnp->key;
827 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
828 			if ((options & MDCMD_DOIT) &&
829 			    (shs.shs_options != HS_OPT_POOL)) {
830 				(void) del_key_name(sp, hsnp, ep);
831 			}
832 			return (mdstealerror(ep, &shs.mde));
833 		}
834 	}
835 
836 	/* print success message */
837 success:
838 	if (options & MDCMD_PRINT) {
839 		if ((options & MDCMD_INIT) || (hsnlp == NULL)) {
840 			(void) printf(dgettext(TEXT_DOMAIN,
841 			    "%s: Hotspare pool is setup\n"),
842 			    hspnp->hspname);
843 		} else if (hsnlp->next == NULL) {
844 			(void) printf(dgettext(TEXT_DOMAIN,
845 			    "%s: Hotspare is added\n"),
846 			    hspnp->hspname);
847 		} else {
848 			(void) printf(dgettext(TEXT_DOMAIN,
849 			    "%s: Hotspares are added\n"),
850 			    hspnp->hspname);
851 		}
852 		(void) fflush(stdout);
853 	}
854 
855 	/* return success */
856 	return (0);
857 }
858 
859 /*
860  * delete hotspares from pool
861  */
862 int
863 meta_hs_delete(
864 	mdsetname_t	*sp,
865 	mdhspname_t	*hspnp,
866 	mdnamelist_t	*hsnlp,
867 	mdcmdopts_t	options,
868 	md_error_t	*ep
869 )
870 {
871 	mdnamelist_t	*p;
872 	set_hs_params_t	shs;
873 
874 	/* should have a set */
875 	assert(sp != NULL);
876 	assert(sp->setno == HSP_SET(hspnp->hsp));
877 
878 	/* clear cache */
879 	meta_invalidate_hsp(hspnp);
880 
881 	/* setup hotspare pool info */
882 	(void) memset(&shs, 0, sizeof (shs));
883 	shs.shs_hot_spare_pool = hspnp->hsp;
884 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
885 	shs.shs_cmd = DELETE_HOT_SPARE;
886 
887 	/* delete empty hotspare pool */
888 	if (hsnlp == NULL) {
889 		shs.shs_options = HS_OPT_POOL;
890 		/* If DOIT is not set, it's a dryrun */
891 		if ((options & MDCMD_DOIT) == 0) {
892 			shs.shs_options |= HS_OPT_DRYRUN;
893 		}
894 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
895 		    hspnp->hspname) != 0)
896 			return (mdstealerror(ep, &shs.mde));
897 		goto success;
898 	}
899 
900 	/* delete hotspares */
901 	shs.shs_options = HS_OPT_NONE;
902 	/* If DOIT is not set, it's a dryrun */
903 	if ((options & MDCMD_DOIT) == 0) {
904 		shs.shs_options |= HS_OPT_DRYRUN;
905 	}
906 	for (p = hsnlp; (p != NULL); p = p->next) {
907 		mdname_t	*hsnp = p->namep;
908 
909 		/* should be in same set */
910 		assert(sp->setno == HSP_SET(hspnp->hsp));
911 
912 		/* delete hotspare */
913 		shs.shs_component_old = hsnp->dev;
914 		meta_invalidate_name(hsnp);
915 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0)
916 			return (mdstealerror(ep, &shs.mde));
917 	}
918 
919 	/* print success message */
920 success:
921 	if (options & MDCMD_PRINT) {
922 		if (hsnlp == NULL) {
923 			(void) printf(dgettext(TEXT_DOMAIN,
924 			    "%s: Hotspare pool is cleared\n"),
925 			    hspnp->hspname);
926 		} else if (hsnlp->next == NULL) {
927 			(void) printf(dgettext(TEXT_DOMAIN,
928 			    "%s: Hotspare is deleted\n"),
929 			    hspnp->hspname);
930 		} else {
931 			(void) printf(dgettext(TEXT_DOMAIN,
932 			    "%s: Hotspares are deleted\n"),
933 			    hspnp->hspname);
934 		}
935 		(void) fflush(stdout);
936 	}
937 
938 	/* return success */
939 	return (0);
940 }
941 
942 /*
943  * replace hotspare in pool
944  */
945 int
946 meta_hs_replace(
947 	mdsetname_t	*sp,
948 	mdhspname_t	*hspnp,
949 	mdname_t	*oldnp,
950 	mdname_t	*newnp,
951 	mdcmdopts_t	options,
952 	md_error_t	*ep
953 )
954 {
955 	set_hs_params_t	shs;
956 	diskaddr_t	size, label, start_blk;
957 	md_dev64_t	old_dev, new_dev;
958 	diskaddr_t	new_start_blk, new_end_blk;
959 	int		rebind;
960 	char		*new_devidp = NULL;
961 	int		ret;
962 	md_set_desc	*sd;
963 
964 	/* should be in same set */
965 	assert(sp != NULL);
966 	assert(sp->setno == HSP_SET(hspnp->hsp));
967 
968 	/* save new binding incase this is a rebind where oldnp==newnp */
969 	new_dev = newnp->dev;
970 	new_start_blk = newnp->start_blk;
971 	new_end_blk = newnp->end_blk;
972 
973 	/* invalidate, then get the hotspare (fill in oldnp from metadb) */
974 	meta_invalidate_hsp(hspnp);
975 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
976 		return (-1);
977 
978 	/* the old device binding is now established */
979 	if ((old_dev = oldnp->dev) == NODEV64)
980 		return (mdsyserror(ep, ENODEV, oldnp->cname));
981 
982 	/*
983 	 * check for the case where oldnp and newnp indicate the same
984 	 * device, but the dev_t of the device has changed between old
985 	 * and new.  This is called a rebind.  On entry the dev_t
986 	 * represents the new device binding determined from the
987 	 * filesystem (meta_getdev). After calling meta_get_hsp
988 	 * oldnp (and maybe newnp if this is a rebind) is updated based
989 	 * to the old binding from the metadb (done by metakeyname).
990 	 */
991 	if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
992 	    (old_dev != new_dev)) {
993 		rebind = 1;
994 	} else {
995 		rebind = 0;
996 	}
997 	if (rebind) {
998 		newnp->dev = new_dev;
999 		newnp->start_blk = new_start_blk;
1000 		newnp->end_blk = new_end_blk;
1001 	}
1002 
1003 	/*
1004 	 * Save a copy of the devid associated with the new disk, the reason
1005 	 * is that the meta_check_hotspare() call could cause the devid to
1006 	 * be changed to that of the devid that is currently stored in the
1007 	 * replica namespace for the disk in question. This devid could be
1008 	 * stale if we are replacing the disk. The function that overwrites
1009 	 * the devid is dr2drivedesc().
1010 	 */
1011 	if (newnp->drivenamep->devid != NULL)
1012 		new_devidp = Strdup(newnp->drivenamep->devid);
1013 
1014 	/* if it's a multi-node diskset clear new_devidp */
1015 	if (!metaislocalset(sp)) {
1016 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1017 			Free(new_devidp);
1018 			return (-1);
1019 		}
1020 		if (MD_MNSET_DESC(sd)) {
1021 			Free(new_devidp);
1022 			new_devidp = NULL;
1023 		}
1024 	}
1025 
1026 	/* check it out */
1027 	if (meta_check_hotspare(sp, newnp, ep) != 0) {
1028 		if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
1029 			Free(new_devidp);
1030 			return (-1);
1031 		}
1032 		mdclrerror(ep);
1033 	}
1034 	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
1035 		Free(new_devidp);
1036 		return (-1);
1037 	}
1038 	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
1039 		Free(new_devidp);
1040 		return (-1);
1041 	}
1042 	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
1043 		Free(new_devidp);
1044 		return (-1);
1045 	}
1046 	if (start_blk >= size) {
1047 		(void) mdsyserror(ep, ENOSPC, newnp->cname);
1048 		Free(new_devidp);
1049 		return (-1);
1050 	}
1051 
1052 	/*
1053 	 * Copy back the saved devid.
1054 	 */
1055 	Free(newnp->drivenamep->devid);
1056 	if (new_devidp != NULL) {
1057 		newnp->drivenamep->devid = new_devidp;
1058 		new_devidp = NULL;
1059 	}
1060 
1061 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
1062 	if (options & MDCMD_DOIT) {
1063 		/* store name in namespace */
1064 		if (add_key_name(sp, newnp, NULL, ep) != 0)
1065 			return (-1);
1066 	}
1067 
1068 	if (rebind && !metaislocalset(sp)) {
1069 		/*
1070 		 * We are 'rebind'ing a disk that is in a diskset so as well
1071 		 * as updating the diskset's namespace the local set needs
1072 		 * to be updated because it also contains a reference to the
1073 		 * disk in question.
1074 		 */
1075 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
1076 		    ep);
1077 
1078 		if (ret != METADEVADM_SUCCESS) {
1079 			md_error_t	xep = mdnullerror;
1080 
1081 			/*
1082 			 * In dryrun mode (DOIT not set) we must not alter
1083 			 * the mddb
1084 			 */
1085 			if (options & MDCMD_DOIT) {
1086 				(void) del_key_name(sp, newnp, &xep);
1087 				mdclrerror(&xep);
1088 				return (-1);
1089 			}
1090 		}
1091 	}
1092 
1093 	/* replace hotspare */
1094 	(void) memset(&shs, 0, sizeof (shs));
1095 
1096 	shs.shs_size_option = meta_check_devicesize(size);
1097 
1098 	shs.shs_cmd = REPLACE_HOT_SPARE;
1099 	shs.shs_hot_spare_pool = hspnp->hsp;
1100 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1101 	shs.shs_component_old = old_dev;
1102 	shs.shs_options = HS_OPT_NONE;
1103 	/* If DOIT is not set, it's a dryrun */
1104 	if ((options & MDCMD_DOIT) == 0) {
1105 		shs.shs_options |= HS_OPT_DRYRUN;
1106 	}
1107 	shs.shs_component_new = new_dev;
1108 	shs.shs_start_blk = start_blk;
1109 	shs.shs_has_label = ((label > 0) ? 1 : 0);
1110 	shs.shs_number_blks = size;
1111 	shs.shs_key_new = newnp->key;
1112 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1113 		if (options & MDCMD_DOIT) {
1114 			(void) del_key_name(sp, newnp, ep);
1115 		}
1116 		return (mdstealerror(ep, &shs.mde));
1117 	}
1118 
1119 	/* clear cache */
1120 	meta_invalidate_name(oldnp);
1121 	meta_invalidate_name(newnp);
1122 	meta_invalidate_hsp(hspnp);
1123 
1124 	/* let em know */
1125 	if (options & MDCMD_PRINT) {
1126 		(void) printf(dgettext(TEXT_DOMAIN,
1127 		    "%s: Hotspare %s is replaced with %s\n"),
1128 		    hspnp->hspname, oldnp->cname, newnp->cname);
1129 		(void) fflush(stdout);
1130 	}
1131 
1132 	/* return success */
1133 	return (0);
1134 }
1135 
1136 /*
1137  * enable hotspares
1138  */
1139 int
1140 meta_hs_enable(
1141 	mdsetname_t	*sp,
1142 	mdnamelist_t	*hsnlp,
1143 	mdcmdopts_t	options,
1144 	md_error_t	*ep
1145 )
1146 {
1147 	mdhspnamelist_t	*hspnlp = NULL;
1148 	mdhspnamelist_t	*hspnp;
1149 	set_hs_params_t	shs;
1150 	int		rval = -1;
1151 
1152 	/* should have a set */
1153 	assert(sp != NULL);
1154 
1155 	/* setup device info */
1156 	(void) memset(&shs, 0, sizeof (shs));
1157 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1158 	shs.shs_cmd = FIX_HOT_SPARE;
1159 	shs.shs_options = HS_OPT_NONE;
1160 	/* If DOIT is not set, it's a dryrun */
1161 	if ((options & MDCMD_DOIT) == 0) {
1162 		shs.shs_options |= HS_OPT_DRYRUN;
1163 	}
1164 
1165 	/* get the list of hotspare names */
1166 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1167 		goto out;
1168 
1169 	/* enable hotspares for each components */
1170 	for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
1171 		mdname_t	*hsnp = hsnlp->namep;
1172 		md_dev64_t	fs_dev;
1173 		int		rebind = 0;
1174 		diskaddr_t	size, label, start_blk;
1175 
1176 		/* get the file_system dev binding */
1177 		if (meta_getdev(sp, hsnp, ep) != 0)
1178 			return (-1);
1179 		fs_dev = hsnp->dev;
1180 
1181 		/*
1182 		 * search for the component in each hotspare pool
1183 		 * and replace it (instead of enable) if the binding
1184 		 * has changed.
1185 		 */
1186 		for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1187 			/*
1188 			 * in_hsp will call meta_get_hsp which will fill
1189 			 * in hspnp with metadb version of component
1190 			 */
1191 			meta_invalidate_hsp(hspnp->hspnamep);
1192 			if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
1193 				/*
1194 				 * check for the case where the dev_t has
1195 				 * changed between the filesystem and the
1196 				 * metadb.  This is called a rebind, and
1197 				 * is handled by meta_hs_replace.
1198 				 */
1199 				if (fs_dev != hsnp->dev) {
1200 					/*
1201 					 * establish file system binding
1202 					 * with invalid start/end
1203 					 */
1204 					rebind++;
1205 					hsnp->dev = fs_dev;
1206 					hsnp->start_blk = -1;
1207 					hsnp->end_blk = -1;
1208 					rval = meta_hs_replace(sp,
1209 					    hspnp->hspnamep,
1210 					    hsnp, hsnp, options, ep);
1211 					if (rval != 0)
1212 						goto out;
1213 				}
1214 			}
1215 		}
1216 		if (rebind)
1217 			continue;
1218 
1219 		/* enable the component in all hotspares that use it */
1220 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1221 			goto out;
1222 
1223 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
1224 			goto out;
1225 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
1226 			goto out;
1227 		if ((start_blk = metagetstart(sp, hsnp, ep))
1228 		    == MD_DISKADDR_ERROR)
1229 			goto out;
1230 		if (start_blk >= size) {
1231 			(void) mdsyserror(ep, ENOSPC, hsnp->cname);
1232 			goto out;
1233 		}
1234 
1235 		/* enable hotspare */
1236 		shs.shs_component_old = hsnp->dev;
1237 		shs.shs_component_new = hsnp->dev;
1238 		shs.shs_start_blk = start_blk;
1239 		shs.shs_has_label = ((label > 0) ? 1 : 0);
1240 		shs.shs_number_blks = size;
1241 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
1242 			rval = mdstealerror(ep, &shs.mde);
1243 			goto out;
1244 		}
1245 
1246 		/*
1247 		 * Are we dealing with a non-local set? If so need to update
1248 		 * the local namespace so that the disk record has the correct
1249 		 * devid.
1250 		 */
1251 		if (!metaislocalset(sp)) {
1252 			rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
1253 			    hsnp->cname, ep);
1254 
1255 			if (rval != METADEVADM_SUCCESS) {
1256 				/*
1257 				 * Failed to update the local set. Nothing to
1258 				 * do here apart from report the error. The
1259 				 * namespace is most likely broken and some
1260 				 * form of remedial recovery is going to
1261 				 * be required.
1262 				 */
1263 				mde_perror(ep, "");
1264 				mdclrerror(ep);
1265 			}
1266 		}
1267 
1268 		/* clear cache */
1269 		meta_invalidate_name(hsnp);
1270 
1271 		/* let em know */
1272 		if (options & MDCMD_PRINT) {
1273 			(void) printf(dgettext(TEXT_DOMAIN,
1274 			    "hotspare %s is enabled\n"),
1275 			    hsnp->cname);
1276 			(void) fflush(stdout);
1277 		}
1278 	}
1279 
1280 	/* clear whole cache */
1281 	for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1282 		meta_invalidate_hsp(hspnp->hspnamep);
1283 	}
1284 
1285 
1286 	/* return success */
1287 	rval = 0;
1288 
1289 out:
1290 	if (hspnlp)
1291 		metafreehspnamelist(hspnlp);
1292 	return (rval);
1293 }
1294 
1295 /*
1296  * check for dups in the hsp itself
1297  */
1298 static int
1299 check_twice(
1300 	md_hsp_t	*hspp,
1301 	uint_t		hsi,
1302 	md_error_t	*ep
1303 )
1304 {
1305 	mdhspname_t	*hspnp = hspp->hspnamep;
1306 	mdname_t	*thisnp;
1307 	uint_t		h;
1308 
1309 	thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
1310 	for (h = 0; (h < hsi); ++h) {
1311 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[h];
1312 		mdname_t	*hsnp = hsp->hsnamep;
1313 
1314 		if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
1315 		    hsnp, 0, -1, ep) != 0)
1316 			return (-1);
1317 	}
1318 	return (0);
1319 }
1320 
1321 /*
1322  * check hsp
1323  */
1324 /*ARGSUSED2*/
1325 int
1326 meta_check_hsp(
1327 	mdsetname_t	*sp,
1328 	md_hsp_t	*hspp,
1329 	mdcmdopts_t	options,
1330 	md_error_t	*ep
1331 )
1332 {
1333 	mdhspname_t	*hspnp = hspp->hspnamep;
1334 	uint_t		hsi;
1335 
1336 	/* check hotspares */
1337 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1338 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1339 		mdname_t	*hsnp = hsp->hsnamep;
1340 		diskaddr_t	size;
1341 
1342 		/* check hotspare */
1343 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1344 			return (-1);
1345 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
1346 			return (-1);
1347 		} else if (size == 0) {
1348 			return (mdsyserror(ep, ENOSPC, hspnp->hspname));
1349 		}
1350 
1351 		/* check this hsp too */
1352 		if (check_twice(hspp, hsi, ep) != 0)
1353 			return (-1);
1354 	}
1355 
1356 	/* return success */
1357 	return (0);
1358 }
1359 
1360 /*
1361  * create hsp
1362  */
1363 int
1364 meta_create_hsp(
1365 	mdsetname_t	*sp,
1366 	md_hsp_t	*hspp,
1367 	mdcmdopts_t	options,
1368 	md_error_t	*ep
1369 )
1370 {
1371 	mdhspname_t	*hspnp = hspp->hspnamep;
1372 	mdnamelist_t	*hsnlp = NULL;
1373 	uint_t		hsi;
1374 	int		rval = -1;
1375 
1376 	/* validate hsp */
1377 	if (meta_check_hsp(sp, hspp, options, ep) != 0)
1378 		return (-1);
1379 
1380 	/* if we're not doing anything, return success */
1381 	if (! (options & MDCMD_DOIT))
1382 		return (0);
1383 
1384 	/* create hsp */
1385 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1386 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1387 		mdname_t	*hsnp = hsp->hsnamep;
1388 
1389 		(void) metanamelist_append(&hsnlp, hsnp);
1390 	}
1391 	options |= MDCMD_INIT;
1392 	rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
1393 
1394 	/* cleanup, return success */
1395 	metafreenamelist(hsnlp);
1396 	return (rval);
1397 }
1398 
1399 /*
1400  * initialize hsp
1401  * NOTE: this functions is metainit(1m)'s command line parser!
1402  */
1403 int
1404 meta_init_hsp(
1405 	mdsetname_t	**spp,
1406 	int		argc,
1407 	char		*argv[],
1408 	mdcmdopts_t	options,
1409 	md_error_t	*ep
1410 )
1411 {
1412 	char		*uname = argv[0];
1413 	mdhspname_t	*hspnp = NULL;
1414 	md_hsp_t	*hspp = NULL;
1415 	uint_t		hsi;
1416 	int		rval = -1;
1417 
1418 
1419 	/* get hsp name */
1420 	assert(argc > 0);
1421 	if (argc < 1)
1422 		goto syntax;
1423 	if ((hspnp = metahspname(spp, uname, ep)) == NULL)
1424 		goto out;
1425 	assert(*spp != NULL);
1426 	uname = hspnp->hspname;
1427 
1428 	if (!(options & MDCMD_NOLOCK)) {
1429 		/* grab set lock */
1430 		if (meta_lock(*spp, TRUE, ep))
1431 			goto out;
1432 
1433 		if (meta_check_ownership(*spp, ep) != 0)
1434 			goto out;
1435 	}
1436 
1437 	/* see if it exists already */
1438 	if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
1439 		(void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP, hspnp->hsp, uname);
1440 		goto out;
1441 	} else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
1442 		goto out;
1443 	} else {
1444 		mdclrerror(ep);
1445 	}
1446 	--argc, ++argv;
1447 
1448 	/* parse general options */
1449 	optind = 0;
1450 	opterr = 0;
1451 	if (getopt(argc, argv, "") != -1)
1452 		goto options;
1453 
1454 	/* allocate hsp */
1455 	hspp = Zalloc(sizeof (*hspp));
1456 	hspp->hotspares.hotspares_len = argc;
1457 	if (argc > 0) {
1458 		hspp->hotspares.hotspares_val =
1459 		    Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
1460 	}
1461 
1462 	/* setup pool */
1463 	hspp->hspnamep = hspnp;
1464 
1465 	/* parse hotspares */
1466 	for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
1467 	    ++hsi) {
1468 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1469 		mdname_t	*hsnamep;
1470 
1471 		/* parse hotspare name */
1472 		if ((hsnamep = metaname(spp, argv[0], ep)) == NULL)
1473 			goto out;
1474 		hsp->hsnamep = hsnamep;
1475 		--argc, ++argv;
1476 	}
1477 
1478 	/* we should be at the end */
1479 	if (argc != 0)
1480 		goto syntax;
1481 
1482 	/* create hotspare pool */
1483 	if (meta_create_hsp(*spp, hspp, options, ep) != 0)
1484 		goto out;
1485 	rval = 0;	/* success */
1486 	goto out;
1487 
1488 	/* syntax error */
1489 syntax:
1490 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
1491 	goto out;
1492 
1493 	/* options error */
1494 options:
1495 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
1496 	goto out;
1497 
1498 	/* cleanup, return error */
1499 out:
1500 	if (hspp != NULL)
1501 		meta_free_hsp(hspp);
1502 	return (rval);
1503 }
1504 
1505 /*
1506  * reset hotspare pool
1507  */
1508 int
1509 meta_hsp_reset(
1510 	mdsetname_t	*sp,
1511 	mdhspname_t	*hspnp,
1512 	mdcmdopts_t	options,
1513 	md_error_t	*ep
1514 )
1515 {
1516 	md_hsp_t	*hspp;
1517 	set_hs_params_t	shs;
1518 	uint_t		i;
1519 	int		rval = -1;
1520 
1521 	/* should have the same set */
1522 	assert(sp != NULL);
1523 	assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp)));
1524 
1525 	/* reset all hotspares */
1526 	if (hspnp == NULL) {
1527 		mdhspnamelist_t	*hspnlp = NULL;
1528 		mdhspnamelist_t	*p;
1529 
1530 		/* for each hotspare pool */
1531 		rval = 0;
1532 		if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1533 			return (-1);
1534 		for (p = hspnlp; (p != NULL); p = p->next) {
1535 			/* reset hotspare pool */
1536 			hspnp = p->hspnamep;
1537 
1538 			/*
1539 			 * If this is a multi-node set, we send a series
1540 			 * of individual metaclear commands.
1541 			 */
1542 			if (meta_is_mn_set(sp, ep)) {
1543 				if (meta_mn_send_metaclear_command(sp,
1544 				    hspnp->hspname, options, 0, ep) != 0) {
1545 					rval = -1;
1546 					break;
1547 				}
1548 			} else {
1549 				if (meta_hsp_reset(sp, hspnp, options,
1550 				    ep) != 0) {
1551 					rval = -1;
1552 					break;
1553 				}
1554 			}
1555 		}
1556 
1557 		/* cleanup, return success */
1558 		metafreehspnamelist(hspnlp);
1559 		return (rval);
1560 	}
1561 
1562 	/* get unit structure */
1563 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
1564 		return (-1);
1565 
1566 	/* make sure nobody owns us */
1567 	if (hspp->refcount > 0) {
1568 		return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
1569 		    hspnp->hspname));
1570 	}
1571 
1572 	/* clear hotspare pool members */
1573 	(void) memset(&shs, 0, sizeof (shs));
1574 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1575 	shs.shs_cmd = DELETE_HOT_SPARE;
1576 	shs.shs_hot_spare_pool = hspnp->hsp;
1577 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
1578 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
1579 		mdname_t	*hsnamep = hs->hsnamep;
1580 
1581 		/* clear cache */
1582 		meta_invalidate_name(hsnamep);
1583 
1584 		/* clear hotspare */
1585 		shs.shs_component_old = hsnamep->dev;
1586 		shs.shs_options = HS_OPT_FORCE;
1587 		/* If DOIT is not set, it's a dryrun */
1588 		if ((options & MDCMD_DOIT) == 0) {
1589 			shs.shs_options |= HS_OPT_DRYRUN;
1590 		}
1591 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1592 			(void) mdstealerror(ep, &shs.mde);
1593 			goto out;
1594 		}
1595 	}
1596 
1597 	/* clear hotspare pool */
1598 	shs.shs_options = HS_OPT_POOL;
1599 	/* If DOIT is not set, it's a dryrun */
1600 	if ((options & MDCMD_DOIT) == 0) {
1601 		shs.shs_options |= HS_OPT_DRYRUN;
1602 	}
1603 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hspnp->hspname) != 0) {
1604 		(void) mdstealerror(ep, &shs.mde);
1605 		goto out;
1606 	}
1607 	rval = 0;	/* success */
1608 
1609 	/* let em know */
1610 	if (options & MDCMD_PRINT) {
1611 		(void) printf(dgettext(TEXT_DOMAIN,
1612 		    "%s: Hotspare pool is cleared\n"),
1613 		    hspnp->hspname);
1614 		(void) fflush(stdout);
1615 	}
1616 
1617 	/* clear subdevices (nothing to do) */
1618 
1619 	/* cleanup, return success */
1620 out:
1621 	meta_invalidate_hsp(hspnp);
1622 	return (rval);
1623 }
1624