summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/conf/files.i3864
-rw-r--r--sys/i386/isa/wd.c125
-rw-r--r--sys/i386/isa/wdreg.h104
3 files changed, 219 insertions, 14 deletions
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
index fe46c28..8a79192 100644
--- a/sys/i386/conf/files.i386
+++ b/sys/i386/conf/files.i386
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.i386,v 1.167 1997/07/24 23:45:17 fsmp Exp $
+# $Id: files.i386,v 1.168 1997/07/25 11:53:20 phk Exp $
#
aic7xxx_asm optional ahc device-driver \
dependency "$S/dev/aic7xxx/*.[chyl]" \
@@ -293,4 +293,4 @@ gnu/i386/fpemul/reg_u_sub.s optional gpl_math_emulate
gnu/i386/fpemul/wm_shrx.s optional gpl_math_emulate
gnu/i386/fpemul/wm_sqrt.s optional gpl_math_emulate
gnu/i386/isa/dgb.c optional dgb device-driver
-pci/wd82371.c optional wd device-driver
+pci/ide_pci.c optional wd device-driver
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
index 09beae0..09231ad 100644
--- a/sys/i386/isa/wd.c
+++ b/sys/i386/isa/wd.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
- * $Id: wd.c,v 1.131 1997/07/01 00:22:45 bde Exp $
+ * $Id: wd.c,v 1.132 1997/07/20 14:10:17 bde Exp $
*/
/* TODO:
@@ -110,6 +110,7 @@ extern void wdstart(int ctrlr);
/* can't handle that in all cases */
#define WDOPT_32BIT 0x8000
#define WDOPT_SLEEPHACK 0x4000
+#define WDOPT_DMA 0x2000
#define WDOPT_FORCEHD(x) (((x)&0x0f00)>>8)
#define WDOPT_MULTIMASK 0x00ff
@@ -173,12 +174,17 @@ struct disk {
#define DKFL_32BIT 0x00100 /* use 32-bit i/o mode */
#define DKFL_MULTI 0x00200 /* use multi-i/o mode */
#define DKFL_BADSCAN 0x00400 /* report all errors */
+#define DKFL_USEDMA 0x00800 /* use DMA for data transfers */
+#define DKFL_DMA 0x01000 /* using DMA on this transfer-- DKFL_SINGLE
+ * overrides this
+ */
struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
int dk_dkunit; /* disk stats unit number */
int dk_multi; /* multi transfers */
int dk_currentiosize; /* current io size */
struct diskgeom dk_dd; /* device configuration data */
struct diskslices *dk_slices; /* virtual drives */
+ void *dk_dmacookie; /* handle for DMA services */
};
#define WD_COUNT_RETRIES
@@ -215,6 +221,7 @@ static int wdsetctlr(struct disk *du);
#if 0
static int wdwsetctlr(struct disk *du);
#endif
+static int wdsetmode(int mode, void *wdinfo);
static int wdgetctlr(struct disk *du);
static void wderror(struct buf *bp, struct disk *du, char *mesg);
static void wdflushirq(struct disk *du, int old_ipl);
@@ -381,6 +388,7 @@ wdattach(struct isa_device *dvp)
int unit, lunit;
struct isa_device *wdup;
struct disk *du;
+ struct wdparams *wp;
if (dvp->id_unit >= NWDC)
return (0);
@@ -443,6 +451,8 @@ wdattach(struct isa_device *dvp)
dvp->id_unit, unit, lunit,
sizeof du->dk_params.wdp_model,
du->dk_params.wdp_model);
+ if (du->dk_flags & DKFL_USEDMA)
+ printf(", DMA");
if (du->dk_flags & DKFL_32BIT)
printf(", 32-bit");
if (du->dk_multi > 1)
@@ -465,6 +475,17 @@ wdattach(struct isa_device *dvp)
du->dk_dd.d_nsectors,
du->dk_dd.d_secsize);
+ if (bootverbose) {
+ wp = &du->dk_params;
+ printf(
+"wd%d: ATA INQUIRE valid = %04x, dmamword = %04x, apio = %04x, udma = %04x\n",
+ du->dk_lunit,
+ wp->wdp_atavalid,
+ wp->wdp_dmamword,
+ wp->wdp_eidepiomodes,
+ wp->wdp_udmamode);
+ }
+
/*
* Start timeout routine for this drive.
* XXX timeout should be per controller.
@@ -818,7 +839,19 @@ wdstart(int ctrlr)
count = 1;
du->dk_currentiosize = 1;
} else {
- if( (count > 1) && (du->dk_multi > 1)) {
+ if((du->dk_flags & DKFL_USEDMA) &&
+ wddma.wdd_dmaverify(du->dk_dmacookie,
+ (void *)((int)bp->b_un.b_addr +
+ du->dk_skip * DEV_BSIZE),
+ du->dk_bc,
+ bp->b_flags & B_READ)) {
+ du->dk_flags |= DKFL_DMA;
+ if( bp->b_flags & B_READ)
+ command = WDCC_READ_DMA;
+ else
+ command = WDCC_WRITE_DMA;
+ du->dk_currentiosize = count;
+ } else if( (count > 1) && (du->dk_multi > 1)) {
du->dk_flags |= DKFL_MULTI;
if( bp->b_flags & B_READ) {
command = WDCC_READ_MULTI;
@@ -854,6 +887,14 @@ wdstart(int ctrlr)
if(du->dk_dkunit >= 0) {
dk_busy |= 1 << du->dk_dkunit;
}
+
+ if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
+ wddma.wdd_dmaprep(du->dk_dmacookie,
+ (void *)((int)bp->b_un.b_addr +
+ du->dk_skip * DEV_BSIZE),
+ du->dk_bc,
+ bp->b_flags & B_READ);
+ }
while (wdcommand(du, cylin, head, sector, count, command)
!= 0) {
wderror(bp, du,
@@ -884,6 +925,12 @@ wdstart(int ctrlr)
*/
du->dk_timeout = 1 + 3;
+ /* if this is a DMA op, start DMA and go away until it's done. */
+ if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
+ wddma.wdd_dmastart(du->dk_dmacookie);
+ return;
+ }
+
/* If this is a read operation, just go away until it's done. */
if (bp->b_flags & B_READ)
return;
@@ -988,6 +1035,15 @@ wdintr(int unit)
du = wddrives[dkunit(bp->b_dev)];
du->dk_timeout = 0;
+ /* finish off DMA. ignore errors if we're not using it. */
+ if (du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) {
+ if ((wddma.wdd_dmadone(du->dk_dmacookie) != WDDS_INTERRUPT) &&
+ !(du->dk_flags & DKFL_USEDMA)) {
+ wderror(bp, du, "wdintr: DMA failure");
+ du->dk_status |= WDCS_ERR; /* XXX totally bogus err */
+ }
+ }
+
if (wdwait(du, 0, TIMEOUT) < 0) {
wderror(bp, du, "wdintr: timeout waiting for status");
du->dk_status |= WDCS_ERR; /* XXX */
@@ -1014,7 +1070,12 @@ oops:
* XXX bogus inb() here, register 0 is assumed and intr status
* is reset.
*/
- if( (du->dk_flags & DKFL_MULTI) && (inb(du->dk_port) & WDERR_ABORT)) {
+ if((du->dk_flags & DKFL_DMA ) &&
+ (inb(du->dk_port) & WDERR_ABORT)) {
+ wderror(bp, du, "reverting to PIO mode");
+ du->dk_flags |= ~DKFL_USEDMA;
+ } else if((du->dk_flags & DKFL_MULTI) &&
+ (inb(du->dk_port) & WDERR_ABORT)) {
wderror(bp, du, "reverting to non-multi sector mode");
du->dk_multi = 1;
}
@@ -1052,6 +1113,7 @@ oops:
* If this was a successful read operation, fetch the data.
*/
if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ)
+ && !(du->dk_flags & DKFL_DMA)
&& wdtab[unit].b_active) {
int chk, dummy, multisize;
multisize = chk = du->dk_currentiosize * DEV_BSIZE;
@@ -1093,6 +1155,20 @@ oops:
dk_wds[du->dk_dkunit] += chk >> 6;
}
+ /* final cleanup on DMA */
+ if (((bp->b_flags & B_ERROR) == 0)
+ && (du->dk_flags & DKFL_DMA)
+ && wdtab[unit].b_active) {
+ int iosize;
+
+ iosize = du->dk_currentiosize * DEV_BSIZE;
+
+ du->dk_bc -= iosize;
+
+ if (du->dk_dkunit >= 0)
+ dk_wds[du->dk_dkunit] += iosize >> 6;
+ }
+
outt:
if (wdtab[unit].b_active) {
if ((bp->b_flags & B_ERROR) == 0) {
@@ -1124,7 +1200,7 @@ outt:
done: ;
/* done with this transfer, with or without error */
- du->dk_flags &= ~DKFL_SINGLE;
+ du->dk_flags &= ~(DKFL_SINGLE|DKFL_DMA);
TAILQ_REMOVE(&wdtab[unit].controller_queue, bp, b_act);
wdtab[unit].b_errcnt = 0;
bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE;
@@ -1441,7 +1517,7 @@ wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
outb(wdc + wd_sector, sector + 1);
outb(wdc + wd_seccnt, count);
}
- if (wdwait(du, command == WDCC_DIAGNOSE || command == WDCC_IDC
+ if (wdwait(du, (command == WDCC_DIAGNOSE || command == WDCC_IDC)
? 0 : WDCS_READY, TIMEOUT) < 0)
return (1);
outb(wdc + wd_command, command);
@@ -1557,6 +1633,25 @@ wdwsetctlr(struct disk *du)
#endif
/*
+ * gross little callback function for wdddma interface. returns 1 for
+ * success, 0 for failure.
+ */
+static int
+wdsetmode(int mode, void *wdinfo)
+{
+ int i;
+ struct disk *du;
+
+ du = wdinfo;
+ if (bootverbose)
+ printf("wdsetmode() setting transfer mode to %02x\n", mode);
+ i = wdcommand(du, 0, 0, mode, WDFEA_SETXFER,
+ WDCC_FEATURES) == 0 &&
+ wdwait(du, WDCS_READY, TIMEOUT) == 0;
+ return i;
+}
+
+/*
* issue READP to drive to ask it what it is.
*/
static int
@@ -1711,6 +1806,21 @@ failed:
du->dk_multi = wp->wdp_nsecperint & 0xff;
wdsetmulti(du);
+ du->dk_dmacookie = NULL;
+ /*
+ * check drive's DMA capability
+ */
+ /* does user want this? */
+ if ((du->cfg_flags & WDOPT_DMA) &&
+ /* have we got a DMA controller? */
+ (wddma.wdd_candma &&
+ (du->dk_dmacookie = wddma.wdd_candma(du->dk_port,
+ du->dk_unit))) &&
+ /* can said drive do DMA? */
+ (wddma.wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)))
+
+ du->dk_flags |= DKFL_USEDMA;
+
#ifdef WDDEBUG
printf(
"\nwd(%d,%d): wdgetctlr: gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
@@ -2061,6 +2171,9 @@ wdreset(struct disk *du)
{
int wdc, err = 0;
+ if ((du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) && du->dk_dmacookie)
+ wddma.wdd_dmadone(du->dk_dmacookie);
+
wdc = du->dk_port;
(void)wdwait(du, 0, TIMEOUT);
outb(wdc + wd_ctlr, WDCTL_IDS | WDCTL_RST);
@@ -2112,7 +2225,7 @@ wdtimeout(void *cdu)
if(timeouts++ == 5)
wderror((struct buf *)NULL, du,
"Last time I say: interrupt timeout. Probably a portable PC.");
- else if(timeouts++ < 5)
+ else if(timeouts < 5)
wderror((struct buf *)NULL, du, "interrupt timeout");
wdunwedge(du);
wdflushirq(du, x);
diff --git a/sys/i386/isa/wdreg.h b/sys/i386/isa/wdreg.h
index 3ad2403..f7dfa488 100644
--- a/sys/i386/isa/wdreg.h
+++ b/sys/i386/isa/wdreg.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91
- * $Id$
+ * $Id: wdreg.h,v 1.17 1997/02/22 09:37:27 peter Exp $
*/
/*
@@ -122,6 +122,8 @@
#define WDCC_READ_MULTI 0xC4 /* read multiple */
#define WDCC_WRITE_MULTI 0xC5 /* write multiple */
#define WDCC_SET_MULTI 0xC6 /* set multiple count */
+#define WDCC_READ_DMA 0xC8 /* read using DMA */
+#define WDCC_WRITE_DMA 0xCA /* write using DMA */
#define WDCC_EXTDCMD 0xE0 /* send extended command */
@@ -130,6 +132,7 @@
#define WDFEA_RCACHE 0xAA /* read cache enable */
#define WDFEA_WCACHE 0x02 /* write cache enable */
+#define WDFEA_SETXFER 0x03 /* set transfer mode */
#define WD_STEP 0 /* winchester- default 35us step */
@@ -140,10 +143,14 @@
* read parameters command returns this:
*/
struct wdparams {
+ /*
+ * XXX partly based on DRAFT X3T13/1153D rev 14.
+ * by the time you read this it will have changed.
+ */
/* drive info */
short wdp_config; /* general configuration bits */
u_short wdp_cylinders; /* number of cylinders */
- short wdp_reserved;
+ short wdp_reserved2;
u_short wdp_heads; /* number of heads */
short wdp_unfbytespertrk; /* number of unformatted bytes/track */
short wdp_unfbytes; /* number of unformatted bytes/sector */
@@ -159,8 +166,58 @@ struct wdparams {
short wdp_necc; /* ecc bytes appended */
char wdp_rev[8]; /* firmware revision */
char wdp_model[40]; /* model name */
- short wdp_nsecperint; /* sectors per interrupt */
+ char wdp_nsecperint; /* sectors per interrupt */
+ char wdp_vendorunique1;
short wdp_usedmovsd; /* can use double word read/write? */
+ char wdp_vendorunique2;
+ char wdp_capability; /* various capability bits */
+ short wdp_cap_validate; /* validation for above */
+ char wdp_vendorunique3;
+ char wdp_opiomode; /* PIO modes 0-2 */
+ char wdp_vendorunique4;
+ char wdp_odmamode; /* old DMA modes, not in ATA-3 */
+ short wdp_atavalid; /* validation for newer fields */
+ short wdp_currcyls;
+ short wdp_currheads;
+ short wdp_currsectors;
+ short wdp_currsize0;
+ short wdp_currsize1;
+ char wdp_currmultsect;
+ char wdp_multsectvalid;
+ int wdp_lbasize;
+ short wdp_dmasword; /* obsolete in ATA-3 */
+ short wdp_dmamword; /* multiword DMA modes */
+ short wdp_eidepiomodes; /* advanced PIO modes */
+ short wdp_eidedmamin; /* fastest possible DMA timing */
+ short wdp_eidedmanorm; /* recommended DMA timing */
+ short wdp_eidepioblind; /* fastest possible blind PIO */
+ short wdp_eidepioacked; /* fastest possible IORDY PIO */
+ short wdp_reserved69;
+ short wdp_reserved70;
+ short wdp_reserved71;
+ short wdp_reserved72;
+ short wdp_reserved73;
+ short wdp_reserved74;
+ short wdp_queuelen;
+ short wdp_reserved76;
+ short wdp_reserved77;
+ short wdp_reserved78;
+ short wdp_reserved79;
+ short wdp_versmaj;
+ short wdp_versmin;
+ short wdp_featsupp1;
+ short wdp_featsupp2;
+ short wdp_featsupp3;
+ short wdp_featenab1;
+ short wdp_featenab2;
+ short wdp_featenab3;
+ short wdp_udmamode; /* UltraDMA modes */
+ short wdp_erasetime;
+ short wdp_enherasetime;
+ short wdp_apmlevel;
+ short wdp_reserved92[34];
+ short wdp_rmvcap;
+ short wdp_securelevel;
};
/*
@@ -179,12 +236,18 @@ int wdformat(struct buf *bp);
* To use this:
* For each drive which you might want to do DMA on, call wdd_candma()
* to get a cookie. If it returns a null pointer, then the drive
- * can't do DMA.
+ * can't do DMA. Then call wdd_dmainit() to initialize the controller
+ * and drive. wdd_dmainit should leave PIO modes operational, though
+ * perhaps with suboptimal performance.
*
- * Set up the transfer be calling wdd_dmaprep(). The cookie is what
+ * Check the transfer by calling wdd_dmaverify(). The cookie is what
* you got before; vaddr is the virtual address of the buffer to be
* written; len is the length of the buffer; and direction is either
- * B_READ or B_WRITE.
+ * B_READ or B_WRITE. This function verifies that the DMA hardware is
+ * capable of handling the request you've made.
+ *
+ * Setup the transfer by calling wdd_dmaprep(). This takes the same
+ * paramaters as wdd_dmaverify().
*
* Send a read/write DMA command to the drive.
*
@@ -199,6 +262,8 @@ int wdformat(struct buf *bp);
struct wddma {
void *(*wdd_candma) /* returns a cookie if can do DMA */
__P((int ctlr, int drive));
+ int (*wdd_dmaverify) /* verify that request is DMA-able */
+ __P((void *cookie, char *vaddr, u_long len, int direction));
int (*wdd_dmaprep) /* prepare DMA hardware */
__P((void *cookie, char *vaddr, u_long len, int direction));
void (*wdd_dmastart) /* begin DMA transfer */
@@ -207,12 +272,39 @@ struct wddma {
__P((void *cookie));
int (*wdd_dmastatus) /* return status of DMA */
__P((void *cookie));
+ int (*wdd_dmainit) /* initialize controller and drive */
+ __P((void *cookie,
+ struct wdparams *wp,
+ int(wdcmd)__P((int mode, void *wdinfo)),
+ void *wdinfo));
};
+/* logical status bits returned by wdd_dmastatus */
#define WDDS_ACTIVE 0x0001
#define WDDS_ERROR 0x0002
#define WDDS_INTERRUPT 0x0004
+#if 0
+/* XXX are these now useless? */
+/* local defines for ATA timing modes */
+#define WDDMA_GRPMASK 0xf0
+/* flow-controlled PIO modes */
+#define WDDMA_PIO 0x10
+#define WDDMA_PIO3 0x10
+#define WDDMA_PIO4 0x11
+/* multi-word DMA timing modes */
+#define WDDMA_MDMA 0x20
+#define WDDMA_MDMA0 0x20
+#define WDDMA_MDMA1 0x21
+#define WDDMA_MDMA2 0x22
+
+/* Ultra DMA timing modes */
+#define WDDMA_UDMA 0x30
+#define WDDMA_UDMA0 0x30
+#define WDDMA_UDMA1 0x31
+#define WDDMA_UDMA2 0x32
+#endif
+
extern struct wddma wddma;
#endif /* KERNEL */
OpenPOWER on IntegriCloud