1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 1991-2002 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * This file contains functions implementing the analyze menu commands.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <string.h>
33*0Sstevel@tonic-gate #include "global.h"
34*0Sstevel@tonic-gate #include "analyze.h"
35*0Sstevel@tonic-gate #include "misc.h"
36*0Sstevel@tonic-gate #include "menu_analyze.h"
37*0Sstevel@tonic-gate #include "param.h"
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * This routine implements the 'read' command.  It performs surface
43*0Sstevel@tonic-gate  * analysis by reading the disk.  It is ok to run this command on
44*0Sstevel@tonic-gate  * mounted file systems.
45*0Sstevel@tonic-gate  */
46*0Sstevel@tonic-gate int
47*0Sstevel@tonic-gate a_read()
48*0Sstevel@tonic-gate {
49*0Sstevel@tonic-gate 	/*
50*0Sstevel@tonic-gate 	 * The current disk must be formatted before disk analysis.
51*0Sstevel@tonic-gate 	 */
52*0Sstevel@tonic-gate 	if (!(cur_flags & DISK_FORMATTED)) {
53*0Sstevel@tonic-gate 		err_print("Current Disk is unformatted.\n");
54*0Sstevel@tonic-gate 		return (-1);
55*0Sstevel@tonic-gate 	}
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate 	if (check(
58*0Sstevel@tonic-gate "Ready to analyze (won't harm SunOS). This takes a long time, \n"
59*0Sstevel@tonic-gate "but is interruptable with CTRL-C. Continue"))
60*0Sstevel@tonic-gate 		return (-1);
61*0Sstevel@tonic-gate 	return (do_scan(SCAN_VALID, F_NORMAL));
62*0Sstevel@tonic-gate }
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate /*
65*0Sstevel@tonic-gate  * This routine implements the 'refresh' command.  It performs surface
66*0Sstevel@tonic-gate  * analysis by reading the disk then writing the same data back to the
67*0Sstevel@tonic-gate  * disk.  It is ok to run this command on file systems, but not while
68*0Sstevel@tonic-gate  * they are mounted.
69*0Sstevel@tonic-gate  */
70*0Sstevel@tonic-gate int
71*0Sstevel@tonic-gate a_refresh()
72*0Sstevel@tonic-gate {
73*0Sstevel@tonic-gate 	/*
74*0Sstevel@tonic-gate 	 * The current disk must be formatted before disk analysis.
75*0Sstevel@tonic-gate 	 */
76*0Sstevel@tonic-gate 	if (!(cur_flags & DISK_FORMATTED)) {
77*0Sstevel@tonic-gate 		err_print("Current Disk is unformatted.\n");
78*0Sstevel@tonic-gate 		return (-1);
79*0Sstevel@tonic-gate 	}
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	if (check(
82*0Sstevel@tonic-gate "Ready to analyze (won't harm data). This takes a long time, \n"
83*0Sstevel@tonic-gate "but is interruptable with CTRL-C. Continue"))
84*0Sstevel@tonic-gate 		return (-1);
85*0Sstevel@tonic-gate 	return (do_scan(SCAN_VALID | SCAN_WRITE, F_NORMAL));
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate /*
89*0Sstevel@tonic-gate  * This routine implements the 'test' command.  It performs surface
90*0Sstevel@tonic-gate  * analysis by reading the disk, writing then reading a pattern on the disk,
91*0Sstevel@tonic-gate  * then writing the original data back to the disk.
92*0Sstevel@tonic-gate  * It is ok to run this command on file systems, but not while they are
93*0Sstevel@tonic-gate  * mounted.
94*0Sstevel@tonic-gate  */
95*0Sstevel@tonic-gate int
96*0Sstevel@tonic-gate a_test()
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	/*
99*0Sstevel@tonic-gate 	 * The current disk must be formatted before disk analysis.
100*0Sstevel@tonic-gate 	 */
101*0Sstevel@tonic-gate 	if (!(cur_flags & DISK_FORMATTED)) {
102*0Sstevel@tonic-gate 		err_print("Current Disk is unformatted.\n");
103*0Sstevel@tonic-gate 		return (-1);
104*0Sstevel@tonic-gate 	}
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	if (check(
107*0Sstevel@tonic-gate "Ready to analyze (won't harm data). This takes a long time, \n"
108*0Sstevel@tonic-gate "but is interruptable with CTRL-C. Continue"))
109*0Sstevel@tonic-gate 		return (-1);
110*0Sstevel@tonic-gate 	return (do_scan(SCAN_VALID | SCAN_PATTERN | SCAN_WRITE, F_NORMAL));
111*0Sstevel@tonic-gate }
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate /*
114*0Sstevel@tonic-gate  * This routine implements the 'write' command.  It performs surface
115*0Sstevel@tonic-gate  * analysis by writing a pattern to the disk then reading it back.
116*0Sstevel@tonic-gate  * It is not ok to run this command on any data you want to keep.
117*0Sstevel@tonic-gate  */
118*0Sstevel@tonic-gate int
119*0Sstevel@tonic-gate a_write()
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	/*
122*0Sstevel@tonic-gate 	 * The current disk must be formatted before disk analysis.
123*0Sstevel@tonic-gate 	 */
124*0Sstevel@tonic-gate 	if (!(cur_flags & DISK_FORMATTED)) {
125*0Sstevel@tonic-gate 		err_print("Current Disk is unformatted.\n");
126*0Sstevel@tonic-gate 		return (-1);
127*0Sstevel@tonic-gate 	}
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	if (check(
130*0Sstevel@tonic-gate "Ready to analyze (will corrupt data). This takes a long time, \n"
131*0Sstevel@tonic-gate "but is interruptable with CTRL-C. Continue"))
132*0Sstevel@tonic-gate 		return (-1);
133*0Sstevel@tonic-gate 	return (do_scan(SCAN_PATTERN, F_NORMAL));
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate /*
137*0Sstevel@tonic-gate  * This routine implements the 'compare' command.  It performs surface
138*0Sstevel@tonic-gate  * analysis by writing a pattern to the disk, reading it back, then
139*0Sstevel@tonic-gate  * checking the data to be sure it's the same.
140*0Sstevel@tonic-gate  * It is not ok to run this command on any data you want to keep.
141*0Sstevel@tonic-gate  */
142*0Sstevel@tonic-gate int
143*0Sstevel@tonic-gate a_compare()
144*0Sstevel@tonic-gate {
145*0Sstevel@tonic-gate 	/*
146*0Sstevel@tonic-gate 	 * The current disk must be formatted before disk analysis.
147*0Sstevel@tonic-gate 	 */
148*0Sstevel@tonic-gate 	if (!(cur_flags & DISK_FORMATTED)) {
149*0Sstevel@tonic-gate 		err_print("Current Disk is unformatted.\n");
150*0Sstevel@tonic-gate 		return (-1);
151*0Sstevel@tonic-gate 	}
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	if (check(
154*0Sstevel@tonic-gate "Ready to analyze (will corrupt data). This takes a long time, \n"
155*0Sstevel@tonic-gate "but is interruptable with CTRL-C. Continue"))
156*0Sstevel@tonic-gate 		return (-1);
157*0Sstevel@tonic-gate 	return (do_scan(SCAN_PATTERN | SCAN_COMPARE, F_NORMAL));
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate /*
161*0Sstevel@tonic-gate  * This routine implements the 'print' command.  It displays the data
162*0Sstevel@tonic-gate  * buffer in hexadecimal.  It is only useful for checking the disk for
163*0Sstevel@tonic-gate  * a specific set of data (by reading it then printing it).
164*0Sstevel@tonic-gate  */
165*0Sstevel@tonic-gate int
166*0Sstevel@tonic-gate a_print()
167*0Sstevel@tonic-gate {
168*0Sstevel@tonic-gate 	int	i, j, lines, nomore = 0;
169*0Sstevel@tonic-gate 	int	c, one_line = 0;
170*0Sstevel@tonic-gate 	int	tty_lines = get_tty_lines();
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	/*
173*0Sstevel@tonic-gate 	 * If we are running out of command file, don't page the output.
174*0Sstevel@tonic-gate 	 * Otherwise we are running with a user.  Turn off echoing of
175*0Sstevel@tonic-gate 	 * input characters so we can page the output.
176*0Sstevel@tonic-gate 	 */
177*0Sstevel@tonic-gate 	if (option_f || (!isatty(0)) || (!isatty(1)))
178*0Sstevel@tonic-gate 		nomore++;
179*0Sstevel@tonic-gate 	else {
180*0Sstevel@tonic-gate 		enter_critical();
181*0Sstevel@tonic-gate 		echo_off();
182*0Sstevel@tonic-gate 		charmode_on();
183*0Sstevel@tonic-gate 		exit_critical();
184*0Sstevel@tonic-gate 	}
185*0Sstevel@tonic-gate 	/*
186*0Sstevel@tonic-gate 	 * Loop through the data buffer.
187*0Sstevel@tonic-gate 	 */
188*0Sstevel@tonic-gate 	lines = 0;
189*0Sstevel@tonic-gate 	for (i = 0; i < scan_size * SECSIZE / sizeof (int); i += 6) {
190*0Sstevel@tonic-gate 		/*
191*0Sstevel@tonic-gate 		 * Print the data.
192*0Sstevel@tonic-gate 		 */
193*0Sstevel@tonic-gate 		for (j = 0; j < 6; j++)
194*0Sstevel@tonic-gate 			if (i + j < scan_size * SECSIZE / sizeof (int))
195*0Sstevel@tonic-gate 				fmt_print("0x%08x  ",
196*0Sstevel@tonic-gate 				*((int *)((int *)cur_buf + i + j)));
197*0Sstevel@tonic-gate 		fmt_print("\n");
198*0Sstevel@tonic-gate 		lines++;
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 		/*
201*0Sstevel@tonic-gate 		 * If we are paging and hit the end of a page, wait for
202*0Sstevel@tonic-gate 		 * the user to hit either space-bar, "q", return,
203*0Sstevel@tonic-gate 		 * or ctrl-C before going on.
204*0Sstevel@tonic-gate 		 */
205*0Sstevel@tonic-gate 		if (one_line ||
206*0Sstevel@tonic-gate 		    (!nomore && (lines % (tty_lines - 1) == 0))) {
207*0Sstevel@tonic-gate 			/*
208*0Sstevel@tonic-gate 			 * Print until first screenfull
209*0Sstevel@tonic-gate 			 */
210*0Sstevel@tonic-gate 			if (lines < (tty_lines -1))
211*0Sstevel@tonic-gate 				continue;
212*0Sstevel@tonic-gate 			/*
213*0Sstevel@tonic-gate 			 * Get the next character.
214*0Sstevel@tonic-gate 			 */
215*0Sstevel@tonic-gate 			(void) printf("- hit space for more - ");
216*0Sstevel@tonic-gate 			c = getchar();
217*0Sstevel@tonic-gate 			(void) printf("\015");
218*0Sstevel@tonic-gate 			one_line = 0;
219*0Sstevel@tonic-gate 			/*
220*0Sstevel@tonic-gate 			 * Handle display one line command (return key)
221*0Sstevel@tonic-gate 			 */
222*0Sstevel@tonic-gate 			if (c == '\012') {
223*0Sstevel@tonic-gate 				one_line++;
224*0Sstevel@tonic-gate 			}
225*0Sstevel@tonic-gate 			/* Handle Quit command */
226*0Sstevel@tonic-gate 			if (c == 'q') {
227*0Sstevel@tonic-gate 				(void) printf(
228*0Sstevel@tonic-gate 				"                       \015");
229*0Sstevel@tonic-gate 				goto PRINT_EXIT;
230*0Sstevel@tonic-gate 			}
231*0Sstevel@tonic-gate 			/* handle ^D */
232*0Sstevel@tonic-gate 			if (c == '\004')
233*0Sstevel@tonic-gate 				fullabort();
234*0Sstevel@tonic-gate 		}
235*0Sstevel@tonic-gate 	}
236*0Sstevel@tonic-gate 	/*
237*0Sstevel@tonic-gate 	 * If we were doing paging, turn echoing back on.
238*0Sstevel@tonic-gate 	 */
239*0Sstevel@tonic-gate PRINT_EXIT:
240*0Sstevel@tonic-gate 	if (!nomore) {
241*0Sstevel@tonic-gate 		enter_critical();
242*0Sstevel@tonic-gate 		charmode_off();
243*0Sstevel@tonic-gate 		echo_on();
244*0Sstevel@tonic-gate 		exit_critical();
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 	return (0);
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate /*
250*0Sstevel@tonic-gate  * This routine implements the 'setup' command.  It allows the user
251*0Sstevel@tonic-gate  * to program the variables that drive surface analysis.  The approach
252*0Sstevel@tonic-gate  * is to prompt the user for the value of each variable, with the current
253*0Sstevel@tonic-gate  * value as the default.
254*0Sstevel@tonic-gate  */
255*0Sstevel@tonic-gate int
256*0Sstevel@tonic-gate a_setup()
257*0Sstevel@tonic-gate {
258*0Sstevel@tonic-gate 	int			deflt;
259*0Sstevel@tonic-gate 	uint64_t		size;
260*0Sstevel@tonic-gate 	u_ioparam_t		ioparam;
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	/*
263*0Sstevel@tonic-gate 	 * Because of the polarity of the yes/no structure (yes is 0),
264*0Sstevel@tonic-gate 	 * we have to invert the values for all yes/no questions.
265*0Sstevel@tonic-gate 	 */
266*0Sstevel@tonic-gate 	deflt = !scan_entire;
267*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
268*0Sstevel@tonic-gate 	scan_entire = !input(FIO_MSTR, "Analyze entire disk", '?',
269*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
270*0Sstevel@tonic-gate 	/*
271*0Sstevel@tonic-gate 	 * If we are not scanning the whole disk, input the bounds of the scan.
272*0Sstevel@tonic-gate 	 */
273*0Sstevel@tonic-gate 	if (!scan_entire) {
274*0Sstevel@tonic-gate 		ioparam.io_bounds.lower = 0;
275*0Sstevel@tonic-gate 		if ((cur_ctype->ctype_flags & CF_SCSI) &&
276*0Sstevel@tonic-gate 		    (cur_disk->label_type == L_TYPE_SOLARIS)) {
277*0Sstevel@tonic-gate 		    ioparam.io_bounds.upper = datasects() - 1;
278*0Sstevel@tonic-gate 		} else if (cur_disk->label_type == L_TYPE_SOLARIS) {
279*0Sstevel@tonic-gate 		    ioparam.io_bounds.upper = physsects() - 1;
280*0Sstevel@tonic-gate 		} else if (cur_disk->label_type == L_TYPE_EFI) {
281*0Sstevel@tonic-gate 		    ioparam.io_bounds.upper = cur_parts->etoc->efi_last_lba;
282*0Sstevel@tonic-gate 		}
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 		scan_lower = (diskaddr_t)input(FIO_BN,
285*0Sstevel@tonic-gate 		    "Enter starting block number", ':',
286*0Sstevel@tonic-gate 		    &ioparam, (int *)&scan_lower, DATA_INPUT);
287*0Sstevel@tonic-gate 		ioparam.io_bounds.lower = scan_lower;
288*0Sstevel@tonic-gate 		if (scan_upper < scan_lower)
289*0Sstevel@tonic-gate 			scan_upper = scan_lower;
290*0Sstevel@tonic-gate 		scan_upper = (diskaddr_t)input(FIO_BN,
291*0Sstevel@tonic-gate 		    "Enter ending block number", ':',
292*0Sstevel@tonic-gate 		    &ioparam, (int *)&scan_upper, DATA_INPUT);
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 	deflt = !scan_loop;
295*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
296*0Sstevel@tonic-gate 	scan_loop = !input(FIO_MSTR, "Loop continuously", '?',
297*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
298*0Sstevel@tonic-gate 	/*
299*0Sstevel@tonic-gate 	 * If we are not looping continuously, input the number of passes.
300*0Sstevel@tonic-gate 	 */
301*0Sstevel@tonic-gate 	if (!scan_loop) {
302*0Sstevel@tonic-gate 		ioparam.io_bounds.lower = 1;
303*0Sstevel@tonic-gate 		ioparam.io_bounds.upper = 100;
304*0Sstevel@tonic-gate 		scan_passes = input(FIO_INT, "Enter number of passes", ':',
305*0Sstevel@tonic-gate 		    &ioparam, &scan_passes, DATA_INPUT);
306*0Sstevel@tonic-gate 	}
307*0Sstevel@tonic-gate 	deflt = !scan_correct;
308*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
309*0Sstevel@tonic-gate 	scan_correct = !input(FIO_MSTR, "Repair defective blocks", '?',
310*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
311*0Sstevel@tonic-gate 	deflt = !scan_stop;
312*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
313*0Sstevel@tonic-gate 	scan_stop = !input(FIO_MSTR, "Stop after first error", '?',
314*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
315*0Sstevel@tonic-gate 	deflt = !scan_random;
316*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
317*0Sstevel@tonic-gate 	scan_random = !input(FIO_MSTR, "Use random bit patterns", '?',
318*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
319*0Sstevel@tonic-gate 	ioparam.io_bounds.lower = 1;
320*0Sstevel@tonic-gate 	/*
321*0Sstevel@tonic-gate 	 * The number of blocks per transfer is limited by the buffer
322*0Sstevel@tonic-gate 	 * size, or the scan boundaries, whichever is smaller.
323*0Sstevel@tonic-gate 	 */
324*0Sstevel@tonic-gate 	if ((scan_entire) && (cur_disk->label_type == L_TYPE_SOLARIS)) {
325*0Sstevel@tonic-gate 		size = physsects() - 1;
326*0Sstevel@tonic-gate 	} else if ((scan_entire) && (cur_disk->label_type == L_TYPE_EFI)) {
327*0Sstevel@tonic-gate 		size = cur_parts->etoc->efi_last_lba;
328*0Sstevel@tonic-gate 	} else {
329*0Sstevel@tonic-gate 		size = scan_upper - scan_lower + 1;
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 	ioparam.io_bounds.upper = min(size, BUF_SECTS);
332*0Sstevel@tonic-gate 	if (scan_size > ioparam.io_bounds.upper)
333*0Sstevel@tonic-gate 		scan_size = ioparam.io_bounds.upper;
334*0Sstevel@tonic-gate 	scan_size = input(FIO_BN, "Enter number of blocks per transfer", ':',
335*0Sstevel@tonic-gate 	    &ioparam, &scan_size, DATA_INPUT);
336*0Sstevel@tonic-gate 	deflt = !scan_auto;
337*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
338*0Sstevel@tonic-gate 	scan_auto = !input(FIO_MSTR, "Verify media after formatting", '?',
339*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	deflt = !option_msg;
342*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
343*0Sstevel@tonic-gate 	option_msg = !input(FIO_MSTR, "Enable extended messages", '?',
344*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
345*0Sstevel@tonic-gate 	deflt = !scan_restore_defects;
346*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
347*0Sstevel@tonic-gate 	scan_restore_defects = !input(FIO_MSTR, "Restore defect list", '?',
348*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
349*0Sstevel@tonic-gate 	deflt = !scan_restore_label;
350*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
351*0Sstevel@tonic-gate 	scan_restore_label = !input(FIO_MSTR, "Restore disk label", '?',
352*0Sstevel@tonic-gate 	    &ioparam, &deflt, DATA_INPUT);
353*0Sstevel@tonic-gate 	fmt_print("\n");
354*0Sstevel@tonic-gate 	return (0);
355*0Sstevel@tonic-gate }
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate /*
358*0Sstevel@tonic-gate  * This routine implements the 'config' command.  It simply prints out
359*0Sstevel@tonic-gate  * the values of all the variables controlling surface analysis.  It
360*0Sstevel@tonic-gate  * is meant to complement the 'setup' command by allowing the user to
361*0Sstevel@tonic-gate  * check the current setup.
362*0Sstevel@tonic-gate  */
363*0Sstevel@tonic-gate int
364*0Sstevel@tonic-gate a_config()
365*0Sstevel@tonic-gate {
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	fmt_print("        Analyze entire disk? ");
368*0Sstevel@tonic-gate 	fmt_print(scan_entire ? "yes\n" : "no\n");
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	if (!scan_entire) {
371*0Sstevel@tonic-gate 		fmt_print("        Starting block number: %llu (", scan_lower);
372*0Sstevel@tonic-gate 		pr_dblock(fmt_print, scan_lower);
373*0Sstevel@tonic-gate 		fmt_print(")\n        Ending block number: %llu (", scan_upper);
374*0Sstevel@tonic-gate 		pr_dblock(fmt_print, scan_upper);
375*0Sstevel@tonic-gate 		fmt_print(")\n");
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 	fmt_print("        Loop continuously? ");
378*0Sstevel@tonic-gate 	fmt_print(scan_loop ? "yes\n" : "no\n");
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	if (!scan_loop) {
381*0Sstevel@tonic-gate 		fmt_print("        Number of passes: %d\n", scan_passes);
382*0Sstevel@tonic-gate 	}
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	fmt_print("        Repair defective blocks? ");
385*0Sstevel@tonic-gate 	fmt_print(scan_correct ? "yes\n" : "no\n");
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	fmt_print("        Stop after first error? ");
388*0Sstevel@tonic-gate 	fmt_print(scan_stop ? "yes\n" : "no\n");
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	fmt_print("        Use random bit patterns? ");
391*0Sstevel@tonic-gate 	fmt_print(scan_random ? "yes\n" : "no\n");
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	fmt_print("        Number of blocks per transfer: %d (", scan_size);
394*0Sstevel@tonic-gate 	pr_dblock(fmt_print, (daddr_t)scan_size);
395*0Sstevel@tonic-gate 	fmt_print(")\n");
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	fmt_print("        Verify media after formatting? ");
398*0Sstevel@tonic-gate 	fmt_print(scan_auto ? "yes\n" : "no\n");
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	fmt_print("        Enable extended messages? ");
401*0Sstevel@tonic-gate 	fmt_print(option_msg ? "yes\n" : "no\n");
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	fmt_print("        Restore defect list? ");
404*0Sstevel@tonic-gate 	fmt_print(scan_restore_defects ? "yes\n" : "no\n");
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	fmt_print("        Restore disk label? ");
407*0Sstevel@tonic-gate 	fmt_print(scan_restore_label ? "yes\n" : "no\n");
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	fmt_print("\n");
410*0Sstevel@tonic-gate 	return (0);
411*0Sstevel@tonic-gate }
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate /*
414*0Sstevel@tonic-gate  * This routine implements the 'purge' command.  It purges the disk
415*0Sstevel@tonic-gate  * by writing three patterns to the disk then reading the last one back.
416*0Sstevel@tonic-gate  * It is not ok to run this command on any data you want to keep.
417*0Sstevel@tonic-gate  */
418*0Sstevel@tonic-gate int
419*0Sstevel@tonic-gate a_purge()
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	int status = 0;
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	/*
424*0Sstevel@tonic-gate 	 * The current disk must be formatted before disk analysis.
425*0Sstevel@tonic-gate 	 */
426*0Sstevel@tonic-gate 	if (!(cur_flags & DISK_FORMATTED)) {
427*0Sstevel@tonic-gate 		err_print("Current Disk is unformatted.\n");
428*0Sstevel@tonic-gate 		return (-1);
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 	if (scan_random) {
431*0Sstevel@tonic-gate 		fmt_print("The purge command does not write random data\n");
432*0Sstevel@tonic-gate 		scan_random = 0;
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	if (!scan_loop && (scan_passes <= NPPATTERNS)) {
436*0Sstevel@tonic-gate 		if (scan_passes < NPPATTERNS) {
437*0Sstevel@tonic-gate 			fmt_print("The purge command runs for a minimum of ");
438*0Sstevel@tonic-gate 			fmt_print("%d passes plus a last pass if the\n",
439*0Sstevel@tonic-gate 						NPPATTERNS);
440*0Sstevel@tonic-gate 			fmt_print("first %d passes were successful.\n",
441*0Sstevel@tonic-gate 					NPPATTERNS);
442*0Sstevel@tonic-gate 		}
443*0Sstevel@tonic-gate 		scan_passes = NPPATTERNS + 1;
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	if (check(
447*0Sstevel@tonic-gate "Ready to purge (will corrupt data). This takes a long time, \n"
448*0Sstevel@tonic-gate "but is interruptable with CTRL-C. Continue"))
449*0Sstevel@tonic-gate 		return (-1);
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	status = do_scan(SCAN_PATTERN | SCAN_PURGE, F_NORMAL);
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	return (status);
454*0Sstevel@tonic-gate }
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate /*
457*0Sstevel@tonic-gate  * This routine implements the 'verify' command.  It writes the disk
458*0Sstevel@tonic-gate  * by writing unique data for each block; after the write pass, it
459*0Sstevel@tonic-gate  * reads the data and verifies for correctness. Note that the entire
460*0Sstevel@tonic-gate  * disk (or the range of disk) is fully written first and then read.
461*0Sstevel@tonic-gate  * This should eliminate any caching effect on the drives.
462*0Sstevel@tonic-gate  * It is not ok to run this command on any data you want to keep.
463*0Sstevel@tonic-gate  */
464*0Sstevel@tonic-gate int
465*0Sstevel@tonic-gate a_verify()
466*0Sstevel@tonic-gate {
467*0Sstevel@tonic-gate 	/*
468*0Sstevel@tonic-gate 	 * The current disk must be formatted before disk analysis.
469*0Sstevel@tonic-gate 	 */
470*0Sstevel@tonic-gate 	if (!(cur_flags & DISK_FORMATTED)) {
471*0Sstevel@tonic-gate 		err_print("Current Disk is unformatted.\n");
472*0Sstevel@tonic-gate 		return (-1);
473*0Sstevel@tonic-gate 	}
474*0Sstevel@tonic-gate 	if (scan_random) {
475*0Sstevel@tonic-gate 		fmt_print("The verify command does not write random data\n");
476*0Sstevel@tonic-gate 		scan_random = 0;
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 	if (scan_passes < 2 && !scan_loop) {
479*0Sstevel@tonic-gate 		scan_passes = 2;
480*0Sstevel@tonic-gate 		fmt_print("The verify command runs minimum of 2 passes, one"
481*0Sstevel@tonic-gate 		    " for writing and \nanother for reading and verfying."
482*0Sstevel@tonic-gate 		    " Resetting the number of passes to 2.\n");
483*0Sstevel@tonic-gate 	}
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	if (check("Ready to verify (will corrupt data). This takes a long time,"
486*0Sstevel@tonic-gate 	    "\nbut is interruptable with CTRL-C. Continue")) {
487*0Sstevel@tonic-gate 		return (-1);
488*0Sstevel@tonic-gate 	}
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	return (do_scan(SCAN_WRITE | SCAN_VERIFY, F_NORMAL));
491*0Sstevel@tonic-gate }
492