Subject: Re: bad144 on IDE disks
To: None <current-users@netbsd.org>
From: Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
List: current-users
Date: 12/07/2001 00:23:44
Hi.

I received this subject's mail which was posted to port-i386 on
Septemer.  After some mails between Torelli, I decided to post my
little utility which checks and tries to fix IDE hard disk's bad
sectors.

This tool read all sectors (or specified one) of IDE disk.  If -W
option is specified, it tries to write the bad sector and read it
again.  The IDE disk should replace bad sector with spair one if it
support automatic replacement function.

To do:

1. No on-line manual.
2. If read error occurs, IDE driver down grade transfer mode to
   slowest PIO mode.  If driver have support disabling down grade
   transfer mode, this tool should enable it white testing.

--
Takahiro Kambe <taca@sky.yamashina.kyoto.jp>

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	dsck
#	dsck/Makefile
#	dsck/dsck.c
#
echo c - dsck
mkdir -p dsck > /dev/null 2>&1
echo x - dsck/Makefile
sed 's/^X//' >dsck/Makefile << 'END-of-dsck/Makefile'
X#	$NetBSD$
X#	$Id: Makefile,v 1.1.2.1 2001/10/31 02:40:27 taca Exp $
X
XPROG=	dsck
XMKMAN=	no
XLDADD+=	-lutil
X
X.include <bsd.prog.mk>
END-of-dsck/Makefile
echo x - dsck/dsck.c
sed 's/^X//' >dsck/dsck.c << 'END-of-dsck/dsck.c'
X/*
X * $Id: dsck.c,v 1.1.2.4 2001/11/07 08:58:50 taca Exp $
X *
X * Copyright (C) 2000-2001, Takahiro Kambe, All right reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X *
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X#include <sys/cdefs.h>
X#ifndef lint
X__COPYRIGHT("Copyright (C) 2000-2001, Takahiro Kambe, All right reserved.");
X__RCSID("$Id: dsck.c,v 1.1.2.4 2001/11/07 08:58:50 taca Exp $");
X#endif
X#include <sys/param.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X#include <sys/stat.h>
X#define DKTYPENAMES
X#define FSTYPENAMES
X#include <sys/disklabel.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <fcntl.h>
X#include <err.h>
X#include <util.h>
X
Xextern char	*__progname;
X
Xint main(int, char **);
Xint scan_sectors(int, int);
Xint check_sector(int, unsigned long, int);
Xvoid usage(void);
X
X#ifndef BBSIZE
X#define BBSIZE 8192
X#endif
X
Xint verbose = 0;
Xint nowrite = 0;
Xchar namebuf[BBSIZE], *np = namebuf;
Xchar *dkname, *specname;
X
Xint
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	int ch, fd, r, status;
X	unsigned long num;
X	int wmode = 0;
X
X	status = EXIT_FAILURE;
X	while ((ch = getopt(argc, argv, "hnvW")) != -1) {
X		switch (ch) {
X		case 'h':
X			status = EXIT_SUCCESS;
X			goto finish;
X			break;
X		case 'n':
X			nowrite = 1;
X			break;
X		case 'v':
X			verbose = 1;
X			break;
X		case 'W':
X			wmode = 1;
X			break;
X		default:
X			goto finish;
X			break;
X		}
X	}
X	argc -= optind;
X	argv += optind;
X
X	if (argc < 1)
X		goto finish;
X
X	dkname = *argv;
X	fd = opendisk(dkname, (nowrite)? O_RDONLY: O_RDWR, np, MAXPATHLEN, 0);
X	specname = np;
X	if (fd < 0)
X		err(4, "%s", specname);
X
X	argc--;
X	argv++;
X	if (verbose)
X		printf("Checking %s(%s)\n", dkname, specname);
X	if (argc == 0)
X		status = scan_sectors(fd, wmode);
X	else {
X		status = EXIT_SUCCESS;
X		if (verbose)
X			verbose++;
X		while (argc > 0) {
X			num = strtoul(*argv, (char **)NULL, 10);
X			r = check_sector(fd, num, wmode);
X			if (r < 0)
X				status = EXIT_FAILURE;
X			argc -= optind;
X			argv += optind;
X		}
X	}
X	goto end;
Xfinish:
X	usage();
Xend:
X	exit(status);
X}
X
Xint
Xscan_sectors(fd, mode)
X	int fd;
X	int mode;
X{
X	int status;
X	unsigned long n, num;
X	struct disklabel lab;
X
X	if (ioctl(fd, DIOCGDINFO, &lab) < 0) {
X		err(4, "ioctl DIOCGDINFO");
X	}
X	num = lab.d_secperunit;
X
X	if (verbose)
X		printf("%lu sector will be checked.\n", num);
X	status = EXIT_SUCCESS;
X	if (isatty(fileno(stdout)))
X		setbuf(stdout, NULL);
X	for (n = 0; n < num; n++) {
X		if (check_sector(fd, n, mode) < 0)
X			status = EXIT_FAILURE;
X	}
X	if (verbose)
X	    printf("total %lu read succeeded.\r", num);
X	return status;
X}
X
Xint
Xcheck_sector(fd, num, mode)
X    int fd;
X    unsigned long num;
X    int mode;
X{
X	int n;
X	static char buf[512];
X	static int initial = 1;
X
X	if (initial) {
X		memset(buf, 0, sizeof buf);
X		initial = 0;
X	}
X	if (!mode) {
X		if (lseek(fd, num * 512, SEEK_SET) < 0) {
X			warn("%s: lseek", specname);
X			return -1;
X		}
X
X		n = read(fd, buf, sizeof buf);
X		if (n == 0)
X			return 0;
X		if (n == sizeof buf) {
X			if ((verbose == 1 && num % 1000 == 0) || verbose > 1) {
X				printf("%lu read success\r", num);
X				if (verbose > 1)
X					putchar('\n');
X			}
X			return 1;
X		}
X		if (nowrite)
X			return 1;
X	}
X
X	if (lseek(fd, num * 512, SEEK_SET) < 0) {
X		warn("%s: lseek", specname);
X		return -1;
X	}
X	n = write(fd, buf, sizeof buf);
X	if (n == sizeof buf) {
X		if (verbose) {
X			if (mode) {
X				if (num % 1000 == 0 || verbose > 1) {
X					printf("%lu write success\r", num);
X					if (verbose > 1)
X						putchar('\n');
X				}
X			} else {
X				printf("%lu seems to recoverd.\n", num);
X			}
X		}
X	} else {
X		warn("%s: write", specname);
X		if (!mode)
X			return -1;
X	}
X	return 1;
X}
X
Xvoid
Xusage()
X{
X	fprintf(stderr, "%s [-vnWh] <dev> [<num> [<num> ...]]\n", __progname);
X}
END-of-dsck/dsck.c
exit