Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93d-bb - 7,6/ap015/rpxkon.x15
There are 2 other files named rpxkon.x15 in the archive. Click here to see a list.
TITLE	RPXKON - DRIVER FOR RP04'S  V207
SUBTTL  T WACHS/TW   8 JULY 86
	SEARCH	F,S,ICHPRM
	$RELOC
	$HIGH



;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1974,1986>
;COPYRIGHT (C) 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.


;

XP VRPKON,207
;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
DOER2==140000		;ERROR REG 2
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
;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
DTE==1B23		;DRIVE TIMING ERR
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 FTKL10,<
	IMULI	P,1
	IMULI	P,1
>
LIST
>
;RH10 
DOCRC==400000		;CONTROL REGISTER - CONTROLLER
DODB==500000		;DATA BUFFER
DORA==540000		;RAE ERROR STATUS


;CONI/CONO BITS
CHNPAR==6		;(LH) CHAN-DETECTED PARITY
CHNNXM==1		;(LH) CHAN-DETECTED NXM
CHNERR==120000		;CHAN ERROR OR OVERRUN
OVERUN==20000
ALLERR==736320		;ALL ERRORS
RPALCL==:734210	;CLEAR ALL ERRORS
ATTNEN==40
SDRAE==200		;(LH) SELECTED DRIVE REG ACCESS ERR
CI.PWF==2000		;POWERFAIL



;RH20
;CONI/CONO
CI.ERR==CI.DBP!CI.LWC!CI.DRE!CI.RAE!CI.OVR
CO.CLR==CO.RAE!CO.TEC!CO.CCD

;CHANNEL LOGOUT AREA
CS.ERR==CS.MPE!CS.NAE!CS.NXM!CS.RHE!CS.LWC!CS.SWC!CS.OVR
				;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 THE IVI
	PUSHJ	P,RPXIVI	; SO RESET IT
>
	MOVEI	T4,CO.STP
	XCT	RPXCO4##(J)	;ZAP
	XCT	RPXCI2##(J)	;DID IT CLEAR?
	TRNN	T2,CI.BSY
	AOS	-1(P)		;YES, SKIP RETURN
	POP	P,T2		;RESTORE CONI
IFN FTKL10,<
	SKIPL	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	T3,T1		;GET DATAI'S FROM KONEBK

;HERE TO ENABLE ATTEN INTERRUPTS
;HERE FROM RPXI11 WITH T1=RPXGON
ATNENB:	LDB	T4,KOYPI##
IFN FTKL10,<
	TLNE	T1,200000	;IF DEFERRED IO NOW GOING
	TROA	T4,CO.MBE	; DON'T ENABLE ATTENTION
>
	TRO	T4,CO.AIE!CO.MBE ;RE-ENABLE FOR INTERRUPTS
	XCT	RPXCO4##(J)
	POPJ	P,

;HERE TO MAKE SURE KONTROLLER IS ALIVE
RPXALV::XCT	RPXCI2##(J)	;CONI
	TRNE	T2,7		;ALIVE AND WELL?
	POPJ	P,		;YES
IFN FTKL10,<
	PUSHJ	P,SETP14	;NO. SET UP IVI
	MOVSI	T1,200000	;ENABLE FOR ATTENS
>
	PJRST	ATNENB		;GIVE IT A PI AND EXIT
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
	LDB	T4,UNYBPT##	;NO OF BLOCKS PER TRACK
	POP	P,T1		;RESTORE TARGET BLOCK
	ADDI	T1,-2(T4)	;ALLOW A 2-SECTOR FUDGE FACTOR
	IDIVI	T1,(T4)		;COMPUTE DESIRED SECTOR
	SUBI	T2,(T3)		;DISTANCE
	SKIPGE	T2		;IF NEGATIVE
	ADDI	T2,(T4)		; 1 MORE REVOLUTION
	CAIN	T4,^D20		;IF RP04/RP06
	SKIPA	T1,[^D838]	; 838 PER SECTOR
	MOVEI	T1,^D556	;RP07 - 556 PER SECTOR
	IMULI	T1,(T2)		;TIMES MICRO-SECS PER SECTOR
	PJRST	CPOPJ1##	;GOOD RETURN

RPXLT3:
IFN FTKL10,<
	SKIPE	P1
	PUSHJ	P,CLRRAE
>
	JRST	TPOPJ##
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
	LDB	T2,UNYBPT##	;IF NOT RP04/6
	CAIE	T2,^D20
	JRST	[SETZ T3,	;16-BIT MODE IS ILLEGAL
		 POPJ P,]
	TLO	T1,F22		;INDICATE 22-SECTOR MODE
	JRST	RPXDGO

RPXRED::SKIPA	T1,[FNCRED+DO.DTE] ;READ, DONT STOP ON ERROR
RPXWRT::MOVEI	T1,FNCWRT+DO.DTE ;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,DO.DTE	;STOP ON ERROR?
	AOS	RPXFLG##(J)	;NO, SET RPXFLG POSITIVE
	TLNE	T1,F22		;IF 22-SECTOR MODE,
	MOVEI	T4,^D22		; ADDRESSING IS DIFFERENT
	TLNN	T1,F22

	LDB	T4,UNYBPT##	;BLOCKS PER TRACK
	IDIVI	T3,(T4)		;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
	TLNE	T1,F22		;IF 22-SECTOR I/O
	TROA	T2,ECI+FMT22	; LIGHT FMT22 IN OFFSET REGISTER

	TRNE	T1,DO.DTE	;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,(.DOSTC!DO.RCP!DO.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,<(DO.LDR)>(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
	TLZ	T1,F22		;MAKE SURE SOFTWARE BIT ISNT DATAO'D

	XCT	RPXDO1##(J)	;START THINGS HAPPENING
IFN FTKL10,<
	JFCL			;KL10 TIMING PROBLEM
>
	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,(.DOIVI)	;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,RPDWN4	;CONTINUE IF NOT ON ANOTHER PORT
	SKIPE	RPXGON##(J)	;IF ALREADY WAITING FOR A DRIVE,
	JRST	RPDWN3		; 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)
RPDWN3:	PUSHJ	P,SETCO
	XCT	RPXCO4##(J)
	PJRST	CPOPJ1##	;AND LIE TO FILIO SAYING WE STARTED THE OPERATION
RPDWN4:>
	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,CI.BSY	;YES, KONTROLLER BUSY?
>
IFN FTKL10,<
	TRNN	T2,CI.BSY+CI.DON ;KONTROL BUSY OR DONE?
>
	JRST	CONEC1		;NO, ALL IS OK
IFE FTKL10,<
	MOVSI	T2,DOCRC
>
IFN FTKL10,<
	MOVE	T2,[DOCRC,,	;READ CONTROL REGISTER
		    .DOPTC](P1)
>
	PUSHJ	P,DODTIC
	LDB	T4,[POINT 3,T2,17] ;NUMBER OF LAST UNIT
	MOVE	T3,T1
	PUSHJ	P,RDREG		;READ ITS REGISTERS
	MOVE	T1,T3
	MOVSI	T2,UNPHNG##+UNPFIR## ;IF NOT IN ERROR RECOVERY
	SKIPGE	UNIECT##(U)
	MOVEM	T2,UNIECT##(U)	;SET FLAG FOR FILIO
IFN FTKL10,<
	XCT	RPXCI2##(J)	;RESET T2 TO CONI
>
	MOVEI	T4,CO.STP+CO.MBE ;YES, CLEAR BUSY, SET DONE
IFN FTKL10,<
	TRNE	T2,CI.BSY
>
	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)	;RH20S NEED 2
>
	XCT	RPXCO4##(J)
	TRNE	T2,CI.BSY	;DID BUSY CLEAR?
	JRST	CONER2		;NO, CALL DRIVE OFF-LINE
IFN FTKL10,<
	XCT	RPXCI2##(J)
	TRNN	T2,CI.DON	;DID WE WIN?
	JRST	CONEC1		;YES
	MOVEI	T4,CO.MBI	;NO.  I HATE TO DO IT
	XCT	RPXCO4##(J)	; BUT MASSBUS INIT IS THE ONLY WAY
	MOVEI	T4,CO.MBE+CO.STP
	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
	LDB	T3,UNYBPY##	;BLOCKS PER CYLINDER
	TLNE	T1,F22		;IF 22-SECTOR MODE,
	IDIVI	T2,^D418	; ADDRESSING IS DIFFERENT
	TLNN	T1,F22

	IDIVI	T2,(T3)		;COMPUTE CYLINDER IN T2
	MOVEM	T2,UNICYL##(U)	;SAVE IN UDB
	PJRST	CPOPJ1##	;AND SKIP-RETURN

;HERE IF ERROR TRYING TO CONNECT
CONERR:
IFN FTKL10,<
	JUMPN	T2,CONER0	;GO IF NOT SEIZED TO ANOTHER PORT
	MOVSI	T2,U2PPGA##	;DID THE OTHER PORT DISAPPEAR FROM UNDER US?
	TDNE	T2,UNIDS2##(U)
	JRST	[MOVEI T3,KOPOFL## ;YES, INDICATE THE DRIVE IS OFF-LINE
		 POPJ P,]	;TELL FILIO
	TLNE	T1,F22		;NO, IT MUST BE SIEZED BY FRONT END
	TRO	T1,F22		;SAVE 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:>
	LDB	T4,UNYPUN##	;GET UNIT NUMBER
	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,T1
	LDB	T4,UNYPUN##
	PUSHJ	P,RDREG		;READ DRIVE REGISTERS
	PUSHJ	P,DVCLR		;NO, CLEAR THE DRIVE
	POP	P,T1
	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,<(DO.LDR)>(T3) ;SET TO WRITE THE REGISTER
DODO4:	TLO	T2,<(DO.LDR)>(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
	PUSHJ	P,SETP13	;SET UP IVI
	PUSH	P,T4		;RH20, SAVE T4
	PUSHJ	P,SETCO		;SET UP FOR CONO (MAKE SURE CO.MBE IS ON)
	XCT	RPXCO4##(J)	;ENABLE MASSBUS, LIGHT PIA
	POP	P,T4		;RESTORE T4
SETP12:	POP	P,(P)		;MAKE STACK RIGHT
	PUSHJ	P,@1(P)		;GO TO CALLER
	  CAIA
	AOS	-1(P)
	JRST	P1POPJ##	;RESTORE P1
SETP13:	PUSHJ	P,SAVT##	
SETP14:	MOVEI	T4,CO.MBE	;SO WE CAN TALK TO IT
	XCT	RPXCO4##(J)	
	PJRST	RPXIVI		;TELL IT WHERE TO GO

;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,CO.AIE	;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
IFN FTDUAL,<
	TLNN	T2,770000	;CAN'T WRITE REGISTER 0
	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+<(DO.LDR)> ;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
	JUMPN	T1,RPXIN9	;ISSUE RELEASES AND EXIT THE INTERRUPT
	JRST	DUAIN4		;DONE INTERRUPT WE ARE CONFUSED
;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)
	HRRZ	U,KONTBP##(J)	;POINT AT UDB
	ADD	T2,U		;...
	HRRZ	U,(T2)		;SET U TO THE DRIVE
	SKIPG	UNILAS##(U)
	JRST	DUAIN5		;SOMEONE IS CONFUSED
	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	DUAIN3		;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:	SKIPGE	RPXGON##(J)	;WAITING FOR DATA XFER?
	JRST	DUAIN9		;YES, ISSUE RELEASES AND WAIT FOR DONE
DUAIN3:	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
DUAIN5:	SETZM	RPXGON##(J)	;NOT WAITING NOW
DUAINX:>
	HRRZ	T1,T2		;BITS FOR ATTN-DRIVES
RPXIN2:	LSHC	T1,-1		;TEST THE NEXT DRIVE
	JUMPGE	T2,RPXIN8	;NOT THIS ONE
	MOVSI	T2,DOSR(T4)	;THIS DRIVE INTERRUPTED
	PUSHJ	P,DODIC		;READ ITS STATUS REGISTER
	HRRZ	U,KONTBP##(J)	;SET UP U TO UDB
	ADDI	U,(T4)
	SKIPN	U,(U)
	JRST	RPXIN6		;NEW UNIT - BUILD A UDB FOR IT
	TRNN	T2,MOL		;ON-LINE?
	JRST	RPXIN7		;OFF-LINE INTERRUPT, TELL FILSER
	TRNE	T2,VV		;YES, VOLUME VALID?
	TRNN	T2,ERR		;YES, ERROR?
	JRST	RPXIN4		;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,RPXIN8	;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 RPXIN8]	; 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+<(DO.LDR)>(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	RPXIN3
	MOVSI	T2,DOER
	PUSHJ	P,DODI4		; AND UNSAFE IS OFF
	TRNE	T2,UNS
	JRST	RPXIN3
	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]
RPXIN3:	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
RPXIN4:
IFN FTDUAL,<
	SKIPN	T3,UNI2ND##(U)	;POINTER 2 SECOND PORT
	JRST	RPXIN5		;NONE
	MOVSI	F,U2PPGA##	;SET OR CLEAR PORT-GONE-AWAY BIT
	TRNN	T2,PGM		;STILL DUAL (PORT SWITCH ECO)?
	JRST	[IORM F,UNIDS2##(T3) ;NO. SO INDICATE
		 MOVEI F,O2COD## ;MARK PORT DOWN FOR REST OF WORLD TO SEE
		 MOVEM F,UNISTS##(T3)
		 JRST RPXIN5]	;AND KEEP ON
	ANDCAM	F,UNIDS2##(T3)	;DUAL - MAKE SURE BIT IS CLEAR
RPXIN5:>
	TRNN	T2,VV		;FREE INTERRUPT?
	PUSHJ	P,NOWUP		;YES, DO A PACK ACKNOWLEDGE
	IOR	S,BITTBL##(T4)	;LIGHT THE ATTN BIT FOR FILIO
	JRST	RPXIN8		;AND CONTINUE

;HERE FOR INTERUPT ON AN UNKNOWN UNIT
RPXIN6:
IFE FTAUTC,<
	JRST	RPXIN8		;CHUCK IT
>
IFN FTAUTC,<
	MOVSI	T2,DODT		;READ DRIVE TYPE REGISTER
	PUSHJ	P,DODI4
	PUSH	P,T1
	PUSH	P,T4
	MOVE	T1,T2		;WHERE AUTCON WANTS IT
	MOVS	T2,T4		;UNIT NUMBER, SLAVE 0
	PUSH	P,J
	PUSHJ	P,NEWDSK##	;TELL THE WORLD WE'RE HERE
	POP	P,J
	POP	P,T4
	POP	P,T1
	JUMPE	U,RPXIN8	;AND TELL FILSER THE DRIVE IS OFF-LINE
>
;HERE WHEN A UNIT GOES OFF-LINE
RPXIN7:	TRNN	T2,ERR		;IS THERE AN ERROR?
	JRST	RPXI3Z		;NO
	PUSHJ	P,DVCLR		;YES, CLEAR IT
	MOVSI	T2,DOSR(T4)	;DID IT CLEAR?
	PUSHJ	P,DODIC
	TRNN	T2,ERR
	JRST	RPXI3Z		;YES
	MOVSI	T2,DOER3	;NO, CLEAR IT THE HARD WAY
	PUSHJ	P,DODO4
	MOVSI	T2,DOER2
	PUSHJ	P,DODO4
	MOVSI	T2,DOER
	PUSHJ	P,DODO4
	MOVSI	T2,DOSR(T4)	;DID IT CLEAR?
	PUSHJ	P,DODIC
	TRNE	T2,ATA
	TRNN	T2,ERR
	JRST	RPXI3Z		;YES
;HERE WHEN AN RP07 WITH BAD UCODE GETS SPUN UP.
;DISABLE ATTENTION INTERRUPTS FOR ONE SECOND
	JUMPN	S,RPXI3Z	;GO IF OTHER DRIVES INTERRUPT
	JUMPN	T1,RPXI3Z
	SKIPL	RPXFLG(J)	;GO IF DATA TRANSFER
	JRST	RPXI3Z
	MOVE	T2,.CPCPN##	;CPU
	ROT	T2,-4
	TLO	T2,(1B0)	;ONLY THIS CPU
	HRR	T2,U		;FAILING UNIT
	MOVE	T3,TICSEC##	;ONE SECOND
	HRLI	T3,RPXENB	;ADDR OF ROUTINE TO CALL
	SYSPIF			;STORE CLOCK REQUEST
	IDPB	T3,CLOCK##
	IDPB	T2,CLOCK##
	SYSPIN
	MOVE	T2,.CPCPN##	;CPU
	SETZM	CLKMIN##(T2)
	POP	P,T2		;PRUNE STACK
	LDB	T2,KOYPI##
IFN FTKL10,<TRO T2,CO.MBE>
	XCT	RPXCO2##(J)	;DISABLE ATTENTION INTERRUPTS
	PJRST	FILDN##		;TELL FILSER AND DISMISS
;HERE ONE SECOND LATER TO RE-ENABLE
RPXENB:	HRRZ	J,UNIKON##(T1)	;KDB
	DSKOFF			;MAKE SURE RPXFLG DOESN'T CHANGE
	PUSHJ	P,SETCO		;SET UP FOR CONO
	XCT	RPXCO4##(J)	;RE-ENABLE
	PJRST	DOPOPJ##
RPXI3Z:	PUSHJ	P,FILDN##	;TELL FILSER UNIT WENT AWAY
RPXIN8:	JUMPE	T1,RPXIN9	;GO IF NO MORE ATTNS
	AOJA	T4,RPXIN2	;AT LEAST 1 MORE - TRY THE NEXT DRIVE
IFN FTKL10,<
DUAIN9:	HRLZ	T1,(P)
	IORM	T1,RPXGON##(J)
>
RPXIN9:	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
RPXI10:	JUMPGE	T3,RPXI11	;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	RPXI11
	MOVEI	T2,FNCREL	;DO A RELEASE SO OTHER PORT CAN GET IT
	PUSHJ	P,DODO4
	HRRZ	U,KONTBP##(J)	;AN INCREDIBLE CROCK, BUT
	ADDI	U,(T4)		;IF AN UNLOAD WAS DONE
	MOVE	U,(U)
	HRRZ	T2,UNILAS##(U)	; THEN WE ONLY GET A FREE INTERLOCK
	CAIN	T2,FNCUNL	; ON THAT PORT
	SKIPN	T2,UNI2ND##(U)	;IF THE DRIVE IS STILL IN A/B
	CAIA
	SETZM	UNISTS##(T2)	;MAKE THE OTHER PORT IDLE
RPXI11:	LSH	T3,1		;STEP TO NEXT DRIVE
	TLNE	T3,-1		;ANOTHER ATTN BIT?
	SOJGE	T4,RPXI10	;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
		.DOPTC](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)
		 SKIPL UNILAS##(U) ;IF DRIVE WAS ON OTHER PORT
		 LDB T4,UNYPUN## ; WE NEVER TALKED TO IT, SO
		 MOVEI T2,CO.CLR+CO.MBE
		 SKIPE P1	;IF AN RH20 DONE MUST=0
		 XCT RPXCO2##(J) ; OR XFER WON'T START
		 JRST .+1]	; SET UNIT TO WHAT IT SHOULD BE
>
	MOVE	U,RPXFNC##(J)
	TRNN	U,10		;IS IT A WRITE?
	TRO	S,OPWRT		;(OPRED=0)
	MOVSI	T2,DOOF+<(DO.LDR)>(T4)	;CLEAR ECI AND/OR FMT22
	TRNN	U,DO.DTE
	TLNE	U,F22		; IF THEY WERE ON FOR THE DRIVE
	XCT	RPXDO2##(J)
	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
	MOVE	U,KONCUA##(J)	;UNIT WE'RE TALKING TO
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,(CS.NAE)	;MAKE THE BIT=1 IF ERROR
				;AND FALL INTO DATIN2
DATIN2:	TDNN	T2,[ALLERR	;ANY ERROR?
		CS.ERR!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
	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
		CO.AIE+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
		CS.MPE!CS.NXM!CS.OVR](P1)
>
	JRST	ERROR1		;NO
IFN FTKL10,<
	JUMPE	P1,ERRH10	;ALL DIFFERENT FOR RH10S
	TLNE	T2,(CS.MPE)	;CHECK LOGOUT AREA FOR NXM
	TRO	S,IOCHMP
	TLNE	T2,(CS.NXM)
	TRO	S,IOCHNX
	TLNE	T2,(CS.OVR)	;CHECKK LOGOUT AREA FOR OVERRUN
	TRO	S,IOVRUN
	JRST	ERRDON		;AND FINISH UP
ERRH10:>
	TLNE	T2,CHNPAR	;YES, CHAN PARITY ERROR?
	TRO	S,IOCHMP	;YES
	TLNE	T2,CHNNXM
	TRO	S,IOCHNX
	TRNE	T2,OVERUN
	TRO	S,IOVRUN
	JRST	ERRDON		;FINISH UP
ERROR1:	MOVE	T1,T3		;ERROR BITS
	SKIPL	UNIDS2##(U)	;RP07?
	TLZ	T1,OPI!DTE		;NO OPI,DTE ARENT HEADER ERRORS
	TLNN	T1,HCE+HCRC!OPI!DTE	;HEADER ERROR?
	JRST	ERROR2
	TRO	S,IOHDER+IODTER	;YES
	TRZ	S,IODERR
ERROR2:	SKIPG	RPXFLG##(J)	;IF STOPPING ON ERROR,
	TRNE	S,IODERR	;AND DATA ERROR IS UP
	JRST	ERRDON
	SKIPGE	UNIECT##(U)	;IF INITIAL ERROR
	JRST	ERRDON		; REREAD BEFORE TRYING ECC
	TLNE	T3,DCK		;DATA CHECK
	TLNE	T3,ECH		;HARD DATA CHECK?
	CAIA
	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
	TLC	T2,(CS.NAE)	;RECOMPLEMENT BIT
	MOVEM	T2,-1(P)	;SO SYSERR WILL REPORT IT
	TRNN	T2,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	ERRDN1		;NO
	PUSHJ	P,CLRRAE	;YES, CLEAR IT
	JRST	ERRDN1		;AND CONTINUE
ERRDN0:>
	TLNN	T2,SDRAE	;REGISTER ACCESS ERROR?
	JRST	ERRDN2		;NO
	MOVEI	T2,1		;YES, CLEAR THE BIT IN RAE REGISTER
	LSH	T2,(T4)
	HRLI	T2,DORA+<(DO.LDR)>
	XCT	RPXDO2##(J)
ERRDN2:	TRNN	T2,CI.PWF	;POWERFAIL BIT SET
	JRST	ERRDN1		;NO, CONTINUE
	MOVEI	T2,CO.MBI	;YES, SET UP FOR MASSBUS INIT
	XCT	RPXCO2##(J)	;DO THE INIT
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
	MOVE	T4,KONEBK##+17(J) ;GET PATTERN
	SETZ	T3,		;CLEAR MASK EXTENSION
	MOVSI	T2,DEPCPT##	;16-BIT DISK?
	TDNE	T2,DEVCPT##(F)
	JRST	RPXEC6		;DO 16-BIT ECC
	IDIVI	T1,^D36		;COMPUTE WORD LOC, POSITION IN WORD
	EXCH	T2,T4		;T2,,T3 = MASK; T4 = BIT OFFSET
	ROTC	T2,(T4)		;POSITION MASK
	PJRST	CPOPJ1##	;AND SKIP-RETURN

;HERE TO DO 16-BIT ECC

RPXEC6:	IDIVI	T1,^D32		;COMPUTE WORD, BIT OFFSETS (32 DATA BITS)
	EXCH	T2,T4		;T2,,T3 = MASK; T4 = BIT OFFSET
	JUMPLE	T4,CPOPJ1##	;IF NO SHIFT NEEDED, WE'RE DONE
RPXEC7:	ROTC	T2,1		;ROTATE PATTERN TOWARD ERROR
	TLZE	T2,200000	;IF CARRY OUT OF HI LH
	TRO	T3,1		; CARRY INTO LO RH
	TRZE	T2,200000	;IF CARRY OUT OF HI RH
	TLO	T2,1		; CARRY INTO HI LH
	SOJG	T4,RPXEC7	;LOOP UNTIL MASK IS IN PLACE
	JRST	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

;ROUTINE TO MAKE SURE ATTN IS NOT UP OR DRIVE
;ENTER WITH T4 = DRIVE NO.
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+<(DO.LDR)>
	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)
	SKIPGE	UNIDS2##(U)	;IF RP07
	ADDI	T1,^D14		; DON'T BOTHER WITH OFFSET
	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
	TRNE	T2,-1		;IS THIS OFFSET=0?
	JRST	RPXR2A		;NO--GO DO IT
	MOVE	T2,KONEBK##+2(J) ;YES--RETURN TO CENTERLINE
	TRNE	T2,HCE		; UNLESS HCE=1, HCRC=0
	TRNE	T2,HCRC
	SKIPA	T1,[FNCRTC]
	MOVEI	T1,FNCRCL	;IN WHICH CASE DO A RECAL
RPXR2A:	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		;DO.DTE ON (30TH TIME)?
	JRST	RETRY		;YES, THIS TIME STOP ON ERROR
	JRST	GIVEUP		;NO, TELL DAEMON ABOUT IT
RPXCFG::			;DUMMY ENTRY POINT FOR AUTCON

;HERE TO CHECK CAPACITY & STATUS OF RH10/RP04
RPXCPY::
IFN FTKL10,<
	PUSHJ	P,SETP1		;DO MASSBUS ENABLE IF RH20, SET UP P1
>
	MOVSI	T2,DODT		;READ DRIVE-TYPE REGISTER
	PUSHJ	P,DODTI4
	LDB	T3,[POINT 9,T2,35]
	CAIE	T3,42		;RP07?
	JRST	RPXCP1		;NO
	MOVSI	T4,U2PNRM##
	IORM	T4,UNIDS2##(U)	;YES. INDICATE NON-REMOVABLE MEDIA
	MOVEI	T4,3		;UNIT TYPE =3
	JRST	RPXCP2
RPXCP1:	CAIL	T3,20		;IN RANGE OF RP04-PR06 ?
	CAILE	T3,22
	JRST	RPXCP4		;NO, NO SUCH DRIVE
	CAIE	T3,22		;YES, RP06 ?
	TDZA	T4,T4		;NO
	MOVEI	T4,1		;YES, UNIT TYPE=1
RPXCP2:
IFN FTDUAL,<
>
	MOVEM	T2,UNIEBK##+6(U) ;SAVE FOR SYSERR
	MOVSI	T2,DOSR		;YES, READ STATUS REGISTER
	PUSHJ	P,DODTI4
	JUMPE	T2,RPXCP4	;NO SUCH DRIVE IF CAN'T READ STATUS (SEIZED TO OTHER PORT)
	MOVE	T1,T2		;PRESERVE STATUS REGISTER (PROGRAMMABLE BIT)
	TRCN	T2,MOL		;MOL?
	TLO	T4,KOPUHE##	;NO, INIT IS OFF-LINE OR DOWN
IFN FTDUAL,<
	TRNE	T2,MOL!VV	;IF VV=0 BUT MOL=1
	JRST	RPXCP3
	PUSH	P,T4		;THEN THE DRIVE WON'T DO A RELEASE
	LDB	T4,UNYPUN##	; SO DO A PACK ACKNOWLEDGE
	PUSHJ	P,NOWUP		; SO THAT RELEASE WILL WORK
	POP	P,T4
RPXCP3:>
	MOVSI	T2,DOSN		;READ DRIVE SERIAL NUMBER
	PUSHJ	P,DODTI4
	MOVEM	T2,UNIEBK##+10(U)	;AND STORE IN UDB
IFN FTDUAL,<
	TRNE	T1,PGM		;DUAL-PORTED DRIVE?
	JUMPE	T2,RPXCP4	;YES. SN=0 IF DRIVE GOT SEIZED TO OTHER PORT
	HRRZM	T2,UNISER##(U)	;RETURN SN IN UNISER
>
	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
	CAMN	T1,BLKPR7
	SKIPA	W,[^D43,,^D1376] ;(RP07) BLK/TRK,,BLK/CYL
	MOVE	W,[^D20,,^D380]	;BLKS PER TRK,, BLKS PER CYL
	AOS	(P)		;SET FOR SKIP RETURN
	JRST	RPXCP5		;CLEAR POSSIBLE RAE AND EXIT

RPXCP4:	MOVSI	T4,KOPUHE##+KOPNSU##	;OFF LINE OR DOWN
	SETZB	T1,T2		;NO BLOCKS PGR UNIT - CANT READ
RPXCP5:
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+<(DO.DRE+DO.LDR)>
	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,
>
;ENTRY TO READ DRIVE REGS
RPXREG::
IFN FTKL10,<
	PUSHJ	P,SETP1		;MASSBUS ENABLE IF RH20
>
	LDB	T4,UNYPUN##	;DRIVE NUMBER
	PUSHJ	P,RDREG		;READ REGS
IFE FTDUAL,<
	POPJ	P,		;RETURN
>
IFN FTDUAL,<
	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
RDREG:	PUSH	P,U
	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
		    .DOPTC](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
		    .DOPBA](P1)
>
	PUSHJ	P,DODTIC
	MOVEM	T2,KONEDB##(J)	; AND SAVE
	PJRST	UPOPJ##		;RETURN
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

BLKPRU:	DEC	154280		;406 CYLINDERS
	DEC	307800		;810 CYLINDERS
	0			;(RM03)
BLKPR7:	DEC	865504		;629 CYL, 32 SURF, 43 SECT
BLKPUM:	DEC	156180		;411 CYLINDERS
	DEC	309700		;815 CYLINDERS
	0			;(RM03)
	DEC	866880		;630 CYL *1376
BLKPUC:	DEC	171798		;22*19*411
	DEC	340670		;22*19*815
	0
	0

	$LIT
RPXEND:	END