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