From: fpm@crash.cts.com (Frank Maclachlan)
Subject: wd.c problem (w/ Patch)
Organization: CTS Network Services (crash, ctsnet), El Cajon, CA
Date: 19 Aug 92 16:32:35 PDT
Summary: bad144 bug fixed
Keywords: bad144, ESDI

Greetings:

I think there is a problem in 'usr/src/sys.386bsd/i386/isa/wd.c'
when the first sector in a multi-sector read or write request is
present in the bad144 table.  The bad144 table search code at
line 382 finds the sector in the bad144 table and replaces the
block number, cylinder, head, and sector addresses with values
corresponding to the replacement sector.  At line 434, the sector
count register is loaded with the number of sectors in the entire
transfer.  This is wrong; it *MUST* be set to *one* sector.  A
read would return the wrong data in sectors after the first; a
write would *overwrite* other replacement sectors or even the
bad144 table on the last track.

You could fix this by changing lines 382 and 383 from

	if ((du->dk_flags & (/*DKFL_SINGLE|*/DKFL_BADSECT))
		== (/*DKFL_SINGLE|*/DKFL_BADSECT))

to
	if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT))
		== (DKFL_SINGLE|DKFL_BADSECT))

This prevents the defective sector from being replaced the first
time through (DKFL_SINGLE is not set).  Assuming the sector is
marked bad, the read or write of the defective sector will fail,
and the interrupt routine (wdintr) will retry the operation with
the DKFL_SINGLE bit set.  This causes the sector to be replaced
and the transfer count is properly set to 1.

Another solution is to leave the above two lines unchanged and
apply the following patch.  This has the advantage of immediately
replacing a defective sector at the start of a transfer without
requiring that the operation first fail.

---- snip snip ----
*** wd.c.ORIG	Wed Aug 19 15:43:21 1992
--- wd.c	Wed Aug 19 16:16:18 1992
***************
*** 402,407 ****
--- 402,408 ----
  			cylin = blknum / secpercyl;
  			head = (blknum % secpercyl) / secpertrk;
  			sector = blknum % secpertrk;
+ 			du->dk_flags |= DKFL_SINGLE;
  #ifdef	WDDEBUG
  			    printf("new = %d\n", blknum);
  #endif
---- snip snip ----

Note that the bad144 code *doesn't* work unless *all* sectors
present in the bad144 table are marked bad (any attempt to read
or write any of them will return an immediate error - usually a
BAD BLOCK error code).

On a different note, when setting up your hard disk, be aware that
many diagnostic packages assume that the last cylinder on a hard
disk is a test cylinder and will cheerfully scribble on it when
performing hard disk diagnostics.  Also, if the hard disk has more
than 1024 cylinders and the BIOS parameter table entry for the
drive shows less than the number of cylinders on the drive (a
Western Digital WD1007v-se2 controller attached to a drive having
1222 cylinders sets up a BIOS parameter table indicating 1023
cylinders), disk diagnostics assume that the last cylinder as
specified by the BIOS parameter table is a test cylinder.  I once
trashed an SCO Xenix filesystem by running a diagnostic which
wrote test patterns on cylinder 1023 on a 1222 cylinder hard disk.
You have been warned!
--
UUCP: {hplabs!hp-sdd ucsd nosc}!crash!fpm
ARPA: crash!fpm@nosc.mil
INET: fpm@crash.cts.com

Newsgroups: comp.unix.bsd