Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 1 Feb 1997 13:08:55 -0500 (EST)
From:      Peter Dufault <dufault@hda.com>
To:        Don.Lewis@tsc.tdk.com (Don Lewis)
Cc:        joerg_wunsch@uriah.heep.sax.de, Don.Lewis@tsc.tdk.com, freebsd-scsi@freebsd.org
Subject:   Re: SCSI disk MEDIUM ERROR with a few twists
Message-ID:  <199702011808.NAA16376@hda.hda.com>
In-Reply-To: <199702011537.HAA28985@salsa.gv.tsc.tdk.com> from Don Lewis at "Feb 1, 97 07:37:09 am"

next in thread | previous in thread | raw e-mail | index | archive | help
> As Don Lewis wrote:
> 
> > } We need a remapping tool as well.  Anybody here who ever dealt with
> > } defect list management?  Since we do already know the block number
> > } (from the info field in the syslog message), it should be easy to add
> > } it to the defect list.
> > 
> > I was reading the SCSI spec and thinking about writing something that
> > would at dump out the current defect list, but then my brain started
> > hurting too much :-(
> 
> Metoo.  This defect list stuff is even worse to understand (from just
> reading the specs only) than mode pages.

The remapping tool is easy: write anything to the block.  Here is an sector
slipper I wrote in C once, however, it may fail also if it can't recover
the data - I don't have time to check the spec right now.

I also put together a defect list dumper for Satoshi when he was having some problems,
so I'm putting that here too.

Caveat emptor.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	slipsec.c
#	dump-defects.c
#	defect
#
echo x - slipsec.c
sed 's/^X//' >slipsec.c << 'END-of-slipsec.c'
X/* slipsec: Slip a sector using "reallocate block".
X */
X#include <stdlib.h>
X#include <sys/scsiio.h>
X#include <errno.h>
X#include <sys/file.h>
X
X#include <scsi.h>
X
Xint main(int argc, char *argv[])
X{
X	scsireq_t *scsireq;
X
X	int qualifier, type, rmb, modifier, iso, ecma, ansi;
X	char vendor_id[17], product_id[17], revision[5];
X	int lba, len;
X	int i;
X	int fid;
X	u_char *inq_buf = malloc(96), *lbas;
X	u_long block = 0;
X	int n;
X
X	if (argc < 3)
X	{
X		fprintf(stderr, "Usage: %s device sector1 ... sectorn\n", argv[0]);
X		exit(-1);
X	}
X
X	fid = scsi_open(argv[1], O_RDWR);
X	if (fid == -1)
X	{
X		perror(argv[1]);
X		exit(errno);
X	}
X
X	scsireq = scsireq_build(scsireq_new(),
X	96, inq_buf, SCCMD_READ,
X	"12 0 0 0 v 0", 96);
X
X	if (scsireq_enter(fid, scsireq) == -1)
X	{
X		scsi_debug(stderr, -1, scsireq);
X		exit(errno);
X	}
X
X	scsireq_decode(scsireq, "b3 b5 b1 b7 b2 b3 b3 s8 z16 z16 z4",
X	&qualifier, &type, &rmb, &modifier, &iso, &ecma, &ansi,
X	vendor_id, product_id, revision);
X
X	printf("%s %s %s\n", vendor_id, product_id, revision);
X	if (type != 0)
X	{
X		printf("This is not a direct access device.\n");
X		exit(0);
X	}
X
X	switch(ansi)
X	{
X		case 0:
X		printf("WARNING: This device might not comply to any standard.\n");
X		break;
X
X		case 1:
X		printf("This is a SCSI-1 device.\n");
X		break;
X
X		case 2:
X		printf("This is a SCSI-2 device.\n");
X		break;
X	}
X
X	/* How many blocks?
X	 */
X	if (scsireq_enter(fid, scsireq_build(scsireq,
X	8, inq_buf, SCCMD_READ,
X	"25 0 0 0 0 0 0 0 0 0")) == -1)	/* Read capacity */
X	{
X		scsi_debug(stderr, -1, scsireq);
X		exit(errno);
X	}
X
X	scsireq_decode(scsireq, "i4 i4", &lba, &len);
X
X	printf("The device has %d %d byte blocks.\n", lba, len);
X	fflush(stdout);
X
X	/* Verify all blocks seem reasonable first:
X	 */
X	for (i = 2; i < argc; i++)
X	{
X		if ((block = strtoul(argv[i], 0, 0)) > lba)
X		{
X			fprintf(stderr,
X			"Block at %ld outside of maximum %d.\n", block, lba);
X			exit(-1);
X		}
X	}
X
X	n = i - 2;
X	len = 4 + 4 * n;
X	if ( (lbas = malloc(len)) == 0 )
X	{
X		perror("malloc");
X		exit(errno);
X	}
X
X	(void)scsireq_build(scsireq,
X	len, lbas, SCCMD_WRITE,
X	"07 0 0 0 0 0");
X
X	scsireq_encode(scsireq, "0 0 v:i2 ", 4 * n);
X
X	for (i = 0; i < n; i++)
X		scsireq_encode(scsireq, "sv v:i4 ", 4 + 4 * i, strtoul(argv[i + 2], 0, 0));
X
X	if (scsireq_enter(fid, scsireq) == -1)
X	{
X		perror("scsireq_enter");
X		exit(errno);
X	}
X
X	/* Did we get sense?
X	 */
X	if (scsireq->senselen_used)
X	{
X		int valid, code, key, info, asc, ascq;
X
X		scsireq_buff_decode(scsireq->sense, scsireq->senselen_used,
X		"b1 b7 *i1 *b4 b4 i4 s12 i1 i1", &valid, &code,
X		&key, &info, &asc, &ascq);
X
X		printf("Block %lx: valid %d code %02x sense key %02x info %x asc %02x ascq %02x\n",
X		block, valid, code, key, info, asc, ascq);
X		fflush(stdout);
X	}
X
X	exit(0);
X}
END-of-slipsec.c
echo x - dump-defects.c
sed 's/^X//' >dump-defects.c << 'END-of-dump-defects.c'
X#include <sys/types.h>
X#include <stdio.h>
Xint main(int ac, char *av[])
X{
X	struct header {
X		u_char stuff[2];
X		u_char length[2];
X	} h;
X
X	struct physical_sector {
X		u_char cyl[3];
X		u_char head;
X		u_char sec[4];
X	} p;
X
X	if (fread(&h, sizeof(h), 1, stdin) == 1)
X		while (fread(&p, sizeof(p), 1, stdin) == 1)
X			printf("%d %d %d\n", (p.cyl[0] << 16) | (p.cyl[1] << 8) | p.cyl[2],
X			p.head,
X			(p.sec[0] << 24) | (p.sec[1] << 16) | (p.sec[2] << 8) | p.sec[3]);
X}
END-of-dump-defects.c
echo x - defect
sed 's/^X//' >defect << 'END-of-defect'
X#!/bin/sh
Xusage()
X{
X	echo "usage: defect raw-device-name" 1>&2
X	exit 2
X}
X
X# Get the grown defect length:
X
Xif [ $# -ne 1 ] ; then
X	usage
Xfi
X
XCTL=$1
XBASE=$CTL
X
X#
X# Select what you want to read.  PList include the primary defect list
X# from the factory.  GList is grown defects only.
X#
X
XGList=1
XPList=0
X
Xif [ "x$CTL" = "x" ] ; then
X	usage
Xfi
X
Xif expr "$CTL" : 'sd[0-9][0-9]*$' > /dev/null ; then
X	# generic disk name given, convert to control device name
X	CTL="/dev/r${CTL}.ctl"
Xfi
X
Xlength=`scsi -f ${CTL} \
X-c "{ Op code} 37 0 0:3 v:1 v:1 5:3 0 0 0 0 4:i2 0" $PList $GList \
X-i 4 "{ stuff } *i2 { Defect list length } i2"`
X
Xecho "There are" `expr $length / 8` defects  
X
X# Adjust for the header:
Xlength=`expr $length + 4`
X
X# Read the defects and store to disk
X
Xscsi -f ${CTL} \
X-c "{ Op code} 37 0 0:3 v:1 v:1 5:3 0 0 0 0 v:i2 0" $PList $GList $length \
X-i $length - > /tmp/defects.$BASE
X
Xecho "Defects in /tmp/defects.$BASE"
X
X# They are in the physical sector format.  The format (assume packing) is:
X# struct physical_sector {
X#    u_short cylinder;
X#    u_char  head;
X#    u_long  sector;
X# };
X#
X# Note that they are bigendian!  You'll have to use ntohl or something.
X#
END-of-defect
exit



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