summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/tc/asc.c161
-rw-r--r--sys/dev/tc/asc_ioasic.c164
-rw-r--r--sys/dev/tc/asc_tc.c53
-rw-r--r--sys/dev/tc/ascvar.h15
4 files changed, 253 insertions, 140 deletions
diff --git a/sys/dev/tc/asc.c b/sys/dev/tc/asc.c
index 7246a421457..57f88ebc608 100644
--- a/sys/dev/tc/asc.c
+++ b/sys/dev/tc/asc.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: asc.c,v 1.13 1997/07/08 05:29:11 mhitch Exp $ */
-/* $NetBSD: asc.c,v 1.31 1996/10/13 01:38:35 christos Exp $ */
+/* $OpenBSD: asc.c,v 1.14 1998/05/18 00:25:06 millert Exp $ */
+/* $NetBSD: asc.c,v 1.46 1998/05/08 15:39:01 mhitch Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -140,9 +140,8 @@
#include <scsi/scsiconf.h>
#include <machine/cpu.h>
-#include <machine/machConst.h> /* XXX */
-#include <machine/locore.h> /* XXX */
#include <machine/autoconf.h>
+#include <machine/bus.h>
#include <pmax/dev/device.h>
#include <pmax/dev/scsi.h>
@@ -412,12 +411,6 @@ static void asc_reset __P((asc_softc_t asc, asc_regmap_t *regs));
static void asc_startcmd __P((asc_softc_t asc, int target));
static void asc_timeout __P((void *arg));
-extern struct cfdriver asc_cd;
-struct cfdriver asc_cd = {
- NULL, "asc", DV_DULL
-};
-
-
#ifdef USE_NEW_SCSI
/* Glue to the machine-independent scsi */
struct scsi_adapter asc_switch = {
@@ -446,17 +439,21 @@ struct pmax_driver ascdriver = {
void asc_minphys __P((struct buf *bp));
+extern struct cfdriver asc_cd;
+struct cfdriver asc_cd = {
+ NULL, "asc", DV_DULL
+};
/*
* bus-parent shared attach function
*/
void
-ascattach(asc, dmabufsize, bus_speed)
+ascattach(asc, bus_speed)
register asc_softc_t asc;
- int dmabufsize;
+ int bus_speed;
{
register asc_regmap_t *regs;
- int id, s, i;
+ int id, s;
int unit;
@@ -523,21 +520,6 @@ ascattach(asc, dmabufsize, bus_speed)
id = asc->sc_id;
splx(s);
- /*
- * Statically partition the DMA buffer between targets.
- * This way we will eventually be able to attach/detach
- * drives on-fly. And 18k/target is plenty for normal use.
- */
-
- /*
- * Give each target its own DMA buffer region.
- * We may want to try ping ponging buffers later.
- */
- for (i = 0; i < ASC_NCMD; i++) {
- asc->st[i].dmaBufAddr = asc->buff + dmabufsize * i;
- asc->st[i].dmaBufSize = dmabufsize;
- }
-
/* Hack for old-sytle SCSI-device probe */
(void) pmax_add_scsi(&ascdriver, unit);
@@ -731,12 +713,8 @@ asc_startcmd(asc, target)
state->script = (script_t *)0;
state->msg_out = SCSI_NO_OP;
- /*
- * Copy command data to the DMA buffer.
- */
len = scsicmd->cmdlen;
state->dmalen = len;
- bcopy(scsicmd->cmd, state->dmaBufAddr, len);
/* check for simple SCSI command with no data transfer */
if ((state->buflen = scsicmd->buflen) == 0) {
@@ -781,7 +759,8 @@ asc_startcmd(asc, target)
tc_mb();
/* initialize the DMA */
- (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
+ len = (*asc->dma_start)(asc, state, scsicmd->cmd, ASCDMA_WRITE,
+ len, 0);
ASC_TC_PUT(regs, len);
readback(regs->asc_cmd);
@@ -847,6 +826,7 @@ asc_intr(sc)
register script_t *scpt;
register int ss, ir, status;
register unsigned char cmd_was;
+ static int ill_cmd_count = 0; /* XXX */
/* collect ephemeral information */
status = regs->asc_status;
@@ -923,7 +903,8 @@ again:
state = &asc->st[asc->target];
switch (ASC_PHASE(status)) {
case SCSI_PHASE_DATAI:
- if ((asc->script - asc_scripts) == SCRIPT_GET_STATUS) {
+ if ((asc->script - asc_scripts) == SCRIPT_DATA_IN + 1 ||
+ (asc->script - asc_scripts) == SCRIPT_CONTINUE_IN) {
/*
* From the Mach driver:
* After a reconnect and restart dma in, we
@@ -1015,14 +996,16 @@ again:
/* flush any data in the FIFO */
if (fifo) {
if (state->flags & DMA_OUT) {
-#ifdef DIAGNOSTIC /* XXX - don't exacly know it this should be ifdefed */
- printf("asc: DMA_OUT, fifo resid %d, len %d, flags 0x%x\n",
- fifo, len, state->flags);
-#endif
+#ifdef ASC_DIAGNOSTIC
+ printf("asc: DMA_OUT, fifo resid %d, len %d, flags 0x%x\n",
+ fifo, len, state->flags);
+#endif /* ASC_DIAGNOSTIC */
len += fifo;
} else if (state->flags & DMA_IN) {
+#ifdef ASC_DIAGNOSTIC
printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
state->dmalen, len, fifo); /* XXX */
+#endif /* ASC_DIAGNOSTIC */
} else
printf("asc_intr: dmalen %d len %d fifo %d\n",
state->dmalen, len, fifo); /* XXX */
@@ -1060,31 +1043,33 @@ again:
}
state->script =
&asc_scripts[SCRIPT_RESUME_DMA_IN];
- } else if (state->flags & DMA_OUT)
+ state->flags |= DMA_RESUME;
+ } else if (state->flags & DMA_OUT) {
state->script =
&asc_scripts[SCRIPT_RESUME_DMA_OUT];
- else
+ state->flags |= DMA_RESUME;
+ } else
state->script = asc->script;
} else if (state->flags & DMA_IN) {
+#ifdef ASC_DIAGNOSTIC
if (len) {
-#ifdef DEBUG
- printf("asc_intr: 1: bn %d len %d (fifo %d)\n",
- asc_debug_bn, len, fifo); /* XXX */
-#endif
- goto abort;
+ printf("asc_intr: 1: len %d (fifo %d)\n",
+ len, fifo); /* XXX */
}
+#endif
/* setup state to resume to */
if (state->flags & DMA_IN_PROGRESS) {
len = state->dmalen;
state->flags &= ~DMA_IN_PROGRESS;
do_in:
+ state->dmalen = len; /* dma_end needs actual length */
(*asc->dma_end)(asc, state, ASCDMA_READ);
- bcopy(state->dmaBufAddr, state->buf, len);
state->buf += len;
state->buflen -= len;
}
if (state->buflen)
- state->script =
+ state->script = (state->flags & DMA_RESUME) ?
+ &asc_scripts[SCRIPT_RESUME_DMA_IN] :
&asc_scripts[SCRIPT_RESUME_IN];
else
state->script =
@@ -1108,7 +1093,8 @@ again:
state->buflen -= len;
}
if (state->buflen)
- state->script =
+ state->script = (state->flags & DMA_RESUME) ?
+ &asc_scripts[SCRIPT_RESUME_DMA_OUT] :
&asc_scripts[SCRIPT_RESUME_OUT];
else
state->script =
@@ -1212,6 +1198,30 @@ again:
/* Should process reselect? */
}
+ /* check for illegal command */
+ if (ir & ASC_INT_ILL) {
+#ifdef ASC_DIAGNOSTIC
+ printf("asc_intr: Illegal command status %x ir %x cmd %x ? %x\n",
+ status, ir, regs->asc_cmd, asc_scripts[SCRIPT_MSG_IN].command);
+#endif
+ /*
+ * On a 5000/200, I see this frequently when using an RD52
+ * CDROM. The 53c94 doesn't seem to get the Message Accept
+ * command, and generates an "Illegal Command" interrupt.
+ * Re-issuing the Message Accept at this point seems to keep
+ * things going. Don't allow this too many times in a row,
+ * just to make sure we don't get hung up. mhitch
+ */
+ if (ill_cmd_count++ != 3) { /* XXX */
+ regs->asc_cmd = ASC_CMD_MSG_ACPT; /* XXX */
+ readback(regs->asc_cmd); /* XXX */
+ goto done; /* XXX */
+ } /* XXX */
+ printf("asc_intr: Illegal command tgt %d\n", asc->target);
+ goto abort; /* XXX */
+ }
+ ill_cmd_count = 0; /* XXX */
+
/* check for reselect */
if (ir & ASC_INT_RESEL) {
unsigned fifo, id, msg;
@@ -1235,6 +1245,11 @@ again:
else
asc_logp[-1].msg = msg;
#endif
+ /*
+ * TC may have been initialized during a selection attempt.
+ * Clear it to prevent possible confusion later.
+ */
+ ASC_TC_PUT(regs,0); /* ensure TC clear */
asc->state = ASC_STATE_BUSY;
asc->target = id;
state = &asc->st[id];
@@ -1280,7 +1295,7 @@ abort:
#if 0
panic("asc_intr");
#else
- boot(4); /* XXX */
+ boot(RB_NOSYNC); /* XXX */
#endif
}
@@ -1449,10 +1464,10 @@ asc_dma_in(asc, status, ss, ir)
* There may be some bytes in the FIFO if synchonous transfers
* are in progress.
*/
- (*asc->dma_end)(asc, state, ASCDMA_READ);
ASC_TC_GET(regs, len);
len = state->dmalen - len;
- bcopy(state->dmaBufAddr, state->buf, len);
+ state->dmalen = len; /* dma_end may need actual length */
+ (*asc->dma_end)(asc, state, ASCDMA_READ);
state->buf += len;
state->buflen -= len;
}
@@ -1473,7 +1488,7 @@ asc_dma_in(asc, status, ss, ir)
*/
if (state->sync_offset == 0)
async_fifo_junk = regs->asc_fifo;
-#ifdef DEBUG
+#ifdef ASC_DIAGNOSTIC
printf("%s: asc_dma_in: FIFO count %x flags %x sync_offset %d",
asc->sc_dev.dv_xname, regs->asc_flags,
state->flags, state->sync_offset);
@@ -1481,10 +1496,10 @@ asc_dma_in(asc, status, ss, ir)
printf("\n");
else
printf(" unexpected fifo data %x\n", async_fifo_junk);
-#ifdef DIAGNOSTIC
+#ifdef DEBUG
asc_DumpLog("asc_dma_in");
-#endif /* DIAGNOSTIC */
#endif /* DEBUG */
+#endif /* ASC_DIAGNOSTIC */
}
/* setup to start reading the next chunk */
@@ -1495,10 +1510,8 @@ asc_dma_in(asc, status, ss, ir)
else
asc_logp[-1].resid = len;
#endif
- if (len > state->dmaBufSize)
- len = state->dmaBufSize;
+ len = (*asc->dma_start)(asc, state, state->buf, ASCDMA_READ, len, 0);
state->dmalen = len;
- (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
ASC_TC_PUT(regs, len);
#ifdef DEBUG
if (asc_debug > 2)
@@ -1526,8 +1539,6 @@ asc_last_dma_in(asc, status, ss, ir)
register State *state = &asc->st[asc->target];
register int len, fifo;
- /* copy data from buffer to main memory */
- (*asc->dma_end)(asc, state, ASCDMA_READ);
ASC_TC_GET(regs, len);
fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
#ifdef DEBUG
@@ -1542,8 +1553,9 @@ asc_last_dma_in(asc, status, ss, ir)
}
state->flags &= ~DMA_IN_PROGRESS;
len = state->dmalen - len;
+ state->dmalen = len; /* dma_end may need actual length */
+ (*asc->dma_end)(asc, state, ASCDMA_READ);
state->buflen -= len;
- bcopy(state->dmaBufAddr, state->buf, len);
return (1);
}
@@ -1566,10 +1578,8 @@ asc_resume_in(asc, status, ss, ir)
else
asc_logp[-1].resid = len;
#endif
- if (len > state->dmaBufSize)
- len = state->dmaBufSize;
+ len = (*asc->dma_start)(asc, state, state->buf, ASCDMA_READ, len, 0);
state->dmalen = len;
- (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
ASC_TC_PUT(regs, len);
#ifdef DEBUG
if (asc_debug > 2)
@@ -1604,7 +1614,7 @@ asc_resume_dma_in(asc, status, ss, ir)
if ((off & 1) && state->sync_offset) {
printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
state->dmalen, len, off); /* XXX */
- regs->asc_res_fifo = state->dmaBufAddr[off];
+ regs->asc_res_fifo = state->buf[off];
}
#ifdef DEBUG
if (asc_logp == asc_log)
@@ -1612,7 +1622,7 @@ asc_resume_dma_in(asc, status, ss, ir)
else
asc_logp[-1].resid = len;
#endif
- (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ);
+ len = (*asc->dma_start)(asc, state, state->buf + off, ASCDMA_READ, len, off);
ASC_TC_PUT(regs, len);
#ifdef DEBUG
if (asc_debug > 2)
@@ -1622,6 +1632,7 @@ asc_resume_dma_in(asc, status, ss, ir)
/* check for next chunk */
state->flags |= DMA_IN_PROGRESS;
+ state->flags &= ~DMA_RESUME;
if (state->dmalen != state->buflen) {
regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
readback(regs->asc_cmd);
@@ -1671,11 +1682,8 @@ asc_dma_out(asc, status, ss, ir)
else
asc_logp[-1].resid = len;
#endif
- if (len > state->dmaBufSize)
- len = state->dmaBufSize;
+ len = (*asc->dma_start)(asc, state, state->buf, ASCDMA_WRITE, len, 0);
state->dmalen = len;
- bcopy(state->buf, state->dmaBufAddr, len);
- (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
ASC_TC_PUT(regs, len);
#ifdef DEBUG
if (asc_debug > 2)
@@ -1741,11 +1749,8 @@ asc_resume_out(asc, status, ss, ir)
else
asc_logp[-1].resid = len;
#endif
- if (len > state->dmaBufSize)
- len = state->dmaBufSize;
+ len = (*asc->dma_start)(asc, state, state->buf, ASCDMA_WRITE, len, 0);
state->dmalen = len;
- bcopy(state->buf, state->dmaBufAddr, len);
- (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
ASC_TC_PUT(regs, len);
#ifdef DEBUG
if (asc_debug > 2)
@@ -1780,7 +1785,7 @@ asc_resume_dma_out(asc, status, ss, ir)
if (off & 1) {
printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
state->dmalen, len, off); /* XXX */
- regs->asc_fifo = state->dmaBufAddr[off];
+ regs->asc_fifo = state->buf[off];
off++;
len--;
}
@@ -1790,7 +1795,8 @@ asc_resume_dma_out(asc, status, ss, ir)
else
asc_logp[-1].resid = len;
#endif
- (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE);
+ /* XXX may result in redundant copy of data */
+ len = (*asc->dma_start)(asc, state, state->buf + off, ASCDMA_WRITE, len, off);
ASC_TC_PUT(regs, len);
#ifdef DEBUG
if (asc_debug > 2)
@@ -1800,6 +1806,7 @@ asc_resume_dma_out(asc, status, ss, ir)
/* check for next chunk */
state->flags |= DMA_IN_PROGRESS;
+ state->flags &= ~DMA_RESUME;
if (state->dmalen != state->buflen) {
regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
readback(regs->asc_cmd);
@@ -2101,7 +2108,6 @@ asc_disconnect(asc, status, ss, ir)
return (1);
}
-
void
asc_timeout(arg)
void *arg;
@@ -2116,8 +2122,9 @@ asc_timeout(arg)
#if 0
panic("asc_timeout");
#else
- boot(4); /* XXX */
+ boot(RB_NOSYNC); /* XXX */
#endif
+ splx(s);
}
diff --git a/sys/dev/tc/asc_ioasic.c b/sys/dev/tc/asc_ioasic.c
index 894d94aebcd..7ee81b0529d 100644
--- a/sys/dev/tc/asc_ioasic.c
+++ b/sys/dev/tc/asc_ioasic.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: asc_ioasic.c,v 1.3 1997/11/07 08:07:43 niklas Exp $ */
-/* $NetBSD: asc_ioasic.c,v 1.3 1996/10/13 01:38:36 christos Exp $ */
+/* $OpenBSD: asc_ioasic.c,v 1.4 1998/05/18 00:25:08 millert Exp $ */
+/* $NetBSD: asc_ioasic.c,v 1.12 1998/01/12 09:51:30 thorpej Exp $ */
/*
* Copyright 1996 The Board of Trustees of The Leland Stanford
@@ -14,6 +14,8 @@
* express or implied warranty.
*
*/
+#define USE_CACHED_BUFFER 0
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
@@ -21,13 +23,14 @@
#include <dev/tc/ioasicvar.h>
#include <machine/autoconf.h>
-#include <pmax/dev/device.h> /* XXX */
-#include <pmax/dev/scsi.h> /* XXX */
+#include <pmax/dev/device.h> /* XXX */
+#include <pmax/dev/scsi.h> /* XXX */
-#include <pmax/dev/ascreg.h> /* XXX */
+#include <pmax/dev/ascreg.h> /* XXX */
#include <dev/tc/ascvar.h>
-#include <machine/locore.h> /* XXX XXX bus.h needs cache-consistency*/
+#include <machine/cpu.h>
+#include <machine/bus.h> /* bus, cache consistency, etc */
/*XXX*/
#include <pmax/pmax/asic.h> /* XXX ioasic register defs? */
@@ -35,6 +38,7 @@
#include <pmax/pmax/pmaxtype.h>
extern int pmax_boardtype;
+extern vm_offset_t kvtophys __P((vm_offset_t));
/*
* Autoconfiguration data for config.
@@ -46,13 +50,20 @@ struct cfattach asc_ioasic_ca = {
sizeof(struct asc_softc), asc_ioasic_match, asc_ioasic_attach
};
+#ifdef notdef
+extern struct cfdriver asc_cd;
+#endif
+
/*
* DMA callback declarations
*/
+#ifdef ASC_IOASIC_BOUNCE
extern u_long asc_iomem;
-static void
-asic_dma_start __P((asc_softc_t asc, State *state, caddr_t cp, int flag));
+#endif
+static int
+asic_dma_start __P((asc_softc_t asc, State *state, caddr_t cp, int flag,
+ int len, int off));
static void
asic_dma_end __P((asc_softc_t asc, State *state, int flag));
@@ -86,12 +97,15 @@ asc_ioasic_attach(parent, self, aux)
{
register struct ioasicdev_attach_args *d = aux;
register asc_softc_t asc = (asc_softc_t) self;
- int bufsiz, speed;
+#ifdef ASC_IOASIC_BOUNCE
+ u_char *buff;
+ int i;
+#endif
void *ascaddr;
int unit;
- ascaddr = (void*)MACH_PHYS_TO_UNCACHED(d->iada_addr);
+ ascaddr = (void*)MIPS_PHYS_TO_KSEG1(d->iada_addr);
unit = asc->sc_dev.dv_unit;
/*
@@ -105,34 +119,35 @@ asc_ioasic_attach(parent, self, aux)
* (2) timing based on turbochannel frequency
*/
- asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem);
- bufsiz = 8192;
+#ifdef ASC_IOASIC_BOUNCE
+#if USE_CACHED_BUFFER
+ /* XXX Use cached address for DMA buffer to increase raw read speed */
+ buff = (u_char *)MIPS_PHYS_TO_KSEG0(asc_iomem);
+#else
+ buff = (u_char *)MIPS_PHYS_TO_KSEG1(asc_iomem);
+#endif /* USE_CACHED_BUFFER */
+ /*
+ * Statically partition the DMA buffer between targets.
+ * This way we will eventually be able to attach/detach
+ * drives on-fly. And 18k/target is plenty for normal use.
+ */
+
+ /*
+ * Give each target its own DMA buffer region.
+ * We may want to try ping ponging buffers later.
+ */
+ for (i = 0; i < ASC_NCMD; i++)
+ asc->st[i].dmaBufAddr = buff + 8192 * i;
+
+#endif /* ASC_IOASIC_BOUNCE */
*((volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base)) = -1;
*((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1;
*((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0;
asc->dma_start = asic_dma_start;
asc->dma_end = asic_dma_end;
- /*
- * Now for timing. The 3max has a 25Mhz tb whereas the 3min and
- * maxine are 12.5Mhz.
- */
-
- /*printf(" (bus speed: %d) ", t->ta_busspeed);*/
- /* XXX don't these run at 25MHz on any ioasic??*/
- switch (pmax_boardtype) {
- case DS_3MAX:
- case DS_3MAXPLUS:
- speed = ASC_SPEED_25_MHZ;
- break;
- case DS_3MIN:
- case DS_MAXINE:
- default:
- speed = ASC_SPEED_12_5_MHZ;
- break;
- };
-
- ascattach(asc, bufsiz, speed);
+ /* digital meters show IOASIC 53c94s are clocked at approx 25MHz */
+ ascattach(asc, ASC_SPEED_25_MHZ);
/* tie pseudo-slot to device */
@@ -145,12 +160,14 @@ asc_ioasic_attach(parent, self, aux)
* DMA handling routines. For a turbochannel device, just set the dmar.
* For the I/O ASIC, handle the actual DMA interface.
*/
-static void
-asic_dma_start(asc, state, cp, flag)
+static int
+asic_dma_start(asc, state, cp, flag, len, off)
asc_softc_t asc;
State *state;
caddr_t cp;
int flag;
+ int len;
+ int off;
{
register volatile u_int *ssr = (volatile u_int *)
IOASIC_REG_CSR(ioasic_base);
@@ -160,12 +177,61 @@ asic_dma_start(asc, state, cp, flag)
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
*((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0;
- phys = MACH_CACHED_TO_PHYS(cp);
+#ifndef ASC_IOASIC_BOUNCE
+ /* restrict len to the maximum the IOASIC can transfer */
+ if (len > ((caddr_t)mips_trunc_page(cp + NBPG * 2) - cp))
+ len = (caddr_t)mips_trunc_page(cp + NBPG * 2) - cp;
+
+ /* If R4K, writeback and invalidate the buffer */
+ if (CPUISMIPS3)
+ mips3_HitFlushDCache((vm_offset_t)cp, len);
+
+ /* Get physical address of buffer start, no next phys addr */
+ phys = (u_int)kvtophys((vm_offset_t)cp);
+ nphys = -1;
+
+ /* Compute 2nd DMA pointer only if next page is part of this I/O */
+ if ((NBPG - (phys & (NBPG - 1))) < len) {
+ cp = (caddr_t)mips_trunc_page(cp + NBPG);
+ nphys = (u_int)kvtophys((vm_offset_t)cp);
+ }
+
+ /* If not R4K, need to invalidate cache lines for both physical segments */
+ if (!CPUISMIPS3 && flag == ASCDMA_READ) {
+ MachFlushDCache(MIPS_PHYS_TO_KSEG0(phys),
+ nphys == 0xffffffff ? len : NBPG - (phys & (NBPG - 1)));
+ if (nphys != 0xffffffff)
+ MachFlushDCache(MIPS_PHYS_TO_KSEG0(nphys),
+ NBPG); /* XXX */
+ }
+#else /* ASC_IOASIC_BOUNCE */
+ /* restrict len to the maximum the IOASIC can transfer */
+ if (len > ((caddr_t)mips_trunc_page(state->dmaBufAddr + off + NBPG * 2) - (caddr_t)(state->dmaBufAddr + off)))
+ len = (caddr_t)mips_trunc_page(state->dmaBufAddr + off + NBPG * 2) - (caddr_t)(state->dmaBufAddr + off);
+
+ if (flag == ASCDMA_WRITE)
+ bcopy(cp, state->dmaBufAddr + off, len);
+ cp = state->dmaBufAddr + off;
+#if USE_CACHED_BUFFER
+#ifdef MIPS3
+ /* If R4K, need to writeback the bounce buffer */
+ if (CPUISMIPS3)
+ mips3_HitFlushDCache((vm_offset_t)cp, len);
+#endif /* MIPS3 */
+ phys = MIPS_KSEG0_TO_PHYS(cp);
+ cp = (caddr_t)mips_trunc_page(cp + NBPG);
+ nphys = MIPS_KSEG0_TO_PHYS(cp);
+#else
+ phys = MIPS_KSEG1_TO_PHYS(cp);
cp = (caddr_t)mips_trunc_page(cp + NBPG);
- nphys = MACH_CACHED_TO_PHYS(cp);
+ nphys = MIPS_KSEG1_TO_PHYS(cp);
+#endif /* USE_CACHED_BUFFER */
+#endif /* ASC_IOASIC_BOUNCE */
+#ifdef notyet
asc->dma_next = cp;
asc->dma_xfer = state->dmalen - (nphys - phys);
+#endif
*(volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base) =
IOASIC_DMA_ADDR(phys);
@@ -176,6 +242,7 @@ asic_dma_start(asc, state, cp, flag)
else
*ssr = (*ssr & ~IOASIC_CSR_SCSI_DIR) | IOASIC_CSR_DMAEN_SCSI;
wbflush();
+ return (len);
}
static void
@@ -193,14 +260,28 @@ asic_dma_end(asc, state, flag)
int nb;
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
- to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3);
+#if USE_CACHED_BUFFER /* XXX - Should uncached address always be used? */
+ to = (u_short *)MIPS_PHYS_TO_KSEG0(*dmap >> 3);
+#else
+ to = (u_short *)MIPS_PHYS_TO_KSEG1(*dmap >> 3);
+#endif
*dmap = -1;
*((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1;
wbflush();
if (flag == ASCDMA_READ) {
- MachFlushDCache(MACH_PHYS_TO_CACHED(
- MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
+#if !defined(ASC_IOASIC_BOUNCE) && USE_CACHED_BUFFER
+ /* Invalidate cache for the buffer */
+#ifdef MIPS3
+ if (CPUISMIPS3)
+ MachFlushDCache(MIPS_KSEG1_TO_PHYS(state->dmaBufAddr),
+ state->dmalen);
+ else
+#endif /* MIPS3 */
+ MachFlushDCache(MIPS_PHYS_TO_KSEG0(
+ MIPS_KSEG1_TO_PHYS(state->dmaBufAddr)),
+ state->dmalen);
+#endif /* USE_CACHED_BUFFER */
if ( (nb = *((int *)IOASIC_REG_SCSI_SCR(ioasic_base))) != 0) {
/* pick up last upto6 bytes, sigh. */
@@ -216,6 +297,9 @@ asic_dma_end(asc, state, flag)
*to++ = w;
}
}
+#ifdef ASC_IOASIC_BOUNCE
+ bcopy(state->dmaBufAddr, state->buf, state->dmalen);
+#endif
}
}
@@ -236,7 +320,7 @@ asc_dma_intr()
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
} else {
asc->dma_next += NBPG;
- next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
+ next_phys = MIPS_KSEG0_TO_PHYS(asc->dma_next);
}
*(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) =
IOASIC_DMA_ADDR(next_phys);
diff --git a/sys/dev/tc/asc_tc.c b/sys/dev/tc/asc_tc.c
index e17cdd6cbf8..abdf7ed6b6e 100644
--- a/sys/dev/tc/asc_tc.c
+++ b/sys/dev/tc/asc_tc.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: asc_tc.c,v 1.2 1997/11/07 08:07:44 niklas Exp $ */
-/* $NetBSD: asc_tc.c,v 1.4 1996/10/13 01:38:37 christos Exp $ */
+/* $OpenBSD: asc_tc.c,v 1.3 1998/05/18 00:25:09 millert Exp $ */
+/* $NetBSD: asc_tc.c,v 1.8 1997/10/31 06:29:59 jonathan Exp $ */
/*
* Copyright 1996 The Board of Trustees of The Leland Stanford
@@ -46,9 +46,9 @@ struct cfattach asc_tc_ca = {
* DMA callbacks
*/
-static void
+static int
tc_dma_start __P((struct asc_softc *asc, struct scsi_state *state,
- caddr_t cp, int flag));
+ caddr_t cp, int flag, int len, int off));
static void
tc_dma_end __P((struct asc_softc *asc, struct scsi_state *state,
@@ -85,12 +85,14 @@ asc_tc_attach(parent, self, aux)
{
register struct tc_attach_args *t = aux;
register asc_softc_t asc = (asc_softc_t) self;
- int bufsiz, speed;
+ u_char *buff;
+ int i, speed;
void *ascaddr;
int unit;
- ascaddr = (void*)MACH_PHYS_TO_UNCACHED(t->ta_addr);
+ /* Use uncached address for chip registers. */
+ ascaddr = (void*)MIPS_PHYS_TO_KSEG1(t->ta_addr);
unit = asc->sc_dev.dv_unit;
/*
@@ -108,8 +110,21 @@ asc_tc_attach(parent, self, aux)
* Fall through for turbochannel option.
*/
asc->dmar = (volatile int *)(ascaddr + ASC_OFFSET_DMAR);
- asc->buff = (u_char *)(ascaddr + ASC_OFFSET_RAM);
- bufsiz = PER_TGT_DMA_SIZE;
+ buff = (u_char *)(ascaddr + ASC_OFFSET_RAM);
+
+ /*
+ * Statically partition the DMA buffer between targets.
+ * This way we will eventually be able to attach/detach
+ * drives on-fly. And 18k/target is plenty for normal use.
+ */
+
+ /*
+ * Give each target its own DMA buffer region.
+ * We may want to try ping ponging buffers later.
+ */
+ for (i = 0; i < ASC_NCMD; i++)
+ asc->st[i].dmaBufAddr = buff + PER_TGT_DMA_SIZE * i;
+
asc->dma_start = tc_dma_start;
asc->dma_end = tc_dma_end;
@@ -117,7 +132,7 @@ asc_tc_attach(parent, self, aux)
* Now for timing. The 3max has a 25Mhz tb whereas the 3min and
* maxine are 12.5Mhz.
*/
- printf(" (bus speed: %d) ", t->ta_busspeed);
+ printf(" (bus speed: %s MHz) ", t->ta_busspeed? "25" : "12.5");
switch (t->ta_busspeed) {
case TC_SPEED_25_MHZ:
@@ -132,7 +147,7 @@ asc_tc_attach(parent, self, aux)
break;
};
- ascattach(asc, bufsiz, speed);
+ ascattach(asc, speed);
/* tie pseudo-slot to device */
tc_intr_establish(parent, t->ta_cookie, TC_IPL_BIO,
@@ -144,18 +159,25 @@ asc_tc_attach(parent, self, aux)
* DMA handling routines. For a turbochannel device, just set the dmar.
* For the I/O ASIC, handle the actual DMA interface.
*/
-static void
-tc_dma_start(asc, state, cp, flag)
+static int
+tc_dma_start(asc, state, cp, flag, len, off)
asc_softc_t asc;
State *state;
caddr_t cp;
int flag;
+ int len;
+ int off;
{
+ if (len > PER_TGT_DMA_SIZE)
+ len = PER_TGT_DMA_SIZE;
if (flag == ASCDMA_WRITE)
- *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
+ bcopy(cp, state->dmaBufAddr + off, len);
+ if (flag == ASCDMA_WRITE)
+ *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off);
else
- *asc->dmar = ASC_DMA_ADDR(cp);
+ *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off);
+ return (len);
}
static void
@@ -164,5 +186,6 @@ tc_dma_end(asc, state, flag)
State *state;
int flag;
{
-
+ if (flag == ASCDMA_READ)
+ bcopy(state->dmaBufAddr, state->buf, state->dmalen);
}
diff --git a/sys/dev/tc/ascvar.h b/sys/dev/tc/ascvar.h
index db640b4ca50..0eeb964c1de 100644
--- a/sys/dev/tc/ascvar.h
+++ b/sys/dev/tc/ascvar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: ascvar.h,v 1.2 1997/11/07 08:07:45 niklas Exp $ */
-/* $NetBSD: ascvar.h,v 1.1 1996/09/25 21:07:56 jonathan Exp $ */
+/* $OpenBSD: ascvar.h,v 1.3 1998/05/18 00:25:10 millert Exp $ */
+/* $NetBSD: ascvar.h,v 1.4 1997/11/28 18:23:40 mhitch Exp $ */
/*
@@ -12,7 +12,6 @@ typedef struct scsi_state {
int statusByte; /* status byte returned during STATUS_PHASE */
int error; /* errno to pass back to device driver */
u_char *dmaBufAddr; /* DMA buffer address */
- u_int dmaBufSize; /* DMA buffer size */
int dmalen; /* amount to transfer in this chunk */
int dmaresid; /* amount not transfered if chunk suspended */
int buflen; /* total remaining amount of data to transfer */
@@ -30,6 +29,7 @@ typedef struct scsi_state {
#define DISCONN 0x001 /* true if currently disconnected from bus */
#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */
#define DMA_IN 0x004 /* true if reading from SCSI device */
+#define DMA_RESUME 0x08 /* true if DMA was interrupted by disc. */
#define DMA_OUT 0x010 /* true if writing to SCSI device */
#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */
#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */
@@ -45,7 +45,6 @@ struct asc_softc {
struct device sc_dev; /* us as a device */
asc_regmap_t *regs; /* chip address */
volatile int *dmar; /* DMA address register address */
- u_char *buff; /* RAM buffer address (uncached) */
int sc_id; /* SCSI ID of this interface */
int myidmask; /* ~(1 << myid) */
int state; /* current SCSI connection state */
@@ -54,9 +53,9 @@ struct asc_softc {
ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */
State st[ASC_NCMD]; /* state info for each active command */
/* Start dma routine */
- void (*dma_start) __P((struct asc_softc *asc,
+ int (*dma_start) __P((struct asc_softc *asc,
struct scsi_state *state,
- caddr_t cp, int flag));
+ caddr_t cp, int flag, int len, int off));
/* End dma routine */
void (*dma_end) __P((struct asc_softc *asc,
struct scsi_state *state, int flag));
@@ -69,7 +68,7 @@ struct asc_softc {
int timeout_250; /* 250ms timeout */
int tb_ticks; /* 4ns. ticks/tb channel ticks */
#ifdef USE_NEW_SCSI
- struct scsi_link sc_link; /* scsi link struct */
+ struct scsi_link sc_link; /* scsipi link struct */
#endif
};
typedef struct asc_softc *asc_softc_t;
@@ -83,7 +82,7 @@ typedef struct asc_softc *asc_softc_t;
#define ASC_SPEED_25_MHZ 250
#define ASC_SPEED_12_5_MHZ 125
-void ascattach __P((struct asc_softc *asc, int dmabufsiz, int bus_speed));
+void ascattach __P((struct asc_softc *asc, int bus_speed));
int asc_intr __P ((void *asc));
/*