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