xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_hotspares.c (revision bc913c4cbc9594e8ca0a031ba908f496ef40bbca)
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 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
1053 	if (options & MDCMD_DOIT) {
1054 		/* store name in namespace */
1055 		if (add_key_name(sp, newnp, NULL, ep) != 0)
1056 			return (-1);
1057 	}
1058 
1059 	/*
1060 	 * Copy back the saved devid.
1061 	 */
1062 	Free(newnp->drivenamep->devid);
1063 	if (new_devidp != NULL) {
1064 		newnp->drivenamep->devid = new_devidp;
1065 		new_devidp = NULL;
1066 	}
1067 
1068 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
1069 	if (options & MDCMD_DOIT) {
1070 		/* store name in namespace */
1071 		if (add_key_name(sp, newnp, NULL, ep) != 0)
1072 			return (-1);
1073 	}
1074 
1075 	if (rebind && !metaislocalset(sp)) {
1076 		/*
1077 		 * We are 'rebind'ing a disk that is in a diskset so as well
1078 		 * as updating the diskset's namespace the local set needs
1079 		 * to be updated because it also contains a reference to the
1080 		 * disk in question.
1081 		 */
1082 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
1083 		    ep);
1084 
1085 		if (ret != METADEVADM_SUCCESS) {
1086 			md_error_t	xep = mdnullerror;
1087 
1088 			/*
1089 			 * In dryrun mode (DOIT not set) we must not alter
1090 			 * the mddb
1091 			 */
1092 			if (options & MDCMD_DOIT) {
1093 				(void) del_key_name(sp, newnp, &xep);
1094 				mdclrerror(&xep);
1095 				return (-1);
1096 			}
1097 		}
1098 	}
1099 
1100 	/* replace hotspare */
1101 	(void) memset(&shs, 0, sizeof (shs));
1102 
1103 	shs.shs_size_option = meta_check_devicesize(size);
1104 
1105 	shs.shs_cmd = REPLACE_HOT_SPARE;
1106 	shs.shs_hot_spare_pool = hspnp->hsp;
1107 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1108 	shs.shs_component_old = old_dev;
1109 	shs.shs_options = HS_OPT_NONE;
1110 	/* If DOIT is not set, it's a dryrun */
1111 	if ((options & MDCMD_DOIT) == 0) {
1112 		shs.shs_options |= HS_OPT_DRYRUN;
1113 	}
1114 	shs.shs_component_new = new_dev;
1115 	shs.shs_start_blk = start_blk;
1116 	shs.shs_has_label = ((label > 0) ? 1 : 0);
1117 	shs.shs_number_blks = size;
1118 	shs.shs_key_new = newnp->key;
1119 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1120 		if (options & MDCMD_DOIT) {
1121 			(void) del_key_name(sp, newnp, ep);
1122 		}
1123 		return (mdstealerror(ep, &shs.mde));
1124 	}
1125 
1126 	/* clear cache */
1127 	meta_invalidate_name(oldnp);
1128 	meta_invalidate_name(newnp);
1129 	meta_invalidate_hsp(hspnp);
1130 
1131 	/* let em know */
1132 	if (options & MDCMD_PRINT) {
1133 		(void) printf(dgettext(TEXT_DOMAIN,
1134 		    "%s: Hotspare %s is replaced with %s\n"),
1135 		    hspnp->hspname, oldnp->cname, newnp->cname);
1136 		(void) fflush(stdout);
1137 	}
1138 
1139 	/* return success */
1140 	return (0);
1141 }
1142 
1143 /*
1144  * enable hotspares
1145  */
1146 int
1147 meta_hs_enable(
1148 	mdsetname_t	*sp,
1149 	mdnamelist_t	*hsnlp,
1150 	mdcmdopts_t	options,
1151 	md_error_t	*ep
1152 )
1153 {
1154 	mdhspnamelist_t	*hspnlp = NULL;
1155 	mdhspnamelist_t	*hspnp;
1156 	set_hs_params_t	shs;
1157 	int		rval = -1;
1158 
1159 	/* should have a set */
1160 	assert(sp != NULL);
1161 
1162 	/* setup device info */
1163 	(void) memset(&shs, 0, sizeof (shs));
1164 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1165 	shs.shs_cmd = FIX_HOT_SPARE;
1166 	shs.shs_options = HS_OPT_NONE;
1167 	/* If DOIT is not set, it's a dryrun */
1168 	if ((options & MDCMD_DOIT) == 0) {
1169 		shs.shs_options |= HS_OPT_DRYRUN;
1170 	}
1171 
1172 	/* get the list of hotspare names */
1173 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1174 		goto out;
1175 
1176 	/* enable hotspares for each components */
1177 	for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
1178 		mdname_t	*hsnp = hsnlp->namep;
1179 		md_dev64_t	fs_dev;
1180 		int		rebind = 0;
1181 		diskaddr_t	size, label, start_blk;
1182 
1183 		/* get the file_system dev binding */
1184 		if (meta_getdev(sp, hsnp, ep) != 0)
1185 			return (-1);
1186 		fs_dev = hsnp->dev;
1187 
1188 		/*
1189 		 * search for the component in each hotspare pool
1190 		 * and replace it (instead of enable) if the binding
1191 		 * has changed.
1192 		 */
1193 		for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1194 			/*
1195 			 * in_hsp will call meta_get_hsp which will fill
1196 			 * in hspnp with metadb version of component
1197 			 */
1198 			meta_invalidate_hsp(hspnp->hspnamep);
1199 			if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
1200 				/*
1201 				 * check for the case where the dev_t has
1202 				 * changed between the filesystem and the
1203 				 * metadb.  This is called a rebind, and
1204 				 * is handled by meta_hs_replace.
1205 				 */
1206 				if (fs_dev != hsnp->dev) {
1207 					/*
1208 					 * establish file system binding
1209 					 * with invalid start/end
1210 					 */
1211 					rebind++;
1212 					hsnp->dev = fs_dev;
1213 					hsnp->start_blk = -1;
1214 					hsnp->end_blk = -1;
1215 					rval = meta_hs_replace(sp,
1216 					    hspnp->hspnamep,
1217 					    hsnp, hsnp, options, ep);
1218 					if (rval != 0)
1219 						goto out;
1220 				}
1221 			}
1222 		}
1223 		if (rebind)
1224 			continue;
1225 
1226 		/* enable the component in all hotspares that use it */
1227 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1228 			goto out;
1229 
1230 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
1231 			goto out;
1232 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
1233 			goto out;
1234 		if ((start_blk = metagetstart(sp, hsnp, ep))
1235 		    == MD_DISKADDR_ERROR)
1236 			goto out;
1237 		if (start_blk >= size) {
1238 			(void) mdsyserror(ep, ENOSPC, hsnp->cname);
1239 			goto out;
1240 		}
1241 
1242 		/* enable hotspare */
1243 		shs.shs_component_old = hsnp->dev;
1244 		shs.shs_component_new = hsnp->dev;
1245 		shs.shs_start_blk = start_blk;
1246 		shs.shs_has_label = ((label > 0) ? 1 : 0);
1247 		shs.shs_number_blks = size;
1248 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
1249 			rval = mdstealerror(ep, &shs.mde);
1250 			goto out;
1251 		}
1252 
1253 		/*
1254 		 * Are we dealing with a non-local set? If so need to update
1255 		 * the local namespace so that the disk record has the correct
1256 		 * devid.
1257 		 */
1258 		if (!metaislocalset(sp)) {
1259 			rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
1260 			    hsnp->cname, ep);
1261 
1262 			if (rval != METADEVADM_SUCCESS) {
1263 				/*
1264 				 * Failed to update the local set. Nothing to
1265 				 * do here apart from report the error. The
1266 				 * namespace is most likely broken and some
1267 				 * form of remedial recovery is going to
1268 				 * be required.
1269 				 */
1270 				mde_perror(ep, "");
1271 				mdclrerror(ep);
1272 			}
1273 		}
1274 
1275 		/* clear cache */
1276 		meta_invalidate_name(hsnp);
1277 
1278 		/* let em know */
1279 		if (options & MDCMD_PRINT) {
1280 			(void) printf(dgettext(TEXT_DOMAIN,
1281 			    "hotspare %s is enabled\n"),
1282 			    hsnp->cname);
1283 			(void) fflush(stdout);
1284 		}
1285 	}
1286 
1287 	/* clear whole cache */
1288 	for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1289 		meta_invalidate_hsp(hspnp->hspnamep);
1290 	}
1291 
1292 
1293 	/* return success */
1294 	rval = 0;
1295 
1296 out:
1297 	if (hspnlp)
1298 		metafreehspnamelist(hspnlp);
1299 	return (rval);
1300 }
1301 
1302 /*
1303  * check for dups in the hsp itself
1304  */
1305 static int
1306 check_twice(
1307 	md_hsp_t	*hspp,
1308 	uint_t		hsi,
1309 	md_error_t	*ep
1310 )
1311 {
1312 	mdhspname_t	*hspnp = hspp->hspnamep;
1313 	mdname_t	*thisnp;
1314 	uint_t		h;
1315 
1316 	thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
1317 	for (h = 0; (h < hsi); ++h) {
1318 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[h];
1319 		mdname_t	*hsnp = hsp->hsnamep;
1320 
1321 		if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
1322 		    hsnp, 0, -1, ep) != 0)
1323 			return (-1);
1324 	}
1325 	return (0);
1326 }
1327 
1328 /*
1329  * check hsp
1330  */
1331 /*ARGSUSED2*/
1332 int
1333 meta_check_hsp(
1334 	mdsetname_t	*sp,
1335 	md_hsp_t	*hspp,
1336 	mdcmdopts_t	options,
1337 	md_error_t	*ep
1338 )
1339 {
1340 	mdhspname_t	*hspnp = hspp->hspnamep;
1341 	uint_t		hsi;
1342 
1343 	/* check hotspares */
1344 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1345 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1346 		mdname_t	*hsnp = hsp->hsnamep;
1347 		diskaddr_t	size;
1348 
1349 		/* check hotspare */
1350 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1351 			return (-1);
1352 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
1353 			return (-1);
1354 		} else if (size == 0) {
1355 			return (mdsyserror(ep, ENOSPC, hspnp->hspname));
1356 		}
1357 
1358 		/* check this hsp too */
1359 		if (check_twice(hspp, hsi, ep) != 0)
1360 			return (-1);
1361 	}
1362 
1363 	/* return success */
1364 	return (0);
1365 }
1366 
1367 /*
1368  * create hsp
1369  */
1370 int
1371 meta_create_hsp(
1372 	mdsetname_t	*sp,
1373 	md_hsp_t	*hspp,
1374 	mdcmdopts_t	options,
1375 	md_error_t	*ep
1376 )
1377 {
1378 	mdhspname_t	*hspnp = hspp->hspnamep;
1379 	mdnamelist_t	*hsnlp = NULL;
1380 	uint_t		hsi;
1381 	int		rval = -1;
1382 
1383 	/* validate hsp */
1384 	if (meta_check_hsp(sp, hspp, options, ep) != 0)
1385 		return (-1);
1386 
1387 	/* if we're not doing anything, return success */
1388 	if (! (options & MDCMD_DOIT))
1389 		return (0);
1390 
1391 	/* create hsp */
1392 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1393 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1394 		mdname_t	*hsnp = hsp->hsnamep;
1395 
1396 		(void) metanamelist_append(&hsnlp, hsnp);
1397 	}
1398 	options |= MDCMD_INIT;
1399 	rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
1400 
1401 	/* cleanup, return success */
1402 	metafreenamelist(hsnlp);
1403 	return (rval);
1404 }
1405 
1406 /*
1407  * initialize hsp
1408  * NOTE: this functions is metainit(1m)'s command line parser!
1409  */
1410 int
1411 meta_init_hsp(
1412 	mdsetname_t	**spp,
1413 	int		argc,
1414 	char		*argv[],
1415 	mdcmdopts_t	options,
1416 	md_error_t	*ep
1417 )
1418 {
1419 	char		*uname = argv[0];
1420 	mdhspname_t	*hspnp = NULL;
1421 	md_hsp_t	*hspp = NULL;
1422 	uint_t		hsi;
1423 	int		rval = -1;
1424 
1425 
1426 	/* get hsp name */
1427 	assert(argc > 0);
1428 	if (argc < 1)
1429 		goto syntax;
1430 	if ((hspnp = metahspname(spp, uname, ep)) == NULL)
1431 		goto out;
1432 	assert(*spp != NULL);
1433 	uname = hspnp->hspname;
1434 
1435 	if (!(options & MDCMD_NOLOCK)) {
1436 		/* grab set lock */
1437 		if (meta_lock(*spp, TRUE, ep))
1438 			goto out;
1439 
1440 		if (meta_check_ownership(*spp, ep) != 0)
1441 			goto out;
1442 	}
1443 
1444 	/* see if it exists already */
1445 	if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
1446 		(void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP, hspnp->hsp, uname);
1447 		goto out;
1448 	} else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
1449 		goto out;
1450 	} else {
1451 		mdclrerror(ep);
1452 	}
1453 	--argc, ++argv;
1454 
1455 	/* parse general options */
1456 	optind = 0;
1457 	opterr = 0;
1458 	if (getopt(argc, argv, "") != -1)
1459 		goto options;
1460 
1461 	/* allocate hsp */
1462 	hspp = Zalloc(sizeof (*hspp));
1463 	hspp->hotspares.hotspares_len = argc;
1464 	if (argc > 0) {
1465 		hspp->hotspares.hotspares_val =
1466 		    Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
1467 	}
1468 
1469 	/* setup pool */
1470 	hspp->hspnamep = hspnp;
1471 
1472 	/* parse hotspares */
1473 	for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
1474 	    ++hsi) {
1475 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1476 		mdname_t	*hsnamep;
1477 
1478 		/* parse hotspare name */
1479 		if ((hsnamep = metaname(spp, argv[0], ep)) == NULL)
1480 			goto out;
1481 		hsp->hsnamep = hsnamep;
1482 		--argc, ++argv;
1483 	}
1484 
1485 	/* we should be at the end */
1486 	if (argc != 0)
1487 		goto syntax;
1488 
1489 	/* create hotspare pool */
1490 	if (meta_create_hsp(*spp, hspp, options, ep) != 0)
1491 		goto out;
1492 	rval = 0;	/* success */
1493 	goto out;
1494 
1495 	/* syntax error */
1496 syntax:
1497 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
1498 	goto out;
1499 
1500 	/* options error */
1501 options:
1502 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
1503 	goto out;
1504 
1505 	/* cleanup, return error */
1506 out:
1507 	if (hspp != NULL)
1508 		meta_free_hsp(hspp);
1509 	return (rval);
1510 }
1511 
1512 /*
1513  * reset hotspare pool
1514  */
1515 int
1516 meta_hsp_reset(
1517 	mdsetname_t	*sp,
1518 	mdhspname_t	*hspnp,
1519 	mdcmdopts_t	options,
1520 	md_error_t	*ep
1521 )
1522 {
1523 	md_hsp_t	*hspp;
1524 	set_hs_params_t	shs;
1525 	uint_t		i;
1526 	int		rval = -1;
1527 
1528 	/* should have the same set */
1529 	assert(sp != NULL);
1530 	assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp)));
1531 
1532 	/* reset all hotspares */
1533 	if (hspnp == NULL) {
1534 		mdhspnamelist_t	*hspnlp = NULL;
1535 		mdhspnamelist_t	*p;
1536 
1537 		/* for each hotspare pool */
1538 		rval = 0;
1539 		if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1540 			return (-1);
1541 		for (p = hspnlp; (p != NULL); p = p->next) {
1542 			/* reset hotspare pool */
1543 			hspnp = p->hspnamep;
1544 
1545 			/*
1546 			 * If this is a multi-node set, we send a series
1547 			 * of individual metaclear commands.
1548 			 */
1549 			if (meta_is_mn_set(sp, ep)) {
1550 				if (meta_mn_send_metaclear_command(sp,
1551 				    hspnp->hspname, options, 0, ep) != 0) {
1552 					rval = -1;
1553 					break;
1554 				}
1555 			} else {
1556 				if (meta_hsp_reset(sp, hspnp, options,
1557 				    ep) != 0) {
1558 					rval = -1;
1559 					break;
1560 				}
1561 			}
1562 		}
1563 
1564 		/* cleanup, return success */
1565 		metafreehspnamelist(hspnlp);
1566 		return (rval);
1567 	}
1568 
1569 	/* get unit structure */
1570 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
1571 		return (-1);
1572 
1573 	/* make sure nobody owns us */
1574 	if (hspp->refcount > 0) {
1575 		return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
1576 		    hspnp->hspname));
1577 	}
1578 
1579 	/* clear hotspare pool members */
1580 	(void) memset(&shs, 0, sizeof (shs));
1581 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1582 	shs.shs_cmd = DELETE_HOT_SPARE;
1583 	shs.shs_hot_spare_pool = hspnp->hsp;
1584 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
1585 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
1586 		mdname_t	*hsnamep = hs->hsnamep;
1587 
1588 		/* clear cache */
1589 		meta_invalidate_name(hsnamep);
1590 
1591 		/* clear hotspare */
1592 		shs.shs_component_old = hsnamep->dev;
1593 		shs.shs_options = HS_OPT_FORCE;
1594 		/* If DOIT is not set, it's a dryrun */
1595 		if ((options & MDCMD_DOIT) == 0) {
1596 			shs.shs_options |= HS_OPT_DRYRUN;
1597 		}
1598 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1599 			(void) mdstealerror(ep, &shs.mde);
1600 			goto out;
1601 		}
1602 	}
1603 
1604 	/* clear hotspare pool */
1605 	shs.shs_options = HS_OPT_POOL;
1606 	/* If DOIT is not set, it's a dryrun */
1607 	if ((options & MDCMD_DOIT) == 0) {
1608 		shs.shs_options |= HS_OPT_DRYRUN;
1609 	}
1610 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hspnp->hspname) != 0) {
1611 		(void) mdstealerror(ep, &shs.mde);
1612 		goto out;
1613 	}
1614 	rval = 0;	/* success */
1615 
1616 	/* let em know */
1617 	if (options & MDCMD_PRINT) {
1618 		(void) printf(dgettext(TEXT_DOMAIN,
1619 		    "%s: Hotspare pool is cleared\n"),
1620 		    hspnp->hspname);
1621 		(void) fflush(stdout);
1622 	}
1623 
1624 	/* clear subdevices (nothing to do) */
1625 
1626 	/* cleanup, return success */
1627 out:
1628 	meta_invalidate_hsp(hspnp);
1629 	return (rval);
1630 }
1631