diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2005-03-02 16:42:38 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2005-03-02 16:42:38 +0000 |
commit | 75699d05e12889fd103ff022333d521b76b4eebd (patch) | |
tree | f5fac7dabfe42ee6f627be04b084ad71ea4351f6 /sys/arch/sparc/dev | |
parent | 835ad1539d3707443bfadd1763cc0383eab238e4 (diff) |
Support for SUNW,fas SCSI, currently restricted to the lower 8 targets due
to MI esp code limitations.
ok deraadt@
Diffstat (limited to 'sys/arch/sparc/dev')
-rw-r--r-- | sys/arch/sparc/dev/dma.c | 137 | ||||
-rw-r--r-- | sys/arch/sparc/dev/dmavar.h | 6 | ||||
-rw-r--r-- | sys/arch/sparc/dev/esp.c | 234 |
3 files changed, 290 insertions, 87 deletions
diff --git a/sys/arch/sparc/dev/dma.c b/sys/arch/sparc/dev/dma.c index 0ecfa849131..18b45f116ef 100644 --- a/sys/arch/sparc/dev/dma.c +++ b/sys/arch/sparc/dev/dma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dma.c,v 1.20 2005/02/27 22:01:03 miod Exp $ */ +/* $OpenBSD: dma.c,v 1.21 2005/03/02 16:42:37 miod Exp $ */ /* $NetBSD: dma.c,v 1.46 1997/08/27 11:24:16 bouyer Exp $ */ /* @@ -131,6 +131,7 @@ dmaattach(parent, self, aux) { struct confargs *ca = aux; struct dma_softc *sc = (void *)self; + int devnode; #if defined(SUN4C) || defined(SUN4M) int node; struct confargs oca; @@ -142,6 +143,7 @@ dmaattach(parent, self, aux) mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len); sc->sc_regs = (struct dma_regs *) ca->ca_ra.ra_vaddr; + devnode = ca->ca_ra.ra_node; /* * If we're a ledma, check to see what cable type is currently @@ -151,8 +153,7 @@ dmaattach(parent, self, aux) * can change it via a "link0" option to ifconfig. */ if (strcmp(ca->ca_ra.ra_name, "ledma") == 0) { - char *cabletype = getpropstring(ca->ca_ra.ra_node, - "cable-selection"); + char *cabletype = getpropstring(devnode, "cable-selection"); if (strcmp(cabletype, "tpe") == 0) { sc->sc_regs->csr |= E_TP_AUI; } else if (strcmp(cabletype, "aui") == 0) { @@ -174,7 +175,7 @@ dmaattach(parent, self, aux) if (sbusburst == 0) sbusburst = SBUS_BURST_32 - 1; /* 1->16 */ - sc->sc_burst = getpropint(ca->ca_ra.ra_node,"burst-sizes", -1); + sc->sc_burst = getpropint(devnode, "burst-sizes", -1); if (sc->sc_burst == -1) /* take SBus burst sizes */ sc->sc_burst = sbusburst; @@ -201,25 +202,17 @@ dmaattach(parent, self, aux) case DMAREV_2: printf("2"); break; + case DMAREV_HME: + printf("fas"); + break; default: printf("unknown (0x%x)", sc->sc_rev); } printf("\n"); /* indirect functions */ - if (sc->sc_dev.dv_cfdata->cf_attach == &dma_ca) { - sc->reset = espdma_reset; - sc->intr = espdmaintr; - } else { - sc->reset = ledma_reset; - sc->intr = ledmaintr; - } - sc->enintr = dma_enintr; - sc->isintr = dma_isintr; - sc->setup = dma_setup; - sc->go = dma_go; + dma_setuphandlers(sc); - sc->sc_node = ca->ca_ra.ra_node; if (CPU_ISSUN4) goto espsearch; @@ -237,7 +230,7 @@ dmaattach(parent, self, aux) oca.ca_ra.ra_bp = NULL; /* search through children */ - node = firstchild(sc->sc_node); + node = firstchild(devnode); if (node != 0) do { name = getpropstring(node, "name"); if (!romprop(&oca.ca_ra, name, node)) @@ -272,6 +265,23 @@ espsearch: } } +void +dma_setuphandlers(struct dma_softc *sc) +{ + if (sc->sc_dev.dv_cfdata == NULL || /* happens on SUNW,fas */ + sc->sc_dev.dv_cfdata->cf_attach == &dma_ca) { + sc->reset = espdma_reset; + sc->intr = espdmaintr; + } else { + sc->reset = ledma_reset; + sc->intr = ledmaintr; + } + sc->enintr = dma_enintr; + sc->isintr = dma_isintr; + sc->setup = dma_setup; + sc->go = dma_go; +} + #define DMAWAIT(SC, COND, MSG, DONTPANIC) do if (COND) { \ int count = 500000; \ while ((COND) && --count > 0) DELAY(1); \ @@ -293,14 +303,16 @@ espsearch: * other revs: D_ESC_R_PEND bit reads as 0 \ */ \ DMAWAIT(sc, sc->sc_regs->csr & D_ESC_R_PEND, "R_PEND", dontpanic);\ - /* \ - * Select drain bit based on revision \ - * also clears errors and D_TC flag \ - */ \ - if (sc->sc_rev == DMAREV_1 || sc->sc_rev == DMAREV_0) \ - DMACSR(sc) |= D_ESC_DRAIN; \ - else \ - DMACSR(sc) |= D_INVALIDATE; \ + if (sc->sc_rev != DMAREV_HME) { \ + /* \ + * Select drain bit based on revision \ + * also clears errors and D_TC flag \ + */ \ + if (sc->sc_rev == DMAREV_1 || sc->sc_rev == DMAREV_0) \ + DMACSR(sc) |= D_ESC_DRAIN; \ + else \ + DMACSR(sc) |= D_INVALIDATE; \ + } \ /* \ * Wait for draining to finish \ * rev0 & rev1 call this PACKCNT \ @@ -318,8 +330,8 @@ espsearch: */ \ DMAWAIT(sc, sc->sc_regs->csr & D_ESC_R_PEND, "R_PEND", dontpanic);\ csr = DMACSR(sc); \ - csr &= ~(D_WRITE|D_EN_DMA); \ - csr |= D_INVALIDATE; \ + csr &= ~(D_WRITE|D_EN_DMA); /* no-ops on ENET */ \ + csr |= D_INVALIDATE; /* XXX FAS ? */ \ DMACSR(sc) = csr; \ } while(0) @@ -328,36 +340,59 @@ dma_reset(sc, isledma) struct dma_softc *sc; int isledma; { + int csr; + DMA_FLUSH(sc, 1); - DMACSR(sc) |= D_RESET; /* reset DMA */ - DELAY(200); /* what should this be ? */ + csr = DMACSR(sc); + + if (sc->sc_rev == DMAREV_HME) + DMACSR(sc) = csr | D_HW_RESET_FAS366; + + csr |= D_RESET; /* reset DMA */ + DMACSR(sc) = csr; + DELAY(200); /* > 10 Sbus clocks(?) */ + /*DMAWAIT1(sc); why was this here? */ DMACSR(sc) &= ~D_RESET; /* de-assert reset line */ - DMACSR(sc) |= D_INT_EN; /* enable interrupts */ - if (sc->sc_rev > DMAREV_1 && isledma == 0) - DMACSR(sc) |= D_FASTER; + DELAY(5); + + csr = DMACSR(sc); + csr |= D_INT_EN; /* enable interrupts */ + if (sc->sc_rev > DMAREV_1 && isledma == 0) { + if (sc->sc_rev == DMAREV_HME) + csr |= D_TWO_CYCLE; + else + csr |= D_FASTER; + } switch (sc->sc_rev) { + case DMAREV_HME: case DMAREV_2: - sc->sc_regs->csr &= ~L64854_BURST_SIZE; /* must clear first */ + csr &= ~L64854_BURST_SIZE; /* must clear first */ if (sc->sc_burst & SBUS_BURST_32) { - DMACSR(sc) |= L64854_BURST_32; + csr |= L64854_BURST_32; } else if (sc->sc_burst & SBUS_BURST_16) { - DMACSR(sc) |= L64854_BURST_16; + csr |= L64854_BURST_16; } else { - DMACSR(sc) |= L64854_BURST_0; + csr |= L64854_BURST_0; } break; case DMAREV_ESC: - DMACSR(sc) |= D_ESC_AUTODRAIN; /* Auto-drain */ + csr |= D_ESC_AUTODRAIN; /* Auto-drain */ if (sc->sc_burst & SBUS_BURST_32) { - DMACSR(sc) &= ~0x800; + csr &= ~D_ESC_BURST; } else - DMACSR(sc) |= 0x800; + csr |= D_ESC_BURST; break; default: break; } + DMACSR(sc) = csr; + + if (sc->sc_rev == DMAREV_HME) { + DMADDR(sc) = 0; + sc->sc_dmactl = csr; + } sc->sc_active = 0; /* and of course we aren't */ } @@ -445,6 +480,15 @@ dma_setup(sc, addr, len, datain, dmasize) NCR_DMA(("dma_setup: dmasize = %d\n", sc->sc_dmasize)); + /* + * XXX what length? + */ + if (sc->sc_rev == DMAREV_HME) { + DMACSR(sc) = sc->sc_dmactl | L64854_RESET; + DMACSR(sc) = sc->sc_dmactl; + DMACNT(sc) = *dmasize; + } + /* Program the DMA address */ if (CPU_ISSUN4M && sc->sc_dmasize) { /* @@ -474,6 +518,11 @@ dma_setup(sc, addr, len, datain, dmasize) else csr &= ~D_WRITE; csr |= D_INT_EN; + + if (sc->sc_rev == DMAREV_HME) { + csr |= (D_DSBL_SCSI_DRN | D_EN_DMA); + } + DMACSR(sc) = csr; return 0; @@ -503,17 +552,19 @@ espdmaintr(sc) struct ncr53c9x_softc *nsc = &sc->sc_esp->sc_ncr53c9x; int trans, resid; u_long csr; + csr = DMACSR(sc); NCR_DMA(("%s: intr: addr %p, csr %b\n", sc->sc_dev.dv_xname, DMADDR(sc), csr, DDMACSR_BITS)); - if (csr & D_ERR_PEND) { - DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */ - DMACSR(sc) |= D_INVALIDATE; + if (csr & (D_ERR_PEND|D_SLAVE_ERR)) { printf("%s: error: csr=%b\n", sc->sc_dev.dv_xname, csr, DDMACSR_BITS); - return -1; + DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */ + /* Invalidate the queue; SLAVE_ERR bit is write-to-clear */ + DMACSR(sc) |= D_INVALIDATE|D_SLAVE_ERR; + return (-1); } /* This is an "assertion" :) */ diff --git a/sys/arch/sparc/dev/dmavar.h b/sys/arch/sparc/dev/dmavar.h index 622e2297457..b86cf79d1c3 100644 --- a/sys/arch/sparc/dev/dmavar.h +++ b/sys/arch/sparc/dev/dmavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dmavar.h,v 1.5 2003/06/05 12:27:02 deraadt Exp $ */ +/* $OpenBSD: dmavar.h,v 1.6 2005/03/02 16:42:37 miod Exp $ */ /* $NetBSD: dmavar.h,v 1.11 1996/11/27 21:49:53 pk Exp $ */ /* @@ -32,7 +32,6 @@ struct dma_softc { struct dma_regs *sc_regs; /* the registers */ int sc_active; /* DMA active ? */ u_int sc_rev; /* revision */ - int sc_node; /* PROM node ID */ int sc_burst; /* DVMA burst size in effect */ caddr_t sc_dvmakaddr; /* DVMA cookies */ caddr_t sc_dvmaaddr; /* */ @@ -45,6 +44,7 @@ struct dma_softc { int (*intr)(struct dma_softc *); /* interrupt ! */ int (*setup)(struct dma_softc *, caddr_t *, size_t *, int, size_t *); void (*go)(struct dma_softc *); + u_int sc_dmactl; }; #define DMACSR(sc) (sc->sc_regs->csr) @@ -59,3 +59,5 @@ struct dma_softc { #define DMA_ISACTIVE(r) ((r)->sc_active) #define DMA_SETUP(a, b, c, d, e) (((a)->setup)(a, b, c, d, e)) #define DMA_GO(r) (((r)->go)(r)) + +void dma_setuphandlers(struct dma_softc *); diff --git a/sys/arch/sparc/dev/esp.c b/sys/arch/sparc/dev/esp.c index 245e94d8a6b..520b3e90e43 100644 --- a/sys/arch/sparc/dev/esp.c +++ b/sys/arch/sparc/dev/esp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: esp.c,v 1.22 2004/09/29 07:35:11 miod Exp $ */ +/* $OpenBSD: esp.c,v 1.23 2005/03/02 16:42:37 miod Exp $ */ /* $NetBSD: esp.c,v 1.69 1997/08/27 11:24:18 bouyer Exp $ */ /* @@ -107,6 +107,7 @@ #include <sys/proc.h> #include <sys/user.h> #include <sys/queue.h> +#include <sys/malloc.h> #include <scsi/scsi_all.h> #include <scsi/scsiconf.h> @@ -150,6 +151,8 @@ struct scsi_device esp_dev = { */ u_char esp_read_reg(struct ncr53c9x_softc *, int); void esp_write_reg(struct ncr53c9x_softc *, int, u_char); +u_char esp_rdreg1(struct ncr53c9x_softc *, int); +void esp_wrreg1(struct ncr53c9x_softc *, int, u_char); int esp_dma_isintr(struct ncr53c9x_softc *); void esp_dma_reset(struct ncr53c9x_softc *); int esp_dma_intr(struct ncr53c9x_softc *); @@ -172,6 +175,21 @@ struct ncr53c9x_glue esp_glue = { NULL, /* gl_clear_latched_intr */ }; +#if defined(SUN4C) || defined(SUN4M) +struct ncr53c9x_glue esp_glue1 = { + esp_rdreg1, + esp_wrreg1, + esp_dma_isintr, + esp_dma_reset, + esp_dma_intr, + esp_dma_setup, + esp_dma_go, + esp_dma_stop, + esp_dma_isactive, + NULL, /* gl_clear_latched_intr */ +}; +#endif + int espmatch(parent, vcf, aux) struct device *parent; @@ -181,6 +199,14 @@ espmatch(parent, vcf, aux) register struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; +#if defined(SUN4C) || defined(SUN4M) + if (ca->ca_bustype == BUS_SBUS) { + if (strcmp("SUNW,fas", ra->ra_name) == 0 || + strcmp("ptscII", ra->ra_name) == 0) + return (1); + } +#endif + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); #if defined(SUN4C) || defined(SUN4M) @@ -206,16 +232,12 @@ espattach(parent, self, aux) struct esp_softc *esc = (void *)self; struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; struct bootpath *bp; - int dmachild = strncmp(parent->dv_xname, "dma", 3) == 0; + int dmachild; + unsigned int uid = 0; /* - * Set up glue for MI code early; we use some of it here. - */ - sc->sc_glue = &esp_glue; - - /* - * Make sure things are sane. I don't know if this is ever - * necessary, but it seem to be in all of Torek's code. + * If no interrupts properties, bail out: this might happen + * on the Sparc X terminal. */ if (ca->ca_ra.ra_nintr != 1) { printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr); @@ -225,17 +247,6 @@ espattach(parent, self, aux) esc->sc_pri = ca->ca_ra.ra_intr[0].int_pri; printf(" pri %d", esc->sc_pri); - /* - * Map my registers in, if they aren't already in virtual - * address space. - */ - if (ca->ca_ra.ra_vaddr) - esc->sc_reg = (volatile u_char *) ca->ca_ra.ra_vaddr; - else { - esc->sc_reg = (volatile u_char *) - mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len); - } - /* Other settings */ esc->sc_node = ca->ca_ra.ra_node; if (ca->ca_bustype == BUS_SBUS) { @@ -252,34 +263,142 @@ espattach(parent, self, aux) /* gimme MHz */ sc->sc_freq /= 1000000; - if (dmachild) { - esc->sc_dma = (struct dma_softc *)parent; - esc->sc_dma->sc_esp = esc; - } else { +#if defined(SUN4C) || defined(SUN4M) + if (ca->ca_bustype == BUS_SBUS && + strcmp("SUNW,fas", ca->ca_ra.ra_name) == 0) { + struct dma_softc *dsc; + /* - * find the DMA by poking around the dma device structures - * - * What happens here is that if the dma driver has not been - * configured, then this returns a NULL pointer. Then when the - * dma actually gets configured, it does the opposing test, and - * if the sc->sc_esp field in it's softc is NULL, then tries to - * find the matching esp driver. + * fas has 2 register spaces: DMA (lsi64854) and SCSI core + * (ncr53c9x). */ - esc->sc_dma = (struct dma_softc *) - getdevunit("dma", sc->sc_dev.dv_unit); + if (ca->ca_ra.ra_nreg != 2) { + printf(": expected 2 register spaces, found %d\n", + ca->ca_ra.ra_nreg); + return; + } /* - * and a back pointer to us, for DMA + * Allocate a softc for the DMA companion, which will not + * get a regular attachment. */ - if (esc->sc_dma) - esc->sc_dma->sc_esp = esc; + dsc = malloc(sizeof(struct dma_softc), M_DEVBUF, M_NOWAIT); + if (dsc == NULL) { + printf(": could not allocate dma softc\n"); + return; + } + bzero(dsc, sizeof(struct dma_softc)); + strlcpy(dsc->sc_dev.dv_xname, sc->sc_dev.dv_xname, + sizeof(dsc->sc_dev.dv_xname)); + esc->sc_dma = dsc; + + /* + * Map DMA registers + */ + dsc->sc_regs = (struct dma_regs *)mapiodev(&ca->ca_ra.ra_reg[0], + 0, ca->ca_ra.ra_reg[0].rr_len); + if (dsc->sc_regs == NULL) { + printf(": could not map DMA registers\n"); + return; + } + dsc->sc_rev = dsc->sc_regs->csr & D_DEV_ID; + dsc->sc_esp = esc; + +#ifdef SUN4M + /* + * Get transfer burst size from PROM and plug it into the + * controller registers. This is needed on the Sun4m; do + * others need it too? + */ + if (CPU_ISSUN4M) { + int sbusburst; + + sbusburst = ((struct sbus_softc *)parent)->sc_burst; + if (sbusburst == 0) + sbusburst = SBUS_BURST_32 - 1; /* 1 -> 16 */ + + dsc->sc_burst = + getpropint(ca->ca_ra.ra_node, "burst-sizes", -1); + if (dsc->sc_burst == -1) + /* take SBus burst sizes */ + dsc->sc_burst = sbusburst; + + /* Clamp at parent's burst sizes */ + dsc->sc_burst &= sbusburst; + } +#endif /* SUN4M */ + + /* indirect functions */ + dma_setuphandlers(dsc); + + /* + * Map SCSI core registers + */ + esc->sc_reg = (volatile u_char *)mapiodev(&ca->ca_ra.ra_reg[1], + 0, ca->ca_ra.ra_reg[1].rr_len); + if (esc->sc_reg == NULL) { + printf(": could not map SCSI core registers\n"); + return; + } + + dmachild = 0; + } else +#endif + { + /* + * Map my registers in, if they aren't already in virtual + * address space. + */ + if (ca->ca_ra.ra_vaddr) + esc->sc_reg = (volatile u_char *) ca->ca_ra.ra_vaddr; else { - printf("\n"); - panic("espattach: no dma found"); + esc->sc_reg = (volatile u_char *) + mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len); + } + + dmachild = strncmp(parent->dv_xname, "dma", 3) == 0; + if (dmachild) { + esc->sc_dma = (struct dma_softc *)parent; + esc->sc_dma->sc_esp = esc; + } else { + /* + * Find the DMA by poking around the DMA device + * structures. + * + * What happens here is that if the DMA driver has + * not been configured, then this returns a NULL + * pointer. Then when the DMA actually gets configured, + * it does the opposite test, and if the sc->sc_esp + * field in its softc is NULL, then tries to find the + * matching esp driver. + */ + esc->sc_dma = (struct dma_softc *) + getdevunit("dma", sc->sc_dev.dv_unit); + + /* + * ...and a back pointer to us, for DMA. + */ + if (esc->sc_dma) + esc->sc_dma->sc_esp = esc; + else { + printf("\n"); + panic("espattach: no dma found"); + } } } /* + * Set up glue for MI code. + */ +#if defined(SUN4C) || defined(SUN4M) + if (ca->ca_bustype == BUS_SBUS && + strcmp("ptscII", ca->ca_ra.ra_name) == 0) { + sc->sc_glue = &esp_glue1; + } else +#endif + sc->sc_glue = &esp_glue; + + /* * XXX More of this should be in ncr53c9x_attach(), but * XXX should we really poke around the chip that much in * XXX the MI code? Think about this more... @@ -314,6 +433,11 @@ espattach(parent, self, aux) sc->sc_cfg3 = 0; NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); sc->sc_rev = NCR_VARIANT_ESP200; + + /* XXX spec says it's valid after power up or chip reset */ + uid = NCR_READ_REG(sc, NCR_UID); + if (((uid & 0xf8) >> 3) == 0x0a) /* XXX */ + sc->sc_rev = NCR_VARIANT_FAS366; } } @@ -352,6 +476,7 @@ espattach(parent, self, aux) break; case NCR_VARIANT_ESP200: + case NCR_VARIANT_FAS366: sc->sc_maxxfer = 16 * 1024 * 1024; /* XXX - do actually set FAST* bits */ break; @@ -368,7 +493,7 @@ espattach(parent, self, aux) } #endif /* SUN4C || SUN4M */ - /* and the interuppts */ + /* and the interrupts */ esc->sc_ih.ih_fun = (void *) ncr53c9x_intr; esc->sc_ih.ih_arg = sc; intr_establish(esc->sc_pri, &esc->sc_ih, IPL_BIO, self->dv_xname); @@ -392,12 +517,13 @@ espattach(parent, self, aux) break; } + /* Turn on target selection using the `dma' method */ + if (sc->sc_rev != NCR_VARIANT_FAS366) + sc->sc_features |= NCR_F_DMASELECT; + /* Do the common parts of attachment. */ ncr53c9x_attach(sc, &esp_switch, &esp_dev); - /* Turn on target selection using the `dma' method */ - sc->sc_features |= NCR_F_DMASELECT; - bootpath_store(1, NULL); } @@ -427,6 +553,30 @@ esp_write_reg(sc, reg, val) esc->sc_reg[reg * 4] = v; } +#if defined(SUN4C) || defined(SUN4M) +u_char +esp_rdreg1(sc, reg) + struct ncr53c9x_softc *sc; + int reg; +{ + struct esp_softc *esc = (struct esp_softc *)sc; + + return (esc->sc_reg[reg]); +} + +void +esp_wrreg1(sc, reg, val) + struct ncr53c9x_softc *sc; + int reg; + u_char val; +{ + struct esp_softc *esc = (struct esp_softc *)sc; + u_char v = val; + + esc->sc_reg[reg] = v; +} +#endif + int esp_dma_isintr(sc) struct ncr53c9x_softc *sc; |