Subject: Re: BAD BLOCKS WITH SCSI DISKS, HOW TO REMAP
To: Brian Buhrow <firstname.lastname@example.org>
From: Jason Thorpe <email@example.com>
Date: 06/03/1996 23:04:38
On Mon, 3 Jun 1996 16:17:53 -0700
firstname.lastname@example.org (Brian Buhrow) wrote:
> Hello NetBSD folks. I'm running a machine with NetBSD 1.1A (circa
> February 1996 sources) which has a Bus Logic BT946C and a Seagate
> Technologies ST31230N 1.X gig disk attached to it. The machine (an i386
> Pentium) runs fine, except that I'm getting lines of the form:
A few months ago, I wrote a quick little program to do this for a friend
of mine. It's appended below...
sdremap /dev/rsd1d 45532
...assuming that sd1 has the bad block, and the bad block number is
45532. Note, you must use the "raw" partition, d on i386, c on all others.
> Jun 3 02:01:53 rumpleteazer /netbsd: sd0(bt0:0:0):
> medium error, info = 842458 (decimal),
> data = 00 00 00 00 11 00 00 00 00 00 06 22 00 53
Hmm, might want to look up that sense key in the SCSI specs...
> Is there a utility under NetBSD, like SunOS's format command, which
> will let me issue the remap scsi request to this drive so it will use a new
> block? I've had this discussion before, but seem to remember that in order
> to do this, I had to become a scsi byte coder and issue raw requests to the
> scsi disk. I'd prefer something with a little higher level interface if
Oh, it's actually a lot easier than sending raw requests ... Anyhow, my
quick little hack is appended below ... Gee, a libscsi sure would be nice :-)
----save the ancient forests - http://www.bayarea.net/~thorpej/forest/----
Jason R. Thorpe email@example.com
NASA Ames Research Center Home: 408.866.1912
NAS: M/S 258-6 Work: 415.604.0935
Moffett Field, CA 94035 Pager: 415.428.6939
----- snip -----
* sdremap <dev> <blkno> - tell a SCSI disk to remap the bad block
* specified on the command line.
* Compile this on your favorite NetBSD 1.1 system with:
* cc -I/sys -DOLD_SCSI_BYTES -o sdremap sdremap.c
* or on newer NetBSD systems with:
* cc -I/sys -o sdremap sdremap.c
* It will be pretty obvious if you need to add or remove the OLD_SCSI_BYTES
* define; this program won't compile if the setting is incorrect.
* When you use this program, make sure the disk you're mucking with
* has no mounted filesystems (unless that's just not possible, in which
* case, make sure they're mounted read-only, and you're in single-user
* mode). You must use the "raw partition" of the disk. On an i386, this
* is `d', and everywhere else `c'.
* ./sdremap /dev/rsd1d 356642
* Written by Jason R. Thorpe <thorpej@NetBSD.ORG>.
* This program is in the public domain.
* Use this software at your own risk. At no time shall Jason R. Thorpe
* be liable for any damages it may cause.
* Handle multiple blocks with a single command. I'm just lazy.
extern char *__progname; /* from crt0.o */
static void usage __P((void));
static void cleanup __P((void));
static int disk_fd;
struct scsi_reassign_blocks cmd;
struct scsi_reassign_blocks_data desc;
char *disk, *cp;
if (argc != 3)
disk = argv;
blkno = (u_int32_t)strtol(argv, &cp, 10);
if (*cp != '\0')
errx(1, "invalid block number `%s'", argv);
/* Register cleanup function. */
err(1, "can't register cleanup function");
/* Open the device... */
if ((disk_fd = open(disk, O_RDWR, 0600)) == -1)
err(1, "%s: open", disk);
/* Build SCSI command. */
cmd.opcode = REASSIGN_BLOCKS;
* Build the block descriptor.
desc_data_len = sizeof(desc.defect_descriptor);
/* Descriptor length. */
desc.length_msb = (desc_data_len >> 8) & 0xff;
desc.length_lsb = desc_data_len & 0xff;
desc.length = (desc_data_len >> 8) & 0xff;
desc.length = desc_data_len & 0xff;
/* Block number. */
desc.defect_descriptor.dlbaddr_3 = (blkno >> 24) & 0xff;
desc.defect_descriptor.dlbaddr_2 = (blkno >> 16) & 0xff;
desc.defect_descriptor.dlbaddr_1 = (blkno >> 8) & 0xff;
desc.defect_descriptor.dlbaddr_0 = blkno & 0xff;
desc.defect_descriptor.dlbaddr = (blkno >> 24) & 0xff;
desc.defect_descriptor.dlbaddr = (blkno >> 16) & 0xff;
desc.defect_descriptor.dlbaddr = (blkno >> 8) & 0xff;
desc.defect_descriptor.dlbaddr = blkno & 0xff;
/* Fill out user-level SCSI request. */
bcopy((struct scsi_generic *)&cmd, &req.cmd, sizeof(cmd));
req.cmdlen = (u_char)sizeof(cmd);
req.databuf = (void *)&desc;
req.datalen = (u_long)sizeof(desc);
req.flags |= SCCMD_WRITE;
req.timeout = 20000; /* XXX */
/* Send the request to the SCSI subsystem. */
if (ioctl(disk_fd, SCIOCCOMMAND, (char *)&req) == -1)
* XXX should check for error condition and print
* sense data.
/* ...simple enough... */
fprintf(stderr, "usage: %s disk blkno\n", __progname);