10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * diskscan: 310Sstevel@tonic-gate * performs a verification pass over a device specified on command line; 320Sstevel@tonic-gate * display progress on stdout, and print bad sector numbers to stderr 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate #include <stdio.h> 350Sstevel@tonic-gate #include <stdlib.h> 360Sstevel@tonic-gate #include <fcntl.h> 370Sstevel@tonic-gate #include <unistd.h> 380Sstevel@tonic-gate #include <stropts.h> 390Sstevel@tonic-gate #include <memory.h> 400Sstevel@tonic-gate #include <ctype.h> 410Sstevel@tonic-gate #include <malloc.h> 420Sstevel@tonic-gate #include <signal.h> 430Sstevel@tonic-gate #include <sys/types.h> 440Sstevel@tonic-gate #include <sys/param.h> 450Sstevel@tonic-gate #include <sys/stat.h> 460Sstevel@tonic-gate #include <sys/vtoc.h> 470Sstevel@tonic-gate #include <sys/dkio.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate static void verexit(); /* signal handler and exit routine */ 500Sstevel@tonic-gate static void report(); /* tell user how we're getting on */ 510Sstevel@tonic-gate static void scandisk(char *device, int devfd, int writeflag); 520Sstevel@tonic-gate static void report(char *what, int sector); 530Sstevel@tonic-gate static void verexit(int code); 540Sstevel@tonic-gate 550Sstevel@tonic-gate #define TRUE 1 560Sstevel@tonic-gate #define FALSE 0 570Sstevel@tonic-gate #define VER_WRITE 1 580Sstevel@tonic-gate #define VER_READ 2 590Sstevel@tonic-gate 600Sstevel@tonic-gate static char *progname; 610Sstevel@tonic-gate static struct dk_geom dkg; /* physical device boot info */ 620Sstevel@tonic-gate static char replybuf[64]; /* used for user replies to questions */ 630Sstevel@tonic-gate static daddr_t unix_base; /* first sector of UNIX System partition */ 640Sstevel@tonic-gate static daddr_t unix_size; /* # sectors in UNIX System partition */ 650Sstevel@tonic-gate static long numbadrd = 0; /* number of bad sectors on read */ 660Sstevel@tonic-gate static long numbadwr = 0; /* number of bad sectors on write */ 670Sstevel@tonic-gate static char eol = '\n'; /* end-of-line char (if -n, we set to '\n') */ 680Sstevel@tonic-gate static int print_warn = 1; /* should the warning message be printed? */ 690Sstevel@tonic-gate static int do_scan = VER_READ; 700Sstevel@tonic-gate 71*362Sbg159949 int 720Sstevel@tonic-gate main(int argc, char *argv[]) { 730Sstevel@tonic-gate extern int optind; 740Sstevel@tonic-gate int devfd; /* device file descriptor */ 750Sstevel@tonic-gate struct stat statbuf; 760Sstevel@tonic-gate struct part_info part_info; 770Sstevel@tonic-gate int c; 780Sstevel@tonic-gate int errflag = 0; 790Sstevel@tonic-gate char *device; 800Sstevel@tonic-gate progname = argv[0]; 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* Don't buffer stdout - we don't want to see bursts */ 830Sstevel@tonic-gate 840Sstevel@tonic-gate setbuf(stdout, NULL); 850Sstevel@tonic-gate 860Sstevel@tonic-gate while ((c = getopt(argc, argv, "Wny")) != -1) 870Sstevel@tonic-gate { 880Sstevel@tonic-gate switch (c) { 890Sstevel@tonic-gate case 'W': 900Sstevel@tonic-gate do_scan = VER_WRITE; 910Sstevel@tonic-gate break; 920Sstevel@tonic-gate 930Sstevel@tonic-gate case 'n': 940Sstevel@tonic-gate eol = '\r'; 950Sstevel@tonic-gate break; 960Sstevel@tonic-gate 970Sstevel@tonic-gate case 'y': 980Sstevel@tonic-gate print_warn = 0; 990Sstevel@tonic-gate break; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate default: 1020Sstevel@tonic-gate ++errflag; 1030Sstevel@tonic-gate break; 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate if ((argc - optind) < 1) 1080Sstevel@tonic-gate errflag++; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate if (errflag) { 1110Sstevel@tonic-gate (void) fprintf(stderr, 1120Sstevel@tonic-gate "\nUsage: %s [-W] [-n] [-y] <phys_device_name> \n", 1130Sstevel@tonic-gate progname); 1140Sstevel@tonic-gate exit(1); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate device = argv[optind]; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate if (stat(device, &statbuf)) { 1200Sstevel@tonic-gate (void) fprintf(stderr, 1210Sstevel@tonic-gate "%s: invalid device %s, stat failed\n", progname, device); 1220Sstevel@tonic-gate perror(""); 1230Sstevel@tonic-gate exit(4); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 1260Sstevel@tonic-gate (void) fprintf(stderr, 1270Sstevel@tonic-gate "%s: device %s is not character special\n", 1280Sstevel@tonic-gate progname, device); 1290Sstevel@tonic-gate exit(5); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate if ((devfd = open(device, O_RDWR)) == -1) { 1320Sstevel@tonic-gate (void) fprintf(stderr, 1330Sstevel@tonic-gate "%s: open of %s failed\n", progname, device); 1340Sstevel@tonic-gate perror(""); 1350Sstevel@tonic-gate exit(8); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate if ((ioctl(devfd, DKIOCGGEOM, &dkg)) == -1) { 1390Sstevel@tonic-gate (void) fprintf(stderr, 1400Sstevel@tonic-gate "%s: unable to get disk geometry.\n", progname); 1410Sstevel@tonic-gate perror(""); 1420Sstevel@tonic-gate exit(9); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate if ((ioctl(devfd, DKIOCPARTINFO, &part_info)) == -1) { 1450Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to get partition info.\n", 1460Sstevel@tonic-gate progname); 1470Sstevel@tonic-gate perror(""); 1480Sstevel@tonic-gate exit(9); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate unix_base = part_info.p_start; 1520Sstevel@tonic-gate unix_size = part_info.p_length; 1530Sstevel@tonic-gate scandisk(device, devfd, do_scan); 154*362Sbg159949 return (0); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * scandisk: 1590Sstevel@tonic-gate * attempt to read every sector of the drive; 1600Sstevel@tonic-gate * display bad sectors found on stderr 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate static void 1640Sstevel@tonic-gate scandisk(char *device, int devfd, int writeflag) 1650Sstevel@tonic-gate { 1660Sstevel@tonic-gate int trksiz = NBPSCTR * dkg.dkg_nsect; 1670Sstevel@tonic-gate char *verbuf; 1680Sstevel@tonic-gate daddr_t cursec; 1690Sstevel@tonic-gate int cylsiz = dkg.dkg_nsect * dkg.dkg_nhead; 1700Sstevel@tonic-gate int i; 1710Sstevel@tonic-gate char *rptr; 1720Sstevel@tonic-gate long tmpend = 0; 1730Sstevel@tonic-gate long tmpsec = 0; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /* #define LIBMALLOC */ 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate #ifdef LIBMALLOC 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate extern int mallopt(); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* This adds 5k to the binary, but it's a lot prettier */ 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate /* make track buffer sector aligned */ 1850Sstevel@tonic-gate if (mallopt(M_GRAIN, 0x200)) { 1860Sstevel@tonic-gate perror("mallopt"); 1870Sstevel@tonic-gate exit(1); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate if ((verbuf = malloc(NBPSCTR * dkg.dkg_nsect)) == (char *)NULL) { 1900Sstevel@tonic-gate perror("malloc"); 1910Sstevel@tonic-gate exit(1); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate #else 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if ((verbuf = malloc(0x200 + NBPSCTR * dkg.dkg_nsect)) 1970Sstevel@tonic-gate == (char *)NULL) { 1980Sstevel@tonic-gate perror("malloc"); 1990Sstevel@tonic-gate exit(1); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate verbuf = (char *)(((unsigned long)verbuf + 0x00000200) & 0xfffffe00); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate #endif 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate /* write pattern in track buffer */ 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate for (i = 0; i < trksiz; i++) 2080Sstevel@tonic-gate verbuf[i] = (char)0xe5; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* Turn off retry, and set trap to turn them on again */ 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate (void) signal(SIGINT, verexit); 2130Sstevel@tonic-gate (void) signal(SIGQUIT, verexit); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate if (writeflag == VER_READ) 2160Sstevel@tonic-gate goto do_readonly; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * display warning only if -n arg not passed 2200Sstevel@tonic-gate * (otherwise the UI system will take care of it) 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate if (print_warn == 1) { 2240Sstevel@tonic-gate (void) printf( 2250Sstevel@tonic-gate "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device); 2260Sstevel@tonic-gate (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n"); 2270Sstevel@tonic-gate (void) printf(" THAT PARTITION OR SLICE.\n"); 2280Sstevel@tonic-gate (void) printf("Do you want to continue (y/n)? "); 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate rptr = fgets(replybuf, 64*sizeof (char), stdin); 2310Sstevel@tonic-gate if (!rptr || !((replybuf[0] == 'Y') || (replybuf[0] == 'y'))) 2320Sstevel@tonic-gate exit(10); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 2360Sstevel@tonic-gate if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 2370Sstevel@tonic-gate (void) fprintf(stderr, 2380Sstevel@tonic-gate "Error seeking sector %ld Cylinder %ld\n", 2390Sstevel@tonic-gate cursec, cursec / cylsiz); 2400Sstevel@tonic-gate verexit(1); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * verify sector at a time only when 2450Sstevel@tonic-gate * the whole track write fails; 2460Sstevel@tonic-gate * (if we write a sector at a time, it takes forever) 2470Sstevel@tonic-gate */ 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate report("Writing", cursec); 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate if (write(devfd, verbuf, trksiz) != trksiz) { 2520Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 2530Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 2540Sstevel@tonic-gate /* 2550Sstevel@tonic-gate * try writing to it once; if this fails, 2560Sstevel@tonic-gate * then announce the sector bad on stderr 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate if (lseek 2600Sstevel@tonic-gate (devfd, (long)tmpsec * NBPSCTR, 0) == -1) { 2610Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking " 2620Sstevel@tonic-gate "sector %ld Cylinder %ld\n", 2630Sstevel@tonic-gate tmpsec, cursec / cylsiz); 2640Sstevel@tonic-gate verexit(1); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate report("Writing", tmpsec); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate if (write(devfd, verbuf, NBPSCTR) != NBPSCTR) { 2700Sstevel@tonic-gate (void) fprintf(stderr, 2710Sstevel@tonic-gate "%ld\n", tmpsec + unix_base); 2720Sstevel@tonic-gate numbadwr++; 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate (void) putchar(eol); 2790Sstevel@tonic-gate do_readonly: 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 2820Sstevel@tonic-gate if (lseek(devfd, (long)cursec * NBPSCTR, 0) == -1) { 2830Sstevel@tonic-gate (void) fprintf(stderr, 2840Sstevel@tonic-gate "Error seeking sector %ld Cylinder %ld\n", 2850Sstevel@tonic-gate cursec, cursec / cylsiz); 2860Sstevel@tonic-gate verexit(1); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * read a sector at a time only when 2910Sstevel@tonic-gate * the whole track write fails; 2920Sstevel@tonic-gate * (if we do a sector at a time read, it takes forever) 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate report("Reading", cursec); 2960Sstevel@tonic-gate if (read(devfd, verbuf, trksiz) != trksiz) { 2970Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 2980Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 2990Sstevel@tonic-gate if (lseek(devfd, (long)tmpsec * NBPSCTR, 0) 3000Sstevel@tonic-gate == -1) { 3010Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking" 3020Sstevel@tonic-gate " sector %ld Cylinder %ld\n", 3030Sstevel@tonic-gate tmpsec, cursec / cylsiz); 3040Sstevel@tonic-gate verexit(1); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate report("Reading", tmpsec); 3070Sstevel@tonic-gate if (read(devfd, verbuf, NBPSCTR) != NBPSCTR) { 3080Sstevel@tonic-gate (void) fprintf(stderr, "%ld\n", 3090Sstevel@tonic-gate tmpsec + unix_base); 3100Sstevel@tonic-gate numbadrd++; 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate (void) printf("%c%c======== Diskscan complete ========%c", eol, 3160Sstevel@tonic-gate eol, eol); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate if ((numbadrd > 0) || (numbadwr > 0)) { 3190Sstevel@tonic-gate (void) printf("%cFound %ld bad sector(s) on read," 3200Sstevel@tonic-gate " %ld bad sector(s) on write%c", 3210Sstevel@tonic-gate eol, numbadrd, numbadwr, eol); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate static void 3260Sstevel@tonic-gate verexit(int code) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate (void) printf("\n"); 3290Sstevel@tonic-gate exit(code); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /* 3340Sstevel@tonic-gate * report where we are... 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate static void 3380Sstevel@tonic-gate report(char *what, int sector) 3390Sstevel@tonic-gate { 3400Sstevel@tonic-gate (void) printf("%s sector %-7d of %-7ld%c", what, sector, 3410Sstevel@tonic-gate unix_size, eol); 3420Sstevel@tonic-gate } 343