summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/advansys/adv_eisa.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/sys/dev/advansys/adv_eisa.c b/sys/dev/advansys/adv_eisa.c
new file mode 100644
index 0000000..77b2a92
--- /dev/null
+++ b/sys/dev/advansys/adv_eisa.c
@@ -0,0 +1,354 @@
+/*
+ * Device probe and attach routines for the following
+ * Advanced Systems Inc. SCSI controllers:
+ *
+ * Single Channel Products:
+ * ABP742 - Bus-Master EISA (240 CDB)
+ *
+ * Dual Channel Products:
+ * ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
+ *
+ * Copyright (c) 1997 Justin Gibbs.
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "eisa.h"
+#if NEISA > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+
+#include <i386/eisa/eisaconf.h>
+
+#include <dev/advansys/advansys.h>
+
+#define EISA_DEVICE_ID_ADVANSYS_740 0x04507400
+#define EISA_DEVICE_ID_ADVANSYS_750 0x04507500
+
+#define ADV_EISA_SLOT_OFFSET 0xc00
+#define ADV_EISA_OFFSET_CHAN1 0x30
+#define ADV_EISA_OFFSET_CHAN2 0x50
+#define ADV_EISA_IOSIZE 0x100
+
+#define ADV_EISA_ROM_BIOS_ADDR_REG 0x86
+#define ADV_EISA_IRQ_BURST_LEN_REG 0x87
+#define ADV_EISA_IRQ_MASK 0x07
+#define ADV_EISA_IRQ_10 0x00
+#define ADV_EISA_IRQ_11 0x01
+#define ADV_EISA_IRQ_12 0x02
+#define ADV_EISA_IRQ_14 0x04
+#define ADV_EISA_IRQ_15 0x05
+
+#define ADV_EISA_MAX_DMA_ADDR (0x07FFFFFFL)
+#define ADV_EISA_MAX_DMA_COUNT (0x07FFFFFFL)
+
+static int adveisaprobe(void);
+static int adveisaattach(struct eisa_device *e_dev);
+
+/*
+ * The overrun buffer shared amongst all EISA adapters.
+ */
+static u_int8_t* overrun_buf;
+bus_dma_tag_t overrun_dmat;
+bus_dmamap_t overrun_dmamap;
+bus_addr_t overrun_physbase;
+
+static struct eisa_driver adv_eisa_driver =
+{
+ "adv",
+ adveisaprobe,
+ adveisaattach,
+ /*shutdown*/NULL,
+ &adv_unit
+};
+
+DATA_SET (eisadriver_set, adv_eisa_driver);
+
+static const char *adveisamatch(eisa_id_t type);
+
+static const char*
+adveisamatch(type)
+ eisa_id_t type;
+{
+ switch (type & ~0xF) {
+ case EISA_DEVICE_ID_ADVANSYS_740:
+ return ("AdvanSys ABP-740/742 SCSI adapter");
+ break;
+ case EISA_DEVICE_ID_ADVANSYS_750:
+ return ("AdvanSys ABP-750/752 SCSI adapter");
+ break;
+ default:
+ break;
+ }
+ return (NULL);
+}
+
+static int
+adveisaprobe(void)
+{
+ u_int32_t iobase;
+ u_int8_t irq;
+ struct eisa_device *e_dev = NULL;
+ int count;
+
+ count = 0;
+ while ((e_dev = eisa_match_dev(e_dev, adveisamatch))) {
+ iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE)
+ + ADV_EISA_SLOT_OFFSET;
+
+ eisa_add_iospace(e_dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE);
+ irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG);
+ irq &= ADV_EISA_IRQ_MASK;
+ switch (irq) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 5:
+ break;
+ default:
+ printf("adv at slot %d: illegal "
+ "irq setting %d\n", e_dev->ioconf.slot,
+ irq);
+ continue;
+ }
+ eisa_add_intr(e_dev, irq + 10);
+ eisa_registerdev(e_dev, &adv_eisa_driver);
+ count++;
+ }
+ return count;
+}
+
+static int
+adveisaattach(struct eisa_device *e_dev)
+{
+ struct adv_softc *adv;
+ struct adv_softc *adv_b;
+ resvaddr_t *iospace;
+ int unit;
+ int irq;
+ int error;
+
+ adv_b = NULL;
+ unit = e_dev->unit;
+ iospace = e_dev->ioconf.ioaddrs.lh_first;
+
+ if (TAILQ_FIRST(&e_dev->ioconf.irqs) == NULL)
+ return (-1);
+
+ irq = TAILQ_FIRST(&e_dev->ioconf.irqs)->irq_no;
+
+ if (!iospace)
+ return (-1);
+
+ switch (e_dev->id & ~0xF) {
+ case EISA_DEVICE_ID_ADVANSYS_750:
+ adv_b = adv_alloc(unit, I386_BUS_SPACE_IO,
+ iospace->addr + ADV_EISA_OFFSET_CHAN2);
+ if (adv_b == NULL)
+ return (-1);
+
+ /*
+ * Allocate a parent dmatag for all tags created
+ * by the MI portions of the advansys driver
+ */
+ /* XXX Should be a child of the PCI bus dma tag */
+ error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/0,
+ /*boundary*/0,
+ /*lowaddr*/ADV_EISA_MAX_DMA_ADDR,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
+ /*nsegments*/BUS_SPACE_UNRESTRICTED,
+ /*maxsegsz*/ADV_EISA_MAX_DMA_COUNT,
+ /*flags*/0,
+ &adv_b->parent_dmat);
+
+ if (error != 0) {
+ printf("%s: Could not allocate DMA tag - error %d\n",
+ adv_name(adv_b), error);
+ adv_free(adv_b);
+ return (-1);
+ }
+
+ adv_b->init_level++;
+
+ /* FALLTHROUGH */
+ case EISA_DEVICE_ID_ADVANSYS_740:
+ adv = adv_alloc(unit, I386_BUS_SPACE_IO,
+ iospace->addr + ADV_EISA_OFFSET_CHAN1);
+ if (adv == NULL) {
+ if (adv_b != NULL)
+ adv_free(adv_b);
+ return (-1);
+ }
+
+ /*
+ * Allocate a parent dmatag for all tags created
+ * by the MI portions of the advansys driver
+ */
+ /* XXX Should be a child of the PCI bus dma tag */
+ error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/0,
+ /*boundary*/0,
+ /*lowaddr*/ADV_EISA_MAX_DMA_ADDR,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
+ /*nsegments*/BUS_SPACE_UNRESTRICTED,
+ /*maxsegsz*/ADV_EISA_MAX_DMA_COUNT,
+ /*flags*/0,
+ &adv->parent_dmat);
+
+ if (error != 0) {
+ printf("%s: Could not allocate DMA tag - error %d\n",
+ adv_name(adv), error);
+ adv_free(adv);
+ return (-1);
+ }
+
+ adv->init_level++;
+ break;
+ default:
+ printf("adveisaattach: Unknown device type!\n");
+ return (-1);
+ break;
+ }
+
+ if (overrun_buf == NULL) {
+ /* Need to allocate our overrun buffer */
+ if (bus_dma_tag_create(adv->parent_dmat,
+ /*alignment*/8,
+ /*boundary*/0,
+ ADV_EISA_MAX_DMA_ADDR,
+ BUS_SPACE_MAXADDR,
+ /*filter*/NULL,
+ /*filterarg*/NULL,
+ ADV_OVERRUN_BSIZE,
+ /*nsegments*/1,
+ BUS_SPACE_MAXSIZE_32BIT,
+ /*flags*/0,
+ &overrun_dmat) != 0) {
+ adv_free(adv);
+ return (-1);
+ }
+ if (bus_dmamem_alloc(overrun_dmat,
+ (void **)&overrun_buf,
+ BUS_DMA_NOWAIT,
+ &overrun_dmamap) != 0) {
+ bus_dma_tag_destroy(overrun_dmat);
+ adv_free(adv);
+ return (-1);
+ }
+ /* And permanently map it in */
+ bus_dmamap_load(overrun_dmat, overrun_dmamap,
+ overrun_buf, ADV_OVERRUN_BSIZE,
+ adv_map, &overrun_physbase,
+ /*flags*/0);
+ }
+
+ eisa_reg_start(e_dev);
+ if (eisa_reg_iospace(e_dev, iospace)) {
+ adv_free(adv);
+ if (adv_b != NULL)
+ adv_free(adv_b);
+ return (-1);
+ }
+
+ if (eisa_reg_intr(e_dev, irq, adv_intr, (void *)adv, &cam_imask,
+ /*shared ==*/TRUE)) {
+ adv_free(adv);
+ if (adv_b != NULL)
+ adv_free(adv_b);
+ return (-1);
+ }
+ eisa_reg_end(e_dev);
+
+ /*
+ * Now that we know we own the resources we need, do the
+ * card initialization.
+ */
+
+ /*
+ * Stop the chip.
+ */
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
+ ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
+
+ adv->chip_version = EISA_REVISION_ID(e_dev->id)
+ + ADV_CHIP_MIN_VER_EISA - 1;
+
+ if (adv_init(adv) != 0) {
+ adv_free(adv);
+ if (adv_b != NULL)
+ adv_free(adv_b);
+ return(-1);
+ }
+
+ adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
+ adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
+
+ if (adv_b != NULL) {
+ /*
+ * Stop the chip.
+ */
+ ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT);
+ ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0);
+
+ adv_b->chip_version = EISA_REVISION_ID(e_dev->id)
+ + ADV_CHIP_MIN_VER_EISA - 1;
+
+ if (adv_init(adv_b) != 0) {
+ adv_free(adv_b);
+ } else {
+ adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
+ adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
+ }
+ }
+
+ /*
+ * Enable our interrupt handler.
+ */
+ if (eisa_enable_intr(e_dev, irq)) {
+ adv_free(adv);
+ if (adv_b != NULL)
+ adv_free(adv_b);
+ eisa_release_intr(e_dev, irq, adv_intr);
+ return (-1);
+ }
+
+ /* Attach sub-devices - always succeeds */
+ adv_attach(adv);
+ if (adv_b != NULL)
+ adv_attach(adv_b);
+
+ return 0;
+}
+
+#endif /* NEISA > 0 */
OpenPOWER on IntegriCloud