summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/mips64/conf/files.mips643
-rw-r--r--sys/arch/mips64/include/arcbios.h3
-rw-r--r--sys/arch/mips64/include/cpu.h5
-rw-r--r--sys/arch/mips64/mips64/arcbios.c3
-rw-r--r--sys/arch/mips64/mips64/cache_r4k.c323
-rw-r--r--sys/arch/mips64/mips64/cp0access.S9
-rw-r--r--sys/arch/mips64/mips64/cpu.c28
-rw-r--r--sys/arch/mips64/mips64/exception.S7
-rw-r--r--sys/arch/mips64/mips64/lcore_access.S34
-rw-r--r--sys/arch/mips64/mips64/tlbhandler.S18
-rw-r--r--sys/arch/mips64/mips64/trap.c32
-rw-r--r--sys/arch/sgi/compile/.cvsignore3
-rw-r--r--sys/arch/sgi/conf/GENERIC-IP2285
-rw-r--r--sys/arch/sgi/conf/RAMDISK-IP2295
-rw-r--r--sys/arch/sgi/conf/files.sgi29
-rw-r--r--sys/arch/sgi/dev/dsrtc.c4
-rw-r--r--sys/arch/sgi/gio/Makefile8
-rw-r--r--sys/arch/sgi/gio/devlist2h.awk152
-rw-r--r--sys/arch/sgi/gio/files.gio31
-rw-r--r--sys/arch/sgi/gio/gio.c518
-rw-r--r--sys/arch/sgi/gio/giodevs21
-rw-r--r--sys/arch/sgi/gio/gioreg.h68
-rw-r--r--sys/arch/sgi/gio/giovar.h75
-rw-r--r--sys/arch/sgi/hpc/dpclock.c312
-rw-r--r--sys/arch/sgi/hpc/dsclock.c192
-rw-r--r--sys/arch/sgi/hpc/files.hpc56
-rw-r--r--sys/arch/sgi/hpc/hpc.c822
-rw-r--r--sys/arch/sgi/hpc/hpcdma.c208
-rw-r--r--sys/arch/sgi/hpc/hpcdma.h63
-rw-r--r--sys/arch/sgi/hpc/hpcreg.h450
-rw-r--r--sys/arch/sgi/hpc/hpcvar.h109
-rw-r--r--sys/arch/sgi/hpc/if_sq.c1348
-rw-r--r--sys/arch/sgi/hpc/if_sqvar.h200
-rw-r--r--sys/arch/sgi/hpc/iocreg.h122
-rw-r--r--sys/arch/sgi/hpc/wdsc.c290
-rw-r--r--sys/arch/sgi/hpc/z8530sc.c409
-rw-r--r--sys/arch/sgi/hpc/z8530sc.h199
-rw-r--r--sys/arch/sgi/hpc/z8530tty.c1663
-rw-r--r--sys/arch/sgi/hpc/zs.c712
-rw-r--r--sys/arch/sgi/include/autoconf.h3
-rw-r--r--sys/arch/sgi/include/eisa_machdep.h68
-rw-r--r--sys/arch/sgi/include/z8530var.h121
-rw-r--r--sys/arch/sgi/localbus/imc.c826
-rw-r--r--sys/arch/sgi/localbus/imcreg.h143
-rw-r--r--sys/arch/sgi/localbus/imcvar.h42
-rw-r--r--sys/arch/sgi/localbus/int.c369
-rw-r--r--sys/arch/sgi/localbus/intreg.h51
-rw-r--r--sys/arch/sgi/localbus/intvar.h34
-rw-r--r--sys/arch/sgi/sgi/autoconf.c45
-rw-r--r--sys/arch/sgi/sgi/conf.c12
-rw-r--r--sys/arch/sgi/sgi/ip22.h32
-rw-r--r--sys/arch/sgi/sgi/ip22_machdep.c277
-rw-r--r--sys/arch/sgi/sgi/ip30_machdep.c6
-rw-r--r--sys/arch/sgi/sgi/ip32_machdep.c6
-rw-r--r--sys/arch/sgi/sgi/machdep.c147
-rw-r--r--sys/arch/sgi/sgi/mainbus.c21
-rw-r--r--sys/arch/sgi/stand/Makefile5
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/eisa/eisavar.h15
-rw-r--r--sys/dev/ic/dp8573areg.h121
-rw-r--r--sys/dev/ic/dp857xreg.h133
-rw-r--r--sys/dev/ic/ds1286reg.h182
-rw-r--r--sys/dev/ic/seeq8003reg.h134
-rw-r--r--sys/dev/ic/wd33c93.c2337
-rw-r--r--sys/dev/ic/wd33c93reg.h510
-rw-r--r--sys/dev/ic/wd33c93var.h262
-rw-r--r--sys/dev/ic/z8530reg.h7
67 files changed, 14400 insertions, 224 deletions
diff --git a/sys/arch/mips64/conf/files.mips64 b/sys/arch/mips64/conf/files.mips64
index def002b4c53..9383b21aadd 100644
--- a/sys/arch/mips64/conf/files.mips64
+++ b/sys/arch/mips64/conf/files.mips64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.mips64,v 1.17 2010/10/24 15:40:03 miod Exp $
+# $OpenBSD: files.mips64,v 1.18 2012/03/28 20:44:23 miod Exp $
file arch/mips64/mips64/arcbios.c arcbios
file arch/mips64/mips64/clock.c
@@ -15,6 +15,7 @@ file arch/mips64/mips64/trap.c
file arch/mips64/mips64/vm_machdep.c
file arch/mips64/mips64/cache_loongson2.S cpu_loongson2
+file arch/mips64/mips64/cache_r4k.c cpu_r4000
file arch/mips64/mips64/cache_r5k.S cpu_r5000 | cpu_rm7000
file arch/mips64/mips64/cache_r10k.S cpu_r10000
file arch/mips64/mips64/cache_octeon.c cpu_octeon
diff --git a/sys/arch/mips64/include/arcbios.h b/sys/arch/mips64/include/arcbios.h
index 51e6f00b014..112bbaf2f2c 100644
--- a/sys/arch/mips64/include/arcbios.h
+++ b/sys/arch/mips64/include/arcbios.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: arcbios.h,v 1.18 2011/06/05 20:58:46 miod Exp $ */
+/* $OpenBSD: arcbios.h,v 1.19 2012/03/28 20:44:23 miod Exp $ */
/*-
* Copyright (c) 1996 M. Warner Losh. All rights reserved.
*
@@ -419,6 +419,7 @@ typedef struct arc_param_blk_64
#define ARCBIOS_PAGE_SIZE 4096
extern int bios_is_32bit;
+extern int bios_consrate;
extern char bios_enaddr[20];
extern char bios_console[30];
extern char bios_graphics[6];
diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h
index 5a079b54e11..59b0760382b 100644
--- a/sys/arch/mips64/include/cpu.h
+++ b/sys/arch/mips64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.77 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: cpu.h,v 1.78 2012/03/28 20:44:23 miod Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -560,6 +560,7 @@ uint32_t cp0_get_config_2(void);
uint32_t cp0_get_config_3(void);
uint32_t cp0_get_prid(void);
void cp0_set_compare(u_int);
+void cp0_set_config(uint32_t);
u_int cp1_get_prid(void);
void tlb_set_page_mask(uint32_t);
void tlb_set_pid(int);
@@ -580,6 +581,8 @@ void save_fpu(void);
int fpe_branch_emulate(struct proc *, struct trap_frame *, uint32_t,
vaddr_t);
+int guarded_read_1(paddr_t, uint8_t *);
+int guarded_read_2(paddr_t, uint16_t *);
int guarded_read_4(paddr_t, uint32_t *);
int guarded_write_4(paddr_t, uint32_t);
diff --git a/sys/arch/mips64/mips64/arcbios.c b/sys/arch/mips64/mips64/arcbios.c
index e0704b8a504..dac9405f891 100644
--- a/sys/arch/mips64/mips64/arcbios.c
+++ b/sys/arch/mips64/mips64/arcbios.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: arcbios.c,v 1.31 2012/03/24 20:11:28 miod Exp $ */
+/* $OpenBSD: arcbios.c,v 1.32 2012/03/28 20:44:23 miod Exp $ */
/*-
* Copyright (c) 1996 M. Warner Losh. All rights reserved.
* Copyright (c) 1996-2004 Opsycon AB. All rights reserved.
@@ -50,6 +50,7 @@ int bios_is_32bit;
*/
char bios_enaddr[20] = "ff:ff:ff:ff:ff:ff";
+int bios_consrate; /* Serial console speed. */
char bios_console[30]; /* Primary console. */
char bios_graphics[6]; /* Graphics state. */
char bios_keyboard[6]; /* Keyboard layout. */
diff --git a/sys/arch/mips64/mips64/cache_r4k.c b/sys/arch/mips64/mips64/cache_r4k.c
new file mode 100644
index 00000000000..5d8aec81215
--- /dev/null
+++ b/sys/arch/mips64/mips64/cache_r4k.c
@@ -0,0 +1,323 @@
+/* $OpenBSD: cache_r4k.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <mips64/cache.h>
+#include <machine/cpu.h>
+
+#define IndexInvalidate_I 0x00
+#define IndexWBInvalidate_D 0x01
+#define IndexWBInvalidate_S 0x03
+
+#define HitInvalidate_D 0x11
+#define HitInvalidate_S 0x13
+
+#define HitWBInvalidate_D 0x15
+#define HitWBInvalidate_S 0x17
+
+#define cache(op,addr) \
+ __asm__ __volatile__ ("cache %0, 0(%1)" :: "i"(op), "r"(addr) : "memory")
+#define sync() \
+ __asm__ __volatile__ ("sync" ::: "memory");
+
+void
+Mips4k_ConfigCache(struct cpu_info *ci)
+{
+ uint32_t cfg;
+
+ cfg = cp0_get_config();
+
+ if (cfg & (1 << 5)) /* IB */
+ ci->ci_l1instcacheline = 32;
+ else
+ ci->ci_l1instcacheline = 16;
+ ci->ci_l1instcachesize = (1 << 12) << ((cfg >> 9) & 0x07); /* IC */
+
+ if (cfg & (1 << 4)) /* DB */
+ ci->ci_l1datacacheline = 32;
+ else
+ ci->ci_l1datacacheline = 16;
+ ci->ci_l1datacachesize = (1 << 12) << ((cfg >> 6) & 0x07); /* DC */
+
+ /* R4000 and R4400 L1 caches are direct */
+ ci->ci_cacheways = 1;
+ ci->ci_l1instcacheset = ci->ci_l1instcachesize;
+ ci->ci_l1datacacheset = ci->ci_l1datacachesize;
+
+ CpuCacheAliasMask = (ci->ci_l1instcachesize | ci->ci_l1datacachesize) &
+ ~PAGE_MASK;
+
+ if ((cfg & (1 << 17)) == 0) { /* SC */
+ /*
+ * We expect the setup code to have set up ci->ci_l2size for
+ * us. Unfortunately we aren't allowed to panic() there,
+ * because the console is not available.
+ */
+
+ /* fixed 32KB aliasing to avoid VCE */
+ CpuCacheAliasMask |= ((1 << 15) - 1) & ~PAGE_MASK;
+ } else {
+ ci->ci_cacheconfiguration = 0;
+ ci->ci_l2size = 0;
+ }
+ ci->ci_l3size = 0;
+
+ if (CpuCacheAliasMask != 0)
+ CpuCacheAliasMask |= PAGE_MASK;
+
+ if ((cfg & 7) != CCA_CACHED) {
+ void (*fn)(uint32_t);
+ vaddr_t va;
+ paddr_t pa;
+
+ va = (vaddr_t)&cp0_set_config;
+ if (IS_XKPHYS(va)) {
+ pa = XKPHYS_TO_PHYS(va);
+ va = PHYS_TO_XKPHYS(pa, CCA_NC);
+ } else {
+ pa = CKSEG0_TO_PHYS(va);
+ va = PHYS_TO_CKSEG1(pa);
+ }
+ fn = (void (*)(uint32_t))va;
+
+ cfg = (cfg & ~7) | CCA_CACHED;
+ (*fn)(cfg);
+ }
+}
+
+/*
+ * Writeback and invalidate all caches.
+ */
+void
+Mips4k_SyncCache(struct cpu_info *ci)
+{
+ vaddr_t sva, eva;
+ uint64_t line;
+
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ eva = sva + ci->ci_l1instcachesize;
+ line = ci->ci_l1instcacheline;
+ while (sva != eva) {
+ cache(IndexInvalidate_I, sva);
+ sva += line;
+ }
+
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ eva = sva + ci->ci_l1datacachesize;
+ line = ci->ci_l1datacacheline;
+ while (sva != eva) {
+ cache(IndexWBInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ eva = sva + ci->ci_l2size;
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ while (sva != eva) {
+ cache(IndexWBInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Invalidate I$ for the given range.
+ */
+void
+Mips4k_InvalidateICache(struct cpu_info *ci, uint64_t _va, size_t _sz)
+{
+ vaddr_t va, sva, eva;
+ vsize_t sz;
+ uint64_t line;
+
+ line = ci->ci_l1instcacheline;
+ /* extend the range to integral cache lines */
+ if (line == 16) {
+ va = _va & ~(16UL - 1);
+ sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - _va;
+ } else {
+ va = _va & ~(32UL - 1);
+ sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - _va;
+ }
+
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ /* keep only the index bits */
+ sva += va & ((1UL << 15) - 1);
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(IndexInvalidate_I, sva);
+ sva += line;
+ }
+
+ sync();
+}
+
+/*
+ * Writeback D$ for the given page.
+ */
+void
+Mips4k_SyncDCachePage(struct cpu_info *ci, uint64_t va)
+{
+ vaddr_t sva, eva;
+ uint64_t line;
+
+ line = ci->ci_l1datacacheline;
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ /* keep only the index bits */
+ sva += va & ((1UL << 15) - 1);
+ eva = sva + PAGE_SIZE;
+ while (sva != eva) {
+ cache(IndexWBInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ /* keep only the index bits */
+ sva += va & ((1UL << 22) - 1); /* largest L2 is 4MB */
+ eva = sva + PAGE_SIZE;
+ while (sva != eva) {
+ cache(IndexWBInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Writeback D$ for the given range. Range is expected to be currently
+ * mapped, allowing the use of `Hit' operations. This is less aggressive
+ * than using `Index' operations.
+ */
+void
+Mips4k_HitSyncDCache(struct cpu_info *ci, uint64_t _va, size_t _sz)
+{
+ vaddr_t va, sva, eva;
+ vsize_t sz;
+ uint64_t line;
+
+ line = ci->ci_l1datacacheline;
+ /* extend the range to integral cache lines */
+ if (line == 16) {
+ va = _va & ~(16UL - 1);
+ sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - va;
+ } else {
+ va = _va & ~(32UL - 1);
+ sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - va;
+ }
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitWBInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ /* extend the range to integral cache lines */
+ va = _va & ~(line - 1);
+ sz = ((_va + _sz + line - 1) & ~(line - 1)) - va;
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitWBInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Invalidate D$ for the given range. Range is expected to be currently
+ * mapped, allowing the use of `Hit' operations. This is less aggressive
+ * than using `Index' operations.
+ */
+void
+Mips4k_HitInvalidateDCache(struct cpu_info *ci, uint64_t _va, size_t _sz)
+{
+ vaddr_t va, sva, eva;
+ vsize_t sz;
+ uint64_t line;
+
+ line = ci->ci_l1datacacheline;
+ /* extend the range to integral cache lines */
+ if (line == 16) {
+ va = _va & ~(16UL - 1);
+ sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - _va;
+ } else {
+ va = _va & ~(32UL - 1);
+ sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - _va;
+ }
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ /* extend the range to integral cache lines */
+ va = _va & ~(line - 1);
+ sz = ((_va + _sz + line - 1) & ~(line - 1)) - va;
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Backend for bus_dmamap_sync(). Enforce coherency of the given range
+ * by performing the necessary cache writeback and/or invalidate
+ * operations.
+ */
+void
+Mips4k_IOSyncDCache(struct cpu_info *ci, uint64_t va, size_t sz, int how)
+{
+ switch (how) {
+ case CACHE_SYNC_R:
+ if (((va | sz) & (ci->ci_l1datacacheline - 1)) == 0) {
+ Mips4k_HitInvalidateDCache(ci, va, sz);
+ break;
+ }
+ /* FALLTHROUGH */
+ case CACHE_SYNC_X:
+ Mips4k_HitSyncDCache(ci, va, sz);
+ break;
+ case CACHE_SYNC_W:
+ Mips4k_HitSyncDCache(ci, va, sz);
+ break;
+ }
+}
diff --git a/sys/arch/mips64/mips64/cp0access.S b/sys/arch/mips64/mips64/cp0access.S
index 32866dce285..7bb04346f0c 100644
--- a/sys/arch/mips64/mips64/cp0access.S
+++ b/sys/arch/mips64/mips64/cp0access.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: cp0access.S,v 1.14 2010/09/11 11:29:50 syuu Exp $ */
+/* $OpenBSD: cp0access.S,v 1.15 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -154,6 +154,13 @@ LEAF(cp0_get_config, 0)
nop
END(cp0_get_config)
+/* WARNING! Needs to be invoked from uncached address. */
+LEAF(cp0_set_config, 0)
+ mtc0 a0, COP_0_CONFIG
+ j ra
+ nop
+END(cp0_set_config)
+
LEAF(cp0_get_prid, 0)
mfc0 v0, COP_0_PRID
j ra
diff --git a/sys/arch/mips64/mips64/cpu.c b/sys/arch/mips64/mips64/cpu.c
index 37240e67095..2a85adba26e 100644
--- a/sys/arch/mips64/mips64/cpu.c
+++ b/sys/arch/mips64/mips64/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.39 2011/04/10 17:16:51 miod Exp $ */
+/* $OpenBSD: cpu.c,v 1.40 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1997-2004 Opsycon AB (www.opsycon.se)
@@ -112,14 +112,18 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf(": ");
displayver = 1;
+ fptype = (ch->c1prid >> 8) & 0xff;
vers_maj = (ch->c0prid >> 4) & 0x0f;
vers_min = ch->c0prid & 0x0f;
switch (ch->type) {
case MIPS_R4000:
- if (ci->ci_l1instcachesize == 16384)
- printf("MIPS R4400 CPU");
- else
+ if (vers_maj < 4)
printf("MIPS R4000 CPU");
+ else {
+ vers_maj -= 3;
+ printf("MIPS R4400 CPU");
+ }
+ fptype = MIPS_R4000;
break;
case MIPS_R5000:
printf("MIPS R5000 CPU");
@@ -184,6 +188,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
break;
case MIPS_OCTEON:
printf("Cavium OCTEON CPU");
+ fptype = MIPS_SOFT;
break;
default:
printf("Unknown CPU type (0x%x)", ch->type);
@@ -194,13 +199,8 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf(" %d MHz, ", ch->clock / 1000000);
displayver = 1;
- if (ch->type == MIPS_OCTEON)
- fptype = MIPS_SOFT;
- else {
- fptype = (ch->c1prid >> 8) & 0xff;
- vers_maj = (ch->c1prid >> 4) & 0x0f;
- vers_min = ch->c1prid & 0x0f;
- }
+ vers_maj = (ch->c1prid >> 4) & 0x0f;
+ vers_min = ch->c1prid & 0x0f;
switch (fptype) {
case MIPS_SOFT:
printf("Software FP emulation");
@@ -267,7 +267,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf("4 way");
break;
default:
- printf("1 way");
+ printf("direct");
break;
}
@@ -293,8 +293,10 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf("\n");
#ifdef DEBUG
- printf("cpu%d: Setsize %d:%d\n", cpuno,
+ printf("cpu%d: L1 set size %d:%d\n", cpuno,
ci->ci_l1instcacheset, ci->ci_l1datacacheset);
+ printf("cpu%d: L1 line size %d:%d\n", cpuno,
+ ci->ci_l1instcacheline, ci->ci_l1datacacheline);
printf("cpu%d: Alias mask %p\n", cpuno, CpuCacheAliasMask);
printf("cpu%d: Config Register %08x\n", cpuno, cp0_get_config());
printf("cpu%d: Cache configuration %x\n",
diff --git a/sys/arch/mips64/mips64/exception.S b/sys/arch/mips64/mips64/exception.S
index a02a560136b..2626cf95a77 100644
--- a/sys/arch/mips64/mips64/exception.S
+++ b/sys/arch/mips64/mips64/exception.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: exception.S,v 1.32 2010/12/28 18:40:28 miod Exp $ */
+/* $OpenBSD: exception.S,v 1.33 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -129,6 +129,11 @@ u_exception_table:
* to the vector area and must thus be PIC and less than 128
* bytes long to fit. Only k0 and k1 may be used at this time.
*/
+ .globl cache_err
+cache_err:
+#ifdef CPU_R4000
+ nop
+#endif
.globl exception
exception:
.set noat
diff --git a/sys/arch/mips64/mips64/lcore_access.S b/sys/arch/mips64/mips64/lcore_access.S
index 4975d28094e..c48b44ef6fa 100644
--- a/sys/arch/mips64/mips64/lcore_access.S
+++ b/sys/arch/mips64/mips64/lcore_access.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: lcore_access.S,v 1.19 2010/01/31 19:39:04 miod Exp $ */
+/* $OpenBSD: lcore_access.S,v 1.20 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -286,10 +286,42 @@ _kcopyerr:
/*
* Guarded ``memory'' access routines
+ * int guarded_read_1(paddr_t address, uint8_t *dest);
+ * int guarded_read_2(paddr_t address, uint16_t *dest);
* int guarded_read_4(paddr_t address, uint32_t *dest);
* int guarded_write_4(paddr_t address, uint32_t src);
*/
+LEAF(guarded_read_1, 0)
+ GET_CPU_INFO(t1, t0)
+ PTR_L t3, CI_CURPROCPADDR(t1)
+ li v0, KT_GUARDERR
+ lw v1, PCB_ONFAULT(t3)
+ sw v0, PCB_ONFAULT(t3)
+
+ lb v0, 0(a0)
+ sb v0, 0(a1)
+
+ sw v1, PCB_ONFAULT(t3)
+ j ra
+ move v0, zero
+END(guarded_read_1)
+
+LEAF(guarded_read_2, 0)
+ GET_CPU_INFO(t1, t0)
+ PTR_L t3, CI_CURPROCPADDR(t1)
+ li v0, KT_GUARDERR
+ lw v1, PCB_ONFAULT(t3)
+ sw v0, PCB_ONFAULT(t3)
+
+ lh v0, 0(a0)
+ sh v0, 0(a1)
+
+ sw v1, PCB_ONFAULT(t3)
+ j ra
+ move v0, zero
+END(guarded_read_2)
+
LEAF(guarded_read_4, 0)
GET_CPU_INFO(t1, t0)
PTR_L t3, CI_CURPROCPADDR(t1)
diff --git a/sys/arch/mips64/mips64/tlbhandler.S b/sys/arch/mips64/mips64/tlbhandler.S
index d96e343d765..d78fe8cebc6 100644
--- a/sys/arch/mips64/mips64/tlbhandler.S
+++ b/sys/arch/mips64/mips64/tlbhandler.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: tlbhandler.S,v 1.32 2010/09/12 12:05:37 syuu Exp $ */
+/* $OpenBSD: tlbhandler.S,v 1.33 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1995-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -54,6 +54,22 @@
*/
.set noat
+#ifdef CPU_R4000
+ .globl xtlb_miss_err_r4k
+ .ent xtlb_miss_err_r4k, 0
+xtlb_miss_err_r4k:
+ /*
+ * R4000 errata: TLB miss exception may be invoked with BadVAddr
+ * being incorrect.
+ */
+ tlbp
+ mfc0 k1, COP_0_TLB_INDEX
+ bltz k1, xtlb_miss # missing!
+ nop
+ eret
+ nop
+ .end xtlb_miss_err_r4k
+#endif /* CPU_R4000 */
#if defined(CPU_R5000) || defined(CPU_RM7000)
.globl xtlb_miss_err_r5k
.ent xtlb_miss_err_r5k, 0
diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c
index d906010b49a..73aa524bcf7 100644
--- a/sys/arch/mips64/mips64/trap.c
+++ b/sys/arch/mips64/mips64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.77 2011/11/16 20:50:19 deraadt Exp $ */
+/* $OpenBSD: trap.c,v 1.78 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@@ -763,6 +763,36 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr
}
goto err;
+#ifdef CPU_R4000
+ case T_VCEI:
+ case T_VCEI+T_USER:
+ {
+ vaddr_t va = trapframe->badvaddr &
+ ~((vaddr_t)ci->ci_l1instcacheline - 1);
+#ifdef DEBUG
+ printf("VCEI trap, badvaddr %p\n", trapframe->badvaddr);
+#endif
+ /* HitWBInvalidate_S */
+ __asm__ __volatile__ ("cache 0x17, 0(%0)" :: "r"(va));
+ /* HitInvalidate_I */
+ __asm__ __volatile__ ("cache 0x10, 0(%0)" :: "r"(va));
+ }
+ return;
+ case T_VCED:
+ case T_VCED+T_USER:
+ {
+ vaddr_t va = trapframe->badvaddr &
+ ~((vaddr_t)ci->ci_l1datacacheline - 1);
+#ifdef DEBUG
+ printf("VCED trap, badvaddr %p\n", trapframe->badvaddr);
+#endif
+ /* HitWBInvalidate_S */
+ __asm__ __volatile__ ("cache 0x17, 0(%0)" :: "r"(va));
+ /* HitInvalidate_D */
+ __asm__ __volatile__ ("cache 0x11, 0(%0)" :: "r"(va));
+ }
+ return;
+#endif /* CPU_R4000 */
default:
err:
disableintr();
diff --git a/sys/arch/sgi/compile/.cvsignore b/sys/arch/sgi/compile/.cvsignore
index 8a0ebe82e75..db6b8d0fedd 100644
--- a/sys/arch/sgi/compile/.cvsignore
+++ b/sys/arch/sgi/compile/.cvsignore
@@ -1,7 +1,10 @@
+GENERIC-IP22
GENERIC-IP27
+GENERIC-IP27.MP
GENERIC-IP30
GENERIC-IP30.MP
GENERIC-IP32
+RAMDISK-IP22
RAMDISK-IP27
RAMDISK-IP30
RAMDISK-IP32
diff --git a/sys/arch/sgi/conf/GENERIC-IP22 b/sys/arch/sgi/conf/GENERIC-IP22
new file mode 100644
index 00000000000..c062b6c4cb4
--- /dev/null
+++ b/sys/arch/sgi/conf/GENERIC-IP22
@@ -0,0 +1,85 @@
+# $OpenBSD: GENERIC-IP22,v 1.1 2012/03/28 20:44:23 miod Exp $
+#
+# THIS KERNEL IS FOR INDIGO (IP20), INDY (IP22) AND INDIGO2 (IP24) SYSTEMS ONLY.
+#
+# For further information on compiling OpenBSD kernels, see the config(8)
+# man page.
+#
+# For further information on hardware support for this architecture, see
+# the intro(4) man page. For further information about kernel options
+# for this architecture, see the options(4) man page. For an explanation
+# of each device driver in this file see the section 4 man page for the
+# device.
+
+machine sgi mips64
+include "../../../conf/GENERIC"
+maxusers 32 # Estimated number of users
+
+# Make options
+makeoption LINK_ADDRESS="0xffffffff88100000"
+# Force use of 16KB pages. The R5000 Indy, which has the infamous XKPHYS
+# coherency bug wrt ll/sc instructions, can not have more than 256MB of
+# physical memory, all of it fitting within CKSEG0.
+option PAGE_SHIFT="14"
+
+#option WSDISPLAY_COMPAT_RAWKBD # Provide raw scancodes; needed for X11
+
+# Define what targets to support
+option TGT_INDIGO # R4x00 Indigo (IP20)
+option TGT_INDIGO2 # Indigo2 (IP22/IP26/IP28)
+option TGT_INDY # Indy (IP24)
+option ARCBIOS # mandatory
+option CPU_R4000 # R4000/R4400 support (IP20/IP22/IP24)
+#option CPU_R4600 # R4600 support (IP22/IP24)
+option CPU_R5000 # R5000 support (IP24)
+
+config bsd swap generic
+
+#
+# Definition of system
+#
+mainbus0 at root
+cpu* at mainbus0
+clock0 at mainbus0
+
+int0 at mainbus0 # Interrupt Controller
+imc0 at mainbus0 # Memory Controller
+gio0 at imc0
+#eisa0 at imc0
+
+hpc0 at gio? addr 0x1fb80000
+hpc1 at gio? addr 0x1fb00000
+hpc2 at gio? addr 0x1f980000
+
+dpclock0 at hpc0 # IP20
+dsclock0 at hpc0 # IP22/24
+sq* at hpc? # On-board Ethernet or E++ adapter
+wdsc* at hpc? # On-board SCSI or GIO32 SCSI adapter
+#haltwo* at hpc? # Indy/Indigo2 Audio
+#panel* at hpc? # Indy front panel buttons
+#pckbc* at hpc? # Indy/Indigo2 keyboard and mouse
+
+zs* at hpc?
+zstty* at zs? # Serial ports
+
+#newport* at gio? # Indy Newport graphics
+#wsdisplay* at newport?
+
+#grtwo* at gio? # Express (GR2) graphics
+#wsdisplay* at grtwo?
+
+#light* at gio? # Light/Starter/Entry (LG1/LG2) graphics
+#wsdisplay* at light?
+
+scsibus* at scsi?
+sd* at scsibus?
+st* at scsibus?
+cd* at scsibus?
+ch* at scsibus?
+safte* at scsibus?
+ses* at scsibus?
+uk* at scsibus?
+
+pseudo-device crypto 1
+#pseudo-device hotplug 1 # devices hot plugging
+#pseudo-device wsmux 2 # Mouse and keyboard multiplexor
diff --git a/sys/arch/sgi/conf/RAMDISK-IP22 b/sys/arch/sgi/conf/RAMDISK-IP22
new file mode 100644
index 00000000000..91e2e00f390
--- /dev/null
+++ b/sys/arch/sgi/conf/RAMDISK-IP22
@@ -0,0 +1,95 @@
+# $OpenBSD: RAMDISK-IP22,v 1.1 2012/03/28 20:44:23 miod Exp $
+#
+# THIS KERNEL IS FOR INDIGO (IP20), INDY (IP22) AND INDIGO2 (IP24) SYSTEMS ONLY.
+
+machine sgi mips64
+
+maxusers 4
+option TIMEZONE=0 # minutes west of GMT (for)
+option DST=0 # use daylight savings rules
+
+# Make options
+makeoption LINK_ADDRESS="0xffffffff88100000"
+# Force use of 16KB pages. The R5000 Indy, which has the infamous XKPHYS
+# coherency bug wrt ll/sc instructions, can not have more than 256MB of
+# physical memory, all of it fitting within CKSEG0.
+option PAGE_SHIFT="14"
+
+option DDB
+
+# Filesystem options
+option CD9660 # ISO 9660 + Rock Ridge file system
+option FIFO # POSIX fifo support (in all filesystems)
+option FFS # fast filesystem
+#option MSDOSFS # Ability to read write MS-Dos filesystem
+option NFSCLIENT # Sun NFS-compatible filesystem (client)
+
+# Networking options
+option INET # IP + ICMP + TCP + UDP
+option INET6 # IPv6 (needs INET)
+
+# RAMDISK stuff
+option MINIROOTSIZE=10240
+option RAMDISK_HOOKS
+
+# Define what targets to support
+option TGT_INDIGO # R4x00 Indigo (IP20)
+option TGT_INDIGO2 # Indigo2 (IP22/IP26/IP28)
+option TGT_INDY # Indy (IP24)
+option ARCBIOS # mandatory
+option CPU_R4000 # R4000/R4400 support (IP20/IP22/IP24)
+#option CPU_R4600 # R4600 support (IP22/IP24)
+option CPU_R5000 # R5000 support (IP24)
+
+# Specify storage configuration using ramdisk
+config bsd root on rd0a swap on rd0b
+
+#
+# Definition of system
+#
+mainbus0 at root
+cpu* at mainbus0
+clock0 at mainbus0
+
+int0 at mainbus0 # Interrupt Controller
+imc0 at mainbus0 # Memory Controller
+gio0 at imc0
+#eisa0 at imc0
+
+hpc0 at gio? addr 0x1fb80000
+hpc1 at gio? addr 0x1fb00000
+hpc2 at gio? addr 0x1f980000
+
+dpclock0 at hpc0 # IP20
+dsclock0 at hpc0 # IP22/24
+sq* at hpc? # On-board Ethernet or E++ adapter
+wdsc* at hpc? # On-board SCSI or GIO32 SCSI adapter
+#pckbc* at hpc? # Indy/Indigo2 keyboard and mouse
+
+zs* at hpc?
+zstty* at zs? # Serial ports
+
+#newport* at gio? # Indy Newport graphics
+#wsdisplay* at newport?
+
+#grtwo* at gio? # Express (GR2) graphics
+#wsdisplay* at grtwo?
+
+#light* at gio? # Light/Starter/Entry (LG1/LG2) graphics
+#wsdisplay* at light?
+
+scsibus* at scsi?
+sd* at scsibus?
+st* at scsibus?
+cd* at scsibus?
+#ch* at scsibus?
+#uk* at scsibus?
+
+#### PSEUDO Devices
+pseudo-device loop 1 # network loopback
+pseudo-device bpfilter 1 # packet filter ports
+
+pseudo-device rd 1 # Ram disk.
+pseudo-device bio 1 # ioctl multiplexing device
+
+option BOOT_CONFIG # add support for boot -c
diff --git a/sys/arch/sgi/conf/files.sgi b/sys/arch/sgi/conf/files.sgi
index 83953010ed9..a13ff36f3c7 100644
--- a/sys/arch/sgi/conf/files.sgi
+++ b/sys/arch/sgi/conf/files.sgi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sgi,v 1.46 2011/11/15 22:27:53 deraadt Exp $
+# $OpenBSD: files.sgi,v 1.47 2012/03/28 20:44:23 miod Exp $
#
# maxpartitions must be first item in files.${ARCH}
#
@@ -14,6 +14,8 @@ file arch/sgi/sgi/bus_dma.c
file arch/sgi/sgi/conf.c
file arch/sgi/sgi/disksubr.c disk
file arch/sgi/sgi/lock_machdep.c multiprocessor
+file arch/sgi/sgi/ip22_machdep.c tgt_indigo | tgt_indigo2 |
+ tgt_indy
file arch/sgi/sgi/ip27_machdep.c tgt_origin
file arch/sgi/sgi/ip30_machdep.c tgt_octane
file arch/sgi/sgi/ip30_nmi.S tgt_octane & ddb
@@ -56,6 +58,21 @@ device clock
attach clock at mainbus
#
+# IP20/22/24 specific devices
+#
+define giobus {}
+device imc: giobus, eisabus
+attach imc at mainbus
+file arch/sgi/localbus/imc.c imc
+
+device int
+attach int at mainbus
+file arch/sgi/localbus/int.c int
+
+include "arch/sgi/gio/files.gio"
+include "arch/sgi/hpc/files.hpc"
+
+#
# O2 MACE localbus autoconfiguration devices
#
define macebus {[base = -1]}
@@ -87,6 +104,13 @@ major {cd = 3}
include "dev/i2o/files.i2o"
#
+# EISA Bus support
+#
+
+include "dev/eisa/files.eisa"
+file arch/sgi/sgi/eisa_machdep.c eisa
+
+#
# PCI Bus support
#
@@ -132,9 +156,9 @@ file arch/sgi/dev/iockbc.c iockbc |
# DS1687 Time-Of-Day calendar device
device dsrtc
-attach dsrtc at macebus with dsrtc_macebus
attach dsrtc at ioc with dsrtc_ioc
attach dsrtc at iof with dsrtc_iof
+attach dsrtc at macebus with dsrtc_macebus
file arch/sgi/dev/dsrtc.c dsrtc
# GBE framebuffer
@@ -207,4 +231,3 @@ file arch/sgi/dev/owmem_subr.c owmac | owserial
# IP35 SPD memory information
attach spdmem at mainbus with spdmem_mainbus
file arch/sgi/dev/spdmem_mainbus.c spdmem_mainbus
-
diff --git a/sys/arch/sgi/dev/dsrtc.c b/sys/arch/sgi/dev/dsrtc.c
index 7132df8e5fd..8991abfe0bf 100644
--- a/sys/arch/sgi/dev/dsrtc.c
+++ b/sys/arch/sgi/dev/dsrtc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsrtc.c,v 1.11 2009/11/07 14:49:01 miod Exp $ */
+/* $OpenBSD: dsrtc.c,v 1.12 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -122,7 +122,7 @@ dsrtc_attach_ioc(struct device *parent, struct device *self, void *aux)
bus_space_handle_t ih, ih2;
/*
- * The IOC3 RTC is either a Dallas (now Maxim) DS1386 or compatible
+ * The IOC3 RTC is either a Dallas (now Maxim) DS1397 or compatible
* (likely a more recent DS1687), or a DS1747 or compatible
* (itself being a Mostek MK48T35 clone).
*
diff --git a/sys/arch/sgi/gio/Makefile b/sys/arch/sgi/gio/Makefile
new file mode 100644
index 00000000000..130e520dcfb
--- /dev/null
+++ b/sys/arch/sgi/gio/Makefile
@@ -0,0 +1,8 @@
+# $OpenBSD: Makefile,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: Makefile.giodevs,v 1.5 2008/10/19 22:05:21 apb Exp $
+
+AWK= awk
+
+giodevs.h giodevs_data.h: giodevs devlist2h.awk
+ /bin/rm -f giodevs.h giodevs_data.h
+ ${AWK} -f devlist2h.awk giodevs
diff --git a/sys/arch/sgi/gio/devlist2h.awk b/sys/arch/sgi/gio/devlist2h.awk
new file mode 100644
index 00000000000..361a2eb2a25
--- /dev/null
+++ b/sys/arch/sgi/gio/devlist2h.awk
@@ -0,0 +1,152 @@
+#! /usr/bin/awk -f
+# $OpenBSD: devlist2h.awk,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: devlist2h.awk,v 1.5 2008/05/02 18:11:05 martin Exp $
+#
+# Copyright (c) 1998 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Christos Zoulas.
+#
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Copyright (c) 1995, 1996 Christopher G. Demetriou
+# 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 Christopher G. Demetriou.
+# This product includes software developed by Christos Zoulas
+# 4. The name of the author(s) 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.
+#
+function collectline(_f, _line) {
+ _oparen = 0
+ _line = ""
+ while (_f <= NF) {
+ if ($_f == "#") {
+ _line = _line "("
+ _oparen = 1
+ _f++
+ continue
+ }
+ if (_oparen) {
+ _line = _line $_f
+ if (_f < NF)
+ _line = _line " "
+ _f++
+ continue
+ }
+ _line = _line $_f
+ if (_f < NF)
+ _line = _line " "
+ _f++
+ }
+ if (_oparen)
+ _line = _line ")"
+ return _line
+}
+BEGIN {
+ nproducts = nvendors = blanklines = 0
+ dfile="giodevs_data.h"
+ hfile="giodevs.h"
+ line=""
+}
+NR == 1 {
+ VERSION = $0
+ gsub("\\$", "", VERSION)
+
+ printf("/*\n") > hfile
+ printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \
+ > hfile
+ printf(" *\n") > hfile
+ printf(" * generated from:\n") > hfile
+ printf(" *\t%s\n", VERSION) > hfile
+ printf(" */\n\n") > hfile
+
+ printf("/*\n") > dfile
+ printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \
+ > dfile
+ printf(" *\n") > dfile
+ printf(" * generated from:\n") > dfile
+ printf(" *\t%s\n", VERSION) > dfile
+ printf(" */\n\n") > dfile
+
+ next
+}
+NF > 0 && $1 == "product" {
+ nproducts++
+
+ products[nproducts, 1] = $2;
+ products[nproducts, 2] = $3
+ products[nproducts, 3] = collectline(4, line)
+
+ next
+}
+{
+ if ($0 == "")
+ blanklines++
+ if (blanklines < 2)
+ print $0 > dfile
+}
+END {
+ # print out the match tables
+
+ printf("\n") > dfile
+
+ printf("struct gio_knowndev {\n") > dfile
+ printf("\tint productid;\n") > dfile
+ printf("\tconst char *product;\n") > dfile
+ printf("};\n") > dfile
+ printf("\nstruct gio_knowndev gio_knowndevs[] = {\n") > dfile
+
+ printf("\n") > hfile
+ for (i = 1; i <= nproducts; i++) {
+ printf("#define %s\t%s\t/* %s */\n", products[i, 1], products[i,2], products[i, 3]) > hfile
+
+ printf("\t{ %s, \"%s\" },\n",
+ products[i, 2], products[i, 3]) > dfile
+ }
+ printf("\t{ 0, NULL }\n") > dfile
+ printf("};\n") > dfile
+ close(dfile)
+ close(hfile)
+}
diff --git a/sys/arch/sgi/gio/files.gio b/sys/arch/sgi/gio/files.gio
new file mode 100644
index 00000000000..fe393862625
--- /dev/null
+++ b/sys/arch/sgi/gio/files.gio
@@ -0,0 +1,31 @@
+# $OpenBSD: files.gio,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: files.gio,v 1.11 2009/02/12 06:33:57 rumble Exp $
+
+device gio {[slot = -1], [addr = -1]}
+attach gio at giobus
+
+file arch/sgi/gio/gio.c gio needs-flag
+
+device hpc {[offset = -1]}: smc93cx6
+attach hpc at gio
+file arch/sgi/hpc/hpc.c hpc
+
+# XL graphics
+device newport: wsemuldisplaydev, rasops8
+attach newport at gio
+file arch/sgi/gio/newport.c newport needs-flag
+
+# GR2 graphics
+device grtwo: wsemuldisplaydev
+attach grtwo at gio
+file arch/sgi/gio/grtwo.c grtwo needs-flag
+
+# LG1/LG2 graphics
+device light: wsemuldisplaydev
+attach light at gio
+file arch/sgi/gio/light.c light needs-flag
+
+# PCI cards glued to the GIO bus
+device giopci: pcibus
+attach giopci at gio
+file arch/sgi/gio/pci_gio.c giopci
diff --git a/sys/arch/sgi/gio/gio.c b/sys/arch/sgi/gio/gio.c
new file mode 100644
index 00000000000..b201adab5b9
--- /dev/null
+++ b/sys/arch/sgi/gio/gio.c
@@ -0,0 +1,518 @@
+/* $OpenBSD: gio.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: gio.c,v 1.32 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2000 Soren S. Jorvang
+ * 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 for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+#include <sgi/gio/gioreg.h>
+#include <sgi/gio/giovar.h>
+#include <sgi/gio/giodevs_data.h>
+
+#include <sgi/localbus/imcvar.h>
+#include <sgi/localbus/intvar.h>
+#include <sgi/sgi/ip22.h>
+
+int gio_match(struct device *, void *, void *);
+void gio_attach(struct device *, struct device *, void *);
+int gio_print(void *, const char *);
+int gio_print_fb(void *, const char *);
+int gio_search(struct device *, void *, void *);
+int gio_submatch(struct device *, void *, void *);
+uint32_t gio_id(paddr_t, int);
+
+struct gio_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_dma_tag_t sc_dmat;
+};
+
+const struct cfattach gio_ca = {
+ sizeof(struct gio_softc), gio_match, gio_attach
+};
+
+struct cfdriver gio_cd = {
+ NULL, "gio", DV_DULL
+};
+
+struct gio_probe {
+ uint32_t slot;
+ uint64_t base;
+ uint32_t mach_type;
+ uint32_t mach_subtype;
+};
+
+/*
+ * Expansion Slot Base Addresses
+ *
+ * IP12, IP20 and IP24 have two GIO connectors: GIO_SLOT_EXP0 and
+ * GIO_SLOT_EXP1.
+ *
+ * On IP24 these slots exist on the graphics board or the IOPLUS
+ * "mezzanine" on Indy and Challenge S, respectively. The IOPLUS or
+ * graphics board connects to the mainboard via a single GIO64 connector.
+ *
+ * IP22 has either three or four physical connectors, but only two
+ * electrically distinct slots: GIO_SLOT_GFX and GIO_SLOT_EXP0.
+ *
+ * It should also be noted that DMA is (mostly) not supported in Challenge S's
+ * GIO_SLOT_EXP1. See gio(4) for the story.
+ */
+static const struct gio_probe slot_bases[] = {
+ { GIO_SLOT_GFX, 0x1f000000, SGI_IP22, IP22_INDIGO2 },
+
+ { GIO_SLOT_EXP0, 0x1f400000, SGI_IP20, -1 },
+ { GIO_SLOT_EXP0, 0x1f400000, SGI_IP22, -1 },
+
+ { GIO_SLOT_EXP1, 0x1f600000, SGI_IP20, -1 },
+ { GIO_SLOT_EXP1, 0x1f600000, SGI_IP22, IP22_INDY },
+
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * Graphic Board Base Addresses
+ *
+ * Graphics boards are not treated like expansion slot cards. Their base
+ * addresses do not necessarily correspond to GIO slot addresses and they
+ * do not contain product identification words.
+ */
+static const struct gio_probe gfx_bases[] = {
+ /* grtwo, and newport on IP22 */
+ { -1, 0x1f000000, SGI_IP20, -1 },
+ { -1, 0x1f000000, SGI_IP22, -1 },
+
+ /* light */
+ { -1, 0x1f3f0000, SGI_IP20, -1 },
+
+ /* light (dual headed) */
+ { -1, 0x1f3f8000, SGI_IP20, -1 },
+
+ /* grtwo, and newport on IP22 */
+ { -1, 0x1f400000, SGI_IP20, -1 },
+ { -1, 0x1f400000, SGI_IP22, -1 },
+
+ /* grtwo */
+ { -1, 0x1f600000, SGI_IP20, -1 },
+ { -1, 0x1f600000, SGI_IP22, -1 },
+
+ /* newport */
+ { -1, 0x1f800000, SGI_IP22, IP22_INDIGO2 },
+
+ /* newport */
+ { -1, 0x1fc00000, SGI_IP22, IP22_INDIGO2 },
+
+ { 0, 0, 0, 0 }
+};
+
+/* maximum number of graphics boards possible (arbitrarily large estimate) */
+#define MAXGFX (nitems(gfx_bases) - 1)
+
+int
+gio_match(struct device *parent, void *match, void *aux)
+{
+ struct imc_attach_args *iaa = aux;
+
+ if (strcmp(iaa->iaa_name, gio_cd.cd_name) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+gio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gio_softc *sc = (struct gio_softc *)self;
+ struct imc_attach_args *iaa = (struct imc_attach_args *)aux;
+ struct gio_attach_args ga;
+ uint32_t gfx[MAXGFX];
+ uint i, j, ngfx;
+
+ printf("\n");
+
+ sc->sc_iot = iaa->iaa_st;
+ sc->sc_dmat = iaa->iaa_dmat;
+
+ ngfx = 0;
+ memset(gfx, 0, sizeof(gfx));
+
+ /*
+ * Try and attach graphics devices first.
+ * Unfortunately, they - not being GIO devices after all - do not
+ * contain a Product Identification Word, nor have a slot number.
+ *
+ * Record addresses to which graphics devices attach so that
+ * we do not confuse them with expansion slots, should the
+ * addresses coincide.
+ *
+ * Unfortunately graphics devices for which we have no configured
+ * driver, which address matches a regular slot number, will show
+ * up as rogue devices attached to real slots.
+ *
+ * If only the ARCBios component tree would be so kind as to give
+ * us the address of the frame buffer components...
+ */
+ for (i = 0; gfx_bases[i].base != 0; i++) {
+ /* skip slots that don't apply to us */
+ if (gfx_bases[i].mach_type != sys_config.system_type)
+ continue;
+
+ if (gfx_bases[i].mach_subtype != -1 &&
+ gfx_bases[i].mach_subtype != sys_config.system_subtype)
+ continue;
+
+ ga.ga_slot = -1;
+ ga.ga_addr = gfx_bases[i].base;
+ ga.ga_iot = sc->sc_iot;
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = sc->sc_dmat;
+ ga.ga_product = -1;
+
+ if (gio_id(ga.ga_ioh, 1) == 0)
+ continue;
+
+ if (config_found_sm(self, &ga, gio_print_fb, gio_submatch)) {
+ gfx[ngfx++] = gfx_bases[i].base;
+ }
+ }
+
+ /*
+ * Now attach any GIO expansion cards.
+ *
+ * Be sure to skip any addresses to which a graphics device has
+ * already been attached.
+ */
+ for (i = 0; slot_bases[i].base != 0; i++) {
+ int skip = 0;
+
+ /* skip slots that don't apply to us */
+ if (slot_bases[i].mach_type != sys_config.system_type)
+ continue;
+
+ if (slot_bases[i].mach_subtype != -1 &&
+ slot_bases[i].mach_subtype != sys_config.system_subtype)
+ continue;
+
+ for (j = 0; j < ngfx; j++) {
+ if (slot_bases[i].base == gfx[j]) {
+ skip = 1;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+
+ ga.ga_slot = slot_bases[i].slot;
+ ga.ga_addr = slot_bases[i].base;
+ ga.ga_iot = sc->sc_iot;
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = sc->sc_dmat;
+
+ if (gio_id(ga.ga_ioh, 0) == 0)
+ continue;
+
+ ga.ga_product = bus_space_read_4(ga.ga_iot, ga.ga_ioh, 0);
+
+ config_found_sm(self, &ga, gio_print, gio_submatch);
+ }
+
+ config_search(gio_search, self, aux);
+}
+
+/*
+ * Try and figure out whether there is a device at the given slot address.
+ */
+uint32_t
+gio_id(paddr_t pa, int maybe_gfx)
+{
+ uint32_t id32;
+ uint16_t id16 = 0;
+ uint8_t id8 = 0;
+
+ if (guarded_read_4(pa, &id32) != 0)
+ return 0;
+
+ id16 = id32 ^ 0xffff;
+ (void)guarded_read_2(pa | 2, &id16);
+ id8 = id16 ^ 0xff;
+ (void)guarded_read_1(pa | 3, &id8);
+
+ /*
+ * If there is a real GIO device at this address (as opposed to
+ * a graphics card), then the low-order 8 bits of each read need
+ * to be consistent...
+ */
+ if (id8 == (id16 & 0xff) && id8 == (id32 & 0xff)) {
+ if (GIO_PRODUCT_32BIT_ID(id8)) {
+ if (id16 == (id32 & 0xffff))
+ return id32;
+ } else {
+ if (id8 != 0)
+ return id32;
+ }
+ }
+
+ if (maybe_gfx)
+ return 1;
+
+ return 0;
+}
+
+int
+gio_print(void *aux, const char *pnp)
+{
+ struct gio_attach_args *ga = aux;
+ const char *descr;
+ int product, revision;
+ uint i;
+
+ product = GIO_PRODUCT_PRODUCTID(ga->ga_product);
+ if (GIO_PRODUCT_32BIT_ID(ga->ga_product))
+ revision = GIO_PRODUCT_REVISION(ga->ga_product);
+ else
+ revision = 0;
+
+ descr = "unknown GIO card";
+ for (i = 0; gio_knowndevs[i].productid != 0; i++) {
+ if (gio_knowndevs[i].productid == product) {
+ descr = gio_knowndevs[i].product;
+ break;
+ }
+ }
+
+ if (pnp != NULL) {
+ printf("%s", descr);
+ if (ga->ga_product != -1)
+ printf(" (product 0x%02x revision 0x%02x)",
+ product, revision);
+ printf(" at %s", pnp);
+ }
+
+ if (ga->ga_slot != -1)
+ printf(" slot %d", ga->ga_slot);
+ printf(" addr 0x%lx", ga->ga_addr);
+
+ return UNCONF;
+}
+
+int
+gio_print_fb(void *aux, const char *pnp)
+{
+#if 0 /* once we can know for sure there really is a frame buffer here */
+ if (pnp != NULL)
+ printf("framebuffer at %s", pnp);
+
+ if (ga->ga_addr != (uint64_t)-1)
+ printf(" addr 0x%lx", ga->ga_addr);
+
+ return UNCONF;
+#else
+ return QUIET;
+#endif
+}
+
+int
+gio_search(struct device *parent, void *vcf, void *aux)
+{
+ struct gio_softc *sc = (struct gio_softc *)parent;
+ struct cfdata *cf = (struct cfdata *)vcf;
+ struct gio_attach_args ga;
+
+ /* Handled by direct configuration, so skip here */
+ if (cf->cf_loc[1 /*GIOCF_ADDR*/] == -1)
+ return 0;
+
+ ga.ga_product = -1;
+ ga.ga_slot = cf->cf_loc[0 /*GIOCF_SLOT*/];
+ ga.ga_addr = (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/];
+ ga.ga_iot = sc->sc_iot;
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = sc->sc_dmat;
+
+ if ((*cf->cf_attach->ca_match)(parent, cf, &ga) == 0)
+ return 0;
+
+ config_attach(parent, cf, &ga, gio_print);
+
+ return 1;
+}
+
+int
+gio_submatch(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = (struct cfdata *)vcf;
+ struct gio_attach_args *ga = (struct gio_attach_args *)aux;
+
+ if (cf->cf_loc[0 /*GIOCF_SLOT*/] != -1 &&
+ cf->cf_loc[0 /*GIOCF_SLOT*/] != ga->ga_slot)
+ return 0;
+
+ if (cf->cf_loc[1 /*GIOCF_ADDR*/] != -1 &&
+ (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/] != ga->ga_addr)
+ return 0;
+
+ return (*cf->cf_attach->ca_match)(parent, cf, aux);
+}
+
+#if 0 /* XXX involve wscons_machdep somehow */
+int
+gio_cnattach(void)
+{
+ extern struct machine_bus_dma_tag imc_bus_dma_tag; /* XXX */
+ extern bus_space_t imcbus_tag; /* XXX */
+ struct gio_attach_args ga;
+ uint32_t dummy;
+ int i;
+
+ for (i = 0; gfx_bases[i].base != 0; i++) {
+ /* skip bases that don't apply to us */
+ if (gfx_bases[i].mach_type != sys_config.system_type)
+ continue;
+
+ if (gfx_bases[i].mach_subtype != -1 &&
+ gfx_bases[i].mach_subtype != sys_config.system_subtype)
+ continue;
+
+ ga.ga_slot = -1;
+ ga.ga_addr = gfx_bases[i].base;
+ ga.ga_iot = &imcbus_tag; /* XXX */
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = &imc_bus_dma_tag; /* XXX */
+ ga.ga_product = -1;
+
+ if (gio_id(ga.ga_ioh, 1) == 0)
+ continue;
+
+#if NGRTWO > 0
+ if (grtwo_cnattach(&ga) == 0)
+ return 0;
+#endif
+
+#if NLIGHT > 0
+ if (light_cnattach(&ga) == 0)
+ return 0;
+#endif
+
+#if NNEWPORT > 0
+ if (newport_cnattach(&ga) == 0)
+ return 0;
+#endif
+
+ }
+
+ return ENXIO;
+}
+#endif
+
+/*
+ * Devices living in the expansion slots must enable or disable some
+ * GIO arbiter settings. This is accomplished via imc(4) registers.
+ */
+int
+gio_arb_config(int slot, uint32_t flags)
+{
+ if (flags == 0)
+ return (EINVAL);
+
+ if (flags & ~(GIO_ARB_RT | GIO_ARB_LB | GIO_ARB_MST | GIO_ARB_SLV |
+ GIO_ARB_PIPE | GIO_ARB_NOPIPE | GIO_ARB_32BIT | GIO_ARB_64BIT |
+ GIO_ARB_HPC2_32BIT | GIO_ARB_HPC2_64BIT))
+ return (EINVAL);
+
+ if (((flags & GIO_ARB_RT) && (flags & GIO_ARB_LB)) ||
+ ((flags & GIO_ARB_MST) && (flags & GIO_ARB_SLV)) ||
+ ((flags & GIO_ARB_PIPE) && (flags & GIO_ARB_NOPIPE)) ||
+ ((flags & GIO_ARB_32BIT) && (flags & GIO_ARB_64BIT)) ||
+ ((flags & GIO_ARB_HPC2_32BIT) && (flags & GIO_ARB_HPC2_64BIT)))
+ return (EINVAL);
+
+ return (imc_gio64_arb_config(slot, flags));
+}
+
+/*
+ * Establish an interrupt handler for the specified slot.
+ *
+ * Indy and Challenge S have an interrupt per GIO slot. Indigo and Indigo2
+ * share a single interrupt, however.
+ */
+void *
+gio_intr_establish(int slot, int level, int (*func)(void *), void *arg,
+ const char *what)
+{
+ int intr;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ if (slot == GIO_SLOT_GFX)
+ return NULL;
+ intr = 6;
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (sys_config.system_subtype == IP22_INDIGO2) {
+ if (slot == GIO_SLOT_EXP1)
+ return NULL;
+ intr = 6;
+ } else {
+ if (slot == GIO_SLOT_GFX)
+ return NULL;
+ intr = (slot == GIO_SLOT_EXP0) ? 22 : 23;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ return int2_intr_establish(intr, level, func, arg, what);
+}
+
+const char *
+gio_product_string(int prid)
+{
+ int i;
+
+ for (i = 0; gio_knowndevs[i].product != NULL; i++)
+ if (gio_knowndevs[i].productid == prid)
+ return (gio_knowndevs[i].product);
+
+ return (NULL);
+}
diff --git a/sys/arch/sgi/gio/giodevs b/sys/arch/sgi/gio/giodevs
new file mode 100644
index 00000000000..8189affed20
--- /dev/null
+++ b/sys/arch/sgi/gio/giodevs
@@ -0,0 +1,21 @@
+$OpenBSD: giodevs,v 1.1 2012/03/28 20:44:23 miod Exp $
+/* $NetBSD: giodevs,v 1.8 2007/02/19 04:46:33 rumble Exp $ */
+
+product XPI 0x01 XPI low cost FDDI
+product GTR 0x02 GTR TokenRing
+product ISDN 0x04 Synchronous ISDN
+product CANON 0x06 Canon Interface
+product JPEG_D 0x08 JPEG (Double Wide)
+product JPEG_S 0x09 JPEG (Single Wide)
+product XPI_M0 0x0a XPI mez. FDDI device 0
+product XPI_M1 0x0b XPI mez. FDDI device 1
+product EP 0x0e E-Plex 8-port Ethernet
+product IVAS 0x30 Lyon Lamb IVAS
+product PHOBOS_G160 0x35 Phobos G160 10/100 Ethernet
+product PHOBOS_G130 0x36 Phobos G130 10/100 Ethernet
+product PHOBOS_G100 0x37 Phobos G100 100baseTX Fast Ethernet
+product SETENG_GFE 0x38 Set Engineering GFE 10/100 Ethernet
+product ATM 0x85 ATM board
+product SCSI 0x87 16 bit SCSI Card
+product SMPTE 0x8c SMPTE 259M Video
+product BABBLE 0x8d Babblefish Compression
diff --git a/sys/arch/sgi/gio/gioreg.h b/sys/arch/sgi/gio/gioreg.h
new file mode 100644
index 00000000000..a5bf76444e3
--- /dev/null
+++ b/sys/arch/sgi/gio/gioreg.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: gioreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: gioreg.h,v 1.4 2006/08/31 00:01:10 rumble Exp $ */
+
+/*
+ * Copyright (c) 2003 Ilpo Ruotsalainen
+ * 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. 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.
+ *
+ * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
+ */
+
+/*
+ * The GIO Product Identification Word is the first word (1 or 4 bytes)
+ * in each GIO device's address space. It is the same format for GIO32,
+ * GIO32-bis, and GIO64 devices. The macros below extract the following
+ * fields:
+ *
+ * Bits:
+ * 0-6 Product ID Code
+ * 7 Product Identification Word size (0: 8 bits, 1: 32 bits)
+ * 8-15 Product Revision
+ * 16 GIO Interface Size (0: 32, 1: 64; NB: GIO64 devices may be 32)
+ * 17 Rom Present (1: present)
+ * 18-31 Manufacturer-specific Code
+ *
+ * The upper three bytes containing the Product Revision, GIO Interface
+ * Size, Rom Presence indicator, and Manufacturer-specific Code are only
+ * valid if bit 7 is set in the Product ID Word. If it is not set, all
+ * values default to 0.
+ *
+ * If the Rom Present bit is set, the three words after the Product ID are
+ * reserved for three ROM registers:
+ * Board Serial Number Register (base_address + 0x4)
+ * ROM Index Register (base_address + 0x8)
+ * ROM Read Register (base_address + 0xc)
+ *
+ * The ROM Index Register is initialised by the CPU to 0 and incremented by
+ * 4 on each read from the ROM Read Register. The Board Serial Number
+ * Register contains a manufacturer-specific serial number.
+ */
+
+#define GIO_PRODUCT_32BIT_ID(x) ((x) & 0x80)
+#define GIO_PRODUCT_PRODUCTID(x) ((x) & 0x7f)
+#define GIO_PRODUCT_REVISION(x) (((x) >> 8) & 0xff)
+#define GIO_PRODUCT_IS_64BIT(x) (!!((x) & 0x8000))
+#define GIO_PRODUCT_HAS_ROM(x) (!!((x) & 0x10000))
+#define GIO_PRODUCT_MANUCODE(x) ((x) >> 18)
diff --git a/sys/arch/sgi/gio/giovar.h b/sys/arch/sgi/gio/giovar.h
new file mode 100644
index 00000000000..6c35c7561da
--- /dev/null
+++ b/sys/arch/sgi/gio/giovar.h
@@ -0,0 +1,75 @@
+/* $OpenBSD: giovar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: giovar.h,v 1.10 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2000 Soren S. Jorvang
+ * 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 for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 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.
+ */
+
+/*
+ * GIO 32/32-bis/64 bus
+ */
+
+struct gio_attach_args {
+ bus_space_tag_t ga_iot;
+ bus_space_handle_t ga_ioh;
+ bus_dma_tag_t ga_dmat;
+
+ int ga_slot; /* not valid if graphics */
+ u_int64_t ga_addr;
+
+ u_int32_t ga_product; /* not valid if graphics */
+};
+
+
+#define GIO_SLOT_GFX 0
+#define GIO_SLOT_EXP0 1
+#define GIO_SLOT_EXP1 2
+
+#define GIO_ARB_RT 0x001 /* real-time device */
+#define GIO_ARB_LB 0x002 /* long-burst device */
+
+#define GIO_ARB_MST 0x004 /* bus master enable */
+#define GIO_ARB_SLV 0x008 /* slave */
+
+#define GIO_ARB_PIPE 0x010 /* pipelining enable */
+#define GIO_ARB_NOPIPE 0x020 /* pipelining disable */
+
+#define GIO_ARB_32BIT 0x040 /* 32-bit transfers */
+#define GIO_ARB_64BIT 0x080 /* 64-bit transfers */
+
+#define GIO_ARB_HPC2_32BIT 0x100 /* 32-bit secondary HPC (ignores slot)*/
+#define GIO_ARB_HPC2_64BIT 0x200 /* 64-bit secondary HPC (ignores slot)*/
+
+int gio_cnattach(void);
+int gio_arb_config(int, uint32_t);
+void *gio_intr_establish(int, int, int (*)(void *), void *,
+ const char *);
+const char *gio_product_string(int);
diff --git a/sys/arch/sgi/hpc/dpclock.c b/sys/arch/sgi/hpc/dpclock.c
new file mode 100644
index 00000000000..600c3ede567
--- /dev/null
+++ b/sys/arch/sgi/hpc/dpclock.c
@@ -0,0 +1,312 @@
+/* $OpenBSD: dpclock.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: dpclock.c,v 1.3 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2001 Erik Reid
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 2001 Christopher Sekiya
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions of this code are derived from software contributed to The
+ * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * 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. 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.
+ */
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: clock.c 1.18 91/01/21$
+ *
+ * @(#)clock.c 8.2 (Berkeley) 1/12/94
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+#include <mips64/archtype.h>
+#include <mips64/dev/clockvar.h>
+
+#include <dev/ic/dp8573areg.h>
+#include <sgi/hpc/hpcvar.h>
+
+#define IRIX_BASE_YEAR 1940
+
+struct dpclock_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+int dpclock_match(struct device *, void *, void *);
+void dpclock_attach(struct device *, struct device *, void *);
+
+struct cfdriver dpclock_cd = {
+ NULL, "dpclock", DV_DULL
+};
+
+const struct cfattach dpclock_ca = {
+ sizeof(struct dpclock_softc), dpclock_match, dpclock_attach
+};
+
+#define dpclock_read(sc,r) \
+ bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3)
+#define dpclock_write(sc,r,v) \
+ bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v))
+
+static inline int frombcd(int);
+static inline int tobcd(int);
+static inline int leapyear(int year);
+
+static inline int
+frombcd(int x)
+{
+ return (x >> 4) * 10 + (x & 0xf);
+}
+static inline int
+tobcd(int x)
+{
+ return (x / 10 * 16) + (x % 10);
+}
+/*
+ * This inline avoids some unnecessary modulo operations
+ * as compared with the usual macro:
+ * ( ((year % 4) == 0 &&
+ * (year % 100) != 0) ||
+ * ((year % 400) == 0) )
+ * It is otherwise equivalent.
+ * (borrowed from kern/clock_subr.c)
+ */
+static inline int
+leapyear(int year)
+{
+ int rv = 0;
+
+ if ((year & 3) == 0) {
+ rv = 1;
+ if ((year % 100) == 0) {
+ rv = 0;
+ if ((year % 400) == 0)
+ rv = 1;
+ }
+ }
+ return (rv);
+}
+
+void dpclock_gettime(void *, time_t, struct tod_time *);
+void dpclock_settime(void *, struct tod_time *);
+
+int
+dpclock_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *haa = aux;
+
+ if (strcmp(haa->ha_name, dpclock_cd.cd_name) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+dpclock_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct dpclock_softc *sc = (void *)self;
+ struct hpc_attach_args *haa = aux;
+ uint8_t st, r;
+
+ sc->sc_iot = haa->ha_st;
+ if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
+ 4 * DP8573A_NREG, &sc->sc_ioh) != 0) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ st = dpclock_read(sc, DP8573A_STATUS);
+ dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL);
+ r = dpclock_read(sc, DP8573A_RT_MODE);
+ if ((r & DP8573A_RT_MODE_CLKSS) == 0) {
+ printf(": clock stopped");
+ dpclock_write(sc, DP8573A_RT_MODE, r | DP8573A_RT_MODE_CLKSS);
+ dpclock_write(sc, DP8573A_INT0_CTL, 0);
+ dpclock_write(sc, DP8573A_INT1_CTL, DP8573A_INT1_CTL_PWRINT);
+ }
+ dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL);
+ r = dpclock_read(sc, DP8573A_PFLAG);
+ if (r & DP8573A_PFLAG_TESTMODE) {
+ dpclock_write(sc, DP8573A_RAM_1F, 0);
+ dpclock_write(sc, DP8573A_PFLAG, r & ~DP8573A_PFLAG_TESTMODE);
+ }
+
+ printf("\n");
+
+ sys_tod.tod_get = dpclock_gettime;
+ sys_tod.tod_set = dpclock_settime;
+ sys_tod.tod_cookie = self;
+}
+
+/*
+ * Get the time of day, based on the clock's value and/or the base value.
+ */
+void
+dpclock_gettime(void *cookie, time_t base, struct tod_time *ct)
+{
+ struct dpclock_softc *sc = (void *)cookie;
+ uint i;
+ uint8_t regs[DP8573A_NREG];
+
+ i = dpclock_read(sc, DP8573A_TIMESAVE_CTL);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, i | DP8573A_TIMESAVE_CTL_EN);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, i);
+
+ for (i = 0; i < DP8573A_NREG; i++)
+ regs[i] = dpclock_read(sc, i);
+
+ ct->sec = frombcd(regs[DP8573A_SAVE_SEC]);
+ ct->min = frombcd(regs[DP8573A_SAVE_MIN]);
+
+ if (regs[DP8573A_RT_MODE] & DP8573A_RT_MODE_1224) {
+ ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] &
+ DP8573A_HOUR_12HR_MASK) +
+ ((regs[DP8573A_SAVE_HOUR] & DP8573A_RT_MODE_1224) ? 0 : 12);
+
+ /*
+ * In AM/PM mode, hour range is 01-12, so adding in 12 hours
+ * for PM gives us 01-24, whereas we want 00-23, so map hour
+ * 24 to hour 0.
+ */
+ if (ct->hour == 24)
+ ct->hour = 0;
+ } else {
+ ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] &
+ DP8573A_HOUR_24HR_MASK);
+ }
+
+ ct->day = frombcd(regs[DP8573A_SAVE_DOM]);
+ ct->mon = frombcd(regs[DP8573A_SAVE_MONTH]);
+ ct->year = frombcd(regs[DP8573A_YEAR]) + (IRIX_BASE_YEAR - 1900);
+}
+
+/*
+ * Reset the TODR based on the time value.
+ */
+void
+dpclock_settime(void *cookie, struct tod_time *ct)
+{
+ struct dpclock_softc *sc = (void *)cookie;
+ uint i;
+ uint st, r, delta;
+ uint8_t regs[DP8573A_NREG];
+
+ r = dpclock_read(sc, DP8573A_TIMESAVE_CTL);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, r | DP8573A_TIMESAVE_CTL_EN);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, r);
+
+ for (i = 0; i < DP8573A_NREG; i++)
+ regs[i] = dpclock_read(sc, i);
+
+ regs[DP8573A_SUBSECOND] = 0;
+ regs[DP8573A_SECOND] = tobcd(ct->sec);
+ regs[DP8573A_MINUTE] = tobcd(ct->min);
+ regs[DP8573A_HOUR] = tobcd(ct->hour) & DP8573A_HOUR_24HR_MASK;
+ regs[DP8573A_DOW] = tobcd(ct->dow);
+ regs[DP8573A_DOM] = tobcd(ct->day);
+ regs[DP8573A_MONTH] = tobcd(ct->mon);
+ regs[DP8573A_YEAR] = tobcd(ct->year - (IRIX_BASE_YEAR - 1900));
+
+ st = dpclock_read(sc, DP8573A_STATUS);
+ dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL);
+ r = dpclock_read(sc, DP8573A_RT_MODE);
+ dpclock_write(sc, DP8573A_RT_MODE, r & ~DP8573A_RT_MODE_CLKSS);
+
+ for (i = 0; i < 10; i++)
+ dpclock_write(sc, DP8573A_COUNTERS + i,
+ regs[DP8573A_COUNTERS + i]);
+
+ /*
+ * We now need to set the leap year counter to the correct value.
+ * Unfortunately it is only two bits wide, while eight years can
+ * happen between two leap years. Skirting this is left as an
+ * exercise to the reader with an Indigo in working condition
+ * by year 2100.
+ */
+ delta = 0;
+ while (delta < 3 && !leapyear(ct->year - delta))
+ delta++;
+
+ r &= ~(DP8573A_RT_MODE_LYLSB | DP8573A_RT_MODE_LYMSB);
+ dpclock_write(sc, DP8573A_RT_MODE, r | delta | DP8573A_RT_MODE_CLKSS);
+
+ dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL);
+}
diff --git a/sys/arch/sgi/hpc/dsclock.c b/sys/arch/sgi/hpc/dsclock.c
new file mode 100644
index 00000000000..396d68ec9d9
--- /dev/null
+++ b/sys/arch/sgi/hpc/dsclock.c
@@ -0,0 +1,192 @@
+/* $OpenBSD: dsclock.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: dsclock.c,v 1.5 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 2001 Christopher Sekiya
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions of this code are derived from software contributed to The
+ * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * 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. 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.
+ */
+
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+#include <mips64/archtype.h>
+#include <mips64/dev/clockvar.h>
+
+#include <dev/ic/ds1286reg.h>
+#include <sgi/hpc/hpcvar.h>
+
+#define IRIX_BASE_YEAR 1940
+
+struct dsclock_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+int dsclock_match(struct device *, void *, void *);
+void dsclock_attach(struct device *, struct device *, void *);
+
+struct cfdriver dsclock_cd = {
+ NULL, "dsclock", DV_DULL
+};
+
+const struct cfattach dsclock_ca = {
+ sizeof(struct dsclock_softc), dsclock_match, dsclock_attach
+};
+
+#define ds1286_read(sc,r) \
+ bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3)
+#define ds1286_write(sc,r,v) \
+ bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v))
+
+static inline int frombcd(int);
+static inline int tobcd(int);
+
+static inline int
+frombcd(int x)
+{
+ return (x >> 4) * 10 + (x & 0xf);
+}
+static inline int
+tobcd(int x)
+{
+ return (x / 10 * 16) + (x % 10);
+}
+
+void dsclock_gettime(void *, time_t, struct tod_time *);
+void dsclock_settime(void *, struct tod_time *);
+
+int
+dsclock_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *haa = aux;
+
+ if (strcmp(haa->ha_name, dsclock_cd.cd_name) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+dsclock_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct dsclock_softc *sc = (void *)self;
+ struct hpc_attach_args *haa = aux;
+
+ sc->sc_iot = haa->ha_st;
+ if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
+ 4 * 8192, &sc->sc_ioh) != 0) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ printf("\n");
+
+ sys_tod.tod_get = dsclock_gettime;
+ sys_tod.tod_set = dsclock_settime;
+ sys_tod.tod_cookie = self;
+}
+
+/*
+ * Get the time of day, based on the clock's value and/or the base value.
+ */
+void
+dsclock_gettime(void *cookie, time_t base, struct tod_time *ct)
+{
+ struct dsclock_softc *sc = (void *)cookie;
+ ds1286_todregs regs;
+ int s;
+
+ s = splhigh();
+ DS1286_GETTOD(sc, &regs)
+ splx(s);
+
+ ct->sec = frombcd(regs[DS1286_SEC]);
+ ct->min = frombcd(regs[DS1286_MIN]);
+
+ if (regs[DS1286_HOUR] & DS1286_HOUR_12MODE) {
+ ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_12HR_MASK) +
+ ((regs[DS1286_HOUR] & DS1286_HOUR_12HR_PM) ? 12 : 0);
+
+ /*
+ * In AM/PM mode, hour range is 01-12, so adding in 12 hours
+ * for PM gives us 01-24, whereas we want 00-23, so map hour
+ * 24 to hour 0.
+ */
+ if (ct->hour == 24)
+ ct->hour = 0;
+ } else {
+ ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_24HR_MASK);
+ }
+
+ ct->day = frombcd(regs[DS1286_DOM]);
+ ct->mon = frombcd(regs[DS1286_MONTH] & DS1286_MONTH_MASK);
+ ct->year = frombcd(regs[DS1286_YEAR]) + (IRIX_BASE_YEAR - 1900);
+}
+
+/*
+ * Reset the TODR based on the time value.
+ */
+void
+dsclock_settime(void *cookie, struct tod_time *ct)
+{
+ struct dsclock_softc *sc = (void *)cookie;
+ ds1286_todregs regs;
+ int s;
+
+ s = splhigh();
+ DS1286_GETTOD(sc, &regs);
+ splx(s);
+
+ regs[DS1286_SUBSEC] = 0;
+ regs[DS1286_SEC] = tobcd(ct->sec);
+ regs[DS1286_MIN] = tobcd(ct->min);
+ regs[DS1286_HOUR] = tobcd(ct->hour) & DS1286_HOUR_24HR_MASK;
+ regs[DS1286_DOW] = tobcd(ct->dow);
+ regs[DS1286_DOM] = tobcd(ct->day);
+
+ /* Leave wave-generator bits as set originally */
+ regs[DS1286_MONTH] &= ~DS1286_MONTH_MASK;
+ regs[DS1286_MONTH] |= tobcd(ct->mon) & DS1286_MONTH_MASK;
+
+ regs[DS1286_YEAR] = tobcd(ct->year - (IRIX_BASE_YEAR - 1900));
+
+ s = splhigh();
+ DS1286_PUTTOD(sc, &regs);
+ splx(s);
+}
diff --git a/sys/arch/sgi/hpc/files.hpc b/sys/arch/sgi/hpc/files.hpc
new file mode 100644
index 00000000000..4463f066a45
--- /dev/null
+++ b/sys/arch/sgi/hpc/files.hpc
@@ -0,0 +1,56 @@
+# $OpenBSD: files.hpc,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: files.hpc,v 1.14 2009/05/14 01:10:19 macallan Exp $
+
+# IP20 RTC
+device dpclock
+attach dpclock at hpc
+file arch/sgi/hpc/dpclock.c dpclock
+
+# IP22/24 RTC
+device dsclock
+attach dsclock at hpc
+file arch/sgi/hpc/dsclock.c dsclock
+
+device sq: ether, ifnet
+attach sq at hpc
+file arch/sgi/hpc/if_sq.c sq
+
+define hpcdma
+file arch/sgi/hpc/hpcdma.c hpcdma
+
+device wdsc: wd33c93, scsi, hpcdma
+attach wdsc at hpc
+file arch/sgi/hpc/wdsc.c wdsc
+
+device haltwo: audio, auconv, mulaw
+attach haltwo at hpc
+file arch/sgi/hpc/haltwo.c haltwo
+
+device zs {[channel = -1]}
+attach zs at hpc with zs_hpc
+file arch/sgi/hpc/zs.c zs needs-flag
+file arch/sgi/hpc/z8530sc.c zs
+
+device zstty: tty
+attach zstty at zs
+file arch/sgi/hpc/z8530tty.c zstty needs-flag
+
+device zskbd: wskbddev
+attach zskbd at zs
+file arch/sgi/hpc/zs_kbd.c zskbd needs-flag
+file arch/sgi/dev/wskbdmap_sgi.c zskbd
+
+device zsms: wsmousedev
+attach zsms at zs
+file arch/sgi/hpc/zs_ms.c zsms
+
+attach pckbc at hpc with pckbc_hpc
+file arch/sgi/hpc/pckbc_hpc.c pckbc_hpc
+
+#device pione
+#attach pione at hpc
+#file arch/sgi/hpc/pione.c pione
+
+device panel
+attach panel at hpc
+file arch/sgi/hpc/panel.c panel
diff --git a/sys/arch/sgi/hpc/hpc.c b/sys/arch/sgi/hpc/hpc.c
new file mode 100644
index 00000000000..ca2c31c06ed
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpc.c
@@ -0,0 +1,822 @@
+/* $OpenBSD: hpc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpc.c,v 1.66 2011/07/01 18:53:46 dyoung Exp $ */
+/* $NetBSD: ioc.c,v 1.9 2011/07/01 18:53:47 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2003 Christopher Sekiya
+ * 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 for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 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.
+ */
+/*
+ * Copyright (c) 2000 Soren S. Jorvang
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 2001 Jason R. Thorpe
+ * 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 for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 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.
+ */
+
+/*
+ * Combined driver for the HPC (High performance Peripheral Controller)
+ * and IOC2 (I/O Controller) chips.
+ *
+ * It would theoretically be better to attach an IOC driver to HPC on
+ * IOC systems (IP22/24/26/28), and attach the few onboard devices
+ * which attach directly to HPC on IP20, to IOC. But since IOC depends
+ * too much on HPC, the complexity this would introduce is not worth
+ * the hassle.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <sgi/gio/gioreg.h>
+#include <sgi/gio/giovar.h>
+
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/iocreg.h>
+#include <sgi/sgi/ip22.h>
+
+#include <dev/ic/smc93cx6var.h>
+
+struct hpc_device {
+ const char *hd_name;
+ bus_addr_t hd_base;
+ bus_addr_t hd_devoff;
+ bus_addr_t hd_dmaoff;
+ int hd_irq;
+ int hd_sysmask;
+};
+
+static const struct hpc_device hpc1_devices[] = {
+ /* probe order is important for IP20 zs */
+
+ { "zs", /* Indigo serial 0/1 duart 1 */
+ HPC_BASE_ADDRESS_0,
+ 0x0d10, 0,
+ 5,
+ HPCDEV_IP20 },
+
+ { "zs", /* Indigo kbd/ms duart 0 */
+ HPC_BASE_ADDRESS_0,
+ 0x0d00, 0,
+ 5,
+ HPCDEV_IP20 },
+
+ { "sq", /* Indigo onboard ethernet */
+ HPC_BASE_ADDRESS_0,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 3,
+ HPCDEV_IP20 },
+
+ { "sq", /* E++ GIO adapter slot 0 (Indigo) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "sq", /* E++ GIO adapter slot 0 (Indy) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 16 + 6,
+ HPCDEV_IP24 },
+
+ { "sq", /* E++ GIO adapter slot 1 (Indigo) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "sq", /* E++ GIO adapter slot 1 (Indy/Challenge S) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 16 + 7,
+ HPCDEV_IP24 },
+
+ { "wdsc", /* Indigo onboard SCSI */
+ HPC_BASE_ADDRESS_0,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 2,
+ HPCDEV_IP20 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 0 (Indigo) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 0 (Indy) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 16 + 6,
+ HPCDEV_IP24 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 1 (Indigo) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 1 (Indy/Challenge S) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 16 + 7,
+ HPCDEV_IP24 },
+
+ { NULL,
+ 0,
+ 0, 0,
+ 0,
+ 0
+ }
+};
+
+static const struct hpc_device hpc3_devices[] = {
+ { "zs", /* serial 0/1 duart 0 */
+ HPC_BASE_ADDRESS_0,
+ /* XXX Magic numbers */
+ HPC3_PBUS_CH6_DEVREGS + IOC_SERIAL_REGS, 0,
+ 24 + 5,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "pckbc", /* Indigo2/Indy ps2 keyboard/mouse controller */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH6_DEVREGS + IOC_KB_REGS, 0,
+ 24 + 4,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "sq", /* Indigo2/Indy/Challenge S/Challenge M onboard enet */
+ HPC_BASE_ADDRESS_0,
+ HPC3_ENET_DEVREGS, HPC3_ENET_REGS,
+ 3,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "sq", /* Challenge S IOPLUS secondary ethernet */
+ HPC_BASE_ADDRESS_1,
+ HPC3_ENET_DEVREGS, HPC3_ENET_REGS,
+ 0,
+ HPCDEV_IP24 },
+
+ { "wdsc", /* Indigo2/Indy/Challenge S/Challenge M onboard SCSI */
+ HPC_BASE_ADDRESS_0,
+ HPC3_SCSI0_DEVREGS, HPC3_SCSI0_REGS,
+ 1,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "wdsc", /* Indigo2/Challenge M secondary onboard SCSI */
+ HPC_BASE_ADDRESS_0,
+ HPC3_SCSI1_DEVREGS, HPC3_SCSI1_REGS,
+ 2,
+ HPCDEV_IP22 },
+
+ { "haltwo", /* Indigo2/Indy onboard audio */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH0_DEVREGS, HPC3_PBUS_DMAREGS,
+ 8 + 4, /* really the HPC DMA complete interrupt */
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "pione", /* Indigo2/Indy/Challenge S/Challenge M onboard pport */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH6_DEVREGS + IOC_PLP_REGS, 0,
+ 5,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "panel", /* Indy front panel */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH6_DEVREGS + IOC_PANEL, 0,
+ 9,
+ HPCDEV_IP24 },
+
+ { NULL,
+ 0,
+ 0, 0,
+ 0,
+ 0
+ }
+};
+
+struct hpc_softc {
+ struct device sc_dev;
+
+ bus_addr_t sc_base;
+
+ bus_space_tag_t sc_ct;
+ bus_space_handle_t sc_ch;
+ bus_dma_tag_t sc_dmat;
+
+ struct timeout sc_blink_tmo;
+};
+
+static struct hpc_values hpc1_values = {
+ .revision = 1,
+ .scsi0_regs = HPC1_SCSI0_REGS,
+ .scsi0_regs_size = HPC1_SCSI0_REGS_SIZE,
+ .scsi0_cbp = HPC1_SCSI0_CBP,
+ .scsi0_ndbp = HPC1_SCSI0_NDBP,
+ .scsi0_bc = HPC1_SCSI0_BC,
+ .scsi0_ctl = HPC1_SCSI0_CTL,
+ .scsi0_gio = HPC1_SCSI0_GIO,
+ .scsi0_dev = HPC1_SCSI0_DEV,
+ .scsi0_dmacfg = HPC1_SCSI0_DMACFG,
+ .scsi0_piocfg = HPC1_SCSI0_PIOCFG,
+ .scsi1_regs = 0,
+ .scsi1_regs_size = 0,
+ .scsi1_cbp = 0,
+ .scsi1_ndbp = 0,
+ .scsi1_bc = 0,
+ .scsi1_ctl = 0,
+ .scsi1_gio = 0,
+ .scsi1_dev = 0,
+ .scsi1_dmacfg = 0,
+ .scsi1_piocfg = 0,
+ .enet_regs = HPC1_ENET_REGS,
+ .enet_regs_size = HPC1_ENET_REGS_SIZE,
+ .enet_intdelay = HPC1_ENET_INTDELAY,
+ .enet_intdelayval = HPC1_ENET_INTDELAY_OFF,
+ .enetr_cbp = HPC1_ENETR_CBP,
+ .enetr_ndbp = HPC1_ENETR_NDBP,
+ .enetr_bc = HPC1_ENETR_BC,
+ .enetr_ctl = HPC1_ENETR_CTL,
+ .enetr_ctl_active = HPC1_ENETR_CTL_ACTIVE,
+ .enetr_reset = HPC1_ENETR_RESET,
+ .enetr_dmacfg = 0,
+ .enetr_piocfg = 0,
+ .enetx_cbp = HPC1_ENETX_CBP,
+ .enetx_ndbp = HPC1_ENETX_NDBP,
+ .enetx_bc = HPC1_ENETX_BC,
+ .enetx_ctl = HPC1_ENETX_CTL,
+ .enetx_ctl_active = HPC1_ENETX_CTL_ACTIVE,
+ .enetx_dev = 0,
+ .enetr_fifo = HPC1_ENETR_FIFO,
+ .enetr_fifo_size = HPC1_ENETR_FIFO_SIZE,
+ .enetx_fifo = HPC1_ENETX_FIFO,
+ .enetx_fifo_size = HPC1_ENETX_FIFO_SIZE,
+ .enet_dma_boundary = 4096,
+ .enet_devregs = HPC1_ENET_DEVREGS,
+ .enet_devregs_size = HPC1_ENET_DEVREGS_SIZE,
+ .pbus_fifo = 0,
+ .pbus_fifo_size = 0,
+ .pbus_bbram = 0,
+#define MAX_SCSI_XFER (roundup(MAXPHYS, PAGE_SIZE))
+ .scsi_dma_segs = (MAX_SCSI_XFER / 4096),
+ .scsi_dma_segs_size = 4096,
+ .scsi_dma_datain_cmd = (HPC1_SCSI_DMACTL_ACTIVE | HPC1_SCSI_DMACTL_DIR),
+ .scsi_dma_dataout_cmd = HPC1_SCSI_DMACTL_ACTIVE,
+ .scsi_dmactl_flush = HPC1_SCSI_DMACTL_FLUSH,
+ .scsi_dmactl_active = HPC1_SCSI_DMACTL_ACTIVE,
+ .scsi_dmactl_reset = HPC1_SCSI_DMACTL_RESET
+};
+
+static struct hpc_values hpc3_values = {
+ .revision = 3,
+ .scsi0_regs = HPC3_SCSI0_REGS,
+ .scsi0_regs_size = HPC3_SCSI0_REGS_SIZE,
+ .scsi0_cbp = HPC3_SCSI0_CBP,
+ .scsi0_ndbp = HPC3_SCSI0_NDBP,
+ .scsi0_bc = HPC3_SCSI0_BC,
+ .scsi0_ctl = HPC3_SCSI0_CTL,
+ .scsi0_gio = HPC3_SCSI0_GIO,
+ .scsi0_dev = HPC3_SCSI0_DEV,
+ .scsi0_dmacfg = HPC3_SCSI0_DMACFG,
+ .scsi0_piocfg = HPC3_SCSI0_PIOCFG,
+ .scsi1_regs = HPC3_SCSI1_REGS,
+ .scsi1_regs_size = HPC3_SCSI1_REGS_SIZE,
+ .scsi1_cbp = HPC3_SCSI1_CBP,
+ .scsi1_ndbp = HPC3_SCSI1_NDBP,
+ .scsi1_bc = HPC3_SCSI1_BC,
+ .scsi1_ctl = HPC3_SCSI1_CTL,
+ .scsi1_gio = HPC3_SCSI1_GIO,
+ .scsi1_dev = HPC3_SCSI1_DEV,
+ .scsi1_dmacfg = HPC3_SCSI1_DMACFG,
+ .scsi1_piocfg = HPC3_SCSI1_PIOCFG,
+ .enet_regs = HPC3_ENET_REGS,
+ .enet_regs_size = HPC3_ENET_REGS_SIZE,
+ .enet_intdelay = 0,
+ .enet_intdelayval = 0,
+ .enetr_cbp = HPC3_ENETR_CBP,
+ .enetr_ndbp = HPC3_ENETR_NDBP,
+ .enetr_bc = HPC3_ENETR_BC,
+ .enetr_ctl = HPC3_ENETR_CTL,
+ .enetr_ctl_active = HPC3_ENETR_CTL_ACTIVE,
+ .enetr_reset = HPC3_ENETR_RESET,
+ .enetr_dmacfg = HPC3_ENETR_DMACFG,
+ .enetr_piocfg = HPC3_ENETR_PIOCFG,
+ .enetx_cbp = HPC3_ENETX_CBP,
+ .enetx_ndbp = HPC3_ENETX_NDBP,
+ .enetx_bc = HPC3_ENETX_BC,
+ .enetx_ctl = HPC3_ENETX_CTL,
+ .enetx_ctl_active = HPC3_ENETX_CTL_ACTIVE,
+ .enetx_dev = HPC3_ENETX_DEV,
+ .enetr_fifo = HPC3_ENETR_FIFO,
+ .enetr_fifo_size = HPC3_ENETR_FIFO_SIZE,
+ .enetx_fifo = HPC3_ENETX_FIFO,
+ .enetx_fifo_size = HPC3_ENETX_FIFO_SIZE,
+ .enet_dma_boundary = 8192,
+ .enet_devregs = HPC3_ENET_DEVREGS,
+ .enet_devregs_size = HPC3_ENET_DEVREGS_SIZE,
+ .pbus_fifo = HPC3_PBUS_FIFO,
+ .pbus_fifo_size = HPC3_PBUS_FIFO_SIZE,
+ .pbus_bbram = HPC3_PBUS_BBRAM,
+ .scsi_dma_segs = (MAX_SCSI_XFER / 8192),
+ .scsi_dma_segs_size = 8192,
+ .scsi_dma_datain_cmd = HPC3_SCSI_DMACTL_ACTIVE,
+ .scsi_dma_dataout_cmd =(HPC3_SCSI_DMACTL_ACTIVE | HPC3_SCSI_DMACTL_DIR),
+ .scsi_dmactl_flush = HPC3_SCSI_DMACTL_FLUSH,
+ .scsi_dmactl_active = HPC3_SCSI_DMACTL_ACTIVE,
+ .scsi_dmactl_reset = HPC3_SCSI_DMACTL_RESET
+};
+
+int hpc_match(struct device *, void *, void *);
+void hpc_attach(struct device *, struct device *, void *);
+int hpc_print(void *, const char *);
+
+int hpc_revision(struct hpc_softc *, struct gio_attach_args *);
+int hpc_submatch(struct device *, void *, void *);
+int hpc_power_intr(void *);
+void hpc_blink(void *);
+void hpc_blink_ioc(void *);
+int hpc_read_eeprom(int, bus_space_tag_t, bus_space_handle_t, uint8_t *,
+ size_t);
+
+const struct cfattach hpc_ca = {
+ sizeof(struct hpc_softc), hpc_match, hpc_attach
+};
+
+struct cfdriver hpc_cd = {
+ NULL, "hpc", DV_DULL
+};
+
+uint8_t hpc_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint16_t hpc_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void hpc_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void hpc_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t);
+void hpc_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t);
+void hpc_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+uint32_t hpc_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint64_t hpc_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void hpc_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t);
+void hpc_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t);
+void hpc_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void hpc_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+void hpc_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void hpc_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+int hpc_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+void hpc_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+int hpc_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+void *hpc_space_vaddr(bus_space_tag_t, bus_space_handle_t);
+void hpc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, int);
+
+int
+hpc_match(struct device *parent, void *vcf, void *aux)
+{
+ struct gio_attach_args* ga = aux;
+ uint32_t dummy;
+
+ /* Make sure it's actually there and readable */
+ if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr, CCA_NC), &dummy) == 0)
+ return 1;
+
+ return 0;
+}
+
+void
+hpc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct hpc_softc *sc = (struct hpc_softc *)self;
+ struct gio_attach_args* ga = aux;
+ struct hpc_attach_args ha;
+ const struct hpc_device *hd;
+ uint32_t dummy;
+ uint32_t hpctype;
+ int isonboard;
+ int isioplus;
+ int sysmask = 0;
+
+ sc->sc_base = ga->ga_addr;
+ sc->sc_ct = ga->ga_iot;
+ sc->sc_ch = PHYS_TO_XKPHYS(sc->sc_base, CCA_NC);
+ sc->sc_dmat = ga->ga_dmat;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ sysmask = HPCDEV_IP20;
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (sys_config.system_subtype == IP22_INDIGO2)
+ sysmask = HPCDEV_IP22;
+ else
+ sysmask = HPCDEV_IP24;
+ break;
+ };
+
+ if ((hpctype = hpc_revision(sc, ga)) == 0) {
+ printf(": could not identify HPC revision\n");
+ return;
+ }
+
+ /* force big-endian mode */
+ if (hpctype == 15)
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, HPC1_BIGENDIAN, 0);
+
+ /*
+ * All machines have only one HPC on the mainboard itself. ''Extra''
+ * HPCs require bus arbiter and other magic to run happily.
+ */
+ isonboard = (sc->sc_base == HPC_BASE_ADDRESS_0);
+ isioplus = (sc->sc_base == HPC_BASE_ADDRESS_1 && hpctype == 3 &&
+ sysmask == HPCDEV_IP24);
+
+ printf(": SGI HPC%d%s (%s)\n", (hpctype == 3) ? 3 : 1,
+ (hpctype == 15) ? ".5" : "", (isonboard) ? "onboard" :
+ (isioplus) ? "IOPLUS mezzanine" : "GIO slot");
+
+ /*
+ * Configure the IOC.
+ */
+ if (isonboard && sys_config.system_type != SGI_IP20) {
+ /* Reset IOC */
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET,
+ IOC_RESET_PARALLEL | IOC_RESET_PCKBC | IOC_RESET_EISA |
+ IOC_RESET_ISDN | IOC_RESET_LED_GREEN );
+
+ /*
+ * Set the 10BaseT port to use UTP cable, set autoselect mode
+ * for the Ethernet interface (AUI vs. TP), set the two serial
+ * ports to PC mode.
+ */
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_WRITE,
+ IOC_WRITE_ENET_AUTO | IOC_WRITE_ENET_UTP |
+ IOC_WRITE_PC_UART2 | IOC_WRITE_PC_UART1);
+
+ /* XXX: the firmware should have taken care of this already */
+#if 0
+ if (sys_config.system_subtype == IP22_INDY) {
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ IOC_BASE + IOC_GCSEL, 0xff);
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ IOC_BASE + IOC_GCREG, 0xff);
+ }
+#endif
+ }
+
+ /*
+ * Configure the bus arbiter appropriately.
+ *
+ * In the case of Challenge S, we must tell the IOPLUS board which
+ * DMA channel to use (we steal it from one of the slots). SGI allows
+ * an HPC1.5 in slot 1, in which case IOPLUS must use EXP0, or any
+ * other DMA-capable board in slot 0, which leaves us to use EXP1. Of
+ * course, this means that only one GIO board may use DMA.
+ *
+ * Note that this never happens on Indigo2.
+ */
+ if (isioplus) {
+ int arb_slot;
+
+ if (guarded_read_4(PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_2, CCA_NC),
+ &dummy) != 0)
+ arb_slot = GIO_SLOT_EXP1;
+ else
+ arb_slot = GIO_SLOT_EXP0;
+
+ if (gio_arb_config(arb_slot, GIO_ARB_LB | GIO_ARB_MST |
+ GIO_ARB_64BIT | GIO_ARB_HPC2_64BIT)) {
+ printf("%s: failed to configure GIO bus arbiter\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+
+ printf("%s: using EXP%d's DMA channel\n",
+ sc->sc_dev.dv_xname,
+ (arb_slot == GIO_SLOT_EXP0) ? 0 : 1);
+
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ HPC3_PBUS_CFGPIO_REGS, 0x0003ffff);
+
+ if (arb_slot == GIO_SLOT_EXP0)
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ HPC3_PBUS_CH0_DEVREGS, 0x20202020);
+ else
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ HPC3_PBUS_CH0_DEVREGS, 0x30303030);
+ } else if (!isonboard) {
+ int arb_slot;
+
+ arb_slot = (sc->sc_base == HPC_BASE_ADDRESS_1) ?
+ GIO_SLOT_EXP0 : GIO_SLOT_EXP1;
+
+ if (gio_arb_config(arb_slot, GIO_ARB_RT | GIO_ARB_MST)) {
+ printf("%s: failed to configure GIO bus arbiter\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ }
+
+ hpc_read_eeprom(hpctype, sc->sc_ct, sc->sc_ch,
+ ha.hpc_eeprom, sizeof(ha.hpc_eeprom));
+
+ hd = hpctype == 3 ? hpc3_devices : hpc1_devices;
+ for (; hd->hd_name != NULL; hd++) {
+ if (!(hd->hd_sysmask & sysmask) || hd->hd_base != sc->sc_base)
+ continue;
+
+ ha.ha_name = hd->hd_name;
+ ha.ha_devoff = hd->hd_devoff;
+ ha.ha_dmaoff = hd->hd_dmaoff;
+ ha.ha_irq = hd->hd_irq;
+
+ ha.ha_st = sc->sc_ct;
+ ha.ha_sh = sc->sc_ch;
+ ha.ha_dmat = sc->sc_dmat;
+ if (hpctype == 3)
+ ha.hpc_regs = &hpc3_values;
+ else
+ ha.hpc_regs = &hpc1_values;
+ ha.hpc_regs->revision = hpctype;
+
+ /*
+ * XXX On hpc@gio boards such as the E++, this will cause
+ * XXX `wdsc not configured' messages (or sq on SCSI
+ * XXX boards. We need to move some device detection
+ * XXX in there, or figure out if there is a way to know
+ * XXX what is really connected.
+ */
+ config_found_sm(self, &ha, hpc_print, hpc_submatch);
+ }
+
+ /*
+ * Attach the clock chip as well if on hpc0.
+ */
+ if (isonboard) {
+ if (sys_config.system_type == SGI_IP20) {
+ ha.ha_name = "dpclock";
+ ha.ha_devoff = HPC1_PBUS_BBRAM;
+ } else {
+ ha.ha_name = "dsclock";
+ ha.ha_devoff = HPC3_PBUS_BBRAM;
+ }
+ ha.ha_dmaoff = 0;
+ ha.ha_irq = -1;
+ ha.ha_st = sc->sc_ct;
+ ha.ha_sh = sc->sc_ch;
+ ha.ha_dmat = sc->sc_dmat;
+ ha.hpc_regs = NULL;
+
+ config_found_sm(self, &ha, hpc_print, hpc_submatch);
+
+ if (sys_config.system_type == SGI_IP20) {
+ timeout_set(&sc->sc_blink_tmo, hpc_blink, sc);
+ hpc_blink(sc);
+ } else {
+ timeout_set(&sc->sc_blink_tmo, hpc_blink_ioc, sc);
+ hpc_blink_ioc(sc);
+ }
+ }
+}
+
+/*
+ * HPC revision detection isn't as simple as it should be. Devices probe
+ * differently depending on their slots, but luckily there is only one
+ * instance in which we have to decide the major revision (HPC1 vs HPC3).
+ *
+ * The HPC is found in the following configurations:
+ * o Indigo R4k
+ * One on-board HPC1 or HPC1.5.
+ * Up to two additional HPC1.5's in GIO slots 0 and 1.
+ * o Indy
+ * One on-board HPC3.
+ * Up to two additional HPC1.5's in GIO slots 0 and 1.
+ * o Challenge S
+ * One on-board HPC3.
+ * Up to one additional HPC3 on the IOPLUS board (if installed).
+ * Up to one additional HPC1.5 in slot 1 of the IOPLUS board.
+ * o Indigo2, Challenge M
+ * One on-board HPC3.
+ *
+ * All we really have to worry about is the IP22 case.
+ */
+int
+hpc_revision(struct hpc_softc *sc, struct gio_attach_args *ga)
+{
+ uint32_t reg;
+
+ /* No hardware ever supported the last hpc base address. */
+ if (ga->ga_addr == HPC_BASE_ADDRESS_3)
+ return 0;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr + HPC1_BIGENDIAN,
+ CCA_NC), &reg) != 0) {
+ if (((reg >> HPC1_REVSHIFT) & HPC1_REVMASK) ==
+ HPC1_REV15)
+ return 15;
+ else
+ return 1;
+ }
+ return 1;
+
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ /*
+ * If IP22, probe slot 0 to determine if HPC1.5 or HPC3. Slot 1
+ * must be HPC1.5.
+ */
+ if (ga->ga_addr == HPC_BASE_ADDRESS_0)
+ return 3;
+
+ if (ga->ga_addr == HPC_BASE_ADDRESS_2)
+ return 15;
+
+ /*
+ * Probe for it. We use one of the PBUS registers. Note
+ * that this probe succeeds with my E++ adapter in slot 1
+ * (bad), but it appears to always do the right thing in
+ * slot 0 (good!) and we're only worried about that one
+ * anyhow.
+ */
+ if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr +
+ HPC3_PBUS_CH7_BP, CCA_NC), &reg) != 0)
+ return 15;
+ else
+ return 3;
+ }
+
+ return 0;
+}
+
+int
+hpc_submatch(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = (struct cfdata *)vcf;
+ struct hpc_attach_args *ha = (struct hpc_attach_args *)aux;
+
+ if (cf->cf_loc[0 /*HPCCF_OFFSET*/] != -1 &&
+ (bus_addr_t)cf->cf_loc[0 /*HPCCF_OFFSET*/] != ha->ha_devoff)
+ return 0;
+
+ return (*cf->cf_attach->ca_match)(parent, cf, aux);
+}
+
+int
+hpc_print(void *aux, const char *pnp)
+{
+ struct hpc_attach_args *ha = aux;
+
+ if (pnp)
+ printf("%s at %s", ha->ha_name, pnp);
+
+ printf(" offset 0x%08lx", ha->ha_devoff);
+ if (ha->ha_irq >= 0)
+ printf(" irq %d", ha->ha_irq);
+
+ return UNCONF;
+}
+
+void
+hpc_blink(void *arg)
+{
+ struct hpc_softc *sc = arg;
+
+ bus_space_write_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS,
+ bus_space_read_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS) ^
+ HPC1_AUX_CONSLED);
+
+ timeout_add(&sc->sc_blink_tmo,
+ (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)));
+}
+
+void
+hpc_blink_ioc(void *arg)
+{
+ struct hpc_softc *sc = arg;
+ uint32_t value;
+
+ /* This is a bit odd. To strobe the green LED, we have to toggle the
+ red control bit. */
+ value = bus_space_read_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET) &
+ 0xff;
+ value ^= IOC_RESET_LED_RED;
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET, value);
+
+ timeout_add(&sc->sc_blink_tmo,
+ (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)));
+}
+
+/*
+ * Read the eeprom associated with one of the HPC's.
+ *
+ * NB: An eeprom is not always present, but the HPC should be able to
+ * handle this gracefully. Any consumers should validate the data to
+ * ensure it's reasonable.
+ */
+int
+hpc_read_eeprom(int hpctype, bus_space_tag_t t, bus_space_handle_t h,
+ uint8_t *buf, size_t len)
+{
+ struct seeprom_descriptor sd;
+ bus_space_handle_t bsh;
+ bus_size_t offset;
+
+ if (!len || len & 0x1)
+ return (1);
+
+ offset = (hpctype == 3) ? HPC3_EEPROM_DATA : HPC1_AUX_REGS;
+
+ if (bus_space_subregion(t, h, offset, 1, &bsh) != 0)
+ return (1);
+
+ sd.sd_chip = C56_66;
+ sd.sd_tag = t;
+ sd.sd_bsh = bsh;
+ sd.sd_regsize = 1;
+ sd.sd_control_offset = 0;
+ sd.sd_status_offset = 0;
+ sd.sd_dataout_offset = 0;
+ sd.sd_DI = 0x10; /* EEPROM -> CPU */
+ sd.sd_DO = 0x08; /* CPU -> EEPROM */
+ sd.sd_CK = 0x04;
+ sd.sd_CS = 0x02;
+ sd.sd_MS = 0;
+ sd.sd_RDY = 0;
+
+ if (read_seeprom(&sd, (uint16_t *)buf, 0, len / 2) != 1)
+ return (1);
+
+ bus_space_unmap(t, bsh, 1);
+
+ return 0;
+}
diff --git a/sys/arch/sgi/hpc/hpcdma.c b/sys/arch/sgi/hpc/hpcdma.c
new file mode 100644
index 00000000000..53dc86994ce
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcdma.c
@@ -0,0 +1,208 @@
+/* $OpenBSD: hpcdma.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcdma.c,v 1.21 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wayne Knowles
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Support for SCSI DMA provided by the HPC.
+ *
+ * Note: We use SCSI0 offsets, etc. here. Since the layout of SCSI0
+ * and SCSI1 are the same, this is no problem.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/bus.h>
+
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcdma.h>
+
+/*
+ * Allocate DMA Chain descriptor list
+ */
+void
+hpcdma_init(struct hpc_attach_args *haa, struct hpc_dma_softc *sc, int ndesc)
+{
+ bus_dma_segment_t seg;
+ int rseg, allocsz;
+
+ sc->sc_bst = haa->ha_st;
+ sc->sc_dmat = haa->ha_dmat;
+ sc->sc_ndesc = ndesc;
+ sc->sc_flags = 0;
+
+ if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_dmaoff,
+ sc->hpc->scsi0_regs_size, &sc->sc_bsh) != 0) {
+ printf(": can't map DMA registers\n");
+ return;
+ }
+
+ /* Alloc 1 additional descriptor - needed for DMA bug fix */
+ allocsz = sizeof(struct hpc_dma_desc) * (ndesc + 1);
+
+ /*
+ * Allocate a block of memory for dma chaining pointers
+ */
+ if (bus_dmamem_alloc(sc->sc_dmat, allocsz, 0, 0, &seg, 1, &rseg,
+ BUS_DMA_NOWAIT)) {
+ printf(": can't allocate sglist\n");
+ return;
+ }
+ /* Map pages into kernel memory */
+ if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, allocsz,
+ (caddr_t *)&sc->sc_desc_kva, BUS_DMA_NOWAIT)) {
+ printf(": can't map sglist\n");
+ bus_dmamem_free(sc->sc_dmat, &seg, rseg);
+ return;
+ }
+
+ if (bus_dmamap_create(sc->sc_dmat, allocsz, 1 /*seg*/, allocsz, 0,
+ BUS_DMA_WAITOK, &sc->sc_dmamap) != 0) {
+ printf(": failed to create dmamap\n");
+ return;
+ }
+
+ if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
+ sc->sc_desc_kva, allocsz, NULL, BUS_DMA_NOWAIT)) {
+ printf(": can't load sglist\n");
+ return;
+ }
+
+ sc->sc_desc_pa = sc->sc_dmamap->dm_segs[0].ds_addr;
+}
+
+
+void
+hpcdma_sglist_create(struct hpc_dma_softc *sc, bus_dmamap_t dmamap)
+{
+ struct hpc_dma_desc *hva;
+ bus_addr_t hpa;
+ bus_dma_segment_t *segp;
+ int i;
+
+ KASSERT(dmamap->dm_nsegs <= sc->sc_ndesc);
+
+ hva = sc->sc_desc_kva;
+ hpa = sc->sc_desc_pa;
+ segp = dmamap->dm_segs;
+
+#ifdef DMA_DEBUG
+ printf("DMA_SGLIST<");
+#endif
+ for (i = dmamap->dm_nsegs; i; i--) {
+#ifdef DMA_DEBUG
+ printf("%p:%ld, ", (void *)segp->ds_addr, segp->ds_len);
+#endif
+ hpa += sizeof(struct hpc_dma_desc); /* next chain desc */
+ if (sc->hpc->revision == 3) {
+ hva->hpc3_hdd_bufptr = segp->ds_addr;
+ hva->hpc3_hdd_ctl = segp->ds_len;
+ hva->hdd_descptr = hpa;
+ } else /* HPC 1/1.5 */ {
+ /*
+ * there doesn't seem to be any good way of doing this
+ * via an abstraction layer
+ */
+ hva->hpc1_hdd_bufptr = segp->ds_addr;
+ hva->hpc1_hdd_ctl = segp->ds_len;
+ hva->hdd_descptr = hpa;
+ }
+ ++hva;
+ ++segp;
+ }
+
+ /* Work around HPC3 DMA bug */
+ if (sc->hpc->revision == 3) {
+ hva->hpc3_hdd_bufptr = 0;
+ hva->hpc3_hdd_ctl = HPC3_HDD_CTL_EOCHAIN;
+ hva->hdd_descptr = 0;
+ } else {
+ hva--;
+ hva->hpc1_hdd_bufptr |= HPC1_HDD_CTL_EOCHAIN;
+ hva->hdd_descptr = 0;
+ }
+
+#ifdef DMA_DEBUG
+ printf(">\n");
+#endif
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
+ 0, sizeof(struct hpc_dma_desc) * (dmamap->dm_nsegs + 1),
+ BUS_DMASYNC_PREWRITE);
+
+ /* Load DMA Descriptor list */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ndbp,
+ sc->sc_desc_pa);
+}
+
+void
+hpcdma_cntl(struct hpc_dma_softc *sc, uint32_t mode)
+{
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, mode);
+}
+
+void
+hpcdma_reset(struct hpc_dma_softc *sc)
+{
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl,
+ sc->hpc->scsi_dmactl_reset);
+ delay(100);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 0);
+ delay(1000);
+}
+
+void
+hpcdma_flush(struct hpc_dma_softc *sc)
+{
+ uint32_t mode;
+
+ mode = bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+ sc->hpc->scsi0_ctl, mode | sc->hpc->scsi_dmactl_flush);
+
+ /* Wait for Active bit to drop */
+ while (bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl) &
+ sc->hpc->scsi_dmactl_active) {
+ bus_space_barrier(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 4,
+ BUS_SPACE_BARRIER_READ);
+ }
+}
diff --git a/sys/arch/sgi/hpc/hpcdma.h b/sys/arch/sgi/hpc/hpcdma.h
new file mode 100644
index 00000000000..bca5fc5b171
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcdma.h
@@ -0,0 +1,63 @@
+/* $OpenBSD: hpcdma.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcdma.h,v 1.11 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wayne Knowles
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct hpc_dma_softc {
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ bus_dma_tag_t sc_dmat;
+
+ uint32_t sc_flags;
+#define HPCDMA_READ 0x20 /* direction of transfer */
+#define HPCDMA_LOADED 0x40 /* bus_dmamap loaded */
+#define HPCDMA_ACTIVE 0x80 /* DMA engine is busy */
+ uint32_t sc_dmacmd;
+ int sc_ndesc;
+ bus_dmamap_t sc_dmamap;
+ struct hpc_dma_desc *sc_desc_kva; /* Virtual address */
+ bus_addr_t sc_desc_pa; /* DMA address */
+ ssize_t sc_dlen; /* number of bytes transfered */
+ struct hpc_values *hpc; /* constants for HPC1/3 */
+};
+
+
+void hpcdma_init(struct hpc_attach_args *, struct hpc_dma_softc *, int);
+void hpcdma_sglist_create(struct hpc_dma_softc *, bus_dmamap_t);
+void hpcdma_cntl(struct hpc_dma_softc *, uint32_t);
+void hpcdma_reset(struct hpc_dma_softc *);
+void hpcdma_flush(struct hpc_dma_softc *);
diff --git a/sys/arch/sgi/hpc/hpcreg.h b/sys/arch/sgi/hpc/hpcreg.h
new file mode 100644
index 00000000000..bce6a2d2245
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcreg.h
@@ -0,0 +1,450 @@
+/* $OpenBSD: hpcreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcreg.h,v 1.20 2011/01/25 12:21:04 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * 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. 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.
+ */
+
+/*
+ * HPC locations are identical across all HPC-supported
+ * platforms.
+ */
+#define HPC_BASE_ADDRESS_0 0x1fb80000 /* Primary onboard */
+#define HPC_BASE_ADDRESS_1 0x1fb00000
+#define HPC_BASE_ADDRESS_2 0x1f980000
+#define HPC_BASE_ADDRESS_3 0x1f900000 /* NB: Never supported in h/w */
+
+/*
+ * HPC3 descriptor layout.
+ */
+struct hpc_dma_desc {
+ uint32_t hdd_bufptr; /* Physical address of buffer */
+ uint32_t hdd_ctl; /* Control flags and byte count */
+ uint32_t hdd_descptr; /* Physical address of next descr. */
+ uint32_t hdd_pad; /* Pad out to quadword alignment */
+};
+
+/*
+ * The hdd_bufptr and hdd_ctl fields are swapped between HPC1 and
+ * HPC3. These fields are referenced by macro for readability.
+ */
+#define hpc1_hdd_ctl hdd_bufptr
+#define hpc1_hdd_bufptr hdd_ctl
+#define hpc3_hdd_ctl hdd_ctl
+#define hpc3_hdd_bufptr hdd_bufptr
+
+/*
+ * Control flags
+ */
+#define HPC3_HDD_CTL_EOCHAIN 0x80000000 /* End of descriptor chain */
+#define HPC3_HDD_CTL_EOPACKET 0x40000000 /* Ethernet: end of packet */
+#define HPC3_HDD_CTL_INTR 0x20000000 /* Interrupt when finished */
+#define HPC3_HDD_CTL_XMITDONE 0x00008000 /* Ethernet transmit done */
+#define HPC3_HDD_CTL_OWN 0x00004000 /* CPU owns this frame */
+
+#define HPC3_HDD_CTL_BYTECNT(x) ((x) & 0x3fff) /* Byte count: for ethernet
+ * rcv channel also doubles as
+ * length of packet received
+ */
+
+/*
+ * HPC memory map, as offsets from HPC base
+ *
+ * XXXrkb: should each section be used as a base and have the specific
+ * registers offset from there??
+ *
+ * XXX: define register values as well as their offsets.
+ *
+ */
+#define HPC3_PBUS_DMAREGS 0x00000000 /* DMA registers for PBus */
+#define HPC3_PBUS_DMAREGS_SIZE 0x0000ffff /* channels 0 - 7 */
+
+#define HPC3_PBUS_CH0_BP 0x00000000 /* Chan 0 Buffer Ptr */
+#define HPC3_PBUS_CH0_DP 0x00000004 /* Chan 0 Descriptor Ptr */
+#define HPC3_PBUS_CH0_CTL 0x00001000 /* Chan 0 Control Register */
+
+#define HPC3_PBUS_CH1_BP 0x00002000 /* Chan 1 Buffer Ptr */
+#define HPC3_PBUS_CH1_DP 0x00002004 /* Chan 1 Descriptor Ptr */
+#define HPC3_PBUS_CH1_CTL 0x00003000 /* Chan 1 Control Register */
+
+#define HPC3_PBUS_CH2_BP 0x00004000 /* Chan 2 Buffer Ptr */
+#define HPC3_PBUS_CH2_DP 0x00004004 /* Chan 2 Descriptor Ptr */
+#define HPC3_PBUS_CH2_CTL 0x00005000 /* Chan 2 Control Register */
+
+#define HPC3_PBUS_CH3_BP 0x00006000 /* Chan 3 Buffer Ptr */
+#define HPC3_PBUS_CH3_DP 0x00006004 /* Chan 3 Descriptor Ptr */
+#define HPC3_PBUS_CH3_CTL 0x00007000 /* Chan 3 Control Register */
+
+#define HPC3_PBUS_CH4_BP 0x00008000 /* Chan 4 Buffer Ptr */
+#define HPC3_PBUS_CH4_DP 0x00008004 /* Chan 4 Descriptor Ptr */
+#define HPC3_PBUS_CH4_CTL 0x00009000 /* Chan 4 Control Register */
+
+#define HPC3_PBUS_CH5_BP 0x0000a000 /* Chan 5 Buffer Ptr */
+#define HPC3_PBUS_CH5_DP 0x0000a004 /* Chan 5 Descriptor Ptr */
+#define HPC3_PBUS_CH5_CTL 0x0000b000 /* Chan 5 Control Register */
+
+#define HPC3_PBUS_CH6_BP 0x0000c000 /* Chan 6 Buffer Ptr */
+#define HPC3_PBUS_CH6_DP 0x0000c004 /* Chan 6 Descriptor Ptr */
+#define HPC3_PBUS_CH6_CTL 0x0000d000 /* Chan 6 Control Register */
+
+#define HPC3_PBUS_CH7_BP 0x0000e000 /* Chan 7 Buffer Ptr */
+#define HPC3_PBUS_CH7_DP 0x0000e004 /* Chan 7 Descriptor Ptr */
+#define HPC3_PBUS_CH7_CTL 0x0000f000 /* Chan 7 Control Register */
+
+#define HPC3_SCSI0_REGS 0x00010000 /* SCSI channel 0 registers */
+#define HPC3_SCSI0_REGS_SIZE 0x00001fff
+
+#define HPC3_SCSI0_CBP 0x00000000 /* Current buffer ptr */
+#define HPC3_SCSI0_NDBP 0x00000004 /* Next descriptor ptr */
+
+#define HPC3_SCSI0_BC 0x00001000 /* DMA byte count & flags */
+#define HPC3_SCSI0_CTL 0x00001004 /* DMA control flags */
+#define HPC3_SCSI0_GIO 0x00001008 /* GIO DMA FIFO pointer */
+#define HPC3_SCSI0_DEV 0x0000100c /* Device DMA FIFO pointer */
+#define HPC3_SCSI0_DMACFG 0x00001010 /* DMA configuration */
+#define HPC3_SCSI0_PIOCFG 0x00001014 /* PIO configuration */
+
+#define HPC3_SCSI1_REGS 0x00012000 /* SCSI channel 1 registers */
+#define HPC3_SCSI1_REGS_SIZE 0x00001fff
+
+#define HPC3_SCSI1_CBP 0x00000000 /* Current buffer ptr */
+#define HPC3_SCSI1_NDBP 0x00000004 /* Next descriptor ptr */
+
+#define HPC3_SCSI1_BC 0x00001000 /* DMA byte count & flags */
+#define HPC3_SCSI1_CTL 0x00001004 /* DMA control flags */
+#define HPC3_SCSI1_GIO 0x00001008 /* GIO DMA FIFO pointer */
+#define HPC3_SCSI1_DEV 0x0000100c /* Device DMA FIFO pointer */
+#define HPC3_SCSI1_DMACFG 0x00001010 /* DMA configuration */
+#define HPC3_SCSI1_PIOCFG 0x00001014 /* PIO configuration */
+
+/* HPC3_SCSIx_CTL "SCSI control register" flags: */
+#define HPC3_SCSI_DMACTL_IRQ 0x01 /* IRQ asserted, dma done or parity */
+#define HPC3_SCSI_DMACTL_ENDIAN 0x02 /* DMA endian mode, 0=BE, 1=LE */
+#define HPC3_SCSI_DMACTL_DIR 0x04 /* DMA direction, 0=dev->mem, 1=mem->dev */
+#define HPC3_SCSI_DMACTL_FLUSH 0x08 /* Flush DMA FIFO's */
+#define HPC3_SCSI_DMACTL_ACTIVE 0x10 /* DMA channel is active */
+#define HPC3_SCSI_DMACTL_AMASK 0x20 /* DMA active inhibits PIO */
+#define HPC3_SCSI_DMACTL_RESET 0x40 /* Reset dma channel and ext. controller */
+#define HPC3_SCSI_DMACTL_PERR 0x80 /* Parity error: interface to controller */
+
+/* HPC_PBUS_CHx_CTL read: */
+#define HPC3_PBUS_DMACTL_IRQ 0x01 /* IRQ asserted, DMA done */
+#define HPC3_PBUS_DMACTL_ISACT 0x02 /* DMA channel is active */
+
+/* HPC_PBUS_CHx_CTL write: */
+#define HPC3_PBUS_DMACTL_ENDIAN 0x02 /* DMA endianness, 0=BE 1=LE */
+#define HPC3_PBUS_DMACTL_RECEIVE 0x04 /* DMA direction, 1=dev->mem, 0=mem->dev*/
+#define HPC3_PBUS_DMACTL_FLUSH 0x08 /* Flush DMA FIFO */
+#define HPC3_PBUS_DMACTL_ACT 0x10 /* Activate DMA channel */
+#define HPC3_PBUS_DMACTL_ACT_LD 0x20 /* Load enable for ACT */
+#define HPC3_PBUS_DMACTL_RT 0x40 /* Enable real time GIO service for DMA */
+#define HPC3_PBUS_DMACTL_HIGHWATER_SHIFT 8
+#define HPC3_PBUS_DMACTL_FIFOBEG_SHIFT 16
+#define HPC3_PBUS_DMACTL_FIFOEND_SHIFT 24
+
+#define HPC3_ENET_REGS 0x00014000 /* Ethernet registers */
+#define HPC3_ENET_REGS_SIZE 0x00003fff
+
+#define HPC3_ENETR_CBP 0x00000000 /* Recv: Current buffer ptr */
+#define HPC3_ENETR_NDBP 0x00000004 /* Recv: Next descriptor ptr */
+
+#define HPC3_ENETR_BC 0x00001000 /* Recv: DMA byte cnt/flags */
+#define HPC3_ENETR_CTL 0x00001004 /* Recv: DMA control flags */
+
+#define HPC3_ENETR_CTL_STAT_5_0 0x003f /* Seeq irq status: bits 0-5 */
+#define HPC3_ENETR_CTL_STAT_6 0x0040 /* Irq status: late_rxdc */
+#define HPC3_ENETR_CTL_STAT_7 0x0080 /* Irq status: old/new bit */
+#define HPC3_ENETR_CTL_LENDIAN 0x0100 /* DMA channel endian mode */
+#define HPC3_ENETR_CTL_ACTIVE 0x0200 /* DMA channel active? */
+#define HPC3_ENETR_CTL_ACTIVE_MSK 0x0400 /* DMA channel active? */
+#define HPC3_ENETR_CTL_RBO 0x0800 /* Recv buffer overflow */
+
+#define HPC3_ENETR_GIO 0x00001008 /* Recv: GIO DMA FIFO ptr */
+#define HPC3_ENETR_DEV 0x0000100c /* Recv: Device DMA FIFO ptr */
+#define HPC3_ENETR_RESET 0x00001014 /* Recv: Ethernet chip reset */
+
+#define HPC3_ENETR_RESET_CH 0x0001 /* Reset controller & chan */
+#define HPC3_ENETR_RESET_CLRINT 0x0002 /* Clear channel interrupt */
+#define HPC3_ENETR_RESET_LOOPBK 0x0004 /* External loopback enable */
+#define HPC3_ENETR_RESET_CLRRBO 0x0008 /* Clear RBO condition (??) */
+
+#define HPC3_ENETR_DMACFG 0x00001018 /* Recv: DMA configuration */
+
+#define HPC3_ENETR_DMACFG_D1(_x) (((_x) << 0) & 0x000f) /* D1 gio_clk cycles */
+#define HPC3_ENETR_DMACFG_D2(_x) (((_x) << 4) & 0x00f0) /* D2 gio_clk cycles */
+#define HPC3_ENETR_DMACFG_D3(_x) (((_x) << 8) & 0x0f00) /* D3 gio_clk cycles */
+#define HPC3_ENETR_DMACFG_WRCTL 0x01000 /* Enable IPG write */
+
+/*
+ * The following three bits work around bugs in the Seeq 8003; if you
+ * don't set them, the Seeq gets wonky pretty often.
+ */
+#define HPC3_ENETR_DMACFG_FIX_RXDC 0x02000 /* Clear EOP bits on RXDC */
+#define HPC3_ENETR_DMACFG_FIX_EOP 0x04000 /* Enable rxintr timeout */
+#define HPC3_ENETR_DMACFG_FIX_INTR 0x08000 /* Enable EOP timeout */
+#define HPC3_ENETR_DMACFG_TIMEOUT 0x30000 /* Timeout value for above two*/
+
+#define HPC3_ENETR_PIOCFG 0x0000101c /* Recv: PIO configuration */
+
+#define HPC3_ENETR_PIOCFG_P1(_x) (((_x) << 0) & 0x000f) /* P1 gio_clk cycles */
+#define HPC3_ENETR_PIOCFG_P2(_x) (((_x) << 4) & 0x00f0) /* P2 gio_clk cycles */
+#define HPC3_ENETR_PIOCFG_P3(_x) (((_x) << 8) & 0x0f00) /* P3 gio_clk cycles */
+
+#define HPC3_ENETX_CBP 0x00002000 /* Xmit: Current buffer ptr */
+#define HPC3_ENETX_NDBP 0x00002004 /* Xmit: Next descriptor ptr */
+
+#define HPC3_ENETX_BC 0x00003000 /* Xmit: DMA byte cnt/flags */
+#define HPC3_ENETX_CTL 0x00003004 /* Xmit: DMA control flags */
+
+#define HPC3_ENETX_CTL_STAT_5_0 0x003f /* Seeq irq status: bits 0-5 */
+#define HPC3_ENETX_CTL_STAT_6 0x0040 /* Irq status: late_rxdc */
+#define HPC3_ENETX_CTL_STAT_7 0x0080 /* Irq status: old/new bit */
+#define HPC3_ENETX_CTL_LENDIAN 0x0100 /* DMA channel endian mode */
+#define HPC3_ENETX_CTL_ACTIVE 0x0200 /* DMA channel active? */
+#define HPC3_ENETX_CTL_ACTIVE_MSK 0x0400 /* DMA channel active? */
+#define HPC3_ENETX_CTL_RBO 0x0800 /* Recv buffer overflow */
+
+#define HPC3_ENETX_GIO 0x00003008 /* Xmit: GIO DMA FIFO ptr */
+#define HPC3_ENETX_DEV 0x0000300c /* Xmit: Device DMA FIFO ptr */
+
+#define HPC3_PBUS_FIFO 0x00020000 /* PBus DMA FIFO */
+#define HPC3_PBUS_FIFO_SIZE 0x00007fff /* PBus DMA FIFO size */
+
+#define HPC3_SCSI0_FIFO 0x00028000 /* SCSI0 DMA FIFO */
+#define HPC3_SCSI0_FIFO_SIZE 0x00001fff /* SCSI0 DMA FIFO size */
+
+#define HPC3_SCSI1_FIFO 0x0002a000 /* SCSI1 DMA FIFO */
+#define HPC3_SCSI1_FIFO_SIZE 0x00001fff /* SCSI1 DMA FIFO size */
+
+#define HPC3_ENETR_FIFO 0x0002c000 /* Ether recv DMA FIFO */
+#define HPC3_ENETR_FIFO_SIZE 0x00001fff /* Ether recv DMA FIFO size */
+
+#define HPC3_ENETX_FIFO 0x0002e000 /* Ether xmit DMA FIFO */
+#define HPC3_ENETX_FIFO_SIZE 0x00001fff /* Ether xmit DMA FIFO size */
+
+/*
+ * HPCBUG: The interrupt status is split amongst two registers, and they're
+ * not even consecutive in the HPC address space. This is documented as a
+ * bug by SGI.
+ */
+#define HPC3_INTRSTAT_40 0x00030000 /* Interrupt stat, bits 4:0 */
+#define HPC3_INTRSTAT_95 0x0003000c /* Interrupt stat, bits 9:5 */
+
+#define HPC3_GIO_MISC 0x00030004 /* GIO64 misc register */
+
+#define HPC3_EEPROM_DATA 0x0003000b /* Serial EEPROM data reg. */
+ /* (byte) */
+
+#define HPC3_GIO_BUSERR 0x00030010 /* GIO64 bus error intr stat */
+
+#define HPC3_SCSI0_DEVREGS 0x00044000 /* SCSI channel 0 chip regs */
+#define HPC3_SCSI1_DEVREGS 0x0004c000 /* SCSI channel 1 chip regs */
+
+#define HPC3_ENET_DEVREGS 0x00054000 /* Ethernet chip registers */
+#define HPC3_ENET_DEVREGS_SIZE 0x000004ff /* Size of chip registers */
+
+#define HPC3_PBUS_DEVREGS 0x00054000 /* PBus PIO chip registers */
+#define HPC3_PBUS_DEVREGS_SIZE 0x000003ff /* PBus PIO chip registers */
+
+#define HPC3_PBUS_CH0_DEVREGS 0x00058000 /* PBus ch. 0 chip registers */
+#define HPC3_PBUS_CH0_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH1_DEVREGS 0x00058400 /* PBus ch. 1 chip registers */
+#define HPC3_PBUS_CH1_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH2_DEVREGS 0x00058800 /* PBus ch. 2 chip registers */
+#define HPC3_PBUS_CH2_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH3_DEVREGS 0x00058c00 /* PBus ch. 3 chip registers */
+#define HPC3_PBUS_CH3_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH4_DEVREGS 0x00059000 /* PBus ch. 4 chip registers */
+#define HPC3_PBUS_CH4_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH5_DEVREGS 0x00059400 /* PBus ch. 5 chip registers */
+#define HPC3_PBUS_CH5_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH6_DEVREGS 0x00059800 /* PBus ch. 6 chip registers */
+#define HPC3_PBUS_CH6_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH7_DEVREGS 0x00059c00 /* PBus ch. 7 chip registers */
+#define HPC3_PBUS_CH7_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS 0x0005a000 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS 0x0005a400 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS_2 0x0005a800 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_2_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS_2 0x0005ac00 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_2_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS_3 0x0005b000 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_3_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS_3 0x0005b400 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_3_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS_4 0x0005b800 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_4_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS_4 0x0005bc00 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_4_SIZE 0x03ff
+
+#define HPC3_PBUS_CFGDMA_REGS 0x0005c000 /* PBus DMA config registers */
+#define HPC3_PBUS_CFGDMA_REGS_SIZE 0x0fff
+
+#define HPC3_PBUS_CH0_CFGDMA 0x0005c000 /* PBus Ch. 0 DMA config */
+#define HPC3_PBUS_CH0_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH1_CFGDMA 0x0005c200 /* PBus Ch. 1 DMA config */
+#define HPC3_PBUS_CH1_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH2_CFGDMA 0x0005c400 /* PBus Ch. 2 DMA config */
+#define HPC3_PBUS_CH2_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH3_CFGDMA 0x0005c600 /* PBus Ch. 3 DMA config */
+#define HPC3_PBUS_CH3_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH4_CFGDMA 0x0005c800 /* PBus Ch. 4 DMA config */
+#define HPC3_PBUS_CH4_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH5_CFGDMA 0x0005ca00 /* PBus Ch. 5 DMA config */
+#define HPC3_PBUS_CH5_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH6_CFGDMA 0x0005cc00 /* PBus Ch. 6 DMA config */
+#define HPC3_PBUS_CH6_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH7_CFGDMA 0x0005ce00 /* PBus Ch. 7 DMA config */
+#define HPC3_PBUS_CH7_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CFGPIO_REGS 0x0005d000 /* PBus PIO config registers */
+#define HPC3_PBUS_CFGPIO_REGS_SIZE 0x0fff
+
+#define HPC3_PBUS_CH0_CFGPIO 0x0005d000 /* PBus Ch. 0 PIO config */
+#define HPC3_PBUS_CH1_CFGPIO 0x0005d100 /* PBus Ch. 1 PIO config */
+#define HPC3_PBUS_CH2_CFGPIO 0x0005d200 /* PBus Ch. 2 PIO config */
+#define HPC3_PBUS_CH3_CFGPIO 0x0005d300 /* PBus Ch. 3 PIO config */
+#define HPC3_PBUS_CH4_CFGPIO 0x0005d400 /* PBus Ch. 4 PIO config */
+#define HPC3_PBUS_CH5_CFGPIO 0x0005d500 /* PBus Ch. 5 PIO config */
+#define HPC3_PBUS_CH6_CFGPIO 0x0005d600 /* PBus Ch. 6 PIO config */
+#define HPC3_PBUS_CH7_CFGPIO 0x0005d700 /* PBus Ch. 7 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO 0x0005d800 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO 0x0005d900 /* PBus Ch. 9 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO_2 0x0005da00 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO_2 0x0005db00 /* PBus Ch. 9 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO_3 0x0005dc00 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO_3 0x0005dd00 /* PBus Ch. 9 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO_4 0x0005de00 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO_4 0x0005df00 /* PBus Ch. 9 PIO config */
+
+#define HPC3_PBUS_PROM_WE 0x0005e000 /* PBus boot-prom write
+ * enable register
+ */
+
+#define HPC3_PBUS_PROM_SWAP 0x0005e800 /* PBus boot-prom chip-select
+ * swap register
+ */
+
+#define HPC3_PBUS_GEN_OUT 0x0005f000 /* PBus general-purpose output
+ * register
+ */
+
+#define HPC3_PBUS_BBRAM 0x00060000 /* PBus battery-backed RAM
+ * external registers
+ */
+
+/* HPC1/HPC1.5 differs from HPC3 in several details. */
+
+#define HPC1_HDD_CTL_EOCHAIN 0x80000000 /* End of descriptor chain */
+#define HPC1_HDD_CTL_EOPACKET 0x80000000 /* Ethernet: end of packet */
+#define HPC1_HDD_CTL_INTR 0x00008000 /* Interrupt when finished */
+#define HPC1_HDD_CTL_OWN 0x40000000 /* CPU owns this frame */
+#define HPC1_HDD_CTL_BYTECNT(x) ((x) & 0x1fff) /* Byte count: for ethernet */
+#define HPC1_BIGENDIAN 0x000000c0 /* Endianness:5 revision:2 */
+#define HPC1_REVSHIFT 0x00000006 /* Revision rshft */
+#define HPC1_REVMASK 0x00000003 /* Revision mask */
+#define HPC1_REV15 0x00000001 /* HPC Revision 1.5 */
+#define HPC1_SCSI0_REGS 0x00000088
+#define HPC1_SCSI0_REGS_SIZE 0x00000018
+#define HPC1_SCSI0_CBP 0x00000004 /* Current buffer ptr */
+#define HPC1_SCSI0_NDBP 0x00000008 /* Next descriptor ptr */
+#define HPC1_SCSI0_BC 0x00000000 /* DMA byte count & flags */
+#define HPC1_SCSI0_CTL 0x0000000c /* DMA control flags */
+#define HPC1_SCSI0_DEV 0x00000014 /* Device DMA FIFO pointer */
+#define HPC1_SCSI0_DMACFG 0x00000010 /* DMA configuration */
+#define HPC1_SCSI0_GIO 0x00001008 /* GIO DMA FIFO pointer */
+#define HPC1_SCSI0_PIOCFG 0x00001014 /* PIO configuration */
+#define HPC1_SCSI_DMACTL_RESET 0x01 /* Reset dma channel and ext. controller */
+#define HPC1_SCSI_DMACTL_FLUSH 0x02 /* Flush DMA FIFO's */
+#define HPC1_SCSI_DMACTL_DIR 0x10 /* DMA direction: 1=dev->mem, 0=mem->dev */
+#define HPC1_SCSI_DMACTL_ACTIVE 0x80 /* DMA channel is active */
+#define HPC1_ENET_REGS 0x00000000 /* Ethernet registers */
+#define HPC1_ENET_REGS_SIZE 0x00000100
+#define HPC1_ENET_INTDELAY 0x0000002c /* Interrupt Delay Count */
+#define HPC1_ENET_INTDELAY_OFF 0x01000000 /* Disable Interrupt Delay */
+#define HPC1_ENETR_CBP 0x00000054 /* Recv: Current buffer ptr */
+#define HPC1_ENETR_NDBP 0x00000050 /* Recv: Next descriptor ptr */
+#define HPC1_ENETR_BC 0x00000048 /* Recv: DMA byte cnt/flags */
+#define HPC1_ENETR_CTL 0x00000038 /* Recv: DMA control flags */
+#define HPC1_ENETR_CTL_ACTIVE 0x00004000 /* DMA channel active? */
+#define HPC1_ENETR_RESET 0x0000003c /* Recv: Ethernet chip reset */
+#define HPC1_ENETR_RESET_CH 0x0001 /* Reset controller & chan */
+#define HPC1_ENETR_RESET_CLRINT 0x0002 /* Clear channel interrupt */
+#define HPC1_ENETR_RESET_LOOPBK 0x0004 /* External loopback enable */
+#define HPC1_ENETR_RESET_CLRRBO 0x0008 /* Clear RBO condition (??) */
+#define HPC1_ENETX_CBP 0x00000020 /* Xmit: Current buffer ptr */
+#define HPC1_ENETX_NDBP 0x00000010 /* Xmit: Next descriptor ptr */
+#define HPC1_ENETX_CFXBP 0x00000024 /* Xmit: Current first buf */
+#define HPC1_ENETX_PFXBP 0x00000028 /* Xmit: Prev. first buf */
+#define HPC1_ENETX_BC 0x00000014 /* Xmit: DMA byte cnt/flags */
+#define HPC1_ENETX_CTL 0x00000034 /* Xmit: DMA control flags */
+#define HPC1_ENETX_CTL_ACTIVE 0x00400000
+#define HPC1_ENETR_FIFO 0x0002c000 /* Ether recv DMA FIFO */
+#define HPC1_ENETR_FIFO_SIZE 0x00001fff /* Ether recv DMA FIFO size */
+#define HPC1_ENETX_FIFO 0x0002e000 /* Ether xmit DMA FIFO */
+#define HPC1_ENETX_FIFO_SIZE 0x00001fff /* Ether xmit DMA FIFO size */
+#define HPC1_SCSI0_DEVREGS 0x0000011f /* (actually 122) */
+#define HPC1_ENET_DEVREGS 0x00000100 /* Ethernet chip registers */
+#define HPC1_ENET_DEVREGS_SIZE 0x00000020 /* Size of chip registers */
+#define HPC1_PBUS_BBRAM 0x00000e00 /* PBus battery-backed RAM */
+#define HPC1_LPT_REGS 0x000000a8 /* LPT HPC Registers */
+#define HPC1_LPT_REGS_SIZE 0x00000018
+#define HPC1_LPT_BC 0x00000000 /* Byte Count */
+#define HPC1_LPT_CBP 0x00000004 /* Current Buffer Ptr */
+#define HPC1_LPT_NDBP 0x00000008 /* Next Buffer Ptr */
+#define HPC1_LPT_CTL 0x0000000c /* DMA Control Flags */
+#define HPC1_LPT_DEV 0x00000010 /* DMA Fifo Ptr */
+#define HPC1_LPT_DMACFG 0x00000014 /* DMA Configuration */
+#define HPC1_LPT_DEVREGS 0x00000132 /* Ext. Parallel Registers */
+#define HPC1_LPT_DEVREGS_SIZE 0x00000001 /* Size of External Registers */
+
+/* AUX regs on the primary HPC */
+#define HPC1_AUX_REGS 0x000001bf /* EEPROM/LED Control (byte) */
+#define HPC1_AUX_CONSLED 0x01 /* Console LED */
diff --git a/sys/arch/sgi/hpc/hpcvar.h b/sys/arch/sgi/hpc/hpcvar.h
new file mode 100644
index 00000000000..c79f284ff87
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcvar.h
@@ -0,0 +1,109 @@
+/* $OpenBSD: hpcvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcvar.h,v 1.12 2011/01/25 12:21:04 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * 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. 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.
+ */
+
+#define HPCDEV_IP20 (1U << 1) /* Indigo R4k */
+#define HPCDEV_IP22 (1U << 2) /* Indigo2 */
+#define HPCDEV_IP24 (1U << 3) /* Indy */
+
+/* HPC 1.5/3 differ a bit, thus we need an abstraction layer */
+
+struct hpc_values {
+ int revision;
+ uint32_t scsi0_regs;
+ uint32_t scsi0_regs_size;
+ uint32_t scsi0_cbp;
+ uint32_t scsi0_ndbp;
+ uint32_t scsi0_bc;
+ uint32_t scsi0_ctl;
+ uint32_t scsi0_gio;
+ uint32_t scsi0_dev;
+ uint32_t scsi0_dmacfg;
+ uint32_t scsi0_piocfg;
+ uint32_t scsi1_regs;
+ uint32_t scsi1_regs_size;
+ uint32_t scsi1_cbp;
+ uint32_t scsi1_ndbp;
+ uint32_t scsi1_bc;
+ uint32_t scsi1_ctl;
+ uint32_t scsi1_gio;
+ uint32_t scsi1_dev;
+ uint32_t scsi1_dmacfg;
+ uint32_t scsi1_piocfg;
+ uint32_t enet_regs;
+ uint32_t enet_regs_size;
+ uint32_t enet_intdelay;
+ uint32_t enet_intdelayval;
+ uint32_t enetr_cbp;
+ uint32_t enetr_ndbp;
+ uint32_t enetr_bc;
+ uint32_t enetr_ctl;
+ uint32_t enetr_ctl_active;
+ uint32_t enetr_reset;
+ uint32_t enetr_dmacfg;
+ uint32_t enetr_piocfg;
+ uint32_t enetx_cbp;
+ uint32_t enetx_ndbp;
+ uint32_t enetx_bc;
+ uint32_t enetx_ctl;
+ uint32_t enetx_ctl_active;
+ uint32_t enetx_dev;
+ uint32_t enetr_fifo;
+ uint32_t enetr_fifo_size;
+ uint32_t enetx_fifo;
+ uint32_t enetx_fifo_size;
+ uint32_t enet_dma_boundary;
+ uint32_t enet_devregs;
+ uint32_t enet_devregs_size;
+ uint32_t pbus_fifo;
+ uint32_t pbus_fifo_size;
+ uint32_t pbus_bbram;
+ uint32_t scsi_dma_segs;
+ uint32_t scsi_dma_segs_size;
+ uint32_t scsi_dma_datain_cmd;
+ uint32_t scsi_dma_dataout_cmd;
+ uint32_t scsi_dmactl_flush;
+ uint32_t scsi_dmactl_active;
+ uint32_t scsi_dmactl_reset;
+};
+
+struct hpc_attach_args {
+ const char *ha_name; /* name of device */
+ bus_addr_t ha_devoff; /* offset of device */
+ bus_addr_t ha_dmaoff; /* offset of DMA regs */
+ int ha_irq; /* interrupt line */
+
+ bus_space_tag_t ha_st; /* HPC space tag */
+ bus_space_handle_t ha_sh; /* HPC space handle XXX */
+ bus_dma_tag_t ha_dmat; /* HPC DMA tag */
+
+ struct hpc_values *hpc_regs; /* HPC register definitions */
+
+ uint8_t hpc_eeprom[256];/* HPC eeprom contents */
+};
diff --git a/sys/arch/sgi/hpc/if_sq.c b/sys/arch/sgi/hpc/if_sq.c
new file mode 100644
index 00000000000..44521062c38
--- /dev/null
+++ b/sys/arch/sgi/hpc/if_sq.c
@@ -0,0 +1,1348 @@
+/* $OpenBSD: if_sq.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: if_sq.c,v 1.42 2011/07/01 18:53:47 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions of this code are derived from software contributed to The
+ * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * 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. 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.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+#include <sys/mbuf.h>
+#include <sys/pool.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <netinet/if_ether.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h> /* guarded_read_4 */
+#include <machine/intr.h>
+#include <mips64/arcbios.h> /* bios_enaddr */
+#include <sgi/localbus/intvar.h>
+
+#include <dev/ic/seeq8003reg.h>
+
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/if_sqvar.h>
+
+/*
+ * Short TODO list:
+ * (1) Do counters for bad-RX packets.
+ * (2) Allow multi-segment transmits, instead of copying to a single,
+ * contiguous mbuf.
+ * (3) Verify sq_stop() turns off enough stuff; I was still getting
+ * seeq interrupts after sq_stop().
+ * (4) Implement EDLC modes: especially packet auto-pad and simplex
+ * mode.
+ * (5) Should the driver filter out its own transmissions in non-EDLC
+ * mode?
+ * (6) Multicast support -- multicast filter, address management, ...
+ * (7) Deal with RB0 (recv buffer overflow) on reception. Will need
+ * to figure out if RB0 is read-only as stated in one spot in the
+ * HPC spec or read-write (ie, is the 'write a one to clear it')
+ * the correct thing?
+ */
+
+#if defined(SQ_DEBUG)
+int sq_debug = 0;
+#define SQ_DPRINTF(x) do { if (sq_debug) printf x; } while (0)
+#else
+#define SQ_DPRINTF(x) do { } while (0)
+#endif
+
+int sq_match(struct device *, void *, void *);
+void sq_attach(struct device *, struct device *, void *);
+int sq_init(struct ifnet *);
+void sq_start(struct ifnet *);
+void sq_stop(struct ifnet *);
+void sq_watchdog(struct ifnet *);
+int sq_ioctl(struct ifnet *, u_long, caddr_t);
+
+void sq_set_filter(struct sq_softc *);
+int sq_intr(void *);
+void sq_rxintr(struct sq_softc *);
+void sq_txintr(struct sq_softc *);
+void sq_txring_hpc1(struct sq_softc *);
+void sq_txring_hpc3(struct sq_softc *);
+void sq_reset(struct sq_softc *);
+int sq_add_rxbuf(struct sq_softc *, int);
+#ifdef SQ_DEBUG
+void sq_trace_dump(struct sq_softc *);
+#endif
+
+const struct cfattach sq_ca = {
+ sizeof(struct sq_softc), sq_match, sq_attach
+};
+
+struct cfdriver sq_cd = {
+ NULL, "sq", DV_IFNET
+};
+
+/* XXX these values should be moved to <net/if_ether.h> ? */
+#define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
+
+#define sq_seeq_read(sc, off) \
+ bus_space_read_1(sc->sc_regt, sc->sc_regh, ((off) << 2) | 3)
+#define sq_seeq_write(sc, off, val) \
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, ((off) << 2) | 3, val)
+
+#define sq_hpc_read(sc, off) \
+ bus_space_read_4(sc->sc_hpct, sc->sc_hpch, off)
+#define sq_hpc_write(sc, off, val) \
+ bus_space_write_4(sc->sc_hpct, sc->sc_hpch, off, val)
+
+/* MAC address offset for non-onboard implementations */
+#define SQ_HPC_EEPROM_ENADDR 250
+
+#define SGI_OUI_0 0x08
+#define SGI_OUI_1 0x00
+#define SGI_OUI_2 0x69
+
+int
+sq_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *ha = aux;
+ struct cfdata *cf = vcf;
+ vaddr_t reset, txstat;
+ uint32_t dummy;
+
+ if (strcmp(ha->ha_name, cf->cf_driver->cd_name) != 0)
+ return 0;
+
+ reset = PHYS_TO_XKPHYS(ha->ha_sh + ha->ha_dmaoff +
+ ha->hpc_regs->enetr_reset, CCA_NC);
+ txstat = PHYS_TO_XKPHYS(ha->ha_sh + ha->ha_devoff + (SEEQ_TXSTAT << 2),
+ CCA_NC);
+
+ if (guarded_read_4(reset, &dummy) != 0)
+ return 0;
+
+ *(volatile uint32_t *)reset = 0x1;
+ delay(20);
+ *(volatile uint32_t *)reset = 0x0;
+
+ if (guarded_read_4(txstat, &dummy) != 0)
+ return 0;
+
+ if ((*(volatile uint32_t *)txstat & 0xff) != TXSTAT_OLDNEW)
+ return 0;
+
+ return 1;
+}
+
+void
+sq_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct sq_softc *sc = (struct sq_softc *)self;
+ struct hpc_attach_args *haa = aux;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ int i, rc;
+
+ sc->sc_hpct = haa->ha_st;
+ sc->hpc_regs = haa->hpc_regs; /* HPC register definitions */
+
+ if ((rc = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_dmaoff, sc->hpc_regs->enet_regs_size,
+ &sc->sc_hpch)) != 0) {
+ printf(": can't HPC DMA registers, error = %d\n", rc);
+ goto fail_0;
+ }
+
+ sc->sc_regt = haa->ha_st;
+ if ((rc = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff, sc->hpc_regs->enet_devregs_size,
+ &sc->sc_regh)) != 0) {
+ printf(": can't map Seeq registers, error = %d\n", rc);
+ goto fail_0;
+ }
+
+ sc->sc_dmat = haa->ha_dmat;
+
+ if ((rc = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct sq_control),
+ sc->hpc_regs->enet_dma_boundary,
+ sc->hpc_regs->enet_dma_boundary, &sc->sc_cdseg, 1,
+ &sc->sc_ncdseg, BUS_DMA_NOWAIT)) != 0) {
+ printf(": unable to allocate control data, error = %d\n", rc);
+ goto fail_0;
+ }
+
+ if ((rc = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg,
+ sizeof(struct sq_control), (caddr_t *)&sc->sc_control,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ printf(": unable to map control data, error = %d\n", rc);
+ goto fail_1;
+ }
+
+ if ((rc = bus_dmamap_create(sc->sc_dmat,
+ sizeof(struct sq_control), 1, sizeof(struct sq_control),
+ sc->hpc_regs->enet_dma_boundary, BUS_DMA_NOWAIT,
+ &sc->sc_cdmap)) != 0) {
+ printf(": unable to create DMA map for control data, error "
+ "= %d\n", rc);
+ goto fail_2;
+ }
+
+ if ((rc = bus_dmamap_load(sc->sc_dmat, sc->sc_cdmap,
+ sc->sc_control, sizeof(struct sq_control), NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf(": unable to load DMA map for control data, error "
+ "= %d\n", rc);
+ goto fail_3;
+ }
+
+ memset(sc->sc_control, 0, sizeof(struct sq_control));
+
+ /* Create transmit buffer DMA maps */
+ for (i = 0; i < SQ_NTXDESC; i++) {
+ if ((rc = bus_dmamap_create(sc->sc_dmat,
+ MCLBYTES, 1, MCLBYTES, 0,
+ BUS_DMA_NOWAIT, &sc->sc_txmap[i])) != 0) {
+ printf(": unable to create tx DMA map %d, error = %d\n",
+ i, rc);
+ goto fail_4;
+ }
+ }
+
+ /* Create receive buffer DMA maps */
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if ((rc = bus_dmamap_create(sc->sc_dmat,
+ MCLBYTES, 1, MCLBYTES, 0,
+ BUS_DMA_NOWAIT, &sc->sc_rxmap[i])) != 0) {
+ printf(": unable to create rx DMA map %d, error = %d\n",
+ i, rc);
+ goto fail_5;
+ }
+ }
+
+ /* Pre-allocate the receive buffers. */
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if ((rc = sq_add_rxbuf(sc, i)) != 0) {
+ printf(": unable to allocate or map rx buffer %d\n,"
+ " error = %d\n", i, rc);
+ goto fail_6;
+ }
+ }
+
+ bcopy(&haa->hpc_eeprom[SQ_HPC_EEPROM_ENADDR], sc->sc_ac.ac_enaddr,
+ ETHER_ADDR_LEN);
+
+ /*
+ * If our mac address is bogus, obtain it from ARCBIOS. This will
+ * be true of the onboard HPC3 on IP22, since there is no eeprom,
+ * but rather the DS1386 RTC's battery-backed ram is used.
+ */
+ if (sc->sc_ac.ac_enaddr[0] != SGI_OUI_0 ||
+ sc->sc_ac.ac_enaddr[1] != SGI_OUI_1 ||
+ sc->sc_ac.ac_enaddr[2] != SGI_OUI_2)
+ enaddr_aton(bios_enaddr, sc->sc_ac.ac_enaddr);
+
+ if ((int2_intr_establish(haa->ha_irq, IPL_NET, sq_intr, sc,
+ self->dv_xname)) == NULL) {
+ printf(": unable to establish interrupt!\n");
+ goto fail_6;
+ }
+
+ /* Reset the chip to a known state. */
+ sq_reset(sc);
+
+ /*
+ * Determine if we're an 8003 or 80c03 by setting the first
+ * MAC address register to non-zero, and then reading it back.
+ * If it's zero, we have an 80c03, because we will have read
+ * the TxCollLSB register.
+ */
+ sq_seeq_write(sc, SEEQ_TXCOLLS0, 0xa5);
+ if (sq_seeq_read(sc, SEEQ_TXCOLLS0) == 0)
+ sc->sc_type = SQ_TYPE_80C03;
+ else
+ sc->sc_type = SQ_TYPE_8003;
+ sq_seeq_write(sc, SEEQ_TXCOLLS0, 0x00);
+
+ printf(": Seeq %s, address %s\n",
+ sc->sc_type == SQ_TYPE_80C03 ? "80c03" : "8003",
+ ether_sprintf(sc->sc_ac.ac_enaddr));
+
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_start = sq_start;
+ ifp->if_ioctl = sq_ioctl;
+ ifp->if_watchdog = sq_watchdog;
+ ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_MULTICAST;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ if_attach(ifp);
+ IFQ_SET_MAXLEN(&ifp->if_snd, SQ_NTXDESC - 1);
+ ether_ifattach(ifp);
+
+ /* Done! */
+ return;
+
+ /*
+ * Free any resources we've allocated during the failed attach
+ * attempt. Do this in reverse order and fall through.
+ */
+ fail_6:
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if (sc->sc_rxmbuf[i] != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[i]);
+ m_freem(sc->sc_rxmbuf[i]);
+ }
+ }
+ fail_5:
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if (sc->sc_rxmap[i] != NULL)
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_rxmap[i]);
+ }
+ fail_4:
+ for (i = 0; i < SQ_NTXDESC; i++) {
+ if (sc->sc_txmap[i] != NULL)
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_txmap[i]);
+ }
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_cdmap);
+ fail_3:
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_cdmap);
+ fail_2:
+ bus_dmamem_unmap(sc->sc_dmat,
+ (void *)sc->sc_control, sizeof(struct sq_control));
+ fail_1:
+ bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg);
+ fail_0:
+ return;
+}
+
+/* Set up data to get the interface up and running. */
+int
+sq_init(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ int i;
+
+ /* Cancel any in-progress I/O */
+ sq_stop(ifp);
+
+ sc->sc_nextrx = 0;
+
+ sc->sc_nfreetx = SQ_NTXDESC;
+ sc->sc_nexttx = sc->sc_prevtx = 0;
+
+ SQ_TRACE(SQ_RESET, sc, 0, 0);
+
+ /* Set into 8003 mode, bank 0 to program ethernet address */
+ sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_BANK0);
+
+ /* Now write the address */
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ sq_seeq_write(sc, i, sc->sc_ac.ac_enaddr[i]);
+
+ sc->sc_rxcmd =
+ RXCMD_IE_CRC |
+ RXCMD_IE_DRIB |
+ RXCMD_IE_SHORT |
+ RXCMD_IE_END |
+ RXCMD_IE_GOOD;
+
+ /*
+ * Set the receive filter -- this will add some bits to the
+ * prototype RXCMD register. Do this before setting the
+ * transmit config register, since we might need to switch
+ * banks.
+ */
+ sq_set_filter(sc);
+
+ /* Set up Seeq transmit command register */
+ sq_seeq_write(sc, SEEQ_TXCMD,
+ TXCMD_IE_UFLOW | TXCMD_IE_COLL | TXCMD_IE_16COLL | TXCMD_IE_GOOD);
+
+ /* Now write the receive command register. */
+ sq_seeq_write(sc, SEEQ_RXCMD, sc->sc_rxcmd);
+
+ /*
+ * Set up HPC ethernet PIO and DMA configurations.
+ *
+ * The PROM appears to do most of this for the onboard HPC3, but
+ * not for the Challenge S's IOPLUS chip. We copy how the onboard
+ * chip is configured and assume that it's correct for both.
+ */
+ if (sc->hpc_regs->revision == 3) {
+ uint32_t dmareg, pioreg;
+
+ pioreg =
+ HPC3_ENETR_PIOCFG_P1(1) |
+ HPC3_ENETR_PIOCFG_P2(6) |
+ HPC3_ENETR_PIOCFG_P3(1);
+
+ dmareg =
+ HPC3_ENETR_DMACFG_D1(6) |
+ HPC3_ENETR_DMACFG_D2(2) |
+ HPC3_ENETR_DMACFG_D3(0) |
+ HPC3_ENETR_DMACFG_FIX_RXDC |
+ HPC3_ENETR_DMACFG_FIX_INTR |
+ HPC3_ENETR_DMACFG_FIX_EOP |
+ HPC3_ENETR_DMACFG_TIMEOUT;
+
+ sq_hpc_write(sc, HPC3_ENETR_PIOCFG, pioreg);
+ sq_hpc_write(sc, HPC3_ENETR_DMACFG, dmareg);
+ }
+
+ /* Pass the start of the receive ring to the HPC */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp, SQ_CDRXADDR(sc, 0));
+
+ /* And turn on the HPC ethernet receive channel */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ctl,
+ sc->hpc_regs->enetr_ctl_active);
+
+ /*
+ * Turn off delayed receive interrupts on HPC1.
+ * (see Hollywood HPC Specification 2.1.4.3)
+ */
+ if (sc->hpc_regs->revision != 3)
+ sq_hpc_write(sc, HPC1_ENET_INTDELAY, HPC1_ENET_INTDELAY_OFF);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sq_start(ifp);
+
+ return 0;
+}
+
+void
+sq_set_filter(struct sq_softc *sc)
+{
+ struct arpcom *ac = &sc->sc_ac;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ /*
+ * Check for promiscuous mode. Also implies
+ * all-multicast.
+ */
+ if (ifp->if_flags & IFF_PROMISC) {
+ sc->sc_rxcmd |= RXCMD_REC_ALL;
+ ifp->if_flags |= IFF_ALLMULTI;
+ return;
+ }
+
+ /*
+ * The 8003 has no hash table. If we have any multicast
+ * addresses on the list, enable reception of all multicast
+ * frames.
+ *
+ * XXX The 80c03 has a hash table. We should use it.
+ */
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+
+ if (enm == NULL) {
+ sc->sc_rxcmd &= ~RXCMD_REC_MASK;
+ sc->sc_rxcmd |= RXCMD_REC_BROAD;
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ return;
+ }
+
+ sc->sc_rxcmd |= RXCMD_REC_MULTI;
+ ifp->if_flags |= IFF_ALLMULTI;
+}
+
+int
+sq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error = 0;
+
+ SQ_TRACE(SQ_IOCTL, sc, 0, 0);
+
+ s = splnet();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ if (!(ifp->if_flags & IFF_RUNNING))
+ sq_init(ifp);
+#ifdef INET
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ arp_ifinit(&sc->sc_ac, ifa);
+#endif
+ break;
+
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING)
+ error = ENETRESET;
+ else
+ sq_init(ifp);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ sq_stop(ifp);
+ }
+ break;
+
+ default:
+ error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
+ break;
+ }
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ if (ifp->if_flags & IFF_RUNNING)
+ error = sq_init(ifp);
+ else
+ error = 0;
+ }
+
+ splx(s);
+ return error;
+}
+
+void
+sq_start(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ uint32_t status;
+ struct mbuf *m0, *m;
+ bus_dmamap_t dmamap;
+ int err, len, totlen, nexttx, firsttx, lasttx = -1, ofree, seg;
+
+ if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ /*
+ * Remember the previous number of free descriptors and
+ * the first descriptor we'll use.
+ */
+ ofree = sc->sc_nfreetx;
+ firsttx = sc->sc_nexttx;
+
+ /*
+ * Loop through the send queue, setting up transmit descriptors
+ * until we drain the queue, or use up all available transmit
+ * descriptors.
+ */
+ while (sc->sc_nfreetx != 0) {
+ /*
+ * Grab a packet off the queue.
+ */
+ IFQ_POLL(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+ m = NULL;
+
+ dmamap = sc->sc_txmap[sc->sc_nexttx];
+
+ /*
+ * Load the DMA map. If this fails, the packet either
+ * didn't fit in the alloted number of segments, or we were
+ * short on resources. In this case, we'll copy and try
+ * again.
+ * Also copy it if we need to pad, so that we are sure there
+ * is room for the pad buffer.
+ * XXX the right way of doing this is to use a static buffer
+ * for padding and adding it to the transmit descriptor (see
+ * sys/dev/pci/if_tl.c for example). We can't do this here yet
+ * because we can't send packets with more than one fragment.
+ */
+ len = m0->m_pkthdr.len;
+ if (len < ETHER_PAD_LEN ||
+ bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
+ BUS_DMA_NOWAIT) != 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ printf("%s: unable to allocate Tx mbuf\n",
+ sc->sc_dev.dv_xname);
+ break;
+ }
+ if (len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ printf("%s: unable to allocate Tx "
+ "cluster\n",
+ sc->sc_dev.dv_xname);
+ m_freem(m);
+ break;
+ }
+ }
+
+ m_copydata(m0, 0, len, mtod(m, void *));
+ if (len < ETHER_PAD_LEN) {
+ memset(mtod(m, char *) + len, 0,
+ ETHER_PAD_LEN - len);
+ len = ETHER_PAD_LEN;
+ }
+ m->m_pkthdr.len = m->m_len = len;
+
+ if ((err = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
+ m, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load Tx buffer, "
+ "error = %d\n",
+ sc->sc_dev.dv_xname, err);
+ break;
+ }
+ }
+
+ /*
+ * Ensure we have enough descriptors free to describe
+ * the packet.
+ */
+ if (dmamap->dm_nsegs > sc->sc_nfreetx) {
+ /*
+ * Not enough free descriptors to transmit this
+ * packet. We haven't committed to anything yet,
+ * so just unload the DMA map, put the packet
+ * back on the queue, and punt. Notify the upper
+ * layer that there are no more slots left.
+ *
+ * XXX We could allocate an mbuf and copy, but
+ * XXX it is worth it?
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ bus_dmamap_unload(sc->sc_dmat, dmamap);
+ if (m != NULL)
+ m_freem(m);
+ break;
+ }
+
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+#if NBPFILTER > 0
+ /*
+ * Pass the packet to any BPF listeners.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
+#endif
+ if (m != NULL) {
+ m_freem(m0);
+ m0 = m;
+ }
+
+ /*
+ * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
+ */
+
+ SQ_TRACE(SQ_ENQUEUE, sc, sc->sc_nexttx, 0);
+
+ /* Sync the DMA map. */
+ bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Initialize the transmit descriptors.
+ */
+ for (nexttx = sc->sc_nexttx, seg = 0, totlen = 0;
+ seg < dmamap->dm_nsegs;
+ seg++, nexttx = SQ_NEXTTX(nexttx)) {
+ if (sc->hpc_regs->revision == 3) {
+ sc->sc_txdesc[nexttx].hpc3_hdd_bufptr =
+ dmamap->dm_segs[seg].ds_addr;
+ sc->sc_txdesc[nexttx].hpc3_hdd_ctl =
+ dmamap->dm_segs[seg].ds_len;
+ } else {
+ sc->sc_txdesc[nexttx].hpc1_hdd_bufptr =
+ dmamap->dm_segs[seg].ds_addr;
+ sc->sc_txdesc[nexttx].hpc1_hdd_ctl =
+ dmamap->dm_segs[seg].ds_len;
+ }
+ sc->sc_txdesc[nexttx].hdd_descptr =
+ SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx));
+ lasttx = nexttx;
+ totlen += dmamap->dm_segs[seg].ds_len;
+ }
+
+ /* Last descriptor gets end-of-packet */
+ KASSERT(lasttx != -1);
+ if (sc->hpc_regs->revision == 3)
+ sc->sc_txdesc[lasttx].hpc3_hdd_ctl |=
+ HPC3_HDD_CTL_EOPACKET;
+ else
+ sc->sc_txdesc[lasttx].hpc1_hdd_ctl |=
+ HPC1_HDD_CTL_EOPACKET;
+
+ SQ_DPRINTF(("%s: transmit %d-%d, len %d\n",
+ sc->sc_dev.dv_xname, sc->sc_nexttx, lasttx, totlen));
+
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf(" transmit chain:\n");
+ for (seg = sc->sc_nexttx;; seg = SQ_NEXTTX(seg)) {
+ printf(" descriptor %d:\n", seg);
+ printf(" hdd_bufptr: 0x%08x\n",
+ (sc->hpc_regs->revision == 3) ?
+ sc->sc_txdesc[seg].hpc3_hdd_bufptr :
+ sc->sc_txdesc[seg].hpc1_hdd_bufptr);
+ printf(" hdd_ctl: 0x%08x\n",
+ (sc->hpc_regs->revision == 3) ?
+ sc->sc_txdesc[seg].hpc3_hdd_ctl:
+ sc->sc_txdesc[seg].hpc1_hdd_ctl);
+ printf(" hdd_descptr: 0x%08x\n",
+ sc->sc_txdesc[seg].hdd_descptr);
+
+ if (seg == lasttx)
+ break;
+ }
+ }
+
+ /* Sync the descriptors we're using. */
+ SQ_CDTXSYNC(sc, sc->sc_nexttx, dmamap->dm_nsegs,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Store a pointer to the packet so we can free it later */
+ sc->sc_txmbuf[sc->sc_nexttx] = m0;
+
+ /* Advance the tx pointer. */
+ sc->sc_nfreetx -= dmamap->dm_nsegs;
+ sc->sc_nexttx = nexttx;
+ }
+
+ /* All transmit descriptors used up, let upper layers know */
+ if (sc->sc_nfreetx == 0)
+ ifp->if_flags |= IFF_OACTIVE;
+
+ if (sc->sc_nfreetx != ofree) {
+ SQ_DPRINTF(("%s: %d packets enqueued, first %d, INTR on %d\n",
+ sc->sc_dev.dv_xname, lasttx - firsttx + 1,
+ firsttx, lasttx));
+
+ /*
+ * Cause a transmit interrupt to happen on the
+ * last packet we enqueued, mark it as the last
+ * descriptor.
+ *
+ * HPC1_HDD_CTL_INTR will generate an interrupt on
+ * HPC1. HPC3 requires HPC3_HDD_CTL_EOPACKET in
+ * addition to HPC3_HDD_CTL_INTR to interrupt.
+ */
+ KASSERT(lasttx != -1);
+ if (sc->hpc_regs->revision == 3) {
+ sc->sc_txdesc[lasttx].hpc3_hdd_ctl |=
+ HPC3_HDD_CTL_INTR | HPC3_HDD_CTL_EOCHAIN;
+ } else {
+ sc->sc_txdesc[lasttx].hpc1_hdd_ctl |= HPC1_HDD_CTL_INTR;
+ sc->sc_txdesc[lasttx].hpc1_hdd_bufptr |=
+ HPC1_HDD_CTL_EOCHAIN;
+ }
+
+ SQ_CDTXSYNC(sc, lasttx, 1,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /*
+ * There is a potential race condition here if the HPC
+ * DMA channel is active and we try and either update
+ * the 'next descriptor' pointer in the HPC PIO space
+ * or the 'next descriptor' pointer in a previous desc-
+ * riptor.
+ *
+ * To avoid this, if the channel is active, we rely on
+ * the transmit interrupt routine noticing that there
+ * are more packets to send and restarting the HPC DMA
+ * engine, rather than mucking with the DMA state here.
+ */
+ status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl);
+
+ if ((status & sc->hpc_regs->enetx_ctl_active) != 0) {
+ SQ_TRACE(SQ_ADD_TO_DMA, sc, firsttx, status);
+
+ /*
+ * NB: hpc3_hdd_ctl == hpc1_hdd_bufptr, and
+ * HPC1_HDD_CTL_EOCHAIN == HPC3_HDD_CTL_EOCHAIN
+ */
+ sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc3_hdd_ctl &=
+ ~HPC3_HDD_CTL_EOCHAIN;
+
+ if (sc->hpc_regs->revision != 3)
+ sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc1_hdd_ctl
+ &= ~HPC1_HDD_CTL_INTR;
+
+ SQ_CDTXSYNC(sc, SQ_PREVTX(firsttx), 1,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ } else if (sc->hpc_regs->revision == 3) {
+ SQ_TRACE(SQ_START_DMA, sc, firsttx, status);
+
+ sq_hpc_write(sc, HPC3_ENETX_NDBP, SQ_CDTXADDR(sc,
+ firsttx));
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC3_ENETX_CTL, HPC3_ENETX_CTL_ACTIVE);
+ } else {
+ /*
+ * In the HPC1 case where transmit DMA is
+ * inactive, we can either kick off if
+ * the ring was previously empty, or call
+ * our transmit interrupt handler to
+ * figure out if the ring stopped short
+ * and restart at the right place.
+ */
+ if (ofree == SQ_NTXDESC) {
+ SQ_TRACE(SQ_START_DMA, sc, firsttx, status);
+
+ sq_hpc_write(sc, HPC1_ENETX_NDBP,
+ SQ_CDTXADDR(sc, firsttx));
+ sq_hpc_write(sc, HPC1_ENETX_CFXBP,
+ SQ_CDTXADDR(sc, firsttx));
+ sq_hpc_write(sc, HPC1_ENETX_CBP,
+ SQ_CDTXADDR(sc, firsttx));
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC1_ENETX_CTL,
+ HPC1_ENETX_CTL_ACTIVE);
+ } else
+ sq_txring_hpc1(sc);
+ }
+
+ /* Set a watchdog timer in case the chip flakes out. */
+ ifp->if_timer = 5;
+ }
+}
+
+void
+sq_stop(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ int i;
+
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ for (i = 0; i < SQ_NTXDESC; i++) {
+ if (sc->sc_txmbuf[i] != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
+ m_freem(sc->sc_txmbuf[i]);
+ sc->sc_txmbuf[i] = NULL;
+ }
+ }
+
+ /* Clear Seeq transmit/receive command registers */
+ sq_seeq_write(sc, SEEQ_TXCMD, 0);
+ sq_seeq_write(sc, SEEQ_RXCMD, 0);
+
+ sq_reset(sc);
+}
+
+/* Device timeout/watchdog routine. */
+void
+sq_watchdog(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ uint32_t status;
+
+ status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl);
+ log(LOG_ERR, "%s: device timeout (prev %d, next %d, free %d, "
+ "status %08x)\n", sc->sc_dev.dv_xname, sc->sc_prevtx,
+ sc->sc_nexttx, sc->sc_nfreetx, status);
+
+#ifdef SQ_DEBUG
+ sq_trace_dump(sc);
+#endif
+
+ ++ifp->if_oerrors;
+
+ sq_init(ifp);
+}
+
+#ifdef SQ_DEBUG
+void
+sq_trace_dump(struct sq_softc *sc)
+{
+ int i;
+ const char *act;
+
+ for (i = 0; i < sc->sq_trace_idx; i++) {
+ switch (sc->sq_trace[i].action) {
+ case SQ_RESET: act = "SQ_RESET"; break;
+ case SQ_ADD_TO_DMA: act = "SQ_ADD_TO_DMA"; break;
+ case SQ_START_DMA: act = "SQ_START_DMA"; break;
+ case SQ_DONE_DMA: act = "SQ_DONE_DMA"; break;
+ case SQ_RESTART_DMA: act = "SQ_RESTART_DMA"; break;
+ case SQ_TXINTR_ENTER: act = "SQ_TXINTR_ENTER"; break;
+ case SQ_TXINTR_EXIT: act = "SQ_TXINTR_EXIT"; break;
+ case SQ_TXINTR_BUSY: act = "SQ_TXINTR_BUSY"; break;
+ case SQ_IOCTL: act = "SQ_IOCTL"; break;
+ case SQ_ENQUEUE: act = "SQ_ENQUEUE"; break;
+ default: act = "UNKNOWN";
+ }
+
+ printf("%s: [%03d] action %-16s buf %03d free %03d "
+ "status %08x line %d\n", sc->sc_dev.dv_xname, i, act,
+ sc->sq_trace[i].bufno, sc->sq_trace[i].freebuf,
+ sc->sq_trace[i].status, sc->sq_trace[i].line);
+ }
+
+ memset(&sc->sq_trace, 0, sizeof(sc->sq_trace));
+ sc->sq_trace_idx = 0;
+}
+#endif
+
+int
+sq_intr(void *arg)
+{
+ struct sq_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ uint32_t stat;
+
+ stat = sq_hpc_read(sc, sc->hpc_regs->enetr_reset);
+
+ if ((stat & 2) == 0) {
+ SQ_DPRINTF(("%s: Unexpected interrupt!\n",
+ sc->sc_dev.dv_xname));
+ } else
+ sq_hpc_write(sc, sc->hpc_regs->enetr_reset, (stat | 2));
+
+ /*
+ * If the interface isn't running, the interrupt couldn't
+ * possibly have come from us.
+ */
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ return 0;
+
+ /* Always check for received packets */
+ sq_rxintr(sc);
+
+ /* Only handle transmit interrupts if we actually sent something */
+ if (sc->sc_nfreetx < SQ_NTXDESC)
+ sq_txintr(sc);
+
+ /*
+ * XXX Always claim the interrupt, even if we did nothing.
+ * XXX There seem to be extra interrupts when the receiver becomes
+ * XXX idle.
+ */
+ return 1;
+}
+
+void
+sq_rxintr(struct sq_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ struct mbuf* m;
+ int i, framelen;
+ uint8_t pktstat;
+ uint32_t status;
+ uint32_t ctl_reg;
+ int new_end, orig_end;
+
+ for (i = sc->sc_nextrx; ; i = SQ_NEXTRX(i)) {
+ SQ_CDRXSYNC(sc, i,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ /*
+ * If this is a CPU-owned buffer, we're at the end of the list.
+ */
+ if (sc->hpc_regs->revision == 3)
+ ctl_reg =
+ sc->sc_rxdesc[i].hpc3_hdd_ctl & HPC3_HDD_CTL_OWN;
+ else
+ ctl_reg =
+ sc->sc_rxdesc[i].hpc1_hdd_ctl & HPC1_HDD_CTL_OWN;
+
+ if (ctl_reg) {
+#if defined(SQ_DEBUG)
+ uint32_t reg;
+
+ reg = sq_hpc_read(sc, sc->hpc_regs->enetr_ctl);
+ SQ_DPRINTF(("%s: rxintr: done at %d (ctl %08x)\n",
+ sc->sc_dev.dv_xname, i, reg));
+#endif
+ break;
+ }
+
+ m = sc->sc_rxmbuf[i];
+ framelen = m->m_ext.ext_size - 3;
+ if (sc->hpc_regs->revision == 3)
+ framelen -=
+ HPC3_HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc3_hdd_ctl);
+ else
+ framelen -=
+ HPC1_HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc1_hdd_ctl);
+
+ /* Now sync the actual packet data */
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
+ sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_POSTREAD);
+
+ pktstat = *((uint8_t *)m->m_data + framelen + 2);
+
+ if ((pktstat & RXSTAT_GOOD) == 0) {
+ ifp->if_ierrors++;
+
+ if (pktstat & RXSTAT_OFLOW)
+ printf("%s: receive FIFO overflow\n",
+ sc->sc_dev.dv_xname);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
+ sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD);
+ SQ_INIT_RXDESC(sc, i);
+ SQ_DPRINTF(("%s: sq_rxintr: buf %d no RXSTAT_GOOD\n",
+ sc->sc_dev.dv_xname, i));
+ continue;
+ }
+
+ if (sq_add_rxbuf(sc, i) != 0) {
+ ifp->if_ierrors++;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
+ sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD);
+ SQ_INIT_RXDESC(sc, i);
+ SQ_DPRINTF(("%s: sq_rxintr: buf %d sq_add_rxbuf() "
+ "failed\n", sc->sc_dev.dv_xname, i));
+ continue;
+ }
+
+
+ m->m_data += 2;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = framelen;
+
+ ifp->if_ipackets++;
+
+ SQ_DPRINTF(("%s: sq_rxintr: buf %d len %d\n",
+ sc->sc_dev.dv_xname, i, framelen));
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
+#endif
+
+ ether_input_mbuf(ifp, m);
+ }
+
+
+ /* If anything happened, move ring start/end pointers to new spot */
+ if (i != sc->sc_nextrx) {
+ /*
+ * NB: hpc3_hdd_ctl == hpc1_hdd_bufptr, and
+ * HPC1_HDD_CTL_EOCHAIN == HPC3_HDD_CTL_EOCHAIN
+ */
+
+ new_end = SQ_PREVRX(i);
+ sc->sc_rxdesc[new_end].hpc3_hdd_ctl |= HPC3_HDD_CTL_EOCHAIN;
+ SQ_CDRXSYNC(sc, new_end,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ orig_end = SQ_PREVRX(sc->sc_nextrx);
+ sc->sc_rxdesc[orig_end].hpc3_hdd_ctl &= ~HPC3_HDD_CTL_EOCHAIN;
+ SQ_CDRXSYNC(sc, orig_end,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ sc->sc_nextrx = i;
+ }
+
+ status = sq_hpc_read(sc, sc->hpc_regs->enetr_ctl);
+
+ /* If receive channel is stopped, restart it... */
+ if ((status & sc->hpc_regs->enetr_ctl_active) == 0) {
+ /* Pass the start of the receive ring to the HPC */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp,
+ SQ_CDRXADDR(sc, sc->sc_nextrx));
+
+ /* And turn on the HPC ethernet receive channel */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ctl,
+ sc->hpc_regs->enetr_ctl_active);
+ }
+}
+
+void
+sq_txintr(struct sq_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ uint shift = 0;
+ uint32_t status, tmp;
+
+ if (sc->hpc_regs->revision != 3)
+ shift = 16;
+
+ status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl) >> shift;
+
+ SQ_TRACE(SQ_TXINTR_ENTER, sc, sc->sc_prevtx, status);
+
+ tmp = (sc->hpc_regs->enetx_ctl_active >> shift) | TXSTAT_GOOD;
+ if ((status & tmp) == 0) {
+ if (status & TXSTAT_COLL)
+ ifp->if_collisions++;
+
+ if (status & TXSTAT_UFLOW) {
+ printf("%s: transmit underflow\n",
+ sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+#ifdef SQ_DEBUG
+ sq_trace_dump(sc);
+#endif
+ sq_init(ifp);
+ return;
+ }
+
+ if (status & TXSTAT_16COLL) {
+ printf("%s: max collisions reached\n",
+ sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+ ifp->if_collisions += 16;
+ }
+ }
+
+ /* prevtx now points to next xmit packet not yet finished */
+ if (sc->hpc_regs->revision == 3)
+ sq_txring_hpc3(sc);
+ else
+ sq_txring_hpc1(sc);
+
+ /* If we have buffers free, let upper layers know */
+ if (sc->sc_nfreetx > 0)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /* If all packets have left the coop, cancel watchdog */
+ if (sc->sc_nfreetx == SQ_NTXDESC)
+ ifp->if_timer = 0;
+
+ SQ_TRACE(SQ_TXINTR_EXIT, sc, sc->sc_prevtx, status);
+ sq_start(ifp);
+}
+
+/*
+ * Reclaim used transmit descriptors and restart the transmit DMA
+ * engine if necessary.
+ */
+void
+sq_txring_hpc1(struct sq_softc *sc)
+{
+ /*
+ * HPC1 doesn't tag transmitted descriptors, however,
+ * the NDBP register points to the next descriptor that
+ * has not yet been processed. If DMA is not in progress,
+ * we can safely reclaim all descriptors up to NDBP, and,
+ * if necessary, restart DMA at NDBP. Otherwise, if DMA
+ * is active, we can only safely reclaim up to CBP.
+ *
+ * For now, we'll only reclaim on inactive DMA and assume
+ * that a sufficiently large ring keeps us out of trouble.
+ */
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ uint32_t reclaimto, status;
+ int reclaimall, i = sc->sc_prevtx;
+
+ status = sq_hpc_read(sc, HPC1_ENETX_CTL);
+ if (status & HPC1_ENETX_CTL_ACTIVE) {
+ SQ_TRACE(SQ_TXINTR_BUSY, sc, i, status);
+ return;
+ } else
+ reclaimto = sq_hpc_read(sc, HPC1_ENETX_NDBP);
+
+ if (sc->sc_nfreetx == 0 && SQ_CDTXADDR(sc, i) == reclaimto)
+ reclaimall = 1;
+ else
+ reclaimall = 0;
+
+ while (sc->sc_nfreetx < SQ_NTXDESC) {
+ if (SQ_CDTXADDR(sc, i) == reclaimto && !reclaimall)
+ break;
+
+ SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ /* Sync the packet data, unload DMA map, free mbuf */
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[i],
+ 0, sc->sc_txmap[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
+ m_freem(sc->sc_txmbuf[i]);
+ sc->sc_txmbuf[i] = NULL;
+
+ ifp->if_opackets++;
+ sc->sc_nfreetx++;
+
+ SQ_TRACE(SQ_DONE_DMA, sc, i, status);
+
+ i = SQ_NEXTTX(i);
+ }
+
+ if (sc->sc_nfreetx < SQ_NTXDESC) {
+ SQ_TRACE(SQ_RESTART_DMA, sc, i, status);
+
+ KASSERT(reclaimto == SQ_CDTXADDR(sc, i));
+
+ sq_hpc_write(sc, HPC1_ENETX_CFXBP, reclaimto);
+ sq_hpc_write(sc, HPC1_ENETX_CBP, reclaimto);
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC1_ENETX_CTL, HPC1_ENETX_CTL_ACTIVE);
+
+ /*
+ * Set a watchdog timer in case the chip
+ * flakes out.
+ */
+ ifp->if_timer = 5;
+ }
+
+ sc->sc_prevtx = i;
+}
+
+/*
+ * Reclaim used transmit descriptors and restart the transmit DMA
+ * engine if necessary.
+ */
+void
+sq_txring_hpc3(struct sq_softc *sc)
+{
+ /*
+ * HPC3 tags descriptors with a bit once they've been
+ * transmitted. We need only free each XMITDONE'd
+ * descriptor, and restart the DMA engine if any
+ * descriptors are left over.
+ */
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ int i;
+ uint32_t status = 0;
+
+ i = sc->sc_prevtx;
+ while (sc->sc_nfreetx < SQ_NTXDESC) {
+ /*
+ * Check status first so we don't end up with a case of
+ * the buffer not being finished while the DMA channel
+ * has gone idle.
+ */
+ status = sq_hpc_read(sc, HPC3_ENETX_CTL);
+
+ SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ /* Check for used descriptor and restart DMA chain if needed */
+ if ((sc->sc_txdesc[i].hpc3_hdd_ctl &
+ HPC3_HDD_CTL_XMITDONE) == 0) {
+ if ((status & HPC3_ENETX_CTL_ACTIVE) == 0) {
+ SQ_TRACE(SQ_RESTART_DMA, sc, i, status);
+
+ sq_hpc_write(sc, HPC3_ENETX_NDBP,
+ SQ_CDTXADDR(sc, i));
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC3_ENETX_CTL,
+ HPC3_ENETX_CTL_ACTIVE);
+
+ /*
+ * Set a watchdog timer in case the chip
+ * flakes out.
+ */
+ ifp->if_timer = 5;
+ } else
+ SQ_TRACE(SQ_TXINTR_BUSY, sc, i, status);
+ break;
+ }
+
+ /* Sync the packet data, unload DMA map, free mbuf */
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[i],
+ 0, sc->sc_txmap[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
+ m_freem(sc->sc_txmbuf[i]);
+ sc->sc_txmbuf[i] = NULL;
+
+ ifp->if_opackets++;
+ sc->sc_nfreetx++;
+
+ SQ_TRACE(SQ_DONE_DMA, sc, i, status);
+ i = SQ_NEXTTX(i);
+ }
+
+ sc->sc_prevtx = i;
+}
+
+void
+sq_reset(struct sq_softc *sc)
+{
+ /* Stop HPC dma channels */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ctl, 0);
+ sq_hpc_write(sc, sc->hpc_regs->enetx_ctl, 0);
+
+ sq_hpc_write(sc, sc->hpc_regs->enetr_reset, 3);
+ delay(20);
+ sq_hpc_write(sc, sc->hpc_regs->enetr_reset, 0);
+}
+
+/* sq_add_rxbuf: Add a receive buffer to the indicated descriptor. */
+int
+sq_add_rxbuf(struct sq_softc *sc, int idx)
+{
+ int err;
+ struct mbuf *m;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return ENOBUFS;
+
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ return ENOBUFS;
+ }
+
+ if (sc->sc_rxmbuf[idx] != NULL)
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[idx]);
+
+ sc->sc_rxmbuf[idx] = m;
+
+ if ((err = bus_dmamap_load(sc->sc_dmat, sc->sc_rxmap[idx],
+ m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't load rx DMA map %d, error = %d\n",
+ sc->sc_dev.dv_xname, idx, err);
+ panic("sq_add_rxbuf"); /* XXX */
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx],
+ 0, sc->sc_rxmap[idx]->dm_mapsize, BUS_DMASYNC_PREREAD);
+
+ SQ_INIT_RXDESC(sc, idx);
+
+ return 0;
+}
diff --git a/sys/arch/sgi/hpc/if_sqvar.h b/sys/arch/sgi/hpc/if_sqvar.h
new file mode 100644
index 00000000000..657025771f7
--- /dev/null
+++ b/sys/arch/sgi/hpc/if_sqvar.h
@@ -0,0 +1,200 @@
+/* $OpenBSD: if_sqvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: sqvar.h,v 1.12 2011/01/25 13:12:39 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * 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. 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.
+ */
+
+/* Note, these must be powers of two for the magic NEXT/PREV macros to work */
+#define SQ_NRXDESC 64
+#define SQ_NTXDESC 64
+
+#define SQ_NRXDESC_MASK (SQ_NRXDESC - 1)
+#define SQ_NEXTRX(x) ((x + 1) & SQ_NRXDESC_MASK)
+#define SQ_PREVRX(x) ((x - 1) & SQ_NRXDESC_MASK)
+
+#define SQ_NTXDESC_MASK (SQ_NTXDESC - 1)
+#define SQ_NEXTTX(x) ((x + 1) & SQ_NTXDESC_MASK)
+#define SQ_PREVTX(x) ((x - 1) & SQ_NTXDESC_MASK)
+
+/*
+ * We pack all DMA control structures into one container so we can alloc just
+ * one chunk of DMA-safe memory and pack them into it. Otherwise, we'd have to
+ * allocate a page for each descriptor, since the bus_dmamem_alloc() interface
+ * does not allow us to allocate smaller chunks.
+ */
+struct sq_control {
+ /* Receive descriptors */
+ struct hpc_dma_desc rx_desc[SQ_NRXDESC];
+
+ /* Transmit descriptors */
+ struct hpc_dma_desc tx_desc[SQ_NTXDESC];
+};
+
+#define SQ_CDOFF(x) offsetof(struct sq_control, x)
+#define SQ_CDTXOFF(x) SQ_CDOFF(tx_desc[(x)])
+#define SQ_CDRXOFF(x) SQ_CDOFF(rx_desc[(x)])
+
+#define SQ_TYPE_8003 0
+#define SQ_TYPE_80C03 1
+
+/* Trace Actions */
+#define SQ_RESET 1
+#define SQ_ADD_TO_DMA 2
+#define SQ_START_DMA 3
+#define SQ_DONE_DMA 4
+#define SQ_RESTART_DMA 5
+#define SQ_TXINTR_ENTER 6
+#define SQ_TXINTR_EXIT 7
+#define SQ_TXINTR_BUSY 8
+#define SQ_IOCTL 9
+#define SQ_ENQUEUE 10
+
+struct sq_action_trace {
+ int action;
+ int line;
+ int bufno;
+ int status;
+ int freebuf;
+};
+
+#ifdef SQ_DEBUG
+#define SQ_TRACEBUF_SIZE 100
+
+#define SQ_TRACE(act, sc, buf, stat) do { \
+ (sc)->sq_trace[(sc)->sq_trace_idx].action = (act); \
+ (sc)->sq_trace[(sc)->sq_trace_idx].line = __LINE__; \
+ (sc)->sq_trace[(sc)->sq_trace_idx].bufno = (buf); \
+ (sc)->sq_trace[(sc)->sq_trace_idx].status = (stat); \
+ (sc)->sq_trace[(sc)->sq_trace_idx].freebuf = (sc)->sc_nfreetx; \
+ if (++(sc)->sq_trace_idx == SQ_TRACEBUF_SIZE) \
+ (sc)->sq_trace_idx = 0; \
+} while (/* CONSTCOND */0)
+#else
+#define SQ_TRACE(act, sc, buf, stat) do { } while (/* CONSTCOND */0)
+#endif
+
+struct sq_softc {
+ struct device sc_dev;
+
+ /* HPC registers */
+ bus_space_tag_t sc_hpct;
+ bus_space_handle_t sc_hpch;
+
+ /* HPC external Ethernet registers: aka Seeq 8003 registers */
+ bus_space_tag_t sc_regt;
+ bus_space_handle_t sc_regh;
+
+ bus_dma_tag_t sc_dmat;
+
+ struct arpcom sc_ac;
+ uint8_t sc_enaddr[ETHER_ADDR_LEN];
+
+ int sc_type;
+
+ struct sq_control* sc_control;
+#define sc_rxdesc sc_control->rx_desc
+#define sc_txdesc sc_control->tx_desc
+
+ /* DMA structures for control data (DMA RX/TX descriptors) */
+ int sc_ncdseg;
+ bus_dma_segment_t sc_cdseg;
+ bus_dmamap_t sc_cdmap;
+#define sc_cddma sc_cdmap->dm_segs[0].ds_addr
+
+ int sc_nextrx;
+
+ /* DMA structures for RX packet data */
+ bus_dma_segment_t sc_rxseg[SQ_NRXDESC];
+ bus_dmamap_t sc_rxmap[SQ_NRXDESC];
+ struct mbuf* sc_rxmbuf[SQ_NRXDESC];
+
+ int sc_nexttx;
+ int sc_prevtx;
+ int sc_nfreetx;
+
+ /* DMA structures for TX packet data */
+ bus_dma_segment_t sc_txseg[SQ_NTXDESC];
+ bus_dmamap_t sc_txmap[SQ_NTXDESC];
+ struct mbuf* sc_txmbuf[SQ_NTXDESC];
+
+ uint8_t sc_rxcmd; /* prototype rxcmd */
+
+ struct hpc_values *hpc_regs; /* HPC register definitions */
+
+#ifdef SQ_DEBUG
+ int sq_trace_idx;
+ struct sq_action_trace sq_trace[SQ_TRACEBUF_SIZE];
+#endif
+};
+
+#define SQ_CDTXADDR(sc, x) ((sc)->sc_cddma + SQ_CDTXOFF((x)))
+#define SQ_CDRXADDR(sc, x) ((sc)->sc_cddma + SQ_CDRXOFF((x)))
+
+static inline void
+SQ_CDTXSYNC(struct sq_softc *sc, int __x, int __n, int ops)
+{
+ /* If it will wrap around, sync to the end of the ring. */
+ if ((__x + __n) > SQ_NTXDESC) {
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap,
+ SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) *
+ (SQ_NTXDESC - __x), (ops));
+ __n -= (SQ_NTXDESC - __x);
+ __x = 0;
+ }
+
+ /* Now sync whatever is left. */
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap,
+ SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) * __n, (ops));
+}
+
+#define SQ_CDRXSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \
+ SQ_CDRXOFF((x)), sizeof(struct hpc_dma_desc), (ops))
+
+static inline void
+SQ_INIT_RXDESC(struct sq_softc *sc, unsigned int x)
+{
+ struct hpc_dma_desc* __rxd = &(sc)->sc_rxdesc[(x)];
+ struct mbuf *__m = (sc)->sc_rxmbuf[(x)];
+
+ __m->m_data = __m->m_ext.ext_buf;
+ if (sc->hpc_regs->revision == 3) {
+ __rxd->hpc3_hdd_bufptr =
+ (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr;
+ __rxd->hpc3_hdd_ctl = __m->m_ext.ext_size | HPC3_HDD_CTL_OWN |
+ HPC3_HDD_CTL_INTR | HPC3_HDD_CTL_EOPACKET |
+ ((x) == (SQ_NRXDESC - 1) ? HPC3_HDD_CTL_EOCHAIN : 0);
+ } else {
+ __rxd->hpc1_hdd_bufptr =
+ (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr |
+ ((x) == (SQ_NRXDESC - 1) ? HPC1_HDD_CTL_EOCHAIN : 0);
+ __rxd->hpc1_hdd_ctl = __m->m_ext.ext_size | HPC1_HDD_CTL_OWN |
+ HPC1_HDD_CTL_INTR | HPC1_HDD_CTL_EOPACKET;
+ }
+ __rxd->hdd_descptr = SQ_CDRXADDR((sc), SQ_NEXTRX((x)));
+ SQ_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+}
diff --git a/sys/arch/sgi/hpc/iocreg.h b/sys/arch/sgi/hpc/iocreg.h
new file mode 100644
index 00000000000..274454e4ddf
--- /dev/null
+++ b/sys/arch/sgi/hpc/iocreg.h
@@ -0,0 +1,122 @@
+/* $OpenBSD: iocreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: iocreg.h,v 1.2 2005/12/11 12:18:53 christos Exp $ */
+
+/*
+ * Copyright (c) 2003 Christopher Sekiya
+ * Copyright (c) 2001 Rafal K. Boni
+ * 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. 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.
+ */
+
+/*
+ * IOC1/2 memory map.
+ *
+ * The IOC1/2 is connected to the HPC#0, PBus channel 6, so these registers
+ * are based from the external register window for PBus channel 6 on HPC#0.
+ *
+ */
+
+#define IOC_BASE HPC3_PBUS_CH6_DEVREGS
+
+#define IOC_PLP_REGS 0x00 /* Parallel port registers */
+#define IOC_PLP_REGS_SIZE 0x2c
+
+#define IOC_PLP_DATA 0x00 /* Data register */
+#define IOC_PLP_CTL 0x04 /* Control register */
+#define IOC_PLP_STAT 0x08 /* Status register */
+#define IOC_PLP_DMACTL 0x0c /* DMA control register */
+#define IOC_PLP_INTSTAT 0x10 /* Interrupt status register */
+#define IOC_PLP_INTMASK 0x14 /* Interrupt mask register */
+#define IOC_PLP_TIMER1 0x18 /* Timer 1 register */
+#define IOC_PLP_TIMER2 0x1c /* Timer 2 register */
+#define IOC_PLP_TIMER3 0x20 /* Timer 3 register */
+#define IOC_PLP_TIMER4 0x24 /* Timer 4 register */
+
+#define IOC_SERIAL_REGS 0x30 /* Serial port registers */
+#define IOC_SERIAL_REGS_SIZE 0x0c
+
+#define IOC_SERIAL_PORT1_CMD 0x00 /* Port 1 command transfer */
+#define IOC_SERIAL_PORT1_DATA 0x04 /* Port 1 data transfer */
+#define IOC_SERIAL_PORT2_CMD 0x08 /* Port 2 command transfer */
+#define IOC_SERIAL_PORT2_DATA 0x0c /* Port 2 data transfer */
+
+#define IOC_KB_REGS 0x40 /* Keyboard/mouse registers */
+#define IOC_KB_REGS_SIZE 0x08
+
+/* Miscellaneous registers */
+
+#define IOC_MISC_REGS 0x48 /* Misc. IOC regs */
+#define IOC_MISC_REGS_SIZE 0x34
+
+#define IOC_GCSEL 0x48 /* General select register */
+
+#define IOC_GCREG 0x4c /* General control register */
+
+#define IOC_PANEL 0x50 /* Front Panel register */
+#define IOC_PANEL_POWER_STATE 0x01
+#define IOC_PANEL_POWER_IRQ 0x02
+#define IOC_PANEL_VDOWN_IRQ 0x10
+#define IOC_PANEL_VDOWN_HOLD 0x20
+#define IOC_PANEL_VUP_IRQ 0x40
+#define IOC_PANEL_VUP_HOLD 0x80
+
+#define IOC_SYSID 0x58 /* System ID register */
+#define IOC_SYSID_SYSTYPE 0x01 /* 0: Sapphire, 1: Full House */
+#define IOC_SYSID_BOARDREV 0x1e
+#define IOC_SYSID_BOARDREV_SHIFT 1
+#define IOC_SYSID_CHIPREV 0xe0
+#define IOC_SYSID_CHIPREV_SHIFT 5
+
+#define IOC_READ 0x60 /* Read register */
+#define IOC_READ_SCSI0_POWER 0x10
+#define IOC_READ_SCSI1_POWER 0x20
+#define IOC_READ_ENET_POWER 0x40
+#define IOC_READ_ENET_LINK 0x80
+
+#define IOC_DMASEL 0x68 /* DMA select register */
+#define IOC_DMASEL_ISDN_B 0x01
+#define IOC_DMASEL_ISDN_A 0x02
+#define IOC_DMASEL_PARALLEL 0x04
+#define IOC_DMASEL_SERIAL_10MHZ 0x00
+#define IOC_DMASEL_SERIAL_6MHZ 0x10
+#define IOC_DMASEL_SERIAL_EXTERNAL 0x20
+
+#define IOC_RESET 0x70 /* Reset register */
+#define IOC_RESET_PARALLEL 0x01
+#define IOC_RESET_PCKBC 0x02
+#define IOC_RESET_EISA 0x04
+#define IOC_RESET_ISDN 0x08
+#define IOC_RESET_LED_GREEN 0x10
+#define IOC_RESET_LED_RED 0x20
+#define IOC_RESET_LED_ORANGE 0x40
+
+#define IOC_WRITE 0x78 /* Write register */
+#define IOC_WRITE_ENET_NTH 0x01
+#define IOC_WRITE_ENET_UTP 0x02
+#define IOC_WRITE_ENET_AUI 0x04
+#define IOC_WRITE_ENET_AUTO 0x08
+#define IOC_WRITE_PC_UART2 0x10
+#define IOC_WRITE_PC_UART1 0x20
+#define IOC_WRITE_MARGIN_LOW 0x40
+#define IOC_WRITE_MARGIN_HIGH 0x80
diff --git a/sys/arch/sgi/hpc/wdsc.c b/sys/arch/sgi/hpc/wdsc.c
new file mode 100644
index 00000000000..101b5178819
--- /dev/null
+++ b/sys/arch/sgi/hpc/wdsc.c
@@ -0,0 +1,290 @@
+/* $OpenBSD: wdsc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: wdsc.c,v 1.32 2011/07/01 18:53:47 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wayne Knowles
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+#include <sys/timeout.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <sgi/localbus/intvar.h>
+
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcdma.h>
+
+#include <dev/ic/wd33c93reg.h>
+#include <dev/ic/wd33c93var.h>
+
+struct wdsc_softc {
+ struct wd33c93_softc sc_wd33c93; /* Must be first */
+ bus_dma_tag_t sc_dmat;
+ bus_dmamap_t sc_dmamap;
+ int sc_flags;
+#define WDSC_DMA_ACTIVE 0x1
+#define WDSC_DMA_MAPLOADED 0x2
+ struct hpc_dma_softc sc_hpcdma;
+};
+
+int wdsc_match(struct device *, void *, void *);
+void wdsc_attach(struct device *, struct device *, void *);
+
+const struct cfattach wdsc_ca = {
+ sizeof(struct wdsc_softc), wdsc_match, wdsc_attach
+};
+
+struct cfdriver wdsc_cd = {
+ NULL, "wdsc", DV_DULL
+};
+
+int wdsc_dmasetup(struct wd33c93_softc *, void ** ,size_t *, int, size_t *);
+int wdsc_dmago(struct wd33c93_softc *);
+void wdsc_dmastop(struct wd33c93_softc *);
+void wdsc_reset(struct wd33c93_softc *);
+
+struct scsi_adapter wdsc_switch = {
+ wd33c93_scsi_cmd,
+ scsi_minphys,
+ NULL,
+ NULL,
+};
+
+/*
+ * Match for SCSI devices on the onboard and GIO32 adapter WD33C93 chips
+ */
+int
+wdsc_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *haa = aux;
+ struct cfdata *cf = vcf;
+ vaddr_t reset, asr;
+ uint32_t dummy;
+ uint8_t reg;
+
+ if (strcmp(haa->ha_name, cf->cf_driver->cd_name) != 0)
+ return 0;
+
+ reset = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_dmaoff +
+ haa->hpc_regs->scsi0_ctl, CCA_NC);
+ if (guarded_read_4(reset, &dummy) != 0)
+ return 0;
+ *(volatile uint32_t *)reset = haa->hpc_regs->scsi_dmactl_reset;
+ delay(1000);
+ *(volatile uint32_t *)reset = 0x0;
+ delay(1000);
+
+ asr = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_devoff + 3, CCA_NC);
+ if (guarded_read_1(asr, &reg) != 0)
+ return 0;
+ if ((reg & 0xff) != SBIC_ASR_INT)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Attach the wdsc driver
+ */
+void
+wdsc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)self;
+ struct wd33c93_softc *sc = &wsc->sc_wd33c93;
+ struct hpc_attach_args *haa = aux;
+ int err;
+
+ sc->sc_regt = haa->ha_st;
+ wsc->sc_dmat = haa->ha_dmat;
+
+ wsc->sc_hpcdma.hpc = haa->hpc_regs;
+
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff + 3, 1, &sc->sc_asr_regh)) != 0) {
+ printf(": unable to map asr reg, err=%d\n", err);
+ return;
+ }
+
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff + 3 + 4, 1, &sc->sc_data_regh)) != 0) {
+ printf(": unable to map asr reg, err=%d\n", err);
+ return;
+ }
+
+ if (bus_dmamap_create(wsc->sc_dmat, MAXPHYS,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs_size,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs_size,
+ BUS_DMA_WAITOK, &wsc->sc_dmamap) != 0) {
+ printf(": failed to create dmamap\n");
+ return;
+ }
+
+ sc->sc_dmasetup = wdsc_dmasetup;
+ sc->sc_dmago = wdsc_dmago;
+ sc->sc_dmastop = wdsc_dmastop;
+ sc->sc_reset = wdsc_reset;
+
+ sc->sc_id = 0; /* Host ID = 0 */
+ sc->sc_clkfreq = 200; /* 20MHz */
+ sc->sc_dmamode = SBIC_CTL_BURST_DMA;
+
+ if (int2_intr_establish(haa->ha_irq, IPL_BIO,
+ wd33c93_intr, wsc, self->dv_xname) == NULL) {
+ printf(": unable to establish interrupt!\n");
+ return;
+ }
+
+ hpcdma_init(haa, &wsc->sc_hpcdma, wsc->sc_hpcdma.hpc->scsi_dma_segs);
+ wd33c93_attach(sc, &wdsc_switch);
+}
+
+/*
+ * Prime the hardware for a DMA transfer
+ *
+ * Requires splbio() interrupts to be disabled by the caller
+ */
+int
+wdsc_dmasetup(struct wd33c93_softc *sc, void **addr, size_t *len, int datain,
+ size_t *dmasize)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+ int count, err;
+ void *vaddr;
+
+ KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
+
+ vaddr = *addr;
+ count = dsc->sc_dlen = *len;
+ if (count) {
+ KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED) == 0);
+
+ /* Build list of physical addresses for this transfer */
+ if ((err = bus_dmamap_load(wsc->sc_dmat, wsc->sc_dmamap,
+ vaddr, count, NULL /* kernel address */,
+ BUS_DMA_NOWAIT)) != 0)
+ panic("%s: bus_dmamap_load err=%d",
+ sc->sc_dev.dv_xname, err);
+
+ hpcdma_sglist_create(dsc, wsc->sc_dmamap);
+ wsc->sc_flags |= WDSC_DMA_MAPLOADED;
+
+ if (datain) {
+ dsc->sc_dmacmd =
+ wsc->sc_hpcdma.hpc->scsi_dma_datain_cmd;
+ dsc->sc_flags |= HPCDMA_READ;
+ } else {
+ dsc->sc_dmacmd =
+ wsc->sc_hpcdma.hpc->scsi_dma_dataout_cmd;
+ dsc->sc_flags &= ~HPCDMA_READ;
+ }
+ }
+ return count;
+}
+
+/*
+ * Prime the hardware for the next DMA transfer
+ */
+int
+wdsc_dmago(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ if (dsc->sc_dlen == 0)
+ return 0;
+
+ KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
+ KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED));
+
+ wsc->sc_flags |= WDSC_DMA_ACTIVE;
+
+ bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap,
+ 0, wsc->sc_dmamap->dm_mapsize,
+ (dsc->sc_flags & HPCDMA_READ) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+
+ hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */
+
+ return wsc->sc_dmamap->dm_mapsize;
+}
+
+/*
+ * Stop DMA and unload active DMA maps
+ */
+void
+wdsc_dmastop(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ if (wsc->sc_flags & WDSC_DMA_ACTIVE) {
+ if (dsc->sc_flags & HPCDMA_READ)
+ hpcdma_flush(dsc);
+ hpcdma_cntl(dsc, 0); /* Stop DMA */
+ bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap,
+ 0, wsc->sc_dmamap->dm_mapsize,
+ (dsc->sc_flags & HPCDMA_READ) ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ }
+ if (wsc->sc_flags & WDSC_DMA_MAPLOADED)
+ bus_dmamap_unload(wsc->sc_dmat, wsc->sc_dmamap);
+ wsc->sc_flags &= ~(WDSC_DMA_ACTIVE | WDSC_DMA_MAPLOADED);
+}
+
+/*
+ * Reset the controller.
+ */
+void
+wdsc_reset(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ hpcdma_reset(dsc);
+}
diff --git a/sys/arch/sgi/hpc/z8530sc.c b/sys/arch/sgi/hpc/z8530sc.c
new file mode 100644
index 00000000000..fbec53846b4
--- /dev/null
+++ b/sys/arch/sgi/hpc/z8530sc.c
@@ -0,0 +1,409 @@
+/* $OpenBSD: z8530sc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530sc.c,v 1.30 2009/05/22 03:51:30 mrg Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (common part)
+ *
+ * This file contains the machine-independent parts of the
+ * driver common to tty and keyboard/mouse sub-drivers.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <dev/ic/z8530reg.h>
+#include <machine/z8530var.h>
+
+void
+zs_break(struct zs_chanstate *cs, int set)
+{
+
+ if (set) {
+ cs->cs_preg[5] |= ZSWR5_BREAK;
+ cs->cs_creg[5] |= ZSWR5_BREAK;
+ } else {
+ cs->cs_preg[5] &= ~ZSWR5_BREAK;
+ cs->cs_creg[5] &= ~ZSWR5_BREAK;
+ }
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
+}
+
+
+/*
+ * drain on-chip fifo
+ */
+void
+zs_iflush(struct zs_chanstate *cs)
+{
+ uint8_t c, rr0, rr1;
+ int i;
+
+ /*
+ * Count how many times we loop. Some systems, such as some
+ * Apple PowerBooks, claim to have SCC's which they really don't.
+ */
+ for (i = 0; i < 32; i++) {
+ /* Is there input available? */
+ rr0 = zs_read_csr(cs);
+ if ((rr0 & ZSRR0_RX_READY) == 0)
+ break;
+
+ /*
+ * First read the status, because reading the data
+ * destroys the status of this char.
+ */
+ rr1 = zs_read_reg(cs, 1);
+ c = zs_read_data(cs);
+
+ if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
+ /* Clear the receive error. */
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
+ }
+ }
+}
+
+
+/*
+ * Write the given register set to the given zs channel in the proper order.
+ * The channel must not be transmitting at the time. The receiver will
+ * be disabled for the time it takes to write all the registers.
+ * Call this with interrupts disabled.
+ */
+void
+zs_loadchannelregs(struct zs_chanstate *cs)
+{
+ uint8_t *reg, v;
+
+ zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */
+
+#if 1
+ /*
+ * XXX: Is this really a good idea?
+ * XXX: Should go elsewhere! -gwr
+ */
+ zs_iflush(cs); /* XXX */
+#endif
+
+ if (cs->cs_ctl_chan != NULL)
+ v = ((cs->cs_ctl_chan->cs_creg[5] & (ZSWR5_RTS | ZSWR5_DTR)) !=
+ (cs->cs_ctl_chan->cs_preg[5] & (ZSWR5_RTS | ZSWR5_DTR)));
+ else
+ v = 0;
+
+ if (memcmp((void *)cs->cs_preg, (void *)cs->cs_creg, 16) == 0 && !v)
+ return; /* only change if values are different */
+
+ /* Copy "pending" regs to "current" */
+ memcpy((void *)cs->cs_creg, (void *)cs->cs_preg, 16);
+ reg = cs->cs_creg; /* current regs */
+
+ /* disable interrupts */
+ zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK);
+
+ /* baud clock divisor, stop bits, parity */
+ zs_write_reg(cs, 4, reg[4]);
+
+ /* misc. TX/RX control bits */
+ zs_write_reg(cs, 10, reg[10]);
+
+ /* char size, enable (RX/TX) */
+ zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE);
+ zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE);
+
+ /* synchronous mode stuff */
+ zs_write_reg(cs, 6, reg[6]);
+ zs_write_reg(cs, 7, reg[7]);
+
+#if 0
+ /*
+ * Registers 2 and 9 are special because they are
+ * actually common to both channels, but must be
+ * programmed through channel A. The "zsc" attach
+ * function takes care of setting these registers
+ * and they should not be touched thereafter.
+ */
+ /* interrupt vector */
+ zs_write_reg(cs, 2, reg[2]);
+ /* master interrupt control */
+ zs_write_reg(cs, 9, reg[9]);
+#endif
+
+ /* Shut down the BRG */
+ zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA);
+
+#ifdef ZS_MD_SETCLK
+ /* Let the MD code setup any external clock. */
+ ZS_MD_SETCLK(cs);
+#endif /* ZS_MD_SETCLK */
+
+ /* clock mode control */
+ zs_write_reg(cs, 11, reg[11]);
+
+ /* baud rate (lo/hi) */
+ zs_write_reg(cs, 12, reg[12]);
+ zs_write_reg(cs, 13, reg[13]);
+
+ /* Misc. control bits */
+ zs_write_reg(cs, 14, reg[14]);
+
+ /* which lines cause status interrupts */
+ zs_write_reg(cs, 15, reg[15]);
+
+ /*
+ * Zilog docs recommend resetting external status twice at this
+ * point. Mainly as the status bits are latched, and the first
+ * interrupt clear might unlatch them to new values, generating
+ * a second interrupt request.
+ */
+ zs_write_csr(cs, ZSM_RESET_STINT);
+ zs_write_csr(cs, ZSM_RESET_STINT);
+
+ /* char size, enable (RX/TX)*/
+ zs_write_reg(cs, 3, reg[3]);
+ zs_write_reg(cs, 5, reg[5]);
+
+ /* Write the status bits on the alternate channel also. */
+ if (cs->cs_ctl_chan != NULL) {
+ v = cs->cs_ctl_chan->cs_preg[5];
+ cs->cs_ctl_chan->cs_creg[5] = v;
+ zs_write_reg(cs->cs_ctl_chan, 5, v);
+ }
+
+ /* interrupt enables: RX, TX, STATUS */
+ zs_write_reg(cs, 1, reg[1]);
+}
+
+/*
+ * ZS hardware interrupt. Scan all ZS channels. NB: we know here that
+ * channels are kept in (A,B) pairs.
+ *
+ * Do just a little, then get out; set a software interrupt if more
+ * work is needed.
+ *
+ * We deliberately ignore the vectoring Zilog gives us, and match up
+ * only the number of `reset interrupt under service' operations, not
+ * the order.
+ */
+int
+zsc_intr_hard(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ struct zs_chanstate *cs0, *cs1;
+ int handled;
+ uint8_t rr3;
+
+ handled = 0;
+
+ /* First look at channel A. */
+ cs0 = zsc->zsc_cs[0];
+ cs1 = zsc->zsc_cs[1];
+
+ /*
+ * We have to clear interrupt first to avoid a race condition,
+ * but it will be done in each MD handler.
+ */
+ for (;;) {
+ /* Note: only channel A has an RR3 */
+ rr3 = zs_read_reg(cs0, 3);
+
+ if ((rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT |
+ ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) == 0) {
+ break;
+ }
+ handled = 1;
+
+ /* First look at channel A. */
+ if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT))
+ zs_write_csr(cs0, ZSWR0_CLR_INTR);
+
+ if (rr3 & ZSRR3_IP_A_RX)
+ (*cs0->cs_ops->zsop_rxint)(cs0);
+ if (rr3 & ZSRR3_IP_A_STAT)
+ (*cs0->cs_ops->zsop_stint)(cs0, 0);
+ if (rr3 & ZSRR3_IP_A_TX)
+ (*cs0->cs_ops->zsop_txint)(cs0);
+
+ /* Now look at channel B. */
+ if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT))
+ zs_write_csr(cs1, ZSWR0_CLR_INTR);
+
+ if (rr3 & ZSRR3_IP_B_RX)
+ (*cs1->cs_ops->zsop_rxint)(cs1);
+ if (rr3 & ZSRR3_IP_B_STAT)
+ (*cs1->cs_ops->zsop_stint)(cs1, 0);
+ if (rr3 & ZSRR3_IP_B_TX)
+ (*cs1->cs_ops->zsop_txint)(cs1);
+ }
+
+ /* Note: caller will check cs_x->cs_softreq and DTRT. */
+ return handled;
+}
+
+
+/*
+ * ZS software interrupt. Scan all channels for deferred interrupts.
+ */
+int
+zsc_intr_soft(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ struct zs_chanstate *cs;
+ int rval, chan;
+
+ rval = 0;
+ for (chan = 0; chan < 2; chan++) {
+ cs = zsc->zsc_cs[chan];
+
+ /*
+ * The softint flag can be safely cleared once
+ * we have decided to call the softint routine.
+ * (No need to do splzs() first.)
+ */
+ if (cs->cs_softreq) {
+ cs->cs_softreq = 0;
+ (*cs->cs_ops->zsop_softint)(cs);
+ rval++;
+ }
+ }
+ return (rval);
+}
+
+/*
+ * Provide a null zs "ops" vector.
+ */
+
+static void zsnull_rxint (struct zs_chanstate *);
+static void zsnull_stint (struct zs_chanstate *, int);
+static void zsnull_txint (struct zs_chanstate *);
+static void zsnull_softint(struct zs_chanstate *);
+
+static void
+zsnull_rxint(struct zs_chanstate *cs)
+{
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+static void
+zsnull_stint(struct zs_chanstate *cs, int force)
+{
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+static void
+zsnull_txint(struct zs_chanstate *cs)
+{
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+static void
+zsnull_softint(struct zs_chanstate *cs)
+{
+
+ zs_write_reg(cs, 1, 0);
+ zs_write_reg(cs, 15, 0);
+}
+
+struct zsops zsops_null = {
+ zsnull_rxint, /* receive char available */
+ zsnull_stint, /* external/status */
+ zsnull_txint, /* xmit buffer empty */
+ zsnull_softint, /* process software interrupt */
+};
diff --git a/sys/arch/sgi/hpc/z8530sc.h b/sys/arch/sgi/hpc/z8530sc.h
new file mode 100644
index 00000000000..d4b707ad518
--- /dev/null
+++ b/sys/arch/sgi/hpc/z8530sc.h
@@ -0,0 +1,199 @@
+/* $OpenBSD: z8530sc.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530sc.h,v 1.26 2009/05/22 03:51:30 mrg Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Function vector - per channel
+ */
+struct zs_chanstate;
+struct zsops {
+ void (*zsop_rxint)(struct zs_chanstate *);
+ /* receive char available */
+ void (*zsop_stint)(struct zs_chanstate *, int);
+ /* external/status */
+ void (*zsop_txint)(struct zs_chanstate *);
+ /* xmit buffer empty */
+ void (*zsop_softint)(struct zs_chanstate *);
+ /* process software interrupt */
+};
+
+extern struct zsops zsops_null;
+
+
+/*
+ * Software state, per zs channel.
+ */
+struct zs_chanstate {
+
+ /* Pointers to the device registers. */
+ volatile uint8_t *cs_reg_csr; /* ctrl, status, and reg. number. */
+ volatile uint8_t *cs_reg_data; /* data or numbered register */
+
+ int cs_channel; /* sub-unit number */
+ void *cs_private; /* sub-driver data pointer */
+ struct zsops *cs_ops;
+
+ int cs_brg_clk; /* BAUD Rate Generator clock
+ * (usually PCLK / 16) */
+ int cs_defspeed; /* default baud rate */
+ int cs_defcflag; /* default cflag */
+
+ /*
+ * We must keep a copy of the write registers as they are
+ * mostly write-only and we sometimes need to set and clear
+ * individual bits (e.g., in WR3). Not all of these are
+ * needed but 16 bytes is cheap and this makes the addressing
+ * simpler. Unfortunately, we can only write to some registers
+ * when the chip is not actually transmitting, so whenever
+ * we are expecting a `transmit done' interrupt the preg array
+ * is allowed to `get ahead' of the current values. In a
+ * few places we must change the current value of a register,
+ * rather than (or in addition to) the pending value; for these
+ * cs_creg[] contains the current value.
+ */
+ uint8_t cs_creg[16]; /* current values */
+ uint8_t cs_preg[16]; /* pending values */
+ int cs_heldchange; /* change pending (creg != preg) */
+
+ uint8_t cs_rr0; /* last rr0 processed */
+ uint8_t cs_rr0_delta; /* rr0 changes at status intr. */
+ uint8_t cs_rr0_mask; /* rr0 bits that stop output */
+ uint8_t cs_rr0_dcd; /* which bit to read as DCD */
+ uint8_t cs_rr0_cts; /* which bit to read as CTS */
+ uint8_t cs_rr0_pps; /* which bit to use for PPS */
+ /* the above is set only while CRTSCTS is enabled. */
+
+ uint8_t cs_wr5_dtr; /* which bit to write as DTR */
+ uint8_t cs_wr5_rts; /* which bit to write as RTS */
+ /* the above is set only while CRTSCTS is enabled. */
+
+ volatile uint8_t cs_softreq; /* need soft interrupt call */
+ char cs_cua; /* CUA mode flag */
+
+ /*
+ * For strange systems that have oddly wired serial ports, we
+ * provide a pointer to the channel state of the port that has
+ * our status lines on it.
+ */
+ struct zs_chanstate *cs_ctl_chan;
+
+ /* power management hooks */
+ int (*enable)(struct zs_chanstate *);
+ void (*disable)(struct zs_chanstate *);
+ int enabled;
+
+ /* MD code might define a larger variant of this. */
+};
+
+struct consdev;
+struct zsc_attach_args {
+ int channel; /* two serial channels per zsc */
+ int hwflags; /* see definitions below */
+ /* `consdev' is only valid if ZS_HWFLAG_USE_CONSDEV is set */
+ struct consdev *consdev;
+};
+
+/* In case of split console devices, use these: */
+#define ZS_HWFLAG_CONSOLE_INPUT 1
+#define ZS_HWFLAG_CONSOLE_OUTPUT 2
+#define ZS_HWFLAG_CONSOLE \
+ (ZS_HWFLAG_CONSOLE_INPUT | ZS_HWFLAG_CONSOLE_OUTPUT)
+#define ZS_HWFLAG_NO_DCD 4 /* Ignore the DCD bit */
+#define ZS_HWFLAG_NO_CTS 8 /* Ignore the CTS bit */
+#define ZS_HWFLAG_RAW 16 /* advise raw mode */
+#define ZS_HWFLAG_USE_CONSDEV 32 /* Use console ops from `consdev' */
+#define ZS_HWFLAG_NORESET 64 /* Don't reset at attach time */
+
+extern int zs_major;
+
+int zsc_intr_soft(void *);
+int zsc_intr_hard(void *);
+
+void zs_abort(struct zs_chanstate *);
+void zs_break(struct zs_chanstate *, int);
+void zs_iflush(struct zs_chanstate *);
+void zs_loadchannelregs(struct zs_chanstate *);
+int zs_set_speed(struct zs_chanstate *, int);
+int zs_set_modes(struct zs_chanstate *, int);
diff --git a/sys/arch/sgi/hpc/z8530tty.c b/sys/arch/sgi/hpc/z8530tty.c
new file mode 100644
index 00000000000..4108ed6ea10
--- /dev/null
+++ b/sys/arch/sgi/hpc/z8530tty.c
@@ -0,0 +1,1663 @@
+/* $OpenBSD: z8530tty.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530tty.c,v 1.128 2011/04/24 16:27:00 rmind Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999
+ * Charles M. Hannum. 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 Charles M. Hannum.
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (tty interface)
+ *
+ * This is the "slave" driver that will be attached to
+ * the "zsc" driver for plain "tty" async. serial lines.
+ *
+ * Credits, history:
+ *
+ * The original version of this code was the sparc/dev/zs.c driver
+ * as distributed with the Berkeley 4.4 Lite release. Since then,
+ * Gordon Ross reorganized the code into the current parent/child
+ * driver scheme, separating the Sun keyboard and mouse support
+ * into independent child drivers.
+ *
+ * RTS/CTS flow-control support was a collaboration of:
+ * Gordon Ross <gwr@NetBSD.org>,
+ * Bill Studenmund <wrstuden@loki.stanford.edu>
+ * Ian Dall <Ian.Dall@dsto.defence.gov.au>
+ *
+ * The driver was massively overhauled in November 1997 by Charles Hannum,
+ * fixing *many* bugs, and substantially improving performance.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <dev/ic/z8530reg.h>
+#include <machine/z8530var.h>
+
+#include <dev/cons.h>
+
+/*
+ * How many input characters we can buffer.
+ * The port-specific var.h may override this.
+ * Note: must be a power of two!
+ */
+#ifndef ZSTTY_RING_SIZE
+#define ZSTTY_RING_SIZE 2048
+#endif
+
+struct cfdriver zstty_cd = {
+ NULL, "zstty", DV_TTY
+};
+
+/*
+ * Make this an option variable one can patch.
+ * But be warned: this must be a power of 2!
+ */
+u_int zstty_rbuf_size = ZSTTY_RING_SIZE;
+
+/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
+u_int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE * 1) / 4;
+u_int zstty_rbuf_lowat = (ZSTTY_RING_SIZE * 3) / 4;
+
+struct zstty_softc {
+ struct device zst_dev; /* required first: base device */
+ struct tty *zst_tty;
+ struct zs_chanstate *zst_cs;
+
+ struct timeout zst_diag_ch;
+
+ u_int zst_overflows,
+ zst_floods,
+ zst_errors;
+
+ int zst_hwflags, /* see z8530var.h */
+ zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */
+
+ u_int zst_r_hiwat,
+ zst_r_lowat;
+ uint8_t *volatile zst_rbget,
+ *volatile zst_rbput;
+ volatile u_int zst_rbavail;
+ uint8_t *zst_rbuf,
+ *zst_ebuf;
+
+ /*
+ * The transmit byte count and address are used for pseudo-DMA
+ * output in the hardware interrupt code. PDMA can be suspended
+ * to get pending changes done; heldtbc is used for this. It can
+ * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state.
+ */
+ uint8_t *zst_tba; /* transmit buffer address */
+ u_int zst_tbc, /* transmit byte count */
+ zst_heldtbc; /* held tbc while xmission stopped */
+
+ /* Flags to communicate with zstty_softint() */
+ volatile uint8_t zst_rx_flags, /* receiver blocked */
+#define RX_TTY_BLOCKED 0x01
+#define RX_TTY_OVERFLOWED 0x02
+#define RX_IBUF_BLOCKED 0x04
+#define RX_IBUF_OVERFLOWED 0x08
+#define RX_ANY_BLOCK 0x0f
+ zst_tx_busy, /* working on an output chunk */
+ zst_tx_done, /* done with one output chunk */
+ zst_tx_stopped, /* H/W level stop (lost CTS) */
+ zst_st_check, /* got a status interrupt */
+ zst_rx_ready;
+
+ /* PPS signal on DCD, with or without inkernel clock disciplining */
+ uint8_t zst_ppsmask; /* pps signal mask */
+ uint8_t zst_ppsassert; /* pps leading edge */
+ uint8_t zst_ppsclear; /* pps trailing edge */
+};
+
+/* Definition of the driver for autoconfig. */
+int zstty_match(struct device *, void *, void *);
+void zstty_attach(struct device *, struct device *, void *);
+
+const struct cfattach zstty_ca = {
+ sizeof(struct zstty_softc), zstty_match, zstty_attach
+};
+
+cdev_decl(zs);
+
+struct zsops zsops_tty;
+
+void zs_shutdown(struct zstty_softc *);
+void zsstart(struct tty *);
+int zsparam(struct tty *, struct termios *);
+void zs_modem(struct zstty_softc *, int);
+void tiocm_to_zs(struct zstty_softc *, u_long, int);
+int zs_to_tiocm(struct zstty_softc *);
+int zshwiflow(struct tty *, int);
+void zs_hwiflow(struct zstty_softc *);
+void zs_maskintr(struct zstty_softc *);
+
+struct zstty_softc *zs_device_lookup(struct cfdriver *, int);
+
+/* Low-level routines. */
+void zstty_rxint (struct zs_chanstate *);
+void zstty_stint (struct zs_chanstate *, int);
+void zstty_txint (struct zs_chanstate *);
+void zstty_softint(struct zs_chanstate *);
+void zstty_diag(void *);
+
+#define ZSUNIT(x) (minor(x) & 0x7f)
+#define ZSDIALOUT(x) (minor(x) & 0x80)
+
+struct zstty_softc *
+zs_device_lookup(struct cfdriver *cf, int unit)
+{
+ return (struct zstty_softc *)device_lookup(cf, unit);
+}
+
+/*
+ * zstty_match: how is this zs channel configured?
+ */
+int
+zstty_match(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = vcf;
+ struct zsc_attach_args *args = aux;
+
+ /* Exact match is better than wildcard. */
+ if (cf->cf_loc[0] == args->channel)
+ return 2;
+
+ /* This driver accepts wildcard. */
+ if (cf->cf_loc[0] == -1)
+ return 1;
+
+ return 0;
+}
+
+void
+zstty_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct zsc_softc *zsc = (struct zsc_softc *)parent;
+ struct zstty_softc *zst = (struct zstty_softc *)self;
+ struct cfdata *cf = self->dv_cfdata;
+ struct zsc_attach_args *args = aux;
+ struct zs_chanstate *cs;
+ struct tty *tp;
+ int channel, s, tty_unit;
+ dev_t dev;
+ const char *i, *o;
+ int dtr_on;
+ int resetbit;
+
+ timeout_set(&zst->zst_diag_ch, zstty_diag, zst);
+
+ tty_unit = zst->zst_dev.dv_unit;
+ channel = args->channel;
+ cs = zsc->zsc_cs[channel];
+ cs->cs_private = zst;
+ cs->cs_ops = &zsops_tty;
+
+ zst->zst_cs = cs;
+ zst->zst_swflags = cf->cf_flags; /* softcar, etc. */
+ zst->zst_hwflags = args->hwflags;
+ dev = makedev(zs_major, tty_unit);
+
+ if (zst->zst_swflags)
+ printf(" flags 0x%x", zst->zst_swflags);
+
+ /*
+ * Check whether we serve as a console device.
+ * XXX - split console input/output channels aren't
+ * supported yet on /dev/console
+ */
+ i = o = NULL;
+ if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) {
+ i = " input";
+ if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) {
+ args->consdev->cn_dev = dev;
+ cn_tab->cn_pollc = args->consdev->cn_pollc;
+ cn_tab->cn_getc = args->consdev->cn_getc;
+ }
+ cn_tab->cn_dev = dev;
+ }
+ if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) {
+ o = " output";
+ if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) {
+ cn_tab->cn_putc = args->consdev->cn_putc;
+ }
+ cn_tab->cn_dev = dev;
+ }
+ if (i != NULL || o != NULL)
+ printf(": console%s", i ? (o ? "" : i) : o);
+
+#ifdef KGDB
+ if (zs_check_kgdb(cs, dev)) {
+ /*
+ * Allow kgdb to "take over" this port. Returns true
+ * if this serial port is in-use by kgdb.
+ */
+ printf(" (kgdb)\n");
+ /*
+ * This is the kgdb port (exclusive use)
+ * so skip the normal attach code.
+ */
+ return;
+ }
+#endif
+
+ printf("\n");
+
+ tp = ttymalloc(0);
+ tp->t_dev = dev;
+ tp->t_oproc = zsstart;
+ tp->t_param = zsparam;
+ tp->t_hwiflow = zshwiflow;
+
+ zst->zst_tty = tp;
+ zst->zst_rbuf = malloc(zstty_rbuf_size << 1, M_DEVBUF, M_WAITOK);
+ zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size << 1);
+ /* Disable the high water mark. */
+ zst->zst_r_hiwat = 0;
+ zst->zst_r_lowat = 0;
+ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
+ zst->zst_rbavail = zstty_rbuf_size;
+
+ /* if there are no enable/disable functions, assume the device
+ is always enabled */
+ if (!cs->enable)
+ cs->enabled = 1;
+
+ /*
+ * Hardware init
+ */
+ dtr_on = 0;
+ resetbit = 0;
+ if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ /* Call zsparam similar to open. */
+ struct termios t;
+
+ /* Wait a while for previous console output to complete */
+ DELAY(10000);
+
+ /* Setup the "new" parameters in t. */
+ t.c_ispeed = 0;
+ t.c_ospeed = cs->cs_defspeed;
+ t.c_cflag = cs->cs_defcflag;
+
+ s = splzs();
+
+ /*
+ * Turn on receiver and status interrupts.
+ * We defer the actual write of the register to zsparam(),
+ * but we must make sure status interrupts are turned on by
+ * the time zsparam() reads the initial rr0 state.
+ */
+ SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
+
+ splx(s);
+
+ /* Make sure zsparam will see changes. */
+ tp->t_ospeed = 0;
+ (void)zsparam(tp, &t);
+
+ /* Make sure DTR is on now. */
+ dtr_on = 1;
+ } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) {
+ /* Not the console; may need reset. */
+ resetbit = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET;
+ }
+
+ s = splzs();
+ if (resetbit)
+ zs_write_reg(cs, 9, resetbit);
+ zs_modem(zst, dtr_on);
+ splx(s);
+}
+
+
+/*
+ * Return pointer to our tty.
+ */
+struct tty *
+zstty(dev_t dev)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+
+ return (zst->zst_tty);
+}
+
+
+void
+zs_shutdown(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ s = splzs();
+
+ /* If we were asserting flow control, then deassert it. */
+ SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+
+ /* Clear any break condition set with TIOCSBRK. */
+ zs_break(cs, 0);
+
+ /* Turn off PPS capture on last close. */
+ zst->zst_ppsmask = 0;
+
+ /*
+ * Hang up if necessary. Wait a bit, so the other side has time to
+ * notice even if we immediately open the port again.
+ */
+ if (ISSET(tp->t_cflag, HUPCL) || ISSET(tp->t_state, TS_WOPEN)) {
+ zs_modem(zst, 0);
+ /* hold low for 1 second */
+ (void)tsleep(cs, TTIPRI, ttclos, hz);
+ }
+
+ /* Turn off interrupts if not the console. */
+ if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+
+ /* Call the power management hook. */
+ if (cs->disable) {
+#ifdef DIAGNOSTIC
+ if (!cs->enabled)
+ panic("%s: not enabled?", __func__);
+#endif
+ (*cs->disable)(zst->zst_cs);
+ }
+
+ splx(s);
+}
+
+/*
+ * Open a zs serial (tty) port.
+ */
+int
+zsopen(dev_t dev, int flags, int mode, struct proc *p)
+{
+ struct zstty_softc *zst;
+ struct zs_chanstate *cs;
+ struct tty *tp;
+ int s, s2;
+ int error;
+
+ zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ if (zst == NULL)
+ return (ENXIO);
+
+ tp = zst->zst_tty;
+ cs = zst->zst_cs;
+
+ /* If KGDB took the line, then tp==NULL */
+ if (tp == NULL)
+ return (EBUSY);
+
+ if (ISSET(tp->t_state, TS_ISOPEN) &&
+ ISSET(tp->t_state, TS_XCLUDE) &&
+ suser(p, 0) != 0)
+ return (EBUSY);
+
+ s = spltty();
+
+ /*
+ * Do the following iff this is a first open.
+ */
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ struct termios t;
+
+ tp->t_dev = dev;
+
+ /* Call the power management hook. */
+ if (cs->enable) {
+ if ((*cs->enable)(cs)) {
+ splx(s);
+ printf("%s: device enable failed\n",
+ zst->zst_dev.dv_xname);
+ return (EIO);
+ }
+ }
+
+ /*
+ * Initialize the termios status to the defaults. Add in the
+ * sticky bits from TIOCSFLAGS.
+ */
+ t.c_ispeed = 0;
+ t.c_ospeed = cs->cs_defspeed;
+ t.c_cflag = cs->cs_defcflag;
+ if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL))
+ SET(t.c_cflag, CLOCAL);
+ if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS))
+ SET(t.c_cflag, CRTSCTS);
+ if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF))
+ SET(t.c_cflag, MDMBUF);
+
+ s2 = splzs();
+
+ /*
+ * Turn on receiver and status interrupts.
+ * We defer the actual write of the register to zsparam(),
+ * but we must make sure status interrupts are turned on by
+ * the time zsparam() reads the initial rr0 state.
+ */
+ SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
+
+ /* Clear PPS capture state on first open. */
+ zst->zst_ppsmask = 0;
+
+ splx(s2);
+
+ /* Make sure zsparam will see changes. */
+ tp->t_ospeed = 0;
+ (void)zsparam(tp, &t);
+
+ /*
+ * Note: zsparam has done: cflag, ispeed, ospeed
+ * so we just need to do: iflag, oflag, lflag, cc
+ * For "raw" mode, just leave all zeros.
+ */
+ if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) {
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ } else {
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_lflag = 0;
+ }
+ ttychars(tp);
+ ttsetwater(tp);
+
+ if (ZSDIALOUT(dev))
+ SET(tp->t_state, TS_CARR_ON);
+ else
+ CLR(tp->t_state, TS_CARR_ON);
+
+ s2 = splzs();
+
+ /* Clear the input ring, and unblock. */
+ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
+ zst->zst_rbavail = zstty_rbuf_size;
+ zs_iflush(cs);
+ CLR(zst->zst_rx_flags, RX_ANY_BLOCK);
+ zs_hwiflow(zst);
+
+ splx(s2);
+ }
+
+ if (ZSDIALOUT(dev)) {
+ if (ISSET(tp->t_state, TS_ISOPEN)) {
+ /* someone already is dialed in... */
+ splx(s);
+ return EBUSY;
+ }
+ cs->cs_cua = 1;
+ }
+
+ error = 0;
+ /* wait for carrier if necessary */
+ if (ISSET(flags, O_NONBLOCK)) {
+ if (!ZSDIALOUT(dev) && cs->cs_cua) {
+ /* Opening TTY non-blocking... but the CUA is busy */
+ error = EBUSY;
+ }
+ } else
+ while (cs->cs_cua ||
+ (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON))) {
+ int rr0;
+
+ error = 0;
+ SET(tp->t_state, TS_WOPEN);
+
+ if (!ZSDIALOUT(dev) && !cs->cs_cua) {
+ /*
+ * Turn on DTR. We must always do this on non-CUA
+ * devices, even if carrier is not present, because
+ * otherwise we'd have to use TIOCSDTR immediately
+ * after setting CLOCAL, which applications do not
+ * expect. We always assert DTR while the device is
+ * open unless explicitly requested to deassert it.
+ */
+ s2 = splzs();
+ zs_modem(zst, 1);
+ rr0 = zs_read_csr(cs);
+ splx(s2);
+
+ /* loop, turning on the device, until carrier present */
+ if (ISSET(rr0, ZSRR0_DCD) ||
+ ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR))
+ SET(tp->t_state, TS_CARR_ON);
+ }
+
+ if ((ISSET(tp->t_cflag, CLOCAL) ||
+ ISSET(tp->t_state, TS_CARR_ON)) && !cs->cs_cua)
+ break;
+
+ error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0);
+
+ if (!ZSDIALOUT(dev) && cs->cs_cua && error == EINTR) {
+ error = 0;
+ continue;
+ }
+
+ if (error) {
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ s2 = splzs();
+ zs_modem(zst, 0);
+ splx(s2);
+ CLR(tp->t_state, TS_WOPEN);
+ ttwakeup(tp);
+ }
+ if (ZSDIALOUT(dev))
+ cs->cs_cua = 0;
+ CLR(tp->t_state, TS_WOPEN);
+ break;
+ }
+ if (!ZSDIALOUT(dev) && cs->cs_cua)
+ continue;
+ }
+
+ splx(s);
+
+ if (error == 0)
+ error = ((*linesw[tp->t_line].l_open)(dev, tp, p));
+ if (error)
+ goto bad;
+
+ return (0);
+
+bad:
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ /*
+ * We failed to open the device, and nobody else had it opened.
+ * Clean up the state as appropriate.
+ */
+ zs_shutdown(zst);
+ }
+
+ return (error);
+}
+
+/*
+ * Close a zs serial port.
+ */
+int
+zsclose(dev_t dev, int flags, int mode, struct proc *p)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flags, p);
+
+ s = spltty();
+ cs->cs_cua = 0;
+ ttyclose(tp);
+ splx(s);
+
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ /*
+ * Although we got a last close, the device may still be in
+ * use; e.g. if this was the dialout node, and there are still
+ * processes waiting for carrier on the non-dialout node.
+ */
+ zs_shutdown(zst);
+ }
+
+ return (0);
+}
+
+/*
+ * Read/write zs serial port.
+ */
+int
+zsread(dev_t dev, struct uio *uio, int flags)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct tty *tp = zst->zst_tty;
+
+ return (*linesw[tp->t_line].l_read)(tp, uio, flags);
+}
+
+int
+zswrite(dev_t dev, struct uio *uio, int flags)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct tty *tp = zst->zst_tty;
+
+ return (*linesw[tp->t_line].l_write)(tp, uio, flags);
+}
+
+int
+zsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int error;
+ int s;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+#ifdef ZS_MD_IOCTL
+ error = ZS_MD_IOCTL;
+ if (error >= 0)
+ return (error);
+#endif /* ZS_MD_IOCTL */
+
+ error = 0;
+
+ s = splzs();
+
+ switch (cmd) {
+ case TIOCSBRK:
+ zs_break(cs, 1);
+ break;
+
+ case TIOCCBRK:
+ zs_break(cs, 0);
+ break;
+
+ case TIOCGFLAGS:
+ *(int *)data = zst->zst_swflags;
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p, 0);
+ if (error)
+ break;
+ zst->zst_swflags = *(int *)data;
+ break;
+
+ case TIOCSDTR:
+ zs_modem(zst, 1);
+ break;
+
+ case TIOCCDTR:
+ zs_modem(zst, 0);
+ break;
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ tiocm_to_zs(zst, cmd, *(int *)data);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = zs_to_tiocm(zst);
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ splx(s);
+
+ return (error);
+}
+
+/*
+ * Start or restart transmission.
+ */
+void
+zsstart(struct tty *tp)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ u_char *tba;
+ int tbc;
+ int s;
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (zst->zst_tx_stopped)
+ goto out;
+
+ ttwakeupwr(tp);
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+
+ /* Grab the first contiguous region of buffer space. */
+ tba = tp->t_outq.c_cf;
+ tbc = ndqb(&tp->t_outq, 0);
+
+ (void)splzs();
+
+ zst->zst_tba = tba;
+ zst->zst_tbc = tbc;
+ SET(tp->t_state, TS_BUSY);
+ zst->zst_tx_busy = 1;
+
+ /* Enable transmit completion interrupts if necessary. */
+ if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
+ SET(cs->cs_preg[1], ZSWR1_TIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+
+ /* Output the first character of the contiguous buffer. */
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tbc--;
+ zst->zst_tba++;
+
+out:
+ splx(s);
+}
+
+/*
+ * Stop output, e.g., for ^S or output flush.
+ */
+int
+zsstop(struct tty *tp, int flag)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ int s;
+
+ s = splzs();
+ if (ISSET(tp->t_state, TS_BUSY)) {
+ /* Stop transmitting at the next chunk. */
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0;
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ }
+ splx(s);
+ return 0;
+}
+
+/*
+ * Set ZS tty parameters from termios.
+ * XXX - Should just copy the whole termios after
+ * making sure all the changes could be done.
+ */
+int
+zsparam(struct tty *tp, struct termios *t)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ int ospeed;
+ tcflag_t cflag;
+ uint8_t tmp3, tmp4, tmp5;
+ int s, error;
+
+ ospeed = t->c_ospeed;
+ cflag = t->c_cflag;
+
+ /* Check requested parameters. */
+ if (ospeed < 0)
+ return (EINVAL);
+ if (t->c_ispeed && t->c_ispeed != ospeed)
+ return (EINVAL);
+
+ /*
+ * For the console, always force CLOCAL and !HUPCL, so that the port
+ * is always active.
+ */
+ if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) ||
+ ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ SET(cflag, CLOCAL);
+ CLR(cflag, HUPCL);
+ }
+
+ /*
+ * Only whack the UART when params change.
+ * Some callers need to clear tp->t_ospeed
+ * to make sure initialization gets done.
+ */
+ if (tp->t_ospeed == ospeed &&
+ tp->t_cflag == cflag)
+ return (0);
+
+ /*
+ * Call MD functions to deal with changed
+ * clock modes or H/W flow control modes.
+ * The BRG divisor is set now. (reg 12,13)
+ */
+ error = zs_set_speed(cs, ospeed);
+ if (error)
+ return (error);
+ error = zs_set_modes(cs, cflag);
+ if (error)
+ return (error);
+
+ /*
+ * Block interrupts so that state will not
+ * be altered until we are done setting it up.
+ *
+ * Initial values in cs_preg are set before
+ * our attach routine is called. The master
+ * interrupt enable is handled by zsc.c
+ *
+ */
+ s = splzs();
+
+ /*
+ * Recalculate which status ints to enable.
+ */
+ zs_maskintr(zst);
+
+ /* Recompute character size bits. */
+ tmp3 = cs->cs_preg[3];
+ tmp5 = cs->cs_preg[5];
+ CLR(tmp3, ZSWR3_RXSIZE);
+ CLR(tmp5, ZSWR5_TXSIZE);
+ switch (ISSET(cflag, CSIZE)) {
+ case CS5:
+ SET(tmp3, ZSWR3_RX_5);
+ SET(tmp5, ZSWR5_TX_5);
+ break;
+ case CS6:
+ SET(tmp3, ZSWR3_RX_6);
+ SET(tmp5, ZSWR5_TX_6);
+ break;
+ case CS7:
+ SET(tmp3, ZSWR3_RX_7);
+ SET(tmp5, ZSWR5_TX_7);
+ break;
+ case CS8:
+ SET(tmp3, ZSWR3_RX_8);
+ SET(tmp5, ZSWR5_TX_8);
+ break;
+ }
+ cs->cs_preg[3] = tmp3;
+ cs->cs_preg[5] = tmp5;
+
+ /*
+ * Recompute the stop bits and parity bits. Note that
+ * zs_set_speed() may have set clock selection bits etc.
+ * in wr4, so those must preserved.
+ */
+ tmp4 = cs->cs_preg[4];
+ CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK);
+ if (ISSET(cflag, CSTOPB))
+ SET(tmp4, ZSWR4_TWOSB);
+ else
+ SET(tmp4, ZSWR4_ONESB);
+ if (!ISSET(cflag, PARODD))
+ SET(tmp4, ZSWR4_EVENP);
+ if (ISSET(cflag, PARENB))
+ SET(tmp4, ZSWR4_PARENB);
+ cs->cs_preg[4] = tmp4;
+
+ /* And copy to tty. */
+ tp->t_ispeed = 0;
+ tp->t_ospeed = ospeed;
+ tp->t_cflag = cflag;
+
+ /*
+ * If nothing is being transmitted, set up new current values,
+ * else mark them as pending.
+ */
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+
+ /*
+ * If hardware flow control is disabled, turn off the buffer water
+ * marks and unblock any soft flow control state. Otherwise, enable
+ * the water marks.
+ */
+ if (!ISSET(cflag, CHWFLOW)) {
+ zst->zst_r_hiwat = 0;
+ zst->zst_r_lowat = 0;
+ if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+ if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ } else {
+ zst->zst_r_hiwat = zstty_rbuf_hiwat;
+ zst->zst_r_lowat = zstty_rbuf_lowat;
+ }
+
+ /*
+ * Force a recheck of the hardware carrier and flow control status,
+ * since we may have changed which bits we're looking at.
+ */
+ zstty_stint(cs, 1);
+
+ splx(s);
+
+ /*
+ * If hardware flow control is disabled, unblock any hard flow control
+ * state.
+ */
+ if (!ISSET(cflag, CHWFLOW)) {
+ if (zst->zst_tx_stopped) {
+ zst->zst_tx_stopped = 0;
+ zsstart(tp);
+ }
+ }
+
+ zstty_softint(cs);
+
+ return (0);
+}
+
+/*
+ * Compute interrupt enable bits and set in the pending bits. Called both
+ * in zsparam() and when PPS (pulse per second timing) state changes.
+ * Must be called at splzs().
+ */
+void
+zs_maskintr(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ uint8_t tmp15;
+
+ cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd;
+ if (zst->zst_ppsmask != 0)
+ cs->cs_rr0_mask |= cs->cs_rr0_pps;
+ tmp15 = cs->cs_preg[15];
+ if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD))
+ SET(tmp15, ZSWR15_DCD_IE);
+ else
+ CLR(tmp15, ZSWR15_DCD_IE);
+ if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS))
+ SET(tmp15, ZSWR15_CTS_IE);
+ else
+ CLR(tmp15, ZSWR15_CTS_IE);
+ cs->cs_preg[15] = tmp15;
+}
+
+
+/*
+ * Raise or lower modem control (DTR/RTS) signals. If a character is
+ * in transmission, the change is deferred.
+ * Called at splzs().
+ */
+void
+zs_modem(struct zstty_softc *zst, int onoff)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+
+ if (cs->cs_wr5_dtr == 0)
+ return;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ if (onoff)
+ SET(ccs->cs_preg[5], cs->cs_wr5_dtr);
+ else
+ CLR(ccs->cs_preg[5], cs->cs_wr5_dtr);
+
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+}
+
+/*
+ * Set modem bits.
+ * Called at splzs().
+ */
+void
+tiocm_to_zs(struct zstty_softc *zst, u_long how, int ttybits)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+ uint8_t zsbits;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ zsbits = 0;
+ if (ISSET(ttybits, TIOCM_DTR))
+ SET(zsbits, ZSWR5_DTR);
+ if (ISSET(ttybits, TIOCM_RTS))
+ SET(zsbits, ZSWR5_RTS);
+
+ switch (how) {
+ case TIOCMBIC:
+ CLR(ccs->cs_preg[5], zsbits);
+ break;
+
+ case TIOCMBIS:
+ SET(ccs->cs_preg[5], zsbits);
+ break;
+
+ case TIOCMSET:
+ CLR(ccs->cs_preg[5], ZSWR5_RTS | ZSWR5_DTR);
+ SET(ccs->cs_preg[5], zsbits);
+ break;
+ }
+
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+}
+
+/*
+ * Get modem bits.
+ * Called at splzs().
+ */
+int
+zs_to_tiocm(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+ uint8_t zsbits;
+ int ttybits = 0;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ zsbits = ccs->cs_preg[5];
+ if (ISSET(zsbits, ZSWR5_DTR))
+ SET(ttybits, TIOCM_DTR);
+ if (ISSET(zsbits, ZSWR5_RTS))
+ SET(ttybits, TIOCM_RTS);
+
+ zsbits = cs->cs_rr0;
+ if (ISSET(zsbits, ZSRR0_DCD))
+ SET(ttybits, TIOCM_CD);
+ if (ISSET(zsbits, ZSRR0_CTS))
+ SET(ttybits, TIOCM_CTS);
+
+ return (ttybits);
+}
+
+/*
+ * Try to block or unblock input using hardware flow-control.
+ * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
+ * if this function returns non-zero, the TS_TBLOCK flag will
+ * be set or cleared according to the "block" arg passed.
+ */
+int
+zshwiflow(struct tty *tp, int block)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ int s;
+
+ if (cs->cs_wr5_rts == 0)
+ return (0);
+
+ s = splzs();
+ if (block) {
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ SET(zst->zst_rx_flags, RX_TTY_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ } else {
+ if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+ if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ }
+ splx(s);
+ return (1);
+}
+
+/*
+ * Internal version of zshwiflow
+ * Called at splzs()
+ */
+void
+zs_hwiflow(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+
+ if (cs->cs_wr5_rts == 0)
+ return;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) {
+ CLR(ccs->cs_preg[5], cs->cs_wr5_rts);
+ CLR(ccs->cs_creg[5], cs->cs_wr5_rts);
+ } else {
+ SET(ccs->cs_preg[5], cs->cs_wr5_rts);
+ SET(ccs->cs_creg[5], cs->cs_wr5_rts);
+ }
+ zs_write_reg(ccs, 5, ccs->cs_creg[5]);
+}
+
+
+/****************************************************************
+ * Interface to the lower layer (zscc)
+ ****************************************************************/
+
+#define integrate static inline
+integrate void zstty_rxsoft(struct zstty_softc *, struct tty *);
+integrate void zstty_txsoft(struct zstty_softc *, struct tty *);
+integrate void zstty_stsoft(struct zstty_softc *, struct tty *);
+void zstty_diag(void *);
+
+/*
+ * Receiver Ready interrupt.
+ * Called at splzs().
+ */
+void
+zstty_rxint(struct zs_chanstate *cs)
+{
+ struct zstty_softc *zst = cs->cs_private;
+ uint8_t *put, *end;
+ u_int cc;
+ uint8_t rr0, rr1, c;
+
+ end = zst->zst_ebuf;
+ put = zst->zst_rbput;
+ cc = zst->zst_rbavail;
+
+ while (cc > 0) {
+ /*
+ * First read the status, because reading the received char
+ * destroys the status of this char.
+ */
+ rr1 = zs_read_reg(cs, 1);
+ c = zs_read_data(cs);
+
+ if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
+ /* Clear the receive error. */
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
+ }
+
+ put[0] = c;
+ put[1] = rr1;
+ put += 2;
+ if (put >= end)
+ put = zst->zst_rbuf;
+ cc--;
+
+ rr0 = zs_read_csr(cs);
+ if (!ISSET(rr0, ZSRR0_RX_READY))
+ break;
+ }
+
+ /*
+ * Current string of incoming characters ended because
+ * no more data was available or we ran out of space.
+ * Schedule a receive event if any data was received.
+ * If we're out of space, turn off receive interrupts.
+ */
+ zst->zst_rbput = put;
+ zst->zst_rbavail = cc;
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+
+ /*
+ * See if we are in danger of overflowing a buffer. If
+ * so, use hardware flow control to ease the pressure.
+ */
+ if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) &&
+ cc < zst->zst_r_hiwat) {
+ SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+
+ /*
+ * If we're out of space, disable receive interrupts
+ * until the queue has drained a bit.
+ */
+ if (!cc) {
+ SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
+ CLR(cs->cs_preg[1], ZSWR1_RIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+}
+
+/*
+ * Transmitter Ready interrupt.
+ * Called at splzs().
+ */
+void
+zstty_txint(struct zs_chanstate *cs)
+{
+ struct zstty_softc *zst = cs->cs_private;
+
+ zs_write_csr(cs, ZSWR0_RESET_TXINT);
+
+ /*
+ * If we've delayed a parameter change, do it now, and restart
+ * output.
+ */
+ if (cs->cs_heldchange) {
+ zs_loadchannelregs(cs);
+ cs->cs_heldchange = 0;
+ zst->zst_tbc = zst->zst_heldtbc;
+ zst->zst_heldtbc = 0;
+ }
+
+ /* Output the next character in the buffer, if any. */
+ if (zst->zst_tbc > 0) {
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tbc--;
+ zst->zst_tba++;
+ } else {
+ /* Disable transmit completion interrupts if necessary. */
+ if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
+ CLR(cs->cs_preg[1], ZSWR1_TIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+ if (zst->zst_tx_busy) {
+ zst->zst_tx_busy = 0;
+ zst->zst_tx_done = 1;
+ cs->cs_softreq = 1;
+ }
+ }
+}
+
+#ifdef DDB
+#include <ddb/db_var.h>
+#define DB_CONSOLE db_console
+#else
+#define DB_CONSOLE 1
+#endif
+
+/*
+ * Status Change interrupt.
+ * Called at splzs().
+ */
+void
+zstty_stint(struct zs_chanstate *cs, int force)
+{
+ struct zstty_softc *zst = cs->cs_private;
+ struct tty *tp = zst->zst_tty;
+ uint8_t rr0, delta;
+
+ rr0 = zs_read_csr(cs);
+ zs_write_csr(cs, ZSWR0_RESET_STATUS);
+
+ /*
+ * Check here for console break, so that we can abort
+ * even when interrupts are locking up the machine.
+ */
+ if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) &&
+ ISSET(rr0, ZSRR0_BREAK) && DB_CONSOLE)
+ zs_abort(cs);
+
+ if (!force)
+ delta = rr0 ^ cs->cs_rr0;
+ else
+ delta = cs->cs_rr0_mask;
+
+ ttytstamp(tp, cs->cs_rr0 & ZSRR0_CTS, rr0 & ZSRR0_CTS,
+ cs->cs_rr0 & ZSRR0_DCD, rr0 & ZSRR0_DCD);
+
+ cs->cs_rr0 = rr0;
+
+ if (ISSET(delta, cs->cs_rr0_mask)) {
+ SET(cs->cs_rr0_delta, delta);
+
+ /*
+ * Stop output immediately if we lose the output
+ * flow control signal or carrier detect.
+ */
+ if (ISSET(~rr0, cs->cs_rr0_mask)) {
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0;
+ }
+
+ zst->zst_st_check = 1;
+ cs->cs_softreq = 1;
+ }
+}
+
+void
+zstty_diag(void *arg)
+{
+ struct zstty_softc *zst = arg;
+ int overflows, floods;
+ int s;
+
+ s = splzs();
+ overflows = zst->zst_overflows;
+ zst->zst_overflows = 0;
+ floods = zst->zst_floods;
+ zst->zst_floods = 0;
+ zst->zst_errors = 0;
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
+ zst->zst_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+integrate void
+zstty_rxsoft(struct zstty_softc *zst, struct tty *tp)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint;
+ uint8_t *get, *end;
+ u_int cc, scc;
+ uint8_t rr1;
+ int code;
+ int s;
+
+ end = zst->zst_ebuf;
+ get = zst->zst_rbget;
+ scc = cc = zstty_rbuf_size - zst->zst_rbavail;
+
+ if (cc == zstty_rbuf_size) {
+ zst->zst_floods++;
+ if (zst->zst_errors++ == 0)
+ timeout_add_sec(&zst->zst_diag_ch, 60);
+ }
+
+ /* If not yet open, drop the entire buffer content here */
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ get += cc << 1;
+ if (get >= end)
+ get -= zstty_rbuf_size << 1;
+ cc = 0;
+ }
+ while (cc) {
+ code = get[0];
+ rr1 = get[1];
+ if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) {
+ if (ISSET(rr1, ZSRR1_DO)) {
+ zst->zst_overflows++;
+ if (zst->zst_errors++ == 0)
+ timeout_add_sec(&zst->zst_diag_ch, 60);
+ }
+ if (ISSET(rr1, ZSRR1_FE))
+ SET(code, TTY_FE);
+ if (ISSET(rr1, ZSRR1_PE))
+ SET(code, TTY_PE);
+ }
+ if ((*rint)(code, tp) == -1) {
+ /*
+ * The line discipline's buffer is out of space.
+ */
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ /*
+ * We're either not using flow control, or the
+ * line discipline didn't tell us to block for
+ * some reason. Either way, we have no way to
+ * know when there's more space available, so
+ * just drop the rest of the data.
+ */
+ get += cc << 1;
+ if (get >= end)
+ get -= zstty_rbuf_size << 1;
+ cc = 0;
+ } else {
+ /*
+ * Don't schedule any more receive processing
+ * until the line discipline tells us there's
+ * space available (through comhwiflow()).
+ * Leave the rest of the data in the input
+ * buffer.
+ */
+ SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ }
+ break;
+ }
+ get += 2;
+ if (get >= end)
+ get = zst->zst_rbuf;
+ cc--;
+ }
+
+ if (cc != scc) {
+ zst->zst_rbget = get;
+ s = splzs();
+ cc = zst->zst_rbavail += scc - cc;
+ /* Buffers should be ok again, release possible block. */
+ if (cc >= zst->zst_r_lowat) {
+ if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
+ SET(cs->cs_preg[1], ZSWR1_RIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+ if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ }
+ splx(s);
+ }
+}
+
+integrate void
+zstty_txsoft(struct zstty_softc *zst, struct tty *tp)
+{
+ int s;
+
+ CLR(tp->t_state, TS_BUSY);
+ if (ISSET(tp->t_state, TS_FLUSH))
+ CLR(tp->t_state, TS_FLUSH);
+ else {
+ s = splzs();
+ ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf));
+ splx(s);
+ }
+ (*linesw[tp->t_line].l_start)(tp);
+}
+
+integrate void
+zstty_stsoft(struct zstty_softc *zst, struct tty *tp)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ uint8_t rr0, delta;
+ int s;
+
+ s = splzs();
+ rr0 = cs->cs_rr0;
+ delta = cs->cs_rr0_delta;
+ cs->cs_rr0_delta = 0;
+ splx(s);
+
+ if (ISSET(delta, cs->cs_rr0_dcd)) {
+ /*
+ * Inform the tty layer that carrier detect changed.
+ */
+ (void)(*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD));
+ }
+
+ if (ISSET(delta, cs->cs_rr0_cts)) {
+ /* Block or unblock output according to flow control. */
+ if (ISSET(rr0, cs->cs_rr0_cts)) {
+ zst->zst_tx_stopped = 0;
+ (*linesw[tp->t_line].l_start)(tp);
+ } else {
+ zst->zst_tx_stopped = 1;
+ }
+ }
+}
+
+/*
+ * Software interrupt. Called at zssoft
+ *
+ * The main job to be done here is to empty the input ring
+ * by passing its contents up to the tty layer. The ring is
+ * always emptied during this operation, therefore the ring
+ * must not be larger than the space after "high water" in
+ * the tty layer, or the tty layer might drop our input.
+ *
+ * Note: an "input blockage" condition is assumed to exist if
+ * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
+ */
+void
+zstty_softint(struct zs_chanstate *cs)
+{
+ struct zstty_softc *zst = cs->cs_private;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ s = spltty();
+
+ if (zst->zst_rx_ready) {
+ zst->zst_rx_ready = 0;
+ zstty_rxsoft(zst, tp);
+ }
+
+ if (zst->zst_st_check) {
+ zst->zst_st_check = 0;
+ zstty_stsoft(zst, tp);
+ }
+
+ if (zst->zst_tx_done) {
+ zst->zst_tx_done = 0;
+ zstty_txsoft(zst, tp);
+ }
+
+ splx(s);
+}
+
+struct zsops zsops_tty = {
+ zstty_rxint, /* receive char available */
+ zstty_stint, /* external/status */
+ zstty_txint, /* xmit buffer empty */
+ zstty_softint, /* process software interrupt */
+};
diff --git a/sys/arch/sgi/hpc/zs.c b/sys/arch/sgi/hpc/zs.c
new file mode 100644
index 00000000000..c8ce8b74102
--- /dev/null
+++ b/sys/arch/sgi/hpc/zs.c
@@ -0,0 +1,712 @@
+/* $OpenBSD: zs.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: zs.c,v 1.37 2011/02/20 07:59:50 matt Exp $ */
+
+/*-
+ * Copyright (c) 1996, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Gordon W. Ross and Wayne Knowles
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (machine-dependent part)
+ *
+ * Runs two serial lines per chip using slave drivers.
+ * Plain tty/async lines use the zs_async slave.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+
+#include <mips64/archtype.h>
+#include <mips64/arcbios.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/z8530var.h>
+
+#include <dev/cons.h>
+
+#include <dev/ic/z8530reg.h>
+
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/localbus/intvar.h>
+
+/*
+ * Some warts needed by z8530tty.c -
+ * The default parity REALLY needs to be the same as the PROM uses,
+ * or you can not see messages done with printf during boot-up...
+ */
+int zs_def_cflag = (CREAD | CS8 | HUPCL);
+int zs_major = 19;
+
+#define PCLK 3672000 /* PCLK pin input clock rate */
+
+#ifndef ZS_DEFSPEED
+#define ZS_DEFSPEED 9600
+#endif
+
+/*
+ * Define interrupt levels.
+ */
+#define ZSHARD_PRI 64
+
+/* SGI shouldn't need ZS_DELAY() as recovery time is done in hardware? */
+#define ZS_DELAY() delay(3)
+
+/* The layout of this is hardware-dependent (padding, order). */
+struct zschan {
+ uint8_t pad1[3];
+ volatile uint8_t zc_csr; /* ctrl,status, and indirect access */
+ uint8_t pad2[3];
+ volatile uint8_t zc_data; /* data */
+};
+
+struct zsdevice {
+ struct zschan zs_chan_b;
+ struct zschan zs_chan_a;
+};
+
+/* Return the byte offset of element within a structure */
+#define OFFSET(struct_def, el) ((size_t)&((struct_def *)0)->el)
+
+#define ZS_CHAN_A OFFSET(struct zsdevice, zs_chan_a)
+#define ZS_CHAN_B OFFSET(struct zsdevice, zs_chan_b)
+#define ZS_REG_CSR 3
+#define ZS_REG_DATA 7
+static int zs_chan_offset[] = {ZS_CHAN_A, ZS_CHAN_B};
+
+cons_decl(zs);
+struct consdev zs_cn = {
+ zscnprobe,
+ zscninit,
+ zscngetc,
+ zscnputc,
+ zscnpollc,
+ NULL
+};
+
+
+/* Flags from cninit() */
+static int zs_consunit = -1;
+static int zs_conschan = -1;
+
+/* Default speed for all channels */
+static int zs_defspeed = ZS_DEFSPEED;
+
+static uint8_t zs_init_reg[16] = {
+ 0, /* 0: CMD (reset, etc.) */
+ 0, /* 1: No interrupts yet. */
+ ZSHARD_PRI, /* 2: IVECT */
+ ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
+ ZSWR4_CLK_X16 | ZSWR4_ONESB,
+ ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
+ 0, /* 6: TXSYNC/SYNCLO */
+ 0, /* 7: RXSYNC/SYNCHI */
+ 0, /* 8: alias for data port */
+ ZSWR9_MASTER_IE,
+ 0, /*10: Misc. TX/RX control bits */
+ ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD | ZSWR11_TRXC_OUT_ENA,
+ BPS_TO_TCONST(PCLK/16, ZS_DEFSPEED), /*12: BAUDLO (default=9600) */
+ 0, /*13: BAUDHI (default=9600) */
+ ZSWR14_BAUD_ENA,
+ ZSWR15_BREAK_IE,
+};
+
+
+/****************************************************************
+ * Autoconfig
+ ****************************************************************/
+
+/* Definition of the driver for autoconfig. */
+int zs_hpc_match(struct device *, void *, void *);
+void zs_hpc_attach(struct device *, struct device *, void *);
+int zs_print(void *, const char *name);
+
+struct cfdriver zs_cd = {
+ NULL, "zs", DV_TTY
+};
+
+struct cfattach zs_hpc_ca = {
+ sizeof(struct zsc_softc), zs_hpc_match, zs_hpc_attach
+};
+
+int zshard(void *);
+void zssoft(void *);
+struct zschan *zs_get_chan_addr(int, int);
+int zs_getc(void *);
+void zs_putc(void *, int);
+
+/*
+ * Is the zs chip present?
+ */
+int
+zs_hpc_match(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = vcf;
+ struct hpc_attach_args *ha = aux;
+
+ if (strcmp(ha->ha_name, cf->cf_driver->cd_name) == 0)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Attach a found zs.
+ *
+ * Match slave number to zs unit number, so that misconfiguration will
+ * not set up the keyboard as ttya, etc.
+ */
+void
+zs_hpc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct zsc_softc *zsc = (void *)self;
+ struct hpc_attach_args *haa = aux;
+ struct zsc_attach_args zsc_args;
+ struct zs_chanstate *cs;
+ struct zs_channel *ch;
+ int zs_unit, channel, err, s;
+
+ zsc->zsc_bustag = haa->ha_st;
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff, 0x10,
+ &zsc->zsc_base)) != 0) {
+ printf(": unable to map 85c30 registers, error = %d\n",
+ err);
+ return;
+ }
+
+ zs_unit = zsc->zsc_dev.dv_unit;
+ printf("\n");
+
+ /*
+ * Initialize software state for each channel.
+ *
+ * Done in reverse order of channels since the first serial port
+ * is actually attached to the *second* channel, and vice versa.
+ * Doing it this way should force a 'zstty*' to attach zstty0 to
+ * channel 1 and zstty1 to channel 0. They couldn't have wired
+ * it up in a more sensible fashion, could they?
+ */
+ for (channel = 1; channel >= 0; channel--) {
+ zsc_args.channel = channel;
+ ch = &zsc->zsc_cs_store[channel];
+ cs = zsc->zsc_cs[channel] = (struct zs_chanstate *)ch;
+
+ cs->cs_reg_csr = NULL;
+ cs->cs_reg_data = NULL;
+ cs->cs_channel = channel;
+ cs->cs_private = NULL;
+ cs->cs_ops = &zsops_null;
+ cs->cs_brg_clk = PCLK / 16;
+
+ if (bus_space_subregion(zsc->zsc_bustag, zsc->zsc_base,
+ zs_chan_offset[channel],
+ sizeof(struct zschan),
+ &ch->cs_regs) != 0) {
+ printf("%s: cannot map regs\n", self->dv_xname);
+ return;
+ }
+ ch->cs_bustag = zsc->zsc_bustag;
+
+ memcpy(cs->cs_creg, zs_init_reg, 16);
+ memcpy(cs->cs_preg, zs_init_reg, 16);
+
+ /* If console, don't stomp speed, let zstty know */
+ if (zs_unit == zs_consunit && channel == zs_conschan) {
+ zsc_args.consdev = &zs_cn;
+ zsc_args.hwflags = ZS_HWFLAG_CONSOLE;
+ cs->cs_defspeed = bios_consrate;
+ } else {
+ zsc_args.consdev = NULL;
+ zsc_args.hwflags = 0;
+ cs->cs_defspeed = zs_defspeed;
+ }
+
+ cs->cs_defcflag = zs_def_cflag;
+
+ /* Make these correspond to cs_defcflag (-crtscts) */
+ cs->cs_rr0_dcd = ZSRR0_DCD;
+ cs->cs_rr0_cts = 0;
+ cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
+ cs->cs_wr5_rts = 0;
+
+ /*
+ * Clear the master interrupt enable.
+ * The INTENA is common to both channels,
+ * so just do it on the A channel.
+ */
+ if (channel == 0) {
+ zs_write_reg(cs, 9, 0);
+ }
+ /*
+ * Look for a child driver for this channel.
+ * The child attach will setup the hardware.
+ */
+ if (!config_found(self, (void *)&zsc_args, zs_print)) {
+ /* No sub-driver. Just reset it. */
+ uint8_t reset = (channel == 0) ?
+ ZSWR9_A_RESET : ZSWR9_B_RESET;
+
+ s = splhigh();
+ zs_write_reg(cs, 9, reset);
+ splx(s);
+ }
+ }
+
+
+ zsc->sc_si = softintr_establish(SI_SOFTTTY, zssoft, zsc);
+ int2_intr_establish(haa->ha_irq, IPL_TTY, zshard, zsc, self->dv_xname);
+
+ /*
+ * Set the master interrupt enable and interrupt vector.
+ * (common to both channels, do it on A)
+ */
+ cs = zsc->zsc_cs[0];
+ s = splhigh();
+ /* interrupt vector */
+ zs_write_reg(cs, 2, zs_init_reg[2]);
+ /* master interrupt control (enable) */
+ zs_write_reg(cs, 9, zs_init_reg[9]);
+ splx(s);
+}
+
+int
+zs_print(void *aux, const char *name)
+{
+ struct zsc_attach_args *args = aux;
+
+ if (name != NULL)
+ printf("%s: ", name);
+
+ if (args->channel != -1)
+ printf(" channel %d", args->channel);
+
+ return UNCONF;
+}
+
+/*
+ * Our ZS chips all share a common, autovectored interrupt,
+ * so we have to look at all of them on each interrupt.
+ */
+int
+zshard(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ int rr3, rval;
+
+ rval = 0;
+ while ((rr3 = zsc_intr_hard(zsc))) {
+ rval |= rr3;
+ }
+
+ if (zsc->zsc_cs[0]->cs_softreq ||
+ zsc->zsc_cs[1]->cs_softreq)
+ softintr_schedule(zsc->sc_si);
+
+ return rval;
+}
+
+/*
+ * Similar scheme as for zshard (look at all of them)
+ */
+void
+zssoft(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ int s;
+
+ /* Make sure we call the tty layer at spltty. */
+ s = spltty();
+ (void) zsc_intr_soft(zsc);
+ splx(s);
+}
+
+
+/*
+ * MD functions for setting the baud rate and control modes.
+ */
+int
+zs_set_speed(struct zs_chanstate *cs, int bps)
+{
+ int tconst, real_bps;
+
+ if (bps == 0)
+ return (0);
+
+#ifdef DIAGNOSTIC
+ if (cs->cs_brg_clk == 0)
+ panic("zs_set_speed");
+#endif
+
+ tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
+ if (tconst < 0)
+ return (EINVAL);
+
+ /* Convert back to make sure we can do it. */
+ real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
+
+#if 0 /* PCLK is too small, 9600bps really yields 9562 */
+ /* XXX - Allow some tolerance here? */
+ if (real_bps != bps)
+ return (EINVAL);
+#endif
+
+ cs->cs_preg[12] = tconst;
+ cs->cs_preg[13] = tconst >> 8;
+
+ /* Caller will stuff the pending registers. */
+ return (0);
+}
+
+int
+zs_set_modes(struct zs_chanstate *cs, int cflag)
+{
+ int s;
+
+ /*
+ * Output hardware flow control on the chip is horrendous:
+ * if carrier detect drops, the receiver is disabled, and if
+ * CTS drops, the transmitter is stoped IN MID CHARACTER!
+ * Therefore, NEVER set the HFC bit, and instead use the
+ * status interrupt to detect CTS changes.
+ */
+ s = splzs();
+ cs->cs_rr0_pps = 0;
+ if ((cflag & (CLOCAL | MDMBUF)) != 0) {
+ cs->cs_rr0_dcd = 0;
+ if ((cflag & MDMBUF) == 0)
+ cs->cs_rr0_pps = ZSRR0_DCD;
+ } else
+ cs->cs_rr0_dcd = ZSRR0_DCD;
+ if ((cflag & CRTSCTS) != 0) {
+ cs->cs_wr5_dtr = ZSWR5_DTR;
+ cs->cs_wr5_rts = ZSWR5_RTS;
+ cs->cs_rr0_cts = ZSRR0_CTS;
+ } else if ((cflag & MDMBUF) != 0) {
+ cs->cs_wr5_dtr = 0;
+ cs->cs_wr5_rts = ZSWR5_DTR;
+ cs->cs_rr0_cts = ZSRR0_DCD;
+ } else {
+ cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
+ cs->cs_wr5_rts = 0;
+ cs->cs_rr0_cts = 0;
+ }
+ splx(s);
+
+ /* Caller will stuff the pending registers. */
+ return (0);
+}
+
+
+/*
+ * Read or write the chip with suitable delays.
+ */
+
+uint8_t
+zs_read_reg(struct zs_chanstate *cs, uint8_t reg)
+{
+ uint8_t val;
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, reg);
+ ZS_DELAY();
+ val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR);
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, reg);
+ ZS_DELAY();
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, val);
+ ZS_DELAY();
+}
+
+uint8_t
+zs_read_csr(struct zs_chanstate *cs)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+ uint8_t val;
+
+ val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR);
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_csr(struct zs_chanstate *cs, uint8_t val)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, val);
+ ZS_DELAY();
+}
+
+uint8_t
+zs_read_data(struct zs_chanstate *cs)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+ uint8_t val;
+
+ val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_DATA);
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_data(struct zs_chanstate *cs, uint8_t val)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_DATA, val);
+ ZS_DELAY();
+}
+
+void
+zs_abort(struct zs_chanstate *cs)
+{
+#if defined(KGDB)
+ zskgdb(cs);
+#elif defined(DDB)
+ Debugger();
+#endif
+}
+
+
+/*********************************************************/
+/* Polled character I/O functions for console and KGDB */
+/*********************************************************/
+
+struct zschan *
+zs_get_chan_addr(int zs_unit, int channel)
+{
+#if 0
+ static int dumped_addr = 0;
+#endif
+ struct zsdevice *addr = NULL;
+ struct zschan *zc;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ switch (zs_unit) {
+ case 0:
+ addr = (struct zsdevice *)
+ PHYS_TO_XKPHYS(0x1fb80d00, CCA_NC);
+ break;
+ case 1:
+ addr = (struct zsdevice *)
+ PHYS_TO_XKPHYS(0x1fb80d10, CCA_NC);
+ break;
+ }
+ break;
+
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (zs_unit == 0)
+ addr = (struct zsdevice *)
+ PHYS_TO_XKPHYS(0x1fbd9830, CCA_NC);
+ break;
+ }
+ if (addr == NULL)
+ panic("zs_get_chan_addr: bad zs_unit %d\n", zs_unit);
+
+ /*
+ * We need to swap serial ports to match reality on
+ * non-keyboard channels.
+ */
+ if (sys_config.system_type != SGI_IP20) {
+ if (channel == 0)
+ zc = &addr->zs_chan_b;
+ else
+ zc = &addr->zs_chan_a;
+ } else {
+ if (zs_unit == 0) {
+ if (channel == 0)
+ zc = &addr->zs_chan_a;
+ else
+ zc = &addr->zs_chan_b;
+ } else {
+ if (channel == 0)
+ zc = &addr->zs_chan_b;
+ else
+ zc = &addr->zs_chan_a;
+ }
+ }
+
+#if 0
+ if (dumped_addr == 0) {
+ dumped_addr++;
+ printf("zs unit %d, channel %d had address %p\n",
+ zs_unit, channel, zc);
+ }
+#endif
+
+ return (zc);
+}
+
+int
+zs_getc(void *arg)
+{
+ register volatile struct zschan *zc = arg;
+ register int s, c, rr0;
+
+ s = splzs();
+ /* Wait for a character to arrive. */
+ do {
+ rr0 = zc->zc_csr;
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_RX_READY) == 0);
+
+ c = zc->zc_data;
+ ZS_DELAY();
+ splx(s);
+
+ return (c);
+}
+
+/*
+ * Polled output char.
+ */
+void
+zs_putc(void *arg, int c)
+{
+ register volatile struct zschan *zc = arg;
+ register int s, rr0;
+
+ s = splzs();
+ /* Wait for transmitter to become ready. */
+ do {
+ rr0 = zc->zc_csr;
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_TX_READY) == 0);
+
+ zc->zc_data = c;
+ __asm__ __volatile__ ("sync" ::: "memory"); /* wbflush(); */
+ ZS_DELAY();
+ splx(s);
+}
+
+/***************************************************************/
+
+static int cons_port;
+
+void
+zscnprobe(struct consdev *cp)
+{
+ cp->cn_dev = makedev(zs_major, 0);
+ cp->cn_pri = CN_DEAD;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (strlen(bios_console) == 9 &&
+ strncmp(bios_console, "serial", 6) == 0)
+ cp->cn_pri = CN_FORCED;
+ else
+ cp->cn_pri = CN_MIDPRI;
+ break;
+ }
+}
+
+void
+zscninit(struct consdev *cn)
+{
+ if (strlen(bios_console) == 9 &&
+ strncmp(bios_console, "serial", 6) != 0)
+ cons_port = bios_console[7] - '0';
+
+ /* Mark this unit as the console */
+ zs_consunit = 0;
+
+ /* SGI hardware wires serial port 1 to channel B, port 2 to A */
+ if (cons_port == 0)
+ zs_conschan = 1;
+ else
+ zs_conschan = 0;
+}
+
+int
+zscngetc(dev_t dev)
+{
+ struct zschan *zs;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ zs = zs_get_chan_addr(1, cons_port);
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ default:
+ zs = zs_get_chan_addr(0, cons_port);
+ break;
+ }
+
+ return zs_getc(zs);
+}
+
+void
+zscnputc(dev_t dev, int c)
+{
+ struct zschan *zs;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ zs = zs_get_chan_addr(1, cons_port);
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ default:
+ zs = zs_get_chan_addr(0, cons_port);
+ break;
+ }
+
+ zs_putc(zs, c);
+}
+
+void
+zscnpollc(dev_t dev, int on)
+{
+}
diff --git a/sys/arch/sgi/include/autoconf.h b/sys/arch/sgi/include/autoconf.h
index b71366edba6..d3db14d94e5 100644
--- a/sys/arch/sgi/include/autoconf.h
+++ b/sys/arch/sgi/include/autoconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.h,v 1.32 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: autoconf.h,v 1.33 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -93,6 +93,7 @@ void arcs_device_register(struct device *, void *);
void dksc_device_register(struct device *, void *);
extern void (*_device_register)(struct device *, void *);
+void ip22_setup(void);
void ip27_setup(void);
void ip27_autoconf(struct device *);
void ip30_setup(void);
diff --git a/sys/arch/sgi/include/eisa_machdep.h b/sys/arch/sgi/include/eisa_machdep.h
new file mode 100644
index 00000000000..93ba8c4c4e8
--- /dev/null
+++ b/sys/arch/sgi/include/eisa_machdep.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: eisa_machdep.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: eisa_machdep.h,v 1.4 1997/06/06 23:12:52 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1996 Christopher G. Demetriou. 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 Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 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.
+ */
+
+/*
+ * Machine-specific definitions for EISA autoconfiguration.
+ */
+
+/*
+ * EISA spaces memory layout
+ */
+
+#define EISA_IO_BASE 0x00080000
+#define EISA_IO_END 0x00090000
+
+#define EISA_MEM0_BASE 0x00100000
+#define EISA_MEM0_END 0x08000000
+
+#define EISA_MEM1_BASE 0x80000000
+#define EISA_MEM1_END 0x100000000UL
+
+/*
+ * Types provided to machine-independent EISA code.
+ */
+typedef void *eisa_chipset_tag_t;
+typedef int eisa_intr_handle_t;
+
+/*
+ * Functions provided to machine-independent EISA code.
+ */
+void eisa_attach_hook(struct device *, struct device *,
+ struct eisabus_attach_args *);
+int eisa_maxslots(eisa_chipset_tag_t);
+int eisa_intr_map(eisa_chipset_tag_t, u_int,
+ eisa_intr_handle_t *);
+const char *eisa_intr_string(eisa_chipset_tag_t, eisa_intr_handle_t);
+void *eisa_intr_establish(eisa_chipset_tag_t, eisa_intr_handle_t,
+ int, int, int (*)(void *), void *, char *);
+void eisa_intr_disestablish(eisa_chipset_tag_t, void *);
diff --git a/sys/arch/sgi/include/z8530var.h b/sys/arch/sgi/include/z8530var.h
new file mode 100644
index 00000000000..5fab516b720
--- /dev/null
+++ b/sys/arch/sgi/include/z8530var.h
@@ -0,0 +1,121 @@
+/* $OpenBSD: z8530var.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530var.h,v 1.10 2011/07/01 21:00:21 dyoung Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+#include <machine/bus.h>
+#include <sgi/hpc/z8530sc.h>
+
+struct zs_channel {
+ struct zs_chanstate cs_zscs; /* Required: soft state */
+ bus_space_tag_t cs_bustag; /* Machine-dependent */
+ bus_space_handle_t cs_regs;
+};
+
+struct zsc_softc {
+ struct device zsc_dev; /* required: base device */
+ struct zs_chanstate *zsc_cs[2]; /* channel soft state */
+ struct zs_channel zsc_cs_store[2];
+ /* Machine-dependent part follows... */
+ bus_space_tag_t zsc_bustag; /* Bus type */
+ bus_space_handle_t zsc_base; /* Device base address */
+ void *sc_si; /* Softinterrupt handle */
+};
+
+/*
+ * Functions to read and write individual registers in a channel.
+ * The SCC chip requires 3-4 PCLK cycles recovery time between accesses
+ */
+
+uint8_t zs_read_reg(struct zs_chanstate *, uint8_t);
+uint8_t zs_read_csr(struct zs_chanstate *);
+uint8_t zs_read_data(struct zs_chanstate *);
+
+void zs_write_reg(struct zs_chanstate *, uint8_t, uint8_t);
+void zs_write_csr(struct zs_chanstate *, uint8_t);
+void zs_write_data(struct zs_chanstate *, uint8_t);
+
+/* Zilog Serial hardware interrupts (level 0) */
+#define splzs() spltty()
+#define IPL_ZS IPL_TTY
diff --git a/sys/arch/sgi/localbus/imc.c b/sys/arch/sgi/localbus/imc.c
new file mode 100644
index 00000000000..c8544aa8788
--- /dev/null
+++ b/sys/arch/sgi/localbus/imc.c
@@ -0,0 +1,826 @@
+/* $OpenBSD: imc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: imc.c,v 1.32 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * 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. 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.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <sgi/sgi/ip22.h>
+#include <sgi/localbus/imcreg.h>
+#include <sgi/localbus/imcvar.h>
+
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/gio/giovar.h>
+
+#include "eisa.h"
+
+#if NEISA > 0
+#include <dev/eisa/eisavar.h>
+#endif
+
+int imc_match(struct device *, void *, void *);
+void imc_attach(struct device *, struct device *, void *);
+int imc_print(void *, const char *);
+
+const struct cfattach imc_ca = {
+ sizeof(struct device), imc_match, imc_attach
+};
+
+struct cfdriver imc_cd = {
+ NULL, "imc", DV_DULL
+};
+
+uint32_t imc_bus_error(uint32_t, struct trap_frame *);
+void imc_bus_reset(void);
+int imc_watchdog_cb(void *, int);
+
+uint8_t imc_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint16_t imc_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void imc_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void imc_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t);
+void imc_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t);
+void imc_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+uint32_t imc_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint64_t imc_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void imc_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t);
+void imc_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t);
+void imc_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void imc_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+void imc_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void imc_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+int imc_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+void imc_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+int imc_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+void *imc_space_vaddr(bus_space_tag_t, bus_space_handle_t);
+void imc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, int);
+
+bus_space_t imcbus_tag = {/* not static for gio_cnattch() */
+ PHYS_TO_XKPHYS(0, CCA_NC),
+ NULL,
+ imc_read_1, imc_write_1,
+ imc_read_2, imc_write_2,
+ imc_read_4, imc_write_4,
+ imc_read_8, imc_write_8,
+ imc_read_raw_2, imc_write_raw_2,
+ imc_read_raw_4, imc_write_raw_4,
+ imc_read_raw_8, imc_write_raw_8,
+ imc_space_map, imc_space_unmap, imc_space_region,
+ imc_space_vaddr, imc_space_barrier
+};
+
+#if NEISA > 0
+int imc_eisa_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+int imc_eisa_io_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+int imc_eisa_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+int imc_eisa_mem_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+
+static bus_space_t imcbus_eisa_io_tag = {
+ PHYS_TO_XKPHYS(EISA_IO_BASE, CCA_NC),
+ NULL,
+ imc_read_1, imc_write_1,
+ imc_read_2, imc_write_2,
+ imc_read_4, imc_write_4,
+ imc_read_8, imc_write_8,
+ imc_read_raw_2, imc_write_raw_2,
+ imc_read_raw_4, imc_write_raw_4,
+ imc_read_raw_8, imc_write_raw_8,
+ imc_eisa_io_map, imc_space_unmap, imc_eisa_io_region,
+ imc_space_vaddr, imc_space_barrier
+};
+static bus_space_t imcbus_eisa_mem_tag = {
+ PHYS_TO_XKPHYS(0, CCA_NC),
+ NULL,
+ imc_read_1, imc_write_1,
+ imc_read_2, imc_write_2,
+ imc_read_4, imc_write_4,
+ imc_read_8, imc_write_8,
+ imc_read_raw_2, imc_write_raw_2,
+ imc_read_raw_4, imc_write_raw_4,
+ imc_read_raw_8, imc_write_raw_8,
+ imc_eisa_mem_map, imc_space_unmap, imc_eisa_mem_region,
+ imc_space_vaddr, imc_space_barrier
+};
+#endif
+
+bus_addr_t imc_pa_to_device(paddr_t);
+paddr_t imc_device_to_pa(bus_addr_t);
+
+struct machine_bus_dma_tag imc_bus_dma_tag = {/* not static for gio_cnattch() */
+ NULL, /* _cookie */
+ _dmamap_create,
+ _dmamap_destroy,
+ _dmamap_load,
+ _dmamap_load_mbuf,
+ _dmamap_load_uio,
+ _dmamap_load_raw,
+ _dmamap_load_buffer,
+ _dmamap_unload,
+ _dmamap_sync,
+ _dmamem_alloc,
+ _dmamem_free,
+ _dmamem_map,
+ _dmamem_unmap,
+ _dmamem_mmap,
+ imc_pa_to_device,
+ imc_device_to_pa,
+ 0
+};
+
+/*
+ * Bus access primitives.
+ */
+
+uint8_t
+imc_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint8_t *)(h + o);
+}
+
+uint16_t
+imc_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint16_t *)(h + o);
+}
+
+uint32_t
+imc_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint32_t *)(h + o);
+}
+
+uint64_t
+imc_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint64_t *)(h + o);
+}
+
+void
+imc_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t v)
+{
+ *(volatile uint8_t *)(h + o) = v;
+}
+
+void
+imc_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t v)
+{
+ *(volatile uint16_t *)(h + o) = v;
+}
+
+void
+imc_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint32_t v)
+{
+ *(volatile uint32_t *)(h + o) = v;
+}
+
+void
+imc_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint64_t v)
+{
+ *(volatile uint64_t *)(h + o) = v;
+}
+
+void
+imc_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + o);
+ len >>= 1;
+ while (len-- != 0) {
+ *(uint16_t *)buf = *addr;
+ buf += 2;
+ }
+}
+
+void
+imc_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + o);
+ len >>= 1;
+ while (len-- != 0) {
+ *addr = *(uint16_t *)buf;
+ buf += 2;
+ }
+}
+
+void
+imc_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + o);
+ len >>= 2;
+ while (len-- != 0) {
+ *(uint32_t *)buf = *addr;
+ buf += 4;
+ }
+}
+
+void
+imc_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + o);
+ len >>= 2;
+ while (len-- != 0) {
+ *addr = *(uint32_t *)buf;
+ buf += 4;
+ }
+}
+
+void
+imc_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + o);
+ len >>= 3;
+ while (len-- != 0) {
+ *(uint64_t *)buf = *addr;
+ buf += 8;
+ }
+}
+
+void
+imc_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + o);
+ len >>= 3;
+ while (len-- != 0) {
+ *addr = *(uint64_t *)buf;
+ buf += 8;
+ }
+}
+
+int
+imc_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ *bshp = t->bus_base + offs;
+ return 0;
+}
+
+void
+imc_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
+{
+}
+
+int
+imc_space_region(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
+{
+ *nbshp = bsh + offset;
+ return 0;
+}
+
+void *
+imc_space_vaddr(bus_space_tag_t t, bus_space_handle_t h)
+{
+ return (void *)h;
+}
+
+void
+imc_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs,
+ bus_size_t len, int flags)
+{
+ __asm__ __volatile__ ("sync" ::: "memory");
+}
+
+#if NEISA > 0
+int
+imc_eisa_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
+ bus_space_handle_t *bshp)
+{
+ if (offs + size > EISA_IO_END - EISA_IO_BASE)
+ return EINVAL;
+
+ *bshp = t->bus_base + offs;
+ return 0;
+}
+
+int
+imc_eisa_io_region(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, bus_space_handle_t *nbshp)
+{
+ if ((bsh - t->bus_base) + offset + size > EISA_IO_END - EISA_IO_BASE)
+ return EINVAL;
+
+ *nbshp = bsh + offset;
+ return 0;
+}
+
+int
+imc_eisa_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
+ bus_space_handle_t *bshp)
+{
+ if ((offs >= EISA_MEM0_BASE && offs + size <= EISA_MEM0_END) ||
+ (offs >= EISA_MEM1_BASE && offs + size <= EISA_MEM1_END)) {
+ *bshp = t->bus_base + offs;
+ return 0;
+ }
+
+ return EINVAL;
+}
+
+int
+imc_eisa_mem_region(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
+{
+ bus_addr_t orig = bsh - t->bus_base;
+
+ if ((orig >= EISA_MEM0_BASE && orig + offset + size <= EISA_MEM0_END) ||
+ (orig >= EISA_MEM1_BASE && orig + offset + size <= EISA_MEM1_END)) {
+ *nbshp = t->bus_base + offset;
+ return 0;
+ }
+
+ return EINVAL;
+}
+#endif
+
+bus_addr_t
+imc_pa_to_device(paddr_t pa)
+{
+ return (bus_addr_t)pa;
+}
+
+paddr_t
+imc_device_to_pa(bus_addr_t addr)
+{
+ return (paddr_t)addr;
+}
+
+/*
+ * Autoconf glue.
+ */
+
+int
+imc_match(struct device *parent, void *match, void *aux)
+{
+ struct mainbus_attach_args *maa = (void *)aux;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return 0;
+ }
+
+ return strcmp(maa->maa_name, imc_cd.cd_name) == 0;
+}
+
+void
+imc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct imc_attach_args iaa;
+#if NEISA > 0
+ struct eisabus_attach_args eba;
+#endif
+ uint32_t reg;
+ uint32_t id, rev;
+ int have_eisa;
+
+ id = imc_read(IMC_SYSID);
+ rev = id & IMC_SYSID_REVMASK;
+
+ /* EISA exists on Indigo2 only */
+ if (sys_config.system_type != SGI_IP20 &&
+ sys_config.system_subtype == IP22_INDIGO2)
+ have_eisa = (id & IMC_SYSID_HAVEISA) != 0;
+ else
+ have_eisa = 0;
+
+ printf(": revision %d\n", rev);
+
+ /* Clear CPU/GIO error status registers to clear any leftover bits. */
+ imc_bus_reset();
+
+ /* Disable watchdog if leftover from previous reboot */
+ imc_watchdog_cb(self, 0);
+
+ /* Hook the bus error handler into the ISR */
+ set_intr(INTPRI_BUSERR, CR_INT_4, imc_bus_error);
+
+ /*
+ * Enable parity reporting on GIO/main memory transactions.
+ * Disable parity checking on CPU bus transactions (as turning
+ * it on seems to cause spurious bus errors), but enable parity
+ * checking on CPU reads from main memory (note that this bit
+ * has the opposite sense... Turning it on turns the checks off!).
+ * Finally, turn on interrupt writes to the CPU from the MC.
+ */
+ reg = imc_read(IMC_CPUCTRL0);
+ reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
+ reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA);
+ imc_write(IMC_CPUCTRL0, reg);
+
+ /* Setup the MC write buffer depth */
+ reg = imc_read(IMC_CPUCTRL1);
+ reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13;
+
+ /*
+ * Force endianness on the onboard HPC and both slots.
+ * This should be safe for Fullhouse, but leave it conditional
+ * for now.
+ */
+ switch (sys_config.system_type) {
+ case SGI_IP22:
+ if (sys_config.system_subtype != IP22_INDY)
+ break;
+ /* FALLTHROUGH */
+ case SGI_IP20:
+ reg |= IMC_CPUCTRL1_HPCFX;
+ reg |= IMC_CPUCTRL1_EXP0FX;
+ reg |= IMC_CPUCTRL1_EXP1FX;
+ reg &= ~IMC_CPUCTRL1_HPCLITTLE;
+ reg &= ~IMC_CPUCTRL1_EXP0LITTLE;
+ reg &= ~IMC_CPUCTRL1_EXP1LITTLE;
+ break;
+ }
+ imc_write(IMC_CPUCTRL1, reg);
+
+ /*
+ * Set GIO64 arbitrator configuration register:
+ *
+ * Preserve PROM-set graphics-related bits, as they seem to depend
+ * on the graphics variant present and I'm not sure how to figure
+ * that out or 100% sure what the correct settings are for each.
+ */
+ reg = imc_read(IMC_GIO64ARB);
+ reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST);
+
+ /*
+ * Rest of settings are machine/board dependent
+ * XXX I wonder if this even works as advertized. The logic apparently
+ * XXX comes from Linux, but the EISA settings look horribly broken to
+ * XXX me -- miod
+ */
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ reg |= IMC_GIO64ARB_ONEGIO;
+ reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT;
+ reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST;
+ reg &= ~(IMC_GIO64ARB_HPC64 |
+ IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 |
+ IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 |
+ IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE);
+ break;
+ default:
+ /*
+ * GIO64 invariant for all IP22 platforms: one GIO bus,
+ * HPC1 @ 64
+ */
+ reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64;
+
+ switch (sys_config.system_subtype) {
+ default:
+ case IP22_INDY:
+ /* XXX is MST mutually exclusive? */
+ reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT;
+ reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST;
+
+ /* EISA can bus-master, is 64-bit */
+ reg |= IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64;
+ break;
+
+ case IP22_INDIGO2:
+ /*
+ * All Fullhouse boards have a 64-bit HPC2 and pipelined
+ * EXP0 slot.
+ */
+ reg |= IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE;
+
+ if (rev < 2) {
+ /* EXP0 realtime, EXP1 can master */
+ reg |= IMC_GIO64ARB_EXP0RT |
+ IMC_GIO64ARB_EXP1MST;
+ } else {
+ /* EXP1 pipelined as well, EISA masters */
+ reg |= IMC_GIO64ARB_EXP1PIPE |
+ IMC_GIO64ARB_EISAMST;
+ }
+ break;
+ }
+ }
+
+ imc_write(IMC_GIO64ARB, reg);
+
+#if NEISA > 0
+ if (have_eisa) {
+ memset(&eba, 0, sizeof(eba));
+ eba.eba_busname = "eisa";
+ eba.eba_iot = &imcbus_eisa_io_tag;
+ eba.eba_memt = &imcbus_eisa_mem_tag;
+ eba.eba_dmat = &imc_bus_dma_tag;
+ eba.eba_ec = NULL;
+ config_found(self, &eba, imc_print);
+ }
+#endif
+
+ memset(&iaa, 0, sizeof(iaa));
+ iaa.iaa_name = "gio";
+ iaa.iaa_st = &imcbus_tag;
+ iaa.iaa_dmat = &imc_bus_dma_tag;
+ config_found(self, &iaa, imc_print);
+
+ /* Clear CPU/GIO error status registers to clear any leftover bits. */
+ imc_bus_reset();
+
+ /* Register watchdog */
+ wdog_register(self, imc_watchdog_cb);
+}
+
+int
+imc_print(void *aux, const char *name)
+{
+ struct imc_attach_args *iaa = aux;
+
+ if (name != NULL)
+ printf("%s at %s", iaa->iaa_name, name);
+
+ return UNCONF;
+}
+
+void
+imc_bus_reset()
+{
+ imc_write(IMC_CPU_ERRSTAT, 0);
+ imc_write(IMC_GIO_ERRSTAT, 0);
+}
+
+uint32_t
+imc_bus_error(uint32_t hwpend, struct trap_frame *tf)
+{
+ printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n",
+ imc_read(IMC_CPU_ERRSTAT),
+ imc_read(IMC_CPU_ERRADDR),
+ imc_read(IMC_GIO_ERRSTAT),
+ imc_read(IMC_GIO_ERRADDR));
+ imc_bus_reset();
+
+ return hwpend;
+}
+
+int
+imc_watchdog_cb(void *v, int period)
+{
+ uint32_t reg;
+
+ if (period == 0) {
+ /* reset... */
+ imc_write(IMC_WDOG, 0);
+ /* ...and disable */
+ reg = imc_read(IMC_CPUCTRL0);
+ reg &= ~(IMC_CPUCTRL0_WDOG);
+ imc_write(IMC_CPUCTRL0, reg);
+
+ return 0;
+ } else {
+ /* enable... */
+ reg = imc_read(IMC_CPUCTRL0);
+ reg |= IMC_CPUCTRL0_WDOG;
+ imc_write(IMC_CPUCTRL0, reg);
+ /* ...and reset */
+ imc_write(IMC_WDOG, 0);
+
+ /*
+ * The watchdog period is not controllable; it will fire
+ * when the 20 bit counter, running on a 64 usec clock,
+ * overflows.
+ */
+ return (64 << 20) / 1000000;
+ }
+}
+
+/* intended to be called from gio/gio.c only */
+int
+imc_gio64_arb_config(int slot, uint32_t flags)
+{
+ uint32_t reg;
+
+ if (sys_config.system_type == SGI_IP20 ||
+ sys_config.system_subtype != IP22_INDIGO2) {
+ /* GIO_SLOT_GFX is only usable on Fullhouse */
+ if (slot == GIO_SLOT_GFX)
+ return EINVAL;
+ } else {
+ /* GIO_SLOT_EXP1 is unusable on Fullhouse */
+ if (slot == GIO_SLOT_EXP1)
+ return EINVAL;
+ }
+
+ /* GIO_SLOT_GFX is always pipelined */
+ if (slot == GIO_SLOT_GFX && (flags & GIO_ARB_NOPIPE))
+ return EINVAL;
+
+ /* IP20 does not support pipelining (XXX what about Indy?) */
+ if (((flags & GIO_ARB_PIPE) || (flags & GIO_ARB_NOPIPE)) &&
+ sys_config.system_type == SGI_IP20)
+ return EINVAL;
+
+ reg = imc_read(IMC_GIO64ARB);
+
+ if (flags & GIO_ARB_RT) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP0RT;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP1RT;
+ else if (slot == GIO_SLOT_GFX)
+ reg |= IMC_GIO64ARB_GRXRT;
+ }
+
+ if (flags & GIO_ARB_MST) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP0MST;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP1MST;
+ else if (slot == GIO_SLOT_GFX)
+ reg |= IMC_GIO64ARB_GRXMST;
+ }
+
+ if (flags & GIO_ARB_PIPE) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP0PIPE;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP1PIPE;
+ }
+
+ if (flags & GIO_ARB_LB) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP0RT;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP1RT;
+ else if (slot == GIO_SLOT_GFX)
+ reg &= ~IMC_GIO64ARB_GRXRT;
+ }
+
+ if (flags & GIO_ARB_SLV) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP0MST;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP1MST;
+ else if (slot == GIO_SLOT_GFX)
+ reg &= ~IMC_GIO64ARB_GRXMST;
+ }
+
+ if (flags & GIO_ARB_NOPIPE) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP0PIPE;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP1PIPE;
+ }
+
+ if (flags & GIO_ARB_32BIT) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP064;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP164;
+ }
+
+ if (flags & GIO_ARB_64BIT) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP064;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP164;
+ }
+
+ if (flags & GIO_ARB_HPC2_32BIT)
+ reg &= ~IMC_GIO64ARB_HPCEXP64;
+
+ if (flags & GIO_ARB_HPC2_64BIT)
+ reg |= IMC_GIO64ARB_HPCEXP64;
+
+ imc_write(IMC_GIO64ARB, reg);
+
+ return 0;
+}
+
+/*
+ * According to chapter 19 of the "IRIX Device Driver Programmer's Guide",
+ * some GIO devices, which do not drive all data lines, may cause false
+ * memory read parity errors on the SysAD bus. The workaround is to disable
+ * parity checking.
+ */
+void
+imc_disable_sysad_parity(void)
+{
+ uint32_t reg;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return;
+ }
+
+ reg = imc_read(IMC_CPUCTRL0);
+ reg |= IMC_CPUCTRL0_NCHKMEMPAR;
+ imc_write(IMC_CPUCTRL0, reg);
+}
+
+void
+imc_enable_sysad_parity(void)
+{
+ uint32_t reg;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return;
+ }
+
+ reg = imc_read(IMC_CPUCTRL0);
+ reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
+ imc_write(IMC_CPUCTRL0, reg);
+}
+
+#if 0
+int
+imc_is_sysad_parity_enabled(void)
+{
+ uint32_t reg;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return 0;
+ }
+
+ reg = imc_read(IMC_CPUCTRL0);
+
+ return reg & IMC_CPUCTRL0_NCHKMEMPAR;
+}
+#endif
diff --git a/sys/arch/sgi/localbus/imcreg.h b/sys/arch/sgi/localbus/imcreg.h
new file mode 100644
index 00000000000..fd27ff4c9be
--- /dev/null
+++ b/sys/arch/sgi/localbus/imcreg.h
@@ -0,0 +1,143 @@
+/* $OpenBSD: imcreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: imcreg.h,v 1.4 2005/12/11 12:18:52 christos Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * 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. 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.
+ */
+
+#define IMC_BASE 0x1fa00000
+
+#define IMC_CPUCTRL0 0x04 /* CPU control, register 0 */
+
+#define IMC_CPUCTRL0_REFMASK 0x000f /* # lines to refresh */
+#define IMC_CPUCTRL0_RFE 0x0010 /* refresh enable */
+#define IMC_CPUCTRL0_GPR 0x0020 /* GIO parity enable */
+#define IMC_CPUCTRL0_MPR 0x0040 /* memory parity enable */
+#define IMC_CPUCTRL0_CPR 0x0080 /* cpu bus parity enable */
+#define IMC_CPUCTRL0_WDOG 0x0100 /* watchdog enable */
+#define IMC_CPUCTRL0_SIN 0x0200 /* reset system */
+#define IMC_CPUCTRL0_GRR 0x0400 /* graphics reset */
+#define IMC_CPUCTRL0_ENLOCK 0x0800 /* enable EISA memory lock */
+#define IMC_CPUCTRL0_CMDPAR 0x1000 /* SysCmd parity enable */
+#define IMC_CPUCTRL0_INTENA 0x2000 /* enable CPU interrupts */
+#define IMC_CPUCTRL0_SNOOPENA 0x4000 /* enable gfx DMA snoop */
+#define IMC_CPUCTRL0_PROM_WRENA 0x8000 /* disable buserr on PROM
+ * writes */
+#define IMC_CPUCTRL0_WRST 0x00010000 /* warm restart (reset cpu) */
+/* Bit 17 reserved 0x00020000 */
+#define IMC_CPUCTRL0_LITTLE 0x00040000 /* MC little-endian toggle */
+#define IMC_CPUCTRL0_WRRST 0x00080000 /* cpu warm reset */
+#define IMC_CPUCTRL0_MUXHWMSK 0x01f00000 /* MUX fifo high-water mask */
+#define IMC_CPUCTRL0_BADPAR 0x02000000 /* generate bad parity on
+ * CPU->memory writes */
+#define IMC_CPUCTRL0_NCHKMEMPAR 0x04000000 /* disable CPU parity check
+ * on memory reads. */
+#define IMC_CPUCTRL0_BACK2 0x08000000 /* enable back2back GIO wrt */
+#define IMC_CPUCTRL0_BUSRTMSK 0xf0000000 /* stall cycle for berr data */
+
+#define IMC_CPUCTRL1 0x0c /* CPU control, register 1 */
+#define IMC_CPUCTRL1_MCHWMSK 0x0000000f /* MC FIFO high water mask */
+#define IMC_CPUCTRL1_ABORTEN 0x00000010 /* Enable GIO bus timeouts */
+/* Bits 5 - 11 reserved 0x00000fe0 */
+#define IMC_CPUCTRL1_HPCFX 0x00001000 /* HPC endian fix */
+#define IMC_CPUCTRL1_HPCLITTLE 0x00002000 /* HPC DMA is little-endian */
+#define IMC_CPUCTRL1_EXP0FX 0x00004000 /* EXP0 endian fix */
+#define IMC_CPUCTRL1_EXP0LITTLE 0x00008000 /* EXP0 DMA is little-endian */
+#define IMC_CPUCTRL1_EXP1FX 0x00010000 /* EXP1 endian fix */
+#define IMC_CPUCTRL1_EXP1LITTLE 0x00020000 /* EXP1 DMA is little-endian */
+
+#define IMC_WDOG 0x14 /* Watchdog counter */
+#define IMC_WDOG_MASK 0x001fffff /* counter mask */
+
+#define IMC_SYSID 0x1c /* MC revision register */
+#define IMC_SYSID_REVMASK 0x0000000f /* MC revision mask */
+#define IMC_SYSID_HAVEISA 0x00000010 /* EISA present */
+
+#define IMC_RPSSDIV 0x2c /* RPSS divider */
+#define IMC_RPSSDIV_DIVMSK 0x000000ff /* RPC divider mask */
+#define IMC_RPSSDIV_INCMSK 0x0000ff00 /* RPC increment mask */
+
+#define IMC_EEPROM 0x34 /* EEPROM serial interface */
+/* Bit 1 is reserved 0x00000001 */
+#define IMC_EEPROM_CS 0x00000002 /* EEPROM chip select */
+#define IMC_EEPROM_SCK 0x00000004 /* EEPROM serial clock */
+#define IMC_EEPROM_SO 0x00000008 /* Serial data to EEPROM */
+#define IMC_EEPROM_SI 0x00000010 /* Serial data from EEPROM */
+
+#define IMC_CTRLD 0x44 /* Refresh counter preload */
+#define IMC_CTRLD_MSK 0x000000ff /* Counter preload mask */
+
+#define IMC_REFCTR 0x4c /* Refresh counter */
+#define IMC_REFCTR_MSK 0x000000ff /* Refresh counter mask */
+
+#define IMC_GIO64ARB 0x84 /* GIO64 arbitration params */
+#define IMC_GIO64ARB_HPC64 0x00000001 /* HPC addr size (32/64bit) */
+#define IMC_GIO64ARB_GRX64 0x00000002 /* Gfx addr size (32/64bit) */
+#define IMC_GIO64ARB_EXP064 0x00000004 /* EXP0 addr size (32/64bit) */
+#define IMC_GIO64ARB_EXP164 0x00000008 /* EXP0 addr size (32/64bit) */
+#define IMC_GIO64ARB_EISA64 0x00000010 /* EISA addr size (32/64bit) */
+#define IMC_GIO64ARB_HPCEXP64 0x00000020 /* HPC2 addr size (32/64bit) */
+#define IMC_GIO64ARB_GRXRT 0x00000040 /* Gfx is realtime device */
+#define IMC_GIO64ARB_EXP0RT 0x00000080 /* EXP0 is realtime device */
+#define IMC_GIO64ARB_EXP1RT 0x00000100 /* EXP1 is realtime device */
+#define IMC_GIO64ARB_EISAMST 0x00000200 /* EISA can be busmaster */
+#define IMC_GIO64ARB_ONEGIO 0x00000400 /* Only one GIO64 bus */
+#define IMC_GIO64ARB_GRXMST 0x00000800 /* Gfx can be busmaster */
+#define IMC_GIO64ARB_EXP0MST 0x00001000 /* EXP0 can be busmaster */
+#define IMC_GIO64ARB_EXP1MST 0x00002000 /* EXP1 can be busmaster */
+#define IMC_GIO64ARB_EXP0PIPE 0x00004000 /* EXP0 is pipelined */
+#define IMC_GIO64ARB_EXP1PIPE 0x00008000 /* EXP1 is pipelined */
+
+#define IMC_CPUTIME 0x8c /* Arbiter CPU time period */
+
+#define IMC_LBTIME 0x9c /* Arbiter long-burst time */
+
+#define IMC_MEMCFG0 0xc4 /* Mem config, register 0 */
+#define IMC_MEMCFG1 0xcc /* Mem config, register 1 */
+#define IMC_MEMC_BANK_MASK 0x0000ffff
+#define IMC_MEMC_BANK_SHIFT 16
+#define IMC_MEMC_ADDR_MASK 0x00ff
+#define IMC_MEMC_ADDR_SHIFT 0
+#define IMC_MEMC_SIZE_MASK 0x1f00
+#define IMC_MEMC_SIZE_SHIFT 8
+#define IMC_MEMC_LSHIFT 22 /* 4MB units */
+#define IMC_MEMC_LSHIFT_HUGE 24 /* 16MB units */
+#define IMC_MEMC_VALID 0x2000
+#define IMC_MEMC_SUBBANKS 0x4000
+
+#define IMC_CPU_MEMACC 0xd4 /* CPU mem access config */
+
+#define IMC_GIO_MEMACC 0xdc /* GIO mem access config */
+
+#define IMC_CPU_ERRADDR 0xe4 /* CPU error address */
+
+#define IMC_CPU_ERRSTAT 0xec /* CPU error status */
+
+#define IMC_GIO_ERRADDR 0xf4 /* GIO error address */
+
+#define IMC_GIO_ERRSTAT 0xfc /* GIO error status */
+
+#define IMC_RPSS 0x1004 /* RPSS counter */
diff --git a/sys/arch/sgi/localbus/imcvar.h b/sys/arch/sgi/localbus/imcvar.h
new file mode 100644
index 00000000000..651d23f9d3e
--- /dev/null
+++ b/sys/arch/sgi/localbus/imcvar.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: imcvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: imcvar.h,v 1.1 2006/08/30 23:44:52 rumble Exp $ */
+
+/*
+ * Copyright (c) 2006 Stephen M. Rumble
+ * 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. 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.
+ */
+
+struct imc_attach_args {
+ const char *iaa_name;
+ bus_space_tag_t iaa_st;
+ bus_dma_tag_t iaa_dmat;
+};
+
+int imc_gio64_arb_config(int, uint32_t);
+void imc_disable_sysad_parity(void);
+void imc_enable_sysad_parity(void);
+int imc_is_sysad_parity_enabled(void);
+
+#define imc_read(o) \
+ *(volatile uint32_t *)PHYS_TO_XKPHYS(IMC_BASE + (o), CCA_NC)
+#define imc_write(o,v) \
+ *(volatile uint32_t *)PHYS_TO_XKPHYS(IMC_BASE + (o), CCA_NC) = (v)
diff --git a/sys/arch/sgi/localbus/int.c b/sys/arch/sgi/localbus/int.c
new file mode 100644
index 00000000000..01e8b2a5dde
--- /dev/null
+++ b/sys/arch/sgi/localbus/int.c
@@ -0,0 +1,369 @@
+/* $OpenBSD: int.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: int.c,v 1.24 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2009 Stephen M. Rumble
+ * Copyright (c) 2004 Christopher SEKIYA
+ * 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. 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.
+ */
+
+/*
+ * INT2 (IP20, IP22) /INT3 (IP24) interrupt controllers
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <dev/ic/i8253reg.h>
+
+#include <sgi/localbus/intreg.h>
+#include <sgi/localbus/intvar.h>
+#include <sgi/sgi/ip22.h>
+
+int int2_match(struct device *, void *, void *);
+void int2_attach(struct device *, struct device *, void *);
+int int2_mappable_intr(void *);
+
+const struct cfattach int_ca = {
+ sizeof(struct device), int2_match, int2_attach
+};
+
+struct cfdriver int_cd = {
+ NULL, "int", DV_DULL
+};
+
+paddr_t int2_base;
+
+#define int2_read(r) *(volatile uint8_t *)(int2_base + (r))
+#define int2_write(r, v) *(volatile uint8_t *)(int2_base + (r)) = (v)
+
+/*
+ * INT2 Interrupt handling declarations: 16 local sources on 2 levels.
+ * (we don't use the i8254 timer interrupts)
+ *
+ * In addition to this, INT3 provides 8 so-called mappable interrupts, which
+ * are cascaded to either one of the unused two INT2 VME interrupts.
+ * To make things easier from a software viewpoint, we pretend there are
+ * 16 of them - one set of 8 per cascaded interrupt. This allows for
+ * faster recognition on where to connect these interrupts - as long as
+ * interrupt vector assignment makes sure no mappable interrupt is
+ * registered on both cascaded interrupts.
+ */
+
+#define INT2_NINTS (8 + 8 + 2 * 8)
+struct intrhand *int2_intrhand[INT2_NINTS];
+
+uint32_t int2_intem;
+uint8_t int2_l0imask[NIPLS], int2_l1imask[NIPLS];
+
+void int2_splx(int);
+uint32_t int2_l0intr(uint32_t, struct trap_frame *);
+void int2_l0makemasks(void);
+uint32_t int2_l1intr(uint32_t, struct trap_frame *);
+void int2_l1makemasks(void);
+
+/*
+ * Level 0 interrupt handler.
+ */
+
+uint32_t save_l0imr, save_l0isr, save_l0ipl;
+#define INTR_FUNCTIONNAME int2_l0intr
+#define MASK_FUNCTIONNAME int2_l0makemasks
+
+#define INTR_LOCAL_DECLS
+#define MASK_LOCAL_DECLS
+#define INTR_GETMASKS \
+do { \
+ isr = int2_read(INT2_LOCAL0_STATUS); \
+ imr = int2_read(INT2_LOCAL0_MASK); \
+ bit = 7; \
+save_l0isr = isr; save_l0imr = imr; save_l0ipl = frame->ipl; \
+} while (0)
+#define INTR_MASKPENDING \
+ int2_write(INT2_LOCAL0_MASK, imr & ~isr)
+#define INTR_IMASK(ipl) int2_l0imask[ipl]
+#define INTR_HANDLER(bit) int2_intrhand[bit + 0]
+#define INTR_SPURIOUS(bit) \
+do { \
+ printf("spurious int2 interrupt %d\n", bit); \
+} while (0)
+#define INTR_MASKRESTORE \
+ int2_write(INT2_LOCAL0_MASK, imr)
+#define INTR_MASKSIZE 8
+
+#include <sgi/sgi/intr_template.c>
+
+/*
+ * Level 1 interrupt handler.
+ */
+
+uint32_t save_l1imr, save_l1isr, save_l1ipl;
+#define INTR_FUNCTIONNAME int2_l1intr
+#define MASK_FUNCTIONNAME int2_l1makemasks
+
+#define INTR_LOCAL_DECLS
+#define MASK_LOCAL_DECLS
+#define INTR_GETMASKS \
+do { \
+ isr = int2_read(INT2_LOCAL1_STATUS); \
+ imr = int2_read(INT2_LOCAL1_MASK); \
+ bit = 7; \
+save_l1isr = isr; save_l1imr = imr; save_l1ipl = frame->ipl; \
+} while (0)
+#define INTR_MASKPENDING \
+ int2_write(INT2_LOCAL1_MASK, imr & ~isr)
+#define INTR_IMASK(ipl) int2_l1imask[ipl]
+#define INTR_HANDLER(bit) int2_intrhand[bit + 8]
+#define INTR_SPURIOUS(bit) \
+do { \
+ printf("spurious int2 interrupt %d\n", bit + 8); \
+} while (0)
+#define INTR_MASKRESTORE \
+ int2_write(INT2_LOCAL1_MASK, imr)
+#define INTR_MASKSIZE 8
+
+#include <sgi/sgi/intr_template.c>
+
+void *
+int2_intr_establish(int irq, int level, int (*ih_fun) (void *),
+ void *ih_arg, const char *ih_what)
+{
+ struct intrhand **p, *q, *ih;
+ int s;
+
+#ifdef DIAGNOSTIC
+ if (irq < 0 || irq >= INT2_NINTS)
+ panic("int2_intr_establish: illegal irq %d", irq);
+#endif
+
+ ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT);
+ if (ih == NULL)
+ return NULL;
+
+ ih->ih_next = NULL;
+ ih->ih_fun = ih_fun;
+ ih->ih_arg = ih_arg;
+ ih->ih_level = level;
+ ih->ih_irq = irq;
+ if (ih_what != NULL)
+ evcount_attach(&ih->ih_count, ih_what, &ih->ih_irq);
+
+ s = splhigh();
+
+ for (p = &int2_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
+ ;
+ *p = ih;
+
+ int2_intem |= 1 << irq;
+ switch (irq >> 3) {
+ case 0:
+ int2_l0makemasks();
+ break;
+ case 1:
+ int2_l1makemasks();
+ break;
+ /*
+ * We do not maintain masks for mappable interrupts. They are
+ * masked as a whole, by the level 0 or 1 interrupt they cascade to.
+ */
+ case 2:
+ int2_write(INT2_MAP_MASK0,
+ int2_read(INT2_MAP_MASK0) | (1 << (irq & 7)));
+ break;
+ case 3:
+ int2_write(INT2_MAP_MASK1,
+ int2_read(INT2_MAP_MASK1) | (1 << (irq & 7)));
+ break;
+ }
+
+ splx(s); /* will cause hardware mask update */
+
+ return ih;
+}
+
+void
+int2_splx(int newipl)
+{
+ struct cpu_info *ci = curcpu();
+ uint32_t sr;
+
+ __asm__ ("\t.set noreorder\n");
+ ci->ci_ipl = newipl;
+ __asm__ ("sync\n\t.set reorder\n");
+
+ sr = disableintr(); /* XXX overkill? */
+ int2_write(INT2_LOCAL1_MASK, (int2_intem >> 8) & ~int2_l1imask[newipl]);
+ int2_write(INT2_LOCAL0_MASK, int2_intem & ~int2_l0imask[newipl]);
+ setsr(sr);
+
+ if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
+ setsoftintr0();
+}
+
+/*
+ * Mappable interrupts handler.
+ */
+
+int
+int2_mappable_intr(void *arg)
+{
+ uint which = (unsigned long)arg;
+ uint64_t imr, isr;
+ uint i, intnum;
+ struct intrhand *ih;
+ int rc, ret;
+
+ isr = int2_read(INT2_MAP_STATUS);
+ imr = int2_read(INT2_MAP_MASK0 + (which << 2));
+
+ isr &= imr;
+ if (isr == 0)
+ return 0; /* not for us */
+
+ /*
+ * Don't bother masking sources here - all mappable interrupts are
+ * tied to either a level 1 or level 0 interrupt, and the dispatcher
+ * is registered at IPL_TTY, so we can safely assume we are running
+ * at IPL_TTY now.
+ */
+
+ for (i = 0; i < 8; i++) {
+ intnum = i + 16 + (which << 3);
+ if (isr & (1 << i)) {
+ rc = 0;
+ for (ih = int2_intrhand[intnum]; ih != NULL;
+ ih = ih->ih_next) {
+ ret = (*ih->ih_fun)(ih->ih_arg);
+ if (ret != 0) {
+ rc = 1;
+ atomic_add_uint64(&ih->ih_count.ec_count,
+ 1);
+ }
+ if (ret == 1)
+ break;
+ }
+ if (rc == 0)
+ printf("spurious int2 mapped interrupt %d\n",
+ i);
+ }
+ }
+
+ return 1;
+}
+
+int
+int2_match(struct device *parent, void *match, void *aux)
+{
+ struct mainbus_attach_args *maa = (void *)aux;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return 0;
+ }
+
+ return !strcmp(maa->maa_name, int_cd.cd_name);
+}
+
+void
+int2_attach(struct device *parent, struct device *self, void *aux)
+{
+ uint32_t address;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ address = INT2_IP20;
+ break;
+ default:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (sys_config.system_subtype == IP22_INDIGO2)
+ address = INT2_IP22;
+ else
+ address = INT2_IP24;
+ break;
+ }
+
+ printf(" addr 0x%x\n", address);
+ int2_base = PHYS_TO_XKPHYS((uint64_t)address, CCA_NC);
+
+ /* Clean out interrupt masks */
+ int2_write(INT2_LOCAL0_MASK, 0);
+ int2_write(INT2_LOCAL1_MASK, 0);
+ int2_write(INT2_MAP_MASK0, 0);
+ int2_write(INT2_MAP_MASK1, 0);
+
+ /* Reset timer interrupts */
+ int2_write(INT2_TIMER_CONTROL,
+ TIMER_SEL0 | TIMER_16BIT | TIMER_SWSTROBE);
+ int2_write(INT2_TIMER_CONTROL,
+ TIMER_SEL1 | TIMER_16BIT | TIMER_SWSTROBE);
+ int2_write(INT2_TIMER_CONTROL,
+ TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE);
+ __asm__ __volatile__ ("sync" ::: "memory");
+ delay(4);
+ int2_write(INT2_TIMER_CLEAR, 0x03);
+
+ set_intr(INTPRI_L1, CR_INT_1, int2_l1intr);
+ set_intr(INTPRI_L0, CR_INT_0, int2_l0intr);
+ register_splx_handler(int2_splx);
+
+ if (sys_config.system_type != SGI_IP20) {
+ /* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */
+ int2_intr_establish(7, IPL_TTY, int2_mappable_intr,
+ (void *)0, NULL);
+ int2_intr_establish(8 + 3, IPL_TTY, int2_mappable_intr,
+ (void *)1, NULL);
+ }
+}
+
+/*
+ * Wait for the FIFO Full interrupt condition (Local 0 bit 0) to clear.
+ */
+void
+int2_wait_fifo(uint32_t flag)
+{
+ if (int2_base == 0)
+ delay(5000); /* XXX */
+ else
+ while (int2_read(INT2_LOCAL0_STATUS) & flag)
+ ;
+}
diff --git a/sys/arch/sgi/localbus/intreg.h b/sys/arch/sgi/localbus/intreg.h
new file mode 100644
index 00000000000..c6deca4e933
--- /dev/null
+++ b/sys/arch/sgi/localbus/intreg.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: intreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: int2reg.h,v 1.5 2009/02/12 06:33:57 rumble Exp $ */
+
+/*
+ * Copyright (c) 2004 Christopher SEKIYA
+ * 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. 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.
+ */
+
+/* The INT has known locations on all SGI machines */
+#define INT2_IP20 0x1fb801c0
+#define INT2_IP22 0x1fbd9000
+#define INT2_IP24 0x1fbd9880
+
+/* The following registers are all 8 bit. */
+#define INT2_LOCAL0_STATUS 0x03
+#define INT2_LOCAL0_STATUS_FIFO 0x01
+#define INT2_LOCAL0_MASK 0x07
+#define INT2_LOCAL1_STATUS 0x0b
+#define INT2_LOCAL1_MASK 0x0f
+#define INT2_MAP_STATUS 0x13
+#define INT2_MAP_MASK0 0x17
+#define INT2_MAP_MASK1 0x1b
+#define INT2_MAP_POL 0x1f
+#define INT2_TIMER_CLEAR 0x23
+#define INT2_ERROR_STATUS 0x27
+#define INT2_TIMER_0 0x33
+#define INT2_TIMER_1 0x37
+#define INT2_TIMER_2 0x3b
+#define INT2_TIMER_CONTROL 0x3f
diff --git a/sys/arch/sgi/localbus/intvar.h b/sys/arch/sgi/localbus/intvar.h
new file mode 100644
index 00000000000..c8f6a133862
--- /dev/null
+++ b/sys/arch/sgi/localbus/intvar.h
@@ -0,0 +1,34 @@
+/* $OpenBSD: intvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: int2var.h,v 1.3 2008/08/23 17:25:54 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2004 Christopher SEKIYA
+ * 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. 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.
+ */
+
+void *int2_intr_establish(int, int, int (*)(void *),
+ void *, const char *);
+
+void int2_wait_fifo(uint32_t);
diff --git a/sys/arch/sgi/sgi/autoconf.c b/sys/arch/sgi/sgi/autoconf.c
index 6416fa757d7..0c18a9b1e0a 100644
--- a/sys/arch/sgi/sgi/autoconf.c
+++ b/sys/arch/sgi/sgi/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.33 2011/05/30 22:25:22 oga Exp $ */
+/* $OpenBSD: autoconf.c,v 1.34 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2009, 2010 Miodrag Vallat.
*
@@ -238,7 +238,8 @@ device_register(struct device *dev, void *aux)
(*_device_register)(dev, aux);
}
-#if defined(TGT_O2) || defined(TGT_OCTANE)
+#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2) || \
+ defined(TGT_O2) || defined(TGT_OCTANE)
/*
* ARCS boot path traversal
@@ -324,6 +325,7 @@ arcs_device_register(struct device *dev, void *aux)
{
static struct device *lastparent = NULL;
static struct device *pciparent = NULL;
+ static struct device *wdscparent = NULL;
static int component_pos = 0;
struct device *parent = dev->dv_parent;
@@ -409,22 +411,45 @@ arcs_device_register(struct device *dev, void *aux)
if (parent == lastparent)
goto found_advance;
+ if (component_pos == 0)
+ switch (sys_config.system_type) {
#ifdef TGT_O2
/*
* On O2, the pci(0) component may be omitted from
* the bootpath, in which case we fake the missing
* pci(0) component.
*/
- if (sys_config.system_type == SGI_O2 &&
- component_pos == 0) {
+ case SGI_O2:
if (parent->dv_parent != NULL &&
strcmp(parent->dv_parent->dv_cfdata->cf_driver->cd_name,
"pci") == 0) {
pciparent = parent->dv_parent;
goto found_advance;
}
- }
+ break;
#endif
+#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2)
+ /*
+ * On Ind{igo,y,i^2} systems, the bootpath
+ * starts at scsi().
+ */
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (strcmp(parent->dv_cfdata->cf_driver->cd_name,
+ "wdsc") == 0 &&
+ parent->dv_parent != NULL &&
+ strcmp(parent->dv_parent->dv_cfdata->cf_driver->cd_name,
+ "hpc") == 0) {
+ wdscparent = parent;
+ goto found_advance;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
}
if (parent == lastparent) {
@@ -434,6 +459,12 @@ arcs_device_register(struct device *dev, void *aux)
if (unit == paa->pa_device -
(sys_config.system_type == SGI_O2 ? 1 : 0))
goto found;
+ } else
+ if (parent == wdscparent) {
+ /* XXX is there any better information to use
+ XXX than the attachment number? */
+ if (unit == parent->dv_unit)
+ goto found;
}
/*
* in case scsi() can follow something else then
@@ -473,7 +504,7 @@ found:
lastparent = dev;
}
-#endif /* defined(TGT_O2) || defined(TGT_OCTANE) */
+#endif /* IP20/22/24/26/28/30/32 */
#ifdef TGT_ORIGIN
@@ -647,7 +678,7 @@ dksc_device_register(struct device *dev, void *aux)
}
}
-#endif
+#endif /* IP27/35 */
struct nam2blk nam2blk[] = {
{ "sd", 0 },
diff --git a/sys/arch/sgi/sgi/conf.c b/sys/arch/sgi/sgi/conf.c
index 9a229de9161..0da5395e126 100644
--- a/sys/arch/sgi/sgi/conf.c
+++ b/sys/arch/sgi/sgi/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.29 2011/10/06 20:49:28 deraadt Exp $ */
+/* $OpenBSD: conf.c,v 1.30 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -97,6 +97,8 @@ cdev_decl(fd);
#include "tun.h"
#include "com.h"
cdev_decl(com);
+#include "zs.h"
+cdev_decl(zs);
#include "lpt.h"
cdev_decl(lpt);
#include "ch.h"
@@ -154,7 +156,7 @@ struct cdevsw cdevsw[] =
cdev_lpt_init(NLPT,lpt), /* 16: Parallel printer interface */
cdev_tty_init(NCOM,com), /* 17: 16C450 serial interface */
cdev_disk_init(NWD,wd), /* 18: ST506/ESDI/IDE disk */
- cdev_notdef(), /* 19: */
+ cdev_tty_init(NZS,zs), /* 19: Z8530 serial interface */
cdev_notdef(), /* 20: */
cdev_notdef(), /* 21: */
cdev_disk_init(NRD,rd), /* 22: ramdisk device */
@@ -294,8 +296,9 @@ int nchrtoblktbl = nitems(chrtoblktbl);
#include <dev/cons.h>
-cons_decl(ws);
cons_decl(com);
+cons_decl(ws);
+cons_decl(zs);
struct consdev constab[] = {
#if NWSDISPLAY > 0
@@ -304,5 +307,8 @@ struct consdev constab[] = {
#if NCOM > 0
cons_init(com),
#endif
+#if NZS > 0
+ cons_init(zs),
+#endif
{ 0 },
};
diff --git a/sys/arch/sgi/sgi/ip22.h b/sys/arch/sgi/sgi/ip22.h
new file mode 100644
index 00000000000..9fd00054f77
--- /dev/null
+++ b/sys/arch/sgi/sgi/ip22.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: ip22.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * IP20/IP22/IP24 definitions
+ */
+
+/* IP22 system types */
+
+#define IP22_INDY 0 /* Indy, Challenge S */
+#define IP22_INDIGO2 1 /* Indigo 2 */
+
+/* Interrupt handling priority */
+
+#define INTPRI_BUSERR (INTPRI_CLOCK + 1)
+#define INTPRI_L1 (INTPRI_BUSERR + 1)
+#define INTPRI_L0 (INTPRI_L1 + 1)
diff --git a/sys/arch/sgi/sgi/ip22_machdep.c b/sys/arch/sgi/sgi/ip22_machdep.c
new file mode 100644
index 00000000000..dbe7ccbd330
--- /dev/null
+++ b/sys/arch/sgi/sgi/ip22_machdep.c
@@ -0,0 +1,277 @@
+/* $OpenBSD: ip22_machdep.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/memconf.h>
+
+#include <mips64/arcbios.h>
+#include <mips64/archtype.h>
+
+#include <sgi/sgi/ip22.h>
+#include <sgi/localbus/imcreg.h>
+#include <sgi/localbus/imcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/iocreg.h>
+
+extern char *hw_prod;
+
+void ip22_arcbios_walk(void);
+int ip22_arcbios_walk_component(arc_config_t *);
+void ip22_memory_setup(void);
+
+/*
+ * Walk the ARCBios component tree to get L2 cache information.
+ * This is the only way we can get the L2 cache size.
+ */
+
+int
+ip22_arcbios_walk_component(arc_config_t *cf)
+{
+ struct cpu_info *ci = curcpu();
+ arc_config_t *child;
+
+ /*
+ * Split secondary caches are not supported.
+ * No IP22 processor module uses them anyway.
+ */
+ if (cf->class == arc_CacheClass && cf->type == arc_SecondaryCache) {
+ /*
+ * Secondary cache information is encoded as WWLLSSSS, where
+ * WW is the number of ways (should be 01)
+ * LL is Log2(line size) (should be 04 or 05)
+ * SS is Log2(cache size in 4KB units) (should be 0007)
+ */
+ ci->ci_l2size = (1 << 12) << (cf->key & 0x0000ffff);
+ /* L2 line size */
+ ci->ci_cacheconfiguration = 1 << ((cf->key >> 16) & 0xff);
+ return 0; /* abort walk */
+ }
+
+ /*
+ * It is safe to assume we have a 32-bit ARCBios, until
+ * IP26 and IP28 support is added, hence unconditional
+ * use of arc_config_t.
+ */
+ for (child = (arc_config_t *)Bios_GetChild(cf); child != NULL;
+ child = (arc_config_t *)Bios_GetPeer(child)) {
+ if (ip22_arcbios_walk_component(child) == 0)
+ return 0;
+ }
+
+ return 1; /* continue walk */
+}
+
+void
+ip22_arcbios_walk()
+{
+ (void)ip22_arcbios_walk_component((arc_config_t *)Bios_GetChild(NULL));
+}
+
+#define IMC_NREGION 3
+
+void
+ip22_memory_setup()
+{
+ uint i, bank, shift;
+ uint32_t memc0, memc1;
+ uint32_t memc;
+ paddr_t base[IMC_NREGION], size[IMC_NREGION], limit;
+ paddr_t start0, end0, start1, end1;
+ struct phys_mem_desc *mem;
+
+ /*
+ * Figure out the top of memory, as reported by ARCBios.
+ */
+
+ limit = 0;
+ for (i = 0, mem = mem_layout; i < MAXMEMSEGS; i++, mem++) {
+ if (mem->mem_last_page > limit)
+ limit = mem->mem_last_page;
+ }
+ limit = ptoa(limit);
+
+ /*
+ * Figure out where the memory controller has put memory.
+ */
+
+ memc0 = imc_read(IMC_MEMCFG0);
+ memc1 = imc_read(IMC_MEMCFG1);
+
+ shift = IMC_MEMC_LSHIFT;
+ /* Revision D onwards uses larger units, to allow for more memory */
+ if ((imc_read(IMC_SYSID) & IMC_SYSID_REVMASK) >= 5)
+ shift = IMC_MEMC_LSHIFT_HUGE;
+
+ for (bank = 0; bank < IMC_NREGION; bank++) {
+ memc = (bank & 2) ? memc1 : memc0;
+ if ((bank & 1) == 0)
+ memc >>= IMC_MEMC_BANK_SHIFT;
+ memc &= IMC_MEMC_BANK_MASK;
+
+ if ((memc & IMC_MEMC_VALID) == 0) {
+ base[bank] = size[bank] = 0;
+ continue;
+ }
+
+ base[bank] = (memc & IMC_MEMC_ADDR_MASK) >> IMC_MEMC_ADDR_SHIFT;
+ base[bank] <<= shift;
+
+ size[bank] = (memc & IMC_MEMC_SIZE_MASK) >> IMC_MEMC_SIZE_SHIFT;
+ size[bank]++;
+ size[bank] <<= shift;
+ }
+
+ /*
+ * Perform sanity checks on the above data..
+ */
+
+ /* memory should not start below 128MB */
+ for (bank = 0; bank < IMC_NREGION; bank++)
+ if (size[bank] != 0 && base[bank] < (1ULL << 27))
+ goto dopanic;
+
+ /* banks should not overlap */
+ for (bank = 1; bank < IMC_NREGION; bank++) {
+ if (size[bank] == 0)
+ continue;
+ start0 = base[bank];
+ end0 = base[bank] + size[bank];
+ for (i = 0; i < bank; i++) {
+ if (size[i] == 0)
+ continue;
+ start1 = base[i];
+ end1 = base[i] + size[i];
+ if (end0 > start1 && start0 < end1)
+ goto dopanic;
+ }
+ }
+
+ /*
+ * Now register all the memory beyond what ARCBios stopped at.
+ */
+
+ for (bank = 0; bank < IMC_NREGION; bank++) {
+ if (size[bank] == 0)
+ continue;
+
+ start0 = base[bank];
+ end0 = base[bank] + size[bank];
+ if (end0 <= limit)
+ continue;
+
+ if (start0 < limit)
+ start0 = limit;
+
+ memrange_register(atop(start0), atop(end0), 0);
+ }
+
+ return;
+
+dopanic:
+ bios_printf("** UNEXPECTED MEMORY CONFIGURATION **\n");
+ bios_printf("MEMC0 %08x MEMC1 %08x\n", memc0, memc1);
+ bios_printf("Please contact <sgi@openbsd.org>\n"
+ "Halting system.\n");
+ Bios_Halt();
+ for (;;) ;
+}
+
+void
+ip22_setup()
+{
+ u_long cpuspeed;
+ volatile uint32_t *sysid;
+
+ /*
+ * Get CPU information.
+ */
+ bootcpu_hwinfo.c0prid = cp0_get_prid();
+ bootcpu_hwinfo.c1prid = cp1_get_prid();
+ cpuspeed = bios_getenvint("cpufreq");
+ if (sys_config.system_type == SGI_IP20)
+ cpuspeed <<= 1;
+ if (cpuspeed < 100)
+ cpuspeed = 100; /* reasonable default */
+ bootcpu_hwinfo.clock = cpuspeed * 1000000;
+ bootcpu_hwinfo.type = (bootcpu_hwinfo.c0prid >> 8) & 0xff;
+
+ /*
+ * Figure out what critter we are running on.
+ */
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ hw_prod = "Indigo";
+ break;
+ case SGI_IP22:
+ sysid = (volatile uint32_t *)
+ PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_0 + IOC_BASE + IOC_SYSID,
+ CCA_NC);
+ if (*sysid & 0x01) {
+ sys_config.system_subtype = IP22_INDIGO2;
+ hw_prod = "Indigo2";
+ } else {
+ sys_config.system_subtype = IP22_INDY;
+ hw_prod = "Indy";
+ }
+ break;
+ case SGI_IP26:
+ sys_config.system_subtype = IP22_INDIGO2;
+ hw_prod = "POWER Indigo2 R8000";
+ break;
+ case SGI_IP28:
+ sys_config.system_subtype = IP22_INDIGO2;
+ hw_prod = "POWER Indigo2 R10000";
+ break;
+ }
+
+ /*
+ * Figure out how many TLB entries are available.
+ */
+ switch (bootcpu_hwinfo.type) {
+#ifdef CPU_R10000
+ case MIPS_R10000:
+ bootcpu_hwinfo.tlbsize = 64;
+ break;
+#endif
+ default: /* R4x00, R5000 */
+ bootcpu_hwinfo.tlbsize = 48;
+ break;
+ }
+
+ /*
+ * Compute memory layout. ARCBios may not report all memory (on
+ * Indigo, it seems to only report up to 128MB, and on Indigo2,
+ * up to 256MB).
+ */
+ ip22_memory_setup();
+
+ /*
+ * Scan ARCBios component list for L2 cache information.
+ */
+ ip22_arcbios_walk();
+
+ _device_register = arcs_device_register;
+}
diff --git a/sys/arch/sgi/sgi/ip30_machdep.c b/sys/arch/sgi/sgi/ip30_machdep.c
index 4a2d5dc02e2..c5077d31438 100644
--- a/sys/arch/sgi/sgi/ip30_machdep.c
+++ b/sys/arch/sgi/sgi/ip30_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip30_machdep.c,v 1.50 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: ip30_machdep.c,v 1.51 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2008, 2009 Miodrag Vallat.
@@ -168,9 +168,7 @@ ip30_setup()
comconsaddr = IOC3_UARTA_BASE;
comconsfreq = 22000000 / 3;
comconsiot = &sys_config.console_io;
- comconsrate = bios_getenvint("dbaud");
- if (comconsrate < 50 || comconsrate > 115200)
- comconsrate = 9600;
+ comconsrate = bios_consrate;
#ifdef DDB
/*
diff --git a/sys/arch/sgi/sgi/ip32_machdep.c b/sys/arch/sgi/sgi/ip32_machdep.c
index e3760cbd031..611f3f2d058 100644
--- a/sys/arch/sgi/sgi/ip32_machdep.c
+++ b/sys/arch/sgi/sgi/ip32_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip32_machdep.c,v 1.17 2012/03/15 18:57:22 miod Exp $ */
+/* $OpenBSD: ip32_machdep.c,v 1.18 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -198,9 +198,7 @@ ip32_setup()
comconsaddr = MACE_ISA_SER1_OFFS;
comconsfreq = 1843200;
comconsiot = &macebus_tag;
- comconsrate = bios_getenvint("dbaud");
- if (comconsrate < 50 || comconsrate > 115200)
- comconsrate = 9600;
+ comconsrate = bios_consrate;
}
/* not sure if there is a way to tell O2 and O2+ apart */
diff --git a/sys/arch/sgi/sgi/machdep.c b/sys/arch/sgi/sgi/machdep.c
index 0d4f8811c2a..52405982621 100644
--- a/sys/arch/sgi/sgi/machdep.c
+++ b/sys/arch/sgi/sgi/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.114 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: machdep.c,v 1.115 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -141,11 +141,11 @@ caddr_t
mips_init(int argc, void *argv, caddr_t boot_esym)
{
char *cp;
- int i;
+ int i, guessed;
u_int cputype;
vaddr_t xtlb_handler;
extern char start[], edata[], end[];
- extern char exception[], e_exception[];
+ extern char cache_err[], exception[], e_exception[];
extern char *hw_vendor;
#ifdef MULTIPROCESSOR
@@ -222,6 +222,34 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
*/
hw_vendor = "SGI";
switch (sys_config.system_type) {
+#ifdef TGT_INDIGO
+ case SGI_IP20:
+ bios_printf("Found SGI-IP20, setting up.\n");
+ /* IP22 is intentional, we use the same kernel */
+ strlcpy(cpu_model, "IP22", sizeof(cpu_model));
+ ip22_setup();
+ break;
+#endif
+#if defined(TGT_INDY) || defined(TGT_INDIGO2)
+ case SGI_IP22:
+ bios_printf("Found SGI-IP22, setting up.\n");
+ strlcpy(cpu_model, "IP22", sizeof(cpu_model));
+ ip22_setup();
+ break;
+#endif
+#ifdef TGT_INDIGO2
+ case SGI_IP26:
+ bios_printf("Found SGI-IP26, setting up.\n");
+ /* IP28 is intentional, we will probably use the same kernel */
+ strlcpy(cpu_model, "IP28", sizeof(cpu_model));
+ ip22_setup();
+ break;
+ case SGI_IP28:
+ bios_printf("Found SGI-IP28, setting up.\n");
+ strlcpy(cpu_model, "IP28", sizeof(cpu_model));
+ ip22_setup();
+ break;
+#endif
#ifdef TGT_O2
case SGI_O2:
bios_printf("Found SGI-IP32, setting up.\n");
@@ -253,10 +281,14 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
break;
#endif
default:
- bios_printf("Kernel doesn't support this system type!\n");
+ bios_printf("There is no support for this system type "
+ "(%02x) in this kernel.\n"
+ "Are you sure you have booted the right kernel "
+ "for this machine?\n",
+ sys_config.system_type);
bios_printf("Halting system.\n");
Bios_Halt();
- while(1);
+ for (;;) ;
}
/*
@@ -277,20 +309,16 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
"The kernel might not be able to find out its root device.\n");
/*
- * Read platform-specific environment variables.
+ * Read platform-specific environment variables from ARCBios.
+ * (Note these may not exist on all systems)
*/
- switch (sys_config.system_type) {
-#ifdef TGT_O2
- case SGI_O2:
- /* Get Ethernet address from ARCBIOS. */
- cp = Bios_GetEnvironmentVariable("eaddr");
- if (cp != NULL && strlen(cp) > 0)
- strlcpy(bios_enaddr, cp, sizeof bios_enaddr);
- break;
-#endif
- default:
- break;
- }
+ /* onboard Ethernet address (does not exist on IP27/IP35) */
+ cp = Bios_GetEnvironmentVariable("eaddr");
+ if (cp != NULL && strlen(cp) > 0)
+ strlcpy(bios_enaddr, cp, sizeof bios_enaddr);
+ bios_consrate = bios_getenvint("dbaud");
+ if (bios_consrate < 50 || bios_consrate > 115200)
+ bios_consrate = 9600; /* sane default */
/*
* Set pagesize to enable use of page macros and functions.
@@ -345,6 +373,7 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
/*
* Configure cache.
*/
+ guessed = 0;
switch (bootcpu_hwinfo.type) {
#ifdef CPU_R10000
case MIPS_R10000:
@@ -353,6 +382,16 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
cputype = MIPS_R10000;
break;
#endif
+#ifdef CPU_R4000
+ case MIPS_R4000:
+ cputype = MIPS_R4000;
+ break;
+#endif
+#ifdef CPU_R4600
+ case MIPS_R4600:
+ cputype = MIPS_R5000;
+ break;
+#endif
#ifdef CPU_R5000
case MIPS_R5000:
case MIPS_RM52X0:
@@ -369,24 +408,52 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
/*
* If we can't identify the cpu type, it must be
* r10k-compatible on Octane and Origin families, and
- * it is likely to be r5k-compatible on O2.
+ * it is likely to be r5k-compatible on O2 and
+ * r4k-compatible on Ind{igo*,y}.
*/
+ guessed = 1;
switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ bios_printf("Unrecognized processor type, assuming"
+ " R4000 compatible\n");
+ cputype = MIPS_R4000;
+ break;
case SGI_O2:
+ bios_printf("Unrecognized processor type, assuming"
+ " R5000 compatible\n");
cputype = MIPS_R5000;
break;
+ case SGI_IP26:
+ bios_printf("Unrecognized processor type, assuming"
+ " R8000 compatible\n");
+ cputype = MIPS_R8000;
+ break;
default:
- case SGI_OCTANE:
case SGI_IP27:
+ case SGI_IP28:
+ case SGI_OCTANE:
case SGI_IP35:
+ bios_printf("Unrecognized processor type, assuming"
+ " R10000 compatible\n");
cputype = MIPS_R10000;
break;
}
break;
}
switch (cputype) {
- default:
-#if defined(CPU_R5000) || defined(CPU_RM7000)
+#ifdef CPU_R4000
+ case MIPS_R4000:
+ Mips4k_ConfigCache(curcpu());
+ sys_config._SyncCache = Mips4k_SyncCache;
+ sys_config._InvalidateICache = Mips4k_InvalidateICache;
+ sys_config._SyncDCachePage = Mips4k_SyncDCachePage;
+ sys_config._HitSyncDCache = Mips4k_HitSyncDCache;
+ sys_config._IOSyncDCache = Mips4k_IOSyncDCache;
+ sys_config._HitInvalidateDCache = Mips4k_HitInvalidateDCache;
+ break;
+#endif
+#if defined(CPU_R4600) || defined(CPU_R5000) || defined(CPU_RM7000)
case MIPS_R5000:
Mips5k_ConfigCache(curcpu());
sys_config._SyncCache = Mips5k_SyncCache;
@@ -408,6 +475,20 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
sys_config._HitInvalidateDCache = Mips10k_HitInvalidateDCache;
break;
#endif
+ default:
+ if (guessed) {
+ bios_printf("There is no support for this processor "
+ "family in this kernel.\n"
+ "Are you sure you have booted the right kernel "
+ "for this machine?\n");
+ } else {
+ bios_printf("There is no support for this processor "
+ "family (%02x) in this kernel.\n", cputype);
+ }
+ bios_printf("Halting system.\n");
+ Bios_Halt();
+ for (;;) ;
+ break;
}
/*
@@ -449,13 +530,21 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
/*
* Copy down exception vector code.
*/
- bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception);
+ bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - cache_err);
bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception);
/*
* Build proper TLB refill handler trampolines.
*/
switch (cputype) {
+#ifdef CPU_R4000
+ case MIPS_R4000:
+ {
+ extern void xtlb_miss_err_r4k;
+ xtlb_handler = (vaddr_t)&xtlb_miss_err_r4k;
+ }
+ break;
+#endif
#if defined(CPU_R5000) || defined(CPU_RM7000)
case MIPS_R5000:
{
@@ -744,9 +833,17 @@ arcbios_halt(int howto)
#endif
if (howto & RB_HALT) {
- if (howto & RB_POWERDOWN)
+ if (howto & RB_POWERDOWN) {
+#ifdef TGT_INDY
+ /*
+ * ARCBios needs to use the FPU on Indy during
+ * shutdown.
+ */
+ if (sys_config.system_type == SGI_IP22)
+ setsr(getsr() | SR_COP_1_BIT);
+#endif
Bios_PowerDown();
- else
+ } else
Bios_EnterInteractiveMode();
} else
Bios_Reboot();
diff --git a/sys/arch/sgi/sgi/mainbus.c b/sys/arch/sgi/sgi/mainbus.c
index 5d8e411d0d1..018bbd372a4 100644
--- a/sys/arch/sgi/sgi/mainbus.c
+++ b/sys/arch/sgi/sgi/mainbus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mainbus.c,v 1.8 2010/01/09 20:33:16 miod Exp $ */
+/* $OpenBSD: mainbus.c,v 1.9 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -89,9 +89,9 @@ mbattach(struct device *parent, struct device *self, void *aux)
}
/*
- * On other systems, attach the CPU we are running on early;
- * other processors, if any, will get attached as they are
- * discovered.
+ * On other systems, attach the CPU, its clock, and the
+ * mainbus here.
+ * XXX Would be worth doing as ipXX_autoconf() too.
*/
bzero(&caa, sizeof caa);
@@ -103,6 +103,19 @@ mbattach(struct device *parent, struct device *self, void *aux)
config_found(self, &caa.caa_maa, mbprint);
switch (sys_config.system_type) {
+#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2)
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ /* Interrupt Controller */
+ caa.caa_maa.maa_name = "int";
+ config_found(self, &caa.caa_maa, mbprint);
+ /* Memory Controller */
+ caa.caa_maa.maa_name = "imc";
+ config_found(self, &caa.caa_maa, mbprint);
+ break;
+#endif
#ifdef TGT_O2
case SGI_O2:
caa.caa_maa.maa_name = "macebus";
diff --git a/sys/arch/sgi/stand/Makefile b/sys/arch/sgi/stand/Makefile
index 62a19908f9c..d18503c5228 100644
--- a/sys/arch/sgi/stand/Makefile
+++ b/sys/arch/sgi/stand/Makefile
@@ -1,11 +1,10 @@
-# $OpenBSD: Makefile,v 1.7 2012/03/19 17:38:29 miod Exp $
+# $OpenBSD: Makefile,v 1.8 2012/03/28 20:44:23 miod Exp $
SUBDIR= sgivol
.if ${MACHINE} == "sgi"
SUBDIR+= libsa libsa32 libz libz32
-SUBDIR+= boot64 boot32
-#SUBDIR+= bootecoff
+SUBDIR+= boot64 boot32 bootecoff
.endif
.include <bsd.subdir.mk>
diff --git a/sys/conf/files b/sys/conf/files
index 379b1e2cdb8..dad448cd616 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.534 2012/03/09 13:01:28 ariane Exp $
+# $OpenBSD: files,v 1.535 2012/03/28 20:44:23 miod Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -234,6 +234,10 @@ file dev/ic/osiop.c osiop & (osiop_gsc | osiop_eisa | osiop_pcctwo)
device oosiop: scsi
file dev/ic/oosiop.c oosiop
+# Western Digital WD33C93 SCSI controllers
+define wd33c93
+file dev/ic/wd33c93.c wd33c93
+
# 3Com Etherlink-III Ethernet controller
device ep: ether, ifnet, ifmedia, mii
file dev/ic/elink3.c ep
diff --git a/sys/dev/eisa/eisavar.h b/sys/dev/eisa/eisavar.h
index d8d5b59f84c..e48cfa8f561 100644
--- a/sys/dev/eisa/eisavar.h
+++ b/sys/dev/eisa/eisavar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: eisavar.h,v 1.13 2010/05/23 14:50:31 deraadt Exp $ */
+/* $OpenBSD: eisavar.h,v 1.14 2012/03/28 20:44:23 miod Exp $ */
/* $NetBSD: eisavar.h,v 1.11 1997/06/06 23:30:07 thorpej Exp $ */
/*
@@ -54,17 +54,12 @@ struct eisabus_attach_args;
/*
* Machine-dependent definitions.
*/
-#if (__alpha__ + __i386__ + __hppa__ != 1)
-#error COMPILING FOR UNSUPPORTED MACHINE, OR MORE THAN ONE.
-#endif
-#if __alpha__
+#if defined(__alpha__)
#include <alpha/eisa/eisa_machdep.h>
-#endif
-#if __i386__
+#elif defined(__i386__)
#include <i386/eisa/eisa_machdep.h>
-#endif
-#if __hppa__
-#include <hppa/include/eisa_machdep.h>
+#else
+#include <machine/eisa_machdep.h>
#endif
typedef int eisa_slot_t; /* really only needs to be 4 bits */
diff --git a/sys/dev/ic/dp8573areg.h b/sys/dev/ic/dp8573areg.h
new file mode 100644
index 00000000000..bf66e70bf1e
--- /dev/null
+++ b/sys/dev/ic/dp8573areg.h
@@ -0,0 +1,121 @@
+/* $OpenBSD: dp8573areg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: dp8573areg.h,v 1.1 2009/02/12 06:33:57 rumble Exp $ */
+
+/*
+ * Copyright (c) 2003 Steve Rumble
+ * Copyright (c) 2001 Erik Reid
+ *
+ * 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. 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.
+ */
+
+/*
+ * National Semiconductor DP8573A Real Time Clock
+ */
+
+/* Control and Status Register Offsets and Masks */
+#define DP8573A_STATUS 0x00 /* Main Status */
+#define DP8573A_STATUS_INTSTAT 0x01 /* Interrupt Status */
+#define DP8573A_STATUS_PWRFAIL 0x02 /* Power Fail Interrupt */
+#define DP8573A_STATUS_PERINT 0x04 /* Period Interrupt */
+#define DP8573A_STATUS_ALMINT 0x08 /* Alarm Interrupt */
+#define DP8573A_STATUS_REGSEL 0x40 /* Register Select */
+
+/* Register Select = 0 */
+#define DP8573A_PFLAG 0x03 /* Periodic Flag */
+#define DP8573A_PFLAG_MIN 0x01 /* Minutes */
+#define DP8573A_PFLAG_10SEC 0x02 /* Ten Second */
+#define DP8573A_PFLAG_SEC 0x04 /* Seconds */
+#define DP8573A_PFLAG_100MIL 0x08 /* 100 Millisecond */
+#define DP8573A_PFLAG_10MIL 0x10 /* 10 Millisecond */
+#define DP8573A_PFLAG_MIL 0x20 /* Milliseconds */
+#define DP8573A_PFLAG_OFSS 0x40 /* Oscillator Fail/Single Supply */
+#define DP8573A_PFLAG_TESTMODE 0x80 /* Test Mode Enable */
+
+#define DP8573A_TIMESAVE_CTL 0x04 /* Time Save Control */
+#define DP8573A_TIMESAVE_CTL_EN 0x80 /* Time Save Enable */
+
+/* Register Select = 1 */
+#define DP8573A_RT_MODE 0x01 /* Real Time Mode */
+#define DP8573A_RT_MODE_LYLSB 0x01 /* Leap Year LSB */
+#define DP8573A_RT_MODE_LYMSB 0x02 /* Leap Year MSB */
+#define DP8573A_RT_MODE_1224 0x04 /* 12(low)/24(high) Hour Mode */
+#define DP8573A_RT_MODE_CLKSS 0x08 /* Clock Start(high)/Stop(low) */
+#define DP8573A_RT_MODE_INTPFOP 0x10 /* Interrupt PF Operation */
+
+#define DP8573A_OUT_MODE 0x02 /* Output Mode */
+#define DP8573A_OUT_MODE_MFOPO 0x80 /* MFO Pin as Oscillator */
+
+#define DP8573A_INT0_CTL 0x03 /* Interrupt Control 0 */
+#define DP8573A_INT0_CTL_MIN 0x01 /* Minutes Enable */
+#define DP8573A_INT0_CTL_10SEC 0x02 /* 10 Second Enable */
+#define DP8573A_INT0_CTL_SEC 0x04 /* Seconds Enable */
+#define DP8573A_INT0_CTL_100MIL 0x08 /* 100 Millisecond Enable */
+#define DP8573A_INT0_CTL_10MIL 0x10 /* 10 Millisecond Enable */
+#define DP8573A_INT0_CTL_MIL 0x20 /* Millisecond Enable */
+
+#define DP8573A_INT1_CTL 0x04 /* Interrupt Control 1 */
+#define DP8573A_INT1_CTL_SECC 0x01 /* Second Compare Enable */
+#define DP8573A_INT1_CTL_MINC 0x02 /* Minute Compare Enable */
+#define DP8573A_INT1_CTL_HOURC 0x04 /* Hour Compare Enable */
+#define DP8573A_INT1_CTL_DOMC 0x08 /* Day of Month Compare Enable */
+#define DP8573A_INT1_CTL_MONTHC 0x10 /* Month Compare Enable */
+#define DP8573A_INT1_CTL_DOWC 0x20 /* Day of Week Compare Enable */
+#define DP8573A_INT1_CTL_ALMINT 0x40 /* Alarm Interrupt Enable */
+#define DP8573A_INT1_CTL_PWRINT 0x80 /* Power Fail Interrupt Enable */
+
+/* Clock Counter Offsets */
+#define DP8573A_COUNTERS 0x05 /* Start of Clock Counters */
+#define DP8573A_SUBSECOND 0x05 /* 1/100 Second */
+#define DP8573A_SECOND 0x06 /* Seconds */
+#define DP8573A_MINUTE 0x07 /* Minutes */
+#define DP8573A_HOUR 0x08 /* Hours */
+#define DP8573A_DOM 0x09 /* Day of Month */
+#define DP8573A_MONTH 0x0a /* Months */
+#define DP8573A_YEAR 0x0b /* Years */
+#define DP8573A_DOW 0x0e /* Day of Week */
+
+/* Comparsion Registers */
+#define DP8573A_CMP_SEC 0x13 /* Seconds */
+#define DP8573A_CMP_MIN 0x14 /* Minutes */
+#define DP8573A_CMP_HOUR 0x15 /* Hours */
+#define DP8573A_CMP_DOM 0x16 /* Day of Month */
+#define DP8573A_CMP_MONTH 0x17 /* Months */
+#define DP8573A_CMP_DOW 0x18 /* Day of Week */
+
+/* Time Save Registers */
+#define DP8573A_SAVE_SEC 0x19 /* Seconds */
+#define DP8573A_SAVE_MIN 0x1a /* Minutes */
+#define DP8573A_SAVE_HOUR 0x1b /* Hours */
+#define DP8573A_SAVE_DOM 0x1c /* Day of Month */
+#define DP8573A_SAVE_MONTH 0x1d /* Months */
+
+/* RAM Registers */
+#define DP8573A_RAM_0C 0x0c /* RAM */
+#define DP8573A_RAM_1E 0x1e /* RAM */
+#define DP8573A_RAM_1F 0x1f /* RAM */
+
+/* 12/24 Hour Masks */
+#define DP8573A_HOUR_12HR_MASK 0x1f
+#define DP8573A_HOUR_24HR_MASK 0x3f
+
+#define DP8573A_NREG 0x20
diff --git a/sys/dev/ic/dp857xreg.h b/sys/dev/ic/dp857xreg.h
deleted file mode 100644
index 9164c574718..00000000000
--- a/sys/dev/ic/dp857xreg.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/* $OpenBSD: dp857xreg.h,v 1.4 2012/03/07 18:15:25 miod Exp $ */
-
-/*
- * Copyright (c) 1996 Per Fogelstrom
- *
- * 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.
- *
- * 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.
- *
- */
-
-#if !defined(_DP857X_H)
-#define _DP857X_H
-
-/*
- * Definition of Real Time Clock address space.
- *
- * Clock is a National DP8570A RTC
- */
-#define BSIZE 1 /* No of Bytes for Address Spacing */
-#define MAIN_STATUS 0x00 /* Main status register */
-/*
- * Registers selected with BS=0 RS=0
- */
-#define TIMER0_CTRL 0x01 /* Timer 0 control register */
-#define TIMER1_CTRL 0x02 /* Timer 0 control register */
-#define PERIODIC_FLAGS 0x03 /* Timer periodic flag register */
-#define INTERRUPT_ROUT 0x04 /* Interrupt routing register */
-/*
- * Registers selected with BS=0 RS=1
- */
-#define REAL_TIME_MODE 0x01 /* Real Time Mode register */
-#define OUTPUT_MODE 0x02 /* Output mode register */
-#define INTERRUPT_CTRL0 0x03 /* Interrupt control register 0 */
-#define INTERRUPT_CTRL1 0x04 /* Interrupt control register 1 */
-/*
- * Clock and timer registers when BS=0
- */
-#define CLK_SUBSECONDS 0x05 /* 1/100 seconds register */
-#define CLK_SECONDS 0x06 /* Seconds */
-#define CLK_MINUTES 0x07 /* Minutes */
-#define CLK_HOURS 0x08 /* Hours */
-#define CLK_DAY 0x09 /* Day of month */
-#define CLK_MONTH 0x0a /* Month */
-#define CLK_YEAR 0x0b /* Year */
-#define CLK_JULIAN_L 0x0c /* Lsb of Julian date */
-#define CLK_JULIAN_H 0x0d /* Msb of Julian date */
-#define CLK_WEEKDAY 0x0e /* Day of week */
-#define TIMER0_LSB 0x0f /* Timer 0 lsb */
-#define TIMER0_MSB 0x10 /* Timer 0 msb */
-#define TIMER1_LSB 0x11 /* Timer 1 lsb */
-#define TIMER1_MSB 0x12 /* Timer 1 msb */
-#define CMP_SECONDS 0x13 /* Seconds compare */
-#define CMP_MINUTES 0x14 /* Minutes compare */
-#define CMP_HOUR 0x15 /* Hours compare */
-#define CMP_DAY 0x16 /* Day of month compare */
-#define CMP_MONTH 0x17 /* Month compare */
-#define CMP_WEEKDAY 0x18 /* Day of week compare */
-#define SAVE_SECONDS 0x19 /* Seconds time save */
-#define SAVE_MINUTES 0x1a /* Minutes time save */
-#define SAVE_HOUR 0x1b /* Hours time save */
-#define SAVE_DAY 0x1c /* Day of month time save */
-#define SAVE_MONTH 0x1d /* Month time save */
-#define RAM_1E 0x1e /* Ram location 1e */
-#define RAM_1F 0x1f /* Ram location 1f */
-#define SIZE_DP857X 0x20 /* Size of dp address map */
-
-#define DP_FIRSTTODREG CLK_SUBSECONDS
-#define DP_LASTTODREG CLK_WEEKDAY
-
-typedef u_int dp_todregs[SIZE_DP857X];
-u_int dp857x_read(void *sc, u_int reg);
-void dp857x_write(void *sc, u_int reg, u_int datum);
-
-/*
- * Get all of the TOD/Alarm registers
- * Must be called at splhigh(), and with the RTC properly set up.
- */
-#define DP857X_GETTOD(sc, regs) \
- do { \
- int i; \
- \
- /* make sure clock regs are selected */ \
- dp857x_write(sc, MAIN_STATUS, 0); \
- /* try read until no rollover */ \
- do { \
- /* read all of the tod/alarm regs */ \
- for (i = DP_FIRSTTODREG; i < SIZE_DP857X; i++) \
- (*regs)[i] = dp857x_read(sc, i); \
- } while(dp857x_read(sc, PERIODIC_FLAGS) & 7); \
- } while (0);
-
-/*
- * Set all of the TOD/Alarm registers
- * Must be called at splhigh(), and with the RTC properly set up.
- */
-#define DP857X_PUTTOD(sc, regs) \
- do { \
- int i; \
- \
- /* stop updates while setting, eg clear start bit */ \
- dp857x_write(sc, MAIN_STATUS, 0x40); \
- dp857x_write(sc, REAL_TIME_MODE, \
- dp857x_read(sc, REAL_TIME_MODE) & 0xF7); \
- \
- /* write all of the tod/alarm regs */ \
- for (i = DP_FIRSTTODREG; i <= DP_LASTTODREG; i++) \
- dp857x_write(sc, i, (*regs)[i]); \
- \
- /* reenable updates, eg set clock start bit */ \
- dp857x_write(sc, REAL_TIME_MODE, \
- dp857x_read(sc, REAL_TIME_MODE) | 0x08); \
- } while (0);
-
-#endif /*_DP857X_H*/
-
diff --git a/sys/dev/ic/ds1286reg.h b/sys/dev/ic/ds1286reg.h
new file mode 100644
index 00000000000..2b625fc181f
--- /dev/null
+++ b/sys/dev/ic/ds1286reg.h
@@ -0,0 +1,182 @@
+/* $OpenBSD: ds1286reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: ds1286reg.h,v 1.8 2005/12/11 12:21:26 christos Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ *
+ * 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. 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.
+ */
+
+/*
+ * Originally based on mc146818reg.h, with the following license:
+ *
+ * Copyright (c) 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Definitions for the Dallas Semiconductor DS1286/DS1386 Real Time Clock.
+ *
+ * Plucked right from the Dallas Semicomductor specs available at
+ * http://pdfserv.maxim-ic.com/arpdf/DS1286.pdf and
+ * http://pdfserv.maxim-ic.com/arpdf/DS1386-DS1386P.pdf
+ *
+ * The DS1286 and 1386 have 14 clock-related registers and some amount
+ * of user registers (50 for the 1286, 8K or 32K for the 1386). The
+ * first eleven registers contain time-of-day and alarm data, the rest
+ * contain various control bits and the watchdog timer functionality.
+ *
+ * Since the locations of these ports and the method used to access
+ * them can be machine-dependent, the low-level details of reading
+ * and writing the RTC's registers are handled by machine-specific
+ * functions.
+ *
+ * The DS1286/DS1386 chips always store time-of-day and alarm data in
+ * BCD. The "hour" time-of-year and alarm fields can either be stored
+ * in AM/PM format, or in 24-hour format. If AM/PM format is chosen,
+ * the hour fields can have the values: 1-12 (for AM) and 21-32 (for
+ * PM). If the 24-hour format is chosen, they can have the values 0
+ * to 23. The hour format is selectable separately for the time and
+ * alarm fields, and is controller by bit 6 of the respective register.
+ */
+
+/*
+ * The registers, and the bits within each register.
+ */
+
+#define DS1286_SUBSEC 0x0 /* Time of year: hundredths of seconds (0-99) */
+#define DS1286_SEC 0x1 /* Time of year: seconds (0-59) */
+#define DS1286_MIN 0x2 /* Time of year: minutes (0-59) */
+#define DS1286_AMIN 0x3 /* Alarm: minutes */
+#define DS1286_HOUR 0x4 /* Time of year: hour (see above) */
+
+#define DS1286_HOUR_12MODE 0x40 /* Hour mode: 12-hour (on), 24 (off) */
+#define DS1286_HOUR_12HR_PM 0x20 /* AM/PM in 12-hour mode: on = PM */
+#define DS1286_HOUR_12HR_MASK 0x1f /* Mask for hours in 12hour mode */
+#define DS1286_HOUR_24HR_MASK 0x3f /* Mask for hours in 24hour mode */
+
+#define DS1286_AHOUR 0x5 /* Alarm: hour */
+#define DS1286_DOW 0x6 /* Time of year: day of week (1-7) */
+#define DS1286_ADOW 0x7 /* Alarm: day of week (1-7) */
+#define DS1286_DOM 0x8 /* Time of year: day of month (1-31) */
+#define DS1286_MONTH 0x9 /* Time of year: month (1-12), wave generator */
+
+#define DS1286_MONTH_MASK 0x3f /* Mask to extract month */
+#define DS1286_WAVEGEN_MASK 0xc0 /* Mask to extract wave bits */
+
+#define DS1286_YEAR 0xA /* Time of year: year in century (0-99) */
+
+#define DS1286_CONTROL 0xB /* Control register A */
+
+#define DS1286_TE 0x80 /* Update in progress (on == disable update) */
+#define DS1286_INTSWAP 0x40 /* Swap INTA, INTB outputs */
+#define DS1286_INTBSRC 0x20 /* INTB source (on) or sink (off) current */
+#define DS1286_INTAPLS 0x10 /* INTA pulse (on) or level (off) mode */
+#define DS1286_WAM 0x08 /* Watchdog alarm mask */
+#define DS1286_TDM 0x04 /* Time-of-day alarm mask */
+#define DS1286_WAF 0x02 /* Watchdog alarm flag */
+#define DS1286_TDF 0x01 /* Time-of-day alarm flag */
+
+#define DS1286_NREGS 0xd /* 14 registers; CMOS follows */
+#define DS1286_NTODREGS 0xb /* 11 of those regs are for TOD and alarm */
+
+#define DS1286_NVRAM_START 0xe /* start of NVRAM: offset 14 */
+
+/* NVRAM size depends on the chip -- the 1286 only has 50 bytes, whereas
+ * the 1386 can have 8K or 32K
+ */
+#define DS1286_NVRAM_SIZE 50 /* 50 bytes of NVRAM */
+
+/*
+ * RTC register/NVRAM read and write functions -- machine-dependent.
+ * Appropriately manipulate RTC registers to get/put data values.
+ */
+u_int ds1286_read(void *, u_int);
+void ds1286_write(void *, u_int, u_int);
+
+/*
+ * A collection of TOD/Alarm registers.
+ */
+typedef u_int ds1286_todregs[DS1286_NTODREGS];
+
+/*
+ * Get all of the TOD/Alarm registers
+ * Must be called at splhigh(), and with the RTC properly set up.
+ */
+#define DS1286_GETTOD(sc, regs) \
+ do { \
+ int i; \
+ u_int ctl; \
+ \
+ /* turn off update for now */ \
+ ctl = ds1286_read(sc, DS1286_CONTROL); \
+ ds1286_write(sc, DS1286_CONTROL, ctl | DS1286_TE); \
+ \
+ /* read all of the tod/alarm regs */ \
+ for (i = 0; i < DS1286_NTODREGS; i++) \
+ (*regs)[i] = ds1286_read(sc, i); \
+ \
+ /* turn update back on */ \
+ ds1286_write(sc, DS1286_CONTROL, ctl); \
+ } while (0);
+
+/*
+ * Set all of the TOD/Alarm registers
+ * Must be called at splhigh(), and with the RTC properly set up.
+ */
+#define DS1286_PUTTOD(sc, regs) \
+ do { \
+ int i; \
+ u_int ctl; \
+ \
+ /* turn off update for now */ \
+ ctl = ds1286_read(sc, DS1286_CONTROL); \
+ ds1286_write(sc, DS1286_CONTROL, ctl | DS1286_TE); \
+ \
+ /* write all of the tod/alarm regs */ \
+ for (i = 0; i < DS1286_NTODREGS; i++) \
+ ds1286_write(sc, i, (*regs)[i]); \
+ \
+ /* turn update back on */ \
+ ds1286_write(sc, DS1286_CONTROL, ctl); \
+ } while (0);
diff --git a/sys/dev/ic/seeq8003reg.h b/sys/dev/ic/seeq8003reg.h
new file mode 100644
index 00000000000..c0978c67508
--- /dev/null
+++ b/sys/dev/ic/seeq8003reg.h
@@ -0,0 +1,134 @@
+/* $OpenBSD: seeq8003reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: seeq8003reg.h,v 1.3 2001/06/07 05:19:26 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2000 Soren S. Jorvang. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Register definitions for the Seeq 8003 and 80C03 ethernet controllers
+ *
+ * Based on documentation available at
+ * http://www.lsilogic.com/techlib/techdocs/networking/eol/80c03.pdf .
+ */
+
+#define SEEQ_ADDR0 0 /* Station Address Byte 0 */
+#define SEEQ_ADDR1 1 /* Station Address Byte 1 */
+#define SEEQ_ADDR2 2 /* Station Address Byte 2 */
+#define SEEQ_ADDR3 3 /* Station Address Byte 3 */
+#define SEEQ_ADDR4 4 /* Station Address Byte 4 */
+#define SEEQ_ADDR5 5 /* Station Address Byte 5 */
+
+#define SEEQ_TXCOLLS0 0 /* Transmit Collision Counter LSB */
+#define SEEQ_TXCOLLS1 1 /* Transmit Collision Counter MSB */
+#define SEEQ_ALLCOLL0 2 /* Total Collision Counter LSB */
+#define SEEQ_ALLCOLL1 3 /* Total Collision Counter MSB */
+
+#define SEEQ_TEST 4 /* "For Test Only" - Do Not Use */
+
+#define SEEQ_SQE 5 /* SQE / No Carrier */
+#define SQE_FLAG 0x01 /* SQE Flag */
+#define SQE_NOCARR 0x02 /* No Carrier Flag */
+
+#define SEEQ_RXCMD 6 /* Rx Command */
+#define RXCMD_IE_OFLOW 0x01 /* Interrupt on Overflow Error */
+#define RXCMD_IE_CRC 0x02 /* Interrupt on CRC Error */
+#define RXCMD_IE_DRIB 0x04 /* Interrupt on Dribble Error */
+#define RXCMD_IE_SHORT 0x08 /* Interrupt on Short Frame */
+#define RXCMD_IE_END 0x10 /* Interrupt on End of Frame */
+#define RXCMD_IE_GOOD 0x20 /* Interrupt on Good Frame */
+#define RXCMD_REC_MASK 0xc0 /* Receiver Match Mode Mask */
+#define RXCMD_REC_NONE 0x00 /* Receiver Disabled */
+#define RXCMD_REC_ALL 0x40 /* Receive All Frames */
+#define RXCMD_REC_BROAD 0x80 /* Receive Station/Broadcast Frames */
+#define RXCMD_REC_MULTI 0xc0 /* Station/Broadcast/Multicast */
+
+#define SEEQ_RXSTAT 6 /* Rx Status */
+#define RXSTAT_OFLOW 0x01 /* Frame Overflow Error */
+#define RXSTAT_CRC 0x02 /* Frame CRC Error */
+#define RXSTAT_DRIB 0x04 /* Frame Dribble Error */
+#define RXSTAT_SHORT 0x08 /* Received Short Frame */
+#define RXSTAT_END 0x10 /* Received End of Frame */
+#define RXSTAT_GOOD 0x20 /* Received Good Frame */
+#define RXSTAT_OLDNEW 0x80 /* Old/New Status */
+
+#define SEEQ_TXCMD 7 /* Tx Command */
+#define TXCMD_IE_UFLOW 0x01 /* Interrupt on Transmit Underflow */
+#define TXCMD_IE_COLL 0x02 /* Interrupt on Transmit Collision */
+#define TXCMD_IE_16COLL 0x04 /* Interrupt on 16 Collisions */
+#define TXCMD_IE_GOOD 0x08 /* Interrupt on Transmit Succes */
+#define TXCMD_ENABLE_C 0xf0 /* (80C03) Enable 80C03 Mode */
+#define TXCMD_BANK_MASK 0x60 /* (80C03) Register Bank Mask */
+#define TXCMD_BANK0 0x00 /* (80C03) Register Bank 0 (8003) */
+#define TXCMD_BANK1 0x20 /* (80C03) Register Bank 1 (Writes) */
+#define TXCMD_BANK2 0x40 /* (80C03) Register Bank 2 (Writes) */
+
+#define SEEQ_TXSTAT 7 /* Tx Status */
+#define TXSTAT_UFLOW 0x01 /* Transmit Underflow */
+#define TXSTAT_COLL 0x02 /* Transmit Collision */
+#define TXSTAT_16COLL 0x04 /* 16 Collisions */
+#define TXSTAT_GOOD 0x08 /* Transmit Success */
+#define TXSTAT_OLDNEW 0x80 /* Old/New Status */
+
+/*
+ * 80C03 Mode Register Bank 1
+ */
+
+#define SEEQ_MC_HASH0 0 /* Multicast Filter Byte 0 (LSB) */
+#define SEEQ_MC_HASH1 1 /* Multicast Filter Byte 1 */
+#define SEEQ_MC_HASH2 2 /* Multicast Filter Byte 2 */
+#define SEEQ_MC_HASH3 3 /* Multicast Filter Byte 3 */
+#define SEEQ_MC_HASH4 4 /* Multicast Filter Byte 4 */
+#define SEEQ_MC_HASH5 5 /* Multicast Filter Byte 5 */
+
+/*
+ * 80C03 Mode Register Bank 2
+ */
+
+#define SEEQ_MC_HASH6 0 /* Multicast Filter Byte 6 */
+#define SEEQ_MC_HASH7 1 /* Multicast Filter Byte 7 (MSB) */
+
+#define SEEQ_RESERVED0 2 /* Reserved (Set to All Zeroes) */
+
+#define SEEQ_TXCTRL 3 /* Tx Control */
+#define TXCTRL_TXCOLL 0x01 /* Clear/Enable Tx Collision Counter */
+#define TXCTRL_COLL 0x02 /* Clear/Enable Collision Counter */
+#define TXCTRL_SQE 0x04 /* Clear/Enable SQE Flag */
+#define TXCTRL_HASH 0x08 /* Enable Multicast Hash Filter */
+#define TXCTRL_SHORT 0x10 /* Receive Short (<13 Bytes) Frames */
+#define TXCTRL_NOCARR 0x20 /* Clear/Enable No Carrier Flag */
+
+#define SEEQ_CFG 4 /* Transmit/Receive Configuration */
+#define CFG_RX_GRPADDR 0x01 /* Ignore Last 4 Bits of Address */
+#define CFG_TX_AUTOPAD 0x02 /* Automatically Pad to 60 Bytes */
+#define CFG_TX_NOPRE 0x04 /* Do Not Add Preamble Pattern */
+#define CFG_RX_NOOWN 0x08 /* Do Not Receive Own Packets */
+#define CFG_TX_NOCRC 0x10 /* No Not Append CRC */
+#define CFG_TX_DUPLEX 0x20 /* AutoDUPLEX - Ignore Carrier */
+#define CFG_RX_CRCFIFO 0x40 /* Write CRC to FIFO */
+#define CFG_RX_FASTDISC 0x80 /* Fast Receive Discard Mode */
+
+#define SEEQ_RESERVED1 5 /* Reserved */
+#define SEEQ_RESERVED2 6 /* Reserved */
+#define SEEQ_RESERVED3 7 /* Reserved */
diff --git a/sys/dev/ic/wd33c93.c b/sys/dev/ic/wd33c93.c
new file mode 100644
index 00000000000..2c6fabc6660
--- /dev/null
+++ b/sys/dev/ic/wd33c93.c
@@ -0,0 +1,2337 @@
+/* $OpenBSD: wd33c93.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: wd33c93.c,v 1.24 2010/11/13 13:52:02 uebayasi Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsi.c 7.5 (Berkeley) 5/4/91
+ */
+
+/*
+ * Changes Copyright (c) 2001 Wayne Knowles
+ * Changes Copyright (c) 1996 Steve Woodford
+ * Original Copyright (c) 1994 Christian E. Hopps
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsi.c 7.5 (Berkeley) 5/4/91
+ */
+
+/*
+ * This version of the driver is pretty well generic, so should work with
+ * any flavour of WD33C93 chip.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h> /* For hz */
+#include <sys/malloc.h>
+#include <sys/pool.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_message.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/wd33c93reg.h>
+#include <dev/ic/wd33c93var.h>
+
+/*
+ * SCSI delays
+ * In u-seconds, primarily for state changes on the SPC.
+ */
+#define SBIC_CMD_WAIT 200000 /* wait per step of 'immediate' cmds */
+#define SBIC_DATA_WAIT 200000 /* wait per data in/out step */
+#define SBIC_INIT_WAIT 200000 /* wait per step (both) during init */
+
+#define STATUS_UNKNOWN 0xff /* uninitialized status */
+
+/*
+ * Convenience macro for waiting for a particular wd33c93 event
+ */
+#define SBIC_WAIT(regs, until, timeo) wd33c93_wait(regs, until, timeo, __LINE__)
+
+void wd33c93_init(struct wd33c93_softc *);
+void wd33c93_reset(struct wd33c93_softc *);
+int wd33c93_go(struct wd33c93_softc *, struct wd33c93_acb *);
+int wd33c93_dmaok(struct wd33c93_softc *, struct scsi_xfer *);
+int wd33c93_wait(struct wd33c93_softc *, u_char, int , int);
+u_char wd33c93_selectbus(struct wd33c93_softc *, struct wd33c93_acb *);
+int wd33c93_xfout(struct wd33c93_softc *, int, void *);
+int wd33c93_xfin(struct wd33c93_softc *, int, void *);
+int wd33c93_poll(struct wd33c93_softc *, struct wd33c93_acb *);
+int wd33c93_nextstate(struct wd33c93_softc *, struct wd33c93_acb *,
+ u_char, u_char);
+int wd33c93_abort(struct wd33c93_softc *, struct wd33c93_acb *,
+ const char *);
+void wd33c93_xferdone(struct wd33c93_softc *);
+void wd33c93_error(struct wd33c93_softc *, struct wd33c93_acb *);
+void wd33c93_scsidone(struct wd33c93_softc *, struct wd33c93_acb *, int);
+void wd33c93_sched(struct wd33c93_softc *);
+void wd33c93_dequeue(struct wd33c93_softc *, struct wd33c93_acb *);
+void wd33c93_dma_stop(struct wd33c93_softc *);
+void wd33c93_dma_setup(struct wd33c93_softc *, int);
+int wd33c93_msgin_phase(struct wd33c93_softc *, int);
+void wd33c93_msgin(struct wd33c93_softc *, u_char *, int);
+void wd33c93_reselect(struct wd33c93_softc *, int, int, int, int);
+void wd33c93_sched_msgout(struct wd33c93_softc *, u_short);
+void wd33c93_msgout(struct wd33c93_softc *);
+void wd33c93_timeout(void *arg);
+void wd33c93_watchdog(void *arg);
+u_char wd33c93_stp2syn(struct wd33c93_softc *, struct wd33c93_tinfo *);
+void wd33c93_setsync(struct wd33c93_softc *, struct wd33c93_tinfo *);
+
+struct pool wd33c93_pool; /* Adapter Control Blocks */
+int wd33c93_pool_initialized = 0;
+
+/*
+ * Timeouts
+ */
+int wd33c93_cmd_wait = SBIC_CMD_WAIT;
+int wd33c93_data_wait = SBIC_DATA_WAIT;
+int wd33c93_init_wait = SBIC_INIT_WAIT;
+
+int wd33c93_nodma = 0; /* Use polled IO transfers */
+int wd33c93_nodisc = 0; /* Allow command queues */
+int wd33c93_notags = 0; /* No Tags */
+
+/*
+ * Some useful stuff for debugging purposes
+ */
+#ifdef SBICDEBUG
+
+#define QPRINTF(a) SBIC_DEBUG(MISC, a)
+
+int wd33c93_debug = 0; /* Debug flags */
+
+void wd33c93_print_csr (u_char);
+void wd33c93_hexdump (u_char *, int);
+
+#else
+#define QPRINTF(a) /* */
+#endif
+
+static const char *wd33c93_chip_names[] = SBIC_CHIP_LIST;
+
+/*
+ * Attach instance of driver and probe for sub devices
+ */
+void
+wd33c93_attach(struct wd33c93_softc *sc, struct scsi_adapter *adapter)
+{
+ struct scsibus_attach_args saa;
+
+ sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags;
+ timeout_set(&sc->sc_watchdog, wd33c93_watchdog, sc);
+ wd33c93_init(sc);
+
+ printf(": %s, %d.%d MHz, %s\n",
+ wd33c93_chip_names[sc->sc_chip],
+ sc->sc_clkfreq / 10, sc->sc_clkfreq % 10,
+ (sc->sc_dmamode == SBIC_CTL_DMA) ? "DMA" :
+ (sc->sc_dmamode == SBIC_CTL_DBA_DMA) ? "DBA" :
+ (sc->sc_dmamode == SBIC_CTL_BURST_DMA) ? "burst DMA" : "PIO");
+ if (sc->sc_chip == SBIC_CHIP_WD33C93B) {
+ printf("%s: microcode revision 0x%02x",
+ sc->sc_dev.dv_xname, sc->sc_rev);
+ if (sc->sc_minsyncperiod < 50)
+ printf(", fast SCSI");
+ printf("\n");
+ }
+
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = sc->sc_id;
+ sc->sc_link.adapter_buswidth = SBIC_NTARG;
+ sc->sc_link.adapter = adapter;
+ sc->sc_link.openings = 2;
+ sc->sc_link.luns = SBIC_NLUN;
+
+ bzero(&saa, sizeof(saa));
+ saa.saa_sc_link = &sc->sc_link;
+
+ config_found(&sc->sc_dev, &saa, scsiprint);
+ timeout_add_sec(&sc->sc_watchdog, 60);
+}
+
+/*
+ * Initialize driver-private structures
+ */
+void
+wd33c93_init(struct wd33c93_softc *sc)
+{
+ u_int i;
+
+ timeout_del(&sc->sc_watchdog);
+
+ if (!wd33c93_pool_initialized) {
+ /* All instances share the same pool */
+ pool_init(&wd33c93_pool, sizeof(struct wd33c93_acb), 0, 0, 0,
+ "wd33c93_acb", NULL);
+ ++wd33c93_pool_initialized;
+ }
+
+ if (sc->sc_state == 0) {
+ TAILQ_INIT(&sc->ready_list);
+
+ sc->sc_nexus = NULL;
+ sc->sc_disc = 0;
+ memset(sc->sc_tinfo, 0, sizeof(sc->sc_tinfo));
+ } else {
+ /* XXX cancel all active commands */
+ panic("wd33c93: reinitializing driver!");
+ }
+
+ sc->sc_flags = 0;
+ sc->sc_state = SBIC_IDLE;
+ wd33c93_reset(sc);
+
+ for (i = 0; i < SBIC_NTARG; i++) {
+ struct wd33c93_tinfo *ti = &sc->sc_tinfo[i];
+ /*
+ * cf_flags = 0xTTSSRR
+ *
+ * TT = Bitmask to disable Tagged Queues
+ * SS = Bitmask to disable Sync negotiation
+ * RR = Bitmask to disable disconnect/reselect
+ */
+ ti->flags = T_NEED_RESET;
+ if (CFFLAGS_NOSYNC(sc->sc_cfflags, i))
+ ti->flags |= T_NOSYNC;
+ if (CFFLAGS_NODISC(sc->sc_cfflags, i) || wd33c93_nodisc)
+ ti->flags |= T_NODISC;
+ ti->period = sc->sc_minsyncperiod;
+ ti->offset = 0;
+ }
+}
+
+void
+wd33c93_reset(struct wd33c93_softc *sc)
+{
+ u_int my_id, s, div, i;
+ u_char csr, reg;
+
+ SET_SBIC_cmd(sc, SBIC_CMD_ABORT);
+ WAIT_CIP(sc);
+
+ s = splbio();
+
+ if (sc->sc_reset != NULL)
+ (*sc->sc_reset)(sc);
+
+ my_id = sc->sc_link.adapter_target & SBIC_ID_MASK;
+
+ /* Enable advanced features and really(!) advanced features */
+#if 1
+ my_id |= (SBIC_ID_EAF | SBIC_ID_RAF); /* XXX - MD Layer */
+#endif
+
+ SET_SBIC_myid(sc, my_id);
+
+ /* Reset the chip */
+ SET_SBIC_cmd(sc, SBIC_CMD_RESET);
+ DELAY(25);
+ SBIC_WAIT(sc, SBIC_ASR_INT, 0);
+
+ /* Set up various chip parameters */
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ GET_SBIC_csr(sc, csr); /* clears interrupt also */
+ GET_SBIC_cdb1(sc, sc->sc_rev); /* valid with RAF on wd33c93b */
+
+ switch (csr) {
+ case SBIC_CSR_RESET:
+ sc->sc_chip = SBIC_CHIP_WD33C93;
+ break;
+ case SBIC_CSR_RESET_AM:
+ SET_SBIC_queue_tag(sc, 0x55);
+ GET_SBIC_queue_tag(sc, reg);
+ sc->sc_chip = (reg == 0x55) ?
+ SBIC_CHIP_WD33C93B : SBIC_CHIP_WD33C93A;
+ SET_SBIC_queue_tag(sc, 0x0);
+ break;
+ default:
+ sc->sc_chip = SBIC_CHIP_UNKNOWN;
+ }
+
+ /*
+ * Choose a suitable clock divisor and work out the resulting
+ * sync transfer periods in 4ns units.
+ */
+ if (sc->sc_clkfreq < 110) {
+ my_id |= SBIC_ID_FS_8_10;
+ div = 2;
+ } else if (sc->sc_clkfreq < 160) {
+ my_id |= SBIC_ID_FS_12_15;
+ div = 3;
+ } else if (sc->sc_clkfreq < 210) {
+ my_id |= SBIC_ID_FS_16_20;
+ div = 4;
+ } else
+ panic("wd33c93: invalid clock speed %d", sc->sc_clkfreq);
+
+ for (i = 0; i < 7; i++)
+ sc->sc_syncperiods[i] =
+ (i + 2) * div * 1250 / sc->sc_clkfreq;
+ sc->sc_minsyncperiod = sc->sc_syncperiods[0];
+ SBIC_DEBUG(SYNC, ("available sync periods: %d %d %d %d %d %d %d\n",
+ sc->sc_syncperiods[0], sc->sc_syncperiods[1],
+ sc->sc_syncperiods[2], sc->sc_syncperiods[3],
+ sc->sc_syncperiods[4], sc->sc_syncperiods[5],
+ sc->sc_syncperiods[6]));
+
+ if (sc->sc_clkfreq >= 160 && sc->sc_chip == SBIC_CHIP_WD33C93B) {
+ for (i = 0; i < 3; i++)
+ sc->sc_fsyncperiods[i] =
+ (i + 2) * 2 * 1250 / sc->sc_clkfreq;
+ SBIC_DEBUG(SYNC, ("available fast sync periods: %d %d %d\n",
+ sc->sc_fsyncperiods[0], sc->sc_fsyncperiods[1],
+ sc->sc_fsyncperiods[2]));
+ sc->sc_minsyncperiod = sc->sc_fsyncperiods[0];
+ }
+
+ /* Max Sync Offset */
+ if (sc->sc_chip == SBIC_CHIP_WD33C93A ||
+ sc->sc_chip == SBIC_CHIP_WD33C93B)
+ sc->sc_maxoffset = SBIC_SYN_93AB_MAX_OFFSET;
+ else
+ sc->sc_maxoffset = SBIC_SYN_93_MAX_OFFSET;
+
+ /*
+ * don't allow Selection (SBIC_RID_ES)
+ * until we can handle target mode!!
+ */
+ SET_SBIC_rselid(sc, SBIC_RID_ER);
+
+ /* Asynchronous for now */
+ SET_SBIC_syn(sc, 0);
+
+ sc->sc_flags = 0;
+ sc->sc_state = SBIC_IDLE;
+
+ splx(s);
+}
+
+void
+wd33c93_error(struct wd33c93_softc *sc, struct wd33c93_acb *acb)
+{
+ struct scsi_xfer *xs = acb->xs;
+
+ KASSERT(xs);
+
+ if (xs->flags & SCSI_SILENT)
+ return;
+
+ sc_print_addr(xs->sc_link);
+ printf("SCSI Error\n");
+}
+
+/*
+ * Determine an appropriate value for the synchronous transfer register
+ * given the period and offset values in *ti.
+ */
+u_char
+wd33c93_stp2syn(struct wd33c93_softc *sc, struct wd33c93_tinfo *ti)
+{
+ unsigned i;
+
+ /* see if we can handle fast scsi (100-200ns) first */
+ if (ti->period < 50 && sc->sc_minsyncperiod < 50) {
+ for (i = 0; i < 3; i++)
+ if (sc->sc_fsyncperiods[i] >= ti->period)
+ return (SBIC_SYN(ti->offset, i + 2, 1));
+ }
+
+ for (i = 0; i < 7; i++) {
+ if (sc->sc_syncperiods[i] >= ti->period) {
+ if (i == 6)
+ return (SBIC_SYN(0, 0, 0));
+ else
+ return (SBIC_SYN(ti->offset, i + 2, 0));
+ }
+ }
+
+ /* XXX - can't handle it; do async */
+ return (SBIC_SYN(0, 0, 0));
+}
+
+/*
+ * Setup sync mode for given target
+ */
+void
+wd33c93_setsync(struct wd33c93_softc *sc, struct wd33c93_tinfo *ti)
+{
+ u_char syncreg;
+
+ if (ti->flags & T_SYNCMODE)
+ syncreg = wd33c93_stp2syn(sc, ti);
+ else
+ syncreg = SBIC_SYN(0, 0, 0);
+
+ SBIC_DEBUG(SYNC, ("wd33c93_setsync: sync reg = 0x%02x\n", syncreg));
+ SET_SBIC_syn(sc, syncreg);
+}
+
+/*
+ * Check if current operation can be done using DMA
+ *
+ * returns 1 if DMA OK, 0 for polled I/O transfer
+ */
+int
+wd33c93_dmaok(struct wd33c93_softc *sc, struct scsi_xfer *xs)
+{
+ if (wd33c93_nodma || sc->sc_dmamode == SBIC_CTL_NO_DMA ||
+ (xs->flags & SCSI_POLL) || xs->datalen == 0)
+ return (0);
+ return(1);
+}
+
+/*
+ * Setup for DMA transfer
+ */
+void
+wd33c93_dma_setup(struct wd33c93_softc *sc, int datain)
+{
+ struct wd33c93_acb *acb = sc->sc_nexus;
+ int s;
+
+ sc->sc_daddr = acb->daddr;
+ sc->sc_dleft = acb->dleft;
+
+ s = splbio();
+ /* Indicate that we're in DMA mode */
+ if (sc->sc_dleft) {
+ sc->sc_dmasetup(sc, &sc->sc_daddr, &sc->sc_dleft,
+ datain, &sc->sc_dleft);
+ }
+ splx(s);
+ return;
+}
+
+
+/*
+ * Save DMA pointers. Take into account partial transfer. Shut down DMA.
+ */
+void
+wd33c93_dma_stop(struct wd33c93_softc *sc)
+{
+ size_t count;
+ int asr;
+
+ /* Wait until WD chip is idle */
+ do {
+ GET_SBIC_asr(sc, asr); /* XXX */
+ if (asr & SBIC_ASR_DBR) {
+ printf("wd33c93_dma_stop: asr %02x canceled!\n", asr);
+ break;
+ }
+ } while (asr & (SBIC_ASR_BSY|SBIC_ASR_CIP));
+
+ /* Only need to save pointers if DMA was active */
+ if (sc->sc_flags & SBICF_INDMA) {
+ int s = splbio();
+
+ /* Shut down DMA and flush FIFO's */
+ sc->sc_dmastop(sc);
+
+ /* Fetch the residual count */
+ SBIC_TC_GET(sc, count);
+
+ /* Work out how many bytes were actually transferred */
+ count = sc->sc_tcnt - count;
+
+ if (sc->sc_dleft < count)
+ printf("xfer too large: dleft=%zu resid=%zu\n",
+ sc->sc_dleft, count);
+
+ /* Fixup partial xfers */
+ sc->sc_daddr = (char *)sc->sc_daddr + count;
+ sc->sc_dleft -= count;
+ sc->sc_tcnt = 0;
+ sc->sc_flags &= ~SBICF_INDMA;
+ splx(s);
+ SBIC_DEBUG(DMA, ("dma_stop\n"));
+ }
+ /*
+ * Ensure the WD chip is back in polled I/O mode, with nothing to
+ * transfer.
+ */
+ SBIC_TC_PUT(sc, 0);
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
+}
+
+
+/*
+ * Handle new request from scsi layer
+ */
+void
+wd33c93_scsi_cmd(struct scsi_xfer *xs)
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct wd33c93_softc *sc = sc_link->adapter_softc;
+ struct wd33c93_acb *acb;
+ int flags, s;
+
+ SBIC_DEBUG(MISC, ("wd33c93_scsi_cmd\n"));
+
+ flags = xs->flags;
+
+ if (sc->sc_nexus && (flags & SCSI_POLL))
+ panic("wd33c93_scsicmd: busy");
+
+ s = splbio();
+ acb = (struct wd33c93_acb *)pool_get(&wd33c93_pool,
+ PR_NOWAIT | PR_ZERO);
+ splx(s);
+
+ if (acb == NULL) {
+ xs->error = XS_NO_CCB;
+ scsi_done(xs);
+ return;
+ }
+
+ acb->flags = ACB_ACTIVE;
+ acb->xs = xs;
+ acb->timeout = xs->timeout;
+ timeout_set(&acb->to, wd33c93_timeout, acb);
+
+ memcpy(&acb->cmd, xs->cmd, xs->cmdlen);
+ acb->clen = xs->cmdlen;
+ acb->daddr = xs->data;
+ acb->dleft = xs->datalen;
+
+#if 0
+ if (flags & SCSI_POLL) {
+ /*
+ * Complete currently active command(s) before
+ * issuing an immediate command
+ */
+ while (sc->sc_nexus)
+ wd33c93_poll(sc, sc->sc_nexus);
+ }
+#endif
+
+ s = splbio();
+ TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
+ acb->flags |= ACB_READY;
+
+ /* If nothing is active, try to start it now. */
+ if (sc->sc_state == SBIC_IDLE)
+ wd33c93_sched(sc);
+ splx(s);
+
+ if ((flags & SCSI_POLL) == 0)
+ return;
+
+ if (wd33c93_poll(sc, acb)) {
+ wd33c93_timeout(acb);
+ if (wd33c93_poll(sc, acb)) /* 2nd retry for ABORT */
+ wd33c93_timeout(acb);
+ }
+}
+
+/*
+ * attempt to start the next available command
+ */
+void
+wd33c93_sched(struct wd33c93_softc *sc)
+{
+ struct scsi_link *sc_link;
+ struct wd33c93_acb *acb;
+ struct wd33c93_tinfo *ti;
+ struct wd33c93_linfo *li;
+ int lun, tag, flags;
+ int s;
+
+ if (sc->sc_state != SBIC_IDLE)
+ return;
+
+ KASSERT(sc->sc_nexus == NULL);
+
+ /* Loop through the ready list looking for work to do... */
+ TAILQ_FOREACH(acb, &sc->ready_list, chain) {
+ sc_link = acb->xs->sc_link;
+ lun = sc_link->lun;
+ ti = &sc->sc_tinfo[sc_link->target];
+
+ KASSERT(acb->flags & ACB_READY);
+
+ /* Select type of tag for this command */
+ if ((ti->flags & T_NODISC) != 0)
+ tag = 0;
+ else if ((ti->flags & T_TAG) == 0)
+ tag = 0;
+ else if ((acb->flags & ACB_SENSE) != 0)
+ tag = 0;
+ else if (acb->xs->flags & SCSI_POLL)
+ tag = 0; /* No tags for polled commands */
+ else
+ tag = MSG_SIMPLE_Q_TAG;
+
+ s = splbio();
+ li = TINFO_LUN(ti, lun);
+ if (li == NULL) {
+ /* Initialize LUN info and add to list. */
+ li = malloc(sizeof(*li), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (li == NULL) {
+ splx(s);
+ continue;
+ }
+ li->lun = lun;
+ if (lun < SBIC_NLUN)
+ ti->lun[lun] = li;
+ }
+ li->last_used = time_second;
+
+ /*
+ * We've found a potential command, but is the target/lun busy?
+ */
+
+ if (tag == 0 && li->untagged == NULL)
+ li->untagged = acb; /* Issue untagged */
+
+ if (li->untagged != NULL) {
+ tag = 0;
+ if ((li->state != L_STATE_BUSY) && li->used == 0) {
+ /* Issue this untagged command now */
+ acb = li->untagged;
+ sc_link = acb->xs->sc_link;
+ } else{
+ /* Not ready yet */
+ splx(s);
+ continue;
+ }
+ }
+
+ acb->tag_type = tag;
+ if (tag != 0) {
+ int i;
+
+ /* Allocate a tag */
+ if (li->used == 255) {
+ /* no free tags */
+ splx(s);
+ continue;
+ }
+ /* Start from the last used location */
+ for (i = li->avail; i < 256; i++) {
+ if (li->queued[i] == NULL)
+ break;
+ }
+ /* Couldn't find one, start again from the beginning */
+ if (i == 256) {
+ for (i = 0; i < 256; i++) {
+ if (li->queued[i] == NULL)
+ break;
+ }
+ }
+#ifdef DIAGNOSTIC
+ if (i == 256)
+ panic("%s: tag alloc failure", __func__);
+#endif
+
+ /* Save where to start next time. */
+ li->avail = i + 1;
+ li->used++;
+ li->queued[i] = acb;
+ acb->tag_id = i;
+ }
+ splx(s);
+ if (li->untagged != NULL && (li->state != L_STATE_BUSY)) {
+ li->state = L_STATE_BUSY;
+ break;
+ }
+ if (li->untagged == NULL && tag != 0) {
+ break;
+ } else
+ printf("%d:%d busy\n", sc_link->target, sc_link->lun);
+ }
+
+ if (acb == NULL) {
+ SBIC_DEBUG(ACBS, ("wd33c93sched: no work\n"));
+ return; /* did not find an available command */
+ }
+
+ SBIC_DEBUG(ACBS, ("wd33c93_sched(%d,%d)\n", sc_link->target,
+ sc_link->lun));
+
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ acb->flags &= ~ACB_READY;
+
+ flags = acb->xs->flags;
+ if (flags & SCSI_RESET)
+ wd33c93_reset(sc);
+
+ /* XXX - Implicitly call scsidone on select timeout */
+ if (wd33c93_go(sc, acb) != 0 || acb->xs->error == XS_SELTIMEOUT) {
+ acb->dleft = sc->sc_dleft;
+ wd33c93_scsidone(sc, acb, sc->sc_status);
+ return;
+ }
+}
+
+void
+wd33c93_scsidone(struct wd33c93_softc *sc, struct wd33c93_acb *acb, int status)
+{
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct wd33c93_tinfo *ti;
+ struct wd33c93_linfo *li;
+ int s;
+
+#ifdef DIAGNOSTIC
+ KASSERT(sc->target == sc_link->target);
+ KASSERT(sc->lun == sc_link->lun);
+ KASSERT(acb->flags != ACB_FREE);
+#endif
+
+ SBIC_DEBUG(ACBS, ("scsidone: (%d,%d)->(%d,%d)%02x\n",
+ sc_link->target, sc_link->lun, sc->target, sc->lun, status));
+
+ timeout_del(&acb->to);
+
+ if (xs->error == XS_NOERROR) {
+ xs->status = status & SCSI_STATUS_MASK;
+ xs->resid = acb->dleft;
+
+ switch (xs->status) {
+ case SCSI_CHECK:
+ case SCSI_TERMINATED:
+ /* XXX Need to read sense - return busy for now */
+ /*FALLTHROUGH*/
+ case SCSI_QUEUE_FULL:
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ }
+ }
+
+ ti = &sc->sc_tinfo[sc_link->target];
+ li = TINFO_LUN(ti, sc_link->lun);
+ ti->cmds++;
+ if (xs->error == XS_SELTIMEOUT) {
+ /* Selection timeout -- discard this LUN if empty */
+ if (li->untagged == NULL && li->used == 0) {
+ if (sc_link->lun < SBIC_NLUN)
+ ti->lun[sc_link->lun] = NULL;
+ free(li, M_DEVBUF);
+ }
+ }
+
+ wd33c93_dequeue(sc, acb);
+ if (sc->sc_nexus == acb) {
+ sc->sc_state = SBIC_IDLE;
+ sc->sc_nexus = NULL;
+ sc->sc_flags = 0;
+
+ if (!TAILQ_EMPTY(&sc->ready_list))
+ wd33c93_sched(sc);
+ }
+
+ /* place control block back on free list. */
+ if ((xs->flags & SCSI_POLL) == 0) {
+ s = splbio();
+ acb->flags = ACB_FREE;
+ pool_put(&wd33c93_pool, acb);
+ splx(s);
+ }
+
+ scsi_done(xs);
+}
+
+void
+wd33c93_dequeue(struct wd33c93_softc *sc, struct wd33c93_acb *acb)
+{
+ struct wd33c93_tinfo *ti = &sc->sc_tinfo[acb->xs->sc_link->target];
+ struct wd33c93_linfo *li;
+ int lun = acb->xs->sc_link->lun;
+
+ li = TINFO_LUN(ti, lun);
+#ifdef DIAGNOSTIC
+ if (li == NULL || li->lun != lun)
+ panic("wd33c93_dequeue: lun %d for ecb %p does not exist",
+ lun, acb);
+#endif
+ if (li->untagged == acb) {
+ li->state = L_STATE_IDLE;
+ li->untagged = NULL;
+ }
+ if (acb->tag_type && li->queued[acb->tag_id] != NULL) {
+#ifdef DIAGNOSTIC
+ if (li->queued[acb->tag_id] != NULL &&
+ (li->queued[acb->tag_id] != acb))
+ panic("wd33c93_dequeue: slot %d for lun %d has %p "
+ "instead of acb %p\n", acb->tag_id,
+ lun, li->queued[acb->tag_id], acb);
+#endif
+ li->queued[acb->tag_id] = NULL;
+ li->used--;
+ }
+}
+
+
+int
+wd33c93_wait(struct wd33c93_softc *sc, u_char until, int timeo, int line)
+{
+ u_char val;
+
+ if (timeo == 0)
+ timeo = 1000000; /* some large value.. */
+ GET_SBIC_asr(sc, val);
+ while ((val & until) == 0) {
+ if (timeo-- == 0) {
+ int csr;
+ GET_SBIC_csr(sc, csr);
+#ifdef SBICDEBUG
+ printf("wd33c93_wait: TIMEO @%d with asr=0x%x csr=0x%x\n",
+ line, val, csr);
+#ifdef DDB
+ Debugger();
+#endif
+#endif
+ return(val); /* Maybe I should abort */
+ break;
+ }
+ DELAY(1);
+ GET_SBIC_asr(sc, val);
+ }
+ return(val);
+}
+
+int
+wd33c93_abort(struct wd33c93_softc *sc, struct wd33c93_acb *acb,
+ const char *where)
+{
+ u_char csr, asr;
+
+ GET_SBIC_asr(sc, asr);
+ GET_SBIC_csr(sc, csr);
+
+ sc_print_addr(acb->xs->sc_link);
+ printf("ABORT in %s: csr=0x%02x, asr=0x%02x\n", where, csr, asr);
+
+ acb->timeout = SBIC_ABORT_TIMEOUT;
+ acb->flags |= ACB_ABORT;
+
+ /*
+ * Clean up chip itself
+ */
+ if (sc->sc_nexus == acb) {
+ /* Reschedule timeout. */
+ timeout_add_msec(&acb->to, acb->timeout);
+
+ while (asr & SBIC_ASR_DBR) {
+ /*
+ * wd33c93 is jammed w/data. need to clear it
+ * But we don't know what direction it needs to go
+ */
+ GET_SBIC_data(sc, asr);
+ printf("abort %s: clearing data buffer 0x%02x\n",
+ where, asr);
+ GET_SBIC_asr(sc, asr);
+ if (asr & SBIC_ASR_DBR) /* Not the read direction */
+ SET_SBIC_data(sc, asr);
+ GET_SBIC_asr(sc, asr);
+ }
+
+ sc_print_addr(acb->xs->sc_link);
+ printf("sending ABORT command\n");
+
+ WAIT_CIP(sc);
+ SET_SBIC_cmd(sc, SBIC_CMD_ABORT);
+ WAIT_CIP(sc);
+
+ GET_SBIC_asr(sc, asr);
+
+ sc_print_addr(acb->xs->sc_link);
+ if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) {
+ /*
+ * ok, get more drastic..
+ */
+ printf("Resetting bus\n");
+ wd33c93_reset(sc);
+ } else {
+ printf("sending DISCONNECT to target\n");
+ SET_SBIC_cmd(sc, SBIC_CMD_DISC);
+ WAIT_CIP(sc);
+
+ do {
+ SBIC_WAIT (sc, SBIC_ASR_INT, 0);
+ GET_SBIC_asr(sc, asr);
+ GET_SBIC_csr(sc, csr);
+ SBIC_DEBUG(MISC, ("csr: 0x%02x, asr: 0x%02x\n",
+ csr, asr));
+ } while ((csr != SBIC_CSR_DISC) &&
+ (csr != SBIC_CSR_DISC_1) &&
+ (csr != SBIC_CSR_CMD_INVALID));
+ }
+ sc->sc_state = SBIC_ERROR;
+ sc->sc_flags = 0;
+ }
+ return SBIC_STATE_ERROR;
+}
+
+
+/*
+ * select the bus, return when selected or error.
+ *
+ * Returns the current CSR following selection and optionally MSG out phase.
+ * i.e. the returned CSR *should* indicate CMD phase...
+ * If the return value is 0, some error happened.
+ */
+u_char
+wd33c93_selectbus(struct wd33c93_softc *sc, struct wd33c93_acb *acb)
+{
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct wd33c93_tinfo *ti;
+ u_char target, lun, asr, csr, id;
+
+ KASSERT(sc->sc_state == SBIC_IDLE);
+
+ target = sc_link->target;
+ lun = sc_link->lun;
+ ti = &sc->sc_tinfo[target];
+
+ sc->sc_state = SBIC_SELECTING;
+ sc->target = target;
+ sc->lun = lun;
+
+ SBIC_DEBUG(PHASE, ("wd33c93_selectbus %d: ", target));
+
+ if ((xs->flags & SCSI_POLL) == 0)
+ timeout_add_msec(&acb->to, acb->timeout);
+
+ /*
+ * issue select
+ */
+ SBIC_TC_PUT(sc, 0);
+ SET_SBIC_selid(sc, target);
+ SET_SBIC_timeo(sc, SBIC_TIMEOUT(250, sc->sc_clkfreq));
+
+ GET_SBIC_asr(sc, asr);
+ if (asr & (SBIC_ASR_INT|SBIC_ASR_BSY)) {
+ /* This means we got ourselves reselected upon */
+ SBIC_DEBUG(PHASE, ("WD busy (reselect?) ASR=%02x\n", asr));
+ return 0;
+ }
+
+ SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN);
+ WAIT_CIP(sc);
+
+ /*
+ * wait for select (merged from separate function may need
+ * cleanup)
+ */
+ do {
+ asr = SBIC_WAIT(sc, SBIC_ASR_INT | SBIC_ASR_LCI, 0);
+ if (asr & SBIC_ASR_LCI) {
+ QPRINTF(("late LCI: asr %02x\n", asr));
+ return 0;
+ }
+
+ /* Clear interrupt */
+ GET_SBIC_csr (sc, csr);
+
+ /* Reselected from under our feet? */
+ if (csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY) {
+ SBIC_DEBUG(PHASE, ("got reselected, asr %02x\n", asr));
+ /*
+ * We need to handle this now so we don't lock up later
+ */
+ wd33c93_nextstate(sc, acb, csr, asr);
+ return 0;
+ }
+
+ /* Whoops! */
+ if (csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN) {
+ panic("wd33c93_selectbus: target issued select!");
+ return 0;
+ }
+
+ } while (csr != (SBIC_CSR_MIS_2 | MESG_OUT_PHASE) &&
+ csr != (SBIC_CSR_MIS_2 | CMD_PHASE) &&
+ csr != SBIC_CSR_SEL_TIMEO);
+
+ /* Anyone at home? */
+ if (csr == SBIC_CSR_SEL_TIMEO) {
+ xs->error = XS_SELTIMEOUT;
+ SBIC_DEBUG(PHASE, ("-- Selection Timeout\n"));
+ return 0;
+ }
+
+ SBIC_DEBUG(PHASE, ("Selection Complete\n"));
+
+ /* Assume we're now selected */
+ GET_SBIC_selid(sc, id);
+ if (id != target) {
+ /* Something went wrong - wrong target was select */
+ printf("wd33c93_selectbus: wrong target selected;"
+ " WANTED %d GOT %d", target, id);
+ return 0; /* XXX: Need to call nexstate to handle? */
+ }
+
+ sc->sc_flags |= SBICF_SELECTED;
+ sc->sc_state = SBIC_CONNECTED;
+
+ /* setup correct sync mode for this target */
+ wd33c93_setsync(sc, ti);
+
+ if (ti->flags & T_NODISC && sc->sc_disc == 0)
+ SET_SBIC_rselid (sc, 0); /* Not expecting a reselect */
+ else
+ SET_SBIC_rselid (sc, SBIC_RID_ER);
+
+ /*
+ * We only really need to do anything when the target goes to MSG out
+ * If the device ignored ATN, it's probably old and brain-dead,
+ * but we'll try to support it anyhow.
+ * If it doesn't support message out, it definately doesn't
+ * support synchronous transfers, so no point in even asking...
+ */
+ if (csr == (SBIC_CSR_MIS_2 | MESG_OUT_PHASE)) {
+ if (ti->flags & T_NEGOTIATE) {
+ /* Initiate a SDTR message */
+ SBIC_DEBUG(SYNC, ("Sending SDTR to target %d\n", id));
+ if (ti->flags & T_WANTSYNC) {
+ ti->period = sc->sc_minsyncperiod;
+ ti->offset = sc->sc_maxoffset;
+ } else {
+ ti->period = 0;
+ ti->offset = 0;
+ }
+ /* Send Sync negotiation message */
+ sc->sc_omsg[0] = MSG_IDENTIFY(lun, 0); /* No Disc */
+ sc->sc_omsg[1] = MSG_EXTENDED;
+ sc->sc_omsg[2] = MSG_EXT_SDTR_LEN;
+ sc->sc_omsg[3] = MSG_EXT_SDTR;
+ if (ti->flags & T_WANTSYNC) {
+ sc->sc_omsg[4] = sc->sc_minsyncperiod;
+ sc->sc_omsg[5] = sc->sc_maxoffset;
+ } else {
+ sc->sc_omsg[4] = 0;
+ sc->sc_omsg[5] = 0;
+ }
+ wd33c93_xfout(sc, 6, sc->sc_omsg);
+ sc->sc_msgout |= SEND_SDTR; /* may be rejected */
+ sc->sc_flags |= SBICF_SYNCNEGO;
+ } else {
+ if (sc->sc_nexus->tag_type != 0) {
+ /* Use TAGS */
+ SBIC_DEBUG(TAGS, ("<select %d:%d TAG=%x>\n",
+ sc->target, sc->lun,
+ sc->sc_nexus->tag_id));
+ sc->sc_omsg[0] = MSG_IDENTIFY(lun, 1);
+ sc->sc_omsg[1] = sc->sc_nexus->tag_type;
+ sc->sc_omsg[2] = sc->sc_nexus->tag_id;
+ wd33c93_xfout(sc, 3, sc->sc_omsg);
+ sc->sc_msgout |= SEND_TAG;
+ } else {
+ int no_disc;
+
+ /* Setup LUN nexus and disconnect privilege */
+ no_disc = xs->flags & SCSI_POLL ||
+ ti->flags & T_NODISC;
+ SEND_BYTE(sc, MSG_IDENTIFY(lun, !no_disc));
+ }
+ }
+ /*
+ * There's one interrupt still to come:
+ * the change to CMD phase...
+ */
+ SBIC_WAIT(sc, SBIC_ASR_INT , 0);
+ GET_SBIC_csr(sc, csr);
+ }
+
+ return csr;
+}
+
+/*
+ * Information Transfer *to* a SCSI Target.
+ *
+ * Note: Don't expect there to be an interrupt immediately after all
+ * the data is transferred out. The WD spec sheet says that the Transfer-
+ * Info command for non-MSG_IN phases only completes when the target
+ * next asserts 'REQ'. That is, when the SCSI bus changes to a new state.
+ *
+ * This can have a nasty effect on commands which take a relatively long
+ * time to complete, for example a START/STOP unit command may remain in
+ * CMD phase until the disk has spun up. Only then will the target change
+ * to STATUS phase. This is really only a problem for immediate commands
+ * since we don't allow disconnection for them (yet).
+ */
+int
+wd33c93_xfout(struct wd33c93_softc *sc, int len, void *bp)
+{
+ int wait = wd33c93_data_wait;
+ u_char asr, *buf = bp;
+
+ QPRINTF(("wd33c93_xfout {%d} %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x\n", len, buf[0], buf[1], buf[2],
+ buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]));
+
+ /*
+ * sigh.. WD-PROTO strikes again.. sending the command in one go
+ * causes the chip to lock up if talking to certain (misbehaving?)
+ * targets. Anyway, this procedure should work for all targets, but
+ * it's slightly slower due to the overhead
+ */
+
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ SBIC_TC_PUT (sc, (unsigned)len);
+
+ WAIT_CIP (sc);
+ SET_SBIC_cmd (sc, SBIC_CMD_XFER_INFO);
+
+ /*
+ * Loop for each byte transferred
+ */
+ do {
+ GET_SBIC_asr (sc, asr);
+
+ if (asr & SBIC_ASR_DBR) {
+ if (len) {
+ SET_SBIC_data (sc, *buf);
+ buf++;
+ len--;
+ } else {
+ SET_SBIC_data (sc, 0);
+ }
+ wait = wd33c93_data_wait;
+ }
+ } while (len && (asr & SBIC_ASR_INT) == 0 && wait-- > 0);
+
+ QPRINTF(("wd33c93_xfout done: %d bytes remaining (wait:%d)\n", len, wait));
+
+ /*
+ * Normally, an interrupt will be pending when this routing returns.
+ */
+ return(len);
+}
+
+/*
+ * Information Transfer *from* a Scsi Target
+ * returns # bytes left to read
+ */
+int
+wd33c93_xfin(struct wd33c93_softc *sc, int len, void *bp)
+{
+ int wait = wd33c93_data_wait;
+ u_char *buf = bp;
+ u_char asr;
+#ifdef SBICDEBUG
+ u_char *obp = bp;
+#endif
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ SBIC_TC_PUT (sc, (unsigned)len);
+
+ WAIT_CIP (sc);
+ SET_SBIC_cmd (sc, SBIC_CMD_XFER_INFO);
+
+ /*
+ * Loop for each byte transferred
+ */
+ do {
+ GET_SBIC_asr (sc, asr);
+
+ if (asr & SBIC_ASR_DBR) {
+ if (len) {
+ GET_SBIC_data (sc, *buf);
+ buf++;
+ len--;
+ } else {
+ u_char foo;
+ GET_SBIC_data (sc, foo);
+ }
+ wait = wd33c93_data_wait;
+ }
+
+ } while ((asr & SBIC_ASR_INT) == 0 && wait-- > 0);
+
+ QPRINTF(("wd33c93_xfin {%d} %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2],
+ obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9]));
+
+ SBIC_TC_PUT (sc, 0);
+
+ /*
+ * this leaves with one csr to be read
+ */
+ return len;
+}
+
+
+/*
+ * Finish SCSI xfer command: After the completion interrupt from
+ * a read/write operation, sequence through the final phases in
+ * programmed i/o.
+ */
+void
+wd33c93_xferdone(struct wd33c93_softc *sc)
+{
+ u_char phase, csr;
+ int s;
+
+ QPRINTF(("{"));
+ s = splbio();
+
+ /*
+ * have the wd33c93 complete on its own
+ */
+ SBIC_TC_PUT(sc, 0);
+ SET_SBIC_cmd_phase(sc, 0x46);
+ SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN_XFER);
+
+ do {
+ SBIC_WAIT (sc, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (sc, csr);
+ QPRINTF(("%02x:", csr));
+ } while ((csr != SBIC_CSR_DISC) &&
+ (csr != SBIC_CSR_DISC_1) &&
+ (csr != SBIC_CSR_S_XFERRED));
+
+ sc->sc_flags &= ~SBICF_SELECTED;
+ sc->sc_state = SBIC_DISCONNECT;
+
+ GET_SBIC_cmd_phase (sc, phase);
+ QPRINTF(("}%02x", phase));
+
+ if (phase == 0x60)
+ GET_SBIC_tlun(sc, sc->sc_status);
+ else
+ wd33c93_error(sc, sc->sc_nexus);
+
+ QPRINTF(("=STS:%02x=\n", sc->sc_status));
+ splx(s);
+}
+
+
+int
+wd33c93_go(struct wd33c93_softc *sc, struct wd33c93_acb *acb)
+{
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ int i, dmaok;
+ u_char csr, asr;
+
+ SBIC_DEBUG(ACBS, ("wd33c93_go(%d:%d)\n", sc_link->target, sc_link->lun));
+
+ sc->sc_nexus = acb;
+
+ sc->target = sc_link->target;
+ sc->lun = sc_link->lun;
+
+ sc->sc_status = STATUS_UNKNOWN;
+ sc->sc_daddr = acb->daddr;
+ sc->sc_dleft = acb->dleft;
+
+ sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0;
+ sc->sc_flags = 0;
+
+ dmaok = wd33c93_dmaok(sc, xs);
+
+ if (dmaok == 0)
+ sc->sc_flags |= SBICF_NODMA;
+
+ SBIC_DEBUG(DMA, ("wd33c93_go dmago:%d(tcnt=%zx) dmaok=%d\n",
+ sc->target, sc->sc_tcnt, dmaok));
+
+ /* select the SCSI bus (it's an error if bus isn't free) */
+ if ((csr = wd33c93_selectbus(sc, acb)) == 0)
+ return(0); /* Not done: needs to be rescheduled */
+
+ /*
+ * Lets cycle a while then let the interrupt handler take over.
+ */
+ GET_SBIC_asr(sc, asr);
+ do {
+ QPRINTF(("go[0x%x] ", csr));
+
+ /* Handle the new phase */
+ i = wd33c93_nextstate(sc, acb, csr, asr);
+ WAIT_CIP(sc); /* XXX */
+ if (sc->sc_state == SBIC_CONNECTED) {
+
+ GET_SBIC_asr(sc, asr);
+
+ if (asr & SBIC_ASR_LCI)
+ printf("wd33c93_go: LCI asr:%02x csr:%02x\n", asr, csr);
+
+ if (asr & SBIC_ASR_INT)
+ GET_SBIC_csr(sc, csr);
+ }
+
+ } while (sc->sc_state == SBIC_CONNECTED &&
+ asr & (SBIC_ASR_INT|SBIC_ASR_LCI));
+
+ QPRINTF(("> done i=%d stat=%02x\n", i, sc->sc_status));
+
+ if (i == SBIC_STATE_DONE) {
+ if (sc->sc_status == STATUS_UNKNOWN) {
+ printf("wd33c93_go: done & stat == UNKNOWN\n");
+ return 1; /* Did we really finish that fast? */
+ }
+ }
+ return 0;
+}
+
+
+int
+wd33c93_intr(void *v)
+{
+ struct wd33c93_softc *sc = v;
+ u_char asr, csr;
+ int i;
+
+ /*
+ * pending interrupt?
+ */
+ GET_SBIC_asr (sc, asr);
+ if ((asr & SBIC_ASR_INT) == 0)
+ return(0);
+
+ GET_SBIC_csr(sc, csr);
+
+ do {
+ SBIC_DEBUG(INTS, ("intr[csr=0x%x]", csr));
+
+ i = wd33c93_nextstate(sc, sc->sc_nexus, csr, asr);
+ WAIT_CIP(sc); /* XXX */
+ if (sc->sc_state == SBIC_CONNECTED) {
+ GET_SBIC_asr(sc, asr);
+
+ if (asr & SBIC_ASR_LCI)
+ printf("wd33c93_intr: LCI asr:%02x csr:%02x\n",
+ asr, csr);
+
+ if (asr & SBIC_ASR_INT)
+ GET_SBIC_csr(sc, csr);
+ }
+ } while (sc->sc_state == SBIC_CONNECTED &&
+ asr & (SBIC_ASR_INT|SBIC_ASR_LCI));
+
+ SBIC_DEBUG(INTS, ("intr done. state=%d, asr=0x%02x\n", i, asr));
+
+ return(1);
+}
+
+/*
+ * Complete current command using polled I/O. Used when interrupt driven
+ * I/O is not allowed (ie. during boot and shutdown)
+ *
+ * Polled I/O is very processor intensive
+ */
+int
+wd33c93_poll(struct wd33c93_softc *sc, struct wd33c93_acb *acb)
+{
+ u_char asr, csr=0;
+ int i, count;
+ struct scsi_xfer *xs = acb->xs;
+ int s;
+
+ SBIC_WAIT(sc, SBIC_ASR_INT, wd33c93_cmd_wait);
+ for (count = acb->timeout; count;) {
+ GET_SBIC_asr(sc, asr);
+ if (asr & SBIC_ASR_LCI)
+ printf("wd33c93_poll: LCI; asr:%02x csr:%02x\n",
+ asr, csr);
+ if (asr & SBIC_ASR_INT) {
+ GET_SBIC_csr(sc, csr);
+ sc->sc_flags |= SBICF_NODMA;
+ i = wd33c93_nextstate(sc, sc->sc_nexus, csr, asr);
+ WAIT_CIP(sc); /* XXX */
+ } else {
+ DELAY(1000);
+ count--;
+ }
+
+ if ((xs->flags & ITSDONE) != 0) {
+ s = splbio();
+ acb->flags = ACB_FREE;
+ pool_put(&wd33c93_pool, acb);
+ splx(s);
+
+ return (0);
+ }
+
+ if (sc->sc_state == SBIC_IDLE) {
+ SBIC_DEBUG(ACBS, ("[poll: rescheduling] "));
+ wd33c93_sched(sc);
+ }
+ }
+ return (1);
+}
+
+static inline int
+__verify_msg_format(u_char *p, int len)
+{
+ if (len == 1 && IS1BYTEMSG(p[0]))
+ return 1;
+ if (len == 2 && IS2BYTEMSG(p[0]))
+ return 1;
+ if (len >= 3 && ISEXTMSG(p[0]) &&
+ len == p[1] + 2)
+ return 1;
+ return 0;
+}
+
+/*
+ * Handle message_in phase
+ */
+int
+wd33c93_msgin_phase(struct wd33c93_softc *sc, int reselect)
+{
+ int len;
+ u_char asr, csr, *msg;
+
+ GET_SBIC_asr(sc, asr);
+
+ SBIC_DEBUG(MSGS, ("wd33c93msgin asr=%02x\n", asr));
+
+ GET_SBIC_selid (sc, csr);
+ SET_SBIC_selid (sc, csr | SBIC_SID_FROM_SCSI);
+
+ SBIC_TC_PUT(sc, 0);
+
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ msg = sc->sc_imsg;
+ len = 0;
+
+ do {
+ /* Fetch the next byte of the message */
+ RECV_BYTE(sc, *msg++);
+ len++;
+
+ /*
+ * get the command completion interrupt, or we
+ * can't send a new command (LCI)
+ */
+ SBIC_WAIT(sc, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(sc, csr);
+
+ if (__verify_msg_format(sc->sc_imsg, len))
+ break; /* Complete message received */
+
+ /*
+ * Clear ACK, and wait for the interrupt
+ * for the next byte or phase change
+ */
+ SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(sc, SBIC_ASR_INT, 0);
+
+ GET_SBIC_csr(sc, csr);
+ } while (len < SBIC_MAX_MSGLEN);
+
+ if (__verify_msg_format(sc->sc_imsg, len))
+ wd33c93_msgin(sc, sc->sc_imsg, len);
+
+ /*
+ * Clear ACK, and wait for the interrupt
+ * for the phase change
+ */
+ SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(sc, SBIC_ASR_INT, 0);
+
+ /* Should still have one CSR to read */
+ return SBIC_STATE_RUNNING;
+}
+
+
+void wd33c93_msgin(struct wd33c93_softc *sc, u_char *msgaddr, int msglen)
+{
+ struct wd33c93_acb *acb = sc->sc_nexus;
+ struct wd33c93_tinfo *ti = &sc->sc_tinfo[sc->target];
+ struct wd33c93_linfo *li;
+ u_char asr;
+
+ switch (sc->sc_state) {
+ case SBIC_CONNECTED:
+ switch (msgaddr[0]) {
+ case MSG_MESSAGE_REJECT:
+ SBIC_DEBUG(MSGS, ("msgin: MSG_REJECT, "
+ "last msgout=%x\n", sc->sc_msgout));
+ switch (sc->sc_msgout) {
+ case SEND_TAG:
+ printf("%s: tagged queuing rejected: "
+ "target %d\n",
+ sc->sc_dev.dv_xname, sc->target);
+ ti->flags &= ~T_TAG;
+ li = TINFO_LUN(ti, sc->lun);
+ if (acb->tag_type &&
+ li->queued[acb->tag_id] != NULL) {
+ li->queued[acb->tag_id] = NULL;
+ li->used--;
+ }
+ acb->tag_type = acb->tag_id = 0;
+ li->untagged = acb;
+ li->state = L_STATE_BUSY;
+ break;
+
+ case SEND_SDTR:
+ printf("%s: sync transfer rejected: target %d\n",
+ sc->sc_dev.dv_xname, sc->target);
+
+ sc->sc_flags &= ~SBICF_SYNCNEGO;
+ ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE);
+ wd33c93_setsync(sc, ti);
+
+ case SEND_INIT_DET_ERR:
+ goto abort;
+
+ default:
+ SBIC_DEBUG(MSGS, ("Unexpected MSG_REJECT\n"));
+ break;
+ }
+ sc->sc_msgout = 0;
+ break;
+
+ case MSG_HEAD_OF_Q_TAG:
+ case MSG_ORDERED_Q_TAG:
+ case MSG_SIMPLE_Q_TAG:
+ printf("-- Out of phase TAG;"
+ "Nexus=%d:%d Tag=%02x/%02x\n",
+ sc->target, sc->lun, msgaddr[0], msgaddr[1]);
+ break;
+
+ case MSG_DISCONNECT:
+ SBIC_DEBUG(MSGS, ("msgin: DISCONNECT"));
+ /*
+ * Mark the fact that all bytes have moved. The
+ * target may not bother to do a SAVE POINTERS
+ * at this stage. This flag will set the residual
+ * count to zero on MSG COMPLETE.
+ */
+ if (sc->sc_dleft == 0)
+ acb->flags |= ACB_COMPLETE;
+
+ if (acb->xs->flags & SCSI_POLL)
+ /* Don't allow disconnect in immediate mode */
+ goto reject;
+ else { /* Allow disconnect */
+ sc->sc_flags &= ~SBICF_SELECTED;
+ sc->sc_state = SBIC_DISCONNECT;
+ }
+ if ((acb->xs->sc_link->quirks & SDEV_AUTOSAVE) == 0)
+ break;
+ /*FALLTHROUGH*/
+
+ case MSG_SAVEDATAPOINTER:
+ SBIC_DEBUG(MSGS, ("msgin: SAVEDATAPTR"));
+ acb->daddr = sc->sc_daddr;
+ acb->dleft = sc->sc_dleft;
+ break;
+
+ case MSG_RESTOREPOINTERS:
+ SBIC_DEBUG(MSGS, ("msgin: RESTOREPTR"));
+ sc->sc_daddr = acb->daddr;
+ sc->sc_dleft = acb->dleft;
+ break;
+
+ case MSG_CMDCOMPLETE:
+ /*
+ * !! KLUDGE ALERT !! quite a few drives don't seem to
+ * really like the current way of sending the
+ * sync-handshake together with the ident-message, and
+ * they react by sending command-complete and
+ * disconnecting right after returning the valid sync
+ * handshake. So, all I can do is reselect the drive,
+ * and hope it won't disconnect again. I don't think
+ * this is valid behavior, but I can't help fixing a
+ * problem that apparently exists.
+ *
+ * Note: we should not get here on `normal' command
+ * completion, as that condition is handled by the
+ * high-level sel&xfer resume command used to walk
+ * thru status/cc-phase.
+ */
+ SBIC_DEBUG(MSGS, ("msgin: CMD_COMPLETE"));
+ SBIC_DEBUG(SYNC, ("GOT MSG %d! target %d"
+ " acting weird.."
+ " waiting for disconnect...\n",
+ msgaddr[0], sc->target));
+
+ /* Check to see if wd33c93 is handling this */
+ GET_SBIC_asr(sc, asr);
+ if (asr & SBIC_ASR_BSY)
+ break;
+
+ /* XXX: Assume it works and set status to 00 */
+ sc->sc_status = 0;
+ sc->sc_state = SBIC_CMDCOMPLETE;
+ break;
+
+ case MSG_EXTENDED:
+ switch(msgaddr[2]) {
+ case MSG_EXT_SDTR: /* Sync negotiation */
+ SBIC_DEBUG(MSGS, ("msgin: EXT_SDTR; "
+ "period %d, offset %d",
+ msgaddr[3], msgaddr[4]));
+ if (msgaddr[1] != 3)
+ goto reject;
+
+ ti->period =
+ MAX(msgaddr[3], sc->sc_minsyncperiod);
+ ti->offset = MIN(msgaddr[4], sc->sc_maxoffset);
+
+ /*
+ * <SGI, IBM DORS-32160, WA6A> will do nothing
+ * but attempt sync negotiation until it gets
+ * what it wants. To avoid an infinite loop set
+ * off by the identify request, oblige them.
+ */
+ if ((sc->sc_flags&SBICF_SYNCNEGO) == 0 &&
+ msgaddr[3] != 0)
+ ti->flags |= T_WANTSYNC;
+
+ if (!(ti->flags & T_WANTSYNC))
+ ti->period = ti->offset = 0;
+
+ ti->flags &= ~T_NEGOTIATE;
+
+ if (ti->offset == 0)
+ ti->flags &= ~T_SYNCMODE; /* Async */
+ else
+ ti->flags |= T_SYNCMODE; /* Sync */
+
+ /* target initiated negotiation */
+ if ((sc->sc_flags&SBICF_SYNCNEGO) == 0)
+ wd33c93_sched_msgout(sc, SEND_SDTR);
+ sc->sc_flags &= ~SBICF_SYNCNEGO;
+
+ SBIC_DEBUG(SYNC, ("msgin(%d): SDTR(o=%d,p=%d)",
+ sc->target, ti->offset,
+ ti->period));
+ wd33c93_setsync(sc, ti);
+ break;
+
+ case MSG_EXT_WDTR:
+ SBIC_DEBUG(MSGS, ("msgin: EXT_WDTR rejected"));
+ goto reject;
+
+ default:
+ sc_print_addr(acb->xs->sc_link);
+ printf("unrecognized MESSAGE EXTENDED;"
+ " sending REJECT\n");
+ goto reject;
+ }
+ break;
+
+ default:
+ sc_print_addr(acb->xs->sc_link);
+ printf("unrecognized MESSAGE; sending REJECT\n");
+
+ reject:
+ /* We don't support whatever this message is... */
+ wd33c93_sched_msgout(sc, SEND_REJECT);
+ break;
+ }
+ break;
+
+ case SBIC_IDENTIFIED:
+ /*
+ * IDENTIFY message was received and queue tag is expected now
+ */
+ if ((msgaddr[0]!=MSG_SIMPLE_Q_TAG) || (sc->sc_msgify==0)) {
+ printf("%s: TAG reselect without IDENTIFY;"
+ " MSG %x; sending DEVICE RESET\n",
+ sc->sc_dev.dv_xname, msgaddr[0]);
+ goto reset;
+ }
+ SBIC_DEBUG(TAGS, ("TAG %x/%x\n", msgaddr[0], msgaddr[1]));
+ if (sc->sc_nexus)
+ printf("*TAG Recv with active nexus!!\n");
+ wd33c93_reselect(sc, sc->target, sc->lun,
+ msgaddr[0], msgaddr[1]);
+ break;
+
+ case SBIC_RESELECTED:
+ /*
+ * IDENTIFY message with target
+ */
+ if (MSG_ISIDENTIFY(msgaddr[0])) {
+ SBIC_DEBUG(PHASE, ("IFFY[%x] ", msgaddr[0]));
+ sc->sc_msgify = msgaddr[0];
+ } else {
+ printf("%s: reselect without IDENTIFY;"
+ " MSG %x;"
+ " sending DEVICE RESET\n",
+ sc->sc_dev.dv_xname, msgaddr[0]);
+ goto reset;
+ }
+ break;
+
+ default:
+ printf("%s: unexpected MESSAGE IN. State=%d - Sending RESET\n",
+ sc->sc_dev.dv_xname, sc->sc_state);
+ reset:
+ wd33c93_sched_msgout(sc, SEND_DEV_RESET);
+ break;
+ abort:
+ wd33c93_sched_msgout(sc, SEND_ABORT);
+ break;
+ }
+}
+
+void
+wd33c93_sched_msgout(struct wd33c93_softc *sc, u_short msg)
+{
+ u_char asr;
+
+ SBIC_DEBUG(SYNC,("sched_msgout: %04x\n", msg));
+ sc->sc_msgpriq |= msg;
+
+ /* Schedule MSGOUT Phase to send message */
+
+ WAIT_CIP(sc);
+ SET_SBIC_cmd(sc, SBIC_CMD_SET_ATN);
+ WAIT_CIP(sc);
+ GET_SBIC_asr(sc, asr);
+ if (asr & SBIC_ASR_LCI) {
+ printf("MSGOUT Failed!\n");
+ }
+ SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
+ WAIT_CIP(sc);
+}
+
+/*
+ * Send the highest priority, scheduled message
+ */
+void
+wd33c93_msgout(struct wd33c93_softc *sc)
+{
+ struct wd33c93_tinfo *ti;
+ struct wd33c93_acb *acb = sc->sc_nexus;
+
+ if (acb == NULL)
+ panic("MSGOUT with no nexus");
+
+ if (sc->sc_omsglen == 0) {
+ /* Pick up highest priority message */
+ sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
+ sc->sc_msgoutq |= sc->sc_msgout;
+ sc->sc_msgpriq &= ~sc->sc_msgout;
+ sc->sc_omsglen = 1; /* "Default" message len */
+ switch (sc->sc_msgout) {
+ case SEND_SDTR:
+ ti = &sc->sc_tinfo[acb->xs->sc_link->target];
+ sc->sc_omsg[0] = MSG_EXTENDED;
+ sc->sc_omsg[1] = MSG_EXT_SDTR_LEN;
+ sc->sc_omsg[2] = MSG_EXT_SDTR;
+ if (ti->flags & T_WANTSYNC) {
+ sc->sc_omsg[3] = ti->period;
+ sc->sc_omsg[4] = ti->offset;
+ } else {
+ sc->sc_omsg[3] = 0;
+ sc->sc_omsg[4] = 0;
+ }
+ sc->sc_omsglen = 5;
+ if ((sc->sc_flags & SBICF_SYNCNEGO) == 0) {
+ if (ti->flags & T_WANTSYNC)
+ ti->flags |= T_SYNCMODE;
+ else
+ ti->flags &= ~T_SYNCMODE;
+ wd33c93_setsync(sc, ti);
+ }
+ break;
+ case SEND_IDENTIFY:
+ if (sc->sc_state != SBIC_CONNECTED) {
+ printf("%s at line %d: no nexus\n",
+ sc->sc_dev.dv_xname, __LINE__);
+ }
+ sc->sc_omsg[0] =
+ MSG_IDENTIFY(acb->xs->sc_link->lun, 0);
+ break;
+ case SEND_TAG:
+ if (sc->sc_state != SBIC_CONNECTED) {
+ printf("%s at line %d: no nexus\n",
+ sc->sc_dev.dv_xname, __LINE__);
+ }
+ sc->sc_omsg[0] = acb->tag_type;
+ sc->sc_omsg[1] = acb->tag_id;
+ sc->sc_omsglen = 2;
+ break;
+ case SEND_DEV_RESET:
+ sc->sc_omsg[0] = MSG_BUS_DEV_RESET;
+ ti = &sc->sc_tinfo[sc->target];
+ ti->flags &= ~T_SYNCMODE;
+ if ((ti->flags & T_NOSYNC) == 0)
+ /* We can re-start sync negotiation */
+ ti->flags |= T_NEGOTIATE;
+ break;
+ case SEND_PARITY_ERROR:
+ sc->sc_omsg[0] = MSG_PARITY_ERROR;
+ break;
+ case SEND_ABORT:
+ sc->sc_flags |= SBICF_ABORTING;
+ sc->sc_omsg[0] = MSG_ABORT;
+ break;
+ case SEND_INIT_DET_ERR:
+ sc->sc_omsg[0] = MSG_INITIATOR_DET_ERR;
+ break;
+ case SEND_REJECT:
+ sc->sc_omsg[0] = MSG_MESSAGE_REJECT;
+ break;
+ default:
+ /* Wasn't expecting MSGOUT Phase */
+ sc->sc_omsg[0] = MSG_NOOP;
+ break;
+ }
+ }
+
+ wd33c93_xfout(sc, sc->sc_omsglen, sc->sc_omsg);
+}
+
+
+/*
+ * wd33c93_nextstate()
+ * return:
+ * SBIC_STATE_DONE == done
+ * SBIC_STATE_RUNNING == working
+ * SBIC_STATE_DISCONNECT == disconnected
+ * SBIC_STATE_ERROR == error
+ */
+int
+wd33c93_nextstate(struct wd33c93_softc *sc, struct wd33c93_acb *acb, u_char csr, u_char asr)
+{
+ SBIC_DEBUG(PHASE, ("next[a=%02x,c=%02x]: ",asr,csr));
+
+ switch (csr) {
+
+ case SBIC_CSR_XFERRED | CMD_PHASE:
+ case SBIC_CSR_MIS | CMD_PHASE:
+ case SBIC_CSR_MIS_1 | CMD_PHASE:
+ case SBIC_CSR_MIS_2 | CMD_PHASE:
+
+ if (wd33c93_xfout(sc, acb->clen, &acb->cmd))
+ goto abort;
+ break;
+
+ case SBIC_CSR_XFERRED | STATUS_PHASE:
+ case SBIC_CSR_MIS | STATUS_PHASE:
+ case SBIC_CSR_MIS_1 | STATUS_PHASE:
+ case SBIC_CSR_MIS_2 | STATUS_PHASE:
+
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ /*
+ * this should be the normal i/o completion case.
+ * get the status & cmd complete msg then let the
+ * device driver look at what happened.
+ */
+ wd33c93_xferdone(sc);
+
+ wd33c93_dma_stop(sc);
+
+ /* Fixup byte count to be passed to higher layer */
+ acb->dleft = (acb->flags & ACB_COMPLETE) ? 0 :
+ sc->sc_dleft;
+
+ /*
+ * Indicate to the upper layers that the command is done
+ */
+ wd33c93_scsidone(sc, acb, sc->sc_status);
+
+ return SBIC_STATE_DONE;
+
+
+ case SBIC_CSR_XFERRED | DATA_IN_PHASE:
+ case SBIC_CSR_MIS | DATA_IN_PHASE:
+ case SBIC_CSR_MIS_1 | DATA_IN_PHASE:
+ case SBIC_CSR_MIS_2 | DATA_IN_PHASE:
+ case SBIC_CSR_XFERRED | DATA_OUT_PHASE:
+ case SBIC_CSR_MIS | DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_1 | DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_2 | DATA_OUT_PHASE:
+ /*
+ * Verify that we expected to transfer data...
+ */
+ if (acb->dleft <= 0) {
+ printf("next: DATA phase with xfer count == %zd, asr:0x%02x csr:0x%02x\n",
+ acb->dleft, asr, csr);
+ goto abort;
+ }
+
+ /*
+ * Should we transfer using PIO or DMA ?
+ */
+ if (acb->xs->flags & SCSI_POLL ||
+ sc->sc_flags & SBICF_NODMA) {
+ /* Perfrom transfer using PIO */
+ int resid;
+
+ SBIC_DEBUG(DMA, ("PIO xfer: %d(%p:%zx)\n", sc->target,
+ sc->sc_daddr, sc->sc_dleft));
+
+ if (SBIC_PHASE(csr) == DATA_IN_PHASE)
+ /* data in */
+ resid = wd33c93_xfin(sc, sc->sc_dleft,
+ sc->sc_daddr);
+ else /* data out */
+ resid = wd33c93_xfout(sc, sc->sc_dleft,
+ sc->sc_daddr);
+
+ sc->sc_daddr = (char *)sc->sc_daddr +
+ (acb->dleft - resid);
+ sc->sc_dleft = resid;
+ } else {
+ int datain = SBIC_PHASE(csr) == DATA_IN_PHASE;
+
+ /* Perform transfer using DMA */
+ wd33c93_dma_setup(sc, datain);
+
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI |
+ sc->sc_dmamode);
+
+ SBIC_DEBUG(DMA, ("DMA xfer: %d(%p:%zx)\n", sc->target,
+ sc->sc_daddr, sc->sc_dleft));
+
+ /* Setup byte count for transfer */
+ SBIC_TC_PUT(sc, (unsigned)sc->sc_dleft);
+
+ /* Start the transfer */
+ SET_SBIC_cmd(sc, SBIC_CMD_XFER_INFO);
+
+ /* Start the DMA chip going */
+ sc->sc_tcnt = sc->sc_dmago(sc);
+
+ /* Indicate that we're in DMA mode */
+ sc->sc_flags |= SBICF_INDMA;
+ }
+ break;
+
+ case SBIC_CSR_XFERRED | MESG_IN_PHASE:
+ case SBIC_CSR_MIS | MESG_IN_PHASE:
+ case SBIC_CSR_MIS_1 | MESG_IN_PHASE:
+ case SBIC_CSR_MIS_2 | MESG_IN_PHASE:
+
+ wd33c93_dma_stop(sc);
+
+ /* Handle a single message in... */
+ return wd33c93_msgin_phase(sc, 0);
+
+ case SBIC_CSR_MSGIN_W_ACK:
+
+ /*
+ * We should never see this since it's handled in
+ * 'wd33c93_msgin_phase()' but just for the sake of paranoia...
+ */
+ SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
+
+ printf("Acking unknown msgin CSR:%02x",csr);
+ break;
+
+ case SBIC_CSR_XFERRED | MESG_OUT_PHASE:
+ case SBIC_CSR_MIS | MESG_OUT_PHASE:
+ case SBIC_CSR_MIS_1 | MESG_OUT_PHASE:
+ case SBIC_CSR_MIS_2 | MESG_OUT_PHASE:
+
+ /*
+ * Message out phase. ATN signal has been asserted
+ */
+ wd33c93_dma_stop(sc);
+ wd33c93_msgout(sc);
+ return SBIC_STATE_RUNNING;
+
+ case SBIC_CSR_DISC:
+ case SBIC_CSR_DISC_1:
+ SBIC_DEBUG(RSEL, ("wd33c93next target %d disconnected\n",
+ sc->target));
+ wd33c93_dma_stop(sc);
+
+ sc->sc_nexus = NULL;
+ sc->sc_state = SBIC_IDLE;
+ sc->sc_flags = 0;
+
+ ++sc->sc_tinfo[sc->target].dconns;
+ ++sc->sc_disc;
+
+ if (acb->xs->flags & SCSI_POLL || wd33c93_nodisc)
+ return SBIC_STATE_DISCONNECT;
+
+ /* Try to schedule another target */
+ wd33c93_sched(sc);
+
+ return SBIC_STATE_DISCONNECT;
+
+ case SBIC_CSR_RSLT_NI:
+ case SBIC_CSR_RSLT_IFY:
+ {
+ /*
+ * A reselection.
+ * Note that since we don't enable Advanced Features (assuming
+ * the WD chip is at least the 'A' revision), we're only ever
+ * likely to see the 'SBIC_CSR_RSLT_NI' status. But for the
+ * hell of it, we'll handle it anyway, for all the extra code
+ * it needs...
+ */
+ u_char newtarget, newlun;
+
+ if (sc->sc_flags & SBICF_INDMA) {
+ printf("**** RESELECT WHILE DMA ACTIVE!!! ***\n");
+ wd33c93_dma_stop(sc);
+ }
+
+ sc->sc_state = SBIC_RESELECTED;
+ GET_SBIC_rselid(sc, newtarget);
+
+ /* check SBIC_RID_SIV? */
+ newtarget &= SBIC_RID_MASK;
+
+ if (csr == SBIC_CSR_RSLT_IFY) {
+ /* Read Identify msg to avoid lockup */
+ GET_SBIC_data(sc, newlun);
+ WAIT_CIP(sc);
+ newlun &= SBIC_TLUN_MASK;
+ sc->sc_msgify = MSG_IDENTIFY(newlun, 0);
+ } else {
+ /*
+ * Need to read Identify message the hard way, assuming
+ * the target even sends us one...
+ */
+ for (newlun = 255; newlun; --newlun) {
+ GET_SBIC_asr(sc, asr);
+ if (asr & SBIC_ASR_INT)
+ break;
+ DELAY(10);
+ }
+
+ /* If we didn't get an interrupt, somethink's up */
+ if ((asr & SBIC_ASR_INT) == 0) {
+ printf("%s: Reselect without identify? asr %x\n",
+ sc->sc_dev.dv_xname, asr);
+ newlun = 0; /* XXXX */
+ } else {
+ /*
+ * We got an interrupt, verify that it's a
+ * change to message in phase, and if so
+ * read the message.
+ */
+ GET_SBIC_csr(sc,csr);
+
+ if (csr == (SBIC_CSR_MIS | MESG_IN_PHASE) ||
+ csr == (SBIC_CSR_MIS_1 | MESG_IN_PHASE) ||
+ csr == (SBIC_CSR_MIS_2 | MESG_IN_PHASE)) {
+ /*
+ * Yup, gone to message in.
+ * Fetch the target LUN
+ */
+ sc->sc_msgify = 0;
+ wd33c93_msgin_phase(sc, 1);
+ newlun = sc->sc_msgify & SBIC_TLUN_MASK;
+ } else {
+ /*
+ * Whoops! Target didn't go to msg_in
+ * phase!!
+ */
+ printf("RSLT_NI - not MESG_IN_PHASE %x\n", csr);
+ newlun = 0; /* XXXSCW */
+ }
+ }
+ }
+
+ /* Ok, we have the identity of the reselecting target. */
+ SBIC_DEBUG(RSEL, ("wd33c93next: reselect from targ %d lun %d",
+ newtarget, newlun));
+ wd33c93_reselect(sc, newtarget, newlun, 0, 0);
+ sc->sc_disc--;
+
+ if (csr == SBIC_CSR_RSLT_IFY)
+ SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
+ break;
+ }
+
+ default:
+ abort:
+ /* Something unexpected happend -- deal with it. */
+ printf("next: aborting asr 0x%02x csr 0x%02x\n", asr, csr);
+
+#ifdef DDB
+ Debugger();
+#endif
+
+ SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ if (acb->xs)
+ wd33c93_error(sc, acb);
+ wd33c93_abort(sc, acb, "next");
+
+ if (sc->sc_flags & SBICF_INDMA) {
+ wd33c93_dma_stop(sc);
+ wd33c93_scsidone(sc, acb, STATUS_UNKNOWN);
+ }
+ return SBIC_STATE_ERROR;
+ }
+ return SBIC_STATE_RUNNING;
+}
+
+
+void
+wd33c93_reselect(struct wd33c93_softc *sc, int target, int lun, int tag_type, int tag_id)
+{
+
+ struct wd33c93_tinfo *ti;
+ struct wd33c93_linfo *li;
+ struct wd33c93_acb *acb;
+
+ if (sc->sc_nexus) {
+ /*
+ * Whoops! We've been reselected with a
+ * command in progress!
+ * The best we can do is to put the current
+ * command back on the ready list and hope
+ * for the best.
+ */
+ SBIC_DEBUG(RSEL, ("%s: reselect with active command\n",
+ sc->sc_dev.dv_xname));
+ ti = &sc->sc_tinfo[sc->target];
+ li = TINFO_LUN(ti, sc->lun);
+ li->state = L_STATE_IDLE;
+
+ wd33c93_dequeue(sc, sc->sc_nexus);
+ TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain);
+ sc->sc_nexus->flags |= ACB_READY;
+
+ sc->sc_nexus = NULL;
+ }
+
+ /* Setup state for new nexus */
+ acb = NULL;
+ sc->sc_flags = SBICF_SELECTED;
+ sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0;
+
+ ti = &sc->sc_tinfo[target];
+ li = TINFO_LUN(ti, lun);
+
+ if (li != NULL) {
+ if (li->untagged != NULL && li->state)
+ acb = li->untagged;
+ else if (tag_type != MSG_SIMPLE_Q_TAG) {
+ /* Wait for tag to come by during MESG_IN Phase */
+ sc->target = target; /* setup I_T_L nexus */
+ sc->lun = lun;
+ sc->sc_state = SBIC_IDENTIFIED;
+ return;
+ } else if (tag_type)
+ acb = li->queued[tag_id];
+ }
+
+ if (acb == NULL) {
+ printf("%s: reselect from target %d lun %d tag %x:%x "
+ "with no nexus; sending ABORT\n",
+ sc->sc_dev.dv_xname, target, lun, tag_type, tag_id);
+ goto abort;
+ }
+
+ sc->target = target;
+ sc->lun = lun;
+ sc->sc_nexus = acb;
+ sc->sc_state = SBIC_CONNECTED;
+
+ if (!wd33c93_dmaok(sc, acb->xs))
+ sc->sc_flags |= SBICF_NODMA;
+
+ /* Do an implicit RESTORE POINTERS. */
+ sc->sc_daddr = acb->daddr;
+ sc->sc_dleft = acb->dleft;
+
+ /* Set sync modes for new target */
+ wd33c93_setsync(sc, ti);
+
+ if (acb->flags & ACB_RESET)
+ wd33c93_sched_msgout(sc, SEND_DEV_RESET);
+ else if (acb->flags & ACB_ABORT)
+ wd33c93_sched_msgout(sc, SEND_ABORT);
+ return;
+
+abort:
+ wd33c93_sched_msgout(sc, SEND_ABORT);
+ return;
+
+}
+
+void
+wd33c93_timeout(void *arg)
+{
+ struct wd33c93_acb *acb = arg;
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct wd33c93_softc *sc = sc_link->adapter_softc;
+ int s, asr;
+
+ s = splbio();
+
+ GET_SBIC_asr(sc, asr);
+
+ sc_print_addr(sc_link);
+ printf("%s: timed out; asr=0x%02x [acb %p (flags 0x%x, dleft %zx)], "
+ "<state %d, nexus %p, resid %lx, msg(q %x,o %x)>",
+ sc->sc_dev.dv_xname, asr, acb, acb->flags, acb->dleft,
+ sc->sc_state, sc->sc_nexus, (long)sc->sc_dleft,
+ sc->sc_msgpriq, sc->sc_msgout);
+
+ if (asr & SBIC_ASR_INT) {
+ /* We need to service a missed IRQ */
+ wd33c93_intr(sc);
+ } else {
+ (void) wd33c93_abort(sc, sc->sc_nexus, "timeout");
+ }
+ splx(s);
+}
+
+
+void
+wd33c93_watchdog(void *arg)
+{
+ struct wd33c93_softc *sc = arg;
+ struct wd33c93_tinfo *ti;
+ struct wd33c93_linfo *li;
+ int t, s, l;
+ /* scrub LUN's that have not been used in the last 10min. */
+ time_t old = time_second - (10 * 60);
+
+ for (t = 0; t < SBIC_NTARG; t++) {
+ ti = &sc->sc_tinfo[t];
+ for (l = 0; l < SBIC_NLUN; l++) {
+ s = splbio();
+ li = TINFO_LUN(ti, l);
+ if (li && li->last_used < old &&
+ li->untagged == NULL && li->used == 0) {
+ ti->lun[li->lun] = NULL;
+ free(li, M_DEVBUF);
+ }
+ splx(s);
+ }
+ }
+ timeout_add_sec(&sc->sc_watchdog, 60);
+}
+
+
+#ifdef SBICDEBUG
+void
+wd33c93_hexdump(u_char *buf, int len)
+{
+ printf("{%d}:", len);
+ while (len--)
+ printf(" %02x", *buf++);
+ printf("\n");
+}
+
+
+void
+wd33c93_print_csr(u_char csr)
+{
+ switch (SCSI_PHASE(csr)) {
+ case CMD_PHASE:
+ printf("CMD_PHASE\n");
+ break;
+
+ case STATUS_PHASE:
+ printf("STATUS_PHASE\n");
+ break;
+
+ case DATA_IN_PHASE:
+ printf("DATAIN_PHASE\n");
+ break;
+
+ case DATA_OUT_PHASE:
+ printf("DATAOUT_PHASE\n");
+ break;
+
+ case MESG_IN_PHASE:
+ printf("MESG_IN_PHASE\n");
+ break;
+
+ case MESG_OUT_PHASE:
+ printf("MESG_OUT_PHASE\n");
+ break;
+
+ default:
+ switch (csr) {
+ case SBIC_CSR_DISC_1:
+ printf("DISC_1\n");
+ break;
+
+ case SBIC_CSR_RSLT_NI:
+ printf("RESELECT_NO_IFY\n");
+ break;
+
+ case SBIC_CSR_RSLT_IFY:
+ printf("RESELECT_IFY\n");
+ break;
+
+ case SBIC_CSR_SLT:
+ printf("SELECT\n");
+ break;
+
+ case SBIC_CSR_SLT_ATN:
+ printf("SELECT, ATN\n");
+ break;
+
+ case SBIC_CSR_UNK_GROUP:
+ printf("UNK_GROUP\n");
+ break;
+
+ default:
+ printf("UNKNOWN csr=%02x\n", csr);
+ }
+ }
+}
+#endif
diff --git a/sys/dev/ic/wd33c93reg.h b/sys/dev/ic/wd33c93reg.h
new file mode 100644
index 00000000000..e1f16ad11f9
--- /dev/null
+++ b/sys/dev/ic/wd33c93reg.h
@@ -0,0 +1,510 @@
+/* $OpenBSD: wd33c93reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: wd33c93reg.h,v 1.4 2009/02/12 06:24:45 rumble Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsireg.h 7.3 (Berkeley) 2/5/91
+ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsireg.h 7.3 (Berkeley) 2/5/91
+ */
+
+/*
+ * WD33C93 SCSI interface hardware description.
+ *
+ * Using parts of the Mach scsi driver for the 33C93
+ */
+
+#define SBIC_myid 0
+#define SBIC_cdbsize 0
+#define SBIC_control 1
+#define SBIC_timeo 2
+#define SBIC_cdb1 3
+#define SBIC_tsecs 3
+#define SBIC_cdb2 4
+#define SBIC_theads 4
+#define SBIC_cdb3 5
+#define SBIC_tcyl_hi 5
+#define SBIC_cdb4 6
+#define SBIC_tcyl_lo 6
+#define SBIC_cdb5 7
+#define SBIC_addr_hi 7
+#define SBIC_cdb6 8
+#define SBIC_addr_2 8
+#define SBIC_cdb7 9
+#define SBIC_addr_3 9
+#define SBIC_cdb8 10
+#define SBIC_addr_lo 10
+#define SBIC_cdb9 11
+#define SBIC_secno 11
+#define SBIC_cdb10 12
+#define SBIC_headno 12
+#define SBIC_cdb11 13
+#define SBIC_cylno_hi 13
+#define SBIC_cdb12 14
+#define SBIC_cylno_lo 14
+#define SBIC_tlun 15
+#define SBIC_cmd_phase 16
+#define SBIC_syn 17
+#define SBIC_count_hi 18
+#define SBIC_count_med 19
+#define SBIC_count_lo 20
+#define SBIC_selid 21
+#define SBIC_rselid 22
+#define SBIC_csr 23
+#define SBIC_cmd 24
+#define SBIC_data 25
+#define SBIC_queue_tag 26
+#define SBIC_aux_status 27
+
+/* wd33c93_asr is addressed directly */
+
+/*
+ * Register defines
+ */
+
+/*
+ * Auxiliary Status Register
+ */
+
+#define SBIC_ASR_INT 0x80 /* Interrupt pending */
+#define SBIC_ASR_LCI 0x40 /* Last command ignored */
+#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */
+#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */
+#define SBIC_ASR_xxx 0x0c
+#define SBIC_ASR_PE 0x02 /* Parity error (even) */
+#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */
+
+/*
+ * My ID register, and/or CDB Size
+ */
+
+#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 MHz */
+ /* 11 MHz is invalid */
+#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 MHz */
+#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 MHz */
+#define SBIC_ID_RAF 0x20 /* Enable Really Advanced Features */
+#define SBIC_ID_EHP 0x10 /* Enable host parity */
+#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */
+#define SBIC_ID_MASK 0x07
+#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */
+
+/*
+ * Control register
+ */
+
+#define SBIC_CTL_DMA 0x80 /* Single byte dma */
+#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer access (bus master) */
+#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */
+#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */
+#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */
+#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */
+#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/
+#define SBIC_CTL_HA 0x02 /* Halt on ATN */
+#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */
+
+/*
+ * Timeout period register
+ * [val in msecs, input clk in 0.1 MHz]
+ */
+
+#define SBIC_TIMEOUT(val,clk) ((((val) * (clk)) / 800) + 1)
+
+/*
+ * CDBn registers, note that
+ * cdb11 is used for status byte in target mode (send-status-and-cc)
+ * cdb12 sez if linked command complete, and w/flag if so
+ */
+
+/*
+ * Target LUN register
+ * [holds target status when select-and-xfer]
+ */
+
+#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */
+#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */
+#define SBIC_TLUN_xxx 0x38
+#define SBIC_TLUN_MASK 0x07
+
+/*
+ * Command Phase register
+ */
+
+#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */
+#define SBIC_CPH(p) ((p) & SBIC_CPH_MASK)
+
+/*
+ * FIFO register
+ */
+
+#define SBIC_FIFO_93_DEPTH 5
+#define SBIC_FIFO_93AB_DEPTH 12
+
+/*
+ * maximum possible size in TC registers. Since this is 24 bit, it's easy
+ */
+#define SBIC_TC_MAX ((1 << 24) - 1)
+
+/*
+ * Synchronous xfer register
+ *
+ * NB: SBIC_SYN_FSS only valid on WD33C93B with 16-20MHz clock.
+ */
+
+#define SBIC_SYN_OFF_MASK 0x0f
+#define SBIC_SYN_93_MAX_OFFSET (SBIC_FIFO_93_DEPTH - 1) /* 4 is recommended */
+#define SBIC_SYN_93AB_MAX_OFFSET SBIC_FIFO_93AB_DEPTH
+#define SBIC_SYN_PER_MASK 0x70
+#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */
+#define SBIC_SYN_FSS 0x80 /* Enable Fast SCSI Transfers (10MB/s)*/
+
+#define SBIC_SYN(o,p,f) \
+ (((o) & SBIC_SYN_OFF_MASK) | (((p) << 4) & SBIC_SYN_PER_MASK) | \
+ ((f) ? SBIC_SYN_FSS : 0))
+
+/*
+ * Transfer count register
+ * optimal access macros depend on addressing
+ */
+
+/*
+ * Destination ID (selid) register
+ */
+
+#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */
+#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */
+#define SBIC_SID_FROM_SCSI 0x40
+#define SBIC_SID_TO_SCSI 0x00
+#define SBIC_SID_xxx 0x38
+#define SBIC_SID_IDMASK 0x07
+
+/*
+ * Source ID (rselid) register
+ */
+
+#define SBIC_RID_ER 0x80 /* Enable reselection */
+#define SBIC_RID_ES 0x40 /* Enable selection */
+#define SBIC_RID_DSP 0x20 /* Disable select parity */
+#define SBIC_RID_SIV 0x08 /* Source ID valid */
+#define SBIC_RID_MASK 0x07
+
+/*
+ * Status register
+ */
+
+#define SBIC_CSR_CAUSE 0xf0
+#define SBIC_CSR_RESET 0x00 /* chip was reset */
+#define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */
+#define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/
+#define SBIC_CSR_CMD_ERR 0x40 /* end with error */
+#define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */
+
+
+#define SBIC_CSR_QUALIFIER 0x0f
+/* Reset State Interrupts */
+#define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/
+#define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/
+/* Successful Completion Interrupts */
+#define SBIC_CSR_TARGET 0x10 /* reselect complete */
+#define SBIC_CSR_INITIATOR 0x11 /* select complete */
+#define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */
+#define SBIC_CSR_W_ATN 0x14 /* ditto */
+#define SBIC_CSR_XLATED 0x15 /* translate address cmd */
+#define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/
+#define SBIC_CSR_XFERRED 0x18 /* phase in low bits */
+/* Paused or Aborted Interrupts */
+#define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/
+#define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */
+#define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */
+#define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */
+#define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */
+#define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */
+#define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */
+/* Terminated Interrupts */
+#define SBIC_CSR_CMD_INVALID 0x40
+#define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */
+#define SBIC_CSR_SEL_TIMEO 0x42
+#define SBIC_CSR_PE 0x43 /* parity error */
+#define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */
+#define SBIC_CSR_XLATE_TOOBIG 0x45
+#define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */
+#define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */
+#define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */
+/* Service Required Interrupts */
+#define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */
+#define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */
+#define SBIC_CSR_SLT 0x82 /* selected, no ATN */
+#define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */
+#define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */
+#define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */
+#define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */
+#define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */
+
+#define SBIC_PHASE(csr) SCSI_PHASE(csr)
+
+/*
+ * Command register (command codes)
+ */
+
+#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */
+#define SBIC_CMD_MASK 0x7f
+
+ /* Miscellaneous */
+#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */
+#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */
+#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */
+#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */
+#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */
+#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */
+
+ /* Initiator state */
+#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */
+#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */
+#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */
+#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */
+
+ /* Target state */
+#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */
+#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */
+#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */
+#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */
+#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */
+#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */
+#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */
+#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */
+#define SBIC_CMD_SND 0x17 /* ( T ) lev II */
+
+ /* Disconnected state */
+#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */
+#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */
+#define SBIC_CMD_SEL 0x07 /* (D ) lev II */
+#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */
+#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */
+#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */
+#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */
+#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */
+
+
+#define PHASE_MASK 0x07 /* mask for psns/pctl phase */
+#define DATA_OUT_PHASE 0x00
+#define DATA_IN_PHASE 0x01
+#define CMD_PHASE 0x02
+#define STATUS_PHASE 0x03
+#define BUS_FREE_PHASE 0x04
+#define ARB_SEL_PHASE 0x05 /* Fuji chip combines bus arb with sel. */
+#define MESG_OUT_PHASE 0x06
+#define MESG_IN_PHASE 0x07
+
+#define SCSI_PHASE(reg) ((reg) & PHASE_MASK)
+
+#define SCSI_STATUS_MASK 0x3e /* Mask unused bits in status byte */
+
+/* approximate, but we won't do SBT on selects */
+#define wd33c93_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa))
+
+#define PAD(n) char n;
+#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA
+
+/*
+ * WD33C93 has two registers:
+ * ASR - r : Aux Status Register, w : desired register no
+ * DATA - rw: register value
+ *
+ * We access them via separate handles because some people *cough*SGI*cough*
+ * like to keep them apart.
+ */
+
+#define wd33c93_read_reg(sc,regno,val) \
+ do { \
+ bus_space_write_1((sc)->sc_regt,(sc)->sc_asr_regh, 0, (regno)); \
+ (val) = bus_space_read_1((sc)->sc_regt,(sc)->sc_data_regh, 0); \
+ } while (0)
+
+#define wd33c93_write_reg(sc,regno,val) \
+ do { \
+ bus_space_write_1((sc)->sc_regt, (sc)->sc_asr_regh, 0, (regno)); \
+ bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, (val)); \
+ } while (0)
+
+#define SET_SBIC_myid(sc,val) wd33c93_write_reg(sc,SBIC_myid,val)
+#define GET_SBIC_myid(sc,val) wd33c93_read_reg(sc,SBIC_myid,val)
+#define SET_SBIC_cdbsize(sc,val) wd33c93_write_reg(sc,SBIC_cdbsize,val)
+#define GET_SBIC_cdbsize(sc,val) wd33c93_read_reg(sc,SBIC_cdbsize,val)
+#define SET_SBIC_control(sc,val) wd33c93_write_reg(sc,SBIC_control,val)
+#define GET_SBIC_control(sc,val) wd33c93_read_reg(sc,SBIC_control,val)
+#define SET_SBIC_timeo(sc,val) wd33c93_write_reg(sc,SBIC_timeo,val)
+#define GET_SBIC_timeo(sc,val) wd33c93_read_reg(sc,SBIC_timeo,val)
+#define SET_SBIC_cdb1(sc,val) wd33c93_write_reg(sc,SBIC_cdb1,val)
+#define GET_SBIC_cdb1(sc,val) wd33c93_read_reg(sc,SBIC_cdb1,val)
+#define SET_SBIC_cdb2(sc,val) wd33c93_write_reg(sc,SBIC_cdb2,val)
+#define GET_SBIC_cdb2(sc,val) wd33c93_read_reg(sc,SBIC_cdb2,val)
+#define SET_SBIC_cdb3(sc,val) wd33c93_write_reg(sc,SBIC_cdb3,val)
+#define GET_SBIC_cdb3(sc,val) wd33c93_read_reg(sc,SBIC_cdb3,val)
+#define SET_SBIC_cdb4(sc,val) wd33c93_write_reg(sc,SBIC_cdb4,val)
+#define GET_SBIC_cdb4(sc,val) wd33c93_read_reg(sc,SBIC_cdb4,val)
+#define SET_SBIC_cdb5(sc,val) wd33c93_write_reg(sc,SBIC_cdb5,val)
+#define GET_SBIC_cdb5(sc,val) wd33c93_read_reg(sc,SBIC_cdb5,val)
+#define SET_SBIC_cdb6(sc,val) wd33c93_write_reg(sc,SBIC_cdb6,val)
+#define GET_SBIC_cdb6(sc,val) wd33c93_read_reg(sc,SBIC_cdb6,val)
+#define SET_SBIC_cdb7(sc,val) wd33c93_write_reg(sc,SBIC_cdb7,val)
+#define GET_SBIC_cdb7(sc,val) wd33c93_read_reg(sc,SBIC_cdb7,val)
+#define SET_SBIC_cdb8(sc,val) wd33c93_write_reg(sc,SBIC_cdb8,val)
+#define GET_SBIC_cdb8(sc,val) wd33c93_read_reg(sc,SBIC_cdb8,val)
+#define SET_SBIC_cdb9(sc,val) wd33c93_write_reg(sc,SBIC_cdb9,val)
+#define GET_SBIC_cdb9(sc,val) wd33c93_read_reg(sc,SBIC_cdb9,val)
+#define SET_SBIC_cdb10(sc,val) wd33c93_write_reg(sc,SBIC_cdb10,val)
+#define GET_SBIC_cdb10(sc,val) wd33c93_read_reg(sc,SBIC_cdb10,val)
+#define SET_SBIC_cdb11(sc,val) wd33c93_write_reg(sc,SBIC_cdb11,val)
+#define GET_SBIC_cdb11(sc,val) wd33c93_read_reg(sc,SBIC_cdb11,val)
+#define SET_SBIC_cdb12(sc,val) wd33c93_write_reg(sc,SBIC_cdb12,val)
+#define GET_SBIC_cdb12(sc,val) wd33c93_read_reg(sc,SBIC_cdb12,val)
+#define SET_SBIC_tlun(sc,val) wd33c93_write_reg(sc,SBIC_tlun,val)
+#define GET_SBIC_tlun(sc,val) wd33c93_read_reg(sc,SBIC_tlun,val)
+#define SET_SBIC_cmd_phase(sc,val) wd33c93_write_reg(sc,SBIC_cmd_phase,val)
+#define GET_SBIC_cmd_phase(sc,val) wd33c93_read_reg(sc,SBIC_cmd_phase,val)
+#define SET_SBIC_syn(sc,val) wd33c93_write_reg(sc,SBIC_syn,val)
+#define GET_SBIC_syn(sc,val) wd33c93_read_reg(sc,SBIC_syn,val)
+#define SET_SBIC_count_hi(sc,val) wd33c93_write_reg(sc,SBIC_count_hi,val)
+#define GET_SBIC_count_hi(sc,val) wd33c93_read_reg(sc,SBIC_count_hi,val)
+#define SET_SBIC_count_med(sc,val) wd33c93_write_reg(sc,SBIC_count_med,val)
+#define GET_SBIC_count_med(sc,val) wd33c93_read_reg(sc,SBIC_count_med,val)
+#define SET_SBIC_count_lo(sc,val) wd33c93_write_reg(sc,SBIC_count_lo,val)
+#define GET_SBIC_count_lo(sc,val) wd33c93_read_reg(sc,SBIC_count_lo,val)
+#define SET_SBIC_selid(sc,val) wd33c93_write_reg(sc,SBIC_selid,val)
+#define GET_SBIC_selid(sc,val) wd33c93_read_reg(sc,SBIC_selid,val)
+#define SET_SBIC_rselid(sc,val) wd33c93_write_reg(sc,SBIC_rselid,val)
+#define GET_SBIC_rselid(sc,val) wd33c93_read_reg(sc,SBIC_rselid,val)
+#define SET_SBIC_csr(sc,val) wd33c93_write_reg(sc,SBIC_csr,val)
+#define GET_SBIC_csr(sc,val) wd33c93_read_reg(sc,SBIC_csr,val)
+#define SET_SBIC_cmd(sc,val) wd33c93_write_reg(sc,SBIC_cmd,val)
+#define GET_SBIC_cmd(sc,val) wd33c93_read_reg(sc,SBIC_cmd,val)
+#define SET_SBIC_data(sc,val) wd33c93_write_reg(sc,SBIC_data,val)
+#define GET_SBIC_data(sc,val) wd33c93_read_reg(sc,SBIC_data,val)
+#define SET_SBIC_queue_tag(sc,val) wd33c93_write_reg(sc,SBIC_queue_tag,val)
+#define GET_SBIC_queue_tag(sc,val) wd33c93_read_reg(sc,SBIC_queue_tag,val)
+
+#define SBIC_TC_PUT(sc,val) \
+ do { \
+ wd33c93_write_reg(sc,SBIC_count_hi,((val)>>16)); \
+ bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, \
+ (val)>>8); \
+ bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, \
+ (val)); \
+ } while (0)
+
+#define SBIC_TC_GET(sc,val) \
+ do { \
+ wd33c93_read_reg(sc,SBIC_count_hi,(val)); \
+ (val) = ((val)<<8) | bus_space_read_1((sc)->sc_regt, \
+ (sc)->sc_data_regh, 0); \
+ (val) = ((val)<<8) | bus_space_read_1((sc)->sc_regt, \
+ (sc)->sc_data_regh, 0); \
+ } while (0)
+
+#define SBIC_LOAD_COMMAND(sc,cmd,cmdsize) \
+ do { \
+ int n = (cmdsize) - 1; \
+ char *ptr = (char *)(cmd); \
+ wd33c93_write_reg(regs, SBIC_cdb1, *ptr++); \
+ while(n-- > 0) \
+ bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, \
+ 0, *ptr++); /* XXX write_multi */ \
+ } while (0)
+
+#define GET_SBIC_asr(sc,val) \
+ do { \
+ (val) = bus_space_read_1((sc)->sc_regt,(sc)->sc_asr_regh, 0); \
+ } while (0)
+
+
+#define WAIT_CIP(sc) \
+ do { \
+ while (bus_space_read_1((sc)->sc_regt,(sc)->sc_asr_regh, \
+ 0) & SBIC_ASR_CIP) \
+ /*nop*/; \
+ } while (0)
+
+/*
+ * transmit a byte in programmed I/O mode
+ */
+#define SEND_BYTE(sc, ch) \
+ do { \
+ WAIT_CIP(sc); \
+ SET_SBIC_cmd(sc, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(sc, SBIC_ASR_DBR, 0); \
+ SET_SBIC_data(sc, ch); \
+ } while (0)
+
+/*
+ * receive a byte in programmed I/O mode
+ */
+#define RECV_BYTE(sc, ch) \
+ do { \
+ WAIT_CIP(sc); \
+ SET_SBIC_cmd(sc, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(sc, SBIC_ASR_DBR, 0); \
+ GET_SBIC_data(sc, ch); \
+ } while (0)
diff --git a/sys/dev/ic/wd33c93var.h b/sys/dev/ic/wd33c93var.h
new file mode 100644
index 00000000000..45a24bcebc0
--- /dev/null
+++ b/sys/dev/ic/wd33c93var.h
@@ -0,0 +1,262 @@
+/* $OpenBSD: wd33c93var.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: wd33c93var.h,v 1.10 2009/05/12 14:25:18 cegger Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsivar.h 7.1 (Berkeley) 5/8/90
+ */
+
+#define SBIC_NTARG 8
+#define SBIC_NLUN 8
+#define SBIC_NTAGS 256
+
+#define SBIC_MAX_MSGLEN 8
+
+#define SBIC_ABORT_TIMEOUT 2000 /* time to wait for abort */
+#define SBIC_SENSE_TIMEOUT 1000 /* time to wait for sense */
+
+/*
+ * ACB. Holds additional information for each SCSI command Comments: We
+ * need a separate scsi command block because we may need to overwrite it
+ * with a request sense command. Basically, we refrain from fiddling with
+ * the scsi_xfer struct (except do the expected updating of return values).
+ * We'll generally update: xs->{flags,resid,error,sense,status} and
+ * occasionally xs->retries.
+ */
+struct wd33c93_acb {
+ TAILQ_ENTRY(wd33c93_acb) chain;
+ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+ int flags; /* Status */
+#define ACB_FREE 0x00
+#define ACB_ACTIVE 0x01
+#define ACB_READY 0x02 /* ACB is on ready list */
+#define ACB_DONE 0x04
+#define ACB_SENSE 0x08 /* ACB Requesting sense */
+#define ACB_COMPLETE 0x10 /* Disconnected at end of xfer */
+#define ACB_RESET 0x20 /* Require Reset */
+#define ACB_ABORT 0x40 /* Require Abort */
+ int timeout;
+ struct timeout to;
+
+ struct scsi_generic cmd; /* SCSI command block */
+ char *daddr; /* kva for data */
+ int clen;
+ size_t dleft; /* bytes remaining */
+ u_char tag_type; /* TAG Type (0x20-0x22, 0=No Tags) */
+ u_char tag_id; /* TAG id number */
+};
+
+/*
+ * Some info about each (possible) target on the SCSI bus. This should
+ * probably have been a "per target+lunit" structure, but we'll leave it at
+ * this for now. Is there a way to reliably hook it up to sc->fordriver??
+ */
+
+struct wd33c93_linfo {
+ int lun;
+ LIST_ENTRY(wd33c93_linfo) link;
+ time_t last_used;
+ u_char used; /* # slots in use */
+ u_char avail; /* where to start scanning */
+ u_char state;
+#define L_STATE_IDLE 0
+#define L_STATE_BUSY 1
+#define L_STATE_ESTAT 2
+ struct wd33c93_acb *untagged;
+ struct wd33c93_acb *queued[SBIC_NTAGS];
+};
+
+struct wd33c93_tinfo {
+ int cmds; /* # of commands processed */
+ int dconns; /* # of disconnects */
+
+ u_char flags;
+#define T_NEED_RESET 0x01 /* Should send a BUS_DEV_RESET */
+#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */
+#define T_BUSY 0x04 /* Target is busy */
+#define T_SYNCMODE 0x08 /* SYNC mode has been negotiated */
+#define T_NOSYNC 0x10 /* Force ASYNC mode */
+#define T_NODISC 0x20 /* Don't allow disconnect */
+#define T_TAG 0x40 /* Turn on TAG QUEUEs */
+#define T_WANTSYNC 0x80 /* Negotiatious should aim for sync */
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+ struct wd33c93_linfo *lun[SBIC_NLUN]; /* LUN list for this target */
+};
+
+/* Look up a lun in a tinfo */
+#define TINFO_LUN(t, l) ((t)->lun[(l)])
+
+struct wd33c93_softc {
+ struct device sc_dev;
+
+ struct timeout sc_watchdog;
+ struct scsi_link sc_link;
+ void *sc_driver; /* driver specific field */
+
+ int target; /* Currently active target */
+ int lun; /* Currently active LUN */
+
+ /* WD33c93 registers */
+ bus_space_tag_t sc_regt;
+ bus_space_handle_t sc_asr_regh;
+ bus_space_handle_t sc_data_regh;
+
+ /* Data about the current nexus (updated for every cmd switch) */
+ void * sc_daddr; /* Current data pointer */
+ size_t sc_dleft; /* Data left to transfer */
+ ssize_t sc_tcnt; /* number of bytes transfered */
+
+ /* Lists of command blocks */
+ TAILQ_HEAD(acb_list, wd33c93_acb) ready_list;
+
+ struct wd33c93_acb *sc_nexus; /* current command */
+ struct wd33c93_tinfo sc_tinfo[8];
+
+ u_short sc_state;
+ u_short sc_status;
+ int sc_disc; /* current # of active nexus's */
+ int sc_flags;
+
+ /* Message stuff */
+ u_short sc_msgify; /* Last IDENTIFY message */
+ u_short sc_msgout; /* Current message out */
+ u_short sc_msgpriq; /* mesg_out queue (bitmap) */
+ u_short sc_msgoutq; /* mesg_out queue */
+
+ u_char sc_imsg[SBIC_MAX_MSGLEN];
+ u_char sc_omsg[SBIC_MAX_MSGLEN];
+ u_char sc_imsglen;
+ u_char sc_omsglen;
+
+ /* Static hardware attributes supplied by attachment */
+ int sc_id; /* SCSI ID for controller */
+ int sc_clkfreq; /* wd33c93 clk freq * 10 MHz */
+ uint8_t sc_dmamode; /* One of SBIC_CTL_*DMA */
+
+ /* Static hardware attributes derived by wd33c93_attach() */
+ int sc_chip; /* Chip variation */
+ int sc_rev; /* Chip revision */
+ int sc_cfflags; /* Copy of config flags */
+ int sc_maxxfer; /* Maximum transfer size */
+ uint8_t sc_maxoffset; /* Maximum sync offset (bytes) */
+ uint8_t sc_minsyncperiod; /* Minimum supported sync xfer period */
+ uint8_t sc_syncperiods[7]; /* Sync transfer periods (4ns units) */
+ uint8_t sc_fsyncperiods[3]; /* Sync transfer periods for Fast SCSI*/
+
+ int (*sc_dmasetup)(struct wd33c93_softc *, void **, size_t *, int,
+ size_t *);
+ int (*sc_dmago)(struct wd33c93_softc *);
+ void (*sc_dmastop)(struct wd33c93_softc *);
+ void (*sc_reset)(struct wd33c93_softc *);
+};
+
+/* values for sc_flags */
+#define SBICF_SELECTED 0x01 /* bus is in selected state. */
+#define SBICF_NODMA 0x02 /* Polled transfer */
+#define SBICF_INDMA 0x04 /* DMA I/O in progress */
+#define SBICF_SYNCNEGO 0x08 /* Sync negotiation in progress */
+#define SBICF_ABORTING 0x10 /* Aborting */
+
+/* values for sc_state */
+#define SBIC_UNINITIALIZED 0 /* Driver not initialized */
+#define SBIC_IDLE 1 /* waiting for something to do */
+#define SBIC_SELECTING 2 /* SCSI command is arbiting */
+#define SBIC_RESELECTED 3 /* Has been reselected */
+#define SBIC_IDENTIFIED 4 /* Has gotten IFY but not TAG */
+#define SBIC_CONNECTED 5 /* Actively using the SCSI bus */
+#define SBIC_DISCONNECT 6 /* MSG_DISCONNECT received */
+#define SBIC_CMDCOMPLETE 7 /* MSG_CMDCOMPLETE received */
+#define SBIC_ERROR 8 /* Error has occurred */
+#define SBIC_SELTIMEOUT 9 /* Select Timeout */
+#define SBIC_CLEANING 10 /* Scrubbing ACB's */
+#define SBIC_BUSRESET 11 /* SCSI RST has been issued */
+
+/* values for sc_msgout */
+#define SEND_DEV_RESET 0x0001
+#define SEND_PARITY_ERROR 0x0002
+#define SEND_INIT_DET_ERR 0x0004
+#define SEND_REJECT 0x0008
+#define SEND_IDENTIFY 0x0010
+#define SEND_ABORT 0x0020
+#define SEND_WDTR 0x0040
+#define SEND_SDTR 0x0080
+#define SEND_TAG 0x0100
+
+/* WD33c93 chipset revisions - values for sc_rev */
+#define SBIC_CHIP_UNKNOWN 0
+#define SBIC_CHIP_WD33C93 1
+#define SBIC_CHIP_WD33C93A 2
+#define SBIC_CHIP_WD33C93B 3
+
+#define SBIC_CHIP_LIST {"UNKNOWN", "WD33C93", "WD33C93A", "WD33C93B"}
+
+/* macros for sc_cfflags */
+#define CFFLAGS_NODISC(_cf, _t) ((_cf) & (1 << ( 0 + (_t))))
+#define CFFLAGS_NOSYNC(_cf, _t) ((_cf) & (1 << ( 8 + (_t))))
+#define CFFLAGS_NOTAGS(_cf, _t) ((_cf) & (1 << (16 + (_t))))
+
+/*
+ * States returned by our state machine
+ */
+#define SBIC_STATE_ERROR -1
+#define SBIC_STATE_DONE 0
+#define SBIC_STATE_RUNNING 1
+#define SBIC_STATE_DISCONNECT 2
+
+#define DEBUG_ACBS 0x01
+#define DEBUG_INTS 0x02
+#define DEBUG_CMDS 0x04
+#define DEBUG_MISC 0x08
+#define DEBUG_TRAC 0x10
+#define DEBUG_RSEL 0x20
+#define DEBUG_PHASE 0x40
+#define DEBUG_DMA 0x80
+#define DEBUG_CCMDS 0x100
+#define DEBUG_MSGS 0x200
+#define DEBUG_TAGS 0x400
+#define DEBUG_SYNC 0x800
+
+#ifdef SBICDEBUG
+extern int wd33c93_debug_flags;
+#define SBIC_DEBUG(level, str) \
+ do { \
+ if (wd33c93_debug & __CONCAT(DEBUG_,level)) \
+ printf str; \
+ } while (0)
+#else
+#define SBIC_DEBUG(level, str)
+#endif
+
+void wd33c93_scsi_cmd(struct scsi_xfer *);
+void wd33c93_attach(struct wd33c93_softc *, struct scsi_adapter *);
+int wd33c93_intr(void *);
diff --git a/sys/dev/ic/z8530reg.h b/sys/dev/ic/z8530reg.h
index b07c6249914..4bf7ca41a4f 100644
--- a/sys/dev/ic/z8530reg.h
+++ b/sys/dev/ic/z8530reg.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: z8530reg.h,v 1.6 2003/10/21 18:58:50 jmc Exp $ */
-/* $NetBSD: z8530reg.h,v 1.7 1996/10/23 00:32:31 gwr Exp $ */
+/* $OpenBSD: z8530reg.h,v 1.7 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530reg.h,v 1.12 2005/12/11 12:21:29 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -162,6 +162,8 @@
#define ZSWR1_TIE 0x02 /* transmit interrupt enable */
#define ZSWR1_SIE 0x01 /* external/status interrupt enable */
+#define ZSWR1_IMASK 0x1F /* mask of all itr. enable bits. */
+
/* HSIS compat */
#define ZSWR1_REQ_ENABLE (ZSWR1_REQ_WAIT | ZSWR1_REQ_TX)
@@ -184,6 +186,7 @@
#define ZSWR3_HUNT 0x10 /* enter hunt mode */
#define ZSWR3_RXCRC_ENABLE 0x08 /* enable recv crc calculation */
#define ZSWR3_ADDR_SEARCH_MODE 0x04 /* address search mode (SDLC only) */
+#define ZSWR3_SDLC_SHORT_ADDR 0x02 /* short address mode (SDLC only) */
#define ZSWR3_SYNC_LOAD_INH 0x02 /* sync character load inhibit */
#define ZSWR3_RX_ENABLE 0x01 /* receiver enable */