Use direct DMA with the IOASIC ASC SCSI interface. DMA buffering can be

re-enabled with ASC_IOASIC_BOUNCE.
All DMA buffered processing is now done in the bus-specific DMA routines
in asc_ioasic.c and asc_tc.c.
Disable several informational messages dealing with non-empty FIFO conditions,
but allow enabling with ASC_DIAGNOSTIC for troubleshooting.
This commit is contained in:
mhitch 1997-07-28 19:39:22 +00:00
parent 1f7596052f
commit 0ae3de1a27
4 changed files with 162 additions and 84 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: asc.c,v 1.39 1997/06/16 03:46:29 jonathan Exp $ */
/* $NetBSD: asc.c,v 1.40 1997/07/28 19:39:22 mhitch Exp $ */
/*-
* Copyright (c) 1992, 1993
@ -449,12 +449,12 @@ void asc_minphys __P((struct buf *bp));
* 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;
@ -521,21 +521,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);
@ -730,12 +715,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) {
@ -780,7 +761,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);
@ -1014,14 +996,16 @@ again:
/* flush any data in the FIFO */
if (fifo) {
if (state->flags & DMA_OUT) {
#if 0
#ifdef ASC_DIAGNOSTIC
printf("asc: DMA_OUT, fifo resid %d, len %d, flags 0x%x\n",
fifo, len, state->flags);
#endif
#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 */
@ -1077,8 +1061,8 @@ again:
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;
}
@ -1448,10 +1432,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;
}
@ -1472,7 +1456,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);
@ -1480,10 +1464,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 */
@ -1494,10 +1478,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)
@ -1525,8 +1507,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
@ -1541,8 +1521,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);
}
@ -1565,10 +1546,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)
@ -1603,7 +1582,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)
@ -1611,7 +1590,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)
@ -1670,11 +1649,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)
@ -1740,11 +1716,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)
@ -1779,7 +1752,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--;
}
@ -1789,7 +1762,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)
@ -2100,7 +2074,6 @@ asc_disconnect(asc, status, ss, ir)
return (1);
}
void
asc_timeout(arg)
void *arg;

View File

@ -1,4 +1,4 @@
/* $NetBSD: asc_ioasic.c,v 1.10 1997/07/21 05:39:02 jonathan Exp $ */
/* $NetBSD: asc_ioasic.c,v 1.11 1997/07/28 19:39:25 mhitch Exp $ */
/*
* Copyright 1996 The Board of Trustees of The Leland Stanford
@ -13,6 +13,8 @@
* express or implied warranty.
*
*/
#define USE_CACHED_BUFFER 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
@ -35,6 +37,7 @@
#include <pmax/pmax/pmaxtype.h>
extern int pmax_boardtype;
extern vm_offset_t kvtophys __P((vm_offset_t));
/*
* Autoconfiguration data for config.
@ -50,9 +53,12 @@ struct cfattach asc_ioasic_ca = {
* 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,7 +92,10 @@ asc_ioasic_attach(parent, self, aux)
{
register struct ioasicdev_attach_args *d = aux;
register asc_softc_t asc = (asc_softc_t) self;
int bufsiz;
#ifdef ASC_IOASIC_BOUNCE
u_char *buff;
int i;
#endif
void *ascaddr;
int unit;
@ -105,9 +114,27 @@ asc_ioasic_attach(parent, self, aux)
* (2) timing based on turbochannel frequency
*/
/* XXX why cached? Device registers must be uncached. */
asc->buff = (u_char *)MIPS_PHYS_TO_KSEG0(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;
@ -115,7 +142,7 @@ asc_ioasic_attach(parent, self, aux)
asc->dma_end = asic_dma_end;
/* digital meters show IOASIC 53c94s are clocked at approx 25MHz */
ascattach(asc, bufsiz, ASC_SPEED_25_MHZ);
ascattach(asc, ASC_SPEED_25_MHZ);
/* tie pseudo-slot to device */
@ -128,12 +155,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);
@ -143,16 +172,61 @@ asic_dma_start(asc, state, cp, flag)
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
*((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0;
#ifdef MIPS3
#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, state->dmalen);
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 = 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);
@ -163,6 +237,7 @@ asic_dma_start(asc, state, cp, flag)
else
*ssr = (*ssr & ~IOASIC_CSR_SCSI_DIR) | IOASIC_CSR_DMAEN_SCSI;
wbflush();
return (len);
}
static void
@ -180,12 +255,18 @@ asic_dma_end(asc, state, flag)
int nb;
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
#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) {
#if !defined(ASC_IOASIC_BOUNCE) && USE_CACHED_BUFFER
/* Invalidate cache for the buffer */
#ifdef MIPS3
if (CPUISMIPS3)
MachFlushDCache(MIPS_KSEG1_TO_PHYS(state->dmaBufAddr),
@ -195,6 +276,7 @@ asic_dma_end(asc, state, flag)
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. */
@ -210,6 +292,9 @@ asic_dma_end(asc, state, flag)
*to++ = w;
}
}
#ifdef ASC_IOASIC_BOUNCE
bcopy(state->dmaBufAddr, state->buf, state->dmalen);
#endif
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: asc_tc.c,v 1.6 1997/07/21 05:39:05 jonathan Exp $ */
/* $NetBSD: asc_tc.c,v 1.7 1997/07/28 19:39:26 mhitch Exp $ */
/*
* Copyright 1996 The Board of Trustees of The Leland Stanford
@ -45,9 +45,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,
@ -84,7 +84,8 @@ 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;
@ -108,8 +109,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;
@ -132,7 +146,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 +158,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 +185,6 @@ tc_dma_end(asc, state, flag)
State *state;
int flag;
{
if (flag == ASCDMA_READ)
bcopy(state->dmaBufAddr, state->buf, state->dmalen);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ascvar.h,v 1.1 1996/09/25 21:07:56 jonathan Exp $ */
/* $NetBSD: ascvar.h,v 1.2 1997/07/28 19:39:27 mhitch Exp $ */
/*
@ -11,7 +11,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 */
@ -44,7 +43,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 */
@ -53,9 +51,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));
@ -82,7 +80,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));
/*