Google
 

Trailing-Edge - PDP-10 Archives - BB-JR93L-BB_1990 - 10,7/mon/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  V044
SUBTTL  J EVERETT/JE/DBD	17 APR 90

	SEARCH	F,S,DEVPRM
	$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
; 1978,1979,1980,1982,1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1978,1990>


XP VRHKON,044
;TRACKS VERSION 147 OF RPXKON

RPXKON::ENTRY	RPXKON		;*** SO KS LINKS

RHXKON::ENTRY	RHXKON
	SUBTTL	AUTOCONFIGURATION TABLES

;NOTE:	KONTROLLER SERVICE ROUTINE IS CALLED RHXKON EVEN THOUGH
;	THE UNITS ARE REFERRED TO AS RP'S TO CONFORM WITH RH10,
;	RH20 IMPLEMENTATION.

;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
RPXFNC:!BLOCK	1		;LAST DATA XFER FUNCTION
				; BIT 0 = OFF IF DSK HUNG, ON IF EVERYTHING OK
				; BITS 15-17 = UNIT NUMBER COMMAND ISSUED TO
				; BITS 30-35 = FUNCTION CODE
RPXFLG:!BLOCK	1		;DATA XFER IN-PROGRESS FLAG
				; -1 = CONTROLLER IDLE
				; 0 = XFER IN-PROGRESS, STOP ON ERROR
				; 1 = XFER IN-PROGRESS, DON'T STOP ON ERROR

RPXIUM:! BLOCK	RPXDMW		;IGNORE DRIVE MASK
RPXNUM:! BLOCK	RPXDMW		;NEW DRIVE MASK
RPXKLN:!			;LENGTH OF KDB
	.ORG

;PROTOTYPE KDB
RPXKDB:	XXKON	(RP)
	SETWRD	(RPXFLG,<-1>)
	KDBEND

	RPXCCM==CYLCM##

EQUATE	(LOCAL,0,<RPXUDB,RPXULP,RPXULB>)
EQUATE	(LOCAL,CPOPJ##,<RPXALV,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:	MDKS10	(7,RH11IV,RH11CA,0,0,<MD.KON>)
	MDTERM

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

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

;RH11 REGISTER OFFSETS

.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
SUBTTL	FILSER CALL PROCESSING

RPXUNL::SKIPA	T1,[FNCUNL]	;UNLOAD
RPXRCL::MOVEI	T1,FNCRCL	;RECAL
	PUSHJ	P,SAVE1##	;PRESERVE AN AC
	MOVE	P1,KDBDVC(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,KDBDVC(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,KDBDVC(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 RPXEBK
	POPJ	P,
RPXLTM::PUSHJ	P,SAVE1##	;PRESERVE AN AC
	MOVE	P1,KDBDVC(J)	;SET UP RH11 BASE ADDRESS
	MOVE	T3,UDBPDN(U)	;PHYSICAL DRIVE 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,KDBDVC(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,KDBCHN(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
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	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,RPXEBK+1(J)	;SET RH(T3)=DRIVE STATUS
	HRL	T3,RPXEBK+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:	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE 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:	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
	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,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

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 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,KDBDVC(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,KDBIUN(J)	;SET UP U TO UDB
	ADDI	U,(T4)
	SKIPN	U,(U)		;SET UP U TO UDB
	JRST	RPXIN6		;NEW UNIT - BUILD A UDB FOR IT
	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,KDBICP(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,KDBCHN(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
;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	RPXIN4		;GO SEE IF OTHER ATTENTION BITS TO PROCESS
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.NEX!CS.DLT ;CHANNEL-TYPE PROBLEM?
	JRST	ERROR1		;NO--GO ON
	TRNE	T4,CS.DLT	;DATA LATE?
	TRO	S,IOVRUN	;YES
	MOVE	T1,KDBCHN(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
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE 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,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]	;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,KDBDVC(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,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		;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,KDBDVC(J)	;SET UP RH11 BASE ADDRESS
	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE 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
	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
	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,RPXCP4	;NOT A LEGAL UNIT TYPE, NO SUCH DRIVE
	HRRZS	T4		;ISOLATE UNIT TYPE INDEX
	MOVEM	T2,UNIEBK+6(U)	;SAVE FOR SYSERR
	RDIO	T2,.DOSR(W)	;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
	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
	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,
	$INIT

;CHECK FOR KONTROLLER UP
RPXUPA:	MOVE	T1,KDBDVC(J)	;GET BASE ADDRESS OF I/O REGISTERS
	PUSHJ	P,UBGOOD##	;IS RH11 ALIVE ?
	  POPJ	P,		;NO - RETURN OFF LINE
	SETOM	RPXFLG(J)	;SET CONTROLLER IDLE
	MOVE	P1,KDBCHN(J)	;CHANNEL DATA BLOCK
	MOVE	W,KDBDVC(J)	;GET RH11 BASE ADDRESS
	MOVEI	T4,CS.CLR	;CONTROLLER CLEAR BIT
	WRIO	T4,.DOCS2(W)	;WRITE CONTROLLER STATUS REGISTER
	MOVEI	T4,CS.OR	;READY BIT
	TION	T4,(W)		;SHOULD BE ON
	POPJ	P,		;NOT READY, ASSUME DOWN
	PJSP	T1,CPOPJ1##	;GOOD RETURN

;CHECK HARDWARE WRITE PROTECT
RPXHWP:	MOVE	W,KDBDVC(J)	;SET RH11 BASE ADDRESS
	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	WRIO	T2,.DOCS2(W)	;SELECT UNIT
	RDIO	T2,.DOSR(W)	;GET STATUS REGISTER
	TRNE	T2,DS.WRL	;WRITE PROTECTED?
	AOS	(P)		;YES-SKIP RETURN
	POPJ	P,		;RETURN

	$HIGH
;ENTRY TO READ DRIVE REGS
RPXREG::PUSHJ	P,SAVE1##	;GET A REGISTER
	MOVE	P1,KDBDVC(J)	;AND SET UP RH11 BASE ADDRESS
	PUSH	P,U		;RDREG WIPES U
	MOVE	T4,UDBPDN(U)	;PHYSICAL 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,RPXEBK(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,KDBCHN(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
	SUBTTL	AUTOCONFIGURATION

RPXCFG:	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
	MOVSI	T1,CP.R11	;GET CHANNEL BITS
	PUSHJ	P,AUTCHN##	;BUILD A CHANNEL DATA BLOCK
	  POPJ	P,		;NO CORE
	LDB	T1,[POINT 3,.CPDVC##,17] ;GET UNIBUS ADAPTER NUMBER
	MOVEI	T2,UBAPGS	;NUMBER OF MAPPING REGISTERS REQUIRED
	PUSHJ	P,AUTAMR##	;ALLOCATE UNIBUS MAPPING REGISTERS
	  POPJ	P,		;NONE AVAILABLE
	PUSHJ	P,SAVE1##	;FREE UP P1
	MOVE	P1,.CPCHA##	;GET CHANNEL DATA BLOCK ADDRESS
	MOVEM	T1,CHNIMR(P1)	;STORE INITIAL UNIBUS MAPPING REGISTER
	MOVEM	T2,CHNMRC(P1)	;STORE NUMBER OF MAPPING REGISTERS
	MOVEM	T3,CHNIEA(P1)	;STORE INITIAL ELEVEN ADDRESS
	SETZB	J,P1		;NO KDB YET, START WITH MASSBUS UNIT 0

RPXCF1:	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	RPXCF1		;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
;P1 = UNIT NUMBER,,0

RPXUNI:	JUMPE	J,RPXUN1	;SKIP TEST IF NO KDB YET
	HRRZ	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 SET UP
	PUSHJ	P,RDDTR##	;READ DRIVE TYPE REGISTER
	CAIN	T2,TY.RP5	;RP05?
	MOVEI	T2,TY.RP4	;YES, JUST CALL IT AN RP04
	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,RPXUN3	;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,RPXUN2	;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
	POP	P,T2		;RESTORE THE ACS
	POP	P,T1
RPXUN2:	PUSHJ	P,DSKDRV##	;BUILD AND LINK THE UDB
	  JRST	RPXUN3		;NO CORE
	MOVSI	T2,.DOSN	;SERIAL NUMBER REGISTER
	PUSHJ	P,RDMBR##	;READ IT
	SETZ	T1,		;REALLY A ONE-WORD QUANTITY
	MOVE	T3,UDBDSN(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

RPXUN3:	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)	;COPY UNIBUS ADDRESS
	MOVEI	T2,RH11IV/4	;GET IVI
	DPB	T2,[POINT 7,T1,9] ;STUFF IT
	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
;TABLES INDEXED BY UNIT TYPE CODE
;0 = RP04/RP05, 1 = RP06, 2 = RM03, 3 = RP07

;DRIVE TYPE

TYPTAB:	TY.RP4			;RP04 (RP05 KLUDGED THE SAME)
	TY.RP6			;RP06
	TY.RM3			;RM03
	1B0+TY.RP7		;RP07 (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

;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

;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

;BLOCKS PER TRACK,,BLOCKS PER CYLINDER

BLKPTC:	XWD	^D20,^D380	;(RP04)
	XWD	^D20,^D380	;(RP06)
	XWD	^D30,^D150	;(RM03)
	XWD	^D43,^D1376	;(RP07)
	SUBTTL	THE END

	$LIT
RPXEND:	END