Date: Mon, 26 Jan 1998 08:39:02 -0800 From: John Polstra <jdp@polstra.com> To: freebsd-hardware@FreeBSD.ORG Subject: Re: SCSI bad block handliong ? Message-ID: <199801261639.IAA21681@austin.polstra.com>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Mike Smith wrote:
> You may then need to actually write to the blocks before they will
> be reallocated, which will generally involve using dd to plaster
> the entire disk (unless you write a program to write to just the
> offending parts of the raw device).
Attached is a quickie program I wrote a while ago for just this
purpose. It first reads the block and saves its original contents,
both in memory and in a file on disk. Then it bashes the block on
disk with several fixed patterns and then several random patterns,
trying to provoke a write error and force the disk to remap the block.
Finally, it restores the block from its original data. It has worked
well for me to get a few troublesome blocks remapped. Also, it has
the nice property that it won't remap a block that just isn't bad.
As I mentioned, it was a quickie, so don't expect a software
engineering marvel. In particular, the block number is hard coded
into main(). :-O The fix for that is left as an exercise for the
reader.
John
--
John Polstra jdp@polstra.com
John D. Polstra & Co., Inc. Seattle, Washington USA
"Self-knowledge is always bad news." -- John Barth
[-- Attachment #2 --]
#include <sys/types.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
struct pattern {
size_t len;
char *pat;
};
#define PAT(s) { sizeof(s) - 1, (s) }
static struct pattern patterns[] = {
PAT("\xaa"),
PAT("\x55"),
PAT("\xcc"),
PAT("\x33"),
PAT("\xf0"),
PAT("\x0f"),
PAT("\xff\x00"),
PAT("\x00\xff")
};
#define NUMPATTERNS (sizeof patterns / sizeof patterns[0])
#define NUMRANDOM (10)
#define BLOCKSIZE (512)
extern void err(int, const char *, ...) __attribute__ ((format(printf, 2, 3)));
extern void errx(int, const char *, ...) __attribute__ ((format(printf, 2, 3)));
extern void warn(const char *, ...) __attribute__ ((format(printf, 1, 2)));
extern void warnx(const char *, ...) __attribute__ ((format(printf, 1, 2)));
static int bash(const char *devname, daddr_t block);
static int getblock(int fd, daddr_t block, void *buf);
static int putblock(int fd, daddr_t block, const void *buf);
static void saveblock(const char *devname, daddr_t block, const void *buf);
static int trypat(int fd, daddr_t block, const struct pattern *pat);
int
main(int argc, char *argv[])
{
const char *devname = "/dev/rsd0";
daddr_t block = 0x1efc7;
int status;
status = bash(devname, block);
return status == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int
bash(const char *devname, daddr_t block)
{
int fd;
char orig_data[BLOCKSIZE];
int i;
int status;
time_t t;
union {
long l;
char c[sizeof(long)];
} randata;
struct pattern ranpat;
if ((fd = open(devname, O_RDWR, 0)) == -1)
err(1, "Cannot open %s", devname);
printf("Reading the original data\n");
if (getblock(fd, block, orig_data) == -1)
return -1;
saveblock(devname, block, orig_data);
printf("Trying fixed patterns\n");
for (i = 0, status = 0; i < NUMPATTERNS && status == 0; i++)
if (trypat(fd, block, &patterns[i]) == -1)
status = -1;
printf("Trying random patterns\n");
time(&t);
srandom(t);
for (i = 0; i < NUMRANDOM && status == 0; i++) {
randata.l = random();
ranpat.len = sizeof(long);
ranpat.pat = randata.c;
if (trypat(fd, block, &ranpat) == -1)
status = -1;
}
printf("Restoring the original data\n");
if (putblock(fd, block, orig_data) == -1)
status = -1;
printf("Done\n");
close(fd);
return status;
}
static int
getblock(int fd, daddr_t block, void *buf)
{
ssize_t n;
if (lseek(fd, (off_t)block * BLOCKSIZE, SEEK_SET) == -1) {
warn("Cannot lseek to block %d", block);
return -1;
}
if ((n = read(fd, buf, BLOCKSIZE)) != BLOCKSIZE) {
if (n == -1)
warn("Cannot read block %d", block);
else if (n == 0)
warnx("Unexpected EOF for block %d", block);
else
warnx("Short read of block %d: got %d", block, n);
return -1;
}
return 0;
}
static int
putblock(int fd, daddr_t block, const void *buf)
{
ssize_t n;
if (lseek(fd, (off_t)block * BLOCKSIZE, SEEK_SET) == -1) {
warn("Cannot lseek to block %d", block);
return -1;
}
if ((n = write(fd, buf, BLOCKSIZE)) != BLOCKSIZE) {
if (n == -1)
warn("Cannot write block %d", block);
else
warnx("Short write of block %d: got %d", block, n);
return -1;
}
return 0;
}
static void
saveblock(const char *devname, daddr_t block, const void *buf)
{
char *shortdev;
char *savename;
int fd;
if ((shortdev = strrchr(devname, '/')) == NULL)
errx(1, "Strange device name %s", devname);
shortdev++;
if (asprintf(&savename, "%s.%#x", shortdev, block) == -1)
errx(1, "Out of memory");
if ((fd = open(savename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
err(1, "Cannot create %s", savename);
printf("Saving original data to %s\n", savename);
if (write(fd, buf, BLOCKSIZE) != BLOCKSIZE)
err(1, "Cannot write to %s", savename);
if (fsync(fd) == -1)
err(1, "Cannot fsync %s", savename);
if (close(fd) == -1)
err(1, "Close failed on %s", savename);
free(savename);
}
/*
* Returns 0 on success, -1 on error.
*/
static int
trypat(int fd, daddr_t block, const struct pattern *pat)
{
char patbuf[BLOCKSIZE];
char *p;
int i;
printf("Trying pattern:");
for (i = 0; i < pat->len; i++)
printf(" %02x", (unsigned char)pat->pat[i]);
printf("\n");
for (p = patbuf; p < patbuf + BLOCKSIZE; )
for (i = 0; i < pat->len && p < patbuf + BLOCKSIZE; i++)
*p++ = pat->pat[i];
if (putblock(fd, block, patbuf) == -1)
return -1;
if (getblock(fd, block, patbuf) == -1)
return -1;
return 0;
}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199801261639.IAA21681>
