1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * This file contains routines to analyze the surface of a disk. 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate #include "global.h" 33*7c478bd9Sstevel@tonic-gate #include "analyze.h" 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 35*7c478bd9Sstevel@tonic-gate #include <errno.h> 36*7c478bd9Sstevel@tonic-gate #include "misc.h" 37*7c478bd9Sstevel@tonic-gate #include "defect.h" 38*7c478bd9Sstevel@tonic-gate #include "label.h" 39*7c478bd9Sstevel@tonic-gate #include "param.h" 40*7c478bd9Sstevel@tonic-gate #include "checkmount.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate * These global variables control the surface analysis process. They 45*7c478bd9Sstevel@tonic-gate * are set from a command in the defect menu. 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate int scan_entire = 1; /* scan whole disk flag */ 48*7c478bd9Sstevel@tonic-gate diskaddr_t scan_lower = 0; /* lower bound */ 49*7c478bd9Sstevel@tonic-gate diskaddr_t scan_upper = 0; /* upper bound */ 50*7c478bd9Sstevel@tonic-gate int scan_correct = 1; /* correct errors flag */ 51*7c478bd9Sstevel@tonic-gate int scan_stop = 0; /* stop after error flag */ 52*7c478bd9Sstevel@tonic-gate int scan_loop = 0; /* loop forever flag */ 53*7c478bd9Sstevel@tonic-gate int scan_passes = 2; /* number of passes */ 54*7c478bd9Sstevel@tonic-gate int scan_random = 0; /* random patterns flag */ 55*7c478bd9Sstevel@tonic-gate int scan_size = 0; /* sectors/scan operation */ 56*7c478bd9Sstevel@tonic-gate int scan_auto = 1; /* scan after format flag */ 57*7c478bd9Sstevel@tonic-gate int scan_restore_defects = 1; /* restore defect list after writing */ 58*7c478bd9Sstevel@tonic-gate int scan_restore_label = 1; /* restore label after writing */ 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* 61*7c478bd9Sstevel@tonic-gate * These are summary variables to print out info after analysis. 62*7c478bd9Sstevel@tonic-gate * Values less than 0 imply they are invalid. 63*7c478bd9Sstevel@tonic-gate */ 64*7c478bd9Sstevel@tonic-gate offset_t scan_cur_block = -1; /* current block */ 65*7c478bd9Sstevel@tonic-gate int64_t scan_blocks_fixed = -1; /* # blocks repaired */ 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * This variable is used to tell whether the most recent surface 69*7c478bd9Sstevel@tonic-gate * analysis error was caused by a media defect or some other problem. 70*7c478bd9Sstevel@tonic-gate */ 71*7c478bd9Sstevel@tonic-gate int media_error; /* error was caused by defect */ 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate int disk_error; /* disk errors during analysis */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* 76*7c478bd9Sstevel@tonic-gate * These are the data patterns used if random patterns are not chosen. 77*7c478bd9Sstevel@tonic-gate * They are designed to show pattern dependent errors. 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate static unsigned int scan_patterns[] = { 80*7c478bd9Sstevel@tonic-gate 0xc6dec6de, 81*7c478bd9Sstevel@tonic-gate 0x6db6db6d, 82*7c478bd9Sstevel@tonic-gate 0x00000000, 83*7c478bd9Sstevel@tonic-gate 0xffffffff, 84*7c478bd9Sstevel@tonic-gate 0xaaaaaaaa, 85*7c478bd9Sstevel@tonic-gate }; 86*7c478bd9Sstevel@tonic-gate #define NPATTERNS 5 /* number of predefined patterns */ 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* 89*7c478bd9Sstevel@tonic-gate * These are the data patterns from the SunFed requirements document. 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate static unsigned int purge_patterns[] = { /* patterns to be written */ 92*7c478bd9Sstevel@tonic-gate 0xaaaaaaaa, /* 10101010... */ 93*7c478bd9Sstevel@tonic-gate 0x55555555, /* 01010101... == UUUU... */ 94*7c478bd9Sstevel@tonic-gate 0xaaaaaaaa, /* 10101010... */ 95*7c478bd9Sstevel@tonic-gate 0xaaaaaaaa, /* 10101010... */ 96*7c478bd9Sstevel@tonic-gate }; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate static unsigned int alpha_pattern = 0x40404040; /* 10000000... == @@@@... */ 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* Function prototypes */ 101*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate static int scan_repair(diskaddr_t bn, int mode); 104*7c478bd9Sstevel@tonic-gate static int analyze_blocks(int flags, diskaddr_t blkno, int blkcnt, 105*7c478bd9Sstevel@tonic-gate unsigned data, int init, int driver_flags, int *xfercntp); 106*7c478bd9Sstevel@tonic-gate static int handle_error_conditions(void); 107*7c478bd9Sstevel@tonic-gate static int verify_blocks(int flags, diskaddr_t blkno, int blkcnt, 108*7c478bd9Sstevel@tonic-gate unsigned data, int driver_flags, int *xfercntp); 109*7c478bd9Sstevel@tonic-gate #else /* __STDC__ */ 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate static int scan_repair(); 112*7c478bd9Sstevel@tonic-gate static int analyze_blocks(); 113*7c478bd9Sstevel@tonic-gate static int handle_error_conditions(); 114*7c478bd9Sstevel@tonic-gate static int verify_blocks(); 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate #endif /* __STDC__ */ 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* 119*7c478bd9Sstevel@tonic-gate * This routine performs a surface analysis based upon the global 120*7c478bd9Sstevel@tonic-gate * parameters. It is called from several commands in the defect menu, 121*7c478bd9Sstevel@tonic-gate * and from the format command in the command menu (if post-format 122*7c478bd9Sstevel@tonic-gate * analysis is enable). 123*7c478bd9Sstevel@tonic-gate */ 124*7c478bd9Sstevel@tonic-gate int 125*7c478bd9Sstevel@tonic-gate do_scan(flags, mode) 126*7c478bd9Sstevel@tonic-gate int flags, mode; 127*7c478bd9Sstevel@tonic-gate { 128*7c478bd9Sstevel@tonic-gate diskaddr_t start, end, curnt; 129*7c478bd9Sstevel@tonic-gate int pass, size, needinit, data; 130*7c478bd9Sstevel@tonic-gate int status, founderr, i, j; 131*7c478bd9Sstevel@tonic-gate int error = 0; 132*7c478bd9Sstevel@tonic-gate int pattern = 0; 133*7c478bd9Sstevel@tonic-gate int xfercnt; 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* 136*7c478bd9Sstevel@tonic-gate * Check to be sure we aren't correcting without a defect list 137*7c478bd9Sstevel@tonic-gate * if the controller can correct the defect. 138*7c478bd9Sstevel@tonic-gate */ 139*7c478bd9Sstevel@tonic-gate if (scan_correct && !EMBEDDED_SCSI && (cur_ops->op_repair != NULL) && 140*7c478bd9Sstevel@tonic-gate (cur_list.list == NULL)) { 141*7c478bd9Sstevel@tonic-gate err_print("Current Defect List must be initialized "); 142*7c478bd9Sstevel@tonic-gate err_print("to do automatic repair.\n"); 143*7c478bd9Sstevel@tonic-gate return (-1); 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * Define the bounds of the scan. 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate if (scan_entire) { 149*7c478bd9Sstevel@tonic-gate start = 0; 150*7c478bd9Sstevel@tonic-gate if (cur_label == L_TYPE_SOLARIS) { 151*7c478bd9Sstevel@tonic-gate if (cur_ctype->ctype_flags & CF_SCSI) 152*7c478bd9Sstevel@tonic-gate end = datasects() - 1; 153*7c478bd9Sstevel@tonic-gate else 154*7c478bd9Sstevel@tonic-gate end = physsects() - 1; 155*7c478bd9Sstevel@tonic-gate } else if (cur_label == L_TYPE_EFI) { 156*7c478bd9Sstevel@tonic-gate end = cur_parts->etoc->efi_last_lba; 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate } else { 159*7c478bd9Sstevel@tonic-gate start = scan_lower; 160*7c478bd9Sstevel@tonic-gate end = scan_upper; 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Make sure the user knows if we are scanning over a mounted 164*7c478bd9Sstevel@tonic-gate * partition. 165*7c478bd9Sstevel@tonic-gate */ 166*7c478bd9Sstevel@tonic-gate if ((flags & (SCAN_PATTERN | SCAN_WRITE)) && 167*7c478bd9Sstevel@tonic-gate (checkmount(start, end))) { 168*7c478bd9Sstevel@tonic-gate err_print("Cannot do analysis on a mounted partition.\n"); 169*7c478bd9Sstevel@tonic-gate return (-1); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Make sure the user knows if we are scanning over a 174*7c478bd9Sstevel@tonic-gate * partition being used for swapping. 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate if ((flags & (SCAN_PATTERN | SCAN_WRITE)) && 177*7c478bd9Sstevel@tonic-gate (checkswap(start, end))) { 178*7c478bd9Sstevel@tonic-gate err_print("Cannot do analysis on a partition \ 179*7c478bd9Sstevel@tonic-gate which is currently being used for swapping.\n"); 180*7c478bd9Sstevel@tonic-gate return (-1); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate /* 184*7c478bd9Sstevel@tonic-gate * If we are scanning destructively over certain sectors, 185*7c478bd9Sstevel@tonic-gate * we mark the defect list and/or label dirty so it will get rewritten. 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate if (flags & (SCAN_PATTERN | SCAN_WRITE)) { 188*7c478bd9Sstevel@tonic-gate if (cur_label == L_TYPE_SOLARIS) { 189*7c478bd9Sstevel@tonic-gate if (start < (daddr_t)totalsects() && 190*7c478bd9Sstevel@tonic-gate end >= (daddr_t)datasects()) { 191*7c478bd9Sstevel@tonic-gate if (!EMBEDDED_SCSI) { 192*7c478bd9Sstevel@tonic-gate cur_list.flags |= LIST_DIRTY; 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate if (cur_disk->disk_flags & DSK_LABEL) 195*7c478bd9Sstevel@tonic-gate cur_flags |= LABEL_DIRTY; 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate if (start == 0) { 199*7c478bd9Sstevel@tonic-gate if (cur_disk->disk_flags & DSK_LABEL) 200*7c478bd9Sstevel@tonic-gate cur_flags |= LABEL_DIRTY; 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * Initialize the summary info on sectors repaired. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate scan_blocks_fixed = 0; 207*7c478bd9Sstevel@tonic-gate /* 208*7c478bd9Sstevel@tonic-gate * Loop through the passes of the scan. If required, loop forever. 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate for (pass = 0; pass < scan_passes || scan_loop; pass++) { 211*7c478bd9Sstevel@tonic-gate /* 212*7c478bd9Sstevel@tonic-gate * Determine the data pattern to use if pattern testing 213*7c478bd9Sstevel@tonic-gate * is to be done. 214*7c478bd9Sstevel@tonic-gate */ 215*7c478bd9Sstevel@tonic-gate if (flags & SCAN_PATTERN) { 216*7c478bd9Sstevel@tonic-gate if (scan_random) 217*7c478bd9Sstevel@tonic-gate data = (int)mrand48(); 218*7c478bd9Sstevel@tonic-gate else 219*7c478bd9Sstevel@tonic-gate data = scan_patterns[pass % NPPATTERNS]; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate if (flags & SCAN_PURGE) { 222*7c478bd9Sstevel@tonic-gate flags &= ~(SCAN_PURGE_READ_PASS 223*7c478bd9Sstevel@tonic-gate | SCAN_PURGE_ALPHA_PASS); 224*7c478bd9Sstevel@tonic-gate switch (pattern % (NPPATTERNS + 1)) { 225*7c478bd9Sstevel@tonic-gate case NPPATTERNS: 226*7c478bd9Sstevel@tonic-gate pattern = 0; 227*7c478bd9Sstevel@tonic-gate if (!error) { 228*7c478bd9Sstevel@tonic-gate fmt_print( 229*7c478bd9Sstevel@tonic-gate "\nThe last %d passes were successful, running alpha pattern pass", NPPATTERNS); 230*7c478bd9Sstevel@tonic-gate flags |= SCAN_PURGE_ALPHA_PASS; 231*7c478bd9Sstevel@tonic-gate data = alpha_pattern; 232*7c478bd9Sstevel@tonic-gate } else { 233*7c478bd9Sstevel@tonic-gate data = purge_patterns[pattern]; 234*7c478bd9Sstevel@tonic-gate pattern++; 235*7c478bd9Sstevel@tonic-gate }; 236*7c478bd9Sstevel@tonic-gate break; 237*7c478bd9Sstevel@tonic-gate case READPATTERN: 238*7c478bd9Sstevel@tonic-gate flags |= SCAN_PURGE_READ_PASS; 239*7c478bd9Sstevel@tonic-gate default: 240*7c478bd9Sstevel@tonic-gate data = purge_patterns[pattern]; 241*7c478bd9Sstevel@tonic-gate pattern++; 242*7c478bd9Sstevel@tonic-gate break; 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate } 245*7c478bd9Sstevel@tonic-gate fmt_print("\n pass %d", pass); 246*7c478bd9Sstevel@tonic-gate fmt_print(" - pattern = 0x%x", data); 247*7c478bd9Sstevel@tonic-gate } else 248*7c478bd9Sstevel@tonic-gate fmt_print("\n pass %d", pass); 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate fmt_print("\n"); 251*7c478bd9Sstevel@tonic-gate /* 252*7c478bd9Sstevel@tonic-gate * Mark the pattern buffer as corrupt, since it 253*7c478bd9Sstevel@tonic-gate * hasn't been initialized. 254*7c478bd9Sstevel@tonic-gate */ 255*7c478bd9Sstevel@tonic-gate needinit = 1; 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * Print the first block number to the log file if 258*7c478bd9Sstevel@tonic-gate * logging is on so there is some record of what 259*7c478bd9Sstevel@tonic-gate * analysis was performed. 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate if (log_file) { 262*7c478bd9Sstevel@tonic-gate pr_dblock(log_print, start); 263*7c478bd9Sstevel@tonic-gate log_print("\n"); 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate /* 266*7c478bd9Sstevel@tonic-gate * Loop through this pass, each time analyzing an amount 267*7c478bd9Sstevel@tonic-gate * specified by the global parameters. 268*7c478bd9Sstevel@tonic-gate */ 269*7c478bd9Sstevel@tonic-gate xfercnt = 0; 270*7c478bd9Sstevel@tonic-gate for (curnt = start; curnt <= end; curnt += size) { 271*7c478bd9Sstevel@tonic-gate if ((end - curnt) < scan_size) 272*7c478bd9Sstevel@tonic-gate size = end - curnt + 1; 273*7c478bd9Sstevel@tonic-gate else 274*7c478bd9Sstevel@tonic-gate size = scan_size; 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * Print out where we are, so we don't look dead. 277*7c478bd9Sstevel@tonic-gate * Also store it in summary info for logging. 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate scan_cur_block = curnt; 280*7c478bd9Sstevel@tonic-gate nolog_print(" "); 281*7c478bd9Sstevel@tonic-gate pr_dblock(nolog_print, curnt); 282*7c478bd9Sstevel@tonic-gate nolog_print(" \015"); 283*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 284*7c478bd9Sstevel@tonic-gate disk_error = 0; 285*7c478bd9Sstevel@tonic-gate /* 286*7c478bd9Sstevel@tonic-gate * Do the actual analysis. 287*7c478bd9Sstevel@tonic-gate */ 288*7c478bd9Sstevel@tonic-gate status = analyze_blocks(flags, (daddr_t)curnt, size, 289*7c478bd9Sstevel@tonic-gate (unsigned)data, needinit, (F_ALLERRS | F_SILENT), 290*7c478bd9Sstevel@tonic-gate &xfercnt); 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * If there were no errors, the pattern buffer is 293*7c478bd9Sstevel@tonic-gate * still initialized, and we just loop to next chunk. 294*7c478bd9Sstevel@tonic-gate */ 295*7c478bd9Sstevel@tonic-gate needinit = 0; 296*7c478bd9Sstevel@tonic-gate if (!status) 297*7c478bd9Sstevel@tonic-gate continue; 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * There was an error. Check if surface analysis 300*7c478bd9Sstevel@tonic-gate * can be continued. 301*7c478bd9Sstevel@tonic-gate */ 302*7c478bd9Sstevel@tonic-gate if (handle_error_conditions()) { 303*7c478bd9Sstevel@tonic-gate scan_blocks_fixed = scan_cur_block = -1; 304*7c478bd9Sstevel@tonic-gate return (-1); 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * There was an error. Mark the pattern buffer 308*7c478bd9Sstevel@tonic-gate * corrupt so it will get reinitialized. 309*7c478bd9Sstevel@tonic-gate */ 310*7c478bd9Sstevel@tonic-gate needinit = 1; 311*7c478bd9Sstevel@tonic-gate /* 312*7c478bd9Sstevel@tonic-gate * If it was not a media error, ignore it. 313*7c478bd9Sstevel@tonic-gate */ 314*7c478bd9Sstevel@tonic-gate if (!media_error) 315*7c478bd9Sstevel@tonic-gate continue; 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate * Loop 5 times through each sector of the chunk, 318*7c478bd9Sstevel@tonic-gate * analyzing them individually. 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate nolog_print(" "); 321*7c478bd9Sstevel@tonic-gate pr_dblock(nolog_print, curnt); 322*7c478bd9Sstevel@tonic-gate nolog_print(" \015"); 323*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 324*7c478bd9Sstevel@tonic-gate founderr = 0; 325*7c478bd9Sstevel@tonic-gate for (j = 0; j < size * 5; j++) { 326*7c478bd9Sstevel@tonic-gate i = j % size; 327*7c478bd9Sstevel@tonic-gate disk_error = 0; 328*7c478bd9Sstevel@tonic-gate status = analyze_blocks(flags, (daddr_t) 329*7c478bd9Sstevel@tonic-gate (curnt + i), 1, (unsigned)data, needinit, 330*7c478bd9Sstevel@tonic-gate F_ALLERRS, NULL); 331*7c478bd9Sstevel@tonic-gate needinit = 0; 332*7c478bd9Sstevel@tonic-gate if (!status) 333*7c478bd9Sstevel@tonic-gate continue; 334*7c478bd9Sstevel@tonic-gate /* 335*7c478bd9Sstevel@tonic-gate * There was an error. Check if surface analysis 336*7c478bd9Sstevel@tonic-gate * can be continued. 337*7c478bd9Sstevel@tonic-gate */ 338*7c478bd9Sstevel@tonic-gate if (handle_error_conditions()) { 339*7c478bd9Sstevel@tonic-gate scan_blocks_fixed = scan_cur_block = -1; 340*7c478bd9Sstevel@tonic-gate return (-1); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * An error occurred. Mark the buffer 344*7c478bd9Sstevel@tonic-gate * corrupt and see if it was media 345*7c478bd9Sstevel@tonic-gate * related. 346*7c478bd9Sstevel@tonic-gate */ 347*7c478bd9Sstevel@tonic-gate needinit = 1; 348*7c478bd9Sstevel@tonic-gate if (!media_error) 349*7c478bd9Sstevel@tonic-gate continue; 350*7c478bd9Sstevel@tonic-gate /* 351*7c478bd9Sstevel@tonic-gate * We found a bad sector. Print out a message 352*7c478bd9Sstevel@tonic-gate * and fix it if required. 353*7c478bd9Sstevel@tonic-gate */ 354*7c478bd9Sstevel@tonic-gate founderr = 1; 355*7c478bd9Sstevel@tonic-gate if (scan_correct && (flags != SCAN_VALID)) { 356*7c478bd9Sstevel@tonic-gate if (scan_repair(curnt+i, mode)) { 357*7c478bd9Sstevel@tonic-gate error = -1; 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate } else 360*7c478bd9Sstevel@tonic-gate err_print("\n"); 361*7c478bd9Sstevel@tonic-gate /* 362*7c478bd9Sstevel@tonic-gate * Stop after the error if required. 363*7c478bd9Sstevel@tonic-gate */ 364*7c478bd9Sstevel@tonic-gate if (scan_stop) 365*7c478bd9Sstevel@tonic-gate goto out; 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate /* 368*7c478bd9Sstevel@tonic-gate * Mark the pattern buffer corrupt to be safe. 369*7c478bd9Sstevel@tonic-gate */ 370*7c478bd9Sstevel@tonic-gate needinit = 1; 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * We didn't find an individual sector that was bad. 373*7c478bd9Sstevel@tonic-gate * Print out a warning. 374*7c478bd9Sstevel@tonic-gate */ 375*7c478bd9Sstevel@tonic-gate if (!founderr) { 376*7c478bd9Sstevel@tonic-gate err_print("Warning: unable to pinpoint "); 377*7c478bd9Sstevel@tonic-gate err_print("defective block.\n"); 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate /* 381*7c478bd9Sstevel@tonic-gate * Print the end of each pass to the log file. 382*7c478bd9Sstevel@tonic-gate */ 383*7c478bd9Sstevel@tonic-gate enter_critical(); 384*7c478bd9Sstevel@tonic-gate if (log_file) { 385*7c478bd9Sstevel@tonic-gate pr_dblock(log_print, scan_cur_block); 386*7c478bd9Sstevel@tonic-gate log_print("\n"); 387*7c478bd9Sstevel@tonic-gate } 388*7c478bd9Sstevel@tonic-gate scan_cur_block = -1; 389*7c478bd9Sstevel@tonic-gate exit_critical(); 390*7c478bd9Sstevel@tonic-gate fmt_print("\n"); 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate /* 393*7c478bd9Sstevel@tonic-gate * alternate the read and write for SCAN_VERIFY test 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate if (flags & SCAN_VERIFY) { 396*7c478bd9Sstevel@tonic-gate flags ^= SCAN_VERIFY_READ_PASS; 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate out: 400*7c478bd9Sstevel@tonic-gate /* 401*7c478bd9Sstevel@tonic-gate * We got here either by giving up after an error or falling 402*7c478bd9Sstevel@tonic-gate * through after all passes were completed. 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate fmt_print("\n"); 405*7c478bd9Sstevel@tonic-gate enter_critical(); 406*7c478bd9Sstevel@tonic-gate /* 407*7c478bd9Sstevel@tonic-gate * If the defect list is dirty, write it to disk, 408*7c478bd9Sstevel@tonic-gate * if scan_restore_defects (the default) is true. 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate if (!EMBEDDED_SCSI && (cur_list.flags & LIST_DIRTY) && 411*7c478bd9Sstevel@tonic-gate (scan_restore_defects)) { 412*7c478bd9Sstevel@tonic-gate cur_list.flags = 0; 413*7c478bd9Sstevel@tonic-gate write_deflist(&cur_list); 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate /* 416*7c478bd9Sstevel@tonic-gate * If the label is dirty, write it to disk. 417*7c478bd9Sstevel@tonic-gate * if scan_restore_label (the default) is true. 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate if ((cur_flags & LABEL_DIRTY) && (scan_restore_label)) { 420*7c478bd9Sstevel@tonic-gate cur_flags &= ~LABEL_DIRTY; 421*7c478bd9Sstevel@tonic-gate (void) write_label(); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate /* 424*7c478bd9Sstevel@tonic-gate * If we dropped down to here after an error, we need to write 425*7c478bd9Sstevel@tonic-gate * the final block number to the log file for record keeping. 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate if (log_file && scan_cur_block >= 0) { 428*7c478bd9Sstevel@tonic-gate pr_dblock(log_print, scan_cur_block); 429*7c478bd9Sstevel@tonic-gate log_print("\n"); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate fmt_print("Total of %lld defective blocks repaired.\n", 432*7c478bd9Sstevel@tonic-gate scan_blocks_fixed); 433*7c478bd9Sstevel@tonic-gate /* 434*7c478bd9Sstevel@tonic-gate * Reinitialize the logging variables so they don't get used 435*7c478bd9Sstevel@tonic-gate * when they are not really valid. 436*7c478bd9Sstevel@tonic-gate */ 437*7c478bd9Sstevel@tonic-gate scan_blocks_fixed = scan_cur_block = -1; 438*7c478bd9Sstevel@tonic-gate exit_critical(); 439*7c478bd9Sstevel@tonic-gate return (error); 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate /* 444*7c478bd9Sstevel@tonic-gate * This routine is called to repair a bad block discovered 445*7c478bd9Sstevel@tonic-gate * during a scan operation. Return 0 for success, 1 for failure. 446*7c478bd9Sstevel@tonic-gate * (This has been extracted out of do_scan(), to simplify it.) 447*7c478bd9Sstevel@tonic-gate */ 448*7c478bd9Sstevel@tonic-gate static int 449*7c478bd9Sstevel@tonic-gate scan_repair(bn, mode) 450*7c478bd9Sstevel@tonic-gate diskaddr_t bn; 451*7c478bd9Sstevel@tonic-gate int mode; 452*7c478bd9Sstevel@tonic-gate { 453*7c478bd9Sstevel@tonic-gate int status; 454*7c478bd9Sstevel@tonic-gate int result = 1; 455*7c478bd9Sstevel@tonic-gate char buf[SECSIZE]; 456*7c478bd9Sstevel@tonic-gate int buf_is_good; 457*7c478bd9Sstevel@tonic-gate int i; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate if (cur_ops->op_repair == NULL) { 460*7c478bd9Sstevel@tonic-gate err_print("Warning: Controller does "); 461*7c478bd9Sstevel@tonic-gate err_print("not support repairing.\n\n"); 462*7c478bd9Sstevel@tonic-gate return (result); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate enter_critical(); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate /* 468*7c478bd9Sstevel@tonic-gate * Determine if the error appears to be hard or soft. We 469*7c478bd9Sstevel@tonic-gate * already assume there's an error. If we can get any 470*7c478bd9Sstevel@tonic-gate * good data out of the sector, write that data back 471*7c478bd9Sstevel@tonic-gate * after the repair. 472*7c478bd9Sstevel@tonic-gate */ 473*7c478bd9Sstevel@tonic-gate buf_is_good = 0; 474*7c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 475*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, bn, 1, 476*7c478bd9Sstevel@tonic-gate buf, F_SILENT, NULL); 477*7c478bd9Sstevel@tonic-gate if (status == 0) { 478*7c478bd9Sstevel@tonic-gate buf_is_good = 1; 479*7c478bd9Sstevel@tonic-gate break; 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate fmt_print("Repairing %s error on %llu (", 484*7c478bd9Sstevel@tonic-gate buf_is_good ? "soft" : "hard", bn); 485*7c478bd9Sstevel@tonic-gate pr_dblock(fmt_print, bn); 486*7c478bd9Sstevel@tonic-gate fmt_print(")..."); 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_repair)(bn, mode); 489*7c478bd9Sstevel@tonic-gate if (status) { 490*7c478bd9Sstevel@tonic-gate /* 491*7c478bd9Sstevel@tonic-gate * If the repair failed, we note it and will return the 492*7c478bd9Sstevel@tonic-gate * failure. However, the analysis goes on. 493*7c478bd9Sstevel@tonic-gate */ 494*7c478bd9Sstevel@tonic-gate fmt_print("failed.\n\n"); 495*7c478bd9Sstevel@tonic-gate } else { 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * The repair worked. Write the good data we could 498*7c478bd9Sstevel@tonic-gate * recover from the failed block, if possible. 499*7c478bd9Sstevel@tonic-gate * If not, zero the block. In doing so, try to 500*7c478bd9Sstevel@tonic-gate * determine if the new block appears ok. 501*7c478bd9Sstevel@tonic-gate */ 502*7c478bd9Sstevel@tonic-gate if (!buf_is_good) { 503*7c478bd9Sstevel@tonic-gate bzero(buf, SECSIZE); 504*7c478bd9Sstevel@tonic-gate fmt_print("Warning: Block %llu zero-filled.\n", bn); 505*7c478bd9Sstevel@tonic-gate } else { 506*7c478bd9Sstevel@tonic-gate fmt_print("ok.\n"); 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, bn, 509*7c478bd9Sstevel@tonic-gate 1, buf, (F_SILENT | F_ALLERRS), NULL); 510*7c478bd9Sstevel@tonic-gate if (status == 0) { 511*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, bn, 512*7c478bd9Sstevel@tonic-gate 1, buf, (F_SILENT | F_ALLERRS), NULL); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate if (status) { 515*7c478bd9Sstevel@tonic-gate fmt_print("The new block also appears defective.\n"); 516*7c478bd9Sstevel@tonic-gate } 517*7c478bd9Sstevel@tonic-gate fmt_print("\n"); 518*7c478bd9Sstevel@tonic-gate /* 519*7c478bd9Sstevel@tonic-gate * add the defect to the list and write the list out. 520*7c478bd9Sstevel@tonic-gate * Also, kill the working list so it will get resynced 521*7c478bd9Sstevel@tonic-gate * with the current list. 522*7c478bd9Sstevel@tonic-gate * 523*7c478bd9Sstevel@tonic-gate * For embedded scsi, we don't require a defect list. 524*7c478bd9Sstevel@tonic-gate * However, if we have one, add the defect if the 525*7c478bd9Sstevel@tonic-gate * list includes the grown list. If not, kill it 526*7c478bd9Sstevel@tonic-gate * to force a resync if we need the list later. 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate if (EMBEDDED_SCSI) { 529*7c478bd9Sstevel@tonic-gate if (cur_list.list != NULL) { 530*7c478bd9Sstevel@tonic-gate if (cur_list.flags & LIST_PGLIST) { 531*7c478bd9Sstevel@tonic-gate add_ldef(bn, &cur_list); 532*7c478bd9Sstevel@tonic-gate } else { 533*7c478bd9Sstevel@tonic-gate kill_deflist(&cur_list); 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate /* 537*7c478bd9Sstevel@tonic-gate * The next "if" statement reflects the fix for 538*7c478bd9Sstevel@tonic-gate * bug id 1026096 where format keeps adding the 539*7c478bd9Sstevel@tonic-gate * same defect to the defect list. 540*7c478bd9Sstevel@tonic-gate */ 541*7c478bd9Sstevel@tonic-gate } else if (cur_ctype->ctype_flags & CF_WLIST) { 542*7c478bd9Sstevel@tonic-gate kill_deflist(&cur_list); 543*7c478bd9Sstevel@tonic-gate (*cur_ops->op_ex_cur)(&cur_list); 544*7c478bd9Sstevel@tonic-gate fmt_print("Current list updated\n"); 545*7c478bd9Sstevel@tonic-gate } else { 546*7c478bd9Sstevel@tonic-gate add_ldef(bn, &cur_list); 547*7c478bd9Sstevel@tonic-gate write_deflist(&cur_list); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate kill_deflist(&work_list); 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate /* Log the repair. */ 552*7c478bd9Sstevel@tonic-gate scan_blocks_fixed++; 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* return ok */ 555*7c478bd9Sstevel@tonic-gate result = 0; 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate exit_critical(); 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate return (result); 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate /* 565*7c478bd9Sstevel@tonic-gate * This routine analyzes a set of sectors on the disk. It simply returns 566*7c478bd9Sstevel@tonic-gate * an error if a defect is found. It is called by do_scan(). 567*7c478bd9Sstevel@tonic-gate */ 568*7c478bd9Sstevel@tonic-gate static int 569*7c478bd9Sstevel@tonic-gate analyze_blocks(flags, blkno, blkcnt, data, init, driver_flags, xfercntp) 570*7c478bd9Sstevel@tonic-gate int flags, driver_flags, blkcnt, init; 571*7c478bd9Sstevel@tonic-gate register unsigned data; 572*7c478bd9Sstevel@tonic-gate diskaddr_t blkno; 573*7c478bd9Sstevel@tonic-gate int *xfercntp; 574*7c478bd9Sstevel@tonic-gate { 575*7c478bd9Sstevel@tonic-gate int corrupt = 0; 576*7c478bd9Sstevel@tonic-gate register int status, i, nints; 577*7c478bd9Sstevel@tonic-gate register unsigned *ptr = (uint_t *)pattern_buf; 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate media_error = 0; 580*7c478bd9Sstevel@tonic-gate if (flags & SCAN_VERIFY) { 581*7c478bd9Sstevel@tonic-gate return (verify_blocks(flags, blkno, blkcnt, data, 582*7c478bd9Sstevel@tonic-gate driver_flags, xfercntp)); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* 586*7c478bd9Sstevel@tonic-gate * Initialize the pattern buffer if necessary. 587*7c478bd9Sstevel@tonic-gate */ 588*7c478bd9Sstevel@tonic-gate nints = blkcnt * SECSIZE / sizeof (int); 589*7c478bd9Sstevel@tonic-gate if ((flags & SCAN_PATTERN) && init) { 590*7c478bd9Sstevel@tonic-gate for (i = 0; i < nints; i++) 591*7c478bd9Sstevel@tonic-gate *((int *)((int *)pattern_buf + i)) = data; 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * Lock out interrupts so we can insure valid data will get 595*7c478bd9Sstevel@tonic-gate * restored. This is necessary because there are modes 596*7c478bd9Sstevel@tonic-gate * of scanning that corrupt the disk data then restore it at 597*7c478bd9Sstevel@tonic-gate * the end of the analysis. 598*7c478bd9Sstevel@tonic-gate */ 599*7c478bd9Sstevel@tonic-gate enter_critical(); 600*7c478bd9Sstevel@tonic-gate /* 601*7c478bd9Sstevel@tonic-gate * If the disk data is valid, read it into the data buffer. 602*7c478bd9Sstevel@tonic-gate */ 603*7c478bd9Sstevel@tonic-gate if (flags & SCAN_VALID) { 604*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, blkno, 605*7c478bd9Sstevel@tonic-gate blkcnt, (caddr_t)cur_buf, driver_flags, xfercntp); 606*7c478bd9Sstevel@tonic-gate if (status) 607*7c478bd9Sstevel@tonic-gate goto bad; 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate /* 610*7c478bd9Sstevel@tonic-gate * If we are doing pattern testing, write and read the pattern 611*7c478bd9Sstevel@tonic-gate * from the pattern buffer. 612*7c478bd9Sstevel@tonic-gate */ 613*7c478bd9Sstevel@tonic-gate if (flags & SCAN_PATTERN) { 614*7c478bd9Sstevel@tonic-gate /* 615*7c478bd9Sstevel@tonic-gate * If the disk data was valid, mark it corrupt so we know 616*7c478bd9Sstevel@tonic-gate * to restore it later. 617*7c478bd9Sstevel@tonic-gate */ 618*7c478bd9Sstevel@tonic-gate if (flags & SCAN_VALID) 619*7c478bd9Sstevel@tonic-gate corrupt++; 620*7c478bd9Sstevel@tonic-gate /* 621*7c478bd9Sstevel@tonic-gate * Only write if we're not on the read pass of SCAN_PURGE. 622*7c478bd9Sstevel@tonic-gate */ 623*7c478bd9Sstevel@tonic-gate if (!(flags & SCAN_PURGE_READ_PASS)) { 624*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 625*7c478bd9Sstevel@tonic-gate blkcnt, (caddr_t)pattern_buf, driver_flags, 626*7c478bd9Sstevel@tonic-gate xfercntp); 627*7c478bd9Sstevel@tonic-gate if (status) 628*7c478bd9Sstevel@tonic-gate goto bad; 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate /* 631*7c478bd9Sstevel@tonic-gate * Only read if we are on the read pass of SCAN_PURGE, if we 632*7c478bd9Sstevel@tonic-gate * are purging. 633*7c478bd9Sstevel@tonic-gate */ 634*7c478bd9Sstevel@tonic-gate if ((!(flags & SCAN_PURGE)) || (flags & SCAN_PURGE_READ_PASS)) { 635*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, blkno, 636*7c478bd9Sstevel@tonic-gate blkcnt, (caddr_t)pattern_buf, driver_flags, 637*7c478bd9Sstevel@tonic-gate xfercntp); 638*7c478bd9Sstevel@tonic-gate if (status) 639*7c478bd9Sstevel@tonic-gate goto bad; 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate /* 643*7c478bd9Sstevel@tonic-gate * If we are doing a data compare, make sure the pattern 644*7c478bd9Sstevel@tonic-gate * came back intact. 645*7c478bd9Sstevel@tonic-gate * Only compare if we are on the read pass of SCAN_PURGE, or 646*7c478bd9Sstevel@tonic-gate * we wrote random data instead of the expected data pattern. 647*7c478bd9Sstevel@tonic-gate */ 648*7c478bd9Sstevel@tonic-gate if ((flags & SCAN_COMPARE) || (flags & SCAN_PURGE_READ_PASS)) { 649*7c478bd9Sstevel@tonic-gate for (i = nints, ptr = (uint_t *)pattern_buf; i; i--) 650*7c478bd9Sstevel@tonic-gate if (*ptr++ != data) { 651*7c478bd9Sstevel@tonic-gate err_print("Data miscompare error (expecting "); 652*7c478bd9Sstevel@tonic-gate err_print("0x%x, got 0x%x) at ", data, 653*7c478bd9Sstevel@tonic-gate *((int *)((int *)pattern_buf + 654*7c478bd9Sstevel@tonic-gate (nints - i)))); 655*7c478bd9Sstevel@tonic-gate pr_dblock(err_print, blkno); 656*7c478bd9Sstevel@tonic-gate err_print(", offset = 0x%x.\n", 657*7c478bd9Sstevel@tonic-gate (nints - i) * sizeof (int)); 658*7c478bd9Sstevel@tonic-gate goto bad; 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate /* 662*7c478bd9Sstevel@tonic-gate * If we are supposed to write data out, do so. 663*7c478bd9Sstevel@tonic-gate */ 664*7c478bd9Sstevel@tonic-gate if (flags & SCAN_WRITE) { 665*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 666*7c478bd9Sstevel@tonic-gate blkcnt, (caddr_t)cur_buf, driver_flags, xfercntp); 667*7c478bd9Sstevel@tonic-gate if (status) 668*7c478bd9Sstevel@tonic-gate goto bad; 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate exit_critical(); 671*7c478bd9Sstevel@tonic-gate /* 672*7c478bd9Sstevel@tonic-gate * No errors occurred, return ok. 673*7c478bd9Sstevel@tonic-gate */ 674*7c478bd9Sstevel@tonic-gate return (0); 675*7c478bd9Sstevel@tonic-gate bad: 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * There was an error. If the data was corrupted, we write it 678*7c478bd9Sstevel@tonic-gate * out from the data buffer to restore it. 679*7c478bd9Sstevel@tonic-gate */ 680*7c478bd9Sstevel@tonic-gate if (corrupt) { 681*7c478bd9Sstevel@tonic-gate if ((*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 682*7c478bd9Sstevel@tonic-gate blkcnt, (caddr_t)cur_buf, F_NORMAL, xfercntp)) 683*7c478bd9Sstevel@tonic-gate err_print("Warning: unable to restore original data.\n"); 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate exit_critical(); 686*7c478bd9Sstevel@tonic-gate /* 687*7c478bd9Sstevel@tonic-gate * Return the error. 688*7c478bd9Sstevel@tonic-gate */ 689*7c478bd9Sstevel@tonic-gate return (-1); 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* 694*7c478bd9Sstevel@tonic-gate * This routine analyzes a set of sectors on the disk. It simply returns 695*7c478bd9Sstevel@tonic-gate * an error if a defect is found. It is called by analyze_blocks(). 696*7c478bd9Sstevel@tonic-gate * For simplicity, this is done as a separate function instead of 697*7c478bd9Sstevel@tonic-gate * making the analyze_block routine complex. 698*7c478bd9Sstevel@tonic-gate * 699*7c478bd9Sstevel@tonic-gate * This routine implements the 'verify' command. It writes the disk 700*7c478bd9Sstevel@tonic-gate * by writing unique data for each block; after the write pass, it 701*7c478bd9Sstevel@tonic-gate * reads the data and verifies for correctness. Note that the entire 702*7c478bd9Sstevel@tonic-gate * disk (or the range of disk) is fully written first and then read. 703*7c478bd9Sstevel@tonic-gate * This should eliminate any caching effect on the drives. 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate static int 706*7c478bd9Sstevel@tonic-gate verify_blocks(int flags, 707*7c478bd9Sstevel@tonic-gate diskaddr_t blkno, 708*7c478bd9Sstevel@tonic-gate int blkcnt, 709*7c478bd9Sstevel@tonic-gate unsigned data, 710*7c478bd9Sstevel@tonic-gate int driver_flags, 711*7c478bd9Sstevel@tonic-gate int *xfercntp) 712*7c478bd9Sstevel@tonic-gate { 713*7c478bd9Sstevel@tonic-gate int status, i, nints; 714*7c478bd9Sstevel@tonic-gate unsigned *ptr = (uint_t *)pattern_buf; 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate nints = SECSIZE / sizeof (int); 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate /* 719*7c478bd9Sstevel@tonic-gate * Initialize the pattern buffer if we are in write pass. 720*7c478bd9Sstevel@tonic-gate * Use the block number itself as data, each block has unique 721*7c478bd9Sstevel@tonic-gate * buffer data that way. 722*7c478bd9Sstevel@tonic-gate */ 723*7c478bd9Sstevel@tonic-gate if (!(flags & SCAN_VERIFY_READ_PASS)) { 724*7c478bd9Sstevel@tonic-gate for (data = blkno; data < blkno + blkcnt; data++) { 725*7c478bd9Sstevel@tonic-gate for (i = 0; i < nints; i++) { 726*7c478bd9Sstevel@tonic-gate *ptr++ = data; 727*7c478bd9Sstevel@tonic-gate } 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate ptr = (uint_t *)pattern_buf; 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* 733*7c478bd9Sstevel@tonic-gate * Only write if we're not on the read pass of SCAN_VERIFY. 734*7c478bd9Sstevel@tonic-gate */ 735*7c478bd9Sstevel@tonic-gate if (!(flags & SCAN_VERIFY_READ_PASS)) { 736*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, blkno, 737*7c478bd9Sstevel@tonic-gate blkcnt, (caddr_t)pattern_buf, driver_flags, xfercntp); 738*7c478bd9Sstevel@tonic-gate if (status) 739*7c478bd9Sstevel@tonic-gate goto bad; 740*7c478bd9Sstevel@tonic-gate } else { 741*7c478bd9Sstevel@tonic-gate /* 742*7c478bd9Sstevel@tonic-gate * Only read if we are on the read pass of SCAN_VERIFY 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, blkno, 745*7c478bd9Sstevel@tonic-gate blkcnt, (caddr_t)pattern_buf, driver_flags, xfercntp); 746*7c478bd9Sstevel@tonic-gate if (status) 747*7c478bd9Sstevel@tonic-gate goto bad; 748*7c478bd9Sstevel@tonic-gate /* 749*7c478bd9Sstevel@tonic-gate * compare and make sure the pattern came back intact. 750*7c478bd9Sstevel@tonic-gate */ 751*7c478bd9Sstevel@tonic-gate for (data = blkno; data < blkno + blkcnt; data++) { 752*7c478bd9Sstevel@tonic-gate for (i = 0; i < nints; i++) { 753*7c478bd9Sstevel@tonic-gate if (*ptr++ != data) { 754*7c478bd9Sstevel@tonic-gate ptr--; 755*7c478bd9Sstevel@tonic-gate err_print("Data miscompare error (expecting " 756*7c478bd9Sstevel@tonic-gate "0x%x, got 0x%x) at ", data, *ptr); 757*7c478bd9Sstevel@tonic-gate pr_dblock(err_print, blkno); 758*7c478bd9Sstevel@tonic-gate err_print(", offset = 0x%x.\n", (ptr - 759*7c478bd9Sstevel@tonic-gate (uint_t *)pattern_buf) * sizeof (int)); 760*7c478bd9Sstevel@tonic-gate goto bad; 761*7c478bd9Sstevel@tonic-gate } 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate } 765*7c478bd9Sstevel@tonic-gate /* 766*7c478bd9Sstevel@tonic-gate * No errors occurred, return ok. 767*7c478bd9Sstevel@tonic-gate */ 768*7c478bd9Sstevel@tonic-gate return (0); 769*7c478bd9Sstevel@tonic-gate bad: 770*7c478bd9Sstevel@tonic-gate return (-1); 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate static int 775*7c478bd9Sstevel@tonic-gate handle_error_conditions() 776*7c478bd9Sstevel@tonic-gate { 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* 779*7c478bd9Sstevel@tonic-gate * Check if the errno is ENXIO. 780*7c478bd9Sstevel@tonic-gate */ 781*7c478bd9Sstevel@tonic-gate if (errno == ENXIO) { 782*7c478bd9Sstevel@tonic-gate fmt_print("\n\nWarning:Cannot access drive, "); 783*7c478bd9Sstevel@tonic-gate fmt_print("aborting surface analysis.\n"); 784*7c478bd9Sstevel@tonic-gate return (-1); 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate /* 787*7c478bd9Sstevel@tonic-gate * check for disk errors 788*7c478bd9Sstevel@tonic-gate */ 789*7c478bd9Sstevel@tonic-gate switch (disk_error) { 790*7c478bd9Sstevel@tonic-gate case DISK_STAT_RESERVED: 791*7c478bd9Sstevel@tonic-gate case DISK_STAT_UNAVAILABLE: 792*7c478bd9Sstevel@tonic-gate fmt_print("\n\nWarning:Drive may be reserved "); 793*7c478bd9Sstevel@tonic-gate fmt_print("or has been removed, "); 794*7c478bd9Sstevel@tonic-gate fmt_print("aborting surface analysis.\n"); 795*7c478bd9Sstevel@tonic-gate return (-1); 796*7c478bd9Sstevel@tonic-gate case DISK_STAT_NOTREADY: 797*7c478bd9Sstevel@tonic-gate fmt_print("\n\nWarning: Drive not ready, "); 798*7c478bd9Sstevel@tonic-gate fmt_print("aborting surface analysis.\n"); 799*7c478bd9Sstevel@tonic-gate return (-1); 800*7c478bd9Sstevel@tonic-gate case DISK_STAT_DATA_PROTECT: 801*7c478bd9Sstevel@tonic-gate fmt_print("\n\nWarning: Drive is write protected, "); 802*7c478bd9Sstevel@tonic-gate fmt_print("aborting surface analysis.\n"); 803*7c478bd9Sstevel@tonic-gate return (-1); 804*7c478bd9Sstevel@tonic-gate default: 805*7c478bd9Sstevel@tonic-gate break; 806*7c478bd9Sstevel@tonic-gate } 807*7c478bd9Sstevel@tonic-gate return (0); 808*7c478bd9Sstevel@tonic-gate } 809