1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/param.h> 30*0Sstevel@tonic-gate #include <sys/systm.h> 31*0Sstevel@tonic-gate #include <sys/conf.h> 32*0Sstevel@tonic-gate #include <sys/file.h> 33*0Sstevel@tonic-gate #include <sys/user.h> 34*0Sstevel@tonic-gate #include <sys/uio.h> 35*0Sstevel@tonic-gate #include <sys/t_lock.h> 36*0Sstevel@tonic-gate #include <sys/kmem.h> 37*0Sstevel@tonic-gate #include <vm/page.h> 38*0Sstevel@tonic-gate #include <sys/sysmacros.h> 39*0Sstevel@tonic-gate #include <sys/types.h> 40*0Sstevel@tonic-gate #include <sys/mkdev.h> 41*0Sstevel@tonic-gate #include <sys/stat.h> 42*0Sstevel@tonic-gate #include <sys/open.h> 43*0Sstevel@tonic-gate #include <sys/modctl.h> 44*0Sstevel@tonic-gate #include <sys/ddi.h> 45*0Sstevel@tonic-gate #include <sys/sunddi.h> 46*0Sstevel@tonic-gate #include <sys/debug.h> 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h> 49*0Sstevel@tonic-gate #include <sys/lvm/md_convert.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h> 52*0Sstevel@tonic-gate #include <sys/sysevent/svm.h> 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate md_ops_t hotspares_md_ops; 55*0Sstevel@tonic-gate #ifndef lint 56*0Sstevel@tonic-gate static char _depends_on[] = "drv/md"; 57*0Sstevel@tonic-gate md_ops_t *md_interface_ops = &hotspares_md_ops; 58*0Sstevel@tonic-gate #endif 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate extern md_ops_t **md_ops; 61*0Sstevel@tonic-gate extern md_ops_t *md_opslist; 62*0Sstevel@tonic-gate extern md_set_t md_set[]; 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate extern kmutex_t md_mx; /* used to md global stuff */ 65*0Sstevel@tonic-gate extern kcondvar_t md_cv; /* md_status events */ 66*0Sstevel@tonic-gate extern int md_status; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate extern void md_clear_hot_spare_interface(); 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate static void 71*0Sstevel@tonic-gate set_hot_spare_state(hot_spare_t *hs, hotspare_states_t newstate) 72*0Sstevel@tonic-gate { 73*0Sstevel@tonic-gate hs->hs_state = newstate; 74*0Sstevel@tonic-gate uniqtime32(&hs->hs_timestamp); 75*0Sstevel@tonic-gate } 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate static hot_spare_t * 78*0Sstevel@tonic-gate lookup_hot_spare(set_t setno, mddb_recid_t hs_id, int must_exist) 79*0Sstevel@tonic-gate { 80*0Sstevel@tonic-gate hot_spare_t *hs; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate for (hs = (hot_spare_t *)md_set[setno].s_hs; hs; hs = hs->hs_next) { 83*0Sstevel@tonic-gate if (hs->hs_record_id == hs_id) 84*0Sstevel@tonic-gate return (hs); 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate if (must_exist) 87*0Sstevel@tonic-gate ASSERT(0); 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate return ((hot_spare_t *)NULL); 90*0Sstevel@tonic-gate } 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate static hot_spare_pool_t * 93*0Sstevel@tonic-gate find_hot_spare_pool(set_t setno, int hsp_id) 94*0Sstevel@tonic-gate { 95*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; 98*0Sstevel@tonic-gate while (hsp != NULL) { 99*0Sstevel@tonic-gate if (hsp->hsp_self_id == hsp_id) 100*0Sstevel@tonic-gate return (hsp); 101*0Sstevel@tonic-gate hsp = hsp->hsp_next; 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate return ((hot_spare_pool_t *)0); 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate static int 109*0Sstevel@tonic-gate seths_create_hsp(set_hs_params_t *shs) 110*0Sstevel@tonic-gate { 111*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 112*0Sstevel@tonic-gate mddb_recid_t recid; 113*0Sstevel@tonic-gate set_t setno; 114*0Sstevel@tonic-gate mddb_type_t typ1; 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* Scan the hot spare pool list */ 119*0Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); 120*0Sstevel@tonic-gate if (hsp != (hot_spare_pool_t *)0) 121*0Sstevel@tonic-gate return (0); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 124*0Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate /* create a hot spare pool record */ 127*0Sstevel@tonic-gate if (shs->shs_options & MD_CRO_64BIT) { 128*0Sstevel@tonic-gate #if defined(_ILP32) 129*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_UNIT_TOO_LARGE, 130*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 131*0Sstevel@tonic-gate #else 132*0Sstevel@tonic-gate recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1, 133*0Sstevel@tonic-gate HSP_REC, MD_CRO_64BIT | MD_CRO_HOTSPARE_POOL, setno); 134*0Sstevel@tonic-gate #endif 135*0Sstevel@tonic-gate } else { 136*0Sstevel@tonic-gate recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1, 137*0Sstevel@tonic-gate HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL, setno); 138*0Sstevel@tonic-gate } 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate if (recid < 0) { 141*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, 142*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* get the record addr */ 146*0Sstevel@tonic-gate hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, sizeof (*hsp), 147*0Sstevel@tonic-gate HSP_ONDSK_STR_OFF); 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate hsp->hsp_self_id = shs->shs_hot_spare_pool; 150*0Sstevel@tonic-gate hsp->hsp_record_id = recid; 151*0Sstevel@tonic-gate hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; 152*0Sstevel@tonic-gate hsp->hsp_refcount = 0; 153*0Sstevel@tonic-gate hsp->hsp_nhotspares = 0; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate mddb_commitrec_wrapper(recid); 158*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno, 159*0Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 162*0Sstevel@tonic-gate hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 163*0Sstevel@tonic-gate hsp->hsp_link.ln_setno = setno; 164*0Sstevel@tonic-gate hsp->hsp_link.ln_id = hsp->hsp_self_id; 165*0Sstevel@tonic-gate hotspares_md_ops.md_head = &hsp->hsp_link; 166*0Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate return (0); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate static int 173*0Sstevel@tonic-gate seths_add(set_hs_params_t *shs) 174*0Sstevel@tonic-gate { 175*0Sstevel@tonic-gate hot_spare_t *hs; 176*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 177*0Sstevel@tonic-gate hot_spare_pool_t *prev_hsp; 178*0Sstevel@tonic-gate hot_spare_pool_t *new_hsp; 179*0Sstevel@tonic-gate hot_spare_pool_t *old_hsp; 180*0Sstevel@tonic-gate mddb_recid_t recid; 181*0Sstevel@tonic-gate mddb_recid_t recids[5]; 182*0Sstevel@tonic-gate size_t new_size; 183*0Sstevel@tonic-gate int i; 184*0Sstevel@tonic-gate int delete_hsp = 0; 185*0Sstevel@tonic-gate int irecid; 186*0Sstevel@tonic-gate set_t setno; 187*0Sstevel@tonic-gate mddb_type_t typ1; 188*0Sstevel@tonic-gate int hsp_created = 0; 189*0Sstevel@tonic-gate mdkey_t key_old; 190*0Sstevel@tonic-gate int num_keys_old = 0; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate /* Not much to do here in case of a dryrun */ 193*0Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 194*0Sstevel@tonic-gate return (0); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* create an empty hot spare pool */ 198*0Sstevel@tonic-gate if (shs->shs_options & HS_OPT_POOL) { 199*0Sstevel@tonic-gate return (seths_create_hsp(shs)); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 203*0Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 204*0Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate /* Scan the hot spare list */ 207*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 208*0Sstevel@tonic-gate while (hs) { 209*0Sstevel@tonic-gate if (hs->hs_devnum == shs->shs_component_old) { 210*0Sstevel@tonic-gate break; 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate hs = hs->hs_next; 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate if (hs == NULL) { 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * Did not find match for device using devnum so use 218*0Sstevel@tonic-gate * key associated with shs_component_old just 219*0Sstevel@tonic-gate * in case there is a match but the match's dev is NODEV. 220*0Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 221*0Sstevel@tonic-gate * then fail since namespace has multiple entries 222*0Sstevel@tonic-gate * for this old component and we shouldn't allow 223*0Sstevel@tonic-gate * an addition of a hotspare in this case. 224*0Sstevel@tonic-gate */ 225*0Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 226*0Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 227*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 228*0Sstevel@tonic-gate shs->shs_component_old)); 229*0Sstevel@tonic-gate } 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate /* 232*0Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 233*0Sstevel@tonic-gate * since shouldn't add new hotspare if namespace has 234*0Sstevel@tonic-gate * multiple entries. 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate if (num_keys_old > 1) { 237*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 238*0Sstevel@tonic-gate shs->shs_component_old)); 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * If there is no key for this entry then fail since 242*0Sstevel@tonic-gate * a key for this entry should exist. 243*0Sstevel@tonic-gate */ 244*0Sstevel@tonic-gate if (num_keys_old == 0) { 245*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 246*0Sstevel@tonic-gate shs->shs_component_old)); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate /* Scan the hot spare list again */ 249*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 250*0Sstevel@tonic-gate while (hs) { 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate if ((hs->hs_devnum == NODEV64) && 255*0Sstevel@tonic-gate (hs->hs_key == key_old)) { 256*0Sstevel@tonic-gate break; 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate hs = hs->hs_next; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate if (hs == NULL) { 263*0Sstevel@tonic-gate /* create a hot spare record */ 264*0Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 265*0Sstevel@tonic-gate #if defined(_ILP32) 266*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE, 267*0Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_old)); 268*0Sstevel@tonic-gate #else 269*0Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 270*0Sstevel@tonic-gate MD_CRO_64BIT | MD_CRO_HOTSPARE, setno); 271*0Sstevel@tonic-gate #endif 272*0Sstevel@tonic-gate } else { 273*0Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 274*0Sstevel@tonic-gate MD_CRO_32BIT | MD_CRO_HOTSPARE, setno); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate if (recid < 0) { 278*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE, 279*0Sstevel@tonic-gate shs->shs_hot_spare_pool, 280*0Sstevel@tonic-gate shs->shs_component_old)); 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* get the addr */ 284*0Sstevel@tonic-gate hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, sizeof (*hs), 285*0Sstevel@tonic-gate 0); 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate hs->hs_record_id = recid; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate hs->hs_devnum = shs->shs_component_old; 290*0Sstevel@tonic-gate hs->hs_key = shs->shs_key_old; 291*0Sstevel@tonic-gate hs->hs_start_blk = shs->shs_start_blk; 292*0Sstevel@tonic-gate hs->hs_has_label = shs->shs_has_label; 293*0Sstevel@tonic-gate hs->hs_number_blks = shs->shs_number_blks; 294*0Sstevel@tonic-gate set_hot_spare_state(hs, HSS_AVAILABLE); 295*0Sstevel@tonic-gate hs->hs_refcount = 0; 296*0Sstevel@tonic-gate hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; 297*0Sstevel@tonic-gate md_set[setno].s_hs = (void *) hs; 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* Scan the hot spare pool list */ 301*0Sstevel@tonic-gate hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; 302*0Sstevel@tonic-gate prev_hsp = (hot_spare_pool_t *)0; 303*0Sstevel@tonic-gate while (hsp) { 304*0Sstevel@tonic-gate if (hsp->hsp_self_id == shs->shs_hot_spare_pool) { 305*0Sstevel@tonic-gate break; 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate prev_hsp = hsp; 308*0Sstevel@tonic-gate hsp = hsp->hsp_next; 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate if (hsp == NULL) { 312*0Sstevel@tonic-gate /* create a hot spare pool record */ 313*0Sstevel@tonic-gate recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), 314*0Sstevel@tonic-gate typ1, HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL, setno); 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate if (recid < 0) { 317*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, 318*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate /* get the record addr */ 322*0Sstevel@tonic-gate hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, 323*0Sstevel@tonic-gate sizeof (*hsp), HSP_ONDSK_STR_OFF); 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate hsp->hsp_self_id = shs->shs_hot_spare_pool; 326*0Sstevel@tonic-gate hsp->hsp_record_id = recid; 327*0Sstevel@tonic-gate hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; 328*0Sstevel@tonic-gate hsp->hsp_refcount = 0; 329*0Sstevel@tonic-gate hsp->hsp_nhotspares = 0; 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate /* force prev_hsp to NULL, this will cause hsp to be linked */ 332*0Sstevel@tonic-gate prev_hsp = (hot_spare_pool_t *)0; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 335*0Sstevel@tonic-gate hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 336*0Sstevel@tonic-gate hsp->hsp_link.ln_setno = setno; 337*0Sstevel@tonic-gate hsp->hsp_link.ln_id = hsp->hsp_self_id; 338*0Sstevel@tonic-gate hotspares_md_ops.md_head = &hsp->hsp_link; 339*0Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 340*0Sstevel@tonic-gate hsp_created = 1; 341*0Sstevel@tonic-gate } else { 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* 344*0Sstevel@tonic-gate * Make sure the hot spare is not already in the pool. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) 347*0Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 348*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_INUSE, 349*0Sstevel@tonic-gate shs->shs_hot_spare_pool, 350*0Sstevel@tonic-gate hs->hs_devnum)); 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate /* 353*0Sstevel@tonic-gate * Create a new hot spare pool record 354*0Sstevel@tonic-gate * This gives us the one extra hs slot, 355*0Sstevel@tonic-gate * because there is one slot in the 356*0Sstevel@tonic-gate * hot_spare_pool struct 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate new_size = sizeof (hot_spare_pool_ond_t) + 359*0Sstevel@tonic-gate (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); 360*0Sstevel@tonic-gate recid = mddb_createrec(new_size, typ1, HSP_REC, 361*0Sstevel@tonic-gate MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL, setno); 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate if (recid < 0) { 364*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, 365*0Sstevel@tonic-gate hsp->hsp_self_id)); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate new_size = sizeof (hot_spare_pool_t) + 368*0Sstevel@tonic-gate (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* get the record addr */ 371*0Sstevel@tonic-gate new_hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, 372*0Sstevel@tonic-gate new_size, HSP_ONDSK_STR_OFF); 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* copy the old record into the new one */ 375*0Sstevel@tonic-gate bcopy((caddr_t)hsp, (caddr_t)new_hsp, 376*0Sstevel@tonic-gate (size_t)((sizeof (hot_spare_pool_t) + 377*0Sstevel@tonic-gate (sizeof (mddb_recid_t) * hsp->hsp_nhotspares) 378*0Sstevel@tonic-gate - sizeof (mddb_recid_t)))); 379*0Sstevel@tonic-gate new_hsp->hsp_record_id = recid; 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate md_rem_link(setno, hsp->hsp_self_id, 382*0Sstevel@tonic-gate &hotspares_md_ops.md_link_rw.lock, 383*0Sstevel@tonic-gate &hotspares_md_ops.md_head); 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 386*0Sstevel@tonic-gate new_hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 387*0Sstevel@tonic-gate new_hsp->hsp_link.ln_setno = setno; 388*0Sstevel@tonic-gate new_hsp->hsp_link.ln_id = new_hsp->hsp_self_id; 389*0Sstevel@tonic-gate hotspares_md_ops.md_head = &new_hsp->hsp_link; 390*0Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate /* mark the old hsp to be deleted */ 393*0Sstevel@tonic-gate delete_hsp = 1; 394*0Sstevel@tonic-gate old_hsp = hsp; 395*0Sstevel@tonic-gate hsp = new_hsp; 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 399*0Sstevel@tonic-gate hs->hs_revision = MD_64BIT_META_DEV; 400*0Sstevel@tonic-gate } else { 401*0Sstevel@tonic-gate hs->hs_revision = MD_32BIT_META_DEV; 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate /* lock the db records */ 405*0Sstevel@tonic-gate recids[0] = hs->hs_record_id; 406*0Sstevel@tonic-gate recids[1] = hsp->hsp_record_id; 407*0Sstevel@tonic-gate irecid = 2; 408*0Sstevel@tonic-gate if (delete_hsp) 409*0Sstevel@tonic-gate recids[irecid++] = old_hsp->hsp_record_id; 410*0Sstevel@tonic-gate recids[irecid] = 0; 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate /* increment the reference count */ 413*0Sstevel@tonic-gate hs->hs_refcount++; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* add the hs at the end of the hot spare pool */ 416*0Sstevel@tonic-gate hsp->hsp_hotspares[hsp->hsp_nhotspares] = hs->hs_record_id; 417*0Sstevel@tonic-gate hsp->hsp_nhotspares++; 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare pool record. 421*0Sstevel@tonic-gate * There is no need, the link gets rebuilt at boot time. 422*0Sstevel@tonic-gate */ 423*0Sstevel@tonic-gate if (prev_hsp) 424*0Sstevel@tonic-gate prev_hsp->hsp_next = hsp; 425*0Sstevel@tonic-gate else 426*0Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp; 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate if (delete_hsp) 429*0Sstevel@tonic-gate old_hsp->hsp_self_id = MD_HSP_NONE; 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate /* commit the db records */ 432*0Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate if (delete_hsp) { 435*0Sstevel@tonic-gate /* delete the old hot spare pool record */ 436*0Sstevel@tonic-gate mddb_deleterec_wrapper(old_hsp->hsp_record_id); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate if (hsp_created) { 440*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno, 441*0Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_ADD, SVM_TAG_HSP, setno, 444*0Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate return (0); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate static int 451*0Sstevel@tonic-gate seths_delete_hsp(set_hs_params_t *shs) 452*0Sstevel@tonic-gate { 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate hot_spare_pool_t *prev_hsp; 455*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 456*0Sstevel@tonic-gate set_t setno; 457*0Sstevel@tonic-gate hsp_t hspid; 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* Scan the hot spare pool list */ 462*0Sstevel@tonic-gate prev_hsp = (hot_spare_pool_t *)0; 463*0Sstevel@tonic-gate hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; 464*0Sstevel@tonic-gate while (hsp) { 465*0Sstevel@tonic-gate if (hsp->hsp_self_id == shs->shs_hot_spare_pool) { 466*0Sstevel@tonic-gate break; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate prev_hsp = hsp; 469*0Sstevel@tonic-gate hsp = hsp->hsp_next; 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate if (hsp == NULL) { 473*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_INVAL_HSP, 474*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate if (hsp->hsp_nhotspares != 0) { 478*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_BUSY, 479*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate if (hsp->hsp_refcount != 0) { 483*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_HSP_REF, 484*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 488*0Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 489*0Sstevel@tonic-gate return (0); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate /* 492*0Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare pool record. 493*0Sstevel@tonic-gate * There is no need, the link gets rebuilt at boot time. 494*0Sstevel@tonic-gate */ 495*0Sstevel@tonic-gate if (prev_hsp) 496*0Sstevel@tonic-gate prev_hsp->hsp_next = hsp->hsp_next; 497*0Sstevel@tonic-gate else 498*0Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp->hsp_next; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate hspid = hsp->hsp_self_id; 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate md_rem_link(setno, hsp->hsp_self_id, 503*0Sstevel@tonic-gate &hotspares_md_ops.md_link_rw.lock, 504*0Sstevel@tonic-gate &hotspares_md_ops.md_head); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate mddb_deleterec_wrapper(hsp->hsp_record_id); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_HSP, setno, 509*0Sstevel@tonic-gate md_expldev(hspid)); 510*0Sstevel@tonic-gate return (0); 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate static int 515*0Sstevel@tonic-gate seths_delete(set_hs_params_t *shs) 516*0Sstevel@tonic-gate { 517*0Sstevel@tonic-gate hot_spare_t *hs; 518*0Sstevel@tonic-gate hot_spare_t *prev_hs; 519*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 520*0Sstevel@tonic-gate mddb_recid_t recids[4]; 521*0Sstevel@tonic-gate int i; 522*0Sstevel@tonic-gate set_t setno; 523*0Sstevel@tonic-gate sv_dev_t sv; 524*0Sstevel@tonic-gate int delete_hs = 0; 525*0Sstevel@tonic-gate mdkey_t key_old; 526*0Sstevel@tonic-gate int num_keys_old = 0; 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate /* delete the hot spare pool */ 529*0Sstevel@tonic-gate if (shs->shs_options & HS_OPT_POOL) { 530*0Sstevel@tonic-gate return (seths_delete_hsp(shs)); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* Scan the hot spare list */ 536*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 537*0Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 538*0Sstevel@tonic-gate while (hs) { 539*0Sstevel@tonic-gate if (hs->hs_devnum == shs->shs_component_old) { 540*0Sstevel@tonic-gate break; 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate prev_hs = hs; 543*0Sstevel@tonic-gate hs = hs->hs_next; 544*0Sstevel@tonic-gate } 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if (hs == NULL) { 547*0Sstevel@tonic-gate /* 548*0Sstevel@tonic-gate * Unable to find device using devnum so use 549*0Sstevel@tonic-gate * key associated with shs_component_old instead. 550*0Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 551*0Sstevel@tonic-gate * then fail since namespace has multiple entries 552*0Sstevel@tonic-gate * for this old component and we're unable to determine 553*0Sstevel@tonic-gate * which key is the valid match for shs_component_old. 554*0Sstevel@tonic-gate * 555*0Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 556*0Sstevel@tonic-gate */ 557*0Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 558*0Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 559*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 560*0Sstevel@tonic-gate shs->shs_component_old)); 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate /* 564*0Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 565*0Sstevel@tonic-gate * since shouldn't add new hotspare if namespace has 566*0Sstevel@tonic-gate * multiple entries. 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate if (num_keys_old > 1) { 569*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 570*0Sstevel@tonic-gate shs->shs_component_old)); 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate /* 573*0Sstevel@tonic-gate * If there is no key for this entry then fail since 574*0Sstevel@tonic-gate * a key for this entry should exist. 575*0Sstevel@tonic-gate */ 576*0Sstevel@tonic-gate if (num_keys_old == 0) { 577*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 578*0Sstevel@tonic-gate shs->shs_component_old)); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate /* Scan the hot spare list again */ 581*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 582*0Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 583*0Sstevel@tonic-gate while (hs) { 584*0Sstevel@tonic-gate /* 585*0Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 586*0Sstevel@tonic-gate */ 587*0Sstevel@tonic-gate if ((hs->hs_devnum == NODEV64) && 588*0Sstevel@tonic-gate (hs->hs_key == key_old)) { 589*0Sstevel@tonic-gate break; 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate prev_hs = hs; 592*0Sstevel@tonic-gate hs = hs->hs_next; 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate if (hs == NULL) { 597*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 598*0Sstevel@tonic-gate shs->shs_component_old)); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate /* Scan the hot spare pool list */ 602*0Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); 603*0Sstevel@tonic-gate if (hsp == (hot_spare_pool_t *)0) { 604*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_INVAL_HSP, 605*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate /* check for force flag and state of hot spare */ 609*0Sstevel@tonic-gate if (((shs->shs_options & HS_OPT_FORCE) == 0) && 610*0Sstevel@tonic-gate (hs->hs_state == HSS_RESERVED)) { 611*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_RESVD, 612*0Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_old)); 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate if (hsp->hsp_refcount && (hs->hs_state == HSS_RESERVED)) { 616*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_RESVD, 617*0Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_old)); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * Make sure the device is in the pool. 622*0Sstevel@tonic-gate */ 623*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 624*0Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 625*0Sstevel@tonic-gate break; 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate if (i >= hsp->hsp_nhotspares) { 630*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 631*0Sstevel@tonic-gate hs->hs_devnum)); 632*0Sstevel@tonic-gate } 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 635*0Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 636*0Sstevel@tonic-gate return (0); 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate /* lock the db records */ 640*0Sstevel@tonic-gate recids[0] = hs->hs_record_id; 641*0Sstevel@tonic-gate recids[1] = hsp->hsp_record_id; 642*0Sstevel@tonic-gate recids[2] = 0; 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate sv.setno = setno; 645*0Sstevel@tonic-gate sv.key = hs->hs_key; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate hs->hs_refcount--; 648*0Sstevel@tonic-gate if (hs->hs_refcount == 0) { 649*0Sstevel@tonic-gate /* 650*0Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare record. 651*0Sstevel@tonic-gate * There is no need, the link we get rebuilt at boot time. 652*0Sstevel@tonic-gate */ 653*0Sstevel@tonic-gate if (prev_hs) { 654*0Sstevel@tonic-gate prev_hs->hs_next = hs->hs_next; 655*0Sstevel@tonic-gate } else 656*0Sstevel@tonic-gate md_set[setno].s_hs = (void *) hs->hs_next; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* mark the hot spare to be deleted */ 659*0Sstevel@tonic-gate delete_hs = 1; 660*0Sstevel@tonic-gate recids[0] = hsp->hsp_record_id; 661*0Sstevel@tonic-gate recids[1] = 0; 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate /* find the location of the hs in the hsp */ 665*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 666*0Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) 667*0Sstevel@tonic-gate break; 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate /* remove the hs from the hsp */ 671*0Sstevel@tonic-gate for (i++; i < hsp->hsp_nhotspares; i++) 672*0Sstevel@tonic-gate hsp->hsp_hotspares[i - 1] = hsp->hsp_hotspares[i]; 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate hsp->hsp_nhotspares--; 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate /* commit the db records */ 677*0Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate if (delete_hs) 680*0Sstevel@tonic-gate mddb_deleterec_wrapper(hs->hs_record_id); 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate md_rem_names(&sv, 1); 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REMOVE, SVM_TAG_HSP, setno, 685*0Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate return (0); 688*0Sstevel@tonic-gate } 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate static int 691*0Sstevel@tonic-gate seths_replace(set_hs_params_t *shs) 692*0Sstevel@tonic-gate { 693*0Sstevel@tonic-gate hot_spare_t *hs; 694*0Sstevel@tonic-gate hot_spare_t *prev_hs; 695*0Sstevel@tonic-gate hot_spare_t *new_hs; 696*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 697*0Sstevel@tonic-gate int new_found = 0; 698*0Sstevel@tonic-gate mddb_recid_t recid; 699*0Sstevel@tonic-gate mddb_recid_t recids[5]; 700*0Sstevel@tonic-gate int i; 701*0Sstevel@tonic-gate sv_dev_t sv; 702*0Sstevel@tonic-gate int delete_hs = 0; 703*0Sstevel@tonic-gate set_t setno; 704*0Sstevel@tonic-gate mddb_type_t typ1; 705*0Sstevel@tonic-gate mdkey_t key_old; 706*0Sstevel@tonic-gate int num_keys_old = 0; 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate setno = HSP_SET(shs->shs_hot_spare_pool); 709*0Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 710*0Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate /* Scan the hot spare list */ 713*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 714*0Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 715*0Sstevel@tonic-gate while (hs) { 716*0Sstevel@tonic-gate if (hs->hs_devnum == shs->shs_component_old) { 717*0Sstevel@tonic-gate break; 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate prev_hs = hs; 720*0Sstevel@tonic-gate hs = hs->hs_next; 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate if (hs == NULL) { 724*0Sstevel@tonic-gate /* 725*0Sstevel@tonic-gate * Unable to find device using devnum so use 726*0Sstevel@tonic-gate * key associated with shs_component_old instead. 727*0Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 728*0Sstevel@tonic-gate * then fail since namespace has multiple entries 729*0Sstevel@tonic-gate * for this old component and we're unable to determine 730*0Sstevel@tonic-gate * which key is the valid match for shs_component_old. 731*0Sstevel@tonic-gate * 732*0Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 733*0Sstevel@tonic-gate */ 734*0Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 735*0Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 736*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 737*0Sstevel@tonic-gate shs->shs_component_old)); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate /* 741*0Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 742*0Sstevel@tonic-gate * since unable to determine which key is correct. 743*0Sstevel@tonic-gate */ 744*0Sstevel@tonic-gate if (num_keys_old > 1) { 745*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 746*0Sstevel@tonic-gate shs->shs_component_old)); 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate /* 749*0Sstevel@tonic-gate * If there is no key for this entry then fail since 750*0Sstevel@tonic-gate * a key for this entry should exist. 751*0Sstevel@tonic-gate */ 752*0Sstevel@tonic-gate if (num_keys_old == 0) { 753*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 754*0Sstevel@tonic-gate shs->shs_component_old)); 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate /* Scan the hot spare list again */ 757*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 758*0Sstevel@tonic-gate prev_hs = (hot_spare_t *)0; 759*0Sstevel@tonic-gate while (hs) { 760*0Sstevel@tonic-gate /* 761*0Sstevel@tonic-gate * Only need to compare keys when hs_devnum is NODEV. 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate if ((hs->hs_devnum == NODEV64) && 764*0Sstevel@tonic-gate (hs->hs_key == key_old)) { 765*0Sstevel@tonic-gate break; 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate prev_hs = hs; 768*0Sstevel@tonic-gate hs = hs->hs_next; 769*0Sstevel@tonic-gate } 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate if (hs == NULL) { 773*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 774*0Sstevel@tonic-gate shs->shs_component_old)); 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate /* check the force flag and the state of the hot spare */ 778*0Sstevel@tonic-gate if (((shs->shs_options & HS_OPT_FORCE) == 0) && 779*0Sstevel@tonic-gate (hs->hs_state == HSS_RESERVED)) { 780*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_RESVD, 781*0Sstevel@tonic-gate shs->shs_hot_spare_pool, 782*0Sstevel@tonic-gate hs->hs_devnum)); 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate /* Scan the hot spare pool list */ 786*0Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); 787*0Sstevel@tonic-gate if (hsp == (hot_spare_pool_t *)0) { 788*0Sstevel@tonic-gate return (mdhsperror(&shs->mde, MDE_INVAL_HSP, 789*0Sstevel@tonic-gate shs->shs_hot_spare_pool)); 790*0Sstevel@tonic-gate } 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * Make sure the old device is in the pool. 794*0Sstevel@tonic-gate */ 795*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 796*0Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 797*0Sstevel@tonic-gate break; 798*0Sstevel@tonic-gate } 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate if (i >= hsp->hsp_nhotspares) { 801*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 802*0Sstevel@tonic-gate hs->hs_devnum)); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate /* Scan the hot spare list for the new hs */ 806*0Sstevel@tonic-gate new_hs = (hot_spare_t *)md_set[setno].s_hs; 807*0Sstevel@tonic-gate new_found = 0; 808*0Sstevel@tonic-gate while (new_hs) { 809*0Sstevel@tonic-gate if (new_hs->hs_devnum == shs->shs_component_new) { 810*0Sstevel@tonic-gate new_found = 1; 811*0Sstevel@tonic-gate break; 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate new_hs = new_hs->hs_next; 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate /* 817*0Sstevel@tonic-gate * Make sure the new device is not already in the pool. 818*0Sstevel@tonic-gate * We don't have to search the hs in this hsp, if the 819*0Sstevel@tonic-gate * new hs was just created. Only if the hot spare was found. 820*0Sstevel@tonic-gate */ 821*0Sstevel@tonic-gate if (new_found) { 822*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) 823*0Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == new_hs->hs_record_id) { 824*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_INUSE, 825*0Sstevel@tonic-gate shs->shs_hot_spare_pool, 826*0Sstevel@tonic-gate new_hs->hs_devnum)); 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 831*0Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 832*0Sstevel@tonic-gate return (0); 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate /* 836*0Sstevel@tonic-gate * Create the new hotspare 837*0Sstevel@tonic-gate */ 838*0Sstevel@tonic-gate if (!new_found) { 839*0Sstevel@tonic-gate /* create a hot spare record */ 840*0Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 841*0Sstevel@tonic-gate #if defined(_ILP32) 842*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE, 843*0Sstevel@tonic-gate shs->shs_hot_spare_pool, shs->shs_component_new)); 844*0Sstevel@tonic-gate #else 845*0Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 846*0Sstevel@tonic-gate MD_CRO_64BIT | MD_CRO_HOTSPARE, setno); 847*0Sstevel@tonic-gate #endif 848*0Sstevel@tonic-gate } else { 849*0Sstevel@tonic-gate recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, 850*0Sstevel@tonic-gate MD_CRO_32BIT | MD_CRO_HOTSPARE, setno); 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate if (recid < 0) { 854*0Sstevel@tonic-gate return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE, 855*0Sstevel@tonic-gate shs->shs_hot_spare_pool, 856*0Sstevel@tonic-gate shs->shs_component_new)); 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate /* get the addr */ 860*0Sstevel@tonic-gate new_hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, 861*0Sstevel@tonic-gate sizeof (*new_hs), 0); 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate new_hs->hs_record_id = recid; 864*0Sstevel@tonic-gate new_hs->hs_devnum = shs->shs_component_new; 865*0Sstevel@tonic-gate new_hs->hs_key = shs->shs_key_new; 866*0Sstevel@tonic-gate new_hs->hs_start_blk = shs->shs_start_blk; 867*0Sstevel@tonic-gate new_hs->hs_has_label = shs->shs_has_label; 868*0Sstevel@tonic-gate new_hs->hs_number_blks = shs->shs_number_blks; 869*0Sstevel@tonic-gate set_hot_spare_state(new_hs, HSS_AVAILABLE); 870*0Sstevel@tonic-gate new_hs->hs_refcount = 0; 871*0Sstevel@tonic-gate new_hs->hs_isopen = 1; 872*0Sstevel@tonic-gate } 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate /* lock the db records */ 875*0Sstevel@tonic-gate recids[0] = hs->hs_record_id; 876*0Sstevel@tonic-gate recids[1] = new_hs->hs_record_id; 877*0Sstevel@tonic-gate recids[2] = hsp->hsp_record_id; 878*0Sstevel@tonic-gate recids[3] = 0; 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate sv.setno = setno; 881*0Sstevel@tonic-gate sv.key = hs->hs_key; 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate hs->hs_refcount--; 884*0Sstevel@tonic-gate if (hs->hs_refcount == 0) { 885*0Sstevel@tonic-gate /* 886*0Sstevel@tonic-gate * NOTE: We do not commit the previous hot spare record. 887*0Sstevel@tonic-gate * There is no need, the link we get rebuilt at boot time. 888*0Sstevel@tonic-gate */ 889*0Sstevel@tonic-gate if (prev_hs) { 890*0Sstevel@tonic-gate prev_hs->hs_next = hs->hs_next; 891*0Sstevel@tonic-gate } else 892*0Sstevel@tonic-gate md_set[setno].s_hs = (void *) hs->hs_next; 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate /* mark hs to be deleted in the correct order */ 895*0Sstevel@tonic-gate delete_hs = 1; 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate recids[0] = new_hs->hs_record_id; 898*0Sstevel@tonic-gate recids[1] = hsp->hsp_record_id; 899*0Sstevel@tonic-gate recids[2] = 0; 900*0Sstevel@tonic-gate } 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate /* link into the hs list */ 903*0Sstevel@tonic-gate new_hs->hs_refcount++; 904*0Sstevel@tonic-gate if (!new_found) { 905*0Sstevel@tonic-gate /* do this AFTER the old dev is possibly removed */ 906*0Sstevel@tonic-gate new_hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; 907*0Sstevel@tonic-gate md_set[setno].s_hs = (void *) new_hs; 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate /* find the location of the old hs in the hsp */ 911*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 912*0Sstevel@tonic-gate if (hsp->hsp_hotspares[i] == hs->hs_record_id) { 913*0Sstevel@tonic-gate hsp->hsp_hotspares[i] = new_hs->hs_record_id; 914*0Sstevel@tonic-gate break; 915*0Sstevel@tonic-gate } 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate if (shs->shs_size_option & MD_CRO_64BIT) { 919*0Sstevel@tonic-gate new_hs->hs_revision = MD_64BIT_META_DEV; 920*0Sstevel@tonic-gate } else { 921*0Sstevel@tonic-gate new_hs->hs_revision = MD_32BIT_META_DEV; 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate /* commit the db records */ 925*0Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate if (delete_hs) 928*0Sstevel@tonic-gate mddb_deleterec_wrapper(hs->hs_record_id); 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate md_rem_names(&sv, 1); 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REPLACE, SVM_TAG_HSP, setno, 933*0Sstevel@tonic-gate md_expldev(hsp->hsp_self_id)); 934*0Sstevel@tonic-gate return (0); 935*0Sstevel@tonic-gate } 936*0Sstevel@tonic-gate 937*0Sstevel@tonic-gate static int 938*0Sstevel@tonic-gate seths_enable(set_hs_params_t *shs) 939*0Sstevel@tonic-gate { 940*0Sstevel@tonic-gate hot_spare_t *hs; 941*0Sstevel@tonic-gate mddb_recid_t recids[2]; 942*0Sstevel@tonic-gate set_t setno = shs->md_driver.md_setno; 943*0Sstevel@tonic-gate mdkey_t key_old; 944*0Sstevel@tonic-gate int num_keys_old = 0; 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate /* 948*0Sstevel@tonic-gate * Find device by using key associated with shs_component_old. 949*0Sstevel@tonic-gate * If unable to find a unique key for shs_component_old 950*0Sstevel@tonic-gate * then fail since namespace has multiple entries 951*0Sstevel@tonic-gate * for this old component and we're unable to determine 952*0Sstevel@tonic-gate * which key is the valid match for shs_component_old. 953*0Sstevel@tonic-gate * This failure keeps a hotspare from being enabled on a slice 954*0Sstevel@tonic-gate * that may already be in use by another metadevice. 955*0Sstevel@tonic-gate */ 956*0Sstevel@tonic-gate if (md_getkeyfromdev(setno, mddb_getsidenum(setno), 957*0Sstevel@tonic-gate shs->shs_component_old, &key_old, &num_keys_old) != 0) { 958*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_NAME_SPACE, 959*0Sstevel@tonic-gate shs->shs_component_old)); 960*0Sstevel@tonic-gate } 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate /* 963*0Sstevel@tonic-gate * If more than one key matches given old_dev - fail command 964*0Sstevel@tonic-gate * since unable to determine which key is correct. 965*0Sstevel@tonic-gate */ 966*0Sstevel@tonic-gate if (num_keys_old > 1) { 967*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_MULTNM, 968*0Sstevel@tonic-gate shs->shs_component_old)); 969*0Sstevel@tonic-gate } 970*0Sstevel@tonic-gate /* 971*0Sstevel@tonic-gate * If there is no key for this entry then fail since 972*0Sstevel@tonic-gate * a key for this entry should exist. 973*0Sstevel@tonic-gate */ 974*0Sstevel@tonic-gate if (num_keys_old == 0) { 975*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 976*0Sstevel@tonic-gate shs->shs_component_old)); 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate /* Scan the hot spare list for the hs */ 980*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 981*0Sstevel@tonic-gate while (hs) { 982*0Sstevel@tonic-gate /* 983*0Sstevel@tonic-gate * Since component may or may not be currently in the system, 984*0Sstevel@tonic-gate * use the keys to find a match (not the devt). 985*0Sstevel@tonic-gate */ 986*0Sstevel@tonic-gate if (hs->hs_key == key_old) { 987*0Sstevel@tonic-gate break; 988*0Sstevel@tonic-gate } 989*0Sstevel@tonic-gate hs = hs->hs_next; 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate if (hs == NULL) { 993*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_INVAL_HS, 994*0Sstevel@tonic-gate shs->shs_component_old)); 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate /* make sure it's broken */ 998*0Sstevel@tonic-gate if (hs->hs_state != HSS_BROKEN) { 999*0Sstevel@tonic-gate return (mddeverror(&shs->mde, MDE_FIX_INVAL_HS_STATE, 1000*0Sstevel@tonic-gate hs->hs_devnum)); 1001*0Sstevel@tonic-gate } 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate /* In case of a dryrun, we're done here */ 1004*0Sstevel@tonic-gate if (shs->shs_options & HS_OPT_DRYRUN) { 1005*0Sstevel@tonic-gate return (0); 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate /* fix it */ 1009*0Sstevel@tonic-gate set_hot_spare_state(hs, HSS_AVAILABLE); 1010*0Sstevel@tonic-gate hs->hs_start_blk = shs->shs_start_blk; 1011*0Sstevel@tonic-gate hs->hs_has_label = shs->shs_has_label; 1012*0Sstevel@tonic-gate hs->hs_number_blks = shs->shs_number_blks; 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate /* commit the db records */ 1015*0Sstevel@tonic-gate recids[0] = hs->hs_record_id; 1016*0Sstevel@tonic-gate recids[1] = 0; 1017*0Sstevel@tonic-gate mddb_commitrecs_wrapper(recids); 1018*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ENABLE, SVM_TAG_HS, setno, 1019*0Sstevel@tonic-gate shs->shs_component_old); 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate return (0); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate static int 1025*0Sstevel@tonic-gate get_hs( 1026*0Sstevel@tonic-gate get_hs_params_t *ghs 1027*0Sstevel@tonic-gate ) 1028*0Sstevel@tonic-gate { 1029*0Sstevel@tonic-gate hot_spare_t *hs; 1030*0Sstevel@tonic-gate set_t setno = ghs->md_driver.md_setno; 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate mdclrerror(&ghs->mde); 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate /* Scan the hot spare list for the hs */ 1035*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 1036*0Sstevel@tonic-gate while (hs) { 1037*0Sstevel@tonic-gate if (hs->hs_key == ghs->ghs_key) { 1038*0Sstevel@tonic-gate break; 1039*0Sstevel@tonic-gate } 1040*0Sstevel@tonic-gate hs = hs->hs_next; 1041*0Sstevel@tonic-gate } 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate if (hs == NULL) { 1044*0Sstevel@tonic-gate return (mddeverror(&ghs->mde, MDE_INVAL_HS, 1045*0Sstevel@tonic-gate ghs->ghs_devnum)); 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate 1048*0Sstevel@tonic-gate ghs->ghs_start_blk = hs->hs_start_blk; 1049*0Sstevel@tonic-gate ghs->ghs_number_blks = hs->hs_number_blks; 1050*0Sstevel@tonic-gate ghs->ghs_state = hs->hs_state; 1051*0Sstevel@tonic-gate ghs->ghs_timestamp = hs->hs_timestamp; 1052*0Sstevel@tonic-gate ghs->ghs_revision = hs->hs_revision; 1053*0Sstevel@tonic-gate return (0); 1054*0Sstevel@tonic-gate } 1055*0Sstevel@tonic-gate 1056*0Sstevel@tonic-gate static void 1057*0Sstevel@tonic-gate build_key_list(set_t setno, hot_spare_pool_t *hsp, mdkey_t *list) 1058*0Sstevel@tonic-gate { 1059*0Sstevel@tonic-gate int i; 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 1062*0Sstevel@tonic-gate hot_spare_t *hs; 1063*0Sstevel@tonic-gate hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1); 1064*0Sstevel@tonic-gate list[i] = hs->hs_key; 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate 1068*0Sstevel@tonic-gate static int 1069*0Sstevel@tonic-gate get_hsp( 1070*0Sstevel@tonic-gate void *d, 1071*0Sstevel@tonic-gate int mode 1072*0Sstevel@tonic-gate ) 1073*0Sstevel@tonic-gate { 1074*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 1075*0Sstevel@tonic-gate get_hsp_t *ghsp; 1076*0Sstevel@tonic-gate size_t size; 1077*0Sstevel@tonic-gate set_t setno; 1078*0Sstevel@tonic-gate int err = 0; 1079*0Sstevel@tonic-gate md_i_get_t *migp = (md_i_get_t *)d; 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate 1082*0Sstevel@tonic-gate setno = migp->md_driver.md_setno; 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate mdclrerror(&migp->mde); 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate /* Scan the hot spare pool list */ 1087*0Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, migp->id); 1088*0Sstevel@tonic-gate if (hsp == NULL) { 1089*0Sstevel@tonic-gate return (mdhsperror(&migp->mde, MDE_INVAL_HSP, 1090*0Sstevel@tonic-gate migp->id)); 1091*0Sstevel@tonic-gate } 1092*0Sstevel@tonic-gate 1093*0Sstevel@tonic-gate size = (sizeof (ghsp->ghsp_hs_keys[0]) * (hsp->hsp_nhotspares - 1)) + 1094*0Sstevel@tonic-gate sizeof (get_hsp_t); 1095*0Sstevel@tonic-gate 1096*0Sstevel@tonic-gate if (migp->size == 0) { 1097*0Sstevel@tonic-gate migp->size = (int)size; 1098*0Sstevel@tonic-gate return (0); 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate if (migp->size < size) 1102*0Sstevel@tonic-gate return (EFAULT); 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate ghsp = kmem_alloc(size, KM_SLEEP); 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate ghsp->ghsp_id = hsp->hsp_self_id; 1107*0Sstevel@tonic-gate ghsp->ghsp_refcount = hsp->hsp_refcount; 1108*0Sstevel@tonic-gate ghsp->ghsp_nhotspares = hsp->hsp_nhotspares; 1109*0Sstevel@tonic-gate build_key_list(setno, hsp, ghsp->ghsp_hs_keys); 1110*0Sstevel@tonic-gate if (ddi_copyout(ghsp, (caddr_t)(uintptr_t)migp->mdp, size, mode)) 1111*0Sstevel@tonic-gate err = EFAULT; 1112*0Sstevel@tonic-gate kmem_free(ghsp, size); 1113*0Sstevel@tonic-gate return (err); 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate static int 1117*0Sstevel@tonic-gate set_hs( 1118*0Sstevel@tonic-gate set_hs_params_t *shs 1119*0Sstevel@tonic-gate ) 1120*0Sstevel@tonic-gate { 1121*0Sstevel@tonic-gate mdclrerror(&shs->mde); 1122*0Sstevel@tonic-gate 1123*0Sstevel@tonic-gate if (md_get_setstatus(shs->md_driver.md_setno) & MD_SET_STALE) 1124*0Sstevel@tonic-gate return (mdmddberror(&shs->mde, MDE_DB_STALE, NODEV32, 1125*0Sstevel@tonic-gate shs->md_driver.md_setno)); 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate switch (shs->shs_cmd) { 1128*0Sstevel@tonic-gate case ADD_HOT_SPARE: 1129*0Sstevel@tonic-gate return (seths_add(shs)); 1130*0Sstevel@tonic-gate case DELETE_HOT_SPARE: 1131*0Sstevel@tonic-gate return (seths_delete(shs)); 1132*0Sstevel@tonic-gate case REPLACE_HOT_SPARE: 1133*0Sstevel@tonic-gate return (seths_replace(shs)); 1134*0Sstevel@tonic-gate case FIX_HOT_SPARE: 1135*0Sstevel@tonic-gate return (seths_enable(shs)); 1136*0Sstevel@tonic-gate default: 1137*0Sstevel@tonic-gate return (mderror(&shs->mde, MDE_INVAL_HSOP)); 1138*0Sstevel@tonic-gate } 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate static void 1142*0Sstevel@tonic-gate hotspares_poke_hotspares(void) 1143*0Sstevel@tonic-gate { 1144*0Sstevel@tonic-gate intptr_t (*poke_hs)(); 1145*0Sstevel@tonic-gate int i; 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate for (i = 0; i < MD_NOPS; i++) { 1148*0Sstevel@tonic-gate /* handle change */ 1149*0Sstevel@tonic-gate poke_hs = md_get_named_service(NODEV64, i, "poke hotspares", 0); 1150*0Sstevel@tonic-gate if (poke_hs) 1151*0Sstevel@tonic-gate (void) (*poke_hs)(); 1152*0Sstevel@tonic-gate } 1153*0Sstevel@tonic-gate } 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate 1156*0Sstevel@tonic-gate /*ARGSUSED4*/ 1157*0Sstevel@tonic-gate static int 1158*0Sstevel@tonic-gate hotspares_ioctl( 1159*0Sstevel@tonic-gate dev_t dev, 1160*0Sstevel@tonic-gate int cmd, 1161*0Sstevel@tonic-gate void *data, 1162*0Sstevel@tonic-gate int mode, 1163*0Sstevel@tonic-gate IOLOCK *lockp 1164*0Sstevel@tonic-gate ) 1165*0Sstevel@tonic-gate { 1166*0Sstevel@tonic-gate size_t sz = 0; 1167*0Sstevel@tonic-gate void *d = NULL; 1168*0Sstevel@tonic-gate int err = 0; 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate /* single thread */ 1171*0Sstevel@tonic-gate if (getminor(dev) != MD_ADM_MINOR) 1172*0Sstevel@tonic-gate return (ENOTTY); 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate /* We can only handle 32-bit clients for internal commands */ 1175*0Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32) { 1176*0Sstevel@tonic-gate return (EINVAL); 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate mutex_enter(&md_mx); 1180*0Sstevel@tonic-gate while (md_status & MD_GBL_HS_LOCK) 1181*0Sstevel@tonic-gate cv_wait(&md_cv, &md_mx); 1182*0Sstevel@tonic-gate md_status |= MD_GBL_HS_LOCK; 1183*0Sstevel@tonic-gate mutex_exit(&md_mx); 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate /* dispatch ioctl */ 1186*0Sstevel@tonic-gate switch (cmd) { 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate case MD_IOCSET_HS: /* setup hot spares and pools */ 1189*0Sstevel@tonic-gate { 1190*0Sstevel@tonic-gate if (! (mode & FWRITE)) { 1191*0Sstevel@tonic-gate err = EACCES; 1192*0Sstevel@tonic-gate break; 1193*0Sstevel@tonic-gate } 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate sz = sizeof (set_hs_params_t); 1196*0Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP); 1197*0Sstevel@tonic-gate 1198*0Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) { 1199*0Sstevel@tonic-gate err = EFAULT; 1200*0Sstevel@tonic-gate break; 1201*0Sstevel@tonic-gate } 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate err = set_hs(d); 1204*0Sstevel@tonic-gate break; 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate case MD_IOCGET_HS: /* get hot spare info */ 1208*0Sstevel@tonic-gate { 1209*0Sstevel@tonic-gate if (! (mode & FREAD)) { 1210*0Sstevel@tonic-gate err = EACCES; 1211*0Sstevel@tonic-gate break; 1212*0Sstevel@tonic-gate } 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate sz = sizeof (get_hs_params_t); 1215*0Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP); 1216*0Sstevel@tonic-gate 1217*0Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) { 1218*0Sstevel@tonic-gate err = EFAULT; 1219*0Sstevel@tonic-gate break; 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate err = get_hs(d); 1223*0Sstevel@tonic-gate break; 1224*0Sstevel@tonic-gate } 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate case MD_IOCGET: /* get hot spare pool info */ 1227*0Sstevel@tonic-gate { 1228*0Sstevel@tonic-gate if (! (mode & FREAD)) { 1229*0Sstevel@tonic-gate err = EACCES; 1230*0Sstevel@tonic-gate break; 1231*0Sstevel@tonic-gate } 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate sz = sizeof (md_i_get_t); 1234*0Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP); 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) { 1237*0Sstevel@tonic-gate err = EFAULT; 1238*0Sstevel@tonic-gate break; 1239*0Sstevel@tonic-gate } 1240*0Sstevel@tonic-gate 1241*0Sstevel@tonic-gate err = get_hsp(d, mode); 1242*0Sstevel@tonic-gate break; 1243*0Sstevel@tonic-gate } 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate default: 1246*0Sstevel@tonic-gate err = ENOTTY; 1247*0Sstevel@tonic-gate } 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate /* 1250*0Sstevel@tonic-gate * copyout and free any args 1251*0Sstevel@tonic-gate */ 1252*0Sstevel@tonic-gate if (sz != 0) { 1253*0Sstevel@tonic-gate if (err == 0) { 1254*0Sstevel@tonic-gate if (ddi_copyout(d, data, sz, mode) != 0) { 1255*0Sstevel@tonic-gate err = EFAULT; 1256*0Sstevel@tonic-gate } 1257*0Sstevel@tonic-gate } 1258*0Sstevel@tonic-gate kmem_free(d, sz); 1259*0Sstevel@tonic-gate } 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate /* un single thread */ 1262*0Sstevel@tonic-gate mutex_enter(&md_mx); 1263*0Sstevel@tonic-gate md_status &= ~MD_GBL_HS_LOCK; 1264*0Sstevel@tonic-gate cv_broadcast(&md_cv); 1265*0Sstevel@tonic-gate mutex_exit(&md_mx); 1266*0Sstevel@tonic-gate 1267*0Sstevel@tonic-gate /* handle change */ 1268*0Sstevel@tonic-gate hotspares_poke_hotspares(); 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate /* return success */ 1271*0Sstevel@tonic-gate return (err); 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate static void 1276*0Sstevel@tonic-gate load_hotspare(set_t setno, mddb_recid_t recid) 1277*0Sstevel@tonic-gate { 1278*0Sstevel@tonic-gate hot_spare_t *hs; 1279*0Sstevel@tonic-gate mddb_de_ic_t *dep; 1280*0Sstevel@tonic-gate mddb_rb32_t *rbp; 1281*0Sstevel@tonic-gate size_t newreqsize; 1282*0Sstevel@tonic-gate hot_spare_t *b_hs; 1283*0Sstevel@tonic-gate hot_spare32_od_t *s_hs; 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate dep = mddb_getrecdep(recid); 1288*0Sstevel@tonic-gate dep->de_flags = MDDB_F_HOTSPARE; 1289*0Sstevel@tonic-gate rbp = dep->de_rb; 1290*0Sstevel@tonic-gate if (rbp->rb_revision == MDDB_REV_RB) { 1291*0Sstevel@tonic-gate /* 1292*0Sstevel@tonic-gate * Needs to convert to internal 64 bit 1293*0Sstevel@tonic-gate */ 1294*0Sstevel@tonic-gate s_hs = (hot_spare32_od_t *)mddb_getrecaddr(recid); 1295*0Sstevel@tonic-gate newreqsize = sizeof (hot_spare_t); 1296*0Sstevel@tonic-gate b_hs = (hot_spare_t *)kmem_zalloc(newreqsize, KM_SLEEP); 1297*0Sstevel@tonic-gate hs_convert((caddr_t)s_hs, (caddr_t)b_hs, SMALL_2_BIG); 1298*0Sstevel@tonic-gate kmem_free(s_hs, dep->de_reqsize); 1299*0Sstevel@tonic-gate dep->de_rb_userdata = b_hs; 1300*0Sstevel@tonic-gate dep->de_reqsize = newreqsize; 1301*0Sstevel@tonic-gate hs = b_hs; 1302*0Sstevel@tonic-gate } else { 1303*0Sstevel@tonic-gate hs = (hot_spare_t *)mddb_getrecaddr_resize 1304*0Sstevel@tonic-gate (recid, sizeof (*hs), 0); 1305*0Sstevel@tonic-gate } 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate #if defined(_ILP32) 1309*0Sstevel@tonic-gate if (hs->hs_revision == MD_64BIT_META_DEV) { 1310*0Sstevel@tonic-gate char devname[MD_MAX_CTDLEN]; 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate set_hot_spare_state(hs, HSS_BROKEN); 1313*0Sstevel@tonic-gate (void) md_devname(setno, hs->hs_devnum, devname, 1314*0Sstevel@tonic-gate sizeof (devname)); 1315*0Sstevel@tonic-gate cmn_err(CE_NOTE, "%s is unavailable because 64 bit hotspares " 1316*0Sstevel@tonic-gate "are not accessible on a 32 bit kernel\n", devname); 1317*0Sstevel@tonic-gate } 1318*0Sstevel@tonic-gate #endif 1319*0Sstevel@tonic-gate 1320*0Sstevel@tonic-gate ASSERT(hs != NULL); 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gate if (hs->hs_refcount == 0) { 1323*0Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_PENDDEL); 1324*0Sstevel@tonic-gate return; 1325*0Sstevel@tonic-gate } 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; 1328*0Sstevel@tonic-gate md_set[setno].s_hs = (void *)hs; 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate hs->hs_isopen = 0; 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate hs->hs_devnum = md_getdevnum(setno, mddb_getsidenum(setno), 1333*0Sstevel@tonic-gate hs->hs_key, MD_NOTRUST_DEVT); 1334*0Sstevel@tonic-gate } 1335*0Sstevel@tonic-gate 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate static void 1338*0Sstevel@tonic-gate load_hotsparepool(set_t setno, mddb_recid_t recid) 1339*0Sstevel@tonic-gate { 1340*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 1341*0Sstevel@tonic-gate hot_spare_pool_ond_t *hsp_ond; 1342*0Sstevel@tonic-gate size_t hsp_icsize; 1343*0Sstevel@tonic-gate 1344*0Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 1345*0Sstevel@tonic-gate 1346*0Sstevel@tonic-gate hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid); 1347*0Sstevel@tonic-gate ASSERT(hsp_ond != NULL); 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate if (hsp_ond->hsp_self_id == MD_HSP_NONE) { 1350*0Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_PENDDEL); 1351*0Sstevel@tonic-gate return; 1352*0Sstevel@tonic-gate } 1353*0Sstevel@tonic-gate 1354*0Sstevel@tonic-gate hsp_icsize = HSP_ONDSK_STR_OFF + mddb_getrecsize(recid); 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, hsp_icsize, 1357*0Sstevel@tonic-gate HSP_ONDSK_STR_OFF); 1358*0Sstevel@tonic-gate hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; 1359*0Sstevel@tonic-gate md_set[setno].s_hsp = (void *) hsp; 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); 1362*0Sstevel@tonic-gate hsp->hsp_link.ln_next = hotspares_md_ops.md_head; 1363*0Sstevel@tonic-gate hsp->hsp_link.ln_setno = setno; 1364*0Sstevel@tonic-gate hsp->hsp_link.ln_id = hsp->hsp_self_id; 1365*0Sstevel@tonic-gate hotspares_md_ops.md_head = &hsp->hsp_link; 1366*0Sstevel@tonic-gate rw_exit(&hotspares_md_ops.md_link_rw.lock); 1367*0Sstevel@tonic-gate } 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate static int 1370*0Sstevel@tonic-gate hotspares_snarf(md_snarfcmd_t cmd, set_t setno) 1371*0Sstevel@tonic-gate { 1372*0Sstevel@tonic-gate mddb_recid_t recid; 1373*0Sstevel@tonic-gate int gotsomething; 1374*0Sstevel@tonic-gate mddb_type_t typ1; 1375*0Sstevel@tonic-gate 1376*0Sstevel@tonic-gate if (cmd == MD_SNARF_CLEANUP) 1377*0Sstevel@tonic-gate return (0); 1378*0Sstevel@tonic-gate 1379*0Sstevel@tonic-gate gotsomething = 0; 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 1382*0Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 1383*0Sstevel@tonic-gate recid = mddb_makerecid(setno, 0); 1384*0Sstevel@tonic-gate while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) { 1385*0Sstevel@tonic-gate if (mddb_getrecprivate(recid) & MD_PRV_GOTIT) 1386*0Sstevel@tonic-gate continue; 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate switch (mddb_getrectype2(recid)) { 1389*0Sstevel@tonic-gate case HSP_REC: 1390*0Sstevel@tonic-gate load_hotsparepool(setno, recid); 1391*0Sstevel@tonic-gate gotsomething = 1; 1392*0Sstevel@tonic-gate break; 1393*0Sstevel@tonic-gate case HS_REC: 1394*0Sstevel@tonic-gate load_hotspare(setno, recid); 1395*0Sstevel@tonic-gate gotsomething = 1; 1396*0Sstevel@tonic-gate break; 1397*0Sstevel@tonic-gate default: 1398*0Sstevel@tonic-gate ASSERT(0); 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate } 1401*0Sstevel@tonic-gate 1402*0Sstevel@tonic-gate if (gotsomething) 1403*0Sstevel@tonic-gate return (gotsomething); 1404*0Sstevel@tonic-gate 1405*0Sstevel@tonic-gate recid = mddb_makerecid(setno, 0); 1406*0Sstevel@tonic-gate while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) 1407*0Sstevel@tonic-gate if (!(mddb_getrecprivate(recid) & MD_PRV_GOTIT)) 1408*0Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_PENDDEL); 1409*0Sstevel@tonic-gate 1410*0Sstevel@tonic-gate return (0); 1411*0Sstevel@tonic-gate } 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate static int 1414*0Sstevel@tonic-gate hotspares_halt(md_haltcmd_t cmd, set_t setno) 1415*0Sstevel@tonic-gate { 1416*0Sstevel@tonic-gate hot_spare_t *hs, **p_hs; 1417*0Sstevel@tonic-gate hot_spare_pool_t *hsp, **p_hsp; 1418*0Sstevel@tonic-gate 1419*0Sstevel@tonic-gate if (cmd == MD_HALT_CLOSE) 1420*0Sstevel@tonic-gate return (0); 1421*0Sstevel@tonic-gate 1422*0Sstevel@tonic-gate if (cmd == MD_HALT_OPEN) 1423*0Sstevel@tonic-gate return (0); 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate if (cmd == MD_HALT_CHECK) 1426*0Sstevel@tonic-gate return (0); 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate if (cmd == MD_HALT_UNLOAD) 1429*0Sstevel@tonic-gate return (0); 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate if (cmd != MD_HALT_DOIT) 1432*0Sstevel@tonic-gate return (1); 1433*0Sstevel@tonic-gate /* 1434*0Sstevel@tonic-gate * Find all the hotspares for set "setno" 1435*0Sstevel@tonic-gate * and remove them from the hot_spare_list. 1436*0Sstevel@tonic-gate */ 1437*0Sstevel@tonic-gate p_hs = (hot_spare_t **)&md_set[setno].s_hs; 1438*0Sstevel@tonic-gate hs = (hot_spare_t *)md_set[setno].s_hs; 1439*0Sstevel@tonic-gate for (; hs != NULL; hs = *p_hs) 1440*0Sstevel@tonic-gate *p_hs = hs->hs_next; 1441*0Sstevel@tonic-gate 1442*0Sstevel@tonic-gate /* 1443*0Sstevel@tonic-gate * Find all the hotspare pools for set "setno" 1444*0Sstevel@tonic-gate * and remove them from the hot_spare_pools list. 1445*0Sstevel@tonic-gate * Also remove from the get_next list. 1446*0Sstevel@tonic-gate */ 1447*0Sstevel@tonic-gate p_hsp = (hot_spare_pool_t **)&md_set[setno].s_hsp; 1448*0Sstevel@tonic-gate hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; 1449*0Sstevel@tonic-gate for (; hsp != NULL; hsp = *p_hsp) { 1450*0Sstevel@tonic-gate md_rem_link(setno, hsp->hsp_self_id, 1451*0Sstevel@tonic-gate &hotspares_md_ops.md_link_rw.lock, 1452*0Sstevel@tonic-gate &hotspares_md_ops.md_head); 1453*0Sstevel@tonic-gate *p_hsp = hsp->hsp_next; 1454*0Sstevel@tonic-gate } 1455*0Sstevel@tonic-gate 1456*0Sstevel@tonic-gate return (0); 1457*0Sstevel@tonic-gate } 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate static hot_spare_t * 1460*0Sstevel@tonic-gate usable_hs( 1461*0Sstevel@tonic-gate set_t setno, 1462*0Sstevel@tonic-gate mddb_recid_t hs_id, 1463*0Sstevel@tonic-gate diskaddr_t nblks, 1464*0Sstevel@tonic-gate int labeled, 1465*0Sstevel@tonic-gate diskaddr_t *start) 1466*0Sstevel@tonic-gate { 1467*0Sstevel@tonic-gate hot_spare_t *hs; 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate hs = lookup_hot_spare(setno, hs_id, 1); 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate if (hs->hs_state != HSS_AVAILABLE) 1472*0Sstevel@tonic-gate return ((hot_spare_t *)0); 1473*0Sstevel@tonic-gate 1474*0Sstevel@tonic-gate if (labeled && hs->hs_has_label && (hs->hs_number_blks >= nblks)) { 1475*0Sstevel@tonic-gate *start = 0; 1476*0Sstevel@tonic-gate return (hs); 1477*0Sstevel@tonic-gate } else if ((hs->hs_number_blks - hs->hs_start_blk) >= nblks) { 1478*0Sstevel@tonic-gate *start = hs->hs_start_blk; 1479*0Sstevel@tonic-gate return (hs); 1480*0Sstevel@tonic-gate } 1481*0Sstevel@tonic-gate return ((hot_spare_t *)0); 1482*0Sstevel@tonic-gate } 1483*0Sstevel@tonic-gate 1484*0Sstevel@tonic-gate static int 1485*0Sstevel@tonic-gate reserve_a_hs( 1486*0Sstevel@tonic-gate set_t setno, 1487*0Sstevel@tonic-gate mddb_recid_t id, 1488*0Sstevel@tonic-gate uint64_t size, 1489*0Sstevel@tonic-gate int labeled, 1490*0Sstevel@tonic-gate mddb_recid_t *hs_id, 1491*0Sstevel@tonic-gate mdkey_t *key, 1492*0Sstevel@tonic-gate md_dev64_t *dev, 1493*0Sstevel@tonic-gate diskaddr_t *sblock) 1494*0Sstevel@tonic-gate { 1495*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 1496*0Sstevel@tonic-gate hot_spare_t *hs; 1497*0Sstevel@tonic-gate int i; 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate *hs_id = 0; 1500*0Sstevel@tonic-gate 1501*0Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, id); 1502*0Sstevel@tonic-gate if (hsp == NULL) 1503*0Sstevel@tonic-gate return (-1); 1504*0Sstevel@tonic-gate 1505*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 1506*0Sstevel@tonic-gate hs = usable_hs(setno, hsp->hsp_hotspares[i], 1507*0Sstevel@tonic-gate size, labeled, sblock); 1508*0Sstevel@tonic-gate if (hs == NULL) 1509*0Sstevel@tonic-gate continue; 1510*0Sstevel@tonic-gate 1511*0Sstevel@tonic-gate set_hot_spare_state(hs, HSS_RESERVED); 1512*0Sstevel@tonic-gate *hs_id = hs->hs_record_id; 1513*0Sstevel@tonic-gate *key = hs->hs_key; 1514*0Sstevel@tonic-gate *dev = hs->hs_devnum; 1515*0Sstevel@tonic-gate /* NOTE: Mirror code commits the hs record */ 1516*0Sstevel@tonic-gate return (0); 1517*0Sstevel@tonic-gate } 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate return (-1); 1520*0Sstevel@tonic-gate } 1521*0Sstevel@tonic-gate 1522*0Sstevel@tonic-gate 1523*0Sstevel@tonic-gate /* ARGSUSED3 */ 1524*0Sstevel@tonic-gate static int 1525*0Sstevel@tonic-gate return_a_hs( 1526*0Sstevel@tonic-gate set_t setno, 1527*0Sstevel@tonic-gate mddb_recid_t id, 1528*0Sstevel@tonic-gate mddb_recid_t *hs_id, 1529*0Sstevel@tonic-gate mdkey_t key, 1530*0Sstevel@tonic-gate diskaddr_t sblock, 1531*0Sstevel@tonic-gate uint64_t size, 1532*0Sstevel@tonic-gate hotspare_states_t new_state) 1533*0Sstevel@tonic-gate { 1534*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 1535*0Sstevel@tonic-gate hot_spare_t *hs; 1536*0Sstevel@tonic-gate int i; 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate /* 1539*0Sstevel@tonic-gate * NOTE: sblock/size are not currently being used. 1540*0Sstevel@tonic-gate * That is because we always allocate the whole hs. 1541*0Sstevel@tonic-gate * Later if we choose to allocate only what is needed 1542*0Sstevel@tonic-gate * then the sblock/size can be used to determine 1543*0Sstevel@tonic-gate * which part is being unreseved. 1544*0Sstevel@tonic-gate */ 1545*0Sstevel@tonic-gate *hs_id = 0; 1546*0Sstevel@tonic-gate 1547*0Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, id); 1548*0Sstevel@tonic-gate if (hsp == NULL) 1549*0Sstevel@tonic-gate return (-1); 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate for (i = 0; i < hsp->hsp_nhotspares; i++) { 1552*0Sstevel@tonic-gate hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1); 1553*0Sstevel@tonic-gate if (hs->hs_key != key) 1554*0Sstevel@tonic-gate continue; 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate set_hot_spare_state(hs, new_state); 1557*0Sstevel@tonic-gate *hs_id = hs->hs_record_id; 1558*0Sstevel@tonic-gate if (new_state == HSS_BROKEN) { 1559*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ERRED, SVM_TAG_HS, 1560*0Sstevel@tonic-gate setno, hs->hs_devnum); 1561*0Sstevel@tonic-gate } 1562*0Sstevel@tonic-gate if (new_state == HSS_AVAILABLE) { 1563*0Sstevel@tonic-gate SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_HS, 1564*0Sstevel@tonic-gate setno, hs->hs_devnum); 1565*0Sstevel@tonic-gate } 1566*0Sstevel@tonic-gate 1567*0Sstevel@tonic-gate /* NOTE: Mirror/Raid code commits the hs record */ 1568*0Sstevel@tonic-gate return (0); 1569*0Sstevel@tonic-gate } 1570*0Sstevel@tonic-gate 1571*0Sstevel@tonic-gate return (-1); 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate 1574*0Sstevel@tonic-gate 1575*0Sstevel@tonic-gate static int 1576*0Sstevel@tonic-gate modify_hsp_ref(set_t setno, mddb_recid_t id, int incref, mddb_recid_t *hsp_id) 1577*0Sstevel@tonic-gate { 1578*0Sstevel@tonic-gate hot_spare_pool_t *hsp; 1579*0Sstevel@tonic-gate 1580*0Sstevel@tonic-gate *hsp_id = 0; 1581*0Sstevel@tonic-gate 1582*0Sstevel@tonic-gate if (id < 0) 1583*0Sstevel@tonic-gate return (0); 1584*0Sstevel@tonic-gate 1585*0Sstevel@tonic-gate hsp = find_hot_spare_pool(setno, id); 1586*0Sstevel@tonic-gate if (hsp == NULL) 1587*0Sstevel@tonic-gate return (-1); 1588*0Sstevel@tonic-gate 1589*0Sstevel@tonic-gate if (incref) 1590*0Sstevel@tonic-gate hsp->hsp_refcount++; 1591*0Sstevel@tonic-gate else 1592*0Sstevel@tonic-gate hsp->hsp_refcount--; 1593*0Sstevel@tonic-gate 1594*0Sstevel@tonic-gate *hsp_id = hsp->hsp_record_id; 1595*0Sstevel@tonic-gate 1596*0Sstevel@tonic-gate /* NOTE: Stripe code commits the hsp record */ 1597*0Sstevel@tonic-gate return (0); 1598*0Sstevel@tonic-gate } 1599*0Sstevel@tonic-gate 1600*0Sstevel@tonic-gate 1601*0Sstevel@tonic-gate static int 1602*0Sstevel@tonic-gate mkdev_for_a_hs(mddb_recid_t hs_id, md_dev64_t *dev) 1603*0Sstevel@tonic-gate { 1604*0Sstevel@tonic-gate hot_spare_t *hs; 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate hs = lookup_hot_spare(mddb_getsetnum(hs_id), hs_id, 0); 1607*0Sstevel@tonic-gate if (hs == NULL) 1608*0Sstevel@tonic-gate return (0); 1609*0Sstevel@tonic-gate 1610*0Sstevel@tonic-gate *dev = hs->hs_devnum; 1611*0Sstevel@tonic-gate return (0); 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate 1614*0Sstevel@tonic-gate static intptr_t 1615*0Sstevel@tonic-gate hotspares_interface( 1616*0Sstevel@tonic-gate hs_cmds_t cmd, 1617*0Sstevel@tonic-gate mddb_recid_t id, 1618*0Sstevel@tonic-gate uint64_t size, 1619*0Sstevel@tonic-gate int bool, 1620*0Sstevel@tonic-gate mddb_recid_t *hs_id, 1621*0Sstevel@tonic-gate mdkey_t *key, 1622*0Sstevel@tonic-gate md_dev64_t *dev, 1623*0Sstevel@tonic-gate diskaddr_t *sblock) 1624*0Sstevel@tonic-gate { 1625*0Sstevel@tonic-gate set_t setno; 1626*0Sstevel@tonic-gate int err = -1; 1627*0Sstevel@tonic-gate 1628*0Sstevel@tonic-gate mutex_enter(&md_mx); 1629*0Sstevel@tonic-gate while (md_status & MD_GBL_HS_LOCK) 1630*0Sstevel@tonic-gate cv_wait(&md_cv, &md_mx); 1631*0Sstevel@tonic-gate 1632*0Sstevel@tonic-gate /* If md_halt has been run do not continue */ 1633*0Sstevel@tonic-gate if (md_status & (MD_GBL_HALTED | MD_GBL_DAEMONS_DIE)) { 1634*0Sstevel@tonic-gate mutex_exit(&md_mx); 1635*0Sstevel@tonic-gate return (ENXIO); 1636*0Sstevel@tonic-gate } 1637*0Sstevel@tonic-gate 1638*0Sstevel@tonic-gate md_status |= MD_GBL_HS_LOCK; 1639*0Sstevel@tonic-gate mutex_exit(&md_mx); 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate setno = mddb_getsetnum(id); 1642*0Sstevel@tonic-gate 1643*0Sstevel@tonic-gate switch (cmd) { 1644*0Sstevel@tonic-gate case HS_GET: 1645*0Sstevel@tonic-gate err = reserve_a_hs(setno, id, size, bool, hs_id, 1646*0Sstevel@tonic-gate key, dev, sblock); 1647*0Sstevel@tonic-gate break; 1648*0Sstevel@tonic-gate case HS_FREE: 1649*0Sstevel@tonic-gate err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_AVAILABLE); 1650*0Sstevel@tonic-gate hotspares_poke_hotspares(); 1651*0Sstevel@tonic-gate break; 1652*0Sstevel@tonic-gate case HS_BAD: 1653*0Sstevel@tonic-gate err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_BROKEN); 1654*0Sstevel@tonic-gate break; 1655*0Sstevel@tonic-gate case HSP_INCREF: 1656*0Sstevel@tonic-gate err = modify_hsp_ref(setno, id, 1, hs_id); 1657*0Sstevel@tonic-gate break; 1658*0Sstevel@tonic-gate case HSP_DECREF: 1659*0Sstevel@tonic-gate err = modify_hsp_ref(setno, id, 0, hs_id); 1660*0Sstevel@tonic-gate break; 1661*0Sstevel@tonic-gate case HS_MKDEV: 1662*0Sstevel@tonic-gate err = mkdev_for_a_hs(*hs_id, dev); 1663*0Sstevel@tonic-gate break; 1664*0Sstevel@tonic-gate } 1665*0Sstevel@tonic-gate 1666*0Sstevel@tonic-gate mutex_enter(&md_mx); 1667*0Sstevel@tonic-gate md_status &= ~MD_GBL_HS_LOCK; 1668*0Sstevel@tonic-gate cv_broadcast(&md_cv); 1669*0Sstevel@tonic-gate mutex_exit(&md_mx); 1670*0Sstevel@tonic-gate 1671*0Sstevel@tonic-gate return (err); 1672*0Sstevel@tonic-gate } 1673*0Sstevel@tonic-gate 1674*0Sstevel@tonic-gate static void 1675*0Sstevel@tonic-gate imp_hotsparepool( 1676*0Sstevel@tonic-gate set_t setno, 1677*0Sstevel@tonic-gate mddb_recid_t recid 1678*0Sstevel@tonic-gate ) 1679*0Sstevel@tonic-gate { 1680*0Sstevel@tonic-gate hot_spare_pool_ond_t *hsp_ond; 1681*0Sstevel@tonic-gate mddb_recid_t *hsp_recid, *hs_recid; 1682*0Sstevel@tonic-gate int i; 1683*0Sstevel@tonic-gate uint_t *hsp_selfid; 1684*0Sstevel@tonic-gate 1685*0Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid); 1688*0Sstevel@tonic-gate hsp_recid = &(hsp_ond->hsp_record_id); 1689*0Sstevel@tonic-gate hsp_selfid = &(hsp_ond->hsp_self_id); 1690*0Sstevel@tonic-gate /* 1691*0Sstevel@tonic-gate * Fixup the pool and hotspares 1692*0Sstevel@tonic-gate */ 1693*0Sstevel@tonic-gate *hsp_recid = MAKERECID(setno, DBID(*hsp_recid)); 1694*0Sstevel@tonic-gate *hsp_selfid = MAKERECID(setno, DBID(*hsp_selfid)); 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate for (i = 0; i < hsp_ond->hsp_nhotspares; i++) { 1697*0Sstevel@tonic-gate hs_recid = &(hsp_ond->hsp_hotspares[i]); 1698*0Sstevel@tonic-gate *hs_recid = MAKERECID(setno, DBID(*hs_recid)); 1699*0Sstevel@tonic-gate } 1700*0Sstevel@tonic-gate } 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate static void 1703*0Sstevel@tonic-gate imp_hotspare( 1704*0Sstevel@tonic-gate set_t setno, 1705*0Sstevel@tonic-gate mddb_recid_t recid 1706*0Sstevel@tonic-gate ) 1707*0Sstevel@tonic-gate { 1708*0Sstevel@tonic-gate mddb_de_ic_t *dep; 1709*0Sstevel@tonic-gate mddb_rb32_t *rbp; 1710*0Sstevel@tonic-gate hot_spare_t *hs64; 1711*0Sstevel@tonic-gate hot_spare32_od_t *hs32; 1712*0Sstevel@tonic-gate mddb_recid_t *hs_recid; 1713*0Sstevel@tonic-gate 1714*0Sstevel@tonic-gate mddb_setrecprivate(recid, MD_PRV_GOTIT); 1715*0Sstevel@tonic-gate 1716*0Sstevel@tonic-gate dep = mddb_getrecdep(recid); 1717*0Sstevel@tonic-gate rbp = dep->de_rb; 1718*0Sstevel@tonic-gate if (rbp->rb_revision == MDDB_REV_RB) { 1719*0Sstevel@tonic-gate /* 1720*0Sstevel@tonic-gate * 32 bit hotspare 1721*0Sstevel@tonic-gate */ 1722*0Sstevel@tonic-gate hs32 = (hot_spare32_od_t *)mddb_getrecaddr(recid); 1723*0Sstevel@tonic-gate hs_recid = &(hs32->hs_record_id); 1724*0Sstevel@tonic-gate } else { 1725*0Sstevel@tonic-gate hs64 = (hot_spare_t *)mddb_getrecaddr(recid); 1726*0Sstevel@tonic-gate hs_recid = &(hs64->hs_record_id); 1727*0Sstevel@tonic-gate } 1728*0Sstevel@tonic-gate 1729*0Sstevel@tonic-gate /* 1730*0Sstevel@tonic-gate * Fixup the setno 1731*0Sstevel@tonic-gate */ 1732*0Sstevel@tonic-gate *hs_recid = MAKERECID(setno, DBID(*hs_recid)); 1733*0Sstevel@tonic-gate } 1734*0Sstevel@tonic-gate 1735*0Sstevel@tonic-gate static int 1736*0Sstevel@tonic-gate hotspares_imp_set( 1737*0Sstevel@tonic-gate set_t setno 1738*0Sstevel@tonic-gate ) 1739*0Sstevel@tonic-gate { 1740*0Sstevel@tonic-gate mddb_recid_t recid; 1741*0Sstevel@tonic-gate int gotsomething; 1742*0Sstevel@tonic-gate mddb_type_t typ1; 1743*0Sstevel@tonic-gate 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate gotsomething = 0; 1746*0Sstevel@tonic-gate 1747*0Sstevel@tonic-gate typ1 = (mddb_type_t)md_getshared_key(setno, 1748*0Sstevel@tonic-gate hotspares_md_ops.md_driver.md_drivername); 1749*0Sstevel@tonic-gate recid = mddb_makerecid(setno, 0); 1750*0Sstevel@tonic-gate while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) { 1751*0Sstevel@tonic-gate if (mddb_getrecprivate(recid) & MD_PRV_GOTIT) 1752*0Sstevel@tonic-gate continue; 1753*0Sstevel@tonic-gate 1754*0Sstevel@tonic-gate switch (mddb_getrectype2(recid)) { 1755*0Sstevel@tonic-gate case HSP_REC: 1756*0Sstevel@tonic-gate imp_hotsparepool(setno, recid); 1757*0Sstevel@tonic-gate gotsomething = 1; 1758*0Sstevel@tonic-gate break; 1759*0Sstevel@tonic-gate case HS_REC: 1760*0Sstevel@tonic-gate imp_hotspare(setno, recid); 1761*0Sstevel@tonic-gate gotsomething = 1; 1762*0Sstevel@tonic-gate break; 1763*0Sstevel@tonic-gate default: 1764*0Sstevel@tonic-gate ASSERT(0); 1765*0Sstevel@tonic-gate } 1766*0Sstevel@tonic-gate } 1767*0Sstevel@tonic-gate 1768*0Sstevel@tonic-gate return (gotsomething); 1769*0Sstevel@tonic-gate } 1770*0Sstevel@tonic-gate 1771*0Sstevel@tonic-gate static md_named_services_t hotspares_named_services[] = { 1772*0Sstevel@tonic-gate {hotspares_interface, "hot spare interface"}, 1773*0Sstevel@tonic-gate {NULL, 0} 1774*0Sstevel@tonic-gate }; 1775*0Sstevel@tonic-gate 1776*0Sstevel@tonic-gate md_ops_t hotspares_md_ops = { 1777*0Sstevel@tonic-gate NULL, /* open */ 1778*0Sstevel@tonic-gate NULL, /* close */ 1779*0Sstevel@tonic-gate NULL, /* strategy */ 1780*0Sstevel@tonic-gate NULL, /* print */ 1781*0Sstevel@tonic-gate NULL, /* dump */ 1782*0Sstevel@tonic-gate NULL, /* read */ 1783*0Sstevel@tonic-gate NULL, /* write */ 1784*0Sstevel@tonic-gate hotspares_ioctl, /* hotspares_ioctl, */ 1785*0Sstevel@tonic-gate hotspares_snarf, /* hotspares_snarf */ 1786*0Sstevel@tonic-gate hotspares_halt, /* halt */ 1787*0Sstevel@tonic-gate NULL, /* aread */ 1788*0Sstevel@tonic-gate NULL, /* awrite */ 1789*0Sstevel@tonic-gate hotspares_imp_set, /* import set */ 1790*0Sstevel@tonic-gate hotspares_named_services /* named_services */ 1791*0Sstevel@tonic-gate }; 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate static void 1794*0Sstevel@tonic-gate fini_uninit() 1795*0Sstevel@tonic-gate { 1796*0Sstevel@tonic-gate /* prevent access to services that may have been imported */ 1797*0Sstevel@tonic-gate md_clear_hot_spare_interface(); 1798*0Sstevel@tonic-gate } 1799*0Sstevel@tonic-gate 1800*0Sstevel@tonic-gate /* define the module linkage */ 1801*0Sstevel@tonic-gate MD_PLUGIN_MISC_MODULE("hot spares module %I%", md_noop, fini_uninit()) 1802