Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - tapuuo.mac
There are 13 other files named tapuuo.mac in the archive. Click here to see a list.
TITLE TAPUUO - MAGTAPE USER INTERFACE FOR TOPS10 - V112
SUBTTL T.HESS/TAH/TW	22 MAR 77
	SEARCH	F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VTPUUO,112		;DEFINE VERSION NUMBER FOR STORAGE MAP
	SALL

TAPUUO::	ENTRY	TAPUUO

;DISPATCH TABLE

	POPJ	P,		;(-4) SPECIAL ERROR STATUS
	JRST	REGSIZ##	;(-3) USE DEFAULT
	JRST	TPMINI##(P2)	;(-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	TPSETF		;(4) LOOKUP
	JRST	TPSETF		;(5) ENTER
	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,<
TPSETF==CPOPJ1##		;DUMMY ENTRIES
TPCLSI==CPOPJ##
>
;RANDOM DDB BYTE POINTERS

TDYMOD::POINT 4,TDVSTS##(F),11
TDYDEN::POINT 4,TDVSTS##(F),7
TDYDN1::POINT 4,TDVSTS##(F),35		;FOR SET DENSITY
TDYBYT::POINT 9,TDVSTS##(F),11		;PARITY/DENSITY/MODE

;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)

COMPAT==<RB.D16>B31+<RB.MBY>B35

;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
>
MTSNAR==:(1B9)		;SET-RETRY BIT (UUOCON,COMCON USE)
IOSRTY==:(1B10)		;IF ON, NO ERROR RETRY (TXIKON)

;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


>
IFN FTMTSET,<
PMTRTY::POINT	1,DEVIOS(F),9
>
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		;...
>
TPMINA:	PUSHJ	P,SETRED	;SET READ OP
	PUSHJ	P,GENIOR	;GENERATE IORB
	  JRST	TPMINF		;WHOOPS (UNABLE TO GET STORAGE)
	MOVEI	T2,DEPAIO	;ASYNC I/O?
	TDNE	T2,DEVAIO(F)
	JRST	ASYNCI		;YES - GO TO IT
	MOVEM	T1,TDVIOR##(F)	;NO - REMEMBER THIS IORB
	PUSHJ	P,TAPRQT##	;PLACE AT END OF QUEUE
	PUSHJ	P,KONWAT	;WAIT FOR KONTROLLER
				;RETURN HERE P1 := IORB
	SKIPGE	TRBLNK(P1)	;AOK??
	JRST	TPMFLS		;FLUSH REQUEST ARE RETURN TO USER
IFN FTKI10!FTKL10,<
	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
	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,STOIOS##	;SET/RESET HUNG DEVICE TIMER
	MOVEI	T1,INPDUN	;WHERE TO GO WHEN DONE
	HRRM	T1,TRBIVA(P1)	;STORE IT
TPSWST:
IFN FTKL10,<
	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##

;ROUTINE TO SET IMPROPER MODE AND RETURN

TPMINF:	IFN FTKI10!FTKL10,<
	PUSHJ	P,RTEVM##	;RETURN RESOURCES
>
	TRO	S,IOIMPM	;LITE A BIT
	PJRST	STOIOS##
;HERE WHEN INPUT DONE
; P1 := IORB
;U,W,F SETUP
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
IFN FTKI10!FTKL10&FTDX10,<	;ONLY FOR TU70'S

	MOVE	T1,TKBCNT##(W)	;NUMBER OF RECORDS WE DID
	SOJLE	T1,INPDN2	;IF MORE THAN 1,
	PUSHJ	P,SVEUF##	;MAKE JOB ADDRESSABLE
	MOVE	T1,DEVIAD(F)	;GET BUFFER ADDRESS
	EXCTUX	<LDB T3,[POINT 17,0(T1),17]>
	SUBI	T3,1		;WORDCOUNT OF ALL BUT LAST RECORD
INPDN1:	SOSG	TKBCNT##(W)	; (WOULD HAVE STOPPED EARLY ON LENGTH ERROR
	JRST	INPDN2		; IF THE WRDCNT WAS WRONG)
	MOVE	T1,DEVIAD(F)
	EXCTUU	<HRRM T3,1(T1)>	;STORE WRDCNT IN BUFFER
	PUSHJ	P,ADVBFF##	;MOVE TO NEXT BUFFER
	  JFCL
	JRST	INPDN1		;AND KEEP ON GOING
INPDN2:>
	MOVE	T1,P1
	LDB	T4,PRBMOD##	;GET MODE
IFN FTKI10!FTKL10&FTDX10,<
	MOVSI	T2,RB.SEN	;IS THERE 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
		JRST INPDN3]	; SO ENSURE THAT LH(WORD 0) WILL BE USED AS REC SIZE
>
	MOVE	T2,TRBRCT(P1)	;GET CHARS READ
	MOVEM	T2,TUBCCR##(U)	;SAVE COUNT FOR TAPOP
	IDIV	T2,TMODTB##(T4)	;CONVERT TO WORDS
	SKIPE	T3		;RESIDUE?
	ADDI	T2,1		;  ADJUST ACCORDINGLY
INPDN3:	PUSHJ	P,TPMXCI	;RELOCATE DEVIAD, XCT .+1
	  EXCTUX <LDB T3,[POINT 17,0(T1),17]> ;GET BUFFER SIZE+1
	CAIG	T2,-1(T3)	;RECORD .LTE. BUFFER?
	SKIPA	T4,TRBRCT(P1)	;YES, T2=WORDS, T4=BYTES
	SKIPA	T4,TMODTB(T4)	;NO, T2=SIZE OF BUF
	JRST	INPDN4
	MOVEI	T2,-1(T3)
	IMULI	T4,(T2)		;T4=THAT NUMBER OF BYTES?
INPDN4:	LDB	T3,PIOMOD##
	CAIN	T3,BYTMOD	;BYTE MODE DDB?
	MOVE	T2,T4		;YES, STORE NO OF BYTES READ
	PUSHJ	P,TPMXCI	;GET C(DEVIAD) AGAIN
	  EXCTUU <HRRM	T2,1(T1)>	;STORE IN HEADER
	PUSHJ	P,TPMRCW	;RETURN XFER LIST
	PUSHJ	P,ADVBFF##	;ADVANCE BUFFERS
	  JRST	TPSWSP		;NO MORE STOP IO
	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
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:
IFN FTKI10!FTKL10,<
	PUSHJ	P,RTEVM##	;RETURN EVM IF ANY
>
	PUSHJ	P,SETIOD##	;REVIVE HIM
	PUSHJ	P,CLRACT##	;CLEAR IOACTIVE
	HLLZS	TKBSTS##(W)	;SET CNTR TO ZERO
	PJRST	STOIOS##	;STASH IOS & EXIT
TPSWSP:
IFN FTKL10,<
	PUSHJ	P,TPMSWP	;SWEEP CACHE IF NOT TM10A
>
	JRST	TPMSTP		;NOW STOP IO

;ROUTINE TO RETURN IOWD LIST , P1 := IORB

TPMRCW:	HRRE	T1,TRBXCW(P1)	;FETCH CHL LIST
	CAIG	T1,100		;ALLOW FOR COUNT
	POPJ	P,		;RETURN
IFN FTKI10!FTKL10,<
	PJRST	RTNIOW##	;ELSE RETURN WHOLE LIST
>
IFN FTKA10,<
	JRST	TPMRI1		;RETURN 4-WD BLOCK
>

;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		;GIV4WD LIKES IT IN T2
	MOVEI	T1,1		;# OF BLOCKS
	PJRST	GIV4WD##	;RETURN 4-WD BLOCK

;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
>
	MOVEI	P2,RB.FWT	;FUNCTION WRITE
	PUSHJ	P,GENIOR	;MAKE AN IORB
	  JRST	TPMINF		;UNABLE TO GET STORAGE
	MOVEI	T2,DEPAIO	;ASYNC I/O?
	TDNE	T2,DEVAIO(F)
	JRST	ASYNCO		;YES - GO TO IT
	MOVEM	T1,TDVIOR##(F)	;NO - WAIT FOR THIS ONE
	PUSHJ	P,TAPRQT##	;QUEUE IT UP
	PUSHJ	P,KONWAT	;WAIT FOR CONTROLLER
				;RETURN WITH P1 := IORB
	SKIPGE	TRBLNK(P1)	;THINGS IN SHAPE
	JRST	TPMFLS		;NO - U LOSE
IFN FTKI10!FTKL10,<
	SKIPN	DEVEVM(F)	;HAVE EVM
	PUSHJ	P,RSTEVM##	;NO - GET IT IF NECESSARY
>
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:	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,STOIOS##	;SET/RESET HUNG DEVICE TIMER
	MOVEI	T1,OUTDUN	;WHERE TO GO WHEN FINISHED
	HRRM	T1,TRBIVA(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
	MOVEM	S,DEVIOS(F)	;SAVE S IN DDB
	PUSHJ	P,TPMRCW	;RETURN XFER LIST
IFN FTTLAB,<
	TRNE	S,IOTEND	;EOT SEEN YET?
	JRST	LBLEOT		;YES - INVOKE LBL PCS
>
IFN FTKI10!FTKL10&FTDX10,<	;ONLY FOR TU70'S
OUTDN1:	SOSG	TKBCNT##(W)	;FOR ALL BUT THE LAST BUFFER,
	JRST	OUTDN2
	PUSHJ	P,ADVBFE##	;TELL UUOCON THAT IT'S FULL
	  JFCL
	JRST	OUTDN1		;AND TRY THE NEXT
OUTDN2:>
	PUSHJ	P,ADVBFE##	;ADVANCE BUFFER
	  JRST	TPMSTP		;NO MORE STOP IO
	MOVEI	P2,RB.FWT	;TRY TO WRITE ON
	PUSHJ	P,TPIOGO	;...
	  JRST	TPMSTP		;NO MORE RETURN
	JRST	TPMOU1		;CONTINUE WRITING

;HERE TO ADVANCE BUFFER IF ONE FOUND EMPTY

ADVOUT:	PUSHJ	P,ADVBFE##	;CYCLE
	  SKIPA			;NO NEXT BUFFER
	JRST	TPMOU1		;TRY THIS ONE
	PUSHJ	P,SETIOD##	;REVIVE USER
	PUSHJ	P,CLRACT##	;...
TPMFLX:	PUSHJ	P,TAPFLS##	;ELSE FLUSH REQUEST
IFN FTKI10!FTKL10,<
	PUSHJ	P,TPMRI1	;RETURN IORB
	PJRST	RTEVM##		;AND EVM IF ANY
>
IFN FTKA10,<
	PJRST	TPMRI1		;RETURN IORB
>
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?
	  TLOA	S,LBLNED	;YES - SEND MSG ETC.
	PJRST	TPMSTP		;ELSE PROCESS AS BEFORE
	TRZ	S,IOTEND	;CLEAR EOT NOW
	MOVEI	T1,LR.EOT	;SET TYPE EOT
	DPB	T1,TUYRQT	; IN LBL MESSAGE
	PJRST	TPMSTP		;  AND STOP IO
>
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
>

	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
	PUSHJ	P,ADJIOW	;ADJUST IOWDS IF NECESSARY
				;RETURNS IOWD IN T2
	PUSHJ	P,TPMDGO	;START I/O
	  JRST	TPMFLS		;CAN'T - MAKLST LOST
	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO CEASE
IFN FTKL10,<
	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
>
	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,MAKLSD	;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
	MOVEI	T1,DMPDUN	;WHERE TO GO WHEN DONE
	HRRM	T1,TRBIVA(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,TRBLNK(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
	MOVNS	T4		;NEGATE -- + BLOCK SIZE
	HRLS	T4		;+BS,,+BS
	ADD	T2,T4		;ADJUST FOR MAX SIZE
	MOVEM	T2,TDVREM##(F)	;SAVE FOR LATER
	TLNN	S,IO		;OUTPUT?
	POPJ	P,		;NO - THEN DONE
	SUBI	T2,0(T4)	;RE-ADJUST IOWD FOR NOW
	MOVNS	T4		;-BS AGAIN
	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
	PUSHJ	P,TAPRQT##	;QUEUE IT UP
	PUSHJ	P,KONWAT	;WAIT TILL NOTICED
				;RETURN WITH P1 := IORB
IFN FTKI10!FTKL10,<
	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
	HLRZ	U,TDVUDB##(F)	;GET UDB PNTR
IFN FTTLAB,<
	TLNE	S,LBLWAT	;WAITING FOR LABELS
	POPJ	P,		;YES, DO NOTHING NOW
>
	PUSHJ	P,TPMRLW	;WAIT TILL DESELECTED
TPMRL2:	PUSHJ	P,TAPKIL##	;KLANK CTL
	PJRST	TPMDQ		;UNWIND Q , PNTR IN T1

TPMRLW:	MOVSI	T1,TKSSEL##
	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,WSYNC##	;WAIT FOR I/O TO STOP
IFN FTTLAB,<
	HLRZ	U,TDVUDB##(F)	;SET UP UDB ADDRS
	LDB	J,PJOBN##	;RESTORE J
	PUSHJ	P,LBLCHK	;NEED LABELING?
	  JRST	TPCLSO		;YES - SEND CLOSE MSG
>
	PUSHJ	P,SAVE2##	;SAVE P1,P2
	TRNE	S,IOBOT		;TAPE AT BOT (REW OR UNLOAD) ?
	POPJ	P,		;YES, DON'T WRITE EOF'S
	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
	PUSHJ	P,TAPRQT##	;Q IT UP
	PUSHJ	P,GENIOR	;ANOTHER REQUEST
	  JRST	TPMINF
	PUSHJ	P,TAPRQT##	;ADD TO QUEUE
	MOVEI	P2,RB.FBR	;BACK OVER LAST TM
	PUSHJ	P,GENIOR	;MAKE ANOTHER IORB
	  JRST	TPMINF		;LOSER
	PUSHJ	P,TAPRQT##	;Q IT
	PUSHJ	P,KONWAT	;NOW WAIT YOUR TURN
				;P1 := FIRST IORB
	PUSHJ	P,SETACT##	;SET I/O ACTIVE
	MOVEI	T1,CLSDUN	;WHERE TO GO ON ENDING INT
	HRRZM	T1,TRBIVA(P1)	;STORE IN IORB
	MOVEI	T1,1		;SET FOR ONE OP
	HRRM	T1,TRBXCW(P1)	;INTO IORB
	PUSHJ	P,TPSTRT	;GO START IT
	PUSHJ	P,WSYNC##	;WAIT FOR IT TO STOP
	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?
	MOVEI	P2,TPMISP	;YES - GO HERE INSTEAD
	HRRZM	P2,TRBIVA(T1)	;SAVE NEXT INT ADDRS
	HLLOS	TKBSTS##(W)	;GRNTEE STILL KEEP KONTROLLER
	MOVEI	T2,1		;ONLY ONE OP PSE
	HRRM	T2,TRBXCW(T1)	;...
	PJRST	TAPSIO##	;START DEVICE

;HERE IF WRITE LOCKED ON CLOSE

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

IFN FTTLAB,<

;ROUTINE TO SET FIRST OPERATION

TPSETF:	TLO	S,FSTOP		;GET BIT
	MOVEM	S,DEVIOS(F)	;SET IT
	PJRST	CPOPJ1##	;SKIP RETURN

;ROUTINE TO HANDLE INPUT CLOSE OPERATION

TPCLSI:	HLRZ	U,TDVUDB##(F)	;SET UDB ADDRS
	PUSHJ	P,LBLCHK	;NEED LABELING?
	TLNN	F,INPB		;YES - ANY INPUTS??
	POPJ	P,		;NO - RETURN
	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		;SET FIRST OP ALSO
	PJRST	LBLMSG		;INFORM LBL PCS
>
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	RTM1##		;RETURN -1 ON ERROR
	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##(U)	;POINT TO UDB INFO AREA
MTACH1:	MOVE	T1,0(P1)	;GET VALUE
	PUSHJ	P,PUTWR1##	;STORE IN USER BLOCK (INCR M)
	  JRST	RTM1##		;OUT OF BOUNDS
	AOBJN	P1,MTACH1	;LOOP TILL DONE
	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,DVCNSG##	;LOOK FOR DDB
	  PJRST	RTM1##		;NO PRIVS OR NO DDB
	MOVE	T1,DEVMOD(F)	;MAKE SURE ITS AN MTA
IFN FTNUL,<
	TLNN	T1,DVTTY	;...
>
	TLNN	T1,DVMTA	;....
	JRST	RTM1##		;ERROR RETURN
	HLRZ	U,TDVUDB##(F)	;SET UP UDB PNTR
	MOVE	T1,TUBCRD##(U)	;SEE IF ANY READS OR WRITES
	IOR	T1,TUBCWR##(U)	;SINCE LAST UNLOAD
	JUMPE	T1,MTARIX	;OK IF ZERO
	PUSHJ	P,TPDCPY	;NO - COPY TO SHADOW AREA
IFN FTEL,<
	LDB	T1,PJOBN##	;GET OWNING JOB #
	CAME	T1,J		;IS IT US?
	JUMPN	T1,MTARIX	;OK IF NO ERROR
	MOVEI	T1,.ERTPS	;SET UP CODE FOR DAEMON
	HRL	T1,F		;GET DDB ADDRESS FOR DAEMON
	PUSHJ	P,DAEERR##	; WAKE DAEMON
>
MTARIX:	PUSHJ	P,GETWD1##	;GET REEL ID
	MOVEM	T1,TUBRID##(U)	;STORE IN UDB
	PJRST	CPOPJ1##	;GIVE SKIP RETURN
;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
	HLRZ	U,TDVUDB##(F)	;SET U := UDB ADDRS
	PUSHJ	P,GETDEN	;GET CURRENT DENSITY
	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

;ROUTINE TO SAVE DAEMON INFO IN SHADOW AREA AND CLEAR
;STATISTICS BLOCK FOR MOUNT OR UNLOAD PROCESSING

TPDCPY:	HRLI	T2,TUBRID##(U)	;GEN COPY PNTR
	HRRI	T2,TUBDDA##(U)	;  TO DAEMON DUMP AREA
	BLT	T2,TUBDDE##(U)	;...
	SETZM	TUBRID##(U)	;NOW CLEAR AREA
	HRLI	T2,TUBRID##(U)	;GEN CLEAR PNTR
	HRRI	T2,TUBRID##+1(U)
	BLT	T2,TUBCLE##(U)	;END OF AREA TO CLEAR
	POPJ	P,		;RETURN
SUBTTL	TAPOP. UUO
IFN FTTAPOP,<

;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
	MOVE	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
	MOVSI	T1,DVMTA	;CHECK ON TAPE UNIT
	TDNN	T1,DEVMOD(F)	;...
	PJRST	ECOD2##		;NOPE
	MOVSI	T1,DVTTY	;CHECK IF ALSO TTY
	TDNE	T1,DEVMOD(F)
	PJRST	CPOPJ1##	;NUL WINS
	HLRZ	U,TDVUDB##(F)	;YES - SET UP UDB PNTR
	MOVE	S,DEVIOS(F)	;  AND S
	HRRZ	T1,P1		;GET FCN CODE
	TRNE	T1,3000		;READ/SET CODE?
	JRST	TAPRSQ		;YES - GO HANDLE
	CAIG	T1,TAPLN0	;NO - CHECK LEGAL
	SKIPN	TAPTB0(T1)	;EXISTS?
	PJRST	RTZER##		;ILLEGAL FCN CODE
	MOVE	P3,TAPTB0-1(P1)	;GET TABLE ENTRY
	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
	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
TAPSET:	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.SP)
	JRST	0(P3)
	DPB	P2,0(P3)	;SET BIT (BYTE)
	JRST	CPOPJ1##	;GIVE GOOD RETURN
;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
	PJRST	STOTC1##	;STORE IT & SKIP RETURN

;HERE TO HANDLE DENSITY READ

TAPRD1:	PUSHJ	P,GETDEN	;GET DENSITY ARG
	PJRST	STOTC1##	;STORE ETC.

;ROUTINES TO CHECK PRIVS FOR READ OR WRITE

TREDOK:	PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVSI	P1,PVSPYM	;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
;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
>
IFE FTTLAB,<				;;; DUMMIES
	0				;15
	0				;16
	0				;17
	0				;20
	0				;21
	0				;22
>
	TMAC	(0,TAP.NP,TPMSMM)	;23 - SET MAINT MODE
	TMAC	(0,TAP.NP,TPMCMM)	;24 - CLEAR MAINT MODE

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

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
IFN FTRDBACK,<
	TMAC	(0,TAP.SA,<[POINT 1,TDVSTS##(F),0]>) 	;1003 - READ BACKWARDS
>
IFE FTRDBACK,<			;DUMMY FOR RDBACK
	0
>
	TMAC	(0,TAP.SA,<[POINT 1,TDVSTS##(F),1]>) 	;1004 - LOW THRESHOLD
	TMAC	(0,TAP.SA,<[POINT 1,TDVSTS##(F),3]>) 	;1005 - EVEN PARITY
	TMAC	(2,TAP.SA,PBUFSZ##)		  	;1006 - BLOCKSIZE
	TMAC	(3,TAP.SA,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.SA,TUYLTP)			;1024 - LABEL TYPE
	TMAC	(0,TAP.PS,TUYLTP)			;1025 - LABEL TYPE (PRIV SET)
	TMAC	(0,0,PDVESE##)				;1026 - LABEL TERMINATION CODE
>
IFE FTTLAB,<				;;; DUMMIES
	0				;1024
	0				;1025
	0				;1026
>
	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
>
IFE FTTLAB,<
	0			;1033 - DUMMY
>
TAPLN1==.-TAPTB1
;RANGE TABLE FOR TAPOP UUO

TAPSRT:	0,,5			;1 - DENSITY
	NOISEW##,,^D4095	;2 - BLOCKSIZE
	0,,5			;3 - MODE
IFN FTTLAB,< LT.SL,,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
;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
	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	MTAP0		;ISSUE MTAPE CMD

;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##(U)	;BASE ADDRS OF STATS
TAPOPL:	MOVE	T1,0(P1)	;FETCH WORD
	PUSHJ	P,PUTWR1##	;STORE IN USER AREA
	  JRST	RTM1##		;OUT OF BOUNDS
	AOBJN	P1,TAPOPL	;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
	ADDI	P1,0(U)		;RELOCATE 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
	JRST	TAPOPL		;JOIN COMMON CODE
;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
>
	JUMPE	J,ECOD6##	;ERROR IF NO OWNER
	MOVEI	P2,RB.FSE	;FCN TO P2
	MOVEI	P3,TPMWRT	;USE DEFAULT WRITE
	PUSHJ	P,MTAP2		;START OP
	PUSHJ	P,TPSKPW	;WAIT TILL DONE
	MOVEI	P2,RB.FLG	;NOW DO 14 ERASE GAP OPS
	MOVEI	P3,TPMDE1
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	MTAP2		;START OP

;HERE ON KONTROLLER AVAILABLE

TPMDE1:	MOVEI	T1,^D14		;SET COUNT
	HRRM	T1,TRBXCW(P1)	;INTO IORB
	PJRST	TPMWRT		;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
>
	JUMPE	J,ECOD6##	;ERROR IF NO OWNER
	AOS	(P)		;SET SKIP RETURN
	PJRST	TPMCL1		;JOIN CLOSE CODE
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
	  SKIPA			;NOT FOUND
	JRST	[POP P,T1	;FOUND - PRUNE PDL
		 POP P,T1	;...
		 JRST TPLBG1]	;AND CONTINUE PROCESSING
TPLBGA:	MOVEI	T2,SPROTO	;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,SLEEP## ;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,LPROTO	;LOC IF PROTOTYPE
	BLT	T1,SPROTO-1(F)	;MOVE INTO PLACE
	POP	P,DEVNAM(F)	;GIVE IT A NAME
	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
	DPB	J,PJOBN##	;ASSIGN TO THIS JOB
	HLRZ	T1,DEVSER(P1)	;FIX UP LINKS OF
	HRLM	T1,DEVSER(F)	;  DDB CHAIN TO
	HRLM	F,DEVSER(P1)	;  INCLUDE THIS NEW ONE
	MOVE	T1,TDVKDB##(P1)	;GET UDB / KDB PNTRS
	MOVEM	T1,TDVKDB##(F)	;INTO NEW DDB
	LDB	T1,[POINT 9,TDVSTS##(P1),11] ;PAR/DEN/MODE BYTE
	DPB	T1,TDYBYT	;COPY TO NEW DDB ***TEMP***
TPLBG1:	HRLM	F,TUBDDB##(U)	;LINK TO SECONDARY PNTR IN UDB
	MOVSI	T1,TUBQUE##(U)	;AND SET UP NEW EMPTY QUEUE
	EXCH	T1,TUBQUE##(U)	;EXCHANGE PNTRS
	MOVEM	T1,TDVSVQ(F)	;SAVE IN NEW DDB
	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:	HLRZ	P1,TUBDDB##(U)	;2ND DDB ADDRS
	JUMPE	P1,TPLBR1	;OK IF NO DDB
	MOVE	T1,TDVSVQ(P1)	;RESTORE USERS "Q"
	MOVEM	T1,TUBQUE##(U)	;...
	HRRZS	TUBDDB##(U)	;CLEAR SECONDARY DDB
TPLBR1:	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
	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
	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:	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	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
	EXCH	F,P1		;CONFUSE THINGS
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;REAL OWNERS JOB #
	PUSHJ	P,SETDVL##	;FIX UP LOGICAL NAME TABLE
	EXCH	F,P1		;PUT THINGS BACK
	POP	P,J		;...
TPLSU1:	MOVE	T1,TDVKDB##(P1)	;EXCHANGE UNIT / KONTROLLER PNTRS
	EXCH	T1,TDVKDB##(F)
	MOVEM	T1,TDVKDB##(P1)
	HRRM	F,TUBDDB##(U)	;FIX UDB / DDB PNTR
	MOVE	P2,U		;OLD UDB PNTR
	HLRZ	U,TDVKDB##(P1)	;GET NEW UDB ADRS
	MOVE	T2,TUBLBL##(U)	;EXCHANGE LABEL INFO IN UDBS
	EXCH	T2,TUBLBL##(P2)
	MOVEM	T2,TUBLBL##(U)	;...
	HRRM	P1,TUBDDB##(U)	;AND SET PNTR
	MOVE	F,P1		;MAKE F POINT AT NEW DDB
	HLRZ	P1,TUBDDB(P2)	;GET OLD SECONDARY DDB PNTR
	JUMPE	P1,CPOPJ1##	;QUIT NOW IF NONE
	MOVE	T1,TDVKDB##(F)	;GET NEW UNIT/KONTROLLE PNTR
	MOVEM	T1,TDVKDB##(P1)	;SAVE IT IN LABEL DDB
	HRLM	P1,TUBDDB##(U)	;MAKE NEW UDB HAVE SECOND DDB
	HRRZS	TUBDDB##(P2)	;AND OLD DDB HAVE NONE
	JRST	CPOPJ1##	;SKIP EXIT
;ROUTINE TO SEND FORCE EOV MESSAGE TO LBL PCS

TPMFEV:	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO CEASE
	MOVE	S,DEVIOS(F)	;SET UP S
	PUSHJ	P,LBLCHK	;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:	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO CEASE
	MOVE	S,DEVIOS(F)	;SET UP S
	PUSHJ	P,LBLCHK	;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:	HLRZ	T1,TUBDDB##(U)	;GET 2ND DDB ADDR
	JUMPN	T1,ECOD12##	;THRERE IS ONE, ERROR
	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
	  JRST	ECOD6##		;NO, ERROR - NOT ASSIGNED
	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO STOP
	MOVEI	T1,MT0DDB##	;GET START OF MAGTAPE DDB'S

TPMLD1:	MOVE	T2,T1
	HLRZ	T1,DEVSER(T2)	;GET SUCCESSOR
	SKIPN	T1		;END ?
	  STOPCD CPOPJ##,DEBUG,LDN, ;TT LABEL DDB NOT FOUND
	CAIE	T1,(F)		;IS SUCCESSOR THE ONE WE
	JRST	TPMLD1		;NO, TRY NEXT
	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
	HRRZ	T1,USRHCU##	;GET HIGHEST CHANNEL IN USE
TPMLD2:	HRRZ	T2,USRJDA##(T1)	;GET DDB ADDR FOR THIS CHANNEL
	CAIE	T2,(F)		;IS IT INITED ON THIS CHANNEL
	SOJGE	T1,TPMLD2	;NO, LOOP FOR MORE
	SKIPL	T1		;LOOP EXPIRED?
	SETZM	USRJDA##(T1)	;NO, CLEAR OUT THIS CHANNEL
	MOVEI	T1,SPROTO	;SIZE OF DDB
	HRRZ	T2,F		;ADDR
	PJRST	GIVWDS##	;GIVE BACK STORAGE AND RETURN
;READ/SET LABEL PARAMETERS
TAPRLP:	HRR	M,P4		;GET USER'S FUNCTION AGAIN
	PUSHJ	P,GETWRD##	;...
	 PJRST	ECOD4##		;ADDR ERROR
	PUSHJ	P,LBLCHK	;CHECK FOR LBL PCS
	JRST	TAPRL0		;THERE IS ONE, GO AHEAD
	HLRZ	T2,TUBDDB(U)	;GET SECOND DDB
	CAIE	T2,(F)		;OURS
	PJRST	ECOD7##		;NO, NO LBL PCS
	TRNE	T1,1000		;SET FUNCTION
	JRST	TAPSL0		;YES, DO IT
	JRST	TAPRL1		;DO READ
TAPRL0:	PUSHJ	P,LBLSLP
	TRNE	T1,1000		;SET FUNCTION?
	JRST	TAPSLP		;YES
	TLZN	S,FINP		;HAS FIRST INP BEEN DONE?
	JRST	TAPRL1		;YES, PROCEED
	MOVEI	T1,LR.FIN	;REQUEST FOR FIRST INPUT
	DPB	T1,TUYRQT	;SAVE IN TUB
	MOVEM	S,DEVIOS(F)	;SAVE S
	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##(U)	;BASE OF LABEL PARAMETER AREA
	JRST	TAPOPL		;USE EXISTING ROUTINE TO RETURN BLOCK
TAPSLP:	TLNN	S,FOUT		;BEFORE FIRST OUTPUT
	PJRST	ECOD13##	;NO, ERROR
TAPSL0:	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
>	;;;; END IFN FTTAPOP

IFE FTTAPOP,<
UTAPOP:: POPJ	P,		;NOT IMPLEMENTED
>
;ROUTINE TO TAKE CTL OFF-LINE AND SET MAINT MODE

TPMSMM:	HRRZ	W,TUBKDB##(U)	;GET KDB ADDRS
	MOVE	T3,TKBIUN##(W)	;GET UDB PNTR
TPMSM1:	SKIPN	T2,0(T3)	;SEE IF UNIT EXISTS
	JRST	TPMSM2		;NO - TRY NEXT
	HRRZ	F,TUBDDB##(T2)	;GET DDB PNTR
	LDB	T1,PJOBN##	;OWING JOB NUMBER
	CAME	T1,J		;IT HAD BETTER BE ME
	JRST	ECOD11##	;ELSE ERROR
TPMSM2:	AOBJN	T3,TPMSM1	;LOOP TILL ALL UNITS DONE
	CONO	PI,PIOFF##	;TURN OFF WORLD
	HLLZS	TKBCSO##(W)	;REMOVE FROM CONSO CHAIN
	MOVSI	T1,TKSMNT##	;SET MAINT MODE BIT
	IORM	T1,TKBSTS##(W)	;IN KDB
	CONO	PI,PION##	;RESTORE WORLD
	MOVEM	J,TKBJOB##(W)	;SAVE HIS JOB NUMBER
	MOVE	T1,TKBICP##(W)	;INFO USER WOULD LIKE
	PJRST	STOTC1##	;AND SKIP RETURN

;ROUTINE TO RESTORE CTL AND CLEAR MAINT MODE

TPMCMM:	HRRZ	W,TUBKDB##(U)	;GET KDB PNTR
TPMCM1:	CAME	J,TKBJOB##(W)	;DOES THIS JOB HAVE KONTROLLER?
	JRST	ECOD11##	;NO - LOSE
	SETZM	TKBJOB##(W)	;YES, HE DOESN'T ANY MORE
	HRRZ	T4,TKBDSP##(W)	;ADDRS OF CTL DEP CODE
	PUSHJ	P,TPKINI##(T4)	;DISPATCH TO LOWER LEVEL INIT
	MOVSI	T1,TKSMNT##	;BIT TO CLEAR NOW
	ANDCAM	T1,TKBSTS##(W)	; IN KDB
	PJRST	CPOPJ1##	;AND RETURN

IFN FTMDA,<
;ROUTINE TO CALL MDA ON TAPE ON-LINE
TPMONL::MOVE	T1,@TUBDDB##(U)	;SIXBIT NAME
	MOVEI	T2,.TYMTA	;A MAGTAPE
	PUSHJ	P,SNDMDC##	;TELL MDC
	  JFCL
	POPJ	P,		; AND RETURN
>
SUBTTL MTAPE UUO

;MTAPE UUO

MTAPE0::PUSHJ	P,SAVE3##	;SAVE P1,P3
	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:	CAIG	T1,MT.MAX	;CHECK VALID ARG
	SKIPN	P3,MTDTBL(T1)	;GET TABLE ENTRY
	JRST	UUOERR##	;ERROR IF NOT IMPLEMENTED

IFN FTTLAB,<
	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
>
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
	HRRM	P3,TRBIVA(T1)	;SAVE INT VECTOR
	PUSHJ	P,TAPRQT##	;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
	HRRZ	T1,TRBIVA(P1)	;GET ROUT ADDRS
	JUMPN	T1,0(T1)	;DO SPECIAL ROUTINE
MTAPG1:	MOVEI	T1,1		;ONE OP ONLY
MTAPGO:	HRRM	T1,TRBXCW(P1)	;...
	MOVEI	T1,TPMISP	;WHERE TO GO WHEN DONE
	HRRZM	T1,TRBIVA(P1)	;SAVE IT
	MOVEI	T1,TAPTIM##	;SET A HUNG TIMER GOING
	MOVEM	T1,TKBTIM##(W)	; (NOT DEVCHK SINCE IOACT=0)
	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.FSR,,TPMFSF		;16-FORWARD SKIP FILE
	RB.FBR,,TPMBSF		;17-BACKWARD SKIP FILE

;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,WRTDUN	;WHERE TO GO
	HRRZM	T1,TRBIVA(P1)
	PJRST	TPSTRT		;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:	SETZM	TKBTIM##(W)	;NO LONGER HAVE MTAPE GOING
	PUSHJ	P,SETIOS	;SET UP S
	  JSP	P2,SPERR	;HANDLE SPACING ERROR
	PJRST	TPMSTP		;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
	PUSHJ	P,WAIT1##	;WAIT FOR THINGS TO SETTLE OUT
	HRRZ	T1,M		;RESTORE T1
	CAIE	T1,MT.DEC	;IS IT DEC MODE?
	JRST	TPSETI		;NO - SET INDUSTRY COMPAT
	MOVEI	T2,RB.MCD	;YES - SET NORMAL MODE
	DPB	T2,TDYMOD	;SET IN MODE FIELD OF DDB
	POPJ	P,		;RETURN

;HERE TO SET INDUSTRY COMPATIBLE MODE (WHATEVER THAT IS)

TPSETI:	MOVEI	T1,COMPAT	;SET BYTE IN STATUS WORD
	DPB	T1,TDYBYT
	POPJ	P,		;RETURN

;SET LOW THRESHOLD FOR TM10 CONTROLLERS

TPMLOW:	PUSHJ	P,WAIT1##	;WAIT A BIT (MAYBE)
	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:
	SETO	P2,		;REMEMBER THIS IS AN UNLOAD
	AOSA	TUBTUN##(U)	;TOTAL UNLOADS
TPMREW:	SETZ	P2,		;CLEAR UNLOAD FLAG
	MOVSI	T1,TUSREW##	;SET REWINDING NOW!
	IORM	T1,TUBSTS##(U)	;...
	PUSHJ	P,MTAPG1	;START OPERATION
	PUSHJ	P,TPMRLW	;WAIT TILL DISCONNECTED
	JUMPE	P2,TPMRW1	;NO MSG IF REWIND
	MOVE	T1,TUBCRD##(U)	;ANYTHING TO TALK ABOUT?
	IOR	T1,TUBCWR##(U)	;..
	JUMPE	T1,TPMRW1	;NOPE
	PUSHJ	P,TPSTAT	;YES - PRINT STATS
TPMRW1:	TRO	S,IOBOT		;SET BOT
	MOVSI	T1,TKSOFL##
	TDNN	T1,TUBSTS##(U)	;CHECK OFF-LINE
	PJRST	STOIOS##
	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
	MOVE	P1,F		;HIDE DDB IN P1
	MOVE	P2,U		;HIDE UDB IN P2
IFN FTWATCH,<
	PUSHJ	P,TTYFUW##	;SET UP F AND U
	LDB	J,PJOBN##	;GET CORRECT J
	MOVSI	T1,JW.WMT	;CHECK IF HE WANTS TO SEE IT
	TDNN	T1,JBTWCH##(J)	;?
>
	JRST	TPSTA3		;JUST TELL OPR & DAEMON
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?
	JRST	TPSTA1		;NO - 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##
	SKIPN	TUBCWR##(P2)	;ANYTHING WRITTEN ALSO
	JRST	TPSTA2		;NO - FINISH UP
				;;; FALLIN TPSTA1
TPSTA1:	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
TPSTA3:	TLZ	U,-1		;RH ONLY
	CAMN	U,OPRLDB##	;THIS DA OPR?
	JRST	TPSTA4		;YES - DONE
	HRRZ	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,TPDCPY	;COPY STATS TO SHADOW AREA
IFN FTEL,<
	MOVEI	T1,.ERTPS	;SET UP CODE FOR DAEMON
	HRL	T1,F		;SET UP DDB FOR DAEMON
	PUSHJ	P,DAEERR##	;PROD DAEMON
>
	POP	P,W		;RESTORE KDB
	MOVE	S,DEVIOS(F)	;RESTORE S
	POPJ	P,		;RETURN
;ROUTINE TO PERFORM SKIP FILE AS MULTIPLE SKIP RECORDS

TPMFSF:	PUSHJ	P,TPSKPS	;CALL SKIP SET
				;RETURN WITH S SETUP
	TRNE	S,IODEND!IODERR ;SEEN EOF OR DEVICE ERROR?
	POPJ	P,		;RETURN
TPMFS0:	MOVEI	T1,MT.FSF	;GO 'ROUND AGAIN
	JRST	MTAP		;...

;ROUTINE TO PERFORM BACKSPACE FILE
;USES MULTIPLE BACKSPACE RECORDS UNTIL BOT OR EOF IS SEEN

TPMBSF:	PUSHJ	P,TPSKPS	;CALL SKIP SET
				;RETURN WITH S SETUP
	TRNE	S,IODEND!IOBOT!IODERR
	POPJ	P,		;RETURN
	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,TKBSTS##(W)	;GET QUANTUM
	PUSHJ	P,MTAPGO	;START OP
TPSKPW:	MOVEI	T1,MT.WAT	;WAIT OP CODE
	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
	PJRST	MTAP		;RETURN
SUBTTL DIAG UUO

;ROUTINE TO GET CONTROLLER/UNIT NUMBERS
DIAMTA::HLRZ	U,TDVUDB##(F)	;UNIT
	HRRZ	T1,TUBKDB##(U)
	LDB	T2,[POINT 7,TKBCSO##(T1),9]
	LDB	T1,PUNIT##
	LDB	T3,TUYKTP##
	CAIE	T3,K.TM2
	LSH	T1,3
	LSH	T2,2
	HRL	T1,T2
	AOS	(P)
	PJRST	STOTAC##
SUBTTL ERROR RECOVERY

;HERE ON TAPE UNIT HUNG FROM CLOCK1

TPMHNG:	HLRZ	U,TDVUDB##(F)	;GET UNIT PNTR
	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
TPMDQ1:	CAIN	P1,TKBERB##(W)	;CHECK FOR ERROR IORB
	JRST	[HRRZ P2,TRBLNK(P1) ;TRY NEXT IF IT IS
		 JRST TPMDQ2]	;CHECK DONE
	PUSHJ	P,TPMRCW	;RETURN XFER LIST IF ANY
	MOVE	T2,P1		;SET FOR GIV4WD
	MOVEI	T1,1		;ONE BLOCK
	HRRZ	P2,TRBLNK(P1)	;GET LINK
	PUSHJ	P,GIV4WD##	;RETURN IORB
TPMDQ2:	SKIPE	P1,P2		;CHECK FOR MORE
	JRST	TPMDQ1		;YES - RETURN IT
	POPJ	P,		;DONE - EXIT
;HERE FROM GIVRES IN ERRCON

TPFREE::MOVEI	F,MT0DDB##	;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
	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:	MOVEI	W,MT0KDB##	;START AT FIRST KONTROLLER
	PUSH	P,M
	TLO	M,400000
TPFRE3:	PUSHJ	P,TPMCM1	;RELEASE MAINT MODE IF SET
	  JFCL
	HRRZ	W,TKBKDB##(W)	;NEXT KONTROL
	JUMPN	W,TPFRE3	;TEST IT IF THERE
	POP	P,M
	PJRST	UPOPJ##		;DONE IF NONE LEFT

TPMHLD::HLRZ	U,TDVUDB##(F)	;SET UP UDB PNTR
	HRRZ	W,TUBAKA##(U)	;AND KDB IF SELECTED
IFN FTTLAB,<
	HLRZ	T1,TUBDDB##(U)	;CHECK 2ND DDB
	JUMPE	T1,TPHLD1		;IF NONE THEN OK
	CAIE	T1,(F)		;IS THIS OURS
	POPJ	P,		;NO - THEN EXIT
>
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
	PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVE	P1,U		;UDB ADDRS TO P1
	MOVE	P2,W		;KDB ADDRS TO P2
	HRRZ	U,OPRLDB##	;GET OPR ADDRS TO SEND MSG
	PUSHJ	P,INLMES##	;NOW INFORM HIM
	  ASCIZ	"
%% TAPE CONTROLLER "
	MOVE	T2,TKBNAM##(P2)	;NAME
	ADD	T2,['A'-'0',,0]
	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
	SUB	T1,['A'-'0',,0]	;ADJUST FOR CTL NAME
	PUSH	P,W		;SAVE W
	MOVEI	W,MT0KDB##	;GET FIRST KDB
TPMSLL:	CAMN	T1,TKBNAM##(W)	;THIS ONE?
	JRST	TPMSL1		;YES - SET BIT
	HRRZ	W,TKBKDB##(W)	;NO - LINK TO NEXT
	JUMPN	W,TPMSLL	;CHECK NEXT IF IT EXISTS
	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
;OUTPUT ERROR DETECTED - CHECK FOR WRITE LOCK

DMPERR:				;DUMP MODE ERRORS
OUTERR:	TRNE	S,IOIMPM	;WRITE LOCKED?
	JRSTF	@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
>
	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
	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 UST TO TRY?
	JRST	ERRX1		;JUST LOG ERROR & EXIT
IFN FT5UUO,<
	MOVEI	T2,DEPDER	;ERROR RETRY DISABLED?
	TDNE	T2,DEVSTA(F)
	JRST	ERRX1		;YES, LOG AND EXIT
>
	TRZ	S,IOERRS	;ALL ERRORS
	MOVEM	S,DEVIOS(F)	;CLEAR THESE FOR NOW
	PJRST	TAPERP##	; AND TRY TO RECOVER

;HERE TO HANDLE UNIT OFF-LINE (FLUSH IORB AND RETURN TO UUO LEVEL

IFN FTTLAB,<
ERRLBL:	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	ERROF1		; AND CLEAR IODEND SO AS NOT
	TRZA	S,IODEND	; TO CONFUSE UUOCON
>
ERROFL:	TLO	S,OFFLIN	;SET OFF-LINE IN DEVIOS
IFN FTEL,<
	TRNN	T1,RB.SMO	;MONITOR DIRECTED OFF-LINE ?
	JRST	ERROF1		;NO -
	MOVSI	T1,(1B1)	;MDO IS UNRECOVERABLE
	IORM	T1,TUBTRY##(U)	;
	MOVEI	T1,.ERTAP	;INDICATE TAPE ERROR
	HRL	T1,F		;WITH DDB
	PUSHJ	P,DAEERR##	;GO TELL DAEMON
>
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
	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:	TRZ	S,IOERRS	;ALL ERROR FLGS
	MOVEM	S,DEVIOS(F)	;CLEAR ANY EXTRANEOUS BITS
	TLNE	S,IO		;WHICH WAY
	AOSA	TUBSWE##(U)	;SOFT WRITE ERROR
	AOS	TUBSRE##(U)	;SOFT READ ERROR
IFN FTEL,<
	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:	MOVEI	T1,.ERTAP	;CODE FOR DAEMON
	HRL	T1,F		;SET UP DDB ADDR FOR DAEMON
	PUSHJ	P,DAEERR	;LOG IT
ERRX4:>
IFE FTEL,<ERRX3:>
	TRNE	S,IODERR
	AOS	TUBTDE##(U)	;TOTAL DEVICE ERRORS
	TRNE	S,IODTER
	AOS	TUBTME##(U)	;TOTAL MEDIA ERRORS
	JRSTF	@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
IFN FTKI10!FTKL10,<
	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 NOT TM10A
	MOVEI	T1,@T1		;RELOCATE KA STYLE
	CONSZ	PI,II.IPA	;SKIP IF AT UUO LEVEL
	PUSHJ	P,SVEUF##	;ELSE - SET UP UBR
	TRNN	P1,DEPEVM	;SKIP IF NO TM10A
	TLZ	P2,(<17B12>)	;CLEAR AC FIELD
	XCT	P2		;CLANK INSTR
>
IFN FTKA10,<
	MOVEI	T1,@T1		;RELOCATE
	XCT	@0(P)		;XCT
>
	JRST	CPOPJ1##	;RETURN & SKIP OVER INSTR

;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,1		;ONLY WANT ONE
	PUSHJ	P,GET4WD##	;GET 4 WORDS
	  POPJ	P,		;SIGH
	MOVEI	T2,RB.RPN	;REQUEST PENDING
	ROT	T2,-RB.RQP-1	;PUT IN PROPER PLACE
	MOVEM	T2,TRBLNK(T1)	;STASH
GNIOR1:	DPB	P2,PRBFCN##	;AND FUNCTION
	LDB	T2,TDYBYT	;GET MODE/PAR/DEN
	DPB	T2,PRBBYT##	;SET INTO IORB
	SETZM	TRBSTS(T1)	;CLEAR REST OF BLOCK
	SETZM	TRBRCT(T1)
	SETZM	TRBIVA(T1)	;...
	JRST	CPOPJ1##	;GIVE GOOD RETURN

;ROUTINE TO SET UP CURRENT IORB

STOIOR:	ROT	T2,-RB.RQP-1	;POSITION STATUS
	HLLM	T2,TRBLNK(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)	; DONT CALL MSEEP
	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
	CAME	P1,TDVIOR##(F)	;THIS THE RIGHT ONE?
	JRST	KONWT2		;NO - SNOOZE SOME MORE
	HRRZ	W,TUBAKA##(U)	;SET UP W - KDB ADDRS
	SETZM	TDVIOR##(F)	;CLEAR THIS ONE NOW
	POPJ	P,		;RETURN

KONWT2:	SKIPE	TRBIVA(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
	PUSHJ	P,TAPRQH##	;PUT AT HEAD OF Q
	PUSHJ	P,KONWTN	;WAIT FOR SELECTION
				;RETURN P1 := IORB
	MOVEI	T1,CKREWD	;GO HERE ON INTERUPT
	HRRM	T1,TRBIVA(P1)	;...
	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
	PUSHJ	P,TAPHLD##	;DON'T USE US WHILE SPEEPING
	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:	HLRZ	U,TDVUDB##(F)	;GET UNIT PNTR
	HRRM	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,.C0JOB##	;SET UP J FOR SLEEP
IFN FTPSCD,<
	AOS	%MTASL##	;COUNT MTA GENERATED SLEEP
>;END IFN FTPSCD
	PUSHJ	P,SLEEP##
	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
>
	HRRZ	W,TUBKDB##(U)
	MOVSI	T1,TKSOFL##	;IF KONTROLLER ISN'T OK
	TDNN	T1,TKBSTS##(W)	; GO COMPLAIN
	TLZE	S,OFFLIN	;IS THIS OK?
	JRST	SETOFL		;NO - INFORM USER
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
>
IOSET0:	TLZ	S,OFLUNH	;CLR THIS
	LDB	T1,TDYMOD	;SEE IF WE HAVE A MODE
	JUMPN	T1,IOSET1	;JUMP IF MODE SET
	MOVEI	T1,RB.MCD	;DEFAULT TO 4.5 BYTE MODE
	MOVEI	T2,TUC7TK##	;UNLESS 7 TRACK
	TDNE	T2,TUBCNF##(U)	;??
	MOVEI	T1,RB.M7T	;THEN USE 7-TRACK MODE
	DPB	T1,TDYMOD	;PUT IT BACK

IOSET1:	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:	PUSHJ	P,GETDEN	;GET CORRECT DENSITY
	DPB	T1,TDYDEN	;STORE IN DDB
	PJRST	STOIOS##	;RETURN
;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

CKTC1A:	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
LBLCK1:	HLRZ	T1,TUBDDB##(U)	;GET 2ND DDB
	CAIN	T1,(F)		;OURS?
	JRST	LBLCK2		;YES - NO LABELING THEN
	SKIPN	%SITLP##	;SKIP IF OK TO SEND
	JRST	LBLCK2		;NO PROCESSING
	LDB	T1,TUYLTP	;GET LABEL TYPE
	JUMPE	T1,LBLCK2	;IF NO LABELS, CLEAR SOME FLAGS
	TDZ	S,[IOSTBL!LBLEOF,,IODEND]  ;DON'T LET THIS GUY SEE EOF OR TROUBLE
	JRST	STOIOS##	;EXIT IF LABELS EXPECTED
LBLCK2:	TLZ	S,LBLNED!FSTOP	;ELSE CLEAR THESE FLAGS
	MOVEM	S,DEVIOS(F)	;...
	JRST	CPOPJ1##	;SKIP RETURN
>
IFN FTTLAB,<
;ROUTINE TO INVOKE LABELING PROCESS AND SUSPEND JOB

LBLMSG:	PUSHJ	P,TAPHLD##	;SUSPEND UNIT FOR NOW
	TLZ	S,LBLNED	;CLEAR THIS NOW
	PUSHJ	P,LBLSND	;INFORM LBL PCS
	TLO	S,LBLWAT	;WE ARE NOW WAITING FOR COMPLETION
	MOVEM	S,DEVIOS(F)
	PUSHJ	P,LBLSLP	;WAIT FOR LABEL PROCESS
	LDB	T1,PDVESE##	;GET TERMINATION CODE
	JUMPE	T1,CPOPJ##	;NONE - CONTINUE
	TDO	S,LBLETB(T1)	;GET ERROR BITS FROM TABLE
	JRST	STOIOS##	;SAVE S AND RETURN

;ROUTINE TO SEND IPCF MSG TO LBL PROCESS

LBLSND:	MOVE	T1,DEVNAM(F)	;YES - BUILD MSG
	MOVEM	T1,TUBPHY##(U)	;STORE DEVICE NAME
	DPB	J,TUYJBN	;STORE JOB #
	MOVEI	T1,%SITLP##	;PID
	MOVEI	T2,TUBMSG##(U)	;ADDRS OF MSG
	HLL	T2,TUBMSG##(U)	;MESSAGE MSGE
	PJRST	SENDSN##	;TRANSMIT MESSAGE AND 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
	JRST	IOSET		;NO ERRORS - PROCEED
	POPJ	P,		;ELSE RETURN UP A LEVEL

;ROUTINE TO CHECK FOR LABEL PCS HNDLING POSITION REQUESTS

LBLPOS:	HLRZ	U,TDVUDB##(F)	;SET UP U
	DPB	T1,TUYINF	;SET UP MTAPE CODE
	MOVE	S,DEVIOS(F)	;SET UP STATUS
	LDB	J,PJOBN##	;SET UP JOB #
	PUSHJ	P,LBLCHK	;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##

;TABLE TO TRANSLATE LABEL TERM CODE INTO BITS IN IOS

LBLETB:	-1			;0 - ILLEGAL
	0			;1 - CONTINUE POSITIONING
	LBLSTP!FSTOP,,IODEND	;2 - RETURN EOF + CALL TAPE LABEL PCS ON NEXT IN/OUT
	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
	LBLSTP,,IODTER		;10 - DATA ERROR
	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-17 RESERVED
	FSTOP!LBLSTP,,IOERRS
	FSTOP!LBLSTP,,IOERRS

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

GETDEN:	LDB	T1,[POINT 2,DEVIOS(F),28] ;SEE IF CHANGED BY SETSTS
	JUMPN	T1,CPOPJ##	;IF YES - USE IT
	LDB	T1,TDYDN1	;SEE IF CHANGED BY SET DENSITY
	JUMPN	T1,GETDN1	;IF YES, TRY IT
	MOVEI	T1,STDENS##	;ELSE USE STANDARD
GETDN1:	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
	POPJ	P,		;AND RETURN

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

IFN FTKL10,<
;ROUTINE CALLED TO SWEEP CACHE UNLESS DEVICE IS A TM10A
;DESTROYS T1
TPMSWP:	MOVEI	T1,DEPEVM		;DOES THIS DEVICE NEED
	TDNE	T1,DEVTYP(F)		; EVM (TM10A IF SO)
	PUSHJ	P,CSDMP##		;NO, WE MUST SWEEP THE CACHE
	POPJ	P,			;RETURN
>
;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,,IOBOT!IOTEND!IODEND!IOERRS]>
IFE FTTLAB,< TDZ S,[IOEND!IOSTBL,,IOBOT!IOTEND!IODEND!IOERRS]>
				;CLEAR ALL RELATED BITS
	SKIPL	TRBLNK(P1)	;ANY EXCEPTIONS?
	JRST	SETIOX		;NO - JUST STORE AND EXIT
	TRNE	T1,RB.SOL	;CHECK OFF-LINE
	PJRST	STOIOS##	;YES - HANDLE SPECIAL
	TRNN	T1,RB.SED	;ANY ERROR
	JRST	SETS1		;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
SETS1:	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
	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	;IMPROPER MODE
IFN FTTLAB,<
	LDB	T1,TUYLTP	;GET LABEL TYPE
	SKIPE	%SITLP##	;IS THERE A TAPE LABEL PROCESS?
	SKIPN	T1		;BYPASS?
	TLZ	S,LBLNED	;YES - CLEAR BIT
	TDNN	S,[LBLNED,,IOERRS] ;NON-SKIP IF ANY
>
IFE FTTLAB,<
	TRNN	S,IOERRS	;NON-SKIP IF ANY
>
SETIOX:	AOS	0(P)		;SET FOR SKIP RETURN
	PJRST	STOIOS##	;STASH IOS AND EXIT
;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
IFN FTKI10!FTKL10,<
	PUSHJ	P,SVEUF##	;MAKE JOB ADDRESSABLE
	MOVEI	P2,DEPEVM	;CHECK FOR TM10A
	TDNN	P2,DEVTYP(F)	;SKIP IF IT IS
	JRST	MAKLS0
	ADDI	T2,0(R)
	HLL	T2,P1
>
MAKLS0:	MOVEM	P1,TRBRCT(T1)	;SAVE NUMBER OF WORDS, UVA IN IORB (FOR TM2KON)
	LDB	P4,PRBMOD##	;GET MODE
	MOVE	P4,TMODTB##(P4)	;CHARS/WD TABLE (4,5,6)
	LDB	T1,PBUFRM##	;MAX FRAME COUNT USER GAVE
	SKIPE	T1
	CAMLE	T1,T4
	MOVE	T1,T4
	HRL	P4,T1		;IN LH (P4)
IFN FTDX10,<
IFN FT5UUO,<
	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
>
	HRRZ	P3,TKBCDB##(W)	;ADDRS OF CHNCB
	HRRZ	T1,TUBQUE##(U)	; RESTORE LOC OF IORB
IFN FTKI10!FTKL10,<
	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
	  JRST	MAKLSE		;ERROR - NO FREE SPACE
IFN FTDX10,<	;THIS ONLY WORKS FOR TU70'S
;MAKE MULTI-IOWD LIST IF TU70
	MOVEI	T4,1		;AT LEAST ONE RECORD WILL BE DONE
	MOVEM	T4,TKBCNT##(W)
	TRNE	S,IOCON		;DISCONTINUOUS MODE?
	JRST	CHNDON		;YES, DONE
	MOVE	T4,TKBDSP##(W)	;DOES DEVICE SUPPORT COMMAND CHAINING?
	SKIPN	TUBCNI##(U)	; AND NO ERRORS DETECTED ON LAST XFER?
	SKIPL	TPKCMD##(T4)
	JRST	CHNDON		;NO, ONLY DO 1 RECORD
	LDB	T4,PRBFCN##	;YES, IS IT BUFFERRED MODE,
	LDB	T2,PIOMOD##	; AND NOT READ-BACKWARD?
	CAIE	T4,RB.FRB
	CAIL	T2,SD
	JRST	CHNDON		;NO, ONLY 1 RECORD
	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 FTDX10 CONDITIONAL
CHNLS1:	EXCTUX	<HRRZ T1,(T3)>	;STEP TO NEXT BUF
	CAIN	T4,(T1)		;BACK WHERE WE STARTED?
	JRST	CHNDON		;YES, DONE
	PUSHJ	P,IADRCK##	;WORD 0 OF BUFFER THERE?
	  JRST	CHNDON		;NO, 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,TKBDSP##(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:	EXCTUX	<MOVN T2,1(T1)>;WRITING, GET USERS WRDCNT
	JUMPE	T2,CHNLSX	;DONE IF 0
	LDB	T3,PIOMOD##
	CAIE	T3,BYTMOD
	JRST	CHNLS4
	PUSH	P,T1
	HRRE	T1,TUBQUE##(U)
	LDB	T3,PRBMOD##
	POP	P,T1
	MOVNS	T2
	LDB	T4,PBUFRM##
	JUMPE	T4,CHNLS3
	CAMGE	T4,T2
	MOVE	T2,T4
CHNLS3:	HRL	P4,T2
	IDIV	T2,TMODTB##(T3)
	SKIPE	T3
	ADDI	T2,1
	MOVNS	T2
CHNLS4:
	HRRZS	T3,T1		;SAVE START ADR
	HRL	T3,T2		; AND WORDCOUNT
IFN FTVM,<
	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
>
IFE FTVM,<
	SUB	T1,T2		;TOP OF BUFFER
	PUSHJ	P,IADRCK##	;TOP OF BUFFER THERE?
	  JRST	CHNLSX		;NO
>
	MOVE	T2,T3		;IOWD
	ADDI	T2,1(R)		;RELOCATE IT
	HLL	T2,T3		;IN CASE OF OVERFLOW OF ADDRESS
	PUSH	P,P1		;SAVE CURRENT END
	PUSHJ	P,MAPIO##	;GO MAP IT
	  JRST	CHNPNT		;NOT ENOUGH FREE CORE
	POP	P,(P)		;DISCARD PREVIOUS END
	AOS	TKBCNT##(W)	;ONE MORE RECORD IN THIS XFER
	JRST	CHNLS1		;GO TEST NEXT BUFFER
;STILL IN FTDX10 CONDITIONAL
;HERE WHEN MAPIO RAN OUT OF ROOM
CHNPNT:	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:>	;END FTDX10



	MOVE	P3,P1		;SAVE PNTR TO NEXT WORD
>	;END IFN FTKI10!FTKL10
IFN FTKA10,<
	JRST	MAKLS1
>
MAKLSX:
IFN FTKI10!FTKL10,<
	MOVE	T1,-6(P)
>
IFE FTKI10!FTKL10,<
	MOVE	T1,-4(P)	;IORB TO T1
>
	HRRM	P2,TRBXCW(T1)	;STORE EVA OF IOLIST
	HRLM	P3,TRBEXL(T1)	;POINT TO LAST WORD OF XFER LIST
IFN FTRDBACK,<
	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
IFN FTKI10!FTKL10,<
	PUSHJ	P,GCH4WD##	;GET BLOCK OF STORAGE
	  JRST	T2POPJ##	;ERROR RETURN
>
IFN FTKA10,<
	MOVEI	T2,1		;GET 4 WORDS
	PUSHJ	P,GET4WD##
	  JRST	T2POPJ##	;SORRY FOLKS
>
	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

IFN FTKI10!FTKL10,<
;HERE WHEN MAPIO LOST - RETURN ANY PARTIAL STUFF

MAKLSF:	MOVE	P1,-6(P)
	HRRZ	T1,TRBXCW(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
>

;ENTER HERE FOR DUMP MODE IOLISTS

MAKLSD:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	MOVE	P1,T2
	SUBI	P1,(R)
IFN FTKI10!FTKL10,<
	PUSHJ	P,SVEUF##
>
	PJRST	MAKLS0		;CONTINUE PROCESSING

;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
IFN FTKI10!FTKL10,<
	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
>
	PUSHJ	P,(T3)	;WAIT FOR EVENT
	MOVE	S,DEVIOS(F)	;NEW STATE OF UNIT
	POPJ	P,
IFN FTRDBACK,<
;ROUTINE TO GENERATE XFER LIST FOR READ BACKWARDS
;ENTER WITH P2 := FORWARD XFER LIST
;	    T1 := IORB ADDRS
;	    P4 := CHARS/WD

IFN FTKI10!FTKL10,<
INVERT:	LDB	T2,TUYKTP##	;UNIT TYPE
	CAIE	T2,K.TX1	;TX01?
	PJRST	CPOPJ1##	;NO, LEAVE THE LNT ALONE
	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	MAKLSE		;LOSE
	HRRM	T1,TRBXCW(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
	MOVNS	T3		;POSITIVE
	IDIVI	T3,(P4)		;MAKE INTO WORDS
	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,INVMOR	;NEED MORE STORAGE
	  PJRST	MAKLSF		;RETURN TRASH AND LOSE
	JRST	INVL2		;TRY AGAIN

INVD3:	AOBJN	P1,.+1		;POINT TO END OF LIST
	SETZM	0(P1)		;GRNTEE ZERO
IFN FTDX10,<
	MOVE	T1,-6(P)
>
IFE FTDX10,<
	MOVE	T1,-4(P)	;RESTORE IORB
>
	HRLM	P1,TRBEXL(T1)	;SAVE NEW LIST END
	MOVE	T1,P2		;NOW RETURN OLD LIST
	PUSHJ	P,RTNIOW##
	PJRST	CPOPJ1##	;GIVE GOOD RETURN
>
IFN FTKA10,<
INVERT:	MOVEI	T2,P2		;RETURN IOWDS
	MOVEI	T1,1		;...
	PJRST	GIV4WD##	;AND GIVE ERROR
>
INVMOR:	PUSH	P,U		;SAVE U
	MOVEI	U,0		;CAUSE GETMOR TESTS U
	PUSHJ	P,GETMOR##	; TO SET RH20 GOTO WORDS
	  SOS	-1(P)		;LOSE
	JRST	UPOPJ1##	;RETURN
>	;;; END IFN FTRDBACK
;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

ASYNCO:	SKIPA	T2,[TPMOU1]	;OUTPUT
ASYNCI:	MOVEI	T2,TPMIN1	;INPUT
	HRRM	T2,TRBIVA(T1)	;SAVE IN INT VECTOR
	PUSH	P,T1		;SAVE IORB PNTR
	PUSHJ	P,CKREW		;MAKE SURE NOT REW'D
	PUSHJ	P,SETACT##	;MAKE (RAD)IOACTIVE
	POP	P,T1		;IORB
	MOVSI	T2,RB.AIO	;SPECIAL IORB
	IORM	T2,TRBLNK(T1)	;...
	CONO	PI,PIOFF##	;FIGHT RACE
	PUSHJ	P,TAPRQT##	;QUEUE IORB, SELECT IF IDLE
	MOVE	T1,TUBSTS##(U)
	CONO	PI,PION##	;RESTORE PI
	TLNN	T1,TKSSEL##	;UNIT SELECTED?
	POPJ	P,		;NO, IT WILL HAPPEN LATER
	HRRZ	T1,TUBQUE##(U)	;YES, SET T1=IORB
	JRST	TAPAGO##	; AND GO DO IO WITH IT
IFN FTWATCH,<
;PROCESS CONTROL-T
TPMCTT::PUSHJ	P,SAVE1##	;SAVE P1
	HLRZ	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,
>	;END FTWATCH
SUBTTL	TAPSER CALLED ROUTINES

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

TPMSIO::HRRZ	F,TUBCUR##(U)	;PNTR TO DDB
	MOVSI	T2,RB.AIO	;CHECK FOR SPECIAL IORBS
	TDNE	T2,TRBLNK(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
	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
	HRRZ	F,TUBCUR##(U)	;PNTR TO DDB
	LDB	J,PJOBN##	; J = JOB NUMBER
	MOVE	R,JBTADR##(J)	; R = ADDRS OF JOBDAT
	LDB	T1,PRBDEN##	;GET SELECTED DENSITY
	DPB	T1,TDYDN1	;SAVE FOR ALL TO SEE
	HRRZ	T1,TRBIVA(P1)	;GET ROUTINE ADDRS
	JUMPN	T1,0(T1)	;DIPATCH
	STOPCD	.,STOP,NIV,	;++ NULL INT VECTOR ADDRS
IFN FTTLAB,<
;TAPE LABELING DDB PROTOTYPE

LPROTO:
	0			;(0) DEVNAM
	<^D5*HUNGST>,,MTSIZ##+1  ;(1)  DEVCHR
	0			;(2)  DEVIOS
	TPMDSP			;(3)  DEVSER
	1023,,ASSCON+154403	;(4)  DEVMOD
	0			;(5)  DEVLOG
	0			;(6)  DEVBUF
	R,,0			;(7)  DEVIAD
	R,,0			;(10) DEVOAD
	0			;(11) DEVSTS
	.TYMTA!DEPLEN,,0	;(12) DEVSTA
	0			;(13) DEVXTR
	0			;(14) DEVEVM
	0			;(15) DEVPSI
	0			;(16) DEVJOB (6.02 AND LATER)
	PHASE	DEVPSI+2
	0			;(17) LH = UDB PNTR
				;     RH = KDB PNTR
	0			;(20) UNIT STATUS INFO
	0			;(21) IORB TO WAIT FOR
	0			;(22) SAVED USER UPPER LIMIT
	0			;(23) SAVED USER LOWER LIMIT
	0			;(24) SAVED M FOR DUMP MODE
	0			;(25) REMAINDER FOR MODE 16
TDVSVQ:! 0			;(26) PLACE TO SAVE 'Q' FOR LABELING PCS
	DEPHASE
SPROTO==.-LPROTO
>
	LIT
TPMEND::!  END