summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2006-05-27 19:03:56 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2006-05-27 19:03:56 +0000
commit679f4cf78cfbf28255564c11aefa46d6eba43c9c (patch)
treeb68d832bccbece8a4182463afaa3b8522f92724b /sys
parent560ca4733ed4d59254c35ab5320b725ee4cc3ff7 (diff)
add mpi(4), an alternative (replacement) driver for lsi logic fusion mpt
controllers currently supported by mpt(4). ok marco@
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/ic/mpi.c1509
-rw-r--r--sys/dev/ic/mpireg.h694
-rw-r--r--sys/dev/ic/mpivar.h93
-rw-r--r--sys/dev/pci/files.pci6
-rw-r--r--sys/dev/pci/mpi_pci.c168
6 files changed, 2474 insertions, 2 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 2dac313a655..fe9364e4012 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.371 2006/05/27 14:18:01 miod Exp $
+# $OpenBSD: files,v 1.372 2006/05/27 19:03:55 dlg Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -188,6 +188,10 @@ file dev/ic/mpt.c mpt
file dev/ic/mpt_debug.c mpt
file dev/ic/mpt_openbsd.c mpt
+# LSI Logic Fusion-MPT Message Passing Interface
+device mpi: scsi
+file dev/ic/mpi.c mpi
+
# UltraStor SCSI controllers
device uha: scsi
file dev/ic/uha.c uha
diff --git a/sys/dev/ic/mpi.c b/sys/dev/ic/mpi.c
new file mode 100644
index 00000000000..cda1b2c374e
--- /dev/null
+++ b/sys/dev/ic/mpi.c
@@ -0,0 +1,1509 @@
+/* $OpenBSD: mpi.c,v 1.1 2006/05/27 19:03:55 dlg Exp $ */
+
+/*
+ * Copyright (c) 2005, 2006 David Gwynne <dlg@openbsd.org>
+ * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+
+#include <machine/bus.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/mpireg.h>
+#include <dev/ic/mpivar.h>
+
+#define MPI_DEBUG
+
+#ifdef MPI_DEBUG
+#define DPRINTF(x...) do { if (mpidebug) printf(x); } while (0)
+#define DPRINTFN(n, x...) do { if (mpidebug > (n)) printf(x); } while (0)
+int mpidebug = 0;
+#else
+#define DPRINTF(x...) /* x */
+#define DPRINTFN(n, x...) /* n, x */
+#endif
+
+struct cfdriver mpi_cd = {
+ NULL, "mpi", DV_DULL
+};
+
+int mpi_scsi_cmd(struct scsi_xfer *);
+void mpi_scsi_cmd_done(struct mpi_ccb *, void *, paddr_t);
+void mpi_minphys(struct buf *bp);
+int mpi_scsi_ioctl(struct scsi_link *, u_long, caddr_t,
+ int, struct proc *);
+
+struct scsi_adapter mpi_switch = {
+ mpi_scsi_cmd, mpi_minphys, NULL, NULL, mpi_scsi_ioctl
+};
+
+struct scsi_device mpi_dev = {
+ NULL, NULL, NULL, NULL
+};
+
+struct mpi_dmamem *mpi_dmamem_alloc(struct mpi_softc *, size_t);
+void mpi_dmamem_free(struct mpi_softc *,
+ struct mpi_dmamem *);
+int mpi_alloc_ccbs(struct mpi_softc *);
+struct mpi_ccb *mpi_get_ccb(struct mpi_softc *);
+void mpi_put_ccb(struct mpi_softc *, struct mpi_ccb *);
+int mpi_alloc_replies(struct mpi_softc *);
+
+void mpi_start(struct mpi_softc *, struct mpi_ccb *);
+void mpi_complete(struct mpi_softc *, struct mpi_ccb *);
+void mpi_timeout_xs(void *);
+int mpi_load_xs(struct mpi_ccb *);
+
+u_int32_t mpi_read(struct mpi_softc *, bus_size_t);
+void mpi_write(struct mpi_softc *, bus_size_t, u_int32_t);
+int mpi_wait_eq(struct mpi_softc *, bus_size_t, u_int32_t,
+ u_int32_t);
+int mpi_wait_ne(struct mpi_softc *, bus_size_t, u_int32_t,
+ u_int32_t);
+
+int mpi_init(struct mpi_softc *);
+int mpi_reset_soft(struct mpi_softc *);
+int mpi_reset_hard(struct mpi_softc *);
+
+int mpi_handshake_send(struct mpi_softc *, void *, size_t);
+int mpi_handshake_recv_dword(struct mpi_softc *,
+ u_int32_t *);
+int mpi_handshake_recv(struct mpi_softc *, void *, size_t);
+
+int mpi_iocinit(struct mpi_softc *);
+int mpi_iocfacts(struct mpi_softc *);
+int mpi_portfacts(struct mpi_softc *);
+void mpi_portfacts_done(struct mpi_ccb *, void *, paddr_t);
+int mpi_oportfacts(struct mpi_softc *);
+int mpi_eventnotify(struct mpi_softc *);
+void mpi_eventnotify_done(struct mpi_ccb *, void *, paddr_t);
+int mpi_portenable(struct mpi_softc *);
+void mpi_portenable_done(struct mpi_ccb *, void *, paddr_t);
+
+#define DEVNAME(s) ((s)->sc_dev.dv_xname)
+
+#define dwordsof(s) (sizeof(s) / sizeof(u_int32_t))
+#define sizeofa(s) (sizeof(s) / sizeof((s)[0]))
+
+#define mpi_read_db(s) mpi_read((s), MPI_DOORBELL)
+#define mpi_write_db(s, v) mpi_write((s), MPI_DOORBELL, (v))
+#define mpi_read_intr(s) mpi_read((s), MPI_INTR_STATUS)
+#define mpi_write_intr(s, v) mpi_write((s), MPI_INTR_STATUS, (v))
+#define mpi_pop_reply(s) mpi_read((s), MPI_REPLY_QUEUE)
+#define mpi_push_reply(s, v) mpi_write((s), MPI_REPLY_QUEUE, (v))
+
+#define mpi_wait_db_int(s) mpi_wait_ne((s), MPI_INTR_STATUS, \
+ MPI_INTR_STATUS_DOORBELL, 0)
+#define mpi_wait_db_ack(s) mpi_wait_eq((s), MPI_INTR_STATUS, \
+ MPI_INTR_STATUS_IOCDOORBELL, 0)
+
+
+
+int
+mpi_attach(struct mpi_softc *sc)
+{
+ struct mpi_ccb *ccb;
+
+ printf("\n");
+
+ /* disable interrupts */
+ mpi_write(sc, MPI_INTR_MASK,
+ MPI_INTR_MASK_REPLY | MPI_INTR_MASK_DOORBELL);
+
+ if (mpi_init(sc) != 0) {
+ printf("%s: unable to initialise\n", DEVNAME(sc));
+ return (1);
+ }
+
+ if (mpi_iocfacts(sc) != 0) {
+ printf("%s: unable to get iocfacts\n", DEVNAME(sc));
+ return (1);
+ }
+
+ if (mpi_alloc_ccbs(sc) != 0) {
+ /* error already printed */
+ return (1);
+ }
+
+ if (mpi_iocinit(sc) != 0) {
+ printf("%s: unable to send iocinit\n", DEVNAME(sc));
+ goto free_ccbs;
+ }
+
+ /* spin until we're operational */
+ if (mpi_wait_eq(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
+ MPI_DOORBELL_STATE_OPER) != 0) {
+ printf("%s: state: 0x%08x\n", DEVNAME(sc),
+ mpi_read_db(sc) & MPI_DOORBELL_STATE);
+ printf("%s: operational state timeout\n", DEVNAME(sc));
+ goto free_ccbs;
+ }
+
+ if (mpi_alloc_replies(sc) != 0) {
+ /* error already printed */
+ goto free_ccbs;
+ }
+
+ if (mpi_portfacts(sc) != 0) {
+ printf("%s: unable to get portfacts\n", DEVNAME(sc));
+ goto free_replies;
+ }
+
+#if notyet
+ if (mpi_eventnotify(sc) != 0) {
+ printf("%s: unable to get portfacts\n", DEVNAME(sc));
+ goto free_replies;
+ }
+#endif
+
+ if (mpi_portenable(sc) != 0) {
+ printf("%s: unable to enable port\n", DEVNAME(sc));
+ goto free_replies;
+ }
+
+ /* we should be good to go now, attach scsibus */
+ sc->sc_link.device = &mpi_dev;
+ sc->sc_link.adapter = &mpi_switch;
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = sc->sc_target;
+ sc->sc_link.adapter_buswidth = sc->sc_buswidth;
+ sc->sc_link.openings = sc->sc_maxcmds / sc->sc_buswidth;
+
+ config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
+
+ /* XXX enable interrupts */
+ mpi_write(sc, MPI_INTR_MASK, MPI_INTR_MASK_DOORBELL);
+
+ return (0);
+
+free_replies:
+ bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_replies),
+ 0, PAGE_SIZE, BUS_DMASYNC_POSTREAD);
+ mpi_dmamem_free(sc, sc->sc_replies);
+free_ccbs:
+ while ((ccb = mpi_get_ccb(sc)) != NULL)
+ bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
+ mpi_dmamem_free(sc, sc->sc_requests);
+ free(sc->sc_ccbs, M_DEVBUF);
+
+ return(1);
+}
+
+void
+mpi_detach(struct mpi_softc *sc)
+{
+
+}
+
+int
+mpi_intr(void *arg)
+{
+ struct mpi_softc *sc = arg;
+ struct mpi_ccb *ccb;
+ struct mpi_msg_reply *reply = NULL;
+ paddr_t reply_dva;
+ char *reply_addr;
+ u_int32_t reg, id;
+ int rv = 0;
+
+ while ((reg = mpi_pop_reply(sc)) != 0xffffffff) {
+
+ DPRINTF("%s: %s reply_queue: 0x%08x\n", DEVNAME(sc), __func__,
+ reg);
+
+ if (reg & MPI_REPLY_QUEUE_ADDRESS) {
+ bus_dmamap_sync(sc->sc_dmat,
+ MPI_DMA_MAP(sc->sc_replies), 0, PAGE_SIZE,
+ BUS_DMASYNC_POSTREAD);
+
+ reply_dva = (reg & MPI_REPLY_QUEUE_ADDRESS_MASK) << 1;
+
+ reply_addr = MPI_DMA_KVA(sc->sc_replies) +
+ (reply_dva - MPI_DMA_DVA(sc->sc_replies));
+ reply = (struct mpi_msg_reply *)reply_addr;
+
+ id = letoh32(reply->msg_context);
+
+ bus_dmamap_sync(sc->sc_dmat,
+ MPI_DMA_MAP(sc->sc_replies), 0, PAGE_SIZE,
+ BUS_DMASYNC_PREREAD);
+ } else {
+ switch (reg & MPI_REPLY_QUEUE_TYPE_MASK) {
+ case MPI_REPLY_QUEUE_TYPE_INIT:
+ id = reg & MPI_REPLY_QUEUE_CONTEXT;
+ break;
+
+ default:
+ panic("%s: unsupported context reply\n",
+ DEVNAME(sc));
+ }
+ }
+
+ DPRINTF("%s: %s id: %d\n", DEVNAME(sc), __func__, id);
+
+ ccb = &sc->sc_ccbs[id];
+
+ bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_requests),
+ ccb->ccb_offset, MPI_REQUEST_SIZE, BUS_DMASYNC_POSTWRITE);
+
+ ccb->ccb_done(ccb, reply, reply_dva);
+ rv = 1;
+ }
+
+ return (rv);
+}
+
+struct mpi_dmamem *
+mpi_dmamem_alloc(struct mpi_softc *sc, size_t size)
+{
+ struct mpi_dmamem *mdm;
+ int nsegs;
+
+ mdm = malloc(sizeof(struct mpi_dmamem), M_DEVBUF, M_NOWAIT);
+ if (mdm == NULL)
+ return (NULL);
+
+ bzero(mdm, sizeof(struct mpi_dmamem));
+ mdm->mdm_size = size;
+
+ if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
+ BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mdm->mdm_map) != 0)
+ goto mdmfree;
+
+ if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mdm->mdm_seg,
+ 1, &nsegs, BUS_DMA_NOWAIT) != 0)
+ goto destroy;
+
+ if (bus_dmamem_map(sc->sc_dmat, &mdm->mdm_seg, nsegs, size,
+ &mdm->mdm_kva, BUS_DMA_NOWAIT) != 0)
+ goto free;
+
+ if (bus_dmamap_load(sc->sc_dmat, mdm->mdm_map, mdm->mdm_kva, size,
+ NULL, BUS_DMA_NOWAIT) != 0)
+ goto unmap;
+
+ bzero(mdm->mdm_kva, size);
+ return (mdm);
+
+unmap:
+ bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, size);
+free:
+ bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
+destroy:
+ bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
+mdmfree:
+ free(mdm, M_DEVBUF);
+
+ return (NULL);
+}
+
+void
+mpi_dmamem_free(struct mpi_softc *sc, struct mpi_dmamem *mdm)
+{
+ bus_dmamap_unload(sc->sc_dmat, mdm->mdm_map);
+ bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, mdm->mdm_size);
+ bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
+ bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
+ free(mdm, M_DEVBUF);
+}
+
+int
+mpi_alloc_ccbs(struct mpi_softc *sc)
+{
+ struct mpi_ccb *ccb;
+ u_int8_t *cmd;
+ int i;
+
+ TAILQ_INIT(&sc->sc_ccb_free);
+ TAILQ_INIT(&sc->sc_ccb_runq);
+
+ sc->sc_ccbs = malloc(sizeof(struct mpi_ccb) * sc->sc_maxcmds,
+ M_DEVBUF, M_WAITOK);
+ if (sc->sc_ccbs == NULL) {
+ printf("%s: unable to allocate ccbs\n", DEVNAME(sc));
+ return (1);
+ }
+ bzero(sc->sc_ccbs, sizeof(struct mpi_ccb) * sc->sc_maxcmds);
+
+ sc->sc_requests = mpi_dmamem_alloc(sc,
+ MPI_REQUEST_SIZE * sc->sc_maxcmds);
+ if (sc->sc_requests == NULL) {
+ printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc));
+ goto free_ccbs;
+ }
+ cmd = MPI_DMA_KVA(sc->sc_requests);
+ bzero(cmd, MPI_REQUEST_SIZE * sc->sc_maxcmds);
+
+ for (i = 0; i < sc->sc_maxcmds; i++) {
+ ccb = &sc->sc_ccbs[i];
+
+ if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, MPI_MAX_SGL,
+ MAXPHYS, 0, 0, &ccb->ccb_dmamap) != 0) {
+ printf("%s: unable to create dma map\n", DEVNAME(sc));
+ goto free_maps;
+ }
+
+ ccb->ccb_sc = sc;
+ ccb->ccb_id = i;
+ ccb->ccb_offset = MPI_REQUEST_SIZE * i;
+
+ ccb->ccb_cmd = &cmd[ccb->ccb_offset];
+ ccb->ccb_cmd_dva = MPI_DMA_DVA(sc->sc_requests) +
+ ccb->ccb_offset;
+
+ mpi_put_ccb(sc, ccb);
+ }
+
+ return (0);
+
+free_maps:
+ while ((ccb = mpi_get_ccb(sc)) != NULL)
+ bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
+
+ mpi_dmamem_free(sc, sc->sc_requests);
+free_ccbs:
+ free(sc->sc_ccbs, M_DEVBUF);
+
+ return (1);
+}
+
+struct mpi_ccb *
+mpi_get_ccb(struct mpi_softc *sc)
+{
+ struct mpi_ccb *ccb;
+
+ ccb = TAILQ_FIRST(&sc->sc_ccb_free);
+ if (ccb == NULL)
+ return (NULL);
+
+ TAILQ_REMOVE(&sc->sc_ccb_free, ccb, ccb_link);
+
+ DPRINTFN(10, "%s: %s: ccb_id: %d\n", DEVNAME(sc), __func__,
+ ccb->ccb_id);
+
+ return (ccb);
+}
+
+void
+mpi_put_ccb(struct mpi_softc *sc, struct mpi_ccb *ccb)
+{
+ DPRINTFN(10, "%s: %s: ccb_id: %d\n", DEVNAME(sc), __func__,
+ ccb->ccb_id);
+
+ ccb->ccb_state = MPI_CCB_FREE;
+ ccb->ccb_xs = NULL;
+ ccb->ccb_done = NULL;
+ bzero(ccb->ccb_cmd, MPI_REQUEST_SIZE);
+ TAILQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_link);
+}
+
+int
+mpi_alloc_replies(struct mpi_softc *sc)
+{
+ paddr_t reply;
+ int i;
+
+ sc->sc_replies = mpi_dmamem_alloc(sc, PAGE_SIZE);
+ if (sc->sc_replies == NULL) {
+ printf("%s: unable to allocate replies\n", DEVNAME(sc));
+ return (1);
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_replies),
+ 0, PAGE_SIZE, BUS_DMASYNC_PREREAD);
+
+ for (i = 0; i < PAGE_SIZE / MPI_REPLY_SIZE; i++) {
+ reply = MPI_DMA_DVA(sc->sc_replies) + MPI_REPLY_SIZE * i;
+ mpi_push_reply(sc, reply);
+ }
+
+ return (0);
+}
+
+void
+mpi_start(struct mpi_softc *sc, struct mpi_ccb *ccb)
+{
+ bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_requests),
+ ccb->ccb_offset, MPI_REQUEST_SIZE, BUS_DMASYNC_PREWRITE);
+
+ ccb->ccb_state = MPI_CCB_QUEUED;
+ TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
+ mpi_write(sc, MPI_REQ_QUEUE, ccb->ccb_cmd_dva);
+}
+
+void
+mpi_complete(struct mpi_softc *sc, struct mpi_ccb *nccb)
+{
+ struct mpi_ccb *ccb;
+ struct mpi_msg_reply *reply = NULL;
+ paddr_t reply_dva;
+ char *reply_addr;
+ u_int32_t reg, id;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ do {
+ reg = mpi_pop_reply(sc);
+ if (reg == 0xffffffff) {
+ delay(1000);
+ continue;
+ }
+
+ DPRINTF("%s: %s reply_queue: 0x%08x\n", DEVNAME(sc), __func__,
+ reg);
+
+ if (reg & MPI_REPLY_QUEUE_ADDRESS) {
+ bus_dmamap_sync(sc->sc_dmat,
+ MPI_DMA_MAP(sc->sc_replies), 0, PAGE_SIZE,
+ BUS_DMASYNC_POSTREAD);
+
+ reply_dva = (reg & MPI_REPLY_QUEUE_ADDRESS_MASK) << 1;
+
+ reply_addr = MPI_DMA_KVA(sc->sc_replies) +
+ (reply_dva - MPI_DMA_DVA(sc->sc_replies));
+ reply = (struct mpi_msg_reply *)reply_addr;
+
+ id = letoh32(reply->msg_context);
+
+ bus_dmamap_sync(sc->sc_dmat,
+ MPI_DMA_MAP(sc->sc_replies), 0, PAGE_SIZE,
+ BUS_DMASYNC_PREREAD);
+ } else {
+ switch (reg & MPI_REPLY_QUEUE_TYPE_MASK) {
+ case MPI_REPLY_QUEUE_TYPE_INIT:
+ id = reg & MPI_REPLY_QUEUE_CONTEXT;
+ break;
+
+ default:
+ panic("%s: unsupported context reply\n",
+ DEVNAME(sc));
+ }
+ }
+
+ DPRINTF("%s: %s id: %d\n", DEVNAME(sc), __func__, id);
+
+ ccb = &sc->sc_ccbs[id];
+
+ bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_requests),
+ ccb->ccb_offset, MPI_REQUEST_SIZE, BUS_DMASYNC_POSTWRITE);
+
+ ccb->ccb_done(ccb, reply, reply_dva);
+
+ } while (nccb->ccb_id != id);
+}
+
+int
+mpi_scsi_cmd(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct mpi_softc *sc = link->adapter_softc;
+ struct mpi_ccb *ccb;
+ struct mpi_ccb_bundle *mcb;
+ struct mpi_msg_scsi_io *io;
+ int s;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ if (xs->cmdlen > MPI_CDB_LEN) {
+ DPRINTF("%s: CBD too big %d", DEVNAME(sc), xs->cmdlen);
+ bzero(&xs->sense, sizeof(xs->sense));
+ xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
+ xs->sense.flags = SKEY_ILLEGAL_REQUEST;
+ xs->sense.add_sense_code = 0x20;
+ xs->error = XS_SENSE;
+ scsi_done(xs);
+ return (COMPLETE);
+ }
+
+ s = splbio();
+ ccb = mpi_get_ccb(sc);
+ splx(s);
+ if (ccb == NULL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ return (COMPLETE);
+ }
+ DPRINTF("%s: ccb_id: %d xs->flags: 0x%x\n", DEVNAME(sc), ccb->ccb_id,
+ xs->flags);
+
+ ccb->ccb_xs = xs;
+ ccb->ccb_done = mpi_scsi_cmd_done;
+
+ mcb = ccb->ccb_cmd;
+ io = &mcb->mcb_io;
+
+ io->function = MPI_FUNCTION_SCSI_IO_REQUEST;
+// io->chain_offset = dwordsof(mcb->mcb_io);
+// io->bus = htole16(sc->sc_bus);
+ io->target_id = link->target;
+
+ io->cdb_length = xs->cmdlen;
+ io->sense_buf_len = sizeof(xs->sense);
+
+ io->msg_context = htole32(ccb->ccb_id);
+
+ /* XXX */
+ io->lun[0] = htole16(link->lun);
+
+ switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
+ case SCSI_DATA_IN:
+ io->control = htole32(MPI_SCSIIO_DATA_DIR_READ);
+ break;
+ case SCSI_DATA_OUT:
+ io->control = htole32(MPI_SCSIIO_DATA_DIR_WRITE);
+ break;
+ default:
+ io->control = htole32(MPI_SCSIIO_DATA_DIR_NONE);
+ break;
+ }
+
+ bcopy(xs->cmd, io->cdb, xs->cmdlen);
+
+ io->data_length = htole32(xs->datalen);
+
+ io->sense_buf_low_addr = htole32(ccb->ccb_cmd_dva +
+ ((u_int8_t *)&mcb->mcb_sense - (u_int8_t *)mcb));
+
+ if (mpi_load_xs(ccb) != 0) {
+ s = splbio();
+ mpi_put_ccb(sc, ccb);
+ splx(s);
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ return (COMPLETE);
+ }
+
+ timeout_set(&xs->stimeout, mpi_timeout_xs, ccb);
+
+ if (xs->flags & SCSI_POLL) {
+ s = splbio();
+ mpi_start(sc, ccb);
+ mpi_complete(sc, ccb);
+ splx(s);
+
+ return (COMPLETE);
+ }
+
+ mpi_start(sc, ccb);
+ return (SUCCESSFULLY_QUEUED);
+}
+
+void
+mpi_scsi_cmd_done(struct mpi_ccb *ccb, void *reply, paddr_t reply_dva)
+{
+ struct mpi_softc *sc = ccb->ccb_sc;
+ struct scsi_xfer *xs = ccb->ccb_xs;
+ struct mpi_ccb_bundle *mcb = ccb->ccb_cmd;
+ bus_dmamap_t dmap = ccb->ccb_dmamap;
+ struct mpi_msg_scsi_io_error *sie = reply;
+
+ if (xs->datalen != 0) {
+ bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_unload(sc->sc_dmat, dmap);
+ }
+
+ /* timeout_del */
+ xs->error = XS_NOERROR;
+ xs->resid = 0;
+ xs->flags |= ITSDONE;
+ DPRINTFN(10, "%s: xs cmd: 0x%02x len: %d error: 0x%02x flags 0x%x\n",
+ DEVNAME(sc), xs->cmd->opcode, xs->datalen, xs->error, xs->flags);
+
+ if (sie == NULL) {
+ /* no scsi error, we're ok so drop out early */
+ xs->status = SCSI_OK;
+ mpi_put_ccb(sc, ccb);
+ scsi_done(xs);
+ return;
+ }
+
+#ifdef MPI_DEBUG
+ if (mpidebug > 10) {
+ printf("%s: target_id: %d bus: %d msg_length: %d "
+ "function: 0x%02x\n", DEVNAME(sc), sie->target_id,
+ sie->bus, sie->msg_length, sie->function);
+
+ printf("%s: cdb_length: %d sense_buf_length: %d "
+ "msg_flags: 0x%02x\n", DEVNAME(sc), sie->cdb_length,
+ sie->bus, sie->msg_flags);
+
+ printf("%s: msg_context: 0x%08x\n", DEVNAME(sc),
+ letoh32(sie->msg_context));
+
+ printf("%s: scsi_status: 0x%02x scsi_state: 0x%02x "
+ "ioc_status: 0x%04x\n", DEVNAME(sc), sie->scsi_status,
+ sie->scsi_state, letoh16(sie->ioc_status));
+
+ printf("%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc),
+ letoh32(sie->ioc_loginfo));
+
+ printf("%s: transfer_count: %d\n", DEVNAME(sc),
+ letoh32(sie->transfer_count));
+
+ printf("%s: sense_count: %d\n", DEVNAME(sc),
+ letoh32(sie->sense_count));
+
+ printf("%s: response_info: 0x%08x\n", DEVNAME(sc),
+ letoh32(sie->response_info));
+
+ printf("%s: tag: 0x%04x\n", DEVNAME(sc), letoh16(sie->tag));
+ }
+#endif /* MPI_DEBUG */
+
+
+ xs->status = sie->scsi_status;
+ switch (sie->ioc_status) {
+ case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
+ /*
+ * Yikes! Tagged queue full comes through this path!
+ *
+ * So we'll change it to a status error and anything
+ * that returns status should probably be a status
+ * error as well.
+ */
+ xs->resid = xs->datalen - letoh32(sie->transfer_count);
+ if (sie->scsi_state & MPI_SCSIIO_ERR_STATE_NO_SCSI_STATUS) {
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ /* FALLTHROUGH */
+ case MPI_IOCSTATUS_SUCCESS:
+ case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:
+ switch (xs->status) {
+ case SCSI_OK:
+ xs->resid = 0;
+ break;
+
+ case SCSI_CHECK:
+ xs->error = XS_SENSE;
+ break;
+
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+
+ case SCSI_QUEUE_FULL:
+ xs->error = XS_TIMEOUT;
+ xs->retries++;
+ break;
+ default:
+ printf("%s: invalid status code %d\n", xs->status);
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ break;
+
+ case MPI_IOCSTATUS_BUSY:
+ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
+ xs->error = XS_BUSY;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_INVALID_BUS:
+ case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
+ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+ xs->error = XS_SELTIMEOUT;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+ /* XXX */
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
+ /* XXX */
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
+ /* XXX This is a bus-reset */
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ default:
+ /* XXX unrecognized HBA error */
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ if (sie->scsi_state & MPI_SCSIIO_ERR_STATE_AUTOSENSE_VALID) {
+ bcopy(&mcb->mcb_sense, &xs->sense, sizeof(xs->sense));
+ } else if (sie->scsi_state & MPI_SCSIIO_ERR_STATE_AUTOSENSE_FAILED) {
+ /* This will cause the scsi layer to issue a REQUEST SENSE */
+ if (xs->status == SCSI_CHECK)
+ xs->error = XS_BUSY;
+ }
+
+ DPRINTFN(10, "%s: xs error: 0x%02x len: %d\n", DEVNAME(sc),
+ xs->error, xs->status);
+ mpi_push_reply(sc, reply_dva);
+ mpi_put_ccb(sc, ccb);
+ scsi_done(xs);
+}
+
+void
+mpi_timeout_xs(void *arg)
+{
+ /* XXX */
+}
+
+int
+mpi_load_xs(struct mpi_ccb *ccb)
+{
+ struct mpi_softc *sc = ccb->ccb_sc;
+ struct scsi_xfer *xs = ccb->ccb_xs;
+ struct mpi_ccb_bundle *mcb = ccb->ccb_cmd;
+ struct mpi_sge32 *sge;
+ bus_dmamap_t dmap = ccb->ccb_dmamap;
+ u_int32_t flags;
+ int i, error;
+
+ if (xs->datalen == 0) {
+ sge = &mcb->mcb_sgl[0];
+ sge->sg_hdr = htole32(MPI_SGE_FL_TYPE_SIMPLE |
+ MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL);
+ return (0);
+ }
+
+#if 0
+ error = bus_dmamap_load(sc->sc_dmat, dmap,
+ xs->data, xs->datalen, NULL, BUS_DMA_STREAMING |
+ (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK |
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ : BUS_DMA_WRITE);
+#endif
+ error = bus_dmamap_load(sc->sc_dmat, dmap,
+ xs->data, xs->datalen, NULL,
+ (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
+ if (error) {
+ printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
+ return (1);
+ }
+
+ flags = MPI_SGE_FL_TYPE_SIMPLE;
+ if (xs->flags & SCSI_DATA_OUT)
+ flags |= MPI_SGE_FL_DIR_OUT;
+
+ for (i = 0; i < dmap->dm_nsegs; i++) {
+ sge = &mcb->mcb_sgl[i];
+ sge->sg_hdr = htole32(flags | dmap->dm_segs[i].ds_len);
+ sge->sg_addr = htole32(dmap->dm_segs[i].ds_addr);
+ }
+
+ /* terminate list */
+ sge->sg_hdr |= htole32(MPI_SGE_FL_LAST | MPI_SGE_FL_EOB |
+ MPI_SGE_FL_EOL);
+
+#ifdef MPI_DEBUG
+ if (mpidebug > 11) {
+ for (i = 0; i < dmap->dm_nsegs; i++) {
+ printf("%s: %d: 0x%08x 0x%08x\n", DEVNAME(sc), i,
+ mcb->mcb_sgl[i].sg_hdr, mcb->mcb_sgl[i].sg_addr);
+ }
+ }
+#endif
+
+ bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
+ BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+void
+mpi_minphys(struct buf *bp)
+{
+ /* XXX */
+ if (bp->b_bcount > MAXPHYS)
+ bp->b_bcount = MAXPHYS;
+ minphys(bp);
+}
+
+int
+mpi_scsi_ioctl(struct scsi_link *a, u_long b, caddr_t c, int d, struct proc *e)
+{
+ return (0);
+}
+
+u_int32_t
+mpi_read(struct mpi_softc *sc, bus_size_t r)
+{
+ bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
+ BUS_SPACE_BARRIER_READ);
+ return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
+}
+
+void
+mpi_write(struct mpi_softc *sc, bus_size_t r, u_int32_t v)
+{
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
+ bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
+ BUS_SPACE_BARRIER_WRITE);
+}
+
+int
+mpi_wait_eq(struct mpi_softc *sc, bus_size_t r, u_int32_t mask,
+ u_int32_t target)
+{
+ int i;
+
+ for (i = 0; i < 10000; i++) {
+ if ((mpi_read(sc, r) & mask) == target)
+ return (0);
+ delay(1000);
+ }
+
+ return (1);
+}
+
+int
+mpi_wait_ne(struct mpi_softc *sc, bus_size_t r, u_int32_t mask,
+ u_int32_t target)
+{
+ int i;
+
+ for (i = 0; i < 10000; i++) {
+ if ((mpi_read(sc, r) & mask) != target)
+ return (0);
+ delay(1000);
+ }
+
+ return (1);
+}
+
+int
+mpi_init(struct mpi_softc *sc)
+{
+ u_int32_t db;
+ int i;
+
+ /* spin until the IOC leaves the RESET state */
+ if (mpi_wait_ne(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
+ MPI_DOORBELL_STATE_RESET) != 0) {
+ DPRINTF("%s: %s timeout waiting to leave reset state\n",
+ DEVNAME(sc), __func__);
+ return (1);
+ }
+
+ /* check current ownership */
+ db = mpi_read_db(sc);
+ if ((db & MPI_DOORBELL_WHOINIT) == MPI_DOORBELL_WHOINIT_PCIPEER) {
+ DPRINTF("%s: %s initialised by pci peer\n", DEVNAME(sc),
+ __func__);
+ return (0);
+ }
+
+ for (i = 0; i < 5; i++) {
+ switch (db & MPI_DOORBELL_STATE) {
+ case MPI_DOORBELL_STATE_READY:
+ DPRINTF("%s: %s ioc is ready\n", DEVNAME(sc),
+ __func__);
+ return (0);
+
+ case MPI_DOORBELL_STATE_OPER:
+ case MPI_DOORBELL_STATE_FAULT:
+ DPRINTF("%s: %s ioc is being reset\n", DEVNAME(sc),
+ __func__);
+ if (mpi_reset_soft(sc) != 0)
+ mpi_reset_hard(sc);
+ break;
+
+ case MPI_DOORBELL_STATE_RESET:
+ DPRINTF("%s: %s waiting to come out of reset\n",
+ DEVNAME(sc), __func__);
+ if (mpi_wait_ne(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
+ MPI_DOORBELL_STATE_RESET) != 0)
+ return (1);
+ break;
+ }
+ db = mpi_read_db(sc);
+ }
+
+ return (1);
+}
+
+int
+mpi_reset_soft(struct mpi_softc *sc)
+{
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ if (mpi_read_db(sc) & MPI_DOORBELL_INUSE)
+ return (1);
+
+ mpi_write_db(sc,
+ MPI_DOORBELL_FUNCTION(MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET));
+ if (mpi_wait_eq(sc, MPI_INTR_STATUS,
+ MPI_INTR_STATUS_IOCDOORBELL, 0) != 0)
+ return (1);
+
+ if (mpi_wait_eq(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
+ MPI_DOORBELL_STATE_READY) != 0)
+ return (1);
+
+ return (0);
+}
+
+int
+mpi_reset_hard(struct mpi_softc *sc)
+{
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ /* enable diagnostic register */
+ mpi_write(sc, MPI_WRITESEQ, 0xff);
+ mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_1);
+ mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_2);
+ mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_3);
+ mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_4);
+ mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_5);
+
+ /* reset ioc */
+ mpi_write(sc, MPI_HOSTDIAG, MPI_HOSTDIAG_RESET_ADAPTER);
+
+ delay(10000);
+
+ /* disable diagnostic register */
+ mpi_write(sc, MPI_WRITESEQ, 0xff);
+
+ /* restore pci bits? */
+
+ /* firmware bits? */
+ return (0);
+}
+
+int
+mpi_handshake_send(struct mpi_softc *sc, void *buf, size_t dwords)
+{
+ u_int32_t *query = buf;
+ int i;
+
+ /* make sure the doorbell is not in use. */
+ if (mpi_read_db(sc) & MPI_DOORBELL_INUSE)
+ return (1);
+
+ /* clear pending doorbell interrupts */
+ if (mpi_read_intr(sc) & MPI_INTR_STATUS_DOORBELL)
+ mpi_write_intr(sc, 0);
+
+ /*
+ * first write the doorbell with the handshake function and the
+ * dword count.
+ */
+ mpi_write_db(sc, MPI_DOORBELL_FUNCTION(MPI_FUNCTION_HANDSHAKE) |
+ MPI_DOORBELL_DWORDS(dwords));
+
+ /*
+ * the doorbell used bit will be set because a doorbell function has
+ * started. Wait for the interrupt and then ack it.
+ */
+ if (mpi_wait_db_int(sc) != 0)
+ return (1);
+ mpi_write_intr(sc, 0);
+
+ /* poll for the acknowledgement. */
+ if (mpi_wait_db_ack(sc) != 0)
+ return (1);
+
+ /* write the query through the doorbell. */
+ for (i = 0; i < dwords; i++) {
+ mpi_write_db(sc, htole32(query[i]));
+ if (mpi_wait_db_ack(sc) != 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+mpi_handshake_recv_dword(struct mpi_softc *sc, u_int32_t *dword)
+{
+ u_int16_t *words = (u_int16_t *)dword;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (mpi_wait_db_int(sc) != 0)
+ return (1);
+ words[i] = letoh16(mpi_read_db(sc) & MPI_DOORBELL_DATA_MASK);
+ mpi_write_intr(sc, 0);
+ }
+
+ return (0);
+}
+
+int
+mpi_handshake_recv(struct mpi_softc *sc, void *buf, size_t dwords)
+{
+ struct mpi_msg_reply *reply = buf;
+ u_int32_t *dbuf = buf, dummy;
+ int i;
+
+ /* get the first dword so we can read the length out of the header. */
+ if (mpi_handshake_recv_dword(sc, &dbuf[0]) != 0)
+ return (1);
+
+ DPRINTFN(10, "%s: %s dwords: %d reply: %d\n", DEVNAME(sc), __func__,
+ dwords, reply->msg_length);
+
+ /*
+ * the total length, in dwords, is in the message length field of the
+ * reply header.
+ */
+ for (i = 1; i < MIN(dwords, reply->msg_length); i++) {
+ if (mpi_handshake_recv_dword(sc, &dbuf[i]) != 0)
+ return (1);
+ }
+
+ /* if there's extra stuff to come off the ioc, discard it */
+ while (i++ < reply->msg_length) {
+ if (mpi_handshake_recv_dword(sc, &dummy) != 0)
+ return (1);
+ DPRINTFN(10, "%s: %s dummy read: 0x%08x\n", DEVNAME(sc),
+ __func__, dummy);
+ }
+
+ /* wait for the doorbell used bit to be reset and clear the intr */
+ if (mpi_wait_db_int(sc) != 0)
+ return (1);
+ mpi_write_intr(sc, 0);
+
+ return (0);
+}
+
+int
+mpi_iocfacts(struct mpi_softc *sc)
+{
+ struct mpi_msg_iocfacts_request ifq;
+ struct mpi_msg_iocfacts_reply ifp;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ bzero(&ifq, sizeof(ifq));
+ bzero(&ifp, sizeof(ifp));
+
+ ifq.function = MPI_FUNCTION_IOC_FACTS;
+ ifq.chain_offset = 0;
+ ifq.msg_flags = 0;
+ ifq.msg_context = htole32(0xdeadbeef);
+
+ if (mpi_handshake_send(sc, &ifq, dwordsof(ifq)) != 0) {
+ DPRINTF("%s: %s send failed\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+ if (mpi_handshake_recv(sc, &ifp, dwordsof(ifp)) != 0) {
+ DPRINTF("%s: %s recv failed\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+#ifdef MPI_DEBUG
+ printf("%s: func: 0x%02x len: %d msgver: %d.%d\n",
+ DEVNAME(sc), ifp.function, ifp.msg_length,
+ ifp.msg_version_maj, ifp.msg_version_min);
+
+ printf("%s: msgflags: 0x%02x iocnumber: 0x%02x hdrver: %d.%d\n",
+ DEVNAME(sc), ifp.msg_flags, ifp.ioc_number,
+ ifp.header_version_maj, ifp.header_version_min);
+
+ printf("%s: message context: 0x%08x\n", DEVNAME(sc),
+ letoh32(ifp.msg_context));
+
+ printf("%s: iocstatus: 0x%04x ioexcept: 0x%04x\n", DEVNAME(sc),
+ letoh16(ifp.ioc_status), letoh16(ifp.ioc_exceptions));
+
+ printf("%s: iocloginfo: 0x%08x\n", DEVNAME(sc),
+ letoh32(ifp.ioc_loginfo));
+
+ printf("%s: flags: 0x%02x blocksize: %d whoinit: 0x%02x "
+ "maxchdepth: %d\n", DEVNAME(sc), ifp.flags, ifp.block_size,
+ ifp.whoinit, ifp.max_chain_depth);
+
+ printf("%s: reqfrsize: %d replyqdepth: %d\n", DEVNAME(sc),
+ letoh16(ifp.request_frame_size), letoh16(ifp.reply_queue_depth));
+
+ printf("%s: productid: 0x%04x\n", DEVNAME(sc),
+ letoh16(ifp.product_id));
+
+ printf("%s: hostmfahiaddr: 0x%08x\n", DEVNAME(sc),
+ letoh32(ifp.current_host_mfa_hi_addr));
+
+ printf("%s: event_state: 0x%02x number_of_ports: %d "
+ "global_credits: %d\n",
+ DEVNAME(sc), ifp.event_state, ifp.number_of_ports,
+ letoh16(ifp.global_credits));
+
+ printf("%s: sensebufhiaddr: 0x%08x\n", DEVNAME(sc),
+ letoh32(ifp.current_sense_buffer_hi_addr));
+
+ printf("%s: maxbus: %d maxdev: %d replyfrsize: %d\n", DEVNAME(sc),
+ ifp.max_buses, ifp.max_devices,
+ letoh16(ifp.current_reply_frame_size));
+
+ printf("%s: fw_image_size: %d\n", DEVNAME(sc),
+ letoh32(ifp.fw_image_size));
+
+ printf("%s: ioc_capabilities: 0x%08x\n", DEVNAME(sc),
+ letoh32(ifp.ioc_capabilities));
+
+ printf("%s: fw_version: %d.%d fw_version_unit: 0x%02x "
+ "fw_version_dev: 0x%02x\n", DEVNAME(sc), ifp.fw_version_maj,
+ ifp.fw_version_min, ifp.fw_version_unit, ifp.fw_version_dev);
+
+ printf("%s: hi_priority_queue_depth: 0x%04x\n", DEVNAME(sc),
+ letoh16(ifp.hi_priority_queue_depth));
+
+ printf("%s: host_page_buffer_sge: hdr: 0x%08x addr 0x%08x %08x\n",
+ DEVNAME(sc), letoh32(ifp.host_page_buffer_sge.sg_hdr),
+ letoh32(ifp.host_page_buffer_sge.sg_hiaddr),
+ letoh32(ifp.host_page_buffer_sge.sg_loaddr));
+#endif /* MPI_DEBUG */
+
+ sc->sc_maxcmds = letoh16(ifp.global_credits);
+ sc->sc_maxchdepth = ifp.max_chain_depth;
+ sc->sc_buswidth = ifp.max_devices;
+
+ return (0);
+}
+
+int
+mpi_iocinit(struct mpi_softc *sc)
+{
+ struct mpi_msg_iocinit_request iiq;
+ struct mpi_msg_iocinit_reply iip;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ bzero(&iiq, sizeof(iiq));
+ bzero(&iip, sizeof(iip));
+
+ iiq.function = MPI_FUNCTION_IOC_INIT;
+ iiq.whoinit = MPI_WHOINIT_HOST_DRIVER;
+
+ iiq.max_devices = sc->sc_buswidth;
+ iiq.max_buses = 1;
+
+ iiq.msg_context = htole32(0xd00fd00f);
+
+ iiq.reply_frame_size = htole16(MPI_REPLY_SIZE);
+
+ iiq.msg_version_maj = 0x01;
+ iiq.msg_version_min = 0x02;
+
+ iiq.hdr_version_unit = 0x0d;
+ iiq.hdr_version_dev = 0x00;
+
+ if (mpi_handshake_send(sc, &iiq, dwordsof(iiq)) != 0) {
+ DPRINTF("%s: %s send failed\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+ if (mpi_handshake_recv(sc, &iip, dwordsof(iip)) != 0) {
+ DPRINTF("%s: %s recv failed\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+#ifdef MPI_DEBUG
+ printf("%s: function: 0x%02x msg_length: %d whoinit: 0x%02x\n",
+ DEVNAME(sc), iip.function, iip.msg_length, iip.whoinit);
+
+ printf("%s: msg_flags: 0x%02x max_buses: %d max_devices: %d "
+ "flags: 0x%02x\n", DEVNAME(sc), iip.msg_flags, iip.max_buses,
+ iip.max_devices, iip.flags);
+
+ printf("%s: msg_context: 0x%08x\n", DEVNAME(sc),
+ letoh32(iip.msg_context));
+
+ printf("%s: ioc_status: 0x%04x\n", DEVNAME(sc),
+ letoh16(iip.ioc_status));
+
+ printf("%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc),
+ letoh32(iip.ioc_loginfo));
+#endif /* MPI_DEBUG */
+
+ return (0);
+}
+
+int
+mpi_portfacts(struct mpi_softc *sc)
+{
+ struct mpi_ccb *ccb;
+ struct mpi_msg_portfacts_request *pfq;
+ int s;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ s = splbio();
+ ccb = mpi_get_ccb(sc);
+ splx(s);
+ if (ccb == NULL) {
+ DPRINTF("%s: %s ccb_get\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+ ccb->ccb_done = mpi_portfacts_done;
+ pfq = ccb->ccb_cmd;
+
+ pfq->function = MPI_FUNCTION_PORT_FACTS;
+ pfq->chain_offset = 0;
+ pfq->msg_flags = 0;
+ pfq->port_number = 0;
+ pfq->msg_context = htole32(ccb->ccb_id);
+
+ s = splbio();
+ mpi_start(sc, ccb);
+ mpi_complete(sc, ccb);
+ splx(s);
+
+ return (0);
+}
+
+void
+mpi_portfacts_done(struct mpi_ccb *ccb, void *reply, paddr_t reply_dva)
+{
+ struct mpi_softc *sc = ccb->ccb_sc;
+ struct mpi_msg_portfacts_reply *pfp = reply;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ if (pfp == NULL)
+ panic("%s: empty portfacts reply\n", DEVNAME(sc));
+
+#ifdef MPI_DEBUG
+ printf("%s: function: 0x%02x msg_length: %d\n", DEVNAME(sc),
+ pfp->function, pfp->msg_length);
+
+ printf("%s: msg_flags: 0x%02x port_number: %d\n", DEVNAME(sc),
+ pfp->msg_flags, pfp->port_number);
+
+ printf("%s: msg_context: 0x%08x\n", DEVNAME(sc),
+ letoh32(pfp->msg_context));
+
+ printf("%s: ioc_status: 0x%04x\n", DEVNAME(sc),
+ letoh16(pfp->ioc_status));
+
+ printf("%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc),
+ letoh32(pfp->ioc_loginfo));
+
+ printf("%s: max_devices: %d port_type: 0x%02x\n", DEVNAME(sc),
+ letoh16(pfp->max_devices), pfp->port_type);
+
+ printf("%s: protocol_flags: 0x%04x port_scsi_id: %d\n",
+ DEVNAME(sc), letoh16(pfp->protocol_flags),
+ letoh16(pfp->port_scsi_id));
+
+ printf("%s: max_persistent_ids: %d max_posted_cmd_buffers: %d\n",
+ DEVNAME(sc), letoh16(pfp->max_persistent_ids),
+ letoh16(pfp->max_posted_cmd_buffers));
+
+ printf("%s: max_lan_buckets: %d\n", DEVNAME(sc),
+ letoh16(pfp->max_lan_buckets));
+#endif /* MPI_DEBUG */
+
+ sc->sc_porttype = pfp->port_type;
+ sc->sc_target = letoh16(pfp->port_scsi_id);
+
+ mpi_push_reply(sc, reply_dva);
+ mpi_put_ccb(sc, ccb);
+}
+
+int
+mpi_eventnotify(struct mpi_softc *sc)
+{
+ struct mpi_ccb *ccb;
+ struct mpi_msg_event_request *enq;
+ int s;
+
+ s = splbio();
+ ccb = mpi_get_ccb(sc);
+ splx(s);
+ if (ccb == NULL) {
+ DPRINTF("%s: %s ccb_get\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+ ccb->ccb_done = mpi_eventnotify_done;
+ enq = ccb->ccb_cmd;
+
+ enq->function = MPI_FUNCTION_EVENT_NOTIFICATION;
+ enq->chain_offset = 0;
+ enq->ev_switch = 1;
+ enq->msg_context = htole32(ccb->ccb_id);
+
+ mpi_start(sc, ccb);
+
+ return (0);
+}
+
+void
+mpi_eventnotify_done(struct mpi_ccb *ccb, void *reply, paddr_t reply_dva)
+{
+ struct mpi_softc *sc = ccb->ccb_sc;
+ struct mpi_msg_event_reply *enp = reply;
+ u_int32_t *data;
+ int i;
+
+ printf("%s: %s\n", DEVNAME(sc), __func__);
+
+ printf("%s: function: 0x%02x msg_length: %d data_length: %d\n",
+ DEVNAME(sc), enp->function, enp->msg_length,
+ letoh16(enp->data_length));
+
+ printf("%s: ack_required: %d msg_flags 0x%02x\n", DEVNAME(sc),
+ enp->msg_flags, enp->msg_flags);
+
+ printf("%s: msg_context: 0x%08x\n", DEVNAME(sc),
+ letoh32(enp->msg_context));
+
+ printf("%s: ioc_status: 0x%04x\n", DEVNAME(sc),
+ letoh16(enp->ioc_status));
+
+ printf("%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc),
+ letoh32(enp->ioc_loginfo));
+
+ data = reply;
+ data += dwordsof(struct mpi_msg_event_reply);
+ for (i = 0; i < letoh16(enp->data_length); i++) {
+ printf("%s: data[%d]: 0x%08x\n", DEVNAME(sc), i, data[i]);
+ }
+}
+
+int
+mpi_portenable(struct mpi_softc *sc)
+{
+ struct mpi_ccb *ccb;
+ struct mpi_msg_portenable_request *peq;
+ int s;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ s = splbio();
+ ccb = mpi_get_ccb(sc);
+ splx(s);
+ if (ccb == NULL) {
+ DPRINTF("%s: %s ccb_get\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+ ccb->ccb_done = mpi_portenable_done;
+ peq = ccb->ccb_cmd;
+
+ peq->function = MPI_FUNCTION_PORT_ENABLE;
+ peq->port_number = 0;
+ peq->msg_context = htole32(ccb->ccb_id);
+
+ s = splbio();
+ mpi_start(sc, ccb);
+ mpi_complete(sc, ccb);
+ splx(s);
+
+ return (0);
+}
+
+void
+mpi_portenable_done(struct mpi_ccb *ccb, void *reply, paddr_t reply_dva)
+{
+ struct mpi_softc *sc = ccb->ccb_sc;
+ struct mpi_msg_portenable_reply *pep = reply;
+
+ DPRINTF("%s: %s\n", DEVNAME(sc), __func__);
+
+ if (pep == NULL)
+ panic("%s: empty portfacts reply\n", DEVNAME(sc));
+
+ mpi_push_reply(sc, reply_dva);
+ mpi_put_ccb(sc, ccb);
+}
+
+int
+mpi_oportfacts(struct mpi_softc *sc)
+{
+ struct mpi_msg_portfacts_request pfq;
+ struct mpi_msg_portfacts_reply pfp;
+
+ bzero(&pfq, sizeof(pfq));
+ bzero(&pfp, sizeof(pfp));
+
+ pfq.function = MPI_FUNCTION_PORT_FACTS;
+ pfq.chain_offset = 0;
+ pfq.msg_flags = 0;
+ pfq.port_number = 0;
+ pfq.msg_context = htole32(0xdeadbeef);
+
+ if (mpi_handshake_send(sc, &pfq, dwordsof(pfq)) != 0) {
+ DPRINTF("%s: %s send failed\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+ if (mpi_handshake_recv(sc, &pfp, dwordsof(pfp)) != 0) {
+ DPRINTF("%s: %s recv failed\n", DEVNAME(sc), __func__);
+ return (1);
+ }
+
+#ifdef MPI_DEBUG
+ printf("%s: function: 0x%02x msg_length: %d\n", DEVNAME(sc),
+ pfp.function, pfp.msg_length);
+
+ printf("%s: msg_flags: 0x%02x port_number: %d\n", DEVNAME(sc),
+ pfp.msg_flags, pfp.port_number);
+
+ printf("%s: msg_context: 0x%08x\n", DEVNAME(sc),
+ letoh32(pfp.msg_context));
+
+ printf("%s: ioc_status: 0x%04x\n", DEVNAME(sc),
+ letoh16(pfp.ioc_status));
+
+ printf("%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc),
+ letoh32(pfp.ioc_loginfo));
+
+ printf("%s: max_devices: %d port_type: 0x%02x\n", DEVNAME(sc),
+ letoh16(pfp.max_devices), pfp.port_type);
+
+ printf("%s: protocol_flags: 0x%04x port_scsi_id: %d\n",
+ DEVNAME(sc), letoh16(pfp.protocol_flags),
+ letoh16(pfp.port_scsi_id));
+
+ printf("%s: max_persistent_ids: %d max_posted_cmd_buffers: %d\n",
+ DEVNAME(sc), letoh16(pfp.max_persistent_ids),
+ letoh16(pfp.max_posted_cmd_buffers));
+
+ printf("%s: max_lan_buckets: %d\n", DEVNAME(sc),
+ letoh16(pfp.max_lan_buckets));
+#endif /* MPI_DEBUG */
+
+ sc->sc_porttype = pfp.port_type;
+ sc->sc_target = letoh16(pfp.port_scsi_id);
+
+ return (0);
+}
diff --git a/sys/dev/ic/mpireg.h b/sys/dev/ic/mpireg.h
new file mode 100644
index 00000000000..c8fa1e27f75
--- /dev/null
+++ b/sys/dev/ic/mpireg.h
@@ -0,0 +1,694 @@
+/* $OpenBSD: mpireg.h,v 1.1 2006/05/27 19:03:55 dlg Exp $ */
+
+/*
+ * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
+ * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * System Interface Register Set
+ */
+
+#define MPI_DOORBELL 0x00
+/* doorbell read bits */
+#define MPI_DOORBELL_STATE (0xf<<28) /* ioc state */
+#define MPI_DOORBELL_STATE_RESET (0x0<<28)
+#define MPI_DOORBELL_STATE_READY (0x1<<28)
+#define MPI_DOORBELL_STATE_OPER (0x2<<28)
+#define MPI_DOORBELL_STATE_FAULT (0x4<<28)
+#define MPI_DOORBELL_INUSE (0x1<<27) /* doorbell used */
+#define MPI_DOORBELL_WHOINIT (0x7<<24) /* last to reset ioc */
+#define MPI_DOORBELL_WHOINIT_NOONE (0x0<<24) /* not initialized */
+#define MPI_DOORBELL_WHOINIT_SYSBIOS (0x1<<24) /* system bios */
+#define MPI_DOORBELL_WHOINIT_ROMBIOS (0x2<<24) /* rom bios */
+#define MPI_DOORBELL_WHOINIT_PCIPEER (0x3<<24) /* pci peer */
+#define MPI_DOORBELL_WHOINIT_DRIVER (0x4<<24) /* host driver */
+#define MPI_DOORBELL_WHOINIT_MANUFACT (0x5<<24) /* manufacturing */
+#define MPI_DOORBELL_FAULT (0xffff<<0) /* fault code */
+#define MPI_DOORBELL_FAULT_REQ_PCIPAR 0x8111 /* req msg pci parity err */
+#define MPI_DOORBELL_FAULT_REQ_PCIBUS 0x8112 /* req msg pci bus err */
+#define MPI_DOORBELL_FAULT_REP_PCIPAR 0x8113 /* reply msg pci parity err */
+#define MPI_DOORBELL_FAULT_REP_PCIBUS 0x8114 /* reply msg pci bus err */
+#define MPI_DOORBELL_FAULT_SND_PCIPAR 0x8115 /* data send pci parity err */
+#define MPI_DOORBELL_FAULT_SND_PCIBUS 0x8116 /* data send pci bus err */
+#define MPI_DOORBELL_FAULT_RCV_PCIPAR 0x8117 /* data recv pci parity err */
+#define MPI_DOORBELL_FAULT_RCV_PCIBUS 0x8118 /* data recv pci bus err */
+/* doorbell write bits */
+#define MPI_DOORBELL_FUNCTION_SHIFT 24
+#define MPI_DOORBELL_FUNCTION_MASK (0xff << MPI_DOORBELL_FUNCTION_SHIFT)
+#define MPI_DOORBELL_FUNCTION(x) \
+ (((x) << MPI_DOORBELL_FUNCTION_SHIFT) & MPI_DOORBELL_FUNCTION_MASK)
+#define MPI_DOORBELL_DWORDS_SHIFT 16
+#define MPI_DOORBELL_DWORDS_MASK (0xff << MPI_DOORBELL_DWORDS_SHIFT)
+#define MPI_DOORBELL_DWORDS(x) \
+ (((x) << MPI_DOORBELL_DWORDS_SHIFT) & MPI_DOORBELL_DWORDS_MASK)
+#define MPI_DOORBELL_DATA_MASK 0xffff
+
+#define MPI_WRITESEQ 0x04
+#define MPI_WRITESEQ_VALUE 0x0000000f /* key value */
+#define MPI_WRITESEQ_1 0x04
+#define MPI_WRITESEQ_2 0x0b
+#define MPI_WRITESEQ_3 0x02
+#define MPI_WRITESEQ_4 0x07
+#define MPI_WRITESEQ_5 0x0d
+
+#define MPI_HOSTDIAG 0x08
+#define MPI_HOSTDIAG_CLEARFBS (1<<10) /* clear flash bad sig */
+#define MPI_HOSTDIAG_POICB (1<<9) /* prevent ioc boot */
+#define MPI_HOSTDIAG_DWRE (1<<7) /* diag reg write enabled */
+#define MPI_HOSTDIAG_FBS (1<<6) /* flash bad sig */
+#define MPI_HOSTDIAG_RESET_HIST (1<<5) /* reset history */
+#define MPI_HOSTDIAG_DIAGWR_EN (1<<4) /* diagnostic write enabled */
+#define MPI_HOSTDIAG_RESET_ADAPTER (1<<2) /* reset adapter */
+#define MPI_HOSTDIAG_DISABLE_ARM (1<<1) /* disable arm */
+#define MPI_HOSTDIAG_DIAGMEM_EN (1<<0) /* diag mem enable */
+
+#define MPI_TESTBASE 0x0c
+
+#define MPI_DIAGRWDATA 0x10
+
+#define MPI_DIAGRWADDR 0x18
+
+#define MPI_INTR_STATUS 0x30
+#define MPI_INTR_STATUS_IOCDOORBELL (1<<31) /* ioc doorbell status */
+#define MPI_INTR_STATUS_REPLY (1<<3) /* reply message interrupt */
+#define MPI_INTR_STATUS_DOORBELL (1<<0) /* doorbell interrupt */
+
+#define MPI_INTR_MASK 0x34
+#define MPI_INTR_MASK_REPLY (1<<3) /* reply message intr mask */
+#define MPI_INTR_MASK_DOORBELL (1<<0) /* doorbell interrupt mask */
+
+#define MPI_REQ_QUEUE 0x40
+
+#define MPI_REPLY_QUEUE 0x44
+#define MPI_REPLY_QUEUE_ADDRESS (1<<31) /* address reply */
+#define MPI_REPLY_QUEUE_ADDRESS_MASK 0x7fffffff
+#define MPI_REPLY_QUEUE_TYPE_MASK (3<<29)
+#define MPI_REPLY_QUEUE_TYPE_INIT (0<<29) /* scsi initiator reply */
+#define MPI_REPLY_QUEUE_TYPE_TARGET (1<<29) /* scsi target reply */
+#define MPI_REPLY_QUEUE_TYPE_LAN (2<<29) /* lan reply */
+#define MPI_REPLY_QUEUE_CONTEXT 0x1fffffff /* not address and type */
+
+#define MPI_PRIREQ_QUEUE 0x48
+
+/*
+ * Scatter Gather Lists
+ */
+
+#define MPI_SGE_FL_LAST (0x1<<31) /* last element in segment */
+#define MPI_SGE_FL_EOB (0x1<<30) /* last element of buffer */
+#define MPI_SGE_FL_TYPE (0x3<<28) /* element type */
+#define MPI_SGE_FL_TYPE_SIMPLE (0x1<<28) /* simple element */
+#define MPI_SGE_FL_TYPE_CHAIN (0x3<<28) /* chain element */
+#define MPI_SGE_FL_TYPE_XACTCTX (0x0<<28) /* transaction context */
+#define MPI_SGE_FL_LOCAL (0x1<<27) /* local address */
+#define MPI_SGE_FL_DIR (0x1<<26) /* direction */
+#define MPI_SGE_FL_DIR_OUT (0x1<<26)
+#define MPI_SGE_FL_DIR_IN (0x0<<26)
+#define MPI_SGE_FL_SIZE (0x1<<25) /* address size */
+#define MPI_SGE_FL_SIZE_32 (0x0<<25) /* address size */
+#define MPI_SGE_FL_SIZE_64 (0x1<<25) /* address size */
+#define MPI_SGE_FL_EOL (0x1<<24) /* end of list */
+
+struct mpi_sge32 {
+ u_int32_t sg_hdr;
+ u_int32_t sg_addr;
+} __packed;
+
+struct mpi_sge64 {
+ u_int32_t sg_hdr;
+ u_int32_t sg_loaddr;
+ u_int32_t sg_hiaddr;
+} __packed;
+
+/* XXX */
+struct mpi_sgl_se {
+ u_int32_t sg_hdr;
+ u_int32_t sg_loaddr;
+ u_int32_t sg_hiaddr;
+} __packed;
+
+struct mpi_sgl_ce {
+ u_int32_t sg_hdr;
+ u_int32_t sg_loaddr;
+ u_int32_t sg_hiaddr;
+} __packed;
+
+struct mpi_sgl_tce {
+ u_int32_t sg_hdr;
+ u_int32_t sg_loaddr;
+ u_int32_t sg_hiaddr;
+} __packed;
+
+/*
+ * Messages
+ */
+
+/* functions */
+#define MPI_FUNCTION_SCSI_IO_REQUEST (0x00)
+#define MPI_FUNCTION_SCSI_TASK_MGMT (0x01)
+#define MPI_FUNCTION_IOC_INIT (0x02)
+#define MPI_FUNCTION_IOC_FACTS (0x03)
+#define MPI_FUNCTION_CONFIG (0x04)
+#define MPI_FUNCTION_PORT_FACTS (0x05)
+#define MPI_FUNCTION_PORT_ENABLE (0x06)
+#define MPI_FUNCTION_EVENT_NOTIFICATION (0x07)
+#define MPI_FUNCTION_EVENT_ACK (0x08)
+#define MPI_FUNCTION_FW_DOWNLOAD (0x09)
+#define MPI_FUNCTION_TARGET_CMD_BUFFER_POST (0x0A)
+#define MPI_FUNCTION_TARGET_ASSIST (0x0B)
+#define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C)
+#define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D)
+#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete */
+#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete */
+#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete */
+#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete */
+#define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E)
+#define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F)
+#define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10)
+#define MPI_FUNCTION_FC_ABORT (0x11)
+#define MPI_FUNCTION_FW_UPLOAD (0x12)
+#define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND (0x13)
+#define MPI_FUNCTION_FC_PRIMITIVE_SEND (0x14)
+
+#define MPI_FUNCTION_RAID_ACTION (0x15)
+#define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16)
+
+#define MPI_FUNCTION_TOOLBOX (0x17)
+
+#define MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18)
+
+#define MPI_FUNCTION_MAILBOX (0x19)
+
+#define MPI_FUNCTION_LAN_SEND (0x20)
+#define MPI_FUNCTION_LAN_RECEIVE (0x21)
+#define MPI_FUNCTION_LAN_RESET (0x22)
+
+#define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
+#define MPI_FUNCTION_IO_UNIT_RESET (0x41)
+#define MPI_FUNCTION_HANDSHAKE (0x42)
+#define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43)
+
+/* reply flags */
+#define MPI_REP_FLAGS_CONT (1<<7) /* continuation reply */
+
+#define MPI_REP_IOCSTATUS_AVAIL (1<<15) /* logging info available */
+#define MPI_REP_IOCSTATUS (0x7fff) /* status */
+
+/* Common IOCStatus values for all replies */
+#define MPI_IOCSTATUS_SUCCESS (0x0000)
+#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001)
+#define MPI_IOCSTATUS_BUSY (0x0002)
+#define MPI_IOCSTATUS_INVALID_SGL (0x0003)
+#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004)
+#define MPI_IOCSTATUS_RESERVED (0x0005)
+#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006)
+#define MPI_IOCSTATUS_INVALID_FIELD (0x0007)
+#define MPI_IOCSTATUS_INVALID_STATE (0x0008)
+#define MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009)
+/* Config IOCStatus values */
+#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020)
+#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021)
+#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022)
+#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023)
+#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024)
+#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025)
+/* SCSIIO Reply (SPI & FCP) initiator values */
+#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040)
+#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041)
+#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042)
+#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043)
+#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044)
+#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045)
+#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046)
+#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047)
+#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048)
+#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049)
+#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A)
+#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B)
+#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C)
+/* For use by SCSI Initiator and SCSI Target end-to-end data protection */
+#define MPI_IOCSTATUS_EEDP_GUARD_ERROR (0x004D)
+#define MPI_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E)
+#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F)
+/* SCSI (SPI & FCP) target values */
+#define MPI_IOCSTATUS_TARGET_PRIORITY_IO (0x0060)
+#define MPI_IOCSTATUS_TARGET_INVALID_PORT (0x0061)
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) /* obsolete */
+#define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062)
+#define MPI_IOCSTATUS_TARGET_ABORTED (0x0063)
+#define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064)
+#define MPI_IOCSTATUS_TARGET_NO_CONNECTION (0x0065)
+#define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
+#define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B)
+#define MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D)
+#define MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E)
+#define MPI_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F)
+/* Additional FCP target values */
+#define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_RX_ID_INVALID (0x0067) /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_DID_INVALID (0x0068) /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_NODE_LOGGED_OUT (0x0069) /* obsolete */
+/* Fibre Channel Direct Access values */
+#define MPI_IOCSTATUS_FC_ABORTED (0x0066)
+#define MPI_IOCSTATUS_FC_RX_ID_INVALID (0x0067)
+#define MPI_IOCSTATUS_FC_DID_INVALID (0x0068)
+#define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT (0x0069)
+#define MPI_IOCSTATUS_FC_EXCHANGE_CANCELED (0x006C)
+/* LAN values */
+#define MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND (0x0080)
+#define MPI_IOCSTATUS_LAN_DEVICE_FAILURE (0x0081)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ERROR (0x0082)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED (0x0083)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ERROR (0x0084)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ABORTED (0x0085)
+#define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086)
+#define MPI_IOCSTATUS_LAN_CANCELED (0x0087)
+/* Serial Attached SCSI values */
+#define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090)
+#define MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091)
+/* Inband values */
+#define MPI_IOCSTATUS_INBAND_ABORTED (0x0098)
+#define MPI_IOCSTATUS_INBAND_NO_CONNECTION (0x0099)
+/* Diagnostic Tools values */
+#define MPI_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0)
+
+#define MPI_REP_IOCLOGINFO_TYPE (0xf<<28) /* logging info type */
+#define MPI_REP_IOCLOGINFO_TYPE_NONE (0x0<<28)
+#define MPI_REP_IOCLOGINFO_TYPE_SCSI (0x1<<28)
+#define MPI_REP_IOCLOGINFO_TYPE_FC (0x2<<28)
+#define MPI_REP_IOCLOGINFO_TYPE_SAS (0x3<<28)
+#define MPI_REP_IOCLOGINFO_TYPE_ISCSI (0x4<<28)
+#define MPI_REP_IOCLOGINFO_DATA (0x0fffffff) /* logging info data */
+
+/* messages */
+
+#define MPI_WHOINIT_NOONE 0x00
+#define MPI_WHOINIT_SYSTEM_BIOS 0x01
+#define MPI_WHOINIT_ROM_BIOS 0x02
+#define MPI_WHOINIT_PCI_PEER 0x03
+#define MPI_WHOINIT_HOST_DRIVER 0x04
+#define MPI_WHOINIT_MANUFACTURER 0x05
+
+/* default messages */
+
+struct mpi_msg_request {
+ u_int8_t reserved1;
+ u_int8_t reserved2;
+ u_int8_t chain_offset;
+ u_int8_t function;
+
+ u_int8_t reserved3;
+ u_int8_t reserved4;
+ u_int8_t reserved5;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+} __packed;
+
+struct mpi_msg_reply {
+ u_int8_t reserved1;
+ u_int8_t reserved2;
+ u_int8_t msg_length;
+ u_int8_t function;
+
+ u_int8_t reserved3;
+ u_int8_t reserved4;
+ u_int8_t reserved5;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int8_t reserved6;
+ u_int8_t reserved7;
+ u_int16_t ioc_status;
+
+ u_int32_t ioc_loginfo;
+} __packed;
+
+/* ioc init */
+
+struct mpi_msg_iocinit_request {
+ u_int8_t whoinit;
+ u_int8_t reserved1;
+ u_int8_t chain_offset;
+ u_int8_t function;
+
+ u_int8_t flags;
+#define MPI_IOCINIT_F_DISCARD_FW (1<<0)
+#define MPI_IOCINIT_F_ENABLE_HOST_FIFO (1<<1)
+#define MPI_IOCINIT_F_HOST_PG_BUF_PERSIST (1<<2)
+ u_int8_t max_devices;
+ u_int8_t max_buses;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int16_t reply_frame_size;
+ u_int16_t reserved2;
+
+ u_int32_t host_mfa_hi_addr;
+ u_int32_t sense_buffer_hi_addr;
+ u_int32_t reply_fifo_host_signalling_addr;
+ struct mpi_sgl_se host_page_buffer_sge;
+
+ u_int8_t msg_version_min;
+ u_int8_t msg_version_maj;
+
+ u_int8_t hdr_version_unit;
+ u_int8_t hdr_version_dev;
+} __packed;
+
+struct mpi_msg_iocinit_reply {
+ u_int8_t whoinit;
+ u_int8_t reserved1;
+ u_int8_t msg_length;
+ u_int8_t function;
+
+ u_int8_t flags;
+ u_int8_t max_devices;
+ u_int8_t max_buses;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int16_t reserved2;
+ u_int16_t ioc_status;
+
+ u_int32_t ioc_loginfo;
+} __packed;
+
+
+/* ioc facts */
+struct mpi_msg_iocfacts_request {
+ u_int8_t reserved1;
+ u_int8_t reserved2;
+ u_int8_t chain_offset;
+ u_int8_t function;
+
+ u_int8_t reserved3;
+ u_int8_t reserved4;
+ u_int8_t reserved5;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+} __packed;
+
+struct mpi_msg_iocfacts_reply {
+ u_int8_t msg_version_min;
+ u_int8_t msg_version_maj;
+ u_int8_t msg_length;
+ u_int8_t function;
+
+ u_int8_t header_version_min;
+ u_int8_t header_version_maj;
+ u_int8_t ioc_number;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int16_t ioc_exceptions;
+#define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (1<<0)
+#define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (1<<1)
+#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (1<<2)
+#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (1<<3)
+ u_int16_t ioc_status;
+
+ u_int32_t ioc_loginfo;
+
+ u_int8_t max_chain_depth;
+ u_int8_t whoinit;
+ u_int8_t block_size;
+ u_int8_t flags;
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (1<<0)
+#define MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL (1<<1)
+#define MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT (1<<2)
+
+ u_int16_t reply_queue_depth;
+ u_int16_t request_frame_size;
+
+ u_int16_t reserved1;
+ u_int16_t product_id; /* product id */
+
+ u_int32_t current_host_mfa_hi_addr;
+
+ u_int16_t global_credits;
+ u_int8_t number_of_ports;
+ u_int8_t event_state;
+
+ u_int32_t current_sense_buffer_hi_addr;
+
+ u_int16_t current_reply_frame_size;
+ u_int8_t max_devices;
+ u_int8_t max_buses;
+
+ u_int32_t fw_image_size;
+
+ u_int32_t ioc_capabilities;
+#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q (1<<0)
+#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL (1<<1)
+#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING (1<<2)
+#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (1<<3)
+#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (1<<4)
+#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (1<<5)
+#define MPI_IOCFACTS_CAPABILITY_EEDP (1<<6)
+#define MPI_IOCFACTS_CAPABILITY_BIDIRECTIONAL (1<<7)
+#define MPI_IOCFACTS_CAPABILITY_MULTICAST (1<<8)
+#define MPI_IOCFACTS_CAPABILITY_SCSIIO32 (1<<9)
+#define MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 (1<<10)
+
+ u_int8_t fw_version_dev;
+ u_int8_t fw_version_unit;
+ u_int8_t fw_version_min;
+ u_int8_t fw_version_maj;
+
+ u_int16_t hi_priority_queue_depth;
+ u_int16_t reserved2;
+
+ struct mpi_sgl_se host_page_buffer_sge;
+
+ u_int32_t reply_fifo_host_signalling_addr;
+} __packed;
+
+struct mpi_msg_portfacts_request {
+ u_int8_t reserved1;
+ u_int8_t reserved2;
+ u_int8_t chain_offset;
+ u_int8_t function;
+
+ u_int8_t reserved3;
+ u_int8_t reserved4;
+ u_int8_t port_number;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+} __packed;
+
+struct mpi_msg_portfacts_reply {
+ u_int16_t reserved1;
+ u_int8_t msg_length;
+ u_int8_t function;
+
+ u_int16_t reserved2;
+ u_int8_t port_number;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int16_t reserved3;
+ u_int16_t ioc_status;
+
+ u_int32_t ioc_loginfo;
+
+ u_int8_t reserved4;
+ u_int8_t port_type;
+#define MPI_PORTFACTS_PORTTYPE_INACTIVE 0x00
+#define MPI_PORTFACTS_PORTTYPE_SCSI 0x01
+#define MPI_PORTFACTS_PORTTYPE_FC 0x10
+#define MPI_PORTFACTS_PORTTYPE_ISCSI 0x20
+#define MPI_PORTFACTS_PORTTYPE_SAS 0x30
+
+ u_int16_t max_devices;
+
+ u_int16_t port_scsi_id;
+ u_int16_t protocol_flags;
+#define MPI_PORTFACTS_PROTOCOL_LOGBUSADDR (1<<0)
+#define MPI_PORTFACTS_PROTOCOL_LAN (1<<1)
+#define MPI_PORTFACTS_PROTOCOL_TARGET (1<<2)
+#define MPI_PORTFACTS_PROTOCOL_INITIATOR (1<<3)
+
+ u_int16_t max_posted_cmd_buffers;
+ u_int16_t max_persistent_ids;
+
+ u_int16_t max_lan_buckets;
+ u_int16_t reserved5;
+
+ u_int32_t reserved6;
+} __packed;
+
+struct mpi_msg_portenable_request {
+ u_int16_t reserved1;
+ u_int8_t chain_offset;
+ u_int8_t function;
+
+ u_int16_t reserved2;
+ u_int8_t port_number;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+} __packed;
+
+struct mpi_msg_portenable_reply {
+ u_int16_t reserved1;
+ u_int8_t msg_length;
+ u_int8_t function;
+
+ u_int16_t reserved2;
+ u_int8_t port_number;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int16_t reserved3;
+ u_int16_t ioc_status;
+
+ u_int32_t ioc_loginfo;
+} __packed;
+
+struct mpi_msg_event_request {
+ u_int8_t ev_switch;
+ u_int8_t reserved1;
+ u_int8_t chain_offset;
+ u_int8_t function;
+
+ u_int8_t reserved2[3];
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+} __packed;
+
+struct mpi_msg_event_reply {
+ u_int16_t data_length;
+ u_int8_t msg_length;
+ u_int8_t function;
+
+ u_int16_t reserved1;
+ u_int8_t ack_required;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int16_t reserved2;
+ u_int16_t ioc_status;
+
+ u_int32_t ioc_loginfo;
+
+ u_int32_t event;
+
+ u_int32_t event_context;
+
+ /* event data follows */
+} __packed;
+
+struct mpi_msg_scsi_io {
+ u_int8_t target_id;
+ u_int8_t bus;
+ u_int8_t chain_offset;
+ u_int8_t function;
+
+ u_int8_t cdb_length;
+ u_int8_t sense_buf_len;
+ u_int8_t reserved;
+ u_int8_t msg_flags;
+#define MPI_SCSIIO_EEDP 0xf0
+#define MPI_SCSIIO_CMD_DATA_DIR (1<<2)
+#define MPI_SCSIIO_SENSE_BUF_LOC (1<<1)
+#define MPI_SCSIIO_SENSE_BUF_ADDR_WIDTH (1<<0)
+
+ u_int32_t msg_context;
+
+ u_int16_t lun[4];
+
+ u_int32_t control;
+#define MPI_SCSIIO_ADDITIONAL_CDB_LEN (0xf<<26)
+#define MPI_SCSIIO_DATA_DIR (0x3<<24)
+#define MPI_SCSIIO_DATA_DIR_NONE (0x0<<24)
+#define MPI_SCSIIO_DATA_DIR_WRITE (0x1<<24)
+#define MPI_SCSIIO_DATA_DIR_READ (0x2<<24)
+#define MPI_SCSIIO_TASK_ATTR (0x7<<8)
+#define MPI_SCSIIO_TASK_ATTR_SIMPLE_Q (0x0<<8)
+#define MPI_SCSIIO_TASK_ATTR_HEAD_OF_Q (0x1<<8)
+#define MPI_SCSIIO_TASK_ATTR_ORDERED_Q (0x2<<8)
+#define MPI_SCSIIO_TASK_ATTR_ACA_Q (0x4<<8)
+#define MPI_SCSIIO_TASK_ATTR_UNTAGGED (0x5<<8)
+#define MPI_SCSIIO_TASK_ATTR_NO_DISCONNECT (0x7<<8)
+
+#define MPI_CDB_LEN 16
+ u_int8_t cdb[MPI_CDB_LEN];
+
+ u_int32_t data_length;
+
+ u_int32_t sense_buf_low_addr;
+
+ /* followed by an sgl */
+} __packed;
+
+struct mpi_msg_scsi_io_error {
+ u_int8_t target_id;
+ u_int8_t bus;
+ u_int8_t msg_length;
+ u_int8_t function;
+
+ u_int8_t cdb_length;
+ u_int8_t sense_buf_len;
+ u_int8_t reserved1;
+ u_int8_t msg_flags;
+
+ u_int32_t msg_context;
+
+ u_int8_t scsi_status;
+#if notyet
+#define MPI_SCSIIO_ERR_STATUS_SUCCESS
+#define MPI_SCSIIO_ERR_STATUS_CHECK_COND
+#define MPI_SCSIIO_ERR_STATUS_BUSY
+#define MPI_SCSIIO_ERR_STATUS_INTERMEDIATE
+#define MPI_SCSIIO_ERR_STATUS_INTERMEDIATE_CONDMET
+#define MPI_SCSIIO_ERR_STATUS_RESERVATION_CONFLICT
+#define MPI_SCSIIO_ERR_STATUS_CMD_TERM
+#define MPI_SCSIIO_ERR_STATUS_TASK_SET_FULL
+#define MPI_SCSIIO_ERR_STATUS_ACA_ACTIVE
+#endif
+ u_int8_t scsi_state;
+#define MPI_SCSIIO_ERR_STATE_AUTOSENSE_VALID (1<<0)
+#define MPI_SCSIIO_ERR_STATE_AUTOSENSE_FAILED (1<<2)
+#define MPI_SCSIIO_ERR_STATE_NO_SCSI_STATUS (1<<3)
+#define MPI_SCSIIO_ERR_STATE_TERMINATED (1<<4)
+#define MPI_SCSIIO_ERR_STATE_RESPONSE_INFO_VALID (1<<5)
+#define MPI_SCSIIO_ERR_STATE_QUEUE_TAG_REJECTED (1<<6)
+
+ u_int16_t ioc_status;
+
+ u_int32_t ioc_loginfo;
+
+ u_int32_t transfer_count;
+
+ u_int32_t sense_count;
+
+ u_int32_t response_info;
+
+ u_int16_t tag;
+ u_int16_t reserved2;
+} __packed;
diff --git a/sys/dev/ic/mpivar.h b/sys/dev/ic/mpivar.h
new file mode 100644
index 00000000000..d1a70619e71
--- /dev/null
+++ b/sys/dev/ic/mpivar.h
@@ -0,0 +1,93 @@
+/* $OpenBSD: mpivar.h,v 1.1 2006/05/27 19:03:55 dlg Exp $ */
+
+/*
+ * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
+ * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* XXX */
+#define MPI_MAX_SGL 32
+
+#define MPI_REQUEST_SIZE 512
+#define MPI_REPLY_SIZE 128
+
+struct mpi_dmamem {
+ bus_dmamap_t mdm_map;
+ bus_dma_segment_t mdm_seg;
+ size_t mdm_size;
+ caddr_t mdm_kva;
+};
+#define MPI_DMA_MAP(_mdm) ((_mdm)->mdm_map)
+#define MPI_DMA_DVA(_mdm) ((_mdm)->mdm_map->dm_segs[0].ds_addr)
+#define MPI_DMA_KVA(_mdm) ((void *)(_mdm)->mdm_kva)
+
+struct mpi_ccb_bundle {
+ struct mpi_msg_scsi_io mcb_io; /* sgl must follow */
+ struct mpi_sge32 mcb_sgl[MPI_MAX_SGL];
+ struct scsi_sense_data mcb_sense;
+} __packed;
+
+struct mpi_softc;
+
+struct mpi_ccb {
+ struct mpi_softc *ccb_sc;
+ int ccb_id;
+
+ struct scsi_xfer *ccb_xs;
+ bus_dmamap_t ccb_dmamap;
+
+ bus_addr_t ccb_offset;
+ void *ccb_cmd;
+ paddr_t ccb_cmd_dva;
+
+ volatile enum {
+ MPI_CCB_FREE,
+ MPI_CCB_READY,
+ MPI_CCB_QUEUED
+ } ccb_state;
+ void (*ccb_done)(struct mpi_ccb *, void *, paddr_t);
+
+ TAILQ_ENTRY(mpi_ccb) ccb_link;
+};
+
+TAILQ_HEAD(mpi_ccb_list, mpi_ccb);
+
+struct mpi_softc {
+ struct device sc_dev;
+ struct scsi_link sc_link;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_size_t sc_ios;
+ bus_dma_tag_t sc_dmat;
+
+ int sc_maxcmds;
+ int sc_maxchdepth;
+ u_int8_t sc_porttype;
+
+ int sc_buswidth;
+ int sc_target;
+
+ struct mpi_dmamem *sc_requests;
+ struct mpi_ccb *sc_ccbs;
+ struct mpi_ccb_list sc_ccb_free, sc_ccb_runq;
+
+ struct mpi_dmamem *sc_replies;
+};
+
+int mpi_attach(struct mpi_softc *);
+void mpi_detach(struct mpi_softc *);
+
+int mpi_intr(void *);
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index e8ced38bbfc..1f2b12c9682 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.205 2006/05/14 19:00:48 damien Exp $
+# $OpenBSD: files.pci,v 1.206 2006/05/27 19:03:55 dlg Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -192,6 +192,10 @@ file dev/pci/isp_pci.c isp_pci
attach mpt at pci with mpt_pci
file dev/pci/mpt_pci.c mpt_pci
+# LSI Logic Fusion-MPT Message Passing Interface
+attach mpi at pci with mpi_pci
+file dev/pci/mpi_pci.c mpi_pci
+
# Ethernet driver for DC21040-based boards
device de: ether, ifnet, ifmedia
attach de at pci
diff --git a/sys/dev/pci/mpi_pci.c b/sys/dev/pci/mpi_pci.c
new file mode 100644
index 00000000000..371a4c61427
--- /dev/null
+++ b/sys/dev/pci/mpi_pci.c
@@ -0,0 +1,168 @@
+/* $OpenBSD: mpi_pci.c,v 1.1 2006/05/27 19:03:55 dlg Exp $ */
+
+/*
+ * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
+ * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/mpireg.h>
+#include <dev/ic/mpivar.h>
+
+int mpi_pci_match(struct device *, void *, void *);
+void mpi_pci_attach(struct device *, struct device *, void *);
+int mpi_pci_detach(struct device *, int);
+
+struct mpi_pci_softc {
+ struct mpi_softc psc_mpi;
+
+ pci_chipset_tag_t psc_pc;
+ pcitag_t psc_tag;
+
+ void *psc_ih;
+};
+
+struct cfattach mpi_pci_ca = {
+ sizeof(struct mpi_pci_softc), mpi_pci_match, mpi_pci_attach,
+ mpi_pci_detach
+};
+
+#define PREAD(s, r) pci_conf_read((s)->psc_pc, (s)->psc_tag, (r))
+#define PWRITE(s, r, v) pci_conf_write((s)->psc_pc, (s)->psc_tag, (r), (v))
+
+#define MPP_DUAL 0x01 /* Dual port adapter */
+
+static const struct pci_matchid mpi_devices[] = {
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_1030 },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_FC909 },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_FC909A },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_FC919 },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_FC919_1 },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_FC929 },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_FC929_1 },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS1068 }
+
+};
+
+int
+mpi_pci_match(struct device *parent, void *match, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+
+ return (pci_matchbyid(pa, mpi_devices,
+ sizeof(mpi_devices) / sizeof(mpi_devices[0])) * 2);
+}
+
+void
+mpi_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct mpi_pci_softc *psc = (void *)self;
+ struct mpi_softc *sc = &psc->psc_mpi;
+ struct pci_attach_args *pa = aux;
+ pcireg_t memtype;
+ int r;
+ pci_intr_handle_t ih;
+ const char *intrstr;
+
+ psc->psc_pc = pa->pa_pc;
+ psc->psc_tag = pa->pa_tag;
+ psc->psc_ih = NULL;
+ sc->sc_dmat = pa->pa_dmat;
+ sc->sc_ios = 0;
+
+ /* find the appropriate memory base */
+ for (r = PCI_MAPREG_START; r < PCI_MAPREG_END; r += sizeof(memtype)) {
+ memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag, r);
+ if ((memtype & PCI_MAPREG_TYPE_MASK) == PCI_MAPREG_TYPE_MEM)
+ break;
+ }
+ if (r >= PCI_MAPREG_END) {
+ printf(": unable to locate system interface registers\n");
+ return;
+ }
+
+ if (pci_mapreg_map(pa, r, memtype, 0, &sc->sc_iot, &sc->sc_ioh,
+ NULL, &sc->sc_ios, 0) != 0) {
+ printf(": unable to map system interface registers\n");
+ return;
+ }
+
+ /* disable the expansion rom */
+ PWRITE(psc, PCI_ROM_REG, PREAD(psc, PCI_ROM_REG & ~PCI_ROM_ENABLE));
+
+ /* hook up the interrupt */
+ if (pci_intr_map(pa, &ih)) {
+ printf(": unable to map interrupt\n");
+ goto unmap;
+ }
+ intrstr = pci_intr_string(psc->psc_pc, ih);
+ psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO,
+ mpi_intr, sc, sc->sc_dev.dv_xname);
+ if (psc->psc_ih == NULL) {
+ printf(": unable to map interrupt%s%s\n",
+ intrstr == NULL ? "" : " at ",
+ intrstr == NULL ? "" : intrstr);
+ goto unmap;
+ }
+ printf(": %s", intrstr);
+
+ if (mpi_attach(sc) != 0) {
+ /* error printed by mpi_attach */
+ goto deintr;
+ }
+
+ return;
+
+deintr:
+ pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
+ psc->psc_ih = NULL;
+unmap:
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+ sc->sc_ios = 0;
+}
+
+int
+mpi_pci_detach(struct device *self, int flags)
+{
+ struct mpi_pci_softc *psc = (struct mpi_pci_softc *)self;
+ struct mpi_softc *sc = &psc->psc_mpi;
+
+ mpi_detach(sc);
+
+ if (psc->psc_ih != NULL) {
+ pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
+ psc->psc_ih = NULL;
+ }
+ if (sc->sc_ios != 0) {
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+ sc->sc_ios = 0;
+ }
+
+ return (0);
+}