Return to BSD News archive
Newsgroups: comp.unix.bsd Path: sserve!manuel!munnari.oz.au!mips!mips!sdd.hp.com!usc!sol.ctr.columbia.edu!ucselx!crash!fpm 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 Message-ID: <1992Aug19.163236.16943@crash> Summary: bad144 bug fixed Keywords: bad144, ESDI Lines: 73 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