summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/tc/asc_ioasic.c244
-rw-r--r--sys/dev/tc/asc_tc.c167
-rw-r--r--sys/dev/tc/ascvar.h92
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