Google
 

Trailing-Edge - PDP-10 Archives - BB-BT99T-BB_1990 - 10,7/mon/rpxkon.mac
There are 11 other files named rpxkon.mac in the archive. Click here to see a list.
TITLE	RPXKON - DRIVER FOR MASSBUS DISKS  V243
SUBTTL  T WACHS/TW/JAD   17-APRIL-90

	SEARCH	F,S,DEVPRM,SAXPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1974,1990>


XP VRPKON,243
;ASSEMBLY INSTRUCTIONS: RPXKON,RPXKON_KONPAR,RPXKON

RPXKON::ENTRY	RPXKON
	SUBTTL	AUTOCONFIGURATION TABLES

	SUBTTL	DEFINITIONS

;PARAMETERS TO CONTROL XXKON MACRO:

RPFIX==KOPPWX			;POSITIONING DEVICE, CAN SEEK WHILE XFERRING
RPOFS==0			;CAN OFFSET FOR ERROR RECOVERY
RPRDC==0			;10/11 COMPATABILITY MODE
RPUNL==0			;DRIVE CAN BE UNLOADED
RPCPY==0			;CAN TELL UNIT TYPE EVEN IF KONTROL IS BUSY
RPMX==0				;CANNOT DO MULTIPLE TRANSFERS
RPDRB==0			;DOESN'T USE DISK I/O REQUEST BLOCKS
RPBMX==0			;NOT A BLOCK MULTIPLEX KONTROLLER
RPECA==0			;TRY OFFSET/RECAL BEFORE TRYING ECC
RPERNO==^D16			;16 DRIVE REGISTERS TO SAVE ON ERROR
RPXELG==MDEELG##		;ERROR LOG ROUTINE IS IN FILIO

RPXDMX==10			;MAXIMUM DRIVES PER KONTROLLER
RPXHDN==RPXDMX-1		;HIGHEST DRIVE NUMBER ON KONTROLLER

;DRIVER CHARACTERISTICS
;	RPX	= RPXCNF
;	DSK	= DISK
;	0	= MAXIMUM DEVICES IN SYSTEM (NO LIMIT)
;	TYPRP	= KONTROLLER TYPE
;	RPXDMX	= MAXIMUM DRIVES PER KONTROLLER
;	RPXHDN	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(RPX,DSK,0,TYPRP,RPXDMX,RPXHDN,MDSEC0,MDSEC0,DR.MCD)

	.ORG	KONUDB		;START OF RP0X/RM0X SPECIFIC DATA
RPXUTB:!BLOCK	RPXDMX		;TABLE OF POINTERS TO UDBS
RPXEBK:!BLOCK	RPERNO		;STORAGE FOR ERROR REGISTERS
RPXIOB:!			;START OF SPECIAL I/O INSTRUCTIONS
RPXCO4:!BLOCK	1
RPXCI2:!BLOCK	1
RPXCO2:!BLOCK	1
RPXDI1:!BLOCK	1
RPXDI2:!BLOCK	1
RPXDO1:!BLOCK	1
RPXDO2:!BLOCK	1
RPXRAE:!BLOCK	1		;TEST RAE IF RH20
RPXIOE:!			;END OF SPECIAL I/O INSTRUCTIONS
RPXFNC:!BLOCK	1		;CURRENT FUNCTION AND FLAGS
RPXFLG:!BLOCK	1
RPXGON:!BLOCK	1
RAECNT:!BLOCK	1		;RAE ERRS - CBPE,,NO TRA
RPXIUM:! BLOCK	RPXDMW		;IGNORE DRIVE MASK
RPXNUM:! BLOCK	RPXDMW		;NEW DRIVE MASK
RPXKLN:!			;LENGTH OF KDB
	.ORG

;PROTOTYPE KDB
RPXKDB:	XXKON	(RP)
	SETWRD	(RPXCO4,<CONO  000,(T4)>)
	SETWRD	(RPXCI2,<CONI  000,T2>)
	SETWRD	(RPXCO2,<CONO  000,(T2)>)
	SETWRD	(RPXDI1,<DATAI 000,T1>)
	SETWRD	(RPXDI2,<DATAI 000,T2>)
	SETWRD	(RPXDO1,<DATAO 000,T1>)
	SETWRD	(RPXDO2,<DATAO 000,T2>)
	SETWRD	(RPXRAE,<CONSZ 000,CI.RAE>)
	SETWRD	(RPXFLG,<-1>)
	KDBEND

	RPXCCM==CYLCM##

EQUATE	(LOCAL,0,<RPXUDB,RPXULP,RPXULB>)
EQUATE	(LOCAL,CPOPJ##,<RPXINI,RPXRLD,RPXEDL>)

	RPXICD==DSKICD##	;PROTOTYPE INTERRUPT CODE
	RPXICL==DSKICL##

	RPXUDB==0		;NO PROTOTYPE UDB
	RPXULN==UNIEBK+RPERNO	;LENGTH OF UDB

RPXDSP::DRVDSP	(RPX,DSKCHN##,DSKDDB##,DDBLEN##,DSKDIA##)

;DEFAULT MONGEN'ED DEVICE TABLE

DEFMDT:	MDKL10	(7,270,0,0,<MD.KON>)	;RH10 DEVICE CODE 270
	MDKL10	(7,274,0,0,<MD.KON>)	;RH10 DEVICE CODE 274
	MDKL10	(7,360,0,0,<MD.KON>)	;RH10 DEVICE CODE 360
	MDTERM				;TERMINATE TABLE

RPXCKT:	EXP	TYPRP,	0		;COMPATIBLE KONTROLLER TABLE
	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

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

;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
OM==1B35		;OFFSET MODE ON AN RM03

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
	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,(.DIDCR)	;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,(.DIDCR)	;SET FOR DATAO TO DESIRED CYL
RPXMOV:	PUSH	P,T2		;SAVE CYLINDER
	MOVSI	T2,(.DIOFS)	;CLEAR OFFSET REGISTER
	PUSHJ	P,DODTO
	MOVSI	T2,(.DIDAR)	;CLEAR POSSIBLE ILLEGAL
	PUSHJ	P,DODTO		; SECTOR FROM DESIRED ADR REG
	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
	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
	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 RPXEBK

;HERE TO ENABLE ATTEN INTERRUPTS
;HERE FROM RPXI11 WITH T1=RPXGON
ATNENB:	MOVEI	T4,DSKCHN##
	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
	PUSHJ	P,SETP14	;NO. SET UP IVI
	MOVSI	T1,200000	;ENABLE FOR ATTENS
	PJRST	ATNENB		;GIVE IT A PI AND EXIT
RPXLTM:	MOVE	T3,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	MOVEI	T4,3		;MAKE SURE WE DONT TRY TOO MUCH
	MOVSI	T2,<(.DILAR)>(T3) ;READ LOOK-AHEAD REGISTER
	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)
	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/RM03 - 556 PER SECTOR
	IMULI	T1,(T2)		;TIMES MICRO-SECS PER SECTOR
	PJRST	CPOPJ1##	;GOOD RETURN

RPXLT3:	SKIPE	P1
	PUSHJ	P,CLRRAE
	JRST	TPOPJ##
RPXRDF:	SKIPA	T1,[FNCRHD]	;READ HEADERS AND DATA
RPXWTF:	MOVEI	T1,FNCWTF	;WRITE HEADERS AND DATA (FORMAT)
	MOVE	T2,KONCNT(J)	;IF WRITING-READING HEADERS AND DATA
	LDB	T3,UNYUTP##	;GET UNIT TYPE
	CAIN	T3,2		;201 WORDS/SECTOR FOR RM03
	SKIPA	T3,[201]
	MOVEI	T3,202		;202 WORDS/SECTOR FOR RP04/6/7
	IDIV	T2,T3		;DIVIDE BY SECTOR SIZE
	SKIPE	T3		; FILIO COMPUTED CHNNUM ASED 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,UNYUTP##	;GET UNIT TYPE
	CAIN	T2,3		;SKIP UNLESS AN RP07
	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
	LDB	T4,UNYUTP##	;GET UNIT TYPE
	CAIN	T4,2		;RM03?
	JRST	RPXDG0		;YES
	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
	JRST	RPXD0A		;PROCEED

RPXDG0:	TLNE	T1,F22		;IF 22-SECTOR MODE,
	IDIVI	T3,^D32		;32 SECTORS/TRACK
	TLNN	T1,F22		;IF NOT 22-SECTOR MODE,
	IDIVI	T3,^D30		;30 SECTORS/TRACK
RPXD0A:	DPB	T3,[POINT 5,T4,27]	;SET T4 FOR DESIRED ADDRESS REGISTER
	HRLI	T2,(.DIDCR)	;SET DESIRED CYLINDER
	PUSHJ	P,DODTO
	MOVSI	T2,(.DIOFS)
	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
	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,KDBICP(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,(.DIDAR)	;SET TO DATAO THE RIGHT REGISTER
RPXGO:
	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
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE 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
	JFCL			;KL10 TIMING PROBLEM
	XCT	RPXCO4(J)	;TURN ON THE PI
	PJRST	CPOPJ1##	;AND SKIP RETURN
;ROUTINE TO SET UP THE INTERRUPT VECTOR ADDRESS FOR AN RH20
RPXIVI:	MOVEI	T2,40+DSKCHN##_1 ;CAUSE INTERRUPT AT 40+2N
	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:	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:	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:	MOVE	T1,UDBPDN(U)	;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
	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,RPXEBK+1(J)	;SET RH (T3) = STATUS
	HRL	T3,RPXEBK+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:	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?
	TRNN	T2,CI.BSY+CI.DON ;KONTROL BUSY OR DONE?
	JRST	CONEC1		;NO, ALL IS OK
	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
	XCT	RPXCI2(J)	;RESET T2 TO CONI
	MOVEI	T4,CO.STP+CO.MBE ;YES, CLEAR BUSY, SET DONE
	TRNE	T2,CI.BSY
	XCT	RPXCO4(J)
	AOS	UNIHNG(U)	;BUMP A COUNTER
	XCT	RPXCI2(J)	;CONI
	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
	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:	MOVSI	T2,(.DISNR)	;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,(.DISTR)	;SET TO READ DRIVE'S STATUS REGISTER
	PUSHJ	P,DODTI
	TRZ	T2,LST+PGM+OM	;DON'T CARE ABOUT LAST SECTOR TRANSFERRED
				; OR PGM OR OFFSET MODE
	CAIE	T2,GUDSTS	;DRIVE OK?
	JRST	CONERR		;NO
CONEC2:	MOVE	T2,UNIBLK(U)	;YES, GET DESIRED BLOCK
	LDB	T3,UNYBPY##	;BLOCKS PER CYLINDER
	TLNN	T1,F22		;SKIP IF 22-SECTOR MODE
	JRST	CONC2A		;NOT
	LDB	T3,UNYUTP##	;GET UNIT TYPE
	CAIE	T3,2		;SKIP IF AN RM03
	SKIPA	T3,[^D418]	;NOT AN RM03
	MOVEI	T3,^D160	;AN RM03
CONC2A:	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:	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,(.DISNR)	;WRITE A READ-ONLY REGISTER SO WILL GET
	PUSHJ	P,DODTO		; INTERRUPT ON RELEASE FROM OTHER PORT
	MOVSI	T2,(.DISTR)	;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:	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE 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,(.DISTR)	;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
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	PUSHJ	P,RDREG		;READ DRIVE REGISTERS
	PUSHJ	P,DVCLR		;NO, CLEAR THE DRIVE
	POP	P,T1
	MOVSI	T2,(.DISTR)	;READ STATUS REG
	PUSHJ	P,DODTI
	TRZ	T2,LST+PGM+OM
	CAIN	T2,GUDSTS	;DID DRIVE CLEAR FIX IT?
	JRST	CONER4		;YES, RETRY
	HRL	T2,RPXEBK+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


;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,RPXEBK(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:	MOVE	T3,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	TLOA	T2,(T3)		;SET TO READ IT
DODI4:	TLO	T2,(T4)
DODIC:	SKIPE	P1		;RH20?
	TLO	T2,(DO.DRE)	;YES, DONT INTERRUPT ON RAE
	XCT	RPXDO2(J)	;INDICATE WHICH REGISTER WE WANT
	PUSH	P,T2		;SAVE REGISTER WE WANT TO READ
	IMULI	T2,1		;WAIT (IN CASE RH10)
	XCT	RPXDI2(J)	;READ THE REGISTER
	JUMPE	P1,DODIX	;SKIP RAE TEST IF RH10
	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
;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:	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:	MOVE	T3,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	TLOA	T2,<(DO.LDR)>(T3) ;SET TO WRITE THE REGISTER
DODO4:	TLO	T2,<(DO.LDR)>(T4)
	SKIPE	P1		;RH20?
	TLO	T2,(DO.DRE)	;YES, DONT INTERRUPT ON RAE
	XCT	RPXDO2(J)	;ZAP
	JUMPE	P1,CPOPJ##	;SKIP RAE TEST IF RH10
	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
	$INIT

;CHECK FOR KONTROLLER UP
RPXUPA:	PUSHJ	P,SAVE2##
	SETOM	RPXFLG(J)
	PUSHJ	P,RPXSTW	;SET P1=0 IF RH10, =1 IF RH20
	MOVEI	T4,DSKCHN##	;GET PI CHANNEL
	SKIPE	P1		;IF AN RH20,
	TROA	T4,CO.RAE!CO.MBE!CO.AIE!CO.CCD	; CLEAR THESE BITS
	TRO	T4,RPALCL+40	;CLEAR ALL ERROR BITS, ATTEN ENABLE
	XCT	RPXCO4(J)	;CONO RPX,(T4)
	XCT	RPXCI2(J)	;CONI RPX,T2
	TDNN	T2,[EXP 2030,CI.DBP!CI.LWC!CI.DRE!CI.RAE!CI.OVR!CI.BSY](P1)
	TRNN	T2,7		;NO, PI UP?
	POPJ	P,		;DOWN
	PJSP	T1,CPOPJ1##	;UP, SET T1 NON-0 (WH LOCKOUT), AND RETURN

;CHECK HARDWARE WRITE PROTECT
RPXHWP:	PUSHJ	P,RPXSTW	;MASSBUS ENABLE IF AN RH20
	MOVSI	T2,(.DISTR)	;READ STATUS REGISTER
	PUSHJ	P,DODTI4
	TRNE	T2,WRL
	AOS	(P)		;WRITE LOCKED
	POPJ	P,		;RETURN

	$HIGH
;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
	MOVE	P1,KDBDVC(J)	;GET DEVICE CODE/4
	CAIL	P1,FSTICD/4	;RH20 DEVICE CODE?
	CAILE	P1,LSTICD/4
	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:	MOVEI	T4,CO.MBE+DSKCHN## ;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##
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	MOVEI	T2,FNCREL	;RELEASE
	PUSHJ	P,DODO4
	PJRST	CHKATN
>
;HERE ON INTERRUPT FOR A MASSBUS DISK
RPXINT:	PUSHJ	P,SETP1		;SET P1=0 OR 1 FOR RH10 OR 20
	MOVE	W,J		;SET UP KDB ADDRESS
	PUSHJ	P,SVMBR##	;SAVE CURRENT MBR FOR UUO LEVEL
	MOVSI	T2,(.DIASR)	;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?
	SKIPL	RPXGON(J)	;AND NO (POSSIBLE) POSTPONED ATTN INTERRUPTS
	JUMPE	T2,NOATTN	;NO
	HRLI	T2,(.DIASR!DO.LDR) ;YES, SET TO CLEAR WHAT WE READ
	PUSH	P,T2		;SAVE IT (CLEAR IF NO ERRORS LATER ON)
	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,(.DIASR)	;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,KDBIUN(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,KDBCHN(J)	;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,<(.DISTR)>(T4) ;THIS DRIVE INTERRUPTED
	PUSHJ	P,DODIC		;READ ITS STATUS REGISTER
	HRRZ	U,KDBIUN(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,<(.DIASR!DO.LDR)>(T4) ; (WILL INTERRUPT AGAIN FOR THE OTHERS)
	XCT	RPXDO2(J)	;CLEAR IT
	MOVSI	T2,(.DIER3)
	PUSHJ	P,DODI4		;IF SEEK INCOMPLETE IS ON
	TRNN	T2,SKI
	JRST	RPXIN3
	MOVSI	T2,(.DIERR)
	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:	MOVE	T2,BITTBL##(T4)	;TRANSLATE MASSBUS UNIT (DRIVE) TO BIT
	IORM	T2,RPXNUM(J)	;REMEMBER TO CONFIGURE LATER
	HRROS	KDBNUM(J)	;FLAG IT FOR THE REST OF THE WORLD TO SEE
	JRST	RPXIN8		;GO SEE IF OTHER ATTENTION BITS TO PROCESS
;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,<(.DISTR)>(T4) ;DID IT CLEAR?
	PUSHJ	P,DODIC
	TRNN	T2,ERR
	JRST	RPXI3Z		;YES
	MOVSI	T2,(.DIER3)	;NO, CLEAR IT THE HARD WAY
	PUSHJ	P,DODO4
	MOVSI	T2,(.DIER2)
	PUSHJ	P,DODO4
	MOVSI	T2,(.DIERR)
	PUSHJ	P,DODO4
	MOVSI	T2,<(.DISTR)>(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##
	MOVE	T2,.CPCPN##	;CPU
	SETZM	CLKMIN##(T2)
	SYSPIN
	POP	P,T2		;PRUNE STACK
	MOVEI	T2,CO.MBE+DSKCHN##
	XCT	RPXCO2(J)	;DISABLE ATTENTION INTERRUPTS
	PJRST	FILDN##		;TELL FILSER AND DISMISS
;HERE ONE SECOND LATER TO RE-ENABLE
RPXENB:	MOVE	J,UDBKDB(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
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,RPXDMX-1	;START AT HIGH-ORDER DRIVE
	LSHC	T2,-^D8
RPXI10:	JUMPGE	T3,RPXI11	;THIS DRIVE INTERRUPT?
	MOVSI	T2,(.DISTR)	;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,KDBIUN(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
>
	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:
	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
	SKIPL	RPXFNC(J)	;IF CALLED FROM RPXSTP
	JRST	[MOVE U,KONCUA(J)
		 SKIPL UNILAS(U) ;IF DRIVE WAS ON OTHER PORT
		 MOVE T4,UDBPDN(U) ; 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,<(.DIOFS!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,(.DISTR)	;READ THE DRIVE STATUS REGISTER
	PUSHJ	P,DODI4
	MOVE	T1,T2		;SAVE STATUS
	MOVSI	T2,(.DIERR)	;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
	JUMPE	P1,DATIN2	;EASY IF RH10
	MOVE	T1,KDBICP(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:	MOVEI	T4,DSKCHN##	;GET PI CHAN
	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
	TDNN	T2,[CHNERR
		CS.MPE!CS.NXM!CS.OVR](P1)
	JRST	ERROR1		;NO
	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
	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,RPXEBK+16(J)	;GET POSITION
	SOJL	T1,CPOPJ##	;ERROR IF 0
;THE FIRE CODE IN THE MASSBUS DISKS CAN GENERATE THE WRONG ECC CORRECTION.
;STATISTICALLY, THIS ONLY HAPPENS FOR AN ERROR ENVELOPE OF GREATER THAN
;FOUR BITS.  THIS CODE COUNTS THE WIDTH OF THE MASK AND DECLARES THE ERROR
;NON-ECC CORRECTABLE IF THE CORRECTION PART OF THE MASK IS WIDER THAN THIS.
	MOVE	T2,RPXEBK+17(J)	;GET PATTERN
	JFFO	T2,.+1		;FIND FIRST BIT OF PATTERN
	MOVE	T4,T3		;PRESERVE NUMBER OF FIRST BIT IN PATTERN
	TDZ	T2,BITTBL##(T3)	;WIPE OUT THAT BIT
RPXEC8:	JUMPE	T2,RPXEC9	;JUMP WHEN PATTERN IS ZERO
	JFFO	T2,.+1		;FIND NEXT BIT OF PATTERN
	TDZ	T2,BITTBL##(T3)	;WIPE OUT THAT BIT
	JRST	RPXEC8		;LOOK FOR ANOTHER
RPXEC9:	SUB	T3,T4		;GET WIDTH-1 OF PATTERN
	CAILE	T3,4-1		;IS PATTERN LESS THAN/EQUAL TO FOUR BITS WIDE?
	POPJ	P,		;NO, THEN IT IS NOT ECC CORRECTABLE
;HERE IF THE ERROR IS TRULY ECC CORRECTABLE.
	MOVE	T4,RPXEBK+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,(.DIOFS)	;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,(.DIOFS)	; 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,(.DIASR)	;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,(.DIASR!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
	PUSHJ	P,SETP1
	SOJN	T1,RPXER1	;IF FIRST ERROR,
	MOVSI	T2,(.DISTR)	;READ DRIVE'S STATUS REGISTER
	PUSHJ	P,DODTI
	TRNE	T2,OM		;OFFSET RM03?
	JRST	RPXER0		;YES
	MOVSI	T2,(.DIOFS)	;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
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)
	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,(.DIOFS)	;SET TO DO OFFSET
	MOVEI	T1,FNCOFS	;FUNCTION = OFFSET
	TRNE	T2,-1		;IS THIS OFFSET=0?
	JRST	RPXR2A		;NO--GO DO IT
	MOVE	T2,RPXEBK+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
;HERE TO CHECK CAPACITY & STATUS OF RH10/RP04
RPXCPY:	PUSHJ	P,SETP1		;DO MASSBUS ENABLE IF RH20, SET UP P1
;*** PROBABLY STILL NEEDED SINCE SOMEONE CAN TWIDDLE LAP PLUG
;*** AND CHANGE AN RM03 INTO AN RP06 AND VICE VERSA?
	MOVSI	T2,(.DIDTR)	;READ DRIVE-TYPE REGISTER
	PUSHJ	P,DODTI4
	LDB	T3,[POINT 9,T2,35] ;GET DRIVE TYPE CODE
	CAIN	T3,TY.RP5	;RP05?
	MOVEI	T3,TY.RP4	;YES, JUST CALL IT AN RP04
	CAIN	T3,TY.RM2	;RM02?
	MOVEI	T3,TY.RM3	;IT'S A SLOW RM03
	MOVSI	T4,-TYPTBL	;-VE LENGTH OF DRIVE TYPE TABLE
	MOVE	T1,TYPTAB(T4)	;GET AN ENTRY
	CAIE	T3,(T1)		;DRIVE TYPES MATCH?
	AOBJN	T4,.-2		;NO, LOOP FOR A MATCH
	JUMPGE	T4,RPXCP5	;NOT A LEGAL UNIT TYPE, NO SUCH DRIVE
	HRRZS	T4		;ISOLATE UNIT TYPE INDEX
	MOVEM	T2,UNIEBK+6(U)	;SAVE DRIVE TYPE REGISTER FOR SYSERR
	MOVSI	T2,(.DISTR)	;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
	MOVE	T4,UDBPDN(U)	; SO DO A PACK ACKNOWLEDGE
	PUSHJ	P,NOWUP		; SO THAT RELEASE WILL WORK
	POP	P,T4
RPXCP3:>
	MOVSI	T2,(.DISNR)	;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,UDBDSN+1(U)	;RETURN SN IN UNISER
> ;END IFN FTDUAL
	AOSA	(P)		;SET FOR SKIP RETURN
RPXCP4:	MOVSI	T4,KOPUHE+KOPNSU ;OFF LINE OR DOWN
	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,BLKPTC(T4)	;BLKS PER TRK,, BLKS PER CYL
	JRST	RPXCP6		;CLEAR POSSIBLE RAE AND EXIT

RPXCP5:	PUSHJ	P,CLRRAE	;CLEAR RAE
	MOVSI	T4,KOPUHE+KOPNSU ;OFF LINE OR DOWN
	SETZB	T1,T2		;NO BLOCKS PGR UNIT - CANT READ
RPXCP6:
IFE FTDUAL,<
	JUMPE	P1,CPOPJ##	;NO SWEAT IF AN RH10
>
IFN FTDUAL,<
	JUMPE	P1,RLESE
>
	PUSH	P,T4		;PRESERVE T4
	PUSH	P,T3		;SAVE T3
	PUSH	P,T2		;SAVE T2
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	MOVEI	T2,1
	LSH	T2,(T4)		;POSITION BIT TO CLEAR ATTN-SUMMARY REG
	HRLI	T2,(.DIASR!DO.DRE!DO.LDR)
	XCT	RPXDO2(J)	; WHICH MIGHT BE ON
IFN FTDUAL,<
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	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
	POP	P,T3
	PJRST	T4POPJ##	;RESTORE T4 AND RETURN
;ENTRY TO READ DRIVE REGS
RPXREG:	PUSHJ	P,SETP1		;MASSBUS ENABLE IF RH20
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	PUSHJ	P,RDREG		;READ REGS
IFE FTDUAL,<
	POPJ	P,		;RETURN
>
IFN FTDUAL,<
	MOVE	T2,RPXEBK+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,RPXEBK(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
	MOVE	T2,[DOCRC,,	;OR RH20 PTCR
		    .DOPTC](P1)
	PUSHJ	P,DODTIC
	MOVEM	T2,KONECR(J)	;SAVE IN KDB
	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
;TABLES INDEXED BY UNIT TYPE CODE

;DRIVE TYPE

TYPTAB:	TY.RP4			;RP04 (RP05 KLUDGED THE SAME)
	TY.RP6			;RP06
	TY.RM3			;RM03
	1B0+TY.RP7		;RP07 (NON-REMOVABLE MEDIA)
	TY.RM5			;RM05
	1B0+TY.RM8		;RM80 (NON-REMOVABLE MEDIA)
TYPTBL==.-TYPTAB		;LENGTH OF TABLE

;BLOCKS PER UNIT

BLKPRU:	DEC	154280		;(RP04/05) 406 CYLINDERS
	DEC	307800		;(RP06) 810 CYLINDERS
	DEC	123150		;(RM03) 821 CYLINDERS
	DEC	865504		;(RP07) 629 CYL, 32 SURF, 43 SECT
	DEC	467970		;(RM05) 821 CYL, 19 SURF, 20 SECT
	DEC	234780		;(RM80) 559 CYL, 14 SURF, 30 SECT

;BLOCKS PER UNIT IN MAINTENANCE MODE

BLKPUM:	DEC	156180		;(RP04/RP05) 411 CYLINDERS
	DEC	309700		;(RP06) 815 CYLINDERS
	DEC	123450		;(RM03) 823 CYLINDERS
	DEC	866880		;(RP07) 630 CYLINDERS
	DEC	469110		;(RM05) 815 CYLINDERS
	DEC	235620		;(RM80) 561 CYLINDERS

;BLOCKS PER UNIT IN COMPATIBILITY MODE

BLKPUC:	DEC	171798		;(RP04/RP05) 22*19*411
	DEC	340670		;(RP06) 22*19*815
	DEC	131680		;(RM03) 32*5*823
	0			;(RP07) NO COMPATIBILITY MODE
	DEC	500384		;(RM05) 32*19*815
	DEC	243474		;(RM80) 31*14*561

;BLOCKS PER TRACK,,BLOCKS PER CYLINDER

BLKPTC:	XWD	^D20,^D380	;(RP04)
	XWD	^D20,^D380	;(RP06)
	XWD	^D30,^D150	;(RM03)
	XWD	^D43,^D1376	;(RP07)
	XWD	^D30,^D570	;(RM05)
	XWD	^D30,^D420	;(RM80)
	SUBTTL	AUTOCONFIGURATION

;ENTERED WITH DEVICE CODE/4 IN T1, AND CONI DEV, IN T2

RPXCFG:	CAIL	T1,FSTICD/4	;RH20?
	CAILE	T1,LSTICD/4
	JRST	RPXCF1		;NO, MIGHT BE RH10
	TLNE	T2,(CI.PPT)	;BETTER NOT BE IPA CHANNEL
	JRST	CPOPJ1##	;SORRY, I'M NOT INTERESTED
	MOVSI	T1,CP.RH2	;GET CHANNEL TYPE BITS FOR RH20
	JRST	RPXCF2		;GO BUILD CHN/KDB AND UNITS

RPXCF1:	TLNE	T2,(SI.SAX)	;SA10 CHANNEL?
	JRST	CPOPJ1##	;IGNORE IT
	XMOVEI	T1,RPXMDT##	;MONGEN'ED DEVICE TABLE
	XMOVEI	T2,DEFMDT	;DEFAULT TABLE
	MOVSI	T3,-1		;MATCH ON ANY MASSBUS UNIT
	MOVEI	T4,MD.KON	;MATCH ON KONTROLLER DEFINITION
	PUSHJ	P,AUTMDT##	;SCAN THE TABLES
	  JRST	CPOPJ1##	;NO MATCHES
	XCT	.CPCNI##	;GET CONI ,T1
	TLNN	T1,4000		;CHECK FOR DF10 OR DF10C IN 18-BIT MODE
	JRST	AUTEBD##	;18-BIT DF10/DF10C, INFORM OF ERROR AND RETURN
	MOVSI	T1,0		;GET CHANNEL TYPE BITS FOR RH10
RPXCF2:	PUSHJ	P,AUTCHN##	;BUILD A CHANNEL DATA BLOCK
	  POPJ	P,		;NO CORE
	PUSHJ	P,SAVE1##	;FREE UP P1
	SETZB	J,P1		;NO KDB YET, START WITH MASSBUS UNIT 0

RPXCF3:	PUSHJ	P,RPXUNI	;CONFIGURE A SINGLE UNIT
	  JFCL			;IGNORE ERRORS
	AOBJN	P1,.+1		;ADVANCE TO NEXT UNIT
	HLLZS	P1		;KEEP JUST MASSBUS UNIT NUMBER
	TLNN	P1,10		;DONE THEM ALL?
	JRST	RPXCF3		;NO, DO ANOTHER
	SKIPN	J		;HAVE A KDB?
	AOS	(P)		;NO--SO CHECK WITH OTHER DRIVERS
	POPJ	P,		;RETURN
;HERE TO CONFIGURE A SINGLE NEW UNIT

RPXUNI:	JUMPE	J,RPXUN1	;SKIP TEST IF NO KDB YET
	HLRZ	T1,P1		;GET UNIT
	MOVE	T1,BITTBL##(T1)	;AND IT'S BIT
	TDNE	T1,RPXIUM(J)	;WANT TO IGNORE THIS DRIVE?
	POPJ	P,		;SAY IT DOESN'T EXIST
RPXUN1:	MOVE	W,J		;AUTCON WANTS W SETUP
	PUSHJ	P,RDDTR##	;READ DRIVE TYPE REGISTER
	CAIN	T2,TY.RP5	;RP05?
	MOVEI	T2,TY.RP4	;YES, JUST CALL IT AN RP04
	CAIN	T3,TY.RM2	;RM02?
	MOVEI	T3,TY.RM3	;IT'S A SLOW RM03
	MOVSI	T1,-TYPTBL	;-VE LENGTH OF DRIVE TYPE TABLE
	MOVE	T3,TYPTAB(T1)	;GET AN ENTRY
	CAIE	T2,(T3)		;DRIVE TYPES MATCH?
	AOBJN	T1,.-2		;NO, LOOP FOR A MATCH
	JUMPGE	T1,RPXUN4	;IGNORE THIS UNIT IF UNKNOWN TYPE
	MOVE	T2,T1		;COPY TYPTAB INDEX (UNIT TYPE CODE, UNYUTP)
	HLL	T2,TYPTAB(T1)	;COPY UNIT TYPE FLAGS
	HLLZ	T1,P1		;COPY UNIT NUMBER
	HLRS	T1		;ALSO USE AS UDB TABLE OFFSET
	JUMPN	J,RPXUN3	;IF WE ALREADY HAVE A KDB, PROCEED
	PUSH	P,T1		;SAVE THE USEFUL ACS
	PUSH	P,T2
	MOVNI	T1,1		;NO MASSBUS UNIT NUMBER
	MOVEI	T2,TYPRP	;KONTROLLER TYPE CODE
	PUSHJ	P,DSKKON##	;BUILD A KONTROLLER DATA BLOCK
	  JRST	TTPOPJ##	;NO CORE
	MOVSI	T1,-<RPXIOE-RPXIOB> ;NUMBER OF WORDS TO CHECK
	XMOVEI	T2,RPXIOB(J)	;STARTING WORD
	HRRZ	T3,.CPDVC##	;<DEVICE CODE>/4
	PUSHJ	P,AUTDVC##	;SET DEVICE CODES
	MOVE	T1,.CPCHA##	;GET CHANNEL DATA BLOCK ADDRESS
	MOVE	T1,CHNTYP(T1)	;GET CHANNEL TYPE BITS
	TLNE	T1,CP.RH2	;RH20?
	SKIPA	T2,[CI.RAE!CI.ATN!CI.DON] ;YES, GET INTERRUPT FLAGS FOR RH20
				;*** NEED SYMBOL - CBOV, RAE, ATTN, DONE
	MOVEI	T2,350		;NO, GET INTERRUPT FLAGS FOR RH10
	MOVE	T3,KDBCSO(J)	;GET ADDRESS OF CONSO SKIP CHAIN
	HRRM	T2,DICDIF##(T3)	;SET CORRECT INTERRUPT FLAGS
	TLNN	T1,CP.RH2	;RH20?
	JRST	RPXUN2		;NO
	HRRZ	T1,.CPDVC##	;GET DEVICE CODE/4
	MOVE	T2,[CONSZ 0,CI.RAE!CI.AIE!CI.DON] ;CONSZ TEST FOR ATTN INTS
	DPB	T1,[POINT 7,T2,9] ;PLUG IN THE DEVICE CODE
	MOVEM	T2,DICDAE##(T3)	;NO, NEUTER TEST ON ATTN INTERRUPTS DISABLED
RPXUN2:	POP	P,T2		;RESTORE THE ACS
	POP	P,T1
RPXUN3:	PUSHJ	P,DSKDRV##	;BUILD AND LINK THE UDB
	  JRST	RPXUN4		;NO CORE
	MOVSI	T2,(.DISNR)	;READ SERIAL NUMBER REGISTER
	PUSHJ	P,RDMBR##
	SETZ	T1,		;REALLY A ONE-WORD QUANTITY
	MOVE	T3,UDBPDN(U)	;GET PHYSICAL DRIVE NUMBER
	PUSHJ	P,AUTDSN##	;FAKE UP S/N IF A ZERO
	DMOVEM	T1,UDBDSN(U)	;SET SERIAL NUMBER IN UDB
	JRST	CPOPJ1##	;RETURN

RPXUN4:	SETZ	U,		;INDICATE NO UDB
	POPJ	P,		;RETURN
;ONCE A SECOND CODE
RPXSEC:	SKIPL	@KDBCHN(J)	;CHANNEL BUSY?
	POPJ	P,		;LEAVE IT ALONE
	SKIPE	T1,RPXNUM(J)	;GET BIT MASK
	JFFO	T1,RPXSE1	;FIND FIRST UNIT NUMBER
	HRRZS	KDBNUM(J)	;INDICATE NO DRIVES TO CONFIGURE
	POPJ	P,		;DONE
RPXSE1:	PUSHJ	P,AUTLOK##	;GET AUTCON INTERLOCK
	  POPJ	P,		;TRY AGAIN NEXT TIME
	PUSHJ	P,SAVW##	;PRESERVE W
	MOVE	W,J		;COPY KDB ADDRESS TO W FOR AUTCON
	MOVSS	T2		;MASSBUS UNIT = DRIVE NUMBER FOR RPX DISKS
	PUSH	P,T2		;SAVE
	MOVE	T1,KDBDVC(J)	;DEVICE CODE
	XMOVEI	T2,RPXDSP	;DISPATCH
	MOVE	T3,KDBCHN(J)	;CHANNEL DATA BLOCK
	PUSHJ	P,AUTSET##	;SET UP CPU VARIABLES
	EXCH	P1,(P)		;SAVE P1, GET MASSBUS UNIT
	PUSH	P,KDBUNI(J)	;SAVE KDBUNI
	MOVEM	P1,KDBUNI(J)	;SET FOR THIS MASSBUS UNIT NUMBER (FOR RDMBR)
	PUSHJ	P,RPXUNI	;CONFIGURE A NEW UNIT
	  JFCL			;IGNORE ERRORS
	PUSHJ	P,AUTULK##	;RELEASE AUTCON INTERLOCK
	POP	P,KDBUNI(J)	;RESTORE KDBUNI
	PJRST	P1POPJ##	;RESTORE P1 AND RETURN
	$LIT
RPXEND:	END