xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_hotspares.c (revision b2178a54bfad47b786da1c125ad5c89bbffb0a03)
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*/
55 int
meta_get_hsp_names(mdsetname_t * sp,mdhspnamelist_t ** hspnlpp,int options,md_error_t * ep)56 meta_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 
116 out:
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  */
127 static get_hsp_t *
get_hspinfo(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)128 get_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  */
163 void
meta_free_hsp(md_hsp_t * hspp)164 meta_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  */
178 md_hsp_t *
meta_get_hsp_common(mdsetname_t * sp,mdhspname_t * hspnp,int fast,md_error_t * ep)179 meta_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 */
249 out:
250 	Free(ghsp);
251 	meta_free_hsp(hspp);
252 	return (NULL);
253 }
254 
255 /*
256  * get hotspare pool unit
257  */
258 md_hsp_t *
meta_get_hsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)259 meta_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  */
271 static int
in_hsp(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)272 in_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  */
312 int
meta_check_inhsp(mdsetname_t * sp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)313 meta_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  */
349 int
meta_check_hotspare(mdsetname_t * sp,mdname_t * np,md_error_t * ep)350 meta_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  */
382 static int
hsp_print(md_hsp_t * hspp,char * fname,FILE * fp,md_error_t * ep)383 hsp_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 */
429 out:
430 	if (rval != 0)
431 		(void) mdsyserror(ep, errno, fname);
432 	return (rval);
433 }
434 
435 /*
436  * hotspare state name
437  */
438 char *
hs_state_to_name(md_hs_t * hsp,md_timeval32_t * tvp)439 hs_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  */
466 static int
hsp_report(md_hsp_t * hspp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep,mdsetname_t * sp)467 hsp_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 */
661 out:
662 	if (rval != 0)
663 		(void) mdsyserror(ep, errno, fname);
664 	return (rval);
665 }
666 
667 /*
668  * print/report hsp
669  */
670 int
meta_hsp_print(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)671 meta_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  */
729 int
metachkhsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)730 metachkhsp(
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  */
744 void
meta_invalidate_hsp(mdhspname_t * hspnp)745 meta_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  */
772 static void
del_hsp_name_mn_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)773 del_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  */
809 static void
del_hsp_name_trad_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)810 del_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  */
852 static int
del_hsp_keys(mdsetname_t * sp,hsp_t hspid,md_error_t * ep)853 del_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  */
913 static int
add_hsp_name_mn_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,char * hsp_name,md_error_t * ep)914 add_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, NULL, NULL, 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  */
950 static int
add_hsp_name_trad_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,char * hsp_name,md_error_t * ep)951 add_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, NULL, NULL, 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  */
989 static hsp_t
add_hsp_name(mdsetname_t * sp,char * hsp_name,md_error_t * ep)990 add_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, NULL, NULL, 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 
1057 cleanup:
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  */
1066 int
meta_hs_add(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)1067 meta_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 */
1194 success:
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  */
1225 static int
meta_hsp_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)1226 meta_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  */
1262 int
meta_hs_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)1263 meta_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 */
1315 success:
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  */
1340 int
meta_hs_replace(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * oldnp,mdname_t * newnp,mdcmdopts_t options,md_error_t * ep)1341 meta_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  */
1534 int
meta_hs_enable(mdsetname_t * sp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)1535 meta_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 
1684 out:
1685 	if (hspnlp)
1686 		metafreehspnamelist(hspnlp);
1687 	return (rval);
1688 }
1689 
1690 /*
1691  * check for dups in the hsp itself
1692  */
1693 static int
check_twice(md_hsp_t * hspp,uint_t hsi,md_error_t * ep)1694 check_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*/
1720 int
meta_check_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)1721 meta_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  */
1758 int
meta_create_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)1759 meta_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  */
1798 int
meta_init_hsp(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)1799 meta_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 (is_existing_metadevice(*spp, uname)) {
1834 		mdname_t	*np;
1835 		if ((np = metaname(spp, uname, META_DEVICE, ep)) != NULL)
1836 			if ((meta_get_unit(*spp, np, ep)) != NULL)
1837 				return (mderror(ep, MDE_NAME_IN_USE, uname));
1838 	}
1839 
1840 	if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
1841 		(void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP,
1842 		    hspnp->hsp, uname);
1843 		goto out;
1844 	} else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
1845 		goto out;
1846 	} else {
1847 		mdclrerror(ep);
1848 	}
1849 	--argc, ++argv;
1850 
1851 	/* parse general options */
1852 	optind = 0;
1853 	opterr = 0;
1854 	if (getopt(argc, argv, "") != -1)
1855 		goto options;
1856 
1857 	/* allocate hsp */
1858 	hspp = Zalloc(sizeof (*hspp));
1859 	hspp->hotspares.hotspares_len = argc;
1860 	if (argc > 0) {
1861 		hspp->hotspares.hotspares_val =
1862 		    Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
1863 	}
1864 
1865 	/* setup pool */
1866 	hspp->hspnamep = hspnp;
1867 
1868 	/* parse hotspares */
1869 	for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
1870 	    ++hsi) {
1871 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1872 		mdname_t	*hsnamep;
1873 
1874 		/* parse hotspare name */
1875 		if ((hsnamep = metaname(spp, argv[0],
1876 		    LOGICAL_DEVICE, ep)) == NULL)
1877 			goto out;
1878 		hsp->hsnamep = hsnamep;
1879 		--argc, ++argv;
1880 	}
1881 
1882 	/* we should be at the end */
1883 	if (argc != 0)
1884 		goto syntax;
1885 
1886 	/* create hotspare pool */
1887 	if (meta_create_hsp(*spp, hspp, options, ep) != 0)
1888 		goto out;
1889 	rval = 0;	/* success */
1890 	goto out;
1891 
1892 	/* syntax error */
1893 syntax:
1894 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
1895 	goto out;
1896 
1897 	/* options error */
1898 options:
1899 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
1900 	goto out;
1901 
1902 	/* cleanup, return error */
1903 out:
1904 	if (hspp != NULL)
1905 		meta_free_hsp(hspp);
1906 	return (rval);
1907 }
1908 
1909 /*
1910  * reset hotspare pool
1911  */
1912 int
meta_hsp_reset(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)1913 meta_hsp_reset(
1914 	mdsetname_t	*sp,
1915 	mdhspname_t	*hspnp,
1916 	mdcmdopts_t	options,
1917 	md_error_t	*ep
1918 )
1919 {
1920 	md_hsp_t	*hspp;
1921 	set_hs_params_t	shs;
1922 	uint_t		i;
1923 	int		rval = -1;
1924 
1925 	/* should have the same set */
1926 	assert(sp != NULL);
1927 	assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
1928 	    sp->setno == HSP_SET(hspnp->hsp));
1929 
1930 	/* reset all hotspares */
1931 	if (hspnp == NULL) {
1932 		mdhspnamelist_t	*hspnlp = NULL;
1933 		mdhspnamelist_t	*p;
1934 
1935 		/* for each hotspare pool */
1936 		rval = 0;
1937 		if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1938 			return (-1);
1939 		for (p = hspnlp; (p != NULL); p = p->next) {
1940 			/* reset hotspare pool */
1941 			hspnp = p->hspnamep;
1942 
1943 			/*
1944 			 * If this is a multi-node set, we send a series
1945 			 * of individual metaclear commands.
1946 			 */
1947 			if (meta_is_mn_set(sp, ep)) {
1948 				if (meta_mn_send_metaclear_command(sp,
1949 				    hspnp->hspname, options, 0, ep) != 0) {
1950 					rval = -1;
1951 					break;
1952 				}
1953 			} else {
1954 				if (meta_hsp_reset(sp, hspnp, options,
1955 				    ep) != 0) {
1956 					rval = -1;
1957 					break;
1958 				}
1959 			}
1960 		}
1961 
1962 		/* cleanup, return success */
1963 		metafreehspnamelist(hspnlp);
1964 		return (rval);
1965 	}
1966 
1967 	/* get unit structure */
1968 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
1969 		return (-1);
1970 
1971 	/* make sure nobody owns us */
1972 	if (hspp->refcount > 0) {
1973 		return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
1974 		    hspnp->hspname));
1975 	}
1976 
1977 	/* clear hotspare pool members */
1978 	(void) memset(&shs, 0, sizeof (shs));
1979 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1980 	shs.shs_cmd = DELETE_HOT_SPARE;
1981 	shs.shs_hot_spare_pool = hspnp->hsp;
1982 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
1983 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
1984 		mdname_t	*hsnamep = hs->hsnamep;
1985 
1986 		/* clear cache */
1987 		meta_invalidate_name(hsnamep);
1988 
1989 		/* clear hotspare */
1990 		shs.shs_component_old = hsnamep->dev;
1991 		shs.shs_options = HS_OPT_FORCE;
1992 		/* If DOIT is not set, it's a dryrun */
1993 		if ((options & MDCMD_DOIT) == 0) {
1994 			shs.shs_options |= HS_OPT_DRYRUN;
1995 		}
1996 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1997 			(void) mdstealerror(ep, &shs.mde);
1998 			goto out;
1999 		}
2000 	}
2001 
2002 	/* clear hotspare pool */
2003 	if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
2004 		goto out;
2005 	rval = 0;	/* success */
2006 
2007 	/* let em know */
2008 	if (options & MDCMD_PRINT) {
2009 		(void) printf(dgettext(TEXT_DOMAIN,
2010 		    "%s: Hotspare pool is cleared\n"),
2011 		    hspnp->hspname);
2012 		(void) fflush(stdout);
2013 	}
2014 
2015 	/* clear subdevices (nothing to do) */
2016 
2017 	/* cleanup, return success */
2018 out:
2019 	meta_invalidate_hsp(hspnp);
2020 	return (rval);
2021 }
2022