summaryrefslogtreecommitdiffstats
path: root/sys/dev/pst
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pst')
-rw-r--r--sys/dev/pst/pst-iop.c499
-rw-r--r--sys/dev/pst/pst-iop.h647
-rw-r--r--sys/dev/pst/pst-pci.c132
-rw-r--r--sys/dev/pst/pst-raid.c375
4 files changed, 1653 insertions, 0 deletions
diff --git a/sys/dev/pst/pst-iop.c b/sys/dev/pst/pst-iop.c
new file mode 100644
index 0000000..dd372ef
--- /dev/null
+++ b/sys/dev/pst/pst-iop.c
@@ -0,0 +1,499 @@
+/*-
+ * Copyright (c) 2001,2002,2003 Søren Schmidt <sos@FreeBSD.org>
+ * 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. 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. 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 ``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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include "dev/pst/pst-iop.h"
+
+struct iop_request {
+ struct i2o_single_reply *reply;
+ u_int32_t mfa;
+};
+
+/* local vars */
+MALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver");
+
+int
+iop_init(struct iop_softc *sc)
+{
+ int mfa, timeout = 10000;
+
+ while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
+ DELAY(1000);
+ if (!timeout) {
+ printf("pstiop: no free mfa\n");
+ return 0;
+ }
+ iop_free_mfa(sc, mfa);
+
+ sc->reg->oqueue_intr_mask = 0xffffffff;
+
+ if (!iop_reset(sc)) {
+ printf("pstiop: no reset response\n");
+ return 0;
+ }
+
+ if (!iop_init_outqueue(sc)) {
+ printf("pstiop: init outbound queue failed\n");
+ return 0;
+ }
+
+ /* register iop_attach to be run when interrupts are enabled */
+ if (!(sc->iop_delayed_attach = (struct intr_config_hook *)
+ malloc(sizeof(struct intr_config_hook),
+ M_PSTIOP, M_NOWAIT | M_ZERO))) {
+ printf("pstiop: malloc of delayed attach hook failed\n");
+ return 0;
+ }
+ sc->iop_delayed_attach->ich_func = (void *)iop_attach;
+ sc->iop_delayed_attach->ich_arg = (void *)sc;
+ if (config_intrhook_establish(sc->iop_delayed_attach)) {
+ printf("pstiop: config_intrhook_establish failed\n");
+ free(sc->iop_delayed_attach, M_PSTIOP);
+ }
+ return 1;
+}
+
+void
+iop_attach(struct iop_softc *sc)
+{
+ int i;
+
+ if (sc->iop_delayed_attach) {
+ config_intrhook_disestablish(sc->iop_delayed_attach);
+ free(sc->iop_delayed_attach, M_PSTIOP);
+ sc->iop_delayed_attach = NULL;
+ }
+
+ if (!iop_get_lct(sc)) {
+ printf("pstiop: get LCT failed\n");
+ return;
+ }
+
+ /* figure out what devices are here and config as needed */
+ for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) {
+#ifdef PSTDEBUG
+ struct i2o_get_param_reply *reply;
+
+ printf("pstiop: LCT entry %d ", i);
+ printf("class=%04x ", sc->lct[i].class);
+ printf("sub=%04x ", sc->lct[i].sub_class);
+ printf("localtid=%04x ", sc->lct[i].local_tid);
+ printf("usertid=%04x ", sc->lct[i].user_tid);
+ printf("parentid=%04x\n", sc->lct[i].parent_tid);
+
+ if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid,
+ I2O_PARAMS_OPERATION_FIELD_GET,
+ I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) {
+ struct i2o_device_identity *ident =
+ (struct i2o_device_identity *)reply->result;
+ printf("pstiop: vendor=<%.16s> product=<%.16s>\n",
+ ident->vendor, ident->product);
+ printf("pstiop: description=<%.16s> revision=<%.8s>\n",
+ ident->description, ident->revision);
+ contigfree(reply, PAGE_SIZE, M_PSTIOP);
+ }
+#endif
+
+ if (sc->lct[i].user_tid != I2O_TID_NONE &&
+ sc->lct[i].user_tid != I2O_TID_HOST)
+ continue;
+
+ switch (sc->lct[i].class) {
+ case I2O_CLASS_DDM:
+ if (sc->lct[i].sub_class == I2O_SUBCLASS_ISM)
+ sc->ism = sc->lct[i].local_tid;
+ break;
+
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ pst_add_raid(sc, &sc->lct[i]);
+ break;
+ }
+ }
+
+ /* setup and enable interrupts */
+ bus_setup_intr(sc->dev, sc->r_irq, INTR_TYPE_BIO|INTR_ENTROPY|INTR_MPSAFE,
+ iop_intr, sc, &sc->handle);
+ sc->reg->oqueue_intr_mask = 0x0;
+}
+
+void
+iop_intr(void *data)
+{
+ struct iop_softc *sc = (struct iop_softc *)data;
+ struct i2o_single_reply *reply;
+ u_int32_t mfa;
+
+ /* we might get more than one finished request pr interrupt */
+ mtx_lock(&sc->mtx);
+ while (1) {
+ if ((mfa = sc->reg->oqueue) == 0xffffffff)
+ if ((mfa = sc->reg->oqueue) == 0xffffffff)
+ break;
+
+ reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase));
+
+ /* if this is an event register reply, shout! */
+ if (reply->function == I2O_UTIL_EVENT_REGISTER) {
+ struct i2o_util_event_reply_message *event =
+ (struct i2o_util_event_reply_message *)reply;
+
+ printf("pstiop: EVENT!! idx=%08x data=%08x\n",
+ event->event_mask, event->event_data[0]);
+ break;
+ }
+
+ /* if reply is a failurenotice we need to free the original mfa */
+ if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL)
+ iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa);
+
+ /* reply->initiator_context points to the service routine */
+ ((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *))
+ (reply->initiator_context))(sc, mfa, reply);
+ }
+ mtx_unlock(&sc->mtx);
+}
+
+int
+iop_reset(struct iop_softc *sc)
+{
+ struct i2o_exec_iop_reset_message *msg;
+ int mfa, timeout = 5000;
+ volatile u_int32_t reply = 0;
+
+ mfa = iop_get_mfa(sc);
+ msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa);
+ bzero(msg, sizeof(struct i2o_exec_iop_reset_message));
+ msg->version_offset = 0x1;
+ msg->message_flags = 0x0;
+ msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2;
+ msg->target_address = I2O_TID_IOP;
+ msg->initiator_address = I2O_TID_HOST;
+ msg->function = I2O_EXEC_IOP_RESET;
+ msg->status_word_low_addr = vtophys(&reply);
+ msg->status_word_high_addr = 0;
+
+ sc->reg->iqueue = mfa;
+
+ while (--timeout && !reply)
+ DELAY(1000);
+
+ /* wait for iqueue ready */
+ timeout = 10000;
+ while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
+ DELAY(1000);
+
+ iop_free_mfa(sc, mfa);
+ return reply;
+}
+
+int
+iop_init_outqueue(struct iop_softc *sc)
+{
+ struct i2o_exec_init_outqueue_message *msg;
+ int i, mfa, timeout = 5000;
+ volatile u_int32_t reply = 0;
+
+ if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT *
+ I2O_IOP_OUTBOUND_FRAME_SIZE,
+ M_PSTIOP, M_NOWAIT,
+ 0x00010000, 0xFFFFFFFF,
+ PAGE_SIZE, 0))) {
+ printf("pstiop: contigmalloc of outqueue buffers failed!\n");
+ return 0;
+ }
+ sc->phys_obase = vtophys(sc->obase);
+ mfa = iop_get_mfa(sc);
+ msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa);
+ bzero(msg, sizeof(struct i2o_exec_init_outqueue_message));
+ msg->version_offset = 0x61;
+ msg->message_flags = 0x0;
+ msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2;
+ msg->target_address = I2O_TID_IOP;
+ msg->initiator_address = I2O_TID_HOST;
+ msg->function = I2O_EXEC_OUTBOUND_INIT;
+ msg->host_pagesize = PAGE_SIZE;
+ msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */
+ msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t);
+ msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
+ msg->sgl[0].count = sizeof(reply);
+ msg->sgl[0].phys_addr[0] = vtophys(&reply);
+ msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB;
+ msg->sgl[1].count = 1;
+ msg->sgl[1].phys_addr[0] = 0;
+
+ sc->reg->iqueue = mfa;
+
+ /* wait for init to complete */
+ while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE)
+ DELAY(1000);
+
+ if (!timeout) {
+ printf("pstiop: timeout waiting for init-complete response\n");
+ iop_free_mfa(sc, mfa);
+ return 0;
+ }
+
+ /* now init our oqueue bufs */
+ for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) {
+ sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE);
+ DELAY(1000);
+ }
+
+ return 1;
+}
+
+int
+iop_get_lct(struct iop_softc *sc)
+{
+ struct i2o_exec_get_lct_message *msg;
+ struct i2o_get_lct_reply *reply;
+ int mfa;
+#define ALLOCSIZE (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry)))
+
+ if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
+ 0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
+ return 0;
+
+ mfa = iop_get_mfa(sc);
+ msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa);
+ bzero(msg, sizeof(struct i2o_exec_get_lct_message));
+ msg->version_offset = 0x61;
+ msg->message_flags = 0x0;
+ msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2;
+ msg->target_address = I2O_TID_IOP;
+ msg->initiator_address = I2O_TID_HOST;
+ msg->function = I2O_EXEC_LCT_NOTIFY;
+ msg->class = I2O_CLASS_MATCH_ANYCLASS;
+ msg->last_change_id = 0;
+
+ msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
+ msg->sgl.count = ALLOCSIZE;
+ msg->sgl.phys_addr[0] = vtophys(reply);
+
+ if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) {
+ contigfree(reply, ALLOCSIZE, M_PSTIOP);
+ return 0;
+ }
+ if (!(sc->lct = malloc(reply->table_size * sizeof(struct i2o_lct_entry),
+ M_PSTIOP, M_NOWAIT | M_ZERO))) {
+ contigfree(reply, ALLOCSIZE, M_PSTIOP);
+ return 0;
+ }
+ bcopy(&reply->entry[0], sc->lct,
+ reply->table_size * sizeof(struct i2o_lct_entry));
+ sc->lct_count = reply->table_size;
+ contigfree(reply, ALLOCSIZE, M_PSTIOP);
+ return 1;
+}
+
+struct i2o_get_param_reply *
+iop_get_util_params(struct iop_softc *sc, int target, int operation, int group)
+{
+ struct i2o_util_get_param_message *msg;
+ struct i2o_get_param_operation *param;
+ struct i2o_get_param_reply *reply;
+ int mfa;
+
+ if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
+ 0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
+ return NULL;
+
+ if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
+ 0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
+ return NULL;
+
+ mfa = iop_get_mfa(sc);
+ msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa);
+ bzero(msg, sizeof(struct i2o_util_get_param_message));
+ msg->version_offset = 0x51;
+ msg->message_flags = 0x0;
+ msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2;
+ msg->target_address = target;
+ msg->initiator_address = I2O_TID_HOST;
+ msg->function = I2O_UTIL_PARAMS_GET;
+ msg->operation_flags = 0;
+
+ param->operation_count = 1;
+ param->operation[0].operation = operation;
+ param->operation[0].group = group;
+ param->operation[0].field_count = 0xffff;
+
+ msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB;
+ msg->sgl[0].count = sizeof(struct i2o_get_param_operation);
+ msg->sgl[0].phys_addr[0] = vtophys(param);
+
+ msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
+ msg->sgl[1].count = PAGE_SIZE;
+ msg->sgl[1].phys_addr[0] = vtophys(reply);
+
+ if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) ||
+ reply->error_info_size) {
+ contigfree(reply, PAGE_SIZE, M_PSTIOP);
+ reply = NULL;
+ }
+ contigfree(param, PAGE_SIZE, M_PSTIOP);
+ return reply;
+}
+
+u_int32_t
+iop_get_mfa(struct iop_softc *sc)
+{
+ u_int32_t mfa;
+ int timeout = 10000;
+
+ while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) {
+ DELAY(1000);
+ timeout--;
+ }
+ if (!timeout)
+ printf("pstiop: no free mfa\n");
+ return mfa;
+}
+
+void
+iop_free_mfa(struct iop_softc *sc, int mfa)
+{
+ struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa);
+
+ bzero(msg, sizeof(struct i2o_basic_message));
+ msg->version = 0x01;
+ msg->message_flags = 0x0;
+ msg->message_size = sizeof(struct i2o_basic_message) >> 2;
+ msg->target_address = I2O_TID_IOP;
+ msg->initiator_address = I2O_TID_HOST;
+ msg->function = I2O_UTIL_NOP;
+ sc->reg->iqueue = mfa;
+}
+
+static void
+iop_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply)
+{
+ struct iop_request *request =
+ (struct iop_request *)reply->transaction_context;
+
+ request->reply = reply;
+ request->mfa = mfa;
+ wakeup(request);
+}
+
+int
+iop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg)
+{
+ struct i2o_single_reply *reply;
+ struct iop_request request;
+ u_int32_t out_mfa;
+ int status, timeout = 10000;
+
+ mtx_lock(&sc->mtx);
+ if (!(sc->reg->oqueue_intr_mask & 0x08)) {
+ msg->transaction_context = (u_int32_t)&request;
+ msg->initiator_context = (u_int32_t)iop_done;
+ sc->reg->iqueue = mfa;
+ if (msleep(&request, &sc->mtx, PRIBIO, "pstwt", 10 * hz)) {
+ printf("pstiop: timeout waiting for message response\n");
+ iop_free_mfa(sc, mfa);
+ mtx_unlock(&sc->mtx);
+ return -1;
+ }
+ status = request.reply->status;
+ sc->reg->oqueue = request.mfa;
+ }
+ else {
+ sc->reg->iqueue = mfa;
+ while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff))
+ DELAY(1000);
+ if (!timeout) {
+ printf("pstiop: timeout waiting for message response\n");
+ iop_free_mfa(sc, mfa);
+ mtx_unlock(&sc->mtx);
+ return -1;
+ }
+ reply = (struct i2o_single_reply *)(sc->obase+(out_mfa-sc->phys_obase));
+ status = reply->status;
+ sc->reg->oqueue = out_mfa;
+ }
+ mtx_unlock(&sc->mtx);
+ return status;
+}
+
+int
+iop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir)
+{
+ struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset);
+ u_int32_t sgl_count, sgl_phys;
+ int i = 0;
+
+ if (((uintptr_t)data & 3) || (count & 3)) {
+ printf("pstiop: non aligned DMA transfer attempted\n");
+ return 0;
+ }
+ if (!count) {
+ printf("pstiop: zero length DMA transfer attempted\n");
+ return 0;
+ }
+
+ sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
+ sgl_phys = vtophys(data);
+ sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END;
+ sgl->count = count;
+ data += sgl_count;
+ count -= sgl_count;
+
+ while (count) {
+ sgl->phys_addr[i] = sgl_phys;
+ sgl_phys = vtophys(data);
+ data += min(count, PAGE_SIZE);
+ count -= min(count, PAGE_SIZE);
+ if (++i >= I2O_SGL_MAX_SEGS) {
+ printf("pstiop: too many segments in SGL\n");
+ return 0;
+ }
+ }
+ sgl->phys_addr[i] = sgl_phys;
+ msg->message_size += i;
+ return 1;
+}
diff --git a/sys/dev/pst/pst-iop.h b/sys/dev/pst/pst-iop.h
new file mode 100644
index 0000000..9badbf8
--- /dev/null
+++ b/sys/dev/pst/pst-iop.h
@@ -0,0 +1,647 @@
+/*-
+ * Copyright (c) 2001,2002,2003 Søren Schmidt <sos@FreeBSD.org>
+ * 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. 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. 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 ``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 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.
+ *
+ * $FreeBSD$
+ */
+
+/* misc defines */
+MALLOC_DECLARE(M_PSTIOP);
+#define I2O_IOP_OUTBOUND_FRAME_COUNT 32
+#define I2O_IOP_OUTBOUND_FRAME_SIZE 0x20
+
+/* structure defs */
+struct out_mfa_buf {
+ u_int32_t buf[I2O_IOP_OUTBOUND_FRAME_SIZE];
+};
+
+struct iop_softc {
+ struct resource *r_mem;
+ struct resource *r_irq;
+ caddr_t ibase;
+ u_int32_t phys_ibase;
+ caddr_t obase;
+ u_int32_t phys_obase;
+ struct i2o_registers *reg;
+ struct i2o_status_get_reply *status;
+ int lct_count;
+ struct i2o_lct_entry *lct;
+ int ism;
+ device_t dev;
+ struct mtx mtx;
+ int outstanding;
+ void *handle;
+ struct intr_config_hook *iop_delayed_attach;
+};
+
+/* structure at start of IOP shared mem */
+struct i2o_registers {
+ volatile u_int32_t apic_select;
+ volatile u_int32_t reserved0;
+ volatile u_int32_t apic_winreg;
+ volatile u_int32_t reserved1;
+ volatile u_int32_t iqueue_reg0;
+ volatile u_int32_t iqueue_reg1;
+ volatile u_int32_t oqueue_reg0;
+ volatile u_int32_t oqueue_reg1;
+ volatile u_int32_t iqueue_event;
+ volatile u_int32_t iqueue_intr_status;
+ volatile u_int32_t iqueue_intr_mask;
+ volatile u_int32_t oqueue_event;
+ volatile u_int32_t oqueue_intr_status;
+ volatile u_int32_t oqueue_intr_mask;
+#define I2O_OUT_INTR_QUEUE 0x08
+#define I2O_OUT_INTR_BELL 0x04
+#define I2O_OUT_INTR_MSG1 0x02
+#define I2O_OUT_INTR_MSG0 0x01
+
+ volatile u_int64_t reserved2;
+ volatile u_int32_t iqueue;
+ volatile u_int32_t oqueue;
+ volatile u_int64_t reserved3;
+ volatile u_int64_t mac_addr;
+ volatile u_int32_t ip_addr;
+ volatile u_int32_t ip_mask;
+};
+
+/* Scatter/Gather List management */
+struct i2o_sgl {
+ u_int32_t count:24;
+#define I2O_SGL_CNT_MASK 0xffffff
+
+ u_int32_t flags:8;
+#define I2O_SGL_SIMPLE 0x10
+#define I2O_SGL_PAGELIST 0x20
+#define I2O_SGL_CHAIN 0x30
+#define I2O_SGL_ATTRIBUTE 0x7c
+#define I2O_SGL_BC0 0x01
+#define I2O_SGL_BC1 0x02
+#define I2O_SGL_DIR 0x04
+#define I2O_SGL_LA 0x08
+#define I2O_SGL_EOB 0x40
+#define I2O_SGL_END 0x80
+
+ u_int32_t phys_addr[1];
+} __packed;
+
+#define I2O_SGL_MAX_SEGS ((I2O_IOP_OUTBOUND_FRAME_SIZE - (8 + 2)) + 1)
+
+/* i2o command codes */
+#define I2O_UTIL_NOP 0x00
+#define I2O_UTIL_PARAMS_GET 0x06
+#define I2O_UTIL_CLAIM 0x09
+#define I2O_UTIL_CONFIG_DIALOG 0x10
+#define I2O_UTIL_EVENT_REGISTER 0x13
+#define I2O_BSA_BLOCK_READ 0x30
+#define I2O_BSA_BLOCK_WRITE 0x31
+#define I2O_BSA_CACHE_FLUSH 0x37
+#define I2O_EXEC_STATUS_GET 0xa0
+#define I2O_EXEC_OUTBOUND_INIT 0xa1
+#define I2O_EXEC_LCT_NOTIFY 0xa2
+#define I2O_EXEC_SYSTAB_SET 0xa3
+#define I2O_EXEC_IOP_RESET 0xbd
+#define I2O_EXEC_SYS_ENABLE 0xd1
+#define I2O_PRIVATE_MESSAGE 0xff
+
+/* basic message layout */
+struct i2o_basic_message {
+ u_int8_t version:4;
+ u_int8_t offset:4;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+} __packed;
+
+/* basic reply layout */
+struct i2o_single_reply {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+#define I2O_MESSAGE_FLAGS_STATIC 0x01
+#define I2O_MESSAGE_FLAGS_64BIT 0x02
+#define I2O_MESSAGE_FLAGS_MULTIPLE 0x10
+#define I2O_MESSAGE_FLAGS_FAIL 0x20
+#define I2O_MESSAGE_FLAGS_LAST 0x40
+#define I2O_MESSAGE_FLAGS_REPLY 0x80
+
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int16_t detailed_status;
+#define I2O_DETAIL_STATUS_SUCCESS 0x0000
+#define I2O_DETAIL_STATUS_BAD_KEY 0x0002
+#define I2O_DETAIL_STATUS_TCL_ERROR 0x0003
+#define I2O_DETAIL_STATUS_REPLY_BUFFER_FULL 0x0004
+#define I2O_DETAIL_STATUS_NO_SUCH_PAGE 0x0005
+#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_SOFT 0x0006
+#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_HARD 0x0007
+#define I2O_DETAIL_STATUS_CHAIN_BUFFER_TOO_LARGE 0x0009
+#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION 0x000a
+#define I2O_DETAIL_STATUS_DEVICE_LOCKED 0x000b
+#define I2O_DETAIL_STATUS_DEVICE_RESET 0x000c
+#define I2O_DETAIL_STATUS_INAPPROPRIATE_FUNCTION 0x000d
+#define I2O_DETAIL_STATUS_INVALID_INITIATOR_ADDRESS 0x000e
+#define I2O_DETAIL_STATUS_INVALID_MESSAGE_FLAGS 0x000f
+#define I2O_DETAIL_STATUS_INVALID_OFFSET 0x0010
+#define I2O_DETAIL_STATUS_INVALID_PARAMETER 0x0011
+#define I2O_DETAIL_STATUS_INVALID_REQUEST 0x0012
+#define I2O_DETAIL_STATUS_INVALID_TARGET_ADDRESS 0x0013
+#define I2O_DETAIL_STATUS_MESSAGE_TOO_LARGE 0x0014
+#define I2O_DETAIL_STATUS_MESSAGE_TOO_SMALL 0x0015
+#define I2O_DETAIL_STATUS_MISSING_PARAMETER 0x0016
+#define I2O_DETAIL_STATUS_TIMEOUT 0x0017
+#define I2O_DETAIL_STATUS_UNKNOWN_ERROR 0x0018
+#define I2O_DETAIL_STATUS_UNKNOWN_FUNCTION 0x0019
+#define I2O_DETAIL_STATUS_UNSUPPORTED_VERSION 0x001a
+#define I2O_DETAIL_STATUS_DEVICE_BUSY 0x001b
+#define I2O_DETAIL_STATUS_DEVICE_NOT_AVAILABLE 0x001c
+
+ u_int8_t retry_count;
+ u_int8_t status;
+#define I2O_REPLY_STATUS_SUCCESS 0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
+#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04
+#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
+#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06
+#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x08
+#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x09
+#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x0a
+#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0b
+#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80
+
+ u_int32_t donecount;
+} __packed;
+
+struct i2o_fault_reply {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int8_t lowest_version;
+ u_int8_t highest_version;
+ u_int8_t severity;
+#define I2O_SEVERITY_FORMAT_ERROR 0x01
+#define I2O_SEVERITY_PATH_ERROR 0x02
+#define I2O_SEVERITY_PATH_STATE 0x04
+#define I2O_SEVERITY_CONGESTION 0x08
+
+ u_int8_t failure_code;
+#define I2O_FAILURE_CODE_TRANSPORT_SERVICE_SUSPENDED 0x81
+#define I2O_FAILURE_CODE_TRANSPORT_SERVICE_TERMINATED 0x82
+#define I2O_FAILURE_CODE_TRANSPORT_CONGESTION 0x83
+#define I2O_FAILURE_CODE_TRANSPORT_FAIL 0x84
+#define I2O_FAILURE_CODE_TRANSPORT_STATE_ERROR 0x85
+#define I2O_FAILURE_CODE_TRANSPORT_TIME_OUT 0x86
+#define I2O_FAILURE_CODE_TRANSPORT_ROUTING_FAILURE 0x87
+#define I2O_FAILURE_CODE_TRANSPORT_INVALID_VERSION 0x88
+#define I2O_FAILURE_CODE_TRANSPORT_INVALID_OFFSET 0x89
+#define I2O_FAILURE_CODE_TRANSPORT_INVALID_MSG_FLAGS 0x8A
+#define I2O_FAILURE_CODE_TRANSPORT_FRAME_TOO_SMALL 0x8B
+#define I2O_FAILURE_CODE_TRANSPORT_FRAME_TOO_LARGE 0x8C
+#define I2O_FAILURE_CODE_TRANSPORT_INVALID_TARGET_ID 0x8D
+#define I2O_FAILURE_CODE_TRANSPORT_INVALID_INITIATOR_ID 0x8E
+#define I2O_FAILURE_CODE_TRANSPORT_INVALID_INITIATOR_CONTEXT 0x8F
+#define I2O_FAILURE_CODE_TRANSPORT_UNKNOWN_FAILURE 0xFF
+
+ u_int32_t failing_iop_id:12;
+ u_int32_t reserved:4;
+ u_int32_t failing_host_unit_id:16;
+ u_int32_t age_limit;
+ u_int64_t preserved_mfa;
+} __packed;
+
+struct i2o_exec_iop_reset_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int8_t reserved[16];
+ u_int32_t status_word_low_addr;
+ u_int32_t status_word_high_addr;
+} __packed;
+
+struct i2o_exec_status_get_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int8_t reserved[16];
+ u_int32_t reply_buf_low_addr;
+ u_int32_t reply_buf_high_addr;
+ u_int32_t reply_buf_length;
+} __packed;
+
+struct i2o_status_get_reply {
+ u_int16_t organization_id;
+ u_int16_t reserved;
+ u_int32_t iop_id:12;
+ u_int32_t reserved1:4;
+ u_int32_t host_unit_id:16;
+ u_int32_t segment_number:12;
+ u_int32_t i2o_version:4;
+ u_int32_t iop_state:8;
+#define I2O_IOP_STATE_INITIALIZING 0x01
+#define I2O_IOP_STATE_RESET 0x02
+#define I2O_IOP_STATE_HOLD 0x04
+#define I2O_IOP_STATE_READY 0x05
+#define I2O_IOP_STATE_OPERATIONAL 0x08
+#define I2O_IOP_STATE_FAILED 0x10
+#define I2O_IOP_STATE_FAULTED 0x11
+
+ u_int32_t messenger_type:8;
+ u_int16_t inbound_mframe_size;
+ u_int8_t init_code;
+ u_int8_t reserved2;
+ u_int32_t max_inbound_mframes;
+ u_int32_t current_ibound_mframes;
+ u_int32_t max_outbound_mframes;
+ u_int8_t product_idstring[24];
+ u_int32_t expected_lct_size;
+ u_int32_t iop_capabilities;
+ u_int32_t desired_private_memsize;
+ u_int32_t current_private_memsize;
+ u_int32_t current_private_membase;
+ u_int32_t desired_private_iosize;
+ u_int32_t current_private_iosize;
+ u_int32_t current_private_iobase;
+ u_int8_t reserved3[3];
+ u_int8_t sync_byte;
+} __packed;
+
+struct i2o_exec_init_outqueue_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int32_t host_pagesize;
+ u_int8_t init_code;
+ u_int8_t reserved;
+ u_int16_t queue_framesize;
+ struct i2o_sgl sgl[2];
+} __packed;
+
+#define I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS 0x01
+#define I2O_EXEC_OUTBOUND_INIT_REJECTED 0x02
+#define I2O_EXEC_OUTBOUND_INIT_FAILED 0x03
+#define I2O_EXEC_OUTBOUND_INIT_COMPLETE 0x04
+
+struct i2o_exec_systab_set_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int32_t iop_id:12;
+#define I2O_EXEC_SYS_TAB_IOP_ID_LOCAL_IOP 0x000
+#define I2O_EXEC_SYS_TAB_IOP_ID_LOCAL_HOST 0x001
+#define I2O_EXEC_SYS_TAB_IOP_ID_UNKNOWN_IOP 0xfff
+
+ u_int32_t reserved1:4;
+ u_int32_t host_unit_id:16;
+#define I2O_EXEC_SYS_TAB_HOST_UNIT_ID_LOCAL_UNIT 0x0000
+#define I2O_EXEC_SYS_TAB_HOST_UNIT_ID_UNKNOWN_UNIT 0xffff
+
+ u_int32_t segment_number:12;
+#define I2O_EXEC_SYS_TAB_SEG_NUMBER_LOCAL_SEGMENT 0x000
+#define I2O_EXEC_SYS_TAB_SEG_NUMBER_UNKNOWN_SEGMENT 0xfff
+
+ u_int32_t reserved2:4;
+ u_int32_t reserved3:8;
+ struct i2o_sgl sgl[3];
+} __packed;
+
+struct i2o_exec_systab {
+ u_int8_t entries;
+ u_int8_t version;
+#define I2O_RESOURCE_MANAGER_VERSION 0
+
+ u_int16_t reserved1;
+ u_int32_t change_id;
+ u_int64_t reserved2;
+ u_int16_t organization_id;
+ u_int16_t reserved3;
+ u_int32_t iop_id:12;
+ u_int32_t reserved4:20;
+ u_int32_t segment_number:12;
+ u_int32_t i2o_version:4;
+ u_int32_t iop_state:8;
+ u_int32_t messenger_type:8;
+ u_int16_t inbound_mframe_size;
+ u_int16_t reserved5;
+ u_int32_t last_changed;
+ u_int32_t iop_capabilities;
+ u_int64_t messenger_info;
+} __packed;
+
+struct i2o_exec_get_lct_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int32_t class;
+ u_int32_t last_change_id;
+ struct i2o_sgl sgl;
+} __packed;
+
+#define I2O_TID_IOP 0x000
+#define I2O_TID_HOST 0x001
+#define I2O_TID_NONE 0xfff
+
+struct i2o_lct_entry {
+ u_int32_t entry_size:16;
+ u_int32_t local_tid:12;
+ u_int32_t reserved:4;
+ u_int32_t change_id;
+ u_int32_t device_flags;
+ u_int32_t class:12;
+#define I2O_CLASS_EXECUTIVE 0x000
+#define I2O_CLASS_DDM 0x001
+#define I2O_CLASS_RANDOM_BLOCK_STORAGE 0x010
+#define I2O_CLASS_SEQUENTIAL_STORAGE 0x011
+#define I2O_CLASS_LAN 0x020
+#define I2O_CLASS_WAN 0x030
+#define I2O_CLASS_FIBRE_CHANNEL_PORT 0x040
+#define I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL 0x041
+#define I2O_CLASS_SCSI_PERIPHERAL 0x051
+#define I2O_CLASS_ATE_PORT 0x060
+#define I2O_CLASS_ATE_PERIPHERAL 0x061
+#define I2O_CLASS_FLOPPY_CONTROLLER 0x070
+#define I2O_CLASS_FLOPPY_DEVICE 0x071
+#define I2O_CLASS_BUS_ADAPTER_PORT 0x080
+#define I2O_CLASS_MATCH_ANYCLASS 0xffffffff
+
+ u_int32_t class_version:4;
+ u_int32_t class_org:16;
+ u_int32_t sub_class;
+#define I2O_SUBCLASS_i960 0x001
+#define I2O_SUBCLASS_HDM 0x020
+#define I2O_SUBCLASS_ISM 0x021
+
+ u_int32_t user_tid:12;
+ u_int32_t parent_tid:12;
+ u_int32_t bios_info:8;
+ u_int8_t identity_tag[8];
+ u_int32_t event_capabilities;
+} __packed;
+
+#define I2O_LCT_ENTRYSIZE (sizeof(struct i2o_lct_entry)/sizeof(u_int32_t))
+
+struct i2o_get_lct_reply {
+ u_int32_t table_size:16;
+ u_int32_t boot_device:12;
+ u_int32_t lct_version:4;
+ u_int32_t iop_flags;
+ u_int32_t current_change_id;
+ struct i2o_lct_entry entry[1];
+} __packed;
+
+struct i2o_util_get_param_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int32_t operation_flags;
+ struct i2o_sgl sgl[2];
+} __packed;
+
+struct i2o_get_param_template {
+ u_int16_t operation;
+#define I2O_PARAMS_OPERATION_FIELD_GET 0x0001
+#define I2O_PARAMS_OPERATION_LIST_GET 0x0002
+#define I2O_PARAMS_OPERATION_MORE_GET 0x0003
+#define I2O_PARAMS_OPERATION_SIZE_GET 0x0004
+#define I2O_PARAMS_OPERATION_TABLE_GET 0x0005
+#define I2O_PARAMS_OPERATION_FIELD_SET 0x0006
+#define I2O_PARAMS_OPERATION_LIST_SET 0x0007
+#define I2O_PARAMS_OPERATION_ROW_ADD 0x0008
+#define I2O_PARAMS_OPERATION_ROW_DELETE 0x0009
+#define I2O_PARAMS_OPERATION_TABLE_CLEAR 0x000A
+
+ u_int16_t group;
+#define I2O_BSA_DEVICE_INFO_GROUP_NO 0x0000
+#define I2O_BSA_OPERATIONAL_CONTROL_GROUP_NO 0x0001
+#define I2O_BSA_POWER_CONTROL_GROUP_NO 0x0002
+#define I2O_BSA_CACHE_CONTROL_GROUP_NO 0x0003
+#define I2O_BSA_MEDIA_INFO_GROUP_NO 0x0004
+#define I2O_BSA_ERROR_LOG_GROUP_NO 0x0005
+
+#define I2O_UTIL_PARAMS_DESCRIPTOR_GROUP_NO 0xF000
+#define I2O_UTIL_PHYSICAL_DEVICE_TABLE_GROUP_NO 0xF001
+#define I2O_UTIL_CLAIMED_TABLE_GROUP_NO 0xF002
+#define I2O_UTIL_USER_TABLE_GROUP_NO 0xF003
+#define I2O_UTIL_PRIVATE_MESSAGE_EXTENSIONS_GROUP_NO 0xF005
+#define I2O_UTIL_AUTHORIZED_USER_TABLE_GROUP_NO 0xF006
+#define I2O_UTIL_DEVICE_IDENTITY_GROUP_NO 0xF100
+#define I2O_UTIL_DDM_IDENTITY_GROUP_NO 0xF101
+#define I2O_UTIL_USER_INFORMATION_GROUP_NO 0xF102
+#define I2O_UTIL_SGL_OPERATING_LIMITS_GROUP_NO 0xF103
+#define I2O_UTIL_SENSORS_GROUP_NO 0xF200
+
+ u_int16_t field_count;
+ u_int16_t pad;
+} __packed;
+
+struct i2o_get_param_operation {
+ u_int16_t operation_count;
+ u_int16_t reserved;
+ struct i2o_get_param_template operation[1];
+} __packed;
+
+struct i2o_get_param_reply {
+ u_int16_t result_count;
+ u_int16_t reserved;
+ u_int16_t block_size;
+ u_int8_t block_status;
+ u_int8_t error_info_size;
+ u_int32_t result[1];
+} __packed;
+
+struct i2o_device_identity {
+ u_int32_t class;
+ u_int16_t owner;
+ u_int16_t parent;
+ u_int8_t vendor[16];
+ u_int8_t product[16];
+ u_int8_t description[16];
+ u_int8_t revision[8];
+ u_int8_t sn_format;
+ u_int8_t serial[256];
+} __packed;
+
+struct i2o_bsa_device {
+ u_int8_t device_type;
+ u_int8_t path_count;
+ u_int16_t power_state;
+ u_int32_t block_size;
+ u_int64_t capacity;
+ u_int32_t capabilities;
+ u_int32_t state;
+} __packed;
+
+struct i2o_util_claim_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int16_t claim_flags;
+ u_int8_t reserved;
+ u_int8_t claim_type;
+} __packed;
+
+struct i2o_util_event_register_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int32_t event_mask;
+} __packed;
+
+struct i2o_util_event_reply_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int32_t event_mask;
+ u_int32_t event_data[1];
+} __packed;
+
+struct i2o_util_config_dialog_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int32_t page_number;
+ struct i2o_sgl sgl[2];
+} __packed;
+
+struct i2o_private_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int16_t function_code;
+ u_int16_t organization_id;
+ struct i2o_sgl in_sgl;
+ struct i2o_sgl out_sgl;
+} __packed;
+
+struct i2o_bsa_rw_block_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int16_t control_flags;
+ u_int8_t time_multiplier;
+ u_int8_t fetch_ahead;
+ u_int32_t bytecount;
+ u_int64_t lba;
+ struct i2o_sgl sgl;
+} __packed;
+
+struct i2o_bsa_cache_flush_message {
+ u_int8_t version_offset;
+ u_int8_t message_flags;
+ u_int16_t message_size;
+ u_int32_t target_address:12;
+ u_int32_t initiator_address:12;
+ u_int32_t function:8;
+ u_int32_t initiator_context;
+ u_int32_t transaction_context;
+ u_int16_t control_flags;
+ u_int8_t time_multiplier;
+ u_int8_t reserved;
+} __packed;
+
+/* prototypes */
+int iop_init(struct iop_softc *);
+void iop_attach(struct iop_softc *);
+void iop_intr(void *);
+int iop_reset(struct iop_softc *);
+int iop_init_outqueue(struct iop_softc *);
+int iop_get_lct(struct iop_softc *);
+struct i2o_get_param_reply *iop_get_util_params(struct iop_softc *,int,int,int);
+u_int32_t iop_get_mfa(struct iop_softc *);
+void iop_free_mfa(struct iop_softc *, int);
+int iop_queue_wait_msg(struct iop_softc *, int, struct i2o_basic_message *);
+int iop_create_sgl(struct i2o_basic_message *, caddr_t, int, int);
+
+/* global prototypes */
+int pst_add_raid(struct iop_softc *, struct i2o_lct_entry *);
diff --git a/sys/dev/pst/pst-pci.c b/sys/dev/pst/pst-pci.c
new file mode 100644
index 0000000..47272dc
--- /dev/null
+++ b/sys/dev/pst/pst-pci.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2001,2002,2003 Søren Schmidt <sos@FreeBSD.org>
+ * 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. 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. 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 ``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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+
+#include "dev/pst/pst-iop.h"
+
+static int
+iop_pci_probe(device_t dev)
+{
+ /* tested with actual hardware kindly donated by Promise */
+ if (pci_get_devid(dev) == 0x19628086 && pci_get_subvendor(dev) == 0x105a) {
+ device_set_desc(dev, "Promise SuperTrak SX6000 ATA RAID controller");
+ return 0;
+ }
+
+ /* support the older SuperTrak 100 as well */
+ if (pci_get_devid(dev) == 0x19608086 && pci_get_subvendor(dev) == 0x105a) {
+ device_set_desc(dev, "Promise SuperTrak 100 ATA RAID controller");
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+iop_pci_attach(device_t dev)
+{
+ struct iop_softc *sc = device_get_softc(dev);
+ int rid;
+
+ bzero(sc, sizeof(struct iop_softc));
+
+ /* get resources */
+ rid = 0x10;
+ sc->r_mem =
+ bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE);
+
+ if (!sc->r_mem)
+ return 0;
+
+ rid = 0x00;
+ sc->r_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0,
+ 1, RF_SHAREABLE | RF_ACTIVE);
+
+ /* now setup the infrastructure to talk to the device */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 1) |
+ PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN, 1);
+
+ sc->ibase = rman_get_virtual(sc->r_mem);
+ sc->phys_ibase = vtophys(sc->ibase);
+ sc->reg = (struct i2o_registers *)sc->ibase;
+ sc->dev = dev;
+ mtx_init(&sc->mtx, "pst lock", MTX_DEF, 0);
+
+ if (!iop_init(sc))
+ return 0;
+ return bus_generic_attach(dev);
+}
+
+static int
+iop_pci_detach(device_t dev)
+{
+ struct iop_softc *sc = device_get_softc(dev);
+
+ bus_teardown_intr(dev, sc->r_irq, sc->handle);
+ bus_release_resource(dev, SYS_RES_IRQ, 0x00, sc->r_irq);
+ bus_release_resource(dev, SYS_RES_MEMORY, 0x10, sc->r_mem);
+ return bus_generic_detach(dev);
+}
+
+
+static device_method_t pst_pci_methods[] = {
+ DEVMETHOD(device_probe, iop_pci_probe),
+ DEVMETHOD(device_attach, iop_pci_attach),
+ DEVMETHOD(device_detach, iop_pci_detach),
+ { 0, 0 }
+};
+
+static driver_t pst_pci_driver = {
+ "pstpci",
+ pst_pci_methods,
+ sizeof(struct iop_softc),
+};
+
+static devclass_t pst_pci_devclass;
+
+DRIVER_MODULE(pstpci, pci, pst_pci_driver, pst_pci_devclass, 0, 0);
diff --git a/sys/dev/pst/pst-raid.c b/sys/dev/pst/pst-raid.c
new file mode 100644
index 0000000..957d3b7
--- /dev/null
+++ b/sys/dev/pst/pst-raid.c
@@ -0,0 +1,375 @@
+/*-
+ * Copyright (c) 2001,2002,2003 Søren Schmidt <sos@FreeBSD.org>
+ * 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. 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. 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 ``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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/conf.h>
+#include <sys/eventhandler.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <geom/geom_disk.h>
+
+#include "dev/pst/pst-iop.h"
+
+struct pst_softc {
+ struct iop_softc *iop;
+ struct i2o_lct_entry *lct;
+ struct i2o_bsa_device *info;
+ struct disk disk;
+ struct bio_queue_head queue;
+};
+
+struct pst_request {
+ struct pst_softc *psc; /* pointer to softc */
+ u_int32_t mfa; /* frame addreess */
+ struct callout_handle timeout_handle; /* handle for untimeout */
+ struct bio *bp; /* associated bio ptr */
+};
+
+/* prototypes */
+static disk_strategy_t pststrategy;
+static int pst_probe(device_t);
+static int pst_attach(device_t);
+static int pst_shutdown(device_t);
+static void pst_start(struct pst_softc *);
+static void pst_done(struct iop_softc *, u_int32_t, struct i2o_single_reply *);
+static int pst_rw(struct pst_request *);
+static void pst_timeout(struct pst_request *);
+static void bpack(int8_t *, int8_t *, int);
+
+/* local vars */
+static MALLOC_DEFINE(M_PSTRAID, "pst", "Promise SuperTrak RAID driver");
+
+int
+pst_add_raid(struct iop_softc *sc, struct i2o_lct_entry *lct)
+{
+ struct pst_softc *psc;
+ device_t child = device_add_child(sc->dev, "pst", -1);
+
+ if (!child)
+ return ENOMEM;
+ if (!(psc = malloc(sizeof(struct pst_softc),
+ M_PSTRAID, M_NOWAIT | M_ZERO))) {
+ device_delete_child(sc->dev, child);
+ return ENOMEM;
+ }
+ psc->iop = sc;
+ psc->lct = lct;
+ device_set_softc(child, psc);
+ return bus_generic_attach(sc->dev);
+}
+
+static int
+pst_probe(device_t dev)
+{
+ device_set_desc(dev, "Promise SuperTrak RAID");
+ return 0;
+}
+
+static int
+pst_attach(device_t dev)
+{
+ struct pst_softc *psc = device_get_softc(dev);
+ struct i2o_get_param_reply *reply;
+ struct i2o_device_identity *ident;
+ int lun = device_get_unit(dev);
+ int8_t name [32];
+
+ if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid,
+ I2O_PARAMS_OPERATION_FIELD_GET,
+ I2O_BSA_DEVICE_INFO_GROUP_NO)))
+ return ENODEV;
+
+ if (!(psc->info = (struct i2o_bsa_device *)
+ malloc(sizeof(struct i2o_bsa_device), M_PSTRAID, M_NOWAIT))) {
+ contigfree(reply, PAGE_SIZE, M_PSTRAID);
+ return ENOMEM;
+ }
+ bcopy(reply->result, psc->info, sizeof(struct i2o_bsa_device));
+ contigfree(reply, PAGE_SIZE, M_PSTRAID);
+
+ if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid,
+ I2O_PARAMS_OPERATION_FIELD_GET,
+ I2O_UTIL_DEVICE_IDENTITY_GROUP_NO)))
+ return ENODEV;
+ ident = (struct i2o_device_identity *)reply->result;
+#ifdef PSTDEBUG
+ printf("pst: vendor=<%.16s> product=<%.16s>\n",
+ ident->vendor, ident->product);
+ printf("pst: description=<%.16s> revision=<%.8s>\n",
+ ident->description, ident->revision);
+ printf("pst: capacity=%lld blocksize=%d\n",
+ psc->info->capacity, psc->info->block_size);
+#endif
+ bpack(ident->vendor, ident->vendor, 16);
+ bpack(ident->product, ident->product, 16);
+ sprintf(name, "%s %s", ident->vendor, ident->product);
+ contigfree(reply, PAGE_SIZE, M_PSTRAID);
+
+ bioq_init(&psc->queue);
+
+ psc->disk.d_name = "pst";
+ psc->disk.d_strategy = pststrategy;
+ psc->disk.d_maxsize = 64 * 1024; /*I2O_SGL_MAX_SEGS * PAGE_SIZE;*/
+ psc->disk.d_drv1 = psc;
+ disk_create(lun, &psc->disk, DISKFLAG_NOGIANT, NULL, NULL);
+
+ psc->disk.d_sectorsize = psc->info->block_size;
+ psc->disk.d_mediasize = psc->info->capacity;
+ psc->disk.d_fwsectors = 63;
+ psc->disk.d_fwheads = 255;
+
+ printf("pst%d: %lluMB <%.40s> [%lld/%d/%d] on %.16s\n", lun,
+ (unsigned long long)psc->info->capacity / (1024 * 1024),
+ name, psc->info->capacity/(512*255*63), 255, 63,
+ device_get_nameunit(psc->iop->dev));
+
+ EVENTHANDLER_REGISTER(shutdown_post_sync, pst_shutdown,
+ dev, SHUTDOWN_PRI_FIRST);
+ return 0;
+}
+
+static int
+pst_shutdown(device_t dev)
+{
+ struct pst_softc *psc = device_get_softc(dev);
+ struct i2o_bsa_cache_flush_message *msg;
+ int mfa;
+
+ mfa = iop_get_mfa(psc->iop);
+ msg = (struct i2o_bsa_cache_flush_message *)(psc->iop->ibase + mfa);
+ bzero(msg, sizeof(struct i2o_bsa_cache_flush_message));
+ msg->version_offset = 0x01;
+ msg->message_flags = 0x0;
+ msg->message_size = sizeof(struct i2o_bsa_cache_flush_message) >> 2;
+ msg->target_address = psc->lct->local_tid;
+ msg->initiator_address = I2O_TID_HOST;
+ msg->function = I2O_BSA_CACHE_FLUSH;
+ msg->control_flags = 0x0; /* 0x80 = post progress reports */
+ if (iop_queue_wait_msg(psc->iop, mfa, (struct i2o_basic_message *)msg))
+ printf("pst: shutdown failed!\n");
+ return 0;
+}
+
+static void
+pststrategy(struct bio *bp)
+{
+ struct pst_softc *psc = bp->bio_disk->d_drv1;
+
+ mtx_lock(&psc->iop->mtx);
+ bioq_disksort(&psc->queue, bp);
+ pst_start(psc);
+ mtx_unlock(&psc->iop->mtx);
+}
+
+static void
+pst_start(struct pst_softc *psc)
+{
+ struct pst_request *request;
+ struct bio *bp;
+ u_int32_t mfa;
+
+ if (psc->iop->outstanding < (I2O_IOP_OUTBOUND_FRAME_COUNT - 1) &&
+ (bp = bioq_first(&psc->queue))) {
+ if ((mfa = iop_get_mfa(psc->iop)) != 0xffffffff) {
+ bioq_remove(&psc->queue, bp);
+ if (!(request = malloc(sizeof(struct pst_request),
+ M_PSTRAID, M_NOWAIT | M_ZERO))) {
+ printf("pst: out of memory in start\n");
+ biofinish(request->bp, NULL, ENOMEM);
+ iop_free_mfa(psc->iop, mfa);
+ return;
+ }
+ psc->iop->outstanding++;
+ request->psc = psc;
+ request->mfa = mfa;
+ request->bp = bp;
+ if (pst_rw(request)) {
+ biofinish(request->bp, NULL, EIO);
+ iop_free_mfa(request->psc->iop, request->mfa);
+ psc->iop->outstanding--;
+ free(request, M_PSTRAID);
+ }
+ }
+ }
+}
+
+static void
+pst_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply)
+{
+ struct pst_request *request =
+ (struct pst_request *)reply->transaction_context;
+ struct pst_softc *psc = request->psc;
+
+ untimeout((timeout_t *)pst_timeout, request, request->timeout_handle);
+ request->bp->bio_resid = request->bp->bio_bcount - reply->donecount;
+ biofinish(request->bp, NULL, reply->status ? EIO : 0);
+ free(request, M_PSTRAID);
+ psc->iop->reg->oqueue = mfa;
+ psc->iop->outstanding--;
+ pst_start(psc);
+}
+
+int
+pst_rw(struct pst_request *request)
+{
+ struct i2o_bsa_rw_block_message *msg;
+ int sgl_flag;
+
+ msg = (struct i2o_bsa_rw_block_message *)
+ (request->psc->iop->ibase + request->mfa);
+ bzero(msg, sizeof(struct i2o_bsa_rw_block_message));
+ msg->version_offset = 0x81;
+ msg->message_flags = 0x0;
+ msg->message_size = sizeof(struct i2o_bsa_rw_block_message) >> 2;
+ msg->target_address = request->psc->lct->local_tid;
+ msg->initiator_address = I2O_TID_HOST;
+ switch (request->bp->bio_cmd) {
+ case BIO_READ:
+ msg->function = I2O_BSA_BLOCK_READ;
+ msg->control_flags = 0x0; /* 0x0c = read cache + readahead */
+ msg->fetch_ahead = 0x0; /* 8 Kb */
+ sgl_flag = 0;
+ break;
+ case BIO_WRITE:
+ msg->function = I2O_BSA_BLOCK_WRITE;
+ msg->control_flags = 0x0; /* 0x10 = write behind cache */
+ msg->fetch_ahead = 0x0;
+ sgl_flag = I2O_SGL_DIR;
+ break;
+ default:
+ printf("pst: unknown command type 0x%02x\n", request->bp->bio_cmd);
+ return -1;
+ }
+ msg->initiator_context = (u_int32_t)pst_done;
+ msg->transaction_context = (u_int32_t)request;
+ msg->time_multiplier = 1;
+ msg->bytecount = request->bp->bio_bcount;
+ msg->lba = ((u_int64_t)request->bp->bio_pblkno) * (DEV_BSIZE * 1LL);
+
+ if (!iop_create_sgl((struct i2o_basic_message *)msg, request->bp->bio_data,
+ request->bp->bio_bcount, sgl_flag))
+ return -1;
+
+ request->psc->iop->reg->iqueue = request->mfa;
+
+ if (dumping)
+ request->timeout_handle.callout = NULL;
+ else
+ request->timeout_handle =
+ timeout((timeout_t*)pst_timeout, request, 10 * hz);
+ return 0;
+}
+
+static void
+pst_timeout(struct pst_request *request)
+{
+ printf("pst: timeout mfa=0x%08x cmd=0x%02x\n",
+ request->mfa, request->bp->bio_cmd);
+ mtx_lock(&request->psc->iop->mtx);
+ iop_free_mfa(request->psc->iop, request->mfa);
+ if ((request->mfa = iop_get_mfa(request->psc->iop)) == 0xffffffff) {
+ printf("pst: timeout no mfa possible\n");
+ biofinish(request->bp, NULL, EIO);
+ request->psc->iop->outstanding--;
+ mtx_unlock(&request->psc->iop->mtx);
+ return;
+ }
+ if (dumping)
+ request->timeout_handle.callout = NULL;
+ else
+ request->timeout_handle =
+ timeout((timeout_t*)pst_timeout, request, 10 * hz);
+ if (pst_rw(request)) {
+ iop_free_mfa(request->psc->iop, request->mfa);
+ biofinish(request->bp, NULL, EIO);
+ request->psc->iop->outstanding--;
+ }
+ mtx_unlock(&request->psc->iop->mtx);
+}
+
+static void
+bpack(int8_t *src, int8_t *dst, int len)
+{
+ int i, j, blank;
+ int8_t *ptr, *buf = dst;
+
+ for (i = j = blank = 0 ; i < len; i++) {
+ if (blank && src[i] == ' ')
+ continue;
+ if (blank && src[i] != ' ') {
+ dst[j++] = src[i];
+ blank = 0;
+ continue;
+ }
+ if (src[i] == ' ') {
+ blank = 1;
+ if (i == 0)
+ continue;
+ }
+ dst[j++] = src[i];
+ }
+ if (j < len)
+ dst[j] = 0x00;
+ for (ptr = buf; ptr < buf+len; ++ptr)
+ if (!*ptr)
+ *ptr = ' ';
+ for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
+ *ptr = 0;
+}
+
+static device_method_t pst_methods[] = {
+ DEVMETHOD(device_probe, pst_probe),
+ DEVMETHOD(device_attach, pst_attach),
+ { 0, 0 }
+};
+
+static driver_t pst_driver = {
+ "pst",
+ pst_methods,
+ sizeof(struct pst_softc),
+};
+
+static devclass_t pst_devclass;
+
+DRIVER_MODULE(pst, pstpci, pst_driver, pst_devclass, 0, 0);
OpenPOWER on IntegriCloud