Subject: Re: Support for polled IDE controllers
To: Manuel Bouyer <bouyer@antioche.lip6.fr>
From: Ben Harris <bjh21@netbsd.org>
List: tech-kern
Date: 06/12/2001 00:20:07
On Mon, 11 Jun 2001, Ben Harris wrote:

> > Otherwise we need a way to pass this capability up to wd or scsipi, so that
> > the polling flag can be set from the beggining. Setting it in the
> > middle of the xfer won't work.
>
> Well, my patch effectively already passes it up to wd, since it has to
> know to mark its xfers as polled.  The ATAPI side is trickier, but there
> are already polled SCSI controllers (e.g. ncr5380 with
> NCR5380_FORCE_POLL), so I don't think pushing knowledge of polling
> adaptors up to scspi_execute_xs (where it looks like it belongs) would be
> terribly inappropriate.  I'll see if I can work out how to do it.

OK.  Here's a rough patch that pushes knowledge of polling adaptors up
into the scsipi layer, as well as adding support for polling wdc.  For
fun, it also includes a patch to ncr5380sbc.c to make it use the new
mechanism.  I've tested it with an ATAPI CD-ROM drive and an ATA hard disc
on a polling IDE controller, and a SCSI hard disc on a polling 5380.

Index: sys/dev/ata/ata_wdc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ata/ata_wdc.c,v
retrieving revision 1.29
diff -u -p -r1.29 ata_wdc.c
--- sys/dev/ata/ata_wdc.c	2001/04/18 05:40:03	1.29
+++ sys/dev/ata/ata_wdc.c	2001/06/11 22:58:28
@@ -141,6 +141,8 @@ wdc_ata_bio(drvp, ata_bio)
 	xfer = wdc_get_xfer(WDC_NOSLEEP);
 	if (xfer == NULL)
 		return WDC_TRY_AGAIN;
+	if (chp->wdc->cap & WDC_CAPABILITY_NOIRQ)
+		ata_bio->flags |= ATA_POLL;
 	if (ata_bio->flags & ATA_POLL)
 		xfer->c_flags |= C_POLL;
 	if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
@@ -592,10 +594,8 @@ wdc_ata_bio_kill_xfer(chp, xfer)
 	ata_bio->flags |= ATA_ITSDONE;
 	ata_bio->error = ERR_NODEV;
 	ata_bio->r_error = WDCE_ABRT;
-	if ((ata_bio->flags & ATA_POLL) == 0) {
-		WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
-		wddone(chp->ch_drive[drive].drv_softc);
-	}
+	WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
+	wddone(chp->ch_drive[drive].drv_softc);
 }

 void
@@ -620,10 +620,8 @@ wdc_ata_bio_done(chp, xfer)
 	wdc_free_xfer(chp, xfer);

 	ata_bio->flags |= ATA_ITSDONE;
-	if ((ata_bio->flags & ATA_POLL) == 0) {
-		WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
-		wddone(chp->ch_drive[drive].drv_softc);
-	}
+	WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
+	wddone(chp->ch_drive[drive].drv_softc);
 	WDCDEBUG_PRINT(("wdcstart from wdc_ata_done, flags 0x%x\n",
 	    chp->ch_flags), DEBUG_XFERS);
 	wdcstart(chp);
Index: sys/dev/ata/wd.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ata/wd.c,v
retrieving revision 1.213
diff -u -p -r1.213 wd.c
--- sys/dev/ata/wd.c	2001/05/06 18:30:57	1.213
+++ sys/dev/ata/wd.c	2001/06/11 22:58:29
@@ -573,6 +573,8 @@ wddone(v)
 	WDCDEBUG_PRINT(("wddone %s\n", wd->sc_dev.dv_xname),
 	    DEBUG_XFERS);

+	if (bp == NULL)
+		return;
 	bp->b_resid = wd->sc_wdc_bio.bcount;
 	errbuf[0] = '\0';
 	switch (wd->sc_wdc_bio.error) {
@@ -1219,6 +1221,7 @@ wddump(dev, blkno, va, size)

 	while (nblks > 0) {
 again:
+		wd->sc_bp = NULL;
 		wd->sc_wdc_bio.blkno = blkno;
 		wd->sc_wdc_bio.flags = ATA_POLL;
 		if (wddumpmulti == 1)
Index: sys/dev/ic/ncr5380sbc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/ncr5380sbc.c,v
retrieving revision 1.40
diff -u -p -r1.40 ncr5380sbc.c
--- sys/dev/ic/ncr5380sbc.c	2001/04/25 17:53:33	1.40
+++ sys/dev/ic/ncr5380sbc.c	2001/06/11 22:58:32
@@ -610,9 +610,6 @@ ncr5380_scsipi_request(chan, req, arg)
 		periph = xs->xs_periph;
 		flags = xs->xs_control;

-		if (sc->sc_flags & NCR5380_FORCE_POLLING)
-			flags |= XS_CTL_POLL;
-
 		if (flags & XS_CTL_DATA_UIO)
 			panic("ncr5380: scsi data uio requested");

@@ -2580,6 +2577,8 @@ ncr5380_attach(sc)
 	adapt->adapt_nchannels = 1;
 	adapt->adapt_openings = SCI_OPENINGS;
 	adapt->adapt_max_periph = 1;
+	if (sc->sc_flags & NCR5380_FORCE_POLLING)
+		adapt->adapt_flags |= SCSIPI_ADAPT_POLL_ONLY;
 	/* adapt_minphys filled in by front-end */

 	/*
Index: sys/dev/ic/wdc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/wdc.c,v
retrieving revision 1.97
diff -u -p -r1.97 wdc.c
--- sys/dev/ic/wdc.c	2001/06/11 21:18:36	1.97
+++ sys/dev/ic/wdc.c	2001/06/11 22:58:32
@@ -653,6 +653,8 @@ wdcstart(chp)
 		chp->ch_drive[xfer->drive].drive_flags &= ~DRIVE_RESET;
 		chp->ch_drive[xfer->drive].state = 0;
 	}
+	if (chp->wdc->cap & WDC_CAPABILITY_NOIRQ)
+		KASSERT(xfer->c_flags & C_POLL);
 	xfer->c_start(chp, xfer);
 }

@@ -1258,6 +1260,8 @@ wdc_exec_command(drvp, wdc_c)
 		return WDC_TRY_AGAIN;
 	 }

+	if (chp->wdc->cap & WDC_CAPABILITY_NOIRQ)
+		wdc_c->flags |= AT_POLL;
 	if (wdc_c->flags & AT_POLL)
 		xfer->c_flags |= C_POLL;
 	xfer->drive = drvp->drive;
Index: sys/dev/ic/wdcvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/wdcvar.h,v
retrieving revision 1.29
diff -u -p -r1.29 wdcvar.h
--- sys/dev/ic/wdcvar.h	2001/04/25 17:53:35	1.29
+++ sys/dev/ic/wdcvar.h	2001/06/11 22:58:33
@@ -101,6 +101,7 @@ struct wdc_softc { /* Per controller sta
 #define WDC_CAPABILITY_PREATA 0x0200 /* ctrl can be a pre-ata one */
 #define WDC_CAPABILITY_IRQACK 0x0400 /* callback to ack interrupt */
 #define WDC_CAPABILITY_SINGLE_DRIVE 0x0800 /* Don't probe second drive */
+#define WDC_CAPABILITY_NOIRQ  0x1000	/* Controller never interrupts */
 	u_int8_t      PIO_cap; /* highest PIO mode supported */
 	u_int8_t      DMA_cap; /* highest DMA mode supported */
 	u_int8_t      UDMA_cap; /* highest UDMA mode supported */
Index: sys/dev/scsipi/atapi_wdc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/scsipi/atapi_wdc.c,v
retrieving revision 1.41
diff -u -p -r1.41 atapi_wdc.c
--- sys/dev/scsipi/atapi_wdc.c	2001/05/15 13:53:20	1.41
+++ sys/dev/scsipi/atapi_wdc.c	2001/06/11 22:58:35
@@ -121,6 +121,8 @@ wdc_atapibus_attach(chp)
 	adapt->adapt_nchannels = wdc->nchannels;
 	adapt->adapt_request = wdc_atapi_scsipi_request;
 	adapt->adapt_minphys = wdc_atapi_minphys;
+	if (wdc->cap & WDC_CAPABILITY_NOIRQ)
+		adapt->adapt_flags |= SCSIPI_ADAPT_POLL_ONLY;
 	wdc->sc_atapi_adapter.atapi_probe_device = wdc_atapi_probe_device;

 	/*
Index: sys/dev/scsipi/scsipi_base.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/scsipi/scsipi_base.c,v
retrieving revision 1.44
diff -u -p -r1.44 scsipi_base.c
--- sys/dev/scsipi/scsipi_base.c	2001/05/23 15:50:32	1.44
+++ sys/dev/scsipi/scsipi_base.c	2001/06/11 22:58:35
@@ -1822,6 +1822,10 @@ scsipi_execute_xs(xs)
 		}
 	}

+	/* If the adaptor wants us to poll, poll. */
+	if (chan->chan_adapter->adapt_flags & SCSIPI_ADAPT_POLL_ONLY)
+		xs->xs_control |= XS_CTL_POLL;
+
 	/*
 	 * If we don't yet have a completion thread, or we are to poll for
 	 * completion, clear the ASYNC flag.
Index: sys/dev/scsipi/scsipiconf.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/scsipi/scsipiconf.h,v
retrieving revision 1.52
diff -u -p -r1.52 scsipiconf.h
--- sys/dev/scsipi/scsipiconf.h	2001/05/21 15:50:46	1.52
+++ sys/dev/scsipi/scsipiconf.h	2001/06/11 22:58:36
@@ -197,6 +197,7 @@ struct scsipi_adapter {
 	int	adapt_refcnt;		/* adapter's reference count */
 	int	adapt_openings;		/* total # of command openings */
 	int	adapt_max_periph;	/* max openings per periph */
+	int	adapt_flags;

 	void	(*adapt_request) __P((struct scsipi_channel *,
 		    scsipi_adapter_req_t, void *));
@@ -209,6 +210,9 @@ struct scsipi_adapter {
 	int	(*adapt_accesschk) __P((struct scsipi_periph *,
 			struct scsipi_inquiry_pattern *));
 };
+
+/* adapt_flags */
+#define SCSIPI_ADAPT_POLL_ONLY	0x01 /* Adaptor can't do interrupts. */

 #define	scsipi_adapter_minphys(chan, bp)				\
 	(*(chan)->chan_adapter->adapt_minphys)((bp))

-- 
Ben Harris                                                   <bjh21@netbsd.org>
Portmaster, NetBSD/arm26               <URL:http://www.netbsd.org/Ports/arm26/>