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 51366Spetede * Common Development and Distribution License (the "License"). 61366Spetede * 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 /* 221366Spetede * 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 #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/systm.h> 300Sstevel@tonic-gate #include <sys/conf.h> 310Sstevel@tonic-gate #include <sys/file.h> 320Sstevel@tonic-gate #include <sys/user.h> 330Sstevel@tonic-gate #include <sys/uio.h> 340Sstevel@tonic-gate #include <sys/t_lock.h> 350Sstevel@tonic-gate #include <sys/kmem.h> 360Sstevel@tonic-gate #include <vm/page.h> 370Sstevel@tonic-gate #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/types.h> 390Sstevel@tonic-gate #include <sys/mkdev.h> 400Sstevel@tonic-gate #include <sys/stat.h> 410Sstevel@tonic-gate #include <sys/open.h> 420Sstevel@tonic-gate #include <sys/modctl.h> 430Sstevel@tonic-gate #include <sys/ddi.h> 440Sstevel@tonic-gate #include <sys/sunddi.h> 450Sstevel@tonic-gate #include <sys/debug.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h> 480Sstevel@tonic-gate #include <sys/lvm/md_convert.h> 490Sstevel@tonic-gate 500Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h> 510Sstevel@tonic-gate #include <sys/sysevent/svm.h> 520Sstevel@tonic-gate 530Sstevel@tonic-gate md_ops_t hotspares_md_ops; 540Sstevel@tonic-gate #ifndef lint 551366Spetede char _depends_on[] = "drv/md"; 560Sstevel@tonic-gate md_ops_t *md_interface_ops = &hotspares_md_ops; 570Sstevel@tonic-gate #endif 580Sstevel@tonic-gate 590Sstevel@tonic-gate extern md_ops_t **md_ops; 600Sstevel@tonic-gate extern md_ops_t *md_opslist; 610Sstevel@tonic-gate extern md_set_t md_set[]; 620Sstevel@tonic-gate 630Sstevel@tonic-gate extern kmutex_t md_mx; /* used to md global stuff */ 640Sstevel@tonic-gate extern kcondvar_t md_cv; /* md_status events */ 650Sstevel@tonic-gate extern int md_status; 660Sstevel@tonic-gate 670Sstevel@tonic-gate extern void md_clear_hot_spare_interface(); 680Sstevel@tonic-gate 690Sstevel@tonic-gate static void 700Sstevel@tonic-gate set_hot_spare_state(hot_spare_t *hs, hotspare_states_t newstate) 710Sstevel@tonic-gate { 720Sstevel@tonic-gate hs->hs_state = newstate; 730Sstevel@tonic-gate uniqtime32(&hs->hs_timestamp); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate 760Sstevel@tonic-gate static hot_spare_t * 770Sstevel@tonic-gate lookup_hot_spare(set_t setno, mddb_recid_t hs_id, int must_exist) 780Sstevel@tonic-gate { 790Sstevel@tonic-gate hot_spare_t *hs; 800Sstevel@tonic-gate 810Sstevel@tonic-gate for (hs = (hot_spare_t *)md_set[setno].s_hs; hs; hs = hs->hs_next) { 820Sstevel@tonic-gate if (hs->hs_record_id == hs_id) 830Sstevel@tonic-gate return (hs); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate if (must_exist) 860Sstevel@tonic-gate ASSERT(0); 870Sstevel@tonic-gate 880Sstevel@tonic-gate return ((hot_spare_t *)NULL); 890Sstevel@tonic-gate } 900Sstevel@tonic-gate 910Sstevel@tonic-gate 920Sstevel@tonic-gate static int 930Sstevel@tonic-gate seths_create_hsp(set_hs_params_t *shs) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate hot_spare_pool_t *hsp; 960Sstevel@tonic-gate mddb_recid_t recid; 970Sstevel@tonic-gate set_t setno; 980Sstevel@tonic-gate mddb_type_t typ1; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate /* Scan the hot spare pool list */ 1030Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); 1040Sstevel@tonic-gate if (hsp != (hot_spare_pool_t *)0) 1050Sstevel@tonic-gate return (0); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 1080Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* create a hot spare pool record */ 1110Sstevel@tonic-gate if (shs->shs_options & MD_CRO_64BIT) { 1120Sstevel@tonic-gate #if defined(_ILP32) 1130Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_UNIT_TOO_LARGE, 1140Sstevel@tonic-gate shs->shs_hot_spare_pool)); 1150Sstevel@tonic-gate #else 1160Sstevel@tonic-gate recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1, 117*1623Stw21770 HSP_REC, MD_CRO_64BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, 118*1623Stw21770 setno); 1190Sstevel@tonic-gate #endif 1200Sstevel@tonic-gate } else { 1210Sstevel@tonic-gate recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1, 122*1623Stw21770 HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, 123*1623Stw21770 setno); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if (recid < 0) { 1270Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, 1280Sstevel@tonic-gate shs->shs_hot_spare_pool)); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* get the record addr */ 1320Sstevel@tonic-gate hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, sizeof (*hsp), 1330Sstevel@tonic-gate HSP_ONDSK_STR_OFF); 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate hsp->hsp_self_id = shs->shs_hot_spare_pool; 1360Sstevel@tonic-gate hsp->hsp_record_id = recid; 1370Sstevel@tonic-gate hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; 1380Sstevel@tonic-gate hsp->hsp_refcount = 0; 1390Sstevel@tonic-gate hsp->hsp_nhotspares = 0; 140*1623Stw21770 hsp->hsp_revision |= MD_FN_META_DEV; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp; 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate mddb_commitrec_wrapper(recid); 1450Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno, 1460Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 1490Sstevel@tonic-gate hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 1500Sstevel@tonic-gate hsp->hsp_link.ln_setno = setno; 1510Sstevel@tonic-gate hsp->hsp_link.ln_id = hsp->hsp_self_id; 1520Sstevel@tonic-gate hotspares_md_ops.md_head = &hsp->hsp_link; 1530Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate return (0); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static int 1600Sstevel@tonic-gate seths_add(set_hs_params_t *shs) 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate hot_spare_t *hs; 1630Sstevel@tonic-gate hot_spare_pool_t *hsp; 1640Sstevel@tonic-gate hot_spare_pool_t *prev_hsp; 1650Sstevel@tonic-gate hot_spare_pool_t *new_hsp; 1660Sstevel@tonic-gate hot_spare_pool_t *old_hsp; 167*1623Stw21770 md_create_rec_option_t options; 1680Sstevel@tonic-gate mddb_recid_t recid; 1690Sstevel@tonic-gate mddb_recid_t recids[5]; 1700Sstevel@tonic-gate size_t new_size; 1710Sstevel@tonic-gate int i; 1720Sstevel@tonic-gate int delete_hsp = 0; 1730Sstevel@tonic-gate int irecid; 1740Sstevel@tonic-gate set_t setno; 1750Sstevel@tonic-gate mddb_type_t typ1; 1760Sstevel@tonic-gate int hsp_created = 0; 1770Sstevel@tonic-gate mdkey_t key_old; 1780Sstevel@tonic-gate int num_keys_old = 0; 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* Not much to do here in case of a dryrun */ 1810Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 1820Sstevel@tonic-gate return (0); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* create an empty hot spare pool */ 1860Sstevel@tonic-gate if (shs->shs_options & HS_OPT_POOL) { 1870Sstevel@tonic-gate return (seths_create_hsp(shs)); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 1910Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 1920Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* Scan the hot spare list */ 1950Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 1960Sstevel@tonic-gate while (hs) { 1970Sstevel@tonic-gate if (hs->hs_devnum == shs->shs_component_old) { 1980Sstevel@tonic-gate break; 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate hs = hs->hs_next; 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate if (hs == NULL) { 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * Did not find match for device using devnum so use 2060Sstevel@tonic-gate * key associated with shs_component_old just 2070Sstevel@tonic-gate * in case there is a match but the match's dev is NODEV. 2080Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 2090Sstevel@tonic-gate * then fail since namespace has multiple entries 2100Sstevel@tonic-gate * for this old component and we shouldn't allow 2110Sstevel@tonic-gate * an addition of a hotspare in this case. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 2140Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 2150Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 2160Sstevel@tonic-gate shs->shs_component_old)); 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* 2200Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 2210Sstevel@tonic-gate * since shouldn't add new hotspare if namespace has 2220Sstevel@tonic-gate * multiple entries. 2230Sstevel@tonic-gate */ 2240Sstevel@tonic-gate if (num_keys_old > 1) { 2250Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 2260Sstevel@tonic-gate shs->shs_component_old)); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate /* 2290Sstevel@tonic-gate * If there is no key for this entry then fail since 2300Sstevel@tonic-gate * a key for this entry should exist. 2310Sstevel@tonic-gate */ 2320Sstevel@tonic-gate if (num_keys_old == 0) { 2330Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 2340Sstevel@tonic-gate shs->shs_component_old)); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate /* Scan the hot spare list again */ 2370Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 2380Sstevel@tonic-gate while (hs) { 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate if ((hs->hs_devnum == NODEV64) && 2430Sstevel@tonic-gate (hs->hs_key == key_old)) { 2440Sstevel@tonic-gate break; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate hs = hs->hs_next; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate if (hs == NULL) { 2510Sstevel@tonic-gate /* create a hot spare record */ 2520Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 2530Sstevel@tonic-gate #if defined(_ILP32) 2540Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE, 2550Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_old)); 2560Sstevel@tonic-gate #else 2570Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 2580Sstevel@tonic-gate MD_CRO_64BIT | MD_CRO_HOTSPARE, setno); 2590Sstevel@tonic-gate #endif 2600Sstevel@tonic-gate } else { 2610Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 2620Sstevel@tonic-gate MD_CRO_32BIT | MD_CRO_HOTSPARE, setno); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate if (recid < 0) { 2660Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE, 2670Sstevel@tonic-gate shs->shs_hot_spare_pool, 2680Sstevel@tonic-gate shs->shs_component_old)); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate /* get the addr */ 2720Sstevel@tonic-gate hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, sizeof (*hs), 2730Sstevel@tonic-gate 0); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate hs->hs_record_id = recid; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate hs->hs_devnum = shs->shs_component_old; 2780Sstevel@tonic-gate hs->hs_key = shs->shs_key_old; 2790Sstevel@tonic-gate hs->hs_start_blk = shs->shs_start_blk; 2800Sstevel@tonic-gate hs->hs_has_label = shs->shs_has_label; 2810Sstevel@tonic-gate hs->hs_number_blks = shs->shs_number_blks; 2820Sstevel@tonic-gate set_hot_spare_state(hs, HSS_AVAILABLE); 2830Sstevel@tonic-gate hs->hs_refcount = 0; 2840Sstevel@tonic-gate hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; 2850Sstevel@tonic-gate md_set[setno].s_hs = (void *) hs; 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate /* Scan the hot spare pool list */ 2890Sstevel@tonic-gate hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; 2900Sstevel@tonic-gate prev_hsp = (hot_spare_pool_t *)0; 2910Sstevel@tonic-gate while (hsp) { 2920Sstevel@tonic-gate if (hsp->hsp_self_id == shs->shs_hot_spare_pool) { 2930Sstevel@tonic-gate break; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate prev_hsp = hsp; 2960Sstevel@tonic-gate hsp = hsp->hsp_next; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate if (hsp == NULL) { 3000Sstevel@tonic-gate /* create a hot spare pool record */ 3010Sstevel@tonic-gate recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), 302*1623Stw21770 typ1, HSP_REC, 303*1623Stw21770 MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, setno); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate if (recid < 0) { 3060Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, 3070Sstevel@tonic-gate shs->shs_hot_spare_pool)); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* get the record addr */ 3110Sstevel@tonic-gate hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, 3120Sstevel@tonic-gate sizeof (*hsp), HSP_ONDSK_STR_OFF); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate hsp->hsp_self_id = shs->shs_hot_spare_pool; 3150Sstevel@tonic-gate hsp->hsp_record_id = recid; 3160Sstevel@tonic-gate hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; 3170Sstevel@tonic-gate hsp->hsp_refcount = 0; 3180Sstevel@tonic-gate hsp->hsp_nhotspares = 0; 319*1623Stw21770 hsp->hsp_revision |= MD_FN_META_DEV; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* force prev_hsp to NULL, this will cause hsp to be linked */ 3220Sstevel@tonic-gate prev_hsp = (hot_spare_pool_t *)0; 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 3250Sstevel@tonic-gate hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 3260Sstevel@tonic-gate hsp->hsp_link.ln_setno = setno; 3270Sstevel@tonic-gate hsp->hsp_link.ln_id = hsp->hsp_self_id; 3280Sstevel@tonic-gate hotspares_md_ops.md_head = &hsp->hsp_link; 3290Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 3300Sstevel@tonic-gate hsp_created = 1; 3310Sstevel@tonic-gate } else { 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /* 3340Sstevel@tonic-gate * Make sure the hot spare is not already in the pool. 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) 3370Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 3380Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_INUSE, 3390Sstevel@tonic-gate shs->shs_hot_spare_pool, 3400Sstevel@tonic-gate hs->hs_devnum)); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate /* 3430Sstevel@tonic-gate * Create a new hot spare pool record 3440Sstevel@tonic-gate * This gives us the one extra hs slot, 3450Sstevel@tonic-gate * because there is one slot in the 3460Sstevel@tonic-gate * hot_spare_pool struct 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate new_size = sizeof (hot_spare_pool_ond_t) + 3490Sstevel@tonic-gate (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); 350*1623Stw21770 351*1623Stw21770 /* 352*1623Stw21770 * The Friendly Name status of the new HSP should duplicate 353*1623Stw21770 * the status of the existing one. 354*1623Stw21770 */ 355*1623Stw21770 if (hsp->hsp_revision & MD_FN_META_DEV) { 356*1623Stw21770 options = 357*1623Stw21770 MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN; 358*1623Stw21770 } else { 359*1623Stw21770 options = MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL; 360*1623Stw21770 } 361*1623Stw21770 recid = mddb_createrec(new_size, typ1, HSP_REC, options, setno); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate if (recid < 0) { 3640Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, 3650Sstevel@tonic-gate hsp->hsp_self_id)); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate new_size = sizeof (hot_spare_pool_t) + 3680Sstevel@tonic-gate (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate /* get the record addr */ 3710Sstevel@tonic-gate new_hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, 3720Sstevel@tonic-gate new_size, HSP_ONDSK_STR_OFF); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* copy the old record into the new one */ 3750Sstevel@tonic-gate bcopy((caddr_t)hsp, (caddr_t)new_hsp, 3760Sstevel@tonic-gate (size_t)((sizeof (hot_spare_pool_t) + 3770Sstevel@tonic-gate (sizeof (mddb_recid_t) * hsp->hsp_nhotspares) 3780Sstevel@tonic-gate - sizeof (mddb_recid_t)))); 3790Sstevel@tonic-gate new_hsp->hsp_record_id = recid; 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate md_rem_link(setno, hsp->hsp_self_id, 3820Sstevel@tonic-gate &hotspares_md_ops.md_link_rw.lock, 3830Sstevel@tonic-gate &hotspares_md_ops.md_head); 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 3860Sstevel@tonic-gate new_hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 3870Sstevel@tonic-gate new_hsp->hsp_link.ln_setno = setno; 3880Sstevel@tonic-gate new_hsp->hsp_link.ln_id = new_hsp->hsp_self_id; 3890Sstevel@tonic-gate hotspares_md_ops.md_head = &new_hsp->hsp_link; 3900Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate /* mark the old hsp to be deleted */ 3930Sstevel@tonic-gate delete_hsp = 1; 3940Sstevel@tonic-gate old_hsp = hsp; 3950Sstevel@tonic-gate hsp = new_hsp; 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 399*1623Stw21770 hs->hs_revision |= MD_64BIT_META_DEV; 4000Sstevel@tonic-gate } else { 401*1623Stw21770 hs->hs_revision &= ~MD_64BIT_META_DEV; 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate /* lock the db records */ 4050Sstevel@tonic-gate recids[0] = hs->hs_record_id; 4060Sstevel@tonic-gate recids[1] = hsp->hsp_record_id; 4070Sstevel@tonic-gate irecid = 2; 4080Sstevel@tonic-gate if (delete_hsp) 4090Sstevel@tonic-gate recids[irecid++] = old_hsp->hsp_record_id; 4100Sstevel@tonic-gate recids[irecid] = 0; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* increment the reference count */ 4130Sstevel@tonic-gate hs->hs_refcount++; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate /* add the hs at the end of the hot spare pool */ 4160Sstevel@tonic-gate hsp->hsp_hotspares[hsp->hsp_nhotspares] = hs->hs_record_id; 4170Sstevel@tonic-gate hsp->hsp_nhotspares++; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 4200Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare pool record. 4210Sstevel@tonic-gate * There is no need, the link gets rebuilt at boot time. 4220Sstevel@tonic-gate */ 4230Sstevel@tonic-gate if (prev_hsp) 4240Sstevel@tonic-gate prev_hsp->hsp_next = hsp; 4250Sstevel@tonic-gate else 4260Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate if (delete_hsp) 4290Sstevel@tonic-gate old_hsp->hsp_self_id = MD_HSP_NONE; 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate /* commit the db records */ 4320Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate if (delete_hsp) { 4350Sstevel@tonic-gate /* delete the old hot spare pool record */ 4360Sstevel@tonic-gate mddb_deleterec_wrapper(old_hsp->hsp_record_id); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate if (hsp_created) { 4400Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno, 4410Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_ADD, SVM_TAG_HSP, setno, 4440Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate return (0); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate static int 4510Sstevel@tonic-gate seths_delete_hsp(set_hs_params_t *shs) 4520Sstevel@tonic-gate { 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate hot_spare_pool_t *prev_hsp; 4550Sstevel@tonic-gate hot_spare_pool_t *hsp; 4560Sstevel@tonic-gate set_t setno; 4570Sstevel@tonic-gate hsp_t hspid; 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate /* Scan the hot spare pool list */ 4620Sstevel@tonic-gate prev_hsp = (hot_spare_pool_t *)0; 4630Sstevel@tonic-gate hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; 4640Sstevel@tonic-gate while (hsp) { 4650Sstevel@tonic-gate if (hsp->hsp_self_id == shs->shs_hot_spare_pool) { 4660Sstevel@tonic-gate break; 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate prev_hsp = hsp; 4690Sstevel@tonic-gate hsp = hsp->hsp_next; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate if (hsp == NULL) { 4730Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_INVAL_HSP, 4740Sstevel@tonic-gate shs->shs_hot_spare_pool)); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate if (hsp->hsp_nhotspares != 0) { 4780Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_BUSY, 4790Sstevel@tonic-gate shs->shs_hot_spare_pool)); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate if (hsp->hsp_refcount != 0) { 4830Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_REF, 4840Sstevel@tonic-gate shs->shs_hot_spare_pool)); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 4880Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 4890Sstevel@tonic-gate return (0); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare pool record. 4930Sstevel@tonic-gate * There is no need, the link gets rebuilt at boot time. 4940Sstevel@tonic-gate */ 4950Sstevel@tonic-gate if (prev_hsp) 4960Sstevel@tonic-gate prev_hsp->hsp_next = hsp->hsp_next; 4970Sstevel@tonic-gate else 4980Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp->hsp_next; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate hspid = hsp->hsp_self_id; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate md_rem_link(setno, hsp->hsp_self_id, 5030Sstevel@tonic-gate &hotspares_md_ops.md_link_rw.lock, 5040Sstevel@tonic-gate &hotspares_md_ops.md_head); 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate mddb_deleterec_wrapper(hsp->hsp_record_id); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_HSP, setno, 5090Sstevel@tonic-gate md_expldev(hspid)); 5100Sstevel@tonic-gate return (0); 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate static int 5150Sstevel@tonic-gate seths_delete(set_hs_params_t *shs) 5160Sstevel@tonic-gate { 5170Sstevel@tonic-gate hot_spare_t *hs; 5180Sstevel@tonic-gate hot_spare_t *prev_hs; 5190Sstevel@tonic-gate hot_spare_pool_t *hsp; 5200Sstevel@tonic-gate mddb_recid_t recids[4]; 5210Sstevel@tonic-gate int i; 5220Sstevel@tonic-gate set_t setno; 5230Sstevel@tonic-gate sv_dev_t sv; 5240Sstevel@tonic-gate int delete_hs = 0; 5250Sstevel@tonic-gate mdkey_t key_old; 5260Sstevel@tonic-gate int num_keys_old = 0; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* delete the hot spare pool */ 5290Sstevel@tonic-gate if (shs->shs_options & HS_OPT_POOL) { 5300Sstevel@tonic-gate return (seths_delete_hsp(shs)); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate /* Scan the hot spare list */ 5360Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 5370Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 5380Sstevel@tonic-gate while (hs) { 5390Sstevel@tonic-gate if (hs->hs_devnum == shs->shs_component_old) { 5400Sstevel@tonic-gate break; 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate prev_hs = hs; 5430Sstevel@tonic-gate hs = hs->hs_next; 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate if (hs == NULL) { 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate * Unable to find device using devnum so use 5490Sstevel@tonic-gate * key associated with shs_component_old instead. 5500Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 5510Sstevel@tonic-gate * then fail since namespace has multiple entries 5520Sstevel@tonic-gate * for this old component and we're unable to determine 5530Sstevel@tonic-gate * which key is the valid match for shs_component_old. 5540Sstevel@tonic-gate * 5550Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 5560Sstevel@tonic-gate */ 5570Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 5580Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 5590Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 5600Sstevel@tonic-gate shs->shs_component_old)); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 5650Sstevel@tonic-gate * since shouldn't add new hotspare if namespace has 5660Sstevel@tonic-gate * multiple entries. 5670Sstevel@tonic-gate */ 5680Sstevel@tonic-gate if (num_keys_old > 1) { 5690Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 5700Sstevel@tonic-gate shs->shs_component_old)); 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate /* 5730Sstevel@tonic-gate * If there is no key for this entry then fail since 5740Sstevel@tonic-gate * a key for this entry should exist. 5750Sstevel@tonic-gate */ 5760Sstevel@tonic-gate if (num_keys_old == 0) { 5770Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 5780Sstevel@tonic-gate shs->shs_component_old)); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate /* Scan the hot spare list again */ 5810Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 5820Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 5830Sstevel@tonic-gate while (hs) { 5840Sstevel@tonic-gate /* 5850Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate if ((hs->hs_devnum == NODEV64) && 5880Sstevel@tonic-gate (hs->hs_key == key_old)) { 5890Sstevel@tonic-gate break; 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate prev_hs = hs; 5920Sstevel@tonic-gate hs = hs->hs_next; 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if (hs == NULL) { 5970Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 5980Sstevel@tonic-gate shs->shs_component_old)); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate /* Scan the hot spare pool list */ 6020Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); 6030Sstevel@tonic-gate if (hsp == (hot_spare_pool_t *)0) { 6040Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_INVAL_HSP, 6050Sstevel@tonic-gate shs->shs_hot_spare_pool)); 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* check for force flag and state of hot spare */ 6090Sstevel@tonic-gate if (((shs->shs_options & HS_OPT_FORCE) == 0) && 6100Sstevel@tonic-gate (hs->hs_state == HSS_RESERVED)) { 6110Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_RESVD, 6120Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_old)); 6130Sstevel@tonic-gate } 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate if (hsp->hsp_refcount && (hs->hs_state == HSS_RESERVED)) { 6160Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_RESVD, 6170Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_old)); 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate /* 6210Sstevel@tonic-gate * Make sure the device is in the pool. 6220Sstevel@tonic-gate */ 6230Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 6240Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 6250Sstevel@tonic-gate break; 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate if (i >= hsp->hsp_nhotspares) { 6300Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 6310Sstevel@tonic-gate hs->hs_devnum)); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 6350Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 6360Sstevel@tonic-gate return (0); 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* lock the db records */ 6400Sstevel@tonic-gate recids[0] = hs->hs_record_id; 6410Sstevel@tonic-gate recids[1] = hsp->hsp_record_id; 6420Sstevel@tonic-gate recids[2] = 0; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate sv.setno = setno; 6450Sstevel@tonic-gate sv.key = hs->hs_key; 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate hs->hs_refcount--; 6480Sstevel@tonic-gate if (hs->hs_refcount == 0) { 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare record. 6510Sstevel@tonic-gate * There is no need, the link we get rebuilt at boot time. 6520Sstevel@tonic-gate */ 6530Sstevel@tonic-gate if (prev_hs) { 6540Sstevel@tonic-gate prev_hs->hs_next = hs->hs_next; 6550Sstevel@tonic-gate } else 6560Sstevel@tonic-gate md_set[setno].s_hs = (void *) hs->hs_next; 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* mark the hot spare to be deleted */ 6590Sstevel@tonic-gate delete_hs = 1; 6600Sstevel@tonic-gate recids[0] = hsp->hsp_record_id; 6610Sstevel@tonic-gate recids[1] = 0; 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate /* find the location of the hs in the hsp */ 6650Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 6660Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) 6670Sstevel@tonic-gate break; 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* remove the hs from the hsp */ 6710Sstevel@tonic-gate for (i++; i < hsp->hsp_nhotspares; i++) 6720Sstevel@tonic-gate hsp->hsp_hotspares[i - 1] = hsp->hsp_hotspares[i]; 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate hsp->hsp_nhotspares--; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate /* commit the db records */ 6770Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (delete_hs) 6800Sstevel@tonic-gate mddb_deleterec_wrapper(hs->hs_record_id); 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate md_rem_names(&sv, 1); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REMOVE, SVM_TAG_HSP, setno, 6850Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate return (0); 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate static int 6910Sstevel@tonic-gate seths_replace(set_hs_params_t *shs) 6920Sstevel@tonic-gate { 6930Sstevel@tonic-gate hot_spare_t *hs; 6940Sstevel@tonic-gate hot_spare_t *prev_hs; 6950Sstevel@tonic-gate hot_spare_t *new_hs; 6960Sstevel@tonic-gate hot_spare_pool_t *hsp; 6970Sstevel@tonic-gate int new_found = 0; 6980Sstevel@tonic-gate mddb_recid_t recid; 6990Sstevel@tonic-gate mddb_recid_t recids[5]; 7000Sstevel@tonic-gate int i; 7010Sstevel@tonic-gate sv_dev_t sv; 7020Sstevel@tonic-gate int delete_hs = 0; 7030Sstevel@tonic-gate set_t setno; 7040Sstevel@tonic-gate mddb_type_t typ1; 7050Sstevel@tonic-gate mdkey_t key_old; 7060Sstevel@tonic-gate int num_keys_old = 0; 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 7090Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 7100Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate /* Scan the hot spare list */ 7130Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 7140Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 7150Sstevel@tonic-gate while (hs) { 7160Sstevel@tonic-gate if (hs->hs_devnum == shs->shs_component_old) { 7170Sstevel@tonic-gate break; 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate prev_hs = hs; 7200Sstevel@tonic-gate hs = hs->hs_next; 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate if (hs == NULL) { 7240Sstevel@tonic-gate /* 7250Sstevel@tonic-gate * Unable to find device using devnum so use 7260Sstevel@tonic-gate * key associated with shs_component_old instead. 7270Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 7280Sstevel@tonic-gate * then fail since namespace has multiple entries 7290Sstevel@tonic-gate * for this old component and we're unable to determine 7300Sstevel@tonic-gate * which key is the valid match for shs_component_old. 7310Sstevel@tonic-gate * 7320Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 7330Sstevel@tonic-gate */ 7340Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 7350Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 7360Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 7370Sstevel@tonic-gate shs->shs_component_old)); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /* 7410Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 7420Sstevel@tonic-gate * since unable to determine which key is correct. 7430Sstevel@tonic-gate */ 7440Sstevel@tonic-gate if (num_keys_old > 1) { 7450Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 7460Sstevel@tonic-gate shs->shs_component_old)); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * If there is no key for this entry then fail since 7500Sstevel@tonic-gate * a key for this entry should exist. 7510Sstevel@tonic-gate */ 7520Sstevel@tonic-gate if (num_keys_old == 0) { 7530Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 7540Sstevel@tonic-gate shs->shs_component_old)); 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate /* Scan the hot spare list again */ 7570Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 7580Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 7590Sstevel@tonic-gate while (hs) { 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate if ((hs->hs_devnum == NODEV64) && 7640Sstevel@tonic-gate (hs->hs_key == key_old)) { 7650Sstevel@tonic-gate break; 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate prev_hs = hs; 7680Sstevel@tonic-gate hs = hs->hs_next; 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate if (hs == NULL) { 7730Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 7740Sstevel@tonic-gate shs->shs_component_old)); 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate /* check the force flag and the state of the hot spare */ 7780Sstevel@tonic-gate if (((shs->shs_options & HS_OPT_FORCE) == 0) && 7790Sstevel@tonic-gate (hs->hs_state == HSS_RESERVED)) { 7800Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_RESVD, 7810Sstevel@tonic-gate shs->shs_hot_spare_pool, 7820Sstevel@tonic-gate hs->hs_devnum)); 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate /* Scan the hot spare pool list */ 7860Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); 7870Sstevel@tonic-gate if (hsp == (hot_spare_pool_t *)0) { 7880Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_INVAL_HSP, 7890Sstevel@tonic-gate shs->shs_hot_spare_pool)); 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* 7930Sstevel@tonic-gate * Make sure the old device is in the pool. 7940Sstevel@tonic-gate */ 7950Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 7960Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 7970Sstevel@tonic-gate break; 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate if (i >= hsp->hsp_nhotspares) { 8010Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 8020Sstevel@tonic-gate hs->hs_devnum)); 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate /* Scan the hot spare list for the new hs */ 8060Sstevel@tonic-gate new_hs = (hot_spare_t *)md_set[setno].s_hs; 8070Sstevel@tonic-gate new_found = 0; 8080Sstevel@tonic-gate while (new_hs) { 8090Sstevel@tonic-gate if (new_hs->hs_devnum == shs->shs_component_new) { 8100Sstevel@tonic-gate new_found = 1; 8110Sstevel@tonic-gate break; 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate new_hs = new_hs->hs_next; 8140Sstevel@tonic-gate } 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * Make sure the new device is not already in the pool. 8180Sstevel@tonic-gate * We don't have to search the hs in this hsp, if the 8190Sstevel@tonic-gate * new hs was just created. Only if the hot spare was found. 8200Sstevel@tonic-gate */ 8210Sstevel@tonic-gate if (new_found) { 8220Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) 8230Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == new_hs->hs_record_id) { 8240Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_INUSE, 8250Sstevel@tonic-gate shs->shs_hot_spare_pool, 8260Sstevel@tonic-gate new_hs->hs_devnum)); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 8310Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 8320Sstevel@tonic-gate return (0); 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* 8360Sstevel@tonic-gate * Create the new hotspare 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate if (!new_found) { 8390Sstevel@tonic-gate /* create a hot spare record */ 8400Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 8410Sstevel@tonic-gate #if defined(_ILP32) 8420Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE, 8430Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_new)); 8440Sstevel@tonic-gate #else 8450Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 8460Sstevel@tonic-gate MD_CRO_64BIT | MD_CRO_HOTSPARE, setno); 8470Sstevel@tonic-gate #endif 8480Sstevel@tonic-gate } else { 8490Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 8500Sstevel@tonic-gate MD_CRO_32BIT | MD_CRO_HOTSPARE, setno); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate if (recid < 0) { 8540Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE, 8550Sstevel@tonic-gate shs->shs_hot_spare_pool, 8560Sstevel@tonic-gate shs->shs_component_new)); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate /* get the addr */ 8600Sstevel@tonic-gate new_hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, 8610Sstevel@tonic-gate sizeof (*new_hs), 0); 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate new_hs->hs_record_id = recid; 8640Sstevel@tonic-gate new_hs->hs_devnum = shs->shs_component_new; 8650Sstevel@tonic-gate new_hs->hs_key = shs->shs_key_new; 8660Sstevel@tonic-gate new_hs->hs_start_blk = shs->shs_start_blk; 8670Sstevel@tonic-gate new_hs->hs_has_label = shs->shs_has_label; 8680Sstevel@tonic-gate new_hs->hs_number_blks = shs->shs_number_blks; 8690Sstevel@tonic-gate set_hot_spare_state(new_hs, HSS_AVAILABLE); 8700Sstevel@tonic-gate new_hs->hs_refcount = 0; 8710Sstevel@tonic-gate new_hs->hs_isopen = 1; 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate /* lock the db records */ 8750Sstevel@tonic-gate recids[0] = hs->hs_record_id; 8760Sstevel@tonic-gate recids[1] = new_hs->hs_record_id; 8770Sstevel@tonic-gate recids[2] = hsp->hsp_record_id; 8780Sstevel@tonic-gate recids[3] = 0; 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate sv.setno = setno; 8810Sstevel@tonic-gate sv.key = hs->hs_key; 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate hs->hs_refcount--; 8840Sstevel@tonic-gate if (hs->hs_refcount == 0) { 8850Sstevel@tonic-gate /* 8860Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare record. 8870Sstevel@tonic-gate * There is no need, the link we get rebuilt at boot time. 8880Sstevel@tonic-gate */ 8890Sstevel@tonic-gate if (prev_hs) { 8900Sstevel@tonic-gate prev_hs->hs_next = hs->hs_next; 8910Sstevel@tonic-gate } else 8920Sstevel@tonic-gate md_set[setno].s_hs = (void *) hs->hs_next; 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* mark hs to be deleted in the correct order */ 8950Sstevel@tonic-gate delete_hs = 1; 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate recids[0] = new_hs->hs_record_id; 8980Sstevel@tonic-gate recids[1] = hsp->hsp_record_id; 8990Sstevel@tonic-gate recids[2] = 0; 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate /* link into the hs list */ 9030Sstevel@tonic-gate new_hs->hs_refcount++; 9040Sstevel@tonic-gate if (!new_found) { 9050Sstevel@tonic-gate /* do this AFTER the old dev is possibly removed */ 9060Sstevel@tonic-gate new_hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; 9070Sstevel@tonic-gate md_set[setno].s_hs = (void *) new_hs; 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate /* find the location of the old hs in the hsp */ 9110Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 9120Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 9130Sstevel@tonic-gate hsp->hsp_hotspares[i] = new_hs->hs_record_id; 9140Sstevel@tonic-gate break; 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 919*1623Stw21770 new_hs->hs_revision |= MD_64BIT_META_DEV; 9200Sstevel@tonic-gate } else { 921*1623Stw21770 new_hs->hs_revision &= ~MD_64BIT_META_DEV; 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate /* commit the db records */ 9250Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate if (delete_hs) 9280Sstevel@tonic-gate mddb_deleterec_wrapper(hs->hs_record_id); 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate md_rem_names(&sv, 1); 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REPLACE, SVM_TAG_HSP, setno, 9330Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 9340Sstevel@tonic-gate return (0); 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate static int 9380Sstevel@tonic-gate seths_enable(set_hs_params_t *shs) 9390Sstevel@tonic-gate { 9400Sstevel@tonic-gate hot_spare_t *hs; 9410Sstevel@tonic-gate mddb_recid_t recids[2]; 9420Sstevel@tonic-gate set_t setno = shs->md_driver.md_setno; 9430Sstevel@tonic-gate mdkey_t key_old; 9440Sstevel@tonic-gate int num_keys_old = 0; 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate /* 9480Sstevel@tonic-gate * Find device by using key associated with shs_component_old. 9490Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 9500Sstevel@tonic-gate * then fail since namespace has multiple entries 9510Sstevel@tonic-gate * for this old component and we're unable to determine 9520Sstevel@tonic-gate * which key is the valid match for shs_component_old. 9530Sstevel@tonic-gate * This failure keeps a hotspare from being enabled on a slice 9540Sstevel@tonic-gate * that may already be in use by another metadevice. 9550Sstevel@tonic-gate */ 9560Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 9570Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 9580Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 9590Sstevel@tonic-gate shs->shs_component_old)); 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate /* 9630Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 9640Sstevel@tonic-gate * since unable to determine which key is correct. 9650Sstevel@tonic-gate */ 9660Sstevel@tonic-gate if (num_keys_old > 1) { 9670Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 9680Sstevel@tonic-gate shs->shs_component_old)); 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate /* 9710Sstevel@tonic-gate * If there is no key for this entry then fail since 9720Sstevel@tonic-gate * a key for this entry should exist. 9730Sstevel@tonic-gate */ 9740Sstevel@tonic-gate if (num_keys_old == 0) { 9750Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 9760Sstevel@tonic-gate shs->shs_component_old)); 9770Sstevel@tonic-gate } 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate /* Scan the hot spare list for the hs */ 9800Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 9810Sstevel@tonic-gate while (hs) { 9820Sstevel@tonic-gate /* 9830Sstevel@tonic-gate * Since component may or may not be currently in the system, 9840Sstevel@tonic-gate * use the keys to find a match (not the devt). 9850Sstevel@tonic-gate */ 9860Sstevel@tonic-gate if (hs->hs_key == key_old) { 9870Sstevel@tonic-gate break; 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate hs = hs->hs_next; 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate if (hs == NULL) { 9930Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 9940Sstevel@tonic-gate shs->shs_component_old)); 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate /* make sure it's broken */ 9980Sstevel@tonic-gate if (hs->hs_state != HSS_BROKEN) { 9990Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_FIX_INVAL_HS_STATE, 10000Sstevel@tonic-gate hs->hs_devnum)); 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 10040Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 10050Sstevel@tonic-gate return (0); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate /* fix it */ 10090Sstevel@tonic-gate set_hot_spare_state(hs, HSS_AVAILABLE); 10100Sstevel@tonic-gate hs->hs_start_blk = shs->shs_start_blk; 10110Sstevel@tonic-gate hs->hs_has_label = shs->shs_has_label; 10120Sstevel@tonic-gate hs->hs_number_blks = shs->shs_number_blks; 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate /* commit the db records */ 10150Sstevel@tonic-gate recids[0] = hs->hs_record_id; 10160Sstevel@tonic-gate recids[1] = 0; 10170Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 10180Sstevel@tonic-gate SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ENABLE, SVM_TAG_HS, setno, 10190Sstevel@tonic-gate shs->shs_component_old); 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate return (0); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate static int 10250Sstevel@tonic-gate get_hs( 10260Sstevel@tonic-gate get_hs_params_t *ghs 10270Sstevel@tonic-gate ) 10280Sstevel@tonic-gate { 10290Sstevel@tonic-gate hot_spare_t *hs; 10300Sstevel@tonic-gate set_t setno = ghs->md_driver.md_setno; 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate mdclrerror(&ghs->mde); 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate /* Scan the hot spare list for the hs */ 10350Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 10360Sstevel@tonic-gate while (hs) { 10370Sstevel@tonic-gate if (hs->hs_key == ghs->ghs_key) { 10380Sstevel@tonic-gate break; 10390Sstevel@tonic-gate } 10400Sstevel@tonic-gate hs = hs->hs_next; 10410Sstevel@tonic-gate } 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate if (hs == NULL) { 10440Sstevel@tonic-gate return (mddeverror(&ghs->mde, MDE_INVAL_HS, 10450Sstevel@tonic-gate ghs->ghs_devnum)); 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate ghs->ghs_start_blk = hs->hs_start_blk; 10490Sstevel@tonic-gate ghs->ghs_number_blks = hs->hs_number_blks; 10500Sstevel@tonic-gate ghs->ghs_state = hs->hs_state; 10510Sstevel@tonic-gate ghs->ghs_timestamp = hs->hs_timestamp; 10520Sstevel@tonic-gate ghs->ghs_revision = hs->hs_revision; 10530Sstevel@tonic-gate return (0); 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate static void 10570Sstevel@tonic-gate build_key_list(set_t setno, hot_spare_pool_t *hsp, mdkey_t *list) 10580Sstevel@tonic-gate { 10590Sstevel@tonic-gate int i; 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 10620Sstevel@tonic-gate hot_spare_t *hs; 10630Sstevel@tonic-gate hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1); 10640Sstevel@tonic-gate list[i] = hs->hs_key; 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate static int 10690Sstevel@tonic-gate get_hsp( 10700Sstevel@tonic-gate void *d, 10710Sstevel@tonic-gate int mode 10720Sstevel@tonic-gate ) 10730Sstevel@tonic-gate { 10740Sstevel@tonic-gate hot_spare_pool_t *hsp; 10750Sstevel@tonic-gate get_hsp_t *ghsp; 10760Sstevel@tonic-gate size_t size; 10770Sstevel@tonic-gate set_t setno; 10780Sstevel@tonic-gate int err = 0; 10790Sstevel@tonic-gate md_i_get_t *migp = (md_i_get_t *)d; 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate setno = migp->md_driver.md_setno; 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate mdclrerror(&migp->mde); 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /* Scan the hot spare pool list */ 10870Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, migp->id); 10880Sstevel@tonic-gate if (hsp == NULL) { 10890Sstevel@tonic-gate return (mdhsperror(&migp->mde, MDE_INVAL_HSP, 10900Sstevel@tonic-gate migp->id)); 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate size = (sizeof (ghsp->ghsp_hs_keys[0]) * (hsp->hsp_nhotspares - 1)) + 10940Sstevel@tonic-gate sizeof (get_hsp_t); 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate if (migp->size == 0) { 10970Sstevel@tonic-gate migp->size = (int)size; 10980Sstevel@tonic-gate return (0); 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate if (migp->size < size) 11020Sstevel@tonic-gate return (EFAULT); 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate ghsp = kmem_alloc(size, KM_SLEEP); 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate ghsp->ghsp_id = hsp->hsp_self_id; 11070Sstevel@tonic-gate ghsp->ghsp_refcount = hsp->hsp_refcount; 11080Sstevel@tonic-gate ghsp->ghsp_nhotspares = hsp->hsp_nhotspares; 11090Sstevel@tonic-gate build_key_list(setno, hsp, ghsp->ghsp_hs_keys); 11100Sstevel@tonic-gate if (ddi_copyout(ghsp, (caddr_t)(uintptr_t)migp->mdp, size, mode)) 11110Sstevel@tonic-gate err = EFAULT; 11120Sstevel@tonic-gate kmem_free(ghsp, size); 11130Sstevel@tonic-gate return (err); 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate static int 11170Sstevel@tonic-gate set_hs( 11180Sstevel@tonic-gate set_hs_params_t *shs 11190Sstevel@tonic-gate ) 11200Sstevel@tonic-gate { 11210Sstevel@tonic-gate mdclrerror(&shs->mde); 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate if (md_get_setstatus(shs->md_driver.md_setno) & MD_SET_STALE) 11240Sstevel@tonic-gate return (mdmddberror(&shs->mde, MDE_DB_STALE, NODEV32, 11250Sstevel@tonic-gate shs->md_driver.md_setno)); 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate switch (shs->shs_cmd) { 11280Sstevel@tonic-gate case ADD_HOT_SPARE: 11290Sstevel@tonic-gate return (seths_add(shs)); 11300Sstevel@tonic-gate case DELETE_HOT_SPARE: 11310Sstevel@tonic-gate return (seths_delete(shs)); 11320Sstevel@tonic-gate case REPLACE_HOT_SPARE: 11330Sstevel@tonic-gate return (seths_replace(shs)); 11340Sstevel@tonic-gate case FIX_HOT_SPARE: 11350Sstevel@tonic-gate return (seths_enable(shs)); 11360Sstevel@tonic-gate default: 11370Sstevel@tonic-gate return (mderror(&shs->mde, MDE_INVAL_HSOP)); 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate } 11400Sstevel@tonic-gate 11410Sstevel@tonic-gate static void 11420Sstevel@tonic-gate hotspares_poke_hotspares(void) 11430Sstevel@tonic-gate { 11440Sstevel@tonic-gate intptr_t (*poke_hs)(); 11450Sstevel@tonic-gate int i; 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate for (i = 0; i < MD_NOPS; i++) { 11480Sstevel@tonic-gate /* handle change */ 11490Sstevel@tonic-gate poke_hs = md_get_named_service(NODEV64, i, "poke hotspares", 0); 11500Sstevel@tonic-gate if (poke_hs) 11510Sstevel@tonic-gate (void) (*poke_hs)(); 11520Sstevel@tonic-gate } 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate /*ARGSUSED4*/ 11570Sstevel@tonic-gate static int 11580Sstevel@tonic-gate hotspares_ioctl( 11590Sstevel@tonic-gate dev_t dev, 11600Sstevel@tonic-gate int cmd, 11610Sstevel@tonic-gate void *data, 11620Sstevel@tonic-gate int mode, 11630Sstevel@tonic-gate IOLOCK *lockp 11640Sstevel@tonic-gate ) 11650Sstevel@tonic-gate { 11660Sstevel@tonic-gate size_t sz = 0; 11670Sstevel@tonic-gate void *d = NULL; 11680Sstevel@tonic-gate int err = 0; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate /* single thread */ 11710Sstevel@tonic-gate if (getminor(dev) != MD_ADM_MINOR) 11720Sstevel@tonic-gate return (ENOTTY); 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate /* We can only handle 32-bit clients for internal commands */ 11750Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32) { 11760Sstevel@tonic-gate return (EINVAL); 11770Sstevel@tonic-gate } 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate mutex_enter(&md_mx); 11800Sstevel@tonic-gate while (md_status & MD_GBL_HS_LOCK) 11810Sstevel@tonic-gate cv_wait(&md_cv, &md_mx); 11820Sstevel@tonic-gate md_status |= MD_GBL_HS_LOCK; 11830Sstevel@tonic-gate mutex_exit(&md_mx); 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate /* dispatch ioctl */ 11860Sstevel@tonic-gate switch (cmd) { 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate case MD_IOCSET_HS: /* setup hot spares and pools */ 11890Sstevel@tonic-gate { 11900Sstevel@tonic-gate if (! (mode & FWRITE)) { 11910Sstevel@tonic-gate err = EACCES; 11920Sstevel@tonic-gate break; 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate sz = sizeof (set_hs_params_t); 11960Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP); 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) { 11990Sstevel@tonic-gate err = EFAULT; 12000Sstevel@tonic-gate break; 12010Sstevel@tonic-gate } 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate err = set_hs(d); 12040Sstevel@tonic-gate break; 12050Sstevel@tonic-gate } 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate case MD_IOCGET_HS: /* get hot spare info */ 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate if (! (mode & FREAD)) { 12100Sstevel@tonic-gate err = EACCES; 12110Sstevel@tonic-gate break; 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate sz = sizeof (get_hs_params_t); 12150Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP); 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) { 12180Sstevel@tonic-gate err = EFAULT; 12190Sstevel@tonic-gate break; 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate err = get_hs(d); 12230Sstevel@tonic-gate break; 12240Sstevel@tonic-gate } 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate case MD_IOCGET: /* get hot spare pool info */ 12270Sstevel@tonic-gate { 12280Sstevel@tonic-gate if (! (mode & FREAD)) { 12290Sstevel@tonic-gate err = EACCES; 12300Sstevel@tonic-gate break; 12310Sstevel@tonic-gate } 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate sz = sizeof (md_i_get_t); 12340Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP); 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) { 12370Sstevel@tonic-gate err = EFAULT; 12380Sstevel@tonic-gate break; 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate err = get_hsp(d, mode); 12420Sstevel@tonic-gate break; 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate default: 12460Sstevel@tonic-gate err = ENOTTY; 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate /* 12500Sstevel@tonic-gate * copyout and free any args 12510Sstevel@tonic-gate */ 12520Sstevel@tonic-gate if (sz != 0) { 12530Sstevel@tonic-gate if (err == 0) { 12540Sstevel@tonic-gate if (ddi_copyout(d, data, sz, mode) != 0) { 12550Sstevel@tonic-gate err = EFAULT; 12560Sstevel@tonic-gate } 12570Sstevel@tonic-gate } 12580Sstevel@tonic-gate kmem_free(d, sz); 12590Sstevel@tonic-gate } 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate /* un single thread */ 12620Sstevel@tonic-gate mutex_enter(&md_mx); 12630Sstevel@tonic-gate md_status &= ~MD_GBL_HS_LOCK; 12640Sstevel@tonic-gate cv_broadcast(&md_cv); 12650Sstevel@tonic-gate mutex_exit(&md_mx); 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate /* handle change */ 12680Sstevel@tonic-gate hotspares_poke_hotspares(); 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate /* return success */ 12710Sstevel@tonic-gate return (err); 12720Sstevel@tonic-gate } 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate static void 12760Sstevel@tonic-gate load_hotspare(set_t setno, mddb_recid_t recid) 12770Sstevel@tonic-gate { 12780Sstevel@tonic-gate hot_spare_t *hs; 12790Sstevel@tonic-gate mddb_de_ic_t *dep; 12800Sstevel@tonic-gate mddb_rb32_t *rbp; 12810Sstevel@tonic-gate size_t newreqsize; 12820Sstevel@tonic-gate hot_spare_t *b_hs; 12830Sstevel@tonic-gate hot_spare32_od_t *s_hs; 12840Sstevel@tonic-gate 12850Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate dep = mddb_getrecdep(recid); 12880Sstevel@tonic-gate dep->de_flags = MDDB_F_HOTSPARE; 12890Sstevel@tonic-gate rbp = dep->de_rb; 1290*1623Stw21770 switch (rbp->rb_revision) { 1291*1623Stw21770 case MDDB_REV_RB: 1292*1623Stw21770 case MDDB_REV_RBFN: 12930Sstevel@tonic-gate /* 12940Sstevel@tonic-gate * Needs to convert to internal 64 bit 12950Sstevel@tonic-gate */ 12960Sstevel@tonic-gate s_hs = (hot_spare32_od_t *)mddb_getrecaddr(recid); 12970Sstevel@tonic-gate newreqsize = sizeof (hot_spare_t); 12980Sstevel@tonic-gate b_hs = (hot_spare_t *)kmem_zalloc(newreqsize, KM_SLEEP); 12990Sstevel@tonic-gate hs_convert((caddr_t)s_hs, (caddr_t)b_hs, SMALL_2_BIG); 13000Sstevel@tonic-gate kmem_free(s_hs, dep->de_reqsize); 13010Sstevel@tonic-gate dep->de_rb_userdata = b_hs; 13020Sstevel@tonic-gate dep->de_reqsize = newreqsize; 13030Sstevel@tonic-gate hs = b_hs; 1304*1623Stw21770 break; 1305*1623Stw21770 case MDDB_REV_RB64: 1306*1623Stw21770 case MDDB_REV_RB64FN: 13070Sstevel@tonic-gate hs = (hot_spare_t *)mddb_getrecaddr_resize 13080Sstevel@tonic-gate (recid, sizeof (*hs), 0); 1309*1623Stw21770 break; 13100Sstevel@tonic-gate } 1311*1623Stw21770 NOTE_FN(rbp->rb_revision, hs->hs_revision); 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate #if defined(_ILP32) 1314*1623Stw21770 if (hs->hs_revision & MD_64BIT_META_DEV) { 13150Sstevel@tonic-gate char devname[MD_MAX_CTDLEN]; 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate set_hot_spare_state(hs, HSS_BROKEN); 13180Sstevel@tonic-gate (void) md_devname(setno, hs->hs_devnum, devname, 13190Sstevel@tonic-gate sizeof (devname)); 13200Sstevel@tonic-gate cmn_err(CE_NOTE, "%s is unavailable because 64 bit hotspares " 13210Sstevel@tonic-gate "are not accessible on a 32 bit kernel\n", devname); 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate #endif 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate ASSERT(hs != NULL); 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate if (hs->hs_refcount == 0) { 13280Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_PENDDEL); 13290Sstevel@tonic-gate return; 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; 13330Sstevel@tonic-gate md_set[setno].s_hs = (void *)hs; 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate hs->hs_isopen = 0; 13360Sstevel@tonic-gate 13370Sstevel@tonic-gate hs->hs_devnum = md_getdevnum(setno, mddb_getsidenum(setno), 13380Sstevel@tonic-gate hs->hs_key, MD_NOTRUST_DEVT); 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate static void 13430Sstevel@tonic-gate load_hotsparepool(set_t setno, mddb_recid_t recid) 13440Sstevel@tonic-gate { 13450Sstevel@tonic-gate hot_spare_pool_t *hsp; 13460Sstevel@tonic-gate hot_spare_pool_ond_t *hsp_ond; 13470Sstevel@tonic-gate size_t hsp_icsize; 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid); 13520Sstevel@tonic-gate ASSERT(hsp_ond != NULL); 13530Sstevel@tonic-gate 13540Sstevel@tonic-gate if (hsp_ond->hsp_self_id == MD_HSP_NONE) { 13550Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_PENDDEL); 13560Sstevel@tonic-gate return; 13570Sstevel@tonic-gate } 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate hsp_icsize = HSP_ONDSK_STR_OFF + mddb_getrecsize(recid); 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, hsp_icsize, 13620Sstevel@tonic-gate HSP_ONDSK_STR_OFF); 13630Sstevel@tonic-gate hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; 13640Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp; 13650Sstevel@tonic-gate 13660Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 13670Sstevel@tonic-gate hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 13680Sstevel@tonic-gate hsp->hsp_link.ln_setno = setno; 13690Sstevel@tonic-gate hsp->hsp_link.ln_id = hsp->hsp_self_id; 13700Sstevel@tonic-gate hotspares_md_ops.md_head = &hsp->hsp_link; 13710Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 13720Sstevel@tonic-gate } 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate static int 13750Sstevel@tonic-gate hotspares_snarf(md_snarfcmd_t cmd, set_t setno) 13760Sstevel@tonic-gate { 13770Sstevel@tonic-gate mddb_recid_t recid; 13780Sstevel@tonic-gate int gotsomething; 13790Sstevel@tonic-gate mddb_type_t typ1; 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate if (cmd == MD_SNARF_CLEANUP) 13820Sstevel@tonic-gate return (0); 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate gotsomething = 0; 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 13870Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 13880Sstevel@tonic-gate recid = mddb_makerecid(setno, 0); 13890Sstevel@tonic-gate while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) { 13900Sstevel@tonic-gate if (mddb_getrecprivate(recid) & MD_PRV_GOTIT) 13910Sstevel@tonic-gate continue; 13920Sstevel@tonic-gate 13930Sstevel@tonic-gate switch (mddb_getrectype2(recid)) { 13940Sstevel@tonic-gate case HSP_REC: 13950Sstevel@tonic-gate load_hotsparepool(setno, recid); 13960Sstevel@tonic-gate gotsomething = 1; 13970Sstevel@tonic-gate break; 13980Sstevel@tonic-gate case HS_REC: 13990Sstevel@tonic-gate load_hotspare(setno, recid); 14000Sstevel@tonic-gate gotsomething = 1; 14010Sstevel@tonic-gate break; 14020Sstevel@tonic-gate default: 14030Sstevel@tonic-gate ASSERT(0); 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate } 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate if (gotsomething) 14080Sstevel@tonic-gate return (gotsomething); 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate recid = mddb_makerecid(setno, 0); 14110Sstevel@tonic-gate while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) 14120Sstevel@tonic-gate if (!(mddb_getrecprivate(recid) & MD_PRV_GOTIT)) 14130Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_PENDDEL); 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate return (0); 14160Sstevel@tonic-gate } 14170Sstevel@tonic-gate 14180Sstevel@tonic-gate static int 14190Sstevel@tonic-gate hotspares_halt(md_haltcmd_t cmd, set_t setno) 14200Sstevel@tonic-gate { 14210Sstevel@tonic-gate hot_spare_t *hs, **p_hs; 14220Sstevel@tonic-gate hot_spare_pool_t *hsp, **p_hsp; 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate if (cmd == MD_HALT_CLOSE) 14250Sstevel@tonic-gate return (0); 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate if (cmd == MD_HALT_OPEN) 14280Sstevel@tonic-gate return (0); 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate if (cmd == MD_HALT_CHECK) 14310Sstevel@tonic-gate return (0); 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate if (cmd == MD_HALT_UNLOAD) 14340Sstevel@tonic-gate return (0); 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate if (cmd != MD_HALT_DOIT) 14370Sstevel@tonic-gate return (1); 14380Sstevel@tonic-gate /* 14390Sstevel@tonic-gate * Find all the hotspares for set "setno" 14400Sstevel@tonic-gate * and remove them from the hot_spare_list. 14410Sstevel@tonic-gate */ 14420Sstevel@tonic-gate p_hs = (hot_spare_t **)&md_set[setno].s_hs; 14430Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 14440Sstevel@tonic-gate for (; hs != NULL; hs = *p_hs) 14450Sstevel@tonic-gate *p_hs = hs->hs_next; 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate /* 14480Sstevel@tonic-gate * Find all the hotspare pools for set "setno" 14490Sstevel@tonic-gate * and remove them from the hot_spare_pools list. 14500Sstevel@tonic-gate * Also remove from the get_next list. 14510Sstevel@tonic-gate */ 14520Sstevel@tonic-gate p_hsp = (hot_spare_pool_t **)&md_set[setno].s_hsp; 14530Sstevel@tonic-gate hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; 14540Sstevel@tonic-gate for (; hsp != NULL; hsp = *p_hsp) { 14550Sstevel@tonic-gate md_rem_link(setno, hsp->hsp_self_id, 14560Sstevel@tonic-gate &hotspares_md_ops.md_link_rw.lock, 14570Sstevel@tonic-gate &hotspares_md_ops.md_head); 14580Sstevel@tonic-gate *p_hsp = hsp->hsp_next; 14590Sstevel@tonic-gate } 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate return (0); 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate static hot_spare_t * 14650Sstevel@tonic-gate usable_hs( 14660Sstevel@tonic-gate set_t setno, 14670Sstevel@tonic-gate mddb_recid_t hs_id, 14680Sstevel@tonic-gate diskaddr_t nblks, 14690Sstevel@tonic-gate int labeled, 14700Sstevel@tonic-gate diskaddr_t *start) 14710Sstevel@tonic-gate { 14720Sstevel@tonic-gate hot_spare_t *hs; 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate hs = lookup_hot_spare(setno, hs_id, 1); 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate if (hs->hs_state != HSS_AVAILABLE) 14770Sstevel@tonic-gate return ((hot_spare_t *)0); 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate if (labeled && hs->hs_has_label && (hs->hs_number_blks >= nblks)) { 14800Sstevel@tonic-gate *start = 0; 14810Sstevel@tonic-gate return (hs); 14820Sstevel@tonic-gate } else if ((hs->hs_number_blks - hs->hs_start_blk) >= nblks) { 14830Sstevel@tonic-gate *start = hs->hs_start_blk; 14840Sstevel@tonic-gate return (hs); 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate return ((hot_spare_t *)0); 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate static int 14900Sstevel@tonic-gate reserve_a_hs( 14910Sstevel@tonic-gate set_t setno, 14920Sstevel@tonic-gate mddb_recid_t id, 14930Sstevel@tonic-gate uint64_t size, 14940Sstevel@tonic-gate int labeled, 14950Sstevel@tonic-gate mddb_recid_t *hs_id, 14960Sstevel@tonic-gate mdkey_t *key, 14970Sstevel@tonic-gate md_dev64_t *dev, 14980Sstevel@tonic-gate diskaddr_t *sblock) 14990Sstevel@tonic-gate { 15000Sstevel@tonic-gate hot_spare_pool_t *hsp; 15010Sstevel@tonic-gate hot_spare_t *hs; 15020Sstevel@tonic-gate int i; 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate *hs_id = 0; 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, id); 15070Sstevel@tonic-gate if (hsp == NULL) 15080Sstevel@tonic-gate return (-1); 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 15110Sstevel@tonic-gate hs = usable_hs(setno, hsp->hsp_hotspares[i], 15120Sstevel@tonic-gate size, labeled, sblock); 15130Sstevel@tonic-gate if (hs == NULL) 15140Sstevel@tonic-gate continue; 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate set_hot_spare_state(hs, HSS_RESERVED); 15170Sstevel@tonic-gate *hs_id = hs->hs_record_id; 15180Sstevel@tonic-gate *key = hs->hs_key; 15190Sstevel@tonic-gate *dev = hs->hs_devnum; 15200Sstevel@tonic-gate /* NOTE: Mirror code commits the hs record */ 15210Sstevel@tonic-gate return (0); 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate return (-1); 15250Sstevel@tonic-gate } 15260Sstevel@tonic-gate 15270Sstevel@tonic-gate 15280Sstevel@tonic-gate /* ARGSUSED3 */ 15290Sstevel@tonic-gate static int 15300Sstevel@tonic-gate return_a_hs( 15310Sstevel@tonic-gate set_t setno, 15320Sstevel@tonic-gate mddb_recid_t id, 15330Sstevel@tonic-gate mddb_recid_t *hs_id, 15340Sstevel@tonic-gate mdkey_t key, 15350Sstevel@tonic-gate diskaddr_t sblock, 15360Sstevel@tonic-gate uint64_t size, 15370Sstevel@tonic-gate hotspare_states_t new_state) 15380Sstevel@tonic-gate { 15390Sstevel@tonic-gate hot_spare_pool_t *hsp; 15400Sstevel@tonic-gate hot_spare_t *hs; 15410Sstevel@tonic-gate int i; 15420Sstevel@tonic-gate 15430Sstevel@tonic-gate /* 15440Sstevel@tonic-gate * NOTE: sblock/size are not currently being used. 15450Sstevel@tonic-gate * That is because we always allocate the whole hs. 15460Sstevel@tonic-gate * Later if we choose to allocate only what is needed 15470Sstevel@tonic-gate * then the sblock/size can be used to determine 15480Sstevel@tonic-gate * which part is being unreseved. 15490Sstevel@tonic-gate */ 15500Sstevel@tonic-gate *hs_id = 0; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, id); 15530Sstevel@tonic-gate if (hsp == NULL) 15540Sstevel@tonic-gate return (-1); 15550Sstevel@tonic-gate 15560Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 15570Sstevel@tonic-gate hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1); 15580Sstevel@tonic-gate if (hs->hs_key != key) 15590Sstevel@tonic-gate continue; 15600Sstevel@tonic-gate 15610Sstevel@tonic-gate set_hot_spare_state(hs, new_state); 15620Sstevel@tonic-gate *hs_id = hs->hs_record_id; 15630Sstevel@tonic-gate if (new_state == HSS_BROKEN) { 15640Sstevel@tonic-gate SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ERRED, SVM_TAG_HS, 15650Sstevel@tonic-gate setno, hs->hs_devnum); 15660Sstevel@tonic-gate } 15670Sstevel@tonic-gate if (new_state == HSS_AVAILABLE) { 15680Sstevel@tonic-gate SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_HS, 15690Sstevel@tonic-gate setno, hs->hs_devnum); 15700Sstevel@tonic-gate } 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate /* NOTE: Mirror/Raid code commits the hs record */ 15730Sstevel@tonic-gate return (0); 15740Sstevel@tonic-gate } 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate return (-1); 15770Sstevel@tonic-gate } 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate 15800Sstevel@tonic-gate static int 15810Sstevel@tonic-gate modify_hsp_ref(set_t setno, mddb_recid_t id, int incref, mddb_recid_t *hsp_id) 15820Sstevel@tonic-gate { 15830Sstevel@tonic-gate hot_spare_pool_t *hsp; 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate *hsp_id = 0; 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate if (id < 0) 15880Sstevel@tonic-gate return (0); 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, id); 15910Sstevel@tonic-gate if (hsp == NULL) 15920Sstevel@tonic-gate return (-1); 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate if (incref) 15950Sstevel@tonic-gate hsp->hsp_refcount++; 15960Sstevel@tonic-gate else 15970Sstevel@tonic-gate hsp->hsp_refcount--; 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate *hsp_id = hsp->hsp_record_id; 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate /* NOTE: Stripe code commits the hsp record */ 16020Sstevel@tonic-gate return (0); 16030Sstevel@tonic-gate } 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate 16060Sstevel@tonic-gate static int 16070Sstevel@tonic-gate mkdev_for_a_hs(mddb_recid_t hs_id, md_dev64_t *dev) 16080Sstevel@tonic-gate { 16090Sstevel@tonic-gate hot_spare_t *hs; 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate hs = lookup_hot_spare(mddb_getsetnum(hs_id), hs_id, 0); 16120Sstevel@tonic-gate if (hs == NULL) 16130Sstevel@tonic-gate return (0); 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate *dev = hs->hs_devnum; 16160Sstevel@tonic-gate return (0); 16170Sstevel@tonic-gate } 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate static intptr_t 16200Sstevel@tonic-gate hotspares_interface( 16210Sstevel@tonic-gate hs_cmds_t cmd, 16220Sstevel@tonic-gate mddb_recid_t id, 16230Sstevel@tonic-gate uint64_t size, 16240Sstevel@tonic-gate int bool, 16250Sstevel@tonic-gate mddb_recid_t *hs_id, 16260Sstevel@tonic-gate mdkey_t *key, 16270Sstevel@tonic-gate md_dev64_t *dev, 16280Sstevel@tonic-gate diskaddr_t *sblock) 16290Sstevel@tonic-gate { 16300Sstevel@tonic-gate set_t setno; 16310Sstevel@tonic-gate int err = -1; 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate mutex_enter(&md_mx); 16340Sstevel@tonic-gate while (md_status & MD_GBL_HS_LOCK) 16350Sstevel@tonic-gate cv_wait(&md_cv, &md_mx); 16360Sstevel@tonic-gate 16370Sstevel@tonic-gate /* If md_halt has been run do not continue */ 16380Sstevel@tonic-gate if (md_status & (MD_GBL_HALTED | MD_GBL_DAEMONS_DIE)) { 16390Sstevel@tonic-gate mutex_exit(&md_mx); 16400Sstevel@tonic-gate return (ENXIO); 16410Sstevel@tonic-gate } 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate md_status |= MD_GBL_HS_LOCK; 16440Sstevel@tonic-gate mutex_exit(&md_mx); 16450Sstevel@tonic-gate 16460Sstevel@tonic-gate setno = mddb_getsetnum(id); 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate switch (cmd) { 16490Sstevel@tonic-gate case HS_GET: 16500Sstevel@tonic-gate err = reserve_a_hs(setno, id, size, bool, hs_id, 16510Sstevel@tonic-gate key, dev, sblock); 16520Sstevel@tonic-gate break; 16530Sstevel@tonic-gate case HS_FREE: 16540Sstevel@tonic-gate err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_AVAILABLE); 16550Sstevel@tonic-gate hotspares_poke_hotspares(); 16560Sstevel@tonic-gate break; 16570Sstevel@tonic-gate case HS_BAD: 16580Sstevel@tonic-gate err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_BROKEN); 16590Sstevel@tonic-gate break; 16600Sstevel@tonic-gate case HSP_INCREF: 16610Sstevel@tonic-gate err = modify_hsp_ref(setno, id, 1, hs_id); 16620Sstevel@tonic-gate break; 16630Sstevel@tonic-gate case HSP_DECREF: 16640Sstevel@tonic-gate err = modify_hsp_ref(setno, id, 0, hs_id); 16650Sstevel@tonic-gate break; 16660Sstevel@tonic-gate case HS_MKDEV: 16670Sstevel@tonic-gate err = mkdev_for_a_hs(*hs_id, dev); 16680Sstevel@tonic-gate break; 16690Sstevel@tonic-gate } 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate mutex_enter(&md_mx); 16720Sstevel@tonic-gate md_status &= ~MD_GBL_HS_LOCK; 16730Sstevel@tonic-gate cv_broadcast(&md_cv); 16740Sstevel@tonic-gate mutex_exit(&md_mx); 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate return (err); 16770Sstevel@tonic-gate } 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate static void 16800Sstevel@tonic-gate imp_hotsparepool( 16810Sstevel@tonic-gate set_t setno, 16820Sstevel@tonic-gate mddb_recid_t recid 16830Sstevel@tonic-gate ) 16840Sstevel@tonic-gate { 16850Sstevel@tonic-gate hot_spare_pool_ond_t *hsp_ond; 16860Sstevel@tonic-gate mddb_recid_t *hsp_recid, *hs_recid; 16870Sstevel@tonic-gate int i; 16880Sstevel@tonic-gate uint_t *hsp_selfid; 16890Sstevel@tonic-gate 16900Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid); 16930Sstevel@tonic-gate hsp_recid = &(hsp_ond->hsp_record_id); 16940Sstevel@tonic-gate hsp_selfid = &(hsp_ond->hsp_self_id); 16950Sstevel@tonic-gate /* 16960Sstevel@tonic-gate * Fixup the pool and hotspares 16970Sstevel@tonic-gate */ 16980Sstevel@tonic-gate *hsp_recid = MAKERECID(setno, DBID(*hsp_recid)); 16990Sstevel@tonic-gate *hsp_selfid = MAKERECID(setno, DBID(*hsp_selfid)); 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate for (i = 0; i < hsp_ond->hsp_nhotspares; i++) { 17020Sstevel@tonic-gate hs_recid = &(hsp_ond->hsp_hotspares[i]); 17030Sstevel@tonic-gate *hs_recid = MAKERECID(setno, DBID(*hs_recid)); 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate static void 17080Sstevel@tonic-gate imp_hotspare( 17090Sstevel@tonic-gate set_t setno, 17100Sstevel@tonic-gate mddb_recid_t recid 17110Sstevel@tonic-gate ) 17120Sstevel@tonic-gate { 17130Sstevel@tonic-gate mddb_de_ic_t *dep; 17140Sstevel@tonic-gate mddb_rb32_t *rbp; 17150Sstevel@tonic-gate hot_spare_t *hs64; 17160Sstevel@tonic-gate hot_spare32_od_t *hs32; 17170Sstevel@tonic-gate mddb_recid_t *hs_recid; 17180Sstevel@tonic-gate 17190Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate dep = mddb_getrecdep(recid); 17220Sstevel@tonic-gate rbp = dep->de_rb; 1723*1623Stw21770 switch (rbp->rb_revision) { 1724*1623Stw21770 case MDDB_REV_RB: 1725*1623Stw21770 case MDDB_REV_RBFN: 17260Sstevel@tonic-gate /* 17270Sstevel@tonic-gate * 32 bit hotspare 17280Sstevel@tonic-gate */ 17290Sstevel@tonic-gate hs32 = (hot_spare32_od_t *)mddb_getrecaddr(recid); 17300Sstevel@tonic-gate hs_recid = &(hs32->hs_record_id); 1731*1623Stw21770 break; 1732*1623Stw21770 case MDDB_REV_RB64: 1733*1623Stw21770 case MDDB_REV_RB64FN: 17340Sstevel@tonic-gate hs64 = (hot_spare_t *)mddb_getrecaddr(recid); 17350Sstevel@tonic-gate hs_recid = &(hs64->hs_record_id); 1736*1623Stw21770 break; 17370Sstevel@tonic-gate } 17380Sstevel@tonic-gate 17390Sstevel@tonic-gate /* 17400Sstevel@tonic-gate * Fixup the setno 17410Sstevel@tonic-gate */ 17420Sstevel@tonic-gate *hs_recid = MAKERECID(setno, DBID(*hs_recid)); 17430Sstevel@tonic-gate } 17440Sstevel@tonic-gate 17450Sstevel@tonic-gate static int 17460Sstevel@tonic-gate hotspares_imp_set( 17470Sstevel@tonic-gate set_t setno 17480Sstevel@tonic-gate ) 17490Sstevel@tonic-gate { 17500Sstevel@tonic-gate mddb_recid_t recid; 17510Sstevel@tonic-gate int gotsomething; 17520Sstevel@tonic-gate mddb_type_t typ1; 17530Sstevel@tonic-gate 17540Sstevel@tonic-gate 17550Sstevel@tonic-gate gotsomething = 0; 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 17580Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 17590Sstevel@tonic-gate recid = mddb_makerecid(setno, 0); 17600Sstevel@tonic-gate while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) { 17610Sstevel@tonic-gate if (mddb_getrecprivate(recid) & MD_PRV_GOTIT) 17620Sstevel@tonic-gate continue; 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate switch (mddb_getrectype2(recid)) { 17650Sstevel@tonic-gate case HSP_REC: 17660Sstevel@tonic-gate imp_hotsparepool(setno, recid); 17670Sstevel@tonic-gate gotsomething = 1; 17680Sstevel@tonic-gate break; 17690Sstevel@tonic-gate case HS_REC: 17700Sstevel@tonic-gate imp_hotspare(setno, recid); 17710Sstevel@tonic-gate gotsomething = 1; 17720Sstevel@tonic-gate break; 17730Sstevel@tonic-gate default: 17740Sstevel@tonic-gate ASSERT(0); 17750Sstevel@tonic-gate } 17760Sstevel@tonic-gate } 17770Sstevel@tonic-gate 17780Sstevel@tonic-gate return (gotsomething); 17790Sstevel@tonic-gate } 17800Sstevel@tonic-gate 17810Sstevel@tonic-gate static md_named_services_t hotspares_named_services[] = { 17820Sstevel@tonic-gate {hotspares_interface, "hot spare interface"}, 17830Sstevel@tonic-gate {NULL, 0} 17840Sstevel@tonic-gate }; 17850Sstevel@tonic-gate 17860Sstevel@tonic-gate md_ops_t hotspares_md_ops = { 17870Sstevel@tonic-gate NULL, /* open */ 17880Sstevel@tonic-gate NULL, /* close */ 17890Sstevel@tonic-gate NULL, /* strategy */ 17900Sstevel@tonic-gate NULL, /* print */ 17910Sstevel@tonic-gate NULL, /* dump */ 17920Sstevel@tonic-gate NULL, /* read */ 17930Sstevel@tonic-gate NULL, /* write */ 17940Sstevel@tonic-gate hotspares_ioctl, /* hotspares_ioctl, */ 17950Sstevel@tonic-gate hotspares_snarf, /* hotspares_snarf */ 17960Sstevel@tonic-gate hotspares_halt, /* halt */ 17970Sstevel@tonic-gate NULL, /* aread */ 17980Sstevel@tonic-gate NULL, /* awrite */ 17990Sstevel@tonic-gate hotspares_imp_set, /* import set */ 18000Sstevel@tonic-gate hotspares_named_services /* named_services */ 18010Sstevel@tonic-gate }; 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate static void 18040Sstevel@tonic-gate fini_uninit() 18050Sstevel@tonic-gate { 18060Sstevel@tonic-gate /* prevent access to services that may have been imported */ 18070Sstevel@tonic-gate md_clear_hot_spare_interface(); 18080Sstevel@tonic-gate } 18090Sstevel@tonic-gate 18100Sstevel@tonic-gate /* define the module linkage */ 18110Sstevel@tonic-gate MD_PLUGIN_MISC_MODULE("hot spares module %I%", md_noop, fini_uninit()) 1812