From 28fc2b2ee88d4c458a3bde1cdd91d2f93130ca28 Mon Sep 17 00:00:00 2001 From: ad Date: Thu, 24 Feb 2000 18:49:06 +0000 Subject: [PATCH] Add a DPT ISA HBA frontend, tested lightly with a PM2021A/9X. There are some issues. --- sys/dev/isa/dpt_isa.c | 321 ++++++++++++++++++++++++++++++++++++++++++ sys/dev/isa/files.isa | 7 +- 2 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 sys/dev/isa/dpt_isa.c diff --git a/sys/dev/isa/dpt_isa.c b/sys/dev/isa/dpt_isa.c new file mode 100644 index 000000000000..1f378ec5f2fa --- /dev/null +++ b/sys/dev/isa/dpt_isa.c @@ -0,0 +1,321 @@ +/* $NetBSD: dpt_isa.c,v 1.1 2000/02/24 18:49:06 ad Exp $ */ + +/* + * Copyright (c) 1999, 2000 Andy Doran + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * ISA front-end for DPT EATA SCSI driver. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: dpt_isa.c,v 1.1 2000/02/24 18:49:06 ad Exp $"); + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#define DPT_ISA_IOSIZE 16 +#define DPT_ISA_MAXCCBS 16 + +static int dpt_isa_match __P((struct device *, struct cfdata *, void *)); +static void dpt_isa_attach __P((struct device *, struct device *, void *)); +static int dpt_isa_probe __P((struct isa_attach_args *, int)); +static int dpt_isa_wait __P((bus_space_handle_t, bus_space_tag_t, u_int8_t, + u_int8_t)); + +struct cfattach dpt_isa_ca = { + sizeof(struct dpt_softc), dpt_isa_match, dpt_isa_attach +}; + +/* Try 'less intrusive' addresses first */ +static int dpt_isa_iobases[] = { 0x230, 0x330, 0x1f0, 0x170, -1 }; + +/* + * Wait for the HBA status register to reach a specific state. + */ +static int +dpt_isa_wait(ioh, iot, mask, state) + bus_space_handle_t ioh; + bus_space_tag_t iot; + u_int8_t mask, state; +{ + int ms; + + for (ms = 2000 * 10; ms; ms--) { + if ((bus_space_read_1(iot, ioh, HA_STATUS) & mask) == state) + return (0); + DELAY(100); + } + return (-1); +} + +/* + * Match a supported board. + */ +static int +dpt_isa_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct isa_attach_args *ia; + int i; + + ia = aux; + + if (ia->ia_iobase == ISACF_PORT_DEFAULT) { + for (i = 0; dpt_isa_iobases[i] != -1; i++) { + if (dpt_isa_probe(ia, dpt_isa_iobases[i])) { + ia->ia_iobase = dpt_isa_iobases[i]; + return (1); + } + } + } else if (dpt_isa_probe(ia, ia->ia_iobase)) + return (1); + + return (0); +} + +/* + * Probe for a supported board. + */ +static int +dpt_isa_probe(ia, iobase) + struct isa_attach_args *ia; + int iobase; +{ + struct eata_cfg ec; + bus_space_handle_t ioh; + bus_space_tag_t iot; + int i, j, stat; + u_int16_t *p; + + iot = ia->ia_iot; + + if (bus_space_map(iot, iobase, DPT_ISA_IOSIZE, 0, &ioh) != 0) + return(0); + + /* + * Assumuing the DPT BIOS reset the board, we shouldn't need to + * re-do it here. The tests below should weed out non-EATA devices + * before we start poking any registers. + */ + for (i = 1000; i; i--) { + if ((bus_space_read_1(iot, ioh, HA_STATUS) & HA_ST_READY) != 0) + break; + DELAY(2000); + } + + if (i == 0) { + bus_space_unmap(iot, ioh, DPT_ISA_IOSIZE); + return (0); + } + + while((((stat = bus_space_read_1(iot, ioh, HA_STATUS)) + != (HA_ST_READY|HA_ST_SEEK_COMPLETE)) + && (stat != (HA_ST_READY|HA_ST_SEEK_COMPLETE|HA_ST_ERROR)) + && (stat != (HA_ST_READY|HA_ST_SEEK_COMPLETE|HA_ST_ERROR|HA_ST_DRQ))) + || (dpt_isa_wait(ioh, iot, HA_ST_BUSY, 0))) { + /* RAID drives still spinning up? */ + if((bus_space_read_1(iot, ioh, HA_ERROR) != 'D') + || (bus_space_read_1(iot, ioh, HA_ERROR + 1) != 'P') + || (bus_space_read_1(iot, ioh, HA_ERROR + 2) != 'T')) { + bus_space_unmap(iot, ioh, DPT_ISA_IOSIZE); + return (0); + } + } + + /* + * At this point we can be confident that we are dealing with a DPT + * HBA. Issue the read-config command and wait for the data to + * appear. XXX we shouldn't be doing this with PIO, but it makes it + * a lot easier as no DMA setup is required. + */ + bus_space_write_1(iot, ioh, HA_COMMAND, CP_PIO_GETCFG); + memset(&ec, 0, sizeof(ec)); + i = ((int)&((struct eata_cfg *)0)->ec_cfglen + + sizeof(ec.ec_cfglen)) >> 1; + p = (u_int16_t *)&ec; + + if (dpt_isa_wait(ioh, iot, 0xFF, HA_ST_DATA_RDY)) { + bus_space_unmap(iot, ioh, DPT_ISA_IOSIZE); + return (0); + } + + /* Begin reading */ + while (i--) + *p++ = le16toh(bus_space_read_2(iot, ioh, HA_DATA)); + + if ((i = ec.ec_cfglen) > (sizeof(struct eata_cfg) + - (int)(&(((struct eata_cfg *)0L)->ec_cfglen)) + - sizeof(ec.ec_cfglen))) + i = sizeof(struct eata_cfg) + - (int)(&(((struct eata_cfg *)0L)->ec_cfglen)) + - sizeof(ec.ec_cfglen); + + j = i + (int)(&(((struct eata_cfg *)0L)->ec_cfglen)) + + sizeof(ec.ec_cfglen); + i >>= 1; + + while (i--) + *p++ = le16toh(bus_space_read_2(iot, ioh, HA_DATA)); + + /* Flush until we have read 512 bytes. */ + i = (512 - j + 1) >> 1; + while (i--) + le16toh(bus_space_read_2(iot, ioh, HA_DATA)); + + /* Puke if we don't like the returned configuration data. */ + if ((bus_space_read_1(iot, ioh, HA_STATUS) & HA_ST_ERROR) != 0 || + memcmp(ec.ec_eatasig, "EATA", 4) != 0 || + (ec.ec_feat0 & (EC_F0_HBA_VALID | EC_F0_DMA_SUPPORTED)) != + (EC_F0_HBA_VALID | EC_F0_DMA_SUPPORTED)) { + bus_space_unmap(iot, ioh, DPT_ISA_IOSIZE); + return (0); + } + + /* + * Which DMA channel to use: if it was hardwired in the kernel + * configuration, use that value. If the HBA told us, use that + * value. Otherwise, puke. + */ + if (ia->ia_drq == -1) { + int dmanum = ((ec.ec_feat1 & EC_F1_DMA_NUM_MASK) >> + EC_F1_DMA_NUM_SHIFT); + + if ((ec.ec_feat0 & EC_F0_DMA_NUM_VALID) == 0 || dmanum > 3) { + bus_space_unmap(iot, ioh, DPT_ISA_IOSIZE); + return (0); + } + + ia->ia_drq = "\0\7\6\5"[dmanum]; + } + + /* + * Which IRQ to use: if it was hardwired in the kernel configuration, + * use that value. Otherwise, use what the HBA told us. + */ + if (ia->ia_irq == -1) + ia->ia_irq = ((ec.ec_feat1 & EC_F1_IRQ_NUM_MASK) >> + EC_F1_IRQ_NUM_SHIFT); + + ia->ia_msize = 0; + ia->ia_iosize = DPT_ISA_IOSIZE; + bus_space_unmap(iot, ioh, DPT_ISA_IOSIZE); + return (1); +} + +/* + * Attach a matched board. + */ +static void +dpt_isa_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isa_attach_args *ia; + isa_chipset_tag_t ic; + bus_space_handle_t ioh; + bus_space_tag_t iot; + struct dpt_softc *sc; + struct eata_cfg *ec; + int error; + + ia = aux; + sc = (struct dpt_softc *)self; + iot = ia->ia_iot; + ic = ia->ia_ic; + + printf(": "); + + if ((error = bus_space_map(iot, ia->ia_iobase, DPT_ISA_IOSIZE, 0, + &ioh)) != 0) { + printf("can't map i/o space, error = %d\n", error); + return; + } + + sc->sc_iot = iot; + sc->sc_ioh = ioh; + sc->sc_dmat = ia->ia_dmat; + + if ((error = isa_dmacascade(ic, ia->ia_drq)) != 0) { + printf("unable to cascade DRQ, error = %d\n", error); + return; + } + + /* Establish the interrupt. */ + if ((sc->sc_ih = isa_intr_establish(ic, ia->ia_irq, IST_EDGE, IPL_BIO, + dpt_intr, sc)) == NULL) { + printf("can't establish interrupt\n"); + return; + } + + if (dpt_readcfg(sc)) { + printf("readcfg failed - see dpt(4)\n"); + return; + } + + /* + * Now attach to the bus-independent code. XXX We need to force + * parameters that aren't filled in by some ISA boards. In + * particular, due to the limited amount of memory we have to play + * with for DMA, clamp the number of CCBs to 16. I don't know if + * making the DMA map non-contigiuous would allow us to play with + * more CCBs, but in any case that *could* cause a performance hit, + * at least for ISA HBAs. + */ + ec = &sc->sc_ec; + + if (be16toh(*(int16_t *)ec->ec_queuedepth) > DPT_ISA_MAXCCBS) + *(int16_t *)ec->ec_queuedepth = htobe16(DPT_ISA_MAXCCBS); + if (ec->ec_maxlun == 0) + ec->ec_maxlun = 7; + if ((ec->ec_feat3 & EC_F3_MAX_TARGET_MASK) >> EC_F3_MAX_TARGET_SHIFT + == 0) + ec->ec_feat3 = (ec->ec_feat3 & ~EC_F3_MAX_TARGET_MASK) | + (7 << EC_F3_MAX_TARGET_SHIFT); + + /* Now attach to the bus-independent code */ + dpt_init(sc, NULL); +} diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 8ec82e169f4c..eebd655655be 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $NetBSD: files.isa,v 1.95 2000/01/04 06:30:04 chopps Exp $ +# $NetBSD: files.isa,v 1.96 2000/02/24 18:49:06 ad Exp $ # # Config file and device description for machine-independent ISA code. # Included by ports that need it. Requires that the SCSI files be @@ -102,6 +102,11 @@ file dev/isa/esp_isa.c esp_isa attach bha at isa with bha_isa: isadma file dev/isa/bha_isa.c bha_isa +# DPT SmartCache/SmartRAID III/IV ISA family +# device declaration in sys/conf/files +attach dpt at isa with dpt_isa: isadma +file dev/isa/dpt_isa.c dpt_isa + # Seagate ST0[12] ICs device sea: scsi, isadma attach sea at isa