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/>