10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51623Stw21770 * Common Development and Distribution License (the "License").
61623Stw21770 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
221623Stw21770 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * Just in case we're not in a build environment, make sure that
300Sstevel@tonic-gate * TEXT_DOMAIN gets set to something.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
330Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
340Sstevel@tonic-gate #endif
350Sstevel@tonic-gate
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate * hotspares utilities
380Sstevel@tonic-gate */
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include <meta.h>
410Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h>
420Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate * FUNCTION: meta_get_hsp_names()
460Sstevel@tonic-gate * INPUT: sp - the set name to get hotspares from
470Sstevel@tonic-gate * options - options from the command line
480Sstevel@tonic-gate * OUTPUT: hspnlpp - list of all hotspare names
490Sstevel@tonic-gate * ep - return error pointer
500Sstevel@tonic-gate * RETURNS: int - -1 if error, 0 success
510Sstevel@tonic-gate * PURPOSE: returns a list of all hotspares in the metadb
520Sstevel@tonic-gate * for all devices in the specified set
530Sstevel@tonic-gate */
540Sstevel@tonic-gate /*ARGSUSED*/
550Sstevel@tonic-gate int
meta_get_hsp_names(mdsetname_t * sp,mdhspnamelist_t ** hspnlpp,int options,md_error_t * ep)560Sstevel@tonic-gate meta_get_hsp_names(
570Sstevel@tonic-gate mdsetname_t *sp,
580Sstevel@tonic-gate mdhspnamelist_t **hspnlpp,
590Sstevel@tonic-gate int options,
600Sstevel@tonic-gate md_error_t *ep
610Sstevel@tonic-gate )
620Sstevel@tonic-gate {
630Sstevel@tonic-gate md_i_getnum_t gn; /* MD_IOCGET_NUM params */
640Sstevel@tonic-gate minor_t *minors = NULL;
650Sstevel@tonic-gate minor_t *m_ptr;
660Sstevel@tonic-gate int i;
670Sstevel@tonic-gate
680Sstevel@tonic-gate /* we must have a set */
690Sstevel@tonic-gate assert(sp != NULL);
700Sstevel@tonic-gate
710Sstevel@tonic-gate (void) memset(&gn, 0, sizeof (gn));
720Sstevel@tonic-gate MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno);
730Sstevel@tonic-gate
740Sstevel@tonic-gate /* get number of devices */
750Sstevel@tonic-gate if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
760Sstevel@tonic-gate if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
770Sstevel@tonic-gate mdclrerror(&gn.mde);
780Sstevel@tonic-gate } else {
790Sstevel@tonic-gate (void) mdstealerror(ep, &gn.mde);
800Sstevel@tonic-gate return (-1);
810Sstevel@tonic-gate }
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
840Sstevel@tonic-gate if (gn.size > 0) {
850Sstevel@tonic-gate /* malloc minor number buffer to be filled by ioctl */
860Sstevel@tonic-gate if ((minors = (minor_t *)malloc(
870Sstevel@tonic-gate gn.size * sizeof (minor_t))) == 0) {
880Sstevel@tonic-gate return (ENOMEM);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate gn.minors = (uintptr_t)minors;
910Sstevel@tonic-gate if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
920Sstevel@tonic-gate (void) mdstealerror(ep, &gn.mde);
930Sstevel@tonic-gate free(minors);
940Sstevel@tonic-gate return (-1);
950Sstevel@tonic-gate }
960Sstevel@tonic-gate m_ptr = minors;
970Sstevel@tonic-gate for (i = 0; i < gn.size; i++) {
980Sstevel@tonic-gate mdhspname_t *hspnp;
990Sstevel@tonic-gate
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /* get name */
1020Sstevel@tonic-gate if ((hspnp = metahsphspname(&sp, *m_ptr, ep))
1030Sstevel@tonic-gate == NULL)
1040Sstevel@tonic-gate goto out;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /* append to list */
1070Sstevel@tonic-gate (void) metahspnamelist_append(hspnlpp, hspnp);
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /* next device */
1100Sstevel@tonic-gate m_ptr++;
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate free(minors);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate return (gn.size);
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate out:
1170Sstevel@tonic-gate if (minors != NULL)
1180Sstevel@tonic-gate free(minors);
1190Sstevel@tonic-gate metafreehspnamelist(*hspnlpp);
1200Sstevel@tonic-gate *hspnlpp = NULL;
1210Sstevel@tonic-gate return (-1);
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate * get information of a specific hotspare pool from driver
1260Sstevel@tonic-gate */
1270Sstevel@tonic-gate static get_hsp_t *
get_hspinfo(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)1280Sstevel@tonic-gate get_hspinfo(
1290Sstevel@tonic-gate mdsetname_t *sp,
1300Sstevel@tonic-gate mdhspname_t *hspnp,
1310Sstevel@tonic-gate md_error_t *ep
1320Sstevel@tonic-gate )
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate md_i_get_t mig;
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate /* should have a set */
1370Sstevel@tonic-gate assert(sp != NULL);
1381623Stw21770 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate /* get size of unit structure */
1410Sstevel@tonic-gate (void) memset(&mig, 0, sizeof (mig));
1420Sstevel@tonic-gate MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno);
1430Sstevel@tonic-gate mig.id = hspnp->hsp;
1440Sstevel@tonic-gate if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
1450Sstevel@tonic-gate (void) mdstealerror(ep, &mig.mde);
1460Sstevel@tonic-gate return (NULL);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /* get actual unit structure */
1500Sstevel@tonic-gate assert(mig.size > 0);
1510Sstevel@tonic-gate mig.mdp = (uintptr_t)Zalloc(mig.size);
1520Sstevel@tonic-gate if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
1530Sstevel@tonic-gate (void) mdstealerror(ep, &mig.mde);
15462Sjeanm Free((void *)(uintptr_t)mig.mdp);
1550Sstevel@tonic-gate return (NULL);
1560Sstevel@tonic-gate }
15762Sjeanm return ((get_hsp_t *)(uintptr_t)mig.mdp);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate * free hotspare pool unit
1620Sstevel@tonic-gate */
1630Sstevel@tonic-gate void
meta_free_hsp(md_hsp_t * hspp)1640Sstevel@tonic-gate meta_free_hsp(
1650Sstevel@tonic-gate md_hsp_t *hspp
1660Sstevel@tonic-gate )
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate if (hspp->hotspares.hotspares_val != NULL) {
1690Sstevel@tonic-gate assert(hspp->hotspares.hotspares_len > 0);
1700Sstevel@tonic-gate Free(hspp->hotspares.hotspares_val);
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate Free(hspp);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * get hotspare pool unit (common)
1770Sstevel@tonic-gate */
1780Sstevel@tonic-gate md_hsp_t *
meta_get_hsp_common(mdsetname_t * sp,mdhspname_t * hspnp,int fast,md_error_t * ep)1790Sstevel@tonic-gate meta_get_hsp_common(
1800Sstevel@tonic-gate mdsetname_t *sp,
1810Sstevel@tonic-gate mdhspname_t *hspnp,
1820Sstevel@tonic-gate int fast,
1830Sstevel@tonic-gate md_error_t *ep
1840Sstevel@tonic-gate )
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate get_hsp_t *ghsp;
1870Sstevel@tonic-gate md_hsp_t *hspp;
1880Sstevel@tonic-gate uint_t hsi;
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /* must have set */
1910Sstevel@tonic-gate assert(sp != NULL);
1921623Stw21770 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate /* short circuit */
1950Sstevel@tonic-gate if (hspnp->unitp != NULL)
1960Sstevel@tonic-gate return (hspnp->unitp);
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /* get unit */
1990Sstevel@tonic-gate if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL)
2000Sstevel@tonic-gate return (NULL);
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate /* allocate hsp */
2030Sstevel@tonic-gate hspp = Zalloc(sizeof (*hspp));
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /* allocate hotspares */
2060Sstevel@tonic-gate hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares;
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate /* if empty hotspare pool, we are done */
2090Sstevel@tonic-gate if (hspp->hotspares.hotspares_len != 0)
2100Sstevel@tonic-gate hspp->hotspares.hotspares_val =
2110Sstevel@tonic-gate Zalloc(hspp->hotspares.hotspares_len *
2120Sstevel@tonic-gate sizeof (*hspp->hotspares.hotspares_val));
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /* get name, refcount */
2150Sstevel@tonic-gate hspp->hspnamep = hspnp;
2160Sstevel@tonic-gate hspp->refcount = ghsp->ghsp_refcount;
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate /* get hotspares */
2190Sstevel@tonic-gate for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
2200Sstevel@tonic-gate mdkey_t hs_key = ghsp->ghsp_hs_keys[hsi];
2210Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
2220Sstevel@tonic-gate get_hs_params_t ghs;
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /* get hotspare name */
2250Sstevel@tonic-gate hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep);
2260Sstevel@tonic-gate if (hsp->hsnamep == NULL)
2270Sstevel@tonic-gate goto out;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /* get hotspare state */
2300Sstevel@tonic-gate (void) memset(&ghs, 0, sizeof (ghs));
2310Sstevel@tonic-gate MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno);
2320Sstevel@tonic-gate ghs.ghs_key = hs_key;
2330Sstevel@tonic-gate if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) {
2340Sstevel@tonic-gate (void) mdstealerror(ep, &ghs.mde);
2350Sstevel@tonic-gate goto out;
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate hsp->state = ghs.ghs_state;
2380Sstevel@tonic-gate hsp->size = ghs.ghs_number_blks;
2390Sstevel@tonic-gate hsp->timestamp = ghs.ghs_timestamp;
2400Sstevel@tonic-gate hsp->revision = ghs.ghs_revision;
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate /* cleanup, return success */
2440Sstevel@tonic-gate Free(ghsp);
2450Sstevel@tonic-gate hspnp->unitp = hspp;
2460Sstevel@tonic-gate return (hspp);
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /* cleanup, return error */
2490Sstevel@tonic-gate out:
2500Sstevel@tonic-gate Free(ghsp);
2510Sstevel@tonic-gate meta_free_hsp(hspp);
2520Sstevel@tonic-gate return (NULL);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate * get hotspare pool unit
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate md_hsp_t *
meta_get_hsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)2590Sstevel@tonic-gate meta_get_hsp(
2600Sstevel@tonic-gate mdsetname_t *sp,
2610Sstevel@tonic-gate mdhspname_t *hspnp,
2620Sstevel@tonic-gate md_error_t *ep
2630Sstevel@tonic-gate )
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate return (meta_get_hsp_common(sp, hspnp, 0, ep));
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate * check hotspare pool for dev
2700Sstevel@tonic-gate */
2710Sstevel@tonic-gate static int
in_hsp(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)2720Sstevel@tonic-gate in_hsp(
2730Sstevel@tonic-gate mdsetname_t *sp,
2740Sstevel@tonic-gate mdhspname_t *hspnp,
2750Sstevel@tonic-gate mdname_t *np,
2760Sstevel@tonic-gate diskaddr_t slblk,
2770Sstevel@tonic-gate diskaddr_t nblks,
2780Sstevel@tonic-gate md_error_t *ep
2790Sstevel@tonic-gate )
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate md_hsp_t *hspp;
2820Sstevel@tonic-gate uint_t i;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate /* should be in the same set */
2850Sstevel@tonic-gate assert(sp != NULL);
2861623Stw21770 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate /* get unit */
2890Sstevel@tonic-gate if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
2900Sstevel@tonic-gate return (-1);
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate /* look in hotspares */
2930Sstevel@tonic-gate for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
2940Sstevel@tonic-gate md_hs_t *hs = &hspp->hotspares.hotspares_val[i];
2950Sstevel@tonic-gate mdname_t *hsnp = hs->hsnamep;
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate /* check overlap */
2980Sstevel@tonic-gate if (metaismeta(hsnp))
2990Sstevel@tonic-gate continue;
3000Sstevel@tonic-gate if (meta_check_overlap(hspnp->hspname, np, slblk, nblks,
3010Sstevel@tonic-gate hsnp, 0, -1, ep) != 0)
3020Sstevel@tonic-gate return (-1);
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /* return success */
3060Sstevel@tonic-gate return (0);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate /*
3100Sstevel@tonic-gate * check to see if we're in a hotspare pool
3110Sstevel@tonic-gate */
3120Sstevel@tonic-gate int
meta_check_inhsp(mdsetname_t * sp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)3130Sstevel@tonic-gate meta_check_inhsp(
3140Sstevel@tonic-gate mdsetname_t *sp,
3150Sstevel@tonic-gate mdname_t *np,
3160Sstevel@tonic-gate diskaddr_t slblk,
3170Sstevel@tonic-gate diskaddr_t nblks,
3180Sstevel@tonic-gate md_error_t *ep
3190Sstevel@tonic-gate )
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate mdhspnamelist_t *hspnlp = NULL;
3220Sstevel@tonic-gate mdhspnamelist_t *p;
3230Sstevel@tonic-gate int rval = 0;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate /* should have a set */
3260Sstevel@tonic-gate assert(sp != NULL);
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate /* for each hotspare pool */
3290Sstevel@tonic-gate if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
3300Sstevel@tonic-gate return (-1);
3310Sstevel@tonic-gate for (p = hspnlp; (p != NULL); p = p->next) {
3320Sstevel@tonic-gate mdhspname_t *hspnp = p->hspnamep;
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate /* check hotspare pool */
3350Sstevel@tonic-gate if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) {
3360Sstevel@tonic-gate rval = -1;
3370Sstevel@tonic-gate break;
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate /* cleanup, return success */
3420Sstevel@tonic-gate metafreehspnamelist(hspnlp);
3430Sstevel@tonic-gate return (rval);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate /*
3470Sstevel@tonic-gate * check hotspare
3480Sstevel@tonic-gate */
3490Sstevel@tonic-gate int
meta_check_hotspare(mdsetname_t * sp,mdname_t * np,md_error_t * ep)3500Sstevel@tonic-gate meta_check_hotspare(
3510Sstevel@tonic-gate mdsetname_t *sp,
3520Sstevel@tonic-gate mdname_t *np,
3530Sstevel@tonic-gate md_error_t *ep
3540Sstevel@tonic-gate )
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate mdchkopts_t options = (MDCHK_ALLOW_HS);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate /* make sure we have a disk */
3590Sstevel@tonic-gate if (metachkcomp(np, ep) != 0)
3600Sstevel@tonic-gate return (-1);
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /* check to ensure that it is not already in use */
3630Sstevel@tonic-gate if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
3640Sstevel@tonic-gate return (-1);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate /* make sure it is in the set */
3680Sstevel@tonic-gate if (meta_check_inset(sp, np, ep) != 0)
3690Sstevel@tonic-gate return (-1);
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate /* make sure its not in a metadevice */
3720Sstevel@tonic-gate if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
3730Sstevel@tonic-gate return (-1);
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate /* return success */
3760Sstevel@tonic-gate return (0);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate * print hsp
3810Sstevel@tonic-gate */
3820Sstevel@tonic-gate static int
hsp_print(md_hsp_t * hspp,char * fname,FILE * fp,md_error_t * ep)3830Sstevel@tonic-gate hsp_print(
3840Sstevel@tonic-gate md_hsp_t *hspp,
3850Sstevel@tonic-gate char *fname,
3860Sstevel@tonic-gate FILE *fp,
3870Sstevel@tonic-gate md_error_t *ep
3880Sstevel@tonic-gate )
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate uint_t hsi;
3910Sstevel@tonic-gate int rval = -1;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate /* print name */
3940Sstevel@tonic-gate if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF)
3950Sstevel@tonic-gate goto out;
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /* print hotspares */
3980Sstevel@tonic-gate for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
3990Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate /* print hotspare */
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * If the path is our standard /dev/rdsk or /dev/md/rdsk
4040Sstevel@tonic-gate * then just print out the cxtxdxsx or the dx, metainit
4050Sstevel@tonic-gate * will assume the default, otherwise we need the full
4060Sstevel@tonic-gate * pathname to make sure this works as we intend.
4070Sstevel@tonic-gate */
4080Sstevel@tonic-gate if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) &&
4090Sstevel@tonic-gate (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) &&
4100Sstevel@tonic-gate (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) {
4110Sstevel@tonic-gate /* not standard path, print full pathname */
4120Sstevel@tonic-gate if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF)
4130Sstevel@tonic-gate goto out;
4140Sstevel@tonic-gate } else {
4150Sstevel@tonic-gate /* standard path, just print ctd or d value */
4160Sstevel@tonic-gate if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF)
4170Sstevel@tonic-gate goto out;
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate /* terminate last line */
4220Sstevel@tonic-gate if (fprintf(fp, "\n") == EOF)
4230Sstevel@tonic-gate goto out;
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate /* success */
4260Sstevel@tonic-gate rval = 0;
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate /* cleanup, return error */
4290Sstevel@tonic-gate out:
4300Sstevel@tonic-gate if (rval != 0)
4310Sstevel@tonic-gate (void) mdsyserror(ep, errno, fname);
4320Sstevel@tonic-gate return (rval);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate * hotspare state name
4370Sstevel@tonic-gate */
4380Sstevel@tonic-gate char *
hs_state_to_name(md_hs_t * hsp,md_timeval32_t * tvp)4390Sstevel@tonic-gate hs_state_to_name(
4400Sstevel@tonic-gate md_hs_t *hsp,
4410Sstevel@tonic-gate md_timeval32_t *tvp
4420Sstevel@tonic-gate )
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate hotspare_states_t state = hsp->state;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate /* grab time */
4470Sstevel@tonic-gate if (tvp != NULL)
4480Sstevel@tonic-gate *tvp = hsp->timestamp;
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate switch (state) {
4510Sstevel@tonic-gate case HSS_AVAILABLE:
4520Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Available"));
4530Sstevel@tonic-gate case HSS_RESERVED:
4540Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "In use"));
4550Sstevel@tonic-gate case HSS_BROKEN:
4560Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Broken"));
4570Sstevel@tonic-gate case HSS_UNUSED:
4580Sstevel@tonic-gate default:
4590Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "invalid"));
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /*
4640Sstevel@tonic-gate * report hsp
4650Sstevel@tonic-gate */
4660Sstevel@tonic-gate 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)4670Sstevel@tonic-gate hsp_report(
4680Sstevel@tonic-gate md_hsp_t *hspp,
4690Sstevel@tonic-gate mdnamelist_t **nlpp,
4700Sstevel@tonic-gate char *fname,
4710Sstevel@tonic-gate FILE *fp,
4720Sstevel@tonic-gate mdprtopts_t options,
4730Sstevel@tonic-gate md_error_t *ep,
4740Sstevel@tonic-gate mdsetname_t *sp
4750Sstevel@tonic-gate )
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate uint_t hsi;
4780Sstevel@tonic-gate int rval = -1;
4790Sstevel@tonic-gate char *devid = "";
4800Sstevel@tonic-gate mdname_t *didnp = NULL;
4810Sstevel@tonic-gate uint_t len;
4820Sstevel@tonic-gate int large_hs_dev_cnt = 0;
4831623Stw21770 int fn_hs_dev_cnt = 0;
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate if (options & PRINT_LARGEDEVICES) {
4860Sstevel@tonic-gate for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
4870Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
4881623Stw21770 if (hsp->revision & MD_64BIT_META_DEV) {
4890Sstevel@tonic-gate large_hs_dev_cnt += 1;
4900Sstevel@tonic-gate if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
4910Sstevel@tonic-gate != 0)
4920Sstevel@tonic-gate goto out;
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate if (large_hs_dev_cnt == 0) {
4970Sstevel@tonic-gate rval = 0;
4980Sstevel@tonic-gate goto out;
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate }
5011623Stw21770
5021623Stw21770 if (options & PRINT_FN) {
5031623Stw21770 if (!HSP_ID_IS_FN(hspp->hspnamep->hsp)) {
5041623Stw21770 rval = 0;
5051623Stw21770 goto out;
5061623Stw21770 }
5071623Stw21770 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
5081623Stw21770 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
5091623Stw21770 fn_hs_dev_cnt += 1;
5101623Stw21770 if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
5111623Stw21770 != 0)
5121623Stw21770 goto out;
5131623Stw21770 }
5141623Stw21770 }
5151623Stw21770
5160Sstevel@tonic-gate /* print header */
5170Sstevel@tonic-gate if (hspp->hotspares.hotspares_len == 0) {
5180Sstevel@tonic-gate if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"),
5190Sstevel@tonic-gate hspp->hspnamep->hspname) == EOF) {
5200Sstevel@tonic-gate goto out;
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate } else if (hspp->hotspares.hotspares_len == 1) {
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate /*
5250Sstevel@tonic-gate * This allows the length
5260Sstevel@tonic-gate * of the ctd to vary from small to large without
5270Sstevel@tonic-gate * looking horrible.
5280Sstevel@tonic-gate */
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname);
5310Sstevel@tonic-gate /*
5320Sstevel@tonic-gate * if the length is to short to print out all of the header
5330Sstevel@tonic-gate * force the matter
5340Sstevel@tonic-gate */
5350Sstevel@tonic-gate len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
5360Sstevel@tonic-gate len += 2;
5370Sstevel@tonic-gate if (options & PRINT_LARGEDEVICES) {
5380Sstevel@tonic-gate if (fprintf(fp,
5390Sstevel@tonic-gate "%s: 1 hot spare (1 big device)\n\t%-*.*s "
5400Sstevel@tonic-gate "%-12.12s%-8.6s\t\t%s\n",
5410Sstevel@tonic-gate hspp->hspnamep->hspname, len, len,
5420Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Device"),
5430Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Status"),
5440Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Length"),
5450Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5460Sstevel@tonic-gate goto out;
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate } else {
5490Sstevel@tonic-gate if (fprintf(fp,
5500Sstevel@tonic-gate "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n",
5510Sstevel@tonic-gate hspp->hspnamep->hspname, len, len,
5520Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Device"),
5530Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Status"),
5540Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Length"),
5550Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5560Sstevel@tonic-gate goto out;
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate } else {
5600Sstevel@tonic-gate /*
5610Sstevel@tonic-gate * This allows the length
5620Sstevel@tonic-gate * of the ctd to vary from small to large without
5630Sstevel@tonic-gate * looking horrible.
5640Sstevel@tonic-gate */
5650Sstevel@tonic-gate len = 0;
5660Sstevel@tonic-gate for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
5670Sstevel@tonic-gate len = max(len, strlen(hspp->
5680Sstevel@tonic-gate hotspares.hotspares_val[hsi].hsnamep->cname));
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
5710Sstevel@tonic-gate len += 2;
5720Sstevel@tonic-gate if (options & PRINT_LARGEDEVICES) {
5730Sstevel@tonic-gate if (fprintf(fp,
5740Sstevel@tonic-gate "%s: %u hot spares (%d big device(s))\n\t%-*.*s "
5750Sstevel@tonic-gate "%-12.12s%-8.6s\t\t%s\n",
5760Sstevel@tonic-gate hspp->hspnamep->hspname,
5770Sstevel@tonic-gate hspp->hotspares.hotspares_len,
5780Sstevel@tonic-gate large_hs_dev_cnt, len, len,
5790Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Device"),
5800Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Status"),
5810Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Length"),
5820Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5830Sstevel@tonic-gate goto out;
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate } else {
5860Sstevel@tonic-gate if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s "
5870Sstevel@tonic-gate "%-12.12s%-8.6s\t\t%s\n",
5880Sstevel@tonic-gate hspp->hspnamep->hspname,
5890Sstevel@tonic-gate hspp->hotspares.hotspares_len, len, len,
5900Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Device"),
5910Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Status"),
5920Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Length"),
5930Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5940Sstevel@tonic-gate goto out;
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate /* print hotspares */
6000Sstevel@tonic-gate for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
6010Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
6020Sstevel@tonic-gate char *cname = hsp->hsnamep->cname;
6030Sstevel@tonic-gate char *hs_state;
6040Sstevel@tonic-gate md_timeval32_t tv;
6050Sstevel@tonic-gate char *timep;
6060Sstevel@tonic-gate ddi_devid_t dtp;
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate /* populate the key in the name_p structure */
6090Sstevel@tonic-gate if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) {
6100Sstevel@tonic-gate return (-1);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate if (options & PRINT_LARGEDEVICES) {
6141623Stw21770 if ((hsp->revision & MD_64BIT_META_DEV) == 0)
6150Sstevel@tonic-gate continue;
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate /* determine if devid does NOT exist */
6180Sstevel@tonic-gate if (options & PRINT_DEVID) {
6190Sstevel@tonic-gate if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
6200Sstevel@tonic-gate didnp->key, ep)) == NULL)
6210Sstevel@tonic-gate devid = dgettext(TEXT_DOMAIN, "No ");
6220Sstevel@tonic-gate else {
6230Sstevel@tonic-gate devid = dgettext(TEXT_DOMAIN, "Yes");
6240Sstevel@tonic-gate free(dtp);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate /* print hotspare */
6280Sstevel@tonic-gate hs_state = hs_state_to_name(hsp, &tv);
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate * This allows the length
6310Sstevel@tonic-gate * of the ctd to vary from small to large without
6320Sstevel@tonic-gate * looking horrible.
6330Sstevel@tonic-gate */
6340Sstevel@tonic-gate if (! (options & PRINT_TIMES)) {
6350Sstevel@tonic-gate if (fprintf(fp,
6360Sstevel@tonic-gate " %-*s %-12s %lld blocks\t%s\n",
6370Sstevel@tonic-gate len, cname, hs_state,
6380Sstevel@tonic-gate hsp->size, devid) == EOF) {
6390Sstevel@tonic-gate goto out;
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate } else {
6420Sstevel@tonic-gate timep = meta_print_time(&tv);
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate if (fprintf(fp,
6450Sstevel@tonic-gate " %-*s\t %-11s %8lld blocks%s\t%s\n",
6460Sstevel@tonic-gate len, cname, hs_state,
6470Sstevel@tonic-gate hsp->size, devid, timep) == EOF) {
6480Sstevel@tonic-gate goto out;
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate /* add extra line */
6540Sstevel@tonic-gate if (fprintf(fp, "\n") == EOF)
6550Sstevel@tonic-gate goto out;
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate /* success */
6580Sstevel@tonic-gate rval = 0;
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate /* cleanup, return error */
6610Sstevel@tonic-gate out:
6620Sstevel@tonic-gate if (rval != 0)
6630Sstevel@tonic-gate (void) mdsyserror(ep, errno, fname);
6640Sstevel@tonic-gate return (rval);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate * print/report hsp
6690Sstevel@tonic-gate */
6700Sstevel@tonic-gate int
meta_hsp_print(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)6710Sstevel@tonic-gate meta_hsp_print(
6720Sstevel@tonic-gate mdsetname_t *sp,
6730Sstevel@tonic-gate mdhspname_t *hspnp,
6740Sstevel@tonic-gate mdnamelist_t **nlpp,
6750Sstevel@tonic-gate char *fname,
6760Sstevel@tonic-gate FILE *fp,
6770Sstevel@tonic-gate mdprtopts_t options,
6780Sstevel@tonic-gate md_error_t *ep
6790Sstevel@tonic-gate )
6800Sstevel@tonic-gate {
6810Sstevel@tonic-gate md_hsp_t *hspp;
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate /* should have same set */
6840Sstevel@tonic-gate assert(sp != NULL);
6851623Stw21770 assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
6861623Stw21770 sp->setno == HSP_SET(hspnp->hsp));
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /* print all hsps */
6890Sstevel@tonic-gate if (hspnp == NULL) {
6900Sstevel@tonic-gate mdhspnamelist_t *hspnlp = NULL;
6910Sstevel@tonic-gate mdhspnamelist_t *p;
6920Sstevel@tonic-gate int cnt;
6930Sstevel@tonic-gate int rval = 0;
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0)
6960Sstevel@tonic-gate return (-1);
6970Sstevel@tonic-gate else if (cnt == 0)
6980Sstevel@tonic-gate return (0);
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate /* recurse */
7010Sstevel@tonic-gate for (p = hspnlp; (p != NULL); p = p->next) {
7020Sstevel@tonic-gate mdhspname_t *hspnp = p->hspnamep;
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate if (meta_hsp_print(sp, hspnp, nlpp, fname, fp,
7050Sstevel@tonic-gate options, ep) != 0)
7060Sstevel@tonic-gate rval = -1;
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate /* cleanup, return success */
7100Sstevel@tonic-gate metafreehspnamelist(hspnlp);
7110Sstevel@tonic-gate return (rval);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate /* get unit structure */
7150Sstevel@tonic-gate if ((hspp = meta_get_hsp_common(sp, hspnp,
7160Sstevel@tonic-gate ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
7170Sstevel@tonic-gate return (-1);
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate /* print appropriate detail */
7200Sstevel@tonic-gate if (options & PRINT_SHORT)
7210Sstevel@tonic-gate return (hsp_print(hspp, fname, fp, ep));
7220Sstevel@tonic-gate else
7230Sstevel@tonic-gate return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp));
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate /*
7270Sstevel@tonic-gate * check for valid hotspare pool
7280Sstevel@tonic-gate */
7290Sstevel@tonic-gate int
metachkhsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)7300Sstevel@tonic-gate metachkhsp(
7310Sstevel@tonic-gate mdsetname_t *sp,
7320Sstevel@tonic-gate mdhspname_t *hspnp,
7330Sstevel@tonic-gate md_error_t *ep
7340Sstevel@tonic-gate )
7350Sstevel@tonic-gate {
7360Sstevel@tonic-gate if (meta_get_hsp(sp, hspnp, ep) == NULL)
7370Sstevel@tonic-gate return (-1);
7380Sstevel@tonic-gate return (0);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate /*
7420Sstevel@tonic-gate * invalidate hotspare pool info
7430Sstevel@tonic-gate */
7440Sstevel@tonic-gate void
meta_invalidate_hsp(mdhspname_t * hspnp)7450Sstevel@tonic-gate meta_invalidate_hsp(
7460Sstevel@tonic-gate mdhspname_t *hspnp
7470Sstevel@tonic-gate )
7480Sstevel@tonic-gate {
7490Sstevel@tonic-gate md_hsp_t *hspp = hspnp->unitp;
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate /* free it up */
7520Sstevel@tonic-gate if (hspp == NULL)
7530Sstevel@tonic-gate return;
7540Sstevel@tonic-gate meta_free_hsp(hspp);
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate /* clear cache */
7570Sstevel@tonic-gate hspnp->unitp = NULL;
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate /*
7611623Stw21770 * FUNCTION: del_hsp_name_mn_sides()
7621623Stw21770 * INPUT: sp - set name
7631623Stw21770 * curside - side of this node
7641623Stw21770 * key - key of records to delete
7651623Stw21770 * OUTPUT: ep - error information
7661623Stw21770 * RETURNS: none.
7671623Stw21770 * PURPOSE: There are name records for each side in a set. This
7681623Stw21770 * function deletes the records associated with the specified
7691623Stw21770 * key for all sides except curside. This function is used
7701623Stw21770 * when the set is a multinode set.
7711623Stw21770 */
7721623Stw21770 static void
del_hsp_name_mn_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)7731623Stw21770 del_hsp_name_mn_sides(
7741623Stw21770 mdsetname_t *sp,
7751623Stw21770 md_set_desc *sd,
7761623Stw21770 side_t curside,
7771623Stw21770 mdkey_t key,
7781623Stw21770 md_error_t *ep
7791623Stw21770 )
7801623Stw21770 {
7811623Stw21770 md_error_t first_error = MDNULLERROR;
7821623Stw21770 int error_seen = FALSE;
7831623Stw21770 md_mnnode_desc *nd;
7841623Stw21770
7851623Stw21770 for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
7861623Stw21770 if (nd->nd_nodeid == curside)
7871623Stw21770 continue;
7881623Stw21770 if (del_name(sp, nd->nd_nodeid, key, &first_error) == -1) {
7891623Stw21770 if (error_seen == FALSE) {
7901623Stw21770 error_seen = TRUE;
7911623Stw21770 (void) mdstealerror(ep, &first_error);
7921623Stw21770 }
7931623Stw21770 }
7941623Stw21770 }
7951623Stw21770 }
7961623Stw21770
7971623Stw21770 /*
7981623Stw21770 * FUNCTION: del_hsp_name_trad_sides()
7991623Stw21770 * INPUT: sp - set name
8001623Stw21770 * curside - side of this node
8011623Stw21770 * key - key of records to delete
8021623Stw21770 * OUTPUT: ep - error information
8031623Stw21770 * RETURNS: none.
8041623Stw21770 * PURPOSE: There are name records for each side in a set. This
8051623Stw21770 * function deletes the records associated with the specified
8061623Stw21770 * key for all sides except curside. This function is used
8071623Stw21770 * when the set is a traditional set.
8081623Stw21770 */
8091623Stw21770 static void
del_hsp_name_trad_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)8101623Stw21770 del_hsp_name_trad_sides(
8111623Stw21770 mdsetname_t *sp,
8121623Stw21770 md_set_desc *sd,
8131623Stw21770 side_t curside,
8141623Stw21770 mdkey_t key,
8151623Stw21770 md_error_t *ep
8161623Stw21770 )
8171623Stw21770 {
8181623Stw21770 int error_seen = FALSE;
8191623Stw21770 md_error_t first_error = MDNULLERROR;
8201623Stw21770 int i;
8211623Stw21770
8221623Stw21770 for (i = 0; i < MD_MAXSIDES; i++) {
8231623Stw21770 if (i == curside)
8241623Stw21770 continue;
8251623Stw21770 if (sd->sd_nodes[i][0] != '\0') {
8261623Stw21770 if (del_name(sp, i, key, &first_error) == -1) {
8271623Stw21770 if (error_seen == FALSE) {
8281623Stw21770 error_seen = TRUE;
8291623Stw21770 (void) mdstealerror(ep, &first_error);
8301623Stw21770 }
8311623Stw21770 }
8321623Stw21770 }
8331623Stw21770 }
8341623Stw21770 }
8351623Stw21770
8361623Stw21770 /*
8371623Stw21770 * FUNCTION: del_hsp_keys()
8381623Stw21770 * INPUT: sp - set name
8391623Stw21770 * hspid - ID of records to delete
8401623Stw21770 * OUTPUT: ep - error information
8411623Stw21770 * RETURNS: 0 - success
8421623Stw21770 * -1 - error
8431623Stw21770 * PURPOSE: Remove the NM records associated with hspid from all sides
8441623Stw21770 * of the set. Missing records are not considered to be an
8451623Stw21770 * error. The key associated with the current side is removed
8461623Stw21770 * last.
8471623Stw21770 *
8481623Stw21770 * This function is very similar to del_key_name(), except it
8491623Stw21770 * does not require any device look up. This is because the
8501623Stw21770 * hot spare pool is not a device.
8511623Stw21770 */
8521623Stw21770 static int
del_hsp_keys(mdsetname_t * sp,hsp_t hspid,md_error_t * ep)8531623Stw21770 del_hsp_keys(mdsetname_t *sp, hsp_t hspid, md_error_t *ep)
8541623Stw21770 {
8551623Stw21770 md_error_t first_error = MDNULLERROR;
8561623Stw21770 mdkey_t key = HSP_ID_TO_KEY(hspid);
8571623Stw21770 md_set_desc *sd;
8581623Stw21770 side_t thisside; /* Side # of this node. */
8591623Stw21770
8601623Stw21770 /*
8611623Stw21770 * If there is no key, this means that the hot spare was created
8621623Stw21770 * before the introduction of friendly names. Thus, the is no NM
8631623Stw21770 * record and nothing for us to do in this function.
8641623Stw21770 */
8651623Stw21770 if (key == MD_KEYBAD)
8661623Stw21770 return (0);
8671623Stw21770
8681623Stw21770 /* Find our current side */
8691623Stw21770 mdclrerror(ep);
8701623Stw21770 thisside = getmyside(sp, ep);
8711623Stw21770 if (! mdisok(ep))
8721623Stw21770 return (-1);
8731623Stw21770
8741623Stw21770 /*
8751623Stw21770 * If not the local set, we need to process the non-local sides
8761623Stw21770 * first.
8771623Stw21770 */
8781623Stw21770 if (!metaislocalset(sp)) {
8791623Stw21770 if ((sd = metaget_setdesc(sp, ep)) == NULL)
8801623Stw21770 return (-1);
8811623Stw21770 if (MD_MNSET_DESC(sd)) {
8821623Stw21770 /* Multinode set. Sides are in a linked list. */
8831623Stw21770 del_hsp_name_mn_sides(sp, sd, thisside, key,
8841623Stw21770 &first_error);
8851623Stw21770 } else {
8861623Stw21770 /* Sides are in an array. */
8871623Stw21770 del_hsp_name_trad_sides(sp, sd, thisside, key,
8881623Stw21770 &first_error);
8891623Stw21770 }
8901623Stw21770 }
8911623Stw21770
8921623Stw21770 /* Now delete the name for the current side. */
8931623Stw21770 (void) del_name(sp, thisside, key, ep);
8941623Stw21770 if (! mdisok(&first_error))
8951623Stw21770 (void) mdstealerror(ep, &first_error);
8961623Stw21770 return (mdisok(ep) ? 0 : -1);
8971623Stw21770 }
8981623Stw21770
8991623Stw21770 /*
9001623Stw21770 * FUNCTION: add_hsp_name_mn_sides()
9011623Stw21770 * INPUT: sp - set name
9021623Stw21770 * curside - side number for this node
9031623Stw21770 * key - key to use for the name record
9041623Stw21770 * hsp_name - name of the hot spare
9051623Stw21770 * OUTPUT: ep - error information
9061623Stw21770 * RETURNS: 0 indicates success, and -1 indicates failure.
9071623Stw21770 * PURPOSE: Once the name record has been added for the current side,
9081623Stw21770 * this function adds the record to the remaining sides. This
9091623Stw21770 * function is to be used when the set is a multinode set.
9101623Stw21770 * The side designated by curside will be ignored when adding
9111623Stw21770 * records.
9121623Stw21770 */
9131623Stw21770 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)9141623Stw21770 add_hsp_name_mn_sides(
9151623Stw21770 mdsetname_t *sp,
9161623Stw21770 md_set_desc *sd,
9171623Stw21770 side_t curside,
9181623Stw21770 mdkey_t key,
9191623Stw21770 char *hsp_name,
9201623Stw21770 md_error_t *ep
9211623Stw21770 )
9221623Stw21770 {
9231623Stw21770 md_mnnode_desc *nd;
9241623Stw21770
9251623Stw21770 for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
9261623Stw21770 if (nd->nd_nodeid == curside)
9271623Stw21770 continue;
9281623Stw21770 if (add_name(sp, nd->nd_nodeid, key, MD_HOTSPARES,
9291945Sjeanm minor(NODEV), hsp_name, NULL, NULL, ep) == -1) {
9301623Stw21770 return (-1);
9311623Stw21770 }
9321623Stw21770 }
9331623Stw21770 return (0);
9341623Stw21770 }
9351623Stw21770
9361623Stw21770 /*
9371623Stw21770 * FUNCTION: add_hsp_name_trad_sides()
9381623Stw21770 * INPUT: sp - set name
9391623Stw21770 * curside - side number for this node
9401623Stw21770 * key - key to use for the name record
9411623Stw21770 * hsp_name - name of the hot spare
9421623Stw21770 * OUTPUT: ep - error information
9431623Stw21770 * RETURNS: 0 indicates success, and -1 indicates failure.
9441623Stw21770 * PURPOSE: Once the name record has been added for the current side,
9451623Stw21770 * this function adds the record to the remaining sides. This
9461623Stw21770 * function is to be used when the set is a traditional set.
9471623Stw21770 * The side designated by curside will be ignored when adding
9481623Stw21770 * records.
9491623Stw21770 */
9501623Stw21770 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)9511623Stw21770 add_hsp_name_trad_sides(
9521623Stw21770 mdsetname_t *sp,
9531623Stw21770 md_set_desc *sd,
9541623Stw21770 side_t curside,
9551623Stw21770 mdkey_t key,
9561623Stw21770 char *hsp_name,
9571623Stw21770 md_error_t *ep
9581623Stw21770 )
9591623Stw21770 {
9601623Stw21770 int i;
9611623Stw21770
9621623Stw21770 for (i = 0; i < MD_MAXSIDES; i++) {
9631623Stw21770 if (i == curside)
9641623Stw21770 continue;
9651623Stw21770 if (sd->sd_nodes[i][0] != '\0') {
9661623Stw21770 if (add_name(sp, i, key, MD_HOTSPARES, minor(NODEV),
9671945Sjeanm hsp_name, NULL, NULL, ep) == -1) {
9681623Stw21770 return (-1);
9691623Stw21770 }
9701623Stw21770 }
9711623Stw21770 }
9721623Stw21770 return (0);
9731623Stw21770 }
9741623Stw21770
9751623Stw21770 /*
9761623Stw21770 * FUNCTION: add_hsp_name()
9771623Stw21770 * INPUT: sp - Name of the set containing the hsp
9781623Stw21770 * hsp_name - Hot spare pool name to be added
9791623Stw21770 * OUTPUT: ep - Error information
9801623Stw21770 * RETURNS: If successful the key of the newly added record is
9811623Stw21770 * returned. MD_KEYBAD is returned to indicate a failure.
9821623Stw21770 * PURPOSE: This function creates a new NM record containing the name
9831623Stw21770 * of the hotspare pool. A record containing the name is
9841623Stw21770 * added to each active side, but the record is added first to
9851623Stw21770 * the current side. This function is modeled on
9861623Stw21770 * add_key_name() in meta_namespace. The difference is that
9871623Stw21770 * there is no device associated with a hot spare pool
9881623Stw21770 */
9891623Stw21770 static hsp_t
add_hsp_name(mdsetname_t * sp,char * hsp_name,md_error_t * ep)9901623Stw21770 add_hsp_name(
9911623Stw21770 mdsetname_t *sp,
9921623Stw21770 char *hsp_name,
9931623Stw21770 md_error_t *ep
9941623Stw21770 )
9951623Stw21770 {
9961623Stw21770 md_error_t ignore_error = MDNULLERROR;
9971623Stw21770 mdkey_t key;
9981623Stw21770 md_set_desc *sd;
9991623Stw21770 side_t thisside; /* Side # of this node. */
10001623Stw21770
10011623Stw21770 if (sp == NULL) {
10021623Stw21770 (void) mderror(ep, MDE_NO_SET, NULL);
10031623Stw21770 return (MD_KEYBAD);
10041623Stw21770 }
10051623Stw21770 if (hsp_name == NULL) {
10061623Stw21770 (void) mderror(ep, MDE_INVAL_HSOP, NULL);
10071623Stw21770 return (MD_KEYBAD);
10081623Stw21770 }
10091623Stw21770
10101623Stw21770 mdclrerror(ep);
10111623Stw21770 thisside = getmyside(sp, ep);
10121623Stw21770 if (! mdisok(ep))
10131623Stw21770 return (MD_HSPID_WILD);
10141623Stw21770
10151623Stw21770 /* First add the record for the side of the current node. */
10161623Stw21770 key = add_name(sp, thisside, MD_KEYWILD, MD_HOTSPARES, minor(NODEV),
10171945Sjeanm hsp_name, NULL, NULL, ep);
10181623Stw21770 if (key == -1) {
10191623Stw21770 goto cleanup;
10201623Stw21770 }
10211623Stw21770
10221623Stw21770 /* Make sure that we can use the key */
10231623Stw21770 if (!HSP_KEY_OK(key)) {
10241623Stw21770 (void) mdhsperror(ep, MDE_HSP_CREATE_FAILURE, MD_HSPID_WILD,
10251623Stw21770 hsp_name);
10261623Stw21770 goto cleanup;
10271623Stw21770 }
10281623Stw21770
10291623Stw21770 /*
10301623Stw21770 * Now that we have a key, we will use it to add a record to the
10311623Stw21770 * rest of the sides in the set. For multinode sets, the sides are
10321623Stw21770 * in a linked list that is anchored on the set descriptor. For
10331623Stw21770 * traditional sets the side information is in an array in the set
10341623Stw21770 * descriptor.
10351623Stw21770 */
10361623Stw21770 if (!metaislocalset(sp)) {
10371623Stw21770 if ((sd = metaget_setdesc(sp, ep)) == NULL) {
10381623Stw21770 goto cleanup;
10391623Stw21770 }
10401623Stw21770 if (MD_MNSET_DESC(sd)) {
10411623Stw21770 /* Multinode set. Sides are in linked list. */
10421623Stw21770 if (add_hsp_name_mn_sides(sp, sd, thisside, key,
10431623Stw21770 hsp_name, ep) == -1) {
10441623Stw21770 goto cleanup;
10451623Stw21770 }
10461623Stw21770 } else {
10471623Stw21770 /* Traditional set. Sides are in an array. */
10481623Stw21770 if (add_hsp_name_trad_sides(sp, sd, thisside, key,
10491623Stw21770 hsp_name, ep) == -1) {
10501623Stw21770 goto cleanup;
10511623Stw21770 }
10521623Stw21770 }
10531623Stw21770 }
10541623Stw21770
10551623Stw21770 return (KEY_TO_HSP_ID(sp->setno, key));
10561623Stw21770
10571623Stw21770 cleanup:
10581623Stw21770 /* Get rid records that we added. */
10591623Stw21770 (void) del_hsp_keys(sp, KEY_TO_HSP_ID(sp->setno, key), &ignore_error);
10601623Stw21770 return (MD_HSPID_WILD);
10611623Stw21770 }
10621623Stw21770
10631623Stw21770 /*
10640Sstevel@tonic-gate * add hotspares and/or hotspare pool
10650Sstevel@tonic-gate */
10660Sstevel@tonic-gate int
meta_hs_add(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)10670Sstevel@tonic-gate meta_hs_add(
10680Sstevel@tonic-gate mdsetname_t *sp,
10690Sstevel@tonic-gate mdhspname_t *hspnp,
10700Sstevel@tonic-gate mdnamelist_t *hsnlp,
10710Sstevel@tonic-gate mdcmdopts_t options,
10720Sstevel@tonic-gate md_error_t *ep
10730Sstevel@tonic-gate )
10740Sstevel@tonic-gate {
10751623Stw21770 md_error_t ignore_error = MDNULLERROR;
10760Sstevel@tonic-gate mdnamelist_t *p;
10770Sstevel@tonic-gate set_hs_params_t shs;
10781623Stw21770 side_t thisside;
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate /* should have a set */
10810Sstevel@tonic-gate assert(sp != NULL);
10821623Stw21770 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate /* clear cache */
10850Sstevel@tonic-gate meta_invalidate_hsp(hspnp);
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate /* setup hotspare pool info */
10880Sstevel@tonic-gate (void) memset(&shs, 0, sizeof (shs));
10890Sstevel@tonic-gate shs.shs_cmd = ADD_HOT_SPARE;
10900Sstevel@tonic-gate MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
10910Sstevel@tonic-gate
10921623Stw21770 /* Get key for hot spare pool name record. */
10931623Stw21770 if (options & MDCMD_DOIT) {
10941623Stw21770 /* First see if the name record already exists. */
10951623Stw21770 mdclrerror(ep);
10961623Stw21770 thisside = getmyside(sp, ep);
10971623Stw21770 if (! mdisok(ep))
10981623Stw21770 return (-1);
10991623Stw21770 shs.shs_hot_spare_pool =
11001623Stw21770 meta_gethspnmentbyname(sp->setno, thisside,
11011623Stw21770 hspnp->hspname, ep);
11021623Stw21770 if (! mdisok(ep)) {
11031623Stw21770 /*
11041623Stw21770 * If the error is ENOENT, then we will create a
11051623Stw21770 * hot spare pool name records. For other types of
11061623Stw21770 * errors, however, we'll bail out.
11071623Stw21770 */
11081623Stw21770 if (! mdissyserror(ep, ENOENT))
11091623Stw21770 return (-1);
11101623Stw21770 mdclrerror(ep);
11111623Stw21770 /* make sure that the name isn't already in use */
11121623Stw21770 if (is_existing_metadevice(sp, hspnp->hspname))
11131623Stw21770 return (mderror(ep, MDE_NAME_IN_USE,
11141623Stw21770 hspnp->hspname));
11151623Stw21770 if ((shs.shs_hot_spare_pool =
11161623Stw21770 add_hsp_name(sp, hspnp->hspname, ep)) ==
11171623Stw21770 MD_HSPID_WILD) {
11181623Stw21770 return (-1);
11191623Stw21770 }
11201623Stw21770 }
11211623Stw21770 }
11221623Stw21770
11230Sstevel@tonic-gate /* add empty hotspare pool */
11240Sstevel@tonic-gate if (hsnlp == NULL) {
11250Sstevel@tonic-gate shs.shs_options = HS_OPT_POOL;
11260Sstevel@tonic-gate /* If DOIT is not set, it's a dryrun */
11270Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
11280Sstevel@tonic-gate shs.shs_options |= HS_OPT_DRYRUN;
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
11311623Stw21770 hspnp->hspname) != 0) {
11321623Stw21770 if (options & MDCMD_DOIT) {
11331623Stw21770 (void) del_hsp_keys(sp,
11341623Stw21770 shs.shs_hot_spare_pool,
11351623Stw21770 &ignore_error);
11361623Stw21770 }
11370Sstevel@tonic-gate return (mdstealerror(ep, &shs.mde));
11381623Stw21770 }
11390Sstevel@tonic-gate goto success;
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate
11420Sstevel@tonic-gate /* add hotspares */
11430Sstevel@tonic-gate shs.shs_options = HS_OPT_NONE;
11440Sstevel@tonic-gate /* If DOIT is not set, it's a dryrun */
11450Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
11460Sstevel@tonic-gate shs.shs_options |= HS_OPT_DRYRUN;
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate for (p = hsnlp; (p != NULL); p = p->next) {
11490Sstevel@tonic-gate mdname_t *hsnp = p->namep;
11500Sstevel@tonic-gate diskaddr_t size, label, start_blk;
11510Sstevel@tonic-gate
11520Sstevel@tonic-gate /* should be in same set */
11531623Stw21770 assert(hspnp->hsp == MD_HSP_NONE ||
11541623Stw21770 sp->setno == HSP_SET(hspnp->hsp));
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate /* check it out */
11570Sstevel@tonic-gate if (meta_check_hotspare(sp, hsnp, ep) != 0)
11580Sstevel@tonic-gate return (-1);
11590Sstevel@tonic-gate if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
11600Sstevel@tonic-gate return (-1);
11610Sstevel@tonic-gate else if (size == 0)
11620Sstevel@tonic-gate return (mdsyserror(ep, ENOSPC, hsnp->cname));
11630Sstevel@tonic-gate if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
11640Sstevel@tonic-gate return (-1);
11650Sstevel@tonic-gate if ((start_blk = metagetstart(sp, hsnp, ep))
11660Sstevel@tonic-gate == MD_DISKADDR_ERROR)
11670Sstevel@tonic-gate return (-1);
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate shs.shs_size_option = meta_check_devicesize(size);
11700Sstevel@tonic-gate
11710Sstevel@tonic-gate /* In dryrun mode (DOIT not set) we must not alter the mddb */
11720Sstevel@tonic-gate if (options & MDCMD_DOIT) {
11730Sstevel@tonic-gate /* store name in namespace */
11740Sstevel@tonic-gate if (add_key_name(sp, hsnp, NULL, ep) != 0)
11750Sstevel@tonic-gate return (-1);
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate /* add hotspare and/or hotspare pool */
11790Sstevel@tonic-gate shs.shs_component_old = hsnp->dev;
11800Sstevel@tonic-gate shs.shs_start_blk = start_blk;
11810Sstevel@tonic-gate shs.shs_has_label = ((label > 0) ? 1 : 0);
11820Sstevel@tonic-gate shs.shs_number_blks = size;
11830Sstevel@tonic-gate shs.shs_key_old = hsnp->key;
11840Sstevel@tonic-gate if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
11850Sstevel@tonic-gate if ((options & MDCMD_DOIT) &&
11860Sstevel@tonic-gate (shs.shs_options != HS_OPT_POOL)) {
11870Sstevel@tonic-gate (void) del_key_name(sp, hsnp, ep);
11880Sstevel@tonic-gate }
11890Sstevel@tonic-gate return (mdstealerror(ep, &shs.mde));
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /* print success message */
11940Sstevel@tonic-gate success:
11950Sstevel@tonic-gate if (options & MDCMD_PRINT) {
11960Sstevel@tonic-gate if ((options & MDCMD_INIT) || (hsnlp == NULL)) {
11970Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
11980Sstevel@tonic-gate "%s: Hotspare pool is setup\n"),
11990Sstevel@tonic-gate hspnp->hspname);
12000Sstevel@tonic-gate } else if (hsnlp->next == NULL) {
12010Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
12020Sstevel@tonic-gate "%s: Hotspare is added\n"),
12030Sstevel@tonic-gate hspnp->hspname);
12040Sstevel@tonic-gate } else {
12050Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
12060Sstevel@tonic-gate "%s: Hotspares are added\n"),
12070Sstevel@tonic-gate hspnp->hspname);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate (void) fflush(stdout);
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate
12120Sstevel@tonic-gate /* return success */
12130Sstevel@tonic-gate return (0);
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate /*
12171623Stw21770 * FUNCTION: meta_hsp_delete()
12181623Stw21770 * INPUT: sp - Name of the set containing the hsp
12191623Stw21770 * hspnp - Hot spare pool name information
12201623Stw21770 * options - Options from command line
12211623Stw21770 * OUTPUT: ep - Error information
12221623Stw21770 * RETURNS: 0 on success and -1 on failure.
12231623Stw21770 * PURPOSE: Common code to delete an empty hot spare pool.
12241623Stw21770 */
12251623Stw21770 static int
meta_hsp_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)12261623Stw21770 meta_hsp_delete(
12271623Stw21770 mdsetname_t *sp,
12281623Stw21770 mdhspname_t *hspnp,
12291623Stw21770 mdcmdopts_t options,
12301623Stw21770 md_error_t *ep
12311623Stw21770 )
12321623Stw21770 {
12331623Stw21770 set_hs_params_t shs;
12341623Stw21770
12351623Stw21770 /* setup hotspare pool info */
12361623Stw21770 (void) memset(&shs, 0, sizeof (shs));
12371623Stw21770 shs.shs_hot_spare_pool = hspnp->hsp;
12381623Stw21770 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
12391623Stw21770 shs.shs_cmd = DELETE_HOT_SPARE;
12401623Stw21770 shs.shs_options = HS_OPT_POOL;
12411623Stw21770 /* If DOIT is not set, it's a dryrun */
12421623Stw21770 if ((options & MDCMD_DOIT) == 0) {
12431623Stw21770 shs.shs_options |= HS_OPT_DRYRUN;
12441623Stw21770 }
12451623Stw21770
12461623Stw21770 /* Remove hsp record. */
12471623Stw21770 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
12481623Stw21770 hspnp->hspname) != 0)
12491623Stw21770 return (mdstealerror(ep, &shs.mde));
12501623Stw21770
12511623Stw21770 /* Get rid of hsp NM records */
12521623Stw21770 if ((options & MDCMD_DOIT) &&
12531623Stw21770 (del_hsp_keys(sp, hspnp->hsp, ep) == -1)) {
12541623Stw21770 return (-1);
12551623Stw21770 }
12561623Stw21770 return (0);
12571623Stw21770 }
12581623Stw21770
12591623Stw21770 /*
12600Sstevel@tonic-gate * delete hotspares from pool
12610Sstevel@tonic-gate */
12620Sstevel@tonic-gate int
meta_hs_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)12630Sstevel@tonic-gate meta_hs_delete(
12640Sstevel@tonic-gate mdsetname_t *sp,
12650Sstevel@tonic-gate mdhspname_t *hspnp,
12660Sstevel@tonic-gate mdnamelist_t *hsnlp,
12670Sstevel@tonic-gate mdcmdopts_t options,
12680Sstevel@tonic-gate md_error_t *ep
12690Sstevel@tonic-gate )
12700Sstevel@tonic-gate {
12710Sstevel@tonic-gate mdnamelist_t *p;
12720Sstevel@tonic-gate set_hs_params_t shs;
12730Sstevel@tonic-gate
12740Sstevel@tonic-gate /* should have a set */
12750Sstevel@tonic-gate assert(sp != NULL);
12761623Stw21770 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
12770Sstevel@tonic-gate
12780Sstevel@tonic-gate /* clear cache */
12790Sstevel@tonic-gate meta_invalidate_hsp(hspnp);
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate /* setup hotspare pool info */
12820Sstevel@tonic-gate (void) memset(&shs, 0, sizeof (shs));
12830Sstevel@tonic-gate shs.shs_hot_spare_pool = hspnp->hsp;
12840Sstevel@tonic-gate MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
12850Sstevel@tonic-gate shs.shs_cmd = DELETE_HOT_SPARE;
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate /* delete empty hotspare pool */
12880Sstevel@tonic-gate if (hsnlp == NULL) {
12891623Stw21770 if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
12901623Stw21770 return (-1);
12910Sstevel@tonic-gate goto success;
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate /* delete hotspares */
12950Sstevel@tonic-gate shs.shs_options = HS_OPT_NONE;
12960Sstevel@tonic-gate /* If DOIT is not set, it's a dryrun */
12970Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
12980Sstevel@tonic-gate shs.shs_options |= HS_OPT_DRYRUN;
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate for (p = hsnlp; (p != NULL); p = p->next) {
13010Sstevel@tonic-gate mdname_t *hsnp = p->namep;
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate /* should be in same set */
13041623Stw21770 assert(hspnp->hsp == MD_HSP_NONE ||
13051623Stw21770 sp->setno == HSP_SET(hspnp->hsp));
13060Sstevel@tonic-gate
13070Sstevel@tonic-gate /* delete hotspare */
13080Sstevel@tonic-gate shs.shs_component_old = hsnp->dev;
13090Sstevel@tonic-gate meta_invalidate_name(hsnp);
13100Sstevel@tonic-gate if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0)
13110Sstevel@tonic-gate return (mdstealerror(ep, &shs.mde));
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate /* print success message */
13150Sstevel@tonic-gate success:
13160Sstevel@tonic-gate if (options & MDCMD_PRINT) {
13170Sstevel@tonic-gate if (hsnlp == NULL) {
13180Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
13190Sstevel@tonic-gate "%s: Hotspare pool is cleared\n"),
13200Sstevel@tonic-gate hspnp->hspname);
13210Sstevel@tonic-gate } else if (hsnlp->next == NULL) {
13220Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
13230Sstevel@tonic-gate "%s: Hotspare is deleted\n"),
13240Sstevel@tonic-gate hspnp->hspname);
13250Sstevel@tonic-gate } else {
13260Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
13270Sstevel@tonic-gate "%s: Hotspares are deleted\n"),
13280Sstevel@tonic-gate hspnp->hspname);
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate (void) fflush(stdout);
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate /* return success */
13340Sstevel@tonic-gate return (0);
13350Sstevel@tonic-gate }
13360Sstevel@tonic-gate
13370Sstevel@tonic-gate /*
13380Sstevel@tonic-gate * replace hotspare in pool
13390Sstevel@tonic-gate */
13400Sstevel@tonic-gate int
meta_hs_replace(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * oldnp,mdname_t * newnp,mdcmdopts_t options,md_error_t * ep)13410Sstevel@tonic-gate meta_hs_replace(
13420Sstevel@tonic-gate mdsetname_t *sp,
13430Sstevel@tonic-gate mdhspname_t *hspnp,
13440Sstevel@tonic-gate mdname_t *oldnp,
13450Sstevel@tonic-gate mdname_t *newnp,
13460Sstevel@tonic-gate mdcmdopts_t options,
13470Sstevel@tonic-gate md_error_t *ep
13480Sstevel@tonic-gate )
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate set_hs_params_t shs;
13510Sstevel@tonic-gate diskaddr_t size, label, start_blk;
13520Sstevel@tonic-gate md_dev64_t old_dev, new_dev;
13530Sstevel@tonic-gate diskaddr_t new_start_blk, new_end_blk;
13540Sstevel@tonic-gate int rebind;
13550Sstevel@tonic-gate char *new_devidp = NULL;
13560Sstevel@tonic-gate int ret;
13570Sstevel@tonic-gate md_set_desc *sd;
13580Sstevel@tonic-gate
13590Sstevel@tonic-gate /* should be in same set */
13600Sstevel@tonic-gate assert(sp != NULL);
13611623Stw21770 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
13620Sstevel@tonic-gate
13630Sstevel@tonic-gate /* save new binding incase this is a rebind where oldnp==newnp */
13640Sstevel@tonic-gate new_dev = newnp->dev;
13650Sstevel@tonic-gate new_start_blk = newnp->start_blk;
13660Sstevel@tonic-gate new_end_blk = newnp->end_blk;
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate /* invalidate, then get the hotspare (fill in oldnp from metadb) */
13690Sstevel@tonic-gate meta_invalidate_hsp(hspnp);
13700Sstevel@tonic-gate if (meta_get_hsp(sp, hspnp, ep) == NULL)
13710Sstevel@tonic-gate return (-1);
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate /* the old device binding is now established */
13740Sstevel@tonic-gate if ((old_dev = oldnp->dev) == NODEV64)
13750Sstevel@tonic-gate return (mdsyserror(ep, ENODEV, oldnp->cname));
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate /*
13780Sstevel@tonic-gate * check for the case where oldnp and newnp indicate the same
13790Sstevel@tonic-gate * device, but the dev_t of the device has changed between old
13800Sstevel@tonic-gate * and new. This is called a rebind. On entry the dev_t
13810Sstevel@tonic-gate * represents the new device binding determined from the
13820Sstevel@tonic-gate * filesystem (meta_getdev). After calling meta_get_hsp
13830Sstevel@tonic-gate * oldnp (and maybe newnp if this is a rebind) is updated based
13840Sstevel@tonic-gate * to the old binding from the metadb (done by metakeyname).
13850Sstevel@tonic-gate */
13860Sstevel@tonic-gate if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
13870Sstevel@tonic-gate (old_dev != new_dev)) {
13880Sstevel@tonic-gate rebind = 1;
13890Sstevel@tonic-gate } else {
13900Sstevel@tonic-gate rebind = 0;
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate if (rebind) {
13930Sstevel@tonic-gate newnp->dev = new_dev;
13940Sstevel@tonic-gate newnp->start_blk = new_start_blk;
13950Sstevel@tonic-gate newnp->end_blk = new_end_blk;
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate /*
13990Sstevel@tonic-gate * Save a copy of the devid associated with the new disk, the reason
14000Sstevel@tonic-gate * is that the meta_check_hotspare() call could cause the devid to
14010Sstevel@tonic-gate * be changed to that of the devid that is currently stored in the
14020Sstevel@tonic-gate * replica namespace for the disk in question. This devid could be
14030Sstevel@tonic-gate * stale if we are replacing the disk. The function that overwrites
14040Sstevel@tonic-gate * the devid is dr2drivedesc().
14050Sstevel@tonic-gate */
14060Sstevel@tonic-gate if (newnp->drivenamep->devid != NULL)
14070Sstevel@tonic-gate new_devidp = Strdup(newnp->drivenamep->devid);
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate /* if it's a multi-node diskset clear new_devidp */
14100Sstevel@tonic-gate if (!metaislocalset(sp)) {
14110Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == NULL) {
14120Sstevel@tonic-gate Free(new_devidp);
14130Sstevel@tonic-gate return (-1);
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate if (MD_MNSET_DESC(sd)) {
14160Sstevel@tonic-gate Free(new_devidp);
14170Sstevel@tonic-gate new_devidp = NULL;
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate /* check it out */
14220Sstevel@tonic-gate if (meta_check_hotspare(sp, newnp, ep) != 0) {
14230Sstevel@tonic-gate if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
14240Sstevel@tonic-gate Free(new_devidp);
14250Sstevel@tonic-gate return (-1);
14260Sstevel@tonic-gate }
14270Sstevel@tonic-gate mdclrerror(ep);
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
14300Sstevel@tonic-gate Free(new_devidp);
14310Sstevel@tonic-gate return (-1);
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
14340Sstevel@tonic-gate Free(new_devidp);
14350Sstevel@tonic-gate return (-1);
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
14380Sstevel@tonic-gate Free(new_devidp);
14390Sstevel@tonic-gate return (-1);
14400Sstevel@tonic-gate }
14410Sstevel@tonic-gate if (start_blk >= size) {
14420Sstevel@tonic-gate (void) mdsyserror(ep, ENOSPC, newnp->cname);
14430Sstevel@tonic-gate Free(new_devidp);
14440Sstevel@tonic-gate return (-1);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate /*
14480Sstevel@tonic-gate * Copy back the saved devid.
14490Sstevel@tonic-gate */
14500Sstevel@tonic-gate Free(newnp->drivenamep->devid);
14510Sstevel@tonic-gate if (new_devidp != NULL) {
14520Sstevel@tonic-gate newnp->drivenamep->devid = new_devidp;
14530Sstevel@tonic-gate new_devidp = NULL;
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate /* In dryrun mode (DOIT not set) we must not alter the mddb */
14570Sstevel@tonic-gate if (options & MDCMD_DOIT) {
14580Sstevel@tonic-gate /* store name in namespace */
14590Sstevel@tonic-gate if (add_key_name(sp, newnp, NULL, ep) != 0)
14600Sstevel@tonic-gate return (-1);
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate
14630Sstevel@tonic-gate if (rebind && !metaislocalset(sp)) {
14640Sstevel@tonic-gate /*
14650Sstevel@tonic-gate * We are 'rebind'ing a disk that is in a diskset so as well
14660Sstevel@tonic-gate * as updating the diskset's namespace the local set needs
14670Sstevel@tonic-gate * to be updated because it also contains a reference to the
14680Sstevel@tonic-gate * disk in question.
14690Sstevel@tonic-gate */
14700Sstevel@tonic-gate ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
14710Sstevel@tonic-gate ep);
14720Sstevel@tonic-gate
14730Sstevel@tonic-gate if (ret != METADEVADM_SUCCESS) {
14740Sstevel@tonic-gate md_error_t xep = mdnullerror;
14750Sstevel@tonic-gate
14760Sstevel@tonic-gate /*
14770Sstevel@tonic-gate * In dryrun mode (DOIT not set) we must not alter
14780Sstevel@tonic-gate * the mddb
14790Sstevel@tonic-gate */
14800Sstevel@tonic-gate if (options & MDCMD_DOIT) {
14810Sstevel@tonic-gate (void) del_key_name(sp, newnp, &xep);
14820Sstevel@tonic-gate mdclrerror(&xep);
14830Sstevel@tonic-gate return (-1);
14840Sstevel@tonic-gate }
14850Sstevel@tonic-gate }
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate /* replace hotspare */
14890Sstevel@tonic-gate (void) memset(&shs, 0, sizeof (shs));
14900Sstevel@tonic-gate
14910Sstevel@tonic-gate shs.shs_size_option = meta_check_devicesize(size);
14920Sstevel@tonic-gate
14930Sstevel@tonic-gate shs.shs_cmd = REPLACE_HOT_SPARE;
14940Sstevel@tonic-gate shs.shs_hot_spare_pool = hspnp->hsp;
14950Sstevel@tonic-gate MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
14960Sstevel@tonic-gate shs.shs_component_old = old_dev;
14970Sstevel@tonic-gate shs.shs_options = HS_OPT_NONE;
14980Sstevel@tonic-gate /* If DOIT is not set, it's a dryrun */
14990Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
15000Sstevel@tonic-gate shs.shs_options |= HS_OPT_DRYRUN;
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate shs.shs_component_new = new_dev;
15030Sstevel@tonic-gate shs.shs_start_blk = start_blk;
15040Sstevel@tonic-gate shs.shs_has_label = ((label > 0) ? 1 : 0);
15050Sstevel@tonic-gate shs.shs_number_blks = size;
15060Sstevel@tonic-gate shs.shs_key_new = newnp->key;
15070Sstevel@tonic-gate if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
15080Sstevel@tonic-gate if (options & MDCMD_DOIT) {
15090Sstevel@tonic-gate (void) del_key_name(sp, newnp, ep);
15100Sstevel@tonic-gate }
15110Sstevel@tonic-gate return (mdstealerror(ep, &shs.mde));
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate
15140Sstevel@tonic-gate /* clear cache */
15150Sstevel@tonic-gate meta_invalidate_name(oldnp);
15160Sstevel@tonic-gate meta_invalidate_name(newnp);
15170Sstevel@tonic-gate meta_invalidate_hsp(hspnp);
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate /* let em know */
15200Sstevel@tonic-gate if (options & MDCMD_PRINT) {
15210Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
15220Sstevel@tonic-gate "%s: Hotspare %s is replaced with %s\n"),
15230Sstevel@tonic-gate hspnp->hspname, oldnp->cname, newnp->cname);
15240Sstevel@tonic-gate (void) fflush(stdout);
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate /* return success */
15280Sstevel@tonic-gate return (0);
15290Sstevel@tonic-gate }
15300Sstevel@tonic-gate
15310Sstevel@tonic-gate /*
15320Sstevel@tonic-gate * enable hotspares
15330Sstevel@tonic-gate */
15340Sstevel@tonic-gate int
meta_hs_enable(mdsetname_t * sp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)15350Sstevel@tonic-gate meta_hs_enable(
15360Sstevel@tonic-gate mdsetname_t *sp,
15370Sstevel@tonic-gate mdnamelist_t *hsnlp,
15380Sstevel@tonic-gate mdcmdopts_t options,
15390Sstevel@tonic-gate md_error_t *ep
15400Sstevel@tonic-gate )
15410Sstevel@tonic-gate {
15420Sstevel@tonic-gate mdhspnamelist_t *hspnlp = NULL;
15430Sstevel@tonic-gate mdhspnamelist_t *hspnp;
15440Sstevel@tonic-gate set_hs_params_t shs;
15450Sstevel@tonic-gate int rval = -1;
15460Sstevel@tonic-gate
15470Sstevel@tonic-gate /* should have a set */
15480Sstevel@tonic-gate assert(sp != NULL);
15490Sstevel@tonic-gate
15500Sstevel@tonic-gate /* setup device info */
15510Sstevel@tonic-gate (void) memset(&shs, 0, sizeof (shs));
15520Sstevel@tonic-gate MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
15530Sstevel@tonic-gate shs.shs_cmd = FIX_HOT_SPARE;
15540Sstevel@tonic-gate shs.shs_options = HS_OPT_NONE;
15550Sstevel@tonic-gate /* If DOIT is not set, it's a dryrun */
15560Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
15570Sstevel@tonic-gate shs.shs_options |= HS_OPT_DRYRUN;
15580Sstevel@tonic-gate }
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate /* get the list of hotspare names */
15610Sstevel@tonic-gate if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
15620Sstevel@tonic-gate goto out;
15630Sstevel@tonic-gate
15640Sstevel@tonic-gate /* enable hotspares for each components */
15650Sstevel@tonic-gate for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
15660Sstevel@tonic-gate mdname_t *hsnp = hsnlp->namep;
15670Sstevel@tonic-gate md_dev64_t fs_dev;
15680Sstevel@tonic-gate int rebind = 0;
15690Sstevel@tonic-gate diskaddr_t size, label, start_blk;
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate /* get the file_system dev binding */
15720Sstevel@tonic-gate if (meta_getdev(sp, hsnp, ep) != 0)
15730Sstevel@tonic-gate return (-1);
15740Sstevel@tonic-gate fs_dev = hsnp->dev;
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate /*
15770Sstevel@tonic-gate * search for the component in each hotspare pool
15780Sstevel@tonic-gate * and replace it (instead of enable) if the binding
15790Sstevel@tonic-gate * has changed.
15800Sstevel@tonic-gate */
15810Sstevel@tonic-gate for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
15820Sstevel@tonic-gate /*
15830Sstevel@tonic-gate * in_hsp will call meta_get_hsp which will fill
15840Sstevel@tonic-gate * in hspnp with metadb version of component
15850Sstevel@tonic-gate */
15860Sstevel@tonic-gate meta_invalidate_hsp(hspnp->hspnamep);
15870Sstevel@tonic-gate if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
15880Sstevel@tonic-gate /*
15890Sstevel@tonic-gate * check for the case where the dev_t has
15900Sstevel@tonic-gate * changed between the filesystem and the
15910Sstevel@tonic-gate * metadb. This is called a rebind, and
15920Sstevel@tonic-gate * is handled by meta_hs_replace.
15930Sstevel@tonic-gate */
15940Sstevel@tonic-gate if (fs_dev != hsnp->dev) {
15950Sstevel@tonic-gate /*
15960Sstevel@tonic-gate * establish file system binding
15970Sstevel@tonic-gate * with invalid start/end
15980Sstevel@tonic-gate */
15990Sstevel@tonic-gate rebind++;
16000Sstevel@tonic-gate hsnp->dev = fs_dev;
16010Sstevel@tonic-gate hsnp->start_blk = -1;
16020Sstevel@tonic-gate hsnp->end_blk = -1;
16030Sstevel@tonic-gate rval = meta_hs_replace(sp,
16040Sstevel@tonic-gate hspnp->hspnamep,
16050Sstevel@tonic-gate hsnp, hsnp, options, ep);
16060Sstevel@tonic-gate if (rval != 0)
16070Sstevel@tonic-gate goto out;
16080Sstevel@tonic-gate }
16090Sstevel@tonic-gate }
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate if (rebind)
16120Sstevel@tonic-gate continue;
16130Sstevel@tonic-gate
16140Sstevel@tonic-gate /* enable the component in all hotspares that use it */
16150Sstevel@tonic-gate if (meta_check_hotspare(sp, hsnp, ep) != 0)
16160Sstevel@tonic-gate goto out;
16170Sstevel@tonic-gate
16180Sstevel@tonic-gate if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
16190Sstevel@tonic-gate goto out;
16200Sstevel@tonic-gate if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
16210Sstevel@tonic-gate goto out;
16220Sstevel@tonic-gate if ((start_blk = metagetstart(sp, hsnp, ep))
16230Sstevel@tonic-gate == MD_DISKADDR_ERROR)
16240Sstevel@tonic-gate goto out;
16250Sstevel@tonic-gate if (start_blk >= size) {
16260Sstevel@tonic-gate (void) mdsyserror(ep, ENOSPC, hsnp->cname);
16270Sstevel@tonic-gate goto out;
16280Sstevel@tonic-gate }
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate /* enable hotspare */
16310Sstevel@tonic-gate shs.shs_component_old = hsnp->dev;
16320Sstevel@tonic-gate shs.shs_component_new = hsnp->dev;
16330Sstevel@tonic-gate shs.shs_start_blk = start_blk;
16340Sstevel@tonic-gate shs.shs_has_label = ((label > 0) ? 1 : 0);
16350Sstevel@tonic-gate shs.shs_number_blks = size;
16360Sstevel@tonic-gate if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
16370Sstevel@tonic-gate rval = mdstealerror(ep, &shs.mde);
16380Sstevel@tonic-gate goto out;
16390Sstevel@tonic-gate }
16400Sstevel@tonic-gate
16410Sstevel@tonic-gate /*
16420Sstevel@tonic-gate * Are we dealing with a non-local set? If so need to update
16430Sstevel@tonic-gate * the local namespace so that the disk record has the correct
16440Sstevel@tonic-gate * devid.
16450Sstevel@tonic-gate */
16460Sstevel@tonic-gate if (!metaislocalset(sp)) {
16470Sstevel@tonic-gate rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
16480Sstevel@tonic-gate hsnp->cname, ep);
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate if (rval != METADEVADM_SUCCESS) {
16510Sstevel@tonic-gate /*
16520Sstevel@tonic-gate * Failed to update the local set. Nothing to
16530Sstevel@tonic-gate * do here apart from report the error. The
16540Sstevel@tonic-gate * namespace is most likely broken and some
16550Sstevel@tonic-gate * form of remedial recovery is going to
16560Sstevel@tonic-gate * be required.
16570Sstevel@tonic-gate */
16580Sstevel@tonic-gate mde_perror(ep, "");
16590Sstevel@tonic-gate mdclrerror(ep);
16600Sstevel@tonic-gate }
16610Sstevel@tonic-gate }
16620Sstevel@tonic-gate
16630Sstevel@tonic-gate /* clear cache */
16640Sstevel@tonic-gate meta_invalidate_name(hsnp);
16650Sstevel@tonic-gate
16660Sstevel@tonic-gate /* let em know */
16670Sstevel@tonic-gate if (options & MDCMD_PRINT) {
16680Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
16690Sstevel@tonic-gate "hotspare %s is enabled\n"),
16700Sstevel@tonic-gate hsnp->cname);
16710Sstevel@tonic-gate (void) fflush(stdout);
16720Sstevel@tonic-gate }
16730Sstevel@tonic-gate }
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate /* clear whole cache */
16760Sstevel@tonic-gate for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
16770Sstevel@tonic-gate meta_invalidate_hsp(hspnp->hspnamep);
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate /* return success */
16820Sstevel@tonic-gate rval = 0;
16830Sstevel@tonic-gate
16840Sstevel@tonic-gate out:
16850Sstevel@tonic-gate if (hspnlp)
16860Sstevel@tonic-gate metafreehspnamelist(hspnlp);
16870Sstevel@tonic-gate return (rval);
16880Sstevel@tonic-gate }
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate /*
16910Sstevel@tonic-gate * check for dups in the hsp itself
16920Sstevel@tonic-gate */
16930Sstevel@tonic-gate static int
check_twice(md_hsp_t * hspp,uint_t hsi,md_error_t * ep)16940Sstevel@tonic-gate check_twice(
16950Sstevel@tonic-gate md_hsp_t *hspp,
16960Sstevel@tonic-gate uint_t hsi,
16970Sstevel@tonic-gate md_error_t *ep
16980Sstevel@tonic-gate )
16990Sstevel@tonic-gate {
17000Sstevel@tonic-gate mdhspname_t *hspnp = hspp->hspnamep;
17010Sstevel@tonic-gate mdname_t *thisnp;
17020Sstevel@tonic-gate uint_t h;
17030Sstevel@tonic-gate
17040Sstevel@tonic-gate thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
17050Sstevel@tonic-gate for (h = 0; (h < hsi); ++h) {
17060Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[h];
17070Sstevel@tonic-gate mdname_t *hsnp = hsp->hsnamep;
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
17100Sstevel@tonic-gate hsnp, 0, -1, ep) != 0)
17110Sstevel@tonic-gate return (-1);
17120Sstevel@tonic-gate }
17130Sstevel@tonic-gate return (0);
17140Sstevel@tonic-gate }
17150Sstevel@tonic-gate
17160Sstevel@tonic-gate /*
17170Sstevel@tonic-gate * check hsp
17180Sstevel@tonic-gate */
17190Sstevel@tonic-gate /*ARGSUSED2*/
17200Sstevel@tonic-gate int
meta_check_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)17210Sstevel@tonic-gate meta_check_hsp(
17220Sstevel@tonic-gate mdsetname_t *sp,
17230Sstevel@tonic-gate md_hsp_t *hspp,
17240Sstevel@tonic-gate mdcmdopts_t options,
17250Sstevel@tonic-gate md_error_t *ep
17260Sstevel@tonic-gate )
17270Sstevel@tonic-gate {
17280Sstevel@tonic-gate mdhspname_t *hspnp = hspp->hspnamep;
17290Sstevel@tonic-gate uint_t hsi;
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate /* check hotspares */
17320Sstevel@tonic-gate for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
17330Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
17340Sstevel@tonic-gate mdname_t *hsnp = hsp->hsnamep;
17350Sstevel@tonic-gate diskaddr_t size;
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate /* check hotspare */
17380Sstevel@tonic-gate if (meta_check_hotspare(sp, hsnp, ep) != 0)
17390Sstevel@tonic-gate return (-1);
17400Sstevel@tonic-gate if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
17410Sstevel@tonic-gate return (-1);
17420Sstevel@tonic-gate } else if (size == 0) {
17430Sstevel@tonic-gate return (mdsyserror(ep, ENOSPC, hspnp->hspname));
17440Sstevel@tonic-gate }
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate /* check this hsp too */
17470Sstevel@tonic-gate if (check_twice(hspp, hsi, ep) != 0)
17480Sstevel@tonic-gate return (-1);
17490Sstevel@tonic-gate }
17500Sstevel@tonic-gate
17510Sstevel@tonic-gate /* return success */
17520Sstevel@tonic-gate return (0);
17530Sstevel@tonic-gate }
17540Sstevel@tonic-gate
17550Sstevel@tonic-gate /*
17560Sstevel@tonic-gate * create hsp
17570Sstevel@tonic-gate */
17580Sstevel@tonic-gate int
meta_create_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)17590Sstevel@tonic-gate meta_create_hsp(
17600Sstevel@tonic-gate mdsetname_t *sp,
17610Sstevel@tonic-gate md_hsp_t *hspp,
17620Sstevel@tonic-gate mdcmdopts_t options,
17630Sstevel@tonic-gate md_error_t *ep
17640Sstevel@tonic-gate )
17650Sstevel@tonic-gate {
17660Sstevel@tonic-gate mdhspname_t *hspnp = hspp->hspnamep;
17670Sstevel@tonic-gate mdnamelist_t *hsnlp = NULL;
17680Sstevel@tonic-gate uint_t hsi;
17690Sstevel@tonic-gate int rval = -1;
17700Sstevel@tonic-gate
17710Sstevel@tonic-gate /* validate hsp */
17720Sstevel@tonic-gate if (meta_check_hsp(sp, hspp, options, ep) != 0)
17730Sstevel@tonic-gate return (-1);
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate /* if we're not doing anything, return success */
17760Sstevel@tonic-gate if (! (options & MDCMD_DOIT))
17770Sstevel@tonic-gate return (0);
17780Sstevel@tonic-gate
17790Sstevel@tonic-gate /* create hsp */
17800Sstevel@tonic-gate for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
17810Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
17820Sstevel@tonic-gate mdname_t *hsnp = hsp->hsnamep;
17830Sstevel@tonic-gate
17840Sstevel@tonic-gate (void) metanamelist_append(&hsnlp, hsnp);
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate options |= MDCMD_INIT;
17870Sstevel@tonic-gate rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
17880Sstevel@tonic-gate
17890Sstevel@tonic-gate /* cleanup, return success */
17900Sstevel@tonic-gate metafreenamelist(hsnlp);
17910Sstevel@tonic-gate return (rval);
17920Sstevel@tonic-gate }
17930Sstevel@tonic-gate
17940Sstevel@tonic-gate /*
17950Sstevel@tonic-gate * initialize hsp
17960Sstevel@tonic-gate * NOTE: this functions is metainit(1m)'s command line parser!
17970Sstevel@tonic-gate */
17980Sstevel@tonic-gate int
meta_init_hsp(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)17990Sstevel@tonic-gate meta_init_hsp(
18000Sstevel@tonic-gate mdsetname_t **spp,
18010Sstevel@tonic-gate int argc,
18020Sstevel@tonic-gate char *argv[],
18030Sstevel@tonic-gate mdcmdopts_t options,
18040Sstevel@tonic-gate md_error_t *ep
18050Sstevel@tonic-gate )
18060Sstevel@tonic-gate {
18070Sstevel@tonic-gate char *uname = argv[0];
18080Sstevel@tonic-gate mdhspname_t *hspnp = NULL;
18090Sstevel@tonic-gate md_hsp_t *hspp = NULL;
18100Sstevel@tonic-gate uint_t hsi;
18110Sstevel@tonic-gate int rval = -1;
18120Sstevel@tonic-gate
18130Sstevel@tonic-gate
18140Sstevel@tonic-gate /* get hsp name */
18150Sstevel@tonic-gate assert(argc > 0);
18160Sstevel@tonic-gate if (argc < 1)
18170Sstevel@tonic-gate goto syntax;
18180Sstevel@tonic-gate if ((hspnp = metahspname(spp, uname, ep)) == NULL)
18190Sstevel@tonic-gate goto out;
18200Sstevel@tonic-gate assert(*spp != NULL);
18210Sstevel@tonic-gate uname = hspnp->hspname;
18220Sstevel@tonic-gate
18230Sstevel@tonic-gate if (!(options & MDCMD_NOLOCK)) {
18240Sstevel@tonic-gate /* grab set lock */
18250Sstevel@tonic-gate if (meta_lock(*spp, TRUE, ep))
18260Sstevel@tonic-gate goto out;
18270Sstevel@tonic-gate
18280Sstevel@tonic-gate if (meta_check_ownership(*spp, ep) != 0)
18290Sstevel@tonic-gate goto out;
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate
18320Sstevel@tonic-gate /* see if it exists already */
1833*2099Stn143363 if (is_existing_metadevice(*spp, uname)) {
1834*2099Stn143363 mdname_t *np;
1835*2099Stn143363 if ((np = metaname(spp, uname, META_DEVICE, ep)) != NULL)
1836*2099Stn143363 if ((meta_get_unit(*spp, np, ep)) != NULL)
1837*2099Stn143363 return (mderror(ep, MDE_NAME_IN_USE, uname));
1838*2099Stn143363 }
1839*2099Stn143363
18400Sstevel@tonic-gate if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
18411623Stw21770 (void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP,
18421623Stw21770 hspnp->hsp, uname);
18430Sstevel@tonic-gate goto out;
18440Sstevel@tonic-gate } else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
18450Sstevel@tonic-gate goto out;
18460Sstevel@tonic-gate } else {
18470Sstevel@tonic-gate mdclrerror(ep);
18480Sstevel@tonic-gate }
18490Sstevel@tonic-gate --argc, ++argv;
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate /* parse general options */
18520Sstevel@tonic-gate optind = 0;
18530Sstevel@tonic-gate opterr = 0;
18540Sstevel@tonic-gate if (getopt(argc, argv, "") != -1)
18550Sstevel@tonic-gate goto options;
18560Sstevel@tonic-gate
18570Sstevel@tonic-gate /* allocate hsp */
18580Sstevel@tonic-gate hspp = Zalloc(sizeof (*hspp));
18590Sstevel@tonic-gate hspp->hotspares.hotspares_len = argc;
18600Sstevel@tonic-gate if (argc > 0) {
18610Sstevel@tonic-gate hspp->hotspares.hotspares_val =
18620Sstevel@tonic-gate Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate
18650Sstevel@tonic-gate /* setup pool */
18660Sstevel@tonic-gate hspp->hspnamep = hspnp;
18670Sstevel@tonic-gate
18680Sstevel@tonic-gate /* parse hotspares */
18690Sstevel@tonic-gate for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
18700Sstevel@tonic-gate ++hsi) {
18710Sstevel@tonic-gate md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
18720Sstevel@tonic-gate mdname_t *hsnamep;
18730Sstevel@tonic-gate
18740Sstevel@tonic-gate /* parse hotspare name */
18751623Stw21770 if ((hsnamep = metaname(spp, argv[0],
18761623Stw21770 LOGICAL_DEVICE, ep)) == NULL)
18770Sstevel@tonic-gate goto out;
18780Sstevel@tonic-gate hsp->hsnamep = hsnamep;
18790Sstevel@tonic-gate --argc, ++argv;
18800Sstevel@tonic-gate }
18810Sstevel@tonic-gate
18820Sstevel@tonic-gate /* we should be at the end */
18830Sstevel@tonic-gate if (argc != 0)
18840Sstevel@tonic-gate goto syntax;
18850Sstevel@tonic-gate
18860Sstevel@tonic-gate /* create hotspare pool */
18870Sstevel@tonic-gate if (meta_create_hsp(*spp, hspp, options, ep) != 0)
18880Sstevel@tonic-gate goto out;
18890Sstevel@tonic-gate rval = 0; /* success */
18900Sstevel@tonic-gate goto out;
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate /* syntax error */
18930Sstevel@tonic-gate syntax:
18940Sstevel@tonic-gate rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
18950Sstevel@tonic-gate goto out;
18960Sstevel@tonic-gate
18970Sstevel@tonic-gate /* options error */
18980Sstevel@tonic-gate options:
18990Sstevel@tonic-gate rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
19000Sstevel@tonic-gate goto out;
19010Sstevel@tonic-gate
19020Sstevel@tonic-gate /* cleanup, return error */
19030Sstevel@tonic-gate out:
19040Sstevel@tonic-gate if (hspp != NULL)
19050Sstevel@tonic-gate meta_free_hsp(hspp);
19060Sstevel@tonic-gate return (rval);
19070Sstevel@tonic-gate }
19080Sstevel@tonic-gate
19090Sstevel@tonic-gate /*
19100Sstevel@tonic-gate * reset hotspare pool
19110Sstevel@tonic-gate */
19120Sstevel@tonic-gate int
meta_hsp_reset(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)19130Sstevel@tonic-gate meta_hsp_reset(
19140Sstevel@tonic-gate mdsetname_t *sp,
19150Sstevel@tonic-gate mdhspname_t *hspnp,
19160Sstevel@tonic-gate mdcmdopts_t options,
19170Sstevel@tonic-gate md_error_t *ep
19180Sstevel@tonic-gate )
19190Sstevel@tonic-gate {
19200Sstevel@tonic-gate md_hsp_t *hspp;
19210Sstevel@tonic-gate set_hs_params_t shs;
19220Sstevel@tonic-gate uint_t i;
19230Sstevel@tonic-gate int rval = -1;
19240Sstevel@tonic-gate
19250Sstevel@tonic-gate /* should have the same set */
19260Sstevel@tonic-gate assert(sp != NULL);
19271623Stw21770 assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
19281623Stw21770 sp->setno == HSP_SET(hspnp->hsp));
19290Sstevel@tonic-gate
19300Sstevel@tonic-gate /* reset all hotspares */
19310Sstevel@tonic-gate if (hspnp == NULL) {
19320Sstevel@tonic-gate mdhspnamelist_t *hspnlp = NULL;
19330Sstevel@tonic-gate mdhspnamelist_t *p;
19340Sstevel@tonic-gate
19350Sstevel@tonic-gate /* for each hotspare pool */
19360Sstevel@tonic-gate rval = 0;
19370Sstevel@tonic-gate if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
19380Sstevel@tonic-gate return (-1);
19390Sstevel@tonic-gate for (p = hspnlp; (p != NULL); p = p->next) {
19400Sstevel@tonic-gate /* reset hotspare pool */
19410Sstevel@tonic-gate hspnp = p->hspnamep;
19420Sstevel@tonic-gate
19430Sstevel@tonic-gate /*
19440Sstevel@tonic-gate * If this is a multi-node set, we send a series
19450Sstevel@tonic-gate * of individual metaclear commands.
19460Sstevel@tonic-gate */
19470Sstevel@tonic-gate if (meta_is_mn_set(sp, ep)) {
19480Sstevel@tonic-gate if (meta_mn_send_metaclear_command(sp,
19490Sstevel@tonic-gate hspnp->hspname, options, 0, ep) != 0) {
19500Sstevel@tonic-gate rval = -1;
19510Sstevel@tonic-gate break;
19520Sstevel@tonic-gate }
19530Sstevel@tonic-gate } else {
19540Sstevel@tonic-gate if (meta_hsp_reset(sp, hspnp, options,
19550Sstevel@tonic-gate ep) != 0) {
19560Sstevel@tonic-gate rval = -1;
19570Sstevel@tonic-gate break;
19580Sstevel@tonic-gate }
19590Sstevel@tonic-gate }
19600Sstevel@tonic-gate }
19610Sstevel@tonic-gate
19620Sstevel@tonic-gate /* cleanup, return success */
19630Sstevel@tonic-gate metafreehspnamelist(hspnlp);
19640Sstevel@tonic-gate return (rval);
19650Sstevel@tonic-gate }
19660Sstevel@tonic-gate
19670Sstevel@tonic-gate /* get unit structure */
19680Sstevel@tonic-gate if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
19690Sstevel@tonic-gate return (-1);
19700Sstevel@tonic-gate
19710Sstevel@tonic-gate /* make sure nobody owns us */
19720Sstevel@tonic-gate if (hspp->refcount > 0) {
19730Sstevel@tonic-gate return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
19740Sstevel@tonic-gate hspnp->hspname));
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate
19770Sstevel@tonic-gate /* clear hotspare pool members */
19780Sstevel@tonic-gate (void) memset(&shs, 0, sizeof (shs));
19790Sstevel@tonic-gate MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
19800Sstevel@tonic-gate shs.shs_cmd = DELETE_HOT_SPARE;
19810Sstevel@tonic-gate shs.shs_hot_spare_pool = hspnp->hsp;
19820Sstevel@tonic-gate for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
19830Sstevel@tonic-gate md_hs_t *hs = &hspp->hotspares.hotspares_val[i];
19840Sstevel@tonic-gate mdname_t *hsnamep = hs->hsnamep;
19850Sstevel@tonic-gate
19860Sstevel@tonic-gate /* clear cache */
19870Sstevel@tonic-gate meta_invalidate_name(hsnamep);
19880Sstevel@tonic-gate
19890Sstevel@tonic-gate /* clear hotspare */
19900Sstevel@tonic-gate shs.shs_component_old = hsnamep->dev;
19910Sstevel@tonic-gate shs.shs_options = HS_OPT_FORCE;
19920Sstevel@tonic-gate /* If DOIT is not set, it's a dryrun */
19930Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) {
19940Sstevel@tonic-gate shs.shs_options |= HS_OPT_DRYRUN;
19950Sstevel@tonic-gate }
19960Sstevel@tonic-gate if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
19970Sstevel@tonic-gate (void) mdstealerror(ep, &shs.mde);
19980Sstevel@tonic-gate goto out;
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate }
20010Sstevel@tonic-gate
20020Sstevel@tonic-gate /* clear hotspare pool */
20031623Stw21770 if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
20040Sstevel@tonic-gate goto out;
20050Sstevel@tonic-gate rval = 0; /* success */
20060Sstevel@tonic-gate
20070Sstevel@tonic-gate /* let em know */
20080Sstevel@tonic-gate if (options & MDCMD_PRINT) {
20090Sstevel@tonic-gate (void) printf(dgettext(TEXT_DOMAIN,
20100Sstevel@tonic-gate "%s: Hotspare pool is cleared\n"),
20110Sstevel@tonic-gate hspnp->hspname);
20120Sstevel@tonic-gate (void) fflush(stdout);
20130Sstevel@tonic-gate }
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate /* clear subdevices (nothing to do) */
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate /* cleanup, return success */
20180Sstevel@tonic-gate out:
20190Sstevel@tonic-gate meta_invalidate_hsp(hspnp);
20200Sstevel@tonic-gate return (rval);
20210Sstevel@tonic-gate }
2022