Skip site navigation (1)Skip section navigation (2)
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
This is a multipart MIME message.

--===_0_Mon_Jan_26_08:38:13_PST_1998
Content-Type: text/plain; charset=us-ascii

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


--===_0_Mon_Jan_26_08:38:13_PST_1998
Content-Type: text/plain; charset=us-ascii
Content-Description: sdfix.c

#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;
}

--===_0_Mon_Jan_26_08:38:13_PST_1998--





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