From owner-freebsd-hardware Mon Jan 26 08:39:13 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id IAA11591 for hardware-outgoing; Mon, 26 Jan 1998 08:39:13 -0800 (PST) (envelope-from owner-freebsd-hardware@FreeBSD.ORG) Received: from austin.polstra.com (austin.polstra.com [206.213.73.10]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id IAA11579 for ; Mon, 26 Jan 1998 08:39:04 -0800 (PST) (envelope-from jdp@austin.polstra.com) Received: from austin.polstra.com (jdp@localhost) by austin.polstra.com (8.8.8/8.8.8) with ESMTP id IAA21681 for ; Mon, 26 Jan 1998 08:39:03 -0800 (PST) (envelope-from jdp) Message-Id: <199801261639.IAA21681@austin.polstra.com> To: freebsd-hardware@FreeBSD.ORG Subject: Re: SCSI bad block handliong ? Mime-Version: 1.0 Content-Type: multipart/mixed ; boundary="===_0_Mon_Jan_26_08:38:13_PST_1998" Date: Mon, 26 Jan 1998 08:39:02 -0800 From: John Polstra Sender: owner-freebsd-hardware@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org 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 #include #include #include #include #include #include #include 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--