Home | History | Annotate | Download | only in common
      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
     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 *
    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
    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 *
    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 *
    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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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