Google
 

Trailing-Edge - PDP-10 Archives - de-10-omona-v-mc9 - rpxkon.mac
There are 11 other files named rpxkon.mac in the archive. Click here to see a list.
TITLE	RPXKON - DRIVER FOR RP04'S  V12074
SUBTTL  T WACHS/TW   04 OCT 78
	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 VRPKON,12074
;ASSEMBLY INSTRUCTIONS: RPXKON,RPXKON_KONPAR,RPXKON

ENTRY	RPXKON
RPXKON::
;FUNCTIONS (OP CODES IN THE CONTROL REGISTER)
FNCUNL==3		;UNLOAD
FNCSEK==5		;SEEK
FNCRCL==7		;RECALIBRATE
FNCCLR==11		;DRIVE CLEAR
FNCREL==13		;RELEASE (DUAL PORT)
FNCOFS==15		;OFFSET
FNCRTC==17		;RETURN TO CENTERLINE
FNCPST==21		;READIN PRESET
FNCACK==23		;PACK ACKNOWLEDGE
FNCSRC==31		;SEARCH
FNCWRT==61		;WRITE DATA
FNCWTF==63		;WRITE FORMAT
FNCRED==71		;READ DATA
FNCRHD==73		;READ FORMAT

F22==100		;COMPATABILITY MODE (SOFTWARE ONLY, NEVER STORED IN DDB)

;DRIVE REGISTERS
DOCR==000000		;DRIVE CONTROL REGISTER
DOSR==010000		;STATUS
DOER==020000		;ERROR
DOER3==150000		;ERROR REG 3
DOAS==040000		;ATTENTION SUMMARY
DODA==050000		;DESIRED ADDRESS (TRACK/SECTOR)
DODT==060000	;DRIVE TYPE
DOLA==070000		;LOOK-AHEAD (SECTOR COUNTER)
DOSN==100000	;SERIAL NUMBER
DOOF==110000		;OFFSET
DODC==120000		;DESIRED CYLINDER
DOECP==160000		;ECC POSITION
DOECB==170000		;ECC BURST (PATTERN)

;DATAI/DATAO BITS
DIERRS==3600		;DIB ERRORS
CBTO==2000		;CONTROL BUS TIME OUT


LR==4000		;(LH) DISABLE STOP ON ERROR
DXES==200000		;DISABLE STOP ON ERROR
EXTERN	RPXCO4,RPXCI2,RPXDI1,RPXDI2,RPXDO2,RPXDO1,RPXFNC,RPXFLG
;RP04 STATUS REGISTER BITS
ATA==1B20		;ATTN ACTIVE
ERR==1B21		;ERROR
PIP==1B22		;POSITION IN PROGRESS
MOL==1B23		;MEDIUM ON LINE
WRL==1B24		;WRITE LOCK
LST==1B25		;LAST SECTOR TRANSFERED
PGM==1B26		;PROGRAMMABLE
DPR==1B27		;DRIVE PRESENT
DRY==1B28		;DRIVE READY
VV==1B29		;VOLUME VALID

GUDSTS==MOL!DPR!DRY!VV


;ERROR REG STATUS BITS
DCK==1B20		;DATA CHECK
UNS==1B21		;UNSAFE
OPI==1B22		;OPERATION INCOMPLETE
HCRC==1B27		;HEADER CRC ERROR
HCE==1B28		;HEADER COMPARE ERROR
ECH==1B29		;ECC HARD
FER==1B31		;FORMAT ERROR
PAR==1B32		;PARITY

;ERROR REG 3 STATUS BITS
OCYL==1B20		;OFF CYLINDER
SKI==1B21		;SEEK CYLINDER

;OFFSET REGISTER
FMT22==1B23		;22-SECTOR MODE
ECI==1B24		;ECC INHIBIT

DEFINE	STALL,<
XLIST
IFN FTKI10!FTKA10,<
	IMULI	P,1	;THIS TAKES LESS THAN 3 MIC-SECS ON KL
>
IFN FTKL10,<
	IMULI	P,1
	IMULI	P,1
>
LIST
>
;RH10 
DOCRC==400000		;CONTROL REGISTER - CONTROLLER
DODB==500000		;DATA BUFFER
DORA==540000		;RAE ERROR STATUS

INTERN RPALCL

;CONI/CONO BITS
CHNPAR==6		;(LH) CHAN-DETECTED PARITY
DBPE==400000
CHNERR==120000		;CHAN ERROR OR OVERRUN
OVERUN==20000
ALLERR==736320		;ALL ERRORS
RPALCL==734210	;CLEAR ALL ERRORS
DRVERR==600,,236300	;DRIVE OR CONTROL ERRORS
DONBIT==10
BSYBIT==20
STPBIT==20
ATTNEN==40
SDRAE==200		;(LH) SELECTED DRIVE REG ACCESS ERR
ALLCLR==734200		;CLEAR ALL CONI ERRORS
;RH20
;REGISTERS
DO.CT2==710000			;SECONDARY TRANSFER CONTROL
DO.PBA==72B5			;PRIMARY BLOCK ADDRESS
DO.CT1==73B5			;PRIMARY TRANSFER CONTROL
DO.IVI==74B5			;INTERRUPT VECTOR INDEX

;CONI/CONO
CI.ATN==200			;ATTEN LIGHT EVEN IF NOT ENABLED
CI.RAE==4000			;REGISTER ACCESS ERROR
CO.RAE==4000			;CLEAR RAE
CI.ERR==515000
CO.CLR==5010
CO.MBE==400			;MASSBUS ENABLE
CO.INI==2000			;MASSBUS INIT

;DATAO
DO.DRE==400			;DISABLE REGISTER ACCESS ERROR STOP

;DATAO STCR (LH)
D2.RCP==2000			;RESET CHANNEL PC
D2.SCS==200			;STORE CHANNEL STATUS

;DATAI
DI.TRA==200			;TRANSFER (SHOULD BE ON)
DI.CPE==1000			;CONTROL BUS PARITY ERROR

;CHANNEL LOGOUT AREA
CS1MPE==1B1			;MEM PARITY ERROR
CS1NSE==1B2			;NEGATION OF SBUS ERR
CS1NXM==1B4			;NXM
CS1RHE==1B10			;RH20 ERROR
CS1LWC==1B11			;LONG WORD COUNT
CS1SWC==1B12			;SHORT WORD COUNT
CS1OVR==1B13			;OVERRUN
CS1ERR==320360,,0		;ALL CHAN LOGOUT ERRS
RPXUNL::SKIPA	T1,[FNCUNL]	;UNLOAD
RPXRCL::MOVEI	T1,FNCRCL	;RECAL
	PUSHJ	P,CONECT	;CONECT TO THE DRIVE
	  JRST	RPXDWN		;UNIT IS DOWN
	MOVSI	T2,DODC		;SET TO CLEAR DESIRED CYLINDER REG
	JRST	RPXMOV		;AND CONTINUE

RPXPOS::MOVEI	T1,FNCSEK	;SET TO DO A SEEK
	PUSHJ	P,CONECT	;CONECT TO THE DRIVE
	  JRST	RPXDWN		;DOWN
	HRLI	T2,DODC		;SET FOR DATAO TO DESIRED CYL
RPXMOV:	PUSH	P,T2		;SAVE CYLINDER
	MOVSI	T2,DOOF		;CLEAR OFFSET REGISTER
	PUSHJ	P,DODTO
	MOVSI	T2,DODA		;CLEAR POSSIBLE ILLEGAL
	PUSHJ	P,DODTO		; SECTOR FROM DESIRED ADR REG
IFN FTKL10,<
	MOVEI	T2,1		;SINCE WE COULD TALK TO THE DRIVE
	LSH	T2,(T3)		; IF WE WERE WAITING FOR THE FRONT-END
	ANDCAB	T2,RPXGON##(J)	; THERE WAS A MISSED INTERRUPT. CLEAR FLAG
	TRNN	T2,-1		; WAITING FOR ANY DRIVE?
	SETZM	RPXGON##(J)	;NO, ZERO THE FLAG
>
	POP	P,T2		;RESTORE DATAO DESIRED CYL
	JRST	RPXGO		;AND CONTINUE

RPXSTP::XCT	RPXCI2##(J)	;(BEFORE) CONI
	PUSH	P,T2
IFN FTKL10,<
	MOVEI	T4,CO.MBE	;IF AFTER POWER FAIL
	XCT	RPXCO4##(J)	; THE RH20 LOST ITS IVI
	PUSHJ	P,RPXIVI	;SO RESET IT NOW
>
	MOVEI	T4,STPBIT
	XCT	RPXCO4##(J)	;ZAP
	XCT	RPXCI2##(J)	;DID IT CLEAR?
	TRNN	T2,BSYBIT
	AOS	-1(P)		;YES, SKIP RETURN
	POP	P,T2		;RESTORE CONI
IFE FTKL10,<
	MOVEI	T4,RPALCL
>
IFN FTKL10,<
	PUSHJ	P,SETP1
	MOVE	T4,[RPALCL
		    CO.CLR+CO.MBE](P1)
>
	XCT	RPXCO4##(J)
IFN FTKL10,<
	SKIPL	T4,UNILAS##(U)	;IF DRIVE WAS ON OTHER PORT
	SETZM	RPXGON##(J)	;CLEAR DATA XFER ON OTHER PORT FLAG
>
	MOVSI	T4,400000	;CLEAR SIGN BIT OF RPXFNC
	ANDCAM	T4,RPXFNC##(J)	; AS A FLAG THAT WE'RE IN RPXSTP (HNGDSK)
	SETZB	T1,T3		;GET DATAI FROM KONEBK
ATNENB:	LDB	T4,KOYPI##
IFN FTKL10,<
	TLNE	T1,200000	;IF DEFERRED IO NOW GOING
	TROA	T4,CO.MBE	; DON'T ENABLE ATTENTION
>
	TRO	T4,ATTNEN!CO.MBE ;RE-ENABLE FOR INTERRUPTS
	XCT	RPXCO4##(J)
	POPJ	P,
IFN FTDOPT,<
RPXLTM::LDB	T3,UNYPUN##	;UNIT NUMBER
	MOVEI	T4,3		;MAKE SURE WE DONT TRY TOO MUCH
	MOVSI	T2,DOLA(T3)	;READ LOOK-AHEAD REGISTER
IFN FTKL10,<
	PUSHJ	P,SETP1
	SKIPE	P1
	TLO	T2,DO.DRE
>
	PUSH	P,T1		;SAVE TARGET BLOCK
RPXLT1:	XCT	RPXDO2##(J)
	STALL			;WAIT A WHILE
	XCT	RPXDI1##(J)
IFE FTKL10,<
	TLNE	T1,DIERRS	;ERROR?
>
IFN FTKL10,<
	SKIPE	P1
	TLC	T1,DI.TRA
	TDNE	T1,[DIERRS,,
		DI.TRA!DI.CPE,,](P1)
>
	JRST	RPXLT3		;YES, ERROR
	ANDI	T1,3777		;NO, MASK OUT USEFUL PART
	CAIN	T3,(T1)		;SAME AS LAST TIME (OR 1ST TIME)?
	JRST	RPXLT2		;YES, WE HAVE A GOOD NUMBER
	HRRZ	T3,T1		;NO, SAVE PREVIOUS LA CONTENTS
	SOJG	T4,RPXLT1	;AND TRY AGAIN
	MOVEI	T1,^D8380	;WONT SETTLE - ASSUME 1/2 REVOLUTION
	PJRST	T2POJ1##	;AND SKIP
RPXLT2:	LSHC	T3,-6		;GET SECTOR CNTR, FRACTION TO T4
	SKIPGE	T4		;OVER HALF 1 SECTOR?
	ADDI	T3,1		;YES, BUMP SECTOR COUNT
	POP	P,T1		;RESTORE TARGET BLOCK
	IDIVI	T1,^D20		;COMPUTE DESIRED SECTOR
	SUBI	T2,2(T3)	;ALLOW A 2-SECTOR FUDGE FACTOR
	SKIPL	T2
	SKIPA	T1,T2		;T1=CURRENT-DESIRED
	MOVEI	T1,^D20(T2)	;NEGATIVE - ADD 1 REVOLUTION
	IMULI	T1,^D838	;838 MICRO-SECS PER SECTOR
	PJRST	CPOPJ1##	;GOOD RETURN

RPXLT3:
IFN FTKL10,<
	SKIPE	P1
	PUSHJ	P,CLRRAE
>
	JRST	TPOPJ##
>	;END FTDOPT
IFN FTDSUP,<
RPXRDF::SKIPA	T1,[FNCRHD]	;READ HEADERS AND DATA
RPXWTF::MOVEI	T1,FNCWTF	;WRITE HEADERS AND DATA (FORMAT)
IFN FTKL10,<
	MOVE	T2,KONCNT##(J)	;IF WRITING-READING HEADERS AND DATA
	IDIVI	T2,202		; SECTORS ARE 202 WORDS LONG
	SKIPE	T3		; FILIO COMPUTED CHNNUM BASED ON 200 WDS/SECTOR
	ADDI	T2,1		; AND THE RH20 HAS TO BE TOLD THE REAL NUMBER
	HRRM	T2,CHNNUM##(P1)	; SO RECOMPUTE CHNNUM BASED ON 202 WORDS
>
	JRST	RPXDGO
RPXRDC::SKIPA	T1,[FNCRED]	;READ 22-SECTOR MODE
RPXWTC::MOVEI	T1,FNCWRT	;WRITE 22-SECTOR MODE
	TLO	T1,F22		;INDICATE 22-SECTOR MODE
	JRST	RPXDGO
>
IFE FTDSUP,<
RPXWTF==CPOPJ
RPXRDF==CPOPJ
RPXRDC==CPOPJ
RPXWTC==CPOPJ
>
RPXRED::SKIPA	T1,[FNCRED+DXES] ;READ, DONT STOP ON ERROR
RPXWRT::MOVEI	T1,FNCWRT+DXES	;WRITE, DONT STOP ON ERROR
	JRST	RPXDGO
RPXRDS::SKIPA	T1,[FNCRED]	;READ, STOP ON ERROR
RPXWTS::MOVEI	T1,FNCWRT	;WRITE, STOP ON ERROR
RPXDGO:	SETZM	RPXFLG##(J)	;INDICATE DATA-XFER FUNCTION
	PUSHJ	P,CONECT	;CONECT TO THE DRIVE
	  JRST	RPDWND		;DOWN
	TRNE	T1,DXES		;STOP ON ERROR?
	AOS	RPXFLG##(J)	;NO, SET RPXFLG POSITIVE
IFN FTDSUP,<
	TLNE	T1,F22		;IF 22-SECTOR MODE,
	IDIVI	T3,^D22		; ADDRESSING IS DIFFERENT
	TLNN	T1,F22
>
	IDIVI	T3,^D20		;COMPUTE SECTOR, BLOCK
	DPB	T3,[POINT 5,T4,27] ;SET T4 FOR DESIRED ADDRESS REGISTER
	HRLI	T2,DODC		;SET DESIRED CYLINDER
	PUSHJ	P,DODTO
	MOVSI	T2,DOOF
IFN FTDSUP,<
	TLNE	T1,F22		;IF 22-SECTOR I/O
	TROA	T2,ECI+FMT22	; LIGHT FMT22 IN OFFSET REGISTER
>
	TRNE	T1,DXES		;IF NOT STOPPING ON ERROR
	TRCA	T2,ECI		;CLEAR OFFSET, SET ECI
	TRNN	T1,10		;IF WRITING
	PUSHJ	P,DODTO		;CLEAR OFFSET REGISTER
IFN FTKL10,<
	JUMPE	P1,RPXDG1
	MOVE	T2,-1(P)	;LOC OF CHANNEL DATA BLOCK
	MOVN	T2,CHNNUM##(T2)
	DPB	T2,[POINT 10,T1,29]
	TLO	T1,DO.CT2!D2.RCP!D2.SCS!DO.DRE
	JRST	RPXDG2
RPXDG1:>
	MOVE	T2,KONIOC##(J)	;LOC OF THE ICWA
	LSH	T2,6		;POSITION IT
	TRO	T1,(T2)		;INTO COMMAND
	TLO	T1,DOCRC	;T1=DATAO RH CNTRL REG
RPXDG2:	MOVE	T2,T4		;DESIRED ADDRESS
	HRLI	T2,DODA		;SET TO DATAO THE RIGHT REGISTER
RPXGO:
IFE FTKL10,<
	SETZ	T4,		;TURN OF PI FOR THE RH10
>
IFN FTKL10,<
	MOVEI	T4,CO.MBE	;MAKE SURE THE MASSBUS IS ENABLED
				;(BIT IGNORED FOR RH10)
	SKIPE	P1		;IF AN RH20
	TLO	T1,DO.DRE	; DISABLE REGISTER ACCESS ERROR INTERRUPT
>
	XCT	RPXCO4##(J)
	PUSHJ	P,DODTO		;DO THE DATAO IN T2
	LDB	T4,UNYPUN##	;UNIT NUMBER
	TLO	T1,LR(T4)	;SET TO DATAO CNTRL REG (RH OR DRIVE)
	PUSHJ	P,SETCO		;SET PIA, ATTN ENABLE
	TRNE	T1,40		;IF A DATA XFER COMMAND,
	MOVEM	T1,RPXFNC##(J)	;SAVE COMMAND IN RPXFNC
	MOVEM	T1,UNILAS##(U)	;SAVE AS LAST COMMAND FOR THE DRIVE
IFN FTDSUP,<
	TLZ	T1,F22		;MAKE SURE SOFTWARE BIT ISNT DATAO'D
>
	XCT	RPXDO1##(J)	;START THINGS HAPPENING
IFN FTKL10,<
	SKIPE	P1		;IF RH20
	PUSHJ	P,RPXIVI	;SET UP INTERRUPR VECTOR ADDRESS
>
	XCT	RPXCO4##(J)	;TURN ON THE PI
	PJRST	CPOPJ1##	;AND SKIP RETURN
IFN FTKL10,<
;ROUTINE TO SET UP THE INTERRUPT VECTOR ADDRESS FOR AN RH20
RPXIVI:	LDB	T2,KOYPI##
	LSH	T2,1		;CAUSE INTERRUPT AT 40+2N
	ADDI	T2,40
	HRLI	T2,(DO.IVI)	;SET UP DATAO INTERRUPT VECTOR REGISTER
	PJRST	DODTOC		;DO THE DATAO AND RETURN
>

;HERE IF A DRIVE IS DOWN WHEN WE'RE TRYING TO START IO
RPDWND:
IFN FTKL10,<
	JUMPN	T1,RPDWN1	;IF DRIVE IS ON ANOTHER PORT
	MOVSI	T1,400000	;INDICATE DATA-OP WE'RE WAITING FOR
	MOVEM	T1,RPXGON##(J)
	JRST	RPDWN2		;SET RPXGON RH AND RETURN TO FILIO
RPDWN1:>
	SETOM	RPXFLG##(J)	;NOT DOING IO NOW
;HERE IF A DRIVE IS DOWN WHEN WE'RE TRYING TO SEEK/RECAL
RPXDWN:
IFN FTKL10,<
	JUMPN	T1,RPDWN3	;CONTINUE IF NOT ON ANOTHER PORT
	SKIPE	RPXGON##(J)	;IF ALREADY WAITING FOR A DRIVE,
	PJRST	CPOPJ1##	; IGNORE THIS (IMPLIED SEEK LATER WILL WIN)
RPDWN2:	LDB	T1,UNYPUN##	;DRIVE IS ON ANOTHER PORT.
	MOVEI	T2,1		;SET A BIT IN RPXGON INIDCATING WHICH
	LSH	T2,(T1)		; DRIVE WE'RE WAITING TO INTERRUPT
	IORM	T2,RPXGON##(J)
	PUSHJ	P,RPXIVI
	PUSHJ	P,SETCO
	XCT	RPXCO4##(J)
	PJRST	CPOPJ1##	;AND LIE TO FILIO SAYING WE STARTED THE OPERATION
RPDWN3:>
	MOVE	T1,T3		;ERROR FLAGS INTO T1
IFE FTKL10,<
	PUSHJ	P,SETCO		;SET PIA, ATTEN ENABLE
>
IFN FTKL10,<
	PUSHJ	P,CLRRAE	;SET PIA, ATTNEN, CLEAR POSSIBLE RAE
>
	XCT	RPXCO4##(J)	;ENSURE THAT RH10 HAS A PI (POWER FAIL RECOVERY)
	XCT	RPXCI2##(J)	;GET CONI STATUS
	MOVE	T3,KONEBK##+1(J)	;SET RH (T3) = STATUS
	HRL	T3,KONEBK##+2(J)  ; AND LH = ERROR REGISTER
	POPJ	P,		;AND NON-SKIP RETURN TO FILSER
;ENTER T1=FUNCTION
;EXIT CPOPJ IF DRIVE/CONTROLLER DOWN
;EXIT CPOPJ1 IF OK, T1=FUNCTION, T2=CYL, T3=REMAINDER OF CYL COMP.
CONECT:

IFN FTKL10,<
	POP	P,T4		;SAVE RETURN ADDR (SETP1 LEAVES SAVE1 ON STACK)
	PUSHJ	P,SETP1		;SET P1=0 OR 1 FOR RH10 OR 20
	PUSH	P,T4		;RESTORE RETURN ADDRESS
>
CONECX:	MOVEI	T4,CO.MBE	;IF ON UUO LEVEL
	XCT	RPXCO4##(J)	; GUARD AGAINST INTERRUPTS
CONEC0:	XCT	RPXCI2##(J)	;CONI RP,T2
	TRNE	T1,40		;TRYING TO DO IO?
IFE FTKL10,<
	TRNN	T2,BSYBIT	;YES, KONTROLLER BUSY?
>
IFN FTKL10,<
	TRNN	T2,BSYBIT+DONBIT ;KONTROL BUSY OR DONE
>
	JRST	CONEC1		;NO, ALL IS OK
	MOVEI	T4,STPBIT+CO.MBE  ;YES, CLEAR BUSY, SET DONE
IFN FTKL10,<
	TRNE	T2,BSYBIT
>
	XCT	RPXCO4##(J)
	AOS	UNIHNG##(U)	;BUMP A COUNTER
	XCT	RPXCI2##(J)	;CONI
IFE FTKL10,<
	MOVEI	T4,RPALCL
>
IFN FTKL10,<
	MOVE	T4,[RPALCL
		CO.CLR+CO.MBE](P1)
	XCT	RPXCO4##(J)
>
	XCT	RPXCO4##(J)
	TRNE	T2,BSYBIT	;DID BUSY CLEAR?
	JRST	CONER2		;NO, CALL THE DRIVE OFF-LINE
IFN FTKL10,<
	XCT	RPXCI2##(J)
	TRNN	T2,DONBIT	;DID WE WIN ?
	JRST	CONEC1		;YES
	MOVEI	T4,CO.INI	;NO, I HATE TO DO IT
	XCT	RPXCO4##(J)	; BUT MASSBUSS INIT IS THE ONLY WAY
	MOVEI	T4,CO.MBE+STPBIT
	XCT	RPXCO4##(J)	;NOW GET THE RH20 USABLE AGAIN
	MOVEI	T4,CO.MBE+CO.CLR
	XCT	RPXCO4##(J)
>
CONEC1:
IFN FTKL10,<
	MOVSI	T2,DOSN		;WRITE A READ-ONLY REGISTER TO SIEZE THE DRIVE
	PUSHJ	P,DODTO		; SO THE FRONT-END CANT AB IT OUT FROM UNDER US
>
	MOVSI	T2,DOSR		;SET TO READ DRIVE'S STATUS REGISTER
	PUSHJ	P,DODTI
	TRZ	T2,LST+PGM	;DON'T CARE ABOUT LAST SECTOR TRANSFERRED OR PGM
	CAIE	T2,GUDSTS	;DRIVE OK?
	JRST	CONERR		;NO
CONEC2:	MOVE	T2,UNIBLK##(U)	;YES, GET DESIRED BLOCK
IFN FTDSUP,<
	TLNE	T1,F22		;IF 22-SECTOR MODE,
	IDIVI	T2,^D418	; ADDRESSING IS DIFFERENT
	TLNN	T1,F22
>
	IDIVI	T2,^D380	;COMPUTE CYLINDER IN T2
	MOVEM	T2,UNICYL##(U)	;SAVE IN UDB
	PJRST	CPOPJ1##	;AND SKIP-RETURN

;HERE IF ERROR TRYING TO CONNECT
CONERR:
	LDB	T4,UNYPUN##	;GET UNIT NUMBER
IFN FTKL10,<
	JUMPN	T2,CONER0	;GO IF NOT SEIZED TO ANOTHER PORT
	TLNE	T1,F22		;STATUS=0, IT MUST BE SIEZED BY FRONT END
	TRO	T1,F22		;VE STATE OF F22 IN RH(T1)
	HRL	T1,(P)		;SAVE CONTINUE ADDRESS FOR WHEN WE GET IT
	MOVSM	T1,UNILAS##(U)	; SAVE FUNCTION+FLAG+ADDRESS
	MOVSI	T2,DOSN		;WRITE A READ-ONLY REGISTER SO WILL GET
	PUSHJ	P,DODTO		; INTERRUPT ON RELEASE FROM OTHER PORT
	MOVSI	T2,DOSR		;IF DRIVE RELEASED BEFORE WRITE
	PUSHJ	P,DODTI		; WE WONT GET ATTN INTERRUPTS
	JUMPN	T2,CONER3	;IT DID, TRY OPERATION NOW
	SETZ	T1,		;T1=0 IS A FLAG
	AOS	INTFNC##	;BUMP INTERFERENCE-COUNT
	POPJ	P,		;AND TAKE NO-GOOD RETURN
CONER0:>
	CAIE	T2,GUDSTS+WRL	;STATUS OK EXCEPT FOR WRITE-LOCK?
	JRST	CONER1		;NO, REALLY IS BAD
	LDB	T3,[POINT 3,T1,32]  ;YES, IS THIS A WRITE?
	CAIE	T3,6
	JRST	CONEC2		;NO, ITS OK
	SETZ	T3,		;WRITE-INDICATE NOT OFF-LINE,
	POPJ	P,		; BUT BAD
CONER1:	MOVEI	T3,KOPOFL	;ASSUME OFF-LINE
	TRNE	T2,MOL		;MEDIUM ON-LINE?
	TRNE	T2,VV		;YES, VOLUME VALID?
	JRST	CONER2		;YES
	PUSHJ	P,NOWUP		;ACKNOWLEDGE THE DRIVE
	MOVSI	T2,DOSR		;READ THE STATUS REG
	PUSHJ	P,DODTI
	TRNE	T2,VV		;DRIVE IS DOWN IF VV DIDNT SET
	JRST	CONEC1		;AND GO TRY AGAIN
CONER2:	PUSH	P,U		;RDREG CLOBBERS U
	PUSH	P,T1
	LDB	T4,UNYPUN##
	PUSHJ	P,RDREG		;READ DRIVE REGISTERS
	PUSHJ	P,DVCLR		;NO, CLEAR THE DRIVE
	POP	P,T1
	POP	P,U
	MOVSI	T2,DOSR		;READ STATUS REG
	PUSHJ	P,DODTI
	TRZ	T2,LST+PGM
	CAIN	T2,GUDSTS	;DID DRIVE CLEAR FIX IT?
	JRST	CONER4		;YES, RETRY
	HRL	T2,KONEBK##+2(J);MOL AND VV ON, BUT STATUS SAYS ERROR
				;READ THE ERROR REGISTER
	MOVEI	T3,KOPOFL##	;PRETEND THE UNIT IS OFF-LINE
	TLNE	T2,UNS		;UNSAFE?
	TRO	T3,KOPFUS##	;YES, SO INDICATE
	TRNE	T2,MOL		;REALLY OFF-LINE?
	TRO	T3,KOPUSI##	;NO, STATUS INCONSISTENT
	AOJA	T1,CPOPJ##	;AND NON-SKIP, INSURING THAT T1 ISNT 0

IFN FTKL10,<
;HERE IF WE GOT DRIVE BACK AFTER THE FE HAD IT
CONER3:	HRRZS	T1		;CLEAR LH
	TRZE	T1,F22		;RESTORE STATE OF F22
	TLO	T1,F22
	JRST	CONEC1		;NOW TRY IT AGAIN
>
CONER4:	SKIPL	UNIECT##(U)	;IN ERROR RECOVERY?
	JRST	CONEC2		;YES, CANT SAVE REGS
	SETZM	UNIECT##(U)	;NO. FLAG FILIO TO KICK DAEMON
	MOVSI	T2,KONEBK##(J)	;STORE REGS IN "AT ERROR" HALF
	HRRI	T2,UNIEBK##(U)	; OF UDB FOR DAEMON
	BLT	T2,UNIEBK##+17(U)
	JRST	CONEC2		;AND DO THE OPERATION
;ROUTINE TO DO A DATAI FOR THE DRIVE
;ENTER T2=REGISTER TO READ, RETURN T2=CONTENTS OF THE REGISTER
;PRESERVES T1,T4
;DODI4 - ENTER WITH T4=DRIVE NUMBER.PRESERVES ALL ACS (EXCEPT T2)
;DODIC - NO DRIVE INVOLVED. PRESERVES ALL ACS BUT T2
DODTI4::		;ENTRY POINT FOR ONCMOD
DODTI:	LDB	T3,UNYPUN##	;UNIT NUMBER
	TLOA	T2,(T3)		;SET TO READ IT
DODI4:	TLO	T2,(T4)
DODIC:
IFN FTKL10,<
	SKIPE	P1		;RH20?
	TLO	T2,DO.DRE	;YES, DONT INTERRUPT ON RAE
>
	XCT	RPXDO2##(J)	;INDICATE WHICH REGISTER WE WANT
IFE FTKL10,<
	STALL			;WAIT 3 MICRO-SECS
>
IFN FTKL10,<
	PUSH	P,T2		;SAVE REGISTER WE WANT TO READ
	IMULI	T2,1		;WAIT (IN CASE RH10)
>
	XCT	RPXDI2##(J)	;READ THE REGISTER
IFN FTKL10,<
	XCT	RPXRAE##(J)	;REGISTER ACCESS ERROR?
	JRST	DTIERR		;YES
DODIX:	POP	P,(P)		;NO, REMOVE JUNK FROM LIST
>
	ANDI	T2,177777	;CLEAR GARBAGE BITS
	POPJ	P,		;AND RETURN
IFN FTKL10,<
;HERE ON RAE
DTIERR:	TLNE	T2,DI.TRA	;TRA UP?
	MOVSI	P1,1		;NO, COUNT PAR ERROR IN LH (P1=1 FOR RH20)
	ADDM	P1,RAECNT##(J)	;COUNT THE ERROR
	MOVEI	P1,^D10		;UP TO 10 RETRIES
	PUSH	P,T4		;NEED TO PRESERVE T4
	MOVEI	T4,CO.MBE!CO.RAE
DTIER1:	XCT	RPXCO4##(J)	;CLEAR THE RAE
	MOVE	T2,-1(P)	;REGISTER WE WANT TO READ
	XCT	RPXDO2##(J)
	STALL
	XCT	RPXDI2##(J)	;READ IT
	XCT	RPXRAE##(J)	;ERROR?
	SOJG	P1,DTIER1	;YES, TRY AGAIN
	XCT	RPXCO4##(J)	;CLEAR IT
	POP	P,T4		;RESTORE T4
	MOVEI	P1,1		;RESTORE P1
	JRST	DODIX		;REMOVE GARBAGE AND RETURN
>

;READ CONTROLLER REG
DODTIC:
IFN FTKL10,<
	SKIPE	P1		;RH20?
	TLO	T2,DO.DRE	;YES, DONT INTERRUPT ON RAE
>
	XCT	RPXDO2##(J)	;WHICH REGISTER
	XCT	RPXDI2##(J)	;CONTROL INFO COMES BACK WITH NO WAITING
	POPJ	P,
;ROUTINE TO WRITE A CONTROLLER REGISTER
DODTOC:	TDZA	T3,T3		;USE UNIT 0

;ROUTINE TO WRITE A DRIVE REGISTER
;ENTER T2=REGISTER TO WRITE,,DATA TO WRITE
;PRESERVES T1,T4
;DODO4 - ENTER WITH T4=DRIVE. PRESERVES ALL ACS
DODTO:	LDB	T3,UNYPUN##	;UNIT
	TLOA	T2,LR(T3)	;SET TO WRITE THE REGISTER
DODO4:	TLO	T2,LR(T4)
IFN FTKL10,<
	SKIPE	P1		;RH20?
	TLO	T2,DO.DRE	;YES, DONT INTERRUPT ON RAE
>
	XCT	RPXDO2##(J)	;ZAP
IFN FTKL10,<
	XCT	RPXRAE##(J)	;REGISTER ACCESS ERROR?
	AOSA	RAECNT##(J)	;YES, COUNT A NO-TRA ERROR
	POPJ	P,		;NO, DONE
	MOVEI	P1,^D10		;UP TO 10 RETRIES
	PUSH	P,T4		;PRESERVE T4
	MOVEI	T4,CO.MBE!CO.RAE
DOERR1:	XCT	RPXCO4##(J)	;CLEAR THE ERROR
	XCT	RPXDO2##(J)	;RETRY
	XCT	RPXRAE##(J)	;ERROR?
	SOJG	P1,DOERR1	;YES, RETRY
	XCT	RPXCO4##(J)	;CLEAR THE RAE
	POP	P,T4		;RESTORE T4
	MOVEI	P1,1		;RESTORE P1
>
	POPJ	P,		;AND RETURN

;ROUTINE CALLED WHEN VV ISNT ON FOR A DRIVE - DOES A DRIVE CLEAR, ACKNOWLEDGE
;ENTER T4=DRIVE NUMBER
;PRESERVES T1,T4
NOWUP:	PUSHJ	P,DVCLR		;CLEAR THE DRIVE
	MOVEI	T2,FNCACK
	PJRST	DODO4		;DO A PACK ACKNOWLEDGE AND RETURN
IFN FTKL10,<
;ROUTINE TO SET P1 =0 FOR RH10, =1 FOR RH20
;PRESERVES ALL BUT P1
RPXSTW::			;CALLED BY ONCMOD (RPXUPA)
SETP1:	EXCH	P1,(P)		;SAVE P1, GET CALLERS PC
	PUSH	P,P1		;SAVE PC
	LDB	P1,[POINT 3,RPXDI2##(J),5]
	CAIE	P1,5		;RH20 DEV CODES ALL START WITH 5
	TDZA	P1,P1		;RH10
	MOVEI	P1,1		;RH20
	JUMPE	P1,SETP12	;RETURN IF AN RH10
	PUSH	P,T4		;RH20, SAVE T4
	PUSHJ	P,SETCO		;SET UP FOR CONO (MAKE SURE CO.MBE IS ON)
	SKIPE	DINITF##	;IF IN ONCE-ONLY,
	TRZ	T4,7		; DONT LIGHT A PIA
	XCT	RPXCO4##(J)	;ENABLE MASSBUS
	POP	P,T4		;RESTORE T4
SETP12:	POP	P,(P)		;MAKE STACK RIGHT
	PUSHJ	P,@1(P)		;GO TO CALLER
	  CAIA
	AOS	-1(P)
	POP	P,P1		;RESTORE P1
	POPJ	P,		;AND EXIT

;ROUTINE TO CLEAR RAE
CLRRAE:	PUSHJ	P,SETCO		;"REGULAR" BITS
	TRO	T4,CO.RAE	;CLEAR RAE
	XCT	RPXCO4##(J)	;ZAP THE ERROR, PRESERVE THE REST
	POPJ	P,		;AND RETURN
>

;ROUTINE TO SET UP BITS FOR CONO
;PRESERVES ALL BUT T4
SETCO:	LDB	T4,KOYPI##	;GET PIA
IFN FTKL10,<
	TRO	T4,CO.MBE	;BIT NEEDED FOR RH20, IGNORED FOR RH10
	HLL	T4,RPXGON##(J)	;IF WE ARE WAITING FOR THE FRONT END
	TLNE	T4,400000	; AND WE ANT TO DO A DATA XFER
	TLNE	T4,200000	;ENABLE FOR ATTENS IF XFER NOT STARTED
>
	SKIPGE	RPXFLG##(J)
	TRO	T4,ATTNEN	;ENABLE FOR ATN IF NO XFER
	POPJ	P,		;AND RETURN

IFN FTDUAL,<
;ROUTINE TO ISSUE A RELEASE FOR DUAL-PORT OPERATION
;PRESERVES ALL ACS
RLESE:	PUSHJ	P,SAVT##
	LDB	T4,UNYPUN##
	MOVEI	T2,FNCREL	;RELEASE
	PUSHJ	P,DODO4
	PJRST	CHKATN
>
;HERE ON INTERRUPT FOR AN RP04
RPXINT::
IFN FTKL10,<
	PUSHJ	P,SETP1		;SET P1=0 OR 1 FOR RH10 OR 20
>
	XCT	RPXDI2##(J)	;SAVE REGISTER THE RH10 WAS CONNECTED TO
	PUSH	P,T2		; (MIGHT INTERRUPT BETWEEN DATAO AND ITS DATAI)
	PUSH	P,J		;SAVE J
	PUSHJ	P,RPXIN1	;DO THE REAL INTERRUPT STUFF
	POP	P,J		;RESTORE J
	HLLZ	T2,(P)		;GET DRIVE NUMBER, REGISTER NUMBER
	TLZ	T2,007770
	TLNN	T2,770000	;CANT DATAO TO REG 4
	TLO	T2,010000	; SINCE THAT WOULD SIEZE THE DRIVE
	XCT	RPXDO2##(J)	;SET THR RH10 BACK TO THAT REGISTER
	PJRST	TPOPJ##		;AND RETURN (DISMISS INTERRUPT)

;THE "REAL" INTERRUPT ROUTINE....
RPXIN1:	MOVSI	T2,DOAS		;SET TO READ ATTN SUMMARY REGISTER
	PUSHJ	P,DODIC		;(ATTN NOT ON IN CONI IF NOT ENABLED)
	SETZB	S,T4
	ANDI	T2,377		;ANY ATTENTION ON?
IFN FTKL10,<
	SKIPL	RPXGON##(J)	;AND NO (POSSIBLE) POSTPONED ATTN INTERRUPTS
>
	JUMPE	T2,NOATTN	;NO
	HRLI	T2,DOAS+LR	;YES, SET TO CLEAR WHAT WE READ
	PUSH	P,T2		;SAVE IT (CLEAR IF NO ERRORS LATER ON)
IFN FTKL10,<
	SKIPN	T1,RPXGON##(J)	;ARE WE LYING TO FILSER ABOUT SOME DRIVE?
	JRST	DUAINX		;NO, CONTINUE
	TLZE	T1,200000	;YES, DID WE START THE "REAL" OPERATION?
	JRST	DUAIN4		;YES, FINISH UP
	TRNE	T2,(T1)		;NO, IS THERE AN ATTEN FROM THAT DRIVE?
	JRST	DUAIN1		;YES
	JUMPG	T1,DUAINX	;NO, REGULAR SERVICE IF IT WAS A SEEK
	HRLZ	T1,T2		;DATA XFER - REMEMBER THE DRIVES
	IORM	T1,RPXGON##(J)	; SO WE CAN TELL FILSER AFTER THE XFER
	JRST	RPXIN5		;ISSUE RELEASES AND EXIT THE INTERRUPT
;HERE IF WE TRIED TO START AN OPERATION ON A DRIVE WHICH WAS BUSY ON THE
;OTHER PORT (FRONT END). WE WROTE A READ-ONLY REGISTER IN ORDER TO GET THIS
;ATTENTION INTERRUPT WHEN THE DRIVE WAS RELEASED FROM THE OTHER PORT
DUAIN1:	HRRZS	T2,T1		;DRIVE WE WERE WAITING FOR
	ANDCAM	T2,(P)		;CLEAR IT FROM STUFF TO DO AT END
	HRLI	T2,DOAS		;CLEAR ATA IN DRIVE
	PUSHJ	P,DODO4
	JFFO	T1,.+2		;COMPUTE DRIVE NUMBER
	STOPCD	DUAIN2,DEBUG,NFD, ;++NO FRONT-END DRIVE
	MOVNI	T2,-^D35(T2)
	ADDI	T2,(J)		;POINT AT UDB
	HRRZ	U,(T2)		;SET U TO THE DRIVE
	HLRZ	T1,UNILAS##(U)	;FUNCTION
	TRZE	T1,F22
	TLO	T1,F22		;SET 22-SECTOR MODE IF NEEDED
	PUSHJ	P,CONEC0	;SET UP TO TALK TO DRIVE
	  JRST	DUAIN2		;NOT RIGHT, LET IT TIME OUT
	PUSH	P,UNICHN##(U)	;DATA OPS NEED CHAN DB LOC ON PDL
	MOVSI	T4,200000	;INDICATE THAT THE DATA XFER HAS STARTED
	SKIPG	RPXGON##(J)	; IF WE ARE ABOUT TO START IT
	IORM	T4,RPXGON##(J)	; SO THAT SETCO WONT ENABLE FOR ATTENTIONS
	HRRZ	T4,UNILAS##(U)	;CONTINUE ADDRESS
	PUSHJ	P,1(T4)		;START OPERATION NOW
	  JFCL			;LOSE (SYSTEM ERROR?)
	POP	P,(P)		;REMOVE CHNXCB FROM LIST
DUAIN2:	SKIPG	RPXGON##(J)	;WAITING FOR DATA XFER?
	JRST	RPXIN5		;YES, ISSUE RELEASES AND WAIT FOR DONE
	SETZB	T4,RPXGON##(J)	;NO, CLEAR UP THE EVIDENCE
	HRRZ	T2,(P)		;RESTORE OTHER DRIVE ATTN BITS
	JRST	DUAINX		;AND PROCESS NORMALLY

;HERE AFTER COMPLETION OF DATA XFER WHICH WAS DELAYED WHEN FRONT END HAD DRIVE
DUAIN4:	HLRZS	T1		;SEEKS WHICH COMPLETED WHILE WE WAITED
	TRO	T2,400000(T1)	; PROCESS AS IF THEY JUST FINISHED
	SETZM	RPXGON##(J)	;NOT WAITING NOW
DUAINX:>
	HRRZ	T1,T2		;BITS FOR ATTN-DRIVES
RPXIN2:	LSHC	T1,-1		;TEST THE NEXT DRIVE
	JUMPGE	T2,RPXIN4	;NOT THIS ONE
	MOVSI	T2,DOSR(T4)	;THIS DRIVE INTERRUPTED
	PUSHJ	P,DODIC		;READ ITS STATUS REGISTER
	MOVEI	U,KONTAB##(J)	;SET UP U TO UDB
	ADDI	U,(T4)
	MOVE	U,(U)
	TRNN	T2,MOL		;ON-LINE?
	JRST	RPXI3C		;OFF-LINE INTERRUPT, TELL FILSER
	TRNE	T2,VV		;YES, VOLUME VALID?
	TRNN	T2,ERR		;YES, ERROR?
	JRST	RPXIN3		;FREE INTERRUPT OR NO ERR
	MOVSI	T3,(T4)		;ERROR - WAS THE DRIVE DOING IO?
	XOR	T3,RPXFNC##(J)
	MOVE	F,RPXFLG##(J)
	TLNN	T3,7		;IF SAME UNIT
	JUMPGE	F,RPXIN4	;ERROR ON XFERRING DRIVE IF RPXFLG NON-NEG
	MOVEI	T3,1		;IF A DATA XFER IS IN PROGRESS
	LSH	T3,(T4)		; WE HAVE TO TELL FILSER ABOUT THAT FIRST
	JUMPGE	F,[ANDCAM T3,(P)  ; SO DONT CLEAR ATTN FOR THIS
		   JRST RPXIN4]	; DRIVE. IT WILL INTERRUPT LATER

;HERE IF INTERRUPT & NO XFER IN PROGRESS AND THE DRIVE HAD AN ERROR
	MOVEM	T2,(P)		;SAVE STATUS OF DRIVE
	MOVE	T2,T3		;CLEAR JUST THIS 1 ATTENTION BIT
	HRLI	T2,DOAS+LR(T4)	; (WILL INTERRUPT AGAIN FOR THE OTHERS)
	XCT	RPXDO2##(J)	;CLEAR IT
	MOVSI	T2,DOER3
	PUSHJ	P,DODI4		;IF SEEK INCOMPLETE IS ON
	TRNN	T2,SKI
	JRST	RPXI2A
	MOVSI	T2,DOER
	PUSHJ	P,DODI4		; AND UNSAFE IS OFF
	TRNE	T2,UNS
	JRST	RPXI2A
	MOVE	T2,(P)
	TRNN	T2,DRY		;IF DRIVE READY IS OFF THE UNIT IS RECALIBRATING
	JRST	TPOPJ##		; SO WAIT FOR NEXT INTERRUPT
	PUSHJ	P,DVCLR		;RECAL DONE, CLEAR THE DRIVE
				;(UNIT IS NOT ON RIGHT CYLINDER, BUT IMPLIED SEEK WILL WIN)
	SKIPA	T1,[1]
RPXI2A:	MOVSI	T1,1
	ADDM	T1,UNIPCT##(U)	;UPDATE NUMBER OF POSITIONING ERRORS
	PUSHJ	P,DVCLR		;MAKE SURE THE ERROR IS RESET
	PUSHJ	P,RDIPST	;CLEAR POSSIBLE GARBAGE FROM DA & DC
IFN FTDUAL,<
	PUSHJ	P,RLESE		;DO A DUAL-PORT RELEASE
>
	MOVEI	T1,OPPOS+IODERR;INDICATE AN ERROR FOR FILSER
	HRLI	T1,(T4)		;DRIVE WHICH ERRORED
	IOR	T1,BITTBL##(T4)	;SET THE ATTN BIT FOR THE DRIVE
	POP	P,T3		;RETURN DATAI STATUS IN T3
	XCT	RPXCI2##(J)	; AND CONI STATUS IN T2
	PJRST	FILINT##	;CALL FILIO
;HERE FOR ATTENTION INTERRUPT, NO ERROR INDICATED FOR DRIVE
RPXIN3:	TRNN	T2,VV		;FREE INTERRUPT?
	PUSHJ	P,NOWUP		;YES, DO A PACK ACKNOWLEDGE
RPXI3B:	IOR	S,BITTBL##(T4)	;LIGHT THE ATTN BIT FOR FILIO
	JRST	RPXIN4		;AND CONTINUE
;HERE WHEN A UNIT GOES OFF-LINE
RPXI3C:	PUSHJ	P,FILDN##	;TELL FILSER UNIT WENT AWAY
RPXIN4:	JUMPE	T1,RPXIN5	;GO IF NO MORE ATTNS
	AOJA	T4,RPXIN2	;AT LEAST 1 MORE - TRY THE NEXT DRIVE
RPXIN5:	POP	P,T2		;NO ERRORS - CLEAR THE ATTN SUMMARY REGISTER
	XCT	RPXDO2##(J)	; OF ALL THE DRIVES WE JUST LOOKED AT
IFN FTDUAL,<
	SETZ	T3,		;T3 WILL HAVE ATTENTION BITS
	MOVEI	T4,7		;START AT HIGH-ORDER DRIVE
	LSHC	T2,-^D8
RPXIN6:	JUMPGE	T3,RPXIN7	;THIS DRIVE INTERRUPT?
	MOVSI	T2,DOSR		;YES, READ STATUS REG
	PUSHJ	P,DODI4
	TRNE	T2,PGM		;IF A DUAL-PORT DRIVE
	TRNE	T2,ERR		;WHICH HAS NO ERROR BITS UP IN IT
	JRST	RPXIN7
	MOVEI	T2,FNCREL	;DO A RELEASE SO OTHER PORT CAN GET IT
	PUSHJ	P,DODO4
RPXIN7:	LSH	T3,1		;STEP TO NEXT DRIVE
	TLNE	T3,-1		;ANOTHER ATTN BIT?
	SOJGE	T4,RPXIN6	;YES, TEST THIS DRIVE
>
IFN FTKL10,<
	SKIPL	T1,RPXGON##(J)	;LIE TO FILSER WHILE WAITING FOR FE TO RELEASE DRIVE?
>
	SKIPGE	RPXFLG##(J)	;DATA XFER IN PROGRESS?
	JUMPE	S,ATNENB	;NO, DISMISS INTERRUPT IF JUST A POWER-DOWN ATTN
NOATTN:
	SKIPL	RPXFLG##(J)	;DATA XFER IN PROGRESS?
	JRST	DATINT		;YES
	XCT	RPXCI2##(J)	;NO, GET CONI STATUS
	HRRI	S,OPPOS		;INDICATE POSITION INTERRUPT
	JRST	CALLIO		;AND TELL FILSER
DATINT:
IFE FTKL10,<
	MOVSI	T2,DOCRC	;SET TO READ RH10 CNTRL REG
>
IFN FTKL10,<
	MOVE	T2,[DOCRC,,	;READ RH10 CNTRL REG
		DO.CT1](P1)	; OR PRIMARY TRANSFER CNTRL REG
>
	PUSHJ	P,DODTIC
	LDB	T4,[POINT 3,T2,17] ;DRIVE NUMBER WE'RE TALKING ABOUT
IFN FTKL10,<
	SKIPL	RPXFNC##(J)	;IF CALLED FROM RPXSTP
	JRST	[MOVE U,KONCUA##(J) ; IF DRIVE WAS ON OTHER PORT
		 SKIPL UNILAS##(U) ; WE NEVER TALKED TO IT
		 LDB T4,UNYPUN##  ; SO SET UNIT TO WHAT IT SHOULD BE
		 JRST .+1]
>
	MOVE	U,RPXFNC##(J)
	TRNN	U,10		;IS IT A WRITE?
	TRO	S,OPWRT		;(OPRED=0)
	MOVSI	T2,DOOF+LR(T4)	;CLEAR ECI AND/OR FMT22
	TRNN	U,DXES
	TLNE	U,F22		; IF THEY WERE ON FOR THE DRIVE
	XCT	RPXDO2##(J)
DATIN1:	TLO	S,(T4)		;DRIVE NUMBER IN LH
	MOVSI	T2,DOSR		;READ THE DRIVE STATUS REGISTER
	PUSHJ	P,DODI4
	MOVE	T1,T2		;SAVE STATUS
	MOVSI	T2,DOER		;READ THE ERROR REGISTER
	PUSHJ	P,DODI4
	HRL	T3,T2		;T3=ERROR,,STATUS
	HRR	T3,T1
	XCT	RPXCI2##(J)	;T2=CONI STATUS
IFE FTKL10,<
	TRNN	T2,ALLERR	;ANY ERROR?
>
IFN FTKL10,<
	JUMPE	P1,DATIN2	;EASY IF RH10
	MOVE	T1,KONIOC##(J)	;GET ICWA
	HLL	T2,1(T1)	;GET BITS FROM CHAN LOGOUT AREA
	TLC	T2,(CS1NSE)	;MAKE THE BIT=1 IF ERROR
				;AND FALL INTO DATIN2
DATIN2:	TDNN	T2,[ALLERR	;ANY ERROR?
		CS1ERR!CI.ERR](P1)
>
	TRNE	T3,ERR
	JRST	ERROR		;YES
	SKIPL	RPXFNC##(J)	;CALL FROM RPXSTP (FROM HNGDSK)?
	JRST	ERROR		;YES, CAUSE ERROR SO WILL RETRY
	MOVE	U,KONCUA##(J)	;UNIT WE'RE TALKING TO
	SKIPG	UNIECT##(U)	;IN ERROR RECOVERY?
	JRST	DATDON		;NO
	PUSH	P,T2		;YES, READ ALL DRIVE REGS
	PUSHJ	P,RDREG		; SINCE WE JUST WON
	POP	P,T2

DATDON:	SETOM	RPXFLG##(J)	;NO, INDICATE NO XFER NOW IN PROGRESS
IFN FTDUAL,<
	TRNN	T3,PGM		;DUAL PORT DRIVE IN A/B?
	JRST	CALLIO		;NO
	PUSH	P,T2		;YES, SAVE CONI
	MOVEI	T2,FNCREL	;ISSUE A RELEASE
	PUSHJ	P,DODO4
	POP	P,T2		;RESTORE CONI
>

CALLIO:	LDB	T4,KOYPI##	;GET PI CHAN
IFE FTKL10,<
	TRO	T4,ATTNEN+RPALCL ;CLEAR ERRORS, ENABLE FOR ATTN INTERRUPTS
>
IFN FTKL10,<
	TDO	T4,[ATTNEN+RPALCL
		ATTNEN+CO.CLR+CO.MBE](P1)
>
	XCT	RPXCO4##(J)
	MOVE	T1,S		;T1=ATTN+DRIVE,,ERROR+FUNCT
	PJRST	FILINT##	;GO TELL FILSER
ERROR:	TLNE	T3,DCK		;DATA CHECK ERROR?
	TROA	S,IODTER	;YES
	TRO	S,IODERR	;NO
	TLNE	T3,FER		;FORMAT ERROR?
	TROA	S,IODTER+IODERR	;YES, LIGHT BOTH ERROR BITS
IFE FTKL10,<
	TRNN	T2,CHNERR	;CHAN-DETECTED ERROR?
>
IFN FTKL10,<
	TDNN	T2,[CHNERR
		CS1MPE!CS1NXM](P1)
>
	JRST	ERROR1		;NO
IFN FTKL10,<
	JUMPE	P1,ERRH10	;ALL DIFFERENT FOR RH10S
	TLNN	T2,(CS1MPE)	;CHECK LOGOUT AREA FOR NXM
	TROA	S,IOCHNX
	TRO	S,IOCHMP
	TLNE	T2,(CS1OVR)	;CHECKK LOGOUT AREA FOR OVERRUN
	TRO	S,IOVRUN
	JRST	ERRDON		;AND FINISH UP
ERRH10:>
	TLNN	T2,CHNPAR	;YES, CHAN PARITY ERROR?
	TROA	S,IOCHNX	;NO, NXM
	TRO	S,IOCHMP	;YES
	TLNE	T3,OVERUN
	TRO	S,IOVRUN
	JRST	ERRDON		;FINISH UP
ERROR1:	TLNE	T3,HCE+HCRC	;HEADER ERROR?
	TRO	S,IOHDER+IODTER	;YES
	SKIPG	RPXFLG##(J)	;IF STOPPING ON ERROR,
	TRNE	S,IODERR	;AND DATA ERROR IS UP
	JRST	ERRDON
	TLNN	T3,ECH		;HARD DATA CHECK?
	TRO	S,IOECCX	;NO, INDICATE RECOVERABLE ERROR
ERRDON:	PUSH	P,T2		;SAVE CONI STATUS
	PUSH	P,T3		;SAVE STATUS, ERROR REGISTERS
IFN FTKL10,<
	JUMPE	P1,ERRDN0
	TRNN	T2,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	ERRDN0		;NO
	PUSHJ	P,CLRRAE	;YES, CLEAR IT
	JRST	ERRDN1		;AND CONTINUE
ERRDN0:>
	TLNN	T2,SDRAE	;REGISTER ACCESS ERROR?
	JRST	ERRDN1		;NO
	MOVEI	T2,1		;YES, CLEAR THE BIT IN RAE REGISTER
	LSH	T2,(T4)
	HRLI	T2,DORA+LR
	XCT	RPXDO2##(J)
ERRDN1:	PUSHJ	P,RDREG
	PUSHJ	P,DVCLR		;CLEAR THE DRIVE
	POP	P,T3		;RESTORE DRIVE REGISTERS
	POP	P,T2		;RESTORE CONI
	JRST	DATDON		;AND GO TELL FILSER
;HERE TO COMPUTE ECC MASK, POSITION
RPXECC::MOVE	T1,KONEBK##+16(J) ;GET POSITION
	SOJL	T1,CPOPJ##	;ERROR IF 0
	IDIVI	T1,^D36		;COMPUTE WORD LOC, POSITION IN WORD
	MOVE	T4,KONEBK##+17(J) ;GET PATTERN
	EXCH	T2,T4
	MOVEI	T3,0		;SET T2, T3= MASK
	ROTC	T2,(T4)
	PJRST	CPOPJ1##	;AND SKIP-RETURN

;ROUTINE TO CLEAR POSSIBLE GARBAGE FROM DRIVE REGS
RDIPST:	SKIPA	T2,[FNCPST]	;ENSURE DA & DC REGS DON'T

;ROUTINE TO CLEAR A DRIVE AND MAKE SURE IT REALLY CLEARED
;PRESERVES T1
DVCLR:	MOVEI	T2,FNCCLR
	PUSH	P,T2
	MOVSI	T2,DOOF		;DRIVE CLEAR ZEROES OFFSET REG
	PUSHJ	P,DODI4		; SO READ IT
	EXCH	T2,0(P)		; AND SAVE
	PUSHJ	P,DODO4		;ZAP
	PUSHJ	P,DODO4		;SOME DRIVES NEED 2!
	POP	P,T2		;RESTORE OFFSET REG
	HRLI	T2,DOOF		; SO SYSERR WILL REPORT IT
	PUSHJ	P,DODO4		; AND TEST ON 1ST ERROR WILL WORK
CHKATN:	MOVSI	T2,DOAS		;READ ATTN SUMMARY REGISTER
	PUSHJ	P,DODI4
	MOVEI	T3,1		;IS ATTN NOW UP?
	LSH	T3,(T4)
	TDNN	T2,T3
	POPJ	P,		;NO, EVERYTHING IS OK
	MOVE	T2,T3		;YES, THIS ERROR CAN'T BE CLEARED
	HRLI	T2,DOAS+LR
	XCT	RPXDO2##(J)	;CLEAR BIT IN ATTN SUMMARY REG
	POPJ	P,		; AND RETURN
;HERE WITH T1=NUMBER OF THE RETRY IF A DATA ERROR. TELL FILSER WHAT TO DO
RPXERR::TLO	M,400000
IFN FTKL10,<
	PUSHJ	P,SETP1
>
	SOJN	T1,RPXER1	;IF FIRST ERROR,
	MOVSI	T2,DOOF		;READ THE OFFSET REGISTER
	PUSHJ	P,DODTI		;(IF LAST OP WAS SOFT ERROR
	TRNN	T2,60		; THE DRIVE IS LEFT IN OFFSET STATE)
	JRST	RPXER1		;DRIVE ISNT OFFSET - CONTINUE
	MOVEI	T1,RTCNDX	;DRIVE IS OFFSET - RETURN TO CENTERLINE
	JRST	RPXER2
;HERE IF NOT 1ST ERROR, OR 1ST AND DRIVE ISNT OFFSET
RPXER1::SUBI	T1,^D15		;IF LESS THAN 16TH RETRY,
	JUMPL	T1,RETRY	;RETURN 0 (JUST RETRY)
	CAILE	T1,^D13		;IF TRIED EVERYTHING AND DIDNT RECOVER
	JRST	RPXER3		;GIVE UP
	CAIN	T1,^D13		;IF THE LAST TIME
	JRST	LASTIM		; TRY LAST TIME
	TRNE	T1,1		;IF DIDNT TRY TWICE AT THIS OFFSET,
	JRST	RETRY		;TRY A SECOND TIME
	LSH	T1,-1		;TRIED TWICE - DO NEXT OFFSET
RPXER2:	PUSHJ	P,CONECX	;CONNECT TO DRIVE
	  JRST	RETRY		;DOWN - PRETEND JUST STRAIGHT RETRY
	MOVE	T2,OFSTBL(T1)	;OK, GET OFFSET
	LDB	T1,UNYUTP##	;UNIT TYPE
	SKIPE	T1		;RP06?
	HLRS	T2		;YES, GET OTHER OFFSET VALUE
	HRLI	T2,DOOF		;SET TO DO OFFSET
	MOVEI	T1,FNCOFS	;FUNCTION = OFFSET
	TRNN	T2,-1		;BUT IF OFFSET=0,
	MOVEI	T1,FNCRTC	; DO A RETURN TO CENTERLINE
	HRROS	RPXFLG##(J)	;SET RPXFLG NEGATIVE
	PUSHJ	P,RPXGO		;START THE OFFSET
	  JFCL
	JRST	OFFSET		;AND TELL FILSER OFFSET IS IN PROGRESS


;HERE ON A HARD ERROR
RPXER3:	CAIN	T1,^D14		;DXES ON (30TH TIME)?
	JRST	RETRY		;YES, THIS TIME STOP ON ERROR
	JRST	GIVEUP		;NO, TELL DAEMON ABOUT IT

ERCODE	RETRY,0			;RETRY
ERCODE	OFFSET,1		;OFFSET
ERCODE	LASTIM,2		;LAST TIME
ERCODE	GIVEUP,3		;GIVE UP
OFSTBL:	10,,20			;+400 MICRO INCHES
	210,,220		;-400
	20,,40			;+800
	220,,240		;-800
	30,,60			;+1200
	230,,260		;-1200
	0,,0			;RTC
RTCNDX==.-OFSTBL-1
IFN FTDHIA,<
;HERE TO CHECK CAPACITY & STATUS OF RH10/RP04
RPXCPY::
IFN FTKL10,<
	MOVEI	T4,CO.MBE
	XCT	RPXCO4##(J)
	PUSHJ	P,RPXIVI	;SET UP IVI REG IN CASE OF ERROR
	PUSHJ	P,SETP1		;DO MASSBUS ENABLE IF RH20
	SETZ	T1,
>
RPXCP1:	MOVSI	T2,DODT		;READ DRIVE-TYPE REGISTER
	PUSHJ	P,DODTI4
	LDB	T3,[POINT 9,T2,35]
	CAIL	T3,20		;IN RANGE OF RP04-PR06 ?
	CAILE	T3,22
	JRST	RPXCP3		;NO, NO SUCH DRIVE
	CAIE	T3,22		;YES, RP06 ?
	TDZA	T4,T4		;NO
	MOVEI	T4,1		;YES, UNIT TYPE=1
IFN FTDUAL,<
	HRLM	T2,UNISER##(U)	;SAVE DRIVE TYPE
>
	MOVEM	T2,UNIEBK##+6(U) ;SAVE FOR SYSERR
	MOVSI	T2,DOSR		;YES, READ STATUS REGISTER
	PUSHJ	P,DODTI4
	TRCN	T2,MOL		;MOL?
	TLO	T4,KOPUHE	;NO, INIT IS OFF-LINE OR DOWN
IFN FTDUAL,<
	TRNE	T2,VV!MOL	;IF MOL=1 BUT VV=0
	JRST	RPXCP2
	PUSH	P,T4		;THEN THE DRIVE WONT DO A RELEASE
	MOVE	T4,T3		; SO SET VV
	PUSHJ	P,NOWUP		; SO THAT RELEASE WILL WORK
	POP	P,T4
RPXCP2:>
	MOVSI	T2,DOSN		;READ DRIVE SERIAL NUMBER
	PUSHJ	P,DODTI4
	MOVEM	T2,UNIEBK##+10(U)  ;AND STORE IN UDB
IFN FTDUAL,<
	HRL	J,T2		;RETURN SN IN J ALSO
>
IFN FT22BIT,<
	XCT	RPXCI2##(J)	;CONI FN'N T2
	TLNE	T2,4000		;22 BIT CHAN?
	TLO	T4,KOP22B##	;YES
>
	MOVE	T1,BLKPRU(T4)	;BLOCKS PER UNIT
	MOVE	T2,BLKPUM(T4)	;BLOCKS PER UNIT INCLUDING MAINT CYLS
	MOVE	T3,BLKPUC(T4)	;BLOCKS PER UNIT IN 10/11 COMPAT MODE
	MOVE	W,[^D20,,^D380]	;BLKS PER TRK,, BLKS PER CYL
	AOS	(P)		;SET FOR SKIP RETURN
	JRST	RPXCP4		;CLEAR POSSIBLE RAE AND EXIT
RPXCP3:	MOVSI	T4,KOPUHE##	;OFF LINE OR DOWN
	TLO	T4,KOPNSU##	;NO SUCH UNIT
	SETZB	T1,T2		;NO BLOCKS PGR UNIT - CANT READ
RPXCP4:
IFN FTKL10,<
IFE FTDUAL,<
	JUMPE	P1,CPOPJ##	;NO SWEAT IF AN RH10
>
IFN FTDUAL,<
	JUMPE	P1,RLESE
>
	TLO	T4,KOP22B##	;RH20'S ARE 22 BIT CHANNEL
	PUSH	P,T4		;PRESERVE T4
	PUSH	P,T2		;SAVE T2
	LDB	T4,UNYPUN##
	MOVEI	T2,1
	LSH	T2,(T4)		;POSITION BIT TO CLEAR ATTN-SUMMARY REG
	HRLI	T2,DOAS+LR+DO.DRE
	XCT	RPXDO2##(J)	; WHICH MIGHT BE ON
IFN FTDUAL,<
	LDB	T4,UNYPUN##
	PUSHJ	P,DVCLR		;MAKE SURE ERR ISNT UP SO RELEASE WILL WIN
	PUSHJ	P,RLESE		;DO A DUAL-PORT RELEASE
>
	PUSHJ	P,CLRRAE	;CLEAR RAE, LIT IF NON-EX DRIVE
	POP	P,T2
	PJRST	T4POPJ##	;RESTORE T4 AND RETURN
> ;END IFN FTKL10'
IFE FTKL10,<
IFN FTDUAL,<
	PUSHJ	P,RLESE		;DO A DUAL-PORT RELEASE
>
	POPJ	P,
>

BLKPRU:	DEC	154280		;406 CYLINDERS
	DEC	307800		;810 CYLINDERS
BLKPUM:	DEC	156180		;411 CYLINDERS
	DEC	309700		;815 CYLINDERS
BLKPUC:	DEC	171798		;22*19*411
	DEC	340670		;22*19*815
>	;END FTDHIA
;ENTRY TO READ DRIVE REGS
RPXREG::
IFN FTKL10,<
	PUSHJ	P,SETP1		;MASSBUS ENABLE IF RH20
>
	PUSH	P,U		;RDREG WIPES U
	LDB	T4,UNYPUN##	;DRIVE NUMBER
	PUSHJ	P,RDREG		;READ REGS
IFE FTDUAL,<
	PJRST	UPOPJ##		;RESTORE U AND RETURN
>
IFN FTDUAL,<
	POP	P,U		;RESTORE U
	MOVE	T2,KONEBK##+1(J) ;GET STATUS REG
	TRNE	T2,PGM		;IF DUAL PORTED
	TRNE	T2,ERR		; AND NO ERROR
	POPJ	P,
	PJRST	RLESE		;DO A RELEASE (READ REG 0 SIEZES THE DRIVE)
>

;SUBROUTINE TO READ ALL DRIVE REGISTERS
;PRESERVES T3, CLOBBERS U
RDREG:	MOVE	T1,KONREG##(J)	;NUMBER OF DRIVE REGISTERS TO READ
	MOVEI	U,KONEBK##(J)	;WHERE TO STORE THEM
	ADDI	U,-1(T1)	;POINT AT TOP OF BLOCK
RDREG1:	MOVSI	T2,-1(T1)	;READ A REGISTER
	LSH	T2,^D12
	PUSHJ	P,DODI4
	MOVEM	T2,(U)		;SAVE IN KONTROLLER DB
	SUBI	U,1
	SOJG	T1,RDREG1	;AND GO READ ANOTHER
IFE FTKL10,<
	MOVSI	T2,DOCRC	;READ RH10 CONTROL REG
>
IFN FTKL10,<
	MOVE	T2,[DOCRC,,	;OR RH20 PTCR
		    DO.CT1](P1)
>
	PUSHJ	P,DODTIC
	MOVEM	T2,KONECR##(J)	;SAVE IN KDB
IFE FTKL10,<
	MOVSI	T2,DODB		;READ DATA BUFFER
>
IFN FTKL10,<
	MOVE	T2,[DODB,,	;OR RH20 PBAR
		    DO.PBA](P1)
>
	PUSHJ	P,DODTIC
	MOVEM	T2,KONEDB##(J)	; AND SAVE
	POPJ	P,		;RETURN
	$LIT
RPXEND:	END