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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Just in case we're not in a build environment, make sure that 31 * TEXT_DOMAIN gets set to something. 32 */ 33 #if !defined(TEXT_DOMAIN) 34 #define TEXT_DOMAIN "SYS_TEST" 35 #endif 36 37 /* 38 * hotspares utilities 39 */ 40 41 #include <meta.h> 42 #include <sys/lvm/md_hotspares.h> 43 #include <sys/lvm/md_convert.h> 44 45 46 /* 47 * FUNCTION: meta_get_hsp_names() 48 * INPUT: sp - the set name to get hotspares from 49 * options - options from the command line 50 * OUTPUT: hspnlpp - list of all hotspare names 51 * ep - return error pointer 52 * RETURNS: int - -1 if error, 0 success 53 * PURPOSE: returns a list of all hotspares in the metadb 54 * for all devices in the specified set 55 */ 56 /*ARGSUSED*/ 57 int 58 meta_get_hsp_names( 59 mdsetname_t *sp, 60 mdhspnamelist_t **hspnlpp, 61 int options, 62 md_error_t *ep 63 ) 64 { 65 md_i_getnum_t gn; /* MD_IOCGET_NUM params */ 66 minor_t *minors = NULL; 67 minor_t *m_ptr; 68 int i; 69 70 /* we must have a set */ 71 assert(sp != NULL); 72 73 (void) memset(&gn, 0, sizeof (gn)); 74 MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno); 75 76 /* get number of devices */ 77 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) { 78 if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) { 79 mdclrerror(&gn.mde); 80 } else { 81 (void) mdstealerror(ep, &gn.mde); 82 return (-1); 83 } 84 } 85 86 if (gn.size > 0) { 87 /* malloc minor number buffer to be filled by ioctl */ 88 if ((minors = (minor_t *)malloc( 89 gn.size * sizeof (minor_t))) == 0) { 90 return (ENOMEM); 91 } 92 gn.minors = (uintptr_t)minors; 93 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) { 94 (void) mdstealerror(ep, &gn.mde); 95 free(minors); 96 return (-1); 97 } 98 m_ptr = minors; 99 for (i = 0; i < gn.size; i++) { 100 mdhspname_t *hspnp; 101 102 103 /* get name */ 104 if ((hspnp = metahsphspname(&sp, *m_ptr, ep)) 105 == NULL) 106 goto out; 107 108 /* append to list */ 109 (void) metahspnamelist_append(hspnlpp, hspnp); 110 111 /* next device */ 112 m_ptr++; 113 } 114 free(minors); 115 } 116 return (gn.size); 117 118 out: 119 if (minors != NULL) 120 free(minors); 121 metafreehspnamelist(*hspnlpp); 122 *hspnlpp = NULL; 123 return (-1); 124 } 125 126 /* 127 * get information of a specific hotspare pool from driver 128 */ 129 static get_hsp_t * 130 get_hspinfo( 131 mdsetname_t *sp, 132 mdhspname_t *hspnp, 133 md_error_t *ep 134 ) 135 { 136 md_i_get_t mig; 137 138 /* should have a set */ 139 assert(sp != NULL); 140 assert(sp->setno == HSP_SET(hspnp->hsp)); 141 142 /* get size of unit structure */ 143 (void) memset(&mig, 0, sizeof (mig)); 144 MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno); 145 mig.id = hspnp->hsp; 146 if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) { 147 (void) mdstealerror(ep, &mig.mde); 148 return (NULL); 149 } 150 151 /* get actual unit structure */ 152 assert(mig.size > 0); 153 mig.mdp = (uintptr_t)Zalloc(mig.size); 154 if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) { 155 (void) mdstealerror(ep, &mig.mde); 156 Free((void *)(uintptr_t)mig.mdp); 157 return (NULL); 158 } 159 return ((get_hsp_t *)(uintptr_t)mig.mdp); 160 } 161 162 /* 163 * free hotspare pool unit 164 */ 165 void 166 meta_free_hsp( 167 md_hsp_t *hspp 168 ) 169 { 170 if (hspp->hotspares.hotspares_val != NULL) { 171 assert(hspp->hotspares.hotspares_len > 0); 172 Free(hspp->hotspares.hotspares_val); 173 } 174 Free(hspp); 175 } 176 177 /* 178 * get hotspare pool unit (common) 179 */ 180 md_hsp_t * 181 meta_get_hsp_common( 182 mdsetname_t *sp, 183 mdhspname_t *hspnp, 184 int fast, 185 md_error_t *ep 186 ) 187 { 188 get_hsp_t *ghsp; 189 md_hsp_t *hspp; 190 uint_t hsi; 191 192 /* must have set */ 193 assert(sp != NULL); 194 assert(sp->setno == HSP_SET(hspnp->hsp)); 195 196 /* short circuit */ 197 if (hspnp->unitp != NULL) 198 return (hspnp->unitp); 199 200 /* get unit */ 201 if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL) 202 return (NULL); 203 204 /* allocate hsp */ 205 hspp = Zalloc(sizeof (*hspp)); 206 207 /* allocate hotspares */ 208 hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares; 209 210 /* if empty hotspare pool, we are done */ 211 if (hspp->hotspares.hotspares_len != 0) 212 hspp->hotspares.hotspares_val = 213 Zalloc(hspp->hotspares.hotspares_len * 214 sizeof (*hspp->hotspares.hotspares_val)); 215 216 /* get name, refcount */ 217 hspp->hspnamep = hspnp; 218 hspp->refcount = ghsp->ghsp_refcount; 219 220 /* get hotspares */ 221 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 222 mdkey_t hs_key = ghsp->ghsp_hs_keys[hsi]; 223 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 224 get_hs_params_t ghs; 225 226 /* get hotspare name */ 227 hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep); 228 if (hsp->hsnamep == NULL) 229 goto out; 230 231 /* get hotspare state */ 232 (void) memset(&ghs, 0, sizeof (ghs)); 233 MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno); 234 ghs.ghs_key = hs_key; 235 if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) { 236 (void) mdstealerror(ep, &ghs.mde); 237 goto out; 238 } 239 hsp->state = ghs.ghs_state; 240 hsp->size = ghs.ghs_number_blks; 241 hsp->timestamp = ghs.ghs_timestamp; 242 hsp->revision = ghs.ghs_revision; 243 } 244 245 /* cleanup, return success */ 246 Free(ghsp); 247 hspnp->unitp = hspp; 248 return (hspp); 249 250 /* cleanup, return error */ 251 out: 252 Free(ghsp); 253 meta_free_hsp(hspp); 254 return (NULL); 255 } 256 257 /* 258 * get hotspare pool unit 259 */ 260 md_hsp_t * 261 meta_get_hsp( 262 mdsetname_t *sp, 263 mdhspname_t *hspnp, 264 md_error_t *ep 265 ) 266 { 267 return (meta_get_hsp_common(sp, hspnp, 0, ep)); 268 } 269 270 /* 271 * check hotspare pool for dev 272 */ 273 static int 274 in_hsp( 275 mdsetname_t *sp, 276 mdhspname_t *hspnp, 277 mdname_t *np, 278 diskaddr_t slblk, 279 diskaddr_t nblks, 280 md_error_t *ep 281 ) 282 { 283 md_hsp_t *hspp; 284 uint_t i; 285 286 /* should be in the same set */ 287 assert(sp != NULL); 288 assert(sp->setno == HSP_SET(hspnp->hsp)); 289 290 /* get unit */ 291 if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL) 292 return (-1); 293 294 /* look in hotspares */ 295 for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) { 296 md_hs_t *hs = &hspp->hotspares.hotspares_val[i]; 297 mdname_t *hsnp = hs->hsnamep; 298 299 /* check overlap */ 300 if (metaismeta(hsnp)) 301 continue; 302 if (meta_check_overlap(hspnp->hspname, np, slblk, nblks, 303 hsnp, 0, -1, ep) != 0) 304 return (-1); 305 } 306 307 /* return success */ 308 return (0); 309 } 310 311 /* 312 * check to see if we're in a hotspare pool 313 */ 314 int 315 meta_check_inhsp( 316 mdsetname_t *sp, 317 mdname_t *np, 318 diskaddr_t slblk, 319 diskaddr_t nblks, 320 md_error_t *ep 321 ) 322 { 323 mdhspnamelist_t *hspnlp = NULL; 324 mdhspnamelist_t *p; 325 int rval = 0; 326 327 /* should have a set */ 328 assert(sp != NULL); 329 330 /* for each hotspare pool */ 331 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 332 return (-1); 333 for (p = hspnlp; (p != NULL); p = p->next) { 334 mdhspname_t *hspnp = p->hspnamep; 335 336 /* check hotspare pool */ 337 if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) { 338 rval = -1; 339 break; 340 } 341 } 342 343 /* cleanup, return success */ 344 metafreehspnamelist(hspnlp); 345 return (rval); 346 } 347 348 /* 349 * check hotspare 350 */ 351 int 352 meta_check_hotspare( 353 mdsetname_t *sp, 354 mdname_t *np, 355 md_error_t *ep 356 ) 357 { 358 mdchkopts_t options = (MDCHK_ALLOW_HS); 359 360 /* make sure we have a disk */ 361 if (metachkcomp(np, ep) != 0) 362 return (-1); 363 364 /* check to ensure that it is not already in use */ 365 if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) { 366 return (-1); 367 } 368 369 /* make sure it is in the set */ 370 if (meta_check_inset(sp, np, ep) != 0) 371 return (-1); 372 373 /* make sure its not in a metadevice */ 374 if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0) 375 return (-1); 376 377 /* return success */ 378 return (0); 379 } 380 381 /* 382 * print hsp 383 */ 384 static int 385 hsp_print( 386 md_hsp_t *hspp, 387 char *fname, 388 FILE *fp, 389 md_error_t *ep 390 ) 391 { 392 uint_t hsi; 393 int rval = -1; 394 395 /* print name */ 396 if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF) 397 goto out; 398 399 /* print hotspares */ 400 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 401 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 402 403 /* print hotspare */ 404 /* 405 * If the path is our standard /dev/rdsk or /dev/md/rdsk 406 * then just print out the cxtxdxsx or the dx, metainit 407 * will assume the default, otherwise we need the full 408 * pathname to make sure this works as we intend. 409 */ 410 if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) && 411 (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) && 412 (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) { 413 /* not standard path, print full pathname */ 414 if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF) 415 goto out; 416 } else { 417 /* standard path, just print ctd or d value */ 418 if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF) 419 goto out; 420 } 421 } 422 423 /* terminate last line */ 424 if (fprintf(fp, "\n") == EOF) 425 goto out; 426 427 /* success */ 428 rval = 0; 429 430 /* cleanup, return error */ 431 out: 432 if (rval != 0) 433 (void) mdsyserror(ep, errno, fname); 434 return (rval); 435 } 436 437 /* 438 * hotspare state name 439 */ 440 char * 441 hs_state_to_name( 442 md_hs_t *hsp, 443 md_timeval32_t *tvp 444 ) 445 { 446 hotspare_states_t state = hsp->state; 447 448 /* grab time */ 449 if (tvp != NULL) 450 *tvp = hsp->timestamp; 451 452 switch (state) { 453 case HSS_AVAILABLE: 454 return (dgettext(TEXT_DOMAIN, "Available")); 455 case HSS_RESERVED: 456 return (dgettext(TEXT_DOMAIN, "In use")); 457 case HSS_BROKEN: 458 return (dgettext(TEXT_DOMAIN, "Broken")); 459 case HSS_UNUSED: 460 default: 461 return (dgettext(TEXT_DOMAIN, "invalid")); 462 } 463 } 464 465 /* 466 * report hsp 467 */ 468 static int 469 hsp_report( 470 md_hsp_t *hspp, 471 mdnamelist_t **nlpp, 472 char *fname, 473 FILE *fp, 474 mdprtopts_t options, 475 md_error_t *ep, 476 mdsetname_t *sp 477 ) 478 { 479 uint_t hsi; 480 int rval = -1; 481 char *devid = ""; 482 mdname_t *didnp = NULL; 483 uint_t len; 484 int large_hs_dev_cnt = 0; 485 486 if (options & PRINT_LARGEDEVICES) { 487 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 488 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 489 if (hsp->revision == MD_64BIT_META_DEV) { 490 large_hs_dev_cnt += 1; 491 if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep) 492 != 0) 493 goto out; 494 } 495 } 496 497 if (large_hs_dev_cnt == 0) { 498 rval = 0; 499 goto out; 500 } 501 } 502 /* print header */ 503 if (hspp->hotspares.hotspares_len == 0) { 504 if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"), 505 hspp->hspnamep->hspname) == EOF) { 506 goto out; 507 } 508 } else if (hspp->hotspares.hotspares_len == 1) { 509 510 /* 511 * This allows the length 512 * of the ctd to vary from small to large without 513 * looking horrible. 514 */ 515 516 len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname); 517 /* 518 * if the length is to short to print out all of the header 519 * force the matter 520 */ 521 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device"))); 522 len += 2; 523 if (options & PRINT_LARGEDEVICES) { 524 if (fprintf(fp, 525 "%s: 1 hot spare (1 big device)\n\t%-*.*s " 526 "%-12.12s%-8.6s\t\t%s\n", 527 hspp->hspnamep->hspname, len, len, 528 dgettext(TEXT_DOMAIN, "Device"), 529 dgettext(TEXT_DOMAIN, "Status"), 530 dgettext(TEXT_DOMAIN, "Length"), 531 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 532 goto out; 533 } 534 } else { 535 if (fprintf(fp, 536 "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n", 537 hspp->hspnamep->hspname, len, len, 538 dgettext(TEXT_DOMAIN, "Device"), 539 dgettext(TEXT_DOMAIN, "Status"), 540 dgettext(TEXT_DOMAIN, "Length"), 541 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 542 goto out; 543 } 544 } 545 } else { 546 /* 547 * This allows the length 548 * of the ctd to vary from small to large without 549 * looking horrible. 550 */ 551 len = 0; 552 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 553 len = max(len, strlen(hspp-> 554 hotspares.hotspares_val[hsi].hsnamep->cname)); 555 } 556 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device"))); 557 len += 2; 558 if (options & PRINT_LARGEDEVICES) { 559 if (fprintf(fp, 560 "%s: %u hot spares (%d big device(s))\n\t%-*.*s " 561 "%-12.12s%-8.6s\t\t%s\n", 562 hspp->hspnamep->hspname, 563 hspp->hotspares.hotspares_len, 564 large_hs_dev_cnt, len, len, 565 dgettext(TEXT_DOMAIN, "Device"), 566 dgettext(TEXT_DOMAIN, "Status"), 567 dgettext(TEXT_DOMAIN, "Length"), 568 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 569 goto out; 570 } 571 } else { 572 if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s " 573 "%-12.12s%-8.6s\t\t%s\n", 574 hspp->hspnamep->hspname, 575 hspp->hotspares.hotspares_len, len, len, 576 dgettext(TEXT_DOMAIN, "Device"), 577 dgettext(TEXT_DOMAIN, "Status"), 578 dgettext(TEXT_DOMAIN, "Length"), 579 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) { 580 goto out; 581 } 582 } 583 } 584 585 /* print hotspares */ 586 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 587 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 588 char *cname = hsp->hsnamep->cname; 589 char *hs_state; 590 md_timeval32_t tv; 591 char *timep; 592 ddi_devid_t dtp; 593 594 /* populate the key in the name_p structure */ 595 if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) { 596 return (-1); 597 } 598 599 if (options & PRINT_LARGEDEVICES) { 600 if (hsp->revision != MD_64BIT_META_DEV) 601 continue; 602 } 603 /* determine if devid does NOT exist */ 604 if (options & PRINT_DEVID) { 605 if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep), 606 didnp->key, ep)) == NULL) 607 devid = dgettext(TEXT_DOMAIN, "No "); 608 else { 609 devid = dgettext(TEXT_DOMAIN, "Yes"); 610 free(dtp); 611 } 612 } 613 /* print hotspare */ 614 hs_state = hs_state_to_name(hsp, &tv); 615 /* 616 * This allows the length 617 * of the ctd to vary from small to large without 618 * looking horrible. 619 */ 620 if (! (options & PRINT_TIMES)) { 621 if (fprintf(fp, 622 " %-*s %-12s %lld blocks\t%s\n", 623 len, cname, hs_state, 624 hsp->size, devid) == EOF) { 625 goto out; 626 } 627 } else { 628 timep = meta_print_time(&tv); 629 630 if (fprintf(fp, 631 " %-*s\t %-11s %8lld blocks%s\t%s\n", 632 len, cname, hs_state, 633 hsp->size, devid, timep) == EOF) { 634 goto out; 635 } 636 } 637 } 638 639 /* add extra line */ 640 if (fprintf(fp, "\n") == EOF) 641 goto out; 642 643 /* success */ 644 rval = 0; 645 646 /* cleanup, return error */ 647 out: 648 if (rval != 0) 649 (void) mdsyserror(ep, errno, fname); 650 return (rval); 651 } 652 653 /* 654 * print/report hsp 655 */ 656 int 657 meta_hsp_print( 658 mdsetname_t *sp, 659 mdhspname_t *hspnp, 660 mdnamelist_t **nlpp, 661 char *fname, 662 FILE *fp, 663 mdprtopts_t options, 664 md_error_t *ep 665 ) 666 { 667 md_hsp_t *hspp; 668 669 /* should have same set */ 670 assert(sp != NULL); 671 assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp))); 672 673 /* print all hsps */ 674 if (hspnp == NULL) { 675 mdhspnamelist_t *hspnlp = NULL; 676 mdhspnamelist_t *p; 677 int cnt; 678 int rval = 0; 679 680 if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0) 681 return (-1); 682 else if (cnt == 0) 683 return (0); 684 685 /* recurse */ 686 for (p = hspnlp; (p != NULL); p = p->next) { 687 mdhspname_t *hspnp = p->hspnamep; 688 689 if (meta_hsp_print(sp, hspnp, nlpp, fname, fp, 690 options, ep) != 0) 691 rval = -1; 692 } 693 694 /* cleanup, return success */ 695 metafreehspnamelist(hspnlp); 696 return (rval); 697 } 698 699 /* get unit structure */ 700 if ((hspp = meta_get_hsp_common(sp, hspnp, 701 ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL) 702 return (-1); 703 704 /* print appropriate detail */ 705 if (options & PRINT_SHORT) 706 return (hsp_print(hspp, fname, fp, ep)); 707 else 708 return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp)); 709 } 710 711 /* 712 * check for valid hotspare pool 713 */ 714 int 715 metachkhsp( 716 mdsetname_t *sp, 717 mdhspname_t *hspnp, 718 md_error_t *ep 719 ) 720 { 721 if (meta_get_hsp(sp, hspnp, ep) == NULL) 722 return (-1); 723 return (0); 724 } 725 726 /* 727 * invalidate hotspare pool info 728 */ 729 void 730 meta_invalidate_hsp( 731 mdhspname_t *hspnp 732 ) 733 { 734 md_hsp_t *hspp = hspnp->unitp; 735 736 /* free it up */ 737 if (hspp == NULL) 738 return; 739 meta_free_hsp(hspp); 740 741 /* clear cache */ 742 hspnp->unitp = NULL; 743 } 744 745 /* 746 * add hotspares and/or hotspare pool 747 */ 748 int 749 meta_hs_add( 750 mdsetname_t *sp, 751 mdhspname_t *hspnp, 752 mdnamelist_t *hsnlp, 753 mdcmdopts_t options, 754 md_error_t *ep 755 ) 756 { 757 mdnamelist_t *p; 758 set_hs_params_t shs; 759 760 /* should have a set */ 761 assert(sp != NULL); 762 assert(sp->setno == HSP_SET(hspnp->hsp)); 763 764 /* clear cache */ 765 meta_invalidate_hsp(hspnp); 766 767 /* setup hotspare pool info */ 768 (void) memset(&shs, 0, sizeof (shs)); 769 shs.shs_cmd = ADD_HOT_SPARE; 770 shs.shs_hot_spare_pool = hspnp->hsp; 771 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 772 773 /* add empty hotspare pool */ 774 if (hsnlp == NULL) { 775 shs.shs_options = HS_OPT_POOL; 776 /* If DOIT is not set, it's a dryrun */ 777 if ((options & MDCMD_DOIT) == 0) { 778 shs.shs_options |= HS_OPT_DRYRUN; 779 } 780 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, 781 hspnp->hspname) != 0) 782 return (mdstealerror(ep, &shs.mde)); 783 goto success; 784 } 785 786 /* add hotspares */ 787 shs.shs_options = HS_OPT_NONE; 788 /* If DOIT is not set, it's a dryrun */ 789 if ((options & MDCMD_DOIT) == 0) { 790 shs.shs_options |= HS_OPT_DRYRUN; 791 } 792 for (p = hsnlp; (p != NULL); p = p->next) { 793 mdname_t *hsnp = p->namep; 794 diskaddr_t size, label, start_blk; 795 796 /* should be in same set */ 797 assert(sp->setno == HSP_SET(hspnp->hsp)); 798 799 /* check it out */ 800 if (meta_check_hotspare(sp, hsnp, ep) != 0) 801 return (-1); 802 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) 803 return (-1); 804 else if (size == 0) 805 return (mdsyserror(ep, ENOSPC, hsnp->cname)); 806 if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR) 807 return (-1); 808 if ((start_blk = metagetstart(sp, hsnp, ep)) 809 == MD_DISKADDR_ERROR) 810 return (-1); 811 812 shs.shs_size_option = meta_check_devicesize(size); 813 814 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 815 if (options & MDCMD_DOIT) { 816 /* store name in namespace */ 817 if (add_key_name(sp, hsnp, NULL, ep) != 0) 818 return (-1); 819 } 820 821 /* add hotspare and/or hotspare pool */ 822 shs.shs_component_old = hsnp->dev; 823 shs.shs_start_blk = start_blk; 824 shs.shs_has_label = ((label > 0) ? 1 : 0); 825 shs.shs_number_blks = size; 826 shs.shs_key_old = hsnp->key; 827 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 828 if ((options & MDCMD_DOIT) && 829 (shs.shs_options != HS_OPT_POOL)) { 830 (void) del_key_name(sp, hsnp, ep); 831 } 832 return (mdstealerror(ep, &shs.mde)); 833 } 834 } 835 836 /* print success message */ 837 success: 838 if (options & MDCMD_PRINT) { 839 if ((options & MDCMD_INIT) || (hsnlp == NULL)) { 840 (void) printf(dgettext(TEXT_DOMAIN, 841 "%s: Hotspare pool is setup\n"), 842 hspnp->hspname); 843 } else if (hsnlp->next == NULL) { 844 (void) printf(dgettext(TEXT_DOMAIN, 845 "%s: Hotspare is added\n"), 846 hspnp->hspname); 847 } else { 848 (void) printf(dgettext(TEXT_DOMAIN, 849 "%s: Hotspares are added\n"), 850 hspnp->hspname); 851 } 852 (void) fflush(stdout); 853 } 854 855 /* return success */ 856 return (0); 857 } 858 859 /* 860 * delete hotspares from pool 861 */ 862 int 863 meta_hs_delete( 864 mdsetname_t *sp, 865 mdhspname_t *hspnp, 866 mdnamelist_t *hsnlp, 867 mdcmdopts_t options, 868 md_error_t *ep 869 ) 870 { 871 mdnamelist_t *p; 872 set_hs_params_t shs; 873 874 /* should have a set */ 875 assert(sp != NULL); 876 assert(sp->setno == HSP_SET(hspnp->hsp)); 877 878 /* clear cache */ 879 meta_invalidate_hsp(hspnp); 880 881 /* setup hotspare pool info */ 882 (void) memset(&shs, 0, sizeof (shs)); 883 shs.shs_hot_spare_pool = hspnp->hsp; 884 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 885 shs.shs_cmd = DELETE_HOT_SPARE; 886 887 /* delete empty hotspare pool */ 888 if (hsnlp == NULL) { 889 shs.shs_options = HS_OPT_POOL; 890 /* If DOIT is not set, it's a dryrun */ 891 if ((options & MDCMD_DOIT) == 0) { 892 shs.shs_options |= HS_OPT_DRYRUN; 893 } 894 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, 895 hspnp->hspname) != 0) 896 return (mdstealerror(ep, &shs.mde)); 897 goto success; 898 } 899 900 /* delete hotspares */ 901 shs.shs_options = HS_OPT_NONE; 902 /* If DOIT is not set, it's a dryrun */ 903 if ((options & MDCMD_DOIT) == 0) { 904 shs.shs_options |= HS_OPT_DRYRUN; 905 } 906 for (p = hsnlp; (p != NULL); p = p->next) { 907 mdname_t *hsnp = p->namep; 908 909 /* should be in same set */ 910 assert(sp->setno == HSP_SET(hspnp->hsp)); 911 912 /* delete hotspare */ 913 shs.shs_component_old = hsnp->dev; 914 meta_invalidate_name(hsnp); 915 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) 916 return (mdstealerror(ep, &shs.mde)); 917 } 918 919 /* print success message */ 920 success: 921 if (options & MDCMD_PRINT) { 922 if (hsnlp == NULL) { 923 (void) printf(dgettext(TEXT_DOMAIN, 924 "%s: Hotspare pool is cleared\n"), 925 hspnp->hspname); 926 } else if (hsnlp->next == NULL) { 927 (void) printf(dgettext(TEXT_DOMAIN, 928 "%s: Hotspare is deleted\n"), 929 hspnp->hspname); 930 } else { 931 (void) printf(dgettext(TEXT_DOMAIN, 932 "%s: Hotspares are deleted\n"), 933 hspnp->hspname); 934 } 935 (void) fflush(stdout); 936 } 937 938 /* return success */ 939 return (0); 940 } 941 942 /* 943 * replace hotspare in pool 944 */ 945 int 946 meta_hs_replace( 947 mdsetname_t *sp, 948 mdhspname_t *hspnp, 949 mdname_t *oldnp, 950 mdname_t *newnp, 951 mdcmdopts_t options, 952 md_error_t *ep 953 ) 954 { 955 set_hs_params_t shs; 956 diskaddr_t size, label, start_blk; 957 md_dev64_t old_dev, new_dev; 958 diskaddr_t new_start_blk, new_end_blk; 959 int rebind; 960 char *new_devidp = NULL; 961 int ret; 962 md_set_desc *sd; 963 964 /* should be in same set */ 965 assert(sp != NULL); 966 assert(sp->setno == HSP_SET(hspnp->hsp)); 967 968 /* save new binding incase this is a rebind where oldnp==newnp */ 969 new_dev = newnp->dev; 970 new_start_blk = newnp->start_blk; 971 new_end_blk = newnp->end_blk; 972 973 /* invalidate, then get the hotspare (fill in oldnp from metadb) */ 974 meta_invalidate_hsp(hspnp); 975 if (meta_get_hsp(sp, hspnp, ep) == NULL) 976 return (-1); 977 978 /* the old device binding is now established */ 979 if ((old_dev = oldnp->dev) == NODEV64) 980 return (mdsyserror(ep, ENODEV, oldnp->cname)); 981 982 /* 983 * check for the case where oldnp and newnp indicate the same 984 * device, but the dev_t of the device has changed between old 985 * and new. This is called a rebind. On entry the dev_t 986 * represents the new device binding determined from the 987 * filesystem (meta_getdev). After calling meta_get_hsp 988 * oldnp (and maybe newnp if this is a rebind) is updated based 989 * to the old binding from the metadb (done by metakeyname). 990 */ 991 if ((strcmp(oldnp->rname, newnp->rname) == 0) && 992 (old_dev != new_dev)) { 993 rebind = 1; 994 } else { 995 rebind = 0; 996 } 997 if (rebind) { 998 newnp->dev = new_dev; 999 newnp->start_blk = new_start_blk; 1000 newnp->end_blk = new_end_blk; 1001 } 1002 1003 /* 1004 * Save a copy of the devid associated with the new disk, the reason 1005 * is that the meta_check_hotspare() call could cause the devid to 1006 * be changed to that of the devid that is currently stored in the 1007 * replica namespace for the disk in question. This devid could be 1008 * stale if we are replacing the disk. The function that overwrites 1009 * the devid is dr2drivedesc(). 1010 */ 1011 if (newnp->drivenamep->devid != NULL) 1012 new_devidp = Strdup(newnp->drivenamep->devid); 1013 1014 /* if it's a multi-node diskset clear new_devidp */ 1015 if (!metaislocalset(sp)) { 1016 if ((sd = metaget_setdesc(sp, ep)) == NULL) { 1017 Free(new_devidp); 1018 return (-1); 1019 } 1020 if (MD_MNSET_DESC(sd)) { 1021 Free(new_devidp); 1022 new_devidp = NULL; 1023 } 1024 } 1025 1026 /* check it out */ 1027 if (meta_check_hotspare(sp, newnp, ep) != 0) { 1028 if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) { 1029 Free(new_devidp); 1030 return (-1); 1031 } 1032 mdclrerror(ep); 1033 } 1034 if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) { 1035 Free(new_devidp); 1036 return (-1); 1037 } 1038 if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) { 1039 Free(new_devidp); 1040 return (-1); 1041 } 1042 if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) { 1043 Free(new_devidp); 1044 return (-1); 1045 } 1046 if (start_blk >= size) { 1047 (void) mdsyserror(ep, ENOSPC, newnp->cname); 1048 Free(new_devidp); 1049 return (-1); 1050 } 1051 1052 /* 1053 * Copy back the saved devid. 1054 */ 1055 Free(newnp->drivenamep->devid); 1056 if (new_devidp != NULL) { 1057 newnp->drivenamep->devid = new_devidp; 1058 new_devidp = NULL; 1059 } 1060 1061 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 1062 if (options & MDCMD_DOIT) { 1063 /* store name in namespace */ 1064 if (add_key_name(sp, newnp, NULL, ep) != 0) 1065 return (-1); 1066 } 1067 1068 if (rebind && !metaislocalset(sp)) { 1069 /* 1070 * We are 'rebind'ing a disk that is in a diskset so as well 1071 * as updating the diskset's namespace the local set needs 1072 * to be updated because it also contains a reference to the 1073 * disk in question. 1074 */ 1075 ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname, 1076 ep); 1077 1078 if (ret != METADEVADM_SUCCESS) { 1079 md_error_t xep = mdnullerror; 1080 1081 /* 1082 * In dryrun mode (DOIT not set) we must not alter 1083 * the mddb 1084 */ 1085 if (options & MDCMD_DOIT) { 1086 (void) del_key_name(sp, newnp, &xep); 1087 mdclrerror(&xep); 1088 return (-1); 1089 } 1090 } 1091 } 1092 1093 /* replace hotspare */ 1094 (void) memset(&shs, 0, sizeof (shs)); 1095 1096 shs.shs_size_option = meta_check_devicesize(size); 1097 1098 shs.shs_cmd = REPLACE_HOT_SPARE; 1099 shs.shs_hot_spare_pool = hspnp->hsp; 1100 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1101 shs.shs_component_old = old_dev; 1102 shs.shs_options = HS_OPT_NONE; 1103 /* If DOIT is not set, it's a dryrun */ 1104 if ((options & MDCMD_DOIT) == 0) { 1105 shs.shs_options |= HS_OPT_DRYRUN; 1106 } 1107 shs.shs_component_new = new_dev; 1108 shs.shs_start_blk = start_blk; 1109 shs.shs_has_label = ((label > 0) ? 1 : 0); 1110 shs.shs_number_blks = size; 1111 shs.shs_key_new = newnp->key; 1112 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 1113 if (options & MDCMD_DOIT) { 1114 (void) del_key_name(sp, newnp, ep); 1115 } 1116 return (mdstealerror(ep, &shs.mde)); 1117 } 1118 1119 /* clear cache */ 1120 meta_invalidate_name(oldnp); 1121 meta_invalidate_name(newnp); 1122 meta_invalidate_hsp(hspnp); 1123 1124 /* let em know */ 1125 if (options & MDCMD_PRINT) { 1126 (void) printf(dgettext(TEXT_DOMAIN, 1127 "%s: Hotspare %s is replaced with %s\n"), 1128 hspnp->hspname, oldnp->cname, newnp->cname); 1129 (void) fflush(stdout); 1130 } 1131 1132 /* return success */ 1133 return (0); 1134 } 1135 1136 /* 1137 * enable hotspares 1138 */ 1139 int 1140 meta_hs_enable( 1141 mdsetname_t *sp, 1142 mdnamelist_t *hsnlp, 1143 mdcmdopts_t options, 1144 md_error_t *ep 1145 ) 1146 { 1147 mdhspnamelist_t *hspnlp = NULL; 1148 mdhspnamelist_t *hspnp; 1149 set_hs_params_t shs; 1150 int rval = -1; 1151 1152 /* should have a set */ 1153 assert(sp != NULL); 1154 1155 /* setup device info */ 1156 (void) memset(&shs, 0, sizeof (shs)); 1157 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1158 shs.shs_cmd = FIX_HOT_SPARE; 1159 shs.shs_options = HS_OPT_NONE; 1160 /* If DOIT is not set, it's a dryrun */ 1161 if ((options & MDCMD_DOIT) == 0) { 1162 shs.shs_options |= HS_OPT_DRYRUN; 1163 } 1164 1165 /* get the list of hotspare names */ 1166 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 1167 goto out; 1168 1169 /* enable hotspares for each components */ 1170 for (; (hsnlp != NULL); hsnlp = hsnlp->next) { 1171 mdname_t *hsnp = hsnlp->namep; 1172 md_dev64_t fs_dev; 1173 int rebind = 0; 1174 diskaddr_t size, label, start_blk; 1175 1176 /* get the file_system dev binding */ 1177 if (meta_getdev(sp, hsnp, ep) != 0) 1178 return (-1); 1179 fs_dev = hsnp->dev; 1180 1181 /* 1182 * search for the component in each hotspare pool 1183 * and replace it (instead of enable) if the binding 1184 * has changed. 1185 */ 1186 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) { 1187 /* 1188 * in_hsp will call meta_get_hsp which will fill 1189 * in hspnp with metadb version of component 1190 */ 1191 meta_invalidate_hsp(hspnp->hspnamep); 1192 if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) { 1193 /* 1194 * check for the case where the dev_t has 1195 * changed between the filesystem and the 1196 * metadb. This is called a rebind, and 1197 * is handled by meta_hs_replace. 1198 */ 1199 if (fs_dev != hsnp->dev) { 1200 /* 1201 * establish file system binding 1202 * with invalid start/end 1203 */ 1204 rebind++; 1205 hsnp->dev = fs_dev; 1206 hsnp->start_blk = -1; 1207 hsnp->end_blk = -1; 1208 rval = meta_hs_replace(sp, 1209 hspnp->hspnamep, 1210 hsnp, hsnp, options, ep); 1211 if (rval != 0) 1212 goto out; 1213 } 1214 } 1215 } 1216 if (rebind) 1217 continue; 1218 1219 /* enable the component in all hotspares that use it */ 1220 if (meta_check_hotspare(sp, hsnp, ep) != 0) 1221 goto out; 1222 1223 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) 1224 goto out; 1225 if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR) 1226 goto out; 1227 if ((start_blk = metagetstart(sp, hsnp, ep)) 1228 == MD_DISKADDR_ERROR) 1229 goto out; 1230 if (start_blk >= size) { 1231 (void) mdsyserror(ep, ENOSPC, hsnp->cname); 1232 goto out; 1233 } 1234 1235 /* enable hotspare */ 1236 shs.shs_component_old = hsnp->dev; 1237 shs.shs_component_new = hsnp->dev; 1238 shs.shs_start_blk = start_blk; 1239 shs.shs_has_label = ((label > 0) ? 1 : 0); 1240 shs.shs_number_blks = size; 1241 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) { 1242 rval = mdstealerror(ep, &shs.mde); 1243 goto out; 1244 } 1245 1246 /* 1247 * Are we dealing with a non-local set? If so need to update 1248 * the local namespace so that the disk record has the correct 1249 * devid. 1250 */ 1251 if (!metaislocalset(sp)) { 1252 rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, 1253 hsnp->cname, ep); 1254 1255 if (rval != METADEVADM_SUCCESS) { 1256 /* 1257 * Failed to update the local set. Nothing to 1258 * do here apart from report the error. The 1259 * namespace is most likely broken and some 1260 * form of remedial recovery is going to 1261 * be required. 1262 */ 1263 mde_perror(ep, ""); 1264 mdclrerror(ep); 1265 } 1266 } 1267 1268 /* clear cache */ 1269 meta_invalidate_name(hsnp); 1270 1271 /* let em know */ 1272 if (options & MDCMD_PRINT) { 1273 (void) printf(dgettext(TEXT_DOMAIN, 1274 "hotspare %s is enabled\n"), 1275 hsnp->cname); 1276 (void) fflush(stdout); 1277 } 1278 } 1279 1280 /* clear whole cache */ 1281 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) { 1282 meta_invalidate_hsp(hspnp->hspnamep); 1283 } 1284 1285 1286 /* return success */ 1287 rval = 0; 1288 1289 out: 1290 if (hspnlp) 1291 metafreehspnamelist(hspnlp); 1292 return (rval); 1293 } 1294 1295 /* 1296 * check for dups in the hsp itself 1297 */ 1298 static int 1299 check_twice( 1300 md_hsp_t *hspp, 1301 uint_t hsi, 1302 md_error_t *ep 1303 ) 1304 { 1305 mdhspname_t *hspnp = hspp->hspnamep; 1306 mdname_t *thisnp; 1307 uint_t h; 1308 1309 thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep; 1310 for (h = 0; (h < hsi); ++h) { 1311 md_hs_t *hsp = &hspp->hotspares.hotspares_val[h]; 1312 mdname_t *hsnp = hsp->hsnamep; 1313 1314 if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1, 1315 hsnp, 0, -1, ep) != 0) 1316 return (-1); 1317 } 1318 return (0); 1319 } 1320 1321 /* 1322 * check hsp 1323 */ 1324 /*ARGSUSED2*/ 1325 int 1326 meta_check_hsp( 1327 mdsetname_t *sp, 1328 md_hsp_t *hspp, 1329 mdcmdopts_t options, 1330 md_error_t *ep 1331 ) 1332 { 1333 mdhspname_t *hspnp = hspp->hspnamep; 1334 uint_t hsi; 1335 1336 /* check hotspares */ 1337 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 1338 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1339 mdname_t *hsnp = hsp->hsnamep; 1340 diskaddr_t size; 1341 1342 /* check hotspare */ 1343 if (meta_check_hotspare(sp, hsnp, ep) != 0) 1344 return (-1); 1345 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) { 1346 return (-1); 1347 } else if (size == 0) { 1348 return (mdsyserror(ep, ENOSPC, hspnp->hspname)); 1349 } 1350 1351 /* check this hsp too */ 1352 if (check_twice(hspp, hsi, ep) != 0) 1353 return (-1); 1354 } 1355 1356 /* return success */ 1357 return (0); 1358 } 1359 1360 /* 1361 * create hsp 1362 */ 1363 int 1364 meta_create_hsp( 1365 mdsetname_t *sp, 1366 md_hsp_t *hspp, 1367 mdcmdopts_t options, 1368 md_error_t *ep 1369 ) 1370 { 1371 mdhspname_t *hspnp = hspp->hspnamep; 1372 mdnamelist_t *hsnlp = NULL; 1373 uint_t hsi; 1374 int rval = -1; 1375 1376 /* validate hsp */ 1377 if (meta_check_hsp(sp, hspp, options, ep) != 0) 1378 return (-1); 1379 1380 /* if we're not doing anything, return success */ 1381 if (! (options & MDCMD_DOIT)) 1382 return (0); 1383 1384 /* create hsp */ 1385 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 1386 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1387 mdname_t *hsnp = hsp->hsnamep; 1388 1389 (void) metanamelist_append(&hsnlp, hsnp); 1390 } 1391 options |= MDCMD_INIT; 1392 rval = meta_hs_add(sp, hspnp, hsnlp, options, ep); 1393 1394 /* cleanup, return success */ 1395 metafreenamelist(hsnlp); 1396 return (rval); 1397 } 1398 1399 /* 1400 * initialize hsp 1401 * NOTE: this functions is metainit(1m)'s command line parser! 1402 */ 1403 int 1404 meta_init_hsp( 1405 mdsetname_t **spp, 1406 int argc, 1407 char *argv[], 1408 mdcmdopts_t options, 1409 md_error_t *ep 1410 ) 1411 { 1412 char *uname = argv[0]; 1413 mdhspname_t *hspnp = NULL; 1414 md_hsp_t *hspp = NULL; 1415 uint_t hsi; 1416 int rval = -1; 1417 1418 1419 /* get hsp name */ 1420 assert(argc > 0); 1421 if (argc < 1) 1422 goto syntax; 1423 if ((hspnp = metahspname(spp, uname, ep)) == NULL) 1424 goto out; 1425 assert(*spp != NULL); 1426 uname = hspnp->hspname; 1427 1428 if (!(options & MDCMD_NOLOCK)) { 1429 /* grab set lock */ 1430 if (meta_lock(*spp, TRUE, ep)) 1431 goto out; 1432 1433 if (meta_check_ownership(*spp, ep) != 0) 1434 goto out; 1435 } 1436 1437 /* see if it exists already */ 1438 if (meta_get_hsp(*spp, hspnp, ep) != NULL) { 1439 (void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP, hspnp->hsp, uname); 1440 goto out; 1441 } else if (! mdishsperror(ep, MDE_INVAL_HSP)) { 1442 goto out; 1443 } else { 1444 mdclrerror(ep); 1445 } 1446 --argc, ++argv; 1447 1448 /* parse general options */ 1449 optind = 0; 1450 opterr = 0; 1451 if (getopt(argc, argv, "") != -1) 1452 goto options; 1453 1454 /* allocate hsp */ 1455 hspp = Zalloc(sizeof (*hspp)); 1456 hspp->hotspares.hotspares_len = argc; 1457 if (argc > 0) { 1458 hspp->hotspares.hotspares_val = 1459 Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val)); 1460 } 1461 1462 /* setup pool */ 1463 hspp->hspnamep = hspnp; 1464 1465 /* parse hotspares */ 1466 for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len)); 1467 ++hsi) { 1468 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1469 mdname_t *hsnamep; 1470 1471 /* parse hotspare name */ 1472 if ((hsnamep = metaname(spp, argv[0], ep)) == NULL) 1473 goto out; 1474 hsp->hsnamep = hsnamep; 1475 --argc, ++argv; 1476 } 1477 1478 /* we should be at the end */ 1479 if (argc != 0) 1480 goto syntax; 1481 1482 /* create hotspare pool */ 1483 if (meta_create_hsp(*spp, hspp, options, ep) != 0) 1484 goto out; 1485 rval = 0; /* success */ 1486 goto out; 1487 1488 /* syntax error */ 1489 syntax: 1490 rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv); 1491 goto out; 1492 1493 /* options error */ 1494 options: 1495 rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv); 1496 goto out; 1497 1498 /* cleanup, return error */ 1499 out: 1500 if (hspp != NULL) 1501 meta_free_hsp(hspp); 1502 return (rval); 1503 } 1504 1505 /* 1506 * reset hotspare pool 1507 */ 1508 int 1509 meta_hsp_reset( 1510 mdsetname_t *sp, 1511 mdhspname_t *hspnp, 1512 mdcmdopts_t options, 1513 md_error_t *ep 1514 ) 1515 { 1516 md_hsp_t *hspp; 1517 set_hs_params_t shs; 1518 uint_t i; 1519 int rval = -1; 1520 1521 /* should have the same set */ 1522 assert(sp != NULL); 1523 assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp))); 1524 1525 /* reset all hotspares */ 1526 if (hspnp == NULL) { 1527 mdhspnamelist_t *hspnlp = NULL; 1528 mdhspnamelist_t *p; 1529 1530 /* for each hotspare pool */ 1531 rval = 0; 1532 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 1533 return (-1); 1534 for (p = hspnlp; (p != NULL); p = p->next) { 1535 /* reset hotspare pool */ 1536 hspnp = p->hspnamep; 1537 1538 /* 1539 * If this is a multi-node set, we send a series 1540 * of individual metaclear commands. 1541 */ 1542 if (meta_is_mn_set(sp, ep)) { 1543 if (meta_mn_send_metaclear_command(sp, 1544 hspnp->hspname, options, 0, ep) != 0) { 1545 rval = -1; 1546 break; 1547 } 1548 } else { 1549 if (meta_hsp_reset(sp, hspnp, options, 1550 ep) != 0) { 1551 rval = -1; 1552 break; 1553 } 1554 } 1555 } 1556 1557 /* cleanup, return success */ 1558 metafreehspnamelist(hspnlp); 1559 return (rval); 1560 } 1561 1562 /* get unit structure */ 1563 if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL) 1564 return (-1); 1565 1566 /* make sure nobody owns us */ 1567 if (hspp->refcount > 0) { 1568 return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp, 1569 hspnp->hspname)); 1570 } 1571 1572 /* clear hotspare pool members */ 1573 (void) memset(&shs, 0, sizeof (shs)); 1574 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1575 shs.shs_cmd = DELETE_HOT_SPARE; 1576 shs.shs_hot_spare_pool = hspnp->hsp; 1577 for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) { 1578 md_hs_t *hs = &hspp->hotspares.hotspares_val[i]; 1579 mdname_t *hsnamep = hs->hsnamep; 1580 1581 /* clear cache */ 1582 meta_invalidate_name(hsnamep); 1583 1584 /* clear hotspare */ 1585 shs.shs_component_old = hsnamep->dev; 1586 shs.shs_options = HS_OPT_FORCE; 1587 /* If DOIT is not set, it's a dryrun */ 1588 if ((options & MDCMD_DOIT) == 0) { 1589 shs.shs_options |= HS_OPT_DRYRUN; 1590 } 1591 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 1592 (void) mdstealerror(ep, &shs.mde); 1593 goto out; 1594 } 1595 } 1596 1597 /* clear hotspare pool */ 1598 shs.shs_options = HS_OPT_POOL; 1599 /* If DOIT is not set, it's a dryrun */ 1600 if ((options & MDCMD_DOIT) == 0) { 1601 shs.shs_options |= HS_OPT_DRYRUN; 1602 } 1603 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hspnp->hspname) != 0) { 1604 (void) mdstealerror(ep, &shs.mde); 1605 goto out; 1606 } 1607 rval = 0; /* success */ 1608 1609 /* let em know */ 1610 if (options & MDCMD_PRINT) { 1611 (void) printf(dgettext(TEXT_DOMAIN, 1612 "%s: Hotspare pool is cleared\n"), 1613 hspnp->hspname); 1614 (void) fflush(stdout); 1615 } 1616 1617 /* clear subdevices (nothing to do) */ 1618 1619 /* cleanup, return success */ 1620 out: 1621 meta_invalidate_hsp(hspnp); 1622 return (rval); 1623 } 1624