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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file contains functions implementing the analyze menu commands.
33 #include "menu_analyze.h"
39 * This routine implements the 'read' command. It performs surface
40 * analysis by reading the disk. It is ok to run this command on
41 * mounted file systems.
47 * The current disk must be formatted before disk analysis.
49 if (!(cur_flags
& DISK_FORMATTED
)) {
50 err_print("Current Disk is unformatted.\n");
55 "Ready to analyze (won't harm SunOS). This takes a long time, \n"
56 "but is interruptible with CTRL-C. Continue"))
58 return (do_scan(SCAN_VALID
, F_NORMAL
));
62 * This routine implements the 'refresh' command. It performs surface
63 * analysis by reading the disk then writing the same data back to the
64 * disk. It is ok to run this command on file systems, but not while
71 * The current disk must be formatted before disk analysis.
73 if (!(cur_flags
& DISK_FORMATTED
)) {
74 err_print("Current Disk is unformatted.\n");
79 "Ready to analyze (won't harm data). This takes a long time, \n"
80 "but is interruptible with CTRL-C. Continue"))
82 return (do_scan(SCAN_VALID
| SCAN_WRITE
, F_NORMAL
));
86 * This routine implements the 'test' command. It performs surface
87 * analysis by reading the disk, writing then reading a pattern on the disk,
88 * then writing the original data back to the disk.
89 * It is ok to run this command on file systems, but not while they are
96 * The current disk must be formatted before disk analysis.
98 if (!(cur_flags
& DISK_FORMATTED
)) {
99 err_print("Current Disk is unformatted.\n");
104 "Ready to analyze (won't harm data). This takes a long time, \n"
105 "but is interruptible with CTRL-C. Continue"))
107 return (do_scan(SCAN_VALID
| SCAN_PATTERN
| SCAN_WRITE
, F_NORMAL
));
111 * This routine implements the 'write' command. It performs surface
112 * analysis by writing a pattern to the disk then reading it back.
113 * It is not ok to run this command on any data you want to keep.
119 * The current disk must be formatted before disk analysis.
121 if (!(cur_flags
& DISK_FORMATTED
)) {
122 err_print("Current Disk is unformatted.\n");
127 "Ready to analyze (will corrupt data). This takes a long time, \n"
128 "but is interruptible with CTRL-C. Continue"))
130 return (do_scan(SCAN_PATTERN
, F_NORMAL
));
134 * This routine implements the 'compare' command. It performs surface
135 * analysis by writing a pattern to the disk, reading it back, then
136 * checking the data to be sure it's the same.
137 * It is not ok to run this command on any data you want to keep.
143 * The current disk must be formatted before disk analysis.
145 if (!(cur_flags
& DISK_FORMATTED
)) {
146 err_print("Current Disk is unformatted.\n");
151 "Ready to analyze (will corrupt data). This takes a long time, \n"
152 "but is interruptible with CTRL-C. Continue"))
154 return (do_scan(SCAN_PATTERN
| SCAN_COMPARE
, F_NORMAL
));
158 * This routine implements the 'print' command. It displays the data
159 * buffer in hexadecimal. It is only useful for checking the disk for
160 * a specific set of data (by reading it then printing it).
165 int i
, j
, lines
, nomore
= 0;
167 int tty_lines
= get_tty_lines();
170 * If we are running out of command file, don't page the output.
171 * Otherwise we are running with a user. Turn off echoing of
172 * input characters so we can page the output.
174 if (option_f
|| (!isatty(0)) || (!isatty(1)))
183 * Loop through the data buffer.
186 for (i
= 0; i
< scan_size
* cur_blksz
/ sizeof (int); i
+= 6) {
190 for (j
= 0; j
< 6; j
++)
191 if (i
+ j
< scan_size
* cur_blksz
/ sizeof (int))
193 *((int *)((int *)cur_buf
+ i
+ j
)));
198 * If we are paging and hit the end of a page, wait for
199 * the user to hit either space-bar, "q", return,
200 * or ctrl-C before going on.
203 (!nomore
&& (lines
% (tty_lines
- 1) == 0))) {
205 * Print until first screenfull
207 if (lines
< (tty_lines
-1))
210 * Get the next character.
212 (void) printf("- hit space for more - ");
214 (void) printf("\015");
217 * Handle display one line command (return key)
222 /* Handle Quit command */
234 * If we were doing paging, turn echoing back on.
247 * This routine implements the 'setup' command. It allows the user
248 * to program the variables that drive surface analysis. The approach
249 * is to prompt the user for the value of each variable, with the current
250 * value as the default.
260 * Because of the polarity of the yes/no structure (yes is 0),
261 * we have to invert the values for all yes/no questions.
263 deflt
= !scan_entire
;
264 ioparam
.io_charlist
= confirm_list
;
265 scan_entire
= !input(FIO_MSTR
, "Analyze entire disk", '?',
266 &ioparam
, &deflt
, DATA_INPUT
);
268 * If we are not scanning the whole disk, input the bounds of the scan.
271 ioparam
.io_bounds
.lower
= 0;
272 if ((cur_ctype
->ctype_flags
& CF_SCSI
) &&
273 (cur_disk
->label_type
== L_TYPE_SOLARIS
)) {
274 ioparam
.io_bounds
.upper
= datasects() - 1;
275 } else if (cur_disk
->label_type
== L_TYPE_SOLARIS
) {
276 ioparam
.io_bounds
.upper
= physsects() - 1;
277 } else if (cur_disk
->label_type
== L_TYPE_EFI
) {
278 ioparam
.io_bounds
.upper
= cur_parts
->etoc
->efi_last_lba
;
281 scan_lower
= (diskaddr_t
)input(FIO_BN
,
282 "Enter starting block number", ':',
283 &ioparam
, (int *)&scan_lower
, DATA_INPUT
);
284 ioparam
.io_bounds
.lower
= scan_lower
;
285 if (scan_upper
< scan_lower
)
286 scan_upper
= scan_lower
;
287 scan_upper
= (diskaddr_t
)input(FIO_BN
,
288 "Enter ending block number", ':',
289 &ioparam
, (int *)&scan_upper
, DATA_INPUT
);
292 ioparam
.io_charlist
= confirm_list
;
293 scan_loop
= !input(FIO_MSTR
, "Loop continuously", '?',
294 &ioparam
, &deflt
, DATA_INPUT
);
296 * If we are not looping continuously, input the number of passes.
299 ioparam
.io_bounds
.lower
= 1;
300 ioparam
.io_bounds
.upper
= 100;
301 scan_passes
= input(FIO_INT
, "Enter number of passes", ':',
302 &ioparam
, &scan_passes
, DATA_INPUT
);
304 deflt
= !scan_correct
;
305 ioparam
.io_charlist
= confirm_list
;
306 scan_correct
= !input(FIO_MSTR
, "Repair defective blocks", '?',
307 &ioparam
, &deflt
, DATA_INPUT
);
309 ioparam
.io_charlist
= confirm_list
;
310 scan_stop
= !input(FIO_MSTR
, "Stop after first error", '?',
311 &ioparam
, &deflt
, DATA_INPUT
);
312 deflt
= !scan_random
;
313 ioparam
.io_charlist
= confirm_list
;
314 scan_random
= !input(FIO_MSTR
, "Use random bit patterns", '?',
315 &ioparam
, &deflt
, DATA_INPUT
);
316 ioparam
.io_bounds
.lower
= 1;
318 * The number of blocks per transfer is limited by the buffer
319 * size, or the scan boundaries, whichever is smaller.
321 if ((scan_entire
) && (cur_disk
->label_type
== L_TYPE_SOLARIS
)) {
322 size
= physsects() - 1;
323 } else if ((scan_entire
) && (cur_disk
->label_type
== L_TYPE_EFI
)) {
324 size
= cur_parts
->etoc
->efi_last_lba
;
326 size
= scan_upper
- scan_lower
+ 1;
328 ioparam
.io_bounds
.upper
= min(size
, BUF_SECTS
);
329 if (scan_size
> ioparam
.io_bounds
.upper
)
330 scan_size
= ioparam
.io_bounds
.upper
;
331 scan_size
= input(FIO_INT
, "Enter number of blocks per transfer", ':',
332 &ioparam
, (int *)&scan_size
, DATA_INPUT
);
334 ioparam
.io_charlist
= confirm_list
;
335 scan_auto
= !input(FIO_MSTR
, "Verify media after formatting", '?',
336 &ioparam
, &deflt
, DATA_INPUT
);
339 ioparam
.io_charlist
= confirm_list
;
340 option_msg
= !input(FIO_MSTR
, "Enable extended messages", '?',
341 &ioparam
, &deflt
, DATA_INPUT
);
342 deflt
= !scan_restore_defects
;
343 ioparam
.io_charlist
= confirm_list
;
344 scan_restore_defects
= !input(FIO_MSTR
, "Restore defect list", '?',
345 &ioparam
, &deflt
, DATA_INPUT
);
346 deflt
= !scan_restore_label
;
347 ioparam
.io_charlist
= confirm_list
;
348 scan_restore_label
= !input(FIO_MSTR
, "Restore disk label", '?',
349 &ioparam
, &deflt
, DATA_INPUT
);
355 * This routine implements the 'config' command. It simply prints out
356 * the values of all the variables controlling surface analysis. It
357 * is meant to complement the 'setup' command by allowing the user to
358 * check the current setup.
364 fmt_print(" Analyze entire disk? ");
365 fmt_print(scan_entire
? "yes\n" : "no\n");
368 fmt_print(" Starting block number: %llu (", scan_lower
);
369 pr_dblock(fmt_print
, scan_lower
);
370 fmt_print(")\n Ending block number: %llu (", scan_upper
);
371 pr_dblock(fmt_print
, scan_upper
);
374 fmt_print(" Loop continuously? ");
375 fmt_print(scan_loop
? "yes\n" : "no\n");
378 fmt_print(" Number of passes: %d\n", scan_passes
);
381 fmt_print(" Repair defective blocks? ");
382 fmt_print(scan_correct
? "yes\n" : "no\n");
384 fmt_print(" Stop after first error? ");
385 fmt_print(scan_stop
? "yes\n" : "no\n");
387 fmt_print(" Use random bit patterns? ");
388 fmt_print(scan_random
? "yes\n" : "no\n");
390 fmt_print(" Number of blocks per transfer: %d (", scan_size
);
391 pr_dblock(fmt_print
, (diskaddr_t
)scan_size
);
394 fmt_print(" Verify media after formatting? ");
395 fmt_print(scan_auto
? "yes\n" : "no\n");
397 fmt_print(" Enable extended messages? ");
398 fmt_print(option_msg
? "yes\n" : "no\n");
400 fmt_print(" Restore defect list? ");
401 fmt_print(scan_restore_defects
? "yes\n" : "no\n");
403 fmt_print(" Restore disk label? ");
404 fmt_print(scan_restore_label
? "yes\n" : "no\n");
411 * This routine implements the 'purge' command. It purges the disk
412 * by writing three patterns to the disk then reading the last one back.
413 * It is not ok to run this command on any data you want to keep.
421 * The current disk must be formatted before disk analysis.
423 if (!(cur_flags
& DISK_FORMATTED
)) {
424 err_print("Current Disk is unformatted.\n");
428 fmt_print("The purge command does not write random data\n");
432 if (!scan_loop
&& (scan_passes
<= NPPATTERNS
)) {
433 if (scan_passes
< NPPATTERNS
) {
434 fmt_print("The purge command runs for a minimum of ");
435 fmt_print("%d passes plus a last pass if the\n",
437 fmt_print("first %d passes were successful.\n",
440 scan_passes
= NPPATTERNS
+ 1;
444 "Ready to purge (will corrupt data). This takes a long time, \n"
445 "but is interruptible with CTRL-C. Continue"))
448 status
= do_scan(SCAN_PATTERN
| SCAN_PURGE
, F_NORMAL
);
454 * This routine implements the 'verify' command. It writes the disk
455 * by writing unique data for each block; after the write pass, it
456 * reads the data and verifies for correctness. Note that the entire
457 * disk (or the range of disk) is fully written first and then read.
458 * This should eliminate any caching effect on the drives.
459 * It is not ok to run this command on any data you want to keep.
465 * The current disk must be formatted before disk analysis.
467 if (!(cur_flags
& DISK_FORMATTED
)) {
468 err_print("Current Disk is unformatted.\n");
472 fmt_print("The verify command does not write random data\n");
475 if (scan_passes
< 2 && !scan_loop
) {
477 fmt_print("The verify command runs minimum of 2 passes, one"
478 " for writing and \nanother for reading and verfying."
479 " Resetting the number of passes to 2.\n");
482 if (check("Ready to verify (will corrupt data). This takes a long time,"
483 "\nbut is interruptible with CTRL-C. Continue")) {
487 return (do_scan(SCAN_WRITE
| SCAN_VERIFY
, F_NORMAL
));