Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Sep 2000 21:37:46 -0500 (CDT)
From:      Joe Greco <jgreco@ns.sol.net>
To:        imp@village.org
Cc:        hackers@freebsd.org, isp@freebsd.org
Subject:   Re: Frustration with SCSI system
Message-ID:  <200009220237.VAA16401@aurora.sol.net>

next in thread | raw e-mail | index | archive | help
Whoops, sorry about the previous misfire...

> In message <200009201958.MAA45703@ns2.uncanny.net> Edward Elhauge writes:
> : to autorecover on bad sectors, but every system that I've had to recover
> : seems to be in a state where the bad sectors aren't remapping. I've tried
> 
> I've often wanted to write a bad block remapper.  While SCSI is
> supposed to do this automatically, I've found that a scan on any
> adaptec controller will remap these blocks (forces the remapping).

I've got a program which attempts to read all blocks and may be able
to rewrite bad blocks.  It's nothing fancy.  Only works if you've got
auto-reallocate turned on in the drive.

% cat diskscan.c
#include	<stdio.h>
#include	<unistd.h>
#include	<errno.h>
#include	<fcntl.h>





int fixup(off, fd)
off_t off;
int fd;
{
	char buffer[512];
	int i, rval;

	for (i = 0; i < 65536; i += 512) {
		if (lseek(fd, off + i, SEEK_SET) < 0) {
			doerror("lseek", off + i, 0);
		}
		if ((rval = read(fd, buffer, sizeof(buffer))) != sizeof(buffer)) {
			if (errno) {
				if (lseek(fd, off + i, SEEK_SET) < 0) {
					doerror("lseek", off + i, 0);
				}
				write(fd, buffer, sizeof(buffer));
			}
		}
	}
}





int doerror(str, off, type)
char *str;
off_t off;
int type;
{
	static int ign = 0;
	char buffer[80];

	fprintf(stderr, "\nError at %qx, ", (quad_t) off);
	perror(str);
	if (! ign) {
		if (type) {
			fprintf(stderr, "Attempt to correct?  (y/n/a) ");
		} else {
			fprintf(stderr, "Press 'y' to continue: ");
		}
		while (! ign) {
			fgets(buffer, sizeof(buffer), stdin);
			if (*buffer == 'y') {
				return(0);
			}
			if (*buffer == 'n') {
				return(1);
			}
			if (*buffer == 'a') {
				ign++;
				return(0);
			}
		}
	}
	return(0);
}





int main(argc, argv)
int argc;
char *argv[];
{
	int fd, rval;
	char buffer[65536];
	off_t off = 0;
	int eof = 0;
	int count = 0;

	if (argc != 2) {
		fprintf(stderr, "usage: diskscan <dev>\n");
		exit(1);
	}
	if ((fd = open(argv[1], O_RDWR, 0644)) < 0) {
		perror(argv[1]);
	}
	while (! eof) {
		if (! count) {
			fprintf(stderr, "%qx, ", (quad_t) off);
		}
		count++;
		count %= 8;

		if (lseek(fd, off, SEEK_SET) < 0) {
			doerror("lseek", off, 0);
		}
		if ((rval = read(fd, buffer, sizeof(buffer))) != sizeof(buffer)) {
			if (errno) {
				if (! doerror("read", off, 1)) {
					fixup(off, fd);
				}
			}
		}
		off += sizeof(buffer);
	}
}

I don't even guarantee that it's correct, but I do use it with some
success...  vinum takes an entire drive offline when it sees an error,
and I use this to scan for and fix errors before turning the drive back
on.
-- 
... Joe

-------------------------------------------------------------------------------
Joe Greco - Systems Administrator			      jgreco@ns.sol.net
Solaria Public Access UNIX - Milwaukee, WI			   414/342-4847


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200009220237.VAA16401>