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 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 1053 if (options & MDCMD_DOIT) { 1054 /* store name in namespace */ 1055 if (add_key_name(sp, newnp, NULL, ep) != 0) 1056 return (-1); 1057 } 1058 1059 /* 1060 * Copy back the saved devid. 1061 */ 1062 Free(newnp->drivenamep->devid); 1063 if (new_devidp != NULL) { 1064 newnp->drivenamep->devid = new_devidp; 1065 new_devidp = NULL; 1066 } 1067 1068 /* In dryrun mode (DOIT not set) we must not alter the mddb */ 1069 if (options & MDCMD_DOIT) { 1070 /* store name in namespace */ 1071 if (add_key_name(sp, newnp, NULL, ep) != 0) 1072 return (-1); 1073 } 1074 1075 if (rebind && !metaislocalset(sp)) { 1076 /* 1077 * We are 'rebind'ing a disk that is in a diskset so as well 1078 * as updating the diskset's namespace the local set needs 1079 * to be updated because it also contains a reference to the 1080 * disk in question. 1081 */ 1082 ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname, 1083 ep); 1084 1085 if (ret != METADEVADM_SUCCESS) { 1086 md_error_t xep = mdnullerror; 1087 1088 /* 1089 * In dryrun mode (DOIT not set) we must not alter 1090 * the mddb 1091 */ 1092 if (options & MDCMD_DOIT) { 1093 (void) del_key_name(sp, newnp, &xep); 1094 mdclrerror(&xep); 1095 return (-1); 1096 } 1097 } 1098 } 1099 1100 /* replace hotspare */ 1101 (void) memset(&shs, 0, sizeof (shs)); 1102 1103 shs.shs_size_option = meta_check_devicesize(size); 1104 1105 shs.shs_cmd = REPLACE_HOT_SPARE; 1106 shs.shs_hot_spare_pool = hspnp->hsp; 1107 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1108 shs.shs_component_old = old_dev; 1109 shs.shs_options = HS_OPT_NONE; 1110 /* If DOIT is not set, it's a dryrun */ 1111 if ((options & MDCMD_DOIT) == 0) { 1112 shs.shs_options |= HS_OPT_DRYRUN; 1113 } 1114 shs.shs_component_new = new_dev; 1115 shs.shs_start_blk = start_blk; 1116 shs.shs_has_label = ((label > 0) ? 1 : 0); 1117 shs.shs_number_blks = size; 1118 shs.shs_key_new = newnp->key; 1119 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 1120 if (options & MDCMD_DOIT) { 1121 (void) del_key_name(sp, newnp, ep); 1122 } 1123 return (mdstealerror(ep, &shs.mde)); 1124 } 1125 1126 /* clear cache */ 1127 meta_invalidate_name(oldnp); 1128 meta_invalidate_name(newnp); 1129 meta_invalidate_hsp(hspnp); 1130 1131 /* let em know */ 1132 if (options & MDCMD_PRINT) { 1133 (void) printf(dgettext(TEXT_DOMAIN, 1134 "%s: Hotspare %s is replaced with %s\n"), 1135 hspnp->hspname, oldnp->cname, newnp->cname); 1136 (void) fflush(stdout); 1137 } 1138 1139 /* return success */ 1140 return (0); 1141 } 1142 1143 /* 1144 * enable hotspares 1145 */ 1146 int 1147 meta_hs_enable( 1148 mdsetname_t *sp, 1149 mdnamelist_t *hsnlp, 1150 mdcmdopts_t options, 1151 md_error_t *ep 1152 ) 1153 { 1154 mdhspnamelist_t *hspnlp = NULL; 1155 mdhspnamelist_t *hspnp; 1156 set_hs_params_t shs; 1157 int rval = -1; 1158 1159 /* should have a set */ 1160 assert(sp != NULL); 1161 1162 /* setup device info */ 1163 (void) memset(&shs, 0, sizeof (shs)); 1164 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1165 shs.shs_cmd = FIX_HOT_SPARE; 1166 shs.shs_options = HS_OPT_NONE; 1167 /* If DOIT is not set, it's a dryrun */ 1168 if ((options & MDCMD_DOIT) == 0) { 1169 shs.shs_options |= HS_OPT_DRYRUN; 1170 } 1171 1172 /* get the list of hotspare names */ 1173 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 1174 goto out; 1175 1176 /* enable hotspares for each components */ 1177 for (; (hsnlp != NULL); hsnlp = hsnlp->next) { 1178 mdname_t *hsnp = hsnlp->namep; 1179 md_dev64_t fs_dev; 1180 int rebind = 0; 1181 diskaddr_t size, label, start_blk; 1182 1183 /* get the file_system dev binding */ 1184 if (meta_getdev(sp, hsnp, ep) != 0) 1185 return (-1); 1186 fs_dev = hsnp->dev; 1187 1188 /* 1189 * search for the component in each hotspare pool 1190 * and replace it (instead of enable) if the binding 1191 * has changed. 1192 */ 1193 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) { 1194 /* 1195 * in_hsp will call meta_get_hsp which will fill 1196 * in hspnp with metadb version of component 1197 */ 1198 meta_invalidate_hsp(hspnp->hspnamep); 1199 if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) { 1200 /* 1201 * check for the case where the dev_t has 1202 * changed between the filesystem and the 1203 * metadb. This is called a rebind, and 1204 * is handled by meta_hs_replace. 1205 */ 1206 if (fs_dev != hsnp->dev) { 1207 /* 1208 * establish file system binding 1209 * with invalid start/end 1210 */ 1211 rebind++; 1212 hsnp->dev = fs_dev; 1213 hsnp->start_blk = -1; 1214 hsnp->end_blk = -1; 1215 rval = meta_hs_replace(sp, 1216 hspnp->hspnamep, 1217 hsnp, hsnp, options, ep); 1218 if (rval != 0) 1219 goto out; 1220 } 1221 } 1222 } 1223 if (rebind) 1224 continue; 1225 1226 /* enable the component in all hotspares that use it */ 1227 if (meta_check_hotspare(sp, hsnp, ep) != 0) 1228 goto out; 1229 1230 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) 1231 goto out; 1232 if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR) 1233 goto out; 1234 if ((start_blk = metagetstart(sp, hsnp, ep)) 1235 == MD_DISKADDR_ERROR) 1236 goto out; 1237 if (start_blk >= size) { 1238 (void) mdsyserror(ep, ENOSPC, hsnp->cname); 1239 goto out; 1240 } 1241 1242 /* enable hotspare */ 1243 shs.shs_component_old = hsnp->dev; 1244 shs.shs_component_new = hsnp->dev; 1245 shs.shs_start_blk = start_blk; 1246 shs.shs_has_label = ((label > 0) ? 1 : 0); 1247 shs.shs_number_blks = size; 1248 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) { 1249 rval = mdstealerror(ep, &shs.mde); 1250 goto out; 1251 } 1252 1253 /* 1254 * Are we dealing with a non-local set? If so need to update 1255 * the local namespace so that the disk record has the correct 1256 * devid. 1257 */ 1258 if (!metaislocalset(sp)) { 1259 rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, 1260 hsnp->cname, ep); 1261 1262 if (rval != METADEVADM_SUCCESS) { 1263 /* 1264 * Failed to update the local set. Nothing to 1265 * do here apart from report the error. The 1266 * namespace is most likely broken and some 1267 * form of remedial recovery is going to 1268 * be required. 1269 */ 1270 mde_perror(ep, ""); 1271 mdclrerror(ep); 1272 } 1273 } 1274 1275 /* clear cache */ 1276 meta_invalidate_name(hsnp); 1277 1278 /* let em know */ 1279 if (options & MDCMD_PRINT) { 1280 (void) printf(dgettext(TEXT_DOMAIN, 1281 "hotspare %s is enabled\n"), 1282 hsnp->cname); 1283 (void) fflush(stdout); 1284 } 1285 } 1286 1287 /* clear whole cache */ 1288 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) { 1289 meta_invalidate_hsp(hspnp->hspnamep); 1290 } 1291 1292 1293 /* return success */ 1294 rval = 0; 1295 1296 out: 1297 if (hspnlp) 1298 metafreehspnamelist(hspnlp); 1299 return (rval); 1300 } 1301 1302 /* 1303 * check for dups in the hsp itself 1304 */ 1305 static int 1306 check_twice( 1307 md_hsp_t *hspp, 1308 uint_t hsi, 1309 md_error_t *ep 1310 ) 1311 { 1312 mdhspname_t *hspnp = hspp->hspnamep; 1313 mdname_t *thisnp; 1314 uint_t h; 1315 1316 thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep; 1317 for (h = 0; (h < hsi); ++h) { 1318 md_hs_t *hsp = &hspp->hotspares.hotspares_val[h]; 1319 mdname_t *hsnp = hsp->hsnamep; 1320 1321 if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1, 1322 hsnp, 0, -1, ep) != 0) 1323 return (-1); 1324 } 1325 return (0); 1326 } 1327 1328 /* 1329 * check hsp 1330 */ 1331 /*ARGSUSED2*/ 1332 int 1333 meta_check_hsp( 1334 mdsetname_t *sp, 1335 md_hsp_t *hspp, 1336 mdcmdopts_t options, 1337 md_error_t *ep 1338 ) 1339 { 1340 mdhspname_t *hspnp = hspp->hspnamep; 1341 uint_t hsi; 1342 1343 /* check hotspares */ 1344 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 1345 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1346 mdname_t *hsnp = hsp->hsnamep; 1347 diskaddr_t size; 1348 1349 /* check hotspare */ 1350 if (meta_check_hotspare(sp, hsnp, ep) != 0) 1351 return (-1); 1352 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) { 1353 return (-1); 1354 } else if (size == 0) { 1355 return (mdsyserror(ep, ENOSPC, hspnp->hspname)); 1356 } 1357 1358 /* check this hsp too */ 1359 if (check_twice(hspp, hsi, ep) != 0) 1360 return (-1); 1361 } 1362 1363 /* return success */ 1364 return (0); 1365 } 1366 1367 /* 1368 * create hsp 1369 */ 1370 int 1371 meta_create_hsp( 1372 mdsetname_t *sp, 1373 md_hsp_t *hspp, 1374 mdcmdopts_t options, 1375 md_error_t *ep 1376 ) 1377 { 1378 mdhspname_t *hspnp = hspp->hspnamep; 1379 mdnamelist_t *hsnlp = NULL; 1380 uint_t hsi; 1381 int rval = -1; 1382 1383 /* validate hsp */ 1384 if (meta_check_hsp(sp, hspp, options, ep) != 0) 1385 return (-1); 1386 1387 /* if we're not doing anything, return success */ 1388 if (! (options & MDCMD_DOIT)) 1389 return (0); 1390 1391 /* create hsp */ 1392 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 1393 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1394 mdname_t *hsnp = hsp->hsnamep; 1395 1396 (void) metanamelist_append(&hsnlp, hsnp); 1397 } 1398 options |= MDCMD_INIT; 1399 rval = meta_hs_add(sp, hspnp, hsnlp, options, ep); 1400 1401 /* cleanup, return success */ 1402 metafreenamelist(hsnlp); 1403 return (rval); 1404 } 1405 1406 /* 1407 * initialize hsp 1408 * NOTE: this functions is metainit(1m)'s command line parser! 1409 */ 1410 int 1411 meta_init_hsp( 1412 mdsetname_t **spp, 1413 int argc, 1414 char *argv[], 1415 mdcmdopts_t options, 1416 md_error_t *ep 1417 ) 1418 { 1419 char *uname = argv[0]; 1420 mdhspname_t *hspnp = NULL; 1421 md_hsp_t *hspp = NULL; 1422 uint_t hsi; 1423 int rval = -1; 1424 1425 1426 /* get hsp name */ 1427 assert(argc > 0); 1428 if (argc < 1) 1429 goto syntax; 1430 if ((hspnp = metahspname(spp, uname, ep)) == NULL) 1431 goto out; 1432 assert(*spp != NULL); 1433 uname = hspnp->hspname; 1434 1435 if (!(options & MDCMD_NOLOCK)) { 1436 /* grab set lock */ 1437 if (meta_lock(*spp, TRUE, ep)) 1438 goto out; 1439 1440 if (meta_check_ownership(*spp, ep) != 0) 1441 goto out; 1442 } 1443 1444 /* see if it exists already */ 1445 if (meta_get_hsp(*spp, hspnp, ep) != NULL) { 1446 (void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP, hspnp->hsp, uname); 1447 goto out; 1448 } else if (! mdishsperror(ep, MDE_INVAL_HSP)) { 1449 goto out; 1450 } else { 1451 mdclrerror(ep); 1452 } 1453 --argc, ++argv; 1454 1455 /* parse general options */ 1456 optind = 0; 1457 opterr = 0; 1458 if (getopt(argc, argv, "") != -1) 1459 goto options; 1460 1461 /* allocate hsp */ 1462 hspp = Zalloc(sizeof (*hspp)); 1463 hspp->hotspares.hotspares_len = argc; 1464 if (argc > 0) { 1465 hspp->hotspares.hotspares_val = 1466 Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val)); 1467 } 1468 1469 /* setup pool */ 1470 hspp->hspnamep = hspnp; 1471 1472 /* parse hotspares */ 1473 for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len)); 1474 ++hsi) { 1475 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi]; 1476 mdname_t *hsnamep; 1477 1478 /* parse hotspare name */ 1479 if ((hsnamep = metaname(spp, argv[0], ep)) == NULL) 1480 goto out; 1481 hsp->hsnamep = hsnamep; 1482 --argc, ++argv; 1483 } 1484 1485 /* we should be at the end */ 1486 if (argc != 0) 1487 goto syntax; 1488 1489 /* create hotspare pool */ 1490 if (meta_create_hsp(*spp, hspp, options, ep) != 0) 1491 goto out; 1492 rval = 0; /* success */ 1493 goto out; 1494 1495 /* syntax error */ 1496 syntax: 1497 rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv); 1498 goto out; 1499 1500 /* options error */ 1501 options: 1502 rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv); 1503 goto out; 1504 1505 /* cleanup, return error */ 1506 out: 1507 if (hspp != NULL) 1508 meta_free_hsp(hspp); 1509 return (rval); 1510 } 1511 1512 /* 1513 * reset hotspare pool 1514 */ 1515 int 1516 meta_hsp_reset( 1517 mdsetname_t *sp, 1518 mdhspname_t *hspnp, 1519 mdcmdopts_t options, 1520 md_error_t *ep 1521 ) 1522 { 1523 md_hsp_t *hspp; 1524 set_hs_params_t shs; 1525 uint_t i; 1526 int rval = -1; 1527 1528 /* should have the same set */ 1529 assert(sp != NULL); 1530 assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp))); 1531 1532 /* reset all hotspares */ 1533 if (hspnp == NULL) { 1534 mdhspnamelist_t *hspnlp = NULL; 1535 mdhspnamelist_t *p; 1536 1537 /* for each hotspare pool */ 1538 rval = 0; 1539 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0) 1540 return (-1); 1541 for (p = hspnlp; (p != NULL); p = p->next) { 1542 /* reset hotspare pool */ 1543 hspnp = p->hspnamep; 1544 1545 /* 1546 * If this is a multi-node set, we send a series 1547 * of individual metaclear commands. 1548 */ 1549 if (meta_is_mn_set(sp, ep)) { 1550 if (meta_mn_send_metaclear_command(sp, 1551 hspnp->hspname, options, 0, ep) != 0) { 1552 rval = -1; 1553 break; 1554 } 1555 } else { 1556 if (meta_hsp_reset(sp, hspnp, options, 1557 ep) != 0) { 1558 rval = -1; 1559 break; 1560 } 1561 } 1562 } 1563 1564 /* cleanup, return success */ 1565 metafreehspnamelist(hspnlp); 1566 return (rval); 1567 } 1568 1569 /* get unit structure */ 1570 if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL) 1571 return (-1); 1572 1573 /* make sure nobody owns us */ 1574 if (hspp->refcount > 0) { 1575 return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp, 1576 hspnp->hspname)); 1577 } 1578 1579 /* clear hotspare pool members */ 1580 (void) memset(&shs, 0, sizeof (shs)); 1581 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno); 1582 shs.shs_cmd = DELETE_HOT_SPARE; 1583 shs.shs_hot_spare_pool = hspnp->hsp; 1584 for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) { 1585 md_hs_t *hs = &hspp->hotspares.hotspares_val[i]; 1586 mdname_t *hsnamep = hs->hsnamep; 1587 1588 /* clear cache */ 1589 meta_invalidate_name(hsnamep); 1590 1591 /* clear hotspare */ 1592 shs.shs_component_old = hsnamep->dev; 1593 shs.shs_options = HS_OPT_FORCE; 1594 /* If DOIT is not set, it's a dryrun */ 1595 if ((options & MDCMD_DOIT) == 0) { 1596 shs.shs_options |= HS_OPT_DRYRUN; 1597 } 1598 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) { 1599 (void) mdstealerror(ep, &shs.mde); 1600 goto out; 1601 } 1602 } 1603 1604 /* clear hotspare pool */ 1605 shs.shs_options = HS_OPT_POOL; 1606 /* If DOIT is not set, it's a dryrun */ 1607 if ((options & MDCMD_DOIT) == 0) { 1608 shs.shs_options |= HS_OPT_DRYRUN; 1609 } 1610 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hspnp->hspname) != 0) { 1611 (void) mdstealerror(ep, &shs.mde); 1612 goto out; 1613 } 1614 rval = 0; /* success */ 1615 1616 /* let em know */ 1617 if (options & MDCMD_PRINT) { 1618 (void) printf(dgettext(TEXT_DOMAIN, 1619 "%s: Hotspare pool is cleared\n"), 1620 hspnp->hspname); 1621 (void) fflush(stdout); 1622 } 1623 1624 /* clear subdevices (nothing to do) */ 1625 1626 /* cleanup, return success */ 1627 out: 1628 meta_invalidate_hsp(hspnp); 1629 return (rval); 1630 } 1631