BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 25 Sep 1983 11:06:48 +0000 (03:06 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 25 Sep 1983 11:06:48 +0000 (03:06 -0800)
Work on file usr/src/sys/cassette/Makefile
Work on file usr/src/sys/floppy/anyboo.cmd
Work on file usr/src/sys/floppy/hkmboo.cmd
Work on file usr/src/sys/floppy/hksboo.cmd
Work on file usr/src/sys/floppy/rasboo.cmd
Work on file usr/src/sys/floppy/hpmboo.cmd
Work on file usr/src/sys/floppy/ramboo.cmd
Work on file usr/src/sys/floppy/upmboo.cmd
Work on file usr/src/sys/floppy/utboot.cmd
Work on file usr/src/sys/floppy/upsboo.cmd
Work on file usr/src/sys/floppy/restar.cmd
Work on file usr/src/sys/floppy/hpsboo.cmd
Work on file usr/src/sys/floppy/defboo.hk
Work on file usr/src/sys/floppy/defboo.hp
Work on file usr/src/sys/floppy/defboo.cmd
Work on file usr/src/sys/cassette/rlsboo.cmd
Work on file usr/src/sys/floppy/defboo.ra
Work on file usr/src/sys/floppy/defboo.up
Work on file usr/src/sys/conf/makefile.vax
Work on file usr/src/sys/h/file.h
Work on file usr/src/sys/h/protosw.h
Work on file usr/src/sys/stand/format.c
Work on file usr/src/sys/stand/Makefile
Work on file usr/src/sys/stand/hp.c
Work on file usr/src/sys/stand/sys.c
Work on file usr/src/sys/stand/saio.h
Work on file usr/src/sys/stand/up.c
Work on file usr/src/sys/sys/init_sysent.c
Work on file usr/src/sys/sys/kern_descrip.c
Work on file usr/src/sys/sys/kern_sig.c
Work on file usr/src/sys/sys/subr_xxx.c
Work on file usr/src/sys/sys/tty_conf.c
Work on file usr/src/sys/sys/tty_tb.c
Work on file usr/src/sys/sys/ufs_nami.c
Work on file usr/src/sys/sys/uipc_syscalls.c
Work on file usr/src/sys/sys/uipc_usrreq.c
Work on file usr/src/sys/sys/vm_swp.c
Work on file usr/src/sys/vax/asm.sed
Work on file usr/src/sys/vaxif/if_il.c
Work on file usr/src/sys/vaxuba/tm.c
Work on file usr/src/sys/vaxuba/vp.c

Synthesized-from: CSRG/cd1/4.2

41 files changed:
usr/src/sys/cassette/Makefile [new file with mode: 0644]
usr/src/sys/cassette/rlsboo.cmd [new file with mode: 0644]
usr/src/sys/conf/makefile.vax [new file with mode: 0644]
usr/src/sys/floppy/anyboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/defboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/defboo.hk [new file with mode: 0644]
usr/src/sys/floppy/defboo.hp [new file with mode: 0644]
usr/src/sys/floppy/defboo.ra [new file with mode: 0644]
usr/src/sys/floppy/defboo.up [new file with mode: 0644]
usr/src/sys/floppy/hkmboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/hksboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/hpmboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/hpsboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/ramboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/rasboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/restar.cmd [new file with mode: 0644]
usr/src/sys/floppy/upmboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/upsboo.cmd [new file with mode: 0644]
usr/src/sys/floppy/utboot.cmd [new file with mode: 0644]
usr/src/sys/h/file.h [new file with mode: 0644]
usr/src/sys/h/protosw.h [new file with mode: 0644]
usr/src/sys/stand/Makefile [new file with mode: 0644]
usr/src/sys/stand/format.c [new file with mode: 0644]
usr/src/sys/stand/hp.c [new file with mode: 0644]
usr/src/sys/stand/saio.h [new file with mode: 0644]
usr/src/sys/stand/sys.c [new file with mode: 0644]
usr/src/sys/stand/up.c [new file with mode: 0644]
usr/src/sys/sys/init_sysent.c [new file with mode: 0644]
usr/src/sys/sys/kern_descrip.c [new file with mode: 0644]
usr/src/sys/sys/kern_sig.c [new file with mode: 0644]
usr/src/sys/sys/subr_xxx.c [new file with mode: 0644]
usr/src/sys/sys/tty_conf.c [new file with mode: 0644]
usr/src/sys/sys/tty_tb.c [new file with mode: 0644]
usr/src/sys/sys/ufs_nami.c [new file with mode: 0644]
usr/src/sys/sys/uipc_syscalls.c [new file with mode: 0644]
usr/src/sys/sys/uipc_usrreq.c [new file with mode: 0644]
usr/src/sys/sys/vm_swp.c [new file with mode: 0644]
usr/src/sys/vax/asm.sed [new file with mode: 0644]
usr/src/sys/vaxif/if_il.c [new file with mode: 0644]
usr/src/sys/vaxuba/tm.c [new file with mode: 0644]
usr/src/sys/vaxuba/vp.c [new file with mode: 0644]

diff --git a/usr/src/sys/cassette/Makefile b/usr/src/sys/cassette/Makefile
new file mode 100644 (file)
index 0000000..464727b
--- /dev/null
@@ -0,0 +1,52 @@
+#      Makefile        6.2     83/09/25
+#
+# Make a 750/730 tu58 cassette
+# 
+BOOTS= boot.730 boot.750
+STDBOO=        defboo.cmd anyboo.cmd restar.cmd
+DEFBOO=        defboo.rb defboo.rl defboo.hk defboo.up defboo.ra
+DEVBOO=        rbmboo.cmd rbsboo.cmd rlsboo.cmd hkmboo.cmd hksboo.cmd \
+       upmboo.cmd upsboo.cmd ramboo.cmd rasboo.cmd
+UTILS= format.730 format.750 copy.730 copy.750 drtest.730 drtest.750
+# order is NOT random...
+OBJS=  boot ${STDBOO} ${DEFBOO} ${DEVBOO} format copy drtest
+FROMDEC=d[lmq]* cs* *boo.* boot.exe vmb.exe
+CASSETTE=/dev/tu0
+
+all:   cassette
+
+cassette: boot.750 ${STDBOO} ${DEFBOO} ${DEVBOO} format.750
+cassette: copy.750 drtest.750
+       cp /dev/null cassette
+       cp /dev/null pad
+       cp boot.750 boot
+       cp format.750 format
+       cp copy.750 copy
+       cp drtest.750 drtest
+       arff mcrf cassette ${OBJS} pad
+       rm -f pad
+
+../mdec/tuboot: ../mdec/tuboot.s
+       cd ../mdec; make ${MFLAGS} tuboot
+
+install: cassette ../mdec/tuboot
+       dd if=cassette of=${CASSETTE} bs=2k conv=sync
+       dd if=../mdec/tuboot of=${CASSETTE} bs=512 count=2
+
+# build a 730 boot cassette from a DEC console cassette
+# DONT TRY THIS ON A 750 W/O MRSP, THE SYSTEM WILL CRASH
+update:        boot.730 ${STDBOO} ${DEFBOO} ${DEVBOO} format.730
+update:        copy.730 drtest.730
+       -mkdir fromdec
+       cd fromdec; arff mxf ${CASSETTE}; rm -f ${FROMDEC} ${OBJS}; \
+               flcopy -t3 -f ${CASSETTE}; arff mcrf ${CASSETTE} *
+       rm -rf fromdec
+       cp boot.730 boot
+       cp format.730 format
+       cp copy.730 copy
+       cp drtest.730 drtest
+       arff mrf ${CASSETTE} ${OBJS}
+
+clean:
+       rm -f ${BOOTS} ${UTILS} cassette form50 boot50 copy50
+       rm -f boot format copy drtest
diff --git a/usr/src/sys/cassette/rlsboo.cmd b/usr/src/sys/cassette/rlsboo.cmd
new file mode 100644 (file)
index 0000000..0000b75
--- /dev/null
@@ -0,0 +1,10 @@
+!\r
+! BOOTSTRAP ON UP, LEAVING SINGLE USER\r
+! R11 = 2 = SINGLE\r
+! R10 = 14 = RA\r
+!\r
+I\r
+L BOOT\r
+D RB 2\r
+D RA E\r
+S 2\r
diff --git a/usr/src/sys/conf/makefile.vax b/usr/src/sys/conf/makefile.vax
new file mode 100644 (file)
index 0000000..d83f627
--- /dev/null
@@ -0,0 +1,146 @@
+#      makefile.vax    6.3     9/25/83
+#
+# Makefile for 4.2 BSD
+#
+# This makefile is constructed from a machine description:
+#      config machine
+# Most changes should be made in the machine description
+#      /sys/conf/``machineid''
+# after which you should do
+#       config machineid
+# Generic makefile changes should be made in
+#      /sys/conf/makefile
+# after which config should be rerun for all machines.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
+#      IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE      compile in kernel tracing hooks
+# -DQUOTA      compile in file system quotas
+# -DUUDMA      compile in unibus tu58 pseudo-dma code
+# -DSWABIPS    compile in code to byte swap ip packets on 3Mb/s Ethernet
+#
+C2=    /lib/c2
+LD=    /bin/ld
+TOUCH= touch -f -c
+
+COPTS= ${IDENT} -DKERNEL
+CFLAGS=        -O ${COPTS}
+
+AHEADS=        ../vax/pcb.m
+
+%OBJS
+
+%CFILES
+
+%LOAD
+
+clean:
+       rm -f eddep *vmunix tags *.o locore.i [a-tv-z]*.s \
+               errs linterrs makelinks
+
+lint: /tmp
+       @lint -hbxn -I. -DGENERIC ${COPTS} ../vax/Locore.c \
+         ${CFILES} ../vax/swapgeneric.c ioconf.c | \
+           grep -v 'struct/union .* never defined' | \
+           grep -v 'possible pointer alignment problem'
+
+../vax/symbols.sort: ../vax/symbols.raw
+       grep -v '^#' ../vax/symbols.raw \
+           | sed 's/^  //' | sort -u > ../vax/symbols.sort
+
+locore.o: assym.s ${AHEADS} ../vax/rpb.s ../vax/scb.s ../vax/locore.s \
+    ubglue.s ../vax/mtpr.h ../vax/trap.h ../machine/psl.h \
+    ../machine/pte.h ../vax/cpu.h mba.h
+       cat assym.s ../vax/rpb.s ../vax/scb.s ../vax/locore.s \
+           ubglue.s > locore.c
+       cc -E -I. -DLOCORE ${COPTS} locore.c > locore.i
+       @echo 'as -o locore.o $${AHEADS} locore.i'
+       @as -o locore.o ${AHEADS} locore.i
+       @rm locore.i
+
+# the following is necessary because autoconf.o depends on #if GENERIC
+autoconf.o tu.o: makefile
+
+# the following are necessary because the files depend on the types of
+# vax cpu's included in the system configuration
+clock.o machdep.o autoconf.o conf.o cons.o flp.o mba.o uba.o vaxcpu.o : makefile
+# depend on network configuration
+af.o : makefile
+# depend on maxusers
+assym.s: makefile
+
+assym.s: ../h/param.h ../machine/pte.h ../h/buf.h ../h/vmparam.h \
+    ../h/vmmeter.h ../h/dir.h ../h/cmap.h ../h/map.h ../vaxuba/ubavar.h \
+    ../h/proc.h ../h/msgbuf.h
+       cc ${IDENT} ${PARAM} ../vax/genassym.c; ./a.out >assym.s; rm -f a.out
+
+../h/param.h: /usr/include/signal.h
+       ${TOUCH} ../h/param.h
+../h/tty.h:  ../h/ttychars.h ../h/ttydev.h
+       ${TOUCH} ../h/tty.h
+../h/ioctl.h: /usr/include/sgtty.h ../h/ttychars.h ../h/ttydev.h
+       ${TOUCH} ../h/ioctl.h
+../h/user.h: ../vax/pcb.h ../h/dmap.h ../h/types.h \
+    /usr/include/errno.h
+       ${TOUCH} ../h/user.h
+../h/vm.h: ../h/vmmac.h ../h/vmmeter.h ../h/vmparam.h ../h/vmsystm.h
+       ${TOUCH} ../h/vm.h
+
+depend:
+       grep '^#include' ${CFILES} | grep -v '<' | \
+       sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' \
+           -e 's/\.c/.o/' \
+           -e 's,../[a-zA-Z]*/,,' | \
+       awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
+               else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
+                      else rec = rec " " $$2 } } \
+             END { print rec } ' > makedep
+       echo '$$r makedep' >>eddep
+       echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
+       echo '$$r makedep' >>eddep
+       echo 'w' >>eddep
+       cp makefile makefile.bak
+       ed - makefile < eddep
+       rm eddep makedep
+
+
+links:
+       egrep '#if' ${CFILES} | sed -f ../conf/defines | \
+         sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+       echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+         sort -u | comm -23 - dontlink | \
+         sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+       echo 'rm -f udiv.o;ln -s ../GENERIC/udiv.o udiv.o' >> makelinks
+       echo 'rm -f urem.o;ln -s ../GENERIC/urem.o urem.o' >> makelinks
+       sh makelinks && rm -f dontlink
+
+tags:
+       /usr/ucb/ctags ${CFILES}
+
+print:
+       @pr -f makefile ../sys/TODO linterrs
+       @/usr/ucb/ctags -x ${CFILES} | pr -f -h XREF
+       @(size vmunix *.o) | pr -f -h sizes
+       @ls -ls | pr -f
+       @cd ../h; ls -ls | pr -f ; pr -f *.m *.h
+       @echo 'once upon a time ...'
+       @cd ../sys; pr -f asm.sed Locore.c scb.s locore.s
+       @pr -f ${CFILES}
+
+ioconf.o: ioconf.c ../h/param.h ../machine/pte.h ../h/buf.h ../h/map.h \
+    ../vaxmba/mbavar.h ../h/vm.h ../vaxuba/ubavar.h
+       ${CC} -I. -c -S ${COPTS} ioconf.c
+       ${C2} ioconf.s | sed -f ../vax/asm.sed | ${AS} -o ioconf.o
+       rm -f ioconf.s
+
+param.c: ../conf/param.c
+       cp ../conf/param.c .
+
+param.o: param.c makefile
+       ${CC} -I. -c ${CFLAGS} ${PARAM} param.c
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
diff --git a/usr/src/sys/floppy/anyboo.cmd b/usr/src/sys/floppy/anyboo.cmd
new file mode 100644 (file)
index 0000000..3476047
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ANY DEVICE TO A SINGLE USER SHELL\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R11 3                ! 3=RB_ASKNAME+RB_SINGLE
+! R10 NICHTS   ! DEVICE CHOICE ISNT APPLICABLE
+START 2\r
diff --git a/usr/src/sys/floppy/defboo.cmd b/usr/src/sys/floppy/defboo.cmd
new file mode 100644 (file)
index 0000000..d576910
--- /dev/null
@@ -0,0 +1,14 @@
+!\r
+! BOOTSTRAP BY BOOT() SYSCALL\r
+! GO MULTI-USER AFTER CHECKING; BOOT FROM DEFAULT DEVICE\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D/G B 0                ! BOOT PARAMETERS: MULTI USER AFTER CHECK\r
+D/G A 0                ! DEV TO BOOT FROM (0=HP, 2=UP, 3=HK, 9=RA)\r
+START 2\r
diff --git a/usr/src/sys/floppy/defboo.hk b/usr/src/sys/floppy/defboo.hk
new file mode 100644 (file)
index 0000000..26cc262
--- /dev/null
@@ -0,0 +1,14 @@
+!\r
+! BOOTSTRAP BY BOOT() SYSCALL\r
+! GO MULTI-USER AFTER CHECKING; BOOT FROM DEFAULT DEVICE\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D/G B 0                ! BOOT PARAMETERS: MULTI USER AFTER CHECK\r
+D/G A 3                ! DEV TO BOOT FROM (0=HP, 2=UP, 3=HK, 9=RA)\r
+START 2\r
diff --git a/usr/src/sys/floppy/defboo.hp b/usr/src/sys/floppy/defboo.hp
new file mode 100644 (file)
index 0000000..d576910
--- /dev/null
@@ -0,0 +1,14 @@
+!\r
+! BOOTSTRAP BY BOOT() SYSCALL\r
+! GO MULTI-USER AFTER CHECKING; BOOT FROM DEFAULT DEVICE\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D/G B 0                ! BOOT PARAMETERS: MULTI USER AFTER CHECK\r
+D/G A 0                ! DEV TO BOOT FROM (0=HP, 2=UP, 3=HK, 9=RA)\r
+START 2\r
diff --git a/usr/src/sys/floppy/defboo.ra b/usr/src/sys/floppy/defboo.ra
new file mode 100644 (file)
index 0000000..9317d56
--- /dev/null
@@ -0,0 +1,14 @@
+!\r
+! BOOTSTRAP BY BOOT() SYSCALL\r
+! GO MULTI-USER AFTER CHECKING; BOOT FROM DEFAULT DEVICE\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D/G B 0                ! BOOT PARAMETERS: MULTI USER AFTER CHECK\r
+D/G A 9                ! DEV TO BOOT FROM (0=HP, 2=UP, 3=HK, 9=RA)\r
+START 2\r
diff --git a/usr/src/sys/floppy/defboo.up b/usr/src/sys/floppy/defboo.up
new file mode 100644 (file)
index 0000000..655e3dd
--- /dev/null
@@ -0,0 +1,14 @@
+!\r
+! BOOTSTRAP BY BOOT() SYSCALL\r
+! GO MULTI-USER AFTER CHECKING; BOOT FROM DEFAULT DEVICE\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D/G B 0                ! BOOT PARAMETERS: MULTI USER AFTER CHECK\r
+D/G A 2                ! DEV TO BOOT FROM (0=HP, 2=UP, 3=HK, 9=RA)\r
+START 2\r
diff --git a/usr/src/sys/floppy/hkmboo.cmd b/usr/src/sys/floppy/hkmboo.cmd
new file mode 100644 (file)
index 0000000..db42434
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON HK, GOING MULTI USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 3                ! DEVICE CHOICE 3=HK\r
+D R11 0                ! 0= AUTOBOOT\r
+START 2\r
diff --git a/usr/src/sys/floppy/hksboo.cmd b/usr/src/sys/floppy/hksboo.cmd
new file mode 100644 (file)
index 0000000..670f9e6
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON HK, LEAVING SINGLE USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 3                ! DEVICE CHOICE 3=HK\r
+D R11 2                ! 2= RB_SINGLE\r
+START 2\r
diff --git a/usr/src/sys/floppy/hpmboo.cmd b/usr/src/sys/floppy/hpmboo.cmd
new file mode 100644 (file)
index 0000000..e424d5f
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON RP, GOING MULTI USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 0                ! DEVICE CHOICE 0=HP\r
+D R11 0                ! 0= AUTOBOOT\r
+START 2\r
diff --git a/usr/src/sys/floppy/hpsboo.cmd b/usr/src/sys/floppy/hpsboo.cmd
new file mode 100644 (file)
index 0000000..2d9d81e
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON RP, LEAVING SINGLE USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 0                ! DEVICE CHOICE 0=HP\r
+D R11 2                ! 2= RB_SINGLE\r
+START 2\r
diff --git a/usr/src/sys/floppy/ramboo.cmd b/usr/src/sys/floppy/ramboo.cmd
new file mode 100644 (file)
index 0000000..40d2e8c
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON UP, GOING MULTI USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 9                ! DEVICE CHOICE 9=RA\r
+D R11 0                ! 0= AUTOBOOT\r
+START 2\r
diff --git a/usr/src/sys/floppy/rasboo.cmd b/usr/src/sys/floppy/rasboo.cmd
new file mode 100644 (file)
index 0000000..bade1bb
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON UP, LEAVING SINGLE USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 9                ! DEVICE CHOICE 9=RA\r
+D R11 2                ! 2= RB_SINGLE\r
+START 2\r
diff --git a/usr/src/sys/floppy/restar.cmd b/usr/src/sys/floppy/restar.cmd
new file mode 100644 (file)
index 0000000..64e345d
--- /dev/null
@@ -0,0 +1,16 @@
+!      RESTART COMMMAND FILE\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT                   ! HALT PROCESSOR\r
+UNJAM                  ! UNJAM SBI\r
+INIT                   ! INITIALIZE PROCESSOR\r
+D/I 11 20003800                ! SET SCBB TO ROM\r
+D/G 0 0\r
+D/G 1 3                        ! UBA TR NUMBER\r
+D/G 2 0\r
+D/G 3 0\r
+D/G 4 0\r
+D/G 5 0\r
+D/G FP 0\r
+S 20003004\r
diff --git a/usr/src/sys/floppy/upmboo.cmd b/usr/src/sys/floppy/upmboo.cmd
new file mode 100644 (file)
index 0000000..41be64d
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON UP, GOING MULTI USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 2                ! DEVICE CHOICE 2=UP\r
+D R11 0                ! 0= AUTOBOOT\r
+START 2\r
diff --git a/usr/src/sys/floppy/upsboo.cmd b/usr/src/sys/floppy/upsboo.cmd
new file mode 100644 (file)
index 0000000..af96678
--- /dev/null
@@ -0,0 +1,13 @@
+!\r
+! BOOTSTRAP ON UP, LEAVING SINGLE USER\r
+!\r
+SET DEF HEX\r
+SET DEF LONG\r
+SET REL:0\r
+HALT\r
+UNJAM\r
+INIT\r
+LOAD BOOT\r
+D R10 2                ! DEVICE CHOICE 2=UP\r
+D R11 2                ! 2= RB_SINGLE\r
+START 2\r
diff --git a/usr/src/sys/floppy/utboot.cmd b/usr/src/sys/floppy/utboot.cmd
new file mode 100644 (file)
index 0000000..fe89eb5
--- /dev/null
@@ -0,0 +1,20 @@
+SET DEF HEX
+SET DEF LONG
+SET REL:0
+HALT
+UNJAM
+INIT
+D/P 200 0036EFD0
+D + D0510000
+D + 2000008F
+D + 0800C180 
+D + 0804C1D4
+D + 0026EFD0
+D + C8520000
+D + 00F5208F 
+D + 8FB05200
+D + 1AA204C0
+02008fae  8fae06a2 
+0000060 02a20100  b004a2b4  00006239  20006000 
+0000100 2013e000 
+0000104
diff --git a/usr/src/sys/h/file.h b/usr/src/sys/h/file.h
new file mode 100644 (file)
index 0000000..9a04140
--- /dev/null
@@ -0,0 +1,115 @@
+/*     file.h  6.2     83/09/23        */
+
+#ifdef KERNEL
+/*
+ * Descriptor table entry.
+ * One for each kernel object.
+ */
+struct file {
+       int     f_flag;         /* see below */
+       short   f_type;         /* descriptor type */
+       short   f_count;        /* reference count */
+       short   f_msgcount;     /* references from message queue */
+       struct  fileops {
+               int     (*fo_rw)();
+               int     (*fo_ioctl)();
+               int     (*fo_select)();
+               int     (*fo_close)();
+       } *f_ops;
+       caddr_t f_data;         /* inode */
+       off_t   f_offset;
+};
+
+struct file *file, *fileNFILE;
+int    nfile;
+struct file *getf();
+struct file *falloc();
+#endif
+
+/*
+ * flags- also for fcntl call.
+ */
+#define        FOPEN           (-1)
+#define        FREAD           00001           /* descriptor read/receive'able */
+#define        FWRITE          00002           /* descriptor write/send'able */
+#ifndef        F_DUPFD
+#define        FNDELAY         00004           /* no delay */
+#define        FAPPEND         00010           /* append on each write */
+#endif
+#define        FMARK           00020           /* mark during gc() */
+#define        FDEFER          00040           /* defer for next gc pass */
+#ifndef        F_DUPFD
+#define        FASYNC          00100           /* signal pgrp when data ready */
+#endif
+#define        FSHLOCK         00200           /* shared lock present */
+#define        FEXLOCK         00400           /* exclusive lock present */
+
+/* bits to save after open */
+#define        FMASK           00113
+#define        FCNTLCANT       (FREAD|FWRITE|FMARK|FDEFER|FSHLOCK|FEXLOCK)
+
+/* open only modes */
+#define        FCREAT          01000           /* create if nonexistant */
+#define        FTRUNC          02000           /* truncate to zero length */
+#define        FEXCL           04000           /* error if already created */
+
+#ifndef        F_DUPFD
+/* fcntl(2) requests--from <fcntl.h> */
+#define        F_DUPFD 0       /* Duplicate fildes */
+#define        F_GETFD 1       /* Get fildes flags */
+#define        F_SETFD 2       /* Set fildes flags */
+#define        F_GETFL 3       /* Get file flags */
+#define        F_SETFL 4       /* Set file flags */
+#define        F_GETOWN 5      /* Get owner */
+#define F_SETOWN 6     /* Set owner */
+#endif
+
+/*
+ * User definitions.
+ */
+
+/*
+ * Open call.
+ */
+#define        O_RDONLY        000             /* open for reading */
+#define        O_WRONLY        001             /* open for writing */
+#define        O_RDWR          002             /* open for read & write */
+#define        O_NDELAY        FNDELAY         /* non-blocking open */
+#define        O_APPEND        FAPPEND         /* append on each write */
+#define        O_CREAT         FCREAT          /* open with file create */
+#define        O_TRUNC         FTRUNC          /* open with truncation */
+#define        O_EXCL          FEXCL           /* error on create if file exists */
+
+/*
+ * Flock call.
+ */
+#define        LOCK_SH         1       /* shared lock */
+#define        LOCK_EX         2       /* exclusive lock */
+#define        LOCK_NB         4       /* don't block when locking */
+#define        LOCK_UN         8       /* unlock */
+
+/*
+ * Access call.
+ */
+#define        F_OK            0       /* does file exist */
+#define        X_OK            1       /* is it executable by caller */
+#define        W_OK            2       /* writable by caller */
+#define        R_OK            4       /* readable by caller */
+
+/*
+ * Lseek call.
+ */
+#define        L_SET           0       /* absolute offset */
+#define        L_INCR          1       /* relative to current offset */
+#define        L_XTND          2       /* relative to end of file */
+
+#ifdef KERNEL
+#define        GETF(fp, fd) { \
+       if ((unsigned)(fd) >= NOFILE || ((fp) = u.u_ofile[fd]) == NULL) { \
+               u.u_error = EBADF; \
+               return; \
+       } \
+}
+#define        DTYPE_INODE     1       /* file */
+#define        DTYPE_SOCKET    2       /* communications endpoint */
+#endif
diff --git a/usr/src/sys/h/protosw.h b/usr/src/sys/h/protosw.h
new file mode 100644 (file)
index 0000000..abd0d1d
--- /dev/null
@@ -0,0 +1,153 @@
+/*     protosw.h       6.2     83/09/19        */
+
+/*
+ * Protocol switch table.
+ *
+ * Each protocol has a handle initializing one of these structures,
+ * which is used for protocol-protocol and system-protocol communication.
+ *
+ * A protocol is called through the pr_init entry before any other.
+ * Thereafter it is called every 200ms through the pr_fasttimo entry and
+ * every 500ms through the pr_slowtimo for timer based actions.
+ * The system will call the pr_drain entry if it is low on space and
+ * this should throw away any non-critical data.
+ *
+ * Protocols pass data between themselves as chains of mbufs using
+ * the pr_input and pr_output hooks.  Pr_input passes data up (towards
+ * UNIX) and pr_output passes it down (towards the imps); control
+ * information passes up and down on pr_ctlinput and pr_ctloutput.
+ * The protocol is responsible for the space occupied by any the
+ * arguments to these entries and must dispose it.
+ *
+ * The userreq routine interfaces protocols to the system and is
+ * described below.
+ */
+struct protosw {
+       short   pr_type;                /* socket type used for */
+       short   pr_family;              /* protocol family */
+       short   pr_protocol;            /* protocol number */
+       short   pr_flags;               /* see below */
+/* protocol-protocol hooks */
+       int     (*pr_input)();          /* input to protocol (from below) */
+       int     (*pr_output)();         /* output to protocol (from above) */
+       int     (*pr_ctlinput)();       /* control input (from below) */
+       int     (*pr_ctloutput)();      /* control output (from above) */
+/* user-protocol hook */
+       int     (*pr_usrreq)();         /* user request: see list below */
+/* utility hooks */
+       int     (*pr_init)();           /* initialization hook */
+       int     (*pr_fasttimo)();       /* fast timeout (200ms) */
+       int     (*pr_slowtimo)();       /* slow timeout (500ms) */
+       int     (*pr_drain)();          /* flush any excess space possible */
+};
+
+#define        PR_SLOWHZ       2               /* 2 slow timeouts per second */
+#define        PR_FASTHZ       5               /* 5 fast timeouts per second */
+
+/*
+ * Values for pr_flags
+ */
+#define        PR_ATOMIC       0x01            /* exchange atomic messages only */
+#define        PR_ADDR         0x02            /* addresses given with messages */
+/* in the current implementation, PR_ADDR needs PR_ATOMIC to work */
+#define        PR_CONNREQUIRED 0x04            /* connection required by protocol */
+#define        PR_WANTRCVD     0x08            /* want PRU_RCVD calls */
+#define        PR_RIGHTS       0x10            /* passes capabilities */
+
+/*
+ * The arguments to usrreq are:
+ *     (*protosw[].pr_usrreq)(up, req, m, nam, opt);
+ * where up is a (struct socket *), req is one of these requests,
+ * m is a optional mbuf chain containing a message,
+ * nam is an optional mbuf chain containing an address,
+ * and opt is a pointer to a socketopt structure or nil.
+ * The protocol is responsible for disposal of the mbuf chain m,
+ * the caller is responsible for any space held by nam and opt.
+ * A non-zero return from usrreq gives an
+ * UNIX error number which should be passed to higher level software.
+ */
+#define        PRU_ATTACH              0       /* attach protocol to up */
+#define        PRU_DETACH              1       /* detach protocol from up */
+#define        PRU_BIND                2       /* bind socket to address */
+#define        PRU_LISTEN              3       /* listen for connection */
+#define        PRU_CONNECT             4       /* establish connection to peer */
+#define        PRU_ACCEPT              5       /* accept connection from peer */
+#define        PRU_DISCONNECT          6       /* disconnect from peer */
+#define        PRU_SHUTDOWN            7       /* won't send any more data */
+#define        PRU_RCVD                8       /* have taken data; more room now */
+#define        PRU_SEND                9       /* send this data */
+#define        PRU_ABORT               10      /* abort (fast DISCONNECT, DETATCH) */
+#define        PRU_CONTROL             11      /* control operations on protocol */
+#define        PRU_SENSE               12      /* return status into m */
+#define        PRU_RCVOOB              13      /* retrieve out of band data */
+#define        PRU_SENDOOB             14      /* send out of band data */
+#define        PRU_SOCKADDR            15      /* fetch socket's address */
+#define        PRU_PEERADDR            16      /* fetch peer's address */
+#define        PRU_CONNECT2            17      /* connect two sockets */
+/* begin for protocols internal use */
+#define        PRU_FASTTIMO            18      /* 200ms timeout */
+#define        PRU_SLOWTIMO            19      /* 500ms timeout */
+#define        PRU_PROTORCV            20      /* receive from below */
+#define        PRU_PROTOSEND           21      /* send to below */
+
+#define        PRU_NREQ                21
+
+#ifdef PRUREQUESTS
+char *prurequests[] = {
+       "ATTACH",       "DETACH",       "BIND",         "LISTEN",
+       "CONNECT",      "ACCEPT",       "DISCONNECT",   "SHUTDOWN",
+       "RCVD",         "SEND",         "ABORT",        "CONTROL",
+       "SENSE",        "RCVOOB",       "SENDOOB",      "SOCKADDR",
+       "PEERADDR",     "CONNECT2",     "FASTTIMO",     "SLOWTIMO",
+       "PROTORCV",     "PROTOSEND",
+};
+#endif
+
+/*
+ * The arguments to the ctlinput routine are
+ *     (*protosw[].pr_ctlinput)(cmd, arg);
+ * where cmd is one of the commands below, and arg is
+ * an optional argument (caddr_t).
+ *
+ * N.B. The IMP code, in particular, pressumes the values
+ *      of some of the commands; change with extreme care.
+ * TODO:
+ *     spread out codes so new ICMP codes can be
+ *     accomodated more easily
+ */
+#define        PRC_IFDOWN              0       /* interface transition */
+#define        PRC_ROUTEDEAD           1       /* select new route if possible */
+#define        PRC_QUENCH              4       /* some said to slow down */
+#define        PRC_MSGSIZE             5       /* message size forced drop */
+#define        PRC_HOSTDEAD            6       /* normally from IMP */
+#define        PRC_HOSTUNREACH         7       /* ditto */
+#define        PRC_UNREACH_NET         8       /* no route to network */
+#define        PRC_UNREACH_HOST        9       /* no route to host */
+#define        PRC_UNREACH_PROTOCOL    10      /* dst says bad protocol */
+#define        PRC_UNREACH_PORT        11      /* bad port # */
+#define        PRC_UNREACH_NEEDFRAG    12      /* IP_DF caused drop */
+#define        PRC_UNREACH_SRCFAIL     13      /* source route failed */
+#define        PRC_REDIRECT_NET        14      /* net routing redirect */
+#define        PRC_REDIRECT_HOST       15      /* host routing redirect */
+#define        PRC_REDIRECT_TOSNET     16      /* redirect for type of service & net */
+#define        PRC_REDIRECT_TOSHOST    17      /* redirect for tos & host */
+#define        PRC_TIMXCEED_INTRANS    18      /* packet lifetime expired in transit */
+#define        PRC_TIMXCEED_REASS      19      /* lifetime expired on reass q */
+#define        PRC_PARAMPROB           20      /* header incorrect */
+
+#define        PRC_NCMDS               21
+
+#ifdef PRCREQUESTS
+char   *prcrequests[] = {
+       "IFDOWN", "ROUTEDEAD", "#2", "#3",
+       "QUENCH", "MSGSIZE", "HOSTDEAD", "HOSTUNREACH",
+       "NET-UNREACH", "HOST-UNREACH", "PROTO-UNREACH", "PORT-UNREACH",
+       "FRAG-UNREACH", "SRCFAIL-UNREACH", "NET-REDIRECT", "HOST-REDIRECT",
+       "TOSNET-REDIRECT", "TOSHOST-REDIRECT", "TX-INTRANS", "TX-REASS",
+       "PARAMPROB"
+};
+#endif
+
+#ifdef KERNEL
+extern struct protosw *pffindproto(), *pffindtype();
+#endif
diff --git a/usr/src/sys/stand/Makefile b/usr/src/sys/stand/Makefile
new file mode 100644 (file)
index 0000000..a9e1e02
--- /dev/null
@@ -0,0 +1,238 @@
+#      Makefile        6.2     83/09/25
+
+DESTDIR=/
+CFLAGS=        -O -DSTANDALONE ${COPTS} 
+COPTS= -DVAX780 -DVAX750 -DVAX730
+730OPTS=-O -DSTANDALONE -DVAX730
+RELOC= 70000
+SRCS=  sys.c conf.c prf.c machdep.c \
+       autoconf.c hp.c hpmaptype.c ht.c idc.c mba.c mt.c rk.c \
+       rl.c tm.c ts.c \
+       up.c upmaptype.c uba.c uda.c ut.c \
+       drtest.c format.c up.old.c hp.old.c
+DRIVERS=autoconf.o hp.o hpmaptype.o ht.o idc.o mba.o mt.o \
+       rk.o rl.o tm.o ts.o \
+       up.o upmaptype.o uba.o uda.o ut.o
+# These drivers don't have ecc correction and bad sector forwarding;
+# they are placed in the file system boot area for 750's.  If your
+# root has bad sectors you can try and squeeze the newer drivers in...
+ODRIVERS=hp.old.o up.old.o
+
+ALL=   /usr/lib/libsa.a srt0.o boot tpboot copy tpcopy \
+       format tpformat drtest boothp boothk bootup bootra bootrl \
+       730boot 730copy 730format 730drtest
+
+all: ${ALL}
+
+/usr/lib/libsa.a: sys.o conf.o ${DRIVERS} prf.o machdep.o dkbad.o
+       ar crv /usr/lib/libsa.a $?
+       ranlib /usr/lib/libsa.a
+
+${ODRIVERS} ${DRIVERS}: savax.h
+       cc -c -S ${COPTS} $*.c
+       /lib/c2 -i $*.s | as -o $*.o
+       rm $*.s
+
+dkbad.o: ../vax/dkbad.c
+       ${CC} -c ${CFLAGS} ../vax/dkbad.c
+
+# startups
+
+srt0.o: srt0.c ../vax/mtpr.h ../vax/cpu.h
+       cc -E -DRELOC=0x${RELOC} ${COPTS} srt0.c | as -o srt0.o
+
+tpsrt0.o: srt0.c ../vax/mtpr.h ../vax/cpu.h
+       cc -E -DRELOC=0x${RELOC} -DTP ${COPTS} srt0.c | as -o tpsrt0.o 
+
+relsrt0.o: srt0.c ../vax/mtpr.h ../vax/cpu.h
+       cc -E -DRELOC=0x${RELOC} -DREL ${COPTS} srt0.c | as -o relsrt0.o
+
+# bootable from tape
+
+tpboot:        tpboot.o relsrt0.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} relsrt0.o tpboot.o -lsa -lc
+       cp a.out b.out; strip b.out; dd if=b.out of=tpboot ibs=32 skip=1; rm b.out
+
+tpboot.o: boot.c ../h/param.h ../h/inode.h ../h/fs.h
+tpboot.o: saio.h ../h/reboot.h ../h/vm.h 
+       cp boot.c tpboot.c; chmod +w tpboot.c
+       cc -c -O -DJUSTASK tpboot.c
+       rm tpboot.c
+
+tpcopy:        copy.o tpsrt0.o /usr/lib/libsa.a
+       ld -N tpsrt0.o copy.o -lsa -lc
+       cp a.out b.out; strip b.out; \
+               dd if=b.out of=tpcopy ibs=32 skip=1; rm b.out
+
+tpformat: format.o tpsrt0.o confhpup.o /usr/lib/libsa.a
+       cp format.c tpformat.c; chmod +w tpformat.c
+       cc -c -O -DJUSTEXIT tpformat.c
+       rm tpformat.c
+       ld -N tpsrt0.o tpformat.o confhpup.o -lsa -lc
+       cp a.out b.out; strip b.out; \
+               dd if=b.out of=tpformat ibs=32 skip=1; rm b.out
+
+# bootable from floppy or real disks
+
+boot:  boot.o relsrt0.o bootconf.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} -o boot relsrt0.o boot.o bootconf.o -lsa -lc
+
+bootconf.o: conf.c ../h/param.h ../h/inode.h ../machine/pte.h
+bootconf.o: ../h/fs.h saio.h ../vaxmba/mbareg.h
+       cp conf.c bootconf.c
+       cc -c ${COPTS} -DBOOT bootconf.c
+       rm bootconf.c
+
+copy:  copy.o srt0.o conf.o /usr/lib/libsa.a
+       ld -N -o copy srt0.o copy.o conf.o -lsa -lc
+
+format:        format.o srt0.o confhpup.o /usr/lib/libsa.a
+       ld -N -o format srt0.o format.o confhpup.o -lsa -lc
+
+drtest:        drtest.o srt0.o confhpup.o /usr/lib/libsa.a
+       ld -N -o drtest srt0.o drtest.o confhpup.o -lsa -lc
+
+# for 730s minimize size to avoid microcode botch
+# (won't load files larger than 12.5 Kbytes)
+
+730boot.o: boot.c ../h/param.h ../h/inode.h ../h/fs.h
+730boot.o: saio.h ../h/reboot.h ../h/vm.h 
+       cp boot.c 730boot.c; chmod +w 730boot.c
+       cc -c ${730OPTS} 730boot.c
+       rm 730boot.c
+
+730boot: 730boot.o relsrt0.o 730bootconf.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} -o 730boot relsrt0.o 730boot.o 730bootconf.o -lsa -lc
+
+730bootconf.o: conf.c ../h/param.h ../h/inode.h ../machine/pte.h
+730bootconf.o: ../h/fs.h saio.h
+       cp conf.c 730bootconf.c
+       cc -c ${730OPTS} -DBOOT 730bootconf.c
+       rm -f 730bootconf.c
+
+730copy: copy.o srt0.o 730conf.o /usr/lib/libsa.a
+       ld -N -o 730copy srt0.o copy.o 730conf.o -lsa -lc
+
+730drtest: drtest.o srt0.o confup.o /usr/lib/libsa.a
+       ld -N -o 730drtest srt0.o drtest.o confup.o -lsa -lc
+
+730format: format.o srt0.o confup.o /usr/lib/libsa.a
+       ld -N -o 730format srt0.o format.o confup.o -lsa -lc
+
+730conf.o: conf.c ../h/param.h ../h/inode.h ../machine/pte.h
+730conf.o: ../h/fs.h saio.h
+       cp conf.c 730conf.c
+       cc -c ${730OPTS} 730conf.c
+       rm -f 730conf.c
+
+# bootstrap from ether
+
+### not yet, rosin, not yet ###
+
+# getting booted from disc
+
+boothk: relsrt0.o boothk.o confrk.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} relsrt0.o boothk.o confrk.o -lsa -lc
+       cp a.out b.out;strip b.out;dd if=b.out of=boothk ibs=32 skip=1;rm b.out
+
+boothp: relsrt0.o boothp.o confhp.o hp.old.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} relsrt0.o boothp.o confhp.o hp.old.o -lsa -lc
+       cp a.out b.out;strip b.out;dd if=b.out of=boothp ibs=32 skip=1;rm b.out
+
+bootup: relsrt0.o bootup.o confup.o up.old.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} relsrt0.o bootup.o confup.o up.old.o -lsa -lc
+       cp a.out b.out;strip b.out;dd if=b.out of=bootup ibs=32 skip=1;rm b.out
+
+bootra: relsrt0.o bootra.o confra.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} relsrt0.o bootra.o confra.o -lsa -lc
+       cp a.out b.out;strip b.out;dd if=b.out of=bootra ibs=32 skip=1;rm b.out
+
+bootrl: relsrt0.o bootrl.o confrl.o /usr/lib/libsa.a
+       ld -N -T ${RELOC} relsrt0.o bootrl.o confrl.o -lsa -lc
+       cp a.out b.out;strip b.out;dd if=b.out of=bootrl ibs=32 skip=1;rm b.out
+
+boothp.o: boothp.c ../h/param.h ../h/inode.h ../machine/pte.h ../h/reboot.h
+boothp.o: ../h/fs.h saio.h
+boothk.o: boothk.c ../h/param.h ../h/inode.h ../machine/pte.h ../h/reboot.h
+boothk.o: ../h/fs.h saio.h
+bootup.o: bootup.c ../h/param.h ../h/inode.h ../machine/pte.h ../h/reboot.h
+bootup.o: ../h/fs.h saio.h
+bootra.o: bootra.c ../h/param.h ../h/inode.h ../machine/pte.h ../h/reboot.h
+bootra.o: ../h/fs.h saio.h
+bootrl.o: bootrl.c ../h/param.h ../h/inode.h ../machine/pte.h ../h/reboot.h
+bootrl.o: ../h/fs.h saio.h
+
+boothk.c: bootxx.c
+       sed -e 's/xx/hk/g' <bootxx.c >boothk.c
+boothp.c: bootxx.c
+       sed -e 's/xx/hp/g' <bootxx.c >boothp.c
+bootup.c: bootxx.c
+       sed -e 's/xx/up/g' <bootxx.c >bootup.c
+bootra.c: bootxx.c
+       sed -e 's/xx/ra/g' <bootxx.c >bootra.c
+bootrl.c: bootxx.c
+       sed -e 's/xx/rl/g' <bootxx.c >bootrl.c
+
+confrk.o: confrk.c ../h/param.h ../h/fs.h ../machine/pte.h ../h/inode.h saio.h
+confhp.o: confhp.c ../h/param.h ../h/fs.h ../machine/pte.h ../h/inode.h saio.h
+confup.o: confup.c ../h/param.h ../h/fs.h ../machine/pte.h ../h/inode.h saio.h
+confra.o: confra.c ../h/param.h ../h/fs.h ../machine/pte.h ../h/inode.h saio.h
+confrl.o: confrl.c ../h/param.h ../h/fs.h ../machine/pte.h ../h/inode.h saio.h
+
+confrk.c: confxx.c
+       sed -e 's/XX/hk/' -e 's/xx/rk/g' <confxx.c >confrk.c
+confhp.c: confxx.c
+       sed -e 's/XX/hp/' -e 's/xx/hp/g' <confxx.c >confhp.c
+confup.c: confxx.c
+       sed -e 's/XX/up/' -e 's/xx/up/g' <confxx.c >confup.c
+confra.c: confxx.c
+       sed -e 's/XX/ra/' -e 's/xx/ra/g' <confxx.c >confra.c
+confrl.c: confxx.c
+       sed -e 's/XX/rl/' -e 's/xx/rl/g' <confxx.c >confrl.c
+
+# utilities
+
+print:
+       @pr makefile
+       @ls -l | pr 
+       @pr *.h *.c
+
+clean:
+       rm -f *.o *.exe *.i errs
+       rm -f a.out b.out boot cat tpboot tpcopy copy tpformat
+       rm -f boot[a-z]? boot[a-wyz][a-z].c conf[a-wyz][a-z].c
+       rm -f format drtest core sboot bootconf.c
+       rm -f 730boot 730copy 730drtest 730format
+
+lint:
+       lint ${COPTS} -hxbn boot.c ${SRCS} | \
+           grep -v 'possible pointer alignment' | \
+           grep -v 'struct/union .* never defined'
+
+install: ${ALL}
+       cp tpcopy ${DESTDIR}/tp/copy
+       cp tpboot ${DESTDIR}/tp/boot
+       cp tpformat ${DESTDIR}/tp/format
+       cp boot a.out; strip a.out; \
+               dd if=a.out of=../floppy/boot bs=32 skip=1
+       cp 730boot a.out; strip a.out; \
+               dd if=a.out of=../cassette/boot.730 bs=32 skip=1
+       cp ../floppy/boot ../cassette/boot.750
+       cp copy a.out; strip a.out; \
+               dd if=a.out of=../floppy/copy bs=32 skip=1
+       cp 730copy a.out; strip a.out; \
+               dd if=a.out of=../cassette/copy.730 bs=32 skip=1
+       cp ../floppy/copy ../cassette/copy.750
+       cp format a.out; strip a.out; \
+               dd if=a.out of=../floppy/format bs=32 skip=1
+       cp 730format a.out; strip a.out; \
+               dd if=a.out of=../cassette/format.730 bs=32 skip=1
+       cp ../floppy/format ../cassette/format.750
+       cp drtest a.out; strip a.out; \
+               dd if=a.out of=../floppy/drtest bs=32 skip=1
+       cp 730drtest a.out; strip a.out; \
+               dd if=a.out of=../cassette/drtest.730 bs=32 skip=1
+       cp ../floppy/drtest ../cassette/drtest.750
+       cp bootup boothk boothp bootra bootrl ${DESTDIR}/usr/mdec
+
+# beware...
diff --git a/usr/src/sys/stand/format.c b/usr/src/sys/stand/format.c
new file mode 100644 (file)
index 0000000..58e667b
--- /dev/null
@@ -0,0 +1,501 @@
+/*     format.c        6.3     83/09/23        */
+
+
+/* 
+ * Standalone program to do media checking
+ * and record bad block information on any 
+ * disk with the appropriate driver and RM03-style headers.
+ */
+#include "../h/param.h"
+#include "../h/fs.h"
+#include "../h/inode.h"
+#include "../h/dkbad.h"
+#include "../h/vmmac.h"
+
+#include "saio.h"
+#include "savax.h"
+
+#define MAXBADDESC     126             /* size of bad block table */
+#define CHUNK          48              /* max # of sectors/io operation */
+#define SECTSIZ                512             /* standard sector size */
+#define HDRSIZ         4               /* number of bytes in sector header */
+
+#define SSERR          0
+#define BSERR          1
+
+#define SSDEV          ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0))
+
+struct sector {
+       u_short header1;
+       u_short header2;
+       char    buf[SECTSIZ];
+};
+
+struct dkbad dkbad;            /* bad sector table */
+struct dkbad sstab;            /* skip sector table */
+
+#define        NERRORS         6
+static char *
+errornames[NERRORS] = {
+#define        FE_BSE          0
+       "Bad sector",
+#define        FE_WCE          1
+       "Write check",
+#define        FE_ECC          2
+       "ECC",
+#define        FE_HARD         3
+       "Other hard",
+#define        FE_TOTAL        4
+       "Total",
+#define        FE_SSE          5
+       "Skip sector",
+};
+
+int    errors[NERRORS];        /* histogram of errors */
+int    pattern;
+
+/*
+ * Purdue/EE severe burnin patterns.
+ */
+unsigned short ppat[] = {
+0031463,0070707,0133333,0155555,0161616,0143434,
+0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525,
+0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
+#ifndef        SHORTPASS
+0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
+ 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525,
+#endif
+ 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525
+ };
+
+#define        NPT     (sizeof (ppat) / sizeof (short))
+int    npat;           /* subscript to ppat[] */
+int    severe;         /* nz if running "severe" burnin */
+int    nbads;          /* subscript for bads */
+long   bads[MAXBADDESC]; /* Bad blocks accumulated */
+
+char   *malloc();
+int    qcompar();
+char   *prompt();
+extern int end;
+
+main()
+{
+       register int sector, sn;
+       int lastsector, tracksize, rtracksize;
+       int unit, fd, resid, i, trk, cyl, debug;
+       struct st st;
+       struct sector *bp, *cbp;
+       char *rbp, *rcbp;
+       int pass, maxpass;
+       char *cp;
+
+       printf("Disk format/check utility\n\n");
+
+again:
+       nbads = 0;
+       cp = prompt("Enable debugging (0=none, 1=bse, 2=ecc, 3=bse+ecc)? ");
+       debug = atoi(cp);
+       if (debug < 0)
+               debug = 0;
+       for (i = 0; i < NERRORS; i++)
+               errors[i] = 0;
+       fd = getdevice();
+       ioctl(fd, SAIODEVDATA, &st);
+       printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n",
+         st.ncyl, st.ntrak, st.nsect);
+       if (getpattern())
+               goto again;
+       printf("Start formatting...make sure the drive is online\n");
+       if (severe)
+               ioctl(fd, SAIOSEVRE, (char *) 0);
+       ioctl(fd, SAIONOBAD, (char *)0);
+       ioctl(fd, SAIOECCLIM, (char *)0);
+       ioctl(fd, SAIODEBUG, (char *)debug);
+       if (SSDEV) {
+               if (severe) {
+                       printf("Severe burnin doesn't work with RM80 yet\n");
+                       exit(1);
+               }
+               ioctl(fd, SAIOSSI, (char *)0);  /* set skip sector inhibit */
+               st.nsect++;
+               st.nspc += st.ntrak;
+       }
+       tracksize = sizeof (struct sector) * st.nsect;
+       rtracksize = SECTSIZ * st.nsect;
+       bp = (struct sector *)malloc(tracksize);
+       rbp = malloc(rtracksize);
+       if (severe) {
+               npat = 0;
+               maxpass = NPT;
+       } else
+               maxpass = 1;
+       for (pass = 0; pass < maxpass; pass++) {
+               if (severe)
+                       printf("Begin pass %d\n", pass);
+               bufinit(bp, tracksize);
+               if (severe)
+                       npat++;
+               /*
+                * Begin check, for each track,
+                *
+                * 1) Write header and test pattern.
+                * 2) Read data.  Hardware checks header and data ECC.
+                *    Read data (esp on Eagles) is much faster when write check.
+                */
+               lastsector = st.nspc * st.ncyl;
+               for (sector = 0; sector < lastsector; sector += st.nsect) {
+                       cyl = sector / st.nspc;
+                       trk = (sector % st.nspc) / st.nsect;
+                       for (i = 0; i < st.nsect; i++) {
+                               bp[i].header1 =
+                                       (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
+                               bp[i].header2 = ((u_short)trk << 8) + i;
+                       }
+                       if (sector && (sector % (st.nspc * 100)) == 0)
+                               printf("cylinder %d\n", cyl);
+                       /*
+                        * Try and write the headers and data patterns into
+                        * each sector in the track.  Continue until such
+                        * we're done, or until there's less than a sector's
+                        * worth of data to transfer.
+                        *
+                        * The lseek call is necessary because of
+                        * the odd sector size (516 bytes)
+                        */
+                       for (resid = tracksize, cbp = bp, sn = sector;;) {
+                               int cc;
+
+                               lseek(fd, sn * SECTSIZ, 0);
+                               ioctl(fd, SAIOHDR, (char *)0);
+                               cc = write(fd, cbp, resid);
+                               if (cc == resid)
+                                       break;
+                               /*
+                                * Don't record errors during write,
+                                * all errors will be found during
+                                * writecheck performed below.
+                                */
+                               sn = iob[fd - 3].i_errblk;
+                               cbp += sn - sector;
+                               resid -= (sn - sector) * sizeof (struct sector);
+                               if (resid < sizeof (struct sector)) 
+                                       break;
+                       }
+                       /*
+                        * Read test patterns.
+                        * Retry remainder of track on error until
+                        * we're done, or until there's less than a
+                        * sector to verify.
+                        */
+                       for (resid = rtracksize, rcbp = rbp, sn = sector;;) {
+                               int cc;
+
+                               lseek(fd, sn * SECTSIZ, 0);
+                               cc = read(fd, rcbp, resid);
+                               if (cc == resid)
+                                       break;
+                               sn = iob[fd-3].i_errblk;
+                               printf("sector %d, read error\n", sn);
+                               if (recorderror(fd, sn, &st) < 0 && pass > 0)
+                                       goto out;
+                               /* advance past bad sector */
+                               sn++;
+                               rcbp += sn - sector;
+                               resid -= ((sn - sector) * SECTSIZ);
+                               if (resid < SECTSIZ) 
+                                       break;
+                       }
+               }
+       }
+       /*
+        * Checking finished.
+        */
+out:
+       if (severe && nbads) {
+               /*
+                * Sort bads and insert in bad block table.
+                */
+               qsort(bads, nbads, sizeof (long), qcompar);
+               severe = 0;
+               for (i = 0; i < nbads; i++) {
+                       errno = EECC;   /* for now */
+                       recorderror(fd, bads[i], &st);
+               }
+               severe++;
+       }
+       if (errors[FE_TOTAL] || errors[FE_SSE]) {
+               printf("Errors:\n");
+               for (i = 0; i < NERRORS; i++)
+                       printf("%s: %d\n", errornames[i], errors[i]);
+               printf("Total of %d hard errors found\n",
+                       errors[FE_TOTAL] + errors[FE_SSE]);
+               /* change the headers of all the bad sectors */
+               writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
+               writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
+       }
+       while (errors[FE_TOTAL] < MAXBADDESC) {
+               int i = errors[FE_TOTAL]++;
+
+               dkbad.bt_bad[i].bt_cyl = -1;
+               dkbad.bt_bad[i].bt_trksec = -1;
+       }
+       printf("\nWriting bad sector table at sector #%d\n",
+               st.ncyl * st.nspc - st.nsect);
+       /* place on disk */
+       for (i = 0; i < 10; i += 2) {
+               lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
+               write(fd, &dkbad, sizeof (dkbad));
+       }
+       printf("Done\n");
+       ioctl(fd,SAIONOSSI,(char *)0);
+       close(fd);
+/*
+       if (severe) {
+               asm("halt");
+               exit(0);
+       }
+*/
+#ifndef JUSTEXIT
+       goto again;
+#endif
+}
+
+qcompar(l1, l2)
+register long *l1, *l2;
+{
+       if (*l1 < *l2)
+               return(-1);
+       if (*l1 == *l2)
+               return(0);
+       return(1);
+}
+
+/*
+ * Write out the bad blocks.
+ */
+writebb(fd, nsects, dbad, st, sw)
+       int nsects, fd;
+       struct dkbad *dbad;
+       register struct st *st;
+{
+       struct sector bb_buf; /* buffer for one sector plus 4 byte header */
+       register int i;
+       int bn, j;
+       struct bt_bad *btp;
+
+       for (i = 0; i < nsects; i++) {
+               btp = &dbad->bt_bad[i];
+               if (sw == BSERR) {
+                       bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
+                       if (SSDEV)
+                               bb_buf.header1 |= HDR1_SSF;
+               } else
+                       bb_buf.header1 =
+                              btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
+               bb_buf.header2 = btp->bt_trksec;
+               bn = st->nspc * btp->bt_cyl +
+                    st->nsect * (btp->bt_trksec >> 8) +
+                    (btp->bt_trksec & 0xff);
+               lseek(fd, bn * SECTSIZ, 0);
+               ioctl(fd, SAIOHDR, (char *)0);
+               write(fd, &bb_buf, sizeof (bb_buf));
+               if (!SSDEV)
+                       continue;
+               /*
+                * If skip sector, mark all remaining
+                * sectors on the track.
+                */
+               for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) {
+                       bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF;
+                       ioctl(fd, SAIOHDR, (char *)0);
+                       write(fd, &bb_buf, sizeof (bb_buf));
+               }
+       }
+}
+
+/*
+ * Record an error, and if there's room, put
+ * it in the appropriate bad sector table.
+ *
+ * If severe burnin store block in a list after making sure
+ * we have not already found it on a prev pass.
+ */
+recorderror(fd, bn, st)
+       int fd, bn;
+       register struct st *st;
+{
+       int cn, tn, sn, strk;
+       register i;
+
+       
+       if (severe) {
+               for (i = 0; i < nbads; i++)
+                       if (bads[i] == bn)
+                               return(0);      /* bn already flagged */
+               if (nbads >= MAXBADDESC) {
+                       printf("Bad sector table full, burnin terminating\n");
+                       return(-1);
+               }
+               bads[nbads++] = bn;
+               return(0);
+       }
+       if (errors[FE_TOTAL] >= MAXBADDESC) {
+               printf("Too many bad sectors\n");
+               return(-1);
+       }
+       if (errors[FE_SSE] >= MAXBADDESC) {
+               printf("Too many skip sector errors\n");
+               return(-1);
+       }
+       if (errno < EBSE || errno > EHER)
+               return(0);
+       errno -= EBSE;
+       errors[errno]++;
+       cn = bn / st->nspc;
+       sn = bn % st->nspc;
+       tn = sn / st->nsect;
+       sn %= st->nsect;
+       if (SSDEV) {            /* if drive has skip sector capability */
+               int ss = errors[FE_SSE]++;
+
+               if (ss)
+                       strk = sstab.bt_bad[ss - 1].bt_trksec >> 8;
+               else
+                       strk = -1;
+               if (tn != strk) {         /* only one skip sector/track */
+                       sstab.bt_bad[ss].bt_cyl = cn;
+                       sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
+                       return;
+               }
+               cn = -cn;
+       }
+       /* record the bad sector address and continue */
+       dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn;
+       dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
+       return(0);
+}
+
+/*
+ * Allocate memory on a page-aligned address.
+ * Round allocated chunk to a page multiple to
+ * ease next request.
+ */
+char *
+malloc(size)
+       int size;
+{
+       char *result;
+       static caddr_t last = 0;
+
+       if (last == 0)
+               last = (caddr_t)(((int)&end + 511) & ~0x1ff);
+       size = (size + 511) & ~0x1ff;
+       result = (char *)last;
+       last += size;
+       return (result);
+}
+
+/*
+ * Prompt and verify a device name from the user.
+ */
+getdevice()
+{
+       register char *cp;
+       register struct devsw *dp;
+       int fd;
+
+top:
+       cp = prompt("Device to format? ");
+       if ((fd = open(cp, 2)) < 0) {
+               printf("Known devices are: ");
+               for (dp = devsw; dp->dv_name; dp++)
+                       printf("%s ",dp->dv_name);
+               printf("\n");
+               goto top;
+       }
+       printf("Formatting drive %c%c%d on adaptor %d: ",
+               cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8);
+       cp = prompt("verify (yes/no)? ");
+       while (*cp != 'y' && *cp != 'n')
+               cp = prompt("Huh, yes or no? ");
+       if (*cp == 'y')
+               return (fd);
+       goto top;
+}
+
+static struct pattern {
+       long    pa_value;
+       char    *pa_name;
+} pat[] = {
+       { 0xf00ff00f,   "RH750 worst case" },
+       { 0xec6dec6d,   "media worst case" },
+       { 0xa5a5a5a5,   "alternate 1's and 0's" },
+       { 0xFFFFFFFF,   "Severe burnin (takes several hours)" },
+       { 0, 0 },
+};
+
+getpattern()
+{
+       register struct pattern *p;
+       int npatterns;
+       char *cp;
+
+       printf("Available test patterns are:\n");
+       for (p = pat; p->pa_value; p++)
+               printf("\t%d - (%x) %s\n", (p - pat) + 1,
+                 p->pa_value & 0xffff, p->pa_name);
+       npatterns = p - pat;
+       cp = prompt("Pattern (one of the above, other to restart)? ");
+       pattern = atoi(cp) - 1;
+       severe = 0;
+       if (pat[pattern].pa_value == -1)
+               severe = 1;
+       return (pattern < 0 || pattern >= npatterns);
+}
+
+struct xsect {
+       u_short hd1;
+       u_short hd2;
+       long    buf[128];
+};
+
+/*
+ * Initialize the buffer with the requested pattern. 
+ */
+bufinit(bp, size)
+       register struct xsect *bp;
+       int size;
+{
+       register struct pattern *pptr;
+       register long *pp, *last;
+       register struct xsect *lastbuf;
+       int patt;
+
+       size /= sizeof (struct sector);
+       lastbuf = bp + size;
+       if (severe) {
+               patt = ppat[npat] | ((long)ppat[npat] << 16);
+               printf("Write pattern 0x%x\n", patt&0xffff);
+       } else {
+               pptr = &pat[pattern];
+               patt = pptr->pa_value;
+       }
+       while (bp < lastbuf) {
+               last = &bp->buf[128];
+               for (pp = bp->buf; pp < last; pp++)
+                       *pp = patt;
+               bp++;
+       }
+}
+
+char *
+prompt(msg)
+       char *msg;
+{
+       static char buf[132];
+
+       printf("%s", msg);
+       gets(buf);
+       return (buf);
+}
diff --git a/usr/src/sys/stand/hp.c b/usr/src/sys/stand/hp.c
new file mode 100644 (file)
index 0000000..a9a25fe
--- /dev/null
@@ -0,0 +1,520 @@
+/*     hp.c    6.3     83/09/23        */
+
+/*
+ * RP??/RM?? disk driver
+ * with ECC handling and bad block forwarding.
+ * Also supports header io operations and
+ * commands to write check header and data.
+ */
+#include "../h/param.h"
+#include "../h/inode.h"
+#include "../h/fs.h"
+#include "../h/dkbad.h"
+
+#include "../vax/pte.h"
+#include "../vaxmba/hpreg.h"
+#include "../vaxmba/mbareg.h"
+
+#include "saio.h"
+#include "savax.h"
+
+#define        MASKREG(reg)    ((reg)&0xffff)
+
+#define        MAXBADDESC      126
+#define        SECTSIZ         512     /* sector size in bytes */
+#define        HDRSIZ          4       /* number of bytes in sector header */
+#define        MAXECC          5       /* max # bits allow in ecc error w/ F_ECCLM */
+
+char   hp_type[MAXNMBA*8] = { 0 };
+extern struct st hpst[];
+
+short  hptypes[] = {
+       MBDT_RM03,
+       MBDT_RM05,
+       MBDT_RP06,
+       MBDT_RM80,
+       MBDT_RP05,
+       MBDT_RP07,
+       MBDT_ML11A,
+       MBDT_ML11B,
+       -1,             /* 9755 */
+       -1,             /* 9730 */
+       -1,             /* Capricorn */
+       -1,             /* Eagle */
+       MBDT_RM02,      /* actually something else */
+       -1,             /* 9300 */
+       0
+};
+
+#define        RP06 (hptypes[hp_type[unit]] <= MBDT_RP06)
+#define        ML11 (hptypes[hp_type[unit]] == MBDT_ML11A)
+#define        RM80 (hptypes[hp_type[unit]] == MBDT_RM80)
+
+u_char hp_offset[16] = {
+    HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
+    HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
+    HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
+    0, 0, 0, 0,
+};
+
+struct dkbad hpbad[MAXNMBA*8];
+int    ssect[MAXNMBA*8];               /* 1 when on track w/skip sector */
+
+int    hpdebug[MAXNMBA*8];
+#define        HPF_BSEDEBUG    01      /* debugging bad sector forwarding */
+#define        HPF_ECCDEBUG    02      /* debugging ecc correction */
+
+int    sectsiz;
+
+/*
+ * When awaiting command completion, don't
+ * hang on to the status register since
+ * this ties up some controllers.
+ */
+#define        HPWAIT(addr) \
+       while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500);
+
+hpopen(io)
+       register struct iob *io;
+{
+       register unit = io->i_unit;
+       struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
+       register struct st *st;
+
+       mbainit(UNITTOMBA(unit));
+       if (hp_type[unit] == 0) {
+               register i, type = hpaddr->hpdt & MBDT_TYPE;
+               struct iob tio;
+
+               for (i = 0; hptypes[i]; i++)
+                       if (hptypes[i] == type)
+                               goto found;
+               _stop("unknown drive type");
+found:
+               hpaddr->hpcs1 = HP_DCLR|HP_GO;          /* init drive */
+               hpaddr->hpcs1 = HP_PRESET|HP_GO;
+               if (!ML11)
+                       hpaddr->hpof = HPOF_FMT22;
+               hp_type[unit] = hpmaptype(hpaddr, i, unit);
+               /*
+                * Read in the bad sector table.
+                */
+               st = &hpst[hp_type[unit]];
+               tio = *io;
+               tio.i_bn = st->nspc * st->ncyl - st->nsect;
+               tio.i_ma = (char *)&hpbad[unit];
+               tio.i_cc = sizeof (struct dkbad);
+               tio.i_flgs |= F_RDDATA;
+               for (i = 0; i < 5; i++) {
+                       if (hpstrategy(&tio, READ) == sizeof (struct dkbad))
+                               break;
+                       tio.i_bn += 2;
+               }
+               if (i == 5) {
+                       printf("Unable to read bad sector table\n");
+                       for (i = 0; i < MAXBADDESC; i++) {
+                               hpbad[unit].bt_bad[i].bt_cyl = -1;
+                               hpbad[unit].bt_bad[i].bt_trksec = -1;
+                       }
+               }       
+       }
+       if (io->i_boff < 0 || io->i_boff > 7 ||
+           st->off[io->i_boff]== -1)
+               _stop("hp bad minor");
+       io->i_boff = st->off[io->i_boff] * st->nspc;
+}
+
+hpstrategy(io, func)
+       register struct iob *io;
+{
+       register unit = io->i_unit;
+       struct mba_regs *mba = mbamba(unit);
+       daddr_t bn, startblock;
+       struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
+       struct st *st = &hpst[hp_type[unit]];
+       int cn, tn, sn, bytecnt, bytesleft; 
+       char *membase;
+       int er1, er2, hprecal;
+
+       sectsiz = SECTSIZ;
+       if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0)
+               sectsiz += HDRSIZ;
+       if ((hpaddr->hpds & HPDS_VV) == 0) {
+               hpaddr->hpcs1 = HP_DCLR|HP_GO;
+               hpaddr->hpcs1 = HP_PRESET|HP_GO;
+               if (!ML11)
+                       hpaddr->hpof = HPOF_FMT22;
+       }
+       io->i_errcnt = 0;
+       ssect[unit] = 0;
+       bytecnt = io->i_cc;
+       membase = io->i_ma;
+       startblock = io->i_bn;
+       hprecal = 0;
+
+restart:
+       bn = io->i_bn;
+       cn = bn/st->nspc;
+       sn = bn%st->nspc;
+       tn = sn/st->nsect;
+       sn = sn%st->nsect + ssect[unit];
+
+       HPWAIT(hpaddr);
+       mba->mba_sr = -1;
+       if (ML11)
+               hpaddr->hpda = bn;
+       else {
+               hpaddr->hpdc = cn;
+               hpaddr->hpda = (tn << 8) + sn;
+       }
+       if (mbastart(io, func) != 0)            /* start transfer */
+               return (-1);
+       HPWAIT(hpaddr);
+       /*
+        * Successful data transfer, return.
+        */
+       if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0)
+               goto done;
+
+       /*
+        * Error handling.  Calculate location of error.
+        */
+       bytesleft = MASKREG(mba->mba_bcr);
+       if (bytesleft) 
+               bytesleft |= 0xffff0000;        /* sxt */
+       bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz;
+       er1 = MASKREG(hpaddr->hper1);
+       er2 = MASKREG(hpaddr->hper2);
+       if (er1 & (HPER1_DCK|HPER1_ECH))
+               bn--;   /* Error is in Prev block */
+       cn = bn/st->nspc;
+       sn = bn%st->nspc;
+       tn = sn/st->nsect;
+       sn = sn%st->nsect;
+       if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG)) {
+               printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b\n",
+                       cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
+               printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS);
+               printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft,
+                       hpaddr->hpof, hpaddr->hpda);
+       }
+       if (er1 & HPER1_HCRC) {
+               er1 &= ~(HPER1_HCE|HPER1_FER);
+               er2 &= ~HPER2_BSE;
+       }
+       /*
+        * Give up early if drive write locked.
+        */
+       if (er1&HPER1_WLE) {
+               printf("hp%d: write locked\n", unit);
+               return (-1);
+       }
+       /*
+        * Interpret format error bit as a bad block on RP06's.
+        */
+       if (MASKREG(er1) == HPER1_FER && RP06)
+               goto badsect;
+
+       /*
+        * If a hard error, or maximum retry count
+        * exceeded, clear controller state and
+        * pass back error to caller.
+        */
+       if (++io->i_errcnt > 27 || (er1 & HPER1_HARD) ||
+           (!ML11 && (er2 & HPER2_HARD))) {
+               /*
+                * The last ditch effort to bad sector forward
+                * below will probably fail since mba byte ctr
+                * (bcr) is different for BSE and ECC errors and
+                * the wrong block will be revectored to if one
+                * has 2 contiguous bad blocks and reads the second.
+                * For now, we can probably just let a header CRC
+                * error be handled like a BSE since no data will
+                * have been transferred and the bcr should the same
+                * as it would with a BSE error.
+                * --ghg.
+                */
+               if (er1 & HPER1_HCRC) 
+                       if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0)
+                               goto success;
+hard0:
+               io->i_error = EHER;
+               if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR))
+                       io->i_error = EWCK;
+hard:
+               io->i_errblk = bn + ssect[unit];
+               printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
+                          cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
+               printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
+               if (hpaddr->hpmr)
+                       printf(" mr1=%o", MASKREG(hpaddr->hpmr));
+               if (hpaddr->hpmr2)
+                       printf(" mr2=%o", MASKREG(hpaddr->hpmr2));
+               if (hpdebug[unit] & (HPF_BSEDEBUG|HPF_ECCDEBUG))
+                       printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc),
+                         MASKREG(hpaddr->hpda));
+               hpaddr->hpcs1 = HP_DCLR|HP_GO;
+               printf("\n");
+               bytecnt = -1;
+               goto done;
+
+       }
+       /*
+        * Attempt to forward bad sectors on
+        * anything but an ML11.  If drive
+        * supports skip sector handling, try to
+        * use it first; otherwise try the
+        * bad sector table.
+        */
+       if ((er2 & HPER2_BSE) && !ML11) {
+badsect:
+               if (!ssect[unit] && (er2&HPER2_SSE))
+                       goto skipsect;
+               if (io->i_flgs & F_NBSF) {
+                       io->i_error = EBSE;     
+                       goto hard;
+               }
+               if (hpecc(io, BSE) == 0)
+                       goto success;
+               io->i_error = EBSE;
+               goto hard;
+       }
+
+       /*
+        * Skip sector handling.
+        */
+       if (RM80 && (er2 & HPER2_SSE)) {
+skipsect:
+               (void) hpecc(io, SSE);
+               ssect[unit] = 1;
+               goto success;
+       }
+       /*
+        * ECC correction?
+        */
+       if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) {
+               if (hpecc(io, ECC) == 0)
+                       goto success;
+               io->i_error = EECC;
+               io->i_errblk = bn + ssect[unit];
+               return (-1);    
+       } 
+#ifdef F_SEVRE
+       if (io->i_flgs & F_SEVRE)
+               goto hard;
+#endif
+       if (ML11 && (io->i_errcnt >= 16))
+               goto hard0;
+       /* fall thru to retry */
+       hpaddr->hpcs1 = HP_DCLR|HP_GO;
+       HPWAIT(hpaddr);
+
+       /* 
+        * Every fourth retry recalibrate.
+        */
+       if (((io->i_errcnt & 07) == 4) ) {
+               hpaddr->hpcs1 = HP_RECAL|HP_GO;
+               HPWAIT(hpaddr);
+               hpaddr->hpdc = cn;
+               hpaddr->hpcs1 = HP_SEEK|HP_GO;
+               HPWAIT(hpaddr);
+       }
+
+       if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) {
+               hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22;
+               hpaddr->hpcs1 = HP_OFFSET|HP_GO;
+               HPWAIT(hpaddr);
+       }
+       if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG))
+               printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
+                 io->i_bn, io->i_cc, io->i_ma, hprecal);
+       goto restart;   /* retry whole transfer  --ghg */
+
+success:
+       /*
+        * On successful error recovery, bump
+        * block number to advance to next portion
+        * of i/o transfer.
+        */
+       bn++;
+       if ((bn-startblock) * sectsiz < bytecnt) {
+               io->i_bn = bn;
+               io->i_ma = membase + (io->i_bn - startblock)*sectsiz;
+               io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz;
+               if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG))
+                       printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
+                         io->i_bn, io->i_cc, io->i_ma, hprecal);
+               goto restart;
+       }
+done:
+       if (io->i_errcnt >= 16) {
+               hpaddr->hpcs1 = HP_RTC|HP_GO;
+               while (hpaddr->hpds & HPDS_PIP)
+                       ;
+       }
+       return (bytecnt);
+}
+
+hpecc(io, flag)
+       register struct iob *io;
+       int flag;
+{
+       register unit = io->i_unit;
+       register struct mba_regs *mbp = mbamba(unit);
+       register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit);
+       register struct st *st = &hpst[hp_type[unit]];
+       int npf, bn, cn, tn, sn, bcr;
+
+       bcr = MASKREG(mbp->mba_bcr);
+       if (bcr)
+               bcr |= 0xffff0000;              /* sxt */
+       npf = (bcr + io->i_cc) / sectsiz;       /* # sectors read */
+       if (flag == ECC)
+               npf--;          /* Error is in prev block --ghg */
+       bn = io->i_bn + npf + ssect[unit];      /* physical block #*/
+       if (hpdebug[unit]&HPF_ECCDEBUG)
+               printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n",
+                       bcr, npf, ssect[unit], sectsiz, io->i_cc);
+       /*
+        * ECC correction logic.
+        */
+       if (flag == ECC) {
+               register int i;
+               caddr_t addr;
+               int bit, o, mask, ecccnt = 0;
+
+               printf("hp%d: soft ecc sn%d\n", unit, bn);
+               mask = MASKREG(rp->hpec2);
+               i = MASKREG(rp->hpec1) - 1;     /* -1 makes 0 origin */
+               bit = i&07;
+               o = (i & ~07) >> 3;
+               rp->hpcs1 = HP_DCLR | HP_GO;
+               while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) {
+                       addr = io->i_ma + (npf*sectsiz) + o;
+                       /*
+                        * No data transfer occurs with a write check,
+                        * so don't correct the resident copy of data.
+                        */
+                       if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
+                               if (hpdebug[unit] & HPF_ECCDEBUG)
+                                       printf("addr=%x old=%x ", addr,
+                                               (*addr & 0xff));
+                               *addr ^= (mask << bit);
+                               if (hpdebug[unit] & HPF_ECCDEBUG)
+                                       printf("new=%x\n",(*addr & 0xff));
+                       }
+                       o++, bit -= 8;
+                       if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC)
+                               return (1);
+               }
+#ifdef F_SEVRE
+               if (io->i_flgs & F_SEVRE)
+                       return(1);
+#endif
+               return (0);
+       }
+
+       /*
+        * Skip sector error.
+        * Set skip-sector-inhibit and
+        * read next sector
+        */
+       if (flag == SSE) {
+               rp->hpcs1 = HP_DCLR | HP_GO;
+               HPWAIT(rp);
+               rp->hpof |= HPOF_SSEI;
+               return (0);     
+       }
+
+       /*
+        * Bad block forwarding.
+        */
+        if (flag == BSE) {
+               int bbn;
+
+               rp->hpcs1 = HP_DCLR | HP_GO;
+               if (hpdebug[unit] & HPF_BSEDEBUG)
+                       printf("hpecc: BSE @ bn %d\n", bn);
+               cn = bn/st->nspc;
+               sn = bn%st->nspc;
+               tn = sn/st->nsect;
+               sn = sn%st->nsect;
+               bcr += sectsiz;
+               if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0)
+                       return (1);
+               bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn;
+               cn = bbn/st->nspc;
+               sn = bbn%st->nspc;
+               tn = sn/st->nsect;
+               sn = sn%st->nsect;
+               io->i_cc = sectsiz;
+               io->i_ma += npf*sectsiz;
+               if (hpdebug[unit] & HPF_BSEDEBUG)
+                       printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
+               rp->hpof &= ~HPOF_SSEI;
+               mbp->mba_sr = -1;
+               rp->hpdc = cn;
+               rp->hpda = (tn<<8) + sn;
+               mbastart(io,io->i_flgs);
+               io->i_errcnt = 0;
+               HPWAIT(rp);
+               return (rp->hpds&HPDS_ERR);
+       }
+       printf("hpecc: flag=%d\n", flag);
+       return (1);
+}
+
+/*ARGSUSED*/
+hpioctl(io, cmd, arg)
+       struct iob *io;
+       int cmd;
+       caddr_t arg;
+{
+       register unit = io->i_unit;
+       struct st *st = &hpst[hp_type[unit]], *tmp;
+       struct mba_drv *drv = mbadrv(unit);
+       int flag;
+
+       switch(cmd) {
+
+       case SAIODEBUG:
+               flag = (int)arg;
+               if (flag > 0)
+                       hpdebug[unit] |= flag;
+               else
+                       hpdebug[unit] &= ~flag;
+               return (0);
+
+       case SAIODEVDATA:
+               if ((drv->mbd_dt&MBDT_TAP) == 0) {
+                       tmp = (struct st *)arg;
+                       *tmp = *st;
+                       return (0);
+               }
+               return (ECMD);
+
+       case SAIOSSI:                   /* skip-sector-inhibit */
+               if (drv->mbd_dt&MBDT_TAP)
+                       return (ECMD);
+               if ((io->i_flgs&F_SSI) == 0) {
+                       /* make sure this is done once only */
+                       io->i_flgs |= F_SSI;
+                       st->nsect++;
+                       st->nspc += st->ntrak;
+               }
+               return (0);
+
+       case SAIONOSSI:                 /* remove skip-sector-inhibit */
+               if (io->i_flgs & F_SSI) {
+                       io->i_flgs &= ~F_SSI;
+                       drv->mbd_of &= ~HPOF_SSEI;
+                       st->nsect--;
+                       st->nspc -= st->ntrak;
+               }
+               return(0);
+
+       case SAIOSSDEV:                 /* drive have skip sector? */
+               return (RM80 ? 0 : ECMD);
+       }
+       return (ECMD);
+}
diff --git a/usr/src/sys/stand/saio.h b/usr/src/sys/stand/saio.h
new file mode 100644 (file)
index 0000000..c3f9d95
--- /dev/null
@@ -0,0 +1,125 @@
+/*     saio.h  6.2     9/23/83 */
+
+/*
+ * Header file for standalone package
+ */
+
+/*
+ * Io block: includes an
+ * inode, cells for the use of seek, etc,
+ * and a buffer.
+ */
+struct iob {
+       int     i_flgs;         /* see F_ below */
+       struct  inode i_ino;    /* inode, if file */
+       int     i_unit;         /* pseudo device unit */
+       daddr_t i_boff;         /* block offset on device */
+       daddr_t i_cyloff;       /* cylinder offset on device */
+       off_t   i_offset;       /* seek offset in file */
+       daddr_t i_bn;           /* 1st block # of next read */
+       char    *i_ma;          /* memory address of i/o buffer */
+       int     i_cc;           /* character count of transfer */
+       int     i_error;        /* error # return */
+       int     i_errcnt;       /* error count for driver retries */
+       int     i_errblk;       /* block # in error for error reporting */
+       char    i_buf[MAXBSIZE];/* i/o buffer */
+       union {
+               struct fs ui_fs;        /* file system super block info */
+               char dummy[SBSIZE];
+       } i_un;
+};
+#define i_fs i_un.ui_fs
+#define NULL 0
+
+#define F_READ         0x1     /* file opened for reading */
+#define F_WRITE                0x2     /* file opened for writing */
+#define F_ALLOC                0x4     /* buffer allocated */
+#define F_FILE         0x8     /* file instead of device */
+#define F_NBSF         0x10    /* no bad sector forwarding */
+#define F_ECCLM                0x20    /* limit # of bits in ecc correction */
+#define F_SSI          0x40    /* set skip sector inhibit */
+#define F_SEVRE                0x80    /* Severe burnin (no retries, no ECC) */
+/* io types */
+#define        F_RDDATA        0x0100  /* read data */
+#define        F_WRDATA        0x0200  /* write data */
+#define F_HDR          0x0400  /* include header on next i/o */
+#define F_CHECK                0x0800  /* perform check of data read/write */
+#define F_HCHECK       0x1000  /* perform check of header and data */
+
+#define        F_TYPEMASK      0xff00
+
+/*
+ * Device switch.
+ */
+struct devsw {
+       char    *dv_name;
+       int     (*dv_strategy)();
+       int     (*dv_open)();
+       int     (*dv_close)();
+       int     (*dv_ioctl)();
+};
+
+struct devsw devsw[];
+
+/*
+ * Drive description table.
+ * Returned from SAIODEVDATA call.
+ */
+struct st {
+       short   nsect;          /* # sectors/track */
+       short   ntrak;          /* # tracks/surfaces/heads */
+       short   nspc;           /* # sectors/cylinder */
+       short   ncyl;           /* # cylinders */
+       short   *off;           /* partition offset table (cylinders) */
+};
+
+/*
+ * Request codes. Must be the same a F_XXX above
+ */
+#define        READ    1
+#define        WRITE   2
+
+#define        NBUFS   4
+
+char   b[NBUFS][MAXBSIZE];
+daddr_t        blknos[NBUFS];
+
+#define        NFILES  4
+struct iob iob[NFILES];
+
+extern int errno;      /* just like unix */
+
+/* error codes */
+#define        EBADF   1       /* bad file descriptor */
+#define        EOFFSET 2       /* relative seek not supported */
+#define        EDEV    3       /* improper device specification on open */
+#define        ENXIO   4       /* unknown device specified */
+#define        EUNIT   5       /* improper unit specification */
+#define        ESRCH   6       /* directory search for file failed */
+#define        EIO     7       /* generic error */
+#define        ECMD    10      /* undefined driver command */
+#define        EBSE    11      /* bad sector error */
+#define        EWCK    12      /* write check error */
+#define        EECC    13      /* uncorrectable ecc error */
+#define        EHER    14      /* hard error */
+
+/* ioctl's -- for disks just now */
+#define        SAIOHDR         (('d'<<8)|1)    /* next i/o includes header */
+#define        SAIOCHECK       (('d'<<8)|2)    /* next i/o checks data */
+#define        SAIOHCHECK      (('d'<<8)|3)    /* next i/o checks header & data */
+#define        SAIONOBAD       (('d'<<8)|4)    /* inhibit bad sector forwarding */
+#define        SAIODOBAD       (('d'<<8)|5)    /* enable bad sector forwarding */
+#define        SAIOECCLIM      (('d'<<8)|6)    /* limit ecc correction to 5 bits */
+#define        SAIOECCUNL      (('d'<<8)|7)    /* use standard ecc procedures */
+#define        SAIODEVDATA     (('d'<<8)|8)    /* get device data */
+#define        SAIOSSI         (('d'<<8)|9)    /* set skip sector inhibit */
+#define        SAIONOSSI       (('d'<<8)|10)   /* inhibit skip sector handling */
+#define        SAIOSSDEV       (('d'<<8)|11)   /* is device skip sector type? */
+#define        SAIODEBUG       (('d'<<8)|12)   /* enable/disable debugging */
+#define        SAIOSEVRE       (('d'<<8)|13)   /* severe burnin, no ECC, no retries */
+#define        SAIONSEVRE      (('d'<<8)|14)   /* clear severe burnin */
+
+/* codes for sector header word 1 */
+#define        HDR1_FMT22      0x1000  /* standard 16 bit format */
+#define        HDR1_OKSCT      0xc000  /* sector ok */
+#define        HDR1_SSF        0x2000  /* skip sector flag */
diff --git a/usr/src/sys/stand/sys.c b/usr/src/sys/stand/sys.c
new file mode 100644 (file)
index 0000000..6ac73c4
--- /dev/null
@@ -0,0 +1,611 @@
+/*     sys.c   6.2     83/09/23        */
+
+#include "../h/param.h"
+#include "../h/inode.h"
+#include "../h/fs.h"
+#include "../h/dir.h"
+#include "saio.h"
+
+ino_t  dlook();
+
+struct dirstuff {
+       int loc;
+       struct iob *io;
+};
+
+static
+openi(n, io)
+       register struct iob *io;
+{
+       register struct dinode *dp;
+       int cc;
+
+       io->i_offset = 0;
+       io->i_bn = fsbtodb(&io->i_fs, itod(&io->i_fs, n)) + io->i_boff;
+       io->i_cc = io->i_fs.fs_bsize;
+       io->i_ma = io->i_buf;
+       cc = devread(io);
+       dp = (struct dinode *)io->i_buf;
+       io->i_ino.i_ic = dp[itoo(&io->i_fs, n)].di_ic;
+       return (cc);
+}
+
+static
+find(path, file)
+       register char *path;
+       struct iob *file;
+{
+       register char *q;
+       char c;
+       int n;
+
+       if (path==NULL || *path=='\0') {
+               printf("null path\n");
+               return (0);
+       }
+
+       if (openi((ino_t) ROOTINO, file) < 0) {
+               printf("can't read root inode\n");
+               return (0);
+       }
+       while (*path) {
+               while (*path == '/')
+                       path++;
+               q = path;
+               while(*q != '/' && *q != '\0')
+                       q++;
+               c = *q;
+               *q = '\0';
+
+               if ((n = dlook(path, file)) != 0) {
+                       if (c == '\0')
+                               break;
+                       if (openi(n, file) < 0)
+                               return (0);
+                       *q = c;
+                       path = q;
+                       continue;
+               } else {
+                       printf("%s not found\n", path);
+                       return (0);
+               }
+       }
+       return (n);
+}
+
+static daddr_t
+sbmap(io, bn)
+       register struct iob *io;
+       daddr_t bn;
+{
+       register struct inode *ip;
+       int i, j, sh;
+       daddr_t nb, *bap;
+
+       ip = &io->i_ino;
+       if (bn < 0) {
+               printf("bn negative\n");
+               return ((daddr_t)0);
+       }
+
+       /*
+        * blocks 0..NDADDR are direct blocks
+        */
+       if(bn < NDADDR) {
+               nb = ip->i_db[bn];
+               return (nb);
+       }
+
+       /*
+        * addresses NIADDR have single and double indirect blocks.
+        * the first step is to determine how many levels of indirection.
+        */
+       sh = 1;
+       bn -= NDADDR;
+       for (j = NIADDR; j > 0; j--) {
+               sh *= NINDIR(&io->i_fs);
+               if (bn < sh)
+                       break;
+               bn -= sh;
+       }
+       if (j == 0) {
+               printf("bn ovf %D\n", bn);
+               return ((daddr_t)0);
+       }
+
+       /*
+        * fetch the first indirect block address from the inode
+        */
+       nb = ip->i_ib[NIADDR - j];
+       if (nb == 0) {
+               printf("bn void %D\n",bn);
+               return ((daddr_t)0);
+       }
+
+       /*
+        * fetch through the indirect blocks
+        */
+       for (; j <= NIADDR; j++) {
+               if (blknos[j] != nb) {
+                       io->i_bn = fsbtodb(&io->i_fs, nb) + io->i_boff;
+                       io->i_ma = b[j];
+                       io->i_cc = io->i_fs.fs_bsize;
+                       if (devread(io) != io->i_fs.fs_bsize) {
+                               if (io->i_error)
+                                       errno = io->i_error;
+                               printf("bn %D: read error\n", io->i_bn);
+                               return ((daddr_t)0);
+                       }
+                       blknos[j] = nb;
+               }
+               bap = (daddr_t *)b[j];
+               sh /= NINDIR(&io->i_fs);
+               i = (bn / sh) % NINDIR(&io->i_fs);
+               nb = bap[i];
+               if(nb == 0) {
+                       printf("bn void %D\n",bn);
+                       return ((daddr_t)0);
+               }
+       }
+       return (nb);
+}
+
+static ino_t
+dlook(s, io)
+       char *s;
+       register struct iob *io;
+{
+       register struct direct *dp;
+       register struct inode *ip;
+       struct dirstuff dirp;
+       int len;
+
+       if (s == NULL || *s == '\0')
+               return (0);
+       ip = &io->i_ino;
+       if ((ip->i_mode&IFMT) != IFDIR) {
+               printf("not a directory\n");
+               return (0);
+       }
+       if (ip->i_size == 0) {
+               printf("zero length directory\n");
+               return (0);
+       }
+       len = strlen(s);
+       dirp.loc = 0;
+       dirp.io = io;
+       for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
+               if(dp->d_ino == 0)
+                       continue;
+               if (dp->d_namlen == len && !strcmp(s, dp->d_name))
+                       return (dp->d_ino);
+       }
+       return (0);
+}
+
+/*
+ * get next entry in a directory.
+ */
+struct direct *
+readdir(dirp)
+       register struct dirstuff *dirp;
+{
+       register struct direct *dp;
+       register struct iob *io;
+       daddr_t lbn, d;
+       int off;
+
+       io = dirp->io;
+       for(;;) {
+               if (dirp->loc >= io->i_ino.i_size)
+                       return (NULL);
+               off = blkoff(&io->i_fs, dirp->loc);
+               if (off == 0) {
+                       lbn = lblkno(&io->i_fs, dirp->loc);
+                       d = sbmap(io, lbn);
+                       if(d == 0)
+                               return NULL;
+                       io->i_bn = fsbtodb(&io->i_fs, d) + io->i_boff;
+                       io->i_ma = io->i_buf;
+                       io->i_cc = blksize(&io->i_fs, &io->i_ino, lbn);
+                       if (devread(io) < 0) {
+                               errno = io->i_error;
+                               printf("bn %D: read error\n", io->i_bn);
+                               return (NULL);
+                       }
+               }
+               dp = (struct direct *)(io->i_buf + off);
+               dirp->loc += dp->d_reclen;
+               if (dp->d_ino == 0)
+                       continue;
+               return (dp);
+       }
+}
+
+lseek(fdesc, addr, ptr)
+       int fdesc, ptr;
+       off_t addr;
+{
+       register struct iob *io;
+
+       if (ptr != 0) {
+               printf("Seek not from beginning of file\n");
+               errno = EOFFSET;
+               return (-1);
+       }
+       fdesc -= 3;
+       if (fdesc < 0 || fdesc >= NFILES ||
+           ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       io->i_offset = addr;
+       io->i_bn = addr / DEV_BSIZE;
+       io->i_cc = 0;
+       return (0);
+}
+
+getc(fdesc)
+       int fdesc;
+{
+       register struct iob *io;
+       register struct fs *fs;
+       register char *p;
+       int c, lbn, off, size, diff;
+
+
+       if (fdesc >= 0 && fdesc <= 2)
+               return (getchar());
+       fdesc -= 3;
+       if (fdesc < 0 || fdesc >= NFILES ||
+           ((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       p = io->i_ma;
+       if (io->i_cc <= 0) {
+               if ((io->i_flgs & F_FILE) != 0) {
+                       diff = io->i_ino.i_size - io->i_offset;
+                       if (diff <= 0)
+                               return (-1);
+                       fs = &io->i_fs;
+                       lbn = lblkno(fs, io->i_offset);
+                       io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
+                       off = blkoff(fs, io->i_offset);
+                       size = blksize(fs, &io->i_ino, lbn);
+               } else {
+                       io->i_bn = io->i_offset / DEV_BSIZE;
+                       off = 0;
+                       size = DEV_BSIZE;
+               }
+               io->i_ma = io->i_buf;
+               io->i_cc = size;
+               if (devread(io) < 0) {
+                       errno = io->i_error;
+                       return (-1);
+               }
+               if ((io->i_flgs & F_FILE) != 0) {
+                       if (io->i_offset - off + size >= io->i_ino.i_size)
+                               io->i_cc = diff + off;
+                       io->i_cc -= off;
+               }
+               p = &io->i_buf[off];
+       }
+       io->i_cc--;
+       io->i_offset++;
+       c = (unsigned)*p++;
+       io->i_ma = p;
+       return (c);
+}
+
+/* does this port?
+getw(fdesc)
+       int fdesc;
+{
+       register w,i;
+       register char *cp;
+       int val;
+
+       for (i = 0, val = 0, cp = &val; i < sizeof(val); i++) {
+               w = getc(fdesc);
+               if (w < 0) {
+                       if (i == 0)
+                               return (-1);
+                       else
+                               return (val);
+               }
+               *cp++ = w;
+       }
+       return (val);
+}
+*/
+int    errno;
+
+read(fdesc, buf, count)
+       int fdesc, count;
+       char *buf;
+{
+       register i;
+       register struct iob *file;
+
+       errno = 0;
+       if (fdesc >= 0 & fdesc <= 2) {
+               i = count;
+               do {
+                       *buf = getchar();
+               } while (--i && *buf++ != '\n');
+               return (count - i);
+       }
+       fdesc -= 3;
+       if (fdesc < 0 || fdesc >= NFILES ||
+           ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       if ((file->i_flgs&F_READ) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       if ((file->i_flgs & F_FILE) == 0) {
+               file->i_cc = count;
+               file->i_ma = buf;
+               file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
+               i = devread(file);
+               file->i_offset += count;
+               if (i < 0)
+                       errno = file->i_error;
+               return (i);
+       } else {
+               if (file->i_offset+count > file->i_ino.i_size)
+                       count = file->i_ino.i_size - file->i_offset;
+               if ((i = count) <= 0)
+                       return (0);
+               do {
+                       *buf++ = getc(fdesc+3);
+               } while (--i);
+               return (count);
+       }
+}
+
+write(fdesc, buf, count)
+       int fdesc, count;
+       char *buf;
+{
+       register i;
+       register struct iob *file;
+
+       errno = 0;
+       if (fdesc >= 0 && fdesc <= 2) {
+               i = count;
+               while (i--)
+                       putchar(*buf++);
+               return (count);
+       }
+       fdesc -= 3;
+       if (fdesc < 0 || fdesc >= NFILES ||
+           ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       if ((file->i_flgs&F_WRITE) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       file->i_cc = count;
+       file->i_ma = buf;
+       file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
+       i = devwrite(file);
+       file->i_offset += count;
+       if (i < 0)
+               errno = file->i_error;
+       return (i);
+}
+
+int    openfirst = 1;
+
+open(str, how)
+       char *str;
+       int how;
+{
+       register char *cp;
+       int i;
+       register struct iob *file;
+       register struct devsw *dp;
+       int fdesc;
+       long atol();
+
+       if (openfirst) {
+               for (i = 0; i < NFILES; i++)
+                       iob[i].i_flgs = 0;
+               openfirst = 0;
+       }
+
+       for (fdesc = 0; fdesc < NFILES; fdesc++)
+               if (iob[fdesc].i_flgs == 0)
+                       goto gotfile;
+       _stop("No more file slots");
+gotfile:
+       (file = &iob[fdesc])->i_flgs |= F_ALLOC;
+
+       for (cp = str; *cp && *cp != '('; cp++)
+                       ;
+       if (*cp != '(') {
+               printf("Bad device\n");
+               file->i_flgs = 0;
+               errno = EDEV;
+               return (-1);
+       }
+       *cp++ = '\0';
+       for (dp = devsw; dp->dv_name; dp++) {
+               if (!strcmp(str, dp->dv_name))
+                       goto gotdev;
+       }
+       printf("Unknown device\n");
+       file->i_flgs = 0;
+       errno = ENXIO;
+       return (-1);
+gotdev:
+       *(cp-1) = '(';
+       file->i_ino.i_dev = dp-devsw;
+       file->i_unit = *cp++ - '0';
+       if (*cp >= '0' && *cp <= '9')
+               file->i_unit = file->i_unit * 10 + *cp++ - '0';
+       if (file->i_unit < 0 || file->i_unit > 31) {
+               printf("Bad unit specifier\n");
+               file->i_flgs = 0;
+               errno = EUNIT;
+               return (-1);
+       }
+       if (*cp++ != ',') {
+badoff:
+               printf("Missing offset specification\n");
+               file->i_flgs = 0;
+               errno = EOFFSET;
+               return (-1);
+       }
+       file->i_boff = atol(cp);
+       for (;;) {
+               if (*cp == ')')
+                       break;
+               if (*cp++)
+                       continue;
+               goto badoff;
+       }
+       devopen(file);
+       if (*++cp == '\0') {
+               file->i_flgs |= how+1;
+               file->i_cc = 0;
+               file->i_offset = 0;
+               return (fdesc+3);
+       }
+       file->i_ma = (char *)(&file->i_fs);
+       file->i_cc = SBSIZE;
+       file->i_bn = SBLOCK + file->i_boff;
+       file->i_offset = 0;
+       if (devread(file) < 0) {
+               errno = file->i_error;
+               printf("super block read error\n");
+               return (-1);
+       }
+       if ((i = find(cp, file)) == 0) {
+               file->i_flgs = 0;
+               errno = ESRCH;
+               return (-1);
+       }
+       if (how != 0) {
+               printf("Can't write files yet.. Sorry\n");
+               file->i_flgs = 0;
+               errno = EIO;
+               return (-1);
+       }
+       if (openi(i, file) < 0) {
+               errno = file->i_error;
+               return (-1);
+       }
+       file->i_offset = 0;
+       file->i_cc = 0;
+       file->i_flgs |= F_FILE | (how+1);
+       return (fdesc+3);
+}
+
+close(fdesc)
+       int fdesc;
+{
+       struct iob *file;
+
+       fdesc -= 3;
+       if (fdesc < 0 || fdesc >= NFILES ||
+           ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       if ((file->i_flgs&F_FILE) == 0)
+               devclose(file);
+       file->i_flgs = 0;
+       return (0);
+}
+
+ioctl(fdesc, cmd, arg)
+       int fdesc, cmd;
+       char *arg;
+{
+       register struct iob *file;
+       int error = 0;
+
+       fdesc -= 3;
+       if (fdesc < 0 || fdesc >= NFILES ||
+           ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       switch (cmd) {
+
+       case SAIOHDR:
+               file->i_flgs |= F_HDR;
+               break;
+
+       case SAIOCHECK:
+               file->i_flgs |= F_CHECK;
+               break;
+
+       case SAIOHCHECK:
+               file->i_flgs |= F_HCHECK;
+               break;
+
+       case SAIONOBAD:
+               file->i_flgs |= F_NBSF;
+               break;
+
+       case SAIODOBAD:
+               file->i_flgs &= ~F_NBSF;
+               break;
+
+       case SAIOECCLIM:
+               file->i_flgs |= F_ECCLM;
+               break;
+
+       case SAIOECCUNL:
+               file->i_flgs &= ~F_ECCLM;
+               break;
+
+       case SAIOSEVRE:
+               file->i_flgs |= F_SEVRE;
+               break;
+
+       case SAIONSEVRE:
+               file->i_flgs &= ~F_SEVRE;
+               break;
+
+       default:
+               error = devioctl(file, cmd, arg);
+               break;
+       }
+       if (error < 0)
+               errno = file->i_error;
+       return (error);
+}
+
+exit()
+{
+       _stop("Exit called");
+}
+
+_stop(s)
+       char *s;
+{
+       int i;
+
+       for (i = 0; i < NFILES; i++)
+               if (iob[i].i_flgs != 0)
+                       close(i);
+       printf("%s\n", s);
+       _rtt();
+}
+
+trap(ps)
+       int ps;
+{
+       printf("Trap %o\n", ps);
+       for (;;)
+               ;
+}
diff --git a/usr/src/sys/stand/up.c b/usr/src/sys/stand/up.c
new file mode 100644 (file)
index 0000000..f286918
--- /dev/null
@@ -0,0 +1,486 @@
+/*     up.c    6.2     83/09/23        */
+
+/*
+ * UNIBUS peripheral standalone driver
+ * with ECC correction and bad block forwarding.
+ * Also supports header operation and write
+ * check for data and/or header.
+ */
+#include "../h/param.h" 
+#include "../h/inode.h"
+#include "../h/fs.h"
+#include "../h/dkbad.h"
+#include "../h/vmmac.h"
+
+#include "../vax/pte.h"
+#include "../vaxuba/upreg.h"
+#include "../vaxuba/ubareg.h"
+
+#include "saio.h"
+#include "savax.h"
+
+#define MAXBADDESC     126     /* max number of bad sectors recorded */
+#define SECTSIZ                512     /* sector size in bytes */
+#define HDRSIZ         4       /* number of bytes in sector header */
+
+#define MAXECC         5       /* max # bad bits allowed on ecc w/ F_ECCLM */
+
+u_short        ubastd[] = { 0776700 };
+
+char   up_gottype[MAXNUBA*8];
+char   up_type[MAXNUBA*8];
+extern struct st upst[];
+
+struct  dkbad upbad[MAXNUBA*8];                /* bad sector table */
+int    sectsiz;                        /* real sector size */
+int    updebug[MAXNUBA*8];
+#define        UPF_BSEDEBUG    01      /* debugging bad sector forwarding */
+#define        UPF_ECCDEBUG    02      /* debugging ecc correction */
+
+u_char up_offset[16] = {
+       UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
+       UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 
+       UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
+       0, 0, 0, 0
+};
+
+upopen(io)
+       register struct iob *io;
+{
+       register unit = io->i_unit;
+       register struct updevice *upaddr;
+       register struct st *st;
+
+       if (io->i_boff < 0 || io->i_boff > 7)
+               _stop("up bad unit");
+       upaddr = (struct updevice *)ubamem(unit, ubastd[0]);
+       upaddr->upcs2 = unit % 8;
+       while ((upaddr->upcs1 & UP_DVA) == 0)
+               ;
+       if (up_gottype[unit] == 0) {
+               register int i;
+               struct iob tio;
+
+               up_type[unit] = upmaptype(unit, upaddr);
+               if (up_type[unit] < 0)
+                       _stop("unknown drive type");
+               st = &upst[up_type[unit]];
+               if (st->off[io->i_boff] == -1)
+                       _stop("up bad unit");
+               /*
+                * Read in the bad sector table.
+                */
+               tio = *io;
+               tio.i_bn = st->nspc * st->ncyl - st->nsect;
+               tio.i_ma = (char *)&upbad[tio.i_unit];
+               tio.i_cc = sizeof (struct dkbad);
+               tio.i_flgs |= F_RDDATA;
+               for (i = 0; i < 5; i++) {
+                       if (upstrategy(&tio, READ) == sizeof (struct dkbad))
+                               break;
+                       tio.i_bn += 2;
+               }
+               if (i == 5) {
+                       printf("Unable to read bad sector table\n");
+                       for (i = 0; i < MAXBADDESC; i++) {
+                               upbad[unit].bt_bad[i].bt_cyl = -1;
+                               upbad[unit].bt_bad[i].bt_trksec = -1;
+                       }
+               }       
+               up_gottype[unit] = 1;
+       }
+       io->i_boff = st->off[io->i_boff] * st->nspc;
+       io->i_flgs &= ~F_TYPEMASK;
+}
+
+upstrategy(io, func)
+       register struct iob *io;
+{
+       int cn, tn, sn, o;
+       register unit = io->i_unit;
+       daddr_t bn;
+       int recal, info, waitdry;
+       register struct updevice *upaddr =
+           (struct updevice *)ubamem(unit, ubastd[0]);
+       register struct st *st = &upst[up_type[unit]];
+       int doprintf = 0;
+
+       sectsiz = SECTSIZ;
+       if (io->i_flgs & (F_HDR|F_HCHECK))
+               sectsiz += HDRSIZ;
+       upaddr->upcs2 = unit % 8;
+       if ((upaddr->upds & UPDS_VV) == 0) {
+               upaddr->upcs1 = UP_DCLR|UP_GO;
+               upaddr->upcs1 = UP_PRESET|UP_GO;
+               upaddr->upof = UPOF_FMT22;
+       }
+       if ((upaddr->upds & UPDS_DREADY) == 0)
+               _stop("up not ready");
+       info = ubasetup(io, 1);
+       upaddr->upwc = -io->i_cc / sizeof (short);
+       recal = 0;
+       io->i_errcnt = 0;
+
+restart: 
+       o = io->i_cc + (upaddr->upwc * sizeof (short));
+       upaddr->upba = info + o;
+       bn = io->i_bn + o / sectsiz;
+       if (doprintf && updebug[unit] & (UPF_ECCDEBUG|UPF_BSEDEBUG))
+               printf("wc=%d o=%d i_bn=%d bn=%d\n",
+                       upaddr->upwc, o, io->i_bn, bn);
+       while((upaddr->upds & UPDS_DRY) == 0)
+               ;
+       if (upstart(io, bn) != 0) {
+               ubafree(io, info);
+               return (-1);
+       }
+       do {
+               DELAY(25);
+       } while ((upaddr->upcs1 & UP_RDY) == 0);
+       /*
+        * If transfer has completed, free UNIBUS
+        * resources and return transfer size.
+        */
+       if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0)
+               goto done;
+       if (updebug[unit] & (UPF_ECCDEBUG|UPF_BSEDEBUG)) {
+               printf("up error: (cyl,trk,sec)=(%d,%d,%d) ",
+                 upaddr->updc, upaddr->upda>>8, upaddr->upda&0xff);
+               printf("cs2=%b er1=%b er2=%b wc=%d\n",
+                 upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 
+                 UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc);
+       }
+       waitdry = 0;
+       while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz)
+               DELAY(5);
+       if (upaddr->uper1&UPER1_WLE) {
+               /*
+                * Give up on write locked devices immediately.
+                */
+               printf("up%d: write locked\n", unit);
+               return (-1);
+       }
+       if (++io->i_errcnt > 27) {
+               /*
+                * After 28 retries (16 without offset, and
+                * 12 with offset positioning) give up.
+                * But first, if the error is a header CRC,
+                * check if a replacement sector exists in
+                * the bad sector table.
+                */
+               if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 &&
+                    upecc(io, BSE) == 0)
+                       goto success;
+               io->i_error = EHER;
+               if (upaddr->upcs2 & UPCS2_WCE)
+                       io->i_error = EWCK;
+hard:
+               bn = io->i_bn +
+                       (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz;
+               cn = bn/st->nspc;
+               sn = bn%st->nspc;
+               tn = sn/st->nsect;
+               sn = sn%st->nsect;
+               printf(
+                 "up error: (cyl,trk,sec)=(%d,%d,%d) cs2=%b er1=%b er2=%b\n",
+                  cn, tn, sn,
+                  upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 
+                  UPER1_BITS, upaddr->uper2, UPER2_BITS);
+               upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
+               io->i_errblk = bn;
+               if (io->i_errcnt >= 16) {
+                       upaddr->upof = UPOF_FMT22;
+                       upaddr->upcs1 = UP_RTC|UP_GO;
+                       while ((upaddr->upds&UPDS_DRY) == 0)
+                               DELAY(25);
+               }
+               return (io->i_cc + upaddr->upwc * sizeof(short));
+       }
+       if (upaddr->uper2 & UPER2_BSE) {
+               if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0)
+                       goto success;
+               io->i_error = EBSE;
+               goto hard;
+       }
+       /*
+        * ECC error. If a soft error, correct it;
+        * otherwise fall through and retry the transfer.
+        */
+       if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) {
+               if (upecc(io, ECC) == 0)
+#ifdef F_SEVRE
+                   if (io->i_flgs & F_SEVRE)
+                       return (-1);
+                   else
+#endif
+                       goto success;
+               io->i_error = EECC;
+               goto hard;
+       } 
+#ifdef F_SEVRE
+       if (io->i_flgs & F_SEVRE)
+               goto hard;
+#endif
+       /*
+        * Clear drive error and, every eight attempts,
+        * (starting with the fourth)
+        * recalibrate to clear the slate.
+        */
+       upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
+       if ((io->i_errcnt&07) == 4 ) {
+               upaddr->upcs1 = UP_RECAL|UP_GO;
+               while ((upaddr->upds&UPDS_DRY) == 0)
+                       DELAY(25);
+               upaddr->updc = cn;
+               upaddr->upcs1 = UP_SEEK|UP_GO;
+               while ((upaddr->upds&UPDS_DRY) == 0)
+                       DELAY(25);
+       }
+       if (io->i_errcnt >= 16 && (func & READ)) {
+               upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22;
+               upaddr->upcs1 = UP_OFFSET|UP_GO;
+               while ((upaddr->upds&UPDS_DRY) == 0)
+                       DELAY(25);
+       }
+       goto restart;
+
+success:
+#define        rounddown(x, y) (((x) / (y)) * (y))
+       upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short));
+       if (upaddr->upwc) {
+               doprintf++;
+               goto restart;
+       }
+done:
+       /*
+        * Release UNIBUS 
+        */
+       ubafree(io, info);
+       /*
+        * If we were offset positioning,
+        * return to centerline.
+        */
+       if (io->i_errcnt >= 16) {
+               upaddr->upof = UPOF_FMT22;
+               upaddr->upcs1 = UP_RTC|UP_GO;
+               while ((upaddr->upds&UPDS_DRY) == 0)
+                       DELAY(25);
+       }
+       return (io->i_cc);
+}
+
+/*
+ * Correct an ECC error, and restart the
+ * i/o to complete the transfer (if necessary). 
+ * This is quite complicated because the transfer
+ * may be going to an odd memory address base and/or
+ * across a page boundary.
+ */
+upecc(io, flag)
+       register struct iob *io;
+       int flag;
+{
+       register i, unit = io->i_unit;
+       register struct updevice *up = 
+               (struct updevice *)ubamem(unit, ubastd[0]);
+       register struct st *st;
+       caddr_t addr;
+       int bn, twc, npf, mask, cn, tn, sn;
+       daddr_t bbn;
+
+       /*
+        * Npf is the number of sectors transferred
+        * before the sector containing the ECC error;
+        * bn is the current block number.
+        */
+       twc = up->upwc;
+       npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz;
+       if (flag == ECC)
+               npf--;
+       if (updebug[unit] & UPF_ECCDEBUG)
+               printf("npf=%d mask=0x%x ec1=%d wc=%d\n",
+                       npf, up->upec2, up->upec1, twc);
+       bn = io->i_bn + npf;
+       st = &upst[up_type[unit]];
+       cn = bn/st->nspc;
+       sn = bn%st->nspc;
+       tn = sn/st->nsect;
+       sn = sn%st->nsect;
+
+       /*
+        * ECC correction.
+        */
+       if (flag == ECC) {
+               int bit, o, ecccnt;
+
+               ecccnt = 0;
+               mask = up->upec2;
+               printf("up%d: soft ecc sn%d\n", unit, bn);
+               /*
+                * Compute the byte and bit position of
+                * the error.  o is the byte offset in
+                * the transfer at which the correction
+                * applied.
+                */
+               i = up->upec1 - 1;              /* -1 makes 0 origin */
+               bit = i & 07;
+               o = (i & ~07) >> 3;
+               up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
+               /*
+                * Correct while possible bits remain of mask.
+                * Since mask contains 11 bits, we continue while
+                * the bit offset is > -11.  Also watch out for
+                * end of this block and the end of the transfer.
+                */
+               while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) {
+                       /*
+                        * addr =
+                        *  (base address of transfer) +
+                        *  (# sectors transferred before the error) *
+                        *    (sector size) +
+                        *  (byte offset to incorrect data)
+                        */
+                       addr = io->i_ma + (npf * sectsiz) + o;
+                       /*
+                        * No data transfer occurs with a write check,
+                        * so don't correct the resident copy of data.
+                        */
+                       if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
+                               if (updebug[unit] & UPF_ECCDEBUG)
+                                       printf("addr=0x%x old=0x%x ", addr,
+                                               (*addr&0xff));
+                               *addr ^= (mask << bit);
+                               if (updebug[unit] & UPF_ECCDEBUG)
+                                       printf("new=0x%x\n", (*addr&0xff));
+                       }
+                       o++, bit -= 8;
+                       if ((io->i_flgs&F_ECCLM) && ++ecccnt > MAXECC)
+                               return (1);
+               }
+#ifdef F_SEVRE
+               if (io->i_flgs & F_SEVRE) {
+                       io->i_error = EECC;
+                       io->i_bn = bn;
+                       return(1);
+               }
+#endif
+               return (0);
+       }
+
+       /*
+        * Bad sector forwarding.
+        */
+       if (flag == BSE) {
+               /*
+                * If not in bad sector table,
+                * indicate a hard error to caller.
+                */
+               up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
+               if ((bbn = isbad(&upbad[unit], cn, tn, sn)) < 0)
+                       return (1);
+               bbn = (st->ncyl * st->nspc) - st->nsect - 1 - bbn;
+               twc = up->upwc + sectsiz;
+               up->upwc = - (sectsiz / sizeof (short));
+               if (updebug[unit] & UPF_BSEDEBUG)
+                       printf("revector sn %d to %d\n", sn, bbn);
+               /*
+                * Clear the drive & read the replacement
+                * sector.  If this is in the middle of a
+                * transfer, then set up the controller
+                * registers in a normal fashion. 
+                * The UNIBUS address need not be changed.
+                */
+               while ((up->upcs1 & UP_RDY) == 0) 
+                       ;
+               if (upstart(io, bbn))
+                       return (1);             /* error */
+               io->i_errcnt = 0;               /* success */
+               do {
+                       DELAY(25);
+               } while ((up->upcs1 & UP_RDY) == 0) ;
+               if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) {
+                       up->upwc = twc - sectsiz;
+                       return (1);
+               }
+       }
+       if (twc)
+               up->upwc = twc;
+       return (0);
+}
+
+upstart(io, bn)
+       register struct iob *io;
+       daddr_t bn;
+{
+       register struct updevice *upaddr = 
+               (struct updevice *)ubamem(io->i_unit, ubastd[0]);
+       register struct st *st = &upst[up_type[io->i_unit]];
+       int sn, tn;
+
+       sn = bn%st->nspc;
+       tn = sn/st->nsect;
+       sn %= st->nsect;
+       upaddr->updc = bn/st->nspc;
+       upaddr->upda = (tn << 8) + sn;
+       switch (io->i_flgs & F_TYPEMASK) {
+
+       case F_RDDATA:
+               upaddr->upcs1 = UP_RCOM|UP_GO;
+               break;
+
+       case F_WRDATA:
+               upaddr->upcs1 = UP_WCOM|UP_GO;
+               break;
+
+       case F_HDR|F_RDDATA:    
+               upaddr->upcs1 = UP_RHDR|UP_GO;
+               break;
+
+       case F_HDR|F_WRDATA:
+               upaddr->upcs1 = UP_WHDR|UP_GO;
+               break;
+
+       case F_CHECK|F_WRDATA:
+       case F_CHECK|F_RDDATA:
+               upaddr->upcs1 = UP_WCDATA|UP_GO;
+               break;
+
+       case F_HCHECK|F_WRDATA:
+       case F_HCHECK|F_RDDATA:
+               upaddr->upcs1 = UP_WCHDR|UP_GO;
+               break;
+
+       default:
+               io->i_error = ECMD;
+               io->i_flgs &= ~F_TYPEMASK;
+               return (1);
+       }
+       return (0);
+}
+
+/*ARGSUSED*/
+upioctl(io, cmd, arg)
+       struct iob *io;
+       int cmd;
+       caddr_t arg;
+{
+       int unit = io->i_unit, flag;
+       struct st *st = &upst[up_type[unit]], *tmp;
+
+       switch(cmd) {
+
+       case SAIODEBUG:
+               flag = (int)arg;
+               if (flag > 0)
+                       updebug[unit] |= flag;
+               else
+                       updebug[unit] &= ~flag;
+               return (0);
+
+       case SAIODEVDATA:
+               tmp = (struct st *)arg;
+               *tmp = *st;
+               return (0);
+       }
+       return (ECMD);
+}
diff --git a/usr/src/sys/sys/init_sysent.c b/usr/src/sys/sys/init_sysent.c
new file mode 100644 (file)
index 0000000..1cee312
--- /dev/null
@@ -0,0 +1,266 @@
+/*     init_sysent.c   6.1     83/08/17        */
+
+/*
+ * System call switch table.
+ */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+
+int    nosys();
+
+/* 1.1 processes and protection */
+int    sethostid(),gethostid(),sethostname(),gethostname(),getpid();
+int    fork(),rexit(),execv(),execve(),wait();
+int    getuid(),setreuid(),getgid(),getgroups(),setregid(),setgroups();
+int    getpgrp(),setpgrp();
+
+/* 1.2 memory management */
+int    sbrk(),sstk();
+int    getpagesize(),smmap(),mremap(),munmap(),mprotect(),madvise(),mincore();
+
+/* 1.3 signals */
+int    sigvec(),sigblock(),sigsetmask(),sigpause(),sigstack();
+int    kill(), killpg();
+
+/* 1.4 timing and statistics */
+int    gettimeofday(),settimeofday();
+int    getitimer(),setitimer();
+
+/* 1.5 descriptors */
+int    getdtablesize(),dup(),dup2(),close();
+int    select(),getdopt(),setdopt(),fcntl(),flock();
+
+/* 1.6 resource controls */
+int    getpriority(),setpriority(),getrusage(),getrlimit(),setrlimit();
+int    setquota(),qquota();
+
+/* 1.7 system operation support */
+int    umount(),smount(),swapon();
+int    sync(),reboot(),sysacct();
+
+/* 2.1 generic operations */
+int    read(),write(),readv(),writev(),ioctl();
+
+/* 2.2 file system */
+int    chdir(),chroot();
+int    mkdir(),rmdir();
+int    creat(),open(),mknod(),unlink(),stat(),fstat(),lstat();
+int    chown(),fchown(),chmod(),fchmod(),utimes();
+int    link(),symlink(),readlink(),rename();
+int    lseek(),truncate(),ftruncate(),saccess(),fsync();
+
+/* 2.3 communications */
+int    socket(),bind(),listen(),accept(),connect();
+int    socketpair(),sendto(),send(),recvfrom(),recv();
+int    sendmsg(),recvmsg(),shutdown(),setsockopt(),getsockopt();
+int    getsockname(),getpeername(),pipe();
+
+int    umask();                /* XXX */
+
+/* 2.4 processes */
+int    ptrace();
+
+/* 2.5 terminals */
+
+#ifdef COMPAT
+/* emulations for backwards compatibility */
+#define        compat(n, name) n, o/**/name
+
+int    owait();                /* now receive message on channel */
+int    otime();                /* now use gettimeofday */
+int    ostime();               /* now use settimeofday */
+int    oalarm();               /* now use setitimer */
+int    outime();               /* now use utimes */
+int    opause();               /* now use sigpause */
+int    onice();                /* now use setpriority,getpriority */
+int    oftime();               /* now use gettimeofday */
+int    osetpgrp();             /* ??? */
+int    otimes();               /* now use getrusage */
+int    ossig();                /* now use sigvec, etc */
+int    ovlimit();              /* now use setrlimit,getrlimit */
+int    ovtimes();              /* now use getrusage */
+int    osetuid();              /* now use setreuid */
+int    osetgid();              /* now use setregid */
+int    ostat();                /* now use stat */
+int    ofstat();               /* now use fstat */
+#else
+#define        compat(n, name) 0, nosys
+#endif
+
+/* BEGIN JUNK */
+#ifdef vax
+int    resuba();
+#ifdef TRACE
+int    vtrace();
+#endif
+#endif
+int    profil();               /* 'cuz sys calls are interruptible */
+int    vhangup();              /* should just do in exit() */
+int    vfork();                /* awaiting fork w/ copy on write */
+int    obreak();               /* awaiting new sbrk */
+int    ovadvise();             /* awaiting new madvise */
+/* END JUNK */
+
+struct sysent sysent[] = {
+       0, nosys,                       /*   0 = indir */
+       1, rexit,                       /*   1 = exit */
+       0, fork,                        /*   2 = fork */
+       3, read,                        /*   3 = read */
+       3, write,                       /*   4 = write */
+       3, open,                        /*   5 = open */
+       1, close,                       /*   6 = close */
+       compat(0,wait),                 /*   7 = old wait */
+       2, creat,                       /*   8 = creat */
+       2, link,                        /*   9 = link */
+       1, unlink,                      /*  10 = unlink */
+       2, execv,                       /*  11 = execv */
+       1, chdir,                       /*  12 = chdir */
+       compat(0,time),                 /*  13 = old time */
+       3, mknod,                       /*  14 = mknod */
+       2, chmod,                       /*  15 = chmod */
+       3, chown,                       /*  16 = chown; now 3 args */
+       1, obreak,                      /*  17 = old break */
+       compat(2,stat),                 /*  18 = old stat */
+       3, lseek,                       /*  19 = lseek */
+       0, getpid,                      /*  20 = getpid */
+       3, smount,                      /*  21 = mount */
+       1, umount,                      /*  22 = umount */
+       compat(1,setuid),               /*  23 = old setuid */
+       0, getuid,                      /*  24 = getuid */
+       compat(1,stime),                /*  25 = old stime */
+       4, ptrace,                      /*  26 = ptrace */
+       compat(1,alarm),                /*  27 = old alarm */
+       compat(2,fstat),                /*  28 = old fstat */
+       compat(0,pause),                /*  29 = opause */
+       compat(2,utime),                /*  30 = old utime */
+       0, nosys,                       /*  31 = was stty */
+       0, nosys,                       /*  32 = was gtty */
+       2, saccess,                     /*  33 = access */
+       compat(1,nice),                 /*  34 = old nice */
+       compat(1,ftime),                /*  35 = old ftime */
+       0, sync,                        /*  36 = sync */
+       2, kill,                        /*  37 = kill */
+       2, stat,                        /*  38 = stat */
+       compat(2,setpgrp),              /*  39 = old setpgrp */
+       2, lstat,                       /*  40 = lstat */
+       2, dup,                         /*  41 = dup */
+       0, pipe,                        /*  42 = pipe */
+       compat(1,times),                /*  43 = old times */
+       4, profil,                      /*  44 = profil */
+       0, nosys,                       /*  45 = nosys */
+       compat(1,setgid),               /*  46 = old setgid */
+       0, getgid,                      /*  47 = getgid */
+       compat(2,ssig),                 /*  48 = old sig */
+       0, nosys,                       /*  49 = reserved for USG */
+       0, nosys,                       /*  50 = reserved for USG */
+       1, sysacct,                     /*  51 = turn acct off/on */
+       0, nosys,                       /*  52 = old set phys addr */
+       0, nosys,                       /*  53 = old lock in core */
+       3, ioctl,                       /*  54 = ioctl */
+       1, reboot,                      /*  55 = reboot */
+       0, nosys,                       /*  56 = old mpxchan */
+       2, symlink,                     /*  57 = symlink */
+       3, readlink,                    /*  58 = readlink */
+       3, execve,                      /*  59 = execve */
+       1, umask,                       /*  60 = umask */
+       1, chroot,                      /*  61 = chroot */
+       2, fstat,                       /*  62 = fstat */
+       0, nosys,                       /*  63 = used internally */
+       1, getpagesize,                 /*  64 = getpagesize */
+       5, mremap,                      /*  65 = mremap */
+       0, vfork,                       /*  66 = vfork */
+       0, read,                        /*  67 = old vread */
+       0, write,                       /*  68 = old vwrite */
+       1, sbrk,                        /*  69 = sbrk */
+       1, sstk,                        /*  70 = sstk */
+       6, smmap,                       /*  71 = mmap */
+       1, ovadvise,                    /*  72 = old vadvise */
+       2, munmap,                      /*  73 = munmap */
+       3, mprotect,                    /*  74 = mprotect */
+       3, madvise,                     /*  75 = madvise */
+       1, vhangup,                     /*  76 = vhangup */
+       compat(2,vlimit),               /*  77 = old vlimit */
+       3, mincore,                     /*  78 = mincore */
+       2, getgroups,                   /*  79 = getgroups */
+       2, setgroups,                   /*  80 = setgroups */
+       1, getpgrp,                     /*  81 = getpgrp */
+       2, setpgrp,                     /*  82 = setpgrp */
+       3, setitimer,                   /*  83 = setitimer */
+       0, wait,                        /*  84 = wait */
+       1, swapon,                      /*  85 = swapon */
+       2, getitimer,                   /*  86 = getitimer */
+       2, gethostname,                 /*  87 = gethostname */
+       2, sethostname,                 /*  88 = sethostname */
+       0, getdtablesize,               /*  89 = getdtablesize */
+       2, dup2,                        /*  90 = dup2 */
+       2, getdopt,                     /*  91 = getdopt */
+       3, fcntl,                       /*  92 = fcntl */
+       5, select,                      /*  93 = select */
+       2, setdopt,                     /*  94 = setdopt */
+       1, fsync,                       /*  95 = fsync */
+       3, setpriority,                 /*  96 = setpriority */
+       3, socket,                      /*  97 = socket */
+       3, connect,                     /*  98 = connect */
+       3, accept,                      /*  99 = accept */
+       2, getpriority,                 /* 100 = getpriority */
+       4, send,                        /* 101 = send */
+       4, recv,                        /* 102 = recv */
+       0, nosys,                       /* 103 = old socketaddr */
+       3, bind,                        /* 104 = bind */
+       5, setsockopt,                  /* 105 = setsockopt */
+       2, listen,                      /* 106 = listen */
+       compat(2,vtimes),               /* 107 = old vtimes */
+       3, sigvec,                      /* 108 = sigvec */
+       1, sigblock,                    /* 109 = sigblock */
+       1, sigsetmask,                  /* 110 = sigsetmask */
+       1, sigpause,                    /* 111 = sigpause */
+       2, sigstack,                    /* 112 = sigstack */
+       3, recvmsg,                     /* 113 = recvmsg */
+       3, sendmsg,                     /* 114 = sendmsg */
+#ifdef TRACE
+       2, vtrace,                      /* 115 = vtrace */
+#else
+       0, nosys,                       /* 115 = nosys */
+#endif
+       2, gettimeofday,                /* 116 = gettimeofday */
+       2, getrusage,                   /* 117 = getrusage */
+       5, getsockopt,                  /* 118 = getsockopt */
+#ifdef vax
+       1, resuba,                      /* 119 = resuba */
+#else
+       0, nosys,                       /* 119 = nosys */
+#endif
+       3, readv,                       /* 120 = readv */
+       3, writev,                      /* 121 = writev */
+       2, settimeofday,                /* 122 = settimeofday */
+       3, fchown,                      /* 123 = fchown */
+       2, fchmod,                      /* 124 = fchmod */
+       6, recvfrom,                    /* 125 = recvfrom */
+       2, setreuid,                    /* 126 = setreuid */
+       2, setregid,                    /* 127 = setregid */
+       2, rename,                      /* 128 = rename */
+       2, truncate,                    /* 129 = truncate */
+       2, ftruncate,                   /* 130 = ftruncate */
+       2, flock,                       /* 131 = flock */
+       0, nosys,                       /* 132 = nosys */
+       6, sendto,                      /* 133 = sendto */
+       2, shutdown,                    /* 134 = shutdown */
+       5, socketpair,                  /* 135 = socketpair */
+       2, mkdir,                       /* 136 = mkdir */
+       1, rmdir,                       /* 137 = rmdir */
+       2, utimes,                      /* 138 = utimes */
+       0, nosys,                       /* 139 = used internally */
+       0, nosys,                       /* 140 = nosys */
+       3, getpeername,                 /* 141 = getpeername */
+       2, gethostid,                   /* 142 = gethostid */
+       2, sethostid,                   /* 143 = sethostid */
+       2, getrlimit,                   /* 144 = getrlimit */
+       2, setrlimit,                   /* 145 = setrlimit */
+       2, killpg,                      /* 146 = killpg */
+       0, nosys,                       /* 147 = nosys */
+       2, setquota,                    /* 148 = quota */
+       4, qquota,                      /* 149 = qquota */
+       3, getsockname,                 /* 150 = getsockname */
+};
+int    nsysent = sizeof (sysent) / sizeof (sysent[0]);
diff --git a/usr/src/sys/sys/kern_descrip.c b/usr/src/sys/sys/kern_descrip.c
new file mode 100644 (file)
index 0000000..6f2a97d
--- /dev/null
@@ -0,0 +1,417 @@
+/*     kern_descrip.c  6.2     83/09/25        */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/kernel.h"
+#include "../h/inode.h"
+#include "../h/proc.h"
+#include "../h/conf.h"
+#include "../h/file.h"
+#include "../h/socket.h"
+#include "../h/socketvar.h"
+#include "../h/mount.h"
+#include "../h/stat.h"
+
+#include "../h/ioctl.h"
+
+/*
+ * Descriptor management.
+ */
+
+/*
+ * TODO:
+ *     increase NOFILE
+ *     eliminate u.u_error side effects
+ */
+
+/*
+ * System calls on descriptors.
+ */
+getdtablesize()
+{
+
+       u.u_r.r_val1 = NOFILE;
+}
+
+getdopt()
+{
+
+}
+
+setdopt()
+{
+
+}
+
+dup()
+{
+       register struct a {
+               int     i;
+       } *uap = (struct a *) u.u_ap;
+       struct file *fp;
+       int j;
+
+       if (uap->i &~ 077) { uap->i &= 077; dup2(); return; }   /* XXX */
+
+       fp = getf(uap->i);
+       if (fp == 0)
+               return;
+       j = ufalloc(0);
+       if (j < 0)
+               return;
+       dupit(j, fp, u.u_pofile[uap->i]);
+}
+
+dup2()
+{
+       register struct a {
+               int     i, j;
+       } *uap = (struct a *) u.u_ap;
+       register struct file *fp;
+
+       fp = getf(uap->i);
+       if (fp == 0)
+               return;
+       if (uap->j < 0 || uap->j >= NOFILE) {
+               u.u_error = EBADF;
+               return;
+       }
+       u.u_r.r_val1 = uap->j;
+       if (uap->i == uap->j)
+               return;
+       if (u.u_ofile[uap->j]) {
+               if (u.u_pofile[uap->j] & UF_MAPPED)
+                       munmapfd(uap->j);
+               closef(u.u_ofile[uap->j]);
+               if (u.u_error)
+                       return;
+       }
+       dupit(uap->j, fp, u.u_pofile[uap->i]);
+}
+
+dupit(fd, fp, flags)
+       int fd;
+       register struct file *fp;
+       register int flags;
+{
+
+       u.u_ofile[fd] = fp;
+       u.u_pofile[fd] = flags;
+       fp->f_count++;
+}
+
+/*
+ * The file control system call.
+ */
+fcntl()
+{
+       register struct file *fp;
+       register struct a {
+               int     fdes;
+               int     cmd;
+               int     arg;
+       } *uap;
+       register i;
+       register char *pop;
+
+       uap = (struct a *)u.u_ap;
+       fp = getf(uap->fdes);
+       if (fp == NULL)
+               return;
+       pop = &u.u_pofile[uap->fdes];
+       switch(uap->cmd) {
+       case F_DUPFD:
+               i = uap->arg;
+               if (i < 0 || i > NOFILE) {
+                       u.u_error = EINVAL;
+                       return;
+               }
+               if ((i = ufalloc(i)) < 0)
+                       return;
+               dupit(i, fp, *pop);
+               break;
+
+       case F_GETFD:
+               u.u_r.r_val1 = *pop & 1;
+               break;
+
+       case F_SETFD:
+               *pop = (*pop &~ 1) | (uap->arg & 1);
+               break;
+
+       case F_GETFL:
+               u.u_r.r_val1 = fp->f_flag+FOPEN;
+               break;
+
+       case F_SETFL:
+               fp->f_flag &= FCNTLCANT;
+               fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
+               u.u_error = fset(fp, FNDELAY, fp->f_flag & FNDELAY);
+               if (u.u_error)
+                       break;
+               u.u_error = fset(fp, FASYNC, fp->f_flag & FASYNC);
+               if (u.u_error)
+                       (void) fset(fp, FNDELAY, 0);
+               break;
+
+       case F_GETOWN:
+               u.u_error = fgetown(fp, &u.u_r.r_val1);
+               break;
+
+       case F_SETOWN:
+               u.u_error = fsetown(fp, uap->arg);
+               break;
+
+       default:
+               u.u_error = EINVAL;
+       }
+}
+
+fset(fp, bit, value)
+       struct file *fp;
+       int bit, value;
+{
+
+       if (value)
+               fp->f_flag |= bit;
+       else
+               fp->f_flag &= ~bit;
+       return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
+           (caddr_t)&value));
+}
+
+fgetown(fp, valuep)
+       struct file *fp;
+       int *valuep;
+{
+       int error;
+
+       switch (fp->f_type) {
+
+       case DTYPE_SOCKET:
+               *valuep = ((struct socket *)fp->f_data)->so_pgrp;
+               return (0);
+
+       default:
+               error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
+               *valuep = -*valuep;
+               return (error);
+       }
+}
+
+fsetown(fp, value)
+       struct file *fp;
+       int value;
+{
+
+       if (fp->f_type == DTYPE_SOCKET) {
+               ((struct socket *)fp->f_data)->so_pgrp = value;
+               return (0);
+       }
+       if (value > 0) {
+               struct proc *p = pfind(value);
+               if (p == 0)
+                       return (EINVAL);
+               value = p->p_pgrp;
+       } else
+               value = -value;
+       return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
+}
+
+fioctl(fp, cmd, value)
+       struct file *fp;
+       int cmd;
+       caddr_t value;
+{
+
+       return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
+}
+
+close()
+{
+       register struct a {
+               int     i;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       register u_char *pf;
+
+       fp = getf(uap->i);
+       if (fp == 0)
+               return;
+       pf = (u_char *)&u.u_pofile[uap->i];
+       if (*pf & UF_MAPPED)
+               munmapfd(uap->i);
+       closef(fp);
+       /* WHAT IF u.u_error ? */
+       u.u_ofile[uap->i] = NULL;
+       *pf = 0;
+}
+
+fstat()
+{
+       register struct file *fp;
+       register struct a {
+               int     fdes;
+               struct  stat *sb;
+       } *uap;
+       struct stat ub;
+
+       uap = (struct a *)u.u_ap;
+       fp = getf(uap->fdes);
+       if (fp == 0)
+               return;
+       switch (fp->f_type) {
+
+       case DTYPE_INODE:
+               u.u_error = ino_stat((struct inode *)fp->f_data, &ub);
+               break;
+
+       case DTYPE_SOCKET:
+               u.u_error = soo_stat((struct socket *)fp->f_data, &ub);
+               break;
+
+       default:
+               panic("fstat");
+               /*NOTREACHED*/
+       }
+       if (u.u_error == 0)
+               u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb,
+                   sizeof (ub));
+}
+
+/*
+ * Allocate a user file descriptor.
+ */
+ufalloc(i)
+       register int i;
+{
+
+       for (; i < NOFILE; i++)
+               if (u.u_ofile[i] == NULL) {
+                       u.u_r.r_val1 = i;
+                       u.u_pofile[i] = 0;
+                       return (i);
+               }
+       u.u_error = EMFILE;
+       return (-1);
+}
+
+ufavail()
+{
+       register int i, avail = 0;
+
+       for (i = 0; i < NOFILE; i++)
+               if (u.u_ofile[i] == NULL)
+                       avail++;
+       return (avail);
+}
+
+struct file *lastf;
+/*
+ * Allocate a user file descriptor
+ * and a file structure.
+ * Initialize the descriptor
+ * to point at the file structure.
+ */
+struct file *
+falloc()
+{
+       register struct file *fp;
+       register i;
+
+       i = ufalloc(0);
+       if (i < 0)
+               return (NULL);
+       if (lastf == 0)
+               lastf = file;
+       for (fp = lastf; fp < fileNFILE; fp++)
+               if (fp->f_count == 0)
+                       goto slot;
+       for (fp = file; fp < lastf; fp++)
+               if (fp->f_count == 0)
+                       goto slot;
+       tablefull("file");
+       u.u_error = ENFILE;
+       return (NULL);
+slot:
+       u.u_ofile[i] = fp;
+       fp->f_count = 1;
+       fp->f_data = 0;
+       fp->f_offset = 0;
+       lastf = fp + 1;
+       return (fp);
+}
+
+/*
+ * Convert a user supplied file descriptor into a pointer
+ * to a file structure.  Only task is to check range of the descriptor.
+ * Critical paths should use the GETF macro.
+ */
+struct file *
+getf(f)
+       register int f;
+{
+       register struct file *fp;
+
+       if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) {
+               u.u_error = EBADF;
+               return (NULL);
+       }
+       return (fp);
+}
+
+/*
+ * Internal form of close.
+ * Decrement reference count on file structure.
+ * If last reference not going away, but no more
+ * references except in message queues, run a
+ * garbage collect.  This would better be done by
+ * forcing a gc() to happen sometime soon, rather
+ * than running one each time.
+ */
+closef(fp)
+       register struct file *fp;
+{
+
+       if (fp == NULL)
+               return;
+       if (fp->f_count > 1) {
+               fp->f_count--;
+               if (fp->f_count == fp->f_msgcount)
+                       unp_gc();
+               return;
+       }
+       (*fp->f_ops->fo_close)(fp);
+       fp->f_count = 0;
+}
+
+/*
+ * Apply an advisory lock on a file descriptor.
+ */
+flock()
+{
+       register struct a {
+               int     fd;
+               int     how;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+
+       fp = getf(uap->fd);
+       if (fp == NULL)
+               return;
+       if (fp->f_type != DTYPE_INODE) {
+               u.u_error = EOPNOTSUPP;
+               return;
+       }
+       if (uap->how & LOCK_UN) {
+               ino_unlock(fp, FSHLOCK|FEXLOCK);
+               return;
+       }
+       /* avoid work... */
+       if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
+           (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
+               return;
+       u.u_error = ino_lock(fp, uap->how);
+}
diff --git a/usr/src/sys/sys/kern_sig.c b/usr/src/sys/sys/kern_sig.c
new file mode 100644 (file)
index 0000000..07a8467
--- /dev/null
@@ -0,0 +1,783 @@
+/*     kern_sig.c      6.2     83/09/08        */
+
+#include "../machine/reg.h"
+#include "../machine/pte.h"
+#include "../machine/psl.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/proc.h"
+#include "../h/timeb.h"
+#include "../h/times.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/mount.h"
+#include "../h/text.h"
+#include "../h/seg.h"
+#include "../h/vm.h"
+#include "../h/acct.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+#include "../h/nami.h"
+
+#define        mask(s) (1 << ((s)-1))
+#define        cantmask        (mask(SIGKILL)|mask(SIGCONT)|mask(SIGSTOP))
+
+sigvec()
+{
+       register struct a {
+               int     signo;
+               struct  sigvec *nsv;
+               struct  sigvec *osv;
+       } *uap = (struct a  *)u.u_ap;
+       struct sigvec vec;
+       register struct sigvec *sv;
+       register int sig;
+
+       sig = uap->signo;
+       if (sig <= 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP) {
+               u.u_error = EINVAL;
+               return;
+       }
+       sv = &vec;
+       if (uap->osv) {
+               sv->sv_handler = u.u_signal[sig];
+               sv->sv_mask = u.u_sigmask[sig];
+               sv->sv_onstack = (u.u_sigonstack & mask(sig)) != 0;
+               u.u_error =
+                   copyout((caddr_t)sv, (caddr_t)uap->osv, sizeof (vec));
+               if (u.u_error)
+                       return;
+       }
+       if (uap->nsv) {
+               u.u_error =
+                   copyin((caddr_t)uap->nsv, (caddr_t)sv, sizeof (vec));
+               if (u.u_error)
+                       return;
+               if (sig == SIGCONT && sv->sv_handler == SIG_IGN) {
+                       u.u_error = EINVAL;
+                       return;
+               }
+               setsigvec(sig, sv);
+       }
+}
+
+setsigvec(sig, sv)
+       int sig;
+       register struct sigvec *sv;
+{
+       register struct proc *p;
+       register int bit;
+
+       bit = mask(sig);
+       p = u.u_procp;
+       /*
+        * Change setting atomically.
+        */
+       (void) spl6();
+       u.u_signal[sig] = sv->sv_handler;
+       u.u_sigmask[sig] = sv->sv_mask &~ cantmask;
+       if (sv->sv_onstack)
+               u.u_sigonstack |= bit;
+       else
+               u.u_sigonstack &= ~bit;
+       if (sv->sv_handler == SIG_IGN) {
+               p->p_sig &= ~bit;               /* never to be seen again */
+               p->p_sigignore |= bit;
+               p->p_sigcatch &= ~bit;
+       } else {
+               p->p_sigignore &= ~bit;
+               if (sv->sv_handler == SIG_DFL)
+                       p->p_sigcatch &= ~bit;
+               else
+                       p->p_sigcatch |= bit;
+       }
+       (void) spl0();
+}
+
+sigblock()
+{
+       struct a {
+               int     sigmask;
+       } *uap = (struct a *)u.u_ap;
+       register struct proc *p = u.u_procp;
+
+       (void) spl6();
+       u.u_r.r_val1 = p->p_sigmask;
+       p->p_sigmask |= uap->sigmask &~ cantmask;
+       (void) spl0();
+}
+
+sigsetmask()
+{
+       struct a {
+               int     sigmask;
+       } *uap = (struct a *)u.u_ap;
+       register struct proc *p = u.u_procp;
+
+       (void) spl6();
+       u.u_r.r_val1 = p->p_sigmask;
+       p->p_sigmask = uap->sigmask &~ cantmask;
+       (void) spl0();
+}
+
+sigpause()
+{
+       struct a {
+               int     sigmask;
+       } *uap = (struct a *)u.u_ap;
+       register struct proc *p = u.u_procp;
+
+       /*
+        * When returning from sigpause, we want
+        * the old mask to be restored after the
+        * signal handler has finished.  Thus, we
+        * save it here and mark the proc structure
+        * to indicate this (should be in u.).
+        */
+       u.u_oldmask = p->p_sigmask;
+       p->p_flag |= SOMASK;
+       p->p_sigmask = uap->sigmask &~ cantmask;
+       for (;;)
+               sleep((caddr_t)&u, PSLEP);
+       /*NOTREACHED*/
+}
+#undef cantmask
+#undef mask
+
+sigstack()
+{
+       register struct a {
+               struct  sigstack *nss;
+               struct  sigstack *oss;
+       } *uap = (struct a *)u.u_ap;
+       struct sigstack ss;
+
+       if (uap->oss) {
+               u.u_error = copyout((caddr_t)&u.u_sigstack, (caddr_t)uap->oss, 
+                   sizeof (struct sigstack));
+               if (u.u_error)
+                       return;
+       }
+       if (uap->nss) {
+               u.u_error =
+                   copyin((caddr_t)uap->nss, (caddr_t)&ss, sizeof (ss));
+               if (u.u_error == 0)
+                       u.u_sigstack = ss;
+       }
+}
+
+/* KILL SHOULD BE UPDATED */
+
+kill()
+{
+       register struct a {
+               int     pid;
+               int     signo;
+       } *uap = (struct a *)u.u_ap;
+
+       u.u_error = kill1(uap->signo < 0,
+               uap->signo < 0 ? -uap->signo : uap->signo, uap->pid);
+}
+
+killpg()
+{
+       register struct a {
+               int     pgrp;
+               int     signo;
+       } *uap = (struct a *)u.u_ap;
+
+       u.u_error = kill1(1, uap->signo, uap->pgrp);
+}
+
+/* KILL CODE SHOULDNT KNOW ABOUT PROCESS INTERNALS !?! */
+
+kill1(ispgrp, signo, who)
+       int ispgrp, signo, who;
+{
+       register struct proc *p;
+       int f, priv = 0;
+
+       if (signo < 0 || signo > NSIG)
+               return (EINVAL);
+       if (who > 0 && !ispgrp) {
+               p = pfind(who);
+               if (p == 0)
+                       return (ESRCH);
+               if (u.u_uid && u.u_uid != p->p_uid)
+                       return (EPERM);
+               if (signo)
+                       psignal(p, signo);
+               return (0);
+       }
+       if (who == -1 && u.u_uid == 0)
+               priv++, who = 0, ispgrp = 1;    /* like sending to pgrp */
+       else if (who == 0) {
+               /*
+                * Zero process id means send to my process group.
+                */
+               ispgrp = 1;
+               who = u.u_procp->p_pgrp;
+               if (who == 0)
+                       return (EINVAL);
+       }
+       for (f = 0, p = proc; p < procNPROC; p++) {
+               if (p->p_stat == NULL)
+                       continue;
+               if (!ispgrp) {
+                       if (p->p_pid != who)
+                               continue;
+               } else if (p->p_pgrp != who && priv == 0 || p->p_ppid == 0 ||
+                   (p->p_flag&SSYS) || (priv && p == u.u_procp))
+                       continue;
+               if (u.u_uid != 0 && u.u_uid != p->p_uid &&
+                   (signo != SIGCONT || !inferior(p)))
+                       continue;
+               f++;
+               if (signo)
+                       psignal(p, signo);
+       }
+       return (f == 0 ? ESRCH : 0);
+}
+
+/*
+ * Send the specified signal to
+ * all processes with 'pgrp' as
+ * process group.
+ */
+gsignal(pgrp, sig)
+       register int pgrp;
+{
+       register struct proc *p;
+
+       if (pgrp == 0)
+               return;
+       for(p = proc; p < procNPROC; p++)
+               if (p->p_pgrp == pgrp)
+                       psignal(p, sig);
+}
+
+/*
+ * Send the specified signal to
+ * the specified process.
+ */
+psignal(p, sig)
+       register struct proc *p;
+       register int sig;
+{
+       register int s;
+       register int (*action)();
+       int sigmask;
+
+       if ((unsigned)sig >= NSIG)
+               return;
+       sigmask = 1 << (sig-1);
+
+       /*
+        * If proc is traced, always give parent a chance.
+        */
+       if (p->p_flag & STRC)
+               action = SIG_DFL;
+       else {
+               /*
+                * If the signal is being ignored,
+                * then we forget about it immediately.
+                */
+               if (p->p_sigignore & sigmask)
+                       return;
+               if (p->p_sigmask & sigmask)
+                       action = SIG_HOLD;
+               else if (p->p_sigcatch & sigmask)
+                       action = SIG_CATCH;
+               else
+                       action = SIG_DFL;
+       }
+#define mask(sig)      (1<<(sig-1))
+#define        stops   (mask(SIGSTOP)|mask(SIGTSTP)|mask(SIGTTIN)|mask(SIGTTOU))
+       if (sig) {
+               p->p_sig |= sigmask;
+               switch (sig) {
+
+               case SIGTERM:
+                       if ((p->p_flag&STRC) || action != SIG_DFL)
+                               break;
+                       /* fall into ... */
+
+               case SIGKILL:
+                       if (p->p_nice > NZERO)
+                               p->p_nice = NZERO;
+                       break;
+
+               case SIGCONT:
+                       p->p_sig &= ~stops;
+                       break;
+
+               case SIGSTOP:
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                       p->p_sig &= ~mask(SIGCONT);
+                       break;
+               }
+       }
+#undef mask
+#undef stops
+       /*
+        * Defer further processing for signals which are held.
+        */
+       if (action == SIG_HOLD)
+               return;
+       s = spl6();
+       switch (p->p_stat) {
+
+       case SSLEEP:
+               /*
+                * If process is sleeping at negative priority
+                * we can't interrupt the sleep... the signal will
+                * be noticed when the process returns through
+                * trap() or syscall().
+                */
+               if (p->p_pri <= PZERO)
+                       goto out;
+               /*
+                * Process is sleeping and traced... make it runnable
+                * so it can discover the signal in issig() and stop
+                * for the parent.
+                */
+               if (p->p_flag&STRC)
+                       goto run;
+               switch (sig) {
+
+               case SIGSTOP:
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                       /*
+                        * These are the signals which by default
+                        * stop a process.
+                        */
+                       if (action != SIG_DFL)
+                               goto run;
+                       /*
+                        * Don't clog system with children of init
+                        * stopped from the keyboard.
+                        */
+                       if (sig != SIGSTOP && p->p_pptr == &proc[1]) {
+                               psignal(p, SIGKILL);
+                               p->p_sig &= ~sigmask;
+                               splx(s);
+                               return;
+                       }
+                       /*
+                        * If a child in vfork(), stopping could
+                        * cause deadlock.
+                        */
+                       if (p->p_flag&SVFORK)
+                               goto out;
+                       p->p_sig &= ~sigmask;
+                       p->p_cursig = sig;
+                       stop(p);
+                       goto out;
+
+               case SIGIO:
+               case SIGURG:
+               case SIGCHLD:
+                       /*
+                        * These signals are special in that they
+                        * don't get propogated... if the process
+                        * isn't interested, forget it.
+                        */
+                       if (action != SIG_DFL)
+                               goto run;
+                       p->p_sig &= ~sigmask;           /* take it away */
+                       goto out;
+
+               default:
+                       /*
+                        * All other signals cause the process to run
+                        */
+                       goto run;
+               }
+               /*NOTREACHED*/
+
+       case SSTOP:
+               /*
+                * If traced process is already stopped,
+                * then no further action is necessary.
+                */
+               if (p->p_flag&STRC)
+                       goto out;
+               switch (sig) {
+
+               case SIGKILL:
+                       /*
+                        * Kill signal always sets processes running.
+                        */
+                       goto run;
+
+               case SIGCONT:
+                       /*
+                        * If the process catches SIGCONT, let it handle
+                        * the signal itself.  If it isn't waiting on
+                        * an event, then it goes back to run state.
+                        * Otherwise, process goes back to sleep state.
+                        */
+                       if (action != SIG_DFL || p->p_wchan == 0)
+                               goto run;
+                       p->p_stat = SSLEEP;
+                       goto out;
+
+               case SIGSTOP:
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                       /*
+                        * Already stopped, don't need to stop again.
+                        * (If we did the shell could get confused.)
+                        */
+                       p->p_sig &= ~sigmask;           /* take it away */
+                       goto out;
+
+               default:
+                       /*
+                        * If process is sleeping interruptibly, then
+                        * unstick it so that when it is continued
+                        * it can look at the signal.
+                        * But don't setrun the process as its not to
+                        * be unstopped by the signal alone.
+                        */
+                       if (p->p_wchan && p->p_pri > PZERO)
+                               unsleep(p);
+                       goto out;
+               }
+               /*NOTREACHED*/
+
+       default:
+               /*
+                * SRUN, SIDL, SZOMB do nothing with the signal,
+                * other than kicking ourselves if we are running.
+                * It will either never be noticed, or noticed very soon.
+                */
+               if (p == u.u_procp && !noproc)
+#include "../vax/mtpr.h"
+                       aston();
+               goto out;
+       }
+       /*NOTREACHED*/
+run:
+       /*
+        * Raise priority to at least PUSER.
+        */
+       if (p->p_pri > PUSER)
+               if ((p != u.u_procp || noproc) && p->p_stat == SRUN &&
+                   (p->p_flag & SLOAD)) {
+                       remrq(p);
+                       p->p_pri = PUSER;
+                       setrq(p);
+               } else
+                       p->p_pri = PUSER;
+       setrun(p);
+out:
+       splx(s);
+}
+
+/*
+ * Returns true if the current
+ * process has a signal to process.
+ * The signal to process is put in p_cursig.
+ * This is asked at least once each time a process enters the
+ * system (though this can usually be done without actually
+ * calling issig by checking the pending signal masks.)
+ * A signal does not do anything
+ * directly to a process; it sets
+ * a flag that asks the process to
+ * do something to itself.
+ */
+issig()
+{
+       register struct proc *p;
+       register int sig;
+       int sigbits, sigmask;
+
+       p = u.u_procp;
+       for (;;) {
+               sigbits = p->p_sig &~ p->p_sigmask;
+               if ((p->p_flag&STRC) == 0)
+                       sigbits &= ~p->p_sigignore;
+               if (p->p_flag&SVFORK)
+#define bit(a) (1<<(a-1))
+                       sigbits &= ~(bit(SIGSTOP)|bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU));
+               if (sigbits == 0)
+                       break;
+               sig = ffs(sigbits);
+               sigmask = 1 << (sig-1);
+               p->p_sig &= ~sigmask;           /* take the signal! */
+               p->p_cursig = sig;
+               if (p->p_flag&STRC && (p->p_flag&SVFORK) == 0) {
+                       /*
+                        * If traced, always stop, and stay
+                        * stopped until released by the parent.
+                        */
+                       do {
+                               stop(p);
+                               swtch();
+                       } while (!procxmt() && p->p_flag&STRC);
+
+                       /*
+                        * If the traced bit got turned off,
+                        * then put the signal taken above back into p_sig
+                        * and go back up to the top to rescan signals.
+                        * This ensures that p_sig* and u_signal are consistent.
+                        */
+                       if ((p->p_flag&STRC) == 0) {
+                               p->p_sig |= sigmask;
+                               continue;
+                       }
+
+                       /*
+                        * If parent wants us to take the signal,
+                        * then it will leave it in p->p_cursig;
+                        * otherwise we just look for signals again.
+                        */
+                       sig = p->p_cursig;
+                       if (sig == 0)
+                               continue;
+
+                       /*
+                        * If signal is being masked put it back
+                        * into p_sig and look for other signals.
+                        */
+                       sigmask = 1 << (sig-1);
+                       if (p->p_sigmask & sigmask) {
+                               p->p_sig |= sigmask;
+                               continue;
+                       }
+               }
+               switch (u.u_signal[sig]) {
+
+               case SIG_DFL:
+                       /*
+                        * Don't take default actions on system processes.
+                        */
+                       if (p->p_ppid == 0)
+                               break;
+                       switch (sig) {
+
+                       case SIGTSTP:
+                       case SIGTTIN:
+                       case SIGTTOU:
+                               /*
+                                * Children of init aren't allowed to stop
+                                * on signals from the keyboard.
+                                */
+                               if (p->p_pptr == &proc[1]) {
+                                       psignal(p, SIGKILL);
+                                       continue;
+                               }
+                               /* fall into ... */
+
+                       case SIGSTOP:
+                               if (p->p_flag&STRC)
+                                       continue;
+                               stop(p);
+                               swtch();
+                               continue;
+
+                       case SIGCONT:
+                       case SIGCHLD:
+                       case SIGURG:
+                       case SIGIO:
+                               /*
+                                * These signals are normally not
+                                * sent if the action is the default.
+                                */
+                               continue;               /* == ignore */
+
+                       default:
+                               goto send;
+                       }
+                       /*NOTREACHED*/
+
+               case SIG_HOLD:
+               case SIG_IGN:
+                       /*
+                        * Masking above should prevent us
+                        * ever trying to take action on a held
+                        * or ignored signal, unless process is traced.
+                        */
+                       if ((p->p_flag&STRC) == 0)
+                               printf("issig\n");
+                       continue;
+
+               default:
+                       /*
+                        * This signal has an action, let
+                        * psig process it.
+                        */
+                       goto send;
+               }
+               /*NOTREACHED*/
+       }
+       /*
+        * Didn't find a signal to send.
+        */
+       p->p_cursig = 0;
+       return (0);
+
+send:
+       /*
+        * Let psig process the signal.
+        */
+       return (sig);
+}
+
+/*
+ * Put the argument process into the stopped
+ * state and notify the parent via wakeup and/or signal.
+ */
+stop(p)
+       register struct proc *p;
+{
+
+       p->p_stat = SSTOP;
+       p->p_flag &= ~SWTED;
+       wakeup((caddr_t)p->p_pptr);
+       /*
+        * Avoid sending signal to parent if process is traced
+        */
+       if (p->p_flag&STRC)
+               return;
+       psignal(p->p_pptr, SIGCHLD);
+}
+
+/*
+ * Perform the action specified by
+ * the current signal.
+ * The usual sequence is:
+ *     if (issig())
+ *             psig();
+ * The signal bit has already been cleared by issig,
+ * and the current signal number stored in p->p_cursig.
+ */
+psig()
+{
+       register struct proc *p = u.u_procp;
+       register int sig = p->p_cursig;
+       int sigmask = 1 << (sig - 1), returnmask;
+       register int (*action)();
+
+       if (sig == 0)
+               panic("psig");
+       action = u.u_signal[sig];
+       if (action != SIG_DFL) {
+               if (action == SIG_IGN || (p->p_sigmask & sigmask))
+                       panic("psig action");
+               u.u_error = 0;
+               /*
+                * Set the new mask value and also defer further
+                * occurences of this signal (unless we're simulating
+                * the old signal facilities). 
+                *
+                * Special case: user has done a sigpause.  Here the
+                * current mask is not of interest, but rather the
+                * mask from before the sigpause is what we want restored
+                * after the signal processing is completed.
+                */
+               (void) spl6();
+               if (p->p_flag & SOUSIG) {
+                       if (sig != SIGILL && sig != SIGTRAP) {
+                               u.u_signal[sig] = SIG_DFL;
+                               p->p_sigcatch &= ~sigmask;
+                       }
+                       sigmask = 0;
+               }
+               if (p->p_flag & SOMASK) {
+                       returnmask = u.u_oldmask;
+                       p->p_flag &= ~SOMASK;
+               } else
+                       returnmask = p->p_sigmask;
+               p->p_sigmask |= u.u_sigmask[sig] | sigmask;
+               (void) spl0();
+               u.u_ru.ru_nsignals++;
+               sendsig(action, sig, returnmask);
+               p->p_cursig = 0;
+               return;
+       }
+       u.u_acflag |= AXSIG;
+       switch (sig) {
+
+       case SIGILL:
+       case SIGIOT:
+       case SIGBUS:
+       case SIGQUIT:
+       case SIGTRAP:
+       case SIGEMT:
+       case SIGFPE:
+       case SIGSEGV:
+       case SIGSYS:
+               u.u_arg[0] = sig;
+               if (core())
+                       sig += 0200;
+       }
+       exit(sig);
+}
+
+/*
+ * Create a core image on the file "core"
+ * If you are looking for protection glitches,
+ * there are probably a wealth of them here
+ * when this occurs to a suid command.
+ *
+ * It writes UPAGES block of the
+ * user.h area followed by the entire
+ * data+stack segments.
+ */
+core()
+{
+       register struct inode *ip;
+       extern schar();
+
+       if (u.u_uid != u.u_ruid || u.u_gid != u.u_rgid)
+               return (0);
+       if (ctob(UPAGES+u.u_dsize+u.u_ssize) >=
+           u.u_rlimit[RLIMIT_CORE].rlim_cur)
+               return (0);
+       u.u_error = 0;
+       u.u_dirp = "core";
+       ip = namei(schar, CREATE, 1);
+       if (ip == NULL) {
+               if (u.u_error)
+                       return (0);
+               ip = maknode(0644);
+               if (ip==NULL)
+                       return (0);
+       }
+       if (access(ip, IWRITE) ||
+          (ip->i_mode&IFMT) != IFREG ||
+          ip->i_nlink != 1) {
+               u.u_error = EFAULT;
+               goto out;
+       }
+       itrunc(ip, (u_long)0);
+       u.u_acflag |= ACORE;
+       u.u_error = rdwri(UIO_WRITE, ip,
+           (caddr_t)&u,
+           ctob(UPAGES),
+           0, 1, (int *)0);
+       if (u.u_error == 0)
+               u.u_error = rdwri(UIO_WRITE, ip,
+                   (caddr_t)ctob(dptov(u.u_procp, 0)),
+                   ctob(u.u_dsize),
+                   ctob(UPAGES), 0, (int *)0);
+       if (u.u_error == 0)
+               u.u_error = rdwri(UIO_WRITE, ip,
+                   (caddr_t)ctob(sptov(u.u_procp, u.u_ssize - 1)),
+                   ctob(u.u_ssize),
+                   ctob(UPAGES)+ctob(u.u_dsize), 0, (int *)0);
+out:
+       iput(ip);
+       return (u.u_error == 0);
+}
diff --git a/usr/src/sys/sys/subr_xxx.c b/usr/src/sys/sys/subr_xxx.c
new file mode 100644 (file)
index 0000000..3a01cc3
--- /dev/null
@@ -0,0 +1,134 @@
+/*     subr_xxx.c      6.2     83/09/09        */
+
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/inode.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/proc.h"
+#include "../h/fs.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+#include "../h/uio.h"
+
+/*
+ * Routine placed in illegal entries in the bdevsw and cdevsw tables.
+ */
+nodev()
+{
+
+       return (ENODEV);
+}
+
+/*
+ * Null routine; placed in insignificant entries
+ * in the bdevsw and cdevsw tables.
+ */
+nulldev()
+{
+
+       return (0);
+}
+
+imin(a, b)
+{
+
+       return (a < b ? a : b);
+}
+
+imax(a, b)
+{
+
+       return (a > b ? a : b);
+}
+
+unsigned
+min(a, b)
+       u_int a, b;
+{
+
+       return (a < b ? a : b);
+}
+
+unsigned
+max(a, b)
+       u_int a, b;
+{
+
+       return (a > b ? a : b);
+}
+
+extern cabase, calimit;
+extern struct pte camap[];
+
+caddr_t        cacur = (caddr_t)&cabase;
+caddr_t        camax = (caddr_t)&cabase;
+int    cax = 0;
+/*
+ * This is a kernel-mode storage allocator.
+ * It is very primitive, currently, in that
+ * there is no way to give space back.
+ * It serves, for the time being, the needs of
+ * auto-configuration code and the like which
+ * need to allocate some stuff at boot time.
+ */
+caddr_t
+calloc(size)
+       int size;
+{
+       register caddr_t res;
+       register int i;
+
+       if (cacur+size >= (caddr_t)&calimit)
+               panic("calloc");
+       while (cacur+size > camax) {
+               (void) vmemall(&camap[cax], CLSIZE, &proc[0], CSYS);
+               vmaccess(&camap[cax], camax, CLSIZE);
+               for (i = 0; i < CLSIZE; i++)
+                       clearseg(camap[cax++].pg_pfnum);
+               camax += NBPG * CLSIZE;
+       }
+       res = cacur;
+       cacur += size;
+       return (res);
+}
+
+#ifndef vax
+ffs(mask)
+       register long mask;
+{
+       register int i;
+
+       for(i = 1; i < NSIG; i++) {
+               if (mask & 1)
+                       return (i);
+               mask >>= 1;
+       }
+       return (0);
+}
+
+bcmp(s1, s2, len)
+       register char *s1, *s2;
+       register int len;
+{
+
+       while (len--)
+               if (*s1++ != *s2++)
+                       return (1);
+       return (0);
+}
+
+strlen(s1)
+       register char *s1;
+{
+       register int len;
+
+       for (len = 0; *s1++ != '\0'; len++)
+               /* void */;
+       return (len);
+}
+#endif
diff --git a/usr/src/sys/sys/tty_conf.c b/usr/src/sys/sys/tty_conf.c
new file mode 100644 (file)
index 0000000..333a9b7
--- /dev/null
@@ -0,0 +1,71 @@
+/*     tty_conf.c      6.2     83/09/25        */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/tty.h"
+#include "../h/conf.h"
+
+int    nodev();
+int    nulldev();
+
+int    ttyopen(),ttyclose(),ttread(),ttwrite(),nullioctl(),ttstart();
+int    ttyinput();
+
+#include "bk.h"
+#if NBK > 0
+int    bkopen(),bkclose(),bkread(),bkinput(),bkioctl();
+#endif
+
+#include "tb.h"
+#if NTB > 0
+int    tbopen(),tbclose(),tbread(),tbinput(),tbioctl();
+#endif
+
+struct linesw linesw[] =
+{
+       ttyopen, nulldev, ttread, ttwrite, nullioctl,
+       ttyinput, nodev, nulldev, ttstart, nulldev,
+#if NBK > 0
+       bkopen, bkclose, bkread, ttwrite, bkioctl,
+       bkinput, nodev, nulldev, ttstart, nulldev,
+#else
+       nodev, nodev, nodev, nodev, nodev,
+       nodev, nodev, nodev, nodev, nodev,
+#endif
+       ttyopen, ttyclose, ttread, ttwrite, nullioctl,
+       ttyinput, nodev, nulldev, ttstart, nulldev,
+#if NTB > 0
+       tbopen, tbclose, tbread, nodev, tbioctl,
+       tbinput, nodev, nulldev, ttstart, nulldev,              /* 3 */
+#else
+       nodev, nodev, nodev, nodev, nodev,
+       nodev, nodev, nodev, nodev, nodev,
+#endif
+#if NTB > 0
+       tbopen, tbclose, tbread, nodev, tbioctl,
+       tbinput, nodev, nulldev, ttstart, nulldev,              /* 4 */
+#else
+       nodev, nodev, nodev, nodev, nodev,
+       nodev, nodev, nodev, nodev, nodev,
+#endif
+};
+
+int    nldisp = sizeof (linesw) / sizeof (linesw[0]);
+
+/*
+ * Do nothing specific version of line
+ * discipline specific ioctl command.
+ */
+/*ARGSUSED*/
+nullioctl(tp, cmd, data, flags)
+       struct tty *tp;
+       char *data;
+       int flags;
+{
+
+#ifdef lint
+       tp = tp; data = data; flags = flags;
+#endif
+       return (-1);
+}
diff --git a/usr/src/sys/sys/tty_tb.c b/usr/src/sys/sys/tty_tb.c
new file mode 100644 (file)
index 0000000..62f125c
--- /dev/null
@@ -0,0 +1,211 @@
+/*     tty_tb.c        6.2     83/09/22        */
+
+#include "tb.h"
+#if NTB > 0
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/ioctl.h"
+#include "../h/tty.h"
+#include "../h/proc.h"
+#include "../h/inode.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/uio.h"
+
+/*
+ * Line discipline for RS232 tablets.
+ * Supplies binary coordinate data.
+ *
+ * MAKE TABLET TYPE AN ioctl TO AVOID HAVING ONE DISCIPLINE PER TABLET TYPE.
+ */
+
+#define NTBS           (16)
+#define MALLTABCHAR    (8)
+#define MTABCHAR       (5)
+#define MNTABCHAR      (6)
+
+struct tb {
+       short used;
+       char cbuf[MALLTABCHAR];
+       struct tbpos {
+               int     xpos;
+               int     ypos;
+               short   status;
+               short   scount;
+       } tbpos;
+} tb[NTBS];
+
+/*
+ * Open as tablet discipline.  Called when discipline changed
+ * with ioctl, and changes the interpretation of the information
+ * in the tty structure.
+ */
+/*ARGSUSED*/
+tbopen(dev, tp)
+       dev_t dev;
+       register struct tty *tp;
+{
+       register struct tb *tbp;
+
+       if (tp->t_line == TABLDISC || tp->t_line == NTABLDISC)
+               return (ENODEV);
+       ttywflush(tp);
+       for (tbp = tb; tbp < &tb[NTBS]; tbp++)
+               if (!tbp->used)
+                       break;
+       if (tbp >= &tb[NTBS])
+               return (EBUSY);
+       tbp->used++;
+       tp->t_cp = tbp->cbuf;
+       tp->t_inbuf = 0;
+       tbp->tbpos.xpos = tbp->tbpos.ypos = 0;
+       tbp->tbpos.status = tbp->tbpos.scount = 0;
+       tp->T_LINEP = (caddr_t) tbp;
+       return (0);
+}
+
+/*
+ * Break down... called when discipline changed or from device
+ * close routine.
+ */
+tbclose(tp)
+       register struct tty *tp;
+{
+       register int s = spl5();
+
+       ((struct tb *) tp->T_LINEP)->used = 0;
+       tp->t_cp = 0;
+       tp->t_inbuf = 0;
+       tp->t_rawq.c_cc = 0;            /* clear queues -- paranoid */
+       tp->t_canq.c_cc = 0;
+       tp->t_line = 0;                 /* paranoid: avoid races */
+       splx(s);
+}
+
+/*
+ * Read from a tablet line.
+ * Characters have been buffered in a buffer and
+ * decoded. The coordinates are now sluffed back to the user.
+ */
+tbread(tp, uio)
+       register struct tty *tp;
+       struct uio *uio;
+{
+       struct tbpos *tbpos;
+
+       if ((tp->t_state&TS_CARR_ON)==0)
+               return (EIO);
+       tbpos = &(((struct tb *) (tp->T_LINEP))->tbpos);
+       return (uiomove(tbpos, sizeof *tbpos, UIO_READ, uio));
+}
+
+/*
+ * Low level character input routine.
+ * Stuff the character in the buffer, and decode the it
+ * if all the chars are there.
+ *
+ * This routine could be expanded in-line in the receiver
+ * interrupt routine of the dh-11 to make it run as fast as possible.
+ */
+int    LASTTABC;
+
+tbinput(c, tp)
+       register int c;
+       register struct tty *tp;
+{
+       register struct tb *tbp = (struct tb *) tp->T_LINEP;
+
+       if (tp->t_line == TABLDISC) {
+               if ((c&0200) || (tp->t_inbuf == MTABCHAR)) {
+                       tp->t_cp = tbp->cbuf;
+                       tp->t_inbuf = 0;
+               }
+               *tp->t_cp++ = c&0177;
+               if (++tp->t_inbuf == MTABCHAR)
+                       tbdecode(tbp->cbuf, &tbp->tbpos);
+       } else if (tp->t_line == NTABLDISC) {
+               if ((c&0200) || (tp->t_inbuf == MNTABCHAR)) {
+                       tp->t_cp = tbp->cbuf;
+                       tp->t_inbuf = 0;
+               }
+               *tp->t_cp++ = c&0177;
+               if (++tp->t_inbuf == MNTABCHAR)
+                       tbndecode(tbp->cbuf, &tbp->tbpos);
+       }
+}
+
+/*
+ * Decode tablet coordinates from ascii to binary.
+ *     (gtco 6 character format)
+ */
+tbndecode(cp, tbpos)
+       register char *cp;
+       register struct tbpos *tbpos;
+{
+
+       tbpos->status = *cp>>2; /* this needs to be decoded */
+       tbpos->xpos = ((*cp++)&03)<<14;
+       tbpos->xpos |= (*cp++)<<7;
+       tbpos->xpos |= (*cp++);
+       tbpos->ypos = ((*cp++)&03)<<14;
+       tbpos->ypos |= (*cp++)<<7;
+       tbpos->ypos |= (*cp++);
+       tbpos->scount++;
+}
+
+/*
+ * Decode tablet coordinates from ascii to binary.
+ *     (hitachi 5 character format)
+ */
+tbdecode(cp, tbpos)
+       register char *cp;
+       register struct tbpos *tbpos;
+{
+       register int status;
+       register char byte;
+
+       byte = *cp++;
+       status = (byte&0100) ? 0100000 : 0;
+       byte &= ~0100;
+       if (byte > 036)
+               status |= 1<<((byte-040)/2);
+       tbpos->xpos = (*cp++)<<7;
+       tbpos->xpos |= (*cp++);
+       if (tbpos->xpos < 256)          /* tablet wraps around at 256 */
+               status &= 077777;       /* make it out of proximity */
+       tbpos->ypos = (*cp++)<<7;
+       tbpos->ypos |= (*cp++);
+       tbpos->status  = status;
+       tbpos->scount++;
+}
+
+/*
+ * This routine is called whenever a ioctl is about to be performed
+ * and gets a chance to reject the ioctl.  We reject all teletype
+ * oriented ioctl's except those which set the discipline, and
+ * those which get parameters (gtty and get special characters).
+ */
+/*ARGSUSED*/
+tbioctl(tp, cmd, data, flag)
+       struct tty *tp;
+       caddr_t data;
+{
+
+       if ((cmd>>8) != 't')
+               return (cmd);
+       switch (cmd) {
+
+       case TIOCSETD:
+       case TIOCGETD:
+       case TIOCGETP:
+       case TIOCGETC:
+               return (cmd);
+       }
+       u.u_error = ENOTTY;
+       return (0);
+}
+#endif
diff --git a/usr/src/sys/sys/ufs_nami.c b/usr/src/sys/sys/ufs_nami.c
new file mode 100644 (file)
index 0000000..148d998
--- /dev/null
@@ -0,0 +1,844 @@
+/*     ufs_nami.c      6.2     83/09/09        */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/inode.h"
+#include "../h/fs.h"
+#include "../h/mount.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/uio.h"
+#include "../h/nami.h"
+
+struct buf *blkatoff();
+int    dirchk = 0;
+/*
+ * Convert a pathname into a pointer to a locked inode,
+ * with side effects usable in creating and removing files.
+ * This is a very central and rather complicated routine.
+ *
+ * The func argument gives the routine which returns successive
+ * characters of the name to be translated. 
+ *
+ * The flag argument is (LOOKUP, CREATE, DELETE) depending on whether
+ * the name is to be (looked up, created, deleted).  If flag has
+ * LOCKPARENT or'ed into it and the target of the pathname exists,
+ * namei returns both the target and its parent directory locked. 
+ * If the file system is not maintained in a strict tree hierarchy,
+ * this can result in a deadlock situation.  When creating and
+ * LOCKPARENT is specified, the target may not be ".".  When deleting
+ * and LOCKPARENT is specified, the target may be ".", but the caller
+ * must check to insure it does an irele and iput instead of two iputs.
+ *
+ * The follow argument is 1 when symbolic links are to be followed
+ * when they occur at the end of the name translation process.
+ *
+ * Overall outline:
+ *
+ *     copy in name
+ *     get starting directory
+ * dirloop:
+ *     check accessibility of directory
+ * dirloop2:
+ *     copy next component of name to u.u_dent
+ *     handle degenerate case where name is null string
+ *     search for name in directory, to found or notfound
+ * notfound:
+ *     if creating, return locked directory, leaving info on avail. slots
+ *     else return error
+ * found:
+ *     if at end of path and deleting, return information to allow delete
+ *     if at end of path and rewriting (create and LOCKPARENT), lock targe
+ *       inode and return info to allow rewrite
+ *     if .. and on mounted filesys, look in mount table for parent
+ *     if symbolic link, massage name in buffer and continue at dirloop
+ *     if more components of name, do next level at dirloop
+ *     return the answer as locked inode
+ *
+ * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode,
+ *      but unlocked.
+ */
+struct inode *
+namei(func, flag, follow)
+       int (*func)(), flag, follow;
+{
+       register char *cp;              /* pointer into pathname argument */
+/* these variables refer to things which must be freed or unlocked */
+       register struct inode *dp = 0;  /* the directory we are searching */
+       register struct fs *fs;         /* file system that directory is in */
+       register struct buf *bp = 0;    /* a buffer of directory entries */
+       register struct direct *ep;     /* the current directory entry */
+       int entryoffsetinblock;         /* offset of ep in bp's buffer */
+       register struct buf *nbp;       /* buffer storing path name argument */
+/* these variables hold information about the search for a slot */
+       enum {NONE, COMPACT, FOUND} slotstatus;
+       int slotoffset = -1;            /* offset of area with free space */
+       int slotsize;                   /* size of area at slotoffset */
+       int slotfreespace;              /* amount of space free in slot */
+       int slotneeded;                 /* size of the entry we're seeking */
+/* */
+       int dirsize;
+       int prevoff;                    /* u.u_offset of previous entry */
+       int nlink = 0;                  /* number of symbolic links taken */
+       struct inode *pdp;              /* saved dp during symlink work */
+       int i;
+       int lockparent;
+
+       lockparent = flag & LOCKPARENT;
+       flag &= ~LOCKPARENT;
+       /*
+        * Get a buffer for the name to be translated, and copy the
+        * name into the buffer.
+        */
+       nbp = geteblk(MAXPATHLEN);
+       for (cp = nbp->b_un.b_addr; *cp = (*func)(); ) {
+               if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != 2) {
+                       u.u_error = EPERM;
+                       goto bad;
+               }
+               cp++;
+               if (cp >= nbp->b_un.b_addr + MAXPATHLEN) {
+                       u.u_error = ENOENT;
+                       goto bad;
+               }
+       }
+       if (u.u_error)
+               goto bad;
+
+       /*
+        * Get starting directory.
+        */
+       cp = nbp->b_un.b_addr;
+       if (*cp == '/') {
+               while (*cp == '/')
+                       cp++;
+               if ((dp = u.u_rdir) == NULL)
+                       dp = rootdir;
+       } else
+               dp = u.u_cdir;
+       fs = dp->i_fs;
+       ilock(dp);
+       dp->i_count++;
+       u.u_pdir = (struct inode *)0xc0000000;          /* illegal */
+
+       /*
+        * We come to dirloop to search a new directory.
+        * The directory must be locked so that it can be
+        * iput, and fs must be already set to dp->i_fs.
+        */
+dirloop:
+       /*
+        * Check accessiblity of directory.
+        */
+       if ((dp->i_mode&IFMT) != IFDIR) {
+               u.u_error = ENOTDIR;
+               goto bad;
+       }
+       if (access(dp, IEXEC))
+               goto bad;
+
+dirloop2:
+       /*
+        * Copy next component of name to u.u_dent.
+        */
+       for (i = 0; *cp != 0 && *cp != '/'; cp++) {
+               if (i >= MAXNAMLEN) {
+                       u.u_error = ENOENT;
+                       goto bad;
+               }
+               u.u_dent.d_name[i++] = *cp;
+       }
+       u.u_dent.d_namlen = i;
+       u.u_dent.d_name[i] = 0;
+
+       /*
+        * Check for degenerate name (e.g. / or "")
+        * which is a way of talking about a directory,
+        * e.g. like "/." or ".".
+        */
+       if (u.u_dent.d_name[0] == 0) {
+               if (flag || lockparent) {
+                       u.u_error = EISDIR;
+                       goto bad;
+               }
+               brelse(nbp);
+               return (dp);
+       }
+
+       /*
+        * Suppress search for slots unless creating
+        * file and at end of pathname, in which case
+        * we watch for a place to put the new file in
+        * case it doesn't already exist.
+        */
+       slotstatus = FOUND;
+       if (flag == CREATE && *cp == 0) {
+               slotstatus = NONE;
+               slotfreespace = 0;
+               slotneeded = DIRSIZ(&u.u_dent);
+       }
+
+       dirsize = roundup(dp->i_size, DIRBLKSIZ);
+       u.u_offset = 0;
+       while (u.u_offset < dirsize) {
+               /*
+                * If offset is on a block boundary,
+                * read the next directory block.
+                * Release previous if it exists.
+                */
+               if (blkoff(fs, u.u_offset) == 0) {
+                       if (bp != NULL)
+                               brelse(bp);
+                       bp = blkatoff(dp, u.u_offset, (char **)0);
+                       if (bp == 0)
+                               goto bad;
+                       entryoffsetinblock = 0;
+               }
+
+               /*
+                * If still looking for a slot, and at a DIRBLKSIZE
+                * boundary, have to start looking for free space
+                * again.
+                */
+               if (slotstatus == NONE &&
+                   (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) {
+                       slotoffset = -1;
+                       slotfreespace = 0;
+               }
+
+               /*
+                * Get pointer to next entry, and do consistency checking:
+                *      record length must be multiple of 4
+                *      record length must not be zero
+                *      entry must fit in rest of this DIRBLKSIZ block
+                *      record must be large enough to contain name
+                * When dirchk is set we also check:
+                *      name is not longer than MAXNAMLEN
+                *      name must be as long as advertised, and null terminated
+                * Checking last two conditions is done only when dirchk is
+                * set, to save time.
+                */
+               ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
+               i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
+               if ((ep->d_reclen & 0x3) || ep->d_reclen == 0 ||
+                   ep->d_reclen > i || DIRSIZ(ep) > ep->d_reclen ||
+                   dirchk && (ep->d_namlen > MAXNAMLEN || dirbadname(ep))) {
+                       dirbad(dp, "mangled entry");
+                       u.u_offset += i;
+                       entryoffsetinblock += i;
+                       continue;
+               }
+
+               /*
+                * If an appropriate sized slot has not yet been found,
+                * check to see if one is available. Also accumulate space
+                * in the current block so that we can determine if
+                * compaction is viable.
+                */
+               if (slotstatus != FOUND) {
+                       int size = ep->d_reclen;
+
+                       if (ep->d_ino != 0)
+                               size -= DIRSIZ(ep);
+                       if (size > 0) {
+                               if (size >= slotneeded) {
+                                       slotstatus = FOUND;
+                                       slotoffset = u.u_offset;
+                                       slotsize = ep->d_reclen;
+                               } else if (slotstatus == NONE) {
+                                       slotfreespace += size;
+                                       if (slotoffset == -1)
+                                               slotoffset = u.u_offset;
+                                       if (slotfreespace >= slotneeded) {
+                                               slotstatus = COMPACT;
+                                               slotsize =
+                                                   u.u_offset+ep->d_reclen -
+                                                     slotoffset;
+                                       }
+                               }
+                       }
+               }
+
+               /*
+                * Check for a name match.
+                */
+               if (ep->d_ino) {
+                       if (ep->d_namlen == u.u_dent.d_namlen &&
+                           !bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen))
+                               goto found;
+               }
+               prevoff = u.u_offset;
+               u.u_offset += ep->d_reclen;
+               entryoffsetinblock += ep->d_reclen;
+       }
+/* notfound: */
+       /*
+        * If creating, and at end of pathname and current
+        * directory has not been removed, then can consider
+        * allowing file to be created.
+        */
+       if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) {
+               /*
+                * Access for write is interpreted as allowing
+                * creation of files in the directory.
+                */
+               if (access(dp, IWRITE))
+                       goto bad;
+               /*
+                * Return an indication of where the new directory
+                * entry should be put.  If we didn't find a slot,
+                * then set u.u_count to 0 indicating that the
+                * new slot belongs at the end of the directory.
+                * If we found a slot, then the new entry can be
+                * put in the range [u.u_offset..u.u_offset+u.u_count)
+                */
+               if (slotstatus == NONE)
+                       u.u_count = 0;
+               else {
+                       u.u_offset = slotoffset;
+                       u.u_count = slotsize;
+               }
+               dp->i_flag |= IUPD|ICHG;
+               if (bp)
+                       brelse(bp);
+               brelse(nbp);
+               /*
+                * We return with the directory locked, so that
+                * the parameters we set up above will still be
+                * valid if we actually decide to do a direnter().
+                * We return NULL to indicate that the entry doesn't
+                * currently exist, leaving a pointer to the (locked)
+                * directory inode in u.u_pdir.
+                */
+               u.u_pdir = dp;
+               return (NULL);
+       }
+       u.u_error = ENOENT;
+       goto bad;
+found:
+       /*
+        * Check that directory length properly reflects presence
+        * of this entry.
+        */
+       if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
+               dirbad(dp, "i_size too small");
+               dp->i_size = entryoffsetinblock + DIRSIZ(ep);
+               dp->i_flag |= IUPD|ICHG;
+       }
+
+       /*
+        * Found component in pathname; save directory
+        * entry in u.u_dent, and release directory buffer.
+        */
+       bcopy((caddr_t)ep, (caddr_t)&u.u_dent, (u_int)DIRSIZ(ep));
+       brelse(bp);
+       bp = NULL;
+
+       /*
+        * If deleting, and at end of pathname, return
+        * parameters which can be used to remove file.
+        * If the lockparent flag isn't set, we return only
+        * the directory (in u.u_pdir), otherwise we go
+        * on and lock the inode, being careful with ".".
+        */
+       if (flag == DELETE && *cp == 0) {
+               /*
+                * Write access to directory required to delete files.
+                */
+               if (access(dp, IWRITE))
+                       goto bad;
+               u.u_pdir = dp;          /* for dirremove() */
+               /*
+                * Return pointer to current entry in u.u_offset,
+                * and distance past previous entry (if there
+                * is a previous entry in this block) in u.u_count.
+                * Save directory inode pointer in u.u_pdir for dirremove().
+                */
+               if ((u.u_offset&(DIRBLKSIZ-1)) == 0)
+                       u.u_count = 0;
+               else
+                       u.u_count = u.u_offset - prevoff;
+               if (lockparent) {
+                       if (dp->i_number == u.u_dent.d_ino)
+                               dp->i_count++;
+                       else {
+                               dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
+                               if (dp == NULL) {
+                                       iput(u.u_pdir);
+                                       goto bad;
+                               }
+                       }
+               }
+               brelse(nbp);
+               return (dp);
+       }
+
+       /*
+        * Special handling for ".." allowing chdir out of mounted
+        * file system: indirect .. in root inode to reevaluate
+        * in directory file system was mounted on.
+        */
+       if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' &&
+           u.u_dent.d_name[2] == '\0') {
+               if (dp == u.u_rdir)
+                       u.u_dent.d_ino = dp->i_number;
+               else if (u.u_dent.d_ino == ROOTINO &&
+                  dp->i_number == ROOTINO) {
+                       for (i = 1; i < NMOUNT; i++)
+                       if (mount[i].m_bufp != NULL &&
+                          mount[i].m_dev == dp->i_dev) {
+                               iput(dp);
+                               dp = mount[i].m_inodp;
+                               ilock(dp);
+                               dp->i_count++;
+                               fs = dp->i_fs;
+                               cp -= 2;     /* back over .. */
+                               goto dirloop2;
+                       }
+               }
+       }
+
+       /*
+        * If rewriting (rename), return the inode and the
+        * information required to rewrite the present directory
+        * Must get inode of directory entry to verify it's a
+        * regular file, or empty directory.  
+        */
+       if ((flag == CREATE && lockparent) && *cp == 0) {
+               if (access(dp, IWRITE))
+                       goto bad;
+               u.u_pdir = dp;          /* for dirrewrite() */
+               /*
+                * Careful about locking second inode. 
+                * This can only occur if the target is ".". 
+                */
+               if (dp->i_number == u.u_dent.d_ino) {
+                       u.u_error = EISDIR;             /* XXX */
+                       goto bad;
+               }
+               dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
+               if (dp == NULL) {
+                       iput(u.u_pdir);
+                       goto bad;
+               }
+               brelse(nbp);
+               return (dp);
+       }
+
+       /*
+        * Check for symbolic link, which may require us to massage the
+        * name before we continue translation.  We do not `iput' the
+        * directory because we may need it again if the symbolic link
+        * is relative to the current directory.  Instead we save it
+        * unlocked as "pdp".  We must get the target inode before unlocking
+        * the directory to insure that the inode will not be removed
+        * before we get it.  We prevent deadlock by always fetching
+        * inodes from the root, moving down the directory tree. Thus
+        * when following backward pointers ".." we must unlock the
+        * parent directory before getting the requested directory.
+        * There is a potential race condition here if both the current
+        * and parent directories are removed before the `iget' for the
+        * inode associated with ".." returns.  We hope that this occurs
+        * infrequently since we cannot avoid this race condition without
+        * implementing a sophisticated deadlock detection algorithm.
+        * Note also that this simple deadlock detection scheme will not
+        * work if the file system has any hard links other than ".."
+        * that point backwards in the directory structure.
+        */
+       pdp = dp;
+       if (bcmp(u.u_dent.d_name, "..", 3) == 0) {
+               iunlock(pdp);   /* race to get the inode */
+               dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
+               if (dp == NULL)
+                       goto bad2;
+       } else if (dp->i_number == u.u_dent.d_ino) {
+               dp->i_count++;  /* we want ourself, ie "." */
+       } else {
+               dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
+               iunlock(pdp);
+               if (dp == NULL)
+                       goto bad2;
+       }
+       fs = dp->i_fs;
+
+       /*
+        * Check for symbolic link
+        */
+       if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) {
+               u_int pathlen = strlen(cp) + 1;
+
+               if (dp->i_size + pathlen >= MAXPATHLEN - 1 ||
+                   ++nlink > MAXSYMLINKS) {
+                       u.u_error = ELOOP;
+                       goto bad2;
+               }
+               ovbcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
+               u.u_error =
+                   rdwri(UIO_READ, dp, nbp->b_un.b_addr, (int)dp->i_size,
+                       0, 1, (int *)0);
+               if (u.u_error)
+                       goto bad2;
+               cp = nbp->b_un.b_addr;
+               iput(dp);
+               if (*cp == '/') {
+                       irele(pdp);
+                       while (*cp == '/')
+                               cp++;
+                       if ((dp = u.u_rdir) == NULL)
+                               dp = rootdir;
+                       ilock(dp);
+                       dp->i_count++;
+               } else {
+                       dp = pdp;
+                       ilock(dp);
+               }
+               fs = dp->i_fs;
+               goto dirloop;
+       }
+
+       /*
+        * Not a symbolic link.  If more pathname,
+        * continue at next component, else return.
+        */
+       if (*cp == '/') {
+               while (*cp == '/')
+                       cp++;
+               irele(pdp);
+               goto dirloop;
+       }
+       brelse(nbp);
+       if (lockparent)
+               u.u_pdir = pdp;
+       else
+               irele(pdp);
+       return (dp);
+bad2:
+       irele(pdp);
+bad:
+       if (bp)
+               brelse(bp);
+       if (dp)
+               iput(dp);
+       brelse(nbp);
+       return (NULL);
+}
+
+dirbad(ip, how)
+       struct inode *ip;
+       char *how;
+{
+
+       printf("%s: bad dir ino %d at offset %d: %s\n",
+           ip->i_fs->fs_fsmnt, ip->i_number, u.u_offset, how);
+}
+
+dirbadname(ep)
+       register struct direct *ep;
+{
+       register int i;
+
+       for (i = 0; i < ep->d_namlen; i++)
+               if (ep->d_name[i] == 0)
+                       return (1);
+       return (ep->d_name[i]);
+}
+
+/*
+ * Write a directory entry after a call to namei, using the parameters
+ * which it left in the u. area.  The argument ip is the inode which
+ * the new directory entry will refer to.  The u. area field u.u_pdir is
+ * a pointer to the directory to be written, which was left locked by
+ * namei.  Remaining parameters (u.u_offset, u.u_count) indicate
+ * how the space for the new entry is to be gotten.
+ */
+direnter(ip)
+       struct inode *ip;
+{
+       register struct direct *ep, *nep;
+       struct buf *bp;
+       int loc, spacefree, error = 0;
+       u_int dsize;
+       int newentrysize;
+       char *dirbuf;
+
+       u.u_dent.d_ino = ip->i_number;
+       u.u_segflg = 1;
+       newentrysize = DIRSIZ(&u.u_dent);
+       if (u.u_count == 0) {
+               /*
+                * If u.u_count is 0, then namei could find no space in the
+                * directory.  In this case u.u_offset will be on a directory
+                * block boundary and we will write the new entry into a fresh
+                * block.
+                */
+               if (u.u_offset&(DIRBLKSIZ-1))
+                       panic("wdir: newblk");
+               u.u_dent.d_reclen = DIRBLKSIZ;
+               error = rdwri(UIO_WRITE, u.u_pdir, (caddr_t)&u.u_dent,
+                   newentrysize, u.u_offset, 1, (int *)0);
+               iput(u.u_pdir);
+               return (error);
+       }
+
+       /*
+        * If u.u_count is non-zero, then namei found space for the
+        * new entry in the range u.u_offset to u.u_offset+u.u_count.
+        * in the directory.  To use this space, we may have to compact
+        * the entries located there, by copying them together towards
+        * the beginning of the block, leaving the free space in
+        * one usable chunk at the end.
+        */
+
+       /*
+        * Increase size of directory if entry eats into new space.
+        * This should never push the size past a new multiple of
+        * DIRBLKSIZE.
+        */
+       if (u.u_offset + u.u_count > u.u_pdir->i_size)
+               u.u_pdir->i_size = u.u_offset + u.u_count;
+
+       /*
+        * Get the block containing the space for the new directory
+        * entry.  Should return error by result instead of u.u_error.
+        */
+       bp = blkatoff(u.u_pdir, u.u_offset, (char **)&dirbuf);
+       if (bp == 0) {
+               iput(u.u_pdir);
+               return (u.u_error);
+       }
+
+       /*
+        * Find space for the new entry.  In the simple case, the
+        * entry at offset base will have the space.  If it does
+        * not, then namei arranged that compacting the region
+        * u.u_offset to u.u_offset+u.u_count would yield the space.
+        */
+       ep = (struct direct *)dirbuf;
+       dsize = DIRSIZ(ep);
+       spacefree = ep->d_reclen - dsize;
+       for (loc = ep->d_reclen; loc < u.u_count; ) {
+               nep = (struct direct *)(dirbuf + loc);
+               if (ep->d_ino) {
+                       /* trim the existing slot */
+                       ep->d_reclen = dsize;
+                       ep = (struct direct *)((char *)ep + dsize);
+               } else {
+                       /* overwrite; nothing there; header is ours */
+                       spacefree += dsize;     
+               }
+               dsize = DIRSIZ(nep);
+               spacefree += nep->d_reclen - dsize;
+               loc += nep->d_reclen;
+               bcopy((caddr_t)nep, (caddr_t)ep, dsize);
+       }
+       /*
+        * Update the pointer fields in the previous entry (if any),
+        * copy in the new entry, and write out the block.
+        */
+       if (ep->d_ino == 0) {
+               if (spacefree + dsize < newentrysize)
+                       panic("wdir: compact1");
+               u.u_dent.d_reclen = spacefree + dsize;
+       } else {
+               if (spacefree < newentrysize)
+                       panic("wdir: compact2");
+               u.u_dent.d_reclen = spacefree;
+               ep->d_reclen = dsize;
+               ep = (struct direct *)((char *)ep + dsize);
+       }
+       bcopy((caddr_t)&u.u_dent, (caddr_t)ep, (u_int)newentrysize);
+       bwrite(bp);
+       u.u_pdir->i_flag |= IUPD|ICHG;
+       iput(u.u_pdir);
+       return (error);
+}
+
+/*
+ * Remove a directory entry after a call to namei, using the
+ * parameters which it left in the u. area.  The u. entry
+ * u_offset contains the offset into the directory of the
+ * entry to be eliminated.  The u_count field contains the
+ * size of the previous record in the directory.  If this
+ * is 0, the first entry is being deleted, so we need only
+ * zero the inode number to mark the entry as free.  If the
+ * entry isn't the first in the directory, we must reclaim
+ * the space of the now empty record by adding the record size
+ * to the size of the previous entry.
+ */
+dirremove()
+{
+       register struct inode *dp = u.u_pdir;
+       register struct buf *bp;
+       struct direct *ep;
+
+       if (u.u_count == 0) {
+               /*
+                * First entry in block: set d_ino to zero.
+                */
+               u.u_dent.d_ino = 0;
+               (void) rdwri(UIO_WRITE, dp, (caddr_t)&u.u_dent,
+                   (int)DIRSIZ(&u.u_dent), u.u_offset, 1, (int *)0);
+       } else {
+               /*
+                * Collapse new free space into previous entry.
+                */
+               bp = blkatoff(dp, (int)(u.u_offset - u.u_count), (char **)&ep);
+               if (bp == 0)
+                       return (0);
+               ep->d_reclen += u.u_dent.d_reclen;
+               bwrite(bp);
+               dp->i_flag |= IUPD|ICHG;
+       }
+       return (1);
+}
+
+/*
+ * Rewrite an existing directory entry to point at the inode
+ * supplied.  The parameters describing the directory entry are
+ * set up by a call to namei.
+ */
+dirrewrite(dp, ip)
+       struct inode *dp, *ip;
+{
+
+       u.u_dent.d_ino = ip->i_number;
+       u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&u.u_dent,
+               (int)DIRSIZ(&u.u_dent), u.u_offset, 1, (int *)0);
+       iput(dp);
+}
+
+/*
+ * Return buffer with contents of block "offset"
+ * from the beginning of directory "ip".  If "res"
+ * is non-zero, fill it in with a pointer to the
+ * remaining space in the directory.
+ */
+struct buf *
+blkatoff(ip, offset, res)
+       struct inode *ip;
+       off_t offset;
+       char **res;
+{
+       register struct fs *fs = ip->i_fs;
+       daddr_t lbn = lblkno(fs, offset);
+       int base = blkoff(fs, offset);
+       int bsize = blksize(fs, ip, lbn);
+       daddr_t bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize));
+       register struct buf *bp;
+
+       if (u.u_error)
+               return (0);
+       bp = bread(ip->i_dev, bn, bsize);
+       if (bp->b_flags & B_ERROR) {
+               brelse(bp);
+               return (0);
+       }
+       if (res)
+               *res = bp->b_un.b_addr + base;
+       return (bp);
+}
+
+/*
+ * Check if a directory is empty or not.
+ * Inode supplied must be locked.
+ *
+ * Using a struct dirtemplate here is not precisely
+ * what we want, but better than using a struct direct.
+ *
+ * NB: does not handle corrupted directories.
+ */
+dirempty(ip)
+       register struct inode *ip;
+{
+       register off_t off;
+       struct dirtemplate dbuf;
+       register struct direct *dp = (struct direct *)&dbuf;
+       int error, count;
+#define        MINDIRSIZ (sizeof (struct dirtemplate) / 2)
+
+       for (off = 0; off < ip->i_size; off += dp->d_reclen) {
+               error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ,
+                   off, 1, &count);
+               /*
+                * Since we read MINDIRSIZ, residual must
+                * be 0 unless we're at end of file.
+                */
+               if (error || count != 0)
+                       return (0);
+               /* skip empty entries */
+               if (dp->d_ino == 0)
+                       continue;
+               /* accept only "." and ".." */
+               if (dp->d_namlen > 2)
+                       return (0);
+               if (dp->d_name[0] != '.')
+                       return (0);
+               /*
+                * At this point d_namlen must be 1 or 2.
+                * 1 implies ".", 2 implies ".." if second
+                * char is also "."
+                */
+               if (dp->d_namlen == 1 || dp->d_name[1] == '.')
+                       continue;
+               return (0);
+       }
+       return (1);
+}
+
+/*
+ * Check if source directory is in the path of the target directory.
+ * Target is supplied locked, source is unlocked.
+ * The target is always iput() before returning.
+ */
+checkpath(source, target)
+       struct inode *source, *target;
+{
+       struct dirtemplate dirbuf;
+       register struct inode *ip;
+       int error = 0;
+
+       ip = target;
+       if (ip->i_number == source->i_number) {
+               error = EEXIST;
+               goto out;
+       }
+       if (ip->i_number == ROOTINO)
+               goto out;
+
+       for (;;) {
+               if ((ip->i_mode&IFMT) != IFDIR) {
+                       error = ENOTDIR;
+                       break;
+               }
+               error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
+                       sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
+               if (error != 0)
+                       break;
+               if (dirbuf.dotdot_namlen != 2 ||
+                   bcmp(dirbuf.dotdot_name, "..", 3) != 0) {
+                       error = ENOTDIR;
+                       break;
+               }
+               if (dirbuf.dotdot_ino == source->i_number) {
+                       error = EINVAL;
+                       break;
+               }
+               if (dirbuf.dotdot_ino == ROOTINO)
+                       break;
+               iput(ip);
+               ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino);
+               if (ip == NULL) {
+                       error = u.u_error;
+                       break;
+               }
+       }
+
+out:
+       if (error == ENOTDIR)
+               printf("checkpath: .. not a directory\n");
+       if (ip != NULL)
+               iput(ip);
+       return (error);
+}
diff --git a/usr/src/sys/sys/uipc_syscalls.c b/usr/src/sys/sys/uipc_syscalls.c
new file mode 100644 (file)
index 0000000..8979f65
--- /dev/null
@@ -0,0 +1,824 @@
+/*     uipc_syscalls.c 6.2     83/09/25        */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/file.h"
+#include "../h/inode.h"
+#include "../h/buf.h"
+#include "../h/mbuf.h"
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/socketvar.h"
+#include "../h/uio.h"
+
+/*
+ * System call interface to the socket abstraction.
+ */
+
+struct file *getsock();
+extern struct fileops socketops;
+
+socket()
+{
+       register struct a {
+               int     domain;
+               int     type;
+               int     protocol;
+       } *uap = (struct a *)u.u_ap;
+       struct socket *so;
+       register struct file *fp;
+
+       if ((fp = falloc()) == NULL)
+               return;
+       fp->f_flag = FREAD|FWRITE;
+       fp->f_type = DTYPE_SOCKET;
+       fp->f_ops = &socketops;
+       u.u_error = socreate(uap->domain, &so, uap->type, uap->protocol);
+       if (u.u_error)
+               goto bad;
+       fp->f_data = (caddr_t)so;
+       return;
+bad:
+       u.u_ofile[u.u_r.r_val1] = 0;
+       fp->f_count = 0;
+}
+
+bind()
+{
+       register struct a {
+               int     s;
+               caddr_t name;
+               int     namelen;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       struct mbuf *nam;
+
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       u.u_error = sockargs(&nam, uap->name, uap->namelen);
+       if (u.u_error)
+               return;
+       u.u_error = sobind((struct socket *)fp->f_data, nam);
+       m_freem(nam);
+}
+
+listen()
+{
+       register struct a {
+               int     s;
+               int     backlog;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       u.u_error = solisten((struct socket *)fp->f_data, uap->backlog);
+}
+
+accept()
+{
+       register struct a {
+               int     s;
+               caddr_t name;
+               int     *anamelen;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       struct mbuf *nam;
+       int namelen;
+       int s;
+       register struct socket *so;
+
+       if (uap->name == 0)
+               goto noname;
+       u.u_error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen,
+               sizeof (namelen));
+       if (u.u_error)
+               return;
+       if (useracc((caddr_t)uap->name, (u_int)namelen, B_WRITE) == 0) {
+               u.u_error = EFAULT;
+               return;
+       }
+noname:
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       s = splnet();
+       so = (struct socket *)fp->f_data;
+       if ((so->so_options & SO_ACCEPTCONN) == 0) {
+               u.u_error = EINVAL;
+               splx(s);
+               return;
+       }
+       if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
+               u.u_error = EWOULDBLOCK;
+               splx(s);
+               return;
+       }
+       while (so->so_qlen == 0 && so->so_error == 0) {
+               if (so->so_state & SS_CANTRCVMORE) {
+                       so->so_error = ECONNABORTED;
+                       break;
+               }
+               sleep((caddr_t)&so->so_timeo, PZERO+1);
+       }
+       if (so->so_error) {
+               u.u_error = so->so_error;
+               splx(s);
+               return;
+       }
+       if (ufalloc(0) < 0) {
+               splx(s);
+               return;
+       }
+       fp = falloc();
+       if (fp == 0) {
+               u.u_ofile[u.u_r.r_val1] = 0;
+               splx(s);
+               return;
+       }
+       { struct socket *aso = so->so_q;
+         if (soqremque(aso, 1) == 0)
+               panic("accept");
+         so = aso;
+       }
+       fp->f_type = DTYPE_SOCKET;
+       fp->f_flag = FREAD|FWRITE;
+       fp->f_ops = &socketops;
+       fp->f_data = (caddr_t)so;
+       nam = m_get(M_WAIT, MT_SONAME);
+       (void) soaccept(so, nam);
+       if (uap->name) {
+               if (namelen > nam->m_len)
+                       namelen = nam->m_len;
+               /* SHOULD COPY OUT A CHAIN HERE */
+               (void) copyout(mtod(nam, caddr_t), (caddr_t)uap->name,
+                   (u_int)namelen);
+               (void) copyout((caddr_t)&namelen, (caddr_t)uap->anamelen,
+                   sizeof (*uap->anamelen));
+       }
+       m_freem(nam);
+       splx(s);
+}
+
+connect()
+{
+       register struct a {
+               int     s;
+               caddr_t name;
+               int     namelen;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       register struct socket *so;
+       struct mbuf *nam;
+       int s;
+
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       so = (struct socket *)fp->f_data;
+       u.u_error = sockargs(&nam, uap->name, uap->namelen);
+       if (u.u_error)
+               return;
+       u.u_error = soconnect(so, nam);
+       if (u.u_error)
+               goto bad;
+       s = splnet();
+       if ((so->so_state & SS_NBIO) &&
+           (so->so_state & SS_ISCONNECTING)) {
+               u.u_error = EINPROGRESS;
+               goto bad2;
+       }
+       if (setjmp(&u.u_qsave)) {
+               if (u.u_error == 0)
+                       u.u_error = EINTR;
+               goto bad2;
+       }
+       while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
+               sleep((caddr_t)&so->so_timeo, PZERO+1);
+       u.u_error = so->so_error;
+       so->so_error = 0;
+bad2:
+       splx(s);
+bad:
+       m_freem(nam);
+}
+
+socketpair()
+{
+       register struct a {
+               int     domain;
+               int     type;
+               int     protocol;
+               int     *rsv;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp1, *fp2;
+       struct socket *so1, *so2;
+       int sv[2];
+
+       if (useracc((caddr_t)uap->rsv, 2 * sizeof (int), B_WRITE) == 0) {
+               u.u_error = EFAULT;
+               return;
+       }
+       u.u_error = socreate(uap->domain, &so1, uap->type, uap->protocol);
+       if (u.u_error)
+               return;
+       u.u_error = socreate(uap->domain, &so2, uap->type, uap->protocol);
+       if (u.u_error)
+               goto free;
+       fp1 = falloc();
+       if (fp1 == NULL)
+               goto free2;
+       sv[0] = u.u_r.r_val1;
+       fp1->f_flag = FREAD|FWRITE;
+       fp1->f_type = DTYPE_SOCKET;
+       fp1->f_ops = &socketops;
+       fp1->f_data = (caddr_t)so1;
+       fp2 = falloc();
+       if (fp2 == NULL)
+               goto free3;
+       fp2->f_flag = FREAD|FWRITE;
+       fp2->f_type = DTYPE_SOCKET;
+       fp2->f_ops = &socketops;
+       fp2->f_data = (caddr_t)so2;
+       sv[1] = u.u_r.r_val1;
+       u.u_error = soconnect2(so1, so2);
+       if (u.u_error)
+               goto free4;
+       (void) copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int));
+       return;
+free4:
+       fp2->f_count = 0;
+       u.u_ofile[sv[1]] = 0;
+free3:
+       fp1->f_count = 0;
+       u.u_ofile[sv[0]] = 0;
+free2:
+       so2->so_state |= SS_NOFDREF;
+       sofree(so2);
+free:
+       so1->so_state |= SS_NOFDREF;
+       sofree(so1);
+}
+
+sendto()
+{
+       register struct a {
+               int     s;
+               caddr_t buf;
+               int     len;
+               int     flags;
+               caddr_t to;
+               int     tolen;
+       } *uap = (struct a *)u.u_ap;
+       struct msghdr msg;
+       struct iovec aiov;
+
+       msg.msg_name = uap->to;
+       msg.msg_namelen = uap->tolen;
+       msg.msg_iov = &aiov;
+       msg.msg_iovlen = 1;
+       aiov.iov_base = uap->buf;
+       aiov.iov_len = uap->len;
+       msg.msg_accrights = 0;
+       msg.msg_accrightslen = 0;
+       sendit(uap->s, &msg, uap->flags);
+}
+
+send()
+{
+       register struct a {
+               int     s;
+               caddr_t buf;
+               int     len;
+               int     flags;
+       } *uap = (struct a *)u.u_ap;
+       struct msghdr msg;
+       struct iovec aiov;
+
+       msg.msg_name = 0;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &aiov;
+       msg.msg_iovlen = 1;
+       aiov.iov_base = uap->buf;
+       aiov.iov_len = uap->len;
+       msg.msg_accrights = 0;
+       msg.msg_accrightslen = 0;
+       sendit(uap->s, &msg, uap->flags);
+}
+
+sendmsg()
+{
+       register struct a {
+               int     s;
+               caddr_t msg;
+               int     flags;
+       } *uap = (struct a *)u.u_ap;
+       struct msghdr msg;
+       struct iovec aiov[MSG_MAXIOVLEN];
+
+       u.u_error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
+       if (u.u_error)
+               return;
+       if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) {
+               u.u_error = EMSGSIZE;
+               return;
+       }
+       u.u_error =
+           copyin((caddr_t)msg.msg_iov, (caddr_t)aiov,
+               (unsigned)(msg.msg_iovlen * sizeof (aiov[0])));
+       if (u.u_error)
+               return;
+       msg.msg_iov = aiov;
+#ifdef notdef
+printf("sendmsg name %x namelen %d iov %x iovlen %d accrights %x &len %d\n",
+msg.msg_name, msg.msg_namelen, msg.msg_iov, msg.msg_iovlen,
+msg.msg_accrights, msg.msg_accrightslen);
+#endif
+       sendit(uap->s, &msg, uap->flags);
+}
+
+sendit(s, mp, flags)
+       int s;
+       register struct msghdr *mp;
+       int flags;
+{
+       register struct file *fp;
+       struct uio auio;
+       register struct iovec *iov;
+       register int i;
+       struct mbuf *to, *rights;
+       int len;
+       
+       fp = getsock(s);
+       if (fp == 0)
+               return;
+       auio.uio_iov = mp->msg_iov;
+       auio.uio_iovcnt = mp->msg_iovlen;
+       auio.uio_segflg = 0;
+       auio.uio_offset = 0;                    /* XXX */
+       auio.uio_resid = 0;
+       iov = mp->msg_iov;
+       for (i = 0; i < mp->msg_iovlen; i++) {
+               if (iov->iov_len < 0) {
+                       u.u_error = EINVAL;
+                       return;
+               }
+               if (iov->iov_len == 0)
+                       continue;
+               if (useracc(iov->iov_base, (u_int)iov->iov_len, B_READ) == 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+               auio.uio_resid += iov->iov_len;
+               iov++;
+       }
+       if (mp->msg_name) {
+               u.u_error =
+                   sockargs(&to, mp->msg_name, mp->msg_namelen);
+               if (u.u_error)
+                       return;
+       } else
+               to = 0;
+       if (mp->msg_accrights) {
+               u.u_error =
+                   sockargs(&rights, mp->msg_accrights, mp->msg_accrightslen);
+               if (u.u_error)
+                       goto bad;
+       } else
+               rights = 0;
+       len = auio.uio_resid;
+       u.u_error =
+           sosend((struct socket *)fp->f_data, to, &auio, flags, rights);
+       u.u_r.r_val1 = len - auio.uio_resid;
+       if (rights)
+               m_freem(rights);
+bad:
+       if (to)
+               m_freem(to);
+}
+
+recvfrom()
+{
+       register struct a {
+               int     s;
+               caddr_t buf;
+               int     len;
+               int     flags;
+               caddr_t from;
+               int     *fromlenaddr;
+       } *uap = (struct a *)u.u_ap;
+       struct msghdr msg;
+       struct iovec aiov;
+       int len;
+
+       u.u_error = copyin((caddr_t)uap->fromlenaddr, (caddr_t)&len,
+          sizeof (len));
+       if (u.u_error)
+               return;
+       msg.msg_name = uap->from;
+       msg.msg_namelen = len;
+       msg.msg_iov = &aiov;
+       msg.msg_iovlen = 1;
+       aiov.iov_base = uap->buf;
+       aiov.iov_len = uap->len;
+       msg.msg_accrights = 0;
+       msg.msg_accrightslen = 0;
+       recvit(uap->s, &msg, uap->flags, (caddr_t)uap->fromlenaddr, (caddr_t)0);
+}
+
+recv()
+{
+       register struct a {
+               int     s;
+               caddr_t buf;
+               int     len;
+               int     flags;
+       } *uap = (struct a *)u.u_ap;
+       struct msghdr msg;
+       struct iovec aiov;
+
+       msg.msg_name = 0;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &aiov;
+       msg.msg_iovlen = 1;
+       aiov.iov_base = uap->buf;
+       aiov.iov_len = uap->len;
+       msg.msg_accrights = 0;
+       msg.msg_accrightslen = 0;
+       recvit(uap->s, &msg, uap->flags, (caddr_t)0, (caddr_t)0);
+}
+
+recvmsg()
+{
+       register struct a {
+               int     s;
+               struct  msghdr *msg;
+               int     flags;
+       } *uap = (struct a *)u.u_ap;
+       struct msghdr msg;
+       struct iovec aiov[MSG_MAXIOVLEN];
+
+       u.u_error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg));
+       if (u.u_error)
+               return;
+       if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) {
+               u.u_error = EMSGSIZE;
+               return;
+       }
+       u.u_error =
+           copyin((caddr_t)msg.msg_iov, (caddr_t)aiov,
+               (unsigned)(msg.msg_iovlen * sizeof (aiov[0])));
+       if (u.u_error)
+               return;
+       msg.msg_iov = aiov;
+       if (msg.msg_accrights)
+               if (useracc((caddr_t)msg.msg_accrights,
+                   (unsigned)msg.msg_accrightslen, B_WRITE) == 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+       recvit(uap->s, &msg, uap->flags,
+           (caddr_t)&uap->msg->msg_namelen,
+           (caddr_t)&uap->msg->msg_accrightslen);
+}
+
+recvit(s, mp, flags, namelenp, rightslenp)
+       int s;
+       register struct msghdr *mp;
+       int flags;
+       caddr_t namelenp, rightslenp;
+{
+       register struct file *fp;
+       struct uio auio;
+       register struct iovec *iov;
+       register int i;
+       struct mbuf *from, *rights;
+       int len;
+       
+       fp = getsock(s);
+       if (fp == 0)
+               return;
+       auio.uio_iov = mp->msg_iov;
+       auio.uio_iovcnt = mp->msg_iovlen;
+       auio.uio_segflg = 0;
+       auio.uio_offset = 0;                    /* XXX */
+       auio.uio_resid = 0;
+       iov = mp->msg_iov;
+       for (i = 0; i < mp->msg_iovlen; i++) {
+               if (iov->iov_len < 0) {
+                       u.u_error = EINVAL;
+                       return;
+               }
+               if (iov->iov_len == 0)
+                       continue;
+               if (useracc(iov->iov_base, (u_int)iov->iov_len, B_WRITE) == 0) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+               auio.uio_resid += iov->iov_len;
+               iov++;
+       }
+       len = auio.uio_resid;
+       u.u_error =
+           soreceive((struct socket *)fp->f_data, &from, &auio,
+               flags, &rights);
+       u.u_r.r_val1 = len - auio.uio_resid;
+       if (mp->msg_name) {
+               len = mp->msg_namelen;
+               if (len <= 0 || from == 0)
+                       len = 0;
+               else {
+                       if (len > from->m_len)
+                               len = from->m_len;
+                       (void) copyout((caddr_t)mtod(from, caddr_t),
+                           (caddr_t)mp->msg_name, (unsigned)len);
+               }
+               (void) copyout((caddr_t)&len, namelenp, sizeof (int));
+       }
+       if (mp->msg_accrights) {
+               len = mp->msg_accrightslen;
+               if (len <= 0 || rights == 0)
+                       len = 0;
+               else {
+                       if (len > rights->m_len)
+                               len = rights->m_len;
+                       (void) copyout((caddr_t)mtod(rights, caddr_t),
+                           (caddr_t)mp->msg_accrights, (unsigned)len);
+               }
+               (void) copyout((caddr_t)&len, rightslenp, sizeof (int));
+       }
+       if (rights)
+               m_freem(rights);
+       if (from)
+               m_freem(from);
+}
+
+shutdown()
+{
+       struct a {
+               int     s;
+               int     how;
+       } *uap = (struct a *)u.u_ap;
+       struct file *fp;
+
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       u.u_error = soshutdown((struct socket *)fp->f_data, uap->how);
+}
+
+setsockopt()
+{
+       struct a {
+               int     s;
+               int     level;
+               int     name;
+               caddr_t val;
+               int     valsize;
+       } *uap = (struct a *)u.u_ap;
+       struct file *fp;
+       struct mbuf *m = NULL;
+
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       if (uap->valsize > MLEN) {
+               u.u_error = EINVAL;
+               return;
+       }
+       if (uap->val) {
+               m = m_get(M_WAIT, MT_SOOPTS);
+               if (m == NULL) {
+                       u.u_error = ENOBUFS;
+                       return;
+               }
+               u.u_error =
+                   copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
+               if (u.u_error)
+                       goto bad;
+               m->m_len = uap->valsize;
+       }
+       u.u_error =
+           sosetopt((struct socket *)fp->f_data, uap->level, uap->name, m);
+bad:
+       if (m != NULL)
+               (void) m_free(m);
+}
+
+getsockopt()
+{
+       struct a {
+               int     s;
+               int     level;
+               int     name;
+               caddr_t val;
+               int     *avalsize;
+       } *uap = (struct a *)u.u_ap;
+       struct file *fp;
+       struct mbuf *m = NULL;
+       int valsize;
+
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       if (uap->val) {
+               u.u_error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
+                       sizeof (valsize));
+               if (u.u_error)
+                       return;
+               m = m_get(M_WAIT, MT_SOOPTS);
+               if (m == NULL) {
+                       u.u_error = ENOBUFS;
+                       return;
+               }
+       }
+       u.u_error =
+           sogetopt((struct socket *)fp->f_data, uap->level, uap->name, m);
+       if (u.u_error)
+               goto bad;
+       if (uap->val) {
+               if (valsize > m->m_len)
+                       valsize = m->m_len;
+               u.u_error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize);
+               if (u.u_error)
+                       goto bad;
+               u.u_error = copyout((caddr_t)&valsize, (caddr_t)uap->avalsize,
+                   sizeof (valsize));
+       }
+bad:
+       if (m != NULL)
+               (void) m_free(m);
+}
+
+pipe()
+{
+       register struct file *rf, *wf;
+       struct socket *rso, *wso;
+       int r;
+
+       u.u_error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0);
+       if (u.u_error)
+               return;
+       u.u_error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0);
+       if (u.u_error)
+               goto free;
+       rf = falloc();
+       if (rf == NULL)
+               goto free2;
+       r = u.u_r.r_val1;
+       rf->f_flag = FREAD;
+       rf->f_type = DTYPE_SOCKET;
+       rf->f_ops = &socketops;
+       rf->f_data = (caddr_t)rso;
+       wf = falloc();
+       if (wf == NULL)
+               goto free3;
+       wf->f_flag = FWRITE;
+       wf->f_type = DTYPE_SOCKET;
+       wf->f_ops = &socketops;
+       wf->f_data = (caddr_t)wso;
+       u.u_r.r_val2 = u.u_r.r_val1;
+       u.u_r.r_val1 = r;
+       if (piconnect(wso, rso) == 0)
+               goto free4;
+       return;
+free4:
+       wf->f_count = 0;
+       u.u_ofile[u.u_r.r_val2] = 0;
+free3:
+       rf->f_count = 0;
+       u.u_ofile[r] = 0;
+free2:
+       wso->so_state |= SS_NOFDREF;
+       sofree(wso);
+free:
+       rso->so_state |= SS_NOFDREF;
+       sofree(rso);
+}
+
+/*
+ * Get socket name.
+ */
+getsockname()
+{
+       register struct a {
+               int     fdes;
+               caddr_t asa;
+               int     *alen;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       register struct socket *so;
+       struct mbuf *m;
+       int len;
+
+       fp = getsock(uap->fdes);
+       if (fp == 0)
+               return;
+       u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
+       if (u.u_error)
+               return;
+       so = (struct socket *)fp->f_data;
+       m = m_getclr(M_WAIT, MT_SONAME);
+       if (m == NULL) {
+               u.u_error = ENOBUFS;
+               return;
+       }
+       u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
+       if (u.u_error)
+               goto bad;
+       if (len > m->m_len)
+               len = m->m_len;
+       u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
+       if (u.u_error)
+               goto bad;
+       u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
+bad:
+       m_freem(m);
+}
+
+/*
+ * Get name of peer for connected socket.
+ */
+getpeername()
+{
+       register struct a {
+               int     fdes;
+               caddr_t asa;
+               int     *alen;
+       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       register struct socket *so;
+       struct mbuf *m;
+       int len;
+
+       fp = getsock(uap->fdes);
+       if (fp == 0)
+               return;
+       so = (struct socket *)fp->f_data;
+       if ((so->so_state & SS_ISCONNECTED) == 0) {
+               u.u_error = ENOTCONN;
+               return;
+       }
+       m = m_getclr(M_WAIT, MT_SONAME);
+       if (m == NULL) {
+               u.u_error = ENOBUFS;
+               return;
+       }
+       u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
+       if (u.u_error)
+               return;
+       u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0);
+       if (u.u_error)
+               goto bad;
+       if (len > m->m_len)
+               len = m->m_len;
+       u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
+       if (u.u_error)
+               goto bad;
+       u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
+bad:
+       m_freem(m);
+}
+
+sockargs(aname, name, namelen)
+       struct mbuf **aname;
+       caddr_t name;
+       int namelen;
+{
+       register struct mbuf *m;
+       int error;
+
+       if (namelen > MLEN)
+               return (EINVAL);
+       m = m_get(M_WAIT, MT_SONAME);
+       if (m == NULL)
+               return (ENOBUFS);
+       m->m_len = namelen;
+       error = copyin(name, mtod(m, caddr_t), (u_int)namelen);
+       if (error)
+               (void) m_free(m);
+       else
+               *aname = m;
+       return (error);
+}
+
+struct file *
+getsock(fdes)
+       int fdes;
+{
+       register struct file *fp;
+
+       fp = getf(fdes);
+       if (fp == NULL)
+               return (0);
+       if (fp->f_type != DTYPE_SOCKET) {
+               u.u_error = ENOTSOCK;
+               return (0);
+       }
+       return (fp);
+}
diff --git a/usr/src/sys/sys/uipc_usrreq.c b/usr/src/sys/sys/uipc_usrreq.c
new file mode 100644 (file)
index 0000000..df87c7c
--- /dev/null
@@ -0,0 +1,601 @@
+/*     uipc_usrreq.c   6.2     83/09/08        */
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/mbuf.h"
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/socketvar.h"
+#include "../h/unpcb.h"
+#include "../h/un.h"
+#include "../h/inode.h"
+#include "../h/nami.h"
+#include "../h/file.h"
+
+/*
+ * Unix communications domain.
+ *
+ * TODO:
+ *     SEQPACKET, RDM
+ *     rethink name space problems
+ *     need a proper out-of-band
+ */
+struct sockaddr sun_noname = { AF_UNIX };
+
+/*ARGSUSED*/
+uipc_usrreq(so, req, m, nam, rights)
+       struct socket *so;
+       int req;
+       struct mbuf *m, *nam, *rights;
+{
+       struct unpcb *unp = sotounpcb(so);
+       register struct socket *so2;
+       int error = 0;
+
+       if (req != PRU_SEND && rights && rights->m_len) {
+               error = EOPNOTSUPP;
+               goto release;
+       }
+       if (unp == 0 && req != PRU_ATTACH) {
+               error = EINVAL;
+               goto release;
+       }
+       switch (req) {
+
+       case PRU_ATTACH:
+               if (unp) {
+                       error = EISCONN;
+                       break;
+               }
+               error = unp_attach(so);
+               break;
+
+       case PRU_DETACH:
+               unp_detach(unp);
+               break;
+
+       case PRU_BIND:
+               error = unp_bind(unp, nam);
+               break;
+
+       case PRU_LISTEN:
+               if (unp->unp_inode == 0)
+                       error = EINVAL;
+               break;
+
+       case PRU_CONNECT:
+               error = unp_connect(so, nam);
+               break;
+
+       case PRU_CONNECT2:
+               error = unp_connect2(so, (struct mbuf *)0,
+                   (struct socket *)nam);
+               break;
+
+       case PRU_DISCONNECT:
+               unp_disconnect(unp);
+               break;
+
+       case PRU_ACCEPT:
+               nam->m_len = unp->unp_remaddr->m_len;
+               bcopy(mtod(unp->unp_remaddr, caddr_t),
+                   mtod(nam, caddr_t), (unsigned)nam->m_len);
+               break;
+
+       case PRU_SHUTDOWN:
+               socantsendmore(so);
+               unp_usrclosed(unp);
+               break;
+
+       case PRU_RCVD:
+               switch (so->so_type) {
+
+               case SOCK_DGRAM:
+                       panic("uipc 1");
+                       /*NOTREACHED*/
+
+               case SOCK_STREAM:
+#define        rcv (&so->so_rcv)
+#define snd (&so2->so_snd)
+                       if (unp->unp_conn == 0)
+                               break;
+                       so2 = unp->unp_conn->unp_socket;
+                       /*
+                        * Transfer resources back to send port
+                        * and wakeup any waiting to write.
+                        */
+                       snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
+                       rcv->sb_mbmax = rcv->sb_mbcnt;
+                       snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
+                       rcv->sb_hiwat = rcv->sb_cc;
+                       sbwakeup(snd);
+#undef snd
+#undef rcv
+                       break;
+
+               default:
+                       panic("uipc 2");
+               }
+               break;
+
+       case PRU_SEND:
+               switch (so->so_type) {
+
+               case SOCK_DGRAM:
+                       if (nam) {
+                               if (unp->unp_conn) {
+                                       error = EISCONN;
+                                       break;
+                               }
+                               error = unp_connect(so, nam);
+                               if (error)
+                                       break;
+                       } else {
+                               if (unp->unp_conn == 0) {
+                                       error = ENOTCONN;
+                                       break;
+                               }
+                       }
+                       so2 = unp->unp_conn->unp_socket;
+                       /* BEGIN XXX */
+                       if (rights) {
+                               error = unp_internalize(rights);
+                               if (error)
+                                       break;
+                       }
+                       if (sbspace(&so2->so_rcv) > 0) {
+                               /*
+                                * There's no record of source socket's
+                                * name, so send null name for the moment.
+                                */
+                               (void) sbappendaddr(&so2->so_rcv,
+                                   &sun_noname, m, rights);
+                               sbwakeup(&so2->so_rcv);
+                               m = 0;
+                       }
+                       /* END XXX */
+                       if (nam)
+                               unp_disconnect(unp);
+                       break;
+
+               case SOCK_STREAM:
+#define        rcv (&so2->so_rcv)
+#define        snd (&so->so_snd)
+                       if (rights && rights->m_len) {
+                               error = EOPNOTSUPP;
+                               break;
+                       }
+                       if (unp->unp_conn == 0)
+                               panic("uipc 3");
+                       so2 = unp->unp_conn->unp_socket;
+                       /*
+                        * Send to paired receive port, and then
+                        * give it enough resources to hold what it already has.
+                        * Wake up readers.
+                        */
+                       sbappend(rcv, m);
+                       snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
+                       rcv->sb_mbmax = rcv->sb_mbcnt;
+                       snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
+                       rcv->sb_hiwat = rcv->sb_cc;
+                       sbwakeup(rcv);
+#undef snd
+#undef rcv
+                       break;
+
+               default:
+                       panic("uipc 4");
+               }
+               m = 0;
+               break;
+
+       case PRU_ABORT:
+               unp_drop(unp, ECONNABORTED);
+               break;
+
+/* SOME AS YET UNIMPLEMENTED HOOKS */
+       case PRU_CONTROL:
+               return (EOPNOTSUPP);
+
+       case PRU_SENSE:
+               error = EOPNOTSUPP;
+               break;
+/* END UNIMPLEMENTED HOOKS */
+
+       case PRU_RCVOOB:
+               break;
+
+       case PRU_SENDOOB:
+               break;
+
+       case PRU_SOCKADDR:
+               break;
+
+       case PRU_PEERADDR:
+               break;
+
+       case PRU_SLOWTIMO:
+               break;
+
+       default:
+               panic("piusrreq");
+       }
+release:
+       if (m)
+               m_freem(m);
+       return (error);
+}
+
+/* SHOULD BE PIPSIZ and 0 */
+int    unp_sendspace = 1024*2;
+int    unp_recvspace = 1024*2;
+
+unp_attach(so)
+       struct socket *so;
+{
+       register struct mbuf *m;
+       register struct unpcb *unp;
+       int error;
+       
+       error = soreserve(so, unp_sendspace, unp_recvspace);
+       if (error)
+               return (error);
+       m = m_getclr(M_DONTWAIT, MT_PCB);
+       if (m == NULL)
+               return (ENOBUFS);
+       unp = mtod(m, struct unpcb *);
+       so->so_pcb = (caddr_t)unp;
+       unp->unp_socket = so;
+       return (0);
+}
+
+unp_detach(unp)
+       register struct unpcb *unp;
+{
+       
+       if (unp->unp_inode) {
+               irele(unp->unp_inode);
+               unp->unp_inode = 0;
+       }
+       if (unp->unp_conn)
+               unp_disconnect(unp);
+       while (unp->unp_refs)
+               unp_drop(unp->unp_refs, ECONNRESET);
+       soisdisconnected(unp->unp_socket);
+       unp->unp_socket->so_pcb = 0;
+       m_freem(unp->unp_remaddr);
+       (void) m_free(dtom(unp));
+}
+
+unp_bind(unp, nam)
+       struct unpcb *unp;
+       struct mbuf *nam;
+{
+       struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
+       register struct inode *ip;
+       extern schar();
+       int error;
+
+       u.u_dirp = soun->sun_path;
+       if (nam->m_len == MLEN)
+               return (EINVAL);
+       *(mtod(nam, caddr_t) + nam->m_len) = 0;
+/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
+       ip = namei(schar, CREATE, 1);
+       if (ip) {
+               iput(ip);
+               return (EADDRINUSE);
+       }
+       if (error = u.u_error) {
+               u.u_error = 0;                  /* XXX */
+               return (error);
+       }
+       ip = maknode(IFSOCK | 0777);
+       if (ip == NULL) {
+               error = u.u_error;              /* XXX */
+               u.u_error = 0;                  /* XXX */
+               return (error);
+       }
+       ip->i_socket = unp->unp_socket;
+       unp->unp_inode = ip;
+       iunlock(ip);                    /* but keep reference */
+       return (0);
+}
+
+unp_connect(so, nam)
+       struct socket *so;
+       struct mbuf *nam;
+{
+       register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
+       register struct inode *ip;
+       int error;
+       register struct socket *so2;
+
+       u.u_dirp = soun->sun_path;
+       if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
+               return (EMSGSIZE);
+       *(mtod(nam, caddr_t) + nam->m_len) = 0;
+       ip = namei(schar, LOOKUP, 1);
+       if (ip == 0) {
+               error = u.u_error;
+               u.u_error = 0;
+               return (error);         /* XXX */
+       }
+       if ((ip->i_mode&IFMT) != IFSOCK) {
+               error = ENOTSOCK;
+               goto bad;
+       }
+       so2 = ip->i_socket;
+       if (so2 == 0) {
+               error = ECONNREFUSED;
+               goto bad;
+       }
+       if (so->so_type != so2->so_type) {
+               error = EPROTOTYPE;
+               goto bad;
+       }
+       if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
+           ((so2->so_options&SO_ACCEPTCONN) == 0 ||
+            (so2 = sonewconn(so2)) == 0)) {
+               error = ECONNREFUSED;
+               goto bad;
+       }
+       error = unp_connect2(so, nam, so2);
+bad:
+       iput(ip);
+       return (error);
+}
+
+unp_connect2(so, sonam, so2)
+       register struct socket *so;
+       struct mbuf *sonam;
+       register struct socket *so2;
+{
+       register struct unpcb *unp = sotounpcb(so);
+       register struct unpcb *unp2;
+
+       if (so2->so_type != so->so_type)
+               return (EPROTOTYPE);
+       unp2 = sotounpcb(so2);
+       unp->unp_conn = unp2;
+       switch (so->so_type) {
+
+       case SOCK_DGRAM:
+               unp->unp_nextref = unp2->unp_refs;
+               unp2->unp_refs = unp;
+               break;
+
+       case SOCK_STREAM:
+               unp2->unp_conn = unp;
+               if (sonam)
+                       unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
+               soisconnected(so2);
+               soisconnected(so);
+               break;
+
+       default:
+               panic("unp_connect2");
+       }
+       return (0);
+}
+
+unp_disconnect(unp)
+       struct unpcb *unp;
+{
+       register struct unpcb *unp2 = unp->unp_conn;
+
+       if (unp2 == 0)
+               return;
+       unp->unp_conn = 0;
+       switch (unp->unp_socket->so_type) {
+
+       case SOCK_DGRAM:
+               if (unp2->unp_refs == unp)
+                       unp2->unp_refs = unp->unp_nextref;
+               else {
+                       unp2 = unp2->unp_refs;
+                       for (;;) {
+                               if (unp2 == 0)
+                                       panic("unp_disconnect");
+                               if (unp2->unp_nextref == unp)
+                                       break;
+                               unp2 = unp2->unp_nextref;
+                       }
+                       unp2->unp_nextref = unp->unp_nextref;
+               }
+               unp->unp_nextref = 0;
+               break;
+
+       case SOCK_STREAM:
+               soisdisconnected(unp->unp_socket);
+               unp2->unp_conn = 0;
+               soisdisconnected(unp2->unp_socket);
+               break;
+       }
+}
+
+#ifdef notdef
+unp_abort(unp)
+       struct unpcb *unp;
+{
+
+       unp_detach(unp);
+}
+#endif
+
+/*ARGSUSED*/
+unp_usrclosed(unp)
+       struct unpcb *unp;
+{
+
+}
+
+unp_drop(unp, errno)
+       struct unpcb *unp;
+       int errno;
+{
+
+       unp->unp_socket->so_error = errno;
+       unp_disconnect(unp);
+}
+
+#ifdef notdef
+unp_drain()
+{
+
+}
+#endif
+
+unp_externalize(rights)
+       struct mbuf *rights;
+{
+       int newfds = rights->m_len / sizeof (int);
+       register int i;
+       register struct file **rp = mtod(rights, struct file **);
+       register struct file *fp;
+       int f;
+
+       if (newfds > ufavail()) {
+               for (i = 0; i < newfds; i++) {
+                       fp = *rp;
+                       unp_discard(fp);
+                       *rp++ = 0;
+               }
+               return (EMSGSIZE);
+       }
+       for (i = 0; i < newfds; i++) {
+               f = ufalloc(0);
+               if (f < 0)
+                       panic("unp_externalize");
+               fp = *rp;
+               u.u_ofile[f] = fp;
+               fp->f_msgcount--;
+               *(int *)rp++ = f;
+       }
+       return (0);
+}
+
+unp_internalize(rights)
+       struct mbuf *rights;
+{
+       register struct file **rp;
+       int oldfds = rights->m_len / sizeof (int);
+       register int i;
+       register struct file *fp;
+
+       rp = mtod(rights, struct file **);
+       for (i = 0; i < oldfds; i++)
+               if (getf(*(int *)rp++) == 0)
+                       return (EBADF);
+       rp = mtod(rights, struct file **);
+       for (i = 0; i < oldfds; i++) {
+               fp = getf(*(int *)rp);
+               *rp++ = fp;
+               fp->f_count++;
+               fp->f_msgcount++;
+       }
+       return (0);
+}
+
+int    unp_defer, unp_gcing;
+int    unp_mark();
+
+unp_gc()
+{
+       register struct file *fp;
+       register struct socket *so;
+
+       if (unp_gcing)
+               return;
+       unp_gcing = 1;
+restart:
+       unp_defer = 0;
+       for (fp = file; fp < fileNFILE; fp++)
+               fp->f_flag &= ~(FMARK|FDEFER);
+       do {
+               for (fp = file; fp < fileNFILE; fp++) {
+                       if (fp->f_count == 0)
+                               continue;
+                       if (fp->f_flag & FDEFER) {
+                               fp->f_flag &= ~FDEFER;
+                               unp_defer--;
+                       } else {
+                               if (fp->f_flag & FMARK)
+                                       continue;
+                               if (fp->f_count == fp->f_msgcount)
+                                       continue;
+                               fp->f_flag |= FMARK;
+                       }
+                       if (fp->f_type != DTYPE_SOCKET)
+                               continue;
+                       so = (struct socket *)fp->f_data;
+                       if (so->so_proto->pr_family != AF_UNIX ||
+                           (so->so_proto->pr_flags&PR_ADDR) == 0)
+                               continue;
+                       if (so->so_rcv.sb_flags & SB_LOCK) {
+                               sbwait(&so->so_rcv);
+                               goto restart;
+                       }
+                       unp_scan(so->so_rcv.sb_mb, unp_mark);
+               }
+       } while (unp_defer);
+       for (fp = file; fp < fileNFILE; fp++) {
+               if (fp->f_count == 0)
+                       continue;
+               if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
+                       if (fp->f_type != DTYPE_SOCKET)
+                               panic("unp_gc");
+                       (void) soshutdown((struct socket *)fp->f_data, 0);
+               }
+       }
+       unp_gcing = 0;
+}
+
+unp_scan(m, op)
+       register struct mbuf *m;
+       int (*op)();
+{
+       register struct file **rp;
+       register int i;
+       int qfds;
+
+       while (m) {
+               m = m->m_next;
+               if (m == 0)
+                       goto bad;
+               if (m->m_len) {
+                       qfds = m->m_len / sizeof (struct file *);
+                       rp = mtod(m, struct file **);
+                       for (i = 0; i < qfds; i++)
+                               (*op)(*rp++);
+               }
+               do {
+                       m = m->m_next;
+                       if (m == 0)
+                               goto bad;
+               } while (m->m_act == 0);
+               m = m->m_next;
+       }
+       return;
+bad:
+       panic("unp_gcscan");
+}
+
+unp_mark(fp)
+       struct file *fp;
+{
+
+       if (fp->f_flag & FMARK)
+               return;
+       unp_defer++;
+       fp->f_flag |= (FMARK|FDEFER);
+}
+
+unp_discard(fp)
+       struct file *fp;
+{
+
+       fp->f_msgcount--;
+       closef(fp);
+}
diff --git a/usr/src/sys/sys/vm_swp.c b/usr/src/sys/sys/vm_swp.c
new file mode 100644 (file)
index 0000000..47ca9ff
--- /dev/null
@@ -0,0 +1,258 @@
+/*     vm_swp.c        6.2     83/09/09        */
+
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/proc.h"
+#include "../h/seg.h"
+#include "../h/vm.h"
+#include "../h/trace.h"
+#include "../h/map.h"
+#include "../h/uio.h"
+
+/*
+ * Swap IO headers -
+ * They contain the necessary information for the swap I/O.
+ * At any given time, a swap header can be in three
+ * different lists. When free it is in the free list, 
+ * when allocated and the I/O queued, it is on the swap 
+ * device list, and finally, if the operation was a dirty 
+ * page push, when the I/O completes, it is inserted 
+ * in a list of cleaned pages to be processed by the pageout daemon.
+ */
+struct buf *swbuf;
+
+/*
+ * swap I/O -
+ *
+ * If the flag indicates a dirty page push initiated
+ * by the pageout daemon, we map the page into the i th
+ * virtual page of process 2 (the daemon itself) where i is
+ * the index of the swap header that has been allocated.
+ * We simply initialize the header and queue the I/O but
+ * do not wait for completion. When the I/O completes,
+ * iodone() will link the header to a list of cleaned
+ * pages to be processed by the pageout daemon.
+ */
+swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent)
+       struct proc *p;
+       swblk_t dblkno;
+       caddr_t addr;
+       int nbytes, rdflg, flag;
+       dev_t dev;
+       u_int pfcent;
+{
+       register struct buf *bp;
+       register u_int c;
+       int p2dp;
+       register struct pte *dpte, *vpte;
+       int s;
+       extern swdone();
+
+       s = spl6();
+       while (bswlist.av_forw == NULL) {
+               bswlist.b_flags |= B_WANTED;
+               sleep((caddr_t)&bswlist, PSWP+1);
+       }
+       bp = bswlist.av_forw;
+       bswlist.av_forw = bp->av_forw;
+       splx(s);
+
+       bp->b_flags = B_BUSY | B_PHYS | rdflg | flag;
+       if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0)
+               if (rdflg == B_READ)
+                       sum.v_pswpin += btoc(nbytes);
+               else
+                       sum.v_pswpout += btoc(nbytes);
+       bp->b_proc = p;
+       if (flag & B_DIRTY) {
+               p2dp = ((bp - swbuf) * CLSIZE) * KLMAX;
+               dpte = dptopte(&proc[2], p2dp);
+               vpte = vtopte(p, btop(addr));
+               for (c = 0; c < nbytes; c += NBPG) {
+                       if (vpte->pg_pfnum == 0 || vpte->pg_fod)
+                               panic("swap bad pte");
+                       *dpte++ = *vpte++;
+               }
+               bp->b_un.b_addr = (caddr_t)ctob(dptov(&proc[2], p2dp));
+               bp->b_flags |= B_CALL;
+               bp->b_iodone = swdone;
+               bp->b_pfcent = pfcent;
+       } else
+               bp->b_un.b_addr = addr;
+       while (nbytes > 0) {
+               bp->b_bcount = nbytes;
+               minphys(bp);
+               c = bp->b_bcount;
+               bp->b_blkno = dblkno;
+               bp->b_dev = dev;
+#ifdef TRACE
+               trace(TR_SWAPIO, dev, bp->b_blkno);
+#endif
+               physstrat(bp, bdevsw[major(dev)].d_strategy, PSWP);
+               if (flag & B_DIRTY) {
+                       if (c < nbytes)
+                               panic("big push");
+                       return;
+               }
+               bp->b_un.b_addr += c;
+               bp->b_flags &= ~B_DONE;
+               if (bp->b_flags & B_ERROR) {
+                       if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE)
+                               panic("hard IO err in swap");
+                       swkill(p, (char *)0);
+               }
+               nbytes -= c;
+               dblkno += btodb(c);
+       }
+       s = spl6();
+       bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
+       bp->av_forw = bswlist.av_forw;
+       bswlist.av_forw = bp;
+       if (bswlist.b_flags & B_WANTED) {
+               bswlist.b_flags &= ~B_WANTED;
+               wakeup((caddr_t)&bswlist);
+               wakeup((caddr_t)&proc[2]);
+       }
+       splx(s);
+}
+
+/*
+ * Put a buffer on the clean list after I/O is done.
+ * Called from biodone.
+ */
+swdone(bp)
+       register struct buf *bp;
+{
+       register int s;
+
+       if (bp->b_flags & B_ERROR)
+               panic("IO err in push");
+       s = spl6();
+       bp->av_forw = bclnlist;
+       cnt.v_pgout++;
+       cnt.v_pgpgout += bp->b_bcount / NBPG;
+       bclnlist = bp;
+       if (bswlist.b_flags & B_WANTED)
+               wakeup((caddr_t)&proc[2]);
+       splx(s);
+}
+
+/*
+ * If rout == 0 then killed on swap error, else
+ * rout is the name of the routine where we ran out of
+ * swap space.
+ */
+swkill(p, rout)
+       struct proc *p;
+       char *rout;
+{
+       char *mesg;
+
+       printf("pid %d: ", p->p_pid);
+       if (rout)
+               printf(mesg = "killed due to no swap space\n");
+       else
+               printf(mesg = "killed on swap error\n");
+       uprintf("sorry, pid %d was %s", p->p_pid, mesg);
+       /*
+        * To be sure no looping (e.g. in vmsched trying to
+        * swap out) mark process locked in core (as though
+        * done by user) after killing it so noone will try
+        * to swap it out.
+        */
+       psignal(p, SIGKILL);
+       p->p_flag |= SULOCK;
+}
+
+/*
+ * Raw I/O. The arguments are
+ *     The strategy routine for the device
+ *     A buffer, which will always be a special buffer
+ *       header owned exclusively by the device for this purpose
+ *     The device number
+ *     Read/write flag
+ * Essentially all the work is computing physical addresses and
+ * validating them.
+ * If the user has the proper access privilidges, the process is
+ * marked 'delayed unlock' and the pages involved in the I/O are
+ * faulted and locked. After the completion of the I/O, the above pages
+ * are unlocked.
+ */
+physio(strat, bp, dev, rw, mincnt, uio)
+       int (*strat)(); 
+       register struct buf *bp;
+       dev_t dev;
+       int rw;
+       unsigned (*mincnt)();
+       struct uio *uio;
+{
+       register struct iovec *iov = uio->uio_iov;
+       register int c;
+       char *a;
+       int s, error = 0;
+
+nextiov:
+       if (uio->uio_iovcnt == 0)
+               return (0);
+       if (useracc(iov->iov_base,(u_int)iov->iov_len,rw==B_READ?B_WRITE:B_READ) == NULL)
+               return (EFAULT);
+       s = spl6();
+       while (bp->b_flags&B_BUSY) {
+               bp->b_flags |= B_WANTED;
+               sleep((caddr_t)bp, PRIBIO+1);
+       }
+       splx(s);
+       bp->b_error = 0;
+       bp->b_proc = u.u_procp;
+       bp->b_un.b_addr = iov->iov_base;
+       while (iov->iov_len > 0) {
+               bp->b_flags = B_BUSY | B_PHYS | rw;
+               bp->b_dev = dev;
+               bp->b_blkno = btodb(uio->uio_offset);
+               bp->b_bcount = iov->iov_len;
+               (*mincnt)(bp);
+               c = bp->b_bcount;
+               u.u_procp->p_flag |= SPHYSIO;
+               vslock(a = bp->b_un.b_addr, c);
+               physstrat(bp, strat, PRIBIO);
+               (void) spl6();
+               vsunlock(a, c, rw);
+               u.u_procp->p_flag &= ~SPHYSIO;
+               if (bp->b_flags&B_WANTED)
+                       wakeup((caddr_t)bp);
+               splx(s);
+               c -= bp->b_resid;
+               bp->b_un.b_addr += c;
+               iov->iov_len -= c;
+               uio->uio_resid -= c;
+               uio->uio_offset += c;
+               /* temp kludge for tape drives */
+               if (bp->b_resid || (bp->b_flags&B_ERROR))
+                       break;
+       }
+       bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
+       error = geterror(bp);
+       /* temp kludge for tape drives */
+       if (bp->b_resid || error)
+               return (error);
+       uio->uio_iov++;
+       uio->uio_iovcnt--;
+       goto nextiov;
+}
+
+#define        MAXPHYS (63 * 1024)
+
+unsigned
+minphys(bp)
+       struct buf *bp;
+{
+
+       if (bp->b_bcount > MAXPHYS)
+               bp->b_bcount = MAXPHYS;
+}
diff --git a/usr/src/sys/vax/asm.sed b/usr/src/sys/vax/asm.sed
new file mode 100644 (file)
index 0000000..6c7f65b
--- /dev/null
@@ -0,0 +1,123 @@
+s,asm.sed 4.27 83/09/08,asm.sed 4.27 83/09/08,
+s/calls        $0,_spl0/mfpr   $18,r0\
+       mtpr    $0,$18/
+s/calls        $0,_spl1/mfpr   $18,r0\
+       mtpr    $0,$18/
+s/calls        $0,_splnet/mfpr $18,r0\
+       mtpr    $0xc,$18/
+s/calls        $0,_splimp/mfpr $18,r0\
+       mtpr    $0x16,$18/
+s/calls        $0,_spl4/mfpr   $18,r0\
+       mtpr    $0x14,$18/
+s/calls        r[0-9]*,_spl4/mfpr      $18,r0\
+       mtpr    $0x14,$18/
+s/calls        $0,_spl5/mfpr   $18,r0\
+       mtpr    $0x15,$18/
+s/calls        r[0-9]*,_spl5/mfpr      $18,r0\
+       mtpr    $0x15,$18/
+s/calls        $0,_spl6/mfpr   $18,r0\
+       mtpr    $0x18,$18/
+s/calls        r[0-9]*,_spl6/mfpr      $18,r0\
+       mtpr    $0x18,$18/
+s/calls        $0,_spl7/mfpr   $18,r0\
+       mtpr    $0x1f,$18/
+s/calls        $1,_splx/mfpr   $18,r0\
+       mtpr    (sp)+,$18/
+s/calls        $1,_mfpr/mfpr   (sp)+,r0/
+s/calls        $2,_mtpr/mtpr   4(sp),(sp)\
+       addl2   $8,sp/
+s/calls        $0,_setsoftclock/mtpr   $0x8,$0x14/
+s/calls        $1,_resume/ashl $9,(sp)+,r0 \
+       movpsl  -(sp) \
+       jsb     _Resume/
+s/calls        $3,_bcopy/movc3 8(sp),*(sp),*4(sp)\
+       addl2   $12,sp/
+s/calls        $3,_ovbcopy/movc3       8(sp),*(sp),*4(sp)\
+       addl2   $12,sp/
+s/calls        $2,_bzero/movc5 $0,(r0),$0,4(sp),*(sp)\
+       addl2   $8,sp/
+s/calls        $3,_bcmp/popr   $0x7\
+       cmpc3   r2,(r0),(r1)/
+s/calls        $3,_strncmp/cmpc3       8(sp),*(sp),*4(sp)\
+       addl2   $12,sp/
+s/calls        $2,_blkclr/movl (sp)+,r3\
+       jbr     2f\
+1:\
+       subl2   r0,(sp)\
+       movc5   $0,(r3),$0,r0,(r3)\
+2:\
+       movzwl  $65535,r0\
+       cmpl    (sp),r0\
+       jgtr    1b\
+       movl    (sp)+,r0\
+       movc5   $0,(r3),$0,r0,(r3)/
+s/calls        $1,_strlen/movl (sp),r1\
+1:\
+       locc    $0,$65535,(r1)\
+       jeql    1b\
+       subl3   (sp)+,r1,r0/
+s/calls        $4,_scanc/popr  $0xf\
+       scanc   r0,(r1),(r2),r3/
+s/calls        $3,_copyin/jsb  _Copyin\
+       addl2   $12,sp/
+s/calls        $3,_copyout/jsb _Copyout\
+       addl2   $12,sp/
+s/calls        $1,_fubyte/movl (sp)+,r0 \
+       jsb     _Fubyte/
+s/calls        $1,_fuibyte/movl (sp)+,r0 \
+       jsb     _Fubyte/
+s/calls        $1,_fuword/movl (sp)+,r0 \
+       jsb     _Fuword/
+s/calls        $1,_fuiword/movl (sp)+,r0 \
+       jsb     _Fuword/
+s/calls        $2,_subyte/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Subyte/
+s/calls        $2,_suibyte/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Subyte/
+s/calls        $2,_suword/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Suword/
+s/calls        $2,_suiword/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Suword/
+s/calls        $1,_setrq/movl  (sp)+,r0 \
+       jsb     _Setrq/
+s/calls        $1,_remrq/movl  (sp)+,r0 \
+       jsb     _Remrq/
+s/calls        $0,_swtch/movpsl        -(sp)\
+       jsb     _Swtch/
+s/calls        $1,_setjmp/movl (sp)+,r0 \
+       jsb     _Setjmp/
+s/calls        $1,_longjmp/movl        (sp)+,r0 \
+       jsb     _Longjmp/
+s/calls        $1,_ffs/movl    (sp)+,r1\
+       ffs     $0,$32,r1,r0 \
+       bneq    1f \
+       mnegl   $1,r0 \
+1: \
+       incl    r0/
+s/calls        $1,_htons/rotl  $8,(sp),r0\
+       movb    1(sp),r0\
+       movzwl  r0,r0\
+       addl2   $4,sp/
+s/calls        $1,_ntohs/rotl  $8,(sp),r0\
+       movb    1(sp),r0\
+       movzwl  r0,r0\
+       addl2   $4,sp/
+s/calls        $1,_htonl/rotl  $-8,(sp),r0\
+       insv    r0,$16,$8,r0\
+       movb    3(sp),r0\
+       addl2   $4,sp/
+s/calls        $1,_ntohl/rotl  $-8,(sp),r0\
+       insv    r0,$16,$8,r0\
+       movb    3(sp),r0\
+       addl2   $4,sp/
+s/calls        $2,__insque/insque      *(sp)+,*(sp)+/
+s/calls        $1,__remque/remque      *(sp)+,r0/
+s/calls        $2,__queue/movl (sp)+,r0\
+       movl    (sp)+,r1\
+       insque  r1,*4(r0)/
+s/calls        $1,__dequeue/movl       (sp)+,r0\
+       remque  *(r0),r0/
diff --git a/usr/src/sys/vaxif/if_il.c b/usr/src/sys/vaxif/if_il.c
new file mode 100644 (file)
index 0000000..7e2dd92
--- /dev/null
@@ -0,0 +1,652 @@
+/*     if_il.c 6.2     83/09/24        */
+
+#include "il.h"
+
+/*
+ * Interlan Ethernet Communications Controller interface
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mbuf.h"
+#include "../h/buf.h"
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/vmmac.h"
+#include "../h/ioctl.h"
+#include "../h/errno.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netinet/if_ether.h"
+#include "../netpup/pup.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_il.h"
+#include "../vaxif/if_ilreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+int    ilprobe(), ilattach(), ilrint(), ilcint();
+struct uba_device *ilinfo[NIL];
+u_short ilstd[] = { 0 };
+struct uba_driver ildriver =
+       { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
+#define        ILUNIT(x)       minor(x)
+int    ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch();
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * is_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct il_softc {
+       struct  arpcom is_ac;           /* Ethernet common part */
+#define        is_if   is_ac.ac_if             /* network-visible interface */
+#define        is_addr is_ac.ac_enaddr         /* hardware Ethernet address */
+       struct  ifuba is_ifuba;         /* UNIBUS resources */
+       int     is_flags;
+#define        ILF_OACTIVE     0x1             /* output is active */
+#define        ILF_RCVPENDING  0x2             /* start rcv in ilcint */
+#define        ILF_STATPENDING 0x4             /* stat cmd pending */
+       short   is_lastcmd;             /* can't read csr, so must save it */
+       short   is_scaninterval;        /* interval of stat collection */
+#define        ILWATCHINTERVAL 60              /* once every 60 seconds */
+       struct  il_stats is_stats;      /* holds on-board statistics */
+       struct  il_stats is_sum;        /* summation over time */
+       int     is_ubaddr;              /* mapping registers of is_stats */
+} il_softc[NIL];
+
+ilprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* r11, r10 value-result */
+       register struct ildevice *addr = (struct ildevice *)reg;
+       register i;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       i = 0; ilrint(i); ilcint(i); ilwatch(i);
+#endif
+
+       addr->il_csr = ILC_OFFLINE|IL_CIE;
+       DELAY(100000);
+       i = addr->il_csr;               /* clear CDONE */
+       if (cvec > 0 && cvec != 0x200)
+               cvec -= 4;
+       return (1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.  A STATUS command is done to get the ethernet
+ * address and other interesting data.
+ */
+ilattach(ui)
+       struct uba_device *ui;
+{
+       register struct il_softc *is = &il_softc[ui->ui_unit];
+       register struct ifnet *ifp = &is->is_if;
+       register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
+       struct sockaddr_in *sin;
+
+       ifp->if_unit = ui->ui_unit;
+       ifp->if_name = "il";
+       ifp->if_mtu = ETHERMTU;
+
+       /*
+        * Reset the board and map the statistics
+        * buffer onto the Unibus.
+        */
+       addr->il_csr = ILC_RESET;
+       while ((addr->il_csr&IL_CDONE) == 0)
+               ;
+       if (addr->il_csr&IL_STATUS)
+               printf("il%d: reset failed, csr=%b\n", ui->ui_unit,
+                       addr->il_csr, IL_BITS);
+       
+       is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+           sizeof (struct il_stats), 0);
+       addr->il_bar = is->is_ubaddr & 0xffff;
+       addr->il_bcr = sizeof (struct il_stats);
+       addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
+       while ((addr->il_csr&IL_CDONE) == 0)
+               ;
+       if (addr->il_csr&IL_STATUS)
+               printf("il%d: status failed, csr=%b\n", ui->ui_unit,
+                       addr->il_csr, IL_BITS);
+       ubarelse(ui->ui_ubanum, &is->is_ubaddr);
+#ifdef notdef
+       printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
+               ui->ui_unit,
+               is->is_stats.ils_addr[0]&0xff, is->is_stats.ils_addr[1]&0xff,
+               is->is_stats.ils_addr[2]&0xff, is->is_stats.ils_addr[3]&0xff,
+               is->is_stats.ils_addr[4]&0xff, is->is_stats.ils_addr[5]&0xff,
+               is->is_stats.ils_module, is->is_stats.ils_firmware);
+#endif
+       bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
+           sizeof (is->is_addr));
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = arpmyaddr((struct arpcom *)0);
+       ifp->if_init = ilinit;
+       ifp->if_output = iloutput;
+       ifp->if_ioctl = ilioctl;
+       ifp->if_reset = ilreset;
+       is->is_ifuba.ifu_flags = UBA_CANTWAIT;
+#ifdef notdef
+       is->is_ifuba.ifu_flags |= UBA_NEEDBDP;
+#endif
+       if_attach(ifp);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+ilreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+
+       if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" il%d", unit);
+       ilinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+ilinit(unit)
+       int unit;
+{
+       register struct il_softc *is = &il_softc[unit];
+       register struct uba_device *ui = ilinfo[unit];
+       register struct ildevice *addr;
+       register struct ifnet *ifp = &is->is_if;
+       register struct sockaddr_in *sin;
+       int s;
+
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       if (sin->sin_addr.s_addr == 0)          /* address still unknown */
+               return;
+
+       if (ifp->if_flags & IFF_RUNNING)
+               goto justarp;
+       if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
+           sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 
+               printf("il%d: can't initialize\n", unit);
+               is->is_if.if_flags &= ~IFF_UP;
+               return;
+       }
+       is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+           sizeof (struct il_stats), 0);
+       ifp->if_watchdog = ilwatch;
+       is->is_scaninterval = ILWATCHINTERVAL;
+       ifp->if_timer = is->is_scaninterval;
+       addr = (struct ildevice *)ui->ui_addr;
+
+       /*
+        * Turn off source address insertion (it's faster this way),
+        * and set board online.  Former doesn't work if board is
+        * already online (happens on ubareset), so we put it offline
+        * first.
+        */
+       s = splimp();
+       addr->il_csr = ILC_OFFLINE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       addr->il_csr = ILC_CISA;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       /*
+        * Set board online.
+        * Hang receive buffer and start any pending
+        * writes by faking a transmit complete.
+        * Receive bcr is not a muliple of 4 so buffer
+        * chaining can't happen.
+        */
+       addr->il_csr = ILC_ONLINE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
+       addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+       addr->il_csr =
+           ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       is->is_flags = ILF_OACTIVE;
+       is->is_if.if_flags |= IFF_UP|IFF_RUNNING;
+       is->is_lastcmd = 0;
+       ilcint(unit);
+       splx(s);
+justarp:
+       if_rtinit(&is->is_if, RTF_UP);
+       arpattach(&is->is_ac);
+       arpwhohas(&is->is_ac, &sin->sin_addr);
+}
+
+/*
+ * Start output on interface.
+ * Get another datagram to send off of the interface queue,
+ * and map it to the interface before starting the output.
+ */
+ilstart(dev)
+       dev_t dev;
+{
+        int unit = ILUNIT(dev), len;
+       struct uba_device *ui = ilinfo[unit];
+       register struct il_softc *is = &il_softc[unit];
+       register struct ildevice *addr;
+       struct mbuf *m;
+       short csr;
+
+       IF_DEQUEUE(&is->is_if.if_snd, m);
+       addr = (struct ildevice *)ui->ui_addr;
+       if (m == 0) {
+               if ((is->is_flags & ILF_STATPENDING) == 0)
+                       return;
+               addr->il_bar = is->is_ubaddr & 0xffff;
+               addr->il_bcr = sizeof (struct il_stats);
+               csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE;
+               is->is_flags &= ~ILF_STATPENDING;
+               goto startcmd;
+       }
+       len = if_wubaput(&is->is_ifuba, m);
+       /*
+        * Ensure minimum packet length.
+        * This makes the safe assumtion that there are no virtual holes
+        * after the data.
+        * For security, it might be wise to zero out the added bytes,
+        * but we're mainly interested in speed at the moment.
+        */
+       if (len - sizeof(struct ether_header) < ETHERMIN)
+               len = ETHERMIN + sizeof(struct ether_header);
+       if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
+       addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
+       addr->il_bcr = len;
+       csr =
+         ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
+
+startcmd:
+       is->is_lastcmd = csr & IL_CMD;
+       addr->il_csr = csr;
+       is->is_flags |= ILF_OACTIVE;
+}
+
+/*
+ * Command done interrupt.
+ */
+ilcint(unit)
+       int unit;
+{
+       register struct il_softc *is = &il_softc[unit];
+       struct uba_device *ui = ilinfo[unit];
+       register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
+       short csr;
+
+       if ((is->is_flags & ILF_OACTIVE) == 0) {
+               printf("il%d: stray xmit interrupt, csr=%b\n", unit,
+                       addr->il_csr, IL_BITS);
+               return;
+       }
+
+       csr = addr->il_csr;
+       /*
+        * Hang receive buffer if it couldn't
+        * be done earlier (in ilrint).
+        */
+       if (is->is_flags & ILF_RCVPENDING) {
+               addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
+               addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+               addr->il_csr =
+                 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+               while ((addr->il_csr & IL_CDONE) == 0)
+                       ;
+               is->is_flags &= ~ILF_RCVPENDING;
+       }
+       is->is_flags &= ~ILF_OACTIVE;
+       csr &= IL_STATUS;
+       switch (is->is_lastcmd) {
+
+       case ILC_XMIT:
+               is->is_if.if_opackets++;
+               if (csr > ILERR_RETRIES)
+                       is->is_if.if_oerrors++;
+               break;
+
+       case ILC_STAT:
+               if (csr == ILERR_SUCCESS)
+                       iltotal(is);
+               break;
+       }
+       if (is->is_ifuba.ifu_xtofree) {
+               m_freem(is->is_ifuba.ifu_xtofree);
+               is->is_ifuba.ifu_xtofree = 0;
+       }
+       ilstart(unit);
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ * If input error just drop packet.
+ * Otherwise purge input buffered data path and examine 
+ * packet to determine type.  If can't determine length
+ * from type, then have to drop packet.  Othewise decapsulate
+ * packet based on type and pass to type specific higher-level
+ * input routine.
+ */
+ilrint(unit)
+       int unit;
+{
+       register struct il_softc *is = &il_softc[unit];
+       struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
+       register struct il_rheader *il;
+       struct mbuf *m;
+       int len, off, resid;
+       register struct ifqueue *inq;
+
+       is->is_if.if_ipackets++;
+       if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
+       il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
+       len = il->ilr_length - sizeof(struct il_rheader);
+       if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 ||
+           len > ETHERMTU) {
+               is->is_if.if_ierrors++;
+#ifdef notdef
+               if (is->is_if.if_ierrors % 100 == 0)
+                       printf("il%d: += 100 input errors\n", unit);
+#endif
+               goto setup;
+       }
+
+       /*
+        * Deal with trailer protocol: if type is PUP trailer
+        * get true type from first 16-bit word past data.
+        * Remember that type was trailer by setting off.
+        */
+       il->ilr_type = ntohs((u_short)il->ilr_type);
+#define        ildataaddr(il, off, type)       ((type)(((caddr_t)((il)+1)+(off))))
+       if (il->ilr_type >= ETHERPUP_TRAIL &&
+           il->ilr_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
+               off = (il->ilr_type - ETHERPUP_TRAIL) * 512;
+               if (off >= ETHERMTU)
+                       goto setup;             /* sanity */
+               il->ilr_type = ntohs(*ildataaddr(il, off, u_short *));
+               resid = ntohs(*(ildataaddr(il, off+2, u_short *)));
+               if (off + resid > len)
+                       goto setup;             /* sanity */
+               len = off + resid;
+       } else
+               off = 0;
+       if (len == 0)
+               goto setup;
+
+       /*
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; ilget will then force this header
+        * information to be at the front, but we still have to drop
+        * the type and length which are at the front of any trailer data.
+        */
+       m = if_rubaget(&is->is_ifuba, len, off);
+       if (m == 0)
+               goto setup;
+       if (off) {
+               m->m_off += 2 * sizeof (u_short);
+               m->m_len -= 2 * sizeof (u_short);
+       }
+       switch (il->ilr_type) {
+
+#ifdef INET
+       case ETHERPUP_IPTYPE:
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+
+       case ETHERPUP_ARPTYPE:
+               arpinput(&is->is_ac, m);
+               goto setup;
+#endif
+       default:
+               m_freem(m);
+               goto setup;
+       }
+
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+               goto setup;
+       }
+       IF_ENQUEUE(inq, m);
+
+setup:
+       /*
+        * Reset for next packet if possible.
+        * If waiting for transmit command completion, set flag
+        * and wait until command completes.
+        */
+       if (is->is_flags & ILF_OACTIVE) {
+               is->is_flags |= ILF_RCVPENDING;
+               return;
+       }
+       addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
+       addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+       addr->il_csr =
+               ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+}
+
+/*
+ * Ethernet output routine.
+ * Encapsulate a packet of type family for the local net.
+ * Use trailer local net encapsulation if enough data in first
+ * packet leaves a multiple of 512 bytes of data in remainder.
+ */
+iloutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       int type, s, error;
+       u_char edst[6];
+       struct in_addr idst;
+       register struct il_softc *is = &il_softc[ifp->if_unit];
+       register struct mbuf *m = m0;
+       register struct ether_header *il;
+       register int off;
+
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET:
+               idst = ((struct sockaddr_in *)dst)->sin_addr;
+               if (!arpresolve(&is->is_ac, m, &idst, edst))
+                       return (0);     /* if not yet resolved */
+               off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+               /* need per host negotiation */
+               if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
+               if (off > 0 && (off & 0x1ff) == 0 &&
+                   m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
+                       type = ETHERPUP_TRAIL + (off>>9);
+                       m->m_off -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
+                       *mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
+                       *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
+                       goto gottrailertype;
+               }
+               type = ETHERPUP_IPTYPE;
+               off = 0;
+               goto gottype;
+#endif
+
+       case AF_UNSPEC:
+               il = (struct ether_header *)dst->sa_data;
+               bcopy((caddr_t)il->ether_dhost, (caddr_t)edst, sizeof (edst));
+               type = il->ether_type;
+               goto gottype;
+
+       default:
+               printf("il%d: can't handle af%d\n", ifp->if_unit,
+                       dst->sa_family);
+               error = EAFNOSUPPORT;
+               goto bad;
+       }
+
+gottrailertype:
+       /*
+        * Packet to be sent as trailer: move first packet
+        * (control information) to end of chain.
+        */
+       while (m->m_next)
+               m = m->m_next;
+       m->m_next = m0;
+       m = m0->m_next;
+       m0->m_next = 0;
+       m0 = m;
+
+gottype:
+       /*
+        * Add local net header.  If no space in first mbuf,
+        * allocate another.
+        */
+       if (m->m_off > MMAXOFF ||
+           MMINOFF + sizeof (struct ether_header) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       error = ENOBUFS;
+                       goto bad;
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = sizeof (struct ether_header);
+       } else {
+               m->m_off -= sizeof (struct ether_header);
+               m->m_len += sizeof (struct ether_header);
+       }
+       il = mtod(m, struct ether_header *);
+       il->ether_type = htons((u_short)type);
+       bcopy((caddr_t)edst, (caddr_t)il->ether_dhost, sizeof (edst));
+       bcopy((caddr_t)is->is_addr, (caddr_t)il->ether_shost, 6);
+
+       /*
+        * Queue message on interface, and start output if interface
+        * not yet active.
+        */
+       s = splimp();
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               splx(s);
+               m_freem(m);
+               return (ENOBUFS);
+       }
+       IF_ENQUEUE(&ifp->if_snd, m);
+       if ((is->is_flags & ILF_OACTIVE) == 0)
+               ilstart(ifp->if_unit);
+       splx(s);
+       return (0);
+
+bad:
+       m_freem(m0);
+       return (error);
+}
+
+/*
+ * Watchdog routine, request statistics from board.
+ */
+ilwatch(unit)
+       int unit;
+{
+       register struct il_softc *is = &il_softc[unit];
+       register struct ifnet *ifp = &is->is_if;
+       int s;
+
+       if (is->is_flags & ILF_STATPENDING) {
+               ifp->if_timer = is->is_scaninterval;
+               return;
+       }
+       s = splimp();
+       is->is_flags |= ILF_STATPENDING;
+       if ((is->is_flags & ILF_OACTIVE) == 0)
+               ilstart(ifp->if_unit);
+       splx(s);
+       ifp->if_timer = is->is_scaninterval;
+}
+
+/*
+ * Total up the on-board statistics.
+ */
+iltotal(is)
+       register struct il_softc *is;
+{
+       register u_short *interval, *sum, *end;
+
+       interval = &is->is_stats.ils_frames;
+       sum = &is->is_sum.ils_frames;
+       end = is->is_sum.ils_fill2;
+       while (sum < end)
+               *sum++ += *interval++;
+       is->is_if.if_collisions = is->is_sum.ils_collis;
+}
+
+/*
+ * Process an ioctl request.
+ */
+ilioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       register struct ifreq *ifr = (struct ifreq *)data;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               ilsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+               ilinit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+ilsetaddr(ifp, sin)
+       register struct ifnet *ifp;
+       register struct sockaddr_in *sin;
+{
+
+       ifp->if_addr = *(struct sockaddr *)sin;
+       ifp->if_net = in_netof(sin->sin_addr);
+       ifp->if_host[0] = in_lnaof(sin->sin_addr);
+       sin = (struct sockaddr_in *)&ifp->if_broadaddr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
+       ifp->if_flags |= IFF_BROADCAST;
+}
diff --git a/usr/src/sys/vaxuba/tm.c b/usr/src/sys/vaxuba/tm.c
new file mode 100644 (file)
index 0000000..74a6349
--- /dev/null
@@ -0,0 +1,977 @@
+/*     tm.c    6.3     83/09/25        */
+
+#include "te.h"
+#include "ts.h"
+#if NTE > 0
+/*
+ * TM11/TE10 tape driver
+ *
+ * TODO:
+ *     test driver with more than one slave
+ *     test driver with more than one controller
+ *     test reset code
+ *     what happens if you offline tape during rewind?
+ *     test using file system on tape
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/dir.h"
+#include "../h/conf.h"
+#include "../h/user.h"
+#include "../h/file.h"
+#include "../h/map.h"
+#include "../h/vm.h"
+#include "../h/ioctl.h"
+#include "../h/mtio.h"
+#include "../h/cmap.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vax/cpu.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/tmreg.h"
+
+/*
+ * There is a ctmbuf per tape controller.
+ * It is used as the token to pass to the internal routines
+ * to execute tape ioctls, and also acts as a lock on the slaves
+ * on the controller, since there is only one per controller.
+ * In particular, when the tape is rewinding on close we release
+ * the user process but any further attempts to use the tape drive
+ * before the rewind completes will hang waiting for ctmbuf.
+ */
+struct buf     ctmbuf[NTM];
+
+/*
+ * Raw tape operations use rtmbuf.  The driver
+ * notices when rtmbuf is being used and allows the user
+ * program to continue after errors and read records
+ * not of the standard length (BSIZE).
+ */
+struct buf     rtmbuf[NTM];
+
+/*
+ * Driver unibus interface routines and variables.
+ */
+int    tmprobe(), tmslave(), tmattach(), tmdgo(), tmintr();
+struct uba_ctlr *tmminfo[NTM];
+struct uba_device *tedinfo[NTE];
+struct buf teutab[NTE];
+short  tetotm[NTE];
+u_short        tmstd[] = { 0772520, 0 };
+struct uba_driver tmdriver =
+ { tmprobe, tmslave, tmattach, tmdgo, tmstd, "te", tedinfo, "tm", tmminfo, 0 };
+
+/* bits in minor device */
+#define        TEUNIT(dev)     (minor(dev)&03)
+#define        TMUNIT(dev)     (tetotm[TEUNIT(dev)])
+#define        T_NOREWIND      04
+#define        T_1600BPI       08
+
+#define        INF     (daddr_t)1000000L
+
+/*
+ * Software state per tape transport.
+ *
+ * 1. A tape drive is a unique-open device; we refuse opens when it is already.
+ * 2. We keep track of the current position on a block tape and seek
+ *    before operations by forward/back spacing if necessary.
+ * 3. We remember if the last operation was a write on a tape, so if a tape
+ *    is open read write and the last thing done is a write we can
+ *    write a standard end of tape mark (two eofs).
+ * 4. We remember the status registers after the last command, using
+ *    then internally and returning them to the SENSE ioctl.
+ * 5. We remember the last density the tape was used at.  If it is
+ *    not a BOT when we start using it and we are writing, we don't
+ *    let the density be changed.
+ */
+struct te_softc {
+       char    sc_openf;       /* lock against multiple opens */
+       char    sc_lastiow;     /* last op was a write */
+       daddr_t sc_blkno;       /* block number, for block device tape */
+       daddr_t sc_nxrec;       /* position of end of tape, if known */
+       u_short sc_erreg;       /* copy of last erreg */
+       u_short sc_dsreg;       /* copy of last dsreg */
+       short   sc_resid;       /* copy of last bc */
+#ifdef unneeded
+       short   sc_lastcmd;     /* last command to handle direction changes */
+#endif
+       u_short sc_dens;        /* prototype command with density info */
+       daddr_t sc_timo;        /* time until timeout expires */
+       short   sc_tact;        /* timeout is active */
+} te_softc[NTE];
+#ifdef unneeded
+int    tmgapsdcnt;             /* DEBUG */
+#endif
+
+/*
+ * States for um->um_tab.b_active, the per controller state flag.
+ * This is used to sequence control in the driver.
+ */
+#define        SSEEK   1               /* seeking */
+#define        SIO     2               /* doing seq i/o */
+#define        SCOM    3               /* sending control command */
+#define        SREW    4               /* sending a drive rewind */
+
+/*
+ * Determine if there is a controller for
+ * a tm at address reg.  Our goal is to make the
+ * device interrupt.
+ */
+tmprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* must be r11,r10; value-result */
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       tmintr(0);
+#endif
+       ((struct tmdevice *)reg)->tmcs = TM_IE;
+       /*
+        * If this is a tm11, it ought to have interrupted
+        * by now, if it isn't (ie: it is a ts04) then we just
+        * hope that it didn't interrupt, so autoconf will ignore it.
+        * Just in case, we will reference one
+        * of the more distant registers, and hope for a machine
+        * check, or similar disaster if this is a ts.
+        *
+        * Note: on an 11/780, badaddr will just generate
+        * a uba error for a ts; but our caller will notice that
+        * so we won't check for it.
+        */
+       if (badaddr((caddr_t)&((struct tmdevice *)reg)->tmrd, 2))
+               return (0);
+       return (sizeof (struct tmdevice));
+}
+
+/*
+ * Due to a design flaw, we cannot ascertain if the tape
+ * exists or not unless it is on line - ie: unless a tape is
+ * mounted. This is too servere a restriction to bear,
+ * so all units are assumed to exist.
+ */
+/*ARGSUSED*/
+tmslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+
+       return (1);
+}
+
+/*
+ * Record attachment of the unit to the controller.
+ */
+/*ARGSUSED*/
+tmattach(ui)
+       struct uba_device *ui;
+{
+       /*
+        * Tetotm is used in TMUNIT to index the ctmbuf and rtmbuf
+        * arrays given a te unit number.
+        */
+       tetotm[ui->ui_unit] = ui->ui_mi->um_ctlr;
+}
+
+int    tmtimer();
+/*
+ * Open the device.  Tapes are unique open
+ * devices, so we refuse if it is already open.
+ * We also check that a tape is available, and
+ * don't block waiting here; if you want to wait
+ * for a tape you should timeout in user code.
+ */
+tmopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register int teunit;
+       register struct uba_device *ui;
+       register struct te_softc *sc;
+       int olddens, dens;
+       int s;
+
+       teunit = TEUNIT(dev);
+       if (teunit>=NTE || (sc = &te_softc[teunit])->sc_openf ||
+           (ui = tedinfo[teunit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       olddens = sc->sc_dens;
+       dens = TM_IE | TM_GO | (ui->ui_slave << 8);
+       if ((minor(dev) & T_1600BPI) == 0)
+               dens |= TM_D800;
+       sc->sc_dens = dens;
+get:
+       tmcommand(dev, TM_SENSE, 1);
+       if (sc->sc_erreg&TMER_SDWN) {
+               sleep((caddr_t)&lbolt, PZERO+1);
+               goto get;
+       }
+       sc->sc_dens = olddens;
+       if ((sc->sc_erreg&(TMER_SELR|TMER_TUR)) != (TMER_SELR|TMER_TUR)) {
+               uprintf("te%d: not online\n", teunit);
+               return (EIO);
+       }
+       if ((flag&FWRITE) && (sc->sc_erreg&TMER_WRL)) {
+               uprintf("te%d: no write ring\n", teunit);
+               return (EIO);
+       }
+       if ((sc->sc_erreg&TMER_BOT) == 0 && (flag&FWRITE) &&
+           dens != sc->sc_dens) {
+               uprintf("te%d: can't change density in mid-tape\n", teunit);
+               return (EIO);
+       }
+       sc->sc_openf = 1;
+       sc->sc_blkno = (daddr_t)0;
+       sc->sc_nxrec = INF;
+       sc->sc_lastiow = 0;
+       sc->sc_dens = dens;
+       s = spl6();
+       if (sc->sc_tact == 0) {
+               sc->sc_timo = INF;
+               sc->sc_tact = 1;
+               timeout(tmtimer, (caddr_t)dev, 5*hz);
+       }
+       splx(s);
+       return (0);
+}
+
+/*
+ * Close tape device.
+ *
+ * If tape was open for writing or last operation was
+ * a write, then write two EOF's and backspace over the last one.
+ * Unless this is a non-rewinding special file, rewind the tape.
+ * Make the tape available to others.
+ */
+tmclose(dev, flag)
+       register dev_t dev;
+       register flag;
+{
+       register struct te_softc *sc = &te_softc[TEUNIT(dev)];
+
+       if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) {
+               tmcommand(dev, TM_WEOF, 1);
+               tmcommand(dev, TM_WEOF, 1);
+               tmcommand(dev, TM_SREV, 1);
+       }
+       if ((minor(dev)&T_NOREWIND) == 0)
+               /*
+                * 0 count means don't hang waiting for rewind complete
+                * rather ctmbuf stays busy until the operation completes
+                * preventing further opens from completing by
+                * preventing a TM_SENSE from completing.
+                */
+               tmcommand(dev, TM_REW, 0);
+       sc->sc_openf = 0;
+}
+
+/*
+ * Execute a command on the tape drive
+ * a specified number of times.
+ */
+tmcommand(dev, com, count)
+       dev_t dev;
+       int com, count;
+{
+       register struct buf *bp;
+       register int s;
+
+       bp = &ctmbuf[TMUNIT(dev)];
+       s = spl5();
+       while (bp->b_flags&B_BUSY) {
+               /*
+                * This special check is because B_BUSY never
+                * gets cleared in the non-waiting rewind case.
+                */
+               if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
+                       break;
+               bp->b_flags |= B_WANTED;
+               sleep((caddr_t)bp, PRIBIO);
+       }
+       bp->b_flags = B_BUSY|B_READ;
+       splx(s);
+       bp->b_dev = dev;
+       bp->b_repcnt = -count;
+       bp->b_command = com;
+       bp->b_blkno = 0;
+       tmstrategy(bp);
+       /*
+        * In case of rewind from close, don't wait.
+        * This is the only case where count can be 0.
+        */
+       if (count == 0)
+               return;
+       iowait(bp);
+       if (bp->b_flags&B_WANTED)
+               wakeup((caddr_t)bp);
+       bp->b_flags &= B_ERROR;
+}
+
+/*
+ * Queue a tape operation.
+ */
+tmstrategy(bp)
+       register struct buf *bp;
+{
+       int teunit = TEUNIT(bp->b_dev);
+       register struct uba_ctlr *um;
+       register struct buf *dp;
+       int s;
+
+       /*
+        * Put transfer at end of unit queue
+        */
+       dp = &teutab[teunit];
+       bp->av_forw = NULL;
+       s = spl5();
+       um = tedinfo[teunit]->ui_mi;
+       if (dp->b_actf == NULL) {
+               dp->b_actf = bp;
+               /*
+                * Transport not already active...
+                * put at end of controller queue.
+                */
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+       } else
+               dp->b_actl->av_forw = bp;
+       dp->b_actl = bp;
+       /*
+        * If the controller is not busy, get
+        * it going.
+        */
+       if (um->um_tab.b_active == 0)
+               tmstart(um);
+       splx(s);
+}
+
+/*
+ * Start activity on a tm controller.
+ */
+tmstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp, *dp;
+       register struct tmdevice *addr = (struct tmdevice *)um->um_addr;
+       register struct te_softc *sc;
+       register struct uba_device *ui;
+       int teunit, cmd;
+       daddr_t blkno;
+
+       /*
+        * Look for an idle transport on the controller.
+        */
+loop:
+       if ((dp = um->um_tab.b_actf) == NULL)
+               return;
+       if ((bp = dp->b_actf) == NULL) {
+               um->um_tab.b_actf = dp->b_forw;
+               goto loop;
+       }
+       teunit = TEUNIT(bp->b_dev);
+       ui = tedinfo[teunit];
+       /*
+        * Record pre-transfer status (e.g. for TM_SENSE)
+        */
+       sc = &te_softc[teunit];
+       addr = (struct tmdevice *)um->um_addr;
+       addr->tmcs = (ui->ui_slave << 8);
+       sc->sc_dsreg = addr->tmcs;
+       sc->sc_erreg = addr->tmer;
+       sc->sc_resid = addr->tmbc;
+       /*
+        * Default is that last command was NOT a write command;
+        * if we do a write command we will notice this in tmintr().
+        */
+       sc->sc_lastiow = 0;
+       if (sc->sc_openf < 0 || (addr->tmcs&TM_CUR) == 0) {
+               /*
+                * Have had a hard error on a non-raw tape
+                * or the tape unit is now unavailable
+                * (e.g. taken off line).
+                */
+               bp->b_flags |= B_ERROR;
+               goto next;
+       }
+       if (bp == &ctmbuf[TMUNIT(bp->b_dev)]) {
+               /*
+                * Execute control operation with the specified count.
+                */
+               if (bp->b_command == TM_SENSE)
+                       goto next;
+               /*
+                * Set next state; give 5 minutes to complete
+                * rewind, or 10 seconds per iteration (minimum 60
+                * seconds and max 5 minutes) to complete other ops.
+                */
+               if (bp->b_command == TM_REW) {
+                       um->um_tab.b_active = SREW;
+                       sc->sc_timo = 5 * 60;
+               } else {
+                       um->um_tab.b_active = SCOM;
+                       sc->sc_timo =
+                           imin(imax(10*(int)-bp->b_repcnt,60),5*60);
+               }
+               if (bp->b_command == TM_SFORW || bp->b_command == TM_SREV)
+                       addr->tmbc = bp->b_repcnt;
+               goto dobpcmd;
+       }
+       /*
+        * The following checks handle boundary cases for operation
+        * on non-raw tapes.  On raw tapes the initialization of
+        * sc->sc_nxrec by tmphys causes them to be skipped normally
+        * (except in the case of retries).
+        */
+       if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
+               /*
+                * Can't read past known end-of-file.
+                */
+               bp->b_flags |= B_ERROR;
+               bp->b_error = ENXIO;
+               goto next;
+       }
+       if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
+           bp->b_flags&B_READ) {
+               /*
+                * Reading at end of file returns 0 bytes.
+                */
+               bp->b_resid = bp->b_bcount;
+               clrbuf(bp);
+               goto next;
+       }
+       if ((bp->b_flags&B_READ) == 0)
+               /*
+                * Writing sets EOF
+                */
+               sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
+       /*
+        * If the data transfer command is in the correct place,
+        * set up all the registers except the csr, and give
+        * control over to the UNIBUS adapter routines, to
+        * wait for resources to start the i/o.
+        */
+       if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
+               addr->tmbc = -bp->b_bcount;
+               if ((bp->b_flags&B_READ) == 0) {
+                       if (um->um_tab.b_errcnt)
+                               cmd = TM_WIRG;
+                       else
+                               cmd = TM_WCOM;
+               } else
+                       cmd = TM_RCOM;
+               um->um_tab.b_active = SIO;
+               um->um_cmd = sc->sc_dens|cmd;
+#ifdef notdef
+               if (tmreverseop(sc->sc_lastcmd))
+                       while (addr->tmer & TMER_SDWN)
+                               tmgapsdcnt++;
+               sc->sc_lastcmd = TM_RCOM;               /* will serve */
+#endif
+               sc->sc_timo = 60;       /* premature, but should serve */
+               (void) ubago(ui);
+               return;
+       }
+       /*
+        * Tape positioned incorrectly;
+        * set to seek forwards or backwards to the correct spot.
+        * This happens for raw tapes only on error retries.
+        */
+       um->um_tab.b_active = SSEEK;
+       if (blkno < bdbtofsb(bp->b_blkno)) {
+               bp->b_command = TM_SFORW;
+               addr->tmbc = blkno - bdbtofsb(bp->b_blkno);
+       } else {
+               bp->b_command = TM_SREV;
+               addr->tmbc = bdbtofsb(bp->b_blkno) - blkno;
+       }
+       sc->sc_timo = imin(imax(10 * -addr->tmbc, 60), 5 * 60);
+dobpcmd:
+#ifdef notdef
+       /*
+        * It is strictly necessary to wait for the tape
+        * to stop before changing directions, but the TC11
+        * handles this for us.
+        */
+       if (tmreverseop(sc->sc_lastcmd) != tmreverseop(bp->b_command))
+               while (addr->tmer & TM_SDWN)
+                       tmgapsdcnt++;
+       sc->sc_lastcmd = bp->b_command;
+#endif
+       /*
+        * Do the command in bp.
+        */
+       addr->tmcs = (sc->sc_dens | bp->b_command);
+       return;
+
+next:
+       /*
+        * Done with this operation due to error or
+        * the fact that it doesn't do anything.
+        * Release UBA resources (if any), dequeue
+        * the transfer and continue processing this slave.
+        */
+       if (um->um_ubinfo)
+               ubadone(um);
+       um->um_tab.b_errcnt = 0;
+       dp->b_actf = bp->av_forw;
+       iodone(bp);
+       goto loop;
+}
+
+/*
+ * The UNIBUS resources we needed have been
+ * allocated to us; start the device.
+ */
+tmdgo(um)
+       register struct uba_ctlr *um;
+{
+       register struct tmdevice *addr = (struct tmdevice *)um->um_addr;
+
+       addr->tmba = um->um_ubinfo;
+       addr->tmcs = um->um_cmd | ((um->um_ubinfo >> 12) & 0x30);
+}
+
+/*
+ * Tm interrupt routine.
+ */
+/*ARGSUSED*/
+tmintr(tm11)
+       int tm11;
+{
+       struct buf *dp;
+       register struct buf *bp;
+       register struct uba_ctlr *um = tmminfo[tm11];
+       register struct tmdevice *addr;
+       register struct te_softc *sc;
+       int teunit;
+       register state;
+
+       if ((dp = um->um_tab.b_actf) == NULL)
+               return;
+       bp = dp->b_actf;
+       teunit = TEUNIT(bp->b_dev);
+       addr = (struct tmdevice *)tedinfo[teunit]->ui_addr;
+       sc = &te_softc[teunit];
+       /*
+        * If last command was a rewind, and tape is still
+        * rewinding, wait for the rewind complete interrupt.
+        */
+       if (um->um_tab.b_active == SREW) {
+               um->um_tab.b_active = SCOM;
+               if (addr->tmer&TMER_RWS) {
+                       sc->sc_timo = 5*60;             /* 5 minutes */
+                       return;
+               }
+       }
+       /*
+        * An operation completed... record status
+        */
+       sc->sc_timo = INF;
+       sc->sc_dsreg = addr->tmcs;
+       sc->sc_erreg = addr->tmer;
+       sc->sc_resid = addr->tmbc;
+       if ((bp->b_flags & B_READ) == 0)
+               sc->sc_lastiow = 1;
+       state = um->um_tab.b_active;
+       um->um_tab.b_active = 0;
+       /*
+        * Check for errors.
+        */
+       if (addr->tmcs&TM_ERR) {
+               while (addr->tmer & TMER_SDWN)
+                       ;                       /* await settle down */
+               /*
+                * If we hit the end of the tape file, update our position.
+                */
+               if (addr->tmer&TMER_EOF) {
+                       tmseteof(bp);           /* set blkno and nxrec */
+                       state = SCOM;           /* force completion */
+                       /*
+                        * Stuff bc so it will be unstuffed correctly
+                        * later to get resid.
+                        */
+                       addr->tmbc = -bp->b_bcount;
+                       goto opdone;
+               }
+               /*
+                * If we were reading raw tape and the only error was that the
+                * record was too long, then we don't consider this an error.
+                */
+               if (bp == &rtmbuf[TMUNIT(bp->b_dev)] && (bp->b_flags&B_READ) &&
+                   (addr->tmer&(TMER_HARD|TMER_SOFT)) == TMER_RLE)
+                       goto ignoreerr;
+               /*
+                * If error is not hard, and this was an i/o operation
+                * retry up to 8 times.
+                */
+               if ((addr->tmer&TMER_HARD)==0 && state==SIO) {
+                       if (++um->um_tab.b_errcnt < 7) {
+                               sc->sc_blkno++;
+                               ubadone(um);
+                               goto opcont;
+                       }
+               } else
+                       /*
+                        * Hard or non-i/o errors on non-raw tape
+                        * cause it to close.
+                        */
+                       if (sc->sc_openf>0 && bp != &rtmbuf[TMUNIT(bp->b_dev)])
+                               sc->sc_openf = -1;
+               /*
+                * Couldn't recover error
+                */
+               printf("te%d: hard error bn%d er=%b\n", minor(bp->b_dev)&03,
+                   bp->b_blkno, sc->sc_erreg, TMER_BITS);
+               bp->b_flags |= B_ERROR;
+               goto opdone;
+       }
+       /*
+        * Advance tape control FSM.
+        */
+ignoreerr:
+       switch (state) {
+
+       case SIO:
+               /*
+                * Read/write increments tape block number
+                */
+               sc->sc_blkno++;
+               goto opdone;
+
+       case SCOM:
+               /*
+                * For forward/backward space record update current position.
+                */
+               if (bp == &ctmbuf[TMUNIT(bp->b_dev)])
+               switch (bp->b_command) {
+
+               case TM_SFORW:
+                       sc->sc_blkno -= bp->b_repcnt;
+                       break;
+
+               case TM_SREV:
+                       sc->sc_blkno += bp->b_repcnt;
+                       break;
+               }
+               goto opdone;
+
+       case SSEEK:
+               sc->sc_blkno = bdbtofsb(bp->b_blkno);
+               goto opcont;
+
+       default:
+               panic("tmintr");
+       }
+opdone:
+       /*
+        * Reset error count and remove
+        * from device queue.
+        */
+       um->um_tab.b_errcnt = 0;
+       dp->b_actf = bp->av_forw;
+       /*
+        * Check resid; watch out for resid >32767 (tmbc not negative).
+        */
+       bp->b_resid = ((int) -addr->tmbc) & 0xffff;
+       ubadone(um);
+       iodone(bp);
+       /*
+        * Circulate slave to end of controller
+        * queue to give other slaves a chance.
+        */
+       um->um_tab.b_actf = dp->b_forw;
+       if (dp->b_actf) {
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+       }
+       if (um->um_tab.b_actf == 0)
+               return;
+opcont:
+       tmstart(um);
+}
+
+tmtimer(dev)
+       int dev;
+{
+       register struct te_softc *sc = &te_softc[TEUNIT(dev)];
+       register short x;
+
+       if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) {
+               printf("te%d: lost interrupt\n", TEUNIT(dev));
+               sc->sc_timo = INF;
+               x = spl5();
+               tmintr(TMUNIT(dev));
+               (void) splx(x);
+       }
+       timeout(tmtimer, (caddr_t)dev, 5*hz);
+}
+
+tmseteof(bp)
+       register struct buf *bp;
+{
+       register int teunit = TEUNIT(bp->b_dev);
+       register struct tmdevice *addr = 
+           (struct tmdevice *)tedinfo[teunit]->ui_addr;
+       register struct te_softc *sc = &te_softc[teunit];
+
+       if (bp == &ctmbuf[TMUNIT(bp->b_dev)]) {
+               if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
+                       /* reversing */
+                       sc->sc_nxrec = bdbtofsb(bp->b_blkno) - addr->tmbc;
+                       sc->sc_blkno = sc->sc_nxrec;
+               } else {
+                       /* spacing forward */
+                       sc->sc_blkno = bdbtofsb(bp->b_blkno) + addr->tmbc;
+                       sc->sc_nxrec = sc->sc_blkno - 1;
+               }
+               return;
+       } 
+       /* eof on read */
+       sc->sc_nxrec = bdbtofsb(bp->b_blkno);
+}
+
+tmread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int errno;
+
+       errno = tmphys(dev, uio);
+       if (errno)
+               return (errno);
+       return (physio(tmstrategy, &rtmbuf[TMUNIT(dev)], dev, B_READ, minphys, uio));
+}
+
+tmwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int errno;
+
+       errno = tmphys(dev, uio);
+       if (errno)
+               return (errno);
+       return (physio(tmstrategy, &rtmbuf[TMUNIT(dev)], dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * Check that a raw device exists.
+ * If it does, set up sc_blkno and sc_nxrec
+ * so that the tape will appear positioned correctly.
+ */
+tmphys(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int teunit = TEUNIT(dev);
+       register daddr_t a;
+       register struct te_softc *sc;
+       register struct uba_device *ui;
+
+       if (teunit >= NTE || (ui=tedinfo[teunit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       sc = &te_softc[teunit];
+       a = bdbtofsb(uio->uio_offset >> 9);
+       sc->sc_blkno = a;
+       sc->sc_nxrec = a + 1;
+       return (0);
+}
+
+tmreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register tm11, teunit;
+       register struct uba_device *ui;
+       register struct buf *dp;
+
+       for (tm11 = 0; tm11 < NTM; tm11++) {
+               if ((um = tmminfo[tm11]) == 0 || um->um_alive == 0 ||
+                  um->um_ubanum != uban)
+                       continue;
+               printf(" tm%d", tm11);
+               um->um_tab.b_active = 0;
+               um->um_tab.b_actf = um->um_tab.b_actl = 0;
+               if (um->um_ubinfo) {
+                       printf("<%d>", (um->um_ubinfo>>28)&0xf);
+                       um->um_ubinfo = 0;
+               }
+               ((struct tmdevice *)(um->um_addr))->tmcs = TM_DCLR;
+               for (teunit = 0; teunit < NTE; teunit++) {
+                       if ((ui = tedinfo[teunit]) == 0 || ui->ui_mi != um ||
+                           ui->ui_alive == 0)
+                               continue;
+                       dp = &teutab[teunit];
+                       dp->b_active = 0;
+                       dp->b_forw = 0;
+                       if (um->um_tab.b_actf == NULL)
+                               um->um_tab.b_actf = dp;
+                       else
+                               um->um_tab.b_actl->b_forw = dp;
+                       um->um_tab.b_actl = dp;
+                       if (te_softc[teunit].sc_openf > 0)
+                               te_softc[teunit].sc_openf = -1;
+               }
+               tmstart(um);
+       }
+}
+
+/*ARGSUSED*/
+tmioctl(dev, cmd, data, flag)
+       caddr_t data;
+       dev_t dev;
+{
+       int teunit = TEUNIT(dev);
+       register struct te_softc *sc = &te_softc[teunit];
+       register struct buf *bp = &ctmbuf[TMUNIT(dev)];
+       register callcount;
+       int fcount;
+       struct mtop *mtop;
+       struct mtget *mtget;
+       /* we depend of the values and order of the MT codes here */
+       static tmops[] =
+          {TM_WEOF,TM_SFORW,TM_SREV,TM_SFORW,TM_SREV,TM_REW,TM_OFFL,TM_SENSE};
+
+       switch (cmd) {
+
+       case MTIOCTOP:  /* tape operation */
+               mtop = (struct mtop *)data;
+               switch (mtop->mt_op) {
+
+               case MTWEOF:
+                       callcount = mtop->mt_count;
+                       fcount = 1;
+                       break;
+
+               case MTFSF: case MTBSF:
+                       callcount = mtop->mt_count;
+                       fcount = INF;
+                       break;
+
+               case MTFSR: case MTBSR:
+                       callcount = 1;
+                       fcount = mtop->mt_count;
+                       break;
+
+               case MTREW: case MTOFFL: case MTNOP:
+                       callcount = 1;
+                       fcount = 1;
+                       break;
+
+               default:
+                       return (ENXIO);
+               }
+               if (callcount <= 0 || fcount <= 0)
+                       return (EINVAL);
+               while (--callcount >= 0) {
+                       tmcommand(dev, tmops[mtop->mt_op], fcount);
+                       if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
+                           bp->b_resid)
+                               return (EIO);
+                       if ((bp->b_flags&B_ERROR) || sc->sc_erreg&TMER_BOT)
+                               break;
+               }
+               return (geterror(bp));
+
+       case MTIOCGET:
+               mtget = (struct mtget *)data;
+               mtget->mt_dsreg = sc->sc_dsreg;
+               mtget->mt_erreg = sc->sc_erreg;
+               mtget->mt_resid = sc->sc_resid;
+               mtget->mt_type = MT_ISTM;
+               break;
+
+       default:
+               return (ENXIO);
+       }
+       return (0);
+}
+
+#define        DBSIZE  20
+
+tmdump()
+{
+       register struct uba_device *ui;
+       register struct uba_regs *up;
+       register struct tmdevice *addr;
+       int blk, num;
+       int start;
+
+       start = 0;
+       num = maxfree;
+#define        phys(a,b)       ((b)((int)(a)&0x7fffffff))
+       if (tedinfo[0] == 0)
+               return (ENXIO);
+       ui = phys(tedinfo[0], struct uba_device *);
+       up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
+       ubainit(up);
+       DELAY(1000000);
+       addr = (struct tmdevice *)ui->ui_physaddr;
+       tmwait(addr);
+       addr->tmcs = TM_DCLR | TM_GO;
+       while (num > 0) {
+               blk = num > DBSIZE ? DBSIZE : num;
+               tmdwrite(start, blk, addr, up);
+               start += blk;
+               num -= blk;
+       }
+       tmeof(addr);
+       tmeof(addr);
+       tmwait(addr);
+       if (addr->tmcs&TM_ERR)
+               return (EIO);
+       addr->tmcs = TM_REW | TM_GO;
+       tmwait(addr);
+       return (0);
+}
+
+tmdwrite(dbuf, num, addr, up)
+       register dbuf, num;
+       register struct tmdevice *addr;
+       struct uba_regs *up;
+{
+       register struct pte *io;
+       register int npf;
+
+       tmwait(addr);
+       io = up->uba_map;
+       npf = num+1;
+       while (--npf != 0)
+                *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
+       *(int *)io = 0;
+       addr->tmbc = -(num*NBPG);
+       addr->tmba = 0;
+       addr->tmcs = TM_WCOM | TM_GO;
+}
+
+tmwait(addr)
+       register struct tmdevice *addr;
+{
+       register s;
+
+       do
+               s = addr->tmcs;
+       while ((s & TM_CUR) == 0);
+}
+
+tmeof(addr)
+       struct tmdevice *addr;
+{
+
+       tmwait(addr);
+       addr->tmcs = TM_WEOF | TM_GO;
+}
+#endif
diff --git a/usr/src/sys/vaxuba/vp.c b/usr/src/sys/vaxuba/vp.c
new file mode 100644 (file)
index 0000000..eb0e4bb
--- /dev/null
@@ -0,0 +1,348 @@
+/*     vp.c    6.3     83/09/25        */
+
+#include "vp.h"
+#if NVP > 0
+/*
+ * Versatec matrix printer/plotter
+ * dma interface driver
+ *
+ * SETUP NOTES:
+ *     Set up both print and plot interrupts to go through the same vector
+ *     (or kludge probe to reset second vector to first;
+ *     default 174/200 is already handled).
+ *     Give the address of the plcsr register in the config specification
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+#include "../h/ioctl.h"
+#include "../h/vcmd.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/ubareg.h"
+
+unsigned minvpph();
+
+#define        VPPRI   (PZERO-1)
+
+struct vpdevice {
+       short   plbcr;
+       short   pbxaddr;
+       short   prbcr;
+       u_short pbaddr;
+       short   plcsr;
+       short   plbuf;
+       short   prcsr;
+       u_short prbuf;
+};
+
+#define        VP_ERROR        0100000
+#define        VP_DTCINTR      0040000
+#define        VP_DMAACT       0020000
+#define        VP_READY        0000200
+#define        VP_IENABLE      0000100
+#define        VP_TERMCOM      0000040
+#define        VP_FFCOM        0000020
+#define        VP_EOTCOM       0000010
+#define        VP_CLRCOM       0000004
+#define        VP_RESET        0000002
+#define        VP_SPP          0000001
+
+struct vp_softc {
+       int     sc_state;
+       int     sc_count;
+       int     sc_bufp;
+       struct  buf *sc_bp;
+       int     sc_ubinfo;
+} vp_softc[NVP];
+
+/* sc_state bits */
+#define        VPSC_BUSY       0001000
+#define        VPSC_MODE       0000700
+#define        VPSC_SPP        0000400
+#define        VPSC_PLOT       0000200
+#define        VPSC_PRINT      0000100
+#define        VPSC_CMNDS      0000076
+#define        VPSC_OPEN       0000001
+
+struct uba_device *vpdinfo[NVP];
+
+#define        VPUNIT(dev)     (minor(dev))
+
+struct buf rvpbuf[NVP];
+
+int    vpprobe(), vpattach();
+struct uba_device *vpdinfo[NVP];
+u_short        vpstd[] = { 0777500, 0 };
+struct uba_driver vpdriver =
+    { vpprobe, 0, vpattach, 0, vpstd, "vp", vpdinfo };
+
+vpprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* value-result */
+       register struct vpdevice *vpaddr = (struct vpdevice *)(reg-010);
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       vpintr(0);
+#endif
+       vpaddr->prcsr = VP_IENABLE|VP_DTCINTR;
+       vpaddr->pbaddr = 0;
+       vpaddr->pbxaddr = 0;
+       vpaddr->prbcr = 1;
+       DELAY(10000);
+       vpaddr->prcsr = 0;
+       /* GET INTERRUPT AT SECOND VECTOR BUT WANT FIRST */
+       if (cvec == 0200) {
+               printf("vp reset vec from 200 to 174\n");
+               cvec = 0174;
+       }
+       return (sizeof (struct vpdevice));
+}
+
+/*ARGSUSED*/
+vpattach(ui)
+       struct uba_device *ui;
+{
+
+       ui->ui_addr -= 010;
+       ui->ui_physaddr -= 010;
+}
+
+vpopen(dev)
+       dev_t dev;
+{
+       register struct vp_softc *sc;
+       register struct vpdevice *vpaddr;
+       register struct uba_device *ui;
+
+       if (VPUNIT(dev) >= NVP ||
+           ((sc = &vp_softc[minor(dev)])->sc_state&VPSC_OPEN) ||
+           (ui = vpdinfo[VPUNIT(dev)]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       vpaddr = (struct vpdevice *)ui->ui_addr;
+       sc->sc_state = VPSC_OPEN|VPSC_PRINT | VP_CLRCOM|VP_RESET;
+       sc->sc_count = 0;
+       vpaddr->prcsr = VP_IENABLE|VP_DTCINTR;
+       vptimo(dev);
+       while (sc->sc_state & VPSC_CMNDS) {
+               (void) spl4();
+               if (vpwait(dev)) {
+                       vpclose(dev);
+                       return (EIO);
+               }
+               vpstart(dev);
+               (void) spl0();
+       }
+       return (0);
+}
+
+vpstrategy(bp)
+       register struct buf *bp;
+{
+       register int e;
+       register struct vp_softc *sc = &vp_softc[VPUNIT(bp->b_dev)];
+       register struct uba_device *ui = vpdinfo[VPUNIT(bp->b_dev)];
+       register struct vpdevice *vpaddr = (struct vpdevice *)ui->ui_addr;
+
+       (void) spl4();
+       while (sc->sc_state & VPSC_BUSY)
+               sleep((caddr_t)sc, VPPRI);
+       sc->sc_state |= VPSC_BUSY;
+       sc->sc_bp = bp;
+       sc->sc_ubinfo = ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP);
+       if (e = vpwait(bp->b_dev))
+               goto brkout;
+       sc->sc_count = bp->b_bcount;
+       vpstart(bp->b_dev);
+       while (((sc->sc_state&VPSC_PLOT) ? vpaddr->plcsr : vpaddr->prcsr) & VP_DMAACT)
+               sleep((caddr_t)sc, VPPRI);
+       sc->sc_count = 0;
+       if ((sc->sc_state&VPSC_MODE) == VPSC_SPP)
+               sc->sc_state = (sc->sc_state &~ VPSC_MODE) | VPSC_PLOT;
+       (void) spl0();
+brkout:
+       ubarelse(ui->ui_ubanum, &sc->sc_ubinfo);
+       sc->sc_state &= ~VPSC_BUSY;
+       sc->sc_bp = 0;
+       if (e)
+               bp->b_flags |= B_ERROR;
+       iodone(bp);
+       wakeup((caddr_t)sc);
+}
+
+int    vpblock = 16384;
+
+unsigned
+minvpph(bp)
+       struct buf *bp;
+{
+
+       if (bp->b_bcount > vpblock)
+               bp->b_bcount = vpblock;
+}
+
+/*ARGSUSED*/
+vpwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+
+       if (VPUNIT(dev) >= NVP)
+               return (ENXIO);
+       return (physio(vpstrategy, &rvpbuf[VPUNIT(dev)], dev, B_WRITE,
+                   minvpph, uio));
+}
+
+vpwait(dev)
+       dev_t dev;
+{
+       register struct vpdevice *vpaddr =
+           (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
+       register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
+       register int e;
+
+       for (;;) {
+               e = (sc->sc_state & VPSC_PLOT) ? vpaddr->plcsr : vpaddr->prcsr;
+               if (e & (VP_READY|VP_ERROR))
+                       break;
+               sleep((caddr_t)sc, VPPRI);
+       }
+       /* I WISH I COULD TELL WHETHER AN ERROR INDICATED AN NPR TIMEOUT */
+       return (e & VP_ERROR);
+}
+
+vpstart(dev)
+       dev_t;
+{
+       register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
+       register struct vpdevice *vpaddr =
+           (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
+       short bit;
+
+       if (sc->sc_count) {
+               vpaddr->pbaddr = sc->sc_ubinfo;
+               vpaddr->pbxaddr = (sc->sc_ubinfo>>12)&0x30;
+               if (sc->sc_state & (VPSC_PRINT|VPSC_SPP))
+                       vpaddr->prbcr = sc->sc_count;
+               else
+                       vpaddr->plbcr = sc->sc_count;
+               return;
+       }
+       for (bit = 1; bit != 0; bit <<= 1)
+               if (sc->sc_state&bit&VPSC_CMNDS) {
+                       vpaddr->plcsr |= bit;
+                       sc->sc_state &= ~bit;
+                       return;
+               }
+}
+
+/*ARGSUSED*/
+vpioctl(dev, cmd, data, flag)
+       dev_t dev;
+       int cmd;
+       register caddr_t data;
+       int flag;
+{
+       register int m;
+       register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
+       register struct vpdevice *vpaddr =
+           (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
+
+       switch (cmd) {
+
+       case VGETSTATE:
+               *(int *)data = sc->sc_state;
+               break;
+
+       case VSETSTATE:
+               sc->sc_state =
+                   (sc->sc_state & ~VPSC_MODE) |
+                   ((*(int *)data) & (VPSC_MODE|VPSC_CMNDS));
+               break;
+
+       default:
+               return (ENOTTY);
+       }
+       (void) spl4();
+       (void) vpwait(dev);
+       if (sc->sc_state&VPSC_SPP)
+               vpaddr->plcsr |= VP_SPP;
+       else
+               vpaddr->plcsr &= ~VP_SPP;
+       sc->sc_count = 0;
+       while (sc->sc_state & VPSC_CMNDS) {
+               (void) vpwait(dev);
+               vpstart(dev);
+       }
+       (void) spl0();
+       return (0);
+}
+
+vptimo(dev)
+       dev_t dev;
+{
+       register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
+
+       if (sc->sc_state&VPSC_OPEN)
+               timeout(vptimo, (caddr_t)dev, hz/10);
+       vpintr(dev);
+}
+
+/*ARGSUSED*/
+vpintr(dev)
+       dev_t dev;
+{
+       register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
+
+       wakeup((caddr_t)sc);
+}
+
+vpclose(dev)
+       dev_t dev;
+{
+       register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
+       register struct vpdevice *vpaddr =
+           (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
+
+       sc->sc_state = 0;
+       sc->sc_count = 0;
+       vpaddr->plcsr = 0;
+}
+
+vpreset(uban)
+       int uban;
+{
+       register int vp11;
+       register struct uba_device *ui;
+       register struct vp_softc *sc = vp_softc;
+       register struct vpdevice *vpaddr;
+
+       for (vp11 = 0; vp11 < NVP; vp11++, sc++) {
+               if ((ui = vpdinfo[vp11]) == 0 || ui->ui_alive == 0 ||
+                   ui->ui_ubanum != uban || (sc->sc_state&VPSC_OPEN) == 0)
+                       continue;
+               printf(" vp%d", vp11);
+               vpaddr = (struct vpdevice *)ui->ui_addr;
+               vpaddr->prcsr = VP_IENABLE|VP_DTCINTR;
+               if ((sc->sc_state & VPSC_BUSY) == 0)
+                       continue;
+               sc->sc_ubinfo = 0;
+               sc->sc_count = sc->sc_bp->b_bcount;
+               vpstart(sc->sc_bp->b_dev);
+       }
+}
+
+vpselect()
+{
+       return (1);
+}
+#endif