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