Google
 

Trailing-Edge - PDP-10 Archives - BB-L288A-RM - swskit-changed-sources/magtap.mac
There are 58 other files named magtap.mac in the archive. Click here to see a list.
;TCO 4.1.1119 - MAKE CHANGES REQUIRED BY RP20 DISKS
;<4.MONITOR>MAGTAP.MAC.249,  3-Jan-80 08:09:30, EDIT BY R.ACE
;UPDATE COPYRIGHT DATE
; UPD ID= 65, SNARK:<4.MONITOR>MAGTAP.MAC.248,  30-Nov-79 10:35:09 by MILLER
;TCO 4.2586. CLEAR BUFFER WORDS IN MTAFLA
;<4.MONITOR>MAGTAP.MAC.247, 25-Oct-79 21:30:33, EDIT BY DBELL
;TCO 4.2552 - CHECK FOR ERRORS WHEN SPACING OR BACKSPACING FILES
;<4.MONITOR>MAGTAP.MAC.246,  4-Oct-79 15:57:05, EDIT BY MURPHY
;FIX BUG INTRODUCED BY PREVIOUS EDIT
;<4.MONITOR>MAGTAP.MAC.245, 20-Sep-79 15:46:42, EDIT BY HALL
;DUMPI AND DUMPO - APPLY PCS
;<OSMAN.MON>MAGTAP.MAC.1, 10-Sep-79 15:42:27, EDIT BY OSMAN
;TCO 4.2412 - Move definition of BUGHLTs, BUGCHKs, and BUGINFs to BUGS.MAC
;<4.MONITOR>MAGTAP.MAC.243, 11-Aug-79 22:26:53, EDIT BY ZIMA
;TCO 4.2387 - FIX BKUPDF BUGHLTS CAUSED BY DUMPO OF NONEXISTENT FILE PAGES
;<4.MONITOR>MAGTAP.MAC.242, 30-Jul-79 10:26:35, EDIT BY MILLER
;ONE MORE TRY. MAKE .MOCLE AND .MONOP REQUIRE MTA TO BE OPENED.
;<4.MONITOR>MAGTAP.MAC.241, 25-Jul-79 15:10:44, EDIT BY MILLER
;MOVE MTMTP1 LABEL TO INCLUDE CALLS TO MTACLW AND UPDSTS
;<4.MONITOR>MAGTAP.MAC.240, 11-Jun-79 19:18:21, EDIT BY MILLER
;MAKE FORWARD FILE RECOVER READ AHEAD BEFORE PROCEEDING.
;<4.MONITOR>MAGTAP.MAC.239, 11-Jun-79 09:34:09, EDIT BY MILLER
;MORE TCO 4.2281. FIX MTDIND TO DETECT RECORD LENGTH ERROR
;<4.MONITOR>MAGTAP.MAC.238, 10-Jun-79 14:21:53, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.237,  9-Jun-79 16:28:48, EDIT BY MILLER
;TCO 4.2281. ALLOW GDSTS TO RETURN STATUS OF LAST CALL, NOT NECESSARILY CURRENT
; STATUS
;<4.MONITOR>MAGTAP.MAC.236, 17-May-79 17:22:40, EDIT BY MILLER
;MAKE MTFLSH INTERNAL FOR USE BY TAPE
;<4.MONITOR>MAGTAP.MAC.235,  4-May-79 10:17:48, EDIT BY MILLER
;ALLOW MTOPR CODES 0 AND 31 EVEN IF MTA NOT OPENED
;<4.MONITOR>MAGTAP.MAC.234,  4-May-79 08:57:15, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.233, 20-Mar-79 13:53:05, EDIT BY MILLER
;FIX MTDIRQ TO PRE-WRITE PAGES FOR DUMPI
;<4.MONITOR>MAGTAP.MAC.232,  4-Mar-79 18:24:30, EDIT BY KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
;<4.MONITOR>MAGTAP.MAC.231,  2-Mar-79 11:18:27, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.230,  1-Mar-79 17:26:18, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.229,  1-Mar-79 12:42:48, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.228,  1-Mar-79 12:05:37, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.227,  1-Mar-79 11:41:30, EDIT BY MILLER
;HANDLE READ AHEAD ERRORS WHEN DOING BACKSPACING
;<4.MONITOR>MAGTAP.MAC.226, 28-Feb-79 18:41:20, EDIT BY MILLER
;ADD MTAFLA
;<4.MONITOR>MAGTAP.MAC.225, 27-Feb-79 15:35:52, EDIT BY HALL
;CHANGE MTAINI TO INIT TAPE WORDS PROPERLY
;<2BOSACK>MAGTAP.MAC.1, 19-Feb-79 21:21:02, EDIT BY BOSACK
;RETURN HARDWARE DETERMINED DENSITY FOR READ DENSITY MTOPR
;<4.MONITOR>MAGTAP.MAC.223, 15-Feb-79 12:29:27, EDIT BY MILLER
;ADD SUPPORT FOR .MORVL. MAKE IT SAME ROUTINE AS .MOREW
;<4.MONITOR>MAGTAP.MAC.222, 10-Jan-79 14:06:40, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.221, 10-Jan-79 13:10:48, EDIT BY MILLER
;ADD CODE TO MTALOC THAT SETS VOLUME SET NAME
;<4.MONITOR>MAGTAP.MAC.220, 28-Dec-78 20:34:06, EDIT BY ZIMA
;TCO 4.2138 - CLEAR RH(AC3) FOR GDSTS
;<4.MONITOR>MAGTAP.MAC.219, 11-Dec-78 17:06:29, EDIT BY MILLER
;DON'T CHECK OFF-LINE OR WRITE-LOCKED IF DRIVE IS A TU7X
;<4.MONITOR>MAGTAP.MAC.218, 26-Nov-78 17:07:38, EDIT BY MILLER
;PASS CURRENT VOLUME NUMBER TO TAPE ON SETMTU FUNCTION
;<4.MONITOR>MAGTAP.MAC.217, 22-Nov-78 07:41:05, EDIT BY MILLER
;FIX MTALOC TO PASS DENSITY ON SETMTU CALL
;<4.MONITOR>MAGTAP.MAC.216, 22-Nov-78 07:33:29, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.215, 19-Nov-78 20:37:24, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.214, 24-Oct-78 14:06:41, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.213, 24-Oct-78 13:10:21, EDIT BY MILLER
;ADD LABELS READING TO MTALOC
;<4.MONITOR>MAGTAP.MAC.212, 23-Oct-78 12:43:31, EDIT BY MILLER
;REMOVE LABEL MTOPRS FROM MTA DISPATCH TABLE
;<4.MONITOR>MAGTAP.MAC.211, 19-Oct-78 14:55:16, EDIT BY R.ACE
;REARRANGED MTOPR DISPATCH TABLE AND LOGIC
;FIXED BUG IN .MOSTA MTOPR FUNCTION
;<4.MONITOR>MAGTAP.MAC.210, 16-Oct-78 09:24:40, EDIT BY MILLER
;MORE FIXES TO MATLOC
;<4.MONITOR>MAGTAP.MAC.209, 12-Oct-78 13:36:05, EDIT BY MILLER
;MAKE .MOLOC NOT REQUIRE JFN TO BE OPENED
;<4.MONITOR>MAGTAP.MAC.208, 12-Oct-78 11:27:17, EDIT BY MILLER
;FIX MTALOC
;<4.MONITOR>MAGTAP.MAC.207, 12-Oct-78 11:24:43, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.206, 11-Oct-78 11:21:46, EDIT BY MILLER
;FIX MTALOC TO PICK UP ARGS PROPERLY
;<4.MONITOR>MAGTAP.MAC.205,  2-Oct-78 13:46:33, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.204,  2-Oct-78 13:45:23, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.203,  2-Oct-78 13:40:43, EDIT BY MILLER
;<4.MONITOR>MAGTAP.MAC.202,  2-Oct-78 13:23:09, EDIT BY MILLER
;CHANGE .MOLOC FUNCTION
;<4.MONITOR>MAGTAP.MAC.201, 22-Aug-78 13:49:29, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.200, 17-Aug-78 21:13:38, EDIT BY PORCHER
;CHANGE "SETBW" TO "MTASBW" AND MAKE IT GLOBAL FOR TAPE
;<4.MONITOR>MAGTAP.MAC.199, 17-Aug-78 10:33:31, EDIT BY R.ACE
;TCO 1986 - FIX .MOSTA TO RETURN DEVICE TYPE CORRECTLY
;<4.MONITOR>MAGTAP.MAC.198, 15-Aug-78 23:58:55, Edit by MCLEAN
;DON'T BLOCK ON MOINF
;<4.MONITOR>MAGTAP.MAC.197, 28-Jul-78 00:00:48, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.196, 22-Jul-78 22:20:41, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.194, 22-Jul-78 22:16:54, Edit by MCLEAN
;TCO 1949 ADD WRITE/READ COUNT
;<4.MONITOR>MAGTAP.MAC.193, 21-Jul-78 14:55:27, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.192, 21-Jul-78 14:52:11, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.191, 21-Jul-78 03:38:17, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.190, 21-Jul-78 03:34:11, Edit by MCLEAN
;TCO 1950 FIX MTAINF SO IT HAS ERJMP AFTER UMOVEM
;<4.MONITOR>MAGTAP.MAC.189, 20-Jul-78 00:38:17, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.188, 20-Jul-78 00:16:34, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.187, 19-Jul-78 11:55:22, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.186, 19-Jul-78 01:34:45, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.185, 19-Jul-78 01:31:57, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.184, 18-Jul-78 14:11:55, Edit by MCLEAN
;FIX MTALN JSYS SO IT IS THE NEW ONE
;<4.MONITOR>MAGTAP.MAC.183, 18-Jul-78 00:41:55, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.182, 18-Jul-78 00:32:19, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.181, 18-Jul-78 00:08:53, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.180, 17-Jul-78 23:50:16, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.179, 17-Jul-78 23:44:13, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.178, 17-Jul-78 23:25:31, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.177, 17-Jul-78 23:23:36, Edit by MCLEAN
;<4.MONITOR>MAGTAP.MAC.176, 17-Jul-78 23:15:58, Edit by MCLEAN
;TCO 1939 PSI FOR ONLINE/OFFLINE MTA'S
;<4.MONITOR>MAGTAP.MAC.175, 14-Jul-78 01:03:35, Edit by MCLEAN
;ADD OPENED CHECK TO MTOPR
;<4.MONITOR>MAGTAP.MAC.174, 13-Jul-78 18:33:16, Edit by ENGEL
;PUT MTMXDM BACK IN MAGTAP WHERE IT BELONGS
;<4.MONITOR>MAGTAP.MAC.173, 12-Jul-78 03:17:58, Edit by MCLEAN
;TCO 1940 STARTED (RETURN TAPE STATUS)
;<4.MONITOR>MAGTAP.MAC.172, 22-Jun-78 14:48:47, Edit by FORTMILLER
;TCO 1925 Fix MTOPR function .MOINF to return Magtape type code
; in word .MOITP
;<4.MONITOR>MAGTAP.MAC.171, 15-Jun-78 15:31:32, Edit by MCLEAN
;TCO 1921 MAKE GDSTS RETURN DEFAULT DENSITY ALWAYS... NO LONGER
;SUPPORTED
;<4.MONITOR>MAGTAP.MAC.170, 14-Jun-78 07:11:04, Edit by JBORCHEK
;DELETE ASSIGNMENT TO MTMXDM, IT IS DONE CORRECTLY IN STG
;<4.MONITOR>MAGTAP.MAC.169,  6-Jun-78 15:11:19, EDIT BY MILLER
;CHECK FOR NEGATIVE CODE IN MAGTAP MTOPR
;<4-NEW>MAGTAP.MAC.168,  1-Jun-78 15:00:53, Edit by FORTMILLER
;ADD DX20 SUPPORT
;<3A.MONITOR>MAGTAP.MAC.7,  4-May-78 05:52:42, Edit by MCLEAN
;TEMP FIX TO REMOVE .MTT16
;<3A.MONITOR>MAGTAP.MAC.6,  2-May-78 23:05:53, Edit by MCLEAN
;PERMIT READ BACKWARDS FOR KS10
;<2BOSACK>MAGTAP.MAC.1, 24-Feb-78 01:41:48, EDIT BY BOSACK
;CHANGE TO NEW DEVICE/DATA ERROR BITS
;<3.SM10-RELEASE-3>MAGTAP.MAC.4,  9-Jan-78 16:29:10, EDIT BY ENGEL
;TCO #1890 FIX INCORRECT RECORD COUNT IN MTOPR .MOINF (REVERSE WORDS 6 AND 7)
;<3.SM10-RELEASE-3>MAGTAP.MAC.2, 13-Nov-77 14:41:03, Edit by MCLEAN
;READ BACKWARDS ILLEGAL ON KS10
;<4.MONITOR>MAGTAP.MAC.163,  5-Nov-77 00:24:01, EDIT BY CROSSLAND
;FIX MTOPR SO YOU CAN GET NUMBER OF HARD ERRORS.
;<4.MONITOR>MAGTAP.MAC.162,  5-Oct-77 10:13:29, Edit by HESS
;TCO 1873 - ADD FUNCTIONS TO MTALN JSYS
;<4.MONITOR>MAGTAP.MAC.161, 19-Aug-77 14:41:58, Edit by HESS
;ADD ROUTINE FOR TAPE TO CALL TO CLEAR EOF AND ABORTF

;COPYRIGHT (C) 1976,1977,1978,1979,1980 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

	SEARCH PROLOG,PHYPAR
	TTITLE MAGTAP

;TEMP EXTERNAL DEFS

	EXTN <SETT20>

;SPECIAL AC DEFINITIONS USED HEREIN

DEFAC (U,Q1)			;UNIT NUMBER
DEFAC (IOS,Q2)			;STATUS BITS FROM MTASTS
DEFAC (STS,P1)			;DEVICE STATUS
DEFAC (JFN,P2)			;JFN
DEFAC (DEV,P4)			;DEVICE DISPATCH ADR


;DEFAULT VALUES FOR MAGTAPES

	MTSPCN==5		;MAX # OF SPACING OPERATIONS AT 1 TIME
	MINREC==4		;MINIMUM # OF WORDS FOR OUTPUT RECORD


;BIT DEFINITIONS FOR LH OF MTASTS

	OPN==1B0		;UNIT HAS BEEN OPENED
	OPND==:1B2		;UNIT WAS OPENED FOR DUMP MODE
	DMPWT==1B3		;WAITING FOR A DUMP MODE OP TO FINISH
	LTERR==1B4		;ERROR OCCURED ON LAST DUMP MODE OPER.
	BUFA==1B5		;BUFFERS HAVE BEEN ASSIGNED
	CLOF==1B6		;CLOSF IN PROGRESS
	MTOWT==1B7		;MTOPR IN PROGRESS
	MTIEL==1B8		;INHIBIT ERROR LOGGING
	MTNOWT==1B9		;DON'T SET MTOWT


;BITS IN RH OF MTASTS (DEFINED IN MONSYM)
;DATA STRUCTURE DEFINITIONS

DEFSTR (MTRS,MTANR1(U),35,18)	;RECORD SIZE IN HARDWARE BYTES
DEFSTR (MTDM,MTANR1(U),17,3)	;DATA MODE
DEFSTR (MTDN,MTANR1(U),14,4)	;DENSITY
DEFSTR (MTSTC,MTANR1(U),10,3)	;CLOSF FUNCTION COUNTER
DEFSTR (MTRBF,MTANR1(U),7,1)	;READING BACKWARDS FLAG
DEFSTR (MTPAR,MTANR1(U),6,1)	;PARITY
DEFSTR (MTFCN,MTANR1(U),5,4)	;LAST FUNCTION PERFORMED
DEFSTR (MTNTM,MTANR1(U),1,2)	;COUNT OF EOF'S WRITTEN
DEFSTR (MTBYT,MTANR2(U),17,18)	;INITIAL LH OF FILBYT
DEFSTR (MTBUF,MTANR2(U),35,18)	;POINTER TO START OF LIST OF BUF PAGES
DEFSTR (MTCUB,MTANR3(U),23,6)	;CURRENT USER BUFFER
DEFSTR (MTCSB,MTANR3(U),17,6)	;CURRENT SERVICE ROUTINE BUFFER
DEFSTR (MTUBW,MTANR3(U),11,6)	;USER BYTES PER WORD
DEFSTR (MTHBW,MTANR3(U),5,6)	;HARDWARE BYTES PER WORD
DEFSTR (MTCUP,MTANR4(U),35,18)	;CURRENT USER PAGE
DEFSTR (MTCIRB,MTANR4(U),17,18)	;CURRENT IORB IN USE
DEFSTR (MTUBP,MTANR5(U),35,18)	;USER BYTES PER PAGE
DEFSTR (MTUBB,MTANR5(U),17,18)	;USER BYTES PER BUFFER
DEFSTR (MTLIRB,MTANR6(U),35,18)	;LAST IORB ADR FOR DUMP MODE
DEFSTR (MTALTC,MTANR6(U),17,18)	;LAST TRANSFER COUNT

DEFSTR (MTNIR,MTARS1(U),35,6)	;# OF IORB'S QUEUED UP
DEFSTR (MTANIR,MTARS1,35,6)	;ABSOULTE VERSION OF MTNIR
DEFSTR (MTPPB,MTARS1(U),29,9)	;NUMBER OF PAGES PER BUFFER
DEFSTR (ABORTF,MTARS1,20,1)	;AN ERROR OCCURED AND IORB'S ABORTED

DEFSTR (IRFLG,MTIRSD,8,9)	;FLAGS FOR USE BY HIGH LEVEL ROUTINE
	MSKSTR (IRBFR,MTIRSD,1B0)	;BUFFER READY FOR USER
	MSKSTR (IRBFQ,MTIRSD,1B1)	;CURRENT BUFFER FLAG
	MSKSTR (IRBFA,MTIRSD,1B2)	;ACTIVE FLAG, IORB BEING FILLED
					; OR EMPTIED BY SERVICE ROUTINE
	MSKSTR (IRBAB,MTIRSD,1B3)	;IORB ABORTED DUE TO AN ERROR
	MSKSTR (IRBFF,MTIRSD,1B4)	;IORB IS FREE
DEFSTR (IRBUN,MTIRSD,17,9)	;UNIT NUMBER
DEFSTR (IRBPB,MTIRSD,35,18)	;POINTER TO BUFFER OF PAGE POINTERS
DEFSTR (IRBOC,MTIRSD+1,35,18)	;ORIGINAL COUNT


DEFINE MTERET (X) <
	IFNB <X>,<
	JRST [	MOVEI A,X
		MOVX IOS,MT%DVE
		IORB IOS,MTASTS(U)
		TQO <ERRF>
		RET]>
	IFB <X>,<
	JRST [	MOVX IOS,MT%DVE
		IORB IOS,MTASTS(U)
		TQO <ERRF>
		RET]>>
;MAGTAPE DISPATCH TABLE

	SWAPCD

MTADTB::DTBDSP (MTASET)		;SET DIRECTORY
	DTBDSP (MTANAM)		;LOOKUP NAME
	DTBDSP (MTAEXT)		;LOOKUP EXTENTION
	DTBDSP (MTAVER)		;LOOKUP VERSION
	DTBBAD (DESX9)		;PROTECTION INSERTION
	DTBBAD (DESX9)		;ACCOUNT INSERTION
	DTBBAD (DESX9)		;STATUS INSERTION
	DTBDSP (MTAOPN)		;OPENF
	DTBDSP (MTASQI)		;BIN/SIN
	DTBDSP (MTASQO)		;BOUT/SOUT
	DTBDSP (MTACLZ)		;CLOSF
	DTBDSP (MTAREN)		;RENAME
	DTBDSP (MTADEL)		;DELETE
	DTBDSP (MTDMPI)		;DUMPI
	DTBDSP (MTDMPO)		;DUMPO
	DTBDSP (MTAMNT)		;MOUNT
	DTBDSP (MTADSM)		;DISMOUNT
	DTBDSP (MTINID)		;INIT DIRECTORY
	DTBDSP (MTMTAP)		;MTOPR
	DTBDSP (MTGTS)		;GETSTS
	DTBDSP (MTSTS)		;SETSTS
	DTBDSP (MTRECO)		;RECORD OUT
	DTBDSP (RFTADN)		;READ TAD
	DTBDSP (SFTADN)		;SET TAD
	DTBDSP (BIOINP)		;SET JFN FOR INPUT
	DTBDSP (BIOOUT)		;SET JFN FOR OUTPUT
	DTBBAD (GJFX49)		;CHECK ATTRIBUTE

	DTBLEN==:.-MTADTB	;GLOBAL LENGTH OF DISPATCH TABLE
;ROUTINE TO INITIALIZE THE MAGTAP DATA STRUCTURES

	SWAPCD

MTAINI::MOVSI A,-MTAN		;SET UP TO INIT UNITS
MTINI2:	SETOM MTALCK(A)		;INIT LOCK WORD
	SETZM MTASTS(A)		;ZERO STATUS WORD ALSO
	SETZM TLABL0(A)		;CLEAR ALL STATUS BITS
	SETZM TLABL1(A)		;CLEAR MT STATUS
	AOBJN A,MTINI2		;LOOP BACK FOR ALL UNITS
	RET			;ALL DONE

;ROUTINE TO MOUNT A MAGTAPE UNIT

MTAMNT:	RETSKP


;ROUTINE TO DISMOUNT A MAGTAPE UNIT

MTADSM:	RETSKP


;ROUTINE TO INITIALIZE THE DIRECTORY OF A MAGTAPE

MTINID:	RETBAD (DESX9)


;ROUTINE TO SET THE DIRECTORY

MTASET:	RETBAD (GJFX32)	;NO FILES IN DIR


;ROUTINE TO LOOKUP A NAME ON A MAGTAPE UNIT

MTANAM:	RETBAD (DESX9)


;ROUTINE TO FIND AN EXTENTION

MTAEXT:	RETBAD (DESX9)


;ROUTINE TO FIND A VERSION

MTAVER:	MOVEI A,0
	RETSKP


;ROUITNE TO DO RENAME ON A MAGTAPE 

MTAREN:	RETBAD (DESX9)


;ROUTINE TO DELETE

MTADEL:	RETBAD (DESX9)
;ROUTINE TO GET MAGTAP STATUS BITS

MTGTS::	HLRZ U,DEV		;SET UP UNIT NUMBER
	CALL UPDSTS		;UPDATE THE STATUS
	 RET			;NEED TO BLOCK
MTGTS0:	HRRZ A,MTASTS(U)	;GET CURRENT STATUS BITS
	LOAD B,MTALTC		;GET LAST TRANSFER COUNT
	XCTU [HRLZM B,3]	;GIVE IT TO USER
	SETZ B,0		;DENSITY (DEFAULT (NO LONGER SUPPORTED))
	DPB B,[POINTR A,MT%DEN]	;DOESNT HANDLE 1600 BPI TOO WELL
	LOAD B,MTPAR		;GET PARITY
	DPB B,[POINTR A,MT%EVP]
	RET			;RETURN WITH STATUS IN A


;ROUTINE TO SET THE MAGTAP STATUS BITS

MTSTS::	STKVAR <MTSTSA,MTSTSE>
	SETZM MTSTSE		;ZERO THE ERROR BIT
	MOVEM A,MTSTSA		;SAVE NEW STATUS SETTING
	HLRZ U,DEV		;SET UP UNIT NUMBER
	CALL UPDSTS		;UPDATE THE STATUS
	 RET			;NEED TO BLOCK
	MOVE A,MTASTS(U)	;GET CURRENT STATUS
	TXNE A,MT%DAE!MT%DVE!MT%IRL!MT%EOF!MT%EOT
	SETOM MTSTSE		;THERE WAS AN ERROR AT START OF THIS
	MOVE A,MTSTSA		;GET BACK NEW SETTING
	ANDI A,MT%DAE!MT%DVE!MT%IRL!MT%EOT!MT%EOF!MT%SER!MT%EVP!MT%DEN
	MOVX B,MT%DAE!MT%DVE!MT%IRL!MT%EOT!MT%EOF!MT%SER!MT%EVP!MT%DEN
	ANDCAM B,MTASTS(U)	;CLEAR BITS BEING SPECIFIED BY USER
	IORB A,MTASTS(U)	;SET BITS FROM USER
	LDB B,[POINTR A,MT%EVP]	;GET PARITY
	STOR B,MTPAR
	HRRZ B,MTCUTB(U)	;GET UDB ADDRESS
	MOVE B,UDBCHR(B)	;GET THE CHARACTERISTICS WORD
	TXNE B,UC.625		;IS DRIVE CAPABLE OF 6250?
	JRST MTSTS2		;YES, DON'T STORE INTO DENSITY FIELD OF UDB
	LDB B,[POINTR A,MT%DEN]	;AND DENSITY (NOT GOOD FOR 1600 BPI)
	SKIPN B			;DEFAULT WANTED
	JRST [	LOAD B,JSMTD	;YES, GET DEFAULT DENSITY
		SKIPN B
		MOVEI B,MTDFDN	;IF NO JOB DEFAULT, USE SYSTEM DEFAULT
		JRST .+1]
	STOR B,MTDN
MTSTS2:	SKIPE MTSTSE		;ANY ERRORS AT START?
	TXNE A,MT%DAE!MT%DVE!MT%IRL!MT%EOT!MT%EOF
	RET			;IF THERE ARE STILL SOME ERRORS, RETURN
	TQZ <ERRF,EOFF>		;CLEAR ERROR FLAGS
	JE ABORTF,(U),R		;IF ABORTF NOT ON ALREADY, DONT CLEAR IT
	SETZRO ABORTF,(U)	;ZERO THE ABORT FLAG
	RET			;AND EXIT
;ROUTINE TO UPDATE MTASTS
;	CALL UPDSTS
;RETURNS +1:	NEEDS TO BLOCK
;	 +2:	OK

UPDSTA:	TDZA C,C		;ALWAYS DO UPDATE
UPDSTS:	MOVEI C,1		;DO NORMAL SEQUENTIAL STUFF
	CALL SETWLK		;GO SET WRITE LOCK BIT CORRECTLY
	JUMPE C,UPDST1		;IF FORCED UPDATE, GET TO IT
	LOAD A,MTFCN		;GET FUNCTION CODE OF LAST OPERATION
	CAIE A,IRFRED		;READ?
	CAIN A,IRFRDR		;OR READ BACKWARDS?
	SKIPA IOS,MTASTS(U)	;YES
	JRST UPDST1		;NO, GO WAIT FOR ACTIVITY TO FINISH
	TXNN IOS,OPND		;OPENED FOR SEQUENTIAL READ?
	RETSKP			;YES, STATUS GETS UPDATED LATER
UPDST1:	CALL MTACLW		;WAIT FOR ACTIVITY TO STOP
	 RET			;NEED TO BLOCK
	CALL MTFLSH		;GO UPDATE STATUS FROM EACH IORB
	 TQZ <BLKF>		;DONT WANT TO BLOCK
	CALL SETBOT		;SET BOT BIT IN STATUS WORD
	RETSKP			;ALL DONE



;ROUTINE TO SET THE WRITE LOCK BIT CORRECTLY IN MTASTS

SETWLK:	HRRZ A,MTCUTB(U)	;GET UDB ADR
	MOVE A,UDBSTS(A)	;GET STATUS OF DRIVE
	MOVX B,MT%ILW		;GET WRITE LOCK BIT IN STATUS WORD
	ANDCAM B,MTASTS(U)	;START BY CLEARING IT
	TXNE A,US.WLK		;IS THIS DRIVE WRITE LOCKED?
	IORM B,MTASTS(U)	;YES, SET THE BIT IN THE STATUS WORD
	RET			;ALL DONE


;ROUTINE TO SET UP MT%BOT

SETBOT:	HRRZ A,MTCUTB(U)	;GET UDB ADR
	MOVE A,UDBSTS(A)	;GET STATUS BITS
	MOVX B,MT%BOT		;FIRST CLEAR THE BIT
	ANDCAM B,MTASTS(U)
	TXNE A,US.BOT		;AT BOT?
	IORM B,MTASTS(U)	;YES, SET THE BIT
	RET
;ROUTINE TO OPEN A MAG TAPE UNIT FOR READING OR WRITING
;CALLED BY OPENF

MTAOPN::STKVAR <DRVTYP>		;SAVE DRIVE TYPE HERE
	SETZM DRVTYP		;ASSUME NOT TU7X
	HLRZ U,DEV		;SET UP UNIT NUMBER
	TXNE STS,READF!WRTF	;MUST BE OPENED FOR AT LEAST ONE
	TXNE STS,XCTF!RNDF!NONXF
	RETBAD (OPNX15)		;ILLEGAL MODE FOR OPENING
	SKIPN A,MTCUTB(U)	;GET UDB ADR
	JRST MTAOFL		;IF NO UNIT, PRETEND IT IS OFF-LINE
	HRRZS A			;GET ADDRESS ONLY
	LOAD B,USTYP,(A)	;GET DRIVE TYPE
	CAIL B,.UTT70		;A TU7X?
	CAILE B,.UTT73		;STILL?
	SKIPA			;NO.
	JRST [	SETOM DRVTYP	;YES. SAY SO
		JRST MTAOP2]	;AND PROCEED
	JN USOFL,(A),[CALL CHKOFL ;SEE IF OPENS ALLOWED IF OFFLINE
		 JRST MTAOFL	;NO
		JRST .+1]	;YES
MTAOP2:	LDB A,[POINT 4,STS,35]	;GET DATA MODE
	CAIE A,17		;MUST BE 0 OR 17
	JUMPN A,MTAILM		;ILLEGAL MODE IF NOT 0 OR 17
	LOCK MTALCK(U),<CALL LCKTST>	;PREVENT MULTIPLE OPENS
	MOVX IOS,OPN		;SEE IF UNIT IS ALREADY OPENED
	TDNE IOS,MTASTS(U)	;...
	JRST BUSY		;YES, DONT OPEN IT TWICE
	CAIN A,17		;DUMP MODE?
	TXO IOS,OPND		;YES, REMEMBER THAT FOR CLOSE
	TXC STS,WRTF!READF	;SEE IF OPEN FOR BOTH READ AND WRITE
	TXCN STS,WRTF!READF	;ONLY ALLOWED IF DUMP MODE
	CAIN A,17		;OPEN FOR BOTH, IS THIS DUMP MODE?
	SKIPA			;YES, OK
	JRST MTAISM		;ILLEGAL SEQUENTIAL I/O MODE
	MOVEM IOS,MTASTS(U)	;MARK THAT UNIT IS NOW OPENED
	CALL SETWLK		;SET THE WRITE LOCK BIT CORRECTLY
	MOVE IOS,MTASTS(U)	;GET STATUS AGAIN
	SKIPE DRVTYP		;A TU7X?
	JRST MTOPNX		;YES. DON'T CHECK WRITE LOCKED
	TXNE IOS,MT%ILW		;IS DRIVE WRITE LOCKED?
	TQNN <WRTF>		;YES, IS THIS A WRITE OPENF?
	SKIPA			;NO, THEN DONT COMPLAIN ABOUT WRITE LOCK
	JRST MTAWLK		;GO COMPLAIN THAT DRIVE IS WRITE LOCKED
MTOPNX:	SETZM MTANR1(U)		;INITIALIZE PER UNIT STORAGE
	SETZM MTANR2(U)
	SETZM MTANR3(U)
	SETZM MTANR4(U)
	SETZM MTANR5(U)
	SETZM MTANR6(U)
	SETZM MTARS1(U)
	LOAD A,JSMTR		;GET DEFAULT RECORD SIZE
	SKIPG A			;IS THE DEFAULT SET?
	MOVEI A,MTDFRS		;NO, USE SYSTEM DEFAULT VALUE
	STOR A,MTRS		;USE THIS UNLESS CHANGED BEFORE BIN 1
	LOAD A,JSMTM		;GET DATA MODE
	SKIPG A			;IS IT SET YET?
	MOVEI A,MTDFDM		;NO, USE SYSTEM DEFAULT VALUE
	STOR A,MTDM
	;..
	;..
	CALL MTASBW		;SET UP BYTES PER WORD, ETC.
	 JRST MTOPNF		;FAILED
	LOAD A,JSMTD		;AND ALSO GET THE DEFAULT DENSITY
	SKIPG A			;SPECIFIED?
	MOVEI A,MTDFDN		;NO, USE SYSTEM DEFAULT VALUE
	STOR A,MTDN
	LOAD A,JSMTP		;GET DEFAULT PARITY
	STOR A,MTPAR		;STORE PARITY
	SETZM FILCNT(JFN)	;INITIALIZE COUNT OF BYTES IN BUFFER
	SETZM FILLEN(JFN)	;INITIALIZE LENGTH OF CURRENT BUFFER
	SETZM FILBYN(JFN)	;AND BYTE POSITION
	MOVEI A,^D36		;SET UP BYTE POSITION
	DPB A,PBYTPO		;STORE IN FILBYT(JFN)
	HLRZ A,FILBYT(JFN)	;GET INITIAL BYTE POINTER
	STOR A,MTBYT		;SAVE FOR LATER
	SETZRO MTNIR		;INIT COUNT OF IORB'S IN QUEUE
	MOVEI A,MTBUFN*MTIRBL	;NOW INITIALIZE THE IORB'S
	IMULI A,(U)		;GET START OF IORB AREA
	ADDI A,MTIRBF		;GET ABS ADR OF IORB
	MOVSI B,-MTBUFN		;SET UP COUNT
MTAOP1:	MOVSI C,(A)		;ZERO IORB
	HRRI C,1(A)
	SETZM 0(A)
	BLT C,MTIRBL-1(A)	;INITIALIZED TO ALL ZEROS
	SETONE IRBFF,(A)	;YES, MARK ALL BUFFERS AS FREE 
	STOR U,IRBUN,(A)	;SAVE UNIT NUMBER FOR INTERRUPT LEVEL
	ADDI A,MTIRBL		;STEP TO NEXT IORB
	AOBJN B,MTAOP1		;LOOP BACK FOR ALL IORB'S
	MOVEI A,MAXPPB*MTBUFN	;GET ADDRESS OF START OF LIST
	IMULI A,(U)		;  FOR THIS UNIT
	ADDI A,MTAPBF		;ADD IN BASE ADR OF PAGE BUFFER AREA
	STOR A,MTBUF		;REMEMBER ADR OF LIST
	STOR A,MTCUP		;SET UP CURRENT P TO BE EMPTIED
	SETZRO MTCUB		;START AT BUFFER 0
	SETZRO MTCSB		;FOR BOTH USER AND SERVICE ROUTINE BUF'S
	MOVE A,JOBNO		;GET USER PROGRAM NAME FOR SYSERR
	MOVE B,JOBPNM(A)
	HRRZ C,MTCUTB(U)	;GET UDB ADR
	MOVEM B,UDBPNM(C)	;STORE PROGRAM NAME IN UDB
	HRR B,JOBDIR(A)		;GET LOGGED-IN DIRECTORY
	HRLI B,USRLH		;MAKE IT A USER NUMBER
	MOVEM B,UDBUDR(C)	;STORE IT IN UDB ALSO
	UNLOCK MTALCK(U)	;UNLOCK THE LOCK ON THIS UNIT
	RETSKP			;SUCCESSFULLY OPENED
BUSY:	SKIPA A,[OPNX9]		;UNIT ALREADY OPENED
MTOPNF:	SETZM MTASTS(U)		;CLEAR STATUS WORD
	UNLOCK MTALCK(U)	;UNLOCK THIS UNIT
	RET			;NOT OPENED!

MTAILM:	MOVEI A,OPNX14		;ILLEGAL MODE
	RET

MTAOFL:	MOVEI A,OPNX8		;DEVICE IS OFF-LINE
	RET

MTAWLK:	MOVEI A,OPNX25		;RETURN WRITE LOCKED ERROR CODE
	JRST MTOPNF		;OPENF FAILED

MTAISM:	MOVEI A,OPNX15		;ILLEGAL SEQUENTIAL I/O MODE
	JRST MTOPNF		;GO UNLOCK AND BOMB OUT
;ROUTINE TO SET UP MTUBW, MTHBW, MTUBB, AND MTUBP

MTASBW:: LOAD A,MTDM		;GET DATA MODE
	CAILE A,MTMXDM		;LEGAL MODE?
	RETBAD (MTOX5)		;NO
	MOVE A,HBWTB(A)		;GET BYTES PER WORD
	STOR A,MTHBW		;SAVE HARDWARE BYTES PER WORD
	LDB A,PBYTSZ		;GET SIZE OF USER BYTES
	MOVEI C,^D36		;GET USER BYTES PER WORD
	SKIPN A			;SIZE = 0?
	MOVEI A,^D36		;YES, PRETEND IT IS WORD MODE
	IDIV C,A		;GET BYTES PER WORD
	STOR C,MTUBW		;USER BYTES PER WORD
	LOAD A,MTRS		;NOW CALCULATE USER BYTES PER BUFFER
	IMUL A,C		;RECORD SIZE * USER BYTES PER WORD
	OPSTR <IDIV A,>,MTHBW	;NOW HAVE DESIRED VALUE
	SKIPE B			;ANY REMAINING BITS IN RECORD?
	AOS A			;YES, INCR USER BYTES PER BUFFER
	STOR A,MTUBB		;SAVE COUNT OF USER BYTES PER BUFFER
	IMULI C,PGSIZ		;GET USER BYTES PER PAGE
	STOR C,MTUBP		;SAVE USER BYTES PER PAGE
	IDIV A,C		;SEE IF RECORD SIZE TOO LARGE
	SKIPE B			;GET NUMBER OF PAGES PER BUFFER
	AOS A			;PARTIAL PAGE
	CAILE A,MAXPPB		;WITHIN LEGAL RANGE?
	RETBAD (MTOX4)		;NO
	RETSKP			;EXIT OK


HBWTB:	1			;TABLE OF HARDWARE BYTES PER WORD
	1			;36 BIT BYTES
	6			;6 BIT BYTES
	5			;7 BIT BYTES
	4			;8 BIT BYTES
	1			;36 BIT BYTES (HI-DENSITY)
MTMXDM==:.-HBWTB-1
;ROUTINE TO CLOSE A MAGTAPE UNIT
;CALLED BY CLOSF

MTACLZ::HLRZ U,DEV		;SET UP UNIT NUMBER
	MOVX IOS,MTOWT!DMPWT	;CLEAR WAIT FLAGS
	ANDCAB IOS,MTASTS(U)
	TXNN IOS,CLOF		;ALREADY STARTED THE CLOSE?
	JRST [	SETZRO MTSTC	;NO, INITIALIZE CLOSE FUNCTION COUNT
		MOVX IOS,CLOF	;AND MARK THAT CLOSE IS IN PROGRESS
		IORB IOS,MTASTS(U)
		TXNN IOS,OPND	;DUMP MODE?
		JRST .+1	;NO
		INCR MTSTC	;YES, DONT FORCE OUT LAST BUFFER
		JRST .+1]
	TXNE A,CZ%ABT		;AN ABORT TYPE CLOSE?
	JRST MTACLA		;YES, GO ABORT
	CALL MTACLW		;WAIT FOR ACTIVITY TO CEASE
	 RET			;NEED TO BLOCK
	MOVE IOS,MTASTS(U)	;GET STATUS
	TXNN IOS,BUFA!OPND	;ANY BUFFERS?
	JRST MTACLR		;NO, NOTHING TO DO
	TQNE <WRTF>		;WRITING?
	JRST MTACL1		;YES, GO CLOSE THE WRITE
	TXNN IOS,OPND		;DUMP MODE
	TQNN <READF>		;NO, READING?
	JRST MTACLR		;NOTHING TO DO
	SETZRO ABORTF,(U)	;CLEAR ERROR ABORT BIT
	CALL MTPOS0		;SEQUENTIAL READ, GO LEAVE TAPE IN
	 RET			; CORRECT POSITION
	CALL MTACLW		;WAIT FOR ACTIVITY TO STOP
	 RET			;NEED TO BLOCK
	JRST MTACLR
MTACL1:	CALL MTACLW		;WAIT FOR ALL ACTIVITY TO STOP
	 RET			;NEED TO BLOCK
	MOVE IOS,MTASTS(U)	;GET STATUS FLAGS
	TXNE IOS,MT%DAE!MT%DVE	;ERROR IN PROGRESS?
	RETBAD (IOX5)		;YES, GIVE ERROR RETURN
	LOAD A,MTSTC		;GET CLOSE FUNCTION COUNT
	CAIL A,MTACLN		;FINISHED YET?
	JRST MTACLR		;YES, GO RELEASE PAGES
	XCT MTACLT(A)		;PERFORM THE NEXT FUNCTION IN LIST
	 RET			;NEED TO BLOCK
	INCR MTSTC		;STEP TO NEXT FUNCTION TO BE DONE
	JRST MTACL1		;LOOP BACK TIL CLOSE IS COMPLETE

MTACLT:	CALL MTRECO		;FORCE OUT THE LAST PARTIAL BUFFER
	CALL MTCHKE		;CHECK IF EOF'S NEED WRITING
	CALL MTABKE		;THEN BACKSPACE OVER SECOND EOF
	CALL MTFLSH		;FLUSH OUT ALL REMAINING IORBS
MTACLN==.-MTACLT		;NUMBER OF FUNCTIONS IN TABLE

MTACLA:	NOSKED			;DONT ALLOW SCHEDULING
	CALL MTAKIL		;KILL ALL REQUESTS IN QUEUE
	OKSKED
MTCLA1:	LOAD A,MTNIR		;GET NUMBER OF IORBS STILL ACTIVE
	JUMPE A,MTACLR		;IF NONE, CLOSE OUT
	MOVEI A,MTAWAT		;WAIT FOR IT TO FINISH
	HRL A,U
	MDISMS
	JRST MTCLA1		;LOOP BACK TO CHECK IF DONE
;ROUTINE TO CHECK IF EOF'S SHOULD BE WRITTEN
;	CALL MTCHKE
;RETURNS +1:	NEED TO BLOCK
;	 +2:	EOF'S WRITTEN OR NOT NEEDED

MTCHKE:	LOAD A,MTFCN		;GET LAST FUNCTION PERFORMED
	CAIE A,IRFWRT		;A WRITE?
	CAIN A,IRFWTM		;OR WRITE TAPE MARK?
	SKIPA A,[2]		;YES, GO MAKE SURE TWO EOF'S ARE WRITTEN
	RETSKP			;NO NEED FOR ANY EOF'S
	CALLRET MTAWTM		;GO WRITE TAPE MARKS


;ROUTINE TO BACKSPACE OVER SECOND TAPE MARK

MTABKE:	LOAD A,MTFCN		;GET LAST FUNCTION
	CAIE A,IRFWTM		;MUST HAVE BEEN WRITE TAPE MARK
	RETSKP			;NOTHING TO BE DONE IF NOT
	LOAD A,MTNTM		;GET # OF TAPE MARKS WRITTEN
	CAIE A,2		;EXACTLY 2?
	RETSKP			;NO, ALL DONE
	CALL GETIRB		;GET AN IORB TO USE
	 RET			;MUST WAIT FOR ONE
	MOVEI B,IRFBSB		;GET FUNCTION CODE OF BACKSPACE BLOCK
	MOVEI C,1		;DO ONE
	CALL MTPIRQ		;QUEUE IT UP
	RETSKP			;ALL DONE

;SPECIAL ROUTINE USED BY TAPE TO "RETIRE" ALL IORBS.
;THIS IS NEEDED WHEN DUMP MODE AND SEQ MODE CONFLCIT
;E.G. IF A LABEL IS READ IN DUMP MODE AND THEN A
;POSITIONING OPERATION IS PERFORMED WITH THE TAPE
;OPENED FOR SEQ ACCESS, THE CODE IN MAGTAP REALLY SCREWS UP.

MTAFLA::CALL MTFLSH		;RETIRE ALL REQUESTS
	 TQZ <BLKF>		;IGNORE BLOCK REQUEST
	SETZM FILLEN(JFN)
	SETZM FILCNT(JFN)
	SETZM FILBYN(JFN)	;NO MORE BUFFER ACTIVE
	RET			;AND DONE
;ROUTINE TO WAIT FOR ALL IORB'S TO BE FINISHED
;	CALL MTACLW
;RETURNS +1:	NEEDS TO BLOCK
;	 +2:	NO IORB'S LEFT IN QUEUE

MTACLW:	LOAD A,MTNIR		;GET NUMBER OF IORB'S IN QUEUE
	JUMPE A,RSKP		;IF NONE, RETURN
	MOVEI A,MTAWAT		;SET UP TO WAIT FOR REQUESTS TO FINISH
	HRL A,U			;FOR THIS UNIT
	TXO STS,BLKF		;SET WAIT FLAG FOR IO
	RET			;AND GIVE NON-SKIP RETURN

MTACLR:	CALL MTARLB		;RELEASE PAGES (IF ANY)
	SETZM MTASTS(U)		;INITIALIZE STATUS
	RETSKP			;CLOSE IS COMPLETE


;ROUTINE TO WAIT FOR ALL REQUESTS TO BE FINISHED

	RESCD

MTAWAT::LOAD B,MTANIR,(A)	;GET NUMBER OF IORB'S OUTSTANDING
	JUMPLE B,1(4)		;IF 0, RETURN +2
	JRST 0(4)		;OTHERWISE CONTINUE WAITING

	SWAPCD


;ROUTINE TO RETURN ALL IORBS TO THE FREE STATE AND CHECK FOR I/O ERRORS
;	CALL MTFLSH
;RETURNS +1:	NEED TO BLOCK
;	 +2:	OK

MTFLSH::SAVEQ
	CALL MTACLW		;WAIT FOR ALL QUIET
	 RET			;NEED TO BLOCK
	MOVEI Q3,MTBUFN		;SET UP COUNT OF IORBS
MTFL0:	CALL GETIRB		;GET NEXT IORB
	 JRST MTFL1		;IGNORE ERRORS, (THEY WERE ADDED TO MTASTS)
	CALL IRBDON		;YES, MARK IT DONE
	 JFCL			;IGNORE ERRORS
MTFL1:	LOAD B,MTCSB		;STEP TO NEXT IORB
	AOS B
	IDIVI B,MTBUFN
	STOR C,MTCSB
	SOJG Q3,MTFL0		;LOOP BACK FOR ALL IORBS
	TQZ <BLKF>		;MAKE SURE WAIT FLAG IS NOT SET
	RETSKP			;ALL FLUSHED OUT
;ROUTINE TO DO SEQUENTIAL INPUT FROM MAGTAPE

MTASQI::HLRZ U,DEV		;SET UP UNIT NUMBER
	CALL MTAASB		;GO ASSIGN BUFFER SPACE (IF NEEDED)
	 MTERET ()		;NO ROOM IN JSB FOR BUFFERS
	MOVX IOS,MTOWT		;CLEAR MTOPR WAIT FLAG
	ANDCAB IOS,MTASTS(U)
	LOAD A,MTFCN		;GET LAST FUNCTION DONE
	CAIE A,IRFRED		;LAST ONE A READ?
	CAIN A,IRFRDR		;OR READ REVERSE?
	JRST MTSQI6		;YES, DONT NEED TO UPDATE STATUS
	CALL UPDSTS		;UPDATE STATUS
	 RET			;NEED TO BLOCK
MTSQI6:	CALL CHKERI		;SEE IF ANY ERRORS
	 RET			;YES, DONT GO ANY FURTHER
	MOVE A,FILBYN(JFN)	;SEE IF THE BUFFER IS EMPTY YET
	CAMGE A,FILLEN(JFN)	;...
	JRST MTSQI1		;NO, JUST STEP TO NEXT PAGE IN BUFFER
	JUMPE A,MTSQI5		;IF NO BUFFER YET, DONT CALL IRBDON
MTSQI0:	CALL CLRINP		;CLEAR FILLEN ETC
	 MTERET ()		;ERROR
MTSQI5:	LOAD A,MTRS		;GET RECORD SIZE
	MOVEI B,IRFRED		;MARK THAT A READ IS BEING DONE
	LOAD C,MTRBF		;GET READ BACKWARDS FLAG
	SKIPE C			;READING BACKWARDS?
	MOVEI B,IRFRDR		;YES, GET CORRECT FUNCTION CODE
	CALL MTIRQI		;QUEUE UP ANY FREE IORBS FOR FILLING
	 RET			;ERROR OCCURED
	CALL GETUBF		;GET NEXT IORB TO BE EMPTIED
	 RET			;MUST WAIT FOR ONE TO FILL UP
	JUMPE B,MTSQI0		;IF NO CHARACTERS IN IORB, GET ANOTHER
	OPSTR <IMUL B,>,MTUBW	;CALCULATE USER BYTES IN BUFFER
	OPSTR <IDIV B,>,MTHBW	; HDW BYTES * USER BPW / HDW BPW
	SKIPE C			;PARTIAL BYTE?
	AOS B			;YES, COUNT TOTAL BYTES BY ONE
	LOAD C,MTUBB		;GET MAX USER BYTES PER BUFFER
	CAMLE B,C		;LIMIT TO MAX BYTES
	MOVE B,C		;...
	MOVEM B,FILLEN(JFN)	;THIS = # OF BYTES TO BE BIN'D OR SIN'D
	SETZM FILBYN(JFN)	;SET BYTE NUMBER TO ZERO
	SETZM FILCNT(JFN)	;ZERO COUNT TOO
	JE MTRBF,,MTSQI1	;READING BACKWARDS?
	IDIVI B,PGSIZ		;YES, GET NUMBER OF PAGES OF DATA
	SKIPE C			;PARTIAL PAGES INCLUDED
	AOS B
	MOVEI B,-1(B)		;PAGES GO FROM 0 TO N-1
	OPSTRM <ADDM B,>,MTCUP	;START AT END OF LIST OF PAGES
	;..
	;..
MTSQI1:	SKIPLE FILCNT(JFN)	;ARE THERE ANY MORE BYTES IN BUFFER
	JRST MTSQI2		;YES
	LOAD A,MTCUP		;GET NEXT BUFFER PAGE TO BE EMPTIED
	MOVE A,(A)		;GET VIRTUAL ADDRESS OF THE PAGE
	OPSTR <HRL A,>,MTBYT	;SET UP BYTE POINTER
	MOVEM A,FILBYT(JFN)	;SAVE BYTE POINTER FOR BIN/SIN
	MOVE A,FILLEN(JFN)	;GET LENGTH OF BUFFER
	SUB A,FILBYN(JFN)	;GET NUMBER OF BYTES LEFT IN BUFFER
	LOAD B,MTUBP		;GET NUMBER OF USER BYTES PER PAGE
	CAMLE A,B		;IS THERE MORE THAN 1 PAGE OF BYTES
	MOVE A,B		;YES, LIMIT COUNT TO 1 PAGE ONLY
	MOVEM A,FILCNT(JFN)	;SAVE COUNT OF BYTES IN THIS PAGE
	JN MTRBF,,MTSQI3	;IF READING BACKWARDS, GO FIX UP FILBYT
	INCR MTCUP		;STEP TO NEXT PAGE IN BUFFER
MTSQI2:	SOS FILCNT(JFN)		;NOW GET THE NEXT BYTE
	AOS FILBYN(JFN)		;DECREMENT COUNT AND INCREMENT POSITION
	ILDB A,FILBYT(JFN)	;GET BYTE FROM BUFFER
	RET			;GIVE SUCCESSFUL RETURN


MTSQI3:	DECR MTCUP		;STEP TO NEXT USER PAGE
	MOVE C,FILLEN(JFN)	;GET NUMBER OF BYTES ON THIS PAGE
	SUB C,FILBYN(JFN)	;GET NUMBER OF BYTES LEFT IN RECORD
	IDIV C,B		;DIVIDE BY USER BYTES PER PAGE
	JUMPE D,MTSQI2		;IF ON A PAGE BOUNDRY, USE FULL COUNT
	MOVEM D,FILCNT(JFN)	;IF FIRST TIME THRU, USE THIS COUNT
	SUB B,D			;GET NUMBER OF BYTES TO SKIP
	OPSTR <IDIV B,>,MTUBW	;SPLIT INTO WORDS AND BYTES
	ADDM B,FILBYT(JFN)	;STEP OVER THE FULL WORDS
MTSQI4:	SOJL C,MTSQI2		;THEN STEP OVER BYTES (IF ANY)
	IBP FILBYT(JFN)
	JRST MTSQI4		;LOOP BACK TIL ALL BYTES SKIPPED
;ROUTINE TO WAIT FOR AN IORB TO GO INACTIVE
;ACCEPTS IN A/	IORB ADR
;	JRST MTAWTR
;RETURNS +1:	ALWAYS, WITH BLKF SET AND A SET UP FOR MDISMS

MTAWTR:	HRLI A,MTARWT		;SET UP FOR DISMIS
	MOVSS A
	TQO <BLKF>		;MARK THAT ROUTINE WANTS TO BLOCK
	RET			;GO BLOCK


;ROUTINE TO WAIT FOR AN IORB TO BECOME READY

	RESCD

MTARWT::JN IRBFA,(A),0(4)	;IF STILL ACTIVE, TAKE NON-SKIP RET
	JRST 1(4)		;NO LONGER ACTIVE

	SWAPCD

;ROUTINE TO CLEAR EOFF AND ABORTF FOR UNIT IN A

MTACEF::MOVX IOS,MT%EOF!MT%EOT	;BITS TO CLEAR
	ANDCAB IOS,MTASTS(A)	;CLEAR THEM
	TQZ <EOFF,ERRF>		; AND THESE ALSO (IN STS)
	SETZRO ABORTF,(A)	; AND THIS
	RET			;RETURN
;ROUTINE TO DO SEQUENTIAL OUTPUT
;CALLED FROM IO

MTASQO::STKVAR <MTSQOB>
	MOVEM A,MTSQOB		;SAVE THE BYTE
	HLRZ U,DEV		;SET UP UNIT
	MOVX IOS,MTOWT		;CLEAR MTOPR WAIT FLAG
	ANDCAB IOS,MTASTS(U)
	CALL CHKERO		;CHECK FOR ERRORS
	 RET			;THERE ARE SOME, EXIT NOW
	CALL MTAASB		;ASSIGN BUFFERS IF NEEDED
	 MTERET ()		;NO ROOM IN JSB FOR BUFFERS
	SKIPG FILLEN(JFN)	;IS THIS THE VERY FIRST TIME THROUGH?
	JRST [	CALL GETIRB	;GET NEXT IORB TO USE
		 RET		;WAIT FOR AN IORB
		JRST MTSQO2]	;GO USE THIS BUFFER FOR FILLING
	MOVE A,FILBYN(JFN)	;GET BYTE COUNT
	CAMGE A,FILLEN(JFN)	;ANY BYTES LEFT IN THIS BUFFER?
	JRST MTSQO1		;YES, GO STEP TO NEXT PAGE
	CALL MTSQO0		;GO OUTPUT THE BUFFER
	CALL GETIRB		;GET NEXT BUFFER FOR USER TO FILL
	 RET			;NONE AVAILABLE, GO WAIT FOR A BUFFER
MTSQO2:	CALL CHKERO		;CHECK FOR ERRORS
	 RET			;ERRORS EXIST
	LOAD A,MTUBB		;GET USER BYTES PER BUFFER
	MOVEM A,FILLEN(JFN)	;SET UP NUMBER OF BYTES TO BE BOUT'ED
	SETZM FILBYN(JFN)	;START AT BYTE 0
	SETZM FILCNT(JFN)	;GUARANTEE TO SET UP FILCNT
MTSQO1:	SKIPLE FILCNT(JFN)	;ANY BYTES LEFT ON THIS PAGE?
	JRST MTSQO3		;YES, GO FINISH OUT THIS PAGE
	LOAD A,MTCUP		;GET POINTER TO CURRENT PAGE
	INCR MTCUP		;STEP TO NEXT PAGE
	MOVE A,(A)		;GET ADDRESS OF BUFFER PAGE
	OPSTR <HRL A,>,MTBYT	;SET UP FILBYT
	MOVEM A,FILBYT(JFN)
	HRLI B,0(A)		;ZERO BUFFER
	HRRI B,1(A)
	SETZM 0(A)
	BLT B,PGSIZ-1(A)
	MOVE B,FILLEN(JFN)	;GET LENGTH OF BUFFER
	SUB B,FILBYN(JFN)	;GET REMAINING BYTES IN BUFFER
	LOAD A,MTUBP		;GET USER BYTES PER PAGE
	CAML A,B		;ENOUGH BYTES LEFT IN BUFFER?
	MOVE A,B		;NO, SET FILCNT CORRECTLY
	MOVEM A,FILCNT(JFN)	;SET UP COUNT OF BYTES TO BE BOUT'ED
MTSQO3:	SOS FILCNT(JFN)		;NOW PUT IN THE ORIGINAL BYTE
	AOS FILBYN(JFN)		;KEEP THE COUNTS RIGHT
	MOVE A,MTSQOB		;GET BACK THE BYTE
	IDPB A,FILBYT(JFN)	;PUT THE BYTE INTO THE BUFFER
	RET			;AND GIVE SUCCESSFUL RETURN
;ROUTINE TO WRITE OUT A PARTIAL BUFFER
;	CALL MTRECO
;RETURNS +1:	ERROR
;	 +2:	DONE

MTRECO::HLRZ U,DEV		;SET UP UNIT NUMBER
	MOVE IOS,MTASTS(U)	;GET STATUS BITS
	TQNN <OPNF>		;CHECK OPENED
	RETBAD (IOX2)		;NOT (CAN GET HERE ON MTOPR)
	TQNE <WRTF>		;OPENED FOR WRITE?
	TXNE IOS,OPND		;AND NOT IN DUMP MODE?
	RETBAD (IOX9)		;NO, RECORD OUT LEGAL FOR SEQUENTIAL WRITE ONLY
	SKIPLE FILLEN(JFN)	;ANY BUFFERS SET UP YET?
	SKIPG FILBYN(JFN)	;YES, ANY THING IN THEM YET?
	RETSKP			;NO, NOTHING TO DO
	CALL MTSQO0		;OUTPUT THE BUFFER
	RETSKP			;ALL DONE



;ROUTINE TO OUTPUT A BUFFER AS SPECIFIED BY FILBYN, FILCNT, AND FILLEN
;	CALL MTSQO0
;RETURNS +1:	NEEDS TO BLOCK
;	 +2:	BUFFER HAS BEEN QUEUED

MTSQO0:	CALL GETCSB		;GET CURRENT IORB BEING USED
	LOAD B,MTHBW		;GET RECORD SIZE FOR OUTPUT
	LOAD D,MTUBW		;GET USER BYTES PER WORD
	IMUL B,FILBYN(JFN)	;BYN * HBW / UBW
	IDIV B,D
	SKIPE C			;ANY PARTIAL BYTES?
	AOS B			;YES, WRITE OUT PARTIAL BYTE
	LOAD D,MTHBW		;NOW GET MIN # OF HDW BYTES PER RECORD
	IMULI D,MINREC		;GET # OF BYTES IN MIN RECORD
	CAMGE B,D		;IS THIS RECORD TOO SMALL?
	MOVE B,D		;YES, MAKE IT THE MINIMUM SIZE
	MOVEI C,IRFWRT		;FUNCTION IS WRITE
	CALL MTAIRQ		;QUEUE UP THIS IORB
	SETZM FILLEN(JFN)	;MARK THAT BUFFER WAS QUEUED UP
	SETZM FILBYN(JFN)
	SETZM FILCNT(JFN)
	MOVX C,MT%EOT		;CHECK FOR EOT
	TDNN C,MTASTS(U)	;...
	RET			;NOT AT EOT
	TQO <ERRF>		;SET ERROR FLAG
	RET			;WILL BE NOTICED LATER
;ROUTINE TO ASSIGN BUFFER SPACE IN THE JSB
;THIS ROUTINE SETS UP MTBUF, MTCUB, AND MTNBF
;ACCEPTS U/	UNIT #
;	CALL MTAASB
;RETURNS +1:	NO ROOM IN JSB FOR BUFFERS
;	 +2:	BUFFERS ASSIGNED

MTAASB:	MOVX A,BUFA		;BUFFERS ALREADY ASSIGNED?
	TDNE A,MTASTS(U)	;...
	RETSKP			;YES, NO NEED TO GO ANY FURTHER
	SAVEP			;SAVE PERMANENT ACS
	LOAD B,MTRS		;GET RECORD SIZE
	OPSTR <IDIV B,>,MTHBW	;GET NUMBER OF WORDS PER RECORD
	ADDI B,PGSIZ-1		;CALCULATE NUMBER OF PAGES REQUIRED
	IDIVI B,PGSIZ		;...
	CAILE B,MAXPPB		;WITHIN BOUNDS?
	RETBAD (MTOX4)		;NO, RECORD SIZE TOO LARGE
	STOR B,MTPPB		;SAVE PAGES PER BUFFER
	LOAD P5,MTBUF		;SET UP BASE ADR OF LIST
	LOAD P3,MTPPB		;SET UP COUNTER
	IMULI P3,MTBUFN
MTAAS1:	CALL ASGPAG		;GET A PAGE FROM JSB
	 JRST MTAAS2		;NO MORE LEFT, GO RELEASE SPACE
	HRRZM A,0(P5)		;STORE ADDRESS IN LIST
	AOS P5			;STEP POINTER TO LIST
	SOJG P3,MTAAS1		;LOOP BACK TIL ALL PAGES ASSIGNED
	MOVX A,BUFA		;MARK THAT BUFFERS ARE NOW ASSIGNED
	IORM A,MTASTS(U)	;...
	RETSKP			;BUFFERS ASSIGNED

MTAAS2:	LOAD A,MTPPB		;GET MAX NUMBER OF ASSIGNABLE PAGES 
	IMULI A,MTBUFN		;...
	SUB P3,A		;GET NEGATIVE COUNT OF PAGES ASSIGNED
MTAAS3:	AOJG P3,MTAAS4		;ANY MORE PAGES TO BE RELEASED?
	MOVE A,-1(P5)		;YES, GET ADDRESS
	CALL RELPAG		;AND RELEASE IT
	SOJA P5,MTAAS3		;LOOP BACK TIL ALL PAGES RELEASED

MTAAS4:	MOVEI A,IOX7		;NO ROOM IN JSB FOR BUFFERS
	RETBAD			;GIVE FAIL RETURN
;ROUTINE TO RELEASE ALL OF THE BUFFER PAGES
;	CALL MTARLB
;RETURNS +1:	ALWAYS

MTARLB:	MOVX A,BUFA		;ARE THERE ANY BUFFERS ASSIGNED?
	TDNN A,MTASTS(U)	;...
	RET			;NO, DONT RELEASE ANY
	SAVEP
	LOAD P3,MTPPB		;GET COUNT OF NUMBER OF PAGES
	IMULI P3,MTBUFN		;...
	LOAD P5,MTBUF		;GET STARTING ADR OF LIST OF PAGES
MTARL1:	HRRZ A,0(P5)		;GET NEXT PAGE TO BE RELEASED
	CALL RELPAG		;RELEASE IT
	AOS P5			;STEP POINTER TO LIST
	SOJG P3,MTARL1		;LOOP BACK TIL ALL PAGES RELEASED
	MOVX A,BUFA		;NOW MARK THAT THERE ARE NO BUFFERS
	ANDCAM A,MTASTS(U)	;...
	RET			;AND RETURN
;ROUTINE TO GET AN IORB TO USE AND STEP TO NEXT IORB
;	CALL GETIRB
;RETURNS +1:	NEED TO WAIT OR ERROR
;	 +2:	A/	IORB ADR

GETIRB:	CALL GETCSB		;GET CURRENT IORB ADR
	JN IRBFA,(A),MTAWTR	;IF ACTIVE STILL, GO WAIT
	JN IRBFF,(A),GETIR1	;IF FREE, DONT CALL IRBDON
	CALL SETSTS		;CHECK FOR ERRORS IN IORB
	CALL IRBDON		;MARK IORB AS DONE
	 RET			;ERROR
GETIR1:	LOAD B,MTCSB		;GET BUFFER NUMBER AGAIN
	OPSTR <IMUL B,>,MTPPB	;GET OFFSET INTO LIST OF PAGES
	OPSTR <ADD B,>,MTBUF	;ADD START ADR OF BUFFER
	STOR B,MTCUP		;SAVE CURRENT PAGE BEING EMPTIED
	SETONE IRBFQ,(A)	;MARK IT AS QUEUED UP
	SETZRO <IRBAB,IRBFF,IRBFR,IRBFA>,(A)
	RETSKP			;GIVE OK RETURN
;ROUTINE TO GET THE NEXT BUFFER TO BE GIVEN TO USER ON INPUT
;	CALL GETUBF
;RETURNS +1:	WAIT OR ERROR
;	 +2:	A/	IORB ADR
;		B/	# OF CHARACTERS IN BUFFER

GETUBF:	CALL GTUBFA		;GET NEXT USER IORB
	 JRST GTUBF1		;NONE AVAILABLE
	CALL SETSTS		;SEE IF ANY ERRORS IN THIS IORB
	CALL CHKERI		;SEE IF ANY ERRORS OR EOF
	 JRST [	PUSH P,A	;SAVE ERROR CODE
		CALL GETCUB	;GET CURRENT IORB
		CALL IRBDON	;RELEASE IT
		 JFCL
		JRST PA1]	;GIVE ERROR RETURN
	MOVE B,IRBCNT(A)	;GET # OF BYTES IN RECORD
	RETSKP			;GOT ONE

GTUBF1:	JUMPE A,[CALL GETCUB	;GET BACK THE IORB ADR
		JRST MTAWTR]	;GO WAIT FOR ACTIVE BIT TO GO OFF
	SKIPL A			;NONE QUEUED UP?
	RETBAD ()		;NO, JUST PLAIN ERROR
	BUG(MTANOI)
	JRST MTASIC		;GO BOMB


;ROUTINE TO GET A BUFFER FOR INPUTING
;	CALL GTUBFA
;RETURNS +1:	A = 0		;NEED TO WAIT FOR ACTIVITY TO FINISH
;		A = -1		;NO IORB'S QUEUED UP FOR INPUT
;		A POSITIVE	;ERROR CODE
;	 +2:	A/	IORB ADR

GTUBFA:	CALL GETCUB		;GET IORB FOR USER TO EMPTY
	JN IRBFA,(A),RETZ	;GO WAIT FOR AN IORB
	LOAD B,MTCUB		;GET BUFFER NUMBER AGAIN
	OPSTR <IMUL B,>,MTPPB	;GET OFFSET INTO LIST OF PAGES
	OPSTR <ADD B,>,MTBUF	;ADD START ADR OF BUFFER
	STOR B,MTCUP		;SAVE CURRENT PAGE BEING EMPTIED
	JN <IRBFF,IRBAB>,(A),GETUB1
	LOAD C,ISFCN,(A)	;GET FUNCTION CODE
	CAIE C,IRFRDR		;READ BACKWARDS?
	CAIN C,IRFRED		;OR READ?
	RETSKP			;YES, GIVE THIS BUFFER TO USER
	CALL IRBDON		;MARK THIS BUFFER AS DONE
	 RET			;ERROR OCCURED
GETUB1:	JRST RETO		;NONE QUEUED UP
;ROUTINE TO GET CURRENT USER IORB ADR
;	CALL GETCUB
;RETURNS +1:	ALWAYS, A/	IORB ADR

GETCUB:	MOVEI A,MTBUFN
	IMULI A,(U)		;GET BUFFER NUMBER FOR THIS UNIT
	OPSTR <ADD A,>,MTCUB	;GET RELATIVE BUFFER NUMBER
	IMULI A,MTIRBL
	ADDI A,MTIRBF		;GET ACTUAL ADR
	RET			;AND RETURN


;ROUTINE TO GET CURRENT IORB ADR
;	CALL GETCSB
;RETURNS +1:	ALWAYS, A/	IORB ADR

GETCSB:	MOVEI A,MTBUFN
	IMULI A,(U)		;GET BUFFER NUMBER FOR THIS UNIT
	OPSTR <ADD A,>,MTCSB	;GET RELATIVE BUFFER NUMBER
	IMULI A,MTIRBL
	ADDI A,MTIRBF		;GET ACTUAL ADR
	RET			;AND RETURN


;ROUTINE TO STEP TO NEXT USER BUFFER
;	CALL STPCUB
;RETURNS +1:	ALWAYS

STPCUB:	LOAD B,MTCUB		;STEP USER BUFFER
	AOS B
	IDIVI B,MTBUFN		;MODULO NUMBER OF IORBS
	STOR C,MTCUB		;SAVE NEW BUFFER NUMBER
	RET


;ROUTINE TO CLEAR FILLEN, FILBYN, FILCNT AND AN IORB

CLRINP:	SETZM FILLEN(JFN)	;MARK THAT THERE IS NO MORE BUFFER
	SETZM FILBYN(JFN)	;  IN CASE WE NEED TO BLOCK
	SETZM FILCNT(JFN)
	CALL GETCUB		;GET ADR OF THE BUFFER BEING USED
	CALL IRBDON		;MARK IT DONE
	 RET			;SOME SORT OF ERROR OCCURED
	CALL STPCUB		;STEP TO NEXT USER BUFFER
	RETSKP
;ROUTINE TO MARK AN IORB AS DONE
;ACCEPTS IN A/	IORB ADR
;	CALL IRBDON
;RETURNS +1:	ERROR
;	 +2:	A/	IORB ADR

IRBDON:	JE IRBFQ,(A),IRBDN1	;IF NOT QUEUED UP, ERROR
	JN IRBFA,(A),IRBDN2	;IF STILL ACTIVE, ERROR
	SETZM IRBSTS(A)		;INIT THE IORB
	SETZM IRBMOD(A)
	SETZM IRBXFL(A)		;CLEAR OUT POINTER TO TRANSFER LIST
	SETZRO <IRBFQ,IRBFR,IRBAB,IRBFA>,(A)
	SETONE IRBFF,(A)	;MARK IT AS FREE
	RETSKP			;FINISHED

IRBDN1:	BUG(MTANOQ)
	JRST MTASIC

IRBDN2:	BUG(MTANOA)
MTASIC:	MOVX A,MT%DVE		;MAKE THIS BE A HARD ERROR
	IORM A,MTASTS(U)
	MTERET (IOX8)		;SOFTWARE CONFUSION
;ROUTINE TO QUEUE UP AN IORB
;ACCEPTS IN A/	IORB ADR
;	CALL QUEIRB
;RETURNS +1:	ALWAYS

QUEIRB:	MOVE IOS,MTASTS(U)	;GET STATUS BITS
	MOVX C,IS.IER		;SEE IF USER DOESNT WANT ERROR RECOVERY
	TXNE IOS,MT%SER		;...
	IORM C,IRBSTS(A)	;DONT DO ANY ERROR RECOVERY ACTION
	MOVX C,IS.IEL		;USER WANT TO IGNORE ERROR LOGGING?
	TXNE IOS,MTIEL		;...
	IORM C,IRBSTS(A)	;YES
	LOAD B,MTCSB		;GET CURRENT IORB NUMBER
	SETONE IRBFA,(A)	;MARK THIS IORB AS ACTIVE
	LOAD C,ISFCN,(A)	;GET FUNCTION
	LOAD D,MTFCN		;GET LAST FUNCTION
	CAIE C,IRFRED		;READING?
	JRST [	CAIE C,IRFRDR	;OR READ REVERSE?
		JRST QUEIR1	;NO, UPDATE MTCUB
		CAIE D,IRFRDR	;YES, WAS LAST ONE A READ REVERSE TOO?
		JRST QUEIR1	;NO, SET POINTER TO BUFFER
		JRST QUEIR2]	;YES, DONT RESET BUFFER POINTER
	CAIE D,IRFRED		;LAST ONE A READ?
QUEIR1:	STOR B,MTCUB		;NO, SET USER BUFFER POINTER HERE
QUEIR2:	STOR C,MTFCN		;SET LAST FUNCTION
	AOS B			;NOW STEP IORB NUMBER
	IDIVI B,MTBUFN		;MODULO NUMBER OF IORBS
	STOR C,MTCSB
	INCR MTNIR		;COUNT UP NUMBER OF QUEUED IORBS
	HRRZ B,MTCUTB(U)	;GET UDB
	NOSKED			;PHYSIO REQUIRES NOSKED
	CALL PHYSIO		;QUEUE UP REQUEST
	OKSKED
	RET			;RETURN
;ROUTINE TO CHECK AN IORB FOR ERRORS
;	CALL CHKERI	OR	CALL CHKERO
;RETURNS +1:	ERROR
;	 +2:	OK, A-D UNCHANGED

CHKERI:	MOVE IOS,MTASTS(U)	;GET STATUS BITS
	TXNN IOS,MT%EOF!MT%DAE!MT%DVE!MT%IRL
	RETSKP			;NO ERRORS OR EOF
	JRST CHKER1

CHKERO:	MOVE IOS,MTASTS(U)	;GET STATUS BITS
	TXNN IOS,MT%DAE!MT%DVE!MT%IRL
	RETSKP			;NO ERRORS
CHKER1:	MOVEI A,IOX4		;SET UP FOR EOF ERROR
	TXNE IOS,MT%DAE!MT%DVE!MT%IRL	;ANY ERRORS?
	SKIPA A,[IOX5]		;YES, GET ERROR CODE
	TQOA <EOFF>		;MARK EOF FLAG
	TQO <ERRF>		;OR ERROR FLAG
	RET			;AND GIVE ERROR RETURN
;ROUTINE TO SET UP THE STATUS WORD
;ACCEPTS IN A/	IORB ADR
;	CALL SETSTS
;RETURNS +1:	ALWAYS

SETSTS:	JN <IRBAB,IRBFF>,(A),R ;ABORTED OR FREE ARE OK
	JE IRBFR,(A),R		;IF NEVER QUEUED UP, DONT SET STATUS
	MOVE B,IRBSTS(A)	;GET STATUS BITS
	MOVX C,MT%EOT!MT%BOT!MT%EOF ;SET UP TO TEST CONDITIONS
	ANDCAM C,MTASTS(U)	;CLEAR THESE BITS FIRST
	TXNN B,IS.TPM		;EOF SET?
	TXZ C,MT%EOF		;NO
	TXNN B,IS.EOT		;AT END OF TAPE?
	TXZ C,MT%EOT		;NO
	TXNN B,IS.BOT		;OR AT BEGINING OF TAPE
	TXZ C,MT%BOT		;NO
	TXNE B,IS.DTE		;DATA ERROR?
	TXO C,MT%DAE		;YES
	TXNE B,IS.DVE		;DEVICE (HARDWARE) ERROR?
	TXO C,MT%DVE		;YES
	TXNE B,IS.RTL		;RECORD TOO LONG?
	TXO C,MT%IRL		;YES
	IORB C,MTASTS(U)	;SET BITS IN STATUS WORD
	LOAD D,ISFCN,(A)	;GET THE FUNCTION
	CAIN D,IRFRDR		;READ BACKWARDS?
	JRST SETST1		;YES, CHECK RECORD LENGTH
	CAIE D,IRFRED		;READ?
	CAIN D,IRFWRT		;OR WRITE?
SETST1:	SKIPA D,IRBCNT(A)	;YES, CHECK RECORD LENGTH
	JRST SETST2		;NO, DONT SET MT%IRL
	TXNN C,MT%EOF!MT%BOT	;IF NO TRANSFER, DON'T LOSE RECORD SIZE
	STOR D,MTALTC		;REMEMBER THIS FOR MTGTS
	OPSTR <SUB D,>,IRBOC,(A) ;SUBTRACT ORIGINAL COUNT
	TXNE C,OPND		;DUMP MODE?
	SKIPN D			;YES, MUST BE 0 ELSE ERROR
	JRST SETST2		;NO RECORD LENGTH ERROR
	MOVX C,MT%IRL		;SET UP FOR RECORD LENGTH ERROR
	TXNN B,IS.TPM		;SAW A TAPE MARK THIS TIME?
	IORB C,MTASTS(U)	;NO, SET MT%IRL IN MTASTS
SETST2:	RET			;ALL DONE
;ROUTINE TO CHECK IF AN IORB SHOULD BE ABORTED
;ACCEPTS IN A/	IORB ADR
;	CALL MTCHKA		;CALLED FROM PHYTM2
;RTURNS +1:	ABORT THE IORB
;	 +2:	OK

	RESCD

MTCHKA:	LOAD B,IRBUN,(A)	;GET UNIT NUMBER
	JE ABORTF,(B),RSKP	;IF ABORT FLAG = 0, GIVE OK RETURN
	SETONE IRBAB,(A)	;MARK THAT THE IORB WAS ABORTED
	RET			;LET PHYSIO MARK THIS AS DONE

	SWAPCD



;ROUTINE TO QUEUE UP IORB'S FOR FILLING
;ACCEPTS IN A/	RECORD SIZE
;	    B/	FUNCTION CODE
;	CALL MTIRQI
;RETURNS +1:	ERROR
;	 +2:	SUCCESSFUL

MTIRQI:	STKVAR <MTIRQR,MTIRQF>
	MOVEM A,MTIRQR		;SAVE THE RECORD SIZE
	MOVEM B,MTIRQF		;SAVE FUNCTION CODE
MTIRQ0:	CALL GETCSB		;GET ADR OF THIS IORB
	JN IRBFA,(A),RSKP	;IF IORB IS STILL ACTIVE, ALL DONE
	JN IRBAB,(A),MTIRQ1	;IF ABORTED, USE THIS IORB
	LOAD B,IRBFQ,(A)	;GET QUEUED FLAG
	LOAD C,ISFCN,(A)	;GET FUNCTION CODE OF THIS IORB
	CAIE C,IRFRDR		;READ BACKWARDS
	CAIN C,IRFRED		;OR READ AHEAD?
	JUMPN B,RSKP		;YES, CAUGHT UP WITH USER
MTIRQ1:	CALL GETIRB		;GET NEXT IORB (SHOULD NOT BLOCK)
	 RET			;AN ERROR OCCURED
	MOVE B,MTIRQR		;GET RECORD SIZE
	MOVE C,MTIRQF		;AND FUNCTION CODE
	CALL MTAIRQ		;QUEUE UP THIS IORB FOR READING
	JRST MTIRQ0		;LOOP BACK TILL CAUGHT UP WITH EMPTIER
;ROUTINE TO QUEUE 1 IORB FOR FILLING
;ACCEPTS IN A/	ADR OF IORB TO BE USED
;	    B/	RECORD SIZE
;	    C/	FUNCTION CODE
;	CALL MTIRQ1
;RETURNS +1:	ALWAYS

MTAIRQ:	STKVAR <MTIRQA,MTIRQB,MTIRQC,MTIRQP,MTIRQT,MTIRQF>
	MOVEM A,MTIRQA		;SAVE ADDRESS OF IORB
	MOVEM B,MTIRQT		;SAVE SIZE OF RECORD
	MOVEM B,IRBCNT(A)	;STORE CHARACTER COUNT
	STOR B,IRBOC,(A)	;SAVE ORIGINAL COUNT FOR CHKERR
	MOVEM C,MTIRQF		;SAVE FUNCTION FOR LATER
	STOR C,ISFCN,(A)	;STORE FUNCTION CODE
	ADDI A,MTIRTL		;GET POINTER TO IO LIST AREA
	MOVEM A,MTIRQC		;SAVE FOR STORING LIST LATER
	LOAD B,MTPPB		;GET PAGES PER BUFFER
	MOVEM B,MTIRQP		;SAVE THIS COUNT
	OPSTR <IMUL B,>,MTCSB	;THEN GET START OF AREA FOR THIS BUFFER
	OPSTR <ADD B,>,MTBUF	;GET ADR OF PAGE TO BE FILLED
	MOVEM B,MTIRQB
	MOVE A,MTIRQA		;GET IORB ADR AGAIN
	STOR B,IRBPB,(A)	;SAVE ADR OF LIST OF PAGES FOR MTAINT
MTIRQ2:	HRRZS A,(B)		;ZERO PHYSICAL PAGE IN CASE NOT LOCKED
	SKIPG MTIRQT		;ANY MORE BYTES TO BE TRANSFERED?
	JRST [	MOVE C,MTIRQC	;NO, GO END TRANSFER LIST
		JRST MTIRQ4]
	CALL MLKMA		;LOCK DOWN THIS PAGE
	MOVE B,MTIRQB		;GET INDEX INTO PAGE LIST AGAIN
	HRLM A,(B)		;STORE PHYSICAL PAGE ADDRESS
	MOVE B,MTIRQF		;GET FUNCTION
	CAIE B,IRFRED		;READING?
	CAIN B,IRFRDR		;OR READ REVERSE?
	CALL MRKMPG		;YES, MARK THAT PAGE IS MODIFIED
	MOVE B,MTIRQB		;GET PAGE NUMBER AGAIN
	HLRZ B,(B)		;...
	LSH B,PGSFT		;GET ADDRESS FROM PAGE NUMBER
	LOAD A,MTHBW		;GET HARDWARE BYTES PER WORD
	IMULI A,PGSIZ		;ASK FOR A PAGE TO BE FILLED
	CAMLE A,MTIRQT		;ENOUGH BYTES FOR A FULL PAGE?
	MOVE A,MTIRQT		;NO, JUST DO THE REMAINDER OF BYTES
	SUBM A,MTIRQT		;DECREMENT THE COUNT OF BYTES LEFT
	MOVNS MTIRQT		;SUBM DOESNT DO WHAT WAS DESIRED
	OPSTR <HRL A,>,MTDM	;GET MODE OF TRANSFER
	;..
	;..
	MOVE D,MTIRQF		;GET FUNCTION AGAIN
	CAIE D,IRFRED		;READING?
	CAIN D,IRFRDR		;OR READING BACKWARDS
	SKIPA			;YES
	JRST MTIRQ3		;NO
	JE MTRBF,,MTIRQ3	;READING BACKWARDS?
	TRO B,777		;START AT END OF THIS PAGE
	TXO A,1B0		;YES, TELL PHYSIO THAT
MTIRQ3:	HLRZ C,MTCUTB(U)	;GET CDB FOR THIS UNIT
	CALL PHYCCW		;GET IOWD FOR TRANSFER LIST
	MOVEM A,@MTIRQC		;SAVE IOWD IN TRANSFER LIST
	AOS B,MTIRQB		;STEP TO NEXT PAGE
	AOS C,MTIRQC		;STEP POINTER TO IORB TRANSFER LIST
	SOSLE MTIRQP		;ANY MORE PAGES TO BE DONE?
	JRST MTIRQ2		;LOOP BACK FOR ALL IOWD'S
MTIRQ4:	SKIPLE MTIRQP		;IF USED ALL PAGES IN LIST, DONT SETZM
	SETZM 0(C)		;END TRANSFER LIST WITH A ZERO
	MOVE A,MTIRQA		;GET POINTER TO IORB
	STOR C,IRBTL,(A)	;SAVE POINTER TO TAIL
	MOVEI C,MTIRTL(A)	;GET POINTER TO TRANSFER LIST HEAD
	STOR C,IRBHD,(A)	;STORE HEAD POINTER
	CALL SETMOD		;SET UP MODE WORD
	MOVE D,[MTCHKA,,MTAINT]	;NOW SET UP INTERRUPT LEVEL HANDLER ADR
	MOVEM D,IRBIVA(A)	;IN IORB
	CALLRET QUEIRB		;GO QUEUE UP THE IORB


;ROUTINE TO SET UP MODE WORD IN IORB
;ACCEPTS IN A/	IORB ADR
;	CALL SETMOD
;RETURNS +1:	ALWAYS - IORB ADR STILL IN A

SETMOD:	LOAD D,MTDM		;SET UP DATA MODE
	STOR D,IRBDM,(A)
	LOAD D,MTDN		;SET UP DENSITY
	STOR D,IRBDN,(A)
	LOAD D,MTPAR		;AND SET UP PARITY
	STOR D,IRBPAR,(A)
	RET
;ROUTINE TO MARK THAT IORB IS READY AND UNLOCK BUFFER PAGES
;CALLED AT INTERRUPT LEVEL BY PHYSIO
;ASSUMES IN A/	ADR OF IORB
;	CALL MTAINT
;RETURNS +1:	ALWAYS

	RESCD

MTAINT:	LOAD B,IRBFA,(A)	;MAKE SURE THIS IORB IS REALLY ACTIVE
	JUMPE B,NOACTV		;IF 0, A FATAL STATE OF CONFUSION
	MOVE B,IRBSTS(A)	;GET STATUS BITS FROM IORB
	TXNE B,IS.ERR!IS.TPM	;ERROR OR EOF?
	JRST MTAINE		;YES, GO FLUSH ALL QUEUED REQUESTS
MTAIN0:	CALLRET MTAIND		;NO, GO UNLOCK PAGES AND MARK DONE

MTAINE:	TXNN B,IS.TPM!IS.DTE!IS.DVE!IS.WGU!IS.NRT
	JRST MTAIN0		;DONT ABORT FOR NO GOOD REASON
	SAVEQ			;GET SOME PERMANENT ACS
	LOAD U,IRBUN,(A)	;GET UNIT NUMBER
	CALL MTAIND		;UNLOCK PAGES
	CALLRET MTAKIL		;KILL ALL IORBS LEFT ON QUEUE


NOACTV:	BUG(MTARIN)

	SWAPCD


;ROUTINE TO KILL ALL QUEUED UP REQUESTS

	RESCD

MTAKIL:	STKVAR <MTAKLA>
	SETONE ABORTF,(U)	;MARK THAT IORB'S SHOULD BE ABORTED
	MOVE A,MTCUTB(U)	;SET UP CDB ,, UDB FOR PHYKIL
	CALL PHYKIL		;DEQUEUE ALL IORB'S
MTAKL1:	HRRZM A,MTAKLA		;SAVE ADR OF NEXT IORB
	JUMPE A,R		;IF NONE, RETURN
	HRRZS A			;CLEAR HIGH ORDER BITS
	SETONE IRBAB,(A)	;MARK IORB AS BEING ABORTED
	HRRZ B,IRBIVA(A)	;GET INTERRUPT LEVEL ROUTINE TO  CALL
	CALL 0(B)		;CLEAN UP IORB
	HRRZ A,@MTAKLA		;GET NEXT IORB
	JRST MTAKL1		;LOOP BACK TIL ALL IORB'S DEQUEUED

	SWAPCD
;ROUTINE TO DEQUEUE ONE IORB

	RESCD

MTAIND:	SAVEQ			;SAVE ALL PERMANENT ACS USED
	MOVX B,IRBFR		;MARK THAT BUFFER IS READY
	IORM B,MTIRSD(A)
	MOVX B,IRBFA		;AND CLEAR ACTIVE BIT
	ANDCAM B,MTIRSD(A)
	LOAD U,IRBUN,(A)	;GET UNIT NUMBER
	LOAD B,MTPPB		;GET COUNT OF PAGES THAT NEED UNLOCKING
	MOVNS B			;SET UP FOR AOBJN POINTER
	LOAD Q3,IRBPB,(A)	;GET ADDRESS OF LIST OF LOCKED PAGES
	HRL Q3,B		;Q3 = -MTPPB ,, ADR OF LOCKED PAGES
MTAIN1:	HLRZ A,(Q3)		;GET PHYSICAL ADR OF LOCKED PAGE
	JUMPE A,MTAIN2		;IF AT END OF LOCKED PAGES, STOP
	CALL MULKCR		;UNLOCK IT
	AOBJN Q3,MTAIN1		;LOOP BACK TILL ALL PAGES UNLOCKED
MTAIN2:	DECR MTNIR		;DECREMENT NUMBER OF REQUESTS PENDING
	RET			;AND RETURN

	SWAPCD
;JSYS TO SET UP LOGICAL TO PHYSICAL CORRESPONDENCE. ;INPUT IS:
;	USER A/ SLAVE,,UNIT NUMBER
;	USER B/ SERIAL NUMBER

.MTALN::MCENT
	MOVX B,SC%WHL!SC%OPR
	TDNN B,CAPENB		;IS THIS A PRIVILEGED JOB?
	ITERR (WHELX1)		;NO. COMPLAIN
	HRLI A,600002		;MAGTAPE TYPE
	CALL CHKDES		;MAKE SURE IS A VALID UNIT
	 ITERR()		;CAN'T GET IT
	HLRZ U,DEV		;GET UNIT
	XCTU [SKIPN B,B]	;A VALID SERIAL #
	ITERR ()		;NO
	XCTU [HLRZ P5,A]	;GET DEVICE TYPE
	SKIPN P5		;IS THERE ONE?
	MOVEI P5,.MTT45		;NO ASSUME 45
	JRST MTALNA

	RESCD			;MUST BE RESIDENT

MTALNA:	IOPIOF			;DISABLE INTERRUPTS
	MOVSI P3,-MTAN		;SET UP TO SEARCH ALL UNITS
MTLUN1:	SKIPN C,MTCUTB(P3)	;GET UDB ADDRESS FOR THIS UNIT
	JRST MTLUN2		;NONE THERE. FORGET IT
	HRRZ D,C		;GET ADDRESS ONLY
	CAME B,UDBDSN(D)	;IS THIS THE ONE?
	JRST MTLUN2		;NO. KEEP LOOKING
	LOAD P6,USTYP,(D)	;GET TYPE OF SLAVE
	CAIE P6,0(P5)		;MATCH?
	JRST MTLUN2		;NOPE TRY NEXT ENTRY
	CAIN U,0(P3)		;IS THIS ALREADY CORRECT?
	JRST MTALNX		;YES. JUST RETURN GOOD
	MOVX B,OPN		;SEE IF UNIT NOW ASSIGNED
	TDNN B,MTASTS(U)	;IS THIS ONE BEING USED?
	TDNE B,MTASTS(P3)	;IS IT NOW BEING USED?
	JRST [	IOPION	;TURN DISKS BACK ON
		ITERR (OPNX7)]	;UNAVAILABLE
	EXCH C,MTCUTB(U)	;SWITCH ASSIGNMENTS
	MOVEM C,MTCUTB(P3)	;DITTO
MTALNX:	IOPION			;ENABLE I/O
	JRST MRETN		;GOOD

MTLUN2:	AOBJN P3,MTLUN1		;DO ALL UNITS
	IOPION			;TURN DISKS ON AGAIN
	ITERR()			;NONE FOUND
	SWAPCD			;BACK TO SWAPPABLE CODE
;MTOPR JSYS
;ACCEPTS IN B/	OPERATION
;	CALL MTMTAP
;RETURNS +1:	ROUTINE WANTS TO BLOCK (BLKF SET) OR ERROR
;	 +2:	DONE

MTMTAP::STKVAR <MTMTAO,MTMTAE>
	MOVEM B,MTMTAO		;SAVE OPERATION CODE
	HLRZ U,DEV		;SET UP UNIT NUMBER
	MOVX IOS,DMPWT!MTNOWT	;CLEAR THESE FLAGS
	ANDCAB IOS,MTASTS(U)
	SKIPL B			;LEGAL OPERATION?
	CAIL B,MTMTBL		;LEGAL OPERATION?
	RETBAD (MTOX1)		;NO, ERROR
	SKIPN A,MTMTAB(B)	;GET FLAGS
	RETBAD (MTOX1)		;ILLEGAL OPERATION
	TRNE A,MTONOF		;NEED OPEN JFN?
	JRST MTMTP1		;NO, SKIP OPEN CHECKS
	TXNN IOS,MTOWT		;OK IF NOT FIRST TIME
	TXNE IOS,OPN		;OPENED?
	SKIPA			;YES
	RETBAD (CLSX1)		;FILE NOT OPENED ERROR
	CALL MTACLW		;WAIT FOR ACTIVITY TO STOP
	 RET			;NEED TO BLOCK
	CALL UPDSTS		;UPDATE STATUS
	 RET			;NEED TO BLOCK
MTMTP1:	MOVE B,MTMTAO		;GET BACK OPERATION CODE
	HLRZ A,MTMTAB(B)	;GET ROUTINE ADDRESS
	CALL 0(A)		;DO THE OPERATION
	 TDZA B,B		;ERROR OR WAIT
	SETO B,			;SUCCESSFUL
	MOVX C,MTOWT		;ALWAYS CLEAR WAIT BIT
	ANDCAM C,MTASTS(U)
	JUMPN B,RSKP		;IF SUCCESSFUL, RETURN NOW
	TXNE IOS,MTNOWT		;SUPPRESS WAIT BIT?
	RET			;YES. RETURN NOW THEN
	TQNE <BLKF>		;BLOCKING?
	IORM C,MTASTS(U)	;YES, REMEMBER THIS FOR NEXT PASS
	RET


;ROUTINE TO INIT DRIVE STORAGE IF IT IS NOT OPENED

MTNOPN:	LOCK MTALCK(U),<CALL LCKTST>
	CALL MTOPNX		;INIT DATA BASE
	 RET			;ERROR , PASS ON
	RETSKP			;OK - RETURN
;FLAGS FOR MTOPR OPERATIONS

MTONOF==1B18			;NOT NECESSARY TO HAVE JFN OPEN

;TABLE OF MTOPR FUNCTIONS

MTMTAB:	MTACLE,,0		;0  - CLEAR ERRORS
	MTAREW,,0		;1  - REWIND
	MTARBK,,0		;2  - SET READ BACKWARDS
	MTATPM,,0		;3  - WRITE TAPE MARK
	MTASDM,,0		;4  - SET DATA MODE
	MTASRS,,0		;5  - SET RECORD SIZE
	MTAFRC,,0		;6  - FORWARD RECORD
	MTABRC,,0		;7  - BACKWARD RECORD
	MTAEOT,,0		;10 - SKIP TO EOT
	MTARWU,,0		;11 - REWIND AND UNLOAD
	MTARDN,,0		;12 - READ DENSITY
	MTAERT,,0		;13 - ERASE TAPE
	MTARDM,,0		;14 - GET DATA MODE
	MTARRS,,0		;15 - GET REC SIZE
	MTAFFL,,0		;16 - FORWARD FILE
	MTABFL,,0		;17 - BACKWARD FILE
	MTASPA,,0		;20 - SET PARITY
	MTARPA,,0		;21 - READ PARITY
	MTANRB,,0		;22 - GET # OF BYTES LEFT IN RECORD
	MTRECO,,0		;23 - OUTPUT RECORD
	MTASDN,,0		;24 - SET DENSITY
	MTAINF,,MTONOF		;25 - GET TAPE INFO
	MTARDR,,0		;26 - READ DIRECTION
	MTASID,,MTONOF		;27 - SET REEL ID
	MTAIEL,,0		;30 - INHIBIT ERROR LOGGING
	RSKP,,0			;31 - WAIT NOP
	MTALOC,,MTONOF		;32 - ATTACH MT TO MTA
	0
	0
	0
	0
	MTASTA,,MTONOF		;37 - MAGTAPE DRIVE STATUS
	MTAONL,,MTONOF		;40 - ENABLE ON/OFFLINE PSI
	REPEAT 2,<0>		;41-42 UNDEFINED
	MTAREW,,0		;SAME AS .MOREW (IS .MORVL)

MTMTBL==.-MTMTAB		;SIZE OF MTOPR DISPATCH TABLE
;ROUTINE TO CLEAR ERRORS

MTACLE:	MOVX A,MT%DVE!MT%DAE!MT%IRL!MT%EOT!MT%EOF
	TDNN A,MTASTS(U)	;ANY ERRORS SHOWING?
	RETSKP			;NO, DONT CLEAR ABORTF
	ANDCAM A,MTASTS(U)
	SETZRO ABORTF,(U)
	TQZ <ERRF,EOFF>		;CLEAR STS ALSO
	RETSKP			;EXIT SUCCESSFULLY


;ROUTINE TO SET OR CLEAR THE READ BACKWARDS FLAG

MTARBK:	CALL MTPOS0		;POSITION TAPE TO WHERE USER EXPECTS IT
	 RET			;NEED TO BLOCK
	UMOVE T1,3		;GET NEW VALUE
	STOR T1,MTRBF		;SAVE NEW SETTING OF FLAG
	RETSKP			;EXIT


;ROUTINE TO POSITION TAPE TO WHERE USER THINKS IT SHOULD BE
;	CALL MTPOS0
;RETURNS +1:	NEEDS TO BLOCK
;	 +2:	DONE

MTPOS0:	MOVEI A,0		;SET UP TO POSITION HEAD CORRECTLY
	JE MTRBF,,MTPOS1	;READING BACKWARDS?
	CALLRET MTFRC0		;NO, MOVE TAPE FORWARD OVER READ AHEAD

MTPOS1:	CALLRET MTBRC0		;BACK UP OVER READ AHEAD


;ROUTINE TO READ THE DIRECTION OF READ TRANSFER

MTARDR:	LOAD T1,MTRBF		;GET READ BACKWARDS FLAG
	UMOVEM T1,3		;GIVE IT TO USER
	RETSKP


;ROUTINE TO SET DATA MODE

MTASDM:	SAVEQ
	XCTU [HRRZ Q3,3]	;GET NEW DATA MODE
	CAILE Q3,MTMXDM		;LEGAL?
	RETBAD (MTOX5)		;NO, ILLEGAL DATA MODE
	CALL MTAPBO		;OUTPUT PARTIAL BUFFER IF ANY
	 RET			;NEEDS TO BLOCK
	SKIPN Q3		;IS THIS 0?
	LOAD Q3,JSMTM		;YES, GET JOB DEFAULT
	SKIPN Q3		;IS THAT NOT SET YET?
	MOVEI Q3,MTDFDM		;YES, USE SYSTEM DEFAULT
	STOR Q3,MTDM		;STORE NEW DATA MODE
	CALL MTARLB		;RELEASE ANY BUFFERS
	SETZM FILLEN(JFN)	;THROW AWAY ANY DATA IN BUFFERS
	SETZM FILBYN(JFN)
	SETZM FILCNT(JFN)
	CALLRET MTASBW		;SET UP OTHER PARAMETERS BASED ON MODE


;ROUTINE TO READ DATA MODE

MTARDM:	LOAD T1,MTDM		;GET DATA MODE
	UMOVEM T1,3		;RETURN IT TO USER
	RETSKP			;AND GIVE SUCCESSFUL RETURN
;ROUTINE TO SET RECORD SIZE

MTASRS:	MOVE IOS,MTASTS(U)	;GET STATUS
	TXNE IOS,OPND		;DUMP MODE IN EFFECT?
	RETBAD (MTOX3)		;YES, ERROR
	TXNE IOS,BUFA		;BUFFERS ASSIGNED YET?
	RETBAD(MTOX2)		;YES, RECORD SIZE MUST BE SET BEFORE I/O IS DONE
	XCTU [HRRZ T1,3]	;GET NEW SIZE
	STOR T1,MTRS		;STORE NEW RECORD SIZE
	CALLRET MTASBW		;GO COMPUTE NEW PARAMETERS


;ROUTINE TO READ RECORD SIZE

MTARRS:	LOAD T1,MTRS		;GET RECORD SIZE
	UMOVEM T1,3		;RETURN IT TO USER
	RETSKP			;AND GIVE SUCCESSFUL RETURN



;ROUTINE TO SET REEL I.D.

MTASID:	MOVE T1,CAPENB		;CHECK CAPABILITIES
	TRNN T1,SC%WHL!SC%OPR	;WHEEL OR OPERATOR?
	RETBAD (MTOX7)		;NO, NOT PRIVILEGED TO DO THIS FUNCTION
	UMOVE T1,3		;GET I.D.
	HRRZ T2,MTCUTB(U)	;GET UDB ADR
	MOVEM T1,UDBVID(T2)	;STORE NEW I.D.
	RETSKP


;ROUTINE TO SET ERROR LOGGING FLAG

MTAIEL:	MOVX T1,MTIEL		;GET FLAG
	ANDCAM T1,MTASTS(U)	;CLEAR IT
	XCTU [SKIPE 3]		;USER WANT TO SET IT?
	IORM T1,MTASTS(U)	;YES
	RETSKP
;ROUTINE TO SET DENSITY
;ENTRY FROM JSYS

MTASDN:	XCTU [HRRZ T1,3]	;GET NEW DENSITY

;ENTRY FROM MT TO SET DENSITY FROM VAULE IN REG
MTADNS::CAILE T1,MTMXDN		;LEGAL?
	RETBAD (MTOX6)		;NO, ILLEGAL DENSITY
	SKIPN T1		;WANT DEFAULT?
	LOAD T1,JSMTD		;YES, GET JOB DEFAULT
	SKIPN T1		;GOT ONE YET?
	MOVEI T1,MTDFDN		;NO, USE SYSTEM DEFAULT
	STOR T1,MTDN		;STORE IT
	RETSKP


;ROUTINE TO READ THE DENSITY

MTARDN:	HRRZ T1,MTCUTB(U)	;GET UDB
	SKIPGE T1,UDBDDP+0(T1)	;HARDWARE DETERMINED DENSITY SET?
	LOAD T1,MTDN		;NO - GET THE USER DENSITY
	UMOVEM T1,3		;RETURN IT TO USER
	RETSKP			;AND GIVE SUCCESSFUL RETURN



;ROUTINE TO SET PARITY

MTASPA:	UMOVE T1,3		;GET NEW PARITY SETTING
	STOR T1,MTPAR		;SAVE IT
	RETSKP


;ROUTINE TO READ PARITY SETTING

MTARPA:	LOAD T1,MTPAR		;GET PARITY SETTING
	UMOVEM T1,3		;RETURN IT TO USER
	RETSKP			;AND GIVE SUCCESSFUL RETURN



;ROUTINE TO GET THE NUMBER OF BYTES LEFT IN BUFFER

MTANRB:	MOVE IOS,MTASTS(U)	;GET STATUS
	TXNE IOS,OPND		;MUST BE SEQUENTIAL I/O MODE
	RETBAD (MTOX3)		;THIS FUNCTION NOT LEGAL FOR DUMP MODE
	SKIPE T1,FILLEN(JFN)	;ANY BUFFER SET UP
	SUB T1,FILBYN(JFN)	;YES, GET NUMBER OF BYTES REMAINING
	UMOVEM T1,3		;RETURN IT TO USER
	RETSKP			;AND GIVE SUCCESSFUL RETURN
;ROUTINE TO RETURN INFORMATION ABOUT A TAPE

MTAINF:	SAVEPQ			;SAVE PERMANENT ACS
	UMOVE P3,3		;GET POINTER TO ARGUMENT BLOCK
	HRRZ Q3,MTCUTB(U)	;GET POINTER TO UDB
	XCTU [HRRZ P5,0(P3)]	;GET COUNT OF WORDS TO BE RETURNED
	CAILE P5,MTIFTL		;TOO MANY?
	RETBAD (MTOX8)		;YES, ARGUMENT BLOCK TOO LONG
	MOVNS P5
	HRLZS P5		;SET UP AOBJN POINTER
MTAIFL:	AOS P3			;STEP POINTER TO ARGUMENT BLOCK
	XCT MTINFT(P5)		;GET NEXT WORD
	UMOVEM T1,0(P3)		;STORE IT IN USER'S BLOCK
	ERJMP [	RETBAD (MTOX13)]
	AOBJN P5,MTAIFL		;LOOP BACK UNTIL DONE
	RETSKP

MTINFT:	LOAD T1,USTYP,(Q3)	;TAPE TYPE CODE
	MOVE T1,UDBVID(Q3)	;TAPE ID
	CALL MTASER		;DRIVE SERIAL NUMBER
	MOVE T1,UDBRED(Q3)	;FRAMES READ
	MOVE T1,UDBWRT(Q3)	;FRAMES WRITTEN
	MOVE T1,UDBPS2(Q3)	;RECORD # WITHIN CURRENT FILE
	MOVE T1,UDBPS1(Q3)	;FILE # ON TAPE
	MOVE T1,UDBSRE(Q3)	;SOFT READ ERRORS
	MOVE T1,UDBSWE(Q3)	;SOFT WRITE ERRORS
	MOVE T1,UDBHRE(Q3)	;HARD READ ERRORS
	MOVE T1,UDBHWE(Q3)	;HARD WRITE ERRORS
	MOVE T1,UDBRCT(Q3)	;READ COUNT
	MOVE T1,UDBWCT(Q3)	;WRITE COUNT
MTIFTL==.-MTINFT

;ROUTINE TO GET SERIAL # OF UNIT

MTASER:	HRRZ B,UDBDSN(Q3)	;GET DRIVE SERIAL #
	MOVE C,UDBSLV(Q3)	;GET SLAVE NUMBER
	DPB C,[POINT 3,B,17]
	MOVE C,UDBADR(Q3)	;GET TM02 NUMBER
	DPB C,[POINT 3,B,14]
	MOVE A,UDBCDB(Q3)	;GET CHANNEL #
	MOVE C,CDBADR(A)
	DPB C,[POINT 3,B,11]
	MOVE A,B		;RETURN CHAN,CONTRL,UNIT ,, SERIAL #
	RET
;ROUTINE TO REWIND THE TAPE

MTAREW:	CALL MTARWX		;FINISH OUTPUT/CLEAR INPUT
	 RET			;NEEDS TO BLOCK
	CALL GETIRB		;GET AN IORB TO USE
	 RET			;NEED TO WAIT FOR ONE TO BE FREE
	MOVEI B,IRFREW		;GET REWIND FUNCTION CODE
MTARW1:	MOVEI C,1		;DO ONE OPERATION
	CALL MTPIRQ		;QUEUE UP THIS REQUEST
	RETSKP			;ALL DONE


;ROUTINE TO REWIND AND UNLOAD

MTARWU:	CALL MTARWX		;FINISH OUTPUT/CLEAR INPUT
	 RET			;NEEDS TO BLOCK
	CALL GETIRB		;GET AN IORB
	 RET
	MOVEI B,IRFRUN		;SET UP OPERATION CODE
	JRST MTARW1		;GO DO THE OPERATION

;COMMON ROUTINE FOR REWINDS TO FINISH OUTPUT OR CLEAR INPUT

MTARWX:	TQNE <OPNF>		;IF NOT OPENED
	TXNE IOS,OPND		;DUMP MODE?
	RETSKP			;YES - DO NOTHING
	TQNN <WRTF>		;WRITING?
	JRST MTRWXR		;NO
	CALLRET MTAPBO		;YES - DO PARTIAL BUFFER OUTPUT

MTRWXR:	SKIPN FILBYN(JFN)	;BUFFER EXIST?
	RETSKP			;NO
	CALL CLRINP		;YES - CLEAR IT
	 MTERET()		;ERROR
	RETSKP

;ROUTINE TO ERASE GAP

MTAERT:	TQNE <OPNF>		;MUST BE OPENED
	TQNN <WRTF>		;MUST BE OPENED FOR WRITE
	RETBAD (IOX2)		;ILLEGAL WRITE ATTEMPT
	CALL MTAPBO		;OUTPUT PARTIAL BUFFER IF ANY
	 RET			;NEEDS TO BLOCK
	CALL GETIRB		;GET AN IORB TO USE
	 RET
	MOVEI B,IRFERG		;GET OPERATION CODE
	JRST MTARW1		;GO DO OPERATION
;ROUTINE TO FORCE OUT ANY PARTIAL BUFFER
;	CALL MTAPBO
;RETURNS +1:	NEED TO BLOCK
;	 +2:	OK

MTAPBO:	CALL MTRECO		;OUTPUT RECORD
	 JFCL			;NOT DOING SEQUENTIAL OUTPUT
	CALLRET UPDSTS		;WAIT FOR IT TO STOP WRITING


;ROUTINE TO SKIP TO END OF TAPE

MTAEOT:	MOVE IOS,MTASTS(U)	;GET FLAGS
	TXNE IOS,MTOWT		;FIRST TIME THRU?
	JRST MTAET1		;NO
	CALL MTABRC		;FIRST TIME, DO A BACKSPACE
	 RET			;NEED TO BLOCK
MTAET2:	SETZRO MTSTC		;SET COUNT OF EOF'S SEEN TO ZERO
	CALL MTAFFL		;FORWARD SPACE OVER A FILE
	 RET			;NEED TO BLOCK
	JRST MTAET1		;GO SEE IF NEXT RECORD IS AN EOF ALSO

MTAET1:	CALL UPDSTS		;GET CURRENT STATUS
	 RET			;NEED TO BLOCK
	LOAD A,MTFCN		;GET LAST OPERATION DONE
	CAIN A,IRFBSB		;BACKSPACE?
	JRST MTAET2		;YES, GO START SEARCHING FOR EOT
	MOVE IOS,MTASTS(U)	;GET STATUS
	TXNN IOS,MT%EOF		;AT END OF FILE?
	JRST MTAET2		;NO, GO SKIP A FILE
	INCR MTSTC		;STEP STATE CODE
	LOAD A,MTSTC		;GET COUNT OF EOF'S SEEN
	CAIL A,2		;LESS THAN 2?
	JRST MTAET3		;NO, FOUND EOT
	CALL MTAFRC		;SPACE FORWARD ONE RECORD
	 RET			;NEED TO BLOCK
	JRST MTAET1		;GO SEE IF ON ANOTHER EOF

MTAET3:	CAIE A,2		;JUST FOUND THE SECOND TAPE MARK?
	RETSKP			;NO, MUST BE DONE NOW
	CALLRET MTABRC		;YES, BACKSPACE OVER SECOND EOF
;ROUTINE TO SPACE OVER A FILE

MTAFFL:	MOVE IOS,MTASTS(U)	;GET THE STATUS
	TXNN IOS,MTOWT		;FIRST TIME THRU?
	JRST [	CALL MTCNCL	;CANCEL READ AHEAD
		 JRST [	TXO IOS,MTNOWT ;NO MTOPR WAIT
			RETBAD()] ;DONE
		JRST MTAFF1]	;TRY FOR ONE TO START
MTAFF0:	CALL UPDSTA		;UPDATE THE STATUS WORD
	 RET			;NEED TO BLOCK
	CALL CHKERO		;SEE IF ANY ERRORS OCCURED
	 RET			;YES, STOP NOW
	TXNE IOS,MT%EOF		;HIT A TAPE MARK YET?
	RETSKP			;YES, ALL DONE
	SKIPA A,[MTSPCN]	;GET MAX # OF RECORDS TO DO AT A TIME
MTAFF1:	MOVEI A,1		;DO 1 RECORD FOR THE FIRST TIME ONLY
	CALL MTFRC0		;GO SPACE FORWARD A BIT
	 RET			;NEED TO BLOCK
	JRST MTAFF0		;LOOP BACK TIL A TAPE MARK SEEN


;ROUTINE TO SPACE THE TAPE FORWARD ONE RECORD

MTAFRC:	MOVEI A,1		;SPACE FORWARD ONE RECORD
	CALLRET MTFRC0		;DO THE WORK

MTFRC0:	STKVAR <MTAFRS>
	MOVEM A,MTAFRS		;SAVE THE SPACING COUNT
	MOVE IOS,MTASTS(U)	;GET CURRENT STATUS
	TQNE <OPNF>		;IF NOT OPENED
	TXNE IOS,OPND		;IN DUMP MODE?
	JRST MTFRC2		;YES, JUST GO DO OPERATION
	TQNE <WRTF>		;WRITING?
	JRST [	CALL MTRECO	;YES, WRITE OUT ANY PARTIAL BUFFERS
		 RET		;NEED TO BLOCK
		JRST MTFRC2]	;GO SPACE
	SETZ B,			;SPECIFY THAT DIRECTION IS FORWARD
	CALL MTBCNT		;COUNT THE READ AHEAD BUFFERS
	 RET			;ERROR
	MOVEM A,MTAFRS		;SAVE COUNT OF RECORDS TO SPACE OVER
MTFRC2:	SKIPG MTAFRS		;ANYTHING TO DO?
	RETSKP			;NO
	CALL GETIRB		;GET AN IORB TO USE
	 RET			;NEED TO BLOCK
	MOVEI B,IRFFSB		;GET FUNCTION CODE
	MOVE C,MTAFRS		;GET COUNT OF RECORDS TO SPACE OVER
	CALL MTPIRQ		;DO THE SPACING OPERATION
	RETSKP			;ALL DONE
;ROUTINE TO BACKSPACE OVER ONE FILE

MTABFL:	MOVE IOS,MTASTS(U)	;GET FLAGS
	TXNN IOS,MTOWT		;FIRST TIME THRU?
	JRST [	CALL MTCNCL	;CANCEL READ AHEAD
		 JRST [	TXO IOS,MTNOWT ;NO MTOPR WAIT
			RETBAD ()]
		JRST MTABF1]	;AND DO BS
MTABF0:	CALL UPDSTA		;UPDATE THE STATUS WORD
	 RET			;NEED TO BLOCK
	CALL CHKERO		;SEE IF ANY ERRORS OCCURED
	 RET			;YES, ABORT THIS
	TXNE IOS,MT%EOF!MT%BOT	;HIT TAPE MARK YET?
	RETSKP			;YES, ALL DONE
	SKIPA A,[MTSPCN]	;GET MAX # OF RECORDS TO DO AT A TIME
MTABF1:	MOVEI A,1		;DO 1 RECORD FOR THE FIRST TIME ONLY
	CALL MTBRC0		;BACKSPACE SOME
	 RET			;NEED TO BLOCK
	JRST MTABF0		;LOOP BACK TILL EOF HIT


;ROUTINE TO BACKSPACE ONE RECORD

MTABRC:	CALL MTCNCL		;CANCEL READ AHEAD
	 RETBAD ()		;BLOCK OR ERROR
	MOVEI A,1		;SET UP TO BACK SPACE ONE RECORD
	CALLRET MTBRC0		;DO IT

MTBRC0:	STKVAR <MTABRN>
	MOVEM A,MTABRN		;STORE COUNT OF RECORDS TO SPACE OVER
	MOVE IOS,MTASTS(U)	;GET STATUS BITS
	TQNE <OPNF>		;IF NOT OPENED
	TXNE IOS,OPND		;DUMP MODE?
	JRST MTBRC2		;YES, GO DO THE OPERATION DIRECTLY
	TQNE <WRTF>		;WRITING?
	JRST [	CALL MTRECO	;YES, FORCE OUT THE LAST PARTIAL BUFFER
		 RET		;NEED TO BLOCK
		JRST MTBRC2]	;THEN GO BACKSPACE
	SETO B,			;SPECIFY THAT DIRECTION IS BACKWARDS
	CALL MTBCNT		;COUNT BUFFERS OF READ AHEAD
	 RET			;ERROR
	MOVEM A,MTABRN		;SAVE COUNT OF RECORDS TO SKIP OVER
MTBRC2:	SKIPG MTABRN		;ANYTHING TO DO?
	RETSKP			;NO
	MOVE IOS,MTASTS(U)	;GET STATUS AGAIN
	TXNE IOS,MT%BOT		;AT TAPE MARK ALREADY?
	RETSKP			;YES, DONT DO ANYTHING
	CALL GETIRB		;GET AN IORB TO USE
	 RET			;MUST WAIT
	MOVEI B,IRFBSB		;SET UP TO DO THE BACKSPACE
	MOVE C,MTABRN		;GET COUNT OF RECORDS TO SKIP
	CALL MTPIRQ		;GO QUEUE UP THIS REQUEST
	RETSKP			;AND EXIT
;SPECIAL ROUTINE USED TO CANCEL READ AHEAD BUFFERS

MTCNCL:	SKIPL IOS,MTASTS(U)	;OPEN?
	RETSKP			;NO. NOTHING TO DO THEN
	TXNE IOS,OPND		;OPEN I DUMP MODE?
	RETSKP			;YES. NOTHING TO CANCEL THEN
	CALL MTACLW		;WAIT FOR ALL IO TO FINISH
	 RETBAD ()		;MUST BLOCK
	CALL MTPOS0		;DO POSITIONING
	 RETBAD()		;BLOCK OR ERROR
	CALL UPDSTA		;UPDATE STATUS
	 RETBAD ()		;NEED TO WAIT FOR ACTIVITY TO CEASE
	MOVX IOS,MT%EOF		;MAKE SURE EOF NOT ON
	ANDCAB IOS,MTASTS(U)	;""
	RETSKP			;AND DONE
;ROUTINE TO COUNT THE BUFFERS OF READ AHEAD
;ACCEPTS IN A/	THE COUNT OF RECORDS TO SKIP
;	    B/	0 = SPACING FORWARD
;		-1= SPACING BACKWARDS
;	CALL MTBCNT
;RETURNS +1:	ERROR
;	 +2:	COUNT OF RECORDS TO SPACE OVER IN AC A

MTBCNT:	STKVAR <MTBCTA>
	MOVEM A,MTBCTA		;SAVE STARTING COUNT
	JE MTRBF,,MTBCT0	;IF NOT READING BACKWARDS, NOT SPECIAL
	SETCA B,		;READING BACKWARDS, COMPLEMENT B
MTBCT0:	JUMPN B,MTBCT3		;GO COUNT BUFFERS
	MOVE A,FILLEN(JFN)	;GET CURRENT END OF BUFFER
	CAMG A,FILBYN(JFN)	;ANY BYTES LEFT IN BUFFER?
	JUMPE A,MTBCT1		;IF NO BUFFER SET UP, DONT CLEAR IT
	CALL CLRINP		;AT END OF BUFFER, CLEAR FILLEN
	 RET			;ERROR
MTBCT1:	SOSGE MTBCTA		;ANYTHING MORE TO DO?
	JRST MTBCT2		;NO
	CALL GTUBFA		;GET A BUFFER IF ANY
	 JRST MTBCT2		;NONE THERE
	CALL SETSTS		;UPDATE THE ERROR AND STATUS WORDS
	CALL IRBDON		;JUST THROW THIS AWAY INSTEAD OF SPACING
	 RET
	CALL STPCUB		;DONE WITH THIS IORB
	JRST MTBCT1		;LOOP BACK TILL DONE

MTBCT2:	AOS A,MTBCTA		;GET COUNT OF RECORDS TO SKIP
	RETSKP			;AND EXIT

MTBCT3:	SKIPG FILLEN(JFN)	;ANY BUFFER SET UP?
	JRST MTBCT4		;NO, JUST COUNT QUEUED UP BUFFERS
	CALL CLRINP		;YES, CLEAR OUT THE BUFFER IN PROGRESS
	 RET			;ERROR OCCURED
MTBCT4:	CALL GTUBFA		;GET NEXT BUFFER QUEUED UP
	 JRST [	MOVE A,MTBCTA	;NO MORE, GET COUNT
		RETSKP]		;AND RETURN
	CALL SETSTS		;UPDATE THE STATUS
	MOVX B,IS.BOT		;HIT BOT?
	TDNN B,IRBSTS(A)	;IF YES, NO TAPE MOVED SO DONT COUNT UP
	AOS MTBCTA		;COUNT UP NUMBER OF RECORDS TO PASS OVER
	CALL IRBDON		;MARK THIS BUFFER AS DONE
	 RET			;ERROR OCCURED
	CALL STPCUB		;STEP TO NEXT USER BUFFER
	JRST MTBCT4		;LOOP BACK TIL ALL QUEUED UP IORBS DONE
;ROUTINE TO QUEUE A MTOPR REQUEST
;ACCEPTS IN A/	IORB ADR
;	    B/	FUNCTION CODE
;	    C/	COUNT
;	CALL MTPIRQ
;RETURNS +1:	ALWAYS

MTPIRQ:	STOR B,ISFCN,(A)	;SAVE FUNCTION CODE IN IORB ALSO
	MOVEM C,IRBCNT(A)	;SAVE COUNT IN IORB
	STOR C,IRBOC,(A)	;SAVE ORIGINAL COUNT ALSO
	MOVE C,[MTCHKA,,MTPINT]	;NOW SET UP INTERRUPT LEVEL HANDLER ADR
	MOVEM C,IRBIVA(A)	;SAVE IT IN IORB
	SETZRO MTCIRB		;CLEAR DUMP MODE MEMORY OF IORB
	CALL SETMOD		;SET UP DENSITY ETC.
	SETZRO ABORTF,(U)	;ALWAYS DO THE OPERATION
	CALLRET QUEIRB		;QUEUE UP THE REQUEST


;ROUTINE TO BE CALLED AT INTERRUPT LEVEL WHEN IORB IS DONE

	RESCD

MTPINT:	LOAD B,IRBFA,(A)	;MAKE SURE THIS IORB IS ACTIVE
	JUMPE B,NOACTV		;IF NOT, BUGHLT
	MOVX B,IRBFR		;MARK THAT BUFFER IS READY
	IORM B,MTIRSD(A)
	MOVX B,IRBFA		;AND CLEAR ACTIVE BIT
	ANDCAM B,MTIRSD(A)
	LOAD B,IRBUN,(A)	;GET UNIT NUMBER
	DECR MTANIR,(B)		;COUNT DOWN # OF BUSY IORB'S
	RET			;AND EXIT

	SWAPCD
;ROUTINE TO WRITE A TAPE MARK

MTATPM:	TQNN <OPNF>		;FILE OPENED?
	RETBAD (IOX2)		;NO - ERROR
	CALL MTAPBO		;OUTPUT PARTIAL BUFFERS IF ANY
	 RET			;NEED TO BLOCK
	LOAD A,MTFCN		;GET LAST FUNCTION
	CAIN A,IRFWTM		;TAPE MARK?
	JRST MTTPM1		;YES
	SETZRO MTNTM		;NO, SET COUNT TO 0
MTTPM1:	CALL GETIRB		;GET AN IORB TO USE
	 RET			;NEED TO BLOCK
	MOVEI B,IRFWTM		;WRITE A TAPE MARK
	MOVEI C,1		;JUST 1
	CALL MTPIRQ		;QUEUE IT UP
	CALL NTMINC		;INCREMENT # OF TAPE MARKS WRITTEN
	RETSKP			;ALL DONE


;ROUTINE TO WRITE N TAPE MARKS
;ACCEPTS IN A/	NUMBER OF TAPE MARKS TO BE WRITTEN
;	CALL MTAWTM
;RETURNS +1:	NEED TO BLOCK
;	 +2:	DONE

MTAWTM:	STKVAR <MTAWTC>
	TQNN <WRTF>		;MUST BE OPENED FOR WRITE
	RETBAD (IOX2)		;ILLEGAL ATTEMPT TO WRITE
	MOVEM A,MTAWTC		;SAVE NUMBER OF TAPE MARKS TO WRITE
	LOAD B,MTFCN		;GET LAST FUNCTION TO BE DONE
	CAIN B,IRFWTM		;WAS A TAPE MARK JUST WRITTEN?
	JRST MTWTM1		;YES
	SETZRO MTNTM		;NO, CLEAR COUNT OF TAPE MARKS WRITTEN
MTWTM1:	LOAD B,MTNTM		;GET COUNT OF TAPE MARKS WRITTEN
	CAML B,MTAWTC		;WRITTEN ENOUGH YET?
	RETSKP			;YES, EXIT
	CALL GETIRB		;GET AN IORB TO USE
	 RET			;NONE AVAILABLE, GO WAIT
	MOVEI B,IRFWTM		;GET FUNCTION CODE
	MOVEI C,1		;ONE OPERATION
	CALL MTPIRQ		;QUEUE UP REQUEST
	CALL NTMINC		;INCREMENT # OF EOF'S WRITTEN
	JRST MTWTM1		;LOOP BACK TIL ALL WRITTEN


;ROUTINE TO INCREMENT # OF TAPE MARKS WRITTEN

NTMINC:	LOAD T1,MTNTM		;GET NUMBER OF TAPE MARKS
	CAIGE T1,2		;ONLY COUNT TO 2
	AOS T1			;INCREMENT COUNT
	STOR T1,MTNTM		;STORE COUNT
	RET
;ROUTINE TO ATTACH AN MTA TO A GIVEN MT
; T2/ ARG ADDRESS

MTALOC:	SAVEAC <Q3,P3>		;SAVE WORK REGS
	MOVE T1,CAPENB		;GET CAPABILITIES
	TXNN T1,SC%WHL!SC%OPR	;*** CHECK FOR TLP INSTEAD ***
	RETBAD (MTOX7)
	UMOVE T2,3		;GET USER BLOCK ADDRESS
	UMOVE T1,0(T2)		;GET COUNT FROM ARG BLOCK
	CAIGE T1,2		;ENOUGH ROOM?
	RETBAD (ARGX04)		;NO.
	MOVEI Q3,-1(T1)		;GET COUNT MINUS THE HEADER
	MOVE P3,T2		;GET ADDRESS
	UMOVE T1,.MOMTN(P3)	;GET MT #
	SETZM T3		;ASSUME DEFAULT DENSITY
	CAIL Q3,.MODNS		;DENSITY GIVEN?
	UMOVE T3,.MODNS(P3)	;YES. GET SPECIFIED DENSITY
	CAILE T3,MTMXDN		;VALID?
	RETBAD (MTOX6)		;NO. ERROR THEN
	CAIGE Q3,.MOCVN		;CURRENT VOLUME NUMBER GIVEN?
	TDZA T2,T2		;NO. SAY NONE GIVEN
	UMOVE T2,.MOCVN(P3)	;YES. GET IT
	CALL SETMTU		;SET CORRESPONDENCE
	 RETBAD ()		;BAD
	CAIL Q3,.MONVL		;HAVE VOLUME LABELS TO DECLARE?
	 JRST [	UMOVE T1,.MOMTN(P3) ;YES. MT UNIT NUMBER
		UMOVE T2,.MOAVL(P3) ;GET ADDRESS OF LABELS
		UMOVE T3,.MONVL(P3) ;GET # OF LABELS
		CALL PUTVOL	;PUT LABELS INTO TAPE'S DATA BASE
		 RETBAD ()	;SOME SORT OF ERROR
		JRST .+1]	;PROCEED
	SOJLE Q3,RSKP		;IF NO MORE, ALL DONE
	UMOVE T1,.MOMTN(P3)	;GET MT UNIT NUMBER AGAIN
	UMOVE T2,.MOLBT(P3)	;GET LABEL TYPE
	SETZM T3		;ASSUME NO VOLUME # PRESENT
	CAIL Q3,.MOCVN-1	;VOLUME # PRESENT
	UMOVE T3,.MOCVN(P3)	;YES. FETCH IT THEN
	SOSL T2			;A VALID TYPE?
	CAILE T2,.LTMAX-1	;STILL?
	RETBAD (ARGX05)		;NO
	XCT [	CALL SETVV	;SET VALID VOLUME
		CALL SETLBL	;SET LABELED
		CALL SETEBD	;SET EBCDIC VOLUME
		CALL SETT20](T2) ;SET TOPS20 VOLUME
	 RETBAD ()		;BAD
	CAIGE Q3,.MOVSN-1	;HAVE A VOLUME SET NAME?
	RETSKP			;ALL DONE
	UMOVE T1,.MOMTN(P3)	;YES. GET MT #
	UMOVE T3,.MOVSN(P3)	;AND GET VOLUME SET NAME
	CALL SETVSN		;SET IT
	 RETBAD ()		;ERROR
	RETSKP			;AND DONE

;ROUTINE TO RETURN CURRENT STATUS OF MTA
;

MTASTA:	SAVEP			;SAVE REGISTERS
	UMOVE P3,3		;GET ADDRESS OF ARGUMENT BLOCK
	UMOVE T3,0(P3)		;GET SIZE OF BLOCK
	ERJMP [	MOVE T1,LSTERR	;GET ERROR CODE
		RETBAD ()]	;RETURN IT TO USER
	SKIPG T3		;DOES USER WANT ANY ARGUMENTS?
	RETBAD (ARGX04)		;NO, ARGUMENT BLOCK TO SMALL
	CALL MTSTGS		;GET STATUS
	SETZ T1,0		;START WITH 0
	TXNE T2,UC.200		;CHECK FOR 200 BPI
	TXO T1,SJ%CP2		;SET 200 BPI
	TXNE T2,UC.556		;556 BPI
	TXO T1,SJ%CP5
	TXNE T2,UC.800		;800 BPI
	TXO T1,SJ%CP8
	TXNE T2,UC.160		;1600 BPI
	TXO T1,SJ%C16
	TXNE T2,UC.625		;6250 BPI
	TXO T1,SJ%C62
	CAIL T3,.MODDN
	UMOVEM T1,.MODDN(P3)	;STORE DENSITIES CAPABLE
	SETZ T1,0		;DO DATA MODES
	TXNE T2,UC.CD		;CORE DUMP
	TXO T1,SJ%CMC
	TXNE T2,UC.6B		;SIXBIT
	TXO T1,SJ%CM6
	TXNE T2,UC.AA		;ANSI ASCII
	TXO T1,SJ%CMA
	TXNE T2,UC.IC		;INDUSTRY COMPATABLE
	TXO T1,SJ%CM8
	TXNE T2,UC.HD		;HIGH DENSITY
	TXO T1,SJ%CMH
	CAIL T3,.MODDM
	UMOVEM T1,.MODDM(P3)	;STORE DATA MODES CAPABLE
	SETZ T1,0		;RESET T1
	TXNE T2,UC.7TK		;CHECK FOR 7 TRACK
	TXOA T1,SJ%7TR		;YES
	TXO T1,SJ%9TR		;NO MUST BE 9 TRACK
	CAIL T3,.MOTRK
	UMOVEM T1,.MOTRK(P3)
	SETZ T1,0		;RESET T1
	TXNE P6,US.OFS		;OFLINE
	TXO T1,SJ%OFS
	TXNE P6,US.MAI
	TXO T1,SJ%MAI		;MAINT MODE
	TXNE P6,US.MRQ		;MAINT MODE REQUESTED
	TXO T1,SJ%MRQ
	TXNE P6,US.BOT		;BOT
	TXO T1,SJ%BOT
	TXNE P6,US.REW		;REWIND
	TXO T1,SJ%REW
	TXNE P6,US.WLK		;WRITE LOCK
	TXO T1,SJ%WLK
	CAIL T3,.MOCST
	UMOVEM T1,.MOCST(P3)	;STORE WORD
	LDB P6,[POINT USSTYP,P6,USPTYP] ;GET DEVICE TYPE
	CAIL T3,.MODVT
	UMOVEM P6,.MODVT(P3)	;STORE DEVICE TYPE
	RETSKP			;DONE AT LAST

	RESCD			;MUST BE RESIDENT CODE
MTSTGS:	IOPIOF			;INTERLOCK WITH MTALN TO PREVENT A MESS
	HRRZ T2,MTCUTB(U)	;GET UDB POINTER
	MOVE P6,UDBSTS(T2)	;GET STATUS WORD
	MOVE T2,UDBCHR(T2)	;GET CHARACTERISTICS WORD
	IOPION			;ENABLE INTERRUPTS AGAIN
	RET
	SWAPCD			;SWAPABLE CODE AGAIN
;
; .MOOFL - ENABLE FOR ONLINE/OFFLINE PSI INTERRUPTS

MTAONL:	MOVX T1,SC%WHL!SC%OPR!SC%MNT	;CHECK PRIVS
	TDNN T1,CAPENB
	RETBAD (CAPX2)			;NOT ENOUGH CAPABILITIES
	MOVEI T1,1		;GET OFFSET TO PSI CHANNEL IN ARG BLOCK
	CALL GETWRD		;GET PSI CHANNNEL TO ENABLE
	 RETBAD (MTOX13)	;ARGUMENT BLOCK TOO SMALL
	CAIN T2,-1		;CHECK FOR -1 (CLEAR)
	JRST [	SETZM MTPSFK(U)	;CLEAR PSI
		RETSKP]		;QUIT
	CAIL T2,0		;CHECK THAT GIVEN PSI CHANNEL IS VALID
	CAILE T2,5		; ASSIGNABLE CHANNEL
	JRST [	CAIL T2,^D24	;CHECK THAT GIVEN PSI CHANNEL IS VALID
		CAILE T2,^D35	; ASSIGNABLE CHANNEL
		RETBAD (MTOX14)	;BAD PSI CHANNEL NUMBER GIVEN
		JRST .+1]	;PSI CHANNEL OK
	HRRM T2,MTPSFK(U)	;SAVE PSI
	MOVE T2,FORKX		;GET FORK NUMBER
	HRLM T2,MTPSFK(U)	;SAVE FORK NUMBER
	RETSKP			;SUCCESS RETURN

;ROUTINE TO KILL ENTRIES IN MTPSFK. IT IS CALLED BY KSELF

MTAKFK::MOVE T1,[-MTAN,,MTPSFK]	;POINTER TO TABLE
MTAFKL:	HLRZ T2,0(T1)		;GET FORK #
	CAIN 7,0(2)		;CHECK AGAINST TABLE
	SETZM 0(T1)		;CLEAR ENTRY
	AOBJN T1,MTAFKL		;NEXT ENTRY
	RET			;QUIT
;ROUTINES TO DO DUMP MODE IO TO AND FROM MAGTAPE
;CALLED FROM IO AND TAPE
;ACCEPTS IN A/	IOWD

MTDMOX::TDZA B,B		;FLAG FOR EXEC ADDRS
MTDMPO::SETO B,			;FLAG FOR USER ADDRS
	TRVAR <MTDMOT,MTDMOF,MTDMAD>
	MOVEM B,MTDMAD		;SAVE FOR LATER
	MOVEM A,MTDMOT		;SAVE IOWD
	SETOM MTDMOF		;MARK THAT A DUMPO WAS DONE
	HLRZ U,DEV		;SET UP UNIT NUMBER
	MOVE IOS,MTASTS(U)	;GET STATUS BITS
	TQNN <WRTF>		;OPENED FOR WRITE?
	RETBAD (IOX2)		;NO
	CALL CHKERO		;ANY ERRORS?
	 RET			;YES
	JRST MTDMO1		;ENTER COMMON CODE

MTDMIX::TDZA B,B		;FLAG FOR EXEC ADDRS
MTDMPI::SETO B,			;FLAG FOR USER ADDRS
	TRVAR <MTDMOT,MTDMOF,MTDMAD>
	MOVEM B,MTDMAD		;SAVE FLAG
	MOVEM A,MTDMOT		;SAVE IOWD
	SETZM MTDMOF		;MARK THAT A DUMPI WAS DONE
	HLRZ U,DEV		;SET UP UNIT NUMBER
	TQNN <READF>		;OPENED FOR READ?
	RETBAD (IOX1)		;NO
	LOAD A,MTFCN		;GET LAST FUNCTION DONE
	CAIE A,IRFRED		;LAST ONE A READ?
	CAIN A,IRFRDR		;OR READ REVERSE?
	JRST MTDMI0		;YES, DONT NEED TO UPDATE STATUS
	CALL UPDSTS		;UPDATE STATUS
	 RET			;NEED TO BLOCK
MTDMI0:	CALL CHKERI		;ANY ERRORS OR EOF?
	 RET			;YES
MTDMO1:	MOVX IOS,MTOWT		;CLEAR MTOPR WAIT FLAG
	ANDCAB IOS,MTASTS(U)
	TXC IOS,OPN!OPND	;OPENED FOR DUMP MODE
	TXCE IOS,OPN!OPND	; AND OPENED?
	RETBAD (DUMPX2)		;NO, MUST BE MODE 17 FOR DUMPI/O
	TXNE IOS,DMPWT		;IN A DUMP MODE WAIT?
	JRST MTDMI1		;YES, GO SEE IF WAIT IS FINISHED
	;..
	;..
	CALL GETIRB		;GET AN IORB TO USE
	 RET			;NEED TO WAIT FOR ONE
	MOVEI B,IRFRED		;SET FUNCTION
	LOAD C,MTRBF		;GET READ BACKWARDS FLAG
	SKIPE C			;READING BACKWARDS?
	MOVEI B,IRFRDR		;YES, GET CORRECT FUNCTION CODE
	SKIPE MTDMOF		;OPENED FOR WRITE
	MOVEI B,IRFWRT		;YES, SET WRITE FUNCTION
	MOVE C,MTDMOT		;GET THE IOWD
	LOAD D,MTCIRB		;GET LAST IORB IN USE
	STOR D,MTLIRB		;SAVE IT FOR STATUS CHECK LATER
	STOR A,MTCIRB		;SAVE CURRENT IORB ADR
	CALL MTDIRQ		;GO BUILD AN IORB AND CALL PHYSIO
	 RETBAD			;FAILED, GIVE ERROR RETURN
MTDMI1:	CALL MTDWAT		;WAIT FOR APPROPRIATE TIME
	 RET			;ROUTINE WANTS TO BLOCK
	LOAD A,MTLIRB		;GET ADR OF LAST IORB
	TQNN <NWTF>		;IN NO-WAIT MODE?
	LOAD A,MTCIRB		;NO, GET CURRENT IORB
	JUMPE A,MTDMI2		;IF NONE, OK
	CALL SETSTS		;SEE IF ANY ERRORS OCCURED
MTDMI2:	SKIPE MTDMOF		;WRITING?
	JRST [	CALL CHKERO	;YES, CHECK FOR ERRORS
		 RET		;THERE ARE ERRORS
		JRST MTDMI3]
	CALL CHKERI		;CHECK FOR ERRORS OR EOF
	 RET			;TAKE ERROR RETURN
MTDMI3:	MOVE IOS,MTASTS(U)	;GET STATUS
	SKIPE MTDMOF		;WRITING?
	TXNN IOS,MT%EOT		;AND AT EOT?
	RETSKP			;NO, ALL DONE
	RETBAD (IOX5)		;RETURN ERROR
;ROUTINE TO QUEUE AN IORB FOR PHYSIO
;ACCEPTS IN A/	IORB ADR
;	    B/	FUNCTION CODE
;	    C/	IOWD TO BE TRANSFERED (IN CONTEXT OF USER PROGRAM)
;	CALL MTDIRQ
;RETURNS +1:	ALWAYS

;NOTE: THIS ROUTINE ASSUMES THE EXISTENCE OF THE TRVAR IN
;MTDMPO AND MTDMPI

MTDIRQ:	STKVAR <MTDIRA,MTDIRC,MTDIRI,MTDIRM,MTDIRT,MTDIRL,MTDIRF,MTDIRZ>
	MOVEM A,MTDIRI		;SAVE IORB ADR
	MOVEM B,MTDIRF		;SAVE FUNCTION CODE
	HLRO B,C		;GET COUNT
	MOVNM B,MTDIRC		;SAVE POSITIVE COUNT
	HRRZI C,1(C)		;POINT TO FIRST WORD
	SKIPN MTDMAD		;CALLED FROM THE MONITOR?
	JRST MTDIR5		;YES. DON'T APPLY PCS
	XSFM B			;GET FLAGS
	ANDI B,EXPCS		;GET ONLY PREVIOUS CONTEXT SECTION
	HRL C,B			;ADD PCS TO THE ADDRESS
MTDIR5:	MOVEM C,MTDIRA		;SAVE ADDRESS OF FIRST WORD
	MOVE B,MTDIRA		;NOW CALCULATE NUMBER OF PAGES
	ADD B,MTDIRC		;GET END OF USER BUFFER
	SOS B			;GET ADR OF LAST WORD REFERENCED
	TRZ B,777		;GET PAGE ADDRESS
	TRZ C,777		; OF START AND END OF BUFFER
	SUB B,C			;GET # OF PAGES -1
	LSH B,-PGSFT
	CAILE B,MAXPPB-2	;LEGAL LENGTH? (LEAVING ROOM FOR 0 WORD)
	RETBAD (DUMPX3)		;NO, NOT ENOUGH ROOM IN IORB FOR IOWD'S
	MOVE A,MTDIRF		;GET FUNCTION
	CAIE A,IRFRED		;READ?
	CAIN A,IRFRDR		;OR READ BACKWARDS?
	JRST [	CALL WRPGS	;YES. PRE-WRITE THE PAGES THEN
		 RETBAD ()	;ERROR
		JRST .+1]	;PROCEED
	MOVE A,MTDIRF		;GET FUNCTION AGAIN
	CAIN A,IRFWRT		;WRITE?
	JRST [	CALL RDPGS	;YES.  PRE-READ THE PAGES THEN
		 RETBAD ()	;ERROR
		JRST .+1]	;PROCEED
	MOVE A,MTDIRI		;GET IORB ADR
	LOAD D,ISFCN,(A)	;GET THE FUNCTION CODE
	SKIPE D			;IT SHOULD BE ZERO
	BUG(MTAORN)
	ADDI A,MTIRTL		;GET ADDRESS OF START OF TRANSFER LIST
	MOVEM A,MTDIRZ		;SAVE POINTER TO START OF LIST
	MOVE D,MTDIRF		;GET FUNCTION
	CAIE D,IRFRDR		;READING BACKWARDS?
	JRST MTDIR0		;NO
	ADDI A,0(B)		;YES, PUT ENTRIES IN FROM END OF LIST
MTDIR0:	MOVEM A,MTDIRL
	SKIPN MTDMAD		;EXEC XFER?
	JRST [	MOVE B,U	;YES - GET UNIT #
		LSH B,1		; TIMES 2
		ADDI B,TLABBP	; INDEX INTO POINTER LIST
		JRST MTDR1A]
	LOAD B,MTCSB		;GET ADDRESS OF LIST OF LOCKED PAGES
	IMULI B,MAXPPB		;USED AT INTERRUPT LEVEL TO UNLOCK
	OPSTR <ADD B,>,MTBUF	;GET ABSOLUTE ADR OF LIST
MTDR1A:	MOVEM B,MTDIRM		;SAVE FOR LATER
	MOVE A,MTDIRI		;GET ADR OF IORB
	STOR B,IRBPB,(A)	;STORE LIST ADR IN IORB
	LOAD B,MTHBW		;GET BYTES PER WORD
	IMUL B,MTDIRC		;GET TOTAL BYTES IN TRANSFER
	MOVEM B,IRBCNT(A)	;SET UP COUNT IN IORB
	STOR B,IRBOC,(A)	;SAVE COUNT TWICE FOR CHKERR
	;..
	;..
MTDIR1:	SETZM @MTDIRM		;ZERO THIS LIST ELEMENT FIRST
	SKIPG MTDIRC		;ANY MORE WORDS TO BE TRANSFERED?
	JRST MTDIR3		;NO, GO POST REQUEST
	MOVE B,MTDIRA		;GET ADDRESS OF FIRST WORD
	ANDI B,777		;GET OFFSET IN PAGE
	MOVEI C,PGSIZ		;GET NUMBER OF WORDS LEFT ON PAGE
	SUB C,B			;...
	CAMLE C,MTDIRC		;NOW SEE IF THERE ARE ENOUGH LEFT
	MOVE C,MTDIRC		;NO, JUST TRANSFER THE REMAINDER
	MOVEM C,MTDIRT		;SAVE COUNT
	SUBM C,MTDIRC		;UPDATE THE COUNT
	MOVNS MTDIRC		;DO WHAT SUBM DOESNT
	MOVE A,MTDIRA		;GET ACTUAL ADDRESS
	SKIPE MTDMAD		;SKIP IF EXEC PAGE
	TXO A,1B0		;MARK THIS AS A USER PAGE
	CALL MLKMA		;LOCK DOWN THE PAGE
	MOVEM A,@MTDIRM		;SAVE PHYSICAL ADDRESS FOR UNLOCKING
;	MOVE B,MTDIRF		;GET FUNCTION
;	CAIE B,IRFRED		;READING?
;	CAIN B,IRFRDR		;OR READ REVERSE?
;	CALL MRKMPG		;YES, MARK THAT PAGE IS MODIFIED
	MOVE B,@MTDIRM		;GET PHYSICAL PAGE FOR PHYCCW
	LSH B,PGSFT		;MAKE IT INTO AN ADDRESS
	MOVE C,MTDIRA		;GET USER ADDRESS AGAIN
	ANDI C,777		;LOW ORDER BITS ONLY
	IOR B,C			;SET STARTING WORD WITHIN PAGE
	MOVE C,MTDIRT		;GET COUNT OF WORDS ON THIS PAGE
	ADDM C,MTDIRA		;UPDATE THE ADDRESS OF USER BUFFER
	LOAD A,MTHBW		;GET # OF HARDWARE BYTES PER WORD
	IMUL A,MTDIRT		;GET # OF BYTES TO BE TRANSFERED
	OPSTR <HRL A,>,MTDM	;ADD IN MODE OF TRANSFER
	MOVE D,MTDIRF		;GET FUNCTION CODE
	CAIE D,IRFRDR		;READING BACKWARDS?
	JRST MTDIR2		;NO
	ADDI B,-1(C)		;YES, START AT LAST WORD OF BLOCK
	TXO A,1B0		;SET BIT 0 TO INDICATE BACKWARDS
MTDIR2:	HLRZ C,MTCUTB(U)	;GET CDB FOR THIS UNIT
	CALL PHYCCW		;GET TRANSFER COMMAND
	MOVEM A,@MTDIRL		;SAVE COMMAND IN TRANSFER LIST
	MOVE D,MTDIRF		;GET FUNCTION
	CAIN D,IRFRDR		;READING BACKWARDS?
	SOSA MTDIRL		;YES, STEP BACK THROUGH LIST
	AOS MTDIRL		;STEP TO NEXT ITEM IN TRANSFER LIST
	AOS MTDIRZ		;STEP POINTER TO END OF LIST
	AOS MTDIRM		;STEP TO NEXT ITEM IN PAGE LIST
	JRST MTDIR1		;LOOP BACK TILL FINISHED
MTDIR3:	MOVE C,MTDIRZ		;GET POINTER TO TAIL OF TRANSFER LIST
	SETZM 0(C)		;END WITH A ZERO
	MOVE A,MTDIRI		;GET ADR OF IORB
	STOR C,IRBTL,(A)	;SAVE ADR OF TAIL IN IORB
	MOVEI C,MTIRTL(A)	;GET POINTER TO TRANSFER LIST HEAD
	STOR C,IRBHD,(A)	;STORE HEAD POINTER
	CALL SETMOD		;SET UP DENSITY, DATA MODE, PARITY
	MOVE D,MTDIRF		;GET FUNCTION CODE
	STOR D,ISFCN,(A)	;PUT IT IN IORB
	MOVE D,[MTCHKA,,MTDINT]	;NOW SET UP INTERRUPT LEVEL HANDLER ADR
	MOVEM D,IRBIVA(A)	; IN IORB
	CALL QUEIRB		;QUEUE THE IORB
	RETSKP			;GIVE OK RETURN

;SUBROUTINE OF MTDIRQ TO PRE-WRITE ALL PAGES FOR DUMP MODE INPUT.
;	B/	#PAGES -1
;	C/	STARTING PAGE NUMBER
;CLOBBERS ONLY A AND D
;RETURNS:	+1 ERROR
;		+2 ALL SET

WRPGS:	MOVE D,C		;COPY PAGE #
	MOVE A,B		;COPY COUNT
	SKIPE MTDMAD		;MONITOR OR USER?
	SKIPA CX,[XCTU [MOVES 0(D)]] ;USER. GET PROPER INSTRUCTION
	MOVE CX,[MOVES 0(D)]	;EXEC.
WRPG0:	XCT CX			;MODIFY THE PAGE
	 ERJMP [RETBAD (DUMPX4)] ;ACCESS ERROR
	ADDI D,PGSIZ		;NEXT PAGE
	SOJGE A,WRPG0		;DO THEM ALL
	RETSKP			;AND DONE


;SUBROUTINE OF MTDIRQ TO PRE-READ PAGES FOR DUMP MODE OUTPUT
;	B/	#PAGES-1
;	C/	STARTING PAGE NUMBER
;CLOBBERS A AND D
;RETURNS:	+1 ERROR, CODE IN A
;		+2 OK

RDPGS:	MOVE D,C		;COPY PAGE NUMBER
	MOVE A,B		;COPY PAGE COUNT
	SKIPE MTDMAD		;CHECK MONITOR OR USER
	SKIPA CX,[XCTU [SKIP 0(D)]] ;USER
	MOVE CX,[SKIP 0(D)]	;MONITOR, GET PROPER INSTRUCTION
RDPG0:	XCT CX			;ACCESS THE PAGE
	 ERJMP [RETBAD (DUMPX4)] ;REPORT ACCESS ERROR
	ADDI D,PGSIZ		;NEXT PAGE
	SOJGE A,RDPG0		;LOOP FOR THEM ALL
	RETSKP			;AND DONE
;ROUTINE TO WAIT FOR APPROPRIATE EVENT AFTER QUEUEING IORB
;	CALL MTDWAT
;RETURNS +1:	ROUTINE WANTS TO BLOCK
;	 +2:	WAITING IS NOT NECESSARY

MTDWAT:	LOAD A,MTNIR		;GET NUMBER OF REQUESTS IN QUEUE
	JUMPE A,MTDWTR		;IF 0, RETURN IMMEDIATELY
	TQNE <NWTF>		;"NO WAIT" MODE?
	CAILE A,1		;YES, WAIT FOR COUNT TO GO TO 1
	JRST MTDWT0		;MUST WAIT
MTDWTR:	MOVX IOS,DMPWT		;MARK THAT WAITING IS OVER
	ANDCAB IOS,MTASTS(U)
	RETSKP			;GIVE SKIP RETURN

MTDWT0:	MOVX IOS,DMPWT		;MARK THAT WE ARE WAITING
	IORB IOS,MTASTS(U)
	MOVEI A,MTAWAT		;GET ADR OF ROUTINE TO DO TEST
	TQNE <NWTF>		;IF "NO WAIT" MODE,
	MOVEI A,MTDWT1		; THEN WAIT FOR COUNT TO GO TO 1
	HRL A,U			;GET UNIT NUMBER
	TQO <BLKF>		;SET BLOCK FLAG
	RET			;AND GIVE NON-SKIP RETURN


;ROUTINE TO WAIT FOR COUNT OF REQUESTS TO GO TO 1

	RESCD

MTDWT1::LOAD B,MTANIR,(A)	;GET COUNT OF OUTSTANDING REQUESTS
	CAILE B,1		;DOWN TO 1 YET?
	JRST 0(4)		;NO
	JRST 1(4)		;YES, WAIT IS OVER

	SWAPCD
;ROUTINE TO HANDLE AN INTERRUPT FROM END OF A DUMP MODE REQUEST

	RESCD

MTDINT:	LOAD B,IRBFA,(A)	;MAKE SURE THE IORB IS ACTIVE
	JUMPE B,NOACTV		;IF NOT, THEN BUGHLT
	MOVE B,IRBCNT(A)	;GET FINAL COUNT
	OPSTR <CAME B,>,IRBOC,(A) ;MUST BE THE SAME
	JRST MTDIN3		;NOT. RECORD LENGTH ERROR
	MOVE B,IRBSTS(A)	;GET STATUS OF REQUEST
	TXNE B,IS.ERR!IS.TPM	;ERROR OR TAPE MARK?
	JRST MTDINE		;YES, GO ABORT OTHER IORBS
MTDIN0:	CALLRET MTDIND		;NO, GO UNLOCK THIS IORB

MTDINE:	TXNN B,IS.WGU!IS.TPM!IS.DTE!IS.DVE!IS.NRT
	JRST [	LOAD C,ISFCN,(A) ;GET FUNCTION
		CAIN C,IRFWRT	;WRITING?
		TXNN B,IS.EOT	;YES, THEN CHECK FOR EOT ALSO
		JRST MTDIN0	;NO, THIS IS NOT AN ERROR
		JRST .+1]	;EOT ABORTS FURTHER WRITES
MTDIN3:	SAVEQ
	LOAD U,IRBUN,(A)	;SET UP UNIT NUMBER FOR MTAKIL
	CALL MTDIND		;CLEAN UP THE CURRENT IORB FIRST
	CALLRET MTAKIL		;THEN ABORT ALL OTHER IORBS

MTDIND:	SAVEQ			;SAVE PERMANENT ACS USED
	MOVX B,IRBFR		;MARK THAT BUFFER IS READY
	IORM B,MTIRSD(A)
	MOVX B,IRBFA		;AND CLEAR ACTIVE BIT
	ANDCAM B,MTIRSD(A)
	LOAD U,IRBUN,(A)	;GET UNIT NUMBER
	LOAD Q3,IRBPB,(A)	;GET POINTER TO LIST OF PAGES TO UNLOCK
	HRLI Q3,-MAXPPB		;SET UP AOBJN POINTER
MTDIN1:	MOVE A,0(Q3)		;GET PAGE TO UNLOCK
	JUMPE A,MTDIN2		;IF 0, REACHED END OF LIST
	CALL MULKCR		;UNLOCK THE PAGE
	AOBJN Q3,MTDIN1		;LOOP BACK FOR ALL PAGES
MTDIN2:	DECR MTNIR		;DECREMENT COUNT OF REQUESTS IN QUEUE
	RET			;AND RETURN

	SWAPCD

	TNXEND
	END