17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * diskscan: 317c478bd9Sstevel@tonic-gate * performs a verification pass over a device specified on command line; 327c478bd9Sstevel@tonic-gate * display progress on stdout, and print bad sector numbers to stderr 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <stdlib.h> 367c478bd9Sstevel@tonic-gate #include <fcntl.h> 377c478bd9Sstevel@tonic-gate #include <unistd.h> 387c478bd9Sstevel@tonic-gate #include <stropts.h> 397c478bd9Sstevel@tonic-gate #include <memory.h> 407c478bd9Sstevel@tonic-gate #include <ctype.h> 417c478bd9Sstevel@tonic-gate #include <malloc.h> 427c478bd9Sstevel@tonic-gate #include <signal.h> 437c478bd9Sstevel@tonic-gate #include <sys/types.h> 447c478bd9Sstevel@tonic-gate #include <sys/param.h> 457c478bd9Sstevel@tonic-gate #include <sys/stat.h> 467c478bd9Sstevel@tonic-gate #include <sys/vtoc.h> 477c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate static void verexit(); /* signal handler and exit routine */ 507c478bd9Sstevel@tonic-gate static void report(); /* tell user how we're getting on */ 517c478bd9Sstevel@tonic-gate static void scandisk(char *device, int devfd, int writeflag); 527c478bd9Sstevel@tonic-gate static void report(char *what, int sector); 537c478bd9Sstevel@tonic-gate static void verexit(int code); 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #define TRUE 1 567c478bd9Sstevel@tonic-gate #define FALSE 0 577c478bd9Sstevel@tonic-gate #define VER_WRITE 1 587c478bd9Sstevel@tonic-gate #define VER_READ 2 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate static char *progname; 617c478bd9Sstevel@tonic-gate static struct dk_geom dkg; /* physical device boot info */ 627c478bd9Sstevel@tonic-gate static char replybuf[64]; /* used for user replies to questions */ 637c478bd9Sstevel@tonic-gate static daddr_t unix_base; /* first sector of UNIX System partition */ 647c478bd9Sstevel@tonic-gate static daddr_t unix_size; /* # sectors in UNIX System partition */ 657c478bd9Sstevel@tonic-gate static long numbadrd = 0; /* number of bad sectors on read */ 667c478bd9Sstevel@tonic-gate static long numbadwr = 0; /* number of bad sectors on write */ 677c478bd9Sstevel@tonic-gate static char eol = '\n'; /* end-of-line char (if -n, we set to '\n') */ 687c478bd9Sstevel@tonic-gate static int print_warn = 1; /* should the warning message be printed? */ 697c478bd9Sstevel@tonic-gate static int do_scan = VER_READ; 707c478bd9Sstevel@tonic-gate 71*052b6e8aSbg159949 int 727c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) { 737c478bd9Sstevel@tonic-gate extern int optind; 747c478bd9Sstevel@tonic-gate int devfd; /* device file descriptor */ 757c478bd9Sstevel@tonic-gate struct stat statbuf; 767c478bd9Sstevel@tonic-gate struct part_info part_info; 777c478bd9Sstevel@tonic-gate int c; 787c478bd9Sstevel@tonic-gate int errflag = 0; 797c478bd9Sstevel@tonic-gate char *device; 807c478bd9Sstevel@tonic-gate progname = argv[0]; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* Don't buffer stdout - we don't want to see bursts */ 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate setbuf(stdout, NULL); 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "Wny")) != -1) 877c478bd9Sstevel@tonic-gate { 887c478bd9Sstevel@tonic-gate switch (c) { 897c478bd9Sstevel@tonic-gate case 'W': 907c478bd9Sstevel@tonic-gate do_scan = VER_WRITE; 917c478bd9Sstevel@tonic-gate break; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate case 'n': 947c478bd9Sstevel@tonic-gate eol = '\r'; 957c478bd9Sstevel@tonic-gate break; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate case 'y': 987c478bd9Sstevel@tonic-gate print_warn = 0; 997c478bd9Sstevel@tonic-gate break; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate default: 1027c478bd9Sstevel@tonic-gate ++errflag; 1037c478bd9Sstevel@tonic-gate break; 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if ((argc - optind) < 1) 1087c478bd9Sstevel@tonic-gate errflag++; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate if (errflag) { 1117c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1127c478bd9Sstevel@tonic-gate "\nUsage: %s [-W] [-n] [-y] <phys_device_name> \n", 1137c478bd9Sstevel@tonic-gate progname); 1147c478bd9Sstevel@tonic-gate exit(1); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate device = argv[optind]; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate if (stat(device, &statbuf)) { 1207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1217c478bd9Sstevel@tonic-gate "%s: invalid device %s, stat failed\n", progname, device); 1227c478bd9Sstevel@tonic-gate perror(""); 1237c478bd9Sstevel@tonic-gate exit(4); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 1267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1277c478bd9Sstevel@tonic-gate "%s: device %s is not character special\n", 1287c478bd9Sstevel@tonic-gate progname, device); 1297c478bd9Sstevel@tonic-gate exit(5); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate if ((devfd = open(device, O_RDWR)) == -1) { 1327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1337c478bd9Sstevel@tonic-gate "%s: open of %s failed\n", progname, device); 1347c478bd9Sstevel@tonic-gate perror(""); 1357c478bd9Sstevel@tonic-gate exit(8); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate if ((ioctl(devfd, DKIOCGGEOM, &dkg)) == -1) { 1397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1407c478bd9Sstevel@tonic-gate "%s: unable to get disk geometry.\n", progname); 1417c478bd9Sstevel@tonic-gate perror(""); 1427c478bd9Sstevel@tonic-gate exit(9); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate if ((ioctl(devfd, DKIOCPARTINFO, &part_info)) == -1) { 1457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to get partition info.\n", 1467c478bd9Sstevel@tonic-gate progname); 1477c478bd9Sstevel@tonic-gate perror(""); 1487c478bd9Sstevel@tonic-gate exit(9); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate unix_base = part_info.p_start; 1527c478bd9Sstevel@tonic-gate unix_size = part_info.p_length; 1537c478bd9Sstevel@tonic-gate scandisk(device, devfd, do_scan); 154*052b6e8aSbg159949 return (0); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * scandisk: 1597c478bd9Sstevel@tonic-gate * attempt to read every sector of the drive; 1607c478bd9Sstevel@tonic-gate * display bad sectors found on stderr 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate static void 1647c478bd9Sstevel@tonic-gate scandisk(char *device, int devfd, int writeflag) 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate int trksiz = NBPSCTR * dkg.dkg_nsect; 1677c478bd9Sstevel@tonic-gate char *verbuf; 1687c478bd9Sstevel@tonic-gate daddr_t cursec; 1697c478bd9Sstevel@tonic-gate int cylsiz = dkg.dkg_nsect * dkg.dkg_nhead; 1707c478bd9Sstevel@tonic-gate int i; 1717c478bd9Sstevel@tonic-gate char *rptr; 1727c478bd9Sstevel@tonic-gate long tmpend = 0; 1737c478bd9Sstevel@tonic-gate long tmpsec = 0; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* #define LIBMALLOC */ 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate #ifdef LIBMALLOC 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate extern int mallopt(); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* This adds 5k to the binary, but it's a lot prettier */ 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* make track buffer sector aligned */ 1857c478bd9Sstevel@tonic-gate if (mallopt(M_GRAIN, 0x200)) { 1867c478bd9Sstevel@tonic-gate perror("mallopt"); 1877c478bd9Sstevel@tonic-gate exit(1); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate if ((verbuf = malloc(NBPSCTR * dkg.dkg_nsect)) == (char *)NULL) { 1907c478bd9Sstevel@tonic-gate perror("malloc"); 1917c478bd9Sstevel@tonic-gate exit(1); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate #else 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate if ((verbuf = malloc(0x200 + NBPSCTR * dkg.dkg_nsect)) 1977c478bd9Sstevel@tonic-gate == (char *)NULL) { 1987c478bd9Sstevel@tonic-gate perror("malloc"); 1997c478bd9Sstevel@tonic-gate exit(1); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate verbuf = (char *)(((unsigned long)verbuf + 0x00000200) & 0xfffffe00); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate #endif 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* write pattern in track buffer */ 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate for (i = 0; i < trksiz; i++) 2087c478bd9Sstevel@tonic-gate verbuf[i] = (char)0xe5; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* Turn off retry, and set trap to turn them on again */ 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate (void) signal(SIGINT, verexit); 2137c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, verexit); 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate if (writeflag == VER_READ) 2167c478bd9Sstevel@tonic-gate goto do_readonly; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * display warning only if -n arg not passed 2207c478bd9Sstevel@tonic-gate * (otherwise the UI system will take care of it) 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate if (print_warn == 1) { 2247c478bd9Sstevel@tonic-gate (void) printf( 2257c478bd9Sstevel@tonic-gate "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device); 2267c478bd9Sstevel@tonic-gate (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n"); 2277c478bd9Sstevel@tonic-gate (void) printf(" THAT PARTITION OR SLICE.\n"); 2287c478bd9Sstevel@tonic-gate (void) printf("Do you want to continue (y/n)? "); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate rptr = fgets(replybuf, 64*sizeof (char), stdin); 2317c478bd9Sstevel@tonic-gate if (!rptr || !((replybuf[0] == 'Y') || (replybuf[0] == 'y'))) 2327c478bd9Sstevel@tonic-gate exit(10); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 2367c478bd9Sstevel@tonic-gate if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 2377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2387c478bd9Sstevel@tonic-gate "Error seeking sector %ld Cylinder %ld\n", 2397c478bd9Sstevel@tonic-gate cursec, cursec / cylsiz); 2407c478bd9Sstevel@tonic-gate verexit(1); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /* 2447c478bd9Sstevel@tonic-gate * verify sector at a time only when 2457c478bd9Sstevel@tonic-gate * the whole track write fails; 2467c478bd9Sstevel@tonic-gate * (if we write a sector at a time, it takes forever) 2477c478bd9Sstevel@tonic-gate */ 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate report("Writing", cursec); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (write(devfd, verbuf, trksiz) != trksiz) { 2527c478bd9Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 2537c478bd9Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 2547c478bd9Sstevel@tonic-gate /* 2557c478bd9Sstevel@tonic-gate * try writing to it once; if this fails, 2567c478bd9Sstevel@tonic-gate * then announce the sector bad on stderr 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate if (lseek 2607c478bd9Sstevel@tonic-gate (devfd, (long)tmpsec * NBPSCTR, 0) == -1) { 2617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking " 2627c478bd9Sstevel@tonic-gate "sector %ld Cylinder %ld\n", 2637c478bd9Sstevel@tonic-gate tmpsec, cursec / cylsiz); 2647c478bd9Sstevel@tonic-gate verexit(1); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate report("Writing", tmpsec); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (write(devfd, verbuf, NBPSCTR) != NBPSCTR) { 2707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2717c478bd9Sstevel@tonic-gate "%ld\n", tmpsec + unix_base); 2727c478bd9Sstevel@tonic-gate numbadwr++; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate (void) putchar(eol); 2797c478bd9Sstevel@tonic-gate do_readonly: 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 2827c478bd9Sstevel@tonic-gate if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 2837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2847c478bd9Sstevel@tonic-gate "Error seeking sector %ld Cylinder %ld\n", 2857c478bd9Sstevel@tonic-gate cursec, cursec / cylsiz); 2867c478bd9Sstevel@tonic-gate verexit(1); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * read a sector at a time only when 2917c478bd9Sstevel@tonic-gate * the whole track write fails; 2927c478bd9Sstevel@tonic-gate * (if we do a sector at a time read, it takes forever) 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate report("Reading", cursec); 2967c478bd9Sstevel@tonic-gate if (read(devfd, verbuf, trksiz) != trksiz) { 2977c478bd9Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 2987c478bd9Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 2997c478bd9Sstevel@tonic-gate if (lseek(devfd, (long)tmpsec * NBPSCTR, 0) 3007c478bd9Sstevel@tonic-gate == -1) { 3017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking" 3027c478bd9Sstevel@tonic-gate " sector %ld Cylinder %ld\n", 3037c478bd9Sstevel@tonic-gate tmpsec, cursec / cylsiz); 3047c478bd9Sstevel@tonic-gate verexit(1); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate report("Reading", tmpsec); 3077c478bd9Sstevel@tonic-gate if (read(devfd, verbuf, NBPSCTR) != NBPSCTR) { 3087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%ld\n", 3097c478bd9Sstevel@tonic-gate tmpsec + unix_base); 3107c478bd9Sstevel@tonic-gate numbadrd++; 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate (void) printf("%c%c======== Diskscan complete ========%c", eol, 3167c478bd9Sstevel@tonic-gate eol, eol); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if ((numbadrd > 0) || (numbadwr > 0)) { 3197c478bd9Sstevel@tonic-gate (void) printf("%cFound %ld bad sector(s) on read," 3207c478bd9Sstevel@tonic-gate " %ld bad sector(s) on write%c", 3217c478bd9Sstevel@tonic-gate eol, numbadrd, numbadwr, eol); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate static void 3267c478bd9Sstevel@tonic-gate verexit(int code) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate (void) printf("\n"); 3297c478bd9Sstevel@tonic-gate exit(code); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * report where we are... 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate static void 3387c478bd9Sstevel@tonic-gate report(char *what, int sector) 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate (void) printf("%s sector %-7d of %-7ld%c", what, sector, 3417c478bd9Sstevel@tonic-gate unix_size, eol); 3427c478bd9Sstevel@tonic-gate } 343