Acer Labs IDE bug workaround

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Mark Kettenis
Date: Friday, November 5, 2010 - 3:40 pm

Many older revisions of the Acer Labs M5229 UDMA IDE controller have a
hardware bug that makes DMA fail for LBA48 commands fail.  As a result
accessing data on disks bigger than 137 GB beyond the 137 GB boundary
will fail.  A workaround for this is to fall back to PIO, but this is
quite a bit slower than DMA (3 MB/s vs. 15 MB/s on my setup).  A much
better approach would be to use DMA for everything below the 137 GB
boundary and PIO for everything above.  I never found an elegant way
to do that though.

Recently, Takeshi Nakayama did post a diff to the NetBSD sparc64
mailing list that has a fairly elegant way to fix this:

http://mail-index.netbsd.org/port-sparc64/2010/10/26/msg001398.html

Here's the equivalent diff for our tree.  With this diff, I can access
everything on a 160 GB disk.  Accessing the tail end is quite a bit
slower than the start of the disk.  For that reason NetBSD prints a
warning in dmesg.  I chose not to do that for now, but I can probably
be convinced to add a printf here.

ok?


Index: ata/ata_wdc.c
===================================================================
RCS file: /cvs/src/sys/dev/ata/ata_wdc.c,v
retrieving revision 1.34
diff -u -p -r1.34 ata_wdc.c
--- ata/ata_wdc.c	23 Jul 2010 07:47:12 -0000	1.34
+++ ata/ata_wdc.c	5 Nov 2010 22:18:48 -0000
@@ -167,7 +167,7 @@ _wdc_ata_bio_start(struct channel_softc 
 	u_int8_t head, sect, cmd = 0;
 	int nblks;
 	int ata_delay;
-	int dma_flags = 0;
+	int error, dma_flags = 0;
 
 	WDCDEBUG_PRINT(("_wdc_ata_bio_start %s:%d:%d\n",
 	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
@@ -249,10 +249,21 @@ again:
 				cmd = (ata_bio->flags & ATA_READ) ?
 				    WDCC_READDMA : WDCC_WRITEDMA;
 	    		/* Init the DMA channel. */
-			if ((*chp->wdc->dma_init)(chp->wdc->dma_arg,
+			error = (*chp->wdc->dma_init)(chp->wdc->dma_arg,
 			    chp->channel, xfer->drive,
 			    (char *)xfer->databuf + xfer->c_skip,
-			    ata_bio->nbytes, dma_flags) != 0) {
+			    ata_bio->nbytes, dma_flags);
+			if (error) {
+				if (error == EINVAL) {
+					/*
+					 * We can't do DMA on this transfer
+					 * for some reason.  Fall back to
+					 * PIO.
+					 */
+					xfer->c_flags &= ~C_DMA;
+					error = 0;
+					goto do_pio;
+				}
 				ata_bio->error = ERR_DMA;
 				ata_bio->r_error = 0;
 				wdc_ata_bio_done(chp, xfer);
@@ -276,6 +287,7 @@ again:
 			/* wait for irq */
 			goto intr;
 		} /* else not DMA */
+ do_pio:
 		ata_bio->nblks = min(nblks, ata_bio->multi);
 		ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize;
 		KASSERT(nblks == 1 || (ata_bio->flags & ATA_SINGLE) == 0);
Index: pci/pciide.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/pciide.c,v
retrieving revision 1.321
diff -u -p -r1.321 pciide.c
--- pci/pciide.c	31 Aug 2010 17:13:44 -0000	1.321
+++ pci/pciide.c	5 Nov 2010 22:18:51 -0000
@@ -215,6 +215,7 @@ void ns_scx200_setup_channel(struct chan
 void acer_chip_map(struct pciide_softc *, struct pci_attach_args *);
 void acer_setup_channel(struct channel_softc *);
 int  acer_pci_intr(void *);
+int  acer_dma_init(void *, int, int, void *, size_t, int);
 
 void pdc202xx_chip_map(struct pciide_softc *, struct pci_attach_args *);
 void pdc202xx_setup_channel(struct channel_softc *);
@@ -5629,6 +5630,8 @@ acer_chip_map(struct pciide_softc *sc, s
 		}
 		sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
 		sc->sc_wdcdev.irqack = pciide_irqack;
+		if (rev <= 0xC4)
+			sc->sc_wdcdev.dma_init = acer_dma_init;
 	}
 
 	sc->sc_wdcdev.PIO_cap = 4;
@@ -5821,6 +5824,17 @@ acer_pci_intr(void *arg)
 		}
 	}
 	return (rv);
+}
+
+int
+acer_dma_init(void *v, int channel, int drive, void *databuf,
+    size_t datalen, int flags)
+{
+	/* Use PIO for LBA48 transfers. */
+	if (flags & WDC_DMA_LBA48)
+		return (EINVAL);
+
+	return (pciide_dma_init(v, channel, drive, databuf, datalen, flags));
 }
 
 void
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
Acer Labs IDE bug workaround, Mark Kettenis, (Fri Nov 5, 3:40 pm)
Re: Acer Labs IDE bug workaround, Kenneth R Westerback, (Sat Nov 6, 8:20 am)