diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/tc/asc.c | 161 | ||||
-rw-r--r-- | sys/dev/tc/asc_ioasic.c | 164 | ||||
-rw-r--r-- | sys/dev/tc/asc_tc.c | 53 | ||||
-rw-r--r-- | sys/dev/tc/ascvar.h | 15 |
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)); /* |