diff --git a/sys/dev/pst/pst-iop.c b/sys/dev/pst/pst-iop.c new file mode 100644 index 000000000000..85a1b3b4f2ad --- /dev/null +++ b/sys/dev/pst/pst-iop.c @@ -0,0 +1,454 @@ +/*- + * Copyright (c) 2001,2002 Søren Schmidt + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev/pst/pst-iop.h" + +/* 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_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, + 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; + + if ((mfa = sc->reg->oqueue) == 0xffffffff) { + if ((mfa = sc->reg->oqueue) == 0xffffffff) { + printf("pstiop: no mfa on interrupt ?\n"); + return; + } + } + reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase)); + + /* if this is a 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]); + return; + } + + /* 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); +} + +int +iop_reset(struct iop_softc *sc) +{ + struct i2o_exec_iop_reset_message *msg; + int mfa, timeout = 5000; + 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; + u_int32_t reply = 0; + + if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT * + I2O_IOP_OUTBOUND_FRAME_SIZE, + M_PSTIOP, M_NOWAIT, + 0, 0xFFFFFFFF, sizeof(u_int32_t), 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); + } + + iop_free_mfa(sc, mfa); + 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, + 0, 0xFFFFFFFF, sizeof(u_int32_t), 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, + 0, 0xFFFFFFFF, sizeof(u_int32_t), 0))) + return NULL; + + if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO, + 0, 0xFFFFFFFF, sizeof(u_int32_t), 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; +} + +int +iop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg) +{ + struct i2o_single_reply *reply; + int out_mfa, status, timeout = 10000; + + 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); + return -1; + } + + reply = (struct i2o_single_reply *)(sc->obase + (out_mfa - sc->phys_obase)); + status = reply->status; + sc->reg->oqueue = out_mfa; + 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 000000000000..c3cceffb1535 --- /dev/null +++ b/sys/dev/pst/pst-iop.h @@ -0,0 +1,627 @@ +/*- + * Copyright (c) 2001,2002 Søren Schmidt + * 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; + device_t dev; + 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]; +} __attribute__((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 + +/* 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; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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]; +} __attribute__((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]; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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]; +} __attribute__((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]; +} __attribute__((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; +} __attribute__((packed)); + +struct i2o_get_param_operation { + u_int16_t operation_count; + u_int16_t reserved; + struct i2o_get_param_template operation[1]; +} __attribute__((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]; +} __attribute__((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]; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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]; +} __attribute__((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]; +} __attribute__((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; +} __attribute__((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; +} __attribute__((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 000000000000..3bba025134e4 --- /dev/null +++ b/sys/dev/pst/pst-pci.c @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2001,2002 Søren Schmidt + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } + + /* this should work as well (not tested no hardware) */ + if (pci_get_devid(dev) == 0x09628086 && 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; + + if (!iop_init(sc)) + return 0; + + return bus_generic_attach(dev); +} + +static device_method_t pst_pci_methods[] = { + DEVMETHOD(device_probe, iop_pci_probe), + DEVMETHOD(device_attach, iop_pci_attach), + { 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 000000000000..9964dd28d497 --- /dev/null +++ b/sys/dev/pst/pst-raid.c @@ -0,0 +1,401 @@ +/*- + * Copyright (c) 2001,2002 Søren Schmidt + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev/pst/pst-iop.h" + +/* device structures */ +static d_strategy_t pststrategy; +static struct cdevsw pst_cdevsw = { + /* open */ nullopen, + /* close */ nullclose, + /* read */ physread, + /* write */ physwrite, + /* ioctl */ noioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strat */ pststrategy, + /* name */ "pst", + /* maj */ 200, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ D_DISK, +}; +static struct cdevsw pstdisk_cdevsw; + +struct pst_softc { + struct iop_softc *iop; + struct i2o_lct_entry *lct; + struct i2o_bsa_device *info; + dev_t device; + struct devstat stats; + struct disk disk; + struct bio_queue_head queue; + struct mtx mtx; + int outstanding; +}; + +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 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; + psc = malloc(sizeof(struct pst_softc), M_PSTRAID, M_NOWAIT | M_ZERO); + 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); + mtx_init(&psc->mtx, "pst lock", MTX_DEF, 0); + + psc->device = disk_create(lun, &psc->disk, 0, &pst_cdevsw, &pstdisk_cdevsw); + psc->device->si_drv1 = psc; + psc->device->si_iosize_max = 64 * 1024; /*I2O_SGL_MAX_SEGS * PAGE_SIZE;*/ + + bzero(&psc->disk.d_label, sizeof(struct disklabel)); + psc->disk.d_label.d_secsize = psc->info->block_size; + psc->disk.d_label.d_nsectors = 63; + psc->disk.d_label.d_ntracks = 255; + psc->disk.d_label.d_ncylinders = + (psc->info->capacity / psc->info->block_size) / (255 * 63); + psc->disk.d_label.d_secpercyl = 255 * 63; + psc->disk.d_label.d_secperunit = + psc->info->capacity / psc->info->block_size; + + devstat_add_entry(&psc->stats, "pst", lun, psc->info->block_size, + DEVSTAT_NO_ORDERED_TAGS, + DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, + DEVSTAT_PRIORITY_DISK); + + printf("pst%d: %lluMB <%.40s> [%d/%d/%d] on %.16s\n", lun, + (unsigned long long)psc->disk.d_label.d_secperunit / (1024 * 2), + name, psc->disk.d_label.d_ncylinders, 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_dev->si_drv1; + + mtx_lock(&psc->mtx); + bioqdisksort(&psc->queue, bp); + pst_start(psc); + mtx_unlock(&psc->mtx); +} + +static void +pst_start(struct pst_softc *psc) +{ + struct pst_request *request; + struct bio *bp; + u_int32_t mfa; + + if (psc->outstanding < (I2O_IOP_OUTBOUND_FRAME_COUNT - 1) && + (bp = bioq_first(&psc->queue))) { + if ((mfa = iop_get_mfa(psc->iop)) != 0xffffffff) { + if (!(request = malloc(sizeof(struct pst_request), + M_PSTRAID, M_NOWAIT | M_ZERO))) { + printf("pst: out of memory in start\n"); + iop_free_mfa(psc->iop, mfa); + return; + } + psc->outstanding++; + request->psc = psc; + request->mfa = mfa; + request->bp = bp; + if (dumping) + request->timeout_handle.callout = NULL; + else + request->timeout_handle = + timeout((timeout_t*)pst_timeout, request, 20 * hz); + bioq_remove(&psc->queue, bp); + devstat_start_transaction(&psc->stats); + if (pst_rw(request)) { + biofinish(request->bp, &psc->stats, EIO); + iop_free_mfa(request->psc->iop, request->mfa); + psc->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, &psc->stats, reply->status ? EIO : 0); + free(request, M_PSTRAID); + mtx_lock(&psc->mtx); + psc->iop->reg->oqueue = mfa; + psc->outstanding--; + pst_start(psc); + mtx_unlock(&psc->mtx); +} + +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->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, &request->psc->stats, EIO); + request->psc->outstanding--; + mtx_unlock(&request->psc->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, &request->psc->stats, EIO); + request->psc->outstanding--; + } + mtx_unlock(&request->psc->mtx); +} + +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\n"); + 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; + return 0; +} + +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);