summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 10:44:53 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 10:44:53 +0000
commit49235ceee0c25492d4ca35194d7c72838a9ec284 (patch)
tree14f77677934d4f4cb9baa428691ace792fd0deed
parentc9328c850e70436131e06a34f73c14cc230c18f9 (diff)
mvme68k port by me. some parts by dale rahn.
-rw-r--r--sys/arch/mvme68k/conf/GENERIC108
-rw-r--r--sys/arch/mvme68k/conf/MVME14769
-rw-r--r--sys/arch/mvme68k/conf/MVME162110
-rw-r--r--sys/arch/mvme68k/conf/MVME167109
-rw-r--r--sys/arch/mvme68k/dev/bug.c248
-rw-r--r--sys/arch/mvme68k/dev/bugtty.c496
-rw-r--r--sys/arch/mvme68k/dev/cd2400reg.h151
-rw-r--r--sys/arch/mvme68k/dev/cl.c1665
-rw-r--r--sys/arch/mvme68k/dev/cl.c.dale1666
-rw-r--r--sys/arch/mvme68k/dev/clock.c393
-rw-r--r--sys/arch/mvme68k/dev/dmavar.h47
-rw-r--r--sys/arch/mvme68k/dev/flash.c360
-rw-r--r--sys/arch/mvme68k/dev/flashreg.h63
-rw-r--r--sys/arch/mvme68k/dev/fooip.c123
-rw-r--r--sys/arch/mvme68k/dev/i82586.h286
-rw-r--r--sys/arch/mvme68k/dev/if_ie.c1958
-rw-r--r--sys/arch/mvme68k/dev/if_ie.h191
-rw-r--r--sys/arch/mvme68k/dev/ipic.c195
-rw-r--r--sys/arch/mvme68k/dev/ipicreg.h114
-rw-r--r--sys/arch/mvme68k/dev/lp.c144
-rw-r--r--sys/arch/mvme68k/dev/mc.c217
-rw-r--r--sys/arch/mvme68k/dev/mcreg.h164
-rw-r--r--sys/arch/mvme68k/dev/memc.c131
-rw-r--r--sys/arch/mvme68k/dev/memcreg.h106
-rw-r--r--sys/arch/mvme68k/dev/memdevs.c76
-rw-r--r--sys/arch/mvme68k/dev/nvram.c416
-rw-r--r--sys/arch/mvme68k/dev/nvramreg.h70
-rw-r--r--sys/arch/mvme68k/dev/pcctwo.c180
-rw-r--r--sys/arch/mvme68k/dev/pcctworeg.h150
-rw-r--r--sys/arch/mvme68k/dev/sbic.c2561
-rw-r--r--sys/arch/mvme68k/dev/sbicdma.c278
-rw-r--r--sys/arch/mvme68k/dev/sbicreg.h424
-rw-r--r--sys/arch/mvme68k/dev/sbicvar.h230
-rw-r--r--sys/arch/mvme68k/dev/siop.c1523
-rw-r--r--sys/arch/mvme68k/dev/siop_script.out175
-rw-r--r--sys/arch/mvme68k/dev/siop_script.ss205
-rw-r--r--sys/arch/mvme68k/dev/siopdma.c223
-rw-r--r--sys/arch/mvme68k/dev/siopreg.h336
-rw-r--r--sys/arch/mvme68k/dev/siopvar.h201
-rw-r--r--sys/arch/mvme68k/dev/sram.c231
-rw-r--r--sys/arch/mvme68k/dev/vme.c557
-rw-r--r--sys/arch/mvme68k/dev/vme.h325
-rw-r--r--sys/arch/mvme68k/dev/vmel.c173
-rw-r--r--sys/arch/mvme68k/dev/vmes.c173
-rw-r--r--sys/arch/mvme68k/include/autoconf.h55
-rw-r--r--sys/arch/mvme68k/include/ieeefp.h4
-rw-r--r--sys/arch/mvme68k/include/mioctl.h33
-rw-r--r--sys/arch/mvme68k/include/nvram.h78
-rw-r--r--sys/arch/mvme68k/include/prom.h155
-rw-r--r--sys/arch/mvme68k/stand/bootsd/Makefile43
-rw-r--r--sys/arch/mvme68k/stand/bootsd/README3
-rw-r--r--sys/arch/mvme68k/stand/bootsd/boot.c339
-rw-r--r--sys/arch/mvme68k/stand/bootsd/bugdev.c259
-rw-r--r--sys/arch/mvme68k/stand/bootsd/filesystem.c42
-rw-r--r--sys/arch/mvme68k/stand/bootsd/version.c9
-rw-r--r--sys/arch/mvme68k/stand/bootst/Makefile41
-rw-r--r--sys/arch/mvme68k/stand/bootst/bootst.c346
-rw-r--r--sys/arch/mvme68k/stand/bugcrt/Makefile24
-rw-r--r--sys/arch/mvme68k/stand/bugcrt/Makefile.inc12
-rw-r--r--sys/arch/mvme68k/stand/bugcrt/m68k/Makefile.inc1
-rw-r--r--sys/arch/mvme68k/stand/bugcrt/m68k/bugcrt.c43
-rw-r--r--sys/arch/mvme68k/stand/bugcrt/m88k/Makefile.inc1
-rw-r--r--sys/arch/mvme68k/stand/bugcrt/m88k/bugcrt.c42
-rw-r--r--sys/arch/mvme68k/stand/libbug/Makefile14
-rw-r--r--sys/arch/mvme68k/stand/libbug/Makefile.inc12
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/delay.c15
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/diskrd.c19
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/diskwr.c19
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/getbrdid.c18
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/instat.c17
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/outln.c15
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/outstr.c15
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/return.c14
-rw-r--r--sys/arch/mvme68k/stand/libbug/m68k/rtc_rd.c14
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/delay.c15
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/diskrd.c19
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/diskwr.c19
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/getbrdid.c17
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/instat.c17
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/outch.c15
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/outln.c15
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/outstr.c15
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/prom.h3
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/return.c14
-rw-r--r--sys/arch/mvme68k/stand/libbug/m88k/rtc_rd.c14
-rw-r--r--sys/arch/mvme68k/stand/libbug/ppc/bug.c133
-rw-r--r--sys/arch/mvme68k/stand/libsa/Makefile.inc12
-rw-r--r--sys/arch/mvme68k/stand/libsa/bug.c107
-rw-r--r--sys/arch/mvme68k/stand/libsa/dev_disk.c132
-rw-r--r--sys/arch/mvme68k/stand/libsa/dev_disk.h6
-rw-r--r--sys/arch/mvme68k/stand/libsa/dvma.c68
-rw-r--r--sys/arch/mvme68k/stand/libsa/dvma.h6
-rw-r--r--sys/arch/mvme68k/stand/libsa/exec_sun.c183
-rw-r--r--sys/arch/mvme68k/stand/libsa/netif_sun.c284
-rw-r--r--sys/arch/mvme68k/stand/libsa/promboot.c92
-rw-r--r--sys/arch/mvme68k/stand/libsa/promboot.h5
-rw-r--r--sys/arch/mvme68k/stand/libsa/promcons.c61
-rw-r--r--sys/arch/mvme68k/stand/libsa/promdev.c193
-rw-r--r--sys/arch/mvme68k/stand/libsa/promdev.h4
-rw-r--r--sys/arch/mvme68k/stand/netboot/i82586.h306
-rw-r--r--sys/arch/mvme68k/stand/netboot/if_ie.c495
-rw-r--r--sys/arch/mvme68k/stand/netboot/if_iereg.h163
-rw-r--r--sys/arch/mvme68k/stand/netboot/if_le.c431
-rw-r--r--sys/arch/mvme68k/stand/netboot/if_lereg.h173
-rw-r--r--sys/arch/mvme68k/stand/prtvid/Makefile6
-rw-r--r--sys/arch/mvme68k/stand/prtvid/prtvid.c132
-rw-r--r--sys/arch/mvme68k/stand/sboot/XBUG.S72
-rw-r--r--sys/arch/mvme68k/stand/sboot/XSRT0.S42
-rw-r--r--sys/arch/mvme68k/stand/sboot/if_le.c327
-rw-r--r--sys/arch/mvme68k/stand/sboot/oc_cksum.S187
-rw-r--r--sys/arch/mvme68k/stand/sboot/srec.c155
-rw-r--r--sys/arch/mvme68k/stand/wrtvid/Makefile6
-rw-r--r--sys/arch/mvme68k/stand/wrtvid/Makefile.inc12
-rw-r--r--sys/arch/mvme68k/stand/wrtvid/wrtvid.c145
114 files changed, 23424 insertions, 0 deletions
diff --git a/sys/arch/mvme68k/conf/GENERIC b/sys/arch/mvme68k/conf/GENERIC
new file mode 100644
index 00000000000..a9918483c75
--- /dev/null
+++ b/sys/arch/mvme68k/conf/GENERIC
@@ -0,0 +1,108 @@
+# $NetBSD: AVAGO,v 1.6 1994/10/26 02:32:32 cgd Exp $
+
+machine mvme68k m68k
+
+#options "M68060" # support for 060
+options "M68040" # support for 040
+options FPSP # MC68040 floating point support
+options "M68030" # support for 030
+options FPCOPROC # Support for MC6888[12] (Required)
+
+options MAPPEDCOPY # GOOD? BAD? UGLY? PRETTY?
+
+options MVME147 # (requires M68030)
+options MVME162 # (requires M68040, FPSP)
+options MVME167 # includes 166 (requires M68040, FPSP)
+#options MVME177 # (requires M68060, ...)
+
+maxusers 6
+
+# obsolete timezone spec
+options TIMEZONE=0, DST=0
+
+#options DIAGNOSTIC, DEBUG
+options DDB
+options FFS
+options NFSCLIENT
+options NFSSERVER
+options SYSVSEM,SYSVMSG,SYSVSHM
+options KTRACE
+options COMPAT_43
+options FIFO
+#options MFS
+options DEVPAGER, SWAPPAGER, VNODEPAGER
+#options MSDOSFS
+
+options COMPAT_SUNOS
+
+# Networking options
+options INET
+options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP
+options GATEWAY # IP packet forwarding
+#options ISO # OSI networking
+#options TPIP
+#options EON
+#options COMPAT_09, COMPAT_10
+
+config netbsd swap generic
+
+pseudo-device sl 2
+pseudo-device ppp 2
+pseudo-device loop
+pseudo-device bpfilter
+pseudo-device pty
+
+mainbus0 at root
+
+# MVME147
+pcc0 at mainbus0 addr 0xfffe0000
+clock0 at pcc0 ipl 5
+nvram0 at pcc0 offset 0x0000
+zs0 at pcc0 offset 0x3000 ipl 4
+zs1 at pcc0 offset 0x3800 ipl 4
+le0 at pcc0 offset 0x1800 ipl 1
+sbic0 at pcc0 offset 0x4000 ipl 2
+lp0 at pcc0 ipl 1
+vme0 at pcc0 offset 0x2000
+
+# MVME162
+mc0 at mainbus0 addr 0xfff00000
+clock0 at mc0 ipl 5
+nvram0 at mc0 offset 0xc0000
+zs0 at mc0 offset 0x45000 ipl 4
+zs1 at mc0 offset 0x45801 ipl 4
+ie0 at mc0 offset 0x46000 ipl 1
+siop0 at mc0 offset 0x47000 ipl 2
+memc0 at mc0 offset 0x43000
+memc1 at mc0 offset 0x43100
+ipic0 at mc0 offset 0xbc000
+vme0 at mc0 offset 0x40000
+flash0 at mainbus0 addr 0xffa00000
+sram0 at mainbus0 addr 0xffe00000
+
+fooip* at ipic? manu 0x11 prod 0x22 ipl 1
+
+# MVME166/167/177
+pcctwo0 at mainbus0 addr 0xfff00000
+clock0 at pcctwo0 ipl 5
+nvram0 at pcctwo0 offset 0xc0000
+ie0 at pcctwo0 offset 0x46000 ipl 1
+siop0 at pcctwo0 offset 0x47000 ipl 2
+cl0 at pcctwo0 offset 0x45000 ipl 3
+vme0 at pcctwo0 offset 0x40000
+#lptwo0 at pcctwo0 ipl 1
+memc0 at pcctwo0 offset 0x43000
+memc1 at pcctwo0 offset 0x43100
+sram0 at mainbus0 addr 0xffe00000
+
+bugtty0 at mainbus0
+
+vmes0 at vme0
+vmel0 at vme0
+
+scsibus* at sbic?
+scsibus* at siop?
+
+sd* at scsibus? target ? lun ?
+st* at scsibus? target ? lun ?
+cd* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/conf/MVME147 b/sys/arch/mvme68k/conf/MVME147
new file mode 100644
index 00000000000..1db2af5c30a
--- /dev/null
+++ b/sys/arch/mvme68k/conf/MVME147
@@ -0,0 +1,69 @@
+# $NetBSD: AVAGO,v 1.6 1994/10/26 02:32:32 cgd Exp $
+
+machine mvme68k m68k
+
+options "M68030" # support for 030
+options FPCOPROC # Support for MC6888[12] (Required)
+
+options MAPPEDCOPY # GOOD? BAD? UGLY? PRETTY?
+
+options MVME147 # (requires M68030)
+
+maxusers 6
+
+# obsolete timezone spec
+options TIMEZONE=0, DST=0
+
+#options DIAGNOSTIC, DEBUG
+options DDB
+options FFS
+options NFSCLIENT
+options NFSSERVER
+options SYSVSEM,SYSVMSG,SYSVSHM
+options KTRACE
+options COMPAT_43
+options FIFO
+#options MFS
+options DEVPAGER, SWAPPAGER, VNODEPAGER
+#options MSDOSFS
+
+options COMPAT_SUNOS
+
+# Networking options
+options INET
+options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP
+options GATEWAY # IP packet forwarding
+#options ISO # OSI networking
+#options TPIP
+#options EON
+#options COMPAT_09, COMPAT_10
+
+config netbsd swap generic
+
+#pseudo-device sl
+#pseudo-device ppp 2
+pseudo-device loop
+pseudo-device bpfilter
+pseudo-device pty
+
+mainbus0 at root
+
+# MVME147
+pcc0 at mainbus0 addr 0xfffe0000
+clock0 at pcc0 ipl 5
+nvram0 at pcc0 offset 0x0000
+zs0 at pcc0 offset 0x3000 ipl 4
+zs1 at pcc0 offset 0x3800 ipl 4
+le0 at pcc0 offset 0x1800 ipl 1
+sbic0 at pcc0 offset 0x4000 ipl 2
+lp0 at pcc0 ipl 1
+vme0 at pcc0 offset 0x2000
+
+vmes0 at vme0
+vmel0 at vme0
+
+scsibus* at sbic?
+
+sd* at scsibus? target ? lun ?
+st* at scsibus? target ? lun ?
+cd* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/conf/MVME162 b/sys/arch/mvme68k/conf/MVME162
new file mode 100644
index 00000000000..7f245be0c40
--- /dev/null
+++ b/sys/arch/mvme68k/conf/MVME162
@@ -0,0 +1,110 @@
+# $NetBSD: AVAGO,v 1.6 1994/10/26 02:32:32 cgd Exp $
+
+machine mvme68k m68k
+
+options "M68040" # support for 040
+options FPSP # MC68040 floating point support
+#options "M68030" # support for 030
+options FPCOPROC # Support for MC6888[12] (Required)
+
+options MAPPEDCOPY # GOOD? BAD? UGLY? PRETTY?
+
+#options MVME147 # (requires M68030)
+options MVME162 # (requires M68040)
+#options MVME167 # includes 166 (requires M68040)
+
+maxusers 6
+
+# obsolete timezone spec
+options TIMEZONE=0, DST=0
+
+#options DIAGNOSTIC, DEBUG
+options DDB
+options FFS
+options NFSCLIENT
+options NFSSERVER
+options SYSVSEM,SYSVMSG,SYSVSHM
+options KTRACE
+options COMPAT_43
+options FIFO
+#options MFS
+options DEVPAGER, SWAPPAGER, VNODEPAGER
+#options MSDOSFS
+
+options COMPAT_SUNOS
+
+# Networking options
+options INET
+options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP
+options GATEWAY # IP packet forwarding
+#options ISO # OSI networking
+#options TPIP
+#options EON
+#options COMPAT_09, COMPAT_10
+
+config netbsd swap generic
+
+#pseudo-device sl
+#pseudo-device ppp 2
+pseudo-device loop
+pseudo-device bpfilter
+pseudo-device pty
+
+mainbus0 at root
+
+# MVME147
+#pcc0 at mainbus0 addr 0xfffe0000
+#clock0 at pcc0 ipl 5
+#nvram0 at pcc0 offset 0x0000
+#zs0 at pcc0 offset 0x3000 ipl 4
+#zs1 at pcc0 offset 0x3800 ipl 4
+#le0 at pcc0 offset 0x1800 ipl 1
+#sbic0 at pcc0 offset 0x4000 ipl 2
+##lp0 at pcc0 ipl 1
+#vme0 at pcc0 offset 0x2000
+
+# MVME162
+mc0 at mainbus0 addr 0xfff00000
+clock0 at mc0 ipl 5
+nvram0 at mc0 offset 0xc0000
+zs0 at mc0 offset 0x45000 ipl 4
+zs1 at mc0 offset 0x45801 ipl 4
+ie0 at mc0 offset 0x46000 ipl 1
+siop0 at mc0 offset 0x47000 ipl 2
+memc0 at mc0 offset 0x43000
+memc1 at mc0 offset 0x41000
+ipic0 at mc0 offset 0xbc000
+vme0 at mc0 offset 0x40000
+flash0 at mainbus0 addr 0xffa00000
+sram0 at mainbus0 addr 0xffe00000
+
+fooip* at ipic? manu 0x11 prod 0x22 ipl 1
+
+# MVME166/167/177
+#pcctwo0 at mainbus0 addr 0xfff00000
+#clock0 at pcctwo0 ipl 5
+#nvram0 at pcctwo0 offset 0xc0000
+#ie0 at pcctwo0 offset 0x46000 ipl 1
+#siop0 at pcctwo0 offset 0x47000 ipl 2
+#cl0 at pcctwo0 offset 0x45000 ipl 3
+#vme0 at pcctwo0 offset 0x40000
+#lptwo0 at pcctwo0 ipl 1
+#memc0 at pcctwo0 offset 0x43000
+#memc1 at pcctwo0 offset 0x43100
+#sram0 at mainbus0 addr 0xffe00000
+
+#bugtty0 at mainbus0
+
+vmes0 at vme0
+vmel0 at vme0
+
+#si0 at vmes0 addr 0xff200000 ipl 2 vec 0x40
+#xdc0 at vmel0 addr 0xff00ee80 ipl 2 vec 0x44
+#xd* at xdc? target ?
+
+#scsibus* at sbic?
+scsibus* at siop?
+
+sd* at scsibus? target ? lun ?
+st* at scsibus? target ? lun ?
+cd* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/conf/MVME167 b/sys/arch/mvme68k/conf/MVME167
new file mode 100644
index 00000000000..be091c704d0
--- /dev/null
+++ b/sys/arch/mvme68k/conf/MVME167
@@ -0,0 +1,109 @@
+# $NetBSD: AVAGO,v 1.6 1994/10/26 02:32:32 cgd Exp $
+
+machine mvme68k m68k
+
+options "M68040" # support for 040
+options FPSP # MC68040 floating point support
+#options "M68030" # support for 030
+options FPCOPROC # Support for MC6888[12] (Required)
+
+options MAPPEDCOPY # GOOD? BAD? UGLY? PRETTY?
+
+#options MVME147 # (requires M68030)
+options MVME162 # (requires M68040)
+#options MVME167 # includes 166 (requires M68040)
+
+maxusers 6
+
+# obsolete timezone spec
+options TIMEZONE=0, DST=0
+
+#options DIAGNOSTIC, DEBUG
+options DDB
+options FFS
+options NFSCLIENT
+options NFSSERVER
+options SYSVSEM,SYSVMSG,SYSVSHM
+options KTRACE
+options COMPAT_43
+options FIFO
+#options MFS
+options DEVPAGER, SWAPPAGER, VNODEPAGER
+#options MSDOSFS
+
+options COMPAT_SUNOS
+
+# Networking options
+options INET
+options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP
+options GATEWAY # IP packet forwarding
+#options ISO # OSI networking
+#options TPIP
+#options EON
+#options COMPAT_09, COMPAT_10
+
+config netbsd swap generic
+
+#pseudo-device sl
+#pseudo-device ppp 2
+pseudo-device loop
+pseudo-device bpfilter
+pseudo-device pty
+
+mainbus0 at root
+
+# MVME147
+#pcc0 at mainbus0 addr 0xfffe0000
+#clock0 at pcc0 ipl 5
+#nvram0 at pcc0 offset 0x0000
+#zs0 at pcc0 offset 0x3000 ipl 4
+#zs1 at pcc0 offset 0x3800 ipl 4
+#le0 at pcc0 offset 0x1800 ipl 1
+#sbic0 at pcc0 offset 0x4000 ipl 2
+##lp0 at pcc0 ipl 1
+#vme0 at pcc0 offset 0x2000
+
+# MVME162
+#mc0 at mainbus0 addr 0xfff00000
+#clock0 at mc0 ipl 5
+#nvram0 at mc0 offset 0xc0000
+#zs0 at mc0 offset 0x45000 ipl 4
+#zs1 at mc0 offset 0x45801 ipl 4
+#ie0 at mc0 offset 0x46000 ipl 1
+#siop0 at mc0 offset 0x47000 ipl 2
+#memc0 at mc0 offset 0x43000
+#memc1 at mc0 offset 0x41000
+#ipic0 at mc0 offset 0xbc000
+#vme0 at mc0 offset 0x40000
+#flash0 at mainbus0 addr 0xffa00000
+#sram0 at mainbus0 addr 0xffe00000
+#fooip* at ipic? manu 0x11 prod 0x22 ipl 1
+
+# MVME166/167/177
+pcctwo0 at mainbus0 addr 0xfff00000
+clock0 at pcctwo0 ipl 5
+nvram0 at pcctwo0 offset 0xc0000
+ie0 at pcctwo0 offset 0x46000 ipl 1
+siop0 at pcctwo0 offset 0x47000 ipl 2
+cl0 at pcctwo0 offset 0x45000 ipl 3
+vme0 at pcctwo0 offset 0x40000
+lptwo0 at pcctwo0 ipl 1
+memc0 at pcctwo0 offset 0x43000
+memc1 at pcctwo0 offset 0x43100
+sram0 at mainbus0 addr 0xffe00000
+
+#bugtty0 at mainbus0
+
+vmes0 at vme0
+vmel0 at vme0
+
+#si0 at vmes0 addr 0xff200000 ipl 2 vec 0x40
+#xdc0 at vmel0 addr 0xff00ee80 ipl 2 vec 0x44
+#xd* at xdc? target ?
+
+#scsibus* at sbic?
+scsibus* at siop?
+
+sd* at scsibus? target ? lun ?
+st* at scsibus? target ? lun ?
+cd* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/dev/bug.c b/sys/arch/mvme68k/dev/bug.c
new file mode 100644
index 00000000000..808cf6d4413
--- /dev/null
+++ b/sys/arch/mvme68k/dev/bug.c
@@ -0,0 +1,248 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn.
+ * 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 Dale Rahn.
+ * 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.
+ */
+
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/param.h>
+#include <machine/prom.h>
+
+/* flag to traphandler to signify prom call. presumes splhigh() */
+extern volatile int promcall;
+
+/* tty routines */
+char
+bug_inchr()
+{
+ int s = splhigh();
+ char a;
+
+ promcall = 1;
+ asm volatile ("subql #2,sp");
+ MVMEPROM_CALL(MVMEPROM_INCHR);
+ asm volatile ("nop");
+ asm volatile ("movb sp@+,%0" : "=d" (a));
+ promcall = 0;
+ splx(s);
+ return (a);
+}
+
+/* returns 0 if no characters ready to read */
+int
+bug_instat()
+{
+ int s = splhigh();
+ short ret;
+
+ promcall = 1;
+ MVMEPROM_CALL(MVMEPROM_INSTAT);
+ asm volatile ("nop");
+ asm volatile ("movw ccr,%0" : "=d" (ret));
+ promcall = 0;
+ splx(s);
+ return (!(ret & 0x4));
+}
+
+void
+bug_outchr(a)
+ char a;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movb %0,sp@-" :: "d" (a));
+ MVMEPROM_CALL(MVMEPROM_OUTCHR);
+ asm volatile ("nop");
+ promcall = 0;
+ splx(s);
+}
+
+void
+bug_outstr(pstrb, pstre)
+ char *pstrb;
+ char *pstre;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "d" (pstre));
+ asm volatile ("movl %0,sp@-" :: "d" (pstrb));
+ MVMEPROM_CALL(MVMEPROM_OUTSTR);
+ promcall = 0;
+ splx(s);
+}
+
+void
+bug_outln(pstrb, pstre)
+ char *pstrb;
+ char *pstre;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "d" (pstre));
+ asm volatile ("movl %0,sp@-" :: "d" (pstrb));
+ MVMEPROM_CALL(MVMEPROM_OUTSTRCRLF);
+ promcall = 0;
+ splx(s);
+}
+
+/* BUG - disk routines */
+
+#if 0
+/* returns 0: success, nonzero: error */
+u_int bug_drdcnt = 0;
+int
+bug_diskrd(arg)
+ bug_dskio *arg;
+{
+ int ret;
+
+ promcall = 1;
+ bug_drdcnt++;
+ asm volatile ("movl %0, sp@-" :: "d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKRD);
+ asm volatile ("nop");
+ asm volatile ("movw ccr,%0" : "=d" (ret));
+ promcall = 0;
+ return (!(ret & 0x4));
+}
+/* returns 0: success, nonzero: error */
+u_int bug_dwrcnt = 0;
+int
+bug_diskwr(arg)
+ bug_dskio *arg;
+{
+ int ret;
+
+ promcall = 1;
+ bug_dwrcnt ++;
+ asm volatile ("movl %0, sp@-" :: "d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKWR);
+ asm volatile ("nop");
+ asm volatile ("movw ccr,%0" : "=d" (ret));
+ promcall = 0;
+ return (!(ret & 0x4));
+}
+
+bug_diskcfig()
+{
+}
+
+bug_diskfmt()
+{
+}
+
+bug_diskctrl()
+{
+}
+#endif
+
+/* BUG - timing routine */
+void
+bug_delay(delay_msec)
+ int delay_msec;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "d" (delay_msec));
+ MVMEPROM_CALL(MVMEPROM_DELAY);
+ asm volatile ("nop");
+ promcall = 0;
+ splx(s);
+}
+
+/* BUG - return to bug routine */
+void
+bug_return()
+{
+ promcall = 1;
+ MVMEPROM_CALL(MVMEPROM_EXIT);
+ promcall = 0;
+ /*NOTREACHED*/
+}
+
+/* BUG - query board routines */
+struct bug_brdid *
+bug_brdid()
+{
+ struct bug_brdid *pbrd_id;
+
+ promcall = 1;
+ asm volatile ("clrl sp@-");
+ MVMEPROM_CALL(MVMEPROM_GETBRDID);
+ asm volatile ("movl sp@+,%0" : "=d" (pbrd_id):);
+ promcall = 0;
+ return (pbrd_id);
+}
+
+void
+bug_rtc_rd(ptime)
+ struct bug_time *ptime;
+{
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "a" (ptime));
+ MVMEPROM_CALL(MVMEPROM_RTC_RD);
+ asm volatile ("nop");
+ promcall = 0;
+}
+
+int asm_callbuf[4];
+
+void
+bug_stat()
+{
+ char val[] = "|/-\\";
+ static int cnt = 0;
+
+ bug_outchr('\b');
+ bug_outchr(val[cnt]);
+ cnt = (cnt + 1) % (sizeof(val) -1);
+}
+
+void
+asm_bug_stat()
+{
+ asm volatile ("movl a0,_asm_callbuf+0");
+ asm volatile ("movl a1,_asm_callbuf+4");
+ asm volatile ("movl d0,_asm_callbuf+8");
+ asm volatile ("movl d1,_asm_callbuf+12");
+
+ bug_stat();
+
+ asm volatile ("movl _asm_callbuf+0,a0");
+ asm volatile ("movl _asm_callbuf+4,a1");
+ asm volatile ("movl _asm_callbuf+8,d0");
+ asm volatile ("movl _asm_callbuf+12,d1");
+}
diff --git a/sys/arch/mvme68k/dev/bugtty.c b/sys/arch/mvme68k/dev/bugtty.c
new file mode 100644
index 00000000000..367db8f804b
--- /dev/null
+++ b/sys/arch/mvme68k/dev/bugtty.c
@@ -0,0 +1,496 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn.
+ * 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 Dale Rahn.
+ * 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/ioctl.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
+#include <dev/cons.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/prom.h>
+
+#include "bugtty.h"
+
+int bugttymatch __P((struct device *parent, void *self, void *aux));
+void bugttyattach __P((struct device *parent, struct device *self, void *aux));
+
+struct cfdriver bugttycd = {
+ NULL, "bugtty", bugttymatch, bugttyattach,
+ DV_TTY, sizeof(struct device)
+};
+
+/* prototypes */
+int bugttycnprobe __P((struct consdev *cp));
+int bugttycninit __P((struct consdev *cp));
+int bugttycngetc __P((dev_t dev));
+int bugttycnputc __P((dev_t dev, char c));
+
+int bugttyopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int bugttyclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int bugttyread __P((dev_t dev, struct uio *uio, int flag));
+int bugttywrite __P((dev_t dev, struct uio *uio, int flag));
+int bugttyioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int bugttystop __P((struct tty *tp, int flag));
+
+#define DIALOUT(x) ((x) & 0x80)
+#define SWFLAGS(dev) (bugttyswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0))
+#define BUGTTYUNIT(x) ((x) & 0x7f)
+
+#define BUGBUF 80
+char bugtty_ibuffer[BUGBUF+1];
+volatile char *pinchar = bugtty_ibuffer;
+char bug_obuffer[BUGBUF+1];
+
+struct tty *bugtty_tty[NBUGTTY];
+
+struct tty *
+bugttytty(dev)
+ dev_t dev;
+{
+ int unit;
+
+ unit = BUGTTYUNIT(dev);
+ if (unit >= NBUGTTY)
+ return (NULL);
+ return (bugtty_tty[unit]);
+}
+
+int
+bugttymatch(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ extern int needprom;
+
+ if (needprom == 0)
+ return (0);
+ return (1);
+}
+
+void
+bugttyattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ printf("\n");
+}
+
+void bugttyoutput __P((struct tty *tp));
+
+int bugttydefaultrate = TTYDEF_SPEED;
+int bugttyswflags;
+
+int
+bugttymctl(dev, bits, how)
+ dev_t dev;
+ int bits, how;
+{
+ static int settings = TIOCM_DTR | TIOCM_RTS |
+ TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
+ int s;
+
+ /*printf("mctl: dev %x, bits %x, how %x,",dev, bits, how);*/
+
+ /* settings are currently ignored */
+ s = spltty();
+ switch (how) {
+ case DMSET:
+ break;
+ case DMBIC:
+ break;
+ case DMBIS:
+ break;
+ case DMGET:
+ break;
+ }
+ (void)splx(s);
+
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+
+ /* printf("retbits %x\n", bits); */
+ return (bits);
+}
+
+int
+bugttyopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int s, unit = BUGTTYUNIT(dev);
+ struct tty *tp;
+ extern int needprom;
+
+ if (needprom == 0)
+ return (ENODEV);
+
+ s = spltty();
+ if (bugtty_tty[unit]) {
+ tp = bugtty_tty[unit];
+ } else {
+ tp = bugtty_tty[unit] = ttymalloc();
+ }
+ tp->t_oproc = bugttyoutput;
+ tp->t_param = NULL;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = bugttydefaultrate;
+ }
+ /* bugtty does not have carrier */
+ tp->t_cflag |= CLOCAL;
+ /*
+ * do these all the time
+ */
+ if (bugttyswflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (bugttyswflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (bugttyswflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ bugttyparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+ /*
+ if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
+ (bugttymctl(dev, 0, DMGET) & TIOCM_CD))
+ tp->t_state |= TS_CARR_ON;
+ else
+ tp->t_state &= ~TS_CARR_ON;
+ */
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+/*
+ if (flag & O_NONBLOCK)
+ goto done;
+*/
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+bugttyparam()
+{
+ return (0);
+}
+
+void
+bugttyoutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt ;
+
+ /* only supports one unit */
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+ cnt = min(BUGBUF, cc);
+ cnt = q_to_b(&tp->t_outq, bug_obuffer, cnt);
+ bug_outstr(bug_obuffer, &bug_obuffer[cnt]);
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int
+bugttyclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = BUGTTYUNIT(dev);
+ struct tty *tp = bugtty_tty[unit];
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ ttyclose(tp);
+#if 0
+ bugtty_tty[unit] = NULL;
+#endif
+ return (0);
+}
+
+int
+bugttyread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp;
+
+ if ((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+#if 1
+/* only to be called at splclk() */
+bugtty_chkinput()
+{
+ struct tty *tp;
+
+ tp = bugtty_tty[0]; /* Kinda ugly hack */
+ if (tp == NULL )
+ return;
+
+ if (bug_instat()) {
+ while (bug_instat()) {
+ u_char c = bug_inchr() & 0xff;
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+}
+#endif
+
+int
+bugttywrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+#if 0
+ /* bypass tty output routines. */
+ int i, cnt, s;
+ int oldoff;
+
+ s = spltty();
+ oldoff = uio->uio_offset;
+ do {
+ uiomove(bug_obuffer, BUGBUF, uio);
+ bug_outstr(bug_obuffer, &bug_obuffer[uio->uio_offset - oldoff]);
+ oldoff = uio->uio_offset;
+ } while (uio->uio_resid != 0);
+ splx(s);
+
+ return (0);
+#else
+ struct tty *tp;
+ if((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+#endif
+}
+
+int
+bugttyioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int unit = BUGTTYUNIT(dev);
+ struct tty *tp = bugtty_tty[unit];
+ int error;
+
+ if (!tp)
+ return (ENXIO);
+
+ 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);
+
+ switch (cmd) {
+ case TIOCSBRK:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) bugttymctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) bugttymctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) bugttymctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = bugttymctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = SWFLAGS(dev);
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+
+ bugttyswflags = *(int *)data;
+ bugttyswflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+int
+bugttystop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+/*
+ * bugtty is the last possible choice for a console device.
+ */
+int
+bugttycnprobe(cp)
+ struct consdev *cp;
+{
+ int maj;
+ extern int needprom;
+
+ if (needprom == 0) {
+ cp->cn_pri = CN_DEAD;
+ return (0);
+ }
+
+ switch (cputyp) {
+ case CPU_147:
+ case CPU_162:
+ cp->cn_pri = CN_NORMAL;
+ return (0);
+ default:
+ break;
+ }
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == bugttyopen)
+ break;
+
+ cp->cn_dev = makedev(maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return (1);
+}
+
+int
+bugttycninit(cp)
+ struct consdev *cp;
+{
+}
+
+int
+bugttycngetc(dev)
+ dev_t dev;
+{
+ return (bug_inchr());
+}
+
+int
+bugttycnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ if (c == '\n')
+ bug_outchr('\r');
+ bug_outchr(c);
+}
diff --git a/sys/arch/mvme68k/dev/cd2400reg.h b/sys/arch/mvme68k/dev/cd2400reg.h
new file mode 100644
index 00000000000..d42fe00c7b2
--- /dev/null
+++ b/sys/arch/mvme68k/dev/cd2400reg.h
@@ -0,0 +1,151 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 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.
+ */
+
+/*
+ * Memory map for CL-CD2400 (CD2401)
+ * NOTE: intel addresses are different than motorola addresss
+ * do we want both here (really is based on endian)
+ * or do we want to put these in a carefully packed structure?
+ */
+
+/* these are mot addresses */
+/* global registers */
+#define CD2400_GFRCR 0x81
+#define CD2400_CAR 0xee
+
+/* option registers */
+#define CD2400_CMR 0x1b
+#define CD2400_COR1 0x10
+#define CD2400_COR2 0x17
+#define CD2400_COR3 0x16
+#define CD2400_COR4 0x15
+#define CD2400_COR5 0x14
+#define CD2400_COR6 0x18
+#define CD2400_COR7 0x07
+#define CD2400_SCHR1 0x1f /* async */
+#define CD2400_SCHR2 0x1e /* async */
+#define CD2400_SCHR3 0x1d /* async */
+#define CD2400_SCHR4 0x1c /* async */
+#define CD2400_SCRl 0x23 /* async */
+#define CD2400_SCRh 0x22 /* async */
+#define CD2400_LNXT 0x2e
+#define CD2400_RFAR1 0x1f /* sync */
+#define CD2400_RFAR2 0x1e /* sync */
+#define CD2400_RFAR3 0x1d /* sync */
+#define CD2400_RFAR4 0x1c /* sync */
+
+#define CD2400_CPSR 0xd6
+
+/* bit rate and clock option registers */
+#define CD2400_RBPR 0xcb
+#define CD2400_RCOR 0xc8
+#define CD2400_TBPR 0xc3
+#define CD2400_TCOR 0xc0
+
+/* channel command and status registers */
+#define CD2400_CCR 0x13
+#define CD2400_STCR 0x12 /* sync */
+#define CD2400_CSR 0x1a
+#define CD2400_MSVR_RTS 0xde
+#define CD2400_MSVR_DTR 0xdf
+
+/* interrupt registers */
+#define CD2400_LIVR 0x09
+#define CD2400_IER 0x11
+#define CD2400_LICR 0x26
+#define CD2400_STK 0xe2
+
+/* receive interrupt registers */
+#define CD2400_RPILR 0xe1
+#define CD2400_RIR 0xeD
+#define CD2400_RISR 0x88
+#define CD2400_RISRl 0x89
+#define CD2400_RISRh 0x88
+#define CD2400_RFOC 0x30
+#define CD2400_RDR 0xf8
+#define CD2400_REOIR 0x84
+
+/* transmit interrupt registers */
+#define CD2400_TPILR 0xe0
+#define CD2400_TIR 0xec
+#define CD2400_TISR 0x8a
+#define CD2400_TFTC 0x80
+#define CD2400_TDR 0xf8
+#define CD2400_TEOIR 0x85
+
+/* modem interrrupt registers */
+#define CD2400_MPILR 0xe3
+#define CD2400_MIR 0xef
+#define CD2400_MISR 0x8B
+#define CD2400_MEOIR 0x86
+
+/* dma registers */
+#define CD2400_DMR 0xf6
+#define CD2400_BERCNT 0x8e
+#define CD2400_DMABSTS 0x19
+
+/* dma receive registers - leave these long names, as in manual */
+#define CD2400_ARBADRL 0x42
+#define CD2400_ARBADRU 0x40
+#define CD2400_BRBADRL 0x46
+#define CD2400_BRBADRU 0x44
+#define CD2400_ARBCNT 0x4a
+#define CD2400_BRBCNT 0x48
+#define CD2400_ARBSTS 0x4f
+#define CD2400_BRBSTS 0x4e
+#define CD2400_RCBADRL 0x3e
+#define CD2400_RCBADRU 0x3c
+
+/* dma transmit registers */
+#define CD2400_ATBADRL 0x52
+#define CD2400_ATBADRU 0x50
+#define CD2400_BTBADRL 0x56
+#define CD2400_BTBADRU 0x54
+#define CD2400_ATBCNT 0x5a
+#define CD2400_BTBCNT 0x58
+#define CD2400_ATBSTS 0x5f
+#define CD2400_BTBSTS 0x5e
+#define CD2400_RTBADRL 0x3a
+#define CD2400_RTBADRU 0x38
+
+/* timer registers */
+#define CD2400_TPR 0xda
+#define CD2400_RTPR 0x24 /* async */
+#define CD2400_RTPRl 0x25 /* async */
+#define CD2400_RTPRh 0x24 /* async */
+#define CD2400_GT1 0x2a /* sync */
+#define CD2400_GT1l 0x2b /* sync */
+#define CD2400_GT1h 0x2a /* sync */
+#define CD2400_GT2 0x29 /* sync */
+#define CD2400_TTR 0x29 /* async */
+
+
+#define CD2400_SIZE 0x200
diff --git a/sys/arch/mvme68k/dev/cl.c b/sys/arch/mvme68k/dev/cl.c
new file mode 100644
index 00000000000..38f0469f53c
--- /dev/null
+++ b/sys/arch/mvme68k/dev/cl.c
@@ -0,0 +1,1665 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 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/callout.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+/* #include <sys/queue.h> */
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+#include <mvme68k/dev/cd2400reg.h>
+#include <sys/syslog.h>
+#include "cl.h"
+
+#include "pcctwo.h"
+
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+/* min timeout 0xa, what is a good value */
+#define CL_TIMEOUT 0x10
+#define CL_FIFO_MAX 0x10
+#define CL_FIFO_CNT 0xc
+#define CL_RX_TIMEOUT 0x10
+
+#define CL_DMAMODE 0x1
+#define CL_INTRMODE 0x0
+
+struct cl_cons {
+ u_char *cl_paddr;
+ volatile u_char *cl_vaddr;
+ volatile struct pcctworeg *pcctwoaddr;
+ u_char channel;
+} cl_cons;
+
+struct cl_info {
+ struct tty *tty;
+ u_char cl_swflags;
+ u_char cl_softchar;
+ u_char cl_consio;
+ u_char cl_speed;
+ u_char cl_parstop; /* parity, stop bits. */
+ u_char cl_rxmode;
+ u_char cl_txmode;
+ u_char cl_clen;
+ u_char cl_parity;
+ u_char transmitting;
+ u_long txcnt;
+ u_long rxcnt;
+};
+
+#define CLCD_PORTS_PER_CHIP 4
+struct clsoftc {
+ struct device sc_dev;
+ struct evcnt sc_txintrcnt;
+ struct evcnt sc_rxintrcnt;
+ struct evcnt sc_mxintrcnt;
+ time_t sc_rotime; /* time of last ring overrun */
+ time_t sc_fotime; /* time of last fifo overrun */
+ volatile u_char *vbase;
+ struct cl_info sc_cl[CLCD_PORTS_PER_CHIP];
+ struct intrhand sc_ih_e;
+ struct intrhand sc_ih_m;
+ struct intrhand sc_ih_t;
+ struct intrhand sc_ih_r;
+ struct pcctworeg *sc_pcctwo;
+ int sc_flags;
+};
+
+struct {
+ u_int speed;
+ u_char divisor;
+ u_char clock;
+ u_char rx_timeout;
+} cl_clocks[] = {
+ { 64000, 0x26, 0, 0x01},
+ { 56000, 0x2c, 0, 0x01},
+ { 38400, 0x40, 0, 0x01},
+ { 19200, 0x81, 0, 0x02},
+ { 9600, 0x40, 1, 0x04},
+ { 7200, 0x56, 1, 0x04},
+ { 4800, 0x81, 1, 0x08},
+ { 3600, 0xad, 1, 0x08},
+ { 2400, 0x40, 2, 0x10},
+ { 1200, 0x81, 2, 0x20},
+ { 600, 0x40, 3, 0x40},
+ { 300, 0x81, 3, 0x80},
+ { 150, 0x40, 3, 0x80},
+ { 110, 0x58, 4, 0xff},
+ { 50, 0xC2, 4, 0xff},
+ { 0, 0x00, 0, 0},
+};
+
+/* prototypes */
+int clcnprobe __P((struct consdev *cp));
+int clcninit __P((struct consdev *cp));
+int clcngetc __P((dev_t dev));
+int clcnputc __P((dev_t dev, char c));
+u_char cl_clkdiv __P((int speed));
+u_char cl_clknum __P((int speed));
+u_char cl_clkrxtimeout __P((int speed));
+void clstart __P((struct tty *tp));
+void cl_unblock __P((struct tty *tp));
+int clccparam __P((struct clsoftc *sc, struct termios *par, int channel));
+
+int clparam __P((struct tty *tp, struct termios *t));
+int cl_mintr __P((struct clsoftc *sc));
+int cl_txintr __P((struct clsoftc *sc));
+int cl_rxintr __P((struct clsoftc *sc));
+void cl_overflow __P((struct clsoftc *sc, int channel, long *ptime, char *msg));
+void cl_parity __P((struct clsoftc *sc, int channel));
+void cl_frame __P((struct clsoftc *sc, int channel));
+void cl_break __P(( struct clsoftc *sc, int channel));
+int clmctl __P((dev_t dev, int bits, int how));
+void cl_dumpport __P((int channel));
+
+int clprobe __P((struct device *parent, void *self, void *aux));
+void clattach __P((struct device *parent, struct device *self, void *aux));
+
+int clopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int clclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int clread __P((dev_t dev, struct uio *uio, int flag));
+int clwrite __P((dev_t dev, struct uio *uio, int flag));
+int clioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int clstop __P((struct tty *tp, int flag));
+
+static void cl_initchannel __P((struct clsoftc *sc, int channel));
+static void clputc __P((struct clsoftc *sc, int unit, char c));
+static u_char clgetc __P((struct clsoftc *sc, int *channel));
+static void cloutput __P((struct tty *tp));
+
+struct cfdriver clcd = {
+ NULL, "cl", clprobe, clattach, DV_TTY, sizeof(struct clsoftc), 0
+};
+
+#define CLCDBUF 80
+char cltty_ibuffer[CLCDBUF+1];
+char cl_obuffer[CLCDBUF+1];
+
+int dopoll = 1;
+
+#define CL_UNIT(x) (minor(x) >> 2)
+#define CL_CHANNEL(x) (minor(x) & 3)
+#define CL_TTY(x) (minor(x))
+
+extern int cputyp;
+
+struct tty *
+cltty(dev)
+ dev_t dev;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (NULL);
+ }
+ channel = CL_CHANNEL(dev);
+ return (sc->sc_cl[channel].tty);
+}
+
+/*
+ * probing onboard 166/167/187 CL-cd2400
+ * should be previously configured,
+ * we can check the value before resetting the chip
+ */
+int
+clprobe(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ volatile u_char *cd_base;
+ struct cfdata *cf = self;
+ struct confargs *ca = aux;
+ int ret;
+
+ if (cputyp != CPU_167 && cputyp != CPU_166)
+ return (0);
+
+ cd_base = ca->ca_vaddr;
+#if 0
+ return (!badvaddr(&cd_base[CD2400_GFRCR], 1));
+#endif
+ return (ret);
+}
+
+void
+clattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct clsoftc *sc = (struct clsoftc *)self;
+ struct confargs *ca = aux;
+ int i;
+#if 0
+ int size = (CD2400_SIZE + PGOFSET) & ~PGOFSET;
+#endif
+
+ sc->vbase = ca->ca_vaddr;
+ sc->sc_pcctwo = ca->ca_master;
+
+ if (ca->ca_paddr == cl_cons.cl_paddr) {
+ /* if this device is configured as console,
+ * line cl_cons.channel is the console */
+ sc->sc_cl[cl_cons.channel].cl_consio = 1;
+ printf(" console");
+ } else {
+ /* reset chip only if we are not console device */
+ /* wait for GFRCR */
+ }
+ /* set up global registers */
+ sc->vbase[CD2400_TPR] = CL_TIMEOUT;
+ sc->vbase[CD2400_RPILR] = 0x03;
+ sc->vbase[CD2400_TPILR] = 0x02;
+ sc->vbase[CD2400_MPILR] = 0x01;
+
+ for (i = 0; i < CLCD_PORTS_PER_CHIP; i++) {
+#if 0
+ sc->sc_cl[i].cl_rxmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x01));
+ sc->sc_cl[i].cl_txmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x02));
+ sc->sc_cl[i].cl_softchar =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x04));
+#endif
+ cl_initchannel(sc, i);
+ }
+ /* enable interrupts */
+ sc->sc_ih_e.ih_fn = cl_rxintr;
+ sc->sc_ih_e.ih_arg = sc;
+ sc->sc_ih_e.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_e.ih_wantframe = 0;
+
+ sc->sc_ih_m.ih_fn = cl_mintr;
+ sc->sc_ih_m.ih_arg = sc;
+ sc->sc_ih_m.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_m.ih_wantframe = 0;
+
+ sc->sc_ih_t.ih_fn = cl_txintr;
+ sc->sc_ih_t.ih_arg = sc;
+ sc->sc_ih_t.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_t.ih_wantframe = 0;
+
+ sc->sc_ih_r.ih_fn = cl_rxintr;
+ sc->sc_ih_r.ih_arg = sc;
+ sc->sc_ih_r.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_r.ih_wantframe = 0;
+ switch (ca->ca_bustype) {
+ case BUS_PCCTWO:
+ dopoll = 0;
+ pcctwointr_establish(PCC2V_SCC_RXE, &sc->sc_ih_e);
+ pcctwointr_establish(PCC2V_SCC_M, &sc->sc_ih_m);
+ pcctwointr_establish(PCC2V_SCC_TX, &sc->sc_ih_t);
+ pcctwointr_establish(PCC2V_SCC_RX, &sc->sc_ih_r);
+ sc->sc_pcctwo = (void *)ca->ca_master;
+ sc->sc_pcctwo->pcc2_sccerr = 0x01; /* clear errors */
+
+ /* enable all interrupts at ca_ipl */
+ sc->sc_pcctwo->pcc2_sccirq = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_scctx = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_sccrx = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ break;
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_txintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_rxintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_mxintrcnt);
+ printf("\n");
+}
+
+static void
+cl_initchannel(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ int s;
+ volatile u_char *cd_base = sc->vbase;
+
+ /* set up option registers */
+ sc->sc_cl[channel].tty = NULL;
+ s = splhigh();
+ cd_base[CD2400_CAR] = (char)channel;
+ /* async, do we want to try DMA at some point? */
+ cd_base[CD2400_LIVR] = PCC2_VECBASE + 0xc;/* set vector base at 5C */
+ cd_base[CD2400_IER] = 0x88; /* should change XXX */
+ cd_base[CD2400_LICR] = 0x00; /* will change if DMA support XXX */
+ /* if the port is not the console */
+ if (sc->sc_cl[channel].cl_consio != 1) {
+ cd_base[CD2400_CMR] = 0x02;
+ cd_base[CD2400_COR1] = 0x17;
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02;
+ cd_base[CD2400_COR4] = 0xec;
+ cd_base[CD2400_COR5] = 0xec;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_RBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_RCOR] = 0x01;
+ cd_base[CD2400_TBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_TCOR] = 0x01 << 5;
+ /* console port should be 0x88 already */
+ cd_base[CD2400_MSVR_RTS] = 0x00;
+ cd_base[CD2400_MSVR_DTR] = 0x00;
+ cd_base[CD2400_RTPRl] = CL_RX_TIMEOUT;
+ cd_base[CD2400_RTPRh] = 0x00;
+ }
+ splx(s);
+}
+
+int cldefaultrate = TTYDEF_SPEED;
+
+int clmctl(dev, bits, how)
+ dev_t dev;
+ int bits;
+ int how;
+{
+ struct clsoftc *sc = (struct clsoftc *)clcd.cd_devs[CL_UNIT(dev)];
+ int s;
+
+ /* settings are currently ignored */
+ s = spltty();
+ switch (how) {
+ case DMSET:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ } else {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ } else {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIC:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIS:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ }
+ break;
+
+ case DMGET:
+ bits = 0;
+ {
+ u_char msvr = sc->vbase[CD2400_MSVR_RTS];
+
+ if (msvr & 0x80)
+ bits |= TIOCM_DSR;
+ if (msvr & 0x40)
+ bits |= TIOCM_CD;
+ if (msvr & 0x20)
+ bits |= TIOCM_CTS;
+ if (msvr & 0x10)
+ bits |= TIOCM_DTR;
+ if (msvr & 0x02)
+ bits |= TIOCM_DTR;
+ if (msvr & 0x01)
+ bits |= TIOCM_RTS;
+ }
+ break;
+ }
+ (void)splx(s);
+#if 0
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+#endif
+
+ /*
+ printf("retbits %x\n", bits);
+ */
+ return (bits);
+}
+
+int
+clopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int s, unit, channel;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ struct tty *tp;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ s = spltty();
+ if (cl->tty) {
+ tp = cl->tty;
+ } else {
+ tp = cl->tty = ttymalloc();
+ }
+ tp->t_oproc = clstart;
+ tp->t_param = clparam;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = cldefaultrate;
+ }
+ /*
+ * do these all the time
+ */
+ if (cl->cl_swflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (cl->cl_swflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (cl->cl_swflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ clparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+#ifdef XXX
+ if ((cl->cl_swflags & TIOCFLAG_SOFTCAR) ||
+ (clmctl(dev, 0, DMGET) & TIOCM_CD)) {
+ tp->t_state |= TS_CARR_ON;
+ } else {
+ tp->t_state &= ~TS_CARR_ON;
+ }
+#endif
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+#ifdef XXX
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+ if (flag & O_NONBLOCK)
+ goto done;
+#endif
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+#ifdef DEBUG
+ cl_dumpport(channel);
+#endif
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+clparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+ int s;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+/*
+ t->c_ispeed = tp->t_ispeed;
+ t->c_ospeed = tp->t_ospeed;
+ t->c_cflag = tp->t_cflag;
+*/
+ clccparam(sc, t, channel);
+ s = spltty();
+ cl_unblock(tp);
+ splx(s);
+ return (0);
+}
+
+void
+cloutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt;
+ char *tptr;
+ int channel;
+ struct clsoftc *sc;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+ channel = CL_CHANNEL(dev);
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+/*XXX*/
+ cnt = min(CLCDBUF, cc);
+ cnt = q_to_b(&tp->t_outq, cl_obuffer, cnt);
+ if (cnt == 0) {
+ break;
+ }
+ for (tptr = cl_obuffer; tptr < &cl_obuffer[cnt]; tptr++) {
+ clputc(sc, channel, *tptr);
+ }
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int
+clclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ int s;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ s = spltty();
+ sc->vbase[CD2400_CAR] = channel;
+ if (cl->cl_consio == 0 && (tp->t_cflag & HUPCL) != 0) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+
+ splx(s);
+ ttyclose(tp);
+
+#if 0
+ cl->tty = NULL;
+#endif
+#if 0
+ cl_dumpport(channel);
+#endif
+ return (0);
+}
+
+int
+clread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+clwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+int
+clioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int error;
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+
+ 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);
+
+ switch (cmd) {
+ case TIOCSBRK:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) clmctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) clmctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) clmctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = clmctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = cl->cl_swflags;
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+
+ cl->cl_swflags = *(int *)data;
+ cl->cl_swflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+int
+clstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+int
+clcnprobe(cp)
+ struct consdev *cp;
+{
+ /* always there ? */
+ /* serial major */
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == clopen)
+ break;
+ cp->cn_dev = makedev (maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return (1);
+}
+
+int
+clcninit(cp)
+ struct consdev *cp;
+{
+#ifdef MAP_DOES_WORK
+ int size = (0x1ff + PGOFSET) & ~PGOFSET;
+ int pcc2_size = (0x3C + PGOFSET) & ~PGOFSET;
+#endif
+ volatile u_char *cd_base;
+
+ cl_cons.cl_paddr = (void *)0xfff45000;
+#ifdef MAP_DOES_WORK
+ cl_cons.cl_vaddr = mapiodev(cl_cons.cl_paddr, size);
+ cd_pcc2_base = mapiodev(0xfff42000, pcc2_size);
+#else
+ cl_cons.cl_vaddr = cl_cons.cl_paddr;
+ cl_cons.pcctwoaddr = (void *)0xfff42000;
+#endif
+ cd_base = cl_cons.cl_vaddr;
+ /* reset the chip? */
+#ifdef CLCD_DO_RESET
+#endif
+#ifdef NEW_CLCD_STRUCT
+ /* set up globals */
+ cl->tftc = 0x10;
+ cl->tpr = CL_TIMEOUT; /* is this correct?? */
+ cl->rpilr = 0x03;
+ cl->tpilr = 0x02;
+ cl->mpilr = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cl->car = 0x00;
+ cl->cor1 = 0x17; /* No parity, ignore parity, 8 bit char */
+ cl->cor2 = 0x00;
+ cl->cor3 = 0x02; /* 1 stop bit */
+ cl->cor4 = 0x00;
+ cl->cor5 = 0x00;
+ cl->cor6 = 0x00;
+ cl->cor7 = 0x00;
+ cl->schr1 = 0x00;
+ cl->schr2 = 0x00;
+ cl->schr3 = 0x00;
+ cl->schr4 = 0x00;
+ cl->scrl = 0x00;
+ cl->scrh = 0x00;
+ cl->lnxt = 0x00;
+ cl->cpsr = 0x00;
+#else
+ /* set up globals */
+#ifdef NOT_ALREADY_SETUP
+ cd_base[CD2400_TFTC] = 0x10;
+ cd_base[CD2400_TPR] = CL_TIMEOUT; /* is this correct?? */
+ cd_base[CD2400_RPILR] = 0x03;
+ cd_base[CD2400_TPILR] = 0x02;
+ cd_base[CD2400_MPILR] = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cd_base[CD2400_CAR] = 0x00;
+ cd_base[CD2400_COR1] = 0x17; /* No parity, ignore parity, 8 bit char */
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02; /* 1 stop bit */
+ cd_base[CD2400_COR4] = 0x00;
+ cd_base[CD2400_COR5] = 0x00;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_CPSR] = 0x00;
+#endif
+#endif
+ return (0);
+}
+
+int
+cl_instat(sc)
+ struct clsoftc *sc;
+{
+ volatile u_char *cd_base;
+
+ if ( NULL == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+ return (cd_base[CD2400_RIR] & 0x80);
+}
+
+int
+clcngetc(dev)
+ dev_t dev;
+{
+ u_char val, reoir, licr, isrl, data, status, fifo_cnt;
+ int got_char = 0;
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ volatile struct pcctworeg *pcc2_base = cl_cons.pcctwoaddr;
+
+ while (got_char == 0) {
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ continue;
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ if (((licr >> 2) & 0x3) == 0) {
+ /* is the interrupt for us (port 0) */
+ /* the character is for us. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ data = cd_base[CD2400_RDR];
+ got_char = 1;
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ }
+
+ }
+ return (data);
+}
+
+int
+clcnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ /* is this the correct location for the cr -> cr/lf tranlation? */
+ if (c == '\n')
+ clputc(0, 0, '\r');
+
+ clputc(0, 0, c);
+ return (0);
+}
+
+clcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+ if (1 == on) {
+ /* enable polling */
+ } else {
+ /* disable polling */
+ }
+}
+
+static void
+clputc(sc, unit, c)
+ struct clsoftc *sc;
+ int unit;
+ char c;
+{
+ int s;
+ u_char schar;
+ u_char oldchannel;
+ volatile u_char *cd_base;
+ if (0 == sc) {
+ /* output on console */
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+#ifdef NEW_CLCD_STRUCT
+ /* should we disable, flush and all that goo? */
+ cl->car = unit;
+ schar = cl->schr3;
+ cl->schr3 = c;
+ cl->stcr = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cl->stcr) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ cl->schr3 = schar;
+#else
+if (unit == 0) {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ schar = cd_base[CD2400_SCHR3];
+ cd_base[CD2400_SCHR3] = c;
+ cd_base[CD2400_STCR] = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cd_base[CD2400_STCR]) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ DELAY(5);
+ cd_base[CD2400_SCHR3] = schar;
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+} else {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ if (cd_base[CD2400_TFTC] > 0) {
+ cd_base[CD2400_TDR] = c;
+ }
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+}
+#endif
+}
+
+/*
+#ifdef CLCD_DO_POLLED_INPUT
+*/
+#if 1
+void
+cl_chkinput()
+{
+ struct tty *tp;
+ int unit;
+ struct clsoftc *sc;
+ int channel;
+
+ if (dopoll == 0)
+ return;
+ for (unit = 0; unit < clcd.cd_ndevs; unit++) {
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ continue;
+ }
+ if (cl_instat(sc)) {
+ while (cl_instat(sc)){
+ int ch;
+ u_char c;
+ /*
+ *(pinchar++) = clcngetc();
+ */
+ ch = clgetc(sc, &channel) & 0xff;
+ c = ch;
+
+ tp = sc->sc_cl[channel].tty;
+ if (NULL != tp) {
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+ }
+}
+#endif
+
+static u_char
+clgetc(sc, channel)
+ struct clsoftc *sc;
+ int *channel;
+{
+ volatile u_char *cd_base;
+ volatile struct pcctworeg *pcc2_base;
+ u_char val, reoir, licr, isrl, fifo_cnt, data;
+
+ if (0 == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ pcc2_base = cl_cons.pcctwoaddr;
+ } else {
+ cd_base = sc->vbase;
+ pcc2_base = sc->sc_pcctwo;
+ }
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ return (0);
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ *channel = (licr >> 2) & 0x3;
+ /* is the interrupt for us (port 0) */
+ /* the character is for us yea. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ if (fifo_cnt > 0) {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = 0;
+ cd_base[CD2400_TEOIR] = 0x08;
+ }
+ return (data);
+}
+
+int
+clccparam(sc, par, channel)
+ struct clsoftc *sc;
+ struct termios *par;
+ int channel;
+{
+ u_int divisor, clk, clen;
+ int s, imask, ints;
+
+ s = spltty();
+ sc->vbase[CD2400_CAR] = channel;
+ if (par->c_ospeed == 0) {
+ /* dont kill the console */
+ if (sc->sc_cl[channel].cl_consio == 0) {
+ /* disconnect, drop RTS DTR stop reciever */
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+ splx(s);
+ return (0xff);
+ }
+
+ sc->vbase[CD2400_MSVR_RTS] = 0x03;
+ sc->vbase[CD2400_MSVR_DTR] = 0x03;
+
+ divisor = cl_clkdiv(par->c_ospeed);
+ clk = cl_clknum(par->c_ospeed);
+ sc->vbase[CD2400_TBPR] = divisor;
+ sc->vbase[CD2400_TCOR] = clk << 5;
+ divisor = cl_clkdiv(par->c_ispeed);
+ clk = cl_clknum(par->c_ispeed);
+ sc->vbase[CD2400_RBPR] = divisor;
+ sc->vbase[CD2400_RCOR] = clk;
+ sc->vbase[CD2400_RTPRl] = cl_clkrxtimeout(par->c_ispeed);
+ sc->vbase[CD2400_RTPRh] = 0x00;
+
+ switch (par->c_cflag & CSIZE) {
+ case CS5:
+ clen = 4; /* this is the mask for the chip. */
+ imask = 0x1F;
+ break;
+ case CS6:
+ clen = 5;
+ imask = 0x3F;
+ break;
+ case CS7:
+ clen = 6;
+ imask = 0x7F;
+ break;
+ default:
+ clen = 7;
+ imask = 0xFF;
+ }
+ sc->vbase[CD2400_COR3] = par->c_cflag & PARENB ? 4 : 2;
+
+ if (par->c_cflag & PARENB) {
+ if (par->c_cflag & PARODD) {
+ sc->vbase[CD2400_COR1] = 0xE0 | clen ; /* odd */
+ } else {
+ sc->vbase[CD2400_COR1] = 0x40 | clen ; /* even */
+ }
+ } else {
+ sc->vbase[CD2400_COR1] = 0x10 | clen; /* ignore parity */
+ }
+
+ if (sc->sc_cl[channel].cl_consio == 0 &&
+ (par->c_cflag & CREAD) == 0 ) {
+/*
+ sc->vbase[CD2400_CSR] = 0x08;
+*/
+ sc->vbase[CD2400_CCR] = 0x08;
+ } else {
+ sc->vbase[CD2400_CCR] = 0x0a;
+ }
+ ints = 0;
+#define SCC_DSR 0x80
+#define SCC_DCD 0x40
+#define SCC_CTS 0x20
+ if ((par->c_cflag & CLOCAL) == 0) {
+ ints |= SCC_DCD;
+ }
+ if ((par->c_cflag & CCTS_OFLOW) != 0) {
+ ints |= SCC_CTS;
+ }
+ if ((par->c_cflag & CRTSCTS) != 0) {
+ ints |= SCC_CTS;
+ }
+#ifdef DONT_LET_HARDWARE
+ if ((par->c_cflag & CCTS_IFLOW) != 0) {
+ ints |= SCC_DSR;
+ }
+#endif
+ sc->vbase[CD2400_COR4] = ints | CL_FIFO_CNT;
+ sc->vbase[CD2400_COR5] = ints | CL_FIFO_CNT;
+ return (imask);
+}
+
+static int clknum = 0;
+
+u_char
+cl_clkdiv(speed)
+ int speed;
+{
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].divisor);
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].divisor);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].divisor);
+}
+
+u_char
+cl_clknum(speed)
+ int speed;
+{
+ int found = 0;
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].clock);
+ }
+ for (i = 0; found != 0 && cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[clknum].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].clock);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].clock);
+}
+
+u_char
+cl_clkrxtimeout(speed)
+ int speed;
+{
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].rx_timeout);
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].rx_timeout);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].rx_timeout);
+}
+
+void
+cl_unblock(tp)
+ struct tty *tp;
+{
+ tp->t_state &= ~TS_FLUSH;
+ if (tp->t_outq.c_cc != 0)
+ clstart(tp);
+}
+
+void
+clstart(tp)
+ struct tty *tp;
+{
+ dev_t dev;
+ u_char cbuf;
+ struct clsoftc *sc;
+ int channel, unit, s, cnt;
+
+ dev = tp->t_dev;
+ channel = CL_CHANNEL(dev);
+/* hack to test output on non console only */
+#if 0
+ if (channel == 0) {
+ cloutput(tp);
+ return;
+ }
+#endif
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+#if 0
+ if (sc->sc_cl[channel].transmitting == 1) {
+ /* i'm busy, go away, I will get to it later. */
+ splx(s);
+ return;
+ }
+ cnt = q_to_b(&tp->t_outq, &cbuf, 1);
+ if (cnt != 0) {
+ sc->sc_cl[channel].transmitting = 1;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_TDR] = cbuf;
+ } else {
+ sc->sc_cl[channel].transmitting = 0;
+ }
+#else
+ if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0) {
+ tp->t_state |= TS_BUSY;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_IER] = 0xb;
+ }
+#endif
+ splx(s);
+}
+
+int
+cl_mintr(sc)
+ struct clsoftc *sc;
+{
+ u_char mir, misr, msvr;
+ int channel;
+ struct tty *tp;
+
+ mir = sc->vbase[CD2400_MIR];
+ if ((mir & 0x40) == 0x0) {
+ /* only if intr is not shared? */
+ printf("cl_mintr extra intr\n");
+ return (0);
+ }
+ sc->sc_mxintrcnt.ev_count++;
+
+ channel = mir & 0x03;
+ misr = sc->vbase[CD2400_MISR];
+ msvr = sc->vbase[CD2400_MSVR_RTS];
+ if (misr & 0x01) {
+ /* timers are not currently used?? */
+ printf("cl_mintr: channel %x timer 1 unexpected\n", channel);
+ }
+ if (misr & 0x02) {
+ /* timers are not currently used?? */
+ printf("cl_mintr: channel %x timer 2 unexpected\n", channel);
+ }
+ if (misr & 0x20) {
+ printf("cl_mintr: channel %x cts %x\n", channel,
+ (msvr & 0x20) != 0x0);
+ }
+ if (misr & 0x40) {
+ struct tty *tp = sc->sc_cl[channel].tty;
+
+ printf("cl_mintr: channel %x cd %x\n", channel,
+ (msvr & 0x40) != 0x0);
+ ttymodem(tp, (msvr & 0x40) != 0x0);
+ }
+ if (misr & 0x80) {
+ printf("cl_mintr: channel %x dsr %x\n", channel,
+ (msvr & 0x80) != 0x0);
+ }
+ sc->vbase[CD2400_MEOIR] = 0x00;
+ return (1);
+}
+
+int
+cl_txintr(sc)
+ struct clsoftc *sc;
+{
+ static empty = 0;
+ u_char tir, licr, teoir;
+ u_char max;
+ int channel;
+ struct tty *tp;
+ int cnt;
+ u_char buffer[CL_FIFO_MAX +1];
+ u_char *tptr;
+
+ tir = sc->vbase[CD2400_TIR];
+ if ((tir & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf("cl_txintr extra intr\n");
+ return (0);
+ }
+ sc->sc_txintrcnt.ev_count++;
+
+ channel = tir & 0x03;
+ licr = sc->vbase[CD2400_LICR];
+
+ sc->sc_cl[channel].txcnt ++;
+
+ tp = sc->sc_cl[channel].tty;
+ if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
+ sc->vbase[CD2400_TEOIR] = 0x08;
+ return (1);
+ }
+ switch ((licr >> 4) & 0x3) {
+ case CL_DMAMODE:
+ teoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ max = sc->vbase[CD2400_TFTC];
+ cnt = min((int)max, tp->t_outq.c_cc);
+ if (cnt != 0) {
+ cnt = q_to_b(&tp->t_outq, buffer, cnt);
+ empty = 0;
+ for (tptr = buffer; tptr < &buffer[cnt]; tptr++) {
+ sc->vbase[CD2400_TDR]= *tptr;
+ }
+ teoir = 0x00;
+ } else {
+ if (empty > 5 && (empty % 20000 ) == 0) {
+ printf("cl_txintr: too many empty intr %d chan %d\n",
+ empty, channel);
+ }
+ empty++;
+ teoir = 0x08;
+ if (tp->t_state & TS_BUSY) {
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ sc->vbase[CD2400_IER] = sc->vbase[CD2400_IER] & ~0x3;
+ }
+ break;
+ default:
+ printf("cl_txintr unknown mode %x\n", (licr >> 4) & 0x3);
+ /* we probably will go to hell quickly now */
+ teoir = 0x08;
+ }
+ sc->vbase[CD2400_TEOIR] = teoir;
+ return (1);
+}
+
+int
+cl_rxintr(sc)
+ struct clsoftc *sc;
+{
+ u_char rir, channel, licr, risrl;
+ u_char c;
+ u_char fifocnt;
+ struct tty *tp;
+ int i;
+ u_char reoir;
+
+ rir = sc->vbase[CD2400_RIR];
+ if ((rir & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf("cl_rxintr extra intr\n");
+ return (0);
+ }
+ sc->sc_rxintrcnt.ev_count++;
+ channel = rir & 0x3;
+ licr = sc->vbase[CD2400_LICR];
+ reoir = 0x08;
+
+ sc->sc_cl[channel].rxcnt ++;
+
+ switch (licr & 0x03) {
+ case CL_DMAMODE:
+ reoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ risrl = sc->vbase[CD2400_RISRl];
+ if (risrl & 0x80) {
+ /* timeout, no characters */
+ reoir = 0x08;
+ } else
+ /* We don't need no sinkin special characters */
+ if (risrl & 0x08) {
+ cl_overflow (sc, channel, &sc->sc_fotime, "fifo");
+ reoir = 0x08;
+ } else
+ if (risrl & 0x04) {
+ cl_parity(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x02) {
+ cl_frame(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x01) {
+ cl_break(sc, channel);
+ reoir = 0x08;
+ } else {
+ fifocnt = sc->vbase[CD2400_RFOC];
+ tp = sc->sc_cl[channel].tty;
+ for (i = 0; i < fifocnt; i++) {
+ c = sc->vbase[CD2400_RDR];
+#if USE_BUFFER
+ cl_appendbuf(sc, channel, c);
+#else
+ /* does any restricitions exist on spl
+ * for this call
+ */
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ reoir = 0x00;
+#endif
+ }
+ }
+ break;
+ default:
+ printf("cl_rxintr unknown mode %x\n", licr & 0x03);
+ /* we probably will go to hell quickly now */
+ reoir = 0x08;
+ }
+ sc->vbase[CD2400_REOIR] = reoir;
+ return (1);
+}
+
+void
+cl_overflow(sc, channel, ptime, msg)
+ struct clsoftc *sc;
+ int channel;
+ long *ptime;
+ char *msg;
+{
+/*
+ if (*ptime != time.tv_sec) {
+*/
+ {
+/*
+ *ptime = time.tv_sec);
+*/
+ log(LOG_WARNING, "%s%d[%d]: %s overrun", clcd.cd_name,
+ 0 /* fix */, channel, msg);
+ }
+}
+
+void
+cl_parity(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: parity error", clcd.cd_name, 0, channel);
+}
+
+void
+cl_frame(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: frame error", clcd.cd_name, 0, channel);
+}
+
+void
+cl_break(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: break detected", clcd.cd_name, 0, channel);
+}
+
+void
+cl_dumpport0()
+{
+ cl_dumpport(0);
+}
+
+void
+cl_dumpport1()
+{
+ cl_dumpport(1);
+}
+
+void
+cl_dumpport2()
+{
+ cl_dumpport(2);
+}
+
+void
+cl_dumpport3()
+{
+ cl_dumpport(3);
+}
+
+void
+cl_dumpport(channel)
+ int channel;
+{
+ u_char livr, cmr, cor1, cor2, cor3, cor4, cor5, cor6, cor7;
+ u_char schr1, schr2, schr3, schr4, scrl, scrh, lnxt;
+ u_char rbpr, rcor, tbpr, tcor, rpilr, rir, tpr, ier, ccr;
+ u_char csr, rts, dtr, rtprl, rtprh;
+ struct clsoftc *sc = (struct clsoftc *) clcd.cd_devs[0];
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ int s;
+
+ s = spltty();
+ cd_base[CD2400_CAR] = (char) channel;
+ livr = cd_base[CD2400_LIVR];
+ cmr = cd_base[CD2400_CMR];
+ cor1 = cd_base[CD2400_COR1];
+ cor2 = cd_base[CD2400_COR2];
+ cor3 = cd_base[CD2400_COR3];
+ cor4 = cd_base[CD2400_COR4];
+ cor5 = cd_base[CD2400_COR5];
+ cor6 = cd_base[CD2400_COR6];
+ cor7 = cd_base[CD2400_COR7];
+ schr1 = cd_base[CD2400_SCHR1];
+ schr2 = cd_base[CD2400_SCHR2];
+ schr3 = cd_base[CD2400_SCHR3];
+ schr4 = cd_base[CD2400_SCHR4];
+ scrl = cd_base[CD2400_SCRl];
+ scrh = cd_base[CD2400_SCRh];
+ lnxt = cd_base[CD2400_LNXT];
+ rbpr = cd_base[CD2400_RBPR];
+ rcor = cd_base[CD2400_RCOR];
+ tbpr = cd_base[CD2400_TBPR];
+ rpilr = cd_base[CD2400_RPILR];
+ ier = cd_base[CD2400_IER];
+ ccr = cd_base[CD2400_CCR];
+ tcor = cd_base[CD2400_TCOR];
+ csr = cd_base[CD2400_CSR];
+ tpr = cd_base[CD2400_TPR];
+ rts = cd_base[CD2400_MSVR_RTS];
+ dtr = cd_base[CD2400_MSVR_DTR];
+ rtprl = cd_base[CD2400_RTPRl];
+ rtprh = cd_base[CD2400_RTPRh];
+ splx(s);
+
+ printf("{ port %x livr %x cmr %x\n", channel, livr, cmr);
+ printf("cor1 %x cor2 %x cor3 %x cor4 %x cor5 %x cor6 %x cor7 %x\n",
+ cor1, cor2, cor3, cor4, cor5, cor6, cor7);
+ printf("schr1 %x schr2 %x schr3 %x schr4 %x\n", schr1, schr2, schr3,
+ schr4);
+ printf("scrl %x scrh %x lnxt %x\n", scrl, scrh, lnxt);
+ printf("rbpr %x rcor %x tbpr %x tcor %x\n", rbpr, rcor, tbpr, tcor);
+ printf("rpilr %x rir %x ier %x ccr %x\n", rpilr, rir, ier, ccr);
+ printf("tpr %x csr %x rts %x dtr %x\n", tpr, csr, rts, dtr);
+ printf("rtprl %x rtprh %x\n", rtprl, rtprh);
+ printf("rxcnt %x txcnt %x\n", sc->sc_cl[channel].rxcnt,
+ sc->sc_cl[channel].txcnt);
+ printf("}\n");
+}
diff --git a/sys/arch/mvme68k/dev/cl.c.dale b/sys/arch/mvme68k/dev/cl.c.dale
new file mode 100644
index 00000000000..c59ad812a10
--- /dev/null
+++ b/sys/arch/mvme68k/dev/cl.c.dale
@@ -0,0 +1,1666 @@
+/* $NetBSD$ */
+/*
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 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/callout.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+/* #include <sys/queue.h> */
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+#include <mvme68k/dev/cd2400reg.h>
+#include <sys/syslog.h>
+#include "cl.h"
+
+#include "pcctwo.h"
+
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+#define splcl() spl3()
+
+/* min timeout 0xa, what is a good value */
+#define CL_TIMEOUT 0x10
+#define CL_FIFO_MAX 0x10
+#define CL_FIFO_CNT 0xc
+#define CL_RX_TIMEOUT 0x10
+
+#define CL_DMAMODE 0x1
+#define CL_INTRMODE 0x0
+
+struct cl_cons {
+ u_char *cl_paddr;
+ volatile u_char *cl_vaddr;
+ volatile struct pcctworeg *pcctwoaddr;
+ u_char channel;
+} cl_cons;
+
+struct cl_info {
+ struct tty *tty;
+ u_char cl_swflags;
+ u_char cl_softchar;
+ u_char cl_consio;
+ u_char cl_speed;
+ u_char cl_parstop; /* parity, stop bits. */
+ u_char cl_rxmode;
+ u_char cl_txmode;
+ u_char cl_clen;
+ u_char cl_parity;
+ u_char transmitting;
+ u_long txcnt;
+ u_long rxcnt;
+};
+#define CLCD_PORTS_PER_CHIP 4
+struct clsoftc {
+ struct device sc_dev;
+ struct evcnt sc_txintrcnt;
+ struct evcnt sc_rxintrcnt;
+ struct evcnt sc_mxintrcnt;
+ time_t sc_rotime; /* time of last ring overrun */
+ time_t sc_fotime; /* time of last fifo overrun */
+ u_char *pbase;
+ volatile u_char *vbase;
+ struct cl_info sc_cl[CLCD_PORTS_PER_CHIP];
+ struct intrhand sc_ih_e;
+ struct intrhand sc_ih_m;
+ struct intrhand sc_ih_t;
+ struct intrhand sc_ih_r;
+ struct pcctworeg *sc_pcctwo;
+ int sc_flags;
+};
+struct {
+ u_int speed;
+ u_char divisor;
+ u_char clock;
+ u_char rx_timeout;
+} cl_clocks[] = {
+ { 64000, 0x26, 0, 0x01},
+ { 56000, 0x2c, 0, 0x01},
+ { 38400, 0x40, 0, 0x01},
+ { 19200, 0x81, 0, 0x02},
+ { 9600, 0x40, 1, 0x04},
+ { 7200, 0x56, 1, 0x04},
+ { 4800, 0x81, 1, 0x08},
+ { 3600, 0xad, 1, 0x08},
+ { 2400, 0x40, 2, 0x10},
+ { 1200, 0x81, 2, 0x20},
+ { 600, 0x40, 3, 0x40},
+ { 300, 0x81, 3, 0x80},
+ { 150, 0x40, 3, 0x80},
+ { 110, 0x58, 4, 0xff},
+ { 50, 0xC2, 4, 0xff},
+ { 0, 0x00, 0, 0},
+};
+
+/* prototypes */
+int clcnprobe __P((struct consdev *cp));
+int clcninit __P((struct consdev *cp));
+int clcngetc __P((dev_t dev));
+int clcnputc __P((dev_t dev, char c));
+u_char cl_clkdiv __P((int speed));
+u_char cl_clknum __P((int speed));
+u_char cl_clkrxtimeout __P((int speed));
+void clstart __P((struct tty *tp));
+void cl_unblock __P((struct tty *tp));
+int clccparam __P((struct clsoftc *sc, struct termios *par, int channel));
+
+int clparam __P((struct tty *tp, struct termios *t));
+int cl_mintr __P((struct clsoftc *sc));
+int cl_txintr __P((struct clsoftc *sc));
+int cl_rxintr __P((struct clsoftc *sc));
+void cl_overflow __P((struct clsoftc *sc, int channel, long *ptime, char *msg));
+void cl_parity __P((struct clsoftc *sc, int channel));
+void cl_frame __P((struct clsoftc *sc, int channel));
+void cl_break __P(( struct clsoftc *sc, int channel));
+int clmctl __P((dev_t dev, int bits, int how));
+void cl_dumpport __P((int channel));
+
+int clprobe __P((struct device *parent, void *self, void *aux));
+void clattach __P((struct device *parent, struct device *self, void *aux));
+
+int clopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int clclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int clread __P((dev_t dev, struct uio *uio, int flag));
+int clwrite __P((dev_t dev, struct uio *uio, int flag));
+int clioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int clstop __P((struct tty *tp, int flag));
+
+static void cl_initchannel __P((struct clsoftc *sc, int channel));
+static void clputc __P((struct clsoftc *sc, int unit, char c));
+static u_char clgetc __P((struct clsoftc *sc, int *channel));
+static void cloutput __P( (struct tty *tp));
+
+struct cfdriver clcd = {
+ NULL, "cl", clprobe, clattach, DV_TTY, sizeof(struct clsoftc), 0
+};
+
+#if 0
+struct {
+ u_char *pbase;
+ u_char *vbase;
+ struct cl_info info[CLCD_PORTS_PER_CHIP];
+} cl[NCL];
+#endif
+
+#define CLCDBUF 80
+
+int dopoll = 1;
+
+#define CL_UNIT(x) (minor(x) >> 2)
+#define CL_CHANNEL(x) (minor(x) & 3)
+#define CL_TTY(x) (minor(x))
+
+extern int cputyp;
+
+struct tty * cltty(dev)
+ dev_t dev;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (NULL);
+ }
+ channel = CL_CHANNEL(dev);
+ return sc->sc_cl[channel].tty;
+}
+
+int clprobe(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ /* probing onboard 166/167/187 CL-cd2400
+ * should be previously configured,
+ * we can check the value before resetting the chip
+ */
+ volatile u_char *cd_base;
+ struct confargs *ca = aux;
+ int ret;
+ if (cputyp != CPU_167 && cputyp != CPU_166
+#ifdef CPU_187
+ && cputyp != CPU_187
+#endif
+ )
+ {
+ return 0;
+ }
+ cd_base = ca->ca_vaddr;
+
+#if 0
+ ret = !badvaddr(&cd_base[CD2400_GFRCR],1);
+#else
+ ret = 1;
+#endif
+ return ret;
+}
+
+void
+clattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct clsoftc *sc = (struct clsoftc *)self;
+ struct confargs *ca = aux;
+ int i;
+
+ sc->vbase = ca->ca_vaddr;
+ sc->sc_pcctwo = ca->ca_master;
+
+ if (ca->ca_paddr == cl_cons.cl_paddr) {
+ /* if this device is configured as console,
+ * line cl_cons.channel is the console */
+ sc->sc_cl[cl_cons.channel].cl_consio = 1;
+ printf(" console");
+ } else {
+ /* reset chip only if we are not console device */
+ /* wait for GFRCR */
+ }
+ /* set up global registers */
+ sc->vbase[CD2400_TPR] = CL_TIMEOUT;
+ sc->vbase[CD2400_RPILR] = 0x03;
+ sc->vbase[CD2400_TPILR] = 0x02;
+ sc->vbase[CD2400_MPILR] = 0x01;
+
+ for (i = 0; i < CLCD_PORTS_PER_CHIP; i++) {
+#if 0
+ sc->sc_cl[i].cl_rxmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x01));
+ sc->sc_cl[i].cl_txmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x02));
+ sc->sc_cl[i].cl_softchar =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x04));
+#endif
+ cl_initchannel(sc, i);
+ }
+ /* enable interrupts */
+ sc->sc_ih_e.ih_fn = cl_rxintr;
+ sc->sc_ih_e.ih_arg = sc;
+ sc->sc_ih_e.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_e.ih_wantframe = 0;
+
+ sc->sc_ih_m.ih_fn = cl_mintr;
+ sc->sc_ih_m.ih_arg = sc;
+ sc->sc_ih_m.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_m.ih_wantframe = 0;
+
+ sc->sc_ih_t.ih_fn = cl_txintr;
+ sc->sc_ih_t.ih_arg = sc;
+ sc->sc_ih_t.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_t.ih_wantframe = 0;
+
+ sc->sc_ih_r.ih_fn = cl_rxintr;
+ sc->sc_ih_r.ih_arg = sc;
+ sc->sc_ih_r.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_r.ih_wantframe = 0;
+ switch (ca->ca_bustype) {
+ case BUS_PCCTWO:
+ dopoll = 0;
+ pcctwointr_establish(PCC2V_SCC_RXE,&sc->sc_ih_e);
+ pcctwointr_establish(PCC2V_SCC_M,&sc->sc_ih_m);
+ pcctwointr_establish(PCC2V_SCC_TX,&sc->sc_ih_t);
+ pcctwointr_establish(PCC2V_SCC_RX,&sc->sc_ih_r);
+ sc->sc_pcctwo = (void *)ca->ca_master;
+ sc->sc_pcctwo->pcc2_sccerr = 0x01; /* clear errors */
+
+ /* enable all interrupts at ca_ipl */
+ sc->sc_pcctwo->pcc2_sccirq = 0x10 | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_scctx = 0x10 | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_sccrx = 0x10 | (ca->ca_ipl & 0x7);
+ break;
+ default:
+ /* oops */
+ panic ("cl driver on unknown bus\n");
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_txintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_rxintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_mxintrcnt);
+ printf("\n");
+}
+static void
+cl_initchannel(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ int s;
+ volatile u_char *cd_base = sc->vbase;
+ /* set up option registers */
+ sc->sc_cl[channel].tty = NULL;
+ s = splhigh();
+ cd_base[CD2400_CAR] = (char) channel;
+ /* async, do we want to try DMA at some point? */
+ cd_base[CD2400_LIVR] = PCC2_VECBASE + 0xc;/* set vector base at 5C */
+ cd_base[CD2400_IER] = 0x88; /* should change XXX */
+ cd_base[CD2400_LICR] = 0x00; /* will change if DMA support XXX */
+ /* if the port is not the console */
+ if (sc->sc_cl[channel].cl_consio != 1) {
+ cd_base[CD2400_CMR] = 0x02;
+ cd_base[CD2400_COR1] = 0x17;
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02;
+ cd_base[CD2400_COR4] = 0xec;
+ cd_base[CD2400_COR5] = 0xec;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_RBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_RCOR] = 0x01;
+ cd_base[CD2400_TBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_TCOR] = 0x01 << 5;
+ /* console port should be 0x88 already */
+ cd_base[CD2400_MSVR_RTS] = 0x00;
+ cd_base[CD2400_MSVR_DTR] = 0x00;
+ cd_base[CD2400_RTPRl] = CL_RX_TIMEOUT;
+ cd_base[CD2400_RTPRh] = 0x00;
+ }
+
+ splx(s);
+}
+
+
+int cldefaultrate = TTYDEF_SPEED;
+
+int clmctl (dev, bits, how)
+ dev_t dev;
+ int bits;
+ int how;
+{
+ int s;
+ struct clsoftc *sc;
+ /* should only be called with valid device */
+ sc = (struct clsoftc *) clcd.cd_devs[CL_UNIT(dev)];
+ /*
+ printf("mctl: dev %x, bits %x, how %x,\n",dev, bits, how);
+ */
+ /* settings are currently ignored */
+ s = splcl();
+ switch (how) {
+ case DMSET:
+ if( bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ } else {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if( bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ } else {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIC:
+ if( bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if( bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIS:
+ if( bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ }
+ if( bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ }
+ break;
+
+ case DMGET:
+ bits = 0;
+
+ {
+ u_char msvr;
+ msvr = sc->vbase[CD2400_MSVR_RTS];
+ if( msvr & 0x80) {
+ bits |= TIOCM_DSR;
+ }
+ if( msvr & 0x40) {
+ bits |= TIOCM_CD;
+ }
+ if( msvr & 0x20) {
+ bits |= TIOCM_CTS;
+ }
+ if( msvr & 0x10) {
+ bits |= TIOCM_DTR;
+ }
+ if( msvr & 0x02) {
+ bits |= TIOCM_DTR;
+ }
+ if( msvr & 0x01) {
+ bits |= TIOCM_RTS;
+ }
+
+ }
+ break;
+ }
+ (void)splx(s);
+#if 0
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+#endif
+
+ /*
+ printf("retbits %x\n", bits);
+ */
+ return(bits);
+}
+
+int clopen (dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int s, unit, channel;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ struct tty *tp;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ s = splcl();
+ if (cl->tty) {
+ tp = cl->tty;
+ } else {
+ tp = cl->tty = ttymalloc();
+ }
+ tp->t_oproc = clstart;
+ tp->t_param = clparam;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = cldefaultrate;
+ }
+ /*
+ * do these all the time
+ */
+ if (cl->cl_swflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (cl->cl_swflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (cl->cl_swflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ clparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+#ifdef XXX
+ if ((cl->cl_swflags & TIOCFLAG_SOFTCAR) ||
+ (clmctl(dev, 0, DMGET) & TIOCM_CD)) {
+ tp->t_state |= TS_CARR_ON;
+ } else {
+ tp->t_state &= ~TS_CARR_ON;
+ }
+#endif
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return(EBUSY);
+ }
+#ifdef XXX
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+ if (flag & O_NONBLOCK)
+ goto done;
+#endif
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+#ifdef DEBUG
+ cl_dumpport(channel);
+#endif
+ return((*linesw[tp->t_line].l_open)(dev, tp));
+}
+int clparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+ int s;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+ clccparam(sc, t, channel);
+ s = splcl();
+ cl_unblock(tp);
+ splx(s);
+ return 0;
+}
+
+void cloutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt;
+ char *tptr;
+ int channel;
+ struct clsoftc *sc;
+ dev_t dev;
+ char cl_obuffer[CLCDBUF+1];
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+ channel = CL_CHANNEL(dev);
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = splcl();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+/*XXX*/
+ cnt = min (CLCDBUF,cc);
+ cnt = q_to_b(&tp->t_outq, cl_obuffer, cnt);
+ if (cnt == 0) {
+ break;
+ }
+ for (tptr = cl_obuffer; tptr < &cl_obuffer[cnt]; tptr++) {
+ clputc(sc, channel, *tptr);
+ }
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int clclose (dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ int s;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ s = splcl();
+
+ sc->vbase[CD2400_CAR] = channel;
+ if(cl->cl_consio == 0 && (tp->t_cflag & HUPCL) != 0) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+
+ splx(s);
+ ttyclose(tp);
+
+#if 0
+ cl->tty = NULL;
+#endif
+#ifdef DEBUG
+ cl_dumpport(channel);
+#endif
+
+ return 0;
+}
+int clread (dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return ENXIO;
+ return((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+int clwrite (dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return ENXIO;
+ return((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+int clioctl (dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int error;
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return ENXIO;
+
+ 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);
+
+ switch (cmd) {
+ case TIOCSBRK:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) clmctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) clmctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) clmctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = clmctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = cl->cl_swflags;
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return(EPERM);
+
+ cl->cl_swflags = *(int *)data;
+ cl->cl_swflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return(ENOTTY);
+ }
+
+ return 0;
+}
+int
+clstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = splcl();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return 0;
+}
+
+int
+clcnprobe(cp)
+ struct consdev *cp;
+{
+ /* always there ? */
+ /* serial major */
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == clopen)
+ break;
+ cp->cn_dev = makedev (maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return 1;
+}
+
+int
+clcninit(cp)
+struct consdev *cp;
+{
+#ifdef MAP_DOES_WORK
+ int size = (0x1ff + PGOFSET) & ~PGOFSET;
+ int pcc2_size = (0x3C + PGOFSET) & ~PGOFSET;
+#endif
+ volatile u_char *cd_base;
+
+ cl_cons.cl_paddr = (void *)0xfff45000;
+#ifdef MAP_DOES_WORK
+ cl_cons.cl_vaddr = mapiodev(cl_cons.cl_paddr,size);
+ cd_pcc2_base = mapiodev(0xfff42000,pcc2_size);
+#else
+ cl_cons.cl_vaddr = cl_cons.cl_paddr;
+ cl_cons.pcctwoaddr = (void *)0xfff42000;
+#endif
+ cd_base = cl_cons.cl_vaddr;
+ /* reset the chip? */
+#ifdef CLCD_DO_RESET
+#endif
+#ifdef NEW_CLCD_STRUCT
+ /* set up globals */
+ cl->tftc = 0x10;
+ cl->tpr = CL_TIMEOUT; /* is this correct?? */
+ cl->rpilr = 0x03;
+ cl->tpilr = 0x02;
+ cl->mpilr = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cl->car = 0x00;
+ cl->cor1 = 0x17; /* No parity, ignore parity, 8 bit char */
+ cl->cor2 = 0x00;
+ cl->cor3 = 0x02; /* 1 stop bit */
+ cl->cor4 = 0x00;
+ cl->cor5 = 0x00;
+ cl->cor6 = 0x00;
+ cl->cor7 = 0x00;
+ cl->schr1 = 0x00;
+ cl->schr2 = 0x00;
+ cl->schr3 = 0x00;
+ cl->schr4 = 0x00;
+ cl->scrl = 0x00;
+ cl->scrh = 0x00;
+ cl->lnxt = 0x00;
+ cl->cpsr = 0x00;
+#else
+ /* set up globals */
+#ifdef NOT_ALREADY_SETUP
+ cd_base[CD2400_TFTC] = 0x10;
+ cd_base[CD2400_TPR] = CL_TIMEOUT; /* is this correct?? */
+ cd_base[CD2400_RPILR] = 0x03;
+ cd_base[CD2400_TPILR] = 0x02;
+ cd_base[CD2400_MPILR] = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cd_base[CD2400_CAR] = 0x00;
+ cd_base[CD2400_COR1] = 0x17; /* No parity, ignore parity, 8 bit char */
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02; /* 1 stop bit */
+ cd_base[CD2400_COR4] = 0x00;
+ cd_base[CD2400_COR5] = 0x00;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_CPSR] = 0x00;
+#endif
+#endif
+ return 0;
+}
+
+int
+cl_instat(sc)
+ struct clsoftc *sc;
+{
+ volatile u_char *cd_base;
+ if ( NULL == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+ return (cd_base[CD2400_RIR] & 0x80);
+}
+int
+clcngetc(dev)
+ dev_t dev;
+{
+ u_char val, reoir, licr, isrl, data, status, fifo_cnt;
+ int got_char = 0;
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ volatile struct pcctworeg *pcc2_base = cl_cons.pcctwoaddr;
+ while (got_char == 0) {
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ continue;
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ if (((licr >> 2) & 0x3) == 0) {
+ /* is the interrupt for us (port 0) */
+ /* the character is for us yea. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ data = cd_base[CD2400_RDR];
+ got_char = 1;
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ }
+
+ }
+
+ return data;
+}
+
+int
+clcnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ /* is this the correct location for the cr -> cr/lf tranlation? */
+ if (c == '\n')
+ clputc(0, 0, '\r');
+
+ clputc(0, 0, c);
+ return 0;
+}
+clcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+ if (1 == on) {
+ /* enable polling */
+ } else {
+ /* disable polling */
+ }
+ return;
+}
+static void
+clputc(sc, unit, c)
+ struct clsoftc *sc;
+ int unit;
+ char c;
+{
+ int s;
+ u_char schar;
+ u_char oldchannel;
+ volatile u_char *cd_base;
+ if (0 == sc) {
+ /* output on console */
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+#ifdef NEW_CLCD_STRUCT
+ /* should we disable, flush and all that goo? */
+ cl->car = unit;
+ schar = cl->schr3;
+ cl->schr3 = c;
+ cl->stcr = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cl->stcr) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ cl->schr3 = schar;
+#else
+if (unit == 0) {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ schar = cd_base[CD2400_SCHR3];
+ cd_base[CD2400_SCHR3] = c;
+ cd_base[CD2400_STCR] = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cd_base[CD2400_STCR]) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ DELAY(5);
+ cd_base[CD2400_SCHR3] = schar;
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+} else {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ if (cd_base[CD2400_TFTC] > 0) {
+ cd_base[CD2400_TDR] = c;
+ }
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+}
+#endif
+ return;
+}
+
+/*
+#ifdef CLCD_DO_POLLED_INPUT
+*/
+#if 1
+void
+cl_chkinput()
+{
+ struct tty *tp;
+ int unit;
+ struct clsoftc *sc;
+ int channel;
+
+ if (dopoll == 0)
+ return;
+ for (unit = 0; unit < clcd.cd_ndevs; unit++) {
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ continue;
+ }
+ if (cl_instat(sc)) {
+ while (cl_instat(sc)){
+ int ch;
+ u_char c;
+ /*
+ *(pinchar++) = clcngetc();
+ */
+ ch = clgetc(sc,&channel) & 0xff;
+ c = ch;
+
+ tp = sc->sc_cl[channel].tty;
+ if (NULL != tp) {
+ (*linesw[tp->t_line].l_rint)(c,tp);
+ }
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+ }
+}
+#endif
+static u_char
+clgetc(sc, channel)
+ struct clsoftc *sc;
+ int *channel;
+{
+ volatile u_char *cd_base;
+ volatile struct pcctworeg *pcc2_base;
+ u_char val, reoir, licr, isrl, fifo_cnt, data;
+ if (0 == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ pcc2_base = cl_cons.pcctwoaddr;
+ } else {
+ cd_base = sc->vbase;
+ pcc2_base = sc->sc_pcctwo;
+ }
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ return 0;
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ *channel = (licr >> 2) & 0x3;
+ /* is the interrupt for us (port 0) */
+ /* the character is for us yea. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ if (fifo_cnt > 0) {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = 0;
+ cd_base[CD2400_TEOIR] = 0x08;
+ }
+ return data;
+}
+int
+clccparam(sc, par, channel)
+ struct clsoftc *sc;
+ struct termios *par;
+ int channel;
+{
+ u_int divisor, clk, clen;
+ int s, imask, ints;
+
+ s = splcl();
+ sc->vbase[CD2400_CAR] = channel;
+ if (par->c_ospeed == 0) {
+ /* dont kill the console */
+ if(sc->sc_cl[channel].cl_consio == 0) {
+ /* disconnect, drop RTS DTR stop reciever */
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+ splx(s);
+ return (0xff);
+ }
+
+ sc->vbase[CD2400_MSVR_RTS] = 0x03;
+ sc->vbase[CD2400_MSVR_DTR] = 0x03;
+
+ divisor = cl_clkdiv(par->c_ospeed);
+ clk = cl_clknum(par->c_ospeed);
+ sc->vbase[CD2400_TBPR] = divisor;
+ sc->vbase[CD2400_TCOR] = clk << 5;
+ divisor = cl_clkdiv(par->c_ispeed);
+ clk = cl_clknum(par->c_ispeed);
+ sc->vbase[CD2400_RBPR] = divisor;
+ sc->vbase[CD2400_RCOR] = clk;
+ sc->vbase[CD2400_RTPRl] = cl_clkrxtimeout(par->c_ispeed);
+ sc->vbase[CD2400_RTPRh] = 0x00;
+
+ switch (par->c_cflag & CSIZE) {
+ case CS5:
+ clen = 4; /* this is the mask for the chip. */
+ imask = 0x1F;
+ break;
+ case CS6:
+ clen = 5;
+ imask = 0x3F;
+ break;
+ case CS7:
+ clen = 6;
+ imask = 0x7F;
+ break;
+ default:
+ clen = 7;
+ imask = 0xFF;
+ }
+ sc->vbase[CD2400_COR3] = par->c_cflag & PARENB ? 4 : 2;
+
+ if (par->c_cflag & PARENB) {
+ if (par->c_cflag & PARODD) {
+ sc->vbase[CD2400_COR1] = 0xE0 | clen ; /* odd */
+ } else {
+ sc->vbase[CD2400_COR1] = 0x40 | clen ; /* even */
+ }
+ } else {
+ sc->vbase[CD2400_COR1] = 0x10 | clen; /* ignore parity */
+ }
+
+ if (sc->sc_cl[channel].cl_consio == 0
+ && (par->c_cflag & CREAD) == 0 )
+ {
+ sc->vbase[CD2400_CCR] = 0x08;
+ } else {
+ sc->vbase[CD2400_CCR] = 0x0a;
+ }
+ ints = 0;
+#define SCC_DSR 0x80
+#define SCC_DCD 0x40
+#define SCC_CTS 0x20
+ if ((par->c_cflag & CLOCAL) == 0) {
+ ints |= SCC_DCD;
+ }
+ if ((par->c_cflag & CCTS_OFLOW) != 0) {
+ ints |= SCC_CTS;
+ }
+ if ((par->c_cflag & CRTSCTS) != 0) {
+ ints |= SCC_CTS;
+ }
+#ifdef DONT_LET_HARDWARE
+ if ((par->c_cflag & CCTS_IFLOW) != 0) {
+ ints |= SCC_DSR;
+ }
+#endif
+ sc->vbase[CD2400_COR4] = ints | CL_FIFO_CNT;
+ sc->vbase[CD2400_COR5] = ints | CL_FIFO_CNT;
+
+ return imask;
+}
+static int clknum = 0;
+u_char
+cl_clkdiv(speed)
+ int speed;
+{
+ int i = 0;
+ if (cl_clocks[clknum].speed == speed) {
+ return cl_clocks[clknum].divisor;
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return cl_clocks[clknum].divisor;
+ }
+ }
+ /* return some sane value if unknown speed */
+ return cl_clocks[4].divisor;
+}
+u_char
+cl_clknum(speed)
+ int speed;
+{
+ int found = 0;
+ int i = 0;
+ if (cl_clocks[clknum].speed == speed) {
+ return cl_clocks[clknum].clock;
+ }
+ for (i = 0; found != 0 && cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[clknum].speed == speed) {
+ clknum = i;
+ return cl_clocks[clknum].clock;
+ }
+ }
+ /* return some sane value if unknown speed */
+ return cl_clocks[4].clock;
+}
+u_char
+cl_clkrxtimeout(speed)
+ int speed;
+{
+ int i = 0;
+ if (cl_clocks[clknum].speed == speed) {
+ return cl_clocks[clknum].rx_timeout;
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return cl_clocks[clknum].rx_timeout;
+ }
+ }
+ /* return some sane value if unknown speed */
+ return cl_clocks[4].rx_timeout;
+}
+void
+cl_unblock(tp)
+ struct tty *tp;
+{
+ tp->t_state &= ~TS_FLUSH;
+ if (tp->t_outq.c_cc != 0)
+ clstart(tp);
+}
+void
+clstart(tp)
+ struct tty *tp;
+{
+ dev_t dev;
+ u_char cbuf;
+ struct clsoftc *sc;
+ int channel, unit, s, cnt;
+
+ dev = tp->t_dev;
+ channel = CL_CHANNEL(dev);
+/* hack to test output on non console only */
+#if 0
+ if (channel == 0) {
+ cloutput(tp);
+ return;
+ }
+#endif
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = splcl();
+#if 0
+ if (sc->sc_cl[channel].transmitting == 1) {
+ /* i'm busy, go away, I will get to it later. */
+ splx(s);
+ return;
+ }
+ cnt = q_to_b(&tp->t_outq, &cbuf, 1);
+ if ( cnt != 0 ) {
+ sc->sc_cl[channel].transmitting = 1;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_TDR] = cbuf;
+ } else {
+ sc->sc_cl[channel].transmitting = 0;
+ }
+#else
+ if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0)
+ {
+ tp->t_state |= TS_BUSY;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_IER] = sc->vbase[CD2400_IER] | 0x3;
+ }
+#endif
+ splx(s);
+ return;
+}
+int
+cl_mintr(sc)
+ struct clsoftc *sc;
+{
+ u_char mir, misr, msvr;
+ int channel;
+ struct tty *tp;
+ if(((mir = sc->vbase[CD2400_MIR]) & 0x40) == 0x0) {
+ /* only if intr is not shared? */
+ printf("cl_mintr extra intr\n");
+ return 0;
+ }
+ sc->sc_mxintrcnt.ev_count++;
+
+ channel = mir & 0x03;
+ misr = sc->vbase[CD2400_MISR];
+ msvr = sc->vbase[CD2400_MSVR_RTS];
+ if (misr & 0x01) {
+ /* timers are not currently used?? */
+ printf ("cl_mintr: channel %x timer 1 unexpected\n",channel);
+ }
+ if (misr & 0x02) {
+ /* timers are not currently used?? */
+ printf ("cl_mintr: channel %x timer 2 unexpected\n",channel);
+ }
+ if (misr & 0x20) {
+ printf ("cl_mintr: channel %x cts %x\n",channel,
+ ((msvr & 0x20) != 0x0)
+ );
+ }
+ if (misr & 0x40) {
+ struct tty *tp = sc->sc_cl[channel].tty;
+ printf ("cl_mintr: channel %x cd %x\n",channel,
+ ((msvr & 0x40) != 0x0)
+ );
+ ttymodem(tp, ((msvr & 0x40) != 0x0) );
+ }
+ if (misr & 0x80) {
+ printf ("cl_mintr: channel %x dsr %x\n",channel,
+ ((msvr & 0x80) != 0x0)
+ );
+ }
+ sc->vbase[CD2400_MEOIR] = 0x00;
+ return 1;
+}
+
+int
+cl_txintr(sc)
+ struct clsoftc *sc;
+{
+ static empty = 0;
+ u_char tir, licr, teoir;
+ u_char max;
+ int channel;
+ struct tty *tp;
+ int cnt;
+ u_char buffer[CL_FIFO_MAX +1];
+ u_char *tptr;
+ if(((tir = sc->vbase[CD2400_TIR]) & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf ("cl_txintr extra intr\n");
+ return 0;
+ }
+ sc->sc_txintrcnt.ev_count++;
+
+ channel = tir & 0x03;
+ licr = sc->vbase[CD2400_LICR];
+
+ sc->sc_cl[channel].txcnt ++;
+
+ tp = sc->sc_cl[channel].tty;
+ if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
+ sc->vbase[CD2400_TEOIR] = 0x08;
+ return 1;
+ }
+ switch ((licr >> 4)& 0x3) {
+ case CL_DMAMODE:
+ teoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ max = sc->vbase[CD2400_TFTC];
+ cnt = min ((int)max,tp->t_outq.c_cc);
+ if (cnt != 0) {
+ cnt = q_to_b(&tp->t_outq, buffer, cnt);
+ empty = 0;
+ for (tptr = buffer; tptr < &buffer[cnt]; tptr++) {
+ sc->vbase[CD2400_TDR]= *tptr;
+ }
+ teoir = 0x00;
+ } else {
+ if (empty > 5 && ((empty % 20000 )== 0)) {
+ printf("cl_txintr to many empty intr %d channel %d\n",
+ empty, channel);
+ }
+ empty++;
+ teoir = 0x08;
+ if (tp->t_state & TS_BUSY) {
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t) &tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ sc->vbase[CD2400_IER] = sc->vbase[CD2400_IER] & ~0x3;
+ }
+ break;
+ default:
+ printf("cl_txintr unknown mode %x\n", ((licr >> 4) & 0x3));
+ /* we probably will go to hell quickly now */
+ teoir = 0x08;
+ }
+ sc->vbase[CD2400_TEOIR] = teoir;
+ return 1;
+}
+
+int
+cl_rxintr(sc)
+ struct clsoftc *sc;
+{
+ u_char rir, channel, licr, risrl;
+ u_char c;
+ u_char fifocnt;
+ struct tty *tp;
+ int i;
+ u_char reoir;
+
+ if(((rir = sc->vbase[CD2400_RIR]) & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf ("cl_rxintr extra intr\n");
+ return 0;
+ }
+ sc->sc_rxintrcnt.ev_count++;
+ channel = rir & 0x3;
+ licr = sc->vbase[CD2400_LICR];
+ reoir = 0x08;
+
+ sc->sc_cl[channel].rxcnt ++;
+
+ switch (licr & 0x03) {
+ case CL_DMAMODE:
+ reoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ risrl = sc->vbase[CD2400_RISRl];
+ if (risrl & 0x80) {
+ /* timeout, no characters */
+ reoir = 0x08;
+ } else
+ /* We don't need no sinkin special characters */
+ if (risrl & 0x08) {
+ cl_overflow (sc, channel, &sc->sc_fotime, "fifo");
+ reoir = 0x08;
+ } else
+ if (risrl & 0x04) {
+ cl_parity(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x02) {
+ cl_frame(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x01) {
+ cl_break(sc, channel);
+ reoir = 0x08;
+ } else {
+ fifocnt = sc->vbase[CD2400_RFOC];
+ tp = sc->sc_cl[channel].tty;
+ for (i = 0; i < fifocnt; i++) {
+ c = sc->vbase[CD2400_RDR];
+#if USE_BUFFER
+ cl_appendbuf(sc, channel, c);
+#else
+ /* does any restricitions exist on spl
+ * for this call
+ */
+ (*linesw[tp->t_line].l_rint)(c,tp);
+ reoir = 0x00;
+#endif
+ }
+ }
+ break;
+ default:
+ printf("cl_rxintr unknown mode %x\n",licr & 0x03);
+ /* we probably will go to hell quickly now */
+ reoir = 0x08;
+ }
+ sc->vbase[CD2400_REOIR] = reoir;
+ return 1;
+}
+
+void
+cl_overflow (sc, channel, ptime, msg)
+struct clsoftc *sc;
+int channel;
+long *ptime;
+char *msg;
+{
+/*
+ if (*ptime != time.tv_sec) {
+*/
+ {
+/*
+ *ptime = time.tv_sec);
+*/
+ log(LOG_WARNING, "%s%d[%d]: %s overrun", clcd.cd_name,
+ 0 /* fix */, channel, msg);
+ }
+ return;
+}
+void
+cl_parity (sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: parity error", clcd.cd_name, 0, channel);
+ return;
+}
+void
+cl_frame (sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: frame error", clcd.cd_name, 0, channel);
+ return;
+}
+void
+cl_break (sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: break detected", clcd.cd_name, 0, channel);
+ return;
+}
+
+void
+cl_dumpport0()
+{
+ cl_dumpport(0);
+ return;
+}
+void
+cl_dumpport1()
+{
+ cl_dumpport(1);
+ return;
+}
+void
+cl_dumpport2()
+{
+ cl_dumpport(2);
+ return;
+}
+void
+cl_dumpport3()
+{
+ cl_dumpport(3);
+ return;
+}
+
+void
+cl_dumpport(channel)
+ int channel;
+{
+ u_char livr, cmr, cor1, cor2, cor3, cor4, cor5, cor6, cor7,
+ schr1, schr2, schr3, schr4, scrl, scrh, lnxt,
+ rbpr, rcor, tbpr, tcor, rpilr, rir, tpr, ier, ccr,
+ csr, rts, dtr, rtprl, rtprh;
+ struct clsoftc *sc;
+
+ volatile u_char *cd_base;
+ int s;
+
+ cd_base = cl_cons.cl_vaddr;
+
+ sc = (struct clsoftc *) clcd.cd_devs[0];
+
+ s = splcl();
+ cd_base[CD2400_CAR] = (char) channel;
+ livr = cd_base[CD2400_LIVR];
+ cmr = cd_base[CD2400_CMR];
+ cor1 = cd_base[CD2400_COR1];
+ cor2 = cd_base[CD2400_COR2];
+ cor3 = cd_base[CD2400_COR3];
+ cor4 = cd_base[CD2400_COR4];
+ cor5 = cd_base[CD2400_COR5];
+ cor6 = cd_base[CD2400_COR6];
+ cor7 = cd_base[CD2400_COR7];
+ schr1 = cd_base[CD2400_SCHR1];
+ schr2 = cd_base[CD2400_SCHR2];
+ schr3 = cd_base[CD2400_SCHR3];
+ schr4 = cd_base[CD2400_SCHR4];
+ scrl = cd_base[CD2400_SCRl];
+ scrh = cd_base[CD2400_SCRh];
+ lnxt = cd_base[CD2400_LNXT];
+ rbpr = cd_base[CD2400_RBPR];
+ rcor = cd_base[CD2400_RCOR];
+ tbpr = cd_base[CD2400_TBPR];
+ rpilr = cd_base[CD2400_RPILR];
+ ier = cd_base[CD2400_IER];
+ ccr = cd_base[CD2400_CCR];
+ tcor = cd_base[CD2400_TCOR];
+ csr = cd_base[CD2400_CSR];
+ tpr = cd_base[CD2400_TPR];
+ rts = cd_base[CD2400_MSVR_RTS];
+ dtr = cd_base[CD2400_MSVR_DTR];
+ rtprl = cd_base[CD2400_RTPRl];
+ rtprh = cd_base[CD2400_RTPRh];
+ splx(s);
+
+ printf("{ port %x livr %x cmr %x\n",
+ channel,livr, cmr);
+ printf("cor1 %x cor2 %x cor3 %x cor4 %x cor5 %x cor6 %x cor7 %x\n",
+ cor1, cor2, cor3, cor4, cor5, cor6, cor7);
+ printf("schr1 %x schr2 %x schr3 %x schr4 %x\n",
+ schr1, schr2, schr3, schr4);
+ printf("scrl %x scrh %x lnxt %x\n",
+ scrl, scrh, lnxt);
+ printf("rbpr %x rcor %x tbpr %x tcor %x\n",
+ rbpr, rcor, tbpr, tcor);
+ printf("rpilr %x rir %x ier %x ccr %x\n",
+ rpilr, rir, ier, ccr);
+ printf("tpr %x csr %x rts %x dtr %x\n",
+ tpr, csr, rts, dtr);
+ printf("rtprl %x rtprh %x\n",
+ rtprl, rtprh);
+ printf("rxcnt %x txcnt %x\n",
+ sc->sc_cl[channel].rxcnt, sc->sc_cl[channel].txcnt);
+ printf("}\n");
+ return;
+}
diff --git a/sys/arch/mvme68k/dev/clock.c b/sys/arch/mvme68k/dev/clock.c
new file mode 100644
index 00000000000..e4871cc2db3
--- /dev/null
+++ b/sys/arch/mvme68k/dev/clock.c
@@ -0,0 +1,393 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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. 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.
+ *
+ * @(#)clock.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <machine/psl.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+
+#include "pcc.h"
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NPCC > 0
+#include <mvme68k/dev/pccreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+
+#if defined(GPROF)
+#include <sys/gmon.h>
+#endif
+
+/*
+ * Statistics clock interval and variance, in usec. Variance must be a
+ * power of two. Since this gives us an even number, not an odd number,
+ * we discard one case and compensate. That is, a variance of 8192 would
+ * give us offsets in [0..8191]. Instead, we take offsets in [1..8191].
+ * This is symmetric about the point 2048, or statvar/2, and thus averages
+ * to that value (assuming uniform random numbers).
+ */
+int statvar = 8192;
+int statmin; /* statclock interval - 1/2*variance */
+
+struct clocksoftc {
+ struct device sc_dev;
+ struct intrhand sc_profih;
+ struct intrhand sc_statih;
+};
+
+void clockattach __P((struct device *, struct device *, void *));
+int clockmatch __P((struct device *, void *, void *));
+
+struct cfdriver clockcd = {
+ NULL, "clock", clockmatch, clockattach,
+ DV_DULL, sizeof(struct clocksoftc), 0
+};
+
+int clockintr __P((void *));
+int statintr __P((void *));
+
+int clockbus;
+u_char stat_reset, prof_reset;
+
+/*
+ * Every machine must have a clock tick device of some sort; for this
+ * platform this file manages it, no matter what form it takes.
+ */
+int
+clockmatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ return (1);
+}
+
+void
+clockattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct clocksoftc *sc = (struct clocksoftc *)self;
+
+ sc->sc_profih.ih_fn = clockintr;
+ sc->sc_profih.ih_arg = 0;
+ sc->sc_profih.ih_wantframe = 1;
+ sc->sc_profih.ih_ipl = ca->ca_ipl;
+
+ sc->sc_statih.ih_fn = statintr;
+ sc->sc_statih.ih_arg = 0;
+ sc->sc_statih.ih_wantframe = 1;
+ sc->sc_statih.ih_ipl = ca->ca_ipl;
+
+ clockbus = ca->ca_bustype;
+ switch (ca->ca_bustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ prof_reset = ca->ca_ipl | PCC_IRQ_IEN | PCC_TIMERACK;
+ stat_reset = ca->ca_ipl | PCC_IRQ_IEN | PCC_TIMERACK;
+ pccintr_establish(PCCV_TIMER1, &sc->sc_profih);
+ pccintr_establish(PCCV_TIMER2, &sc->sc_statih);
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ prof_reset = ca->ca_ipl | MC_IRQ_IEN | MC_IRQ_ICLR;
+ stat_reset = ca->ca_ipl | MC_IRQ_IEN | MC_IRQ_ICLR;
+ mcintr_establish(MCV_TIMER1, &sc->sc_profih);
+ mcintr_establish(MCV_TIMER2, &sc->sc_statih);
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ prof_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR;
+ stat_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR;
+ pcctwointr_establish(PCC2V_TIMER1, &sc->sc_profih);
+ pcctwointr_establish(PCC2V_TIMER2, &sc->sc_statih);
+ break;
+#endif
+ }
+
+ printf("\n");
+}
+
+/*
+ * clockintr: ack intr and call hardclock
+ */
+int
+clockintr(arg)
+ void *arg;
+{
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t1irq = prof_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ sys_mc->mc_t1irq = prof_reset;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sys_pcc2->pcc2_t1irq = prof_reset;
+ break;
+#endif
+ }
+ hardclock(arg);
+ return (1);
+}
+
+/*
+ * Set up real-time clock; we don't have a statistics clock at
+ * present.
+ */
+cpu_initclocks()
+{
+ register int statint, minint;
+
+ if (1000000 % hz) {
+ printf("cannot get %d Hz clock; using 100 Hz\n", hz);
+ hz = 100;
+ tick = 1000000 / hz;
+ }
+ if (stathz == 0)
+ stathz = hz;
+ if (1000000 % stathz) {
+ printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
+ stathz = 100;
+ }
+ profhz = stathz; /* always */
+
+ statint = 1000000 / stathz;
+ minint = statint / 2 + 100;
+ while (statvar > minint)
+ statvar >>= 1;
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t1pload = pcc_timer_us2lim(tick);
+ sys_pcc->pcc_t1ctl = PCC_TIMERCLEAR;
+ sys_pcc->pcc_t1ctl = PCC_TIMERSTART;
+ sys_pcc->pcc_t1irq = prof_reset;
+
+ sys_pcc->pcc_t2pload = pcc_timer_us2lim(statint);
+ sys_pcc->pcc_t2ctl = PCC_TIMERCLEAR;
+ sys_pcc->pcc_t2ctl = PCC_TIMERSTART;
+ sys_pcc->pcc_t2irq = stat_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ /* profclock */
+ sys_mc->mc_t1ctl = 0;
+ sys_mc->mc_t1cmp = mc_timer_us2lim(tick);
+ sys_mc->mc_t1count = 0;
+ sys_mc->mc_t1ctl = MC_TCTL_CEN | MC_TCTL_COC | MC_TCTL_COVF;
+ sys_mc->mc_t1irq = prof_reset;
+
+ /* statclock */
+ sys_mc->mc_t2ctl = 0;
+ sys_mc->mc_t2cmp = mc_timer_us2lim(statint);
+ sys_mc->mc_t2count = 0;
+ sys_mc->mc_t2ctl = MC_TCTL_CEN | MC_TCTL_COC | MC_TCTL_COVF;
+ sys_mc->mc_t2irq = stat_reset;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ /* profclock */
+ sys_pcc2->pcc2_t1ctl = 0;
+ sys_pcc2->pcc2_t1cmp = pcc2_timer_us2lim(tick);
+ sys_pcc2->pcc2_t1count = 0;
+ sys_pcc2->pcc2_t1ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC |
+ PCC2_TCTL_COVF;
+ sys_pcc2->pcc2_t1irq = prof_reset;
+
+ /* statclock */
+ sys_pcc2->pcc2_t2ctl = 0;
+ sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(statint);
+ sys_pcc2->pcc2_t2count = 0;
+ sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC |
+ PCC2_TCTL_COVF;
+ sys_pcc2->pcc2_t2irq = stat_reset;
+ break;
+#endif
+ }
+ statmin = statint - (statvar >> 1);
+}
+
+void
+setstatclockrate(newhz)
+ int newhz;
+{
+}
+
+int
+statintr(cap)
+ void *cap;
+{
+ register u_long newint, r, var;
+
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t2irq = stat_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ sys_mc->mc_t2irq = stat_reset;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sys_pcc2->pcc2_t2irq = stat_reset;
+ break;
+#endif
+ }
+
+ statclock((struct clockframe *)cap);
+
+ /*
+ * Compute new randomized interval. The intervals are uniformly
+ * distributed on [statint - statvar / 2, statint + statvar / 2],
+ * and therefore have mean statint, giving a stathz frequency clock.
+ */
+ var = statvar;
+ do {
+ r = random() & (var - 1);
+ } while (r == 0);
+ newint = statmin + r;
+
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t2pload = pcc_timer_us2lim(newint);
+ sys_pcc->pcc_t2ctl = PCC_TIMERCLEAR;
+ sys_pcc->pcc_t2ctl = PCC_TIMERSTART;
+ sys_pcc->pcc_t2irq = stat_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ sys_mc->mc_t2ctl = 0;
+ sys_mc->mc_t2cmp = mc_timer_us2lim(newint);
+ sys_mc->mc_t2count = 0; /* should I? */
+ sys_mc->mc_t2irq = stat_reset;
+ sys_mc->mc_t2ctl = MC_TCTL_CEN | MC_TCTL_COC;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sys_pcc2->pcc2_t2ctl = 0;
+ sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(newint);
+ sys_pcc2->pcc2_t2count = 0; /* should I? */
+ sys_pcc2->pcc2_t2irq = stat_reset;
+ sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC;
+ break;
+#endif
+ }
+ return (1);
+}
+
+delay(us)
+ register int us;
+{
+ volatile register int c;
+
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ /*
+ * XXX MVME147 doesn't have a 3rd free-running timer,
+ * so we use a stupid loop. Fix the code to watch t1:
+ * the profiling timer.
+ */
+ c = 2 * us;
+ while (--c > 0)
+ ;
+ return (0);
+#endif
+#if NMC > 0
+ case BUS_MC:
+ /*
+ * Reset and restart a free-running timer 1MHz, watch
+ * for it to reach the required count.
+ */
+ sys_mc->mc_t3irq = 0;
+ sys_mc->mc_t3ctl = 0;
+ sys_mc->mc_t3count = 0;
+ sys_mc->mc_t3ctl = MC_TCTL_CEN | MC_TCTL_COVF;
+
+ while (sys_mc->mc_t3count < us)
+ ;
+ return (0);
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ /*
+ * XXX MVME167 doesn't have a 3rd free-running timer,
+ * so we use a stupid loop. Fix the code to watch t1:
+ * the profiling timer.
+ */
+ c = 4 * us;
+ while (--c > 0)
+ ;
+ return (0);
+#endif
+ }
+}
diff --git a/sys/arch/mvme68k/dev/dmavar.h b/sys/arch/mvme68k/dev/dmavar.h
new file mode 100644
index 00000000000..99da32b62c1
--- /dev/null
+++ b/sys/arch/mvme68k/dev/dmavar.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * 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 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.
+ *
+ * @(#)dmavar.h 7.2 (Berkeley) 11/4/90
+ * $Id: dmavar.h,v 1.1 1995/10/18 10:43:06 deraadt Exp $
+ */
+
+/* dmago flags */
+#define DMAGO_READ 0x08 /* transfer is a read */
+#define DMAGO_NOINT 0x80 /* don't interrupt on completion */
+
+#ifdef KERNEL
+typedef void (*dmafree_t) __P((void *dev));
+typedef int (*dmago_t) __P((void *dev, char *, int, int));
+typedef int (*dmanext_t) __P((void *dev));
+typedef void (*dmastop_t) __P((void *dev));
+#endif
+
diff --git a/sys/arch/mvme68k/dev/flash.c b/sys/arch/mvme68k/dev/flash.c
new file mode 100644
index 00000000000..933b2a199a6
--- /dev/null
+++ b/sys/arch/mvme68k/dev/flash.c
@@ -0,0 +1,360 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/mioctl.h>
+
+#include "mc.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+
+#include <mvme68k/dev/flashreg.h>
+
+struct flashsoftc {
+ struct device sc_dev;
+ caddr_t sc_paddr;
+ volatile u_char * sc_vaddr;
+ u_char sc_manu;
+ u_char sc_ii;
+ int sc_len;
+ int sc_zonesize;
+};
+
+void flashattach __P((struct device *, struct device *, void *));
+int flashmatch __P((struct device *, void *, void *));
+
+struct cfdriver flashcd = {
+ NULL, "flash", flashmatch, flashattach,
+ DV_DULL, sizeof(struct flashsoftc), 0
+};
+
+int flashwritebyte __P((struct flashsoftc *sc, int addr, u_char val));
+int flasherasezone __P((struct flashsoftc *sc, int addr));
+
+struct flashii intel_flashii[] = {
+ { "28F008SA", FLII_INTEL_28F008SA, 1024*1024, 64*1024 },
+ { "28F008SA-L", FLII_INTEL_28F008SA_L, 1024*1024, 64*1024 },
+ { NULL },
+};
+
+struct flashmanu {
+ char *name;
+ u_char manu;
+ struct flashii *flashii;
+} flashmanu[] = {
+ { "intel", FLMANU_INTEL, intel_flashii },
+ { NULL }
+};
+
+int
+flashmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ struct confargs *ca = args;
+
+#ifdef MVME147
+ if (cputyp == CPU_147)
+ return (0);
+#endif
+#ifdef MVME167
+ /*
+ * XXX: 166 has 4 byte-wide flash rams side-by-side, and
+ * isn't supported (yet).
+ */
+ if (cputyp == CPU_166)
+ return (0);
+#endif
+
+ if (badpaddr(ca->ca_paddr, 1))
+ return (0);
+
+ /*
+ * XXX: need to determine if it is flash or rom
+ */
+ return (1);
+}
+
+void
+flashattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct flashsoftc *sc = (struct flashsoftc *)self;
+ struct confargs *ca = args;
+ int manu, ident;
+
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = mapiodev(sc->sc_paddr, NBPG);
+
+ switch (cputyp) {
+#ifdef MVME162
+ case CPU_162:
+ mc_enableflashwrite(1);
+ break;
+#endif
+ }
+
+ /* read manufacturer and product identifier from flash */
+ sc->sc_vaddr[0] = FLCMD_RESET;
+ sc->sc_vaddr[0] = FLCMD_READII;
+ sc->sc_manu = sc->sc_vaddr[0];
+ sc->sc_ii = sc->sc_vaddr[1];
+ sc->sc_vaddr[0] = FLCMD_RESET;
+
+ for (manu = 0; flashmanu[manu].name; manu++)
+ if (flashmanu[manu].manu == sc->sc_manu)
+ break;
+ if (flashmanu[manu].name == NULL) {
+ printf(": unknown manu 0x%02x ident %02x\n",
+ sc->sc_manu, sc->sc_ii);
+ return;
+ }
+ for (ident = 0; flashmanu[manu].flashii[ident].name; ident++)
+ if (flashmanu[manu].flashii[ident].ii == sc->sc_ii)
+ break;
+ if (flashmanu[manu].flashii[ident].name == NULL) {
+ printf(": unknown manu %s ident 0x%02x\n",
+ flashmanu[manu].name, sc->sc_ii);
+ return;
+ }
+ sc->sc_len = flashmanu[manu].flashii[ident].size;
+ sc->sc_zonesize = flashmanu[manu].flashii[ident].zonesize;
+ printf(": %s %s len %d", flashmanu[manu].name,
+ flashmanu[manu].flashii[ident].name, sc->sc_len);
+
+ unmapiodev(sc->sc_vaddr, NBPG);
+ sc->sc_vaddr = mapiodev(sc->sc_paddr, sc->sc_len);
+ if (sc->sc_vaddr == NULL) {
+ sc->sc_len = 0;
+ printf(" -- failed to map");
+ }
+ printf("\n");
+}
+
+/*ARGSUSED*/
+int
+flashopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= flashcd.cd_ndevs ||
+ flashcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+flashclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+flashioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct flashsoftc *sc = (struct flashsoftc *) flashcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ case MIOCGSIZ:
+ *(int *)data = sc->sc_len;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+flashread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct flashsoftc *sc = (struct flashsoftc *) flashcd.cd_devs[unit];
+ register vm_offset_t v;
+ register int c;
+ register struct iovec *iov;
+ int error = 0;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("flashrw");
+ continue;
+ }
+
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if (v + c > sc->sc_len)
+ c = sc->sc_len - v; /* till end of FLASH */
+ if (c == 0)
+ return (0);
+ error = uiomove((caddr_t)sc->sc_vaddr + v, c, uio);
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+flashwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ return (ENXIO);
+}
+
+int
+flashmmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct flashsoftc *sc = (struct flashsoftc *) flashcd.cd_devs[unit];
+
+ /* allow access only in RAM */
+ if (off > sc->sc_len)
+ return (-1);
+ return (m68k_btop(sc->sc_paddr + off));
+}
+
+int
+flasherasezone(sc, addr)
+ struct flashsoftc *sc;
+ int addr;
+{
+ u_char sr;
+
+ sc->sc_vaddr[addr] = FLCMD_ESETUP;
+ sc->sc_vaddr[addr] = FLCMD_ECONFIRM;
+
+ /* XXX should use sleep/wakeup/timeout combination */
+ do {
+ sc->sc_vaddr[0] = FLCMD_READSTAT;
+ sr = sc->sc_vaddr[0];
+ } while (sr & FLSR_WSMS == 0);
+ if (sr & FLSR_ES)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Should add some light retry code. If a write fails see if an
+ * erase helps the situation... eventually flash rams become
+ * useless but perhaps we can get just one more cycle out of it.
+ */
+int
+flashwritebyte(sc, addr, val)
+ struct flashsoftc *sc;
+ int addr;
+ u_char val;
+{
+ u_char sr;
+
+ /*
+ * If a zero'd bit in the flash memory needs to become set,
+ * then the zone must be erased and rebuilt.
+ */
+ if (val & ~sc->sc_vaddr[addr]) {
+ int faddr = addr & ~(sc->sc_zonesize - 1);
+ u_char *zone;
+ int i;
+
+ zone = (u_char *)malloc(sc->sc_zonesize, M_TEMP, M_WAITOK);
+ if (!zone)
+ return (-1);
+ bcopy((caddr_t)&sc->sc_vaddr[faddr], zone, sc->sc_zonesize);
+
+ if (flasherasezone(sc, faddr) == -1)
+ return (-1);
+
+ zone[addr - faddr] = val;
+ for (i = 0; i < sc->sc_zonesize; i++) {
+ sc->sc_vaddr[faddr + i] = FLCMD_WSETUP;
+ sc->sc_vaddr[faddr + i] = zone[i];
+ do {
+ sc->sc_vaddr[0] = FLCMD_READSTAT;
+ sr = sc->sc_vaddr[0];
+ } while (sr & FLSR_WSMS == 0);
+ if (sr & FLSR_BWS)
+ return (-1); /* write failed! */
+ }
+ free(zone, M_TEMP);
+ return (0);
+ }
+
+ sc->sc_vaddr[addr] = FLCMD_WSETUP;
+ sc->sc_vaddr[addr] = val;
+ do {
+ sc->sc_vaddr[0] = FLCMD_READSTAT;
+ sr = sc->sc_vaddr[0];
+ } while (sr & FLSR_WSMS == 0);
+ if (sr & FLSR_BWS)
+ return (-1); /* write failed! */
+ return (0);
+}
diff --git a/sys/arch/mvme68k/dev/flashreg.h b/sys/arch/mvme68k/dev/flashreg.h
new file mode 100644
index 00000000000..d9d82c5e492
--- /dev/null
+++ b/sys/arch/mvme68k/dev/flashreg.h
@@ -0,0 +1,63 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+#define FLCMD_RESET 0xff
+#define FLCMD_READII 0x90
+#define FLCMD_READSTAT 0x70
+#define FLCMD_CLEARSTAT 0x50
+#define FLCMD_ESETUP 0x20
+#define FLCMD_ECONFIRM 0xd0
+#define FLCMD_ESUSPEND 0xb0
+#define FLCMD_ERESUME 0xd0
+#define FLCMD_WSETUP 0x40
+#define FLCMD_AWSETUP 0x10
+
+#define FLSR_WSMS 0x80
+#define FLSR_ESS 0x40
+#define FLSR_ES 0x20
+#define FLSR_BWS 0x10
+#define FLSR_VPPS 0x08
+
+/* manufacturers */
+#define FLMANU_INTEL 0x89
+
+/* intel parts */
+#define FLII_INTEL_28F020 0xbd
+#define FLII_INTEL_28F008SA 0xa1
+#define FLII_INTEL_28F008SA_L 0xa2
+
+struct flashii {
+ char *name;
+ u_char ii;
+ int size;
+ int zonesize;
+};
diff --git a/sys/arch/mvme68k/dev/fooip.c b/sys/arch/mvme68k/dev/fooip.c
new file mode 100644
index 00000000000..f0217ba369a
--- /dev/null
+++ b/sys/arch/mvme68k/dev/fooip.c
@@ -0,0 +1,123 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * A sample framework for writing an IP module driver.
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/ipicreg.h>
+
+struct fooipregs {
+ volatile u_char fooip_reg1;
+ volatile u_char fooip_vec;
+};
+
+struct fooipsoftc {
+ struct device sc_dev;
+ struct ipicsoftc *sc_ipicsc;
+ struct intrhand sc_ih;
+
+ int sc_slot;
+ struct fooipregs *sc_regs;
+};
+
+void fooipattach __P((struct device *, struct device *, void *));
+int fooipmatch __P((struct device *, void *, void *));
+
+struct cfdriver fooipcd = {
+ NULL, "fooip", fooipmatch, fooipattach,
+ DV_DULL, sizeof(struct fooipsoftc), 0
+};
+
+int fooipintr __P((void *));
+
+int
+fooipmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ return (1);
+}
+
+void
+fooipattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct fooipsoftc *sc = (struct fooipsoftc *)self;
+ struct confargs *ca = args;
+
+ sc->sc_ipicsc = (struct ipicsoftc *)ca->ca_master;
+ sc->sc_regs = (struct fooipregs *)(ca->ca_vaddr +
+ IPIC_IP_REGOFFSET);
+ sc->sc_slot = ca->ca_offset;
+
+ /* this device uses only one interrupt */
+ sc->sc_ih.ih_fn = fooipintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+ ipicintr_establish(ca->ca_vec, &sc->sc_ih);
+
+ sc->sc_regs->fooip_vec = ca->ca_vec;
+ sc->sc_ipicsc->sc_ipic->ipic_irq[sc->sc_slot][0] = ca->ca_ipl |
+ IPIC_IRQ_ICLR | IPIC_IRQ_IEN;
+
+ printf("\n");
+}
+
+int
+fooipintr(arg)
+ void *arg;
+{
+ struct fooipsoftc *sc = arg;
+
+ if (sc->sc_ipicsc->sc_ipic->ipic_irq[sc->sc_slot][0] & IPIC_IRQ_INT) {
+ /* clear interrupt on device */
+ return (1);
+ }
+ return (0);
+}
diff --git a/sys/arch/mvme68k/dev/i82586.h b/sys/arch/mvme68k/dev/i82586.h
new file mode 100644
index 00000000000..cb40672da90
--- /dev/null
+++ b/sys/arch/mvme68k/dev/i82586.h
@@ -0,0 +1,286 @@
+/* $NetBSD: i82586.h,v 1.3 1995/01/27 09:49:55 pk Exp $ */
+
+/*-
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1992, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * 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 the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * 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 UNIVERSITY OR 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ *
+ * Sun support added by Charles D. Cranor, 25-Oct-94
+ */
+
+struct ie_en_addr {
+ u_char data[6];
+};
+
+/*
+ * This is the master configuration block. It tells the hardware where all
+ * the rest of the stuff is.
+ */
+struct ie_sys_conf_ptr {
+ u_char mbz1[3]; /* must be zero */
+ u_char ie_bus_use; /* true if 8-bit only */
+ u_char mbz2[4]; /* must be zero */
+ caddr_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */
+};
+
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ */
+struct ie_int_sys_conf_ptr {
+ u_char mbz1[1];
+ u_char ie_busy; /* zeroed after init */
+ u_short ie_scb_offset; /* 16-bit physaddr of next struct */
+ caddr_t ie_base; /* 24-bit physaddr for all 16-bit vars */
+};
+
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ */
+struct ie_sys_ctl_block {
+ u_short ie_status; /* status word */
+ u_short ie_command; /* command word */
+ u_short ie_command_list; /* 16-pointer to command block list */
+ u_short ie_recv_list; /* 16-pointer to receive frame list */
+ u_short ie_err_crc; /* CRC errors */
+ u_short ie_err_align; /* Alignment errors */
+ u_short ie_err_resource; /* Resource errors */
+ u_short ie_err_overrun; /* Overrun errors */
+};
+
+/* Command values */
+#define IE_RU_COMMAND SWAP(0x0070) /* mask for RU command */
+#define IE_RU_NOP SWAP(0) /* for completeness */
+#define IE_RU_START SWAP(0x0010) /* start receive unit command */
+#define IE_RU_ENABLE SWAP(0x0020) /* enable receiver command */
+#define IE_RU_DISABLE SWAP(0x0030) /* disable receiver command */
+#define IE_RU_ABORT SWAP(0x0040) /* abort current receive operation */
+
+#define IE_CU_COMMAND SWAP(0x0700) /* mask for CU command */
+#define IE_CU_NOP SWAP(0) /* included for completeness */
+#define IE_CU_START SWAP(0x0100) /* do-command command */
+#define IE_CU_RESUME SWAP(0x0200) /* resume a suspended cmd list */
+#define IE_CU_STOP SWAP(0x0300) /* SUSPEND was already taken */
+#define IE_CU_ABORT SWAP(0x0400) /* abort current command */
+
+#define IE_ACK_COMMAND SWAP(0xf000) /* mask for ACK command */
+#define IE_ACK_CX SWAP(0x8000) /* ack IE_ST_DONE */
+#define IE_ACK_FR SWAP(0x4000) /* ack IE_ST_RECV */
+#define IE_ACK_CNA SWAP(0x2000) /* ack IE_ST_ALLDONE */
+#define IE_ACK_RNR SWAP(0x1000) /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE SWAP(0xf000) /* mask for cause of interrupt */
+#define IE_ST_DONE SWAP(0x8000) /* command with I bit completed */
+#define IE_ST_RECV SWAP(0x4000) /* frame received */
+#define IE_ST_ALLDONE SWAP(0x2000) /* all commands completed */
+#define IE_ST_RNR SWAP(0x1000) /* receive not ready */
+
+#define IE_CU_STATUS SWAP(0x700) /* mask for command unit status */
+#define IE_CU_ACTIVE SWAP(0x200) /* command unit is active */
+#define IE_CU_SUSPEND SWAP(0x100) /* command unit is suspended */
+
+#define IE_RU_STATUS SWAP(0x70) /* mask for receiver unit status */
+#define IE_RU_SUSPEND SWAP(0x10) /* receiver is suspended */
+#define IE_RU_NOSPACE SWAP(0x20) /* receiver has no resources */
+#define IE_RU_READY SWAP(0x40) /* reveiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ */
+struct ie_recv_frame_desc {
+ u_short ie_fd_status; /* status for this frame */
+ u_short ie_fd_last; /* end of frame list flag */
+ u_short ie_fd_next; /* 16-pointer to next RFD */
+ u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */
+ struct ie_en_addr dest; /* destination ether */
+ struct ie_en_addr src; /* source ether */
+ u_short ie_length; /* 802 length/Ether type */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_FD_LAST SWAP(0x8000) /* last rfd in list */
+#define IE_FD_SUSP SWAP(0x4000) /* suspend RU after receipt */
+
+#define IE_FD_COMPLETE SWAP(0x8000) /* frame is complete */
+#define IE_FD_BUSY SWAP(0x4000) /* frame is busy */
+#define IE_FD_OK SWAP(0x2000) /* frame is bad */
+#define IE_FD_RNR SWAP(0x0200) /* receiver out of resources here */
+
+/*
+ * linked list of buffers...
+ */
+struct ie_recv_buf_desc {
+ u_short ie_rbd_actual; /* status for this buffer */
+ u_short ie_rbd_next; /* 16-pointer to next RBD */
+ caddr_t ie_rbd_buffer; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_length; /* length of the buffer */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_RBD_LAST SWAP(0x8000) /* last buffer */
+#define IE_RBD_USED SWAP(0x4000) /* this buffer has data */
+/*
+ * All commands share this in common.
+ */
+struct ie_cmd_common {
+ u_short ie_cmd_status; /* status of this command */
+ u_short ie_cmd_cmd; /* command word */
+ u_short ie_cmd_link; /* link to next command */
+};
+
+#define IE_STAT_COMPL SWAP(0x8000) /* command is completed */
+#define IE_STAT_BUSY SWAP(0x4000) /* command is running now */
+#define IE_STAT_OK SWAP(0x2000) /* command completed successfully */
+#define IE_STAT_ABORT SWAP(0x1000) /* command was aborted */
+
+
+#define IE_CMD_NOP SWAP(0x0000) /* NOP */
+#define IE_CMD_IASETUP SWAP(0x0001) /* initial address setup */
+#define IE_CMD_CONFIG SWAP(0x0002) /* configure command */
+#define IE_CMD_MCAST SWAP(0x0003) /* multicast setup command */
+#define IE_CMD_XMIT SWAP(0x0004) /* transmit command */
+#define IE_CMD_TDR SWAP(0x0005) /* time-domain reflectometer command */
+#define IE_CMD_DUMP SWAP(0x0006) /* dump command */
+#define IE_CMD_DIAGNOSE SWAP(0x0007) /* diagnostics command */
+
+#define IE_CMD_LAST SWAP(0x8000) /* this is the last command in the list */
+#define IE_CMD_SUSPEND SWAP(0x4000) /* suspend CU after this command */
+#define IE_CMD_INTR SWAP(0x2000) /* post an interrupt after completion */
+
+/*
+ * This is the command to transmit a frame.
+ */
+struct ie_xmit_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_xmit_status com.ie_cmd_status
+
+ u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */
+ struct ie_en_addr ie_xmit_addr; /* destination address */
+
+ u_short ie_xmit_length; /* 802.3 length/Ether type field */
+};
+
+#define IE_XS_MAXCOLL SWAP(0x000f) /* number of collisions during transmit */
+#define IE_XS_EXCMAX SWAP(0x0020) /* exceeded maximum number of collisions */
+#define IE_XS_SQE SWAP(0x0040) /* SQE positive */
+#define IE_XS_DEFERRED SWAP(0x0080) /* transmission deferred */
+#define IE_XS_UNDERRUN SWAP(0x0100) /* DMA underrun */
+#define IE_XS_LOSTCTS SWAP(0x0200) /* Lost CTS */
+#define IE_XS_NOCARRIER SWAP(0x0400) /* No Carrier */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ */
+
+struct ie_xmit_buf {
+ u_short ie_xmit_flags; /* see below */
+ u_short ie_xmit_next; /* 16-pointer to next desc. */
+ caddr_t ie_xmit_buf; /* 24-pointer to the actual buffer */
+};
+
+#define IE_XMIT_LAST SWAP(0x8000) /* this TBD is the last one */
+/* The rest of the `flags' word is actually the length. */
+
+/*
+ * Multicast setup command.
+ */
+
+#define MAXMCAST 250 /* must fit in transmit buffer */
+
+struct ie_mcast_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_mcast_status com.ie_cmd_status
+
+ u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */
+ struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */
+};
+
+/*
+ * Time Domain Reflectometer command.
+ */
+
+struct ie_tdr_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_tdr_status com.ie_cmd_status
+
+ u_short ie_tdr_time; /* error bits and time */
+};
+
+#define IE_TDR_SUCCESS SWAP(0x8000) /* TDR succeeded without error */
+#define IE_TDR_XCVR SWAP(0x4000) /* detected a transceiver problem */
+#define IE_TDR_OPEN SWAP(0x2000) /* detected an open */
+#define IE_TDR_SHORT SWAP(0x1000) /* TDR detected a short */
+#define IE_TDR_TIME SWAP(0x07ff) /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ */
+struct ie_iasetup_cmd {
+ struct ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+
+ struct ie_en_addr ie_address;
+};
+
+/*
+ * Configuration command
+ */
+struct ie_config_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_config_status com.ie_cmd_status
+
+ u_char ie_config_count; /* byte count (0x0c) */
+ u_char ie_fifo; /* fifo (8) */
+ u_char ie_save_bad; /* save bad frames (0x40) */
+ u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */
+ u_char ie_priority; /* priority and backoff (0x0) */
+ u_char ie_ifs; /* inter-frame spacing (0x60) */
+ u_char ie_slot_low; /* slot time, LSB (0x0) */
+ u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */
+ u_char ie_promisc; /* 1 if promiscuous, else 0 */
+ u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */
+ u_char ie_min_len; /* min frame length (0x40) */
+ u_char ie_junk; /* stuff for 82596 (0xff) */
+};
diff --git a/sys/arch/mvme68k/dev/if_ie.c b/sys/arch/mvme68k/dev/if_ie.c
new file mode 100644
index 00000000000..e24a121d0e9
--- /dev/null
+++ b/sys/arch/mvme68k/dev/if_ie.c
@@ -0,0 +1,1958 @@
+/* $NetBSD: if_ie.c,v 1.15 1995/04/11 09:18:09 pk Exp $ */
+
+/*-
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1993, 1994, 1995 Charles Hannum.
+ * Copyright (c) 1992, 1993, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ *
+ * Portions:
+ * Copyright (c) 1994, 1995, Rafal K. Boni
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, The Regents of the University of California
+ *
+ * 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 Hannum, by the
+ * University of Vermont and State Agricultural College and Garrett A.
+ * Wollman, by William F. Jolitz, and by the University of California,
+ * Berkeley, Lawrence Berkeley Laboratory, and its contributors.
+ * 4. Neither the names of the Universities nor the names of the authors
+ * 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 UNIVERSITY OR AUTHORS 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Original StarLAN driver written by Garrett Wollman with reference to the
+ * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
+ *
+ * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
+ *
+ * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
+ *
+ * Majorly cleaned up and 3C507 code merged by Charles Hannum.
+ *
+ * Converted to SUN ie driver by Charles D. Cranor,
+ * October 1994, January 1995.
+ * This sun version based on i386 version 1.30.
+ */
+
+extern void *etherbuf;
+extern int etherlen;
+
+/*
+Mode of operation:
+
+ We run the 82586 in a standard Ethernet mode. We keep NFRAMES
+ received frame descriptors around for the receiver to use, and
+ NRXBUF associated receive buffer descriptors, both in a circular
+ list. Whenever a frame is received, we rotate both lists as
+ necessary. (The 586 treats both lists as a simple queue.) We also
+ keep a transmit command around so that packets can be sent off
+ quickly.
+
+ We configure the adapter in AL-LOC = 1 mode, which means that the
+ Ethernet/802.3 MAC header is placed at the beginning of the receive
+ buffer rather than being split off into various fields in the RFD.
+ This also means that we must include this header in the transmit
+ buffer as well.
+
+ By convention, all transmit commands, and only transmit commands,
+ shall have the I (IE_CMD_INTR) bit set in the command. This way,
+ when an interrupt arrives at ieintr(), it is immediately possible
+ to tell what precisely caused it. ANY OTHER command-sending
+ routines should run at splimp(), and should post an acknowledgement
+ to every interrupt they generate.
+
+*/
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/buf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include <vm/vm.h>
+
+/*
+ * ugly byte-order hack for SUNs
+ */
+
+#define SWAP(x) (x)
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+#include <mvme68k/dev/if_ie.h>
+#include <mvme68k/dev/i82586.h>
+
+static struct mbuf *last_not_for_us;
+vm_map_t ie_map; /* for obio */
+
+#define IED_RINT 0x01
+#define IED_TINT 0x02
+#define IED_RNR 0x04
+#define IED_CNA 0x08
+#define IED_READFRAME 0x10
+#define IED_ALL 0x1f
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+#define B_PER_F 3 /* recv buffers per frame */
+#define MXFRAMES 300 /* max number of recv frames */
+#define MXRXBUF (MXFRAMES*B_PER_F) /* number of buffers to allocate */
+#define IE_RBUF_SIZE 256 /* size of each receive buffer;
+ MUST BE POWER OF TWO */
+#define NTXBUF 2 /* number of transmit commands */
+#define IE_TBUF_SIZE ETHER_MAX_LEN /* length of transmit buffer */
+
+
+/*
+ * Ethernet status, per interface.
+ *
+ * hardware addresses/sizes to know (all KVA):
+ * sc_iobase = base of chip's 24 bit address space
+ * sc_maddr = base address of chip RAM as stored in ie_base of iscp
+ * sc_msize = size of chip's RAM
+ * sc_reg = address of card dependent registers
+ *
+ * the chip uses two types of pointers: 16 bit and 24 bit
+ * 16 bit pointers are offsets from sc_maddr/ie_base
+ * KVA(16 bit offset) = offset + sc_maddr
+ * 24 bit pointers are offset from sc_iobase in KVA
+ * KVA(24 bit address) = address + sc_iobase
+ *
+ * on the vme/multibus we have the page map to control where ram appears
+ * in the address space. we choose to have RAM start at 0 in the
+ * 24 bit address space. this means that sc_iobase == sc_maddr!
+ * to get the phyiscal address of the board's RAM you must take the
+ * top 12 bits of the physical address of the register address
+ * and or in the 4 bits from the status word as bits 17-20 (remember that
+ * the board ignores the chip's top 4 address lines).
+ * For example:
+ * if the register is @ 0xffe88000, then the top 12 bits are 0xffe00000.
+ * to get the 4 bits from the the status word just do status & IEVME_HADDR.
+ * suppose the value is "4". Then just shift it left 16 bits to get
+ * it into bits 17-20 (e.g. 0x40000). Then or it to get the
+ * address of RAM (in our example: 0xffe40000). see the attach routine!
+ *
+ * on the onboard ie interface the 24 bit address space is hardwired
+ * to be 0xff000000 -> 0xffffffff of KVA. this means that sc_iobase
+ * will be 0xff000000. sc_maddr will be where ever we allocate RAM
+ * in KVA. note that since the SCP is at a fixed address it means
+ * that we have to allocate a fixed KVA for the SCP.
+ */
+
+struct ie_softc {
+ struct device sc_dev; /* device structure */
+ struct intrhand sc_ih, sc_failih; /* interrupt info */
+ struct evcnt sc_intrcnt; /* # of interrupts, per ie */
+
+ caddr_t sc_iobase; /* KVA of base of 24 bit addr space */
+ caddr_t sc_maddr; /* KVA of base of chip's RAM (16bit addr sp.)*/
+ u_int sc_msize; /* how much RAM we have/use */
+ caddr_t sc_reg; /* KVA of car's register */
+ int sc_bustype;
+
+ struct arpcom sc_arpcom;/* system arpcom structure */
+
+ void (*reset_586)(); /* card dependent reset function */
+ void (*chan_attn)(); /* card dependent attn function */
+ void (*run_586)(); /* card depenent "go on-line" function */
+ void (*memcopy) __P((const void *, void *, u_int));
+ /* card dependent memory copy function */
+ void (*memzero) __P((void *, u_int));
+ /* card dependent memory zero function */
+
+
+ int want_mcsetup; /* mcsetup flag */
+ int promisc; /* are we in promisc mode? */
+
+ /*
+ * pointers to the 3 major control structures
+ */
+
+ volatile struct ie_sys_conf_ptr *scp;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+
+ /*
+ * pointer and size of a block of KVA where the buffers
+ * are to be allocated from
+ */
+
+ caddr_t buf_area;
+ int buf_area_sz;
+
+ /*
+ * the actual buffers (recv and xmit)
+ */
+
+ volatile struct ie_recv_frame_desc *rframes[MXFRAMES];
+ volatile struct ie_recv_buf_desc *rbuffs[MXRXBUF];
+ volatile char *cbuffs[MXRXBUF];
+ int rfhead, rftail, rbhead, rbtail;
+
+ volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF];
+ volatile struct ie_xmit_buf *xmit_buffs[NTXBUF];
+ u_char *xmit_cbuffs[NTXBUF];
+ int xmit_busy;
+ int xmit_free;
+ int xchead, xctail;
+
+ struct ie_en_addr mcast_addrs[MAXMCAST + 1];
+ int mcast_count;
+
+ int nframes; /* number of frames in use */
+ int nrxbuf; /* number of recv buffs in use */
+
+#ifdef IEDEBUG
+ int sc_debug;
+#endif
+#if NMC > 0
+ struct mcreg *sc_mc;
+#endif
+#if NPCCTWO > 0
+ struct pcctworeg *sc_pcc2;
+#endif
+};
+
+static void ie_obreset __P((struct ie_softc *));
+static void ie_obattend __P((struct ie_softc *));
+static void ie_obrun __P((struct ie_softc *));
+
+void iewatchdog __P((/* short */));
+int ieintr __P((void *));
+int iefailintr __P((void *));
+int ieinit __P((struct ie_softc *));
+int ieioctl __P((struct ifnet *, u_long, caddr_t));
+void iestart __P((struct ifnet *));
+void iereset __P((struct ie_softc *));
+static void ie_readframe __P((struct ie_softc *, int));
+static void ie_drop_packet_buffer __P((struct ie_softc *));
+static int command_and_wait __P((struct ie_softc *, int,
+ void volatile *, int));
+/*static*/ void ierint __P((struct ie_softc *));
+/*static*/ void ietint __P((struct ie_softc *));
+static int ieget __P((struct ie_softc *, struct mbuf **,
+ struct ether_header *, int *));
+static void setup_bufs __P((struct ie_softc *));
+static int mc_setup __P((struct ie_softc *, void *));
+static void mc_reset __P((struct ie_softc *));
+
+#ifdef IEDEBUG
+void print_rbd __P((volatile struct ie_recv_buf_desc *));
+
+int in_ierint = 0;
+int in_ietint = 0;
+#endif
+
+int iematch();
+void ieattach();
+
+struct cfdriver iecd = {
+ NULL, "ie", iematch, ieattach, DV_IFNET, sizeof(struct ie_softc)
+};
+
+/*
+ * address generation macros
+ * MK_24 = KVA -> 24 bit address in SUN byte order
+ * MK_16 = KVA -> 16 bit address in INTEL byte order
+ * ST_24 = store a 24 bit address in SUN byte order to INTEL byte order
+ */
+#define MK_24(base, ptr) ((caddr_t)((u_long)ptr))
+#define MK_16(base, ptr) SWAP((u_short)( ((u_long)(ptr)) - ((u_long)(base)) ))
+#define ST_24(to, from) { \
+ u_long fval = (u_long)(from); \
+ u_char *t = (u_char *)&(to), *f = (u_char *)&fval; \
+ t[0] = f[2]; t[1] = f[3]; /*t[2] = f[0]*/; t[3] = f[1]; \
+ }
+/*
+ * Here are a few useful functions. We could have done these as macros, but
+ * since we have the inline facility, it makes sense to use that instead.
+ */
+static inline void
+ie_setup_config(cmd, promiscuous, manchester)
+ volatile struct ie_config_cmd *cmd;
+ int promiscuous, manchester;
+{
+
+ cmd->ie_config_count = 0x0c;
+ cmd->ie_fifo = 8;
+ cmd->ie_save_bad = 0x40;
+ cmd->ie_addr_len = 0x2e;
+ cmd->ie_priority = 0;
+ cmd->ie_ifs = 0x60;
+ cmd->ie_slot_low = 0;
+ cmd->ie_slot_high = 0xf2;
+ cmd->ie_promisc = !!promiscuous | manchester << 2;
+ cmd->ie_crs_cdt = 0;
+ cmd->ie_min_len = 64;
+ cmd->ie_junk = 0xff;
+}
+
+static inline void
+ie_ack(sc, mask)
+ struct ie_softc *sc;
+ u_int mask;
+{
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+
+ command_and_wait(sc, scb->ie_status & mask, 0, 0);
+}
+
+int
+iematch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+ return (!badvaddr(ca->ca_vaddr, 4));
+}
+
+/*
+ * Deep Magic: reset it, then set SCP address again. Pray.
+ */
+void
+ie_obreset(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ieob *ieo = (struct ieob *) sc->sc_reg;
+ volatile int t;
+ u_long a;
+
+ a = IE_PORT_RESET;
+ ieo->porthigh = a & 0xffff;
+ t = 0; t = 1;
+ ieo->portlow = a >> 16;
+ delay(1000);
+
+ a = (u_long)pmap_extract(pmap_kernel(), (vm_offset_t)sc->scp) |
+ IE_PORT_NEWSCPADDR;
+ ieo->porthigh = a & 0xffff;
+ t = 0; t = 1;
+ ieo->portlow = a >> 16;
+ delay(1000);
+}
+
+void
+ie_obattend(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ieob *ieo = (struct ieob *) sc->sc_reg;
+
+ ieo->attn = 1;
+}
+
+void
+ie_obrun(sc)
+ struct ie_softc *sc;
+{
+}
+
+/*
+ * Taken almost exactly from Bill's if_is.c, then modified beyond recognition.
+ */
+void
+ieattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct ie_softc *sc = (void *) self;
+ struct confargs *ca = aux;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ extern void myetheraddr(u_char *); /* should be elsewhere */
+ register struct bootpath *bp;
+ int pri = ca->ca_ipl;
+ volatile struct ieob *ieo;
+ vm_offset_t pa;
+
+ sc->reset_586 = ie_obreset;
+ sc->chan_attn = ie_obattend;
+ sc->run_586 = ie_obrun;
+ sc->memcopy = bcopy;
+ sc->memzero = bzero;
+ sc->sc_msize = etherlen;
+ sc->sc_reg = ca->ca_vaddr;
+ ieo = (volatile struct ieob *) sc->sc_reg;
+
+ sc->sc_maddr = etherbuf; /* maddr = vaddr */
+ pa = pmap_extract(pmap_kernel(), (vm_offset_t)sc->sc_maddr);
+ if (pa == 0) panic("ie pmap_extract");
+ sc->sc_iobase = (caddr_t)pa; /* iobase = paddr (24 bit) */
+
+ /*printf("maddrP %x iobaseV %x\n", sc->sc_maddr, sc->sc_iobase);*/
+
+ (sc->memzero)(sc->sc_maddr, sc->sc_msize);
+ sc->iscp = (volatile struct ie_int_sys_conf_ptr *)
+ sc->sc_maddr; /* @ location zero */
+ sc->scb = (volatile struct ie_sys_ctl_block *)
+ roundup((int)sc->iscp + sizeof(struct ie_int_sys_conf_ptr), 16);
+ sc->scp = (struct ie_sys_conf_ptr *)
+ roundup((int)sc->scb + sizeof(struct ie_sys_ctl_block), 16);
+ /*printf("scpV %x iscpV %x scbV %x\n", sc->scp, sc->iscp, sc->scb);*/
+
+ sc->scp->ie_bus_use = 0; /* 16-bit */
+ ST_24(sc->scp->ie_iscp_ptr,
+ pmap_extract(pmap_kernel(), (vm_offset_t)sc->iscp));
+
+ /*printf("iscpV(%x) = iscpP(%x) -> scp.ptr@%x = val:%x\n",
+ sc->iscp, pmap_extract(pmap_kernel(), (vm_offset_t)sc->iscp),
+ &sc->scp->ie_iscp_ptr, sc->scp->ie_iscp_ptr);*/
+
+ /*
+ * rest of first page is unused (wasted!), rest of ram
+ * for buffers
+ */
+ sc->buf_area = sc->sc_maddr + NBPG;
+ sc->buf_area_sz = sc->sc_msize - NBPG;
+ myetheraddr(sc->sc_arpcom.ac_enaddr);
+
+ if (ie_setupram(sc) == 0) {
+ printf(": RAM CONFIG FAILED!\n");
+ /* XXX should reclaim resources? */
+ return;
+ }
+ ifp->if_unit = sc->sc_dev.dv_unit;
+ ifp->if_name = iecd.cd_name;
+ ifp->if_start = iestart;
+ ifp->if_ioctl = ieioctl;
+ ifp->if_watchdog = iewatchdog;
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
+
+ /* Attach the interface. */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+
+ sc->sc_bustype = ca->ca_bustype;
+
+ sc->sc_ih.ih_fn = ieintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = pri;
+ sc->sc_failih.ih_fn = iefailintr;
+ sc->sc_failih.ih_arg = sc;
+ sc->sc_failih.ih_ipl = pri;
+
+ switch (sc->sc_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ mcintr_establish(MCV_IE, &sc->sc_ih);
+ sc->sc_mc = (struct mcreg *)ca->ca_master;
+ sc->sc_mc->mc_ieirq = pri | MC_SC_SNOOP | MC_IRQ_IEN |
+ MC_IRQ_ICLR;
+ mcintr_establish(MCV_IEFAIL, &sc->sc_failih);
+ sc->sc_mc->mc_iefailirq = pri | MC_IRQ_IEN | MC_IRQ_ICLR;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ pcctwointr_establish(PCC2V_IE, &sc->sc_ih);
+ sc->sc_pcc2 = (struct pcctworeg *)ca->ca_master;
+ sc->sc_pcc2->pcc2_ieirq = pri | PCC2_SC_SNOOP |
+ PCC2_IRQ_IEN | PCC2_IRQ_ICLR;
+ pcctwointr_establish(PCC2V_IEFAIL, &sc->sc_failih);
+ sc->sc_pcc2->pcc2_iefailirq = pri | PCC2_IRQ_IEN |
+ PCC2_IRQ_ICLR;
+ break;
+#endif
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to generate
+ * an interrupt after a transmit has been started on it.
+ */
+void
+iewatchdog(unit)
+ short unit;
+{
+ struct ie_softc *sc = iecd.cd_devs[unit];
+
+ log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
+ ++sc->sc_arpcom.ac_if.if_oerrors;
+
+ iereset(sc);
+}
+
+int
+iefailintr(v)
+void *v;
+{
+ struct ie_softc *sc = v;
+
+ switch (sc->sc_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ sc->sc_mc->mc_ieirq |= MC_IRQ_ICLR; /* safe: clear irq */
+ sc->sc_mc->mc_iefailirq |= MC_IRQ_ICLR; /* clear failure */
+ sc->sc_mc->mc_ieerr = MC_IEERR_SCLR; /* reset error */
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sc->sc_pcc2->pcc2_ieirq |= PCC2_IRQ_ICLR; /* safe: clear irq */
+ sc->sc_pcc2->pcc2_iefailirq |= PCC2_IRQ_ICLR; /* clear failure */
+ sc->sc_pcc2->pcc2_ieerr = PCC2_IEERR_SCLR; /* reset error */
+ break;
+#endif
+ }
+
+ iereset(sc);
+ return (1);
+}
+
+/*
+ * What to do upon receipt of an interrupt.
+ */
+int
+ieintr(v)
+void *v;
+{
+ struct ie_softc *sc = v;
+ register u_short status;
+
+ status = sc->scb->ie_status;
+/*printf("I");*/
+
+loop:
+ /* Ack interrupts FIRST in case we receive more during the ISR. */
+ ie_ack(sc, IE_ST_WHENCE & status);
+ switch (sc->sc_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ sc->sc_mc->mc_ieirq |= MC_IRQ_ICLR; /* clear irq */
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sc->sc_pcc2->pcc2_ieirq |= PCC2_IRQ_ICLR; /* clear irq */
+ break;
+#endif
+ }
+
+ if (status & (IE_ST_RECV | IE_ST_RNR)) {
+#ifdef IEDEBUG
+ in_ierint++;
+ if (sc->sc_debug & IED_RINT)
+ printf("%s: rint\n", sc->sc_dev.dv_xname);
+#endif
+ ierint(sc);
+#ifdef IEDEBUG
+ in_ierint--;
+#endif
+ }
+
+ if (status & IE_ST_DONE) {
+#ifdef IEDEBUG
+ in_ietint++;
+ if (sc->sc_debug & IED_TINT)
+ printf("%s: tint\n", sc->sc_dev.dv_xname);
+#endif
+ ietint(sc);
+#ifdef IEDEBUG
+ in_ietint--;
+#endif
+ }
+
+ if (status & IE_ST_RNR) {
+ printf("%s: receiver not ready\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_ierrors++;
+ iereset(sc);
+ }
+
+#ifdef IEDEBUG
+ if ((status & IE_ST_ALLDONE) && (sc->sc_debug & IED_CNA))
+ printf("%s: cna\n", sc->sc_dev.dv_xname);
+#endif
+
+ if ((status = sc->scb->ie_status) & IE_ST_WHENCE)
+ goto loop;
+
+ sc->sc_intrcnt.ev_count++;
+ return 1;
+}
+
+/*
+ * Process a received-frame interrupt.
+ */
+void
+ierint(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+ int i, status;
+ static int timesthru = 1024;
+
+ i = sc->rfhead;
+ for (;;) {
+ status = sc->rframes[i]->ie_fd_status;
+
+ if ((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
+ sc->sc_arpcom.ac_if.if_ipackets++;
+ if (!--timesthru) {
+ sc->sc_arpcom.ac_if.if_ierrors +=
+ SWAP(scb->ie_err_crc) +
+ SWAP(scb->ie_err_align) +
+ SWAP(scb->ie_err_resource) +
+ SWAP(scb->ie_err_overrun);
+ scb->ie_err_crc = scb->ie_err_align =
+ scb->ie_err_resource = scb->ie_err_overrun =
+ 0;
+ timesthru = 1024;
+ }
+ ie_readframe(sc, i);
+ } else {
+ if ((status & IE_FD_RNR) != 0 &&
+ (scb->ie_status & IE_RU_READY) == 0) {
+ sc->rframes[0]->ie_fd_buf_desc =
+ MK_16(sc->sc_maddr, sc->rbuffs[0]);
+ scb->ie_recv_list =
+ MK_16(sc->sc_maddr, sc->rframes[0]);
+ command_and_wait(sc, IE_RU_START, 0, 0);
+ }
+ break;
+ }
+ i = (i + 1) % sc->nframes;
+ }
+}
+
+/*
+ * Process a command-complete interrupt. These are only generated by the
+ * transmission of frames. This routine is deceptively simple, since most of
+ * the real work is done by iestart().
+ */
+void
+ietint(sc)
+ struct ie_softc *sc;
+{
+ int status;
+
+ sc->sc_arpcom.ac_if.if_timer = 0;
+ sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ status = sc->xmit_cmds[sc->xctail]->ie_xmit_status;
+
+ if (!(status & IE_STAT_COMPL) || (status & IE_STAT_BUSY))
+ printf("ietint: command still busy!\n");
+
+ if (status & IE_STAT_OK) {
+ sc->sc_arpcom.ac_if.if_opackets++;
+ sc->sc_arpcom.ac_if.if_collisions +=
+ SWAP(status & IE_XS_MAXCOLL);
+ } else if (status & IE_STAT_ABORT) {
+ printf("%s: send aborted\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_NOCARRIER) {
+ printf("%s: no carrier\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_LOSTCTS) {
+ printf("%s: lost CTS\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_UNDERRUN) {
+ printf("%s: DMA underrun\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_EXCMAX) {
+ printf("%s: too many collisions\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_collisions += 16;
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ }
+
+ /*
+ * If multicast addresses were added or deleted while transmitting,
+ * mc_reset() set the want_mcsetup flag indicating that we should do
+ * it.
+ */
+ if (sc->want_mcsetup) {
+ mc_setup(sc, (caddr_t)sc->xmit_cbuffs[sc->xctail]);
+ sc->want_mcsetup = 0;
+ }
+
+ /* Done with the buffer. */
+ sc->xmit_free++;
+ sc->xmit_busy = 0;
+ sc->xctail = (sc->xctail + 1) % NTXBUF;
+
+ iestart(&sc->sc_arpcom.ac_if);
+}
+
+/*
+ * Compare two Ether/802 addresses for equality, inlined and unrolled for
+ * speed. I'd love to have an inline assembler version of this...
+ */
+static inline int
+ether_equal(one, two)
+ u_char *one, *two;
+{
+
+ if (one[0] != two[0] || one[1] != two[1] || one[2] != two[2] ||
+ one[3] != two[3] || one[4] != two[4] || one[5] != two[5])
+ return 0;
+ return 1;
+}
+
+/*
+ * Check for a valid address. to_bpf is filled in with one of the following:
+ * 0 -> BPF doesn't get this packet
+ * 1 -> BPF does get this packet
+ * 2 -> BPF does get this packet, but we don't
+ * Return value is true if the packet is for us, and false otherwise.
+ *
+ * This routine is a mess, but it's also critical that it be as fast
+ * as possible. It could be made cleaner if we can assume that the
+ * only client which will fiddle with IFF_PROMISC is BPF. This is
+ * probably a good assumption, but we do not make it here. (Yet.)
+ */
+static inline int
+check_eh(sc, eh, to_bpf)
+ struct ie_softc *sc;
+ struct ether_header *eh;
+ int *to_bpf;
+{
+ int i;
+
+ switch(sc->promisc) {
+ case IFF_ALLMULTI:
+ /*
+ * Receiving all multicasts, but no unicasts except those
+ * destined for us.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0); /* BPF gets this packet if anybody cares */
+#endif
+ if (eh->ether_dhost[0] & 1)
+ return 1;
+ if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) return 1;
+ return 0;
+
+ case IFF_PROMISC:
+ /*
+ * Receiving all packets. These need to be passed on to BPF.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0);
+#endif
+ /* If for us, accept and hand up to BPF */
+ if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) return 1;
+
+#if NBPFILTER > 0
+ if (*to_bpf)
+ *to_bpf = 2; /* we don't need to see it */
+#endif
+
+ /*
+ * Not a multicast, so BPF wants to see it but we don't.
+ */
+ if (!(eh->ether_dhost[0] & 1))
+ return 1;
+
+ /*
+ * If it's one of our multicast groups, accept it and pass it
+ * up.
+ */
+ for (i = 0; i < sc->mcast_count; i++) {
+ if (ether_equal(eh->ether_dhost, (u_char *)&sc->mcast_addrs[i])) {
+#if NBPFILTER > 0
+ if (*to_bpf)
+ *to_bpf = 1;
+#endif
+ return 1;
+ }
+ }
+ return 1;
+
+ case IFF_ALLMULTI | IFF_PROMISC:
+ /*
+ * Acting as a multicast router, and BPF running at the same
+ * time. Whew! (Hope this is a fast machine...)
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0);
+#endif
+ /* We want to see multicasts. */
+ if (eh->ether_dhost[0] & 1)
+ return 1;
+
+ /* We want to see our own packets */
+ if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
+ return 1;
+
+ /* Anything else goes to BPF but nothing else. */
+#if NBPFILTER > 0
+ if (*to_bpf)
+ *to_bpf = 2;
+#endif
+ return 1;
+
+ default:
+ /*
+ * Only accept unicast packets destined for us, or multicasts
+ * for groups that we belong to. For now, we assume that the
+ * '586 will only return packets that we asked it for. This
+ * isn't strictly true (it uses hashing for the multicast
+ * filter), but it will do in this case, and we want to get out
+ * of here as quickly as possible.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0);
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * We want to isolate the bits that have meaning... This assumes that
+ * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
+ * the size of the buffer, then we are screwed anyway.
+ */
+static inline int
+ie_buflen(sc, head)
+ struct ie_softc *sc;
+ int head;
+{
+
+ return (SWAP(sc->rbuffs[head]->ie_rbd_actual)
+ & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
+}
+
+static inline int
+ie_packet_len(sc)
+ struct ie_softc *sc;
+{
+ int i;
+ int head = sc->rbhead;
+ int acc = 0;
+
+ do {
+ if (!(sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef IEDEBUG
+ print_rbd(sc->rbuffs[sc->rbhead]);
+#endif
+ log(LOG_ERR, "%s: receive descriptors out of sync at %d\n",
+ sc->sc_dev.dv_xname, sc->rbhead);
+ iereset(sc);
+ return -1;
+ }
+
+ i = sc->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
+
+ acc += ie_buflen(sc, head);
+ head = (head + 1) % sc->nrxbuf;
+ } while (!i);
+
+ return acc;
+}
+
+/*
+ * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
+ * command to the chip to be executed. On the way, if we have a BPF listener
+ * also give him a copy.
+ */
+inline static void
+iexmit(sc)
+ struct ie_softc *sc;
+{
+
+#if NBPFILTER > 0
+ /*
+ * If BPF is listening on this interface, let it see the packet before
+ * we push it on the wire.
+ */
+ if (sc->sc_arpcom.ac_if.if_bpf)
+ bpf_tap(sc->sc_arpcom.ac_if.if_bpf,
+ sc->xmit_cbuffs[sc->xctail],
+ SWAP(sc->xmit_buffs[sc->xctail]->ie_xmit_flags));
+#endif
+
+/*printf("iexmit base %x cmd %x bfd %x to %x\n",
+sc->sc_maddr,
+sc->xmit_cmds[sc->xctail],
+sc->xmit_buffs[sc->xctail],
+sc->xmit_cbuffs[sc->xctail]);*/
+ sc->xmit_buffs[sc->xctail]->ie_xmit_flags |= IE_XMIT_LAST;
+ sc->xmit_buffs[sc->xctail]->ie_xmit_next = SWAP(0xffff);
+ ST_24(sc->xmit_buffs[sc->xctail]->ie_xmit_buf,
+ MK_24(sc->sc_iobase, sc->xmit_cbuffs[sc->xctail]));
+
+ sc->xmit_cmds[sc->xctail]->com.ie_cmd_link = SWAP(0xffff);
+ sc->xmit_cmds[sc->xctail]->com.ie_cmd_cmd =
+ IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST;
+
+ sc->xmit_cmds[sc->xctail]->ie_xmit_status = SWAP(0);
+ sc->xmit_cmds[sc->xctail]->ie_xmit_desc =
+ MK_16(sc->sc_maddr, sc->xmit_buffs[sc->xctail]);
+
+ sc->scb->ie_command_list =
+ MK_16(sc->sc_maddr, sc->xmit_cmds[sc->xctail]);
+ command_and_wait(sc, IE_CU_START, 0, 0);
+
+ sc->xmit_busy = 1;
+ sc->sc_arpcom.ac_if.if_timer = 5;
+}
+
+/*
+ * Read data off the interface, and turn it into an mbuf chain.
+ *
+ * This code is DRAMATICALLY different from the previous version; this
+ * version tries to allocate the entire mbuf chain up front, given the
+ * length of the data available. This enables us to allocate mbuf
+ * clusters in many situations where before we would have had a long
+ * chain of partially-full mbufs. This should help to speed up the
+ * operation considerably. (Provided that it works, of course.)
+ */
+static inline int
+ieget(sc, mp, ehp, to_bpf)
+ struct ie_softc *sc;
+ struct mbuf **mp;
+ struct ether_header *ehp;
+ int *to_bpf;
+{
+ struct mbuf *m, *top, **mymp;
+ int i;
+ int offset;
+ int totlen, resid;
+ int thismboff;
+ int head;
+
+ totlen = ie_packet_len(sc);
+ if (totlen <= 0)
+ return -1;
+
+ i = sc->rbhead;
+
+ /*
+ * Snarf the Ethernet header.
+ */
+ (sc->memcopy)((caddr_t)sc->cbuffs[i], (caddr_t)ehp, sizeof *ehp);
+
+ /*
+ * As quickly as possible, check if this packet is for us.
+ * If not, don't waste a single cycle copying the rest of the
+ * packet in.
+ * This is only a consideration when FILTER is defined; i.e., when
+ * we are either running BPF or doing multicasting.
+ */
+ if (!check_eh(sc, ehp, to_bpf)) {
+ ie_drop_packet_buffer(sc);
+ sc->sc_arpcom.ac_if.if_ierrors--; /* just this case, it's not an error */
+ return -1;
+ }
+ totlen -= (offset = sizeof *ehp);
+
+ MGETHDR(*mp, M_DONTWAIT, MT_DATA);
+ if (!*mp) {
+ ie_drop_packet_buffer(sc);
+ return -1;
+ }
+
+ m = *mp;
+ m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
+ m->m_len = MHLEN;
+ resid = m->m_pkthdr.len = totlen;
+ top = 0;
+ mymp = &top;
+
+ /*
+ * This loop goes through and allocates mbufs for all the data we will
+ * be copying in. It does not actually do the copying yet.
+ */
+ do { /* while (resid > 0) */
+ /*
+ * Try to allocate an mbuf to hold the data that we have. If
+ * we already allocated one, just get another one and stick it
+ * on the end (eventually). If we don't already have one, try
+ * to allocate an mbuf cluster big enough to hold the whole
+ * packet, if we think it's reasonable, or a single mbuf which
+ * may or may not be big enough.
+ * Got that?
+ */
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (!m) {
+ m_freem(top);
+ ie_drop_packet_buffer(sc);
+ return -1;
+ }
+ m->m_len = MLEN;
+ }
+
+ if (resid >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = min(resid, MCLBYTES);
+ } else {
+ if (resid < m->m_len) {
+ if (!top && resid + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = resid;
+ }
+ }
+ resid -= m->m_len;
+ *mymp = m;
+ mymp = &m->m_next;
+ } while (resid > 0);
+
+ resid = totlen;
+ m = top;
+ thismboff = 0;
+ head = sc->rbhead;
+
+ /*
+ * Now we take the mbuf chain (hopefully only one mbuf most of the
+ * time) and stuff the data into it. There are no possible failures at
+ * or after this point.
+ */
+ while (resid > 0) { /* while there's stuff left */
+ int thislen = ie_buflen(sc, head) - offset;
+
+ /*
+ * If too much data for the current mbuf, then fill the current
+ * one up, go to the next one, and try again.
+ */
+ if (thislen > m->m_len - thismboff) {
+ int newlen = m->m_len - thismboff;
+ (sc->memcopy)((caddr_t)(sc->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (u_int)newlen);
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, so no offset */
+ offset += newlen; /* we are now this far
+ into the packet */
+ resid -= newlen; /* so there is this much
+ left to get */
+ continue;
+ }
+
+ /*
+ * If there is more than enough space in the mbuf to hold the
+ * contents of this buffer, copy everything in, advance
+ * pointers and so on.
+ */
+ if (thislen < m->m_len - thismboff) {
+ (sc->memcopy)((caddr_t)(sc->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (u_int)thislen);
+ thismboff += thislen; /* we are this far into the mbuf */
+ resid -= thislen; /* and this much is left */
+ goto nextbuf;
+ }
+
+ /*
+ * Otherwise, there is exactly enough space to put this
+ * buffer's contents into the current mbuf. Do the combination
+ * of the above actions.
+ */
+ (sc->memcopy)((caddr_t)(sc->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (u_int)thislen);
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, start at the beginning */
+ resid -= thislen; /* and we are this far through */
+
+ /*
+ * Advance all the pointers. We can get here from either of
+ * the last two cases, but never the first.
+ */
+ nextbuf:
+ offset = 0;
+ sc->rbuffs[head]->ie_rbd_actual = SWAP(0);
+ sc->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST;
+ sc->rbhead = head = (head + 1) % sc->nrxbuf;
+ sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ sc->rbtail = (sc->rbtail + 1) % sc->nrxbuf;
+ }
+
+ /*
+ * Unless something changed strangely while we were doing the copy, we
+ * have now copied everything in from the shared memory.
+ * This means that we are done.
+ */
+ return 0;
+}
+
+/*
+ * Read frame NUM from unit UNIT (pre-cached as IE).
+ *
+ * This routine reads the RFD at NUM, and copies in the buffers from the list
+ * of RBD, then rotates the RBD and RFD lists so that the receiver doesn't
+ * start complaining. Trailers are DROPPED---there's no point in wasting time
+ * on confusing code to deal with them. Hopefully, this machine will never ARP
+ * for trailers anyway.
+ */
+static void
+ie_readframe(sc, num)
+ struct ie_softc *sc;
+ int num; /* frame number to read */
+{
+ int status;
+ struct mbuf *m = 0;
+ struct ether_header eh;
+#if NBPFILTER > 0
+ int bpf_gets_it = 0;
+#endif
+
+ status = sc->rframes[num]->ie_fd_status;
+
+ /* Immediately advance the RFD list, since we have copied ours now. */
+ sc->rframes[num]->ie_fd_status = SWAP(0);
+ sc->rframes[num]->ie_fd_last |= IE_FD_LAST;
+ sc->rframes[sc->rftail]->ie_fd_last &= ~IE_FD_LAST;
+ sc->rftail = (sc->rftail + 1) % sc->nframes;
+ sc->rfhead = (sc->rfhead + 1) % sc->nframes;
+
+ if (status & IE_FD_OK) {
+#if NBPFILTER > 0
+ if (ieget(sc, &m, &eh, &bpf_gets_it)) {
+#else
+ if (ieget(sc, &m, &eh, 0)) {
+#endif
+ sc->sc_arpcom.ac_if.if_ierrors++;
+ return;
+ }
+ }
+
+#ifdef IEDEBUG
+ if (sc->sc_debug & IED_READFRAME)
+ printf("%s: frame from ether %s type %x\n", sc->sc_dev.dv_xname,
+ ether_sprintf(eh.ether_shost), (u_int)eh.ether_type);
+#endif
+
+ if (!m)
+ return;
+
+ if (last_not_for_us) {
+ m_freem(last_not_for_us);
+ last_not_for_us = 0;
+ }
+
+#if NBPFILTER > 0
+ /*
+ * Check for a BPF filter; if so, hand it up.
+ * Note that we have to stick an extra mbuf up front, because bpf_mtap
+ * expects to have the ether header at the front.
+ * It doesn't matter that this results in an ill-formatted mbuf chain,
+ * since BPF just looks at the data. (It doesn't try to free the mbuf,
+ * tho' it will make a copy for tcpdump.)
+ */
+ if (bpf_gets_it) {
+ struct mbuf m0;
+ m0.m_len = sizeof eh;
+ m0.m_data = (caddr_t)&eh;
+ m0.m_next = m;
+
+ /* Pass it up. */
+ bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, &m0);
+ }
+ /*
+ * A signal passed up from the filtering code indicating that the
+ * packet is intended for BPF but not for the protocol machinery.
+ * We can save a few cycles by not handing it off to them.
+ */
+ if (bpf_gets_it == 2) {
+ last_not_for_us = m;
+ return;
+ }
+#endif /* NBPFILTER > 0 */
+
+ /*
+ * In here there used to be code to check destination addresses upon
+ * receipt of a packet. We have deleted that code, and replaced it
+ * with code to check the address much earlier in the cycle, before
+ * copying the data in; this saves us valuable cycles when operating
+ * as a multicast router or when using BPF.
+ */
+
+ /*
+ * Finally pass this packet up to higher layers.
+ */
+ ether_input(&sc->sc_arpcom.ac_if, &eh, m);
+}
+
+static void
+ie_drop_packet_buffer(sc)
+ struct ie_softc *sc;
+{
+ int i;
+
+ do {
+ /*
+ * This means we are somehow out of sync. So, we reset the
+ * adapter.
+ */
+ if (!(sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef IEDEBUG
+ print_rbd(sc->rbuffs[sc->rbhead]);
+#endif
+ log(LOG_ERR, "%s: receive descriptors out of sync at %d\n",
+ sc->sc_dev.dv_xname, sc->rbhead);
+ iereset(sc);
+ return;
+ }
+
+ i = sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_LAST;
+
+ sc->rbuffs[sc->rbhead]->ie_rbd_length |= IE_RBD_LAST;
+ sc->rbuffs[sc->rbhead]->ie_rbd_actual = SWAP(0);
+ sc->rbhead = (sc->rbhead + 1) % sc->nrxbuf;
+ sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ sc->rbtail = (sc->rbtail + 1) % sc->nrxbuf;
+ } while (!i);
+}
+
+
+/*
+ * Start transmission on an interface.
+ */
+void
+iestart(ifp)
+ struct ifnet *ifp;
+{
+ struct ie_softc *sc = iecd.cd_devs[ifp->if_unit];
+ struct mbuf *m0, *m;
+ u_char *buffer;
+ u_short len;
+
+/*printf("iestart\n");*/
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ return;
+
+ if (sc->xmit_free == 0) {
+ ifp->if_flags |= IFF_OACTIVE;
+ if (!sc->xmit_busy)
+ iexmit(sc);
+ return;
+ }
+
+ do {
+ IF_DEQUEUE(&sc->sc_arpcom.ac_if.if_snd, m);
+ if (!m)
+ break;
+
+ len = 0;
+ buffer = sc->xmit_cbuffs[sc->xchead];
+
+ for (m0 = m; m && (len +m->m_len) < IE_TBUF_SIZE;
+ m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+ if (m)
+ printf("%s: tbuf overflow\n", sc->sc_dev.dv_xname);
+
+ m_freem(m0);
+ len = max(len, ETHER_MIN_LEN);
+ sc->xmit_buffs[sc->xchead]->ie_xmit_flags = SWAP(len);
+
+ sc->xmit_free--;
+ sc->xchead = (sc->xchead + 1) % NTXBUF;
+ } while (sc->xmit_free > 0);
+
+ /* If we stuffed any packets into the card's memory, send now. */
+ if ((sc->xmit_free < NTXBUF) && (!sc->xmit_busy))
+ iexmit(sc);
+
+ return;
+}
+
+/*
+ * set up IE's ram space
+ */
+int
+ie_setupram(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ int s;
+
+ s = splimp();
+
+ iscp = sc->iscp;
+ (sc->memzero)((char *) iscp, sizeof *iscp);
+
+ scb = sc->scb;
+ (sc->memzero)((char *) scb, sizeof *scb);
+
+ iscp->ie_busy = 1; /* ie_busy == char */
+ iscp->ie_scb_offset = MK_16(sc->sc_maddr, scb);
+ ST_24(iscp->ie_base, sc->sc_iobase);
+
+ (sc->reset_586) (sc);
+ (sc->chan_attn) (sc);
+
+ delay(100); /* wait a while... */
+
+ if (iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+ /*
+ * Acknowledge any interrupts we may have caused...
+ */
+ ie_ack(sc, IE_ST_WHENCE);
+ splx(s);
+
+ return 1;
+}
+
+void
+iereset(sc)
+ struct ie_softc *sc;
+{
+ int s = splimp();
+
+ printf("%s: reset\n", sc->sc_dev.dv_xname);
+
+ /* Clear OACTIVE in case we're called from watchdog (frozen xmit). */
+ sc->sc_arpcom.ac_if.if_flags &= ~(IFF_UP | IFF_OACTIVE);
+ ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ /*
+ * Stop i82586 dead in its tracks.
+ */
+ if (command_and_wait(sc, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
+ printf("%s: abort commands timed out\n", sc->sc_dev.dv_xname);
+
+ if (command_and_wait(sc, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
+ printf("%s: disable commands timed out\n", sc->sc_dev.dv_xname);
+
+#ifdef notdef
+ if (!check_ie_present(sc, sc->sc_maddr, sc->sc_msize))
+ panic("ie disappeared!\n");
+#endif
+
+ sc->sc_arpcom.ac_if.if_flags |= IFF_UP;
+ ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ splx(s);
+}
+
+/*
+ * This is called if we time out.
+ */
+static void
+chan_attn_timeout(rock)
+ caddr_t rock;
+{
+
+ *(int *)rock = 1;
+}
+
+/*
+ * Send a command to the controller and wait for it to either complete
+ * or be accepted, depending on the command. If the command pointer
+ * is null, then pretend that the command is not an action command.
+ * If the command pointer is not null, and the command is an action
+ * command, wait for
+ * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
+ * to become true.
+ */
+static int
+command_and_wait(sc, cmd, pcmd, mask)
+ struct ie_softc *sc;
+ int cmd;
+ volatile void *pcmd;
+ int mask;
+{
+ volatile struct ie_cmd_common *cc = pcmd;
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+ volatile int timedout = 0;
+ extern int hz;
+
+ scb->ie_command = (u_short)cmd;
+
+ if (IE_ACTION_COMMAND(cmd) && pcmd) {
+ (sc->chan_attn)(sc);
+
+#if 0
+ /*
+ * XXX
+ * I don't think this timeout works on suns.
+ * we are at splimp() in the loop, and the timeout
+ * stuff runs at software spl (so it is masked off?).
+ */
+
+ /*
+ * According to the packet driver, the minimum timeout should
+ * be .369 seconds, which we round up to .4.
+ */
+ timeout(chan_attn_timeout, (caddr_t)&timedout, 2 * hz / 5);
+#endif
+
+ /*
+ * Now spin-lock waiting for status. This is not a very nice
+ * thing to do, but I haven't figured out how, or indeed if, we
+ * can put the process waiting for action to sleep. (We may
+ * be getting called through some other timeout running in the
+ * kernel.)
+ */
+ for (;;)
+ if ((cc->ie_cmd_status & mask) || timedout)
+ break;
+#if 0
+ untimeout(chan_attn_timeout, (caddr_t)&timedout);
+#endif
+
+ return timedout;
+ } else {
+ /*
+ * Otherwise, just wait for the command to be accepted.
+ */
+ (sc->chan_attn)(sc);
+
+ while (scb->ie_command)
+ ; /* XXX spin lock */
+
+ return 0;
+ }
+}
+
+/*
+ * Run the time-domain reflectometer.
+ */
+static void
+run_tdr(sc, cmd)
+ struct ie_softc *sc;
+ struct ie_tdr_cmd *cmd;
+{
+ int result;
+
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ cmd->ie_tdr_time = SWAP(0);
+
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK))
+ result = 0x10000; /* XXX */
+ else
+ result = cmd->ie_tdr_time;
+
+ ie_ack(sc, IE_ST_WHENCE);
+
+ if (result & IE_TDR_SUCCESS)
+ return;
+
+ if (result & 0x10000)
+ printf("%s: TDR command failed\n", sc->sc_dev.dv_xname);
+ else if (result & IE_TDR_XCVR)
+ printf("%s: transceiver problem\n", sc->sc_dev.dv_xname);
+ else if (result & IE_TDR_OPEN)
+ printf("%s: TDR detected an open %d clocks away\n",
+ sc->sc_dev.dv_xname, result & IE_TDR_TIME);
+ else if (result & IE_TDR_SHORT)
+ printf("%s: TDR detected a short %d clocks away\n",
+ sc->sc_dev.dv_xname, result & IE_TDR_TIME);
+ else
+ printf("%s: TDR returned unknown status %x\n",
+ sc->sc_dev.dv_xname, result);
+}
+
+#ifdef notdef
+/* ALIGN works on 8 byte boundaries.... but 4 byte boundaries are ok for sun */
+#define _ALLOC(p, n) (bzero(p, n), p += n, p - n)
+#define ALLOC(p, n) _ALLOC(p, ALIGN(n)) /* XXX convert to this? */
+#endif
+
+static inline caddr_t
+Align(ptr)
+ caddr_t ptr;
+{
+ u_long l = (u_long)ptr;
+
+ l = (l + 3) & ~3L;
+ return (caddr_t)l;
+}
+
+/*
+ * setup_bufs: set up the buffers
+ *
+ * we have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
+ * this is to be used for the buffers. the chip indexs its control data
+ * structures with 16 bit offsets, and it indexes actual buffers with
+ * 24 bit addresses. so we should allocate control buffers first so that
+ * we don't overflow the 16 bit offset field. The number of transmit
+ * buffers is fixed at compile time.
+ *
+ * note: this function was written to be easy to understand, rather than
+ * highly efficient (it isn't in the critical path).
+ */
+static void
+setup_bufs(sc)
+ struct ie_softc *sc;
+{
+ caddr_t ptr = sc->buf_area; /* memory pool */
+ volatile struct ie_recv_frame_desc *rfd = (void *) ptr;
+ volatile struct ie_recv_buf_desc *rbd;
+ int n, r;
+
+ /*
+ * step 0: zero memory and figure out how many recv buffers and
+ * frames we can have. XXX CURRENTLY HARDWIRED AT MAX
+ */
+ (sc->memzero)(ptr, sc->buf_area_sz);
+ ptr = Align(ptr); /* set alignment and stick with it */
+
+ n = (int)Align(sizeof(struct ie_xmit_cmd)) +
+ (int)Align(sizeof(struct ie_xmit_buf)) + IE_TBUF_SIZE;
+ n *= NTXBUF; /* n = total size of xmit area */
+
+ n = sc->buf_area_sz - n;/* n = free space for recv stuff */
+
+ r = (int)Align(sizeof(struct ie_recv_frame_desc)) +
+ (((int)Align(sizeof(struct ie_recv_buf_desc)) + IE_RBUF_SIZE) * B_PER_F);
+
+ /* r = size of one R frame */
+
+ sc->nframes = n / r;
+ if (sc->nframes <= 0)
+ panic("ie: bogus buffer calc\n");
+ if (sc->nframes > MXFRAMES)
+ sc->nframes = MXFRAMES;
+
+ sc->nrxbuf = sc->nframes * B_PER_F;
+
+#ifdef IEDEBUG
+ printf("IEDEBUG: %d frames %d bufs\n", sc->nframes, sc->nrxbuf);
+#endif
+
+ /*
+ * step 1a: lay out and zero frame data structures for transmit and recv
+ */
+ for (n = 0; n < NTXBUF; n++) {
+ sc->xmit_cmds[n] = (volatile struct ie_xmit_cmd *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_xmit_cmd));
+ }
+
+ for (n = 0; n < sc->nframes; n++) {
+ sc->rframes[n] = (volatile struct ie_recv_frame_desc *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_recv_frame_desc));
+ }
+
+ /*
+ * step 1b: link together the recv frames and set EOL on last one
+ */
+ for (n = 0; n < sc->nframes; n++) {
+ sc->rframes[n]->ie_fd_next =
+ MK_16(sc->sc_maddr, sc->rframes[(n + 1) % sc->nframes]);
+ }
+ sc->rframes[sc->nframes - 1]->ie_fd_last |= IE_FD_LAST;
+
+ /*
+ * step 2a: lay out and zero frame buffer structures for xmit and recv
+ */
+ for (n = 0; n < NTXBUF; n++) {
+ sc->xmit_buffs[n] = (volatile struct ie_xmit_buf *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_xmit_buf));
+ }
+
+ for (n = 0; n < sc->nrxbuf; n++) {
+ sc->rbuffs[n] = (volatile struct ie_recv_buf_desc *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_recv_buf_desc));
+ }
+
+ /*
+ * step 2b: link together recv bufs and set EOL on last one
+ */
+ for (n = 0; n < sc->nrxbuf; n++) {
+ sc->rbuffs[n]->ie_rbd_next =
+ MK_16(sc->sc_maddr, sc->rbuffs[(n + 1) % sc->nrxbuf]);
+ }
+ sc->rbuffs[sc->nrxbuf - 1]->ie_rbd_length |= IE_RBD_LAST;
+
+ /*
+ * step 3: allocate the actual data buffers for xmit and recv
+ * recv buffer gets linked into recv_buf_desc list here
+ */
+ for (n = 0; n < NTXBUF; n++) {
+ sc->xmit_cbuffs[n] = (u_char *) ptr;
+ ptr = Align(ptr + IE_TBUF_SIZE);
+ }
+
+ /* Pointers to last packet sent and next available transmit buffer. */
+ sc->xchead = sc->xctail = 0;
+
+ /* Clear transmit-busy flag and set number of free transmit buffers. */
+ sc->xmit_busy = 0;
+ sc->xmit_free = NTXBUF;
+
+ for (n = 0; n < sc->nrxbuf; n++) {
+ sc->cbuffs[n] = (char *) ptr; /* XXX why char vs uchar? */
+ sc->rbuffs[n]->ie_rbd_length = SWAP(IE_RBUF_SIZE);
+ ST_24(sc->rbuffs[n]->ie_rbd_buffer, MK_24(sc->sc_iobase, ptr));
+ ptr = Align(ptr + IE_RBUF_SIZE);
+ }
+
+ /*
+ * step 4: set the head and tail pointers on receive to keep track of
+ * the order in which RFDs and RBDs are used. link in recv frames
+ * and buffer into the scb.
+ */
+
+ sc->rfhead = 0;
+ sc->rftail = sc->nframes - 1;
+ sc->rbhead = 0;
+ sc->rbtail = sc->nrxbuf - 1;
+
+ sc->scb->ie_recv_list = MK_16(sc->sc_maddr, sc->rframes[0]);
+ sc->rframes[0]->ie_fd_buf_desc = MK_16(sc->sc_maddr, sc->rbuffs[0]);
+
+#ifdef IEDEBUG
+ printf("IE_DEBUG: reserved %d bytes\n", ptr - sc->buf_area);
+#endif
+}
+
+/*
+ * Run the multicast setup command.
+ * Called at splimp().
+ */
+static int
+mc_setup(sc, ptr)
+ struct ie_softc *sc;
+ void *ptr;
+{
+ volatile struct ie_mcast_cmd *cmd = ptr;
+
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ (sc->memcopy)((caddr_t)sc->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
+ sc->mcast_count * sizeof *sc->mcast_addrs);
+
+ cmd->ie_mcast_bytes =
+ SWAP(sc->mcast_count * ETHER_ADDR_LEN); /* grrr... */
+
+ sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("%s: multicast address setup command failed\n",
+ sc->sc_dev.dv_xname);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This routine takes the environment generated by check_ie_present() and adds
+ * to it all the other structures we need to operate the adapter. This
+ * includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands, starting
+ * the receiver unit, and clearing interrupts.
+ *
+ * THIS ROUTINE MUST BE CALLED AT splimp() OR HIGHER.
+ */
+int
+ieinit(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+ void *ptr;
+ int n;
+
+ ptr = sc->buf_area;
+
+ /*
+ * Send the configure command first.
+ */
+ {
+ volatile struct ie_config_cmd *cmd = ptr;
+
+ scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ ie_setup_config(cmd, sc->promisc, 0);
+
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("%s: configure command failed\n",
+ sc->sc_dev.dv_xname);
+ return 0;
+ }
+ }
+
+ /*
+ * Now send the Individual Address Setup command.
+ */
+ {
+ volatile struct ie_iasetup_cmd *cmd = ptr;
+
+ scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ (sc->memcopy)(sc->sc_arpcom.ac_enaddr,
+ (caddr_t)&cmd->ie_address, sizeof cmd->ie_address);
+
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("%s: individual address setup command failed\n",
+ sc->sc_dev.dv_xname);
+ return 0;
+ }
+ }
+
+ /*
+ * Now run the time-domain reflectometer.
+ */
+ run_tdr(sc, ptr);
+
+ /*
+ * Acknowledge any interrupts we have generated thus far.
+ */
+ ie_ack(sc, IE_ST_WHENCE);
+
+ /*
+ * Set up the transmit and recv buffers.
+ */
+ setup_bufs(sc);
+
+ sc->sc_arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */
+
+ sc->scb->ie_recv_list = MK_16(sc->sc_maddr, sc->rframes[0]);
+ command_and_wait(sc, IE_RU_START, 0, 0);
+
+ ie_ack(sc, IE_ST_WHENCE);
+
+ if (sc->run_586)
+ (sc->run_586)(sc);
+
+ return 0;
+}
+
+static void
+iestop(sc)
+ struct ie_softc *sc;
+{
+
+ command_and_wait(sc, IE_RU_DISABLE, 0, 0);
+}
+
+int
+ieioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ie_softc *sc = iecd.cd_devs[ifp->if_unit];
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ieinit(sc);
+ arp_ifinit(&sc->sc_arpcom, ifa);
+ break;
+#endif
+#ifdef NS
+ /* XXX - This code is probably wrong. */
+ case AF_NS:
+ {
+ struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
+ else
+ bcopy(ina->x_host.c_host,
+ sc->sc_arpcom.ac_enaddr,
+ sizeof(sc->sc_arpcom.ac_enaddr));
+ /* Set new address. */
+ ieinit(sc);
+ break;
+ }
+#endif /* NS */
+ default:
+ ieinit(sc);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running, then
+ * stop it.
+ */
+ iestop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ ieinit(sc);
+ } else {
+ /*
+ * Reset the interface to pick up changes in any other
+ * flags that affect hardware registers.
+ */
+ iestop(sc);
+ ieinit(sc);
+ }
+#ifdef IEDEBUG
+ if (ifp->if_flags & IFF_DEBUG)
+ sc->sc_debug = IED_ALL;
+ else
+ sc->sc_debug = 0;
+#endif
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_arpcom):
+ ether_delmulti(ifr, &sc->sc_arpcom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ mc_reset(sc);
+ error = 0;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return error;
+}
+
+static void
+mc_reset(sc)
+ struct ie_softc *sc;
+{
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ /*
+ * Step through the list of addresses.
+ */
+ sc->mcast_count = 0;
+ ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
+ while (enm) {
+ if (sc->mcast_count >= MAXMCAST ||
+ bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ sc->sc_arpcom.ac_if.if_flags |= IFF_ALLMULTI;
+ ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
+ goto setflag;
+ }
+
+ bcopy(enm->enm_addrlo, &sc->mcast_addrs[sc->mcast_count], 6);
+ sc->mcast_count++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+setflag:
+ sc->want_mcsetup = 1;
+}
+
+#ifdef IEDEBUG
+void
+print_rbd(rbd)
+ volatile struct ie_recv_buf_desc *rbd;
+{
+
+ printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
+ "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
+ rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
+ rbd->mbz);
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/if_ie.h b/sys/arch/mvme68k/dev/if_ie.h
new file mode 100644
index 00000000000..a17de666905
--- /dev/null
+++ b/sys/arch/mvme68k/dev/if_ie.h
@@ -0,0 +1,191 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * XXX where else is this from?
+ * if_sunie.h
+ *
+ * sun's ie interface
+ */
+
+/*
+ * programming notes:
+ *
+ * the ie chip operates in a 24 bit address space.
+ *
+ * most ie interfaces appear to be divided into two parts:
+ * - generic 586 stuff
+ * - board specific
+ *
+ * generic:
+ * the generic stuff of the ie chip is all done with data structures
+ * that live in the chip's memory address space. the chip expects
+ * its main data structure (the sys conf ptr -- SCP) to be at a fixed
+ * address in its 24 bit space: 0xfffff4
+ *
+ * the SCP points to another structure called the ISCP.
+ * the ISCP points to another structure called the SCB.
+ * the SCB has a status field, a linked list of "commands", and
+ * a linked list of "receive buffers". these are data structures that
+ * live in memory, not registers.
+ *
+ * board:
+ * to get the chip to do anything, you first put a command in the
+ * command data structure list. then you have to signal "attention"
+ * to the chip to get it to look at the command. how you
+ * signal attention depends on what board you have... on PC's
+ * there is an i/o port number to do this, on sun's there is a
+ * register bit you toggle.
+ *
+ * to get data from the chip you program it to interrupt...
+ *
+ *
+ * sun issues:
+ *
+ * there are 3 kinds of sun "ie" interfaces:
+ * 1 - a VME/multibus card
+ * 2 - an on-board interface (sun3's, sun-4/100's, and sun-4/200's)
+ * 3 - another VME board called the 3E
+ *
+ * the VME boards lives in vme16 space. only 16 and 8 bit accesses
+ * are allowed, so functions that copy data must be aware of this.
+ *
+ * the chip is an intel chip. this means that the byte order
+ * on all the "short"s in the chip's data structures is wrong.
+ * so, constants described in the intel docs are swapped for the sun.
+ * that means that any buffer pointers you give the chip must be
+ * swapped to intel format. yuck.
+ *
+ * VME/multibus interface:
+ * for the multibus interface the board ignores the top 4 bits
+ * of the chip address. the multibus interface seems to have its
+ * own MMU like page map (without protections or valid bits, etc).
+ * there are 256 pages of physical memory on the board (each page
+ * is 1024 bytes). there are 1024 slots in the page map. so,
+ * a 1024 byte page takes up 10 bits of address for the offset,
+ * and if there are 1024 slots in the page that is another 10 bits
+ * of the address. that makes a 20 bit address, and as stated
+ * earlier the board ignores the top 4 bits, so that accounts
+ * for all 24 bits of address.
+ *
+ * note that the last entry of the page map maps the top of the
+ * 24 bit address space and that the SCP is supposed to be at
+ * 0xfffff4 (taking into account allignment). so,
+ * for multibus, that entry in the page map has to be used for the SCP.
+ *
+ * the page map effects BOTH how the ie chip sees the
+ * memory, and how the host sees it.
+ *
+ * the page map is part of the "register" area of the board
+ *
+ * on-board interface:
+ *
+ * <fill in useful info later>
+ *
+ *
+ * VME3E interface:
+ *
+ * <fill in useful info later>
+ *
+ */
+
+/*
+ * PART 1: VME/multibus defs
+ */
+#define IEVME_PAGESIZE 1024 /* bytes */
+#define IEVME_PAGSHIFT 10 /* bits */
+#define IEVME_NPAGES 256 /* number of pages on chip */
+#define IEVME_MAPSZ 1024 /* number of entries in the map */
+
+/*
+ * PTE for the page map
+ */
+#define IEVME_SBORDR 0x8000 /* sun byte order */
+#define IEVME_IBORDR 0x0000 /* intel byte ordr */
+
+#define IEVME_P2MEM 0x2000 /* memory is on P2 */
+#define IEVME_OBMEM 0x0000 /* memory is on board */
+
+#define IEVME_PGMASK 0x0fff /* gives the physical page frame number */
+
+struct ievme {
+ u_short pgmap[IEVME_MAPSZ];
+ u_short xxx[32]; /* prom */
+ u_short status; /* see below for bits */
+ u_short xxx2; /* filler */
+ u_short pectrl; /* parity control (see below) */
+ u_short peaddr; /* low 16 bits of address */
+};
+
+/*
+ * status bits
+ */
+#define IEVME_RESET 0x8000 /* reset board */
+#define IEVME_ONAIR 0x4000 /* go out of loopback 'on-air' */
+#define IEVME_ATTEN 0x2000 /* attention */
+#define IEVME_IENAB 0x1000 /* interrupt enable */
+#define IEVME_PEINT 0x0800 /* parity error interrupt enable */
+#define IEVME_PERR 0x0200 /* parity error flag */
+#define IEVME_INT 0x0100 /* interrupt flag */
+#define IEVME_P2EN 0x0020 /* enable p2 bus */
+#define IEVME_256K 0x0010 /* 256kb rams */
+#define IEVME_HADDR 0x000f /* mask for bits 17-20 of address */
+
+/*
+ * parity control
+ */
+#define IEVME_PARACK 0x0100 /* parity error ack */
+#define IEVME_PARSRC 0x0080 /* parity error source */
+#define IEVME_PAREND 0x0040 /* which end of the data got the error */
+#define IEVME_PARADR 0x000f /* mask to get bits 17-20 of parity address */
+
+
+/*
+ * PART 2: the on-board interface
+ */
+struct ieob {
+ u_short porthigh;
+ u_short portlow;
+ u_long attn;
+};
+#define IE_PORT_NEWSCPADDR 0x00000002
+#define IE_PORT_RESET 0x00000000
+
+#define IEOB_ADBASE 0xff000000 /* KVA base addr of 24 bit address space */
+
+/*
+ * PART 3: the 3E board
+ */
+
+/*
+ * not supported (yet?)
+ */
diff --git a/sys/arch/mvme68k/dev/ipic.c b/sys/arch/mvme68k/dev/ipic.c
new file mode 100644
index 00000000000..400f57b25ba
--- /dev/null
+++ b/sys/arch/mvme68k/dev/ipic.c
@@ -0,0 +1,195 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/ipicreg.h>
+#include <mvme68k/dev/mcreg.h>
+
+void ipicattach __P((struct device *, struct device *, void *));
+int ipicmatch __P((struct device *, void *, void *));
+
+struct cfdriver ipiccd = {
+ NULL, "ipic", ipicmatch, ipicattach,
+ DV_DULL, sizeof(struct ipicsoftc), 0
+};
+
+int
+ipicmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct ipicreg *ipic = (struct ipicreg *)ca->ca_vaddr;
+
+ if (badvaddr(ipic, 1) || ipic->ipic_chipid != IPIC_CHIPID)
+ return (0);
+ return (1);
+}
+
+int
+ipicprint(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ printf(" slot %d", ca->ca_offset);
+ if (ca->ca_vec > 0)
+ printf(" vec %d", ca->ca_vec);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+ipicscan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ struct cfdata *cf = child;
+ struct ipicsoftc *sc = (struct ipicsoftc *)parent;
+ register struct confargs *ca = args;
+ struct confargs oca;
+ int slot, n = 0;
+ caddr_t ipv, ipp;
+ struct ipid *ipid;
+
+#if 0
+/* XXX all these are indirect!! how to fix? */
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+#endif
+
+ /* XXX can we determing IPIC_IPSPACE automatically? */
+ for (slot = 0; slot < sc->sc_nip; slot++) {
+ ipp = sc->sc_ipspace + (slot * IPIC_IP_MODSIZE);
+ if (badpaddr(ipp + IPIC_IP_IDOFFSET, 2))
+ continue;
+
+ ipv = mapiodev(ipp, NBPG);
+ if (ipv == NULL)
+ continue;
+
+ ipid = (struct ipid *)(ipv + IPIC_IP_IDOFFSET);
+ if (ipid->ipid_A != 'A' || ipid->ipid_P != 'P' ||
+ ipid->ipid_I != 'I' || ipid->ipid_C != 'C' ||
+ (u_char)cf->cf_loc[0] != ipid->ipid_manu ||
+ (u_char)cf->cf_loc[1] != ipid->ipid_prod) {
+ unmapiodev(ipv, NBPG);
+ continue;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_bustype = BUS_IP;
+ oca.ca_offset = slot; /* slot number */
+ oca.ca_paddr = ipp;
+ oca.ca_vaddr = ipv;
+ oca.ca_len = NBPG;
+ oca.ca_ipl = cf->cf_loc[2];
+ oca.ca_vec = cf->cf_loc[3];
+ if (oca.ca_ipl > 0 && oca.ca_vec == -1)
+ oca.ca_vec = intr_freevec();
+
+ oca.ca_master = (void *)sc;
+ oca.ca_name = cf->cf_driver->cd_name;
+
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0) {
+ unmapiodev(ipv, NBPG);
+ continue;
+ }
+ config_attach(parent, cf, &oca, ipicprint);
+ n++;
+ }
+ return (n);
+}
+
+void
+ipicattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct ipicsoftc *sc = (struct ipicsoftc *)self;
+ struct confargs *ca = args;
+
+ sc->sc_ipic = (struct ipicreg *)ca->ca_vaddr;
+ sc->sc_ipspace = (caddr_t)IPIC_IPSPACE;
+ sc->sc_nip = 2;
+
+ printf(": rev %d\n", sc->sc_ipic->ipic_chiprev);
+
+ sc->sc_ipic->ipic_reset = IPIC_RESET;
+ delay(2);
+
+ config_search(ipicscan, self, args);
+}
+
+caddr_t
+ipicmap(sc, addr, len)
+ struct ipicsoftc *sc;
+ caddr_t addr;
+ int len;
+{
+ return (NULL);
+}
+
+void
+ipicunmap(sc, addr, len)
+ struct ipicsoftc *sc;
+ caddr_t addr;
+ int len;
+{
+}
+
+int
+ipicintr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ return (intr_establish(vec, ih));
+}
diff --git a/sys/arch/mvme68k/dev/ipicreg.h b/sys/arch/mvme68k/dev/ipicreg.h
new file mode 100644
index 00000000000..b329a7342f9
--- /dev/null
+++ b/sys/arch/mvme68k/dev/ipicreg.h
@@ -0,0 +1,114 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+struct ipicreg {
+ volatile u_char ipic_chipid;
+#define IPIC_CHIPID 0x23
+ volatile u_char ipic_chiprev;
+ volatile u_char x0[2];
+ volatile u_short ipic_base[4]; /* [slot] */
+ volatile u_char ipic_size[4]; /* [slot] */
+ volatile u_char ipic_irq[4][2]; /* [slot][irq#] */
+#define IPIC_IRQ_PLTY 0x80 /* 1 = rising edge activated */
+#define IPIC_IRQ_EL 0x40 /* 1 = edge, 0 = level sensitive */
+#define IPIC_IRQ_INT 0x20 /* interrupt is active */
+#define IPIC_IRQ_IEN 0x10 /* enable interrupt */
+#define IPIC_IRQ_ICLR 0x08 /* clear interrupt */
+#define IPIC_IRQ_IPLMASK 0x07
+ volatile u_char ipic_ctl[4]; /* [slot] */
+#define IPIC_CTL_ERR 0x80 /* error from IP module */
+#define IPIC_CTL_RTMASK 0x30 /* recovery time, measured in ms */
+#define IPIC_CTL_RT0MS 0x00
+#define IPIC_CTL_RT2MS 0x10
+#define IPIC_CTL_RT4MS 0x20
+#define IPIC_CTL_RT8MS 0x30
+#define IPIC_CTL_WIDTHMASK 0x0c /* bus width */
+#define IPIC_CTL_WIDTH32 0x00
+#define IPIC_CTL_WIDTH8 0x04
+#define IPIC_CTL_WIDTH16 0x08
+#define IPIC_CTL_MEN 0x01 /* ??? */
+ volatile u_char x1[3];
+ volatile u_char ipic_reset;
+#define IPIC_RESET 0x01 /* bit clears automatically after 1ms */
+};
+
+/*
+ * the following macros convert the size in bytes to/from the
+ * ipic_Xsize reg values. you should ensure your size in bytes
+ * is a legal value, which are 16K, or all the powers of 2 from
+ * 64K to 8M.
+ */
+#define IPIC_SIZE_BTOR(x) \
+ (((x) == 16*1024) ? (0xff) : (((x) / 64*1024) - 1))
+#define IPIC_SIZE_RTOB(x) \
+ (((x) == 0xff) ? (16*1024) : (((x) + 1) * 64*1024))
+
+struct ipid {
+ volatile u_char ipid_I; /* must be 'I' */
+ volatile u_char :8;
+ volatile u_char ipid_P; /* must be 'P' */
+ volatile u_char :8;
+ volatile u_char ipid_A; /* must be 'A' */
+ volatile u_char :8;
+ volatile u_char ipid_C; /* must be 'C' */
+ volatile u_char :8;
+ volatile u_char ipid_manu;
+ volatile u_char :8;
+ volatile u_char ipid_prod;
+ volatile u_char :8;
+ volatile u_char ipid_rev;
+ volatile u_char :8;
+ volatile u_char ipid_zero;
+ volatile u_char :8;
+ volatile u_char ipid_didl;
+ volatile u_char :8;
+ volatile u_char ipid_didh;
+ volatile u_char :8;
+ volatile u_char ipid_pspecn; /* # shorts in pack-spec id */
+ volatile u_char :8;
+ volatile u_char ipid_crc;
+ volatile u_char :8;
+ volatile u_char ipic_pspecbase; /* start of pack-spec id */
+};
+
+#define IPIC_IPSPACE 0xfff58000
+#define IPIC_IP_MODSIZE 0x00000100
+#define IPIC_IP_IDOFFSET 0x80
+#define IPIC_IP_REGOFFSET 0x00
+
+struct ipicsoftc {
+ struct device sc_dev;
+ struct ipicreg *sc_ipic;
+
+ caddr_t sc_ipspace;
+ int sc_nip;
+};
diff --git a/sys/arch/mvme68k/dev/lp.c b/sys/arch/mvme68k/dev/lp.c
new file mode 100644
index 00000000000..77f02834c2a
--- /dev/null
+++ b/sys/arch/mvme68k/dev/lp.c
@@ -0,0 +1,144 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/pccreg.h>
+
+struct lpsoftc {
+ struct device sc_dev;
+ struct intrhand sc_ih;
+ struct pccreg *sc_pcc;
+};
+
+void lpattach __P((struct device *, struct device *, void *));
+int lpmatch __P((struct device *, void *, void *));
+
+struct cfdriver lpcd = {
+ NULL, "lp", lpmatch, lpattach,
+ DV_DULL, sizeof(struct lpsoftc), 0
+};
+
+int lpintr __P((void *));
+
+/*
+ * a PCC chip always has an lp attached to it.
+ */
+int
+lpmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ return (1);
+}
+
+void
+lpattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct lpsoftc *sc = (struct lpsoftc *)self;
+ struct confargs *ca = args;
+
+ sc->sc_pcc = (struct pccreg *)ca->ca_master;
+
+ printf(": unsupported\n");
+
+ sc->sc_ih.ih_fn = lpintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+ pccintr_establish(PCCV_PRINTER, &sc->sc_ih);
+
+ sc->sc_pcc->pcc_lpirq = ca->ca_ipl | PCC_IRQ_IEN | PCC_LPIRQ_ACK;
+}
+
+int
+lpintr(dev)
+ void *dev;
+{
+ struct lpsoftc *sc = dev;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+lpopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+lpclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+lpwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+}
+
+lpioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+}
+
diff --git a/sys/arch/mvme68k/dev/mc.c b/sys/arch/mvme68k/dev/mc.c
new file mode 100644
index 00000000000..1c7dc2889d1
--- /dev/null
+++ b/sys/arch/mvme68k/dev/mc.c
@@ -0,0 +1,217 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * VME162 MCchip
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+
+#include <mvme68k/dev/mcreg.h>
+
+struct mcsoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr;
+ caddr_t sc_paddr;
+ struct mcreg *sc_mc;
+ struct intrhand sc_nmiih;
+};
+
+void mcattach __P((struct device *, struct device *, void *));
+int mcmatch __P((struct device *, void *, void *));
+int mcabort __P((struct frame *));
+
+struct cfdriver mccd = {
+ NULL, "mc", mcmatch, mcattach,
+ DV_DULL, sizeof(struct mcsoftc), 0
+};
+
+struct mcreg *sys_mc = NULL;
+
+int
+mcmatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+ struct mcreg *mc = (struct mcreg *)(IIOV(ca->ca_paddr) + MC_MCCHIP_OFF);
+
+ if (cputyp != CPU_162 || badvaddr(mc, 1) ||
+ mc->mc_chipid != MC_CHIPID)
+ return (0);
+ return (1);
+}
+
+int
+mc_print(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ if (ca->ca_offset != -1)
+ printf(" offset 0x%x", ca->ca_offset);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+mc_scan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ struct cfdata *cf = child;
+ struct mcsoftc *sc = (struct mcsoftc *)parent;
+ struct confargs *ca = args;
+ struct confargs oca;
+
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_offset = cf->cf_loc[0];
+ oca.ca_ipl = cf->cf_loc[1];
+ if (oca.ca_offset != -1 && ISIIOVA(sc->sc_vaddr + oca.ca_offset)) {
+ oca.ca_paddr = sc->sc_paddr + oca.ca_offset;
+ oca.ca_vaddr = sc->sc_vaddr + oca.ca_offset;
+ } else {
+ oca.ca_paddr = (caddr_t)-1;
+ oca.ca_vaddr = (caddr_t)-1;
+ }
+ oca.ca_bustype = BUS_MC;
+ oca.ca_master = (void *)sc->sc_mc;
+ oca.ca_name = cf->cf_driver->cd_name;
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0)
+ return (0);
+ config_attach(parent, cf, &oca, mc_print);
+ return (1);
+}
+
+void
+mcattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct mcsoftc *sc = (struct mcsoftc *)self;
+ int i;
+
+ if (sys_mc)
+ panic("mc already attached!");
+
+ /*
+ * since we know ourself to land in intiobase land,
+ * we must adjust our address
+ */
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = (caddr_t)IIOV(sc->sc_paddr);
+ sc->sc_mc = (struct mcreg *)(sc->sc_vaddr + MC_MCCHIP_OFF);
+ sys_mc = sc->sc_mc;
+
+ printf(": rev %d\n", sc->sc_mc->mc_chiprev);
+
+ sc->sc_nmiih.ih_fn = mcabort;
+ sc->sc_nmiih.ih_arg = 0;
+ sc->sc_nmiih.ih_ipl = 7;
+ sc->sc_nmiih.ih_wantframe = 1;
+ mcintr_establish(MCV_ABORT, &sc->sc_nmiih);
+
+ sc->sc_mc->mc_abortirq = 7 | MC_IRQ_IEN | MC_IRQ_ICLR;
+ sc->sc_mc->mc_vecbase = MC_VECBASE;
+
+ sc->sc_mc->mc_genctl |= MC_GENCTL_IEN; /* global irq enable */
+
+ config_search(mc_scan, self, args);
+}
+
+/*
+ * MC interrupts land in a MC_NVEC sized hole starting at MC_VECBASE
+ */
+int
+mcintr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ if (vec >= MC_NVEC) {
+ printf("mc: illegal vector: 0x%x\n", vec);
+ panic("mcintr_establish");
+ }
+ return (intr_establish(MC_VECBASE+vec, ih));
+}
+
+int
+mcabort(frame)
+ struct frame *frame;
+{
+ /* wait for it to debounce */
+ while (sys_mc->mc_abortirq & MC_ABORT_ABS)
+ ;
+
+ sys_mc->mc_abortirq = sys_mc->mc_abortirq | MC_IRQ_ICLR;
+
+ nmihand(frame);
+ return (1);
+}
+
+#include "flash.h"
+
+#if NFLASH > 0
+void
+mc_enableflashwrite(on)
+ int on;
+{
+ struct mcsoftc *sc = (struct mcsoftc *) mccd.cd_devs[0];
+ volatile char *ena, x;
+
+ ena = sc->sc_vaddr +
+ (on ? MC_ENAFLASHWRITE_OFFSET : MC_DISFLASHWRITE_OFFSET);
+ x = *ena;
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/mcreg.h b/sys/arch/mvme68k/dev/mcreg.h
new file mode 100644
index 00000000000..ead6d812d0f
--- /dev/null
+++ b/sys/arch/mvme68k/dev/mcreg.h
@@ -0,0 +1,164 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * VME162 MCchip
+ */
+struct mcreg {
+ volatile u_char mc_chipid;
+ volatile u_char mc_chiprev;
+ volatile u_char mc_genctl;
+ volatile u_char mc_vecbase;
+ volatile u_long mc_t1cmp;
+ volatile u_long mc_t1count;
+ volatile u_long mc_t2cmp;
+ volatile u_long mc_t2count;
+ volatile u_char mc_lsbprescale;
+ volatile u_char mc_adjprescale;
+ volatile u_char mc_t2ctl;
+ volatile u_char mc_t1ctl;
+ volatile u_char mc_t4irq;
+ volatile u_char mc_t3irq;
+ volatile u_char mc_t2irq;
+ volatile u_char mc_t1irq;
+ volatile u_char mc_parity;
+ volatile u_char mc_zsirq;
+ volatile u_char mc_t4ctl;
+ volatile u_char mc_t3ctl;
+ volatile u_short mc_drambase;
+ volatile u_short mc_srambase;
+ volatile u_char mc_dramsize;
+ volatile u_char mc_memoptions;
+#define MC_MEMOPTIONS_SRAMMASK 0x18
+#define MC_MEMOPTIONS_SRAM128K 0x00
+#define MC_MEMOPTIONS_SRAM512K 0x08
+#define MC_MEMOPTIONS_SRAM1M 0x10
+#define MC_MEMOPTIONS_SRAM2M 0x18
+#define MC_MEMOPTIONS_DRAMMASK 0x07
+#define MC_MEMOPTIONS_DRAM1M 0x00
+#define MC_MEMOPTIONS_DRAM2M 0x01
+#define MC_MEMOPTIONS_DRAM4M 0x03
+#define MC_MEMOPTIONS_DRAM4M2 0x04
+#define MC_MEMOPTIONS_DRAM8M 0x05
+#define MC_MEMOPTIONS_DRAM16M 0x07
+ volatile u_char mc_sramsize;
+ volatile u_char mc_resv1;
+ volatile u_char mc_ieerr;
+ volatile u_char mc_resv2;
+ volatile u_char mc_ieirq;
+ volatile u_char mc_iefailirq;
+ volatile u_char mc_ncrerr;
+ volatile u_char mc_input;
+ volatile u_char mc_ver;
+ volatile u_char mc_ncrirq;
+ volatile u_long mc_t3cmp;
+ volatile u_long mc_t3count;
+ volatile u_long mc_t4cmp;
+ volatile u_long mc_t4count;
+ volatile u_char mc_busclock;
+ volatile u_char mc_promtime;
+ volatile u_char mc_flashctl;
+ volatile u_char mc_abortirq;
+ volatile u_char mc_resetctl;
+ volatile u_char mc_watchdogctl;
+ volatile u_char mc_watchdogtime;
+ volatile u_char mc_resv3;
+ volatile u_char mc_dramctl;
+ volatile u_char mc_resv4;
+ volatile u_char mc_mpustat;
+ volatile u_char mc_resv5;
+ volatile u_long mc_prescale;
+};
+#define MC_MCCHIP_OFF 0x42000
+#define MC_CHIPID 0x84
+
+/*
+ * points to system's MCchip registers
+ */
+extern struct mcreg *sys_mc;
+
+/*
+ * for the console we need zs phys addr
+ */
+#define ZS0_PHYS_162 (0xfff45000)
+#define ZS1_PHYS_162 (0xfff45801)
+
+/*
+ * We lock off our interrupt vector at 0x50.
+ */
+#define MC_VECBASE 0x50
+#define MC_NVEC 16
+
+#define MCV_ZS 0x00
+#define MCV_TIMER4 0x03
+#define MCV_TIMER3 0x04
+#define MCV_NCR 0x05
+#define MCV_IEFAIL 0x06
+#define MCV_IE 0x07
+#define MCV_TIMER2 0x08
+#define MCV_TIMER1 0x09
+#define MCV_PARITY 0x0b
+#define MCV_ABORT 0x0e
+
+#define MC_TCTL_CEN 0x01
+#define MC_TCTL_COC 0x02
+#define MC_TCTL_COVF 0x04
+#define MC_TCTL_OVF 0xf0
+
+#define MC_ABORT_ABS 0x40
+
+#define mc_timer_us2lim(us) (us) /* timer increments in "us" */
+
+#define MC_IRQ_IPL 0x07
+#define MC_IRQ_ICLR 0x08
+#define MC_IRQ_IEN 0x10
+#define MC_IRQ_INT 0x20
+
+#define MC_GENCTL_IEN 0x02
+
+#define MC_IEERR_SCLR 0x01
+
+#define MC_SC_INHIBIT (0 << 6)
+#define MC_SC_SNOOP (1 << 6)
+#define MC_SC_INVAL (2 << 6)
+#define MC_SC_RESV (3 << 6)
+
+#define MC_VER_ISLX 0x40
+#define MC_VER_REAL040 0x10
+#define MC_VER_NOIE 0x08
+#define MC_VER_NONCR 0x04
+#define MC_VER_NOVME 0x02
+#define MC_VER_33MHZ 0x01
+
+void mc_enableflashwrite __P((int on));
+#define MC_ENAFLASHWRITE_OFFSET 0xcc000
+#define MC_DISFLASHWRITE_OFFSET 0xc8000
diff --git a/sys/arch/mvme68k/dev/memc.c b/sys/arch/mvme68k/dev/memc.c
new file mode 100644
index 00000000000..9a16dd2a393
--- /dev/null
+++ b/sys/arch/mvme68k/dev/memc.c
@@ -0,0 +1,131 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * MEMC/MCECC chips
+ * these chips are rather similar in appearance except that the MEMC
+ * does parity while the MCECC does ECC.
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+
+#include <mvme68k/dev/memcreg.h>
+
+struct memcsoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr;
+ struct memcreg *sc_memc;
+ struct intrhand sc_ih;
+};
+
+void memcattach __P((struct device *, struct device *, void *));
+int memcmatch __P((struct device *, void *, void *));
+
+struct cfdriver memccd = {
+ NULL, "memc", memcmatch, memcattach,
+ DV_DULL, sizeof(struct memcsoftc), 0
+};
+
+int memcintr __P((struct frame *frame));
+
+int
+memcmatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+ struct memcreg *memc = (struct memcreg *)ca->ca_vaddr;
+
+ if (badvaddr(memc, 1))
+ return (0);
+ if (memc->memc_chipid==MEMC_CHIPID || memc->memc_chipid==MCECC_CHIPID)
+ return (1);
+ return (0);
+}
+
+void
+memcattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct memcsoftc *sc = (struct memcsoftc *)self;
+
+ /*
+ * since we know ourself to land in intiobase land,
+ * we must adjust our address
+ */
+ sc->sc_memc = (struct memcreg *)ca->ca_vaddr;
+
+ printf(": %s rev %d",
+ (sc->sc_memc->memc_chipid == MEMC_CHIPID) ? "MEMC040" : "MCECC",
+ sc->sc_memc->memc_chiprev);
+
+#if 0
+ sc->sc_ih.ih_fn = memcintr;
+ sc->sc_ih.ih_arg = 0;
+ sc->sc_ih.ih_ipl = 7;
+ sc->sc_ih.ih_wantframe = 1;
+ mcintr_establish(xxx, &sc->sc_ih);
+#endif
+
+ switch (sc->sc_memc->memc_chipid) {
+ case MEMC_CHIPID:
+ break;
+ case MCECC_CHIPID:
+ break;
+ }
+
+ printf("\n");
+}
+
+int
+memcintr(frame)
+ struct frame *frame;
+{
+ return (0);
+}
diff --git a/sys/arch/mvme68k/dev/memcreg.h b/sys/arch/mvme68k/dev/memcreg.h
new file mode 100644
index 00000000000..6bb7b901dec
--- /dev/null
+++ b/sys/arch/mvme68k/dev/memcreg.h
@@ -0,0 +1,106 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * the MEMC's registers are a subset of the MCECC chip
+ */
+struct memcreg {
+ volatile u_char memc_chipid;
+ volatile u_char xx0[3];
+ volatile u_char memc_chiprev;
+ volatile u_char xx1[3];
+ volatile u_char memc_memconf;
+#define MEMC_MEMCONF_MSIZ 0x07
+#define MEMC_MEMCONF_RTOB(x) ((4*1024*1024) << ((x) & MEMC_MEMCONF_MSIZ))
+ volatile u_char xx2[3];
+ volatile u_char memc_x0;
+ volatile u_char xx3[3];
+ volatile u_char memc_x1;
+ volatile u_char xx4[3];
+ volatile u_char memc_baseaddr;
+ volatile u_char xx5[3];
+ volatile u_char memc_control;
+ volatile u_char xx6[3];
+ volatile u_char memc_bclk;
+ volatile u_char xx7[3];
+
+ /* the following registers only exist on the MCECC */
+ volatile u_char memc_datactl;
+ volatile u_char xx8[3];
+ volatile u_char memc_scrubctl;
+ volatile u_char xx9[3];
+ volatile u_char memc_scrubperh;
+ volatile u_char xx10[3];
+ volatile u_char memc_scrubperl;
+ volatile u_char xx11[3];
+ volatile u_char memc_chipprescale;
+ volatile u_char xx12[3];
+ volatile u_char memc_scrubtime;
+ volatile u_char xx13[3];
+ volatile u_char memc_scrubprescaleh;
+ volatile u_char xx14[3];
+ volatile u_char memc_scrubprescalem;
+ volatile u_char xx15[3];
+ volatile u_char memc_scrubprescalel;
+ volatile u_char xx16[3];
+ volatile u_char memc_scrubtimeh;
+ volatile u_char xx17[3];
+ volatile u_char memc_scrubtimel;
+ volatile u_char xx18[3];
+ volatile u_char memc_scrubaddrhh;
+ volatile u_char xx19[3];
+ volatile u_char memc_scrubaddrhm;
+ volatile u_char xx20[3];
+ volatile u_char memc_scrubaddrlm;
+ volatile u_char xx21[3];
+ volatile u_char memc_scrubaddrll;
+ volatile u_char xx22[3];
+ volatile u_char memc_errlog;
+ volatile u_char xx23[3];
+ volatile u_char memc_errloghh;
+ volatile u_char xx24[3];
+ volatile u_char memc_errloghm;
+ volatile u_char xx25[3];
+ volatile u_char memc_errloglm;
+ volatile u_char xx26[3];
+ volatile u_char memc_errlogll;
+ volatile u_char xx27[3];
+ volatile u_char memc_errsyndrome;
+ volatile u_char xx28[3];
+ volatile u_char memc_defaults1;
+ volatile u_char xx29[3];
+ volatile u_char memc_defaults2;
+ volatile u_char xx30[3];
+};
+
+#define MEMC_CHIPID 0x80
+#define MCECC_CHIPID 0x81
diff --git a/sys/arch/mvme68k/dev/memdevs.c b/sys/arch/mvme68k/dev/memdevs.c
new file mode 100644
index 00000000000..a966b8778cc
--- /dev/null
+++ b/sys/arch/mvme68k/dev/memdevs.c
@@ -0,0 +1,76 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/buf.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+
+/*ARGSUSED*/
+int
+memdevrw(base, len, uio, flags)
+ caddr_t base;
+ int len;
+ struct uio *uio;
+ int flags;
+{
+ register vm_offset_t o, v;
+ register int c;
+ register struct iovec *iov;
+ int error = 0;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("memdevrw");
+ continue;
+ }
+
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if (v + c > len)
+ c = len - v; /* till end of dev */
+ if (c == 0)
+ return (0);
+ error = uiomove(base + v, c, uio);
+ }
+ return (error);
+}
diff --git a/sys/arch/mvme68k/dev/nvram.c b/sys/arch/mvme68k/dev/nvram.c
new file mode 100644
index 00000000000..93f484542a6
--- /dev/null
+++ b/sys/arch/mvme68k/dev/nvram.c
@@ -0,0 +1,416 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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. 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.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <machine/psl.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/mioctl.h>
+#include <mvme68k/dev/nvramreg.h>
+
+#if defined(GPROF)
+#include <sys/gmon.h>
+#endif
+
+struct nvramsoftc {
+ struct device sc_dev;
+ caddr_t sc_paddr;
+ caddr_t sc_vaddr;
+ int sc_len;
+ struct clockreg *sc_regs;
+};
+
+void nvramattach __P((struct device *, struct device *, void *));
+int nvrammatch __P((struct device *, void *, void *));
+
+struct cfdriver nvramcd = {
+ NULL, "nvram", nvrammatch, nvramattach,
+ DV_DULL, sizeof(struct nvramsoftc), 0
+};
+
+int
+nvrammatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+/*X*/ if (ca->ca_vaddr == (caddr_t)-1)
+/*X*/ return (1);
+ return (!badvaddr(ca->ca_vaddr, 1));
+}
+
+void
+nvramattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct nvramsoftc *sc = (struct nvramsoftc *)self;
+
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = ca->ca_vaddr;
+
+ sc->sc_len = MK48T08_SIZE;
+ if (cputyp == CPU_147)
+ sc->sc_len = MK48T02_SIZE;
+
+/*X*/ if (sc->sc_vaddr == (caddr_t)-1)
+/*X*/ sc->sc_vaddr = mapiodev((caddr_t)sc->sc_paddr,
+/*X*/ max(sc->sc_len, NBPG));
+/*X*/ if (sc->sc_vaddr == NULL)
+/*X*/ panic("failed to map!\n");
+
+ sc->sc_regs = (struct clockreg *)(sc->sc_vaddr + sc->sc_len -
+ sizeof(struct clockreg));
+
+ printf(": MK48T0%d len %d\n", sc->sc_len / 1024, sc->sc_len);
+}
+
+/*
+ * Return the best possible estimate of the time in the timeval
+ * to which tvp points. We do this by returning the current time
+ * plus the amount of time since the last clock interrupt (clock.c:clkread).
+ *
+ * Check that this time is no less than any previously-reported time,
+ * which could happen around the time of a clock adjustment. Just for fun,
+ * we guarantee that the time will be greater than the value obtained by a
+ * previous call.
+ */
+void
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s = splhigh();
+ static struct timeval lasttime;
+
+ *tvp = time;
+ tvp->tv_usec;
+ while (tvp->tv_usec > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ if (tvp->tv_sec == lasttime.tv_sec &&
+ tvp->tv_usec <= lasttime.tv_usec &&
+ (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ lasttime = *tvp;
+ splx(s);
+}
+
+/*
+ * BCD to decimal and decimal to BCD.
+ */
+#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))
+#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10))
+
+#define SECDAY (24 * 60 * 60)
+#define SECYR (SECDAY * 365)
+#define LEAPYEAR(y) (((y) & 3) == 0)
+
+/*
+ * This code is defunct after 2068.
+ * Will Unix still be here then??
+ */
+const short dayyr[12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+static u_long
+chiptotime(sec, min, hour, day, mon, year)
+ register int sec, min, hour, day, mon, year;
+{
+ register int days, yr;
+
+ sec = FROMBCD(sec);
+ min = FROMBCD(min);
+ hour = FROMBCD(hour);
+ day = FROMBCD(day);
+ mon = FROMBCD(mon);
+ year = FROMBCD(year) + YEAR0;
+
+ /* simple sanity checks */
+ if (year < 70 || year > 164 || mon < 1 || mon > 12 || day < 1 || day > 31)
+ return (0);
+ days = 0;
+ for (yr = 70; yr < year; yr++)
+ days += LEAPYEAR(yr) ? 366 : 365;
+ days += dayyr[mon - 1] + day - 1;
+ if (LEAPYEAR(yr) && mon > 2)
+ days++;
+ /* now have days since Jan 1, 1970; the rest is easy... */
+ return (days * SECDAY + hour * 3600 + min * 60 + sec);
+}
+
+struct chiptime {
+ int sec;
+ int min;
+ int hour;
+ int wday;
+ int day;
+ int mon;
+ int year;
+};
+
+timetochip(c)
+ register struct chiptime *c;
+{
+ register int t, t2, t3, now = time.tv_sec;
+
+ /* compute the year */
+ t2 = now / SECDAY;
+ t3 = (t2 + 2) % 7; /* day of week */
+ c->wday = TOBCD(t3 + 1);
+
+ t = 69;
+ while (t2 >= 0) { /* whittle off years */
+ t3 = t2;
+ t++;
+ t2 -= LEAPYEAR(t) ? 366 : 365;
+ }
+ c->year = t;
+
+ /* t3 = month + day; separate */
+ t = LEAPYEAR(t);
+ for (t2 = 1; t2 < 12; t2++)
+ if (t3 < dayyr[t2] + (t && t2 > 1))
+ break;
+
+ /* t2 is month */
+ c->mon = t2;
+ c->day = t3 - dayyr[t2 - 1] + 1;
+ if (t && t2 > 2)
+ c->day--;
+
+ /* the rest is easy */
+ t = now % SECDAY;
+ c->hour = t / 3600;
+ t %= 3600;
+ c->min = t / 60;
+ c->sec = t % 60;
+
+ c->sec = TOBCD(c->sec);
+ c->min = TOBCD(c->min);
+ c->hour = TOBCD(c->hour);
+ c->day = TOBCD(c->day);
+ c->mon = TOBCD(c->mon);
+ c->year = TOBCD(c->year - YEAR0);
+}
+
+/*
+ * Set up the system's time, given a `reasonable' time value.
+ */
+inittodr(base)
+ time_t base;
+{
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[0];
+ register struct clockreg *cl = sc->sc_regs;
+ int sec, min, hour, day, mon, year;
+ int badbase = 0, waszero = base == 0;
+
+ if (base < 5 * SECYR) {
+ /*
+ * If base is 0, assume filesystem time is just unknown
+ * instead of preposterous. Don't bark.
+ */
+ if (base != 0)
+ printf("WARNING: preposterous time in file system\n");
+ /* not going to use it anyway, if the chip is readable */
+ base = 21*SECYR + 186*SECDAY + SECDAY/2;
+ badbase = 1;
+ }
+ cl->cl_csr |= CLK_READ; /* enable read (stop time) */
+ sec = cl->cl_sec;
+ min = cl->cl_min;
+ hour = cl->cl_hour;
+ day = cl->cl_mday;
+ mon = cl->cl_month;
+ year = cl->cl_year;
+ cl->cl_csr &= ~CLK_READ; /* time wears on */
+ if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) {
+ printf("WARNING: bad date in nvram");
+ /*
+ * Believe the time in the file system for lack of
+ * anything better, resetting the clock.
+ */
+ time.tv_sec = base;
+ if (!badbase)
+ resettodr();
+ } else {
+ int deltat = time.tv_sec - base;
+
+ if (deltat < 0)
+ deltat = -deltat;
+ if (waszero || deltat < 2 * SECDAY)
+ return;
+ printf("WARNING: clock %s %d days",
+ time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
+ }
+ printf(" -- CHECK AND RESET THE DATE!\n");
+}
+
+/*
+ * Reset the clock based on the current time.
+ * Used when the current clock is preposterous, when the time is changed,
+ * and when rebooting. Do nothing if the time is not yet known, e.g.,
+ * when crashing during autoconfig.
+ */
+resettodr()
+{
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[0];
+ register struct clockreg *cl = sc->sc_regs;
+ struct chiptime c;
+
+ if (!time.tv_sec || cl == NULL)
+ return;
+ timetochip(&c);
+ cl->cl_csr |= CLK_WRITE; /* enable write */
+ cl->cl_sec = c.sec;
+ cl->cl_min = c.min;
+ cl->cl_hour = c.hour;
+ cl->cl_wday = c.wday;
+ cl->cl_mday = c.day;
+ cl->cl_month = c.mon;
+ cl->cl_year = c.year;
+ cl->cl_csr &= ~CLK_WRITE; /* load them up */
+}
+
+/*ARGSUSED*/
+int
+nvramopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= nvramcd.cd_ndevs ||
+ nvramcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+nvramclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+nvramioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ case MIOCGSIZ:
+ *(int *)data = sc->sc_len;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+nvramread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+/*ARGSUSED*/
+int
+nvramwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+/*
+ * If the NVRAM is of the 2K variety, an extra 2K of who-knows-what
+ * will also be mmap'd, due to NBPG being 4K. On the MVME147 the NVRAM
+ * repeats, so userland gets two copies back-to-back.
+ */
+int
+nvrammmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+
+ if (minor(dev) != 0)
+ return (-1);
+
+ /* allow access only in RAM */
+ if (off > sc->sc_len)
+ return (-1);
+ return (m68k_btop(sc->sc_paddr + off));
+}
diff --git a/sys/arch/mvme68k/dev/nvramreg.h b/sys/arch/mvme68k/dev/nvramreg.h
new file mode 100644
index 00000000000..ec804e1e049
--- /dev/null
+++ b/sys/arch/mvme68k/dev/nvramreg.h
@@ -0,0 +1,70 @@
+/* $NetBSD: clockreg.h,v 1.5 1994/11/20 20:54:07 deraadt 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. 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.
+ */
+
+/*
+ * Mostek MK48T02 clock.
+ */
+struct clockreg {
+ volatile u_char cl_csr; /* control register */
+ volatile u_char cl_sec; /* seconds (0..59; BCD) */
+ volatile u_char cl_min; /* minutes (0..59; BCD) */
+ volatile u_char cl_hour; /* hour (0..23; BCD) */
+ volatile u_char cl_wday; /* weekday (1..7) */
+ volatile u_char cl_mday; /* day in month (1..31; BCD) */
+ volatile u_char cl_month; /* month (1..12; BCD) */
+ volatile u_char cl_year; /* year (0..99; BCD) */
+};
+
+/* bits in cl_csr */
+#define CLK_WRITE 0x80 /* want to write */
+#define CLK_READ 0x40 /* want to read (freeze clock) */
+
+/*
+ * Motorola chose the year `1900' as their base count.
+ * XXX what happens when it wraps?
+ */
+#define YEAR0 0
+
+#define MK48T02_SIZE 2*1024
+#define MK48T08_SIZE 8*1024
diff --git a/sys/arch/mvme68k/dev/pcctwo.c b/sys/arch/mvme68k/dev/pcctwo.c
new file mode 100644
index 00000000000..6b694606f3b
--- /dev/null
+++ b/sys/arch/mvme68k/dev/pcctwo.c
@@ -0,0 +1,180 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * VME16x PCC2 chip
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+
+#include <mvme68k/dev/pcctworeg.h>
+
+struct pcctwosoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr; /* PCC2 space */
+ caddr_t sc_paddr;
+ struct pcctworeg *sc_pcc2; /* the actual registers */
+};
+
+void pcctwoattach __P((struct device *, struct device *, void *));
+int pcctwomatch __P((struct device *, void *, void *));
+
+struct cfdriver pcctwocd = {
+ NULL, "pcctwo", pcctwomatch, pcctwoattach,
+ DV_DULL, sizeof(struct pcctwosoftc), 0
+};
+
+struct pcctworeg *sys_pcc2 = NULL;
+
+int
+pcctwomatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+ struct pcctworeg *pcc2;
+
+ /* the PCC2 only exists on MVME16x's except the 162, right? */
+ if (cputyp == CPU_162 || cputyp == CPU_147)
+ return (0);
+ pcc2 = (struct pcctworeg *)(IIOV(ca->ca_paddr) + PCC2_PCC2CHIP_OFF);
+ if (badvaddr(pcc2, 1) || pcc2->pcc2_chipid != PCC2_CHIPID)
+ return (0);
+ return (1);
+}
+
+int
+pcctwo_print(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ if (ca->ca_offset != -1)
+ printf(" offset 0x%x", ca->ca_offset);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+pcctwo_scan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ struct cfdata *cf = child;
+ struct pcctwosoftc *sc = (struct pcctwosoftc *)parent;
+ struct confargs *ca = args;
+ struct confargs oca;
+
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_offset = cf->cf_loc[0];
+ oca.ca_ipl = cf->cf_loc[1];
+ if (oca.ca_offset != -1 && ISIIOVA(sc->sc_vaddr + oca.ca_offset)) {
+ oca.ca_vaddr = sc->sc_vaddr + oca.ca_offset;
+ oca.ca_paddr = sc->sc_paddr + oca.ca_offset;
+ } else {
+ oca.ca_vaddr = (caddr_t)-1;
+ oca.ca_paddr = (caddr_t)-1;
+ }
+ oca.ca_bustype = BUS_PCCTWO;
+ oca.ca_master = (void *)sc->sc_pcc2;
+ oca.ca_name = cf->cf_driver->cd_name;
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0)
+ return (0);
+ config_attach(parent, cf, &oca, pcctwo_print);
+ return (1);
+}
+
+void
+pcctwoattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct pcctwosoftc *sc = (struct pcctwosoftc *)self;
+ int i;
+
+ if (sys_pcc2)
+ panic("pcc2 already attached!");
+
+ /*
+ * since we know ourself to land in intiobase land,
+ * we must adjust our address
+ */
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = (caddr_t)IIOV(sc->sc_paddr);
+ sc->sc_pcc2 = (struct pcctworeg *)(sc->sc_vaddr + PCC2_PCC2CHIP_OFF);
+ sys_pcc2 = sc->sc_pcc2;
+
+ printf(": rev %d\n", sc->sc_pcc2->pcc2_chiprev);
+
+ sc->sc_pcc2->pcc2_vecbase = PCC2_VECBASE;
+ sc->sc_pcc2->pcc2_genctl |= PCC2_GENCTL_IEN; /* global irq enable */
+
+ config_search(pcctwo_scan, self, args);
+}
+
+/*
+ * PCC2 interrupts land in a PCC2_NVEC sized hole starting at PCC2_VECBASE
+ */
+int
+pcctwointr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ if (vec >= PCC2_NVEC) {
+ printf("pcctwo: illegal vector: 0x%x\n", vec);
+ panic("pcctwointr_establish");
+ }
+ return (intr_establish(PCC2_VECBASE+vec, ih));
+}
diff --git a/sys/arch/mvme68k/dev/pcctworeg.h b/sys/arch/mvme68k/dev/pcctworeg.h
new file mode 100644
index 00000000000..4c02c246797
--- /dev/null
+++ b/sys/arch/mvme68k/dev/pcctworeg.h
@@ -0,0 +1,150 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * MVME16x PCC2 chip: sort of a confused mish-mash of the MC in the 162
+ * and the PCC in the 147
+ */
+struct pcctworeg {
+ volatile u_char pcc2_chipid;
+ volatile u_char pcc2_chiprev;
+ volatile u_char pcc2_genctl;
+ volatile u_char pcc2_vecbase; /* irq vector base */
+ volatile u_long pcc2_t1cmp; /* timer1 compare */
+ volatile u_long pcc2_t1count; /* timer1 count */
+ volatile u_long pcc2_t2cmp; /* timer2 compare */
+ volatile u_long pcc2_t2count; /* timer2 count */
+ volatile u_char pcc2_pscalecnt; /* timer prescaler counter */
+ volatile u_char pcc2_pscaleadj; /* timer prescaler adjust */
+ volatile u_char pcc2_t2ctl; /* timer2 ctrl reg */
+ volatile u_char pcc2_t1ctl; /* timer1 ctrl reg */
+ volatile u_char pcc2_gpioirq; /* gpio irq */
+ volatile u_char pcc2_gpio; /* gpio i/o */
+ volatile u_char pcc2_t2irq;
+ volatile u_char pcc2_t1irq;
+ volatile u_char pcc2_sccerr;
+ volatile u_char pcc2_sccirq;
+ volatile u_char pcc2_scctx;
+ volatile u_char pcc2_sccrx;
+ volatile u_char :8;
+ volatile u_char :8;
+ volatile u_char :8;
+ volatile u_char pcc2_sccmoiack;
+ volatile u_char :8;
+ volatile u_char pcc2_scctxiack;
+ volatile u_char :8;
+ volatile u_char pcc2_sccrxiack;
+ volatile u_char pcc2_ieerr;
+ volatile u_char :8;
+ volatile u_char pcc2_ieirq;
+ volatile u_char pcc2_iefailirq;
+ volatile u_char pcc2_ncrerr;
+ volatile u_char :8;
+ volatile u_char :8;
+ volatile u_char pcc2_ncrirq;
+ volatile u_char pcc2_prtairq;
+ volatile u_char pcc2_prtfirq;
+ volatile u_char pcc2_prtsirq;
+ volatile u_char pcc2_prtpirq;
+ volatile u_char pcc2_prtbirq;
+ volatile u_char :8;
+ volatile u_char pcc2_prtstat;
+ volatile u_char pcc2_prtctl;
+ volatile u_short pcc2_speed; /* DO NOT USE */
+ volatile u_short pcc2_prtdat;
+ volatile u_short :16;
+ volatile u_char pcc2_ipl;
+ volatile u_char pcc2_mask;
+};
+#define PCC2_PCC2CHIP_OFF 0x42000
+#define PCC2_CHIPID 0x20
+
+/*
+ * points to system's PCCTWO. This is not active until the pcctwo0
+ * device has been attached.
+ */
+extern struct pcctworeg *sys_pcc2;
+
+/*
+ * We lock off our interrupt vector at 0x50.
+ */
+#define PCC2_VECBASE 0x50
+#define PCC2_NVEC 16
+
+/*
+ * Vectors we use
+ */
+#define PCC2V_NCR 0x05
+#define PCC2V_IEFAIL 0x06
+#define PCC2V_IE 0x07
+#define PCC2V_TIMER2 0x08
+#define PCC2V_TIMER1 0x09
+#define PCC2V_GPIO 0x0a
+#define PCC2V_SCC_RXE 0x0c
+#define PCC2V_SCC_M 0x0d
+#define PCC2V_SCC_TX 0x0e
+#define PCC2V_SCC_RX 0x0f
+
+#define PCC2_TCTL_CEN 0x01
+#define PCC2_TCTL_COC 0x02
+#define PCC2_TCTL_COVF 0x04
+#define PCC2_TCTL_OVF 0xf0
+
+#define PCC2_GPIO_PLTY 0x80
+#define PCC2_GPIO_EL 0x40
+
+#define PCC2_GPIOCR_OE 0x2
+#define PCC2_GPIOCR_O 0x1
+
+#define PCC2_SCC_AVEC 0x08
+#define PCC2_SCCRX_INHIBIT (0 << 6)
+#define PCC2_SCCRX_SNOOP (1 << 6)
+#define PCC2_SCCRX_INVAL (2 << 6)
+#define PCC2_SCCRX_RESV (3 << 6)
+
+#define pcc2_timer_us2lim(us) (us) /* timer increments in "us" */
+
+#define PCC2_IRQ_IPL 0x07
+#define PCC2_IRQ_ICLR 0x08
+#define PCC2_IRQ_IEN 0x10
+#define PCC2_IRQ_INT 0x20
+
+#define PCC2_IEERR_SCLR 0x01
+
+#define PCC2_GENCTL_FAST 0x01
+#define PCC2_GENCTL_IEN 0x02
+#define PCC2_GENCTL_C040 0x03
+
+#define PCC2_SC_INHIBIT (0 << 6)
+#define PCC2_SC_SNOOP (1 << 6)
+#define PCC2_SC_INVAL (2 << 6)
+#define PCC2_SC_RESV (3 << 6)
diff --git a/sys/arch/mvme68k/dev/sbic.c b/sys/arch/mvme68k/dev/sbic.c
new file mode 100644
index 00000000000..b871cdd95a2
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbic.c
@@ -0,0 +1,2561 @@
+/* $NetBSD: sbic.c,v 1.14 1995/08/18 15:28:03 chopps Exp $ */
+
+/*
+ * Copyright (c) 1994 Christian E. Hopps
+ * 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. 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
+ */
+
+/*
+ * AMD 33C93 scsi adaptor driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h> /* For hz */
+#include <sys/disklabel.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <machine/pmap.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/dmavar.h>
+#include <mvme68k/dev/sbicreg.h>
+#include <mvme68k/dev/sbicvar.h>
+
+#include <vm/pmap.h>
+
+/* Since I can't find this in any other header files */
+#define SCSI_PHASE(reg) (reg&0x07)
+
+/*
+ * SCSI delays
+ * In u-seconds, primarily for state changes on the SPC.
+ */
+#define SBIC_CMD_WAIT 50000 /* wait per step of 'immediate' cmds */
+#define SBIC_DATA_WAIT 50000 /* wait per data in/out step */
+#define SBIC_INIT_WAIT 50000 /* wait per step (both) during init */
+
+#define b_cylin b_resid
+#define SBIC_WAIT(regs, until, timeo) sbicwait(regs, until, timeo, __LINE__)
+
+extern u_int kvtop();
+
+int sbicicmd __P((struct sbic_softc *, int, int, void *, int, void *, int));
+int sbicgo __P((struct sbic_softc *, struct scsi_xfer *));
+int sbicdmaok __P((struct sbic_softc *, struct scsi_xfer *));
+int sbicwait __P((sbic_regmap_p, char, int , int));
+int sbiccheckdmap __P((void *, u_long, u_long));
+int sbicselectbus __P((struct sbic_softc *, sbic_regmap_p, u_char, u_char, u_char));
+int sbicxfstart __P((sbic_regmap_p, int, u_char, int));
+int sbicxfout __P((sbic_regmap_p regs, int, void *, int));
+int sbicfromscsiperiod __P((struct sbic_softc *, sbic_regmap_p, int));
+int sbictoscsiperiod __P((struct sbic_softc *, sbic_regmap_p, int));
+int sbicintr __P((struct sbic_softc *));
+int sbicpoll __P((struct sbic_softc *));
+int sbicnextstate __P((struct sbic_softc *, u_char, u_char));
+int sbicmsgin __P((struct sbic_softc *));
+int sbicxfin __P((sbic_regmap_p regs, int, void *));
+int sbicabort __P((struct sbic_softc *, sbic_regmap_p, char *));
+void sbicxfdone __P((struct sbic_softc *, sbic_regmap_p, int));
+void sbicerror __P((struct sbic_softc *, sbic_regmap_p, u_char));
+void sbicstart __P((struct sbic_softc *));
+void sbicreset __P((struct sbic_softc *));
+void sbic_scsidone __P((struct sbic_acb *, int));
+void sbic_sched __P((struct sbic_softc *));
+void sbic_save_ptrs __P((struct sbic_softc *, sbic_regmap_p,int,int));
+void sbic_load_ptrs __P((struct sbic_softc *, sbic_regmap_p,int,int));
+
+/*
+ * Synch xfer parameters, and timing conversions
+ */
+int sbic_min_period = SBIC_SYN_MIN_PERIOD; /* in cycles = f(ICLK,FSn) */
+int sbic_max_offset = SBIC_SYN_MAX_OFFSET; /* pure number */
+
+int sbic_cmd_wait = SBIC_CMD_WAIT;
+int sbic_data_wait = SBIC_DATA_WAIT;
+int sbic_init_wait = SBIC_INIT_WAIT;
+
+/*
+ * was broken before.. now if you want this you get it for all drives
+ * on sbic controllers.
+ */
+int sbic_inhibit_sync = 1;
+int sbic_enable_reselect = 1;
+int sbic_clock_override = 0;
+int sbic_no_dma = 0;
+int sbic_parallel_operations = 1;
+
+#ifdef DEBUG
+sbic_regmap_p debug_sbic_regs;
+int sbicdma_ops = 0; /* total DMA operations */
+int sbicdma_bounces = 0; /* number operations using bounce buffer */
+int sbicdma_hits = 0; /* number of DMA chains that were contiguous */
+int sbicdma_misses = 0; /* number of DMA chains that were not contiguous */
+int sbicdma_saves = 0;
+#define QPRINTF(a) if (sbic_debug > 1) printf a
+int sbic_debug = 0;
+int sync_debug = 0;
+int sbic_dma_debug = 0;
+int reselect_debug = 0;
+int report_sense = 0;
+int data_pointer_debug = 0;
+int sbic_timeout = 0;
+u_char debug_asr, debug_csr, timeout_active=0, routine;
+void sbictimeout __P((struct sbic_softc *dev));
+#else
+#define QPRINTF
+#endif
+
+/*
+ * default minphys routine for sbic based controllers
+ */
+void
+sbic_minphys(bp)
+ struct buf *bp;
+{
+
+ /*
+ * No max transfer at this level.
+ */
+ minphys(bp);
+}
+
+/*
+ * Save DMA pointers. Take into account partial transfer. Shut down DMA.
+ */
+void
+sbic_save_ptrs(dev, regs, target, lun)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int target, lun;
+{
+ int count, asr, csr, s;
+ unsigned long ptr;
+ char *vptr;
+ struct sbic_acb* acb;
+
+ extern vm_offset_t vm_first_phys;
+
+ if( !dev->sc_cur ) return;
+ if( !(dev->sc_flags & SBICF_INDMA) ) return; /* DMA not active */
+
+ s = splbio();
+
+ acb = dev->sc_nexus;
+ count = -1;
+ do {
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR ) {
+ printf("sbic_save_ptrs: asr %02x canceled!\n", asr);
+ splx(s);
+ return;
+ }
+ } while( asr & (SBIC_ASR_BSY|SBIC_ASR_CIP) );
+
+ /* Save important state */
+ /* must be done before dmastop */
+ acb->sc_dmacmd = dev->sc_dmacmd;
+ SBIC_TC_GET(regs, count);
+
+ /* Shut down DMA ====CAREFUL==== */
+ dev->sc_dmastop(dev);
+ dev->sc_flags &= ~SBICF_INDMA;
+ SBIC_TC_PUT(regs, 0);
+
+#ifdef DEBUG
+ if(!count && sbic_debug) printf("%dcount0",target);
+ if(data_pointer_debug == -1)
+ printf("SBIC saving target %d data pointers from (%x,%x)%xASR:%02x",
+ target, dev->sc_cur->dc_addr, dev->sc_cur->dc_count,
+ acb->sc_dmacmd, asr);
+#endif
+
+ /* Fixup partial xfers */
+ acb->sc_kv.dc_addr += (dev->sc_tcnt - count);
+ acb->sc_kv.dc_count -= (dev->sc_tcnt - count);
+ acb->sc_pa.dc_addr += (dev->sc_tcnt - count);
+ acb->sc_pa.dc_count -= ((dev->sc_tcnt - count)>>1);
+
+ acb->sc_tcnt = dev->sc_tcnt = count;
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf(" at (%x,%x):%x\n",
+ dev->sc_cur->dc_addr, dev->sc_cur->dc_count,count);
+ sbicdma_saves++;
+#endif
+ splx(s);
+}
+
+
+/*
+ * DOES NOT RESTART DMA!!!
+ */
+void sbic_load_ptrs(dev, regs, target, lun)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int target, lun;
+{
+ int i, s, asr, count;
+ char* vaddr, * paddr;
+ struct sbic_acb *acb;
+
+ acb = dev->sc_nexus;
+ if( !acb->sc_kv.dc_count )
+ /* No data to xfer */
+ return;
+
+ s = splbio();
+
+ dev->sc_last = dev->sc_cur = &acb->sc_pa;
+ dev->sc_tcnt = acb->sc_tcnt;
+ dev->sc_dmacmd = acb->sc_dmacmd;
+
+#ifdef DEBUG
+ sbicdma_ops++;
+#endif
+ if( !dev->sc_tcnt ) {
+ /* sc_tcnt == 0 implies end of segment */
+
+ /* do kvm to pa mappings */
+ paddr = acb->sc_pa.dc_addr =
+ (char *) kvtop(acb->sc_kv.dc_addr);
+
+ vaddr = acb->sc_kv.dc_addr;
+ count = acb->sc_kv.dc_count;
+ for(count = (NBPG - ((int)vaddr & PGOFSET));
+ count < acb->sc_kv.dc_count
+ && (char*)kvtop(vaddr + count + 4) == paddr + count + 4;
+ count += NBPG);
+ /* If it's all contiguous... */
+ if(count > acb->sc_kv.dc_count ) {
+ count = acb->sc_kv.dc_count;
+#ifdef DEBUG
+ sbicdma_hits++;
+#endif
+ } else {
+#ifdef DEBUG
+ sbicdma_misses++;
+#endif
+ }
+ acb->sc_tcnt = count;
+ acb->sc_pa.dc_count = count >> 1;
+
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("DMA recalc:kv(%x,%x)pa(%x,%x)\n",
+ acb->sc_kv.dc_addr,
+ acb->sc_kv.dc_count,
+ acb->sc_pa.dc_addr,
+ acb->sc_tcnt);
+#endif
+ }
+ splx(s);
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("SBIC restoring target %d data pointers at (%x,%x)%x\n",
+ target, dev->sc_cur->dc_addr, dev->sc_cur->dc_count,
+ dev->sc_dmacmd);
+#endif
+}
+
+/*
+ * used by specific sbic controller
+ *
+ * it appears that the higher level code does nothing with LUN's
+ * so I will too. I could plug it in, however so could they
+ * in scsi_scsi_cmd().
+ */
+int
+sbic_scsicmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct sbic_acb *acb;
+ struct sbic_softc *dev;
+ struct scsi_link *slp;
+ int flags, s, stat;
+
+ slp = xs->sc_link;
+ dev = slp->adapter_softc;
+ flags = xs->flags;
+
+ if (flags & SCSI_DATA_UIO)
+ panic("sbic: scsi data uio requested");
+
+ if (dev->sc_nexus && flags & SCSI_POLL)
+ panic("sbic_scsicmd: busy");
+
+ if (slp->target == slp->adapter_target)
+ return ESCAPE_NOT_SUPPORTED;
+
+ s = splbio();
+ acb = dev->free_list.tqh_first;
+ if (acb)
+ TAILQ_REMOVE(&dev->free_list, acb, chain);
+ splx(s);
+
+ if (acb == NULL) {
+#ifdef DEBUG
+ printf("sbic_scsicmd: unable to queue request for target %d\n",
+ slp->target);
+#ifdef DDB
+ Debugger();
+#endif
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+ acb->flags = ACB_ACTIVE;
+ if (flags & SCSI_DATA_IN)
+ acb->flags |= ACB_DATAIN;
+ acb->xs = xs;
+ bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
+ acb->clen = xs->cmdlen;
+ acb->sc_kv.dc_addr = xs->data;
+ acb->sc_kv.dc_count = xs->datalen;
+ acb->pa_addr = xs->data ? (char *)kvtop(xs->data) : 0; /* XXXX check */
+
+ if (flags & SCSI_POLL) {
+ s = splbio();
+ /*
+ * This has major side effects -- it locks up the machine
+ */
+
+ dev->sc_flags |= SBICF_ICMD;
+ do {
+ while(dev->sc_nexus)
+ sbicpoll(dev);
+ dev->sc_nexus = acb;
+ dev->sc_stat[0] = -1;
+ dev->sc_xs = xs;
+ dev->target = slp->target;
+ dev->lun = slp->lun;
+ stat = sbicicmd(dev, slp->target, slp->lun,
+ &acb->cmd, acb->clen,
+ acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
+ } while (dev->sc_nexus != acb);
+ sbic_scsidone(acb, stat);
+
+ splx(s);
+ return(COMPLETE);
+ }
+
+ s = splbio();
+ TAILQ_INSERT_TAIL(&dev->ready_list, acb, chain);
+
+ if (dev->sc_nexus) {
+ splx(s);
+ return(SUCCESSFULLY_QUEUED);
+ }
+
+ /*
+ * nothing is active, try to start it now.
+ */
+ sbic_sched(dev);
+ splx(s);
+
+/* TODO: add sbic_poll to do SCSI_POLL operations */
+#if 0
+ if (flags & SCSI_POLL)
+ return(COMPLETE);
+#endif
+ return(SUCCESSFULLY_QUEUED);
+}
+
+/*
+ * attempt to start the next available command
+ */
+void
+sbic_sched(dev)
+ struct sbic_softc *dev;
+{
+ struct scsi_xfer *xs;
+ struct scsi_link *slp;
+ struct sbic_acb *acb;
+ int flags, /*phase,*/ stat, i;
+
+ if (dev->sc_nexus)
+ return; /* a command is current active */
+
+ for (acb = dev->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
+ slp = acb->xs->sc_link;
+ i = slp->target;
+ if (!(dev->sc_tinfo[i].lubusy & (1 << slp->lun))) {
+ struct sbic_tinfo *ti = &dev->sc_tinfo[i];
+
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ dev->sc_nexus = acb;
+ slp = acb->xs->sc_link;
+ ti = &dev->sc_tinfo[slp->target];
+ ti->lubusy |= (1 << slp->lun);
+ acb->sc_pa.dc_addr = acb->pa_addr; /* XXXX check */
+ break;
+ }
+ }
+
+ if (acb == NULL)
+ return; /* did not find an available command */
+
+ dev->sc_xs = xs = acb->xs;
+ slp = xs->sc_link;
+ flags = xs->flags;
+
+ if (flags & SCSI_RESET)
+ sbicreset(dev);
+
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("sbic_sched(%d,%d)\n",slp->target,slp->lun);
+#endif
+ dev->sc_stat[0] = -1;
+ dev->target = slp->target;
+ dev->lun = slp->lun;
+ if ( flags & SCSI_POLL || ( !sbic_parallel_operations
+ && (/*phase == STATUS_PHASE ||*/
+ sbicdmaok(dev, xs) == 0) ) )
+ stat = sbicicmd(dev, slp->target, slp->lun, &acb->cmd,
+ acb->clen, acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
+ else if (sbicgo(dev, xs) == 0)
+ return;
+ else
+ stat = dev->sc_stat[0];
+
+ sbic_scsidone(acb, stat);
+}
+
+void
+sbic_scsidone(acb, stat)
+ struct sbic_acb *acb;
+ int stat;
+{
+ struct scsi_xfer *xs;
+ struct scsi_link *slp;
+ struct sbic_softc *dev;
+ int s, dosched = 0;
+
+ xs = acb->xs;
+ slp = xs->sc_link;
+ dev = slp->adapter_softc;
+#ifdef DIAGNOSTIC
+ if (acb == NULL || xs == NULL) {
+ printf("sbic_scsidone -- (%d,%d) no scsi_xfer\n",
+ dev->target, dev->lun);
+#ifdef DDB
+ Debugger();
+#endif
+ return;
+ }
+#endif
+#if 1
+ if (((struct device *)(slp->device_softc))->dv_unit < dk_ndrive)
+ ++dk_xfer[((struct device *)(slp->device_softc))->dv_unit];
+#endif
+ /*
+ * is this right?
+ */
+ xs->status = stat;
+
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("scsidone: (%d,%d)->(%d,%d)%02x\n",
+ slp->target, slp->lun,
+ dev->target, dev->lun, stat);
+ if( xs->sc_link->target == dev->sc_link.adapter_target )
+ panic("target == hostid");
+#endif
+
+ if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
+ if (stat == SCSI_CHECK) {
+ /* Schedule a REQUEST SENSE */
+ struct scsi_sense *ss = (void *)&acb->cmd;
+#ifdef DEBUG
+ if (report_sense)
+ printf("sbic_scsidone: autosense %02x targ %d lun %d",
+ acb->cmd.opcode, slp->target, slp->lun);
+#endif
+ bzero(ss, sizeof(*ss));
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = slp->lun << 5;
+ ss->length = sizeof(struct scsi_sense_data);
+ acb->clen = sizeof(*ss);
+ acb->sc_kv.dc_addr = (char *)&xs->sense;
+ acb->sc_kv.dc_count = sizeof(struct scsi_sense_data);
+ acb->pa_addr = (char *)kvtop(&xs->sense); /* XXX check */
+ acb->flags = ACB_ACTIVE | ACB_CHKSENSE | ACB_DATAIN;
+ TAILQ_INSERT_HEAD(&dev->ready_list, acb, chain);
+ dev->sc_tinfo[slp->target].lubusy &=
+ ~(1 << slp->lun);
+ dev->sc_tinfo[slp->target].senses++;
+ if (dev->sc_nexus == acb) {
+ dev->sc_nexus = NULL;
+ sbic_sched(dev);
+ }
+ return;
+ }
+ }
+ if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
+ xs->error = XS_SENSE;
+#ifdef DEBUG
+ if (report_sense)
+ printf(" => %02x %02x\n", xs->sense.extended_flags,
+ xs->sense.extended_extra_bytes[3]);
+#endif
+ } else {
+ xs->resid = 0; /* XXXX */
+ }
+#if whataboutthisone
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+#endif
+ xs->flags |= ITSDONE;
+
+ /*
+ * Remove the ACB from whatever queue it's on. We have to do a bit of
+ * a hack to figure out which queue it's on. Note that it is *not*
+ * necessary to cdr down the ready queue, but we must cdr down the
+ * nexus queue and see if it's there, so we can mark the unit as no
+ * longer busy. This code is sickening, but it works.
+ */
+ if (acb == dev->sc_nexus) {
+ dev->sc_nexus = NULL;
+ dev->sc_tinfo[slp->target].lubusy &= ~(1<<slp->lun);
+ if (dev->ready_list.tqh_first)
+ dosched = 1; /* start next command */
+ } else if (dev->ready_list.tqh_last == &acb->chain.tqe_next) {
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ } else {
+ register struct sbic_acb *acb2;
+ for (acb2 = dev->nexus_list.tqh_first; acb2;
+ acb2 = acb2->chain.tqe_next)
+ if (acb2 == acb) {
+ TAILQ_REMOVE(&dev->nexus_list, acb, chain);
+ dev->sc_tinfo[slp->target].lubusy
+ &= ~(1<<slp->lun);
+ break;
+ }
+ if (acb2)
+ ;
+ else if (acb->chain.tqe_next) {
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ } else {
+ printf("%s: can't find matching acb\n",
+ dev->sc_dev.dv_xname);
+#ifdef DDB
+ Debugger();
+#endif
+ }
+ }
+ /* Put it on the free list. */
+ acb->flags = ACB_FREE;
+ TAILQ_INSERT_HEAD(&dev->free_list, acb, chain);
+
+ dev->sc_tinfo[slp->target].cmds++;
+
+ scsi_done(xs);
+
+ if (dosched)
+ sbic_sched(dev);
+}
+
+int
+sbicdmaok(dev, xs)
+ struct sbic_softc *dev;
+ struct scsi_xfer *xs;
+{
+ if (sbic_no_dma || xs->datalen & 0x1 || (u_int)xs->data & 0x3)
+ return(0);
+ /*
+ * controller supports dma to any addresses?
+ */
+ else if ((dev->sc_flags & SBICF_BADDMA) == 0)
+ return(1);
+ /*
+ * this address is ok for dma?
+ */
+ else if (sbiccheckdmap(xs->data, xs->datalen, dev->sc_dmamask) == 0)
+ return(1);
+#if 0
+ /*
+ * we have a bounce buffer?
+ */
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce)
+ return(1);
+ /*
+ * try to get one
+ */
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce
+ = (char *)alloc_z2mem(MAXPHYS)) {
+ if (isztwomem(dev->sc_tinfo[xs->sc_link->target].bounce))
+ printf("alloc ZII target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ kvtop(dev->sc_tinfo[xs->sc_link->target].bounce));
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce)
+ printf("alloc CHIP target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ PREP_DMA_MEM(dev->sc_tinfo[xs->sc_link->target].bounce));
+ return(1);
+ }
+#endif
+
+ return(0);
+}
+
+
+int
+sbicwait(regs, until, timeo, line)
+ sbic_regmap_p regs;
+ char until;
+ int timeo;
+ int line;
+{
+ u_char val;
+ int csr;
+
+ if (timeo == 0)
+ timeo = 10000; /* some large value.. */
+
+ GET_SBIC_asr(regs,val);
+ while ((val & until) == 0) {
+ if (timeo-- == 0) {
+ GET_SBIC_csr(regs, csr);
+ printf("sbicwait TIMEO @%d with asr=x%x csr=x%x\n",
+ line, val, csr);
+#if defined(DDB) && defined(DEBUG)
+ Debugger();
+#endif
+ return(val); /* Maybe I should abort */
+ break;
+ }
+ DELAY(1);
+ GET_SBIC_asr(regs,val);
+ }
+ return(val);
+}
+
+int
+sbicabort(dev, regs, where)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ char *where;
+{
+ u_char csr, asr;
+
+ GET_SBIC_csr(regs, csr);
+ GET_SBIC_asr(regs, asr);
+
+ printf ("%s: abort %s: csr = 0x%02x, asr = 0x%02x\n",
+ dev->sc_dev.dv_xname, where, csr, asr);
+
+
+#if 0
+ /* Clean up running command */
+ if (dev->sc_nexus != NULL) {
+ dev->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(dev->sc_nexus, dev->sc_stat[0]);
+ }
+ while (acb = dev->nexus_list.tqh_first) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(acb, -1 /*acb->stat[0]*/);
+ }
+#endif
+
+ /* Clean up chip itself */
+ if (dev->sc_flags & SBICF_SELECTED) {
+ while( asr & SBIC_ASR_DBR ) {
+ /* sbic is jammed w/data. need to clear it */
+ /* But we don't know what direction it needs to go */
+ GET_SBIC_data(regs, asr);
+ printf("%s: abort %s: clearing data buffer 0x%02x\n",
+ dev->sc_dev.dv_xname, where, asr);
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR ) /* Not the read direction, then */
+ SET_SBIC_data(regs, asr);
+ GET_SBIC_asr(regs, asr);
+ }
+ WAIT_CIP(regs);
+ SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
+ WAIT_CIP(regs);
+
+ GET_SBIC_asr(regs, asr);
+ if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) {
+ /* ok, get more drastic.. */
+
+ sbicreset(dev);
+ dev->sc_flags &= ~SBICF_SELECTED;
+ return -1;
+ }
+ SET_SBIC_cmd(regs, SBIC_CMD_DISC);
+
+ do {
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (regs, csr);
+ } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
+ && (csr != SBIC_CSR_CMD_INVALID));
+
+ /* lets just hope it worked.. */
+ dev->sc_flags &= ~SBICF_SELECTED;
+ }
+ return -1;
+}
+
+
+/*
+ * Initialize driver-private structures
+ */
+
+void
+sbicinit(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ u_int my_id, i, s;
+ u_char csr;
+ struct sbic_acb *acb;
+
+ regs = dev->sc_sbicp;
+
+ if ((dev->sc_flags & SBICF_ALIVE) == 0) {
+ TAILQ_INIT(&dev->ready_list);
+ TAILQ_INIT(&dev->nexus_list);
+ TAILQ_INIT(&dev->free_list);
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+ acb = dev->sc_acb;
+ bzero(acb, sizeof(dev->sc_acb));
+ for (i = 0; i < sizeof(dev->sc_acb) / sizeof(*acb); i++) {
+ TAILQ_INSERT_TAIL(&dev->free_list, acb, chain);
+ acb++;
+ }
+ bzero(dev->sc_tinfo, sizeof(dev->sc_tinfo));
+ } else panic("sbic: reinitializing driver!");
+
+ dev->sc_flags |= SBICF_ALIVE;
+ dev->sc_flags &= ~SBICF_SELECTED;
+
+ sbicreset(dev);
+}
+
+void
+sbicreset(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ u_int my_id, i, s;
+ u_char csr;
+ struct sbic_acb *acb;
+
+ regs = dev->sc_sbicp;
+#if 0
+ if (dev->sc_flags & SBICF_ALIVE) {
+ SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
+ WAIT_CIP(regs);
+ }
+#else
+ SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
+ WAIT_CIP(regs);
+#endif
+ s = splbio();
+ my_id = dev->sc_link.adapter_target & SBIC_ID_MASK;
+
+ /* Enable advanced mode */
+ my_id |= SBIC_ID_EAF /*| SBIC_ID_EHP*/ ;
+ SET_SBIC_myid(regs, my_id);
+
+ /*
+ * Disable interrupts (in dmainit) then reset the chip
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_RESET);
+ DELAY(25);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr); /* clears interrupt also */
+
+ if (dev->sc_clkfreq < 110)
+ my_id |= SBIC_ID_FS_8_10;
+ else if (dev->sc_clkfreq < 160)
+ my_id |= SBIC_ID_FS_12_15;
+ else if (dev->sc_clkfreq < 210)
+ my_id |= SBIC_ID_FS_16_20;
+
+ SET_SBIC_myid(regs, my_id);
+
+ /*
+ * Set up various chip parameters
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI /* | SBIC_CTL_HSP */
+ | SBIC_MACHINE_DMA_MODE);
+ /*
+ * don't allow (re)selection (SBIC_RID_ES)
+ * until we can handle target mode!!
+ */
+ SET_SBIC_rselid(regs, SBIC_RID_ER);
+ SET_SBIC_syn(regs, 0); /* asynch for now */
+
+ /*
+ * anything else was zeroed by reset
+ */
+ splx(s);
+
+#if 0
+ if ((dev->sc_flags & SBICF_ALIVE) == 0) {
+ TAILQ_INIT(&dev->ready_list);
+ TAILQ_INIT(&dev->nexus_list);
+ TAILQ_INIT(&dev->free_list);
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+ acb = dev->sc_acb;
+ bzero(acb, sizeof(dev->sc_acb));
+ for (i = 0; i < sizeof(dev->sc_acb) / sizeof(*acb); i++) {
+ TAILQ_INSERT_TAIL(&dev->free_list, acb, chain);
+ acb++;
+ }
+ bzero(dev->sc_tinfo, sizeof(dev->sc_tinfo));
+ } else {
+ if (dev->sc_nexus != NULL) {
+ dev->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(dev->sc_nexus, dev->sc_stat[0]);
+ }
+ while (acb = dev->nexus_list.tqh_first) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(acb, -1 /*acb->stat[0]*/);
+ }
+ }
+
+ dev->sc_flags |= SBICF_ALIVE;
+#endif
+ dev->sc_flags &= ~SBICF_SELECTED;
+}
+
+void
+sbicerror(dev, regs, csr)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ u_char csr;
+{
+ struct scsi_xfer *xs;
+
+ xs = dev->sc_xs;
+
+#ifdef DIAGNOSTIC
+ if (xs == NULL)
+ panic("sbicerror");
+#endif
+ if (xs->flags & SCSI_SILENT)
+ return;
+
+ printf("%s: ", dev->sc_dev.dv_xname);
+ printf("csr == 0x%02x\n", csr); /* XXX */
+}
+
+/*
+ * select the bus, return when selected or error.
+ */
+int
+sbicselectbus(dev, regs, target, lun, our_addr)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ u_char target, lun, our_addr;
+{
+ u_char asr, csr, id;
+
+ QPRINTF(("sbicselectbus %d\n", target));
+
+ /*
+ * if we're already selected, return (XXXX panic maybe?)
+ */
+ if (dev->sc_flags & SBICF_SELECTED)
+ return(1);
+
+ SET_SBIC_rselid (regs, 0);
+#if 0
+ GET_SBIC_asr(regs, asr);
+ if( asr & (SBIC_ASR_INT|SBIC_ASR_BSY) ) {
+ /* This means we got ourselves reselected upon */
+/* printf("sbicselectbus: weird asr %02x\n", asr);*/
+#ifdef DDB
+/* Debugger();*/
+#endif
+ SET_SBIC_rselid (regs, SBIC_RID_ER);
+ return 1;
+ }
+#endif
+ /*
+ * issue select
+ */
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_selid(regs, target);
+ SET_SBIC_timeo(regs, SBIC_TIMEOUT(250,dev->sc_clkfreq));
+
+ /*
+ * set sync or async
+ */
+ if (dev->sc_sync[target].state == SYNC_DONE)
+ SET_SBIC_syn(regs, SBIC_SYN (dev->sc_sync[target].offset,
+ dev->sc_sync[target].period));
+ else
+ SET_SBIC_syn(regs, SBIC_SYN (0, sbic_min_period));
+
+ GET_SBIC_asr(regs, asr);
+ if( asr & (SBIC_ASR_INT|SBIC_ASR_BSY) ) {
+ /* This means we got ourselves reselected upon */
+/* printf("sbicselectbus: INT/BSY asr %02x\n", asr);*/
+#ifdef DDB
+/* Debugger();*/
+#endif
+ return 1;
+ }
+
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN);
+
+ /*
+ * wait for select (merged from seperate function may need
+ * cleanup)
+ */
+ WAIT_CIP(regs);
+#if 0
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_LCI ) {
+ /* This means we got ourselves reselected upon */
+#ifdef DEBUG
+ if (reselect_debug)
+ printf("sbicselectbus: LCI asr %02x\n", asr);
+/* Debugger();*/
+#endif
+ return 1;
+ }
+#endif
+ do {
+ asr = SBIC_WAIT(regs, SBIC_ASR_INT | SBIC_ASR_LCI, 0);
+ if (asr & SBIC_ASR_LCI) {
+#ifdef DEBUG
+ if (reselect_debug)
+ printf("sbicselectbus: late LCI asr %02x\n", asr);
+#endif
+ return 1;
+ }
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("%02x ", csr));
+ if( csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY) {
+#ifdef DEBUG
+ if( reselect_debug || 1 )
+ printf("sbicselectbus: reselected asr %02x\n", asr);
+#endif
+ /* We need to handle this now so we don't lock up later */
+ sbicnextstate(dev, csr, asr);
+ return 1;
+ }
+ if( csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN) {
+ panic("sbicselectbus: target issued select!");
+ return 1;
+ }
+ } while (csr != (SBIC_CSR_MIS_2|MESG_OUT_PHASE)
+ && csr != (SBIC_CSR_MIS_2|CMD_PHASE) && csr != SBIC_CSR_SEL_TIMEO);
+
+ /* Enable (or not) reselection */
+ if( (dev->sc_xs->flags & SCSI_POLL
+ || (dev->sc_flags & SBICF_ICMD)
+ || !sbic_enable_reselect)
+ && dev->nexus_list.tqh_first == NULL )
+ SET_SBIC_rselid (regs, 0);
+ else
+ SET_SBIC_rselid (regs, SBIC_RID_ER);
+
+ if (csr == (SBIC_CSR_MIS_2|CMD_PHASE)) {
+ dev->sc_flags |= SBICF_SELECTED; /* device ignored ATN */
+ GET_SBIC_selid(regs, id);
+ dev->target = id;
+ GET_SBIC_tlun(regs,dev->lun);
+ if( dev->lun & SBIC_TLUN_VALID )
+ dev->lun &= SBIC_TLUN_MASK;
+ else
+ dev->lun = lun;
+ } else if (csr == (SBIC_CSR_MIS_2|MESG_OUT_PHASE)) {
+ /*
+ * Send identify message
+ * (SCSI-2 requires an identify msg (?))
+ */
+ GET_SBIC_selid(regs, id);
+ dev->target = id;
+ GET_SBIC_tlun(regs,dev->lun);
+ if( dev->lun & SBIC_TLUN_VALID )
+ dev->lun &= SBIC_TLUN_MASK;
+ else
+ dev->lun = lun;
+ /*
+ * handle drives that don't want to be asked
+ * whether to go sync at all.
+ */
+ if (sbic_inhibit_sync && dev->sc_sync[id].state == SYNC_START) {
+#ifdef DEBUG
+ if (sync_debug)
+ printf("Forcing target %d asynchronous.\n", id);
+#endif
+ dev->sc_sync[id].offset = 0;
+ dev->sc_sync[id].period = sbic_min_period;
+ dev->sc_sync[id].state = SYNC_DONE;
+ }
+
+
+ if (dev->sc_sync[id].state != SYNC_START){
+ if( dev->sc_xs->flags & SCSI_POLL
+ || (dev->sc_flags & SBICF_ICMD)
+ || !sbic_enable_reselect )
+ SEND_BYTE (regs, MSG_IDENTIFY | lun);
+ else
+ SEND_BYTE (regs, MSG_IDENTIFY_DR | lun);
+ } else {
+ /*
+ * try to initiate a sync transfer.
+ * So compose the sync message we're going
+ * to send to the target
+ */
+
+#ifdef DEBUG
+ if (sync_debug)
+ printf("Sending sync request to target %d ... ",
+ id);
+#endif
+ /*
+ * setup scsi message sync message request
+ */
+ dev->sc_msg[0] = MSG_IDENTIFY | lun;
+ dev->sc_msg[1] = MSG_EXT_MESSAGE;
+ dev->sc_msg[2] = 3;
+ dev->sc_msg[3] = MSG_SYNC_REQ;
+ dev->sc_msg[4] = sbictoscsiperiod(dev, regs,
+ sbic_min_period);
+ dev->sc_msg[5] = sbic_max_offset;
+
+ if (sbicxfstart(regs, 6, MESG_OUT_PHASE, sbic_cmd_wait))
+ sbicxfout(regs, 6, dev->sc_msg, MESG_OUT_PHASE);
+
+ dev->sc_sync[id].state = SYNC_SENT;
+#ifdef DEBUG
+ if (sync_debug)
+ printf ("sent\n");
+#endif
+ }
+
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("[%02x]", csr));
+#ifdef DEBUG
+ if (sync_debug && dev->sc_sync[id].state == SYNC_SENT)
+ printf("csr-result of last msgout: 0x%x\n", csr);
+#endif
+
+ if (csr != SBIC_CSR_SEL_TIMEO)
+ dev->sc_flags |= SBICF_SELECTED;
+ }
+ if (csr == SBIC_CSR_SEL_TIMEO)
+ dev->sc_xs->error = XS_SELTIMEOUT;
+
+ QPRINTF(("\n"));
+
+ return(csr == SBIC_CSR_SEL_TIMEO);
+}
+
+int
+sbicxfstart(regs, len, phase, wait)
+ sbic_regmap_p regs;
+ int len, wait;
+ u_char phase;
+{
+ u_char id;
+
+ switch (phase) {
+ case DATA_IN_PHASE:
+ case MESG_IN_PHASE:
+ GET_SBIC_selid (regs, id);
+ id |= SBIC_SID_FROM_SCSI;
+ SET_SBIC_selid (regs, id);
+ SBIC_TC_PUT (regs, (unsigned)len);
+ break;
+ case DATA_OUT_PHASE:
+ case MESG_OUT_PHASE:
+ case CMD_PHASE:
+ GET_SBIC_selid (regs, id);
+ id &= ~SBIC_SID_FROM_SCSI;
+ SET_SBIC_selid (regs, id);
+ SBIC_TC_PUT (regs, (unsigned)len);
+ break;
+ default:
+ SBIC_TC_PUT (regs, 0);
+ }
+ QPRINTF(("sbicxfstart %d, %d, %d\n", len, phase, wait));
+
+ return(1);
+}
+
+int
+sbicxfout(regs, len, bp, phase)
+ sbic_regmap_p regs;
+ int len;
+ void *bp;
+ int phase;
+{
+ u_char orig_csr, csr, asr, *buf;
+ int wait;
+
+ buf = bp;
+ wait = sbic_data_wait;
+
+ QPRINTF(("sbicxfout {%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]));
+
+ GET_SBIC_csr (regs, orig_csr);
+
+ /*
+ * 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
+ */
+ WAIT_CIP (regs);
+ SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
+ for (;len > 0; len--) {
+ GET_SBIC_asr (regs, asr);
+ while ((asr & SBIC_ASR_DBR) == 0) {
+ if ((asr & SBIC_ASR_INT) || --wait < 0) {
+#ifdef DEBUG
+ if (sbic_debug)
+ printf("sbicxfout fail: l%d i%x w%d\n",
+ len, asr, wait);
+#endif
+ return (len);
+ }
+/* DELAY(1);*/
+ GET_SBIC_asr (regs, asr);
+ }
+
+ SET_SBIC_data (regs, *buf);
+ buf++;
+ }
+ SBIC_TC_GET(regs, len);
+ QPRINTF(("sbicxfout done %d bytes\n", len));
+ /*
+ * this leaves with one csr to be read
+ */
+ return(0);
+}
+
+/* returns # bytes left to read */
+int
+sbicxfin(regs, len, bp)
+ sbic_regmap_p regs;
+ int len;
+ void *bp;
+{
+ int wait, read;
+ u_char *obp, *buf;
+ u_char orig_csr, csr, asr;
+
+ wait = sbic_data_wait;
+ obp = bp;
+ buf = bp;
+
+ GET_SBIC_csr (regs, orig_csr);
+
+ QPRINTF(("sbicxfin %d, csr=%02x\n", len, orig_csr));
+
+ WAIT_CIP (regs);
+ SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
+ for (;len > 0; len--) {
+ GET_SBIC_asr (regs, asr);
+ if((asr & SBIC_ASR_PE)) {
+#ifdef DEBUG
+ printf("sbicxfin parity error: l%d i%x w%d\n",
+ len, asr, wait);
+/* return ((unsigned long)buf - (unsigned long)bp); */
+#ifdef DDB
+ Debugger();
+#endif
+#endif
+ }
+ while ((asr & SBIC_ASR_DBR) == 0) {
+ if ((asr & SBIC_ASR_INT) || --wait < 0) {
+#ifdef DEBUG
+ if (sbic_debug) {
+ QPRINTF(("sbicxfin fail:{%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]));
+ printf("sbicxfin fail: l%d i%x w%d\n",
+ len, asr, wait);
+}
+#endif
+ return len;
+ }
+
+ if( ! asr & SBIC_ASR_BSY ) {
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("[CSR%02xASR%02x]", csr, asr));
+ }
+
+/* DELAY(1);*/
+ GET_SBIC_asr (regs, asr);
+ }
+
+ GET_SBIC_data (regs, *buf);
+/* QPRINTF(("asr=%02x, csr=%02x, data=%02x\n", asr, csr, *buf));*/
+ buf++;
+ }
+
+ QPRINTF(("sbicxfin {%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]));
+
+ /* this leaves with one csr to be read */
+ return len;
+}
+
+/*
+ * SCSI 'immediate' command: issue a command to some SCSI device
+ * and get back an 'immediate' response (i.e., do programmed xfer
+ * to get the response data). 'cbuf' is a buffer containing a scsi
+ * command of length clen bytes. 'buf' is a buffer of length 'len'
+ * bytes for data. The transfer direction is determined by the device
+ * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the
+ * command must supply no data.
+ */
+int
+sbicicmd(dev, target, lun, cbuf, clen, buf, len)
+ struct sbic_softc *dev;
+ void *cbuf, *buf;
+ int clen, len;
+{
+ sbic_regmap_p regs;
+ u_char phase, csr, asr;
+ int wait, newtarget, cmd_sent, parity_err;
+ struct sbic_acb *acb;
+
+ int discon;
+ int i;
+
+#define CSR_LOG_BUF_SIZE 0
+#if CSR_LOG_BUF_SIZE
+ int bufptr;
+ int csrbuf[CSR_LOG_BUF_SIZE];
+ bufptr=0;
+#endif
+
+ regs = dev->sc_sbicp;
+ acb = dev->sc_nexus;
+
+ /* Make sure pointers are OK */
+ dev->sc_last = dev->sc_cur = &acb->sc_pa;
+ dev->sc_tcnt = acb->sc_tcnt = 0;
+ acb->sc_pa.dc_count = 0; /* No DMA */
+ acb->sc_kv.dc_addr = buf;
+ acb->sc_kv.dc_count = len;
+
+#ifdef DEBUG
+ routine = 3;
+ debug_sbic_regs = regs; /* store this to allow debug calls */
+ if( data_pointer_debug > 1 )
+ printf("sbicicmd(%d,%d):%d\n", target, lun,
+ acb->sc_kv.dc_count);
+#endif
+
+ /*
+ * set the sbic into non-DMA mode
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI /*| SBIC_CTL_HSP*/);
+
+ dev->sc_stat[0] = 0xff;
+ dev->sc_msg[0] = 0xff;
+ i = 1; /* pre-load */
+
+ /* We're stealing the SCSI bus */
+ dev->sc_flags |= SBICF_ICMD;
+
+ do {
+ /*
+ * select the SCSI bus (it's an error if bus isn't free)
+ */
+ if (!( dev->sc_flags & SBICF_SELECTED )
+ && sbicselectbus(dev, regs, target, lun, dev->sc_scsiaddr)) {
+ /*printf("sbicicmd trying to select busy bus!\n");*/
+ dev->sc_flags &= ~SBICF_ICMD;
+ return(-1);
+ }
+
+ /*
+ * Wait for a phase change (or error) then let the device sequence
+ * us through the various SCSI phases.
+ */
+
+ wait = sbic_cmd_wait;
+
+ GET_SBIC_asr (regs, asr);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF((">ASR:%02xCSR:%02x<", asr, csr));
+
+#if CSR_LOG_BUF_SIZE
+ csrbuf[bufptr++] = csr;
+#endif
+
+
+ switch (csr) {
+ case SBIC_CSR_S_XFERRED:
+ case SBIC_CSR_DISC:
+ case SBIC_CSR_DISC_1:
+ dev->sc_flags &= ~SBICF_SELECTED;
+ GET_SBIC_cmd_phase (regs, phase);
+ if (phase == 0x60) {
+ GET_SBIC_tlun (regs, dev->sc_stat[0]);
+ i = 0; /* done */
+/* break; /* Bypass all the state gobldygook */
+ } else {
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicicmd: handling disconnect\n");
+#endif
+ i = SBIC_STATE_DISCONNECT;
+ }
+ break;
+
+ 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 (sbicxfstart(regs, clen, CMD_PHASE, sbic_cmd_wait))
+ if (sbicxfout(regs, clen,
+ cbuf, CMD_PHASE))
+ i = sbicabort(dev, regs,"icmd sending cmd");
+#if 0
+ GET_SBIC_csr(regs, csr); /* Lets us reload tcount */
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ if( asr & (SBIC_ASR_BSY|SBIC_ASR_LCI|SBIC_ASR_CIP) )
+ printf("next: cmd sent asr %02x, csr %02x\n",
+ asr, csr);
+#endif
+ break;
+
+#if 0
+ case SBIC_CSR_XFERRED|DATA_OUT_PHASE:
+ case SBIC_CSR_XFERRED|DATA_IN_PHASE:
+ case SBIC_CSR_MIS|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_1|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_1|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_2|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_2|DATA_IN_PHASE:
+ if (acb->sc_kv.dc_count <= 0)
+ i = sbicabort(dev, regs, "icmd out of data");
+ else {
+ wait = sbic_data_wait;
+ if (sbicxfstart(regs,
+ acb->sc_kv.dc_count,
+ SBIC_PHASE(csr), wait))
+ if (csr & 0x01)
+ /* data in? */
+ i=sbicxfin(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr);
+ else
+ i=sbicxfout(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr,
+ SBIC_PHASE(csr));
+ acb->sc_kv.dc_addr +=
+ (acb->sc_kv.dc_count - i);
+ acb->sc_kv.dc_count = i;
+ i = 1;
+ }
+ break;
+
+#endif
+ 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:
+ /*
+ * the sbic does the status/cmd-complete reading ok,
+ * so do this with its hi-level commands.
+ */
+#ifdef DEBUG
+ if(sbic_debug)
+ printf("SBICICMD status phase\n");
+#endif
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_cmd_phase(regs, 0x46);
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
+ break;
+
+#if THIS_IS_A_RESERVED_STATE
+ case BUS_FREE_PHASE: /* This is not legal */
+ if( dev->sc_stat[0] != 0xff )
+ goto out;
+ break;
+#endif
+
+ default:
+ i = sbicnextstate(dev, csr, asr);
+ }
+
+ /*
+ * make sure the last command was taken,
+ * ie. we're not hunting after an ignored command..
+ */
+ GET_SBIC_asr(regs, asr);
+
+ /* tapes may take a loooong time.. */
+ while (asr & SBIC_ASR_BSY){
+ if(asr & SBIC_ASR_DBR) {
+ printf("sbicicmd: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n",
+ csr,asr);
+#ifdef DDB
+ Debugger();
+#endif
+ /* SBIC is jammed */
+ /* DUNNO which direction */
+ /* Try old direction */
+ GET_SBIC_data(regs,i);
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR) /* Wants us to write */
+ SET_SBIC_data(regs,i);
+ }
+ GET_SBIC_asr(regs, asr);
+ }
+
+ /*
+ * wait for last command to complete
+ */
+ if (asr & SBIC_ASR_LCI) {
+ printf("sbicicmd: last command ignored\n");
+ }
+ else if( i == 1 ) /* Bsy */
+ SBIC_WAIT (regs, SBIC_ASR_INT, wait);
+
+ /*
+ * do it again
+ */
+ } while ( i > 0 && dev->sc_stat[0] == 0xff);
+
+ /* Sometimes we need to do an extra read of the CSR */
+ GET_SBIC_csr(regs, csr);
+
+#if CSR_LOG_BUF_SIZE
+ if(reselect_debug>1)
+ for(i=0; i<bufptr; i++)
+ printf("CSR:%02x", csrbuf[i]);
+#endif
+
+#ifdef DEBUG
+ if(data_pointer_debug > 1)
+ printf("sbicicmd done(%d,%d):%d =%d=\n",
+ dev->target, lun,
+ acb->sc_kv.dc_count,
+ dev->sc_stat[0]);
+#endif
+
+ QPRINTF(("=STS:%02x=", dev->sc_stat[0]));
+ dev->sc_flags &= ~SBICF_ICMD;
+
+ return(dev->sc_stat[0]);
+}
+
+/*
+ * Finish SCSI xfer command: After the completion interrupt from
+ * a read/write operation, sequence through the final phases in
+ * programmed i/o. This routine is a lot like sbicicmd except we
+ * skip (and don't allow) the select, cmd out and data in/out phases.
+ */
+void
+sbicxfdone(dev, regs, target)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int target;
+{
+ u_char phase, csr;
+ int s;
+
+ QPRINTF(("{"));
+ s = splbio();
+
+ /*
+ * have the sbic complete on its own
+ */
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_cmd_phase(regs, 0x46);
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
+
+ do {
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("%02x:", csr));
+ } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
+ && (csr != SBIC_CSR_S_XFERRED));
+
+ dev->sc_flags &= ~SBICF_SELECTED;
+
+ GET_SBIC_cmd_phase (regs, phase);
+ QPRINTF(("}%02x", phase));
+ if (phase == 0x60)
+ GET_SBIC_tlun(regs, dev->sc_stat[0]);
+ else
+ sbicerror(dev, regs, csr);
+
+ QPRINTF(("=STS:%02x=\n", dev->sc_stat[0]));
+ splx(s);
+}
+
+ /*
+ * No DMA chains
+ */
+
+int
+sbicgo(dev, xs)
+ struct sbic_softc *dev;
+ struct scsi_xfer *xs;
+{
+ int i, dmaflags, count, wait, usedma;
+ u_char csr, asr, cmd, *addr;
+ sbic_regmap_p regs;
+ struct sbic_acb *acb;
+
+ dev->target = xs->sc_link->target;
+ dev->lun = xs->sc_link->lun;
+ acb = dev->sc_nexus;
+ regs = dev->sc_sbicp;
+
+ usedma = sbicdmaok(dev, xs);
+#ifdef DEBUG
+ routine = 1;
+ debug_sbic_regs = regs; /* store this to allow debug calls */
+ if( data_pointer_debug > 1 )
+ printf("sbicgo(%d,%d)\n", dev->target, dev->lun);
+#endif
+
+ /*
+ * set the sbic into DMA mode
+ */
+ if( usedma )
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI |
+ SBIC_MACHINE_DMA_MODE);
+ else
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+
+ /*
+ * select the SCSI bus (it's an error if bus isn't free)
+ */
+ if (sbicselectbus(dev, regs, dev->target, dev->lun,
+ dev->sc_scsiaddr)) {
+/* printf("sbicgo: Trying to select busy bus!\n"); */
+ return(0); /* Not done: needs to be rescheduled */
+ }
+ dev->sc_stat[0] = 0xff;
+
+ /*
+ * Calculate DMA chains now
+ */
+
+ dmaflags = 0;
+ if (acb->flags & ACB_DATAIN)
+ dmaflags |= DMAGO_READ;
+
+
+ /*
+ * Deal w/bounce buffers.
+ */
+
+ addr = acb->sc_kv.dc_addr;
+ count = acb->sc_kv.dc_count;
+ if (count && (char *)kvtop(addr) != acb->sc_pa.dc_addr) { /* XXXX check */
+ printf("sbic: DMA buffer mapping changed %x->%x\n",
+ acb->sc_pa.dc_addr, kvtop(addr));
+#ifdef DDB
+ Debugger();
+#endif
+ }
+
+#ifdef DEBUG
+ ++sbicdma_ops; /* count total DMA operations */
+#endif
+ if (count && usedma && dev->sc_flags & SBICF_BADDMA &&
+ sbiccheckdmap(addr, count, dev->sc_dmamask)) {
+ /*
+ * need to bounce the dma.
+ */
+ if (dmaflags & DMAGO_READ) {
+ acb->flags |= ACB_BBUF;
+ acb->sc_dmausrbuf = addr;
+ acb->sc_dmausrlen = count;
+ acb->sc_usrbufpa = (u_char *)kvtop(addr);
+ if(!dev->sc_tinfo[dev->target].bounce) {
+ printf("sbicgo: HELP! no bounce allocated for %d\n",
+ dev->target);
+ printf("xfer: (%x->%x,%x)\n", acb->sc_dmausrbuf,
+ acb->sc_usrbufpa, acb->sc_dmausrlen);
+#if 0
+ dev->sc_tinfo[xs->sc_link->target].bounce
+ = (char *)alloc_z2mem(MAXPHYS);
+ if (isztwomem(dev->sc_tinfo[xs->sc_link->target].bounce))
+ printf("alloc ZII target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ kvtop(dev->sc_tinfo[xs->sc_link->target].bounce));
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce)
+ printf("alloc CHIP target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ PREP_DMA_MEM(dev->sc_tinfo[xs->sc_link->target].bounce));
+#endif
+
+ printf("Allocating %d bounce at %x\n",
+ dev->target,
+ kvtop(dev->sc_tinfo[dev->target].bounce));
+ }
+ } else { /* write: copy to dma buffer */
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("sbicgo: copying %x bytes to target %d bounce %x\n",
+ count, dev->target,
+ kvtop(dev->sc_tinfo[dev->target].bounce));
+#endif
+ bcopy (addr, dev->sc_tinfo[dev->target].bounce, count);
+ }
+ addr = dev->sc_tinfo[dev->target].bounce;/* and use dma buffer */
+ acb->sc_kv.dc_addr = addr;
+#ifdef DEBUG
+ ++sbicdma_bounces; /* count number of bounced */
+#endif
+ }
+
+ /*
+ * Allocate the DMA chain
+ */
+
+ /* Set start KVM addresses */
+#if 0
+ acb->sc_kv.dc_addr = addr;
+ acb->sc_kv.dc_count = count;
+#endif
+
+ /* Mark end of segment */
+ acb->sc_tcnt = dev->sc_tcnt = 0;
+ acb->sc_pa.dc_count = 0;
+
+ sbic_load_ptrs(dev, regs, dev->target, dev->lun);
+ /* Enable interrupts but don't do any DMA */
+ dev->sc_tcnt = dev->sc_dmago(dev, acb->sc_pa.dc_addr,
+ acb->sc_pa.dc_count,
+ dmaflags);
+ dev->sc_flags |= SBICF_INDMA;
+ if( !usedma )
+ dev->sc_dmacmd = 0; /* Don't use DMA */
+/* SBIC_TC_PUT(regs, dev->sc_tcnt); /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+
+ /*
+ * push the data cache ( I think this won't work (EH))
+ */
+#if defined(M68040)
+ if (mmutype == MMU_68040 && usedma && count) {
+ dma_cachectl(addr, count);
+ if (((u_int)addr & 0xF) || (((u_int)addr + count) & 0xF))
+ dev->sc_flags |= SBICF_DCFLUSH;
+ }
+#endif
+
+ /*
+ * dmago() also enables interrupts for the sbic
+ */
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("sbicgo dmago:%d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+ if( sbic_timeout && !timeout_active ) {
+ timeout((void *)sbictimeout, (void*)dev, sbic_timeout * hz);
+ timeout_active = 1;
+ }
+ debug_asr = asr;
+ debug_csr = csr;
+#endif
+
+ /*
+ * Lets cycle a while then let the interrupt handler take over
+ */
+
+ GET_SBIC_asr(regs, asr);
+ do {
+ GET_SBIC_csr(regs, csr);
+#ifdef DEBUG
+ debug_csr = csr;
+ routine = 1;
+#endif
+ QPRINTF(("go[0x%x]", csr));
+
+ i = sbicnextstate(dev, csr, asr);
+
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+#ifdef DEBUG
+ debug_asr = asr;
+#endif
+ if(asr & SBIC_ASR_LCI) printf("sbicgo: LCI asr:%02x csr:%02x\n",
+ asr,csr);
+ } while( i == SBIC_STATE_RUNNING
+ && asr & (SBIC_ASR_INT|SBIC_ASR_LCI) );
+
+ if (i == SBIC_STATE_DONE && dev->sc_stat[0] != 0xff) {
+ /* Did we really finish that fast? */
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+sbicintr(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ struct dma_chain *df, *dl;
+ u_char asr, csr, *tmpaddr;
+ struct sbic_acb *acb;
+ int i, newtarget, newlun;
+ unsigned tcnt;
+
+ regs = dev->sc_sbicp;
+
+ /*
+ * pending interrupt?
+ */
+ GET_SBIC_asr (regs, asr);
+ if ((asr & SBIC_ASR_INT) == 0)
+ return(0);
+
+ do {
+ GET_SBIC_csr(regs, csr);
+#ifdef DEBUG
+ debug_csr = csr;
+ routine = 2;
+#endif
+ QPRINTF(("intr[0x%x]", csr));
+
+ i = sbicnextstate(dev, csr, asr);
+
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+#ifdef DEBUG
+ debug_asr = asr;
+#endif
+#if 0
+ if(asr & SBIC_ASR_LCI) printf("sbicintr: LCI asr:%02x csr:%02x\n",
+ asr,csr);
+#endif
+ } while(i == SBIC_STATE_RUNNING &&
+ asr & (SBIC_ASR_INT|SBIC_ASR_LCI));
+ return(1);
+}
+
+/*
+ * Run commands and wait for disconnect
+ */
+int
+sbicpoll(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ u_char asr, csr;
+ struct sbic_pending* pendp;
+ int i;
+ unsigned tcnt;
+
+ regs = dev->sc_sbicp;
+
+ do {
+ GET_SBIC_asr (regs, asr);
+#ifdef DEBUG
+ debug_asr = asr;
+#endif
+ GET_SBIC_csr(regs, csr);
+#ifdef DEBUG
+ debug_csr = csr;
+ routine = 2;
+#endif
+ QPRINTF(("poll[0x%x]", csr));
+
+ i = sbicnextstate(dev, csr, asr);
+
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ /* tapes may take a loooong time.. */
+ while (asr & SBIC_ASR_BSY){
+ if(asr & SBIC_ASR_DBR) {
+ printf("sbipoll: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n",
+ csr,asr);
+#ifdef DDB
+ Debugger();
+#endif
+ /* SBIC is jammed */
+ /* DUNNO which direction */
+ /* Try old direction */
+ GET_SBIC_data(regs,i);
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR) /* Wants us to write */
+ SET_SBIC_data(regs,i);
+ }
+ GET_SBIC_asr(regs, asr);
+ }
+
+ if(asr & SBIC_ASR_LCI) printf("sbicpoll: LCI asr:%02x csr:%02x\n",
+ asr,csr);
+ else if( i == 1 ) /* BSY */
+ SBIC_WAIT(regs, SBIC_ASR_INT, sbic_cmd_wait);
+ } while(i == SBIC_STATE_RUNNING);
+ return(1);
+}
+
+/*
+ * Handle a single msgin
+ */
+
+int
+sbicmsgin(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ int recvlen;
+ u_char asr, csr, *tmpaddr;
+
+ regs = dev->sc_sbicp;
+
+ dev->sc_msg[0] = 0xff;
+ dev->sc_msg[1] = 0xff;
+
+ GET_SBIC_asr(regs, asr);
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicmsgin asr=%02x\n", asr);
+#endif
+
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+
+ GET_SBIC_selid (regs, csr);
+ SET_SBIC_selid (regs, csr | SBIC_SID_FROM_SCSI);
+
+ SBIC_TC_PUT(regs, 0);
+ tmpaddr = dev->sc_msg;
+ recvlen = 1;
+ do {
+ while( recvlen-- ) {
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("sbicmsgin ready to go (csr,asr)=(%02x,%02x)\n",
+ csr, asr));
+
+ RECV_BYTE(regs, *tmpaddr);
+#if 1
+ /*
+ * get the command completion interrupt, or we
+ * can't send a new command (LCI)
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr);
+#else
+ WAIT_CIP(regs);
+ do {
+ GET_SBIC_asr(regs, asr);
+ csr = 0xff;
+ GET_SBIC_csr(regs, csr);
+ if( csr == 0xff )
+ printf("sbicmsgin waiting: csr %02x asr %02x\n", csr, asr);
+ } while( csr == 0xff );
+#endif
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicmsgin: got %02x csr %02x asr %02x\n",
+ *tmpaddr, csr, asr);
+#endif
+#if do_parity_check
+ if( asr & SBIC_ASR_PE ) {
+ printf ("Parity error");
+ /* This code simply does not work. */
+ WAIT_CIP(regs);
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ WAIT_CIP(regs);
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ WAIT_CIP(regs);
+ if( !(asr & SBIC_ASR_LCI) )
+ /* Target wants to send garbled msg*/
+ continue;
+ printf("--fixing\n");
+ /* loop until a msgout phase occurs on target */
+ while(csr & 0x07 != MESG_OUT_PHASE) {
+ while( asr & SBIC_ASR_BSY &&
+ !(asr & SBIC_ASR_DBR|SBIC_ASR_INT) )
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR )
+ panic("msgin: jammed again!\n");
+ GET_SBIC_csr(regs, csr);
+ if( csr & 0x07 != MESG_OUT_PHASE ) {
+ sbicnextstate(dev, csr, asr);
+ sbic_save_ptrs(dev, regs,
+ dev->target,
+ dev->lun);
+ }
+ }
+ /* Should be msg out by now */
+ SEND_BYTE(regs, MSG_PARITY_ERROR);
+ }
+ else
+#endif
+ tmpaddr++;
+
+ if(recvlen) {
+ /* Clear ACK */
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("sbicmsgin pre byte CLR_ACK (csr,asr)=(%02x,%02x)\n",
+ csr, asr));
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ }
+
+ };
+
+ if(dev->sc_msg[0] == 0xff) {
+ printf("sbicmsgin: sbic swallowed our message\n");
+ break;
+ }
+#ifdef DEBUG
+ if (sync_debug)
+ printf("msgin done csr 0x%x asr 0x%x msg 0x%x\n",
+ csr, asr, dev->sc_msg[0]);
+#endif
+ /*
+ * test whether this is a reply to our sync
+ * request
+ */
+ if (MSG_ISIDENTIFY(dev->sc_msg[0])) {
+ QPRINTF(("IFFY"));
+#if 0
+ /* There is an implied load-ptrs here */
+ sbic_load_ptrs(dev, regs, dev->target, dev->lun);
+#endif
+ /* Got IFFY msg -- ack it */
+ } else if (dev->sc_msg[0] == MSG_REJECT
+ && dev->sc_sync[dev->target].state == SYNC_SENT) {
+ QPRINTF(("REJECT of SYN"));
+#ifdef DEBUG
+ if (sync_debug)
+ printf("target %d rejected sync, going async\n",
+ dev->target);
+#endif
+ dev->sc_sync[dev->target].period = sbic_min_period;
+ dev->sc_sync[dev->target].offset = 0;
+ dev->sc_sync[dev->target].state = SYNC_DONE;
+ SET_SBIC_syn(regs,
+ SBIC_SYN(dev->sc_sync[dev->target].offset,
+ dev->sc_sync[dev->target].period));
+ } else if ((dev->sc_msg[0] == MSG_REJECT)) {
+ QPRINTF(("REJECT"));
+ /*
+ * we'll never REJECt a REJECT message..
+ */
+ } else if ((dev->sc_msg[0] == MSG_SAVE_DATA_PTR)) {
+ QPRINTF(("MSG_SAVE_DATA_PTR"));
+ /*
+ * don't reject this either.
+ */
+ } else if ((dev->sc_msg[0] == MSG_DISCONNECT)) {
+ QPRINTF(("DISCONNECT"));
+#ifdef DEBUG
+ if( reselect_debug>1 && dev->sc_msg[0] == MSG_DISCONNECT )
+ printf("sbicmsgin: got disconnect msg %s\n",
+ (dev->sc_flags & SBICF_ICMD)?"rejecting":"");
+#endif
+ if( dev->sc_flags & SBICF_ICMD ) {
+ /* We're in immediate mode. Prevent disconnects. */
+ /* prepare to reject the message, NACK */
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ }
+ } else if (dev->sc_msg[0] == MSG_CMD_COMPLETE ) {
+ QPRINTF(("CMD_COMPLETE"));
+ /* !! 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.
+ */
+
+#ifdef DEBUG
+ if (sync_debug)
+ printf ("GOT MSG %d! target %d acting weird.."
+ " waiting for disconnect...\n",
+ dev->sc_msg[0], dev->target);
+#endif
+ /* Check to see if sbic is handling this */
+ GET_SBIC_asr(regs, asr);
+ if(asr & SBIC_ASR_BSY)
+ return SBIC_STATE_RUNNING;
+
+ /* Let's try this: Assume it works and set status to 00 */
+ dev->sc_stat[0] = 0;
+ } else if (dev->sc_msg[0] == MSG_EXT_MESSAGE
+ && tmpaddr == &dev->sc_msg[1]) {
+ QPRINTF(("ExtMSG\n"));
+ /* Read in whole extended message */
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("CLR ACK asr %02x, csr %02x\n", asr, csr));
+ RECV_BYTE(regs, *tmpaddr);
+ /* Wait for command completion IRQ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ recvlen = *tmpaddr++;
+ QPRINTF(("Recving ext msg, asr %02x csr %02x len %02x\n",
+ asr, csr, recvlen));
+ } else if (dev->sc_msg[0] == MSG_EXT_MESSAGE && dev->sc_msg[1] == 3
+ && dev->sc_msg[2] == MSG_SYNC_REQ) {
+ QPRINTF(("SYN"));
+ dev->sc_sync[dev->target].period =
+ sbicfromscsiperiod(dev,
+ regs, dev->sc_msg[3]);
+ dev->sc_sync[dev->target].offset = dev->sc_msg[4];
+ dev->sc_sync[dev->target].state = SYNC_DONE;
+ SET_SBIC_syn(regs,
+ SBIC_SYN(dev->sc_sync[dev->target].offset,
+ dev->sc_sync[dev->target].period));
+ printf("%s: target %d now synchronous,"
+ " period=%dns, offset=%d.\n",
+ dev->sc_dev.dv_xname, dev->target,
+ dev->sc_msg[3] * 4, dev->sc_msg[4]);
+ } else {
+#ifdef DEBUG
+ if (sbic_debug || sync_debug)
+ printf ("sbicmsgin: Rejecting message 0x%02x\n",
+ dev->sc_msg[0]);
+#endif
+ /* prepare to reject the message, NACK */
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ }
+ /* Clear ACK */
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("sbicmsgin pre CLR_ACK (csr,asr)=(%02x,%02x)%d\n",
+ csr, asr, recvlen));
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ }
+#if 0
+ while((csr == SBIC_CSR_MSGIN_W_ACK)
+ || (SBIC_PHASE(csr) == MESG_IN_PHASE));
+#else
+ while (recvlen>0);
+#endif
+
+ QPRINTF(("sbicmsgin finished: csr %02x, asr %02x\n",csr, asr));
+
+ /* Should still have one CSR to read */
+ return SBIC_STATE_RUNNING;
+}
+
+
+/*
+ * sbicnextstate()
+ * return:
+ * 0 == done
+ * 1 == working
+ * 2 == disconnected
+ * -1 == error
+ */
+int
+sbicnextstate(dev, csr, asr)
+ struct sbic_softc *dev;
+ u_char csr, asr;
+{
+ sbic_regmap_p regs;
+ struct dma_chain *df, *dl;
+ struct sbic_acb *acb;
+ int i, newtarget, newlun, wait;
+ unsigned tcnt;
+
+ regs = dev->sc_sbicp;
+ acb = dev->sc_nexus;
+
+ QPRINTF(("next[%02x,%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:
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+ if (sbicxfstart(regs, acb->clen, CMD_PHASE, sbic_cmd_wait))
+ if (sbicxfout(regs, acb->clen,
+ &acb->cmd, CMD_PHASE))
+ 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:
+ /*
+ * this should be the normal i/o completion case.
+ * get the status & cmd complete msg then let the
+ * device driver look at what happened.
+ */
+ sbicxfdone(dev,regs,dev->target);
+ /*
+ * check for overlapping cache line, flush if so
+ */
+#ifdef M68040
+ if (dev->sc_flags & SBICF_DCFLUSH) {
+#if 0
+ printf("sbic: 68040 DMA cache flush needs fixing? %x:%x\n",
+ dev->sc_xs->data, dev->sc_xs->datalen);
+#endif
+ }
+#endif
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+#endif
+ dev->sc_dmastop(dev); /* was dmafree */
+ if (acb->flags & ACB_BBUF) {
+ if ((u_char *)kvtop(acb->sc_dmausrbuf) != acb->sc_usrbufpa)
+ printf("%s: WARNING - buffer mapping changed %x->%x\n",
+ dev->sc_dev.dv_xname, acb->sc_usrbufpa,
+ kvtop(acb->sc_dmausrbuf));
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("sbicgo:copying %x bytes from target %d bounce %x\n",
+ acb->sc_dmausrlen,
+ dev->target,
+ kvtop(dev->sc_tinfo[dev->target].bounce));
+#endif
+ bcopy(dev->sc_tinfo[dev->target].bounce,
+ acb->sc_dmausrbuf,
+ acb->sc_dmausrlen);
+ }
+ dev->sc_flags &= ~(SBICF_INDMA | SBICF_DCFLUSH);
+ sbic_scsidone(acb, dev->sc_stat[0]);
+ return SBIC_STATE_DONE;
+
+ case SBIC_CSR_XFERRED|DATA_OUT_PHASE:
+ case SBIC_CSR_XFERRED|DATA_IN_PHASE:
+ case SBIC_CSR_MIS|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_1|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_1|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_2|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_2|DATA_IN_PHASE:
+ if( dev->sc_xs->flags & SCSI_POLL || dev->sc_flags & SBICF_ICMD
+ || acb->sc_dmacmd == 0 ) {
+ /* Do PIO */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ if (acb->sc_kv.dc_count <= 0) {
+ printf("sbicnextstate:xfer count %d asr%x csr%x\n",
+ acb->sc_kv.dc_count, asr, csr);
+ goto abort;
+ }
+ wait = sbic_data_wait;
+ if( sbicxfstart(regs,
+ acb->sc_kv.dc_count,
+ SBIC_PHASE(csr), wait))
+ if( SBIC_PHASE(csr) == DATA_IN_PHASE )
+ /* data in? */
+ i=sbicxfin(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr);
+ else
+ i=sbicxfout(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr,
+ SBIC_PHASE(csr));
+ acb->sc_kv.dc_addr +=
+ (acb->sc_kv.dc_count - i);
+ acb->sc_kv.dc_count = i;
+ } else {
+ /*
+ * do scatter-gather dma
+ * hacking the controller chip, ouch..
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI |
+ SBIC_MACHINE_DMA_MODE);
+ /*
+ * set next dma addr and dec count
+ */
+#if 0
+ SBIC_TC_GET(regs, tcnt);
+ dev->sc_cur->dc_count -= ((dev->sc_tcnt - tcnt) >> 1);
+ dev->sc_cur->dc_addr += (dev->sc_tcnt - tcnt);
+ dev->sc_tcnt = acb->sc_tcnt = tcnt;
+#else
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+ sbic_load_ptrs(dev, regs, dev->target, dev->lun);
+#endif
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmanext: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,
+ dev->sc_tcnt);
+#endif
+ dev->sc_tcnt = dev->sc_dmanext(dev);
+ SBIC_TC_PUT(regs, (unsigned)dev->sc_tcnt);
+ SET_SBIC_cmd(regs, SBIC_CMD_XFER_INFO);
+ dev->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:
+ return sbicmsgin(dev);
+
+ case SBIC_CSR_MSGIN_W_ACK:
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK); /* Dunno what I'm ACKing */
+ 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:
+#ifdef DEBUG
+ if (sync_debug)
+ printf ("sending REJECT msg to last msg.\n");
+#endif
+
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+ /*
+ * should only get here on reject,
+ * since it's always US that
+ * initiate a sync transfer
+ */
+ SEND_BYTE(regs, MSG_REJECT);
+ WAIT_CIP(regs);
+ if( asr & (SBIC_ASR_BSY|SBIC_ASR_LCI|SBIC_ASR_CIP) )
+ printf("next: REJECT sent asr %02x\n", asr);
+ return SBIC_STATE_RUNNING;
+
+ case SBIC_CSR_DISC:
+ case SBIC_CSR_DISC_1:
+ dev->sc_flags &= ~(SBICF_INDMA|SBICF_SELECTED);
+
+ /* Try to schedule another target */
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicnext target %d disconnected\n", dev->target);
+#endif
+ TAILQ_INSERT_HEAD(&dev->nexus_list, acb, chain);
+ ++dev->sc_tinfo[dev->target].dconns;
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+
+ if( acb->xs->flags & SCSI_POLL
+ || (dev->sc_flags & SBICF_ICMD)
+ || !sbic_parallel_operations )
+ return SBIC_STATE_DISCONNECT;
+ sbic_sched(dev);
+ return SBIC_STATE_DISCONNECT;
+
+ case SBIC_CSR_RSLT_NI:
+ case SBIC_CSR_RSLT_IFY:
+ GET_SBIC_rselid(regs, newtarget);
+ /* check SBIC_RID_SIV? */
+ newtarget &= SBIC_RID_MASK;
+ if (csr == SBIC_CSR_RSLT_IFY) {
+ /* Read IFY msg to avoid lockup */
+ GET_SBIC_data(regs, newlun);
+ WAIT_CIP(regs);
+ newlun &= SBIC_TLUN_MASK;
+ } else {
+ /* Need to get IFY message */
+ for (newlun = 256; newlun; --newlun) {
+ GET_SBIC_asr(regs, asr);
+ if (asr & SBIC_ASR_INT)
+ break;
+ delay(1);
+ }
+ newlun = 0; /* XXXX */
+ if ((asr & SBIC_ASR_INT) == 0) {
+#ifdef DEBUG
+ if (reselect_debug)
+ printf("RSLT_NI - no IFFY message? asr %x\n", asr);
+#endif
+ } else {
+ GET_SBIC_csr(regs,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) {
+ sbicmsgin(dev);
+ newlun = dev->sc_msg[0] & 7;
+ } else {
+ printf("RSLT_NI - not MESG_IN_PHASE %x\n",
+ csr);
+ }
+ }
+ }
+#ifdef DEBUG
+ if(reselect_debug>1 || (reselect_debug && csr==SBIC_CSR_RSLT_NI))
+ printf("sbicnext: reselect %s from targ %d lun %d\n",
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY",
+ newtarget, newlun);
+#endif
+ if (dev->sc_nexus) {
+#ifdef DEBUG
+ if (reselect_debug > 1)
+ printf("%s: reselect %s with active command\n",
+ dev->sc_dev.dv_xname,
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY");
+#ifdef DDB
+/* Debugger();*/
+#endif
+#endif
+ TAILQ_INSERT_HEAD(&dev->ready_list, dev->sc_nexus, chain);
+ dev->sc_tinfo[dev->target].lubusy &= ~(1 << dev->lun);
+ }
+ /* Reload sync values for this target */
+ if (dev->sc_sync[newtarget].state == SYNC_DONE)
+ SET_SBIC_syn(regs, SBIC_SYN (dev->sc_sync[newtarget].offset,
+ dev->sc_sync[newtarget].period));
+ else
+ SET_SBIC_syn(regs, SBIC_SYN (0, sbic_min_period));
+ for (acb = dev->nexus_list.tqh_first; acb;
+ acb = acb->chain.tqe_next) {
+ if (acb->xs->sc_link->target != newtarget ||
+ acb->xs->sc_link->lun != newlun)
+ continue;
+ TAILQ_REMOVE(&dev->nexus_list, acb, chain);
+ dev->sc_nexus = acb;
+ dev->sc_xs = acb->xs;
+ dev->sc_flags |= SBICF_SELECTED;
+ dev->target = newtarget;
+ dev->lun = newlun;
+ break;
+ }
+ if (acb == NULL) {
+ printf("%s: reselect %s targ %d not in nexus_list %x\n",
+ dev->sc_dev.dv_xname,
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY", newtarget,
+ &dev->nexus_list.tqh_first);
+ panic("bad reselect in sbic");
+ }
+ if (csr == SBIC_CSR_RSLT_IFY)
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ break;
+
+ default:
+ abort:
+ /*
+ * Something unexpected happened -- deal with it.
+ */
+ printf("sbicnextstate: aborting csr %02x asr %02x\n", csr, asr);
+#ifdef DDB
+ Debugger();
+#endif
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+#endif
+ dev->sc_dmastop(dev);
+ sbicerror(dev, regs, csr);
+ sbicabort(dev, regs, "next");
+ if (dev->sc_flags & SBICF_INDMA) {
+ /*
+ * check for overlapping cache line, flush if so
+ */
+#ifdef M68040
+ if (dev->sc_flags & SBICF_DCFLUSH) {
+#if 0
+ printf("sibc: 68040 DMA cache flush needs fixing? %x:%x\n",
+ dev->sc_xs->data, dev->sc_xs->datalen);
+#endif
+ }
+#endif
+ dev->sc_flags &=
+ ~(SBICF_INDMA | SBICF_DCFLUSH);
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+#endif
+ dev->sc_dmastop(dev);
+ sbic_scsidone(acb, -1);
+ }
+ return SBIC_STATE_ERROR;
+ }
+
+ return(SBIC_STATE_RUNNING);
+}
+
+
+/*
+ * Check if DMA can not be used with specified buffer
+ */
+
+int
+sbiccheckdmap(bp, len, mask)
+ void *bp;
+ u_long len, mask;
+{
+ u_char *buffer;
+ u_long phy_buf;
+ u_long phy_len;
+
+ buffer = bp;
+
+ if (len == 0)
+ return(0);
+
+ while (len) {
+ phy_buf = kvtop(buffer);
+ if (len < (phy_len = NBPG - ((int) buffer & PGOFSET)))
+ phy_len = len;
+ if (phy_buf & mask)
+ return(1);
+ buffer += phy_len;
+ len -= phy_len;
+ }
+ return(0);
+}
+
+int
+sbictoscsiperiod(dev, regs, a)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int a;
+{
+ unsigned int fs;
+
+ /*
+ * cycle = DIV / (2*CLK)
+ * DIV = FS+2
+ * best we can do is 200ns at 20Mhz, 2 cycles
+ */
+
+ GET_SBIC_myid(regs,fs);
+ fs = (fs >>6) + 2; /* DIV */
+ fs = (fs * 10000) / (dev->sc_clkfreq<<1); /* Cycle, in ns */
+ if (a < 2) a = 8; /* map to Cycles */
+ return ((fs*a)>>2); /* in 4 ns units */
+}
+
+int
+sbicfromscsiperiod(dev, regs, p)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int p;
+{
+ register unsigned int fs, ret;
+
+ /* Just the inverse of the above */
+
+ GET_SBIC_myid(regs,fs);
+ fs = (fs >>6) + 2; /* DIV */
+ fs = (fs * 10000) / (dev->sc_clkfreq<<1); /* Cycle, in ns */
+
+ ret = p << 2; /* in ns units */
+ ret = ret / fs; /* in Cycles */
+ if (ret < sbic_min_period)
+ return(sbic_min_period);
+
+ /* verify rounding */
+ if (sbictoscsiperiod(dev, regs, ret) < p)
+ ret++;
+ return (ret >= 8) ? 0 : ret;
+}
+
+#ifdef DEBUG
+
+void sbicdumpstate()
+{
+ u_char csr, asr;
+
+ GET_SBIC_asr(debug_sbic_regs,asr);
+ GET_SBIC_csr(debug_sbic_regs,csr);
+ printf("%s: asr:csr(%02x:%02x)->(%02x:%02x)\n",
+ (routine==1)?"sbicgo":
+ (routine==2)?"sbicintr":
+ (routine==3)?"sbicicmd":
+ (routine==4)?"sbicnext":"unknown",
+ debug_asr, debug_csr, asr, csr);
+
+}
+
+void sbictimeout(dev)
+ struct sbic_softc *dev;
+{
+ int s, asr;
+
+ /* Dump this every second while there's an active command */
+ if( dev->sc_nexus ) {
+ s = splbio();
+ GET_SBIC_asr(dev->sc_sbicp, asr);
+ if( asr & SBIC_ASR_INT ) {
+ /* We need to service a missed IRQ */
+ printf("Servicing a missed int:(%02x,%02x)->(%02x,??)\n",
+ debug_asr, debug_csr, asr);
+ sbicintr(dev);
+ }
+ splx(s);
+ sbicdumpstate();
+ timeout((void *)sbictimeout, (void*)dev, sbic_timeout * hz);
+ } else timeout_active = 0;
+}
+
+#endif
diff --git a/sys/arch/mvme68k/dev/sbicdma.c b/sys/arch/mvme68k/dev/sbicdma.c
new file mode 100644
index 00000000000..193cc674efa
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbicdma.c
@@ -0,0 +1,278 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 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.
+ */
+
+/*
+ * as you may guess by some of the routines in this file,
+ * dma is not yet working. - its on the TODO list
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <vm/vm.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <machine/autoconf.h>
+#include <mvme68k/dev/pccreg.h>
+#include <mvme68k/dev/sbicreg.h>
+#include <mvme68k/dev/sbicvar.h>
+#include <mvme68k/dev/dmavar.h>
+
+void sbicdmaattach __P((struct device *, struct device *, void *));
+int sbicdmamatch __P((struct device *, void *, void *));
+int sbicdmaprint __P((void *auxp, char *));
+
+void sbicdma_dmafree __P((struct sbic_softc *));
+void sbicdma_dmastop __P((struct sbic_softc *));
+int sbicdma_dmanext __P((struct sbic_softc *));
+int sbicdma_dmago __P((struct sbic_softc *, char *, int, int));
+int sbicdma_dmaintr __P((struct sbic_softc *));
+int sbicdma_scintr __P((struct sbic_softc *));
+
+struct scsi_adapter sbicdma_scsiswitch = {
+ sbic_scsicmd,
+ sbic_minphys,
+ 0, /* no lun support */
+ 0, /* no lun support */
+};
+
+struct scsi_device sbicdma_scsidev = {
+ NULL, /* use default error handler */
+ NULL, /* have a queue served by this ??? */
+ NULL, /* have no async handler ??? */
+ NULL, /* Use default done routine */
+};
+
+#ifdef DEBUG
+int sbicdma_debug = 1;
+#endif
+
+int sbicdma_maxdma = 0; /* Maximum size per DMA transfer */
+int sbicdma_dmamask = 0;
+int sbicdma_dmabounce = 0;
+
+struct cfdriver sbiccd = {
+ NULL, "sbic", sbicdmamatch, sbicdmaattach,
+ DV_DULL, sizeof(struct sbic_softc),
+};
+
+int
+sbicdmamatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ /*
+ * XXX finish to properly probe
+ */
+ return (1);
+}
+
+void
+sbicdmaattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct sbic_softc *sc = (struct sbic_softc *)self;
+ struct pccreg *pcc;
+ struct confargs *ca = args;
+
+ sc->sc_cregs = (struct pccreg *)ca->ca_master;
+ sc->sc_dmafree = sbicdma_dmafree;
+ sc->sc_dmago = sbicdma_dmago;
+ sc->sc_dmanext = sbicdma_dmanext;
+ sc->sc_dmastop = sbicdma_dmastop;
+ sc->sc_dmacmd = 0;
+
+ sc->sc_flags |= SBICF_BADDMA;
+ sc->sc_dmamask = 0;
+ sc->sc_sbicp = (sbic_regmap_p)ca->ca_vaddr;
+ sc->sc_clkfreq = 100;
+
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = 7;
+ sc->sc_link.adapter = &sbicdma_scsiswitch;
+ sc->sc_link.device = &sbicdma_scsidev;
+ sc->sc_link.openings = 1;
+
+ printf(": target %d\n", sc->sc_link.adapter_target);
+
+ /* connect the interrupts */
+ sc->sc_ih.ih_fn = sbicdma_scintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+ pccintr_establish(PCCV_SBIC, &sc->sc_ih);
+
+ sc->sc_dmaih.ih_fn = sbicdma_dmaintr;
+ sc->sc_dmaih.ih_arg = sc;
+ sc->sc_dmaih.ih_ipl = ca->ca_ipl;
+ pccintr_establish(PCCV_DMA, &sc->sc_dmaih);
+
+ pcc = (struct pccreg *)sc->sc_cregs;
+ pcc->pcc_dmairq = sc->sc_dmaih.ih_ipl | PCC_IRQ_INT;
+ pcc->pcc_sbicirq = sc->sc_ih.ih_ipl | PCC_SBIC_RESETIRQ;
+
+ sbicreset(sc);
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_dmaintrcnt);
+
+ config_found(self, &sc->sc_link, sbicdmaprint);
+}
+
+/*
+ * print diag if pnp is NULL else just extra
+ */
+int
+sbicdmaprint(auxp, pnp)
+ void *auxp;
+ char *pnp;
+{
+ if (pnp == NULL)
+ return (UNCONF);
+ return (QUIET);
+}
+
+int
+sbicdma_dmago(sc, va, count, flags)
+ struct sbic_softc *sc;
+ char *va;
+ int count, flags;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+ u_char csr;
+ u_long pa;
+
+ pa = (u_long)pmap_extract(pmap_kernel(), (vm_offset_t)va);
+#ifdef DEBUG
+ if (sbicdma_debug)
+ printf("%s: dmago: va 0x%x pa 0x%x cnt %d flags %x\n",
+ sc->sc_dev.dv_xname, va, pa, count, flags);
+#endif
+
+ sc->sc_flags |= SBICF_INTR;
+ pcc->pcc_dmadaddr = (u_long)pa;
+ if (count & PCC_DMABCNT_CNTMASK) {
+ printf("%s: dma count 0x%x too large\n",
+ sc->sc_dev.dv_xname, count);
+ return (0);
+ }
+ pcc->pcc_dmabcnt = (PCC_DMABCNT_MAKEFC(FC_USERD)) |
+ (count & PCC_DMABCNT_CNTMASK);
+
+ /* make certain interupts are disabled first, and reset */
+ pcc->pcc_dmairq = sc->sc_dmaih.ih_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
+ pcc->pcc_sbicirq = sc->sc_ih.ih_ipl | PCC_SBIC_RESETIRQ | PCC_IRQ_IEN;
+ pcc->pcc_dmacsr = 0;
+ pcc->pcc_dmacsr = PCC_DMACSR_DEN |
+ ((flags & DMAGO_READ) == 0) ? PCC_DMACSR_TOSCSI : 0;
+
+ return (sc->sc_tcnt);
+}
+
+int
+sbicdma_dmaintr(sc)
+ struct sbic_softc *sc;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+ u_char stat;
+ int ret = 0;
+
+ /* DMA done */
+ stat = pcc->pcc_dmacsr;
+printf("dmaintr%d ", stat);
+ if (stat & PCC_DMACSR_DONE) {
+ pcc->pcc_dmacsr = 0;
+ pcc->pcc_dmairq = 0; /* ack and remove intr */
+ if (stat & PCC_DMACSR_ERR8BIT) {
+ printf("%s: 8 bit error\n", sc->sc_dev.dv_xname);
+ }
+ if (stat & PCC_DMACSR_DMAERRDATA) {
+ printf("%s: DMA bus error\n", sc->sc_dev.dv_xname);
+ }
+ sc->sc_dmaintrcnt.ev_count++;
+ return (1);
+ }
+ return (0);
+}
+
+int
+sbicdma_scintr(sc)
+ struct sbic_softc *sc;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+ u_char stat;
+ int ret = 0;
+
+printf("scintr%d ", stat);
+ stat = pcc->pcc_sbicirq;
+ if (stat & PCC_SBIC_RESETIRQ) {
+ printf("%s: scintr: a scsi device pulled reset\n",
+ sc->sc_dev.dv_xname);
+ pcc->pcc_sbicirq = pcc->pcc_sbicirq | PCC_SBIC_RESETIRQ;
+ } else if (stat & PCC_IRQ_INT) {
+ pcc->pcc_sbicirq = 0;
+ sbicintr(sc);
+ ret = 1;
+ sc->sc_intrcnt.ev_count++;
+ }
+ return (ret);
+}
+
+void
+sbicdma_dmastop(sc)
+ struct sbic_softc *sc;
+{
+ printf("sbicdma_dmastop called\n");
+ /* XXX do nothing */
+}
+
+int
+sbicdma_dmanext(sc)
+ struct sbic_softc *sc;
+{
+ printf("sbicdma_dmanext called\n");
+}
+
+void
+sbicdma_dmafree(sc)
+ struct sbic_softc *sc;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+
+ printf("sbicdma_dmafree called\n");
+ /* make certain interupts are disabled first, reset */
+ pcc->pcc_dmairq = 0;
+}
diff --git a/sys/arch/mvme68k/dev/sbicreg.h b/sys/arch/mvme68k/dev/sbicreg.h
new file mode 100644
index 00000000000..f3844dcd246
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbicreg.h
@@ -0,0 +1,424 @@
+/* $NetBSD: sbicreg.h,v 1.2 1994/10/26 02:04:40 cgd 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. 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
+ */
+
+/*
+ * AMD AM33C93A 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
+/* sbic_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_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 acces (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_DEEP 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
+ */
+
+#define SBIC_SYN_OFF_MASK 0x0f
+#define SBIC_SYN_MAX_OFFSET SBIC_FIFO_DEEP
+#define SBIC_SYN_PER_MASK 0x70
+#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */
+
+#define SBIC_SYN(o,p) \
+ (((o) & SBIC_SYN_OFF_MASK) | (((p) << 4) & SBIC_SYN_PER_MASK))
+
+/*
+ * 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 */
+
+/* approximate, but we won't do SBT on selects */
+#define sbic_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa))
+
+#define PAD(n) char n;
+#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA
+
+typedef struct {
+ volatile unsigned char sbic_asr; /* r : Aux Status Register */
+#define sbic_address sbic_asr /* w : desired register no */
+ /* PAD(pad1); */
+ volatile unsigned char sbic_value; /* rw: register value */
+} sbic_padded_ind_regmap_t;
+typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
+
+#define sbic_read_reg(regs,regno,val) do { \
+ (regs)->sbic_address = (regno); \
+ (val) = (regs)->sbic_value; \
+ } while (0)
+
+#define sbic_write_reg(regs,regno,val) do { \
+ (regs)->sbic_address = (regno); \
+ (regs)->sbic_value = (val); \
+ } while (0)
+
+#define SET_SBIC_myid(regs,val) sbic_write_reg(regs,SBIC_myid,val)
+#define GET_SBIC_myid(regs,val) sbic_read_reg(regs,SBIC_myid,val)
+#define SET_SBIC_cdbsize(regs,val) sbic_write_reg(regs,SBIC_cdbsize,val)
+#define GET_SBIC_cdbsize(regs,val) sbic_read_reg(regs,SBIC_cdbsize,val)
+#define SET_SBIC_control(regs,val) sbic_write_reg(regs,SBIC_control,val)
+#define GET_SBIC_control(regs,val) sbic_read_reg(regs,SBIC_control,val)
+#define SET_SBIC_timeo(regs,val) sbic_write_reg(regs,SBIC_timeo,val)
+#define GET_SBIC_timeo(regs,val) sbic_read_reg(regs,SBIC_timeo,val)
+#define SET_SBIC_cdb1(regs,val) sbic_write_reg(regs,SBIC_cdb1,val)
+#define GET_SBIC_cdb1(regs,val) sbic_read_reg(regs,SBIC_cdb1,val)
+#define SET_SBIC_cdb2(regs,val) sbic_write_reg(regs,SBIC_cdb2,val)
+#define GET_SBIC_cdb2(regs,val) sbic_read_reg(regs,SBIC_cdb2,val)
+#define SET_SBIC_cdb3(regs,val) sbic_write_reg(regs,SBIC_cdb3,val)
+#define GET_SBIC_cdb3(regs,val) sbic_read_reg(regs,SBIC_cdb3,val)
+#define SET_SBIC_cdb4(regs,val) sbic_write_reg(regs,SBIC_cdb4,val)
+#define GET_SBIC_cdb4(regs,val) sbic_read_reg(regs,SBIC_cdb4,val)
+#define SET_SBIC_cdb5(regs,val) sbic_write_reg(regs,SBIC_cdb5,val)
+#define GET_SBIC_cdb5(regs,val) sbic_read_reg(regs,SBIC_cdb5,val)
+#define SET_SBIC_cdb6(regs,val) sbic_write_reg(regs,SBIC_cdb6,val)
+#define GET_SBIC_cdb6(regs,val) sbic_read_reg(regs,SBIC_cdb6,val)
+#define SET_SBIC_cdb7(regs,val) sbic_write_reg(regs,SBIC_cdb7,val)
+#define GET_SBIC_cdb7(regs,val) sbic_read_reg(regs,SBIC_cdb7,val)
+#define SET_SBIC_cdb8(regs,val) sbic_write_reg(regs,SBIC_cdb8,val)
+#define GET_SBIC_cdb8(regs,val) sbic_read_reg(regs,SBIC_cdb8,val)
+#define SET_SBIC_cdb9(regs,val) sbic_write_reg(regs,SBIC_cdb9,val)
+#define GET_SBIC_cdb9(regs,val) sbic_read_reg(regs,SBIC_cdb9,val)
+#define SET_SBIC_cdb10(regs,val) sbic_write_reg(regs,SBIC_cdb10,val)
+#define GET_SBIC_cdb10(regs,val) sbic_read_reg(regs,SBIC_cdb10,val)
+#define SET_SBIC_cdb11(regs,val) sbic_write_reg(regs,SBIC_cdb11,val)
+#define GET_SBIC_cdb11(regs,val) sbic_read_reg(regs,SBIC_cdb11,val)
+#define SET_SBIC_cdb12(regs,val) sbic_write_reg(regs,SBIC_cdb12,val)
+#define GET_SBIC_cdb12(regs,val) sbic_read_reg(regs,SBIC_cdb12,val)
+#define SET_SBIC_tlun(regs,val) sbic_write_reg(regs,SBIC_tlun,val)
+#define GET_SBIC_tlun(regs,val) sbic_read_reg(regs,SBIC_tlun,val)
+#define SET_SBIC_cmd_phase(regs,val) sbic_write_reg(regs,SBIC_cmd_phase,val)
+#define GET_SBIC_cmd_phase(regs,val) sbic_read_reg(regs,SBIC_cmd_phase,val)
+#define SET_SBIC_syn(regs,val) sbic_write_reg(regs,SBIC_syn,val)
+#define GET_SBIC_syn(regs,val) sbic_read_reg(regs,SBIC_syn,val)
+#define SET_SBIC_count_hi(regs,val) sbic_write_reg(regs,SBIC_count_hi,val)
+#define GET_SBIC_count_hi(regs,val) sbic_read_reg(regs,SBIC_count_hi,val)
+#define SET_SBIC_count_med(regs,val) sbic_write_reg(regs,SBIC_count_med,val)
+#define GET_SBIC_count_med(regs,val) sbic_read_reg(regs,SBIC_count_med,val)
+#define SET_SBIC_count_lo(regs,val) sbic_write_reg(regs,SBIC_count_lo,val)
+#define GET_SBIC_count_lo(regs,val) sbic_read_reg(regs,SBIC_count_lo,val)
+#define SET_SBIC_selid(regs,val) sbic_write_reg(regs,SBIC_selid,val)
+#define GET_SBIC_selid(regs,val) sbic_read_reg(regs,SBIC_selid,val)
+#define SET_SBIC_rselid(regs,val) sbic_write_reg(regs,SBIC_rselid,val)
+#define GET_SBIC_rselid(regs,val) sbic_read_reg(regs,SBIC_rselid,val)
+#define SET_SBIC_csr(regs,val) sbic_write_reg(regs,SBIC_csr,val)
+#define GET_SBIC_csr(regs,val) sbic_read_reg(regs,SBIC_csr,val)
+#define SET_SBIC_cmd(regs,val) sbic_write_reg(regs,SBIC_cmd,val)
+#define GET_SBIC_cmd(regs,val) sbic_read_reg(regs,SBIC_cmd,val)
+#define SET_SBIC_data(regs,val) sbic_write_reg(regs,SBIC_data,val)
+#define GET_SBIC_data(regs,val) sbic_read_reg(regs,SBIC_data,val)
+
+#define SBIC_TC_PUT(regs,val) do { \
+ sbic_write_reg(regs,SBIC_count_hi,((val)>>16)); \
+ (regs)->sbic_value = (val)>>8; \
+ (regs)->sbic_value = (val); \
+} while (0)
+#define SBIC_TC_GET(regs,val) do { \
+ sbic_read_reg(regs,SBIC_count_hi,(val)); \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+} while (0)
+
+#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) do { \
+ int n=(cmdsize)-1; \
+ char *ptr = (char*)(cmd); \
+ sbic_write_reg(regs,SBIC_cdb1,*ptr++); \
+ while (n-- > 0) (regs)->sbic_value = *ptr++; \
+} while (0)
+
+#define GET_SBIC_asr(regs,val) (val) = (regs)->sbic_asr
+
+#define WAIT_CIP(regs) do { \
+ while ((regs)->sbic_asr & SBIC_ASR_CIP) \
+ ; \
+} while (0)
+
+/* transmit a byte in programmed I/O mode */
+#define SEND_BYTE(regs, ch) do { \
+ WAIT_CIP(regs); \
+ SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
+ SET_SBIC_data(regs, ch); \
+ } while (0)
+
+/* receive a byte in programmed I/O mode */
+#define RECV_BYTE(regs, ch) do { \
+ WAIT_CIP(regs); \
+ SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
+ GET_SBIC_data(regs, ch); \
+ } while (0)
diff --git a/sys/arch/mvme68k/dev/sbicvar.h b/sys/arch/mvme68k/dev/sbicvar.h
new file mode 100644
index 00000000000..339d5f73c39
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbicvar.h
@@ -0,0 +1,230 @@
+/* $NetBSD: sbicvar.h,v 1.8 1995/08/18 15:28:05 chopps 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. 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.
+ *
+ * @(#)scsivar.h 7.1 (Berkeley) 5/8/90
+ */
+#ifndef _SBICVAR_H_
+#define _SBICVAR_H_
+#include <sys/malloc.h>
+
+/*
+ * The largest single request will be MAXPHYS bytes which will require
+ * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
+ * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
+ * buffer is not page aligned (+1).
+ */
+#define DMAMAXIO (MAXPHYS/NBPG+1)
+
+struct dma_chain {
+ int dc_count;
+ char *dc_addr;
+};
+
+/*
+ * 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. Basicly, 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 sbic_acb {
+ TAILQ_ENTRY(sbic_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_DONE 0x04
+#define ACB_CHKSENSE 0x08
+#define ACB_BBUF 0x10 /* DMA input needs to be copied from bounce */
+#define ACB_DATAIN 0x20 /* DMA direction flag */
+ struct scsi_generic cmd; /* SCSI command block */
+ int clen;
+ struct dma_chain sc_kv; /* Virtual address of whole DMA */
+ struct dma_chain sc_pa; /* Physical address of DMA segment */
+ u_long sc_tcnt; /* number of bytes for this DMA */
+ u_char *sc_dmausrbuf; /* user buffer kva - for bounce copy */
+ u_long sc_dmausrlen; /* length of bounce copy */
+ u_short sc_dmacmd; /* Internal data for this DMA */
+ char *pa_addr; /* XXXX initial phys addr */
+ u_char *sc_usrbufpa; /* user buffer phys addr */
+};
+
+/*
+ * 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 sbic_tinfo {
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ u_char* bounce; /* Bounce buffer for this device */
+ ushort lubusy; /* What local units/subr. are busy? */
+ u_char flags;
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+} tinfo_t;
+
+struct sbic_softc {
+ struct device sc_dev;
+ struct intrhand sc_ih, sc_dmaih;
+ struct evcnt sc_intrcnt, sc_dmaintrcnt;
+ struct target_sync {
+ u_char state;
+ u_char period;
+ u_char offset;
+ } sc_sync[8];
+ u_char target; /* Currently active target */
+ u_char lun;
+ struct scsi_link sc_link; /* proto for sub devices */
+ sbic_regmap_p sc_sbicp; /* the SBIC */
+ volatile void *sc_cregs; /* driver specific regs */
+
+ /* Lists of command blocks */
+ TAILQ_HEAD(acb_list, sbic_acb) free_list,
+ ready_list,
+ nexus_list;
+
+ struct sbic_acb *sc_nexus; /* current command */
+ struct sbic_acb sc_acb[8]; /* the real command blocks */
+ struct sbic_tinfo sc_tinfo[8];
+
+ struct scsi_xfer *sc_xs; /* transfer from high level code */
+ u_char sc_flags;
+ u_char sc_scsiaddr;
+ u_char sc_stat[2];
+ u_char sc_msg[7];
+ u_long sc_clkfreq;
+ u_long sc_tcnt; /* number of bytes transfered */
+ u_short sc_dmacmd; /* used by dma drivers */
+ u_short sc_dmatimo; /* dma timeout */
+ u_long sc_dmamask; /* dma valid mem mask */
+ struct dma_chain *sc_cur;
+ struct dma_chain *sc_last;
+ int (*sc_dmago) __P((struct sbic_softc *, char *, int, int));
+ int (*sc_dmanext) __P((struct sbic_softc *));
+ void (*sc_dmafree) __P((struct sbic_softc *));
+ void (*sc_dmastop) __P((struct sbic_softc *));
+ u_short gtsc_bankmask; /* GVP specific bank selected */
+};
+
+/* sc_flags */
+#define SBICF_ALIVE 0x01 /* controller initialized */
+#define SBICF_DCFLUSH 0x02 /* need flush for overlap after dma finishes */
+#define SBICF_SELECTED 0x04 /* bus is in selected state. */
+#define SBICF_ICMD 0x08 /* Immediate command in execution */
+#define SBICF_BADDMA 0x10 /* controller can only DMA to ztwobus space */
+#define SBICF_INTR 0x40 /* SBICF interrupt expected */
+#define SBICF_INDMA 0x80 /* not used yet, DMA I/O in progress */
+
+/* sync states */
+#define SYNC_START 0 /* no sync handshake started */
+#define SYNC_SENT 1 /* we sent sync request, no answer yet */
+#define SYNC_DONE 2 /* target accepted our (or inferior) settings,
+ or it rejected the request and we stay async */
+#ifdef DEBUG
+#define DDB_FOLLOW 0x04
+#define DDB_IO 0x08
+#endif
+extern int sbic_inhibit_sync;
+extern int sbic_no_dma;
+extern int sbic_clock_override;
+
+#define PHASE 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 arbitration with sel. */
+#define MESG_OUT_PHASE 0x06
+#define MESG_IN_PHASE 0x07
+
+#define MSG_CMD_COMPLETE 0x00
+#define MSG_EXT_MESSAGE 0x01
+#define MSG_SAVE_DATA_PTR 0x02
+#define MSG_RESTORE_PTR 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_INIT_DETECT_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT 0x07
+#define MSG_NOOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_BUS_DEVICE_RESET 0x0C
+#define MSG_IDENTIFY 0x80
+#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */
+#define MSG_SYNC_REQ 0x01
+
+#define MSG_ISIDENTIFY(x) (x&MSG_IDENTIFY)
+#define IFY_TRN 0x20
+#define IFY_LUNTRN(x) (x&0x07)
+#define IFY_LUN(x) (!(x&0x20))
+
+/* Check if high bit set */
+
+#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
+#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */
+#define STS_BUSY 0x08
+#define STS_INTERMED 0x10 /* Intermediate status sent */
+#define STS_EXT 0x80 /* Extended status valid */
+
+
+/* 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
+
+/*
+ * XXXX
+ */
+struct scsi_fmt_cdb {
+ int len; /* cdb length (in bytes) */
+ u_char cdb[28]; /* cdb to use on next read/write */
+};
+
+struct buf;
+struct scsi_xfer;
+
+void sbic_minphys __P((struct buf *bp));
+int sbic_scsicmd __P((struct scsi_xfer *));
+
+#endif /* _SBICVAR_H_ */
diff --git a/sys/arch/mvme68k/dev/siop.c b/sys/arch/mvme68k/dev/siop.c
new file mode 100644
index 00000000000..be0b8b32d9f
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siop.c
@@ -0,0 +1,1523 @@
+/* $NetBSD: siop.c,v 1.23 1995/08/18 15:28:08 chopps Exp $ */
+
+/*
+ * Copyright (c) 1994 Michael L. Hitch
+ * 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. 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.
+ *
+ * @(#)siop.c 7.5 (Berkeley) 5/4/91
+ */
+
+/*
+ * 53C710 scsi adaptor driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/siopreg.h>
+#include <mvme68k/dev/siopvar.h>
+
+extern u_int kvtop();
+
+/*
+ * SCSI delays
+ * In u-seconds, primarily for state changes on the SPC.
+ */
+#define SCSI_CMD_WAIT 500000 /* wait per step of 'immediate' cmds */
+#define SCSI_DATA_WAIT 500000 /* wait per data in/out step */
+#define SCSI_INIT_WAIT 500000 /* wait per step (both) during init */
+
+void siop_select __P((struct siop_softc *));
+void siopabort __P((struct siop_softc *, siop_regmap_p, char *));
+void sioperror __P((struct siop_softc *, siop_regmap_p, u_char));
+void siopstart __P((struct siop_softc *));
+void siopreset __P((struct siop_softc *));
+void siopsetdelay __P((int));
+void siop_scsidone __P((struct siop_acb *, int));
+void siop_sched __P((struct siop_softc *));
+int siop_poll __P((struct siop_softc *, struct siop_acb *));
+int siopintr __P((struct siop_softc *));
+
+/* 53C710 script */
+const
+#include <mvme68k/dev/siop_script.out>
+
+/* default to not inhibit sync negotiation on any drive */
+u_char siop_inhibit_sync[8] = { 0, 0, 0, 0, 0, 0, 0 }; /* initialize, so patchable */
+u_char siop_allow_disc[8] = { 3, 3, 3, 3, 3, 3, 3, 3 };
+int siop_no_dma = 0;
+
+int siop_reset_delay = 250; /* delay after reset, in milleseconds */
+
+int siop_cmd_wait = SCSI_CMD_WAIT;
+int siop_data_wait = SCSI_DATA_WAIT;
+int siop_init_wait = SCSI_INIT_WAIT;
+
+#ifdef DEBUG
+/*
+ * 0x01 - full debug
+ * 0x02 - DMA chaining
+ * 0x04 - siopintr
+ * 0x08 - phase mismatch
+ * 0x10 - <not used>
+ * 0x20 - panic on unhandled exceptions
+ * 0x100 - disconnect/reselect
+ */
+int siop_debug = 0;
+int siopsync_debug = 0;
+int siopdma_hits = 0;
+int siopdma_misses = 0;
+int siopchain_ints = 0;
+int siopstarts = 0;
+int siopints = 0;
+int siopphmm = 0;
+#define SIOP_TRACE_SIZE 128
+#define SIOP_TRACE(a,b,c,d) \
+ siop_trbuf[siop_trix] = (a); \
+ siop_trbuf[siop_trix+1] = (b); \
+ siop_trbuf[siop_trix+2] = (c); \
+ siop_trbuf[siop_trix+3] = (d); \
+ siop_trix = (siop_trix + 4) & (SIOP_TRACE_SIZE - 1);
+u_char siop_trbuf[SIOP_TRACE_SIZE];
+int siop_trix;
+#else
+#define SIOP_TRACE(a,b,c,d)
+#endif
+
+
+/*
+ * default minphys routine for siop based controllers
+ */
+void
+siop_minphys(bp)
+ struct buf *bp;
+{
+
+ /*
+ * No max transfer at this level.
+ */
+ minphys(bp);
+}
+
+/*
+ * used by specific siop controller
+ *
+ */
+int
+siop_scsicmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct siop_acb *acb;
+ struct siop_softc *sc;
+ struct scsi_link *slp;
+ int flags, s, i;
+
+ slp = xs->sc_link;
+ sc = slp->adapter_softc;
+ flags = xs->flags;
+
+ /* XXXX ?? */
+ if (flags & SCSI_DATA_UIO)
+ panic("siop: scsi data uio requested");
+
+ /* XXXX ?? */
+ if (sc->sc_nexus && flags & SCSI_POLL)
+ panic("siop_scsicmd: busy");
+
+ s = splbio();
+ acb = sc->free_list.tqh_first;
+ if (acb) {
+ TAILQ_REMOVE(&sc->free_list, acb, chain);
+ }
+ splx(s);
+
+ if (acb == NULL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+ acb->flags = ACB_ACTIVE;
+ acb->xs = xs;
+ bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
+ acb->clen = xs->cmdlen;
+ acb->daddr = xs->data;
+ acb->dleft = xs->datalen;
+
+ s = splbio();
+ TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
+
+ if (sc->sc_nexus == NULL)
+ siop_sched(sc);
+
+ splx(s);
+
+ if (flags & SCSI_POLL || siop_no_dma)
+ return(siop_poll(sc, acb));
+ return(SUCCESSFULLY_QUEUED);
+}
+
+int
+siop_poll(sc, acb)
+ struct siop_softc *sc;
+ struct siop_acb *acb;
+{
+ siop_regmap_p rp = sc->sc_siopp;
+ struct scsi_xfer *xs = acb->xs;
+ int i;
+ int status;
+ u_char istat;
+ u_char dstat;
+ u_char sstat0;
+ int s;
+ int to;
+
+ s = splbio();
+ to = xs->timeout / 1000;
+ if (sc->nexus_list.tqh_first)
+ printf("%s: siop_poll called with disconnected device\n",
+ sc->sc_dev.dv_xname);
+ for (;;) {
+ /* use cmd_wait values? */
+ i = 50000;
+ spl0();
+ while (((istat = rp->siop_istat) &
+ (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
+ if (--i <= 0) {
+#ifdef DEBUG
+ printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %x (+%x) dcmd %x ds %x timeout %d\n",
+ xs->sc_link->target, acb->cmd.opcode,
+ rp->siop_sbcl, rp->siop_dsp,
+ rp->siop_dsp - sc->sc_scriptspa,
+ *((long *)&rp->siop_dcmd), &acb->ds, acb->xs->timeout);
+#endif
+ i = 50000;
+ --to;
+ if (to <= 0) {
+ siopreset(sc);
+ return(COMPLETE);
+ }
+ }
+ delay(10);
+ }
+ sstat0 = rp->siop_sstat0;
+ dstat = rp->siop_dstat;
+ if (siop_checkintr(sc, istat, dstat, sstat0, &status)) {
+ if (acb != sc->sc_nexus)
+ printf("%s: siop_poll disconnected device completed\n",
+ sc->sc_dev.dv_xname);
+ else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
+ sc->sc_flags &= ~SIOP_INTSOFF;
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+ }
+ siop_scsidone(sc->sc_nexus, status);
+ }
+ if (xs->flags & ITSDONE)
+ break;
+ }
+ splx(s);
+ return (COMPLETE);
+}
+
+/*
+ * start next command that's ready
+ */
+void
+siop_sched(sc)
+ struct siop_softc *sc;
+{
+ struct scsi_link *slp;
+ struct siop_acb *acb;
+ int stat, i;
+
+#ifdef DEBUG
+ if (sc->sc_nexus) {
+ printf("%s: siop_sched- nexus %x/%d ready %x/%d\n",
+ sc->sc_dev.dv_xname, sc->sc_nexus,
+ sc->sc_nexus->xs->sc_link->target,
+ sc->ready_list.tqh_first,
+ sc->ready_list.tqh_first->xs->sc_link->target);
+ return;
+ }
+#endif
+ for (acb = sc->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
+ slp = acb->xs->sc_link;
+ i = slp->target;
+ if(!(sc->sc_tinfo[i].lubusy & (1 << slp->lun))) {
+ struct siop_tinfo *ti = &sc->sc_tinfo[i];
+
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ sc->sc_nexus = acb;
+ slp = acb->xs->sc_link;
+ ti = &sc->sc_tinfo[slp->target];
+ ti->lubusy |= (1 << slp->lun);
+ break;
+ }
+ }
+
+ if (acb == NULL) {
+#ifdef DEBUGXXX
+ printf("%s: siop_sched didn't find ready command\n",
+ sc->sc_dev.dv_xname);
+#endif
+ return;
+ }
+
+ if (acb->xs->flags & SCSI_RESET)
+ siopreset(sc);
+
+#if 0
+ acb->cmd.bytes[0] |= slp->lun << 5; /* XXXX */
+#endif
+ ++sc->sc_active;
+ siop_select(sc);
+}
+
+void
+siop_scsidone(acb, stat)
+ struct siop_acb *acb;
+ int stat;
+{
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *slp = xs->sc_link;
+ struct siop_softc *sc = slp->adapter_softc;
+ int s, dosched = 0;
+
+#ifdef DIAGNOSTIC
+ if (acb == NULL || xs == NULL)
+ panic("siop_scsidone");
+#endif
+#if 0
+ if (((struct device *)(slp->device_softc))->dv_unit < dk_ndrive)
+ ++dk_xfer[((struct device *)(slp->device_softc))->dv_unit];
+#endif
+ /*
+ * is this right?
+ */
+ xs->status = stat;
+
+ if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
+ if (stat == SCSI_CHECK) {
+ struct scsi_sense *ss = (void *)&acb->cmd;
+ bzero(ss, sizeof(*ss));
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = slp->lun << 5;
+ ss->length = sizeof(struct scsi_sense_data);
+ acb->clen = sizeof(*ss);
+ acb->daddr = (char *)&xs->sense;
+ acb->dleft = sizeof(struct scsi_sense_data);
+ acb->flags = ACB_ACTIVE | ACB_CHKSENSE;
+ TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
+ --sc->sc_active;
+ sc->sc_tinfo[slp->target].lubusy &=
+ ~(1 << slp->lun);
+ sc->sc_tinfo[slp->target].senses++;
+ if (sc->sc_nexus == acb) {
+ sc->sc_nexus = NULL;
+ siop_sched(sc);
+ }
+ SIOP_TRACE('d','s',0,0)
+ return;
+ }
+ }
+ if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
+ xs->error = XS_SENSE;
+ } else {
+ xs->resid = 0; /* XXXX */
+ }
+#if whataboutthisone
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+#endif
+ xs->flags |= ITSDONE;
+
+ /*
+ * Remove the ACB from whatever queue it's on. We have to do a bit of
+ * a hack to figure out which queue it's on. Note that it is *not*
+ * necessary to cdr down the ready queue, but we must cdr down the
+ * nexus queue and see if it's there, so we can mark the unit as no
+ * longer busy. This code is sickening, but it works.
+ */
+ if (acb == sc->sc_nexus) {
+ sc->sc_nexus = NULL;
+ sc->sc_tinfo[slp->target].lubusy &= ~(1<<slp->lun);
+ if (sc->ready_list.tqh_first)
+ dosched = 1; /* start next command */
+ --sc->sc_active;
+ SIOP_TRACE('d','a',stat,0)
+ } else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) {
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ SIOP_TRACE('d','r',stat,0)
+ } else {
+ register struct siop_acb *acb2;
+ for (acb2 = sc->nexus_list.tqh_first; acb2;
+ acb2 = acb2->chain.tqe_next)
+ if (acb2 == acb) {
+ TAILQ_REMOVE(&sc->nexus_list, acb, chain);
+ sc->sc_tinfo[slp->target].lubusy
+ &= ~(1<<slp->lun);
+ --sc->sc_active;
+ break;
+ }
+ if (acb2)
+ ;
+ else if (acb->chain.tqe_next) {
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ --sc->sc_active;
+ } else {
+ printf("%s: can't find matching acb\n",
+ sc->sc_dev.dv_xname);
+#ifdef DDB
+/* Debugger(); */
+#endif
+ }
+ SIOP_TRACE('d','n',stat,0);
+ }
+ /* Put it on the free list. */
+ acb->flags = ACB_FREE;
+ TAILQ_INSERT_HEAD(&sc->free_list, acb, chain);
+
+ sc->sc_tinfo[slp->target].cmds++;
+
+ scsi_done(xs);
+
+ if (dosched && sc->sc_nexus == NULL)
+ siop_sched(sc);
+}
+
+void
+siopabort(sc, rp, where)
+ register struct siop_softc *sc;
+ siop_regmap_p rp;
+ char *where;
+{
+ int i;
+
+ printf ("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
+ sc->sc_dev.dv_xname,
+ where, rp->siop_dstat, rp->siop_sstat0, rp->siop_sbcl);
+
+ if (sc->sc_active > 0) {
+#ifdef TODO
+ SET_SBIC_cmd (rp, SBIC_CMD_ABORT);
+ WAIT_CIP (rp);
+
+ GET_SBIC_asr (rp, asr);
+ if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI))
+ {
+ /* ok, get more drastic.. */
+
+ SET_SBIC_cmd (rp, SBIC_CMD_RESET);
+ delay(25);
+ SBIC_WAIT(rp, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (rp, csr); /* clears interrupt also */
+
+ return;
+ }
+
+ do
+ {
+ SBIC_WAIT (rp, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (rp, csr);
+ }
+ while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
+ && (csr != SBIC_CSR_CMD_INVALID));
+#endif
+
+ /* lets just hope it worked.. */
+#ifdef fix_this
+ for (i = 0; i < 2; ++i) {
+ if (sc->sc_iob[i].sc_xs && &sc->sc_iob[i] !=
+ sc->sc_cur) {
+ printf ("siopabort: cleanup!\n");
+ sc->sc_iob[i].sc_xs = NULL;
+ }
+ }
+#endif /* fix_this */
+/* sc->sc_active = 0; */
+ }
+}
+
+void
+siopinitialize(sc)
+ struct siop_softc *sc;
+{
+ /*
+ * Need to check that scripts is on a long word boundary
+ * and that DS is on a long word boundary.
+ * Also should verify that dev doesn't span non-contiguous
+ * physical pages.
+ */
+ sc->sc_scriptspa = kvtop(scripts);
+ sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
+ sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
+ sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
+ sc->sc_minsync = sc->sc_tcp[1]; /* in 4ns units */
+ if (sc->sc_minsync < 25)
+ sc->sc_minsync = 25;
+#if not_used
+ if (sc->sc_clock_freq <= 25)
+ sc->sc_tcp[0] = sc->sc_tcp[1];
+ else if (sc->sc_clock_freq <= 37)
+ sc->sc_tcp[0] = sc->sc_tcp[2];
+ else if (sc->sc_clock_freq <= 50)
+ sc->sc_tcp[0] = sc->sc_tcp[3];
+ else
+ sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
+#endif
+
+ siopreset (sc);
+}
+
+void
+siopreset(sc)
+ struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ u_int i, s;
+ u_char dummy;
+ struct siop_acb *acb;
+
+ rp = sc->sc_siopp;
+
+ if (sc->sc_flags & SIOP_ALIVE)
+ siopabort(sc, rp, "reset");
+
+ s = splbio();
+
+ /*
+ * Reset the chip
+ * XXX - is this really needed?
+ */
+ rp->siop_istat |= SIOP_ISTAT_ABRT; /* abort current script */
+ rp->siop_istat |= SIOP_ISTAT_RST; /* reset chip */
+ rp->siop_istat &= ~SIOP_ISTAT_RST;
+ /*
+ * Reset SCSI bus (do we really want this?)
+ */
+ rp->siop_sien = 0;
+ rp->siop_scntl1 |= SIOP_SCNTL1_RST;
+ delay(1);
+ rp->siop_scntl1 &= ~SIOP_SCNTL1_RST;
+
+ /*
+ * Set up various chip parameters
+ */
+ rp->siop_scntl0 = SIOP_ARB_FULL | SIOP_SCNTL0_EPC | SIOP_SCNTL0_EPG;
+ rp->siop_scntl1 = SIOP_SCNTL1_ESR;
+ rp->siop_dcntl = sc->sc_dcntl;
+ rp->siop_dmode = 0x80; /* burst length = 4 */
+ rp->siop_sien = 0x00; /* don't enable interrupts yet */
+ rp->siop_dien = 0x00; /* don't enable interrupts yet */
+ rp->siop_scid = 1 << sc->sc_link.adapter_target;
+ rp->siop_dwt = 0x00;
+ rp->siop_ctest0 |= SIOP_CTEST0_BTD | SIOP_CTEST0_EAN;
+ rp->siop_ctest7 = sc->sc_ctest7;
+
+ /* will need to re-negotiate sync xfers */
+ bzero(&sc->sc_sync, sizeof (sc->sc_sync));
+
+ i = rp->siop_istat;
+ if (i & SIOP_ISTAT_SIP)
+ dummy = rp->siop_sstat0;
+ if (i & SIOP_ISTAT_DIP)
+ dummy = rp->siop_dstat;
+
+ splx(s);
+
+ delay(siop_reset_delay * 1000);
+ printf(": version %d target %d\n", rp->siop_ctest8 >> 4,
+ sc->sc_link.adapter_target);
+
+ if ((sc->sc_flags & SIOP_ALIVE) == 0) {
+ TAILQ_INIT(&sc->ready_list);
+ TAILQ_INIT(&sc->nexus_list);
+ TAILQ_INIT(&sc->free_list);
+ sc->sc_nexus = NULL;
+ acb = sc->sc_acb;
+ bzero(acb, sizeof(sc->sc_acb));
+ for (i = 0; i < sizeof(sc->sc_acb) / sizeof(*acb); i++) {
+ TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
+ acb++;
+ }
+ bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
+ } else {
+ if (sc->sc_nexus != NULL) {
+ sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
+ siop_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
+ }
+ while (acb = sc->nexus_list.tqh_first) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ siop_scsidone(acb, acb->stat[0]);
+ }
+ }
+
+ sc->sc_flags |= SIOP_ALIVE;
+ sc->sc_flags &= ~(SIOP_INTDEFER|SIOP_INTSOFF);
+ /* enable SCSI and DMA interrupts */
+ sc->sc_sien = SIOP_SIEN_M_A | SIOP_SIEN_STO | /*SIOP_SIEN_SEL |*/ SIOP_SIEN_SGE |
+ SIOP_SIEN_UDC | SIOP_SIEN_RST | SIOP_SIEN_PAR;
+ sc->sc_dien = SIOP_DIEN_BF | SIOP_DIEN_ABRT | SIOP_DIEN_SIR |
+ /*SIOP_DIEN_WTD |*/ SIOP_DIEN_IID;
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+}
+
+/*
+ * Setup Data Storage for 53C710 and start SCRIPTS processing
+ */
+
+void
+siop_start (sc, target, lun, cbuf, clen, buf, len)
+ struct siop_softc *sc;
+ int target;
+ int lun;
+ u_char *cbuf;
+ int clen;
+ u_char *buf;
+ int len;
+{
+ siop_regmap_p rp = sc->sc_siopp;
+ int i;
+ int nchain;
+ int count, tcount;
+ char *addr, *dmaend;
+ struct siop_acb *acb = sc->sc_nexus;
+
+#ifdef DEBUG
+ if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
+ printf ("ACK! siop was busy: rp %x script %x dsa %x active %d\n",
+ rp, &scripts, &acb->ds, sc->sc_active);
+ printf ("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
+ rp->siop_istat, rp->siop_sfbr, rp->siop_lcrc,
+ rp->siop_sien, rp->siop_dien);
+#ifdef DDB
+ /*Debugger();*/
+#endif
+ }
+#endif
+ acb->msgout[0] = MSG_IDENTIFY | lun;
+ if (siop_allow_disc[target] & 2 ||
+ (siop_allow_disc[target] && len == 0))
+ acb->msgout[0] = MSG_IDENTIFY_DR | lun;
+ acb->status = 0;
+ acb->stat[0] = -1;
+ acb->msg[0] = -1;
+ acb->ds.scsi_addr = (0x10000 << target) | (sc->sc_sync[target].sxfer << 8);
+ acb->ds.idlen = 1;
+ acb->ds.idbuf = (char *) kvtop(&acb->msgout[0]);
+ acb->ds.cmdlen = clen;
+ acb->ds.cmdbuf = (char *) kvtop(cbuf);
+ acb->ds.stslen = 1;
+ acb->ds.stsbuf = (char *) kvtop(&acb->stat[0]);
+ acb->ds.msglen = 1;
+ acb->ds.msgbuf = (char *) kvtop(&acb->msg[0]);
+ acb->msg[1] = -1;
+ acb->ds.msginlen = 1;
+ acb->ds.extmsglen = 1;
+ acb->ds.synmsglen = 3;
+ acb->ds.msginbuf = (char *) kvtop(&acb->msg[1]);
+ acb->ds.extmsgbuf = (char *) kvtop(&acb->msg[2]);
+ acb->ds.synmsgbuf = (char *) kvtop(&acb->msg[3]);
+ bzero(&acb->ds.chain, sizeof (acb->ds.chain));
+
+ if (sc->sc_sync[target].state == SYNC_START) {
+ if (siop_inhibit_sync[target]) {
+ sc->sc_sync[target].state = SYNC_DONE;
+ sc->sc_sync[target].sbcl = 0;
+ sc->sc_sync[target].sxfer = 0;
+#ifdef DEBUG
+ if (siopsync_debug)
+ printf ("Forcing target %d asynchronous\n", target);
+#endif
+ }
+ else {
+ acb->msg[2] = -1;
+ acb->msgout[1] = MSG_EXT_MESSAGE;
+ acb->msgout[2] = 3;
+ acb->msgout[3] = MSG_SYNC_REQ;
+#ifdef MAXTOR_SYNC_KLUDGE
+ acb->msgout[4] = 50 / 4; /* ask for ridiculous period */
+#else
+ acb->msgout[4] = sc->sc_minsync;
+#endif
+ acb->msgout[5] = SIOP_MAX_OFFSET;
+ acb->ds.idlen = 6;
+ sc->sc_sync[target].state = SYNC_SENT;
+#ifdef DEBUG
+ if (siopsync_debug)
+ printf ("Sending sync request to target %d\n", target);
+#endif
+ }
+ }
+
+/*
+ * Build physical DMA addresses for scatter/gather I/O
+ */
+ acb->iob_buf = buf;
+ acb->iob_len = len;
+ acb->iob_curbuf = acb->iob_curlen = 0;
+ nchain = 0;
+ count = len;
+ addr = buf;
+ dmaend = NULL;
+ while (count > 0) {
+ acb->ds.chain[nchain].databuf = (char *) kvtop (addr);
+ if (count < (tcount = NBPG - ((int) addr & PGOFSET)))
+ tcount = count;
+ acb->ds.chain[nchain].datalen = tcount;
+ addr += tcount;
+ count -= tcount;
+ if (acb->ds.chain[nchain].databuf == dmaend) {
+ dmaend += acb->ds.chain[nchain].datalen;
+ acb->ds.chain[nchain].datalen = 0;
+ acb->ds.chain[--nchain].datalen += tcount;
+#ifdef DEBUG
+ ++siopdma_hits;
+#endif
+ }
+ else {
+ dmaend = acb->ds.chain[nchain].databuf +
+ acb->ds.chain[nchain].datalen;
+ acb->ds.chain[nchain].datalen = tcount;
+#ifdef DEBUG
+ if (nchain) /* Don't count miss on first one */
+ ++siopdma_misses;
+#endif
+ }
+ ++nchain;
+ }
+#ifdef DEBUG
+ if (nchain != 1 && len != 0 && siop_debug & 3) {
+ printf ("DMA chaining set: %d\n", nchain);
+ for (i = 0; i < nchain; ++i) {
+ printf (" [%d] %8x %4x\n", i, acb->ds.chain[i].databuf,
+ acb->ds.chain[i].datalen);
+ }
+ }
+#endif
+
+ /* push data cache for all data the 53c710 needs to access */
+ dma_cachectl (sc, sizeof (struct siop_softc));
+ dma_cachectl (cbuf, clen);
+ if (buf != NULL && len != 0)
+ dma_cachectl (buf, len);
+#ifdef DEBUG
+ if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
+ printf ("ACK! siop was busy at start: rp %x script %x dsa %x active %d\n",
+ rp, &scripts, &acb->ds, sc->sc_active);
+#ifdef DDB
+ /*Debugger();*/
+#endif
+ }
+#endif
+ if (sc->nexus_list.tqh_first == NULL) {
+ if (rp->siop_istat & SIOP_ISTAT_CON)
+ printf("%s: siop_select while connected?\n",
+ sc->sc_dev.dv_xname);
+ rp->siop_temp = 0;
+ rp->siop_sbcl = sc->sc_sync[target].sbcl;
+ rp->siop_dsa = kvtop(&acb->ds);
+ rp->siop_dsp = sc->sc_scriptspa;
+ SIOP_TRACE('s',1,0,0)
+ } else {
+ if ((rp->siop_istat & SIOP_ISTAT_CON) == 0) {
+ rp->siop_istat = SIOP_ISTAT_SIGP;
+ SIOP_TRACE('s',2,0,0);
+ }
+ else {
+ SIOP_TRACE('s',3,rp->siop_istat,0);
+ }
+ }
+#ifdef DEBUG
+ ++siopstarts;
+#endif
+}
+
+/*
+ * Process a DMA or SCSI interrupt from the 53C710 SIOP
+ */
+
+int
+siop_checkintr(sc, istat, dstat, sstat0, status)
+ struct siop_softc *sc;
+ u_char istat;
+ u_char dstat;
+ u_char sstat0;
+ int *status;
+{
+ siop_regmap_p rp = sc->sc_siopp;
+ struct siop_acb *acb = sc->sc_nexus;
+ int target;
+ int dfifo, dbc, sstat1;
+
+ dfifo = rp->siop_dfifo;
+ dbc = rp->siop_dbc0;
+ sstat1 = rp->siop_sstat1;
+ rp->siop_ctest8 |= SIOP_CTEST8_CLF;
+ while ((rp->siop_ctest1 & SIOP_CTEST1_FMT) != SIOP_CTEST1_FMT)
+ ;
+ rp->siop_ctest8 &= ~SIOP_CTEST8_CLF;
+#ifdef DEBUG
+ ++siopints;
+#if 0
+ if (siop_debug & 0x100) {
+ DCIAS(&acb->stat[0]); /* XXX */
+ printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
+ istat, dstat, sstat0, rp->siop_dsps, rp->siop_sbcl, acb->stat[0], acb->msg[0]);
+ printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
+ acb->msg[0], acb->msg[1], acb->msg[2],
+ acb->msg[3], acb->msg[4], acb->msg[5]);
+ }
+#endif
+ if (rp->siop_dsp && (rp->siop_dsp < sc->sc_scriptspa ||
+ rp->siop_dsp >= sc->sc_scriptspa + sizeof(scripts))) {
+ printf ("%s: dsp not within script dsp %x scripts %x:%x",
+ sc->sc_dev.dv_xname, rp->siop_dsp, sc->sc_scriptspa,
+ sc->sc_scriptspa + sizeof(scripts));
+ printf(" istat %x dstat %x sstat0 %x\n",
+ istat, dstat, sstat0);
+ Debugger();
+ }
+#endif
+ SIOP_TRACE('i',dstat,istat,(istat&SIOP_ISTAT_DIP)?rp->siop_dsps&0xff:sstat0);
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff00) {
+ /* Normal completion status, or check condition */
+#ifdef DEBUG
+ if (rp->siop_dsa != kvtop(&acb->ds)) {
+ printf ("siop: invalid dsa: %x %x\n", rp->siop_dsa,
+ kvtop(&acb->ds));
+ panic("*** siop DSA invalid ***");
+ }
+#endif
+ target = acb->xs->sc_link->target;
+ if (sc->sc_sync[target].state == SYNC_SENT) {
+#ifdef DEBUG
+ if (siopsync_debug)
+ printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
+ acb->msg[0], acb->msg[1], acb->msg[2],
+ acb->msg[3], acb->msg[4], acb->msg[5]);
+#endif
+ if (acb->msg[1] == 0xff)
+ printf ("%s: target %d ignored sync request\n",
+ sc->sc_dev.dv_xname, target);
+ else if (acb->msg[1] == MSG_REJECT)
+ printf ("%s: target %d rejected sync request\n",
+ sc->sc_dev.dv_xname, target);
+ sc->sc_sync[target].state = SYNC_DONE;
+ sc->sc_sync[target].sxfer = 0;
+ sc->sc_sync[target].sbcl = 0;
+ if (acb->msg[2] == 3 &&
+ acb->msg[3] == MSG_SYNC_REQ &&
+ acb->msg[5] != 0) {
+#ifdef MAXTOR_KLUDGE
+ /*
+ * Kludge for my Maxtor XT8580S
+ * It accepts whatever we request, even
+ * though it won't work. So we ask for
+ * a short period than we can handle. If
+ * the device says it can do it, use 208ns.
+ * If the device says it can do less than
+ * 100ns, then we limit it to 100ns.
+ */
+ if (acb->msg[4] && acb->msg[4] < 100 / 4) {
+#ifdef DEBUG
+ printf ("%d: target %d wanted %dns period\n",
+ sc->sc_dev.dv_xname, target,
+ acb->msg[4] * 4);
+#endif
+ if (acb->msg[4] == 50 / 4)
+ acb->msg[4] = 208 / 4;
+ else
+ acb->msg[4] = 100 / 4;
+ }
+#endif /* MAXTOR_KLUDGE */
+ printf ("%s: target %d now synchronous, period=%dns, offset=%d\n",
+ sc->sc_dev.dv_xname, target,
+ acb->msg[4] * 4, acb->msg[5]);
+ scsi_period_to_siop (sc, target);
+ }
+ }
+ dma_cachectl(&acb->stat[0], 1);
+ *status = acb->stat[0];
+#ifdef DEBUG
+ if (rp->siop_sbcl & SIOP_BSY) {
+ /*printf ("ACK! siop was busy at end: rp %x script %x dsa %x\n",
+ rp, &scripts, &acb->ds);*/
+#ifdef DDB
+ /*Debugger();*/
+#endif
+ }
+ if (acb->msg[0] != 0x00)
+ printf("%s: message was not COMMAND COMPLETE: %x\n",
+ sc->sc_dev.dv_xname, acb->msg[0]);
+#endif
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return 1;
+ }
+ if (sstat0 & SIOP_SSTAT0_M_A) { /* Phase mismatch */
+#ifdef DEBUG
+ ++siopphmm;
+ if (acb == NULL)
+ printf("%s: Phase mismatch with no active command?\n",
+ sc->sc_dev.dv_xname);
+#endif
+ if (acb->iob_len) {
+ int adjust;
+ adjust = ((dfifo - (dbc & 0x7f)) & 0x7f);
+ if (sstat1 & SIOP_SSTAT1_ORF)
+ ++adjust;
+ if (sstat1 & SIOP_SSTAT1_OLF)
+ ++adjust;
+ acb->iob_curlen = *((long *)&rp->siop_dcmd) & 0xffffff;
+ acb->iob_curlen += adjust;
+ acb->iob_curbuf = *((long *)&rp->siop_dnad) - adjust;
+#ifdef DEBUG
+ if (siop_debug & 0x100) {
+ int i;
+ printf ("Phase mismatch: curbuf %x curlen %x dfifo %x dbc %x sstat1 %x adjust %x sbcl %x starts %d acb %x\n",
+ acb->iob_curbuf, acb->iob_curlen, dfifo,
+ dbc, sstat1, adjust, rp->siop_sbcl, siopstarts, acb);
+ if (acb->ds.chain[1].datalen) {
+ for (i = 0; acb->ds.chain[i].datalen; ++i)
+ printf("chain[%d] addr %x len %x\n",
+ i, acb->ds.chain[i].databuf,
+ acb->ds.chain[i].datalen);
+ }
+ }
+#endif
+ dma_cachectl (acb, sizeof(*acb));
+ }
+#ifdef DEBUG
+ SIOP_TRACE('m',rp->siop_sbcl,(rp->siop_dsp>>8),rp->siop_dsp);
+ if (siop_debug & 9)
+ printf ("Phase mismatch: %x dsp +%x dcmd %x\n",
+ rp->siop_sbcl,
+ rp->siop_dsp - sc->sc_scriptspa,
+ *((long *)&rp->siop_dcmd));
+#endif
+ if ((rp->siop_sbcl & SIOP_REQ) == 0) {
+ printf ("Phase mismatch: REQ not asserted! %02x dsp %x\n",
+ rp->siop_sbcl, rp->siop_dsp);
+#ifdef DEBUG
+ Debugger();
+#endif
+ }
+ switch (rp->siop_sbcl & 7) {
+ case 0: /* data out */
+ case 1: /* data in */
+ case 2: /* status */
+ case 3: /* command */
+ case 6: /* message in */
+ case 7: /* message out */
+ rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
+ break;
+ default:
+ goto bad_phase;
+ }
+ return 0;
+ }
+ if (sstat0 & SIOP_SSTAT0_STO) { /* Select timed out */
+#ifdef DEBUG
+ if (acb == NULL)
+ printf("%s: Select timeout with no active command?\n",
+ sc->sc_dev.dv_xname);
+ if (rp->siop_sbcl & SIOP_BSY) {
+ printf ("ACK! siop was busy at timeout: rp %x script %x dsa %x\n",
+ rp, &scripts, &acb->ds);
+ printf(" sbcl %x sdid %x istat %x dstat %x sstat0 %x\n",
+ rp->siop_sbcl, rp->siop_sdid, istat, dstat, sstat0);
+ if (!(rp->siop_sbcl & SIOP_BSY)) {
+ printf ("Yikes, it's not busy now!\n");
+#if 0
+ *status = -1;
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+ return 1;
+#endif
+ }
+/* rp->siop_dcntl |= SIOP_DCNTL_STD;*/
+ return (0);
+#ifdef DDB
+ Debugger();
+#endif
+ }
+#endif
+ *status = -1;
+ acb->xs->error = XS_SELTIMEOUT;
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+ return 1;
+ }
+ if (acb)
+ target = acb->xs->sc_link->target;
+ else
+ target = 7;
+ if (sstat0 & SIOP_SSTAT0_UDC) {
+#ifdef DEBUG
+ if (acb == NULL)
+ printf("%s: Unexpected disconnect with no active command?\n",
+ sc->sc_dev.dv_xname);
+ printf ("%s: target %d disconnected unexpectedly\n",
+ sc->sc_dev.dv_xname, target);
+#endif
+#if 0
+ siopabort (sc, rp, "siopchkintr");
+#endif
+ *status = STS_BUSY;
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+ return 1;
+ }
+ if (dstat & SIOP_DSTAT_SIR && (rp->siop_dsps == 0xff01 ||
+ rp->siop_dsps == 0xff02)) {
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: ID %02x disconnected TEMP %x (+%x) curbuf %x curlen %x buf %x len %x dfifo %x dbc %x sstat1 %x starts %d acb %x\n",
+ sc->sc_dev.dv_xname, 1 << target, rp->siop_temp,
+ rp->siop_temp ? rp->siop_temp - sc->sc_scriptspa : 0,
+ acb->iob_curbuf, acb->iob_curlen,
+ acb->ds.chain[0].databuf, acb->ds.chain[0].datalen, dfifo, dbc, sstat1, siopstarts, acb);
+#endif
+ if (acb == NULL) {
+ printf("%s: Disconnect with no active command?\n",
+ sc->sc_dev.dv_xname);
+ return (0);
+ }
+ /*
+ * XXXX need to update iob_curbuf/iob_curlen to reflect
+ * current data transferred. If device disconnected in
+ * the middle of a DMA block, they should already be set
+ * by the phase change interrupt. If the disconnect
+ * occurs on a DMA block boundary, we have to figure out
+ * which DMA block it was.
+ */
+ if (acb->iob_len && rp->siop_temp) {
+ int n = rp->siop_temp - sc->sc_scriptspa;
+
+ if (acb->iob_curlen && acb->iob_curlen != acb->ds.chain[0].datalen)
+ printf("%s: iob_curbuf/len already set? n %x iob %x/%x chain[0] %x/%x\n",
+ sc->sc_dev.dv_xname, n, acb->iob_curbuf, acb->iob_curlen,
+ acb->ds.chain[0].databuf, acb->ds.chain[0].datalen);
+ if (n < Ent_datain)
+ n = (n - Ent_dataout) / 16;
+ else
+ n = (n - Ent_datain) / 16;
+ if (n <= 0 && n > DMAMAXIO)
+ printf("TEMP invalid %d\n", n);
+ else {
+ acb->iob_curbuf = (u_long)acb->ds.chain[n].databuf;
+ acb->iob_curlen = acb->ds.chain[n].datalen;
+ }
+#ifdef DEBUG
+ if (siop_debug & 0x100) {
+ printf("%s: TEMP offset %d", sc->sc_dev.dv_xname, n);
+ printf(" curbuf %x curlen %x\n", acb->iob_curbuf,
+ acb->iob_curlen);
+ }
+#endif
+ }
+ /*
+ * If data transfer was interrupted by disconnect, iob_curbuf
+ * and iob_curlen should reflect the point of interruption.
+ * Adjust the DMA chain so that the data transfer begins
+ * at the appropriate place upon reselection.
+ * XXX This should only be done on save data pointer message?
+ */
+ if (acb->iob_curlen) {
+ int i, j;
+
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: adjusting DMA chain\n",
+ sc->sc_dev.dv_xname);
+ if (rp->siop_dsps == 0xff02)
+ printf ("%s: ID %02x disconnected without Save Data Pointers\n",
+ sc->sc_dev.dv_xname, 1 << target);
+#endif
+ for (i = 0; i < DMAMAXIO; ++i) {
+ if (acb->ds.chain[i].datalen == 0)
+ break;
+ if (acb->iob_curbuf >= (long)acb->ds.chain[i].databuf &&
+ acb->iob_curbuf < (long)(acb->ds.chain[i].databuf +
+ acb->ds.chain[i].datalen))
+ break;
+ }
+ if (i >= DMAMAXIO || acb->ds.chain[i].datalen == 0)
+ printf("couldn't find saved data pointer\n");
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf(" chain[0]: %x/%x -> %x/%x\n",
+ acb->ds.chain[0].databuf,
+ acb->ds.chain[0].datalen,
+ acb->iob_curbuf,
+ acb->iob_curlen);
+#endif
+ acb->ds.chain[0].databuf = (char *)acb->iob_curbuf;
+ acb->ds.chain[0].datalen = acb->iob_curlen;
+ for (j = 1, ++i; i < DMAMAXIO && acb->ds.chain[i].datalen; ++i, ++j) {
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf(" chain[%d]: %x/%x -> %x/%x\n", j,
+ acb->ds.chain[j].databuf,
+ acb->ds.chain[j].datalen,
+ acb->ds.chain[i].databuf,
+ acb->ds.chain[i].datalen);
+#endif
+ acb->ds.chain[j].databuf = acb->ds.chain[i].databuf;
+ acb->ds.chain[j].datalen = acb->ds.chain[i].datalen;
+ }
+ if (j < DMAMAXIO)
+ acb->ds.chain[j].datalen = 0;
+ DCIAS(kvtop(&acb->ds.chain));
+ }
+ ++sc->sc_tinfo[target].dconns;
+ /*
+ * add nexus to waiting list
+ * clear nexus
+ * try to start another command for another target/lun
+ */
+ acb->status = sc->sc_flags & SIOP_INTSOFF;
+ TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain);
+ sc->sc_nexus = NULL; /* no current device */
+ /* start script to wait for reselect */
+ if (sc->sc_nexus == NULL)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+/* XXXX start another command ? */
+ if (sc->ready_list.tqh_first)
+ siop_sched(sc);
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff03) {
+ int reselid = rp->siop_scratch & 0x7f;
+ int reselun = rp->siop_sfbr & 0x07;
+
+ sc->sc_sstat1 = rp->siop_sbcl; /* XXXX save current SBCL */
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: target ID %02x reselected dsps %x\n",
+ sc->sc_dev.dv_xname, reselid,
+ rp->siop_dsps);
+ if ((rp->siop_sfbr & 0x80) == 0)
+ printf("%s: Reselect message in was not identify: %x\n",
+ sc->sc_dev.dv_xname, rp->siop_sfbr);
+#endif
+ if (sc->sc_nexus) {
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: reselect ID %02x w/active\n",
+ sc->sc_dev.dv_xname, reselid);
+#endif
+ TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain);
+ sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target].lubusy
+ &= ~(1 << sc->sc_nexus->xs->sc_link->lun);
+ --sc->sc_active;
+ }
+ /*
+ * locate acb of reselecting device
+ * set sc->sc_nexus to acb
+ */
+ for (acb = sc->nexus_list.tqh_first; acb;
+ acb = acb->chain.tqe_next) {
+ if (reselid != (acb->ds.scsi_addr >> 16) ||
+ reselun != (acb->msgout[0] & 0x07))
+ continue;
+ TAILQ_REMOVE(&sc->nexus_list, acb, chain);
+ sc->sc_nexus = acb;
+ sc->sc_flags |= acb->status;
+ acb->status = 0;
+ DCIAS(kvtop(&acb->stat[0]));
+ rp->siop_dsa = kvtop(&acb->ds);
+ rp->siop_sxfer = sc->sc_sync[acb->xs->sc_link->target].sxfer;
+ rp->siop_sbcl = sc->sc_sync[acb->xs->sc_link->target].sbcl;
+ break;
+ }
+ if (acb == NULL) {
+ printf("%s: target ID %02x reselect nexus_list %x\n",
+ sc->sc_dev.dv_xname, reselid,
+ sc->nexus_list.tqh_first);
+ panic("unable to find reselecting device");
+ }
+ dma_cachectl (acb, sizeof(*acb));
+ rp->siop_temp = 0;
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff04) {
+ u_short ctest2 = rp->siop_ctest2;
+
+ /* reselect was interrupted (by Sig_P or select) */
+#ifdef DEBUG
+ if (siop_debug & 0x100 ||
+ (ctest2 & SIOP_CTEST2_SIGP) == 0)
+ printf ("%s: reselect interrupted (Sig_P?) scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
+ sc->sc_dev.dv_xname, rp->siop_scntl1,
+ ctest2, rp->siop_sfbr, istat, rp->siop_istat);
+#endif
+ /* XXX assumes it was not select */
+ if (sc->sc_nexus == NULL) {
+ printf("%s: reselect interrupted, sc_nexus == NULL\n",
+ sc->sc_dev.dv_xname);
+#if 0
+ siop_dump(sc);
+#ifdef DDB
+ Debugger();
+#endif
+#endif
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return(0);
+ }
+ target = sc->sc_nexus->xs->sc_link->target;
+ rp->siop_temp = 0;
+ rp->siop_dsa = kvtop(&sc->sc_nexus->ds);
+ rp->siop_sxfer = sc->sc_sync[target].sxfer;
+ rp->siop_sbcl = sc->sc_sync[target].sbcl;
+ rp->siop_dsp = sc->sc_scriptspa;
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff06) {
+ if (acb == NULL)
+ printf("%s: Bad message-in with no active command?\n",
+ sc->sc_dev.dv_xname);
+ /* Unrecognized message in byte */
+ dma_cachectl (&acb->msg[1],1);
+ printf ("%s: Unrecognized message in data sfbr %x msg %x sbcl %x\n",
+ sc->sc_dev.dv_xname, rp->siop_sfbr, acb->msg[1], rp->siop_sbcl);
+ /* what should be done here? */
+ DCIAS(kvtop(&acb->msg[1]));
+ rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff0a) {
+ /* Status phase wasn't followed by message in phase? */
+ printf ("%s: Status phase not followed by message in phase? sbcl %x sbdl %x\n",
+ sc->sc_dev.dv_xname, rp->siop_sbcl, rp->siop_sbdl);
+ if (rp->siop_sbcl == 0xa7) {
+ /* It is now, just continue the script? */
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return (0);
+ }
+ }
+ if (sstat0 == 0 && dstat & SIOP_DSTAT_SIR) {
+ dma_cachectl (&acb->stat[0], 1);
+ dma_cachectl (&acb->msg[0], 1);
+ printf ("SIOP interrupt: %x sts %x msg %x %x sbcl %x\n",
+ rp->siop_dsps, acb->stat[0], acb->msg[0], acb->msg[1],
+ rp->siop_sbcl);
+ siopreset (sc);
+ *status = -1;
+ return 0; /* siopreset has cleaned up */
+ }
+ if (sstat0 & SIOP_SSTAT0_SGE)
+ printf ("SIOP: SCSI Gross Error\n");
+ if (sstat0 & SIOP_SSTAT0_PAR)
+ printf ("SIOP: Parity Error\n");
+ if (dstat & SIOP_DSTAT_IID)
+ printf ("SIOP: Invalid instruction detected\n");
+bad_phase:
+ /*
+ * temporary panic for unhandled conditions
+ * displays various things about the 53C710 status and registers
+ * then panics.
+ * XXXX need to clean this up to print out the info, reset, and continue
+ */
+ printf ("siopchkintr: target %x ds %x\n", target, &acb->ds);
+ printf ("scripts %x ds %x rp %x dsp %x dcmd %x\n", sc->sc_scriptspa,
+ kvtop(&acb->ds), kvtop(rp), rp->siop_dsp,
+ *((long *)&rp->siop_dcmd));
+ printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x dsa %x sbcl %x sts %x msg %x %x sfbr %x\n",
+ istat, dstat, sstat0, rp->siop_dsps, rp->siop_dsa,
+ rp->siop_sbcl, acb->stat[0], acb->msg[0], acb->msg[1], rp->siop_sfbr);
+#ifdef DEBUG
+ if (siop_debug & 0x20)
+ panic("siopchkintr: **** temp ****");
+#endif
+#ifdef DDB
+ Debugger ();
+#endif
+ siopreset (sc); /* hard reset */
+ *status = -1;
+ return 0; /* siopreset cleaned up */
+}
+
+void
+siop_select(sc)
+ struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ struct siop_acb *acb = sc->sc_nexus;
+
+#ifdef DEBUG
+ if (siop_debug & 1)
+ printf ("%s: select ", sc->sc_dev.dv_xname);
+#endif
+
+ rp = sc->sc_siopp;
+ if (acb->xs->flags & SCSI_POLL || siop_no_dma) {
+ sc->sc_flags |= SIOP_INTSOFF;
+ sc->sc_flags &= ~SIOP_INTDEFER;
+ if ((rp->siop_istat & 0x08) == 0) {
+ rp->siop_sien = 0;
+ rp->siop_dien = 0;
+ }
+#if 0
+ } else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
+ sc->sc_flags &= ~SIOP_INTSOFF;
+ if ((rp->siop_istat & 0x08) == 0) {
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+ }
+#endif
+ }
+#ifdef DEBUG
+ if (siop_debug & 1)
+ printf ("siop_select: target %x cmd %02x ds %x\n",
+ acb->xs->sc_link->target, acb->cmd.opcode,
+ &sc->sc_nexus->ds);
+#endif
+
+ siop_start(sc, acb->xs->sc_link->target, acb->xs->sc_link->lun,
+ &acb->cmd, acb->clen, acb->daddr, acb->dleft);
+
+ return;
+}
+
+/*
+ * 53C710 interrupt handler
+ */
+
+int
+siopintr (sc)
+ register struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ register u_char istat, dstat, sstat0;
+ int status;
+ int s = splbio();
+
+ istat = sc->sc_istat;
+ if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
+ splx(s);
+ return;
+ }
+
+ /* Got a valid interrupt on this device */
+ rp = sc->sc_siopp;
+ dstat = sc->sc_dstat;
+ sstat0 = sc->sc_sstat0;
+ if (dstat & SIOP_DSTAT_SIR)
+ sc->sc_intcode = rp->siop_dsps;
+ sc->sc_istat = 0;
+#ifdef DEBUG
+ if (siop_debug & 1)
+ printf ("%s: intr istat %x dstat %x sstat0 %x\n",
+ sc->sc_dev.dv_xname, istat, dstat, sstat0);
+ if (!sc->sc_active) {
+ printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x status %x\n",
+ sc->sc_dev.dv_xname, istat, dstat, sstat0, sc->sc_nexus->stat[0]);
+ }
+#endif
+
+#ifdef DEBUG
+ if (siop_debug & 5) {
+ DCIAS(kvtop(&sc->sc_nexus->stat[0]));
+ printf ("%s: intr istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
+ sc->sc_dev.dv_xname, istat, dstat, sstat0,
+ rp->siop_dsps, rp->siop_sbcl,
+ sc->sc_nexus->stat[0], sc->sc_nexus->msg[0]);
+ }
+#endif
+ if (sc->sc_flags & SIOP_INTDEFER) {
+ sc->sc_flags &= ~(SIOP_INTDEFER | SIOP_INTSOFF);
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+ }
+ if (siop_checkintr (sc, istat, dstat, sstat0, &status)) {
+#if 1
+ if (status == 0xff)
+ printf ("siopintr: status == 0xff\n");
+#endif
+ if ((sc->sc_flags & (SIOP_INTSOFF | SIOP_INTDEFER)) != SIOP_INTSOFF) {
+#if 0
+ if (rp->siop_sbcl & SIOP_BSY) {
+ printf ("%s: SCSI bus busy at completion",
+ sc->sc_dev.dv_xname);
+ printf(" targ %d sbcl %02x sfbr %x lcrc %02x dsp +%x\n",
+ sc->sc_nexus->xs->sc_link->target,
+ rp->siop_sbcl, rp->siop_sfbr, rp->siop_lcrc,
+ rp->siop_dsp - sc->sc_scriptspa);
+ }
+#endif
+ siop_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
+ }
+ }
+ splx(s);
+}
+
+/*
+ * This is based on the Progressive Peripherals 33Mhz Zeus driver and will
+ * not be correct for other 53c710 boards.
+ *
+ */
+scsi_period_to_siop (sc, target)
+ struct siop_softc *sc;
+{
+ int period, offset, i, sxfer, sbcl;
+
+ period = sc->sc_nexus->msg[4];
+ offset = sc->sc_nexus->msg[5];
+ for (sbcl = 1; sbcl < 4; ++sbcl) {
+ sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
+ if (sxfer >= 0 && sxfer <= 7)
+ break;
+ }
+ if (sbcl > 3) {
+ printf("siop_sync: unable to compute sync params for period %dns\n",
+ period * 4);
+ /*
+ * XXX need to pick a value we can do and renegotiate
+ */
+ sxfer = sbcl = 0;
+ } else
+ sxfer = (sxfer << 4) | ((offset <= SIOP_MAX_OFFSET) ?
+ offset : SIOP_MAX_OFFSET);
+ sc->sc_sync[target].sxfer = sxfer;
+ sc->sc_sync[target].sbcl = sbcl;
+#ifdef DEBUG
+ printf ("siop sync: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl);
+#endif
+}
+
+#ifdef DEBUG
+
+#if SIOP_TRACE_SIZE
+void
+siop_dump_trace()
+{
+ int i;
+
+ printf("siop trace: next index %d\n", siop_trix);
+ i = siop_trix;
+ do {
+ printf("%3d: '%c' %02x %02x %02x\n", i, siop_trbuf[i],
+ siop_trbuf[i + 1], siop_trbuf[i + 2], siop_trbuf[i + 3]);
+ i = (i + 4) & (SIOP_TRACE_SIZE - 1);
+ } while (i != siop_trix);
+}
+#endif
+
+void
+siop_dump_acb(acb)
+ struct siop_acb *acb;
+{
+ u_char *b = (u_char *) &acb->cmd;
+ int i;
+
+#if SIOP_TRACE_SIZE
+ siop_dump_trace();
+#endif
+ printf("acb@%x ", acb);
+ if (acb->xs == NULL) {
+ printf("<unused>\n");
+ return;
+ }
+ printf("(%d:%d) flags %2x clen %2d cmd ", acb->xs->sc_link->target,
+ acb->xs->sc_link->lun, acb->flags, acb->clen);
+ for (i = acb->clen; i; --i)
+ printf(" %02x", *b++);
+ printf("\n");
+ printf(" xs: %08x data %8x:%04x ", acb->xs, acb->xs->data,
+ acb->xs->datalen);
+ printf("va %8x:%04x ", acb->iob_buf, acb->iob_len);
+ printf("cur %8x:%04x\n", acb->iob_curbuf, acb->iob_curlen);
+ }
+
+void
+siop_dump(sc)
+ struct siop_softc *sc;
+{
+ struct siop_acb *acb;
+ siop_regmap_p rp = sc->sc_siopp;
+ int s;
+ int i;
+
+ s = splbio();
+ printf("%s@%x regs %x istat %x\n",
+ sc->sc_dev.dv_xname, sc, rp, rp->siop_istat);
+ if (acb = sc->free_list.tqh_first) {
+ printf("Free list:\n");
+ while (acb) {
+ siop_dump_acb(acb);
+ acb = acb->chain.tqe_next;
+ }
+ }
+ if (acb = sc->ready_list.tqh_first) {
+ printf("Ready list:\n");
+ while (acb) {
+ siop_dump_acb(acb);
+ acb = acb->chain.tqe_next;
+ }
+ }
+ if (acb = sc->nexus_list.tqh_first) {
+ printf("Nexus list:\n");
+ while (acb) {
+ siop_dump_acb(acb);
+ acb = acb->chain.tqe_next;
+ }
+ }
+ if (sc->sc_nexus) {
+ printf("Nexus:\n");
+ siop_dump_acb(sc->sc_nexus);
+ }
+ for (i = 0; i < 8; ++i) {
+ if (sc->sc_tinfo[i].cmds > 2) {
+ printf("tgt %d: cmds %d disc %d senses %d lubusy %x\n",
+ i, sc->sc_tinfo[i].cmds,
+ sc->sc_tinfo[i].dconns,
+ sc->sc_tinfo[i].senses,
+ sc->sc_tinfo[i].lubusy);
+ }
+ }
+ splx(s);
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/siop_script.out b/sys/arch/mvme68k/dev/siop_script.out
new file mode 100644
index 00000000000..c6a91178fc8
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siop_script.out
@@ -0,0 +1,175 @@
+unsigned long scripts[] = {
+ 0x47000000, 0x00000118, /* 000 - 0 */
+ 0x878b0000, 0x00000030, /* 008 - 8 */
+ 0x868a0000, 0x00000168, /* 010 - 16 */
+ 0x828a0000, 0x00000170, /* 018 - 24 */
+ 0x808a0000, 0x00000180, /* 020 - 32 */
+ 0x818a0000, 0x00000288, /* 028 - 40 */
+ 0x838a0000, 0x00000390, /* 030 - 48 */
+ 0x98080000, 0x0000ff05, /* 038 - 56 */
+ 0x1f000024, 0x00000024, /* 040 - 64 */
+ 0x808c0001, 0x00000040, /* 048 - 72 */
+ 0x808c0004, 0x00000078, /* 050 - 80 */
+ 0x808c0002, 0x00000088, /* 058 - 88 */
+ 0x808c0007, 0x00000010, /* 060 - 96 */
+ 0x808c0003, 0x00000008, /* 068 - 104 */
+ 0x98080000, 0x0000ff06, /* 070 - 112 */
+ 0x60000040, 0x00000000, /* 078 - 120 */
+ 0x60000008, 0x00000000, /* 080 - 128 */
+ 0x80880000, 0xffffff78, /* 088 - 136 */
+ 0x60000040, 0x00000000, /* 090 - 144 */
+ 0x1f00002c, 0x0000002c, /* 098 - 152 */
+ 0x808c0003, 0x00000008, /* 0a0 - 160 */
+ 0x98080000, 0x0000ff07, /* 0a8 - 168 */
+ 0x60000040, 0x00000000, /* 0b0 - 176 */
+ 0x1f000034, 0x00000034, /* 0b8 - 184 */
+ 0x60000040, 0x00000000, /* 0c0 - 192 */
+ 0x80880000, 0xffffff38, /* 0c8 - 200 */
+ 0x60000040, 0x00000000, /* 0d0 - 208 */
+ 0x48000000, 0x00000000, /* 0d8 - 216 */
+ 0x98080000, 0x0000ff02, /* 0e0 - 224 */
+ 0x60000040, 0x00000000, /* 0e8 - 232 */
+ 0x87830000, 0xffffff10, /* 0f0 - 240 */
+ 0x1f00002c, 0x0000002c, /* 0f8 - 248 */
+ 0x98040004, 0x0000ff08, /* 100 - 256 */
+ 0x60000040, 0x00000000, /* 108 - 264 */
+ 0x48000000, 0x00000000, /* 110 - 272 */
+ 0x98080000, 0x0000ff01, /* 118 - 280 */
+ 0x54000000, 0x00000038, /* 120 - 288 */
+ 0x72230000, 0x00000000, /* 128 - 296 */
+ 0x6a340000, 0x00000000, /* 130 - 304 */
+ 0x9f030000, 0x0000ff09, /* 138 - 312 */
+ 0x1f00001c, 0x0000001c, /* 140 - 320 */
+ 0x98080000, 0x0000ff03, /* 148 - 328 */
+ 0x60000040, 0x00000000, /* 150 - 336 */
+ 0x80880000, 0xfffffea8, /* 158 - 344 */
+ 0x74011000, 0x00000000, /* 160 - 352 */
+ 0x980c0000, 0x0000ff04, /* 168 - 360 */
+ 0x74164000, 0x00000000, /* 170 - 368 */
+ 0x80880000, 0xffffffa0, /* 178 - 376 */
+ 0x1e000004, 0x00000004, /* 180 - 384 */
+ 0x80880000, 0xfffffe78, /* 188 - 392 */
+ 0x60000008, 0x00000000, /* 190 - 400 */
+ 0x1a00000c, 0x0000000c, /* 198 - 408 */
+ 0x80880000, 0xfffffe60, /* 1a0 - 416 */
+ 0x1800003c, 0x0000003c, /* 1a8 - 424 */
+ 0x88830000, 0xfffffe50, /* 1b0 - 432 */
+ 0x18000044, 0x00000044, /* 1b8 - 440 */
+ 0x88830000, 0xfffffe40, /* 1c0 - 448 */
+ 0x1800004c, 0x0000004c, /* 1c8 - 456 */
+ 0x88830000, 0xfffffe30, /* 1d0 - 464 */
+ 0x18000054, 0x00000054, /* 1d8 - 472 */
+ 0x88830000, 0xfffffe20, /* 1e0 - 480 */
+ 0x1800005c, 0x0000005c, /* 1e8 - 488 */
+ 0x88830000, 0xfffffe10, /* 1f0 - 496 */
+ 0x18000064, 0x00000064, /* 1f8 - 504 */
+ 0x88830000, 0xfffffe00, /* 200 - 512 */
+ 0x1800006c, 0x0000006c, /* 208 - 520 */
+ 0x88830000, 0xfffffdf0, /* 210 - 528 */
+ 0x18000074, 0x00000074, /* 218 - 536 */
+ 0x88830000, 0xfffffde0, /* 220 - 544 */
+ 0x1800007c, 0x0000007c, /* 228 - 552 */
+ 0x88830000, 0xfffffdd0, /* 230 - 560 */
+ 0x18000084, 0x00000084, /* 238 - 568 */
+ 0x88830000, 0xfffffdc0, /* 240 - 576 */
+ 0x1800008c, 0x0000008c, /* 248 - 584 */
+ 0x88830000, 0xfffffdb0, /* 250 - 592 */
+ 0x18000094, 0x00000094, /* 258 - 600 */
+ 0x88830000, 0xfffffda0, /* 260 - 608 */
+ 0x1800009c, 0x0000009c, /* 268 - 616 */
+ 0x88830000, 0xfffffd90, /* 270 - 624 */
+ 0x180000a4, 0x000000a4, /* 278 - 632 */
+ 0x88830000, 0xfffffd80, /* 280 - 640 */
+ 0x180000ac, 0x000000ac, /* 288 - 648 */
+ 0x88830000, 0xfffffd70, /* 290 - 656 */
+ 0x180000b4, 0x000000b4, /* 298 - 664 */
+ 0x88830000, 0xfffffd60, /* 2a0 - 672 */
+ 0x180000bc, 0x000000bc, /* 2a8 - 680 */
+ 0x88880000, 0xfffffd50, /* 2b0 - 688 */
+ 0x1900003c, 0x0000003c, /* 2b8 - 696 */
+ 0x89830000, 0xfffffd40, /* 2c0 - 704 */
+ 0x19000044, 0x00000044, /* 2c8 - 712 */
+ 0x89830000, 0xfffffd30, /* 2d0 - 720 */
+ 0x1900004c, 0x0000004c, /* 2d8 - 728 */
+ 0x89830000, 0xfffffd20, /* 2e0 - 736 */
+ 0x19000054, 0x00000054, /* 2e8 - 744 */
+ 0x89830000, 0xfffffd10, /* 2f0 - 752 */
+ 0x1900005c, 0x0000005c, /* 2f8 - 760 */
+ 0x89830000, 0xfffffd00, /* 300 - 768 */
+ 0x19000064, 0x00000064, /* 308 - 776 */
+ 0x89830000, 0xfffffcf0, /* 310 - 784 */
+ 0x1900006c, 0x0000006c, /* 318 - 792 */
+ 0x89830000, 0xfffffce0, /* 320 - 800 */
+ 0x19000074, 0x00000074, /* 328 - 808 */
+ 0x89830000, 0xfffffcd0, /* 330 - 816 */
+ 0x1900007c, 0x0000007c, /* 338 - 824 */
+ 0x89830000, 0xfffffcc0, /* 340 - 832 */
+ 0x19000084, 0x00000084, /* 348 - 840 */
+ 0x89830000, 0xfffffcb0, /* 350 - 848 */
+ 0x1900008c, 0x0000008c, /* 358 - 856 */
+ 0x89830000, 0xfffffca0, /* 360 - 864 */
+ 0x19000094, 0x00000094, /* 368 - 872 */
+ 0x89830000, 0xfffffc90, /* 370 - 880 */
+ 0x1900009c, 0x0000009c, /* 378 - 888 */
+ 0x89830000, 0xfffffc80, /* 380 - 896 */
+ 0x190000a4, 0x000000a4, /* 388 - 904 */
+ 0x89830000, 0xfffffc70, /* 390 - 912 */
+ 0x190000ac, 0x000000ac, /* 398 - 920 */
+ 0x89830000, 0xfffffc60, /* 3a0 - 928 */
+ 0x190000b4, 0x000000b4, /* 3a8 - 936 */
+ 0x89830000, 0xfffffc50, /* 3b0 - 944 */
+ 0x190000bc, 0x000000bc, /* 3b8 - 952 */
+ 0x88880000, 0xfffffc40, /* 3c0 - 960 */
+ 0x1b000014, 0x00000014, /* 3c8 - 968 */
+ 0x9f030000, 0x0000ff0a, /* 3d0 - 976 */
+ 0x1f00001c, 0x0000001c, /* 3d8 - 984 */
+ 0x60000040, 0x00000000, /* 3e0 - 992 */
+ 0x48000000, 0x00000000, /* 3e8 - 1000 */
+ 0x98080000, 0x0000ff00, /* 3f0 - 1008 */
+ 0x80880000, 0xfffffd20, /* 3f8 - 1016 */
+};
+
+#define A_ds_Device 0x00000000
+#define A_ds_MsgOut 0x00000004
+#define A_ds_Cmd 0x0000000c
+#define A_ds_Status 0x00000014
+#define A_ds_Msg 0x0000001c
+#define A_ds_MsgIn 0x00000024
+#define A_ds_ExtMsg 0x0000002c
+#define A_ds_SyncMsg 0x00000034
+#define A_ds_Data1 0x0000003c
+#define A_ds_Data2 0x00000044
+#define A_ds_Data3 0x0000004c
+#define A_ds_Data4 0x00000054
+#define A_ds_Data5 0x0000005c
+#define A_ds_Data6 0x00000064
+#define A_ds_Data7 0x0000006c
+#define A_ds_Data8 0x00000074
+#define A_ds_Data9 0x0000007c
+#define A_ds_Data10 0x00000084
+#define A_ds_Data11 0x0000008c
+#define A_ds_Data12 0x00000094
+#define A_ds_Data13 0x0000009c
+#define A_ds_Data14 0x000000a4
+#define A_ds_Data15 0x000000ac
+#define A_ds_Data16 0x000000b4
+#define A_ds_Data17 0x000000bc
+#define A_ok 0x0000ff00
+#define A_err1 0x0000ff01
+#define A_err2 0x0000ff02
+#define A_err3 0x0000ff03
+#define A_err4 0x0000ff04
+#define A_err5 0x0000ff05
+#define A_err6 0x0000ff06
+#define A_err7 0x0000ff07
+#define A_err8 0x0000ff08
+#define A_err9 0x0000ff09
+#define A_err10 0x0000ff0a
+#define Ent_scripts 0x00000000
+#define Ent_switch 0x00000008
+#define Ent_wait_reselect 0x00000120
+#define Ent_dataout 0x000001a8
+#define Ent_datain 0x000002b8
+
+unsigned long INSTRUCTIONS = 0x00000080;
+unsigned long PATCHES = 0x00000000;
diff --git a/sys/arch/mvme68k/dev/siop_script.ss b/sys/arch/mvme68k/dev/siop_script.ss
new file mode 100644
index 00000000000..f43c74bfe10
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siop_script.ss
@@ -0,0 +1,205 @@
+; $NetBSD: siop_script.ss,v 1.3 1995/08/18 15:28:11 chopps Exp $
+
+;
+; Copyright (c) 1995 Michael L. Hitch
+; 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 Michael L. Hitch.
+; 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.
+;
+
+; NCR 53c710 script
+;
+ABSOLUTE ds_Device = 0
+ABSOLUTE ds_MsgOut = ds_Device + 4
+ABSOLUTE ds_Cmd = ds_MsgOut + 8
+ABSOLUTE ds_Status = ds_Cmd + 8
+ABSOLUTE ds_Msg = ds_Status + 8
+ABSOLUTE ds_MsgIn = ds_Msg + 8
+ABSOLUTE ds_ExtMsg = ds_MsgIn + 8
+ABSOLUTE ds_SyncMsg = ds_ExtMsg + 8
+ABSOLUTE ds_Data1 = ds_SyncMsg + 8
+ABSOLUTE ds_Data2 = ds_Data1 + 8
+ABSOLUTE ds_Data3 = ds_Data2 + 8
+ABSOLUTE ds_Data4 = ds_Data3 + 8
+ABSOLUTE ds_Data5 = ds_Data4 + 8
+ABSOLUTE ds_Data6 = ds_Data5 + 8
+ABSOLUTE ds_Data7 = ds_Data6 + 8
+ABSOLUTE ds_Data8 = ds_Data7 + 8
+ABSOLUTE ds_Data9 = ds_Data8 + 8
+
+ABSOLUTE ok = 0xff00
+ABSOLUTE err1 = 0xff01
+ABSOLUTE err2 = 0xff02
+ABSOLUTE err3 = 0xff03
+ABSOLUTE err4 = 0xff04
+ABSOLUTE err5 = 0xff05
+ABSOLUTE err6 = 0xff06
+ABSOLUTE err7 = 0xff07
+ABSOLUTE err8 = 0xff08
+ABSOLUTE err9 = 0xff09
+ABSOLUTE err10 = 0xff0a
+
+ENTRY scripts
+ENTRY switch
+ENTRY wait_reselect
+ENTRY dataout
+ENTRY datain
+
+PROC scripts:
+
+scripts:
+
+ SELECT ATN FROM ds_Device, REL(reselect)
+;
+switch:
+ JUMP REL(msgin), WHEN MSG_IN
+ JUMP REL(msgout), IF MSG_OUT
+ JUMP REL(command_phase), IF CMD
+ JUMP REL(dataout), IF DATA_OUT
+ JUMP REL(datain), IF DATA_IN
+ JUMP REL(end), IF STATUS
+
+ INT err5 ; Unrecognized phase
+
+msgin:
+ MOVE FROM ds_MsgIn, WHEN MSG_IN
+ JUMP REL(ext_msg), IF 0x01 ; extended message
+ JUMP REL(disc), IF 0x04 ; disconnect message
+ JUMP REL(msg_sdp), IF 0x02 ; save data pointers
+ JUMP REL(msg_rej), IF 0x07 ; message reject
+ JUMP REL(msg_rdp), IF 0x03 ; restore data pointers
+ INT err6 ; unrecognized message
+
+msg_rdp:
+msg_rej:
+ CLEAR ACK
+ CLEAR ATN
+ JUMP REL(switch)
+
+ext_msg:
+ CLEAR ACK
+ MOVE FROM ds_ExtMsg, WHEN MSG_IN
+ JUMP REL(sync_msg), IF 0x03
+ int err7 ; extended message not SDTR
+
+sync_msg:
+ CLEAR ACK
+ MOVE FROM ds_SyncMsg, WHEN MSG_IN
+ CLEAR ACK
+ JUMP REL(switch)
+
+disc:
+ CLEAR ACK
+ WAIT DISCONNECT
+
+ int err2 ; signal disconnect w/o save DP
+
+msg_sdp:
+ CLEAR ACK ; acknowledge message
+ JUMP REL(switch), WHEN NOT MSG_IN
+ MOVE FROM ds_ExtMsg, WHEN MSG_IN
+ INT err8, IF NOT 0x04 ; interrupt if not disconnect
+ CLEAR ACK
+ WAIT DISCONNECT
+
+ INT err1 ; signal disconnect
+
+reselect:
+wait_reselect:
+ WAIT RESELECT REL(select_adr)
+ MOVE LCRC to SFBR ; Save reselect ID
+ MOVE SFBR to SCRATCH0
+
+ INT err9, WHEN NOT MSG_IN ; didn't get IDENTIFY
+ MOVE FROM ds_Msg, WHEN MSG_IN
+ INT err3 ; let host know about reconnect
+ CLEAR ACK ; acknowlege the message
+ JUMP REL(switch)
+
+
+select_adr:
+ MOVE SCNTL1 & 0x10 to SFBR ; get connected status
+ INT err4, IF 0x00 ; tell host if not connected
+ MOVE CTEST2 & 0x40 to SFBR ; clear Sig_P
+ JUMP REL(wait_reselect) ; and try reselect again
+
+msgout:
+ MOVE FROM ds_MsgOut, WHEN MSG_OUT
+ JUMP REL(switch)
+
+command_phase:
+ CLEAR ATN
+ MOVE FROM ds_Cmd, WHEN CMD
+ JUMP REL(switch)
+
+dataout:
+ MOVE FROM ds_Data1, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data2, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data3, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data4, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data5, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data6, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data7, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data8, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data9, WHEN DATA_OUT
+ CALL REL(switch)
+
+datain:
+ MOVE FROM ds_Data1, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data2, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data3, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data4, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data5, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data6, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data7, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data8, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data9, WHEN DATA_IN
+ CALL REL(switch)
+
+end:
+ MOVE FROM ds_Status, WHEN STATUS
+ int err10, WHEN NOT MSG_IN ; status not followed by msg
+ MOVE FROM ds_Msg, WHEN MSG_IN
+ CLEAR ACK
+ WAIT DISCONNECT
+ INT ok ; signal completion
+ JUMP REL(wait_reselect)
diff --git a/sys/arch/mvme68k/dev/siopdma.c b/sys/arch/mvme68k/dev/siopdma.c
new file mode 100644
index 00000000000..439c4a9d3ea
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siopdma.c
@@ -0,0 +1,223 @@
+/* $NetBSD: afsc.c,v 1.6 1995/02/12 19:19:00 chopps Exp $ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1994 Michael L. Hitch
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * 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 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.
+ *
+ * @(#)dma.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/siopreg.h>
+#include <mvme68k/dev/siopvar.h>
+
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+int afscmatch __P((struct device *, void *, void *));
+void afscattach __P((struct device *, struct device *, void *));
+
+int afscprint __P((void *auxp, char *));
+int siopintr __P((struct siop_softc *));
+int afsc_dmaintr __P((struct siop_softc *));
+
+struct scsi_adapter afsc_scsiswitch = {
+ siop_scsicmd,
+ siop_minphys,
+ 0, /* no lun support */
+ 0, /* no lun support */
+};
+
+struct scsi_device afsc_scsidev = {
+ NULL, /* use default error handler */
+ NULL, /* do not have a start function */
+ NULL, /* have no async handler */
+ NULL, /* Use default done routine */
+};
+
+struct cfdriver siopcd = {
+ NULL, "siop", afscmatch, afscattach,
+ DV_DULL, sizeof(struct siop_softc), NULL, 0 };
+
+int
+afscmatch(pdp, vcf, args)
+ struct device *pdp;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+ return (!badvaddr(ca->ca_vaddr, 4));
+}
+
+void
+afscattach(parent, self, auxp)
+ struct device *parent, *self;
+ void *auxp;
+{
+ struct siop_softc *sc = (struct siop_softc *)self;
+ struct confargs *ca = auxp;
+ siop_regmap_p rp;
+ extern int cpuspeed;
+
+ sc->sc_siopp = rp = ca->ca_vaddr;
+
+ /*
+ * siop uses sc_clock_freq to define the dcntl & ctest7 reg values
+ * (was 0x0221, but i added SIOP_CTEST7_SC0 for snooping control)
+ * XXX does the clock frequency change for the 33MHz processors?
+ */
+ sc->sc_clock_freq = cpuspeed * 2;
+#ifdef MVME177
+ /* XXX this is a guess! */
+ if (cputyp == CPU_177)
+ sc->sc_clock_freq = cpuspeed;
+#endif
+ sc->sc_dcntl = SIOP_DCNTL_EA;
+/*X*/ if (sc->sc_clock_freq <= 25)
+/*X*/ sc->sc_dcntl |= (2 << 6);
+/*X*/ else if (sc->sc_clock_freq <= 37)
+/*X*/ sc->sc_dcntl |= (1 << 6);
+/*X*/ else if (sc->sc_clock_freq <= 50)
+/*X*/ sc->sc_dcntl |= (0 << 6);
+/*X*/ else
+/*X*/ sc->sc_dcntl |= (3 << 6);
+
+ sc->sc_ctest7 = SIOP_CTEST7_SNOOP | SIOP_CTEST7_TT1;
+
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = 7; /* XXXX should ask ROM */
+ sc->sc_link.adapter = &afsc_scsiswitch;
+ sc->sc_link.device = &afsc_scsidev;
+ sc->sc_link.openings = 1;
+
+ sc->sc_ih.ih_fn = afsc_dmaintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+
+ siopinitialize(sc);
+
+ switch (ca->ca_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ {
+ struct mcreg *mc = (struct mcreg *)ca->ca_master;
+
+ mcintr_establish(MCV_NCR, &sc->sc_ih);
+ mc->mc_ncrirq = ca->ca_ipl | MC_IRQ_IEN;
+ break;
+ }
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ {
+ struct pcctworeg *pcc2 = (struct pcctworeg *)ca->ca_master;
+
+ pcctwointr_establish(PCC2V_NCR, &sc->sc_ih);
+ pcc2->pcc2_ncrirq = ca->ca_ipl | PCC2_IRQ_IEN;
+ break;
+ }
+#endif
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
+
+ /*
+ * attach all scsi units on us
+ */
+ config_found(self, &sc->sc_link, afscprint);
+}
+
+/*
+ * print diag if pnp is NULL else just extra
+ */
+int
+afscprint(auxp, pnp)
+ void *auxp;
+ char *pnp;
+{
+ if (pnp == NULL)
+ return (UNCONF);
+ return (QUIET);
+}
+
+int
+afsc_dmaintr(sc)
+ struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ u_char istat;
+
+ rp = sc->sc_siopp;
+ istat = rp->siop_istat;
+ if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0)
+ return (0);
+ if ((rp->siop_sien | rp->siop_dien) == 0)
+ return (0); /* no interrupts enabled */
+
+ /*
+ * save interrupt status, DMA status, and SCSI status 0
+ * (may need to deal with stacked interrupts?)
+ */
+ sc->sc_istat = istat;
+ sc->sc_dstat = rp->siop_dstat;
+ sc->sc_sstat0 = rp->siop_sstat0;
+ siopintr(sc);
+ sc->sc_intrcnt.ev_count++;
+ return (1);
+}
+
+#ifdef DEBUG
+void
+afsc_dump()
+{
+ int i;
+
+ for (i = 0; i < afsccd.cd_ndevs; ++i)
+ if (afsccd.cd_devs[i])
+ siop_dump(afsccd.cd_devs[i]);
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/siopreg.h b/sys/arch/mvme68k/dev/siopreg.h
new file mode 100644
index 00000000000..0fce258fbc5
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siopreg.h
@@ -0,0 +1,336 @@
+/* $NetBSD: siopreg.h,v 1.7 1995/08/18 15:28:13 chopps 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. 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.
+ *
+ * @(#)siopreg.h 7.3 (Berkeley) 2/5/91
+ */
+
+/*
+ * NCR 53C710 SCSI interface hardware description.
+ *
+ * From the Mach scsi driver for the 53C700
+ */
+
+typedef struct {
+/*00*/ volatile unsigned char siop_sien; /* rw: SCSI Interrupt Enable */
+/*01*/ volatile unsigned char siop_sdid; /* rw: SCSI Destination ID */
+/*02*/ volatile unsigned char siop_scntl1; /* rw: SCSI control reg 1 */
+/*03*/ volatile unsigned char siop_scntl0; /* rw: SCSI control reg 0 */
+/*04*/ volatile unsigned char siop_socl; /* rw: SCSI Output Control Latch */
+/*05*/ volatile unsigned char siop_sodl; /* rw: SCSI Output Data Latch */
+/*06*/ volatile unsigned char siop_sxfer; /* rw: SCSI Transfer reg */
+/*07*/ volatile unsigned char siop_scid; /* rw: SCSI Chip ID reg */
+/*08*/ volatile unsigned char siop_sbcl; /* ro: SCSI Bus Control Lines */
+/*09*/ volatile unsigned char siop_sbdl; /* ro: SCSI Bus Data Lines */
+/*0a*/ volatile unsigned char siop_sidl; /* ro: SCSI Input Data Latch */
+/*0b*/ volatile unsigned char siop_sfbr; /* ro: SCSI First Byte Received */
+/*0c*/ volatile unsigned char siop_sstat2; /* ro: SCSI status reg 2 */
+/*0d*/ volatile unsigned char siop_sstat1; /* ro: SCSI status reg 1 */
+/*0e*/ volatile unsigned char siop_sstat0; /* ro: SCSI status reg 0 */
+/*0f*/ volatile unsigned char siop_dstat; /* ro: DMA status */
+/*10*/ volatile unsigned long siop_dsa; /* rw: Data Structure Address */
+/*14*/ volatile unsigned char siop_ctest3; /* ro: Chip test register 3 */
+/*15*/ volatile unsigned char siop_ctest2; /* ro: Chip test register 2 */
+/*16*/ volatile unsigned char siop_ctest1; /* ro: Chip test register 1 */
+/*17*/ volatile unsigned char siop_ctest0; /* ro: Chip test register 0 */
+/*18*/ volatile unsigned char siop_ctest7; /* rw: Chip test register 7 */
+/*19*/ volatile unsigned char siop_ctest6; /* rw: Chip test register 6 */
+/*1a*/ volatile unsigned char siop_ctest5; /* rw: Chip test register 5 */
+/*1b*/ volatile unsigned char siop_ctest4; /* rw: Chip test register 4 */
+/*1c*/ volatile unsigned long siop_temp; /* rw: Temporary Stack reg */
+/*20*/ volatile unsigned char siop_lcrc; /* rw: LCRC value */
+/*21*/ volatile unsigned char siop_ctest8; /* rw: Chip test register 8 */
+/*22*/ volatile unsigned char siop_istat; /* rw: Interrupt Status reg */
+/*23*/ volatile unsigned char siop_dfifo; /* rw: DMA FIFO */
+/*24*/ volatile unsigned char siop_dcmd; /* rw: DMA Command Register */
+/*25*/ volatile unsigned char siop_dbc2; /* rw: DMA Byte Counter reg */
+/*26*/ volatile unsigned char siop_dbc1;
+/*27*/ volatile unsigned char siop_dbc0;
+/*28*/ volatile unsigned long siop_dnad; /* rw: DMA Next Address */
+/*2c*/ volatile unsigned long siop_dsp; /* rw: DMA SCRIPTS Pointer reg */
+/*30*/ volatile unsigned long siop_dsps; /* rw: DMA SCRIPTS Pointer Save reg */
+/*34*/ volatile unsigned long siop_scratch; /* rw: Scratch Register */
+/*38*/ volatile unsigned char siop_dcntl; /* rw: DMA Control reg */
+/*39*/ volatile unsigned char siop_dwt; /* rw: DMA Watchdog Timer */
+/*3a*/ volatile unsigned char siop_dien; /* rw: DMA Interrupt Enable */
+/*3b*/ volatile unsigned char siop_dmode; /* rw: DMA Mode reg */
+/*3c*/ volatile unsigned long siop_adder;
+
+} siop_regmap_t;
+typedef volatile siop_regmap_t *siop_regmap_p;
+
+/*
+ * Register defines
+ */
+
+/* Scsi control register 0 (scntl0) */
+
+#define SIOP_SCNTL0_ARB 0xc0 /* Arbitration mode */
+# define SIOP_ARB_SIMPLE 0x00
+# define SIOP_ARB_FULL 0xc0
+#define SIOP_SCNTL0_START 0x20 /* Start Sequence */
+#define SIOP_SCNTL0_WATN 0x10 /* (Select) With ATN */
+#define SIOP_SCNTL0_EPC 0x08 /* Enable Parity Checking */
+#define SIOP_SCNTL0_EPG 0x04 /* Enable Parity Generation */
+#define SIOP_SCNTL0_AAP 0x02 /* Assert ATN on Parity Error */
+#define SIOP_SCNTL0_TRG 0x01 /* Target Mode */
+
+/* Scsi control register 1 (scntl1) */
+
+#define SIOP_SCNTL1_EXC 0x80 /* Extra Clock Cycle of data setup */
+#define SIOP_SCNTL1_ADB 0x40 /* Assert Data Bus */
+#define SIOP_SCNTL1_ESR 0x20 /* Enable Selection/Reselection */
+#define SIOP_SCNTL1_CON 0x10 /* Connected */
+#define SIOP_SCNTL1_RST 0x08 /* Assert RST */
+#define SIOP_SCNTL1_AESP 0x04 /* Assert even SCSI parity */
+#define SIOP_SCNTL1_RES0 0x02 /* Reserved */
+#define SIOP_SCNTL1_RES1 0x01 /* Reserved */
+
+/* Scsi interrupt enable register (sien) */
+
+#define SIOP_SIEN_M_A 0x80 /* Phase Mismatch or ATN active */
+#define SIOP_SIEN_FCMP 0x40 /* Function Complete */
+#define SIOP_SIEN_STO 0x20 /* (Re)Selection timeout */
+#define SIOP_SIEN_SEL 0x10 /* (Re)Selected */
+#define SIOP_SIEN_SGE 0x08 /* SCSI Gross Error */
+#define SIOP_SIEN_UDC 0x04 /* Unexpected Disconnect */
+#define SIOP_SIEN_RST 0x02 /* RST asserted */
+#define SIOP_SIEN_PAR 0x01 /* Parity Error */
+
+/* Scsi chip ID (scid) */
+
+#define SIOP_SCID_VALUE(i) (1<<i)
+
+/* Scsi transfer register (sxfer) */
+
+#define SIOP_SXFER_DHP 0x80 /* Disable Halt on Parity error/ ATN asserted */
+#define SIOP_SXFER_TP 0x70 /* Synch Transfer Period */
+ /* see specs for formulas:
+ Period = TCP * (4 + XFERP )
+ TCP = 1 + CLK + 1..2;
+ */
+#define SIOP_SXFER_MO 0x0f /* Synch Max Offset */
+# define SIOP_MAX_OFFSET 8
+
+/* Scsi output data latch register (sodl) */
+
+/* Scsi output control latch register (socl) */
+
+#define SIOP_REQ 0x80 /* SCSI signal <x> asserted */
+#define SIOP_ACK 0x40
+#define SIOP_BSY 0x20
+#define SIOP_SEL 0x10
+#define SIOP_ATN 0x08
+#define SIOP_MSG 0x04
+#define SIOP_CD 0x02
+#define SIOP_IO 0x01
+
+#define SIOP_PHASE(socl) SCSI_PHASE(socl)
+
+/* Scsi first byte received register (sfbr) */
+
+/* Scsi input data latch register (sidl) */
+
+/* Scsi bus data lines register (sbdl) */
+
+/* Scsi bus control lines register (sbcl). Same as socl */
+
+/* DMA status register (dstat) */
+
+#define SIOP_DSTAT_DFE 0x80 /* DMA FIFO empty */
+#define SIOP_DSTAT_RES 0x40
+#define SIOP_DSTAT_BF 0x20 /* Bus fault */
+#define SIOP_DSTAT_ABRT 0x10 /* Aborted */
+#define SIOP_DSTAT_SSI 0x08 /* SCRIPT Single Step */
+#define SIOP_DSTAT_SIR 0x04 /* SCRIPT Interrupt Instruction */
+#define SIOP_DSTAT_WTD 0x02 /* Watchdog Timeout Detected */
+#define SIOP_DSTAT_IID 0x01 /* Invalid Instruction Detected */
+
+/* Scsi status register 0 (sstat0) */
+
+#define SIOP_SSTAT0_M_A 0x80 /* Phase Mismatch or ATN active */
+#define SIOP_SSTAT0_FCMP 0x40 /* Function Complete */
+#define SIOP_SSTAT0_STO 0x20 /* (Re)Selection timeout */
+#define SIOP_SSTAT0_SEL 0x10 /* (Re)Selected */
+#define SIOP_SSTAT0_SGE 0x08 /* SCSI Gross Error */
+#define SIOP_SSTAT0_UDC 0x04 /* Unexpected Disconnect */
+#define SIOP_SSTAT0_RST 0x02 /* RST asserted */
+#define SIOP_SSTAT0_PAR 0x01 /* Parity Error */
+
+/* Scsi status register 1 (sstat1) */
+
+#define SIOP_SSTAT1_ILF 0x80 /* Input latch (sidl) full */
+#define SIOP_SSTAT1_ORF 0x40 /* output reg (sodr) full */
+#define SIOP_SSTAT1_OLF 0x20 /* output latch (sodl) full */
+#define SIOP_SSTAT1_AIP 0x10 /* Arbitration in progress */
+#define SIOP_SSTAT1_LOA 0x08 /* Lost arbitration */
+#define SIOP_SSTAT1_WOA 0x04 /* Won arbitration */
+#define SIOP_SSTAT1_RST 0x02 /* SCSI RST current value */
+#define SIOP_SSTAT1_SDP 0x01 /* SCSI SDP current value */
+
+/* Scsi status register 2 (sstat2) */
+
+#define SIOP_SSTAT2_FF 0xf0 /* SCSI FIFO flags (bytecount) */
+# define SIOP_SCSI_FIFO_DEEP 8
+#define SIOP_SSTAT2_SDP 0x08 /* Latched (on REQ) SCSI SDP */
+#define SIOP_SSTAT2_MSG 0x04 /* Latched SCSI phase */
+#define SIOP_SSTAT2_CD 0x02
+#define SIOP_SSTAT2_IO 0x01
+
+/* Chip test register 0 (ctest0) */
+
+#define SIOP_CTEST0_RES0 0x80
+#define SIOP_CTEST0_BTD 0x40 /* Byte-to-byte Timer Disable */
+#define SIOP_CTEST0_GRP 0x20 /* Generate Receive Parity for Passthrough */
+#define SIOP_CTEST0_EAN 0x10 /* Enable Active Negation */
+#define SIOP_CTEST0_HSC 0x08 /* Halt SCSI clock */
+#define SIOP_CTEST0_ERF 0x04 /* Extend REQ/ACK Filtering */
+#define SIOP_CTEST0_RES1 0x02
+#define SIOP_CTEST0_DDIR 0x01 /* Xfer direction (1-> from SCSI bus) */
+
+/* Chip test register 1 (ctest1) */
+
+#define SIOP_CTEST1_FMT 0xf0 /* Byte empty in DMA FIFO bottom (high->byte3) */
+#define SIOP_CTEST1_FFL 0x0f /* Byte full in DMA FIFO top, same */
+
+/* Chip test register 2 (ctest2) */
+
+#define SIOP_CTEST2_RES 0x80
+#define SIOP_CTEST2_SIGP 0x40 /* Signal process */
+#define SIOP_CTEST2_SOFF 0x20 /* Synch Offset compare (1-> zero Init, max Tgt */
+#define SIOP_CTEST2_SFP 0x10 /* SCSI FIFO Parity */
+#define SIOP_CTEST2_DFP 0x08 /* DMA FIFO Parity */
+#define SIOP_CTEST2_TEOP 0x04 /* True EOP (a-la 5380) */
+#define SIOP_CTEST2_DREQ 0x02 /* DREQ status */
+#define SIOP_CTEST2_DACK 0x01 /* DACK status */
+
+/* Chip test register 3 (ctest3) read-only, top of SCSI FIFO */
+
+/* Chip test register 4 (ctest4) */
+
+#define SIOP_CTEST4_MUX 0x80 /* Host bus multiplex mode */
+#define SIOP_CTEST4_ZMOD 0x40 /* High-impedance outputs */
+#define SIOP_CTEST4_SZM 0x20 /* ditto, SCSI "outputs" */
+#define SIOP_CTEST4_SLBE 0x10 /* SCSI loobpack enable */
+#define SIOP_CTEST4_SFWR 0x08 /* SCSI FIFO write enable (from sodl) */
+#define SIOP_CTEST4_FBL 0x07 /* DMA FIFO Byte Lane select (from ctest6)
+ 4->0, .. 7->3 */
+
+/* Chip test register 5 (ctest5) */
+
+#define SIOP_CTEST5_ADCK 0x80 /* Clock Address Incrementor */
+#define SIOP_CTEST5_BBCK 0x40 /* Clock Byte counter */
+#define SIOP_CTEST5_ROFF 0x20 /* Reset SCSI offset */
+#define SIOP_CTEST5_MASR 0x10 /* Master set/reset pulses (of bits 3-0) */
+#define SIOP_CTEST5_DDIR 0x08 /* (re)set internal DMA direction */
+#define SIOP_CTEST5_EOP 0x04 /* (re)set internal EOP */
+#define SIOP_CTEST5_DREQ 0x02 /* (re)set internal REQ */
+#define SIOP_CTEST5_DACK 0x01 /* (re)set internal ACK */
+
+/* Chip test register 6 (ctest6) DMA FIFO access */
+
+/* Chip test register 7 (ctest7) */
+
+#define SIOP_CTEST7_CDIS 0x80 /* Cache burst disable */
+#define SIOP_CTEST7_SC1 0x40 /* Snoop control 1 */
+#define SIOP_CTEST7_SC0 0x20 /* Snoop contorl 0 */
+#define SIOP_CTEST7_INHIBIT (0 << 5)
+#define SIOP_CTEST7_SNOOP (1 << 5)
+#define SIOP_CTEST7_INVAL (2 << 5)
+#define SIOP_CTEST7_RESV (3 << 5)
+#define SIOP_CTEST7_STD 0x10 /* Selection timeout disable */
+#define SIOP_CTEST7_DFP 0x08 /* DMA FIFO parity bit */
+#define SIOP_CTEST7_EVP 0x04 /* Even parity (to host bus) */
+#define SIOP_CTEST7_TT1 0x02 /* Transfer type bit */
+#define SIOP_CTEST7_DIFF 0x01 /* Differential mode */
+
+/* DMA FIFO register (dfifo) */
+
+#define SIOP_DFIFO_RES 0x80
+#define SIOP_DFIFO_BO 0x7f /* FIFO byte offset counter */
+
+/* Interrupt status register (istat) */
+
+#define SIOP_ISTAT_ABRT 0x80 /* Abort operation */
+#define SIOP_ISTAT_RST 0x40 /* Software reset */
+#define SIOP_ISTAT_SIGP 0x20 /* Signal process */
+#define SIOP_ISTAT_RES 0x10
+#define SIOP_ISTAT_CON 0x08 /* Connected */
+#define SIOP_ISTAT_RES1 0x04
+#define SIOP_ISTAT_SIP 0x02 /* SCSI Interrupt pending */
+#define SIOP_ISTAT_DIP 0x01 /* DMA Interrupt pending */
+
+/* Chip test register 8 (ctest8)
+
+#define SIOP_CTEST8_V 0xf0 /* Chip revision level */
+#define SIOP_CTEST8_FLF 0x08 /* Flush DMA FIFO */
+#define SIOP_CTEST8_CLF 0x04 /* Clear DMA and SCSI FIFOs */
+#define SIOP_CTEST8_FM 0x02 /* Fetch pin mode */
+#define SIOP_CTEST8_SM 0x01 /* Snoop pins mode */
+
+/* DMA Mode register (dmode) */
+
+#define SIOP_DMODE_BL_MASK 0xc0 /* 0->1 1->2 2->4 3->8 */
+#define SIOP_DMODE_FC 0x30 /* Function code */
+#define SIOP_DMODE_PD 0x08 /* Program/data */
+#define SIOP_DMODE_FAM 0x04 /* Fixed address mode */
+#define SIOP_DMODE_U0 0x02 /* User programmable transfer type */
+#define SIOP_DMODE_MAN 0x01 /* Manual start mode */
+
+/* DMA interrupt enable register (dien) */
+
+#define SIOP_DIEN_RES 0xc0
+#define SIOP_DIEN_BF 0x20 /* On Bus Fault */
+#define SIOP_DIEN_ABRT 0x10 /* On Abort */
+#define SIOP_DIEN_SSI 0x08 /* On SCRIPTS sstep */
+#define SIOP_DIEN_SIR 0x04 /* On SCRIPTS intr instruction */
+#define SIOP_DIEN_WTD 0x02 /* On watchdog timeout */
+#define SIOP_DIEN_IID 0x01 /* On illegal instruction detected */
+
+/* DMA control register (dcntl) */
+
+#define SIOP_DCNTL_CF_MASK 0xc0 /* Clock frequency dividers:
+ 0 --> 37.51..50.00 Mhz, div=2
+ 1 --> 25.01..37.50 Mhz, div=1.5
+ 2 --> 16.67..25.00 Mhz, div=1
+ 3 --> 50.01..66.67 Mhz, div=3
+ */
+#define SIOP_DCNTL_EA 0x20 /* Enable ack */
+#define SIOP_DCNTL_SSM 0x10 /* Single step mode */
+#define SIOP_DCNTL_LLM 0x08 /* Enable SCSI Low-level mode */
+#define SIOP_DCNTL_STD 0x04 /* Start DMA operation */
+#define SIOP_DCNTL_FA 0x02 /* Fast arbitration */
+#define SIOP_DCNTL_COM 0x01 /* 53C700 compatibility */
diff --git a/sys/arch/mvme68k/dev/siopvar.h b/sys/arch/mvme68k/dev/siopvar.h
new file mode 100644
index 00000000000..af0b3c2fc22
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siopvar.h
@@ -0,0 +1,201 @@
+/* $NetBSD: siopvar.h,v 1.11 1995/08/18 15:28:14 chopps 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. 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.
+ *
+ * @(#)siopvar.h 7.1 (Berkeley) 5/8/90
+ */
+#ifndef _SIOPVAR_H_
+#define _SIOPVAR_H_
+
+/*
+ * The largest single request will be MAXPHYS bytes which will require
+ * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
+ * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
+ * buffer is not page aligned (+1).
+ */
+#define DMAMAXIO (MAXPHYS/NBPG+1)
+
+/*
+ * Data Structure for SCRIPTS program
+ */
+struct siop_ds {
+/*00*/ long scsi_addr; /* SCSI ID & sync */
+/*04*/ long idlen; /* Identify message */
+/*08*/ char *idbuf;
+/*0c*/ long cmdlen; /* SCSI command */
+/*10*/ char *cmdbuf;
+/*14*/ long stslen; /* Status */
+/*18*/ char *stsbuf;
+/*1c*/ long msglen; /* Message */
+/*20*/ char *msgbuf;
+/*24*/ long msginlen; /* Message in */
+/*28*/ char *msginbuf;
+/*2c*/ long extmsglen; /* Extended message in */
+/*30*/ char *extmsgbuf;
+/*34*/ long synmsglen; /* Sync transfer request */
+/*38*/ char *synmsgbuf;
+ struct {
+/*3c*/ long datalen;
+/*40*/ char *databuf;
+ } chain[DMAMAXIO];
+};
+
+/*
+ * 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. Basicly, 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 siop_acb {
+/*00*/ TAILQ_ENTRY(siop_acb) chain;
+/*08*/ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+/*0c*/ int flags; /* Status */
+#define ACB_FREE 0x00
+#define ACB_ACTIVE 0x01
+#define ACB_DONE 0x04
+#define ACB_CHKSENSE 0x08
+/*10*/ struct scsi_generic cmd; /* SCSI command block */
+/*1c*/ struct siop_ds ds;
+/*a0*/ void *iob_buf;
+/*a4*/ u_long iob_curbuf;
+/*a8*/ u_long iob_len, iob_curlen;
+/*b0*/ u_char msgout[6];
+/*b6*/ u_char msg[6];
+/*bc*/ u_char stat[1];
+/*bd*/ u_char status;
+/*be*/ u_char dummy[2];
+/*c0*/ int clen;
+/*c4*/ char *daddr; /* Saved data pointer */
+/*c8*/ int dleft; /* Residue */
+};
+
+/*
+ * 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 siop_tinfo {
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ ushort lubusy; /* What local units/subr. are busy? */
+ u_char flags;
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+} tinfo_t;
+
+struct siop_softc {
+ struct device sc_dev;
+ struct intrhand sc_ih;
+ struct evcnt sc_intrcnt;
+
+ u_char sc_istat;
+ u_char sc_dstat;
+ u_char sc_sstat0;
+ u_char sc_sstat1;
+ u_long sc_intcode;
+ struct scsi_link sc_link; /* proto for sub devices */
+ u_long sc_scriptspa; /* physical address of scripts */
+ siop_regmap_p sc_siopp; /* the SIOP */
+ u_long sc_active; /* number of active I/O's */
+
+ /* Lists of command blocks */
+ TAILQ_HEAD(acb_list, siop_acb) free_list,
+ ready_list,
+ nexus_list;
+
+ struct siop_acb *sc_nexus; /* current command */
+ struct siop_acb sc_acb[8]; /* the real command blocks */
+ struct siop_tinfo sc_tinfo[8];
+
+ u_short sc_clock_freq;
+ u_char sc_dcntl;
+ u_char sc_ctest7;
+ u_short sc_tcp[4];
+ u_char sc_flags;
+ u_char sc_sien;
+ u_char sc_dien;
+ u_char sc_minsync;
+ /* one for each target */
+ struct syncpar {
+ u_char state;
+ u_char sxfer;
+ u_char sbcl;
+ } sc_sync[8];
+};
+
+/* sc_flags */
+#define SIOP_INTSOFF 0x80 /* Interrupts turned off */
+#define SIOP_INTDEFER 0x40 /* Level 6 interrupt has been deferred */
+#define SIOP_ALIVE 0x01 /* controller initialized */
+#define SIOP_SELECTED 0x04 /* bus is in selected state. Needed for
+ correct abort procedure. */
+
+/* sync states */
+#define SYNC_START 0 /* no sync handshake started */
+#define SYNC_SENT 1 /* we sent sync request, no answer yet */
+#define SYNC_DONE 2 /* target accepted our (or inferior) settings,
+ or it rejected the request and we stay async */
+
+#define MSG_CMD_COMPLETE 0x00
+#define MSG_EXT_MESSAGE 0x01
+#define MSG_SAVE_DATA_PTR 0x02
+#define MSG_RESTORE_PTR 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_INIT_DETECT_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT 0x07
+#define MSG_NOOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_BUS_DEVICE_RESET 0x0C
+#define MSG_IDENTIFY 0x80
+#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */
+#define MSG_SYNC_REQ 0x01
+
+#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
+#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */
+#define STS_BUSY 0x08
+#define STS_INTERMED 0x10 /* Intermediate status sent */
+#define STS_EXT 0x80 /* Extended status valid */
+
+void siop_minphys __P((struct buf *bp));
+int siop_scsicmd __P((struct scsi_xfer *));
+
+#endif /* _SIOPVAR_H */
diff --git a/sys/arch/mvme68k/dev/sram.c b/sys/arch/mvme68k/dev/sram.c
new file mode 100644
index 00000000000..77299175e89
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sram.c
@@ -0,0 +1,231 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <machine/mioctl.h>
+
+#include "mc.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+
+#include <vm/vm.h>
+
+struct sramsoftc {
+ struct device sc_dev;
+ caddr_t sc_paddr;
+ caddr_t sc_vaddr;
+ int sc_len;
+};
+
+void sramattach __P((struct device *, struct device *, void *));
+int srammatch __P((struct device *, void *, void *));
+
+struct cfdriver sramcd = {
+ NULL, "sram", srammatch, sramattach,
+ DV_DULL, sizeof(struct sramsoftc), 0
+};
+
+int
+srammatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+ if (cputyp == CPU_147)
+ return (0);
+ if (ca->ca_vaddr == (caddr_t)-1)
+ return (!badpaddr(ca->ca_paddr, 1));
+ return (!badvaddr(ca->ca_vaddr, 1));
+}
+
+void
+sramattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct sramsoftc *sc = (struct sramsoftc *)self;
+ struct mcreg *mc;
+ int i;
+
+ switch (cputyp) {
+#ifdef MVME162
+ case CPU_162:
+ /* XXX this code will almost never be used. just in case. */
+ mc = sys_mc;
+ if (!mc)
+ mc = (struct mcreg *)(IIOV(0xfff00000) + MC_MCCHIP_OFF);
+
+ switch (mc->mc_memoptions & MC_MEMOPTIONS_SRAMMASK) {
+ case MC_MEMOPTIONS_SRAM128K:
+ sc->sc_len = 128*1024;
+ break;
+ case MC_MEMOPTIONS_SRAM512K:
+ sc->sc_len = 512*1024;
+ break;
+ case MC_MEMOPTIONS_SRAM1M:
+ sc->sc_len = 1024*1024;
+ break;
+ case MC_MEMOPTIONS_SRAM2M:
+ sc->sc_len = 2048*1024;
+ break;
+ }
+ break;
+#endif
+#ifdef MVME167
+ case CPU_167:
+ case CPU_166:
+ sc->sc_len = 128*1024; /* always 128K */
+ break;
+#endif
+#ifdef MVME177
+ case CPU_177:
+ XXX
+ break;
+#endif
+ default:
+ sc->sc_len = 0;
+ break;
+ }
+
+ printf(": len %d", sc->sc_len);
+
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = mapiodev((caddr_t)sc->sc_paddr, sc->sc_len);
+ if (sc->sc_vaddr == NULL) {
+ sc->sc_len = 0;
+ printf(" -- failed to map");
+ }
+ printf("\n");
+}
+
+/*ARGSUSED*/
+int
+sramopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= sramcd.cd_ndevs ||
+ sramcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+sramclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+sramioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ case MIOCGSIZ:
+ *(int *)data = sc->sc_len;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sramread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+/*ARGSUSED*/
+int
+sramwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+int
+srammmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+
+ if (minor(dev) != 0)
+ return (-1);
+
+ /* allow access only in RAM */
+ if (off > sc->sc_len)
+ return (-1);
+ return (m68k_btop(sc->sc_paddr + off));
+}
diff --git a/sys/arch/mvme68k/dev/vme.c b/sys/arch/mvme68k/dev/vme.c
new file mode 100644
index 00000000000..ddd4099dd63
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vme.c
@@ -0,0 +1,557 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/vme.h>
+
+#include "pcc.h"
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NPCC > 0
+#include <mvme68k/dev/pccreg.h>
+#endif
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+int vmematch __P((struct device *, void *, void *));
+void vmeattach __P((struct device *, struct device *, void *));
+
+int vme1chip_init __P((struct vmesoftc *sc));
+int vme2chip_init __P((struct vmesoftc *sc));
+u_long vme2chip_map __P((u_long base, int len, int dwidth));
+int vme2abort __P((struct frame *frame));
+
+static int vmebustype;
+
+struct cfdriver vmecd = {
+ NULL, "vme", vmematch, vmeattach,
+ DV_DULL, sizeof(struct vmesoftc), 0
+};
+
+int
+vmematch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ struct confargs *ca = args;
+
+#if NMC > 0
+ if (ca->ca_bustype == BUS_MC) {
+ struct mcreg *mc = (struct mcreg *)ca->ca_master;
+
+ if (mc->mc_ver & MC_VER_NOVME)
+ return (0);
+ }
+#endif
+ return (1);
+}
+
+/*
+ * Returns a physical address mapping for a VME address & length.
+ * Note: on some hardware it is not possible to create certain
+ * mappings, ie. the MVME147 cannot do 32 bit accesses to VME bus
+ * addresses from 0 to physmem.
+ */
+caddr_t
+vmepmap(sc, vmeaddr, len, bustype)
+ struct vmesoftc *sc;
+ caddr_t vmeaddr;
+ int len;
+ int bustype;
+{
+ u_long base = (u_long)vmeaddr;
+
+ len = roundup(len, NBPG);
+ switch (vmebustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ switch (bustype) {
+ case BUS_VMES:
+ if (base > VME1_A16BASE &&
+ (base+len - VME1_A16BASE) < VME1_A16D16LEN)
+ base = base - VME1_A16BASE + VME1_A16D16BASE;
+ else if (base+len < VME1_A32D16LEN)
+ base = base + VME1_A32D16BASE;
+ else {
+ printf("%s: cannot map pa %x len %x\n",
+ sc->sc_dev.dv_xname, base, len);
+ return (NULL);
+ }
+ break;
+ case BUS_VMEL:
+ if (base >= physmem && (base+len) < VME1_A32D32LEN)
+ base = base + VME1_A32D32BASE;
+ else if (base+len < VME1_A32D16LEN) /* HACK! */
+ base = base + VME1_A32D16BASE;
+ else {
+ printf("%s: cannot map pa %x len %x\n",
+ sc->sc_dev.dv_xname, base, len);
+ return (NULL);
+ }
+ break;
+ }
+ break;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ case BUS_MC:
+ case BUS_PCCTWO:
+ switch (bustype) {
+ case BUS_VMES:
+ if (base > VME2_A16BASE &&
+ (base+len-VME2_A16BASE) < VME2_A16D16LEN)
+ base = base - VME2_A16BASE + VME2_A16D16BASE;
+ else if (base > VME2_A24BASE &&
+ (base+len-VME2_A24BASE) < VME2_A24D16LEN)
+ base = base - VME2_A24BASE + VME2_A24D16BASE;
+ else if ((base+len) < VME2_A32D16LEN)
+ base = base + VME2_A32D16BASE;
+ else {
+ base = vme2chip_map(base, len, 16);
+ if (base == NULL)
+ return (NULL);
+ }
+ break;
+ case BUS_VMEL:
+#if 0
+ if (base > VME2_A16BASE &&
+ (base+len-VME2_A16BASE) < VME2_A16D32LEN)
+ base = base - VME2_A16BASE + VME2_A16D32BASE;
+#endif
+ base = vme2chip_map(base, len, 32);
+ if (base == NULL)
+ return (NULL);
+ break;
+ }
+ break;
+#endif
+ }
+ return ((caddr_t)base);
+}
+
+/* if successful, returns the va of a vme bus mapping */
+caddr_t
+vmemap(sc, vmeaddr, len, bustype)
+ struct vmesoftc *sc;
+ caddr_t vmeaddr;
+ int len;
+ int bustype;
+{
+ caddr_t pa, va;
+
+ pa = vmepmap(sc, pa, len, bustype);
+ if (pa == NULL)
+ return (NULL);
+ va = mapiodev(pa, len);
+ return (va);
+}
+
+void
+vmeunmap(va, len)
+ caddr_t va;
+ int len;
+{
+ unmapiodev(va, len);
+}
+
+int
+vmerw(sc, uio, flags, bus)
+ struct vmesoftc *sc;
+ struct uio *uio;
+ int flags;
+ int bus;
+{
+ register vm_offset_t o, v;
+ register int c;
+ register struct iovec *iov;
+ caddr_t vme;
+ int error = 0;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("vmerw");
+ continue;
+ }
+
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if ((v & PGOFSET) + c > NBPG) /* max NBPG at a time */
+ c = NBPG - (v & PGOFSET);
+ if (c == 0)
+ return (0);
+ vme = vmemap(sc, (caddr_t)(v & ~PGOFSET),
+ NBPG, BUS_VMES);
+ if (vme == NULL) {
+ error = EFAULT; /* XXX? */
+ continue;
+ }
+ error = uiomove((caddr_t)vme + (v & PGOFSET), c, uio);
+ vmeunmap(vme, NBPG);
+ }
+ return (error);
+}
+
+int
+vmeprint(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ printf(" offset 0x%x", ca->ca_offset);
+ if (ca->ca_vec > 0)
+ printf(" vec %d", ca->ca_vec);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+vmescan(parent, child, args, bustype)
+ struct device *parent;
+ void *child, *args;
+ int bustype;
+{
+ struct cfdata *cf = child;
+ struct vmesoftc *sc = (struct vmesoftc *)parent;
+ struct confargs *ca = args;
+ struct confargs oca;
+
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_bustype = bustype;
+ oca.ca_paddr = (void *)cf->cf_loc[0];
+ oca.ca_len = cf->cf_loc[1];
+ oca.ca_vec = cf->cf_loc[2];
+ oca.ca_ipl = cf->cf_loc[3];
+ if (oca.ca_ipl > 0 && oca.ca_vec == -1)
+ oca.ca_vec = intr_freevec();
+
+ oca.ca_offset = (int)oca.ca_paddr;
+ oca.ca_vaddr = (void *)vmemap(sc, oca.ca_paddr, oca.ca_len,
+ oca.ca_bustype);
+ if (!oca.ca_vaddr)
+ oca.ca_vaddr = (void *)-1;
+ oca.ca_master = (void *)sc;
+ oca.ca_name = cf->cf_driver->cd_name;
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0) {
+ if (oca.ca_vaddr != (void *)-1)
+ vmeunmap(oca.ca_vaddr, oca.ca_len);
+ return (0);
+ }
+ config_attach(parent, cf, &oca, vmeprint);
+ return (1);
+}
+
+void
+vmeattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct vmesoftc *sc = (struct vmesoftc *)self;
+ struct confargs *ca = args;
+ struct vme1reg *vme1;
+ struct vme2reg *vme2;
+ int scon;
+
+ sc->sc_vaddr = ca->ca_vaddr;
+
+ vmebustype = ca->ca_bustype;
+ switch (ca->ca_bustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ vme1 = (struct vme1reg *)sc->sc_vaddr;
+ scon = (vme1->vme1_scon & VME1_SCON_SWITCH);
+ printf(": %sscon\n", scon ? "" : "not ");
+ vme1chip_init(sc);
+ break;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ case BUS_MC:
+ case BUS_PCCTWO:
+ vme2 = (struct vme2reg *)sc->sc_vaddr;
+ scon = (vme2->vme2_tctl & VME2_TCTL_SCON);
+ printf(": %sscon\n", scon ? "" : "not ");
+ vme2chip_init(sc);
+ break;
+#endif
+ }
+
+ while (config_found(self, NULL, NULL))
+ ;
+}
+
+/*
+ * On the VMEbus, only one cpu may be configured to respond to any
+ * particular vme ipl. Therefore, it wouldn't make sense to globally
+ * enable all the interrupts all the time -- it would not be possible
+ * to put two cpu's and one vme card into a single cage. Rather, we
+ * enable each vme interrupt only when we are attaching a device that
+ * uses it. This makes it easier (though not trivial) to put two cpu
+ * cards in one VME cage, and both can have some limited access to vme
+ * interrupts (just can't share the same irq).
+ * Obviously no check is made to see if another cpu is using that
+ * interrupt. If you share you will lose.
+ */
+int
+vmeintr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ struct vmesoftc *sc = (struct vmesoftc *) vmecd.cd_devs[0];
+#if NPCC > 0
+ struct vme1reg *vme1;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ struct vme2reg *vme2;
+#endif
+ int x;
+
+ x = (intr_establish(vec, ih));
+
+ switch (vmebustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ vme1 = (struct vme1reg *)sc->sc_vaddr;
+ vme1->vme1_irqen = vme1->vme1_irqen |
+ VME1_IRQ_VME(ih->ih_ipl);
+ break;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ case BUS_MC:
+ case BUS_PCCTWO:
+ vme2 = (struct vme2reg *)sc->sc_vaddr;
+ vme2->vme2_irqen = vme2->vme2_irqen |
+ VME2_IRQ_VME(ih->ih_ipl);
+ break;
+#endif
+ }
+ return (x);
+}
+
+#if defined(MVME147)
+int
+vme1chip_init(sc)
+ struct vmesoftc *sc;
+{
+ struct vme1reg *vme1 = (struct vme1reg *)sc->sc_vaddr;
+
+ vme1->vme1_scon &= ~VME1_SCON_SYSFAIL; /* XXX doesn't work */
+}
+#endif
+
+#if defined(MVME162) || defined(MVME167) || defined(MVME177)
+
+/*
+ * make local addresses 1G-2G correspond to VME addresses 3G-4G,
+ * as D32
+ */
+#define VME2_D32STARTPHYS (1*1024*1024*1024UL)
+#define VME2_D32ENDPHYS (2*1024*1024*1024UL)
+#define VME2_D32STARTVME (3*1024*1024*1024UL)
+#define VME2_D32BITSVME (3*1024*1024*1024UL)
+
+/*
+ * make local addresses 3G-3.75G correspond to VME addresses 3G-3.75G,
+ * as D16
+ */
+#define VME2_D16STARTPHYS (3*1024*1024*1024UL)
+#define VME2_D16ENDPHYS (3*1024*1024*1024UL + 768*1024*1024UL)
+
+/*
+ * XXX what AM bits should be used for the D32/D16 mappings?
+ */
+int
+vme2chip_init(sc)
+ struct vmesoftc *sc;
+{
+ struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr;
+ u_long ctl;
+
+ /* turn off SYSFAIL LED */
+ vme2->vme2_tctl &= ~VME2_TCTL_SYSFAIL;
+
+ ctl = vme2->vme2_masterctl;
+
+#if 0
+ /* unused decoders 1 & 2 */
+ printf("%s: phys 0x%08x-0x%08x to VMExxx 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000,
+ vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000);
+ printf("%s: phys 0x%08x-0x%08x to VMExxx 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000,
+ vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000);
+#endif
+
+ /* setup a D16 space */
+ vme2->vme2_master3 = ((VME2_D16ENDPHYS-1) & 0xffff0000) |
+ (VME2_D16STARTPHYS >> 16);
+ ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_3SHIFT);
+ ctl |= (VME2_MASTERCTL_AM32SP | VME2_MASTERCTL_D16) <<
+ VME2_MASTERCTL_3SHIFT;
+#if 0
+ printf("%s: phys 0x%08x-0x%08x to VMED16 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ VME2_D16STARTPHYS, VME2_D16ENDPHYS-1,
+ VME2_D16STARTPHYS, VME2_D16ENDPHYS-1);
+#endif
+
+ /* setup a D32 space */
+ vme2->vme2_master4 = ((VME2_D32ENDPHYS-1) & 0xffff0000) |
+ (VME2_D32STARTPHYS >> 16);
+ vme2->vme2_master4mod = (VME2_D32STARTVME & 0xffff0000) |
+ (VME2_D32BITSVME >> 16);
+ ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_4SHIFT);
+ ctl |= (VME2_MASTERCTL_AM32SP) <<
+ VME2_MASTERCTL_4SHIFT;
+#if 0
+ printf("%s: phys 0x%08x-0x%08x to VMED32 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ VME2_D32STARTPHYS, VME2_D32ENDPHYS-1,
+ VME2_D32STARTVME, VME2_D32STARTVME | ~VME2_D32BITSVME);
+#endif
+
+ vme2->vme2_masterctl = ctl;
+
+ ctl = vme2->vme2_gcsrctl;
+
+ /* enable A16 short IO map decoder (0xffffxxxx) */
+ ctl &= ~(VME2_GCSRCTL_I1EN | VME2_GCSRCTL_I1D16 | VME2_GCSRCTL_I1WP |
+ VME2_GCSRCTL_I1SU);
+ ctl |= VME2_GCSRCTL_I1EN | VME2_GCSRCTL_I1D16 | VME2_GCSRCTL_I1SU;
+
+ /* enable A24D16 (0xf0xxxxxx) and A32D16 (0xf[1-e]xxxxxx) decoders */
+ ctl &= ~(VME2_GCSRCTL_I2EN | VME2_GCSRCTL_I2WP | VME2_GCSRCTL_I2SU |
+ VME2_GCSRCTL_I2PD);
+ ctl |= VME2_GCSRCTL_I2EN | VME2_GCSRCTL_I2SU | VME2_GCSRCTL_I2PD;
+
+ /* map decoders 3 & 4 which were just configured */
+ ctl &= ~(VME2_GCSRCTL_MDEN4 | VME2_GCSRCTL_MDEN3 | VME2_GCSRCTL_MDEN1 |
+ VME2_GCSRCTL_MDEN2);
+ ctl |= VME2_GCSRCTL_MDEN4 | VME2_GCSRCTL_MDEN3;
+
+ vme2->vme2_gcsrctl = ctl;
+
+ /*
+ * Map the VME irq levels to the cpu levels 1:1.
+ * This is rather inflexible, but much easier.
+ */
+ vme2->vme2_irql4 = (7 << VME2_IRQL4_VME7SHIFT) |
+ (6 << VME2_IRQL4_VME6SHIFT) | (5 << VME2_IRQL4_VME5SHIFT) |
+ (4 << VME2_IRQL4_VME4SHIFT) | (3 << VME2_IRQL4_VME3SHIFT) |
+ (2 << VME2_IRQL4_VME2SHIFT) | (1 << VME2_IRQL4_VME1SHIFT);
+
+#if NPCCTWO > 0
+ if (vmebustype == BUS_PCCTWO) {
+ sc->sc_abih.ih_fn = vme2abort;
+ sc->sc_abih.ih_arg = 0;
+ sc->sc_abih.ih_ipl = 7;
+ sc->sc_abih.ih_wantframe = 1;
+
+ intr_establish(110, &sc->sc_abih); /* XXX 110 */
+ vme2->vme2_irqen |= VME2_IRQ_AB;
+ }
+#endif
+}
+
+/*
+ * A32 accesses on the MVME1[67]x require setting up mappings in
+ * the VME2 chip.
+ * XXX VME address must be between 2G and 4G
+ * XXX We only support D32 at the moment..
+ */
+u_long
+vme2chip_map(base, len, dwidth)
+ u_long base;
+ int len, dwidth;
+{
+ switch (dwidth) {
+ case 16:
+ if (base < VME2_D16STARTPHYS ||
+ base + (u_long)len > VME2_D16ENDPHYS)
+ return (NULL);
+ return (base);
+ case 32:
+ if (base < VME2_D32STARTVME)
+ return (NULL);
+ return (base - VME2_D32STARTVME + VME2_D32STARTPHYS);
+ }
+}
+
+#if NPCCTWO > 0
+int
+vme2abort(frame)
+ struct frame *frame;
+{
+ struct vmesoftc *sc = (struct vmesoftc *)vmecd.cd_devs[0];
+ struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr;
+
+ if (vme2->vme2_irqstat & VME2_IRQ_AB == 0) {
+ printf("%s: vme2chip irq not set\n", sc->sc_dev.dv_xname);
+ return (0);
+ }
+ vme2->vme2_irqclr = VME2_IRQ_AB;
+ nmihand(frame);
+ return (1);
+}
+#endif
+
+#endif
diff --git a/sys/arch/mvme68k/dev/vme.h b/sys/arch/mvme68k/dev/vme.h
new file mode 100644
index 00000000000..b49918247aa
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vme.h
@@ -0,0 +1,325 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+struct vmesoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr;
+ struct intrhand sc_abih; /* `abort' switch */
+};
+
+/*
+ * MVME147 vme configuration registers.
+*/
+struct vme1reg {
+/*01*/ volatile u_short vme1_scon;
+#define VME1_SCON_SWITCH 0x01 /* SCON jumper is set */
+#define VME1_SCON_SRESET 0x02 /* assert SRESET on bus */
+#define VME1_SCON_SYSFAIL 0x04 /* assert SYSFAIL on bus */
+#define VME1_SCON_ROBIN 0x08 /* round robin bus requests */
+/*03*/ volatile u_short vme1_reqconf;
+#define VME1_REQ_IPLMASK 0x03 /* interrupt level for requester */
+#define VME1_REQ_RNEVER 0x08
+#define VME1_REQ_RWD 0x10
+#define VME1_REQ_DHB 0x40
+#define VME1_REQ_DWB 0x80
+/*05*/ volatile u_short vme1_masconf;
+#define VME1_MAS_D16 0x01 /* force d8/16 accesses only */
+#define VME1_MAS_MASA24 0x02 /* send address mod for A24 access */
+#define VME1_MAS_MASA16 0x04 /* send address mod for A16 access */
+#define VME1_MAS_MASUAT 0x08 /* handle unaligned VME cycles */
+#define VME1_MAS_CFILL 0x10 /* DO NOT USE */
+#define VME1_MAS_MASWP 0x20 /* VME fast mode (DO NOT USE) */
+/*07*/ volatile u_short vme1_slconf;
+#define VME1_SLAVE_SLVD16 0x01 /* DO NOT USE */
+#define VME1_SLAVE_SLVWP 0x20 /* DO NOT USE */
+#define VME1_SLAVE_SLVEN 0x80 /* allow access to onboard DRAM */
+/*09*/ volatile u_short vme1_timerconf;
+#define VME1_TIMER_LOCAL_MASK 0x03
+#define VME1_TIMER_LOCAL_T0 0x00 /* local timeout 102 microsec */
+#define VME1_TIMER_LOCAL_T1 0x01 /* local timeout 205 microsec */
+#define VME1_TIMER_LOCAL_T2 0x02 /* local timeout 410 microsec */
+#define VME1_TIMER_LOCAL_T3 0x03 /* local timeout disabled */
+#define VME1_TIMER_VMEACC_MASK 0x0c
+#define VME1_TIMER_VMEACC_T0 0x00 /* VME access timeout 102 microsec */
+#define VME1_TIMER_VMEACC_T1 0x04 /* VME access timeout 1.6 millisec */
+#define VME1_TIMER_VMEACC_T2 0x08 /* VME access timeout 51 millisec */
+#define VME1_TIMER_VMEACC_T3 0x0c /* VME access timeout disabled */
+#define VME1_TIMER_VMEGLO_MASK 0x30
+#define VME1_TIMER_VMEGLO_T0 0x00 /* VME glob timeout 102 microsec */
+#define VME1_TIMER_VMEGLO_T1 0x10 /* VME glob timeout 205 microsec */
+#define VME1_TIMER_VMEGLO_T2 0x20 /* VME glob timeout 410 microsec */
+#define VME1_TIMER_VMEGLO_T3 0x30 /* VME glob timeout disabled */
+#define VME1_TIMER_ARBTO 0x40 /* enable VME arbitration timer */
+/*0b*/ volatile u_short vme1_sladdrmod;
+#define VME1_SLMOD_DATA 0x01
+#define VME1_SLMOD_PRGRM 0x02
+#define VME1_SLMOD_BLOCK 0x04
+#define VME1_SLMOD_SHORT 0x08
+#define VME1_SLMOD_STND 0x10
+#define VME1_SLMOD_EXTED 0x20
+#define VME1_SLMOD_USER 0x40
+#define VME1_SLMOD_SUPER 0x80
+/*0d*/ volatile u_short vme1_msaddrmod;
+#define VME1_MSMOD_AM_MASK 0x3f
+#define VME1_MSMOD_AMSEL 0x80
+/*0f*/ volatile u_short vme1_irqen;
+#define VME1_IRQ_VME(x) (1 << (x))
+/*11*/ volatile u_short vme1_uirqen;
+/*13*/ volatile u_short vme1_uirq;
+/*15*/ volatile u_short vme1_irq;
+/*17*/ volatile u_short vme1_vmeid;
+/*19*/ volatile u_short vme1_buserr;
+/*1b*/ volatile u_short vme1_gcsr;
+#define VME1_GCSR_OFF 0x0f
+/*1d*/ u_short :16;
+/*1f*/ u_short :16;
+/*21*/ volatile u_short vme1_gcsr_gr0;
+/*23*/ volatile u_short vme1_gcsr_gr1;
+/*25*/ volatile u_short vme1_gcsr_boardid;
+/*27*/ volatile u_short vme1_gcsr_gpr0;
+/*29*/ volatile u_short vme1_gcsr_gpr1;
+/*2b*/ volatile u_short vme1_gcsr_gpr2;
+/*2d*/ volatile u_short vme1_gcsr_gpr3;
+/*2f*/ volatile u_short vme1_gcsr_gpr4;
+};
+
+/*
+ * Basic VME memory layout for the MVME147 follows:
+ * - A32D32 accesses occur at memsize-0xefffffff. This makes it
+ * impossible to do A32D32 accesses before the end of your onboard
+ * memory. If you want to do low address A24D32 accesses, and you
+ * have 16M or more onboard memory you'll find you cannot.
+ * - A32D16 accesses can occur at 0xf0000000-0xff7fffff.
+ * - A16D16 accesses can occur at 0xffff0000-0xffffffff.
+ */
+#define VME1_A32D32BASE 0x00000000UL
+#define VME1_A32D32LEN 0xf0000000UL
+#define VME1_A32D16BASE 0xf0000000UL
+#define VME1_A32D16LEN 0x0f800000UL
+#define VME1_A16D16BASE 0xffff0000UL
+#define VME1_A16D16LEN 0x00010000UL
+#define VME1_A16BASE 0xffff0000UL
+
+/*
+ * XXX: this chip has some rather inane access rules!
+ */
+struct vme2reg {
+/*00*/ volatile u_long vme2_slaveaddr1;
+/*04*/ volatile u_long vme2_slaveaddr2;
+#define VME2_SADDR_END 0xffff0000 /* VME address END & START */
+#define VME2_SADDR_START 0x0000ffff
+/*08*/ volatile u_long vme2_slavelmod1;
+/*0c*/ volatile u_long vme2_slavelmod2;
+#define VME2_SADDR_LADDR 0xffff0000 /* local base address */
+#define VME2_SADDR_SIZE(mem) (0x1000 - (mem) >> 16) /* encoding of size */
+/*10*/ volatile u_long vme2_slavectl;
+#define VME2_SLAVE_CHOOSE(bits, num) ((bits) << (16*((num)-1)))
+#define VME2_SLAVECTL_WP 0x00000100 /* write posting */
+#define VME2_SLAVECTL_SNP_NO 0x00000000 /* no snooping */
+#define VME2_SLAVECTL_SNP_SINK 0x00000200 /* sink data */
+#define VME2_SLAVECTL_SNP_INVAL 0x00000400 /* invalidate */
+#define VME2_SLAVECTL_ADDER 0x00000800 /* use adder */
+#define VME2_SLAVECTL_SUP 0x00000080 /* modifier bit */
+#define VME2_SLAVECTL_USR 0x00000040 /* modifier bit */
+#define VME2_SLAVECTL_A32 0x00000020 /* modifier bit */
+#define VME2_SLAVECTL_A24 0x00000010 /* modifier bit */
+#define VME2_SLAVECTL_D64 0x00000008 /* modifier bit */
+#define VME2_SLAVECTL_BLK 0x00000004 /* modifier bit */
+#define VME2_SLAVECTL_PGM 0x00000002 /* modifier bit */
+#define VME2_SLAVECTL_DAT 0x00000001 /* modifier bit */
+/*14*/ volatile u_long vme2_master1;
+/*18*/ volatile u_long vme2_master2;
+/*1c*/ volatile u_long vme2_master3;
+/*20*/ volatile u_long vme2_master4;
+/*24*/ volatile u_long vme2_master4mod;
+/*28*/ volatile u_long vme2_masterctl;
+#define VME2_MASTERCTL_4SHIFT 24
+#define VME2_MASTERCTL_3SHIFT 16
+#define VME2_MASTERCTL_2SHIFT 8
+#define VME2_MASTERCTL_1SHIFT 0
+#define VME2_MASTERCTL_D16 0x80
+#define VME2_MASTERCTL_WP 0x40
+#define VME2_MASTERCTL_AM 0x3f
+#define VME2_MASTERCTL_AM24SB 0x3f /* A24 Supervisory Block Transfer */
+#define VME2_MASTERCTL_AM24SP 0x3e /* A24 Supervisory Program Access */
+#define VME2_MASTERCTL_AM24SD 0x3d /* A24 Supervisory Data Access */
+#define VME2_MASTERCTL_AM24UB 0x3b /* A24 Non-priv. Block Transfer */
+#define VME2_MASTERCTL_AM24UP 0x3a /* A24 Non-priv. Program Access */
+#define VME2_MASTERCTL_AM24UD 0x39 /* A24 Non-priv. Data Access */
+#define VME2_MASTERCTL_AM16S 0x2d /* A16 Supervisory Access */
+#define VME2_MASTERCTL_AM16U 0x29 /* A16 Non-priv. Access */
+#define VME2_MASTERCTL_AM32SB 0x0f /* A32 Supervisory Block Transfer */
+#define VME2_MASTERCTL_AM32SP 0x0e /* A32 Supervisory Program Access */
+#define VME2_MASTERCTL_AM32SD 0x0d /* A32 Supervisory Data Access */
+#define VME2_MASTERCTL_AM32UB 0x0b /* A32 Non-priv. Block Transfer */
+#define VME2_MASTERCTL_AM32UP 0x0a /* A32 Non-priv. Program Access */
+#define VME2_MASTERCTL_AM32UD 0x09 /* A32 Non-priv Data Access */
+
+#define VME2_MASTERCTL_ALL 0xff
+/*2c*/ volatile u_long vme2_gcsrctl;
+#define VME2_GCSRCTL_OFF 0xf0000000
+#define VME2_GCSRCTL_MDEN4 0x00080000
+#define VME2_GCSRCTL_MDEN3 0x00040000
+#define VME2_GCSRCTL_MDEN2 0x00020000
+#define VME2_GCSRCTL_MDEN1 0x00010000
+#define VME2_GCSRCTL_I2EN 0x00008000 /* F decode (A24D16/A32D16) on */
+#define VME2_GCSRCTL_I2WP 0x00004000 /* F decode write post */
+#define VME2_GCSRCTL_I2SU 0x00002000 /* F decode is supervisor */
+#define VME2_GCSRCTL_I2PD 0x00001000 /* F decode is program */
+#define VME2_GCSRCTL_I1EN 0x00000800 /* short decode (A16Dx) on */
+#define VME2_GCSRCTL_I1D16 0x00000400 /* short decode is D16 */
+#define VME2_GCSRCTL_I1WP 0x00000200 /* short decode write post */
+#define VME2_GCSRCTL_I1SU 0x00000100 /* short decode is supervisor */
+#define VME2_GCSRCTL_ROMSIZE 0x000000c0 /* size of ROM */
+#define VME2_GCSRCTL_ROMBSPD 0x00000038 /* speed of ROM */
+#define VME2_GCSRCTL_ROMASPD 0x00000007 /* speed of ROM */
+/*30*/ volatile u_long vme2_dmactl;
+/*34*/ volatile u_long vme2_dmamode;
+/*38*/ volatile u_long vme2_dmaladdr;
+/*3c*/ volatile u_long vme2_dmavmeaddr;
+/*40*/ volatile u_long vme2_dmacount;
+/*44*/ volatile u_long vme2_dmatable;
+/*48*/ volatile u_long vme2_dmastat;
+/*4c*/ volatile u_long vme2_vmejunk;
+/*50*/ volatile u_long vme2_t1cmp;
+/*54*/ volatile u_long vme2_t1count;
+/*58*/ volatile u_long vme2_t2cmp;
+/*5c*/ volatile u_long vme2_t2count;
+/*60*/ volatile u_long vme2_tctl;
+#define VME2_TCTL_SCON 0x40000000 /* we are SCON */
+#define VME2_TCTL_SYSFAIL 0x20000000 /* light SYSFAIL led */
+#define VME2_TCTL_SRST 0x00800000 /* system reset */
+/*64*/ volatile u_long vme2_prescale;
+/*68*/ volatile u_long vme2_irqstat;
+/*6c*/ volatile u_long vme2_irqen;
+/*70*/ volatile u_long vme2_setsoftirq; /* VME2_IRQ_SWx only */
+/*74*/ volatile u_long vme2_irqclr; /* except VME2_IRQ_VMEx */
+#define VME2_IRQ_ACF 0x80000000
+#define VME2_IRQ_AB 0x40000000
+#define VME2_IRQ_SYSF 0x20000000
+#define VME2_IRQ_MWP 0x10000000
+#define VME2_IRQ_PE 0x08000000
+#define VME2_IRQ_V1IE 0x04000000
+#define VME2_IRQ_TIC2 0x02000000
+#define VME2_IRQ_TIC1 0x01000000
+#define VME2_IRQ_VIA 0x00800000
+#define VME2_IRQ_DMA 0x00400000
+#define VME2_IRQ_SIG3 0x00200000
+#define VME2_IRQ_SIG2 0x00100000
+#define VME2_IRQ_SIG1 0x00080000
+#define VME2_IRQ_SIG0 0x00040000
+#define VME2_IRQ_LM1 0x00020000
+#define VME2_IRQ_LM0 0x00010000
+#define VME2_IRQ_SW7 0x00008000
+#define VME2_IRQ_SW6 0x00004000
+#define VME2_IRQ_SW5 0x00002000
+#define VME2_IRQ_SW4 0x00001000
+#define VME2_IRQ_SW3 0x00000800
+#define VME2_IRQ_SW2 0x00000400
+#define VME2_IRQ_SW1 0x00000200
+#define VME2_IRQ_SW0 0x00000100
+#define VME2_IRQ_SPARE 0x00000080
+#define VME2_IRQ_VME7 0x00000040
+#define VME2_IRQ_VME6 0x00000020
+#define VME2_IRQ_VME5 0x00000010
+#define VME2_IRQ_VME4 0x00000008
+#define VME2_IRQ_VME3 0x00000004
+#define VME2_IRQ_VME2 0x00000002
+#define VME2_IRQ_VME1 0x00000001
+#define VME2_IRQ_VME(x) (1 << ((x) - 1))
+/*78*/ volatile u_long vme2_irql1;
+#define VME2_IRQL1_ACFSHIFT 28
+#define VME2_IRQL1_ABSHIFT 24
+#define VME2_IRQL1_SYSFSHIFT 20
+#define VME2_IRQL1_WPESHIFT 16
+#define VME2_IRQL1_PESHIFT 12
+#define VME2_IRQL1_V1IESHIFT 8
+#define VME2_IRQL1_TIC2SHIFT 4
+#define VME2_IRQL1_TIC1SHIFT 0
+/*7c*/ volatile u_long vme2_irql2;
+#define VME2_IRQL2_VIASHIFT 28
+#define VME2_IRQL2_DMASHIFT 24
+#define VME2_IRQL2_SIG3SHIFT 20
+#define VME2_IRQL2_SIG2SHIFT 16
+#define VME2_IRQL2_SIG1SHIFT 12
+#define VME2_IRQL2_SIG0SHIFT 8
+#define VME2_IRQL2_LM1SHIFT 4
+#define VME2_IRQL2_LM0SHIFT 0
+/*80*/ volatile u_long vme2_irql3;
+#define VME2_IRQL3_SW7SHIFT 28
+#define VME2_IRQL3_SW6SHIFT 24
+#define VME2_IRQL3_SW5SHIFT 20
+#define VME2_IRQL3_SW4SHIFT 16
+#define VME2_IRQL3_SW3SHIFT 12
+#define VME2_IRQL3_SW2SHIFT 8
+#define VME2_IRQL3_SW1SHIFT 4
+#define VME2_IRQL3_SW0SHIFT 0
+/*84*/ volatile u_long vme2_irql4;
+#define VME2_IRQL4_SPARESHIFT 28
+#define VME2_IRQL4_VME7SHIFT 24
+#define VME2_IRQL4_VME6SHIFT 20
+#define VME2_IRQL4_VME5SHIFT 16
+#define VME2_IRQL4_VME4SHIFT 12
+#define VME2_IRQL4_VME3SHIFT 8
+#define VME2_IRQL4_VME2SHIFT 4
+#define VME2_IRQL4_VME1SHIFT 0
+/*88*/ volatile u_long vme2_vbr;
+#define VME2_VBR_0SHIFT 28
+#define VME2_VBR_1SHIFT 24
+#define VME2_VBR_GPOXXXX 0x00ffffff
+/*8c*/ volatile u_long vme2_misc;
+#define VME2_MISC_MPIRQEN 0x00000080 /* do not set */
+#define VME2_MISC_REVEROM 0x00000040 /* 167: dis eprom. 166: en flash */
+#define VME2_MISC_DISSRAM 0x00000020 /* do not set */
+#define VME2_MISC_DISMST 0x00000010
+#define VME2_MISC_NOELBBSY 0x00000008 /* do not set */
+#define VME2_MISC_DISBSYT 0x00000004 /* do not set */
+#define VME2_MISC_ENINT 0x00000002 /* do not set */
+#define VME2_MISC_DISBGN 0x00000001 /* do not set */
+};
+
+#define VME2_A16D32BASE 0xffff0000UL
+#define VME2_A16D32LEN 0x00010000UL
+#define VME2_A32D16BASE 0xf1000000UL
+#define VME2_A32D16LEN 0x01000000UL
+#define VME2_A16D16BASE 0xffff0000UL
+#define VME2_A16D16LEN 0x00010000UL
+#define VME2_A24D16BASE 0xf0000000UL
+#define VME2_A24D16LEN 0x01000000UL
+#define VME2_A16BASE 0xffff0000UL
+#define VME2_A24BASE 0xff000000UL
+
+caddr_t vmepmap __P((struct vmesoftc *sc, caddr_t vmeaddr, int len,
+ int bustype));
+caddr_t vmemap __P((struct vmesoftc *sc, caddr_t vmeaddr, int len,
+ int bustype));
+int vmerw __P((struct vmesoftc *sc, struct uio *uio, int flags, int bus));
diff --git a/sys/arch/mvme68k/dev/vmel.c b/sys/arch/mvme68k/dev/vmel.c
new file mode 100644
index 00000000000..68fdb1cf7f2
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vmel.c
@@ -0,0 +1,173 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/vme.h>
+
+/*
+ * The VMEL driver deals with D32 transfers on the VME bus. The number
+ * of address bits (A16, A24, A32) is irrelevant since the mapping
+ * functions will decide how many address bits are relevant.
+ */
+
+void vmelattach __P((struct device *, struct device *, void *));
+int vmelmatch __P((struct device *, void *, void *));
+
+struct vmelsoftc {
+ struct device sc_dev;
+ struct vmesoftc *sc_vme;
+};
+
+struct cfdriver vmelcd = {
+ NULL, "vmel", vmelmatch, vmelattach,
+ DV_DULL, sizeof(struct vmelsoftc), 0
+};
+
+int
+vmelmatch(parent, cf, args)
+ struct device *parent;
+ void *cf, *args;
+{
+ return (1);
+}
+
+int
+vmelscan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ return (vmescan(parent, child, args, BUS_VMEL));
+}
+
+void
+vmelattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct vmelsoftc *sc = (struct vmelsoftc *)self;
+
+ printf("\n");
+
+ sc->sc_vme = (struct vmesoftc *)parent;
+
+ config_search(vmelscan, self, args);
+}
+
+/*ARGSUSED*/
+int
+vmelopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= vmelcd.cd_ndevs ||
+ vmelcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmelclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmelioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+int
+vmelread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMEL));
+}
+
+int
+vmelwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMEL));
+}
+
+int
+vmelmmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+ caddr_t pa;
+
+ pa = vmepmap(sc->sc_vme, (caddr_t)off, NBPG, BUS_VMEL);
+ printf("vmel %x pa %x\n", off, pa);
+ if (pa == NULL)
+ return (-1);
+ return (m68k_btop(pa));
+}
diff --git a/sys/arch/mvme68k/dev/vmes.c b/sys/arch/mvme68k/dev/vmes.c
new file mode 100644
index 00000000000..b4d6ac87725
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vmes.c
@@ -0,0 +1,173 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/conf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/vme.h>
+
+/*
+ * The VMES driver deals with D16 transfers on the VME bus. The number
+ * of address bits (A16, A24, A32) is irrelevant since the mapping
+ * functions will decide how many address bits are relevant.
+ */
+
+void vmesattach __P((struct device *, struct device *, void *));
+int vmesmatch __P((struct device *, void *, void *));
+
+struct vmessoftc {
+ struct device sc_dev;
+ struct vmesoftc *sc_vme;
+};
+
+struct cfdriver vmescd = {
+ NULL, "vmes", vmesmatch, vmesattach,
+ DV_DULL, sizeof(struct vmessoftc), 0
+};
+
+int
+vmesmatch(parent, cf, args)
+ struct device *parent;
+ void *cf, *args;
+{
+ return (1);
+}
+
+int
+vmesscan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ return (vmescan(parent, child, args, BUS_VMES));
+}
+
+void
+vmesattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct vmessoftc *sc = (struct vmessoftc *)self;
+
+ printf("\n");
+
+ sc->sc_vme = (struct vmesoftc *)parent;
+
+ config_search(vmesscan, self, args);
+}
+
+/*ARGSUSED*/
+int
+vmesopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= vmescd.cd_ndevs ||
+ vmescd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmesclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmesioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+int
+vmesread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMES));
+}
+
+int
+vmeswrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMES));
+}
+
+int
+vmesmmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+ caddr_t pa;
+
+ pa = vmepmap(sc->sc_vme, (caddr_t)off, NBPG, BUS_VMES);
+ printf("vmes %x pa %x\n", off, pa);
+ if (pa == NULL)
+ return (-1);
+ return (m68k_btop(pa));
+}
diff --git a/sys/arch/mvme68k/include/autoconf.h b/sys/arch/mvme68k/include/autoconf.h
new file mode 100644
index 00000000000..e470530d15d
--- /dev/null
+++ b/sys/arch/mvme68k/include/autoconf.h
@@ -0,0 +1,55 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+struct confargs {
+ int ca_bustype;
+ void *ca_vaddr;
+ void *ca_paddr;
+ int ca_offset;
+ int ca_len;
+ int ca_ipl;
+ int ca_vec;
+ char *ca_name;
+
+ void *ca_master; /* points to bus-dependent data */
+};
+
+#define BUS_MAIN 1
+#define BUS_PCC 2 /* VME147 PCC chip */
+#define BUS_MC 3 /* VME162 MC chip */
+#define BUS_PCCTWO 4 /* VME166/167/177 PCC2 chip */
+#define BUS_VMES 5 /* 16 bit VME access */
+#define BUS_VMEL 6 /* 32 bit VME access */
+#define BUS_IP 7 /* VME162 IP module bus */
+
+caddr_t mapiodev __P((caddr_t pa, int size));
+void unmapiodev __P((caddr_t kva, int size));
diff --git a/sys/arch/mvme68k/include/ieeefp.h b/sys/arch/mvme68k/include/ieeefp.h
new file mode 100644
index 00000000000..8d6941e81b5
--- /dev/null
+++ b/sys/arch/mvme68k/include/ieeefp.h
@@ -0,0 +1,4 @@
+/* $NetBSD: ieeefp.h,v 1.2 1995/04/16 16:47:08 jtc Exp $ */
+
+/* Just use the common m68k definition */
+#include <m68k/ieeefp.h>
diff --git a/sys/arch/mvme68k/include/mioctl.h b/sys/arch/mvme68k/include/mioctl.h
new file mode 100644
index 00000000000..ba76d4a441a
--- /dev/null
+++ b/sys/arch/mvme68k/include/mioctl.h
@@ -0,0 +1,33 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+#define MIOCGSIZ _IOR('m', 1, int)
diff --git a/sys/arch/mvme68k/include/nvram.h b/sys/arch/mvme68k/include/nvram.h
new file mode 100644
index 00000000000..91690b7ba4d
--- /dev/null
+++ b/sys/arch/mvme68k/include/nvram.h
@@ -0,0 +1,78 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+struct nvram_147 {
+ u_char user[0x400];
+ u_char os[0x200];
+ u_char bug[0x174];
+ u_long emem;
+ u_char ether[3];
+ u_char memsizing;
+ u_char other[124];
+ /*struct clockreg cl; */
+};
+
+struct nvram_16x {
+ u_char user[0x1000];
+ u_char net[0x100];
+ u_char os[1528];
+ u_char bug[2048];
+ struct nvram_16x_conf {
+ u_char version[4];
+ u_char serial[12];
+ u_char id[16];
+ u_char pwa[16];
+ u_char speed[4];
+ u_char ether[6];
+ u_char fill[2];
+ u_char lscsiid[2];
+ u_char mem_pwb[8];
+ u_char mem_serial[8];
+ u_char port2_pwb[8];
+ u_char port2_serial[8];
+ u_char ipa_brdid[8];
+ u_char ipa_serial[8];
+ u_char ipa_pwb[8];
+ u_char ipb_brdid[8];
+ u_char ipb_serial[8];
+ u_char ipb_pwb[8];
+ u_char ipc_brdid[8];
+ u_char ipc_serial[8];
+ u_char ipc_pwb[8];
+ u_char ipd_brdid[8];
+ u_char ipd_serial[8];
+ u_char ipd_pwb[8];
+ u_char reserved[65];
+ u_char cksum[1];
+ } conf;
+ /*struct clockreg cl; */
+};
diff --git a/sys/arch/mvme68k/include/prom.h b/sys/arch/mvme68k/include/prom.h
new file mode 100644
index 00000000000..60514bda0dc
--- /dev/null
+++ b/sys/arch/mvme68k/include/prom.h
@@ -0,0 +1,155 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+#define MVMEPROM_INCHR 0x00
+#define MVMEPROM_INSTAT 0x01
+#define MVMEPROM_INLN 0x02
+#define MVMEPROM_READSTR 0x03
+#define MVMEPROM_READLN 0x04
+#define MVMEPROM_OUTCHR 0x20
+#define MVMEPROM_OUTSTR 0x21
+#define MVMEPROM_DSKRD 0x10
+#define MVMEPROM_DSKWR 0x11
+#define MVMEPROM_DSKCFIG 0x12
+#define MVMEPROM_DSKFMT 0x14
+#define MVMEPROM_DSKCTRL 0x15
+#define MVMEPROM_NETCTRL 0x1d
+#define MVMEPROM_OUTSTRCRLF 0x22
+#define MVMEPROM_WRITE 0x23
+#define MVMEPROM_WRITELN 0x24
+#define MVMEPROM_DELAY 0x43
+#define MVMEPROM_RTC_RD 0x53
+#define MVMEPROM_EXIT 0x63
+#define MVMEPROM_GETBRDID 0x70
+#define MVMEPROM_ENVIRON 0x71
+
+#define NETCTRLCMD_GETETHER 1
+
+#define ENVIRONCMD_WRITE 1
+#define ENVIRONCMD_READ 2
+#define ENVIRONTYPE_EOL 0
+#define ENVIRONTYPE_START 1
+#define ENVIRONTYPE_DISKBOOT 2
+#define ENVIRONTYPE_ROMBOOT 3
+#define ENVIRONTYPE_NETBOOT 4
+#define ENVIRONTYPE_MEMSIZE 5
+
+#ifndef LOCORE
+struct prom_netctrl {
+ u_char dev;
+ u_char ctrl;
+ u_short status;
+ u_long cmd;
+ u_long addr;
+ u_long len;
+ u_long flags;
+};
+
+struct prom_environ_hdr {
+ u_char type;
+ u_char len;
+};
+
+struct mvmeprom_brdid {
+ u_long eye_catcher;
+ u_char rev;
+ u_char month;
+ u_char day;
+ u_char year;
+ u_short size;
+ u_short rsv1;
+ u_short model;
+ u_short suffix;
+ u_short options;
+ u_char family;
+ u_char cpu;
+ u_short ctrlun;
+ u_short devlun;
+ u_short devtype;
+ u_short devnum;
+ u_long bug;
+
+ /*
+ * XXX: I have seen no documentation for these!
+ *
+ * The following (appears to) exist only on the MVME162 and
+ * upwards. We should figure out what the other fields are.
+ */
+ u_char xx1[16];
+ u_char xx2[4];
+ u_char longname[12];
+ u_char xx3[16];
+ u_char speed[4];
+ u_char xx4[12];
+};
+
+struct mvmeprom_time {
+ u_char year_BCD;
+ u_char month_BCD;
+ u_char day_BCD;
+ u_char wday_BCD;
+ u_char hour_BCD;
+ u_char min_BCD;
+ u_char sec_BCD;
+ u_char cal_BCD;
+};
+
+struct mvmeprom_dskio {
+ u_char ctrl_lun;
+ u_char dev_lun;
+ u_short status;
+ void *pbuffer;
+ u_long blk_num;
+ u_short blk_cnt;
+ u_char flag;
+#define BUG_FILE_MARK 0x80
+#define IGNORE_FILENUM 0x02
+#define END_OF_FILE 0x01
+ u_char addr_mod;
+};
+#define MVMEPROM_BLOCK_SIZE 256
+
+struct mvmeprom_args {
+ u_int dev_lun;
+ u_int ctrl_lun;
+ u_int flags;
+ u_int ctrl_addr;
+ u_int entry;
+ u_int conf_blk;
+ char *arg_start;
+ char *arg_end;
+};
+
+#endif
+
+#define MVMEPROM_CALL(x) \
+ asm volatile (__CONCAT("trap #15; .short ", __STRING(x)) )
diff --git a/sys/arch/mvme68k/stand/bootsd/Makefile b/sys/arch/mvme68k/stand/bootsd/Makefile
new file mode 100644
index 00000000000..022aae13737
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootsd/Makefile
@@ -0,0 +1,43 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/10/93
+# $Id: Makefile,v 1.1 1995/10/18 10:44:12 deraadt Exp $
+
+RELOC=0x3F0000
+
+S= ${.CURDIR}/../../../..
+DEFS= -DSTANDALONE -DCOMPAT_NOLABEL # -DROMPRF
+INCPATH=-I${.CURDIR} -I${.CURDIR}/../../include -I${S} -I${S}/lib/libsa
+CFLAGS= -O2 ${INCPATH} ${DEFS} ${COPTS}
+CLEANFILES+=sdboot bootsd bootsd.bug
+
+#.PATH: ${S}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+#.PATH: ${S}/lib/libsa
+
+.include "${S}/arch/${MACHINE}/stand/libsa/Makefile.inc"
+.include "${S}/arch/${MACHINE}/stand/libbug/Makefile.inc"
+.include "${S}/arch/${MACHINE}/stand/bugcrt/Makefile.inc"
+.include "${S}/arch/${MACHINE}/stand/wrtvid/Makefile.inc"
+
+SRCS= boot.c filesystem.c bugdev.c version.c
+
+LIBS= ${LIBSA} ${LIBBUG}
+
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+
+BOOTS= bootsd sdboot
+ALL= ${BOOTS}
+
+all: ${ALL}
+
+devopen.o machdep.o: Makefile
+
+bootsd.bug: ${OBJS} ${BUGCRT} ${LIBS}
+ ${LD} -s -N -T ${RELOC} ${BUGCRT} ${OBJS} ${LIBS} -o $@
+ @size bootsd.bug
+
+bootsd sdboot: bootsd.bug ${WRTVID}
+ ${WRTVID} bootsd.bug
+
+install:
+ install -c -m 555 -g bin -o bin ${BOOTS} ${DESTDIR}${MDEC_DIR}
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/mvme68k/stand/bootsd/README b/sys/arch/mvme68k/stand/bootsd/README
new file mode 100644
index 00000000000..f3a503eb63e
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootsd/README
@@ -0,0 +1,3 @@
+In short: stick the the bootblocks into a partition with
+something like:
+ cat sdboot bootsd > /dev/rsd0c
diff --git a/sys/arch/mvme68k/stand/bootsd/boot.c b/sys/arch/mvme68k/stand/bootsd/boot.c
new file mode 100644
index 00000000000..697dbe0891c
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootsd/boot.c
@@ -0,0 +1,339 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. 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 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.
+ *
+ * from: @(#)boot.c 8.1 (Berkeley) 6/10/93
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/reboot.h>
+#include <a.out.h>
+#include <machine/prom.h>
+#include "stand.h"
+
+void reset_twiddle __P((void));
+void copyunix __P((int io, char *addr));
+void parse_args __P((struct mvmeprom_args *pargs));
+
+int debug;
+int netif_debug;
+#define RB_NOSYM 0x400
+
+/*
+ * Boot device is derived from ROM provided information.
+ */
+extern char *version;
+u_long esym;
+char *strtab;
+int strtablen;
+#if 0
+struct nlist *nlp, *enlp;
+#endif
+
+struct kernel {
+ void *entry;
+ void *symtab;
+ void *esym;
+ int bflags;
+ int bdev;
+ char *kname;
+ void *smini;
+ void *emini;
+ u_int end_loaded;
+} kernel;
+
+struct mvmeprom_args *bugargs;
+
+int
+main(pp)
+ struct mvmeprom_args *pp;
+{
+ struct exec x;
+ char *file;
+ void *addr;
+ int io, i;
+
+ printf(">> NetBSD sdboot [%s]\n", version);
+
+ bugargs = pp;
+ parse_args(pp);
+ file = kernel.kname;
+
+ if ((io = open(file, 0)) < 0) {
+ printf("Can't open %s: %s\n", file, strerror(errno));
+ mvmeprom_return();
+ }
+ i = read(io, (char *)&x, sizeof(x));
+ if (i != sizeof(x) ||
+ N_BADMAG(x)) {
+ printf("Bad format\n");
+ return (0);
+ }
+ /* Make load address start of page which containes "start" */
+ addr = (void *)(x.a_entry & ~0x0FFF);
+ lseek(io, 0, SEEK_SET);
+
+ reset_twiddle();
+
+ printf("booting %s load address 0x%x\n", file, addr);
+ copyunix(io, addr);
+ return (0);
+}
+
+/*ARGSUSED*/
+void
+copyunix(io, addr)
+ int io;
+ char *addr;
+{
+ struct exec x;
+ int i;
+ void (*entry)() = (void (*)())addr;
+
+ i = read(io, (char *)&x, sizeof(x));
+ if (i != sizeof(x) ||
+ N_BADMAG(x)) {
+ printf("Bad format\n");
+ return;
+ }
+
+ reset_twiddle();
+ printf("%x", x.a_text);
+ if (N_GETMAGIC(x) == ZMAGIC) {
+ kernel.entry = entry = (void *)x.a_entry;
+ lseek(io, 0, SEEK_SET);
+ }
+ if (read(io, (char *)addr, x.a_text) != x.a_text)
+ goto shread;
+ addr += x.a_text;
+ if (N_GETMAGIC(x) == NMAGIC)
+ while ((int)addr & CLOFSET)
+ *addr++ = 0;
+ reset_twiddle();
+ printf("+%x", x.a_data);
+ if (read(io, addr, x.a_data) != x.a_data)
+ goto shread;
+ addr += x.a_data;
+ reset_twiddle();
+ printf("+%x", x.a_bss);
+ for (i = 0; i < x.a_bss; i++)
+ *addr++ = 0;
+ if (x.a_syms != 0 && !(kernel.bflags & RB_NOSYM)) {
+ bcopy(&x.a_syms, addr, sizeof(x.a_syms));
+ addr += sizeof(x.a_syms);
+#if 0
+ nlp = (struct nlist *)addr;
+#endif
+ printf("+[%x+", x.a_syms);
+ if (read(io, addr, x.a_syms) != x.a_syms)
+ goto shread;
+ addr += x.a_syms;
+#if 0
+ enlp = (struct nlist *)(strtab = addr);
+#endif
+ reset_twiddle();
+
+ if (read(io, &strtablen, sizeof(int)) != sizeof(int))
+ goto shread;
+ reset_twiddle();
+
+ bcopy(&strtablen, addr, sizeof(int));
+ if (i = strtablen) {
+ i -= sizeof(int);
+ addr += sizeof(int);
+ {
+ int cnt;
+ cnt = read(io, addr, i);
+ if (cnt != i)
+ /*
+ goto shread;
+ */printf("symwarn");
+ }
+ reset_twiddle();
+ addr += i;
+ }
+ printf("%x]", i);
+ esym = KERNBASE +
+ (((int)addr + sizeof(int) - 1) & ~(sizeof(int) - 1));
+ kernel.symtab = (void *) x.a_syms;
+ kernel.esym = addr;
+ } else {
+ kernel.symtab = 0;
+ kernel.esym = 0;
+ }
+
+#if 0
+ while (nlp < enlp) {
+ register int strx = nlp->n_un.n_strx;
+ if (strx > strtablen)
+ continue;
+ if (strcmp(strtab+strx, "_esym") == 0) {
+ *(int*)(nlp->n_value - KERNBASE) = esym;
+ break;
+ }
+ nlp++;
+ }
+#endif
+
+ kernel.bdev = 0;
+ kernel.end_loaded = (u_int)addr;
+ kernel.smini = 0;
+ kernel.emini = 0;
+ kernel.kname = 0;
+
+ printf("=%x\n", (u_int)addr - (u_int)entry); /* XXX wrong? */
+
+#if 0
+printf("entry %x\n",kernel.entry);
+printf("symtab %x\n",kernel.symtab);
+printf("esym %x\n",kernel.esym);
+printf("bflags %x\n",kernel.bflags);
+printf("bdev %x\n",kernel.bdev);
+printf("kname %x\n",kernel.kname);
+printf("smini %x\n",kernel.smini);
+printf("emini %x\n",kernel.emini);
+printf("end_loaded %x\n",kernel.end_loaded);
+#endif
+
+ printf("start at 0x%x\n", (int)entry);
+#if 0
+ if (kernel.bflags & RB_HALT) {
+ mvmeprom_return();
+ }
+#endif
+ if (((u_long)entry &0xf) == 0x2) {
+ (entry)(bugargs, &kernel);
+ } else {
+ /* is type fixing anything like price fixing? */
+ typedef (* kernel_start)(int, int, void *,void *, void *);
+ kernel_start addr;
+ addr = (void *)entry;
+ (addr)(kernel.bflags,0,kernel.esym,kernel.smini,kernel.emini);
+ }
+ return;
+shread:
+ printf("Short read\n");
+}
+#define NO_TWIDDLE_FUNC
+
+#ifndef NO_TWIDDLE_FUNC
+static int tw_on;
+static int tw_pos;
+static char tw_chars[] = "|/-\\";
+#endif
+
+void
+reset_twiddle()
+{
+#ifndef NO_TWIDDLE_FUNC
+ if (tw_on)
+ putchar('\b');
+ tw_on = 0;
+ tw_pos = 0;
+#endif
+}
+
+#ifndef NO_TWIDDLE_FUNC
+void
+twiddle()
+{
+ if (tw_on)
+ putchar('\b');
+ else
+ tw_on = 1;
+ putchar(tw_chars[tw_pos++]);
+ tw_pos %= (sizeof(tw_chars) - 1);
+}
+#endif
+
+void
+_rtt()
+{
+ mvmeprom_return();
+}
+void
+parse_args(pargs)
+ struct mvmeprom_args *pargs;
+{
+ char *ptr = pargs->arg_start;
+ char *name = "/netbsd";
+ char c;
+ int howto = 0;
+
+ if (pargs->arg_start != pargs->arg_end) {
+ while (c = *ptr) {
+ while (c == ' ')
+ c = *++ptr;
+ if (!c)
+ return;
+ if (c == '-')
+ while ((c = *++ptr) && c != ' ') {
+ if (c == 'a')
+ howto |= RB_ASKNAME;
+ else if (c == 'b')
+ howto |= RB_HALT;
+ else if (c == 'y')
+ howto |= RB_NOSYM;
+ else if (c == 'd')
+ howto |= RB_KDB;
+ else if (c == 'm')
+ howto |= RB_MINIROOT;
+ else if (c == 'r')
+ howto |= RB_DFLTROOT;
+ else if (c == 's')
+ howto |= RB_SINGLE;
+ }
+ else {
+ name = ptr;
+ while ((c = *++ptr) && c != ' ');
+ if (c)
+ *ptr++ = 0;
+ }
+ }
+#if 0
+ if (RB_NOSYM & howto) printf("RB_NOSYM\n\r");
+ if (RB_AUTOBOOT & howto) printf("RB_AUTOBOOT\n\r");
+ if (RB_SINGLE & howto) printf("RB_SINGLE\n\r");
+ if (RB_NOSYNC & howto) printf("RB_NOSYNC\n\r");
+ if (RB_HALT & howto) printf("RB_HALT\n\r");
+ if (RB_DFLTROOT & howto) printf("RB_DFLTROOT\n\r");
+ if (RB_KDB & howto) printf("RB_KDB\n\r");
+ if (RB_RDONLY & howto) printf("RB_RDONLY\n\r");
+ if (RB_DUMP & howto) printf("RB_DUMP\n\r");
+ if (RB_MINIROOT & howto) printf("RB_MINIROOT\n\r");
+#endif
+ }
+ kernel.bflags = howto;
+ kernel.kname = name;
+}
diff --git a/sys/arch/mvme68k/stand/bootsd/bugdev.c b/sys/arch/mvme68k/stand/bootsd/bugdev.c
new file mode 100644
index 00000000000..551826bca91
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootsd/bugdev.c
@@ -0,0 +1,259 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 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/disklabel.h>
+#include <machine/prom.h>
+#include "stand.h"
+
+int bugscopen __P((struct open_file *, ...));
+int bugscclose __P((struct open_file *));
+int bugscioctl __P((struct open_file *, u_long, void *));
+int bugscstrategy __P((void *, int, daddr_t, u_int, char *, u_int *));
+
+void cputobsdlabel __P((struct disklabel *lp, struct cpu_disklabel *clp));
+
+struct devsw devsw[] = {
+ { "bugsc", bugscstrategy, bugscopen, bugscclose, bugscioctl },
+};
+int ndevs = (sizeof(devsw)/sizeof(devsw[0]));
+
+extern struct mvmeprom_args *bugargs;
+int errno;
+
+struct bugsc_softc {
+ int fd; /* Prom file descriptor */
+ int poff; /* Partition offset */
+ int psize; /* Partition size */
+ short ctrl;
+ short dev;
+} bugsc_softc[1];
+
+static struct disklabel sdlabel;
+
+int
+devopen(f, fname, file)
+ struct open_file *f;
+ const char *fname;
+ char **file;
+{
+ register struct bugsc_softc *pp = &bugsc_softc[0];
+ int error, i, dn = 0, pn = 0;
+ char *dev, *cp;
+ static char iobuf[MAXBSIZE];
+
+ dev = bugargs->arg_start;
+
+ /*
+ * Extract partition # from boot device string.
+ */
+ for (cp = dev; *cp; cp++) /* void */;
+ while (*cp != '/' && cp > dev) {
+ if (*cp == ':')
+ pn = *(cp+1) - 'a';
+ --cp;
+ }
+
+ pp->fd = bugscopen(f);
+
+ if (pp->fd < 0) {
+ printf("Can't open device `%s'\n", dev);
+ return (ENXIO);
+ }
+ error = bugscstrategy(pp, F_READ, LABELSECTOR, DEV_BSIZE, iobuf, &i);
+ if (error)
+ return (error);
+ if (i != DEV_BSIZE)
+ return (EINVAL);
+
+ cputobsdlabel(&sdlabel, (struct cpu_disklabel *)iobuf);
+ if (0) {
+ printf("WARNING: no label\n");
+ /* XXX set some default label */
+ return (EINVAL);
+ } else {
+ pp->poff = sdlabel.d_partitions[pn].p_offset;
+ pp->psize = sdlabel.d_partitions[pn].p_size;
+ }
+
+ f->f_dev = devsw;
+ f->f_devdata = (void *)pp;
+ *file = (char *)fname;
+ return (0);
+}
+
+/* silly block scale factor */
+#define BUG_BLOCK_SIZE 256
+#define BUG_SCALE (512/BUG_BLOCK_SIZE)
+int
+bugscstrategy(devdata, func, dblk, size, buf, rsize)
+ void *devdata;
+ int func;
+ daddr_t dblk;
+ u_int size;
+ char *buf;
+ u_int *rsize;
+{
+ struct mvmeprom_dskio dio;
+ register struct bugsc_softc *pp = (struct bugsc_softc *)devdata;
+ daddr_t blk = dblk + pp->poff;
+ int error = 0;
+ short status = 0;
+
+ twiddle();
+
+ dio.ctrl_lun = pp->ctrl;
+ dio.dev_lun = pp->dev;
+ dio.status = 0;
+ dio.pbuffer = buf;
+ dio.blk_num = blk * BUG_SCALE;
+ dio.blk_cnt = size / BUG_BLOCK_SIZE; /* assumed size in bytes */
+ dio.flag = 0;
+ dio.addr_mod = 0;
+#ifdef 0
+ printf("bugscstrategy: size=%d blk=%d buf=%x\n", size, blk, buf);
+ printf("ctrl %d dev %d\n", dio.ctrl_lun, dio.dev_lun);
+#endif
+ mvmeprom_diskrd(&dio);
+
+ *rsize = dio.blk_cnt * BUG_BLOCK_SIZE;
+#ifdef 0
+printf("rsize %d status %x\n", *rsize, dio.status);
+#endif
+
+ switch (dio.status) {
+ case 0:
+ error = 0;
+ break;
+ default:
+ error = EIO;
+ break;
+ }
+ return (error);
+}
+
+int
+bugscopen(f)
+ struct open_file *f;
+{
+#ifdef DEBUG
+ printf("bugscopen:\n");
+#endif
+
+ f->f_devdata = (void *)bugsc_softc;
+ bugsc_softc[0].ctrl = bugargs->ctrl_lun;
+ bugsc_softc[0].dev = bugargs->dev_lun;
+ printf("using mvmebug ctrl %d dev %d\n",
+ bugsc_softc[0].ctrl, bugsc_softc[0].dev);
+ return (0);
+}
+
+int
+bugscclose(f)
+ struct open_file *f;
+{
+ return (EIO);
+}
+
+int
+bugscioctl(f, cmd, data)
+ struct open_file *f;
+ u_long cmd;
+ void *data;
+{
+ return (EIO);
+}
+
+void
+cputobsdlabel(lp, clp)
+ struct disklabel *lp;
+ struct cpu_disklabel *clp;
+{
+ int i;
+
+ lp->d_magic = clp->magic1;
+ lp->d_type = clp->type;
+ lp->d_subtype = clp->subtype;
+ bcopy(clp->vid_vd, lp->d_typename, 16);
+ bcopy(clp->packname, lp->d_packname, 16);
+ lp->d_secsize = clp->cfg_psm;
+ lp->d_nsectors = clp->cfg_spt;
+ lp->d_ncylinders = clp->cfg_trk; /* trk is really num of cyl! */
+ lp->d_ntracks = clp->cfg_hds;
+
+ lp->d_secpercyl = clp->secpercyl;
+ lp->d_secperunit = clp->secperunit;
+ lp->d_secpercyl = clp->secpercyl;
+ lp->d_secperunit = clp->secperunit;
+ lp->d_sparespertrack = clp->sparespertrack;
+ lp->d_sparespercyl = clp->sparespercyl;
+ lp->d_acylinders = clp->acylinders;
+ lp->d_rpm = clp->rpm;
+ lp->d_interleave = clp->cfg_ilv;
+ lp->d_trackskew = clp->cfg_sof;
+ lp->d_cylskew = clp->cylskew;
+ lp->d_headswitch = clp->headswitch;
+
+ /* this silly table is for winchester drives */
+ switch (clp->cfg_ssr) {
+ case 0:
+ lp->d_trkseek = 0;
+ break;
+ case 1:
+ lp->d_trkseek = 6;
+ break;
+ case 2:
+ lp->d_trkseek = 10;
+ break;
+ case 3:
+ lp->d_trkseek = 15;
+ break;
+ case 4:
+ lp->d_trkseek = 20;
+ break;
+ default:
+ lp->d_trkseek = 0;
+ break;
+ }
+ lp->d_flags = clp->flags;
+ for (i = 0; i < NDDATA; i++)
+ lp->d_drivedata[i] = clp->drivedata[i];
+ for (i = 0; i < NSPARE; i++)
+ lp->d_spare[i] = clp->spare[i];
+ lp->d_magic2 = clp->magic2;
+ lp->d_checksum = clp->checksum;
+ lp->d_npartitions = clp->partitions;
+ lp->d_bbsize = clp->bbsize;
+ lp->d_sbsize = clp->sbsize;
+ bcopy(clp->vid_4, &(lp->d_partitions[0]), sizeof (struct partition) * 4);
+ bcopy(clp->cfg_4, &(lp->d_partitions[4]), sizeof (struct partition) * 12);
+}
diff --git a/sys/arch/mvme68k/stand/bootsd/filesystem.c b/sys/arch/mvme68k/stand/bootsd/filesystem.c
new file mode 100644
index 00000000000..fe2dbe2fb0b
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootsd/filesystem.c
@@ -0,0 +1,42 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1993 Philip A. Nelson.
+ * 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 Philip A. Nelson.
+ * 4. The name of Philip A. Nelson may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PHILIP NELSON ``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 PHILIP NELSON 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 <stand.h>
+#include <ufs.h>
+
+struct fs_ops file_system[] = {
+ { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat },
+};
+
+int nfsys = sizeof(file_system)/sizeof(struct fs_ops);
+
diff --git a/sys/arch/mvme68k/stand/bootsd/version.c b/sys/arch/mvme68k/stand/bootsd/version.c
new file mode 100644
index 00000000000..4920e8b776f
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootsd/version.c
@@ -0,0 +1,9 @@
+/* $NetBSD$ */
+
+/*
+ * NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE.
+ *
+ * 1.1
+ */
+
+char *version = "$Revision: 1.1 $";
diff --git a/sys/arch/mvme68k/stand/bootst/Makefile b/sys/arch/mvme68k/stand/bootst/Makefile
new file mode 100644
index 00000000000..fc02780582b
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootst/Makefile
@@ -0,0 +1,41 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/10/93
+# $Id: Makefile,v 1.1 1995/10/18 10:44:45 deraadt Exp $
+
+RELOC=0x3F0000
+
+S= ${.CURDIR}/../../../..
+DEFS= -DSTANDALONE -DCOMPAT_NOLABEL # -DROMPRF
+INCPATH=-I${.CURDIR} -I${.CURDIR}/../../include -I${S} -I${S}/lib/libsa
+CFLAGS= -O2 ${INCPATH} ${DEFS} ${COPTS}
+CLEANFILES+=sdboot bootst bootst.bug
+
+#.PATH: ${S}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+#.PATH: ${S}/lib/libsa
+
+.include "${S}/arch/${MACHINE}/stand/libsa/Makefile.inc"
+.include "${S}/arch/${MACHINE}/stand/libbug/Makefile.inc"
+.include "${S}/arch/${MACHINE}/stand/bugcrt/Makefile.inc"
+.include "${S}/arch/${MACHINE}/stand/wrtvid/Makefile.inc"
+
+SRCS= bootst.c
+
+LIBS= ${LIBSA} ${LIBBUG}
+
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+
+BOOTS= bootst sdboot
+ALL= ${BOOTS}
+
+all: ${ALL}
+
+bootst.bug: ${OBJS} ${BUGCRT} ${LIBS}
+ ${LD} -s -N -T ${RELOC} ${BUGCRT} ${OBJS} ${LIBS} -o $@
+ @size bootst.bug
+
+bootst sdboot: bootst.bug ${WRTVID}
+ ${WRTVID} bootst.bug
+
+install:
+ install -c -m 555 -g bin -o bin ${BOOTS} ${DESTDIR}${MDEC_DIR}
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/mvme68k/stand/bootst/bootst.c b/sys/arch/mvme68k/stand/bootst/bootst.c
new file mode 100644
index 00000000000..4d850195e5d
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bootst/bootst.c
@@ -0,0 +1,346 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/exec.h>
+#include <machine/prom.h>
+
+#define RB_NOSYM 0x400
+
+void parse_args __P((struct mvmeprom_args *pbugargs));
+int load_kern();
+int read_tape_block __P((short ctrl, short dev, short *status,
+ void *addr, int *cnt, int blk_num, u_char *flags, int verbose));
+
+struct kernel {
+ void *entry;
+ void *symtab;
+ void *esym;
+ int bflags;
+ int bdev;
+ char *kname;
+ void *smini;
+ void *emini;
+ u_int end_loaded;
+} kernel;
+
+typedef(*kernel_entry) __P((struct mvmeprom_args *, struct kernel *));
+
+int
+main(pbugargs)
+ struct mvmeprom_args *pbugargs;
+{
+ kernel_entry addr;
+
+ /*
+ print_bugargs(pbugargs);
+ print_time();
+ print_brdid();
+ print_memory();
+ */
+ parse_args(pbugargs);
+ if (load_kern(pbugargs) == 1) {
+ printf("unsuccessful in loading kernel\n");
+ } else {
+ addr = kernel.entry;
+
+ printf("kernel loaded at %x\n", addr);
+ printf("kernel.entry %x\n", kernel.entry);
+ printf("kernel.symtab %x\n", kernel.symtab);
+ printf("kernel.esym %x\n", kernel.esym);
+ printf("kernel.bflags %x\n", kernel.bflags);
+ printf("kernel.bdev %x\n", kernel.bdev);
+ if (kernel.kname)
+ printf("kernel.kname <%s>\n", kernel.kname);
+ else
+ printf("kernel.kname <null>\n");
+ printf("kernel.end_loaded %x\n", kernel.end_loaded);
+
+ if (kernel.bflags & RB_MINIROOT)
+ loadmini(kernel.end_loaded, pbugargs);
+
+ printf("kernel.smini %x\n", kernel.smini);
+ printf("kernel.emini %x\n", kernel.emini);
+ printf("kernel.end_loaded %x\n", kernel.end_loaded);
+ if (kernel.bflags & RB_HALT)
+ mvmeprom_return();
+ (addr) (pbugargs, &kernel);
+ }
+ return (0);
+}
+
+#define MVMEPROM_SCALE (512/MVMEPROM_BLOCK_SIZE)
+
+int
+read_tape_block(ctrl, dev, status, addr, cnt, blk_num, flags, verbose)
+ short ctrl;
+ short dev;
+ short *status;
+ void *addr;
+ int *cnt;
+ int blk_num;
+ u_char *flags;
+ int verbose;
+{
+ struct mvmeprom_dskio dio;
+ int ret;
+
+ dio.ctrl_lun = ctrl;
+ dio.dev_lun = dev;
+ dio.status = *status;
+ dio.pbuffer = addr;
+ dio.blk_num = blk_num;
+ dio.blk_cnt = *cnt / (512 / MVMEPROM_SCALE);
+ dio.flag = *flags;
+ dio.addr_mod = 0;
+
+ if (verbose)
+ printf("saddr %x eaddr %x", dio.pbuffer,
+ (int) dio.pbuffer + (dio.blk_cnt * MVMEPROM_BLOCK_SIZE));
+ ret = mvmeprom_diskrd(&dio);
+
+ *status = dio.status;
+ *cnt = (dio.blk_cnt / MVMEPROM_SCALE) * 512;
+ if (verbose) {
+ printf("status %x ret %d ", *status, ret);
+ printf("flags %x blocks read %x cnt %x\n",
+ *flags, dio.blk_cnt, *cnt);
+ }
+ return (ret);
+}
+#ifdef DEBUG
+int verbose = 1;
+#else
+int verbose = 0;
+#endif
+
+int
+load_kern(pbugargs)
+ struct mvmeprom_args *pbugargs;
+{
+ int ret;
+ char *addr;
+ u_char flags;
+ short status = 0;
+ int blk_num;
+ struct exec *pexec;
+ int magic;
+ int *esym;
+ int *symtab;
+ int cnt, len;
+ char buf[512];
+
+ blk_num = 2;
+ /* flags = IGNORE_FILENUM; */
+ flags = 0;
+ cnt = 512;
+ ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun, &status,
+ buf, &cnt, blk_num, &flags, verbose);
+ if (ret != 0) {
+ printf("unable to load kernel 1\n");
+ return (1);
+ }
+ pexec = (struct exec *) buf;
+ if (N_GETMID(*pexec) != MID_M68K &&
+ N_GETMID(*pexec) != MID_M68K4K) {
+ printf("invalid mid on kernel\n");
+ return (1);
+ }
+
+ magic = N_GETMAGIC(*pexec);
+ switch (magic) {
+ case ZMAGIC:
+ break;
+ case NMAGIC:
+ printf("NMAGIC not yet supported");
+ case OMAGIC:
+ case QMAGIC:
+ default:
+ printf("Unknown or unsupported magic type <%x>\n", magic);
+ return (1);
+ }
+ if (magic == ZMAGIC) {
+ status = 0;
+ addr = (char *) (pexec->a_entry & ~0x0FFF);
+
+ if ((int) pexec->a_entry != (int) addr + 0x22) {
+ printf("warning kernel start address not %x, %x\n",
+ (int) addr + 0x22, pexec->a_entry);
+ printf("kernel loaded at %x\n", addr);
+ }
+ bcopy(&buf, addr, 512);
+ /* 2nd block of exe */
+ addr += 512;
+
+ printf("text 0x%x data 0x%x bss 0x%x\n",
+ pexec->a_text, pexec->a_data, pexec->a_bss);
+
+ len = (pexec->a_text - 512); /* XXX */
+ len += (pexec->a_data);
+
+ printf("loading [ %x + %x ", pexec->a_text, pexec->a_data);
+
+ cnt = len;
+ flags = IGNORE_FILENUM;
+ ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun,
+ &status, addr, &cnt, blk_num, &flags, verbose);
+ if (ret != 0 || cnt != len) {
+ printf("unable to load kernel 2\n");
+ return 1;
+ }
+ addr += len;
+
+ /* Skip over text and data and zero bss. */
+ len = pexec->a_bss;
+ printf("+ %x", len);
+#ifdef DEBUG
+ printf("bss %x - %x\n", addr, addr + pexec->a_bss);
+#endif
+ bzero(addr, pexec->a_bss);
+ addr += len;
+
+ if (pexec->a_syms != 0 && !(kernel.bflags & RB_NOSYM)) {
+ printf(" + [ %x", pexec->a_syms);
+ addr += 4; /* skip over _end symbol */
+ symtab = (void *) pexec->a_syms;
+ len = pexec->a_syms;
+ cnt = ((len + (512 - 1)) / 512) * 512;
+ flags = IGNORE_FILENUM;
+ ret = read_tape_block(pbugargs->ctrl_lun,
+ pbugargs->dev_lun, &status, addr,
+ &cnt, blk_num, &flags, verbose);
+ if (ret != 0 || cnt != ((len + (512 - 1)) / 512) * 512) {
+ printf("unable to load kernel 3\n");
+ return 1;
+ }
+ /* this value should have already been loaded XXX */
+ esym = (void *) ((u_int) addr + pexec->a_syms);
+ if ((int) addr + cnt <= (int) esym) {
+ printf("missed loading count of symbols\n");
+ return 1;
+ }
+ addr += cnt;
+
+
+ len = *esym;
+#if 0
+ printf("start load %x end load %x %x\n", addr,
+ len, addr + len);
+ printf("esym %x *esym %x\n", esym, len);
+#endif
+ /* dont load tail of already loaded */
+ len -= (u_int) addr - (u_int) esym;
+
+ if (len > 0) {
+ printf(" + %x", *esym);
+ esym = (void *) (addr + len);
+ cnt = ((len + (512 - 1)) / 512) * 512;
+ flags = IGNORE_FILENUM;
+ ret = read_tape_block(pbugargs->ctrl_lun,
+ pbugargs->dev_lun, &status, addr,
+ &cnt, blk_num, &flags, verbose);
+ if (ret != 0 || cnt != ((len + (512-1)) / 512)*512) {
+ printf("unable to load kernel 4\n");
+ return (1);
+ }
+ addr += len;
+ printf(" ]");
+ } else {
+ printf("+ %x ]", *esym);
+ }
+ esym = (int *) (((int) esym) + *esym);
+
+ kernel.symtab = symtab;
+ kernel.esym = esym;
+ } else {
+ kernel.symtab = 0;
+ kernel.esym = 0;
+ }
+ kernel.end_loaded = (int) addr;
+ flags = IGNORE_FILENUM | END_OF_FILE;
+ cnt = 8192;
+ printf("removing pad [");
+ ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun,
+ &status, addr, &cnt, blk_num, &flags, verbose);
+ if (ret != 0) {
+ printf("unable to load kernel 5\n");
+ return (1);
+ }
+ printf(" %d ]", cnt);
+
+ printf("]\n");
+ }
+ kernel.entry = (void *) pexec->a_entry;
+ return (0);
+}
+
+int
+loadmini(addr, pbugargs)
+ u_int addr;
+ struct mvmeprom_args *pbugargs;
+{
+ int cnt, ret, blk_num = 3;
+ short status = 0;
+ u_char flags;
+
+ /* align addr to some boundary */
+#define ALIGN_F 0x4
+ addr = (u_int) ((((int) addr + ALIGN_F - 1) / ALIGN_F) * ALIGN_F);
+#undef ALIGN_F
+ flags = END_OF_FILE;
+ cnt = 6144 * 512; /* some abserdly large value. (3meg) */
+ printf("loading miniroot[ ");
+ ret = read_tape_block(pbugargs->ctrl_lun, pbugargs->dev_lun,
+ &status, (void *) addr, &cnt, blk_num, &flags, verbose);
+ if (ret != 0) {
+ printf("unable to load miniroot\n");
+ return (1);
+ }
+ kernel.smini = (void *)addr;
+ printf("%d ]\n", cnt);
+ kernel.emini = (void *) ((u_int) addr + cnt);
+ kernel.end_loaded = (u_int) kernel.emini;
+ return (0);
+}
+
+void
+parse_args(pargs)
+ struct mvmeprom_args *pargs;
+{
+ char *ptr = pargs->arg_start;
+ char c, *name = NULL;
+ int howto = 0;
+
+ if (pargs->arg_start != pargs->arg_end) {
+ while (c = *ptr) {
+ while (c == ' ')
+ c = *++ptr;
+ if (!c)
+ return;
+ if (c != '-') {
+ name = ptr;
+ while ((c = *++ptr) && c != ' ');
+ if (c)
+ *ptr++ = 0;
+ continue;
+ }
+ while ((c = *++ptr) && c != ' ') {
+ if (c == 'a')
+ howto |= RB_ASKNAME;
+ else if (c == 'b')
+ howto |= RB_HALT;
+ else if (c == 'y')
+ howto |= RB_NOSYM;
+ else if (c == 'd')
+ howto |= RB_KDB;
+ else if (c == 'm')
+ howto |= RB_MINIROOT;
+ else if (c == 'r')
+ howto |= RB_DFLTROOT;
+ else if (c == 's')
+ howto |= RB_SINGLE;
+ }
+ }
+ }
+ kernel.bflags = howto;
+ kernel.kname = name;
+}
diff --git a/sys/arch/mvme68k/stand/bugcrt/Makefile b/sys/arch/mvme68k/stand/bugcrt/Makefile
new file mode 100644
index 00000000000..9efe6b2d092
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bugcrt/Makefile
@@ -0,0 +1,24 @@
+# $Id: Makefile,v 1.1 1995/10/18 10:44:45 deraadt Exp $
+
+CFLAGS+=-I${.CURDIR}/../../include
+
+.include "${MACHINE_ARCH}/Makefile.inc"
+
+.PATH: ${.CURDIR}/${MACHINE_ARCH}
+
+OBJS=bugcrt.o
+
+CLEANFILES+=a.out
+
+all: ${OBJS}
+
+bugcrt.o: bugcrt.c
+ ${CC} ${CFLAGS} -c -O ${.ALLSRC}
+ ${LD} -x -r ${.TARGET}
+ mv a.out ${.TARGET}
+
+install:
+
+lint tags:
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/mvme68k/stand/bugcrt/Makefile.inc b/sys/arch/mvme68k/stand/bugcrt/Makefile.inc
new file mode 100644
index 00000000000..f2bae6c888c
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bugcrt/Makefile.inc
@@ -0,0 +1,12 @@
+BUG_CRT_DIR=${S}/arch/${MACHINE}/stand/bugcrt
+
+BUGCRT_DIR!= cd ${BUG_CRT_DIR}; \
+ printf "xxx:\n\techo \$${.OBJDIR}\n" | ${MAKE} -r -s -f - xxx
+
+BUGCRT=${BUGCRT_DIR}/bugcrt.o
+
+$(BUGCRT): .NOTMAIN __always_make_bugcrt
+ @echo making sure the bugcrt is up to date...
+ @(cd ${BUG_CRT_DIR}; ${MAKE})
+
+__always_make_bugcrt: .NOTMAIN
diff --git a/sys/arch/mvme68k/stand/bugcrt/m68k/Makefile.inc b/sys/arch/mvme68k/stand/bugcrt/m68k/Makefile.inc
new file mode 100644
index 00000000000..f44c6aa6c1d
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bugcrt/m68k/Makefile.inc
@@ -0,0 +1 @@
+CFLAGS+=-fomit-frame-pointer
diff --git a/sys/arch/mvme68k/stand/bugcrt/m68k/bugcrt.c b/sys/arch/mvme68k/stand/bugcrt/m68k/bugcrt.c
new file mode 100644
index 00000000000..1737f837ced
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bugcrt/m68k/bugcrt.c
@@ -0,0 +1,43 @@
+#include <sys/types.h>
+#include <machine/prom.h>
+
+struct mvmeprom_args bugargs;
+
+ asm (".text");
+ asm (".long 0x003ffff8");
+ asm (".long _start");
+extern int edata;
+extern int end;
+start()
+{
+ register int dev_lun asm ("d0");
+ register int ctrl_lun asm ("d1");
+ register int flags asm ("d4");
+ register int ctrl_addr asm ("a0");
+ register int entry asm ("a1");
+ register int conf_blk asm ("a2");
+ register char *arg_start asm ("a5");
+ register char *arg_end asm ("a6");
+
+ register struct mvmeprom_args *bugarea;
+
+ bugarea = &bugargs;
+ bugarea->dev_lun = dev_lun;
+ bugarea->ctrl_lun = ctrl_lun;
+ bugarea->flags = flags;
+ bugarea->ctrl_addr = ctrl_addr;
+ bugarea->entry = entry;
+ bugarea->conf_blk = conf_blk;
+ bugarea->arg_start = arg_start;
+ bugarea->arg_end = arg_end;
+ *arg_end = 0;
+
+ bzero(&edata, (int)&end-(int)&edata);
+ main(bugarea);
+ mvmeprom_return();
+ /* NOTREACHED */
+}
+
+__main()
+{
+}
diff --git a/sys/arch/mvme68k/stand/bugcrt/m88k/Makefile.inc b/sys/arch/mvme68k/stand/bugcrt/m88k/Makefile.inc
new file mode 100644
index 00000000000..f44c6aa6c1d
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bugcrt/m88k/Makefile.inc
@@ -0,0 +1 @@
+CFLAGS+=-fomit-frame-pointer
diff --git a/sys/arch/mvme68k/stand/bugcrt/m88k/bugcrt.c b/sys/arch/mvme68k/stand/bugcrt/m88k/bugcrt.c
new file mode 100644
index 00000000000..c9ffa7ddad7
--- /dev/null
+++ b/sys/arch/mvme68k/stand/bugcrt/m88k/bugcrt.c
@@ -0,0 +1,42 @@
+#include <sys/types.h>
+#include <machine/prom.h>
+
+struct bugargs bugargs;
+ asm (".text");
+ asm (".long 0x003ffff8");
+ asm (".long _start");
+extern int edata;
+extern int end;
+start()
+{
+ register int dev_lun asm ("r2");
+ register int ctrl_lun asm ("r3");
+ register int flags asm ("r4");
+ register int ctrl_addr asm ("r5");
+ register int entry asm ("r6");
+ register int conf_blk asm ("r7");
+ register char *arg_start asm ("r8");
+ register char *arg_end asm ("r9");
+
+ register struct mvmeprom_args *bugarea;
+
+ bugarea = &bugargs;
+ bugarea->dev_lun = dev_lun;
+ bugarea->ctrl_lun = ctrl_lun;
+ bugarea->flags = flags;
+ bugarea->ctrl_addr = ctrl_addr;
+ bugarea->entry = entry;
+ bugarea->conf_blk = conf_blk;
+ bugarea->arg_start = arg_start;
+ bugarea->arg_end = arg_end;
+ *arg_end = 0;
+
+ bzero(&edata, (int)&edata - (int)&end);
+ main(bugarea);
+ mvmeprom_return();
+ /* NOTREACHED */
+}
+
+__main()
+{
+}
diff --git a/sys/arch/mvme68k/stand/libbug/Makefile b/sys/arch/mvme68k/stand/libbug/Makefile
new file mode 100644
index 00000000000..ba775e5693d
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/Makefile
@@ -0,0 +1,14 @@
+LIB=bug
+
+NOPIC=
+NOPROFILE=
+
+CFLAGS+=-I${.CURDIR}/../../include
+
+SRCS=delay.c diskrd.c diskwr.c getbrdid.c instat.c outln.c outstr.c \
+ return.c rtc_rd.c
+.PATH: ${.CURDIR}/../../../../lib/libc_sa ${.CURDIR}/${MACHINE_ARCH}
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/sys/arch/mvme68k/stand/libbug/Makefile.inc b/sys/arch/mvme68k/stand/libbug/Makefile.inc
new file mode 100644
index 00000000000..dc1ad6b04c8
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/Makefile.inc
@@ -0,0 +1,12 @@
+LIB_BUG_DIR=${S}/arch/${MACHINE}/stand/libbug
+
+LIBBUG_DIR!= cd ${LIB_BUG_DIR}; \
+ printf "xxx:\n\techo \$${.OBJDIR}\n" | ${MAKE} -r -s -f - xxx
+
+LIBBUG=${LIBBUG_DIR}/libbug.a
+
+$(LIBBUG): .NOTMAIN __always_make_libbug
+ @echo making sure the libbug is up to date...
+ @(cd ${LIB_BUG_DIR}; ${MAKE})
+
+__always_make_libbug: .NOTMAIN
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/delay.c b/sys/arch/mvme68k/stand/libbug/m68k/delay.c
new file mode 100644
index 00000000000..a5c1f620084
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/delay.c
@@ -0,0 +1,15 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* BUG - timing routine */
+void
+mvmeprom_delay(msec)
+ int msec;
+{
+ asm volatile ("movel %0,sp@-" : :"d" (msec));
+ MVMEPROM_CALL(MVMEPROM_DELAY);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/diskrd.c b/sys/arch/mvme68k/stand/libbug/m68k/diskrd.c
new file mode 100644
index 00000000000..b0ebde49624
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/diskrd.c
@@ -0,0 +1,19 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* returns 0: success, nonzero: error */
+int
+mvmeprom_diskrd(arg)
+ struct mvmeprom_dskio *arg;
+{
+ int ret;
+
+ asm volatile ("movel %0, sp@-"::"d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKRD);
+ asm volatile ("movew ccr,%0": "=d" (ret));
+ return (!(ret & 0x4));
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/diskwr.c b/sys/arch/mvme68k/stand/libbug/m68k/diskwr.c
new file mode 100644
index 00000000000..962b947ccb3
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/diskwr.c
@@ -0,0 +1,19 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* returns 0: success, nonzero: error */
+int
+mvmeprom_diskwr(arg)
+ struct mvmeprom_dskio *arg;
+{
+ int ret;
+
+ asm volatile ("movel %0, sp@-"::"d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKWR);
+ asm volatile ("movew ccr,%0": "=d" (ret));
+ return (!(ret & 0x4));
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/getbrdid.c b/sys/arch/mvme68k/stand/libbug/m68k/getbrdid.c
new file mode 100644
index 00000000000..ded49ac3155
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/getbrdid.c
@@ -0,0 +1,18 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* BUG - query board routines */
+struct mvmeprom_brdid *
+mvmeprom_getbrdid()
+{
+ struct mvmeprom_brdid *id;
+
+ asm volatile ("clrl sp@-");
+ MVMEPROM_CALL(MVMEPROM_GETBRDID);
+ asm volatile ("movel sp@+,%0": "=d" (id):);
+ return (id);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/instat.c b/sys/arch/mvme68k/stand/libbug/m68k/instat.c
new file mode 100644
index 00000000000..5e2f2d3e69e
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/instat.c
@@ -0,0 +1,17 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* returns 0 if no characters ready to read */
+int
+mvmeprom_instat()
+{
+ u_short ret;
+
+ MVMEPROM_CALL(MVMEPROM_INSTAT);
+ asm volatile ("movew ccr,%0": "=d" (ret));
+ return (!(ret & 0x4));
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/outln.c b/sys/arch/mvme68k/stand/libbug/m68k/outln.c
new file mode 100644
index 00000000000..344f0ed01f1
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/outln.c
@@ -0,0 +1,15 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+void
+mvmeprom_outln(start, end)
+ char *start, *end;
+{
+ asm volatile ("movl %0, sp@-" : "=a" (start));
+ asm volatile ("movl %0, sp@-" : "=a" (end));
+ MVMEPROM_CALL(MVMEPROM_OUTSTRCRLF);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/outstr.c b/sys/arch/mvme68k/stand/libbug/m68k/outstr.c
new file mode 100644
index 00000000000..b0a7c9ebc92
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/outstr.c
@@ -0,0 +1,15 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+void
+mvmeprom_outstr(start, end)
+ char *start, *end;
+{
+ asm volatile ("movl %0, sp@-" : "=a" (start));
+ asm volatile ("movl %0, sp@-" : "=a" (end));
+ MVMEPROM_CALL(MVMEPROM_OUTSTR);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/return.c b/sys/arch/mvme68k/stand/libbug/m68k/return.c
new file mode 100644
index 00000000000..00206a16c48
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/return.c
@@ -0,0 +1,14 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* BUG - return to bug routine */
+void
+mvmeprom_return()
+{
+ MVMEPROM_CALL(MVMEPROM_EXIT);
+ /*NOTREACHED*/
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m68k/rtc_rd.c b/sys/arch/mvme68k/stand/libbug/m68k/rtc_rd.c
new file mode 100644
index 00000000000..7b075c4fd9f
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m68k/rtc_rd.c
@@ -0,0 +1,14 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+void
+mvmeprom_rtc_rd(ptime)
+ struct mvmeprom_time *ptime;
+{
+ asm volatile ("movel %0,sp@-" : :"a" (ptime));
+ MVMEPROM_CALL(MVMEPROM_RTC_RD);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/delay.c b/sys/arch/mvme68k/stand/libbug/m88k/delay.c
new file mode 100644
index 00000000000..68b1db12106
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/delay.c
@@ -0,0 +1,15 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* BUG - timing routine */
+void
+mvmeprom_delay(msec)
+ int msec;
+{
+ asm volatile ("or r2,r0,%0": : "r" (msec));
+ MVMEPROM_CALL(MVMEPROM_DELAY);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/diskrd.c b/sys/arch/mvme68k/stand/libbug/m88k/diskrd.c
new file mode 100644
index 00000000000..bc69b365501
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/diskrd.c
@@ -0,0 +1,19 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* returns 0: success, nonzero: error */
+int
+mvmeprom_diskrd(arg)
+ struct mvmeprom_dskio *arg;
+{
+ int ret;
+
+ asm volatile ("or r2,r0,%0": : "r" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKRD);
+ asm volatile ("or %0,r0,r2" : "=r" (ret));
+ return (!(ret & 0x4));
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/diskwr.c b/sys/arch/mvme68k/stand/libbug/m88k/diskwr.c
new file mode 100644
index 00000000000..681f521b5b0
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/diskwr.c
@@ -0,0 +1,19 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* returns 0: success, nonzero: error */
+int
+mvmeprom_diskwr(arg)
+ struct mvmeprom_dskio *arg;
+{
+ int ret;
+
+ asm volatile ("or r2,r0,%0": : "r" (arg) );
+ MVMEPROM_CALL(MVMEPROM_DSKWR);
+ asm volatile ("or %0,r0,r2" : "=r" (ret));
+ return (!(ret & 0x4));
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/getbrdid.c b/sys/arch/mvme68k/stand/libbug/m88k/getbrdid.c
new file mode 100644
index 00000000000..eeda9468ab7
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/getbrdid.c
@@ -0,0 +1,17 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* BUG - query board routines */
+struct mvmeprom_brdid *
+mvmeprom_brdid()
+{
+ struct mvmeprom_brdid *id;
+
+ MVMEPROM_CALL(MVMEPROM_GETBRDID);
+ asm volatile ("or %0,r0,r2": "=r" (id):);
+ return (id);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/instat.c b/sys/arch/mvme68k/stand/libbug/m88k/instat.c
new file mode 100644
index 00000000000..0ac97fe7676
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/instat.c
@@ -0,0 +1,17 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* returns 0 if no characters ready to read */
+int
+mvmeprom_instat()
+{
+ short ret;
+
+ MVMEPROM_CALL(MVMEPROM_INSTAT);
+ asm volatile ("or %0,r0,r2" : "=r" (ret));
+ return (!(ret & 0x4));
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/outch.c b/sys/arch/mvme68k/stand/libbug/m88k/outch.c
new file mode 100644
index 00000000000..78110e0299f
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/outch.c
@@ -0,0 +1,15 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+void
+mvmeprom_outchr(a)
+ char a;
+{
+ asm volatile ("or r2, r0, %0" : :"r" (a));
+ BUG_CALL(_OUTCHR);
+}
+
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/outln.c b/sys/arch/mvme68k/stand/libbug/m88k/outln.c
new file mode 100644
index 00000000000..ed0067e42d9
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/outln.c
@@ -0,0 +1,15 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+void
+mvmeprom_outln(start, end)
+ char *start, *end;
+{
+ asm volatile ("or r2,r0,%0": : "r" (start));
+ asm volatile ("or r3,r0,%0": : "r" (end));
+ MVMEPROM_CALL(MVMEPROM_OUTSTRCRLF);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/outstr.c b/sys/arch/mvme68k/stand/libbug/m88k/outstr.c
new file mode 100644
index 00000000000..c9e3c355736
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/outstr.c
@@ -0,0 +1,15 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+void
+mvmeprom_outstr(start, end)
+ char *start, *end;
+{
+ asm volatile ("or r2,r0,%0": : "r" (start));
+ asm volatile ("or r3,r0,%0": : "r" (end));
+ MVMEPROM_CALL(MVMEPROM_OUTSTR);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/prom.h b/sys/arch/mvme68k/stand/libbug/m88k/prom.h
new file mode 100644
index 00000000000..4048e86eaff
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/prom.h
@@ -0,0 +1,3 @@
+#define MVMEPROM_CALL(x) \
+ asm volatile ( __CONCAT("or r9,r0," __STRING(x)) ); \
+ asm volatile ("tb0 0,r0,496");
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/return.c b/sys/arch/mvme68k/stand/libbug/m88k/return.c
new file mode 100644
index 00000000000..00206a16c48
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/return.c
@@ -0,0 +1,14 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+/* BUG - return to bug routine */
+void
+mvmeprom_return()
+{
+ MVMEPROM_CALL(MVMEPROM_EXIT);
+ /*NOTREACHED*/
+}
diff --git a/sys/arch/mvme68k/stand/libbug/m88k/rtc_rd.c b/sys/arch/mvme68k/stand/libbug/m88k/rtc_rd.c
new file mode 100644
index 00000000000..7cff3227678
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/m88k/rtc_rd.c
@@ -0,0 +1,14 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+void
+mvmeprom_rtc_rd(ptime)
+ struct mvmeprom_time *ptime)
+{
+ asm volatile ("or r2,r0,%0": : "r" (ptime));
+ MVMEPROM_CALL(MVMEPROM_RTC_RD);
+}
diff --git a/sys/arch/mvme68k/stand/libbug/ppc/bug.c b/sys/arch/mvme68k/stand/libbug/ppc/bug.c
new file mode 100644
index 00000000000..02a1b1fd15b
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libbug/ppc/bug.c
@@ -0,0 +1,133 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include "bug.h"
+
+#define _INCHR "0x00"
+#define _INSTAT "0x01"
+#define _INLN "0x02"
+#define _READSTR "0x03"
+#define _READLN "0x04"
+#define _OUTCHR "0x20"
+#define _OUTSTR "0x21"
+#define _OUTLN "0x22"
+#define _DSKRD "0x10"
+#define _DSKWR "0x11"
+#define _DSKCFIG "0x12"
+#define _DSKFMT "0x14"
+#define _DSKCTRL "0x15"
+#define _WRITE "0x23"
+#define _WRITELN "0x24"
+#define _DELAY "0x43"
+#define _RTC_RD "0x53"
+#define _RETURN "0x63"
+#define _BRD_ID "0x70"
+
+/* BUG - tty routines */
+
+#define BUG_CALL(x) \
+ asm volatile ("addi r10,r0," x); \
+ asm volatile ("sc");
+
+char bug_inchr()
+{
+ register char a;
+ asm volatile ("sub r31,r31,4");
+ BUG_CALL(_INCHR);
+ asm volatile ("or %0,r0,r2" : "=r" (a));
+ return a;
+}
+
+/* returns 0 if no characters ready to read */
+int bug_instat()
+{
+ short ret;
+ BUG_CALL(_INSTAT);
+ asm volatile ("or %0,r0,r2" : "=r" (ret));
+ return (!(ret & 0x4));
+
+}
+
+void bug_outchr(char a)
+{
+ asm volatile ("or r2, r0, %0" : :"r" (a));
+ BUG_CALL(_OUTCHR);
+ return;
+}
+
+void bug_outstr(char *pstrb, char *pstre)
+{
+ asm volatile ("or r2,r0,%0": : "r" (pstrb) );
+ asm volatile ("or r3,r0,%0": : "r" (pstre) );
+ BUG_CALL(_OUTSTR);
+ return;
+}
+
+void bug_outln(char *pstrb, char *pstre)
+{
+ asm volatile ("or r2,r0,%0": : "r" (pstrb) );
+ asm volatile ("or r3,r0,%0": : "r" (pstre) );
+ BUG_CALL(_OUTLN);
+ return;
+}
+
+/* BUG - disk routines */
+
+/* returns 0: success, nonzero: error */
+int bug_diskrd(bug_dskio *arg)
+{
+ int ret;
+ asm volatile ("or r2,r0,%0": : "r" (arg) );
+ BUG_CALL(_DSKRD);
+ return (!(ret & 0x4));
+}
+/* returns 0: success, nonzero: error */
+int bug_diskwr(bug_dskio *arg)
+{
+ int ret;
+ asm volatile ("or r2,r0,%0": : "r" (arg) );
+ BUG_CALL(_DSKWR);
+ return (!(ret & 0x4));
+}
+#ifdef NOTYET
+bug_diskcfig()
+{
+
+}
+bug_diskfmt(){}
+bug_diskctrl(){}
+#endif
+
+/* BUG - timing routine */
+
+void bug_delay(int delay_msec)
+{
+ asm volatile ("or r2,r0,%0": : "r" (delay_msec) );
+ BUG_CALL(_DELAY);
+ return ;
+}
+
+/* BUG - return to bug routine */
+
+void bug_return()
+{
+ BUG_CALL(_RETURN);
+ /*NOTREACHED*/
+}
+
+/* BUG - query board routines */
+
+struct bug_brdid *bug_brdid()
+{
+ struct bug_brdid *pbrd_id;
+ BUG_CALL(_BRD_ID);
+ asm volatile ("or %0,r0,r2": "=r" (pbrd_id):);
+ return pbrd_id;
+}
+void bug_rtc_rd(struct bug_time *ptime)
+{
+ asm volatile ("or r2,r0,%0": : "r" (ptime));
+ BUG_CALL(_RTC_RD);
+ return;
+}
diff --git a/sys/arch/mvme68k/stand/libsa/Makefile.inc b/sys/arch/mvme68k/stand/libsa/Makefile.inc
new file mode 100644
index 00000000000..c402951fa76
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/Makefile.inc
@@ -0,0 +1,12 @@
+LIB_SA_DIR=${S}/arch/${MACHINE}/stand/libsa
+
+LIBSA_DIR!= cd ${LIB_SA_DIR}; \
+ printf "xxx:\n\techo \$${.OBJDIR}\n" | ${MAKE} -r -s -f - xxx
+
+LIBSA=${LIBSA_DIR}/libsa.a
+
+$(LIBSA): .NOTMAIN __always_make_libsa
+ @echo making sure the libsa is up to date...
+ @(cd ${LIB_SA_DIR}; ${MAKE})
+
+__always_make_libsa: .NOTMAIN
diff --git a/sys/arch/mvme68k/stand/libsa/bug.c b/sys/arch/mvme68k/stand/libsa/bug.c
new file mode 100644
index 00000000000..9b817b7e7a7
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/bug.c
@@ -0,0 +1,107 @@
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/types.h>
+#include <machine/prom.h>
+
+#define MVMEPROM_CALL(x) \
+ asm volatile (__CONCAT("trap #15; .short ", __STRING(x)) )
+
+/* returns 0 if no characters ready to read */
+int
+mvmeprom_instat()
+{
+ u_short ret;
+
+ MVMEPROM_CALL(MVMEPROM_INSTAT);
+ asm volatile ("movew ccr,%0": "=d" (ret));
+ return (!(ret & 0x4));
+}
+
+void
+mvmeprom_outstr(start, end)
+ char *start, *end;
+{
+ asm volatile ("movl %0, sp@-" : "=a" (start));
+ asm volatile ("movl %0, sp@-" : "=a" (end));
+ MVMEPROM_CALL(MVMEPROM_OUTSTR);
+}
+
+void
+mvmeprom_outln(start, end)
+ char *start, *end;
+{
+ asm volatile ("movl %0, sp@-" : "=a" (start));
+ asm volatile ("movl %0, sp@-" : "=a" (end));
+ MVMEPROM_CALL(MVMEPROM_OUTSTRCRLF);
+}
+
+/* returns 0: success, nonzero: error */
+int
+mvmeprom_diskrd(arg)
+ struct mvmeprom_dskio *arg;
+{
+ int ret;
+
+ asm volatile ("movel %0, sp@-"::"d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKRD);
+ asm volatile ("movew ccr,%0": "=d" (ret));
+ return (!(ret & 0x4));
+}
+
+/* returns 0: success, nonzero: error */
+int
+mvmeprom_diskwr(arg)
+ struct mvmeprom_dskio *arg;
+{
+ int ret;
+
+ asm volatile ("movel %0, sp@-"::"d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKWR);
+ asm volatile ("movew ccr,%0": "=d" (ret));
+ return (!(ret & 0x4));
+}
+
+#ifdef NOTYET
+mvmeprom_diskcfig() {}
+mvmeprom_diskfmt(){}
+mvmeprom_diskctrl(){}
+#endif
+
+/* BUG - timing routine */
+void
+mvmeprom_delay(msec)
+ int msec;
+{
+ asm volatile ("movel %0,sp@-" : :"d" (msec));
+ MVMEPROM_CALL(MVMEPROM_DELAY);
+}
+
+/* BUG - return to bug routine */
+void
+mvmeprom_return()
+{
+ MVMEPROM_CALL(MVMEPROM_EXIT);
+ /*NOTREACHED*/
+}
+
+/* BUG - query board routines */
+struct mvmeprom_brdid *
+mvmeprom_getbrdid()
+{
+ struct mvmeprom_brdid *id;
+
+ asm volatile ("clrl sp@-");
+ MVMEPROM_CALL(MVMEPROM_GETBRDID);
+ asm volatile ("movel sp@+,%0": "=d" (id):);
+ return (id);
+}
+
+void
+mvmeprom_rtc_rd(ptime)
+ struct mvmeprom_time *ptime;
+{
+ asm volatile ("movel %0,sp@-" : :"a" (ptime));
+ MVMEPROM_CALL(MVMEPROM_RTC_RD);
+}
diff --git a/sys/arch/mvme68k/stand/libsa/dev_disk.c b/sys/arch/mvme68k/stand/libsa/dev_disk.c
new file mode 100644
index 00000000000..8f38c06dab6
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/dev_disk.c
@@ -0,0 +1,132 @@
+/* $NetBSD: dev_disk.c,v 1.1.1.1 1995/06/01 20:38:07 gwr Exp $ */
+
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This module implements a "raw device" interface suitable for
+ * use by the stand-alone I/O library UFS file-system code, and
+ * possibly for direct access (i.e. boot from tape).
+ *
+ * The implementation is deceptively simple because it uses the
+ * drivers provided by the Sun PROM monitor. Note that only the
+ * PROM driver used to load the boot program is available here.
+ */
+
+#include <sys/types.h>
+#include <machine/mon.h>
+#include <machine/saio.h>
+
+#include "stand.h"
+
+#include "dvma.h"
+#include "promdev.h"
+
+int
+disk_open(f, devname)
+ struct open_file *f;
+ char *devname; /* Device part of file name (or NULL). */
+{
+ struct saioreq *sip;
+ int error;
+
+#ifdef DEBUG_PROM
+ printf("disk_open: %s\n", devname);
+#endif
+
+ if ((error = prom_iopen(&sip)) != 0)
+ return (error);
+
+ f->f_devdata = sip;
+ return 0;
+}
+
+int
+disk_close(f)
+ struct open_file *f;
+{
+ struct saioreq *sip;
+
+ sip = f->f_devdata;
+ prom_iclose(sip);
+ f->f_devdata = NULL;
+ return 0;
+}
+
+int
+disk_strategy(devdata, flag, dblk, size, buf, rsize)
+ void *devdata;
+ int flag;
+ daddr_t dblk;
+ u_int size;
+ char *buf;
+ u_int *rsize;
+{
+ struct saioreq *si;
+ struct boottab *ops;
+ char *dmabuf;
+ int si_flag, xcnt;
+
+ si = devdata;
+ ops = si->si_boottab;
+
+#ifdef DEBUG_PROM
+ printf("disk_strategy: size=%d dblk=%d\n", size, dblk);
+#else
+ twiddle();
+#endif
+
+ dmabuf = dvma_mapin(buf, size);
+
+ si->si_bn = dblk;
+ si->si_ma = dmabuf;
+ si->si_cc = size;
+
+ si_flag = (flag == F_READ) ? SAIO_F_READ : SAIO_F_WRITE;
+ xcnt = (*ops->b_strategy)(si, si_flag);
+ dvma_mapout(dmabuf, size);
+
+#ifdef DEBUG_PROM
+ printf("disk_strategy: xcnt = %x\n", xcnt);
+#endif
+
+ if (xcnt <= 0)
+ return (EIO);
+
+ *rsize = xcnt;
+ return (0);
+}
+
+int
+disk_ioctl()
+{
+ return EIO;
+}
+
diff --git a/sys/arch/mvme68k/stand/libsa/dev_disk.h b/sys/arch/mvme68k/stand/libsa/dev_disk.h
new file mode 100644
index 00000000000..9f05f74bd82
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/dev_disk.h
@@ -0,0 +1,6 @@
+
+int disk_open __P((struct open_file *, ...));
+int disk_close __P((struct open_file *));
+int disk_strategy __P((void *, int, daddr_t, u_int, char *, u_int *));
+int disk_ioctl();
+
diff --git a/sys/arch/mvme68k/stand/libsa/dvma.c b/sys/arch/mvme68k/stand/libsa/dvma.c
new file mode 100644
index 00000000000..11526106c2a
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/dvma.c
@@ -0,0 +1,68 @@
+
+/*
+ * The easiest way to deal with the need for DVMA mappings is
+ * to just map the first four megabytes of RAM into DVMA space.
+ * That way, dvma_mapin can just compute the DVMA alias address,
+ * and dvma_mapout does nothing.
+ */
+
+#include <sys/param.h>
+
+#define DVMA_BASE 0x00000000
+#define DVMA_MASK 0x00ffFFff
+#define DVMA_MAPLEN 0x400000 /* 4 MB */
+
+void
+dvma_init()
+{
+#if 0
+ int segva, sme;
+
+ for (segva = 0; segva < DVMA_MAPLEN; segva += NBSG) {
+ sme = get_segmap(segva);
+ set_segmap((DVMA_BASE | segva), sme);
+ }
+#endif
+}
+
+/* Convert a local address to a DVMA address. */
+char *
+dvma_mapin(char *addr, int len)
+{
+ int va = (int)addr;
+
+ va |= DVMA_BASE;
+ return ((char *) va);
+}
+
+/* Convert a DVMA address to a local address. */
+char *
+dvma_mapout(char *dmabuf, int len)
+{
+ if (dmabuf < (char*)DVMA_BASE)
+ panic("dvma_mapout");
+ return (dmabuf - DVMA_BASE);
+}
+
+extern char *alloc(int len);
+char *
+dvma_alloc(int len)
+{
+ char *mem;
+
+ mem = alloc(len);
+ if (!mem)
+ return(mem);
+ return(dvma_mapin(mem, len));
+}
+
+extern void free(void *ptr, int len);
+void
+dvma_free(char *dvma, int len)
+{
+ char *mem;
+
+ mem = dvma_mapout(dvma, len);
+ if (mem)
+ free(mem, len);
+}
diff --git a/sys/arch/mvme68k/stand/libsa/dvma.h b/sys/arch/mvme68k/stand/libsa/dvma.h
new file mode 100644
index 00000000000..2b8be37cbe0
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/dvma.h
@@ -0,0 +1,6 @@
+
+char * dvma_mapin(char *pkt, int len);
+void dvma_mapout(char *dmabuf, int len);
+
+char * dvma_alloc(int len);
+
diff --git a/sys/arch/mvme68k/stand/libsa/exec_sun.c b/sys/arch/mvme68k/stand/libsa/exec_sun.c
new file mode 100644
index 00000000000..d58c6ce0cde
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/exec_sun.c
@@ -0,0 +1,183 @@
+/* $NetBSD: exec_sun.c,v 1.3 1995/06/09 22:23:01 gwr Exp $ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. 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 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.
+ *
+ * @(#)boot.c 8.1 (Berkeley) 6/10/93
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <a.out.h>
+
+#include "stand.h"
+
+extern int debug;
+
+extern u_int bootdev;
+
+/*ARGSUSED*/
+exec_sun(file, loadaddr, howto)
+ char *file;
+ char *loadaddr;
+ int howto;
+{
+ register int io;
+ struct exec x;
+ int cc, magic;
+ void (*entry)();
+ register char *cp;
+ register int *ip;
+ int textlen;
+
+#ifdef DEBUG
+ printf("exec_sun: file=%s loadaddr=0x%x\n", file, loadaddr);
+#endif
+
+ io = open(file, 0);
+ if (io < 0)
+ return(-1);
+
+ /*
+ * Read in the exec header, and validate it.
+ */
+ if (read(io, (char *)&x, sizeof(x)) != sizeof(x))
+ goto shread;
+ if (N_BADMAG(x)) {
+ errno = EFTYPE;
+ goto closeout;
+ }
+
+ cp = loadaddr;
+ textlen = x.a_text;
+ magic = N_GETMAGIC(x);
+ if (magic == ZMAGIC) {
+ cp += sizeof(x);
+ textlen -= sizeof(x);
+ }
+ entry = (void (*)())cp;
+
+ /*
+ * Leave a copy of the exec header before the text.
+ * The sun3 kernel uses this to verify that the
+ * symbols were loaded by this boot program.
+ */
+ bcopy(&x, cp - sizeof(x), sizeof(x));
+
+ /*
+ * Read in the text segment.
+ */
+ printf("%x", x.a_text);
+ if (read(io, cp, textlen) != textlen)
+ goto shread;
+ cp += textlen;
+
+ /*
+ * NMAGIC may have a gap between text and data.
+ */
+ if (magic == NMAGIC) {
+ register int mask = N_PAGSIZ(x) - 1;
+ while ((int)cp & mask)
+ *cp++ = 0;
+ }
+
+ /*
+ * Read in the data segment.
+ */
+ printf("+%x", x.a_data);
+ if (read(io, cp, x.a_data) != x.a_data)
+ goto shread;
+ cp += x.a_data;
+
+ /*
+ * Zero out the BSS section.
+ * (Kernel does not do it itself)
+ */
+ printf("+%x", x.a_bss);
+ cc = x.a_bss;
+ while ((int)cp & 3) {
+ *cp++ = 0;
+ --cc;
+ }
+ ip = (int *)cp;
+ cp += cc;
+ while ((char *)ip < cp)
+ *ip++ = 0;
+
+ /*
+ * Read in the symbol table and strings.
+ * (Always set the symtab size word.)
+ */
+ *ip++ = x.a_syms;
+ cp = (char *)ip;
+
+ if (x.a_syms > 0) {
+
+ /* Symbol table and string table length word. */
+ cc = x.a_syms;
+ printf("+[%x", cc);
+ cc += sizeof(int); /* strtab length too */
+ if (read(io, cp, cc) != cc)
+ goto shread;
+ cp += x.a_syms;
+ ip = (int *)cp; /* points to strtab length */
+ cp += sizeof(int);
+
+ /* String table. Length word includes itself. */
+ cc = *ip;
+ printf("+%x]", cc);
+ cc -= sizeof(int);
+ if (cc <= 0)
+ goto shread;
+ if (read(io, cp, cc) != cc)
+ goto shread;
+ cp += cc;
+ }
+ printf("=%x\n", cp - loadaddr);
+ close(io);
+
+ if (debug) {
+ printf("Debug mode - enter c to continue\n");
+ asm(" trap #0");
+ }
+
+ printf("Starting program at 0x%x\n", (int)entry);
+ (*entry)(howto, bootdev, cp, 0, 0);
+ panic("exec returned");
+
+shread:
+ printf("exec: short read\n");
+ errno = EIO;
+closeout:
+ close(io);
+ return(-1);
+}
diff --git a/sys/arch/mvme68k/stand/libsa/netif_sun.c b/sys/arch/mvme68k/stand/libsa/netif_sun.c
new file mode 100644
index 00000000000..db5d203b4fa
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/netif_sun.c
@@ -0,0 +1,284 @@
+/* $NetBSD: netif_sun.c,v 1.1 1995/06/09 22:19:26 gwr Exp $ */
+
+/*
+ * Copyright (c) 1995 Gordon W. Ross
+ * 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.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon W. Ross
+ *
+ * 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 Sun PROM has a fairly general set of network drivers,
+ * so it is easiest to just replace the netif module with
+ * this adaptation to the PROM network interface.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <time.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+
+#include <machine/control.h>
+#include <machine/idprom.h>
+#include <machine/mon.h>
+#include <machine/saio.h>
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+
+#include "clock.h"
+#include "dvma.h"
+#include "promdev.h"
+
+static struct netif netif_prom;
+
+#ifdef NETIF_DEBUG
+int netif_debug;
+#endif
+
+struct iodesc sockets[SOPEN_MAX];
+
+struct iodesc *
+socktodesc(sock)
+ int sock;
+{
+ if (sock != 0) {
+ return(NULL);
+ }
+ return (sockets);
+}
+
+int
+netif_open(machdep_hint)
+ void *machdep_hint;
+{
+ struct saioreq *si;
+ struct iodesc *io;
+ int fd, error;
+
+ /* find a free socket */
+ io = sockets;
+ if (io->io_netif) {
+#ifdef DEBUG
+ printf("netif_open: device busy\n");
+#endif
+ return (-1);
+ }
+ bzero(io, sizeof(*io));
+
+ /*
+ * Note: Sun PROMs will do RARP on open, but does not tell
+ * you the IP address it gets, so it is just noise to us...
+ */
+ if ((error = prom_iopen(&si)) != 0) {
+#ifdef DEBUG
+ printf("netif_open: prom_iopen, error=%d\n", error);
+#endif
+ return (-1);
+ }
+ if (si->si_sif == NULL) {
+#ifdef DEBUG
+ printf("netif_open: not a network device\n");
+#endif
+ prom_iclose(si);
+ return (-1);
+ }
+
+ netif_prom.devdata = si;
+ io->io_netif = &netif_prom;
+
+ /* Put our ethernet address in io->myea */
+ sun3_getether(io->myea);
+
+ return(0);
+}
+
+int
+netif_close(fd)
+ int fd;
+{
+ struct iodesc *io;
+ struct netif *ni;
+
+ if (fd != 0) {
+ errno = EBADF;
+ return(-1);
+ }
+
+ io = sockets;
+ ni = io->io_netif;
+ if (ni != NULL) {
+ prom_iclose(ni->devdata);
+ ni->devdata = NULL;
+ io->io_netif = NULL;
+ }
+ return(0);
+}
+
+/*
+ * Send a packet. The ether header is already there.
+ * Return the length sent (or -1 on error).
+ */
+int
+netif_put(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+{
+ struct saioreq *si;
+ struct saif *sif;
+ char *dmabuf;
+ int rv, sendlen;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug) {
+ struct ether_header *eh;
+
+ printf("netif_put: desc=0x%x pkt=0x%x len=%d\n",
+ desc, pkt, len);
+ eh = pkt;
+ printf("dst: %s ", ether_sprintf(eh->ether_dhost));
+ printf("src: %s ", ether_sprintf(eh->ether_shost));
+ printf("type: 0x%x\n", eh->ether_type & 0xFFFF);
+ }
+#endif
+
+ si = desc->io_netif->devdata;
+ sif = si->si_sif;
+ sendlen = len;
+ if (sendlen < 60) {
+ sendlen = 60;
+#ifdef NETIF_DEBUG
+ printf("netif_put: length padded to %d\n", sendlen);
+#endif
+ }
+
+#ifdef PARANOID
+ if (sif == NULL)
+ panic("netif_put: no saif ptr\n");
+#endif
+
+ dmabuf = dvma_mapin(pkt, sendlen);
+ rv = sif->sif_xmit(si->si_devdata, dmabuf, sendlen);
+ dvma_mapout(dmabuf, sendlen);
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("netif_put: xmit returned %d\n", rv);
+#endif
+ if (rv == 0) rv = len;
+ else rv = -1;
+
+ return rv;
+}
+
+/*
+ * Receive a packet, including the ether header.
+ * Return the total length received (or -1 on error).
+ */
+int
+netif_get(desc, pkt, maxlen, timo)
+ struct iodesc *desc;
+ void *pkt;
+ int maxlen;
+ time_t timo;
+{
+ struct saioreq *si;
+ struct saif *sif;
+ char *dmabuf;
+ int tick0, tmo_ticks;
+ int len;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("netif_get: pkt=0x%x, maxlen=%d, tmo=%d\n",
+ pkt, maxlen, timo);
+#endif
+
+ si = desc->io_netif->devdata;
+ sif = si->si_sif;
+
+#ifdef PARANOID
+ if (sif == NULL)
+ panic("netif_get: no saif ptr\n");
+#endif
+
+ tmo_ticks = timo * hz;
+ tick0 = getticks();
+
+ dmabuf = dvma_mapin(pkt, maxlen);
+ do len = sif->sif_poll(si->si_devdata, dmabuf);
+ while ((len == 0) && ((getticks() - tick0) < tmo_ticks));
+ dvma_mapout(dmabuf, maxlen);
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("netif_get: received len=%d\n", len);
+#endif
+
+ if (len < 12)
+ return -1;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug) {
+ struct ether_header *eh = pkt;
+
+ printf("dst: %s ", ether_sprintf(eh->ether_dhost));
+ printf("src: %s ", ether_sprintf(eh->ether_shost));
+ printf("type: 0x%x\n", eh->ether_type & 0xFFFF);
+ }
+#endif
+
+ return len;
+}
+
+static struct idprom sun3_idprom;
+
+sun3_getether(ea)
+ u_char *ea;
+{
+ u_char *src, *dst;
+ int len, x;
+
+ if (sun3_idprom.idp_format == 0) {
+ dst = (char*)&sun3_idprom;
+ src = (char*)IDPROM_BASE;
+ len = IDPROM_SIZE;
+ do {
+ x = get_control_byte(src++);
+ *dst++ = x;
+ } while (--len > 0);
+ }
+ MACPY(sun3_idprom.idp_etheraddr, ea);
+}
+
diff --git a/sys/arch/mvme68k/stand/libsa/promboot.c b/sys/arch/mvme68k/stand/libsa/promboot.c
new file mode 100644
index 00000000000..157385447e9
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/promboot.c
@@ -0,0 +1,92 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/reboot.h>
+#include "stand.h"
+#include "promboot.h"
+
+char prom_bootdev[32];
+char prom_bootfile[32];
+int prom_boothow;
+int debug;
+
+void
+prom_get_boot_info()
+{
+ char c, *src, *dst;
+ extern int devlun, ctrlun;
+ extern char *oparg, *opargend;
+
+#ifdef DEBUG
+ printf("prom_get_boot_info\n");
+#endif
+
+ /* Get kernel filename */
+ src = oparg;
+ while (src && (*src == ' ' || *src == '\t'))
+ src++;
+
+ dst = prom_bootfile;
+ if (src && *src != '-') {
+ while (src && *src) {
+ if (*src == ' ' || *src == '\t')
+ break;
+ *dst++ = *src++;
+ }
+ }
+ *dst = '\0';
+
+ /* Get boothowto flags */
+ while (src && (*src == ' ' || *src == '\t'))
+ src++;
+ if (src && (*src == '-')) {
+ while (*src) {
+ switch (*src++) {
+ case 'a':
+ prom_boothow |= RB_ASKNAME;
+ break;
+ case 's':
+ prom_boothow |= RB_SINGLE;
+ break;
+ case 'd':
+ prom_boothow |= RB_KDB;
+ debug = 1;
+ break;
+ }
+ }
+ }
+#ifdef DEBUG
+ printf("promboot: device=\"%s\" file=\"%s\" how=0x%x\n",
+ prom_bootdev, prom_bootfile, prom_boothow);
+#endif
+}
diff --git a/sys/arch/mvme68k/stand/libsa/promboot.h b/sys/arch/mvme68k/stand/libsa/promboot.h
new file mode 100644
index 00000000000..86b5aace21c
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/promboot.h
@@ -0,0 +1,5 @@
+
+extern char prom_bootdev[];
+extern char prom_bootfile[];
+extern int prom_boothow;
+
diff --git a/sys/arch/mvme68k/stand/libsa/promcons.c b/sys/arch/mvme68k/stand/libsa/promcons.c
new file mode 100644
index 00000000000..ceffe9e6c39
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/promcons.c
@@ -0,0 +1,61 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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 <stdarg.h>
+#include <sys/types.h>
+
+int
+getchar()
+{
+ char c;
+
+ __asm("movb #0,sp@-; trap #15; .short 0x0; movb sp@+, %0" : : "d" (c));
+ return (c);
+}
+
+peekchar()
+{
+ int have = 0;
+
+ __asm("trap #15; .short 0x1; beq 1f; movl #1, %0\n1:" : : "d" (have));
+ return (have);
+}
+
+void
+putchar(c)
+ int c;
+{
+ if (c == '\n')
+ putchar('\r');
+ __asm("movb %0,sp@-; trap #15; .short 0x20" : : "d" (c));
+}
+
diff --git a/sys/arch/mvme68k/stand/libsa/promdev.c b/sys/arch/mvme68k/stand/libsa/promdev.c
new file mode 100644
index 00000000000..6f733d6bc81
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/promdev.c
@@ -0,0 +1,193 @@
+/* $NetBSD: promdev.c,v 1.2 1995/06/09 22:23:04 gwr Exp $ */
+
+/*
+ * Copyright (c) 1995 Gordon W. Ross
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 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 <machine/mon.h>
+#include <machine/pte.h>
+#include <machine/saio.h>
+
+#include <dvma.h>
+#include <stand.h>
+
+struct saioreq prom_si;
+static int promdev_inuse;
+
+static char *
+prom_mapin(u_long physaddr, int length, int maptype);
+
+int
+prom_iopen(void **devdatap)
+{
+ struct bootparam *bp;
+ struct boottab *ops;
+ struct devinfo *dip;
+ struct saioreq *si;
+ char *p;
+ int error;
+
+ if (promdev_inuse)
+ return(EMFILE);
+
+ bp = *romp->bootParam;
+ ops = bp->bootDevice;
+ dip = ops->b_devinfo;
+
+#ifdef DEBUG_PROM
+ printf("Boot device type: %s\n", ops->b_desc);
+#endif
+
+ dvma_init();
+
+ si = &prom_si;
+ bzero((caddr_t)si, sizeof(*si));
+ si->si_boottab = ops;
+ si->si_ctlr = bp->ctlrNum;
+ si->si_unit = bp->unitNum;
+ si->si_boff = bp->partNum;
+
+ if (si->si_ctlr > dip->d_stdcount) {
+ printf("Invalid controller number\n");
+ return(ENXIO);
+ }
+
+ if (dip->d_devbytes) {
+ si->si_devaddr = prom_mapin(dip->d_stdaddrs[si->si_ctlr],
+ dip->d_devbytes, dip->d_devtype);
+#ifdef DEBUG_PROM
+ printf("prom_iopen: devaddr=0x%x pte=0x%x\n",
+ si->si_devaddr, get_pte(si->si_devaddr));
+#endif
+ }
+
+ if (dip->d_dmabytes) {
+ si->si_dmaaddr = dvma_alloc(dip->d_dmabytes);
+#ifdef DEBUG_PROM
+ printf("prom_iopen: dmaaddr=0x%x\n", si->si_dmaaddr);
+#endif
+ }
+
+ /* OK, call the PROM device open routine. */
+ error = (*ops->b_open)(si);
+ if (error != 0) {
+ printf("prom_iopen: \"%s\" error=%d\n",
+ ops->b_desc, error);
+ return (ENXIO);
+ }
+#ifdef DEBUG_PROM
+ printf("prom_iopen: succeeded, error=%d\n", error);
+#endif
+
+ *devdatap = si;
+ promdev_inuse++;
+ return (0);
+}
+
+void
+prom_iclose(void *devdata)
+{
+ struct boottab *ops;
+ struct devinfo *dip;
+ struct saioreq *si;
+
+ if (promdev_inuse == 0)
+ return;
+
+ si = devdata;
+ ops = si->si_boottab;
+ dip = ops->b_devinfo;
+
+ (*ops->b_close)(si);
+
+ if (si->si_dmaaddr) {
+ dvma_free(si->si_dmaaddr, dip->d_dmabytes);
+ si->si_dmaaddr = NULL;
+ }
+
+ promdev_inuse = 0;
+}
+
+struct mapinfo {
+ int maptype;
+ int pgtype;
+ int base;
+};
+
+static struct mapinfo
+prom_mapinfo[] = {
+ { MAP_MAINMEM, PGT_OBMEM, 0 },
+ { MAP_OBIO, PGT_OBIO, 0 },
+ { MAP_MBMEM, PGT_OBMEM, 0 }, /* XXX - Sun2 Multibus? */
+ { MAP_MBIO, PGT_OBIO, 0 }, /* XXX - Sun2 Multibus? */
+ { MAP_VME16A16D, PGT_VME_D16, 0xFFFF0000 },
+ { MAP_VME16A32D, PGT_VME_D32, 0xFFFF0000 },
+ { MAP_VME24A16D, PGT_VME_D16, 0xFF000000 },
+ { MAP_VME24A32D, PGT_VME_D32, 0xFF000000 },
+ { MAP_VME32A16D, PGT_VME_D16, 0 },
+ { MAP_VME32A32D, PGT_VME_D32, 0 },
+};
+static prom_mapinfo_cnt = sizeof(prom_mapinfo) / sizeof(prom_mapinfo[0]);
+
+/* The virtual address we will use for PROM device mappings. */
+static int prom_devmap = MONSHORTSEG;
+
+static char *
+prom_mapin(physaddr, length, maptype)
+ u_long physaddr;
+ int length, maptype;
+{
+ int i, pa, pte, va;
+
+ if (length > (4*NBPG))
+ panic("prom_mapin: length=%d\n", length);
+
+ for (i = 0; i < prom_mapinfo_cnt; i++)
+ if (prom_mapinfo[i].maptype == maptype)
+ goto found;
+ panic("prom_mapin: invalid maptype %d\n", maptype);
+found:
+
+ pte = prom_mapinfo[i].pgtype;
+ pte |= PG_PERM;
+ pa = prom_mapinfo[i].base;
+ pa += physaddr;
+ pte |= PA_PGNUM(pa);
+
+ va = prom_devmap;
+ do {
+ set_pte(va, pte);
+ va += NBPG;
+ pte += 1;
+ length -= NBPG;
+ } while (length > 0);
+ return ((char*)prom_devmap);
+}
diff --git a/sys/arch/mvme68k/stand/libsa/promdev.h b/sys/arch/mvme68k/stand/libsa/promdev.h
new file mode 100644
index 00000000000..e3ae5ba2d7c
--- /dev/null
+++ b/sys/arch/mvme68k/stand/libsa/promdev.h
@@ -0,0 +1,4 @@
+
+int prom_iopen(struct saioreq **sipp);
+void prom_iclose(struct saioreq *sip);
+
diff --git a/sys/arch/mvme68k/stand/netboot/i82586.h b/sys/arch/mvme68k/stand/netboot/i82586.h
new file mode 100644
index 00000000000..ca4a11cdea0
--- /dev/null
+++ b/sys/arch/mvme68k/stand/netboot/i82586.h
@@ -0,0 +1,306 @@
+/* $NetBSD: i82586.h,v 1.3 1995/01/27 09:49:55 pk Exp $ */
+
+/*-
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1992, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * 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 the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * 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 UNIVERSITY OR 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ */
+
+struct ie_en_addr {
+ u_char data[6];
+};
+/*
+ * the only actual IE registers.
+ */
+struct iereg {
+ u_short ie_porthigh;
+ u_short ie_portlow;
+ u_long ie_attention;
+};
+#define IE_PORT_NEWSCP 0x00000002
+#define IE_PORT_RESET 0x00000000
+
+/*
+ * This is the master configuration block. It tells the hardware where
+ * all the rest of the stuff is.
+ */
+struct ie_scp {
+ u_char mbz1[3]; /* must be zero */
+ u_char scp_sysbus; /* true if 8-bit only */
+ u_char mbz2[4]; /* must be zero */
+ u_short scp_iscp_low; /* 24-bit physaddr of ISCP */
+ u_char mbz3[1];
+ u_char scp_iscp_high; /* the rest of the physaddr.. */
+};
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ */
+struct ie_iscp {
+ u_char mbz1[1];
+ u_char iscp_busy; /* zeroed after init */
+ u_short iscp_scboffset; /* 16-bit physaddr of next struct */
+ u_short iscp_base_low; /* 24-bit physaddr for all 16-bit vars */
+ u_char mbz2[1];
+ u_char iscp_base_high; /* rest of physaddr ... */
+};
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ */
+struct ie_scb {
+ u_short ie_status; /* status word */
+ u_short ie_command; /* command word */
+ u_short ie_command_list;/* 16-pointer to command block list */
+ u_short ie_recv_list; /* 16-pointer to receive frame list */
+ u_short ie_err_crc; /* CRC errors */
+ u_short ie_err_align; /* Alignment errors */
+ u_short ie_err_resource;/* Resource errors */
+ u_short ie_err_overrun; /* Overrun errors */
+};
+/* Command values */
+#define IE_RU_COMMAND 0x0070 /* mask for RU command */
+#define IE_RU_NOP 0 /* for completeness */
+#define IE_RU_START 0x0010 /* start receive unit command */
+#define IE_RU_ENABLE 0x0020 /* enable receiver command */
+#define IE_RU_DISABLE 0x0030 /* disable receiver command */
+#define IE_RU_ABORT 0x0040 /* abort current receive operation */
+
+#define IE_CU_COMMAND 0x0700 /* mask for CU command */
+#define IE_CU_NOP 0 /* included for completeness */
+#define IE_CU_START 0x0100 /* do-command command */
+#define IE_CU_RESUME 0x0200 /* resume a suspended cmd list */
+#define IE_CU_STOP 0x0300 /* SUSPEND was already taken */
+#define IE_CU_ABORT 0x0400 /* abort current command */
+
+#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */
+#define IE_ACK_CX 0x8000 /* ack IE_ST_DONE */
+#define IE_ACK_FR 0x4000 /* ack IE_ST_RECV */
+#define IE_ACK_CNA 0x2000 /* ack IE_ST_ALLDONE */
+#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */
+#define IE_ST_DONE 0x8000 /* command with I bit completed */
+#define IE_ST_RECV 0x4000 /* frame received */
+#define IE_ST_ALLDONE 0x2000 /* all commands completed */
+#define IE_ST_RNR 0x1000 /* receive not ready */
+
+#define IE_CU_STATUS 0x700 /* mask for command unit status */
+#define IE_CU_ACTIVE 0x200 /* command unit is active */
+#define IE_CU_SUSPEND 0x100 /* command unit is suspended */
+
+#define IE_RU_STATUS 0x70 /* mask for receiver unit status */
+#define IE_RU_SUSPEND 0x10 /* receiver is suspended */
+#define IE_RU_NOSPACE 0x20 /* receiver has no resources */
+#define IE_RU_READY 0x40 /* receiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ */
+struct ie_recv_frame_desc {
+ u_short ie_fd_status; /* status for this frame */
+ u_short ie_fd_last; /* end of frame list flag */
+ u_short ie_fd_next; /* 16-pointer to next RFD */
+ u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */
+ struct ie_en_addr dest; /* destination ether */
+ struct ie_en_addr src; /* source ether */
+ u_short ie_length; /* 802 length/Ether type */
+ u_short mbz; /* must be zero */
+};
+#define IE_FD_LAST 0x8000 /* last rfd in list */
+#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */
+
+#define IE_FD_COMPLETE 0x8000 /* frame is complete */
+#define IE_FD_BUSY 0x4000 /* frame is busy */
+#define IE_FD_OK 0x2000 /* frame is bad */
+#define IE_FD_RNR 0x0200 /* receiver out of resources here */
+
+/*
+ * linked list of buffers...
+ */
+struct ie_recv_buf_desc {
+ u_short ie_rbd_actual; /* status for this buffer */
+ u_short ie_rbd_next; /* 16-pointer to next RBD */
+ u_short ie_rbd_buffer_low; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_buffer_high; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_length; /* length of the buffer */
+ u_short mbz; /* must be zero */
+};
+#define IE_RBD_LAST 0x8000 /* last buffer */
+#define IE_RBD_USED 0x4000 /* this buffer has data */
+/*
+ * All commands share this in common.
+ */
+struct ie_cmd_common {
+ u_short ie_cmd_status; /* status of this command */
+ u_short ie_cmd_cmd; /* command word */
+ u_short ie_cmd_link; /* link to next command */
+};
+#define IE_STAT_COMPL 0x8000 /* command is completed */
+#define IE_STAT_BUSY 0x4000 /* command is running now */
+#define IE_STAT_OK 0x2000 /* command completed successfully */
+#define IE_STAT_ABORT 0x1000 /* command was aborted */
+
+
+#define IE_CMD_NOP 0x0000 /* NOP */
+#define IE_CMD_IASETUP 0x0001 /* initial address setup */
+#define IE_CMD_CONFIG 0x0002 /* configure command */
+#define IE_CMD_MCAST 0x0003 /* multicast setup command */
+#define IE_CMD_XMIT 0x0004 /* transmit command */
+#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */
+#define IE_CMD_DUMP 0x0006 /* dump command */
+#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */
+
+#define IE_CMD_LAST 0x8000 /* this is the last command in the list */
+#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */
+#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */
+
+/*
+ * This is the command to transmit a frame.
+ */
+struct ie_xmit_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_xmit_status com.ie_cmd_status
+
+ u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */
+ struct ie_en_addr ie_xmit_addr; /* destination address */
+
+ u_short ie_xmit_length; /* 802.3 length/Ether type field */
+};
+#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */
+#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */
+#define IE_XS_SQE 0x0040 /* SQE positive */
+#define IE_XS_DEFERRED 0x0080 /* transmission deferred */
+#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */
+#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */
+#define IE_XS_NOCARRIER 0x0400 /* No Carrier */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ */
+
+struct ie_xmit_buf {
+ u_short ie_xmit_flags; /* see below */
+ u_short ie_xmit_next; /* 16-pointer to next desc. */
+ u_short ie_xmit_buf_low;/* 24-pointer to the actual buffer */
+ u_short ie_xmit_buf_high; /* 24-pointer to the actual buffer */
+};
+#define IE_XMIT_LAST 0x8000 /* this TBD is the last one */
+/* The rest of the `flags' word is actually the length. */
+
+/*
+ * Multicast setup command.
+ */
+
+#define MAXMCAST 250 /* must fit in transmit buffer */
+
+struct ie_mcast_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_mcast_status com.ie_cmd_status
+
+ u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */
+ struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */
+};
+/*
+ * Time Domain Reflectometer command.
+ */
+
+struct ie_tdr_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_tdr_status com.ie_cmd_status
+
+ u_short ie_tdr_time; /* error bits and time */
+};
+#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */
+#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */
+#define IE_TDR_OPEN 0x2000 /* detected an open */
+#define IE_TDR_SHORT 0x1000 /* TDR detected a short */
+#define IE_TDR_TIME 0x07ff /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ */
+struct ie_iasetup_cmd {
+ struct ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+
+ struct ie_en_addr ie_address;
+};
+/*
+ * Configuration command
+ */
+struct ie_config_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_config_status com.ie_cmd_status
+
+ u_char ie_config_count;/* byte count (0x0c) */
+ u_char ie_fifo; /* fifo (8) */
+ u_char ie_save_bad; /* save bad frames (0x40) */
+ u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */
+ u_char ie_priority; /* priority and backoff (0x0) */
+ u_char ie_ifs; /* inter-frame spacing (0x60) */
+ u_char ie_slot_low; /* slot time, LSB (0x0) */
+ u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */
+ u_char ie_promisc; /* 1 if promiscuous, else 0 */
+ u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */
+ u_char ie_min_len; /* min frame length (0x40) */
+ u_char ie_junk; /* stuff for 82596 (0xff) */
+};
+
+struct iemem {
+ volatile struct ie_scp im_scp;
+ u_char xx1[4];
+ volatile struct ie_iscp im_iscp;
+
+ volatile struct ie_scb im_scb;
+ volatile struct ie_config_cmd im_cc;
+ volatile struct ie_iasetup_cmd im_ic;
+ volatile struct ie_recv_frame_desc im_rfd[NRXBUF];
+ volatile struct ie_recv_buf_desc im_rbd[NRXBUF];
+ volatile struct ie_xmit_cmd im_xc[NTXBUF];
+ volatile struct ie_xmit_buf im_xd[NTXBUF];
+ volatile u_char im_rxbuf[NRXBUF * IE_RBUF_SIZE];
+ volatile u_char im_txbuf[NTXBUF * ETHER_MAX_LEN];
+
+};
diff --git a/sys/arch/mvme68k/stand/netboot/if_ie.c b/sys/arch/mvme68k/stand/netboot/if_ie.c
new file mode 100644
index 00000000000..0038a51ff1f
--- /dev/null
+++ b/sys/arch/mvme68k/stand/netboot/if_ie.c
@@ -0,0 +1,495 @@
+/* $NetBSD: le_poll.c,v 1.3 1994/10/26 09:11:48 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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/types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+
+#define NTXBUF 1
+#define NRXBUF 16
+#define IE_RBUF_SIZE ETHER_MAX_LEN
+
+#include "stand.h"
+#include "netif.h"
+#include "config.h"
+
+#include "i82586.h"
+#include "if_iereg.h"
+
+int ie_debug = 0;
+
+void ie_stop __P((struct netif *));
+void ie_end __P((struct netif *));
+void ie_error __P((struct netif *, char *, volatile struct iereg *));
+int ie_get __P((struct iodesc *, void *, int, time_t));
+void ie_init __P((struct iodesc *, void *));
+int ie_match __P((struct netif *, void *));
+int ie_poll __P((struct iodesc *, void *, int));
+int ie_probe __P((struct netif *, void *));
+int ie_put __P((struct iodesc *, void *, int));
+void ie_reset __P((struct netif *, u_char *));
+
+struct netif_stats ie_stats;
+
+struct netif_dif ie0_dif = {
+ 0, /* unit */
+ 1, /* nsel */
+ &ie_stats,
+ 0,
+ 0,
+};
+
+struct netif_driver ie_driver = {
+ "ie", /* netif_bname */
+ ie_match, /* match */
+ ie_probe, /* probe */
+ ie_init, /* init */
+ ie_get, /* get */
+ ie_put, /* put */
+ ie_end, /* end */
+ &ie0_dif, /* netif_ifs */
+ 1, /* netif_nifs */
+};
+
+struct ie_configuration {
+ u_int phys_addr;
+ int used;
+} ie_config[] = {
+ { INTEL_REG_ADDR, 0 }
+};
+
+int nie_config = sizeof(ie_config) / (sizeof(ie_config[0]));
+
+struct {
+ struct iereg *sc_reg; /* IE registers */
+ struct iemem *sc_mem; /* RAM */
+} ie_softc;
+
+int
+ie_match(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ char *name;
+ int i, val = 0;
+ extern int cputyp;
+
+ if (cputyp == CPU_147)
+ return (0);
+ name = machdep_hint;
+ if (name && !bcmp(ie_driver.netif_bname, name, 2))
+ val += 10;
+ for (i = 0; i < nie_config; i++) {
+ if (ie_config[i].used)
+ continue;
+ if (ie_debug)
+ printf("ie%d: ie_match --> %d\n", i, val + 1);
+ ie_config[i].used++;
+ return (val + 1);
+ }
+ if (ie_debug)
+ printf("ie%d: ie_match --> 0\n", i);
+ return (0);
+}
+
+int
+ie_probe(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ extern int cputyp;
+
+ /* the set unit is the current unit */
+ if (ie_debug)
+ printf("ie%d: ie_probe called\n", nif->nif_unit);
+
+ if (cputyp != CPU_147)
+ return (0);
+ return (1);
+}
+
+void
+ie_error(nif, str, ier)
+ struct netif *nif;
+ char *str;
+ volatile struct iereg *ier;
+{
+ panic("ie%d: unknown error\n", nif->nif_unit);
+}
+
+ieack(ier, iem)
+ volatile struct iereg *ier;
+ struct iemem *iem;
+{
+ /* ack the `interrupt' */
+ iem->im_scb.ie_command = iem->im_scb.ie_status & IE_ST_WHENCE;
+ ier->ie_attention = 1; /* chan attention! */
+ while (iem->im_scb.ie_command)
+ ;
+}
+
+void
+ie_reset(nif, myea)
+ struct netif *nif;
+ u_char *myea;
+{
+ volatile struct iereg *ier = ie_softc.sc_reg;
+ struct iemem *iem = ie_softc.sc_mem;
+ int timo = 10000, stat, i;
+ volatile int t;
+ u_int a;
+
+ if (ie_debug)
+ printf("ie%d: ie_reset called\n", nif->nif_unit);
+
+ /*printf("ier %x iem %x\n", ier, iem);*/
+
+ *(u_char *)0xfff4202a = 0x40;
+
+ bzero(iem, sizeof(*iem));
+ iem->im_scp.scp_sysbus = 0;
+ iem->im_scp.scp_iscp_low = (int) &iem->im_iscp & 0xffff;
+ iem->im_scp.scp_iscp_high = (int) &iem->im_iscp >> 16;
+
+ iem->im_iscp.iscp_scboffset = (int) &iem->im_scb - (int) iem;
+ iem->im_iscp.iscp_busy = 1;
+ iem->im_iscp.iscp_base_low = (int) iem & 0xffff;
+ iem->im_iscp.iscp_base_high = (int) iem >> 16;
+
+ /*
+ * completely and utterly unlike what i expected, the
+ * "write" order is:
+ * 1st: d15-d0 -> high address
+ * 2nd: d31-d16 -> low address
+ */
+
+ /* reset chip */
+ a = IE_PORT_RESET;
+ ier->ie_porthigh = a & 0xffff;
+ t = 0;
+ t = 1;
+ ier->ie_portlow = a >> 16;
+ for (t = timo; t--;)
+ ;
+
+ /* set new SCP pointer */
+ a = (int) &iem->im_scp | IE_PORT_NEWSCP;
+ ier->ie_porthigh = a & 0xffff;
+ t = 0;
+ t = 1;
+ ier->ie_portlow = a >> 16;
+ for (t = timo; t--;)
+ ;
+
+ ier->ie_attention = 1; /* chan attention! */
+ for (t = timo * 10; t--;)
+ ;
+
+ /* send CONFIGURE command */
+ iem->im_scb.ie_command = IE_CU_START;
+ iem->im_scb.ie_command_list = (int) &iem->im_cc - (int) iem;
+ iem->im_cc.com.ie_cmd_status = 0;
+ iem->im_cc.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
+ iem->im_cc.com.ie_cmd_link = 0xffff;
+ iem->im_cc.ie_config_count = 0x0c;
+ iem->im_cc.ie_fifo = 8;
+ iem->im_cc.ie_save_bad = 0x40;
+ iem->im_cc.ie_addr_len = 0x2e;
+ iem->im_cc.ie_priority = 0;
+ iem->im_cc.ie_ifs = 0x60;
+ iem->im_cc.ie_slot_low = 0;
+ iem->im_cc.ie_slot_high = 0xf2;
+ iem->im_cc.ie_promisc = 0;
+ iem->im_cc.ie_crs_cdt = 0;
+ iem->im_cc.ie_min_len = 64;
+ iem->im_cc.ie_junk = 0xff;
+
+ ier->ie_attention = 1; /* chan attention! */
+ for (t = timo * 10; t--;)
+ ;
+
+ ieack(ier, iem);
+
+ /*printf("ic %x\n", &iem->im_ic);*/
+ /* send IASETUP command */
+ iem->im_scb.ie_command = IE_CU_START;
+ iem->im_scb.ie_command_list = (int) &iem->im_ic - (int) iem;
+ iem->im_ic.com.ie_cmd_status = 0;
+ iem->im_ic.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
+ iem->im_ic.com.ie_cmd_link = 0xffff;
+ bcopy(myea, &iem->im_ic.ie_address, sizeof iem->im_ic.ie_address);
+
+ ier->ie_attention = 1; /* chan attention! */
+ for (t = timo * 10; t--;)
+ ;
+
+ ieack(ier, iem);
+
+ /* setup buffers */
+
+ for (i = 0; i < NRXBUF; i++) {
+ iem->im_rfd[i].ie_fd_next = (int) &iem->im_rfd[(i+1) % NRXBUF] -
+ (int) iem;
+ iem->im_rbd[i].ie_rbd_next = (int) &iem->im_rbd[(i+1) % NRXBUF] -
+ (int) iem;
+ a = (int) &iem->im_rxbuf[i * IE_RBUF_SIZE];
+ iem->im_rbd[i].ie_rbd_buffer_low = a & 0xffff;
+ iem->im_rbd[i].ie_rbd_buffer_high = a >> 16;
+ iem->im_rbd[i].ie_rbd_length = IE_RBUF_SIZE;
+ }
+ iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST;
+ iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST;
+ iem->im_rfd[0].ie_fd_buf_desc = (int) &iem->im_rbd[0] - (int) iem;
+
+ /*printf("rfd[0] %x rbd[0] %x buf[0] %x\n", &iem->im_rfd, &iem->im_rbd,
+ &iem->im_rxbuf);*/
+
+ /* send receiver start command */
+ iem->im_scb.ie_command = IE_RU_START;
+ iem->im_scb.ie_command_list = 0;
+ iem->im_scb.ie_recv_list = (int) &iem->im_rfd[0] - (int) iem;
+ ier->ie_attention = 1; /* chan attention! */
+ while (iem->im_scb.ie_command)
+ ;
+
+ ieack(ier, iem);
+}
+
+int
+ie_poll(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+{
+ volatile struct iereg *ier = ie_softc.sc_reg;
+ struct iemem *iem = ie_softc.sc_mem;
+ u_char *p = pkt;
+ static int slot;
+ int length = 0;
+ u_int a;
+ u_short status;
+
+ asm(".word 0xf518\n");
+ status = iem->im_rfd[slot].ie_fd_status;
+ if (status & IE_FD_BUSY)
+ return (0);
+
+ /* printf("slot %d: %x\n", slot, status); */
+ if ((status & (IE_FD_COMPLETE | IE_FD_OK)) == (IE_FD_COMPLETE | IE_FD_OK)) {
+ if (status & IE_FD_OK) {
+ length = iem->im_rbd[slot].ie_rbd_actual & 0x3fff;
+ if (length > len)
+ length = len;
+ bcopy(&iem->im_rxbuf[slot * IE_RBUF_SIZE],
+ pkt, length);
+
+ iem->im_rfd[slot].ie_fd_status = 0;
+ iem->im_rfd[slot].ie_fd_last |= IE_FD_LAST;
+ iem->im_rfd[(slot+NRXBUF-1)%NRXBUF].ie_fd_last &=
+ ~IE_FD_LAST;
+ iem->im_rbd[slot].ie_rbd_actual = 0;
+ iem->im_rbd[slot].ie_rbd_length |= IE_RBD_LAST;
+ iem->im_rbd[(slot+NRXBUF-1)%NRXBUF].ie_rbd_length &=
+ ~IE_RBD_LAST;
+ /*printf("S%d\n", slot);*/
+
+ } else {
+ printf("shit\n");
+ }
+ slot++;
+ /* should move descriptor onto end of queue... */
+ }
+ if ((iem->im_scb.ie_status & IE_RU_READY) == 0) {
+ printf("RR\n");
+
+ for (slot = 0; slot < NRXBUF; slot++) {
+ iem->im_rbd[slot].ie_rbd_length &= ~IE_RBD_LAST;
+ iem->im_rfd[slot].ie_fd_last &= ~IE_FD_LAST;
+ }
+ iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST;
+ iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST;
+
+ iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem;
+
+ iem->im_scb.ie_command = IE_RU_START;
+ iem->im_scb.ie_command_list = 0;
+ iem->im_scb.ie_recv_list = (int)&iem->im_rfd[0] - (int)iem;
+ ier->ie_attention = 1; /* chan attention! */
+ while (iem->im_scb.ie_command)
+ ;
+ slot = 0;
+ }
+ slot = slot % NRXBUF;
+ return (length);
+}
+
+int
+ie_put(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+{
+ volatile struct iereg *ier = ie_softc.sc_reg;
+ struct iemem *iem = ie_softc.sc_mem;
+ u_char *p = pkt;
+ int timo = 10000, stat, i;
+ volatile int t;
+ u_int a;
+ int xx = 0;
+
+ /* send transmit command */
+
+ while (iem->im_scb.ie_command)
+ ;
+
+ /* copy data */
+ bcopy(p, &iem->im_txbuf[xx], len);
+
+ len = MAX(len, ETHER_MIN_LEN);
+
+ /* build transmit descriptor */
+ iem->im_xd[xx].ie_xmit_flags = len | IE_XMIT_LAST;
+ iem->im_xd[xx].ie_xmit_next = 0xffff;
+ a = (int) &iem->im_txbuf[xx];
+ iem->im_xd[xx].ie_xmit_buf_low = a & 0xffff;
+ iem->im_xd[xx].ie_xmit_buf_high = a >> 16;
+
+ /* transmit command */
+ iem->im_xc[xx].com.ie_cmd_status = 0;
+ iem->im_xc[xx].com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_LAST;
+ iem->im_xc[xx].com.ie_cmd_link = 0xffff;
+ iem->im_xc[xx].ie_xmit_desc = (int) &iem->im_xd[xx] - (int) iem;
+ iem->im_xc[xx].ie_xmit_length = len;
+ bcopy(p, &iem->im_xc[xx].ie_xmit_addr, sizeof iem->im_xc[xx].ie_xmit_addr);
+
+ iem->im_scb.ie_command = IE_CU_START;
+ iem->im_scb.ie_command_list = (int) &iem->im_xc[xx] - (int) iem;
+
+ ier->ie_attention = 1; /* chan attention! */
+
+ if (ie_debug) {
+ printf("ie%d: send %d to %x:%x:%x:%x:%x:%x\n",
+ desc->io_netif->nif_unit, len,
+ p[0], p[1], p[2], p[3], p[4], p[5]);
+ }
+ return (len);
+}
+
+int
+ie_get(desc, pkt, len, timeout)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+ time_t timeout;
+{
+ time_t t;
+ int cc;
+
+ t = getsecs();
+ cc = 0;
+ while (((getsecs() - t) < timeout) && !cc) {
+ cc = ie_poll(desc, pkt, len);
+ }
+ return (cc);
+}
+/*
+ * init ie device. return 0 on failure, 1 if ok.
+ */
+void
+ie_init(desc, machdep_hint)
+ struct iodesc *desc;
+ void *machdep_hint;
+{
+ struct netif *nif = desc->io_netif;
+
+ if (ie_debug)
+ printf("ie%d: ie_init called\n", desc->io_netif->nif_unit);
+ machdep_common_ether(desc->myea);
+ bzero(&ie_softc, sizeof(ie_softc));
+ ie_softc.sc_reg =
+ (struct iereg *) ie_config[desc->io_netif->nif_unit].phys_addr;
+ ie_softc.sc_mem = (struct iemem *) 0x1e0000;
+ ie_reset(desc->io_netif, desc->myea);
+ printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname,
+ nif->nif_unit, ether_sprintf(desc->myea));
+}
+
+void
+ie_stop(nif)
+ struct netif *nif;
+{
+ volatile struct iereg *ier = ie_softc.sc_reg;
+ struct iemem *iem = ie_softc.sc_mem;
+ int timo = 10000;
+ volatile int t;
+ u_int a;
+
+ iem->im_iscp.iscp_busy = 1;
+ /* reset chip */
+ a = IE_PORT_RESET;
+ ier->ie_porthigh = a & 0xffff;
+ t = 0;
+ t = 1;
+ ier->ie_portlow = a >> 16;
+ for (t = timo; t--;)
+ ;
+
+ /* reset chip again */
+ a = IE_PORT_RESET;
+ ier->ie_porthigh = a & 0xffff;
+ t = 0;
+ t = 1;
+ ier->ie_portlow = a >> 16;
+ for (t = timo; t--;)
+ ;
+
+ /*printf("status %x busy %x\n", iem->im_scb.ie_status,
+ iem->im_iscp.iscp_busy);*/
+}
+
+void
+ie_end(nif)
+ struct netif *nif;
+{
+ if (ie_debug)
+ printf("ie%d: ie_end called\n", nif->nif_unit);
+
+ ie_stop(nif);
+
+ /* *(u_char *) 0xfff42002 = 0; */
+}
diff --git a/sys/arch/mvme68k/stand/netboot/if_iereg.h b/sys/arch/mvme68k/stand/netboot/if_iereg.h
new file mode 100644
index 00000000000..73d3d47e127
--- /dev/null
+++ b/sys/arch/mvme68k/stand/netboot/if_iereg.h
@@ -0,0 +1,163 @@
+/* $NetBSD: if_ie.h,v 1.4 1994/12/16 22:01:11 deraadt Exp $ */
+
+/*
+ * if_sunie.h
+ *
+ * sun's ie interface
+ */
+
+/*
+ * programming notes:
+ *
+ * the ie chip operates in a 24 bit address space.
+ *
+ * most ie interfaces appear to be divided into two parts:
+ * - generic 586 stuff
+ * - board specific
+ *
+ * generic:
+ * the generic stuff of the ie chip is all done with data structures
+ * that live in the chip's memory address space. the chip expects
+ * its main data structure (the sys conf ptr -- SCP) to be at a fixed
+ * address in its 24 bit space: 0xfffff4
+ *
+ * the SCP points to another structure called the ISCP.
+ * the ISCP points to another structure called the SCB.
+ * the SCB has a status field, a linked list of "commands", and
+ * a linked list of "receive buffers". these are data structures that
+ * live in memory, not registers.
+ *
+ * board:
+ * to get the chip to do anything, you first put a command in the
+ * command data structure list. then you have to signal "attention"
+ * to the chip to get it to look at the command. how you
+ * signal attention depends on what board you have... on PC's
+ * there is an i/o port number to do this, on sun's there is a
+ * register bit you toggle.
+ *
+ * to get data from the chip you program it to interrupt...
+ *
+ *
+ * sun issues:
+ *
+ * there are 3 kinds of sun "ie" interfaces:
+ * 1 - a VME/multibus card
+ * 2 - an on-board interface (sun3's, sun-4/100's, and sun-4/200's)
+ * 3 - another VME board called the 3E
+ *
+ * the VME boards lives in vme16 space. only 16 and 8 bit accesses
+ * are allowed, so functions that copy data must be aware of this.
+ *
+ * the chip is an intel chip. this means that the byte order
+ * on all the "short"s in the chip's data structures is wrong.
+ * so, constants described in the intel docs are swapped for the sun.
+ * that means that any buffer pointers you give the chip must be
+ * swapped to intel format. yuck.
+ *
+ * VME/multibus interface:
+ * for the multibus interface the board ignores the top 4 bits
+ * of the chip address. the multibus interface seems to have its
+ * own MMU like page map (without protections or valid bits, etc).
+ * there are 256 pages of physical memory on the board (each page
+ * is 1024 bytes). there are 1024 slots in the page map. so,
+ * a 1024 byte page takes up 10 bits of address for the offset,
+ * and if there are 1024 slots in the page that is another 10 bits
+ * of the address. that makes a 20 bit address, and as stated
+ * earlier the board ignores the top 4 bits, so that accounts
+ * for all 24 bits of address.
+ *
+ * note that the last entry of the page map maps the top of the
+ * 24 bit address space and that the SCP is supposed to be at
+ * 0xfffff4 (taking into account allignment). so,
+ * for multibus, that entry in the page map has to be used for the SCP.
+ *
+ * the page map effects BOTH how the ie chip sees the
+ * memory, and how the host sees it.
+ *
+ * the page map is part of the "register" area of the board
+ *
+ * on-board interface:
+ *
+ * <fill in useful info later>
+ *
+ *
+ * VME3E interface:
+ *
+ * <fill in useful info later>
+ *
+ */
+
+/*
+ * PART 1: VME/multibus defs
+ */
+#define IEVME_PAGESIZE 1024 /* bytes */
+#define IEVME_PAGSHIFT 10 /* bits */
+#define IEVME_NPAGES 256 /* number of pages on chip */
+#define IEVME_MAPSZ 1024 /* number of entries in the map */
+
+/*
+ * PTE for the page map
+ */
+#define IEVME_SBORDR 0x8000 /* sun byte order */
+#define IEVME_IBORDR 0x0000 /* intel byte ordr */
+
+#define IEVME_P2MEM 0x2000 /* memory is on P2 */
+#define IEVME_OBMEM 0x0000 /* memory is on board */
+
+#define IEVME_PGMASK 0x0fff /* gives the physical page frame number */
+
+struct ievme {
+ u_short pgmap[IEVME_MAPSZ];
+ u_short xxx[32]; /* prom */
+ u_short status; /* see below for bits */
+ u_short xxx2; /* filler */
+ u_short pectrl; /* parity control (see below) */
+ u_short peaddr; /* low 16 bits of address */
+};
+/*
+ * status bits
+ */
+#define IEVME_RESET 0x8000 /* reset board */
+#define IEVME_ONAIR 0x4000 /* go out of loopback 'on-air' */
+#define IEVME_ATTEN 0x2000 /* attention */
+#define IEVME_IENAB 0x1000 /* interrupt enable */
+#define IEVME_PEINT 0x0800 /* parity error interrupt enable */
+#define IEVME_PERR 0x0200 /* parity error flag */
+#define IEVME_INT 0x0100 /* interrupt flag */
+#define IEVME_P2EN 0x0020 /* enable p2 bus */
+#define IEVME_256K 0x0010 /* 256kb rams */
+#define IEVME_HADDR 0x000f /* mask for bits 17-20 of address */
+
+/*
+ * parity control
+ */
+#define IEVME_PARACK 0x0100 /* parity error ack */
+#define IEVME_PARSRC 0x0080 /* parity error source */
+#define IEVME_PAREND 0x0040 /* which end of the data got the error */
+#define IEVME_PARADR 0x000f /* mask to get bits 17-20 of parity address */
+
+
+/*
+ * PART 2: the on-board interface
+ */
+struct ieob {
+ u_char obctrl;
+};
+#define IEOB_NORSET 0x80 /* don't reset the board */
+#define IEOB_ONAIR 0x40 /* put us on the air */
+#define IEOB_ATTEN 0x20 /* attention! */
+#define IEOB_IENAB 0x10 /* interrupt enable */
+#define IEOB_XXXXX 0x08 /* free bit */
+#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */
+#define IEOB_BUSERR 0x02 /* bus error */
+#define IEOB_INT 0x01 /* interrupt */
+
+#define IEOB_ADBASE 0xff000000 /* KVA base addr of 24 bit address space */
+
+/*
+ * PART 3: the 3E board
+ */
+
+/*
+ * not supported (yet?)
+ */
diff --git a/sys/arch/mvme68k/stand/netboot/if_le.c b/sys/arch/mvme68k/stand/netboot/if_le.c
new file mode 100644
index 00000000000..8049b69b9e0
--- /dev/null
+++ b/sys/arch/mvme68k/stand/netboot/if_le.c
@@ -0,0 +1,431 @@
+/* $NetBSD: le_poll.c,v 1.3 1994/10/26 09:11:48 cgd Exp $ */
+
+/*
+ * Copyright (c) 1993 Adam Glass
+ * 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 Adam Glass.
+ * 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 Adam Glass ``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.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include "stand.h"
+#include "netif.h"
+#include "config.h"
+
+#include "if_lereg.h"
+
+int le_debug = 0;
+
+void le_end __P((struct netif *));
+void le_error __P((struct netif *, char *, volatile struct lereg1 *));
+int le_get __P((struct iodesc *, void *, int, time_t));
+void le_init __P((struct iodesc *, void *));
+int le_match __P((struct netif *, void *));
+int le_poll __P((struct iodesc *, void *, int));
+int le_probe __P((struct netif *, void *));
+int le_put __P((struct iodesc *, void *, int));
+void le_reset __P((struct netif *, u_char *));
+
+struct netif_stats le_stats;
+
+struct netif_dif le0_dif = {
+ 0, /* unit */
+ 1, /* nsel */
+ &le_stats,
+ 0,
+ 0,
+};
+
+struct netif_driver le_driver = {
+ "le", /* netif_bname */
+ le_match, /* match */
+ le_probe, /* probe */
+ le_init, /* init */
+ le_get, /* get */
+ le_put, /* put */
+ le_end, /* end */
+ &le0_dif, /* netif_ifs */
+ 1, /* netif_nifs */
+};
+
+struct le_configuration {
+ unsigned int phys_addr;
+ int used;
+} le_config[] = {
+ { LANCE_REG_ADDR, 0 }
+};
+
+int nle_config = sizeof(le_config) / (sizeof(le_config[0]));
+
+struct {
+ struct lereg1 *sc_r1; /* LANCE registers */
+ struct lereg2 *sc_r2; /* RAM */
+ int next_rmd;
+ int next_tmd;
+} le_softc;
+
+int
+le_match(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ char *name;
+ int i, val = 0;
+ extern int cputyp;
+
+ if (cputyp != CPU_147)
+ return (0);
+ name = machdep_hint;
+ if (name && !bcmp(le_driver.netif_bname, name, 2))
+ val += 10;
+ for (i = 0; i < nle_config; i++) {
+ if (le_config[i].used)
+ continue;
+ if (le_debug)
+ printf("le%d: le_match --> %d\n", i, val + 1);
+ le_config[i].used++;
+ return val + 1;
+ }
+ if (le_debug)
+ printf("le%d: le_match --> 0\n", i);
+ return 0;
+}
+
+int
+le_probe(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ extern int cputyp;
+
+ /* the set unit is the current unit */
+ if (le_debug)
+ printf("le%d: le_probe called\n", nif->nif_unit);
+
+ if (cputyp == CPU_147)
+ return 0;
+ return 1;
+}
+
+void
+le_error(nif, str, ler1)
+ struct netif *nif;
+ char *str;
+ volatile struct lereg1 *ler1;
+{
+ /* ler1->ler1_rap = LE_CSRO done in caller */
+ if (ler1->ler1_rdp & LE_C0_BABL)
+ panic("le%d: been babbling, found by '%s'\n", nif->nif_unit, str);
+ if (ler1->ler1_rdp & LE_C0_CERR) {
+ le_stats.collision_error++;
+ ler1->ler1_rdp = LE_C0_CERR;
+ }
+ if (ler1->ler1_rdp & LE_C0_MISS) {
+ le_stats.missed++;
+ ler1->ler1_rdp = LE_C0_MISS;
+ }
+ if (ler1->ler1_rdp & LE_C0_MERR) {
+ printf("le%d: memory error in '%s'\n", nif->nif_unit, str);
+ panic("memory error");
+ }
+}
+
+void
+le_reset(nif, myea)
+ struct netif *nif;
+ u_char *myea;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+ struct lereg2 *ler2 = le_softc.sc_r2;
+ unsigned int a;
+ int timo = 100000, stat, i;
+
+ if (le_debug)
+ printf("le%d: le_reset called\n", nif->nif_unit);
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */
+
+ bzero(ler2, sizeof(*ler2));
+
+ ler2->ler2_mode = LE_MODE_NORMAL;
+ ler2->ler2_padr[0] = myea[1];
+ ler2->ler2_padr[1] = myea[0];
+ ler2->ler2_padr[2] = myea[3];
+ ler2->ler2_padr[3] = myea[2];
+ ler2->ler2_padr[4] = myea[5];
+ ler2->ler2_padr[5] = myea[4];
+
+
+ ler2->ler2_ladrf0 = 0;
+ ler2->ler2_ladrf1 = 0;
+
+ a = (u_int) ler2->ler2_rmd;
+ ler2->ler2_rlen = LE_RLEN | (a >> 16);
+ ler2->ler2_rdra = a & LE_ADDR_LOW_MASK;
+
+ a = (u_int) ler2->ler2_tmd;
+ ler2->ler2_tlen = LE_TLEN | (a >> 16);
+ ler2->ler2_tdra = a & LE_ADDR_LOW_MASK;
+
+ ler1->ler1_rap = LE_CSR1;
+ a = (u_int) ler2;
+ ler1->ler1_rdp = a & LE_ADDR_LOW_MASK;
+ ler1->ler1_rap = LE_CSR2;
+ ler1->ler1_rdp = a >> 16;
+
+ for (i = 0; i < LERBUF; i++) {
+ a = (u_int) & ler2->ler2_rbuf[i];
+ ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK;
+ ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN;
+ ler2->ler2_rmd[i].rmd1_hadr = a >> 16;
+ ler2->ler2_rmd[i].rmd2 = -LEMTU;
+ ler2->ler2_rmd[i].rmd3 = 0;
+ }
+ for (i = 0; i < LETBUF; i++) {
+ a = (u_int) & ler2->ler2_tbuf[i];
+ ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK;
+ ler2->ler2_tmd[i].tmd1_bits = 0;
+ ler2->ler2_tmd[i].tmd1_hadr = a >> 16;
+ ler2->ler2_tmd[i].tmd2 = 0;
+ ler2->ler2_tmd[i].tmd3 = 0;
+ }
+
+ ler1->ler1_rap = LE_CSR3;
+ ler1->ler1_rdp = LE_C3_BSWP;
+
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_INIT;
+ do {
+ if (--timo == 0) {
+ printf("le%d: init timeout, stat = 0x%x\n",
+ nif->nif_unit, stat);
+ break;
+ }
+ stat = ler1->ler1_rdp;
+ } while ((stat & LE_C0_IDON) == 0);
+
+ ler1->ler1_rdp = LE_C0_IDON;
+ le_softc.next_rmd = 0;
+ le_softc.next_tmd = 0;
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STRT;
+}
+
+int
+le_poll(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+ struct lereg2 *ler2 = le_softc.sc_r2;
+ unsigned int a;
+ int length;
+ struct lermd *rmd;
+
+
+ ler1->ler1_rap = LE_CSR0;
+ if ((ler1->ler1_rdp & LE_C0_RINT) != 0)
+ ler1->ler1_rdp = LE_C0_RINT;
+ rmd = &ler2->ler2_rmd[le_softc.next_rmd];
+ if (rmd->rmd1_bits & LE_R1_OWN) {
+ return (0);
+ }
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_poll", ler1);
+ if (rmd->rmd1_bits & LE_R1_ERR) {
+ printf("le%d_poll: rmd status 0x%x\n", desc->io_netif->nif_unit,
+ rmd->rmd1_bits);
+ length = 0;
+ goto cleanup;
+ }
+ if ((rmd->rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != (LE_R1_STP | LE_R1_ENP))
+ panic("le_poll: chained packet\n");
+
+ length = rmd->rmd3;
+ if (length >= LEMTU) {
+ length = 0;
+ panic("csr0 when bad things happen: %x\n", ler1->ler1_rdp);
+ goto cleanup;
+ }
+ if (!length)
+ goto cleanup;
+ length -= 4;
+ if (length > 0) {
+
+ /*
+ * if buffer is smaller than the packet truncate it.
+ * (is this wise?)
+ */
+ if (length > len)
+ length = len;
+
+ bcopy(&ler2->ler2_rbuf[le_softc.next_rmd], pkt, length);
+ }
+cleanup:
+ a = (u_int) & ler2->ler2_rbuf[le_softc.next_rmd];
+ rmd->rmd0 = a & LE_ADDR_LOW_MASK;
+ rmd->rmd1_hadr = a >> 16;
+ rmd->rmd2 = -LEMTU;
+ le_softc.next_rmd =
+ (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1);
+ rmd->rmd1_bits = LE_R1_OWN;
+ return length;
+}
+
+int
+le_put(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+{
+ volatile struct lereg1 *ler1 = le_softc.sc_r1;
+ volatile struct lereg2 *ler2 = le_softc.sc_r2;
+ volatile struct letmd *tmd;
+ int timo = 100000, stat, i;
+ unsigned int a;
+
+ ler1->ler1_rap = LE_CSR0;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(way before xmit)", ler1);
+ tmd = &ler2->ler2_tmd[le_softc.next_tmd];
+ while (tmd->tmd1_bits & LE_T1_OWN) {
+ printf("le%d: output buffer busy\n", desc->io_netif->nif_unit);
+ }
+ bcopy(pkt, ler2->ler2_tbuf[le_softc.next_tmd], len);
+ if (len < 64)
+ tmd->tmd2 = -64;
+ else
+ tmd->tmd2 = -len;
+ tmd->tmd3 = 0;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(before xmit)", ler1);
+ tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN;
+ a = (u_int) & ler2->ler2_tbuf[le_softc.next_tmd];
+ tmd->tmd0 = a & LE_ADDR_LOW_MASK;
+ tmd->tmd1_hadr = a >> 16;
+ ler1->ler1_rdp = LE_C0_TDMD;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(after xmit)", ler1);
+ do {
+ if (--timo == 0) {
+ printf("le%d: transmit timeout, stat = 0x%x\n",
+ desc->io_netif->nif_unit, stat);
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(timeout)", ler1);
+ break;
+ }
+ stat = ler1->ler1_rdp;
+ } while ((stat & LE_C0_TINT) == 0);
+ ler1->ler1_rdp = LE_C0_TINT;
+ if (ler1->ler1_rdp & LE_C0_ERR) {
+ if ((ler1->ler1_rdp & (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS |
+ LE_C0_MERR)) !=
+ LE_C0_CERR)
+ printf("le_put: xmit error, buf %d\n", le_softc.next_tmd);
+ le_error(desc->io_netif, "le_put(xmit error)", ler1);
+ }
+ le_softc.next_tmd = 0;
+/* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/
+ if (tmd->tmd1_bits & LE_T1_DEF)
+ le_stats.deferred++;
+ if (tmd->tmd1_bits & LE_T1_ONE)
+ le_stats.collisions++;
+ if (tmd->tmd1_bits & LE_T1_MORE)
+ le_stats.collisions += 2;
+ if (tmd->tmd1_bits & LE_T1_ERR) {
+ printf("le%d: transmit error, error = 0x%x\n", desc->io_netif->nif_unit,
+ tmd->tmd3);
+ return -1;
+ }
+ if (le_debug) {
+ printf("le%d: le_put() successful: sent %d\n",
+ desc->io_netif->nif_unit, len);
+ printf("le%d: le_put(): tmd1_bits: %x tmd3: %x\n",
+ desc->io_netif->nif_unit,
+ (unsigned int) tmd->tmd1_bits,
+ (unsigned int) tmd->tmd3);
+ }
+ return len;
+}
+
+int
+le_get(desc, pkt, len, timeout)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+ time_t timeout;
+{
+ time_t t;
+ int cc;
+
+ t = getsecs();
+ cc = 0;
+ while (((getsecs() - t) < timeout) && !cc) {
+ cc = le_poll(desc, pkt, len);
+ }
+ return cc;
+}
+/*
+ * init le device. return 0 on failure, 1 if ok.
+ */
+void
+le_init(desc, machdep_hint)
+ struct iodesc *desc;
+ void *machdep_hint;
+{
+ u_long eram = 4*1024*1024;
+ struct netif *nif = desc->io_netif;
+
+ if (le_debug)
+ printf("le%d: le_init called\n", desc->io_netif->nif_unit);
+ machdep_common_ether(desc->myea);
+ bzero(&le_softc, sizeof(le_softc));
+ le_softc.sc_r1 =
+ (struct lereg1 *) le_config[desc->io_netif->nif_unit].phys_addr;
+ le_softc.sc_r2 = (struct lereg2 *) (eram - (1024 * 1024));
+ le_reset(desc->io_netif, desc->myea);
+ printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname,
+ nif->nif_unit, ether_sprintf(desc->myea));
+}
+
+void
+le_end(nif)
+ struct netif *nif;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+
+ if (le_debug)
+ printf("le%d: le_end called\n", nif->nif_unit);
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STOP;
+}
diff --git a/sys/arch/mvme68k/stand/netboot/if_lereg.h b/sys/arch/mvme68k/stand/netboot/if_lereg.h
new file mode 100644
index 00000000000..215ec305fb1
--- /dev/null
+++ b/sys/arch/mvme68k/stand/netboot/if_lereg.h
@@ -0,0 +1,173 @@
+/* $NetBSD: if_lereg.h,v 1.4 1994/11/20 20:52:22 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1982, 1992, 1993
+ * The Regents of the University of California. 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 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.
+ *
+ * @(#)if_lereg.h 8.2 (Berkeley) 10/30/93
+ */
+
+#define LEMTU 1518
+#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */
+#define LERBUF 8
+#define LERBUFLOG2 3
+#define LE_RLEN (LERBUFLOG2 << 13)
+#define LETBUF 1
+#define LETBUFLOG2 0
+#define LE_TLEN (LETBUFLOG2 << 13)
+
+/* Local Area Network Controller for Ethernet (LANCE) registers */
+struct lereg1 {
+ volatile u_short ler1_rdp; /* register data port */
+ volatile u_short ler1_rap; /* register address port */
+};
+/* register addresses */
+#define LE_CSR0 0 /* Control and status register */
+#define LE_CSR1 1 /* low address of init block */
+#define LE_CSR2 2 /* high address of init block */
+#define LE_CSR3 3 /* Bus master and control */
+
+/* Control and status register 0 (csr0) */
+#define LE_C0_ERR 0x8000 /* error summary */
+#define LE_C0_BABL 0x4000 /* transmitter timeout error */
+#define LE_C0_CERR 0x2000 /* collision */
+#define LE_C0_MISS 0x1000 /* missed a packet */
+#define LE_C0_MERR 0x0800 /* memory error */
+#define LE_C0_RINT 0x0400 /* receiver interrupt */
+#define LE_C0_TINT 0x0200 /* transmitter interrupt */
+#define LE_C0_IDON 0x0100 /* initalization done */
+#define LE_C0_INTR 0x0080 /* interrupt condition */
+#define LE_C0_INEA 0x0040 /* interrupt enable */
+#define LE_C0_RXON 0x0020 /* receiver on */
+#define LE_C0_TXON 0x0010 /* transmitter on */
+#define LE_C0_TDMD 0x0008 /* transmit demand */
+#define LE_C0_STOP 0x0004 /* disable all external activity */
+#define LE_C0_STRT 0x0002 /* enable external activity */
+#define LE_C0_INIT 0x0001 /* begin initalization */
+
+#define LE_C0_BITS \
+ "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\
+\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"
+
+/* Control and status register 3 (csr3) */
+#define LE_C3_BSWP 0x4 /* byte swap */
+#define LE_C3_ACON 0x2 /* ALE control, eh? */
+#define LE_C3_BCON 0x1 /* byte control */
+/*
+ * Current size is 13,758 bytes with 8 x 1518 receive buffers and
+ * 1 x 1518 transmit buffer.
+ */
+struct lereg2 {
+ /* initialization block */
+ volatile u_short ler2_mode; /* mode */
+ volatile u_char ler2_padr[6]; /* physical address */
+#ifdef new_code
+ volatile u_short ler2_ladrf[4]; /* logical address filter */
+#else
+ volatile u_long ler2_ladrf0; /* logical address filter */
+ volatile u_long ler2_ladrf1; /* logical address filter */
+#endif
+ volatile u_short ler2_rdra; /* receive descriptor addr */
+ volatile u_short ler2_rlen; /* rda high and ring size */
+ volatile u_short ler2_tdra; /* transmit descriptor addr */
+ volatile u_short ler2_tlen; /* tda high and ring size */
+ /* receive message descriptors. bits/hadr are byte order dependent. */
+ struct lermd {
+ volatile u_short rmd0; /* low address of packet */
+ volatile u_char rmd1_bits; /* descriptor bits */
+ volatile u_char rmd1_hadr; /* high address of packet */
+ volatile short rmd2; /* buffer byte count */
+ volatile u_short rmd3; /* message byte count */
+ } ler2_rmd[LERBUF];
+ /* transmit message descriptors */
+ struct letmd {
+ volatile u_short tmd0; /* low address of packet */
+ volatile u_char tmd1_bits; /* descriptor bits */
+ volatile u_char tmd1_hadr; /* high address of packet */
+ volatile short tmd2; /* buffer byte count */
+ volatile u_short tmd3; /* transmit error bits */
+ } ler2_tmd[LETBUF];
+ volatile char ler2_rbuf[LERBUF][LEMTU];
+ volatile char ler2_tbuf[LETBUF][LEMTU];
+};
+/* Initialzation block (mode) */
+#define LE_MODE_PROM 0x8000 /* promiscuous mode */
+/* 0x7f80 reserved, must be zero */
+#define LE_MODE_INTL 0x0040 /* internal loopback */
+#define LE_MODE_DRTY 0x0020 /* disable retry */
+#define LE_MODE_COLL 0x0010 /* force a collision */
+#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */
+#define LE_MODE_LOOP 0x0004 /* loopback mode */
+#define LE_MODE_DTX 0x0002 /* disable transmitter */
+#define LE_MODE_DRX 0x0001 /* disable receiver */
+#define LE_MODE_NORMAL 0 /* none of the above */
+
+
+/* Receive message descriptor 1 (rmd1_bits) */
+#define LE_R1_OWN 0x80 /* LANCE owns the packet */
+#define LE_R1_ERR 0x40 /* error summary */
+#define LE_R1_FRAM 0x20 /* framing error */
+#define LE_R1_OFLO 0x10 /* overflow error */
+#define LE_R1_CRC 0x08 /* CRC error */
+#define LE_R1_BUFF 0x04 /* buffer error */
+#define LE_R1_STP 0x02 /* start of packet */
+#define LE_R1_ENP 0x01 /* end of packet */
+
+#define LE_R1_BITS \
+ "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP"
+
+/* Transmit message descriptor 1 (tmd1_bits) */
+#define LE_T1_OWN 0x80 /* LANCE owns the packet */
+#define LE_T1_ERR 0x40 /* error summary */
+#define LE_T1_MORE 0x10 /* multiple collisions */
+#define LE_T1_ONE 0x08 /* single collision */
+#define LE_T1_DEF 0x04 /* defferred transmit */
+#define LE_T1_STP 0x02 /* start of packet */
+#define LE_T1_ENP 0x01 /* end of packet */
+
+#define LE_T1_BITS \
+ "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP"
+
+/* Transmit message descriptor 3 (tmd3) */
+#define LE_T3_BUFF 0x8000 /* buffer error */
+#define LE_T3_UFLO 0x4000 /* underflow error */
+#define LE_T3_LCOL 0x1000 /* late collision */
+#define LE_T3_LCAR 0x0800 /* loss of carrier */
+#define LE_T3_RTRY 0x0400 /* retry error */
+#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */
+
+#define LE_XMD2_ONES 0xf000
+
+#define LE_T3_BITS \
+ "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"
+
+
+#define LE_ADDR_LOW_MASK (0xffff)
diff --git a/sys/arch/mvme68k/stand/prtvid/Makefile b/sys/arch/mvme68k/stand/prtvid/Makefile
new file mode 100644
index 00000000000..f6a6d3e1e1a
--- /dev/null
+++ b/sys/arch/mvme68k/stand/prtvid/Makefile
@@ -0,0 +1,6 @@
+PROG= prtvid
+NOMAN=
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/mvme68k/stand/prtvid/prtvid.c b/sys/arch/mvme68k/stand/prtvid/prtvid.c
new file mode 100644
index 00000000000..32784ff0dfa
--- /dev/null
+++ b/sys/arch/mvme68k/stand/prtvid/prtvid.c
@@ -0,0 +1,132 @@
+#include <stdio.h>
+#define __DBINTERFACE_PRIVATE
+#include <db.h>
+#include "vid.h"
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct vid *pvid;
+ struct cfg *pcfg;
+
+ pvid = (struct vid *) malloc(sizeof (struct vid));
+
+ fread(pvid, sizeof(struct vid), 1, stdin);
+
+ if (BYTE_ORDER != BIG_ENDIAN)
+ swabvid(pvid);
+
+ printf("vid_id %s %x\n", pvid->vid_id,
+ (char *)&(pvid->vid_id[4]) - (char *)pvid);
+ printf("vid_oss %x %x\n", pvid->vid_oss,
+ (char *)&(pvid->vid_oss) - (char *)pvid);
+ printf("vid_osl %x %x\n", pvid->vid_osl,
+ (char *)&(pvid->vid_osl) - (char *)pvid);
+ printf("vid_osa_u %x %x\n", pvid->vid_osa_u,
+ (char *)&(pvid->vid_osa_u) - (char *)pvid);
+ printf("vid_osa_l %x %x\n", pvid->vid_osa_l,
+ (char *)&(pvid->vid_osa_l) - (char *)pvid);
+ printf("vid_vd %x\n",
+ (char *)&(pvid->vid_vd) - (char *)pvid);
+ printf("vid_cas %x %x\n", pvid->vid_cas,
+ (char *)&(pvid->vid_cas) - (char *)pvid);
+ printf("vid_cal %x %x\n", pvid->vid_cal,
+ (char *)&(pvid->vid_cal) - (char *)pvid);
+ printf("vid_moto %s %x\n", pvid->vid_mot,
+ (char *)&(pvid->vid_mot[0]) - (char *)pvid);
+
+ free(pvid);
+
+ pcfg = (struct cfg *) malloc(sizeof(struct cfg));
+
+ fread(pcfg, sizeof(struct cfg), 1, stdin);
+
+ if (BYTE_ORDER != BIG_ENDIAN)
+ swabcfg(pcfg);
+
+ printf("cfg_atm %x %x\n", pcfg->cfg_atm,
+ (char *)&(pcfg->cfg_atm) - (char *)(pcfg));
+ printf("cfg_prm %x %x\n", pcfg->cfg_prm,
+ (char *)&(pcfg->cfg_prm) - (char *)(pcfg));
+ printf("cfg_atw %x %x\n", pcfg->cfg_atw,
+ (char *)&(pcfg->cfg_atw) - (char *)(pcfg));
+ printf("cfg_rec %x %x\n",(long)pcfg->cfg_rec,
+ (char *)&(pcfg->cfg_rec) - (char *)(pcfg));
+ printf("cfg_spt %x %x\n", pcfg->cfg_spt,
+ (char *)&(pcfg->cfg_spt) - (char *)(pcfg));
+ printf("cfg_hds %x %x\n", pcfg->cfg_hds,
+ (char *)&(pcfg->cfg_hds) - (char *)(pcfg));
+ printf("cfg_trk %x %x\n", pcfg->cfg_trk,
+ (char *)&(pcfg->cfg_trk) - (char *)(pcfg));
+ printf("cfg_ilv %x %x\n", pcfg->cfg_ilv,
+ (char *)&(pcfg->cfg_ilv) - (char *)(pcfg));
+ printf("cfg_sof %x %x\n", pcfg->cfg_sof,
+ (char *)&(pcfg->cfg_sof) - (char *)(pcfg));
+ printf("cfg_psm %x %x\n", pcfg->cfg_psm,
+ (char *)&(pcfg->cfg_psm) - (char *)(pcfg));
+ printf("cfg_shd %x %x\n", pcfg->cfg_shd,
+ (char *)&(pcfg->cfg_shd) - (char *)(pcfg));
+ printf("cfg_pcom %x %x\n", pcfg->cfg_pcom,
+ (char *)&(pcfg->cfg_pcom) - (char *)(pcfg));
+ printf("cfg_ssr %x %x\n", pcfg->cfg_ssr,
+ (char *)&(pcfg->cfg_ssr) - (char *)(pcfg));
+ printf("cfg_rwcc %x %x\n", pcfg->cfg_rwcc,
+ (char *)&(pcfg->cfg_rwcc) - (char *)(pcfg));
+ printf("cfg_ecc %x %x\n", pcfg->cfg_ecc,
+ (char *)&(pcfg->cfg_ecc) - (char *)(pcfg));
+ printf("cfg_eatm %x %x\n", pcfg->cfg_eatm,
+ (char *)&(pcfg->cfg_eatm) - (char *)(pcfg));
+ printf("cfg_eprm %x %x\n", pcfg->cfg_eprm,
+ (char *)&(pcfg->cfg_eprm) - (char *)(pcfg));
+ printf("cfg_eatw %x %x\n", pcfg->cfg_eatw,
+ (char *)&(pcfg->cfg_eatw) - (char *)(pcfg));
+ printf("cfg_gpb1 %x %x\n", pcfg->cfg_gpb1,
+ (char *)&(pcfg->cfg_gpb1) - (char *)(pcfg));
+ printf("cfg_gpb2 %x %x\n", pcfg->cfg_gpb2,
+ (char *)&(pcfg->cfg_gpb2) - (char *)(pcfg));
+ printf("cfg_gpb3 %x %x\n", pcfg->cfg_gpb3,
+ (char *)&(pcfg->cfg_gpb3) - (char *)(pcfg));
+ printf("cfg_gpb4 %x %x\n", pcfg->cfg_gpb4,
+ (char *)&(pcfg->cfg_gpb4) - (char *)(pcfg));
+ printf("cfg_ssc %x %x\n", pcfg->cfg_ssc,
+ (char *)&(pcfg->cfg_ssc) - (char *)(pcfg));
+ printf("cfg_runit %x %x\n", pcfg->cfg_runit,
+ (char *)&(pcfg->cfg_runit) - (char *)(pcfg));
+ printf("cfg_rsvc1 %x %x\n", pcfg->cfg_rsvc1,
+ (char *)&(pcfg->cfg_rsvc1) - (char *)(pcfg));
+ printf("cfg_rsvc2 %x %x\n", pcfg->cfg_rsvc2,
+ (char *)&(pcfg->cfg_rsvc2) - (char *)(pcfg));
+}
+
+swabvid(pvid)
+ struct vid *pvid;
+{
+ M_32_SWAP(pvid->vid_oss);
+ M_16_SWAP(pvid->vid_osl);
+ M_16_SWAP(pvid->vid_osa_u);
+ M_16_SWAP(pvid->vid_osa_l);
+ M_32_SWAP(pvid->vid_cas);
+}
+
+swabcfg(pcfg)
+ struct cfg *pcfg;
+{
+ printf("swapping cfg\n");
+
+ M_16_SWAP(pcfg->cfg_atm);
+ M_16_SWAP(pcfg->cfg_prm);
+ M_16_SWAP(pcfg->cfg_atm);
+ M_16_SWAP(pcfg->cfg_rec);
+ M_16_SWAP(pcfg->cfg_trk);
+ M_16_SWAP(pcfg->cfg_psm);
+ M_16_SWAP(pcfg->cfg_shd);
+ M_16_SWAP(pcfg->cfg_pcom);
+ M_16_SWAP(pcfg->cfg_rwcc);
+ M_16_SWAP(pcfg->cfg_ecc);
+ M_16_SWAP(pcfg->cfg_eatm);
+ M_16_SWAP(pcfg->cfg_eprm);
+ M_16_SWAP(pcfg->cfg_eatw);
+ M_16_SWAP(pcfg->cfg_rsvc1);
+ M_16_SWAP(pcfg->cfg_rsvc2);
+}
diff --git a/sys/arch/mvme68k/stand/sboot/XBUG.S b/sys/arch/mvme68k/stand/sboot/XBUG.S
new file mode 100644
index 00000000000..8b1e52f76a6
--- /dev/null
+++ b/sys/arch/mvme68k/stand/sboot/XBUG.S
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * Theo sez: I wrote a bootrom for the MVME147 *years* ago. To write
+ * this ROM I copied a few chunks from the old bootrom, like this piece:
+ *
+ * "watch this, the moto bastard struck here, shouldn't have hired people
+ * from intel I tried to tell them...
+ * "BOOT"
+ * offset from baseaddr to entry point.
+ * offset from baseaddr to first word after checksum
+ * garbage
+ * checksum made with CS command
+ * No need to change any of this unless you try to take our names out
+ * of there. Ie. don't touch."
+ */
+
+ .text
+bootlabel: .ascii "BOOT"
+ .long bootstart-0xffa00000 | for rom install
+ .long bootlabelend - bootlabel
+ .asciz "VME147 rboot Copyright (c) 1995 Theo de Raadt"
+ .align 2
+bootstart: jmp bssclr
+ .word 0x229c | XXX bitching cksum!
+bootlabelend:
+ .word 0
+
+ | clear bss and the kernel location
+bssclr: movl #_edata,a0
+ movl #_end - _edata,d0
+1: clrb a0@+
+ subql #1,d0
+ bpl 1b
+
+ | rip the data segment from ROM into ram..
+ movl #_etext,a2 | start of data
+ movl #0x4000,a1 | shovel address
+ movl #_edata - _etext,d0
+1: movb a2@+,a1@+
+ subql #1,d0
+ bpl 1b
+
+ bra start
diff --git a/sys/arch/mvme68k/stand/sboot/XSRT0.S b/sys/arch/mvme68k/stand/sboot/XSRT0.S
new file mode 100644
index 00000000000..5d14a09a7c0
--- /dev/null
+++ b/sys/arch/mvme68k/stand/sboot/XSRT0.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1995 Charles D. Cranor
+ * 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 D. Cranor.
+ * 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.
+ */
+
+ | start at 0x4000, load at 0xa000, stack at 0x9ff0.
+ .text
+ .globl start
+start: movb #0,_reboot
+ jra Ldoit
+restart: movb #1,_reboot | fall through
+
+Ldoit: movl #0x00006ff0,sp
+ jsr _main
+
+ .globl ___main
+___main: rts
diff --git a/sys/arch/mvme68k/stand/sboot/if_le.c b/sys/arch/mvme68k/stand/sboot/if_le.c
new file mode 100644
index 00000000000..2f75f839d8c
--- /dev/null
+++ b/sys/arch/mvme68k/stand/sboot/if_le.c
@@ -0,0 +1,327 @@
+/* $NetBSD: le_poll.c,v 1.3 1994/10/26 09:11:48 cgd Exp $ */
+
+/*
+ * Copyright (c) 1993 Adam Glass
+ * 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 Adam Glass.
+ * 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 Adam Glass ``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.
+ */
+
+#include <sys/cdefs.h>
+#include "sboot.h"
+#include "if_lereg.h"
+
+struct {
+ struct lereg1 *sc_r1; /* LANCE registers */
+ struct lereg2 *sc_r2; /* RAM */
+ int next_rmd;
+ int next_tmd;
+} le_softc;
+
+void
+le_error(str, ler1)
+ char *str;
+ struct lereg1 *ler1;
+{
+ /* ler1->ler1_rap = LE_CSRO done in caller */
+ if (ler1->ler1_rdp & LE_C0_BABL) {
+ printf("le0: been babbling, found by '%s'\n", str);
+ callrom();
+ }
+ if (ler1->ler1_rdp & LE_C0_CERR) {
+ ler1->ler1_rdp = LE_C0_CERR;
+ }
+ if (ler1->ler1_rdp & LE_C0_MISS) {
+ ler1->ler1_rdp = LE_C0_MISS;
+ }
+ if (ler1->ler1_rdp & LE_C0_MERR) {
+ printf("le0: memory error in '%s'\n", str);
+ callrom();
+ }
+}
+
+void
+le_reset(myea)
+ u_char *myea;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+ struct lereg2 *ler2 = le_softc.sc_r2;
+ unsigned int a;
+ int timo = 100000, stat, i;
+
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */
+
+ bzero(ler2, sizeof(*ler2));
+
+ ler2->ler2_mode = LE_MODE_NORMAL;
+ ler2->ler2_padr[0] = myea[1];
+ ler2->ler2_padr[1] = myea[0];
+ ler2->ler2_padr[2] = myea[3];
+ ler2->ler2_padr[3] = myea[2];
+ ler2->ler2_padr[4] = myea[5];
+ ler2->ler2_padr[5] = myea[4];
+
+
+ ler2->ler2_ladrf0 = 0;
+ ler2->ler2_ladrf1 = 0;
+
+ a = (u_int) ler2->ler2_rmd;
+ ler2->ler2_rlen = LE_RLEN | (a >> 16);
+ ler2->ler2_rdra = a & LE_ADDR_LOW_MASK;
+
+ a = (u_int) ler2->ler2_tmd;
+ ler2->ler2_tlen = LE_TLEN | (a >> 16);
+ ler2->ler2_tdra = a & LE_ADDR_LOW_MASK;
+
+ ler1->ler1_rap = LE_CSR1;
+ a = (u_int) ler2;
+ ler1->ler1_rdp = a & LE_ADDR_LOW_MASK;
+ ler1->ler1_rap = LE_CSR2;
+ ler1->ler1_rdp = a >> 16;
+
+ for (i = 0; i < LERBUF; i++) {
+ a = (u_int) & ler2->ler2_rbuf[i];
+ ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK;
+ ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN;
+ ler2->ler2_rmd[i].rmd1_hadr = a >> 16;
+ ler2->ler2_rmd[i].rmd2 = -LEMTU;
+ ler2->ler2_rmd[i].rmd3 = 0;
+ }
+ for (i = 0; i < LETBUF; i++) {
+ a = (u_int) & ler2->ler2_tbuf[i];
+ ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK;
+ ler2->ler2_tmd[i].tmd1_bits = 0;
+ ler2->ler2_tmd[i].tmd1_hadr = a >> 16;
+ ler2->ler2_tmd[i].tmd2 = 0;
+ ler2->ler2_tmd[i].tmd3 = 0;
+ }
+
+ ler1->ler1_rap = LE_CSR3;
+ ler1->ler1_rdp = LE_C3_BSWP;
+
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_INIT;
+ do {
+ if (--timo == 0) {
+ printf("le0: init timeout, stat = 0x%x\n", stat);
+ break;
+ }
+ stat = ler1->ler1_rdp;
+ } while ((stat & LE_C0_IDON) == 0);
+
+ ler1->ler1_rdp = LE_C0_IDON;
+ le_softc.next_rmd = 0;
+ le_softc.next_tmd = 0;
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STRT;
+}
+
+int
+le_poll(pkt, len)
+ void *pkt;
+ int len;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+ struct lereg2 *ler2 = le_softc.sc_r2;
+ unsigned int a;
+ int length;
+ struct lermd *rmd;
+
+ ler1->ler1_rap = LE_CSR0;
+ if ((ler1->ler1_rdp & LE_C0_RINT) != 0)
+ ler1->ler1_rdp = LE_C0_RINT;
+ rmd = &ler2->ler2_rmd[le_softc.next_rmd];
+ if (rmd->rmd1_bits & LE_R1_OWN) {
+ return (0);
+ }
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error("le_poll", ler1);
+ if (rmd->rmd1_bits & LE_R1_ERR) {
+ printf("le0_poll: rmd status 0x%x\n", rmd->rmd1_bits);
+ length = 0;
+ goto cleanup;
+ }
+ if ((rmd->rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != (LE_R1_STP | LE_R1_ENP)) {
+ printf("le_poll: chained packet\n");
+ callrom();
+ }
+ length = rmd->rmd3;
+ if (length >= LEMTU) {
+ length = 0;
+ printf("csr0 when bad things happen: %x\n", ler1->ler1_rdp);
+ callrom();
+ goto cleanup;
+ }
+ if (!length)
+ goto cleanup;
+ length -= 4;
+ if (length > 0)
+ bcopy((char *) &ler2->ler2_rbuf[le_softc.next_rmd], pkt, length);
+
+cleanup:
+ a = (u_int) & ler2->ler2_rbuf[le_softc.next_rmd];
+ rmd->rmd0 = a & LE_ADDR_LOW_MASK;
+ rmd->rmd1_hadr = a >> 16;
+ rmd->rmd2 = -LEMTU;
+ le_softc.next_rmd =
+ (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1);
+ rmd->rmd1_bits = LE_R1_OWN;
+ return length;
+}
+
+int
+le_put(pkt, len)
+ u_char *pkt;
+ size_t len;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+ struct lereg2 *ler2 = le_softc.sc_r2;
+ struct letmd *tmd;
+ int timo = 100000, stat, i;
+ unsigned int a;
+
+ ler1->ler1_rap = LE_CSR0;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error("le_put(way before xmit)", ler1);
+ tmd = &ler2->ler2_tmd[le_softc.next_tmd];
+ while (tmd->tmd1_bits & LE_T1_OWN) {
+ printf("le0: output buffer busy\n");
+ }
+ bcopy(pkt, (char *) ler2->ler2_tbuf[le_softc.next_tmd], len);
+ if (len < 64)
+ tmd->tmd2 = -64;
+ else
+ tmd->tmd2 = -len;
+ tmd->tmd3 = 0;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error("le_put(before xmit)", ler1);
+ tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN;
+ a = (u_int) & ler2->ler2_tbuf[le_softc.next_tmd];
+ tmd->tmd0 = a & LE_ADDR_LOW_MASK;
+ tmd->tmd1_hadr = a >> 16;
+ ler1->ler1_rdp = LE_C0_TDMD;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error("le_put(after xmit)", ler1);
+ do {
+ if (--timo == 0) {
+ printf("le0: transmit timeout, stat = 0x%x\n",
+ stat);
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error("le_put(timeout)", ler1);
+ break;
+ }
+ stat = ler1->ler1_rdp;
+ } while ((stat & LE_C0_TINT) == 0);
+ ler1->ler1_rdp = LE_C0_TINT;
+ if (ler1->ler1_rdp & LE_C0_ERR) {
+ if ((ler1->ler1_rdp & (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | LE_C0_MERR)) !=
+ LE_C0_CERR)
+ printf("le_put: xmit error, buf %d\n", le_softc.next_tmd);
+ le_error("le_put(xmit error)", ler1);
+ }
+ le_softc.next_tmd = 0;
+/* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/
+ if (tmd->tmd1_bits & LE_T1_ERR) {
+ printf("le0: transmit error, error = 0x%x\n",
+ tmd->tmd3);
+ return -1;
+ }
+ return len;
+}
+
+int
+le_get(pkt, len, timeout)
+ u_char *pkt;
+ size_t len;
+ u_long timeout;
+{
+ int cc;
+ int now, then;
+ int stopat = time() + timeout;
+ then = 0;
+
+ cc = 0;
+ while ((now = time()) < stopat && !cc) {
+ cc = le_poll(pkt, len);
+ if (then != now) {
+#ifdef LE_DEBUG
+ printf("%d \r", stopat - now);
+#endif
+ then = now;
+ }
+ if (cc && (pkt[0] != myea[0] || pkt[1] != myea[1] ||
+ pkt[2] != myea[2] || pkt[3] != myea[3] ||
+ pkt[4] != myea[4] || pkt[5] != myea[5])) {
+ cc = 0; /* ignore broadcast / multicast */
+#ifdef LE_DEBUG
+ printf("reject (%d sec left)\n", stopat - now);
+#endif
+ }
+ }
+#ifdef LE_DEBUG
+ printf("\n");
+#endif
+ return cc;
+}
+
+void
+le_init()
+{
+ caddr_t addr;
+ int *ea = (int *) LANCE_ADDR;
+ u_long *eram = (u_long *) ERAM_ADDR;
+ u_long e = *ea;
+ if ((e & 0x2fffff00) == 0x2fffff00) {
+ printf("ERROR: ethernet address not set! Use LSAD.\n");
+ callrom();
+ }
+ myea[0] = 0x08;
+ myea[1] = 0x00;
+ myea[2] = 0x3e;
+ e = e >> 8;
+ myea[5] = e & 0xff;
+ e = e >> 8;
+ myea[4] = e & 0xff;
+ e = e >> 8;
+ myea[3] = e;
+ printf("le0: ethernet address: %x:%x:%x:%x:%x:%x\n",
+ myea[0], myea[1], myea[2], myea[3], myea[4], myea[5]);
+ bzero(&le_softc, sizeof(le_softc));
+ le_softc.sc_r1 = (struct lereg1 *) LANCE_REG_ADDR;
+ le_softc.sc_r2 = (struct lereg2 *) (*eram - (1024 * 1024));
+ le_reset(myea);
+}
+
+void
+le_end()
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STOP;
+}
diff --git a/sys/arch/mvme68k/stand/sboot/oc_cksum.S b/sys/arch/mvme68k/stand/sboot/oc_cksum.S
new file mode 100644
index 00000000000..2c9d6a63a24
--- /dev/null
+++ b/sys/arch/mvme68k/stand/sboot/oc_cksum.S
@@ -0,0 +1,187 @@
+| $NetBSD: oc_cksum.s,v 1.4 1994/10/26 07:51:13 cgd Exp $
+
+| Copyright (c) 1988 Regents of the University of California.
+| 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 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.
+|
+| @(#)oc_cksum.s 7.2 (Berkeley) 11/3/90
+|
+|
+| oc_cksum: ones complement 16 bit checksum for MC68020.
+|
+| oc_cksum (buffer, count, strtval)
+|
+| Do a 16 bit ones complement sum of 'count' bytes from 'buffer'.
+| 'strtval' is the starting value of the sum (usually zero).
+|
+| It simplifies life in in_cksum if strtval can be >= 2^16.
+| This routine will work as long as strtval is < 2^31.
+|
+| Performance
+| -----------
+| This routine is intended for MC 68020s but should also work
+| for 68030s. It (deliberately) does not worry about the alignment
+| of the buffer so will only work on a 68010 if the buffer is
+| aligned on an even address. (Also, a routine written to use
+| 68010 "loop mode" would almost certainly be faster than this
+| code on a 68010).
+|
+| We do not worry about alignment because this routine is frequently
+| called with small counts: 20 bytes for IP header checksums and 40
+| bytes for TCP ack checksums. For these small counts, testing for
+| bad alignment adds ~10% to the per-call cost. Since, by the nature
+| of the kernel allocator, the data we are called with is almost
+| always longword aligned, there is no benefit to this added cost
+| and we are better off letting the loop take a big performance hit
+| in the rare cases where we are handed an unaligned buffer.
+|
+| Loop unrolling constants of 2, 4, 8, 16, 32 and 64 times were
+| tested on random data on four different types of processors (see
+| list below -- 64 was the largest unrolling because anything more
+| overflows the 68020 Icache). On all the processors, the
+| throughput asymptote was located between 8 and 16 (closer to 8).
+| However, 16 was substantially better than 8 for small counts.
+| (It is clear why this happens for a count of 40: unroll-8 pays a
+| loop branch cost and unroll-16 does not. But the tests also showed
+| that 16 was better than 8 for a count of 20. It is not obvious to
+| me why.) So, since 16 was good for both large and small counts,
+| the loop below is unrolled 16 times.
+|
+| The processors tested and their average time to checksum 1024 bytes
+| of random data were:
+| Sun 3/50 (15MHz) 190 us/KB
+| Sun 3/180 (16.6MHz) 175 us/KB
+| Sun 3/60 (20MHz) 134 us/KB
+| Sun 3/280 (25MHz) 95 us/KB
+|
+| The cost of calling this routine was typically 10% of the per-
+| kilobyte cost. E.g., checksumming zero bytes on a 3/60 cost 9us
+| and each additional byte cost 125ns. With the high fixed cost,
+| it would clearly be a gain to "inline" this routine -- the
+| subroutine call adds 400% overhead to an IP header checksum.
+| However, in absolute terms, inlining would only gain 10us per
+| packet -- a 1% effect for a 1ms ethernet packet. This is not
+| enough gain to be worth the effort.
+
+#include <machine/asm.h>
+
+ .text
+
+ .text; .even; .globl _oc_cksum; _oc_cksum:
+ movl sp@(4),a0 | get buffer ptr
+ movl sp@(8),d1 | get byte count
+ movl sp@(12),d0 | get starting value
+ movl d2,sp@- | free a reg
+
+ | test for possible 1, 2 or 3 bytes of excess at end
+ | of buffer. The usual case is no excess (the usual
+ | case is header checksums) so we give that the faster
+ | 'not taken' leg of the compare. (We do the excess
+ | first because we are about the trash the low order
+ | bits of the count in d1.)
+
+ btst #0,d1
+ jne L5 | if one or three bytes excess
+ btst #1,d1
+ jne L7 | if two bytes excess
+L1:
+ movl d1,d2
+ lsrl #6,d1 | make cnt into # of 64 byte chunks
+ andl #0x3c,d2 | then find fractions of a chunk
+ negl d2
+ andb #0xf,cc | clear X
+ jmp pc@(L3-.-2:b,d2)
+L2:
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+ movl a0@+,d2
+ addxl d2,d0
+L3:
+ dbra d1,L2 | (NB- dbra does not affect X)
+
+ movl d0,d1 | fold 32 bit sum to 16 bits
+ swap d1 | (NB- swap does not affect X)
+ addxw d1,d0
+ jcc L4
+ addw #1,d0
+L4:
+ andl #0xffff,d0
+ movl sp@+,d2
+ rts
+
+L5: | deal with 1 or 3 excess bytes at the end of the buffer.
+ btst #1,d1
+ jeq L6 | if 1 excess
+
+ | 3 bytes excess
+ clrl d2
+ movw a0@(-3,d1:l),d2 | add in last full word then drop
+ addl d2,d0 | through to pick up last byte
+
+L6: | 1 byte excess
+ clrl d2
+ movb a0@(-1,d1:l),d2
+ lsll #8,d2
+ addl d2,d0
+ jra L1
+
+L7: | 2 bytes excess
+ clrl d2
+ movw a0@(-2,d1:l),d2
+ addl d2,d0
+ jra L1
diff --git a/sys/arch/mvme68k/stand/sboot/srec.c b/sys/arch/mvme68k/stand/sboot/srec.c
new file mode 100644
index 00000000000..59ff4368995
--- /dev/null
+++ b/sys/arch/mvme68k/stand/sboot/srec.c
@@ -0,0 +1,155 @@
+/*
+ * convert binary file to Srecord format
+ * XXX srec generates improper checksums for 4-byte dumps
+ */
+#include <stdio.h>
+#include <ctype.h>
+
+int get32();
+void put32();
+void sput();
+void put();
+int checksum();
+
+int mask;
+int size;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char buf[32];
+ int cc;
+ int base;
+ int addr;
+ char *name;
+
+ if (argc != 4) {
+ fprintf(stderr, "usage: %s {size} {hex_addr} {name}\n", argv[0]);
+ fprintf(stderr, "Size = 2, 3, or 4 byte address\n");
+ exit(1);
+ }
+ sscanf(argv[1], "%x", &size);
+ mask = (1 << (size * 8)) - 1;
+ if (!mask)
+ mask = (-1);
+ sscanf(argv[2], "%x", &base);
+ name = argv[3];
+
+ if (size == 2)
+ printf("S0%02X%04X", 2 + strlen(name) + 1, 0);
+ if (size == 3)
+ printf("S0%02X%06X", 3 + strlen(name) + 1, 0);
+ if (size == 4)
+ printf("S0%02X%08X", 4 + strlen(name) + 1, 0);
+ sput(name);
+ printf("%02X\n", checksum(0, name, strlen(name), size));
+
+ addr = base;
+ for (;;) {
+ cc = get32(buf);
+ if (cc > 0) {
+ put32(cc, addr, buf, size, mask);
+ addr += cc;
+ } else
+ break;
+ }
+
+ buf[0] = base >> 8;
+ buf[1] = base;
+ printf("S%d%02X", 11 - size, 2 + 1);
+ switch (size) {
+ case 2:
+ printf("%04X", base & mask);
+ break;
+ case 3:
+ printf("%06X", base & mask);
+ break;
+ case 4:
+ printf("%08X", base & mask);
+ break;
+ }
+
+ /*
+ * kludge -> don't know why you have to add the +1 = works
+ * for size =3 at least
+ */
+ printf("%02X\n", checksum(base, (char *) 0, 0, size) + 1);
+ exit (0);
+}
+
+int
+get32(buf)
+ char buf[];
+{
+ char *cp = buf;
+ int i;
+ int c;
+
+ for (i = 0; i < 32; ++i) {
+ if ((c = getchar()) != EOF)
+ *cp++ = c;
+ else
+ break;
+ }
+ return (cp - buf);
+}
+
+void
+put32(len, addr, buf, size, mask)
+ int len;
+ int addr;
+ char buf[];
+ int size, mask;
+{
+ char *cp = buf;
+ int i;
+
+ if (size == 2)
+ printf("S1%02X%04X", 2 + len + 1, addr & mask);
+ if (size == 3)
+ printf("S2%02X%06X", 3 + len + 1, addr & mask);
+ if (size == 4)
+ printf("S3%02X%08X", 4 + len + 1, addr & mask);
+ for (i = 0; i < len; ++i)
+ put(*cp++);
+ printf("%02X\n", checksum(addr, buf, len, size));
+}
+
+void
+sput(s)
+ char *s;
+{
+ while (*s != '\0')
+ put(*s++);
+}
+
+void
+put(c)
+ int c;
+{
+ printf("%02X", c & 0xff);
+}
+
+int
+checksum(addr, buf, len, size)
+ int addr;
+ char buf[];
+ int len;
+ int size;
+{
+ char *cp = buf;
+ int sum = 0xff - 1 - size - (len & 0xff);
+ int i;
+
+ if (size == 4)
+ sum -= (addr >> 24) & 0xff;
+ if (size >= 3)
+ sum -= (addr >> 16) & 0xff;
+ sum -= (addr >> 8) & 0xff;
+ sum -= addr & 0xff;
+ for (i = 0; i < len; ++i) {
+ sum -= *cp++ & 0xff;
+ }
+ return (sum & 0xff);
+}
diff --git a/sys/arch/mvme68k/stand/wrtvid/Makefile b/sys/arch/mvme68k/stand/wrtvid/Makefile
new file mode 100644
index 00000000000..8b6cd97df7d
--- /dev/null
+++ b/sys/arch/mvme68k/stand/wrtvid/Makefile
@@ -0,0 +1,6 @@
+PROG= wrtvid
+NOMAN=
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/mvme68k/stand/wrtvid/Makefile.inc b/sys/arch/mvme68k/stand/wrtvid/Makefile.inc
new file mode 100644
index 00000000000..a8c47af8bd7
--- /dev/null
+++ b/sys/arch/mvme68k/stand/wrtvid/Makefile.inc
@@ -0,0 +1,12 @@
+WRTVID_BASE_DIR=${S}/arch/${MACHINE}/stand/wrtvid
+
+WRTVID_DIR!= cd ${WRTVID_BASE_DIR}; \
+ printf "xxx:\n\techo \$${.OBJDIR}\n" | ${MAKE} -r -s -f - xxx
+
+WRTVID=${WRTVID_DIR}/wrtvid
+
+$(WRTVID): .NOTMAIN __always_make_WRTVID
+ @echo making sure the wrtvid is up to date...
+ @(cd ${WRTVID_BASE_DIR}; ${MAKE})
+
+__always_make_WRTVID: .NOTMAIN
diff --git a/sys/arch/mvme68k/stand/wrtvid/wrtvid.c b/sys/arch/mvme68k/stand/wrtvid/wrtvid.c
new file mode 100644
index 00000000000..6d78b7d8660
--- /dev/null
+++ b/sys/arch/mvme68k/stand/wrtvid/wrtvid.c
@@ -0,0 +1,145 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#define __DBINTERFACE_PRIVATE
+#include <db.h>
+#include <machine/disklabel.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct cpu_disklabel *pcpul;
+ struct stat stat;
+ int exe_file;
+ int tape_vid;
+ int tape_exe;
+ unsigned int exe_addr;
+ unsigned short exe_addr_u;
+ unsigned short exe_addr_l;
+ char *filename;
+ char fileext[256];
+ char filebase[256];
+
+ if (argc == 0)
+ filename = "a.out";
+ else
+ filename = argv[1];
+
+ exe_file = open(filename, O_RDONLY,0444);
+ if (exe_file == -1) {
+ perror(filename);
+ exit(2);
+ }
+ sprintf(fileext, "%c%cboot", filename[4], filename[5]);
+ tape_vid = open(fileext, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ sprintf(fileext, "boot%c%c", filename[4], filename[5]);
+ tape_exe = open(fileext, O_WRONLY|O_CREAT|O_TRUNC,0644);
+
+ pcpul = (struct cpu_disklabel *)malloc(sizeof(struct cpu_disklabel));
+ bzero(pcpul, sizeof(struct cpu_disklabel));
+
+ strcpy(pcpul->vid_id, "NBSD");
+
+ fstat(exe_file, &stat);
+ /* size in 256 byte blocks round up after a.out header removed */
+
+ if (filename[5] == 't' ) {
+ pcpul->vid_oss = 1;
+ }else {
+ pcpul->vid_oss = 2;
+ }
+ pcpul->vid_osl = (((stat.st_size -0x30) +511) / 512) *2;
+
+ lseek(exe_file, 0x14, SEEK_SET);
+ read(exe_file, &exe_addr, 4);
+
+ /* check this, it may not work in both endian. */
+ {
+ union {
+ struct s {
+ unsigned short s1;
+ unsigned short s2;
+ } s;
+ unsigned long l;
+ } a;
+ a.l = exe_addr;
+ pcpul->vid_osa_u = a.s.s1;
+ pcpul->vid_osa_l = a.s.s2;
+
+ }
+ pcpul->vid_cas = 1;
+ pcpul->vid_cal = 1;
+ /* do not want to write past end of structure, not null terminated */
+ strncpy(pcpul->vid_mot, "MOTOROLA", 8);
+
+ if (BYTE_ORDER != BIG_ENDIAN)
+ swabvid(pcpul);
+
+ pcpul->cfg_rec = 0x100;
+ pcpul->cfg_psm = 0x200;
+
+ if (BYTE_ORDER != BIG_ENDIAN)
+ swabcfg(pcpul);
+
+ write(tape_vid, pcpul, sizeof(struct cpu_disklabel));
+
+ free(pcpul);
+
+ copy_exe(exe_file, tape_exe);
+ close(exe_file);
+ close(tape_vid);
+ close(tape_exe);
+ return (0);
+}
+
+#define BUF_SIZ 512
+copy_exe(exe_file, tape_exe)
+ int exe_file, tape_exe;
+{
+ char *buf;
+ int cnt = 0;
+
+ buf = (char *)malloc(BUF_SIZ);
+
+ lseek (exe_file, 0x20, SEEK_SET);
+ while (BUF_SIZ == (cnt = read(exe_file, buf, BUF_SIZ))) {
+ write(tape_exe, buf, cnt);
+ }
+ bzero(&buf[cnt], BUF_SIZ-cnt);
+ write(tape_exe, buf, BUF_SIZ);
+}
+
+swabvid(pcpul)
+ struct cpu_disklabel *pcpul;
+{
+ M_32_SWAP(pcpul->vid_oss);
+ M_16_SWAP(pcpul->vid_osl);
+ /*
+ M_16_SWAP(pcpul->vid_osa_u);
+ M_16_SWAP(pcpul->vid_osa_l);
+ */
+ M_32_SWAP(pcpul->vid_cas);
+}
+
+swabcfg(pcpul)
+ struct cpu_disklabel *pcpul;
+{
+ M_16_SWAP(pcpul->cfg_atm);
+ M_16_SWAP(pcpul->cfg_prm);
+ M_16_SWAP(pcpul->cfg_atm);
+ M_16_SWAP(pcpul->cfg_rec);
+ M_16_SWAP(pcpul->cfg_trk);
+ M_16_SWAP(pcpul->cfg_psm);
+ M_16_SWAP(pcpul->cfg_shd);
+ M_16_SWAP(pcpul->cfg_pcom);
+ M_16_SWAP(pcpul->cfg_rwcc);
+ M_16_SWAP(pcpul->cfg_ecc);
+ M_16_SWAP(pcpul->cfg_eatm);
+ M_16_SWAP(pcpul->cfg_eprm);
+ M_16_SWAP(pcpul->cfg_eatw);
+ M_16_SWAP(pcpul->cfg_rsvc1);
+ M_16_SWAP(pcpul->cfg_rsvc2);
+}