;;; Copyright (c) 1999 Massachusetts Institute of Technology ;;; ;;; This program is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU General Public License as ;;; published by the Free Software Foundation; either version 3 of the ;;; License, or (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program; if not, write to the Free Software ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;******************************** ;** ;** TO BE DONE: ;** ;** RECORDS LONGER THAN 1K ;** AUTOMATIC DETERMINATION OF DENSITY AND RECORD LENGTH WHEN READING ;** ALLOW CLOSE WHEN TAPE HAS BEEN TAKEN OFF ;** BE MORE FORGIVING OF CONTROLLER LOSSAGE ;** PASS .MTAPE TO JOB DEVICE ;** HAVE AN IGNORE ERRORS SWITCH ;** THIS HORRIBLE BLETCHEROUS IOT CODE SHOULD BE REDESIGNED ;** ;******************************** IFE TM10A+TM10B+TM03S,.ERR NO MAGTAPE CONTROLLER TYPE SELECTED IFN TM10A,INFORM IO BUSS MAG TAPE,1 IFN TM10B,INFORM DATA CHANNEL MAG TAPE,1 IFN TM03S,INFORM RH11/TM03 MAG TAPE,1 IFN TM10P,[ $INSRT TM10 ] IFN TM03S,[ $INSRT TM03S ] $INSRT JTWMAC MSCBL==8 ;Command buffer length MGQDLL==10. ;PI level PDL length IF2 IFN MNUMB-140600, .ERR IMPLICIT DEPENDENCY ON MNUMB MSEOFP==210100 ;High bit of MNUMB in MEMBLT is EOF flag MSCHN==140500 ;Other 5 bits of MNUMB is drive number MTXP==410300,, ;BP to set/get transport number from IOCHNM MUNITF==170300 ;BP to set/get unit field in MTC CONI IFN TM10P,[ ;Tape controller commands MNOPIN==10000 ;NOP and interrupt when idle MWRITE==4000 ;Write data MW3IN==14000 ;Write data and long EOR gap MSPRR==7000 ;Space in reverse direction MREAD==2000 ;Read data MSPFR==6000 ;Space in forward direction MSPFF==16000 ;Space forward to EOF MSPRF==17000 ;Space reverse to EOF MREWND==1000 ;Rewind MRWNDD==11000 ;Rewind and unload MWEOF==5000 ;Write EOF mark ] MGNRTY==10. ;Number of retries on read ;Modes in OPEN call ; %MMOUT==1,,0 ;Open for output, 0=>input %MMBLK==2,,0 ;Block mode, 0=>unit mode %MMIMG==4,,0 ;Image mode, 0=>Ascii %MMCNK==10,,0 ;"Chunk" mode, 0=>stream mode %MMNSE==20,,0 ;No skip to EOF on close, 0=>do skip %MMEP==40,,0 ;Even parity, 0=>odd %MMDEN==300,,0 ;Density select ; 00=> "Default" - 1600 for KS/TU77 ; 01=> 800 BPI ; 10=> 1600 BPI ; 11=> 6250 BPI %MM32B==400,,0 ;"IBM" mode, write 8-bit bytes from LH 32 bits ; 0=> core dump %MMRSZ==7000,,0 ;Record Size ; Ranging binarily from 0=>1024. to 7=>8. bytes EBLK SUBTTL MAG TAPE STORAGE AREA MGVTC: 0 ;Scratch word for virgin tape check MGJDTI: 0 ;"Wait for job done" time out value MGNWRD: 0 ;Number of words read in a PI level read MGTBZY: -1 ;Flag to get interrupt started MGSFTI: 0 ;Software interrupt in progress MGUNIT: -1 ;Unit expecting interrupt MGWCW: 0 ;"Wait for control word written" flag LMIOWD: 0 ;Last MIOWD MSRAC: BLOCK NMTCS ;Transport software status flags %MA==1,,525252 %MAEOF==400000 ;4.9 EOF seen on read - must be 4.9 %MAETR==200000 ;4.8 EOT on internal read %MAETW==100000 ;4.7 EOT on write %MAERR==040000 ;4.6 PI level got an error %MARCE==020000 ;4.5 Read compare error %MACTH==014000 ;4.4 Core allocator says stop ;4.3 " (WHY 2 BITS?) %MASTP==002000 ;4.2 Stop read ahead %MANWT==001000 ;4.1 Nothing written on tape yet %MAEFA==000400 ;3.9 EOF seen on read-ahead, user hasn't seen %MAESO==000200 ;3.8 EOF read since open %MAMSO==000100 ;3.7 Tape moved since first open %MAREW==000040 ;3.6 "Tape is rewinding" flag %MARAC==000020 ;3.5 Read active flag %MAMOL==000010 ;3.4 Transport on line %MAWSW==000004 ;3.3 Wants software (timing) interrupts MGERRC: BLOCK NMTCS ;Error count MTCEFW: BLOCK NMTCS ;Number of EOF's written at close MGEOFR: BLOCK NMTCS ;Number of EOF's since last read MTPSAV: BLOCK NMTCS ;Storage to restore P on EOF MSCMDC: REPEAT NMTCS,0 ;Number of commands in command list MGSPCD: BLOCK NMTCS ;Spacing operation command MGSCNT: BLOCK NMTCS ;Spacing operation count MGEOTT: BLOCK NMTCS ;Timeout for detecting virgin tape MSBUFP: REPEAT NMTCS,0 ;Mag tape MP<->PI buffer queue in,,out MSNBOL: BLOCK NMTCS ;Number of buffers on list MSCRW: BLOCK NMTCS ;R/W flag, -1=>output 0=>input MSMPRC: BLOCK NMTCS ;Words left in buffer MSMPRP: BLOCK NMTCS ;Next word in buffer MTMDN: REPEAT NMTCS,-1 ;Block active at MP MGCABN: REPEAT NMTCS,-1 ;Buffer active at PI level MTUSE: REPEAT NMTCS,-1 ;Number of channels open on this transport MTUSR: REPEAT NMTCS,-1 ;User index of transport user MTBLKS: BLOCK NMTCS ;If write, buffer size ;If read, size of last record read MTMFNC: BLOCK NMTCS ;.MTAPE function storage MTMCNT: BLOCK NMTCS ;.MTAPE count MTMTAP: BLOCK NMTCS ;MTAPE call word MGCMTS: BLOCK NMTCS ;PI level status info (CONI MTS or similar) MGCMTC: BLOCK NMTCS ;PI level controller info (CONI MTC or similar) IFN TM10P,[ MTCONO: REPEAT NMTCS,\.RPCNT_17+20 ;Prototype CONO word for each transport ] IFN TM03S,[ MTSELW: BLOCK NMTCS ;Select word (TC reg val) for each transport MTSELM==3777 ;density/format/parity/unit bits mask MTWTFC: BLOCK NMTCS ;-10 word count to tape frame conversion factor ] ;Build table of QDL (PI level stack) pointers MGQDLP: REPEAT NMTCS,-MGQDLL,,CONC MGQD,\.RPCNT,-1 ;Built storage for command lists and PI level stacks REPEAT NMTCS,[ CONC MSCB,\.RPCNT,: BLOCK MSCBL ;Space for command list MGRCV ;Fake "command", causes list to wrap around MGNCMD ;Function on botton of Q PDL, gets new command CONC MGQD,\.RPCNT,: BLOCK MGQDLL ;Space for PI level stack IFE .RPCNT,MSLCTB==.-MSCB0 ;Length of each table ] ;Build table of pointers for adding commands to command list MTCMBP: REPEAT NMTCS,-MSCBL-1,,CONC MSCB,\.RPCNT,-1 ;Build table of bytepointers for removing commands from command list MGCMBP: REPEAT NMTCS,4400,,CONC MSCB,\.RPCNT,-1 ;It is depressing to discover that the DUMP program sucks these directly ; out of the running ITS. If you change what's in here fix DUMP too. MGEMTC: 0 ;CONI MTC, at last error MGEMTS: 0 ;CONI MTS, at last error IFE TM10B,[ MIOWD: BLOCK 2 ;Channel program ] IFN TM10A,[ MGDBRK: 0 CONO MTS,1 JRST 12,@MGDBRK ];TM10A BBLK ;Random Macros ;Enqueue and Dequeue buffers from the lists used to pass buffers between ; main program and PI level. Assumes W has a valid transport number... DEFINE MTENQB REG,TEMP=TT SKIPG MSNBOL(W) ;;Any buffers on list already? IFSKP. HLRZ TEMP,MSBUFP(W) ;;Yes, get old tail pointer DPB REG,[MLO,,MEMBLT(TEMP)] ;;Add new one onto end of list ELSE. HRRM REG,MSBUFP(W) ;;No, make new buffer head of list ENDIF. HRLM REG,MSBUFP(W) ;;New buffer is tail in any event SETZM TEMP DPB TEMP,[MLO,,MEMBLT(REG)] ;;Indicate end of list AOS MSNBOL(W) ;;Increment count of buffers on list TERMIN DEFINE MTDEQB REG,TEMP=TT HRRZ REG,MSBUFP(W) ;;Get head of buffer list HLRZ TEMP,MSBUFP(W) ;;Get tail CAMN REG,TEMP ;;Tail == head? IFSKP. LDB TEMP,[MLO,,MEMBLT(REG)] ;;No, get next buffer on list HRRM TEMP,MSBUFP(W) ;;Make it the new head of list ELSE. SETZM MSBUFP(W) ;;Only one buffer, list is now empty ENDIF. SOS MSNBOL(W) ;;Decrement count of buffers on list TERMIN IFN TM03S,[ ;Macros for testing various status bits as set up by MGGXPT and friends IRP OP,,[NN,NE,NA,O,OE,ON,OA,Z,ZE,ZN,ZA,C,CE,CN,CA] DEFINE TT!OP REG,#MSK ...TSF==0 IFSE REG,CS1,[ TL!OP I,MSK ...TSF==-1 ] IFSE REG,CS2,[ TR!OP I,MSK ...TSF==-1 ] IFSE REG,FS,[ TL!OP J,MSK ...TSF==-1 ] IFSE REG,ERR,[ TR!OP J,MSK ...TSF==-1 ] IFE ...TSF,.ERR Invalid register name REG given in TTxxx macro TERMIN TERMIN ];IFN TM03S SUBTTL MAG TAPE OPEN ROUTINE ; C/ MODE,,DEV ; D/ MODE (ROT 1) 4.9=1=>OUTPUT ; I/ DEVICE NUMBER ; R/ IOCHNM WORD POINTER MAGTO: SKIPL W,I ;Get device CAIL W,NMTCS ;Too big? JRST OPNL1 ;No such device MOVSI T,%MAREW TDNE T,MSRAC(W) ;Rewinding? PUSHJ P,UFLS ;Yes, wait for completion CONO PI,CLKOFF ;Don't want transport status changed under me SKIPL MTUSE(W) ;See if we are the first opener IFSKP. ;First opener. Initialize database for device SETZM MSBUFP(W) ;Indicate no buffers on chain SETZM MSNBOL(W) ;Another way of saying above SETZM MSMPRC(W) ;Buffer words remaining SETZM MSMPRP(W) ;Pointer to buffers SETOM MTMDN(W) ;No buffer at MP level SETOM MGCABN(W) ;No buffer owned by PI code SETZM MSRAC(W) ;Initialize transport software status word MOVEI A,2 MOVEM A,MTCEFW(W) ;Number of EOF's written MOVSI A,%MANWT IORM A,MSRAC(W) ;Indicate nothing written on tape ELSE. ;Not first opener. Check legality of this open CAME U,MTUSR(W) ;Same user as previous open? JRST OPNL10 ;Different user, report error MOVE B,D ;Check direction of open EQV B,MSCRW(W) ;Same as previous direction? SKIPL B ;Yes, OK JRST OPNL2 ;No, wrong direction ENDIF. MOVEM U,MTUSR(W) ;Store user SETZM MSCRW(W) ;Indicate read until found to be otherwise TLNE C,1 ;Read or write? SETOM MSCRW(W) ;Indicate write AOS MTUSE(W) ;Indicate 1 more user PUSHJ P,SOSSET MTUSE(W) ;SOS if PCLSR'd CONO PI,CLKON ;Let um (em?) get me (who's em?) PUSHJ P,MTSTAT ;Get transport status in standard form MOVE A,MSRAC(W) TLNE A,%MAERR ;PI error means device not there JRST MTODNP ;Go report error IFN TM03S,[ TTNN FS,%TMSFP ;Formatter present? JRST MTODNP ;No, can't win ;Should check for slave present too. ] IFN TM10P,[ TXNN J,%T1STH ;Transport hung, by chance? JRST MTOW1 ;No, proceed TXNN J,%T1SRW ;OK if rewinding JRST OPNL7 ;Device not working ] MTOW1: SKIPN MSCRW(W) ;Writing? JRST MTOW2 ;No... IFN TM10P,TXNE J,%T1SWL ;Yes. Write locked? IFN TM03S,TTNE FS,%TMSWL JRST OPNL26 ;Yes, device writelocked error IFN TM10P, TXNN J,%T1SET ;At EOT? IFN TM03S, TTNN FS,%TMSET JRST MTOW2 ;No MOVSI A,%MAETW+%MAERR ;If write and EOT, make .IOT give IOC error, ; but let open win IORM A,MSRAC(W) MTOW2: TXNE C,%MMDEN ;Density specified explicitly? JRST MTOW3 ;Yes, go check for validity IFN TM10P,MOVEI A,1 ;No, pick one. Use 800 for TM10 IFN TM03S,MOVEI A,2 ;Use 1600 for TM03 DPB A,[.BP %MMDEN,C] ;Set value JRST MTOW4 ;Done and assumed correct MTOW3: LDB A,[.BP %MMDEN,C] ;Get density from open IFN TM10P,[ CAIE A,1 ;800 is the only currently OK speed for TM10 JRST OPNL12 IFN 0,[ ;You need something like this if you arrange to allow non-800 TM10 speeds TXNN C,%MM32B ;32-bit compatible mode requested? JRST MTOW4 ;No, core dump CAIN A,1 ;Density specified as 800? JRST MTOW4 ;Yes, we can do that JRST OPNL12 ;32-bit and not 800BPI, controller can't do it ] ];IFN TM10P IFN TM03S,[ CAIN A,3 ;Specified 6250? JRST OPNL12 ;Yep, loser. Else OK ] ;Here on successful open. ; Set up CONO or select word, IOCHNM word, blocksize ; MTOW4: PUSHJ P,LSWDEL ;Release MTUSE switch IFN TM10P,[ MOVEI A,MTCCHN_3 ;Start building CONO word. Set control PI level IFN TM10A,TRO A,1 ;Add in data PI level for non-DF10 controller LDB B,[.BP %MMDEN,C] ;Get density from open CAIE B,1 ;800 BPI BUG INFO,[ILLEGAL TM10 TAPE SPEED SETTING, USING 800BPI] MOVEI B,%T1D80 ; Yep. DPB B,[.BP %T1CDS,A] ;Set density field of CONO word TXNN C,%MM32B ;32-bit mode specified? TXO A,%T1CCD ;No, set core dump mode in CONO TXNN C,%MMEP ;User wants even parity? TXO A,%T1COP ;No, set odd parity DPB W,[.BP %T1CNU,A] ;Set unit number field of CONO MOVEM A,MTCONO(W) ;Save assembled CONO word ];IFN TM10P IFN TM03S,[ MOVE A,W ;Get unit number being initialized TXNN C,%MM32B ;User asked for industry compatible? IFSKP. ;Yes... MOVEI B,4 ;Set word-to-frame conversion factor MOVEM B,MTWTFC(W) MOVEI B,%TMFIC ;Set mode in budding select word ELSE. ;Core dump... MOVEI B,5 ; takes 5 tape frames per word MOVEM B,MTWTFC MOVEI B,%TMFCD ;Set CD format in select word ENDIF. DPB B,[.BP %TMTFS,A] ;Set format in select word TXNE C,%MMEP ;User wants even parity? TXO A,%TMTEP ;Yes, set even parity flag LDB B,[.BP %MMDEN,C] ;Get density from open CAIE B,1 ;800 BPI specified? SKIPA B,[%TMD16] ;Anything else, use 16 MOVEI B,%TMD08 ;800, use that DPB B,[.BP %TMTDS,A] ;Set density in select word MOVEM A,MTSELW(W) ;Set select word for this unit ];IFN TM03S LDB B,[.BP %MMRSZ,C] ;Get record size from open call TRC B,7 ;Convert to power of two MOVEI A,10 ;Minimum record size is 10 (8.) words LSH A,(B) ;Blocksize = minimum * 2^power MOVEM A,MTBLKS(W) ;Save blocksize in words LDB A,[.BP <%MMBLK\%MMIMG>,C] ;Use unit/block and ascii/image bits as index HLR C,MTOPTB(A) ;Get input dispatch routine from table TLNE D,400000 ;Remember D? Skip if user opened in input mode HRR C,MTOPTB(A) ;OK, get output dispatch routine instead MOVEM C,(R) ;Save routine in IOCHNM word DPB W,[MTXP(R)] ;Set transport number in IOCHNM word JRST POPJ1 ;Skip return means success ;Here if device is not present MTODNP: SETZM MSRAC(W) ;Too bad. Clear status word and report error JRST OPNL1 ;Table of I/O routines ; MTOPTB: MTUAIX,,MTUAOX ;Unit Ascii MTBIX,,MTBOX ;Block Ascii MTUIIX,,MTUIOX ;Unit Image MTBIX,,MTBOX ;Block Image SUBTTL MAG TAPE CLOSE ROUTINES ;MTOCL - CLOSE TAPE OPEN FOR OUTPUT MTOCL: LDB W,[MTXP(R)] ;Set up transport number SOSL MTUSE(W) ;Decrement transport use counter POPJ P, ;Not only channel open, all done AOS MTUSE(W) ;Consistant state in case PCLSR'd MOVSI A,%MAERR TDNE A,MSRAC(W) ;See if error has occurred PUSHJ P,MTOCL3 ;Yes, clean up a few things SKIPL MTMDN(W) ;Is there a partially processed buffer? PUSHJ P,MTWBFD ;Yes, write it to tape MOVEI B,MGMEOT ;Queue a "Write EOT" command to PI level PUSHJ P,MTCMD SKIPLE MSCMDC(W) PUSHJ P,UFLS ;Wait till done. MOVEI A,1 MOVEM A,MGEOFR(W) SKIPGE MTMDN(W) ;Active buffer at MP level? IFSKP. MOVE A,MTMDN(W) BUG PAUSE,[MT: MP BUF REMAINS AT CLOSE],OCT,A PUSHJ P,MEMR ENDIF. SKIPGE MGCABN(W) ;Active buffer at PI level? IFSKP. MOVE A,MGCABN(W) BUG PAUSE,[MT: PI BUF REMAINS AT CLOSE],OCT,A PUSHJ P,MEMR ENDIF. SKIPN MSNBOL(W) ;Any buffers on buffer queue? IFSKP. BUG PAUSE,[MT:],DEC,MSNBOL(W),[BFRS QUEUED AT CLOSE] PUSHJ P,MTCBFF ENDIF. SETOM MTUSE(W) ;Nobody is using this transport SETOM MTUSR(W) ;No user associated with this transport SETZM MSRAC(W) ;reset transport software status word POPJ P, MTOCL3: SKIPL A,MTMDN(W) ;Have a buffer active at MP level? PUSHJ P,MEMR ;Flush it if so SETOM MTMDN(W) SETZM MSMPRC(W) ;Say no words left in current buffer POPJ P, ;Close routine for MT open for input MTICL: LDB W,[MTXP(R)] ;Set up channel data pointer SOSL MTUSE(W) ;Last user? POPJ P, ;No, nothing to do AOS MTUSE(W) ;Yes, save state for possible PCLSR MOVEI T,1 ;This crock is because we want to allow CAMGE T,MSCMDC(W) ; one outstanding command if rewinding PUSHJ P,UFLS ;Wait till one or less outstanding command MOVE T,MSRAC(W) ;Get transport software status TLNE T,%MAREW ;Is it rewinding? IFSKP. SKIPLE MSCMDC(W) ;No, wait till no outstanding commands PUSHJ P,UFLS ENDIF. SKIPGE MGCABN(W) ;Any PI-level buffers left? IFSKP. MOVE A,MGCABN(W) BUG PAUSE,[MT: PI INPUT BUF LEFT AT CLOSE],OCT,A PUSHJ P, MEMR ENDIF. PUSHJ P,MTRBD ;Release any MP-level buffers SETOM MTUSR(W) ;Reset user identifier PUSHJ P,MTCBFF ;Free some buffers ?whose+++ SOS MTUSE(W) ;Decrement use count MOVE T,MSRAC(W) ;Get transport software status again TLNE T,%MAREW ;Are we rewinding? JRST MTICL2 ;Yes, don't have to skip to EOF MOVSI A,(%MMNSE) TDNE A,(R) ;Check if user wants skip to EOF JRST MTICL2 ;No, forget it MOVSI A,%MAMSO TDNN A,MSRAC(W) ;Has tape moved at all since open? JRST MTICL2 ;No... SKIPE MGEOFR(W) ; JRST MTICL2 ;Note that this disposes of a read-ahead EOF. PUSHJ P,MTSTAT IFN TM10P,[ MOVE B,MGCMTS(W) TXNE B,%T1SBT ;BOT? JRST MTICL2 ] IFN TM03S,[ TTNN FS,%TMSOL ;Still online? JRST MTICL2 ;No, can't very well skip to EOF TTNE FS,%TMSBT JRST MTICL2 ] MOVEI B,MGSPFF ;Space forward to end of file PUSHJ P,MTCMD SKIPLE MSCMDC(W) ;Wait till command done PUSHJ P,UFLS MTICL2: MOVSI T,%MAREW ANDM T,MSRAC(W) ;Clear all software status except rewinding POPJ P, ;Done ;Free a chain of IO buffers pointed to by MSBUFP(W) ; Count of buffers is in MSNBOL(W) ; MTCBFF: SKIPN MSNBOL(W) ;Any buffers on chain? POPJ P, ;No, fine DO. HRRZ A,MSBUFP(W) ;Yes, get pointer LDB T,[MLO,,MEMBLT(A)] ;Get pointer to next buffer HRRM T,MSBUFP(W) ;Write that in chain header PUSHJ P,MEMR ;Return buffer to IO pool SOSLE MSNBOL(W) ;Any more to do? JRST TOP. ;Yes, loop back for more ENDDO. SETZM MSBUFP(W) ;Zero buffer list pointer POPJ P, SUBTTL MAG TAPE INPUT .IOT ROUTINES SKIPA B,[SIOKT] MTUAI: MOVEI B,CHRKTI ;Unit ASCII input MOVE E,[440700,,5] JRST MTREAD SKIPA B,[SIOKT] MTUII: MOVEI B,CHRKTI ;Unit image input MOVE E,[444400,,1] JRST MTREAD MTBI: MOVE E,[444400,,1] ;Block input MOVEI B,BLKT MTREAD: LDB W,[MTXP(R)] ;W <= Transport number PUSHJ P,MTIECK ;Check for tape errors first MOVEM P,MTPSAV(W) ;Save P for EOF return JSP B,(B) ;IO Routine. BLKT,CHRKT,SIOKT MSMPRP(W) ;Pointer to next word MSMPRC(W) ;Count of words remaining SETZ MTRBG ;Get new buffer (SETZ for CHRKT return on EOF) MTRBD ;Discard buffer JRST 4,. ;Unused PUSHJ P,MTRBFW ;Code to wait for new buffer from PI level ;Get a new buffer for I/O code. ; This routine assumes that there is a buffer ready to get ; (i.e. MTRBFW was called) ; MTRBG: SKIPG MSNBOL(W) ;Any buffers on list? JRST MTRBG3 ;No, must be error or EOF CONO PI,UTCOFF ;Stop I/O for a bit MTDEQB TT,A ;Dequeue buffer into TT using A as temp MOVEM TT,MTMDN(W) ;Remember buffer active at MP level CONO PI,UTCON ;Turn I/O back on LDB J,[MWC,,MEMBLT(TT)] ;Get word count from buffer MOVEM J,MTBLKS(W) ;Save for .MTAPE 13 LSH TT,10. ;Convert buffer number into address JRST SIOBGX ;TT/address, J/word count /E unchanged ;Here if no buffer ready, error or EOF assumed ; MTRBG3: SKIPL MSRAC(W) .SEE %MAEOF ;EOF flag set in transport status? IFSKP. MOVSI T,%MAEFA ;The EOF is now no longer read-ahead ANDCAM T,MSRAC(W) ;So remember that fact JRST POPJ2 ;Double skip to tell I/O code about EOF ENDIF. PUSHJ P,MTIECK ;Not EOF. Check for error conditions BUG HALT,[TAPE READ BUFFER VANISHED] ;No error, shoulda been a buffer ;MAG TAPE READ BUFFER DISCARD ROUTINE MTRBD: SKIPGE A,MTMDN(W) ;Have an active MP buffer? JRST MOVTWJ ;Set up T for buffer wait, return CONO PI,UTCOFF ;Stop IO for a bit SETOM MTMDN(W) ;No active MP buffer SETZM MSMPRC(W) ;No data in nonexistant buffer LDB TT,[MSEOFP,,MEMBLT(A)] ;Get EOF flag from PI level PUSHJ P,MGMEMR ;Return buffer, enable UTC JUMPN TT, [ MOVSI A,%MAEOF ;EOF seen? IORM A,MSRAC(W) ;Record EOF in software status JRST .+1 ] MOVTWJ: MOVE T,W ;T gets transport number for bfr wait UFLS POPJ P, ;Also MTRBG, MTRBFW rely on this setting T ;MAG TAPE READ WAIT FOR DATA ROUTINE ; Called under a UFLS by system IO code to wait for data to arrive. ; Note T, not W, has transport number. T must be set up by some ; previous routine ; MTRBFW: MOVE TT,MSRAC(T) ;Get software status of transport TLNN TT,%MAEOF\%MAERR ;PI code reports EOF or error? SKIPLE MSNBOL(T) ;Or are any buffers available for reading? JRST POPJ1 ;SOme interesting condition, unhang TLNE TT,%MARAC ;Have we asked for a tape read yet? POPJ P, ;Yes, nothing to do but wait, wait, wait PUSH P,W ;This being done under a UFLS. only T good PUSH P,B MOVE W,T ;Set up transport number in usual place MOVEI B,MGREAD ;What we want the PI level to do MOVEI T,MSCBL ;Make sure that there is room in command list CAMG T,MSCMDC(W) ;If there is room, IFSKP. ; we will request a read operation MOVSI TT,%MARAC IORM TT,MSRAC(W) ;Read is active now, or will be shortly PUSHJ P,MTCMD1 ;Queue up command request for PI level ENDIF. ;If no room for command, all we can do is wait MOVE T,W ;Fix up T for UFLS POP P,B ;Clean up everything else POP P,W POPJ P, SUBTTL MAG TAPE OUTPUT .IOT ROUTINES SKIPA B,[SIOKT] MTUAO: MOVEI B,CHRKT ;Unit ASCII output MOVE E,[440700,,5] JRST MTWRIT SKIPA B,[SIOKT] MTUIO: MOVEI B,CHRKT ;Unit image output MOVE E,[444400,,1] JRST MTWRIT MTBO: MOVE E,[444400,,1] ;Block output MOVEI B,BLKT MTWRIT: LDB W,[MTXP(R)] ;Get transport number PUSHJ P,MTIECK ;Check for tape errors first HRLZI A,%MAETW TDNE A,MSRAC(W) ;PI code think it hit EOT? JRST IOCER9 ;Yep, go lose JSP B,(B) SETZ MSMPRP(W) ;Pointer to next word MSMPRC(W) ;Count SETZ MTWBFG ;Get new buffer MTWBFD ;Write out buffer to tape JRST 4,. TRNA ;No wait for buffer routine needed ;MAG TAPE WRITE - BUFFER GET ROUTINE MTWBFG: PUSHJ P,MTIECK ;Check for tape errors PUSHJ P,TCALL ;Turn off UTC JRST IOMQ ;Try to get buffer POPJ P, ;Return noskip if no buffers available MOVEM A,MTMDN(W) ;Store active buffer number MOVEI T,MUMGB DPB T,[MUR,,MEMBLT(A)] ;Tell world that it is a mag tape buffer DPB W,[MSCHN,,MEMBLT(A)] ;Store channel number in buffer header SETZM TT DPB A,[121000,,TT] ;Convert block number in A to address in TT MOVE J,MTBLKS(W) ;Get block size of write JRST SIOBGX ;MAG TAPE WRITE - BUFFER FINISHED ROUTINE ; General IO code has filled a buffer or otherwise finished with it. ; Queue the buffer for writing if there is anything in it. MTWBFD: PUSHJ P,MTIECK ;Check for tape errors SKIPGE A,MTMDN(W) ;Have an active buffer? POPJ P, ;No, nothing to do MOVEI T,MSCBL ;See if there is any room in command list CAMG T,MSCMDC(W) PUSHJ P,UFLS ;Wait for room in command list MOVE T,MTBLKS(W) ;Get blocksize we are writing SUB T,MSMPRC(W) ;Subtract number of words remaining in buffer CONO PI,UTCOFF ;Lock up while frobbing buffer lists SETOM MTMDN(W) ;Clear active buffer SETZM MSMPRC(W) ;Clear free word in buffer count JUMPE T,MEMR ;Nothing in buffer, just return block DPB T,[MWC,,MEMBLT(A)] ;Store word count MTENQB A ;Queue buffer on to-PI list CONO PI,UTCON ;Finished mucking with buffer list PUSH P,B MOVEI B,MGWRIT ;Issue a write request to PI level PUSHJ P,MTCMD MOVSI B,%MANWT ANDCAM B,MSRAC(W) ;Note that we have written something to tape SETZM MTCEFW(W) ;Note no EOF's written at end of tape JRST POPBJ ;Restore B and return SUBTTL MTCMD - GIVE COMMAND TO PI LEVEL ;PUSHJ P,MTCMD ;RH(W) has transport number ;RH(B) has address of PI level routine to execute MTCMD: MOVEI T,MSCBL ;Pending command list length CAMG T,MSCMDC(W) ;Count of commands currently in list PUSHJ P,UFLS ;Wait for room in pending command list CONO PI,UTCOFF ;Grab machine, keep count accurate MTCMD1: MOVE T,MTCMBP(W) ;Get pointer to next slot in command list AOBJN T,MTCMD2 ;Increment slot and check for wraparound SUB T,[MSCBL,,MSCBL] ;Reached end of list, ring it MTCMD2: MOVEM B,(T) ;Store new command MOVEM T,MTCMBP(W) ;Store new pointer AOS MSCMDC(W) ;Indicate one more command in list JRST MSTRTR ;Go start up PI routine SUBTTL MTIECK - CHECK FOR IOC ERROR ;PUSHJ P,MTIECK ;Returns +1 if no error ;Gives IOC error to user if error - never returns. MTIECK: PUSH P,A MOVE A,MSRAC(W) ;Get transport software status TLNN A,%MAERR ;PI level report an error? JRST POPAJ ;No, all is OK SKIPLE MSCMDC(W) ;Wait for PI level to finish cleaning up PUSHJ P,UFLS ; before throwing away buffers SKIPL A,MTMDN(W) ;Have an active MP-level buffer? PUSHJ P,MEMR ;Yes, throw it away SETOM MTMDN(W) ;No active MP buffer SETZM MSMPRP(W) ;No place to get/put next character SETZM MSMPRC(W) ;No room to do it anyway PUSHJ P,MTCBFF ;Free any buffers waiting for MP processing POP P,A MOVE T,MGCMTS(W) ;Get transport status data from PI level IFN TM10P,[ TRNE T,%T1STH\%T1SIO ;Transport hung or illegal operation? JRST IOCER1 ;Yes, report device error TRNE T,%T1SPE\%T1SRC\%T1SRL\%T1SDL\%T1SBT ;Gruesome errors JRST IOCER3 ;Report irrecoverable data error TRNE T,%T1SET ;(Real) End of Tape? JRST IOCER9 ;Device Full error ];IFN TM10P IFN TM03S,[ MOVE I,MGCMTC(W) ;Get controller transport status from PI level MOVE J,MGCMTS(W) TTNE CS1,%TM1MP ;Control bus parity error? JRST IOCER1 TTNN CS1,%TM1TE ;Transfer error? Could be TM03 or RH11 IFSKP. TTNE CS2,%TM2DL\%TM2UP\%TM2NF\%TM2NM\%TM2PE\%TM2MT\%TM2MP JRST IOCER1 ;Non-data errors TTNN FS,%TMSES ;Formatter error? IFSKP. TTNE ERR,%TMEUS\%TMECT\%TMENX\%TMEMD\%TMEFS\%TMEMC\%TMERM\%TMEIR\%TMEIF JRST IOCER1 ;Fatal formatter errors TTNE ERR,%TMECE\%TMECS\%TMEFC\%TMENG\%TMEFL\%TMEIC JRST IOCER3 ;Non-recoverable data errors ENDIF. ENDIF. TTNE FS,%TMSET ;End of tape? JRST IOCER9 ];IFN TM03S MOVE A,MGEOFR(W) ;Check for logical EOT CAIL A,2 ;Read two EOF's since last record? JRST IOCER9 ;Yes, report EOT JRST IOCER3 ;No, give irrecoverable data error for now SUBTTL MAG TAPE .STATUS ROUTINE ;Building a status word in D. ;Routine sets: ; 1.7-1.9 open modes ; 2.3 BOT ; 2.4 EOT ; 2.5 9 track (0 = 7 track) ; 2.6 IBM mode (0 = coredump) ; 2.7 Transport idle (no pending command) ; 2.8 EOF (last thing seen was a tape mark) ; STAMTC: ;Open modes LDB W,[MTXP(R)] ;Get transport number DPB A,[60300,,D] ;Open mode PUSHJ P,MTSTAT ;Get tape status from transport ;EOT? LDB A,[.BP %MAETW_22,MSRAC(W)] ;EOT on write LDB B,[.BP %MAETR_22,MSRAC(W)] ;EOT on read IOR A,B DPB B,[140100,,D] ;Tape at EOT? IFN TM10P,[ ;7 or 9 track drive? LDB A,[20100,,J] ;Get 7/9 track bit TRC A,1 DPB A,[150100,,D] ;7 or 9 track drive .ERR Missing TM10 .STATUS code at STAMTC ] IFN TM03S,[ ;A bunch of new stuff. BOT? SETZ A, TTNE FS,%TMSBT ;Transport is at BOT? SETO A, DPB A,[130100,,D] ;BOT. ;7 or 9 track drive? SETOM A ;TM03 is always 9-track DPB A,[150100,,D] ;7 or 9 track drive ;Core dump or 32 bit mode? MOVE A,MTWTFC(W) ;Get word to frame conversion. 4 or 5 TRC A,1 ;Flip last bit. Last bit now on iff 32bit mode DPB A,[160100,,D] ;Sorry. ;Formatter busy? SETO A, SKIPLE MSCMDC(W) ;Idle if no pending commands SETZ A, DPB A,[170100,,D] ;EOF last thing seen? SETZ A, TTNE FS,%TMSTM ;Last thing seen was a tape mark? SETO A, DPB A,[200100,,D] ;EOF. ];IFN TM03S POPJ P, ;RCHST ROUTINE FOR MAG TAPE RCHMGT: HLRZ E,(R) ;Get open mode from IOCHNM word LDB J,[MTXP(R)] ;Get the mag tape drive number MOVSI J,'MT0(J) ;Return that drive's device name TRZ E,(.BM MTXP) ;Clear drive # field in OPEN modes JRST POPJ1 ;Skip so that J overrides built-in device name SUBTTL MAG TAPE PI LEVEL ;Request magtape interrupt from MP-level software ; Must be called with I/O interrupts off (CONO PI,UTCOFF) ; This is called every 1/2 second by the ITS slow clock routine ; MSTRTR: SETZM MGTBZY ;No busy tapes, flag software interrupt CONO PI,MTCRQ ;Request interrupt on magtape channel CONO PI,UTCON ;Reenable IO interrupt system POPJ P, ;That is all ;Handle tape interrupt requested by software or other nonspecific cause ; Get here via non-vectored MTCCHN interrupt on the KS ; MGSBRK: AOS MGTBZY ;Note interrupt level is busy SETOM MGSFTI ;Note software interrupt in progress MOVEI B,NMTCS-1 ;Loop over all transports SKIPG MSCMDC(B) ;Any commands in command list? MGSBK1: SOJGE B,.-1 ;No, try next transport SKIPGE B ;Found command or finished scan. Which? JRST MGSBK2 ;Finished scanning. Go check other things MOVE W,B ;Have a command. Set up transport number PUSH P,B ;Save B over call to command routine MOVSI B,%MACTH TDNN B,MSRAC(W) ;Core allocator saying go away? PUSHJ P,MGXGO ;No, go start requested routine POP P,B ;Restore transport count JRST MGSBK1 ;Loop back for another transport MGSBK2: SETZM MGSFTI ;Clear software interrupt flag JRST MGEX ;That's all for now ;This probably should check for lost IE bits on TM03 ;Handle interrupt caused by specific hardware conditions ; Get here via vectored interrupt on the KS ; IFN TM10P,[ ; A - result of CONI MTC, ; C - result of CONI MTS, ; MGHBRK: SKIPGE W,MGUNIT ;Get unit we are expecting interrupt on JRST MGUBRK ;None? Probably MP level bailed out. Punt. LDB B,[MUNITF,,A] ;Get unit that controller is squacking about CAME W,B ;Same unit? BUG HALT,[MT PI CODE LOST TRANSPORT] MOVE J,C PUSH P,[MGEX] ;Cause POPJ P, in handler to dismiss interrupt IFN TM10B,[ TXNE C,%T1SCP\%T1SNM\%T1SDP ;Check for DF10 errors JRST MGERR ;Yes, go to error routine ];TM10B TXNE C,%T1SIO ;Illegal operation error? JRST MGERR ;Yes, go to error routine JRST MGXGO ;No, go handle interrupt ;Here to unbreak on unexpected hardware interrupt ; MGUBRK: LDB W,[MUNITF,,A] ;Who's the loser, anyway MOVE B,MTCONO(W) ;Get prototype CONO word for that transport CONO MTC,(B) ;Select offending unit CONO MTS,31 ;Clear interrupt, DF10, stop any op in progress JRST MGEX ;Go dismiss interrupt ];IFN TM10P IFN TM03S,[ ;Check for active unit. If none, go directly to inactive slave ;polling code. If active unit,check that controller is talking about ;this unit, then jump to its routine (MGXGO). When that finishes, ;see if controller is still showing attention, and check status ;of other transports if so. ; ;Well, almost. EBLK MGHBRK: 0 BBLK JSR UTCSAV ;Save AC,s set up interrupt P PDL AOS MGTBZY ;Note interrupt level is alive SKIPGE W,MGUNIT ;Some transport waiting for an interrupt? JRST MGNOUW ;Nope, either Slave Status Change or lossage IORDI B,%TMTC ;Get transport the TM03 is thinking about ANDI B,7 CAME B,W ;Same as the one we were waiting for? BUG HALT,[MT PI CODE LOST TRANSPORT] PUSHJ P,MGXGO ;Go jump into this unit's handler MGNOUW: IFN NMTCS-1,[ .ERR Missing multi-transport code at MGNOUW! If more than one unit, have to see if this is an interrupt caused by a SSC (slave status change), and if so poll all the inactive units and update their software status (rewinding, on/off line, etc.) With only one transport we currently avoid this by keeping the unit active (MGUNIT set) as long as it is doing *anything*, and giving it all the hardware interrupts. See rewind code, too. ];IFN NMTCS-1 JRST MGEX ;Go dismiss interrupt ];IFN TM03S ;Interrupt level control flow ; ; Each transport maintains the current state of its PI-level action ; routines on a seperate (per-transport) PDL with its SP in Q. This ; allows you to save the current state, dismiss the interrupt, and ; resume where you left off when the next interrupt for this transport ; arrives. ; ; Subroutine linkage between routines handling a per-drive PI-level ; action is with PUSHJ Q,xxx and POPJ Q, ; ; The MP level queues commands for the PI level to process on a per- ; transport queue at MGSBx (x=unit number) ; ; Ths general interrupt code transfers to the per-drive actions by ; jumping to MGXGO, which will load Q from the saved state of the ; current drive and start up whatever it finds there. This may be ; the MGNCMD routine, which will start a new command, or it may be ; the middle of an in-progress PI-level command handler. ; ; PI-level action routines can relinquish control in several ways: ; ; PUSHJ Q, CPOPJ will dismiss the current interrupt, arranging for ; control to return to the instruction following the PUSHJ when the ; next interrupt for this unit occurs. ; ; JRST MGOVER will dismiss the current interrupt, arranging for the ; currently executing subroutine to be restarted "from the top" when ; the next interrupt for this unit occurs. ; ; A simple POPJ P, will dismiss the current interrupt, arranging for ; the routine that called this one to be started at the point immediately ; after the call when the next interrupt comes in. This is generally not ; useful except from first-level action routines, where a POPJ P, will ; indicate that you have finished handling the current command and cause ; the next interrupt to fetch and start execution of a new command from the ; queued command list by transferring to MGNCMD. Got that? ;Transfer control to whatever the per-transport code wants to do. ; MGXGO: MOVE Q,MGQDLP(W) ;Getsaved Q PDL pointer for current transport PUSHJ P,QPOPJ ;"Return" to whatever is on top of Q PDL, ; arranging for POPJ P, to return to here MOVEM Q,MGQDLP(W) ;Save current Q PDL for next time POPJ P, ;Return, dismissing this interrupt ;Dismiss interrupt, arranging for next interrupt to restart routine ; we are currently executing (rather than either continuing here or ; starting a new command) ; MGOVER: IFN TM10P,[ CONSZ MTS,%T1STH\%T1SIO\%T1SCE ;Tape hung/ill op/DF10 error, JRST MGERR ; go handle error condition ] SOS (Q) ;Decrement address at top of Q PDL, now ; points to PUSHJ Q, instruction so ; that we will get called again from MGXGO ; at next interrupt dispatch POPJ P, ;Return to P PDL caller, dismissing interrupt ;This routine is always the last "command" in a transport command list ; Wraps the command list BP around the the beginning of the list, ; then gets and executes the next command. ; MGRCV: MOVNI A,MSCBL+1 ;Get negative length of command list ADDM A,MGCMBP(W) ;Wrap command extraction pointer back to start MGNCM1: ILDB B,MGCMBP(W) ;Get new command from list JRST (B) ;And jump to it ;This code is always the first (bottom) thing in a transport's Q PDL ; It is therefore executed whenever MGXGO transfers control to the ; Q PDL and there is no command in progress. ; MGNCMD: AOBJN Q,MGNCM1 ;Got here w/ POPJ Q,. Fake PUSHJ to restore Q, ; then go get the next command BUG ;Q PDL pointer clobbered QPOPJ1: AOS (Q) QPOPJ: POPJ Q, ;WAIT FOR JOB DONE BIT TO SET ; Called from PI-level command routines to wait for end of command. ; Called with PUSHJ Q,MGWTJD ; ; Returns +1 to caller if unusual termination ; +2 to caller if operation terminated normally ; ; I,J contain tape status: ; On TM10, I=CONI MTC, ; J=CONI MTS ; On TM03S, I=%TMCS1,,%TMCS2 (controller status), ; J=%TMFS,,%TMERR (formatter status) IFN TM10P,[ MGWTJD: CONI MTS,J ;Get transport status TXNE J,%T1STH\%T1SIO ;Transport hung or Illegal operation? JRST MGERR ;Yes, job-done isn't ever going to get set MGWJD1: CONI MTS,J ;Get status again SKIPN MGJDTI ;Is there a time out set? IFSKP. MOVE T,TIME ;Yes, check it. Get current time CAML T,MGJDTI ;Smaller than specified timeout time? JRST MGERR ;No, lose ENDIF. TXNN J,%T1SJD ;JOB-DONE bit set? JRST MGOVER ;No, we want to wait for it CONI MTS,J ;Job Done. Get status CONI MTC,I ;Get CONI MTC MOVEM J,MGCMTS(W) ;Save for MP level MOVEM I,MGCMTC(W) IFN TM10B,[ SKIPE MGWCW ;Want to wait for control word? PUSHJ Q,MGWCWC ;Check to see if it is written SETZM MGWCW ;Clear wait-for-control-word request flag ] CONO MTS,30 ;Clear channel conditions MOVE B,MTCONO(W) CONO MTC,(B) ;Release mtc, clear job done bit IFN TM10B,[ TXNE J,%T1SCP\%T1SNM\%T1SDP ;Check for channel errors POPJ Q, ;Channel error, return nonskip ] TXNE J,%T1STH\%T1SIO\%T1SPE\%T1SRC%\T1SRL\%T1SDL\%T1SBT POPJ Q, ;Random other things, not necessarily errors JRST QPOPJ1 ;Success ];IFN TM10P IFN TM03S,[ MGWTJD: MGWJD1: IORDI T,%TMCS1 ;Get controller status TXNN T,%TM1GO ;Go bit still set? JRST MGWJD2 ;No, command is finished. Go check errors SKIPE T,MGJDTI ;Is there a time out set? Get it if so. CAML T,TIME ;Past timeout time JRST MGOVER ;No timeout or not timed out yet, go wait JRST MGERR ;Timed out. Go check transport ;Here if action has terminated. Set up status bits before returning MGWJD2: HRLZ I,T ;%TMCS1,,? IORDI T,%TMCS2 HRR I,T ;I = %TMCS1,,%TMCS2 IORDI J,%TMERR IORDI T,%TMFS HRL J,T ;J = %TMFS,,%TMERR - I,J now in standard form MOVEM J,MGCMTS(W) ;Save for MP level MOVEM I,MGCMTC(W) TTNE CS1,%TM1MP ;Massbus control parity error JRST MGERR ;Who knows what the transport is doing TTNN CS1,%TM1TE ;Controller error? TTNE FS,%TMSES ;Formatter error? POPJ Q, ;Yes, return +1 for closer examination JRST QPOPJ1 ;Success ];IFN TM03S ;Select the transport given by W ; Returns +1 with transport selected, status in I,J ; May dismiss and wait for a while first ; MGGXPT: IFN TM10P,[ CONSO MTS,%T1SNU ;Can controller select new unit right now? JRST MGOVER ;No, wait for it MOVE T,TIME ADDI T,10.*30. ;Time out in 10. seconds MOVEM T,MGJDTI ;Set up job-done timeout MOVEM W,MGUNIT ;Note unit waiting for hardware interrupt MOVE B,MTCONO(W) ;Get CONO word for new unit CONO MTC,MNOPIN(B) ;NOP, but interrupt when new drive is ready PUSHJ Q,MGWJD1 ;Wait for job done JFCL ;Ignore any errors SETZM MGJDTI ;No more timeout SETOM MGUNIT ;Not waiting any more POPJ Q, ;Return to caller ];IFN TM10P IFN TM03S,[ IORDI T,%TMFS ;Get current formatter status TXNN T,%TMSES\%TMSSC ;Showing error or slave status change? IFSKP. ;Yes, clear errors before going ahead IOWRI W,%TMTC ;Select slave MOVEI A,10. ;Try 10 times to clear drive MOVEI B,%TMCLR DO. IOWRI B,%TMCS1 ;Write drive clear command IORDI T,%TMFS ;Get status TXNN T,%TMSES ;Still have error JRST ENDLP. ;No, done SOJG A,TOP. ;Retry up to 10 times JRST MGERR ;Else give up ENDDO. ENDIF. MOVE T,MTSELW(W) ;Get desired settings IOWRI T,%TMTC ;Tell TM03 MOVEI T,%TMNOP ;You may need this to set status values IOWRI T,%TMCS1 ; but I'm not really sure IORDI T,%TMCS1 PUSHJ Q,MGWJD2 ;Go set status registers appropriately JFCL ;Maybe should check non-existant slave? POPJ Q, ];IFN TM03S ;MGERR - HANDLE TAPE ERROR ; ;Called from PI level command routines which detect a tape or controller error ; Flags error in software status word, records error status in MGExxx. ; Flushes command in progress by resetting Q PDL to base. ; Flushes commands in PI-level command queue by resetting queue pointers. ; Flushes any buffers which might be queued for writing. ; Returns to P PDL, to wait for new commands. MGERR: IFN TM10P,[ CONI MTS,MGEMTS ;Get transport status for MP level analysis CONI MTC,MGEMTC ] IFN TM03S,[ IORDI T,%TMCS1 ;Get controller and transport status into HRLM T,MGEMTC ; standard form IORDI T,%TMCS2 HRRM T,MGEMTC IORDI T,%TMFS HRLM T,MGEMTS IORDI T,%TMERR HRRM T,MGEMTS MOVE I,MGEMTC ;Get status to standard place for macros MOVE J,MGEMTS ];IFN TM03S MOVSI T,%MARAC ;Read not active, for sure ANDCAM T,MSRAC(W) SETZM MSCMDC(W) ;No commands active SETOM MGUNIT ;Clear unit wait flag SETZM MGJDTI ;No job-done timeout IFN TM10B,[ TXNE J,%T1SCP\%T1SNM\%T1SDP ;Channel error? BUG PAUSE,[MTAPE: CHANNEL ERROR, STATUS=],OCT,J,[MICWA+1=],OCT,MICWA+1,[MIOWD=],OCT,MIOWD ];TM10B IFN TM03S,[ .ERR UBA errors? More gentle cleanup? TTNE CS1,%TM1MP\%TM1TE ;Cbus parity or transfer error? TTNE FS,%TMSES ;And no formatter error? SKIPA ;Yes and yes (no) (what?). Controller error BUG INFO,[MTAPE: RH11 ERROR, STATUS=],OCT,MGEMTC,[TM STATUS=],OCT,MGEMTS TTNE FS,%TMSES ;Formatter error? BUG INFO,[MTAPE: FORMATTER ERROR, STATUS=],OCT,MGEMTS PUSHJ P,TMINIC ;Go reinit controller ];IFN TM03S SKIPL A,MGCABN(W) ;Any buffers owned by PI routines? PUSHJ P,IMEMR ;Yes, give them back to system SETOM MGCABN(W) ;No PI buffer any more HRLZI B,%MAERR ;Flag error detected by PI level IORM B,MSRAC(W) ;Store in transport status word MOVE Q,[-MGQDLL,,MGQD0-1];Reset Q PDL to base of this unit's stack, MOVE T,MSLCTB ; thus flushing whatever command is in progress IMUL T,W ;Find offset to base of Q PDL for this unit ADD Q,T ;Add to prototype unit 0 QDP pointer, PUSH P,Q ; and save it away MOVE Q,[-MSCBL-1,,MSCB0-1] ;Get command list input pointer ADD Q,T ;Offset it to this unit's command queue, MOVEM Q,MTCMBP(W) ;And save it as new MP (input) queue pointer MOVE Q,[4400,,MSCB0-1] ;Get new command list output pointer ADD Q,T ;Offset correctly for this unit, MOVEM Q,MGCMBP(W) ;And save as PI (output) command queue pointer MOVSI B,%MAREW ;Does initting xport stop TM03 rewind? ANDCAM B,MSRAC(W) ;Say not rewinding SKIPN MSCRW(W) ;If reading, JRST POPQJ ; we're done. Restore Q and exit SKIPN MSNBOL(W) ;Writing. Any buffers on list? JRST POPQJ ;No, restore Q and exit DO. ;Here to free buffers on IO list HRRZ A,MSBUFP(W) ;Get buffer pointer from head of chain LDB T,[MLO,,MEMBLT(A)] ;Get back pointer (next buffer) HRRM T,MSBUFP(W) ;Make next buffer head of chain PUSHJ P,IMEMR ;Free current buffer SOSLE MSNBOL(W) ;Decrement count, check for more JRST TOP. ;More, loop back ENDDO. SETZM MSBUFP(W) ;Mark list as empty JRST POPQJ ;Restore Q and return IFN TM10B,[ ;Wait for control word to get written ; MGWCWC: SKIPE MICWA+1 ;Control word written? POPJ Q, ;Yes, return to caller CONO MTS,4 ;No, tell DF10 to write it MGWCW1: SKIPE MICWA+1 ;Written yet? JRST MGWCW2 ;Good, done PUSHJ Q,CPOPJ ;Not written. Dismiss interrupt and wait JRST MGWCW1 ;We're back. See if written yet. MGWCW2: MOVE I,MGCMTC(W) MOVE J,MGCMTS(W) ;Restore status TLO J,10 ;Set control word written POPJ Q, ;Return to caller ];IFN TM10B IFN TM10A,[ MGDCSI: SKIPA A,[BLKI MTC,MIOWD] MGDCSO: MOVE A,[BLKO MTC,MIOWD] MOVEM A,MAGLOC MOVE A,[JSR MGDBRK] MOVEM A,MAGLOC+1 POPJ Q, ];IFN TM10A IFN TM03S,[ ;Note this one's called on P PDL TMINIC: IORDI A,%TMTC ;Get TC reg value ANDI A,MTSELM ;Keep interesting bits only IORDI B,%TMCS2 ;Get CS2 ANDI B,7 ;Keep selected "drive" (TM03) number only MOVEI T,%TM2CC IOWRI T,%TMCS2 ;Clear controller logic IOWRI B,%TMCS2 ;Reselect TM03 IOWRI A,%TMTC ;Reselect transport MOVX T,%TMCLR ;Do a formatter clear command IOWRI T,%TMCS1 POPJ P, ];IFN TM03S SUBTTL MAG TAPE PI LEVEL WRITE MGWRIT: PUSHJ Q,MGGXPT ;Select desired transport IFN TM10P,[ TXNE J,%T1STH\%T1SRW\%T1SWL ;Write locked, hung or rewinding? JRST MGERR ;Not a good thing ] IFN TM03S,[ TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line? JRST MGERR ;No or no, can't do operation TTNE FS,%TMSWL ;Transport write locked? JRST MGERR ;Shouldn't happen, we checked at open. ] MOVSI A,%MACTH TDNE A,MSRAC(W) ;Core alloc want quit temporarly? JRST [ PUSHJ Q,CPOPJ ;OK, wait a while JRST MGWRIT ] ;Then go back and try again MOVEM W,MGUNIT ;Set unit HRREI B,-MGNRTY ;Number of retries MOVEM B,MGERRC(W) ;Store error count MTDEQB A ;Get buffer to write off list MOVEM A,MGCABN(W) ;Note this buffer active at PI LDB B,[MWC,,MEMBLT(A)] ;Get word count from buffer MOVNS B ;B -> -COUNT HRLZS B ;B -> -COUNT,,0 IFN KL10P,LSH B,4 ;Shift if KL10 data channel IFN KL10P,MOVE R,A ;Save core page number for cache sweep IFE TM03S,[ ;TM03S IOWD is -COUNT,,ITS PAGE LSH A,10. ;Convert buffer number to memory address SUBI A,1 ;Address - 1 ] HRRM A,B ;B -> -COUNT,,ADDRESS-1; an IO word IFN TM10B,DATAO MTS,[MICWA] ;Tell DF10 where IO channel program is IFN TM10A,PUSHJ Q,MGDCSO ; MOVEM B,MIOWD ;Put IO word where controller looks MOVEM B,LMIOWD ;Remember what we're about to do IFN TM10P,SETZM MIOWD+1 ;Stop after one operation IFN KL10P,[ PUSHJ P,CSHSWP ;Unload buffer from cache into core CAI ] MGWRT2: IFN TM10P,[ MOVE B,MTCONO(W) ;Get prototype CONO word CONO MTC,MWRITE(B) ;Perform WRITE operation ] IFN TM03S,[ HLRE A,MIOWD ;Get PDP10 word count ASH A,1 ; * 2 IOWRI A,%TMWC ; = number of unibus words to transfer HLRE A,MIOWD ;Get PDP10 word count again IMUL A,MTWTFC(W) ;Convert to tape frame count IOWRI A,%TMFC ;Set tape frames to write HRRZ A,MIOWD ;Get ITS page to transfer to LSH A,1 ;Convert ITS pg # to DEC pg # TXO A,%UQVAL ;Valid mapping, I should hope IOWRI A,UBAPAG+IUTPG_1 ;Set up first half of UBA mapping TXO A,1 ;Next DEC page number IOWRI A,UBAPAG+IUTPG_1+1 ;Set second half of UBA mapping MOVEI A,IUTPG_14 ;Unibus address to DMA to IOWRI A,%TMBA ;Tell controller MOVX A,%TM1IE\%TMWRT ;Write, enable interrupts IOWRI A,%TMCS1 ;Start controller ] PUSHJ Q,MGWTJD ;Wait for job done JRST MGWERR ;Error, go attempt to repair ;Here if tape written OK MGWRT3: MOVE A,MGCABN(W) ;Get buffer number HRLZI B,%MAETW+%MAERR ;End of tape check IFN TM10P,TXNE J,%T1SET ;Controller says we're at EOT? IFN TM03S,TTNE FS,%TMSET IORM B,MSRAC(W) ;Tell MP LDB T,[MUR,,MEMBLT(A)] ;Get buffer flavor from buffer CAIE T,MUMGB ;Still a magtape buffer? BUG HALT,[MT BUF CHANGED INTO SOME OTHER KIND??] SETOM MGCABN(W) ;No buffer active at PI anymore PUSHJ P,IMEMR ;Return buffer to system MOVSI A,%MAMSO ;Note tape has moved since open IORM A,MSRAC(W) ;JRST MGCMDR ;Falls through ;General exit routine for most PI-level command handlers ; Check command queue for more commands. ; If no further commands, dismiss interrupt. ; If further commands queued, wait for this one to finish, then fetch ; and begin processing of next command. ; MGCMDR: SOS MSCMDC(W) ;Decrement command count SETOM MGUNIT ;Reset active unit SKIPG MSCMDC(W) ;Any more commands? JRST MGCMR1 ;No. Go see about other units IFN TM10P,[ MOVE B,MTCONO(W) CONO MTC,MNOPIN(B) ;Tell controller to interupt when unit ready MOVEM W,MGUNIT ;Set up unit number again for MGWTJD PUSHJ Q,MGWTJD ;Go wait for unit to finish current command JRST MGERR ;Oops SETOM MGUNIT ;No unit waiting any more ];IFN TM10P POPJ Q, ;Return on Q PDL. Most likely this will ; transfer control to MGNCMD routine at ; base of PDL, which will fetch and execute ; next command. MGCMR1: IFN NMTCS-1,[ ;Ought to check other transports for commands to start. ; For now, will get started by 1/2 second timeout, if nothing else. .ERR Unfinished multi-transport code at MGCMR1 ];IFN NMTCS-1 POPJ P, ;No more, return on P to dismiss interrupt ;CONTROLLER DETECTED ERROR ON WRITE OPERATION ; Retry, or give up, or write some blank tape and then try again, ; depending on the type of error. ; MGWERR: IFN TM10P,[ IFN TM10B,SETZM MIOWD ;Seems to do one record anyway IFN TM10A,[ MOVE A,[-1,,MGVTC-1] MOVEM A,MIOWD ;Specify one record to space back cmd. ] TXNE J,%T1STH\%T1SRW\%T1SIO\%T1SET\%T1SWL ;Bad types of errors JRST MGERR ;OK, give up AOSL MGERRC(W) ;Still retrying? JRST MGERR ;No, give up MOVE B,MTCONO(W) CONO MTC,MSPRR(B) ;Space reverse one record PUSHJ Q,MGWTJD ;Wait for job done JRST MGERR ;Error MOVE B,LMIOWD ;Get last operation's IOWD MOVEM B,MIOWD ;We're going to try it again MOVE B,MTCONO(W) ;Get prototype CONO CONO MTC,14000(B) ;Write with extended EOR gap PUSHJ Q,MGWTJD ;Wait for completion JRST MGWBT ;Lost again, retry some more JRST MGWRT3 ;Worked, return to normal write sequence ];IFN TM10P IFN TM03S,[ TTNE ERR,%TMERM\%TMEUS\%TMEFS\%TMEIR\%TMEIF\%TMEMC\%TMECT\%TMENX\%TMEOI JRST MGERR ;Fatal errors TTNN FS,%TMSOL ;On line? JRST MGERR ;This isn't so good either TTNE ERR,%TMEFC\%TMENG\%TMEMD\%TMEIC\%TMECE\%TMECS\%TMEFL JRST MGWER1 ;Error which retrying might fix ;Formatter seems happy. Check channel status before returning ; Currently this only catches the case where there was an RH11 error ; but no TM03 error, and thus should always end up jumping to MGERR. ; Formatter errors on which it might be OK to get here are %TMECE, ; %TMECS, %TMEFL, but someone needs to test this... TTNE CS1,%TM1TE ;Transfer error? TTNE FS,%TMSES ;And not formatter error? CAIA JRST MGERR ;Just lose for now BUG INFO,[MT: ACCEPTING QUESTIONABLE WRITE OPERATION] JRST MGWRT3 ;Retry errors MGWER1: AOSL MGERRC(W) ;Still retrying? JRST MGERR ;No, give up BUG INFO,[MT: RETRYING WRITE OPERATION] PUSHJ P,TMINIC ;Hit controller with hammer MOVEI B,1 MOVEM B,MGSPCD(W) ;1 record PUSHJ Q,MGSPCR ;Reselect transport space back a record TTNE FS,%TMSTM ;Stopped on EOF? SOSGE MGEOFR(W) ;Yes, one less EOF in front of us SETZM MGEOFR(W) ;But never less than zero PUSHJ P,TMINIC ;Hit controller with hammer again PUSHJ Q,MGGXPT ;Set up transport again MOVEI B,%TMER3\%TM1IE IOWRI B,%TMCS1 ;Erase a few inches of tape PUSHJ Q,MGWTJD ;Wait for job done JRST MGERR ;Can't get anything right... MOVE B,LMIOWD ;Get last operation's IOWD MOVEM B,MIOWD ;We're going to try it again JRST MGWRT2 ;Go back to write code and retry operation ];IFN TM03S SUBTTL MAG TAPE PI LEVEL READ MGREAD: PUSHJ Q,MGGXPT ;Select desired transport MGRD0: IFN TM10P,[ TXNE J,%T1STH\%T1SRW\%T1SET ;Unit hung, rewinding, or EOT JRST MGERR ;Seems so, report error ] IFN TM03S,[ TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation ] MOVE B,MGEOFR(W) ;EOF's seen since last read CAIL B,2 ;Apparent logical EOT? JRST MGERR ;Yes, can't read anything SKIPE MSCRW(W) ;Make sure open for reading BUG HALT,[MT: CHN NOT OPEN FOR READING] MOVSI B,%MACTH ;Core allocator wants to wait? TDNN B,MSRAC(W) ;Check in status word PUSHJ P,IOMQ ;No, get a buffer JRST [PUSHJ Q,CPOPJ ;Wanted to wait some or failed, JRST MGREAD ] ; wait a while, then start over MOVEM A,MGCABN(W) ;Note active buffer at PI level MOVEI B,MUMGB DPB B,[MUR,,MEMBLT(A)] ;Note buffer belongs to mag tape code MOVEM W,MGUNIT ;Set active unit number HRREI B,-MGNRTY ;Number of retries MOVEM B,MGERRC(W) ;Store error count IFN KL10P, MOVE R,A ;Get page for cache flush routine IFE TM03S,[ ;TM03S IOWD is -COUNT,,ITS PAGE LSH A,10. ;Convert buffer number to memory address SUBI A,1 ;address-1 ] IFE KL10P,HRLI B,-2000 ;Get count half of IOWD IFN KL10P,HRLI B,-2000_4 ;The KL is, of course, different HRR B,A ;-count,,address-1 MOVEM B,LMIOWD ;Remember IOWD for possible retry IFN TM10B,[ DATAO MTS,[MICWA] ;Tell DF10 where the channel program is SETZM MICWA+1 ;Stop after one operation ] IFN TM10A,PUSHJ Q,MGDCSI IFN TM10P,SETZM MIOWD+1 MGRD1: MOVEM B,MIOWD ;Save IOWD where channel expects it MOVEI B,2000 ;Assume for now that the record has 2K words MOVEM B,MGNWRD ;Set up word count IFN KL10P,[ PUSHJ P,CSHSWP ;Ensure no residue of this page in cache CAIA ] IFN KS10P,CLRCSH ;KS needs cache invalidated on read IFN TM10P,[ MOVE B,MTCONO(W) ;Get prototype CONO word CONO MTC,MREAD(B) ;Issue READ command ] IFN TM03S,[ HLRE A,MIOWD ;Get PDP10 word count ASH A,1 ; * 2 IOWRI A,%TMWC ; = number of unibus words to transfer SETZ A, ;Set FC to zero IOWRI A,%TMFC ;Set tape frames to write HRRZ A,MIOWD ;Get ITS page to transfer to LSH A,1 ;Convert ITS pg # to DEC pg # TXO A,%UQVAL IOWRI A,UBAPAG+IUTPG_1 ;Set up first half of UBA mapping TXO A,1 ;Next DEC page number IOWRI A,UBAPAG+IUTPG_1+1 ;Set second half of UBA mapping MOVEI A,IUTPG_14 ;Unibus address for DMA IOWRI A,%TMBA ;Tell controller MOVX A,%TM1IE\%TMRDF ;Read forward, enable interrupts IOWRI A,%TMCS1 ;Start controller ];IFN TM03S IFN TM10B,SETOM MGWCW ;Tell MGWTJD to wait for control word written PUSHJ Q,MGWTJD ;Wait for command to complete JRST MGRERR ;Error, go do something. May be retry, correct ; MGNWRD if frame count error, or give up IFN TM03S,[ ;Get true record size for TM03, which doesn't give a FC error on READ MGRD1A: TTNE FS,%TMSTM ;Read a tape mark? JRST [ SETZM MGNWRD ;Read a tape mark. No data, just EOF JRST MGRD2 ] IORDI A,%TMFC ;Get record size in tape frames ADD A,MTWTFC(W) ;Round up to PDP10 words. SUBI A,1 ;Add frames_per_word - 1 IDIV A,MTWTFC(W) ;Get record size in PDP10 words MOVEM A,MGNWRD ];IFN TM03S ;Here if OK or error handler has fixed things up MGRD2: MOVE A,MGCABN(W) ;Get buffer we just wrote SETOM MGCABN(W) ;No buffer active at PI level MTENQB A ;Queue buffer up for MP level MOVE B,MGNWRD ;Get number of words we read DPB B,[MWC,,MEMBLT(A)] ;Set number of words in buffer IFN TM10P,TXNE J,%T1SEF ;Read an EOF? IFN TM03S,TTNE FS,%TMSTM ; i.e. a tape mark? IFSKP. SETZM MGEOFR(W) ;No. Note no EOFs read since last record ELSE. MOVSI B,%MAESO+%MAEFA ;EOF seen since open, EOF read ahead IORM B,MSRAC(W) ;Note this in transport status word SETO B, DPB B,[MSEOFP,,MEMBLT(A)] ;Set EOF flag in this buffer AOS A,MGEOFR(W) ;Count EOFs CAIL A,2 ;Enough for EOT? JRST MGRD4 ;Logical EOT, space back over it ENDIF. MOVSI A,%MAMSO IORB A,MSRAC(W) ;Note tape movement IFN TM10P,TXNE J,%T1SET ;Real EOT reached? IFN TM03S,TTNE FS,%TMSET JRST MGRD3 MOVE C,MSNBOL(W) ;Get count of buffers on list IFN TM10P,TXNN J,%T1SEF ;EOF? IFN TM03S,TTNN FS,%TMSTM ; CAIL C,6 ; or read ahead six records? JFCL ;Or just for the hell of it JRST MGRD5 ;Yes, stop reading TLNN A,%MASTP ;Somebody request we stop? JRST MGRD0 ;No, go back and read another record ;Yes, fall through to terminate read ;Here to terminate read command ; MGRD5: MOVSI A,%MASTP+%MARAC ;Clear read active, any read stop request ANDCAM A,MSRAC(W) JRST MGCMDR ;Go to standard command return routine ;Controller saw a real EOT ; MGRD3: DPB B,[MSEOFP,,MEMBLT(A)] ;Fake EOF DPB B,[420100,,MSRAC(W)] .SEE %MAETR ;Indicate EOT on read JRST MGRD5 ;Terminate read ;Here if logical EOT (two EOF's in a row) ; Back up till between the two EOF's ; MGRD4: MOVSI A,%MAESO+%MARAC+%MASTP ;SECOND EOF, LOGICAL EOT ANDCAM A,MSRAC(W) JRST MGSPRF ;Space reverse one file ;Error detected on read. ; Analyze error, retry read if it might help ; MGRERR: IFN TM10P,[ IFN TM10B,[ TXNE J,%T1SCP\%T1SNM\%T1SDP JRST MGERR ;Channel error, forget it ] TXNE J,%T1STH\%T1SRW\%T1SIO\%T1SRC ;Hard error? JRST MGERR ;Yes, abandon read TXNE J,%T1SPE\%T1SDL%T1SBT ;Parity, data-late, or bad tape? JRST MGMRT ;Yes, a read retry might fix it TXNN J,%T1SRL ;Record length error? JRST MGERR ;No, who knows what is going on ;Here if record length error. Adjust MGNWRD to reflect data actually read ; IFN TM10B,HRRZ A,MICWA+1 IFN TM10A,HRRZ A,MIOWD ;Get final control word HRRZ B,LMIOWD ;Get original IOWD SUB A,B ;Calculate words read IFN TM10B,SOS A ;Channel funnyness CAIE A,1 ;Length of 1 may just be EOF indication IFSKP. TXNE J,%T1SEF\%T1SET ;1 word, EOF? EOT? SETZM A ;Yes, zero length record, just carries MSEOFP ENDIF. MOVEM A,MGNWRD ;Save new record length JRST MGRD2 ;Go process as potentially correctly read data ];IFN TM10P IFN TM03S,[ TTNE ERR,%TMERM\%TMEUS\%TMEFS\%TMEIR\%TMEIF\%TMEMC\%TMECT\%TMENX JRST MGERR ;Fatal errors TTNN FS,%TMSOL ;On line? JRST MGERR ;This isn't so good either TTZ ERR,%TMEFC\%TMENG ;Ignore NSG, Frame count error TTNE FS,%TMSPE ;Phase encoded (1600BPI) mode? TTZ ERR,%TMECE\%TMECS ;If so, ignore errors hardware already fixed TTZN ERR,%TMECE\%TMECS\%TMEFC\%TMENG\%TMEFL\%TMEMD\%TMEIC ;Retryable? JRST MGRER1 ;Nothing retrying will help TTNE FS,%TMSTM ;Tape mark? JRST MGRER2 ;Yes, no point in retrying JRST MGMRT ;OK, go retry read ;Formatter seems happy. Check channel status before returning MGRER1: TTNE ERR,177777 ;Sanity check. Shouldn't be any errors left JRST MGERR TTNE CS1,%TM1TE ;Transfer error? TTNE FS,%TMSES ;And not formatter error? CAIA JRST MGERR ;Just lose for now MGRER2: JRST MGRD1A ];IFN TM03S ;Retry a read operation ; MGMRT: AOSL MGERRC(W) ;Still retrying? JRST MGERR ;No, give up IFN TM10P,[ IFN TM10B,SETZM MIOWD IFN TM10A,[ MOVE A,[-1,,MGVTC-1] ] MOVEM A,MIOWD ;One record PUSHJ Q,MGDCSO MOVE B,MTCONO(W) CONO MTC,MSPRR(B) ;Back up one record PUSHJ Q,MGWTJD ;Wait till done JRST MGERR ;No errors allowed IFN TM10A,PUSHJ Q,MGDCSI ;Put back PI 1 BLKI ];IFN TM10P IFN TM03S,[ IORDI T,%TMFS ;Get current formatter status TXNN T,%TMSES ;Showing error? IFSKP. ;Have to clear it before backing up MOVEI A,10. ;Try 10 times to clear drive MOVEI B,%TMCLR DO. IOWRI B,%TMCS1 ;Write drive clear command IORDI T,%TMFS ;Get status TXNN T,%TMSES ;Still have error JRST ENDLP. ;No, done SOJG A,TOP. ;Retry up to 10 times JRST MGERR ;Else give up ENDDO. ENDIF. MOVE T,MTSELW(W) ;Get desired settings IOWRI T,%TMTC ;Tell TM03 SETO A, IOWRI A,%TMFC ;1 record MOVEI A,%TM1IE\%TMSPR ;Space backwards command IOWRI A,%TMCS1 ;Do it PUSHJ Q,MGWTJD ;Wait till finished JRST MGERR ;Give up if error ];IFN TM03S MOVE B,LMIOWD ;Get IOWD from last command JRST MGRD1 ;Try operation again SUBTTL MAG TAPE PI LEVEL SPACING COMMANDS ;Space forward and space reverse are completely under conditionals IFN TM03S,[ ;Space forward MGSPCD(W) records MGSPCF: PUSHJ Q,MGGXPT ;Acquire transport TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation MOVEM W,MGUNIT ;Note active transport MOVN A,MGSPCD(W) ;Get -count IOWRI A,%TMFC ;Tell controller MOVEI A,%TMSPF ;Get command TXO A,%TM1IE ;Turn on interrupts IOWRI A,%TMCS1 ;Start controller PUSHJ Q,MGWTJD ;Wait till command completes IFNSK. ;Error? TTNE CS1,%TM1MP ;Control parity err? JRST MGERR ;Yes, nothing else valid TTNE FS,%TMSES ;Formatter errors? IFSKP. PUSHJ P, TMINIC ;No formatter errors, ignore RH errors ELSE. TTNN ERR,%TMEFC ;Frame count error? JRST MGERR ;Nope, must be important PUSHJ P,TMINIC ENDIF. ENDIF. POPJ Q, ;Space forward record MGSPFR: MOVEI B,1 ;Do one record MOVEM B,MGSPCD(W) ;Set count MOVSI B,%MAMSO ;Note this command causes tape movement IORM B,MSRAC(W) ;Set in transport software status PUSHJ Q,MGSPCF ;Do spacing op TTNN FS,%TMSTM SETZB B,MGEOFR(W) ;Count EOFs since last record. None here TTNE FS,%TMSTM AOS B,MGEOFR(W) ;Saw one. CAIL B,2 ;Saw two? JRST MGSPRR ;Back up over last one... JRST MGCMDR ;Clean up and leave ;Space forward file MGSPFF: MOVSI B,%MAESO ;See if tape has already read ahead to EOF TDZE B,MSRAC(W) JRST MGCMDR ;EOF already read during the read, done MOVEI B,1 ;Do one record MOVEM B,MGSPCD(W) ;Set count MOVSI B,%MAMSO ;Note this command causes tape movement IORM B,MSRAC(W) ;Set in transport software status PUSHJ Q,MGSPCF ;Space forward one record TTNN FS,%TMSTM IFSKP. ;Saw a TM AOS B,MGEOFR(W) ;Saw one. CAIL B,2 ;Saw two? JRST MGSPRR ;Yes, back up over last one, and leave JRST MGCMDR ;No, OK, but we're done ENDIF. SETZB B,MGEOFR(W) ;No tape mark, reset count of EOFs seen MGSPF1: MOVEM B,MGSPCD(W) ;Set count to 0 (B zero from above) PUSHJ Q,MGSPCF ;Do it TTNE FS,%TMSTM ;Saw a EOF? IFSKP. ;No.. TTNE FS,%TMSET ;Saw an EOT? JRST MGERR ;Really shouldn't happen JRST MGSPF1 ;Else go look for TM again ENDIF. AOS MGEOFR(W) ;Saw one. JRST MGCMDR ;EOF read. done ;Space reverse MGSPCD(W) records MGSPCR: PUSHJ Q,MGGXPT ;Set up transport and get status TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation TTNE FS,%TMSBT ;At BOT? POPJ Q, MOVEM W,MGUNIT ;Save selected transport MOVN A,MGSPCD(W) ;Get -count IOWRI A,%TMFC ;Tell controller MOVEI A,%TMSPR ;Space Reverse command TXO A,%TM1IE ;Turn on interrupts IOWRI A,%TMCS1 ;Start controller PUSHJ Q,MGWTJD ;Wait till command completes IFNSK. ;Error? TTNE CS1,%TM1MP ;Control parity err? JRST MGERR ;Yes, nothing else valid TTNE FS,%TMSES IFSKP. PUSHJ P,TMINIC ELSE. TTNN ERR,%TMEFC ;Frame count error? JRST MGERR ;Nope, must be important PUSHJ P,TMINIC ENDIF. ENDIF. POPJ Q, ;Space reverse one record MGSPRR: MOVEI B,1 MOVEM B,MGSPCD(W) ;1 record MOVSI B,%MAMSO ;Note this command causes tape movement IORM B,MSRAC(W) ;Set in transport software status PUSHJ Q,MGSPCR TTNE FS,%TMSTM ;Stopped on EOF? SOSGE MGEOFR(W) ;Yes, one less EOF in front of us SETZM MGEOFR(W) ;But never less than zero JRST MGCMDR ;Leave through general exit ;Space reverse fill MGSPRF: MOVSI B,%MAESO ;See if tape has already read ahead to EOF TDNN B,MSRAC(W) JRST MGSPR2 ;No, we can just do command MGSPR1: MOVEI B,1 MOVEM B,MGSPCD(W) PUSHJ Q,MGSPCR ;Skip back 1 record, should backup over EOF TTNN FS,%TMSTM ;Tape mark seen? JRST MGSPR1 ;Well, apparently not MOVSI B,%MAESO ANDCAM B,MSRAC(W) ;Turn off EOF-read-ahead flag MGSPR2: SETZ B, MOVEM B,MGSPCD(W) ;Space backwards the maximum number of records PUSHJ Q,MGSPCR ;Do it TTNN FS,%TMSBT ;BOT? TTNE FS,%TMSTM ;Tape mark seen? JRST MGCMDR ;Yes or Yes, all done JRST MGSPR2 ;No, go back and try to find one. ];End TM03S way back ;Rewind commands ; MGRWND: IFN TM10P,MOVEI B,MREWND ;Normal rewind IFN TM03S,MOVEI B,%TMREW CAIA MGRWDM: IFN TM10P, MOVEI B,MRWNDD ;Rewind and dismount IFN TM03S, MOVEI B,%TMUNL MOVEM B,MGSPCD(W) ;Set up command PUSHJ Q,MGRWD1 ;Call action routine JRST MGCMDR ;Action routine for rewind commands MGRWD1: PUSHJ Q,MGGXPT IFN TM03S,[ TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation ] MOVEM W,MGUNIT MOVE B,MGSPCD(W) ;Get desired command IFN TM10P,[ ADD B,MTCONO(W) CONO MTC,(B) ] IFN TM03S,[ TXO B,%TM1IE IOWRI B,%TMCS1 ] PUSHJ Q,MGWTJD ;Start controller and wait till done IFNSK. TTNE FS,%TMSES JRST MGERR ;Oops. ENDIF. SETZM MGEOFR(W) ;Seen no EOFs since last record ;Here after rewind command has started. ; Two possibilities: Tape is rewound already, or controller is finished ; but tape is still rewinding. IFN TM10P,[ MGRWD2: TXNN J,%T1SRW ;Slave still rewinding tape? JRST MGRWD3 ;No, at BOT PUSHJ Q,CPOPJ ;Wait some. CONI MTS,J ;Get status again MOVEM J,MGCMTS(W) ;Update in memory JRST MGRWD2 ;Go see if we're done yet. ;Here when tape has rewound MGRWD3: MOVE T,TIME ;Wait 1 second more ADDI T,30. ;This is an attempt to fix a hardware bug MOVEM T,MGJDTI MGRWD4: MOVE T,TIME CAML T,MGJDTI ;Check time JRST MGRWD5 ;Finished waiting, go clean up PUSHJ Q,CPOPJ ;No, wait some more JRST MGRWD4 MGRWD5: MOVSI A,%MAMSO+%MAREW ANDCAM A,MSRAC(W) ;Say not rewinding, hasn't moved SETZM MGJDTI ;Clear timeout POPJ Q, ];IFN TM10P IFN TM03S,[ ;This could be a lot smarter; should dismiss the command completely ; after rewind is started, and just scan for rewinding transports ; when a SSC interrupt is received. This change is also necessary ; to make multiple slaves work right; currently the rewinding unit ; holds active unit (MGUNIT) until the rewind is completed. MGRWD2: TTNN FS,%TMSPP ;Transport still rewinding? JRST MGRWD3 ;No, go finish up PUSHJ Q,CPOPJ ;Dismiss interrupt, wait a while PUSHJ Q,MGGXPT ;Get right slave, set up status JRST MGRWD2 MGRWD3: MOVSI A,%MAMSO+%MAREW ANDCAM A,MSRAC(W) ;Say not rewinding, hasn't moved POPJ Q, ];IFN TM03S ;SKIP TO LOGICAL EOT ; MGSEOT: PUSHJ Q,MGGXPT ;Get transport IFN TM10P,[ TXNE J,%T1STH\%T1SRW ;Hung or rewinding? JRST MGERR ] IFN TM03S,[ TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation ] MOVEM W,MGUNIT ;Set active unit IFN TM10P,TXNE J,%T1SBT ;BOT? IFN TM03S,TTNE FS,%TMSBT JRST MGVTCK ;Yep, do virgin tape check ;Not at BOT ; Do we have enough CONDITIONALS yet? MGNVT: IFN TM10P,[ MOVE B,MTCONO(W) ;Get CONO word IFN TM10A,[ PUSHJ Q,MGDCSO MOVE A,[-1,,MGVTC-1] MOVEM A,MIOWD ;Tell it to move one record ] IFN TM10B,SETZM MIOWD CONO MTC,MSPRR(B) ;Space reverse first ];IFN TM10P IFN TM03S,[ SETO B, ;Space backwards one record IOWRI B,%TMFC MOVEI B,%TMSPR\%TM1IE IOWRI B,%TMCS1 ];IFN TM03S PUSHJ Q,MGWTJD ;Wait till done IFNSK. TTNE FS,%TMSES JRST MGERR ENDIF. SETZM MGEOFR(W) AOS MGEOFR(W) ;Claim to have seen one EOF MGEOT2: IFN TM10P,[ MOVE B,MTCONO(W) CONO MTC,MSPFF(B) ;Skip forward to EOF PUSHJ Q,MGWTJD JRST MGERR ] IFN TM03S,[ AOS MSCMDC(W) ;Kludge so MGSPFF will return here. PUSHJ Q,MGSPFF ;Space forward file ] MOVSI B,%MAETR ;See if we hit real EOT IFN TM10P, TXNE J,%T1SET IFN TM03S, TTNE FS,%TMSET IORM B,MSRAC(W) ;Yep, tell MP IFN TM10P,[ MOVE B,MTCONO(W) IFN TM10A,[ MOVE A,[-1,,MGVTC-1] MOVEM A,MIOWD ;One record ] IFN TM10B,SETZM MIOWD CONO MTC,MSPFR(B) ;Space forward one record ] IFN TM03S,[ SETO B, IOWRI B,%TMFC MOVEI B,%TMSPF\%TM1IE IOWRI B,%TMCS1 ] PUSHJ Q,MGWTJD IFNSK. TTNE FS,%TMSES JRST MGERR ENDIF. MOVSI B,%MAETR ;Check for real EOT again IFN TM10P,TXNE J,%T1SET IFN TM03S,TTNE FS,%TMSET IORM B,MSRAC(W) IFN TM10P,TXNN J,%T1SEF ;Is this another EOF? IFN TM03S,TTNN FS,%TMSTM ;(i.e. a tape mark) JRST MGEOT2 ;No, not at logical EOT. Go try again IFN TM10P,[ MOVE B,MTCONO(W) ;Yes, at logical EOT, Back up over 1 EOF CONO MTC,MSPRF(B) ;Space back one file ] IFN TM03S,[ SETO B, IOWRI B,%TMFC MOVEI B,%TMSPR\%TM1IE IOWRI B,%TMCS1 ] PUSHJ Q,MGWTJD IFNSK. TTNE FS,%TMSES JRST MGERR ENDIF. MOVSI B,%MAEOF+%MAETR ;Tell MP at EOF, EOT IORM B,MSRAC(W) JRST MGCMDR ;Check for virgin tape MGVTCK: MOVE T,TIME ADDI T,60. ;Set a two second timeout MOVEM T,MGEOTT(W) ; before we must see an EOT IFN TM10P,[ IFN TM10B,[ SETZM MIOWD DATAO MTS,[MICWA] ] IFN TM10A,[ MOVE A,[-1,,MGVTC-1] MOVEM A,MIOWD PUSHJ Q,MGDCSO ] MOVE B,MTCONO(W) CONO MTC,MREAD(B) ;Read record. will time out if no EOF marks MGVTC1: CONI MTS,J MOVEM J,MGCMTS(W) TXNE J,%T1SJD ;Job done? JRST MGNVT ;Yep, not virgin tape TXNE J,%T1STH\%T1SIO ;Transport hung or illegal operation? JRST MGERR ;Yes, give up MOVE T,MGEOTT(W) ;Get the timeout value CAMG T,TIME ;Time up? JRST MGVT ;Yes, it's a new tape PUSHJ Q,CPOPJ ;Wait a while JRST MGVTC1 ;Go back and check again ];IFN TM10P IFN TM03S,[ SETO B, IOWRI B,%TMFC ;Do one record MOVEI B,%TMSPF\%TM1IE ;Space forward command IOWRI B,%TMCS1 MGVTC1: IORDI T,%TMCS1 ;Get status TXNN T,%TM1GO ;Still going? IFSKP. ;Yep. MOVE T,MGEOTT(W) ;Get the timeout value CAMG T,TIME ;Time up? JRST MGVT ;Yes, it's a new tape PUSHJ Q,CPOPJ ;Wait a while JRST MGVTC1 ;Go back and check again ENDIF. TXNE T,%TM1TE\%TM1MP ;Controller error? JRST MGERR ;Yes, bad IORDI T,%TMFS ;Get formatter status TXNE T,%TMSES ;Formatter error? JRST MGNVT ;No error, not a new tape IORDI T,%TMERR ;Get formatter error register TXNE T,%TMEFC ;Frame Count error? JRST MGNVT ;Yes, that is probably an OK tape JRST MGERR ;Not FC, must be a real problem ];IFN TM03S ;Virgin tape. Abort operation in progress, rewind tape MGVT: IFN TM10P,[ MOVE B,MTCONO(W) CONO MTS,31 ;Clear controller CONO MTC,MNOPIN(B) ;Start new command to clear things out PUSHJ Q,MGWTJD JFCL ;Ignore errors ] IFN TM03S,[ PUSHJ P,TMINIC ] IFN TM10P,MOVEI B,MREWND ;Do a rewind IFN TM03S,MOVEI B,%TMREW MOVEM B,MGSPCD(W) PUSHJ Q,MGRWD1 SETZM MGEOFR(W) ;No EOFs seen AOS MGEOFR(W) ;??? JRST MGCMDR ;Done ;Write EOT mark (two EOF's) on tape ; MGMEOT: PUSHJ Q,MGGXPT IFN TM10P,[ TXNE J,%T1STH\%T1SRW\%T1SWL ;Hung, rewinding, or write locked... JRST MGERR ] IFN TM03S,[ TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation TTNE FS,%TMSWL ;Transport write locked? JRST MGERR ;Shouldn't happen, we checked at open. ];IFN TM03S MOVEM W,MGUNIT ;Note active unit SKIPE MTCEFW(W) ;Check # of EOF's already written IFSKP. ;None. Need to write two AOS MSCMDC(W) ;Kludge so MGWEOF will return here. AOS MTCEFW(W) ;Increment EOF count PUSHJ Q,MGWEOF ;Write an EOF ENDIF. MOVE A,MTCEFW(W) ;Get EOF count SOSLE A ;Check for at least two EOF's written IFSKP. ;No, need one more on tape AOS MSCMDC(W) ;Again, force MGWEOF to return AOS MTCEFW(W) ;Incr EOF count PUSHJ Q,MGWEOF ;Write EOF ENDIF. MOVE A,MSRAC(W) ;Get transport software status TLNE A,%MANWT ;Are we supposed to back up over last EOF? IFSKP. AOS MSCMDC(W) ;Yes. Force MGSPRF to return, then... PUSHJ Q,MGSPRF ; ...do space reverse file command ENDIF. MOVSI A,%MANWT ;Note what we've done IORM A,MSRAC(W) JRST MGCMDR ;Leave through general exit routine ;Write one EOF mark on tape ; MGWEOF: PUSHJ Q,MGGXPT ;Set up transport for IO IFN TM10P,[ TXNE J,%T1STH\%T1SRW\%T1SWL ;Hung, rewinding, or write locked... JRST MGERR ; ..lose ] IFN TM03S,[ TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation TTNE FS,%TMSWL ;Transport write locked? JRST MGERR ;Shouldn't happen, we checked at open. ] MOVEM W,MGUNIT ;Remember active unit IFN TM10P,[ MOVE B,MTCONO(W) ;Get CONO word for this unit CONO MTC,MWEOF(B) ;Execute Write EOF function ] IFN TM03S,[ MOVEI B,%TM1IE\%TMWTM ;Write tape mark, enable interrupts IOWRI B,%TMCS1 ;Do it ] PUSHJ Q,MGWTJD ;Wait around till command is complete IFNSK. TTNE FS,%TMSES JRST MGERR ENDIF. MOVSI A,%MAMSO IORM A,MSRAC(W) ;Note tape movement in software status JRST MGCMDR ;Return through general exit routine ;Get transport and controller status ; MGSTAT: PUSHJ Q,MGGXPT JRST MGCMDR ;Write some blank space ; MGW3IN: PUSHJ Q,MGGXPT IFN TM10P,[ TXNE J,%T1STH\%T1SRW\%T1SWL ;Hung, rewinding, or write locked... JRST MGERR ] IFN TM03S,[ TTNE FS,%TMSFR ;Formatter ready? TTNN FS,%TMSOL ;Transport on line JRST MGERR ;No or no, can't do operation TTNE FS,%TMSWL ;Transport write locked? JRST MGERR ;Shouldn't happen, we checked at open. ];IFN TM03S MOVEM W,MGUNIT ;Note active transport IFN TM10P,[ ;TM10 can't just write blank space, it has to write blank space followed ; by a data record IFN TM10B,[ SETZM MIOWD ;Tell TM10 to write 1-word record DATAO MTS,[MICWA] ] IFN TM10A,[ MOVE A,[-1,,MGVTC-1] ;1-word record MOVEM A,MIOWD PUSHJ Q,MGDCSO ] MOVE B,MTCONO(W) CONO MTC,MW3IN(B) ;Write date record preceeded by 3-in gap ];IFN TM10P IFN TM03S,[ MOVEI B,%TM1IE\%TMER3 ;Erase 3 inches command, enable interrupts IOWRI B,%TMCS1 ;Do it ];IFN TM03S PUSHJ Q,MGWTJD ;Wait... JFCL ;Ignore errors (really should check kind) IFN TM10P,JRST MGSPRR ;Now space record reverse over the bogus record IFN TM03S,JRST MGCMDR ;TM03 does it right SUBTTL .MTAPE UUO ;.MTAPE AC, ; AC/ CHNM,COMMAND ; COMMAND/ COUNT,,FUNCTION AMTAPE: XCTR XR,[HLRZ R,(J)] ;Get IO channel from user TRNE R,-NIOCHN ;Legal channel? JRST ILUUO ;Lose HRRZM R,UUAC(U) ;Cause errors to report on the correct channel ADDI R,IOCHNM(U) ;Form IOCHNM pointer LDB W,[MTXP(R)] ;Get transport number CAME U,MTUSR(W) ;Same user? POPJ P, ;No, give up XCTR XR,[MOVE J,(J)] ;Get Channel,,Command from user MOVEM J,MTMTAP(W) ;Save it HRRZ A,MTMTAP(W) ;Get address of Count,,Function word PUSHJ P,MTIECK ;Check transport for error states XCTR XR,[MOVE A,(A)] ;Get count,,function from user HRRZM A,MTMFNC(W) ;Store function HLREM A,MTMCNT(W) ; and count SKIPN MTMCNT(W) ;Count of zero always means one, for AOS MTMCNT(W) ; compatibility with the old code. HRRZS A CAIL A,NMTAPC ;Command in range? POPJ P, ;No... AOS (P) ;Command OK, skip return JRST @MTAPDT(A) ;Go do command MTAPDT: MTHANG ;0 Hang till tape motion done MTRWND ;1 Rewind MTRWDM ;2 Rewind and dismount MTWEOR ;3 Write EOR if appropriate MTW3IN ;4 Write 3 inches of blank tape MTWEOF ;5 Write EOF MTSPR ;6 Space records MTSPF ;7 Space files MTSPEOT ;10 Space to EOT MTSTOP ;11 Abort all operations immediately MTSBKS ;12 Set block size (to COUNT) MTRBKS ;13 Read block size (to AC) IFN 0,[ MTRTSW ;14 Read Transport Information (to AC) MTRTEW ;15 Read Tape Error Word (to AC) ] NMTAPC==.-MTAPDT ;Set block size for write ; MTSBKS: MOVE A,MTMCNT(W) ;Desired blocksize CAIL A,4 ;Check reasonableness CAILE A,2000 SOSA (P) ;Fail if too big or too small MOVEM A,MTBLKS(W) ;OK, change write-buffer size POPJ P, ;Read current write blocksize ; MTRBKS: MOVE A,MTBLKS(W) ;Get current write block size JRST APTUAJ ;Return it ;Hang until all motion finished ; MTHANG: SKIPLE MSCMDC(W) ;Check count of queued commands PUSHJ P,UFLS ;Wait if there are any JRST MTIECK ;Done, check for errors and return ;Rewind, Rewind and dismount ; MTRWND: SKIPA B,[MGRWND] ;Get "REWIND" PI level command MTRWDM: MOVEI B,MGRWDM ; or "REWIND and DISMOUNT" if appropriate SKIPE MSCRW(W) ;Writing? JRST MTSOSP ;Yes, error. Go undo skip rtn and exit MOVSI A,%MAREW ;Note rewinding in software status IORM A,MSRAC(W) JRST MTCMD ;Go queue command for PI level ;"Write End of Record" ; This is really the FORCE system call, or should be. ; MTWEOR: SKIPG MTMDN(W) ;MP level have an active buffer? POPJ P, ;No, nothing to do SKIPE MSCRW(W) ;Writing? JRST MTWBFD ;Yes, go write buffer to tape MTSOSP: SOS (P) ;Not writing, error. Undo skip return POPJ P, ;Return ;Write EOF ; MTWEOF: SKIPN MSCRW(W) ;Writing? JRST MTSOSP ;No, can't write EOF. Take error exit PUSHJ P,MTWEOR ;Flush current buffer, if any MOVEI B,MGWEOF ;Get PI level EOF routine AOS MTCEFW(W) ;Increment count of EOF's written MOVSI TT,%MANWT ;Flag something written on tape ANDCAM TT,MSRAC(W) JRST MTCMD ;Queue MGWEOF command for PI level ;Write blank tape ; MTW3IN: SKIPN MSCRW(W) ;Error if tape not open for write JRST MTSOSP MOVEI B,MGW3IN ;Get PI level command SETZM MTCEFW(W) ;No EOF's since last record MOVSI TT,%MANWT ANDCAM TT,MSRAC(W) ;Note written something to tape JRST MTCMD ;Go queue command for PI ;Space records, +=forward, -=back ; MTSPR: SKIPE MSCRW(W) ;Not allowed if writing JRST MTSOSP PUSHJ P,MTFLRA ;Flush read-ahead, find out how far off we are ADD B,C ;Get records tape is ahead of user (EOF=record) MOVNS B ;Subtract this from user's request ADDB B,MTMCNT(W) ;Adjust count JUMPE B,CPOPJ ;If count is now zero, we are done MTSPR1: PUSHJ P,MTCNTR ;Update user's copy in case PCLSR JUMPG B,MTSPFR ;Space forward MOVEI B,MGSPRR ;Get SPACE REVERSE command PUSHJ P,MTCMD ;Queue it AOSGE B,MTMCNT(W) ;Increment count, check if done JRST MTSPR1 ;More POPJ P, ;No more MTSPFR: MOVEI B,MGSPFR ;Get SPACE FORWARD command PUSHJ P,MTCMD ;Queue it SOSLE B,MTMCNT(W) ;Decr count, check if done JRST MTSPR1 ;More POPJ P, ;This routine flushes readahead. Call before doing a spacing operation ; this doesn't actually undo the effect on the drive of the read-ahead. ; It does make sure that read-ahead's effect can't change, then returns ; in B the number of records ahead (non-negative) and in C the number of ; EOF's ahead (0 or 1). If called twice it will return zero the second ; time. Be sure to update your parameters. ; MTFLRA: PUSHJ P,MTCNTR ;Make sure user space is writable first MOVSI B,%MASTP MOVSI T,%MARAC IORM B,MSRAC(W) ;Tell PI-level read routine to stop reading TDNE T,MSRAC(W) ;Wait until PI level actually stops PUSHJ P,UFLS ANDCAM B,MSRAC(W) ;Turn off %MASTP, things are now quiet SKIPLE MSCMDC(W) ;Make sure PI level is completely inactive PUSHJ P,UFLS ;Wait if necessary MOVE B,MSNBOL(W) ;Get # bufs on read list (='s # records ahead) LDB C,[.BP (%MAEFA),MSRAC(W)] ;1 if EOF read ahead MOVSI T,%MAEFA ;Clear read-ahead EOF ANDCAM T,MSRAC(W) JRST MTCBFF ;Go flush read-ahead buffers ;Space files, + = forward, - = back MTSPF: SKIPE MSCRW(W) ;Not allowed if writing JRST MTSOSP PUSHJ P,MTFLRA ;Flush read-ahead MOVN B,C ;Number of files tape is ahead of user ADDB B,MTMCNT(W) ;Adjust desired count JUMPE B,CPOPJ ;If now zero we are done MTSPF1: PUSHJ P,MTCNTR ;Update user's count in case of PCLSR JUMPG B,MTSPFF ;Go do forward if needed MOVEI B,MGSPRF ;Get space reverse file command PUSHJ P,MTCMD ;Queue it AOSGE B,MTMCNT(W) ;Done? JRST MTSPF1 ;Nope POPJ P, MTSPFF: MOVEI B,MGSPFF ;Get space forward file command PUSHJ P,MTCMD ;Do it SOSLE B,MTMCNT(W) ;Count down JRST MTSPF1 ; till done POPJ P, ;Update user's FUNCTION,,COUNT word in case he's PCLSR'd ; MTCNTR: HRRZ A,MTMTAP(W) MOVE T,MTMFNC(W) HRL T,MTMCNT(W) XCTR XW,[MOVEM T,(A)] POPJ P, ;Get Controller status words to I,J ; MTSTAT: SKIPLE MSCMDC(W) ;Wait till commands queued to PI level are done PUSHJ P,UFLS MOVEI B,MGSTAT ;GET STATUS command PUSHJ P,MTCMD ;Give to PI SKIPLE MSCMDC(W) ;Wait till done PUSHJ P,UFLS MOVE I,MGCMTC(W) MOVE J,MGCMTS(W) POPJ P, ;Go to EOT ; MTSPEOT:MOVEI B,MGSEOT ;Get SPACE-TO-LOGICAL-EOT command JRST MTCMD ;Queue it. Note read-ahead doesn't matter here ;Stop whatever we are doing right now ; Very brute-force - throws away all pending commands, read-ahead buffers, etc. ; MTSTOP: CONO PI,UTCOFF ;We are going to mess with buffer lists SETZM MSCMDC(W) ;Poof, no more commands MOVE Q,[-MGQDLL,,MGQD0-1] ;Reset Q PDL pointer to base of stack MOVE T,MSLCTB IMUL T,W ADD Q,T MOVEM Q,MGQDLP(W) MOVE Q,[-MSCBL-1,,MSCB0-1] ;Reset command queue input pointer ADD Q,T MOVEM Q,MTCMBP(W) MOVE Q,[4400,,MSCB0-1] ;Reset command queue output pointer ADD Q,T MOVEM Q,MGCMBP(W) SKIPL A,MTMDN(W) ;Buffer active at MP level? PUSHJ P,IMEMR ;Yes, release it SETOM MTMDN(W) ;No buffer active at MP level SETZM MSMPRP(W) ;Zero MP pointer into current buffer SETZM MSMPRC(W) ;Zero count of available words in buffer PUSHJ P,MTCBFF ;Flush any buffers queued for PI level CAME W,MGUNIT ;Is interrupt level waiting for this unit? JRST UTCONJ ;No, all set SETOM MGUNIT ;Yes, say no unit waiting for interrupt. ;(Makes interrupt go away w/out doing anything) IFN TM10P,[ CONI MTC,I ;See what drive controller thinks it's using LDB B,[MUNITF,,I] CAME W,B ;Same as the drive we're clearing? JRST UTCONJ ;If not same unit, don't do anything MOVE B,MTCONO(W) ;Yes, abort operation in progress CONO MTS,31 ;Stop the tape CONO MTC,(B) ;Clear interupts ];IFN TM10P IFN TM03S,[ IORDI B,%TMTC ANDI B,7 ;Get selected transport CAME W,B ;Same? JRST UTCONJ PUSHJ P,TMINIC ;Yes, go reinit controller ];IFN TM03S SKIPGE A,MGCABN(W) ;Any buffers active at PI level? JRST UTCONJ ;No PUSHJ P,IMEMR ;Yes, return buffer to system SETOM MGCABN(W) ;Say no buffer active at PI level JRST UTCONJ ;Leave