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
)) ==
211 if ((verbuf
= malloc(sector_size
+ sector_size
* dkg
.dkg_nsect
))
216 verbuf
= (char *)((((unsigned long)verbuf
+ sector_size
)) &
221 /* write pattern in track buffer */
223 for (i
= 0; i
< trksiz
; i
++)
224 verbuf
[i
] = (char)0xe5;
226 /* Turn off retry, and set trap to turn them on again */
228 (void) signal(SIGINT
, verexit
);
229 (void) signal(SIGQUIT
, verexit
);
231 if (writeflag
== VER_READ
)
235 * display warning only if -n arg not passed
236 * (otherwise the UI system will take care of it)
239 if (print_warn
== 1) {
241 "\nCAUTION: ABOUT TO DO DESTRUCTIVE WRITE ON %s\n", device
);
242 (void) printf(" THIS WILL DESTROY ANY DATA YOU HAVE ON\n");
243 (void) printf(" THAT PARTITION OR SLICE.\n");
244 (void) printf("Do you want to continue (y/n)? ");
246 rptr
= fgets(replybuf
, 64*sizeof (char), stdin
);
247 if (!rptr
|| !((replybuf
[0] == 'Y') || (replybuf
[0] == 'y')))
251 for (cursec
= 0; cursec
< unix_size
; cursec
+= dkg
.dkg_nsect
) {
252 if (llseek(devfd
, cursec
* sector_size
, 0) == -1) {
253 (void) fprintf(stderr
,
254 "Error seeking sector %llu Cylinder %llu\n",
255 cursec
, cursec
/ cylsiz
);
260 * verify sector at a time only when
261 * the whole track write fails;
262 * (if we write a sector at a time, it takes forever)
265 report("Writing", cursec
);
267 if (write(devfd
, verbuf
, trksiz
) != trksiz
) {
268 tmpend
= cursec
+ dkg
.dkg_nsect
;
269 for (tmpsec
= cursec
; tmpsec
< tmpend
; tmpsec
++) {
271 * try writing to it once; if this fails,
272 * then announce the sector bad on stderr
275 if (llseek(devfd
, tmpsec
* sector_size
,
277 (void) fprintf(stderr
, "Error seeking "
278 "sector %llu Cylinder %llu\n",
279 tmpsec
, cursec
/ cylsiz
);
283 report("Writing", tmpsec
);
285 if (write(devfd
, verbuf
, sector_size
)
287 (void) fprintf(stderr
,
288 "%llu\n", tmpsec
+ unix_base
);
298 for (cursec
= 0; cursec
< unix_size
; cursec
+= dkg
.dkg_nsect
) {
299 if (llseek(devfd
, cursec
* sector_size
, 0) == -1) {
300 (void) fprintf(stderr
,
301 "Error seeking sector %llu Cylinder %llu\n",
302 cursec
, cursec
/ cylsiz
);
307 * read a sector at a time only when
308 * the whole track write fails;
309 * (if we do a sector at a time read, it takes forever)
312 report("Reading", cursec
);
313 if (read(devfd
, verbuf
, trksiz
) != trksiz
) {
314 tmpend
= cursec
+ dkg
.dkg_nsect
;
315 for (tmpsec
= cursec
; tmpsec
< tmpend
; tmpsec
++) {
316 if (llseek(devfd
, tmpsec
* sector_size
,
318 (void) fprintf(stderr
, "Error seeking"
319 " sector %llu Cylinder %llu\n",
320 tmpsec
, cursec
/ cylsiz
);
323 report("Reading", tmpsec
);
324 if (read(devfd
, verbuf
, sector_size
) !=
326 (void) fprintf(stderr
, "%llu\n",
333 (void) printf("%c%c======== Diskscan complete ========%c", eol
,
336 if ((numbadrd
> 0) || (numbadwr
> 0)) {
337 (void) printf("%cFound %ld bad sector(s) on read,"
338 " %ld bad sector(s) on write%c",
339 eol
, numbadrd
, numbadwr
, eol
);
352 * report where we are...
356 report(char *what
, diskaddr_t sector
)
358 (void) printf("%s sector %-19llu of %-19llu%c", what
, sector
,