Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99q-bb - tapuuo.x23
There is 1 other file named tapuuo.x23 in the archive. Click here to see a list.
TITLE	TAPUUO - MAGTAPE USER INTERFACE FOR TOPS10- V441
SUBTTL	T.HESS/TAH/TW/GMU/DPM	28-FEB-89

	SEARCH	F,S,DEVPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1974,1988>


XP VTPUUO,441		;DEFINE VERSION NUMBER FOR STORAGE MAP
	SALL

TAPUUO::ENTRY	TAPUUO

;DISPATCH TABLE

	POPJ	P,		;(-5) OFFLINE
	JRST	ECOD2##		;(-4) SPECIAL ERROR STATUS
	JRST	REGSIZ##	;(-3) USE DEFAULT
	JRST	TPMINI		;(-2) INITIATION
	JRST	TPMHNG		;(-1) HUNG DEVICE
TPMDSP::JRST	TPMREL		;(0) RELEASE
	JRST	TPMCLS		;(1) CLOSE OUTPUT
	JRST	TPMOUT		;(2) OUTPUT
	JRST	TPMIN		;(3) INPUT
	JRST	TPMENT		;(4) ENTER
	JRST	TPMLKP		;(5) LOOKUP
	JRST	TPMDOU		;(6) DUMP OUTPUT
	JRST	TPMDIN		;(7) DUMP INPUT
	POPJ	P,		;(10) USETO
	POPJ	P,		;(11) USETI
	POPJ	P,		;(12) UGETF
	JRST	CPOPJ1##	;(13) RENAME
	JRST	TPCLSI		;(14) CLOSE INPUT
	POPJ	P,		;(15) UTPCLR
	JRST	MTAPE0		;(16) MTAPE UUO

IFE FTTLAB,<
TPMENT==CPOPJ1##		;DUMMY ENTRIES
TPMLKP==CPOPJ1##
TPCLSI==CPOPJ##
> ;END IFE FTTLAB
;RANDOM DDB BYTE POINTERS

TDYMOD:	POINT 3,TDVSTS(F),10
TDYMD1:	POINT 3,TDVSTS(F),31		;FOR SET FORMAT
TDYDEN:	POINT 4,TDVSTS(F),7
TDYDN1:	POINT 4,TDVSTS(F),35		;FOR SET DENSITY
TDYBYT:	POINT 8,TDVSTS(F),10		;PARITY/DENSITY/MODE
	TDMDBY==170			;MASK OF DENSITY IN PAR/DEN/MODE
PDENS:	POINT 2,DEVIOS(F),28		;DENSITY (SETSTS)
PBUFRM:	POINT 14,DEVOAD(F),13		;MAXIMUM FRAME COUNT

;RANDOM DDB STATUS

D.RDBK==(1B0)		;READ BACKWARDS
D.NRLT==(1B1)		;NEXT RECORD AT LOW THRESHOLD
			;(1B2) UNUSED
D.EPAR==(1B3)		;USE EVEN PARITY (7TK ONLY)

;BITS IN S (DEVIOS)

IOERRS==IODERR!IODTER!IOBKTL!IOIMPM ;ALL I/O ERRORS
OFFLIN==(1B1)		;UNIT IS OFF LINE
OFLUNH==(1B2)		;OFF-LINE UNIT NOT READY
IFN FTTLAB,<
FINP==(1B3)		;FIRST INPUT OPERATION
LBLNED==(1B4)		;LABELING ACTION NEEDED
LBLWAT==(1B5)		;WAITING FOR LABEL PROCESS
LBLSTP==(1B6)		;STOP I/O BECAUSE OF ERROR
FOUT==(1B7)		;FIRST OUTPUT OPERATION
FSTOP==FINP!FOUT	;FIRST I/O OPERATION
LBLEOF==(1B8)		;EOF SEEN
> ;END IFN FTTLAB
;BITS IN DEVIAD
OFLHNG==(1B0)		;HUNG DEVICE (MUST BE SIGN BIT)
MTSNAR==:(1B9)		;SET-RETRY BIT (UUOCON,COMCON USE)
IOSRTY==:(1B10)		;IF ON, NO ERROR RETRY (TXIKON)
IOSCP2==:(1B11)		;STARTING IO FROM 2ND CPU

;MISCELLANEOUS STUFF
ST.FAC==1B0		;UPADTE DENSITY IN OTHER DDB
	 .ORG	DEVLEN
TDVUDB::!BLOCK	1		;LH = UDB PNTR
TDVSTS:!BLOCK	1		;UNIT STATUS INFO
TDVIOR::!BLOCK	1		;IORB TO WAIT FOR
TDVSUL:!BLOCK	1		;SAVED USER UPPER LIMIT
TDVSLL:!BLOCK	1		;SAVED USER LOWER LIMIT
TDVSVM:!BLOCK	1		;SAVED M FOR DUMP MODE
TDVREM:!BLOCK	1		;REMAINDER FOR MODE 16
TDVLEN::!			;LENGTH OF TAPE DDB

	 .ORG

	$LOW

TDVDDB::DDBBEG	(TDV,TDVLEN)
	SETWRD	(DEVCHR,<MTSIZ##+1>)		;DEVCHR
	SETWRD	(DEVSER,<MCSEC0+TPMDSP>)	;DEVSER
	SETWRD	(DEVMOD,<DVLNG!1023,,154403+<1_BYTMOD>>) ;DEVMOD
	SETWRD	(DEVTYP,<<.TYMTA*.TYEST>!DEPLEN,,DEPEVM>);DEVTYP
	SETWRD	(DEVCPU,<600000,,TAPCHN##>)	;DEVCPU
	DDBEND
	$HIGH
;POINTERS TO LABEL STATUS WORD IN UDB

IFN FTTLAB,<
TUYLTP::POINT	4,TUBLBL(U),35	;LABEL TYPE
TUYRQT:	POINT	4,TUBLBL(U),27	;REQUEST TYPE CODE
TUYINF:	POINT	6,TUBLBL(U),23	;ADDITIONAL INFO
TUYJBN:	POINT	9,TUBLBL(U),17	;JOB NUMBER

; BITS AND PIECES IN THE TAPE LABEL INFORMATION BLOCK

TUYFCT:	POINT	18,TUBRFM(U),17	;FORMS CONTROL BYTE
   .TFCNO==1			   ;NO FORMS CONTROL
   .TFCAS==2			   ;1ST CHAR IS FORMS CONTROL
   .TFCAM==3			   ;RECORD CONTAINS ALL FORMS CONTROL
TUYRFM:	POINT	18,TUBRFM(U),35	;RECORD FORMAT BYTE
   .TRFDF==0			   ;DEFAULT
   .TRFFX==1			   ;FIXED
   .TRFVR==2			   ;VARIABLE
   .TRFSP==3			   ;SPANNED
   .TRFUN==4			   ;UNDEFINED
TUYRSZ:	POINT	36,TUBRCC(U),35	;RECORD SIZE
TUYBSZ:	POINT	36,TUBBKL(U),35	;BLOCK SIZE
TUYECR:	POINT	18,TUBEXP(U),17	;CREATION DATE (15-BIT FORMAT)
TUYEEX:	POINT	18,TUBEXP(U),35	;EXPIRATION DATE (15-BIT FORMAT)
TUYPRT:	POINT	36,TUBPRT(U),35	;PROTECTION CODE
TUYPSN:	POINT	36,TUBPSN(U),35	;FILE SEQUENCE NUMBER
TUYFNM:	POINT	 7,TUBFNM(U)	;START OF 17 CHARACTER FILE.EXT
TUYGEN:	POINT	18,TUBGVR(U),17	;GENERATION NUMBER
TUYVER:	POINT	18,TUBGVR(U),35	;VERSION NUMBER

; TABLE OF CHARACTERS PER WORD INDEXED BY TAPE MODE
CPWTBL:	EXP	5		;EITHER EQUIV TO 1 OR ILLEGAL
	EXP	5		;DEC CORE DUMP
	EXP	4		;INDUSTRY COMPATIBLE
	EXP	6		;TU70 SIXBIT
	EXP	5		;ANSI ASCII
	EXP	6		;7-TRK CORE DUMP

> ;END IFN FTTLAB

PMTCRC::POINT	9,TUBCHR(U),26	;LAST 9TK CRC (NRZI)
PMTNCR::POINT	3,TUBCHR(U),29	;BYTE RESIDUE OF LAST WORD
PMTRTY:	POINT	1,DEVIOS(F),9	;RETRY BIT

SUBTTL INPUT UUO
TPMIN::	PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSHJ	P,INSET		;SET UP ACS ETC.
IFN FTTLAB,<
	TLZN	S,LBLSTP	;LBL PCS WANT US TO STOP?
	JRST	TPMINA		;NO - PROCEED
	TRNN	S,IODEND	;EOF ONLY?
	PJRST	TPSTP0		;NO - RETURN
	MOVEI	P1,0		;YES - FIX THINGS FOR UUOCON
	PJRST	RDEOF		;...
> ;END IFN FTTLAB
TPMINA:	PUSHJ	P,SETRED	;SET READ OP
	PUSHJ	P,GENIOR	;GENERATE IORB
	  JRST	TPMINF		;WHOOPS (UNABLE TO GET STORAGE)
IFN FTMP,<
	PUSHJ	P,TPMACC	;IF CONT ON OTHER CPU
	  PJRST	PCLINP		; DO IT DIFFERENTLY
> ;END IFN FTMP
	MOVEI	T2,DEPAIO	;ASYNC I/O?
	TDNE	T2,DEVAIO(F)
	JRST	QUEINP		;YES - GO QUEUE INPUT REQUEST
	MOVEM	T1,TDVIOR(F)	;NO - REMEMBER THIS IORB
	XMOVEI	T2,TPMIN1	;HACK LOCATION
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWAT
	PUSHJ	P,TAPRQT##	;PLACE AT END OF QUEUE
	PUSHJ	P,KONWAT	;WAIT FOR KONTROLLER
				;RETURN HERE P1 := IORB
	SKIPGE	TRBFNC(P1)	;AOK??
	JRST	TPMFLS		;FLUSH REQUEST ARE RETURN TO USER
	SKIPN	DEVEVM(F)	;HAVE EVM?
	PUSHJ	P,RSTEVM##	;NO - GET IT IF NECESSARY
TPMIN1:	PUSHJ	P,TPMXCI	;RELOCATE DEVIAD & XCT .+1
	  EXCTUX <LDB T2,[POINT 17,0(T1),17]> ;SIZE OF BUFFER
IFN FTKS10,<
	CAILE	T2,^D7682	;MAX # WORDS GUARANTEED NOT TO RUN OUT
	JRST	TPMFLS		;OF MAPPING REGS (1 WORD ON LAST WORD OF PAGE
				; + 15 FULL PAGES) +1 (T2:=BUFFER SIZE +1)
> ;END IFN FTKS10
	SOJLE	T2,TPMFLS	;LOSE IF TOO SMALL (0 OR 1)
	MOVNS	T2		;NEGATE SIZE
	HRLZS	T2		;TO LH
	HRRI	T2,1(T1)	;MAKE GENUINE IOWD
	MOVE	T1,P1		;IORB PNTR IN T1
	SETZ	T4,		;DO WHOLE BUFFER
	PUSHJ	P,MAKLST	;GET IOWD LIST
	  JRST	TPMFLS		;FLUSH IF NO SPACE
	TRO	S,IOACT		;SET I/O ACTIVE
	PUSHJ	P,STORS7##	;STORE S
	XMOVEI	T1,INPDUN	;WHERE TO GO WHEN DONE
	MOVEM	T1,IRBIVA(P1)	;STORE IT
TPSWST:
IFN FTKS10,<
	TLNN	S,IO		;DON'T SWEEP IF OUTPUT ON KS10
>
	PUSHJ	P,TPMSWP	;SWEEP CACHE IF NOT TM10A
TPSTRT:	MOVE	T1,P1		;IORB TO T1 FOR TAPSER
	PJRST	TAPSIO##	;TELL TAPSER TO TAKE IT AWAY


;ROUTINE TO FLUSH REQUEST AND RETURN IORB / SET IMPROPER MODE

TPMFLS:	PUSHJ	P,TAPFLS##	;FLUSH UNIT
	PUSHJ	P,TPMRI1	;T1 := IORB
	PUSHJ	P,SETIOD##	;REVIVE USER
	PUSHJ	P,CLRACT##	;CLEAR I/O ACTIVE
	PUSHJ	P,TAPCTM##	;CLEAR HUNG TIMER

;ROUTINE TO SET IMPROPER MODE AND RETURN

TPMINF:	PUSHJ	P,RTEVM##	;RETURN RESOURCES
	TRO	S,IOIMPM	;LITE A BIT
	PJRST	STOIOS##	;STORE S AND RETURN
;HERE WHEN INPUT DONE
;U,W,F SETUP  AND P1=IORB
INPDUN:	PUSHJ	P,SETIOS	;SET UP S AND CHECK ERRORS
	  JSP	P2,INPERR	;PONDER PROBLEM
	MOVE	T1,P1		;COPY IORB PNTR TO T1
	LDB	T2,PRBFCN##	;GET FCN
	CAIN	T2,RB.FRB	;READ BACKWARDS?
	TRNN	S,IOBOT		;YES - AT BOT?
	TRNE	S,IODEND	;SEEN EOF?
	JRST	RDEOF		;YES - TELL HIM
	LDB	P2,PRBMOD##	;GET MODE
	MOVE	P2,TMODTB##(P2)	;NO. OF BYTES PER WORD
	LDB	T2,PIOMOD##
	CAIN	T2,BYTMOD	;BUT IF IN BYTE MODE
	SETZ	P2,		; NO CONVERSION OF BYTE COUNT
IFN FTMP,<
	PUSHJ	P,STONBF##	;UPDATE LH(DEVNBF) IF POSSIBLE
	AOS	DEVNBF(F)	;COUNT 1 MORE RECORD READ
> ;END IFN FTMP
	PUSHJ	P,SVEUF##	;MAKE JOB ADDRESSABLE
	PUSHJ	P,SPCS##	;ALSO SETUP PCS
IFN FTKL10,<
	MOVE	T1,TKBCNT(W)	;NUMBER OF RECORDS WE DID
	SOJLE	T1,INPDN2	;IF MORE THAN 1,
IFN FTMP,<ADDM	T1,DEVNBF(F)>	;UPDATE NO OF RECS READ IN DDB

INPDN1:	SOSG	TKBCNT(W)	; (WOULD HAVE STOPPED EARLY ON LENGTH ERROR
	JRST	INPDN2		; IF THE WRDCNT WAS WRONG)
	MOVE	T1,DEVIAD(F)
	EXCTUX	<MOVE T2,1(T1)>	;GET BYTE COUNT
	ADDM	T2,TUBCRD(U)	;UPDATE TOTAL CHARS READ
	LDB	T4,PRBMD2##	;GET MODE
	PUSHJ	P,CHR2WD	;CONVERT TO WORDCOUNT
	EXCTUU	<MOVEM T2,1(T1)>	;STORE WRDCNT IN BUFFER
	PUSHJ	P,ADVBFI##	;MOVE TO NEXT BUFFER
	  TLOA	P1,400000	;FLAG NOT TO CALL ADVBFX AGAIN
	JRST	INPDN1		;AND KEEP ON GOING
INPDN2:
> ;END IFN FTKL10
	LDB	T4,PRBMD2##	;GET MODE
IFN FTKL10,<
	MOVSI	T2,RB.SEN	;AN ERROR IN NEXT RECORD (CHAN CHAINING)?
	TDNE	T2,TRBSTS(P1)	; (BUT THIS RECORD IS OK)
	JRST	[ANDCAM T2,TRBSTS(P1)	;YES - HENCE RECORD LENGTH IS RIGHT
		 PUSHJ  P,TPMXCI	;SO GET BYTE COUNT OUT OF BUFFER
		   EXCTUX <MOVE T2,1(T1)> ; WHERE DX10 STORED IT
		 MOVEM  T2,TRBRCT(P1)
		 JRST   INPDN3]
> ;END IFN FTKL10
	MOVE	T2,TRBRCT(P1)	;GET CHARS READ
INPDN3:	MOVEM	T2,TUBCCR(U)	;SAVE COUNT FOR TAPOP
	PUSHJ 	P,TPMXCI	;SET UP FOR PXCT
	  EXCTUX <LDB T3,[POINT 17,0(T1),17]> ;GET BUFFER SIZE+1 IN WORDS
	SOS	T3		;BUFFER SIZE
	IMUL	T3,TMODTB##(T4)	;GET BUFFER SIZE IN FRAMES
	CAILE	T2,(T3)		;RECORD .LTE. BUFFER
	MOVEI	T2,(T3)		;NO, USE BUFFER SIZE
	PUSHJ	P,CHR2WD	;CONVERT FC TO WC OR BC
	PUSHJ	P,TPMXCI	;GET C(DEVIAD) AGAIN
	  EXCTUU <MOVEM	T2,1(T1)>	;STORE IN HEADER
	PUSHJ	P,TPMRCW	;RETURN XFER LIST
	TLZN	P1,400000	;HAVE AN ADDRESS CHECK EARLIER (DX10)?
	PUSHJ	P,ADVBFF##	;ADVANCE BUFFERS
	  JRST	TPSWSP		;NO MORE STOP IO
IFN FTMP,<
	HRRZ	T1,DEVIAD(F)	;NEXT BUFFER OK WRT CACHE
	PUSHJ	P,BUFSSN##
	  JRST	TPSWSP		;NO, STOP I/O
> ;END IFN FTMP
	PUSHJ	P,SETIOD##	;REVIVE USER
	MOVEM	S,DEVIOS(F)	;SAVE CORRECT IOS
	MOVE	T1,P1		;SET UP IORB PNTR
	LDB	P2,PRBFCN##	;GET FCN BACK
	PUSHJ	P,TPIOGO	;SET IORB
	  JRST	TPSWSP		;NO MORE - STOP I/O
	JRST	TPMIN1		;START NEXT READ

;SUBROUTINE TO CONVERT BYTE-COUNT TO WORD-COUNT
;ENTER T2=BYTE COUNT, P2=NO OF BYTES PER WORD, P2=0 IF BYTE MODE
;EXIT T2=WORDCOUNT
CHR2WD:	JUMPE	P2,FCTOBC
	IDIVI	T2,(P2)
	JUMPE	T3,CPOPJ##
	AOJA	T2,CPOPJ##

;SUBROUTINE TO CONVERT FRAME COUNT TO BYTE COUNT
;ENTER T4=PRBMOD, T2=FRAME COUNT
;EXIT T2=BYTE COUNT
FCTOBC:	PUSHJ	P,SAVE3##
	HRRZ	P1,DEVBUF(F)	;BUFFER HEADER BLOCK ADDR
	EXCTUX	<LDB P3,[POINT 6,1(P1),11]>	;BYTE SIZE
	CAMN	P3,TMODFS##(T4)	;BYTE SIZE = FRAME SIZE ?
	POPJ	P,		;YES, BYTE COUNT = FRAME COUNT
	IDIV	T2,TMODTB##(T4)	;NO, CALCULATE BYTE COUNT
	MOVEI	P1,44		;WORD LENGTH
	IDIVI	P1,(P3)		;36/ BYTE SIZE
	IMULI	T2,(P1)		;# WORDS * BYTES PER WORD
	SKIPN	P1,T3		;EXTRA FRAMES ?
	POPJ	P,		;NO
	IMUL	P1,TMODFS##(T4)	;YES, EXTRA FRAMES * FRAME SIZE
	ADDI	P1,-1(P3)	;ROUND UP
	IDIVI	P1,(P3)		;/ BYTE SIZE
	ADD	T2,P1		;ADD EXTRA BYTES
	POPJ	P,
TPIOGO:	TRNN	S,IOTEND!IOERRS	;ANY ERRORS / EOT
	PUSHJ	P,QDECR		;DECREMENT QUANT
	  POPJ	P,		;NO MORE - RETURN
	MOVE	T1,P1		;GET IORB PNTR
	MOVEI	T2,RB.ACT	;MARK REQUEST ACTIVE
	PUSHJ	P,STOIOR	;STORE INFO IN IORB
	  JFCL			;NO WAY
	PJRST	CPOPJ1##	;GIVE SKIP RETURN


;ROUTINE TO HANDLE EOF/BOT AND STOP TAPE

RDEOF:	TRZ	S,IODEND	;CLEAR EOF
	TLO	S,IOEND		;SAY PAYS END SEEN
	PUSHJ	P,TPMXCI	;GET C(DEVIAD)
	  EXCTXU <MOVEM S,-1(T1)>  ;STORE IOS IN BUFFER HEADER
IFN FTTLAB,<JUMPE P1,TPSTP0>	;JUMP IF NO IOLIST
	PUSHJ	P,TPMRCW	;RETURN CCW LIST

TPMSTP:	PUSHJ	P,TPMRIO	;RETURN IORB
TPSTP0:	PUSHJ	P,RTEVM##	;RETURN EVM IF ANY
	TRZ	S,IOACT		;FIGHT DUAL-CPU RACE
	PUSHJ	P,SETIOD##	;REVIVE HIM
	PUSHJ	P,CLRACT##	;CLEAR I/O ACTIVE
	PUSHJ	P,TAPCTM##	;CLEAR HUNG TIMER
	HLLZS	TKBSTS(W)	;SET CNTR TO ZERO
	PJRST	STOIOS##	;STASH IOS & EXIT
TPSWSP:	PUSHJ	P,TPMSWP	;SWEEP CACHE IF NOT TM10A
	JRST	TPMSTP		;NOW STOP IO

;ROUTINE TO RETURN IOWD LIST , P1 := IORB

TPMRCW:
IFN FTKL10,<
	HRRE	T1,@IRBACC(P1)	;FETCH CHANNEL COMMAND LIST
	CAIG	T1,100		;ALLOW FOR COUNT
	POPJ	P,		;RETURN
	PJRST	RTNIOW##	;ELSE RETURN WHOLE LIST
> ;END IFN FTKL10
IFN FTKS10,<POPJ P,>		;RETURN


;ROUTINE TO RETURN IORB AND DE-Q IT

TPMRIO:	PUSHJ	P,TAPREM##	;HAVE TAPSER PRUNE QUEUE
				; RETURN PNTR TO IORB IN T1
TPMRI1:	MOVE	T2,T1		;GIVWDS LIKES IT IN T2
	MOVEI	T1,TRBLEN	;# OF WORDS
	PJRST	GIVWDS##	;RETURN CORE

;ROUTINE TO DECREMENT KONTROLLER QUANTA - SKIP RETURN IF NON-ZERO

QDECR:	HRRZ	T1,TKBSTS(W)	;GET QUANTA
	SOSL	T1		;DECR SKIP IF NEG
	HRRM	T1,TKBSTS(W)	;STORE RESULT
	JUMPG	T1,CPOPJ1##	;SKIP RET IF STILL POSITIVE
	POPJ	P,		;QUANTUM GONE TO 0, GIVE UP
SUBTTL	OUTPUT UUO

TPMOUT:	PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSHJ	P,OUTSET	;SET UP FOR OUTPUT
	SKIPGE	TUBREC(U)	;IS RECORD COUNT NEGATIVE?
	SETZM	TUBREC(U)	;YES, INITIALIZE TO ZERO
IFN FTTLAB,<
	TLZE	S,LBLSTP	;WANT TO STOP NOW?
	JRST	TPSTP0		;STOP ON LABEL ERROR
> ;END IFN FTTLAB
	MOVEI	P2,RB.FWT	;FUNCTION WRITE
	PUSHJ	P,GENIOR	;MAKE AN IORB
	  JRST	TPMINF		;UNABLE TO GET STORAGE
IFN FTMP,<
	PUSHJ	P,TPMACC	;IF ON OTHER CPU
	  JRST	PCLOUT		; DO IT DIFFERENTLY
> ;END IFN FTMP
	MOVEI	T2,DEPAIO	;ASYNC I/O?
	TDNE	T2,DEVAIO(F)
	JRST	QUEOUT		;YES - GO QUEUE OUTPUT REQUEST
	MOVEM	T1,TDVIOR(F)	;NO - WAIT FOR THIS ONE
	XMOVEI	T2,TPMOU1	;HACK LOCATION
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWAT
	PUSHJ	P,TAPRQT##	;QUEUE IT UP
	PUSHJ	P,KONWAT	;WAIT FOR CONTROLLER
				;RETURN WITH P1 := IORB
	SKIPGE	TRBFNC(P1)	;THINGS IN SHAPE
	JRST	TPMFLS		;NO - U LOSE
	SKIPN	DEVEVM(F)	;HAVE EVM
	PUSHJ	P,RSTEVM##	;NO - GET IT IF NECESSARY
				;FALL INTO TPMOU1
TPMOU1:	PUSHJ	P,TPMXCO	;GET C(DEVOAD)
	  EXCTUX <HRRZ	T2,1(T1)>	;GET WORD COUNT FROM BUFFER
	JUMPE	T2,ADVOUT	;HANDLE EMPTY BUFFER SPECIAL
	LDB	T3,PIOMOD##	;MODE OF DDB
	CAIE	T3,BYTMOD	;BYTE MODE?
	JRST	[SETZM T4	;NO
		   JRST TPMOU2]
	LDB	T3,PRBMD2##	;YES, CONVERT TO WORDS
	MOVE	T4,T2		;KEEP BYTE COUNT AROUND
	IDIV	T2,TMODTB##(T3)
	SKIPE	T3
	ADDI	T2,1		;T2=NUMBER OF WORDS
TPMOU2:	PUSHJ	P,TPMXCO	;GET BUFFER SIZE
	EXCTUX	<LDB T3,[POINT 17,0(T1),17]>
IFN FTKS10,<
	CAIG	T2,^D7621	;MAX # WORDS GUARANTEED NOT TO RUN OUT
				;OF MAPPING REGS (1 WORD ON LAST WORD OF PAGE
				; + IS FULL PAGES)
> ;END IFN FTKS10
	CAILE	T2,-1(T3)	;OK?
	JRST	SETIMP		;NO, LIGHT AN ERROR BIT
	MOVNS	T2		;-N
	HRLZS	T2		;PUT IN LH
	HRRI	T2,1(T1)	;BUFFER ADDRS
	MOVE	T1,P1		;IORB PNTR TO T1
	PUSHJ	P,MAKLST	;MAKE CHL XFER LIST
	  JRST	TPMFLS		;FLUSH REQUEST
	TRO	S,IOACT		;SET I/O ACTIVE
	PUSHJ	P,STORS7##	;STORE S
	XMOVEI	T1,OUTDUN	;WHERE TO GO WHEN FINISHED
	MOVEM	T1,IRBIVA(P1)	;STORE IN IORB
	PJRST	TPSWST		;START DEVICE
;HERE WHEN OUTPUT DONE, P1 := IORB
OUTDUN:	PUSHJ	P,SETIOS	;SET UP S W/ TAPE INFO
	  JSP	P2,OUTERR	;TRY TO FIX WRITE ERROR
	PUSHJ	P,SETIOD##	;REVIVE USER
	PUSHJ	P,STORS7##	;SAVE S IN DDB
	PUSHJ	P,TPMRCW	;RETURN XFER LIST
IFN FTTLAB,<
	TRNE	S,IOTEND	;EOT SEEN YET?
	JRST	LBLEOT		;YES - INVOKE LBL PCS
> ;END IFN FTTLAB
IFN FTKL10,<
	PUSHJ	P,SVEUF##	;SET UP ADDRESSING (ADVBFO DOESN'T)
	PUSHJ	P,SPCS##	;AND PCS
OUTDN1:	SOSG	TKBCNT(W)	;FOR ALL BUT THE LAST BUFFER,
	JRST	OUTDN2
	PUSHJ	P,ADVBFO##	;TELL UUOCON THAT IT'S FULL
	  JRST	TPMSTP		;OOPS, ADDRESS CHECK, ETC.
	JRST	OUTDN1		;AND TRY THE NEXT
OUTDN2:
> ;END IFN FTKL10
	PUSHJ	P,ADVBFE##	;ADVANCE BUFFER
	  JRST	TPMSTP		;NO MORE STOP IO
	MOVEI	P2,RB.FWT	;TRY TO WRITE ON
IFN FTMP,<
	MOVSI	T2,-1		;IF NEXT BUFFER WAS NOT SWEPT
	TDNE	T2,DEVNBF(F)	; SHUT DOWN THE TAPE
> ;END IFN FTMP
	PUSHJ	P,TPIOGO	;...
	  JRST	TPMSTP		;NO MORE RETURN
	JRST	TPMOU1		;CONTINUE WRITING
;HERE TO ADVANCE BUFFER IF ONE FOUND EMPTY

SETIMP:	TRO	S,IOIMPM	;USER FIDDLED WITH BUFFER HEADER
ADVOUT:
IFN FTMP,<
	PUSHJ	P,CHKCPI##	;UUOCON HAS INCREMENTED DEVNBF
	  SKIPA	T1,[-1]		; BUT WE WON'T GET TO MAKLST
	MOVSI	T1,-1		; TO COUNT IT DOWN
	ADDM	T1,DEVNBF(F)	; SO MAKE DEVNBF RIGHT
> ;END IFN FTMP
	PUSHJ	P,ADVBFE##	;CYCLE
	  SKIPA			;NO NEXT BUFFER
	JRST	TPMOU1		;TRY THIS ONE
	PUSHJ	P,SETIOD##	;REVIVE USER
	PUSHJ	P,CLRACT##	;CLEAR I/O ACTIVE
	PUSHJ	P,TAPCTM##	;CLEAR HUNG TIMER
TPMFLX:	PUSHJ	P,TAPFLS##	;ELSE FLUSH REQUEST
	PUSHJ	P,TPMRI1	;RETURN IORB
	PJRST	RTEVM##		;AND EVM IF ANY

IFN FTTLAB,<
;ENTER HERE TO PROCESS EOT AND SEND MSG TO LBL PCS

LBLEOT:	PUSHJ	P,ADVBFE##	;ADVANCE BUFFERS
	  JFCL			;IGNORE
	PUSHJ	P,LBLCHK	;LABEL PROCESSING?
	SKIPA			;YES - SEND MSG ETC.
	PJRST	TPMSTP		;ELSE PROCESS AS BEFORE
	LDB	T1,TUYLTP	;GET LABEL TYPE.
	CAIN	T1,LT.NLV	;SHOULD USER SEE EOT?
	JRST	TPMSTP		;YES, GIVE IT TO THEM
	TLO	S,LBLNED	;NO GIVE IT TO LBL PCS NEXT TIME.
	TRZ	S,IOTEND	;CLEAR EOT NOW
	MOVEI	T1,LR.EOT	;SET TYPE EOT
	DPB	T1,TUYRQT	; IN LBL MESSAGE
	PJRST	TPMSTP		;  AND STOP IO
> ;END IFN FTTLAB
SUBTTL DUMP-MODE I/O
TPMDOU:	PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSHJ	P,OUTSET	;SET FOR OUTPUT
	SKIPGE	TUBREC(U)	;IS RECORD COUNT NEGATIVE?
	SETZM	TUBREC(U)	;YES, INITIALIZE TO ZERO
	JRST	TPMDMP		;TO COMMON ROUTINE

TPMDIN:	PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSHJ	P,INSET		;SET FOR INPUT
TPMDMP:
IFN FTTLAB,<
	TLZE	S,LBLSTP	;LBL ERROR?
	POPJ	P,		;YES, RETURN NOW
> ;END IFN FTTLAB
	PUSHJ	P,DMPSET	;SET UP IORB & WAIT FOR CTL
	  PJRST	TPMINF		;LOSAGE
	PUSHJ	P,COMCHK##	;GET 1ST IOWD & BOUNDARIES
	JUMPN	S,ADRXIT	;ADDRESS CHECK?
	MOVE	S,DEVIOS(F)	;RESTORE S
	JUMPE	T1,TPMFLS	;OR NULL LIST - EXIT
	PUSHJ	P,SAVT##	;SAVE T1 (IOWD)
	MOVEM	T2,TDVSUL(F)	;SAVE USER UPPER LIMIT
	MOVEM	T3,TDVSLL(F)	;  AND USER LOWER LIMIT
TPDNXT:	MOVEM	M,TDVSVM(F)	;  AND M (UUO)
	MOVEM	T1,-1(P)	;SAVE T1 IN CASE OFL
IFN FTKS10,<
	TRNN	S,1B35		;MODE 16?
	TLNN	S,IO		;YES, OUTPUT?
	SKIPA			;NO, CHECK FOR BIG IOWD
	JRST	TPDNX1		;YES, DON'T CHECK (ADIIOW WILL FIX)
	HLRZ	T2,T1		;MAX # WORDS GUARANTEED NOT TO RUN OUT
	CAIGE	T2,^D-7681	;OF MAPPING REGISTERS
	JRST	TPMFLS		;(1 WORD ON LAST WORD OF PAGE + 15 FULL PAGES)
TPDNX1:
> ;END IFN FTKS10
	PUSHJ	P,ADJIOW	;ADJUST IOWDS IF NECESSARY
				;RETURNS IOWD IN T2
	PUSHJ	P,TPMDGO	;START I/O
	  JRST	TPMFLS		;CAN'T - MAKLST LOST
	MOVE	M,TDVSVM(F)	;RESTORE M
	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO CEASE
	TLNN	S,IO		;WRITING?
	PUSHJ	P,TPMSWP	;NO, MUST SWEEP CACHE
IFN FTTLAB,<
	PUSHJ	P,LBLCKS	;CHECK FOR LABEL EXPECTED
	  JFCL			;IGNORE THIS RETURN
	TLNE	S,LBLNED	;NEED LABELS?
	PUSHJ	P,LBLMSG	;YES, SEND THE MESSAGE
	TLZ	S,LBLSTP	;GET RID OF THIS BIT
	MOVEM	S,DEVIOS(F)	;SAVE NEW STATUS
> ;END IFN FTTLAB
	TLNE	S,IOSTBL	;ARE WE IN TROUBLE?
	JRST	TPDOFL		;YES - CHECK OFFLINE
	TRNE	S,IODEND!IOBOT!IOERRS	;ERRORS?
	POPJ	P,		;YES - EXIT
	PUSHJ	P,DMPSET	;GEN IORB FOR NEXT IOWD
	  PJRST	TPMINF		; NO ROOM - LOSE
	MOVE	M,TDVSVM(F)	;RESTORE SAVED STUFF
	MOVE	T2,TDVSUL(F)
	MOVE	T3,TDVSLL(F)	;...
	PUSHJ	P,NXCMR##	;GET NEXT IOWD
	JUMPN	S,ADRXIT	;JUMP IF ADR CHK
	MOVE	S,DEVIOS(F)	;S CLOBBERED BY NXCMR!
	JUMPE	T1,TPMFLX	;ALL DONE IF ZERO
	JRST	TPDNXT		;SAVE M AND TRY NEXT
;ROUTINE TO HANDLE OFF-LINE UNIT IN DUMP MODE

TPDOFL:	TLZ	S,OFFLIN!IOSTBL	;CLEAR BITS
	PUSHJ	P,CKTC10	;CHECK TC10 CROCK
	  PUSHJ	P,HNGSTP##	;CALL ATTEN TO OURSELVES
	PUSHJ	P,DMPSET	;GEN IORB ETC.
	  PJRST	TPMINF		;NO ROOM
	MOVE	T1,-1(P)	;RESTORE IOWD
	JRST	TPDNXT		;TRY AGAIN
;ROUTINE TO START DUMP MODE I/O

TPMDGO:	MOVE	T1,P1		;IORB TO T1
	SETZ	T4,		;NOT BYTE-MODE, DO ALL OF IOWD
	PUSHJ	P,MAKLST	;GEN IO XFER LIST
	  POPJ	P,		;WHOOPS
	CONSO	PI,II.IPA	;DON'T SET IF AT INT LVL
	PUSHJ	P,SETACT##	;SET I/O ACTIVE
	HLLOS	TKBSTS(W)	;GRNTEE CONTROLLER
	XMOVEI	T1,DMPDUN	;WHERE TO GO WHEN DONE
	MOVEM	T1,IRBIVA(P1)	;SAVE IN IORB
	AOS	0(P)		;GIVE SKIP RETURN
	PJRST	TPSWST		;GO START DEVICE

;COME HERE ON DONE INTERUPT FOR DUMP MODE I/O

DMPDUN:	PUSHJ	P,SETIOS	;SET UP S
	  JSP	P2,DMPERR	;ERROR RETURN
	PUSHJ	P,TPMRCW	;RETURN XFER LIST
	MOVE	T2,TRBRCT(P1)	;BYTE COUNT OF LAST REC
	MOVEM	T2,TUBCCR(U)	;SAVE FOR TAPOP
	TRNN	S,IODEND!IOBOT!IOERRS	;ERRORS?
	SKIPN	T1,TDVREM(F)	;ANY PARTIAL LEFT?
	JRST	TPMSTP		;STOP NOW
	PUSHJ	P,ADJIOW	;MUNG IOWD IF NECESSARY
	TLNN	S,IO		;INPUT?
	SKIPE	TDVREM(F)	;YES - DONE?
	SKIPA	T1,P1		;NO - PROCEED
	JRST	TPMSTP		;YES - SHUT DOWN
	PUSH	P,T2		;SAVE IT
	LDB	P2,PRBFCN##	;GET FCN BACK
	MOVEI	T2,RB.ACT	;MAKE IORB ACTIVE AGAIN
	PUSHJ	P,STOIOR	;STORE INFO IN IORB
	  JFCL			;UNLIKELY
	POP	P,T2		;RESTORE IOWD
	PUSHJ	P,TPMDGO	;START IT UP
	  JRST	TPMFLS		;FLUSH - MAKLST LOST
	POPJ	P,		;EXIT INTERUPT
;ROUTINE TO PERFORM IOWD HACKING FOR MODE 16
;DESIRED IOWD IN T1, RETURN ADJUSTED IOWD IN T2


ADJIOW:	MOVE	T2,T1		;MOVE TO T2 IN CASE
	SETZM	TDVREM(F)	;CLEAR REMAINDER
	TRNE	S,1B35		;WE HAVE NOTHING TO DO?
	POPJ	P,		;MODE 17 - RETURN
	TLNE	S,IO		;OUTPUT/INPUT?
	JRST	[LDB T4,PBUFSZ##	;OUTPUT - GET BUFFER SIZE
		 MOVNI	T4,-1(T4) ;- BLOCK SIZE
		 JRST ADJIO1]	;JOIN COMMON CODE
	LDB	T4,[POINT RB.MDS,TRBFNC(P1),RB.MDP]	;INPUT - GET MODE
	MOVE	T3,TRBRCT(P1)	;CHAR COUNT OF LAST RECORD OR ZERO
	IDIV	T3,TMODTB##(T4)	;CONVERT TO WORDS
	SKIPE	T4		;CHECK REMAINDER
	ADDI	T3,1		;ADJUST IF NECESSARY
	MOVNI	T4,(T3)		;NEGATE
ADJIO1:	HLRE	T1,T2		;SIZE OF XFER
	CAML	T1,T4		;DOES IT FIT?
	POPJ	P,		;YES - JUST RETURN
	SUB	T1,T4		;NEW WORD COUNT
	SUB	T2,T4		;NEW ADDRESS
	HRL	T2,T1		;WORRY ABOUT CARRY
	MOVEM	T2,TDVREM(F)	;SAVE FOR LATER
	TLNN	S,IO		;OUTPUT?
	POPJ	P,		;NO - THEN DONE
	ADD	T2,T4		;RE-ADJUST IOWD FOR NOW
	HRL	T2,T4		;-BS,,ADDRS OPTIMAL
	POPJ	P,		;RETURN

;HERE ON ADDRESS CHECK AT UUO LEVEL

ADRXIT:	PUSHJ	P,TPMFLS	;FLUSH REQUEST
	PJRST	ADRERR##	;AND STOP USER

;SET UP IORB FOR DUMP I/O
;RETURN P1 := IORB , CONTROLLER SCHEDULED

DMPSET:	MOVEI	P2,RB.FWT	;ASSUME WRITE
	TLNN	S,IO		;IS IT?
	PUSHJ	P,SETRED	;NO - GET READ FCN
	TRNN	S,1B35		;MODE 16?
	CAIE	P2,RB.FRB	;YES - READ BACKWARDS?
	PUSHJ	P,GENIOR	;GENERATE IORB
	  POPJ	P,		;NO ROOM - LOSE
	MOVEM	T1,TDVIOR(F)	;REMEMBER THIS ONE
	XMOVEI	T2,TPMNOP	;HACK LOCATION
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWAT
	PUSHJ	P,CPURQT##	;QUEUE IT UP
	PUSHJ	P,KONWAT	;WAIT TILL NOTICED
				;RETURN WITH P1 := IORB
	SKIPN	DEVEVM(F)	;KI ONLY
	PUSHJ	P,DMPEV##	;RESTORE EVM IF NECESSARY

	JRST	CPOPJ1##	;SKIP RETURN
SUBTTL RELEASE AND CLOSE UUO'S

TPMREL:	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO CEASE
	MOVEI	T1,0		;RESET TO ZERO MODE
	DPB	T1,TDYMOD	;INTO THE DDB
	MOVSI	T1,D.RDBK!D.NRLT!D.EPAR
	ANDCAM	T1,TDVSTS(F)	;CLEAR THIS STUFF TOO
	MOVE	U,TDVUDB(F)	;UDB POINTER
IFN FTTLAB,<
	TLNE	S,LBLWAT	;WAITING FOR LABELS
	PJRST	LBLABO		;YES,JUST TELL LBL PCS
> ;END IFN FTTLAB
	PUSHJ	P,TPMRLW	;WAIT TILL DESELECTED
TPMRL2:	PUSHJ	P,TAPKIL##	;KLANK CTL
IFN FTMP,<
	SETZM	DEVNBF(F)	;NO SWEPT-FOR BUFFERS
	SETZM	DEVSBF(F)
> ;END IFN FTMP
	PJRST	TPMDQ		;UNWIND Q , PNTR IN T1

TPMRLW:	MOVSI	T1,TUSREW##!TKSSEL##
IFN FTMP,<CONSO	PI,PI.IP7>	;CAN'T SLEEP ON CLOCK LEVEL (TAPTIC)
	TDNN	T1,TUBSTS(U)	;TAPE SHOULD NOT BE SELECTED
	POPJ	P,		;OK TO PROCEED
	PUSHJ	P,TSLEE1	;SLEEP 1 SEC (REWINDS LIKE TO
				;  STRETCH THEIR LEGS SLOWLY!)
	JRST	TPMRLW		;SEE IF SUCCESSFUL
;CLOSE (WRITE TM,TM,BSB)

TPMCLS:	TLNN	F,OUTPB		;ANY OUTPUTS
	POPJ	P,		;NO -RETURN
	LDB	T1,PIOMOD##	;GET MODE
	CAIGE	T1,SD		;DUMP MODE?
	PUSHJ	P,OUT##		;NO - DUMP PARTIAL BUFFER
	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO STOP
IFN FTMP,<
	SETZM	DEVNBF(F)	;NO BUFFERS SWEPT FOR
	SETZM	DEVSBF(F)
> ;END IFN FTMP
	MOVE	U,TDVUDB(F)	;UDB ADDRESS
IFN FTTLAB,<
	LDB	J,PJOBN##	;RESTORE J
	PUSHJ	P,LBLCHK	;NEED LABELING?
	  JRST	TPCLSO		;YES - SEND CLOSE MSG
> ;END IFN FTTLAB
	MOVSI	T1,TKSOFL##!TUSREW##
	TDNN	T1,TUBSTS(U)
	TRNE	S,IOBOT		;TAPE AT BOT (REW OR UNLOAD) ?
	POPJ	P,		;YES, DON'T WRITE EOF'S
	PUSHJ	P,SAVE3##	;SAVE P1,P2,P3
	MOVE	P3,S
	ANDI	P3,IOERRS
	PUSHJ	P,IOSET		;SET UP U
TPMCL1:	MOVEI	P2,RB.FTM	;WRITE TAPE MARK
	PUSHJ	P,GENIOR	;GENERATE IORB
	  JRST	TPMINF		;WHOOPS
	MOVEM	T1,TDVIOR(F)	;IORB TO REMEMBER
	XMOVEI	T2,TPMCL1	;HACK LOCATION
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWAT
	PUSHJ	P,CPURQT##	;Q IT UP
	PUSHJ	P,GENIOR	;ANOTHER REQUEST
	  JRST	TPMINF
	XMOVEI	T2,TPMCL1	;HACK LOCATION
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWAT
	PUSHJ	P,CPURQT##	;ADD TO QUEUE
	MOVEI	P2,RB.FBR	;BACK OVER LAST TM
	PUSHJ	P,GENIOR	;MAKE ANOTHER IORB
	  JRST	TPMINF		;LOSER
	XMOVEI	T2,TPMCL1	;HACK LOCATION
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWAT
	PUSHJ	P,CPURQT##	;Q IT
	PUSHJ	P,KONWAT	;NOW WAIT YOUR TURN
				;P1 := FIRST IORB
	PUSHJ	P,SETACT##	;SET I/O ACTIVE
	XMOVEI	T1,CLSDUN	;WHERE TO GO ON ENDING INT
	MOVEM	T1,IRBIVA(P1)	;STORE IN IORB

	MOVEI	T1,1		;SET FOR ONE OP
	HRRM	T1,@IRBACC(P1)	;INTO IORB
	PUSHJ	P,TPSTRT	;GO START IT
	PUSHJ	P,WSYNC##	;WAIT FOR IT TO STOP
	IOR	S,P3
	TRZ	S,IODEND	;CLEAR EOF ON WRITE
	PJRST	STOIOS##	;STORE S AND RETURN
;ROUTINE TO PERFORM CLOSE INTERUPT ACTION

CLSDUN:	PUSHJ	P,SETIOS	;SET UP S FOR ERROR CHECK
	  JSP	P2,OUTERR	;GO HANDLE ERROR
	TRNE	S,IOIMPM	;WRITE LOCKED?
	JRST	CLSWLK		;YES - FLUSH REMAINDER
	PUSHJ	P,TPMRIO	;REMOVE ITEM
	HRRZ	T1,TUBQUE(U)	;GET NEXT ITEM
	MOVEI	T2,RB.ACT	;MARK ACTIVE
	DPB	T2,PRBRQS##
	MOVEI	P2,CLSDUN	;ASSUME HERE AGAIN
	LDB	T2,PRBFCN##	;GET FCN
	CAIN	T2,RB.FBR	;BACKSPACE RECORD?
	XMOVEI	P2,CLSDN1	;YES - GO HERE INSTEAD
	MOVEM	P2,IRBIVA(T1)	;SAVE NEXT INT ADDRS
	HLLOS	TKBSTS(W)	;GRNTEE STILL KEEP KONTROLLER
	MOVEI	T2,1		;ONLY ONE OP PSE
	HRRM	T2,@IRBACC(T1)	;...
	PJRST	TAPSIO##	;START DEVICE

;HERE AFTER BACKSPACE RECORD

CLSDN1:	PUSHJ	P,SETIOS	;SET UP S
	  JSP	P2,SPERR	;HANDLE SPACING ERROR
	PJRST	TPMSTP		;AND WIND DOWN

;HERE IF WRITE LOCKED ON CLOSE

CLSWLK:	PUSHJ	P,TAPDSL##
	PUSHJ	P,TPMRL2	;FLUSH Q AND STOP I/O
	PJRST	TPSTP0		;...

IFN FTTLAB,<

;ROUTINE TO HANDLE INPUT CLOSE OPERATION
TPCLSI:	MOVE	U,TDVUDB(F)	;UDB ADDRESS
	SETZ	T1,		;CLEAR AC
	TDNE	S,[LBLEOF,,IODEND] ;TAPE MARK OR EOF SEEN?
	MOVEI	T1,1		;YES, SAY SO
	PUSHJ	P,LBLCHK	;NEED LABELING?
	  TLNN	F,INPB		;YES - ANY INPUTS??
	POPJ	P,		;NO - RETURN
	DPB	T1,TUYINF	;SAVE TAPE MARK STATUS
	MOVEI	T1,LR.CLI	;SET REQUEST TYPE
	JRST	TPCLSX		;PICK UP COMMON CODE

;ROUTINE TO HANDLE CLOSE OUTPUT OPERATION

TPCLSO:	MOVEI	T1,LR.CLO	;SET REQUEST TYPE
TPCLSX::DPB	T1,TUYRQT	; INTO UDB
	TLO	S,FSTOP!IOBEG	;SET FIRST OP ALSO
	MOVEM	S,DEVIOS(F)	;UPDATE STATUS
IFN FTMP,<
	PUSHJ	P,WAIT1##	;WAIT FOR IO TO STOP
	SETZM	DEVNBF(F)	;CLEAR COUNTERS OF NUMBER OF BUFS SWEPT FOR
	SETZM	DEVSBF(F)
> ;END IFN FTMP
	PJRST	LBLMSG		;INFORM LBL PCS
> ;END IFN FTTLAB
SUBTTL	ENTER AND LOOKUP UUOS


IFN FTTLAB,<
; ENTER UUO
TPMENT:	PUSHJ	P,TPMLIB	;SET UP U AND LABEL INFO BLOCK
	  JRST	CPOPJ1##	;NOT LABELED OR TAPE LABELER NOT RUNNING
	JSP	T4,TPMARG	;SAVE ACS AND SET POINTERS TO CALLER'S ARGS
	MOVSI	T2,TUSWTL##	;GET WRITE LOCKED BIT
	TDNE	T2,TUBSTS(U)	;CHECK STATUS
	JRST	LERWLK		;CAN'T DO ENTER UUOS ON W/L DEVICES

; FORMS CONTROL BYTE
	MOVE	T2,[.TFCNO,,.TRFDF] ;NO FORMS CONTROL AND DEFAULT RECORD FORMAT
;	HRRI	M,UUXFRW(P1)	;POINT TO FORMS CONTROL/RECORD FORMAT WORD
;	CAIGE	P2,UUXFRW	;ARG BLOCK CONTAIN THIS WORD?
;	TDZA	T1,T1		;NO
;	PUSHJ	P,GETWDU##	;GET FROM ARG BLOCK
;	SKIPN	T1		;WAS ONE SPECIFIED?
	MOVE	T1,T2		;NO--USE DEFAULT
	HLRZ	T2,T1		;GET FORMS CONTROL
	DPB	T2,TUYFCT	;STORE IT

; RECORD FORMAT BYTE
	HRRI	M,UUXBSZ(P1)	;POINT TO RECORD FORMAT WORD (BSZ)
	CAIGE	P2,UUXBSZ	;ARG BLOCK CONTAIN THIS WORD?
	TDZA	T1,T1		;NO
	PUSHJ	P,GETWDU##	;GET FROM ARG BLOCK
	LDB	T1,[POINT 6,T1,29] ;GET RECORD FORMAT BYTE
	SKIPN	T1		;WAS ONE SPECIFIED?
	MOVEI	T1,.TRFDF	;NO--DEFAULT
	DPB	T1,TUYRFM	;STORE RECORD FORMAT

; RECORD SIZE
	LDB	T2,PBUFSZ##	;GET BLOCK SIZE
	SUBI	T2,1		;ACCOUNT FOR OFF BY ONE
	LDB	T1,TDYMOD	;GET THE MODE
	IMUL	T2,CPWTBL(T1)	;MULTIPLY BY CHARACTERS PER WORD
	HRLZS	T2		;PUT IN LH
	HRRI	M,UUXRSZ(P1)	;POINT TO RECORD SIZE WORD IN ARG BLOCK
	CAIGE	P2,UUXRSZ	;ARG BLOCK CONTAIN THIS WORD?
	TDZA	T1,T1		;NO
	PUSHJ	P,GETWDU##	;GET FROM ARG BLOCK
	TLNN	T1,-1		;RZS SPECIFIED?
	HLL	T1,T2		;NO--USE COMPUTED VALUE
	MOVSS	T1		;PUT RZS IN RH, BSZ IN LH
	DPB	T1,TUYRSZ	;STORE RSZ

; BLOCK SIZE
	HLRZS	T1		;GET BSZ
	SKIPE	T1		;WAS ONE SPECIFIED?
	DPB	T1,TUYBSZ	;SET IT

; CREATION DATE
	HRRI	M,UUNATT(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXPRV(P1)	;YES
	PUSHJ	P,GETWDU##	;GET ATTRIBUTE WORD
	LDB	T4,[POINT 12,T1,35] ;KEEP ONLY LOW DATE
	HRRI	M,UUNEXT(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXEXT(P1)	;YES
	PUSHJ	P,GETWDU##	;GET EXTENSION WORD
	LDB	T1,[POINT 3,T1,20] ;GET HIGH DATE
	DPB	T1,[POINT 3,T4,23] ;MERGE LOW AND HIGH
	SKIPN	T4		;USER SPECIFY A CREATION DATE?
	MOVE	T4,THSDAT##	;NO, USE TODAYS
	DPB	T4,TUYECR	;STORE IT

; EXPIRATION DATE
	HRRI	M,UUXDED(P1)	;BUT JUST IN CASE ...
	CAIGE	P2,UUXDED	;ARG BLOCK CONTAIN THIS WORD?
	TDZA	T1,T1		;NO
	PUSHJ	P,GETWDU##	;GET EXPIRATION DATE
	SKIPN	T1		;USER SPECIFY A DATE?
	MOVE	T1,THSDAT##	;ASSUME NO EXPIRATION DATE
	DPB	T1,TUYEEX	;STORE IT

; PROTECTION CODE
	HRRI	M,UUNATT(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXPRV(P1)	;YES
	PUSHJ	P,GETWDU##	;GET PROTECTION CODE
	LSH	T1,-^D27	;POSITION
	DPB	T1,TUYPRT	;SAVE IT

; FILE SEQUENCE NUMBER
;	HRRI	M,UUXPSN(P1)	;POINT TO SEQUENCE NUMBER IN ARG BLOCK
;	CAIGE	P2,UUXPSN	;ARG BLOCK CONTAIN THIS WORD?
;	TDZA	T1,T1		;NO
;	PUSHJ	P,GETWDU##	;GET IT
;	SKIPE	T1		;WAS ONE SPECIFIED?
	LDB	T1,TUYPSN	;GET OLD SEQUENCE NUMBER
	CAIG	T1,0		;MUST BE POSITIVE
	MOVEI	T1,1		;CALL IT THE FIRST FILE
	CAILE	T1,^D999	;THIS IS THE MAX
	MOVEI	T1,^D999	;DON'T OVERFLOW
	DPB	T1,TUYPSN	;AND SAVE IT

; FILE NAME AND EXTENSION
	MOVE	T1,[ASCII |     |] ;A WORD OF BLANKS
	MOVSI	T2,-4		;4 WORDS
	HRRI	T2,TUBFNM(U)	;STARTING HERE
	MOVEM	T1,(T2)		;STORE A WORD OF BLANKS
	AOBJN	T2,.-1		;BLANK OUT ENTIRE BLOCK
	SETZM	DEVFIL(F)	;CLEAR
	SETZM	DEVEXT(F)	; JUNK
	HRRI	M,UUNNAM(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXNAM(P1)	;YES
	PUSHJ	P,GETWDU##	;GET FILE NAME
	SKIPN	T1		;NULL?
	PUSHJ	P,TPMDFE	;GENERATE DEFAULT FILE NAME AND EXTENSION
	MOVEM	T1,DEVFIL(F)	;STORE IN DDB
	PUSHJ	P,SIXOUT	;STORE IN TUB
	MOVEI	T1,"."		;GET A PERIOD
	PUSHJ	P,TPMTYO	;SEPARATE FILENAME FROM EXTENSION
	SKIPN	T1,DEVEXT(F)	;WAS EXTENSION DEFAULTED CUZ BLANK FILE NAME?
	PUSHJ	P,GETWD1##	;NO--GET EXTENSION FROM ENTER BLOCK
	HLLZS	T1		;ZAR RH
	MOVEM	T1,DEVEXT(F)	;STORE IN DDB
	PUSHJ	P,SIXOUT	;STORE IN TUB

; GENERATION
	MOVEI	T2,0		;NO GENERATION,,NO VERSION
;	HRRI	M,UUXGVR(P1)	;POINT TO FORMS CONTROL/RECORD FORMAT WORD
;	CAIGE	P2,UUXGVR	;ARG BLOCK CONTAIN THIS WORD?
;	TDZA	T1,T1		;NO
;	PUSHJ	P,GETWDU##	;GET FROM ARG BLOCK
;	SKIPN	T1		;WAS ONE SPECIFIED?
	MOVE	T1,T2		;NO--USE DEFAULT
	HLRZ	T2,T1		;GET GENERATION NUMBER
	DPB	T2,TUYGEN	;STORE IT

; VERSION
	DPB	T1,TUYVER	;STORE VERSION

	PUSHJ	P,TPMFOU	;DO FIRST OUTPUT PROCESSING
	  JRST	LERLBL		;LABELING ERROR (ERROR CODE IN T1)
	JRST	CPOPJ1##	;RETURN
; STILL UNDER FTTLAB

; LOOKUP UUO
TPMLKP:	PUSHJ	P,TPMLIB	;SET UP U AND LABEL INFO BLOCK
	  JRST	CPOPJ1##	;NOT LABELED OR TAPE LABELER NOT RUNNING
	JSP	T4,TPMARG	;SAVE ACS AND SET POINTERS TO CALLER'S ARGS
	HRRI	M,UUNNAM(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXNAM(P1)	;YES
	PUSHJ	P,GETWDU##	;GET REQUESTED FILE NAME
	MOVEM	T1,DEVFIL(F)	;SAVE IT
	PUSHJ	P,GETWD1##	;GET REQUESTED EXTENSION
	HLLZM	T1,DEVEXT(F)	;SAVE IT
	SKIPE	DEVFIL(F)	;LOOKING FOR A SPECIFIC FILE?
	JRST	TPMLK2		;YES
	SKIPE	DEVEXT(F)	;(BLANK).EXT DOESN'T MAKE IT
	JRST	LERFNF		;CALL IT A FILE NOT FOUND ERROR
	JRST	TPMLK2		;ENTER LOOKUP LOOP
TPMLK1:	MOVEI	T1,16		;CODE TO FORWARD SPACE ONE FILE
	PUSHJ	P,MTAP0		;DO IT
TPMLK2:	PUSHJ	P,TPMLIC	;CLEAR OUT LABEL INFO BLOCK
	  JFCL			;WILL ALWAYS SKIP HERE
	PUSHJ	P,TPMFIN	;DO FIRST INPUT PROCESSING
	  SKIPA			;LABELING ERROR
	JRST	TPMLK3		;ONWARD
	CAIE	T1,LE.EOF	;EOF (LOOKUP READ FORWARD FAILED)?
	CAIN	T1,LE.BOT	;BOT (LOOKUP READ BACKWARDS FAILED)?
	JRST	LERFNF		;CONVERT TO FILE NOT FOUND
	CAIE	T1,LE.FNF	;SPECIFIC FILENAME.EXT LOOKUP FAILED?
	JRST	LERFNF		;YES
	JUMPN	T1,LERLBL	;ELSE IT MIGHT BE A FATAL LABELING ERROR
TPMLK3:	SKIPN	DEVFIL(F)	;LOOKING FOR A SPECIFIC FILE NAME?
	JRST	TPMLK4		;NO--ANY ONE WILL DO
	PUSHJ	P,SIXINP	;GET FILE NAME FROM TAPE LABEL
	CAME	T1,DEVFIL(F)	;MATCH?
	JRST	TPMLK1		;NO
	CAIE	T3,"."		;MUST BE A PROPER FILESPEC
	JRST	TPMLK1		; OR IT'S NO GOOD
	PUSHJ	P,SIXINP	;GET EXTENSION
	CAME	T1,DEVEXT(F)	;MATCH?
	JRST	TPMLK1		;NO
	JRST	TPMLK5		;ONWARD
TPMLK4:	PUSHJ	P,SIXINP	;GET FILE NAME
	MOVEM	T1,DEVFIL(F)	;STORE IN DDB
	HRRI	M,UUNNAM(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXNAM(P1)	;YES
	PUSHJ	P,PUTWDU##	;RETURN THE FILE NAME WE FOUND
	CAIE	T3,"."		;LEGAL TOPS-10 FILESPEC?
	TDZA	T1,T1		;NO--JUST RETURN A ZERO
	PUSHJ	P,SIXINP	;GET EXTENSION
	HLLZS	T1		;EXTENSIONS ARE ONLY 3 CHARACTERS LONG
	MOVEM	T1,DEVEXT(F)	;STORE IN DDB
	PUSHJ	P,PUTWD1##	;STORE IT
TPMLK5:

; FORMS CONTROL BYTE
;	LDB	T2,TUYFCT	;GET FORMS CONTROL

; RECORD FORMAT BYTE
	LDB	T1,TUYRFM	;GET RECORD FORMAT BYTE
	LSH	T1,6		;POSITION
	HRRI	M,UUXBSZ(P1)	;POINT TO RECORD FORMAT WORD (BSZ)
	CAIL	P2,UUXBSZ	;ARG BLOCK CONTAIN THIS WORD?
	PUSHJ	P,PUTWDU##	;YES--STORE IT

; RECORD SIZE / BLOCK SIZE
	LDB	T1,TUYRSZ	;GET RECORD SIZE FROM TAPE LABEL
	HRLZS	T1		;PUT IN LH
	LDB	T2,TUYBSZ	;GET BLOCK SIZE FROM TAPE LABEL
	IOR	T1,T2		;MAKE IT RSZ,,BSZ
	HRRI	M,UUXRSZ(P1)	;POINT TO RECORD SIZE WORD IN ARG BLOCK
	CAIL	P2,UUXRSZ	;ARG BLOCK CONTAIN THIS WORD?
	PUSHJ	P,PUTWDU##	;YES--STORE IT

; CREATION DATE
	HRRI	M,UUNATT(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXPRV(P1)	;YES
	PUSHJ	P,GETWDU##	;GET ATTRIBUTE WORD
	LDB	T4,TUYECR	;GET CREATION DATE FROM LABEL
	LDB	T2,[POINT 12,T4,35] ;KEEP ONLY LOW DATE
	DPB	T2,[POINT 12,T1,35] ;MOVE INTO EXISTING ATTRIBUTE WORD
	PUSHJ	P,PUTWDU##	;SET LOW DATE
	HRRI	M,UUNEXT(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXEXT(P1)	;YES
	PUSHJ	P,GETWDU##	;GET EXTENSION WORD
	LDB	T2,[POINT 3,T4,23] ;GET HIGH DATE FROM THE LABEL
	DPB	T2,[POINT 3,T1,20] ;MOVE INTO EXISTING EXTENSION WORD
	PUSHJ	P,PUTWDU##	;SET HIGH DATE

; EXPIRATION DATE
	LDB	T1,TUYEEX	;GET EXPIRATION DATE
	HRRI	M,UUXDED(P1)	;BUT JUST IN CASE ...
	CAIL	P2,UUXDED	;ARG BLOCK CONTAIN THIS WORD?
	PUSHJ	P,PUTWDU##	;YES--STORE IT

; PROTECTION CODE
	HRRI	M,UUNATT(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXPRV(P1)	;YES
	PUSHJ	P,GETWDU##	;GET EXISTING WORD
	LDB	T2,TUYPRT	;GET PROTECTION CODE FROM TAPE LABEL
	DPB	T2,[POINT 9,T1,8] ;MERGE INTO EXISTING WORD
	PUSHJ	P,PUTWDU##	;STORE IT

; FILE SEQUENCE NUMBER
;	LDB	T1,TUYPSN	;GET SEQUENCE NUMBER
;	HRRI	M,UUXPSN(P1)	;POINT TO SEQUENCE NUMBER IN ARG BLOCK
;	CAIL	P2,UUXPSN	;ARG BLOCK CONTAIN THIS WORD?
;	PUSHJ	P,PUTWDU##	;YES--STORE WORD

; GENERATION
;	LDB	T2,TUYGEN	;GET GENERATION

; VERSION
;	LDB	T1,TUYVER	;GET VERSION
;	HRL	T1,T2		;PUT IN ONE WORD
;	HRRI	M,UUXGVR(P1)	;POINT TO FORMS CONTROL/RECORD FORMAT WORD
;	CAIL	P2,UUXGVR	;ARG BLOCK CONTAIN THIS WORD?
;	PUSHJ	P,PUTWDU##	;YES--STORE WORD

	JRST	CPOPJ1##	;AND RETURN
; STILL UNDER FTTLAB

; INITIALIZE LABEL INFORMATION BLOCK IN THE TUB FOR ENTER
; AND LOOKUP UUOS.  RETURNS CPOPJ1 IF PROCESSING LABELED
; TAPES AND THIS TAPE IS LABELED.
TPMLIB:	PUSHJ	P,NULTST##	;CHECK FOR NUL
	  POPJ	P,		;RETURN IF THE NUL DEVICE
	SETZM	DEVFIL(F)	;CLEAR FILE NAME
	SETZM	DEVEXT(F)	;CLEAR EXTENSION
	MOVE	U,TDVUDB(F)	;POINT TO UDB FOR THIS DDB
	TLO	S,FSTOP		;SET UP
	MOVEM	S,DEVIOS(F)	; FIRST I/O
	PUSHJ	P,LBLCKM	;TAPE LABELED AND TAPE LABELER RUNNING?
	  SKIPA			;YES
	POPJ	P,		;NOTHING MORE TO DO

	LDB	T1,TUYLTP	;GET LABEL TYPE
	CAIL	T1,LT.SL	;ANSI?
	CAILE	T1,LT.IUL	;IBM?
	POPJ	P,		;NO

; HERE TO JUST RE-INITIALIZE THE LABEL INFO BLOCK
TPMLIC:	LDB	T1,TUYPSN	;SAVE CURRENT SEQUENCE NUMBER
	SETZM	TUBLIB(U)	;CLEAR FIRST WORD OF LABEL STORAGE AREA
IFE FTXMON,<
	MOVSI	T2,TUBLIB(U)	;START OF LABEL INFO BLOCK
	HRRI	T2,TUBLIB+1(U)	;MAKE A BLT POINTER
	BLT	T2,TUBLIB+TLPMAX-1(U) ;CLEAR ENTIRE BLOCK
> ;END IFE FTXMON
IFN FTXMON,<
	PUSH	P,T1		;SAVE FROM DESTRUCTION
	MOVEI	T1,TLPMAX	;LENGTH
	XMOVEI	T2,TUBLIB(U)	;STARTING ADDRESS
	XMOVEI	T3,TUBLIB+1(U)	;MAKE A BLT POINTER
	EXTEND	T1,[XBLT]	;COPY
	POP	P,T1		;RESTORE T1
> ;END IFN FTXMON
	DPB	T1,TUYPSN	;RESTORE FILE SEQUENCE NUMBER
	MOVE	T1,TUYFNM	;GET BYTE POINTER TO FILE.EXT
	MOVEM	T1,TUBPTR(U)	;STORE WORKING COPY
	TLO	S,FSTOP		;SET UP
	MOVEM	S,DEVIOS(F)	; FIRST I/O
	JRST	CPOPJ1##	;RETURN


; SAVE ACS AND SET UP POINTERS TO CALLER'S ARG BLOCK
TPMARG:	PUSHJ	P,SAVE4##	;SAVE SOME ACS
	HRRZ	P1,M		;SAVE UVA OF ARG BLOCK
	PUSHJ	P,GETWDU##	;GET FIRST WORD
	TLNN	T1,-1		;4-WORD OR EXTENDED BLOCK
	TRZA	T1,RB.BIT	;EXTENDED
	TDZA	P2,P2		;4-WORD, SO ZERO LENGTH
	MOVE	P2,T1		;ELSE COPY EXTENDED LENGTH TO A SAFE PLACE
	MOVE	T1,P1		;START ADDRESS OF ARG BLOCK
	SKIPN	T2,P2		;EXTENDED?
	MOVEI	T2,4		;4-WORD
	PUSHJ	P,ARNGE##	;RANGE CHECK
	  JRST	UADERR#		;ADDRESS CHECK
	  JFCL			;ADDRESS OK BUT ILLEGAL FOR I/O (IGNORED HERE)
	JRST	(T4)		;RETURN


; FIRST I/O
TPMFIN:	SKIPA	T1,[LR.FIN]	;FIRST INPUT
TPMFOU:	MOVEI	T1,LR.FOU	;FIRST OUTPUT
	DPB	T1,TUYRQT	;SET FOR TAPE LABELER
	MOVEI	T1,77		;GET LABEL READ FUNCTION CODE
	DPB	T1,TUYINF	;SET IT
	PUSHJ	P,LBLMSG	;GIVE PULSAR A KICK
	LDB	T1,PDVESE##	;GET EXTENDED ERROR STATUS SET BY LABELER
	JUMPN	T1,CPOPJ##	;LABELING ERROR IF NON-ZERO
	JRST	CPOPJ1##	;RETURN


; GENERATE A DEFAULT FILE NAME AND EXTENSION
TPMDFE:	LDB	T1,TUYPSN	;GET CURRENT SEQUENCE NUMBER
	MOVEI	T4,3		;EXTENSION IS THREE CHARACTERS
TPMDF1:	IDIVI	T1,12		;DIVIDE BY 10
	ADDI	T2,'0'		;MAKE SIXBIT
	LSHC	T2,-6		;SAVE CHARACTER
	SOJG	T4,TPMDF1	;LOOP
	HLLZM	T3,DEVEXT(F)	;SET EXTENSION
	MOVE	T1,['FILE  ']	;DEFAULT
	MOVEM	T1,DEVFIL(F)	; FILE NAME
	POPJ	P,		;AND RETURN


; CHARACTER TYPER FOR FILE NAME AND EXTENSION GENERATION
TPMTYO:	IDPB	T1,TUBPTR(U)	;PUT CHARACTER
	POPJ	P,		;RETURN


; ROUTINE TO TYPE A SIXBIT WORD FOR FILE.EXT PROCESSING
SIXOUT:	SKIPN	T2,T1		;COPY WORD
	POPJ	P,		;NOTHING TO DO
SIXOU1:	LSHC	T1,6		;SHIFT IN A CHARACTER
	ANDI	T1,77		;NO JUNK
	ADDI	T1,40		;CONVERT SIXBIT TO ASCII
	IDPB	T1,TUBPTR(U)	;STORE CHARACTER
	JUMPN	T2,SIXOU1	;LOOP
	POPJ	P,		;RETURN


; ROUTINE TO GET A SIXBIT WORD FOR FILE.EXT PROCESSING
SIXINP:	SETZ	T1,		;CLEAR DESTINATION
	MOVE	T2,[POINT 6,T1]	;BYTE POINTER
SIXIN1:	ILDB	T3,TUBPTR(U)	;GET CHARACTER
	CAIN	T3,"-"		;DASH?
	JRST	SIXIN2		;YES
	CAIL	T3,"0"		;CHECK
	CAILE	T3,"9"		; DIGITS
	CAIL	T3,"A"		;CHECK
	CAILE	T3,"Z"		; LETTERS
	POPJ	P,		;NO MATCH
SIXIN2:	SUBI	T3,40		;CONVERT ASCII TO SIXBIT
	TRNN	T1,77		;WORD FULL?
	IDPB	T3,T2		;NO--STORE CHARACTER
	JRST	SIXIN1		;LOOP


; ERROR HANDLING
LERFNF:	MOVEI	T4,FNFERR	;FILE NOT FOUND
	JRST	LERERR
LERWLK:	MOVEI	T4,WLKERR	;WRITE-LOCKED
	JRST	LERERR
LERACS:	MOVEI	T4,ACSERR	;ADDRESS CHECK STORING ANSWERS
	JRST	LERERR
LERLBL:	MOVEI	T4,LBLERR	;TAPE LABELING ERROR
LERERR:	HRRI	M,UUNEXT(P1)	;4-WORD
	SKIPE	P2		;EXTENDED?
	HRRI	M,UUXEXT(P1)	;YES
	PUSHJ	P,GETWDU##	;GET EXTENSION WORD
	HRR	T1,T4		;GET ERROR CODE
	PUSHJ	P,PUTWDU##	;STORE IT
	POPJ	P,		;RETURN


> ;END IFN FTTLAB FROM WAY BACK
SUBTTL MTACHR AND MTARID UUO'S
;MTACHR UUO

MTACHR::HLRE	T2,T1		;GET LH ARG FROM USER
	JUMPLE	T2,MTACHX	;JUMP IF OLD STYLE
	SUBI	T2,1		;ACCOUNT FOR WORD USED TO PASS DEVICE NAME
	CAILE	T2,TPCHMX	;CHECK RANGE
	JRST	MTACHX		;MIGHT BE NUMERIC LOGICAL NAME
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVN	P1,T2		;NEGATE LEN IN P1
	HRLZS	P1		;TO LH
	HRR	M,T1		;FIXUP M TO POINT TO USER AREA
	PUSHJ	P,GETWRD##	;GET FIRST WORD OF BLOCK
	  JRST	RTM1##		;OUT OF BOUNDS
	PUSHJ	P,MTACHS	;SCAN FOR DDB (ARG IN T1)
	  JRST	RTM1##		;NO SUCH MTA
				;RETURN DDB IN F, UDB IN U
	HRRI	P1,TUBRID	;OFFSET INTO UDB
	PUSHJ	P,TPMCPY	;COPY DATA
	  POPJ	P,		;OUT OF BOUNDS
	MOVE	T1,TUBCHR(U)	;GET CHARACTERISTICS WORD
	PJRST	STOTC1##	;STORE IN AC AND EXIT

;HERE WHEN ARG IS CHL # OR DEVICE NAME
MTACHX:	PUSHJ	P,MTACHS	;LOOK FOR DDB (ARG IN T1)
	  PJRST	RTM1##		;NO SUCH MTA
	PJRST	STOTC1##	;STORE T1
MTARID::PUSHJ	P,PRVJ##	;NEED PRIVS
	PUSHJ	P,MTAIDD	;FIND DDB
	  PJRST	RTM1##		;NO PRIVS OR NO DDB
	MOVE	T1,DEVMOD(F)	;MAKE SURE ITS AN MTA
	MOVE	U,TDVUDB(F)	;UDB ADDRESS
	TLNN	T1,DVTTY	;...
	TLNN	T1,DVMTA	;....
	JRST	RTM1##		;ERROR RETURN
	PUSHJ	P,GETWD1##	;GET REEL ID
	MOVEM	T1,TUBRID(U)	;STORE IN UDB
	PJRST	CPOPJ1##	;GIVE SKIP RETURN
;ROUTINE TO FIND A DDB FOR THE MTAID. UUO.
;CALL:	MOVE	T1,ARG
;	PUSHJ	P,MTAIDD
;	  RETURN HERE IF NO SUCH DEVICE
;	RETURN HERE WITH F=DDB ADDRESS

MTAIDD:	JUMPL	T1,MTAID1	;IF ARG IS AN
	CAIG	T1,HIGHXC##	;  OPEN CHANNEL,
	PJRST	DVCNSG##	;  LET DVCNSG FIND IT
MTAID1:	PUSHJ	P,DEVSRC##	;LOOK FOR PHYSICAL OR LOGICAL MATCH
	  CAIA			;NONE FOUND
	JRST	CPOPJ1##	;FOUND IT
	TRNE	T1,-1		;LOSE IF GENERIC MTA
	TRNE	T1,7777		;OR IF NOT MTAU
	POPJ	P,
	MOVEI	T3,0		;NO RESTRICTIONS ON DVSTAS
	PUSHJ	P,DVASRC##	;LOOK FOR MTAU
	  SKIPGE	T4		;IF FOUND BUT ASSIGNED TO SOMEONE ELSE,
	JRST	CPOPJ1##	;RETURN SUCCESS
	POPJ	P,		;NOT FOUND
;ROUTINE TO SCAN FOR MTA DDB AND SET UP F AND U
;CALLED WITH T1 := SOMETHING THAT DVCNSG LIKES
;ALSO UPDATE TUBCHR AND RETURN INFO IN T1

MTACHS:	PUSHJ	P,DVCNSG##	;LOOK FOR DDB
	  POPJ	P,		;ERROR RETURN
	MOVSI	T1,DVMTA	;CHECK FOR MTA DDB
	TDNN	T1,DEVMOD(F)	;...
	POPJ	P,		;NOPE - ERROR
	MOVE	U,TDVUDB(F)	;UDB ADDRESS
	PUSHJ	P,GETDEN	;GET CURRENT DENSITY
	LDB	T2,TDYDEN	;UNLESS ACTUAL KNOWN
	SKIPE	T2		;IS IT?
	MOVE	T1,T2		;YES, GIVE THEN THE REAL THING
	DPB	T1,[POINT 3,TUBCHR(U),35]
	MOVEI	T1,1B31+1B32	;BITS FOR TUBCHR
	MOVEI	T2,TUC7TK##	;CHECK 7 TRACK
	TDNN	T2,TUBCNF(U)	;IS IT?
	TRZ	T1,1B31		;NO - CLEAR BIT
	MOVSI	T2,TUSWTL##	;CHECK WRITE LOCKED
	TDNN	T2,TUBSTS(U)	;IS IT?
	TRZ	T1,1B32		;NO - CLEAR BIT
	IORM	T1,TUBCHR(U)	;SET APPROPRIATE BITS
	TRC	T1,1B31+1B32	;COMPLEMENT BITS
	ANDCAB	T1,TUBCHR(U)	;AND CLEAR OTHERS
	JRST	CPOPJ1##	;GIVE GOOD RETURN
SUBTTL	TAPOP. UUO
;TAPOP. UUO OR CALLI 154
;UUO TO PERFORM MISCELLANEOUS FUNCTIONS FOR A SPECIFIC TAPE UNIT
;CALL:	MOVE	AC,[+N,,ADR]
;	CALLI	AC,154
;	  ERROR RETURN
;	NORMAL RETURN
UTAPOP::PUSHJ	P,SAVE4##	;SAVE AC'S
	MOVE	P4,T1		;SAVE USER ARG IN P4
	HRR	M,T1		;ADDRS OF BLOCK
	HLRE	T2,T1		;GET LENGTH
	CAIL	T2,2		;VALID LENGTH?
	PUSHJ	P,GETWRD##	;YES - GET ARG (FCN CODE)
	  PJRST	ECOD4##		; NO - ERROR
	JUMPLE	T1,RTZER##	;RETURN 0 IF BAD FCN
	HRR	P1,T1		;SAVE FCN IN P1
	PUSHJ	P,GETWR1##	;GET NEXT ARG (DEVICE SPEC)
	  PJRST	ECOD4##
	PUSHJ	P,DVCNSG##	;SEARCH FOR IT
	  PJRST	ECOD2##		;NO SUCH
	CAIN	F,DSKDDB##	;IS IT NUL?
	CAME	T1,[SIXBIT/NUL/]
	SKIPA	T1,DEVMOD(F)	;CHECK ON TAPE UNIT
	JRST	CPOPJ1##	;YES, GOOD RETURN
	TLNN	T1,DVMTA	;...
	PJRST	ECOD2##		;NOPE
	TLNE	T1,DVTTY	;CHECK IF ALSO TTY
	PJRST	CPOPJ1##	;NUL WINS
	MOVE	S,DEVIOS(F)	;SET UP STATUS
	TRNN	P1,1000		;IF NOT A READ FNCN
	PUSHJ	P,WAIT##	;WAIT FOR ALL IO TO COMPLETE
	MOVE	U,TDVUDB(F)	;UDB ADDRESS
	HRRZ	T1,P1		;GET FCN CODE
	TRNE	T1,3000		;READ/SET CODE?
	JRST	TAPRSQ		;YES - GO HANDLE
	CAIG	T1,TAPLN0	;NO - CHECK LEGAL
	SKIPN	P3,TAPTB0-1(T1)	;EXISTS?
	PJRST	RTZER##		;ILLEGAL FCN CODE
	TLNN	P3,(TAP.NP)	;NEED POKE PRIVS?
	JRST	CHKRED		;NO - TRY OTHERS
	MOVSI	T1,JP.POK	;YES - CHECK HIS PRIVS
	PUSHJ	P,PRVBIT##	;...
	  PJRST	0(P3)		;OK - DISPATCH
	JRST	ECOD1##		;NO - GIVE ERROR RETURN

CHKRED:	TLNN	P3,(TAP.RP)	;NEED READ PRIVS?
	JRST	CHKWRT		;NO - PROCEED
	PUSHJ	P,TREDOK	;YES - CHECK THEM
	  PJRST	ECOD1##		;NOT ENOUGH PRIVS
CHKWRT:	TLNN	P3,(TAP.WP)	;NEED WRITE PRIVS?
	PJRST	0(P3)		;NO - JUST CALL ROUTINE
	PUSHJ	P,TWRTOK	;YES - CHECK THEM
	  PJRST	ECOD1##		;NOT ENOUGH
	PJRST	0(P3)		;DISPATCH
;HERE IF FCN CODE IS IN THE RANGE 2000-3777

TAPRSQ:	ANDI	P1,777		;MASK FCN CODE
	CAIL	T1,3000		;POSSIBLE CUSTOMER-DEFINED FUNCTION?
	JRST	TAPCUS		;MAYBE, GO SEE
	TRZE	T1,1000		;READ CODE?
	JRST	TAPRED		;YES - TRY IT
	CAIGE	T1,2000+TAPLN1	;CHECK RANGE
	SKIPN	P3,TAPTB1(P1)	;  AND VALIDITY
	PJRST	RTZER##		;INVALID
	HLRZ	T2,P4		;CHECK ARG LIST
	CAIL	T2,3		;AT LEAST 3
	PUSHJ 	P,GETWR1##	;GET NEXT ARG
	  PJRST	ECOD4##		;ADDRS ERROR
	MOVE	P2,T1		;SAVE IT IN P2
	PUSHJ	P,TWRTOK	;CHECK WRITE PRIVS
	  PJRST	ECOD1##		;ERROR RETURN
	LDB	T1,TAPSYR	;LEGAL - RANGE CHK REQ'D?
	JUMPE	T1,TAPST1	;JUMP IF NO
	TLNE	P3,(TAP.FC)	;SETTING FRAME-COUNT?
	JUMPE	P2,TAPST1	;YES, 0 IS LEGAL
	MOVE	T2,TAPSRT-1(T1)	;MAX VALUE IN RH
	HLRZ	T3,T2		; MIN VALUE IN LH
	CAIG	P2,(T2)		;.GT. MAX VALUE?
	CAIGE	P2,(T3)		; OR .LT. MIN VALUE?
	PJRST	ECOD3##		;ARG OUT OF RANGE
	TLNN	P3,(TAP.FC)	;SETTING FRAME COUNTER?
	JRST	TAPST1
	LDB	T2,TDYMOD	;YES, DO WE KNOW MODE?
	JUMPE	T2,TAPST1
	MOVE	T1,P2		;YES, CONVERT TO NUMBER OF WORDS
	IDIV	T1,TMODTB##(T2)
	SKIPE	T2
	ADDI	T1,1
	ADDI	T1,1		;ALLOW FOR OVERHEAD WORD
	DPB	T1,PBUFSZ##	;AND SAVE BUFFER SIZE
TAPST1:	TLNE	P3,(TAP.SA!TAP.FC)	;SET ALLOWED?
	JRST	TAPST2		;YES - DO IT
	TLNN	P3,(TAP.PS)	;NO - NEED PRIVS
	PJRST	ECOD5##		;NOHOW!
	MOVSI	T1,JP.POK	;NEED PRIVS TO SET
	PUSHJ	P,PRVBIT##	;GO CHECK
	  SKIPA			;OK RETURN
	PJRST	ECOD1##		;NOPE
TAPST2:	TLNE	P3,(TAP.DN)	;SETTING DENSITY?
	JRST	TAPDEN		;YES, DO IT
IFN	FTTLAB,<
	TLNE	P3,(TAP.LT)	;SETTING LABEL TYPE?
	JRST	TAPLBT		;YES, DO IT
>				;END FTTLAB
	TLNE	P3,(TAP.SP)
	JRST	0(P3)
	DPB	P2,0(P3)	;SET BIT (BYTE)
	JRST	CPOPJ1##	;DONE
TAPDEN:	SKIPN	T1,P2		;DEFAULT SPECIFIED?
	PUSHJ	P,GETDN1	;YES, SET IT UP
	MOVEI	T3,TUCD20##	;GET LOWEST DENSITY
	LSH	T3,-1(T1)	;CONVERT DENSITY TO BIT POSITION
	TDNN	T3,TUBCNF(U)	;SETTING VALID DENSITY?
	JRST	ECOD15##	;NO, ERROR
	DPB	T1,0(P3)	;SET THE DENSITY
IFN FTTLAB,<
	TLZ	T1,(ST.FAC)	;REQUEST DENSITY CHANGE
	PUSHJ	P,SETODN	; THEN SET OTHER DDB
> ;END IFN FTTLAB
	JRST	CPOPJ1##	;RETURN OK

;SET LABEL TYPE
IFN FTTLAB,<
TAPLBT:	DPB	P2,TUYLTP	;SET THE LABEL TYPE
	MOVE	T1,UDBDDB(U)	;GET THE REAL DDB ADDRESS
	MOVSI	T2,DVDIR	;GET DIRECTORY DEVICE BIT
	ANDCAM	T2,DEVMOD(T1)	;ASSUME NOT LABELED
	CAIL	P2,LT.SL	;SOME FLAVOR OF
	CAILE	P2,LT.IUL	; ANSI OR IBM LABELS?
	SKIPA			;NO
	IORM	T2,DEVMOD(T1)	;LITE DIRECTORY BIT FOR USER PROGRAMS
	JUMPN	P2,CPOPJ1##	;NOT BLP, RETURN
	DPB	P2,PDVESE##	;CLEAR LAST LABELING ERROR
	TLZ	S,LBLNED+LBLWAT+LBLSTP+LBLEOF+FSTOP
	MOVEM	S,DEVIOS(F)	;CLEAR LABEL BITS AND SAVE
	JRST	CPOPJ1##	;RETURN
>				;END IFN FTTLAB
;HERE TO HANDLE READ FUNCTIONS

TAPRED:	CAIGE	T1,TAPLN1	;CHECK VALID ARG
	SKIPN	TAPTB1(P1)	; AND EXISTANCE
	PJRST	RTZER##		;RETURN ZERO
	PUSHJ	P,TREDOK	;CHECK PRIVS
	  PJRST	ECOD1##		;NOPE
	MOVE	P3,TAPTB1(P1)	;GET TABLE ENTRY
	TLNE	P3,(TAP.DN)	;DENSITY?
	JRST	TAPRD1		;YES - SPECIAL
	TLNE	P3,(TAP.SP)	;SPECIAL ROUTINE?
	JRST	0(P3)		;YES - CALL IT
	LDB	T1,0(P3)	;NO - GET VALUE
	TLNE	P3,(TAP.MD)	;MODE READ?
	PUSHJ	P,GTMODE	;YES, FIND OUT WHAT WE HAVE
	PJRST	STOTC1##	;STORE VALUE & SKIP RETURN

;HERE TO HANDLE DENSITY READ

TAPRD1:	PUSHJ	P,GETDEN	;GET DENSITY ARG
	LDB	T2,TDYDEN	;UNLESS ACTUAL KNOWN
	SKIPE	T2		;IS IT?
	MOVE	T1,T2		;YES, GIVE THEN THE REAL THING
	PJRST	STOTC1##	;STORE ETC.

;ROUTINES TO CHECK PRIVS FOR READ OR WRITE

TREDOK:	PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVSI	P1,PVSPYM!PVSPYA ;SPY PRIVS
	JRST	CKMTA

TWRTOK:	PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVSI	P1,JP.POK	;POKE PRIVS
CKMTA:	LDB	P2,PJOBN##	;GET OWNERS JOB #
	CAMN	P2,J		;IS IT US?
	JRST	CPOPJ1##	;YES - DO WHAT U WANT
	EXCH	P1,T1		;NO - FURTHER CHECKING REQ'D
	PUSHJ	P,PRVBIT##
	  AOS	(P)		;OK - SET FOR SKIP
	MOVE	T1,P1		;RESTORE T1
	POPJ	P,		;RETURN

;HERE FOR POSSIBLE CUSTOMER-DEFINED TAPOP. UUO FUNCTION

TAPCUS:	CAIGE	T1,3000+TAPLC0	;IN RANGE?
	SKIPN	TAPTC0(P1)	;AND EXISTS?
	PJRST	RTZER##		;NO, RETURN ZERO
	PUSHJ	P,TREDOK	;CHECK PRIVILEGES
	  JRST	ECOD1##		;NO PRIVILEGES
	MOVE	P3,TAPTC0(P1)	;GET TABLE ENTRY
	TLNE	P3,(TAP.SP)	;SPECIAL ROUTINE?
	PJRST	(P3)		;YES, DISPATCH TO IT
	LDB	T1,(P3)		;NO, GET VALUE
	PJRST	STOTC1##	;STORE IT AND RETURN
;TABLES FOR TAPOP. UUO

;CONTENTS OF TAPTB0 ARE AS FOLLOWS
;BITS 0-5 ARE CORRESPONDING MTAPE CODE IF ANY
;BITS 6-12 ARE FLAGS FOR DETERMINING VALIDITY
;RH IS ROUTINE ADDRS

TAP.RP==1B6	;NEED READ PRIVS FOR THIS FCN
TAP.WP==1B7	;NEED WRITE PRIVS FOR THIS FCN
TAP.NP==1B8	;NEED JACCT / [1,2] PRIVS

DEFINE TMAC(MTCOD,BITS,ROU),<
	EXP	<MTCOD>B5+BITS+ROU
>

TAPTB0:	TMAC	(MT.WAT,TAP.RP,TAPOPM)	;1 - WAIT FOR UNIT AVAIL
	TMAC	(MT.REW,TAP.WP,TAPOPM)	;2 - REWIND
	TMAC	(MT.UNL,TAP.WP,TAPOPM)	;3 - REWIND & UNLOAD
	TMAC	(MT.FSR,TAP.WP,TAPOPM)	;4 - SKIP RECORD
	TMAC	(MT.FSF,TAP.WP,TAPOPM)	;5 - SKIP FILE
	TMAC	(MT.SET,TAP.WP,TAPOPM)	;6 - SKIP TO LEOT
	TMAC	(MT.BSR,TAP.WP,TAPOPM)	;7 - BACKSPACE RECORD
	TMAC	(MT.BSF,TAP.WP,TAPOPM)	;10 - BACKSPACE FILE
	TMAC	(MT.WTM,TAP.WP,TAPOPM)	;11 - WRITE TAPE MARK
	TMAC	(MT.WLG,TAP.WP,TAPOPM)	;12 - WRITE LONG GAP
	TMAC	(0,TAP.WP,TPMDSE)	;13 - DATA SECURITY ERASE
	TMAC	(0,TAP.WP,TPMWET)	;14 - WRITE LEOT
IFN FTTLAB,<
	TMAC	(0,TAP.NP,TPMLBG)	;15 - LABEL GET
	TMAC	(0,TAP.NP,TPMLBR)	;16 - LABEL RELEASE
	TMAC	(0,TAP.NP,TPMLSU)	;17 - SWAP UNITS
	TMAC	(0,TAP.NP,TPMLDD)	;20 - DESTROY LABEL DDB
	TMAC	(0,TAP.WP,TPMFEV)	;21 - FORCE EOV
	TMAC	(0,TAP.WP,TPMURQ)	;22 - USER REQUEST
>	 ;END IFN FTTLAB
IFE FTTLAB,<				;;; DUMMIES
	0				;15
	0				;16
	0				;17
	0				;20
	0				;21
	0				;22
> ;END IFE FTTLAB
	TMAC	(0,TAP.NP,TPMSMM)	;23 - SET MAINT MODE
	TMAC	(0,TAP.NP,TPMCMM)	;24 - CLEAR MAINT MODE
	TMAC	(0,TAP.NP,TPMCEC)	;25 - CLEAR ERROR COUNTERS

IFN FTPATT,<EXP	CPOPJ##>		;ROOM FOR PATCHING
TAPLN0==.-TAPTB0

;CONTENTS OF TAPTB1 ARE AS FOLLOWS
;BITS 0-5 ARE INDEX INTO RANGE TABEL IF ANY
;BITS 6-12 ARE FLAGS FOR DETERMINING VALIDITY
;RH IS ADDRS OF BYTE PNTR

TAP.DN==1B6		;SPECIAL DENSITY ACTION
TAP.SA==1B7		;SET ALLOWED
TAP.PS==1B8		;PRIV SET ONLY
TAP.SP==1B9		;SPECIAL ACTION
TAP.FC==1B10		;SET FRAME COUNT
TAP.MD==1B11		;MODE (ASCII, CORE-DUMP, ...)
TAP.LT==1B13		;SET LABEL TYPE
TAPTB1:	TMAC	(0,0,<[POINT 36,TUBFES(U),35]>)	;1000 - FINAL ERROR DISPOSITION
	TMAC	(1,TAP.DN+TAP.SA,TDYDN1)	;1001 - DENSITY
	TMAC	(0,0,TUYKTP)	;1002 - KONTROLLER TYPE
	TMAC	(0,TAP.SA,<[POINT 1,TDVSTS(F),0]>)	;1003 - READ BACKWARDS

	TMAC	(0,TAP.SA,<[POINT 1,TDVSTS(F),1]>)	;1004 - LOW THRESHOLD
	TMAC	(0,TAP.SA,<[POINT 1,DEVIOS(F),^L<IOPAR>]>)	;1005 - EVEN PARITY
	TMAC	(2,TAP.SA!TAP.SP,TAPBKS)	;1006 - BLOCKSIZE
	TMAC	(3,TAP.SA!TAP.MD,TDYMOD)	;1007 - MODE
	TMAC	(0,TAP.PS,<[POINT 1,TUBCNF(U),18]>)	;1010 - TRACK INFO
	TMAC	(0,0,<[POINT 1,TUBSTS(U),2]>)	;1011 - WRITE LOCK
	TMAC	(0,0,<[POINT 36,TUBCCR(U),35]>)	;1012 - CHAR CNT
	TMAC	(0,TAP.PS,<[POINT 36,TUBRID(U),35]>)	;1013 - REELID
	TMAC	(0,0,PMTCRC)	;1014 - CRC
	TMAC	(0,0,<[POINT 18,TUBSTS(U),17]>)	;1015 - UNIT STATUS
	TMAC	(0,TAP.SP,TAPSTS)	;1016 - STATISTICS
	TMAC	(0,0,<[POINT 36,TUBIEP(U),35]>)	;1017 - INITIAL ERROR POINTER
	TMAC	(0,0,<[POINT 36,TUBFEP(U),35]>)	;1020 - FINAL ERROR POINTER
	TMAC	(0,TAP.SP,TAPIES)	;1021 - INITIAL ERROR STATS
	TMAC	(0,TAP.SP,TAPFES)	;1022 - FINAL ERROR STATS
	TMAC	(0,0,<[POINT 36,TUBTRY(U),35]>)	;1023 - # RETRIES
IFN FTTLAB,<
	TMAC	(4,TAP.PS+TAP.LT,TUYLTP) ;1024 - READ/SET LABEL TYPE
	TMAC	(4,TAP.PS+TAP.LT,TUYLTP) ;1025 - READ/SET LABEL TYPE
	TMAC	(0,0,PDVESE)	;1026 - LABEL TERMINATION CODE
> ;END IFN FTTLAB
IFE FTTLAB,<				;;; DUMMIES
	0				;1024
	0				;1025
	0				;1026
> ;END IFE FTTLAB
	TMAC	(0,TAP.PS,<[POINT 1,TUBCNF(U),20]>)	;1027 - DIAG MODE SET
	TMAC	(0,TAP.PS,<[POINT 1,TUBCNF(U),21]>)	;1030 - FORCE SENSE
	TMAC	(5,TAP.FC,PBUFRM)	;1031 : MAX FRAME COUNT
	TMAC	(0,0,<[POINT 5,TUBCNF(U),27]>)	;1032 - DENSITY CAPABILITIES

IFN FTTLAB,<
	TMAC	(0,TAP.SP!TAP.SA,TAPRLP)	;1033 - READ LABEL PARAMETERS
> ;END IFN FTTLAB
IFE FTTLAB,<
	0			;1033 - DUMMY
> ;END IFE FTTLAB
TAPLN1==.-TAPTB1
;RANGE TABLE FOR TAPOP UUO

TAPSRT:	0,,5			;1 - DENSITY
	<NOISE##/4>,,377777	;2 - BLOCKSIZE
	0,,5			;3 - MODE
IFN FTTLAB,< 0,,LT.MAX		;4 - LABEL TYPE>
IFE FTTLAB,< 0>

NOISE##,,<^D4095*6>-1		;5 - MAX FRAME-COUNT

TAPSYR:	POINT	6,TAPTB1(P1),5	;POINTER TO RANGE INDEX
TAPMTP:	POINT	6,TAPTB0-1(P1),5 ;POINTER TO MTAPE EQUIVALENT

;CONTENTS OF TAPTC0 ARE AS FOLLOWS
;BITS 0-5 ARE INDEX INTO RANGE TABLE (IF ANY)
;BITS 6-12 ARE FLAGS FOR DETERMINING VALIDITY
;BITS 18-35 IS ADDRESS OF BYTE POINTER OR SPECIAL ROUTINE

TAPTC0:				;CUSTOMER FUNCTIONS GO HERE
TAPLC0==.-TAPTC0		;LENGTH OF CUSTOMER-DEFINED TABLE
;ROUTINE TO LINK TAPOP. FCNS TO MTAPE FCNS

TAPOPM:	PUSHJ	P,PIOSET	;SET UP ACS, UDB, ETC.
	JUMPE	J,ECOD6##	;ERROR IN NO OWNER
	LDB	T1,TAPMTP	;GET MTAPE FCN CODE
	HRR	M,T1		;MAKE M LOOK LIKE IN MTAPE
	PUSH	P,T1		;SAVE MTAPE FUNCTION CODE
	PUSHJ	P,MTAP0		;ISSUE MTAPE COMMAND
	POP	P,T1		;RESTORE FUNCTION CODE
	CAIE	T1,MT.WTM	;WRITE TAPE MARK OR
	CAIN	T1,MT.WLG	;LONG GAP?
	SKIPA
	PJRST	CPOPJ1##	;NO, SKIP RETURN
	MOVEI	P2,RB.FYB	;YES, MAKE YELLOW BALL IORB
	PUSHJ	P,GENIOR	;SO WE KNOW WHEN THE WRITE IS DONE
	  JRST	TAPOP1		;CAN'T QUEUE, JUST TEST
	MOVEM	T1,TDVIOR(F)
	XMOVEI	T2,TPMNOP	;HACK LOCATION
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWAT
	PUSHJ	P,TAPRQT##	;PLACE AT END OF QUEUE
	PUSHJ	P,KONWAT	;WAIT FOR CONTROLLER
	PUSHJ	P,TPMFLX	;FLUSH THIS REQUEST
TAPOP1:	MOVE	S,DEVIOS(F)	;SET UP S
	TRNE	S,IOIMPM	;TO CHECK FOR WRITE LOCK
	PJRST	ECOD16##	;CAUSE ERROR RETURN
	PJRST	CPOPJ1##	;ALL OK

;SPECIAL ROUTINE FOR BLOCKSIZE
TAPBKS:	HRR	M,P4		;GET FUNCTION
	PUSHJ	P,GETWRD##	;GET USER'S FUNCTION
	  JRST	ECOD4		;ADDRESS ERROR
	TRNE	T1,2000		;READ OR SET?
	JRST	TAPSBS		;SET
	LDB	T1,PBUFSZ##	;GET IT
	JRST	STOTC1		;STORE AND GOOD RETURN

;HERE TO SET BLOCKSIZE
TAPSBS:	LDB	T1,TUYKTP##	;GET KONTROLLER TYPE
	CAILE	T1,K.MAX	;DO WE KNOW ABOUT IT?
	JRST	ECOD3##		;NO--CALL IT OUT OF RANGE
	MOVE	T2,UDBKDB(U)	;GET KDB ADDRESS
	MOVE	T2,KDBDSP(T2)	;AND IT'S DISPATCH TABLE
	CAMLE	P2,TPKBSZ(T2)	;OK FOR THIS KONTROLLER TYPE?
	JRST	ECOD3##		;NO, OUT OF RANGE ERROR
	DPB	P2,PBUFSZ##	;DO IT
	JRST	CPOPJ1##	;AND GOOD RETURN

;SPECIAL ROUTINE FOR STATISTICS (1016)
;LH(P4) := LEN OF ARG BLOCK , RH(M) := LOC OF LAST ARG

TAPSTS:	HLRZ	T2,P4		;GET LENGTH
	SUBI	T2,2		;CORRECT FOR ARGS
	JUMPLE	T2,ECOD4##	;NOT ENOUGH ARGS
	CAILE	T2,TPCHMX	;COMPARE AGAINST MAX
	MOVEI	T2,TPCHMX	;OUT OF RANGE - USE MAX
	MOVN	P1,T2		;NEGATE LENGTH
	HRLZS	P1		;MOVE TO LH
	HRRI	P1,TUBRID	;BASE OFFSET TO STATISTICS

TPMCPY:	HRRZ	T1,P1		;GET UDB OFFSET
	ADD	T1,U		;RELOCATE
	MOVE	T1,(T1)		;FETCH WORD
	PUSHJ	P,PUTWR1##	;STORE IN USER AREA
	  JRST	RTM1##		;OUT OF BOUNDS
	AOBJN	P1,TPMCPY	;CONTINUE TILL DONE
	PJRST	CPOPJ1##	;THEN GIVE SKIP RETURN

;SPECIAL ROUTINE FOR ERROR INFO (1021/1022)

TAPIES:	SKIPA	P1,TUBIEP(U)	;GET INITIAL ERROR PNTR
TAPFES:	MOVE	P1,TUBFEP(U)	;GET FINAL ERROR PNTR
	HLRZ	T2,P4		;GET USER LEN
	MOVNI	T2,-2(T2)	;NEGATE AND ADJUST FOR ARGS
	JUMPGE	T2,ECOD4##	;NOT ENOUGH ARGS
	HLRE	T3,P1		; -LEN OF ERROR BLOCK
	CAMLE	T2,T3		;CHECK VALIDITY
	HRL	P1,T2		;YES - USE USERS ARG
	PJRST	TPMCPY		;GO COPY DATA
;ROUTINE TO HANDLE DATA SECURITY ERASE

TPMDSE:	PUSHJ	P,PIOSET	;SET ACS ETC.
IFN FTTLAB,<
	MOVEI	T1,40(P1)	;GENERATE SPECIAL CODE
	PUSHJ	P,LBLSLP	;WAIT FOR LBL PCS TO FINISH
	PUSHJ	P,LBLPOS	;CHECK FOR LBL PCS
	  PJRST	CPOPJ1##	;ALL DONE - RETURN
> ;END IFN FTTLAB
	JUMPE	J,ECOD6##	;ERROR IF NO OWNER
	MOVEI	P2,RB.FSE	;FCN TO P2
	MOVEI	P3,TPMDE0	;USE WRITE WITH LONG TIMEOUT
	TRZ	S,IOERRS
	PUSHJ	P,MTAP2		;START OP
	PUSHJ	P,TPSKPW	;WAIT TILL DONE
	TRNE	S,IOERRS
	PJRST	ECOD0##
	MOVEI	P2,RB.FLG	;NOW DO 14 ERASE GAP OPS
	MOVEI	P3,TPMDE1
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	MTAP2		;START OP

;HERE TO PERFORM WRITE OP WITH LONG TIMEOUT

TPMDE0:	XMOVEI	T1,WRTDUN	;WHERE TO GO ON COMPLETION
	MOVEM	T1,IRBIVA(P1)	;SAVE IT
	PJRST	TPSTRT		;GO START THE OPERATION

;HERE ON KONTROLLER AVAILABLE

TPMDE1:	MOVEI	T1,^D14		;SET COUNT
	HRRM	T1,@IRBACC(P1)	;INTO IORB
	PJRST	TPMWR1		;START I/O

;ROUTINE TO WRITE LEOT (TM,TM,BSB)

TPMWET:	PUSHJ	P,PIOSET	;SET ACS ETC.
IFN FTTLAB,<
	MOVEI	T1,40(P1)	;SPECIAL CODE
	PUSHJ	P,LBLSLP	;WAIT FOR LBL PCS TO FINISH
	PUSHJ	P,LBLPOS	;CHECK LABELER
	  PJRST	CPOPJ1##	;THROUGH - EXIT
> ;END IFN FTTLAB
	JUMPE	J,ECOD6##	;ERROR IF NO OWNER
	PUSHJ	P,SAVE3##
	MOVE	P3,S
	ANDI	P3,IOERRS
	PUSHJ	P,TPMCL1	;JOIN CLOSE CODE
	MOVE	S,DEVIOS(F)	;SET UP S
	TRNE	S,IOIMPM	;WRITE LOCK?
	PJRST	ECOD16##	;YES, CAUSE ERROR RETURN
	PJRST	CPOPJ1##	;NO, ALL OK
IFN FTTLAB,<

;TAPE LABEL GET -- SET UP DDB IF NONE AND CONTINUE UNIT

TPMLBG:	MOVE	T1,DEVNAM(F)	;GET PHYS NAME
	MOVEI	T2,'''L'	;CONVERT TO SECONDARY NAME
	DPB	T2,[POINT 12,T1,11]
	PUSH	P,T1		;SAVE IT
	PUSH	P,F		;SAVE DDB PNTR
	PUSHJ	P,DEVPHY##	;SEARCH FOR EXISTANCE
	  JRST	TPLBGA		;NOT FOUND
	POP	P,P1		;FOUND AIM P1 AT REAL DDB
	POP	P,(P)		;AND THROW AWAY THE NAME
	LDB	T1,PJOBN##	;GET  OWNER JOB#
	CAME	T1,J		;DO WE OWN IT?
	JUMPN	T1,ECOD14##	;NO, ERROR IF ANOTHER
	JRST	TPLBG1		;OURS OR NO OWNER

TPLBGA:	MOVEI	T2,TDVLEN	;SIZE OF DDB
	PUSHJ	P,GETWDS##	;ALLOCATE STORAGE
	  JRST	[MOVEI T1,1	;FAILED
IFN FTPSCD,<
		AOS %MTASL##	;COUNT MTA GENERATED SLEEP
>;END IFN FTPSCD
		 PUSHJ P,TSLEE2 ;WAIT FOR SOME TO APPEAR
		 JRST TPLBGA]	;TRY AGAIN
	POP	P,P1		;GET OLD DDB PNTR INTO P1
	MOVE	F,T1		;SET UP NEW PNTR
	HRLI	T1,TDVDDB	;LOC OF PROTOTYPE
	BLT	T1,TDVLEN-1(F)	;MOVE INTO PLACE
	POP	P,DEVNAM(F)	;GIVE IT A NAME
	MOVEI	T1,ASSCON	;MAKE LABEL DDB ASSIGNED BY CONSOLE
	IORM	T1,DEVMOD(F)
	MOVSI	T1,DVLNG	;CLEAR LONG DISPATCH FLAG (WHY?)
	ANDCAM	T1,DEVMOD(F)
	MOVSI	T1,DEPRAS	;SET RESTRICTED ASSIGNMENT FLAG
	IORM	T1,DEVTYP(F)
	MOVEI	T1,DEPEVM	;NOW GET THIS CORRECT
	TDNE	T1,DEVTYP(P1)	;IF OLD DDB NEEDED EVM
	IORM	T1,DEVTYP(F)	;  THEN THIS ONE DOES ALSO
	MOVE	T1,DEVCPU(P1)	;COPY OLD INTERLOCK WORD
	MOVEM	T1,DEVCPU(F)	;TO NEW DDB
	HLRZ	T1,DEVSER(P1)	;FIX UP LINKS OF
	HRLM	T1,DEVSER(F)	;  DDB CHAIN TO
	HRLM	F,DEVSER(P1)	;  INCLUDE THIS NEW ONE
TPLBG1:	DPB	J,PJOBN##	;ASSIGN TO THIS JOB
	MOVE	T1,TDVUDB(P1)	;UDB POINTER
	MOVEM	T1,TDVUDB(F)	;INTO NEW DDB
	MOVE	T1,TDVSTS(P1)	;GET PAR/DEN/MODE, USERS SET
	MOVEM	T1,TDVSTS(F)	; AND STORE IN LABEL DDB
	MOVEM	F,TUBDDL(U)	;LINK LABEL DDB TO UDB
	PUSHJ	P,TPWAIT	;WAIT OUR TURN FOR THIS TAPE
	MOVE	T1,DEVNAM(F)	;GET NAME OF NEW DDB
	PUSHJ	P,STOTAC##	;STORE FOR USER
	AOS	0(P)		;SET FOR SKIP RETURN
	PJRST	TAPCNT##	;ALLOW UNIT TO BE SCHEDULED AGAIN

	;;; STILL IN FTTLAB CONDITIONAL
;TAPE LABEL RELEASE -- TRY TO GET JOB RUNNING AGAIN

TPMLBR:	SKIPE	P1,TUBDDL(U)	;LABEL DDB ADDRESS
	SETZM	TUBDDL(U)	;CLEAR SECONDARY DDB
	AOS	0(P)		;SET FOR SKIP RETURN
	HLRZ	T1,P4		;USERS LENGTH
	CAIL	T1,3		;CHECK FOR POSSIBLE 3RD ARG
	PUSHJ	P,GETWR1##	;FETCH IT
	  MOVEI	T1,0		;ASSUME ZERO
	CAILE	T1,IOMAX%	;RANGE CHECK
	MOVEI	T1,0		;ASSUME IT SHOULD BE ZERO
	DPB	T1,PDVESE##
	TLZN	S,LBLWAT	;CHECK IF WAITING
	JRST	TPLBRU		;NO - UNWIND REQUESTS
	MOVEM	S,DEVIOS(F)
	LDB	T1,PJOBN##	;GET JOB NUMBER
	JUMPE	T1,TPLBRU	;IF NONE - EXIT
	PUSH	P,J		;SAVE RUNNING JOB #
	PUSHJ	P,SETACS	;LINK UP DDB,UDB
	POP	P,J		;GET BACK UUO JOB #
	EXCH	T1,J		;SAVE J - SET OTHER JOB #
	LDB	T2,PJBSTS##	;GET JOB STATUS
	EXCH	T1,J		;RESTORE J
	CAIN	T2,STOPQ##	;IS JOB STOPPED?
	PJRST	TAPHLD##	;YES - JUST SET NS
	PJRST	EWAKE##		;ELSE WAKE HIM UP

;HERE TO JUST QUIETLY DE-Q OLD INFO

TPLBRU:	MOVSI	T1,TUBQUE(U)	;SET Q TO NULL STATE
	EXCH	T1,TUBQUE(U)	;AND FETCH OLD INFO
	TLZ	T1,-1		;CLEAR LH
	PJRST	TPMDQ		;SLUURRRRP!
;ROUTINE TO SWITCH TWO UNITS FOR TAPE LABELING
;CALL - F := CURRENT DDB

TPMLSU:	MOVE	T1,DEVNAM(F)	;GET CURRENT DEVICE'S NAME
	PUSHJ	P,DEVPHY##	;LOCATE IT WITH A VALID PREDECESSOR
	  JRST	ECOD2##		;PUNT IF IT WENT AWAY
	MOVE	P2,T2		;SAVE PREDECESSOR
	TLZ	F,-1-MXSECN	;MAKE COMPARISONS WORK
	PUSH	P,F		;SAVE TAPE LABELER'S DDB
	MOVE	T1,TDVUDB(F)	;POINT TO THE TUB
	MOVE	F,UDBDDB(T1)	;AND NOW THE REAL DDB
	PUSHJ	P,PSIRSW##	;SIGNAL THE REEL SWITCH
	POP	P,F		;AND ITS DDB
	HLRZ	T1,P4		;GET USERS LENGTH
	CAIL	T1,3		;MIN OF 3
	PUSHJ	P,GETWR1##	;GET NAME OF NEW DEVICE
	  PJRST	ECOD4##		;BAD ARG ADDRS
	MOVE	P1,F		;SAVE OLD DDB ADDRS
	PUSHJ	P,DEVPHY##	;LOOK FOR NEW ONE
	  PJRST	ECOD2##		;SEARCH LOST
	MOVSI	T1,DVMTA	;GRNTEE IT IS A MTA
	TDNN	T1,DEVMOD(F)	;...
	PJRST	ECOD2##		;SORRY 'BOUT THAT
	MOVE	P3,T2		;SAVE PRED.
	EXCH	F,P1		;GET OLD DDB ADDRESS FOR STATS
	PUSHJ	P,SNDVSS##	;SEND VOL SWITCH TAPE STATS FOR ACCOUNTING
	  JFCL			;WE TRIED
	PUSHJ	P,TPSTAT	;REPORT STATS
	CAMN	P1,F		;SAME DDB
	JRST	CPOPJ1##	;YES--GO AWAY
	EXCH	F,P1		;NO--GET NEW DDB BACK
	TAPOFF			;DEFEND AGAINST INTERRUPTS
	SKIPA	T1,DEVIOS(P1)	;GET OLD UNIT STATUS BITS
	EXP	 <LBLNED+FSTOP+IOEND+IOSTBL+LBLEOF,,IOTEND+IOEND+IOERRS>
	TDZ	T1,.-1		;CLEAR LOTS OF BITS...
	MOVEM	T1,DEVIOS(P1)	;SAVE THE NEW STATUS
	DDBSRL			;DONT LET ANY OTHER CPU SCAN CHAIN
	MOVE	T1,DEVNAM(F)	;GET NEW NAME
	EXCH	T1,DEVNAM(P1)	;EXCHANGE WITH OLD ONE
	MOVEM	T1,DEVNAM(F)	;AND SAVE IN NEW DDB
	SKIPE	DEVLOG(P1)	;WAS THERE A LOGICAL NAME
	JRST	TPLSU1		;YES - OK THEN
	MOVEM	T1,DEVLOG(P1)	;NO - USE OLD PHYSICAL NAME
TPLSU1:	MOVE	T1,DEVCPU(P1)	;SWAP DEVCPU
	EXCH	T1,DEVCPU(F)	; BETWEEN THE
	MOVEM	T1,DEVCPU(P1)	;  TWO DDBS
	HLRZ	T1,DEVSER(P1)	;SUCCESSOR TO 1ST UNIT
	HLRZ	T2,DEVSER(F)	;SUCCESSOR TO 2ND UNIT
	HRLM	F,DEVSER(P2)	;MAKE PRED(1ST) POINT AT 2ND
	HRLM	P1,DEVSER(P3)	;MAKE PRED(2ND) POINT AT 1ST
	CAIN	T2,(P1)		;MAKE 1ST POINT AT SUCC(2ND)
	MOVE	T2,F		; IF 1ST = SUCC 2ND, POINT 1ST AT 2ND
	HRLM	T2,DEVSER(P1)
	CAIN	T1,(F)		;POINT 2ND AT SUCC (1ST)
	MOVE	T1,P1		; OR AT 1ST
	HRLM	T1,DEVSER(F)
	MOVE	T1,GENPTR##	;AOBJN POINTER TO TABLE
TPLSU2:	HRRZ	T2,GENTAB##+1(T1) ;GET ADDR OF THIS GENERIC DDB
	CAIN	T2,(F)		;IS 1ST DDB GENERIC ?
	HRRM	P1,GENTAB##+1(T1) ;YES, UPDATE NEW DDB AS GENERIC
	CAIN	T2,(P1)		;IS 2ND DDB GENERIC ?
	HRRM	F,GENTAB##+1(T1) ;YES, ITS THE OLD ONE NOW
	AOBJN	T1,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	T1,TPLSU2	;SEARCH THE TABLE
	DDBSRU			;GIVE UP INTERLOCK
	MOVE	T2,TDVUDB(P1)	;UDB ADDRESS
	EXCH	T2,TDVUDB(F)	;SWAP
	MOVEM	T2,TDVUDB(P1)	;UPDATE
	MOVEM	F,UDBDDB(U)	;FIX UDB / DDB PNTR
	MOVE	P2,U		;OLD UDB PNTR
	MOVE	U,TDVUDB(P1)	;NEW UDB ADDRESS
	MOVE	T2,TUBLBL(U)	;EXCHANGE LABEL INFO IN UDBS
	EXCH	T2,TUBLBL(P2)
	MOVEM	T2,TUBLBL(U)	;...
	MOVEM	P1,UDBDDB(U)	;AND SET PNTR
	MOVE	F,P1		;MAKE F POINT AT NEW DDB
	SKIPE	T1,TUBDDL(U)	;GET NEW UNIT'S OLD LABEL DDB
	MOVEM	P2,TDVUDB(T1)	;CHANGE ITS UNIT POINTER IF IT EXISTS
	EXCH	T1,TUBDDL(P2)	;UPDATE PREVIOUS, GET OLD
	SKIPE	T1		;IF NEW LABEL DDB,
	MOVEM	U,TDVUDB(T1)	;UPDATE ITS UNIT POINTER
	MOVEM	T1,TUBDDL(U)	;AND THE UNIT POINTER TO THE DUMB DDB
	TAPON			;ALLOW INTERRUPTS AGAIN
	JRST	CPOPJ1##	;SKIP EXIT
;ROUTINE TO SEND FORCE EOV MESSAGE TO LBL PCS

TPMFEV:	MOVE	S,DEVIOS(F)	;SET UP S
	PUSHJ	P,LBLCKM	;CHECK FOR LBL PROCESS
	  SKIPA	T1,[LR.EOV]	;REQUEST CODE
	PJRST	ECOD7##		;NO LABEL PROCESS
	PUSHJ	P,LBLSLP	;WAIT FOR LBL PCS TO FINISH
	DPB	T1,TUYRQT	;REQUEST TYPE
	MOVEI	T1,0		;ZERO ADDITIONAL INFO
	DPB	T1,TUYINF	;...
TPMSND:	PUSHJ	P,LBLMSG	;SEND MESSAGE AND BLOCK
	LDB	T1,PDVESE##
	JUMPE	T1,CPOPJ1##	;SKIP RETURN IF NO ERROR
	PJRST	ECOD10##	;ELSE ERROR

;ROUTINE TO SEND USER REQUEST FOR LABEL PROCESSING

TPMURQ:	MOVE	S,DEVIOS(F)	;SET UP S
	PUSHJ	P,LBLCKM	;SEE IF LBL PCS
	  SKIPA	T1,[LR.URQ]	;YES - REQUEST TYPE
	PJRST	ECOD7##		;ERROR
	PUSHJ	P,LBLSLP	;WAIT FOR LBL PCS TO FINISH
	DPB	T1,TUYRQT	;REQUEST TYPE
	HLRZ	T1,P4		;GET USER LENGTH ARG
	CAIL	T1,3		;CHECK FOR ENUF ARGS
	PUSHJ	P,GETWR1##	;FETCH NEXT
	  PJRST	ECOD4##		;TOO FEW ARGS
	CAILE	T1,77		;CHECK RANGE
	  JRST	ECOD3##		;OUT OF BOUNDS
	DPB	T1,TUYINF	;STASH IN UDB
	PJRST	TPMSND		;SEND MESSAGE
;ROUTINE TO DESTROY LABEL DDB AND GIVE BACK ITS STORAGE

TPMLDD:	SKIPE	TUBDDL(U)	;LABEL DDB ADDRESS
	JRST	ECOD12##	;ERROR IF THERE IS ONE
	MOVE	T1,DEVNAM(F)	;GET PHYS NAME
	MOVEI	T2,'''L'	;CONVERT TO SECONDARY NAME
	DPB	T2,[POINT 12,T1,11]
	PUSHJ	P,DEVPHY##	;GO FIND IT
	  JRST	CPOPJ1##	;NOT THERE, JUST RETURN
	LDB	T1,PJOBN##	;GET THIS DDB'S OWNER
	CAME	T1,J		;IS IT THE GUY DOING RELEASE
	JUMPN	T1,ECOD6##	;NO, ERROR IF ANOTHER
	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO STOP
	AOS	0(P)		;SET FOR SKIP RETURN
	MOVE	T1,DEVSER(F)	;GET LINK FROM DB TO BE DESTROYED
	HLLM	T1,DEVSER(T2)	;SAVE IN PREDESSOR

;PREVENT THE POSSIBILITY THAT SOMEONE HAS AN F POINTING AT THE
;DDB THAT WILL GO AWAY IN A LITTLE WHILE.  IF THEY GET HELD UP
;AND THEN TRY TO DEVSER THEMSELVES TO THEIR NEXT DDB, THEY MAY
;TRY TO USE CORE THAT HAS BEEN RE-USED BY SOMEONE.
	DDBSRL			;STOP DDB SCANNING
	MOVE	T1,DEVSER(F)	;GET LINK FROM DB TO BE DESTROYED
	HLLM	T1,DEVSER(T2)	;SAVE IN PREDESSOR
	DDBSRU			;RESUME DDB SCANNING
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVEI	P1,0		;START AT CHANNEL 0
TPMLD2:	PUSHJ	P,NXTCH##	;NEXT CHANNEL
	  JRST	TPMLD3		;DONE
	CAIE	T1,(F)		;IS IT INITED ON THIS CHANNEL
	JRST	TPMLD2		;NO
	SOS	P1		;UNDO NXTCH ADVANCE
	PUSHJ	P,JDAADP##	;NO, CLEAR OUT THIS CHANNEL
	SETZM	(T1)
TPMLD3:	SKIPE	DEVPSI##(F)	;ON THE PSI SYSTEM?
	PUSHJ	P,PSIRMV##	;YES, REMOVE IT

	MOVEI	T1,TDVLEN	;SIZE OF DDB
	HRRZ	T2,F		;ADDR
	PJRST	GIVWDS##	;GIVE BACK STORAGE AND RETURN
;READ/SET LABEL PARAMETERS
TAPRLP:	HRR	M,P4		;POINT AT USER'S FUNCTION
	TLZ	F,-1-MXSECN	;CLEAR JUNK FROM UUOCON
	PUSHJ	P,LBLCKM	;CHECK FOR LBL PCS
	  JRST	TAPRL0		;THERE IS ONE, GO AHEAD
	PUSHJ	P,GETWRD##	;GET USER'S FUNCTION
	  PJRST	ECOD4##		;ADDR ERROR
	CAME	F,TUBDDL(U)	;LABEL DDB ADDRESS?
	PJRST	ECOD7##		;NO, NO LBL PCS
	TRNE	T1,2000		;SET FUNCTION
	JRST	TAPSLP		;YES, DO IT
	JRST	TAPRL1		;DO READ
TAPRL0:	PUSHJ	P,GETWRD##	;GET USER'S FUNCTION
	  PJRST	ECOD4##		;ADDR ERROR
	PUSHJ	P,LBLSLP
	TRNE	T1,2000		;SET FUNCTION?
	JRST	TAPSLP		;YES
	TLNN	S,FINP		;FIRST INPUT DONE?
	JRST	TAPRL1		;YES, PROCEED
	MOVEI	T1,LR.FIN	;REQUEST FOR FIRST INPUT
	DPB	T1,TUYRQT	;SAVE IN TUB
	MOVEI	T1,77		;GET LABEL READ FCN
	DPB	T1,TUYINF	;SET IT
	PUSHJ	P,LBLMSG	;SEND MESSAGE
	LDB	T1,PDVESE##	;CHECK ERROR BITS
	JUMPN	T1,ECOD10##	;GIVE ERROR TO USER
TAPRL1:	ADDI	M,1		;POINT AT WHERE TO START STORING
	HLRZ	T2,P4		;GET LENGTH
	SUBI	T2,2		;CORRECT FOR ARG'S
	JUMPLE	T2,ECOD4##	;NOT ENOUGH ARG'S
	CAILE	T2,TLPMAX	;BIGGER THAN MAX?
	MOVEI	T2,TLPMAX	;YES, USE MAX
	MOVN	P1,T2		;NEGATE LENGTH
	HRLZS	P1		;MOVE TO LH
	HRRI	P1,TUBRFM	;UDB OFFSET TO START OF LABEL PARAMETER AREA
	JRST	TPMCPY		;USE EXISTING ROUTINE TO RETURN BLOCK
TAPSLP:	HLRZ	T2,P4		;GET LENGTH OF USER'S ARG BLOCK
	SUBI	T2,2		;ACCOUNT FOR FIRST 2 ARG'S
	JUMPLE	T2,ECOD4##	;NOT ENOUGH ARGS
	CAILE	T2,TLPMAX	;BIGGER THAN MAX
	MOVEI	T2,TLPMAX	;YES, USE MAX
	MOVN	P1,T2		;GET NEGATIVE LENGTH
	HRLZS	P1		; INTO LH FOR AOBJN
	HRRI	P1,TUBRFM(U)	;POINT AT START OF AREA
	ADDI	M,1		;POINT M AT DEVICE ARG WORD
TAPSL1:	PUSHJ	P,GETWR1##	;GET NEXT ARGUMENT
	  PJRST	ECOD4##		;NOT THERE, ERROR
	MOVEM	T1,0(P1)	;STORE IN TUB
	AOBJN	P1,TAPSL1	;GET ALL ARGUMENTS
	MOVEI	T1,TLPMAX
	SUB	T1,T2
	JUMPLE	T1,CPOPJ1##
	ADDI	P1,1
	SETZM	(P1)
	SOJG	T1,.-2
	JRST	CPOPJ1##	;SKIP RETURN
> ;END IFN FTTLAB

IFN FTTLAB,<
;ROUTINE TO SET DENSITY IN THE OTHER DDB.
; (EITHER THE LABEL DDB, OR THE REAL DDB)
;CALL-T1 HAS DESIRED DENSITY CODE
; -F POINTS AT REGULAR (OR LABEL) DDB
;RETURNS- T2,T3 CLOBBERED, DENSITY SET IN
; LABEL (OR REGULAR) DDB

SETODN:	MOVE	T3,TDVUDB(F)	;GET DOWN TO UDB
	SKIPN	T2,TUBDDL(T3)	;GET LABEL DDB ADDRESS
	POPJ	P,		;NO OTHER, DON'T BOTHER
	PUSH	P,F		;SAVE F
	TLZ	F,-1-MXSECN	;CLEAR POSSIBLE JUNK FROM UUOCON
	CAMN	T2,F		;SET DENSITY ON LABEL DDB
	MOVE	T2,UDBDDB(T3)	; GET ADDRESS OF REGULAR DDB
	SKIPN	T2		;BETTER BE ONE!
	STOPCD	FPOPJ##,DEBUG,RDN ;++ REGULAR DDB NOT FOUND
	EXCH	T2,F		;AIM AT OTHER
	TLNN	T1,(ST.FAC)	;REQUEST A DENSITY CHANGE?
	DPB	T1,TDYDN1	;SET DENSITY
	TLNE	T1,(ST.FAC)	;ACTUAL DENSITY?
	DPB	T1,TDYDEN	;YES, SET ACTUAL DENSITY
	EXCH	T2,F		;BACK TO NORMAL
	JRST	FPOPJ##		;RESTORE F AND RETURN
>;END IFN FTTLAB
;ROUTINE TO TAKE CTL OFF-LINE AND SET MAINT MODE FOR ALL KONTROLLERS
;ON SAME SAME CHANNEL. SOME DIAGS THINK SINCE THEY OWN ONE KONTROLLER
;ON THE CHANNEL THAT THEY CAN DO WHAT THEY WANT WITH THE CHANNEL. THIS
;CAN CAUSE PROBLEMS IF THERE ARE OTHER KONTROLLERS ON THE SAME CHANNEL.

TPMSMM:	MOVE	W,UDBKDB(U)	;GET KDB ADDRS
	HRRZ	T3,TKBJOB(W)	;GET KDB "OWNER" IF ANY
	MOVSI	T2,TKSMNT##	;GET MAINT BIT
	TDNN	T2,TKBSTS(W)	;IN MAINTENANCE MODE ALREADY
	JRST	TPMSM0		;NO
	CAIE	T3,(J)		;YES, IS IT SAME PERSON?
	PJRST	ECOD11##	;NO, GIVE ERROR RETURN
	MOVE	T1,KDBICP(W)	;YES, GET ADDRS OF CHANNEL PROGRAM
	PJRST	STOTC1##	;RETURN ADDRS TO CALLER

;LOOP THRU ALL KDBS ON SAME CHANNEL AND SEE IF ALL UDB/DDBS ARE
;"ASSIGNABLE".

TPMSM0:	PUSH	P,KDBICP(W)	;SAVE ADDRS OF CHANNEL PROGRAM FOR USER
	MOVE	T4,KDBDVC(W)	;GET DEVICE CODE
	DDBSRL			;GET THE DDB INTERLOCK
	SKIPA	W,KDBTAB##+.TYMTA ;GET FIRST KDB ADDRS
TPMSM1:	MOVE	W,KDBNXT(W)	;GET NEXT KDB ADDRS
	JUMPE	W,TPMSM4	;IF NONE, GO SET UP DDBS
	CAME	T4,KDBDVC(W)	;ON SAME CHANNEL?
	JRST	TPMSM1		;NO, TRY NEXT KDB
	MOVE	T3,KDBIUN(W)	;YES, GET POINTER TO UDB TABLE
TPMSM2:	SKIPN	T2,0(T3)	;SEE IF UNIT EXISTS
	JRST	TPMSM3		;NO - TRY NEXT
	MOVE	F,UDBDDB(T2)	;GET DDB PNTR
	LDB	T1,PJOBN##	;OWNING JOB NUMBER
	CAME	T1,J		;IT HAD BETTER BE ME
	JUMPN	T1,[DDBSRU	; OR JOB 0
		    POP  P,(P)	;PHASE STACK
		    JRST ECOD11##] ;RETURN ERROR
TPMSM3:	CAMGE	T3,KDBFUN(W)	;LAST UDB?
	AOJA	T3,TPMSM2	;NO, LOOP FOR MORE
	JRST	TPMSM1		;YES, GO TO NEXT KDB

;WE CAN GET ALL UDB/DDBS NEEDED, SET THEM UP

TPMSM4:	SKIPA	W,KDBTAB##+.TYMTA ;GET FIRST KDB ADDRS
TPMSM5:	MOVE	W,KDBNXT(W)	;GET NEXT KDB ADDRS
	JUMPE	W,TPMSM8	;IF NONE, GO FINISH UP
	CAME	T4,KDBDVC(W)	;ON SAME CHANNEL?
	JRST	TPMSM5		;NO, TRY NEXT KDB
	MOVE	T3,KDBIUN(W)	;POINTER TO UDB TABLE
TPMSM6:	SKIPN	T2,0(T3)	;GET TUB
	JRST	TPMSM7		;NONE THERE
	MOVE	F,UDBDDB(T2)	;GET DDB PNTR
	MOVEI	T1,ASSCON	;ASSIGNED BY COMMAND BIT
	IORM	T1,DEVMOD(F)	;NAIL DOWN THE DDB
	DPB	J,PJOBN##	;INCLUDE OWNING JOB NUMBER
TPMSM7:	CAMGE	T3,KDBFUN(W)	;LAST UDB?
	AOJA	T3,TPMSM6	;LOOP FOR MORE
	CONO	PI,PI.OFF	;TURN OFF WORLD
IFN FTKL10,<HLLZS @KDBCSO(W)>	;REMOVE FROM CONSO CHAIN
	MOVSI	T1,TKSMNT##	;SET MAINT MODE BIT
	IORM	T1,TKBSTS(W)	;IN KDB
	CONO	PI,PI.ON	;RESTORE WORLD
	HRRM	J,TKBJOB(W)	;SAVE HIS JOB NUMBER
	JRST	TPMSM5		;LOOP FOR NEXT KDB
TPMSM8:	DDBSRU			;RELEASE DDB INTERLOCK

;PUT ANY KONTROLLERS ACCESSING SAME UNIT(S) IN MAINTENANCE MODE TOO

	XMOVEI	T3,UDBKDB(U)	;GET POINTER TO KDB ADDRESSES
	MOVEI	T2,MXPORT	;GET MAXIMUM NUMBER OF KDBS
	MOVSI	T4,TKSMNT##	;GET BIT TO SET
TPMSM9:	SKIPN	T1,(T3)		;GET KDB ADDRESS
	JRST	TPMS10		;NO MORE
	IORM	T4,TKBSTS(T1)	;SET MAINT BIT
	HRRM	J,TKBJOB(T1)	;SET JOB NUMBER (OWNER) TOO
	AOS	T3		;BUMP POINTER
	SOJG	T2,TPMSM9	;TRY NEXT
TPMS10:	POP	P,T1		;INFO USER WOULD LIKE (KDBICP)
	PJRST	STOTC1##	;AND SKIP RETURN

;ROUTINE TO RESTORE CTL AND CLEAR MAINT MODE (FOR ALL CTLS ON SAME CHANNEL)

TPMCMM:	MOVE	W,UDBKDB(U)	;GET KDB PNTR
	HRRZ	T4,TKBJOB(W)	;DOES THIS JOB HAVE KONTROLLER?
	CAIE	T4,(J)		;?
	JRST	ECOD11##	;NO - LOSE
	PUSH	P,KDBDVC(W)	;SAVE DEVICE CODE
	SKIPA	W,KDBTAB##+.TYMTA ;GET FIRST KDB ADDRS
TPMCM0:	MOVE	W,KDBNXT(W)	;GET NEXT KDB ADDRS
	JUMPE	W,TPMCM1	;GO CHECK POSSIBLE OTHER KDBS
	MOVE	T4,KDBDVC(W)	;GET DEVICE CODE
	CAMN	T4,(P)		;SAME CHANNEL?
	PUSHJ	P,TPMCMX	;YES, FREE UP KDB AND DDBS
	JRST	TPMCM0		;LOOP FOR NEXT KDB
TPMCM1:	XMOVEI	T3,UDBKDB(U)	;GET ADDRESS OF KDBS
	MOVEI	T2,MXPORT	;GET MAXIMUM NUMBER OF KDBS TO UNIT
	MOVSI	T4,TKSMNT##	;GET BIT TO CLEAR
TPMCM9:	SKIPN	T1,(T3)		;GET KDB ADDRESS
	JRST	TPOPJ1##	;NO MORE RETURN
	ANDCAM	T4,TKBSTS(T1)	;CLEAR MAINT BIT
	HLLZS	TKBJOB(T1)	;CLEAR OWNER
	AOS	T3		;BUMP POINTER
	SOJG	T2,TPMCM9	;TRY NEXT KDB
	JRST	TPOPJ1##	;DONE

;FREE UP KDB AND ASSOCIATED DDBS. CALLED FROM TPMCMM AND TPFREE.

TPMCMX:	HLLZS	TKBJOB(W)	;CLEAR KDB OWNER
	MOVE	T4,KDBDSP(W)	;ADDRS OF CTL DEP CODE
	MOVE	T1,KDBCAM(W)	;ON CORRECT CPU?
	TDNE	T1,.CPBIT##
	PUSHJ	P,@TPKRES(T4)	;YES, RESET CONTROLLER
	MOVSI	T1,TKSMNT##	;BIT TO CLEAR NOW
	ANDCAM	T1,TKBSTS(W)	; IN KDB
	MOVE	T3,KDBIUN(W)	;POINTER TO UDB TABLE
	DDBSRL			;INTERLOCK DDB SCANNING
TPMCM2:	SKIPN	T2,0(T3)	;GET TUB
	JRST	TPMCM3		;NONE THERE
	MOVE	F,UDBDDB(T2)	;GET DDB PNTR
	MOVEI	T1,ASSCON	;BIT TO CLEAR
	ANDCAB	T1,DEVMOD(F)	;CLEAR ASSIGNED BY COMMAND
	TRNE	T1,ASSPRG	;IS DEVICE INITED?
	JRST	TPMCM3		;NO
	SETZB	T1,DEVLOG(F)	;CLEAR ANY LOGICAL NAME ASSIGNMENT
	DPB	T1,PJOBN##	;AND OWNING JOB
TPMCM3:	CAMGE	T3,KDBFUN(W)	;LAST UDB?
	AOJA	T3,TPMCM2	;LOOP FOR MORE
	DDBSRU			;RELEASE INTERLOCK
	MOVE	T2,KDBDSP(W)	;GET DISPATCH TABLE
	MOVE	T1,KDBCAM(W)	;ON CORRECT CPU?
	TDNE	T1,.CPBIT##
	PUSHJ	P,@TPKLOD(T2)	;LOAD MICROCODE IF AVAILABLE
	  JFCL			;PROBABLY NOT THAT KIND OF CTL
	POPJ	P,		;RETURN

;ROUTINE CALLED ON TAPE ON-LINE
TPMONL::
IFN FTMDA,<
	PUSH	P,W		;IPCSER WIPES W
	MOVE	T1,UDBDDB(U)
	MOVE	T1,DEVNAM(T1)	;SIXBIT NAME
	MOVEI	T2,.TYMTA	;A MAGTAPE
	PUSHJ	P,SNDMDC##	;TELL MDC
	  JFCL
	POP	P,W		;RESTORE W
>; END IFN FTMDA
	PUSH	P,F		;SAVE F
	MOVE	F,UDBDDB(U)	;GET DDB
	PUSHJ	P,PSIONL##	;TELL PSISER
	POP	P,F		;RESTORE F
	POPJ	P,		;AND RETURN
; TAPOP. UUO FUNCTION .TFCEC
;
; CLEAR ERROR COUNTERS. THIS FUNCTION IS USED MAINLY BY THE TAPE LABLER.
; IN ORDER TO DETERMINE TAPE LABEL TYPE, PULSAR WILL READ A TAPE
; USING VARYING DENSITIES UNTIL A KNOWN LABEL TYPE IS FOUND. ALL
; FAILURES RESULT IN 'HARD ERRORS'. THESE ERRORS ARE REPORTED BY
; DAEMON AND GET TYPED OUT ON THE CTY AND THE USER'S TTY AS A RESULT
; OF THE SET WATCH MTA COMMAND. SINCE THESE AREN'T REALLY ERRORS,
; PULSAR MUST USE TAPOP. UUO FUNCTION .TFCEC TO AVOID MISLEADING AND
; AGGRIVATING USERS, AND DRIVING FIELD SERVICE PEOPLE UP A WALL W;
;
TPMCEC:	SETZM	TUBHRE(U)	;CLEAR HARD READ ERRORS
	SETZM	TUBSRE(U)	;CLEAR SOFT READ ERRORS
	SETZM	TUBHWE(U)	;CLEAR HARD WRITE ERRORS
	SETZM	TUBSWE(U)	;CLEAR SOFT WRITE ERRORS
	JRST	CPOPJ1##	;RETURN
SUBTTL MTAPE UUO

;MTAPE UUO

MTAPE0::PUSHJ	P,SAVE3##	;SAVE P1,P3
	PUSHJ	P,WAIT##	;WAIT FOR ALL PREVIOUS IO TO COMPLETE
	PUSHJ	P,PIOSET	;SET UP ACS
	HRRZ	T1,M		;GET RH OF UUO
	CAIE	T1,MT.DEC	;CHECK SPECIAL JUNK
	CAIN	T1,MT.IND	;  FOR 9-TK TAPES
	JRST	TPM9TK		;SET/CLR 4/4.5 BYTE MODE
	CAIN	T1,MT.STL	;SPECIAL LOW THRESHOLD
	JRST	TPMLOW		;  TM10 ONLY
MTAP0:
IFN FTTLAB,<
	CAIG	T1,MT.MAX	;CHECK VALID ARG
	SKIPN	P3,MTDTBL(T1)	;GET TABLE ENTRY
	JRST	UUOERR##	;ERROR IF NOT IMPLEMENTED
	PUSHJ	P,LBLCKM	;PROCESSOR RUNNING ?
	  SKIPA
	JRST	MTAP1
	PUSHJ	P,LBLSLP	;WAIT FOR LABEL PCS
	JUMPE	T1,MTAP1	;DON'T CALL LBL PLS ON NOOP
	PUSHJ	P,LBLPOS	;CHECK LBLPCS
	  POPJ	P,		;HE DID IT FOR YOU
	JRST	MTAP1		;PROCEED
> ;END IFN FTTLAB
MTAP:	CAIG	T1,MT.MAX	;CHECK VALID ARG
	SKIPN	P3,MTDTBL(T1)	;GET TABLE ENTRY
	JRST	UUOERR##	;ERROR IF NOT IMPLEMENTED
MTAP1:	HLRZ	P2,P3		;FCN INTO P2
MTAP2:	PUSHJ	P,GENIOR	;GENERATE IORB
	  JRST	TPMINF		;WHAT ELSE???
	MOVEM	T1,TDVIOR(F)	;WAIT TILL READY
IFN FTXMON,<
	SKIPE	P3		;HAVE A ROUTINE ADDRESS?
	XHLLI	P3,.		;INCLUDE SECTION NUMBER
> ;END IFN FTXMON
	MOVEM	P3,IRBIVA(T1)	;SAVE INT VECTOR
	PUSHJ	P,CPURQT##	;QUEUE IT UP
	MOVSI	T1,TKSOFL##	;IF KONTROLLER IS OFF-LINE,
	TDNE	T1,TKBSTS(W)
	JRST	POSOFL		;COMPLAIN TO USER AND OPER
	PUSHJ	P,KONWAT	;WAIT FOR KONTROLLER (P1 := IORB UPON RETURN)
	MOVSI	T1,TKSOFL##	;SEE IF UNIT IS OFFLINE
	TDNE	T1,TUBSTS(U)	;??
	JRST	POSOFL		;YES - INFORM WORLD
	SKIPE	T1,IRBIVA(P1)	;GET ROUTINE ADDRESS
IFE FTXMON,<JRST (T1)>		;DO SPECIAL ROUTINE
IFN FTXMON,<XJRST T1>		;DO SPECIAL ROUTINE
MTAPG1:	MOVEI	T1,1		;ONE OP ONLY
MTAPGO:	HRRM	T1,@IRBACC(P1)	;...
	XMOVEI	T1,TPMISP	;WHERE TO GO WHEN DONE
MTAPG2:	MOVEM	T1,IRBIVA(P1)	;SAVE IT
	PJRST	TPSTRT		;GO STRT OP
;ENTER HERE TO HANDLE OFFLINE DEVICE IF MTAPE UUO
;C(T1) := TKSOFL

POSOFL:	ANDCAM	T1,TUBSTS(U)	;CLEAR FLAG
	PUSHJ	P,TPMFLX	;FLUSH CURRENT REQUEST
POSOF1:	TLZ	S,IOSTBL!OFFLIN	;CLEAR THESE ALSO
	PUSHJ	P,CKTC10	;CHECK ON TC10C
	  PUSHJ	P,HNGSTP##	;INFORM ALL
	MOVSI	P2,OFLUNH	;PRESERVE THIS BIT
	AND	P2,DEVIOS(F)	;AROUND CALL TO IOSET
	PUSHJ	P,PIOSET	;RESET ACS
	IORM	P2,DEVIOS(F)	;RESTORE BIT IF ON
	HRRZ	T1,M		;GET FCN BACK IN T1
	JRST	MTAP		;CONTINUE

;DISPATCH TABLE FOR MTAPE UUO FUNCTIONS

MTDTBL:	RB.FYB,,TPMNOP		;0-WAIT
	RB.FRW,,TPMREW		;1-REWIND
	0			;2-ILLEGAL
	RB.FTM,,TPMWRT		;3-WRITE TAPE MARK
	0			;4-ILLEGAL
	0			;5-ILLEGAL
	RB.FSR,,0		;6-FORWARD SKIP RECORD
	RB.FBR,,0		;7-BACKWARD SKIP RECORD
	RB.FBR,,TPMSET		;10-SKIP TO LEOT (BACKUP FIRST)
	RB.FRU,,TPMUNL		;11-REWIND AND UNLOAD
	0			;12-ILLEGAL
	RB.FLG,,TPMWRT		;13-WRITE 3" BLANK TAPE
	0			;14-ILLEGAL
	0			;15-ILLEGAL
	RB.FSF,,TPMFSF		;16-FORWARD SKIP FILE
	RB.FBF,,TPMBSF		;17-BACKWARD SKIP FILE

;HERE TO DO AN INTERNAL MTWAT.
TPWAIT:	MOVEI	P2,RB.FYB	;YELLOW BALL FUNCTION
	PUSHJ	P,GENIOR	;SO WE KNOW WHEN IT'S OUR TURN
	  JRST	[PUSHJ	P,TSLEE1	;WAIT FOR CORE TO APPEAR
		 JRST	.-2]		;TRY AGAIN FOR THE IORB
	MOVEM	T1,TDVIOR(F)
	XMOVEI	T2,TPMNOP	;A PHONY IVA
	MOVEM	T2,IRBIVA(T1)	;DEFEND AGAINST KONWT2
	PUSHJ	P,CPURQT##	;PLACE AT END OF QUEUE
	PUSHJ	P,KONWAT	;WAIT FOR CONTROLLER
;	PJRST	TPMNOP		;UPDATE STATUS AND FLUSH THIS REQUEST

;HERE ON MTAPE 0
TPMNOP:	MOVE	S,DEVIOS(F)
	MOVSI	T1,TUSBOT##	;IS DRIVE AT BOT?
	TDNE	T1,TUBSTS(U)
	TRO	S,IOBOT		;YES
	MOVEM	S,DEVIOS(F)	;LIGHT BIT IF AT BOT
	JRST	TPMFLX		;THROW AWAY IORB AND RETURN

;HERE TO PERFORM SOME SORT OF WRITE FUNCTION

TPMWRT:	MOVEI	T1,1		;DO ONLY ONE OP
	HRRM	T1,@IRBACC(P1)	;STORE FOR DRIVER
TPMWR1:	MOVEI	T1,WRTDUN	;WHERE TO GO
	JRST	MTAPG2		;START OP

;HERE WHEN DONE (CHECK ERRORS)

WRTDUN:	PUSHJ	P,SETIOS	;SET UP S
	  JSP	P2,OUTERR	;ATTEMPT RECOVERY
	PJRST	TPMSTP		;STOP I/O AND RETURN

;INTERUPT AT END OF SPACING OP

TPMISP:	PUSHJ	P,SETIOS	;SET UP S
	  JSP	P2,SPERR	;HANDLE SPACING ERROR
	PUSHJ	P,TPMRIO	;RETURN IORB
	HLLZS	TKBSTS(W)	;CLEAR KON STATUS
TPMISX:
IFN FTTLAB,<TLZ	S,LBLNED>	;NO ADDITIONAL LABELER WORK NEEDED
	PJRST	STOIOS##	;WIND IT DOWN

;ROUTINE TO SET/CLR 4/5 BYTE 9 TRACK MODE

TPM9TK:	MOVEI	T1,TUC7TK##	;7-TRACK BIT
	TDNE	T1,TUBCNF(U)	;SEE IF ITS OK
	POPJ	P,		;FORGET IT IF 7TK
	HRRZ	T1,M		;RESTORE T1
	MOVEI	T2,RB.MCD	;SET NORMAL MODE
	CAIE	T1,MT.DEC	;DEC MODE?
	MOVEI	T2,RB.MBY	;INDUSTRY COMPATIBLE
	DPB	T2,TDYMOD	;SET IN MODE FIELD OF DDB
	POPJ	P,		;RETURN


;SET LOW THRESHOLD FOR TM10 CONTROLLERS

TPMLOW:	MOVSI	T2,D.NRLT	;NEXT REC AT LOW THRESHOLD
	IORM	T2,TDVSTS(F)	;SET IN DDB
	POPJ	P,		;RETURN
;HERE TO HANDLE UNLOAD. SETUP COUNTERS, REPORT TO DAEMON
;AND BITCH AT USER AND OPERATOR. (PS - CHECK SET WATCH MTA)

TPMUNL:
IFN FTMP,<
	SETZM	DEVNBF(F)
	SETZM	DEVSBF(F)
> ;END IFN FTMP
	AOSA	P2,TUBTUN(U)	;TOTAL UNLOADS, REMEMBER THIS IS UNLOAD
TPMREW:	SETZ	P2,		;CLEAR UNLOAD FLAG
	MOVSI	T1,TUSREW##	;SET REWINDING NOW!
	IORM	T1,TUBSTS(U)	;...
	SETZM	TUBCNI(U)	;FORGET ANY ERROR, DO THE REW/UNL
	PUSHJ	P,MTAPG1	;START OPERATION
	PUSHJ	P,TPMRLW	;WAIT TILL DISCONNECTED
	JUMPE	P2,TPMRW1	;NO MSG IF REWIND
	MOVSI	T1,DVDIR	;GET DIRECTORY DEVICE BIT
	ANDCAM	T1,DEVMOD(F)	;CLEAR IT
	PUSHJ	P,TPSTAT	;PRINT STATS
	PJRST	STOIOS##	;STORE S AND RETURN
TPMRW1:	TRO	S,IOBOT		;SET BOT
	MOVSI	T1,TKSOFL##
	TDNN	T1,TUBSTS(U)	;CHECK OFF-LINE
	PJRST	STOIOS##	;STORE S AND RETURN
	ANDCAM	T1,TUBSTS(U)	;CLEAR OFL BIT
	JRST	POSOF1		;INFORM USER
;ROUTINE TO PRINT TAPE STATISTICS AND CALL DAEMON

TPSTAT::PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSH	P,W		;SAVE US FROM SCNSER
	PUSH	P,F		;SAVE F
	PUSH	P,U		;SAVE U
	MOVE	P1,F		;HIDE DDB IN P1
	MOVE	P2,U		;HIDE UDB IN P2
	MOVE	P2,TDVUDB(F)	;GET UDB ADDRESS
	MOVE	P1,UDBDDB(P2)	;GET DDB ADDRESS
	LDB	J,PJOBN##	;GET OWNER JOB NUMBER
IFN FTTLAB,<
	CAME	J,TLPJOB##	;TAPE LABELER?
	JRST	TPSTA6		;NO
	MOVE	F,P1		;USE PRIMARY DDB
	LDB	J,PJOBN##	;GET USER JOB NUMBER
TPSTA6:
> ;END IFN FTTLAB
	MOVE	T1,TUBCRD(P2)	;CHARACTERS READ
	IOR	T1,TUBCWR(P2)	;CHARACTERS WRITTEN
	IOR	T1,TUBHRE(P2)	;HARD READ ERRORS
	IOR	T1,TUBHWE(P2)	;HARD WRITE ERRORS
	JUMPE	T1,TPSTA5	;ANYTHING TO REPORT?
	MOVSI	T1,JW.WMT	;CHECK IF HE WANTS TO SEE IT
	TDNN	T1,JBTWCH##(J)	;?

	JRST	TPSTA3		;JUST TELL OPR & DAEMON
	PUSHJ	P,TTYFND##	;SET UP F AND U
TPSTA0:	PUSHJ	P,CRLF##	;PRINT CRLF
	PUSHJ	P,PRLBK##	;LEFT BRACKET
	MOVE	T2,DEVNAM(P1)	;GET DEVICE NAME
	PUSHJ	P,PRNAME##	;RPINT IT
	PUSHJ	P,INLMES##	;PRINT A COLON
	  ASCIZ	":"
	SKIPE	T2,TUBRID(P2)	;SEE IF REEL ID
	PUSHJ	P,PRNAME##	;YES - PRINT IT
	SKIPN	TUBCRD(P2)	;READ STATS?
	SKIPE TUBHRE(P2)	;HARD READ ERRORS?
	 CAIA
	JRST	TPSTA1		;NO READ STATS-JUMP AROUND
	PUSHJ	P,INLMES##
	  ASCIZ	" Read(C/H/S) = "
	MOVE	T1,TUBCRD(P2)	;CHARS READ
	PUSHJ	P,PRTDIG##
	PUSHJ	P,PRSLSH##	;SLASH
	MOVE	T1,TUBHRE(P2)	;HARD READ ERRORS
	PUSHJ	P,PRTDIG##
	PUSHJ	P,PRSLSH##	;SLASH
	MOVE	T1,TUBSRE(P2)	;SOFT READ ERRORS
	PUSHJ	P,PRTDIG##
				;;; FALLIN TPSTA1
TPSTA1: SKIPN	TUBCWR(P2)	;ANYTHING WRITTEN?
	SKIPE	TUBHWE(P2)	;OR HARD WRITE ERRORS?
	CAIA			;YES, PRINT STATS
	JRST	TPSTA2		;NO
	PUSHJ	P,INLMES##
	  ASCIZ	" Write(C/H/S) = "
	MOVE	T1,TUBCWR(P2)	;CHARS WRITTEN
	PUSHJ	P,PRTDIG##
	PUSHJ	P,PRSLSH##	;SLASH
	MOVE	T1,TUBHWE(P2)	;HARD WRITE ERRORS
	PUSHJ	P,PRTDIG##
	PUSHJ	P,PRSLSH##	;SLASH
	MOVE	T1,TUBSWE(P2)	;SOFT WRITE ERRORS
	PUSHJ	P,PRTDIG##
TPSTA2:	PUSHJ	P,PRRBKC##	;RIGHT BRACKET
	CAMN	U,OPRLDB##	;THIS DA OPR?
	JRST	TPSTA4		;YES - DONE
TPSTA3:	MOVE	U,OPRLDB##	;NO - GET OPR LINE
	JRST	TPSTA0		;DO OVER

TPSTA4:	MOVE	U,P2		;RESTORE UDB PNTR
	MOVE	F,P1		;  AND DDB PNTR
	PUSHJ	P,TPESTS	;CREATE AN ERROR LOG ENTRY

TPSTA5:	POP	P,U
	POP	P,F
	POP	P,W		;RESTORE KDB
	MOVE	S,DEVIOS(F)	;RESTORE S
	POPJ	P,		;RETURN
;ROUTINE TO PERFORM SKIP FILE

TPMFSF:	PUSHJ	P,TAPFOL##	;FILE OPERATION LEGAL?
	  JRST	MTAPG1		;YES, DON'T DO MULTIPLE SKIP REC OPS
	MOVE	T1,P1		;COPY IORB
	MOVEI	P1,RB.FSR	;SKIP RECORD FUNCTION CODE
	DPB	P1,PRBFCN##	;CHANGE SO SIMULATION WORKS
	MOVE	P1,T1		;RESTORE IORB
	PUSHJ	P,TPSKPS	;CALL SKIP SET (RETURN WITH S SETUP)
	TRNE	S,IODEND!IODERR	;SEEN EOF OR DEVICE ERROR?
	PJRST	TPMISX		;GO CLEAR LABELER STUFF
TPMFS0:	MOVEI	T1,MT.FSF	;GO 'ROUND AGAIN
	JRST	MTAP		;...


;ROUTINE TO PERFORM BACKSPACE FILE

TPMBSF:	PUSHJ	P,TAPFOL##	;FILE OPERATION LEGAL?
	  JRST	MTAPG1		;YES, DON'T DO MULTIPLE SKIP REC OPS
	MOVE	T1,P1		;COPY IORB
	MOVEI	P1,RB.FBR	;BACKSPACE RECORD FUNCTION CODE
	DPB	P1,PRBFCN##	;CHANGE SO SIMULATION WORKS
	MOVE	P1,T1		;RESTORE IORB
	PUSHJ	P,TPSKPS	;CALL SKIP SET (RETURN WITH S SETUP)
	TRNE	S,IODEND!IOBOT!IODERR ;ERRORS?
	PJRST	TPMISX		;GO CLEAR LABELER STUFF
	MOVEI	T1,MT.BSF	;CALL BACKSPACE AGAIN
	JRST	MTAP		;SKIP SOME MORE

;ROUTINE CALLED TO SET UP MULTIPLE SKIPPING OPERATION
;RETURN S WITH STATUS OF OUTCOME

TPSKPS:	HRRZ	T1,-1(P)	;HAVE WE JUST BEEN HERE?
	CAIE	T1,TPSKPX+1	; (IF SO, WE CAME THROUGH HNGSTP)
	JRST	TPSKP0		;NO, CARRY ON
	POP	P,(P)		;YES, REMOVE LAST 2 CALLS FROM
	POP	P,(P)		; LIST SO AS NOT TO GET AN EPO
TPSKP0:	HRRZ	T1,TKBSTS(W)	;GET QUANTUM
	PUSHJ	P,MTAPGO	;START OP
TPSKPW::MOVEI	T1,MT.WAT	;WAIT OP CODE
TPSKPX:	PUSHJ	P,MTAP		;GO EXECUTE
	MOVE	S,DEVIOS(F)	;SET UP S
	POPJ	P,		;RETURN

;ROUTINE TO SKIP TO LOGICAL EOT

TPMSET:	PUSHJ	P,MTAPG1	;DO BSR FIRST
	PUSHJ	P,TPSKPW	;WAIT
TPMST1:	PUSHJ	P,TPMFS0	;FORWARD SKIP FILE
	TRNE	S,IODERR	;DEVICE ERROR
	POPJ	P,		;YES - RETURN
	MOVEI	T1,MT.FSR	;PLUS ONE RECORD
	PUSHJ	P,MTAP		;...
	PUSHJ	P,TPSKPW	;WAIT TILL DONE
	TRNE	S,IODERR	;DEVICE ERROR?
	POPJ	P,		;YES - RETURN
	TRNN	S,IODEND	;2ND EOF?
	JRST	TPMST1		;NO - TRY AGAIN
	MOVEI	T1,MT.BSR	;BACKSPACE OVER EOF
	PUSHJ	P,MTAP		;DO IT
	PJRST	TPSKPW		;QUEUE YELLOW BALL AND RETURN
	SUBTTL	DIAG UUO INTERFACE


TPMDIA::EXP	TPMPPR			;PREPROCESSOR ROUTINE
	DIAFNC	(CTC,TPDCTC,TPDCTC)	;CONTROL-C ENTRY FROM MONITOR
	DIAFNC	(ASU,TPDASU,TPDASU)	;ASSIGN SINGLE UNIT
	DIAFNC	(AAU,TPDAAU,TPDAAU)	;ASSIGN ALL UNITS
	DIAFNC	(RAU,TPDRCU,TPDRCU)	;RELEASE ALL UNITS
	DIAFNC	(SCP,TPDSCP,CPOPJ##)	;SPECIFY CHANNEL PROGRAM
	DIAFNC	(RCP,TPDRCP,CPOPJ##)	;RELEASE CHANNEL PROGRAM
	DIAFNC	(GCS,TPDGCS,CPOPJ##)	;GET CHANNEL STATUS
	DIAFNC	(AKU,TPDKUN,TPDKUN)	;GET KONTROLLER AND UNIT
	DIAFNC	(SCR,TPDSCR,CPOPJ##)	;SPECIFY CHN PGM FOR READ REV
	DIAFNC	(ELD,TPDELD,TPDELD)	;ENABLE MICROCODE LOADING
	DIAFNC	(DLD,TPDDLD,TPDDLD)	;DISABLE MICROCODE LOADING
	DIAFNC	(LOD,TPDLOD,TPDLOD)	;LOAD MICROCODE
	DIAFNC	(SDS,TPDSDS,TPDSDS)	;SET DEVICE STATUS
	DIAFNC				;TERMINATE TABLE

TPMPPR:	JRST	(P3)		;GO PROCESS DIAG. UUO
; ENABLE/DISABLE MICROCODE LOADING
TPDDLD:	TDZA	T1,T1		;DISABLE
TPDELD:	MOVEI	T1,1		;ENABLE
	MOVE	T2,KDBDSP(W)	;GET DISPATCH TABLE
	PUSHJ	P,@TPKEDL(T2)	;TOGGLE THE BIT
	  JRST	DIAANM##	;MICROCODE NOT AVAILABLE
	JRST	CPOPJ1##	;RETURN


; LOAD MICROCODE
TPDLOD:	MOVE	T2,KDBDSP(W)	;GET DISPATCH TABLE
	PUSHJ	P,@TPKLOD(T2)	;LOAD MICROCODE
	  JRST	DIAARF##	;COULDN'T
	JRST	CPOPJ1##	;RETURN
;SET DEVICE STATUS
TPDSDS:
IFN FTMP,<
	MOVE	T1,KDBCAM(W)	;FETCH CPU MASK
	PUSHJ	P,CPUOK##	;FIND A RUNNING CPU
	  JRST	DIAANR##	;CPU NOT RUNNING
	PUSHJ	P,ONCPUS##	;TRY TO GET THERE
	  JRST	DIAANR##	;CPU NOT RUNNING
> ;END IFN FTMP
	PUSHJ	P,GETWD1##	;GET NEXT ARGUMNET
	CAIL	T1,0		;RANGE
	CAILE	T1,SDSLEN	; CHECK
	JRST	DIAABA##	;BAD ARGUMENT LIST
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	MOVE	P2,T1		;SAVE SUB-FUNCTION CODE
	SETZB	P1,P3		;ASSUME DOING ONLY ONE UNIT
	JUMPGE	U,TPDSD1	;ROMP THROUGH LOOP ONLY ONCE
	MOVNI	P3,1		;REMEMBER DOING THE WHOLE KONTROLLER
	PUSHJ	P,@SDSTAB(P2)	;DO KONT STUFF BEFORE LOOPING THROUGH DRIVES
	  POPJ	P,		;PROPAGATE ERROR BACK
	MOVE	T1,KDBDSP(W)	;POINT TO DRIVER DISPATCH
	LDB	P1,[POINTR (DRVCF2(T1),DR.HDN)] ;GET HIGHEST DRIVE ON KONT
	SETZ	U,		;START WITH FIRST DRIVE

TPDSD1:	MOVE	T1,KDBIUN(W)	;DRIVE TABLE
TPDSD2:	SKIPN	T2,(T1)		;GET A UDB
	JRST	TPDSD3		;NONE THERE
	CAMN	U,UDBPDN(T2)	;FOUND THE UDB?
	JRST	TPDSD4		;YES
TPDSD3:	CAMGE	T1,KDBFUN(W)	;END OF TABLE?
	AOJA	T1,TPDSD2	;KEEP SEARCHING
	HRROS	U		;FLAG A NON-EXISTANT DRIVE

TPDSD4:	PUSHJ	P,@SDSTAB(P2)	;DISPATCH
	  POPJ	P,		;PROPAGATE ERROR BACK
	HRRZS	U		;INCASE LAST DRIVE DIDN'T EXIST
	AOS	U		;ADVANCE TO NEXT
	SOJGE	P1,TPDSD1	;LOOP FOR ANOTHER
	JRST	CPOPJ1##	;RETURN


SDSTAB:	IFIW	SDSIGN		;SET IGNORE
	IFIW	SDSCLR		;CLEAR IGNORE
	IFIW	SDSDET		;SET DETACHE
	IFIW	SDSATT		;SET ATTACHED
SDSLEN==.-SDSTAB		;LENGTH OF TABLE
;SET IGNORE
SDSIGN:	CAMN	U,[EXP -1]	;KONTROLLER?
	JRST	CPOPJ1##	;MEANINGLESS
	JUMPGE	U,CPOPJ1##	;CAN'T IGNORE AN KNOWN DRIVE
	HRRZ	T1,U		;COPY PHYSICAL DRIVE NUMBER
	MOVE	T2,[1,,KDBIUM]	;STATE,,MASK WORD OFFSET
	PUSHJ	P,AUTMSK##	;SET DRIVE IGNORED
	  JRST	DIAAIU##	;ILLEGAL UNIT
	JRST	CPOPJ1##	;RETURN


;CLEAR IGNORE
SDSCLR:	CAMN	U,[EXP -1]	;KONTROLLER?
	JRST	CPOPJ1##	;MEANINGLESS
	HRRZ	T1,U		;GET DRIVE NUMBER
	MOVEI	T2,KDBIUM	;STATE,,MASK WORD OFFSET
	PUSHJ	P,AUTMSK##	;CLEAR DRIVE IGNORED
	  JRST	DIAAIU##	;ILLEGAL UNIT
	JRST	CPOPJ1##	;RETURN


;SET DETACHED
SDSDET:	CAME	U,[EXP -1]	;DETACH KONTROLLER?
	JRST	SDSDE1		;SINGLE DRIVE
	PUSHJ	P,TPDKI0	;STOP I/O ON THIS KONTROLLER
	  POPJ	P,		;PROPAGATE FAILURE
	HRRZS	TKBJOB(W)	;OWNED BY JOB 0
	JRST	CPOPJ1##	;RETURN SUCCESS
SDSDE1:	JUMPL	U,CPOPJ1##	;CANNOT DETACH AN UNKNOWN DRIVE
	MOVE	T1,KDBIUN(W)	;DRIVE TABLE
SDSDE2:	MOVE	T2,(T1)		;GET A UDB
	CAMN	U,UDBPDN(T2)	;FOUND THE UDB?
	JRST	SDSDE3		;YES
	CAMGE	T1,KDBFUN(W)	;END OF TABLE?
	AOJA	T1,SDSDE2	;KEEP SEARCHING
	JRST	CPOPJ1##	;NOT THERE???
SDSDE3:	PUSH	P,U		;SAVE U
	MOVE	U,T2		;COPY UDB ADDRESS
	MOVE	F,UDBDDB(U)	;GET DDB ADDRESS TOO
	PUSHJ	P,DDBDET##	;DETACH SINGLE DRIVE
	  JFCL			;ALREADY ASSIGNED TO SOME JOB
	MOVE	U,UDBPDN(U)	;GET DRIVE NUMBER
	PUSHJ	P,SDSCLR	;MAKE SURE IGNORE IS CLEARED
	  JFCL			;ALWAYS SKIPS
	MOVE	U,TDVUDB(F)	;RESET UDB ADDRESS
	PUSHJ	P,TAPMPD##	;REPORT CHANGE TO [SYSTEM]MDA
	JRST	UPOPJ1##	;RESTORE U AND RETURN


;SET ATTACHED
SDSATT:	CAME	U,[EXP -1]	;ATTACH KONTROLLER?
	JRST	SDSAT1		;SINGLE DRIVE
	SYSPIF			;INTERLOCK
	MOVSI	T1,TKSNS##	;DIAG BIT
	TDNN	T1,TKBSTS(W)	;IS THIS KONTROLLER STOPPED?
	JRST	SDSATE		;NO, ERROR
	HLRZ	T1,TKBJOB(W)	;YES, BUT BY WHAT JOB?
	JUMPE	T1,SDSAT0	;ERROR IF NOT ASSIGNED TO JOB ZERO
SDSATE:	SYSPIN			;ERROR - PI BACK ON AND
	JRST	DIAAAF##	;GIVE ATTACH FAILED ERROR

SDSAT0:	HRLM	J,TKBJOB(W)	;MAKE IT LOOK NORMAL TO TPDSI0
	SYSPIN			;DONE WITH CRITICAL SECTION
	PUSHJ	P,TPDSI0	;START I/O ON THIS KONTROLLER
	  POPJ	P,		;PROPAGATE FAILURE
	JRST	CPOPJ1##	;OR SUCCESS
SDSAT1:	PUSHJ	P,AUTLOK##	;GET AUTCON INTERLOCK
	  JRST	SDSAT1		;SPIN IF AT CLOCK LEVEL
	PUSH	P,U		;SAVE U
	PUSH	P,P1		;SAVE P1
	HLLZ	P1,KDBIUN(W)	;MASSBUS UNIT
	HRRI	P1,(U)		;PHYSICAL DRIVE NUMBER
	MOVE	T1,KDBDVC(W)	;DEVICE CODE
	MOVE	T2,KDBDSP(W)	;DRIVER DISPATCH
	MOVE	T3,KDBCHN(W)	;CHANNEL DATA BLOCK
	PUSHJ	P,AUTSET##	;SET UP CPU VARIABLES
	MOVE	T1,KDBDSP(W)	;DISPATCH
	PUSHJ	P,@TPKDRV(T1)	;TRY TO CONFIGURE A DRIVE
	  TDZA	T1,T1		;FAILED
	MOVNI	T1,1		;SUCCESS
	POP	P,P1		;RESTORE P1
	POP	P,U		;RESTORE U
	PUSHJ	P,AUTULK##	;RELEASE AUTCON INTERLOCK
	JUMPN	T1,SDSAT2	;CONTINUE IF SUCCESSFUL
	SKIPGE	U		;SKIP IF DRIVE EXISTS BUT ATTACH FAILED
	JUMPL	P3,CPOPJ1##	;RETURN IF NON-EXISTANT DRIVE & ATTACHING KONT
	JRST	DIAAAF##	;ELSE TAKE ERROR RETURN
SDSAT2:	MOVEI	T1,ASSCON	;BIT TO TEST
	LDB	T2,PJOBN##	;GET DDB OWNER
	TDNE	T1,DEVMOD(F)	;ASSIGNED?
	JUMPN	T2,DIAAAF##	;ERROR IF OWNED BY NULL JOB (DETACHED)
	JRST	CPOPJ1##	;ELSE RETURN GOODNESS
;HERE TO ASSIGN SOME UNIT
TPDASU:	PUSHJ	P,TPDTST	;SEE IF WE CAN GRAB UNIT
	  POPJ	P,		;SOMEONE ELSE DOES
	MOVEM	T1,TUBCNF(U)	;UPDATE TUBCNF WITH TUCDIG BIT ON
	DPB	J,PJOBN##	;SET JOB NUMBER IN DDB
	JRST	TPDHVF

;HERE TO DETACH A TAPE KONTROLLER
;CALLED ON OWNING CPU BY RECON. UUO WITH KDB ADDRESS IN P1

TPMDET::PUSH	P,W		;SAVE PDB ADDRESS
	MOVE	W,P1		;PUT KDB ADDRESS WHERE IT BELONGS
	PUSHJ	P,TPDKI0	;STOP I/O ON THIS KONTROLLER
	  JRST	WPOPJ##		;PROPAGATE FAILURE
	HRRZS	TKBJOB(W)	;OWNED BY JOB 0
	JRST	WPOPJ1##	;RETURN SUCCESS

;HERE TO START/STOP I/O ON THE SPECIFIED KONTROLLER

TPDKIO::MOVSI	T1,JP.POK	;CHECK FOR PRIVILEGES
	PUSHJ	P,PRVBIT##	;...
	  SKIPA			;PRIVILEGED, SKIP
	JRST	DIAANP##	;ERROR
	PUSHJ	P,GETWD1##	;GET NEXT WORD (DEVICE)
	JUMPE	T1,TPDKI6	;WANTS ALL TAPE I/O
	PUSHJ	P,CHKGEN##	;GET GENERIC POINTER
	JRST	[SETZ F,	;CLEAR STALE DDB
		 JRST DIAAIU##]	;DONE
	MOVE	W,TDVUDB(F)	;POINT TO THE UDB
	MOVE	W,UDBKDB(W)	;AND TO THE PRIMARY KDB
	SETZ	F,		;**NOT AN I/O UUO***
	JUMPE	W,DIAAIU##	;?NO KDB?
;FALL INTO TPDKI0

TPDKI0:	PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	SYSPIF
	HLRZ	T1,TKBJOB(W)	;GET MAINTENANCE JOB
	CAIE	T1,(J)		;IS IT ME?
	JUMPN	T1,[SYSPIN	;NO
		    JRST DIAAAJ##] ;SOMEONE ELSE ALREADY
	MOVSI	T1,TKSNS##	;DIAG BIT
	TDNE	T1,TKBSTS(W)	;IS THIS A NO-OP?
	JRST	[SYSPIN		;YES
		 JRST	CPOPJ1##] ;RETURN VACUOUSLY
	IORM	T1,TKBSTS(W)	;NO, LIGHT THE BIT
	HRLM	J,TKBJOB(W)	;IT'S US NOW
	SYSPIN
TPDKI1:	MOVSI	T1,TKSSEL	;HAS IT STOPPED YET?
	TDNN	T1,TKBSTS(W)	;?
	JRST	TPDKI2		;CHECK REWIND STATUS
	MOVEI	T1,2
	PUSHJ	P,SLEEPF##	;WAIT A BIT
	JRST	TPDKI1

TPDKI2:	MOVE	P1,KDBIUN(W)	;POINTER TO UDB TABLE
	MOVSI	P2,TUSREW##	;REWINDING BIT
TPDKI3:	SKIPE	U,(P1)		;ANY?
TPDKI4:	TDNN	P2,TUBSTS(U)	;YES, IS IT REWINDING?
	JRST	TPDKI5		;NO
	MOVEI	T1,2
	PUSHJ	P,SLEEP##	;WAIT A BIT
	JRST	TPDKI4		;CHECK AGAIN

TPDKI5:	CAMGE	P1,KDBFUN(W)	;FINAL UDB?
	AOJA	P1,TPDKI3	;LOOP FOR MORE
	JRST	CPOPJ1##	;DONE

;HERE TO STOP I/O ON ALL MAG TAPE KONTROLLERS

TPDKI6:	SKIPA	W,KDBTAB##+.TYMTA ;POINT TO FIRST KDB
TPDKI7:	MOVE	W,KDBNXT(W)	;POINT TO NEXT KDB
	JUMPE	W,CPOPJ1##	;DONE
	PUSHJ	P,TPDKI0	;SHUT DOWN THE I/O HERE
	  JRST	TPDKI9		;OOPS, UNDO WHAT WE DID
	JRST	TPDKI7		;NEXT KDB

TPDKI9:	PUSH	P,T1		;SAVE ERROR
	PUSHJ	P,TPDSIA	;CRANK IT UP AGAIN
	  JFCL
	POP	P,T1		;RESTORE ERROR
	PJRST	STOTAC##	;IN CASE SIO CLEARED IT


;HERE TO ATTACH A TAPE KONTROLLER
;CALLED ON OWNING CPU BY RECON. UUO WITH KDB ADDRESS IN P1

TPMATT::PUSH	P,W		;SAVE PDB ADDRESS
	MOVE	W,P1		;PUT KDB ADDRESS WHERE IT BELONGS
	SYSPIF			;INTERLOCK
	MOVSI	T1,TKSNS##	;DIAG BIT
	TDNN	T1,TKBSTS(W)	;IS THIS KONTROLLER STOPPED?
	JRST	[SYSPIN		;NO
		 JRST WPOPJ##]	;GIVE ERROR RETURN
	HLRZ	T1,TKBJOB(W)	;YES, BUT BY WHAT JOB?
	JUMPN	T1,[SYSPIN	;DETACH ASSIGNED IT JOB ZERO
		    JRST WPOPJ##] ;SO ATTACH ONLY TAKES IT BACK FROM THERE
	HRLM	J,TKBJOB(W)	;MAKE IT LOOK NORMAL TO TPDSI0
	SYSPIN			;DONE WITH CRITICAL SECTION
	PUSHJ	P,TPDSI0	;START I/O ON THIS KONTROLLER
	  JRST	WPOPJ##		;PROPAGATE FAILURE
	JRST	WPOPJ1##	;OR SUCCESS

;HERE TO START I/O UP AGAIN

TPDSIO::MOVE	P1,T1		;SAVE ORIGINAL ARG
	MOVSI	T1,JP.POK	;CHECK FOR PRIVILEGES
	PUSHJ	P,PRVBIT##	;...
	  SKIPA			;PRIVILEGED, SKIP
	JRST	DIAANP##	;ERROR
	PUSHJ	P,GETWD1##	;GET NEXT
	JUMPE	T1,TPDSIA	;FIX ALL OF THEM WE OWN
	PUSHJ	P,CHKGEN##	;GET DEVICE NAME
	  JRST	[SETZ F,
		 JRST DIAAIU##]	;CAN'T FIND DEVICE
	MOVE	W,TDVUDB(F)	;POINT TO THE UDB
	MOVE	W,UDBKDB(W)	;AND TO THE PRIMARY KDB
	SETZ	F,		;**DON'T OWN THIS DDB**
	JUMPE	W,DIAAIU##	;NO SUCH DEVICE

TPDSI0:	HLRZ	T1,TKBJOB(W)	;GET MAINTENACE OWNER
	CAIE	T1,(J)		;IS IT ME?
	JRST	DIAAAJ##	;OWNED BY SOMEONE ELSE
	MOVSI	T1,TKSNS##
	ANDCAM	T1,TKBSTS(W)
	HRRZS	TKBJOB(W)	;WE DON'T ANY MORE
	AOS	(P)
IFN FTMP,<
	MOVE	T1,KDBCAM(W)	;GET CPU FOR SPECIFIED KONTROLLER
	PUSHJ	P,CPUOK##	;IS IT RUNNING?
	  POPJ	P,		;NO
	PUSHJ	P,ONCPUS##	;GET US ONTO THAT CPU
	  POPJ	P,		;NOT RUNNING
> ;END IFN FTMP
	MOVE	T1,KDBDSP(W)	;CLANK SCHED TO LOOK
	PJRST	@TPKSCH(T1)

TPDSIA::SKIPA	W,KDBTAB##+.TYMTA ;POINT TO FIRST KDB
TPDSI6:	MOVE	W,KDBNXT(W)	;POINT TO NEXT KDB
	JUMPE	W,TPDSI7	;DONE
	PUSHJ	P,TPDSI0	;START I/O ON THIS ONE
	  JFCL			;DON'T OWN IT
	JRST	TPDSI6

TPDSI7:	JUMPL	M,CPOPJ		;FROM DIACLR
	AOS	(P)		;SKIP RETURN
	MOVE	T1,P1
	PJRST	STOTAC##	;RESTORE ORIGINAL ARG

;HERE TO ASSIGN ALL UNITS ON A CONTROLLER
TPDAAU:	MOVE	T3,KDBIUN(W)	;POINTER TO UDB TABLE
TPDAA1:	SKIPE	U,(T3)		;HAVE A UDB
	PUSHJ	P,TPDTST
	  JUMPN	U,CPOPJ##
	CAMGE	T3,KDBFUN(W)	;FINAL UDB?
	AOJA	T3,TPDAA1	;LOOP FOR MORE
	DDBSRL			;GET DDB INTERLOCK
	MOVE	T3,KDBIUN(W)	;POINTER TO UDB TABLE
	MOVEI	T1,TUCDIG##
	PUSH	P,[EXP 0]	;RESERVE STORAGE FOR A UDB ADDRESS
TPDAA2:	SKIPE	U,(T3)
	JRST	[IORM	T1,TUBCNF(U) ;TURN ON DIAG BIT
		 MOVE	F,UDBDDB(U)  ;GET DDB ADDRESS
		 DPB	J,PJOBN##    ;SET JOB NUMBER IN DDB
		 JRST	.+1]
	SKIPN	(P)		;FOUND THE FIRST UDB YET?
	MOVEM	U,(P)		;SAVE ADDRESS NOW
	CAMGE	T3,KDBFUN(W)	;FINAL UDB?
	AOJA	T3,TPDAA2	;LOOP FOR MORE
	DDBSRU			;RELEASE DDB INTERLOCK
	POP	P,U		;GET SAVED UDB ADDRESS BACK
TPDHVF:	SKIPE	DIATAP		;NO TAPE DIAGS?
	CAMN	J,DIATAP	;OR SAME JOB?
	JRST	TPDSCH
	PUSH	P,T1		;SAVE TUBCNF BITS OR TUCDIG BIT
	MOVEI	T1,2
	PUSHJ	P,SLEEPF##
	POP	P,T1
	JRST	TPDHVF
TPDSCH:	PUSH	P,W		;SAVE KDB
	PUSHJ	P,FNDPDS##	;FIND THE PDB
	HRROM	F,.PDDIA##(W)	;UPDATE DIAG DDB (WITH ONLY ONE OR ONE OF MANY)
	POP	P,W		;RESTORE KDB
	MOVEM	J,DIATAP	;SAVE JOB CURRENTLY DOING TAPE DIAGS
	MOVSI	T1,NSWP!NSHF
	IORM	T1,JBTSTS##(J)
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN


;PRESERVES T3
TPDTST:	MOVE	F,UDBDDB(U)
	MOVE	T1,TUBCNF(U)
	LDB	T2,PJOBN##
	CAME	T2,.CPJOB##
	JUMPN	T2,DIAAAJ##
	TRO	T1,TUCDIG##
	JRST	CPOPJ1##


;HERE ON ^C, HALT, EXIT, ETC   WITH F=DIAGING DDB
TPDCTC:	MOVE	U,TDVUDB(F)	;UDB ADDRESS
	MOVE	W,UDBKDB(U)	;KDB ADDRESS (PRIMARY)
	SOS	(P)

;HERE TO RELEASE ALL UNITS
TPDRCU:	JUMPE	F,CPOPJ1##
IFN FTKL10,<PUSHJ P,TPDRCX>	;RETURN ANY IOWD
	MOVEI	T1,TUCDIG##
	MOVE	T2,KDBIUN(W)	;POINTER TO UDB TABLE
	SETZ	T4,
	PUSH	P,U
	DDBSRL			;GET DDB INTERLOCK
TPDRC1:	SKIPE	U,(T2)
	TDNN	T1,TUBCNF(U)
	JRST	TPDRC2
	MOVE	F,UDBDDB(U)
	LDB	T3,PJOBN##
	CAME	T3,J
	JRST	TPDRC2
	ANDCAM	T1,TUBCNF(U)
	DPB	T4,PJOBN##
TPDRC2:	CAMGE	T2,KDBFUN(W)	;FINAL UDB?
	AOJA	T2,TPDRC1	;LOOP FOR MORE
	DDBSRU			;RELEASE DDB INTERLOCK
	POP	P,U
	PUSH	P,W		;SAVE KDB
	PUSHJ	P,FNDPDS##	;FIND THE PDB
	SETZM	.PDDIA##(W)	;CLEAR DIAG DDB
	POP	P,W		;RESTORE KDB
	SETZM	DIATAP
	HRRZ	T1,TUBQUE(U)
	JUMPE	T1,CPOPJ1##
	PUSHJ	P,TPMFLS	;GIVE UP IORB, START SOME OTHER TAPE
	JRST	CPOPJ1##

IFN FTKL10,<
;HERE TO SET UP A CHANNEL PROGRAM
TPDSCP:	TDZA	P4,P4		;NORMAL CHANNEL PROGRAM
TPDSCR:	MOVNI	P4,1		;READ REVERSE CHANNEL PROGRAM
	JUMPE	F,DIAAAU##	;NO ASS'D UNITS
IFN FTKL10,<PUSHJ P,TPDRCX>	;RETURN ANY IOWD
	PUSHJ	P,GETWD1##	;GET IOWD
	HLRE	T2,T1		;LENGTH OF IOWD
	JUMPE	T2,DIAACP##	;TOO BIG IF 0
	SKIPE	P4		;REVERSE?
	ADD	T1,T2		;YES. POINT TO START
	MOVE	P3,T1		;UNRELOCATED IOWD
	MOVEI	T1,1(T1)	;START ADDRESS
	MOVNS	T2		;+LENGTH
	ADDI	T2,-1(T1)	;TOP ADDRESS
	PUSHJ	P,ZRNGE##	;MAKE SURE THE PAGES ARE OK
	  JRST	DIAACP##	;SOME PAGE NOT THERE, BOMB HIM OUT
	HRRZ	T1,TUBQUE(U)
	JUMPN	T1,TPDSC0	;JUMP IF HAVE AN IORB
	MOVEI	P2,RB.FYB	;DUMMY FUNCTION
	PUSHJ	P,GENIOR	;GET AN IORB
	  JRST	DIAAFC##	;NO FREE CORE
	MOVEM	T1,TDVIOR(F)	;SAVE ADDRESS
	PUSHJ	P,SETACS	;SET UP ACS
	PUSHJ	P,TAPRQT##	;QUEUE IT UP
	HRRZ	T1,TUBQUE(U)	;GET IORB ADDRESS BACK
TPDSC0:	MOVE	T2,P3		;IOWD
	SETZ	T4,		;NOT BYTE MODE, DO ALL OF IOWD
	TRO	S,IOCON
	TLZ	S,IO
	MOVE	P1,T1
	LDB	T3,PRBMOD##
	JUMPN	T3,TPDSC1
	MOVEI	T3,RB.MCD	;CORE-DUMP IF NOT GIVEN
	DPB	T3,PRBMOD##
TPDSC1:	PUSHJ	P,MAKLST
	  JRST	DIAAFC##
	HRRZ	T3,@IRBACC(T1)
	MOVE	T1,KDBICP(W)
	MOVE	T2,KDBCHN(W)
	MOVE	T2,CHNTYP(T2)
	TLNE	T2,CP.RH2
	TLO	T3,(INSVL.(.CCJMP,CC.OPC))
	MOVEM	T3,(T1)
	PUSHJ	P,STOTAC##	;TELL USER ICWA
	JUMPE	P4,TPDSC2	;REVERSE?
	TLZN	T3,(INSVL.(.CCJMP,CC.OPC)) ;YES, RH20 - DEVICE?
	JRST	TPDSC2		;CAN'T REVERSE LIST
	HLRE	T2,P3		;REVERSE IT
	MOVNS	T2
	PUSHJ	P,REVCCW##
TPDSC2:	PUSHJ	P,CSDMP##	;SWEEP CACHE
	JRST	CPOPJ1##	;AND TAKE GOOD RETURN
> ;END IFN FTKL10
IFN FTKL10,<
;HERE TO RETURN A CHANNEL PROGRAM
TPDRCP:	JUMPE	F,CPOPJ1##
	AOS	(P)
TPDRCX:	HRRZ	T2,TUBQUE(U)
	JUMPE	T2,CPOPJ##
	HRRZ	T1,@IRBACC(T2)
	HLLZS	@IRBACC(T2)
	JUMPN	T1,RTNIOW##
	POPJ	P,
> ;END IFN FTKL10

IFN FTKL10,<
;HERE TO TELL USER FINAL CHANNEL STATISTICS
TPDGCS:	JUMPE	F,CPOPJ1##
	MOVE	P2,KDBICP(W)
	PJRST	DIAGCS##
> ;END IFN FTKL10

;ROUTINE TO GET CONTROLLER/UNIT NUMBERS
TPDKUN::MOVE	U,TDVUDB(F)	;UNIT
	MOVE	T1,UDBKDB(U)	;KDB ADDRESS (PRIMARY)
	MOVE	T2,KDBDVC(T1)	;GET DEVICE CODE
	HLRE	T1,KDBUNI(T1)	;UNIT
	SKIPGE	T1		;MULTI UNIT?
	TDZA	T1,T1		;NO, JUST USE SLAVE ADDR
	LSH	T1,3		;YES. SHIFT
	ADD	T1,UDBPDN(U)	;ADD IN PHYSICAL DRIVE NUMBER
	LSH	T2,2		;MAKE DEVICE CODE 9 BITS
	HRL	T1,T2		;DEVICE CODE TO LH,UNIT NO TO RH
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	STOTAC##	;AND STORE VALUE IN USER'S AC
SUBTTL ERROR RECOVERY

;HERE ON TAPE UNIT HUNG FROM CLOCK1

TPMHNG:	PUSHJ	P,SAVE1##	;SAVE P1
	PUSHJ	P,SAVW##	;SAVE W
	MOVE	U,TDVUDB(F)	;UDB ADDRESS
	MOVE	T1,TUBAKA(U)	;GET ACTIVE KDB ADDRESS
	TLZ	T1,(1B0)	;CLEAR POSSIBLY INVALID BIT
	MOVE	T1,TKBSTS(T1)	;GET STS
	TLNE	T1,TKSNS##	;CONFIG DOING ITS THING?
	JRST	CPOPJ1##	;DON'T REALLY HANG IT THEN
	SKIPL	DEVIAD(F)	;JOB IN KONTROLLER WAIT?
	JRST	TPMHN1		;NO, DON'T HAVE TO WAKE IT
	MOVSI	T1,OFLHNG	;WOKEN FROM KONTROLLER WAIT
	ANDCAM	T1,DEVIAD(F)	; BECAUSE OF A HUNG TIME OUT
	LDB	T1,PJOBN##	;JOB NUMBER
	PUSHJ	P,EWAKE##	;GET IT STARTED
TPMHN1:	PUSHJ	P,TAPHNG##	;INFORM LOWER LEVEL
TPMDQ:	PUSHJ	P,SAVE2##	;SAVE P1,P2
	SKIPN	P1,T1		;SEE IF THERE WAS ONE
	POPJ	P,		;NO - JUST EXIT
IFN FTMP,<PUSHJ	P,TAPCPU##>	;GET ONTO OWNING CPU

TPMDQ1:	CAIN	P1,TKBERB(W)	;CHECK FOR ERROR IORB
	JRST	[MOVE P2,IRBLNK(P1) ;TRY NEXT IF IT IS
		 JRST TPMDQ2]	;CHECK DONE
	PUSHJ	P,TPMRCW	;RETURN XFER LIST IF ANY
	MOVE	T2,P1		;SET FOR GIVWDS
	MOVEI	T1,TRBLEN	;LENGTH
	MOVE	P2,IRBLNK(P1)	;GET LINK
	PUSHJ	P,GIVWDS##	;RETURN IORB
TPMDQ2:	SKIPE	P1,P2		;CHECK FOR MORE
	JRST	TPMDQ1		;YES - RETURN IT
	PJRST	TAPCTM##	;CLEAR HUNG TIMER

;HERE FROM GIVRES IN ERRCON
TPFREE::SKIPN	KDBTAB##+.TYMTA ;ANY TAPES AT ALL ON SYSTEM?
	POPJ	P,		;NO, GO AWAY
	MOVEI	F,TDVDDB	;ADDRS OF FIRST DDB
	PUSH	P,U		;SAVE U
TPFRE1:	MOVE	T1,DEVMOD(F)	;GET TYPE INFO
	TLNN	T1,DVMTA	;STILL A MTA
	JRST	TPFRE2		;DONE
	LDB	T1,PJOBN##	;YES - GET OWNING JOB
	MOVE	S,DEVIOS(F)	;AND SETUP S
	CAMN	T1,J		;BELONG TO US?
	PUSHJ	P,TPMHLD	;YES - GO SET ON HOLD
	HLRZ	F,DEVSER(F)	;LINK TO NEXT
	JUMPN	F,TPFRE1	;AND CONTINUE
TPFRE2:	MOVE	W,KDBTAB##+.TYMTA ;START AT FIRST KONTROLLER
TPFRE3:	HRRZ	T1,TKBJOB(W)	;GET GET KDB OWNER
	CAMN	T1,J		;OWNED BY US?
	PUSHJ	P,TPMCMX	;YES, RELEASE MAINT MODE
	SKIPE	W,KDBNXT(W)	;NEXT KONTROLLER
	JRST	TPFRE3		;GO TEST IT
	PJRST	UPOPJ##		;DONE IF NONE LEFT

TPMHLD::MOVE	U,TDVUDB(F)	;UDB ADDRESS
	SKIPG	W,TUBAKA(U)	;AND ACTIVE KDB ADDRESS IF SELECTED
	POPJ	P,		;THERE ISNT ONE
IFN FTTLAB,<
	SKIPN	TUBDDL(U)	;LABEL DDB ADDRESS
	JRST	TPHLD1		;OK IF NONE
	PUSH	P,F		;SAVE F
	TLZ	F,-1-MXSECN	;CLEAR POSSIBLE JUNK FROM UUOCON
	CAME	F,TUBDDL(U)	;LABEL DDB ADDRESS?
	JRST	FPOPJ##		;NO--THEN EXIT
	POP	P,F		;RESTORE F
> ;END IFN FTTLAB
TPHLD1:	TRNN	S,IOACT		;ACTIVE?
	PJRST	TAPHLD##	;NO - CALL TAPSER
	MOVSI	T1,TUSNS##	;ELSE SET NO SCHED
	IORM	T1,TUBSTS(U)	;  AND WAIT FOR I/O TO CEASE
	POPJ	P,
;ROUTINE CALLED FROM TAPSER WHEN KONTROLLER IS FOUND OFF-LINE

TPMOFL::MOVSI	T1,TKSSIL##	;BIT FOR SILENCE
	TDNN	T1,TKBSTS(W)	;WANT TO HEAR?
	SKIPGE	DEBUGF##	;  FOR ANY REASON
	POPJ	P,		;  DEBUG MODE OR SILENCED
	MOVE	T2,STATES##
	TRNE	T2,ST.NOP	;OPR IN ATTENDANCE?
	IORM	T1,TKBSTS(W)	;NO, ONLY TYPE THE MESSAGE ONCE
	PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVE	P1,U		;UDB ADDRS TO P1
	MOVE	P2,W		;KDB ADDRS TO P2
	MOVE	U,OPRLDB##	;GET OPR ADDRS TO SEND MSG
	PUSHJ	P,INLMES##	;NOW INFORM HIM
	  ASCIZ	"
%% Tape controller "
	MOVE	T2,KDBNAM(P2)	;NAME
	PUSHJ	P,PRNAME##	;PRINT IT
	PUSHJ	P,INLMES##	;REST OF MSG
	  ASCIZ	" is off-line
"
	MOVE	U,P1		;RESTORE STUFF
	MOVE	W,P2		;...
	POPJ	P,		;RETURN

;ROUTINE TO SET SILENCE IF C(T1) IS A TAPE KONTROLLER
;CALL:	MOVE T1,<KONTROLLER ID>
;	PUSHJ	P,TPMSIL
;	  RETURN HERE IF OK
;	RETURN HERE TO PROCEED
;T1 - PRESERVED

TPMSIL::PUSH	P,T1		;SAVE ARG
	PUSH	P,W		;SAVE W
	SKIPN	W,KDBTAB##+.TYMTA ;GET FIRST KDB
	JRST	TPMSLX		;NO TAPES ANYWHERE
TPMSLL:	CAMN	T1,KDBNAM(W)	;THIS ONE?
	JRST	TPMSL1		;YES - SET BIT
	SKIPE	W,KDBNXT(W)	;NO--LINK TO NEXT
	JRST	TPMSLL		;GO CHECK IT
TPMSLX:	POP	P,W		;RESTORE W
	PJRST	TPOPJ1##	;SKIP RETURN

TPMSL1:	MOVSI	T2,TKSSIL##	;BIT TO SET IN KDB
	IORM	T2,TKBSTS(W)	;...
	POP	P,W
	PJRST	TPOPJ##		;RETURN
;TAPSER INITIATION

TPMINI:	SE1ENT			;ENTER SECTION ONE
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	T1,[TUBRID,,TDVDDB] ;REELID OFFSET,,FIRST DDB
	MOVEM	T1,CNFMTA##	;SAVE FOR DAEMON ERROR REPORTING
	MOVEI	T1,UDBDDB	;OFFSET TO DDB
	MOVEM	T1,TAPDDP##	;SAVE FOR GETTABS
IFN FTMP,<
	MOVEI	T1,[IORM T2,.CPCHX##-.CPCDB##(P1) ;STORE CACHE SWEEP BIT
		    LSH  T2,1	;POSITION FOR NEXT CPU
		    POPJ P,]	;RETURN
	MOVSI	T2,TKSCHX##	;GET CACHE SWEEP BIT
	PUSHJ	P,CPUAPP##	;STUFF INTO ALL THE CDBS
> ;END IFN FTMP
	POPJ	P,		;RETURN
;OUTPUT ERROR DETECTED - CHECK FOR WRITE LOCK

DMPERR:				;DUMP MODE ERRORS
OUTERR:	TRNE	S,IOIMPM	;WRITE LOCKED?
	JRST	(P2)		;YES - JUST RETURN

;INPUT AND SPACING ERROR
;  ALSO COMMON CODE TO OUTPUT ERRORS

SPERR:
INPERR:	MOVSI	T1,TUSREW##	;CLR REWINDING INFO
	ANDCAM	T1,TUBSTS(U)	;ON ANY ERROR
	HLRZ	T1,TRBSTS(P1)	;GET ERROR INFO
IFN FTTLAB,<
	TLNE	S,LBLNED	;NEED PROCESSING?
	JRST	ERRLBL		;YES - SCHEDULE
> ;END IFN FTTLAB
	PUSHJ	P,TPEMOV
	TRNE	T1,RB.SOL	;OFF-LINE?
	JRST	ERROFL		;YES, HANDLE IT
	TRNN	T1,RB.SER!RB.SRE ;NON-RECOV OR RECOVERED
	TRNE	S,IONRCK	;USER WANT JUST TO TRY?
	JRST	ERRX1		;JUST LOG ERROR & EXIT
	SETZM	TUBTRY(U)	;CLEAR ATTEMPT COUNTER
	MOVEI	T2,DEPDER	;ERROR RETRY DISABLED?
	TDNE	T2,DEVSTA(F)
	JRST	ERRX1		;YES, LOG AND EXIT
	PJRST	TAPERP##	; AND TRY TO RECOVER
;HERE TO HANDLE UNIT OFF-LINE (FLUSH IORB AND RETURN TO UUO LEVEL

IFN FTTLAB,<
ERRLBL:	PUSH	P,T1		;SAVE TRBSTS FOR LATER
	MOVEI	T1,LR.TM	;ASSUME TAPE MARK
	DPB	T1,TUYRQT	;PUT IN CORRECT REQUEST
	MOVE	T1,P1		;LOC OF IORB
	LDB	T1,PRBFCN##	;WHAT WE'RE DOING
	CAIE	T1,RB.FRD	;IF A READ,
	CAIN	T1,RB.FRB
	TLOA	S,LBLEOF	; TURN ON A FUNNY BIT
	JRST	[POP P,T1	; RESTORE TRBSTS
		JRST ERROF1]	; AND CLEAR IODEND SO AS NOT
	LDB	T1,PIOMOD##	;BUFFERED MODE?
	CAIL	T1,SD
	JRST	ERRLB1		;NO
	MOVSI	T2,IOEND	;YES, SAVE BIT IN BUFFER S-WORD
	PUSHJ	P,TPMXCI	; TO TELL USER WE SAW EOF
 	EXCTXU <MOVEM T2,-1(T1)>
ERRLB1:	POP	P,T1		;RESTORE TRBSTS
	TRZA	S,IODEND	; TO CONFUSE UUOCON
> ;END IFN FTTLAB
ERROFL:	TLO	S,OFFLIN	;SET OFF-LINE IN DEVIOS
	TRNN	T1,RB.SMO	;MONITOR DIRECTED OFF-LINE ?
	JRST	ERROF1		;NO -
	MOVSI	T1,(1B1)	;MDO IS UNRECOVERABLE
	IORM	T1,TUBTRY(U)	;
	PUSHJ	P,TPELOG	;LOG THE ERROR

ERROF1:	PUSHJ	P,TPMRCW	;RETURN XFER LIST IF ANY
	PUSHJ	P,TPMRIO	;RETURN IORB
	HLLZS	TKBSTS(W)	;SET QUANTA TO ZERO
	PJRST	DEVERR##	;SET ERROR AND RETURN
;HERE WHEN TAPSER EITHER GAVE UP OR RECOVERED THE ERROR

ERRX1:	TRNE	T1,RB.SRE	;RECOVERED?
	JRST	ERRX2		;YES - REPORT IF NECESSARY
	TRNN	T1,RB.SED	;ANY ERROR ?
	JRST	ERRX1A		;NO - LOOK FOR OTHER STUFF
	TRO	S,IODTER	;ASSUME DATA ERROR
	TRNN	T1,RB.SDE	;IS IT DEVICE ?
	TRC	S,IODTER!IODERR	;YES - CLEAR DATA/SET DEVICE
ERRX1A:	TRNE	T1,RB.STL	;READ ENUF ?
	TRO	S,IOBKTL	;SET BLOCK TOO LARGE
	TRNE	T1,RB.SLK!RB.SIL	;ATTEMPT TO WRITE W/O WRITE RING
	TRO	S,IOIMPM
	MOVEM	S,DEVIOS(F)	;SAVE
	TRNE	T1,RB.STL	;IS BLOCK-TOO-LONG
	JRST	ERRX4		;INCLUDING DAEMON CALL

	TLNE	S,IO		;CHECK INPUT/OUTPUT
	AOSA	TUBHWE(U)	;HARD WRITE ERROR
	AOS	TUBHRE(U)	;HARD READ ERROR
	MOVSI	T1,(1B1)	;FLAG FOR DAEMON
	IORM	T1,TUBTRY(U)	;...
	JRST	ERRX3		;GO LOG IT

;HERE ON RECOVERED ERRORS - CHECK IF LOGGING STILL ON
;ALSO DON'T LOG ERRORS THAT RECOVERED ON 1 RETRY

ERRX2:	TLNE	S,IO		;WHICH WAY
	AOSA	TUBSWE(U)	;SOFT WRITE ERROR
	AOS	TUBSRE(U)	;SOFT READ ERROR
	HRRZ	T1,TUBTRY(U)	;NO OF RETRIES
	SKIPE	[MTELOG##]	;LOG ALL ERRORS?
	SOJLE	T1,ERRX4	;NO, GO IF WE WON ON 1ST RETRY
	MOVE	T1,TUBSWE(U)	;CHECK TOTAL SOFT ERRORS
	ADD	T1,TUBSRE(U)
	CAILE	T1,MTDAEM##	;BEYOND THRESHOLD?
	JRST	ERRX4		;YES - DON'T LOG IT
ERRX3:	PUSHJ	P,TPELOG
ERRX4:	TRNE	S,IODERR
	AOS	TUBTDE(U)	;TOTAL DEVICE ERRORS
	TRNE	S,IODTER
	AOS	TUBTME(U)	;TOTAL MEDIA ERRORS
	MOVE	T1,KDBCHN(W)	;GET CDB
	MOVE	T2,CHNNUM(T1)	;GET CHANNEL ERROR BITS
	TLNN	T2,IOCHMP!IOCHNX ;WERE THERE ANY MEMORY ERRORS?
	JRST	(P2)		;NO--RETURN
	HLLZ	T3,CHNCSR(T1)	;GET CHANNEL FLAGS FOR SWEEP
	TRO	T3,UE.PEF	;ASSUME PARITY
	TLNE	T2,IOCHNX	;WAS IT A NXM?
	TRC	T3,UE.PEF!UE.NXM;YES--SET NXM
	SETZM	CHNNUM(T1)	;CLEAR CHNNUM
	IORM	T3,.CPAEF##	;SET REQUEST FOR MEMORY SCAN
	JRST	(P2)		;RETURN
SUBTTL	UTILITY ROUTINES

;ROUTINE TO RELOCATE I/O BUFFER ADDRS
;CALL:;	PUSHJ	P,TPMXCI, OR TPMXCO
;	<INSTR TO EXECUTE W/ T1 RELOCATED>
;	RETURN HERE WITH T1 ALREADY RELOCATED
;ALL ACS EXCEPT T1 ARE PRESERVED
;INSTR MUST NOT REFERENCE P1-P4

TPMXCO:	SKIPA	T1,DEVOAD(F)	;USE OUTPUT BUFFER
TPMXCI:	MOVE	T1,DEVIAD(F)	;USE INPUT BUFFER
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVE	P2,@-3(P)	;GET INSTR TO XCT
	MOVE	P1,DEVTYP(F)	;SEE WHAT WE HAVE
	TRNN	P1,DEPEVM	;SKIP IF NO TM10A
	MOVEI	T1,@T1		;RELOCATE KA STYLE
	CONSZ	PI,II.IPA	;SKIP IF AT UUO LEVEL
	JRST	[PUSHJ P,SVEUF##;ELSE - SET UP UBR
		 PUSHJ P,SPCS##	;AND PCS
		 JRST .+1]	;AND CONTINUE
	SKIPE	DEVEVM(F)	;EVM IN USE?
	TLZ	P2,(<17B12>)	;CLEAR AC FIELD
IFN FTMP,<PUSH	P,T1>		;SAVE ADDRESS
	XCT	P2		;CLANK INSTR
IFE FTMP,<JRST	CPOPJ1##>	;RETURN & SKIP OVER INSTR
IFN FTMP,<
	EXCH	T1,(P)		;SAVE T1, GET ADDR
	PUSHJ	P,OUCHE##	;SWEEP THAT LOC OUT OF CACHE
	JRST	TPOPJ1##	;SKIP XCT'D INSTR AND RETURN
> ;END IFN FTMP

;ROUTINE TO GENERATE A PENDING IORB
;CALL:	MOVE	P2,FUNCTION
;	PUSHJ	P,GENIOR
;	  ...  ERROR IF NO FREE SPACE
;	RETURN HERE  T1 := IORB

GENIOR:	MOVEI	T2,TRBLEN	;WORDS NEEDED FOR AN IORB
	PUSHJ	P,GETWDS##	;ALLOCATE CORE
	  POPJ	P,		;SIGH
	MOVSI	T2,0(T1)	;START ADDRESS
	HRRI	T2,1(T1)	;MAKE A BLT POINTER
	SETZM	(T1)		;CLEAR FIRST WORD
	BLT	T2,TRBLEN-1(T1)	;CLEAR IORB
	MOVEI	T2,RB.RPN	;REQUEST PENDING
	ROT	T2,-RB.RQP-1	;PUT IN PROPER PLACE
	MOVEM	T2,TRBFNC(T1)	;STASH
GNIOR1:	DPB	P2,PRBFCN##	;AND FUNCTION
	LDB	T2,TDYBYT	;GET MODE/PAR/DEN
	TRZ	T2,TDMDBY	;CLEAR ACTUAL DENSITY
	PUSH	P,T1		;SAVE IORB ADDRESS
	PUSH	P,T2		;AND P/D/M CUZ GETDEN TRASHES THEM
	XMOVEI	T2,IRBCCW(T1)	;***POINT TO BASE OF CCW TABLE
	MOVEM	T2,IRBACC(T1)	;***SET AS CURRENT
	PUSHJ	P,GETDEN	;GET THE DENSITY WE SHOULD USE
	LSH	T1,RB.MDS	;POSITION DENSITY AFTER MODE
	IORM	T1,(P)		;SAVE IT IN "BYT"
	POP	P,T2		;GET "BYT" BACK
	POP	P,T1		;AND THE ADDRESS
	DPB	T2,PRBBYT##	;SET INTO IORB
	SETZM	TRBSTS(T1)	;CLEAR REST OF BLOCK
	SETZM	TRBRCT(T1)
	SETZM	IRBIVA(T1)	;...
	JRST	CPOPJ1##	;GIVE GOOD RETURN
;ROUTINE TO SET UP CURRENT IORB

STOIOR:	ROT	T2,-RB.RQP-1	;POSITION STATUS
	HLLM	T2,TRBFNC(T1)	;STORE IN LHS
	JRST	GNIOR1		;CONTINUE SETUP
;ROUTINE TO WAIT FOR TAPE KONTROLLER

KONWAT:	MOVSI	T1,TKSOFL##	;IF UNIT IS OFF-LINE
	TDNN	T1,TUBSTS(U)	; DON'T CALL MSLEEP
	PUSHJ	P,CKREW		;CHECK FOR REWINDING
	JRST	KONWTN		;NOW SEE IF SELECTED
KONWT1:	PUSHJ	P,TAPCNT##	;MAKE SURE SCHED IS LISTENING
	MOVEI	T1,EV.TKW	;WAIT FOR TAPE KONTROLLER
	PUSHJ	P,KSLEEP	;WAIT FOR EVENT
				;RETURN WHEN READY
KONWTN:	MOVSI	T1,TKSSEL##	;SEE IF WE GOT ONE
	TDNN	T1,TUBSTS(U)	;??
	JRST	KONWT1		;NOPE - TRY AGAIN
	HRRZ	P1,TUBQUE(U)	;SET P1 TO POINT TO IORB
	MOVE	W,TUBAKA(U)	;SET UP WITH ACTIVE KDB ADDRESS
	TLZ	W,(1B0)		;CLEAR POSSIBLY INVALID BIT
	CAME	P1,TDVIOR(F)	;THIS THE RIGHT ONE?
	JRST	KONWT2		;NO - SNOOZE SOME MORE
	SETZM	TDVIOR(F)	;CLEAR THIS ONE NOW
IFN FTMP,<PUSHJ P,TAPCPU##>	;MAKE SURE WE'RE ON CPU WITH A VALID KDB
	POPJ	P,		;RETURN
KONWT2:	CAIE	P1,TKBERB(W)	;IS IT THE ERP IORB (NEVER HAS IVA)
	SKIPE	IRBIVA(P1)	;IS THIS A "REAL" IORB?
	JRST	KONWT1		;YES, REST ASSURED THAT SOMETHING WILL HAPPEN
	PUSHJ	P,TAPREM##	;NO, ITS AN IORB WHICH WILL NEVER BE USED
	JRST	KONWTN		; SO FLUSH IT AND TRY THE NEXT IORB

;ROUTINE TO WAIT FOR DRIVE TO FINISH REWINDING

CKREW:	MOVSI	T2,TUSREW##	;CHECK FOR REWIND
	TDNN	T2,TUBSTS(U)	;...
	POPJ	P,		;NOPE - RETURN
	PUSH	P,TDVIOR(F)	;SAVE IORB PNTR

CKREW1:	MOVEI	T1,TUCIRD##	;SEE IF THIS UNIT
	TDNE	T1,TUBCNF(U)	;  WILL GIVE US AN INTERUPT
	JRST	CKREW2		;WHEN IT FINISHES REWINDING
	MOVSI	T1,TKSSTD##	;NO - UNIT ALREADY ACTIVE?
	TDNE	T1,TUBSTS(U)	;...
	JRST	CKREW2		;YES - HAVEN'T STARTED REWINDING YET
	MOVEI	P2,RB.FYB	;QUE UP WAIT REQUEST
	PUSHJ	P,GENIOR	;GEN IORB
	  JRST	CKREW2		;WAIT AND TRY AGAIN
	MOVEM	T1,TDVIOR(F)	;STASH AWAY
	XMOVEI	T2,CKREWD	;GO HERE ON INTERUPT
	MOVEM	T2,IRBIVA(T1)	;...
	PUSHJ	P,CPURQH##	;PUT AT HEAD OF Q
	PUSHJ	P,KONWTN	;WAIT FOR SELECTION
				;RETURN P1 := IORB
	PUSHJ	P,TPSTRT	;GO START I/O?
	MOVEI	T1,EV.REW	;WAIT FOR REWIND STATUS
	PUSHJ	P,MSLEEP	;...
				;FALL INTO CKREW2
				;PREVIOUS PAGE FALLS INTO THIS
CKREW2:	MOVSI	T2,TUSREW##	;SEE IF STILL REWINDING
	TDNN	T2,TUBSTS(U)	;...
	JRST	NOREW		;NO MORE

;AVOID STACK OVERFLOWS BY INSURING THAT IF TAPCNT ENDS UP CALLING THRU
;AND BACK TO CKREW WE WILL BE ON THE CORRECT CPU NEXT TIME.
IFN FTMP,<PUSHJ	P,TAPCPU##>	;MAKE SURE WE STAY ON THE RIGHT CPU
	PUSHJ	P,TAPHLD##	;DON'T USE US WHILE SLEEPING
	MOVEI	T1,2		;SLEEP 2 SEC
	PUSHJ	P,TSLEEP	;ZZZZ
	PUSHJ	P,TAPCNT##	;OK - START LOOKING AGAIN
	JRST	CKREW1		;CHECK SOME MORE
;HERE WHEN NOT REWINDING

NOREW:	POP	P,TDVIOR(F)	;RESTORE WORLD
	POPJ	P,		;RETURN

;HERE ON STATUS INTERUPT

CKREWD:	MOVE	T1,J		;JOB #
	PUSHJ	P,EWAKE##	;WAKE IT
	MOVE	S,DEVIOS(F)	;SET UP S
	PJRST	TPMSTP		;SHUT DOWN CTL

;ROUTINE TO SET UP INTERESTING ACS
;SET UP - U,J

SETACS:	MOVE	U,TDVUDB(F)	;UDB ADDRESS
;IFN FTTLAB,<
;	MOVSI	J,TKSSEL	;IF UNIT IS ALREADY GOING...
;	TDNN	J,TUBSTS(U)	;...DON'T CHANGE TUBCUR
;>;END IFN FTTLAB
;	MOVEM	F,TUBCUR(U)	;LINK UDB TO CURRENT DDB
	LDB	J,PJOBN##	;GET JOB OWNING DDB
	POPJ	P,		;AND RETURN

;SPECIAL ROUTINE USED BY NON-IO REQUESTS

PIOSET:	PUSHJ	P,SETACS	;SET UP ACS
	MOVE	S,DEVIOS(F)
	JUMPE	J,CPOPJ##	;EXIT NOW IF NOBODY THERE
	JRST	IOSET0		;CONTINUE OPERATION
;ROUTINE TO SLEEP,RESTORE S
TSLEE1::MOVEI	T1,1		;SLEEP 1 SEC
TSLEEP:	MOVE	J,.CPJOB##	;SET UP J FOR SLEEP
IFN FTPSCD,<
	AOS	%MTASL##	;COUNT MTA GENERATED SLEEP
>;END IFN FTPSCD
TSLEE2:	PUSHJ	P,SLEEPF##	;SLEEP ZEROES F
	MOVE	S,DEVIOS(F)	;NEW UNIT STATE
	POPJ	P,
;SETUP ROUTINES FOR INPUT AND OUTPUT

INSET:	TLZA	S,IO

OUTSET:	TLO	S,IO
IOSET:	PUSHJ	P,SETACS	;GET GOOD THINGS
	JUMPE	J,CPOPJ##	;RETURN IF NO OWNER
IFN FTTLAB,<
	PUSHJ	P,LBLSLP	;WAIT FOR LABEL PROCESS TO FINISH
	PUSHJ	P,LBLCKS	;DETERMINE IF PROCESSING NEEDED
	  JFCL			;IGNORE THIS RETURN
> ;END IFN FTTLAB
	PUSHJ	P,TAPACC##	;TRY TO FIND AN ONLINE KONTROLLER
	  JFCL			;...
	MOVSI	T1,TKSOFL##	;IF KONTROLLER ISN'T OK
	TLZE	S,OFFLIN	;OFFLINE IN DEVIOS?
	TDNN	T1,TUBSTS(U)	;OFFLINE IN TUBSTS?
	TDNE	T1,TKBSTS(W)	;NO. KONT. OFFLINE?
	JRST	SETOFL		;YES. INDICATE IT
IFN FTTLAB,<
	MOVEI	T1,FINP!LBLNED	;ASSUME INPUT
	TLNE	S,IO		;IS IT?
	MOVEI	T1,FOUT!LBLNED	;NO, CHECK OUTPUT
	TLNE	S,(T1)		;PROCESSING NEEDED?
	JRST	SETLBL		;YES, INVOKE LBL PCS
> ;END IFN FTTLAB
IOSET0:	TLZ	S,OFLUNH	;CLR THIS
	PUSHJ	P,GTMODE	;GET THE RIGHT MODE
	CAILE	T1,RB.M7T	;"REAL" MODE?
	MOVEI	T1,RB.MBY	;NO, INDUSTRY COMPAT. SET UP FOR CORE-DUMP
	DPB	T1,TDYMOD	;PUT IT BACK

	CAIE	T1,RB.M7T	;SEE IF 7 TRACK
	JRST	IOSET2		;NO - DON'T PLAY WITH PARITY
	MOVSI	T1,D.EPAR	;GET BIT
	ANDCAM	T1,TDVSTS(F)
	TRNE	S,IOPAR		;WANT EVEN OR ODD PARITY?
	IORM	T1,TDVSTS(F)
IOSET2:	PJRST	STOIOS##	;STORE S AND RETURN

;ROUTINE TO GET THE RIGHT MODE FOR A TAPE
;RETURNS T1=MODE
GTMODE:	LDB	T1,TDYMOD	;SEE IF WE HAVE A MODE
	JUMPN	T1,CPOPJ##	;JUMP IF MODE SET
	LDB	T1,TDYMD1	;NONE FROM TAPE. SET FORMAT BEEN ISSUED?
	JUMPN	T1,CPOPJ##	;GO IF IT HAS
	MOVEI	T1,RB.MCD	;DEFAULT TO 4.5 BYTE MODE
	LDB	T2,PIOMOD##	;GET MODE
	CAIN	T2,BYTMOD	;BYTE MODE?
	MOVEI	T1,RB.MBY	;YES
	MOVEI	T2,TUC7TK##	;UNLESS 7 TRACK
	TDNE	T2,TUBCNF(U)	;??
	MOVEI	T1,RB.M7T	;THEN USE 7-TRACK MODE
	POPJ	P,
;HANDLE OFF LINE MESSAGES AND CLEAR ERRORS FOR RE-TRY
;ALSO CHECK FOR TC10C SPECIAL ACTION

SETOFL:	PUSHJ	P,CKTC10	;TC10C CROCK!!!
	  PUSHJ	P,HNGSTP##	;OUTPUT MESSAGE
	PJRST	IOSET		;RESET ACS AND RETURN

;TC10C CONTROLLER SPECIAL ACTION FOR OFF-LINE AT BOT

CKTC10:	LDB	T1,TUYKTP##	;GET KONTROLLER TYPE
	CAIN	T1,K.TC1	;IS IT ONE OF THOSE?
	TLCE	S,OFLUNH	;BEEN HERE BEFORE?
	JRST	STOIOS##	;YES, SAY OFF-LINE
	MOVEM	S,DEVIOS(F)	;REMEMBER FIRST TRY
	PUSHJ	P,TSLEE1	;SLEEP FOR 1 SEC
	JRST	CPOPJ1##	;TRY AGAIN - IT MIGHT BE BACK

IFN FTTLAB,<
;ROUTINE TO CHECK TAPE LABEL STATUS AND FIRST OPERATION
;SKIP RETURN IF NO PROCESSING TO BE DONE

LBLCHK:	TLZE	S,IOBEG		;CHECK FOR FIRST I/O
	TLO	S,FSTOP		;AND SET THIS ONE
LBLCKM: PUSH	P,T1		;SAVE T1
	PUSH	P,F		;SAVE F
	TLZ	F,-1-MXSECN	;CLEAR POSSIBLE JUNK
	CAME	F,TUBDDL(U)	;LABEL DDB OURS?
	SKIPN	%SITLP##	;AND IS THE LABELER ALIVE?
	JRST	LBLCK2		;NO PROCESSING
	LDB	T1,TUYLTP	;GET LABEL TYPE
	JUMPE	T1,LBLCK2	;IF NO LABELS, CLEAR SOME FLAGS
	TDZ	S,[IOSTBL!LBLEOF!LBLSTP,,IODEND] ;DON'T LET SEE EOF OR TROUBLE
	PUSHJ	P,STOIOS##	;STORE S
	POP	P,F		;RESTORE F
	JRST	TPOPJ##		;RESTORE T1
LBLCK2:	TLZ	S,LBLNED!FSTOP	;ELSE CLEAR THESE FLAGS
	MOVEM	S,DEVIOS(F)	;...
	POP	P,F		;RESTORE F
	JRST	TPOPJ1##	;SKIP RETURN
> ;END IFN FTTLAB
IFN FTTLAB,<
;ROUTINE TO INVOKE LABELING PROCESS AND SUSPEND JOB

LBLMSG:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVEI	T1,MT.WAT	;GET CODE FOR WAIT
	PUSHJ	P,MTAP		;WAIT FOR THINGS TO DIE DOWN
	PUSHJ	P,TAPHLD##	;SUSPEND UNIT FOR NOW
	TLZ	S,LBLNED	;CLEAR THIS NOW
	TLO	S,LBLWAT	;WE ARE NOW WAITING FOR COMPLETION
	MOVEM	S,DEVIOS(F)
	PUSH	P,W		;SAVE W
	PUSHJ	P,LBLSND	;INFORM LBL PCS
	POP	P,W		;RESTORE W
	SETZ	T1,		;CLEAR
	DPB	T1,TUYINF	;MSG INFO
	DPB	T1,TUYRQT	;AND REQUEST TYPE
	PUSHJ	P,LBLSLP	;WAIT FOR LABEL PROCESS
	LDB	T1,PDVESE##	;GET TERMINATION CODE
	SKIPGE	LBLETB(T1)	;LEGAL TO SET?
	POPJ	P,		;NO
	TDO	S,LBLETB(T1)	;GET ERROR BITS FROM TABLE
	PJRST	STOIOS##	;STORE S AND RETURN


;ROUTINE TO SEND ABORT MSG
LBLABO::MOVEI	T1,LR.ABO	;GET ABORT CODE
	DPB	T1,TUYRQT	;SET REQUEST TYPE
	PJRST	LBLSND		;SEN MESSAGE OFF

;ROUTINE TO SEND IPCF MSG TO LBL PROCESS

LBLSND:	MOVE	T1,DEVNAM(F)	;YES - BUILD MSG
	MOVEM	T1,TUBPHY(U)	;STORE DEVICE NAME
	LDB	J,PJOBN##	;RESET J INCASE IT HAS CHANGED
	DPB	J,TUYJBN	;STORE JOB #
	MOVE	T1,[TLMSIZ,,.IPCTL##] ;LENGTH,,MESSAGE TYPE
	MOVEM	T1,TUBMSG(U)	;STORE

IFE FTXMON,<MOVEI T2,TUBMSG(U)> ;ADDRESS OF MESSAGE
IFN FTXMON,<
LBLSN1:	MOVEI	T2,TLMSIZ	;LENGTH OF MESSAGE
	PUSHJ	P,GETWDS##	;GET CORE
	  SKIPA			;NONE AVAILABLE
	JRST	LBLSN2		;ONWARD
	PUSHJ	P,TSLEE1	;ZZZZZZ
	JRST	LBLSL1		;TRY AGAIN
LBLSN2:	PUSH	P,T1		;SAVE ADDRESS
	MOVEI	T1,TLMSIZ	;LENGTH IN WORDS
	XMOVEI	T2,TUBMSG(U)	;STATIC STORAGE
	MOVE	T3,(P)		;IPCF MESSAGE
	EXTEND	T1,[XBLT]	;COPY
	MOVE	T2,(P)		;ADDRESS OF MESSAGE
> ;END IFN FTXMON

	MOVEI	T1,%SITLP##	;PID
	HLL	T2,TUBMSG(U)	;MESSAGE MSGE
	PUSHJ	P,SENDSI##	;TRANSMIT MESSAGE
	  JFCL			;IGNORE ERRORS
IFN FTXMON,<
	MOVEI	T1,TLMSIZ	;MESSAGE LENGTH
	POP	P,T2		;MESSAGE ADDRESS
	PUSHJ	P,GIVWDS##	;RELEASE CORE
> ;END IFN FTXMON
	POPJ	P,		;RETURN

;ROUTINE TO FIX UP S AS IF LABEL PROCESSING HAPPENED
LBLCKS:	PUSHJ	P,LBLCHK	;FIRST CALL LABEL CHECK
	  POPJ	P,		;NEED LABELLING, DO NOTHING
	TLZN	S,LBLEOF	;HERE FOR EOF?
	JRST	CPOPJ1##	;NO, JUST RETURN
	TLZ	S,IOSTBL	;CLEAR TROUBLE
	TDO	S,[LBLSTP,,IODEND]	;STOP ON LBL ERR
	MOVEM	S,DEVIOS(F)	;STORE STATUS
	JRST	CPOPJ1##	;RETURN

;ROUTINE TO WAIT FOR LABEL PROCESS TO FINISH
LBLSLP:	PUSH	P,T1		;SAVE T1
LBLSL1:	TLNN	S,LBLWAT	;STILL WAITING?
	JRST	TPOPJ##		;NO, RETURN
	MOVEI	T1,EV.LBL	;EW CODE FOR LABELS
	PUSHJ	P,MSLEEP	;GO AWAY
	JRST	LBLSL1		;CHECK IF REALLY DONE

		;;; STILL IN FTTLAB CONDITIONAL

;ENTER HERE FROM IOSET IF LABEL PROCESSING NEEDED
SETLBL:	TLNN	S,FSTOP		;FIRST OPERATION?
	JRST	STLBL1		;NO - PROCEED
	MOVEI	T1,LR.FIN	;ASSUME FIRST INPUT
	TLNE	S,IO		;IS IT REALLY?
	SKIPA	T1,[LR.FOU]	;NO, FIRST OUTPUT THEN
	TLZA	S,FINP		;CLEAR FIRST INPUT
	TLZ	S,FOUT		;CLEAR FIRST OUTPUT
	DPB	T1,TUYRQT	;SET REQUEST TYPE
	MOVEM	S,DEVIOS(F)
STLBL1:	PUSHJ	P,LBLMSG	;INFORM LBL PCS
	TLNN	S,LBLSTP	;LABELING ERROR?
	JRST	IOSET		;NO--PROCEED
	POPJ	P,		;ELSE RETURN UP A LEVEL

;ROUTINE TO CHECK FOR LABEL PCS HNDLING POSITION REQUESTS

LBLPOS:	MOVE	U,TDVUDB(F)	;SET UP U
	DPB	T1,TUYINF	;SET UP MTAPE CODE
	MOVE	S,DEVIOS(F)	;SET UP STATUS
	PUSHJ	P,LBLCKM	;NEED LABELING?
	  SKIPA	T1,[LR.POS]	;YES - SET POSITION REQ.
	JRST	CPOPJ1##	;NO - PROCEED
	DPB	T1,TUYRQT	;SET REQUEST TYPE
	PUSHJ	P,LBLMSG	;XMIT MSG
	TLZ	S,LBLSTP	;NEVER NEED THIS BIT ON POSITIONING
	LDB	T1,PDVESE##	;GET TERMINATION CODE
	CAIN	T1,LE.CON	;DID HE DO ANYTHING?
	AOS	(P)		;NO - SKIP RETURN
	PJRST	STOIOS##	;STORE S AND RETURN

; TABLE TO TRANSLATE LABEL TERM CODE INTO BITS IN IOS
; THE CODE DEPENDS ON THE SIGN BIT **NEVER** BEING USED

LBLETB:	-1			;0 - ILLEGAL
	0			;1 - CONTINUE POSITIONING
	LBLSTP!FSTOP!IOEND,,IODEND ;2 - RETURN EOF + CALL LABEL PCS ON NEXT I/O
	FSTOP!LBLSTP,,IOERRS	;3 - LABEL TYPE ERROR
	FSTOP!LBLSTP,,IOERRS	;4 - HEADER LABEL ERROR
	FSTOP!LBLSTP,,IOERRS	;5 - TRAILER LABER ERROR
	FSTOP!LBLSTP,,IOERRS	;6 - VOLUME LABEL ERROR
	FSTOP!LBLSTP,,IODERR	;7 - DEVICE ERROR
	FSTOP!LBLSTP,,IODTER	;10 - DATA ERROR
	FSTOP!LBLSTP,,IOERRS	;11 - WRITE LOCKED
	FSTOP!LBLSTP,,IOERRS	;12 - POSITIONING ERROR
	FSTOP,,IOBOT		;13 - BEGINNING OF TAPE
	FSTOP!LBLSTP,,IOERRS	;14 - ILLEGAL OPERATION
	FSTOP!LBLSTP,,IOERRS	;15 - FILE NOT FOUND
	FSTOP!LBLSTP,,IOERRS	;16 - OPR CANCELED VOLUME SWITCH
	FSTOP!LBLSTP,,IOERRS	;17 - TOO MANY VOLUMES IN VOLUME SET
	-1			;20 - ILLEGAL FOR MAGTAPES
	-1			;21 - ILLEGAL FOR MAGTAPES
	-1			;22 - ILLEGAL FOR MAGTAPES
	FSTOP!LBLSTP,,IOERRS	;23 - LABELER REQUEST ABORTED BY RESET UUO
	FSTOP!LBLSTP,,IOERRS	;24 - VOLUME PROTECTION FAILURE
	FSTOP!LBLSTP,,IOERRS	;25 - FILE PROTECTION FAILURE
	FSTOP!LBLSTP,,IOERRS	;26 - UNEXPIRED FILE
	-1			;27 - ILLEGAL FOR MAGTAPES

IFN <IOMAX%-<.-LBLETB-1>>,<PRINTX ? LABEL ERROR TRANSLATION TABLE SKEW>

> ;END IFN FTTLAB
;ROUTINE TO GET CURRENT DENSITY SETTING
;RETURN DENSITY ARG IN T1

GETDEN:	LDB	T1,PDENS	;SEE IF CHANGED BY SETSTS
	JUMPN	T1,CPOPJ##	;IF YES - USE IT
	LDB	T1,TDYDN1	;SEE IF CHANGED BY SET DENSITY
	JUMPN	T1,CPOPJ##	;IF YES, TRY IT
	LDB	T1,TDYDEN	;NOT CHANGED, CHECK FOR ACTUAL
	JUMPN	T1,CPOPJ##	;IE WAS, USE IT
GETDN1:	MOVEI	T1,STDENS##	;ELSE USE STANDARD
	MOVE	T2,TUBCNF(U)	;PICK UP CONFIGURATION WORD
	PUSH	P,T1		;SAVE THE DENSITY FOR A MOMENT
GETDN2:	TDNE	T2,DENBIT(T1)	;THIS DENSITY OK?
	  JRST	GETDN4		;YES
	SOJG	T1,GETDN2	;NO, TRY A LOWER ONE
	MOVE	T1,(P)		;NO LOWER ONES ARE ANY GOOD, TRY HIGHER ONES
GETDN3:	TDNN	T2,DENBIT(T1)	;THIS DENSITY OK?
	AOJA	T1,GETDN3	;NO, TRY A HIGHER ONE
GETDN4:	POP	P,(P)		;GET RID OF ORIGINAL DENSITY
	DPB	T1,TDYDN1	;SAVE DEFAULT DENSITY
	POPJ	P,		;AND RETURN

DENBIT=.-1			;SAVE A WORD
	TUCD20##
	TUCD55##
	TUCD80##
	TUCD16##
	TUCD62##

;ROUTINE CALLED TO SWEEP CACHE UNLESS DEVICE IS A TM10A
;DESTROYS T1
TPMSWP:	MOVEI	T1,DEPEVM	;DOES THIS DEVICE NEED
	TDNN	T1,DEVTYP(F)	; EVM (TM10A IF SO)
	POPJ	P,		;YES, DONT SWEEP
IFN FTKL10,<
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	MOVSI	P1,-MXPORT	;AOBJN POINTER
	XMOVEI	P2,UDBKDB(U)	;POINT TO START OF KONTROLLER TABLE
	SETZ	P3,		;CLEAR A COUNTER

TPMSW1:	SKIPN	T1,(P2)		;GET A KDB ADDRESS
	JRST	TPMSW2		;NONE THERE
	AOS	P3		;COUNT THE KDB
	MOVE	T1,KDBCHN(T1)	;GET CHANNEL DATA BLOCK ADDRESS
	MOVE	T1,CHNTYP(T1)	;AND ASSOCIATED CHANNEL BITS
	TLNN	T1,CP.RH2	;EXTERNAL CHANNEL?
	JRST	TPMSW3		;YES, MUST SWEEP

TPMSW2:	AOS	P2		;ADVANCE TABLE POINTER
	AOBJN	P1,TPMSW1	;LOOP FOR ALL KDBS
	SOJLE	P3,CPOPJ##	;NO CACHE SWEEP IF ONLY ONE PATH
> ;END IFN FTKL10

TPMSW3:	PUSHJ	P,CSDMP##	;WE MUST SWEEP THE CACHE
IFN FTMP,<MOVMS	.CPTAP##>	;TELL ONCE-A-TICK IT DOESNT HAVE TO SWEEP
	POPJ	P,		;RETURN


;ROUTINE TO DO UUO-LEVEL DRIVE ACCESSIBILITY CHECKING
TPMACC::PUSH	P,T1		;SAVE T1
IFN FTMP,<
	LDB	T1,DEYPCL##	;CHECK FOR QUEUED PROTOCOL
	SKIPN	T1		;IF NOT ENABLED,
	PUSHJ	P,TAPCPU##	;GET ON THE RIGHT CPU NOW
> ;END IFN FTMP

TPMAC1:	PUSHJ	P,TAPACC##	;FIND CPU-KDB-UDB PATH
	  TDZA	T1,T1		;CAN'T GET TO DRIVE??
IFE FTMP,<JRST	TPMAC3>		;GO SET ACTIVE KDB
IFN FTMP,<
	MOVE	T1,KDBCAM(W)	;GET ACCESSIBILITY MASK FOR KONTROLLER
	TDNE	T1,.CPBIT##	;ON OUR CPU?
	JRST	TPMAC2		;YES
	MOVSI	T1,TUSREW##	;BIT TO TEST
	TDNN	T1,TUBSTS(U)	;WAITING FOR REWIND COMPLETION?
	JRST	TPOPJ##		;NO, INITIATE QUEUED PROTOCOL I/O
> ;END IFN FTMP
	PUSHJ	P,CKREW		;WAIT FOR REWIND TO FINISH
	JRST	TPMAC1		;CHECK AGAIN
IFN FTMP,<
TPMAC2:	MOVE	T1,.CPCPN##	;GET OUR CPU NUMBER
	PUSHJ	P,ONCPUN##	;MAKE SURE WE STAY THERE
> ;END IFN FTMP

TPMAC3:	MOVEM	W,TUBAKA(U)	;SET ACTIVE KDB
	JRST	TPOPJ1##	;RETURN AND START I/O
;SETUP S AND TRANSLATE ERROR BITS FOUND IN IORB
;NON-SKIP RETURN IF ERROR ENCOUNTERED
;SKIP RETURN IF ALL OK - MAYBE EXCEPTION

SETIOS:	MOVE	S,DEVIOS(F)	;GET STATUS
	HLRZ	T1,TRBSTS(P1)	;GET IORB STATUS
IFN FTTLAB,< TDZ S,[LBLNED!FSTOP!IOEND!IOSTBL!LBLEOF!LBLSTP,,IOBOT!IOTEND!IODEND]>
IFE FTTLAB,< TDZ S,[IOEND!IOSTBL,,IOBOT!IOTEND!IODEND]>
				;CLEAR ALL RELATED BITS
	SKIPL	TRBFNC(P1)	;ANY EXCEPTIONS?
	JRST	SETIOX		;NO - JUST STORE AND EXIT
	TRNE	T1,RB.SOL	;CHECK OFF-LINE
	PJRST	STOIOS##	;STORE S AND RETURN
	TRNE	T1,RB.STM	;TAPE MARK SEEN
IFN FTTLAB,< TDO S,[LBLNED,,IODEND]> ;YES - SAY EOF
IFE FTTLAB,< TRO S,IODEND>	;YES - SET EOF
	TRNE	T1,RB.SBT	;BOT SEEN
	TRO	S,IOBOT		;MARK IT
	TRNE	T1,RB.SET	;TAPE INDICATE
	TRO	S,IOTEND	;SET EOT
IFN FTTLAB,<
	LDB	T2,PDVESE##	;ANY LABELLING ERROR
	SKIPL	LBLETB(T2)	;LEGAL TO SET?
	TDO	S,LBLETB(T2)	;YES
	LDB	T2,TUYLTP	;GET LABEL TYPE
	SKIPE	%SITLP##	;IS THERE A TAPE LABEL PROCESS?
	SKIPN	T2		;BYPASS?
	TLZ	S,LBLNED	;YES - CLEAR BIT
	TLNN	S,LBLNED
	TRNE	T1,RB.SED!RB.SDE!RB.STL!RB.SLK!RB.SIL	;NON-SKIP IF ERRORS OR
	SKIPA			;NEED LABEL ACTION
> ;END IFN FTTLAB
IFE FTTLAB,<
	TRNN	T1,RB.SED!RB.SDE!RB.STL!RB.SLK!RB.SIL	;NON-SKIP IF ERRORS
>
SETIOX:
IFE FTMP,<AOS	(P)>		;INDICATE GOODNESS
IFN FTMP,<
	AOSA	(P)		;INDICATE GOODNESS
	PJRST	STOIOS##	;STORE S AND RETURN
	LDB	T1,PIOMOD##	;IF BUFFERED MODE
	CAIGE	T1,SD
	TRNN	S,IODEND	; IF NOT EOF
	CAIA
	POPJ	P,		;EOF - DON'T STORE IODEND IN DDB
> ;END IFN FTMP
	PJRST	STOIOS##	;STORE S AND RETURN
;ROUTINE TO GENERATE I/O XFER LIST FROM IOWD
;CALL:	MOVE	T2,IOWD
;	MOVE	T4,NUMBER OF BYTES
;	PUSHJ	P,MAKLST
;	... RETURN HERE IF NO ROOM
;	RETURN HERE IF OK

MAKLST:	PUSHJ	P,SAVE4##	;SAVE WORLD
	MOVE	P1,T2		;COPY UNRELOCATED IOWD
	PUSHJ	P,SVEUF##	;MAKE JOB ADDRESSABLE
	PUSHJ	P,SPCS##	;ANS SETUP PCS
	MOVEM	P1,TRBRCT(T1)	;SAVE NUMBER OF WORDS, UVA IN IORB (FOR TM2KON/TD2KON)
	LDB	P4,PRBMOD##	;GET MODE
	MOVE	P4,TMODTB##(P4)	;CHARS/WD TABLE (4,5,6)
	LDB	T3,PBUFRM	;MAX FRAME COUNT USER GAVE
	JUMPE	T3, MAKLS0	;USER SPECIFY MAX FC?
	SKIPE	T4		;YES, T4=0 FOR CORE DUMP
	CAMG	T3,T4		;T4 NON-ZERO MEANS BYTE MODE
	MOVE	T4,T3		;USE MAX FRAME COUNT
MAKLS0:	MOVE	T3,T4
	HRL	P4,T3		;IN LH (P4)
	MOVNS	T3
	SKIPE	T3		;IF BYTE MODE, SAVE
	HRLZM	T3,TRBRCT(T1)	;-BYTE COUNT,,UVA FOR TM2KON/TD2KON
	MOVEI	T1,DEPDER	;ERROR RETRY ENABLED?
	TDNN	T1,DEVSTA(F)
	TDNE	S,[MTSNAR,,IONRCK]
	TLOA	S,IOSRTY	;NO, DON'T LET DX10 RETRY
	TLZ	S,IOSRTY	;YES, TELL DX TO RETRY
	MOVE	P3,KDBCHN(W)	;ADDRS OF CHNCB
	HRRZ	T1,TUBQUE(U)	; RESTORE LOC OF IORB
IFN FTKS10,<
	LDB	P1,PRBFCN##	;GET FUNCTION
	CAIN	P1,RB.FRB	;READ BACKWARDS?
	SETOM	CHNRRV(P3)	;YES -- SET READ REVERSE FLAG
	TLO	P3,400000	;FLAG TO FORCE MAPIO TO STORE EXPECTED FINAL BUS ADDRESS
	MOVEI	P1,0		;INITIAL CALL TO MAPIO
	PUSHJ	P,MAPIO##	;SET UP UNIBUS ADAPTER REGISTERS
	  CAIA			;WE LOST SOMEHOW!!
	AOS	(P)		;SET FOR SKIP RETURN
	SETZM	CHNRRV(P3)	;CLEAR READ REVERSE FLAG
	POPJ	P,		;RETURN
>;END IFN FTKS10
IFE FTKS10,<
	MOVEI	P2,DEPEVM
	TDNN	P2,DEVTYP(F)	;SKIP IF OTHER THAN TM10A
	JRST	MAKLS1		;TRY KA10 STYLE
	MOVEI	P1,0		;INIT CALL TO MAPIOW
	PUSHJ	P,MAPIO##	;MASSAGE IOWD
	  PJRST	MAKLSE		;NO FREE SPACE - RELEASE ANY PARTIAL IOWD LIST
IFN FTKL10,<
;MAKE MULTI-IOWD LIST IF TU70
	MOVEI	T4,1		;AT LEAST ONE RECORD WILL BE DONE
	MOVEM	T4,TKBCNT(W)
IFN FTMP,<
	TLNN	S,IO		;OUTPUT?
	JRST	MAKL0A
	PUSH	P,T1		;YES, FIND OUT HOW MANY BUFS WE CAN DO
	PUSHJ	P,CHKNB##
	POP	P,T1
	MOVSI	T4,-1		;DECREMENT NUMBER OF BUFS SWEPT FOR
	ADDB	T4,DEVNBF(F)
	TLNE	T4,-1		;DONE IF NO MORE AVAILABLE
> ;END IFN FTMP
MAKL0A:	TRNE	S,IOCON		;DISCONTINUOUS MODE?
	JRST	CHNDON		;YES, DONE
	MOVE	T4,KDBDSP(W)	;DRIVER DISPATCH
	SKIPN	TUBCNI(U)	;NO ERRORS DETECTED ON LAST XFER?
	SKIPN	TPKCCF(T4)	; AND DEVICE SUPPORT COMMAND CHAINING?
	JRST	CHNDON		;NO, ONLY DO 1 RECORD
	LDB	T4,PRBFCN##	;YES, IS IT BUFFERRED MODE,
	LDB	T3,PIOMOD##	; AND NOT READ-BACKWARD?
	CAIE	T4,RB.FRB
	CAIL	T3,SD
	JRST	CHNDON		;NO, ONLY 1 RECORD
	TLNE	S,IO		;READING?
	JRST	MAKL0B
	HRROI	T2,-1(T2)	;YES, SET UP TO ASK DX10 TO STORE WRDCNT
	PUSHJ	P,MAPIO##
	  JRST	MAKL0B
	MOVE	T4,KDBDSP(W)	;NOW THAT WE HAVE A "REAL" IOWD
	PUSHJ	P,@TPKCMD(T4)	; ASK TX1KON TO MASSAGE IT INTO WHAT DX10 WANTS
	  JFCL			;ALWAYS COMES BACK NON-SKIP
MAKL0B:	HRRZ	T4,DEVIAD(F)	;YES, GET BUFFER LOC
	TLNE	S,IO
	HRRZ	T4,DEVOAD(F)
	MOVE	T3,T4		;START AT THAT BUFFERS SUCCESSOR
	HRL	P2,T1		;SAVE LOC OF IORB IN P2 (FOR TPKCMD)
;STILL IN FTKL10 CONDITIONAL
;NOTE RACE CONDITION:
;MAPIO GETS NO ROOM TO INSERT WRDCNT READER, BUT IO LIST SPACE IS
;FREED UP BEFORE NEXT CALL TO MAPIO

CHNLS1:	EXCTUX	<HRRZ T1,(T3)>	;STEP TO NEXT BUF
	CAIN	T4,(T1)		;BACK WHERE WE STARTED?
	JRST	CHNDN1		;YES, DONE
	PUSHJ	P,IADRCK##	;WORD 0 OF BUFFER THERE?
	  JRST	CHNDN1		;NO, DONE
	  JRST	CHNDN1		;DONE
	EXCTUX	<HLL T1,(T1)>	;YES, GET LH OF THE BUFFER
	TLNN	S,IO		;IF READING,
	JUMPL	T1,CHNDON	; DONE IF THE USE BIT IS ON
	TLNE	S,IO		;IF WRITING,
	JUMPGE	T1,CHNDON	;DONE IF THE USE BIT IS OFF
	MOVE	T2,KDBDSP(W)	;WE HAVE A RECORD TO WRITE
	PUSHJ	P,@TPKCMD(T2)	;GO SET UP THE DEVICE-COMMAND
	  JRST	CHNDON		;NO ROOM FOR IT IN FREE CORE
	TLNE	S,IO		;READING?
	JRST	CHNLS2		;NO
	LDB	T2,[POINT 17,T1,17]	;YES, GET MAX SIZE OF BUFFER
	MOVNI	T2,-1(T2)	;-SIZE
	JUMPGE	T2,CHNLSX	;DONE IF SIZE WRONG
	JRST	CHNLS4		;OK, CONTINUE
CHNLS2:	MOVEI	T1,1(T1)	;POINT TO WORD COUNT WORD
	PUSHJ	P,IADRCK##	;CHECK IT OUT
	  JRST	CHNDN1		;ILLEGAL ADDRESS
	  JRST	CHNDN1		;ILLEGAL FOR I/O
	MOVEI	T1,-1(T1)	;RESTORE T1
	EXCTUX	<MOVN T2,1(T1)>;WRITING, GET USERS WRDCNT
	JUMPE	T2,CHNLSX	;DONE IF 0
	LDB	T3,PIOMOD##	;BYTE MODE?
	CAIE	T3,BYTMOD
	JRST	CHNLS4
	PUSH	P,T1		;YES. GET MODE OF REQUEST
	HRRE	T1,TUBQUE(U)
	LDB	T3,PRBMOD##
	MOVNS	T2		;+BYTE COUNT
	LDB	T1,PBUFRM	;MAX USER SPECIFIED VIA TAPOP
	JUMPE	T1,CHNLS3
	CAMGE	T1,T2		;IF MORE BYTES THAN MAX
	MOVE	T2,T1		;USE MAX NUMBER HE ASKED FOR
CHNLS3:	POP	P,T1
	HRL	P4,T2		;SET LH(P4)=BYTE COUNT FOR MAPIO
	IDIV	T2,TMODTB##(T3)	;NUMBER OF WORDS
	SKIPE	T3
	ADDI	T2,1
	MOVNS	T2		;T2=-NUMBER OF WORDS
CHNLS4:	HRRZS	T3,T1		;SAVE START ADR
	HRL	T3,T2		; AND WORDCOUNT
	MOVEI	T1,-1(T1)	;MAKE SURE ENTIRE BUFFER, PLUS S-WORD
	MOVNS	T2		; IS IN CORE
	ADDI	T2,2(T1)	;TOP OF BUFFER
	PUSHJ	P,ZRNGE##	;ALL THERE?
	  JRST	CHNLSX		;NO, FORGET ABOUT THIS BUFFER
IFN FTMP,<
	PUSHJ	P,[TLNE S,IO	;INPUT?
		  JRST CPOPJ1##;WRITING, BUF IS OK
	           PUSHJ P,SAVT##
		  HRRZ T1,T3	;IS BUF OK WRT CACHE?
	          PJRST BUFSSN##]
	  JRST	CHNLSX		;NO, DON'T DO BUF
> ;END IFN FTMP
	AOS	T2,T3		;IOWD TO T2, POINT AT DATA-1
	PUSH	P,P1		;SAVE CURRENT END
	PUSH	P,P2		;SAVE P2 (LH=LOC OF IORB)
	PUSHJ	P,MAPIO##	;GO MAP IT
	  JRST	CHNPNT		;NOT ENOUGH FREE CORE
	TLNE	S,IO		;READING?
	JRST	MAKLS5
	HRROI	T2,-1(T2)	;YES
	PUSHJ	P,MAPIO##	;MAKE LIST ENTRY FOR BYTE COUNT
	  JRST	CHNPNT		;NO ROOM
	PUSH	P,T1		;SAVE T1
	MOVE	T1,KDBDSP(W)	;DRIVER DISPATCH
	PUSHJ	P,@TPKCMD(T1)	;SETUP COMMAND CHAINING
	  JFCL			;ALWAYS COMES BACK NON-SKIP
	POP	P,T1		;RESTORE T1
MAKLS5:	POP	P,P2		;RESTORE LOC OF IORB
	POP	P,(P)		;DISCARD PREVIOUS END
	AOS	TKBCNT(W)	;ONE MORE RECORD IN THIS XFER
IFN FTMP,<
	MOVSI	T2,-1		;DECREMENT NO OF BUFFERS SWEPT FOR
	TLNE	S,IO
	ADDB	T2,DEVNBF(F)	; IF OUTPUT
	TLNN	T2,-1		;ANY MORE AVAILABLE?
	JRST	CHNDN1		;NO, WE'RE THROUGH
> ;END IFN FTMP
	SOJA	T3,CHNLS1	;GO TEST NEXT BUFFER
;STILL IN FTKL10 CONDITIONAL
;HERE WHEN MAPIO RAN OUT OF ROOM
CHNPNT:	POP	P,P2
	SETZM	(P1)		;SO RTNIOW WILL KNOW WHEN TO STOP
	POP	P,P1		;RESTORE LOC OF LAST DEVICE COMMAND

;HERE ON BAD WRDCNT, THE DEVICE COMMAND IS ALREADY IN THE LIST
CHNLSX:	SUBI	P1,1		;BACK UP OVER DEVICE COMMAND
	SETZM	(P1)		;CLEAR IT
CHNDON:
CHNDN1:
>;END FTKL10



	MOVE	P3,P1		;SAVE PNTR TO NEXT WORD
MAKLSX:
IFN FTKL10,<MOVE T1,-10(P)>	;GET ADDR OF IORB
IFN FTKS10,<MOVE T1,-6(P)>	;GET ADDR OF IORB
	HRRM	P2,@IRBACC(T1)	;STORE EVA OF IOLIST
	HRLM	P3,@IRBACC(T1)	;POINT TO LAST WORD OF XFER LIST
	LDB	T2,PRBFCN##	;GET FCN
	CAIN	T2,RB.FRB	;READ BACKWARDS?
	JRST	INVERT		;YES - INVERT XFER LIST
	JRST	CPOPJ1##	;NO - RETURN
MAKLS1:	PUSH	P,T2		;SAVE IOWD
	PUSHJ	P,GCH4WD##	;GET BLOCK OF STORAGE
	  JRST	T2POPJ##	;ERROR RETURN

	MOVE	P2,T1		;SAVE IN P2
	SETZM	3(T1)		;CLEAR LAST WORD
	POP	P,0(T1)		;STORE IOWD
	SETZM	1(T1)		;TERMINATE LIST
	MOVEI	P3,1(T1)	;ADDRS OF END OF LIST
	JRST	MAKLSX		;RETURN

;HERE WHEN MAPIO LOST - RETURN ANY PARTIAL STUFF

MAKLSF:
IFN FTKL10,<MOVE P1,-10(P)>	;GET ADDR OF IORB
IFN FTKS10,<MOVE P1,-6(P)>	;GET ADDR OF IORB
	HRRZ	T1,@IRBACC(P1)	;PARTIAL LIST
	PUSHJ	P,RTNIOW##	;RETURN IT
MAKLSE:	SKIPE	T1,P2		;ANYTHING ALLOCATED
	PUSHJ	P,RTNIOW##	;YES - RETURN IT
	POPJ	P,		;GIVE ERROR RETURN
> ;END IFE FTKS10

;HERE TO WAIT FOR A KONTROLLER
KSLEEP:	SKIPA	T3,[FSLEEP##]	;LIKELY THAT EVENT WILL HAPPEN SOON

;HERE TO GO INTO EVENT WAIT
MSLEEP:	MOVEI	T3,ESLEEP##	;LONG TIME UNTIL THE EVENT
	MOVEI	T2,IOACT	;CHECK FOR IOACTIVE
	TDNN	T2,DEVIOS(F)	;DON'T RETURN EVM IF SO
	PUSHJ	P,RTEVM##	;RETURN ANY EVM WHICH WE MAY HAVE
				; SINCE WE MIGHT GET SWAPPED
				; WHILE SLEEPING
	MOVSI	T2,OFLHNG	;IN KONTROLLER WAIT BIT
	IORM	T2,DEVIAD(F)	;LITE IT IN CASE OF HUNG DEVICE
	PUSHJ	P,(T3)		;WAIT FOR EVENT
	MOVE	S,DEVIOS(F)	;NEW STATE OF UNIT
	SKIPL	DEVIAD(F)	;HUNG DEVICE WHILE WAITING FOR THE KONTROLLER?
	PJRST	ERRGOU##	;YES, GET OUT

	MOVSI	T2,OFLHNG	;NO, NO LONGER WAITING
	ANDCAM	T2,DEVIAD(F)	; ..
	POPJ	P,
IFN FTKL10,<
;ROUTINE TO GENERATE XFER LIST FOR READ BACKWARDS
;ENTER WITH P2 := FORWARD XFER LIST
;	    T1 := IORB ADDRS
;	    P4 := CHARS/WD

INVERT:	PUSH	P,U		;WE USE U AS A FLAG TO GETMOR
	MOVE	U,KDBDSP(W)	;POINT TO KONTROLLER DISPATCH
	LDB	U,[POINTR (DRVCF2(U),DR.KTY)] ;GET KONTROLLER TYPE
	CAIE	U,K.T78		;TM78?
	CAIN	U,K.DX2		;OR DX20?
	JRST	[MOVEI U,4
		 JRST	INVL0]
	CAIN	U,K.TX1		;DX10?
	TDZA	U,U		;SET U=0 FOR DX10, U=4 FOR DX20
				;GETMOR USES THIS AS A FLAG FOR WHICH
				;KIND OF CCW JUMP WORDS IT BUILD
	PJRST	UPOPJ1##	;NO, LEAVE THE LIST ALONE
INVL0:	MOVEI	P3,0		;INIT CNTR OF IOWDS
	MOVE	P1,T1		;IORB ADDRESS
	MOVE	T2,P2		;COPY LIST HEAD
INVL1:	MOVE	T1,0(T2)	;IOWD
	JUMPE	T1,INVD1	;DONE IF ZERO
	JUMPG	T1,[MOVE T2,T1	;PERFORM XFER
		    JRST INVL1]	;CONTINUE
	ADDI	P3,1		;INCR COUNTER
	AOJA	T2,INVL1	;AND LOOK AT NEXT

INVD1:	PUSHJ	P,GCH4WD##	;GET SOME STORAGE
	  JRST	[POP	P,U	;RESTORE U
		 JRST	MAKLSE]	;LOSE
	HRRM	T1,@IRBACC(P1)	;SAVE THIS LIST ADDRS
	MOVE	P1,T1		;COPY TO P1
	HRLI	P1,-3		;MAKE AOBJN PNTR
	SETZM	0(P1)		;GRNTEE ZERO AT END
INVL2:	MOVE	T2,P2		;HEAD OF OLD LIST
	MOVE	T3,P3		;ITEM # TO FIND
INVL3:	SKIPN	T1,0(T2)	;LOOK FOR END
	STOPCD	MAKLSF,DEBUG,BFO,	;++BETTER FIND ONE
	JUMPG	T1,[MOVE T2,T1	;LINK TO NEXT
		    JRST INVL3]	;AND PROCEED
	SOJLE	T3,INVD2	;DONE WHEN T3 GOES TO ZERO
	AOJA	T2,INVL3	;LOOK FOR MOVE
INVD2:	HLRE	T3,T1		;GET LH
	ASH	T3,-4		;ADJUST
	JUMPN	U,INVD4		;ALREADY HAVE WORD COUNT IF DX20
	MOVNS	T3		;POSITIVE
	IDIVI	T3,(P4)		;MAKE INTO WORDS
	JRST	INVD5		;JUMP AROUND DX20/RH20 CODE
INVD4:	ANDI	T3,3777		;RH20 USES 11 BIT POSITIVE WORD COUNT
	TLO	T1,(CC.REV)	;SET REVERSE BIT IN RH20 CCW
INVD5:	ADDI	T1,-1(T3)	;ADJUST IOWD TO BUFFER END
	MOVEM	T1,0(P1)	;STORE IN NEW LIST
	SOJLE	P3,INVD3	;DONE IF NO MORE
	AOBJN	P1,INVL2	;NO - DO MORE
	PUSHJ	P,GETMOR##	;NEED MORE STORAGE
	  JRST	[POP	P,U	;RESTORE U
		 PJRST	MAKLSF]	;RETURN TRASH AND LOSE
	JRST	INVL2		;TRY AGAIN

INVD3:	AOBJN	P1,.+1		;POINT TO END OF LIST
	SETZM	0(P1)		;GRNTEE ZERO
	MOVE	T1,-11(P)	;RESTORE IORB
	HRLM	P1,@IRBACC(T1)	;SAVE NEW LIST END
	MOVE	T1,P2		;NOW RETURN OLD LIST
	PUSHJ	P,RTNIOW##
	PJRST	UPOPJ1##	;GIVE GOOD RETURN

>;END IFE FTKL10
;ROUTINE TO SET UP CORRECT READ OP
SETRED:	MOVEI	P2,RB.FRD	;ASSUME NORMAL
	MOVE	T2,TDVSTS(F)	;GET FLAGS
	TLNE	T2,D.NRLT	;LOW THRESHOLD?
	MOVEI	P2,RB.FRL	;YES - SET FCN
	TLNE	T2,D.RDBK	;READ BACKWARDS?
	MOVEI	P2,RB.FRB	;YES - USE THIS
	POPJ	P,		;RETURN

;ROUTINES TO SETUP ASYNCHRONOUS IORB
IFN FTMP,<
PCLOUT:	SKIPA	T3,[TPMOU1]	;OUTPUT
PCLINP:	MOVEI	T3,TPMIN1	;INPUT
	MOVSI	T2,RB.PCL	;QUEUED PROTOCOL BIT
	JRST	QUEIOB		;GO QUEUE UP IORB
> ;END IFN FTMP
QUEOUT:	SKIPA	T3,[TPMOU1]	;OUTPUT
QUEINP:	MOVEI	T3,TPMIN1	;INPUT
	SETZ	T2,		;ASYNCH I/O
QUEIOB:
IFN FTXMON,<XHLLI T3,.>		;INCLUDE SECTION
	MOVEM	T3,IRBIVA(T1)	;SAVE IN INT VECTOR
	PUSH	P,T2		;SAVE IORB BITS
	PUSH	P,T1		;SAVE IORB PNTR
	PUSHJ	P,CKREW		;MAKE SURE NOT REWINDING
	PUSHJ	P,SETACT##	;MAKE (RAD)IOACTIVE
	POP	P,T1		;IORB
	POP	P,T2		;IORB BITS
	MOVEI	T3,DEPAIO	;BIT TO TEST
	TDNE	T3,DEVAIO(F)	;ASYNCH I/O?
	TLO	T2,RB.AIO	;YES
	IORM	T2,TRBFNC(T1)	;...
	PJRST	TAPRQT##	;QUEUE IORB, SELECT IF IDLE

;PROCESS CONTROL-T
TPMCTT::PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,TDVUDB(F)	;UDB POINTER
	PUSHJ	P,INLMES##
	ASCIZ	" file "
	MOVE	T1,TUBFIL(P1)
	PUSHJ	P,PRTDIG##
	PUSHJ	P,INLMES##
	ASCIZ	" record "
	SKIPL	T1,TUBREC(P1)
	PJRST	PRTDIG##
	PUSHJ	P,INLMES##
	ASCIZ	" ???"
	POPJ	P,
SUBTTL	TAPSER CALLED ROUTINES

;ROUTINE CALLED BY TAPSER WHEN KONTROLLER IS GRANTED
;W POINTS TO KDB, U POINTS TO UDB, T1 TO IORB

TPMSIO::MOVE	F,TUBCUR(U)	;POINTER TO DDB
	MOVSI	T2,RB.AIO	;CHECK FOR SPECIAL IORBS
	TDNE	T2,TRBFNC(T1)
	JRST	TPASIO		;START THESE NOW
	PUSH	P,T1		;SAVE IORB PNTR
	LDB	T1,PJOBN##	;JOB NO. IN T1
	JUMPE	T1,TPOPJ##	;NO JOB NUM.?
	PUSHJ	P,EWAKE##	;GET HIM UP
	JRST	TPOPJ##		;RETURN

;HERE TO START ASYNC I/O REQUEST

TPASIO:	PUSHJ	P,SVEUF##	;SET UP UPMP
	PUSHJ	P,SPCS##	;ALSO SETUP PCS
	MOVE	S,DEVIOS(F)	;SET UP S
		;;;;		;FALL INTO TPMDON

;ROUTINE CALLED BY TAPSER WHEN I/O COMPLETE
; U - UDB PNTR , W - KDB PNTR

TPMDON::PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVE	P1,T1		;PLACE IORB PNTR IN P1
	MOVE	F,TUBCUR(U)	;POINTER TO DDB
	LDB	J,PJOBN##	; J = JOB NUMBER
	LDB	T2,PRBFCN##	;GET SELECTED FUNCTION
	LDB	T1,PRBDEN##	;GET SELECTED DENSITY
	CAIE	T2,RB.FRW	;IF REWIND
	CAIN	T2,RB.FYB	; OR YELOW BALL,
	JRST	TPMDO1		;DON'T UPDATE DENSITY STATUS
	DPB	T1,TDYDEN	;UPDATE ACTUAL DENSITY
IFN FTTLAB,<
	TLO	T1,(ST.FAC)	;UPDATE ACTUAL
	PUSHJ	P,SETODN	;SET IN OTHER GUY, TOO!
> ;END IFN FTTLAB
TPMDO1:	SKIPE	T1,IRBIVA(P1)	;GET ROUTINE ADDRESS
IFE FTXMON,<JRST (T1)>		;DISPATCH
IFN FTXMON,<XJRST T1>		;DISPATCH
	STOPCD	.,STOP,NIV,	;++ NULL INT VECTOR ADDRS
;ROUTINE CALLED TO RESET DDB PARAMETERS PECULIAR TO MAGTAPES
;ENTER AT TPMRES FOR A NORMAL RESET OR TPMREA FOR A REASSIGN
TPMRES::TDZA	T1,T1		;NORMAL RESET ENTRY POINT
TPMREA::MOVE	T1,%SITLP##	;REASSIGN ENTRY POINT
	MOVE	T2,DEVMOD(F)	;GET MODE WORD
	TLNN	T2,DVTTY	;WEED OUT NUL:
	TLNN	T2,DVMTA	;A MAGTAPE?
	POPJ	P,		;NO
	MOVEI	T2,MTSIZ##+1	;GET DEFAULT MAGTAPE BLOCK SIZE
	DPB	T2,PBUFSZ	;RESTORE DEFAULT BLOCK SIZE
	SETZ	T2,		;GET A ZERO
	SKIPN	T1		;TAPE LABELER RUNNING?
	DPB	T2,TDYDEN	;RESET ACTUAL DEN TO SYSTEM DEFAULT
	DPB	T2,TDYDN1	;CLEAR USER SET DEFAULT DENSITY
	DPB	T2,TDYMOD	;FORCE REINIT OF MODE
	DPB	T2,TDYMD1	;CLEAR DEFAULT MODE
	DPB	T2,PBUFRM	;CLEAR MAX FRAME-COUNT
	DPB	T2,PMTRTY	;ENABLE AUTO ERROR-RETRY
	POPJ	P,		;RETURN
;ROUTINE CALLED BY DDB SCANNING TO CONVERT SIXBIT /MT/ INTO
;THE APPROPRIATE NAME FOR 7 OR 9-TRACK DEVICES

TPMDVS::CAMN	P1,[SIXBIT/MT/]	;SANITY CHECK
	POPJ	P,		;DON'T MESS WITH NAME
	MOVE	T3,TDVUDB(F)	;IT'S A MAGTAPE, GET UDB
	HRRZ	T3,TUBCNF(T3)	;GET CONFIG INFO
	TRNN	T3,TUC7TK##	;IS THIS 7-TRACK ?
	SKIPA	T3,[SIXBIT/M9/]	;NO, SETUP 9-TRACK
	MOVSI	T3,'M7 '	;YES, SET UP NAME
	JRST	CPOPJ1##	;RETURN
SUBTTL	ERROR LOGGING ROUTINES -- TPELOG - LOG I/O OR POSITIONING ERRORS


TPELOG::JUMPE	U,CPOPJ##	;NEED A UDB FOR ERROR LOGGING
	PUSHJ	P,SAVT##	;SAVE SOME ACS
	JUMPN	F,TPELO1	;DDB ALREADY SETUP?
	SKIPN	F,TUBCUR(U)	;PICK UP CURRENT DDB
	MOVE	F,UDBDDB(U)	;OR THE "REAL" DDB IF NONE
	JUMPE	F,TPELO2	;ASSUME LOGGING WANTED	 IF NO DDB

TPELO1:	MOVEI	T2,DEPDEL	;BIT TO TEST
	TDNE	T2,DEVSTA(F)	;ERROR LOGGING DISABLED?
	JRST	[AOS   DELCNT##	;YES
		 POPJ  P,]	;JUST RETURN

TPELO2:	MOVE	T2,KDBDSP(W)	;ADDRS OF CTL DEP CODE
	PUSHJ	P,@TPKELG(T2)	;DO KONTROLLER DEPENDENT ERROR LOGGING
	  POPJ	P,		;FAILED
	PUSHJ	P,QUESEB##	;QUEUE UP THE BLOCK
	POPJ	P,		;RETURN


;COMMON ROUTINE CALLED BY MOST DRIVERS
TPELGX::HLLZ	T1,ELGTBL+.EXFLG ;GET -VE LENGTH OF XFER TABLE
	ADD	T1,TUBIEP(U)	;PLUS -VE IEP LENGTH
	ADD	T1,TUBFEP(U)	;PLUS -VE FEP LENGTH
	HLRES	T1		;MOVE TO RH
	MOVMS	T1		;MAKE POSITIVE
	PUSHJ	P,ALCSEB##	;ALLOCATE A SYSTEM ERROR BLOCK
	  POPJ	P,		;NO CORE
	LDB	T2,PJOBN##	;GET OWNER JOB NUMBER
	MOVE	T3,JBTPPN##(T2)	;AND ITS PPN
	MOVEM	T3,TUBUID(U)	;STORE FOR XFER
	MOVE	T3,JBTNAM##(T2)	;GET PROGRAM NAME
	MOVEM	T3,TUBPGM(U)	;STORE FOR XFER
	MOVE	T2,KDBDSP(W)	;POINT TO KONTROLLER DISPATCH
	LDB	T2,[POINTR (DRVCF2(T2),DR.KTY)] ;GET KONTROLLER TYPE
	DPB	T2,[POINT 3,TUBTRY(U),14] ;SAVE FOR SYSERR
	MOVEM	T2,TUBKTY(U)	;STORE FOR XFER
	MOVE	T2,KDBDVC(W)	;GET DEVICE CODE WORD
	MOVEM	T2,TUBDVC(U)	;STORE FOR XFER
	MOVE	T2,KDBCHN(W)	;GET CHANNEL DATA BLOCK
	MOVE	T2,CHNTYP(T2)	;AND CHANNEL TYPE WORD
	SETZ	T3,		;CLEAR TEMP
IFN FTKL10,<
	TLNE	T2,CP.RH2	;RH20?
	TLO	T3,(1B11)	;YES
> ;END IFN FTKL10
IFN FTKS10,<
	TLNE	T2,CP.R11	;RH11?
	TLO	T3,(1B10)	;YES
> ;END IFN FTKS10
	IORM	T3,TUBTRY(U)	;STORE FOR XFER

	XMOVEI	T2,ELGTBL	;POINT TO TRANSFER TABLE
	PUSHJ	P,XFRSEB##	;COPY DATA
	  JFCL			;WON'T FAIL
	MOVEI	T2,ELGEND-ELGTBL-.EXHDR+.EBHDR-1 ;OFFSET TO IEP STORAGE
	HRRM	T2,.EBHDR+10(T1) ;FIXUP AOBJN POINTER
	HLRE	T2,TUBIEP(U)	;GET -VE IEP LENGTH
	MOVMS	T2		;MAKE POSITIVE
	PUSH	P,T2		;SAVE FOR A MOMENT
	HRRZ	T3,TUBIEP(U)	;GET OFFSET WITHIN TUB
	ADD	T3,U		;RELOCATE
	HRRZ	T4,.EBHDR+10(T1) ;GET OFFSET TO STORAGE
	AOS	T4		;PLUS ONE CUZ SYSERR IS WIERD
	ADD	T4,T1		;FORM DESTINATION

IFE FTXMON,<
	HRLZS	T3		;GET SOURCE IN LH
	HRRI	T3,(T4)		;AND DESTINATION IN RH
	ADDI	T4,(T2)		;COMPUTE END OF BLT
	BLT	T3,-1(T4)	;COPY DATA
> ;END IFE FTXMON
IFN FTXMON,<EXTEND T2,[XBLT]>	;COPY INTO ERROR BLOCK

	HRRZ	T2,.EBHDR+10(T1) ;GET OFFSET TO START OF IEP DATA
	ADD	T2,(P)		;PLUS IEP SIZE
	HRRM	T2,.EBHDR+11(T1) ;FIXUP OFFSET TO START OF FEP DATA
	HLRE	T2,TUBFEP(U)	;GET -VE FEP LENGTH
	MOVMS	T2		;MAKE POSITIVE
	HRRZ	T3,TUBFEP(U)	;GET OFFSET WITHIN TUB
	ADD	T3,U		;RELOCATE
	HRRZ	T4,.EBHDR+11(T1) ;GET OFFSET TO STORAGE
	AOS	T4		;PLUS ONE FOR SYSERR
	ADD	T4,T1		;FORM DESTINATION

IFE FTXMON,<
	HRLZS	T3		;GET SOURCE IN LH
	HRRI	T3,(T4)		;AND DESTINATION IN RH
	ADDI	T4,(T2)		;COMPUTE END OF BLT
	BLT	T3,-1(T4)	;COPY DATA
> ;END IFE FTXMON
IFN FTXMON,<EXTEND T2,[XBLT]>	;COPY INTO ERROR BLOCK

	POP	P,(P)		;PHASE STACK
	JRST	CPOPJ1##	;RETURN

ELGTBL:	SEBTBL	(.ERTAP,ELGEND,)
	MOVE	UDBNAM(U)	;(R00) DEVICE NAME
	MOVE	TUBRID(U)	;(R01) REELID
	MOVE	TUBFIL(U)	;(R02) FILES FROM BOT
	MOVE	TUBREC(U)	;(R03) RECORDS FROM LAST EOF
	MOVE	TUBTRY(U)	;(R04) RETRY COUNT + HARD ERROR BIT
	MOVE	TUBCCR(U)	;(R05) CHARACTERS INTO CURRENT RECORD
	MOVE	TUBPBE(U)	;(R06) POSITION BEFORE ERROR
	MOVE	TUBFES(U)	;(R07) FINAL ERROR STATE
	MOVE	TUBIEP(U)	;(R10) INITIAL ERROR POINTER
	MOVE	TUBFEP(U)	;(R11) FINAL ERROR POINTER
	MOVE	TUBUID(U)	;(R12) PPN OF USER
	MOVE	TUBPGM(U)	;(R13) SIXBIT PROGRAM NAME
	MOVE	TUBDVC(U)	;(R14) DEVICE CODE/UNIBUS ADDRESS
	MOVE	TUBKTY(U)	;(R15) KONTROLLER TYPE
ELGEND:!			;END OF TABLE
SUBTTL	ERROR LOGGING ROUTINES -- TPEMOV - MOVE DATA WITHIN TUB


TPEMOV::MOVE	T4,KDBDSP(W)	;POINT TO KONTROLLER DISPATCH
	LDB	T4,[POINTR (DRVCF2(T4),DR.KTY)] ;GET KONTROLLER TYPE
	TRNN	T1,RB.SRE	;LEAVE IEP ALONE IF RECOVERED
	CAIN	T4,K.DX2	;IF A DX20, DON'T COPY
	JRST	TPEMO1		;SINCE TD2KON DOESN'T USER TUBIEP
IFE FTXMON,<
	MOVE	T4,TUBIEP(U)	;INITIAL ERROR POINTER
	ADDI	T4,0(U)		;RELOCATE
	HLRE	T2,T4		;-LEN OF AREA
	MOVNS	T2		; +LEN
	ADDI	T2,-1(T4)	;LOC+N-1
	HRR	T3,TUBFEP(U)	;FINAL ERROR STATUS
	ADDI	T3,0(U)		;RELOCATE
	HRL	T4,T3		; FORM BLT WORD
	BLT	T4,0(T2)	;MAKE COPY FOR DAEMON
> ;END IFE FTXMON
IFN FTXMON,<
	HLRE	T2,TUBIEP(U)	;-LENGTH OF AREA
	MOVNS	T2		;MAKE POSITIVE
	HRRZ	T3,TUBFEP(U)	;UDB OFFSET TO FINAL ERROR STATUS
	ADD	T3,U		;RELOCATE
	HRRZ	T4,TUBIEP(U)	;UDB OFFSET TO INITIAL ERROR STATUS
	ADD	T4,U		;RELOCATE
	EXTEND	T2,[XBLT]	;COPY FOR DAEMON
> ;END IFN FTXMON

TPEMO1:	MOVE	T2,TUBREC(U)	;POSITION BEFORE LAST REC
	SUBI	T2,1		;ASSUME THE TAPE MOVED
	HRL	T2,TUBFIL(U)	;SAVE POSITION BEFORE ERROR
	MOVEM	T2,TUBPBE(U)	; IN CASE TAPERP NOT CALLED
	MOVE	T2,TRBRCT(P1)	;SAVE CHAR COUNT IF REC
	MOVEM	T2,TUBCCR(U)	; IN TUB FOR DAEMON
	LDB	T2,PJOBN
	MOVE	T3,JBTNAM##(T2)	;SAVE PROGRAM NAME
	MOVEM	T3,TUBPGM(U)
	MOVE	T3,JBTPPN##(T2)	; AND PPN
	MOVEM	T3,TUBUID(U)	;FOR DAEMON
	POPJ	P,
SUBTTL	ERROR LOGGING ROUTINES -- TPESTS - LOG TAPE STATISTICS


TPESTS:	PUSHJ	P,SAVT##	;SAVE SOME ACS
	LDB	T1,PJOBN##	;GET OWNER JOB NUMBER
	MOVE	T1,JBTPPN##(T1)	;AND ITS PPN
	MOVEM	T1,TUBUID(U)	;STORE FOR XFER
	SETZ	T1,		;LET XFR ROUTINE ALLOCATE
	XMOVEI	T2,TPSTBL	;POINT TO TRANSFER TABLE
	PUSHJ	P,XFRSEB##	;COPY DATA
	  JFCL			;NO CORE
	SETZM	TUBSTB(U)	;NOW CLEAR AREA

IFE FTXMON,<
	HRLI	T2,TUBSTB(U)	;GEN CLEAR PNTR
	HRRI	T2,TUBSTB+1(U)
	BLT	T2,TUBSTE-1(U)	;END OF AREA TO CLEAR
> ;END IFE FTXMON
IFN FTXMON,<
	MOVEI	T1,TUBSTE-TUBSTB ;LENGTH OF AREA
	XMOVEI	T2,TUBSTB(U)	;SOURCE
	XMOVEI	T3,TUBSTB+1(U)	;MAKE A BLT POINTER
	EXTEND	T1,[XBLT]	;ZERO STORAGE
> ;END IFN FTXMON
	POPJ	P,		;RETURN


TPSTBL:	SEBTBL	(.ERTPS,TPSEND,EX.QUE)
	MOVE	UDBNAM(U)	;(R00) DEVICE NAME
	MOVE	TUBRID(U)	;(R01) REELID
	MOVE	TUBCRD(U)	;(R02) CHARACTERS READ
	MOVE	TUBCWR(U)	;(R03) CHARACTERS WRITTEN
	MOVE	TUBSRE(U)	;(R04) SOFT READ ERRORS
	MOVE	TUBHRE(U)	;(R05) HARD READ ERRORS
	MOVE	TUBSWE(U)	;(R06) SOFT WRITE ERRORS
	MOVE	TUBHWE(U)	;(R07) HARD WRITE ERRORS
	MOVE	TUBUID(U)	;(R10) PPN
TPSEND:!			;END OF TABLE
SUBTTL	COMMAND PROCESSING -- MTABLK - SET BLOCKSIZE


MTABLK::PUSHJ	P,MTFIND	;GET REMAINDER OF COMMAND AND FIND MTA DDB
	  JRST	COMERR##	;NOT NUMERIC
	AOS	P2,T2		;COPY TO WHERE IT'S NEEDED
	PUSH	P,U		;SAVE U
	MOVE	U,TDVUDB(F)	;UDB ADDRESS
	PUSHJ	P,TAPSBS	;VALIDATE BLOCK SIZE
	  SKIPA			;OUT OF RANGE
	JRST	UPOPJ1##	;DONE
	POP	P,U		;RESTORE U
	JRST	COMERR##	;AND TELL USER
SUBTTL	COMMAND PROCESSING -- MTADEN - SET DENSITY


MTADEN::PUSHJ	P,MTFIND	;GET THE REST OF COMMAND AND FIND MTA DDB
	  JRST	COMERR##	;NOT NUMERIC
	MOVE	T1,[-DNTBLN,,DENTAB]
	MOVE	T3,0(T1)	;GET ENTRY FROM TABLE
	CAIE	T2,(T3)		;MATCH?
	AOBJN	T1,.-2		;NO - TRY NEXT
	JUMPGE	T1,COMERA##	;ERROR IF NONE FOUND
	HLRZ	T1,T3		;GET CODE
	MOVEI	T3,TUCD20##	;BIT POSITION OF LOWEST DENSITY
	LSH	T3,-1(T1)	;CHANGE DENSITY CODE INTO BIT POSITION
	MOVE	T2,TDVUDB(F)	;GET POINTER TO THE UDB FOR THIS DRIVE
	TDNE	T3,TUBCNF(T2)	;VALID DENSITY FOR THIS DRIVE?
	JRST	MTADE1		;YES, GO PUT DENSITY IN THE DDB
	JSP	T1,ERRMES##	;ILLEGAL DENSITY FOR THIS DRIVE
	ASCIZ	\Illegal density for drive
\
MTADE1:	DPB	T1,TDYDN1	;YES, STORE CODE IN DDB
IFN FTTLAB,<
	TLZ	T1,(ST.FAC)	;INDICATE A REQUEST ONLY
	PUSHJ P,SETODN		;UPDATE DENSITY ON OTHER DDB
> ;END IFN FTTLAB
	JRST	CPOPJ1##	;RETURN


;TABLE OF DENSITIES
DENTAB:	RB.D2,,^D200
	RB.D5,,^D556
	RB.D8,,^D800
	RB.D16,,^D1600
	RB.D62,,^D6250
DNTBLN==.-DENTAB
SUBTTL	COMMAND PROCESSING -- MTAMOD - SET FORMAT


MTAMOD::PUSHJ	P,MTFIND	;GET REST OF COMMAND AND SET UP F
	  SKIPA	T1,[-MDTBLN,,MODTAB] ;SIXBIT ARGUMENT
	JRST	COMERR##	;NUMERIC - LOSE
	PUSHJ	P,FNDNAM##	;FIND THE ARGUMENT
	  JRST	COMERA##	;SORRY, DON'T KNOW THAT ONE
	CAIE	T1,RB.MCD	;CORE-DUMP?
	JRST	MTAMD1		;NO
	MOVE	T2,TDVUDB(F)	;UDB ADDRESS
	MOVEI	T3,TUC7TK##	;BIT TO TEST
	TDNE	T3,TUBCNF(T2)	;A 7-TRACK DRIVE?
	MOVEI	T1,RB.M7T	;YES. SET 7-TRACK CORE-DUMP
MTAMD1:	DPB	T1,TDYMD1	;SAVE MODE IN DDB
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN


;TABLE OF VALID FORMATS
MODTAB:	SIXBIT	/SYSTEM/	;SYSTEM DEFAULT
	SIXBIT	/DUMP/		;CORE DUMP
	SIXBIT	/BYTE/		;BYTE MODE
	SIXBIT	/SIXBIT/	;SIXBIT
	SIXBIT	/ANSI/		;ANSI-ASCII
	SIXBIT	/??????/	;PLACE MARKER FOR 7-TRACK CORE DUMP
	SIXBIT	/INDUST/	;INDUSTRY COMPATABLE
MDTBLN==.-MODTAB
SUBTTL	COMMAND PROCESSING -- MTARTY - SET RETRY


MTARTY::PUSHJ	P,MTFIND	;GET REST OF COMMAND, SET UP F
	  HLRZS	T2		;NON-NUMERIC RETURN (NORMAL)
	MOVSI	T1,MTSNAR	;NO AUTO-RECOVERY BIT
	CAIN	T2,'ON '	;CLEAR OR SET IF 'ON' OR 'OFF'
	JRST	[ANDCAM	T1,DEVIOS(F)
		 PJRST	CPOPJ1##]
	CAIE	T2,'OF '
	CAIN	T2,'OFF'
	JRST	[IORM	T1,DEVIOS(F)
		 PJRST	CPOPJ1##]
	JRST	COMERR##	;NOT A LEGAL ARGUMENT
SUBTTL	COMMAND PROCESSING -- PARSE MAGTAPE DEVICE SPEC


MTFIND:	TLO	M,CMWRQ		;CAUSE SET COMMAND FORGETS
	PUSHJ	P,CTXDEV##	;PICK UP DEVICE ARGUMENT
	SKIPE	T1,T2		;DEVSRG EXPECTS NAME IN T1
	PUSHJ	P,DEVSRG##	;SEARCH FOR DDB
	  PJRST MTFERR		;NO SUCH DEVICE
	LDB	T1,PJOBN##	;GET OWNER'S JOB NUMBER
	CAME	T1,J		;US?
	PJRST	MTFERR		;NO, LOSE!
	MOVE	T1,DEVMOD(F)
	MOVE	U,TTYTAB##(J)	;RESTORE U
	MOVE	U,DDBLDB##(U)
	TLNN	T1,DVMTA	;IS DEVICE A MAGTAPE?
	PJRST	COMERP##	;NO, LOSE!
	PUSHJ	P,DECIN1##	;GET LAST ARGUMENT
	  PJRST NOTENP##	;NO ARGUMENT FOUND
	  PJRST	CTEXT1##	;NOT NUMERICAL, READ SIXBIT
	JRST	CPOPJ1##	;RETURN.
MTFERR:	MOVE	U,TTYTAB##(J)	;TTY DDB
	MOVE	U,DDBLDB##(U)	;LDB BACK INTO LINE
	PJRST	COMERP##	;TYPE ERROR MESSAGE
	LIT

	$LOW

DIATAP:	BLOCK	1		;NON-ZERO IF DIAG IN PROGRESS

TPMEND::!  END