Subject: Support for polled IDE controllers
To: None <tech-kern@netbsd.org>
From: Ben Harris <bjh21@netbsd.org>
List: tech-kern
Date: 06/09/2001 13:38:06
Since breaking the IDE drivers is likely to make me very unpopular, could
someone who understands them better than I sanity-check the following?
I've got a couple of IDE controllers that don't have their interrupt lines
wired up, and I'd like the NetBSD wdc driver to handle them. I've
arranged this by adding a new capability, WDC_CAPABILITY_NOIRQ, and having
the three functions that can queue transfers (wdc_ata_bio(),
wdc_exec_command() and wdc_atapi_scsipi_request()) check that and mark all
transfers as polled if it's set.
In order to make this work, I found that I also had to disable the checks
for ATA_POLL in wdc_ata_bio_done() and wdc_ata_bio_kill_xfer() and have
them unconditionally call wddone(). On the assumption that those tests
were there to avoid calling wddone() when dumping, I added a check on
sc_bp in wddone(), and made wddump() clear it, so that wddone() is a no-op
if the transfer was caused by wddump().
Here's the patch:
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/09 12:36:22
@@ -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/09 12:36:22
@@ -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/wdc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/wdc.c,v
retrieving revision 1.96
diff -u -p -r1.96 wdc.c
--- sys/dev/ic/wdc.c 2001/04/25 17:53:35 1.96
+++ sys/dev/ic/wdc.c 2001/06/09 12:36:24
@@ -651,6 +651,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);
}
@@ -1256,6 +1258,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/09 12:36:25
@@ -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/09 12:36:26
@@ -348,6 +348,8 @@ wdc_atapi_scsipi_request(chan, req, arg)
return;
}
+ if (wdc->cap & WDC_CAPABILITY_NOIRQ)
+ sc_xfer->xs_control |= XS_CTL_POLL;
if (sc_xfer->xs_control & XS_CTL_POLL)
xfer->c_flags |= C_POLL;
xfer->drive = drive;
--
Ben Harris <bjh21@netbsd.org>
Portmaster, NetBSD/arm26 <URL:http://www.netbsd.org/Ports/arm26/>