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 57563SPrasad.Singamsetty@Sun.COM * Common Development and Distribution License (the "License"). 67563SPrasad.Singamsetty@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*9889SLarry.Liu@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * diskscan: 280Sstevel@tonic-gate * performs a verification pass over a device specified on command line; 290Sstevel@tonic-gate * display progress on stdout, and print bad sector numbers to stderr 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate #include <stdio.h> 320Sstevel@tonic-gate #include <stdlib.h> 330Sstevel@tonic-gate #include <fcntl.h> 340Sstevel@tonic-gate #include <unistd.h> 350Sstevel@tonic-gate #include <stropts.h> 360Sstevel@tonic-gate #include <memory.h> 370Sstevel@tonic-gate #include <ctype.h> 380Sstevel@tonic-gate #include <malloc.h> 390Sstevel@tonic-gate #include <signal.h> 400Sstevel@tonic-gate #include <sys/types.h> 410Sstevel@tonic-gate #include <sys/param.h> 420Sstevel@tonic-gate #include <sys/stat.h> 430Sstevel@tonic-gate #include <sys/vtoc.h> 440Sstevel@tonic-gate #include <sys/dkio.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate static void verexit(); /* signal handler and exit routine */ 470Sstevel@tonic-gate static void report(); /* tell user how we're getting on */ 480Sstevel@tonic-gate static void scandisk(char *device, int devfd, int writeflag); 497563SPrasad.Singamsetty@Sun.COM static void report(char *what, diskaddr_t sector); 500Sstevel@tonic-gate static void verexit(int code); 510Sstevel@tonic-gate 520Sstevel@tonic-gate #define TRUE 1 530Sstevel@tonic-gate #define FALSE 0 540Sstevel@tonic-gate #define VER_WRITE 1 550Sstevel@tonic-gate #define VER_READ 2 560Sstevel@tonic-gate 570Sstevel@tonic-gate static char *progname; 580Sstevel@tonic-gate static struct dk_geom dkg; /* physical device boot info */ 590Sstevel@tonic-gate static char replybuf[64]; /* used for user replies to questions */ 607563SPrasad.Singamsetty@Sun.COM static diskaddr_t unix_base; /* first sector of UNIX System partition */ 617563SPrasad.Singamsetty@Sun.COM static diskaddr_t unix_size; /* # sectors in UNIX System partition */ 620Sstevel@tonic-gate static long numbadrd = 0; /* number of bad sectors on read */ 630Sstevel@tonic-gate static long numbadwr = 0; /* number of bad sectors on write */ 640Sstevel@tonic-gate static char eol = '\n'; /* end-of-line char (if -n, we set to '\n') */ 650Sstevel@tonic-gate static int print_warn = 1; /* should the warning message be printed? */ 660Sstevel@tonic-gate static int do_scan = VER_READ; 670Sstevel@tonic-gate 68362Sbg159949 int 690Sstevel@tonic-gate main(int argc, char *argv[]) { 700Sstevel@tonic-gate extern int optind; 710Sstevel@tonic-gate int devfd; /* device file descriptor */ 720Sstevel@tonic-gate struct stat statbuf; 730Sstevel@tonic-gate struct part_info part_info; 747563SPrasad.Singamsetty@Sun.COM struct extpart_info extpartinfo; 750Sstevel@tonic-gate int c; 760Sstevel@tonic-gate int errflag = 0; 770Sstevel@tonic-gate char *device; 780Sstevel@tonic-gate progname = argv[0]; 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* Don't buffer stdout - we don't want to see bursts */ 810Sstevel@tonic-gate 820Sstevel@tonic-gate setbuf(stdout, NULL); 830Sstevel@tonic-gate 840Sstevel@tonic-gate while ((c = getopt(argc, argv, "Wny")) != -1) 850Sstevel@tonic-gate { 860Sstevel@tonic-gate switch (c) { 870Sstevel@tonic-gate case 'W': 880Sstevel@tonic-gate do_scan = VER_WRITE; 890Sstevel@tonic-gate break; 900Sstevel@tonic-gate 910Sstevel@tonic-gate case 'n': 920Sstevel@tonic-gate eol = '\r'; 930Sstevel@tonic-gate break; 940Sstevel@tonic-gate 950Sstevel@tonic-gate case 'y': 960Sstevel@tonic-gate print_warn = 0; 970Sstevel@tonic-gate break; 980Sstevel@tonic-gate 990Sstevel@tonic-gate default: 1000Sstevel@tonic-gate ++errflag; 1010Sstevel@tonic-gate break; 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate if ((argc - optind) < 1) 1060Sstevel@tonic-gate errflag++; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate if (errflag) { 1090Sstevel@tonic-gate (void) fprintf(stderr, 1100Sstevel@tonic-gate "\nUsage: %s [-W] [-n] [-y] <phys_device_name> \n", 1110Sstevel@tonic-gate progname); 1120Sstevel@tonic-gate exit(1); 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate device = argv[optind]; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate if (stat(device, &statbuf)) { 1180Sstevel@tonic-gate (void) fprintf(stderr, 1190Sstevel@tonic-gate "%s: invalid device %s, stat failed\n", progname, device); 1200Sstevel@tonic-gate perror(""); 1210Sstevel@tonic-gate exit(4); 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 1240Sstevel@tonic-gate (void) fprintf(stderr, 1250Sstevel@tonic-gate "%s: device %s is not character special\n", 1260Sstevel@tonic-gate progname, device); 1270Sstevel@tonic-gate exit(5); 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate if ((devfd = open(device, O_RDWR)) == -1) { 1300Sstevel@tonic-gate (void) fprintf(stderr, 1310Sstevel@tonic-gate "%s: open of %s failed\n", progname, device); 1320Sstevel@tonic-gate perror(""); 1330Sstevel@tonic-gate exit(8); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate if ((ioctl(devfd, DKIOCGGEOM, &dkg)) == -1) { 1370Sstevel@tonic-gate (void) fprintf(stderr, 1380Sstevel@tonic-gate "%s: unable to get disk geometry.\n", progname); 1390Sstevel@tonic-gate perror(""); 1400Sstevel@tonic-gate exit(9); 1410Sstevel@tonic-gate } 1427563SPrasad.Singamsetty@Sun.COM 1437563SPrasad.Singamsetty@Sun.COM if ((ioctl(devfd, DKIOCEXTPARTINFO, &extpartinfo)) == 0) { 1447563SPrasad.Singamsetty@Sun.COM unix_base = extpartinfo.p_start; 1457563SPrasad.Singamsetty@Sun.COM unix_size = extpartinfo.p_length; 1467563SPrasad.Singamsetty@Sun.COM } else { 1477563SPrasad.Singamsetty@Sun.COM if ((ioctl(devfd, DKIOCPARTINFO, &part_info)) == 0) { 1487563SPrasad.Singamsetty@Sun.COM unix_base = (ulong_t)part_info.p_start; 1497563SPrasad.Singamsetty@Sun.COM unix_size = (uint_t)part_info.p_length; 1507563SPrasad.Singamsetty@Sun.COM } else { 1517563SPrasad.Singamsetty@Sun.COM (void) fprintf(stderr, "%s: unable to get partition " 1527563SPrasad.Singamsetty@Sun.COM "info.\n", progname); 1537563SPrasad.Singamsetty@Sun.COM perror(""); 1547563SPrasad.Singamsetty@Sun.COM exit(9); 1557563SPrasad.Singamsetty@Sun.COM } 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate scandisk(device, devfd, do_scan); 159362Sbg159949 return (0); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /* 1630Sstevel@tonic-gate * scandisk: 1640Sstevel@tonic-gate * attempt to read every sector of the drive; 1650Sstevel@tonic-gate * display bad sectors found on stderr 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate static void 1690Sstevel@tonic-gate scandisk(char *device, int devfd, int writeflag) 1700Sstevel@tonic-gate { 171*9889SLarry.Liu@Sun.COM int trksiz = 0; 1720Sstevel@tonic-gate char *verbuf; 1737563SPrasad.Singamsetty@Sun.COM diskaddr_t cursec; 1740Sstevel@tonic-gate int cylsiz = dkg.dkg_nsect * dkg.dkg_nhead; 1750Sstevel@tonic-gate int i; 1760Sstevel@tonic-gate char *rptr; 1777563SPrasad.Singamsetty@Sun.COM diskaddr_t tmpend = 0; 1787563SPrasad.Singamsetty@Sun.COM diskaddr_t tmpsec = 0; 179*9889SLarry.Liu@Sun.COM struct dk_minfo mediainfo; 180*9889SLarry.Liu@Sun.COM uint_t sector_size; 181*9889SLarry.Liu@Sun.COM 182*9889SLarry.Liu@Sun.COM if ((ioctl(devfd, DKIOCGMEDIAINFO, &mediainfo)) == 0) { 183*9889SLarry.Liu@Sun.COM sector_size = mediainfo.dki_lbsize; 184*9889SLarry.Liu@Sun.COM } else { 185*9889SLarry.Liu@Sun.COM sector_size = NBPSCTR; 186*9889SLarry.Liu@Sun.COM } 187*9889SLarry.Liu@Sun.COM trksiz = sector_size * dkg.dkg_nsect; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* #define LIBMALLOC */ 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate #ifdef LIBMALLOC 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate extern int mallopt(); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate /* This adds 5k to the binary, but it's a lot prettier */ 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* make track buffer sector aligned */ 199*9889SLarry.Liu@Sun.COM if (mallopt(M_GRAIN, sector_size)) { 2000Sstevel@tonic-gate perror("mallopt"); 2010Sstevel@tonic-gate exit(1); 2020Sstevel@tonic-gate } 203*9889SLarry.Liu@Sun.COM if ((verbuf = malloc(sector_size * dkg.dkg_nsect)) == 204*9889SLarry.Liu@Sun.COM (char *)NULL) { 2050Sstevel@tonic-gate perror("malloc"); 2060Sstevel@tonic-gate exit(1); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate #else 2100Sstevel@tonic-gate 211*9889SLarry.Liu@Sun.COM if ((verbuf = malloc(sector_size + sector_size * dkg.dkg_nsect)) 2120Sstevel@tonic-gate == (char *)NULL) { 2130Sstevel@tonic-gate perror("malloc"); 2140Sstevel@tonic-gate exit(1); 2150Sstevel@tonic-gate } 216*9889SLarry.Liu@Sun.COM verbuf = (char *)((((unsigned long)verbuf + sector_size)) & 217*9889SLarry.Liu@Sun.COM (-sector_size)); 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate #endif 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* write pattern in track buffer */ 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate for (i = 0; i < trksiz; i++) 2240Sstevel@tonic-gate verbuf[i] = (char)0xe5; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* Turn off retry, and set trap to turn them on again */ 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate (void) signal(SIGINT, verexit); 2290Sstevel@tonic-gate (void) signal(SIGQUIT, verexit); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (writeflag == VER_READ) 2320Sstevel@tonic-gate goto do_readonly; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* 2350Sstevel@tonic-gate * display warning only if -n arg not passed 2360Sstevel@tonic-gate * (otherwise the UI system will take care of it) 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate if (print_warn == 1) { 2400Sstevel@tonic-gate (void) printf( 2410Sstevel@tonic-gate "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device); 2420Sstevel@tonic-gate (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n"); 2430Sstevel@tonic-gate (void) printf(" THAT PARTITION OR SLICE.\n"); 2440Sstevel@tonic-gate (void) printf("Do you want to continue (y/n)? "); 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate rptr = fgets(replybuf, 64*sizeof (char), stdin); 2470Sstevel@tonic-gate if (!rptr || !((replybuf[0] == 'Y') || (replybuf[0] == 'y'))) 2480Sstevel@tonic-gate exit(10); 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 252*9889SLarry.Liu@Sun.COM if (llseek(devfd, cursec * sector_size, 0) == -1) { 2530Sstevel@tonic-gate (void) fprintf(stderr, 2547563SPrasad.Singamsetty@Sun.COM "Error seeking sector %llu Cylinder %llu\n", 2557563SPrasad.Singamsetty@Sun.COM cursec, cursec / cylsiz); 2560Sstevel@tonic-gate verexit(1); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * verify sector at a time only when 2610Sstevel@tonic-gate * the whole track write fails; 2620Sstevel@tonic-gate * (if we write a sector at a time, it takes forever) 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate report("Writing", cursec); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate if (write(devfd, verbuf, trksiz) != trksiz) { 2680Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 2690Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * try writing to it once; if this fails, 2720Sstevel@tonic-gate * then announce the sector bad on stderr 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate 275*9889SLarry.Liu@Sun.COM if (llseek(devfd, tmpsec * sector_size, 276*9889SLarry.Liu@Sun.COM 0) == -1) { 2770Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking " 2787563SPrasad.Singamsetty@Sun.COM "sector %llu Cylinder %llu\n", 2790Sstevel@tonic-gate tmpsec, cursec / cylsiz); 2800Sstevel@tonic-gate verexit(1); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate report("Writing", tmpsec); 2840Sstevel@tonic-gate 285*9889SLarry.Liu@Sun.COM if (write(devfd, verbuf, sector_size) 286*9889SLarry.Liu@Sun.COM != sector_size) { 2870Sstevel@tonic-gate (void) fprintf(stderr, 2887563SPrasad.Singamsetty@Sun.COM "%llu\n", tmpsec + unix_base); 2890Sstevel@tonic-gate numbadwr++; 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate (void) putchar(eol); 2960Sstevel@tonic-gate do_readonly: 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate for (cursec = 0; cursec < unix_size; cursec += dkg.dkg_nsect) { 299*9889SLarry.Liu@Sun.COM if (llseek(devfd, cursec * sector_size, 0) == -1) { 3000Sstevel@tonic-gate (void) fprintf(stderr, 3017563SPrasad.Singamsetty@Sun.COM "Error seeking sector %llu Cylinder %llu\n", 3027563SPrasad.Singamsetty@Sun.COM cursec, cursec / cylsiz); 3030Sstevel@tonic-gate verexit(1); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate /* 3070Sstevel@tonic-gate * read a sector at a time only when 3080Sstevel@tonic-gate * the whole track write fails; 3090Sstevel@tonic-gate * (if we do a sector at a time read, it takes forever) 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate report("Reading", cursec); 3130Sstevel@tonic-gate if (read(devfd, verbuf, trksiz) != trksiz) { 3140Sstevel@tonic-gate tmpend = cursec + dkg.dkg_nsect; 3150Sstevel@tonic-gate for (tmpsec = cursec; tmpsec < tmpend; tmpsec++) { 316*9889SLarry.Liu@Sun.COM if (llseek(devfd, tmpsec * sector_size, 317*9889SLarry.Liu@Sun.COM 0) == -1) { 3180Sstevel@tonic-gate (void) fprintf(stderr, "Error seeking" 3197563SPrasad.Singamsetty@Sun.COM " sector %llu Cylinder %llu\n", 3200Sstevel@tonic-gate tmpsec, cursec / cylsiz); 3210Sstevel@tonic-gate verexit(1); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate report("Reading", tmpsec); 324*9889SLarry.Liu@Sun.COM if (read(devfd, verbuf, sector_size) != 325*9889SLarry.Liu@Sun.COM sector_size) { 3267563SPrasad.Singamsetty@Sun.COM (void) fprintf(stderr, "%llu\n", 3270Sstevel@tonic-gate tmpsec + unix_base); 3280Sstevel@tonic-gate numbadrd++; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate (void) printf("%c%c======== Diskscan complete ========%c", eol, 3340Sstevel@tonic-gate eol, eol); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate if ((numbadrd > 0) || (numbadwr > 0)) { 3370Sstevel@tonic-gate (void) printf("%cFound %ld bad sector(s) on read," 3380Sstevel@tonic-gate " %ld bad sector(s) on write%c", 3390Sstevel@tonic-gate eol, numbadrd, numbadwr, eol); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate static void 3440Sstevel@tonic-gate verexit(int code) 3450Sstevel@tonic-gate { 3460Sstevel@tonic-gate (void) printf("\n"); 3470Sstevel@tonic-gate exit(code); 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate /* 3520Sstevel@tonic-gate * report where we are... 3530Sstevel@tonic-gate */ 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate static void 3567563SPrasad.Singamsetty@Sun.COM report(char *what, diskaddr_t sector) 3570Sstevel@tonic-gate { 3587563SPrasad.Singamsetty@Sun.COM (void) printf("%s sector %-19llu of %-19llu%c", what, sector, 3590Sstevel@tonic-gate unix_size, eol); 3600Sstevel@tonic-gate } 361