Subject: Promise Ultra60/100 vs 48-bit LBA compliant drives
To: None <tech-kern@netbsd.org>
From: Takeshi Nakayama <tn@catvmics.ne.jp>
List: tech-kern
Date: 04/27/2003 07:41:57
----Next_Part(Sun_Apr_27_07:41:10_2003_914)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hello,

I have i386 machine which has on-board Promise Ultra100 ATA
controller. When I connect 48-bit LBA compliant drive (IBM
IC35L120AVV207-0) to it, it does not work with any DMA mode (see
attached dmesg.log).

According to FreeBSD driver, it needs some extra operation in
48-bit LBA mode with some old Promise controllers. So I wrote an
attached patch, then works fine with DMA mode.

Could someone please review this patch?

-- Takeshi Nakayama

----Next_Part(Sun_Apr_27_07:41:10_2003_914)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="dmesg.log"

pciide0 at pci0 dev 6 function 0: Promise Ultra100/ATA Bus Master IDE Accelerator (rev. 0x02)
pciide0: bus-master DMA support present
pciide0: primary channel configured to native-PCI mode
pciide0: using irq 9 for native-PCI interrupt
wd0 at pciide0 channel 0 drive 0: <IC35L120AVV207-0>
wd0: drive supports 16-sector PIO transfers, LBA48 addressing
wd0: 115 GB, 16383 cyl, 16 head, 63 sec, 512 bytes/sect x 241254720 sectors
wd0: 32-bit data port
wd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 5 (Ultra/100)
wd0(pciide0:0:0): using PIO mode 4, Ultra-DMA mode 5 (Ultra/100) (using DMA data transfers)
pciide0: secondary channel configured to native-PCI mode
wd1 at pciide0 channel 1 drive 0: <IC35L060AVER07-0>
wd1: drive supports 16-sector PIO transfers, LBA addressing
wd1: 58644 MB, 16383 cyl, 16 head, 63 sec, 512 bytes/sect x 120103200 sectors
wd1: 32-bit data port
wd1: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 5 (Ultra/100)
wd1(pciide0:1:0): using PIO mode 4, Ultra-DMA mode 5 (Ultra/100) (using DMA data transfers)
 :
 :
pciide0:0:0: lost interrupt
	type: ata tc_bcount: 512 tc_skip: 0
pciide0:0:0: bus-master DMA error: missing interrupt, status=0x21
wd0: transfer error, downgrading to Ultra-DMA mode 2
wd0(pciide0:0:0): using PIO mode 4, Ultra-DMA mode 2 (Ultra/33) (using DMA data transfers)
wd0d: DMA error reading fsbn 0 (wd0 bn 0; cn 0 tn 0 sn 0), retrying
pciide0:0:0: lost interrupt
	type: ata tc_bcount: 512 tc_skip: 0
pciide0:0:0: bus-master DMA error: missing interrupt, status=0x21
wd0: transfer error, downgrading to Ultra-DMA mode 1
wd0(pciide0:0:0): using PIO mode 4, Ultra-DMA mode 1 (using DMA data transfers)
wd0d: DMA error reading fsbn 0 (wd0 bn 0; cn 0 tn 0 sn 0), retrying
pciide0:0:0: lost interrupt
	type: ata tc_bcount: 512 tc_skip: 0
pciide0:0:0: bus-master DMA error: missing interrupt, status=0x21
wd0: transfer error, downgrading to DMA mode 2
wd0(pciide0:0:0): using PIO mode 4, DMA mode 2 (using DMA data transfers)
wd0d: DMA error reading fsbn 0 (wd0 bn 0; cn 0 tn 0 sn 0), retrying
pciide0:0:0: lost interrupt
	type: ata tc_bcount: 512 tc_skip: 0
pciide0:0:0: bus-master DMA error: missing interrupt, status=0x21
wd0: transfer error, downgrading to PIO mode 4
wd0(pciide0:0:0): using PIO mode 4
wd0d: DMA error reading fsbn 0 (wd0 bn 0; cn 0 tn 0 sn 0), retrying
wd0: soft error (corrected)
boot device: wd0
root on wd0a dumps on wd0b
root file system type: ffs

----Next_Part(Sun_Apr_27_07:41:10_2003_914)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="promise-ultra60_100-lba48.diff"

Index: sys/dev/ata/ata_wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ata_wdc.c,v
retrieving revision 1.38
diff -u -d -r1.38 ata_wdc.c
--- sys/dev/ata/ata_wdc.c	2002/09/27 15:37:09	1.38
+++ sys/dev/ata/ata_wdc.c	2003/04/26 22:20:40
@@ -271,6 +271,8 @@
 		if (drvp->n_xfers <= NXFER)
 			drvp->n_xfers++;
 		dma_flags = (ata_bio->flags & ATA_READ) ?  WDC_DMA_READ : 0;
+		if (ata_bio->flags & ATA_LBA48)
+			dma_flags |= WDC_DMA_LBA48;
 	}
 	if (ata_bio->flags & ATA_SINGLE)
 		ata_delay = ATA_DELAY;
Index: sys/dev/ic/wdcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdcvar.h,v
retrieving revision 1.35
diff -u -d -r1.35 wdcvar.h
--- sys/dev/ic/wdcvar.h	2003/01/27 18:21:26	1.35
+++ sys/dev/ic/wdcvar.h	2003/04/26 22:20:41
@@ -124,8 +124,9 @@
 	void           (*dma_start) __P((void *, int, int));
 	int            (*dma_finish) __P((void *, int, int, int));
 /* flags passed to dma_init */
-#define WDC_DMA_READ 0x01
-#define WDC_DMA_IRQW 0x02
+#define WDC_DMA_READ	0x01
+#define WDC_DMA_IRQW	0x02
+#define WDC_DMA_LBA48	0x04
 	int		dma_status; /* status returned from dma_finish() */
 #define WDC_DMAST_NOIRQ	0x01	/* missing IRQ */
 #define WDC_DMAST_ERR	0x02	/* DMA error */
Index: sys/dev/pci/pciide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pciide.c,v
retrieving revision 1.190
diff -u -d -r1.190 pciide.c
--- sys/dev/pci/pciide.c	2003/04/19 23:37:26	1.190
+++ sys/dev/pci/pciide.c	2003/04/26 22:20:44
@@ -210,6 +210,8 @@
 void pdc20268_setup_channel __P((struct channel_softc*));
 int  pdc202xx_pci_intr __P((void *));
 int  pdc20265_pci_intr __P((void *));
+static void pdc20262_dma_start __P((void*, int, int));
+static int  pdc20262_dma_finish __P((void*, int, int, int));
 
 void opti_chip_map __P((struct pciide_softc*, struct pci_attach_args*));
 void opti_setup_channel __P((struct channel_softc*));
@@ -4337,6 +4339,13 @@
 	sc->sc_wdcdev.channels = sc->wdc_chanarray;
 	sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
 
+	if (sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA66 ||
+	    sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100 ||
+	    sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA100X) {
+		sc->sc_wdcdev.dma_start = pdc20262_dma_start;
+		sc->sc_wdcdev.dma_finish = pdc20262_dma_finish;
+	}
+
 	if (!PDC_IS_268(sc)) {
 		/* setup failsafe defaults */
 		mode = 0;
@@ -4661,6 +4670,61 @@
 			rv = 1;
 	}
 	return rv;
+}
+
+static void
+pdc20262_dma_start(v, channel, drive)
+	void *v;
+	int channel, drive;
+{
+	struct pciide_softc *sc = v;
+	struct pciide_dma_maps *dma_maps =
+	    &sc->pciide_channels[channel].dma_maps[drive];
+	int atapi;
+
+	if (dma_maps->dma_flags & WDC_DMA_LBA48) {
+		atapi = (dma_maps->dma_flags & WDC_DMA_READ) ?
+		    PDC262_ATAPI_LBA48_READ : PDC262_ATAPI_LBA48_WRITE;
+		atapi |= dma_maps->dmamap_xfer->dm_mapsize >> 1;
+		bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
+		    PDC262_ATAPI(channel), atapi);
+	}
+
+	pciide_dma_start(v, channel, drive);
+}
+
+int
+pdc20262_dma_finish(v, channel, drive, force)
+	void *v;
+	int channel, drive;
+	int force;
+{
+	struct pciide_softc *sc = v;
+	struct pciide_dma_maps *dma_maps =
+	    &sc->pciide_channels[channel].dma_maps[drive];
+	struct channel_softc *chp;
+	int atapi, error;
+
+	error = pciide_dma_finish(v, channel, drive, force);
+
+	if (dma_maps->dma_flags & WDC_DMA_LBA48) {
+		chp = sc->wdc_chanarray[channel];
+		atapi = 0;
+		if (chp->ch_drive[0].drive_flags & DRIVE_ATAPI ||
+		    chp->ch_drive[1].drive_flags & DRIVE_ATAPI) {
+			if ((!(chp->ch_drive[0].drive_flags & DRIVE_UDMA) ||
+			    (chp->ch_drive[1].drive_flags & DRIVE_UDMA) ||
+			    !(chp->ch_drive[1].drive_flags & DRIVE_DMA)) &&
+			    (!(chp->ch_drive[1].drive_flags & DRIVE_UDMA) ||
+			    (chp->ch_drive[0].drive_flags & DRIVE_UDMA) ||
+			    !(chp->ch_drive[0].drive_flags & DRIVE_DMA)))
+				atapi = PDC262_ATAPI_UDMA;
+		}
+		bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
+		    PDC262_ATAPI(channel), atapi);
+	}
+
+	return error;
 }
 
 void
Index: sys/dev/pci/pciide_pdc202xx_reg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pciide_pdc202xx_reg.h,v
retrieving revision 1.8
diff -u -d -r1.8 pciide_pdc202xx_reg.h
--- sys/dev/pci/pciide_pdc202xx_reg.h	2002/07/26 14:11:35	1.8
+++ sys/dev/pci/pciide_pdc202xx_reg.h	2003/04/26 22:20:45
@@ -99,6 +99,8 @@
 #define PDC262_ATAPI_DMA_READ	0x00001000
 #define PDC262_ATAPI_DMA_WRITE	0x00002000
 #define PDC262_ATAPI_UDMA	0x00004000
+#define PDC262_ATAPI_LBA48_READ  0x05000000
+#define PDC262_ATAPI_LBA48_WRITE 0x06000000
 
 /*
  * The timings provided here cmoes from the PDC20262 docs. I hope they are

----Next_Part(Sun_Apr_27_07:41:10_2003_914)----