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