1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * diskscan: 31 * performs a verification pass over a device specified on command line; 32 * display progress on stdout, and print bad sector numbers to stderr 33 */ 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 #include <stropts.h> 39 #include <memory.h> 40 #include <ctype.h> 41 #include <malloc.h> 42 #include <signal.h> 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/stat.h> 46 #include <sys/vtoc.h> 47 #include <sys/dkio.h> 48 49 static void verexit(); /* signal handler and exit routine */ 50 static void report(); /* tell user how we're getting on */ 51 static void scandisk(char *device, int devfd, int writeflag); 52 static void report(char *what, int sector); 53 static void verexit(int code); 54 55 #define TRUE 1 56 #define FALSE 0 57 #define VER_WRITE 1 58 #define VER_READ 2 59 60 static char *progname; 61 static struct dk_geom dkg; /* physical device boot info */ 62 static char replybuf[64]; /* used for user replies to questions */ 63 static daddr_t unix_base; /* first sector of UNIX System partition */ 64 static daddr_t unix_size; /* # sectors in UNIX System partition */ 65 static long numbadrd = 0; /* number of bad sectors on read */ 66 static long numbadwr = 0; /* number of bad sectors on write */ 67 static char eol = '\n'; /* end-of-line char (if -n, we set to '\n') */ 68 static int print_warn = 1; /* should the warning message be printed? */ 69 static int do_scan = VER_READ; 70 71 int 72 main(int argc, char *argv[]) { 73 extern int optind; 74 int devfd; /* device file descriptor */ 75 struct stat statbuf; 76 struct part_info part_info; 77 int c; 78 int errflag = 0; 79 char *device; 80 progname = argv[0]; 81 82 /* Don't buffer stdout - we don't want to see bursts */ 83 84 setbuf(stdout, NULL); 85 86 while ((c = getopt(argc, argv, "Wny")) != -1) 87 { 88 switch (c) { 89 case 'W': 90 do_scan = VER_WRITE; 91 break; 92 93 case 'n': 94 eol = '\r'; 95 break; 96 97 case 'y': 98 print_warn = 0; 99 break; 100 101 default: 102 ++errflag; 103 break; 104 } 105 } 106 107 if ((argc - optind) < 1) 108 errflag++; 109 110 if (errflag) { 111 (void) fprintf(stderr, 112 "\nUsage: %s [-W] [-n] [-y] <phys_device_name> \n", 113 progname); 114 exit(1); 115 } 116 117 device = argv[optind]; 118 119 if (stat(device, &statbuf)) { 120 (void) fprintf(stderr, 121 "%s: invalid device %s, stat failed\n", progname, device); 122 perror(""); 123 exit(4); 124 } 125 if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 126 (void) fprintf(stderr, 127 "%s: device %s is not character special\n", 128 progname, device); 129 exit(5); 130 } 131 if ((devfd = open(device, O_RDWR)) == -1) { 132 (void) fprintf(stderr, 133 "%s: open of %s failed\n", progname, device); 134 perror(""); 135 exit(8); 136 } 137 138 if ((ioctl(devfd, DKIOCGGEOM, &dkg)) == -1) { 139 (void) fprintf(stderr, 140 "%s: unable to get disk geometry.\n", progname); 141 perror(""); 142 exit(9); 143 } 144 if ((ioctl(devfd, DKIOCPARTINFO, &part_info)) == -1) { 145 (void) fprintf(stderr, "%s: unable to get partition info.\n", 146 progname); 147 perror(""); 148 exit(9); 149 } 150 151 unix_base = part_info.p_start; 152 unix_size = part_info.p_length; 153 scandisk(device, devfd, do_scan); 154 return (0); 155 } 156 157 /* 158 * scandisk: 159 * attempt to read every sector of the drive; 160 * display bad sectors found on stderr 161 */ 162 163 static void 164 scandisk(char *device, int devfd, int writeflag) 165 { 166 int trksiz = NBPSCTR * dkg.dkg_nsect; 167 char *verbuf; 168 daddr_t cursec; 169 int cylsiz = dkg.dkg_nsect * dkg.dkg_nhead; 170 int i; 171 char *rptr; 172 long tmpend = 0; 173 long tmpsec = 0; 174 175 /* #define LIBMALLOC */ 176 177 #ifdef LIBMALLOC 178 179 extern int mallopt(); 180 181 /* This adds 5k to the binary, but it's a lot prettier */ 182 183 184 /* make track buffer sector aligned */ 185 if (mallopt(M_GRAIN, 0x200)) { 186 perror("mallopt"); 187 exit(1); 188 } 189 if ((verbuf = malloc(NBPSCTR * dkg.dkg_nsect)) == (char *)NULL) { 190 perror("malloc"); 191 exit(1); 192 } 193 194 #else 195 196 if ((verbuf = malloc(0x200 + NBPSCTR * dkg.dkg_nsect)) 197 == (char *)NULL) { 198 perror("malloc"); 199 exit(1); 200 } 201 verbuf = (char *)(((unsigned long)verbuf + 0x00000200) & 0xfffffe00); 202 203 #endif 204 205 /* write pattern in track buffer */ 206 207 for (i = 0; i < trksiz; i++) 208 verbuf[i] = (char)0xe5; 209 210 /* Turn off retry, and set trap to turn them on again */ 211 212 (void) signal(SIGINT, verexit); 213 (void) signal(SIGQUIT, verexit); 214 215 if (writeflag == VER_READ) 216 goto do_readonly; 217 218 /* 219 * display warning only if -n arg not passed 220 * (otherwise the UI system will take care of it) 221 */ 222 223 if (print_warn == 1) { 224 (void) printf( 225 "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device); 226 (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n"); 227 (void) printf(" THAT PARTITION OR SLICE.\n"); 228 (void) printf("Do you want to continue (y/n)? "); 229 230 rptr = fgets(replybuf, 64*sizeof (char), stdin); 231 if (!rptr || !((replybuf[0] == 'Y') || (replybuf[0] == 'y'))) 232 exit(10); 233 } 234 235 for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 236 if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 237 (void) fprintf(stderr, 238 "Error seeking sector %ld Cylinder %ld\n", 239 cursec, cursec / cylsiz); 240 verexit(1); 241 } 242 243 /* 244 * verify sector at a time only when 245 * the whole track write fails; 246 * (if we write a sector at a time, it takes forever) 247 */ 248 249 report("Writing", cursec); 250 251 if (write(devfd, verbuf, trksiz) != trksiz) { 252 tmpend = cursec + dkg.dkg_nsect; 253 for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 254 /* 255 * try writing to it once; if this fails, 256 * then announce the sector bad on stderr 257 */ 258 259 if (lseek 260 (devfd, (long)tmpsec * NBPSCTR, 0) == -1) { 261 (void) fprintf(stderr, "Error seeking " 262 "sector %ld Cylinder %ld\n", 263 tmpsec, cursec / cylsiz); 264 verexit(1); 265 } 266 267 report("Writing", tmpsec); 268 269 if (write(devfd, verbuf, NBPSCTR) != NBPSCTR) { 270 (void) fprintf(stderr, 271 "%ld\n", tmpsec + unix_base); 272 numbadwr++; 273 } 274 } 275 } 276 } 277 278 (void) putchar(eol); 279 do_readonly: 280 281 for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 282 if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 283 (void) fprintf(stderr, 284 "Error seeking sector %ld Cylinder %ld\n", 285 cursec, cursec / cylsiz); 286 verexit(1); 287 } 288 289 /* 290 * read a sector at a time only when 291 * the whole track write fails; 292 * (if we do a sector at a time read, it takes forever) 293 */ 294 295 report("Reading", cursec); 296 if (read(devfd, verbuf, trksiz) != trksiz) { 297 tmpend = cursec + dkg.dkg_nsect; 298 for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 299 if (lseek(devfd, (long)tmpsec * NBPSCTR, 0) 300 == -1) { 301 (void) fprintf(stderr, "Error seeking" 302 " sector %ld Cylinder %ld\n", 303 tmpsec, cursec / cylsiz); 304 verexit(1); 305 } 306 report("Reading", tmpsec); 307 if (read(devfd, verbuf, NBPSCTR) != NBPSCTR) { 308 (void) fprintf(stderr, "%ld\n", 309 tmpsec + unix_base); 310 numbadrd++; 311 } 312 } 313 } 314 } 315 (void) printf("%c%c======== Diskscan complete ========%c", eol, 316 eol, eol); 317 318 if ((numbadrd > 0) || (numbadwr > 0)) { 319 (void) printf("%cFound %ld bad sector(s) on read," 320 " %ld bad sector(s) on write%c", 321 eol, numbadrd, numbadwr, eol); 322 } 323 } 324 325 static void 326 verexit(int code) 327 { 328 (void) printf("\n"); 329 exit(code); 330 } 331 332 333 /* 334 * report where we are... 335 */ 336 337 static void 338 report(char *what, int sector) 339 { 340 (void) printf("%s sector %-7d of %-7ld%c", what, sector, 341 unix_size, eol); 342 } 343