summaryrefslogtreecommitdiff
path: root/sys/dev/eisa
diff options
context:
space:
mode:
authorad <ad@NetBSD.org>2001-05-06 19:54:59 +0000
committerad <ad@NetBSD.org>2001-05-06 19:54:59 +0000
commitae9cc4fa8a0b13779e87ce755bf147ea4893f5de (patch)
treee9003546f40ee6da8360f605217e89db49a975ca /sys/dev/eisa
parent95450fbced9ad7795ce877a0abd12b2d70f7b9df (diff)
Add an (untested) EISA front-end for the `mlx' driver.
Diffstat (limited to 'sys/dev/eisa')
-rw-r--r--sys/dev/eisa/files.eisa6
-rw-r--r--sys/dev/eisa/mlx_eisa.c340
2 files changed, 345 insertions, 1 deletions
diff --git a/sys/dev/eisa/files.eisa b/sys/dev/eisa/files.eisa
index c0506c07939..319e15f68c3 100644
--- a/sys/dev/eisa/files.eisa
+++ b/sys/dev/eisa/files.eisa
@@ -1,4 +1,4 @@
-# $NetBSD: files.eisa,v 1.23 2001/02/24 02:13:32 lukem Exp $
+# $NetBSD: files.eisa,v 1.24 2001/05/06 19:54:59 ad Exp $
#
# Config file and device description for machine-independent EISA code.
# Included by ports that need it. Requires that the SCSI files be
@@ -51,3 +51,7 @@ file dev/eisa/if_tlp_eisa.c tlp_eisa
device fea: pdq, fddi, ifnet, arp
attach fea at eisa
file dev/eisa/if_fea.c fea
+
+# Mylex RAID controllers
+attach mlx at eisa with mlx_eisa
+file dev/eisa/mlx_eisa.c mlx_eisa
diff --git a/sys/dev/eisa/mlx_eisa.c b/sys/dev/eisa/mlx_eisa.c
new file mode 100644
index 00000000000..7b441dc015d
--- /dev/null
+++ b/sys/dev/eisa/mlx_eisa.c
@@ -0,0 +1,340 @@
+/* $NetBSD: mlx_eisa.c,v 1.1 2001/05/06 19:55:00 ad Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * EISA front-end for mlx(4) driver.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/eisa/eisavar.h>
+#include <dev/eisa/eisadevs.h>
+
+#include <dev/ic/mlxreg.h>
+#include <dev/ic/mlxio.h>
+#include <dev/ic/mlxvar.h>
+
+#define MLX_EISA_SLOT_OFFSET 0x0c89
+#define MLX_EISA_IOSIZE (0x0ce0 - MLX_EISA_SLOT_OFFSET)
+#define MLX_EISA_IOCONF1 0x0cc1
+#define MLX_EISA_IOCONF2 0x0cc3
+
+static void mlx_eisa_attach(struct device *, struct device *, void *);
+static int mlx_eisa_match(struct device *, struct cfdata *, void *);
+
+static int mlx_v1_submit(struct mlx_softc *, struct mlx_ccb *);
+static int mlx_v1_findcomplete(struct mlx_softc *, u_int *, u_int *);
+static void mlx_v1_intaction(struct mlx_softc *, int);
+static int mlx_v1_fw_handshake(struct mlx_softc *, int *, int *, int *);
+#ifdef MLX_RESET
+static int mlx_v1_reset(struct mlx_softc *);
+#endif
+
+struct cfattach mlx_eisa_ca = {
+ sizeof(struct mlx_softc), mlx_eisa_match, mlx_eisa_attach
+};
+
+static const char * const mlx_eisa_prod[] = {
+ "MLX0070",
+ "MLX0071",
+ "MLX0072",
+ "MLX0073",
+ "MLX0074",
+ "MLX0075",
+ "MLX0076",
+ "MLX0077",
+};
+
+static int
+mlx_eisa_match(struct device *parent, struct cfdata *match, void *aux)
+{
+ struct eisa_attach_args *ea;
+ int i;
+
+ ea = aux;
+
+ for (i = 0; i < sizeof(mlx_eisa_prod) / sizeof(mlx_eisa_prod[0]); i++)
+ if (strcmp(ea->ea_idstring, mlx_eisa_prod[i]) == 0)
+ return (1);
+
+ return (0);
+}
+
+static void
+mlx_eisa_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct eisa_attach_args *ea;
+ bus_space_handle_t ioh;
+ eisa_chipset_tag_t ec;
+ eisa_intr_handle_t ih;
+ struct mlx_softc *mlx;
+ bus_space_tag_t iot;
+ const char *intrstr;
+ int irq, le;
+
+ ea = aux;
+ mlx = (struct mlx_softc *)self;
+ iot = ea->ea_iot;
+ ec = ea->ea_ec;
+
+ if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
+ MLX_EISA_SLOT_OFFSET, MLX_EISA_IOSIZE, 0, &ioh)) {
+ printf("can't map i/o space\n");
+ return;
+ }
+
+ mlx->mlx_iot = iot;
+ mlx->mlx_ioh = ioh;
+ mlx->mlx_dmat = ea->ea_dmat;
+
+ /*
+ * Map and establish the interrupt.
+ */
+ switch (bus_space_read_1(iot, ioh, MLX_EISA_IOCONF1) & 0xf0) {
+ case 0xa0:
+ irq = 11;
+ break;
+ case 0xc0:
+ irq = 12;
+ break;
+ case 0xe0:
+ irq = 14;
+ break;
+ case 0x80:
+ irq = 15;
+ break;
+ default:
+ printf("controller on invalid IRQ\n");
+ return;
+ }
+
+ if (eisa_intr_map(ec, irq, &ih)) {
+ printf("can't map interrupt (%d)\n", irq);
+ return;
+ }
+
+ if ((bus_space_read_1(iot, ioh, MLX_EISA_IOCONF1) & 0x08) != 0)
+ le = IST_LEVEL;
+ else
+ le = IST_EDGE;
+
+ intrstr = eisa_intr_string(ec, ih);
+ mlx->mlx_ih = eisa_intr_establish(ec, ih, le, IPL_BIO, mlx_intr, mlx);
+ if (mlx->mlx_ih == NULL) {
+ printf("can't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+
+ mlx->mlx_flags = MLXF_EISA;
+
+ mlx->mlx_submit = mlx_v1_submit;
+ mlx->mlx_findcomplete = mlx_v1_findcomplete;
+ mlx->mlx_intaction = mlx_v1_intaction;
+ mlx->mlx_fw_handshake = mlx_v1_fw_handshake;
+#ifdef MLX_RESET
+ mlx->mlx_reset = mlx_v1_reset;
+#endif
+
+ mlx_init(mlx, intrstr);
+}
+
+/*
+ * ================= V1 interface linkage =================
+ */
+
+/*
+ * Try to give (mc) to the controller. Returns 1 if successful, 0 on
+ * failure (the controller is not ready to take a command).
+ *
+ * Must be called at splbio or in a fashion that prevents reentry.
+ */
+static int
+mlx_v1_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
+{
+
+ /* Ready for our command? */
+ if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_FULL) == 0) {
+ /* Copy mailbox data to window. */
+ bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
+ MLX_V1REG_MAILBOX, mc->mc_mbox, MLX_V1_MAILBOX_LEN);
+ bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
+ MLX_V1REG_MAILBOX, MLX_V1_MAILBOX_LEN,
+ BUS_SPACE_BARRIER_WRITE);
+
+ /* Post command. */
+ mlx_outb(mlx, MLX_V1REG_IDB, MLX_V3_IDB_FULL);
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * See if a command has been completed, if so acknowledge its completion and
+ * recover the slot number and status code.
+ *
+ * Must be called at splbio or in a fashion that prevents reentry.
+ */
+static int
+mlx_v1_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
+{
+
+ /* Status available? */
+ if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) {
+ *slot = mlx_inb(mlx, MLX_V1REG_MAILBOX + 0x0d);
+ *status = mlx_inw(mlx, MLX_V1REG_MAILBOX + 0x0e);
+
+ /* Acknowledge completion. */
+ mlx_outb(mlx, MLX_V1REG_ODB, MLX_V1_ODB_SAVAIL);
+ mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Enable/disable interrupts as requested. (No acknowledge required)
+ *
+ * Must be called at splbio or in a fashion that prevents reentry.
+ */
+static void
+mlx_v1_intaction(struct mlx_softc *mlx, int action)
+{
+
+ mlx_outb(mlx, MLX_V1REG_IE, action ? 1 : 0);
+}
+
+/*
+ * Poll for firmware error codes during controller initialisation.
+ *
+ * Returns 0 if initialisation is complete, 1 if still in progress but no
+ * error has been fetched, 2 if an error has been retrieved.
+ */
+static int
+mlx_v1_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
+{
+ u_int8_t fwerror;
+
+ /*
+ * First time around, enable the IDB interrupt and clear any
+ * hardware completion status.
+ */
+ if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
+ mlx_outb(mlx, MLX_V1REG_ODB_EN, 1);
+ DELAY(1000);
+ mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
+ DELAY(1000);
+ mlx->mlx_flags |= MLXF_FW_INITTED;
+ }
+
+ /* Init in progress? */
+ if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_INIT_BUSY) == 0)
+ return (0);
+
+ /* Test error value. */
+ fwerror = mlx_inb(mlx, MLX_V1REG_ODB);
+
+ if ((fwerror & MLX_V1_FWERROR_PEND) == 0)
+ return (1);
+
+ /* XXX Fetch status. */
+ *error = fwerror & 0xf0;
+ *param1 = -1;
+ *param2 = -1;
+
+ /* Acknowledge. */
+ mlx_outb(mlx, MLX_V1REG_ODB, fwerror);
+
+ return (2);
+}
+
+#ifdef MLX_RESET
+/*
+ * Reset the controller. Return non-zero on failure.
+ */
+static int
+mlx_v1_reset(struct mlx_softc *mlx)
+{
+ int i;
+
+ mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
+ delay(1000000);
+
+ /* Wait up to 2 minutes for the bit to clear. */
+ for (i = 120; i != 0; i--) {
+ delay(1000000);
+ if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_SACK) == 0)
+ break;
+ }
+ if (i == 0)
+ return (-1);
+
+ mlx_outb(mlx, MLX_V1REG_ODB, MLX_V1_ODB_RESET);
+ mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_RESET);
+
+ /* Wait up to 5 seconds for the bit to clear... */
+ for (i = 5; i != 0; i--) {
+ delay(1000000);
+ if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_RESET) == 0)
+ break;
+ }
+ if (i == 0)
+ return (-1);
+
+ /* Wait up to 3 seconds for the other bit to clear... */
+ for (i = 5; i != 0; i--) {
+ delay(1000000);
+ if ((mlx_inb(mlx, MLX_V1REG_ODB) & MLX_V1_ODB_RESET) == 0)
+ break;
+ }
+ if (i == 0)
+ return (-1);
+
+ return (0);
+}
+#endif /* MLX_RESET */