Trailing-Edge
-
PDP-10 Archives
-
bb-m780a-sm
-
monitor-sources/phyp2.mac
There are 25 other files named phyp2.mac in the archive. Click here to see a list.
; 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, 1 9-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
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1979,1980 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
SEARCH PROLOG,PHYPAR,SERCOD ;SYSTEM PARAMETERS
TTITLE (PHYP2,,< - DEVICE DEPENDENT CODE FOR DX20B/RP20 DISKS>)
SUBTTL DAVID I. BELL/GMU 11-AUG-80
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
STMAX==^D10 ;MAXIMUM TIMES TO RESTART MICROCODE
BYTSEC==^D2304 ;NUMBER OF 8-BIT BYTES PER SECTOR
SNSNUM==^D24 ;NUMBER OF SENSE 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.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
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
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(DXBDMI,<<T1,CHAN>,<Q2,DX20>>) ;COMPLAIN
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:
NEWDRV: MOVE T3,K.DNUM(P2) ;GET NUMBER OF DRIVES FOUND SO FAR
CAIL T3,NUMDRV ;ROOM IN K.DUDB TABLE?
JRST [ BUG(DXBTTS) ;NO, COMPLAIN
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(DXBTNF) ;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
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(DXBEUI,<<T1,CHAN>,<Q2,DX20>,<T2,UNIT>>) ;COMPLAIN
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(DXBFEX) ;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(DXBIF2) ;IT'S BAD
LOAD Q1,TBFNC,(T1) ;TRANSLATE TO HARDWARE FUNCTION
CALL PHYBLK ;OBTAIN UNIT RELATIVE ADDRESS IN T2
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 BADSI1 ;IT ISN'T, GO GIVE AN ERROR
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(DXBEWC,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>,<T4,20AND2>>) ;COMPLAIN
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
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
;CANNOT START I/O. MARK THE IORB AS FAILED AND GIVE AN ERROR RETURN.
BADSI1: MOVX T1,<IS.ERR!IS.DVE!IS.NRT> ;GET FATAL DEVICE ERROR FLAGS
IORM T1,IRBSTS(P4) ;MARK THEM IN THE IORB
RET ;AND DO ERROR 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: MOVE T4,UDBSIZ(P3) ;GET POINTER TO DISK SIZE TABLE
HRL T4,T1 ;SAVE LATENCY AS A FLAG (ZERO MEANS DO STACKING)
MOVEI P4,UDBTWQ(P3) ;GET POINTER TO FIRST IORB
TLNN T4,-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 T4,-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: 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
TLNN T4,-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
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: CALL PHYBLK ;COMPUTE UNIT RELATIVE ADDRESS FOR THIS IORB
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(DXBLTF) ;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(DXBNUD,<<T1,CHAN>,<Q2,DX20>>) ;COMPLAIN
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(DXBUA1,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>>) ;COMPLAIN
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 (DXBILF) ;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
AOS UDBRCT(P3) ;YES, COUNT READS DONE ALSO
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(DXBUNA,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>>) ;COMPLAIN
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
CALL SRCDON ;NOPE, MARK SEARCH AS DONE
RET ;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(DXBASD,<<T1,CHAN>,<T2,CTRL>,<T3,UNIT>>) ;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
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 ;SUCCESSFUL 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(DXBIEC,<<T2,CHAN>,<Q2,DX20>,<T1,STATUS>>) ;COMPLAIN
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
PUSH P,T1 ;SAVE ENDING STATUS
CALL REDALL ;READ ALL REGISTERS AND CLEAR ERRORS
POP P,T1 ;RESTORE STATUS
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
TXNN T2,S0.BPE!S0.OVR!S0.ECK!S1.PRM!S1.ITF!S1.EOC!S1.NRF!S1.FPE!S1.OPI
TXNN T2,S0.DCK ;DEVICE ERRORS OR NOT DATA CHECK ERROR?
JRST ISFAI2 ;YES, RETURN RETRIABLE ERROR
JRST ISDATC ;GO FLAG A NORMAL DATA CHECK ERROR
;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). THE DX20 DOES NOT GIVE
;THIS ERROR IN ANY REASONABLE SITUATION, THEREFORE THE MONITOR MAKES NO
;USE OF IT. WE CLEAR THE CONDITION AND DO RETRIES OURSELF.
ISRETY: MOVX T2,.DXFLG ;WANT TO READ FLAG REGISTER SPECIALLY
CALL RDREG ;GET IT
PUSH P,T1 ;SAVE FOR AWHILE
MOVX T2,.DXFLG ;GET READY
CALL WTREG ;CLEAR REGISTER BEFORE DOING ANYTHING ELSE
CALL ISFAIL ;NOW SAFE TO READ SENSE BYTES
POP P,K.DEXS+REG.22(P2) ;RESTORE TRUE VALUE OF REGISTER FOR SYSERR
RET ;DONE
;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(DXBDIE,<<T1,CHAN>,<Q2,DX20>>) ;COMPLAIN THAT THE DX20 DIED
JRST ISHAR2 ;AND TREAT THIS AS A HARD ERROR
;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(DXBZEC) ;NOPE, THEN WHY WERE WE CALLED?
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
CALL PHYMOV ;GET THE DATA WORD
XOR T2,P5 ;APPLY THE ECC MASK TO THE WORD
CALL PHYSTO ;AND STORE BACK THE CORRECTED DATA
ECCER1: JUMPE P6,ECCER2 ;SKIP SOME IF NO CORRECTION NECESSARY
ADDI T1,1 ;INCREMENT TO SECOND WORD
CALL PHYMOV ;GET THE DATA WORD
XOR T2,P6 ;APPLY THE ECC MASK TO THE WORD
CALL PHYSTO ;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(DXBMSR) ;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
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
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
CAILE T1,STMAX ;TOO MANY UPS AND DOWNS?
RET ;YES, LET DX20 REST IN PEACE THEN
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(DXBHLT,<<T1,CHAN>,<T2,DX20>,<T3,REG1>,<T4,2AND26>>) ;COMPLAIN
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(DXBFGS) ;FAILED, COMPLAIN
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(DXBFUS) ;TIMED OUT, COMPLAIN
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
CALL EXSALL ;THEN READ IN EXTENDED STATUS
RET ;DONE
;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
TNXEND
END