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