Google
 

Trailing-Edge - PDP-10 Archives - de-10-omona-v-mc9 - tapser.mac
There are 11 other files named tapser.mac in the archive. Click here to see a list.
TITLE TAPSER - COMMON MAGTAPE PHYSICAL IO DRIVER  V2032
SUBTTL  L.BOSACK/TAH/TW  13 DEC 77
	SEARCH F,S
	$RELOC
	$HIGH



;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1974,1975,1976,1977,1978 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VTAPSR,2032			;FOR LINKEDIT MAP
	SALL

TAPSER::	ENTRY	TAPSER
;BIT DEFINITIONS

;IN TKBSTS & TUBSTS

TKSOFL==:(1B17)		;OFFLINE
TKSSEL==:(1B16)		;SELECTED
TKSSTD==:(1B15)		;STARTED
TKSSCH==:(1B14)		;REQUESTED SCHED INTERUPT
TKSSIL==:(1B13)		;REQUEST SILENCE ABT OFF-LINE CONDITION
TKSMNT==:(1B12)		;CTL IS IN MAINT MODE

;IN TUBSTS

TUSNS==:(1B0)		;DO NOT SCHEDULE THIS UNIT (SIGN BIT)
TUSBOT==:(1B1)		;BEGINNING OF TAPE
TUSWTL==:(1B2)		;WRITE LOCKED
TUSREW==:(1B3)		;TAPE REWINDING
TUSBOF==:TUSBOT!TKSOFL

;IN TUBCNF

TUC7TK==:1B18		;SEVEN TRACK
TUCIRD==:1B19		;INTERUPTS WHEN REWIND DONE
TUCDMS==:1B20		;DIAG MODE SET
TUCSNS==:1B21		;FORCE SENSE
;TUCD??==:1B22		;THIS BIT LEFT FOR EXPANSION
TUCD62==:1B23		;DRIVE CAN DO 6250 BPI
TUCD16==:1B24		;DRIVE CAN DO 1600 BPI
TUCD80==:1B25		;DRIVE CAN DO 800 BPI
TUCD55==:1B26		;DRIVE CAN DO 556 BPI
TUCD20==:1B27		;DRIVE CAN DO 200 BPI
;  THE FOLLOWING SYMBOLS ARE FOR THE CONVENIENCE OF MACRO V50
TUCDR8==:TUCD20+TUCD55+TUCD80	;TM10 9 TRACK DENSITIES
TUCDR7==:TUC7TK+TUCDR8		;7 TRACK TAPE + DENSITIES
TUCDR6==:TUCD80+TUCD16		;TM02 AND TU70 DENSITIES
TUCDR5==:TUCD16+TUCD62		;TU72 DENSITIES

;PI SYSTEM DEFINITIONS

TPIOFF==:PI.TFP+TAPBIT##	;TURN OFF TAPE CHL
TPION==:PI.TNP+TAPBIT##		;TURN ON TAPE CHL

;ERROR RECOVERY PARAMETERS

ERPNCS==5		;NUMBER OF BACKSPACE/SPACE OP IN TAPE CLEANER SEQ.
TPKINI==:0		;INITIALIZATION CODE
TPKRES==:1		;RESET ACTIVE TRANSFER
TPKSIO==:2		;START IO
TPKINT==:3		;INTERRUPT ROUTINE
TPKCMD==:4		;SET DEVICE COMMAND IN LIST (DX10 ONLY)
TPKIDL==:5		;SET DEVICE IDLE
TPKONL==:6		;SKIP IF KON ONLINE
TPKSCH==:7		;CAUSE SCHEDULE CYCLE

;BYTE POINTERS

;INTO KDB

;INTO UDB

TUYKTP:: POINT 4,TUBCNF##(U),35		;CONTROLLER TYPE
TUYECT:	POINT	ERCCTS,TUBERR##(U),17	;POINTER TO RETRY COUNTER
TUYEC1:	POINT	ERCCTS,TUBERR##(U),17-ERCCTS	;SECONDARY RETRY COUNTER

;INTO IORB

PRBRQS:: POINT RB.RQS,TRBLNK(T1),RB.RQP		;REQUEST STATUS
PRBMOD:: POINT RB.MDS,TRBLNK(T1),RB.MDP		;REQUEST MODE
PRBMD2:: POINT RB.MDS,TRBLNK(P1),RB.MDP
PRBFCN:: POINT RB.FNS,TRBLNK(T1),RB.FNP		;REQUEST FUNCTION
PRBDEN:: POINT RB.DNS,TRBLNK(T1),RB.DNP		;DENSITY
PRBBYT:: POINT RB.BYS,TRBLNK(T1),RB.BYP		;REQUEST INFO
SUBTTL INTERRUPT SERVICE.
;HERE WITH AC'S SAVED AND PDL SETUP.
;C(W) := KDB ADDRESS
;AFTER CALL TO DEVICE DEPENDENT ROUTINE OR ERROR PROCESSOR
;C(T1) := IORB ADDRS IF COMPLETED
;	  0 IF ANOTHER INTERUPT COMING - NO FURTHER PROCESSING
;	  -1 IF SCHED CYCLE REQUESTED
;C(TUBERR) NON-ZERO IF ERROR RECOVERY IN PROGRESS

TAPINT::HRRZ	T1,TKBDSP##(W)	;GET XFER VECTOR
	PUSHJ	P,TPKINT(T1)	;CALL DEV DEP INT RTN
TAPAGO::JUMPE	T1,CPOPJ	;IF ZERO, ANOTHER INT IS COMING
	JUMPL	T1,TPINT1	;NO COMPLETION - DO SCHEC CYCLE
	MOVSI	T2,TKSSTD	;CHANNEL NO LONGER STARTED
	ANDCAM	T2,TKBSTS##(W)	;SO CLEAR STATUS
	ANDCAM	T2,TUBSTS##(U)	;AND UNIT STATUS
	SKIPE	T2,TUBERR##(U)	;IS ERP IN PROGRESS?
	PUSHJ	P,ERPINT	;YES - CALL INTERRUPT PART
	JUMPE	T1,CPOPJ	;TERMINATE NOW?
	JUMPL	T1,TPINT1	;NO COMPLETION
	MOVEI	T2,RB.DUN	;MARK IORB AS DONE
	DPB	T2,PRBRQS	;...
	PUSHJ	P,TPMDON##	;YES - NOTIFY UPPER LEVEL
	HRRZ	T2,TKBSTS##(W)	;SEE IF A SCHED CYCLE IS DUE
	JUMPG	T2,CPOPJ##	;NO - DISMISS
	PUSHJ	P,TAPDSL	;DE-SELECT KONTROLLER
TPINT1:	SETZM	TKBTIM##(W)	;CLEAR HUNG TIMER
	PUSHJ	P,TAPSCH	;SEE IF THERE IS MORE WORK
	  POPJ	P,		;NO MORE TO DO
	PJRST	TPMSIO##	;START IO

;ROUTINE TO DE-SELECT A KONTROLLER AND CLEAR I/O

TAPDSL:	HRRZ	T1,TKBDSP##(W)	;GET XFER VECTOR
	PUSHJ	P,TPKIDL(T1)	;MARK IDLE
	HLLZS	TKBSTS##(W)	;SET QUANTUM TO ZERO
	MOVSI	T1,TKSSEL	;CLEAR SELECTION BITS
	ANDCAM	T1,TUBSTS##(U)	;  IN UDB
	ANDCAM	T1,TKBSTS##(W)	;  AND KDB
	POPJ	P,		;RETURN

;GENERAL INTERUPT ERROR HALT

TAPIFI::STOPCD	.,STOP,IFI,	;++ ILLEGAL FUNCTION AT INTERUPT
SUBTTL CHANNEL SCHEDULER
;W/ KDB TO CONTINUE SCANNING.
;SKIP RETURNS WITH W AND U SETUP IF ANOTHER REQUEST IS
;FOUND.
;NON SKIP RETURN IF NOTHING TO DO

TAPSCH:	MOVSI	T2,TKSOFL!TKSMNT ;CHECK IF HE IS AMOUNG US
	TDNE	T2,TKBSTS##(W)	;...
	JRST	TPSCHX		;NO - JUST EXIT
	MOVE	T4,TKBCUN##(W)	;GET CURRENT AOBJN POINTER
	AOBJP	T4,TPSCH2	;AND START LOOKING AT NEXT UNIT

TPSCH1:	SKIPN	U,(T4)		;GET UDB
	JRST	TPSCHN		;NONE PRESENT
	HRRZ	T1,TUBQUE##(U)	;GET QUEUE POINTER
	JUMPE	T1,TPSCHN	;GO IF NONE
	SKIPL	T2,TUBSTS##(U)	;NO SCHED?
	TLNE	T2,TKSSEL	;OR SELECTED BY ANOTHER?
	JRST	TPSCHN		;YES
	JRST	TPSCH3		;FOUND 1 - USE IT
TPSCHN:	CAMN	T4,TKBCUN##(W)	;BACK TO ORIGINAL UNIT?
	JRST	TPSCHX		;NOTHING TO DO - NON SKIP RETURN
	AOBJN	T4,TPSCH1	;NEXT UNIT
TPSCH2:	MOVE	T4,TKBIUN##(W)	;RESET POINTER
	JRST	TPSCH1		;CONTINUE SEARCH

;HERE WHEN A REQUEST IS FOUND

TPSCH3:	MOVEM	T4,TKBCUN##(W)	;STORE CURRENT UNIT
	MOVSI	T2,TKSSEL	;FLAG AS SELECTED
	IORM	T2,TKBSTS##(W)	;IN KDB
	IORM	T2,TUBSTS##(U)	;AND IN UDB
	MOVEI	T2,MQUANT##	;SET SLICE
	HRRM	T2,TKBSTS##(W)	; ..
	HLRZ	T3,TUBADR##(U)	;GET KON1 ADR
	HLRZ	T2,TUBKDB##(U)	;SETUP CURRENT KON AND ADR
	CAIE	T2,(W)		; ...
	HRRZ	T3,TUBADR##(U)	; ...
	HRLM	T3,TUBAKA##(U)	;STORE UNIT ADDR
	HRRM	W,TUBAKA##(U)	;STORE KDB ADDRESS
	AOS	0(P)		;SET FOR SKIP RETURN
TPSCHX:	MOVSI	T2,TKSSCH	;CLEAR FACT THAT WE SCHEDULED
	ANDCAM	T2,TKBSTS##(W)	;  FOR THIS KDB
	POPJ	P,		;RETURN
SUBTTL START IO
;HERE WHEN UPPER LEVEL WANTS TO START IO. THE USER JOB IS LOCKED
;AND THE IORB HAS A VALID DATA XFR LIST IF ONE IS NEEDED

TAPSIO::MOVE	T2,TKBSTS##(W)	;KONTROLLER STATUS
	TLOE	T2,TKSSEL	;SELECTED?
	TLZE	T2,TKSSTD!TKSOFL ;AND NEITHER STARTED NOR OFF-LINE?
	STOPCD	TAPSI3,DEBUG,KSW, ;++KONTROLLER STATUS WRONG
TAPSI1:	MOVE	T2,TUBSTS##(U)	;UNIT STATUS
	TLOE	T2,TKSSEL	;SELECTED?
	TLZE	T2,TKSSTD	;AND NOT STARTED (ON ANOTHER KONTROL)?
	STOPCD	TAPSI4,DEBUG,USW, ;++UNIT STATUS WRONG
TAPSI2:	MOVEI	T2,RB.ACT	;SET IORB STATUS TO ACTIVE
	DPB	T2,PRBRQS	; ...
	MOVSI	T2,TKSSTD	;MARK AS STARTED
	IORM	T2,TKBSTS##(W)	;IN KDB
	IORM	T2,TUBSTS##(U)	;AND UDB
	HRRZ	T2,TKBDSP##(W)	;GET KONTROLLER DISPATCH
	PJRST	TPKSIO(T2)	;CALL START I/O

;HERE AFTER KSW STOPCD, TRY TO RECOVER
TAPSI3:	MOVEM	T2,TKBSTS##(W)	;STORE REASONABLE STAUS
	JRST	TAPSI1		;GO CHECK UNIT STAUS

;HERE AFTER USW STOPCD
TAPSI4:	MOVEM	T2,TUBSTS##(U)	;STORE REASONABLE STATUS
	JRST	TAPSI2		;GO START THE IO
SUBTTL ONLINE CHECK
;HERE ONCE A SECOND/MINUTE..  GROVEL THROUGH THE KDBS AND SEE
;IF THERE ARE ANY OFFLINE. IF SO, COMPLAIN THROUGH TPMOFL.
;IF ANY CLAIM TO BE OFFLINE AND ARE NOW ONLINE, INITIALIZE
;AND OPERATE A SCHEDULE CYCLE. (IT IS UNLIKELY ANYTHING WILL
;				BE THERE, BUT IN CASE..)

CHKKON:	MOVEI	W,MT0KDB##	;GET FIRST KDB
CHKKNL:	MOVSI	T1,TKSMNT	;BIT TO TEST
	TDNE	T1,TKBSTS##(W)	;  TOO SEE IF WE SHOULD CHECK
	JRST	CHKNXT		;  IF HE IS ONLINE
	HRRZ	T1,TKBDSP##(W)	;GET XFR VECTOR
	PUSHJ	P,TPKONL(T1)	;SEE IF ONLINE
	  JRST	CHKOFL		;NOT ON LINE - COMPLAIN
	MOVSI	T1,TKSOFL	;NOW ONLINE - SEE IF
	TDNN	T1,TKBSTS##(W)	;IF FORMERLY OFFLINE.
	JRST	CHKNXT		;NO
	TLO	T1,TKSSCH!TKSSTD!TKSSEL ;CLR THESE ALSO
	ANDCAM	T1,TKBSTS##(W)	;CLEAR OFFLINE
	MOVSI	T2,TKSSTD!TKSSEL ;BITS TO CLEAR IN UDB
	MOVE	T3,TKBIUN##(W)	;GET AOBJN PNTR TO LIST
CHKUNL:	SKIPE	U,0(T3)		;UNIT PRESENT?
	ANDCAM	T2,TUBSTS##(U)	;YES - CLEAR BITS
	AOBJN	T3,CHKUNL	;LOOP TILL DONE
	HRRZ	T1,TKBDSP##(W)	;YES - GET XFR VECTOR
	PUSHJ	P,TPKINI(T1)	;CALL TO INITIALIZE
	PUSHJ	P,CKSIO1	;CLANK SCHED FOR THIS KON.
CHKNXT:	HRRZ	W,TKBKDB##(W)	;GET NEXT KDB
	JUMPN	W,CHKKNL	;IF THE IS ONE, CHECK IT.
	PJRST	CPOPJ1##	;ELSE SKIP OVER ARG

CHKOFL:	PUSHJ	P,@0(P)		;CALL CO-ROUTINE
	JRST	CHKNXT		;CONTINUE LOOP
;ONCE A SECOND - JUST CHECK AND UPDATE INFO

TAPSEC::PUSHJ	P,CHKKON	;CRAWL THROUGH DATA BASE
	  JRST	SETOFL		;WHERE TO GO FOR OFF-LINE CTL
	MOVEI	W,MT0KDB##	;START AT FIRST KONTROLLER
TAPSE1:	SOSE	TKBTIM##(W)	;HUNG MTAPE?
	JRST	TAPSE2		;NO
	MOVSI	T1,TKSSCH	;HUNG TRYING TO FORCE A SCHEDULE?
	TDNN	T1,TKBSTS##(W)	;...
	JRST	TAPSE3		;NO, MUST BE A REAL TAPE OPERATION
	HRRZ	T1,TKBDSP##(W)	;YES, TRY AGAIN
	PUSHJ	P,TPKSCH(T1)	; BY REQUESTING ANOTHER INTERRUPT
	JRST	TAPSE2		;LOOK AT NEXT KONTROLLER
TAPSE3:	MOVE	U,TKBCUN##(W)	;GET RIGHT UNIT
	MOVE	U,(U)
	MOVE	T1,TUBSTS##(U)
	TLNN	T1,TKSSEL	;IS UNIT SELECTED?
	JRST	TAPSE2		;NO, BETTER HUNG THAN STOPCD
	MOVE	F,TUBCUR##(U)	;YES, SET SO DEVCHK WILL CATCH IT
	MOVEI	T1,1
	DPB	T1,PDVCNT##
	MOVEI	S,IOACT
	IORM	S,DEVIOS(F)
TAPSE2:	HRRZ	W,TKBKDB##(W)	;STEP TO NEXT KONTROLLER
	JUMPN	W,TAPSE1
	POPJ	P,		;DONE - RETURN

SETOFL:	MOVSI	T1,TKSOFL
	TDNE	T1,TKBSTS##(W)	;ON LINE?
	POPJ	P,		;NO - JUST RETURN
	IORM	T1,TKBSTS##(W)	;YES - ITS OFF NOW
	PJRST	TPMOFL##	;TELL WORLD AND RETURN

;ONCE A MINUTE - SEE IF STILL OFF LINE

TAPMIN::PUSHJ	P,CHKKON	;LOOK AT THINGS
	  JRST	TPMOFL##	;JUST COMPLAIN IF OFF LINE
	POPJ	P,		;RETURN
SUBTTL HUNG DEVICE

TAPHNG::TAPOFF			;WHO KNOWS WHAT EVIL...
	HRRZ	W,TUBAKA##(U)	;GET CURRENT KDB
	HRRZ	T2,TKBDSP##(W)	;CALL KON RESET ENTRY
	PUSHJ	P,TPKRES(T2)	; ...
	MOVSI	T1,TKSSTD	;CLEAR STARTED
	ANDCAM	T1,TUBSTS##(U)	;IN UDB
	TLO	T1,TKSSCH	;ALSO CLEAR SCH
	ANDCAM	T1,TKBSTS##(W)	;IN KDB
				;PRUNE QUEUE, DESELECT,PION

TAPKIL::TAPOFF			;FIGHT RACE
	HRRZ	W,TUBAKA##(U)	;GET KONTROLLER
	HRRZ	T1,TUBQUE##(U)	;RETURN HEAD OF LIST
	MOVSI	T2,TUBQUE##(U)	;RESET POINTERS
	MOVEM	T2,TUBQUE##(U)	; ...
	HLLZS	TKBSTS##(W)	;ZERO QUANTUM
	SETZM	TUBERR##(U)	;STOP ERROR RECOV
	MOVSI	T2,TUSNS	;CLEAR HOLD
	ANDCAM	T2,TUBSTS##(U)
	PUSH	P,T1		;SAVE PNTR
	PUSHJ	P,TPCSEL	;DESELECT IF NECESSARY
	POP	P,T1		;RESTORE PNTR
	PJRST	TPONPJ		;TURN ON PI AND EXIT

SUBTTL HOLD/CONTINUE

;HERE TO SET NS BIT ON A UNIT

TAPHLD::MOVSI	T1,TUSNS	;SET NO SCHEDULE
	IORM	T1,TUBSTS##(U)	;...
	MOVSI	T1,TKSSTD	;SEE IF STARTED
	TDNE	T1,TUBSTS##(U)	;...
	JRST	[HLLZS TKBSTS##(W) ;GRNTEE NO MORE
		 POPJ P,]	;RETURN
TPCSEL:	MOVSI	T1,TKSSEL	;SEE IF SELECTED
	TDNN	T1,TUBSTS##(U)
	POPJ	P,		;NOT SELECTED - EXIT
	PUSHJ	P,TAPDSL	;YES - DESELECT
	PJRST	CKSIO1		;CLANK SCHED IF NECESSARY

;ROUTINE CALLED TO ALLOW UNIT TO SCHEDULE AGAIN

TAPCNT::MOVSI	T1,TUSNS
	ANDCAM	T1,TUBSTS##(U)	;CLEAR NS BIT


	HLRZ	W,TUBKDB##(U)	;CHECK ONE KONT
	PUSHJ	P,CKSIO1	; ...
	HRRZ	W,TUBKDB##(U)	;AND THEN THE OTHER
				;FALL INTO CKSIO1

CKSIO1:	JUMPE	W,CPOPJ		;IF NONE, PUNT
	MOVSI	T2,TKSSEL!TKSSCH!TKSOFL
	TDNE	T2,TKBSTS##(W)	; ARE ANY OF THESE ON?
	POPJ	P,		;YES - SOMETHING WILL HAPPEN
	MOVSI	T2,TKSSCH	;SET SCHED REQUESTED
	IORM	T2,TKBSTS##(W)	;...
	PUSH	P,U		;SAVE U
	PUSHJ	P,TAPSCH	;TRY TO START SOMETHING
	  JRST	UPOPJ##		;NOTHING TO DO, RETURN FOR NOW
	MOVE	T1,F		;STARTED, SAVE F
	MOVE	F,TUBCUR##(U)	;CURRENT DDB
	LDB	F,PJOBN##	;JOB NUMBER
	EXCH	T1,F		;T1=JOB, RESTORE F
	PUSHJ	P,EWAKE##	;RESTART THE JOB, HE HAS THE KONTROLLER NOW
	JRST	UPOPJ##		;RESTORE U AND RETURN
SUBTTL QUEUE MANIPULATION
;HERE TO INSERT AN IORB AT THE HEAD OF A UNIT QUEUE
;U/ UDB, T1/ IORB

TAPRQH::MOVEI	T2,RB.RPN	;SET IORB TO PENDING
	DPB	T2,PRBRQS	; ...
	TAPOFF			;FIGHT RACE
	HRRZ	T2,TUBQUE##(U)	;GET HEAD POINTER
	HRRM	T2,TRBLNK(T1)	;FORWARD LINK
	HRRM	T1,TUBQUE##(U)	;NEW HEAD
	PUSHJ	P,TAPCNT	;SEE IF THE CHANNEL NEEDED TO BE POKED
	PJRST	TPONPJ		;RESTORE INTS AND EXIT

;HERE TO INSERT AN IORB AT THE TAIL OF A UNIT QUEUE
;U/UDB, T1/IORB

TAPRQT::MOVEI	T2,RB.RPN	;SET IORB AS PENDING
	DPB	T2,PRBRQS	; ...
	TAPOFF			;FIGHT RACE
	HLRZ	T2,TUBQUE##(U)	;GET TAIL POINTER
	HRRM	T1,TRBLNK(T2)	;FORWARD LINK AT OLD TAIL
	HRLM	T1,TUBQUE##(U)	;NEW TAIL POINTER
	PUSHJ	P,TAPCNT
	PJRST	TPONPJ		;RETURN

;HERE TO REMOVE THE IORB FROM THE HEAD OF A UNIT QUEUE

TAPREM::TAPOFF			;FIGHT RACE
	HRRZ	T1,TUBQUE##(U)	;GET CURRENT HEAD
	JUMPE	T1,TPONPJ	;EXIT IF NONE
	HRRZ	T2,TRBLNK(T1)	;FOLLOW FORWARD LINK
	HRRM	T2,TUBQUE##(U)	;NEW HEAD POINTER
	HLRZ	T3,TUBQUE##(U)	;CHECK IF QUEUE ONLY HAD ONE ELEMENT
	CAIE	T3,(T1)		;...
	JRST	TPONPJ		;NO - LEAVE
	MOVSI	T2,TUBQUE##(U)	;MAKE TAIL POINT TO QUEUE  HEAD
	MOVEM	T2,TUBQUE##(U)	; ...
TPONPJ:	TAPON			;ALLOW INTS
	POPJ	P,
;HERE WHEN UPPER LEVEL DECIDES THAT A SELECTED IORB IS NOT TO
;BE INITIATED AFTER ALL

TAPFLS::PUSHJ	P,TAPDSL	;FLUSH HDWRE
	PUSHJ	P,TAPREM	;AND PRUNE QUEUE
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,CKSIO1	;SEE IF SCHED CYCLE NEEDED
	MOVSI	T1,TKSSEL
	TDNN	T1,TUBSTS##(U)	;DID THIS UNIT GET SELECTED AGAIN?
	TDON	T1,TKBSTS##(W)	;NO, DID SOME OTHER UNIT GET SEL'D?
	JRST	TPOPJ##		;NO, RETURN
	TLNE	T1,TKSSTD	;YES, WAS IT ACTUALLY STARTED?
	JRST	TPOPJ##		;YES, RETURN
	PUSH	P,U		;NO, SAVE U
	MOVE	U,TKBCUN##(W)
	MOVE	U,(U)		;SET U TO RIGHT UNIT
	MOVSI	T1,TKSSEL	;NO UNIT IS ACTUALLY STARTED
	ANDCAM	T1,TUBSTS##(U)	; NOW
	MOVSI	T1,TKSSCH	;INDICATE WE'RE REQUESTING A SCHEDULE
	IORM	T1,TKBSTS##(W)	;FOR THIS KONTROLLER
	MOVEI	T1,TAPTIM##	;SET HUNG TIMER GOING
	MOVEM	T1,TKBTIM##(W)	;TO CATCH POSSIBLE LOST INTERRUPT
	HRRZ	T1,TKBDSP##(W)
	PUSHJ	P,TPKSCH(T1)	;GO CAUSE AN INTERRUPT ON THAT UNIT
	POP	P,U		;RESTORE U
	JRST	TPOPJ##		;RESTORE T1 AND EXIT
SUBTTL ERROR RECOVERY PROCEDURE.

;CALL HERE FROM TPMDON WHEN ERROR RECOVERY IS TO BE INITIATED
;SELECT MUST BE ON FOR KDB AND UDB. IORB IN T1.

TAPERP::MOVEI	T1,TKBERB##(W)	;ENQUEUE ERP IORB
	HLLOS	TKBSTS##(W)	;SET INFINITE QUANTUM
	PUSHJ	P,TAPRQH	;THIS IS CHEATING SLIGHTLY
	HRRZ	T1,TRBLNK+TKBERB##(W) ;RECOVER ORIGINAL IORB
	LDB	T2,PRBFCN	;GET FUNCTION CODE
	LDB	T3,ERYCNT	;GET INITIAL RETRY COUNT
	DPB	T3,TUYECT	;SET IN TUBERR
	SETZM	TUBTRY##(U)	;CLEAR ATTEMPT COUNTER
	PUSHJ	P,ERPCMV	;CHECK IF TAPE MOVED
	  TDZA	T4,T4		;NO MOVE
	MOVNI	T4,1		;MOVED - ADJUST POSITION
	SKIPL	ERCTAB(T2)	;WAS OP FORWARD MOTION?
	MOVNS	T4		;NO - FIX COUNT
	ADD	T4,TUBREC##(U)	;GET CORRECTED COUNT
	JUMPL	T4,[SETOM TUBPBE##(U) ;IF NEG REC COUNT
		    JRST ERP0]	;THEN WE WON'T POS CHECK RIGHT
	HRL	T4,TUBFIL##(U)	;ALSO COMPARE FILE POSITION
	MOVEM	T4,TUBPBE##(U)	;STORE POSITION BEFORE ERROR
	JRST	ERP0		;START ERP

;HERE ON AN INTERRUPT WHILE THE ERP IS RUNNING

ERPINT:	CAIE	T1,TKBERB##(W)	;BE REAL SURE ALL IS WELL
	STOPCD	.,STOP,ERF,	;++ERP REALLY FOULED UP
	HRRZ	T2,TUBERR##(U)	;GET DISPATCH ADDR
	CAILE	T2,XERPMX	;SMALLER THAN MAX?
	STOPCD	.,STOP,RFU,	;++RECOVERY FOULED UP
	MOVE	F,TUBCUR##(U)	;SET UP F AND S
	MOVE	S,DEVIOS(F)
	JRST	@ERPSTB(T2)	;THE LEAP OF FAITH
;HERE TO SEE IF ANYTHING OFFENSIVE HAS HAPPENED TO
;THE IORB IN T1

ANYERR:	SKIPL	TRBLNK(T1)	;IS EXCEPTION UP?
	POPJ	P,		;NO - ALL IS WELL.
	MOVE	T2,TRBSTS(T1)	;GET STATUS WORD
	TLNN	T2,RB.SER!RB.SED!RB.SLK!RB.SOL!RB.STL ;...
	POPJ	P,		;NOTHING TO OFFEND
	JRST	CPOPJ1##	;LOSE

;HERE TO COPY NEEDED THINGS TO THE ERP IORB

SETERB:	HRRZ	T1,TRBLNK+TKBERB##(W) ;GET OLD IORB
	HLLZ	T3,TRBLNK(T1)	;GET MODE ETC
	TLZ	T3,RB.EXC	;CLEAR EXCEPTION BIT
	HLLM	T3,TRBLNK+TKBERB##(W) ;STORE IN NEW IORB
	HRRZ	T3,TRBXCW(T1)	;GET XFR LIST ADDR
	MOVEM	T3,TRBXCW+TKBERB##(W) ;STORE
	MOVE	T3,TRBRCT(T1)	;COPY WORDCOUNT (FOR TM02)
	MOVEM	T3,TRBRCT+TKBERB##(W)
	HLLZ	T3,TRBEXL(T1)	;GET END OF XFR LIST
	MOVEM	T3,TRBEXL+TKBERB##(W) ;STORE
	POPJ	P,

;HERE TO SETUP ERP IORB FOR A NON DATA XFR OP

STERBS:	PUSHJ	P,SETERB	;SETUP ERB
	MOVEI	T1,1		;SET OP COUNT
	HRRM	T1,TRBXCW+TKBERB##(W) ;...
	HRRZS	TRBEXL+TKBERB##(W) ;ALSO CLEAR END OF LIST
	MOVEI	T1,TKBERB##(W)	;ERR REC IORB
	POPJ	P,

;HERE TO CLEAN UP WHEN LEAVING THE ERP FOR THE LAST TIME

ERPDON:	HRRZ	T2,TRBLNK+TKBERB##(W) ;PNTR TO ACTUAL IORB
	MOVE	T3,TRBRCT+TKBERB##(W) ;LAST BYTE COUNT
	MOVEM	T3,TRBRCT(T2)	;INTO IORB
	PUSHJ	P,TAPREM	;REMOVE ERP IORB
	MOVE	T2,TUBERR##(U)	;SAVE STATE WORD AT TERMINATION
	MOVEM	T2,TUBFES##(U)	;AS FINAL ERROR STATE
	SETZM	TUBERR##(U)	;CLEAR STATE INFO
	HLLZS	TKBSTS##(W)	;CLEAR CHANNEL QUANTUM
	POPJ	P,
;ERP ACTION 0 - REPOSITION IF NEEDED. IORB IN T1
;FCN CODE IN T2

ERP0:	PUSHJ	P,ERPCMV	;CHECK MOVEMENT
	  JRST	ERP2		;NO - NO NEED TO REPOSITION
	MOVSI	T3,(ERCRPS)	;SHOULD REPOSITIONING BE DONE?
	TDNN	T3,ERCTAB(T2)	; ...
	JRST	ERP2		;NO - GO RETRY
	PUSHJ	P,STERBS	;YES - SETUP ERP IORB
	MOVEI	T4,RB.FBR	;ASSUME FORWARD MOTION, REPOS W/ BS
	SKIPL	ERCTAB(T2)	;WAS OP FORWARD MOTION?
	MOVEI	T4,RB.FSR	;NO-REPOS WITH FWD SPACE
	DPB	T4,PRBFCN	;STORE FUNCTION CODE
	MOVEI	T2,XERP1	;SET NEXT STATE

;HERE TO EXIT AND START IO ON ERP IORB

ERPX0:	HRRM	T2,TUBERR##(U)	;STORE NEXT STATE
ERPX:	MOVEI	T1,TKBERB##(W)	;GET ERP IORB
	PUSHJ	P,TAPSIO	;GO INITIATE OP
	SETZ	T1,		;RETURN ZERO
	POPJ	P,

;HERE AT TERMINATION OF A REPOSITION

ERP1:	MOVSI	T2,RB.SNM!RB.SOL ;MOVED OR OFF-LINE?
	TDNN	T2,TRBSTS(T1)
	JRST	ERP1A		;SEE IF SPECIAL ACTION

;HERE WHEN RECOVERY HAS FAILED

ERP4:	HRRZ	T3,TRBLNK+TKBERB##(W) ;ORIG IORB
	MOVSI	T2,RB.SOL	;OFFLINE BIT
	TDNE	T2,TRBSTS(T1)	;CHECK STATUS
	IORM	T2,TRBSTS(T3)	;COPY BIT TO ORIG. IORB
	PUSHJ	P,ERPDON	;CLEAN UP
	HRRZ	T1,TUBQUE##(U)	;GET FORMER IORB
	MOVSI	T2,RB.SER	;FLAG NON REC ERROR
	IORM	T2,TRBSTS(T1)	;IN  IORB
	POPJ	P,		;RETURN FAILING IORB

;SEE IF THE LAST OP SHOULD BE ERASED.

ERP1A:	HRRZ	T1,TRBLNK+TKBERB##(W) ;GET ORIGINAL OP
	LDB	T2,PRBFCN	; ...
	CAIE	T2,RB.FWT	;WRITE?
	CAIN	T2,RB.FTM	;OR WRITE TAPE MARK?
	JRST	ERP5		;YES
	JRST	ERP2		;NO - DO RETRY NOW.
;MORE ERROR RECOVERY PROCEDURE

;HERE TO RETRY A FAILING OPERATION. THE TAPE HAS BEEN 
;REPOSITIONED IF NECESSARY

ERP2:	MOVE	T3,TUBPBE##(U)	;GET POSITION BEFORE ERROR
	JUMPL	T3,ERP2A	;SKIP CHECK IF NEG.
	MOVE	T2,TUBREC##(U)	;CHECK THAT REPOSITIONING
	HRL	T2,TUBFIL##(U)	;HAS BROUGHT US
	CAME	T2,T3		;BACK TO BEFORE THE ERROR
	JRST	ERP4
ERP2A:	PUSHJ	P,SETERB	;COPY NEEDED GOODIES
	HRRZ	T1,TRBLNK+TKBERB##(W) ;GET OLD IORB
	LDB	T2,PRBFCN	;GET FUNCTION
	LDB	T3,ERYFCN	;GET FUNCTION TO RETRY
	MOVEI	T1,TKBERB##(W)	;GET ERP IORB
	DPB	T3,PRBFCN	;STORE NEW OP.
	AOS	TUBTRY##(U)	;INCREMENT ATTEMPT COUNT
	MOVEI	T2,XERP3	;SET NEXT STATE
	JRST	ERPX0

;HERE ON THE TERMINATION OF A RETRY OPERATION

ERP3:	PUSHJ	P,ANYERR	;ANY ERRORS TO SPEAK OF?
	  JRST	ERP3B		;NO - WIN WIN WIN
	MOVSI	T2,RB.SOL	;OFFLINE
	TDNE	T2,TRBSTS(T1)	;???
	JRST	ERP4		;YES - LOSAGE
	LDB	T2,TUYECT	;GET RETRY COUNTER
	SUBI	T2,1		;DECREMENT
	JUMPLE	T2,ERP4		;SIGH - LOSE
	DPB	T2,TUYECT	;RESTORE COUNT
	HRRZ	T1,TRBLNK+TKBERB##(W) ;GET OLD IORB
	LDB	T2,PRBFCN	;GET FUNCTION
	MOVE	T4,TUBTRY##(U)	;RE-TRY COUNTER
	MOVSI	T3,(ERCTCS)	;THIS OP USE TCS?
	TDNE	T3,ERCTAB(T2)	;??
	TRNE	T4,3		;TCS EVERY 4 RE-TRIES
	JRST	ERP3A		;NO TCS NOW
	JRST	ERP7		;TCS TIME NOW
;HERE TO PERFORM REPOS/RETRY

ERP3A:	MOVEI	T1,TKBERB##(W)	;SET UP ERROR IORB
	LDB	T2,PRBFCN	;AND FUNCTION
	JRST	ERP0		;AND TRY THE WHOLE THING AGAIN

;HERE WHEN THE ERROR IS RECOVERED. THE WORLD IS AMAZED.

ERP3B:	MOVSI	T2,RB.SNM	;CHECK MOVEMENT
	TDNE	T2,TRBSTS(T1)	;DID IT?
	JRST	ERP3C		;NO - TRY AGAIN
	PUSHJ	P,ERPDON	;GO CLEAN UP
	HRRZ	T1,TUBQUE##(U)	;GET OLD IORB
	MOVSI	T2,RB.SRE	;RECOVERY SUCCEEDED
	IORM	T2,TRBSTS(T1)	;SET IN IORB
	POPJ	P,		;RETURN AND REJOICE

;HERE WHEN RETRY DIDN'T MOVE TAPE TRY AGAIN

ERP3C:	LDB	T2,TUYECT	;GET COUNTER
	SUBI	T2,1		;DECREMENT
	JUMPLE	T2,ERP4		;ALL THROUGH IF ZERO
	DPB	T2,TUYECT	;PUT COUNT BACK
	JRST	ERP2		;AND RETRY OP
;HERE TO DO AN ERG BEFORE RETRY

ERP5:	PUSHJ	P,STERBS	;SETUP ERB
	MOVEI	T2,RB.FLG	;GET ERG FUNCTION
	DPB	T2,PRBFCN	;STORE IN ERP IORB
	MOVEI	T2,XERP6	;NEXT STATE
	JRST	ERPX0		;EXIT AND SET STATE

;HERE AT THE TERMINATION OF AN OP BEFORE RETRY.

ERP6:	PUSHJ	P,ANYERR	;ERRORS?
	  JRST	ERP2		;NO - DO RETRY
	JRST	ERP4		;YES - FAIL
;ERROR RECOVERY TAPE CLEANER SEQUENCE (TCS)
;FCN CODE IN T2

;HERE TO STARTUP TCS

ERP7:	MOVEI	T1,TKBERB##(W)	;GET RETRY IORB
	MOVSI	T3,RB.SBT	;AT BOT?
	TDNE	T3,TRBSTS(T1)	; ???
	JRST	ERP3A		;YES - NO TCS
	MOVEI	T4,ERPNCS	;NUMBER OF SPACE OPS IN TCS
	SKIPL	ERCTAB(T2)	;WAS OP FORWARD MOTION?
	SUBI	T4,1		;NO - USE ONE LESS BACKSPACE
	DPB	T4,TUYEC1	;STORE IN SECONDARY COUNTER

;HERE TO DO A BACKSPACE AS PART OF A TAPE CLEANER SEQ

ERP8:	PUSHJ	P,STERBS	;SETUP IORB
	MOVEI	T2,RB.FBR	;BACKSPACE FUNCTION
	DPB	T2,PRBFCN	;STORE
	MOVEI	T2,XERP9	;NEXT STATE
	JRST	ERPX0		;LEAVE

;HERE WHEN A TCS BACKSPACE HAS COMPLETED

ERP9:	LDB	T2,TUYEC1	;GET COUNT
	SOSL	T2		;DECREMENT
	DPB	T2,TUYEC1	;SAVE NEW VALUE
	HLRZ	T3,TRBSTS(T1)	;GET STATUS
	TRNE	T3,RB.SBT	;DONE?
	JRST	ERP9B		;YES - RECOMPUTE SPACE COUNT
	TRNE	T3,RB.SNM	;DID IT MOVE AT ALL
	JRST	ERP4		;NO -******SHOULD FIX POSITION****
	JUMPG	T2,ERP8		;TRY AGAIN IF STILL MORE TO GO
	MOVEI	T4,ERPNCS-1	;NUMBER OF SPACE OPS
	JRST	ERP9C

ERP9B:	MOVEI	T4,ERPNCS-2	;COMPUTE NUMBER OF SPACE OPS
	LDB	T2,TUYEC1	; ...
	SUB	T4,T2		; ...
ERP9C:	HRRZ	T1,TRBLNK+TKBERB##(W) ;GET ORIG IORB
	LDB	T2,PRBFCN	;ORIG FCN
	MOVEI	T1,TKBERB##(W)	;RESTORE ERROR IORB
	SKIPL	ERCTAB(T2)	;WAS OP FORWARD MOTION?
	ADDI	T4,1		;NO - ONE MORE THEN
	DPB	T4,TUYEC1	;STORE COUNT
	JUMPLE	T4,ERP2		;NONE - GO TRY AGAIN

;FALL THROUGH INTO ERP10.
;FALL THROUGH HERE FROM ERP9C.
;HERE TO DO A SPACE RECORD AS PART OF A TCS

ERP10:	PUSHJ	P,STERBS	;SETUP IORB
	MOVEI	T2,RB.FSR	;SPACE OP
	DPB	T2,PRBFCN	;STORE
	MOVEI	T2,XERP11	;NEXT STATE
	JRST	ERPX0		;START IO AND EXIT

;HERE ON THE TERMINATION OF A TCS SPACE OP

ERP11:	HLRZ	T2,TRBSTS(T1)	;GET STATUS
	TRNE	T2,RB.SNM	;MOVED?
	JRST	ERP4		;NO ****SHOULD FIX POSN****
	LDB	T2,TUYEC1	;GET COUNT
	SUBI	T2,1		;DECREMENT
	DPB	T2,TUYEC1	;RESTORE
	JUMPLE	T2,ERP2		;CONTINUE RETRY
	JRST	ERP10		;MORE SPACES TO DO

;TABLE RELATING STATE CODES TO ROUTINE ADDRS.

ERPSTB:	PHASE 0
	0,,-1		;ILLEGAL
XERP1:!	ERP1		;REPOSITION TERMINATION
XERP3:!	ERP3		;RETRY TERMINATION
XERP6:!	ERP6		;ERASE GAP TERMINATION
XERP9:!	ERP9		;TCS BACKSPACE TERMINATION
XERP11:! ERP11		;TCS SPACE TERMINATION
XERPMX:!		;HIGHEST STATE
	DEPHASE
;TABLE USED TO GUIDE THE ERROR RECOVERY PROCEDURE

;BITS
ERCFWD==1B0	;OPERATION MOVES TAPE FOREWARD
ERCRPS==1B1	;OPERATION NEEDS REPOSITION BEFORE RETRY
ERCCSZ==1B2	;THIS OP IGNORE "NOISE" RECORDS
ERCTCS==1B3	;THIS OP USES TCS

;BYTES AND BYTE POINTERS
ERCCTP==^D17		;INITIAL RETRY COUNT POSITION
ERCCTS==6		;INITIAL RETRY COUNT SIZE
ERYCNT:	POINT	ERCCTS,ERCTAB(T2),ERCCTP

ERCFNP==^D35		;RETRY FUNCTION POSITION
ERCFNS==5		;RETRY FUNCTION SIZE
ERYFCN:	POINT	ERCFNS,ERCTAB(T2),ERCFNP

;MACRO TO BUILD ERCTAB ENTRY

DEFINE X(FLGS,CNT,FCN) <
	EXP	FLGS+<CNT>B<ERCCTP>+<FCN>B<ERCFNP>
>

;THE TABLE
ERCTAB:	EXP	-1	;ILLEGAL
	X(ERCFWD+ERCRPS+ERCCSZ+ERCTCS,^D40,RB.FCR) ;READ FORWARD
	X(ERCFWD+ERCRPS,^D14,RB.FWT)		;WRITE
	X(ERCRPS+ERCCSZ+ERCTCS,^D40,RB.FRB)	;READ BACKWARDS
	X(ERCFWD+ERCRPS,6,RB.FSR)		;SKIP RECORD
	X(ERCRPS,6,RB.FBR)			;BACKSPACE RECORD
	X(ERCFWD+ERCRPS,6,RB.FSF)		;SKIP FILE
	X(ERCRPS,6,RB.FBF)			;BACKSPACE FILE
	X(ERCFWD,6,RB.FLG)			;ERASE GAP
	X(ERCFWD,6,RB.FSE)			;DATA SECURITY ERASE
	X(0,6,RB.FRW)				;REWIND
	X(0,6,RB.FRU)				;REWIND AND UNLOAD
	X(ERCFWD+ERCRPS,^D14,RB.FTM)		;TAPE MARK
	X(ERCFWD,1,RB.FYB)			;YELLOW BALL
	X(ERCFWD+ERCRPS+ERCCSZ,6,RB.FCR)	;CORRECTION READ (ONLY IF USER REQD)
	X(ERCFWD+ERCRPS+ERCCSZ+ERCTCS,^D40,RB.FCR) ;READ LOW THRESHOLD

;ROUTINE CHECK IF TAPE MOVED OR ERROR ON NOISE RECORD
;CALL:	MOVE	T1,IORB
;	MOVE	T2,FCN
;	PUSHJ	P,ERPCMV
;	  RETURN IF NO MOVEMENT
;	RETURN IF MOVEMENT

ERPCMV:	MOVE	T4,TRBRCT(T1)	;GET BYTE COUNT
	MOVSI	T3,(ERCCSZ)	;SIZE CHECK?
	TDNN	T3,ERCTAB(T2)	;...
	JRST	ERPCM1		;NO - PROCEED
	CAIGE	T4,NOISE##	;IS THIS A NOISE RECORD
	POPJ	P,		;YES - NO MOVEMENT
ERPCM1:	MOVSI	T3,RB.SNM	;NO - CHECK PHYSICAL MOVEMENT
	TDNN	T3,TRBSTS(T1)	;...
	AOS	0(P)		;OK
	POPJ	P,		;RETURN
SUBTTL COMMON ROUTINES

;ROUTINES COMMON TO ALL KONTROLLER DEPENDENT CODE

;HERE ON REWIND DONE

REWDON::MOVSI	T2,TUSREW	;NO LONGER REWINDING
	ANDCAM	T2,TUBSTS##(U)	;...
UNIBOT::MOVSI	T2,TUSBOT		;ALSO NOW AT BOT
	IORM	T2,TUBSTS##(U)		; ...
	SETZM	TUBREC##(U)	; ...
	SETZM	TUBFIL##(U)		; ...
	POPJ	P,

;HERE TO VERIFY THAT TUBQUE POINTS TO A REASONABLE IORB

CHKIRB::HRRZ	T1,TUBQUE##(U)	;GET HEAD IORB
	JUMPE	T1,CPOPJ##	;EXIT IF NOT REQUEST BLOCK
	LDB	T2,PRBRQS	;GET REQUEST STATUS
	CAIN	T2,RB.ACT	;ACTIVE?
	AOS	(P)		;YES - GIVE GOOD RETURN
	POPJ	P,

;ROUTINE TO HANDLE SPURIOUS INTERRUPTS

TAPDIS::HRRZ	T1,TKBDSP##(W)	;GET DISPATCH
	PUSHJ	P,TPKIDL(T1)	;SET CTRL IDLE (USER WILL GET HUNG DEVICE)
	MOVSI	T2,TKSSCH	;TEST SCHED REG. BIT
	MOVEI	T1,0		;ASSUME IGNORE INT.
	TDNE	T2,TKBSTS##(W)	;WANT SCHED. CYCLE?
	MOVNI	T1,1		;YES- INFORM WORLD
	POPJ	P,		; AND EXIT

;ROUTINE TO SET UP U TO POINT TO UDB MENTIONED IN T2
;C(T2) = UNIT # , C(W) = KDB ADDRS
;NON-SKIP RETURN LF NON-EX UNIT
;SKIP RETURN IF UNIT IS OK

SETUDB::MOVEI	U,TKBUDB##(W)	;BASE ADDRS
	ADD	U,T2		;PLUS OFFSET
	SKIPN	U,0(U)		;SEE IF ONE EXISTS
	POPJ	P,
	PJRST	CPOPJ1##

;TABLE USED TO CONVERT IORB MODE TO CHARS/WORD

TMODTB::0		;0 - ILLEGAL
	5		;1 - 9-TK CORE DUMP
	4		;2 - 9-TK INDUSTRY COMPAT.
	6		;3 - TU70 SIXBIT
	5		;4 - TU70 MARVELOUS ASCII
	6		;5 - 7-TK CORE DUMP

TPSEND:	END