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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright (c) 2016 by Delphix. All rights reserved. 25 */ 26 27 /* 28 * This file contains functions to implement the defect menu commands. 29 */ 30 #include "global.h" 31 #include <unistd.h> 32 #include <string.h> 33 #include "misc.h" 34 #include "menu_defect.h" 35 #include "param.h" 36 #include "ctlr_scsi.h" 37 38 /* 39 * This is the working defect list. All the commands here operate on 40 * the working list, except for 'commit'. This way the user can 41 * change their mind at any time without having mangled the current defect 42 * list. 43 */ 44 struct defect_list work_list; 45 46 static int commit_list(void); 47 48 /* 49 * This routine implements the 'restore' command. It sets the working 50 * list equal to the current list. 51 */ 52 int 53 d_restore(void) 54 { 55 int i; 56 57 assert(!EMBEDDED_SCSI); 58 59 /* 60 * If the working list has not been modified, there's nothing to do. 61 */ 62 if (!(work_list.flags & LIST_DIRTY)) { 63 err_print("working list was not modified.\n"); 64 return (0); 65 } 66 /* 67 * Make sure the user is serious. 68 */ 69 if (check("Ready to update working list, continue")) 70 return (-1); 71 /* 72 * Lock out interrupts so the lists can't get mangled. 73 */ 74 enter_critical(); 75 /* 76 * Kill off the old working list. 77 */ 78 kill_deflist(&work_list); 79 /* 80 * If the current isn't null, set the working list to be a 81 * copy of it. 82 */ 83 if (cur_list.list != NULL) { 84 work_list.header = cur_list.header; 85 work_list.list = (struct defect_entry *)zalloc( 86 deflist_size(cur_blksz, work_list.header.count) * 87 cur_blksz); 88 for (i = 0; i < work_list.header.count; i++) 89 *(work_list.list + i) = *(cur_list.list + i); 90 } 91 /* 92 * Initialize the flags since they are now in sync. 93 */ 94 work_list.flags = 0; 95 if (work_list.list == NULL) 96 fmt_print("working list set to null.\n\n"); 97 else 98 fmt_print("working list updated, total of %d defects.\n\n", 99 work_list.header.count); 100 exit_critical(); 101 return (0); 102 } 103 104 /* 105 * This routine implements the 'original' command. It extracts the 106 * manufacturer's defect list from the current disk. 107 */ 108 int 109 d_original(void) 110 { 111 int status; 112 113 114 /* 115 * If the controller does not support the extraction, we're out 116 * of luck. 117 */ 118 if (cur_ops->op_ex_man == NULL) { 119 err_print("Controller does not support extracting "); 120 err_print("manufacturer's defect list.\n"); 121 return (-1); 122 } 123 /* 124 * Make sure the user is serious. Note, for SCSI disks 125 * since this is instantaneous, we will just do it and 126 * not ask for confirmation. 127 */ 128 if (!(cur_ctype->ctype_flags & CF_CONFIRM) && 129 check( 130 "Ready to update working list. This cannot be interrupted\n\ 131 and may take a long while. Continue")) 132 return (-1); 133 /* 134 * Lock out interrupts so we don't get half the list. 135 */ 136 enter_critical(); 137 /* 138 * Kill off the working list. 139 */ 140 kill_deflist(&work_list); 141 fmt_print("Extracting manufacturer's defect list..."); 142 /* 143 * Do the extraction. 144 */ 145 status = (*cur_ops->op_ex_man)(&work_list); 146 if (status) 147 fmt_print("Extraction failed.\n\n"); 148 else { 149 fmt_print("Extraction complete.\n"); 150 fmt_print("Working list updated, total of %d defects.\n\n", 151 work_list.header.count); 152 } 153 /* 154 * Mark the working list dirty since we modified it. 155 */ 156 work_list.flags |= LIST_DIRTY; 157 exit_critical(); 158 /* 159 * Return status. 160 */ 161 return (status); 162 } 163 164 /* 165 * This routine implements the 'extract' command. It extracts the 166 * entire defect list from the current disk. 167 */ 168 int 169 d_extract(void) 170 { 171 int status; 172 173 /* 174 * If the controller does not support the extraction, we are out 175 * of luck. 176 */ 177 if (cur_ops->op_ex_cur == NULL) { 178 err_print("Controller does not support extracting "); 179 err_print("current defect list.\n"); 180 return (-1); 181 } 182 183 /* 184 * If disk is unformatted, you really shouldn't do this. 185 * However, ask user to be sure. 186 */ 187 if (! (cur_flags & DISK_FORMATTED) && 188 (check( 189 "Cannot extract defect list from an unformatted disk. Continue"))) 190 return (-1); 191 192 /* 193 * If this takes a long time, let's ask the user if they 194 * doesn't mind waiting. Note, for SCSI disks 195 * this operation is instantaneous so we won't ask for 196 * for confirmation. 197 */ 198 if (! (cur_ctype->ctype_flags & CF_CONFIRM) && 199 check( 200 "Ready to extract working list. This cannot be interrupted\n\ 201 and may take a long while. Continue")) 202 return (-1); 203 /* 204 * Lock out interrupts so we don't get half the list and 205 * Kill off the working list. 206 */ 207 enter_critical(); 208 kill_deflist(&work_list); 209 fmt_print("Extracting defect list..."); 210 211 /* 212 * Do the extraction. 213 */ 214 status = (*cur_ops->op_ex_cur)(&work_list); 215 if (status) { 216 if (!EMBEDDED_SCSI) { 217 if (cur_flags & DISK_FORMATTED) 218 read_list(&work_list); 219 220 if (work_list.list != NULL) { 221 status = 0; 222 fmt_print("Extraction complete.\n"); 223 fmt_print( 224 "Working list updated, total of %d defects.\n\n", 225 work_list.header.count); 226 } else { 227 fmt_print("Extraction failed.\n\n"); 228 } 229 } else { 230 fmt_print("Extraction failed.\n\n"); 231 } 232 } else { 233 fmt_print("Extraction complete.\n"); 234 fmt_print("Working list updated, total of %d defects.\n\n", 235 work_list.header.count); 236 } 237 /* 238 * Mark the working list dirty since we modified it. 239 */ 240 work_list.flags |= LIST_DIRTY; 241 exit_critical(); 242 /* 243 * Return status. 244 */ 245 return (status); 246 } 247 248 /* 249 * This routine implements the 'add' command. It allows the user to 250 * enter the working defect list manually. It loops infinitely until 251 * the user breaks out with a ctrl-C. 252 */ 253 int 254 d_add(void) 255 { 256 int type, deflt, index; 257 diskaddr_t bn; 258 u_ioparam_t ioparam; 259 struct defect_entry def; 260 261 assert(!EMBEDDED_SCSI); 262 263 /* 264 * Ask the user which mode of input they'd like to use. 265 */ 266 fmt_print(" 0. bytes-from-index\n"); 267 fmt_print(" 1. logical block\n"); 268 deflt = 0; 269 ioparam.io_bounds.lower = 0; 270 ioparam.io_bounds.upper = 1; 271 type = input(FIO_INT, "Select input format (enter its number)", ':', 272 &ioparam, &deflt, DATA_INPUT); 273 fmt_print("\nEnter Control-C to terminate.\n"); 274 loop: 275 if (type) { 276 /* 277 * Mode selected is logical block. Input the defective block 278 * and fill in the defect entry with the info. 279 */ 280 def.bfi = def.nbits = UNKNOWN; 281 ioparam.io_bounds.lower = 0; 282 if (cur_disk->label_type == L_TYPE_SOLARIS) { 283 ioparam.io_bounds.upper = physsects() - 1; 284 } else { 285 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_lba; 286 } 287 bn = input(FIO_BN, "Enter defective block number", ':', 288 &ioparam, NULL, DATA_INPUT); 289 def.cyl = bn2c(bn); 290 def.head = bn2h(bn); 291 def.sect = bn2s(bn); 292 } else { 293 /* 294 * Mode selected is bytes-from-index. Input the information 295 * about the defect and fill in the defect entry. 296 */ 297 def.sect = UNKNOWN; 298 ioparam.io_bounds.lower = 0; 299 ioparam.io_bounds.upper = pcyl - 1; 300 def.cyl = input(FIO_INT, 301 "Enter defect's cylinder number", ':', 302 &ioparam, NULL, DATA_INPUT); 303 ioparam.io_bounds.upper = nhead - 1; 304 def.head = input(FIO_INT, "Enter defect's head number", 305 ':', &ioparam, NULL, DATA_INPUT); 306 ioparam.io_bounds.upper = cur_dtype->dtype_bpt - 1; 307 def.bfi = input(FIO_INT, "Enter defect's bytes-from-index", 308 ':', &ioparam, NULL, DATA_INPUT); 309 ioparam.io_bounds.lower = -1; 310 ioparam.io_bounds.upper = (cur_dtype->dtype_bpt - def.bfi) * 8; 311 if (ioparam.io_bounds.upper >= 32 * 1024) 312 ioparam.io_bounds.upper = 32 * 1024 - 1; 313 /* 314 * Note: a length of -1 means the length is not known. We 315 * make this the default value. 316 */ 317 deflt = -1; 318 def.nbits = input(FIO_INT, "Enter defect's length (in bits)", 319 ':', &ioparam, &deflt, DATA_INPUT); 320 } 321 /* 322 * Calculate where in the defect list this defect belongs 323 * and print it out. 324 */ 325 index = sort_defect(&def, &work_list); 326 fmt_print(DEF_PRINTHEADER); 327 pr_defect(&def, index); 328 329 /* 330 * Lock out interrupts so lists don't get mangled. 331 * Also, mark the working list dirty since we are modifying it. 332 */ 333 enter_critical(); 334 work_list.flags |= LIST_DIRTY; 335 /* 336 * If the list is null, create it with zero length. This is 337 * necessary because the routines to add a defect to the list 338 * assume the list is initialized. 339 */ 340 if (work_list.list == NULL) { 341 work_list.header.magicno = (uint_t)DEFECT_MAGIC; 342 work_list.header.count = 0; 343 work_list.list = (struct defect_entry *)zalloc( 344 deflist_size(cur_blksz, 0) * cur_blksz); 345 } 346 /* 347 * Add the defect to the working list. 348 */ 349 add_def(&def, &work_list, index); 350 fmt_print("defect number %d added.\n\n", index + 1); 351 exit_critical(); 352 /* 353 * Loop back for the next defect. 354 */ 355 goto loop; 356 /*NOTREACHED*/ 357 #ifdef lint 358 return (0); 359 #endif 360 } 361 362 /* 363 * This routine implements the 'delete' command. It allows the user 364 * to manually delete a defect from the working list. 365 */ 366 int 367 d_delete(void) 368 { 369 int i, count, num; 370 u_ioparam_t ioparam; 371 372 assert(!EMBEDDED_SCSI); 373 374 /* 375 * If the working list is null or zero length, there's nothing 376 * to delete. 377 */ 378 count = work_list.header.count; 379 if (work_list.list == NULL || count == 0) { 380 err_print("No defects to delete.\n"); 381 return (-1); 382 } 383 /* 384 * Ask the user which defect should be deleted. Bounds are off by 385 * one because user sees a one-relative list. 386 */ 387 ioparam.io_bounds.lower = 1; 388 ioparam.io_bounds.upper = count; 389 num = input(FIO_INT, "Specify defect to be deleted (enter its number)", 390 ':', &ioparam, NULL, DATA_INPUT); 391 /* 392 * 393 * The user thinks it's one relative but it's not really. 394 */ 395 --num; 396 /* 397 * Print the defect selected and ask the user for confirmation. 398 */ 399 fmt_print(DEF_PRINTHEADER); 400 pr_defect(work_list.list + num, num); 401 /* 402 * Lock out interrupts so the lists don't get mangled. 403 */ 404 enter_critical(); 405 /* 406 * Move down all the defects beyond the one deleted so the defect 407 * list is still fully populated. 408 */ 409 for (i = num; i < count - 1; i++) 410 *(work_list.list + i) = *(work_list.list + i + 1); 411 /* 412 * If the size of the list in sectors has changed, reallocate 413 * the list to shrink it appropriately. 414 */ 415 if (deflist_size(cur_blksz, count - 1) < 416 deflist_size(cur_blksz, count)) 417 work_list.list = (struct defect_entry *)rezalloc( 418 (void *)work_list.list, 419 deflist_size(cur_blksz, count - 1) * cur_blksz); 420 /* 421 * Decrement the defect count. 422 */ 423 work_list.header.count--; 424 /* 425 * Recalculate the list's checksum. 426 */ 427 (void) checkdefsum(&work_list, CK_MAKESUM); 428 /* 429 * Mark the working list dirty since we modified it. 430 */ 431 work_list.flags |= LIST_DIRTY; 432 fmt_print("defect number %d deleted.\n\n", ++num); 433 exit_critical(); 434 return (0); 435 } 436 437 /* 438 * This routine implements the 'print' command. It prints the working 439 * defect list out in human-readable format. 440 */ 441 int 442 d_print(void) 443 { 444 int i, nomore = 0; 445 int c, one_line = 0; 446 int tty_lines = get_tty_lines(); 447 448 /* 449 * If the working list is null, there's nothing to print. 450 */ 451 if (work_list.list == NULL) { 452 if (EMBEDDED_SCSI) 453 err_print( 454 "No list defined,extract primary or grown or both defects list first.\n"); 455 else 456 err_print("No working list defined.\n"); 457 return (-1); 458 } 459 /* 460 * If we're running from a file, don't use the paging scheme. 461 * If we are running interactive, turn off echoing. 462 */ 463 if (option_f || (!isatty(0)) || (!isatty(1))) 464 nomore++; 465 else { 466 enter_critical(); 467 echo_off(); 468 charmode_on(); 469 exit_critical(); 470 } 471 /* Print out the banner. */ 472 if (work_list.header.count != 0) 473 fmt_print(DEF_PRINTHEADER); 474 475 /* 476 * Loop through the each defect in the working list. 477 */ 478 for (i = 0; i < work_list.header.count; i++) { 479 /* 480 * If we are paging and hit the end of a page, wait for 481 * the user to hit either space-bar, "q", or return 482 * before going on. 483 */ 484 if (one_line || 485 (!nomore && ((i + 1) % (tty_lines - 1) == 0))) { 486 /* 487 * Get the next character. 488 */ 489 fmt_print("- hit space for more - "); 490 c = getchar(); 491 fmt_print("\015"); 492 one_line = 0; 493 /* Handle display one line command (return key) */ 494 if (c == '\012') { 495 one_line++; 496 } 497 /* Handle Quit command */ 498 if (c == 'q') { 499 fmt_print(" \015"); 500 goto PRINT_EXIT; 501 } 502 /* Handle ^D */ 503 if (c == '\004') 504 fullabort(); 505 } 506 /* 507 * Print the defect. 508 */ 509 pr_defect(work_list.list + i, i); 510 } 511 fmt_print("total of %d defects.\n\n", i); 512 /* 513 * If we were doing paging, turn echoing back on. 514 */ 515 PRINT_EXIT: 516 if (!nomore) { 517 enter_critical(); 518 charmode_off(); 519 echo_on(); 520 exit_critical(); 521 } 522 return (0); 523 } 524 525 /* 526 * This routine implements the 'dump' command. It writes the working 527 * defect list to a file. 528 */ 529 int 530 d_dump(void) 531 { 532 int i, status = 0; 533 char *str; 534 FILE *fptr; 535 struct defect_entry *dptr; 536 537 /* 538 * If the working list is null, there's nothing to do. 539 */ 540 if (work_list.list == NULL) { 541 if (EMBEDDED_SCSI) 542 err_print( 543 "No list defined,extract primary or grown or both defects list first.\n"); 544 else 545 err_print("No working list defined.\n"); 546 return (-1); 547 } 548 /* 549 * Ask the user for the name of the defect file. Note that the 550 * input will be in malloc'd space since we are inputting 551 * type OSTR. 552 */ 553 str = (char *)(uintptr_t)input(FIO_OSTR, "Enter name of defect file", 554 ':', NULL, NULL, DATA_INPUT); 555 /* 556 * Lock out interrupts so the file doesn't get half written. 557 */ 558 enter_critical(); 559 /* 560 * Open the file for writing. 561 */ 562 if ((fptr = fopen(str, "w+")) == NULL) { 563 err_print("unable to open defect file.\n"); 564 status = -1; 565 goto out; 566 } 567 /* 568 * Print a header containing the magic number, count, and checksum. 569 */ 570 (void) fprintf(fptr, "0x%08x%8d 0x%08x\n", 571 work_list.header.magicno, 572 work_list.header.count, work_list.header.cksum); 573 /* 574 * Loop through each defect in the working list. Write the 575 * defect info to the defect file. 576 */ 577 for (i = 0; i < work_list.header.count; i++) { 578 dptr = work_list.list + i; 579 (void) fprintf(fptr, "%4d%8d%7d%8d%8d%8d\n", 580 i+1, dptr->cyl, dptr->head, 581 dptr->bfi, dptr->nbits, dptr->sect); 582 } 583 fmt_print("defect file updated, total of %d defects.\n", i); 584 /* 585 * Close the defect file. 586 */ 587 (void) fclose(fptr); 588 out: 589 /* 590 * Destroy the string used for the file name. 591 */ 592 destroy_data(str); 593 exit_critical(); 594 fmt_print("\n"); 595 return (status); 596 } 597 598 /* 599 * This routine implements the 'load' command. It reads the working 600 * list in from a file. 601 */ 602 int 603 d_load(void) 604 { 605 int i, items, status = 0, count, cksum; 606 uint_t magicno; 607 char *str; 608 TOKEN filename; 609 FILE *fptr; 610 struct defect_entry *dptr; 611 612 assert(!EMBEDDED_SCSI); 613 614 /* 615 * Ask the user for the name of the defect file. Note that the 616 * input will be malloc'd space since we inputted type OSTR. 617 */ 618 str = (char *)(uintptr_t)input(FIO_OSTR, "Enter name of defect file", 619 ':', NULL, NULL, DATA_INPUT); 620 /* 621 * Copy the file name into local space then destroy the string 622 * it came in. This is simply a precaution against later having 623 * to remember to destroy this space. 624 */ 625 enter_critical(); 626 (void) strcpy(filename, str); 627 destroy_data(str); 628 exit_critical(); 629 /* 630 * See if the defect file is accessable. If not, we can't load 631 * from it. We do this here just so we can get out before asking 632 * the user for confirmation. 633 */ 634 status = access(filename, 4); 635 if (status) { 636 err_print("defect file not accessable.\n"); 637 return (-1); 638 } 639 /* 640 * Make sure the user is serious. 641 */ 642 if (check("ready to update working list, continue")) 643 return (-1); 644 /* 645 * Lock out interrupts so the list doesn't get half loaded. 646 */ 647 enter_critical(); 648 /* 649 * Open the defect file. 650 */ 651 if ((fptr = fopen(filename, "r")) == NULL) { 652 err_print("unable to open defect file.\n"); 653 exit_critical(); 654 return (-1); 655 } 656 /* 657 * Scan in the header. 658 */ 659 items = fscanf(fptr, "0x%x%d 0x%x\n", &magicno, 660 &count, (uint_t *)&cksum); 661 /* 662 * If the header is wrong, this isn't a good defect file. 663 */ 664 if (items != 3 || count < 0 || 665 (magicno != (uint_t)DEFECT_MAGIC && 666 magicno != (uint_t)NO_CHECKSUM)) { 667 err_print("Defect file is corrupted.\n"); 668 status = -1; 669 goto out; 670 } 671 /* 672 * Kill off any old defects in the working list. 673 */ 674 kill_deflist(&work_list); 675 /* 676 * Load the working list header with the header info. 677 */ 678 if (magicno == NO_CHECKSUM) 679 work_list.header.magicno = (uint_t)DEFECT_MAGIC; 680 else 681 work_list.header.magicno = magicno; 682 work_list.header.count = count; 683 work_list.header.cksum = cksum; 684 /* 685 * Allocate space for the new list. 686 */ 687 work_list.list = (struct defect_entry *)zalloc( 688 deflist_size(cur_blksz, count) * cur_blksz); 689 /* 690 * Mark the working list dirty since we are modifying it. 691 */ 692 work_list.flags |= LIST_DIRTY; 693 /* 694 * Loop through each defect in the defect file. 695 */ 696 for (i = 0; i < count; i++) { 697 dptr = work_list.list + i; 698 /* 699 * Scan the info into the defect entry. 700 */ 701 items = fscanf(fptr, "%*d%hd%hd%d%hd%hd\n", &dptr->cyl, 702 &dptr->head, &dptr->bfi, &dptr->nbits, &dptr->sect); 703 /* 704 * If it didn't scan right, give up. 705 */ 706 if (items != 5) 707 goto bad; 708 } 709 /* 710 * Check to be sure the checksum from the defect file was correct 711 * unless there wasn't supposed to be a checksum. 712 * If there was supposed to be a valid checksum and there isn't 713 * then give up. 714 */ 715 if (magicno != NO_CHECKSUM && checkdefsum(&work_list, CK_CHECKSUM)) 716 goto bad; 717 fmt_print("working list updated, total of %d defects.\n", i); 718 goto out; 719 720 bad: 721 /* 722 * Some kind of error occurred. Kill off the working list and 723 * mark the status bad. 724 */ 725 err_print("Defect file is corrupted, working list set to NULL.\n"); 726 kill_deflist(&work_list); 727 status = -1; 728 out: 729 /* 730 * Close the defect file. 731 */ 732 (void) fclose(fptr); 733 exit_critical(); 734 fmt_print("\n"); 735 return (status); 736 } 737 738 /* 739 * This routine implements the 'commit' command. It causes the current 740 * defect list to be set equal to the working defect list. It is the only 741 * way that changes made to the working list can actually take effect in 742 * the next format. 743 */ 744 int 745 d_commit(void) 746 { 747 /* 748 * If the working list wasn't modified, no commit is necessary. 749 */ 750 if (work_list.list != NULL && !(work_list.flags & LIST_DIRTY)) { 751 err_print("working list was not modified.\n"); 752 return (0); 753 } 754 755 /* 756 * Make sure the user is serious. 757 */ 758 if (check("Ready to update Current Defect List, continue")) 759 return (-1); 760 return (do_commit()); 761 } 762 763 int 764 do_commit(void) 765 { 766 int status; 767 768 if ((status = commit_list()) == 0) { 769 /* 770 * Remind the user to format the drive, since changing 771 * the list does nothing unless a format is performed. 772 */ 773 fmt_print(\ 774 "Disk must be reformatted for changes to take effect.\n\n"); 775 } 776 return (status); 777 } 778 779 780 static int 781 commit_list(void) 782 { 783 int i; 784 785 /* 786 * Lock out interrupts so the list doesn't get half copied. 787 */ 788 enter_critical(); 789 /* 790 * Kill off any current defect list. 791 */ 792 kill_deflist(&cur_list); 793 /* 794 * If the working list is null, initialize it to zero length. 795 * This is so the user can do a commit on a null list and get 796 * a zero length list. Otherwise there would be no way to get 797 * a zero length list conveniently. 798 */ 799 if (work_list.list == NULL) { 800 work_list.header.magicno = (uint_t)DEFECT_MAGIC; 801 work_list.header.count = 0; 802 work_list.list = (struct defect_entry *)zalloc( 803 deflist_size(cur_blksz, 0) * cur_blksz); 804 } 805 /* 806 * Copy the working list into the current list. 807 */ 808 cur_list.header = work_list.header; 809 cur_list.list = (struct defect_entry *)zalloc( 810 deflist_size(cur_blksz, cur_list.header.count) * cur_blksz); 811 for (i = 0; i < cur_list.header.count; i++) 812 *(cur_list.list + i) = *(work_list.list + i); 813 /* 814 * Mark the working list clean, since it is now the same as the 815 * current list. Note we do not mark the current list dirty, 816 * even though it has been changed. This is because it does 817 * not reflect the state of disk, so we don't want it written 818 * out until a format has been done. The format will mark it 819 * dirty and write it out. 820 */ 821 work_list.flags &= ~(LIST_DIRTY|LIST_RELOAD); 822 cur_list.flags = work_list.flags; 823 if (EMBEDDED_SCSI) 824 fmt_print("Defect List has a total of %d defects.\n", 825 cur_list.header.count); 826 else 827 fmt_print("Current Defect List updated, total of %d defects.\n", 828 cur_list.header.count); 829 exit_critical(); 830 return (0); 831 } 832 833 834 /* 835 * This routine implements the 'create' command. It creates the 836 * manufacturer's defect on the current disk from the defect list 837 */ 838 int 839 d_create(void) 840 { 841 int status; 842 843 assert(!EMBEDDED_SCSI); 844 845 /* 846 * If the controller does not support the extraction, we're out 847 * of luck. 848 */ 849 if (cur_ops->op_create == NULL) { 850 err_print("Controller does not support creating "); 851 err_print("manufacturer's defect list.\n"); 852 return (-1); 853 } 854 /* 855 * Make sure the user is serious. Note, for SCSI disks 856 * since this is instantaneous, we will just do it and 857 * not ask for confirmation. 858 */ 859 if (! (cur_ctype->ctype_flags & CF_SCSI) && 860 check( 861 "Ready to create the manufacturers defect information on the disk.\n\ 862 This cannot be interrupted and may take a long while.\n\ 863 IT WILL DESTROY ALL OF THE DATA ON THE DISK! Continue")) 864 return (-1); 865 /* 866 * Lock out interrupts so we don't get half the list. 867 */ 868 enter_critical(); 869 fmt_print("Creating manufacturer's defect list..."); 870 /* 871 * Do the Creation 872 */ 873 status = (*cur_ops->op_create)(&work_list); 874 if (status) { 875 fmt_print("Creation failed.\n\n"); 876 } else { 877 fmt_print("Creation complete.\n"); 878 } 879 exit_critical(); 880 /* 881 * Return status. 882 */ 883 return (status); 884 } 885 886 887 /* 888 * Extract primary defect list - SCSI only 889 */ 890 int 891 d_primary(void) 892 { 893 int status; 894 895 assert(EMBEDDED_SCSI); 896 897 /* 898 * Lock out interrupts so we don't get half the list and 899 * Kill off the working list. 900 */ 901 enter_critical(); 902 kill_deflist(&work_list); 903 fmt_print("Extracting primary defect list..."); 904 905 /* 906 * Do the extraction. 907 */ 908 status = scsi_ex_man(&work_list); 909 if (status) { 910 fmt_print("Extraction failed.\n\n"); 911 } else { 912 fmt_print("Extraction complete.\n"); 913 /* 914 * Mark the working list dirty since we modified it. 915 * Automatically commit it, for SCSI only. 916 */ 917 work_list.flags |= LIST_DIRTY; 918 status = commit_list(); 919 fmt_print("\n"); 920 } 921 exit_critical(); 922 923 /* 924 * Return status. 925 */ 926 return (status); 927 } 928 929 930 /* 931 * Extract grown defects list - SCSI only 932 */ 933 int 934 d_grown(void) 935 { 936 int status; 937 938 assert(EMBEDDED_SCSI); 939 940 /* 941 * Lock out interrupts so we don't get half the list and 942 * Kill off the working list. 943 */ 944 enter_critical(); 945 kill_deflist(&work_list); 946 fmt_print("Extracting grown defects list..."); 947 948 /* 949 * Do the extraction. 950 */ 951 status = scsi_ex_grown(&work_list); 952 if (status) { 953 fmt_print("Extraction failed.\n\n"); 954 } else { 955 fmt_print("Extraction complete.\n"); 956 /* 957 * Mark the working list dirty since we modified it. 958 * Automatically commit it, for SCSI only. 959 */ 960 work_list.flags |= LIST_DIRTY; 961 status = commit_list(); 962 fmt_print("\n"); 963 } 964 exit_critical(); 965 966 /* 967 * Return status. 968 */ 969 return (status); 970 } 971 972 973 /* 974 * Extract both primary and grown defects list - SCSI only 975 */ 976 int 977 d_both(void) 978 { 979 int status; 980 981 assert(EMBEDDED_SCSI); 982 983 /* 984 * Lock out interrupts so we don't get half the list and 985 * Kill off the working list. 986 */ 987 enter_critical(); 988 kill_deflist(&work_list); 989 fmt_print("Extracting both primary and grown defects lists..."); 990 991 /* 992 * Do the extraction. 993 */ 994 status = scsi_ex_cur(&work_list); 995 if (status) { 996 fmt_print("Extraction failed.\n\n"); 997 } else { 998 fmt_print("Extraction complete.\n"); 999 /* 1000 * Mark the working list dirty since we modified it. 1001 * Automatically commit it, for SCSI only. 1002 */ 1003 work_list.flags |= LIST_DIRTY; 1004 status = commit_list(); 1005 fmt_print("\n"); 1006 } 1007 exit_critical(); 1008 1009 /* 1010 * Return status. 1011 */ 1012 return (status); 1013 } 1014