Date: Tue, 4 Feb 1997 00:01:18 -0500 From: garman@jason.garman.net (Jason Garman) To: helbig@BA-Stuttgart.De (Wolfgang Helbig) Cc: nadav@cs.technion.ac.il (Nadav Eiron), hackers@freebsd.org Subject: Re: CMD640b flaw workaround Message-ID: <Mutt.19970204000118.garman@jason.garman.net> In-Reply-To: <199702021846.TAA03678@amadeus.informatik.ba-stuttgart.de>; from Wolfgang Helbig on Feb 2, 1997 19:04:49 %2B0100 References: <Pine.GSO.3.95-heb-2.07.970202182140.22764B-100000@csd> <199702021846.TAA03678@amadeus.informatik.ba-stuttgart.de>
next in thread | previous in thread | raw e-mail | index | archive | help
--tb47fdMN=vveGnh= Wolfgang Helbig writes: > Sorry, but the diff is against revision 1.122 of wd.c , whereas > you have revision 1.81.4.2 in FreeBSD 2.1.6.1 . So the patch will not > work. I tried to produce the diff from 1.122 to 1.81.4.2 and applying > a patch with it to my version of wd.c but there were to many rejects. > After some hacking, I've produced a patch that seems to work for me (FreeBSD 2.1.5-RELEASE). Attached are the patches (it looked like i had to patch atapi.c so atapi_attach could return a value) I don't know if this is the Right Way[tm] of doing this, or if my modifications introduce bugs in the code, but it works for me (after a whopping 5 minutes of testing) Hopefully this helps those stuck with these cmd chips on 2.1.x machines... Enjoy, -- Jason Garman http://www.nesc.k12.ar.us/~garman/ Student, Eleanor Roosevelt High School garman@phs.k12.ar.us --tb47fdMN=vveGnh= Content-Disposition: attachment; filename="wd.c.diffs" --- wd.old.c Mon Dec 2 23:32:06 1996 +++ wd.c Mon Feb 3 23:49:46 1997 @@ -190,6 +190,8 @@ #define RECAL 2 /* doing restore */ #define OPEN 3 /* done with open */ +#define PRIMARY 0 + /* * Disk geometry. A small part of struct disklabel. * XXX disklabel.5 contains an old clone of disklabel.h. @@ -277,6 +279,11 @@ wdprobe, wdattach, "wdc", }; +#ifdef CMD640 +static int wdcports[NWDC]; +static int atapictrlr; +#endif + /* * Probe for controller. */ @@ -296,6 +303,10 @@ du->dk_ctrlr = dvp->id_unit; du->dk_port = dvp->id_iobase; +#ifdef CMD640 + wdcports[du->dk_ctrlr] = du->dk_port; +#endif + wdc_registerdev(dvp); /* check if we have registers that work */ @@ -415,6 +426,10 @@ du->dk_lunit = lunit; du->dk_port = dvp->id_iobase; +#ifdef CMD640 + wdcports[du->dk_ctrlr] = du->dk_port; +#endif + /* * Use the individual device flags or the controller * flags. @@ -491,16 +506,26 @@ if (wddrives[lunit]->dk_ctrlr == dvp->id_unit && wddrives[lunit]->dk_unit == unit) goto next; - atapi_attach (dvp->id_unit, unit, dvp->id_iobase, - &kdc_wdc[dvp->id_unit]); + if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase, + &kdc_wdc[dvp->id_unit]) == 1) { + /* 2.1.5's atapi_attach does not return a value */ +#ifdef CMD640 + wdcports[unit] = dvp->id_iobase; + atapictrlr = dvp->id_unit; + printf ("wd: atapictrlr = %d\n", atapictrlr); +#endif + } next: } #endif /* * Discard any interrupts generated by wdgetctlr(). wdflushirq() * doesn't work now because the ambient ipl is too high. */ +#ifdef CMD640 + wdtab[PRIMARY].b_active = 2; +#else wdtab[dvp->id_unit].b_active = 2; - +#endif return (1); } @@ -576,7 +601,11 @@ du->dk_state = WANTOPEN; } +#ifdef CMD640 + if (wdtab[PRIMARY].b_active == 0) +#else if (wdtab[du->dk_ctrlr].b_active == 0) +#endif wdstart(du->dk_ctrlr); /* start controller */ if (du->dk_dkunit >= 0) { @@ -638,13 +667,21 @@ dp->b_actf = bp->b_actf; bp->b_actf = NULL; /* link onto controller queue */ +#ifdef CMD640 + if (wdtab[PRIMARY].b_actf == NULL) { + wdtab[PRIMARY].b_actf = bp; + } else { + *wdtab[PRIMARY].b_actb = bp; + } + wdtab[PRIMARY].b_actb = &bp->b_actf; +#else if (wdtab[ctrlr].b_actf == NULL) { wdtab[ctrlr].b_actf = bp; } else { *wdtab[ctrlr].b_actb = bp; } wdtab[ctrlr].b_actb = &bp->b_actf; - +#endif /* mark the drive unit as busy */ dp->b_active = 1; } @@ -670,20 +707,40 @@ int count; #ifdef ATAPI +#ifdef CMD640 + if (wdtab[PRIMARY].b_active == 2) + wdtab[PRIMARY].b_active = 0; + if (wdtab[PRIMARY].b_active) + return; +#else if (wdtab[ctrlr].b_active == 2) wdtab[ctrlr].b_active = 0; if (wdtab[ctrlr].b_active) return; #endif +#endif + loop: /* is there a drive for the controller to do a transfer with? */ +#ifdef CMD640 + bp = wdtab[PRIMARY].b_actf; +#else bp = wdtab[ctrlr].b_actf; +#endif if (bp == NULL) { #ifdef ATAPI +#ifdef CMD640 + if (atapi_start (atapictrlr)) +#else if (atapi_start (ctrlr)) +#endif /* mark controller active in ATAPI mode */ +#ifdef CMD640 + wdtab[PRIMARY].b_active = 3; +#else wdtab[ctrlr].b_active = 3; #endif +#endif return; } @@ -739,7 +796,11 @@ blknum - ds_offset) + ds_offset; } +#ifdef CMD640 + wdtab[PRIMARY].b_active = 1; +#else wdtab[ctrlr].b_active = 1; /* mark controller active */ +#endif /* if starting a multisector transfer, or doing single transfers */ if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) { @@ -751,7 +812,11 @@ head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; +#ifdef CMD640 + if (wdtab[PRIMARY].b_errcnt && (bp->b_flags & B_READ) == 0) +#else if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) +#endif du->dk_bc += DEV_BSIZE; count = howmany( du->dk_bc, DEV_BSIZE); @@ -898,9 +963,15 @@ register struct disk *du; register struct buf *bp, *dp; +#ifdef CMD640 + if (wdtab[PRIMARY].b_active == 2) + return; + if (!wdtab[PRIMARY].b_active) { +#else if (wdtab[unit].b_active == 2) return; /* intr in wdflushirq() */ if (!wdtab[unit].b_active) { +#endif #ifdef WDDEBUG /* * These happen mostly because the power-mgt part of the @@ -911,19 +982,29 @@ #endif return; } -#ifdef ATAPI +#ifdef CMD640 + if (wdtab[PRIMARY].b_active == 3) { +#else if (wdtab[unit].b_active == 3) { +#endif /* process an ATAPI interrupt */ if (atapi_intr (unit)) /* ATAPI op continues */ return; /* controller is free, start new op */ +#ifdef CMD640 + wdtab[PRIMARY].b_active = 0; +#else wdtab[unit].b_active = 0; +#endif wdstart (unit); return; } -#endif +#ifdef CMD640 + bp = wdtab[PRIMARY].b_actf; +#else bp = wdtab[unit].b_actf; +#endif du = wddrives[dkunit(bp->b_dev)]; dp = &wdutab[du->dk_lunit]; du->dk_timeout = 0; @@ -935,7 +1016,11 @@ /* is it not a transfer, but a control operation? */ if (du->dk_state < OPEN) { +#ifdef CMD640 + wdtab[PRIMARY].b_active = 0; +#else wdtab[unit].b_active = 0; +#endif switch (wdcontrol(bp)) { case 0: return; @@ -977,8 +1062,13 @@ bp->b_error = EIO; bp->b_flags |= B_ERROR; } else if (du->dk_status & WDCS_ERR) { +#ifdef CMD640 + if (++wdtab[PRIMARY].b_errcnt < RETRIES) { + wdtab[PRIMARY].b_active = 0; +#else if (++wdtab[unit].b_errcnt < RETRIES) { wdtab[unit].b_active = 0; +#endif } else { wderror(bp, du, "hard error"); bp->b_error = EIO; @@ -992,7 +1082,11 @@ * If this was a successful read operation, fetch the data. */ if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) +#ifdef CMD640 + && wdtab[PRIMARY].b_active) { +#else && wdtab[unit].b_active) { +#endif int chk, dummy, multisize; multisize = chk = du->dk_currentiosize * DEV_BSIZE; if( du->dk_bc < chk) { @@ -1034,18 +1128,32 @@ } outt: +#ifdef CMD640 + if (wdtab[PRIMARY].b_active) { +#else if (wdtab[unit].b_active) { +#endif if ((bp->b_flags & B_ERROR) == 0) { du->dk_skip += du->dk_currentiosize;/* add to successful sectors */ +#ifdef CMD640 + if (wdtab[PRIMARY].b_errcnt) + wderror(bp, du, "soft error"); + wdtab[PRIMARY].b_errcnt = 0; +#else if (wdtab[unit].b_errcnt) wderror(bp, du, "soft error"); wdtab[unit].b_errcnt = 0; +#endif /* see if more to transfer */ if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) { if( (du->dk_flags & DKFL_SINGLE) || ((bp->b_flags & B_READ) == 0)) { +#ifdef CMD640 + wdtab[PRIMARY].b_active = 0; +#else wdtab[unit].b_active = 0; +#endif wdstart(unit); } else { du->dk_timeout = 1 + 3; @@ -1056,7 +1164,11 @@ du->dk_skip = 0; du->dk_flags &= ~DKFL_ERROR; du->dk_flags |= DKFL_SINGLE; +#ifdef CMD640 + wdtab[PRIMARY].b_active = 0; +#else wdtab[unit].b_active = 0; +#endif wdstart(unit); return; /* redo xfer sector by sector */ } @@ -1065,8 +1177,13 @@ done: ; /* done with this transfer, with or without error */ du->dk_flags &= ~DKFL_SINGLE; +#ifdef CMD640 + wdtab[PRIMARY].b_actf = bp->b_actf; + wdtab[PRIMARY].b_errcnt = 0; +#else wdtab[unit].b_actf = bp->b_actf; wdtab[unit].b_errcnt = 0; +#endif bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE; dp->b_active = 0; dp->b_errcnt = 0; @@ -1079,15 +1196,23 @@ } /* controller idle */ +#ifdef CMD640 + wdtab[PRIMARY].b_active = 0; +#else wdtab[unit].b_active = 0; +#endif /* anything more on drive queue? */ wdustart(du); /* anything more for controller to do? */ #ifndef ATAPI /* This is not valid in ATAPI mode. */ +#ifdef CMD640 + if (wdtab[PRIMARY].b_actf) +#else if (wdtab[unit].b_actf) #endif +#endif wdstart(unit); } @@ -1112,8 +1237,13 @@ return (ENXIO); /* Finish flushing IRQs left over from wdattach(). */ +#ifdef CMD640 + if (wdtab[PRIMARY].b_active == 2) + wdtab[PRIMARY].b_active = 0; +#else if (wdtab[du->dk_ctrlr].b_active == 2) wdtab[du->dk_ctrlr].b_active = 0; +#endif du->dk_flags &= ~DKFL_BADSCAN; @@ -1285,7 +1415,11 @@ switch (du->dk_state) { case WANTOPEN: tryagainrecal: +#ifdef CMD640 + wdtab[PRIMARY].b_active = 1; +#else wdtab[ctrlr].b_active = 1; +#endif if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) { wderror(bp, du, "wdcontrol: wdcommand failed"); goto maybe_retry; @@ -1299,13 +1433,21 @@ if (du->dk_status & WDCS_ERR) wdunwedge(du); du->dk_state = WANTOPEN; +#ifdef CMD640 + if (++wdtab[PRIMARY].b_errcnt < RETRIES) +#else if (++wdtab[ctrlr].b_errcnt < RETRIES) +#endif goto tryagainrecal; bp->b_error = ENXIO; /* XXX needs translation */ bp->b_flags |= B_ERROR; return (2); } +#ifdef CMD640 + wdtab[PRIMARY].b_errcnt = 0; +#else wdtab[ctrlr].b_errcnt = 0; +#endif du->dk_state = OPEN; /* * The rest of the initialization can be done by normal @@ -1389,7 +1531,11 @@ error = 1; } if (error) { +#ifdef CMD640 + wdtab[PRIMARY].b_errcnt += RETRIES; +#else wdtab[du->dk_ctrlr].b_errcnt += RETRIES; +#endif return (1); } if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0, @@ -1766,6 +1912,8 @@ #if 0 /* Mark controller active for if we panic during the dump. */ + /* does it really matter if we delete this chunk to fix the CMD + bug? The dump should be the only thing happening anyhow... */ wdtab[du->dk_ctrlr].b_active = 1; #endif wddoingadump = 1; @@ -1914,10 +2062,17 @@ static void wdflushirq(struct disk *du, int old_ipl) { +#ifdef CMD640 + wdtab[PRIMARY].b_active = 2; + splx (old_ipl); + (void) splbio(); + wdtab[PRIMARY].b_active = 0; +#else wdtab[du->dk_ctrlr].b_active = 2; splx(old_ipl); (void)splbio(); wdtab[du->dk_ctrlr].b_active = 0; +#endif } /* @@ -1956,8 +2111,14 @@ static void wdsleep(int ctrlr, char *wmesg) { +/* is the splbio/splx pair needed from the 2.2 sources? */ +#ifdef CMD640 + while (wdtab[PRIMARY].b_active) + tsleep((caddr_t)&wdtab[PRIMARY].b_active, PZERO - 1, wmesg, 1); +#else while (wdtab[ctrlr].b_active) tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1); +#endif } static void @@ -2032,6 +2193,36 @@ static int min_retries[NWDC]; #endif +#ifdef CMD640 +int +cmd640_wait(int port) +{ + int port2; + int timeout; + u_char status; + + return (0); + if (NWDC == 1) + return (0); + + if (wdcports[0] == port) + port2 = wdcports[1]; + else + port2 = wdcports[0]; + if (port2 == 0) + return (0); + for (timeout = TIMEOUT; timeout > 0; timeout--) { + status = inb(port2 + wd_status); + if (!(status & WDCS_BUSY)) + return (0); + DELAY (1000); + printf("called by port %x\n",port); + } + printf("wd: timeout on port %x\n", port2); + return (-1); +} +#endif + static int wdwait(struct disk *du, u_char bits_wanted, int timeout) { @@ -2042,6 +2233,11 @@ wdc = du->dk_port; timeout += POLLING; + +#ifdef CMD640 + if (cmd640_wait (wdc) != 0) + return (-1); +#endif /* * This delay is really too long, but does not impact the performance --tb47fdMN=vveGnh= Content-Disposition: attachment; filename="atapi.h.diffs" --- atapi.old.h Fri Sep 29 20:11:16 1995 +++ atapi.h Mon Feb 3 23:50:29 1997 @@ -193,7 +193,7 @@ #ifdef KERNEL struct atapi; struct kern_devconf; -void atapi_attach (int ctlr, int unit, int port, struct kern_devconf*); +int atapi_attach (int ctlr, int unit, int port, struct kern_devconf*); int atapi_start (int ctrlr); int atapi_intr (int ctrlr); void atapi_debug (struct atapi *ata, int on); --tb47fdMN=vveGnh= Content-Disposition: attachment; filename="atapi.c.diffs" --- atapi.old.c Mon Feb 3 23:48:29 1997 +++ atapi.c Mon Feb 3 23:51:30 1997 @@ -168,7 +168,7 @@ extern int wdstart (int ctrlr); -void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) +int atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) { struct atapi *ata = atapitab + ctlr; struct atapi_params *ap; @@ -179,7 +179,7 @@ print (("atapi%d.%d at 0x%x: attach called\n", ctlr, unit, port)); ap = atapi_probe (port, unit); if (! ap) - return; + return 0; bcopy (ap->model, buf, sizeof(buf)-1); buf[sizeof(buf)-1] = 0; @@ -245,7 +245,7 @@ printf ("wdc%d: unit %d: unknown ATAPI protocol=%d\n", ctlr, unit, ap->proto); free (ap, M_TEMP); - return; + return 0; } switch (ap->devtype) { default: @@ -265,7 +265,7 @@ break; } /* Device attached successfully. */ - return; + return 1; #else printf ("wdc%d: ATAPI CD-ROMs not configured\n", ctlr); break; @@ -289,6 +289,7 @@ } /* Attach failed. */ free (ap, M_TEMP); + return 0; } static void bswap (char *buf, int len) --tb47fdMN=vveGnh=--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Mutt.19970204000118.garman>