Skip site navigation (1)Skip section navigation (2)
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>