.MCALL .MODULE .MODULE MU,VERSION=92,COMMENT= ; 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. ;++ ; Facility: Handler fo MSCP Class Magnetic Tape Devices ; ; Author: ; ; Abstract: ; ; Externals Description ; --------- ----------- ; ; ; Edit Who Date Description of modification ; ---- --- ---- --------------------------- ; 001 WLD 16-JAN-90 Remove check on wcnt. No ; justification has been found ; for substituting o'077777' for ; o'177776' for a byte count in ; the MSCP packet. This substitution ; changes wcnt as specified by the ; application programmer from ; 32,767 (o'077777') to 16,383 ; (o'037777'). No other magnetic ; tape handler in RT-11 V5.5 performs ; wcnt reduction. ; 092 WFG 14-Jun-91 ACTION #7479, Fix RESORC/V display ; Remove AUDIT=YES from .MODULE ;-- UM$MU = 1 ;We're building MU .NLIST CND ;Make a readable listing .SBTTL .MCALLs .LIBRARY "SRC:SYSTEM.MLB" .MCALL .ADDR, .ASSUME,.BR, .DRDEF, .INTEN .MCALL .MFPS, .MTPS, .PRINT, .SYNCH, .TRPSET .MCALL .WAIT .MCALL .CF2DF, .CF3DF, .DVMDF, .ELIDF, .ERMDF .MCALL .ERRDF, .FIXDF, .MEMDF, .P1XDF, .SFDDF .MCALL .SFMDF, .SYCDF .UBVDF, .USSDF ;invoke system.mlb macros .CF2DF ;system configuration word number 2 .CF3DF ;system configuration word number 3 .DVMDF ;device handler mode bits .ELIDF ;error logger record types .ERRDF ;RT-11 error definitions .ERMDF ;magtape error definitions .FIXDF ;monitor fixed offsets .P1XDF ;jump table relative to P1EXT .SFDDF ;special function definitions .SFMDF ;special function definitions for magtape .SYCDF ;system communication area, aka "impure area" .UBVDF ;UB handler vector definition .USSDF ;USR error definitions .SBTTL Conditional Assembly Summary ;+ ;COND ; MMG$T std conditional ; TIM$T std conditional (no code effects) ; ERL$G std conditional ; ; MU$FSM (0) FSM support ; 0 NFS ; 1 FS ; ; (NOP for TU81E, so conditionalized out.) ; MU$EWR (0) Enhanced Write Error Recovery support ; 0 no EWR support ; 1 EWR support ; ; MU$ERL (0) ; 0 no error logging ; 1 old fashioned RT-11 error logging ; 2 TMSCP error logging ; ; MU$UN (1) number of units to support ; 1-4 range of values ; ; MU$PORts (MU$UN) ports ; ; MU$GBL (^RMU ) region name ; ; MU$CSR (174500) First CSR ; MU$CS1 (MU$CSR+4) Second CSR ; MU$CS2 (MU$CSR+10) Second CSR ; MU$CS3 (MU$CSR+14) Second CSR ; ; MU$VEC (260) First vector ; MU$VC1 (340) Second vector ; MU$VC2 (MU$VC1+4) Third vector ; MU$VC3 (MU$VC1+10) Fourth vector ;- .SBTTL Check SYSGEN parameters ;+ ; Handler conditionals. ; ; When the MU$FSM conditional is not = 0, 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/22 bit I/O. ; .IIF NDF MMG$T MMG$T = 0 ;No XM, if not defined .IIF NDF MU$EWR MU$EWR= 0 ;No Enhanced Write Error Recovery .IIF NDF MU$FSM MU$FSM = 0 ;No file structure if not defined .IIF NE MU$FSM MU$FSM = 1 ;File structure (make 0 or 1) ; ; Initially, the RT-11 unit numbers translate 1 to 1 with the port ; numbers, since for all existing and planned controllers, there ; is only one drive per controller. All TMSCP unit numbers default ; to 0. Thus RT-11 unit MU0: is unit 0 of port 0; RT-11 unit MU1: ; is unit 0 of port 1; etc. ; ; The UM$Ax value is the 'Owner Job# byte' (UT.JOB) and is format- ; ted as follows: (DU uses this byte for partition #) ; ; Bits: R J J J J n n n ; ^ \ ^ ^ / ^ ^ ^ ; | \ / | | +-> (Not used) ; | \ / | +---> (Not used) ; | | +-----> (Not used) ; | +----------> Job # of Owner (all 1's = available) ; +---------------> Reserved (extra job # bit) ; ; ; UT.JOB Job # Byte (1 byte). (Tape only) ;- ;UT.JOB bit definitions: UT.AVAL=: 170 ; (all 1s -> unit available) .IIF NDF MU$UN MU$UN == 1 ;Assume at least one unit MU$PORTS = MU$UN ;For now, # of ports = # of units. .IIF LE MU$PORTS-1, MU$PORTS = 1 ;Never let the number be less than 1. UM$PORTS = MU$PORTS ;For use in common code UM$UNITS = MU$PORTS ;For use in common code $1=0 .REPT UM$UNITS .IRP Y,\$1 .IIF NDF UM$U'Y UM$U'Y = 0 ;define default TMSCP unit number .IIF NDF UM$O'Y UM$O'Y = $1 ;define default port .Assume UM$O'Y LE UM$PORTS .Assume UM$O'Y GE 0 .IIF NDF UM$A'Y UM$A'Y=UT.AVAL ;define default job ownership, = unowned $1=$1+1 .ENDR .ENDR UM$PRI =: 5 ;Device priority level .IIF NDF MU$CSR MU$CSR = 174500 UM$CSR = MU$CSR .IIF NDF MU$VEC MU$VEC = 260 UM$VEC = MU$VEC .IIF NDF MU$ERL MU$ERL = 0 UM$ERL = MU$ERL .IIF NDF MU$NAM MU$NAM = <^RMU > ;Handler (MU) & global region (MU $ ) UM$NAM = MU$NAM ; name to use instead of .MODULE's UM. .IIF NDF MU$CS1, MU$CS1 = MU$CSR+04 UM$CS1 = MU$CS1 .IIF NDF MU$CS2, MU$CS2 = MU$CSR+10 UM$CS2 = MU$CS2 .IIF NDF MU$CS3, MU$CS3 = MU$CSR+14 UM$CS3 = MU$CS3 .IIF NDF MU$VC1, MU$VC1 = 340 ;Floating vector area UM$VC1 = MU$VC1 .IIF NDF MU$VC2, MU$VC2 = MU$VC1+4 UM$VC2 = MU$VC2 .IIF NDF MU$VC3, MU$VC3 = MU$VC1+10 UM$VC3 = MU$VC3 .SBTTL TMSCP Magtape Handler Functional Description ;+ ; Handler Functional overview ; ; This handler provides support for TMSCP tape class devices. ; ; o Full functional use of TMSCP as required by RT-11 (not ; a subset). ; o Support for TK50,TU81,TU81+ TMSCP tape class devices ; o Transparent special function support to facilitate ; unlimited access to all TMSCP features. ; o Multiple unit (port) support as a SYSGEN option. ; o RT-11 unit translation for port number, CSR, vector, and ; TMSCP unit. ; o Plus standard RT-11 reads and writes (of course). ; o By-pass recovery. ; o TMSCP error logging as a SYSGEN option ; o Traditional RT11 error logging ; ; SET options ; ; Set options in this handler manipulate control and translation tables ; which are used to map any RT-11 unit to any TMSCP port and unit. For ; example: ; ; SET MU5: PORT=2,UNIT=1 ; ; would cause all references on MU5 to go to TMSCP port number 2, ; unit number 1. ; ; SET MU CSRn = nnnnnn ; SET MU VECTOR = nnn (VECn = nnn) ; SET MUx UNIT = nnn ; SET MUx PORT = nnn ; SET MUx DENSE= nnn ;sets magtape density ; SET MUx DEFALT ;resets to default density ; SET SUCCES = Y/N ; SET RETRY = nn ; ;- .SBTTL Special Function Codes ;+ ; Special Directory Operations MU handler accepts the following codes: ; ---------------------------- --------------------------------------- ; 6 .PURGE ; 3 .LOOKUP (NFS) ; 2 .DELETE - Illegal !! ; 1 .CLOSE ; 0 .READx/.WRITx (NFS) ; ; Special Function Codes MU handler accepts the following codes: ; ---------------------- --------------------------------------- ; 377 Write EOF (tapemark) ; (Any other code will 376 Forward space ; cause a hard error.) 375 Backspace ; 374 Write with extended gap (== Write) ; 373 Rewind ; 372 Rewind and Offline ; 371 Write a block ; 370 Read a block ; 367 Stream at 100 IPS - Ignored !! ; 360 TMSCP Bypass ; 352 Read/Write RT-11/TMSCP unit table ; ; The following describes the action taken by the handler for a given code. ; ; Code Action ; 6 .PURGE Treated like .CLOSE ; ; 3 .LOOKUP First, initialize command and message buffers. Next, check ; filename at Q.BUF for zero (means a non file structured .LOOKUP.) Then ; examine table entry in case another channel is using this unit. Last, ; see if the SEQNUM argument (= Q.BLK) is zero, meaning do a rewind. ; ; 1 .CLOSE Mark the unit unused. ; ; 0 .READx/.WRITx Read/Write blocks of data on currently-mounted tape. ; .WRITx reports end of file when it sees EOT marker. .READx reports end ; of file only when it reads a tape mark (TM). It ignores EOT marker. ; ; 377 Write a tapemark. ; ; 376 Space FORWARD n (Q.WCNT) blocks til n expires, EOT sensed, or TM read. ; ; 375 Space BACK n (Q.WCNT) blocks til n expires, BOT sensed, or TM read. ; ; 374 Write a block to tape (same as -7, for compatability with MT,MS). ; ; 373 Rewind the tape to BOT. ; ; 372 Rewind to BOT and turn tape unit offline. ; ; 371 Write a block to tape. ; ; 370 Read a block from tape. ; ; 367 Stream at 100 IPS. (IGNORED for compatability with TS05.) ; ; 360 TMSCP Bypass (see below) ; ; 352 Read/Write RT-11/TMSCP unit table (see below) ; ; 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. ;- .SBTTL SPFUN Code 360 - TMSCP Bypass ;+ ; SPFUN Code 360 - TMSCP Bypass ; ; Q$BLK = 0 -> DO NOT recover ; = 1 -> recover ; Special function code 360 enables direct access to the TMSCP port. The ; buffer address in the .SPFUN request must point to a 52-word area in ; in the user's job. The first 26 words are used to hold the response ; packet length (in bytes), the virtual circuit identifier and the end ; packet when the command is complete. The second 26 words must be set ; up by the caller to contain a length word, a virtual circuit ; identifier and a valid TMSCP command. ; ; ----------------------------------------- ; 0 | Response Packet Length | ; ----------------------------------------- ; 1 | Virtual Circuit ID (from UDA) | ; ----------------------------------------- ; 2 | TMSCP Response Buffer (24 Words) | ; ----------------------------------------- ; / / ; / / ; ----------------------------------------- ; 26 | Command Packet Length (48.) | ; ----------------------------------------- ; 27 | Virtual Circuit ID (from Host) | ; ----------------------------------------- ; 28 | TMSCP Command (24 Words) | ; ----------------------------------------- ; / / ; / / ; ----------------------------------------- ; 51 | Last Word of TMSCP Command Packet | ; ----------------------------------------- ; ;- .SBTTL SPFUN Code 352 - Read/Write RT-11/TMSCP Unit Translation Table ;+ ; SPFUN Code 352 - Read/Write RT-11/TMSCP Unit Translation Table ; ; Q$WCNT = + -> Read Table ; = - -> Write Table ; ; Special function code 352 reads/writes the RT-11 to MSCP translation ; table. The buffer supplied by the user must point to a 10 word area to ; receive/send the information. The format of the area is: ; ; Bit # 15 8|7 0 Offset Size ; .--------------------------------. ; Table ID | RAD50 "MU_" | 0 2 ; .--------------------------------. ; Unit count | 4 (for now) | 2 2 ; .--------------------------------. ; | MSCP Unit Number | 4 2 ; RT-11 Unit 0 |--------------------------------| ; | UDA Port |Owner Job#/Flags| 6 2 ; |--------------------------------| ; | MSCP Unit Number | 10 2 ; RT-11 Unit 1 |--------------------------------| ; | UDA Port |Owner Job#/Flags| 12 2 ; '--------------------------------' ; / / ; / etc. / ;- .IF NE MU$FSM ;If file structured .SBTTL DVINFO Table Offsets FSM only ;+ ; DVINFO Table Offsets - this structure is an FSM structure located ; in low memory ;- D.CFSN = 0 ;Current File Sequence Number D.CBLK = 2 ;Current Block Number D.HBLK = 4 ;Highest Block Written D.FTYPE = 6 ;File Type, 1=NFS, 0=LOOKUP,-1=ENTER D.EOT = 7 ;Position is Past EOT Marker Flag D.FNAM = 10 ;RAD50 File Name .ENDC ;NE MU$FSM .SBTTL Error Codes Returned by Magtape Operations ;+ ; LOOKUP, ENTER, Codes found in BYTE 52 after an error. Placed there by ; READx, WRITx. FSM, if present, otherwise MU.SYS has to do it. ; -------------- ; READ, WRITE 0 = Attempt to read/write past EOT (TM) or ; block size too large on a READ ; EOF bit in CSW set ; READ, WRITE 1 = hard error ; hard error bit in CSW set ; ENTER, LOOKUP 2 = Device in Use by another Job ; ER.SHR returned in SPUSER ; ENTER, LOOKUP 5 = Invalid Sequence Number ; ER.ISN returned in SPUSER ; ENTER, LOOKUP 6 = Invalid Unit ; ER.IUN returned in SPUSER ; SPFUNS ; ------ ; If EOF set in Byte 52: R5 : 1= hard error, 20000 = eof ; R4 : additional information about error. ; ; On return from error, whatever is in R4 is placed in @Q$BLK, additional info ; may be placed in @Q$BLK+2, mainly the number of words not read or blocks not ; spaced. ; R5 R4 @Q$BLKN+2 ; SPFUN Byte 52 Word 1 Word 2 ; 0=eof,20000 in csw ERBSAV ; 1=hderr, 1 in csw ERRBL2 ;----------------------------------------------------------------------------- ; 370, 371, 375, 376 0 1 = EOF (TM) 375, 376 ; 370, 371, 375, 376 0 2 = EOT (no TM) 375, 376 ; 370, 371, 375, 376 0 3 = EOT & EOF 375, 376 ; 375 0 4 = BOT (no TM) 375 ; ; ALL 1 0 = Drive Dependent Error ; ALL 1 1 = Unit not Available ; 370, 371, 377 1 2 = Position Lost ; 370, 371, 377 1 3 = Non existant Memory ; 370, 371, 377 1 4 = Unit Write Locked ; 370 1 5 = Last record read had ; more information 370 ; 370 1 6 = Short block read 370 ;- MAXBLK = 77777 ;Max block count for fwd/bkwd space .SBTTL TMSCP Commands ;+ ; TMSCP Commands Used by RT-11 ; -------------- ------------- ; Abort Yes ; Access No ; Available Yes ; Compare Host Data No ; Erase No ; Get Command Status No ; Get Unit Status Yes ; Online Yes ; Read Yes ; Reposition Yes ; Set Controller Characteristics Yes ; Set Unit Characteristics Yes (if caching drive) ; Write Yes ; Write Tape Mark Yes ; ; ; TMSCP Commands That Will NOT Be Implemented: ; -------------------------------------------- ; ; Compare Controller Data Issuance of this command on TK50/70 is ; a NOP and will return SUCCESS ; ; Determine Access Paths Existing TMSCP drives only communicate ; with 1 host at a time due to physical ; design constraints. Issuance of this ; command is a NOP and will return ; SUCCESS ; ; Erase Gap Issuance of this command on TK50/70 is ; a NOP and will return SUCCESS ; ; Flush Issuance of this command on TK50/TU81 ; is a NOP and returns SUCCESS. On TK70 ; or TU81E, this command forces writing ; to tape of data previously buffered in ; cache. MU handler does not use Flush. ;- .SBTTL TMSCP Specific Protocol Definitions ;+ ; Only TMSCP specific mnemonics are defined here. Mnemonics common to MSCP and ; TMSCP are defined in module UM.MAC which is .INCLUDEd in DU.MAC and TU.MAC. ;- ;+ ; Control Packet Opcodes ;- OP.CCD =: 21 ;COMPARE CONTROLLER DATA Command OP.FLU =: 23 ;FLUSH Command OP.ERG =: 26 ;ERASE GAP Command OP.WTM =: 44 ;WRITE TAPE MARK Command OP.REP =: 45 ;REPOSITION Command ;+ ; NOTE: Command opcode bits 3 thru 5 indicate the command class which is ; encoded for TMSCP as follows: ; ; 000 Immediate command ; 001 sequential commands ; 010 sequential commands ; 100 sequential commands ; ; Write command opcodes bit 0 position is always a zero. ; ; Read command opcodes bit 0 position is always a one. ; ; NOTE: End packet opcodes are formed by ORing the end packet flag to the ; command opcode. For example, OP.RD!OP.END = OP.RD endcode. If the ; endcode is OP.END alone then the command was unknown. If the endcode is ; OP.SEX!OP.END then the command ended with a serious exception. ;- ;+ ; Generic Command Modifiers: ;- MD.CSE =: 20000 ;Clear Serious Exception MD.CDL =: 10000 ;Clear Cached Data Lost MD.ERW =: 20 ;Enable Re-write Error Recovery MD.SWP =: 4 ;Enable Set Write Protect MD.NXU =: 1 ;Next Unit MD.RWD =: 2 ;Rewind ; (Will cause REWIND then SPACE FORWARD ; number of tapemarks and records found ; in P.RECC and P.TMGC. Make sure these ; fields ARE ZERO if plain old REWIND ; is desired.) MD.OBC =: 4 ;Object Count ; (If set causes count of records and ; tape marks - i.e. things written.) MD.REV =: 10 ;Reverse MD.UNL =: 20 ;Unload MD.EXC =: 40 ;Exclusive Access MD.IMM =: 100 ;Immediate Completion MD.DLE =: 200 ;Detect LEOT ;+ ; End Message Flags ;- EF.SEX =: 20 ;Serious Exception EF.EOT =: 10 ;End of Tape encountered EF.PLS =: 4 ;Position Lost (subject to firmware change) EF.DLS =: 2 ;Cached Data Lost ;+ ; Unit Flags (TMSCP) ;- UF.CAC =: 100000 ;Tape Write-back Caching UF.WBN =: 100 ;Write-back UF.EWR =: 10 ;Enhanced Write Error Recovery ;+ ; Error Log Message Format Codes ;- FM.TPE =: 5 ;Tape transfer errors FM.STI =: 6 ;STI communication or command failure FM.DEL =: 7 ;STI Drive Error Log FM.FEL =: 10 ;STI Formatter Error Log ;+ ; Tape Format Flag Values ;- TF.800 =: 1 ;NRZI 800 bpi TF.PE =: 2 ;Phase Encoded 1600 bpi TF.GCR =: 4 ;Group Code Recording 6250 bpi TF.BLK =: 10 ;Cartridge Block Mode (subject to hdw change) ; (TF.BLK is not used) ;+ ; Status and Event codes ;- ; 0 ;Status/event code bit offset ; 5 ;Status/event code field size ST.SUB =: 40 ;Sub-code multiplier ST.ABO =: 2 ;Command aborted ST.MFE =: 5 ;Media Format Error ST.CMP =: 7 ;Compare Error ST.HST =: 11 ;Host buffer access error ST.CNT =: 12 ;Controller error ST.FMT =: 14 ;Formatter error ST.BOT =: 15 ;BOT Encountered ST.TM =: 16 ;Tape mark encountered ; 17 ;UNASSIGNED ST.RDT =: 20 ;Record data truncated ST.POL =: 21 ;Position lost ST.SEX =: 22 ;Serious exception ST.LED =: 23 ;LEOT detected ; 24-36 ;UNASSIGNED ST.DIA =: 37 ;Message from an internal diagnostic ST.EOT =: 2000 ;SUCCESS and physical EOT found, see next page .SBTTL TMSCP Specific Status/Event Sub-Code Values ;+ ; NOTE: The combination of a status or event code with a sub-code should be ; expressed as: ; ((sub-code * ST.SUB) + status_event code)) ; ; Success status/event sub-codes: ; ; 0 normal ; 100 still connected ; 200 duplicate unit number ; 400 already online ; 1000 still online ; 1010 still online/unload ignored ; 2000 EOT encountered ; ; Invalid Command status/event sub-codes: ; ; 1 invalid message length ; other invalid command sub-code values should be referenced as ; follows: (note that this is combined with the status code) ; offset*256.+code ; where offset is the command message ofset symbol for the field ; in error, and code is the symbol for the invalid command ; status code. ; ; Unit-offline status/event sub-codes: ; ; 3 unit unknown or online to another controller ; 43 no media mounted or disabled via switch setting ; 103 unit is inoperative ; 203 duplicate unit number ; 403 unit disabled by field service or internal diagnostic ; ; Write protected status/event sub-codes: ; ; 20006 unit is hardware write protected ; 10006 unit is software write protected ; ; Data error status/event sub-codes: ; ; 10 log gap encountered ; 50 data sync not found (data sync timeout)A ; 350 unrecoverable read error ; many controller and/or drive/formatter type dependent ; ; Controller error status/event sub-codes: ; ; 12 reserved for command timeout/retry limit exceeded ; many controller and/or drive/formatter type dependent ; ; Drive error / Formatter error / Message from internal diagnostic / ; Host buffer access error / status/event sub-codes: ; ; many controller and/or drive/formatter type dependent ;- .SBTTL TMSCP Command Packet Offsets and Field Lengths ;+ ; ONLINE and SET UNIT CHARACTERISTICS Command Packet Offsets and Field Lengths ;- P.FORM =: 40 ;2 Format P.SPED =: 42 ;2 Speed ;+ ; REPOSITION Command Packet Offsets and Field Lengths: ;- P.RECC =: 14 ;4 Replacement block number - # OF RECORDS P.TMGC =: 20 ;4 Tape Mark Count or N/A - # OF TAPE MARKS ;+ ; End and Attention Message Offsets and Field Lengths: ; ; ACCESS, COMPARE HOST DATA, READ, REPOSITION, WRITE, WRITE TAPE MARK end ;- P.POS =: 34 ;4 Position (Object count) # OF THINGS ; WRITTEN TO THE TAPE ;+ ; ACCESS, COMPARE HOST DATA, READ end ;- P.TRBC =: 40 ;4 Tape record byte count ;+ ; GET UNIT STATUS End Packet Offsets and Field Lengths: ;- P.MEDI =: 34 ;4 Media Identifier P.FORM =: 40 ;2 Tape format P.SPED =: 42 ;2 Speed P.FMEN =: 44 ;2 Format Menu ;+ ; ONLINE and SET UNIT CHARACTERISTICS End Packet Offsets and Field Lengths: ;- P.MEDI =: 34 ;4 Media type identifier P.FORM =: 40 ;2 Tape format P.SPED =: 42 ;2 Speed P.MXWR =: 44 ;4 MAXIMUM WRITE record size P.NREC =: 50 ;2 Noise Record ;+ ; REPOSITION end ;- P.RCSK =: 14 ;4 Records Skipped P.TMSK =: 20 ;4 Tape Marks Skipped ;+ ; Error Log Message Packet Offsets and Field Lengths ;- L.FMTD =: 42 ;2 Format dependent L.GPCT =: 44 ;4 Position (object count) L.FSVR =: 50 ;1 Formatter software version L.FHVR =: 51 ;1 Formatter hardware version ;+ ; STI Communication Errors Error Log message Offsets ;- ; 42 ;2 Reserved L.SDI =: 54 ;12 STI UNSUCCESSFUL Response ;+ ; STI Formatter Error Error log Message Offsets ;- ; 42 ;2 Reserved L.STI =: 54 ;24 STE GET EXTNDED FORMATTER STATUS Response ;+ ; STI Drive Error Error Log Message Offsets ;- L.STI =: 54 ;62 STI GET EXTENDED DRIVE STATUS Response ;+ ; Tape Identifier Values (NOT USED) ; ; MU TA78 066550,010116 PE/GCR, 125 ips start/stop ; MU TK50 066550,130062 100 MB Cartridge Drive ; MU TA81 066550,010121 STI version of the TU81 ;- ;+ ; Miscellaneous declarations ;- TAPEID =: 1 ;Virtual circuit id for TMSCP DN1600 =: 1600. ;1600 bpi density value. DN6250 =: 6250. ;6250 bpi density value. ;+ ; Miscellaneous Macros ;- .MACRO ...... .ENDM ;+ ; SET MU DENSE=n ;Define offsets / bit values in density table. ;- DN.DEN =: 0 ;Density byte DN.SET =: 200 ;Flag = @BOT, set density for next cmd DN.FLG =: 1 ;Flag byte DN.CAC =: 1 ; = 1 => Tape write-back caching. DN.CDL =: 2 ; = 1 => Clear cached data lost flag. DN.CSE =: 4 ; = 1 => Clear serious exception flag. .IF NE MU$EWR ;If Enhanced Write Error Recovery. DN.EWR =: 10 ; = 1 => Enhanced write err recovery. .ENDC ;NE MU$EWR ; ; Additional .AUDIT parameters ; ;since we are building MU, not DU, these two conditional muxt ;absolutely positively be zero UM$BBR =: 0 ;For common code UM$BOO =: 0 ;For common code .SBTTL .DRDEF - Device Definition .IF EQ MMG$T .DRDEF UM,60,,0,UM$CSR,UM$VEC .IFF; EQ MMG$T NUMRS = 1+MU$FSM ;number of Unibus Mapping Registers ;required of the UB handler .DRDEF UM,60,,0,UM$CSR,UM$VEC,DMA=YES,PERMUMR=NUMRS,SERIAL=YES .ENDC; EQ MMG$T .SBTTL .DRPTR - .DREST, .DRSPF Macro Invocations .DRPTR FETCH=ONCE,LOAD=ONCE,UNLOAD=UNLOAD,RELEASE=UNLOAD .IF EQ MU$FSM .DREST CLASS=DVC.MT,MOD=DVM.NS ; device is NFS MAGTAPE .IFF; EQ MU$FSM .DREST CLASS=DVC.MT ; device is a MAGTAPE .ENDC; EQ MU$FSM .SBTTL - .DRSPF invocations for MU Special Functions .DRSPF SF.MFS,TYPE=M ;376 Forward space block .DRSPF SF.MBS,TYPE=M ;375 Backspace block ; (SF.MWE) ;374 Write w/ext. gap ; ** NOT SUPPORTED ** If received, ; handler does write physical ; (SF.MWR). (TMSCP: If you use ; Erase Gap, tapes affected may ; not be able to be read on all ; systems.) .DRSPF SF.MRE,TYPE=M ;373 Rewind .DRSPF SF.MOR,TYPE=M ;372 Offline Rewind ; (SF.MST) ;367 Stream @ 100ips **NOT SUPPORTED** .DRSPF SF.BYP,TYPE=O ;360 Bypass handler, pass MSCP -> port .IF NE MU$FSM ;If file structured .DRSPF SF.USR,TYPE=O ;354 Asynchronous Directory Operation .ENDC ;NE MU$FSM .DRSPF SF.MTB,TYPE=O ;352 Read/Write Unit Translation Table .DRSPF +SFTAB .SBTTL Psect Ordering .PSECT UMDVR ;Handler Beginning (Low Mem in XM) .PSECT UMLORD ;Low Mem ORDER DEPENDENT Impure Data LOWBAS:: .PSECT UMLDATA ;Low Mem Impure Data .IF EQ MMG$T .PSECT UMDATA ;Impure Data (Low Mem in SJ/FB) .PSECT UMY ;empty in MU. Full of BBR in DU UMYBAS:: .ENDC ;EQ MMG$T .PSECT UMLCODE ;Handler Code (Low Mem in XM) .IF NE MU$FSM .PSECT MTDVR ;Magtape FSM Code (Low Mem in XM) .ENDC ;NE MU$FSM .PSECT SETOVR ;SET Code Overlays (Block Aligned!!) .PSECT UMLST ;Root to Root references to UM.LST:: ;to relocate .IF NE MMG$T .PSECT UMNDLS ;List End Psect (Block Aligns SETOV1) .PSECT SETOV1 ;Rest of SET/INSTALL Overlay Code .PSECT LDOVR ;Load code overlay block aligned .PSECT UMRLST ;Ext Mem Refs to Root to Relocate .PSECT UYRLST ;more ext mem refs to root to reloc. UYR.LST:: .PSECT UMXDAT ;Ext Mem ORDER DEPENDENT Impure Data ; (Hi Mem in XM) (Block Aligned!!) UMXBAS:: ;Base of Ext Mem Psects UMXDBA:: .PSECT UMDATA ;Impure Data (Hi Mem in XM) DATABA:: .PSECT UMX ;Ext Mem Handler Code (Hi Mem in XM) UMXBA:: .PSECT UMY ;empty in MU. Full of BBR in DU. UMYBAS:: .ENDC ;NE MMG$T .PSECT SPFUNS ;over flow from block 0's spfun table .PSECT $LAST$ ;Null PSECT should be LAST in map!! ;+ ; Should do this, but FSM.MAC has '.DREND MT' for file structured case ; .PSECT UMEND ;Handler end ; .DREND UM,PSECT=UMEND ;- .INCLUDE "SRC:UM.MAC" ;Include the code common with DU .TITLE MU - TMSCP Tape Class Handler .SBTTL ************************* .SBTTL * MU * .SBTTL ************************* ; Now set the AUDIT trail .AUDIT .UM,.UMGEN,.UMUNI ;Universal (T)MSCP Class Handler .AUDIT .MU ;TMSCP Port Handler .IIF EQ MU$FSM .FSM = 100000 ;= N/A Instead of FSM version number .AUDIT .FSM .SBTTL RT-11 Software Definitions ;+ ; Errors And Other Useful Things ;- ER.IUN =: 6 ;Invalid unit number (.LOOKUP) ;********************************************************************* .PSECT UMLORD ;********************************************************************* .SBTTL DNTAB - Magtape Density/Flag Table ;+ ; DNTAB - Magtape Density/Flag Table ; ; This table is used to keep track of the density that a particular unit ; has been SET to via the 'SET MUn DENSE=nnn' command, and of various ; flags which reflect the status of the unit. ; ; The entries are a word long, each corresponding to one of the units of ; MU0:-MUn:, where n= UM$UNITS. The low byte of the entry is a coded byte ; which specifies the desired density. The high byte contains flag bits. ; ; The HIGH byte is a flag byte (DN.FLG) and is formatted as follows: ; ; DN.FLG Flag Byte (1 byte). ; ; Bits: n n n n F F F F ; | ^ ^ ^ ^ ; | | | | +-> Tape Write-back Caching flag (DN.CAC). ; | | | +---> Must clear Cached Data Lost flag (DN.CDL). ; | | +-----> Must clear Serious Exception flag (DN.CSE). ; | +-------> Enhanced Write Error Recovery flag (DN.EWR). ; +------------> (n = not used) ; ; The LOW byte (DN.DEN) is formatted as follows: ; ; Bits: F v v v v v v v ; ; The high bit is a flag (DN.SET) saying set the unit's density. ; ; The other seven bits are a value specifying the desired density: ; ; Value Density ; 0 (Default - do not attempt to set density on this unit.) ; 1 800bpi ; 2 1600bpi Phase Encoded ; 3 6250bpi Group Code Recording ; ;- .ASSUME DN.DEN EQ 0 .ASSUME DN.SET EQ 200 .ASSUME DN.FLG EQ 1 CLONE .DNTAB,<: .WORD 0> ;Pts to current unit's DNTAB code byte CLONE DNTAB,<::> .REPT UM$UNITS CLONE ,< .WORD 0> ;Init all entries to default. .ENDR .EVEN ;********************************************************************* .PSECT UMLDATA ;********************************************************************* .IF NE MMG$T ;If XM ;********************************************************************* .PSECT UMDATA ;********************************************************************* ;+ ; Pointer location to be relocated ;- H$RLPT: .WORD 0 ;$RELOC ptr .IFTF ;NE MMG$T ;+ ; Table of density bits corresponding to binary values of DNTAB entry. ; ; DNTAB entry = 0 -> (default, don't select density) ; = 1 -> TF.800 ; = 2 -> TF.PE ; etc. ;- DENBIT: .BYTE 0 ;(Use default density) .BYTE TF.800 ;NRZI 800 bpi (unused, as yet) .BYTE TF.PE ;Phase Encoded 1600bpi (TU81,81+) .BYTE TF.GCR ;Group Code Rcrding 6250bpi (TU81,81+) .BYTE 0 ; (future) .BYTE 0 ; (future) .BYTE 0 ; (future) .BYTE 0 ; (future) .EVEN .IFT ;NE MMG$T .IF NE MU$FSM ;If file-structured .SBTTL H$NQE - High Memory Copy of Queue Element ;+ ; H$NQE - High Memory Copy of Queue Element ; ; (FSM communicates with the hardware part of the handler, via a fake queue ; element, NQE, located in FSM.) ; ; For MAGTAPE, H$CQE is not just a high memory copy of UMCQE. Rather it ; points to this high memory copy of the queue element. This is to handle ; the case where the handler (and FSM) are .FETCH'ed into PAR1 space in ; low memory. When this happens, FSM's fake queue element is, unfortunately, ; located in PAR1 space in low memory, which we map away to get to the high ; memory portion of the handler (.PSECT UMX). We must therefore copy the ; queue element up to high memory, and be a bit cautious how we access it. ;- H$NQ.CS:.WORD 0 ;CSW pointer H$NQE: .WORD 0 ;Block number (or -> ERRBLK) .BYTE 0,0 ;Function (low), Unit & Job #'s (high) .WORD 0 ;Buffer address .WORD 0 ;Word Count .WORD 0 ;Completion routine code .WORD 0 ;PAR1 relocation bias for DMA address .WORD 0 ;PAR1 relocation bias, non-DMA .WORD 0 ; H$NQND= . .ENDC ;NE MU$FSM .SBTTL CVPHYS - Convert Buffer Virtual Address to Physical ;+ ; CVPHYS ; ; The buffer address in the current queue element is converted from a virtual ; address to a physical one and stored in OLDBA (low 16 bits) and EXTADR (high ; bits). ; ; Input: ; R5 -> Current queue element (Q.BLKN word) ; ; Output: ; R5 -> Current queue element (Q.BLKN word) ; R3 = Destroyed ; OLDBA = Low 16 bits of physical address. ; EXTADR = High bits of physical address. ;- ;********************************************************************* UMPSECT ;********************************************************************* CVPHYS: CMP (R5)+,(R5)+ ;R5 -> Q$BUFF .ASSUME Q$BUFF EQ 4 CALL @$MPPTR ;Convert virtual to physical MOV (SP)+,OLDBA ;Save the low 16 bits of address MOV (SP)+,R3 ;Get the high bits of address ASH #-4,R3 ;Shift high bits into right place MOV R3,EXTADR ;Save the high bits SUB #Q$WCNT,R5 ;Backup queue element pointer RETURN ;Done .ENDC ;NE MMG$T .SBTTL MUBEGN - MU Specific Begin Code ;+ ; MUBEGN ; ; This code is JMP'ed to from the handler BEGIN code and handles magtape ; specifics. If this is a file-structured magtape handler, we transfer ; control to the file-structured module (FSM) to allow it to interrogate ; the queue element and decide if the command is a file operation that ; it must process. If this is an XM system, we copy the queue element ; to high memory, as it may reside in PAR1, which makes it difficult to ; access. Note that in XM, if the handler was .FETCHed into PAR1, then ; any fake queue elements passed to the handler from FSM are guaranteed ; to be in PAR1. ; ; Call: ; CALLR MUBEGN with R5 -> queue element ; ; Return: ; CALLR BEGN01 ;BEGN01 is in high memory in XM ;- .IF NE MMG$T ;********************************************************************* UMXPSECT ;********************************************************************* .IFF ;NE MMG$T ;********************************************************************* .PSECT UMLCOD ;********************************************************************* .ENDC ;NE MMG$T .ENABL LSB MUBEGN: .IF EQ MU$FSM ;If not file structured .ASSUME Q$BLKN EQ 0 MOV R5,R3 ;Get address of block number in R3 .IFF ;EQ MU$FSM ;If file structured RET2LO FSMDIS ;Jump to the file structured module ;will jump back to $MT:: ;********************************************************************* UMPSECT ;********************************************************************* .ENDC ;EQ MU$FSM $MT:: .IF NE MMG$T ;If XM MOVB Q$JNUM(R3),R5 ;Get job number BIC #^C,R5 ; ASR R5 ;Shift ASR R5 ; into ASR R5 ; place .IF NE MU$FSM ;If file structured magtape MOV R5,JOBNM ;Store it in .SYNCH block for errors .IFF ;NE MU$FSM MOV R5,@#JOBNM ;Store it in .SYNCH block for errors $REL .-2 JOBNM UMR .ENDC ;NE MU$FSM MOV R3,R5 ;Restore R5 -> queue element .IF NE MU$FSM ;If file structured magtape TST -(R3) ;-> CSW pointer (don't need link word) MOV #,R1 ;Count of words to move 10$: MOV (R3)+,-(SP) ;Save queue element on the stack SOB R1,10$ ;In case we're .FETCHed into PAR1 .IFTF ;NE MU$FSM MOVB Q$UNIT(R5),R3 ;Get the unit number. .IFT ;NE MU$FSM LOW2HI H$MT,PSECT=YES ;Go to hi memory handler start H$MT:: MOV #H$NQND,R5 ;R5 -> hi memory copy of queue element $REL .-2 H$NQND UMX ; ... MOV #,R1 ;Copy all but link word of q element 20$: MOV (SP)+,-(R5) ;Copy queue element from stack SOB R1,20$ ; TST (R5)+ ;R5 -> Block number in queue element .ENDC ;NE MU$FSM MOV R5,H$CQE ;H$CQE -> hi mem copy of queue element .IFF ;NE MMG$T ;If not XM .IF NE MU$FSM ;If file structured MOV R3,R5 ;Fix register usage .ENDC ;NE MU$FSM MOVB Q$UNIT(R5),R3 ;Get the unit number. .ENDC ;NE MMG$T BIC #^C,R3 ;Isolate the unit number. .IF EQ MU$FSM ; FSM already did unit check .IF GT MU$UN-1 CMP R3,#UM$UNITS-1 ;Is it a valid unit number? BHI 30$ ;Branch if not, exit. .IFF; GT MU$UN-1 BNE 30$ ;Error if unit no. NE 0 .ENDC; GT MU$UN-1 .ENDC; EQ MU$FSM MOV R3,-(SP) ;save unit on stack ASL (SP) .ADDR #DNTAB,@SP,ADD ;(SP) = addr of unit's entry in DNTAB MOV (SP)+,.DNTAB ;Store it in .DNTAB for later CLR BCKTM ;Clear 'backspace tape mark' CLR LASCOM ; and 'last command' for internal ops CALLR BEGN01 ;Back to the common begin code 30$: .IF EQ MU$FSM CMPB Q$FUNC(R5),#LOOK.. ;Invalid unit on LOOKUP? BNE 40$ ;no. some other function. MOV #ER.IUN,R0 ;Code = Invalid Unit JMP SPERR ;Exit to USR with SPUSR set 40$: .ENDC; EQ MU$FSM CALLR UMHERR ;Invalid unit number, hard error. .DSABL LSB .SBTTL ISETUC - Internal Set Unit Characteristics (Caching / Set Density) ;+ ; ISETUC ; Called from the successful completion of a GET UNIT STATUS command. ; Takes responsibility for the GUS's GETNEXT ; ; We check if the desired unit supports caching and if so, issue an ; internal SET UNIT CHARACTERISTICS command to enable write-back ; caching. ; ; If the unit supports multiple densities, we check if the user has ; specified a density for this unit via the SET MUn DENSE=n command ; and verify that the particular unit supports the desired density. ; If it does, we select it and issue the SET UNIT CHARACTERISTICS ; command. If it does not, we use the unit's default density. ; ; NOTE: This area (enabling caching) must be re-worked if future TMSCP ; controllers are developed which handle multiple units (none as yet) ; where one unit supports caching and another does not. ; Input: ; R1 -> End message for GET UNIT STATUS command ; R2 -> tail pointer associated with the end message ; R3 -> port control table entry for the port with the end message ; .DNTAB -> Density code byte, this unit (in DNTAB) ; ; Output: ; R1 -> End message for GET UNIT STATUS command ; R4 -> Command buffer ; R5 = Destroyed ; DNTAB = DN.SET bit cleared in DNTAB entry for this unit. ;- ISETUC: MOV #-1,INTEOP ;Indicate Internal Op in progress MSCP OP.SUC ;Select SET UNIT CHARACTERISTICS cmnd BICB #DN.SET,@.DNTAB ;Clear 'set density' flag if it's set .ASSUME DN.DEN EQ 0 MOVB @.DNTAB,R5 ;R5 = density code byte, this unit .ADDR #DENBIT,R5,ADD ;R5 -> desired density, this unit BITB @R5,P.FMEN(R1) ;Does this unit support this density? BEQ 10$ ;No, just use default. MOVB @R5,P.FORM(R4) ;Yes, set density: FORMAT lo byte, MOVB P.FMEN+1(R1),P.FORM+1(R4) ; & media type: FORMAT hi byte 10$: ;we must call GETNEXT to return the descriptor to the controller MOV R4,-(SP) ;must set up R3, R4, R5 for GETNEXT MOV R5,-(SP) MOV R2,R4 ;R4 -> UQSSP ring MOV R1,R5 ;R5 -> buffer CALL GETNEXT MOV (SP)+,R5 MOV (SP)+,R4 .BR CASHIT ;Go enable write-back, if supported .SBTTL CASHIT - Setup Write-Back Caching if Unit Supports it. ;+ ; CASHIT ; ; Called from the ONLINE routine. If the cache flag bit in the density ; table entry for this unit is set, we enable write-back caching on the ; unit. This bit gets cleared if the unit becomes OFFLINE or AVAILABLE, ; so we always reset it when going online. ; ; Also branched to from the ISETUC routine to set caching bits and/or ; to select unit density prior to issuing a SET UNIT CHARACTERISTICS ; command. ; ; Input: ; R4 -> Command buffer ; ; Output: ; R4 -> Command buffer ; R5 -> current DNTAB entry ; ;- .ENABL LSB CASHIT: MOV .DNTAB,R5 ;R5 -> current DNTAB entry BITB #DN.CAC,DN.FLG(R5) ;Does unit support caching? BEQ 10$ ;If EQ, no BIS #UF.WBN,P.UNFL(R4) ;Set flags bit to enable 'Write-back' 10$: RETURN ;Done .DSABL LSB .SBTTL CKABRT - Check if Abort in Progress ;+ ; CKABRT ; ; This routine is called from interrupt level (from the INTEX subroutine) to ; see if there is an abort in progress on magtape. It updates the expected ; interrupt count, since we just got one, and then checks if we are aborting ; and if there are any more interrupts expected. There can be two outstanding: ; one from the end message of the TMSCP ABORT command, and one from the end ; message of the command which was aborted. These can arrive in any order. ; If one is still expected, we reset the ownership bits of the port's reply ; buffer so that the outstanding message always has a buffer available. ; ; Input: (Called directly from interrupt service routine) ; R4 -> appropriate entry in the port control table ; ; Output: ; R5 = 0 -> Nothing going on, do normal .FORK to service interrupt. ; > 0 -> Abort sequence finished, do a .DRFIN to release q-element. ; < 0 -> Abort sequence not finished, just RETURN and wait for last ; interrupt resulting from the abort. ;- .ENABL LSB CKABRT: MOV R3,-(SP) MOV R4,-(SP) CLR R5 ;Init the return value INC INTEXP ;Decr expected interrupt count, got 1 BGT 20$ ;If GT, 4-step init, get out, no abort MOV ABTFLG,R5 ;Aborting? BEQ 30$ ;No ;call GETNEXT insure port has a reply buffer. MOV R5,-(SP) MOV R4,R3 ;R3 -> Port control table .IF EQ MU$ERL-2 MOV PC.BUF(R3),R5 MOV PC.ADR(R3),R4 .IFF ;EQ MU$ERL-2 MOV #MBUFF0,R5 $REL .-2 MBUFF0 UMX MOV #VADR0,R4 $REL .-2 VADR0 UMX .IFT ;EQ MU$ERL-2 MOV MSGTYP(R5),-(SP) ;if it is a datagram, do not let is BIC #^c,(SP)+ ;affect the abort sequence BEQ 5$ ;branch if it is an end message CLR R5 BR 30$ .ENDC ;EQ MU$ERL-2 5$: CALL GETNEXT MOV (SP)+,R5 MOV INTEXP,R5 ;Yes, any more interrupts expected? BMI 30$ ;Branch if yes, nxt intrpt will .DRFIN ; so just return. 10$: INC R5 ;R5 > 0 to flag finished abort 20$: CLR ABTFLG ;Abort done, clear flag, do .DRFIN 30$: MOV (SP)+,R4 MOV (SP)+,R3 RETURN ;Done .DSABL LSB .SBTTL CDLCK - Check for Cached Data Lost End Flag ;+ ; CDLCK ; ; Called from the interrupt service routine to check if the Cached Data Lost ; End Flag was set in the response message of the last command. If so, we set ; a flag in the flags byte of the density table entry for this unit so that ; the next command issued on this unit will clear Cached Data Lost. We also ; clear the BCKTM and LASCOM flags which are used in error checking/recovery. ; ; Input: ; R5 -> Response buffer for last command ; ; Output: ; R4 -> Density table entry for current unit ; R5 = unchanged ; BCKTM = cleared ; LASCOM = cleared ;- CDLCK: CLR BCKTM ;Clear 'backspace tape mark' flag. CLR LASCOM ;Clear 'last command' (saved value) MOV .DNTAB,R4 ;R4 -> density table BITB #EF.DLS,P.FLGS(R5) ;Did we lose cached data? BEQ 10$ ;No, just go on BISB #DN.CDL,DN.FLG(R4) ;Next command must clr cache data lost 10$: RETURN ;Done .SBTTL CASHCK - Check Tape Caching Support / Enhanced Write Error Recovery ;+ ; CASHCK - Check Magtape Caching / Enhanced Write Error Recovery ; ; On entry, we are called from a successful ONLINE command. We must ; issue a GET UNIT STATUS command and then check the unit flags and ; (later) the format menu in the end message. ; ; If caching is supported, we issue a SET UNIT CHARACTERISTICS ; command to enable write-back caching for this unit. ; ; If Enhanced Write Error Recovery is supported, we set a bit in ; the unit table entry so that WRITE commands issued to this unit ; will set the Enable Re-write Error Recovery modifier (MD.ERW). ;- CASHCK: DO IGETUS,THEN,CKFEAT ;Issue GET UNIT STATUS ;a call to GETNEXT is needed, but we ;wait because we need to pass the ;packet to ISETUC CKFEAT: MOV .DNTAB,R1 ;R5 -> current DNTAB entry .IF NE MU$EWR ;If enhanced write error recovery MOV P.UNFL(R5),-(SP) ;Get unit flags from GUS end msg BIT #UF.EWR,@SP ;Enhanced write err recovery support? BEQ 10$ ;If EQ, nope BISB #DN.EWR,DN.FLG(R1) ;Yup, set bit in unit's flag byte 10$: TST (SP)+ ;Write back caching support? .IFF ;NE MU$EWR TST P.UNFL(R5) ;Write back caching support? .ENDC ;NE MU$EWR BPL 20$ ;If PL, nope .ASSUME UF.CAC EQ 100000 BISB #DN.CAC,DN.FLG(R1) ;Yup, set caching bit in flag byte 20$: MOV R5,R1 ;make R3,R2,R1 = the R3,R4,R5 needed MOV R4,R2 ;for the CALL GETNEXT we must do for ;the previous occurrence of the do ;macro. DO ISETUC,THEN,30$ ;Go issue SET UNIT CHARACTERISTICS ; to enable write-back, and maybe 30$: CALL GETNEXT CALLR DISPAT .SBTTL MUGCBF - Magtape Specific Setup for GETCBF Routine ;+ ; MUGCBF ; ; Handles magtape specifics for GETCBF. Saves current command reference ; number for use in abort, sets the 'Clear Serious Exception' modifier and ; /or the 'Clear Cached Data Lost' modifier for the command (if previous ; command caused a serious exception or lost cached data), and sets the ; virtual circuit id to show that we are talking to a magtape. ; ; NOTE: 'Clear Cached Data Lost' and 'Clear Serious Exception' are not set ; if the command is 'GET UNIT STATUS', 'ABORT', or 'SET CONTROLLER ; CHARACTERISTICS' as they are illegal modifiers for these commands. ; ; Input: ; R4 -> Command buffer ; R5 -> Op Code for Command ; .DNTAB -> DNTAB entry for current unit (w/flags to say if we must clr ; serious exception or cached data lost.) ; ; Output: ; R4 Unchanged ; R5 Unchanged ;- MUGCBF: CMP @R5,#OP.GUS ;MD.CSE/CDL illegal if GET UNIT STATUS BEQ 30$ ; so don't do it CMP @R5,#OP.ABO ;MD.CSE/CDL illegal if ABORT BEQ 30$ ; so don't do it CMP @R5,#OP.SCC ;MD.CSE/CDL illegal if SET CTRLR CHAR BEQ 30$ ; so don't do it MOV R5,-(SP) ;Save R5 MOV .DNTAB,R5 ;R5 -> current DNTAB entry INC R5 ; (the flags byte...) .ASSUME DN.FLG EQ 1 BITB #DN.CDL,@R5 ;Must we Clear Cached Data Lost flag? BEQ 10$ ;No BIS #MD.CDL,P.MOD(R4) ;Yes, set Clear CDL command modifier 10$: BITB #DN.CSE,@R5 ;Must we Clear Serious Exception flag? BEQ 20$ ;No BIS #MD.CSE,P.MOD(R4) ;Yes, set Clear SE command modifier 20$: BICB #DN.CDL!DN.CSE,@R5 ; (only need to clear them once.) MOV (SP)+,R5 ;Restore R5 30$: MOV #,(R4) ;Put Tape ID in envelope .ASSUME VC.CMD EQ CBUFF0-2 RETURN ;Done .SBTTL USRFN - Dispatch for USR Functions ;+ ; USRFN - Control comes here from the common code, when it has been determined ; that the function is positive, non-zero (i.e. a USR function). ; ; R5 -> Current queue element ; R4 = Function (Q$FUNC) ; .UTTAB -> Unit Translation Table entry for this unit ;- .ENABL LSB USRFN: MOVB Q$JNUM(R5),R2 ;Get job # and unit # BIC #^C,R2 ;We only want the job # bits MOV .UTTAB,R3 ;R3 -> Unit translation table entry ADD #UT.JOB,R3 ;R3 -> job # of owner of this unit. CMPB #LOOK..,R4 ;Is function .LOOKUP? BNE 40$ ;No, it's an illegal code, give error. ; It's a .LOOKUP, check if Non-File-Structured (NFS). .IF EQ MU$FSM ;If not file structured .IF NE MMG$T ;If XM MOV H$CQE,R4 ;Get real queue element CALL @H$GTBYT ;Get half of file name TSTB (SP)+ ;NFS .Lookup? BNE 30$ ;If NE, Error, for HH, must be NFS CALL @H$GTBYT ;Get second half TSTB (SP)+ ;NFS .Lookup? BNE 30$ ;Not NFS and must be for HH .IFF ;NE MMG$T ;If not XM TST @Q$BUFF(R5) ;Is there something in Q.BUFF? BNE 40$ ;Yes: not NFS .Lookup & must be for HH .ENDC ;NE MMG$T .ENDC ;EQ MU$FSM MOVB @R3,-(SP) ;Get job owner bits for this unit BICB #^C,(SP) ;Clear extraneous bits CMPB (SP)+,#UT.AVAL ;Unit available? BEQ 10$ ;Yes, go mark it ours MOV #ER.SHR,R0 ;No, device in use. SPERR: MOV @#$SYPTR,R1 ;Point to RMON MOV R0,$SPUSR(R1) ;Return error .IF NE MU$FSM ;If file structured magtape .IF NE MMG$T MOV #$DONE,-(SP) ;Immediate abort after RESTOR $REL .-2 $DONE UMR ; ... .IFF ;NE MMG$T .ADDR #$DONE,-(SP) ;Immediate abort after RESTOR .ENDC ;NE MMG$T RET2LO RESTOR ;To low mem to restore CPU state .IFF ;NE MU$FSM ;If hardware handler only BR 50$ ;JMP MTDONE .ENDC ;NE MU$FSM 10$: CLR Q$WCNT(R5) ;For HH, zero word count to say NFS BICB #JOBMK,@R3 ;Clear avail bits in unit trans table BISB R2,@R3 ; and set Job# bits to mark unit taken .IF NE MU$FSM ;If file structured BR 50$ ;Let FSM tell us what's next .IFF ;NE MU$FSM ;If not file structured 20$: MOV @R5,R1 ;Get seq # .ASSUME Q$BLKN EQ 0 BEQ 60$ ;0 gets a REWIND BGT 30$ ;PLUS is an Invalid Argument error INC R1 ;Is sequence number = -1? BEQ 50$ ;Yes, no rewind, all done 30$: BISB #UT.AVAL,@R3 ;Mark unit available MOV #ER.ISN,R0 ;Code for Invalid Seq. No. BR SPERR ;Go issue error .ENDC ;NE MU$FSM KLOSE: BISB #UT.AVAL,UT.JOB(R3) ;CLOSE function: mark unit available BR 50$ ;And finish up ;+ ; Issue Hard Error. If file support is present, then R0-R3 must be ; restored because we may be running at .INTEN level. ;- 40$: BIS #HDERR$,@-(R5) ;Set hard error bit in CSW word FNDISP: ;(Come here to ignore TS05 .SPFUN) 50$: .IF NE MU$FSM ;If file structured CLR R4 ;No exception codes .IF NE MMG$T MOV #FSMDON,-(SP) ;Tell FSM we are done (after RESTOR) $REL .-2 FSMDON UMR ;(FSM returns to $DONE when it's done) .IFF ;NE MMG$T .ADDR #FSMDON,-(SP) ;Tell FSM we are done (after RESTOR) .ENDC ;NE MMG$T RET2LO RESTOR ;Restore CPU state .IFF ;NE MU$FSM ;If hardware handler RET2LO $DONE ;Lets go home .ENDC ;NE MU$FSM RERWRT: GETCQE R5 ;R5 -> current queue element BR RWRT1 ;Redo the Q$FUNC .IF EQ MU$FSM 60$: MOVB #SF.MRE,R4 ;Do Rewind & fix q element so if err, MOVB R4,Q$FUNC(R5) ; port re-INIT won't retry .LOOKUP! .BR RWRT ;Go to it .ENDC ;EQ MU$FSM .SBTTL RWRT - Handle READ/WRITE and Most .SPFUNs ;+ ; RWRT - Handle READ/WRITE and most .SPFUNs ; RWRT1 - Redo function for some error cases (entry from interrupt service) ; ; The following routine validates the queue element code. ; ; -1 >= R4 >= -8 Code is a legal .SPFUN ; R4 =0 It's .READ/.WRITE, and is converted to .SPFUN read or write ; based on the sign of the word count (+ = read). ; else Illegal function code: hard error is issued ;- RWRT: MOV R4,(PC)+ LASCOM: .WORD 0 ;Last command stored here RWRT1: MOV LASCOM,R4 ;Get the command CMPB #SF.MRD,R4 ;Is the function legal? BLOS 90$ ;If LOS, yes TST R4 ;.READ or .WRITE? BNE 40$ ;If NE, no ;+ ; Convert to proper format for .READ and .WRITE ;- MOVB #SF.MRD,R4 ;Assume .READ .ASSUME Q$BLKN EQ 0 CLR (R5) ;0->Q$BLKN (ERRBLK),NO error reporting TST Q$WCNT(R5) ;.READ? BPL 70$ ;Branch if yes NEG Q$WCNT(R5) ;Make count positive INC R4 ;Change code to write .ASSUME SF.MWR EQ SF.MRD+1 BR 80$ ;Skip next 70$: COM NFSREAD ;Say non-file-structrd READ being done 80$: MOV R4,LASCOM ;Store function we do (for retry) ;stuff the CODE, which is an FSM loc. .IF NE MU$FSM ;If file structured handler .IF EQ MMG$T MOV R4,CODE ;Save code of new request .IFF ;EQ MMG$T .HP1EX P1LOW ; (Map to low memory) MOV R4,@#CODE ;Save code of new request $REL .-2 CODE UMR ; ... .HP1EN ; (Mark end of block) .ENDC ;EQ MMG$T .ENDC ;NE MU$FSM 90$: ADD #FUNTAB-TABLE,R4 ;Make the code positive MOV Q$WCNT(R5),R1 ;Get word count CALL DISPCH ;Go jump to proper routine .BR TABLE ; (TABLE must be next: return addr on ; stack used as pointer into tables) .DSABL LSB ;+ ; The next two tables must be kept in order so that the following routines ; will be found properly. ;- TABLE: .BYTE REDEF-NULLFN ;Address of read routine .BYTE WRIT-NULLFN ;Address of write routine .BYTE OFFLN-NULLFN ;Address of rewind/offline .BYTE RWND-NULLFN ;Address of rewind .BYTE WRIT-NULLFN ;374 write-gap treated as write .BYTE BCKSPC-NULLFN ;Address of backspace routine .BYTE FRSPC1-NULLFN ;Address of forward space .BYTE WRITM-NULLFN ;Address of tape mark routine FUNTAB: .BYTE OP.RD ;Read .BYTE OP.WR ;Write .BYTE OP.AVL ;Rewind & Offline, available & unload .BYTE OP.REP ;Rewind, reposition & rewind .BYTE OP.WR ;Write gap is treated as Write .BYTE OP.REP ;Backspace, reposition and reverse .BYTE OP.REP ;Forward space, reposition .BYTE OP.WTM ;Write tapemark .EVEN .SBTTL DISPCH - Dispatcher Routine ;+ ; DISPCH ; ; This routine uses the special function code, which has been translated to a ; positive number (0-7) as a byte offset into two tables. The first (TABLE) is ; the address of a routine to do function specific setup, like word count to ; byte count adjustment for read/write. The second table (FUNTAB) is the TMSCP ; command which the RT-11 special function translates into (SF.MWR->OP.WR). ; ; For example, if the special function is a rewind, on entry, the rewind code ; (373 or -5) has been converted to a positive offset (3) into the tables. The ; table entries for this value are 'RWND-NULLFN' (the rewind specific routine ; which sets the rewind bit in the TMSCP command buffer), and 'OP.REP' (the ; TMSCP command for Reposition, which, with the rewind bit set, will cause the ; tape to rewind to BOT). The equivalent inline code, would be: ; ; MSCP OP.REP ; DO RWND,THEN,MUDONE ; Input: ; R4 = positive byte offset for the desired function ; (SPFUNS 370-377 have been converted to offsets 0-10) ; (SP) = Address of TABLE ;- DISPCH: MOVB R4,MCODE ;Save for MUINIT later ADD (SP)+,R4 ;Add addr of TABLE to function offset MOVB @R4,NULLFN ;Store address of function specific ; routine for 'DO' macro MOVB FUNTAB-TABLE(R4),WHAT ;Store command for TMSCP buffer setup JSR R5,GETCBF ;Equivalent to: MSCP OP.xxx WHAT: .WORD 0 ; TMSCP funct from FUNTAB (eg: OP.WRT) .WORD USR.IO ; the command type arg. to GETCBF MOV R4,R2 ;COORD uses R4, so save it in R2! CLR BCKTM ;Init internal Backup Tape Mark flag MUDO: DO NULLFN,THEN,MUDONE ;Becomes, e.g.: DO WRIT,then,MUDONE NULLFN =: .-2 ; or, DO BCKSPC,then,MUDONE .ASSUME NULLFN EQ MUDO+6 .SBTTL xxxx - Final Setup Routines for Specific I/O Operations ; *Write/Read* .ENABL LSB WRIT: ;*Write* .IF NE MU$EWR ;If enhanced write error recovery MOV .DNTAB,R5 ;R5 -> current DNTAB entry BITB #DN.EWR,DN.FLG(R5) ;Enhanced write err recovery support? BEQ REDEF ;No BIS #MD.ERW,P.MOD(R2) ;Yes, enable re-write error recovery. .ENDC ;NE MU$EWR REDEF: ASL R1 ;*Read* make word count -> byte count .IF EQ MMG$T MOV OLDBA,P.BUFF(R2) ;Fill in low 16 bits of buffer address .IFF ;EQ MMG$T ;If XM .HP1EX P1LOW ; (Map to low memory) MOV @#OLDBA,R4 ;Get low 16 bits of buffer address $REL .-2 OLDBA UMR ; ... MOV @#EXTADR,R5 ;Get high bits $REL .-2 EXTADR UMR ; ... .HP1EN ; (Mark end of block) MOV R4,P.BUFF(R2) ;Fill in low 16 bits of buffer address MOV R5,P.BUFF+2(R2) ;Fill in high bits .ENDC ;EQ MMG$T BR FRSPC ;CONDITIONAL CODE ON P.BCNT EQ P.RECC ;REMOVED. ;POSSIBLE MODIFICATION OF 2 * WCNT ;IN R1 ELIMINATED. ; *Backspace* BCKSPC: BIS #MD.REV,P.MOD(R2) ;Reverse mode FRSPC1: INC R1 ;Is this the -1 from FSM? (=backup TM) BNE 20$ ;If NE, no INC R1 ;Make R1 = 1 (so 0 stored in P.RECC) MOV R1,P.TMGC(R2) ;Say 'backup 1 tape mark' COM (PC)+ ;Set backup tape mark flag BCKTM: .WORD 0 ; -1 => backup tape mark issued 20$: DEC R1 ;Get 'correct' value back .BR FRSPC ; *Forward space* FRSPC: MOV R1,P.RECC(R2) ;# records to space (or bytes to r/w) BR FNSHUP ;BGE CHANGED TO BR. ;POSSIBLE MODIFICATION OF 2 * WCNT ;IN R1 ELIMINATED. ; *Offline* OFFLN: BIS #MD.UNL,P.MOD(R2) ;Available Command + Unload modifier BR FNSHUP ;Finish up then do command ; *Rewind* / *Write tapemark* RWND: BIS #MD.RWD,P.MOD(R2) ;*Rewind* Set rewind mode BISB #DN.SET,@.DNTAB ;Flag = @ BOT: set density, next cmd .ASSUME DN.DEN EQ 0 WRITM: ;*Write tapemark* FNSHUP: MOV R2,R4 ;POLL expects R4 -> cmd buffer MOV P.RECC(R2),(PC)+ ;Save count for space/read functs RBCNT: .WORD 0 ; # Records/Bytes (space/read functs) .ASSUME P.RECC EQ P.BCNT RETURN ;Return, POLL routine starts command. .DSABL LSB .SBTTL UM$ABO - Abort Entry Point ;+ ; UM$ABO - Abort entry point. ; This code halts any operation in progress and updates the inuse table. ; It sets flags to keep track of whether abort is in progress, and ; whether there is an outstanding command that must be aborted. These ; are needed so that when the response messages from the outstanding ; command and the abort command cause interrupts, we can keep track of ; when to release the queue element, and we don't return it twice. Like- ; wise, the code checks whether this is a second call to the abort ; entry point (either for this job or for another job) and insures that ; the interrupt counting doesn't get screwed up. ; ; This routine is one of the places where we rely on the assumption that ; there can only be one TMSCP unit per TMSCP controller. ;- .ENABL LSB UM$ABO: CLR BCKTM ;0->backspace tape mark interrupt flag CLR -(SP) ;stack flag: 0 = nothing to abort .IF NE MMG$T ;If XM .HP1EX P1LOW ; (Map to low memory) MOV @#UMCQE,R5 ;R5 -> current queue element, if any. $REL .-2 UMCQE UMR ; ... .HP1EN ; (End of block) TST R5 ;Is there a current queue element? BEQ 20$ ;If EQ no active q element MOV H$CQE,R5 ;Yes there is, R5 -> Hi copy of CQE. .IFF ;NE MMG$T ; MOV UMCQE,R5 ;R5 -> current queue element, if any. BEQ 20$ ;If EQ no active q element .ENDC ;NE MMG$T MOVB Q$JNUM(R5),R5 ;Now get job # BIC #^C,R5 ;Clear some bits ASR R5 ;Shift ASR R5 ; into ASR R5 ; place CMP R5,R4 ;Is aborting job active? BNE 20$ ;If NE, no .IF NE MU$FSM ;If file structured .IF EQ MMG$T ;If not XM MOV DVTBL,R5 ;Point to device table .IFF ;EQ MMG$T ;If XM .HP1EX P1LOW ; (Map to low memory) MOV @#DVTBL,R5 ;Point to device table $REL .-2 DVTBL UMR ; ... .IFTF ;EQ MMG$T BEQ 10$ ;If EQ, not initialized yet MOV #-1,@R5 ;Mark tape position lost MOV (R5)+,@R5 ;Mark current block number lost 10$: .IFF ;EQ MMG$T ;If XM .HP1EN ; (End of block) .ENDC ;EQ MMG$T .ENDC ;NE MU$FSM TST ABTFLG ;Abort flag already set? (2nd call?) BNE 50$ ;If NE, yes, nothing much to do... INC @SP ;No, set stack flag => got to abort MOV #-1,(PC)+ ;Set flag to abort current command ABTFLG: .WORD 0 ; -1 => abort current command .IF EQ UM$PORTS-1 .HP1EX P1LOW ; execute following out of PAR1 CLR @#UMFBL0+2 ; cancel pending FORK routine $REL .-2 UMFBL0+2 UMR .HP1EN .IFF; UM$PORTS-1 .ASSUME UM$UNI EQ UM$POR MOV @.UTTAB,R5 ; get aborting port CMP R5,#UM$PORTS ; is it valid for handler? BHIS 16$ ; branch if not. .ASSUME FKBKLN EQ 8. ASL R5 ; make word offset ASL R5 ; 2-word offset ASL R5 ; 4-word offset ADD #,R5 ; point to 2nd word in FORK block $REL .-2 UMFBL0+2 UMR .HP1EX P1LOW ; execute following out of PAR1 CLR @R5 ; cancel pending FORK routine .HP1EN 16$: .ENDC; EQ UM$PORTS-1 20$: MOV #,R5 ;Get unit table (flag/job owner byte) $REL .-2 UTTAB+UT.JOB UMX ;$REL knows if we are in XM or not MOV R5,-(SP) ;Put address of ADD #UTTBND-UTTAB-UT.JOB,@SP ; table end on stack 30$: MOVB (R5),-(SP) ;Get job# byte for this unit # BIC #^C,(SP) ;Isolate job # bits ASR @SP ; shift ASR @SP ; into ASR @SP ; place CMPB R4,(SP)+ ;Does this unit belong to this job? BNE 40$ ;Branch if no BISB #UT.AVAL,(R5) ;Mark unit unbusy (all job bits=1) 40$: ADD #UT.ESZ,R5 ;Get next entry CMP R5,@SP ;End of table? BLO 30$ ;Branch if no TST (SP)+ ;Pop stk junk 50$: TST (SP)+ ;Check stack flag, must we abort? BEQ 60$ ;If EQ, nope ADD ABTFLG,INTEXP ;Abort last cmd? (Must be 1 instr.!!) BCC ABRTND ;If CC, no need, or it's already done. BPL ABRTN1 ;If PL, doing port init, no need. DO ABRT,THEN,UMEXIT ;Go abort it, then return to RMON. ;(UMEXIT won't be executed at @NEXT: a ; .DRFIN will be done after .DRAST) ABRTND: ;do a GETNEXT to make sure the ring is free ;we use the port number to build the arguments to GETNEXT MOV R3,-(SP) MOV @.UTTAB,R3 ASL R3 .IF NE UM$ERL-2 .ASSUME PC.ESZ EQ 12 MOV R3,-(SP) ASL R3 ASL R3 ADD (SP)+,R3 .IFF .ASSUME PC.ESZ EQ 40 ASL R3 ASL R3 ASL R3 ASL R3 .IFTF ADD #PCTAB,R3 ;R3 -> port control table entry $REL .-2 PCTAB UMX .IFT MOV #MBUFF0,R5 ;R5 -> buffer of end message $REL .-2 MBUFF0 UMX MOV #VADR0,R4 ;R4 -> UQSSP ring $REL .-2 VADR0 UMX .IFF MOV PC.BUF(R3),R5 ;R5 -> buffer of end message MOV PC.ADR(R3),R4 ;R4 -> UQSSP ring .ENDC CALL GETNEXT MOV (SP)+,R3 ABRTN1: CLR INTEXP ;Clear count of interrupts expected. .IF EQ MMG$T ;If not XM 60$: RETURN ;Just return .IFF ;EQ MMG$T 60$: CALLR HRET ;Just return (back to low before RTS) .ENDC ;EQ MMG$T .SBTTL ABRT - Abort An Outstanding Command ;+ ; ABRT - There's an outstanding command to be aborted. ; ; We must wait until the command descriptor slot is returned to us, and ; then issue the abort command. In general the descriptor should always ; be free, but protocol dictates we check. We return to a different part ; of the POLL routine (ABPOLL), since we've already adjusted INTEXP. ; ; NOTE ; ; Problem w/serious exception status handling: Interrupt processing does ; not check status of ABORTed commands. If the Serious Exception FLAG is ; set in an ABORTed command's end message, we won't see it. Next command ; will fail w/ Serious Exception STATUS. (Often, a 'MON-F-Dir I/O error' ; occurs.) So, what we do is set DN.CSE flag in density table flag byte ; (.DNTAB -> entry for this unit) so the next command issued for this ; unit will clear the serious exception flag. (A problem still exists if ; the ABORTed command has Cached Data Lost flag set, but this is less ; common, and more difficult to fix, since you can't clear CDL if it is ; not set: you get an error if you try it...) ;- ABRT: TST CRNG0+2 ;Can we use the command buffer? BMI ABRT ;If MI, no, wait till it's available MOV CUROPT,-(SP) ;Get last command ref number for abort MOV CUROPT+2,-(SP) MSCP OP.ABO ;Get ABORT command MOV (SP)+,P.OTRF+2(R4) ;Outstanding command number MOV (SP)+,P.OTRF(R4) ;Outstanding command number MOV .DNTAB,-(SP) ;(SP) -> current DNTAB entry INC (SP) ; (the flags byte...) .ASSUME DN.FLG EQ 1 BISB #DN.CSE,@(SP)+ ;Clear Serious Exception, next cmd. ADD #ABPOLL-POLL,@SP ;Special entry to POLL for Abort cmd. RETURN ;Return, POLL will get it started. CUROPT: .WORD 0 .WORD 0 .DSABL LSB .SBTTL UMERR - Handle Interrupt Level Errors ;+ ; UMERR - Handle interrupt level errors. ; ; The interrupt entry point will transfer control here if there is an ; error of some kind that it cannot fix by doing an ONLINE. ; ; R1 = P.STS of command masked to only major status bits (37) ; ; NOTE: R1 may be ZERO, in which case we could be doing an internal back ; tape mark and it succeeded, or, it's a READ function, and the ; byte counts requested and transferred are not equal. We'll catch ; these at the individual command specific routines, below. ;- .ENABL LSB UMERR: MOV .DNTAB,R4 CMPB #OP.END!OP.ONL,P.OPCD(R5) ;Was it an Online command? BEQ 20$ ;Yes, say unit is unavailable. CMPB #ST.OFL,R1 ;Is status = offline? BEQ 40$ ;Yes CMPB #ST.POL,R1 ;Position Lost? (Status return) BEQ 41$ ;Yes CMPB #ST.SEX,R1 ;Serious Exception (status return)? BEQ 30$ ;Yes CMPB #ST.CMD,R1 ;Invalid Command? BEQ 30$ ;Yes .ASSUME ST.HST EQ ST.DAT+1 ;Check .ASSUME ST.CNT EQ ST.HST+1 ; these .ASSUME ST.DRV EQ ST.CNT+1 ; all .ASSUME ST.FMT EQ ST.DRV+1 ; together CMPB R1,#ST.DAT ;Data, Host Buffer Access, Control, ; Drive, or Formatter error? BLO DSPERR ;If LO, no, go see what it is CMPB R1,#ST.FMT ;Well, is it one of these? BHI DSPERR ;No, go see what it is CMP P.STS(R5),# ;Yes, unrecoverable drive error? BNE 30$ ;No, just abort .IF NE UM$PORTS-1 MOV .PCTAB,R5 ;Yes, reinit port next time we're used CLR PC.STEP(R5) ; to insure error is cleared out. .IFF ;NE UM$PORTS-1 CLR ISTEP ;Yes, reinit port next time we're used .ENDC ;NE UM$PORTS-1 CLRB DN.FLG(R4) ;Clear flags, INIT resets it 30$: CALLR UMHERR ;Hard error (No extra info: R4=0) ;+ ; OFFLINE status returned ;- 40$: DEC RETRY ;Offline: retries exhausted? BLE 20$ ;Yes, report error INC RETRY ;No, inc RETRY: INIT decrements it too CLRB DN.FLG(R4) ;Clear flag byte, INIT resets it CALLR INIT ;Re-init port to get unit available & ; retry command (can't issue ONLINE to ; offline drive). ;+ ; Position Lost Status ;- 41$: BITB #EF.SEX,P.FLGS(R5) ;Serious Exception (endflag) set? BEQ 42$ ;If EQ, no, not a real error MOV #EM.POS,R4 ;Yes, say we're lost BR BABORT ;And abort ; Position Lost without Serious Exception => position lost state. We've given ; initial POS LOST back, so allow operations to continue unless other errors. 42$: CLR R1 ;Clear R1 so we don't infinitely loop. CALLR CKCMD ;Not an error, do post interrupt stuff ;+ ; Error during ONLINE command, or OFFLINE status and retries exhausted. ;- 20$: MOV #EM.OFL,R4 ;Retries exhausted: say we're offline BABORT: BR ABORT ; and unavailable, then leave. .DSABL LSB .SBTTL DSPERR - Dispatch To Appropriate Error Routine For Last Command ;+ ; Dispatch, based on last command, to appropriate error routine ;- DSPERR: CALL GOT$IT ;Go see what routine we want .BR GOTTAB ;+ ; GOTTAB - Table for dispatching to correct routine ; ; Format of entry: ; .byte GOTRD - GOTTAB - (.-GOTTAB) ;.-GOTTAB= positive funct code (MCODE) ; which becomes ; .byte GOTRD - . ;- GOTTAB: .BYTE GOTRD - . ;Read op.rd .BYTE GOTWR - . ;Write op.wr .BYTE GOTOFF - . ;Rewind and offline op.avl .BYTE GOTREW - . ;Rewind op.rep .BYTE GOTWR - . ;Write ext gap = Write op.wr .BYTE GOTBAC - . ;Backspace op.rep .BYTE GOTFR1 - . ;Forward space op.rep .BYTE GOTTM - . ;Write tape mark op.wtm ;+ ; GOT$IT - Dispatch To Appropriate Error Routine For Last Command ;- .ENABL LSB GOT$IT: CLR R4 ;Error bits for user (0=>no xtra info) ADD (PC)+,@SP ;Modified function code + table addr. MCODE: .WORD 0 ; Modified code from RWRT (byte!) MOV @SP,-(SP) ;Make a copy of it MOVB @(SP)+,-(SP) ;Get offset to proper routine CLRB 1(SP) ;Its only a byte ADD (SP)+,@SP ;Offset + table addr + code = routine CALLR @(SP)+ ;Go do routine .SBTTL GOTxx - Handle Errors Based on Last Command Issued GOTTM: ;Write tape mark GOTWR: ;Write CMPB #ST.WPR,R1 ;Write Protected? BNE 70$ ;No, check EOT MOV #EM.WLK,R4 ;Yes, say we're write locked BR ABORT ;Hard error exit GOTBAC: ;Backspace GOTFR1: BIT #ST.MSK,R1 ;Is this backup tape mark? (success) BNE GOTFOR ;If NE, no MOVB #ST.TM,R1 ;Yes, say we hit a tape mark. GOTFOR: ;Forward space CMPB #ST.BOT,R1 ;BOT? BNE 60$ ;No, go check for Tape Mark or EOT BIS #EM.BOT,R4 ;Yes, say BOT found BISB #DN.SET,@.DNTAB ;Flag = @BOT: set density, next cmd .ASSUME DN.DEN EQ 0 BR GOTERR ;+ ; Did we read all that was in record, or, did we try to read too much? ; If we tried to read too much, TMSCP calls this 'success', so the status ; bits are = 0, and we have to check the byte count read vs. byte count ; requested to see if they're the same. Status bits MAY also = 0 if we ; hit EOT, in which case an EOT end flag is set. ; ; R1 = status bits (0 -> success, or short record, or EOT) ; R2 = command buffer ; R5 = message buffer ; R4 = exception conditions ;- GOTRD: CMPB #ST.RDT,R1 ;Record data truncated? BNE 50$ ;No, skip next MOV #EM.BIG,R4 ;Yes, say its a record error BR ABORT ;Report condition ; If no status bits set, either it's EOT or we tried to read too much. 50$: BIT #ST.MSK,R1 ;Any status bits set at all? BNE 60$ ;Yes, go see if it was tape mark BIS #100,R4 ;No, (R4 not=0 so no retry at GOTERR) MOV RBCNT,R2 ;Requested # bytes minus # bytes read. SUB P.BCNT(R5),R2 ;Did we try to read too much? BEQ 70$ ;No, must be EOT, go check it. ASR R2 ;Yes, make difference a word count. MOV #EM.SML,R4 ;Say short block read MOV #HDERR$,-(SP) ;Hard error so FSM will compare labels BR EBLKST ;Go store # of words not transferred 60$: CMPB #ST.TM,R1 ;Tape mark found? BNE 70$ ;No, check EOT .ASSUME EM.EOF EQ 1 INC R4 ;Yes, value 1 for TM 70$: BITB #EF.EOT,P.FLGS(R5) ;Real EOT found? BEQ GOTERR ;No, retry TST NFSREAD ;Yes, was .READ non-file structured? BNE GOTERR ;Yes, so ignore the EOT condition CMPB (R4)+,(R4)+ ;No, value 2 for Physical EOT .ASSUME EM.EOT EQ 2 ; (note: 100 bit may be set in R4!) GOTOFF: ;Rewind/offline GOTREW: ;Plain ole rewind GOTERR: TST R4 ;How did we get here? BNE OBJCNT ;Don't retry ;Non qualifying error, retry function. DEC RETRY ;Tried too much? BLE UMHERR ;Can do no more, error exit CALLR RERWRT ;No, lets try again OBJCNT: MOV #EOF$,-(SP) ;EOF error on the stack for EXCEP CMPB #OP.END!OP.REP,P.OPCD(R5) ;Is this a space function BNE 80$ ;No, skip next MOV RBCNT,R2 ;Get requested # records to space SUB P.RCSK(R5),R2 ;Minus actual # records spaced .BR EBLKST ; In XM, we can't move the extra error information to the user's job space ; until we've done a .SYNCH to get mapping correct. So we move it to ERRBL2 ; and later do the .SYNCH around the $DONE code. In SJ/FB, we don't have to ; worry about mapping, so we just move the info when we get it. EBLKST: .IF NE MMG$T ;If XM .HP1EX P1LOW ; (Map to low memory) MOV R2,@#ERRBL2 ;Put it in error block $REL .-2 ERRBL2 UMR ; ... .HP1EN ; (End of block) .IFF ;NE MMG$T .IF NE MU$FSM ;If file structured MOV @MUCQ,R5 ;Get ERRBLK address .IFF ;NE MU$FSM ;If not file structured MOV @UMCQE,R5 ;Get ERRBLK address .ENDC ;NE MU$FSM BEQ 80$ ;If EQ, don't write to ERRBLK MOV R2,2(R5) ;Report # blks not spaced/wds not read .ENDC ;NE MMG$T 80$: BIC #100,R4 ; (Clear extra R4 bit read EOT uses) BR EXCEP ;Error exit (@SP = HDERR$ or EOF$) .DSABL LSB .SBTTL UMHERR - Error Completion Routines ;+ ; There are several entry points ; ; UMHERR -- Is the entry point to issue a hard error ; ABORT -- Is the entry point to issue a hard error when more specific ; information to report ; EXCEP -- Is the entry point to report an exception conditon ; ; R4 = the error qualification code ; CSW bit to set is on the stack ;- .ENABL LSB UMHERR: CLR R4 ;Say no error qualification code ABORT: MOV #HDERR$,-(SP) ;Say hard error EXCEP: .IF NE MU$FSM ;If file structured .IF NE MMG$T ;If XM MOV @H$CQE,R5 ;Copy Q$BLKN (ERRBLK) changes from hi .HP1EX P1LOW ; (Map to low memory) MOV #MUCQ,-(SP) ;Addr of MUCQ to stack $REL .-2 MUCQ UMR ; ... MOV @(SP)+,-(SP) ;Indirect it... MOV R5,@(SP)+ ;Copy Q$BLKN (ERRBLK) changes to low .HP1EN ; (End of block) .ENDC ;NE MMG$T MOV (SP)+,R5 ;R5 = error type RET2LO FSMERR ;Go to FSM error handler .IFF ;NE MU$FSM ;If not file structured .IF EQ MMG$T MOV UMCQE,R5 ;R5 -> current queue element. .IFF ;EQ MMG$T MOV H$CQE,R5 ;R5 -> current queue element .ENDC ;EQ MMG$T BIS (SP)+,@Q$CSW(R5) ;Set bit in CSW TSTB Q$FUNC(R5) ;USR or READ/WRITE function? BPL MUDONE ; don't return ERRBLK if so TST @R5 ;Do we have more errors to report BEQ MUDONE ;Branch if no RET2LO DOSYNCH .BR ;Error exit ;********************************************************************* UMPSECT ;********************************************************************* ; In XM, we can't move the extra error information to the user's job space ; until we've done a .SYNCH to get mapping correct. So we move it to lo mem ; and later do the .SYNCH (around the $DONE code). In SJ/FB, we don't have ; to worry about mapping, so we just move the info when we get it. DOSYNCH: .IF NE MMG$T COM SINK ;Set .SYNCH flag MOV UMCQE,R5 ;R5 -> current queue element (lo mem!) MOV @R5,ERBSAV MOV R4,TEMP ;This value returns in R0 after SYNCH MOVB Q$JNUM(R5),R5 ;Get job number BIC #^C,R5 ASR R5 ;Shift ASR R5 ; into ASR R5 ; place 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 $DONE ;********************************************************************* UMXPSECT ;********************************************************************* .ENDC ;NE MU$FSM .DSABL LSB .SBTTL MUDONE - Normal Completion Routines ;+ ; MUDONE is the routine that the hardware handler comes to when an operation ; completed with no exception conditions. When FSM is present, a jump to FSM ; is excecuted. If FSM is not present, the hardware handler will exit to the ; completion routine in the monitor. ;- MUDONE: .IF NE MU$FSM ;If file structured CLR R4 ;No exception codes RET2LO FSMDON ;Tell FSM that we are done ;FSM returns to $DONE when it's done .ENDC ;NE MU$FSM ;+ ; Standard exit to RT-11 ;- .ENABL LSB DOFIN: ;ensure compatibility with UM.MAC UMEXIT: RET2LO $DONE .BR ;********************************************************************* UMPSECT ;********************************************************************* ; In XM, we can't move the extra error information to the user's job space ; until we've done a .SYNCH to get mapping correct. So we move it to lo mem ; and here do the .SYNCH. In SJ/FB, we don't have to worry about mapping, so ; we just move the info when we get it. $DONE:: .IF EQ MMG$T ;If SJ/FB .DRFIN UM ...... .IFF; EQ MMG$T ;If XM, TST SINK ;CALL or CALLR BNE 10$ ;Branch if CALL .ADDR #UMCQE,R4 MOV @#$SYPTR,R5 ;Get base of RMON CALLR @$QCOMP(R5) ;Split ...... 10$: CLR SINK ;Initialize .SYNCH has been done flag .ADDR #SYNBLK,R4 ;Point to .SYNCH block .SYNCH ;Do the .SYNCH BR BADSYN ; Error on .SYNCH ; The following code (up until the RETURN) executes in KERNEL mode, ; but in JOB context: MOV ERBSAV,R1 ;Point to ERRBLK BIS #30000,@#177776 ;User mode to previous MOV R0,-(SP) ;Put exception code onto stack MTPD (R1)+ ;Store for the user MOV ERRBL2,-(SP) ;2ND word 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) .ADDR #UMCQE,R4 ; point to queue element, 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: RETURN .ENDC; EQ MMG$T .DSABL LSB .SBTTL Magtape Data Area ;+ ; 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 OR'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 operation being done started life as a .READ on a channel ; opened with a non file structured .LOOKUP. When the EOT marker is detected ; and this word is non zero then the condition is ignored. ;- ; Do not change the order of the following variables OLDBA:: .WORD 0 ;Low order 16 bits of Buffer Address .IF NE MMG$T ;If XM EXTADR::.WORD 0 ;Hi order of 18/22 bit Buffer Address ;********************************************************************* UMXPSECT ;********************************************************************* .ENDC ;NE MMG$T NFSREAD::.WORD 0 ;This word is set to -1 if a ;Non filestructured READ was just ;done, else it is zero. If set, the ;EOT condition will be ignored. .IF NE MMG$T ;If XM ;********************************************************************* UMPSECT ;********************************************************************* SYNBLK::.WORD 0 ;.SYNCH Block JOBNM:: .WORD 0 ; Job number goes here .WORD 0 ; (Unused) .WORD 0 ; (Unused) TEMP:: .WORD 0 ; Loaded in R0 after successful .SYNCH .WORD -1 ; (Leave this alone!) .WORD 0 ; (Leave this alone!) SINK:: .WORD 0 ;= 0 -> .SYNCH not done, so JMP COMPLT ;<>0 -> .SYNCH done, so JSR PC,COMPLT ERBSAV::.WORD 0 ;Save the address of ERRBLK here ERRBL2: .WORD 0 ;Contains value to go to ERRBLK + 2 .ENDC ;NE MMG$T .IF EQ MU$FSM ;If not file structured .DREND UM,PSECT=UMLCODE ;This is the end ;********************************************************************* .PSECT UMDVR ;********************************************************************* .IFF ;EQ MU$FSM ;If file structured MUCQ: .WORD 0 ;Fake a UMCQE for file support DRIVEN == MU$UN ;Used by FSM DVINFO:: ;FSM's Unit table .REPT DRIVEN .WORD -1 ;Current file sequence number .WORD -1 ;Current block number, -1 = unknown .WORD -1 ;Highest block written .BYTE 0 ;File type (0= lookup, -1 = enter) .BYTE 0 ;Position is past EOT marker flag .WORD 0,0,0 ;RAD50 file name .ENDR ;+ ; The following definitions are for FSM compatibility ;- MTDONE == MUDONE MTCQE == UMCQE MT == UM MTLQE == UMLQE MTSTRT == UMSTRT MTCQ == MUCQ MUSTRT == UMSTRT .ENDC ;EQ MU$FSM .IF NE MMG$T ;+ ; UMX Calculations ;- ;********************************************************************* UMXPSECT ;********************************************************************* UMXEND:: ;********************************************************************** .PSECT UMY ;********************************************************************** PADLEN ==: 0 ;no block padding is neccessary ;********************************************************************* .PSECT UMXDAT ;********************************************************************* UMXDND:: ;********************************************************************* .PSECT UMDATA ;********************************************************************* DATAND:: UMXDSZ ==: UMXDND - UMXDBA ;Size in bytes Psect UMXDAT DATASZ ==: DATAND - DATABA ;Size in bytes Psect UMDATA UMXSZ ==: UMXEND - UMXBA ;Size in bytes Psect UMX UMXSIZ ==: UMXDSZ+DATASZ+UMXSZ ;Size in bytes XM PSECTS MEMUMX ==: /100 ;Required global region size ;(Add 77 to be sure we got it all) XMLEN ==: UMXSIZ+PADLEN ;********************************************************************* .PSECT UMRLST ;********************************************************************* UMREND:: UMRLSZ ==: UMREND - UMR.LST ;Size in bytes Psect UMRLST UMLSZ ==: UMRLSZ ;Size in bytes: list PSECT ;********************************************************************* .PSECT UMNDLS ;List end Psect ;********************************************************************* UMPAD:: .BLKB <1000-SOVRSZ> ;PAD to block align SETOV1 ;********************************************************************* UMPSECT ;********************************************************************* ;********************************************************************* .PSECT LDOVR ;******************************************************************** .ASSUME . LE <> - UMLSZ> . = LDOVR + <1*BLK> - UMLSZ .IFF ;NE MMG$T UMLSZ = 0 .ENDC ;NE MMG$T ;********************************************************************* .PSECT UMDVR ;********************************************************************* SIZE = . SIZED = /2 ;******************************************************************** .PSECT UMLST ;******************************************************************* LMEND:: LMSIZE = LMEND - UM.LST ;size in bytes of root to ;root relocation list .IF NE MMG$T ;******************************************************************** .PSECT UYRLST ;******************************************************************* UYREND:: UYRLSZ = UYREND - UYR.LST ;size in bytes of root to ;root relocation list .ENDC; NE MMG$T ; Establish size of low memory data ;********************************************************************* .PSECT UMLORD ;********************************************************************* LOWDATA ==: . - LOWBAS ;Bytes ;;; .ASSUME . LE UMSTRT+1000 ;SET CODE access range .IF NE MMG$T .ASSUME LOWDATA EQ UMXDSZ ;Hi & Low Order Dependent Psects .ENDC ;NE MMG$T ;***************************************************************************** .PSECT SPFUNS ;overflow of SPFUN table from block 0 ;***************************************************************************** SFTAB: .DRSPF -,SF.MTM,TYPE=W ;377 Write Tape Mark .DRSPF -,SF.MWR,TYPE=W ;371 Write physical block .DRSPF -,SF.MRD,TYPE=R ;370 Read physical block .WORD 0 .END