.MCALL .MODULE .MODULE TS,VERSION=30,COMMENT=,AUDIT=NO ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only 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 except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .SBTTL MS HANDLER for TS11, TK25, TS05, and TU80 .SBTTL ......................................... ;+ ; The MS handler controls the following tape drives made by Digital: ; ; TS11 - 1600BPI vertical-mount, 45-ips ; TK25 - DC300-cartridge drive ; TS05 - Front-load 1600BPI horizontal 25/100-ips ; TU80 - 1600BPI horizontal 25/100-ips ; ;- .SBTTL Edit History ;+ ; For RT-11 V5.4C ; 09-Jun-87 RHH Move .FORK call out of conditionalized FSM area ; at TCL1ER: ; ; For RT-11 V5.4F ; 17-Jun-88 RHH Fix BIC #FL$CIP... at TCL0ER: ; ; For RT-11 V5.5 ; 08-Aug-88 RHH Make TS05 status byte part of unit flag word, ; and adapt for UB support ; ; 07-Apr-89 RHH Upon REWIND_OFFLINE, set flag (LASTIM) requiring ; a new GET_UNIT_CHARACTERISTICS ; Update symbol names, use SYSTEM.MLB ; ; 13-Apr-89 RHH Rework abort code to get around TSV05 confusion ; when initialized during streaming write. ; Implement separate DRAST entries per controller ; ; 19-Oct-89 RHH Remove redundant calls to $SCHR, do some LOOKUP ; processing before initial $SCHR, test SSR bit ; before issuing commands. ;- .SBTTL Conditional Assembly Summary ;+ ;COND ; MS$FSM (0) File structured ; 0 NFS ; 1 FS ; ; MS$UN (1) number of supported units ; 1-8 possible range ; ; MS$CSR (172522) First CSR ; MS$CS1 (172526) Second CSR ; MS$CS2 (172532) Third CSR ; MS$CS3 (172536) Fourth CSR ; MS$CS4 (172542) Fifth CSR ; MS$CS5 (172546) Sixth CSR ; MS$CS6 (172552) Seventh CSR ; MS$CS7 (172556) Eighth CSR ; ; MS$VEC (224) First vector ; MS$VC1 (300) Second vector ; MS$VC2 (304) Third vector ; MS$VC3 (310) Fourth vector ; MS$VC4 (314) Fifth vector ; MS$VC5 (320) Sixth vector ; MS$VC6 (324) Seventh vector ; MS$VC7 (330) Eighth vector ; ; MMG$T std conditional ; TIM$T std conditional (no code effects) ; ERL$G std conditional (no code effects) ;- .IIF NDF MS$FSM MS$FSM = 0 ;Assume NO FSM .IIF NE MS$FSM MS$FSM = 1 .IIF NDF MS$UN MS$UN = 1 ;Assume ONE UNIT .IIF NDF MS$CS1 MS$CS1 = 772526 ;Unit 1 controller address MS$DB1 = MS$CS1-2 .IIF NDF MS$CS2 MS$CS2 = 772532 ;Unit 2 controller address MS$DB2 = MS$CS2-2 .IIF NDF MS$CS3 MS$CS3 = 772536 ;Unit 3 controller address MS$DB3 = MS$CS3-2 .IIF NDF MS$CS4 MS$CS4 = 772542 ;Unit 4 controller address MS$DB4 = MS$CS4-2 .IIF NDF MS$CS5 MS$CS5 = 772546 ;Unit 5 controller address MS$DB5 = MS$CS5-2 .IIF NDF MS$CS6 MS$CS6 = 772552 ;Unit 6 controller address MS$DB6 = MS$CS6-2 .IIF NDF MS$CS7 MS$CS7 = 772556 ;Unit 7 controller address MS$DB7 = MS$CS7-2 .IIF NDF MS$VC1 MS$VC1 = 300 .IIF NDF MS$VC2 MS$VC2 = 304 .IIF NDF MS$VC3 MS$VC3 = 310 .IIF NDF MS$VC4 MS$VC4 = 314 .IIF NDF MS$VC5 MS$VC5 = 320 .IIF NDF MS$VC6 MS$VC6 = 324 .IIF NDF MS$VC7 MS$VC7 = 330 .SBTTL Notes on the MS handler ;+ ; TS11 magnetic tape device handler ; ; 1. This handler is designed to allow the RT-11 monitor to access DIGITAL ; TS11 type magtape controllers. Devices include the TS11, TK25, TS05, ; and TU80 magtape drives. ; ; 2. Handler Input Formats ; ; The hardware handler accepts commands through a queue element which is ; passed to it by the system or the file structured module. The following ; table describes the queue element format and how the magtape handler ; interprets it. ; ; Word Mnemonic Purpose MS handler uses this for: ; ; 0 --- Link to next Not used. ; queue element ; ; 2 Q.CSW Pointer to MS handler reports status to monitor ; channel status by setting bit 13(20000-EOF$) if an ; word end of file condition is detected or ; bit (1-HDERR$) if a hard error ; condition is detected. ; ; 4 Q.BLK Starting block 1. .ENTER and .LOOKUP requests interpret ; number this argument as SEQNUM. ; 2. Negative codes use this as an address ; (ERRBLK) to report qualifying information. ; When zero no information is reported. ; 3. NFS .READx/.WRITx requests zero this ; word. ; ; 6(byte) Q.FUNC Special MS handler accepts the following codes: ; Function code ; 6 .PURGE ; 3 .LOOKUP (NFS) ; 1 .CLOSE ; 0 .READx/.WRITx (NFS) ; -1 Write EOF (tapemark) ; -2 Forward space ; -3 Backspace ; -4 Write with extended gap ; -5 Rewind ; -6 Offline and rewind ; -7 Write a block ; -8 Read a block ; -9 Stream at 100 ips ; ; Any other codes detected will cause a hard ; error. ; ; 7(byte) Q.JNUN Job number The job number is used by lookup and abort ; <13:11> to determine whether a unit is being used by ; F/G. ; Unit number The unit number is used to select a tape unit ; <10:8> and also by lookup to determine whether a unit ; is busy. ; ; 10 Q.BUFF Buffer address Used by .LOOKUP as the address of the filename ; to be found. First word of filename must be ; zero. Used as buffer address by ; .READx/.WRITx, read, write and write extend. ; ; 12 Q.WCNT Word count Zeroed by .LOOKUP to indicate a non RT-11 file ; structured device. Used as a word count by ; .READx/.WRITx, read, write, and write extend. ; Used as a count for the number of blocks to ; space by forward space and backspace. ; ; 14 Q.COMP Completion I/O Completion routine address ; Function ; ; 16 Q.PAR PAR1 register Relocation offset, DMA relocation offset ; if UNIBUS mapping enabled ; ; 20 Q.MEM PAR1 Relocation offset ; ; 22 --- --- Not used. ; ; The following is a description of the action taken by the handler for a ; given code. ; ; Code Action ; 3 .LOOKUP First, the command and message buffers are initialized. ; Next, the filename at Q.BUF is checked for zero (meaning a non ; file structured .LOOKUP.) Following this the table entry is ; examined to see whether another channel is using this unit. ; Finally, the SEQNUM argument (passed through Q.BLK) is examined ; for a zero value, which indicates that a rewind should be performed. ; ; 1,6 .CLOSE, .PURGE A message buffer release command is issued and ; the unit is marked unused. ; ; 0 .READx/.WRITx These requests read or write blocks of data on the ; tape currently mounted. .WRITx will report end of file when it ; sees the EOT marker. .READx will report end of file only when it ; reads a tape mark (TM). It will ignore the EOT marker. ; ; -1 Write a tapemark. ; ; -2 Forward space n blocks (n specified in Q.WCNT) until n is ; satisfied, EOT marker is sensed, or a TM is read. ; ; -3 Backspace n blocks (n specified in Q.WCNT) until n is satisfied, ; BOT is sensed, or a TM is read. ; ; -4 Erase 3 inches of tape and write a block to tape (write with ; extended gap.) ; ; -5 Rewind the tape to BOT. ; ; -6 Turn tape unit offline and rewind. ; ; -7 Write a block to tape. ; ; -8 Read a block from tape. ; ; -9 Stream at 100 ips (TS05 only) This code will be ignored by the ; other magtape handlers, as well as MS when it is running a TS11, ; TK25 or TU80. ; ; Other input to the magtape handler comes when the handler is entered at the ; abort entry point. R4 must contain the job number of the job being ; aborted. ; ; 3. Handler conditionals. ; ; When the MS$FSM conditional is defined it creates an object module which ; must be linked with the file structure module (FSM.OBJ or FSMX.OBJ). This ; enables code which allows the handler to be called (at $MT) with a queue ; element (possibly created by FSM) and the handler will execute the ; command in the queue element and will return to either FSMDON or FSMERR ; depending on whether an exception condition (end of file or hard error) ; was detected during the operation. In addition, the handler provides the ; $DONE entry point for ending queue element processing (it exits to the ; monitor.) The legal codes which the FSM may issue to the handler are ; defined in the previous section. ; ; When the MMG$T (extended memory monitor present) conditional is specified ; the handler will support 18 bit I/O. If the UB handler is installed, ; MS will operate in a 22-bit UNIBUS environment. ; ; 4. Handler structure ; ; The handler is divided into 3 main parts. ; ; 1. The I/O init section transforms a queue element into a command, ; initiates the command and then exits to the monitor while the unit ; is performing the command. ; ; 2. When the command completes the interrupt handler is entered. The ; interrupt handler is subdivided into 2 major sections. ; ; 1. The completion evaluation section is divided into 8 ; classes. Each requires different actions based on the ; status returned by the TS11. The classes are summarized ; below: ; 0. The operation succeeded normally ; ; 1. The operation resulted in an attention condition ; ; 2. The operation resulted in a tape status alert, ; (ie. EOT,EOF,BOT,RLS,RLL) ; ; 3. The operation was rejected. (ie. needed message ; buffer address, backspace into BOT, offline, ; writelock, hard error) ; ; 4. The operation resulted in a recoverable error ; with the tape position currently 1 block down from ; where the command was issued. ; ; 5. The operation resulted in a recoverable error ; with the tape positon currently the same as when ; the command was issued ; ; 6. The operation resulted in an unrecoverable error ; ; 7. The TS11 is hopelessly corrupted, must reinit the ; controller ; ; 2. The other section consists of routines needed to implement ; the various recovery algorithms. ; ; 3. The Data area stores information about which tape units are busy ; and what the recovery status is if an operation is being recovered. ;- .SBTTL Definitions .SBTTL ...RT-11 Macro References ; RT-11 Macros .MCALL .MTPS, .MFPS, .DRDEF, .FORK .MCALL .SYNCH, .BR, .ADDR, .ASSUME .LIBRARY "SRC:SYSTEM.MLB" .MCALL .CF2DF, .ERMDF, .ERRDF, .FIXDF .MCALL .SFMDF, .UBVDF, .USSDF .CF2DF ; Define $CNFG2 bits .ERMDF ; Define Magtape Errors .ERRDF ; Define System Errors .FIXDF ; Define Fixed Offsets .SFMDF ; Define Magtape SPFUNs .UBVDF ; Define UB Offsets .USSDF ; Define USR Function Codes .SBTTL ...Local Macros ; TBLINT - Device table entry macro .MACRO TBLINT V,C .WORD -1 .WORD V .WORD C .WORD 0 .WORD 0 .ENDM TBLINT ; REIS - Set up for command re-issue .MACRO REIS MOV R3,-(SP) MOV R2,-(SP) MOV $CBUF,R3 MOV PC,R2 ADD #$SCB+2-.,R2 .ENDM REIS ; ...... - Mark an unconditional transfer of control .MACRO ...... .ENDM .SBTTL ...Unit Table Entry Offsets TB$JOB =: 0 ;WORD = JOB # OF OWNER, ELSE = -1 TB$TSR =: 2 ;WORD -> UNIT'S TSSR REGISTER TB$CBR =: 4 ;WORD -> UNIT'S DATA BUFFER REGISTER TB$FLG =: 6 ;FLAG BYTE FL$RE1 =: 000001 ;PROGRESS IN RECOVERY bit FL$RE2 =: 000002 ;PROGRESS IN RECOVERY bit FL$RC0 =: 000004 ;RECOVERY TYPE 5 IN PROGRESS bit FL$RC1 =: 000010 ;RECOVERY TYPE 4 IN PROGRESS bit FL$IEX =: 000020 ;INTERRUPT EXPECTED bit FL$CIP =: 000100 ;COMMAND IN PROGRESS bit TB$TS5 =: 7 ;STATUS byte TS.STT =: 1 ;Streaming tape type bit TS.SON =: 2 ;STREAMING ON bit TS.EXI =: 4 ;CONTROLLER EXISTS bit TS.GST =: 200 ;GET_STATUS IN PROGRESS bit TB$MBA =: 10 ;Message buffer address TB$ESZ =: 12 ;Size of entry (bytes) .SBTTL ...Miscellaneous Definitions NRETRY =: 8. ;Default recovery retry count ERRGAPS =: -101. ;No. of 3" gaps allowed between blocks JOBMSK =: 174000 ;Job number mask for Q.JNUM UNITMK =: 003400 ;Unit select mask for Q.UNIT F.BADR =: 2 ;.FORK routine offset in block C.DEVQ =: 10 ;Channel Status UNIT and PENDING IOs NXM.V =: 4 ;Trap-to-4 vector $SYPTR =: 54 ;Pointer to base of RMON PR7 =: 340 ;Priority-7 pattern for PSW .IF NE MS$FSM .SBTTL ...Global References for FSM .GLOBL CODE DVTBL FSMSIZ ; data .GLOBL FSMDIS FSMABT FSMDON FSMERR RESTOR ; code .GLOBL MTCQ ; data .IF NE MMG$T .GLOBL OLDBA EXTADR JOBNM SYNBLK ; data .GLOBL TEMP SINK ERBSAV ; data .ENDC ;NE MMG$T .ENDC ;NE MS$FSM .SBTTL ...TS11-Series Hardware Definitions ; MESSAGE BUFFER OFFSETS TSMBC =: 4 ; Byte count word TSXST0 =: 6 ; XST0 TSXST1 =: 10 ; XST1 TSXST2 =: 12 ; XST2 TSXST3 =: 14 ; XST3 TSXST4 =: 16 ; XST4 (TS05 only) MBFSIZ =: 20 ; Message Buffer size ; MESSAGE HEADER BIT DEFINITIONS MG.ACK =: 100000 ;ACKNOWLEDGE BIT MG.FMT =: 000340 ;MESSAGE FORMAT BITS MG.COD =: 000037 ;MESSAGE CODE BITS ; MESSAGE CODES MC.END =: 020 ;END MC.FAL =: 021 ;FAIL MC.ERR =: 022 ;ERROR MC.ATN =: 023 ;ATTENTION ; TSXST0 BIT DEFINITIONS X0.TMK =: 100000 ;TAPE MARK DETECTED X0.RLS =: 040000 ;RECORD LENGTH SHORT X0.LET =: 020000 ;LOGICAL EOT X0.RLL =: 010000 ;RECORD LENGTH LONG X0.WLE =: 004000 ;WRITE LOCK ERROR X0.NEF =: 002000 ;NON EXECUTABLE FUNCTION X0.ILC =: 001000 ;ILLEGAL COMMAND X0.ILA =: 000400 ;ILLEGAL ADDRESS X0.MOT =: 000200 ;TAPE MOTION ON LAST COMMAND X0.ONL =: 000100 ;ON LINE X0.IE =: 000040 ;ENABLE INTERUPT X0.VCK =: 000020 ;VOLUME CHECK X0.PED =: 000010 ;PE DRIVE X0.WLK =: 000004 ;WRITE LOCK X0.BOT =: 000002 ;BEGINNING OF TAPE X0.EOT =: 000001 ;END OF TAPE ; TSXST1 BIT DEFINITIONS X1.DLT =: 100000 ;DATA LATE X1.COR =: 020000 ;CORRECTABLE DATA X1.CRS =: 010000 ;CREASE DETECTED X1.TIG =: 004000 ;TRASH IN GAP X1.DBF =: 002000 ;(PE) DESKEW BUFFER FAILURE X1.NZO =: 002000 ;(NRZ) NRZ BOARD FIFO OVERFLOW X1.SCK =: 001000 ;SPEED CHECK X1.IPR =: 000200 ;(PE) INVALID PREAMBLE X1.SYN =: 000100 ;(PE) SYNCH ERROR X1.DRP =: 000100 ;(NRZ) FRAME DROP OUT X1.IPO =: 000040 ;(PE) INVALID POST AMBLE X1.ITM =: 000040 ;(NRZ) ILLEGAL TAPE MARK X1.IED =: 000020 ;(PE) INVVALID END DATA X1.LC0 =: 000020 ;(NRZ) LRC =: 0 X1.POS =: 000010 ;(PE) POSTAMBLE SHORT X1.NZN =: 000010 ;(NRZ) NOISE RECORD X1.POL =: 000004 ;(PE) POSTAMBLE LONG X1.LRC =: 000004 ;(NRZ) LRC ERROR X1.UNC =: 000002 ;(PE) UNCORRECTABLE DATA ERROR X1.CRC =: 000002 ;(NRZ) CRC ERROR X1.MTE =: 000001 ;(PE) MULTI TRACK ERROR X1.VPE =: 000001 ;(NRZ) VERTICAL PARITY ERROR ; TSXST2 BIT DEFINITIONS X2.OPM =: 100000 ;OPERATION IN PROGRESS X2.SIP =: 040000 ;SILO PARITY ERROR X2.BPE =: 020000 ;SERIAL BUS PARITY ERROR X2.CAF =: 010000 ;CAPSTON ACCELERATION FAIL X2.WCF =: 002000 ;WRITE CLOCK FAIL X2.XSK =: 001000 ;EXCESSIVE SKEW X2.DTK =: 000777 ;DEAD TRACKS P,7-0 ; TSXST3 BIT DEFINITIONS X3.FEC =: 177400 ;FATAL ERROR CODE BITS X3.LMX =: 000200 ;TAPE LIMIT EXCEEDED X3.OPI =: 000100 ;OPERATION INCOMPLETE X3.REV =: 000040 ;TAPE MOVED BACKWARDS X3.CRF =: 000020 ;CAPSTON RESPONCE FAIL X3.DCK =: 000010 ;DENSITY CHECK X3.NOI =: 000004 ;NOISE RECORD X3.SGP =: 000002 ;SHORT GAP X3.RIB =: 000001 ;REVERSE INTO BOT ; TSSR BIT DEFINITIONS SR.SC =: 100000 ;SPECIAL CONDITION SR.UPE =: 040000 ;UNIBUS PARITY ERROR SR.SPE =: 020000 ;SERIAL BUS PARITY ERROR SR.RMR =: 010000 ;REGISTER MODIFICATION REFUSED SR.NXM =: 004000 ;NON-EXISTANT MEMORY SR.NBA =: 002000 ;NEED BUFFER ADDRESS SR.A17 =: 001000 ;BA 17 SR.A16 =: 000400 ;BA 16 SR.SSR =: 000200 ;SUB SYSTEM READY SR.OFL =: 000100 ;DEVICE IS OFF LINE SR.FC1 =: 000040 ;FATAL ERROR CLASS BIT ONE SR.FC0 =: 000020 ;FATAL ERROR CLASS BIT ZERO SR.TC2 =: 000010 ;TERMINATION CLASS BIT 2 SR.TC1 =: 000004 ;TERMINATION CLASS BIT 1 SR.TC0 =: 000002 ;TERMINATION CLASS BIT 0 SR.TCN =: ;TERMINATION CLASS NUMBER SR.BAD =: ;FATAL ERROR CONDITION ; COMMAND HEADER BIT DEFINITIONS CM.ACK =: 100000 ;ACKNOWLEGE BIT CM.CVC =: 040000 ;CLEAR VOLUME CHECK CM.OPP =: 020000 ;OPPOSITE BIT CM.SWB =: 010000 ;SWAP BYTES CM.MOD =: 007400 ;COMMAND MODE BITS CM.RTY =: 001000 ;RETRY MODE BIT CM.RVS =: 000400 ;REVERSE MODE BIT CM.IE =: 000200 ;ENABLE INTERUPT CM.COD =: 000037 ;COMMAND CODE BITS CM.LOW =: 000003 ;LOW HALF OF CODE BITS CM.NML =: ;NORMAL COMBINATION OF FLAGS ; TS05 COMMAND CODES CC.RDN =: <0001!CM.NML> ;READ NEXT -FORWARD- CC.RDP =: <0401!CM.NML> ;READ PREVIOUS -REVERSE- CC.RRP =: <1001!CM.NML> ;REREAD PREVIOUS -FORWARD- CC.RRN =: <1401!CM.NML> ;REREAD NEXT -REVERSE- CC.WRC =: <0004!CM.ACK!CM.CVC> ;WRITE CHARACTERISTICS CC.WRD =: <0005!CM.NML> ;WRITE DATA CC.WDR =: <1005!CM.NML> ;WRITE DATA RETRY CC.WSM =: <0006!CM.NML> ;WRITE SUBSYSTEM MEMORY CC.SRF =: <0010!CM.NML> ;SPACE RECORDS FORWARD CC.SRR =: <0410!CM.NML!CM.CVC> ;SPACE RECORDS REVERSE CC.STF =: <1010!CM.NML> ;SKIP TAPE MARKS FORWARD CC.STR =: <1410!CM.NML> ;SKIP TAPE MARKS REVERSE CC.RWD =: <2010!CM.NML!CM.CVC> ;REWIND CC.WTM =: <0011!CM.NML> ;WRITE TAPE MARK CC.ERS =: <0411!CM.NML> ;ERASE CC.WTR =: <1011!CM.NML> ;WRITE TAPE MARK RETRY CC.BRL =: <0012!CM.ACK> ;MESSAGE BUFFER RELEASE CC.UNL =: <0412!CM.NML!CM.CVC> ;REWIND AND UNLOAD CC.INI =: <0013> ;DRIVE INITIALIZE (IMMEDIATE RETURN) CC.DRI =: ;DRIVE INITIALIZE CC.GST =: <0017!CM.ACK> ;GET STATUS IMMEDIATE CC.MST =: ;MOUNT AND SET CHARACTERISTICS ; CHARACTERISTICS FLAG DEFINITIONS CH.ESS =: 000200 ;ENABLE SPACE STOP ON EOF CH.EAI =: 000040 ;ENABLE ATTENTION INTERRUPTS CH.ERI =: 000020 ;ENABLE BUFFER RELEASE INTERRUPTS CH.HSP =: 000040 ;HIGH SPEED ENABLE (TS05 ONLY) CB$CHR =: 0 ; PSECT ordering .PSECT MSDVR,I,LCL,CON ; This handler's code .PSECT MTDVR,I,LCL,CON ; FSM code .PSECT NONRES,I,LCL,CON ; Non-resident LOAD/UNLOAD code .SBTTL DRDEF - Handler Definition/Characteristics ; Define the device and handler characteristics .IF EQ MMG$T .DRDEF MS,35,,0,172522,224,DMA=YES .IFF; EQ MMG$T NUMRS =: 1 .DRDEF MS,35,,0,172522,224,DMA=YES,PERMUMR=NUMRS,SERIAL=YES .ENDC; EQ MMG$T MS$DB == MS$CSR-2 ; Default UNIBUS address for unit 0 .SBTTL DRPTR - Handler Service Routine Entries .DRPTR LOAD=LOAD,FETCH=LOAD,UNLOAD=UNLOAD,RELEASE=UNLOAD .SBTTL DREST - Extended Status Information .IF EQ MS$FSM .DREST CLASS=DVC.MT,MOD=DVM.NS ; device is NFS MAGTAPE .IFF; EQ MS$FSM .DREST CLASS=DVC.MT ; device is a MAGTAPE .ENDC; EQ MS$FSM .SBTTL DRSPF - SPFUN Definitions .DRSPF SF.MTM ; WRITE TAPE MARK .DRSPF SF.MFS ; FORWARD SPACE .DRSPF SF.MBS ; BACKSPACE .DRSPF SF.MWE ; WRITE WITH EXTENDED INTERBLOCK GAP .DRSPF SF.MRE ; REWIND .DRSPF SF.MOR ; OFFLINE AND REWIND .DRSPF SF.MWR ; WRITE PHYSICAL .DRSPF SF.MRD ; READ PHYSICAL .DRSPF SF.MST ; STREAM AT 100 IPS .IIF NE MS$FSM .DRSPF SF.USR ; ASYNC FILE OPERATIONS .IF NE MMG$T .DRSPF +SPFTAB ; Pointer to SPFUN table for UMRs .ENDC; NE MMG$T .SBTTL Audit trail information .IIF EQ MS$FSM .FSM = 100000 .AUDIT .TS .AUDIT .FSM .SBTTL Installation code .IF EQ MS$UN-1 .DRINS MS .IFF .IF EQ MS$UN-2 .DRINS MS, .IFF .IF EQ MS$UN-3 .DRINS MS, .IFF .IF EQ MS$UN-4 .DRINS MS, .IFF .IF EQ MS$UN-5 .DRINS MS, .IFF .IF EQ MS$UN-6 .DRINS MS, .IFF .IF EQ MS$UN-7 .DRINS MS, .IFF .DRINS MS, .ENDC ;EQ MS$UN-7 .ENDC ;EQ MS$UN-6 .ENDC ;EQ MS$UN-5 .ENDC ;EQ MS$UN-4 .ENDC ;EQ MS$UN-3 .ENDC ;EQ MS$UN-2 .ENDC ;EQ MS$UN-1 .Assume . LE 400,<;INSTALL area overflow> .SBTTL SET code .DRSET CSR, <0*2+1>, O.CSR, OCT .DRSET VECTOR, <0*2+1>, O.VEC, OCT .IF GE MS$UN-2 .DRSET CSR2, <1*2+1>, O.CSR, OCT .DRSET VEC2, <1*2+1>, O.VEC, OCT .IF GE MS$UN-3 .DRSET CSR3, <2*2+1>, O.CSR, OCT .DRSET VEC3, <2*2+1>, O.VEC, OCT .IF GE MS$UN-4 .DRSET CSR4, <3*2+1>, O.CSR, OCT .DRSET VEC4, <3*2+1>, O.VEC, OCT .IF GE MS$UN-5 .DRSET CSR5, <4*2+1>, O.CSR, OCT .DRSET VEC5, <4*2+1>, O.VEC, OCT .IF GE MS$UN-6 .DRSET CSR6, <5*2+1>, O.CSR, OCT .DRSET VEC6, <5*2+1>, O.VEC, OCT .IF GE MS$UN-7 .DRSET CSR7, <6*2+1>, O.CSR, OCT .DRSET VEC7, <6*2+1>, O.VEC, OCT .IF GE MS$UN-8. .DRSET CSR8, <7*2+1>, O.CSR, OCT .DRSET VEC8, <7*2+1>, O.VEC, OCT .ENDC ;GE MS$UN-8. .ENDC ;GE MS$UN-7 .ENDC ;GE MS$UN-6 .ENDC ;GE MS$UN-5 .ENDC ;GE MS$UN-4 .ENDC ;GE MS$UN-3 .ENDC ;GE MS$UN-2 .DRSET RETRY, 127., O.RTRY, NUM O.CSR: CMP R0,#160002 ;Is it a valid CSR address? ; NOTE: Base address for SET CSRx ; command is the higher of a two ; address pair BLO O.BAD ;Nope, reject the command DEC R3 ;Reduce to 0, 2, 4, 6, etc. BNE 10$ ;Not 0, don't change install CSR MOV R0,INSCSR ;Set the installation CSR address 10$: MOV R3,R1 ;Make a copy of the offset NEG R1 ;Negate for reversed CSR table .ADDR #DISCSR,R1,ADD ;Compute display table entry address MOV R0,(R1) ;Set the appropriate display CSR MOV R3,-(SP) .ASSUME TB$ESZ EQ 12 ASL R3 ;*4 to account for entry size ; (entered with *2+1, reduced by 1) ASL R3 ;*10 ADD (SP)+,R3 ;*12 .ADDR #$ADRTB,R3,ADD ;Compute unit table entry address MOV R0,TB$TSR(R3) ;Set the CSR SUB #2,R0 MOV R0,TB$CBR(R3) ; and data buffer addresses O.GOOD: TST (PC)+ ;Good return (c-bit = 0) O.BAD: SEC ;Error return (c-bit = 1) RETURN O.VEC: CMP R0,#500 ;Is it a valid vector address? BHIS O.BAD ;Nope, reject it... .IF GT MS$UN-1 DEC R3 ;Reduce to 0, 2, 4, etc. MOV R3,-(SP) ;Save *2 value ASL R3 ;*4 ADD (SP)+,R3 ;*4 + *2 = *6 .ADDR #MS$VTB,R3,ADD ;R3 -> Vector table entry .IFF .ADDR #MSSTRT,R3 ;R3 -> Vector entry .ENDC ;GT MS$UN-1 MOV R0,(R3) ;Place vector address in table BR O.GOOD O.RTRY: CMP R0,R3 ;Test retry limits BHI O.BAD ;Branch if out of bounds MOV R0,RTRYCT ;Move user-specified retry count BEQ O.BAD ;Zero retries not allowed BR O.GOOD ;Otherwise, okay .Assume . LE 1000,<;SET area overflow> .SBTTL DRBEG - Handler Entry Point .IF EQ MMG$T .DRBEG MS .IFF; EQ MMG$T .DRBEG MS,SPFUN=SPFTAB .ENDC; EQ MMG$T MSBASE =: MSSTRT + 6 ; MSLQE address BR MS ; Bypass some impure data .SBTTL Controller Impure Data Area ;+ ; The following table keeps track of each device. ; Entries are of the form: ; ; +-------------------------------+ ; | JOB # OF OWNER, ELSE -1 | ; +-------------------------------+ ; | TSSR ADDRESS | ; +-------------------------------+ ; | COMMAND POINTER REGISTER | ; +---------------+---------------+ ; | STATUS | FLAGS | ; +---------------+---------------+ ; | POINTER TO MESSAGE BUFFER | ; +---------------+---------------+ ; ; This table is within reach of the handler SET code so that it ; can be modified with SET CSR and SET VECTOR commands. ;- $ADRTB: TBLINT MS$CSR,MS$DB .ASSUME <.-$ADRTB> EQ TB$ESZ .IF GE MS$UN-2 TBLINT MS$CS1,MS$DB1 .IF GE MS$UN-3 TBLINT MS$CS2,MS$DB2 .IF GE MS$UN-4 TBLINT MS$CS3,MS$DB3 .IF GE MS$UN-5 TBLINT MS$CS4,MS$DB4 .IF GE MS$UN-6 TBLINT MS$CS5,MS$DB5 .IF GE MS$UN-7 TBLINT MS$CS6,MS$DB6 .IF GE MS$UN-8. TBLINT MS$CS7,MS$DB7 .ENDC ;GE MS$UN-8. .ENDC ;GE MS$UN-7 .ENDC ;GE MS$UN-6 .ENDC ;GE MS$UN-5 .ENDC ;GE MS$UN-4 .ENDC ;GE MS$UN-3 .ENDC ;GE MS$UN-2 .Assume . LE MSSTRT+1000,<;SET object not in block 1> .WORD -2 ; Signal end of table .SBTTL Multiple Vector Table ;+ ; ; This table is within reach of the handler SET code so that it ; can be modified with SET CSR and SET VECTOR commands. ;- .IF GT MS$UN-1 .DRVTB MS,MS$VEC,MSINT .DRVTB ,MS$VC1,M1INT .IIF GT MS$UN-2 .DRVTB ,MS$VC2,M2INT .IIF GT MS$UN-3 .DRVTB ,MS$VC3,M3INT .IIF GT MS$UN-4 .DRVTB ,MS$VC4,M4INT .IIF GT MS$UN-5 .DRVTB ,MS$VC5,M5INT .IIF GT MS$UN-6 .DRVTB ,MS$VC6,M6INT .IIF GT MS$UN-7 .DRVTB ,MS$VC7,M7INT .ENDC ;GT MS$UN-1 .Assume . LE MSSTRT+1000,<;SET object not in block 1> ; Retry Counter RTRYCT: .WORD NRETRY ; Error recovery retry count .Assume . LE MSSTRT+1000,<;SET object not in block 1> .IF NE MMG$T .SBTTL SPFTAB - SPFUN table for UMR/DMA operations ; The following SPFUNs require automatic UNIBUS address translation ; for DMA. SPFTAB: .DRSPF -,<370>,TYPE=R .DRSPF -,<371,374>,TYPE=W .WORD 0 .ENDC; NE MMG$T .SBTTL I/O Initialization ;+ ; The DRBEG code above branches around SETable data to this entry ; point. Start by determining the physical address of user-passed ; data. Then determine the unit number for which I/O is requested. ;- .ENABL LSB MS:: .IF NE MMG$T MOV MSCQE,R5 ; prepare to get 18-bit address MOV Q$BUFF(R5),(PC)+ ; save user buffer addr SPFBUF: .WORD 0 MOV Q$PAR(R5),(PC)+ ; and PAR value SPFPAR: .WORD 0 CMP (R5)+,(R5)+ ; point to Q$BUFF CALL @$MPPTR ; Get the full 18- or 22-bit address MOV (SP)+,OLDBA ; save low 16 bits ASR @SP ; shift high ASR @SP ; bits 4-5 ASR @SP ; to 0-1 ASR @SP ; MOV (SP)+,EXTADR ; save it in global variable .ENDC ;NE MMG$T .IF EQ MS$FSM MOV MSCQE,R3 ; point to queue element .IFF; EQ MS$FSM CALLR FSMDIS ; call the FSM ................................................... $MT:: ; FSM can then call US here. .ENDC ;EQ MS$FSM MOV SP,SPTMP ; save stack pointer TST (R3)+ ; R3 -> Q$FUNC (code and unit) MOV @R3,R1 ; R1 = code and unit number MOVB R1,R4 ; R4 = function code (sign-extd word) MOV #.-.,R5 ; get address of unit table ADRT1 = .-2 ; **LOAD** ; Process the unit number BIC #^C,R1 ; Strip to unit select bits .IF EQ MS$UN-1 ; Single unit support: .IF EQ MS$FSM ; and NO FSM... BNE BADUNI ; Unit must be MS0: .ENDC; EQ MS$FSM .IFF; EQ MS$UN-1 ; Multi-unit support: SWAB R1 ; Move unit number to low byte. .IF EQ MS$FSM ; and NO FSM... CMPB R1,# ; Too big? BHIS BADUNI ; Invalid unit if so. .IFF; EQ MS$FSM ; Multiple units and FSM... ; FSM already checked unit .ENDC; EQ MS$FSM MOV R1,R0 ; for this unit, 10$: DEC R0 ; loop through the units, BLT 20$ ; until exhausted. ADD #TB$ESZ,R5 ; point to next table entry BR 10$ ; and loop again 20$: BITB #,TB$TS5(R5) ; CSR exists? BEQ BADUNI ; error out now if not .ENDC; EQ MS$UN-1 MOV @R3,R0 ; get job # BIC #^C,R0 ; Strip to job number bits SWAB R0 ; Move to low byte ASR R0 ; Rotate ASR R0 ; down ASR R0 ; to low bits .IF NE MMG$T MOV R0,JOBNM ; Store job number for XM .ENDC; NE MMG$T CMPB R4,#LOOK.. ; Is this a LOOKUP? BNE 40$ ; branch if not .ASSUME TB$JOB EQ 0 CMP @R5,#<-1> ; is unit taken? BNE DEVINU ; Branch if NOT AVAILABLE MOV R0,@R5 ; Allocate the unit MOV SP,LASTIM ; Force GET_CHARACTERISTICS, BICB #,TB$TS5(R5) ; turn off streaming in the process 40$: CLR (PC)+ ; init NFS read flag NFSREAD:.WORD 0 .DSABL LSB ;+ ; If the unit characteristics are unknown, do a GET_STATUS and ; SET_CHARACTERISTICS command. ;- .ENABL LSB MOV TB$MBA(R5),R0 ;get address of message buffer .ASSUME TS.GST EQ 200 AJA: TSTB TB$TS5(R5) ;In the middle of a GET STATUS? BPL 20$ ;No, check if this if tape type done BICB #^C,TB$TS5(R5) ;Reset most of flag byte CMP #<-1>,TSXST4(R0) ;Was the last word touched? BEQ 20$ ;Branch if no BISB #,TB$TS5(R5) ;Indicate a streaming tape type ; R1 now contains the unit number 20$: CMP R1,(PC)+ ;Same unit as the last time? LASTIM: .WORD -1 ;unit of last good I/O BEQ UNIRDY ;Branch if yes - no need for status MOV R1,LASTIM ;Save the new unit information BISB #TS.GST,TB$TS5(R5) ;Set bit - denote GET STATUS in proc. CALL $SCHR ;Tell controller about message buffer .ASSUME SR.SSR EQ 200 30$: TSTB @TB$TSR(R5) ;Wait for ownership of command BPL 30$ ; buffer... MOV #<-1>,TSXST4(R0) ;Make last word in the buffer -1 for ;status check. If -1 after GET STATUS ;then not TS05. If not -1 then TS05 MOV $CBUF,R2 ;Get pointer to command buffer MOV #,@R2 ;Store GET_STATUS command there .IF EQ MMG$T MOV R2,@TB$CBR(R5) ;Give it to the controller... .IFF; EQ MMG$T MOV $CBUFU,@TB$CBR(R5) ;Give it to the controller... .ENDC; EQ MMG$T .ASSUME SR.SSR EQ 200 40$: TSTB @TB$TSR(R5) ;Wait for GET STATUS to finish! BPL 40$ ;...wait and test loop... BR AJA ...... .DSABL LSB .SBTTL ...Error handling .ENABL LSB .SBTTL ......Invalid unit number BADUNI: CMPB R4,#LOOK.. ; If so, was it LOOKUP? BNE 10$ ; if not, return HARD_ERROR MOV #ER.IUN,R0 ; If so, report INVALID_UNIT BR USRERR ...... 10$: MOV MSCQE,R5 ; point to QELEM BIS #HDERR$,@-(R5) ; set HARD ERROR in CSW CALLR MSDONE ; return to monitor ...... .SBTTL ......Device is IN_USE DEVINU: MOV #ER.SHR,R0 ; Otherwise, report DEVICE IN_USE USRERR: MOV @#$SYPTR,R1 ; point to RMON MOV R0,$SPUSR(R1) ; return error to the USR .IF NE MS$FSM ; If file-structured magtape CALL RESTOR ; evolve out of FSM jungle, CALLR $DONE ; Abort ...... .IFF; NE MS$FSM ; If non file-structured magtape BR LEAVE ; Abort ...... .ENDC ;NE MS$FSM .SBTTL ...Unit is READY UNIRDY: CMPB #CLOS..,R4 ; .CLOSE? BEQ PURCLO CMPB #PURG..,R4 ; .PURGE? BNE 20$ ; if not, check for .LOOKUP. .BR PURCLO .SBTTL ...CLOSE and .PURGE processing .ASSUME TB$JOB EQ 0 PURCLO: MOV #<-1>,@R5 ; Release unit CALL STROFF ; Turn off 100 IPS BR LEAVE ; And finish up ...... 20$: CMPB #LOOK..,R4 ; is it a LOOKUP? BNE CHKFUN ; Branch if not .BR LOOKUP .DSABL LSB .SBTTL ...LOOKUP processing ;+ ; The unit is free and the specified unit exists. Check to make ; sure that this is a NON-FILESTRUCTURED LOOKUP. ;- .ENABL LSB LOOKUP: HWXM = 0 ; most assemblies .IF NE MMG$T .IF EQ MS$FSM HWXM = 1 ; this is the Hardware/XM case MOV MSCQE,R4 ; R4 -> queue element CALL @$GTBYT ; Get half of file name CALL @$GTBYT ; get the other half BISB (SP)+,(SP)+ ; test it -- No filename allowed BNE RELEAS ; Fails. Return INVALID ARG .ENDC ;EQ MS$FSM .ENDC ;NE MMG$T .IF EQ HWXM TST @(R3) ; NFS? (FSM would have cleared this) BNE HARDER ; Error if not cleared by FSM, or if ; file specified to HH .ENDC; EQ HWXM CLR (R3) ; for HH zero W.CNT to say NFS .ASSUME TB$JOB EQ 0 .IF NE MS$FSM ; If file-structured handler, BR LEAVE ; Split ...... .IFF; NE MS$FSM ; If not file-structured handler, MOV (R3),R1 ; Get sequence number, BEQ 110$ ; if zero, REWIND BGT RELEAS ; if positive, INVALID INC R1 ; is it -1 BEQ LEAVE ; Yes. No rewind. Just leave. .ASSUME TB$JOB EQ 0 RELEAS: MOV #<-1>,@R5 ; release unit MOV #ER.ISN,R0 ; Report ILLEGAL SEQ NUM error BR USRERR ; abort back through USR ...... 110$: MOVB #SF.MRE,R4 ; say we have to rewind .BR CHKFUN ; merge below ...... .ENDC; NE MS$FSM .DSABL LSB .SBTTL ...get the function code ;+ ; Validate the queue element code: ; ; If 377 >= R4 >= 367 then the code is a legal SPFUN. ; If R4 =0, it will be converted to a READ or WRITE based on the sign ; of the word count (+ = READ). Otherwise, a hard error is issued. ; ; The only exception is for code 367 (-9), which is valid only for a TS05. ; If the drive is anything else, 367 (-9) will pass through the handler ; without doing anything. ;- .ENABL LSB CHKFUN: MOVB #ERRGAPS,TAPELEN ; fill in CMPB #,R4 ; .SPFUN to stream the TS05? BNE 10$ ; Branch if not CALL STREAM ; Give SET CHARACTERISTICS for 100 IPS BR LEAVE ; Go out ...... 10$: CMPB R4,#SF.MRD ; is the function legal? BHIS DOFUNC ; branch if so TST R4 ; .READ or .WRITE? BLT LEAVE ; (Ignore unsupported SPFUNs) BEQ CONVRT ; Yes. Convert to an SPFUN .BR HARDER ; Hard error on weird positive codes .SBTTL ...hard error exit ;+ ; Issue HARD ERROR. ; ; Note: if we have file support, R0-R3 must be restored ; for the case where we are still in an interrupt. ;- HARDER: TST -(R3) ; point to block # BIS #HDERR$,@-(R3) ; set HARD ERROR bit in CSW .BR LEAVE ; Enter here to finish up I/O initialization. LEAVE: .IF NE MS$FSM ; If filestructured magtape CALL RESTOR ; Restore R0-R3 for RMON .ENDC; NE MS$FSM CALLR MSDONE ; Split ...... .SBTTL ...READ/WRITE request processing ; Convert to proper format for .READ and .WRITE CONVRT: MOV R3,R1 ; R1 -> Q$FUNC CLR -2(R1) ; Clear Q$BLK - prevent error report CMP (R1)+,(R1)+ ; R1 -> Q$WCNT MOVB #SF.MRD,R4 ; assume READ TST @R1 ; .READ? BPL 20$ ; branch if so NEG @R1 ; make count positive .ASSUME SF.MWR EQ INCB R4 ; change code to WRITE BR 30$ ; merge below 20$: COM NFSREAD ; mark a NFS READ 30$: .IF NE MS$FSM MOV R4,CODE ; save code of new request .ENDC; NE MS$FSM .BR DOFUNC ; merge below ...... .DSABL LSB .SBTTL ...start an operation ;+ ; Load the user buffer address, and cause a jump to the proper routine. ; ; R4 contains a sign-extended SPFUN code between -8 and -1. ;- DOFUNC: .IF NE MMG$T ; If file-structured magtape MOV (R3),R1 ; get word count .IFF; NE MMG$T ; If non file-structured magtape TST (R3)+ ; point to Q$BUF MOV (R3)+,OLDBA ; save buffer address MOV @R3,R1 ; save word count .ENDC; NE MMG$T MOV $CBUF,R2 ; R2 -> command buffer CALL DISPAT ; Go jump to proper routine .ASSUME . EQ TABLE ...... ; Action routine offset table TABLE: .BYTE REDEF-TABLE .BYTE WRIT-TABLE .BYTE OFFLN-TABLE .BYTE RWND-TABLE .BYTE WRITX-TABLE .BYTE BCKSPC-TABLE .BYTE FRSPC-TABLE .BYTE WRITM-TABLE ENDTAB = . ; TS11 Function code table FUNTAB: .WORD CC.RDN ; READ .WORD CC.WRD ; WRITE .WORD CC.UNL ; OFFLINE AND REWIND .WORD CC.RWD ; REWIND .WORD CC.WRD ; WRITE WITH EXTENDED GAP ; (SAME AS WRITE 1ST TIME) .WORD CC.SRR ; BACKSPACE .WORD CC.SRF ; FORWARD SPACE .WORD CC.WTM ; WRITE TAPEMARK ENDFUN = . .SBTTL ...Dispatcher Routine ;+ ; This routine will fill in the function code in the command buffer ; and transfer control to the appropriate action routine. ; ; On entry, ; R2 points to the command buffer ; R3 (in NON-XM case) points to Q$WCNT ; R4 contains a sign-extended SPFUN code word between -8 and -1. ; ; On exit, ; R2 points to the second word of the command buffer ;- .ENABL LSB DISPAT: MOV R4,LASTCOM ; Save the SPFUN number ASL R4 ; make it a negative word offset ADD @SP,R4 ; Point to offset MOV (R4),(R2)+ ; Get hardware function code MOV LASTCOM,R4 ; get function again, ADD @SP,R4 ; repoint to first table, MOVB (R4),R4 ; get offset byte ADD (SP)+,R4 ; add in PC CALLR @R4 ; Go finish operation ...... .DSABL LSB .ENABL LSB ; Start an operation: OFFLN: MOV SP,LASTIM ; Force GET_UNIT_CHAR next I/O BR RWND WRITX: WRIT: REDEF: .IF NE MMG$T MOV OLDBA,(R2)+ ; low bits of DMA address MOV EXTADR,@R2 ; high bits of DMA address BIT BADBIT,(R2)+ ; check for invalid UNIBUS address BNE HARDER .IFF; NE MMG$T MOV -(R3),(R2)+ ; put BUF address in CBUF CLR (R2)+ ; zero high bits .ENDC; NE MMG$T ASL R1 ; turn WORD count into BYTE count BCKSPC: FRSPC: MOV R1,(R2)+ ; fill in BYTE count RWND: WRITM: GSTAT: MOV R5,-(SP) ; save R5 for a moment... MOV $CBUF,R2 ; point to command buffer MOV #$SCB,R5 ; point to save area SCB1 = .-2 .REPT 4 MOV (R2)+,(R5)+ ; copy command buffer words .ENDR MOV (SP)+,R5 ; restore R5 BISB #FL$IEX,TB$FLG(R5) ; Declare interrupt expected .ASSUME SR.SSR EQ 200 .IF NE MS$FSM CALL ACTION ; Start tape moving... CALLR RESTOR ; Restore CPU state and return .IFF; NE MS$FSM .BR ACTION ; Start tape, wait for interrupt... .ENDC; NE MS$FSM ...... .DSABL LSB .SBTTL ACTION - Start a tape operation ;+ ; ACTION ; ; On entry ; R5 points to a unit table entry ; The command buffer is loaded and ready to go ; ; On exit ; R5 points at TB$FLG word of table entry ;- .ENABL LSB ACTION: .ASSUME SR.SSR EQ 200 10$: TSTB @TB$TSR(R5) ; wait here until controller ready BPL 10$ CMP (R5)+,(R5)+ ; point to TB$CBR, .MFPS ; push priority, .MTPS #PR7 ; UP priority .IF EQ MMG$T MOV $CBUF,@(R5)+ ;;; issue command .IFF; EQ MMG$T MOV $CBUFU,@(R5)+ ;;; issue command UNIBUS style .ENDC; EQ MMG$T BISB #FL$CIP,@R5 ;;; Set COMMAND_IN_PROGRESS .MTPS ;;; restore priority RETURN ; to caller or RMON... ...... .DSABL LSB .SBTTL MSABRT - Abort Entry Point ;+ ; ABORT ENTRY POINT ; ; Enter here to halt any operation and to update the unit table. ; First determine whether this is a JOB ABORT or a CHANNEL ABORT (.ABTIO). ; In either case, look at MSCQE to see whether there is an outstanding ; I/O that must be cancelled. If not, and this is a JOB ABORT, then ; simply update the unit table to reflect that the job no longer exists, ; and that the tape drives owned by the job should be deallocated. In ; cases where there is an I/O outstanding, we clear the INTERRUPT EXPECTED ; bit to defuse potential interrupts that might produce .FORKs, retries, ; and .DRFINs. Send an INITIALIZE CONTROLLER command for each attached ; unit, or on the unit that corresponds to the aborted channel. If I/O's ; are being aborted proceed to $DONE where the I/O will be completed. ; Otherwise, just return. ;- .ENABL LSB MSABRT: MOV R2,-(SP) ; Save R2 MOV R3,-(SP) ; Save R3 CLRB MSFL ; Inhibit DRFIN MOV #CHNABT,R2 ; Point to ABTIO flag/unit CHNAB1 = .-2 CLRB @R2 ; Assume job abort TST R5 ; Is this an .ABTIO? BEQ 10$ ; branch if not. ; Do CHANNEL abort... INCB (R2)+ ; set flag indicating CHANNEL abort MOVB (R5),@R2 ; CHNUNT = unit number from CCB MOV MSCQE,R3 ; active queue element? BEQ 30$ ; branch if no MOV Q$FUNC(R3),R3 ; get word containing unit number SWAB R3 ; get UNIT/JOB byte BIC #177770,R3 ; isolate unit number CMPB @R2,R3 ; does Q-elem unit match CHNUNT? BEQ 20$ ; if so, go enable .DRFIN BR 30$ ; otherwise, just clear table entry ; Do JOB abort... 10$: MOV MSCQE,R3 ; See if active queue element BEQ 30$ ; Branch if no MOV Q$FUNC(R3),R3 ; Get word containing job number SWAB R3 ; Get UNIT/JOB in low byte .REPT 3 ; focus on JOB number ASR R3 .ENDR BIC #177760,R3 ; Strip the extraneous bits CMP R3,R4 ; Is the aborting job the active one? BNE 30$ ; Branch if no ;+ ; Enter or drop through here when there is an I/O to MS outstanding. ; We need to abort that I/O. There is an implicit assumption here that ; this handler allows only one outstanding I/O at a time; it is not ; internally queued. Remember that this handler is now being "held", ; and interrupts to it aren't being DRFIN'ed. ;- 20$: INCB MSFL ; Enable .DRFIN CLR TSFBLK+F.BADR ; Disable pending .FORK routines .IF NE MS$FSM ; If file structured MOV DVTBL,R5 ; Point to device table BEQ 30$ ; Branch if nothing to initialize MOV #<-1>,@R5 ; Mark tape position lost MOV (R5)+,@R5 ; Mark block number lost .ENDC; NE MS$FSM ; Initialize particular controllers and respective unit tables 30$: MOV #.-.,R5 ADRT2 = .-2 ; **LOAD** CLR R2 ; start with unit-0 .ASSUME TB$JOB EQ 0 40$: CMP #<-2>,@R5 ; End of table? BEQ 100$ ; Finished if so. TSTB CHNABT ; Is this a CHANNEL abort? BNE 50$ ; Branch if so. .ASSUME TB$JOB EQ 0 CMP R4,@R5 ; Is unit taken by job number R4? BNE 80$ ; Branch if no MOV #<-1>,@R5 ; Job abort. Release the unit BR 60$ 50$: CMPB CHNUNT,R2 ; .ABTIO; Is this the unit? BNE 80$ ; branch if not. ; Either this is the unit for an ABTIO, or this unit is assigned ; to an aborting job. Initialize it. (Note that TSV05 runs away ; if hit with the CLR TSSR and it's in the midst of a WRITE with ; streaming. 60$: CLRB TB$FLG(R5) ; Clear recovery flags and IEX, 65$: TST @TB$MBA(R5) ; Controller ours? BPL 65$ ; wait till so... ; Special TSV05 code (should work for all MS types) CMPB LASTCOM,#SF.MWR ; What kind of command is it? BHI 70$ ; for most, abort immediately. .ASSUME SR.SSR EQ 200 68$: TSTB @TB$TSR(R5) ; Wait for WRITE or READ to finish BPL 68$ 70$: CLR @TB$TSR(R5) ; Reinitialize controller. ; That's all for this unit. Point to the next table entry and loop around. 80$: ADD #TB$ESZ,R5 ; Point to next entry INC R2 ; next unit number BR 40$ ; Loop for each unit gen'd. ; Restore registers, and return to RMON, one way or the other. 100$: MOV (SP)+,R3 ; Restore R3 MOV (SP)+,R2 ; and R2 TSTB MSFL ; need to DRFIN? BEQ RETCL ; Simply RETURN if not. CALLR $DONE ; Finish up ...... .IF GT MS$UN-4 MSABR1: BR MSABRT ; bucket brigade assist .ENDC; GT MS$UN-4 .DSABL LSB .SBTTL DRAST - Interrupt Entry Point ;+ ; This is the interrupt entry point for the handler. When an operation ; completes, it comes here for processing. It gets the address of the ; unit table entry, looks at the termination class code bits in the ; TSSR for that device, and dispatches to the appropriate routine. ; ; The termination class routines are entered with R5 pointing to the ; unit table entry and R4 pointing to its TB$FLG word. ;- .ENABL LSB .DRAST MS,5,MSABRT ; First controller, MS0: .IF GT MS$UN-1 CLR R5 BR 10$ .DRAST M1,5,MSABRT ; Second controller, MS1: MOV #,R5 .IF GT MS$UN-2 BR 10$ .DRAST M2,5,MSABRT ; Third controller, MS2: MOV #,R5 .IF GT MS$UN-3 BR 10$ .DRAST M3,5,MSABRT ; Fourth controller, MS3: MOV #,R5 .IF GT MS$UN-4 BR 10$ .DRAST M4,5,MSABR1 ; Fifth controller, MS4: MOV #,R5 .IF GT MS$UN-5 BR 10$ .DRAST M5,5,MSABR1 ; Sixth controller, MS5: MOV #,R5 .IF GT MS$UN-6 BR 10$ .DRAST M6,5,MSABR1 ; Seventh controller, MS6: MOV #,R5 .IF GT MS$UN-7 BR 10$ .DRAST M7,5,MSABR1 ; Eighth controller, MS7: MOV #,R5 .ENDC; .ENDC; .ENDC; .ENDC; .ENDC; .ENDC; .ENDC; 10$: MOV SP,SPTMP ; save SP .IF EQ MS$UN-1 MOV #.-.,R5 ; point to unit table entry ADRT3 = .-2 ; **LOAD** .IFF; EQ MS$UN-1 ADD #.-.,R5 ; point to unit table entry ADRT3 = .-2 ; **LOAD** .ENDC; EQ MS$UN-1 MOV R5,R4 ADD #TB$FLG,R4 ; R4 points point to TB$FLG BITB #FL$IEX,@R4 ; Interrupt expected? BEQ RETCL ; None expected? just return. MOV TB$MBA(R5),-(SP) ADD #TSXST0,@SP ; Point to our Message's XST0 word MOV (SP)+,MBSR0 ; save the pointer MOV @TB$TSR(R5),-(SP) ; get TSSR BIC #^C,@SP ; isolate termination class bits ADD #2,@SP ; correct for table access ADD PC,@SP ; PIC format ADD @(SP)+,PC ; here we go... .ASSUME . EQ ERJTBL ...... ERJTBL: .WORD TCL0ER-ERJTBL ; offsets to the routines .WORD TCL1ER-ERJTBL .WORD TCL2ER-ERJTBL .WORD TCL3ER-ERJTBL .WORD TCL4ER-ERJTBL .WORD TCL5ER-ERJTBL .WORD TCL6ER-ERJTBL .WORD TCL7ER-ERJTBL .DSABL LSB .SBTTL Termination Class Routines ;+ ; The following routines process the 8 possible completion codes that ; can be returned. ; ; INPUT: R5 -> unit table entry ; NOTE: the only registers used are r4 and r5, in addition ; to local use of the stack ;- ;+ ; TERMINATION CLASS 0 -- AN END MESSAGE ;- .ENABL LSB TCL0ER: MOVB @R4,-(SP) ; Save current status BICB #FL$CIP,@R4 ; Clear COMMAND_IN_PROGRESS flag BITB #FL$RC1,@R4 ; Recovery in progress? BEQ 10$ ; branch if not CALL REC1CH ; Doing READ recovery? 10$: BIT (SP)+,#FL$CIP ; Was a command in progress? BEQ RETCL ; Quit if not. BIT #X0.EOT,@MBSR0 ; EOT? BNE TCL2ER ; branch if so CALLR MSDONE ; else all done ...... .DSABL LSB ;+ ; TERMINATION CLASS 1 -- ATTENTION MESSAGE ;- .ENABL LSB TCL1ER: BITB #FL$CIP,@R4 ; COMMAND IN PROGRESS? BNE 10$ ; IF NE YES RETCL: RETURN ...... 10$: BICB #FL$CIP,@R4 ; CLEAR FLAG TCRECF: .FORK TSFBLK ; FORK level retry TCREDO: .IF NE MS$FSM ; If file-structured magtape MOV MSCQ,R3 ; Point to psuedo queue element CALLR $MT ; Restart .IFF; NE MS$FSM ; If non file-structured magtape CALLR MS ; Restart .ENDC; NE MS$FSM ...... .DSABL LSB ;+ ; TERMINATION CLASS 2 -- TAPE STATUS ALERT ;- .ENABL LSB TCL2ER: BICB #FL$CIP,@R4 ; RESET COM IN PROG FLAG BITB #FL$RC1,@R4 ; CLASS 4 ERROR RECOV IN BEQ 10$ ; IF EQ NO CALL REC1CH ; YES. FIND OUT WHERE IN RECOV WE ARE 10$: CLR R4 ; THIS IS WHERE THE CODE GOES MOV @MBSR0,-(SP) ; Get the TSXST0 word BIT #X0.BOT,@SP ; BOT? BEQ 20$ ; IF EQ NO MOV #EM.BOT,R4 ; SAY BOT FOUND BR 70$ ; MERGE .ASSUME X0.TMK EQ 100000 20$: TST @SP ; EOF? BPL 40$ ; IF PL NO CMPB #SF.MTM,LASTCOM ; WAS WRITE TM LAST COMMAND BNE 30$ ; IF EQ YES BIS #10000,R4 ; SET INDICATOR BR 40$ ; MERGE .ASSUME EM.EOF EQ 1 30$: INC R4 ; SET BIT 40$: BIT #X0.EOT,@SP ; EOT? BEQ 60$ ; IF EQ NO TST NFSREAD ; NFS READ DONE? BEQ 50$ ; IF NE YES -- IGNORE EOT BIS #10000,R4 ; SET BIT BR 60$ ; MERGE .ASSUME EM.EOT EQ 2 50$: CMPB (R4)+,(R4)+ ; Set value for EOT 60$: TST R4 ; EOT,EOF? BEQ 120$ ; IF EQ NO BIC #10000,R4 ; CLEAR FLAG BEQ 170$ ; If that's all, IGNORE CONDITION 70$: CMPB #SF.MBS,LASTCOM ; BK SPACE TO EOF,EOT? BEQ 80$ ; IF EQ YES CMPB #SF.MFS,LASTCOM ; FWD SPACE TO EOF,EOT BNE 100$ ; IF NE NO 80$: .IF EQ MMG$T ; If SJ/FB MOV R5,-(SP) .ENDC; EQ MMG$T MOV TB$MBA(R5),-(SP) ; message buffer address for this unit ADD #TSMBC,@SP ; point to byte count word .IF NE MMG$T MOV @(SP)+,ERRBL2 ; Report error count for XM .IFF; NE MMG$T .IF NE MS$FSM ; If file-structured SJ/FB, MOV @MSCQ,R5 ; Point to psuedo queue element .IFF; NE MS$FSM ; If not file-structured MOV @MSCQE,R5 ; Point to queue element .ENDC; NE MS$FSM BEQ 90$ ; If no BLK arg, don't report MOV @(SP),2(R5) ; Report records not skipped 90$: TST (SP)+ ; fix stack MOV (SP)+,R5 ; restore R5 .ENDC; NE MMG$T 100$: MOV #EOF$,@SP ; mark error 110$: CALLR EXCEP ; split ...... 120$: BIT #X0.RLL,@SP ; record length LONG? BEQ 130$ ; branch if not MOV #EM.BIG,R4 ; report it BR 160$ ; split ...... 130$: BIT #X0.RLS,@SP ; record length SHORT? BEQ FAT1 ; branch if not MOV TB$MBA(R5),-(SP) ; message buffer adrs for unit ADD #TSMBC,@SP ; point to byte count MOV @(SP)+,@SP ; store it ASR @SP ; Shift to convert to word count .IF NE MMG$T ; If XM MOV @SP,ERRBL2 ; Save it .IFF ; If not XM .IF NE MS$FSM ; If file structure MOV @MSCQ,R4 ; Point to error word in queue element .IFF ; If non filestructure MOV @MSCQE,R4 ; Point to error word in element .ENDC; NE MS$FSM BEQ 150$ ; If no byte count, don't fill it in MOV @SP,2(R4) ; Fill in word count .ENDC; NE MMG$T ; Don't worry about SP - it gets clobbered by any of the exits below. 150$: MOV #EM.SML,R4 ; Fill in SMALL_RECORD error 160$: BR ABORT1 ; Report condition ...... 170$: CALLR MSDONE ; Call COMPLT in RMON ...... .DSABL LSB ;+ ; TERMINATION CLASS 3 -- FUNCTION REJECT ;- .ENABL LSB TCL3ER: BICB #FL$CIP,@R4 ; reset COMMAND_IN_PROGRESS BIT #SR.NBA,@TB$TSR(R5) ; need buffer address? BEQ 10$ ; branch if not .FORK TSFBLK ; Yes. drop to FORK level ; CALL $SCHR ; Set characteristcs command MOV SP,LASTIM ; force set_characteristcs BR TCREDO ; and re-issue command. ...... 10$: BIT #SR.OFL,@TB$TSR(R5) ; device OFF-LINE? BEQ 30$ ; branch if not MOV #,R4 ; Put error code in R4 .ASSUME TB$JOB EQ 0 20$: MOV #<-1>,@R5 ; Release the unit ABORT1: CALLR ABORT ; Give error ...... 30$: BIT #X0.BOT,@MBSR0 ; BOT? BEQ 40$ ; branch if not CMP $SCB,#CC.SRR ; Yes. Backspaced into BOT? BNE 40$ ; branch if not MOV TB$MBA(R5),-(SP) ; point to our message buffer ADD #TSMBC,@SP ; point to byte count word MOV $SCB+2,@(SP)+ ; Set residual record count CALLR TCL2ER ; Merge with other errors ...... 40$: MOV @MBSR0,-(SP) ; put status word on stack CLR R4 ; fix R4 BIT #,@SP ; hard error? BNE FATAL ; branch if so BIT #X0.WLE,@SP ; WRITE LOCK error? FAT1: BEQ FATAL ; FATAL if not MOV #EM.WLK,R4 ; Return with WRITE_LOCK error BR 20$ ...... .DSABL LSB ;+ ; TERMINATION CLASS 4 -- RECOVERABLE ERROR ONE BLOCK DOWN ;- .ENABL LSB TCL4ER: BICB #FL$CIP,@R4 ;RESET COM IN PROG FLAG BITB #FL$RC0,@R4 ;ARE WE RECOVERING FROM BNE FATAL ;IF NE YES --ABORT CMPB #SF.MWR,LASTCOM ;WRITE RECOVERY? (371) BEQ WREC ;IF EQ YES CMPB #SF.MWE,LASTCOM ;WRITEX RECOVERY? (374) BEQ WREC ;IF EQ YES CMPB #SF.MTM,LASTCOM ;WRITE EOF RECOVERY? (377) BEQ WREC ;IF EQ YES BITB #FL$RC1,@R4 ;ALREADY IN A RECOVERY? BEQ 10$ ;IF EQ NO CMPB #SF.MRD,LASTCOM ;READ? BEQ RREC ;IF EQ YES BR FATAL ;ANYTHING ELSE IS NOT RECOVERABLE ...... 10$: CMPB #SF.MRD,LASTCOM ; READ recovery? BNE FATAL ; branch if not BISB #FL$RC1,@R4 ; Declare class-4 retry mode MOVB #5.,BACK1 ; Setup retry limits MOVB RTRYCT,BACK5 ; more retry limits BR RREC ; go process ...... .DSABL LSB ;+ ; TERMINATION CLASS 5 -- RECOVERABLE ERROR SAME POSITION ;- .ENABL LSB TCL5ER: BICB #FL$CIP,@R4 ;RESET COM IN PROG FLAG BITB #FL$RC1,@R4 ;CLASS 4 RECOVERY? BNE FATAL ;IF NE YES--ABORT BITB #FL$RC0,@R4 ;CLASS 5 ALREADY IN PROGRESS? BNE 10$ ;IF NE YES BISB #FL$RC0,@R4 ;SAY THERE IS NOW MOV RTRYCT,(PC)+ ;Re-issue desired number of times RCNT: .WORD 0 ;# of class-5 retries BR 20$ 10$: DEC RCNT ;DECREMENT COUNTER 20$: BEQ FATAL ;ISSUE HARD ERROR ON EXHAUSTED RETRYS JMP TCRECF ; FORK and re-issue command ...... ;+ ; TERMINATION CLASS 7 -- FATAL CONTROLLER ERROR ;- TCL7ER: CLR @TB$TSR(R5) ;DRIVER INIT .BR FATAL ;FALL THROUGH ;+ ; TERMINATION CLASS 6 -- IRRECOVERABLE ERROR ;- FATAL: TCL6ER: CALLR NQUAL ...... .DSABL LSB .SBTTL WRITE recovery ;+ ; WRITE RECOVERY ALGORITHM ; ; This routine will process a retry on a write command given that the tape ; position is one block down from where the command was issued. It will ; issue a WRITE RETRY function -- backspace 1 block, erase 1 block, write. ; If the number of 3 inch gaps produced this way exceeds 25 feet, a hard ; error is declared and the function is aborted. ; ; On entry, R5 points to a unit table entry, and R4 points to ; the TB$FLG offset in that table entry. ;- .ENABL LSB WREC: BITB #FL$RC1,@R4 ; RECOVERY IN PROGRESS BNE 10$ ; IF NE YES MOVB #ERRGAPS,TAPELEN ; FIX COUNTER BISB #FL$RC1,@R4 ; SET BIT 10$: INCB TAPELEN ; INCREMENT COUNTER BEQ FATAL ; IF EQ HARD ERROR REIS ; SET UP RETRY CMPB #SF.MTM,LASTCOM ; WRITE EOF RECOVERY? BNE 20$ ; BRANCH IF NO MOV #CC.WTR,(R3)+ ; PUT IN FUNCTION BR RESETB ; MERGE... 20$: MOV #CC.WDR,(R3)+ ; PUT IN FUNCTION RESETB: MOV (R2)+,(R3)+ ; SET UP COMMAND BUFFER MOV (R2)+,(R3)+ MOV (R2)+,(R3)+ ; Issue a command and return to the monitor. ; (This used to be a MACRO called RESET. It is now a subroutine.) RESET: CALL ACTION ; start tape operation... MOV (SP)+,R2 ; Restore registers saved in REIS MOV (SP)+,R3 MOV SPTMP,SP ; Hijack the stack... RETURN ; return from interrupt ...... .DSABL LSB .SBTTL READ recovery ;+ ; This routine processes the read retrys given that the tape position is ; one block down from where the command was issued. This recovery ; algorithm has 2 parts: ; ; 1) A read retry is issued 5 times. This command is a backspace, ; read forward. ; ; 2) A backspace 5 blocks is issued. Next a forward space 5 blocks ; is issued, followed by another read retry. ; ; The above sequence is tried 8 times. When this is exhausted a hard ; error is declared. Any unpredictable conditions during the recovery ; will also yield a hard error. An example is getting a class 5 error ; on one of the read retrys. ; ; On entry, R5 points to a unit table entry, and R4 points to the TB$FLG ; offset in that table entry. ;- .ENABL LSB RREC: TSTB BACK1 ;START PHASE 2 RECOVERY? BEQ 20$ ;IF EQ YES DECB BACK1 ;UPDATE COUNTER 10$: REIS ;SET UP RETRY MOV #CC.RRP,(R3)+ ;PUT IN A READ RETRY BR RESETB ;GO PLAY ...... 20$: TSTB BACK5 ;HAD ENOUGH YET? BEQ FATAL ;IF NE YES BITB #FL$RE2,@R4 ;HAVE WE FORWARD SPACED TOO? BEQ 30$ ;IF EQ NOP MOVB #4.,BACK1 ;RESET DECB BACK5 ;UPDATE COUNTER BICB #,@R4 MOV #5,BCNT ;RESET BCNT BR 10$ ;GO PROCESS ...... 30$: BITB #FL$RE1,@R4 ;HAVE WE BACKSPACED 5? BNE 60$ ;WE CERTAINLY HAVE, HAVEN'T WE BISB #FL$RE1,@R4 ;SET BIT REIS ;SET UP TO ISSUE MOV #CC.SRR,(R3)+ ;REVERSE 5 40$: MOV BCNT,(R3)+ ;COUNT BR RESET ;GO DO COMMAND ...... 60$: REIS ;SET UP TO REISSUE MOV #CC.SRF,(R3)+ ;FORWARD 5 BISB #FL$RE2,@R4 ;SET FLAG BR 40$ ;CONTINUE ...... .DSABL LSB ;+ ; REC1CH ; ; This routine will check if we are in the middle of recovery. ; If so we go to proper routine to continue it; else normal processing. ; ; On entry, R4 points to TB$FLG byte in unit table ;- .ENABL LSB REC1CH: CMPB LASTCOM,#SF.MRD ; is this a READ recovery BNE 10$ ; if not process normally BITB #,@R4 ; in the middle? BNE RREC ; continue with read recovery 10$: CLRB @R4 ; otherwise clear flags RETURN ...... .DSABL LSB .SBTTL $SCHR - Set Characteristics .SBTTL STROFF - Streaming OFF ;+ ; Issue a SET_CHARACTERISTICS command ; ; The size of the message buffer is 5 words. The TS05 ; in extended features mode returns 5 words, while the TS11 ; (and others) returns 4 words. ; ; On entry, R5 should point to a unit table entry ; ; Entry STROFF turns off streaming ;- .ENABL LSB STROFF: BICB #,TB$TS5(R5) ; Turn OFF 100 IPS BITB #,TB$TS5(R5) ; Drive capable of streaming? BEQ 40$ ; return if not. $SCHR: MOV R0,-(SP) ; Save some registers MOV R1,-(SP) MOV R2,-(SP) MOV TB$MBA(R5),R0 ;R0 -> Message buffer MOV $CBUF,R1 ;R1 -> Command buffer MOV #CC.WRC,(R1)+ ;CBUF(1) = Command .IF EQ MMG$T MOV R0,@R0 ;MBUF(1) = address of MBUF MOV (R0)+,(R1)+ ;CBUF(2) = address of MBUF CLR @R0 ;MBUF(2) = high address of MBUF (0) MOV (R0)+,(R1)+ ;CBUF(3) = high address of MBUF (0) .IFF; EQ MMG$T MOV #.-.,R2 ;translate the unit's MBUF offset MSMB1 = .-2 ; **LOAD** SUB R0,R2 ; (yields a negative offset) MOV MSMUBL,@R0 ;MBUF(1) = UNIBUS(L) address of MBUF SUB R2,@R0 ; (adjust for unit's message buffer) MOV (R0)+,(R1)+ ;CBUF(2) = UNIBUS(L) address of MBUF MOV MSMUBH,@R0 ;MBUF(2) = UNIBUS(H) address of MBUF MOV (R0)+,(R1)+ ;CBUF(3) = UNIBUS(H) address of MBUF .ENDC; EQ MMG$T MOV #14.,R2 ; usual size value BITB #,TB$TS5(R5) ; GET_STATUS is the caller ? BEQ 10$ ; No, branch TST (R2)+ ; ADD #2,R2 - OK IN KERNEL MODE 10$: MOV R2,(R0)+ ;MBUF(3) = size MOV R2,@R1 ;CBUF(4) = size 20$: CLR (R0)+ ;MBUF(4) = 0 CLR @R0 ;MBUF(5) = 0 BITB #,TB$TS5(R5) ;Streaming mode? BEQ 30$ ;if not, branch BIS #CH.HSP,(R0)+ ;set HSP in MBUF .ASSUME SR.SSR EQ 200 30$: TSTB @TB$TSR(R5) ; wait here for controller ready BPL 30$ .IF EQ MMG$T MOV $CBUF,@TB$CBR(R5) ;issue command .IFF; EQ MMG$T MOV $CBUFU,@TB$CBR(R5) ;issue command .ENDC; EQ MMG$T MOV (SP)+,R2 ;fix registers MOV (SP)+,R1 MOV (SP)+,R0 40$: RETURN ...... .DSABL LSB ;+ ; STREAM WILL ISSUE THE SET CHARACTERISTICS COMMAND SPECIFIED ; BY SPFUN 367 (-9). ; ; ON ENTRY, R3 POINTS TO Q.FUNC (BYTE 6 IN THE QUEUE ELEMENT) ; R5 POINTS TO CURRENT UNIT TABLE ;- .ENABL LSB STREAM: BITB #,TB$TS5(R5) ; Drive capable of streaming? BEQ 40$ ; return if not. MOV R1,-(SP) ;SAVE R1 .IF NE MMG$T ;If XM MOV SPFBUF,(R3) ;RESTORE USER BUF ADDR MOV SPFPAR,(R3) ;AND PAR VALUE MOV R4,-(SP) ;SAVE R4 MOV MSCQE,R4 ;POINT TO Q.BLKN CALL @$GTBYT ;Get flag from user MOVB (SP)+,R1 ;GET RETURNED BYTE MOV (SP)+,R4 ;RESTORE R4 TSTB R1 ;TURN OFF 100 IPS? .IFF; NE MMG$T ;If not XM MOV (R3),R1 ;GET USER BUFFER ADDRESS TSTB @R1 ;TURN OFF 100 IPS? .ENDC; NE MMG$T BNE 10$ ;Branch if no BICB #,TB$TS5(R5) ;Turn streaming off BR 20$ ;Join common code 10$: BISB #,TB$TS5(R5) ;Set it on 20$: CALL $SCHR ;Set characteristics command 30$: MOV (SP)+,R1 ;Restore R1 40$: RETURN ...... .DSABL LSB .SBTTL Completion Routines ;+ ; ; THERE ARE SEVERAL ENTRY POINTS HERE ; NQUAL -- IS THE ENTRY POINT TO ISSUE A HARD ERROR ; ABORT -- IS THE ENTRY POINT TO ISSUE A HARD ERROR ; IS MORE SPECIFIC INFORMATION TO REPORT ; EXCEP -- IS THE ENTRY POINT TO REPORT AN EXCEPTION ; CONDITION ; ; R4 CONTAINS THE ERROR QUALIFICATION CODE ; R5 POINTS TO A UNIT TABLE ENTRY ; CSW BIT TO SET IS ON THE STACK ; ;- .ENABL LSB NQUAL: CLR R4 ;SAY NO ERROR QUALIFICATION CODE ABORT: MOV #,-(SP) ;SAY HARD ERROR EXCEP: .IF NE MS$FSM ;If file structured MOV (SP)+,R5 ;R5= ERROR TYPE MOV SPTMP,SP ;RESTORE STACK CALLR FSMERR ;GO TO FSM ...... .IFF; NE MS$FSM ;If non file structured MOV MSCQE,R5 ;POINT TO QUEUE ELEMENT BIS (SP)+,@Q$CSW(R5) ;SET BIT IN CSW TST @R5 ;SET ERRBLK? BEQ MSDONE ;IF EQ NO .IF NE MMG$T ;If XM COM SINK ;SET .SYNCH FLAG MOV @R5,ERBSAV MOV R4,TEMP ;THIS COMES BACK IN R0 AFTER SYNCH MOV Q$FUNC(R5),R5 ;Get word containing job number BIC #^C,R5 ;Strip the extraneous bits SWAB R5 ;Get job number in low byte .REPT 3 ;Make job number into value ASR R5 .ENDR MOV R5,JOBNM ;STORE IN .SYNCH BLOCK .IFF; NE MMG$T ;If not XM MOV R4,@(R5)+ ;MOVE CODE TO ERRBLK .ENDC; NE MMG$T .BR MSDONE .ENDC; NE MS$FSM .DSABL LSB .SBTTL MSDONE - Complete the I/O ;+ ; MSDONE is the routine that the hardware handler enters when an operation ; completes with no exception conditions. When FSM is present, a jump to ; FSM is executed. If FSM is not present, the hardware handler will exit ; to the completion routine in the monitor. For XM, the handler will decide ; whether to do a .SYNCH, so that errors can be reported to the user's ; ERRBLK address. ;- MSDONE: MOV SPTMP,SP ; Restore stack .IF NE MS$FSM ; If file-structured magtape CALLR FSMDON ; Tell FSM that we are done ; FSM will return here when its done .ENDC; NE MS$FSM $DONE:: .IF EQ MMG$T ; If SJ or FB, .DRFIN MS ; report I/O completion ...... .IFF; EQ MMG$T ; If XM... MOV #MSCQE,R4 ; point to queue element MSCQ1 = .-2 TST @R4 ; null queue element? BEQ $RTS TST SINK ; JSR OR JMP? BNE 10$ ; If need SYNCH, do that first. MOV @#$SYPTR,R5 ; get base of RMON CALLR @$QCOMP(R5) ; split ...... ; Do a .SYNCH to defer processing to job-context. Give the queue element ; back to RMON. If multiple units are supported, copy the SYNCH information ; to a SYNCH block that is private for the unit. That way, if two jobs ; are independently using two or more units, SYNCH code of one job ; doesn't mess with status belonging to another. 10$: CLR SINK ; Reset .SYNCH HAS BEEN DONE flag MOV #SYNBLK,R4 ; point to global SYNCH block SYNBL1 = .-2 .SYNCH BR BADSYN ; From here down to the RETURN, we are a completion routine running for ; the job in job-context. MOV ERBSAV,R1 ; point to job's ERRBLK BIS #30000,@#177776 ; USER mode to previous MOV R0,-(SP) ; put exception code on stack MTPD (R1)+ ; store for user MOV ERRBL2,-(SP) ; 2nd word (typically a count) MTPD (R1)+ ; store for user ; DRFIN the queue element. We are in kernel mode, running as a completion ; routine in job-context. Only R0 and R1 are free, so save the other ; registers. MOV R2,-(SP) ; Save registers MOV R3,-(SP) ; that COMPLT MOV R4,-(SP) ; might use MOV R5,-(SP) MOV #MSCQE,R4 ; point to queue element, MSCQ2 = .-2 MOV @#$SYPTR,R5 ; get base of RMON, CALL @$QCOMP(R5) ; CALL COMPLT in RMON MOV (SP)+,R5 MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 BADSYN: $RTS: RETURN ...... .ENDC; EQ MMG$T .SBTTL Data Area ; TAPELEN BYTE - THIS BYTE IS USED TO KEEP TRACK OF THE # OF INCHES OF ; CONSECUTIVE GAP WHICH HAS BEEN WRITTEN BY THE WRITE ERROR RECOVERY ROUTINE. ; THE DEC STANDARD SPECIFIES THAT A GAP OF GREATER THAN 300 INCHES IS ILLEGAL ; AND THE ERROR RECOVERY CODE WILL ISSUE A HARD ERROR IF IT INCREMENTS ; TAPELEN PAST 0. EACH INCREMENT REPRESENTS ONE 3 INCH GAP WRITTEN. ; ; BACK5 AND BACK1 BYTES - THESE ARE COUNTERS USED BY THE READ ERROR RECOVERY ; CODE. THERE ARE TWO TYPES OF READ ERROR RECOVERY. ONE IS SIMPLY TO ; BACKSPACE AND REREAD. WHENEVER THE ERROR RECOVERY ALGORITHM DOES THIS ; IT DECREMENTS BACK1. ANOTHER READ RECOVERY IS TO BACKSPACE 5 BLOCKS THEN ; FORWARD SPACE 4 AND REREAD. WHENEVER THE ERROR RECOVERY ALGORITHM DOES THIS ; IT DECREMENTS BACK5. ; ; LASTCOM CONTAINS A VALUE WHICH CORRESPONDS TO THE LAST TAPE MOVEMENT COMMAND ; ISSUED TO THE TAPE UNIT CONTROLLER. ; ; OPERATION CODE (IN LISTING) ; ; -1 WRITE A TAPE MARK SF.MTM ; -2 FORWARD SPACE N BLOCKS SF.MFS ; -3 BACKSPACE N BLOCKS SF.MBS ; -4 ERASE 3" OF TAPE AND WRITE SF.MWE ; -5 REWIND THE TAPE SF.MRE ; -6 GO OFFLINE AND REWIND THE TAPE SF.MOR ; -7 WRITE A BLOCK SF.MWR ; -8 READ A BLOCK IN FORWARD DIRECTION SF.MRD ; ; OLDBA WORD - THIS WORD CONTAINS THE BUFFER ADDRESS FOR THE LAST READ OR ; WRITE COMMAND. IT IS SAVED SO THAT THE ERROR RECOVERY CODE CAN REISSUE ; THE COMMAND WHICH IS BEING RECOVERED. IF THE HANDLER IS CONDITIONALIZED ; FOR EXTENDED MEMORY THEN OLDBA CONTAINS THE LOW 16 BITS OF A PHYSICAL ; ADDRESS. THIS WORD IS A GLOBAL WHICH CAN BE ACCESSED BY FSM. ; ; EXTADR WORD - THIS WORD IS ONLY IN A HANDLER CONDITIONALIZED FOR EXTENDED ; MEMORY. IT CONTAINS THE 2 HIGH ORDER BITS OF A PHYSICAL ADDRESS CORRECTLY ; POSITIONED SO THAT THEY CAN BE OK'ED INTO THE APPROPRIATE DEVICE REGISTER ; WITHOUT ANY SHIFTING. THIS WORD IS A GLOBAL WHICH IS ACCESSED BY FSM. ; ; NFSREAD WORD - THIS WORD IS IN SPECIAL CASE THE PROBLEM OF HOW TO ; REMEMBER THAT THE READ OEPRATION BEING DONE STARTED LIFE AS A .READ ON ; A CHANNEL OPENED WITH A NON FILE STRUCTURED .LOOPUP. WHEN THE EOT ; MARKER IS DETECTED AND THIS WORD IS NON ZERO THEN THE CONDITION IS IGNORED. ; ; .SYNCH REQUEST BLOCK [ONLY IN HANDLER CONDITIONALIZED FOR EXTENDED MEMORY] ; SYNBLK IS THE ADDRESS OF THE BLOCK. JOBNUM IS THE CURRENT JOB NUMBER FOR ; REQUEST BEING SERVICED. TEMP IS A VARIABLE WHICH WILL BE USED TO ; LOAD R0 ON RETURN FROM THE .SYNCH. ; ; SINK WORD - THIS WORD IS SET TO INDICATE THAT THERE ARE ERRORS TO REPORT TO ; THE CALLING PROGRAM. WHEN ALL PROCESSING FOR THE CURRENT QUEUE ELEMENT IS ; DONE THIS WORD IS CHECKED FOR A NON ZERO VALUE. IF NOT FOUND THE HANDLER ; JUMPS TO THE I/O COMPLETE SUBROUTINE. IF SINK IS NON ZERO THEN THE HANDLER ; DOES A JSR TO THE I/O COMPLETE SUBROUTINE IN ORDER TO FREE UP THE QUEUE ; ELEMENT AND GET OUT OF INTEN LEVEL (SET WHEN INTERRUPT HANDLER WAS ENTERED). ; THEN THE HANDLER DOES A .SYNCH TO GET THE CONTEXT OF THE JOB WHICH WANTED ; THE INFORMATION REPORTED AND THEN USES THE INFORMATION STORED IN ERBSAV TO ; POINT INTO THE USERS AREA. THEN R0 (LOADED FROM TEMP IN .SYNCH BLOCK) ; AND ERRBL2 ARE STORED IN ERRBLK AND ERRBLK+2 RESPECTIVELY. ; ; DO NOT CHANGE THE ORDER OF THE FOLLOWING VARIABLES MSFL: .BYTE 1 ; Normally allow DRFIN's TAPELEN:.BYTE ERRGAPS BACK5: .BYTE 0 BACK1: .BYTE 0 LASTCOM:.WORD 0 ; Last command issued OLDBA: .WORD 0 ; Low 16-bit address .IF NE MMG$T EXTADR: .WORD 0 ; high order bits for 18 bit address .ENDC; NE MMG$T SPTMP: .WORD 0 ; save SP here BCNT: .WORD 5 ;# of block for forward/backward space TSFBLK: .WORD 0,0,0,0 ; FORK block $CBUF: .WORD 0 ; Command buffer address **LOAD** MSCB: .BLKW 6 ; Command buffer ; The message buffer area MSMB: .BLKW MS$UN*</2> ; Message buffer(s) MBSR0: .WORD 0 ; Pointer to current TSXST0 word $SCB: .BLKW 4 ; copy of command buffer ; The following two bytes must remain together... CHNABT: .BYTE 0 ; flag indicating .ABTIO CHNUNT: .BYTE 0 ; Unit no. of .ABTIO .IF NE MMG$T ;If XM ; ------------------------------------------------------------------------- ; .SYNCH REQUEST BLOCK ; ------------------------------------------------------------------------- SYNBLK: .WORD 0 ;RESERVED FOR SYSTEM USE JOBNM: .WORD 0 ;JOB NUMBER GOES HERE .WORD 0,0 ; Words 3 and 4 are "UNUSED" TEMP: .WORD 0 ;TO BE LOADED IN R0 AFTER SUCCESSFUL ; COMPLETION OF THE .SYNCH REQUEST .WORD -1,0 ; Words 6 and 7 (reserved) ; ------------------------------------------------------------------------- SINK: .WORD 0 ;=0, SYNCH NOT DONE, DON'T JSR ; TO COMPLETE ;<>0, SYNCH DONE, REGISTERS NEED TO ; BE RESTORED ON RETURN FROM COMPLETE ERBSAV: .WORD 0 ; save the address of ERRBLK here ERRBL2: .WORD 0 ; contains value to go to ERRBLK+2 MSMUBL: .WORD 0 ; UNIBUS address of Message buffer MSMUBH: .WORD 0 ; **LOAD** $CBUFU: .WORD 0 ; CBUF address with bits 16,17 in 0,1 ; **LOAD** BADBIT: .WORD 176000 ; Invalid high bits for bus **LOAD** .ENDC; NE MMG$T .IF EQ MS$FSM .DREND MS .IFF; EQ MS$FSM MTCQ: .WORD 0 ;FAKE AN MSCQE FOR FILE SUPPORT DRIVEN == MS$UN DVINFO:: .REPT DRIVEN .WORD -1 ;D.CFSN - FILE SEQ NUMBER .WORD -1 ;D.CBLK - CURRENT BLOCK NUMBER .WORD -1 ;D.HBLK - HIGHEST BLOCK WRITTEN .BYTE 0 ;D.FTYPE - FILE TYPE, 0=LOOKUP,1=ENTER .BYTE 0 ;D.EOT - POSITIONED PAST EOT FLAG .WORD 0,0,0 ;D.FNAM - RAD50 FILENAME .ENDR ;+ ; THE FOLLOWING DEFINITIONS ARE FOR FSM COMPATIBILITY ;- MTDONE == MSDONE MTCQE == MSCQE MT == MS MTLQE == MSLQE MTSTRT == MSSTRT MSCQ == MTCQ .GLOBL $FKPTR, $INPTR .IF NE MMG$T .GLOBL $RLPTR, $MPPTR, $GTBYT, $PTBYT, $PTWRD .ENDC; NE MMG$T .IF NE ERL$G .GLOBL $ELPTR .ENDC; NE ERL$G .IF NE TIM$IT .GLOBL $TIMIT .ENDC; NE TIM$IT .ENDC; EQ MS$FSM SIZE = . SIZED = /2 .SBTTL LOAD/FETCH code ;+ ; Entry environment: ; ; R0 = Starting address of handler service routine ; R1 = Address of GETVEC routine (PRO only) ; R2 = $SLOT*2 value (length of $PNAME table in bytes) ; R3 = type of entry ; R4 = address of SY read routine (not used) ; R5 = $ENTRY entry address for this handler ;- .PSECT NONRES,I .ENABL LSB ; Begin by relocating some variable and table addresses LOAD: MOV @R5,R3 ; get address of MSLQE (handler base) MOV R3,R1 ; make a copy ADD #<$ADRTB-MSBASE>,R3 ; point to device table MOV R3,(R1) ; relocate references MOV R3,(R1) ; to $ADRTB MOV R3,(R1) MOV @R5,R0 ADD #<$SCB-MSBASE>,R0 ; point to copy of command buffer MOV R0,(R1) ; relocate reference MOV @R5,R0 ADD #,R0 ; point to abort variables MOV R0,(R1) ; relocate reference .IF NE MMG$T MOV @R5,R0 ADD #,R0 ; point to QUEUE ELEMENT pointer MOV R0,(R1) ; relocate references MOV R0,(R1) MOV @R5,R0 ADD #,R0 ; point to SYNCH BLOCK MOV R0,(R1) ; relocate reference .ENDC; NE MMG$T MOV @R5,R0 ADD #,R0 ; point to message buffer area .IF NE MMG$T MOV R0,(R1) ; relocate reference .ENDC; NE MMG$T .IF GT MS$UN-1 ; Test which CSRs other than MS0: really exist in the backplane... MOV #MS$UN,R4 ; for this many entries, BR 15$ ; force existance of MS0: ; (install code checked it) 10$: CLR -(SP) ; space for return value .MFPS ; get processor status .MTPS #340 ; Enter PRIORITY 7 MOV @#NXM.V+2,-(SP) ;;; save trap vector PS MOV @#NXM.V,-(SP) ;;; save trap vector .ADDR #$MSNXM,-(SP) ;;; build adrs of our trap routine MOV (SP)+,@#NXM.V ;;; MOV #340,@#NXM.V+2 ;;; TST @TB$TSR(R3) ;;; try to read CSR... MOV (SP)+,@#NXM.V ;;;*C* restore system's trap vector MOV (SP)+,@#NXM.V+2 ;;;*C* restore system's trap vector PS ROL 2(SP) ;;; save carry bit .MTPS ; Restore normal priority ROR (SP)+ ; restore C-bit BCS 20$ ; br if no device present .ENDC; GT MS$UN-1 15$: BISB #,TB$TS5(R3) ; declare DEVICE EXISTS 20$: MOV R0,TB$MBA(R3) ; store its MBUF address .IF GT MS$UN-1 ADD #MBFSIZ,R0 ; next MBUF address ADD #TB$ESZ,R3 ; advance to next entry SOB R4,10$ ; continue trying CSRs .ENDC; GT MS$UN-1 ; Relocate a few more variables MOV R1,R0 ADD #,R0 ; get address of Command Buffer .IF EQ MMG$T BIT #2,R0 ; Address must be MOD 4 BEQ 30$ TST (R0)+ ; Force it MOD 4 .ENDC ;EQ MMG$T 30$: MOV R0,<$CBUF-MSBASE>(R1) ; save it .IF NE MMG$T ; Set up communication with UB MOV @#$SYPTR,R0 ; RMON base BIT #,$CNFG2(R0) ; If not UNIBUS, get out. BNE 40$ ; Branch if Q-bus BIS #1700,(R1) ; Set up bad UNIBUS bit mask 40$: MOV $H2UB(R0),R3 ; R3 = UBVECT pointer ; Allocate one UMR for MS handler. It is used by the Command and Message ; buffers. If linked with FSM, it is also used by the FSM label buffers. MOV R1,-(SP) ; save handler base MOV #NUMRS,R0 ADD #,R1 ; point to Command Buffer area MOV R5,R4 ; $ENTRY entry address SUB R2,R4 ; $PNAME entry address CLR R2 ; high bits of FSM buffer CALL UB.ALL(R3) ; Allocate the UMR for FSM MOV (SP)+,R3 ; restore handler base in R3 BCS 60$ ; NO LOAD on failure from ALLUMR MOV R1,R0 BIT #2,R0 ; Force to MOD 4 address BEQ 50$ TST (R0)+ ; ...Adjust $CBUFU ADD #2,<$CBUF-MSBASE>(R3) ; ...Adjust $CBUF accordingly 50$: BIS R2,R0 ; Combine CBUF address bits MOV R0,<$CBUFU-MSBASE>(R3) ; and store for use in TB$CBR ADD #,R1 ; calculate effective UNIBUS address ADC R2 ; of Message Buffer MSMB MOV R1,(R3) ; store low 16 bits of UNIBUS address MOV R2,(R3) ; store high 2 bits of UNIBUS address .IF NE MS$FSM ADD #,R1 ; calculate effective UNIBUS address ADC R2 ; of HDR1LB in FSM MOV R1,(R3) ; store low 16 bits of UNIBUS address MOV R2,(R3) ; store high 2 bits of UNIBUS address ADD #,R1 ; calculate effective UNIBUS address ADC R2 ; of LABLIO in FSM MOV R1,(R3) ; store low 16 bits of UNIBUS address MOV R2,(R3) ; store high 2 bits of UNIBUS address .ENDC; NE MS$FSM .ENDC; NE MMG$T CLC ; Indicate successful ALLUMR call 60$: RETURN .DSABL LSB .SBTTL UNLOAD/RELEASE code ;+ ; UNLOAD/RELEASE code ; ; Release the permanent UMR we got when we were LOADED or FETCHED. ;- UNLOAD: .IF NE MMG$T MOV R5,R1 ; Point to $ENTRY entry SUB R2,R1 ; Point to $PNAME entry MOV @#$SYPTR,R4 ; RMON base MOV $H2UB(R4),R5 ; Get H2UB vector entry CALL UB.RLS(R5) ; Release UMR .ENDC; NE MMG$T CLR R0 ; Ensure clean UNLOAD RETURN ...... ;+ ; $MSNXM ; Local Non-Existant Memory Trap routine ; ; This little routine is set up by the LOAD/FETCH code. It gets ; executed via TRAP-to-4 when a non-existant CSR is addressed. ;- $MSNXM: BIS #1,2(SP) ; set C-bit in saved PSW RTI ; return ...... .ASSUME . LE ,<;LOAD code overflow> .END