diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/tc/asc_ioasic.c | 244 | ||||
-rw-r--r-- | sys/dev/tc/asc_tc.c | 167 | ||||
-rw-r--r-- | sys/dev/tc/ascvar.h | 92 |
3 files changed, 503 insertions, 0 deletions
diff --git a/sys/dev/tc/asc_ioasic.c b/sys/dev/tc/asc_ioasic.c new file mode 100644 index 00000000000..14c6e987a91 --- /dev/null +++ b/sys/dev/tc/asc_ioasic.c @@ -0,0 +1,244 @@ +/* $NetBSD: asc_ioasic.c,v 1.3 1996/10/13 01:38:36 christos Exp $ */ + +/* + * Copyright 1996 The Board of Trustees of The Leland Stanford + * Junior University. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. Stanford University + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <dev/tc/tcvar.h> +#include <dev/tc/ioasicvar.h> +#include <machine/autoconf.h> + +#include <pmax/dev/device.h> /* XXX */ +#include <pmax/dev/scsi.h> /* XXX */ + +#include <pmax/dev/ascreg.h> /* XXX */ +#include <dev/tc/ascvar.h> + +#include <mips/locore.h> /* XXX XXX bus.h needs cache-consistency*/ + +/*XXX*/ +#include <pmax/pmax/asic.h> /* XXX ioasic register defs? */ +#include <pmax/pmax/kmin.h> /* XXX ioasic register defs? */ +#include <pmax/pmax/pmaxtype.h> +extern int pmax_boardtype; + + +/* + * Autoconfiguration data for config. + */ +int asc_ioasic_match __P((struct device *, void *, void *)); +void asc_ioasic_attach __P((struct device *, struct device *, void *)); + +struct cfattach asc_ioasic_ca = { + sizeof(struct asc_softc), asc_ioasic_match, asc_ioasic_attach +}; + +/* + * DMA callback declarations + */ + +extern u_long asc_iomem; +static void +asic_dma_start __P((asc_softc_t asc, State *state, caddr_t cp, int flag)); + +static void +asic_dma_end __P((asc_softc_t asc, State *state, int flag)); + +int +asc_ioasic_match(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + struct ioasicdev_attach_args *d = aux; + void *ascaddr; + + if (strncmp(d->iada_modname, "asc", TC_ROM_LLEN) && + strncmp(d->iada_modname, "PMAZ-AA ", TC_ROM_LLEN)) + return (0); + + /* probe for chip */ + ascaddr = (void*)d->iada_addr; + if (tc_badaddr(ascaddr + ASC_OFFSET_53C94)) + return (0); + + return (1); +} + +void +asc_ioasic_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + register struct ioasicdev_attach_args *d = aux; + register asc_softc_t asc = (asc_softc_t) self; + int bufsiz, speed; + + void *ascaddr; + int unit; + + ascaddr = (void*)MACH_PHYS_TO_UNCACHED(d->iada_addr); + unit = asc->sc_dev.dv_unit; + + /* + * Initialize hw descriptor, cache some pointers + */ + asc->regs = (asc_regmap_t *)(ascaddr + ASC_OFFSET_53C94); + + /* + * Set up machine dependencies. + * (1) how to do dma + * (2) timing based on turbochannel frequency + */ + + asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem); + bufsiz = 8192; + *((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); + + /* tie pseudo-slot to device */ + + ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_BIO, + asc_intr, asc); +} + + +/* + * 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) + asc_softc_t asc; + State *state; + caddr_t cp; + int flag; +{ + register volatile u_int *ssr = (volatile u_int *) + IOASIC_REG_CSR(ioasic_base); + u_int phys, nphys; + + /* stop DMA engine first */ + *ssr &= ~IOASIC_CSR_DMAEN_SCSI; + *((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0; + + phys = MACH_CACHED_TO_PHYS(cp); + cp = (caddr_t)mips_trunc_page(cp + NBPG); + nphys = MACH_CACHED_TO_PHYS(cp); + + asc->dma_next = cp; + asc->dma_xfer = state->dmalen - (nphys - phys); + + *(volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base) = + IOASIC_DMA_ADDR(phys); + *(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) = + IOASIC_DMA_ADDR(nphys); + if (flag == ASCDMA_READ) + *ssr |= IOASIC_CSR_SCSI_DIR | IOASIC_CSR_DMAEN_SCSI; + else + *ssr = (*ssr & ~IOASIC_CSR_SCSI_DIR) | IOASIC_CSR_DMAEN_SCSI; + wbflush(); +} + +static void +asic_dma_end(asc, state, flag) + asc_softc_t asc; + State *state; + int flag; +{ + register volatile u_int *ssr = (volatile u_int *) + IOASIC_REG_CSR(ioasic_base); + register volatile u_int *dmap = (volatile u_int *) + IOASIC_REG_SCSI_DMAPTR(ioasic_base); + register u_short *to; + register int w; + int nb; + + *ssr &= ~IOASIC_CSR_DMAEN_SCSI; + to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3); + *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 ( (nb = *((int *)IOASIC_REG_SCSI_SCR(ioasic_base))) != 0) { + /* pick up last upto6 bytes, sigh. */ + + /* Last byte really xferred is.. */ + w = *(int *)IOASIC_REG_SCSI_SDR0(ioasic_base); + *to++ = w; + if (--nb > 0) { + w >>= 16; + *to++ = w; + } + if (--nb > 0) { + w = *(int *)IOASIC_REG_SCSI_SDR1(ioasic_base); + *to++ = w; + } + } + } +} + +#ifdef notdef +/* + * Called by asic_intr() for scsi dma pointer update interrupts. + */ +void +asc_dma_intr() +{ + asc_softc_t asc = &asc_cd.cd_devs[0]; /*XXX*/ + u_int next_phys; + + asc->dma_xfer -= NBPG; + if (asc->dma_xfer <= -NBPG) { + volatile u_int *ssr = (volatile u_int *) + IOASIC_REG_CSR(ioasic_base); + *ssr &= ~IOASIC_CSR_DMAEN_SCSI; + } else { + asc->dma_next += NBPG; + next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); + } + *(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) = + IOASIC_DMA_ADDR(next_phys); + wbflush(); +} +#endif /*notdef*/ diff --git a/sys/dev/tc/asc_tc.c b/sys/dev/tc/asc_tc.c new file mode 100644 index 00000000000..42417f12213 --- /dev/null +++ b/sys/dev/tc/asc_tc.c @@ -0,0 +1,167 @@ +/* $NetBSD: asc_tc.c,v 1.4 1996/10/13 01:38:37 christos Exp $ */ + +/* + * Copyright 1996 The Board of Trustees of The Leland Stanford + * Junior University. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. Stanford University + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/device.h> +#include <dev/tc/tcvar.h> +#include <machine/autoconf.h> +#include <dev/tc/ioasicvar.h> + +#include <pmax/dev/device.h> /* XXX */ +#include <pmax/dev/scsi.h> /* XXX */ + +#include <pmax/dev/ascreg.h> /* XXX */ +#include <dev/tc/ascvar.h> + +/*XXX*/ + + +/* + * Autoconfiguration data for config. + */ +int asc_tc_match __P((struct device *, void *, void *)); +void asc_tc_attach __P((struct device *, struct device *, void *)); + +struct cfattach asc_tc_ca = { + sizeof(struct asc_softc), asc_tc_match, asc_tc_attach +}; + +/* + * DMA callbacks + */ + +static void +tc_dma_start __P((struct asc_softc *asc, struct scsi_state *state, + caddr_t cp, int flag)); + +static void +tc_dma_end __P((struct asc_softc *asc, struct scsi_state *state, + int flag)); + + +int +asc_tc_match(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + struct tc_attach_args *t = aux; + void *ascaddr; + + if (strncmp(t->ta_modname, "PMAZ-AA ", TC_ROM_LLEN)) + return (0); + + ascaddr = (void*)t->ta_addr; + + if (tc_badaddr(ascaddr + ASC_OFFSET_53C94)) + return (0); + + return (1); +} + + + +void +asc_tc_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + register struct tc_attach_args *t = aux; + register asc_softc_t asc = (asc_softc_t) self; + int bufsiz, speed; + + void *ascaddr; + int unit; + + ascaddr = (void*)MACH_PHYS_TO_UNCACHED(t->ta_addr); + unit = asc->sc_dev.dv_unit; + + /* + * Initialize hw descriptor, cache some pointers + */ + asc->regs = (asc_regmap_t *)(ascaddr + ASC_OFFSET_53C94); + + /* + * Set up machine dependencies. + * (1) how to do dma + * (2) timing based on turbochannel frequency + */ + + /* + * 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; + asc->dma_start = tc_dma_start; + asc->dma_end = tc_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); + + switch (t->ta_busspeed) { + case TC_SPEED_25_MHZ: + speed = ASC_SPEED_25_MHZ; + break; + + default: + printf(" (unknown TC speed, assuming 12.5MHz) "); + /* FALLTHROUGH*/ + case TC_SPEED_12_5_MHZ: + speed = ASC_SPEED_12_5_MHZ; + break; + }; + + ascattach(asc, bufsiz, speed); + + /* tie pseudo-slot to device */ + tc_intr_establish(parent, t->ta_cookie, TC_IPL_BIO, + asc_intr, asc); +} + + +/* + * 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) + asc_softc_t asc; + State *state; + caddr_t cp; + int flag; +{ + + if (flag == ASCDMA_WRITE) + *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); + else + *asc->dmar = ASC_DMA_ADDR(cp); +} + +static void +tc_dma_end(asc, state, flag) + asc_softc_t asc; + State *state; + int flag; +{ + +} diff --git a/sys/dev/tc/ascvar.h b/sys/dev/tc/ascvar.h new file mode 100644 index 00000000000..966d0480a03 --- /dev/null +++ b/sys/dev/tc/ascvar.h @@ -0,0 +1,92 @@ +/* $NetBSD: ascvar.h,v 1.1 1996/09/25 21:07:56 jonathan Exp $ */ + + +/* + * State kept for each active SCSI device. + */ +struct script; + +typedef struct scsi_state { + struct script *script; /* saved script while processing error */ + 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 */ + char *buf; /* current pointer within scsicmd->buf */ + int flags; /* see below */ + int msglen; /* number of message bytes to read */ + int msgcnt; /* number of message bytes received */ + u_char sync_period; /* DMA synchronous period */ + u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ + u_char msg_out; /* next MSG_OUT byte to send */ + u_char msg_in[16]; /* buffer for multibyte messages */ +} State; + +/* state flags */ +#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_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 */ +#define PARITY_ERR 0x080 /* true if parity error seen */ +#define CHECK_SENSE 0x100 /* true if doing sense command */ + + +/* + * State kept for each active SCSI host interface (53C94). + */ + +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 */ + int target; /* target SCSI ID if busy */ + struct script *script; /* next expected interrupt & action */ + 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, + struct scsi_state *state, + caddr_t cp, int flag)); + /* End dma routine */ + void (*dma_end) __P((struct asc_softc *asc, + struct scsi_state *state, int flag)); + + u_char *dma_next; + int dma_xfer; /* Dma len still to go */ + int min_period; /* Min transfer period clk/byte */ + int max_period; /* Max transfer period clk/byte */ + int ccf; /* CCF, whatever that really is? */ + 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 */ +#endif +}; +typedef struct asc_softc *asc_softc_t; + +#define ASC_STATE_IDLE 0 /* idle state */ +#define ASC_STATE_BUSY 1 /* selecting or currently connected */ +#define ASC_STATE_TARGET 2 /* currently selected as target */ +#define ASC_STATE_RESEL 3 /* currently waiting for reselect */ + + +#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)); +int asc_intr __P ((void *asc)); + +/* + * Dma operations. + */ +#define ASCDMA_READ 1 +#define ASCDMA_WRITE 2 |