Google
 

Trailing-Edge - PDP-10 Archives - tops20_version7_0_monitor_sources_clock - monitor-sources/phyp2.mac
There are 25 other files named phyp2.mac in the archive. Click here to see a list.
; UPD ID= 8591, RIP:<7.MONITOR>PHYP2.MAC.4,  11-Feb-88 16:56:29 by GSCOTT
;TCO 7.1218 - Update copyright date.
; UPD ID= 8438, RIP:<7.MONITOR>PHYP2.MAC.3,   4-Feb-88 16:07:19 by GSCOTT
;TCO 7.1210 - Set DXBDIE, DXBDMI, DXBEUI, DXBEWC, DXBFGS, DXBFUS, DXBHLT,
; DXBIEC, DXBNUD, DXBTTS, DXBUA1, DXBUNA, and DXBZEC normally not dumpable.
; UPD ID= 9, RIP:<7.MONITOR>PHYP2.MAC.2,  28-May-87 16:10:51 by RASPUZZI
;TCO 7.1002 - Implement PMOVE/M instructions.
; Edit 7157 to PHYP2.MAC by TBOYLE on 15-Oct-85 (TCO 6-1-1526)
; Remove IORB Retry, edit 7137 did not make it in. 
;Remove IORB retry code as it causes more problems than it solves:
; Change DX2CON to mark IORB in error when cannot connect.
; Change DX2HNG to always restart of microcode. Removes TCO 6.1.1366.
; Change ISDEAD error to mark IORB with hard error.
; Change CALLRET @ERCTAB to CALL with RET, RETSKP return.
; Change CALLRET (T1) at DX2INT to CALL with RET, RETSKP return.
; Edit 7137 to PHYP2.MAC by TBOYLE on 15-Aug-85 (TCO 6-1-1526)
; Remove IORB retry code. 
; UPD ID= 2163, SNARK:<6.1.MONITOR>PHYP2.MAC.53,   5-Jun-85 10:43:17 by MCCOLLUM
;TCO 6.1.1406  - Update copyright notice.
; UPD ID= 1925, SNARK:<6.1.MONITOR>PHYP2.MAC.52,   7-May-85 21:37:49 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 1916, SNARK:<6.1.MONITOR>PHYP2.MAC.51,   7-May-85 16:49:01 by TBOYLE
;TCO 6.1.1369 - Fixup ISUNUS to catch the data errors we have been missing.
; UPD ID= 1912, SNARK:<6.1.MONITOR>PHYP2.MAC.50,   6-May-85 17:05:46 by TBOYLE
;TCO 6.1.1366 - Add support to detect overdue IORBs, and restart microcode.
; UPD ID= 1796, SNARK:<6.1.MONITOR>PHYP2.MAC.49,  23-Apr-85 13:28:37 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 1770, SNARK:<6.1.MONITOR>PHYP2.MAC.48,  22-Apr-85 10:53:51 by MCCOLLUM
;TCO 6.1.1238 - Fix BUG. documentation
; UPD ID= 1554, SNARK:<6.1.MONITOR>PHYP2.MAC.47,  20-Feb-85 17:28:13 by GRANT
;TCO 6.1.1200 - In NEWDRV, call SETDSN
; UPD ID= 1552, SNARK:<6.1.MONITOR>PHYP2.MAC.46,  20-Feb-85 17:20:28 by TBOYLE
;More TCO 6.1.1167 - Simplify the code.
; UPD ID= 1488, SNARK:<6.1.MONITOR>PHYP2.MAC.45,   7-Feb-85 11:52:39 by TBOYLE
;More TCO 6.1.1167 - Fix CI.OVR at ISRETY to retry as device error.
; UPD ID= 1478, SNARK:<6.1.MONITOR>PHYP2.MAC.43,   5-Feb-85 13:37:02 by TBOYLE
;TCO 6.1.1175 - Report all 80 extended status bytes on RP20 errors.
; UPD ID= 1438, SNARK:<6.1.MONITOR>PHYP2.MAC.42,  31-Jan-85 16:03:56 by TBOYLE
;TCO 6.1.1167 - Support for new microcode in CLASS 5 errors. Fix BAT BLOCKS.
; UPD ID= 1432, SNARK:<6.1.MONITOR>PHYP2.MAC.41,  31-Jan-85 13:11:23 by GRANT
;TCO 6.1.1165 - Cause homeblock checking when a unit comes online.
; UPD ID= 1429, SNARK:<6.1.MONITOR>PHYP2.MAC.40,  31-Jan-85 07:53:44 by GRANT
;TCO 6.1.1164 - Make up RP20 drive serial number when UDB is created.
; UPD ID= 993, SNARK:<6.1.MONITOR>PHYP2.MAC.39,   7-Nov-84 13:46:18 by MCLEAN
;INSURE THAT HOMEBLOCKS GET CHECKED FIRST!!
; UPD ID= 5040, SNARK:<6.MONITOR>PHYP2.MAC.38,  30-Oct-84 15:19:09 by MCLEAN
;UPDATE COUNT OF SENSE BYTES
; UPD ID= 4943, SNARK:<6.MONITOR>PHYP2.MAC.37,  16-Oct-84 15:25:29 by MCLEAN
;SUPPORT FOR RETRY OF OVERDUE DATA REQUESTS
; UPD ID= 4709, SNARK:<6.MONITOR>PHYP2.MAC.36,  17-Aug-84 21:27:12 by MCLEAN
;DUAL SUPPORT BETWEEN SYSTEMS NOT SUPPORTED SO DON'T SET US.2PT
; UPD ID= 4546, SNARK:<6.MONITOR>PHYP2.MAC.35,  15-Jul-84 22:18:23 by PURRETTA
;Update copyright notice
; UPD ID= 4250, SNARK:<6.MONITOR>PHYP2.MAC.34,  29-May-84 22:13:43 by MCLEAN
;ADD SUPPORT FOR DOP%PS
; UPD ID= 3141, SNARK:<6.MONITOR>PHYP2.MAC.33,  14-Nov-83 12:01:36 by MCLEAN
;FIX A HRLZ THAT SHOULD BE A HLRZ IN DX2LAT
; UPD ID= 3132, SNARK:<6.MONITOR>PHYP2.MAC.32,   9-Nov-83 20:03:59 by MCLEAN
;TCO 6.1818 MAKE SOME CHANGES FOR NON ZERO SECTIONS
; UPD ID= 3110, SNARK:<6.MONITOR>PHYP2.MAC.31,   7-Nov-83 21:25:08 by MCLEAN
;ADD DISPATCH FOR PORT RELEASE
; UPD ID= 2483, SNARK:<6.MONITOR>PHYP2.MAC.30,  17-May-83 21:42:41 by MILLER
;FIx call to PHYBLK at NOPREF to not get ILMNRF
; UPD ID= 2425, SNARK:<6.MONITOR>PHYP2.MAC.29,   5-May-83 19:31:25 by MILLER
;More TCO 6.1603. make test for dual-ported drive correct
; UPD ID= 2203, SNARK:<6.MONITOR>PHYP2.MAC.28,   8-Apr-83 05:46:53 by WACHS
;TCO 6.1603 - Light US.2PT
; UPD ID= 1105, SNARK:<6.MONITOR>PHYP2.MAC.27,  24-Aug-82 12:17:25 by PAETZOLD
;More TCO 6.1228 - Do not count skip reads in UDBRED
; UPD ID= 1087, SNARK:<6.MONITOR>PHYP2.MAC.26,  17-Aug-82 18:30:17 by PAETZOLD
;TCO 6.1228 - Update UDBRCT as well as UDBRVC for skip reads
; UPD ID= 1049, SNARK:<6.MONITOR>PHYP2.MAC.25,   6-Aug-82 15:30:10 by PAETZOLD
;More TCO 6.1217 - Fix a typo
; UPD ID= 1046, SNARK:<6.MONITOR>PHYP2.MAC.24,   6-Aug-82 14:47:16 by PAETZOLD
;TCO 6.1217 - Update UDBRVC for skip reads and not UDBRCT
; UPD ID= 905, SNARK:<6.MONITOR>PHYP2.MAC.23,   9-Jun-82 23:36:56 by MURPHY
;TCO 6.1147 - Move bugdefs from BUGS.MAC to here and put them in-line.
; UPD ID= 2196, SNARK:<5.MONITOR>PHYP2.MAC.22,  12-Jun-81 15:38:34 by LYONS
; UPD ID= 1824, SNARK:<5.MONITOR>PHYP2.MAC.21,  17-Apr-81 09:55:22 by WACHS
; UPD ID= 1335, SNARK:<5.MONITOR>PHYP2.MAC.20,   1-Dec-80 17:40:55 by LYONS
; UPD ID= 1211, SNARK:<5.MONITOR>PHYP2.MAC.19,  31-Oct-80 07:07:29 by UHLER
;TCO 5.1184 - DON'T READ REGISTER 30 UNLESS THE DX20 IS ALREADY HALTED
; UPD ID= 978, SNARK:<5.MONITOR>PHYP2.MAC.18,   2-Sep-80 07:48:47 by UHLER
;MAKE ECC CORRECTION WORK
; UPD ID= 736, SNARK:<5.MONITOR>PHYP2.MAC.17,   7-Jul-80 00:47:21 by DBELL
;TCO 5.1096 - INSERT ROUTINE TO CHECK FOR HALTED MICROCODE
; UPD ID= 731, SNARK:<5.MONITOR>PHYP2.MAC.16,   3-Jul-80 16:06:46 by DBELL
;DISABLE ECC RECOVERY UNTIL IT IS PROVEN TO WORK
; UPD ID= 677, SNARK:<5.MONITOR>PHYP2.MAC.15,  19-Jun-80 12:33:56 by DBELL
;MORE RECALIBRATION WORK
;READ THE CORRECT NUMBER OF SENSE BYTES
;GET PCTR AND PBAR VALUES FOR SYSERR PROPERLY
;MAKE RECALIBRATES WORK PROPERLY
;HANDLE WRITE-LOCKED DISKS BY MAKING THEM SAY OPR ACTION REQUESTED
; UPD ID= 640, SNARK:<5.MONITOR>PHYP2.MAC.11,  15-Jun-80 00:23:08 by DBELL
;FIX TYPO IN ASYNDO ROUTINE
; UPD ID= 636, SNARK:<5.MONITOR>PHYP2.MAC.10,  13-Jun-80 13:17:43 by DBELL
;TCO 5.1065 - CLEAR WRITE-LOCK BIT ON UNEXPECTED ASYCHRONOUS INTERRUPTS
;FIX SOME PROBLEMS IN ERROR RECOVERY
; UPD ID= 609, SNARK:<5.MONITOR>PHYP2.MAC.9,   5-Jun-80 16:25:01 by DBELL
;STORE FINAL CHANNEL STATUS WORDS WHEN ENDING SYSERR BLOCK
;READ ASYCHRONOUS STATUS REGISTER AGAIN IF NO STATUS FLAGS FIRST TIME
;ADD ADDITIONAL DATA FOR BUGCHKS AND BUGINFS
;<DBELL.M4>PHYP2.MAC.19,  6-May-80 23:37:56, EDIT BY DBELL
;<4.1.MONITOR>PHYP2.MAC.2, 30-Apr-80 21:48:04, EDIT BY DBELL
;TCO 4.1.1119 - WRITE RP20 DRIVER


;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1981, 1988.
;	ALL RIGHTS RESERVED.
;
;	THIS SOFTWARE IS FURNISHED UNDER A  LICENSE AND MAY BE USED AND  COPIED
;	ONLY IN  ACCORDANCE  WITH  THE  TERMS OF  SUCH  LICENSE  AND  WITH  THE
;	INCLUSION OF THE ABOVE  COPYRIGHT NOTICE.  THIS  SOFTWARE OR ANY  OTHER
;	COPIES THEREOF MAY NOT BE PROVIDED  OR OTHERWISE MADE AVAILABLE TO  ANY
;	OTHER PERSON.  NO  TITLE TO  AND OWNERSHIP  OF THE  SOFTWARE IS  HEREBY
;	TRANSFERRED.
;
;	THE INFORMATION IN THIS  SOFTWARE IS SUBJECT  TO CHANGE WITHOUT  NOTICE
;	AND SHOULD  NOT  BE CONSTRUED  AS  A COMMITMENT  BY  DIGITAL  EQUIPMENT
;	CORPORATION.
;
;	DIGITAL ASSUMES NO  RESPONSIBILITY FOR  THE USE OR  RELIABILITY OF  ITS
;	SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.

	SEARCH PROLOG,PHYPAR,SERCOD ;SYSTEM PARAMETERS
	TTITLE (PHYP2,,< - Device Dependent Code For DX20B/RP20 Disks >)
	SUBTTL	DAVID I. BELL/GMU  11-AUG-80
	Subttl	Table of Contents

;		     Table of Contents for PHYP2
;
;				  Section		      Page
;
;
;    1. Parameters . . . . . . . . . . . . . . . . . . . . . .   3
;    2. UDB And KDB Extensions . . . . . . . . . . . . . . . .   5
;    3. Massbus-DX20 Register Definitions  . . . . . . . . . .   7
;    4. Dispatch For DX20B . . . . . . . . . . . . . . . . . .  13
;    5. DX20 Initialization  . . . . . . . . . . . . . . . . .  14
;    6. Routine To Start I/O . . . . . . . . . . . . . . . . .  18
;    7. Routine To Stack Second Transfer Command . . . . . . .  19
;    8. Routine To Start A Position Operation  . . . . . . . .  20
;    9. Subroutine To Connect To A Drive . . . . . . . . . . .  21
;   10. Routine To Compute Latency Optimization  . . . . . . .  23
;   11. Routine To Handle Normal Interrupts  . . . . . . . . .  25
;   12. Routine To Handle Attention Interrupts . . . . . . . .  28
;   13. Routine To Handle Asychronous Status . . . . . . . . .  31
;   14. Routine To Check For Data Errors . . . . . . . . . . .  35
;   15. Error Recovery . . . . . . . . . . . . . . . . . . . .  41
;   16. Subroutines To Load Up The SYSERR Blocks . . . . . . .  48
;   17. Routine To Check For Dual Porting  . . . . . . . . . .  50
;   18. Misc Routines  . . . . . . . . . . . . . . . . . . . .  52
;   19. Subroutines For Manipulating The DX20  . . . . . . . .  56
;   20. Data . . . . . . . . . . . . . . . . . . . . . . . . .  65
;   21. End of PHYP2 . . . . . . . . . . . . . . . . . . . . .  66
	SUBTTL Parameters

	ENTRY DXBDSP		;FOR LIBRARY SEARCH

;PARAMETERS:

	MAXDRV==^D256		;MAXIMUM NUMBER OF DRIVES POSSIBLE
	NUMDRV==^D16		;MOST NUMBER OF DRIVES WE CAN USE
	DUADRV==20		;FIRST DRIVE NUMBER WHICH CAN BE DUAL PORTED
	STADDR==5		;NORMAL START ADDRESS OF DX20 MICROCODE
	BYTSEC==^D2304		;NUMBER OF 8-BIT BYTES PER SECTOR
	SNSNUM==^D80		;NUMBER OF EXTENDED STATUS BYTES
	RTYCNT==^D10		;NUMBER OF RETRIES BEFORE RECALIBRATION
	RCLCNT==^D2		;NUMBER OF RECALIBRATES BEFORE GIVING UP


;DEFINITIONS FOR THE RP2FNC TABLE TO TRANSFER PHYSIO FUNCTIONS TO
;THE CORRESPONDING HARDWARE FUNCTIONS:

	DEFSTR (TBDTF,RP2FNC,0,1)	;FUNCTION TRANSFERS DATA (SIGN BIT)
	DEFSTR (TBFNC,RP2FNC,^D17,^D8)	;RP20 FUNCTION CODE
	DEFSTR (TBDSP,RP2FNC,^D35,^D18)	;DISPATCH ADDRESS
;USEFUL MACROS:




	DEFINE RDRG(REGN),<	;;MACRO TO READ REGISTER OF UNIT IN Q2
	MOVX T2,<REGN>		;;SET UP REGISTER NUMBER
	CALL RDREG3		;;READ IT INTO T1
>



	DEFINE REG(NAME,LENGTH<1>),<	;;MACRO TO ALLOCATE REGISTER OFFSETS
	NAME==.REG.		;;DEFINE THIS OFFSET
	.REG.==.REG.+LENGTH	;;THEN ADVANCE OFFSET BY GIVEN AMOUNT
>




	DEFINE SAVREG(REGS),<	;;MACRO TO SPECIFY REGISTERS FOR SYSERR
	REGNUM==<SAVBIT==0>	;;INITIALIZE BIT MASK AND COUNTER
	IRP REGS,<SAVBIT==SAVBIT!<1B<^O<REGS>>>	;;MARK BIT FOR REGISTER
		  REG.'REGS==REGNUM	;;DEFINE OFFSET FOR USE LATER
		  REGNUM==REGNUM+1	;;INCREMENT COUNTER
		  >		;;LOOP OVER ALL REGISTERS
>				;;RETURN BITS AND COUNT


	SAVREG <0,1,2,3,4,5,6,20,21,22,23,24,26,27,30,31,32,33,34,35,36,37>
	SUBTTL UDB And KDB Extensions

;UDB DEVICE DEPENDENT PORTION:

	.REG.==UDBDDD		;START OFFSETS AT DEVICE DEPENDENT PART

;	REG U.XXXX		;ANY UDB LOCATIONS GET DEFINED HERE

	LU.DX2==.REG.		;LENGTH OF RP20 UDB




;STATUS BITS IN LEFT HALF OF UDBERR:


	UE.HRD==1B0		;HARD ERROR
	UE.ECC==1B1		;ECC-CORRECTABLE ERROR
	UE.DAT==1B2		;DATA ERROR
	UE.HDR==1B3		;HEADER ERROR
	UE.DEV==1B4		;DEVICE ERROR (NEITHER DATA NOR HEADER)
	UE.POS==1B5		;POSITIONING ERROR
;KDB DEVICE DEPENDENT PORTION:


	.REG.==KDBDDP		;START OFFSETS AT DEVICE DEPENDENT PART

	REG K.DUDB,NUMDRV	;UDB TABLE (NUMDRV WORDS LONG)
	REG K.DXAD		;MASSBUSS ADDRESS OF THE DX20
	REG K.STCT		;NUMBER OF TIMES MICROCODE WAS RESTARTED
	REG K.STCL		;CLOCK TIMER FOR RESTARTS ON OVERDUES
	REG K.DNUM		;NUMBER OF DRIVES IN EXISTENCE
	REG K.SAVQ		;STORAGE FOR Q1 ON ATTENTION INTERRUPTS
	REG K.DVER		;DX20 MICROCODE VERSION NUMBER
	REG K.DREG,REGNUM	;DRIVE REGISTERS READ ON ERROR
	REG K.DEXS,<SNSNUM+3>/4	;EXTENDED STATUS BYTES (MUST FOLLOW K.DREG)
	REG K.DCNI		;CONI OF RH READ ON AN ERROR
	REG K.DCS1		;DATAI OF RH CONTROL REGISTER
	REG K.DDBF		;DATAI OF RH DATA REGISTER

	LK.DX2==.REG.		;LENGTH OF DX20 KDB
	SUBTTL Massbus-DX20 Register Definitions

;MASSBUS DEVICE REGISTER ASSIGNMENTS.  MISSING REGISTER DEFINITIONS
;ARE EITHER UNUSED OR ARE FOR DIAGNOSTICS



	.DXCTL==0B5		;CONTROL REGISTER
	.DXSTS==1B5		;STATUS REGISTER
	.DXERR==2B5		;ERROR REGISTER
	.DXMAI==3B5		;MAINTENANCE REGISTER
	.DXATN==4B5		;ATTENTION SUMMARY REGISTER
	.DXREC==5B5		;HEAD/RECORD REGISTER (SAME AS REG 25)
	.DXTYP==6B5		;DRIVE TYPE REGISTER
				;REGISTERS 7-17 ARE UNUSED
	.DXEND==20B5		;ENDING STATUS REGISTER
	.DXASY==21B5		;ASYNCHRONOUS STATUS REGISTER
	.DXFLG==22B5		;FLAGS AND ARGUMENT REGISTER
	.DXDRV==23B5		;DRIVE NUMBER REGISTER
	.DXCYL==24B5		;CYLINDER REGISTER
				;REGISTER 25 IS SAME AS REGISTER 5
	.DXES0==26B5		;EXTENDED STATUS REGISTER 0
	.DXES1==27B5		;EXTENDED STATUS REGISTER 1
	.DXDG0==30B5		;DIAGNOSTIC REGISTER 0 (CONTENTS OF MICROSTORE)
	.DXDG1==31B5		;DIAGNOSTIC REGISTER 1 (PC AND FLAGS)
				;REGISTERS 32-36 ARE FOR DIAGNOSTIC USE
	.DXDG7==37B5		;DIAGNOSTIC REGISTER 7 (PARITY ERROR FLAG)
;REGISTER 0 (.DXCTL) BIT DEFINITIONS:


	DX.GO==1B35		;GO BIT
	DEFSTR (DXFNC,,^D35,6)	;FUNCTION CODE (INCLUDING GO BIT)



;FUNCTION CODES (INCLUDING THE GO BIT).  SOME OF THE FUNCTIONS HAVE
;SUB-CODES WHICH MUST BE LOADED INTO THE FLAG REGISTER (.DXFLG) PRIOR
;TO LOADING THE FUNCTION CODE ITSELF.  POSSIBLE SUB-CODES ARE INDENTED
;FOLLOWING THEIR MAJOR CODE.


	XF.NOP==1		;FUNCTION FOR NO OPERATION SUB-CODES
	  XS.TIO==0		;TEST I/O
	  XS.NOP==3		;NO OPERATION
	XF.SEK==5		;SEEK
	XF.REC==7		;RECALIBRATE
	XF.CLR==11		;DRIVE CLEAR
	XF.SRC==31		;SEARCH
	XF.SEN==47		;FUNCTION FOR SENSE SUB-CODES
	  XS.SEN==4		;SENSE
	  XS.REL==224		;DRIVE RELEASE
	  XS.BUF==244		;READ AND RESET BUFFER LOG
	  XS.RSV==264		;DRIVE RESERVE
	XF.WRT==61		;WRITE DATA
	XF.WRF==63		;WRITE FORMAT
	XF.WRS==65		;WRITE SPECIAL
	XF.RED==71		;READ DATA
	XF.RDF==73		;READ FORMAT
	XF.RDS==75		;READ SPECIAL




;REGISTER 1 (.DXSTS) BIT DEFINITIONS:


	ST.ATN==1B20		;ATTENTION (.DXATN IS NONZERO)
	ST.ERR==1B21		;COMPOSITE ERROR (.DXERR IS NONZERO)
	ST.LNK==1B22		;LINK PRESENT (ALWAYS ON)
	ST.RUN==1B23		;MICROPROCESSOR IS RUNNING
;REGISTER 2 (.DXERR) BIT DEFINITIONS:


	DEFSTR (ERCOD,,^D27,4)	;ERROR CLASS CODE FIELD
	DEFSTR (ERSUB,,^D23,4)	;ERROR SUB-CLASS FIELD

	ER.NEW==1B28		;NEW ERROR DETECTED BY MICROPROCESSOR
	ER.STP==1B29		;MICROPROCESSOR STOPPED
	ER.MPE==1B30		;MICROBUS PARITY ERROR
	ER.DPE==1B31		;DATABUS PARITY ERROR
	ER.CPE==1B32		;CONTROL BUS PARITY ERROR
	ER.RMR==1B33		;REGISTER MODIFICATION REFUSED
	ER.ILR==1B34		;REFERENCE TO ILLEGAL REGISTER
	ER.ILF==1B35		;ILLEGAL FUNCTION ATTEMPTED

	ER.ALL==ER.NEW!ER.STP!ER.MPE!ER.DPE!ER.CPE!ER.RMR!ER.ILR!ER.ILF	;ALL


;ERROR CLASS AND SUB-CLASS CODES (FROM ERCOD AND ERSUB).  VALUES
;IN THE SUB-CLASS ARE INDENTED.

	ER.UDS==1		;UNUSUAL DEVICE STATUS
	  ES.FSS==0		;STATUS IS FROM FINAL SEQUENCE
	  ES.ISS==1		;STATUS IS FROM INITIAL SEQUENCE
	ER.RLE==2		;RECORD LENGTH ERROR
	ER.DSE==3		;DRIVE SELECTION ERROR (NONEXISTENT DRIVE)
	ER.RER==4		;RECOVERABLE ERROR
	  ES.DPE==0		;DATA PATH PARITY ERROR
	  ES.EPE==1		;ENDING STATUS BYTE PARITY ERROR
	  ES.AMM==2		;ADDRESS MISMATCH
	  ES.APE==3		;ADDRESS PARITY ERROR
	  ES.IPE==4		;INITIAL STATUS BYTE PARITY ERROR
	  ES.DMP==5		;DATA PATH DETECTED MICRO BUS PARITY ERROR
	  ES.IMP==6		;DEV BUS INTERFACE FOUND MICRO BUS PARITY ERROR
	  ES.HTO==7		;DEVICE BUS HANDSHAKE TIME-OUT
	  ES.ADI==10		;DEVICE ASSERTED DISCONNECT IN
	  ES.RWR==11		;RUN WASN'T RECEIVED FROM RH20
	ER.CRR==5		;COMMAND RETRY REQUEST
	ER.NER==6		;NON-RECOVERABLE ERROR
	  ES.PE1==0		;PARITY ERROR RECEIVING DRIVE ADDRESS
	  ES.PE2==1		;SAME THING
	ER.RIA==7		;RETRY LOG INFORMATION AVAILABLE
	ER.FTL==10		;FATAL ERRORS (BAD MICROCODE OR BROKEN HARDWARE)
	  ES.WDT==0		;HARDWARE DRIVE TYPE DOESN'T MATCH EXPECTED TYPE
	  ES.FCU==1		;FOREIGN CONTROL UNIT
	  ES.MPF==2		;MASSBUS CONTROLLER POWER FAILED
	  ES.II0==3		;MICROPROCESSOR INTERRUPTED FROM INTERFACE 0
;REGISTER 3 (.DXMAI) BIT DEFINITIONS:


	MR.SS==1B31		;SINGLE STEP MICRO PROCESSOR
	MR.WEP==1B32		;WRITE EVEN PARITY ON ALU OPERATION
	MR.ST==1B33		;START/STOP MICRO PROCESSOR
	MR.RES==1B34		;HALT MICRO PROCESSOR AND CLEAR REGISTERS





;REGISTER 4 (.DXATN) BIT DEFINITIONS:


	AT.0==1B35		;DRIVE 0 NEEDS ATTENTION.  FOR OTHER DRIVES,
				;SHIFT LEFT BY DRIVE NUMBER.




;REGISTER 5 (.DXREC) BIT DEFINITIONS:


	DEFSTR (RCHED,,^D27,^D8)	;HEAD NUMBER
	DEFSTR (RCREC,,^D35,^D8)	;RECORD NUMBER




;REGISTER 20 (.DXEND) BIT DEFINITIONS (THESE STATUS FLAGS ARE ALSO
;RETURNED IN REGISTER .DXASY ON ANCHRONOUS STATUS):


	DEFSTR (ESIDX,,^D35,7)	;EXTENDED STATUS TABLE INDEX

	ES.STM==1B21		;STATUS MODIFIER FLAG
	ES.CUE==1B22		;CONTROL UNIT END
	ES.BSY==1B23		;CONTROL UNIT OR DEVICE IS BUSY
	ES.CHE==1B24		;CHANNEL END
	ES.DVE==1B25		;DEVICE END
	ES.UNC==1B26		;UNIT CHECK
	ES.UNE==1B27		;UNIT EXCEPTION
	ES.SUI==1B28		;STATUS UPDATE INTERLOCK
;REGISTER 21 (.DXASY) BIT DEFINITIONS (BITS 20-28 ARE STATUS BITS
;DEFINED THE SAME AS IN REGISTER .DXEND):


	DEFSTR (ASDRV,,^D35,^D8)	;DRIVE NUMBER PRESENTING STATUS





;REGISTER 22 (.DXFLG) BIT DEFINITIONS:


	DEFSTR (DFCOD,,^D35,^D8)	;SUB-FUNCTION TO PERFORM

	DF.IGL==1B21		;IGNORE LENGTH ERRORS
	DF.DIA==1B22		;DIAGNOSTIC MODE FOR READ AND WRITE SPECIAL
	DF.RTY==1B23		;COMMAND RETRY REQUESTED
	DF.DSN==1B25		;DISABLE SENSE ON UNIT CHECKS
	DF.FSN==1B26		;FORCE SENSE OPERATION ON COMMAND COMPLETION
	DF.WHT==1B27		;READ OR WRITE THE WHOLE TRACK





;REGISTER 23 (.DXDRV) BIT DEFINITIONS:


	DEFSTR (DRVNM,,^D35,^D8)	;DRIVE NUMBER





;REGISTER 31 (.DXDG0) BIT DEFINITIONS:


	DG.UIR==1B20		;READ OR WRITE INSTRUCTION REGISTER
	DG.MSE==1B21		;ENABLE MICROSTORE FOR WRITING
	DG.PCS==1B22		;SET DX20 PC
	DG.PCI==1B23		;INCREMENT PC AFTER USING INSTRUCTION REGISTER
	DG.PC==7777B35		;PC VALUE





;REGISTER 37 (.DXDG7) BIT DEFINITIONS:


	DG.IRP==1B22		;IR PARITY ERROR OCCURED
;DEFINITIONS FOR SENSE BYTES 0-3.  WHEN READ INTO AN AC, BITS 2-9
;CONTAIN BYTE 0, BITS 10-17 CONTAIN BYTE 1, BITS 20-27 CONTAIN
;BYTE 2, AND BITS 28-35 CONTAIN BYTE 3.



	S0.REJ==1B2		;COMMAND REJECT
	S0.IVR==1B3		;INTERVENTION REQUIRED
	S0.BPE==1B4		;BUS OUT PARITY ERROR
	S0.ECK==1B5		;EQUIPMENT CHECK
	S0.DCK==1B6		;DATA CHECK OCCURED
	S0.OVR==1B7		;OVERRUN OCCURED

	S1.PRM==1B10		;PERMANENT ERROR (DCU RETRY COUNT EXHAUSTED)
	S1.ITF==1B11		;INVALID TRACK FORMAT
	S1.EOC==1B12		;END OF CYLINDER
	S1.NRF==1B14		;NO RECORD FOUND
	S1.FPE==1B15		;FILE PROTECTED ERROR
	S1.WLK==1B16		;DRIVE WAS WRITE LOCKED
	S1.OPI==1B17		;OPERATION INCOMPLETE

	S2.COR==1B21		;ERROR IS CORRECTABLE
	S2.EDP==1B23		;ENVIRONMENTAL DATA PRESENT (BYTES 8 - 23)
	S2.CMP==1B24		;DRIVE IS IN 3330 COMPATIBLE MODE

	DEFSTR (S3RSC,,^D35,^D8)	;RESTART COMMAND




;OTHER SENSE BYTE INFORMATION OF INTEREST.  ALL OF THESE DEFINITIONS
;ASSUME THAT ALL OF THE SENSE BYTES WERE READ INTO THE K.DEXS TABLE
;IN THE KDB.  THIS TABLE CONTAINS FOUR SENSE BYTES PER WORD.


	DEFSTR (SBECOD,K.DEXS+1(P2),^D35,^D8)	;SENSE BYTE 7:
						;ERROR TYPE FIELD
	DEFSTR (SBEPOS,K.DEXS+4(P2),^D35,^D16)	;SENSE BYTES 18 AND 19:
						;BYTE POSITION OF ECC ERROR
	DEFSTR (SBEMSK,K.DEXS+5(P2),^D17,^D16)	;SENSE BYTES 20 AND 21:
						;MASK TO FIX ECC ERROR WITH

	FC.ECC==123		;VALUE IN SBECOD FOR ECC ERROR
	FC.IVC==001		;FORMAT 0, MESSAGE 1: INVALID COMMAND
	FC.FPR==012		;FORMAT 0, MESSAGE A: MPL FILE PERM RD CK
	CI.OVR==1B26		;DATA OVERRUN
	SUBTTL Dispatch For DX20B

;THE FOLLOWING TABLE IS THE DISPATCH TABLE FOR THIS DRIVER.  THE OFFSETS
;INTO THE TABLE ARE DEFINED IN PHYPAR.  THE CALLING SEQUENCE TO USE THIS
;TABLE IS:
;
;	HRRZ AC,UDBDSP(P3)	;GET DISPATCH ADDRESS
;	CALL UDSXXX(AC)		;CALL ROUTINE
;	 (NON-SKIP RETURN)	;ROUTINE DIDN'T SKIP
;	(SKIP RETURN)		;ROUTINE SKIPPED
;
;YOU CAN REPLACE THE "HRRZ AC,UDBDSP(P3)" INSTRUCTION WITH "HRRZ AC,KDBDSP(P2)"
;WHEN NECESSARY, SINCE THE KDB AND THE UDB USE THE SAME DISPATCH TABLE.




DXBDSP::JRST DX2INI		;0 - INITIALIZATION
	JRST DX2SIO		;1 - START DATA TRANSFER OPERATION
	JRST DX2INT		;2 - HANDLE INTERRUPT
	JRST DX2ERR		;3 - ERROR RECOVERY
	JRST DX2HNG		;4 - HUNG DEVICE
	JRST DX2CNV		;5 - CONVERT SECTOR NUMBER TO BLOCK/SEC-SURFACE
	JRST DX2LAT		;6 - LATENCY COMPUTATION
	JRST DX2POS		;7 - START POSITION OPERATION (SEARCH)
	JRST DX2ATN		;10 - ATTENTION INTERRUPT
	JRST DX2PCK		;11 - SKIP IF POSITIONING NEEDED
	JRST DX2STK		;12 - STACK SECOND COMMAND
	JRST DX2EXT		;13 - CHECK LEGALITY AND EXISTENCE OF A UNIT
	JRST DX2CCK		;14 - SEE IF DX20 IS HALTED
	JRST R			;15 - RELEASE PORT
	SUBTTL DX20 Initialization

;DX2INI - INITIALIZATION ROUTINE.  THIS ROUTINE IS CALLED ONCE PER
;DX20 DRIVE ON THE SYSTEM AND BUILDS A KDB FOR THE DX20 AND A UDB
;FOR EACH RP20 DRIVE.  CALL:
;  P1/	CDB
;  Q2/	DX20 NUMBER
;  P5/	UNIT NUMBER TO INITIALIZE, OR -1 FOR ALL UNITS
;RETURNS:
;  +1:	ALWAYS
;	  T1/	KDB



DX2INI:	SAVEQ			;SAVE REGISTERS
	JUMPL P5,INILB		;SKIP ON IF INITIALIZING ALL UNITS
	MOVE P2,CDBIUN(P1)	;GET KDB ADDRESS IF IT EXISTS
	ADD P2,Q2		;POINT TO CORRECT UNIT
	MOVE P2,0(P2)		;GET ENTRY
	SKIPE P3,P2		;FOUND ONE?
	JRST INILA		;ALREADY GOT ONE

INILB:	CALL CHKMIC		;CHECK THE DX20 MICROCODE (STOPS IT TOO)
	 JRST [	HRRZ T1,CDBADR(P1)	;BAD MICROCODE, GET CHANNEL READY
		BUG.(CHK,DXBDMI,PHYP2,SOFT,<PHYP2 - DX20B microcode is invalid>,<<T1,CHAN>,<Q2,DX20>>,<

Cause:	TOPS-20 could not verify the microcode in a DX20B (RP20 controller).

Data:	CHAN - Channel number
	DX20 - DX20 number
>,,<DB%NND>)			;[7.1210] 
		RET]		;AND IGNORE THIS DX20
	MOVEI T1,LK.DX2		;LENGTH OF KDB
	CALL PHYALC		;ALLOCATE SPACE
	 RET			;FAILED
	MOVE P2,T1		;SAVE ADDRESS OF KDB IN PROPER AC
	MOVE P3,T1		;NEED POINTER OF KDB ALSO IN P3
	MOVEI T1,.BTKDB		;MARK AS A KDB
	DPB T1,USYBKT		;SET .BTKDB IN KDB
	MOVEI T1,.UTDXB		;GET CODE FOR DX20B CONTROLLER
	STOR T1,USTYP,(P2)	;AND STORE IT INTO THE KDB
	MOVX T1,KS.DSK		;GET FLAG READY
	IORM T1,KDBSTS(P2)	;REMEMBER THAT THIS CONTROLLER DRIVES DISKS
	MOVEI T1,DXBDSP		;INSERT DISPATCH VECTOR
	MOVEM T1,KDBDSP(P2)	; ...
	HRRZM Q2,K.DXAD(P2)	;SAVE MASSBUSS ADDRESS OF THE KDB
	CALL GETVER		;READ THE MICROCODE VERSION IN THE DX20
	MOVEM T1,K.DVER(P2)	;REMEMBER IT IN THE KDB FOR SYSERR STUFF
	MOVEI T1,STADDR		;GET STARTING ADDRESS OF DX20
	CALL DXSTRT		;START THE DX20 MICROCODE
	MOVSI T1,1		;** TEMPORARY
	SOJG T1,.		;** GIVE DX20 TIME TO START UP HAPPILY
	MOVSI T1,-NUMDRV	;SET UP AOBJN INDEX
	HRRI T1,K.DUDB(P2)	;MAKE RH POINT TO UDB ENTRIES IN KDB
	MOVEM T1,KDBIUN(P2)	;INITIAL POINTER
	MOVEM T1,KDBCUN(P2)	;CURRENT POINTER
	SETZM K.DNUM(P2)	;CLEAR NUMBER OF UDB'S IN EXISTENCE

INILA:	SKIPL Q1,P5		;GET POSSIBLE SPECIFIC UNIT TO INITIALIZE
	TLOA Q1,-1		;WAS ONE, DO ONLY 1 TIME
	MOVSI Q1,-MAXDRV	;WANTS ALL DRIVES, SET UP AOBJN INDEX
	MOVEI Q3,4		;GET MAXIMUM DRIVES TO COMPLAIN ABOUT
				;FALL INTO LOOP
;LOOP TO EXAMINE ALL UNITS:


INILP:	SETZ P5,		;NO UDBSTS BITS YET
	MOVX T2,.DXDRV		;GET DRIVE NUMBER REGISTER READY
	STOR Q1,DRVNM,T2	;INSERT DRIVE NUMBER
	CALL WTREG3		;SET IT
	MOVX T2,.DXFLG+<FLD(XS.NOP,DFCOD)>	;GET SUB-FUNCTION NEEDED
	CALL WTREG3		;PLACE INTO ARGUMENT REGISTER
	MOVX T2,.DXCTL+<FLD(XF.NOP,DXFNC)>	;GET FUNCTION FOR NOP
	CALL WTREG3		;TELL DX20 TO DO A NOP ON THE DRIVE
	CALL ATTNWT		;WAIT FOR COMPLETION
	 JRST SIKDRV		;FAILED, COMPLAIN
	RDRG .DXERR		;READ ERROR REGISTER NOW
	TXNE T1,ER.ALL-ER.NEW	;ANY FATAL ERRORS?
	JRST SIKDRV		;YES, GO COMPLAIN
	TXNN T1,ER.NEW		;ANY NEW ERROR STATUS?
	JRST ISDRV		;NO, THEN DRIVE EXISTS AND IS OK
	LOAD T2,ERCOD,T1	;EXTRACT ERROR CODE
	CAIN T2,ER.DSE		;NONEXISTENT DRIVE?
	JRST NXTDRV		;YEP, JUST IGNORE IT
	CAIE T2,ER.UDS		;UNUSUAL DEVICE STATUS?
	JRST SIKDRV		;NO, SOMETHING ELSE, GO COMPLAIN
	RDRG .DXEND		;GET ENDING STATUS
	TXNN T1,ES.UNC		;WAS THE ERROR UNIT CHECK?
	JRST NXTDRV		;NOPE, SO NO SUCH UNIT, EXAMINE NEXT ONE
	CALL RDSNS		;YES, READ IN SENSE BYTES
	 JRST NXTDRV		;FAILED, SKIP THIS DRIVE
	TXNE T1,S0.OVR!S0.DCK!S0.ECK!S0.BPE!S0.REJ!S1.OPI!S1.FPE!S1.NRF!S1.EOC!S1.ITF!S1.PRM			;ANY AWFUL STATUS?
	JRST SIKDRV		;YES, CALL IT SICK
	MOVX P5,US.OFS		;DRIVE IS OFF-LINE, GET STATUS TO SET

;HERE FOR EACH EXISTENT DRIVE.  DECIDE IF THIS DRIVE IS DUAL PORTED, AND
;IF SO EITHER IGNORE THIS ACCESS PATH TO IT, OR ELSE MOVE THE UDB FROM
;THE ALTERNATE ACCESS PATH TO THIS ONE (WHICH WILL IMPROVE PERFORMANCE).
;CALLED WITH INITIAL UDBSTS FLAGS IN P5.


ISDRV:	HRRZ T1,Q1		;GET DRIVE NUMBER
	CALL CKDUAL		;SEE IF THE DRIVE ALREADY EXISTS ON ANOTHER PORT
	 JRST NEWDRV		;NO, BUILD A UDB THEN
	MOVE P3,T1		;REMEMBER UDB (HOWEVER, P1 AND P2 DON'T MATCH!)
	TLC Q1,-1		;GET READY FOR TEST
	TLCE Q1,-1		;DOING ONLY ONE UNIT (OR LAST UNIT OF SERIES)?
	TRNE Q1,1		;OR IS THE DRIVE NUMBER ODD?
	JRST NXTDRV		;YES, LET OTHER CHANNEL KEEP OWNERSHIP OF DRIVE
	MOVE T1,K.DNUM(P2)	;GET NUMBER OF DRIVES ON THIS CONTROLLER
	CAIL T1,NUMDRV		;ANYMORE ROOM IN UDB TABLE?
	JRST NXTDRV		;NO, LEAVE DRIVE ON ORIGINAL CHANNEL
	MOVE T1,UDBSTS(P3)	;PARANOIA CHECK - IS THE UNIT NOW ACTIVE?
	TXNE T1,US.ACT!US.POS!US.MAI	;WELL?
	JRST NXTDRV		;YES, DON'T SWITCH THE UDB!!
	HRRZ T1,UDBKDB(P3)	;GET OLD KDB ADDRESS FROM UDB WE ARE MOVING
	MOVE T2,KDBIUN(T1)	;SETUP TO SEARCH ITS UDB TABLE
	CAME P3,(T2)		;FIND OLD KDB'S POINTER TO UDB?
	AOBJN T2,.-1		;NO, KEEP LOOKING
	JUMPGE T2,NXTDRV	;IF NOT FOUND (??) LEAVE UDB ALONE
	SOS T3,K.DNUM(T1)	;DECREMENT COUNTER OF UNITS IN OTHER KDB
	ADDI T3,K.DUDB(T1)	;COMPUTE ADDRESS OF LAST UDB POINTER USED
	MOVE T4,(T3)		;GRAB THE POINTER
	MOVEM T4,(T2)		;OVERWRITE STOLEN UDB'S POINTER WITH IT
	SETZM (T3)		;AND CLEAR LAST ENTRY IN UDB TABLE
	HRRZM P1,UDBCDB(P3)	;SETUP NEW CHANNEL IN STOLEN UDB
	HRRZM Q2,UDBADR(P3)	;AND NEW CONTROLLER NUMBER
	MOVEM Q2,UDBAKA(P3)	;SET UP THIS WORD ALSO
	HRLM Q2,UDBAKA(P3)	;WITH COPIES OF THESE NUMBERS
	JRST DONDRV		;JOIN OTHER CODE TO FINISH UP
;HERE TO BUILD THE UDB FOR A DRIVE:
;	Q1/ -n,,DRIVE-NUMBER

NEWDRV:	MOVE T3,K.DNUM(P2)	;GET NUMBER OF DRIVES FOUND SO FAR
	CAIL T3,NUMDRV		;ROOM IN K.DUDB TABLE?
	JRST [	BUG.(CHK,DXBTTS,PHYP2,HARD,<PHYP2 - Tables too small for this many drives>,<<T3,NUMDRV>>,<

Cause:	The number of RP20 drives on a DX20 controller exceeds the number
	supported by TOPS-20.

Data:	NUMDRV - Number of drives allowed per controller
>,,<DB%NND>)			;[7.1210] 
		MOVE T1,P2	;TELL RETURN TO PUT KDB INTO CDB
		RET]		;GIVE UP NOW
	MOVE T3,[DXBDSP,,LU.DX2] ;SET UP ADDRESS,,LENGTH
	CALL PHYUDB		;AND ASK FOR UDB ALLOCATION
	 RET			;RETURN IF NO SPACE FOUND
	MOVX T1,.UTP20		;RP20 DISK IS ONLY POSSIBLE DEVICE
	STOR T1,USTYP,(P3)	;PUT UNIT TYPE IN UDB
	MOVSI T2,-NDSKUT	;GET READY FOR SEARCH
	CAME T1,DSKUTP(T2)	;LOOK FOR DISK TYPE IN TABLE
	AOBJN T2,.-1		;KEEP SEARCHING
	SKIPL T2		;FIND IT?
	BUG.(HLT,DXBTNF,PHYP2,SOFT,<PHYP2 - Unit type not found in table>,,<

Cause:	The routine DX2INI was called to initialize a UDB for an RP20 disk.
	It converted the hardware drive type into the internal drive
	type and then looked in the physical parameter table (DSKUTP)
	for that type so that the disk parameters could be obtained.
	The drive type could not be found.

>)		;NO, COMPLAIN
	MOVE T2,DSKSIZ(T2)	;GET POINTER TO PHYSICAL PARAMETER TABLE
	MOVEM T2,UDBSIZ(P3)	;SAVE IN UDB
	TXO P5,US.DSK!US.PRQ	;SET UNIT IS A DISK AND REQUIRES POSITIONING
	IORM P5,UDBSTS(P3)	;REMEMBER FLAGS
DONDRV:	AOS T1,K.DNUM(P2)	;ADVANCE TO NEXT FREE UDB ENTRY
	ADDI T1,K.DUDB-1(P2)	;POINT TO THE NEW TABLE ENTRY
	HRRZM P3,(T1)		;SAVE LINK
	HRRZM P2,UDBKDB(P3)	;SAVE BKWDS LINK
	HRRZM Q1,UDBSLV(P3)	;REMEMBER SLAVE ADDRESS
	MOVX T1,<<.UTP20!400>_20> ;GET DRIVE TYPE
	HRRZ T2,Q1		;MAKE UP
	ADDI T2,^D8000		; SERIAL NUMBER
	CALL SETDSN		;(T1,T2,P3/) SET DSN
	JRST NXTDRV		;GO EXAMINE NEXT DRIVE
;HERE TO COMPLAIN IF NECESSARY ABOUT A SICK DRIVE, CLEAR ANY POSSIBLE
;ERROR STATUS, AND LOOP FOR THE NEXT UNIT.



SIKDRV:	SOJL Q3,NXTDRV		;ONLY COMPLAIN ABOUT FIRST FEW DRIVES
	HRRZ T1,CDBADR(P1)	;SET UP CHANNEL
	HRRZ T2,Q1		;AND UNIT NUMBER
	BUG.(CHK,DXBEUI,PHYP2,HARD,<PHYP2 - Error trying to initialize a unit>,<<T1,CHAN>,<Q2,DX20>,<T2,UNIT>>,<

Cause:	TOPS-20 detected a drive error while trying to initialize an RP20
	disk.

Data:	CHAN - Channel number
	DX20 - DX20 number
	UNIT - Drive number
>,,<DB%NND>)			;[7.1210] 

NXTDRV:	MOVX T2,.DXERR		;WANT TO CLEAR THE ERROR REGISTER
	CALL WTREG3		;DO IT
	AOBJN Q1,INILP		;TRY NEXT SLAVE
	MOVE T1,P2		;TELL RETURN TO PUT KDB INTO CDB
	RET
	SUBTTL Routine To Start I/O

;CALLED TO START A DATA TRANSFER FOR A DRIVE.  CALL:
;  P1/	CDB
;  P2/	KDB
;  P3/	CDB
;  P4/	IORB
;RETURNS:
;  +1:	FAILED, IORB MARKED AS FAILED
;  +2:	I/O SUCCESSFULLY STARTED




DX2SIO:	SAVEQ			;SAVE SOME REGISTERS
	MOVE Q2,K.DXAD(P2)	;SET UP DX20 UNIT NUMBER
	HRRZ T1,UDBERR(P3)	;GET FUNCTION IF ERROR RECOVERY
	JUMPN T1,DS2SI1		;GO IF SO
	LDB T1,IRYFCN		;NORMAL, GET FUNCTION
	CAIGE T1,MNRP2V
	CAIG T1,MXEXTF		;MAKE SURE IT IS WITHIN RANGE
	SKIPN RP2FNC(T1)	;AND LEGAL
	BUG.(HLT,DXBFEX,PHYP2,SOFT,<PHYP2 - Illegal function starting IO>,,<

Cause:	The routine DX2SIO in PHYP2 was called to start a transfer
	operation for an IORB but the function code from the IORB
	was illegal.

>)		;NO, DIE
DS2SI1:	LOAD Q1,TBFNC,(T1)	;TRANSLATE TO HARDWARE FUNCTION
	CALL DX2CON		;CONNECT TO THE DRIVE
	 RET			;FAILED
				;RETURNS: T2/ CYLINDER, T3/ SECTOR WITHIN IT
	CALL GTHWSC		;COMPUTE .DXREC VALUE (HEAD, RECORD NUMBERS)
	MOVE T4,T1		;SAVE FOR AWHILE
	TXO T2,.DXCYL		;ADD REGISTER TO CYLINDER NUMBER
	CALL WTREG		;SET CYLINDER INTO DX20
	MOVE T2,T4		;GET BACK .DXREC DATA
	HRRZM P3,KDBACT(P2)	;REMEMBER WHICH UDB WE ARE DOING I/O ON
	JRST CHSTRT		;GO START CHANNEL AND SKIP IF SUCCESSFUL
	SUBTTL Routine To Stack Second Transfer Command

;CALLED WHEN PRIMARY COMMAND IS BUSY, TO SET UP A SECOND TRANSFER
;COMMAND.  SAME CALL AS DX2SIO.

DX2STK:	SAVEQ			;SAVE ACS
	MOVE Q2,K.DXAD(P2)	;SET UP DX20 UNIT NUMBER
	LDB T1,IRYFCN		;GET FUNCTION TO PERFORM
	CAIGE T1,MNRP2V		;VARIFY?
	CAIG T1,MXEXTF		;VERIFY THAT IS IS NOT TOO LARGE
	SKIPN RP2FNC(T1)	;AND THAT IS IS VALID
	BUG.(HLT,DXBIF2,PHYP2,SOFT,<PHYP2 - Illegal function stacking IO>,,<

Cause:	The routine DX2STK in PHYP2 was called to stack a second
	transfer command but the function in the IORB was illegal.

>)		;IT'S BAD
	LOAD Q1,TBFNC,(T1)	;TRANSLATE TO HARDWARE FUNCTION
	CALL PHYBLK		;OBTAIN UNIT RELATIVE ADDRESS IN T2
	TXZ T2,IRBPAD		;REMOVE PHYSICAL ADDRESSING BIT
	MOVE T3,UDBSIZ(P3)	;GET POINTER TO DISK SIZE DATA
	IDIV T2,SECCYL(T3)	;DIVIDE BY SECTORS PER CYLINDER
	MOVEM T3,UDBPS2(P3)	;UPDATE SECTOR
	CALL GTHWSC		;COMPUTE VALUE FOR .DXREC REGISTER
	MOVE T2,T1		;PUT INTO PROPER AC
	JRST CHSTRT		;GO STACK THE COMMAND
	SUBTTL Routine To Start A Position Operation

;SEEKS ARE POSSIBLE FOR THE RP20, BUT ARE NOT USED BECAUSE ONCE THE
;DISK IS ON CYLINDER, THERE IS NO WAY TO TELL WHEN THE DESIRED SECTOR
;IS NEAR THE HEADS (IE, LATENCY OPTIMIZATION IS NOT POSSIBLE AS IT WAS
;FOR RPO6 AND SIMILAR DISKS).  THEREFORE TO PROGRAM THE RP20 DISKS
;EFFICIENTLY, THE SEARCH FUNCTION IS USED INSTEAD.  THIS FUNCTION WILL
;DO A SEEK IF NECESSARY, AND THEN WILL INTERRUPT THE CPU WHEN THE
;DESIRED SECTOR IS "NEAR" THE HEADS.  THEN A TRANSFER OPERATION CAN
;BE INITIATED QUICKLY, AND VERY LITTLE ROTATIONAL TIME WILL BE LOST.
;CALL TO START THE SEARCH:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB
;  P4/	IORB
;RETURNS:
;  +1:	FAILED
;  +2:	SEARCH STARTED SUCCESSFULLY

DX2POS:	SAVEQ			;SAVE ACS
	MOVE Q2,K.DXAD(P2)	;SET UP DX20 UNIT NUMBER
	MOVEI Q1,XF.SRC		;GET SEARCH FUNCTION
	CALL DX2CON		;CONNECT TO DRIVE AND RETURN CYLINDER IN T2
	 RET			;CAN'T DO IT
DOPOS:	CALL GTHWSC		;COMPUTE .DXREC VALUE (HEAD AND RECORD NUMBERS)
	MOVE T4,T1		;SAVE FOR AWHILE
	TXO T2,.DXCYL		;INSERT REGISTER NUMBER
	CALL WTREG		;SET CYLINDER INTO DX20
	MOVE T2,T4		;GET BACK .DXREC DATA
	TXO T2,.DXCYL		;INSERT REGISTER NUMBER
	HRRZM P3,KDBACT(P2)	;REMEMBER UDB WE HAVE TO WAIT FOR
	JRST CHSTRT		;START CHANNEL AND SKIP IF SUCCESSFUL
	SUBTTL Subroutine To Connect To A Drive

;DX2CON - LOAD DRIVE NUMBER INTO DX20, COMPUTES CYLINDER AND SECTOR.
;CALL:
;  P1/	CDB
;  P2/  KDB
;  P3/  UDB
;  P4/  IORB
;  Q1/  FUNCTION TABLE ENTRY
;  Q2/	DX20 UNIT NUMBER
;RETURNS:
;  +1:	FAILED TO CONNECT
;  +2:  DONE,	T1/  UNIT ADDRESS
;		T2/  CYLINDER
;		T3/  SECTOR WITHIN CYLINDER

DX2CON:	CALL HLTCHK		;MAKE SURE MICROCODE IS STILL HAPPY
	 JRST [	MOVX T1,<IS.ERR!IS.DVE!IS.NRT> ;GET FATAL DEVICE ERROR FLAGS
		IORM T1,IRBSTS(P4)
		RET]
	RDRG .DXERR		;READ ERROR REGISTER
	TXNN T1,ER.ALL		;ANY ERRORS?
	JRST CONNOE		;NO, PROCEED NORMALLY
	MOVE T4,T1		;COPY ERROR
	RDRG .DXEND		;GET ENDING STATUS ALSO
	HRL T4,T1		;PUT WITH OTHER DATA
	CALL FNDCKU		;COLLECT NUMBERS
	BUG.(CHK,DXBEWC,PHYP2,HARD,<PHYP2 - Error present when connecting to a unit>,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>,<T4,20AND2>>,<

Cause:	One or more flags is turned on in a DX20 drive error register.
	TOPS-20 is ignoring the errors and proceeding.

Data:	CHAN - Channel number
	CTRL - Controller number
	UNIT - Unit number
	20AND2 - RH of DX20 ending status,,RH of DX20 error register
>,,<DB%NND>)			;[7.1210] 
	MOVX T2,.DXERR		;CLEAR THE ERROR REGISTER
	CALL WTREG		;SO NO CONFUSION RESULTS
				;AND PROCEED
CONNOE:	MOVE T1,UDBSTS(P3)	;GET CURRENT UNIT STATUS
	CAIE Q1,XF.WRT		;STANDARD WRITE FUNCTION?
	CAIN Q1,XF.WRF		;OR FORMATTING WRITE?
	TXNN T1,US.WLK		;YES, SEE IF THE DISK IS WRITE-LOCKED
	TXNE T1,US.OFS		;AND ALWAYS SEE IF IT IS OFF-LINE
	RET			;IF SO, OPERATOR INTERVENTION IS NEEDED
	MOVX T2,.DXDRV		;WANT TO WRITE THE DRIVE REGISTER
	MOVE T1,UDBSLV(P3)	;GET SLAVE UNIT NUMBER
	STOR T1,DRVNM,T2	;STORE WITH REGISTER NUMBER
	CALL WTREG		;TELL DX20 WHICH DRIVE TO TALK TO
	CALL PHYBLK		;RETURN PHYSICAL DISK ADDRESS TO USE IN T2
	TXZ T2,IRBPAD		;REMOVE PHYSICAL ADDRESSING BIT
	MOVE T1,T2		;REMEMBER IT IN T1
	MOVE T4,UDBSIZ(P3)	;GET POINTER TO DISK SIZE DATA
	IDIV T2,SECCYL(T4)	;DIVIDE BY SECTORS PER CYLINDER
	MOVEM T2,UDBPS1(P3)	;SAVE CYLINDER
	MOVEM T3,UDBPS2(P3)	;AND SECTOR WITHIN CYLINDER
	RETSKP			;SUCCESS RETURN
	SUBTTL Routine To Compute Latency Optimization

;ROUTINE CALLED FROM PHYSIO TO EXAMINE ALL IORBS AND PICK THE ONE
;WITH THE SMALLEST LATENCY GREATER THAN A SPECIFIED MINIMUM.  CALL:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB
;  T1/	MINIMUM LATENCY IN MICROSECONDS, OR ZERO TO PERFORM THE COMMAND
;	STACKING COMPUTATION
;RETURNS:
;  +1:	NO REQUESTS ARE AVAILABLE
;  +2:	T1/  LATENCY OF CLOSEST REQUEST GREATER THAN SPECIFIED MINIMUM,
;	     WITH ZERO RETURNED IF THIS IORB IS THE PREFERRED ONE
;	T2/  PREDECESSOR OF IORB CORRESPONDING TO TIME IN T1
;	T3/  IORB CORRESPONDING TO TIME IN T1
;
;NOTICE:  IT IS IMPOSSIBLE TO ASK THE RP20 WHICH SECTOR IS NEAR THE
;HEADS, SO THAT LATENCY OPTIMIZATION CANNOT WORK AS WELL AS FOR OTHER
;TYPES OF DISK.  INSTEAD, IORBS ARE SCANNED LOOKING FOR A REQUEST NEAR
;THE LAST KNOWN POSITION OF THE DISK.  THE UNIT WHICH LAST DID I/O IS
;GIVEN PRIORITY, SINCE ITS POSITION HAS MORE ACCURACY.  FINALLY, HIGHEST
;PRIORITY IS GIVEN TO THE IORB WHICH JUST COMPLETED A SEARCH OPERATION.
;ACS ARE USED AS FOLLOWS:
;
;  T3/	BEST SECTOR DISTANCE SO FAR,,SECTOR ON SURFACE TO AIM FOR
;  T4/	MINIMUM LATENCY FLAG,,DSKSIZ POINTER
;  P4/	PREDECESSOR TO CURRENT IORB,,CURRENT IORB TO EXAMINE
;  P5/	PREDECESSOR TO BEST IORB SO FAR,,BEST IORB SO FAR FOUND

DX2LAT:	SAVEAC <Q1>		;SAVE A FEW TEMP
	MOVE T4,UDBSIZ(P3)	;GET POINTER TO DISK SIZE TABLE
	HRLZ Q1,T1		;SAVE LATENCY AS A FLAG (ZERO MEANS DO STACKING)
	MOVEI P4,UDBTWQ(P3)	;GET POINTER TO FIRST IORB
	TLNN Q1,-1		;COMMAND STACKING COMPUTATION?
	HRRZ P4,IRBLNK(P4)	;YES, SKIP FIRST IORB SINCE IT'S DOING I/O
	SETZ P5,		;INITIALIZE BEST IORB
	MOVE T1,UDBPS2(P3)	;GET CURRENT SECTOR WITHIN THE CYLINDER
	ADD T1,SECPAG(T4)	;COMPUTE SECTOR OF NEXT PAGE
	TLNN Q1,-1		;STACKING COMPUTATION?
	JRST [	CAML T1,SECCYL(T4)	;YES, NEXT SECTOR ON SAME CYLINDER?
		RET			;NO, CAN'T STACK THEN
		JRST LATBEG]	;YES, PROCEED
	ADD T1,SECPAG(T4)	;NO, SKIP TO NEXT SECTOR
LATBEG:	IDIV T1,SECSRF(T4)	;GET SECTOR WITHIN SURFACE TO AIM FOR IN T2
	HRROI T3,(T2)		;INITIALIZE BEST DISTANCE AND DESIRED SECTOR
				;THEN FALL INTO LOOP
;NOW LOOP OVER ALL IORBS LOOKING FOR THE BEST ONE.


LATLOP:	HRRZ P4,P4		;FIXUP ADDRESS
	HRL P4,IRBLNK(P4)	;FOLLOW LINK TO NEXT IORB
	TLNN P4,-1		;ANOTHER IORB TO EXAMINE?
	JRST LATFIN		;NO, GO RETURN RESULT
	MOVS P4,P4		;YES, SET UP PREDECESSOR AND CURRENT IORB
	CAMN P4,UDBCHB		;CHECK FOR HOMEBLOCK REQUEST
	JRST PREFHB		;PREFERENCE TO HOMEBLOCKS ALWAYS!!!
	TLNN Q1,-1		;COMMAND STACKING COMPUTATION?
	JRST NOPREF		;YES, DON'T CHECK PREFERRED IORB
	HRRZ T2,CDBIRB(T1)	;GET PREFERRED IORB IF ANY
	CAIE T2,(P4)		;IS THIS IT?
	JRST NOPREF		;NO, PROCEED NORMALLY
PREFHB:	MOVEI T1,0		;FLAG PREFERRED IORB WITH ZERO LATENCY
	HLRZ T2,P4		;GET PREVIOUS IORB
	HRRZ T3,P4		;AND THE PREFERRED IORB
	RETSKP			;RETURN IT

NOPREF:	BLOCK.			;Need a context
	 SAVEAC <P4>		;Save IORB addresses
	 HRRZS P4		;Isolate IORB address
	 CALL PHYBLK		;COMPUTE UNIT RELATIVE ADDRESS FOR THIS IORB
	ENDBK.
	TXZ T2,IRBPAD		;REMOVE PHYSICAL ADDRESSING BIT
	MOVE T1,T2		;COPY IT
	IDIV T1,SECCYL(T4)	;COMPUTE SECTOR WITHIN CYLINDER
	MOVE T1,T2		;COPY RESULT AGAIN
	IDIV T1,SECSRF(T4)	;COMPUTE SECTOR WITHIN SURFACE
	CAIGE T2,(T3)		;SECTOR NUMBER BELOW OUR GOAL?
	ADD T2,SECSRF(T4)	;YES, ADD ONE REVOLUTION'S WORTH OF SECTORS
	SUBI T2,(T3)		;SUBTRACT TO GET SECTORS BETWEEN LOCATIONS
	HLRZ T1,T3		;GET BACK OLD BEST DISTANCE
	CAML T2,T1		;THIS IORB CLOSER THAN PREVIOUS ONES?
	JRST LATLOP		;NOPE, LOOK AT NEXT IORB THEN
	MOVE P5,P4		;IT'S BETTER, REMEMBER IORB AND PREDECESSOR
	HRL T3,T2		;REMEMBER NEW BEST DISTANCE ALSO
	JUMPN T2,LATLOP		;LOOK FOR BETTER ONE UNLESS FOUND A BEST CASE

LATFIN:	JUMPE P5,[BUG.(HLT,DXBLTF,PHYP2,SOFT,<PHYP2 - Latency optimization failure>,,<

Cause:	The routine DX2LAT in PHYP2 was called by PHYSIO to find the best
	IORB for a unit.  However, after scanning all IORBs in the transfer
	wait queue for the unit, no IORB was found that could be returned.

>)	;IF FOUND NO IORB, COMPLAIN
		  RET]		;AND ERROR RETURN
	HLRZ T1,T3		;GET BEST DISTANCE
	IMULI T1,^D2700		;CONVERT SECTORS INTO MICROSECONDS OF LATENCY
	HRRZ T2,CDBLUN(P1)	;GET UNIT WHICH LAST DID I/O ON THE CHANNEL
	CAIN T2,(P3)		;WAS IT THIS UNIT?
	AOSA T1			;YES, ADD ONE TO INSURE NONZERO RESULT
	ADDI T1,2		;NO, ADD EXTRA ONE TO PENALIZE UNIT
	HLRZ T2,P5		;GET PREDECESSOR OF BEST IORB
	HRRZ T3,P5		;AND THE BEST IORB ITSELF
	RETSKP			;SUCCESSFUL RETURN
	SUBTTL Routine To Handle Normal Interrupts

;ROUTINE CALLED TO PROCESS A DONE INTERRUPT.  ONLY THE COMPLETION OF A
;DATA OPERATION COMES HERE.
;CALL:
;  P1/	CDB
;  P2/	KDB
;RETURNS:
;  +1:	IORB HAD ERRORS
;	  P3/	UDB
;  +2:	I/O WAS SUCCESSFUL
;	  P3/	UDB

DX2INT:	PUSH P,Q1		;SAVE REGISTERS
	PUSH P,Q2		;THAT WE WILL TRASH (NOTE AOS -2(P) BELOW)
	MOVE Q2,K.DXAD(P2)	;SET UP DX20 UNIT NUMBER
	CALL DOINT		;HANDLE THE INTERRUPT
	 SKIPA			;NON-SKIP
	AOS -2(P)		;SKIP RETURN, PASS IT ON
	RDRG .DXCTL		;READ CONTROL REGISTER
	TXNN T1,DX.GO		;DX20 FREE?
	CALL ASYNST		;YES, CHECK ON ASYCHRONOUS STATUS TOO
	MOVX T1,CS.AC2		;GET READY FOR CHECK
	TDNN T1,CDBSTS(P1)	;STILL DOING I/O BECAUSE OF STACKED COMMAND?
	SETZM KDBACT(P2)	;NO, CLEAR ACTIVE UDB
	POP P,Q2		;RESTORE ACS
	POP P,Q1		;THAT WE SAVED
	RET			;DONE
;HERE TO HANDLE THE DONE INTERRUPT.  DX20 UNIT NUMBER IS IN Q2.


DOINT:	SKIPN P3,KDBACT(P2)	;GET THE UDB I/O WAS BEING DONE FOR
	JRST [	HRRZ T1,CDBADR(P1)	;NONE, GET CHANNEL READY
		BUG.(CHK,DXBNUD,PHYP2,HARD,<PHYP2 - No unit active for Done interrupt>,<<T1,CHAN>,<Q2,DX20>>,<

Cause:	A done interrupt occurred on a DX20 but there is no active UDB for
	this controller.

Data:	CHAN - Channel number
	DX20 - DX20 number
>,,<DB%NND>)			;[7.1210] 
		RET]		;AND GIVE ERROR
	MOVE T1,UDBSTS(P3)	;GET UDB STATUS FLAGS
	TXNE T1,US.ACT		;MAKE SURE UDB WAS ACTIVE
	TXNE T1,US.POS		;AND THAT IT WAS NOT POSITIONING
	JRST [	CALL FNDCKU	;NOPE, COLLECT CKU NUMBERS
		BUG.(CHK,DXBUA1,PHYP2,HARD,<PHYP2 - Done interrupt and unit was not active>,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>>,<

Cause:	A done interrupt occurred on a DX20 but the UDB for the drive
	marked in the KDB as active is not.

Data:	CHAN - Channel number
	CTRL - Controller number
	UNIT - Unit number
>,,<DB%NND>)			;[7.1210] 
		RET]		;AND ERROR RETURN
	CALL SETIRB		;SET UP THE CURRENT IORB
	HRRZ T1,UDBERR(P3)	;GET FUNCTION IF DOING ERROR RECOVERY
	SKIPN T1		;DOING IT?
	LDB T1,IRYFCN		;NO, GET FUNCTION FROM IORB
	CAIG T1,MXFUNC		;A LEGAL FUNCTION?
	JRST DOINT2		;YES
	CAIGE T1,MNRP2V		;MAKE SURE IT IS LEGAL
	JRST INTBDF		;NOPE
DOINT2:	CALL HARCHK		;CHECK FOR ANY ERRORS
	 RET			;HAD SOME, ERROR RETURN
	HRRZ T1,UDBERR(P3)	;GET BACK FUNCTION
	SKIPN T1		;ERROR RECOVERY?
	LDB T1,IRYFCN		;NO, NORMAL FUNCTION FROM IORB THEN
	SKIPGE T1,RP2FNC(T1)	;GET DISPATCH ADDRESS
	TRNN T1,-1		;ALSO MAKE SURE HAVE AN ADDRESS
INTBDF:	BUG.(HLT,DXBILF,PHYP2,SOFT,<PHYP2 - Illegal function at Done interrupt>,,<

Cause:	The routine DX2INT in PHYP2 was called to handle a done interrupt
	for a drive.  The IORB which finished I/O contained a function
	code which was illegal.

>)		;NO, LOSE
	CALL (T1)		;CALL PROPER ROUTINE
	 RET			;FAILED, ERROR RETURN
	RETSKP			;SUCCESSFUL RETURN
;HERE ON THE VARIOUS CASES OF INTERRUPTS:



RP2WRT:	MOVX T1,US.WLK		;GET WRITE LOCKED FLAG
	ANDCAM T1,UDBSTS(P3)	;CLEAR SINCE WRITE HAS COMPLETED
RP2RED:	RDRG .DXSTS		;GET STATUS REGISTER
	TXNN T1,ST.ERR		;ANY DRIVE ERRORS?
	CALL CKERR		;OR ANY CHANNEL ERRORS?
	 JRST RP2DER		;YES, GO HANDLE THEM
	CALL PHYCNT		;COMPUTE LENGTH OF TRANSFER
	ADDI T1,PGSIZ-1		;ROUND UP PARTIAL SECTORS
	LSH T1,-PGSFT		;CONVERT TO SECTORS (PAGES) TRANSFERED
	LDB T2,IRYFCN		;GET FUNCTION
	CAIE T2,IRFRVC
	CAIN T2,IRFRED		;READING?
	JRST [	ADDM T1,UDBRED(P3) ;YES, INCREMENT SECTORS READ
		CAIN T2,IRFRED	;READ?
		 AOS UDBRCT(P3)	;YES, SO COUNT READS DONE ALSO
		CAIN T2,IRFRVC	;IS IT A SKIP READ?
		 AOS UDBRVC(P3) ;YES SO INCREMENT SKIP READS DONE
		RETSKP]
	ADDM T1,UDBWRT(P3)	;YES, INCREMENT SECTORS WRITTEN
	AOS UDBWCT(P3)		;YES, COUNT WRITES DONE
	RETSKP			;SUCCESSFUL

;HERE IF HAD SOME KIND OF ERROR:

RP2DER:	CALL REDALL		;READ ALL REGISTERS AND SENSE BYTES
	MOVX T1,IS.ERR		;GET ERROR FLAG
	IORM T1,IRBSTS(P4)	;FLAG THIS IORB AS FAILED
	RET			;FAIL RETURN
	SUBTTL Routine To Handle Attention Interrupts

;ROUTINE CALLED ON AN ATTENTION INTERRUPT.  SUCH INTERRUPTS OCCUR FOR
;THE FOLLOWING REASONS:
;  1.	THE CURRENT DATA OPERATION TERMINATED WITH ERRORS.  WE WILL FLAG
;	THE FACT THAT AN ERROR OCCURED, AND WILL DISMISS THE INTERRUPT.
;	A NORMAL INTERRUPT WILL IMMEDIATELY OCCUR, AND WE WILL BE RECALLED
;	AT THE DX2INT ROUTINE, WHICH WILL NOTICE AND HANDLE THE ERROR.
;  2.	THE DRIVE THAT A SEEK/SEARCH WAS OPERATION WAS GIVEN TO HAS
;	DISCONNECTED ITSELF FROM THE CONTROLLER, SO THAT THE CONTROLLER
;	IS NOW FREE TO ACCEPT MORE COMMANDS.  IT IS POSSIBLE THAT THE
;	SEEK/SEARCH HAS COMPLETED AT THIS TIME ALSO (BUT IS UNLIKELY).
;  3.	ASYCHRONOUS STATUS FOR A DRIVE HAS APPEARED.
;
;CALL:
;  P1/	CDB
;  P2/	KDB
;RETURNS:
;  +1:	ALWAYS
;	P3/  0
;	P4/  0  (THIS INDICATES NO IORB WAS IN ERROR)
;	Q1/  LEFT HALF SET TO -1 IF SCHEDULING DESIRED BECAUSE OF A
;	     COMPLETED SEEK OPERATION




DX2ATN:	MOVEM Q1,K.SAVQ(P2)	;SAVE Q1 IN AN ACCESSIBLE LOCATION
	PUSH P,Q2		;SAVE ONE ON THE STACK TOO
	MOVE Q2,K.DXAD(P2)	;SET UP DX20 UNIT NUMBER
	MOVX T2,AT.0		;GET ATTENTION BIT READY
	LSH T2,(Q2)		;POSITION IT
	TXO T2,.DXATN		;INSERT REGISTER NUMBER
	CALL WTREG3		;CLEAR THE ATTENTION
	RDRG .DXCTL		;READ CONTROL REGISTER
	TXNE T1,DX.GO		;CONTROLLER STILL BUSY?
	JRST ATNXIT		;YES, IGNORE THIS INTERRUPT
	CALL DOATTN		;CHECK ON NORMAL ATTENTIONS
	CALL ASYNST		;THEN CHECK ON ASYCHRONOUS STATUS
ATNXIT:	POP P,Q2		;RESTORE ONE AC
	MOVE Q1,K.SAVQ(P2)	;RESTORE Q1 WHICH MAYBE HAD LH SET TO -1
	SETZB P3,P4		;NO IORB ERRORS TO RETURN
	RET			;DONE
;ROUTINE TO HANDLE NORMAL (NON ASYCHRONOUS) ATTENTION INTERRUPTS.
;DX20 UNIT NUMBER IS IN Q2.

DOATTN:	SKIPN P3,KDBACT(P2)	;GET ACTIVE UDB IF ANY
	RET			;NONE
	MOVX T1,US.ACT		;VERIFY UDB IS REALLY ACTIVE
	TDNN T1,UDBSTS(P3)	;WELL?
	JRST [	CALL FNDCKU	;NO, COLLECT CKU NUMBERS
		BUG.(CHK,DXBUNA,PHYP2,HARD,<PHYP2 - Attention interrupt and unit was not active>,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>>,<

Cause:	An attention interrupt occurred for a DX20 drive but the unit
	listed in the KDB as active is not.

Data:	CHAN - Channel number
	CTRL - Controller number
	UNIT - Unit number
>,,<DB%NND>)			;[7.1210] 
		SETZB P3,KDBACT(P2)	;CLEAR ACTIVE UDB
		RET]		;AND RETURN
	RDRG .DXEND		;READ ENDING STATUS
	TXNN T1,ES.CHE!ES.DVE!ES.UNC!ES.UNE	;DX20 HAVE STATUS FOR US?
	RET			;NO, DON'T EXAMINE DRIVE YET
	MOVE Q3,T1		;SAVE STATUS
	SKIPE T1,UDBERR(P3)	;DOING ERROR RECOVERY?
	JRST ATNERC		;YES, NEED TO USE DISPATCH ADDRESS
	CALL SETIRB		;GET THE CURRENT IORB
	MOVX T2,US.POS		;GET READY FOR CHECK
	TDNE T2,UDBSTS(P3)	;WAS THIS A POSITION OPERATION?
	JRST ATNPOS		;YES, GO HANDLE IT
	RET			;WAS FAILED DATA OPERATION, IGNORE ATTENTION
				;SINCE DX2INT CODE WILL NOTICE ERROR
;HERE ON AN ATTENTION INTERRUPT DURING ERROR RECOVERY:


ATNERC:	SKIPL T1,RP2FNC(T1)	;GET DISPATCH ADDRESS READY
	TRNN T1,-1		;DATA OPERATION OR NO DISPATCH ADDRESS?
	RET			;YES, IGNORE INTERRUPT
	CALL SETIRB		;GET THE CURRENT IORB
	JRST (T1)		;THEN GO TO ROUTINE



;HERE ON AN ATTENTION CAUSED BY A POSITION DONE INTERRUPT:


ATNPOS:	MOVX T1,KS.ACT		;GET ACTIVE FLAG FOR THE CONTROLLER
	ANDCAM T1,KDBSTS(P2)	;CONTROLLER NO LONGER BUSY
	SETZM KDBACT(P2)	;NO MORE ACTIVE UDB EITHER
	TXNE Q3,ES.DVE!ES.UNC!ES.UNE	;DEVICE END UP OR ERRORS?
	JRST ATNSRC		;YES, SEARCH IS FINISHED
	HRROS K.SAVQ(P2)	;SEARCH STILL GOING, REMEMBER TO SCHEDULE
	RET			;DONE



;HERE WHEN A POSITION REQUEST IS COMPLETED (SEARCH FOUND THE SPECIFIED
;SECTOR AND WE HAVE TO START I/O QUICKLY).


ATNSRC:	TXNE Q3,ES.UNC!ES.UNE	;ANY UNIT ERROR?
	JRST SRCBAD		;YES, GO GIVE SEARCH ERROR
	CALLRET SRCDON		;NOPE, MARK SEARCH AS DONE
	SUBTTL Routine To Handle Asychronous Status

;THIS ROUTINE MUST BE CALLED AT THE END OF EVERY INTERRUPT (IF THE DX20
;IS NOT BUSY) TO LOOK FOR ASYCHRONOUS STATUS.  THE DX20 GIVES US SUCH
;STATUS FOR A DRIVE WHICH COMES ONLINE OR HAS COMPLETED A SEARCH/SEEK.
;ASYCHRONOUS STATUS IS PRESENTED BY THE DX20 ONLY IF THE ATTENTION BIT
;AND THE ASYCHRONOUS REGISTER ARE BOTH CLEAR.  THUS AFTER READING THE
;STATUS, WE HAVE TO ZERO THESE TO ALLOW MORE STATUS TO APPEAR.  CALL:
;  P1/	CDB
;  P2/	KDB
;RETURNS:
;  +1:	ALWAYS

ASYNST:	MOVE Q2,K.DXAD(P2)	;SET UP DX20 UNIT NUMBER
	RDRG .DXASY		;READ ASYNCHRONOUS STATUS IF ANY
	JUMPE T1,R		;NOTHING TO DO IF NO STATUS
	MOVX T2,.DXASY		;SET UP IN CASE NEED TO READ IT AGAIN
	TXNN T1,ES.CUE!ES.BSY!ES.CHE!ES.DVE!ES.UNC!ES.UNE	;STATUS YET?
	CALL RDREG3		;NO, READ AGAIN SINCE HE WASN'T YET DONE
	PUSH P,Q3		;SAVE AN AC
	PUSH P,P3		;AND ANOTHER ONE
	PUSH P,P4		;AND ANOTHER ONE
	MOVE Q3,T1		;MOVE STATUS TO SAFE PLACE
	MOVX T2,AT.0		;GET ATTENTION BIT
	LSH T2,(Q2)		;POSITION FOR THIS DX20
	TXO T2,.DXATN		;INSERT REGISTER NUMBER
	CALL WTREG3		;CLEAR ANY ATTENTION CAUSE BY THE STATUS
	MOVX T2,.DXASY		;WANT TO CLEAR ASYCHRONOUS STATUS REGISTER
	CALL WTREG3		;CLEAR IT TO ALLOW NEW STATUS
	LOAD T4,ASDRV,Q3	;GET DRIVE PRESENTING CURRENT STATUS
	CALL DRVSRC		;FIND THE UDB
	 JRST [	CALL NEWONL	;NOT FOUND, CREATE UDB IF POSSIBLE
		JRST ASYNS2]	;AND FINISH UP
	CALL ASYNDO		;FOUND IT, HANDLE STATUS FOR THE DRIVE
ASYNS2:	POP P,P4		;RESTORE AC
	POP P,P3		;RESTORE AC
	POP P,Q3		;AND ANOTHER
	JRST ASYNST		;CHECK FOR MORE STATUS
;ROUTINE TO HANDLE ASYCHRONOUS STATUS FOR A PARTICULAR UNIT.  CALL:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB
;  Q2/	DX20 NUMBER
;  Q3/	ASYCHRONOUS STATUS FOR THIS DRIVE (FROM .DXASY REGISTER)
;RETURNS:
;  +1:	ALWAYS




ASYNDO:	MOVE T2,UDBSTS(P3)	;GET STATUS
	TXNN T2,US.ACT		;WERE WE EXPECTING AN INTERRUPT?
	JRST ONLINE		;NO, GO SEE IF DRIVE IS USABLE AGAIN
	SKIPE T1,UDBERR(P3)	;IN ERROR RECOVERY?
	JRST ATNERC		;YES, GO TO SPECIAL CODE
	CAMN P3,KDBACT(P2)	;GETTING STATUS FROM CURRENTLY ACTIVE UDB?
	RET			;YES, IGNORE SINCE IT IS EXTRANEOUS
	TXNN T2,US.POS		;DOING A SEEK FOR THIS DRIVE?
	JRST [	CALL FNDCKU	;NO, COLLECT CKU NUMBERS
		BUG.(CHK,DXBASD,PHYP2,HARD,<PHYP2 - Asynchronous status from non-positioning drive>,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>>,<

Cause:	An asynchronous interrupt occurred from a DX20 drive that was not
	in the process of doing a seek operation.

Data:	CHAN - Channel number
	CTRL - Controller number
	UNIT - Unit number

>)	;COMPLAIN
		RET]		;AND RETURN
	CALL SETIRB		;YES, GET THE ACTIVE IORB
	TXNE Q3,ES.DVE		;DEVICE END NOT SET?
	TXNE Q3,ES.UNC!ES.UNE	;OR ANY UNIT ERRORS?
	JRST SRCBAD		;YES, THEN HAVE A FAILED SEEK
				;NOPE, THEN IS A FINISHED SEEK


;HERE WHEN A SEARCH HAS FINISHED SUCCESSFULLY:


SRCDON:	HRRZM P4,CDBIRB(P1)	;WE WANT TO START TRANSFERS ON THIS IORB
	AOS UDBSEK(P3)		;INCREMENT SEEKS (SEARCHES) DONE
	CALL PHYSDN		;INFORM PHYSIO SEARCH IS DONE
	HRROS K.SAVQ(P2)	;REMEMBER TO SCHEDULE MORE STUFF
	RET			;DONE
;HERE IF HAD AN ERROR ON A SEARCH OPERATON.  THE CURRENT WORKINGS OF PHYSIO
;DO NOT ALLOW SEEK ERRORS TO BE RETURNED FOR INDIVIDUAL UNITS OF A CONTROLLER.
;THEREFORE MAKE A SYSERR ENTRY, COUNT SEEK ERRORS, BUT MARK THE IORB AS
;SUCCESSFUL.  THE FOLLOWING TRANSFER WILL THEN DO AN IMPLIED SEEK, WHICH
;WILL CATCH THE ERROR IF IT WAS HARD.



SRCBAD:	AOS UDBSPE(P3)		;CALL THIS A SOFT POSITIONING ERROR
	CALL ERRSET		;ALLOCATE AN ERROR BLOCK
	SKIPN Q1,T1		;MOVE ADDRESS TO RIGHT AC
	JRST SRCDON		;IF NO SYSERR BLOCK, ACT LIKE SEARCH IS DONE
	MOVEM Q1,UDBERP(P3)	;SAVE ADDRESS IN THE UDB
	PUSH P,IRBSTS(P4)	;REMEMBER CURRENT STATUS OF IORB
	MOVX T1,IS.ERR!IS.DVE	;GET SOME ERROR FLAGS
	IORM T1,IRBSTS(P4)	;PLACE INTO IORB TEMPORARILY FOR LOGGING
	CALL REDALL		;READ ALL REGISTERS AND SENSE BYTES
	CALL RDRINI		;STORE THEM INTO SYSERR BLOCK
	CALL RDRFIN		;MAKE THEM THE FINAL REGISTERS ALSO
	CALL ERRFIN		;TERMINATE ERROR LOGGING
	POP P,IRBSTS(P4)	;RESTORE ORIGINAL FLAGS
	JRST SRCDON		;THEN ACT LIKE SEARCH WAS SUCCESSFUL
;ROUTINES TO HANDLE ON-LINE TRANSITIONS, EITHER FROM AN OLD EXISTENT DRIVE
;OR FROM A TOTALLY UNKNOWN DRIVE.  IF CALLED FOR AN UNKNOWN DRIVE, WE
;HAVE TO BUILD A UDB FOR THE UNIT.



NEWONL:	TXNE Q3,ES.DVE		;DEVICE END UP?
	TXNE Q3,ES.UNC!ES.UNE	;AND NO ERRORS DETECTED?
	RET			;NO, DON'T CREATE UDB THEN
	PUSH P,Q3		;PRESERVE DRIVE NUMBER AND STATUS
	PUSH P,P5		;SAVE SOME ACS
	PUSH P,Q1		;THAT WILL BE USED
	LOAD Q1,ASDRV,Q3	;GET UNIT NUMBER
	TLO Q1,-1		;CREATE AOBJN WORD FOR THIS UNIT ONLY
	MOVX P5,US.OFS		;BEGIN STATUS WITH DRIVE OFF-LINE
	SETZ Q3,		;PREVENT A BUGCHK ON SICK DRIVES
	CALL ISDRV		;TRY TO BUILD A NEW UDB FOR THIS DRIVE
	POP P,Q1		;RESTORE ACS
	POP P,P5		;THAT WE SAVED
	POP P,Q3		;RESTORE UNIT NUMBER AND STATUS
	LOAD T4,ASDRV,Q3	;GET DRIVE NUMBER
	CALL DRVSRC		;NOW SEE IF THE UDB GOT BUILT
	 RET			;NOPE, IGNORE IT
				;YES, NOW FALL INTO NORMAL ON-LINE CODE

ONLINE:	MOVX T1,US.WLK		;ASSUME DRIVE IS WRITABLE AGAIN
	ANDCAB T1,UDBSTS(P3)	;SO CLEAR WRITE LOCK AND GET OTHER BITS
	TXNE Q3,ES.DVE		;HAVE DEVICE END?
	TXNE Q3,ES.UNC!ES.UNE	;AND NO ERROR BITS?
	RET			;NO, DRIVE IS STILL OFF-LINE THEN
	TXNN T1,US.OFS		;DID WE THINK THE DRIVE WAS OFF-LINE?
	RET			;NO, IGNORE SPURIOUS STATUS THEN
	MOVX T1,US.CHB		;YES, NEED TO DO
	IORM T1,UDBSTS(P3)	; HOMEBLOCK CHECK
	CALL PHYONL		;MARK THE DEVICE ON-LINE AGAIN
	HRROS K.SAVQ(P2)	;REMEMBER TO TELL PHYSIO TO SCHEDULE
	RET			;DONE
	SUBTTL Routine To Check For Data Errors

;ROUTINE TO SEE IF A TRANSFER OPERATION HAD ANY DRIVE OR CONTROLLER
;ERRORS.  CALL:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB
;  P4/	IORB
;RETURNS:
;  +1:	ERRORS FOUND AND FLAGGED
;  +2:	NO ERRORS FOUND OR OF NO IMPORTANCE



HARCHK:	MOVX T1,IS.DVE!IS.DTE	;GET IORB ERROR BITS
	ANDCAM T1,IRBSTS(P4)	;CLEAR THEM TO BEGIN
	MOVX T2,.DXERR		;SET UP TO READ ERROR REGISTER
	CALL RDREG		;READ IT
	TXNN T1,ER.ALL		;ANY ERRORS?
	RETSKP			;NO, SUCCESSFUL RETURN
	TXNE T1,ER.STP!ER.MPE	;DX20 HALTED OR HAS MEMORY PROBLEMS?
	JRST ISDEAD		;YES, GO MARK THE CONTROLLER DOWN
	TXNE T1,ER.ILF!ER.ILR	;ILLEGAL FUNCTION OR REGISTER?
	JRST ISHARD		;YES, CALL THIS A HARD ERROR
	TXNE T1,ER.RMR!ER.CPE!ER.DPE	;RMR ERROR OR BUS PARITY ERRORS?
	JRST ISFAIL		;YES, TRY THE OPERATION AGAIN
	LOAD T2,ERCOD,T1	;GET POSSIBLE ERROR CODE
	TXNE T1,ER.NEW		;NO ERROR CODE STORED?
	CAILE T2,ERCMAX		;OR CODE IS OUT OF RANGE?
	MOVEI T2,0		;YES, TURN INTO CODE ZERO FOR UNKNOWN
	CALL @ERCTAB(T2)	;DISPATCH ON ERROR CODE TYPE
	 RET			;ERROR RETURN
	RETSKP			;SUCCESS RETURN
;DISPATCH TABLE FOR ERROR CLASS CODES.  CODE IS OBTAINED FROM THE
;ERCOD FIELD OF THE ERROR REGISTER (.DXERR).  THIS FIELD IS VALID ONLY
;IF THE ER.NEW FLAG IS SET IN THE ERROR REGISTER.



ERCTAB:	IFIW ISUNKN		;(0) ILLEGAL OR UNKNOWN ERROR
	IFIW ISUNUS		;(1) UNUSUAL DEVICE STATUS
	IFIW ISIGNR		;(2) RECORD LENGTH ERROR
	IFIW ISOFFL		;(3) DRIVE SELECTION ERROR
	IFIW ISFAIL		;(4) RECOVERABLE ERROR
	IFIW ISRETY		;(5) COMMAND RETRY REQUEST
	IFIW ISFAIL		;(6) NON-RECOVERABLE ERROR
	IFIW ISIGNR		;(7) RETRY LOG INFORMATION AVAILABLE
	IFIW ISDEAD		;(10) FATAL ERRORS

	ERCMAX==.-ERCTAB-1	;HIGHEST KNOWN ERROR CODE




;HERE WHEN THE ERROR IS UNKNOWN:


ISUNKN:	HRRZ T2,CDBADR(P1)	;GET CHANNEL
	BUG.(CHK,DXBIEC,PHYP2,SOFT,<PHYP2 - Unknown error code from DX20>,<<T2,CHAN>,<Q2,DX20>,<T1,STATUS>>,<

Cause:	A transfer operation on a RP20 drive had drive failed. This
	indicates a drive or controller error but the error code provided
	by the DX20 is not valid.

Data:	DX20 - DX20 number
	STATUS - DX20 error register
>,,<DB%NND>)			;[7.1210] 
	JRST ISHARD		;AND MAKE THIS A HARD ERROR
;HERE TO HANDLE UNUSUAL DEVICE STATUS (ERROR CLASS 1).  THIS IS THE
;NORMAL ERROR CODE FOR TYPICAL DEVICE AND DATA ERRORS.  INFORMATION ON
;THE PARTICULAR ERROR IS OBTAINED FROM THE ENDING STATUS REGISTER AND
;THE SENSE BYTES.


ISUNUS:	MOVX T2,.DXEND		;WANT TO READ ENDING STATUS
	CALL RDREG		;DO IT
	TXNE T1,ES.BSY		;IS CONTROLLER BUSY?
	JRST ISFAIL		;YES, VERY OBSCURE, RETRY IT
	TXNN T1,ES.UNC!ES.UNE	;UNIT CHECK OR EXCEPTION?
	JRST ISIGNR		;NO, IGNORE SPURIOUS ERROR
	CALL REDALL		;READ ALL REGISTERS AND CLEAR ERRORS
	MOVE T2,K.DEXS(P2)	;GET SENSE BYTES 0 THROUGH 3
	TXNE T2,S0.IVR		;INTERVENTION REQUIRED?
	JRST ISOFF2		;YES, MARK DRIVE OFF-LINE
	TXNE T2,S0.REJ		;COMMAND REJECTED?
	JRST ISRJEC		;YES, GO SEE IF WRITE-LOCKED
	LOAD T1,SBECOD		;GET ERROR FORMAT AND MESSAGE
	CAIL T1,FC.IVC		;FORMAT 0, MESSAGE 1 THRU
	CAILE T1,FC.FPR		;FORMAT 0, MESSAGE A ARE DEVICE ERRORS
	SKIPA
	CALLRET ISFAI2		;RETRY AS DEVICE ERROR
	LSH T1,-4		;GET FORMAT NUMBER
	CAIN T1,2		;FORMAT 2 ARE DCU ERRORS
	CALLRET ISFAI2		;RETRY AS DEVICE ERROR
	TXNE T2,S0.BPE!S1.FPE!S1.WLK ;CHECK FOR OTHER POSSIBLE DEVICE ERRORS
	CALLRET ISFAI2		;RETRY AS DEVICE ERRORS.
	CALLRET ISDATC		;FLAG ALL OTHERS AS DATA CHECKS.
;HERE IF THE DRIVE HAS GONE OFF-LINE:


ISOFFL:	CALL REDALL		;READ ALL REGISTERS AND CLEAR THE ERROR
ISOFF2:	CALL PHYOFL		;MARK THE DRIVE OFF-LINE
	JRST ISFAI2		;CALL IT A RECOVERABLE ERROR, SO ON THE
				;NEXT RETRY THE UNIT WILL BE MARKED AS
				;WAITING FOR OPERATOR INTERVENTION




;HERE IF THE COMMAND WAS REJECTED, PROBABLY DUE TO A WRITE-LOCKED DRIVE.
;IF SO, CLEAR THE ACTIVE STATUS OF THE IORB AND REQUEST ANOTHER SCHEDULER
;CYCLE, WHICH WILL THEN MARK THE DRIVE AS NEEDING OPERATOR INTERVENTION.
;THE DRIVE WILL STAY THAT WAY UNTIL RANDOM ASYCHRONOUS STATUS APPEARS DUE
;TO THE OPERATOR HITTING THE ATTN BUTTON OR POWERING UP THE DRIVE.  THIS
;ROUNDABOUT PROCEDURE IS NECESSARY BECAUSE YOU CAN'T TELL IF AN RP20 IS
;WRITE-LOCKED WITHOUT ACTUALLY TRYING TO WRITE ON IT!!!



ISRJEC:	TXNN T2,S1.WLK		;IS DRIVE REALLY WRITE-LOCKED?
	JRST ISFAI2		;NO, GO TO NORMAL ERROR STUFF
	SKIPE UDBERR(P3)	;YES, SEE IF IN MIDDLE OF ERROR RECOVERY
	JRST ISHAR2		;IF SO, DON'T CONFUSE THINGS!
	MOVX T1,IS.WLK		;GET FLAG READY
	IORM T1,IRBSTS(P4)	;REMEMBER IN IORB FOR STATUS WATCHERS
	MOVX T1,US.WLK		;GET WRITE-LOCK FLAG FOR UDB
	IORM T1,UDBSTS(P3)	;PREVENT ANY FURTHER WRITES FOR THIS UNIT
	CALL CLRACT		;MARK THE DRIVE IDLE
	SETZM P3		;FORGET ABOUT THIS UNIT
	SETOM P4		;REQUEST A SCHEDULER CYCLE
	RET			;AND STOP STACKED COMMAND BY DOING ERROR RETURN




;HERE ON A NORMAL DATA CHECK ERROR:


ISDATC:	MOVX T1,IS.DTE!IS.ERR	;GET ERROR FLAGS
	IORM T1,IRBSTS(P4)	;FLAG THAT A DATA ERROR OCCURRED
	MOVX T1,UE.DAT		;GET ANOTHER FLAG
	IORM T1,UDBERR(P3)	;REMEMBER IN UDB ALSO
	RET			;RETURN ERROR
;HERE IN CASES WHERE THE OPERATION FAILED DUE TO SOME DEVICE ERROR,
;BUT THERE IS REASON TO THINK THAT RETRYING THE OPERATION MIGHT WIN.



ISFAIL:	CALL REDALL		;READ IN REGISTERS AND CLEAR THE ERROR
ISFAI2:	MOVX T1,UE.DEV		;GET FLAG READY
	IORM T1,UDBERR(P3)	;REMEMBER THAT THIS IS A DEVICE ERROR
	MOVX T1,IS.ERR!IS.DVE	;GET IORB FLAGS
	IORM T1,IRBSTS(P4)	;MARK THE ERROR IN THE IORB
	RET			;DONE




;HERE FOR RETRY REQUEST ERROR (ERROR CLASS 5).
;
;AS OF DXMCE MICROCODE EDIT 16 WE WILL APPEAR HERE UNDER THE FOLLOWING:
;1. A DATA ERROR OR OVERRUN OCCURED THAT THE DX CANNOT RETRY BECAUSE THE
;   DATA PATH WAS REQUIRED. CHANNEL HAS ABORTED CONNECTION.
;2. A DATA ERROR OR OVERRUN OCCURED IN THE COUNT/KEY FIELDS, THE DX HAS
;   RETRIED 39 TIMES WITHOUT SUCCESS.
;3. AN ERROR OCCURED AS IN 2, DX RECOVERED ONLY TO FIND AN ERROR IN THE
;   DATA FIELD. COULD BE ECC RECOVERABLE.
;
;NOTE THAT THE CHANNEL ABORT REQUEST IS IGNORED. THE CHANNEL CONNECTION
;IS ALWAYS ABORTED ON A RETRY.

ISRETY:	CALL REDALL		;READ SENSE INFORMATION
	MOVE T1,K.DCNI(P2)	;GET CONI STATUS WORD
	TXNE T1,CI.OVR		;IF DUE TO OVERRUN
	 CALLRET ISFAI2		;THEN RETRY AS DEVICE ERROR
	CALLRET ISDATC		;FLAG AS DATA ERROR





;HERE ON ERROR CONDITIONS WHICH ARE NOT REALLY ERRORS, OR WHICH ARE
;DETECTED ELSEWHERE (SUCH AS OVERRUNS).  JUST CLEAR THE ERROR REGISTER
;AND SAY THE OPERATION SUCCEEDED.


ISIGNR:	MOVX T2,.DXERR		;GET ERROR REGISTER
	CALL WTREG		;CLEAR IT OUT
	RETSKP			;RETURN SAYING NO ERRORS FOUND
;HERE ON FATAL ERRORS WHICH INDICATE THAT THE MICROPROCESSOR IS
;MALFUNCTIONING.  COMPLAIN AND MARK THE CONTROLLER AS HALTED.


ISDEAD:	CALL REGALL		;READ THE MASSBUSS REGISTERS ONLY
	MOVX T2,.DXMAI!MR.RES	;GET READY TO STOP THE PROCESSOR
	CALL WTREG		;MAKE SURE IT IS STOPPED
	MOVX T1,KS.HLT		;GET HALT FLAG
	IORM T1,KDBSTS(P2)	;REMEMBER THAT THE CONTROLLER IS DEAD
	HRRZ T1,CDBADR(P1)	;GET CHANNEL NUMBER
	BUG.(CHK,DXBDIE,PHYP2,HARD,<PHYP2 - DX20B microcode halted>,<<T1,CHAN>,<Q2,DX20>>,<

Cause:	The microcode in a DX20B has halted. This indicates a hardware
	problem with the DX20 microprocessor.

Action:	Contact Field Service.

Data:	CHAN - Channel number
	DX20 - DX20 number
>,,<DB%NND>)			;[7.1210] 
	JRST ISHAR2		;KILL REQUEST





;HERE ON DEVICE ERRORS WHICH WE CANNOT EXPECT TO RECOVER FROM.  FLAG
;THE ERROR AS FATAL.


ISHARD:	CALL REDALL		;READ IN ALL REGISTERS
ISHAR2:	MOVX T1,IS.DVE!IS.ERR!IS.NRT	;GET FLAGS FOR FATAL ERROR
	IORM T1,IRBSTS(P4)	;MARK THEM IN THE IORB
	MOVX T1,UE.HRD!UE.DEV	;GET HARD ERROR AND DEVICE ERROR FLAGS
	IORM T1,UDBERR(P3)	;REMEMBER IN THE UDB
	RET			;ERROR RETURN
	SUBTTL Error Recovery

;ROUTINE CALLED BY PHYSIO TO RECOVER FROM ERRORS.  THIS ROUTINE IS CALLED
;IN THE FOLLOWING CASES:
;  1.	WHEN A NEW OPERATION FAILED, AFTER THE INITIAL ERROR STATUS
;	AND CAUSE HAS BEEN SAVED.
;  2.	ON EACH RETRY OPERATION THEREAFTER, EVEN IF THE RETRY SUCCEEDED.
;	IS.ERR WILL BE SET IN THE IORB IF THE OPERATION FAILED.  IF IS.ERR
;	IS NOT SET, THEN WE HAVE RECOVERED AND THE ERROR WAS SOFT.
;RETURNS:
;  +1:	ERROR RECOVERY STILL IN PROGRESS
;  +2:	ERROR RECOVERY IS FINISHED (IS.ERR SET IF UNSUCCESSFUL)




DX2ERR:	SAVEQ			;SAVE REGISTERS
	HRRZ Q1,UDBERP(P3)	;GET ERROR BLOCK (IF ANY)
	MOVE Q2,UDBSTS(P3)	;GET UDB STATUS
	AOS Q3,UDBERC(P3)	;INCREMENT RETRY COUNTER
	CAIN Q3,1		;FIRST TIME?
	CALL RDRINI		;YES, COPY INITIAL REGISTERS
	MOVE T1,IRBSTS(P4)	;GET STATUS OF IORB
	TXNE T1,IS.IER!IS.NRT	;ERROR RECOVERY INHIBITED OR NO MORE RETRIES?
	JRST HRDERR		;YES, THIS ERROR IS HARD THEN
	TXNN T1,IS.ERR		;DID THE LAST RETRY SUCCEED?
	JRST SFTERR		;YES, THIS WAS A SOFT ERROR
	TXNE Q2,US.POS		;ERROR DURING A TRANSFER?
	JRST POSERR		;NO, GO HANDLE POSITIONING ERROR
	MOVE T1,UDBERR(P3)	;TRANSFER ERROR, GET ERROR STATUS
	TXNN T1,UE.DEV		;DEVICE ERROR?
	TXNN T1,UE.DAT		;OR NOT A DATA ERROR?
	JRST DEVERR		;YES, A DEVICE ERROR
	LDB T1,IRYFCN		;GET FUNCTION FROM IORB
	LOAD T2,SBECOD		;AND ERROR CLASS CODE FROM 7TH SENSE BYTE
	CAIN T1,IRFRED		;WAS THIS A VANILLA READ OPERATION?
	CAIE T2,FC.ECC		;AND DOES THE DX20 THINK IT'S ECC CORRECTABLE?
	JRST DATERR		;NO, JUST PLAIN DATA ERROR THEN
	LOAD Q3,SBEPOS		;YES, GET ECC POSITION FROM BYTES 18 AND 19
	CAILE Q3,BYTSEC		;REASONABLE ECC POSITION?
	JRST DATERR		;NO, TREAT AS NORMAL DATA ERROR
	JRST ECCERR		;YES, GO DO THE ECC CORRECTION
;HERE ON A DEVICE ERROR DURING A SEARCH OR SEEK OPERATION.  WE DO NOT
;GENERATE SEEK ERRORS, SO THAT SUPPOSEDLY IT IS IMPOSSIBLE TO GET HERE.
;THEREFORE, JUST GIVE A HARD ERROR WITHOUT RETRYING.


POSERR:	MOVX T1,UE.POS!UE.DEV	;MARK A POSITIONING ERROR
	IORM T1,UDBERR(P3)	;IN THE UDB ERROR LOCATION
	MOVX T1,IS.DVE		;MARK A DEVICE ERROR
	IORM T1,IRBSTS(P4)	;IN THE IORB STATUS
	JRST HRDERR		;AND CAUSE A HARD ERROR




;HERE TO HANDLE DEVICE OR SIMPLE DATA ERRORS FROM A DATA TRANSFER OPERATION.
;FLAG THE ERROR AND INITIATE THE NEXT STEP IN ERROR RECOVERY.  THE ALGORITHM
;IS SIMPLE, SINCE THERE ARE NO FANCY OFFSETS OR SUCH TO TRY.  JUST TRY THE
;OPERATION OVER AGAIN MANY TIMES, WITH OCCASIONAL RECALIBRATIONS.


DATERR:	MOVX T1,UE.DAT		;GET DATA ERROR FLAG
	MOVX T2,IS.DTE		;ANOTHER ONE TOO
	JRST ERR		;JOIN OTHER CODE

DEVERR:	MOVX T1,UE.DEV		;GET DEVICE ERROR FLAG
	MOVX T2,IS.DVE		;AND ANOTHER ONE

ERR:	IORM T1,UDBERR(P3)	;FLAG THE ERROR IN THE UDB
	IORM T2,IRBSTS(P4)	;AND IN THE IORB
	MOVE T1,UDBERC(P3)	;GET CURRENT RETRY COUNT
	IDIVI T1,RTYCNT		;SPLIT INTO TWO NUMBERS
	JUMPN T2,RETRY		;DO STRAIGHT RETRY MOST OF THE TIME
	CAIG T1,RCLCNT		;RECALIBRATION TIME, MORE TO DO?
	JRST RECAL		;YES, GO DO ONE
	JRST HRDERR		;NO, GIVE UP
;HERE ON A DATA ERROR WHICH IS ECC CORRECTABLE.  TO CORRECT AN ECC ERROR,
;THE DX20 PROVIDES THE FOLLOWING INFORMATION IN THE SENSE BYTES:
;  18-19  FIRST BYTE IN ERROR COUNTED FROM THE LAST BYTE IN THE SECTOR
;	  (FROM 0 TO ^D2304).  ZERO MEANS THE ERROR WAS IN THE ECC BYTE
;	  ITSELF, AND THEREFORE THE DATA IS ACTUALLY OK.
;  20-21  MASK WHICH WHEN XORED WITH THE DATA ACTUALLY READ WILL
;	  CORRECT THE DATA.
;SENSE BYTES 18-19 ARE ALREADY IN AC Q3.



ECCERR:	JUMPE Q3,ECCER2		;SKIP ON IF ERROR WAS IN ECC BYTE
	MOVNI T1,-BYTSEC(Q3)	;COMPUTE BYTES FROM START OF PAGE
	LSH T1,3		;CONVERT TO BITS
	TLZ T1,-1		;CLEAR JUNK
	IDIVI T1,^D36		;COMPUTE OFFSET IN SECTOR AND POSITION IN WORD
	MOVE Q3,T1		;SAVE OFFSET IN SECTOR
	MOVNI T2,-^D<36-16>(T2)	;COMPUTE SHIFT VALUE FOR MASK
	LOAD P5,SBEMSK		;GET THE ECC MASK FROM BYTES 20 AND 21
	SKIPN P5		;MASK SHOULD BE NONZERO
	BUG.(CHK,DXBZEC,PHYP2,HARD,<PHYP2 - Zero ECC byte returned>,,<

Cause:	An ECC correctable error occurred on a DX20 drive. The byte number
	in error in the sector was zero. This indicates the error was in
	the ECC byte itself and the data is actually correct.
>,,<DB%NND>)			;[7.1210] 
	SETZ P6,		;CLEAR SECOND WORD OF MASK
	LSHC P5,(T2)		;SHIFT MASK TO PROPER POSITION
	CALL ECCADR		;GET ADDRESS OF BEGINNING OF SECTOR TRANSFERED
	ADDI T1,(Q3)		;POINT TO ADDRESS OF FIRST WORD TO BE FIXED
	JUMPE P5,ECCER1		;SKIP SOME IF NO CORRECTION NECESSARY
	PMOVE T2,T1		;[7.1002] GET THE DATA WORD
	XOR T2,P5		;APPLY THE ECC MASK TO THE WORD
	PMOVEM T2,T1		;[7.1002] AND STORE BACK THE CORRECTED DATA
ECCER1:	JUMPE P6,ECCER2		;SKIP SOME IF NO CORRECTION NECESSARY
	ADDI T1,1		;INCREMENT TO SECOND WORD
	PMOVE T2,T1		;[7.1002] GET THE DATA WORD
	XOR T2,P6		;APPLY THE ECC MASK TO THE WORD
	PMOVEM T2,T1		;[7.1002] AND STORE BACK THE CORRECTED DATA
ECCER2:	CALL ECCUCL		;UPDATE CCW LIST, RETURN WORDS TRANSFERED OK
	 JRST ECCDON		;WAS IN LAST SECTOR, FINISH UP
	BUG.(HLT,DXBMSR,PHYP2,SOFT,<PHYP2 - Multiple sectors indicated in ECC recovery>,,<

Cause:	The routine ECCERR in PHYP2 was called to recover from an ECC error
	on a unit.  After correcting the error, the routine ECCUCL in PHYSIO
	was called to update the CCW list.  That routine skipped, indicating
	that more sectors must be read to complete the transfer.  However,
	the RP20 is formatted in pages and no transfer is ever longer than
	a page, so the skip return should never occur.

>)		;NEVER GET HERE SINCE ALWAYS READING ONE SECTOR


ECCDON:	MOVX T1,UE.ECC		;GET ERROR FLAG
	IORM T1,UDBERR(P3)	;REMEMBER WE HAD AN ECC-CORRECTABLE ERROR
	MOVX T1,IS.ERR!IS.DTE	;GET ERROR BIT IN IORB
	ANDCAM T1,IRBSTS(P4)	;AND CLEAR IT SINCE WE RECOVERED
	AOS UDBSRE(P3)		;INCREMENT SOFT READ ERROR COUNTER
	RETSKP			;SKIP RETURN TO SAY ALL DONE
;HERE IF THE LAST RETRY SUCCEEDED SO THAT THE ERROR WAS SOFT:


SFTERR:	MOVEI T1,T1		;PROTECT IN CASE NOTHING MATCHES
	LDB T2,IRYFCN		;GET FUNCTION FROM IORB
	CAIE T2,IRFRVC		;READ VALIDITY CHECK?
	CAIN T2,IRFRED		;READ?
	MOVEI T1,UDBSRE(P3)	;YES, POINT TO SOFT READ COUNTER
	CAIE T2,IRFWVC		;WRITE VALIDITY CHECK?
	CAIN T2,IRFWRT		;WRITE?
	MOVEI T1,UDBSWE(P3)	;YES, POINT TO SOFT WRITE COUNTER
	TXNE Q2,US.POS		;WAS THIS A SEEK OPERATION?
	MOVEI T1,UDBSPE(P3)	;YES, POINT TO SOFT POSITION COUNTER
	AOS (T1)		;INCREMENT PROPER COUNTER
	CALL RDRFIN		;READ FINAL REGISTERS NOW
	RETSKP			;SKIP RETURN TO INDICATE RECOVERY FINISHED




;HERE ON A HARD ERROR WHEN NO AMOUNT OF RETRIES SUCCEEDED, OR IF
;ERROR RECOVERY WAS INHIBITED:


HRDERR:	MOVX T1,IS.ERR!IS.NRT	;INDICATE HARD ERROR WITH NO RETRIES
	IORM T1,IRBSTS(P4)	;PUT IN IORB
	MOVX T1,UE.HRD		;GET HARD ERROR FLAG
	IORM T1,UDBERR(P3)	;REMEMBER IN ERROR WORD
	MOVEI T1,T1		;PROTECT IN CASE OF NO MATCH
	LDB T2,IRYFCN		;GET FUNCTION FROM IORB
	CAIE T2,IRFRVC		;READ VALIDITY?
	CAIN T2,IRFRED		;READ?
	MOVEI T1,UDBHRE(P3)	;YES, POINT TO HARD READ COUNTER
	CAIE T2,IRFWVC		;WRITE VALIDITY CHECK?
	CAIN T2,IRFWRT		;WRITE?
	MOVEI T1,UDBHWE(P3)	;YES, POINT TO HARD WRITE COUNTER
	TXNE Q2,US.POS		;POSITIONING?
	MOVEI T1,UDBHPE(P3)	;YES, POINT TO HARD POSITIONING COUNTER
	AOS (T1)		;INCREMENT COUNTER
	CALL RDRFIN		;READ FINAL REGISTERS
	RETSKP			;SKIP RETURN TO INDICATE ALL DONE
;HERE TO RECALIBRATE A DRIVE AFTER MANY UNSUCCESSFUL OPERATIONS:



RECAL:	MOVEI T1,RCLNDX		;GET INDEX FOR RECALIBRATION
	HRRM T1,UDBERR(P3)	;REMEMBER FUNCTION FOR ERROR RECOVERY
	CALL SETIO		;MARK THE IORB ACTIVE
	HRRZ T1,UDBERR(P3)	;GET FUNCTION BACK
	LOAD Q1,TBFNC,(T1)	;TRANSLATE TO HARDWARE FUNCTION
	MOVE Q2,K.DXAD(P2)	;SET UP DX20 UNIT NUMBER
	CALL DX2CON		;CONNECT TO THE DRIVE
	 JRST HRDERR		;FAILED, CALL THE ERROR HARD
	CALL DOPOS		;START THE OPERATION
	 JFCL			;CHSTRT ALWAYS SKIPS
	RET			;DONE



;HERE ON THE ATTENTION INTERRUPT AFTER THE RECAL IS INITIATED.  SEE
;IF THE OPERATION IS TOTALLY FINISHED.  IF NOT, WE HAVE TO WAIT FOR
;THE ASYCHRONOUS STATUS TO APPEAR.



RTYRCL:	TXNE Q3,ES.DVE!ES.UNC!ES.UNE	;IS OPERATION COMPLETE?
	JRST RCLFIN		;YES, SKIP ONWARD
	MOVEI T1,RC2NDX		;NO, GET FUNCTION CODE READY
	HRRM T1,UDBERR(P3)	;CHANGE DISPATCH FOR NEXT INTERRUPT
	SETZM P4		;WANT TO WAIT FOR ASYCHRONOUS STATUS
	RET			;RETURN
;HERE WHEN DEVICE END IS UP, EITHER FROM THE INITIAL ATTENTION
;INTERRUPT, OR ON THE ASYCHRONOUS STATUS INTERRUPT.  GO BACK
;AND RETRY THE OPERATION WHICH FAILED.




RCLFIN:	MOVX T1,US.POS		;SEE IF ORIGINAL OPERATION WAS A SEARCH
	TDNN T1,UDBSTS(P3)	;WAS IT?
	JRST RETRY		;NO, THEN GO RESTART A TRANSFER OPERATION
	JRST HRDERR		;YES, CALL IT A HARD ERROR THEN





;HERE TO RETRY A TRANSFER OPERATION:


RETRY:	HRRZ Q1,UDBSTS(P3)	;GET ERROR BLOCK IF PRESENT
	LDB T1,IRYFCN		;GET ORIGINAL OPERATION
	HRRM T1,UDBERR(P3)	;REMEMBER FUNCTION FOR ERROR RECOVERY
	CALL SETIO		;MARK THE IORB ACTIVE
	HRRZ T1,CDBDSP(P1)	;GET CHANNEL DISPATCH
	CALL CDSSIO(T1)		;TRY TO RESTART THE I/O
	 JRST HRDERR		;FAILED, CALL IT HARD ERROR
	SETZM P4		;WANT TO DISMISS THIS INTERRUPT
	RET			;DONE
	SUBTTL Subroutines To Load Up The SYSERR Blocks



;RDRINI - ROUTINE CALLED ON FIRST ERROR TO LOAD UP THE SYSERR BLOCK.
;THE MASSBUSS REGISTERS AND DX20 SENSE BYTES HAVE ALREADY BEEN SAVED
;IN THE KDB.  THIS ROUTINE COPIES THEM INTO THE SYSERR BLOCK AS THE
;INITIAL STATUS FOR THE ERROR.



RDRINI:	JUMPE Q1,R		;CAN'T DO THIS IF NO ERROR BLOCK
	MOVE T1,Q1		;COPY ADDRESS OF BLOCK
	MOVE T2,[-NEDAT,,EDAT]	;SET UP POINTER TO CONTROL TABLE
	CALL SEBCPY		;COPY THE DATA
	 JFCL			;FAILURE
	CALL PHYBLK		;GET PHYSICAL ADDRESS
	TXZ T2,IRBPAD		;REMOVE PHYSICAL ADDRESSING BIT
	MOVEM T2,SEBDAT+MB%LOC(Q1)	;SAVE IT
	MOVE T1,[REGNUM,,DX%MBR]	;GET COUNT AND OFFSET READY
	MOVEM T1,SEBDAT+DX%MBI(Q1)	;SAVE POINTER TO MASSBUS REGISTERS
	MOVE T1,[<<SNSNUM+3>/4>,,DX%ESR]	;GET OTHER COUNT READY TOO
	MOVEM T1,SEBDAT+DX%ESI(Q1)	;SAVE POINTER TO SENSE BYTE REGISTERS
	MOVEI T1,SEBDAT+DX%MBR(Q1)	;POINT TO STORAGE AREA FOR REGISTERS
	MOVE T2,T1		;COPY ADDRESS
	HRLI T1,K.DREG(P2)	;INSERT SOURCE ADDRESS FOR BLT
	BLT T1,REGNUM+<<SNSNUM+3>/4>-1(T2)	;MOVE TO SYSERR BLOCK
	RET			;DONE




;TABLE OF DATA TO COPY AT INITIAL ERROR RECOVERY TIME:


EDAT:	SEBPTR MB%CNI,SBTWD,K.DCNI(P2)	;CONI
	SEBPTR MB%D1I,SBTWD,K.DCS1(P2)	;TCR
	SEBPTR MB%D2I,SBTWD,K.DDBF(P2)	;BAR/DBF
	SEBPTR MB%CS0,SBTWD,CDBCS0(P1)	;CHANNEL STATUS 0
	SEBPTR MB%CS1,SBTWD,CDBCS1(P1)	;CHANNEL STATUS 1
	SEBPTR MB%CS2,SBTWD,CDBCS2(P1)	;CHANNEL STATUS 2
	SEBPTR MB%CC1,SBTWD,CDBCC1(P1)	;CCW 1
	SEBPTR MB%CC2,SBTWD,CDBCC2(P1)	;CCW 2
	SEBPTR MB%ICR,SBTWD,CDBICR(P1)	;INITIAL CONTROL REGISTER

	NEDAT==.-EDAT		;NUMBER OF ENTRIES IN TABLE
;RDRFIN - ROUTINE TO STORE REGISTERS AT END OF RETRY.  CALLED AT THE END
;OF ERROR RECOVERY TO COPY THE FINAL MASSBUSS REGISTER VALUES INTO THE
;SYSERR BLOCK ALONGSIDE THE INITIAL REGISTERS.  THE FINAL REGISTERS HAVE
;ALREADY BEEN READ INTO THE KDB.




RDRFIN:	HRRZ Q1,UDBERP(P3)	;GET ERROR BLOCK AGAIN IF ANY
	JUMPE Q1,R		;DONE IF NO BLOCK
	MOVEI T1,K.DREG(P2)	;POINT TO REGISTERS TO SAVE
	HRLI T1,-REGNUM		;INSERT COUNTER FOR LOOP
	MOVEI T2,SEBDAT+DX%MBR(Q1)	;POINT TO STORAGE IN SYSERR BLOCK
RDRFIL:	MOVE T3,(T1)		;GET REGISTER
	HRLM T3,(T2)		;SAVE AWAY ALONGSIDE INITIAL VALUE
	ADDI T2,1		;INCREMENT TO NEXT ADDRESS
	AOBJN T1,RDRFIL		;LOOP OVER ALL REGISTERS
	MOVE T1,K.DCNI(P2)	;GET FINAL CONI
	MOVEM T1,SEBDAT+MB%CIF(Q1)	;SAVE IN SYSERR BLOCK
	MOVE T1,K.DCS1(P2)	;GET FINAL TCR
	MOVEM T1,SEBDAT+MB%D1F(Q1)	;SAVE
	MOVE T1,K.DDBF(P2)	;GET FINAL BAR
	MOVEM T1,SEBDAT+MB%D2F(Q1)	;SAVE IT TOO
	RET			;DONE
	SUBTTL Routine To Check For Dual Porting

;THIS ROUTINE IS CALLED TO SEARCH ALL CURRENTLY BUILT UDBS LOOKING FOR
;THE OTHER END OF A DUAL PORTED DRIVE.  (THIS ASSUMES THAT NO UDB IS YET
;BUILT FOR THIS SIDE OF THE DUAL PORTED DRIVE).
;CALL:
;  T1/	RP20 UNIT NUMBER
;RETURNS:
;  +1:	UNIT IS NOT YET KNOWN TO BE DUAL PORTED
;  +2:	UNIT DEFINITELY DUAL PORTED
;	  T1/  UDB OF THE UNIT
;
;NOTE:  THERE IS NO WAY TO ASK THE HARDWARE WHETHER OR NOT AN RP20 SPINDLE
;IS DUAL PORTED.  THEREFORE THE MONITOR DEPENDS ON THE FOLLOWING CONVENTION
;BASED ON THE DRIVE NUMBER TO MAKE ITS DECISIONS (WHICH SHOULD BE ENFORCED
;BY FIELD SERVICE!):
;
;  DRIVE NUMBER LESS THAN 20:  DRIVE IS SINGLE PORTED.
;  OTHERWISE:  IF TWO DIFFERENT COMBINATIONS OF RH20 AND DX20 EXIST
;   SUCH THAT THE SAME DRIVE NUMBER EXISTS ON EACH COMBINATION, THEN
;   THOSE TWO COMBINATIONS ARE THE TWO PORTS FOR THAT DRIVE.



CKDUAL:	CAIGE T1,DUADRV		;IS DRIVE NUMBER IN RANGE OF DUAL PORT DRIVES?
	RET			;NO, SAY DRIVE ISN'T DUAL PORTED
	SAVEPQ			;PRESERVE REGISTERS
	HRRZ Q1,T1		;SAVE DRIVE NUMBER AND SAY NO UDB FOUND YET
	MOVSI Q2,-CHNN		;GET READY FOR SEARCH OF ALL CHANNELS

CKDUA2:	SKIPN P1,CHNTAB(Q2)	;THIS CHANNEL EXIST?
	JRST CKDUA3		;NO, GO LOOK AT NEXT ONE
	CALL DGUMAP		;LOOP OVER ALL UNITS ON THE CHANNEL
	 CALL CKDUAU		;INSTRUCTION TO XCT FOR EACH UNIT
	TLNN Q1,-1		;CHECKED ALL UNITS ON CHANNEL, FIND THE UNIT?
	JRST CKDUA3		;NOPE, LOOK AT NEXT CHANNEL
	HLRZ T1,Q1		;YES, SET UP UDB ADDRESS
	RETSKP			;AND RETURN SAYING DRIVE IS DUAL PORTED

CKDUA3:	AOBJN Q2,CKDUA2		;LOOP OVER ALL CHANNELS
	RET			;DRIVE NOT FOUND, SO ISN'T DUAL PORTED YET
;SUBROUTINE CALLED BY DGUMAP TO CHECK EACH UDB.  IF THIS UDB IS FOR THE
;DRIVE WE ARE SEARCHING FOR, THE UDB ADDRESS IS SAVED IN LEFT HALF OF Q1.

CKDUAU:	LOAD T1,USTYP,(P3)	;GET UNIT TYPE
	CAIE T1,.UTP20		;IS THIS AN RP20?
	RET			;NO, IGNORE IT
	HRRZ T1,UDBSLV(P3)	;YES, GET SLAVE NUMBER
	CAIN T1,(Q1)		;IS THIS THE ONE WE ARE LOOKING FOR?
	HRL Q1,P3		;YES, REMEMBER UDB ADDRESS
	RET			;DONE
	SUBTTL Misc Routines

;DRVSRC - FIND THE UDB GIVEN THE DRIVE NUMBER OF A DRIVE.
;GIVEN THE 8-BIT DRIVE NUMBER, THIS ROUTINE RETURNS THE UDB FOR
;THAT DRIVE.  INDEXING INTO K.DUDB WILL NOT WORK SINCE A TABLE
;256 ENTRIES LONG WOULD BE NEEDED.
;  T4/	DRIVE NUMBER, P2/  KDB
;RETURNS:
;  +1:	NO UDB FOUND WITH THIS DRIVE NUMBER
;  +2:	P3/  ADDRESS OF THE FOUND UDB
;DESTROYS T1.




DRVSRC:	MOVSI T1,-NUMDRV	;BUILD AOBJN POINTER
	ADDI T1,K.DUDB(P2)	;POINT TO UDB TABLE
	SKIPE P3,(T1)		;ANY UDB THERE?
	CAME T4,UDBSLV(P3)	;YES, IS IT THIS UNIT?
	AOBJN T1,.-2		;NO, LOOK MORE
	JUMPL T1,RSKP		;GOOD RETURN IF FOUND IT
	RET			;ERROR RETURN




;HERE TO SEE IF A PARTICULAR UNIT EXISTS ON THIS DX20.
;  Q2/	UNIT TO CHECK
;RETURNS:
;  +1:	T1/ 0	UNIT IS ILLEGAL
;	T1/ -1	NONEXISTENT UNIT
;  +2:	UNIT EXISTS


DX2EXT:	SKIPL T4,Q2		;MOVE TO RIGHT AC AND CHECK LEGALITY
	CAIL T4,MAXDRV
	 JRST RFALSE		;UNIT NUMBER IS ILLEGAL
	CALL DRVSRC		;SEE IF THIS UNIT IS EXISTENT
	 JRST RTRUE		;NO
	RETSKP			;YES, SKIP RETURN
;DX2CNV - ROUTINE TO CONVERT A SECTOR NUMBER INTO CYLINDER NUMBER AND
;REMAINDER.  CALLED FROM PHYSIO.  CALL:
;  P3/	UDB
;  P4/	IORB
;RETURNS:
;  +1:	ALWAYS, WITH:
;	  T2/	CYLINDER NUMBER (UDBPS1)
;	  T3/	SECTOR WITHIN CYLINDER (UDBPS2)



DX2CNV:	CALL PHYBLK		;GET THE DISK ADDRESS INTO T2
	TXZ T2,IRBPAD		;REMOVE PHYSICAL ADDRESSING BIT
	MOVE T3,UDBSIZ(P3)	;THEN GET POINTER TO DISK SIZE TABLE
	IDIV T2,SECCYL(T3)	;DIVIDE BY SECTORS/CYLINDER TO GET RESULTS
	RET			;DONE





;GTHWSC - ROUTINE TO CONVERT A SECTOR WITHIN A CYLINDER INTO THE FORMAT
;NEEDED FOR SETTING UP THE .DXREC REGISTER (HEAD AND RECORD NUMBERS,
;WITH THE PROPER REGISTER NUMBER).  CALL:
;  T3/	SECTOR IN CYLINDER
;RETURNS:
;  +1:	ALWAYS,	T1/  .DXREC DATA READY FOR USE
;PRESERVES T2.



GTHWSC:	MOVE T4,UDBSIZ(P3)	;GET ADDRESS OF SIZE TABLE
	IDIV T3,SECSRF(T4)	;SPLIT INTO SURFACE AND RECORD VALUES
	MOVX T1,.DXREC		;GET REGISTER NUMBER
	STOR T3,RCHED,T1	;INSERT HEAD NUMBER (SURFACE NUMBER)
	STOR T4,RCREC,T1	;AND RECORD WITHIN SURFACE
	RET			;DONE
;DX2CCK - CALLED ONCE A MINUTE FROM PHYCHK TO SEE IF THE DX20
;HAS HALTED, AND IF SO TO TRY AND RESTART IT.
;ARGUMENTS:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB (ANY ONE WILL DO)
;RETURNS:
;  +1:	ALWAYS
;TRASHES Q2



DX2CCK:	MOVE Q2,K.DXAD(P2)	;GET CONTROLLER NUMBER
	CALL HLTCHK		;IS MICROCODE STILL HAPPY?
	 CALL CHKMIC		;OR IS IT REAL SICK?
	  RET			;YES, NOTHING TO DO
	AOS T1,K.STCT(P2)	;INCREMENT RESTART COUNTER
	MOVEI T1,STADDR		;GET START ADDRESS
	CALL DXSTRT		;RESTART THE MICROCODE
	MOVX T1,KS.HLT		;GET HALT FLAG
	ANDCAM T1,KDBSTS(P2)	;SAY MICROCODE IS RUNNING AGAIN
	RET			;AND RETURN




;DX2HNG - ROUTINE CALLED ON A HUNG IORB.  FORCE THE DX20 TO RESTART.
;CALL:
;  P1/  CDB
;  P2/  KDB
;RETURNS:
;  +1:	ALWAYS



DX2HNG:	MOVE T1,KDBSTS(P2)	;GET STATUS
	TXNE T1,KS.HLT		;DID DX20 STOP RUNNING?
	RET			;YES, LEAVE IT ALONE THEN
	MOVE Q2,K.DXAD(P2)	;SET UP DX20 NUMBER
	MOVEI T1,STADDR		;GET START ADDRESS
	CALL DXSTRT		;CLEAR THE DX20 AND RESTART IT
	RET			;DONE
;DX2PCK - ROUTINE TO SKIP IF POSITIONING IS NEEDED.  CALLED FROM PHYSIO.
;CALL:
;  P3/	UDB
;  P4/	IORB
;RETURNS:
;  +1:	POSITIONING NOT NEEDED, SO APPEND REQUEST TO TWQ
;  +2:	POSITIONING NECESSARY, APPEND TO PWQ




DX2PCK:	MOVX T1,US.POS		;GET POSITIONING FLAG READY
	TDNE T1,UDBSTS(P3)	;UNIT ALREADY POSITIONING?
	RETSKP			;YES, THEN NEED TO POSITION THIS TOO
	CALL DX2CNV		;RETURN CYLINDER OF THIS REQUEST
	CAME T2,UDBPS1(P3)	;SAME AS CURRENT ONE?
	RETSKP			;NO, POSITIONING NECESSARY
	RET			;YES, NO POSITIONING NEEDED
	SUBTTL Subroutines For Manipulating The DX20

;CHKMIC - CHECKS THE MICROCODE IN DX20, TO SEE IF IT IS THE RIGHT ONE
;BY LOOKING INTO CRAM LOCATIONS 7 AND 10.  CRAM LOCATION 7 MUST MATCH THE
;DRIVE TYPE REGISTER, AND CRAM LOCATION 10 MUST CONTAIN THE VALUE 220.
;(VALUE 220 IS FOR TOPS-20 FORMAT DISKS, VALUE 210 IS FOR TOPS-10 FORMAT)
;THIS ROUTINE LEAVES THE MICROCODE HALTED.
;CALL:
;  P1/	CDB
;  Q2/	DX20 UNIT NUMBER
;RETURNS:
;  +1:	MICROCODE IS BAD
;  +2:	MICROCODE IS VALID



CHKMIC:	MOVX T2,.DXMAI!MR.RES	;SET UP BIT AND REGISTER NUMBER
	CALL WTREG3		;RESET THE DX20
	MOVX T2,.DXDG1!DG.UIR!DG.PCS!DG.PCI+7	;GET FLAGS AND PC VALUE OF 7
	CALL WTREG3		;SET PC AND ENABLE MICROSTORE READING
	RDRG .DXDG0		;READ IR REG. SO TO GET LOCATION 7 OF CRAM
	PUSH P,T1		;SAVE IT
	RDRG .DXTYP		;GET DRIVE TYPE REG.
	POP P,T2		;RESTORE LOCATION 7 OF CRAM
	CAME T1,T2		;DRIVE TYPE MATCH?
	RET			;NO, ERROR RETURN
	RDRG .DXDG7		;NOW CHECK FOR PARITY ERRORS
	TXNE T1,DG.IRP		;IRPER=1B22
	RET			;ERROR
	RDRG .DXDG0		;READ AGAIN TO GET LOCATION 10 (AUTO-INCREMENTS)
	CAIE T1,220		;CONTAIN PROPER CONSTANT?
	RET			;NO, ERROR
	RDRG .DXDG7		;CHECK IR PARITY ERROR AGAIN
	TXNE T1,DG.IRP		;IRPER=1B22
	RET			;ERROR
	RETSKP			;GOOD RETURN
;HLTCHK - SEES IF THE MICROCODE IS STILL RUNNING IN THE DX20.
; P1/	CDB
; P2/	KDB
; P3/	UDB
; Q2/	DX20 UNIT NUMBER
;RETURNS:
;  +1:	MICROCODE HALTED, BUGINF PRINTED IF FIRST TIME NOTICED
;  +2:	MICROCODE IS RUNNING FINE
;
;PRESERVES T4.



HLTCHK:	RDRG .DXSTS		;READ THE STATUS REGISTER
	MOVX T2,KS.HLT		;GET HALTED FLAG READY
	TXNN T1,ST.RUN		;IS IT RUNNING?
	JRST DX2STP		;NO IT QUIT ON US
	ANDCAM T2,KDBSTS(P2)	;NOT HALTED, REMEMBER THAT
	RETSKP			;GOOD RETURN


DX2STP:	TDNE T2,KDBSTS(P2)	;ALREADY KNEW THAT IT WAS STOPPED?
	RET			;YES, JUST RETURN
	IORM T2,KDBSTS(P2)	;NOW WE KNOW
	PUSH P,T4		;SAVE T4
	PUSH P,T1		;SAVE STATUS
	RDRG .DXERR		;READ ERROR REGISTER
	HRLZ T4,T1		;SAVE ERROR REGISTER
	RDRG .DXES0		;FINALLY GET POSSIBLE ERROR REASON
	HRR T4,T1		;SAVE IT
	CALL FNDCKU		;SET UP CHANNEL AND CONTROLLER NUMBERS
	POP P,T3		;RESTORE STATUS REGISTER
	BUG.(INF,DXBHLT,PHYP2,HARD,<PHYP2 - DX20B controller halted>,<<T1,CHAN>,<T2,DX20>,<T3,REG1>,<T4,2AND26>>,<

Cause:	A DX20B controller has halted.

Data:	CHAN - Channel number
	REG1 - Status register
	2AND26 - Right half of error register,,RH of error reason register
>,,<DB%NND>)			;[7.1210] 
	POP P,T4		;RESTORE AC
	RET			;ERROR RETURN
;ROUTINE TO START THE DX20 MICROCODE.  CALL:
;  T1/	PC TO START AT
;  P1/	CDB
;  P2/	KDB
;  Q2/  UNIT NUMBER OF DX20
;RETURNS:
;  +1:	ALWAYS



DXSTRT:	PUSH P,T1		;SAVE THE PC
	MOVX T2,.DXMAI!MR.RES	;GET MAINTAINANCE REGISTER AND FLAG
	CALL WTREG3		;STOP AND RESET THE DX20
	POP P,T2		;RESTORE PC
	ANDX T2,DG.PC		;MAKE SURE NOT TOO LARGE
	TXO T2,.DXDG1!DG.PCS!DG.PCI!DG.UIR	;SET REGISTER AND FLAGS
	CALL WTREG3		;LOAD STARTING ADDRESS INTO DX20
	MOVX T2,.DXMAI!MR.ST	;GET START FLAG
	CALLRET WTREG3		;START IT UP





;ROUTINE TO READ THE VERSION OF THE DX20 MICROCODE.  THIS IS STORED IN
;LOCATION 0 OF THE CRAM.  THIS ROUTINE STOPS THE DX20 MICROPROCESSOR.
;CALL:
;  P1/	CDB
;  Q2/	DX20 UNIT NUMBER
;RETURNS:
;  +1:	ALWAYS
;	  T1/	CONTENTS OF LOCATION 0 OF THE CRAM



GETVER:	MOVX T2,.DXMAI!MR.RES	;GET MAINTAINANCE REGISTER AND FLAG
	CALL WTREG3		;STOP AND RESET THE DX20
	MOVX T2,.DXDG1!DG.PCS!DG.UIR	;WANT TO CHANGE THE PC
	CALL WTREG3		;SET THE PC TO ZERO
	RDRG .DXDG0		;FINALLY READ IR REGISTER TO GET VALUE
	RET			;DONE
;GTSNS - DOES SENSE OPERATION FOR A DRIVE AND RETURNS SENSE BYTES.
;THIS ROUTINE RETURNS SENSE BYTES 0-3 IN AC T1 FOR A DRIVE.  CALL:
;  T4/	RP20 UNIT NUMBER
;  P1/	CDB
;  Q2/	DX20 NUMBER
;RETURNS:
;  +1:	FAILED TO READ THEM, BUGCHK GIVEN
;  +2:	SUCCESSFUL RETURN, BYTES IN T1




GTSNS:	CALL HLTCHK		;SEE IF MICROCODE IS STILL ALIVE
	 RET			;NO, FAIL
	MOVX T2,.DXDRV		;GET DRIVE NUMBER REGISTER READY
	STOR T4,DRVNM,T2	;INSERT DRIVE NUMBER
	CALL WTREG3		;SET IT
	MOVX T2,.DXFLG+<FLD(XS.SEN,DFCOD)>	;GET SUB-FUNCTION CODE
	CALL WTREG3		;PLACE INTO ARGUMENT REGISTER
	MOVX T2,.DXCTL+<FLD(XF.SEN,DXFNC)>	;GET FUNCTION FOR SENSE
	CALL WTREG3		;TELL DX20 TO GET THE BYTES NOW
	CALL ATTNWT		;WAIT FOR COMPLETION
	 JRST [	BUG.(CHK,DXBFGS,PHYP2,HARD,<PHYP2 - Failed to get sense bytes>,,<

Cause:	A timeout occurred while waiting for an attention interrupt from
	a DX20B after requesting the sense bytes.
>,,<DB%NND>)			;[7.1210] 
		RET]		;ERROR RETURN
	JRST RDSNS		;OK, JOIN COMMON CODE
;GETEXS - READ IN FOUR BYTES OF EXTENDED STATUS.
;THE SENSE BYTES ARE ASSUMED TO BE VALID FOR THIS CALL (EITHER AN
;ERROR JUST OCCURED ON A DRIVE AND SO THE DX20 AUTOMATICALLY READ
;THE NEW BYTES, OR ELSE A SENSE OPERATION WAS DONE EXPLICITLY).
;  T1/	INDEX FOR EXTENDED STATUS
;  P1/	CDB
;  Q2/  DX20 UNIT NUMBER
;RETURNS:
;  +1:	FAILED, BUGCHK DONE
;  +2:	SUCCESSFUL, 4 SENSE BYTES IN T1



GETEXS:	MOVX T2,.DXEND!ES.SUI	;GET BIT TO REQUEST NEW SENSE BYTES
	STOR T1,ESIDX,T2	;PLACE INDEX INTO WORD
	CALL WTREG3		;TELL DX20 TO GET THE BYTES NOW

RDSNS:	MOVX T4,100		;GET COUNTER TO TIME OUT COMPLETION
RDSNS1:	RDRG .DXEND		;READ BACK REGISTER
	TXNN T1,ES.SUI		;DX20 DONE READING SENSE BYTES YET?
	JRST RDSNS2		;YES, GO GET THEM
	SOJG T4,RDSNS1		;NO, KEEP LOOPING
	BUG.(CHK,DXBFUS,PHYP2,HARD,<PHYP2 - Failed to update sense bytes>,,<

Cause:	A timeout occurred while waiting for a DX20 to update the sense
	bytes provided to it by TOPS-20.
>,,<DB%NND>)			;[7.1210] 
	RET			;AND GIVE ERROR RETURN

RDSNS2:	RDRG .DXES0		;READ FIRST TWO SENSE BYTES
	MOVE T4,T1		;SAVE THEM
	RDRG .DXES1		;READ LAST TWO SENSE BYTES
	HRL T1,T4		;GET BACK FIRST TWO
	RETSKP			;DONE
;REDALL - ROUTINE CALLED ON ERRORS TO READ ALL REGISTERS AND EXTENDED
;STATUS INTO THE KDB, AND CLEAR THE ERROR.  CALL:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB
;RETURNS:  +1:	ALWAYS, WITH REGISTERS READ AND ERROR CLEARED




REDALL:	CALL REGALL		;FIRST READ THE DRIVE REGISTERS
	MOVX T2,.DXERR		;SET UP ERROR REGISTER NUMBER
	CALL WTREG		;CLEAR THE DX20 ERROR REGISTER
	CALLRET EXSALL		;THEN READ IN EXTENDED STATUS
;REGALL - ROUTINE TO READ ALL RELEVANT DX20 REGISTERS INTO THE K.DREG
;AREA OF THE KDB.  ALSO SAVES THE CHANNEL CONI AND DATAI WORDS.  CALLED
;TO STORE INFORMATION ON AN ERROR.  CALL:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB
;RETURNS:  +1:	ALWAYS



REGALL:	SAVEQ			;SAVE REGISTERS
	MOVEI Q1,K.DREG(P2)	;SET UP POINTER TO STORAGE AREA
	MOVX Q2,SAVBIT		;GET BITS SAYING WHICH REGISTERS TO SAVE
	SETZ Q3,		;SET UP FIRST REGISTER NUMBER

REGALP:	JUMPGE Q2,REGALN	;SKIP IF NOT SAVING THIS REGISTER
	HLLZ T2,Q3		;GET REGISTER NUMBER INTO RIGHT AC
	CAMN T2,[.DXDG0]	;ABOUT TO READ REGISTER 30?
	TDZA T1,T1		;YES, READ IT LATER
	CALL RDREG		;READ IT
	MOVEM T1,(Q1)		;SAVE IN THE KDB
	ADDI Q1,1		;ADVANCE TO NEXT STORAGE LOCATION
REGALN:	ADD Q3,[EXP 1B5]	;INCREMENT TO NEXT REGISTER NUMBER
	LSH Q2,1		;SHIFT BIT REGISTER OVER
	JUMPN Q2,REGALP		;LOOP IF STILL MORE TO READ
	CALL ERRCNI		;READ CONI AND DATAI INFO FOR CHANNEL
	MOVEM T1,K.DCNI(P2)	;SAVE CONI
	MOVEM T2,K.DCS1(P2)	;AND PCTR
	MOVEM T3,K.DDBF(P2)	;AND PBAR
	DMOVE T1,K.DREG+REG.0(P2) ;GET CONTROL AND STATUS REGISTERS
	TXNN T1,DX.GO		;IS GO STILL UP?
	TXNE T2,ST.RUN		;NO, IS THE MICROPROCESSOR STILL RUNNING
	RET			;YES, CAN'T READ REGISTER 30 THEN
	MOVX T2,.DXDG1		;SETUP TO READ THE PC REGISTER
	CALL RDREG		;READ IT
	TXZ T1,DG.UIR		;TURN OFF IR ENABLE
	MOVX T2,.DXDG1		;SET TO WRITE PC REGISTER
	IOR T2,T1		;WITH ALL THE BITS BUT IR ENABLE
	CALL WTREG		;WRITE IT BACK
	MOVX T2,.DXDG0		;SETUP TO READ THE IR
	CALL RDREG		;READ IT NOW
	MOVEM T1,K.DREG+REG.30(P2) ;STORE IT WHERE IT BELONGS
	RET			;AND FINALLY RETURN
;EXSALL - ROUTINE TO READ IN ALL EXTENDED STATUS BYTES INTO THE K.DEXS
;AREA OF THE KDB.  CALLED AFTER AN ERROR OCCURS.  CALL:
;  P1/	CDB
;  P2/	KDB
;  P3/	UDB
;RETURNS:  +1:	ALWAYS




EXSALL:	SAVEQ			;SAVE REGISTERS
	MOVSI Q1,-<SNSNUM+3>/4	;SET UP AN AOBJN POINTER FOR SENSE BYTES
	MOVE Q2,K.DXAD(P2)	;GET DX20 UNIT NUMBER
	MOVEI Q3,K.DEXS(P2)	;POINT TO AREA IN KDB TO STORE THEM

EXSALP:	HRRZ T1,Q1		;GET CURRENT INDEX FOR EXTENDED STATUS
	CALL GETEXS		;READ IN THE NEXT FOUR SENSE BYTES
	 JRST EXSALF		;FAILED, GO CLEAR THE TABLE
	MOVEM T1,(Q3)		;SAVE THESE FOUR BYTES
	ADDI Q3,1		;INCREMENT TO NEXT STORAGE ADDRESS IN THE KDB
	AOBJN Q1,EXSALP		;CONTINUE IF HAVE TO GET MORE SENSE BYTES
	RET			;DONE

EXSALF:	HLL Q3,Q1		;CAN'T GET THE INFO, COPY REMAINING COUNT
	SETZM (Q3)		;CLEAR THIS WORD
	AOBJN Q3,.-1		;DO THE REST ALSO
	RET			;AND RETURN
;ATTNWT - ROUTINE TO WAIT FOR AN ATTENTION FROM THE DX20.
;CALLED WHEN A NO OPERATION OR SENSE IS DONE, TO WAIT UNTIL THE
;ATTENTION BIT COMES UP SAYING THE OPERATION IS COMPLETE.  THEN
;THE ATTENTION BIT IS CLEARED.  CALL:
;  P1/	CDB
;  Q2/	DX20 NUMBER
;RETURNS:
;  +1:	TIMED OUT WAITING FOR ATTENTION
;  +2:	ATTENTION SEEN AND CLEARED



ATTNWT:	PUSH P,P4		;SAVE A REGISTER
	MOVEI P4,AT.0		;GET BIT FOR UNIT 0
	LSH P4,(Q2)		;POSITION PROPERLY FOR THIS DX20
	MOVEI T4,4000		;SET UP COUNTER

ATTNW1:	RDRG .DXATN		;READ THE ATTENTION REGISTER
	TDNN T1,P4		;ATTENTION UP YET?
	SOJG T4,ATTNW1		;NO, LOOK SOME MORE
	MOVE T2,P4		;MOVE ATTENTION BIT
	POP P,P4		;RESTORE AC
	JUMPLE T4,R		;FAIL IF COUNTER REACHED ZERO
	TXO T2,.DXATN		;INSERT REGISTER NUMBER
	CALL WTREG3		;CLEAR ATTENTION
	RETSKP			;GOOD RETURN
	SUBTTL Data

;FUNCTION TABLE.  USED TO CONVERT PHYSIO'S FUNCTIONS TO THE ACTUAL RP20
;HARDWARE FUNCTIONS, AND TO REMEMBER DATA ABOUT EACH FUNCTION.  THE FF
;MACRO HAS THE FOLLOWING ARGUMENTS:
;
;	FF (FLAG,FUNCTION,DISPATCH,NAME)
;WHERE:
;	FLAG IS SET IF THE FUNCTION TRANSFERS DATA. LOAD WITH TBDTF
;	FUNC IS HARDWARE FUNCTION (XF.???).  LOAD WITH TBFNC
;	DISP IS ADDRESS TO PROCESS THE FUNCTION ON INTERRUPT.  LOAD WITH TBDSP
;	NAME IS USED TO DEFINE A VARIABLE FOR THIS OFFSET INTO THE TABLE

	DEFINE FF(FLAG,FUNC,DISP,NAME),<
	IFNB <NAME>,<NAME==.-RP2FNC>	;;DEFINE OFFSET
	EXP <FLD(FLAG,TBDTF)>+<FLD(FUNC,TBFNC)>+<FLD(DISP,TBDSP)>	;;DATA
>

RP2FNC:	EXP 0			;0 - ILLEGAL
	FF (1,XF.RED,RP2RED)	;1 - READ
	FF (1,XF.RDF,RP2RED)	;2 - READ FORMAT
	FF (1,XF.WRT,RP2WRT)	;3 - WRITE
	FF (1,XF.WRF,RP2WRT)	;4 - WRITE FORMAT
	FF (0,XF.SRC,HRDERR,SRCNDX)	;5 - SEEK (SEARCH, ACTUALLY)

	MXEXTF==.-RP2FNC-1	;HIGHEST EXTERNAL FUNCTION

	FF (0,XF.REC,RTYRCL,RCLNDX)	;6 - RECALIBRATE DURING ERROR RECOVERY
	FF (0,XF.REC,RCLFIN,RC2NDX)	;7 - SECOND STAGE OF RECALIBRATION

	MXFUNC==.-RP2FNC-1	;HIGHEST LEGAL FUNCTION

	EXP 0,0,0,0,0,0		;ILLEGAL FUNCTIONS

	MNRP2V==.-RP2FNC	;LOWEST LEGAL DATA VALIDITY FUNCTION

	FF (1,XF.WRT,RP2WRT)	;16 - WRITE VALIDITY CHECK
	FF (1,XF.RED,RP2RED)	;17 - READ VALIDITY CHECK
	SUBTTL End of PHYP2

	TNXEND
	END