Subject: Re: Problems with rccide0
To: Martti Kuparinen <martti.kuparinen@iki.fi>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: current-users
Date: 12/01/2003 14:49:54
--gKMricLos+KVdGMg
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mon, Dec 01, 2003 at 10:47:51AM +0200, Martti Kuparinen wrote:
> I added few printfs:
> 
> int
> serverworks_pci_intr(arg)
>         void *arg;
> {
>         struct pciide_softc *sc = arg;
>         struct pciide_channel *cp;
>         struct channel_softc *wdc_cp;
>         int rv = 0;
>         int dmastat, i, crv;
> 
> printf("1\n");
>         for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
> printf("2 i=%d\n", i);
>                 cp = &sc->pciide_channels[i];
>                 dmastat = bus_space_read_1(sc->sc_dma_iot,
>                     cp->dma_iohs[IDEDMA_CTL], 0);
> printf("3 dmastat=0x%x\n", dmastat);
>                 if ((dmastat & (IDEDMA_CTL_ACT | IDEDMA_CTL_INTR)) !=
>                     IDEDMA_CTL_INTR)
>                         continue;
> printf("4\n");
>                 wdc_cp = &cp->wdc_channel;
>                 crv = wdcintr(wdc_cp);
> printf("5\n");
>                 if (crv == 0) {
>                         printf("%s:%d: bogus intr\n",
>                             sc->sc_wdcdev.sc_dev.dv_xname, i);
>                         bus_space_write_1(sc->sc_dma_iot,
>                             cp->dma_iohs[IDEDMA_CTL], 0, dmastat);
>                 } else
>                         rv = 1;
>         }
> printf("6\n");
>         return rv;
> }
> 
> 
> This is what comes to the console (in a never ending loop):
> 
> 1
> 2 i=0
> 3 dmastat=0x20
> 2 i=1
> 3 dmastat=0xff
> 6
> 1
> 2 i=0
> 3 dmastat=0x20
> 2 i=1
> 3 dmastat=0xff
> 6

OK, so this controller doesn't assert IDEDMA_CTL_INTR for non-DMA commands.
Unfortunably I don't know yet of another way to check if the interrupt was from
this controller or not at this point, so we have to rely on the generic
interrupt routine.

Can you try the attached patch ? It should fix the problem.

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
     NetBSD: 24 ans d'experience feront toujours la difference
--

--gKMricLos+KVdGMg
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff

Index: rccide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/rccide.c,v
retrieving revision 1.3
diff -u -r1.3 rccide.c
--- rccide.c	2003/11/27 23:02:40	1.3
+++ rccide.c	2003/12/01 13:43:17
@@ -40,6 +40,7 @@
 void serverworks_chip_map(struct pciide_softc *, struct pci_attach_args *);
 void serverworks_setup_channel(struct channel_softc *);
 int  serverworks_pci_intr(void *);
+int  serverworkscsb6_pci_intr(void *);
 
 int  rccide_match(struct device *, struct cfdata *, void *);
 void rccide_attach(struct device *, struct device *, void *);
@@ -150,8 +151,16 @@
 		cp = &sc->pciide_channels[channel];
 		if (pciide_chansetup(sc, channel, interface) == 0)
 			continue;
-		pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
-		    serverworks_pci_intr);
+		switch (sc->sc_pp->ide_product) {
+		case PCI_PRODUCT_SERVERWORKS_CSB6_IDE:
+		case PCI_PRODUCT_SERVERWORKS_CSB6_RAID:
+			pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
+			    serverworkscsb6_pci_intr);
+			break;
+		default:
+			pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
+			    serverworks_pci_intr);
+		}
 	}
 
 	pcib_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 0);
@@ -258,6 +267,33 @@
 			bus_space_write_1(sc->sc_dma_iot,
 			    cp->dma_iohs[IDEDMA_CTL], 0, dmastat);
 		} else
+			rv = 1;
+	}
+	return rv;
+}
+
+int
+serverworkscsb6_pci_intr(arg)
+	void *arg;
+{
+	struct pciide_softc *sc = arg;
+	struct pciide_channel *cp;
+	struct channel_softc *wdc_cp;
+	int rv = 0;
+	int i, crv;
+
+	for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
+		cp = &sc->pciide_channels[i];
+		wdc_cp = &cp->wdc_channel;
+		/*
+		 * The CSB6 doesn't assert IDEDMA_CTL_INTR for non-DMA commands.
+		 * Until we find a way to know if the controller posted an
+		 * interrupt, always call wdcintr(), wich will try to guess
+		 * if the interrupt was for us or not (and checks
+		 * IDEDMA_CTL_INTR for DMA commands only).
+		 */
+		crv = wdcintr(wdc_cp);
+		if (crv != 0)
 			rv = 1;
 	}
 	return rv;

--gKMricLos+KVdGMg--