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