4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * performs a verification pass over a device specified on command line;
29 * display progress on stdout, and print bad sector numbers to stderr
40 #include <sys/types.h>
41 #include <sys/param.h>
46 static void verexit(); /* signal handler and exit routine */
47 static void report(); /* tell user how we're getting on */
48 static void scandisk(char *device
, int devfd
, int writeflag
);
49 static void report(char *what
, diskaddr_t sector
);
50 static void verexit(int code
);
57 static char *progname
;
58 static struct dk_geom dkg
; /* physical device boot info */
59 static char replybuf
[64]; /* used for user replies to questions */
60 static diskaddr_t unix_base
; /* first sector of UNIX System partition */
61 static diskaddr_t unix_size
; /* # sectors in UNIX System partition */
62 static long numbadrd
= 0; /* number of bad sectors on read */
63 static long numbadwr
= 0; /* number of bad sectors on write */
64 static char eol
= '\n'; /* end-of-line char (if -n, we set to '\n') */
65 static int print_warn
= 1; /* should the warning message be printed? */
66 static int do_scan
= VER_READ
;
69 main(int argc
, char *argv
[]) {
71 int devfd
; /* device file descriptor */
73 struct part_info part_info
;
74 struct extpart_info extpartinfo
;
80 /* Don't buffer stdout - we don't want to see bursts */
84 while ((c
= getopt(argc
, argv
, "Wny")) != -1)
105 if ((argc
- optind
) < 1)
109 (void) fprintf(stderr
,
110 "\nUsage: %s [-W] [-n] [-y] <phys_device_name> \n",
115 device
= argv
[optind
];
117 if (stat(device
, &statbuf
)) {
118 (void) fprintf(stderr
,
119 "%s: invalid device %s, stat failed\n", progname
, device
);
123 if ((statbuf
.st_mode
& S_IFMT
) != S_IFCHR
) {
124 (void) fprintf(stderr
,
125 "%s: device %s is not character special\n",
129 if ((devfd
= open(device
, O_RDWR
)) == -1) {
130 (void) fprintf(stderr
,
131 "%s: open of %s failed\n", progname
, device
);
136 if ((ioctl(devfd
, DKIOCGGEOM
, &dkg
)) == -1) {
137 (void) fprintf(stderr
,
138 "%s: unable to get disk geometry.\n", progname
);
143 if ((ioctl(devfd
, DKIOCEXTPARTINFO
, &extpartinfo
)) == 0) {
144 unix_base
= extpartinfo
.p_start
;
145 unix_size
= extpartinfo
.p_length
;
147 if ((ioctl(devfd
, DKIOCPARTINFO
, &part_info
)) == 0) {
148 unix_base
= (ulong_t
)part_info
.p_start
;
149 unix_size
= (uint_t
)part_info
.p_length
;
151 (void) fprintf(stderr
, "%s: unable to get partition "
152 "info.\n", progname
);
158 scandisk(device
, devfd
, do_scan
);
164 * attempt to read every sector of the drive;
165 * display bad sectors found on stderr
169 scandisk(char *device
, int devfd
, int writeflag
)
174 int cylsiz
= dkg
.dkg_nsect
* dkg
.dkg_nhead
;
177 diskaddr_t tmpend
= 0;
178 diskaddr_t tmpsec
= 0;
179 struct dk_minfo mediainfo
;
182 if ((ioctl(devfd
, DKIOCGMEDIAINFO
, &mediainfo
)) == 0) {
183 sector_size
= mediainfo
.dki_lbsize
;
185 sector_size
= NBPSCTR
;
187 trksiz
= sector_size
* dkg
.dkg_nsect
;
189 /* #define LIBMALLOC */
193 extern int mallopt();
195 /* This adds 5k to the binary, but it's a lot prettier */
198 /* make track buffer sector aligned */
199 if (mallopt(M_GRAIN
, sector_size
)) {
203 if ((verbuf
= malloc(sector_size
* dkg
.dkg_nsect
)) == NULL
) {
210 if ((verbuf
= malloc(sector_size
+ sector_size
* dkg
.dkg_nsect
))
215 verbuf
= (char *)((((unsigned long)verbuf
+ sector_size
)) &
220 /* write pattern in track buffer */
222 for (i
= 0; i
< trksiz
; i
++)
223 verbuf
[i
] = (char)0xe5;
225 /* Turn off retry, and set trap to turn them on again */
227 (void) signal(SIGINT
, verexit
);
228 (void) signal(SIGQUIT
, verexit
);
230 if (writeflag
== VER_READ
)
234 * display warning only if -n arg not passed
235 * (otherwise the UI system will take care of it)
238 if (print_warn
== 1) {
240 "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device
);
241 (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n");
242 (void) printf(" THAT PARTITION OR SLICE.\n");
243 (void) printf("Do you want to continue (y/n)? ");
245 rptr
= fgets(replybuf
, 64*sizeof (char), stdin
);
246 if (!rptr
|| !((replybuf
[0] == 'Y') || (replybuf
[0] == 'y')))
250 for (cursec
= 0; cursec
< unix_size
; cursec
+= dkg
.dkg_nsect
) {
251 if (llseek(devfd
, cursec
* sector_size
, 0) == -1) {
252 (void) fprintf(stderr
,
253 "Error seeking sector %llu Cylinder %llu\n",
254 cursec
, cursec
/ cylsiz
);
259 * verify sector at a time only when
260 * the whole track write fails;
261 * (if we write a sector at a time, it takes forever)
264 report("Writing", cursec
);
266 if (write(devfd
, verbuf
, trksiz
) != trksiz
) {
267 tmpend
= cursec
+ dkg
.dkg_nsect
;
268 for (tmpsec
= cursec
; tmpsec
< tmpend
; tmpsec
++) {
270 * try writing to it once; if this fails,
271 * then announce the sector bad on stderr
274 if (llseek(devfd
, tmpsec
* sector_size
,
276 (void) fprintf(stderr
, "Error seeking "
277 "sector %llu Cylinder %llu\n",
278 tmpsec
, cursec
/ cylsiz
);
282 report("Writing", tmpsec
);
284 if (write(devfd
, verbuf
, sector_size
)
286 (void) fprintf(stderr
,
287 "%llu\n", tmpsec
+ unix_base
);
297 for (cursec
= 0; cursec
< unix_size
; cursec
+= dkg
.dkg_nsect
) {
298 if (llseek(devfd
, cursec
* sector_size
, 0) == -1) {
299 (void) fprintf(stderr
,
300 "Error seeking sector %llu Cylinder %llu\n",
301 cursec
, cursec
/ cylsiz
);
306 * read a sector at a time only when
307 * the whole track write fails;
308 * (if we do a sector at a time read, it takes forever)
311 report("Reading", cursec
);
312 if (read(devfd
, verbuf
, trksiz
) != trksiz
) {
313 tmpend
= cursec
+ dkg
.dkg_nsect
;
314 for (tmpsec
= cursec
; tmpsec
< tmpend
; tmpsec
++) {
315 if (llseek(devfd
, tmpsec
* sector_size
,
317 (void) fprintf(stderr
, "Error seeking"
318 " sector %llu Cylinder %llu\n",
319 tmpsec
, cursec
/ cylsiz
);
322 report("Reading", tmpsec
);
323 if (read(devfd
, verbuf
, sector_size
) !=
325 (void) fprintf(stderr
, "%llu\n",
332 (void) printf("%c%c======== Diskscan complete ========%c", eol
,
335 if ((numbadrd
> 0) || (numbadwr
> 0)) {
336 (void) printf("%cFound %ld bad sector(s) on read,"
337 " %ld bad sector(s) on write%c",
338 eol
, numbadrd
, numbadwr
, eol
);
351 * report where we are...
355 report(char *what
, diskaddr_t sector
)
357 (void) printf("%s sector %-19llu of %-19llu%c", what
, sector
,