summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/gdt_common.c1278
-rw-r--r--sys/dev/ic/gdtreg.h299
-rw-r--r--sys/dev/ic/gdtvar.h272
-rw-r--r--sys/dev/pci/files.pci7
-rw-r--r--sys/dev/pci/gdt_pci.c822
-rw-r--r--sys/dev/pci/pcidevs10
6 files changed, 2682 insertions, 6 deletions
diff --git a/sys/dev/ic/gdt_common.c b/sys/dev/ic/gdt_common.c
new file mode 100644
index 00000000000..51a4d2ba48b
--- /dev/null
+++ b/sys/dev/ic/gdt_common.c
@@ -0,0 +1,1278 @@
+/* $OpenBSD: gdt_common.c,v 1.1 2000/02/07 00:33:02 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niklas Hallqvist.
+ * 4. 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.
+ */
+
+/*
+ * This driver would not have written if it was not for the hardware donations
+ * from both ICP-Vortex and Öko.neT. I want to thank them for their support.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_disk.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/gdtreg.h>
+#include <dev/ic/gdtvar.h>
+
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+int gdt_async_event __P((struct gdt_softc *, int));
+void gdt_chain __P((struct gdt_softc *));
+void gdt_clear_events __P((struct gdt_softc *));
+void gdt_copy_internal_data __P((struct scsi_xfer *, u_int8_t *, size_t));
+struct scsi_xfer *gdt_dequeue __P((struct gdt_softc *));
+void gdt_enqueue __P((struct gdt_softc *, struct scsi_xfer *, int));
+void gdt_enqueue_ccb __P((struct gdt_softc *, struct gdt_ccb *));
+void gdt_eval_mapping __P((u_int32_t, int *, int *, int *));
+int gdt_exec_ccb __P((struct gdt_ccb *));
+void gdt_free_ccb __P((struct gdt_softc *, struct gdt_ccb *));
+struct gdt_ccb *gdt_get_ccb __P((struct gdt_softc *, int));
+int gdt_internal_cache_cmd __P((struct scsi_xfer *));
+int gdt_internal_cmd __P((struct gdt_softc *, u_int8_t, u_int16_t,
+ u_int32_t, u_int32_t, u_int32_t));
+int gdt_raw_scsi_cmd __P((struct scsi_xfer *));
+int gdt_scsi_cmd __P((struct scsi_xfer *));
+void gdt_start_ccbs __P((struct gdt_softc *));
+int gdt_sync_event __P((struct gdt_softc *, int, u_int8_t,
+ struct scsi_xfer *));
+void gdt_timeout __P((void *));
+int gdt_wait __P((struct gdt_softc *, struct gdt_ccb *, int));
+void gdt_watchdog __P((void *));
+
+struct cfdriver gdt_cd = {
+ NULL, "gdt", DV_DULL
+};
+
+struct scsi_adapter gdt_switch = {
+ gdt_scsi_cmd, gdtminphys, 0, 0,
+};
+
+struct scsi_adapter gdt_raw_switch = {
+ gdt_raw_scsi_cmd, gdtminphys, 0, 0,
+};
+
+struct scsi_device gdt_dev = {
+ NULL, NULL, NULL, NULL
+};
+
+u_int8_t gdt_polling;
+u_int8_t gdt_from_wait;
+struct gdt_softc *gdt_wait_gdt;
+int gdt_wait_index;
+#ifdef GDT_DEBUG
+int gdt_debug = GDT_DEBUG;
+#endif
+
+int
+gdt_attach(gdt)
+ struct gdt_softc *gdt;
+{
+ u_int16_t cdev_cnt;
+ int i, id, drv_cyls, drv_hds, drv_secs;
+
+ gdt_polling = 1;
+ gdt_from_wait = 0;
+ gdt_clear_events(gdt);
+
+ TAILQ_INIT(&gdt->sc_free_ccb);
+ TAILQ_INIT(&gdt->sc_ccbq);
+ LIST_INIT(&gdt->sc_queue);
+
+ /* Initialize the ccbs */
+ for (i = 0; i < GDT_MAXCMDS; i++) {
+ gdt->sc_ccbs[i].gc_cmd_index = i + 2;
+ (void)gdt_ccb_set_cmd(gdt->sc_ccbs + i, GDT_GCF_UNUSED);
+ TAILQ_INSERT_HEAD(&gdt->sc_free_ccb, &gdt->sc_ccbs[i],
+ gc_chain);
+ }
+
+ /* Fill in the prototype scsi_link. */
+ gdt->sc_link.adapter_softc = gdt;
+ gdt->sc_link.adapter = &gdt_switch;
+ gdt->sc_link.adapter_target = 7;
+ gdt->sc_link.device = &gdt_dev;
+ gdt->sc_link.openings = GDT_MAXCMDS; /* XXX what is optimal? */
+ gdt->sc_link.adapter_buswidth =
+ (gdt->sc_class & GDT_FC) ? GDT_MAXID : GDT_MAX_HDRIVES;
+
+ if (!gdt_internal_cmd(gdt, GDT_SCREENSERVICE, GDT_INIT, 0, 0, 0)) {
+ printf("screen service initialization error %d\n",
+ gdt->sc_status);
+ return (1);
+ }
+
+ if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_INIT, GDT_LINUX_OS, 0,
+ 0)) {
+ printf("cache service initialization error %d\n",
+ gdt->sc_status);
+ return (1);
+ }
+
+ if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_MOUNT, 0xffff, 1,
+ 0)) {
+ printf("cache service mount error %d\n",
+ gdt->sc_status);
+ return (1);
+ }
+
+ if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_INIT, GDT_LINUX_OS, 0,
+ 0)) {
+ printf("cache service post-mount initialization error %d\n",
+ gdt->sc_status);
+ return (1);
+ }
+ cdev_cnt = (u_int16_t)gdt->sc_info;
+
+ /* Detect number of busses */
+ gdt_enc32(gdt->sc_scratch + GDT_IOC_VERSION, GDT_IOC_NEWEST);
+ gdt->sc_scratch[GDT_IOC_LIST_ENTRIES] = GDT_MAXBUS;
+ gdt->sc_scratch[GDT_IOC_FIRST_CHAN] = 0;
+ gdt->sc_scratch[GDT_IOC_LAST_CHAN] = GDT_MAXBUS - 1;
+ gdt_enc32(gdt->sc_scratch + GDT_IOC_LIST_OFFSET, GDT_IOC_HDR_SZ);
+ if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
+ GDT_IOCHAN_RAW_DESC, GDT_INVALID_CHANNEL,
+ GDT_IOC_HDR_SZ + GDT_RAWIOC_SZ)) {
+ gdt->sc_bus_cnt = gdt->sc_scratch[GDT_IOC_CHAN_COUNT];
+ for (i = 0; i < gdt->sc_bus_cnt; i++) {
+ id = gdt->sc_scratch[GDT_IOC_HDR_SZ +
+ i * GDT_RAWIOC_SZ + GDT_RAWIOC_PROC_ID];
+ gdt->sc_bus_id[id] = id < GDT_MAXID ? id : 0xff;
+ }
+
+ } else {
+ /* New method failed, use fallback. */
+ gdt_enc32(gdt->sc_scratch + GDT_GETCH_CHANNEL_NO, i);
+ for (i = 0; i < GDT_MAXBUS; i++) {
+ if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
+ GDT_SCSI_CHAN_CNT | GDT_L_CTRL_PATTERN,
+ GDT_IO_CHANNEL | GDT_INVALID_CHANNEL,
+ GDT_GETCH_SZ)) {
+ if (i == 0) {
+ printf("cannot get channel count, "
+ "error %d\n", gdt->sc_status);
+ return (1);
+ }
+ break;
+ }
+ gdt->sc_bus_id[i] =
+ (gdt->sc_scratch[GDT_GETCH_SIOP_ID] < GDT_MAXID) ?
+ gdt->sc_scratch[GDT_GETCH_SIOP_ID] : 0xff;
+ }
+ gdt->sc_bus_cnt = i;
+ }
+
+ /* Read cache confgiuration */
+ if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL, GDT_CACHE_INFO,
+ GDT_INVALID_CHANNEL, GDT_CINFO_SZ)) {
+ printf("cannot get cache info, error %d\n", gdt->sc_status);
+ return (1);
+ }
+ gdt->sc_cpar.cp_version =
+ gdt_dec32(gdt->sc_scratch + GDT_CPAR_VERSION);
+ gdt->sc_cpar.cp_state = gdt_dec16(gdt->sc_scratch + GDT_CPAR_STATE);
+ gdt->sc_cpar.cp_strategy =
+ gdt_dec16(gdt->sc_scratch + GDT_CPAR_STRATEGY);
+ gdt->sc_cpar.cp_write_back =
+ gdt_dec16(gdt->sc_scratch + GDT_CPAR_WRITE_BACK);
+ gdt->sc_cpar.cp_block_size =
+ gdt_dec16(gdt->sc_scratch + GDT_CPAR_BLOCK_SIZE);
+
+ /* Read board information and features */
+ gdt->sc_more_proc = 0;
+ if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL, GDT_BOARD_INFO,
+ GDT_INVALID_CHANNEL, GDT_BINFO_SZ)) {
+ /* XXX A lot of these assignments can probably go later */
+ gdt->sc_binfo.bi_ser_no =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_SER_NO);
+ bcopy(gdt->sc_scratch + GDT_BINFO_OEM_ID,
+ gdt->sc_binfo.bi_oem_id, sizeof gdt->sc_binfo.bi_oem_id);
+ gdt->sc_binfo.bi_ep_flags =
+ gdt_dec16(gdt->sc_scratch + GDT_BINFO_EP_FLAGS);
+ gdt->sc_binfo.bi_proc_id =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_PROC_ID);
+ gdt->sc_binfo.bi_memsize =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_MEMSIZE);
+ gdt->sc_binfo.bi_mem_banks =
+ gdt->sc_scratch[GDT_BINFO_MEM_BANKS];
+ gdt->sc_binfo.bi_chan_type =
+ gdt->sc_scratch[GDT_BINFO_CHAN_TYPE];
+ gdt->sc_binfo.bi_chan_count =
+ gdt->sc_scratch[GDT_BINFO_CHAN_COUNT];
+ gdt->sc_binfo.bi_rdongle_pres =
+ gdt->sc_scratch[GDT_BINFO_RDONGLE_PRES];
+ gdt->sc_binfo.bi_epr_fw_ver =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_EPR_FW_VER);
+ gdt->sc_binfo.bi_upd_fw_ver =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_UPD_FW_VER);
+ gdt->sc_binfo.bi_upd_revision =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_UPD_REVISION);
+ bcopy(gdt->sc_scratch + GDT_BINFO_TYPE_STRING,
+ gdt->sc_binfo.bi_type_string,
+ sizeof gdt->sc_binfo.bi_type_string);
+ bcopy(gdt->sc_scratch + GDT_BINFO_RAID_STRING,
+ gdt->sc_binfo.bi_raid_string,
+ sizeof gdt->sc_binfo.bi_raid_string);
+ gdt->sc_binfo.bi_update_pres =
+ gdt->sc_scratch[GDT_BINFO_UPDATE_PRES];
+ gdt->sc_binfo.bi_xor_pres =
+ gdt->sc_scratch[GDT_BINFO_XOR_PRES];
+ gdt->sc_binfo.bi_prom_type =
+ gdt->sc_scratch[GDT_BINFO_PROM_TYPE];
+ gdt->sc_binfo.bi_prom_count =
+ gdt->sc_scratch[GDT_BINFO_PROM_COUNT];
+ gdt->sc_binfo.bi_dup_pres =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_DUP_PRES);
+ gdt->sc_binfo.bi_chan_pres =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_CHAN_PRES);
+ gdt->sc_binfo.bi_mem_pres =
+ gdt_dec32(gdt->sc_scratch + GDT_BINFO_MEM_PRES);
+ gdt->sc_binfo.bi_ft_bus_system =
+ gdt->sc_scratch[GDT_BINFO_FT_BUS_SYSTEM];
+ gdt->sc_binfo.bi_subtype_valid =
+ gdt->sc_scratch[GDT_BINFO_SUBTYPE_VALID];
+ gdt->sc_binfo.bi_board_subtype =
+ gdt->sc_scratch[GDT_BINFO_BOARD_SUBTYPE];
+ gdt->sc_binfo.bi_rampar_pres =
+ gdt->sc_scratch[GDT_BINFO_RAMPAR_PRES];
+
+ if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
+ GDT_BOARD_FEATURES, GDT_INVALID_CHANNEL, GDT_BFEAT_SZ)) {
+ gdt->sc_bfeat.bf_chaining =
+ gdt->sc_scratch[GDT_BFEAT_CHAINING];
+ gdt->sc_bfeat.bf_striping =
+ gdt->sc_scratch[GDT_BFEAT_STRIPING];
+ gdt->sc_bfeat.bf_mirroring =
+ gdt->sc_scratch[GDT_BFEAT_MIRRORING];
+ gdt->sc_bfeat.bf_raid =
+ gdt->sc_scratch[GDT_BFEAT_RAID];
+ gdt->sc_more_proc = 1;
+ }
+ } else {
+ /* XXX Not implemented yet */
+ }
+
+ /* Read more information */
+ if (gdt->sc_more_proc) {
+ /* XXX Not implemented yet */
+ }
+
+ if (!gdt_internal_cmd(gdt, GDT_SCSIRAWSERVICE, GDT_INIT, 0, 0, 0)) {
+ printf("raw service initialization error %d\n",
+ gdt->sc_status);
+ return (1);
+ }
+
+ /* Set/get features raw service (scatter/gather) */
+ gdt->sc_raw_feat = 0;
+ if (gdt_internal_cmd(gdt, GDT_SCSIRAWSERVICE, GDT_SET_FEAT,
+ GDT_SCATTER_GATHER, 0, 0))
+ if (gdt_internal_cmd(gdt, GDT_SCSIRAWSERVICE, GDT_GET_FEAT, 0,
+ 0, 0))
+ gdt->sc_raw_feat = gdt->sc_info;
+
+ /* Set/get features cache service (scatter/gather) */
+ gdt->sc_cache_feat = 0;
+ if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_SET_FEAT, 0,
+ GDT_SCATTER_GATHER, 0))
+ if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_GET_FEAT, 0, 0,
+ 0))
+ gdt->sc_cache_feat = gdt->sc_info;
+
+ /* XXX Linux reserve drives here, potentially */
+
+ /* Scan for cache devices */
+ for (i = 0; i < cdev_cnt && i < GDT_MAX_HDRIVES; i++)
+ if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_INFO, i, 0,
+ 0)) {
+ gdt->sc_hdr[i].hd_present = 1;
+ gdt->sc_hdr[i].hd_size = gdt->sc_info;
+
+ /*
+ * Evaluate mapping (sectors per head, heads per cyl)
+ */
+ gdt->sc_hdr[i].hd_size &= ~GDT_SECS32;
+ if (gdt->sc_info2 == 0)
+ gdt_eval_mapping(gdt->sc_hdr[i].hd_size,
+ &drv_cyls, &drv_hds, &drv_secs);
+ else {
+ drv_hds = gdt->sc_info2 & 0xff;
+ drv_secs = (gdt->sc_info2 >> 8) & 0xff;
+ drv_cyls = gdt->sc_hdr[i].hd_size / drv_hds /
+ drv_secs;
+ }
+ gdt->sc_hdr[i].hd_heads = drv_hds;
+ gdt->sc_hdr[i].hd_secs = drv_secs;
+ /* Round the size */
+ gdt->sc_hdr[i].hd_size = drv_cyls * drv_hds * drv_secs;
+
+ if (gdt_internal_cmd(gdt, GDT_CACHESERVICE,
+ GDT_DEVTYPE, i, 0, 0))
+ gdt->sc_hdr[i].hd_devtype = gdt->sc_info;
+ }
+
+ printf("dpmem %x %d-bus %d cache device%s\n", gdt->sc_dpmembase,
+ gdt->sc_bus_cnt, cdev_cnt, cdev_cnt == 1 ? "" : "s");
+ printf("%s: ver %x, cache %s, strategy %d, writeback %s, blksz %d\n",
+ gdt->sc_dev.dv_xname, gdt->sc_cpar.cp_version,
+ gdt->sc_cpar.cp_state ? "on" : "off", gdt->sc_cpar.cp_strategy,
+ gdt->sc_cpar.cp_write_back ? "on" : "off",
+ gdt->sc_cpar.cp_block_size);
+#if 1
+ printf("%s: raw feat %x cache feat %x\n", gdt->sc_dev.dv_xname,
+ gdt->sc_raw_feat, gdt->sc_cache_feat);
+#endif
+
+ config_found(&gdt->sc_dev, &gdt->sc_link, scsiprint);
+
+ MALLOC(gdt->sc_raw_link, struct scsi_link *,
+ gdt->sc_bus_cnt * sizeof (struct scsi_link), M_DEVBUF, M_NOWAIT);
+ bzero(gdt->sc_raw_link, gdt->sc_bus_cnt * sizeof (struct scsi_link));
+
+ for (i = 0; i < gdt->sc_bus_cnt; i++) {
+ /* Fill in the prototype scsi_link. */
+ gdt->sc_raw_link[i].adapter_softc = gdt;
+ gdt->sc_raw_link[i].adapter = &gdt_raw_switch;
+ gdt->sc_raw_link[i].adapter_target = 7;
+ gdt->sc_raw_link[i].device = &gdt_dev;
+ gdt->sc_raw_link[i].openings = 4; /* XXX a guess */
+ gdt->sc_raw_link[i].adapter_buswidth =
+ (gdt->sc_class & GDT_FC) ? GDT_MAXID : 16; /* XXX */
+
+ config_found(&gdt->sc_dev, &gdt->sc_raw_link[i], scsiprint);
+ }
+
+ gdt_polling = 0;
+ return (0);
+}
+
+void
+gdt_eval_mapping(size, cyls, heads, secs)
+ u_int32_t size;
+ int *cyls, *heads, *secs;
+{
+ *cyls = size / GDT_HEADS / GDT_SECS;
+ if (*cyls < GDT_MAXCYLS) {
+ *heads = GDT_HEADS;
+ *secs = GDT_SECS;
+ } else {
+ /* Too high for 64 * 32 */
+ *cyls = size / GDT_MEDHEADS / GDT_MEDSECS;
+ if (*cyls < GDT_MAXCYLS) {
+ *heads = GDT_MEDHEADS;
+ *secs = GDT_MEDSECS;
+ } else {
+ /* Too high for 127 * 63 */
+ *cyls = size / GDT_BIGHEADS / GDT_BIGSECS;
+ *heads = GDT_BIGHEADS;
+ *secs = GDT_BIGSECS;
+ }
+ }
+}
+
+/*
+ * Insert a command into the driver queue, either at the front or at the tail.
+ * It's ok to overload the freelist link as these structures are never on
+ * the freelist at this time.
+ */
+void
+gdt_enqueue(gdt, xs, infront)
+ struct gdt_softc *gdt;
+ struct scsi_xfer *xs;
+ int infront;
+{
+ if (infront || LIST_FIRST(&gdt->sc_queue) == NULL) {
+ if (LIST_FIRST(&gdt->sc_queue) == NULL)
+ gdt->sc_queuelast = xs;
+ LIST_INSERT_HEAD(&gdt->sc_queue, xs, free_list);
+ return;
+ }
+ LIST_INSERT_AFTER(gdt->sc_queuelast, xs, free_list);
+ gdt->sc_queuelast = xs;
+}
+
+/*
+ * Pull a command off the front of the driver queue.
+ */
+struct scsi_xfer *
+gdt_dequeue(gdt)
+ struct gdt_softc *gdt;
+{
+ struct scsi_xfer *xs;
+
+ xs = LIST_FIRST(&gdt->sc_queue);
+ LIST_REMOVE(xs, free_list);
+
+ if (LIST_FIRST(&gdt->sc_queue) == NULL)
+ gdt->sc_queuelast = NULL;
+
+ return (xs);
+}
+
+/* Start a SCSI operation on a cache device */
+int
+gdt_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *link = xs->sc_link;
+ struct gdt_softc *gdt = link->adapter_softc;
+ u_int8_t target = link->target;
+ struct gdt_ccb *ccb;
+ int dontqueue = 0;
+ u_int32_t blockno, blockcnt;
+ struct scsi_rw *rw;
+ struct scsi_rw_big *rwb;
+
+ GDT_DPRINTF(GDT_D_CMD, ("gdt_scsi_cmd "));
+
+ if (target >= GDT_MAX_HDRIVES || !gdt->sc_hdr[target].hd_present ||
+ link->lun != 0) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+ }
+
+ xs->error = XS_NOERROR;
+ ccb = NULL;
+
+ GDT_LOCK_GDT(gdt);
+ if (!gdt_polling && gdt->sc_test_busy(gdt)) {
+ /* Don't double enqueue if we came from gdt_chain. */
+ if (xs != LIST_FIRST(&gdt->sc_queue))
+ gdt_enqueue(gdt, xs, 0);
+ GDT_UNLOCK_GDT(gdt);
+ return (SUCCESSFULLY_QUEUED);
+ }
+ GDT_LOCK_GDT(gdt);
+
+ switch (xs->cmd->opcode) {
+ case TEST_UNIT_READY:
+ case REQUEST_SENSE:
+ case INQUIRY:
+ case MODE_SENSE:
+ case START_STOP:
+ case READ_CAPACITY:
+ case SYNCHRONIZE_CACHE:
+#if 0
+ case VERIFY:
+#endif
+ return (gdt_internal_cache_cmd(xs) ? COMPLETE :
+ TRY_AGAIN_LATER);
+
+ case PREVENT_ALLOW:
+ GDT_DPRINTF(GDT_D_CMD, ("PREVENT/ALLOW "));
+ /* XXX Not yet implemented */
+ xs->error = XS_NOERROR;
+ return (COMPLETE);
+
+ case READ_COMMAND:
+ case READ_BIG:
+ case WRITE_COMMAND:
+ case WRITE_BIG:
+ GDT_LOCK_GDT(gdt);
+
+ /*
+ * When chaining commands we may get called with the
+ * first command in the queue, recognize this case
+ * easily.
+ */
+ if (xs == LIST_FIRST(&gdt->sc_queue))
+ xs = gdt_dequeue(gdt);
+ else {
+ /* A new command chain, start from the beginning. */
+ gdt->sc_cmd_off = 0;
+
+ /* Don't resort to queuing if we are polling. */
+ dontqueue = xs->flags & SCSI_POLL;
+
+ /*
+ * The queue, if existent, must be processed first,
+ * before the new command can be run.
+ */
+ if (LIST_FIRST(&gdt->sc_queue) != NULL) {
+ /* If order cannot be preserved, punt. */
+ if (dontqueue) {
+ GDT_UNLOCK_GDT(gdt);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Enqueue the new command, ponder on the front
+ * command of the queue instead.
+ */
+ gdt_enqueue(gdt, xs, 0);
+ xs = gdt_dequeue(gdt);
+ }
+ }
+
+ if (xs->cmdlen == 6) {
+ rw = (struct scsi_rw *)xs->cmd;
+ blockno =
+ _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
+ blockcnt = rw->length ? rw->length : 0x100;
+ } else {
+ rwb = (struct scsi_rw_big *)xs->cmd;
+ blockno = _4btol(rwb->addr);
+ blockcnt = _2btol(rwb->length);
+ }
+ if (blockno >= gdt->sc_hdr[target].hd_size ||
+ blockno + blockcnt >= gdt->sc_hdr[target].hd_size) {
+ printf("%s: out of bounds %d-%d >= %d\n",
+ gdt->sc_dev.dv_xname, blockno, blockcnt,
+ gdt->sc_hdr[target].hd_size);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+ }
+
+ ccb = gdt_get_ccb(gdt, xs->flags);
+
+ /*
+ * Are we out of commands, then queue. If we cannot queue,
+ * then punt.
+ */
+ if (ccb == NULL) {
+ if (dontqueue) {
+ GDT_UNLOCK_GDT(gdt);
+ scsi_done(xs);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+ }
+ if (xs->error) {
+ GDT_UNLOCK_GDT(gdt);
+ scsi_done(xs);
+ return (COMPLETE);
+ }
+
+ /* Put back on the queue, in the front. */
+ gdt_enqueue(gdt, xs, 1);
+ GDT_UNLOCK_GDT(gdt);
+ return (SUCCESSFULLY_QUEUED);
+ }
+
+ ccb->gc_blockno = blockno;
+ ccb->gc_blockcnt = blockcnt;
+ ccb->gc_xs = xs;
+ ccb->gc_timeout = xs->timeout;
+ ccb->gc_service = GDT_CACHESERVICE;
+ gdt_ccb_set_cmd(ccb, GDT_GCF_SCSI);
+
+ gdt_enqueue_ccb(gdt, ccb);
+ /* XXX what if enqueue did not start a transfer? */
+ if (gdt_polling) {
+ if (!gdt_wait(gdt, ccb, ccb->gc_timeout)) {
+ GDT_UNLOCK_GDT(gdt);
+ printf("%s: command %d timed out\n",
+ gdt->sc_dev.dv_xname, ccb->gc_cmd_index);
+ xs->error = XS_TIMEOUT;
+ return (TRY_AGAIN_LATER);
+ }
+ }
+
+ GDT_UNLOCK_GDT(gdt);
+
+ if (gdt_polling) {
+ scsi_done(xs);
+ return (COMPLETE);
+ }
+ return (SUCCESSFULLY_QUEUED);
+
+ default:
+ GDT_DPRINTF(GDT_D_CMD, ("unknown opc %d ", xs->cmd->opcode));
+ /* XXX Not yet implemented */
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+ }
+}
+
+/* XXX Currently only for cacheservice, returns 0 if busy */
+int
+gdt_exec_ccb(ccb)
+ struct gdt_ccb *ccb;
+{
+ struct scsi_xfer *xs = ccb->gc_xs;
+ struct scsi_link *link = xs->sc_link;
+ struct gdt_softc *gdt = link->adapter_softc;
+ u_int8_t target = link->target;
+ u_int32_t sg_canz;
+ int i, len, off;
+ u_int8_t *buf;
+ paddr_t pa;
+
+ GDT_DPRINTF(GDT_D_CMD, ("gdt_exec_ccb(%p, %p) ", xs, ccb));
+
+ gdt->sc_cmd_cnt = 0;
+ /*
+ * XXX Yeah I know it's a always-true condition, but that may change
+ * later.
+ */
+ if (gdt->sc_cmd_cnt == 0)
+ gdt->sc_set_sema0(gdt);
+
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_COMMANDINDEX, ccb->gc_cmd_index);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_BOARDNODE, GDT_LOCALBOARD);
+ gdt_enc16(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO,
+ target);
+
+ switch (xs->cmd->opcode) {
+ case PREVENT_ALLOW:
+ /* XXX PREVENT_ALLOW support goes here */
+
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
+ 1);
+ sg_canz = 0;
+ break;
+
+ case WRITE_COMMAND:
+ case WRITE_BIG:
+ /* XXX WRITE_THR could be supported too */
+ gdt->sc_cmd[GDT_CMD_OPCODE] = GDT_WRITE;
+ break;
+
+ case READ_COMMAND:
+ case READ_BIG:
+ gdt->sc_cmd[GDT_CMD_OPCODE] = GDT_READ;
+ break;
+ }
+
+ if (xs->cmd->opcode != PREVENT_ALLOW) {
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
+ ccb->gc_blockno);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT,
+ ccb->gc_blockcnt);
+ }
+
+ if (gdt->sc_cache_feat & GDT_SCATTER_GATHER) {
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
+ 0xffffffff);
+ len = xs->datalen;
+ buf = xs->data;
+ for (i = 0; len > 0; i++) {
+ for (off = PAGE_SIZE, pa = vtophys(buf); off < len;
+ off += PAGE_SIZE)
+ if (pa + off != vtophys(buf + off))
+ break;
+
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_CACHE_SG_LST + i * GDT_SG_SZ + GDT_SG_PTR, pa);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_CACHE_SG_LST + i * GDT_SG_SZ + GDT_SG_LEN,
+ MIN(off, len));
+ GDT_DPRINTF(GDT_D_IO, ("#%d va %p pa %p len %x\n", i,
+ buf, (void *)pa, MIN(off, len)));
+
+ len -= off;
+ buf += off;
+ }
+ sg_canz = i;
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
+ sg_canz * GDT_SG_SZ + GDT_SG_LEN, 0);
+ } else {
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
+ vtophys(xs->data));
+ sg_canz = 0;
+ }
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ, sg_canz);
+
+ gdt->sc_cmd_len =
+ roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST + sg_canz * GDT_SG_SZ,
+ sizeof (u_int32_t));
+
+ if (gdt->sc_cmd_cnt > 0 &&
+ gdt->sc_cmd_off + gdt->sc_cmd_len + GDT_DPMEM_COMMAND_OFFSET >
+ gdt->sc_ic_all_size) {
+ printf("%s: DPMEM overflow\n", gdt->sc_dev.dv_xname);
+ gdt_free_ccb(gdt, ccb);
+ xs->error = XS_BUSY;
+ return (0);
+ }
+
+ gdt->sc_copy_cmd(gdt, ccb);
+ gdt->sc_release_event(gdt, ccb);
+
+ xs->error = XS_NOERROR;
+ xs->resid = 0;
+ return (1);
+}
+
+void
+gdt_copy_internal_data(xs, data, size)
+ struct scsi_xfer *xs;
+ u_int8_t *data;
+ size_t size;
+{
+ size_t copy_cnt;
+
+ GDT_DPRINTF(GDT_D_MISC, ("gdt_copy_internal_data "));
+
+ if (!xs->datalen)
+ printf("uio move not yet supported\n");
+ else {
+ copy_cnt = MIN(size, xs->datalen);
+ bcopy(data, xs->data, copy_cnt);
+ }
+
+
+}
+
+/* Emulated SCSI operation on cache device */
+int
+gdt_internal_cache_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *link = xs->sc_link;
+ struct gdt_softc *gdt = link->adapter_softc;
+ struct scsi_inquiry_data inq;
+ struct scsi_sense_data sd;
+ struct {
+ struct scsi_mode_header hd;
+ struct scsi_blk_desc bd;
+ union scsi_disk_pages dp;
+ } mpd;
+ struct scsi_read_cap_data rcd;
+ u_int8_t target = link->target;
+
+ GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cache_cmd "));
+
+ switch (xs->cmd->opcode) {
+ case TEST_UNIT_READY:
+ case START_STOP:
+#if 0
+ case VERIFY:
+#endif
+ GDT_DPRINTF(GDT_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,
+ target));
+ break;
+
+ case SYNCHRONIZE_CACHE:
+ GDT_DPRINTF(GDT_D_CMD, ("SYNCHRONIZE CACHE tgt %d ", target));
+ break;
+
+ case REQUEST_SENSE:
+ GDT_DPRINTF(GDT_D_CMD, ("REQUEST SENSE tgt %d ", target));
+ bzero(&sd, sizeof sd);
+ sd.error_code = 0x70;
+ sd.segment = 0;
+ sd.flags = SKEY_NO_SENSE;
+ gdt_enc32(sd.info, 0);
+ sd.extra_len = 0;
+ gdt_copy_internal_data(xs, (u_int8_t *)&sd, sizeof sd);
+ break;
+
+ case INQUIRY:
+ GDT_DPRINTF(GDT_D_CMD, ("INQUIRY tgt %d devtype %x ", target,
+ gdt->sc_hdr[target].hd_devtype));
+ bzero(&inq, sizeof inq);
+ inq.device =
+ (gdt->sc_hdr[target].hd_devtype & 4) ? T_CDROM : T_DIRECT;
+ inq.dev_qual2 =
+ (gdt->sc_hdr[target].hd_devtype & 1) ? SID_REMOVABLE : 0;
+ inq.version = 2;
+ inq.response_format = 2;
+ inq.additional_length = 32;
+ strcpy(inq.vendor, "ICP ");
+ sprintf(inq.product, "Host drive #%02d", target);
+ strcpy(inq.revision, " ");
+ gdt_copy_internal_data(xs, (u_int8_t *)&inq, sizeof inq);
+ break;
+
+ case MODE_SENSE:
+ GDT_DPRINTF(GDT_D_CMD, ("MODE SENSE tgt %d ", target));
+
+ bzero(&mpd, sizeof mpd);
+ switch (((struct scsi_mode_sense *)xs->cmd)->page) {
+ case 4:
+ /* scsi_disk.h says this should be 0x16 */
+ mpd.dp.rigid_geometry.pg_length = 0x16;
+ mpd.hd.data_length = sizeof mpd.hd + sizeof mpd.bd +
+ mpd.dp.rigid_geometry.pg_length;
+ mpd.hd.blk_desc_len = sizeof mpd.bd;
+
+ /* XXX */
+ mpd.hd.dev_spec =
+ (gdt->sc_hdr[target].hd_devtype & 2) ? 0x80 : 0;
+ _lto3b(GDT_SECTOR_SIZE, mpd.bd.blklen);
+ mpd.dp.rigid_geometry.pg_code = 4;
+ _lto3b(gdt->sc_hdr[target].hd_size /
+ gdt->sc_hdr[target].hd_heads /
+ gdt->sc_hdr[target].hd_secs,
+ mpd.dp.rigid_geometry.ncyl);
+ mpd.dp.rigid_geometry.nheads =
+ gdt->sc_hdr[target].hd_heads;
+ gdt_copy_internal_data(xs, (u_int8_t *)&mpd,
+ sizeof mpd);
+ break;
+
+ default:
+ printf("%s: mode sense page %d not simulated\n",
+ gdt->sc_dev.dv_xname,
+ ((struct scsi_mode_sense *)xs->cmd)->page);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (0);
+ }
+ break;
+
+ case READ_CAPACITY:
+ GDT_DPRINTF(GDT_D_CMD, ("READ CAPACITY tgt %d ", target));
+ bzero(&rcd, sizeof rcd);
+ _lto4b(gdt->sc_hdr[target].hd_size - 1, rcd.addr);
+ _lto4b(GDT_SECTOR_SIZE, rcd.length);
+ gdt_copy_internal_data(xs, (u_int8_t *)&rcd, sizeof rcd);
+ break;
+
+ default:
+ printf("gdt_internal_cache_cmd got bad opcode: %d\n",
+ xs->cmd->opcode);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (0);
+ }
+
+ xs->error = XS_NOERROR;
+ return (1);
+}
+
+/* Start a raw SCSI operation */
+int
+gdt_raw_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ GDT_DPRINTF(GDT_D_CMD, ("gdt_raw_scsi_cmd "));
+
+ /* XXX Not yet implemented */
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+}
+
+void
+gdt_clear_events(gdt)
+ struct gdt_softc *gdt;
+{
+ GDT_DPRINTF(GDT_D_MISC, ("gdt_clear_events(%p) ", gdt));
+
+ /* XXX To be implemented */
+}
+
+int
+gdt_async_event(gdt, service)
+ struct gdt_softc *gdt;
+ int service;
+{
+ GDT_DPRINTF(GDT_D_INTR, ("gdt_async_event(%p, %d) ", gdt, service));
+
+ if (service == GDT_SCREENSERVICE) {
+ /* XXX To be implemented */
+ } else {
+ /* XXX To be implemented */
+ }
+
+ return (0);
+}
+
+int
+gdt_sync_event(gdt, service, index, xs)
+ struct gdt_softc *gdt;
+ int service;
+ u_int8_t index;
+ struct scsi_xfer *xs;
+{
+ GDT_DPRINTF(GDT_D_INTR,
+ ("gdt_sync_event(%p, %d, %d, %p) ", gdt, service, index, xs));
+
+ if (service == GDT_SCREENSERVICE) {
+ /* XXX To be implemented */
+ return (0);
+ } else {
+ if (gdt->sc_status == GDT_S_OK) {
+ /* XXX To be implemented */
+ } else {
+ /* XXX To be implemented */
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+int
+gdt_intr(arg)
+ void *arg;
+{
+ struct gdt_softc *gdt = arg;
+ struct gdt_intr_ctx ctx;
+ int chain = 1, sync_val = 0;
+ struct scsi_xfer *xs;
+ int prev_cmd;
+ struct gdt_ccb *ccb;
+
+ GDT_DPRINTF(GDT_D_INTR, ("gdt_intr(%p) ", gdt));
+
+ /* If polling and we were not called from gdt_wait, just return */
+ if (gdt_polling && !gdt_from_wait)
+ return (0);
+
+ if (!gdt_polling)
+ GDT_LOCK_GDT(gdt);
+
+ ctx.istatus = gdt->sc_get_status(gdt);
+ if (!ctx.istatus) {
+ GDT_UNLOCK_GDT(gdt);
+ gdt->sc_status = GDT_S_NO_STATUS;
+ return (0);
+ }
+
+ gdt_wait_index = 0;
+ ctx.service = ctx.info2 = 0;
+
+ gdt->sc_intr(gdt, &ctx);
+
+ gdt->sc_status = ctx.cmd_status;
+ gdt->sc_info = ctx.info;
+ gdt->sc_info2 = ctx.info2;
+
+ if (gdt_from_wait) {
+ gdt_wait_gdt = gdt;
+ gdt_wait_index = ctx.istatus;
+ }
+
+ switch (ctx.istatus) {
+ case GDT_ASYNCINDEX:
+ gdt_async_event(gdt, ctx.service);
+ goto finish;
+
+ case GDT_SPEZINDEX:
+ /* XXX Not yet implemented */
+ chain = 0;
+ goto finish;
+ }
+
+ ccb = &gdt->sc_ccbs[ctx.istatus - 2];
+ xs = ccb->gc_xs;
+ if (!gdt_polling)
+ untimeout(gdt_timeout, ccb);
+ ctx.service = ccb->gc_service;
+ prev_cmd = ccb->gc_flags & GDT_GCF_CMD_MASK;
+ gdt_free_ccb(gdt, ccb);
+ switch (prev_cmd) {
+ case GDT_GCF_UNUSED:
+ /* XXX Not yet implemented */
+ chain = 0;
+ goto finish;
+ case GDT_GCF_INTERNAL:
+ chain = 0;
+ goto finish;
+ }
+
+ sync_val = gdt_sync_event(gdt, ctx.service, ctx.istatus, xs);
+
+ finish:
+ if (!gdt_polling)
+ GDT_UNLOCK_GDT(gdt);
+
+ switch (sync_val) {
+ case 1:
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ break;
+
+ case 2:
+ gdt_enqueue(gdt, xs, 0);
+ }
+
+ if (chain)
+ gdt_chain(gdt);
+ return (1);
+}
+
+void
+gdtminphys(bp)
+ struct buf *bp;
+{
+#if 0
+ u_int8_t *buf = bp->b_data;
+ paddr_t pa;
+ long off;
+#endif
+
+ GDT_DPRINTF(GDT_D_MISC, ("gdtminphys(0x%x) ", bp));
+
+#if 1
+ /* As this is way more than MAXPHYS it's really not necessary. */
+ if (bp->b_bcount > ((GDT_MAXOFFSETS - 1) * PAGE_SIZE))
+ bp->b_bcount = ((GDT_MAXOFFSETS - 1) * PAGE_SIZE);
+#else
+ for (off = PAGE_SIZE, pa = vtophys(buf); off < bp->b_bcount;
+ off += PAGE_SIZE)
+ if (pa + off != vtophys(buf + off)) {
+ bp->b_bcount = off;
+ break;
+ }
+#endif
+ minphys(bp);
+}
+
+int
+gdt_wait(gdt, ccb, timeout)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+ int timeout;
+{
+ int rv = 0;
+
+ GDT_DPRINTF(GDT_D_MISC,
+ ("gdt_wait(%p, %p, %d) ", gdt, ccb, timeout));
+
+ gdt_from_wait = 1;
+ do {
+ if (gdt_intr(gdt) && gdt == gdt_wait_gdt &&
+ ccb->gc_cmd_index == gdt_wait_index) {
+ rv = 1;
+ break;
+ }
+ DELAY(1);
+ } while (--timeout);
+ gdt_from_wait = 0;
+
+ while (gdt->sc_test_busy(gdt))
+ DELAY(0); /* XXX correct? */
+
+ return (rv);
+}
+
+int
+gdt_internal_cmd(gdt, service, opcode, arg1, arg2, arg3)
+ struct gdt_softc *gdt;
+ u_int8_t service;
+ u_int16_t opcode;
+ u_int32_t arg1, arg2, arg3;
+{
+ int retries;
+ struct gdt_ccb *ccb;
+
+ GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cmd(%p, %d, %d, %d, %d, %d) ",
+ gdt, service, opcode, arg1, arg2, arg3));
+
+ bzero(gdt->sc_cmd, GDT_CMD_SZ);
+
+ for (retries = GDT_RETRIES; ; ) {
+ ccb = gdt_get_ccb(gdt, SCSI_NOSLEEP);
+ if (ccb == NULL) {
+ printf("%s: no free command index found\n",
+ gdt->sc_dev.dv_xname);
+ return (0);
+ }
+ ccb->gc_service = service;
+ gdt_ccb_set_cmd(ccb, GDT_GCF_INTERNAL);
+
+ gdt->sc_set_sema0(gdt);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_COMMANDINDEX,
+ ccb->gc_cmd_index);
+ gdt_enc16(gdt->sc_cmd + GDT_CMD_OPCODE, opcode);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_BOARDNODE, GDT_LOCALBOARD);
+
+ switch (service) {
+ case GDT_CACHESERVICE:
+ if (opcode == GDT_IOCTL) {
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_IOCTL_SUBFUNC, arg1);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_IOCTL_CHANNEL, arg2);
+ gdt_enc16(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_IOCTL_PARAM_SIZE, (u_int16_t)arg3);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_IOCTL_P_PARAM,
+ vtophys(gdt->sc_scratch));
+ } else {
+ gdt_enc16(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_CACHE_DEVICENO, (u_int16_t)arg1);
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_CACHE_BLOCKNO, arg2);
+ }
+ break;
+
+ case GDT_SCSIRAWSERVICE:
+ gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
+ GDT_RAW_DIRECTION, arg1);
+ gdt->sc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
+ (u_int8_t)arg2;
+ gdt->sc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
+ (u_int8_t)arg3;
+ gdt->sc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
+ (u_int8_t)(arg3 >> 8);
+ }
+
+ gdt->sc_cmd_len = GDT_CMD_SZ;
+ gdt->sc_cmd_off = 0;
+ gdt->sc_cmd_cnt = 0;
+ gdt->sc_copy_cmd(gdt, ccb);
+ gdt->sc_release_event(gdt, ccb);
+ DELAY(20);
+ if (!gdt_wait(gdt, ccb, GDT_POLL_TIMEOUT))
+ return (0);
+ if (gdt->sc_status != GDT_S_BSY || --retries == 0)
+ break;
+ DELAY(1);
+ }
+ return (gdt->sc_status == GDT_S_OK);
+}
+
+struct gdt_ccb *
+gdt_get_ccb(gdt, flags)
+ struct gdt_softc *gdt;
+ int flags;
+{
+ struct gdt_ccb *ccb;
+
+ GDT_DPRINTF(GDT_D_QUEUE, ("gdt_get_ccb(%p, 0x%x) ", gdt, flags));
+
+ GDT_LOCK_GDT(gdt);
+
+ for (;;) {
+ ccb = TAILQ_FIRST(&gdt->sc_free_ccb);
+ if (ccb != NULL)
+ break;
+ if (flags & SCSI_NOSLEEP)
+ goto bail_out;
+ tsleep(&gdt->sc_free_ccb, PRIBIO, "gdt_ccb", 0);
+ }
+
+ TAILQ_REMOVE(&gdt->sc_free_ccb, ccb, gc_chain);
+
+ bail_out:
+ GDT_UNLOCK_GDT(gdt);
+ return (ccb);
+}
+
+void
+gdt_free_ccb(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ GDT_DPRINTF(GDT_D_QUEUE, ("gdt_free_ccb(%p, %p) ", gdt, ccb));
+
+ GDT_LOCK_GDT(gdt);
+
+ TAILQ_INSERT_HEAD(&gdt->sc_free_ccb, ccb, gc_chain);
+
+ /* If the free list was empty, wake up potential waiters. */
+ if (TAILQ_NEXT(ccb, gc_chain) == NULL)
+ wakeup(&gdt->sc_free_ccb);
+
+ GDT_UNLOCK_GDT(gdt);
+}
+
+void
+gdt_enqueue_ccb(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ GDT_DPRINTF(GDT_D_QUEUE, ("gdt_enqueue_ccb(%p, %p) ", gdt, ccb));
+
+ TAILQ_INSERT_TAIL(&gdt->sc_ccbq, ccb, gc_chain);
+ gdt_start_ccbs(gdt);
+}
+
+void
+gdt_start_ccbs(gdt)
+ struct gdt_softc *gdt;
+{
+ struct gdt_ccb *ccb;
+
+ GDT_DPRINTF(GDT_D_QUEUE, ("gdt_start_ccbs(%p) ", gdt));
+
+ while ((ccb = TAILQ_FIRST(&gdt->sc_ccbq)) != NULL) {
+ if (ccb->gc_flags & GDT_GCF_WATCHDOG)
+ untimeout(gdt_watchdog, ccb);
+
+ if (gdt_exec_ccb(ccb) == 0) {
+ ccb->gc_flags |= GDT_GCF_WATCHDOG;
+ timeout(gdt_watchdog, ccb,
+ (GDT_WATCH_TIMEOUT * hz) / 1000);
+ break;
+ }
+ TAILQ_REMOVE(&gdt->sc_ccbq, ccb, gc_chain);
+
+ if ((ccb->gc_xs->flags & SCSI_POLL) == 0)
+ timeout(gdt_timeout, ccb,
+ (ccb->gc_timeout * hz) / 1000);
+ }
+}
+
+void
+gdt_chain(gdt)
+ struct gdt_softc *gdt;
+{
+ GDT_DPRINTF(GDT_D_INTR, ("gdt_chain(%p) ", gdt));
+
+ if (LIST_FIRST(&gdt->sc_queue))
+ gdt_scsi_cmd(LIST_FIRST(&gdt->sc_queue));
+}
+
+void
+gdt_timeout(arg)
+ void *arg;
+{
+ struct gdt_ccb *ccb = arg;
+ struct scsi_link *link = ccb->gc_xs->sc_link;
+ struct gdt_softc *gdt = link->adapter_softc;
+
+ sc_print_addr(link);
+ printf("timed out\n");
+
+ /* XXX Test for multiple timeouts */
+
+ ccb->gc_xs->error = XS_TIMEOUT;
+ GDT_LOCK_GDT(gdt);
+ gdt_enqueue_ccb(gdt, ccb);
+ GDT_UNLOCK_GDT(gdt);
+}
+
+void
+gdt_watchdog(arg)
+ void *arg;
+{
+ struct gdt_ccb *ccb = arg;
+ struct scsi_link *link = ccb->gc_xs->sc_link;
+ struct gdt_softc *gdt = link->adapter_softc;
+
+ GDT_LOCK_GDT(gdt);
+ ccb->gc_flags &= ~GDT_GCF_WATCHDOG;
+ gdt_start_ccbs(gdt);
+ GDT_UNLOCK_GDT(gdt);
+}
diff --git a/sys/dev/ic/gdtreg.h b/sys/dev/ic/gdtreg.h
new file mode 100644
index 00000000000..c77c5d5c4ba
--- /dev/null
+++ b/sys/dev/ic/gdtreg.h
@@ -0,0 +1,299 @@
+/* $OpenBSD: gdtreg.h,v 1.1 2000/02/07 00:33:03 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niklas Hallqvist.
+ * 4. 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.
+ */
+
+/*
+ * This driver would not have written if it was not for the hardware donations
+ * from both ICP-Vortex and Öko.neT. I want to thank them for their support.
+ */
+
+#define GDT_MAXBUS 6 /* XXX Why not 5? */
+#define GDT_MAX_HDRIVES 35 /* 5 busses * 7 targets XXX correct? */
+#define GDT_MAXID 127 /* Fibre-channel maximum ID */
+#define GDT_MAXOFFSETS 128
+#define GDT_MAXSG 128 /* Max. s/g elements */
+#define GDT_PROTOCOL_VERSION 1
+#define GDT_LINUX_OS 8 /* Used for cache optimization */
+#define GDT_SCATTER_GATHER 1 /* s/g feature */
+#define GDT_SECS32 0x1f /* round capacity */
+#define GDT_LOCALBOARD 0 /* Board node always 0 */
+#define GDT_MAXCMDS 124
+#define GDT_SECTOR_SIZE 0x200 /* Always 512 bytes for cache devs */
+
+/* DPMEM constants */
+#define GDT_MPR_MAGIC 0xc0ffee11
+#define GDT_IC_HEADER_BYTES 48
+#define GDT_IC_QUEUE_BYTES 4
+#define GDT_DPMEM_COMMAND_OFFSET \
+ (GDT_IC_HEADER_BYTES + GDT_IC_QUEUE_BYTES * GDT_MAXOFFSETS)
+
+#if 1
+/* Geometry constants. XXX probably not needed. */
+#define GDT_MAXCYLS 1024
+#define GDT_HEADS 64
+#define GDT_SECS 32 /* mapping 64*32 */
+#define GDT_MEDHEADS 127
+#define GDT_MEDSECS 63 /* mapping 127*63 */
+#define GDT_BIGHEADS 255
+#define GDT_BIGSECS 63 /* mapping 255*63 */
+#endif
+
+/* Cache/raw service commands */
+#define GDT_INIT 0 /* service initialization */
+#define GDT_READ 1 /* read command */
+#define GDT_WRITE 2 /* write command */
+#define GDT_INFO 3 /* information about devices */
+#define GDT_FLUSH 4 /* flush dirty cache buffers */
+#define GDT_IOCTL 5 /* ioctl command */
+#define GDT_DEVTYPE 9 /* additional information */
+#define GDT_MOUNT 10 /* mount cache device */
+#define GDT_UNMOUNT 11 /* unmount cache device */
+#define GDT_SET_FEAT 12 /* set features (scatter/gather) */
+#define GDT_GET_FEAT 13 /* get features */
+#define GDT_WRITE_THR 16 /* write through */
+#define GDT_READ_THR 17 /* read through */
+#define GDT_EXT_INFO 18 /* extended info */
+#define GDT_RESET 19 /* controller reset */
+
+/* Additional raw service commands */
+#define GDT_RESERVE 14 /* reserve device to raw service */
+#define GDT_RELEASE 15 /* release device */
+#define GDT_RESERVE_ALL 16 /* reserve all devices */
+#define GDT_RELEASE_ALL 17 /* release all devices */
+#define GDT_RESET_BUS 18 /* reset bus */
+#define GDT_SCAN_START 19 /* start device scan */
+#define GDT_SCAN_END 20 /* stop device scan */
+
+/* IOCTL command defines */
+#define GDT_SCSI_DR_INFO 0x00 /* SCSI drive info */
+#define GDT_SCSI_CHAN_CNT 0x05 /* SCSI channel count */
+#define GDT_SCSI_DR_LIST 0x06 /* SCSI drive list */
+#define GDT_SCSI_DEF_CNT 0x15 /* grown/primary defects */
+#define GDT_DSK_STATISTICS 0x4b /* SCSI disk statistics */
+#define GDT_IOCHAN_DESC 0x5d /* description of IO channel */
+#define GDT_IOCHAN_RAW_DESC 0x5e /* description of raw IO channel */
+
+#define GDT_L_CTRL_PATTERN 0x20000000 /* SCSI IOCTL mask */
+#define GDT_ARRAY_INFO 0x12 /* array drive info */
+#define GDT_ARRAY_DRV_LIST 0x0f /* array drive list */
+#define GDT_LA_CTRL_PATTERN 0x10000000 /* array IOCTL mask */
+#define GDT_CACHE_DRV_CNT 0x01 /* cache drive count */
+#define GDT_CACHE_DRV_LIST 0x02 /* cache drive list */
+#define GDT_CACHE_INFO 0x04 /* cache info */
+#define GDT_CACHE_CONFIG 0x05 /* cache configuration */
+#define GDT_CACHE_DRV_INFO 0x07 /* cache drive info */
+#define GDT_BOARD_FEATURES 0x15 /* controller features */
+#define GDT_BOARD_INFO 0x28 /* controller info */
+#define GDT_HOST_GET 0x10001 /* get host drive list */
+#define GDT_IO_CHANNEL 0x20000 /* default IO channel */
+#define GDT_INVALID_CHANNEL 0xffff /* invalid channel */
+
+/* IOCTLs */
+#define GDTIOCTL_MASK ('J' << 8)
+#define GDTIOCTL_GENERAL (GDTIOCTL_MASK | 0) /* general IOCTL */
+#define GDTIOCTL_DRVERS (GDTIOCTL_MASK | 1) /* get driver version */
+#define GDTIOCTL_CTRTYPE (GDTIOCTL_MASK | 2) /* get controller type */
+#define GDTIOCTL_CTRCNT (GDTIOCTL_MASK | 5) /* get controller count */
+#define GDTIOCTL_LOCKDRV (GDTIOCTL_MASK | 6) /* lock host drive */
+#define GDTIOCTL_LOCKCHN (GDTIOCTL_MASK | 7) /* lock channel */
+#define GDTIOCTL_EVENT (GDTIOCTL_MASK | 8) /* read controller events */
+
+/* Service errors */
+#define GDT_S_OK 1 /* no error */
+#define GDT_S_BSY 7 /* controller busy */
+#define GDT_S_RAW_SCSI 12 /* raw service: target error */
+#define GDT_S_RAW_ILL 0xff /* raw service: illegal */
+#define GDT_S_NO_STATUS 0x1000 /* got no status (driver-generated) */
+
+/* Controller services */
+#define GDT_SCSIRAWSERVICE 3
+#define GDT_CACHESERVICE 9
+#define GDT_SCREENSERVICE 11
+
+/* Scatter/gather element */
+#define GDT_SG_PTR 0x00 /* u_int32_t, address */
+#define GDT_SG_LEN 0x04 /* u_int32_t, length */
+#define GDT_SG_SZ 0x08
+
+/* Cache service command */
+#define GDT_CACHE_DEVICENO 0x00 /* u_int16_t, number of cache drive */
+#define GDT_CACHE_BLOCKNO 0x02 /* u_int32_t, block number */
+#define GDT_CACHE_BLOCKCNT 0x06 /* u_int32_t, block count */
+#define GDT_CACHE_DESTADDR 0x0a /* u_int32_t, dest. addr. (-1: s/g) */
+#define GDT_CACHE_SG_CANZ 0x0e /* u_int32_t, s/g element count */
+#define GDT_CACHE_SG_LST 0x12 /* [GDT_MAXSG], s/g list */
+#define GDT_CACHE_SZ (0x12 + GDT_MAXSG * GDT_SG_SZ)
+
+/* Ioctl command */
+#define GDT_IOCTL_PARAM_SIZE 0x00 /* u_int16_t, size of buffer */
+#define GDT_IOCTL_SUBFUNC 0x02 /* u_int32_t, ioctl function */
+#define GDT_IOCTL_CHANNEL 0x06 /* u_int32_t, device */
+#define GDT_IOCTL_P_PARAM 0x0a /* u_int32_t, buffer */
+#define GDT_IOCTL_SZ 0x0e
+
+/* Screen service command */
+#define GDT_SCREEN_MSG_HANDLE 0x02 /* u_int32_t, message handle */
+#define GDT_SCREEN_MSG_ADDR 0x06 /* u_int32_t, message buffer address */
+#define GDT_SCREEN_SZ 0x0a
+
+/* Raw service command */
+#define GDT_RAW_DIRECTION 0x02 /* u_int32_t, data direction */
+#define GDT_RAW_MDISC_TIME 0x06 /* u_int32_t, disc. time (0: none) */
+#define GDT_RAW_MCON_TIME 0x0a /* u_int32_t, conn. time (0: none) */
+#define GDT_RAW_SDATA 0x0e /* u_int32_t, dest. addr. (-1: s/g) */
+#define GDT_RAW_SDLEN 0x12 /* u_int32_t, data length */
+#define GDT_RAW_CLEN 0x16 /* u_int32_t, SCSI cmd len (6/10/12) */
+#define GDT_RAW_CMD 0x1a /* u_int8_t [12], SCSI command */
+#define GDT_RAW_TARGET 0x26 /* u_int8_t, target ID */
+#define GDT_RAW_LUN 0x27 /* u_int8_t, LUN */
+#define GDT_RAW_BUS 0x28 /* u_int8_t, SCSI bus number */
+#define GDT_RAW_PRIORITY 0x29 /* u_int8_t, only 0 used */
+#define GDT_RAW_SENSE_LEN 0x2a /* u_int32_t, sense data length */
+#define GDT_RAW_SENSE_DATA 0x2e /* u_int32_t, sense data address */
+#define GDT_RAW_SG_RANZ 0x36 /* u_int32_t, s/g element count */
+#define GDT_RAW_SG_LST 0x3a /* [GDT_MAXSG], s/g list */
+#define GDT_RAW_SZ (0x3e + GDT_MAXSG * GDT_SG_SZ)
+
+/* Command structure */
+#define GDT_CMD_BOARDNODE 0x00 /* u_int32_t, board node (always 0) */
+#define GDT_CMD_COMMANDINDEX 0x04 /* u_int32_t, command number */
+#define GDT_CMD_OPCODE 0x08 /* u_int16_t, opcode (READ, ...) */
+#define GDT_CMD_UNION 0x0a /* cache/screen/raw service command */
+#define GDT_CMD_UNION_SZ GDT_RAW_SZ
+#define GDT_CMD_SZ (0x0a + GDT_CMD_UNION_SZ)
+
+/* Command queue entries */
+#define GDT_OFFSET 0x00 /* u_int16_t, command offset in the DP RAM */
+#define GDT_SERV_ID 0x02 /* u_int16_t, service */
+#define GDT_COMM_Q_SZ 0x04
+
+/* Interface area */
+#define GDT_S_CMD_INDX 0x00 /* u_int8_t, special command */
+#define GDT_S_STATUS 0x01 /* volatile u_int8_t, status special command */
+#define GDT_S_INFO 0x04 /* u_int32_t [4], add. info special command */
+#define GDT_SEMA0 0x14 /* volatile u_int8_t, command semaphore */
+#define GDT_CMD_INDEX 0x18 /* u_int8_t, command number */
+#define GDT_STATUS 0x1c /* volatile u_int16_t, command status */
+#define GDT_SERVICE 0x1e /* u_int16_t, service (for asynch. events) */
+#define GDT_DPR_INFO 0x20 /* u_int32_t [2], additional info */
+#define GDT_COMM_QUEUE 0x28 /* command queue */
+#define GDT_DPR_CMD (0x30 + GDT_MAXOFFSETS * GDT_COMM_Q_SZ)
+ /* u_int8_t [], commands */
+#define GDT_DPR_IF_SZ GDT_DPR_CMD
+
+/* I/O channel header */
+#define GDT_IOC_VERSION 0x00 /* u_int32_t, version (~0: newest) */
+#define GDT_IOC_LIST_ENTRIES 0x04 /* u_int8_t, list entry count */
+#define GDT_IOC_FIRST_CHAN 0x05 /* u_int8_t, first channel number */
+#define GDT_IOC_LAST_CHAN 0x06 /* u_int8_t, last channel number */
+#define GDT_IOC_CHAN_COUNT 0x07 /* u_int8_t, (R) channel count */
+#define GDT_IOC_LIST_OFFSET 0x08 /* u_int32_t, offset of list[0] */
+#define GDT_IOC_HDR_SZ 0x0c
+
+#define GDT_IOC_NEWEST 0xffffffff /* goes into GDT_IOC_VERSION */
+
+/* Get I/O channel description */
+#define GDT_IOC_ADDRESS 0x00 /* u_int32_t, channel address */
+#define GDT_IOC_TYPE 0x04 /* u_int8_t, type (SCSI/FCSL) */
+#define GDT_IOC_LOCAL_NO 0x05 /* u_int8_t, local number */
+#define GDT_IOC_FEATURES 0x06 /* u_int16_t, channel features */
+#define GDT_IOC_SZ 0x08
+
+/* Get raw I/O channel description */
+#define GDT_RAWIOC_PROC_ID 0x00 /* u_int8_t, processor id */
+#define GDT_RAWIOC_PROC_DEFECT 0x01 /* u_int8_t, defect? */
+#define GDT_RAWIOC_SZ 0x04
+
+/* Get SCSI channel count */
+#define GDT_GETCH_CHANNEL_NO 0x00 /* u_int32_t, channel number */
+#define GDT_GETCH_DRIVE_CNT 0x04 /* u_int32_t, drive count */
+#define GDT_GETCH_SIOP_ID 0x08 /* u_int8_t, SCSI processor ID */
+#define GDT_GETCH_SIOP_STATE 0x09 /* u_int8_t, SCSI processor state */
+#define GDT_GETCH_SZ 0x0a
+
+/* Cache info/config IOCTL structures */
+#define GDT_CPAR_VERSION 0x00 /* u_int32_t, firmware version */
+#define GDT_CPAR_STATE 0x04 /* u_int16_t, cache state (on/off) */
+#define GDT_CPAR_STRATEGY 0x06 /* u_int16_t, cache strategy */
+#define GDT_CPAR_WRITE_BACK 0x08 /* u_int16_t, write back (on/off) */
+#define GDT_CPAR_BLOCK_SIZE 0x0a /* u_int16_t, cache block size */
+#define GDT_CPAR_SZ 0x0c
+
+#define GDT_CSTAT_CSIZE 0x00 /* u_int32_t, cache size */
+#define GDT_CSTAT_READ_CNT 0x04 /* u_int32_t, read counter */
+#define GDT_CSTAT_WRITE_CNT 0x08 /* u_int32_t, write counter */
+#define GDT_CSTAT_TR_HITS 0x0c /* u_int32_t, track hits */
+#define GDT_CSTAT_SEC_HITS 0x10 /* u_int32_t, sector hits */
+#define GDT_CSTAT_SEC_MISS 0x14 /* u_int32_t, sector misses */
+#define GDT_CSTAT_SZ 0x18
+
+/* Get cache info */
+#define GDT_CINFO_CPAR 0x00
+#define GDT_CINFO_CSTAT GDT_CPAR_SZ
+#define GDT_CINFO_SZ (GDT_CPAR_SZ + GDT_CSTAT_SZ)
+
+/* Get board info */
+#define GDT_BINFO_SER_NO 0x00 /* u_int32_t, serial number */
+#define GDT_BINFO_OEM_ID 0x04 /* u_int8_t [2], OEM ID */
+#define GDT_BINFO_EP_FLAGS 0x06 /* u_int16_t, eprom flags */
+#define GDT_BINFO_PROC_ID 0x08 /* u_int32_t, processor ID */
+#define GDT_BINFO_MEMSIZE 0x0c /* u_int32_t, memory size (bytes) */
+#define GDT_BINFO_MEM_BANKS 0x10 /* u_int8_t, memory banks */
+#define GDT_BINFO_CHAN_TYPE 0x11 /* u_int8_t, channel type */
+#define GDT_BINFO_CHAN_COUNT 0x12 /* u_int8_t, channel count */
+#define GDT_BINFO_RDONGLE_PRES 0x13 /* u_int8_t, dongle present */
+#define GDT_BINFO_EPR_FW_VER 0x14 /* u_int32_t, (eprom) firmware ver */
+#define GDT_BINFO_UPD_FW_VER 0x18 /* u_int32_t, (update) firmware ver */
+#define GDT_BINFO_UPD_REVISION 0x1c /* u_int32_t, update revision */
+#define GDT_BINFO_TYPE_STRING 0x20 /* char [16], controller name */
+#define GDT_BINFO_RAID_STRING 0x30 /* char [16], RAID firmware name */
+#define GDT_BINFO_UPDATE_PRES 0x40 /* u_int8_t, update present? */
+#define GDT_BINFO_XOR_PRES 0x41 /* u_int8_t, XOR engine present */
+#define GDT_BINFO_PROM_TYPE 0x42 /* u_int8_t, ROM type (eprom/flash) */
+#define GDT_BINFO_PROM_COUNT 0x43 /* u_int8_t, number of ROM devices */
+#define GDT_BINFO_DUP_PRES 0x44 /* u_int32_t, duplexing module pres? */
+#define GDT_BINFO_CHAN_PRES 0x48 /* u_int32_t, # of exp. channels */
+#define GDT_BINFO_MEM_PRES 0x4c /* u_int32_t, memory expansion inst? */
+#define GDT_BINFO_FT_BUS_SYSTEM 0x50 /* u_int8_t, fault bus supported? */
+#define GDT_BINFO_SUBTYPE_VALID 0x51 /* u_int8_t, board_subtype valid */
+#define GDT_BINFO_BOARD_SUBTYPE 0x52 /* u_int8_t, subtype/hardware level */
+#define GDT_BINFO_RAMPAR_PRES 0x53 /* u_int8_t, RAM parity check hw? */
+#define GDT_BINFO_SZ 0x54
+
+/* Get board features */
+#define GDT_BFEAT_CHAINING 0x00 /* u_int8_t, chaining supported */
+#define GDT_BFEAT_STRIPING 0x01 /* u_int8_t, striping (RAID-0) supp. */
+#define GDT_BFEAT_MIRRORING 0x02 /* u_int8_t, mirroring (RAID-1) supp */
+#define GDT_BFEAT_RAID 0x03 /* u_int8_t, RAID-4/5/10 supported */
+#define GDT_BFEAT_SZ 0x04
+
+/* Other defines */
+#define GDT_ASYNCINDEX 0 /* command index asynchronous event */
+#define GDT_SPEZINDEX 1 /* command index unknown service */
diff --git a/sys/dev/ic/gdtvar.h b/sys/dev/ic/gdtvar.h
new file mode 100644
index 00000000000..2ab04ed56d0
--- /dev/null
+++ b/sys/dev/ic/gdtvar.h
@@ -0,0 +1,272 @@
+/* $OpenBSD: gdtvar.h,v 1.1 2000/02/07 00:33:03 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. 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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niklas Hallqvist.
+ * 4. 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.
+ */
+
+/*
+ * This driver would not have written if it was not for the hardware donations
+ * from both ICP-Vortex and Öko.neT. I want to thank them for their support.
+ */
+
+/* Debugging */
+#ifdef GDT_DEBUG
+#define GDT_DPRINTF(mask, args) if (gdt_debug & (mask)) printf args
+#define GDT_D_INTR 0x01
+#define GDT_D_MISC 0x02
+#define GDT_D_CMD 0x04
+#define GDT_D_QUEUE 0x08
+#define GDT_D_IO 0x10
+extern int gdt_debug;
+#else
+#define GDT_PRINTF(args)
+#endif
+
+/* Miscellaneous constants */
+#define GDT_RETRIES 100000000 /* 100000 * 1us = 100s */
+#define GDT_TIMEOUT 100000000 /* 100000 * 1us = 100s */
+#define GDT_POLL_TIMEOUT 10000000 /* 10000 * 1us = 10s */
+#define GDT_WATCH_TIMEOUT 10000000 /* 10000 * 1us = 10s */
+#define GDT_SCRATCH_SZ 4096 /* 4KB scratch buffer */
+
+/* Context structure for interrupt services */
+struct gdt_intr_ctx {
+ u_int32_t info, info2;
+ u_int16_t cmd_status, service;
+ u_int8_t istatus;
+};
+
+/*
+ * A command contol block, one for each corresponding command index of the
+ * controller.
+ */
+struct gdt_ccb {
+ TAILQ_ENTRY(gdt_ccb) gc_chain;
+ struct scsi_xfer *gc_xs;
+ int gc_timeout;
+ u_int32_t gc_info;
+ u_int32_t gc_blockno;
+ u_int32_t gc_blockcnt;
+ u_int16_t gc_status;
+ u_int8_t gc_service;
+ u_int8_t gc_cmd_index;
+ u_int8_t gc_flags;
+#define GDT_GCF_CMD_MASK 0x3
+#define GDT_GCF_UNUSED 0
+#define GDT_GCF_INTERNAL 1
+#define GDT_GCF_SCREEN 2
+#define GDT_GCF_SCSI 3
+#define GDT_GCF_WATCHDOG 0x4
+};
+
+static __inline__ int gdt_ccb_set_cmd __P((struct gdt_ccb *, int));
+static __inline__ int
+gdt_ccb_set_cmd(ccb, flag)
+ struct gdt_ccb *ccb;
+ int flag;
+{
+ int rv = ccb->gc_flags & GDT_GCF_CMD_MASK;
+
+ ccb->gc_flags &= ~GDT_GCF_CMD_MASK;
+ ccb->gc_flags |= flag;
+ return (rv);
+}
+
+struct gdt_softc {
+ struct device sc_dev;
+ void *sc_ih;
+ struct scsi_link sc_link; /* Virtual SCSI bus for cache devs */
+ struct scsi_link *sc_raw_link; /* Raw SCSI busses */
+
+ int sc_class; /* Controller class */
+#define GDT_ISA 0x01
+#define GDT_EISA 0x02
+#define GDT_PCI 0x03
+#define GDT_PCINEW 0x04
+#define GDT_MPR 0x05
+#define GDT_CLASS_MASK 0x07
+#define GDT_FC 0x10
+#define GDT_CLASS(gdt) ((gdt)->sc_class & GDT_CLASS_MASK)
+
+ bus_space_tag_t sc_dpmemt;
+ bus_space_handle_t sc_dpmemh;
+ bus_addr_t sc_dpmembase;
+
+ /* XXX These could go into a class-dependent opaque struct instead */
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_addr_t sc_iobase;
+
+ u_int16_t sc_ic_all_size;
+
+ struct gdt_ccb sc_ccbs[GDT_MAXCMDS];
+ TAILQ_HEAD(, gdt_ccb) sc_free_ccb, sc_ccbq;
+ LIST_HEAD(, scsi_xfer) sc_queue;
+ struct scsi_xfer *sc_queuelast;
+
+ u_int16_t sc_cmd_len;
+ u_int16_t sc_cmd_off;
+ u_int16_t sc_cmd_cnt;
+ u_int8_t sc_cmd[GDT_CMD_SZ];
+
+ u_int32_t sc_info;
+ u_int32_t sc_info2;
+ u_int16_t sc_status;
+ u_int8_t sc_scratch[GDT_SCRATCH_SZ];
+
+ u_int8_t sc_bus_cnt;
+ u_int8_t sc_bus_id[GDT_MAXBUS];
+ u_int8_t sc_more_proc;
+
+ struct {
+ u_int8_t hd_present;
+ u_int8_t hd_is_logdrv;
+ u_int8_t hd_is_arraydrv;
+ u_int8_t hd_is_master;
+ u_int8_t hd_is_parity;
+ u_int8_t hd_is_hotfix;
+ u_int8_t hd_master_no;
+ u_int8_t hd_lock;
+ u_int8_t hd_heads;
+ u_int8_t hd_secs;
+ u_int16_t hd_devtype;
+ u_int32_t hd_size;
+ u_int8_t hd_ldr_no;
+ u_int8_t hd_rw_attribs;
+ u_int32_t hd_start_sec;
+ } sc_hdr[GDT_MAX_HDRIVES];
+
+ struct {
+ u_int32_t cp_version;
+ u_int16_t cp_state;
+ u_int16_t cp_strategy;
+ u_int16_t cp_write_back;
+ u_int16_t cp_block_size;
+ } sc_cpar;
+
+ struct {
+ u_int32_t bi_ser_no; /* serial number */
+ u_int8_t bi_oem_id[2]; /* u_int8_t OEM ID */
+ u_int16_t bi_ep_flags; /* eprom flags */
+ u_int32_t bi_proc_id; /* processor ID */
+ u_int32_t bi_memsize; /* memory size (bytes) */
+ u_int8_t bi_mem_banks; /* memory banks */
+ u_int8_t bi_chan_type; /* channel type */
+ u_int8_t bi_chan_count; /* channel count */
+ u_int8_t bi_rdongle_pres; /* dongle present */
+ u_int32_t bi_epr_fw_ver; /* (eprom) firmware ver */
+ u_int32_t bi_upd_fw_ver; /* (update) firmware ver */
+ u_int32_t bi_upd_revision; /* update revision */
+ char bi_type_string[16]; /* char controller name */
+ char bi_raid_string[16]; /* char RAID firmware name */
+ u_int8_t bi_update_pres; /* update present? */
+ u_int8_t bi_xor_pres; /* XOR engine present */
+ u_int8_t bi_prom_type; /* ROM type (eprom/flash) */
+ u_int8_t bi_prom_count; /* number of ROM devices */
+ u_int32_t bi_dup_pres; /* duplexing module pres? */
+ u_int32_t bi_chan_pres; /* # of exp. channels */
+ u_int32_t bi_mem_pres; /* memory expansion inst? */
+ u_int8_t bi_ft_bus_system; /* fault bus supported? */
+ u_int8_t bi_subtype_valid; /* board_subtype valid */
+ u_int8_t bi_board_subtype; /* subtype/hardware level */
+ u_int8_t bi_rampar_pres; /* RAM parity check hw? */
+ } sc_binfo;
+
+ struct {
+ u_int8_t bf_chaining; /* chaining supported */
+ u_int8_t bf_striping; /* striping (RAID-0) supported */
+ u_int8_t bf_mirroring; /* mirroring (RAID-1) supported */
+ u_int8_t bf_raid; /* RAID-4/5/10 supported */
+ } sc_bfeat;
+
+ u_int16_t sc_raw_feat;
+ u_int16_t sc_cache_feat;
+
+ int sc_spl;
+
+ void (*sc_copy_cmd) __P((struct gdt_softc *, struct gdt_ccb *));
+ u_int8_t (*sc_get_status) __P((struct gdt_softc *));
+ void (*sc_intr) __P((struct gdt_softc *, struct gdt_intr_ctx *));
+ void (*sc_release_event) __P((struct gdt_softc *, struct gdt_ccb *));
+ void (*sc_set_sema0) __P((struct gdt_softc *));
+ int (*sc_test_busy) __P((struct gdt_softc *));
+};
+
+/* XXX These have to become spinlocks in case of SMP */
+#define GDT_LOCK_GDT(gdt) (gdt)->sc_spl = splbio()
+#define GDT_UNLOCK_GDT(gdt) splx((gdt)->sc_spl)
+
+void gdtminphys __P((struct buf *));
+int gdt_attach __P((struct gdt_softc *));
+int gdt_intr __P((void *));
+
+#ifdef __GNUC__
+/* These all require correctly aligned buffers */
+static __inline__ void gdt_enc16 __P((u_int8_t *, u_int16_t));
+static __inline__ void gdt_enc32 __P((u_int8_t *, u_int32_t));
+static __inline__ u_int16_t gdt_dec16 __P((u_int8_t *));
+static __inline__ u_int32_t gdt_dec32 __P((u_int8_t *));
+
+static __inline__ void
+gdt_enc16(addr, value)
+ u_int8_t *addr;
+ u_int16_t value;
+{
+ *(u_int16_t *)addr = htole16(value);
+}
+
+static __inline__ void
+gdt_enc32(addr, value)
+ u_int8_t *addr;
+ u_int32_t value;
+{
+ *(u_int32_t *)addr = htole32(value);
+}
+
+static __inline__ u_int16_t
+gdt_dec16(addr)
+ u_int8_t *addr;
+{
+ return letoh16(*(u_int16_t *)addr);
+}
+
+static __inline__ u_int32_t
+gdt_dec32(addr)
+ u_int8_t *addr;
+{
+ return letoh32(*(u_int32_t *)addr);
+}
+#endif
+
+#if defined(__alpha__)
+/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
+#endif
+
+extern u_int8_t gdt_polling;
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 4adbf6698eb..9bdf34912f7 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.62 2000/01/10 13:58:16 jason Exp $
+# $OpenBSD: files.pci,v 1.63 2000/02/07 00:33:03 niklas Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -61,6 +61,11 @@ file dev/pci/eso.c eso
attach opl at eso with opl_eso
file dev/pci/opl_eso.c opl_eso
+# ICP Vortex GDT PCI RAID controllers
+# device declaration in sys/conf/files
+attach gdt at pci with gdt_pci
+file dev/pci/gdt_pci.c gdt_pci
+
# Qlogic ISP 10x0 (PCI) family
# device declaration in sys/conf/files
attach isp at pci with isp_pci
diff --git a/sys/dev/pci/gdt_pci.c b/sys/dev/pci/gdt_pci.c
new file mode 100644
index 00000000000..d84b68cdedc
--- /dev/null
+++ b/sys/dev/pci/gdt_pci.c
@@ -0,0 +1,822 @@
+/* $OpenBSD: gdt_pci.c,v 1.1 2000/02/07 00:33:03 niklas Exp $ */
+
+/*
+ * Copyright (c) 1999 Niklas Hallqvist. 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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niklas Hallqvist.
+ * 4. 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.
+ */
+
+/*
+ * This driver would not have written if it was not for the hardware donations
+ * from both ICP-Vortex and Öko.neT. I want to thank them for their support.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+
+#include <machine/bus.h>
+#include <machine/endian.h>
+#include <machine/intr.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/ic/gdtreg.h>
+#include <dev/ic/gdtvar.h>
+
+/* Product numbers for Fibre-Channel are greater than or equal to 0x200 */
+#define GDT_PCI_PRODUCT_FC 0x200
+
+/* Mapping registers for various areas */
+#define GDT_PCI_DPMEM 0x10
+#define GDT_PCINEW_IOMEM 0x10
+#define GDT_PCINEW_IO 0x14
+#define GDT_PCINEW_DPMEM 0x18
+
+/* PCI SRAM structure */
+#define GDT_MAGIC 0x00 /* u_int32_t, controller ID from BIOS */
+#define GDT_NEED_DEINIT 0x04 /* u_int16_t, switch between BIOS/driver */
+#define GDT_SWITCH_SUPPORT 0x06 /* u_int8_t, see GDT_NEED_DEINIT */
+#define GDT_OS_USED 0x10 /* u_int8_t [16], OS code per service */
+#define GDT_FW_MAGIC 0x3c /* u_int8_t, controller ID from firmware */
+#define GDT_SRAM_SZ 0x40
+
+/* DPRAM PCI controllers */
+#define GDT_DPR_IF 0x00 /* interface area */
+#define GDT_6SR (0xff0 - GDT_SRAM_SZ)
+#define GDT_SEMA1 0xff1 /* volatile u_int8_t, command semaphore */
+#define GDT_IRQEN 0xff5 /* u_int8_t, board interrupts enable */
+#define GDT_EVENT 0xff8 /* u_int8_t, release event */
+#define GDT_IRQDEL 0xffc /* u_int8_t, acknowledge board interrupt */
+#define GDT_DPRAM_SZ 0x1000
+
+/* PLX register structure (new PCI controllers) */
+#define GDT_CFG_REG 0x00 /* u_int8_t, DPRAM cfg. (2: < 1MB, 0: any) */
+#define GDT_SEMA0_REG 0x40 /* volatile u_int8_t, command semaphore */
+#define GDT_SEMA1_REG 0x41 /* volatile u_int8_t, status semaphore */
+#define GDT_PLX_STATUS 0x44 /* volatile u_int16_t, command status */
+#define GDT_PLX_SERVICE 0x46 /* u_int16_t, service */
+#define GDT_PLX_INFO 0x48 /* u_int32_t [2], additional info */
+#define GDT_LDOOR_REG 0x60 /* u_int8_t, PCI to local doorbell */
+#define GDT_EDOOR_REG 0x64 /* volatile u_int8_t, local to PCI doorbell */
+#define GDT_CONTROL0 0x68 /* u_int8_t, control0 register (unused) */
+#define GDT_CONTROL1 0x69 /* u_int8_t, board interrupts enable */
+#define GDT_PLX_SZ 0x80
+
+/* DPRAM new PCI controllers */
+#define GDT_IC 0x00 /* interface */
+#define GDT_PCINEW_6SR (0x4000 - GDT_SRAM_SZ)
+ /* SRAM structure */
+#define GDT_PCINEW_SZ 0x4000
+
+/* i960 register structure (PCI MPR controllers) */
+#define GDT_MPR_SEMA0 0x10 /* volatile u_int8_t, command semaphore */
+#define GDT_MPR_SEMA1 0x12 /* volatile u_int8_t, status semaphore */
+#define GDT_MPR_STATUS 0x14 /* volatile u_int16_t, command status */
+#define GDT_MPR_SERVICE 0x16 /* u_int16_t, service */
+#define GDT_MPR_INFO 0x18 /* u_int32_t [2], additional info */
+#define GDT_MPR_LDOOR 0x20 /* u_int8_t, PCI to local doorbell */
+#define GDT_MPR_EDOOR 0x2c /* volatile u_int8_t, locl to PCI doorbell */
+#define GDT_EDOOR_EN 0x34 /* u_int8_t, board interrupts enable */
+#define GDT_I960_SZ 0x1000
+
+/* DPRAM PCI MPR controllers */
+#define GDT_I960R 0x00 /* 4KB i960 registers */
+#define GDT_MPR_IC GDT_I960_SZ
+ /* interface area */
+#define GDT_MPR_6SR (GDT_I960_SZ + 0x3000 - GDT_SRAM_SZ)
+ /* SRAM structure */
+#define GDT_MPR_SZ 0x4000
+
+int gdt_pci_probe __P((struct device *, void *, void *));
+void gdt_pci_attach __P((struct device *, struct device *, void *));
+void gdt_pci_enable_intr __P((struct gdt_softc *));
+
+void gdt_pci_copy_cmd __P((struct gdt_softc *, struct gdt_ccb *));
+u_int8_t gdt_pci_get_status __P((struct gdt_softc *));
+void gdt_pci_intr __P((struct gdt_softc *, struct gdt_intr_ctx *));
+void gdt_pci_release_event __P((struct gdt_softc *, struct gdt_ccb *));
+void gdt_pci_set_sema0 __P((struct gdt_softc *));
+int gdt_pci_test_busy __P((struct gdt_softc *));
+
+void gdt_pcinew_copy_cmd __P((struct gdt_softc *, struct gdt_ccb *));
+u_int8_t gdt_pcinew_get_status __P((struct gdt_softc *));
+void gdt_pcinew_intr __P((struct gdt_softc *, struct gdt_intr_ctx *));
+void gdt_pcinew_release_event __P((struct gdt_softc *, struct gdt_ccb *));
+void gdt_pcinew_set_sema0 __P((struct gdt_softc *));
+int gdt_pcinew_test_busy __P((struct gdt_softc *));
+
+void gdt_mpr_copy_cmd __P((struct gdt_softc *, struct gdt_ccb *));
+u_int8_t gdt_mpr_get_status __P((struct gdt_softc *));
+void gdt_mpr_intr __P((struct gdt_softc *, struct gdt_intr_ctx *));
+void gdt_mpr_release_event __P((struct gdt_softc *, struct gdt_ccb *));
+void gdt_mpr_set_sema0 __P((struct gdt_softc *));
+int gdt_mpr_test_busy __P((struct gdt_softc *));
+
+struct cfattach gdt_pci_ca = {
+ sizeof (struct gdt_softc), gdt_pci_probe, gdt_pci_attach
+};
+
+int
+gdt_pci_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VORTEX)
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_VORTEX_GDT_60x0:
+ case PCI_PRODUCT_VORTEX_GDT_6000B:
+ case PCI_PRODUCT_VORTEX_GDT_6x10:
+ case PCI_PRODUCT_VORTEX_GDT_6x20:
+ case PCI_PRODUCT_VORTEX_GDT_6530:
+ case PCI_PRODUCT_VORTEX_GDT_6550:
+ case PCI_PRODUCT_VORTEX_GDT_6x17:
+ case PCI_PRODUCT_VORTEX_GDT_6x27:
+ case PCI_PRODUCT_VORTEX_GDT_6537:
+ case PCI_PRODUCT_VORTEX_GDT_6557:
+ case PCI_PRODUCT_VORTEX_GDT_6x15:
+ case PCI_PRODUCT_VORTEX_GDT_6x25:
+ case PCI_PRODUCT_VORTEX_GDT_6535:
+ case PCI_PRODUCT_VORTEX_GDT_6555:
+ case PCI_PRODUCT_VORTEX_GDT_6x17RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x27RP:
+ case PCI_PRODUCT_VORTEX_GDT_6537RP:
+ case PCI_PRODUCT_VORTEX_GDT_6557RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x11RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x21RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x17RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x27RD:
+ case PCI_PRODUCT_VORTEX_GDT_6537RD:
+ case PCI_PRODUCT_VORTEX_GDT_6557RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x11RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x21RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x18RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x28RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x38RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x58RD:
+ case PCI_PRODUCT_VORTEX_GDT_7x18RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x28RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x38RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x58RN:
+ case PCI_PRODUCT_VORTEX_GDT_6x19RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x29RD:
+ case PCI_PRODUCT_VORTEX_GDT_7x19RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x29RN:
+ return (1);
+ }
+ return (0);
+}
+
+void
+gdt_pci_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+ struct gdt_softc *gdt = (void *)self;
+ bus_space_tag_t dpmemt, iomemt, iot;
+ bus_space_handle_t dpmemh, iomemh, ioh;
+ bus_addr_t dpmembase, iomembase, iobase;
+ bus_size_t dpmemsize, iomemsize, iosize;
+ u_int16_t prod;
+ u_int32_t status = 0;
+#define DPMEM_MAPPED 1
+#define IOMEM_MAPPED 2
+#define IO_MAPPED 4
+#define INTR_ESTABLISHED 8
+ int retries;
+ u_int8_t protocol;
+ pci_intr_handle_t ih;
+ const char *intrstr;
+
+ printf(": ");
+
+ prod = PCI_PRODUCT(pa->pa_id);
+ switch (prod) {
+ case PCI_PRODUCT_VORTEX_GDT_60x0:
+ case PCI_PRODUCT_VORTEX_GDT_6000B:
+ gdt->sc_class = GDT_PCI;
+ break;
+
+ case PCI_PRODUCT_VORTEX_GDT_6x10:
+ case PCI_PRODUCT_VORTEX_GDT_6x20:
+ case PCI_PRODUCT_VORTEX_GDT_6530:
+ case PCI_PRODUCT_VORTEX_GDT_6550:
+ case PCI_PRODUCT_VORTEX_GDT_6x17:
+ case PCI_PRODUCT_VORTEX_GDT_6x27:
+ case PCI_PRODUCT_VORTEX_GDT_6537:
+ case PCI_PRODUCT_VORTEX_GDT_6557:
+ case PCI_PRODUCT_VORTEX_GDT_6x15:
+ case PCI_PRODUCT_VORTEX_GDT_6x25:
+ case PCI_PRODUCT_VORTEX_GDT_6535:
+ case PCI_PRODUCT_VORTEX_GDT_6555:
+ gdt->sc_class = GDT_PCINEW;
+ break;
+
+ case PCI_PRODUCT_VORTEX_GDT_6x17RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x27RP:
+ case PCI_PRODUCT_VORTEX_GDT_6537RP:
+ case PCI_PRODUCT_VORTEX_GDT_6557RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x11RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x21RP:
+ case PCI_PRODUCT_VORTEX_GDT_6x17RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x27RD:
+ case PCI_PRODUCT_VORTEX_GDT_6537RD:
+ case PCI_PRODUCT_VORTEX_GDT_6557RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x11RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x21RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x18RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x28RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x38RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x58RD:
+ case PCI_PRODUCT_VORTEX_GDT_7x18RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x28RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x38RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x58RN:
+ case PCI_PRODUCT_VORTEX_GDT_6x19RD:
+ case PCI_PRODUCT_VORTEX_GDT_6x29RD:
+ case PCI_PRODUCT_VORTEX_GDT_7x19RN:
+ case PCI_PRODUCT_VORTEX_GDT_7x29RN:
+ gdt->sc_class = GDT_MPR;
+ }
+ if (prod >= GDT_PCI_PRODUCT_FC)
+ gdt->sc_class |= GDT_FC;
+
+ if (pci_mapreg_map(pa,
+ GDT_CLASS(gdt) == GDT_PCINEW ? GDT_PCINEW_DPMEM : GDT_PCI_DPMEM,
+ PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT_1M, 0, &dpmemt,
+ &dpmemh, &dpmembase, &dpmemsize)) {
+ printf("cannot map DPMEM\n");
+ goto bail_out;
+ }
+ status |= DPMEM_MAPPED;
+ gdt->sc_dpmemt = dpmemt;
+ gdt->sc_dpmemh = dpmemh;
+ gdt->sc_dpmembase = dpmembase;
+
+ /*
+ * The GDT_PCINEW series also has two other regions to map.
+ */
+ if (GDT_CLASS(gdt) == GDT_PCINEW) {
+ if (pci_mapreg_map(pa, GDT_PCINEW_IOMEM, PCI_MAPREG_TYPE_MEM,
+ 0, &iomemt, &iomemh, &iomembase, &iomemsize)) {
+ printf("cannot map memory mapped I/O ports\n");
+ goto bail_out;
+ }
+ status |= IOMEM_MAPPED;
+
+ if (pci_mapreg_map(pa, GDT_PCINEW_IO, PCI_MAPREG_TYPE_IO, 0,
+ &iot, &ioh, &iobase, &iosize)) {
+ printf("cannot map I/O ports\n");
+ goto bail_out;
+ }
+ status |= IO_MAPPED;
+ gdt->sc_iot = iot;
+ gdt->sc_ioh = ioh;
+ gdt->sc_iobase = iobase;
+ }
+
+ switch (GDT_CLASS(gdt)) {
+ case GDT_PCI:
+ bus_space_set_region_4(dpmemt, dpmemh, 0, htole32(0),
+ GDT_DPR_IF_SZ >> 2);
+ if (bus_space_read_1(dpmemt, dpmemh, 0) != 0) {
+ printf("cannot write to DPMEM\n");
+ goto bail_out;
+ }
+
+#if 0
+ /* disable board interrupts, deinit services */
+ gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+ gdth_writeb(0x00, &dp6_ptr->io.irqen);;
+ gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status);
+ gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
+
+ gdth_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
+ gdth_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
+ gdth_writeb(0, &dp6_ptr->io.event);
+ retries = INIT_RETRIES;
+ gdth_delay(20);
+ while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+ gdth_delay(1);
+ }
+ prot_ver = (unchar)gdth_readl(&dp6_ptr->u.ic.S_Info[0]);
+ gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
+ gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+ if (prot_ver != PROTOCOL_VERSION) {
+ printk("GDT-PCI: Illegal protocol version\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+
+ ha->type = GDT_PCI;
+ ha->ic_all_size = sizeof(dp6_ptr->u);
+
+ /* special command to controller BIOS */
+ gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
+ gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
+ gdth_writel(0x01, &dp6_ptr->u.ic.S_Info[2]);
+ gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
+ gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
+ gdth_writeb(0, &dp6_ptr->io.event);
+ retries = INIT_RETRIES;
+ gdth_delay(20);
+ while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+ gdth_delay(1);
+ }
+ gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
+ gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+#endif
+
+ gdt->sc_ic_all_size = GDT_DPRAM_SZ;
+
+ gdt->sc_copy_cmd = gdt_pci_copy_cmd;
+ gdt->sc_get_status = gdt_pci_get_status;
+ gdt->sc_intr = gdt_pci_intr;
+ gdt->sc_release_event = gdt_pci_release_event;
+ gdt->sc_set_sema0 = gdt_pci_set_sema0;
+ gdt->sc_test_busy = gdt_pci_test_busy;
+
+ break;
+
+ case GDT_PCINEW:
+ bus_space_set_region_4(dpmemt, dpmemh, 0, htole32(0),
+ GDT_DPR_IF_SZ >> 2);
+ if (bus_space_read_1(dpmemt, dpmemh, 0) != 0) {
+ printf("cannot write to DPMEM\n");
+ goto bail_out;
+ }
+
+#if 0
+ /* disable board interrupts, deinit services */
+ outb(0x00,PTR2USHORT(&ha->plx->control1));
+ outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
+
+ gdth_writeb(0x00, &dp6c_ptr->u.ic.S_Status);
+ gdth_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
+
+ gdth_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
+ gdth_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
+
+ outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+ retries = INIT_RETRIES;
+ gdth_delay(20);
+ while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+ gdth_delay(1);
+ }
+ prot_ver = (unchar)gdth_readl(&dp6c_ptr->u.ic.S_Info[0]);
+ gdth_writeb(0, &dp6c_ptr->u.ic.Status);
+ if (prot_ver != PROTOCOL_VERSION) {
+ printk("GDT-PCI: Illegal protocol version\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+
+ ha->type = GDT_PCINEW;
+ ha->ic_all_size = sizeof(dp6c_ptr->u);
+
+ /* special command to controller BIOS */
+ gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
+ gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
+ gdth_writel(0x01, &dp6c_ptr->u.ic.S_Info[2]);
+ gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
+ gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
+
+ outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+ retries = INIT_RETRIES;
+ gdth_delay(20);
+ while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+ gdth_delay(1);
+ }
+ gdth_writeb(0, &dp6c_ptr->u.ic.S_Status);
+#endif
+
+ gdt->sc_ic_all_size = GDT_PCINEW_SZ;
+
+ gdt->sc_copy_cmd = gdt_pcinew_copy_cmd;
+ gdt->sc_get_status = gdt_pcinew_get_status;
+ gdt->sc_intr = gdt_pcinew_intr;
+ gdt->sc_release_event = gdt_pcinew_release_event;
+ gdt->sc_set_sema0 = gdt_pcinew_set_sema0;
+ gdt->sc_test_busy = gdt_pcinew_test_busy;
+
+ break;
+
+ case GDT_MPR:
+ bus_space_write_4(dpmemt, dpmemh, GDT_MPR_IC,
+ htole32(GDT_MPR_MAGIC));
+ if (bus_space_read_4(dpmemt, dpmemh, GDT_MPR_IC) !=
+ htole32(GDT_MPR_MAGIC)) {
+ printf("cannot access DPMEM at 0x%x (shadowed?)\n",
+ dpmembase);
+ goto bail_out;
+ }
+
+ /*
+ * XXX Here the Linux driver has a weird remapping logic I
+ * don't understand. My controller does not need it, and I
+ * cannot see what purpose it serves, therefore I did not
+ * do anything similar.
+ */
+
+ bus_space_set_region_4(dpmemt, dpmemh, GDT_I960_SZ, htole32(0),
+ GDT_DPR_IF_SZ >> 2);
+
+ /* Disable everything */
+ bus_space_write_1(dpmemt, dpmemh, GDT_EDOOR_EN,
+ bus_space_read_1(dpmemt, dpmemh, GDT_EDOOR_EN) | 4);
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_EDOOR, 0xff);
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_IC + GDT_S_STATUS,
+ 0);
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_IC + GDT_CMD_INDEX,
+ 0);
+
+ bus_space_write_4(dpmemt, dpmemh, GDT_MPR_IC + GDT_S_INFO,
+ htole32(dpmembase));
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_IC + GDT_S_CMD_INDX,
+ 0xff);
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_LDOOR, 1);
+
+ DELAY(20);
+ retries = GDT_RETRIES;
+ while (bus_space_read_1(dpmemt, dpmemh,
+ GDT_MPR_IC + GDT_S_STATUS) != 0xff) {
+ if (--retries == 0) {
+ printf("DEINIT failed\n");
+ goto bail_out;
+ }
+ DELAY(1);
+ }
+
+ protocol = (u_int8_t)letoh32(bus_space_read_4(dpmemt, dpmemh,
+ GDT_MPR_IC + GDT_S_INFO));
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_IC + GDT_S_STATUS,
+ 0);
+ if (protocol != GDT_PROTOCOL_VERSION) {
+ printf("unsupported protocol %d\n", protocol);
+ goto bail_out;
+ }
+
+ /* special commnd to controller BIOS */
+ bus_space_write_4(dpmemt, dpmemh, GDT_MPR_IC + GDT_S_INFO,
+ htole32(0));
+ bus_space_write_4(dpmemt, dpmemh,
+ GDT_MPR_IC + GDT_S_INFO + sizeof (u_int32_t), htole32(0));
+ bus_space_write_4(dpmemt, dpmemh,
+ GDT_MPR_IC + GDT_S_INFO + 2 * sizeof (u_int32_t),
+ htole32(1));
+ bus_space_write_4(dpmemt, dpmemh,
+ GDT_MPR_IC + GDT_S_INFO + 3 * sizeof (u_int32_t),
+ htole32(0));
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_IC + GDT_S_CMD_INDX,
+ 0xfe);
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_LDOOR, 1);
+
+ DELAY(20);
+ retries = GDT_RETRIES;
+ while (bus_space_read_1(dpmemt, dpmemh,
+ GDT_MPR_IC + GDT_S_STATUS) != 0xfe) {
+ if (--retries == 0) {
+ printf("initialization error\n");
+ goto bail_out;
+ }
+ DELAY(1);
+ }
+
+ bus_space_write_1(dpmemt, dpmemh, GDT_MPR_IC + GDT_S_STATUS,
+ 0);
+
+ gdt->sc_ic_all_size = GDT_MPR_SZ;
+
+ gdt->sc_copy_cmd = gdt_mpr_copy_cmd;
+ gdt->sc_get_status = gdt_mpr_get_status;
+ gdt->sc_intr = gdt_mpr_intr;
+ gdt->sc_release_event = gdt_mpr_release_event;
+ gdt->sc_set_sema0 = gdt_mpr_set_sema0;
+ gdt->sc_test_busy = gdt_mpr_test_busy;
+ }
+
+ if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("couldn't map interrupt\n");
+ goto bail_out;
+ }
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+ gdt->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, gdt_intr, gdt,
+ gdt->sc_dev.dv_xname);
+ if (gdt->sc_ih == NULL) {
+ printf("couldn't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ goto bail_out;
+ }
+ status |= INTR_ESTABLISHED;
+ if (intrstr != NULL)
+ printf("%s ", intrstr);
+
+ if (gdt_attach(gdt))
+ goto bail_out;
+
+ gdt_pci_enable_intr(gdt);
+
+ return;
+
+ bail_out:
+ if (status & DPMEM_MAPPED)
+ bus_space_unmap(dpmemt, dpmemh, dpmemsize);
+ if (status & IOMEM_MAPPED)
+ bus_space_unmap(iomemt, iomemh, iomembase);
+ if (status & IO_MAPPED)
+ bus_space_unmap(iot, ioh, iosize);
+ if (status & INTR_ESTABLISHED)
+ pci_intr_disestablish(pa->pa_pc, gdt->sc_ih);
+ return;
+}
+
+/* Enable interrupts */
+void
+gdt_pci_enable_intr(gdt)
+ struct gdt_softc *gdt;
+{
+ GDT_DPRINTF(GDT_D_INTR, ("gdt_pci_enable_intr(%p) ", gdt));
+
+ switch(GDT_CLASS(gdt)) {
+ case GDT_PCI:
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_IRQDEL,
+ 1);
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_CMD_INDEX, 0);
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_IRQEN,
+ 1);
+ break;
+
+ case GDT_PCINEW:
+ bus_space_write_1(gdt->sc_iot, gdt->sc_ioh, GDT_EDOOR_REG,
+ 0xff);
+ bus_space_write_1(gdt->sc_iot, gdt->sc_ioh, GDT_CONTROL1, 3);
+ break;
+
+ case GDT_MPR:
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_MPR_EDOOR, 0xff);
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_EDOOR_EN,
+ bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_EDOOR_EN) & ~4);
+ break;
+ }
+}
+
+/*
+ * "old" PCI controller-specific functions
+ */
+
+void
+gdt_pci_copy_cmd(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ /* XXX Not yet implemented */
+}
+
+u_int8_t
+gdt_pci_get_status(gdt)
+ struct gdt_softc *gdt;
+{
+ /* XXX Not yet implemented */
+ return (0);
+}
+
+void
+gdt_pci_intr(gdt, ctx)
+ struct gdt_softc *gdt;
+ struct gdt_intr_ctx *ctx;
+{
+ /* XXX Not yet implemented */
+}
+
+void
+gdt_pci_release_event(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ /* XXX Not yet implemented */
+}
+
+void
+gdt_pci_set_sema0(gdt)
+ struct gdt_softc *gdt;
+{
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_SEMA0, 1);
+}
+
+int
+gdt_pci_test_busy(gdt)
+ struct gdt_softc *gdt;
+{
+ /* XXX Not yet implemented */
+ return (0);
+}
+
+/*
+ * "new" PCI controller-specific functions
+ */
+
+void
+gdt_pcinew_copy_cmd(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ /* XXX Not yet implemented */
+}
+
+u_int8_t
+gdt_pcinew_get_status(gdt)
+ struct gdt_softc *gdt;
+{
+ /* XXX Not yet implemented */
+ return (0);
+}
+
+void
+gdt_pcinew_intr(gdt, ctx)
+ struct gdt_softc *gdt;
+ struct gdt_intr_ctx *ctx;
+{
+ /* XXX Not yet implemented */
+}
+
+void
+gdt_pcinew_release_event(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ /* XXX Not yet implemented */
+}
+
+void
+gdt_pcinew_set_sema0(gdt)
+ struct gdt_softc *gdt;
+{
+ bus_space_write_1(gdt->sc_iot, gdt->sc_ioh, GDT_SEMA0_REG, 1);
+}
+
+int
+gdt_pcinew_test_busy(gdt)
+ struct gdt_softc *gdt;
+{
+ /* XXX Not yet implemented */
+ return (0);
+}
+
+/*
+ * MPR PCI controller-specific functions
+ */
+
+void
+gdt_mpr_copy_cmd(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ u_int16_t cp_count = roundup(gdt->sc_cmd_len, sizeof (u_int32_t));
+ u_int16_t dp_offset = gdt->sc_cmd_off;
+ u_int16_t cmd_no = gdt->sc_cmd_cnt++;
+
+ GDT_DPRINTF(GDT_D_CMD, ("gdt_mpr_copy_cmd(%p) ", gdt));
+
+ gdt->sc_cmd_off += cp_count;
+
+ bus_space_write_2(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_MPR_IC + GDT_COMM_QUEUE + cmd_no * GDT_COMM_Q_SZ + GDT_OFFSET,
+ htole16(GDT_DPMEM_COMMAND_OFFSET + dp_offset));
+ bus_space_write_2(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_MPR_IC + GDT_COMM_QUEUE + cmd_no * GDT_COMM_Q_SZ + GDT_SERV_ID,
+ htole16(ccb->gc_service));
+ bus_space_write_raw_region_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_MPR_IC + GDT_DPR_CMD + dp_offset, gdt->sc_cmd, cp_count);
+}
+
+u_int8_t
+gdt_mpr_get_status(gdt)
+ struct gdt_softc *gdt;
+{
+ GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_get_status(%p) ", gdt));
+
+ return bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_EDOOR);
+}
+
+void
+gdt_mpr_intr(gdt, ctx)
+ struct gdt_softc *gdt;
+ struct gdt_intr_ctx *ctx;
+{
+ GDT_DPRINTF(GDT_D_INTR, ("gdt_mpr_intr(%p) ", gdt));
+
+ if (ctx->istatus & 0x80) { /* error flag */
+ ctx->istatus &= 0x80;
+ ctx->cmd_status = bus_space_read_2(gdt->sc_dpmemt,
+ gdt->sc_dpmemh, GDT_MPR_STATUS);
+ if (ctx->istatus == GDT_ASYNCINDEX) {
+ ctx->service = bus_space_read_2(gdt->sc_dpmemt,
+ gdt->sc_dpmemh, GDT_MPR_SERVICE);
+ ctx->info2 = bus_space_read_4(gdt->sc_dpmemt,
+ gdt->sc_dpmemh, GDT_MPR_INFO + sizeof (u_int32_t));
+ }
+ } else /* no error */
+ ctx->cmd_status = GDT_S_OK;
+
+ ctx->info =
+ bus_space_read_4(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_INFO);
+
+ if (gdt_polling) /* init. -> more info */
+ ctx->info2 = bus_space_read_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_MPR_INFO + sizeof (u_int32_t));
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_EDOOR, 0xff);
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_SEMA1, 0);
+}
+
+void
+gdt_mpr_release_event(gdt, ccb)
+ struct gdt_softc *gdt;
+ struct gdt_ccb *ccb;
+{
+ GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_release_event(%p) ", gdt));
+
+ if (gdt_dec16(gdt->sc_cmd + GDT_CMD_OPCODE) == GDT_INIT)
+ ccb->gc_service |= 0x80;
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_LDOOR, 1);
+}
+
+void
+gdt_mpr_set_sema0(gdt)
+ struct gdt_softc *gdt;
+{
+ GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_set_sema0(%p) ", gdt));
+
+ bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_SEMA0, 1);
+}
+
+int
+gdt_mpr_test_busy(gdt)
+ struct gdt_softc *gdt;
+{
+ GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_test_busy(%p) ", gdt));
+
+ return (bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
+ GDT_MPR_SEMA0) & 1);
+}
diff --git a/sys/dev/pci/pcidevs b/sys/dev/pci/pcidevs
index a16598533bd..6384f6c6ca9 100644
--- a/sys/dev/pci/pcidevs
+++ b/sys/dev/pci/pcidevs
@@ -1,4 +1,4 @@
- $OpenBSD: pcidevs,v 1.214 2000/02/01 05:39:41 deraadt Exp $
+ $OpenBSD: pcidevs,v 1.215 2000/02/07 00:33:03 niklas Exp $
/* $NetBSD: pcidevs,v 1.30 1997/06/24 06:20:24 thorpej Exp $ */
@@ -1463,10 +1463,10 @@ product VORTEX GDT_6x27 0x0007 GDT6127/6527
product VORTEX GDT_6537 0x0008 GDT6537
product VORTEX GDT_6557 0x0009 GDT6557/6557-ECC
/* GDT_PCINEW, wide SCSI controllers */
-product VORTEX GDT_6x15 0x00010 GDT6115/6515
-product VORTEX GDT_6x25 0x00011 GDT6125/6525
-product VORTEX GDT_6535 0x00012 GDT6535
-product VORTEX GDT_6555 0x00013 GDT6555/6555-ECC
+product VORTEX GDT_6x15 0x0010 GDT6115/6515
+product VORTEX GDT_6x25 0x0011 GDT6125/6525
+product VORTEX GDT_6535 0x0012 GDT6535
+product VORTEX GDT_6555 0x0013 GDT6555/6555-ECC
/* GDT_MPR, RP series, wide/ultra SCSI */
product VORTEX GDT_6x17RP 0x0100 GDT6117RP/GDT6517RP
product VORTEX GDT_6x27RP 0x0101 GDT6127RP/GDT6527RP