Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93k-bb - 10,7/mon/rnxkon.mac
There are 8 other files named rnxkon.mac in the archive. Click here to see a list.
TITLE	RNXKON -- DRIVER FOR RP20'S  V074
SUBTTL	G.M. UHLER/GMU   25-APRIL-89

	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 1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1980,1988>


XP VRNKON,074
SALL

RNXKON::ENTRY	RNXKON


;NOTE THAT LABELS OF THE FORM RNXBP? ARE USED BY THE RP20 TRACE
;PROGRAM FOR SNOOP. BREAKPOINTS.  DO NOT REMOVE THESE LABELS.


;TECHNICAL INFORMATION AND TECHNIQUES FOR PROGRAMMING THE
;RH20/DX20/RP20 ARE AVAILABLE IN THE FOLLOWING DOCUMENTS:
;
;  FUNCTIONAL SPECIFICATION FOR DX20-V210 MICRO CODE,
;	AUG 79
;  DX20 PROGRAMMED DEVICE ADAPTER TECHNICAL MANUAL,
;	DOCUMENT NUMBER EK-0DX20-TM-001, FEB 78
;  RH20 MASSBUS CONTROLLER UNIT DESCRIPTION,
;	DOCUMENT NUMBER EK-RH20-UD-001, AUG 76
;  DX20-V210 RP20 DISK SUBSYSTEM MICRO-CODE,
;	DOCUMENT NUMBER MAINDEC-10-DXMCD-A, AUG 79
	SUBTTL	RH20/DX20 DEVICE DEPENDENT REGISTER/BIT DEFINITIONS


.DXCTR==00B5			;CONTROL REGISTER
	CR.IGN==1B14		;BIT SET IN UNILAS TO INDICATE THAT THIS
				; COMMAND WAS TOSSED
	CR.FNC==76B35		;FUNCTION CODE
		.CRNOP==01	;NO-OP
		.CRRCL==07	;RECALIBRATE
		.CRSRC==31	;SEARCH
		.CRWRT==61	;WRITE DATA
		.CRWTF==63	;WRITE FORMAT
		.CRRED==71	;READ DATA
		.CRRDF==73	;READ FORMAT
	CR.IOP==40B35		;BITS TELLING THAT THIS OPERATION WAS
				;  AN I/O FUNCTION
	CR.RED==10B35		;BIT TELLING THAT THIS I/O OPERATION WAS
				;  A READ
	CR.GO==1B35		;GO BIT

.DXSTR==01B5			;STATUS REGISTER
	ST.CER==1B21		;COMPOSITE ERROR
	ST.RUN==1B23		;MICROPROCESSOR RUNNING

.DXERR==02B5			;ERROR REGISTER
	ER.SCC==17B23		;ERROR SUB CLASS CODE
	ER.ECC==17B27		;ERROR CLASS CODE
		.ERSEL==3	;DEVICE SELECT ERROR
	ER.UPE==1B28		;MICROPROCESSOR ERROR
	ER.STP==1B29		;MICROPROCESSOR STOPPED
	ER.MPE==1B30		;MICRO BUS PARITY ERROR
	ER.DPE==1B31		;DATA BUS PARITY ERROR
	ER.CPE==1B32		;CONTROL BUS PARITY ERROR
	ER.RMR==1B33		;REGISTER MODIFICATION REFUSED
	ER.ILR==1B34		;ILLEGAL REGISTER
	ER.ILF==1B35		;ILLEGAL FUNCTION
	ER.ERR==ER.MPE!ER.DPE!ER.CPE!ER.RMR!ER.ILR!ER.ILF

.DXMTR==03B5			;MAINTENANCE REGISTER
	MR.SCY==1B31		;MICROPROCESSOR SINGLE CYCLE
	MR.STR==1B33		;MICROPROCESSOR START
	MR.RES==1B34		;MICROPROCESSOR RESET

.DXASR==04B5			;ATTENTION SUMMARY REGISTER
	AT.ATN==377B35		;THE ATTENTION BITS

.DXDAR==05B5			;DESIRED ADDRESS REGISTER (TRACK/SECTOR)
	DA.TRK==377B27		;TRACK
	DA.SEC==377B35		;SECTOR
.DXDTR==06B5			;DRIVE TYPE REGISTER
	DT.COD==777B35		;DRIVE TYPE
		.DTCOD==061	;CODE FOR DX20

.DXESR==20B5			;ENDING STATUS REGISTER
	ES.STM==1B21		;STATUS MODIFIER
	ES.CUE==1B22		;CONTROL UNIT END
	ES.BSY==1B23		;BUSY
	ES.CHE==1B24		;CHANNEL END
	ES.DVE==1B25		;DEVICE END
	ES.UCK==1B26		;UNIT CHECK
	ES.UEX==1B27		;UNIT EXCEPTION
	ES.SUI==1B28		;STATUS UPDATE INTERLOCK
	ES.IDX==177B35		;STATUS INDEX
		.ESSB0==0	;INDEX TO GET SENSE BYTE 0(-3)
		.ESSB7==1	;INDEX TO GET SENSE BYTE (4-)7

.DXASY==21B5			;ASYNCHRONOUS STATUS REGISTER
	AS.DVS==377B27		;DRIVE STATUS
	AS.DRV==377B35		;DRIVE NUMBER
	AS.UNF==17B35		;UNIT NUMBER

.DXFLG==22B5			;FLAGS/ARGUMENT
	FA.RTY==1B23		;COMMAND RETRY
	FA.FNC==377B35		;FUNCTION FOR SENSE/NOOP
		.FATIO==0	;CODE FOR TEST I/O

.DXDNM==23B5			;DRIVE NUMBER REGISTER
	DN.CUA==17B31		;CONTROL UNIT ADDRESS
	DN.DRV==17B35		;DRIVE NUMBER

.DXDCR==24B5			;DESIRED CYLINDER REGISTER

.DXES1==26B5			;EXTENDED STATUS REGISTER 1

.DXES2==27B5			;EXTENDED STATUS REGISTER 2

.DXMIR==30B5			;MICROCONTROLLER INSTRUCTION REGISTER

.DXPCR==31B5			;MICROPROCESSOR PC REGISTER
	PC.IRE==1B20		;INSTRUCTION REGISTER ENABLE
	PC.MSE==1B21		;MICROSTORE ENABLE
	PC.PCE==1B22		;PC ENABLE
	PC.PCI==1B23		;PC AUTO INCREMENT
	PC.MPC==7777B35		;MICROPROCESSOR PC

.DXIPE==37B5			;DIAGNOSTIC REGISTER 7
	DX.IPE==1B22		;INSTRUCTION REGISTER PARITY ERROR
;SENSE BYTE DEFINITIONS

S0.CRJ==1B2		;COMMAND REJECT
S0.IRQ==1B3		;INTERVENTION REQUIRED
S0.BOP==1B4		;CHANNEL BUS OUT PARITY
S0.EQC==1B5		;EQUIPMENT CHECK
S0.DTC==1B6		;DATA CHECK
S0.OVR==1B7		;OVERRUN
S1.PER==1B10		;PERMANENT ERROR
S1.ITF==1B11		;INVALID TRACK FORMAT
S1.ECY==1B12		;END OF CYLINDER
S1.NRF==1B14		;NO RECORD FOUND
S1.FPR==1B15		;FILE PROTECTED
S1.WRI==1B16		;WRITE INHIBITED
S1.OPI==1B17		;OPERATION INCOMPLETE


DEFINE	HEX(SYM,VAL),<
	SYM==0
	IRPC VAL,<
	  SYM==SYM*^D16
	  IFLE <"VAL"-"9">,<SYM==SYM+"VAL"-"0">
	  IFG  <"VAL"-"9">,<SYM==SYM+"VAL"-"A"+^D10>
	>
>

HEX(.S7ECC,53)		;SENSE BYTE 7 CODE INDICATING ECC RECOVERABLE ERROR


;RH20 CONI/CONO/LOGOUT AREA BIT DEFINITIONS

CI.ERR==CI.DBP!CI.LWC!CI.DRE!CI.RAE!CI.OVR
			;ALL CONI ERROR BITS
CO.CLR==CO.RAE!CO.TEC!CO.CCD	;CONO BITS TO CLEAR ERRORS
CS.ERR==CS.MPE!CS.NAE!CS.NXM!CS.RHE!CS.LWC!CS.SWC!CS.OVR
			;ALL CHANNEL LOGOUT AREA ERROR BITS
	SUBTTL	RNXEBK/UNIEBK BLOCK OFFSETS


;OFFSETS IN THE RNXEBK AND UNIEBK BLOCKS FOR THE RP20.  DAEMON KNOWS
;ABOUT THESE OFFSETS SO IF YOU CHANGE THEM, BE SURE TO CHANGE DAEMON
;ALSO.  IF YOU CHANGE THE LENGTH OF THIS BLOCK, YOU MUST ALSO MAKE
;THE CORRESPONDING CHANGE IN THE DATA BLOCK GENERATION MACROS IN COMMOD.
;
;FIRST DEFINE THE SYMBOLS USED IN RNXKON FOR THE OFFSETS.

;MACRO TO DEFINE THE MASSBUS REGISTERS TO SAVE IN THE KDB WHEN AN
;ERROR IS DETECTED.  ARGUMENT IS A LIST OF THE OCTAL MASSBUS REGISTER
;NUMBERS TO SAVE.  THE TOTAL NUMBER OF REGISTERS MUST NOT EXCEED ^D36.

DEFINE	MBRLST	(LST), <
	..CNT==0	;START WITH 0 REGISTERS
	MBRTBL==0	;AND WITH NO BITS
	IRP LST, <
	   IFE <LST-0>,<.EBM00==..CNT>
	   IFE <LST-30>,<.EBM30==..CNT>
	   ..CNT==..CNT+1 ;BUMP NUMBER BY 1
	   MBRTBL==MBRTBL!<1_<^D35-LST>> ;SET BIT IN TABLE
	> ;END IRP LST
	RNVNMR==:..CNT	;DEFINE THE NUMBER OF REGISTERS
>

MBRLST	<0,1,2,3,4,5,6,20,21,22,23,24,25,26,27,30,31,32,33,34,35,36,37>

.EBNMR==RNVNMR		;NUMBER OF MASSBUS REGISTERS
.EBNDR==^D24		;NUMBER OF DRIVE REGISTERS

.EBTYP==0		;BYTE (9) DX20 ADDR(9)0(18) MICROCODE VERSION
.EBCS0==1		;CHANNEL LOGOUT 0
.EBCS1==2		;CHANNEL LOGOUT 1
.EBCS2==3		;CHANNEL LOGOUT 2
.EBCC1==4		;FIRST CCW
.EBCC2==5		;SECOND CCW
.EBMPE==6		;COUNT OF MPE
.EBNXM==7		;COUNT OF NXM
.EBMBR==10		;+LEN,,OFFSET FROM . OF MASSBUS REGISTERS
.EBDVL==11		;+LEN,,OFFSET FROM . OF DEVICE REGISTERS
.EBSMR==12		;START OF MASSBUS REGISTER BLOCK
.EBSTR==.EBSMR+1	;WHERE STATUS REGISTER IS STORED
.EBERR==.EBSMR+2	;WHERE ERROR REGISTER IS STORED
.EBESR==.EBSMR+7	;WHERE ENDING STATUS REGISTER IS STORED
.EBSDR==.EBSMR+.EBNMR	;START OF DEVICE REGISTER BLOCK
.EBS07==.EBSDR+1	;WORD CONTAINING SENSE BYTE 7
	EB.S07==377B35	;POSITION OF SENSE BYTE 7
.EBS18==.EBSDR+4	;WORD CONTAINING SENSE BYTES 18 AND 19
	EB.S18==177777B35 ;POSITION OF SENSE BYTES 18 AND 19
.EBS20==.EBSDR+5	;WORD CONTAINING SENSE BYTES 20 AND 21
	EB.S20==177777B17 ;POSITION OF SENSE BYTES 20 AND 21
.EBICR==.EBSDR+.EBNDR	;CONTENTS OF INITIAL CONTROL REGISTER


;NOW DEFINE THE VALUES THAT THE REST OF THE MONITOR USES TO INTERFACE
;TO THIS BLOCK.

RNVEBK==.EBICR		;LENGTH OF THE ???EBK BLOCK
RNVSMR==:.EBSMR	 	;OFFSET OF START OF MASSBUS REGISTERS IN RNXEBK/UNIEBK
	SUBTTL	DATA STRUCTURE FIELD AND BYTE POINTER DEFINITIONS


RNXMVR==300,,1		;MINIMUM MICROCODE VERSION ALLOWED

;FIELDS IN RNXFLG(J)

RN.UPA==1B1		;BEEN THROUGH RNXUPA ONCE FOR THIS CONTROLLER
RN.FTL==1B3		;LAST TRANSFER ERROR WAS FATAL
RN.CLR==RN.FTL		;BITS TO CLEAR IN CONECT
RN.DCA==17B31		;4 BITS OF DCU ADDRESS (SUBFIELD OF RN.CUA)


;BYTE POINTERS TO ABOVE FIELDS

RNYDCA:	POINTR	RNXFLG(J),RN.DCA ;DCU ADDRESS


;FIELDS IN RNXCMD(J)

CM.FNC==77B5		;FUNCTION ISSUED TO DRIVE (I.E., BITS 30-35
			;  OF DATAO TO CONTROL REGISTER OR STCR)
CM.XFR==1B0		;THIS FUNCTION CAUSES A DATA TRANSFER
CM.IO==1B2		;1=READ, 0=WRITE
CM.HNG==1B6		;THIS INTERRUPT CAME THROUGH RNXSTP
CM.DVA==377B35		;DEVICE ADDRESS FOR THIS OPERATION
CM.UNF==17B35		;4 BIT UNIT NUMBER
;MISCELLANEOUS PARAMETER DEFINITIONS

.CRM10==210			;CONTENTS OF CRAM LOCATION 10
.DXSAD==5			;DX20 RESTART ADDRESS
MAXRSC==^D8			;NUMBER OF TIMES TO SIMPLY RESTART THE
				;  DX20 WHEN WE DISCOVER THAT IT STOPPED
				;  BEFORE SIMPLY CALLING IT DEAD
RTYNUM==^D24			;NUMBER OF RETRIES TO DO IN ERROR RECOVERY
ATNRTY==^D10			;NUMBER OF TIMES TO RETRY CLEARING AN
				;  ATTENTION BIT FOR A DX20 THAT WE KNOW
				;  ABOUT BEFORE RESORTING TO A MASSBUS
				;  INIT TO CLEAR IT
ALLERR==777770B35		;ALL POSSIBLE ERROR BITS SET BY INTERRUPT
				;SERVICE IN THE COMMUNICATIONS WORD
MAXDCU==^D16			;MAXIMUM NUMBER OF DCU ADDRESSES WE
				;  CAN HAVE ON A DX20
MAXSPD==^D16			;MAXIMUM NUMBER OF SPINDLES WE CAN HAVE
				;  ON A DCU
	SUBTTL	MACRO DEFINITIONS


;MACRO TO COMPUTE THE WIDTH OF A MASK
;	"WID" RETURNS THE LENGTH OF THE LEFTMOST STRING OF
;	CONSECUTIVE ONES IN THE WORD.

DEFINE	WID(MASK),<<^L<-<<MASK>_<^L<MASK>>>-1>>>

;MACRO TO COMPUTE THE POSITION OF A MASK

DEFINE	POS(MASK),<<^L<MASK>+^L<-<<MASK>_<^L<MASK>>>-1>-1>>

;MACRO TO BUILD A POINTER TO A MASKED QUANTITY
;	POINTR	LOCATION,MASK

DEFINE	POINTR(LOC,MASK),<<POINT WID(MASK),LOC,POS(MASK)>>

;MACRO TO LOAD AN ARBITRARY BYTE FROM A LOCATION INTO AN AC.
;	LOAD	AC,LOC,MASK

DEFINE	LOAD(A,B,C),<.LDST.(A,B,C,HRRZ,HLRZ,LDB,MOVE)>

;MACRO TO STORE AN ARBITRARY BYTE FROM AN AC INTO A LOCATION
;	STORE	AC,LOC,MASK

DEFINE	STORE(A,B,C),<.LDST.(A,B,C,HRRM,HRLM,DPB,MOVEM)>

;UTILITY MACRO USED BY LOAD AND STORE

DEFINE	.LDST.(A,B,C,D,E,F,G),<
	IFNB	<C>,<..T==0
		IFE	C-777777,<..T==1
			D	A,B>
		IFE	C-777777000000,<..T==1
			E	A,B>
		IFE	..T,<F	A,[POINTR(B,C)]>>
	IFB	<C>,<G	A,B>
>  ;END OF DEFINE .LDST.

;MACRO TO INSERT A VALUE IN A MASKED FIELD
;	INSVL.(VALUE,MASK)

DEFINE INSVL.(VALUE,MASK),<<<<VALUE>B<POS(<MASK>)>>&<MASK>>>
;MACRO TO WAIT AWHILE.  USED IN DODTI TO GIVE THE DRIVE TIME TO
;RESPOND WITH THE VALUE OF THE EXTERNAL REGISTER.

DEFINE	STALL, <
	IMULI	T2,1
	XLIST
	IMULI	T2,1
	LIST
>
	SUBTTL	AUTOCONFIGURATION


RNFIX==0			;NOT FIXED HEAD, CANNOT SEEK WHILE XFERRING
RNOFS==0			;DRIVE CAN OFFSET. IT CAN'T REALLY BUT WE HAVE
				;TO GET FILIO TO CALL US (VIA RNXERR) TO DIRECT
				;ERROR RECOVERY.
RNRDC==400000			;NO 10/11 COMPATABLILITY MODE
RNUNL==400000			;DRIVE CANNOT BE UNLOADED
RNCPY==KOPIDL			;KONTROL MUST BE IDLE FOR RNXCPY
RNMX==0				;CANNOT DO MULTIPLE TRANSFERS
RNDRB==0			;DOESN'T USE DISK I/O REQUEST BLOCKS
RNBMX==0			;NOT A BLOCK MULTIPLEX KONTROLLER
RNECA==0			;TRY OFFSET/RECAL BEFORE TRYING ECC
RNERNO==RNVEBK			;NUMBER OF MASSBUS REGISTERS TO SAVE

RNXDMX==20			;MAXIMUM DRIVES PER KONTROLLER
RNXHDN==RNXDMX-1		;HIGHEST DRIVE NUMBER ON KONTROLLER

;DRIVER CHARACTERISTICS
;	RNX	= RNXCNF
;	DSK	= DISK
;	0	= MAXIMUM DEVICES IN SYSTEM (NO LIMIT)
;	TYPRN	= KONTROLLER TYPE
;	RNXDMX	= MAXIMUM DRIVES PER KONTROLLER
;	RNXHDN	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(RNX,DSK,0,TYPRN,RNXDMX,RNXHDN,MDSEC0,MDSEC0,DR.MCD)

	.ORG	KONUDB		;START OF RP20 SPECIFIC DATA
RNXUTB:!BLOCK	RNXDMX		;UDB TABLE
RNXULB:!BLOCK	.ULLEN		;MICROCODE LOADER BLOCK
RNXEBK:!BLOCK	RNERNO		;STORAGE FOR MASSBUS REGISTERS
RNXIOB:!			;START OF SPECIAL I/O INSTRUCTIONS
RNXCO2:!BLOCK	1
RNXCO4:!BLOCK	1
RNXCI2:!BLOCK	1
RNXDO2:!BLOCK	1
RNXDO1:!BLOCK	1
RNXDI2:!BLOCK	1
RNXRAE:!BLOCK	1		;SKIP IF NO RAE
RNXIOE:!			;END OF SPECIAL I/O INSTRUCTIONS
RNXRAC:!BLOCK	1		;LH=COUNT OF RAE'S CAUSED BY OTHER THAN
				;   NON-EXISTENT DRIVES
				;RH=COUNT OF RAE'S CAUSED BY NON-EXISTENT
				;   DRIVES
RNXAEC:!BLOCK	1		;RH=COUNT OF THE NUMBER OF TIMES AN ATTENTION
				;   SUMMARY REGISTER BIT COULDN'T BE
				;   CLEARED BY WRITING IT TO A 1.  USED
				;   TO TELL WHEN TO DO A MASSBUS INIT.
				;LH=TOTAL NUMBER OF MASSBUS INITS DONE
RNXEC1:!BLOCK	1		;LH=NUMBER OF TIMES LOGUPE WAS CALLED TO
				;   LOG AN ERROR THAT FILIO WOULDN'T HAVE
				;RH=NUMBER OF TIMES WGOCLR DIDN'T TIME
				;   OUT THE GO BIT
RNXEC2:!BLOCK	1		;LH=NUMBER OF TIMES CMDWAT TOSSED A SEEK
				;   BECAUSE AN XFER WAS IN PROGRESS
				;RH=NUMBER OF TIMES CMDWAT WAS CALLED
RNXEC3:!BLOCK	1		;LH=NUMBER OF TRANSFERS WHICH RESULTED IN
				;   MISSED REVOLUTIONS DURING LAST INTERVAL
				;RH=NUMBER OF TRANSFERS ATTEMPTED DURING LAST
				;   INTERVAL
RNXRSC:!BLOCK	1		;NUMBER OF TIMES THIS DX20 WAS RESTARTED.
RNXFLG:!BLOCK	1		;FLAGS (SEE RNXKON FOR DEFINITIONS)
RNXCMD:!BLOCK	1		;LAST COMMAND+FUNCTION FLAGS ISSUED TO
				;  KONTROLLER
RNXLAS:!BLOCK	1		;VALUE OF RNXCMD AT LAST INTERRUPT
				;  (FOR DEBUGGING)
RNXATN:!BLOCK	1		;LH=ATTENTION BITS FOR DRIVES PRESENTING
				;   ASYNCHRONOUS STATUS
				;RH=UNUSED
RNXITB:!BLOCK	2		;VALUE OF THE KL TIME BASE AT THE TIME
				;  THE LAST TRANSFER WAS STARTED.  USED
				;  TO CALCULATE MISSED REVOLUTIONS.
RNXIUM:! BLOCK	RNXDMW		;IGNORE DRIVE MASK
RNXNUM:! BLOCK	RNXDMW		;NEW DRIVE MASK
RNXKLN:!			;LENGTH OF KDB
	.ORG

;PROTOTYPE KDB
RNXKDB:	XXKON	(RN)
	SETWRD	(RNXCO2,<CONO	000,(T2)>)
	SETWRD	(RNXCO4,<CONO	000,(T4)>)
	SETWRD	(RNXCI2,<CONI	000,T2>)
	SETWRD	(RNXDO2,<DATAO	000,T2>)
	SETWRD	(RNXDO1,<DATAO	000,T1>)
	SETWRD	(RNXDI2,<DATAI	000,T2>)
	SETWRD	(RNXRAE,<CONSZ	000,CI.RAE>)
	KDBEND

EQUATE	(LOCAL,0,<RNXUDB>)
EQUATE	(LOCAL,CPOPJ##,<RNXHWP,RNXINI>)

	RNXICD==DSKICD##	;PROTOTYPE INTERRUPT CODE
	RNXICL==DSKICL##

	RNXUDB==0		;NO PROTOTYPE UDB
	RNXULN==UNIEBK+RNERNO	;LENGTH OF UDB

RNXDSP:	DRVDSP	(RNX,DSKCHN##,DSKDDB##,DDBLEN##,DSKDIA##)

RNXCKT:	EXP	TYPRN,	0	;COMPATIBLE KONTROLLER TABLE

;PROTOTYPE MICROCODE LOADER BLOCK
RNXULP:	 EXP	.BTRP2##	;MICROCODE INDEX
	 XWD	000,0		;DEVICE CODE,,MASSBUS UNIT NUMBER
	 SIXBIT	/RP20/		;INTERFACE NAME
	 SIXBIT	/DX20/		;CHANNEL NAME
	 EXP	RNXMVR		;MINIMUM MICROCODE VERSION
	 EXP	0		;DATE/TIME OF LOAD SUCCESS OR FAILURE
	 EXP	0		;MICROCODE VERSION
	 EXP	0		;POINTER TO MAGIC TABLE
	 EXP	0		;MICROCODE LENGTH
	 EXP	0		;MICROCODE ADDRESS
	SUBTTL	START DRIVE POSITIONING


;ROUTINE TO CAUSE THE DRIVE TO DO A RECALIBRATE OPERATION.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,RNXRCL
;RETURN CPOPJ IF ERROR
;	CPOPJ1 WITH RECAL STARTED

RNXRCL:	MOVEI	T1,.DXCTR!.CRRCL ;GET RECAL FUNCTION CODE
	PUSHJ	P,CONECT	;CONNECT TO THE DRIVE
	  JRST	RNXDWN		;DRIVE IS DOWN
	MOVSI	T2,(.DXDCR)	;SET CYLINDER AND
	MOVSI	T3,(.DXDAR)	;  TRACK/SECTOR TO ZERO
	PJRST	RNXGO		;JOIN COMMON CODE


;ROUTINE TO START A POSITION OPERATION GOING.  FOR RP20'S, FILIO ALWAYS
;DOES A SEEK BEFORE EVERY TRANSFER REGARDLESS OF WHETHER THE DRIVE IS
;ALREADY ON CYLINDER.  WE TURN THAT INTO A SEARCH COMMAND SO THAT WE
;GET AN INTERRUPT WHEN THE DRIVE IS BOTH ON CYLINDER AND ON SECTOR.
;CALL WITH UNIBLK(U) CONTAINING THE DESIRED BLOCK NUMBER.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,RNXPOS
;RETURN CPOPJ IF ERRORS
;	CPOPJ1 WITH POSITION STARTED

RNXPOS:	MOVEI	T1,.DXCTR!.CRSRC ;GET SEARCH COMMAND
	PUSHJ	P,CONECT	;CONNECT TO DRIVE
	  JRST	RNXDWN		;DRIVE IS DOWN
	PJRST	RNXGO		;JOIN COMMON CODE
	SUBTTL	START DATA TRANSFERS


;ROUTINES TO START A DATA TRANSFER GOING ON A DRIVE.  ENTRY POINTS
;ARE:
;	RNXRED	- READ DATA, DON'T STOP ON ERROR
;	RNXRDS	- READ DATA, STOP ON ERROR
;	RNXRDF	- READ FORMAT
;	RNXWRT	- WRITE DATA, DON'T STOP ON ERROR
;	RNXWTS	- WRITE DATA, STOP ON ERROR
;	RNXWTF	- WRITE FORMAT
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	P1/CHANNEL DATA BLOCK ADDRESS
;	PUSHJ	P,ROUTINE
;RETURN CPOPJ IF ERRORS WITH:
;	T1/ERROR BITS
;	CPOPJ1 IF TRANSFER STARTED SUCCESSFULLY


;HERE TO START TRANSFER TO READ/WRITE FORMATS.

RNXRDF:	SKIPA	T1,[.CRRDF]	;GET FUNCTION CODE FOR READ FORMAT
RNXWTF:	MOVEI	T1,.CRWTF	;DITTO FOR WRITE FORMAT
	MOVE	T2,KONCNT(J)	;WHEN READING OR WRITING FORMATS,
	IDIVI	T2,202		;  SECTORS ARE 202 WORDS LONG BUT FILIO
	SKIPE	T3		;  COMPUTED THE BLOCK COUNT BASED ON 200
	ADDI	T2,1		;  WORD SECTORS.  RECOMPUTE THE BLOCK
	HRRM	T2,CHNNUM(P1)	;  COUNT TO KEEP THE RH20 HAPPY.
	JRST	RNXDGO		;JOIN COMMON TRANSFER CODE
;HERE TO START TRANSFER TO READ/WRITE DATA, NOT STOPPING ON ERRORS.

RNXRED:	SKIPA	T1,[DO.DTE!.CRRED] ;GET FUNCTION FOR READ DATA+DXES
RNXWRT:	MOVEI	T1,DO.DTE!.CRWRT ;DITTO FOR WRITE DATA+DXES
	JRST	RNXDGO		;JOIN COMMON CODE

;HERE TO START TRANSFER TO READ/WRITE DATA, STOPPING ON ERRORS.

RNXRDS:	SKIPA	T1,[.CRRED]	;GET FUNCTION CODE FOR READ DATA
RNXWTS:	MOVEI	T1,.CRWRT	;DITTO FOR WRITE DATA

;HERE FROM ALL TRANSFER OPERATIONS TO ACTUALLY DO THE WORK WITH
;T1 CONTAINING THE FUNCTION.

RNXDGO:	PUSHJ	P,CONECT	;CONNECT TO DRIVE
	  JRST	RNXDWN		;DRIVE IS DOWN
	PUSH	P,T4		;SAVE IGNORE COMMAND FLAG
	MOVN	T4,CHNNUM(P1)	;GET NEGATIVE BLOCK COUNT FOR TRANSFER
	STORE	T4,T1,DO.CNT	;STORE IN APPRPRIATE PLACE IN STCR
	TLO	T1,(.DOSTC!DO.RCP!DO.SCS) ;SETUP TO TALK TO STCR
	POP	P,T4		;RESTORE T4
;HERE TO START ALL OPERATIONS GOING THROUGH EITHER THE STCR OR THE
;DX20 CONTROL REGISTER WITH:
;	T1/STCR OR CONTROL REGISTER DATAO
;	T2/DATAO TO SETUP DESIRED CYLINDER REGISTER
;	T3/DATAO TO SETUP DESIRED ADDRESS REGISTER
;	T4/NON-ZERO TO TOSS THIS COMMAND

RNXGO:	JUMPN	T4,RNXGO1	;DON'T DO DATAO'S IF TOSSING COMMAND
	PUSH	P,T3		;SAVE DESIRED ADDRESS REGISTER
	PUSHJ	P,DODTO		;WRITE DESIRED CYLINDER REGISTER
	POP	P,T2		;RESTORE DESIRED ADDRESS REGISTER
	PUSHJ	P,DODTO		;WRITE THAT ALSO
RNXGO1:	HLRZ	T3,KDBUNI(J)	;GET DX20 NUMBER
	TLO	T1,<(DO.LDR!DO.DRE)>(T3) ;SET LDR, DRE, AND DS
	SKIPE	T4		;TOSSING THIS COMMAND?
	TLO	T1,(CR.IGN)	;YES, SET FLAG SO WE CAN TELL
	MOVEM	T1,UNILAS(U)	;STORE AS LAST COMMAND FOR THIS UNIT
	JUMPN	T4,RNXGO2	;EXIT NOW IF TOSSING COMMAND
	STORE	T1,RNXCMD(J),CM.FNC ;STORE FUNCTION IN KDB
	TRNE	T1,CR.IOP	;THIS AN I/O FUNCTION?
	RDTIME	RNXITB(J)	;YES, READ THE STARTING TIME BASE
RNXBP1:	XCT	RNXDO1(J)	;START THE OPERATION
RNXGO2:	PUSHJ	P,REASPI	;REASSIGN PIA
	JRST	CPOPJ1##	;GIVE SKIP RETURN


;HERE IF THE DRIVE OR KONTROLLER WAS DECLARED DOWN BY CONECT TO RETURN
;AN ERROR INDICATION TO FILIO.

RNXDWN:	PUSHJ	P,SETCO		;SET CONO MASK
	TRO	T4,CO.RAE	;MAKE SURE RAE IS CLEAR
	XCT	RNXCO4(J)	;GIVE IT A PIA
	XCT	RNXCI2(J)	;GET CONI INTO T2
	MOVE	T3,RNXEBK+.EBERR(J) ;GET ERROR REGISTER
	HRL	T3,RNXEBK+.EBSTR(J) ;MAKE IT STATUS,,ERROR REGISTER
RNXBP5:	POPJ	P,		;RETURN
	SUBTTL	STOP TRANSFER FOR HUNG RECOVERY


;ROUTINE TO STOP THE CURRENT TRANSFER WHEN THE HUNG TIMER TIMES
;OUT.  NOTE THAT THE SETTING OF STOP TRANSFER CAUSES AN IMMEDIATE
;INTERRUPT SO RNXINT HAS TO KNOW ABOUT THESE KINDS OF INTERRUPTS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXSTP
;RETURN CPOPJ IF COULDN'T GET BUSY TO CLEAR
;	CPOPJ1 IF SUCCESSFUL

RNXSTP:	XCT	RNXCI2(J)	;GET CONI BEFORE STOPPING TRANSFER
	PUSH	P,T2		;SAVE IT
	PUSHJ	P,RNXIVI	;ASSIGN AN IVI SINCE WE MIGHT BE HERE
				;  AS THE RESULT OF POWER FAIL RESTART
	MOVSI	T2,(CM.HNG)	;SET BIT TELLING RNXINT THAT THIS
	IORM	T2,RNXCMD(J)	;  INTERRUPT WAS THE RESULT OF A HUNG
	MOVEI	T2,CO.STP	;GET THE STOP TRANSFER BIT
	XCT	RNXCO2(J)	;STOP THE RH20
	XCT	RNXCI2(J)	;GET THE CONI BACK
RNXBP6:	TRNN	T2,CI.BSY	;DID BUSY CLEAR?
	AOS	-1(P)		;YES, GIVE SKIP RETURN
	POP	P,T2		;RESTORE CONI
	MOVEI	T3,0		;DATAI WILL BE SAVED BY RNXINT
	PJRST	REASPI		;REASSIGN PIA AND RETURN
	SUBTTL	INTERRUPT HANDLER


;ROUTINE TO PROCESS RP20 INTERRUPTS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXINT
;EXITS CPOPJ ALWAYS THROUGH FILINT WITH:
;	T1/COMMUNICATIONS WORD (ATN BITS+DRIVE,,ERROR+FUNCTION)
;	T2/CONI
;	T3/ENDING STATUS,,ERROR REGISTER

RNXINT:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVE	W,J		;SET UP KDB ADDRESS
	PUSHJ	P,SVMBR##	;SAVE CURRENT MBR FOR UUO LEVEL
	MOVEI	T2,^D2000	;JUST IN CASE SOMETHING IS HAPPENING,
	PUSHJ	P,WGOCLR	;  WAIT FOR THE GO BIT TO CLEAR
	PUSHJ	P,RNXINR	;PROCESS ANY OPERATION IN PROGRESS
				;  PLUS ANY ERRORS THAT OCCURRED WHILE
				;  THERE WAS NO OPERATION IN PROGRESS
				;  (MICRODIAGNOSTIC FAILURE, UCODE RELOAD)
	PUSHJ	P,CHKATN	;CHECK ON ASYNCHRONOUS EVENTS AND CALL FILIO
	POPJ	P,		;RETURN
;ROUTINE TO PROCESS ANY OPERATION CURRENTLY IN PROGRESS OR ERRORS
;THAT OCCURRED WHILE THERE WAS NO OPERATION IN PROGRESS SUCH
;AS MICRODIAGNOSTIC FAILURES OR INTERRUPTS FOR MICROCODE RELOADS.
;CALLED FROM INTERRUPT SERVICE AND CONECT.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXINR
;RETURN CPOPJ ALWAYS WITH:
;	J/KDB ADDRESS
;	T1/FILIO COMMUNICATION WORD
;	P1/FLAGS FROM RNXCMD OR 0 IF NO OPERATION IN PROGRESS
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI

RNXINR:	SETZB	T1,P2		;CLEAR COMMUNICATION AND DATAI WORDS
	XCT	RNXCI2(J)	;GET CONI IN T2
	MOVEI	P3,(T2)		;MOVE TO P3
	MOVEI	P1,0		;START WITH ZERO FLAGS
	EXCH	P1,RNXCMD(J)	;ZERO FLAG WORD, PUT FLAGS IN P1
	MOVEM	P1,RNXLAS(J)	;SAVE VALUE FOR DEBUGGING
	MOVSI	T2,(.DXESR)	;POINT AT ENDING STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	MOVEI	P2,(T2)		;MOVE TO P2
	JUMPGE	P1,RNXIN2	;GO IF NOT A DATA TRANSFER OPERATION
	MOVE	T2,KDBICP(J)	;GET ADDRESS OF RH20 LOGOUT AREA
	HLL	P3,.CSCLP(T2)	;COPY CHANNEL STATUS TO LH(P3)
RNXIN2:	MOVE	U,KONCUA(J)	;SETUP POSSIBLE UDB ADDRESS
	PUSHJ	P,CHKERR	;CHECK ON DX20 DETECTED ERRORS
	JUMPL	P1,DATINT	;DISPATCH TO DATA XFER DONE HANDLER
	JUMPE	P1,NOPINT	;DISPATCH IF NO OPERATION IN PROGRESS
	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	MOVE	T2,BITTBL##(T2)	;AND CORRESPONDING BIT
	TLNE	P1,(CM.HNG)	;COME THROUGH RNXSTP?
	IORM	T2,RNXATN(J)	;YES, MUST BE A HUNG RECAL
;;	PJRST	POSINT		;FALL INTO POSITION DONE HANDLER
;HERE ON A POSITION INTERRUPT AT POSINT OR AN INTERRUPT WITH NO
;OPERATION IN PROGRESS AT NOPINT WITH THE FOLLOWING AC'S SETUP:
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0 IF NO OPERATION IN PROGRESS
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CONI

POSINT:	LOAD	T2,P1,CM.UNF	;GET UNIT NUMBER OF DRIVE
	TRNN	T1,ALLERR	;NO 2ND INTERRUPT IF WE GOT AN ERROR
	TRNE	P2,ES.DVE	;DEVICE END UP IN ENDING STATUS REGISTER?
	PUSHJ	P,POSDON	;YES, SET CORRESPONDING BIT IN RNXATN
NOPINT:	TRO	T1,OPPOS	;FLAG THIS AS A POSITION OPERATION
	TRZE	T1,ALLERR	;ANY ERRORS DETECTED?
	PUSHJ	P,LOGUPE	;YES, LOG THEM
	POPJ	P,		;RETURN


;HERE ON A DATA TRANSFER INTERRUPT WITH THE FOLLOWING AC'S SETUP:
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI

DATINT:	TLNE	P1,(CM.HNG)	;HERE FROM RNXSTP?
	TRO	T1,IODERR	;YES, SET DEVICE ERROR
	TLNE	P1,(CM.IO)	;DOING A READ?
	TROA	T1,OPRED	;YES, FLAG IT AS SUCH
	TRO	T1,OPWRT	;NO, FLAG IT AS A WRITE
	TLC	P3,(CS.NAE)	;COMPLEMENT ADDRESS PARITY BIT
	TDNN	P3,[CS.ERR!CI.ERR] ;ANY CHANNEL OR RH20 ERRORS DETECTED?
	JRST	DATIN1		;NO
	TLNE	P3,(CS.MPE)	;MEMORY PARITY ERROR?
	TRO	T1,IOCHMP	;YES
	TLNE	P3,(CS.NXM)	;NXM?
	TRO	T1,IOCHNX	;YES
	TLNE	P3,(CS.OVR)	;OVERRUN?
	TRO	T1,IOVRUN	;YES
	TRNN	T1,ALLERR	;ANY ERRORS FLAGGED (BETTER BE)
	TRO	T1,IODERR	;NO??? FLAG A DEVICE ERROR
DATIN1:	TLC	P3,(CS.NAE)	;RECOMPLEMENT ADDRESS PARITY BIT
	TRNN	T1,ALLERR	;ANY ERRORS DETECTED?
	SKIPLE	UNIECT(U)	;NO, READ SUCCEED ON RETRY?
	PUSHJ	P,RDREG		;YES, READ THE REGISTERS
	MOVE	T2,UDBKDB(U)	;UPDATE THE LAST KNOWN POSITION
	MOVE	T2,KDBCHN(T2)
	MOVE	T2,CHNNUM(T2)	; OF THE DISK
	ADD	T2,UNIBLK(U)
	ADDI	T2,^D14		;PLUS A FUDGE FACTOR
	LDB	T3,UNYBPT##
	IDIV	T2,T3
	DPB	T3,UNYLKP##
	POPJ	P,		;RETURN
;ROUTINE TO CHECK FOR ASYNCHRONOUS EVENTS AND DO THE FINAL INTERRUPT
;PROCESSING BEFORE CALLING FILINT.
;CALL:
;	J/KDB ADDRESS
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI
;	PUSHJ	P,CHKATN
;RETURN CPOPJ ALWAYS

CHKATN:	PUSHJ	P,CLRATN	;CLEAR ATTENTION BITS
	PUSHJ	P,CLRERG	;CLEAR THE ERROR REGISTER
	MOVSI	T2,(.DXASY)	;POINT AT THE ASYNCHRONOUS STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	JUMPE	T2,INTDON	;GO IF NONE THERE
	TRNE	T2,AS.DVS	;ANY STATUS BITS SET?
	JRST	RNXBP2		;YES, CONTINUE
	MOVSI	T2,(.DXASY)	;THERE'S A UCODE RACE WHICH CAUSES IT TO GIVE
	PUSHJ	P,DODTI		;US A DRIVE WITH NO STATUS, SO READ IT AGAIN
RNXBP2:	PUSH	P,T2		;SAVE IT
	MOVSI	T2,(.DXASY)	;POINT AT REGISTER AGAIN
	PUSHJ	P,DODTO		;CLEAR IT SO WE CAN GET MORE
	POP	P,T2		;RESTORE VALUE TO PROCESS
	SKIPN	P1		;IF NO OPERATION IN PROGRESS,
	MOVEI	P2,(T2)		;MOVE ASYNCHRONOUS STATUS TO P2 FOR .SYS P
	LOAD	T2,T2,AS.UNF	;GET UNIT NUMBER PRESENTING STATUS
	PUSHJ	P,POSDON	;SET THE CORRESPONDING BIT IN RNXATN
;;	PJRST	INTDON		;FALL INTO INTDON
;HERE TO DO THE FINAL EXIT PROCESSING BEFORE CALLING FILINT WITH:
;	J/KDB ADDRESS
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI
;	LH(RNXATN(J))/ATTENTION BITS OF DRIVES IN POSITION

INTDON:	MOVEI	T4,CO.CLR	;GET BITS TO CLEAR RH20
	XCT	RNXCO4(J)	;DO SO
	PUSHJ	P,REASPI	;REASSIGN PIA
	HLLZ	T4,RNXATN(J)	;GET ATTENTION BITS
	LOAD	T2,P1,CM.UNF	;GET UNIT NUMBER LAST CONNECTED TO
	TLO	T1,(T2)		;SET IN LH OF T1
	TRNN	T1,OPPOS	;THIS A POSITION OPERATION?
	TDZ	T4,BITTBL##(T2)	;NO, MAKE SURE WE DON'T CALL FILIO WITH
				;  A POSITION DONE INTERRUPT ON A TRANSFERRING
				;  DRIVE.  IT HAPPENS AND IT CONFUSES FILIO
	;PJRST	CALFIO		;CALL FILIO TO PROCESS THIS EVENT


;ROUTINE TO ACTUALLY CALL FILIO TO PROCESS AND INTERRUPT.
;CALL:
;	J/KDB ADDRESS
;	T1/COMMUNICATION WORD
;	T4/ATTENTION BITS
;	P2/ERROR REGISTER,,ENDING STATUS REGISTER
;	P3/CHANNEL STATUS,,CONI
;	PUSHJ	P,CALFIO
;RETURN CPOPJ ALWAYS

CALFIO:	PUSH	P,J		;SAVE KONTROLLER ADDRESS; FILINT MAY SMASH IT
	HRRZS	RNXATN(J)	;CLEAR ATTENTION BITS IN KDB
	MOVE	T2,P3		;GET CONI IN T2
	MOVS	T3,P2		;  AND DATAI'S IN T3
	MOVEM	T1,RNXEC3(J)	;****; TEMPORARY FOR DEBUGGING
	TLZ	T1,777700	;CLEAR UNUSED BITS
	TRNE	T1,OPPOS	;POSITION INTERRUPT?
	TLNE	T4,777774	;  WITH NO ATTENTION BITS UP?
	SKIPA			;NO
	JRST	JPOPJ##		;AVOID A LONG NO-OP IN FILIO
	PUSH	P,T2		;SAVE T2
	PUSHJ	P,RNXCSB	;CLEAR MICROPROCESSOR STOPPED BIT
	POP	P,T2		;RESTORE T2
	PUSHJ	P,FLHTID##	;CALL FILIO
	PJRST	JPOPJ##		;RESTORE J AND RETURN
	SUBTTL	DETERMINE CAPACITY AND STATUS


;ROUTINE TO RETURN CAPACITY AND STATUS OF AN RP20 DRIVE TO FILSER.
;CALL:	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,RNXCPY
;RETURN CPOPJ IF ERROR
;	CPOPJ1 IF DRIVE EXISTS AND IS OK TO USE WITH:
;	T1/BLOCKS PER UNIT
;	T2/BLOCKS PER UNIT INCLUDING MAINTENANCE CYLINDERS
;	T3/BLOCKS PER UNIT IN 10/11 COMPATABILITY MODE
;	T4/STATUS BITS (KOPUHE,KOPNSU),,UNIT TYPE
;	LH(J)/DRIVE SERIAL NUMBER
;	W/BLOCKS PER TRACK,,BLOCKS PER CYLINDER

RNXCPY:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVEI	T2,CO.MBE	;MAKE SURE MASSBUS
	XCT	RNXCO2(J)	;  ENABLE IS ON AND DEASSIGN PI
	PUSHJ	P,RNXIVI	;SET INTERRUPT VECTOR ADDRESS
	MOVEI	T4,0		;UNIT TYPE IS 0
	SKIPE	RNXCMD(J)	;ARE WE DOING SOMETHING NOW?
	JRST	RNXCP4		;YES, CAN'T TOUCH THE DRIVE
RNXCP1:	PUSHJ	P,MPRUN		;DX20 STILL RUNNING?
	  JRST	RNXCP4		;NO, CALL UNIT OFF-LINE
	PUSHJ	P,DO2TIO	;DO TWO TEST I/O'S
	  JRST	RNXCP4		;GO IF THE DX20 DIDN'T RESPOND
	PUSHJ	P,INIERR	;CHECK FOR ERRORS
	  JRST	RNXCP5		;DRIVE IS ON-LINE
	  JRST	RNXCP4		;DRIVE EXISTS BUT IS OFF-LINE
;HERE IF NO SUCH UNIT EXISTS OR THE DRIVE TYPE REGISTER IS NOT
;FOR A DX20.

RNXCP3:	TLOA	T4,KOPUHE!KOPNSU ;INDICATE NO SUCH UNIT

;HERE IF THE UNIT EXITS BUT IS OFF-LINE OR IF WE'RE NOT REALLY SURE
;AND DON'T WANT TO TELL FILSER THAT NO SUCH UNIT EXISTS.

RNXCP4:	TLO	T4,KOPUHE	;INDICATE OFF-LINE
	JRST	RNXCP6		;JOIN COMMON EXIT CODE

;HERE IF THE DRIVE IS ON-LINE AND NO ERRORS WERE DETECTED.

RNXCP5:	AOS	0(P)		;GIVE SKIP RETURN
RNXCP6:	LDB	T1,RNYDCA	;GET DCU
;THERE'S NO WAY TO READ THE SERIAL NUMBER OF AN RP20 SO WE BUILD A FAKE
;SERIAL NUMBER BASED ON THE UNIT NUMBER.  THE QUESTION IS: IF YOU'VE GOT
;SEVERAL RH20'S WORTH OF RP20'S, HOW DO YOU TELL WHICH RH20 IS DUAL PORTED
;WITH WHICH?  THE ANSWER IS: YOU CUT THE TWO DCU'S TO BE THE SAME ADDRESS.
;IF THE DCU'S MATCH THE DRIVES WILL BE CONSIDERED DUAL PORTED.  THERE'S A
;SPECIAL CASE, HOWEVER, IN THAT A DCU OF ZERO DOESN'T MATCH ANYTHING.  NOTE
;THAT THE FACTORY SETS ALL THE DCU ADDRESSES TO ZERO.  YOU CAN INSTALL ANY
;NUMBER OF THESE WITH NO MODIFICATION AND THEY WILL ALL BE SINGLE PORTED.  IF
;YOU WANT THEM TO BE DUAL PORTED THEN YOU HAVE TO ASSIGN A UNIQUE DCU ADDRESS.
	JUMPE	T1,RNXCP7	;GO IF FACTORY JUMPERS
	LSH	T1,4		;MAKE ROOM FOR UNIT NUMBER
	IOR	T1,UDBPDN(U)	;DUMMY UP A DRIVE SERIAL NUMBER
	MOVEI	T2,.DTCOD	;GET DT VALUE, VERIFIED BY CHKDTR
RNXCP7:	SETZM	UDBDSN(U)	;NO HIGH WORDER S/N WORD
	HRRZM	T1,UDBDSN+1(U)	;RETURN SERIAL NUMBER IN UNISER
	PUSHJ	P,CLRERG	;CLEAR ERROR REGISTER
	PUSHJ	P,CLRATN	;CLEAR ATTENTIONS
	PUSHJ	P,REASPI	;RESTORE PI ASSIGNMENT
	DMOVE	T1,[EXP ^D839250,^D840000] ;BLOCKS/UNIT WITH/WITHOUT MAINT CYL
	TLNE	T4,KOPNSU	;NO SUCH UNIT?
	SETZB	T1,T2		;YES, RETURN 0'S
	MOVEI	T3,0		;NO BLOCKS IN 10/11 COMPATABILITY MODE
	MOVE	W,[^D25,,^D750]	;BLOCKS/TRACK,,BLOCKS/CYLINDER
	POPJ	P,		;RETURN
	$INIT

;CHECK FOR KONTROLLER UP
RNXUPA:	PUSHJ	P,RNXIVI	;ASSIGN INTERRUPT VECTOR ADDRESS
	MOVSI	T1,(RN.UPA)	;ALREADY BEEN THROUGH HERE FOR
	TDNE	T1,RNXFLG(J)	;  THIS CONTROLLER?
	SJSP	T1,CPOPJ1##	;YES, IT'S UP
	SETZM	RNXCMD(J)	;CLEAR COMMAND/FLAGS
	MOVEI	T2,CO.RAE!CO.MBE!CO.AIE!CO.CCD+DSKCHN##	;GET BITS TO CLEAR
				; ERROR IN RH20
	XCT	RNXCO2(J)	;DO SO
	XCT	RNXCI2(J)	;GET CONI
	TRNN	T2,CI.DBP!CI.LWC!CI.DRE!CI.RAE!CI.OVR!CI.BSY ;ANY ERRORS?
	TRNN	T2,CI.PIA	;  OR NO PIA?
	POPJ	P,		;DRIVE IS DOWN
	MOVSI	T1,(RN.UPA)	;SET FLAG THAT WE HAVE
	IORM	T1,RNXFLG(J)	;  BEEN HERE BEFORE
	SJSP	T1,CPOPJ1##	;AND GIVE SKIP RETURN WITH T1 NON-ZERO

	$HIGH
	SUBTTL	RETURN ECC MASK AND POSITION


;ROUTINE TO RETURN THE ECC POSITION AND MASK TO FILIO FOR AN ECC
;CORRECTABLE ERROR IN A BLOCK.  THE RP20 RETURNS THE ECC POSITION
;AND MASK IN THE SENSE BYTES WHICH ARE NOW IN RNXEBK AS FOLLOWS:
;  18-19  FIRST BYTE IN ERROR COUNTED FROM THE LAST BYTE IN THE
;	  BLOCK.  A COUNT OF ZERO MEANS THAT THE ECC ERROR OCCURRED
;	  IN THE ECC BYTE ITSELF AND MAY BE IGNORED.
;  20-21  MASK WHICH WHEN XORED WITH THE DATA ACTUALLY READ WILL
;	  CORRECT THE ERROR.
;NOTE THAT THE BOTH MASK WORDS ARE SWAPPED SINCE THAT'S THE WAY AN
;RP06 WOULD RETURN THEM AND THE WAY FILIO EXPECTS THEM.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXECC
;RETURN CPOPJ IF NO ECC INFORMATION AVAILABLE
;	CPOPJ1 WITH CORRECTION DATA AS FOLLOWS:
;	T1/WORD POSITION OF START OF ERROR RELATIVE TO START OF BLOCK
;	T2-T3/MASK

RNXECC:	HLRZ	T2,RNXEBK+.EBDVL(J) ;GET NUMBER OF DEVICE REGS STORED
	JUMPE	T2,CPOPJ##	;GIVE UP IF NONE
	LOAD	T3,RNXEBK+.EBS07(J),EB.S07 ;GET FORMAT TYPE AND CODE
	CAIN	T3,.S7ECC	;ECC ERROR?
	CAIGE	T2,.EBS07-.EBSDR+1 ;OR IF WE DIDN'T GET AT LEAST 0-7
	POPJ	P,		;NO ECC INFORMATION AVAILABLE
	SETZB	T2,T3		;ZERO MASKS FOR EARLY EXIT
	LOAD	T1,RNXEBK+.EBS18(J),EB.S18 ;GET BYTES 18-19
	JUMPE	T1,CPOPJ1##	;NO CORRECTION IF IN ECC BYTE
	CAILE	T1,^D576	;OR IF OUT
	POPJ	P,		;  OF RANGE
	MOVNI	T1,-^D576(T1)	;COMPUTE NUMBER OF BYTES FROM START OF BLOCK
	LSH	T1,3		;CONVERT TO COUNT OF BITS
	TLZ	T1,-1		;CLEAR JUNK
	IDIVI	T1,^D36		;COMPUTE WORD COUNT, OFFSET IN WORD
	MOVNI	T4,-<^D36-^D16>(T2) ;COMPUTE SHIFT COUNT IN THIS WORD
	LOAD	T2,RNXEBK+.EBS20(J),EB.S20 ;GET CORRECTION MASK
	LSHC	T2,(T4)		;SHIFT TO PROPER POSITION FOR MASK
	MOVSS	T2		;SWAP THE MASK SO THAT IT
	MOVSS	T3		;  LOOKS LIKE THAT RETURNED BY AN RP06
	JRST	CPOPJ1##	;GIVE SKIP RETURN
	SUBTTL	DIRECT FILIO IN ERROR RECOVERY


;ROUTINE TO DIRECT FILIO IN ERROR RECOVERY.  SINCE THE DCU DOES ITS OWN
;SEEK ERROR RECOVERY AND SINCE WE DON'T HAVE ANY OFFSET CAPABILITY,
;THE BASIC ERROR RECOVERY ALGORITHM IS TO SIMPLY DO 24 STRAIGHT RETRIES.
;IF RN.FTL IS SET IN RNXFLG, HOWEVER, WE GIVE UP IMMEDIATELY.
;CALL:
;	J/KDB ADDRESS
;	T1/RETRY NUMBER
;	P1/CHANNEL DATA BLOCK ADDRESS
;	PUSHJ	P,RNXERR
;RETURN CPOPJ ALWAYS WITH:
;	T1/0 IF STRAIGHT RETRY
;	   2 IF LAST TIME
;	   3 IF GIVE UP

RNXERR:	MOVE	T2,RNXFLG(J)	;GET ERROR FLAGS SET BY CHKERR
	TLNE	T2,(RN.FTL)	;FATAL ERROR?
	MOVEI	T1,RTYNUM	;YES, FORCE IT TO BE FATAL
	CAIGE	T1,RTYNUM-1	;STILL DOING STRAIGHT RETRIES?
	MOVEI	T2,0		;YES
	CAIN	T1,RTYNUM-1	;LAST TIME?
	MOVEI	T2,2		;YES
	CAIL	T1,RTYNUM	;TIME TO GIVE UP?
	MOVEI	T2,3		;YES
	MOVEI	T1,(T2)		;MOVE TO WHERE FILIO WANTS IT
	POPJ	P,		;RETURN
	SUBTTL	MISCELANEOUS GLOBAL FUNCTIONS


;ROUTINE TO RETURN THE LATENCY TIME FOR AN RP20 DRIVE.  SINCE THE
;RP20 CAN'T TELL US WHERE IT REALLY IS (THAT'S RIGHT, NO LOOK AHEAD
;REGISTER RP06 FANS), AND SINCE WE ALWAYS DO SEARCHES BEFORE EACH
;DATA TRANSFER SO THAT WE GET AN INTERRUPT WHEN THE DRIVE IS ON
;BOTH CYLINDER AND SECTOR, WE ALWAYS RETURN A LATENCY TIME OF
;ZERO IN THE HOPE THAT FILIO WILL GET BACK TO START THE TRANSFER
;BEFORE THE DISK REVOLVES PAST THE BLOCK.
;CALL:
;	PUSHJ	P,RNXLTM
;RETURN CPOPJ1 ALWAYS WITH:
;	T1/LATENCY TIME (ZERO)

RNXLTM:	MOVEI	T1,0		;RETURN A ZERO
	JRST	CPOPJ1##	;GIVE SKIP RETURN


;ROUTINE TO RETURN THE DISTANCE TO THE TARGET CYLINDER.  SINCE WE WANT
;TO DO SEEKS (REALLY SEARCHES), WE ALWAYS TELL FILIO THAT WE ARE OFF
;CYLINDER EVEN IF WE ARE ON CYLINDER. 
;BE AWARE THAT WHEN CHOOSING SOMEBODY FROM THE POSITION WAIT QUEUE,
;IF THERE ARE SEVERAL PEOPLE ALREADY ON CYLINDER, FILIO
;WILL TRY TO CHOOSE THE ONE WHOSE ROTATIONAL LATENCY IS THE
;SMALLEST. IN THE CASE OF AN RP20, WE MUST LIE TO FILIO.
;IF WE'RE ON CYLINDER, LIE TO FILIO AND TELL HIM THAT WE'RE OFF
;CYLINDER. BUT LIE BY AN AMOUNT LINEARLY PROPORTIONATE TO THE
;EXPECTED ROTATIONAL LATENCY OF THE DISK. THE EXPECTED LATENCY
;IS CALCULATED FROM THE LAST KNOWN POSITION OF THE DISK.
;THE ONLY TIME WE CAN ACCURATELY KNOW THE POSITION OF THE DISK
;IS AT THE CONCLUSION OF A TRANSFER. IT HAPPEN'S THAT'S
;THE ONLY TIME WE PICK SOMEBODY FROM THE POSITION WAIT QUEUE
;ANYWAY.

;CALL:
;	PUSHJ	P,RNXCCM
;RETURN CPOPJ ALWAYS WITH:
;	T1/DISTANCE FROM CURRENT CYLINDER TO TARGET CYLINDER

RNXCCM:	PUSHJ	P,CYLCM##	;LET FILIO COMPUTE THE REAL DISTANCE
	MOVMS	T1
	ADDI	T1,100		;EXCESS 100
	CAIE	T1,100		;ON CYL?
	POPJ	P,		;NO
	MOVE	T1,DEVBLK##(F)	;YES, COMPUTE TARGET SECTOR
	LDB	T3,UNYBPT##
	IDIV	T1,T3
	LDB	T1,UNYLKP##	;LAST KNOWN POSITION OF DISK
	CAMLE	T1,T2		;TOO LATE?
	ADD	T2,T3		;YES, WAIT ANOTHER REVOLUTION
	SUBM	T2,T1		;DISTANCE TO TARGET
	ADDI	T1,1		;ASSURE NON-ZERO
	SKIPL	UNIECT(U)	;IN ERROR RECOVERY?
	SETZ	T1,		;YES, TELL THE TRUTH (ON CYL)
	POPJ	P,		;RETURN


;ROUTINES WHICH SHOULD NEVER BE CALLED SINCE THE DISPATCH BITS
;IN COMMOD PROHIBIT THIS.  IF WE DO GET HERE HOWEVER...

RNXRDC:				;READ 10/11 COMPATABILITY MODE
RNXWTC:				;WRITE 10/11 COMPATABILITY MODE
RNXUNL:				;UNLOAD DRIVE
	STOPCD	CPOPJ1##,DEBUG,NIF, ;++RNXKON ISN'T FANCY
	SUBTTL	CHECK DRIVE/CONTROLLER STATUS


;ROUTINE TO INSURE THAT THE RH20 AND DX20 ARE OK FOR THE OPERATION
;ABOUT TO BE DONE AND SETUP FOR THAT OPERATION.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	T1/FUNCTION
;	PUSHJ	P,CONECT
;RETURN CPOPJ IF ERROR WITH:
;	T1/ERROR BITS
;	CPOPJ1 IF OK WITH:
;	T1/FUNCTION
;	T2/CYLINDER
;	T3/TRACK/SECTOR IN .DXDAR FORMAT
;	T4/NON-ZERO TO TOSS THIS COMMAND

CONECT:	MOVEI	T4,CO.MBE	;MAKE SURE PIA IS OFF AND MBE
	XCT	RNXCO4(J)	;  IS ON
	SKIPE	T4,RNXCMD(J)	;COMMAND IN PROGRESS ALREADY?
RNXBP4:	PUSHJ	P,CMDWAT	;YES, WAIT FOR IT TO FINISH
	JUMPN	T4,CONEC2	;GO IF TOSSING COMMAND
	MOVSI	T2,(RN.CLR)	;CLEAR TEMPORARY BITS
	ANDCAM	T2,RNXFLG(J)	;  IN KDB
	PUSHJ	P,RNXIVI	;MAKE SURE RH20 HAS AN IVI
	XCT	RNXCI2(J)	;GET CONI IN T2
	TRNE	T1,CR.IOP	;TRYING TO DO I/O?
	TRNN	T2,CI.BSY!CI.DON ;YES, IS BUSY OR DONE UP?
	JRST	CONEC1		;NO
;HERE WHEN WE ARE TRYING TO DO AN I/O OPERATION AND BUSY OR DONE
;IS STILL UP IN THE RH20 CONI.  TRY TO FORCE THE RH20 INTO A
;REASONABLE STATE, FIRST GENTLY AND, IF THAT FAILS, BY BLASTING IT.

	PUSH	P,T1		;SAVE FUNCTION
	PUSHJ	P,RDREG		;READ THE REGISTERS
	POP	P,T1		;RESTORE FUNCTION
	MOVSI	T2,UNPHNG+UNPFIR ;IF NOT IN ERROR RECOVERY,
	SKIPGE	UNIECT(U)	;  SET A FLAG
	MOVEM	T2,UNIECT(U)	;  FOR FILIO
	XCT	RNXCI2(J)	;GET THE CONI BACK
	MOVEI	T4,CO.MBE!CO.STP ;GET BITS TO CLEAR BUSY, SET DONE
	TRNE	T2,CI.BSY	;IS BUSY STILL UP?
	XCT	RNXCO4(J)	;YES, ATTEMPT TO CLEAR IT
	AOS	UNIHNG(U)	;COUNT THE OCCURRANCE
	MOVEI	T2,CO.MBE!CO.CLR ;GET BITS TO CLEAR DONE
	XCT	RNXCO2(J)	;DO SO
	XCT	RNXCI2(J)	;GET THE CONI BACK
	TRNE	T2,CI.BSY	;IS BUSY STILL SET?
	JRST	CONERR		;YES, CALL THE DRIVE DOWN
	TRNN	T2,CI.DON	;HOW ABOUT DONE?
	JRST	CONEC1		;CLEAR, CONTINUE WITH SETUP
	PUSHJ	P,CLRRH2	;BLAST THE RH20
	XCT	RNXCI2(J)	;GET THE CONI BACK
	TRNE	T2,CI.BSY!CI.DON ;DID WE MANAGE TO CLEAR IT UP?
	JRST	CONERR		;NO, GIVE UP AND CALL IT OFFLINE
;HERE WHEN THE RH20 IS IN SOME KIND OF REASONABLE STATE TO START THE
;OPERATION.  MAKE SURE THAT THE DX20 IS ALSO IN SOME REASONABLE STATE
;AND CONTINUE THE FINAL SETUP.

CONEC1:	SETZ	T4,		;LET THIS COMMAND GO THROUGH
CONEC2:	PUSHJ	P,MPRUN		;IS THE DX20 STILL RUNNING?
	  AOSA	T2,RNXRSC(J)	;NO, COUNT THIS
	JRST	CONEC3		;YES, CONTINUE
	CAIG	T2,MAXRSC	;ALREADY RESTARTED IT TOO MANY TIMES?
	PUSHJ	P,MPCHKS	;NO, TRY TO RESTART IT AGAIN
	  JRST	CONMPS		;FAILED, CALL THE DRIVE OFF-LINE
CONEC3:	JUMPN	T4,CONEC5	;DON'T TOUCH HARDWARE IF TOSSING COMMAND
	TRNE	T1,CR.IOP	;THIS AN I/O FUNCTION?
	TRNE	T1,CR.RED	;YES, A WRITE?
	JRST	CONEC4		;NO, DON'T CARE ABOUT WRITE PROTECT
	MOVSI	T2,UNPHWP	;GET HARDWARE WRITE PROTECT BIT
	TDNE	T2,UNIDES(U)	;IS THE UNIT WRITE PROTECTED?
	JRST	CONHWP		;YES
CONEC4:	MOVSI	T2,UNPOFL	;GET OFF-LINE BIT (SET BY CHKERR)
	TDNE	T2,UNIDES(U)	;DRIVE OFF-LINE?
	JRST	CONOFL		;YES
	PUSHJ	P,SETDRV	;SETUP TO TALK TO THAT DRIVE
	STORE	T2,RNXCMD(J),CM.DVA ;STORE DRIVE ADDRESS
CONEC5:	MOVE	T2,UNIBLK(U)	;GET THE BLOCK WE WANT TO ACCESS
	LDB	T3,UNYBPY##	;  AND THE NUMBER OF BLOCKS/CYLINDER
	IDIVI	T2,(T3)		;T2=CYLINDER, T3=REMAINDER
	MOVEM	T2,UNICYL(U)	;STORE IN UDB
	HRLI	T2,(.DXDCR)	;SETUP REGISTER SELECT FOR DCR
	PUSH	P,T2		;SAVE CYLINDER
	MOVE	T2,T3		;MOVE REMAINDER TO T2
	LDB	T3,UNYBPT##	;GET NUMBER OF BLOCKS PER TRACK
	IDIVI	T2,(T3)		;T2=TRACK, T3=BLOCK
	STORE	T2,T3,DA.TRK	;STORE IN CORRECT PLACE IN T3
	HRLI	T3,(.DXDAR)	;SETUP REGISTER SELECT FOR DAR
	JRST	T2POJ1##	;RESTORE T2 AND GIVE SKIP RETURN


;HERE WHEN AN ERROR WAS DETECTED IN EITHER THE RH20 OR DX20 DURING
;THE SETUP.  READ THE REGISTERS AND RETURN AN ERROR INDICATION TO FILIO.

CONHWP:	TDZA	T1,T1		;SET NO FLAGS IF WRITE PROTECTED
CONMPS:	PUSHJ	P,RNXSSB	;SET KOPMPS FOR KONTROLLER
CONOFL:	PUSHJ	P,RDREG		;READ THE REGISTERS
	JUMPE	T1,CPOPJ##	;GO IF HARDWARE WRITE PROTECTED
CONERR:	MOVEI	T1,KOPOFL	;SET BIT FOR OFF-LINE
	POPJ	P,		;  AND RETURN
;ROUTINE TO CHECK IF THE RH20 HAS A PI
;CALL:
;	J/KDB	ADDRESS
;	PUSHJ	P,RNXALV
;RETURN CPOPJ ALWAYS
RNXALV:	XCT	RNXCI2(J)	;CONI
	TRNE	T2,7		;IS IT ALIVE?
	POPJ	P,		;YES
	PUSHJ	P,CLRRH2	;NO, CLEAR THE RH
	PJRST	REASPI		;GIVE IT A PI AND RETURN
	SUBTTL	ERROR ANALYSIS ROUTINES


;ROUTINE TO CHECK TO SEE IF THE DX20 MICROCODE DETECTED AN ERROR
;IN THE LAST OPERATION.
;CALL:
;	J/KDB ADDRESS
;	T1/ERROR BITS
;	P1/FLAGS FROM RNXCMD OR 0 IF NO OPERATION IN PROGRESS
;	P2/ENDING STATUS REGISTER
;	P3/CHANNEL STATUS OR 0,,CONI
;	PUSHJ	P,CHKERR
;RETURN CPOPJ ALWAYS WITH AC'S AS ABOVE AND:
;	LH(P2)/ERROR REGISTER IF ERRORS

CHKERR:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNN	T2,ST.RUN	;IS MICROPROCESSOR STILL RUNNING?
	JRST	FTLERR		;NO
	TRNN	T2,ST.CER	;COMPOSITE ERROR UP?
	POPJ	P,		;NO, NO ERRORS
	MOVSI	T2,(.DXERR)	;POINT AT ERROR REGISTER
	PUSHJ	P,DODTI		;READ IT
	HRLI	P2,(T2)		;MOVE TO P2
	TLNE	P2,ER.ERR	;ANY GENERIC HARDWARE FAILURES?
	TRO	T1,IODERR	;YES, FLAG A DEVICE ERROR
	TLNN	P2,ER.UPE	;MICROPROCESSOR ERROR?
	POPJ	P,		;NO, CODE IS MEANINGLESS
	LOAD	T2,P2,<ER.ECC_^D18> ;GET ERROR CODE IN T2
	CAIL	T2,ERRTBL	;IN THE RANGE WE KNOW ABOUT?
	JRST	FTLERR		;NO, THAT'S FATAL
	JRST	@ERRTAB(T2)	;DISPATCH TO PROCESSING ROUTINE


;THE FOLLOWING TABLE GIVES THE DISPATCH ADDRESS FOR EACH CLASS OF ERROR.

ERRTAB:	EXP	FTLERR		;0  - UNKNOWN
	EXP	UDSERR		;1  - UNUSUAL DEVICE STATUS
	EXP	RLNERR		;2  - RECORD LENGTH ERROR
	EXP	SELERR		;3  - DEVICE SELECTION ERROR
	EXP	RCVERR		;4  - RECOVERABLE ERROR
	EXP	RTYERR		;5  - COMMAND RETRY REQUEST
	EXP	NRCERR		;6  - NON-RECOVERABLE ERROR
	EXP	LOGUPE		;7 -  RETRY LOG INFORMATION, LOG IT
	EXP	FTLERR		;10 - FATAL ERROR
	EXP	FTLERR		;11 - MICRODIAGNOSTIC FAILURE
	EXP	RLDERR		;12 - MICROCODE RELOAD FOR INFORMATION
ERRTBL==.-ERRTAB
;HERE ON UNUSUAL DEVICE STATUS

UDSERR:	TRNN	P2,ES.UCK	;UNIT CHECK UP IN ENDING STATUS BYTE?
	JRST	RCVERR		;NO, JUST CALL IT RECOVERABLE
	MOVEI	T2,.ESSB0	;INDEX INTO EST TO GET SENSE BYTES
	PUSHJ	P,RDEST		;READ SENSE BYTES 0-3
	  MOVEI	T2,0		;SHOULDN'T HAPPEN, DEFAULT TO ZERO BYTES
	JUMPE	P1,UDSER1	;DON'T KNOW DRIVE IF NO OPERATION
	MOVSI	T3,UNPHWP	;GET WRITE PROTECT BIT
	TLNE	T2,(S1.WRI)	;WRITE INHIBITED?
	IORM	T3,UNIDES(U)	;YES, SET THE BIT IN THE UDB
	TLNE	T2,(S0.IRQ)	;INTERVENTION REQUIRED?
	JRST	SELERR		;YES, CALL THE DRIVE OFF-LINE
UDSER1:	TLNE	T2,(S0.DTC)	;DATA CHECK?
	TROA	T1,IODTER	;YES, CALL IT A DATA ERROR
	TRO	T1,IODERR	;NO, FLAG A DEVICE ERROR
	MOVEI	T2,.ESSB7	;EST INDEX TO GET SENSE BYTE 7
	PUSHJ	P,RDEST		;READ IT (ACTUALLY 4-7)
	  MOVEI	T2,0		;SHOULDN'T HAPPEN, DEFAULT TO 0
	ANDI	T2,EB.S07	;KEEP JUST THE ONE BYTE
	CAIN	T2,.S7ECC	;ECC ERROR?
	TRO	T1,IOECCX	;YES, SET BIT FOR FILIO
	POPJ	P,		;RETURN

;HERE ON A RECORD LENGTH ERROR

RLNERR:	SKIPE	DINITF##	;IN ONCE-ONLY?
	TLNN	P1,(CM.IO)	;  AND DOING A READ?
	JRST	RLNER1		;NO
	TRNE	T1,ALLERR	;ANY OTHER ERRORS DETECTED SO FAR?
	POPJ	P,		;YES, THEY TAKE PRECEDENCE
	TDZ	P3,[CS.SWC!CS.OVR!CI.OVR] ;NO, MUST BE ONCE READING THE
	TLZA	P2,-1		;  HOME BLOCKS OF A TOPS20 FORMATTED PACK
RLNER1:	TRO	T1,IODERR	;ELSE FLAG A DEVICE ERROR
	POPJ	P,		;RETURN

;HERE ON A DEVICE SELECTION ERROR

SELERR:	MOVSI	T3,UNPOFL	;GET OFF-LINE BIT
	SKIPE	P1		;DON'T NO WHAT DRIVE IF NO OPERATION
	IORM	T3,UNIDES(U)	;MARK THE DRIVE OFF-LINE
;;	PJRST	RCVERR		;FALL INTO RCVERR

;HERE ON RECOVERABLE ERROR

RCVERR:	TRO	T1,IODERR	;FLAG DEVICE ERROR
	POPJ	P,		;RETURN
;HERE ON COMMAND RETRY REQUEST

RTYERR:	TRO	T1,IODERR	;FLAG DEVICE ERROR
	MOVSI	T2,(.DXFLG)	;POINT AT FLAG REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRZ	T2,FA.RTY	;CLEAR RETRY REQUEST BIT
	HRLI	T2,(.DXFLG)	;SET TO CLEAR IT
	PJRST	DODTO		;CLEAR BIT AND RETURN

;HERE ON NON-RECOVERABLE ERROR

NRCERR:

;HERE ON FATAL ERROR OR UNKNOWN CODE

FTLERR:	TRO	T1,IODERR	;FLAG DEVICE ERROR
	MOVSI	T2,(RN.FTL)	;FLAG THIS FOR CALL TO RNXERR
	IORM	T2,RNXFLG(J)	;  AS UNRECOVERABLE
	POPJ	P,		;RETURN
;HERE ON MICROCODE RELOAD.  DETERMINE WHICH UNITS ON THIS DX20
;ARE OFFLINE WAITING FOR OPERATOR INTERVENTION AND GIVE A FREE
;ATTENTION INTERRUPT TO FILIO FOR THOSE DRIVES.  THIS MEANS THAT
;RELOADING THE MICROCODE SHOULD BE SUFFICIENT TO RESTART ANY JOBS THAT
;ARE STOPPED WITH OFFLINE MESSAGES BECAUSE THE DX20 STOPPED.

RLDERR:	PUSHJ	P,LOGUPE	;LOG IT SINCE MPCHK WILL BLAST THE REGISTERS
	PUSHJ	P,MPCHKS	;MAKE SURE IT'S VALID MICROCODE
	  JRST	FTLERR		;IT'S NOT, CALL IT FATAL
	SETZM	RNXRSC(J)	;CLEAR RESTART COUNTER
	PUSHJ	P,RNXCSB	;CLEAR THE BIT IN THE KDB
	PUSHJ	P,SAVE2##	;SAVE P1-P2


;HERE FOR EACH KDB ASSOCIATED WITH THIS DX20 WITH THE KDB ADDRESS IN
;J TO LOOK AT ALL UDB'S TO SEE IF WE SHOULD GIVE FILIO AN ATTENTION
;INTERRUPT FOR THE UNIT.

RLDER1:	PUSH	P,U		;SAVE U
	MOVE	P1,KDBIUN(J)	;GET AOBJN POINTER TO UDB TABLE
	MOVEI	P2,0		;START WITH NO BITS TO SET
RLDER2:	HRRZ	U,(P1)		;GET THE NEXT KDB ADDRESS
	JUMPE	U,RLDER3	;GO IF NO UDB
	MOVE	T2,UNISTS(U)	;GET THE UNIT STATUS FOR THIS UDB
	MOVE	T3,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	CAIE	T2,OWCOD	;IS IT IN ONE OF THE STATES WAITING FOR
	CAIN	T2,OCOD		;  OPERATOR INTERVENTION?
	IOR	P2,BITTBL##(T3)	;YES, SET THE CORRESPONDING BIT IN P2
RLDER3:	AOBJN	P1,RLDER2	;LOOP FOR ALL UDB'S ON THIS KDB
	IORM	P2,RNXATN(J)	;SET THE APPROPRIATE ATTENTION BITS
	JRST	UPOPJ##		;RESTORE U AND RETURN
	SUBTTL	ERROR LOGGING ROUTINES


;ROUTINE TO READ THE "REGISTERS" INTO RNXEBK FOR THE RP20.
;ENTER AT RDREG FOR INTERNAL CALL.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXREG
;RETURN CPOPJ ALWAYS
;DESTROYS T2-T3

RNXREG:	PUSHJ	P,SETRH2	;SET IVI, MBE, PIA
RDREG:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVSI	T2,(.DIPBA)	;POINT AT RH20 PBAR
	PUSHJ	P,DODTIC	;READ IT
	MOVEM	T2,KONEDB(J)	;STORE IN KDB
	MOVSI	T2,(.DIPTC)	;POINT AT RH20 PTCR
	PUSHJ	P,DODTIC	;READ IT
	MOVEM	T2,KONECR(J)	;STORE IN KDB
	MOVE	T2,KDBICP(J)	;GET ADDRESS OF LOGOUT AREA
	MOVE	T2,.CSICW(T2)	;GET INITIAL CHANNEL JUMP WORD
	MOVEI	T3,0		;ASSUME NO IOWDS
	TRNE	T2,-1		;ANY ADDRESS?
	MOVE	T3,0(T2)	;YES, GET FIRST CCW
	MOVEM	T3,RNXEBK+.EBCC1(J) ;STORE IT
	TRNE	T2,-1		;ANY ADDRESS?
	MOVE	T3,1(T2)	;YES, GET SECOND CCW
	MOVEM	T3,RNXEBK+.EBCC2(J) ;STORE IT
	HRLZ	T2,KDBICP(J)	;GET LOGOUT AREA ADDRESS BACK
	HRRI	T2,RNXEBK+.EBCS0(J) ;MAKE IT A BLT POINTER
	BLT	T2,RNXEBK+.EBCS2(J) ;STORE LOGOUT AREA WORDS 0-2
	MOVE	T2,KDBCHN(J)	;GET ADDRESS OF CHANNEL DATA BLOCK
	MOVE	T3,CHNMPE(T2)	;GET COUNT OF MEMORY PARITY ERRORS
	MOVEM	T3,RNXEBK+.EBMPE(J) ;STORE IT
	MOVE	T3,CHNNXM(T2)	;GET COUNT OF NXM'S
	MOVEM	T3,RNXEBK+.EBNXM(J) ;STORE IT
	HLRZ	T2,KDBUNI(J)	;GET DX20 NUMBER
	LSH	T2,^D9		;SHIFT BY 9 BITS
	HRLM	T2,RNXEBK+.EBTYP(J) ;STORE IN KDB

				;CONTINUED ON THE NEXT PAGE
				;CONTINUED FROM THE PREVIOUS PAGE

;HERE TO STORE THE MASSBUS REGISTERS IN THE KDB.  WE ONLY SAVE THOSE
;REGISTERS SPECIFIED BY THE BIT TABLE MBRTBL.

	MOVE	T2,[.EBNMR,,.EBSMR-.EBMBR] ;GET POINTER TO MASSBUS REGS
	MOVEM	T2,RNXEBK+.EBMBR(J) ;STORE IN KDB
	MOVEI	P1,RNXEBK+.EBSMR(J) ;POINT TO START OF BLOCK
	MOVE	P2,[MBRTBL]	;GET BIT TABLE OF REGISTERS TO SAVE
RDREG1:	JUMPGE	P2,RDREG2	;IF BIT NOT SET, DON'T SAVE THIS ONE
	HLLZ	T2,P1		;GET REGISTER ADDRESS
	CAMN	T2,[.DXMIR]	;TRYING TO READ THE IR?
	TDZA	T2,T2		;YES, DO IT LATER
	PUSHJ	P,DODTI		;READ IT
	MOVEM	T2,(P1)		;STORE IN BLOCK
	HRRI	P1,1(P1)	;BUMP BLOCK POINTER BY 1
RDREG2:	ADD	P1,[1B5]	;PLUS REGISTER ADDRESS BY 1
	LSH	P2,1		;SHIFT BIT TABLE BY 1
	JUMPN	P2,RDREG1	;LOOP IF MORE TO READ
	PUSHJ	P,REDMIR	;CONDITIONALLY READ THE IR REGISTER

;HERE TO STORE THE DX20 REGISTERS IN THE KDB.  THE DX20 MUST BE RUNNING
;IN ORDER TO DO THIS SINCE WE REQUEST EACH REGISTER THROUGH THE
;EXTENDED STATUS TABLE.

	PUSHJ	P,MPRUN		;MICROPROCESSOR STILL RUNNING?
	  JRST	RDREG5		;NO, ZERO COUNT AND RETURN
	MOVSI	P1,-.EBNDR	;BUILD AOBJN POINTER TO REGISTERS
RDREG3:	MOVEI	T2,(P1)		;MOVE INDEX INTO EST TO T2 FOR RDEST
	PUSHJ	P,RDEST		;READ APPROPRIATE SENSE BYTES
	  JRST	RDREG4		;QUIT IF DX20 DIDN'T RESPOND
	MOVEI	T3,RNXEBK+.EBSDR(J) ;GET ADDRESS OF START OF BLOCK
	ADDI	T3,(P1)		;OFFSET INTO IT FOR THIS REGISTER
	MOVEM	T2,(T3)		;STORE REGISTER IN BLOCK
	AOBJN	P1,RDREG3	;LOOP FOR ALL REGISTERS
RDREG4:	MOVSS	P1		;PUT NUMBER OF REGISTERS IN LH
	HRRI	P1,.EBSDR-.EBDVL ;PUT OFFSET IN RH
	TLNN	P1,-1		;IF COUNT IS ZERO,
RDREG5:	MOVEI	P1,0		;ZERO THE WHOLE WORD
	MOVEM	P1,RNXEBK+.EBDVL(J) ;STORE IN KDB
	POPJ	P,		;RETURN
;ROUTINE TO CONDITIONALLY READ THE MICROPROCESSOR INSTRUCTION
;REGISTER.  WE DON'T DO THIS UNLESS THE MICROPROCESSOR IS STOPPED
;BECAUSE READING THE IR WITH IR ENABLE SET CAUSES IT TO BE LOADED
;FROM THE MICROSTORE LOCATION CURRENTLY POINTED TO BY THE PC.  THIS
;SOMETIMES CAUSES IR PARITY ERRORS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,REDMIR
;RETURN CPOPJ ALWAYS

REDMIR:	DMOVE	T2,RNXEBK+.EBSMR+.EBM00(J) ;GET CONTROL AND STATUS REGS
	TRNN	T2,CR.GO	;IS GO STILL UP?
	TRNE	T3,ST.RUN	;NO, IS THE UCODE STILL RUNNING?
	POPJ	P,		;YES, DON'T READ THE REGISTER
	MOVSI	T2,(.DXPCR)	;SETUP TO READ THE PC REGISTER
	PUSHJ	P,DODTI		;DO SO
	TRZ	T2,PC.IRE	;TURN OFF IR ENABLE
	HRLI	T2,(.DXPCR)	;PUT THE REGISTER NUMBER BACK
	PUSHJ	P,DODTO		;WRITE OFF IR ENABLE
	MOVSI	T2,(.DXMIR)	;POINT TO IR REGISTER
	PUSHJ	P,DODTI		;READ IT
	MOVEM	T2,RNXEBK+.EBSMR+.EBM30(J) ;STORE WHERE IT BELONGS
	POPJ	P,		;RETURN
;ROUTINE TO CALL DAEMON TO LOG AN ERROR THAT FILIO WILL NOT, E.G.,
;POSITIONING ERRORS, MICRODIAGNOSTICS FAILURES WHILE NO OPERATION
;IS IN PROGRESS, ETC.
;CALL:
;	J/KDB ADDRESS
;	P1/FLAGS FROM RNXCMD
;	P3/CHANNEL STATUS OR 0,,CONI
;	PUSHJ	P,LOGUPE
;RETURN CPOPJ ALWAYS

LOGUPE:	SKIPE	DINITF##	;IN ONCE-ONLY?
	POPJ	P,		;YES, CAN'T LOG THEM THIS EARLY
	PUSHJ	P,SAVT##	;SAVE T1-T4
	PUSHJ	P,SAVJW##	;AND KONTROLLER POINTERS
	PUSH	P,U		;  AND U
	PUSH	P,F		;  AND F
	MOVSI	T2,1		;COUNT THE NUMBER OF TIMES WE
	ADDM	T2,RNXEC1(J)	;  WERE CALLED TO LOG AN ERROR
	PUSHJ	P,RDREG		;READ THE REGISTERS
	HRRZ	U,KDBIUN(J)	;GET BASE ADDRESS OF UDB TABLE
	LOAD	T2,P1,CM.UNF	;GET UNIT NUMBER FOR OPERATION
	ADDI	U,(T2)		;OFFSET TO CORRECT WORD IN TABLE
	HRRZ	U,(U)		;GET UDB ADDRESS
	JUMPE	U,FUPOPJ##	;QUIT IF NO UDB
	SKIPL	UNIECT(U)	;IF THIS UDB IS IN ERROR RECOVERY, DON'T
	JRST	FUPOPJ##	;OVERWRITE THE (MORE IMPORTANT) DATA
	MOVEI	F,DSKDDB##	;GET THE GENERIC DDB
	PUSHJ	P,FSTREG##	;COPY INITIAL REGISTERS TO UDB
	PUSHJ	P,LSTER##	;  PLUS FINAL REGISTERS
	MOVEM	P3,UNISOF(U)	;STORE INITIAL CONI
	MOVEM	P3,UNIERR(U)	;  AND FINAL CONI
	MOVE	W,J		;MOVE KDB POINTER FOR ERROR ROUTINE
	SETZ	J,		;BLAME JOB 0
	MOVEI	T4,(F)		;'SOFT CODE' FOR THIS CASE
	AOS	SYSERR##	;IT'S A SYSTEM ERROR
	PUSHJ	P,RNXELG	;TELL DAEMON
	JRST	FUPOPJ##	;RESTORE F, U AND RETURN
;ROUTINE CALLED FROM FILIO TO NOTIFY OF DAEMON OF AN ERROR WITH A
;SYSTEM ERROR BLOCK.  SEE MDEERR IN FILIO FOR CALLING SEQUENCE DETAILS.

RNXELG:	MOVEI	T1,45+1		;TABLE ENTRIES PLUS FILSER CODE
	HLRZ	T2,UNIEBK+.EBMBR(U) ;GET NUMBER OF MASSBUS REGS SAVED
	ADDI	T1,(T2)		;INCLUDE IN DESIRED LENGTH
	HLRZ	T2,UNIEBK+.EBDVL(U) ;GET NUMBER OF DEVICE REGS SAVED
	ADDI	T1,(T2)		;INCLUDE THAT, TOO
	PUSH	P,T4		;SAVE FILIO'S CODE
	PUSH	P,T1		;AND THE TOTAL LENGTH WE REQUESTED
	PUSHJ	P,ALCSEB##	;GET A BLOCK OF THE DESIRED SIZE
	  JRST	TTPOPJ##	;PUNT IF NO CORE
	POP	P,T4		;RESTORE THE LENGTH
	ADD	T4,T1		;OFFSET FOR END+1
	POP	P,.EBHDR-1(T4)	;STORE LAST ENTRY FIRST
	XMOVEI	T2,ELGBEG	;POINT TO XFER TABLE
	PUSHJ	P,XFRSEB##	;MOVE SOME DATA
	  JFCL			;CAN'T FAIL HERE
	MOVE	T3,UNIUSC(U)	;GET USER SEEKS
	ADDM	T3,.EBHDR+07(T1) ;UPDATE MONITOR SEEKS TO TOTAL UNIT SEEKS
	MOVE	T3,UNIDRC(U)	;GET DUMP READ COUNT
	ADD	T3,UNIMRC(U)	;ADD IN MONITOR READ COUNT
	ADDM	T3,.EBHDR+10(T1) ;UPDATE BUFFERED READS TO TOTAL UNIT READS
	MOVE	T3,UNIDWC(U)	;GET DUMP WRITES
	ADD	T3,UNIMWC(U)	;ADD IN MONITOR WRITES
	ADDM	T3,.EBHDR+11(T1) ;UPDATE BUFFERED WRITES TO TOTAL UNIT WRITES
	HRLZ	T3,KDBDVC(W)	;GET DEVICE CODE/4
	LSH	T3,2		;MAKE REAL DEVICE CODE
	IOR	T3,UNIEBK+.EBTYP(U) ;INCLUDE DX20 ADDRESS
	HLLM	T3,.EBHDR+02(T1) ;UPDATE SPEAR DEVICE INFO
	XMOVEI	T4,.EBHDR+45(T1) ;POINT TO START OF DYNAMIC SPACE
	XMOVEI	T3,UNIEBK+.EBSMR(U) ;POINT TO START OF SAVED MASSBUS REGS
	HLRZ	T2,UNIEBK+.EBMBR(U) ;GET COUNT OF SAVED MASSBUS REGS
	JUMPE	T2,RNXEL1	;SKIP THIS IF NONE TO SAVE
	EXTEND	T2,[XBLT]	;COPY THE DATA, UPDATING POINTER IN T4
	MOVEI	T2,43		;RELATIVE POINTER
	ADDM	T2,.EBHDR+43(T1) ;UPDATE THE WAY DAEMON USED TO
RNXEL1:	XMOVEI	T3,UNIEBK+.EBSDR(U) ;POINT TO START OF SAVED DEVICE REGS
	HLRZ	T2,UNIEBK+.EBDVL(U) ;GET COUNT OF SAVED DEVICE REGS
	JUMPE	T2,RNXEL2	;SKIP THIS IF NONE
	EXTEND	T2,[XBLT]	;MOVE THE DATA
	MOVEI	T2,44		;RELATIVE POINTER
	ADDM	T2,.EBHDR+44(T1) ;UPDATE FOR SPEAR
RNXEL2:	PJRST	QUESEB##	;GIVE IT TO DAEMON AND RETURN

ELGBEG:	SEBTBL(.ERDXE,ELGEND,)	;START OUR XFER TABLE
	MOVE	UDBNAM(U)	;(R00) UNIT PHYSICAL NAME
	MOVE	UNILOG(U)	;(R01) LOGICAL UNIT NAME
	MOVEI	2		;(R02) RH20/DISK CODE
	MOVE	UNIHBN(U)	;(R03) BLOCK IN ERROR
	MOVE	UNIECT(U)	;(R04) FINAL ERROR STATE
	MOVE	UNISOF(U)	;(R05) 1CONI
	MOVE	UNIERR(U)	;(R06) 2CONI
	MOVE	UNIMSC(U)	;(R07) TOTAL UNIT SEEKS
	MOVE	UNIBRC(U)	;(R10) TOTAL UNIT READS
	MOVE	UNIBWC(U)	;(R11) TOTAL UNIT WRITES
	MOVE	DEVFIL(F)	;(R12) FILENAME
	MOVE	JBTPPN##(J)	;(R13) USER'S PPN
	MOVE	JBTNAM##(J)	;(R14) USER'S PROGRAM NAME
	MOVE	UNISCR(U)	;(R15) DATAI PTCR INITIAL
	MOVE	UNIHCR(U)	;(R16) DATAI PTCR FINAL
	MOVE	UNISDR(U)	;(R17) DATAI PBAR INITIAL
	MOVE	UNIHDR(U)	;(R20) DATAI PBAR FINAL
	MOVE	UNIHCT(U)	;(R21) HARD ERROR COUNTS
	MOVE	UNISCT(U)	;(R22) SOFT ERROR COUNTS
	MOVE	UNIMCT(U)	;(R23) SOFTWARE DETECTED ERRORS
	MOVE	UNIHNG(U)	;(R24) HUNG COUNTS
	SETZ			;(R25) UNUSED
	SETZ			;(R26) UNUSED
	MOVE	UNIEBK+.EBCS0(U) ;(R27) CHANNEL LOGOUT 0
	MOVE	UNIEBK+.EBCS1(U) ;(R30) CHANNEL LOGOUT 1
	MOVE	UNIEBK+.EBCS2(U) ;(R31) CHANNEL LOGOUT 2
	MOVE	UNIEBK+.EBCC1(U) ;(R32) FIRST CCW
	MOVE	UNIEBK+.EBCC2(U) ;(R33) SECOND CCW
	MOVE	UNIEBK+.EBMPE(U) ;(R34) COUNT OF MP ERRORS
	MOVE	UNIEBK+.EBNXM(U) ;(R35) COUNT OF CHANNEL NXM
	SETZ			;(R36) UNUSED
	SETZ			;(R37) UNUSED
	SETZ			;(R40) UNUSED
	MOVE	UNIEBK+.EBICR(U) ;(R41) INITIAL CONTROL REGISTER
	HRRZ	UNIEBK(U)	;(R42) MICROCODE VERSION NUMBER
	MOVE	UNIEBK+.EBMBR(U) ;(R43) POINTER TO MASSBUS REGS
	MOVE	UNIEBK+.EBDVL(U) ;(R44) POINTER TO DX20 REGS
ELGEND:!			;END OF TRANSFER DATA
;ROUTINE TO REQUEST AND THEN READ INFORMATION FROM THE TWO EXTENDED
;STATUS REGISTERS IN THE DX20.  THE INFORMATION THAT IS RETURNED IS
;A FUNCTION OF THE VALUE OF THE STATUS INDEX WHICH IS AN INPUT ARGUMENT
;TO THIS ROUTINE.
;CALL:
;	T2/STATUS INDEX
;	J/KDB ADDRESS
;	PUSHJ	P,RDEST
;RETURN CPOPJ IF THE DX20 DIDN'T RESPOND TO THE HANDSHAKE
;	CPOPJ1 IF WE GOT THE DATA WITH:
;	T2/.DXES1,,.DXES2

RDEST:	PUSHJ	P,SAVE1##	;GET A REGISTER TO USE
	IOR	T2,[.DXESR!ES.SUI] ;SET REGISTER AND REQUEST UPDATE
	PUSHJ	P,DODTO		;ASK THE DX20 FOR THE REGISTERS
	MOVEI	P1,^D1000	;TIME TO WAIT FOR THE BIT TO CLEAR
RDEST1:	MOVSI	T2,(.DXESR)	;POINT TO STATUS INDEX REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,ES.SUI	;DID THE DX20 CLEAR THE BIT YET?
	SOJG	P1,RDEST1	;NO, LOOP
	JUMPLE	P1,CPOPJ##	;RETURN NON-SKIP IF THE DX20 DIDN'T RESPOND
	MOVSI	T2,(.DXES2)	;POINT AT SECOND EXTENDED STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	PUSH	P,T2		;SAVE FOR LATER
	MOVSI	T2,(.DXES1)	;POINT AT FIRST REGISTER
	PUSHJ	P,DODTI		;READ IT
	HRLM	T2,0(P)		;STORE IN LH OF STACK LOCATION
	JRST	T2POJ1##	;GIVE SKIP RETURN WITH VALUE IN T2
	SUBTTL	MISCELLANEOUS SUPPORT SUBROUTINES


;ROUTINE TO SET .DXDNM TO THE DRIVE NUMBER OF THE DRIVE FOR WHICH
;WE ARE ABOUT TO PERFORM AN OPERATION.
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,SETDRV
;RETURN CPOPJ ALWAYS WITH:
;	RH(T2)/DRIVE ADDRESS
;DESTROYS T3

SETDRV:	MOVE	T2,UDBPDN(U)	;PHYSICAL DRIVE NUMBER FROM UDB
	LDB	T3,RNYDCA	;GET CONTROL UNIT ADDRESS FROM KDB
	LSH	T3,4		;POSITION IT
	IOR	T2,T3		;BUILD FULL DRIVE ADDRESS
;;	PJRST	WDVNUM		;FALL INTO WDVNUM


;ROUTINE TO SET .DXDNM TO THE DRIVE NUMBER OF THE DRIVE FOR WHICH
;WE ARE ABOUT TO PERFORM AN OPERATION
;CALL:
;	T2/DRIVE ADDRESS
;	J/KDB ADDRESS
;	PUSHJ	P,WDVNUM
;RETURN CPOPJ ALWAYS WITH:
;	RH(T2)/DRIVE ADDRESS

WDVNUM:	HRLI	T2,(.DXDNM)	;GET REGISTER TO WRITE
	PJRST	DODTO		;WRITE REGISTER AND RETURN
;ROUTINE TO WAIT FOR A COMMAND TO COMPLETE AND CALL RNXINR TO PROCESS
;IT BEFORE STARTING A NEW COMMAND.
;CALL:
;	T1/CURRENT COMMAND
;	T4/FLAGS FROM RNXCMD FOR OLD COMMAND
;	U/UDB ADDRESS
;	J/KDB ADDRESS
;	PUSHJ	P,CMDWAT
;RETURN CPOPJ ALWAYS WITH:
;	T4/NON-ZERO TO TOSS THIS COMMAND
;PRESERVES T1, U

CMDWAT:	AOS	RNXEC2(J)	;COUNT NUMBER OF TIMES WE GOT HERE
	JUMPGE	T4,CMDWA2	;GO IF PREVIOUS COMMAND NOT AN XFER
	PUSHJ	P,RDREG		;READ THE REGISTERS FOR THE DUMP
	STOPCD	CPOPJ##,DEBUG,KCP, ;++KDB COMMAND IN PROGRESS
CMDWA2:	MOVEI	T2,^D2000	;WAIT FOR THE COMMAND
	PUSHJ	P,WGOCLR	;  TO FINISH
	JUMPLE	T2,CMDWA3	;JUMP IF GO STILL UP
	PUSHJ	P,SAVE3##	;RNXINR DESTROYS P1-P2
	PUSH	P,T1		;  AND T1
	PUSH	P,U		;  AND U
	PUSHJ	P,RNXINR	;DO SUBSET OF INTERRUPT PROCESSING
	POP	P,U		;RESTORE U
	SETZ	T4,		;LET THIS COMMAND THROUGH
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

;HERE IF THE GO BIT DIDN'T COME DOWN IN TIME.
;EXIT FROM THE NEW COMMAND WITHOUT DOING ANYTHING.
;WAIT FOR THE PREVIOUS COMMAND TO FINISH, THEN TELL
;FILIO THAT THE NEW COMMAND IS FINISHED (THIS IS A LIE).
;IF THE NEW COMMAND IS A TRANSFER, THEN TELL FILIO "POSITION DONE".
;FILIO WILL THINK HE'S IN THUNG RECOVERY AND WILL RE-ISSUE THE
;TRANSFER COMMAND.
;IF THE NEW COMMAND IS A POSITION, THEN TELL FILIO "RECAL DONE".
;FILIO WILL THINK HE'S IN PHUNG RECOVERY AND WILL RE-ISSUE THE
;POSITION COMMAND.
CMDWA3:	MOVSI	T4,(1B0)	;RECAL BIT (PHUNG RECOVERY)
	CAIN	T1,.DXCTR!.CRSRC;POSITION COMMAND?
	IORM	T4,UNISTS(U)	;YES, TELL FILIO "RECAL DONE"
	MOVE	T4,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	MOVE	T4,BITTBL##(T4)	;GET CORRESPONDING BIT
	IORM	T4,RNXATN(J)	;SET IN KDB FOR INTERRUPT
	MOVSI	T4,1		;COUNT THIS EVENT
	ADDM	T4,RNXEC2(J)	;  IN THE KDB
	POPJ	P,		;RETURN WITH T4 NON-ZERO
;ROUTINE TO WAIT FOR THE GO BIT TO CLEAR IN THE CONTROL REGISTER.
;CALL:
;	J/KDB ADDRESS
;	T2/LOOP COUNT TO WAIT BEFORE TIMING OUT
;	PUSHJ	P,WGOCLR
;RETURN CPOPJ ALWAYS WITH:
;	T2/LOOP COUNT AT WHICH GO BIT CLEARED
;DESTROYS T2,T3

WGOCLR:	PUSH	P,T2		;SAVE LOOP COUNT
WGOCL1:	MOVSI	T2,(.DXCTR)	;POINT AT CONTROL REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNN	T2,CR.GO	;GO BIT STILL UP?
	JRST	T2POPJ##	;NO, RETURN
	SOSLE	0(P)		;DECREMENT LOOP COUNT
	JRST	WGOCL1		;AND LOOP
	AOS	RNXEC1(J)	;COUNT NUMBER OF TIMES GO BIT DIDN'T CLEAR
	JRST	T2POPJ##	;TIMED OUT, RETURN ANYWAY
;ROUTINE TO CLEAR THE ATTENTION SUMMARY REGISTER FOR THIS DX20.  WE
;ALSO CHECK TO MAKE SURE THAT NO SPURIOUS ATTENTION BITS HAVE COME UP
;FOR SOME OTHER DEVICE ON THIS RH20 AND MAKE SURE THAT THEY ARE
;CLEARED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CLRATN
;RETURN CPOPJ ALWAYS
;DESTROYS T2,T3

CLRATN:	PUSH	P,T4		;SAVE T4 (SEE RNXCPY)
	MOVEI	T4,1		;GET A BIT TO SHIFT
	HLRZ	T2,KDBUNI(J)	;GET DX20 MASSBUS UNIT NUMBER
	LSH	T4,(T2)		;SHIFT TO CORRECT POSITION
	HRLS	T4		;COPY TO LH
	TLC	T4,AT.ATN	;MAKE IT ALL BUT THAT BIT IN LH
	MOVSI	T2,(.DXASR)	;SET TO READ ATTENTION SUMMARY REGISTER
	PUSHJ	P,DODTI		;READ IT
;	TSNE	T2,T4		;ANY UNEXPECTED ATTENTION BITS SET?
;	PUSHJ	P,LOGUPE	;YES, LOG THIS AS AN ERROR
	TRNN	T2,AT.ATN	;ANY ATTENTION BITS TO CLEAR?
	JRST	CLRAT2		;NO, EXIT
	HRLI	T2,(.DXASR)	;SET TO CLEAR THE BITS WE READ
	PUSHJ	P,DODTO		;CLEAR THE ATTENTION BITS
	MOVSI	T2,(.DXASR)	;SET TO READ THE REGISTER AGAIN
	PUSHJ	P,DODTI		;READ IT
	TSNE	T2,T4		;STILL HAVE UNEXPECTED BITS SET?
	JRST	CLRAT1		;YES, HAVE TO BLAST THE RH20 THEN
	TDNN	T2,T4		;STILL HAVE THE DX20 BIT UP?
	JRST	CLRAT2		;NO, EXIT
	AOS	T2,RNXAEC(J)	;INCREMENT RETRY COUNT OF TIMES TO CLEAR IT
	TLZ	T2,-1		;CLEAR LEFT HALF
	CAIG	T2,ATNRTY	;FAIL TO CLEAR IT TOO MANY TIMES?
	JRST	T4POPJ##	;BELOW THE THRESHOLD, JUST EXIT
;	PUSHJ	P,LOGUPE	;LOG THIS AS AN ERROR
CLRAT1:	MOVSI	T2,1		;INCREMENT THE LEFT HALF TO
	ADDM	T2,RNXAEC(J)	;  INDICATE THAT WE DID SOMETHING
	PUSHJ	P,CLRRH2	;BLAST THE RH20 TO CLEAR THE BITS
CLRAT2:	HLLZS	RNXAEC(J)	;CLEAR RH OF RETRY COUNT WORD
	JRST	T4POPJ##	;RESTORE T4 AND EXIT


;The calls to LOGUPE are not assembled because CLRATN is called from
;RNXCPY without P1 and P3 containing the data that LOGUPE wants in
;those ACs.  We really need a BUGCHK mechanism for this kind of
;thing.
;ROUTINE TO CLEAR THE ERROR REGISTER IN THE DX20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CLRERG
;RETURN CPOPJ ALWAYS
;DESTROYS T2,T3

CLRERG:	MOVSI	T2,(.DXERR)	;POINT AT ERROR REGISTER
	PJRST	DODTO		;CLEAR IT AND RETURN


;ROUTINES TO SET/CLEAR KOPMPS IN THE KDB WHEN THE MICROPROCESSOR
;STOPS/RESTARTS.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNX?SB
;RETURN CPOPJ ALWAYS
;DESTROYS T2

RNXCSB::SKIPA	T2,[ANDCAM T2,KONMPS(J)] ;GET INSTR TO CLEAR BIT
RNXSSB:	MOVE	T2,[IORM T2,KONMPS(J)]  ;OR INSTR TO SET BIT
	PUSH	P,T2		;SAVE INSTRUCTION
	MOVSI	T2,KOPMPS	;GET THE BIT
	XCT	0(P)		;SET/CLEAR IT
	JRST	T2POPJ##	;BRING STACK INTO PHASE AND RETURN
;ROUTINE TO READ THE DRIVE TYPE REGISTER FOR THE DX20 AND CHECK
;TO MAKE SURE THAT IT IS CORRECT FOR THE RP20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CHKDTR
;RETURN CPOPJ IF NOT A DX20 FOR AN RP20
;	CPOPJ1 IF MATCH WITH:
;	T2/CONTENTS OF REGISTER

CHKDTR:	MOVSI	T2,(.DXDTR)	;POINT AT DRIVE TYPE REGISTER
	PUSHJ	P,DODTI		;READ IT
	PUSH	P,T2		;SAVE FOR RETURN
	ANDI	T2,DT.COD	;MASK OFF JUST THE DRIVE TYPE
	CAIN	T2,.DTCOD	;DOES IT MATCH?
	AOS	-1(P)		;YES, GIVE SKIP RETURN
	PJRST	T2POPJ		;RETURN VALUE IN T2


;ROUTINE TO ASSIGN AN INTERRUPT VECTOR ADDRESS TO THE RH20 AND
;GIVE IT A PIA WITH OR WITHOUT ATTENTION INTERRUPT ENABLE DEPENDING
;ON WHAT'S HAPPENING.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,SETRH2
;RETURN CPOPJ ALWAYS
;PRESERVES ALL AC'S

SETRH2:	PUSHJ	P,RNXIVI	;ASSIGN IVI, ENABLE MASSBUS
;	PJRST	REASPI		;FALL INTO REASPI


;ROUTINE TO REASSIGN THE PIA FOR THE RH20 WITH OR WITHOUT ATTENTION
;INTERRUPT ENABLE DEPENDING ON WHAT'S HAPPENING.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,REASPI
;RETURN CPOPJ ALWAYS
;PRESERVES ALL AC'S

REASPI:	PUSH	P,T4		;SAVE T4
	PUSHJ	P,SETCO		;SETUP CONO MASK
	XCT	RNXCO4(J)	;LIGHT PIA, POSSIBLY AIE
	JRST	T4POPJ##	;RESTORE T4 AND RETURN
;ROUTINE TO FORCE THE RH20 AND CONNECTED DEVICES INTO A KNOWN STATE.
;THIS INVOLVES DOING A MASSBUS INIT, A STOP TRANSFER, AND A CLEAR
;DONE.  WE THEN HAVE TO REASSIGN THE RH20 IVI AND RESTART THE MICRO-
;PROCESSOR.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,CLRRH2
;RETURN CPOPJ ALWAYS

CLRRH2:	MOVEI	T2,CO.MBI	;THE ONLY THING LEFT TO DO IS TO
	XCT	RNXCO2(J)	;  BLAST THE RH20. DO A MASSBUS INIT FIRST
	MOVEI	T2,CO.MBE!CO.STP ;THEN A
	XCT	RNXCO2(J)	;  STOP TRANSFER
	MOVEI	T2,CO.MBE!CO.CLR ;AND FINALLY A
	XCT	RNXCO2(J)	;  CLEAR DONE
	PUSHJ	P,RNXIVI	;GIVE IT AN IVI AGAIN SINCE MBI BLASTS IT
	PJRST	RNXMPS		;START THE MICROPROCESSOR GOING AGAIN
;ROUTINE TO ASSIGN AN INTERRUPT VECTOR ADDRESS TO THE RH20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXIVI
;RETURN CPOPJ ALWAYS
;PRESERVES ALL AC'S

RNXIVI:	PUSHJ	P,SAVT##	;SAVE T1-T4
	MOVEI	T2,CO.MBE	;ENABLE MASSBUS TRANSCEIVERS
	XCT	RNXCO2(J)	;  FIRST
	MOVEI	T2,40+DSKCHN##_1 ;COMPUTE INTERRUPT ADDRESS
	HRLI	T2,(.DOIVI)	;POINT TO PROPER REGISTER
	PJRST	DODTO		;WRITE REGISTER AND RETURN


;ROUTINE TO SETUP A CONO MASK WITH THE PIA AND POSSIBLY ATTENTION
;INTERRUPT ENABLE IF NO TRANSFER IS TAKING PLACE.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,SETCO
;RETURN CPOPJ ALWAYS WITH:
;	T4/CONO MASK

SETCO:	MOVEI	T4,CO.MBE+DSKCHN## ;SET TO ENABLE MASSBUS TRANSCEIVERS
	SKIPL	RNXCMD(J)	;TRANSFER IN PROGRESS?
	TRO	T4,CO.AIE	;NO, ALLOW INTERRUPTS ON ATTENTIONS
	POPJ	P,		;RETURN
;ROUTINE TO SET A BIT IN RNXATN CORRESPONDING TO A DRIVE NUMBER
;WHICH JUST COMPLETED A POSITION OPERATION.
;CALL:
;	T2/DRIVE NUMBER (ALL 4 BITS)
;	PUSHJ	P,POSDON
;RETURN CPOPJ ALWAYS

POSDON:	MOVE	T3,BITTBL##(T2)	;GET THE APPROPRIATE BIT
	IORM	T3,RNXATN(J)	;SET BIT IN KDB
	HRRZ	T3,T2		;COPY 4 BIT DRIVE ADDRESS
	ADD	T3,KDBIUN(J)	;POINT AT UDB ADDRESS SLOT IN KDB
	SKIPN	T3,(T3)		;GET UDB ADDRESS
	JRST	POSDO3		;NO UDB, CALL NEWDSK
	MOVSI	T2,UNPHWP	;GET HARDWARE WRITE PROTECT BIT
	SKIPE	T4,UNISTS(T3)	;UNIT IDLE?
	CAIL	T4,OWCOD	; OR SOME FORM OF OPERATOR WAIT?
	ANDCAM	T2,UNIDES(T3)	;CLEAR HARDWARE WRITE PROTECT BIT
	POPJ	P,		;RETURN

;HERE IF THERE WAS NO UDB FOR THE DRIVE. CALL NEWDSK TO TELL THE
;MONITOR THAT A NEW DRIVE JUST CAME ON-LINE.  T2 CONTAINS THE 4 BIT
;DRIVE ADDRESS OF THE UNIT THAT CAME ON-LINE.

POSDO3:	PUSH	P,T2		;SAVE DRIVE NUMBER
	MOVE	T2,BITTBL##(T2)	;GET ASSOCIATED BIT
	IORM	T2,RNXNUM(J)	;TELL ONCE A SECOND CODE WHAT TO DO
	HRROS	KDBNUM(J)	;FLAG IT FOR OUTSIDE WORLD TOO
	POP	P,T2		;RESTORE T2
	POPJ	P,		;AND RETURN
	SUBTTL	INITIALIZATION SUPPORT SUBROUTINES


;ROUTINE TO DO TWO TEST I/O COMMANDS TO A PARTICULAR DRIVE TO SEE
;IF IT IS ON-LINE.  TWO COMMANDS ARE REQUIRED BECUASE SOMETIMES THE
;8000 LIES AND SAYS THE DRIVE IS ON-LINE WHEN IT ISN'T AND THE FIRST
;ATTEMPT TO ACCESS THE DRIVE CAUSES OFF-LINE MESSAGES.  TWO TEST I/O'S
;ALWAYS SEEM TO WORK (IF YOU BELIEVE...)
;CALL DOTIOC IF THE CONTROLLER AND DRIVE NUMBERS HAVE ALREADY BEEN
;WRITTEN INTO MASSBUS REGISTER .DXDNM.  THIS ENTRY POINT DOES NOT
;REQUIRE THAT U BE SETUP TO THE UDB ADDRESS.
;CALL:
;	U/UDB ADDRESS
;	J/KDB ADDRESS
;	PUSHJ	P,DO2TIO
;RETURN CPOPJ IF THE DX20 DIDN'T RESPOND
;	CPOPJ1 IF IT PROCESSED BOTH COMMANDS

DO2TIO:	PUSHJ	P,SETDRV	;SETUP TO TALK TO THE DRIVE
DOTIOC:	MOVSI	T2,<(.DXFLG)>+INSVL.(.FATIO,FA.FNC) ;TELL THE DX20
	PUSHJ	P,DODTO		;  THAT IT'S A TEST I/O
	PUSHJ	P,DO2TI1	;DO THE FIRST TEST I/O
	  POPJ	P,		;RETURN IF THE DX20 DIDN'T RESPOND
DO2TI1:	PUSHJ	P,CLRERG	;CLEAR THE ERROR REGISTER
	MOVEI	T2,.DXCTR!.CRNOP ;NO-OP IS THE GENERIC COMMAND
	PUSHJ	P,DODTO		;START IT GOING
	MOVEI	T2,^D5000	;MAX TIME TO WAIT FOR IT TO FINISH
	PUSHJ	P,WGOCLR	;WAIT FOR THE GO BIT TO CLEAR
	JUMPG	T2,CPOPJ1##	;GIVE SKIP RETURN IF THE BIT CLEARED
	POPJ	P,		;NON-SKIP IF IT DIDN'T


;ROUTINE TO CHECK FOR ERRORS IN THE TEST I/O SEQUENCE DONE TO
;SEE IF A UNIT IS ON-LINE.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,INIERR
;RETURN CPOPJ IF DRIVE IS ON-LINE
;	CPOPJ1 IF DRIVE EXISTS BUT IS OFF-LINE
;	CPOPJ2 IF DRIVE DOESN'T EXIST

INIERR:	MOVSI	T2,(.DXERR)	;POINT TO THE ERROR REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNN	T2,ER.UPE!ER.STP!ER.ERR	;ANY ERRORS SEEN?
	POPJ	P,		;NO, DRIVE IS ON-LINE
	LOAD	T2,T2,ER.ECC	;GET ERROR CLASS CODE
	CAIE	T2,.ERSEL	;WAS IT SELECT ERROR?
	JRST	CPOPJ1##	;NO, IT EXISTS BUT IT'S OFF-LINE
	JRST	CPOPJ2##	;ELSE IT DOESN'T EXIST
;AUTOCONFIGURE
;ENTERED WITH DEVICE CODE/4 IN T1, AND CONI DEV, IN T2

RNXCFG:	CAIL	T1,FSTICD/4	;AN RH20?
	CAILE	T1,LSTICD/4	;...
	JRST	CPOPJ1##	;WRONG DRIVER
	TLNE	T2,(CI.PPT)	;IPA CHANNEL?
	JRST	CPOPJ1##	;YES
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	SETZB	P1,P2		;MASSBUS UNIT NUMBER 0, DRIVE 0 & COUNT

RNXCF1:	PUSHJ	P,RNXUNI	;AUTOCONFIGURE A SINGLE MASSBUS UNIT
	HLLOS	P1		;RESET DRIVE NUMBER
	AOBJN	P1,.+1		;ADVANCE TO NEXT MASSBUS UNIT
	TLNN	P1,10		;CHECKED ALL UNITS?
	JRST	RNXCF1		;LOOP BACK FOR ANOTHER
	SKIPN	P2		;FOUND AT LEAST A KDB?
	AOS	(P)		;NO--MUST TRY ANOTHER DRIVER
	POPJ	P,		;RETURN
;AUTOCONFIGURE A SINGLE MASSBUS UNIT
RNXUNI:	PUSHJ	P,RDDTR##	;READ DRIVE TYPE REGISTER
	CAIE	T2,TY.DXB	;IS IT A DX20/DISK?
	POPJ	P,		;NO--GIVE UP
	MOVSI	T1,CP.RH2	;RH20 CHANNEL
	PUSHJ	P,AUTCHN##	;BUILD A CHANNEL DATA BLOCK
	  POPJ	P,		;NO CORE
	HLRZ	T1,P1		;GET MASSBUS UNIT NUMBER
	MOVEI	T2,TYPRN	;UNIT TYPE CODE
	PUSHJ	P,DSKKON##	;BUILD A DISK KDB
	  POPJ	P,		;GIVE UP IF NO CORE
	AOS	P2		;REMEMBER WE FOUND AT LEAST A KDB
	MOVSI	T1,-<RNXIOE-RNXIOB> ;NUMBER OF WORDS TO CHECK
	XMOVEI	T2,RNXIOB(J)	;STARTING WORD
	HRRZ	T3,.CPDVC##	;<DEVICE CODE>/4
	PUSHJ	P,AUTDVC##	;SET DEVICE CODES
	MOVE	T1,KDBCSO(J)	;GET CONSO SKIP CHAIN ADDRESS
	MOVEI	T2,CI.RAE!CI.ATN!CI.DON ;AND INTERRUPT FLAGS
	HRRM	T2,DICDIF##(T1)	;SET THEM

RNXUN1:	PUSHJ	P,MPRES		;RESET THE MICROPROCESSOR
	PUSHJ	P,RNXRLD	;LOAD THE MICROCODE
	  POPJ	P,		;GIVE UP
	HRRZS	P2		;CLEAR VALID DCU FLAG (SIGN BIT)
	MOVSI	P3,-MAXDCU	;INIT DCU NUMBER

RNXUN2:	PUSHJ	P,RNXDRV	;AUTOCONFIGURE A SINGLE DRIVE
	  JFCL			;IGNORE ERRORS
	HRRZ	T1,P1		;GET DRIVE NUMBER
	CAIGE	T1,RNXDMX-1	;DONE ALL DRIVES?
	AOJA	P1,RNXUN2	;LOOP BACK FOR MORE
	POPJ	P,		;ALL DONE
;AUTOCONFIGURE A SINGLE DRIVE
RNXDRV:	HRRZ	T1,P1		;GET UNIT
	MOVE	T1,BITTBL##(T1)	;AND IT'S BIT
	TDNE	T1,RNXIUM(J)	;WANT TO IGNORE THIS DRIVE?
	POPJ	P,		;SAY IT DOESN'T EXIST
	HRRZ	T1,P3		;GET DCU NUMBER
	LSH	T1,4		;POSITION
	HRRZ	T2,P1		;GET PHYSICAL DRIVE NUMBER
	IOR	T2,T1		;MERGE WITH MASSBUS UNIT
	HRLI	T2,(.DXDNM)	;DRIVE NUMBER REGISTER
	PUSHJ	P,DODTO		;WRITE IT
	PUSHJ	P,DOTIOC	;DO TWO TEST I/O'S ON THE DRIVE
	  POPJ	P,		;DX20 DIDN'T RESPOND, GIVE UP
	PUSHJ	P,INIERR	;CHECK FOR ERRORS
	  JRST	RNXDR1		;DRIVE ONLINE
	  JRST	RNXDR1		;DRIVE OFFLINE
	JUMPL	P2,CPOPJ##	;JUST GIVE UP IF DCU IS VALID
	AOBJN	P3,RNXDRV	;TRY ANOTHER DCU
	POPJ	P,		;NON-EXISTANT DRIVE

RNXDR1:	TLO	P2,400000	;REMEMBER DCU IN RH OF P3 IS VALID
	DPB	P3,RNYDCA	;STORE DCU ADDRESS
	HRLZ	T1,P1		;PHYSICAL DRIVE NUMBER
	HRR	T1,P1		;UDB TABLE INDEX
	MOVSI	T2,(1B0)	;NON-REMOVABLE MEDIA, UNIT TYPE = RP20
	PUSHJ	P,DSKDRV##	;BUILD AND LINK THE UDB
	  POPJ	P,		;NO CORE
	LDB	T1,RNYDCA	;GET DCU NUMBER
	LSH	T1,4		;POSITION
	HRRZ	T2,P1		;GET PHYSICAL DRIVE NUMBER
	IOR	T2,T1		;BUILD FAKE DRIVE S/N SINCE IT CAN'T BE READ
	SETZ	T1,		;REALLY A ONE-WORD QUANTITY
	DMOVEM	T1,UDBDSN(U)	;SET SERIAL NUNBER IN UDB
	JRST	CPOPJ1##	;RETURN
	SUBTTL	KONTROLLER ONCE-A-SECOND CODE


;ROUTINE TO CHECK THE MICROPROCESSOR
;CALL:	PUSHJ	P,RNXSEC
;RETURN	CPOPJ ALWAYS

RNXSEC:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,ST.RUN	;IS MICROPROCESSOR STILL RUNNING?
	JRST	RNXSE1		;SEE IF DRIVES TO CONFIGURE
	SKIPG	KONRLD(J)	;NOT RUNNING--OK TO ATTEMPT RELOAD?
	POPJ	P,		;RETURN
	PJRST	RNXRLD		;GO RELOAD MICROPROCESSOR
RNXSE1:	SKIPL	@KDBCHN(J)	;CHANNEL BUSY?
	POPJ	P,		;LEAVE IT ALONE
	SKIPE	T1,RNXNUM(J)	;GET BIT MASK
	JFFO	T1,RNXSE2	;FIND FIRST UNIT NUMBER
	HRRZS	KDBNUM(J)	;INDICATE NO DRIVES TO CONFIGURE
	POPJ	P,		;DONE
RNXSE2:	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
	PUSH	P,T2		;SAVE PHYSICAL DRIVE NUMBER
	MOVE	T1,KDBDVC(J)	;DEVICE CODE
	XMOVEI	T2,RNXDSP	;DISPATCH
	MOVE	T3,KDBCHN(J)	;CHANNEL DATA BLOCK
	PUSHJ	P,AUTSET##	;SET UP CPU VARIABLES
	HLLZ	P1,KDBUNI(J)	;GET MASSBUS UNIT NUMBER FOR DX20
	MOVSI	P2,(1B0)	;INDICATE DCU IS VALID
	LDB	P3,RNYDCA	;GET DCU NUMBER
	PUSHJ	P,RNXDRV	;CONFIGURE A NEW UNIT
	  JFCL			;IGNORE ERRORS
	PJRST	AUTULK##	;RELEASE AUTCON INTERLOCK AND RETURN
	SUBTTL	MICROPROCESSOR HANDLING ROUTINES


;ROUTINE TO CHECK THE VALIDITY OF THE MICROPROCESSOR CONTROL STORE.
;THIS INVOLVES CHECKING THREE THINGS AS FOLLOWS:
;   1. CRAM LOCATION 7 MUST CONTAIN A COPY OF THE DRIVE TYPE REGISTER
;   2. CRAM LOCATION 10 MUST CONTAIN AN OCTAL 210 (.CRM10)
;   3. DX.IPE MUST NOT COME UP WHILE READING ANY OF THE ABOVE
;STORES THE MICROCODE VERSION NUMBER IN THE KDB(S) FOR THE DX20.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPCHK
;RETURN CPOPJ IF AN ERROR IS DETECTED
;	CPOPJ1 IF ALL OK
;PRESERVES T1

MPCHK:	PUSHJ	P,MPRES		;RESET THE MICROPROCESSOR
	MOVE	T2,[.DXPCR!PC.IRE!PC.PCE!PC.PCI!INSVL.(7,PC.MPC)] ;REGISTER TO WRITE+
				;  IR ENABLE+PC ENABLE+PC AUTO INCR+PC TO READ
	PUSHJ	P,DODTO		;WRITE THE REGISTER
	MOVSI	T2,(.DXMIR)	;POINT AT IR REGISTER
	PUSHJ	P,DODTI		;READ THE CONTENTS
	PUSH	P,T2		;SAVE FOR COMPARE
	MOVSI	T2,(.DXDTR)	;POINT AT DRIVE TYPE REGISTER
	PUSHJ	P,DODTI		;READ THAT
	POP	P,T3		;RESTORE CRAM LOCATION 7
	CAME	T2,T3		;HAVE TO BE THE SAME
	POPJ	P,		;ERROR IF NOT
	MOVSI	T2,(.DXIPE)	;POINT AT DIAGNOSTIC REGISTER 7
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,DX.IPE	;IR PARITY ERROR ON LAST READ?
	POPJ	P,		;YES, THAT'S AN ERROR
	MOVSI	T2,(.DXMIR)	;POINT AT DIAGNOSTIC REGISTER 0 AGAIN
	PUSHJ	P,DODTI		;READ CRAM LOC 10 (PC AUTO INCR SET)
	CAIE	T2,.CRM10	;MUST BE THIS VALUE
	POPJ	P,		;NOT, ERROR
	MOVSI	T2,(.DXIPE)	;POINT AT DIAGNOSTIC REGISTER 7
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,DX.IPE	;IR PARITY ERROR ON LAST READ?
	POPJ	P,		;YES, THAT'S AN ERROR
	MOVE	T2,[.DXPCR!PC.IRE!PC.PCE!INSVL.(0,PC.MPC)] ;SET TO READ CRAM LOC 0
	PUSHJ	P,DODTO		;TELL THE DX20
	MOVSI	T2,(.DXMIR)	;ANSWER APPEARS HERE
	PUSHJ	P,DODTI		;READ VERSION NUMBER
	MOVEM	T2,RNXEBK+.EBTYP(J) ;STORE MP VERSION IN KDB
	JRST	CPOPJ1##	;GIVE SKIP RETURN
;ROUTINE TO CHECK THE VALIDITY OF THE MICROPROCESSOR CONTROL STORE AND
;START IT IF NO ERRORS ARE DETECTED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPCHKS
;RETURN CPOPJ IF AN ERROR IS DETECTED
;	CPOPJ1 WITH MICROPROCESSOR RESTARTED
;PRESERVES T1

MPCHKS:	PUSHJ	P,MPCHK		;CHECK THE CONTROL STORE
	  POPJ	P,		;ERROR DETECTED
	AOS	0(P)		;GIVE SKIP RETURN
;;	PJRST	RNXMPS		;FALL INTO RNXMPS


;ROUTINE TO START THE MICROPROCESSOR AT .DXSAD.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXMPS
;RETURN CPOPJ ALWAYS

RNXMPS:	PUSHJ	P,MPRES		;RESET THE MICROPROCESSOR
	MOVE	T2,[.DXPCR!PC.IRE!PC.PCE!PC.PCI!INSVL.(.DXSAD,PC.MPC)]
				;POINT TO REGISTER AND SET BITS
	PUSHJ	P,DODTO		;TELL MP ITS START ADDRESS
	MOVE	T2,[.DXMTR!MR.STR] ;SET START BIT IN MAINTENANCE REG
	PJRST	DODTO		;START IT AND RETURN


;ROUTINE TO RESET THE MICROPROCESSOR
;CALL:
;	J/KDB ADDRESS
;	U/UDB ADDRESS
;	PUSHJ	P,MPRES
;RETURN CPOPJ ALWAYS

MPRES:	MOVE	T2,[.DXMTR!MR.RES] ;SET RESET BIT IN MAINT REG
	PJRST	DODTO		;WRITE REGISTER AND RETURN
;ROUTINE TO SEE IF THE DX20 MICROCODE IS STILL RUNNING.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPRUN
;RETURN CPOPJ IF NOT RUNNING
;	CPOPJ1 IF RUNNING
;DESTROYS T2,T3

MPRUN:	MOVSI	T2,(.DXSTR)	;POINT AT STATUS REGISTER
	PUSHJ	P,DODTI		;READ IT
	TRNE	T2,ST.RUN	;IS IT RUNNING?
	AOS	0(P)		;YES
	POPJ	P,		;RETURN


;ROUTINE TO CHECK THE VALIDITY OF THE MICROPROCESSOR CONTROL STORE
;AND ATTEMPT TO RELOAD IT IF IT IS BAD.  RETURNS WITH THE
;MICROPROCESSOR STARTED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,MPINI
;RETURN CPOPJ IF COULDN'T VERYIFY, RELOAD, OR START IT
;	CPOPJ1 WITH THE PROCESSOR RUNNING

MPINI:	PUSHJ	P,MPCHKS	;CHECK INTEGRETY OF MP CONTROL STORE
	  JRST	RNXRLD		;BAD, TRY TO RELOAD IT
	JRST	CPOPJ1##	;GIVE SKIP RETURN
; ENABLE/DISABLE MICROCODE LOADING
RNXEDL:	SE1ENT			;ENTER SECTION ONE
	HRRZS	J		;REMOVE JUNK IN LH
	MOVE	T2,T1		;COPY BIT
	XMOVEI	T1,RNXULB(W)	;POINT TO UCODE LOADER BLOCK IN KDB
	PJRST	BTUEDL##	;ENABLE OR DISABLE


;ROUTINE TO RELOAD THE DX20 MICROCODE IF IT IS FOUND BAD.  CALLED
;VIA THE KONRLD KDB DISPATCH AND FROM MPINI INTERNALLY.  RETURNS
;WITH THE MICROPROCESSOR STARTED.
;CALL:
;	J/KDB ADDRESS
;	PUSHJ	P,RNXRLD
;RETURN CPOPJ IF COULDN'T VERIFY, RELOAD OR START MICROPROCESSOR
;	CPOPJ1 WITH THE PROCESSOR RUNNING

RNXRLD:	SE1ENT			;ENTER SECTION ONE
	PUSHJ	P,SAVW##	;SAVE W
	MOVE	W,J		;LOAD UP KDB ADDRESS
	HRRZS	KONRLD(J)	;ASSUME RELOAD WILL SUCCEED
	XMOVEI	T1,RNXULB(J)	;POINT TO MICROCODE LOADER BLOCK
	PUSHJ	P,DXLOAD## 	;TRY TO RELOAD AND VERIFY THE DX20
	  SKIPA			;FAILED
	JRST	CPOPJ1##	;GIVE SKIP RETURN
	HRROS	KONRLD(J)	;INDICATE RELOAD FAILED
	POPJ	P,		;AND RETURN
	SUBTTL	ROUTINES TO ACCESS MASSBUS REGISTERS


;ROUTINE TO WRITE ONE MASSBUS REGISTER.
;CALL:
;	T2/DATAO ARGUMENT
;	J/KDB ADDRESS
;	PUSHJ	P,DODTO
;RETURN CPOPJ ALWAYS
;DESTROYS T3

DODTO:	HLRZ	T3,KDBUNI(J)	;GET THE MASSBUS UNIT NUMBER OF THE DX20
	TLO	T2,<(DO.LDR!DO.DRE)>(T3) ;DRIVE NUMBER, LOAD REG, DISABLE RAE
	XCT	RNXDO2(J)	;DO THE DATAO
	XCT	RNXRAE(J)	;DID IT RESULT IN AN RAE?
	AOSA	RNXRAC(J)	;YES, INCREMENT COUNT AND RETRY
	POPJ	P,		;NO, RETURN
	PUSH	P,T4		;SAVE T4
	MOVEI	T3,^D10		;RETRY OPERATION 10 TIMES
	MOVEI	T4,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
DODTO1:	XCT	RNXCO4(J)	;CLEAR THE ERROR
	XCT	RNXDO2(J)	;RETRY THE OPERATION
	XCT	RNXRAE(J)	;STILL HAVE AN ERROR?
	SOJG	T3,DODTO1	;YES, LOOP BUT NOT TOO MANY TIMES
	XCT	RNXCO4(J)	;INSURE THAT RAE IS CLEARED
	JRST	T4POPJ##	;RESTORE T4 AND RETURN
;ROUTINE TO READ A DRIVE OR CONTROLLER REGISTER.
;CALL:
;	T2/DATAO ARGUMENT TO LOAD PREPARATION REGISTER
;	J/KDB ADDRESS
;	PUSHJ	P,DODTI
;RETURN CPOPJ ALWAYS WITH:
;	T2/16 BITS OF RETURNED DATAI
;DESTROYS T3

DODTI:	HLRZ	T3,KDBUNI(J)	;GET MASSBUS UNIT NUMBER OF DX20
	TLO	T2,<(DO.DRE)>(T3) ;INSERT NUMBER AND DISABLE RAE
	XCT	RNXDO2(J)	;SETUP THE PREPARATION REGISTER
	PUSH	P,T2		;SAVE THE ARGUMENT
	STALL			;WAIT FOR THINGS TO SETTLE
	XCT	RNXDI2(J)	;READ THE VALUE
	XCT	RNXRAE(J)	;DID WE GET AN RAE?
	JRST	DODTI2		;YES, TRY TO RECOVER
DODTI1:	POP	P,(P)		;BRING STACK INTO PHASE
	ANDI	T2,177777	;RETURN ONLY DATA BITS
	POPJ	P,		;RETURN
DODTI2:	MOVSI	T3,1		;ASSUME CONTROL BUS PARITY ERROR
	TLNN	T2,(DI.TRA)	;DID TRA COME UP?
	MOVEI	T3,1		;NO, MUST BE NON-EXISTENT DRIVE
	ADDM	T3,RNXRAC(J)	;INCREMENT CORRECT COUNT
	PUSH	P,T4		;SAVE T4
	MOVEI	T3,^D10		;RETRY OPERATION 10 TIMES
	MOVEI	T4,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
DODTI3:	XCT	RNXCO4(J)	;CLEAR THE ERROR
	MOVE	T2,-1(P)	;GET DATAO ARGUMENT BACK
	XCT	RNXDO2(J)	;SETUP THE PREPARATION REGISTER AGAIN
	STALL			;WAIT FOR THINGS TO SETTLE
	XCT	RNXDI2(J)	;READ THE VALUE
	XCT	RNXRAE(J)	;STILL HAVE THE ERROR?
	SOJG	T3,DODTI3	;YES, LOOP
	XCT	RNXCO4(J)	;MAKE SURE THE RAE IS CLEARED
	POP	P,T4		;RESTORE T4
	JRST	DODTI1		;RETURN TO THE USER


;ROUTINE TO READ A CONTROLLER REGISTER
;CALL:
;	T2/DATAO ARGUMENT TO LOAD PREPARATION REGISTER
;	J/KDB ADDRESS
;	PUSHJ	P,DODTIC
;RETURN CPOPJ ALWAYS WITH:
;	T2/36 BITS OF RETURNED DATAI

DODTIC:	XCT	RNXDO2(J)	;SETUP THE PREPARATION REGISTER
	XCT	RNXDI2(J)	;READ THE DATA
	POPJ	P,		;RETURN

	END