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>
