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