Google
 

Trailing-Edge - PDP-10 Archives - tops10_703_distr_bb-x140b-sb - 10,7/703mon/rhxkon.mac
There are 8 other files named rhxkon.mac in the archive. Click here to see a list.
TITLE	RHXKON - RH11 DRIVER FOR RP06'S AND RM03'S  V022
SUBTTL  J EVERETT/JE/DBD	3 DEC 85
	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.
;
.CPYRT<1978,1986>
;COPYRIGHT (C) 1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.

;

XP VRHKON,022
;TRACKS VERSION 147 OF RPXKON

;ASSEMBLY INSTRUCTIONS: RHXKON,RHXKON_KONPAR,RHXKON

ENTRY	RHXKON
RHXKON::
SUBTTL DEFINITIONS
;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

FCOMP==400000		;COMPATABILITY MODE (SOFTWARE ONLY, NEVER STORED IN DDB)
FESI==200000		;ERROR STOP INHIBIT (SOFTWARE ONLY, NEVER STORED IN DDB)

;RH11 REGISTER OFFSETS

DOCR==0			;CONTROL REGISTER
DOWC==2			;WORD COUNT REGISTER
DOBA==4			;BUS ADDRESS REGISTER
DODA==6			;DESIRED ADDRESS (TRACK/SECTOR)
DOCS2==10		;STATUS REGISTER
DOSR==12		;DRIVE STATUS REGISTER
DOER==14		;ERROR REG 1
DOAS==16		;ATTENTION SUMMARY
DOLA==20		;LOOK-AHEAD (SECTOR COUNTER)
DODB==22		;DATA BUFFER
DODT==26		;DRIVE TYPE
DOSN==30		;SERIAL NUMBER
DOOF==32		;OFFSET
DODC==34		;DESIRED CYLINDER
DOER2==40		;ERROR REG 2
DOER3==42		;ERROR REG 3
DOECP==44		;ECC POSITION
DOECB==46		;ECC BURST (PATTERN)
;DRIVE 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
OM==1B35		;OFFSET MODE (RM03)

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
;CONTROL REGISTER BIT ASSIGNMENTS

CR.SC==100000		;(R) SPECIAL CONDITION (ALL ERRORS)
CR.TRE==40000		;(R/W) TRANSFER ERROR
CR.CPE==20000		;(R) CONTROL BUS PARITY ERROR
CR.DVA==4000		;(R) DRIVE AVAILABLE
CR.PSL==2000		;(R/W) PORT SELECT
CR.RDY==200		;(R) READY
CR.IE==100		;(R/W) INTERRUPT ENABLED

;STATUS REGISTER BIT ASSIGNMENTS

CS.DLT==100000		;(R) DATA LATE (OVERRUN)
CS.WCE==40000		;(R) WRITE CHECK ERROR
CS.UPE==20000		;(R/W) UNIBUS PARITY ERROR
CS.NXD==10000		;(R) NON-EXISTANT DRIVE
CS.NXM==4000		;(R) NON-EXISTANT MEMORY
CS.PGE==2000		;(R) PROGRAM ERROR
CS.MXF==1000		;(R/W) MISSED TRANSFER
CS.DPE==400		;(R) DATA BUS PARITY ERROR
CS.OR==200		;(R) OUTPUT READY
CS.IR==100		;(R) INPUT READY
CS.CLR==40		;(W) CONTROLLER CLEAR
CS.PAT==20		;(R/W) PARITY TEST
CS.BAI==10		;(R/W) UNIBUS ADDRESS INCREMENT INHIBIT

SUBTTL	FILSER CALL PROCESSING

RPXUNL::SKIPA	T1,[FNCUNL]	;UNLOAD
RPXRCL::MOVEI	T1,FNCRCL	;RECAL
	PUSHJ	P,SAVE1##	;PRESERVE AN AC
	MOVE	P1,RHXBAS##(J)	;SET UP INDEX REGISTER TO RH11 BASE ADDRESS
	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,SAVE1##	;PRESERVE AN AC
	MOVE	P1,RHXBAS##(J)	;SET UP INDEX REGISTER TO RH11 BASE ADDRESS
	PUSHJ	P,CONECT	;CONECT TO THE DRIVE
	  JRST	RPXDWN		;DOWN
	HRLI	T2,DODC		;SET FOR DATAO TO DESIRED CYL
RPXMOV:	SETZ	T4,
	WRIO	T4,DOOF(P1)	;CLEAR OFFSET REGISTER
	WRIO	T4,DODA(P1)	;CLEAR POSSIBLE ILLEGAL SECTOR
	JRST	RPXGO		;AND CONTINUE

RPXSTP::PUSHJ	P,SAVE1##	;PRESERVE AN AC
	MOVE	P1,RHXBAS##(J)	;SET UP INDEX REGISTER TO RH11 BASE ADDRESS
	RDIO	T2,DOCR(P1)	;GET RH11 STATUS
	RDIO	T3,DOCS2(P1)
	HRLI	T2,(T3)
	MOVEI	T3,CR.TRE!CR.IE
	WRIO	T3,DOCR(P1)	;CLEAR CONTROLLER AND ENABLE INTERRUPTS
	MOVEI	T3,CS.MXF	;CAUSE AN INTERRUPT
	WRIO	T3,DOCS2(P1)
	MOVEI	T3,CR.RDY
	TIOE	T3,DOCR(P1)	;READY BIT ON NOW?
	AOS	-1(P)		;YES, SKIP RETURN
	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'S FROM KONEBK
	POPJ	P,
RPXLTM::PUSHJ	P,SAVE1##	;PRESERVE AN AC
	MOVE	P1,RHXBAS##(J)	;SET UP RH11 BASE ADDRESS
	LDB	T3,UNYPUN##	;UNIT NUMBER
	MOVEI	T4,CS.BAI	;BUS ADDRESS INHIBIT
	TIOE	T4,DOCS2(P1)	;IS IT SET?
	ADDI	T3,(T4)		;YES--THEN PRESERVE IT
	WRIOB	T3,DOCS2(P1)	;SELECT UNIT
	MOVEI	T4,3		;MAKE SURE WE DONT TRY TOO MUCH
	PUSH	P,T1		;SAVE TARGET BLOCK
RPXLT1:	RDIO	T1,DOLA(P1)	;GET CONTENTS OF LOOK AHEAD REG
	MOVEI	T2,CR.TRE!CR.CPE	;
	TIOE	T2,DOCR(P1)	;ERROR?
	JRST	TPOPJ##		;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,^D8333	;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
	LDB	T4,UNYBPT##	;GET NUMBER OF BLOCKS PER TRACK
	ADDI	T1,-2(T4)	;ALLOW A 2-SECTOR FUDGE FACTOR
	IDIV	T1,T4		;DESIRED SECTOR TO T2
	SUB	T2,T3		;DISTANCE
	SKIPGE	T1,T2
	ADD	T1,T4		;NEGATIVE - ADD 1 REVOLUTION
	MOVEI	T3,^D16667	;TIME FOR COMPLETE REVOLUTION
	IDIV	T3,T4		;COMPUTE MICRO-SECS PER SECTOR
	IMUL	T1,T3		;MICROSECONDS TO TARGET
	PJRST	CPOPJ1##	;GOOD RETURN
RPXRDF::SKIPA	T1,[FNCRHD]	;READ HEADERS AND DATA
RPXWTF::MOVEI	T1,FNCWTF	;WRITE HEADERS AND DATA (FORMAT)
	JRST	RPXDGO
RPXRDC::SKIPA	T1,[FNCRED!FCOMP];READ 22-SECTOR MODE
RPXWTC::MOVEI	T1,FNCWRT!FCOMP	;WRITE 22-SECTOR MODE
	JRST	RPXDGO

RPXRED::SKIPA	T1,[FNCRED!FESI] ;READ, DONT STOP ON ERROR
RPXWRT::MOVEI	T1,FNCWRT!FESI	;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,SAVE1##	;PRESERVE AN AC
	MOVE	P1,RHXBAS##(J)	;SET UP RH11 BASE ADDRESS
	PUSHJ	P,CONECT	;CONECT TO THE DRIVE
	  JRST	RPDWND		;DOWN
	TRNE	T1,FESI		;STOP ON ERROR?
	AOS	RPXFLG##(J)	;NO, SET RPXFLG POSITIVE
	LDB	T4,UNYUTP##	;GET UNIT TYPE
	CAIN	T4,2		;RM03?
	JRST	RPXDG0		;YES, TREAT DIFFERENTLY
	TRNE	T1,FCOMP	;IF 22-SECTOR MODE,
	IDIVI	T3,^D22		; ADDRESSING IS DIFFERENT
	TRNN	T1,FCOMP

	IDIVI	T3,^D20		;COMPUTE SECTOR, BLOCK
	JRST	RPXDG1
RPXDG0:	
	TRNE	T1,FCOMP	;11 COMPATIBILITY MODE?
	IDIVI	T3,^D32		;YES, 32 SECTORS PER TRACK
	TRNN	T1,FCOMP
	IDIVI	T3,^D30		;RM03 HAS 30 SECTORS PER TRACK
RPXDG1:	DPB	T3,[POINT 5,T4,27] ;SET T4 FOR DESIRED ADDRESS REGISTER
	WRIO	T2,DODC(P1)	;SET DESIRED CYLINDER
	SETZ	T2,
	TRNE	T1,FCOMP	;11 COMPATIBILITY MODE?
	TROA	T2,ECI+FMT22	; LIGHT FMT22 IN OFFSET REGISTER

	TRNE	T1,FESI		;IF NOT STOPPING ON ERROR
	TRCA	T2,ECI		;CLEAR OFFSET, SET ECI
	TRNN	T1,10		;IF WRITING
	WRIO	T2,DOOF(P1)	;CLEAR OFFSET REGISTER
	MOVE	T3,KONCHN##(J)	;GET ADDRESS OF CHANNEL DATA BLOCK
	MOVE	T2,CHNIEA##(T3)	;GET INITIAL ELEVEN STYLE ADDRESS
	WRIO	T2,DOBA(P1)	;AND LOAD THE BUS ADDRESS REGISTER
	MOVE	T2,CHNBTC##(T3)	;GET THE BYTE COUNT FOR THIS TRANSFER
	LSH	T2,-1		;MAKE ELEVEN STYLE WORD COUNT
	MOVNS	T2		;2'S COMPLEMENT
	WRIO	T2,DOWC(P1)	;LOAD THE WORD COUNT REGISTER
	MOVE	T2,CHNNXF##(T3)	;NO-XFER FLAG
	JUMPGE	T2,RPXDG2	;IS THIS A NO XFER READ?
	MOVEI	T2,CS.BAI	;YES--BUS ADDRESS INHIBIT
	BSIOB	T2,DOCS2(P1)	;SET IT
RPXDG2:	MOVE	T2,T4		;DESIRED ADDRESS
	HRLI	T2,DODA		;SET TO DATAO THE RIGHT REGISTER

;HERE TO INITIATE AN OPERATION
;
;CALL	T1=	FUNCTION
;	T2=	REGISTER TO LOAD,,VALUE

RPXGO:	HLRZ	T4,T2		;GET REGISTER TO LOAD
	ADD	T4,P1		;COMPUTE ADDRESS OF REGISTER
	WRIO	T2,(T4)		;AND WRITE IT
	LDB	T4,UNYPUN##	;UNIT NUMBER GETS SAVED FOR INTERRUPT LEVEL
	TLO	T1,400000(T4)	;LIGHT THE DISK NOT HUNG BIT(AN RPXKON HACK)
	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
	TRZ	T1,FCOMP!FESI	;CLEAR SOFTWARE BITS BEFORE STARTING IO

	TRO	T1,CR.IE	;SET INTERRUPT ENABLE BIT
	WRIOB	T1,DOCR(P1)	;START AND TURN ON PI
	DSKON
	PJRST	CPOPJ1##	;AND SKIP RETURN

;HERE TO ENABLE INTERRUPTS
INTENB:	MOVEI	T1,CR.IE	;INTERRUPT ENABLE BIT
	TION	T1,DOCR(P1)	;IF INT ENB SET, LEAVE IT ALONE
	WRIOB	T1,DOCR(P1)	; ELSE SET IT
	POPJ	P,		;RETURN
;HERE IF A DRIVE IS DOWN WHEN WE'RE TRYING TO START IO
RPDWND:
	SETOM	RPXFLG##(J)	;NOT DOING IO NOW
;HERE IF A DRIVE IS DOWN WHEN WE'RE TRYING TO SEEK/RECAL
RPXDWN:
	MOVE	T1,T3		;ERROR FLAGS INTO T1
	MOVEI	T4,CR.IE	;INTERRUPT ENABLE BIT
	BSIOB	T4,DOCR(P1)	;ENABLE INTERRUPTS
	DSKON
	RDIO	T2,DOCR(P1)	;GET "CONI" STATUS
	RDIO	T3,DOCS2(P1)
	HRLI	T2,(T3)
	MOVE	T3,KONEBK##+1(J);SET RH(T3)=DRIVE STATUS
	HRL	T3,KONEBK##+2(J); AND LH = ERROR REGISTER
	POPJ	P,		;AND NON-SKIP RETURN TO FILSER
SUBTTL	GENERAL CONTROLLER-TO-DRIVE CONNECT ROUTINE

;CONNECT RH11 TO A DRIVE
;CALL	U=	UNIT DATA BLOCK
;	P1=	RH11 MASSBUS REGISTERS BASE ADDRESS
;	T1=	FUNCTION TO BE PERFORMED
;RETURN CPOPJ	IF DRIVE/CONTROLLER DOWN
;RETURN CPOPJ1	IF OK (T1 PRESERVED)
;	T2=	CYLINDER
;	T3=	REMAINDER FROM CYLINDER COMPUTATION

CONECT:	DSKOFF			;IF ON UUO LEVEL, GUARD AGAINST INTERRUPTS

	MOVEI	T4,CR.RDY	;GET RH11 READY BIT
	TRNE	T1,40		;TRYING TO DO IO?
	TIOE	T4,DOCR(P1)	;YES, KONTROLLER BUSY?
	JRST	CONEC1		;NO, ALL IS OK
	MOVEI	T2,CS.CLR	;SET RDY
	WRIOB	T2,DOCS2(P1)	;BY CLEARING CONTROLLER
	AOS	UNIHNG##(U)	;BUMP A COUNTER
	TION	T4,DOCR(P1)	;DID RDY SET?
	JRST	CONER2		;NO--CALL DRIVE OFF-LINE
CONEC1:
	LDB	T4,UNYPUN##	;GET UNIT NUMBER
	MOVEI	T2,CS.BAI	;BUS ADDRESS INHIBIT
	TIOE	T2,DOCS2(P1)	;IS IT SET?
	ADDI	T4,(T2)		;YES--THEN PRESERVE IT
	WRIOB	T4,DOCS2(P1)	;AND SELECT PROPER UNIT
	RDIO	T2,DOSR(P1)	;AND READ DRIVE'S STATUS REGISTER
	TRZ	T2,LST+PGM+OM	;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,UNYUTP##	;GET UNIT TYPE
	CAIE	T3,2		;RMO3?
	SKIPA	T3,[^D418,,^D380];NO
	MOVE	T3,[^D160,,^D150];YES
	TRNE	T1,FCOMP	;COMPARTIBILITY MODE?
	HLRS	T3		;YES,MORE SECTORS

	IDIVI	T2,(T3)		; ADDRESSING IS DIFFERENT
	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
	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
	RDIO	T2,DOSR(P1)	;READ THE STATUS REG
	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
	PUSHJ	P,RDREG		;READ DRIVE REGISTERS
	PUSHJ	P,DVCLR		;NO, CLEAR THE DRIVE
	POP	P,T1
	POP	P,U
	RDIO	T2,DOSR(P1)	;READ STATUS REG
	TRZ	T2,LST+PGM+OM
	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

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 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
	WRIOB	T2,DOCR(P1)	;DO A PACK ACKNOWLEDGE
	POPJ	P,		;AND RETURN
SUBTTL	INTERRUPT LEVEL PROCESSING

RPXINT::
	PUSHJ	P,SAVE2##	;PRESERVE SOME AC'S
	MOVE	P1,RHXBAS##(J)	;SET UP INDEX REG TO RH11 BASE ADDRESS
	RDIO	T2,DOAS(P1)	;READ ATTN SUMMARY REGISTER
	SETZB	S,T4
	ANDI	T2,377		;ANY ATTENTION ON?
	JUMPE	T2,NOATTN	;NO
	PUSH	P,T2		;SAVE IT (CLEAR IF NO ERRORS LATER ON)
	HRRZ	T1,T2		;BITS FOR ATTN-DRIVES
	MOVEI	P2,CS.BAI	;BUS ADDRESS INHIBIT
	TION	P2,DOCS2(P1)	;IS IT SET?
	SETZ	P2,		;NO--THEN DON'T PRESERVE IT
RPXIN2:	LSHC	T1,-1		;TEST THE NEXT DRIVE
	JUMPGE	T2,RPXIN4	;NOT THIS ONE
	ADDI	T4,(P2)		;PUT IN BAI IF NEEDED
	WRIOB	T4,DOCS2(P1)	;SELECT THIS DRIVE
	SUBI	T4,(P2)		;TAKE OUT BAI IF SET
	RDIO	T2,DOSR(P1)	;AND READ ITS STATUS REGISTER
	HRRZ	U,KONTBP##(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
;HERE IF INTERRUPT & NO XFER IN PROGRESS AND THE DRIVE HAD AN ERROR
;FILIO IGNORES US IF WE TELL HIM THERE WAS AN ERROR DURING A POSITION
;COMMAND. SO TELL HIM THAT THE POSITION COMMAND WAS SUCCESSFUL.
;THEN DO AN IMPLIED SEEK LATER ON.
	MOVEI	T3,SKI
	TION	T3,DOER3(P1)	;SKIP IF SEEK INCOMPLETE IS ON
	JRST	RPXI2A
	RDIO	T3,DOER(P1)
	TRNE	T3,UNS
	JRST	RPXI2A
	TRNN	T2,DRY		;IF DRIVE READY IS OFF THE UNIT IS RECALIBRATING
	JRST	RPXIN4		; SO WAIT FOR NEXT INTERRUPT (DON'T TELL FILSER)
	PUSHJ	P,DVCLR		;RECAL DONE, CLEAR THE DRIVE
				;(UNIT IS NOT ON RIGHT CYLINDER, BUT IMPLIED SEEK WILL WIN)
	SKIPA	T2,[1]
RPXI2A:	MOVSI	T2,1
	ADDM	T2,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
	JRST	RPXI3B		;PUSH ON

;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:	TRNN	T2,ERR		;IS THERE AN ERROR?
	JRST	RPXI3Z		;NO
	PUSHJ	P,DVCLR		;YES, CLEAR IT
	RDIO	T2,DOSR(P1)	;DID IT CLEAR?
	TRNN	T2,ERR
	JRST	RPXI3Z		;YES
	SETZ	T2,		;NO, CLEAR IT THE HARD WAY
	WRIO	T2,DOER3(P1)
	WRIO	T2,DOER2(P1)
	WRIO	T2,DOER(P1)
RPXI3Z:	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
	WRIO	T2,DOAS(P1)	; OF ALL THE DRIVES WE JUST LOOKED AT
	SKIPGE	RPXFLG##(J)	;DATA XFER IN PROGRESS?
	JUMPE	S,INTENB	;NO--DISMISS INTERRUPT IF JUST A POWER-DOWN ATTN
				;YES--FALL INTO NOATTN
NOATTN:	SKIPL	RPXFLG##(J)	;DATA XFER IN PROGRESS?
	JRST	DATINT		;YES
	RDIO	T2,DOCR(P1)	;NO, GET "CONI" STATUS
	RDIO	T4,DOCS2(P1)
	TRNE	T4,CS.NXD	;NON-EX DRIVE?
	JRST	[MOVEI	T1,CS.CLR	;YES MUST CLEAR CONTROLLER
		 WRIOB	T1,DOCS2(P1)
		 JRST	.+1]	;GIVE INTERRUPT TO FILSER
	HRLI	T2,(T4)
	HRRI	S,OPPOS		;INDICATE POSITION INTERRUPT
	JRST	CALLIO		;AND TELL FILSER

DATINT:	RDIO	T2,DOCR(P1)	;GET THE CONTROLLER STATUS REGISTER
	LSH	T2,-10		;POSITION 2 BIT ADDRESS EXTENSION
	RDIO	T4,DOBA(P1)	;AND THE BUS ADDRESS REGISTER
	DPB	T2,[POINT 2,T4,19] ;MAKE AN 18 BIT ADDRESS
	RDIO	T2,DOWC(P1)	;GET THE REMAINS IN THE WORD COUNT REGISTER
	HRL	T4,T2		;COMBINE
	MOVEM	T4,KONIOC##(J)	;AND STORE IN KONIOC FOR FILIO TO COMPARE
	MOVE	U,RPXFNC##(J)
	TRNN	U,10		;IS IT A WRITE?
	TRO	S,OPWRT		;(OPRED=0)
	HLRZ	T4,U		;DRIVE DOING XFER IS IN HERE
	ANDI	T4,7		;GET ONLY DRIVE NUMBER
	WRIOB	T4,DOCS2(P1)	;SELECT IT AND CLEAR BAI
	MOVEI	T2,ECI!FMT22	;CLEAR ECI AND/OR FMT22
	TRNE	U,FESI!FCOMP	; IF THEY WERE ON FOR THE DRIVE
	BCIO	T2,DOOF(P1)	;ZAP
	TLO	S,(T4)		;DRIVE NUMBER IN LH
	RDIO	T3,DOSR(P1)	;READ THE DRIVE STATUS REGISTER
	RDIO	T2,DOER(P1)	;READ THE ERROR REGISTER
	HRLI	T3,(T2)		;T3=ERROR,,STATUS
	RDIO	T2,DOCR(P1)	;GET RH11 STATUS
	RDIO	T4,DOCS2(P1)
	HRLI	T2,(T4)
	MOVE	U,KONCUA##(J)	;UNIT WE'RE TALKING TO
	TRNN	T2,CR.TRE!CR.CPE;ERROR?
	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
	MOVE	T4,KONCHN##(J)	;CHAN DATA BLOCK ADDRESS
	SETZM	CHNNXF##(T4)	;CLEAR NO-XFER FLAG

CALLIO:	MOVEI	T4,CR.TRE!CR.IE	;CLEAR ERRORS, ENABLE INTERRUPTS
	WRIO	T4,DOCR(P1)	;AND START
	DSKON
	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
	TRNN	T4,CS.NXM!CS.DLT ;CHANNEL-TYPE PROBLEM?
	JRST	ERROR1		;NO--GO ON
	TRNE	T4,CS.DLT	;DATA LATE?
	TRO	S,IOVRUN	;YES
	MOVE	T1,KONCHN##(J)	;GET CHANNEL DATA BLOCK
	RDIO	T4,@CHNUBA##(T1) ;READ UBA STATUS REGISTER
	TRNE	T4,UNBTMO	;DID UBA GET A NXM?
	TRO	S,IOCHNX	;YES
	TRNE	T4,UNBBME	;DID UBA HIT BAD MEMORY?
	TRO	S,IOCHMP	;YES
	MOVEI	T4,UNBTMO!UNBBME ;CLEAR ANY OF THESE UBA
	BSIO	T4,@CHNUBA##(T1) ; ERRORS IF SET
	JRST	ERRDON		;FINISH UP
ERROR1:	TLNN	T3,HCE+HCRC	;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
	LDB	T4,UNYPUN##	;GET UNIT NUMBER
	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]	;CLEAR ALL BUT DA AND DC

;ROUTINE TO CLEAR A DRIVE AND MAKE SURE IT REALLY CLEARED
;PRESERVES T1
DVCLR:	MOVEI	T2,FNCCLR	;CLEAR DRIVE
	PUSH	P,T2		;SAVE FUNCTION CODE
	RDIO	T2,DOOF(P1)	;DRIVE CLEAR ZEROES OFFSET REG
	EXCH	T2,(P)		;SAVE DOOF, GET FUNCTION CODE
	WRIOB	T2,DOCR(P1)	;ZAP
	WRIOB	T2,DOCR(P1)	;SOME DRIVES NEED 2!
	POP	P,T2		;RESTORE OFFSET REG
	WRIO	T2,DOOF(P1)	; SO SYSERR WILL REPORT IT
				; AND TEST ON 1ST ERROR WILL WORK
	RDIO	T2,DOAS(P1)	;READ ATTN SUMMARY REGISTER
	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
	WRIO	T2,DOAS(P1)	;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::PUSHJ	P,SAVE1##	;SAVE A REGISTER
	MOVE	P1,RHXBAS##(J)	;AND SET UP RH11 BASE ADDRESS
	TLO	M,400000
	SOJN	T1,RPXER1	;IF FIRST ERROR,
	RDIO	T3,DOSR(P1)	;READ DRIVE STATUS REGISTER
	RDIO	T2,DOOF(P1)	;READ THE OFFSET REGISTER
	TRNE	T3,OM		;OFFSET RM03?
	JRST	RPXER0		;YES
	TRNN	T2,70		;OFFSET RP06?
	JRST	RPXER1		;NO--DRIVE ISNT OFFSET - CONTINUE
RPXER0:	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,CONECT	;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 OR RM03?
	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--THEN 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		;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
;HERE TO CHECK CAPACITY & STATUS OF UNIT ON RH11
RPXCPY::
	MOVE	W,RHXBAS##(J)	;SET UP RH11 BASE ADDRESS
	LDB	T2,UNYPUN##	;GET UNIT NUMBER
	MOVEI	T3,CS.BAI	;BUS ADDRESS INHIBIT
	TIOE	T3,DOCS2(W)	;IS IT SET?
	ADDI	T2,(T3)		;YES--THEN PRESERVE IT
	WRIOB	T2,DOCS2(W)	;SELECT UNIT
	RDIO	T2,DODT(W)	;READ DRIVE-TYPE REGISTER
	MOVEM	T2,UNIEBK##+6(U);SAVE FOR SYSERR
	LDB	T3,[POINT 9,T2,35]
	SETZ	T4,
;	CAIN	T3,21		;RP04? (NOT SUPPORTED ON 2020)
;	JRST	RPXCP2		;YES, UNIT TYPE 0
	CAIN	T3,22		;RP06
	AOJA	T4,RPXCP2	;YES, UNIT TYPE 1
	CAIE	T3,24		;RM03?
	JRST	RPXCP3		;NOT A LEGAL UNIT TYPE, NO SUCH DRIVE
	MOVEI	T4,2		;RMO3 IS UNIT TYPE 2
RPXCP2:	RDIO	T2,DOSR(W)	;YES, READ STATUS REGISTER
	TRNN	T2,MOL		;MOL?
	TLO	T4,KOPUHE	;NO, INIT IS OFF-LINE OR DOWN
	RDIO	T2,DOSN(W)	;READ DRIVE SERIAL NUMBER
	MOVEM	T2,UNIEBK##+10(U);AND STORE IN UDB
	TLO	T4,KOP22B##	;PRETEND RH11 IS 22 BIT
	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,BLKTBC(T4)	;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:	POPJ	P,

BLKPRU:	DEC	154280		;406 CYLINDERS
	DEC	307800		;810 CYLINDERS
	DEC	123150		;821 CYLINDERS
BLKPUM:	DEC	156180		;411 CYLINDERS
	DEC	309700		;815 CYLINDERS
	DEC	123450		;823 CYLINDERS
BLKPUC:	DEC	171798		;22*19*411
	DEC	340670		;22*19*815
	DEC	131680		;32*5*823
BLKTBC:	^D20,,^D380		;BLKS/TRK,,BLKS/CYL(RP04) (NOT SUPPORTED ON 2020)
	^D20,,^D380		;		   (RP06)
	^D30,,^D150		;		   (RM03)
	;END FTDHIA
;ENTRY TO READ DRIVE REGS
RPXREG::
	PUSHJ	P,SAVE1##	;GET A REGISTER
	MOVE	P1,RHXBAS##(J)	;AND SET UP RH11 BASE ADDRESS
	PUSH	P,U		;RDREG WIPES U
	LDB	T4,UNYPUN##	;DRIVE NUMBER
	MOVEI	T1,CS.BAI	;BUS ADDRESS INHIBIT
	TIOE	T1,DOCS2(P1)	;IS IT SET?
	ADDI	T4,(T1)		;YES--THEN PRESERVE IT
	WRIOB	T4,DOCS2(P1)	;SELECT UNIT
	PUSHJ	P,RDREG		;READ REGS
	PJRST	UPOPJ##		;RESTORE U AND RETURN

;SUBROUTINE TO READ ALL DRIVE REGISTERS
;PRESERVES T3,T4 CLOBBERS U
RDREG:	PUSH	P,P2		;GET SOME WORKING REGISTERS
	PUSH	P,P3		;
	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
	MOVE	P2,[POINT 6,RH11OF]
RDREG1:	ILDB	P3,P2		;GET REGISTER OFFSET
	ADD	P3,P1		;COMPUTE ADDRESS OF REGISTER
	RDIO	T2,(P3)		;READ THE REGISTER
	MOVEM	T2,(U)		;SAVE IN KONTROLLER DB
	SUBI	U,1
	SOJG	T1,RDREG1	;AND GO READ ANOTHER
	MOVE	P2,KONCHN##(J)	;GET ADDRESS OF CHANNEL DATA BLOCK
	RDIO	T2,@CHNUBA##(P2);READ UBA STATUS REGISTER
	MOVEM	T2,KONECR##(J)	;SAVE HERE IN KDB
	RDIO	T2,DOCR(P1)	;GET RPCS1
	LSH	T2,-10		;POSITION 2 BIT ADDRESS EXTENSION
	RDIO	T1,DOBA(P1)	;GET THE ENDING BUS ADDRESS
	DPB	T2,[POINT 2,T1,19] ; AND PUT IN HIGH ORDER BITS
	IDIVI	T1,UBAMUL	;COMPUTE MAP REGISTER OFFSET
	ADDI	T1,UBAEXP	;ADD IN THE BASE ADDRESS
	HLL	T1,CHNUBA##(P2)	;PUT IN PROPER UBA NUMBER
	RDIO	T2,(T1)		;READ OUT MAP SLOT OF LAST WORD XFER'ED
	MOVEM	T2,KONEDB##(J)	;SAVE HERE IN KDB
	POP	P,P3		;RESTORE THE REGISTERS
	POP	P,P2		;
	POPJ	P,		;RETURN

;RH11 REGISTER OFFSETS IN DESCENDING ORDER OF MASSBUS ADDRESSES

RH11OF:	BYTE (6) 46,44,42,40,36,34
	BYTE (6) 32,30,20,26,06,16
	BYTE (6) 24,14,12,0

	$LIT
RPXEND:	END