Google
 

Trailing-Edge - PDP-10 Archives - BB-JR93L-BB_1990 - 10,7/galaxy/quasar/qsrmda.mac
There are 36 other files named qsrmda.mac in the archive. Click here to see a list.
	TITLE	QSRMDA  --  Mountable Device Manager

;
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1975,1976,1977,1978,1979,
;1980,1981,1982,1983,1984,1985,1986,1987.  ALL RIGHTS RESERVED.
;
;     THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;     AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE
;     AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS
;     SOFTWARE  OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR
;     OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON.  NO  TITLE  TO
;     AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.
;
;     THE INFORMATION  IN  THIS  SOFTWARE  IS  SUBJECT  TO  CHANGE
;     WITHOUT  NOTICE  AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
;     BY DIGITAL EQUIPMENT CORPORATION.
;
;     DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
;     OF  ITS  SOFTWARE  ON  EQUIPMENT  WHICH  IS  NOT SUPPLIED BY
;     DIGITAL.

	SEARCH	QSRMAC,GLXMAC,ORNMAC	;GET QUASAR SYMBOLS
	PROLOGUE(QSRMDA)		;GENERATE NECESSARY SYMBOLS

	%%.QSR==:%%.QSR
	QSRVRS==:QSRVRS

	.DIRECT	FLBLST			;SQUASH LITERAL EXPANSION
;               TABLE OF CONTENTS FOR QSRMDA
;
;
;                        SECTION                                   PAGE
;    1. Table of Contents.........................................   2
;    2. MDA structure inter-relationships.........................   3
;    3. Local Storage.............................................   4
;    4. D$CLSV - Clear All STR Valid Status.......................   5
;    5. D$CSTR - Check a structure for on-line....................   6
;    6. D$ESTR - Extract a STR from an FD.........................   7
;    7. D$ASTD - Add a structure dependency.......................   9
;    8. FNDSTR - Find a STR entry.................................  10
;    9. D$INIT - ROUTINE TO INITIALIZE THE MDA DATA BASE..........  15
;   10. HOLD/RELEASE/MOUNT interface for QSRQUE...................  16
;   11. D$MOUN - Process a Tape/Disk Mount Request................  18
;   12. D$DEAS - DEASSIGN/RELEASE A VOLUME SET....................  19
;   13. D$CMDR - ROUTINE TO CREATE AN ENTRY IN THE MDR QUEUE......  20
;   14. D$LOGO - DELETE A USER MDR'S ON LOGOUT....................  23
;   15. D$XCH - Exchange disk units...............................  24
;   16. D$DMDR - ROUTINE TO UNWIND AND DELETE AN MDR..............  25
;   17. D$IDEN - ROUTINE TO PROCESS THE IDENTIFY COMMAND..........  26
;   18. REASSIGN - Try to give a unit to a user...................  29
;   19. REAS.S - Routine to Perform Volume Switch Processing......  31
;   20. D$ASGN - ROUTINE TO ASSIGN FOREIGN DEVICES UNDER MDA......  33
;   21. D$ENAB/D$DISA - DRIVE AVR STATUS..........................  35
;   22. D$RECO - PROCESS THE OPR RECOGNIZE COMMAND................  37
;   23. D$AVR - TAPE/DISK ONLINE PROCESSOR........................  38
;   24. D$DEVS - PROCESS TAPE/DISK STATUS MESSAGES................  39
;   25. TAPDEV - TAPE STATUS MESSAGE PROCESSOR....................  40
;   26. DTADEV - DECTAPE STATUS MESSAGE PROCESSOR.................  43
;   27. DSKDEV - DISK STRUCTURE DEVICE STATUS MESSAGE PROCESSOR...  45
;   28. SETOWN - ROUTINE TO SET UP OWNERSHIP FOR A VSL............  48
;   29. MNTVSL - ROUTINE TO ATTEMPT TO MOUNT A USERS REQUESTS.....  49
;   30. MNTVSR - ROUTINE TO MOUNT A VOLUME AT VOLUME SWITCH TIME..  52
;   31. VSLCHK - ROUTINE TO TRY TO MOUNT A VOLUME FROM THE VSL....  53
;   32. MATUNI - ROUTINE TO GIVE A VOLUME TO ANY VALID REQUESTOR..  55
;   33. CVLVSL - Compare Volume with Volume Set...................  56
;   34. CHKOWN - ROUTINE TO CHECK IF A USER OWNS A VOLUME.........  57
;   35. D$UNLO - ROUTINE TO UNLOAD A TAPE DRIVE...................  58
;   36. D$DISM - STRUCTURE DISMOUNT PROCESSOR.....................  59
;   37. VLUNLO - Unload a unit and break UCB-VOL links............  60
;   38. D$DELE - ROUTINE TO DELETE REQUESTS FROM THE MOUNT QUEUE..  61
;   39. D$SMDA - Set tape drive un/available/ initialize..........  65
;   40. D$VSR - VOLUME SWITCH REQUEST FROM PULSAR.................  67
;   41. D$XVSL - Extend a VSL.....................................  71
;   42. D$DVS - DISMOUNT/DEALLOCATE VOLUME SET PROCESSOR..........  74
;   43. D$ACK - ROUTINE TO PROCESS MDA ACK MESSAGES...............  76
;   44. Structure mount ACK processing............................  77
;   45. D$RMS - Routine to process the structure removed message..  78
;   46. DSMACK - ROUTINE TO PROCESS DISMOUNT ACKS FROM TAPE LABELER  79
;   47. DSMOPR - Tell OPR about a structure just dismounted.......  82
;   48. CATACK - ROUTINE TO PROCESS CATALOG ACKS FROM TAPE LABELER  83
;   49. ASLACK - ROUTINE TO PROCESS ACKS FOR ADDING STR TO A SEARCH LIST  84
;   50. RMSACK - ROUTINE TO PROCESS 'REMOVE STRUCTURE' ACKS.......  85
;   51. D$ALIA - ROUTINE TO MOUNT A STRUCTURE WITH AN ALIAS.......  86
;   52. CHKSTR - ROUTINE TO CHECK FOR STRUCTURE AVAILABILITY......  88
;   53. D$LOCK - PROCESS LOCK AND UNLOCK MESSAGES.................  89
;   54. TIMER ROUTINES FOR LOCK AND UNLOCK........................  92
;   55. LOCNOT - Notify users (countdown) of pending locks........  94
;   56. CLEAR LOCKS ON STRUCTURE DISMOUNT.........................  95
;   57. LNEVEN - Set up a Lock notification event.................  96
;   58. D$LCKM - ROUTINE TO PROCESS THE RESET AFTER LOCK MESSAGE..  97
;   59. VSREOV - ROUTINE TO SEND END OF VOLUME MSG TO TAPE LABELER  98
;   60. REIMSG - ROUTINE TO SEND REINITIALIZATION MESSAGE TO PULSAR  99
;   61. DELETE - ROUTINE TO DELETE ALL NEW VOL SETS FOR A USER....  99
;   62. REMOVE - ROUTINE TO DELETE A SPECIFIC VSL AND RETRY THE MOUNT 100
;   63. DELVSL - ROUTINE TO DELETE A VSL.......................... 101
;   64. ALCVSL - ROUTINE TO RETURN A VSL TO THE ALLOCATION POOL... 104
;   65. DELMDR - ROUTINE TO DELETE AN MDR......................... 105
;   66. DELVOL - ROUTINE TO DELETE VOL BLOCKS FROM THE VOL QUEUE.. 106
;   67. GETLBT - ROUTINE TO RECODE THE VOLUME LABEL TYPE.......... 107
;   68. FNDDSK - ROUTINE TO FIND A DSK VOL BLOCK USING VOLUME ID.. 108
;   69. CREVOL - ROUTINE TO CREATE A VOL BLOCK IN VOL QUEUE....... 109
;   70. USRACK - ROUTINE TO GENERATE AN ACK TO THE USER FOR MOUNT/ALLOC 110
;   71. ACKUSR - ROUTINE TO CREATE AN ACK AFTER THE VOL SET IS MOUNTED 111
;   72. TELOPR - ROUTINE TO NOTIFY THE OPERATOR TO MOUNT DEVICES.. 114
;   73. MNTOPR - ROUTINE TO NOTIFY THE OPR OF PENDING MOUNT REQUESTS 119
;   74. SETSEL - ROUTINE TO FIND THOSE UCB'S WHICH ARE FREE....... 121
;   75. USRNOT - SEND A MESSAGE TO THE USER....................... 122
;   76. NSTUSR - Notify users of pending structure locks.......... 124
;   77. LBLNOT - ROUTINE TO NOTIFY LABEL PROCESS OF DEVICE REASSIGNMENT 125
;   78. LBLHDR - Set up for a message to MDA...................... 127
;   79. SNDREC - ROUTINE TO SEND A RECOGNIZE MSG TO THE TAPE LABELER 128
;   80. UNLOAD - TELL PULSAR TO UNLOAD THE TAPE DRIVE............. 128
;   81. SNDVDM - Send volume dismount message to tape labeler..... 129
;   82. FNDUCB - ROUTINE TO FIND A UCB IN THE UCB CHAIN........... 130
;   83. GETRSN - ROUTINE TO RETURN THE FIRST AVAILABLE RESOURCE NUMBER 131
;   84. GIVRSN - Return a slot of the A matrix.................... 132
;   85. FNTAPE - ROUTINE TO FIND A MAGTAPE VOLUME IN THE VOL DATA BASE 133
;   86. FNDOWN - FIND ANY OWNER OF A VOLUME....................... 134
;   87. FNDMDR - ROUTINE TO FIND AN MDR GIVEN ITS JOB NUMBER...... 135
;   88. FNDVSL - ROUTINE TO FIND A PARTICULAR VSL IN AN MDR....... 136
;   89. FNDVSN - ROUTINE TO FIND A VOLUME SET VIA THE VOL SET NAME 137
;   90. FNDLNM - ROUTINE TO FIND A USERS VSL GIVEN A LOGICAL NAME. 138
;   91. VSLFND - ROUTINE TO FIND A VSL IN A USERS REQUEST......... 139
;   92. GENVOL - ROUTINE TO CREATE A 'SCRATCH' VOLUME BLOCK....... 140
;   93. ADDVOL -  ROUTINE TO ADD A VOL BLOCK DURING MOUNT PROCESSING 141
;   94. CKUVOL - CHECK FOR MULTIPLE USER REQUESTS FOR THE SAME TAPE VOL 142
;   95. Miscellaneous routines.................................... 143
;   96. D$MDAE - ROUTINE TO NOTIFY THE OPERATOR OF ANY ERRORS..... 146
;   97. DSKRSN - ROUTINE TO RETURN RESOURCE NUMBERS FOR DISK DRIVES 147
;   98. TAPRSN - ROUTINE TO RETURN RESOURCE NUMBERS FOR TAPE DRIVES 148
;   99. D$TNRS - GET A MAGTAPE RESOURCE NUMBER.................... 149
;  100. STRRSN - ROUTINE TO RETURN RESOURCE NUMBERS FOR STRUCTURES 150
;  101. D$T/SVRS - Generate resource #s for Tape/Structure volumes 152
;  102. VALMSG - ROUTINE TO VALIDATE THE MOUNT/ALLOCATE MESSAGE... 153
;  103. CHKBAT - ROUTINE TO CHECK FOR BATCH REQUESTS DOING MOUNTS. 154
;  104. BLDVSL - ROUTINE TO BREAK DOWN MOUNT MSG ENTRIES.......... 155
;  105. VSL DEFAULTING ROUTINES................................... 158
;  106. MOUNT REQUEST BLOCK PROCESSOR ROUTINES.................... 159
;  107. Count the number of requests needing a structure.......... 164
;  108. BLDSTR - ROUTINE TO PIECE TOGETHER VOL BLKS AND MAKE A STRUCTURE 165
;  109. SNDBLD - ROUTINE TO LINK THE STR VOL BLKS AND SEND STR BUILD MSG 166
;  110. ASLMSG - ROUTINE TO BUILD AN 'ADD STRUCTURE' MSG.......... 168
;  111. SCNVOL - ROUTINE TO FIND COMMON VOLUMES REQUESTS AND LINK THEM 170
;  112. UPDSVL - UPDATE THE STARTING VOLUME FOR A VOLUME SET...... 172
;  113. D$INID - Initialization done for tape handler............. 173
;  114. D$ALOC - ROUTINE TO PERFORM DEVICE ALLOCATION............. 174
;  115. D$BMTX - ROUTINE TO FIND A USERS ENTRY IN THE 'B' MATRIX.. 178
;  116. Deadlock Avoidance
;       116.1   DEADLK - Interface routine........................ 179
;       116.2   D$DEAD - Check for a deadlock..................... 180
;       116.3   IFPLAY - See if process is playable............... 182
;       116.4   DOPLAY - Play a process........................... 185
;       116.5   IFOTHR - Check for other owners................... 187
;       116.6   UNMAP - Remove lower level resources.............. 188
;       116.7   GTHEAD - Get column headers....................... 189
;       116.8   GTCOLM - Get column entries....................... 190
;       116.9   GTNEXT - Get next process to play................. 191
;       116.10  CLTRY - Clear all tried bits...................... 192
;  117. Dump MDA Database
;       117.1   D$DUMP - Dump all matrices........................ 193
;       117.2   DMPSM - Dump an SM Block.......................... 196
;  118. D$DLCK - ROUTINE TO SET UP THE DEADLOCK AVOIDANCE CHECK... 197
;  119. RETA%C - ROUTINE TO RETURN RESOURCES TO THE 'A' & 'C' MATRICIES 200
;  120. RETBMA - ROUTINE TO RETURN RESOURCES TO THE 'B' MATRIX.... 201
;  121. ADDBMA - ROUTINE  TO UPDATE A RESOURCE NUMBER FOR A USER.. 202
;  122. SUBCMA - ROUTINE TO RETURN RESOURCES TO THE 'C' MATRIX.... 204
;  123. SUBBMA - ROUTINE TO RETURN 'B' MATRIX RESOURCES........... 204
;  124. ADDAMA - ROUTINE TO REMOVE 'A' MATRIX RESOURCES........... 205
;  125. ADJAMA - ROUTINE TO ADJUST THE 'A' MATRIX................. 206
;  126. VSLRSN - ROUTINE TO FIND A VSL'S RESOURCE NUMBERS......... 207
;  127. SETSTK - Setup a queue for VSL, RSN pairs................. 211
;  128. GETADD - ROUTINE TO CALC THE 'A', 'B', 'C' MATRIX ADD VALUE 212
;  129. MDA pseudo process routines
;       129.1   D$PPRL - Delete an MDR............................ 213
;       129.2   D$PPRE - Reset a real process..................... 214
;       129.3   D$PMDR - Find a process........................... 215
;  130. D$MODR - ROUTINE TO MODIFY A USERS ALLOCATION ON THE 'FLY' 216
;  131. SHUFFL - Routine to shuffle resources around for a requestor 217
;  132. MODALC - Routine to modify a users resource number for a request 218
;  133. D$ALCT - ROUTINE TO ALLOCATE TAPE VOLUMES FOR 'IDENTIFY' COMMAND 219
	SUBTTL	MDA structure inter-relationships

;	!-----!     		!-----!
;	!     !     		!     !
; MDR	! MDR !<--------------->! MDR !
;CHAIN	!     !     		!     !
;	!-----!     		!-----!
;	/!\  /!\		  /!\
;	 !    !			   !
;	 !    !			   !
;	 !    !---------------!    !-------------------!
;	 !		      !			       !
;	\!/		     \!/		      \!/
;	!-----!     	     !-----!     	     !-----!
;	!     !     	     !     !     	     !     !
; VSL	! VSL !<------------>! VSL !<--------------->! VSL !
;CHAIN	!     !     	     !     !     	     !     !
;	!-----!     	     !-----!     	     !-----!
;	/!\  /!\            /!\  /!\                /!\  /!\
;	 !    !              !    !		     !    !
;	 !    !              !    !		     !    !--------------!
;	 !    !		     !    !		     !			 !    
;	 !    !		     !    !-------------!    !--------!		 !  
;	 !    !----------!   !			!	      !		 !
;	 !		 !   !-----------!      !	      !		 !
;	 !		 !		 !      !--------!    !		 !
;	\!/		\!/		\!/		\!/  \!/	\!/
;	!-----!		!-----!		!-----!		!-----!		!-----!
;	!     !		!     !		!     !		!     !		!     !
; VOL	! VOL !		! VOL !		! VOL !		! VOL !		! VOL !
;CHAIN	!  1  !<------->!  2  !<------->!  3  !<------->!  4  !<------->!  5  !
;	!     !		!     !		!     !		!     !		!     !
;	!-----!		!-----!		!-----!		!-----!		!-----!
;			/!\		/!\		/!\		  /!\
;	     !-----------!		 !		 !		   !
;	     !     	     !-----------!		 !		   !
;	     !		     !		     !-----------!		   !
;	     !		     !		     !		     !-------------!
;	     !		     !		     !		     !
;	    \!/		    \!/		    \!/		    \!/
;	!-----!		!-----!		!-----!		!-----!		!-----!
;	!     !		!     !		!     !		!     !		!     !
; UCB	! MTA !		! MTA !		! MTB !		! MTB !		! MTB !
;CHAIN	!  0  !<------->!  1  !<------->!  0  !<------->!  1  !<------->!  2  !
;	!     !		!     !		!     !		!     !		!     !
;	!-----!		!-----!		!-----!		!-----!		!-----!
SUBTTL	Local Storage


IFN FTUUOS,<
DSKCBL:	BLOCK	5			;DSKCHR BLOCK
>  ;END IFN FTUUOS

IFN FTJSYS,<
ESTR.A:	BLOCK	^D16			;-20 STRUCTURE NAME
>  ;END IFN FTJSYS


	;Local variables for the TOPS-10 deadlock avoidance code

TOPS10	<
BHEAD:	BLOCK	1			;ADDRESS OF 'B' MATRIX SM BLOCKS
CHEAD:	BLOCK	1			;ADDRESS OF 'C' MATRIX SM BLOCKS
BRESN:	BLOCK	1			;ADDRESS OF 'B' MATRIX RESOURCE COUNTS
CRESN:	BLOCK	1			;ADDRESS OF 'C' MATRIX RESOURCE COUNTS
BFLAG:	BLOCK	1			;ADDRESS OF PROCESS FLAGS
	SM.PLY==1B0			;PROCESS HAS BEEN PLAYED
	SM.DLK==1B1			;PROCESS HAS BEEN TRIED, BUT IT
					; IS DEADLOCKED
	SM.SEQ==RHMASK			;SEQUENCE NUMBER (IF PLAYED)
ATEMP:	BLOCK	1			;ADDRESS OF 'A' MATRIX SCRATCH ARRAY
ASIZE:	BLOCK	1			;NUMBER OF ENTRIES IN 'A' MATRIX
> ;END TOPS10 CONDITIONAL
SUBTTL	D$CLSV - Clear All STR Valid Status

;D$CLSV is called to clear all the STATUS-VALID indicators for all file-
;	structures in the STR queue.  This will cause the status to be
;	re-verified upon calling D$CSTR.


;Call:	No arguments
;
;T Ret:	Always

D$CLSV::LOAD	S1,HDRSTR##+.QHLNK,QH.PTF
					;POINT TO FIRST ITEM IN STR QUEUE
	MOVX	S2,STSSSV		;LOAD THE STATUS-VALID BIT

CLSV.1:	JUMPE	S1,.RETT		;RETURN  ON END OF QUEUE
	ANDCAM	S2,STRSTS(S1)		;CLEAR STATUS-VALID FLAG
	LOAD	S1,.QELNK(S1),QE.PTN	;POINT TO NEXT ITEM
	JRST	CLSV.1			;AND LOOP
SUBTTL	D$CSTR - Check a structure for on-line

;D$CSTR is called with a STR queue entry to check whether or not it is
;	on line.

;Call:	S1/  address of an STR entry
;
;T Ret: Structure is on-line
;	S1/Addr of STR queue entry
;
;F Ret: Structure is off-line
;	S1/Addr of STR queue entry

D$CSTR::MOVE	S2,STRSTS(S1)		;GET STRUCTURE STATUS WORD
	TXNN	S2,STSSSV		;IS STATUS VALID?
	JRST	CSTR.2			;NO, GO ASK MONITOR
CSTR.1:	TXNE	S2,STSONL		;YES, IS IT ON-LINE?
	$RETT				;YES, RETURN TRUE
	$RETF				;NO, RETURN FALSE

TOPS10	<
CSTR.2:	MOVE	S2,STRNAM(S1)		;GET THE STRUCTURE NAME
	MOVEM	S2,DSKCBL+.DCNAM	;STORE IT IN THE DSKCHR BLOCK
	MOVE	S2,[5,,DSKCBL]		;POINT TO DSKCHR ARG
	DSKCHR	S2,			;ASK THE MONITOR FOR STATUS
	  MOVX	S2,DC.OFL		;FAILED, LOAD OFF-LINE BIT
	TXNE	S2,DC.OFL!DC.NNA!DC.SAF	;OFFLINE IFF OFL OR NNA OR SAF
	TDZA	S2,S2			;OFF LINE!!!
	MOVX	S2,STSONL		;ON LINE!!!
	TXO	S2,STSSSV		;SET VALID STATUS
	MOVEM	S2,STRSTS(S1)		;STORE THE STATUS
	JRST	CSTR.1			;AND RETURN CORRECT STATE
>  ;END TOPS10 CONDITIONAL

TOPS20	<
CSTR.2:	PUSHJ	P,.SAVE3		;SAVE P1 THRU P3
	MOVE	P1,S1			;SAVE STR ADDRESS IN P1
	MOVE	S1,[2,,.MSGSS]		;LEN,,FUNCTION
	MOVEI	S2,P2			;ADDRESS OF ARG BLOCK
	HRROI	P2,STRNAM(P1)		;FIRST ARG IS POINT TO STR NAME
	MSTR				;GET STRUCTURE STATUS
	ERJMP	CSTR.3			;LOSE, MUST BE OFF-LINE
	MOVX	S2,STSONL		;LOAD THE ON-LINE BIT
	TXNE	P3,MS%DIS		;IS STR BEING DISMOUNTED?
CSTR.3:	SETZ	S2,			;YES, CLEAR ON-LINE FLAG
	TXO	S2,STSSSV		;SET STATUS VALID
	MOVEM	S2,STRSTS(P1)		;SAVE THE STRUCTURE STATUS
	MOVE	S1,P1			;GET STRUCTURE ADDRESS IN S1
	JRST	CSTR.1			;AND RETURN
>  ;END TOPS20 CONDITIONAL
SUBTTL	D$ESTR - Extract a STR from an FD

;D$ESTR is called with an FD to extract the structure and return the
;	address of an STR queue entry for it.

;Call:	S1/  address of an FD
;
;T Ret:	S1/  address of a STR queue entry
;
;F Ret: If an invalid structure field was in the FD (i.e. non-disk device)

IFN FTUUOS,<
D$ESTR::PUSHJ	P,.SAVE1		;SAVE P1
	SKIPN	S1,.FDSTR(S1)		;GET THE STRUCTURE NAME
	$RETF				;IF NULL,,RETURN FALSE
	MOVE	P1,S1			;AND SAVE IT IN P1
	PUSHJ	P,FNDSTR		;FIND THE STRUCTURE
	JUMPT	.RETT			;RETURN IF FOUND
	MOVEM	P1,DSKCBL+.DCNAM	;STORE STR NAME FOR DSKCHR
	MOVE	S2,[5,,DSKCBL]		;GET DSKCHR ARGS
	DSKCHR	S2,			;SEE IF STR IS ON-LINE
	  JRST	[MOVE S2,P1		;OFF-LINE, PUT STR NAME IN S2
		 DEVCHR S2,		;MAKE SURE ITS NOT A NON-DISK DEVICE
		 JUMPN  S2,.RETF	;IF DEVICE EXISTS, RETURN FALSE
		 JRST ESTR.1]		;ELSE CONTINUE ON
	LOAD	S2,S2,DC.TYP		;GET ARGUMENT TYPE
	CAXE	S2,.DCTFS		;IF IT WAS A FILE STRUCTURE
	CAMN	P1,DSKCBL+.DCSNM	;  OR SAME NAME AS WE ENTERED WITH ???
	JRST	ESTR.1			;THEN GO ADD IT
	MOVE	P1,DSKCBL+.DCSNM	;ELSE, USE STR NAME RET BY DSKCHR
	MOVE	S1,P1			;GET THE NAME IN S1
	PUSHJ	P,FNDSTR		;TRY ONCE MORE TO LOCATE IT
	JUMPT	.RETT			;WIN,,RETURN

ESTR.1:	$SAVE	H			;SAVE H
	$SAVE	AP			;SAVE AP
	MOVEI	H,HDRSTR##		;POINT TO THE CORRECT HEADER
	PUSHJ	P,M$GFRE##		;GET A FREE CELL
	MOVEM	P1,STRNAM(AP) 		;SAVE THE STRUCTURE NAME
	PUSHJ	P,M$ELNK##		;LINK IT IN AT THE END
	MOVE	S1,AP			;PUT ADDRESS IN S1
	$RETT				;AND RETURN
>  ;END IFN FTUUOS

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

IFN FTJSYS,<
D$ESTR:	PUSHJ	P,.SAVET		;SAVE T REGISTERS
	SETZM	ESTR.A			;CLEAR DEVICE NAME HOLD AREA
	HRROI	S2,.FDFIL(S1)		;POINT TO THE FILESPEC
	MOVX	S1,GJ%OFG+GJ%SHT	;PARSE-ONLY AND SHORT GTJFN
	GTJFN				;GET A JFN FOR THE FILESPEC
	ERJMP	.RETF			;ILLEGAL FILESPECIFICATION
	MOVE	S2,S1			;PUT THE FILE HANDLE INTO S2
	HRROI	S1,ESTR.A		;PLACE TO PUT THE STRUCTURE NAME
	MOVX	T1,JS%DEV		;ONLY WANT THE DEVICE.
	SETZ	T2,			;CLEAR T2
	JFNS				;GET THE STRUCTURE NAME
	MOVE	S1,S2			;GET THE JFN IN S1
	RLJFN				;RELEASE IT
	ERJMP	.+1			;IGNORE ERRORS
	MOVE	S1,[ASCIZ/TTY/]		;GET AN ASCIZ 'TTY'
	CAMN	S1,ESTR.A		;SPECIAL CASE TTY:
	$RETF				;IF TTY,,THEN RETURN FALSE
	MOVE	S1,[POINT 7,ESTR.A]	;POINT TO THE DEVICE NAME.
	PUSHJ	P,FNDSTR		;FIND THE STRUCTURE
	JUMPT	.RETT			;RETURN NOW IF FOUND
	HRROI	S1,ESTR.A		;GET THE PTR TO THE DEVICE STRING
	STDEV				;CONVERT TO A DEVICE DESIGNATOR
	ERJMP	ESTR.1			;IF NO SUCH DEVICE, WIN
	LOAD	S1,S2,DV%TYP		;GET THE DEVICE TYPE
	CAIE	S1,.DVDSK		;IS IT A DISK?
	$RETF				;NO,,RETURN FALSE

ESTR.1:	$SAVE	H			;SAVE AC H
	$SAVE	AP			; AND AP
	MOVEI	H,HDRSTR##		;GET A STRUCTURE QUEUE
	PUSHJ	P,M$GFRE##		;GET A FREE CELL
	MOVE	S1,[POINT 7,ESTR.A]	;GET THE SOURCE STR BYTE PTR.
	MOVE	S2,[POINT 7,STRNAM(AP)]	;GET THE DESTINATION STR BYTE PTR.
ESTR.2:	ILDB	T1,S1			;GET A STRUCTURE BYTE.
	IDPB	T1,S2			;SAVE IT IN STR LIST.
	JUMPN	T1,ESTR.2		;NOT NULL,,KEEP ON GOING.
	PUSHJ	P,M$ELNK##		;LINK IT IN AT THE END
	MOVE	S1,AP			;PUT ADDRESS IN S1
	$RETT				;RETURN
>  ;END IFN FTJSYS
SUBTTL	D$ASTD - Add a structure dependency

;This routine is called to place a structure into the dependency list
;	for a job.

;Call:	S1/  adr of STR entry
;	S2/  adr of QE
;
;T Ret:	always

D$ASTD::PUSHJ	P,.SAVET		;SAVE THE T REGISTERS
	DMOVE	T1,S1			;PUT ARGUMENTS INTO T1 AND T2
	LOAD	S1,.QEDIN(T2),QE.DLN	;GET DEPENDENCY LIST NUMBER
	PUSHJ	P,L%FIRST		;AND POSITION TO THE START OF THE LIST
	JUMPF	ASTD.3			;EMPTY LIST, ADD IT ON
	JRST	ASTD.2			;JUMP INTO MIDDLE OF LOOP

ASTD.1:	PUSHJ	P,L%NEXT		;POSITION TO THE NEXT ONE
	JUMPF	ASTD.3			;NO NEXT ONE, LINK IT IN
ASTD.2:	LOAD	T3,.DIBDS(S2),DI.TYP	;GET DEPENDENCY TYPE
	CAXE	T3,.DTSTR		;STRUCTURE?
	JRST	ASTD.1			;NO, GET THE NEXT DEPENDENCY
	CAME	T1,.DIBDT(S2)		;YES, SAME STRUCTURE?
	JRST	ASTD.1			;NO, ON TO THE NEXT DEPENDENCY
	JRST	.RETT			;YES, ALREADY RECORDED

ASTD.3:	LOAD	S1,.QEDIN(T2),QE.DLN	;GET LIST NUMBER
	MOVX	S2,DIBSIZ		;GET LIST ENTRY SIZE
	PUSHJ	P,L%CENT		;CREATE AN ENTRY
	MOVX	S1,.DTSTR		;GET CODE FOR STRUCTURE
	STORE	S1,.DIBDS(S2),DI.TYP	;STORE IT
	STORE	T1,.DIBDT(S2)		;STORE THE STR ADDRESS
	$RETT				;AND RETURN
SUBTTL	FNDSTR - Find a STR entry

;FNDSTR is called with a structure name to find the STR queue entry for it.
;
;Call:	S1/  Structure Name (6bit on -10, byte-pointer on -20)
;
;T Ret:	S1/  Address of STR queue entry
;
;F Ret: If not in STR queue

FNDSTR:	LOAD	S2,HDRSTR##+.QHLNK,QH.PTF
	EXCH	S1,S2			;EXCHANGE S1 AND S2

IFN FTUUOS,<
FNDS.1:	JUMPE	S1,.RETF		;FAIL WHEN DONE.
	CAMN	S2,STRNAM(S1)		;MATCH?
	$RETT				;YES, JUST RETURN
	LOAD	S1,.QELNK(S1),QE.PTN	;NO, POINT TO NEXT
	JRST	FNDS.1			;AND LOOP
>  ;END IFN FTUUOS

IFN FTJSYS,<
	PUSHJ	P,.SAVE4		;SAVE P1 THRU P4
	MOVE	P4,S2			;SAVE THE SOURCE STR POINTER.
FNDS.1:	JUMPE	S1,.RETF		;FAIL WHEN DONE.
	MOVE	P1,[POINT 7,STRNAM(S1)]	;POINT TO THE STRUCTURE NAME IN STR

FNDS.2:	ILDB	P2,P1			;GET A STR CHARACTER
	ILDB	P3,S2			;GET SOURCE CHARACTER
	CAME	P2,P3			;ARE THEY THE SAME?
	JRST	FNDS.3			;NO, NEXT STR
	JUMPN	P2,FNDS.2		;YES, LOOP IF NOT NULL YET
	$RETT				;WIN IF NULLS MATCH

FNDS.3:	LOAD	S1,.QELNK(S1),QE.PTN	;GET POINTER TO NEXT
	MOVE	S2,P4			;RESET THE SOURCE STR POINTER.
	JRST	FNDS.1			;AND LOOP
>  ;END IFN FTJSYS
	EXTERN	BELLS			;MAKE THIS REFERENCE'ABLE
	EXTERN	G$MSG			;MESSAGE BUFFER
	EXTERN	G$ACKB 			;GENERIC ACK BUFFER ADDRESS
TOPS10<	EXTERN	DEVNTB >		;%UNKN DEVICE TRANSLATION TABLE


MDRDSP:	$BUILD	%MDMAX+1
	 $SET(.MDINV,,.RETF)		;OFFSET 0 IS INVALID
	 $SET(.TMDEN,,MNTDEN)		;DENSITY BLOCK PROCESSOR
	 $SET(.TMDRV,,MNTDRV)		;DRIVE BLOCK PROCESSOR
	 $SET(.TMLT,,MNTLT)		;LABEL TYPE BLOCK PROCESSOR
	 $SET(.TMSET,,MNTSET)		;SET NAME BLOCK PROCESSOR
	 $SET(.TMRMK,,MNTRMK)		;REMARK BLOCK PROCESSOR
	 $SET(.TMSTV,,MNTSTV)		;STARTING VOLUME ID BLOCK PROCESSOR
	 $SET(.TMVOL,,MNTVOL)		;VOLUME ID BLOCK PROCESSOR
	 $SET(.TMVPR,,MNTPRT)		;VOL PROTECTION CODE BLOCK PROCESSOR
	 $SET(.TMINI,,.RETT)		;VOL INITIALIZATION BLOCK PROCESSOR
TOPS20<	 $SET(.SMNAM,,MNTSET) >		;STRUCTURE NAME PROCESSOR
TOPS10<	 $SET(.SMNAM,,.RETF) >		; (ILLEGAL ON TOPS10)
TOPS20<	 $SET(.SMALI,,MNTVOL) >		;ALIAS BLOCK PROCESSOR
TOPS10<	 $SET(.SMALI,,.RETF) >		; (ILLEGAL ON TOPS10)
	 $SET(.TMLNM,,MDRLNM)		;LOGICAL NAME PROCESSOR
	$EOB


	;DEFINE A MACRO TO PACK A BLOCK OF STORAGE INTO ITSELF STARTING AT
	;THE ADDRESS CONTAINED IN 'AC'

DEFINE	$PACK(AC),<
	AOBJP	AC,.+4		;;CHECK THE AC,,IF POSITIVE,,SKIP
XLIST
	MOVE	TF,0(AC)	;;STILL NEGATIVE,,GET THE VALUE AT 0(AC)
	MOVEM	TF,-1(AC)	;;AND STORE IT AT ADDRESS AC-1
	JRST	.-3		;;HEAD BACK FOR MORE
	SETZM	-1(AC)		;;WE'RE DONE,,ZERO THE LAST ENTRY
LIST>

	;GENERALIZED VOLUME LABEL TYPE DEFINITIONS

	%UNLBL==1			;VOLUME IS UNLABELED
	%LABEL==2			;VOLUME IS LABELED

LABELS::[ASCIZ/Bypass/]
	[ASCIZ/ANSI/]
	[ASCIZ/ANSI/]
	[ASCIZ/IBM/]
	[ASCIZ/IBM/]
	[ASCIZ/No/]
	[ASCIZ/Non-Standard/]
	[ASCIZ/No/]
	[ASCIZ/Cobol Sixbit/]
	[ASCIZ/Cobol Ascii/]
	[ASCIZ/No/]

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

DENSTY::[ASCIZ/Default/]
	[ASCIZ/200/]
	[ASCIZ/556/]
	[ASCIZ/800/]
	[ASCIZ/1600/]
	[ASCIZ/6250/]

TOPS10<
D$DEN::	0		;SYSTEM DEFAULT
	UC.200		;200 BPI
	UC.556		;556 BPI
	UC.800		;800 BPI
	UC.1600		;1600 BPI
	UC.6250		;6250 BPI

	DENLEN==.-D$DEN
> ;END TOPS10 CONDITIONAL

TRK::	SIXBIT/     /
	SIXBIT/ 7   /
	SIXBIT/ 9   /

WRTENA:	[ASCIZ/Enabled/]
	[ASCIZ/Locked/]

AVA:	[ASCIZ/Available/]
	[ASCIZ/Unavailable/]

LCKTB1:	SIXBIT	/LOCK/
	SIXBIT	/UNLOCK/

LCKTB2:	SIXBIT	/UNLOCK/
	SIXBIT	/LOCK/

RID:	BLOCK	1			;REQUEST ID SAVE AREA
D$ASR::	EXP	-1			;AUTOMATIC STRUCTURE RECOGNITION FLAG
AMATRX::EXP	0			;'A' MATRIX ADDRESS INITIALLY NONE
BMATRX::EXP	0			;'B' MATRIX LIST ID
CMATRX::EXP	0			;'C' MATRIX LIST ID
STRVOL:	BLOCK	1			;STARTING VOLUME SAVE AREA
VOLNBR:	BLOCK	1			;VOLUME COUNT IN A VOLUME SET
ERRACK::BLOCK	1			;ACK BEING SENT IS A FATAL ACK
PROCNT:	EXP	0			;'B' & 'C' MATRIX PROCESS COUNTS
MDAOBJ::.OTMNT				;MDA OBJECT BLOCK - TYPE .OTMNT
	EXP	0			;SPACE FOR SIXBIT UNIT NAME
	0,,0				;NO NODE NAME
VOLNAM:	BLOCK	2			;PLACE FOR AN ASCIZ STR NAME
WRTLCK:	BLOCK	1			;WRITE-LOCKED FLAG FOR STR MOUNTS
OSNFLG:	BLOCK	1			;FLAG FOR OVERRIDE-SET-NUMBER
STRFLG:	BLOCK	1			;FLAG FOR FINDING FREE DISK UNITS
MDRQUE:: EXP	-1			;TAPE MOUNT QUEUE LIST ID
UCBQUE:: 0,,0				;UCB QUEUE
VSLQUE:: 0,,0				;VOLUME SET LIST QUEUE
VOLQUE:: 0,,0				;VOLUME LIST QUEUE
CATOBJ:	BLOCK	OBJ.SZ			;OBJECT BLOCK FOR WTO MSG
CATFLG:	BLOCK	1			;NON-ZERO IF NO CATALOG SEARCH

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

TOPS10<
	;This structure defines the initial 'A' matrix for Resource Allocation
	;  Call: X(Res-Name,Res-Type,Kontroler type,Unit type,Track,Density)

	MAXNCH==^D39			;MAX # OF CHARS IN A RESOURCE NAME
	AMNMLN==<MAXNCH+1+4>/5		;WORDS REQ'D TO STORE ONE OF THESE
	DEFINE	GENRES,<XLIST

	X	(RD10,%DISK,.DCCFH,.DCUFD,0,UC.SHR)
	X	(RS04,%DISK,.DCCFS,.DCUS4,0,UC.SHR)
	X	(RP04,%DISK,.DCCRP,.DCUR4,0,UC.SHR)
	X	(RM10B,%DISK,.DCCFH,.DCUFM,0,UC.SHR)
	X	(RP02,%DISK,.DCCDP,.DCUD2,0,UC.SHR)
	X	(RP06,%DISK,.DCCRP,.DCUR6,0,UC.SHR)
	X	(RP03,%DISK,.DCCDP,.DCUD3,0,UC.SHR)
	X	(RM03,%DISK,.DCCRP,.DCUR3,0,UC.SHR)
	X	(RP07,%DISK,.DCCRP,.DCUR7,0,UC.SHR)
	X	(RP20,%DISK,.DCCRN,.DCUN0,0,UC.SHR)
	X	(RA80,%DISK,.DCCRA,.DCU80,0,UC.SHR)
	X	(RA81,%DISK,.DCCRA,.DCU81,0,UC.SHR)
	X	(RA60,%DISK,.DCCRA,.DCU60,0,UC.SHR)
	X	(3330,%DISK,.DCCSX,.DCUS0,0,UC.SHR)
	X	(3331,%DISK,.DCCSX,.DCUS1,0,UC.SHR)
	X	(<7 TK 200/556/800>,%TAPE,0,0,%TRK7,UC.200+UC.556+UC.800)
	X	(<9 TK 800/1600>,%TAPE,0,0,%TRK9,UC.800+UC.1600)
	X	(<9 TK 1600/6250>,%TAPE,0,0,%TRK9,UC.1600+UC.6250)
	X	(<9 TK 200/556/800>,%TAPE,0,0,%TRK9,UC.200+UC.556+UC.800)
	X	(<9 TK 800/1600/6250>,%TAPE,0,0,%TRK9,UC.800+UC.1600+UC.6250)
	X	(TU56,%DTAP,0,0,0,0)
	LIST>

	DEFINE	X(TYP7,TYPE,KON,UNIT,TRK,DEN),<XLIST
	$BUILD	AMALEN
		$SET	(.AMNAM,AM.NAM,[ASCIZ^TYP7^])
		$SET	(.AMNAM,AM.PRM,1)
		$SET	(.AMNAM,AM.USE,1)
		$SET	(.AMSTA,,<FLD(KON,UC.KTP)+FLD(UNIT,UC.UTP)+FLD(TRK,UC.TRK)+FLD(TYPE,UC.DVT)+DEN>)
	$EOB
	LIST>

	DEFINE	BLDPRM,<XLIST
	  GENRES			;BUILD THE PERMANENT 'A' MATRIX
	LIST >

;Generate the permanent A-matrix - Build block 0, the header

AMATPM:	$BUILD	AMALEN
	$SET	(.AMHDR,AM.CNT,RESCNT)	;HIGHEST IN USE
	$SET	(.AMHDR,AM.MCN,RESCNT)	;BIGGEST MATRIX HAS SPACE FOR
	$SET	(.AMHDR,AM.LEN,RESLEN)	;LENGTH OF THIS BLOCK
	$EOB

	BLDPRM				;BUILD THE PERMANENT 'A' MATRIX
	RESLEN==.-AMATPM		;THE LENGTH OF THE PERMANENT A MATRIX
	RESCNT==<RESLEN/AMALEN>-1	;THE NUMBER OF BLOCKS IN USE

> ;END TOPS10 CONDITIONAL

TMPVSL:	BLOCK	VSLLEN			;MAKE SURE WE AT LEAST HAVE ENOUGH SPACE

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

DEMOB::	ITEXT	(<User: [SYSTEM] for ^15/.VSRFL(T1),MR.QUE/ Request #^D/S1/>)
DEMOT::	ITEXT	(<User: ^W6/.MRNAM(AP)/^W/.MRNAM+1(AP)/ ^U/.MRUSR(AP)/ Job #^D/.MRJOB(AP),MD.PJB/>)

DEFINE	X(CODE,STRING),<XLIST
	EXP	[ASCIZ/STRING/]
	LIST >

MDAERS:	MDAERR			;GENERATE THE ERROR STRINGS
	SUBTTL	D$INIT - ROUTINE TO INITIALIZE THE MDA DATA BASE

D$INIT::SKIPN	G$MDA##			;MDA SUPPORT HERE ???
	$RETT				;NO,,RETURN
	PUSHJ	P,L%CLST		;CREATE A LIST FOR THE MDR
	MOVEM	S1,MDRQUE		;SAVE THE ID
	PUSHJ	P,L%CLST		;CREATE A LIST FOR THE VSL SET CHAIN
	MOVEM	S1,VSLQUE		;SAVE THE ID
	PUSHJ	P,L%CLST		;CREATE A LIST FOR THE VOLUME LIST
	MOVEM	S1,VOLQUE		;SAVE THE ID
TOPS20<	$RETT	>			;RETURN NOW ON THE -20
TOPS10<					;...BUT ON THE -10...
	;NOTE:::: The UCB chain will be built by I$INIT (QSRT10)

	MOVEI	S1,MDADAE		;GET DEADLOCK FLAG
	MOVEM	S1,G$DEAD##		;AND SET IT
	PUSHJ	P,L%CLST		;CREATE A LIST FOR THE 'B' MATRIX
	MOVEM	S1,BMATRX		;SAVE IT
	PUSHJ	P,L%CLST		;CREATE A LIST FOR THE 'C' MATRIX
	MOVEM	S1,CMATRX		;SAVE IT
	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%FIRST		;POSITION TO THE FIRST UCB
	JUMPT	INIT.2			;IF FOUND,,CONTINUE
	STOPCD	(NUE,HALT,,<Null UCB chain encountered>) ;NO,,DEEP TROUBLE
INIT.1:	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT UCB ENTRY
INIT.2:	JUMPF	INIT.4			;NO MORE,,SETUP PERM STRS
	MOVE	T1,S2			;SAVE THE UCB ADDRESS IN T1
	LOAD	S1,.UCBST(T1),UC.AVA	;GET AVAILABLE BIT
	JUMPE	S1,INIT.1		;NOT AVAILABLE,,SKIP THIS
	MOVE	S1,T1			;GET THE UCB ADDRESS IN S1
	PUSHJ	P,D$INCA		;INCRIMENT THE 'A' MATRIX
	JRST	INIT.1			;AND GO TRY THE NEXT UCB

INIT.4:	PUSHJ	P,I$ISTR##		;INITIALIZE SYSTEM STRUCTURE LIST
	PUSHJ	P,I$PERM##		;SETUP 'PERMENANT STRUCTURES'

	MOVN	P1,G$MAXJ##		;GET NUMBER OF JOBS IN THE SYSTEM
	HRLZS	P1			;GET -NUMBER,,0
	AOS	P1			;START WITH JOB NUMBER 1
	MOVEI	S1,0(P1)		;GET A JOB NUMBER
	PUSHJ	P,I$SSRL##		;CREATE THE GUYS MDR ENTRY
	AOBJN	P1,.-2			;CONTINUE FRO ALL JOBS
	PJRST	MNTOPR			;RETURN,,SETTING UP MOUNTS PENDING EVENT
> ;END TOPS10 CONDITIONAL
SUBTTL	HOLD/RELEASE/MOUNT interface for QSRQUE


; Here while processing a HOLD or RELEASE command to notify the
; operator of mount queue changes.
; Call:	MOVE	S1, QE address
;	MOVE	S2, 0 for HOLD or 1 for RELEASE
;	PUSHJ	P,D$HOLD/D$RELE
;
D$HOLD::
TOPS20	<POPJ	P,>			;CAN'T DO THIS HERE

TOPS10	<				;TOPS-10 ONLY
	SKIPN	.QEMDR(S1)		;HAVE AN MDR?
	POPJ	P,			;NO
	$SAVE	<P1,P2,P3,P4>		;SAVE SOME ACS
	$SAVE	<T1,T2>			;SAVE MORE ACS
	$SAVE	<AP>			;SAVE AP
	MOVE	AP,.QEMDR(S1)		;GET THE MDR ADDRESS
	MOVE	T1,S2			;REMEMBER WHAT WE'RE DOING
	LOAD	P1,.MRCNT(AP),MR.CNT	;GET VSL COUNT FOR THIS MDR
	MOVNS	P1			;NEGATE IT
	HRLI	P1,.MRVSL(AP)		;GET ADDRESS OF FIRST VSL
	MOVSS	P1			;MAKE AN AOBJN POINTER

HOLD.1:	HRRZ	P2,(P1)			;GET A VSL ADDRESS
	MOVX	S1,VS.ALC!VS.ABO	;GET SOME BITS
	TDNE	S1,.VSFLG(P2)		;ALLOCATED OR ABORTED?
	JRST	HOLD.4			;YES - IGNORE THIS VSL
	LOAD	P3,.VSCVL(P2),VS.CNT	;GET NUMBER OF VOLS IN THE VSN
	MOVNS	P3			;NEGATE IT
	HRLI	P3,.VSVOL(P2)		;GET ADDRESS OF FIRST VOL
	MOVSS	P3			;MAKE AN AOBJN POINTER

HOLD.2:	HRRZ	P4,(P3)			;GET A VOL ADDRESS
	HRRZ	S1,.VLVSL(P4)		;GET A VSL BACK POINTER
	MOVX	S2,VL.ASN		;GET THE VOL ASSIGNED BIT
	CAMN	S1,P2			;SAME VSL?
	TDNE	S2,.VLVSL(P4)		;AND VOL ASSIGNED?
	JRST	HOLD.3			;TRY ANOTHER VOL
	MOVE	S1,.VSRID(P2)		;GET MOUNT REQUEST ID
	MOVE	S2,.MRQEA(AP)		;GET QE ADDRESS
	MOVE	S2,.QERID(S2)		;GET QE REQUEST ID
	LOAD	T2,.VSRFL(P2),MR.QUE	;[1173] GET OBJECT TYPE
	$WTO	(<Mount request #^D/S1/>,<^I/HOLD.5/>,,<$WTFLG(WT.SJI)>)
	JUMPE	T1,HOLD.3		;ONWARD IF HOLDING THIS JOB
	MOVX	S1,VS.OPR		;GET A BIT
	IORM	S1,.VSFLG(P2)		;AND WAKE UP THE SLEEPING OPERATOR

HOLD.3:	AOBJN	P3,HOLD.2		;LOOP THROUGH ALL VOL BLOCKS
HOLD.4:	AOBJN	P1,HOLD.1		;LOOP THROUGH ALL VSL BLOCKS
	POPJ	P,			;RETURN

HOLD.5:	ITEXT	(<^T/@HOLD.6(T1)/ the queue due to ^T/@MNTTAB(T2)/
request #^D/S2/ being ^T/@HOLD.7(T1)/>)

HOLD.6:	[ASCIZ	|Removed from|]		;HOLD
	[ASCIZ	|Added to|]		;RELEASE

HOLD.7:	[ASCIZ	|held|]			;HOLD
	[ASCIZ	|released|]		;RELEASE
; Translation table of object type to text for mount displays
;
MNTTAB:	[0,,0]				;INVALID
	[0,,0]				;.OTRDR (READER QUEUE)
	[0,,0]				;.OTNET (NETWORK QUEUE)
	[ASCIZ	|Print|]		;.OTLPT (PRINTER QUEUE)
	[ASCIZ	|Batch|]		;.OTBAT (BATCH QUEUE)
	[ASCIZ	|Card punch|]		;.OTCDP (CARD PUNCH QUEUE)
	[ASCIZ	|Paper tape punch|]	;.OTPTP (PAPER TAPE PUNCH QUEUE)
	[ASCIZ	|Plotter|]		;.OTPLT (PLOTTER QUEUE)
	[0,,0]				;.OTJOB
	[0,,0]				;.OTTRM
	[0,,0]				;.OTOPR
	[0,,0]				;.OTIBM
	[0,,0]				;.OTMNT
	[ASCIZ	|File transfer|]	;.OTFTS (FILE TRANSFER QUEUE)
	[ASCIZ	|Interpreter|]		;.OTBIN (SPRINT)
	[ASCIZ	|Retrieval|]		;.OTRET
	[0,,0]				;.OTNOT
	[0,,0]				;.OTDBM
	[0,,0]				;.OTFAL

> ;END TOPS-10 CONDITIONAL
	SUBTTL	D$MOUN - Process a Tape/Disk Mount Request

	;CALL: 	M/ The Mount Message Address
	;	S1/ The QE address if entry point D$MNTP
	;
	;RET:	An Ack to the user (If he wants one)

D$MNTP::SKIPA				;MNTP ENTRY POINT (CALLED FROM I$BMDR)
D$MOUN::SETZM	S1			;'MOUNT' ENTRY POINT
	SKIPN	G$MDA##			;[1135]IS MDA SUPPORTED ???
	JRST	E$MDA##			;NO,,RETURN AN ERROR !!!
	PUSHJ	P,.SAVE1		;SAVE P1 FOR A SECOND
	MOVE	P1,S1			;SAVE THE QE ADDRESS IF THERE IS ONE
	PUSHJ	P,D$CMDR		;GO CREATE THE MDR ENTRY
	JUMPF	.RETT			;RETURN IF AN ERROR OCCURED
	JUMPN	P1,MOU.7		;[1135]JUMP IF QE ADDRESS HELD
	PUSH	P,S1			;[1135]SAVE S1
	LOAD	S1,.MRJOB(AP),MR.JOB	;[1135]GET REQUESTING JOB NUMBER
	TXNE	S1,BA%JOB		;[1135]INITIAL MOUNTS FOR BATCH JOB ?
	  JRST	MOU.6			;[1135]JUMP IF SO
	ANDX	S1,MD.PJB		;JUST JOB NUMBER
	MOVX	S2,JI.BAT		;[1135]GET BATCH DATA FOR JOB
	$CALL	I%JINF			;[1135]GET DATA
	TXNN	S2,OB.BSS		;[1135]BATCH JOB
	  JRST	MOU.6			;[1135] JUMP IF NOT
	PUSH	P,P2			;[1135]SAVE P2 FOR A MINUTE
	LOAD	P2,HDRUSE##+.QHLNK,QH.PTF ;[1135]POINT TO IN USE QUEUE
	JUMPE	P2,MOU.5		;[1135]FORGET IT IF EMPTY
	LOAD	S1,S2,OB.BSN		;[1135]GET BATCH STREAM NUMBER
MOU.2:	LOAD	S2,.QEROB+.ROBTY(P2)	;[1135]GET OBJECT TYPE
	CAIE	S2,.OTBAT		;[1135]BATCH ?
	  JRST	MOU.3			;[1135]JUMP IF SO
	LOAD	S2,.QEOBJ(P2)		;[1135]GET BATCH OBJECT
	LOAD	S2,OBJUNI(S2)		;[1135]GET STREAM NUMBER
	CAME	S2,S1			;RIGHT STREAM?
	  JRST	MOU.3			;NO, TRY AGAIN
	PUSH	P,S1			;SAVE THE STREAM NUMBER
	LOAD	S1,.QEOBJ(P2)		;GET OBJECT BLOCK ADDRESS
	LOAD	S1,OBJNOD(S1)		;GET PROCESSING NODE
	PUSHJ	P,N$LOCL##		;IS PROCESSING LOCAL?
	POP	P,S1			;RECOVER STREAM NUMBER
	JUMPT	MOU.4			;SAME STREAM AND LOCAL?
MOU.3:	LOAD	P2,.QELNK(P2),QE.PTN	;[1135]LOOK AT NEXT ENTRY
	JUMPN	P2,MOU.2		;[1135]LOOP TO END
MOU.4:	MOVE	P1,P2			;[1135]IF QE FOUND, GET ADDRESS
MOU.5:	POP	P,P2			;[1135]RESTORE P2
MOU.6:	POP	P,S1			;[1135]RESTORE S1
MOU.7:	JUMPE	P1,MOU.8		;[1135]NO QE,,SKIP NEXT 2 INSTRUCTIONS
	MOVEM	AP,.QEMDR(P1)		;YES,,SAVE THE MDR ADDRESS
	MOVEM	P1,.MRQEA(AP)		;SAVE THE QE ADDRESS IF ANY
MOU.8:	MOVE	P1,S1			;[1135]SAVE VSL ADDRESS (FROM D$CMDR)
	MOVE	S2,G$ACK##		;GET THE ACK REQUEST CODE
	STORE	S2,.VSRFL(P1),MR.ACK	;[1173] SAVE IT IN VSL
	SETZM	G$ACK##			;CLEAR THE ACK REQUEST
	PUSHJ	P,I$MNTR##		;SEND THE MESSAGE TO MOUNTR (TOPS20 ONL
	JUMPF	D$DMDR			;NO GOOD,,DELETE THE MDR AND RETURN
TOPS20<	PUSHJ	P,USRACK		;ACK THE USER
	$RETT				;AND RETURN
>
TOPS10<	MOVE	S1,P1			;GET THE VSL ADDRESS
	PUSHJ	P,D$ALOC		;TRY TO PERFORM ALLOCATION
	JUMPF	[JUMPL	S1,.RETT	;ALLOCATION POSTPONED,,JUST RETURN
		 MOVE	S1,P1		;NO GOOD,,GET THE VSL ADDRESS BACK
		 PJRST	DELETE ]	;RETURN,,DELETING VOL SETS JUST ADDED
	MOVE S1,P1			;GET THE	VSL ADDRESS
	PUSHJ	P,MNTVSL		;TRY TO MOUNT IT
	$RETT				;RETURN
>
	SUBTTL	D$DEAS - DEASSIGN/RELEASE A VOLUME SET

	;CALL:	M / The Deassign Message Address
	;
	;RET:	True Always

TOPS10 <
D$DEAS::PUSHJ	P,.SAVE3		;SAVE P1 & P2 FOR A MINUTE
	LOAD	S1,.TDDVT(M),TDD.FL	;[1234] GET MONITOR FLAGS
	TXNN	S1,TD.VSW		;[1234] VOL SWITCH STATS?
	JRST	DEAS.0			;[1234] NO, CONTINUE
	MOVE	S1,.TDJBN(M)		;[1234] YES, GET JOB NUMBER
	PUSHJ	P,FNDMDR		;[1234] GET MDR FOR JOB
	JUMPT	I$TDSM##		;[1234] GO UPDATE ACCOUNTING
	$RETT				;[1234] FORGET IT IF NO MDR

DEAS.0:	MOVE	S1,.TDDEV(M)		;[1234] GET THE RELEASED DEVICE NAME
	PUSHJ	P,UCBLOC		;FIND THE DEVICE IN THE UCB CHAIN
	JUMPT	DEAS.1			;CONTINUE IF WE KNOW ABOUT THIS DEVICE
	MOVE	S1,.TDDEV(M)		;PICK UP THE DEVICE NAME
	PUSHJ	P,I$MDAC##		;CLEAR THE MDA BIT
	$WTO	(<Released>,,MDAOBJ)	;TELL THE OPERATOR
	$RETT				;RETURN

DEAS.1:	MOVE	P1,S1			;SAVE THE UCB ADDRESS IN P1
	SKIPN	P2,.UCBVS(P1)		;DOES THE UCB POINT TO A VSL ???
	$RETT				;NO OWNER,,STRANGE !!!
	MOVE	AP,.VSMDR(P2)		;GET THE MDR ADDRESS
	LOAD	S1,.MRJOB(AP),MD.PJB	;GET THE OWNERS JOB NUMBER
	CAME	S1,.TDJBN(M)		;THESE MUST MATCH !!!
	STOPCD	(IOS,HALT,,<Invalid Owner Specified in Reassign Message>) ;NO,,UH OH !!
	$WTO	(<Released>,<^I/DEMOT/>,MDAOBJ) ;TELL OPR WHATS GOING ON
	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	LOAD	S2,.TDDVT(M),TDD.DV	;[1234] GET THE DEVICE TYPE
	CAIN	S2,.TYDTA		;DECTAPE?
	JRST	DEAS.2			;YES
	CAIN	S2,.TYMTA		;MAGTAPE?
	JRST	DEAS.3			;YES
	MOVE	S1,.TDDEV(M)		;[1141]PICK UP THE DEVICE NAME
	PUSHJ	P,I$MDAC##		;CLEAR THE MDA BIT
	MOVE	S1,UCBQUE		;[1141]GET THE UCB QUEUE ID
	MOVE	S2,.VSUCB(P2)		;GET THE UCB ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO THAT ENTRY
	PUSHJ	P,L%DENT		;DELETE THAT ENTRY
	SETZM	.VSUCB(P2)		;ZAP THAT POINTER
	MOVE	S1,P2			;GET THE VSL ADDRESS
	PUSHJ	P,DELVSL		;DELETE IT
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE USERS REQUEST COUNT
	JUMPE	S1,DELMDR		;NOTHING LEFT,,DELETE THE MDR
	$RETT				;AND EXIT

DEAS.2:	PUSHJ	P,I$DDSM##		;DO DECTAPE ACCOUNTING
	MOVE	S1,.TDDEV(M)		;COPY THE DEVICE NAME
	PUSHJ	P,I$MDAC##		;CLEAR THE MDA BIT
	SKIPA				;ENTER COMMON CODE
DEAS.3:	PUSHJ	P,I$TDSM##		;DO MAGTAPE ACCOUNTING
	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,ALCVSL		;RETURN THIS VSL TO THE ALLOCATION POOL
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE USERS REQUEST COUNT
	JUMPE	S1,DELMDR		;NOTHING LEFT,,DELETE THE MDR
	$RETT				;AND EXIT
>
	SUBTTL	D$CMDR - ROUTINE TO CREATE AN ENTRY IN THE MDR QUEUE

	;CALL:	M/The MOUNT Message Address
	;
	;RET:	AP/ The MDR address
	;	S1/ The VSL address

D$CMDR::PUSHJ	P,VALMSG		;GO VALIDATE SOME OF THE MESSAGE
	JUMPF	.RETF			;NO GOOD,,THATS AN ERROR
	PUSHJ	P,.SAVE4		;SAVE 4 P AC'S
	MOVE	S1,REQIDN##		;SAVE THE LAST VALID REQUEST ID
	MOVEM	S1,RID			;  FOR A FEW MINUTES

	LOAD	S1,G$PRVS##,MR.JOB	;GET THE SENDERS JOB NUMBER
	PUSHJ	P,FNDMDR		;FIND THIS USERS MDR
	JUMPF	CMDR.1			;NOT THERE,,CREATE ONE

	;Here to check to see if there is enough room for the next VSL
	;and if not, create a new MDR

	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	PUSHJ	P,L%SIZE		;GET HIS CURRENT MDR LENGTH
	MOVE	P4,S2			;SAVE THE MDR LENGTH
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	SUBI	S2,MDRLEN(S1)		;DELETE BASE MDR LEN+VSL CNT FROM TOTAL
	SUB	S2,.MMARC(M)		;SUBTRACT NEW REQUEST NUMBER
	JUMPGE	S2,CMDR.2		;NEW REQUEST WILL FIT INTO OLD MDR !!
	MOVNS	S2			;GET POSITIVE DIFFERENCE
	ADD	S2,P4			;ADD IT TO THE OLD MDR LENGTH
	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	PUSHJ	P,L%CENT		;CREATE A NEW MDR FOR THE USER
	MOVE	P3,S2			;SAVE THE NEW MDR ADDRESS
	HRL	P3,AP			;CREATE SOURCE,,DEST BLT AC
	ADDI	P4,-1(S2)		;GET BLT END ADDRESS
	BLT	P3,0(P4)		;COPY OLD MDR TO NEW MDR
	EXCH	AP,S2			;EXCHANGE OLD AND NEW MDR ADDRESSES
	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	PUSHJ	P,L%APOS		;POSITION TO THE OLD MDR
	PUSHJ	P,L%DENT		;   AND DELETE IT
	SKIPE	S1,.MRQEA(AP)		;POINTING TO A QE ???
	MOVEM	AP,.QEMDR(S1)		;YES,,RESET POINTER !
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT (CURRENT)
	MOVNS	S1			;NEGATE IT
	MOVSS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.MRVSL(AP)		;CREATE AOBJN AC FOR VSL ADDRESS LIST

CMDR.0:	MOVE	S2,0(S1)		;GET A VSL ADDRESS
	MOVEM	AP,.VSMDR(S2)		;RESET MDR POINTER FOR NEW MDR
	AOBJN	S1,CMDR.0		;RESET ALL VSL MDR POINTERS
	JRST	CMDR.2			;AND CONTINUE PROCESSING

	;CONTINUED ON THE NEXT PAGE
	;Here to create a new MDR for a user who does not already have one

CMDR.1:	MOVE	S1,MDRQUE		;GET THE QUEUE ID
	PUSHJ	P,L%LAST		;POSITION TO THE LAST ENTRY
	MOVE	S1,MDRQUE		;GET THE QUEUE ID
	SKIPG	S2,.MMARC(M)		;CHECK AND LOAD THE VOLUME SET COUNT
	PJRST	E$MRP##			;NONE,,THEN 'MOUNT/WAIT' W/NONE PENDING
	ADDI	S2,MDRLEN-1		;ADD MDR LENGTH-1
	PUSHJ	P,L%CENT		;GO CREATE A QUEUE ENTRY
	MOVE	AP,S2			;GET THE ENTRY ADDRESS
	MOVE	S1,AP			;GET THE MDR ADDRESS IN S1
	PUSHJ	P,I$DFMR##		;FILL IN SYSTEM DEPENDENT DATA

CMDR.2:	MOVE	S1,G$SID##		;GET THE OWNERS ID
	MOVEM	S1,.MRUSR(AP)		;SAVE IT IN THE QUEUE
	MOVE	S1,G$SND##		;GET THE SENDERS PID
	MOVEM	S1,.MRPID(AP)		;SAVE IT
	MOVE	S1,.MSCOD(M)		;GET THE SENDERS ACK CODE
	MOVEM	S1,.MRACK(AP)		;SAVE IT
	MOVE	S1,G$PRVS##		;GET THE SENDERS CAPABILITIES
	MOVEM	S1,.MRJOB(AP)		;SAVE IT IN THE QUEUE
	SETZM	.MRFLG(AP)		;[1173] START CLEAN
	LOAD	S1,.MMFLG(M),MM.WAT	;GET USER REQUEST FOR WAITING
	STORE	S1,.MRFLG(AP),MR.WAT	;SAVE IN MDR
	LOAD	S1,.MMFLG(M),MM.NOT	;AND GET USER NOTIFY BIT
	STORE	S1,.MRFLG(AP),MR.NOT	;AND SAVE THAT IN MDR
	LOAD	S1,.MMFLG(M),MM.GFR	;GET CREATED BY [SYSTEM]GOPHER BIT
;**;[1170] Delete 3 lines after CMDR.2+12L. 29-Dec-83 /LWS
	STORE	S1,.MRFLG(AP),MR.GFR	;SET/CLEAR THE BIT

	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE REQUESTING JOB NUMBER
	TXNE	S1,BA%JOB		;IS THIS A BATCH REQUEST ???
	JRST	CMDR.3			;YES,,SKIP THIS
	MOVX	S2,JI.JLT		;CODE TO GET LOGIN TIME
	$CALL	I%JINF			;ASK THE LIBRARY
	MOVEM	S2,.MRLOG(AP)		;SAVE IN MDR FOR NOTIFY

CMDR.3:	INCR	.MRCNT(AP),MR.LNK	;GEN A NEW VSL LINK CODE
	MOVEI	P2,.MMHSZ(M)		;POINT TO THE FIRST MOUNT ENTRY
	SKIPN	P4,.MMARC(M)		;GET THE VOLUME SET COUNT IN P4
	JRST	CMDR.6			;NONE,,THEN .MOUNT/WAIT...

CMDR.4:	MOVE	S1,P2			;GET THE MOUNT MSG ENTRY ADDRESS IN S1
	PUSHJ	P,BLDVSL		;GO BUILD THE VOLUME SET LIST
	JUMPF	CMDR.5			;CHK BLDVSL - NO GOOD,,DELETE THIS MDR
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	PUSHJ	P,MDR2VS		;[1173] COPY VSL REQUEST DEPENDENT DATA
	LOAD	S1,.MEHDR(P2),AR.LEN	;GET THIS ENTRIES LENGTH
	ADDI	P2,0(S1)		;POINT TO THE NEXT ENTRY
	SOJG	P4,CMDR.4		;CONTINUE THROUGH ALL VOLUME SETS
	SETOM	.MRFLG(AP)		;[1173] INDICATE MDR ACK DATA COPIED
	MOVE	S1,P1			;RETURN THE LAST VSL ADDRESS
	$RETT				;RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

CMDR.5:	PUSHJ	P,DELETE		;DELETE THE VOL SETS JUST ADDED
	MOVE	S1,RID			;GET THE LAST VALID REQUEST ID
	MOVEM	S1,REQIDN##		;SAVE IT
	SKIPN	G$ERR##			;DID WE ALREADY SEE AN ERROR?
	PJRST	E$IMM##			;NO, RETURN THROUGH 'INVALID MOUNT MSG'
	$RETF				;YES, BUBBLE IT UP!

	;Here if MOUNT/WAIT<CRLF> was typed

CMDR.6:	LOAD	P1,.MRCNT(AP),MR.LNK	;GET CURRENT LINK CODE
	LOAD	P2,.MRCNT(AP),MR.CNT	;GET REQUEST COUNT
	MOVNS	P2			;NEGATE THE REQUEST COUNT
	MOVSS	P2			;GET COUNT IN LEFT HALF
	HRRI	P2,.MRVSL(AP)		;CREATE ABOJN AC
	SETZM	P3			;SET MOUNT PENDING FLAG

CMDR.7:	MOVE	S1,0(P2)		;PICK UP A VSL ADDRESS
	LOAD	S2,.VSFLG(S1),VS.ALC	;IS IT JUST ALLOCATED ???
	JUMPN	S2,CMDR.8		;YES,,TRY NEXT
	PUSHJ	P,CHKOWN		;CHECK FOR OWNERSHIP
	JUMPT	[MOVX  S2,VL.ASK	;OWNED,,CHECK TO SEE IF 'ASK' IS SET
		 TDNN  S2,0(S1)		;IS IT REALLY MOUNTED ???
		 JRST  CMDR.8		;YES,,TRY NEXT REQUEST
		 JRST  .+1  ]		;NO,,ADD'EM UP
	MOVE	P3,0(P2)		;SAVE THE VSL ADDRESS
	STORE	P1,.VSLNK(P3),VS.LNK	;RESET LINK CODE
CMDR.8:	AOBJN	P2,CMDR.7		;GET NEXT REQUEST
	JUMPE	P3,E$MRP##		;NONE WAITING,,TELL THE USER
	MOVX	S1,MR.ACK		;[1173] HE HAS MOUNTS, HE'LL
	IORM	S1,.MRFLG(AP)		;[1173] NEED 2 ACKS TO GET OUT OF MOUNT
	MOVE	S1,P3			;RETURN THE LAST VSL ADDRESS
	$RETT				;LETERRIP
	SUBTTL	D$LOGO - DELETE A USER MDR'S ON LOGOUT

	;CALL:	S1/ The User Job Number
	;
	;RET:	True Always

TOPS10 <
D$LOGO::SKIPN	G$MDA##			;MUST BE RUNNING WITH MDA ENABLED
	$RETT				;NO,,RETURN
	$SAVE	<AP>			;SAVE AP FOR A SECOND
	PUSHJ	P,FNDMDR		;FIND THIS USERS MDR
	JUMPF	.RETT			;NO MORE,,RETURN
	PUSHJ	P,D$DMDR		;DELETE THIS MDR
	$RETT				;RETURN
>

TOPS20<
D$LOGO:	$RETT	>			;JUST RETURN ON THE -20
	SUBTTL	D$XCH - Exchange disk units

; Here when the monitor sends us an exchange message (.IPCXC). This can
; happen when an operator issues the priv'ed command XCHANGE to swap two
; disk units.
;
;CALL:	M/ The Message address
;
;RET:	True always

TOPS10<	INTERN	D$XCH			;EXCHANGE DISK UNITS

D$XCH:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	S1,.XCHU1(M)		;GET UNIT 1 NAME
	PUSHJ	P,UCBLOC		;FIND THE UCB
	  JUMPF	XCH.1			;CAN'T - EXIT
	MOVE	P1,S1			;SAVE ADDRESS
	MOVE	S1,.XCHU2(M)		;GET UNIT 2 NAME
	PUSHJ	P,UCBLOC		;FIND THE UCB
	  JUMPF	XCH.2			;CAN'T - EXIT
	MOVE	S2,.UCBNM(P1)		;GET OLD UNIT 1 NAME
	EXCH	S2,.UCBNM(S1)		;SET NEW UNIT 2 NAME, GET OLD UNIT 2
	MOVEM	S2,.UCBNM(P1)		;SET NEW UNIT 1 NAME
	MOVE	S2,.UCBAU(P1)		;GET OLD UNIT 1 ALT PORT
	EXCH	S2,.UCBAU(S1)		;SAVE OLD ALT PORT,,GET NEW ALT PORT
	MOVEM	S2,.UCBAU(P1)		;SAVE NEW ALT PORT NAME
	$WTO	(<Disk unit ^W/.XCHU1(M)/ exchanged with ^W/.XCHU2(M)/>,,,<$WTFLG(WT.SJI)>)
	$RETT				;RETURN

XCH.1:	SKIPA	S1,.XCHU1(M)		;FIRST DEVICE FAILED
XCH.2:	MOVE	S1,.XCHU2(M)		;SECOND DEVICE FAILED
	$WTO	(<MDA data base update failure>,<Cannot find UCB for ^W/S1/>,,<$WTFLG(WT.SJI)>)
	$RETT				;RETURN

> ;END TOPS10 CONDITIONAL

	SUBTTL	D$DMDR - ROUTINE TO UNWIND AND DELETE AN MDR

	;CALL:	AP/ The MDR Address
	;
	;RET:	True Always

	;AC Usage:	AP/ MDR Entry
	;		P1/ VSL AOBJN AC

D$DMDR::PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	SKIPN	S1,.MRVSL(AP)		;CHECK AND LOAD THE FIRST VSL ADDRESS
	PJRST	DELMDR			;NONE THERE,,JUST DELETE THE MDR
	CAIN	S1,TMPVSL		;ARE WE POINTING TO THE TEMP VSL ???
	JRST	DELMDR			;YES,,JUST DELETE THE MDR AND RETURN

	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT

DMDR.1:	MOVE	S1,.MRVSL(AP)		;PICK UP THE CURRENT VSL ADDRESS
	PUSHJ	P,DELVSL		;GO DELETE IT
	SOJG	P1,DMDR.1		;CONTINUE THROUGH ALL VSL'S
	PUSHJ	P,DELMDR		;DELETE THIS MDR
	$RETT				;RETURN

	SUBTTL	D$IDEN - ROUTINE TO PROCESS THE IDENTIFY COMMAND

	;CALL:	M /The Identify Message Address
	;
	;RET:	True Always

TOPS10 <
D$IDEN::PUSHJ	P,.SAVE4		;SAVE SOME REGS
	MOVX	S1,.CMDEV		;GET THE DEVICE BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	E$IMO##			;NOT THERE,,THATS AN ERROR
	PUSHJ	P,LOCUCB		;GO FIND THE AFFECTED UCB
	JUMPF	D$ASGN			;NO UCB,,TRY REASSIGNMENT ANYWAY !!!
	MOVE	P1,S1			;SAVE POINTER TO UCB
	LOAD	S1,.UCBST(P1),UC.AVA	;GET THE AVAILABLE STATUS BIT
	SKIPN	S1			;IS THE DEVICE AVAILABLE ???
	 $ERJMP	MD$IUD			;NO,,RETURN ERROR

	;A Small Security Check Before We Start !!!

	SKIPN	P3,.UCBVL(P1)		;CHECK AND LOAD THE VOL BLOCK ADDRESS
	 $ERJMP	MD$NVM			;RETURN NO VOLUME MOUNTED ON DRIVE !!!
	LOAD	S1,.VLOWN(P3),VL.CNT	;GET THE VOLUME REQUEST COUNT
	LOAD	S2,.UCBST(P1),UC.VSW	;GET THE DEVICE VOLUME SWITCH STATUS
	SKIPE	S1			;CAN'T BE REQUESTED BY ANYONE
	JUMPN	S2,[$ERJMP MD$CIU]	;AND BE SWITCHING VOLS ON SAME DEVICE

	;Check for a VOLID Block and process it if there is one.

	MOVX	S1,.VOLID		;GET THE VOLID BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	IDEN.1			;NOT THERE,,CONTINUE ON
	HRROI	S1,0(S1)		;POINT TO THE ASCIZ VOLID
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	P4,S2			;SAVE THE NEW VOL ID FOR A MINUTE
	LOAD	S1,.UCBST(P1),UC.DVT	;GET DEVICE TYPE
	CAIE	S1,%DTAP		;DECTAPE?
	JRST	IDEN.0			;NO--MUST BE A MAGTAPE
	MOVE	S1,S2			;GET THE REELID IN S1
	PUSHJ	P,FNDECT		;SEE IF IT'S ALREADY IN OUR DATA BASE
	SKIPF				;NOT THERE,,CONTINUE ONWARD
	JUMPN	S2,.RETT		;IF FOUND AND MOUNTED,,JUST RETURN
	MOVE	S1,P3			;GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE VOLUME ???
	SKIPF				;NO,,SKIP
	 $ERJMP	MD$DAU			;YES,,CAN THE REQUEST
	MOVEM	P4,.VLNAM(P3)		;SAVE THE NEW REELID
	$ACK	(<Volume ^W/.VLNAM(P3)/ mounted>,,MDAOBJ,.MSCOD(M))
	$RETT				;ACK THE OPR AND RETURN

IDEN.0:	MOVE	S1,S2			;GET THE VOL ID IN S1
	PUSHJ	P,FNTAPE		;SEE IF IT'S ALREADY IN OUR DATA BASE
	SKIPF				;NOT THERE,,CONTINUE ONWARD
	JUMPN	S2,.RETT		;IF FOUND AND MOUNTED,,JUST RETURN
	MOVE	S1,P3			;GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE VOLUME ???
	SKIPF				;NO,,SKIP
	 $ERJMP	MD$DAU			;YES,,CAN THE REQUEST
	LOAD	S1,.VLFLG(P3),VL.LBT	;GET THE VOLUME LABEL TYPE
	PUSHJ	P,GETLBT		;RECODE IT TO SOMETHING UNDERSTANDABLE
	CAXN	S1,%LABEL		;IS THE VOLUME LABELED ???
	 $ERJMP	MD$VIL			;YES,,CAN'T DO THIS
	MOVEM	P4,.VLNAM(P3)		;SAVE THE NEW VOLUME ID
	$ACK	(<Unlabeled volume ^W/.VLNAM(P3)/ mounted>,,MDAOBJ,.MSCOD(M))
	$RETT				;ACK THE OPR AND RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

IDEN.1:	MOVX	S1,.ORREQ		;GET THE REQUEST-ID BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	E$IMO##			;NOT THERE,,THATS AN ERROR
	MOVE	S1,0(S1)		;LOAD THE USER REQUEST ID NUMBER
	PUSHJ	P,FNDVSL		;GET THE REQUESTED VSL ENTRY
	JUMPF	E$MRP##			;NOT THERE,,OPERATOR ERROR !!!
	MOVE	P4,S1			;SAVE THE VSL ADDRESS

	LOAD	S1,.VSFLG(P4),VS.ABO	;WAS IT CANCELLED ???
	JUMPN	S1,E$MRP##		;YES,,EXIT NOW
	LOAD	S1,.UCBST(P1),UC.VSW	;GET THE VOLUME SWITCH BIT
	SKIPE	S1			;NOT SWITCHING VOLS,,SKIP NEXT CHECK !!
	CAMN	P4,.UCBVS(P1)		;YES,,DOES THIS USER OWN THE DEVICE ???
	SKIPA				;NO VOL SWTCH OR USER OWNS IT,,CONTINUE
	 $ERJMP	MD$DAU			;UH OH,DEVICE IS IN USE BY SOMEONE ELSE

	LOAD	S2,.VSCVL(P4),VS.OFF	;GET OFFSET TO CURRENT VOLUME IN SET
	ADDI	S2,.VSVOL(P4)		;AIM AT THAT POINTER
	MOVE	P2,0(S2)		;GET ADDR OF THAT VOLUME BLOCK
	SKIPE	S1,.VLUCB(P2)		;IS THE REQUESTED VOLUME MOUNTED?
	CAMN	S1,P1			;YES, IS THE OPR DOING THE RIGHT THING?
	SKIPA				;NOT MOUNTED OR CORRECT DRIVE, SKIP
	 $ERJMP	MD$VND,P4		;OPR PICKED WRONG DRIVE.. TELL HIM
	MOVE	S1,P2			;GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE VOLUME ???
	SKIPF				;NO,,SKIP
	 $ERJMP	MD$VAU			;YES,,CAN THE REQUEST
;**;[1134]DELETE FIVE LINES AND IDN.1A LABEL AFTER IDEN.1:+27L	7-JUN-83/CTK
	MOVE	S1,P3			;[1134]GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE VOLUME ???
	SKIPF				;NO,,SKIP
	 $ERJMP	MD$DAU			;YES,,CAN THE REQUEST

	LOAD	S2,.VSFLG(P4),VS.LBT	;GET THE REQUESTED LABEL TYPE
	CAXN	S2,.TFLBP		;USER WANTS BYPASS?
	JRST	IDEN.3			;YES,,JUST GO REASSIGN THE VOLUME

;**;[1134]ADD FIVE LINES AFTER IDEN.1:+34L	7-JUN-83/CTK
	SKIPE	S1,.VLNAM(P3)		;[1134]DID THE OPR SPECIFY A VOLUME?
	SKIPN	S2,.VLNAM(P2)		;[1134]GET USER'S REELID
	 JRST	IDN.1A			;[1134]NO REELID OR SCRATCH
	CAME	S1,S2			;[1134]IS IT WHAT THE USER SPECIFIED
	 $ERJMP	MD$RDM,P4		;[1134]NO, GIVE ERROR

IDN.1A:	LOAD	S1,.VSFLG(P4),VS.TYP	;GET REQUEST TYPE
	CAIE	S1,%TAPE		;MAGTAPE?
	JRST	IDEN.2			;NO--MUST BE DECTAPE
	LOAD	S1,.VLFLG(P3),VL.LBT	;[1134]GET VOLUME'S LABEL TYPE
	PUSHJ	P,GETLBT		;GET EASY CODE
	CAXE	S1,%LABEL		;IS THE MOUNTED VOLUME LABELED?
	JRST	IDEN.2			;NO,,CHECK VOLIDS
	LOAD	S1,.VLFLG(P2),VL.SCR	;YES,,GET THE VOLUME'S SCRATCH BIT
	JUMPE	S1,[$ERJMP MD$VIL,P4]	;CAN'T HAVE LABELS & NOT BE SCRATCH

IDEN.2:	SKIPN	.VLNAM(P2)		;REQUESTED VOL MUST HAVE A NAME !!
	SKIPE	.VLNAM(P3)		; OR ELSE MOUNTED VOL MUST HAVE A NAME
	SKIPA				;YES TO EITHER,,WIN !!
	 $ERJMP	MD$NVI,P4		;BOTH NULL,,CAN'T DO THIS !!!

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

IDEN.3:	DMOVE	S1,P3			;GET THE VOL AND VSL ADDRESSES
	PUSHJ	P,CVLVSL		;CHECK THE REQUESTED CHARACTERISTICS
	JUMPF	.RETF			;NO GOOD,,JUST RETURN

	;Found a matching volume - there may be a VOL block off the VSL from
	;the requesting MDR, and another from the UCB for the mounted volume.
	;If so, we will have to merge them together, and throw one away.

	CAIN	P2,0(P3)		;ARE OLD AND NEW VOL'S THE SAME ???
	JRST	IDEN.4			;YES,,DONT DELETE ANY - JUST CONTINUE
	MOVE	T1,.VLFLG(P2)		;SAVE THE OLD FLAG BITS (JUST IN CASE)
	LOAD	S1,.VLFLG(P3),VL.FLG	;GET ALL THE FLAGS FOR THIS UNIT'S VOL
	STORE	S1,.VLFLG(P2),VL.FLG	;SAVE IN REAL VOL BLOCK
	MOVE	S1,.VLNAM(P3)		;GET VOL NAME FOR THIS UNITS VOL BLK
	SKIPE	.VLNAM(P2)		;IS THERE A NAME IN THE USERS VOL BLOCK
	JRST	IDN.3A			;YES,,NO NEED TO ALLOCATE THE NEW ONE !!

	;Update the VOL volid and allocate it

	MOVEM	S1,.VLNAM(P2)		;NO,,SAVE UNITS VOLID AS USERS VOLID
	MOVE	S1,P4			;GET THE VSL ADDRESS
	PUSHJ	P,CKTVOL		;VALIDATE THIS VOLID FOR THIS USER
	JUMPF	[SETZM .VLNAM(P2)	;NO GOOD,,BACK TO SCRATCH
	 	 MOVEM T1,.VLFLG(P2)	;RESTORE THE OLD FLAG BITS
		 $RETF ]		;AND RETURN
	PUSHJ	P,D$BMTX		;LOCATE THIS GUYS 'B' MATRIX ENTRY
	MOVE	S1,P2			;GET THE VOL ADDRESS
	PUSHJ	P,D$TVRS		;CONVERT TO A RESOURCE NUMBER
	MOVE	S2,P4			;GET THE VSL ADDRESS
	PUSHJ	P,ADDBMA		;UPDATE THE USERS 'B' MATRIX

IDN.3A:	MOVX	S1,VL.SCR		;GET THE SCRATCH VOLUME BIT
	ANDCAM	S1,.VLFLG(P2)		;  AND CLEAR IT 
	MOVE	S1,P3			;GET THE VOL BLK WE WANT TO DELETE
	PUSHJ	P,DELVOL		;GO DELETE IT
	MOVEM	P2,.UCBVL(P1)		;LINK THE USERS VOL TO THE UCB
	MOVEM	P1,.VLUCB(P2)		;LINK THE UCB TO THE USERS VOL

IDEN.4:	LOAD	S1,.VSFLG(P4),VS.LBT	;GET THE VOLUME SET LABEL TYPE
	STORE	S1,.VLFLG(P2),VL.LBT	;SAVE AS THE VOLUME LABEL TYPE

	;Check to make sure there is no deadlock

	MOVE	S1,P4			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,D$ALCT		;ALLOCATE/DEADLOCK CHECK THE VSL
	JUMPF	.RETF			;NO GOOD,,OH WELL WE TRIED !!!!!

	;So far so good, go off and reassign the tape

	MOVE	S1,P1			;AIM AT THIS UCB
	MOVE	S2,P4			;AND THIS VSL
	PUSHJ	P,REASSI		;TRY TO REASSIGN THE DEVICE
	JUMPF	.RETT			;CAN'T,,RETURN
	MOVE	S1,P4			;OK,,GET THE VSL ADDRESS BACK
	PUSHJ	P,MNTVSL		;TRY TO MOUNT OTHER VOLS
	$RETT				;AND RETURN
>;END TOPS10
	SUBTTL	REASSIGN - Try to give a unit to a user

	;CALL:	S1/ The UCB Address
	;	S2/ The VSL Address
	;	AP/ The MDR Address
	;
	;RET:	True - The device was reassigned with the specified logical name
	;       False - The device is owned, the Volume is owned,
	;		or he has Conflicting logical names

REASSI:
TOPS10<	PUSHJ	P,.SAVE4		;SAVE SOME REGS
	$SAVE	<T1,T2>			;SAVE T1 AND T2 ALSO
;**;[1164] Add some code to check or reinit'ing
	MOVE	T1,.VSFLG(S2)		;[1164] GET VSL FLAGS
	TXNE	T1,VS.INI		;[1164] REINIT'ING?
	$RETF				;[1164] YES,,RETURN
	TXNN	T1,VS.NEW		;[1164] VSL NEED REINIT'ING?
	JRST	REAS.A			;[1164] NO,,TRY REASSIGNMENT
	PUSHJ	P,REINIT		;[1164] YES,,GO SEND REINIT MSG TO PULSAR
	$RETF				;[1164] RETURN

REAS.A:	DMOVE	P1,S1			;[1164] GET THE UCB IN P1, VSL IN P2
	MOVE	S1,.UCBNM(P1)		;GET THE DEIVCE NAME IN S1
	MOVEM	S1,MDAOBJ+OBJ.UN	;SAVE AS THE CURRENT UNIT
	LOAD	P3,.VSCVL(P2),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	P3,.VSVOL(P2)		;POINT TO THE CURRENT VOL ADDRESS
	MOVE	P3,0(P3)		;GET THE VOLUME ADDRESS
	MOVX	T1,%STAMN		;GET 'VOLUME MOUNTED' STATUS CODE
	STORE	T1,.VLFLG(P3),VL.STA	;SET IT IN THE VOLUME FLAG WORD
	MOVE	P4,.VSUCB(P2)		;GET THE OLD UNIT ADDRESS
	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,SETOWN		;UPDATE VOLUME OWNERSHIP
	LOAD	S2,.VSFLG(P2),VS.VSW	;IS THIS GUY IN VOLUME SWITCH MODE ???
	JUMPN	S2,REAS.S		;YES, THEN SWITCH UNITS
	MOVX	S1,VL.SRD		;GET SET REQUESTED DENSITY FOR USER BIT
	TDNN	S1,.VLFLG(P3)		;NEED TO DO IT?
	JRST	REAS.0			;NOPE
	MOVE	S1,.UCBNM(P1)		;GET DEVICE NAME
	LOAD	S2,.VSATR(P2),VS.DEN	;GET THE REQUESTED DENSITY
	PUSHJ	P,I$SDEN##		;SET IT
	JUMPT	REAS.0			;ONWARD
	MOVEI	S1,[ITEXT (<Can't set density to ^T/@DENSTY(S2)/ on unit ^W/.UCBNM(P1)/>)]
	LOAD	S2,.VLFLG(P3),VL.DEN	;GET THE REQUESTED DENSITY AGAIN
	JRST	REAS.E			;PROCESS ERROR

REAS.0:	LOAD	S2,.MRJOB(AP),MR.JOB	;GET THE USERS JOB NUMBER
	TXNE	S2,BA%JOB		;FOR A PSEUDO PROCESS ???
	JRST	REAS.3			;YES,,SKIP THE REST OF THIS !!

REAS.1:	LOAD	S1,.UCBST(P1),UC.DVT	;GET DEVICE TYPE
	CAIE	S1,%DTAP		;DECTAPE?
	JRST	REAS.4			;NO--MUST BE A MAGTAPE
	$COUNT	(DTAM)			;COUNT DECTAPE MOUNTS
	JRST	REAS.5			;ONWARD

REAS.4:	$COUNT	(TAPM)			;COUNT TAPE MOUNTS (NOT VOL SWITCHES)
	MOVE	S1,.UCBNM(P1)		;[1224]GET DEVICE NAME
	LOAD	S2,.VSFLG(P2),VS.LBT	;[1224]GET THE REQUESTED LABEL TYPE
	PUSHJ	P,I$SLBT##		;[1224]SET IT

REAS.5:	MOVE	S1,.UCBNM(P1)		;MAKE SURE DVCMDA IS TURNED
	PUSHJ	P,I$MDAS##		; ON SO WE GET DEASSIGN MESSAGES
	MOVE	T2,.VSLNM(P2)		;GET THE LOGICAL NAME IN T2
	MOVE	T1,.UCBNM(P1)		;GET THE DEVICE NAME IN T1
	DEVLNM	T1,			;ASSIGN A LOGICAL NAME
	STOPCD	(LNA,HALT,,<Logical name assignment failed>)
	LOAD	T1,.MRJOB(AP),MD.PJB	;GET THE JOB NUMBER IN T1
	MOVE	T2,.UCBNM(P1)		;GET THE DEVICE NAME IN T2
	REASSI	T1,			;REASSIGN THE DEVICE TO THE USER
	JUMPLE	T1,REAS.2		;FAILED,,RETURN NO GOOD
	MOVEM	T2,MDAOBJ+OBJ.UN	;SAVE THE DEVICE NAME FOR LATER
	MOVEM	P1,.VSUCB(P2)		;LINK THE UCB TO THIS USER
	MOVEM	P2,.UCBVS(P1)		;LINK THIS USER TO THIS DEVICE
	MOVX	S1,VS.DDN+VS.DTK	;GET DEFAULT DENSITY+TRACK STATUS BITS
	ANDCAM	S1,.VSATR(P2)		;CLEAR THEM - NO MORE DEFAULTING !!!!!
	MOVE	S1,P2			;GET THE VSL ADDRESS
	PUSHJ	P,I$TMNT##		;PERFORM TAPE ACCOUNTING
	MOVE	S1,P2			;AIM AT THE VOLUME SET LIST
	PUSHJ	P,LBLNOT		;TELL THE LABEL PROCESSOR OF THE CHANGE
	$WTO	(<Volume ^W/.VLNAM(P3)/ reassigned>,<^I/DEMOT/>,MDAOBJ)
	$RETT				;AND RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

REAS.2:	SKIPE	.VSLNM(P2)		;ANY LOGICAL NAME ???
	JRST	[SETZM .VSLNM(P2)	;YES,,ZAP IT
		 JRST  REAS.1 ]		;AND RETRY THE REASSIGN
;**;[1224] ADD 3 LINES AT REAS.2+1L	13-AUG-84 /DPM
	MOVE	S1,.UCBNM(P1)		;[1224]GET DEVICE NAME
	LOAD	S2,.VLFLG(P3),VL.LBT	;[1224]GET THE VOLUME LABEL TYPE
	PUSHJ	P,I$SLBT##		;[1224]RESET IT
	MOVE	S1,P2			;NO,,GET THE VSL ADDRESS
	PUSHJ	P,CLROWN		;CLEAR THE OWNERSHIP STATUS
	MOVX	S1,%STAWT		;GET WAITING STATUS
	STORE	S1,.VLFLG(P3),VL.STA	;SET IT
	MOVEI	S1,[ITEXT (<REASSI UUO failed on volume ^W/.VLNAM(P3)/>)]

REAS.E:	$WTO	(<Reassignment failure>,<^I/(S1)/ for ^I/DEMOT/>,MDAOBJ)
	$TEXT	(<-1,,G$MSG>,<^I/(S1)/, request deleted^M^J^0>)
	SETOM	ERRACK			;THIS IS AN ERROR
	MOVE	S1,P2			;[1173] COPY VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;TELL THE USER
	MOVE	S1,P2			;NO GOOD,,GET THE VSL ADDRESS
	PUSHJ	P,ALCVSL		;RETURN THIS VSL TO THE ALLOCATION POOL
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE USERS REQUEST COUNT
	SKIPN	S1			;STILL MORE REQUESTS,,SKIP
	PUSHJ	P,DELMDR		;NOTHING LEFT,,DELETE THE MDR
	$RETF				;AND RETURN 'REASSIGN FAILED'

REAS.3:	DOSCHD				;FORCE A SCHEDULING PASS
	MOVX	S1,VS.NMT		;GET THE 'NOT REALLY MOUNTED' FLAG BIT
	IORM	S1,.VSFLG(P2)		;SET IT FOR THIS PSEUDO PROCESS
	MOVE	S1,.MRQEA(AP)		;GET THE QE ADDRESS
	MOVX	S2,QE.WAM		;GET 'WAITING FOR MOUNT' STATUS
	ANDCAM	S2,.QESEQ(S1)		;AND CLEAR IT
	MOVEM	P1,.VSUCB(P2)		;LINK THE UCB TO THIS USER
	MOVEM	P2,.UCBVS(P1)		;LINK THIS USER TO THIS DEVICE
	MOVE	S1,.QERID(S1)		;GET ITS REQUEST ID
	$WTO	(<Volume ^W/.VLNAM(P3)/ reassigned>,<User: ^W6/.MRNAM(AP)/^W/.MRNAM+1(AP)/ ^U/.MRUSR(AP)/ batch request #^D/S1/>,MDAOBJ)
	$RETT				;RETURN
	SUBTTL	REAS.S - Routine to Perform Volume Switch Processing

	;CALL:	P1/ New UCB addr
	;	P2/ VSL addr
	;	P3/ VOL addr
	;	P4/ Old UCB Addr
	;	AP/ MDR

REAS.S:	$COUNT	(VSWM)			;count volume switches
	STORE	P1,.VSUCB(P2)		;LINK THE UCB TO THIS USER
	SETZM	.UCBVS(P4)		;AND THE OLD UNIT ISN'T TIED UP...
	STORE	P2,.UCBVS(P1)		;LINK THIS USER TO THIS DEVICE
	ZERO	.UCBST(P4),UC.VSW	;...WAITING FOR VOLUME SWITCH
	ZERO	.VSFLG(P2),VS.VSW	;...AND VSL ISN'T SWITCHING, EITHER
	MOVX	S1,.QOVSD		;VOLUME SWITCH DIRECTIVE BLOCK
	PUSHJ	P,LBLHDR		;START THE MESSAGE

;Build the First Block, Describing the Units Involved

	AOS	G$MSG+.OARGC		;ONE MORE BLOCK
	MOVEI	S2,G$MSG+.OHDRS		;AIM AT THE FIRST BLOCK SPACE
	MOVX	S1,.VSDBL		;BLOCK TYPE - DEVICES
	STORE	S1,ARG.HD(S2),AR.TYP	;SET IN BLOCK
	MOVX	S1,ARG.DA+VSDLEN	;SIZE OF THE BLOCK
	STORE	S1,ARG.HD(S2),AR.LEN	;LENGTH OF THIS ONE
	ADDI	S2,ARG.DA		;POINT AT THE DATA
	ADDM	S1,G$SAB##+SAB.LN	;AND SEND LENGTH, TOO
	MOVSS	S1			;TO LH
	ADDM	S1,G$MSG+.MSTYP		;UPDATE MESSAGE LENGTH
	LOAD	S1,.UCBNM(P4)		;GET OLD UNIT NAME
	STORE	S1,.VSDID(S2)		;SAVE IN MESSAGE
	LOAD	S1,.UCBNM(P1)		;GET NEW UNIT NAME
	STORE	S1,.VSDCD(S2)		;SAVE AS NEW UNIT NAME
	ADDI	S2,VSDLEN		;UPDATE POINTER PAST BLOCK

;Build the Second Block, Describing the Volume Set and User who Owns The Drive

	AOS	G$MSG+.OARGC		;ONE MORE BLOCK
	MOVX	S1,.VOLMN		;GET THE NEXT BLOCK TYPE
	STORE	S1,ARG.HD(S2),AR.TYP	;SAVE AS BLOCK TYPE
	MOVX	S1,.VMNSZ+ARG.DA	;GET THE LENGTH OF THE BLOCK
	STORE	S1,ARG.HD(S2),AR.LEN	;AND SAVE IN BLOCK HEADER
	ADDM	S1,G$SAB+SAB.LN		;UPDATE SEND LENGTH
	MOVSS	S1			;GET TO  LH
	ADDM	S1,G$MSG+.MSTYP		;UPDATE TOTAL MESSAGE LENGTH
	MOVEI	S2,ARG.DA(S2)		;AIM AT THE DATA PORTION OF THE BLOCK
	LOAD	S1,.VLNAM(P3)		;GET THE VOLUME NAME
	STORE	S1,.VMNIV(S2)		;SAVE AS INITIAL VOLUME NAME

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	MOVEI	S1,.VSVOL(P2)		;AIM AT THE FIRST VOLUME BLOCK ADR
	MOVE	S1,(S1)			;GET THE ADR OF THE FIRST VOL BLOCK
	LOAD	S1,.VLNAM(S1)		;GET THE NAME OF THE FIRST VOLUME
	STORE	S1,.VMNFV(S2)		;SAVE IN MESSAGE TO LABELLER
	LOAD	S1,.VSFLG(P2),VS.LBT	;GET THE LABEL TYPE
	STORE	S1,.VMNIN(S2),VI.LTY	;SAVE IN MESSAGE
	LOAD	S1,.VSFLG(P2),VS.WLK	;GET THE WRITE LOCK BIT
	STORE	S1,.VMNIN(S2),VI.WLK	;SAVE IN INFO WORD OF MESSAGE
	LOAD	S1,.MRJOB(AP),MD.PJB	;GET THE JOB NUMBER
	STORE	S1,.VMNIN(S2),VI.JOB	;TEL THE LABELLER WHO'S THERE

;**;[1136]ADD 7 LINES AND CHANGE 1 LINE AT REAS.S:+65L 11-NOV-82/NT

	;Here to make sure the density is set correctly

	LOAD	S1,.VLFLG(P3),VL.DEN	;[1136]GET THE DENSITY FOR THIS VOLUME
	LOAD	S2,.VSATR(P2),VS.DEN	;[1136]GET DENSITY CODE FOR VOL SET
	CAMN	S1,S2			;[1136]ARE THEY THE SAME ??
	  JRST	REA.S0			;[1136]YES, NO NEED TO SET IT THEN
	STORE 	S2,.VLFLG(P3),VL.DEN	;[1136]STORE IT AWAY FOR NEXT TIME
	LOAD	S1,.UCBNM(P1)		;[1136]GET THE NAME OF THE DRIVE
	PUSHJ	P,I$SDEN##		;[1136]SET IT

	;Tell everyone about it

REA.S0:	PUSHJ	P,C$SEND##		;[1136]TELL THE LABELLER
	MOVE	S1,P2			;GET THE VSL ADDRESS
	PUSHJ	P,I$TMNT##		;PERFORM TAPE ACCOUNTING
	$WTO	(<Volume ^W/.VLNAM(P3)/ reassigned>,<^I/DEMOT/>,MDAOBJ)
	$TEXT	(<-1,,G$MSG>,<Logical name ^W/.VSLNM(P2)/ switched to volume ^W/.VLNAM(P3)/ on ^W/.UCBNM(P1)/^M^J^0>)
	MOVE	S1,P2			;NOTIFY [SYSTEM]CATALOG OF THE
	PUSHJ	P,V$EXTV##		; VOLUME-SET EXTENSION
	MOVE	S1,P2			;[1173] GET VSL ADDRESS
	SETZM	S2			;[1173] USE VSL ACK DATA
	PUSHJ	P,USRNOT		;TELL THE USER, IF INTERESTED
	MOVE	S1,P4			;GET TO THE OLD UNIT
	PUSHJ	P,MATUNI		;TRY TO GIVE IT AWAY
	$RETF				;RETURN FALSE IN ANY CASE
>
TOPS20<	$RETT	>			;REASSIGN FAILS ON THE -20
	SUBTTL	D$ASGN - ROUTINE TO ASSIGN FOREIGN DEVICES UNDER MDA

	;CALL:	M/ The IDENTIFY Message Address
	;
	;RET:	True Always

TOPS10<
D$ASGN:	PUSHJ	P,.SAVE3		;SAVE P1 AND P2 AND P3
	MOVX	S1,.CMDEV		;GET THE DEVICE BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND THE DEVICE BLOCK
	HRROI	S1,0(S1)		;POINT TO THE ASCIZ DEVICE NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	DEVNAM	S2,			;IS IT VALID ???
	 JRST	[MOVEI S1,[ASCIZ/Unknown device specified/] ;NO,,GET ERROR TEXT
		 JRST  ASGN.3 ]		;AND EXIT
	MOVEM	S2,MDAOBJ+OBJ.UN	;SAVE THE DEVICE NAME
	MOVE	S1,S2			;S1:= DEVICE NAME
	PUSHJ	P,I$CKAV##		;IS IT FREE ?
	  JUMPT	[MOVEI S1,[ASCIZ/Device not available/] ;NO
		 JRST  ASGN.3 ]		;EXIT
	MOVE	S2,MDAOBJ+OBJ.UN	;GET THE DEVICE
	DEVTYP	S2,			;GET ITS CHARACTERISTICS
	  JRST	[MOVEI S1,[ASCIZ/Unknown device specified/] ;CAN'T
		 JRST  ASGN.3 ]		;EXIT
	LOAD	P1,S2,TY.DEV		;SAVE THE DEVICE TYPE
	MOVX	S1,.ORREQ		;GET THE REQUEST ID BLOCK TYPE
	PUSHJ	P,A$FNDB##		;GET THE REQUEST TO ASSIGN TO
	JUMPF	[MOVEI S1,[ASCIZ/Request ID must be specified/] ;NOT THERE
		 JRST  ASGN.3 ]		;GET ERROR TEXT AND EXIT
	MOVE	S1,0(S1)		;GET THE REQUEST ID
	PUSHJ	P,FNDVSL		;FIND THE USER
	JUMPF	[MOVEI S1,[ASCIZ/Invalid request ID specified/] ;NOT THERE
		 JRST  ASGN.3 ]		;GET ERROR TEXT AND EXIT
	MOVE	P2,S1			;SAVE THE VSL ADDRESS
	LOAD	S1,.VSFLG(P2),VS.TYP	;GET THE REQUEST TYPE
	CAXE	S1,%UNKN		;S IS 'UNKNOWN' ?
	JRST	[MOVEI S1,[ASCIZ/User requested disk, magtape, or DECtape volumes/]
		 JRST  ASGN.3 ]		;GET ERROR TEXT AND EXIT
	HRROI	S1,.VSVSN(P2)		;GEN POINTER TO VOL SET NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	DEVTYP	S2,			;GET THE REQUESTED DEVICE TYPE
	 SKIPA	S2,P1			;ON ERROR FORCE A MATCH !!!
	LOAD	S2,S2,TY.DEV		;GET THE DEVICE TYPE
	CAME	S2,P1			;DOES REQUESTED MATCH IDENTIFIED ???
	 JRST	[MOVEI S1,[ASCIZ/Specified device does not match requested device/]
		 JRST  ASGN.3 ]		;NO,,GET ERROR TEXT AND EXIT
	MOVE	S1,MDAOBJ+OBJ.UN	;GET THE DEVICE NAME
	PUSHJ	P,I$MDAS##		;SET THE MDA BIT (DVCMDA)
ASGN.1:	MOVE	S1,MDAOBJ+OBJ.UN	;GET THE DEVICE NAME
	MOVE	S2,.VSLNM(P2)		;GET THE LOGICAL NAME
	DEVLNM	S1,			;ASSIGN A LOGICAL NAME TO THE DEVICE
	JFCL				;IGNORE THE ERROR

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	LOAD	S1,.MRJOB(AP),MD.PJB	;GET THE USERS JOB NUMBER
	MOVE	S2,MDAOBJ+OBJ.UN	;GET THE DEVICE NAME
	REASSI	S1,			;ASSIGN IT TO THE USER
	JUMPLE	S1,ASGN.2		;IF IT FAILED,,PROCESS THE ERROR
	$COUNT	(GENM)			;count generic mounts
	$ACK	(<Reassigned>,<^I/DEMOT/>,MDAOBJ,.MSCOD(M)) ;TELL THE OPR
	MOVE	S1,P2			;GET THE VSL ADDRESS
	PUSHJ	P,SETOWN		;SET SOME OWNERSHIP BITS
	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%LAST		;POSITION TO THE LAST ENTRY
	MOVX	S2,UCBLEN		;GET THE UCB LENGTH
	PUSHJ	P,L%CENT		;CREATE A UCB FOR THIS DEVICE
	MOVEM	S2,.VSUCB(P2)		;LINK THE UCB TO THE VSL
	MOVEM	P2,.UCBVS(S2)		;LINK THE VSL TO THE UCB
	MOVE	S1,MDAOBJ+OBJ.UN	;GET THE DEVICE NAME
	MOVEM	S1,.UCBNM(S2)		;SAVE IT
	PUSHJ	P,ASGN.A		;ACK THE USER AND GET NEXT VSL
	MOVE	P1,S1			;SAVE THE NEXT MOUNT VSL ADDRESS
	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	LOAD	TF,.VSFLG(P2),VS.TYP	;GET THE REQUEST TYPE
	CAXN	TF,%DTAP		;A DECTAPE ?
	PUSHJ	P,I$DMNT##		;YES - MAKE ACCOUNTING ENTRY
	MOVX	S2,VS.WAL		;GET THE WAITING FOR ALLOCATION STATUS
	IORM	S2,.VSFLG(P2)		;LITE IT (WE NEVER WERE ALLOCATED)
	SKIPE	S1,P1			;ANY MORE REQUESTS ???
	PUSHJ	P,MNTVSL		;YES,,TRY TO MOUNT THEM
	$RETT				;RETURN

	;Here if the reassignment fails

ASGN.2:	SKIPE	.VSLNM(P2)		;ANY LOGICAL NAME ???
	JRST	[SETZM .VSLNM(P2)	;YES,,ZAP IT
		 JRST  ASGN.1 ]		;AND RETRY THE REASSIGNMENT
	$ACK	(<Reassignment failure>,<Can't reassign device to ^I/DEMOT/>,MDAOBJ,.MSCOD(M))
	MOVEI	S1,[ITEXT (<Reassignment failed - request deleted>)]
	SETOM	ERRACK			;LITE ERROR ACK FLAG
	PUSHJ	P,ASGN.A		;ACK THE USER AND GET NEXT VSL
	MOVE	P1,S1			;SAVE THE NEXT VSL ADDRESS
	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,DELVSL		;DELETE THIS REQUEST
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET HIS REQUEST COUNT
	JUMPE	S1,DELMDR		;IF NO MORE REQUESTS,,DELETE THE MDR
	SKIPE	S1,P1			;ANY MORE REQUESTS ???
	PUSHJ 	P,MNTVSL		;YES,,TRY TO MOUNT THEM
	$RETT				;RETURN

ASGN.3:	$ACK (<Can't identyfy this device>,<^T/0(S1)/>,MDAOBJ,.MSCOD(M))
	$RETT				;RETURN

	;Here to ACK the user and find the next mount request

ASGN.A:	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE USERS REQUEST COUNT
	MOVNS	P1			;NEGATE IT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.MRVSL(AP)		;CREATE VSL AOBJN SEARCH AC
	LOAD	S2,.VSLNK(P2),VS.LNK	;GET THIS REQUESTS LINK CODE

ASGN.B:	MOVE	P3,0(P1)		;GET A VSL ADDRESS
	LOAD	S1,.VSLNK(P3),VS.LNK	;GET ITS LINK CODE
	CAME	P3,P2			;IS THIS THE CURRENT VSL ???
	CAME	S1,S2			;NO,,DO LINK CODES MATCH ???
	AOBJN	P1,ASGN.B		;CURRENT VSL OR NO MATCH,,TRY NEXT
	MOVE	S1,P2			;GET THE VSL ADDRESS
	PUSHJ	P,ACKUSR		;ACK THE USER
	SKIPL	P1			;DID WE FIND A MATCH ???
	SETZM	P3			;NO,,CLEAR THE LAST VSL ADDRESS
	MOVE	S1,P3			;RETURN NEXT VSL ADDRESS
	$RETT				;RETURN

> ;END TOPS10 CONDITIONAL
	SUBTTL	D$ENAB/D$DISA - DRIVE AVR STATUS

	;CALL:	M/ The Enable/Disable Message Address
	;
	;The following cases for enable/disable can occur:
	;	.TAPDV	A particular tape/disk drive - change AVR
	;	.ALTAP	All tape drives - change AVR
	;	.ALDSK	All disk drives - change AVR
	;	.ALSTR	Change automatic structure recognition
	;		(defaults if all others fail)
	;
	;RET: True Always

TOPS10 <
D$ENAB::TDZA  S1,S1			;INDICATE 'ENABLE' ENTRY POINT
D$DISA::SETOM S1			;INDICATE 'DISABLE' ENTRY POINT
	PUSHJ	P,.SAVE2		;SAVE P1 AND P2 FOR A MINUTE
	MOVE	P1,S1			;SAVE THE ENTRY POINT INDICATOR IN P1

	MOVX	S1,.TAPDV		;GET DRIVE BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN OUR MESSAGE
	JUMPT	ABLE.0			;Found specific unit, go process it

	MOVX	S1,.ALTAP		;GET ALL TAPE DRIVE MSG BLOCK
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPT	ABLE.1			;FOUND IT,,GO SET ALL TAPE DRIVES

	MOVX	S1,.ALDSK		;Get all disk drive msg block
	PUSHJ	P,A$FNDB##		;Find it in the message
	JUMPT	ABLE.2			;Go process it

	;Fall through assuming .ALSTR

	;Here to Enable/Disable Automatic Structure Recognition

	SKIPN	P1			;IS THIS AN ENABLE FUNCTION ???
	SETOM	D$ASR			;YES,,LITE THE ASR FLAG
	SKIPE	P1			;IS THIS A DISABLE FUNCTION ???
	SETZM	D$ASR			;YES,,CLEAR THE ASR FLAG
	$ACK	(<Structure recognition is ^T/@DISENA+1(P1)/>,,,.MSCOD(M))
	$RETT				;RETURN

	;Here to Enable/Disable Automatic Volume Recognition for a unit

ABLE.0:	PUSHJ	P,LOCUCB		;GO FIND THE AFFECTED UCB
	JUMPF	.RETF			;NOT THERE,,DEVICE DOES NOT EXIST !!!
	MOVX	S2,UC.AVR		;GET THE AVR BIT IN S1
	SKIPN	P1			;IS THIS 'ENABLE' ???
	IORM	S2,.UCBST(S1)		;YES,,LITE THE AVR BIT
	SKIPE	P1			;OR IS THIS 'DISABLE' ???
	ANDCAM	S2,.UCBST(S1)		;YES,,CLEAR THE AVR BIT
	$ACK	(<Volume recognition is ^T/@DISENA+1(P1)/>,,MDAOBJ,.MSCOD(M))
	$RETT				;ACK THE OPERATOR AND RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here to Enable/Disable Automatic Volume Recognition for all units

ABLE.1:	TDZA	P2,P2			;Indicate all tapes
ABLE.2:	SETOM	P2			;Indicate all disks
	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST ENTRY
ABLE.3:	LOAD	S1,.UCBST(S2),UC.DVT	;Get the device type
	CAIN	S1,%TAPE		;Is it a tape?
	JUMPE	P2,ABLE.4		;Yes, do we want tapes?
	CAIN	S1,%DISK		;No, is it a disk?
	JUMPL	P2,ABLE.4		;Yes, do we want disks?
	JRST	ABLE.5			;No, don't like this one
ABLE.4:	MOVX	S1,UC.AVR		;GET THE AVR BIT IN S1
	SKIPN	P1			;IS THIS 'ENABLE' ???
	IORM	S1,.UCBST(S2)		;YES,,LITE THE AVR BIT
	SKIPE	P1			;OR IS THIS 'DISABLE' ???
	ANDCAM	S1,.UCBST(S2)		;YES,,CLEAR THE AVR BIT

ABLE.5:	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT UCB ENTRY
	JUMPT	ABLE.3			;FOUND ONE,,GO PROCESS IT

	MOVEI	S1,[ASCIZ/tape drives/]	;DEFAULT TO TAPE DRIVES
	SKIPE	P2			;UNLESS IT WAS DISK DRIVES
	MOVEI	S1,[ASCIZ/disk drives/]	;   THEN MAKE IT DISKS
	$ACK	(<Volume recognition is ^T/@DISENA+1(P1)/ for all ^T/0(S1)/>,,,.MSCOD(M))
	$RETT				;ACK THE OPERATOR AND RETURN

DISENA:	[ASCIZ/Disabled/]
	[ASCIZ/Enabled/]
>

	SUBTTL	D$RECO - PROCESS THE OPR RECOGNIZE COMMAND

	;CALL:	M/ The Recognize Message Address
	;
	;RET:	True Always

TOPS10 <
D$RECO::PUSHJ	P,.SAVE2		;[1204] SAVE P1 & P2  FOR A MINUTE
	MOVX	S1,.TAPDV		;GET THE TAPE DEVICE NAME BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	E$IMO##			;NOT THERE,,THATS AN ERROR
	PUSHJ	P,FNDUCB		;FIND THE AFFECTED UCB
	JUMPF	.RETF			;NOT THERE,,THATS AN ERROR

	SKIPN	P1,.UCBVL(S1)		;[1204] GET VOL BLOCK ADDRES
	JRST	RECO.1			;[1204] NONE THERE
	LOAD	P2,.VLFLG(P1),VL.STA	;[1204] GET THE STATUS
	CAXE	P2,%STADM		;[1204] WAITING TO DISMOUNT?
	JRST	RECO.1			;[1204] NO,,LET PULSAR SNIFF ON IT
	$ACK	(<Structure ^W/.VLNAM(P1)/ is dismounting from ^W/S2/>,,,.MSCOD(M),<$WTFLG(WT.SJI)>) ;[1204]
	$RETT				;[1204] RETURN
RECO.1:	MOVE	S1,S2			;[1204] GET THE DEVICE CHECKED AGAINST
	PJRST	SNDREC			;   AND SEND THE RECOGNIZE MESSAGE TO
					;   THE TAPE LABELER
>
	SUBTTL	D$AVR - TAPE/DISK ONLINE PROCESSOR

	;CALL:	M/ The TAPE/DISK Online Message Address
	;
	;RET:	True Always


	;This routine fields Tape/Disk Online IPCF Messages from the
	;monitor and possibly kicks the Tape Label Processor to read the
	;labels from the volume mounted on the unit and send the Info 
	;back to QUASAR


TOPS10 <
D$AVR::	LOAD	S1,.TONST(M),TON.TY	;GET DEVICE TYPE FROM MESSAGE
	CAXE	S1,.TYDSK		;IS IT A DISK ONLINE MESSAGE ???
	CAXN	S1,.TYMTA		;OR IS IT A MAGTAPE?
	SKIPA				;YES,,GO PROCESS IT
	$RETT				;ELSE IGNORE IT

	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVE	S1,.TONDV(M)		;GET DEVICE NAME
	PUSHJ	P,UCBLOC		;FIND OUR UCB BLOCK ON THIS GUY
	JUMPF	.RETT			;STRANGE, MONITOR IS FUNNY
	LOAD	S2,.UCBST(S1),UC.AVA	;IS IT AVAILABLE ???
	JUMPE	S2,.RETT		;NO,,RETURN NOW
	MOVE	S2,S1			;SAVE UCB ADR
	MOVX	S1,UC.AVR		;GET AVR ENABLED BIT
	TDNE	S1,.UCBST(S2)		;IS THIS DRIVE ENABLED?
	SKIPA				;AVR OR DRIVE OWNED,,LETERRIP
	JRST	AVR.2			;NO,,GO FINISH UP
	LOAD	S1,.UCBST(S2),UC.DVT	;GET THE UNIT TYPE
	CAXN	S1,%DISK		;IS IT A DISK UNIT ???
	JRST	AVR.1			;YES,,JUST READ THE LABELS

	SKIPN	P1,.UCBVL(S2)		;GET ATTACHED VOLUME BLOCK, IF ANY
	JRST	AVR.1			;NO VOLUME, GO READ THE LABELS
	MOVE	S1,P1			;GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE VOLUME ???
	JUMPF	AVR.1			;NO,,READ THE LABELS (AGAIN)
	LOAD	S1,.VLFLG(P1),VL.LBT	;IT IS OWNED, GET LABEL TYPE
	CAXN	S1,.TFLBP		;IS IT A BYPASS LABEL TAPE?
	$RETT				;YES, LEAVE IT ALL UP TO THE USER

AVR.1:	MOVE	S1,.TONDV(M)		;GET DEVICE NAME SUPPLIED IN MESSAGE
	PJRST	SNDREC			;AND ASK PULSAR FOR SERVICE

AVR.2:	LOAD	S1,.TONST(M),TON.TY	;GET DEVICE TYPE FROM MESSAGE
	CAXE	S1,.TYDSK		;IS IT A DISK ONLINE MESSAGE ???
	$RETT				;NO,,RETURN
	LOAD	S1,.TONDV(M)		;GET DEVICE NAME
	MOVE	S2,[.DUCLM,,S1]		;GET DISK. PARM LIST
	DISK.	S2,			;CLEAR DEVICE UNISTS WORD
	JFCL				;IGNORE THE ERROR
	$RETT				;RETURN
>
	SUBTTL	D$DEVS - PROCESS TAPE/DISK STATUS MESSAGES

	;CALL:	M/ The Status Message Address
	;
	;RET:	True Always

TOPS10 <
D$DEVS::MOVX	S1,.STSTS		;GET THE STATUS BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	MISC.3			;NOT THERE,,THATS AN ERROR
	MOVE	T1,S1			;SAVE THE STATUS BLOCK ADDRESS
	MOVE	S1,.STUNT(T1)		;GET THE UNIT NAME
	PUSHJ	P,UCBFND		;FIND IT IN OUR DATA BASE
	JUMPF	MISC.3			;NOT THERE,,THATS AN ERROR
	MOVE	T2,S1			;SAVE THE UCB ADDRESS
	MOVSI	S1,.DUCLM		;'CLEAR MDA WAIT' FUNCTION
	HRRI	S1,.UCBNM(T2)		;MUST POINT TO PRIMARY PORT NAME
	DISK.	S1,			; EVEN IF .STUNT HAS ALTERNATE PORT
	  JFCL				;IGNORE ERRORS
	LOAD	S1,.STFLG(T1),ST.OFL	;GET THE UNIT OFFLINE BIT
	STORE	S1,.UCBST(T2),UC.OFL	;AND SAVE IT
	JUMPN	S1,DEVS.1		;IF OFFLINE,,GO PROCESS IT
	MOVX	S1,UC.INI		;GET THE 'DRIVE INITIALIZING' BIT
	TDNE	S1,.UCBST(T2)		;IS THIS DRIVE WRITING LABELS?
	$RETT				;YES, IGNORE THE STATUS MESSAGE
	MOVX	S1,.TLSTA		;GET THE TAPE DEVICE STATUS BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPT	[MOVE  T3,S1		;GET THE TAPE STATUS BLK ADDRESS IN T3
		 PJRST TAPDEV ]		;AND GO PROCESS IT
	MOVX	S1,.DLSTA		;GET THE DECTAPE DEVICE STATUS BLOCK
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPT	[MOVE	T3,S1		;GET THE DECTAPE STATUS BLK ADDR IN T3
		 PJRST	DTADEV ]	;AND GO PROCESS IT
	MOVX	S1,.DSSTA		;GET STRUCTURE DEVICE STATUS BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPT	[MOVE  T3,S1		;GET THE DISK STATUS BLK ADDRESS IN T3
		 PJRST DSKDEV ]		;AND GO PROCESS IT
	PJRST	MISC.3			;NOT THERE,,INVALID STATUS MESSAGE

	;Here if unit is offline

DEVS.1:	$WTO	(<Offline>,,MDAOBJ)	;TELL OPR
	LOAD	S1,.UCBST(T2),UC.DVT	;GET THE UNIT DEVICE TYPE
	CAXN	S1,%DISK		;IS IT A STRUCTURE ???
	SKIPN	S1,.UCBVL(T2)		;YES,,IS THERE A VOLUME MOUNTED ???
	$RETT				;NO TO EITHER,,JUST RETURN
	PUSHJ	P,DELVOL		;YES,,DELETE THE VOLUME
	$RETT				;AND RETURN
>
	SUBTTL	TAPDEV - TAPE STATUS MESSAGE PROCESSOR

	;CALL:	T1/ The .STSTS block address
	;	T2/ The UCB address
	;	T3/ The .TLSTA block address
	;
	;RET:	Usually True

TOPS10 <
TAPDEV::PUSHJ	P,.SAVE4		;SAVE P1-P4
	MOVE	P1,T3			;SAVE THE MESSAGE DATA ADDRESS

TAPD.1:	MOVE	P2,T2			;SAVE THE UCB ADDRESS IN P2
	SKIPN	P3,.UCBVL(P2)		;CHECK AND LOAD THE VOL ADDRESS
	JRST	TAPD.2			;NO VOLUME YET !!!

	MOVE	S1,P3			;GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE VOLUME ???
	JUMPT	[TXO   P3,<1B0>		;YES,,INDICATE PREVIOUS VOL WAS OWNED
		 JRST  TAPD.2 ]		;    AND THEN GO CHECK LABEL TYPES
					;NO -
	SETZM	.VLUCB(P3)		;DELINK THE VOLUME FROM THE UCB
	SETZM	.UCBVL(P2)		;DELINK THE UCB FROM THE VOLUME
	MOVX	S1,%STAWT		;GET VOLUME WAITING STATUS
	STORE	S1,.VLFLG(P3),VL.STA	;   AND SET IT
	MOVE	S1,P3			;AIM AT THE VOL BLK
	PUSHJ	P,DELVOL		;DELETE IT
	SETZM	P3			;INDICATE NO VOLUME FOUND !!!

TAPD.2:	LOAD	S1,.STFLG(T1),TS.LAB	;GET THE MOUNTED VOL LABEL TYPE
	PUSHJ	P,GETLBT		;RECODE IT TO SOMETHING USEFULL
	JUMPGE	P3,[CAXE S1,%LABEL	;PREVIOUS VOL NOT OWNED AND CURRENT
		    JRST TAPD.8		;   VOL UNLABELED,,GEN A NEW VOL BLK
		    JRST TAPD.4  ]	;   VOL LABELED,,FIND IN VOL DATA BASE
	MOVE	P4,S1			;SAVE THE MOUNTED VOL LABEL TYPE
	LOAD	S1,.VLFLG(P3),VL.LBT	;GET THE PREVIOUS VOL LABEL TYPE
	PUSHJ	P,GETLBT		;RECODE IT TO SOMETHING USEFULL
	CAMN	S1,P4			;PREVIOUS VOL OWNED,,CHECK LABEL TYPES
	JRST	[CAXE  S1,%LABEL	;LABELS MATCH,,IS IT A LABELED VOL ???
		 JRST  TAPD.A		;PREV VOL OWNED AND UNLABELED,,UPDATE
		 JRST  TAPD.3 ]		;PREV VOL OWNED AND LABELED,,CHK VOL Q
	LOAD	S1,.VLFLG(P3),VL.LBT	;GET THE PREV VOL LABEL TYPE
	$WTO	(<Unloading>,<User requested ^T/@0(S1)/ labels>,MDAOBJ)
	MOVE	S1,.UCBNM(P2)		;GET THE UNIT NAME
	PUSHJ	P,UNLOAD		;UNLOAD THE UNIT
	$RETT				;AND RETURN

	;CONTINUED ON THE NEXT PAGE
	;Here for a Labeled Volume Mount

TAPD.3:	MOVE	S1,.VLNAM(P3)		;GET THE VOLUME ID
	CAMN	S1,.TLVOL(P1)		;DO THEY MATCH ???
	JRST	TAPD.9			;YES,,JUST UPDATE THE STATUS
	$WTO	(<Mount labeled volume ^W/S1/ on this drive>,,MDAOBJ)
	MOVE	S1,.UCBNM(P2)		;GET THE DEVICE THE VOL IS MOUNTED ON
	PUSHJ	P,UNLOAD		;UNLOAD THE DEVICE
	$RETT				;AND RETURN

TAPD.4:	SKIPN	S1,.TLVOL(P1)		;GET THE VOLUME NAME
	JRST	TAPD.5			;NULL,,THATS AN ERROR !!!
	PUSHJ	P,FNTAPE		;FIND IT IN OUR DATA BASE
	JUMPF	TAPD.8			;NOT THERE,,CREATE A NEW VOL BLOCK
	MOVE	P3,S1			;SAVE THE VOL BLOCK ADDRESS
	JUMPE	S2,TAPD.9		;NOT MOUNTED,,LINK THIS VOL TO THE UCB
	SKIPA				;SKIP OVER WTO
TAPD.5:	$WTO	(<No volume-ID found in this tapes labels>,,MDAOBJ) ;TELL OPR 
	MOVE	S1,.UCBNM(P2)		;GET THE DEVICE THE VOL IS MOUNTED ON
	PUSHJ	P,UNLOAD		;UNLOAD THE DEVICE
	$RETT				;RETURN

	;We could not find the mounted volume in our volume list,
	;so we will have to create an entry for it.

TAPD.8:	PUSHJ	P,CREVOL		;CREATE A VOL QUEUE ENTRY
	MOVE	P3,S1			;SAVE THE ENTRY ADDRESS
	MOVE	S1,.TLVOL(P1)		;PICK UP THE VOLUME NAME
	MOVEM	S1,.VLNAM(P3)		;SAVE IT IN THE VOL ENTRY
	SKIPN	S1			;IS THIS REALLY A VOL BLK?
	JRST	TAPD.9			;NO NAME... NO RESOURCE NUMBER
	MOVE	S1,P1			;AIM AT THIS NEW VOL BLK
	PUSHJ	P,D$TVRS		;GO GENERATE A RESOURCE NUMBER

	;Having set everything up, link the VOL and UCB together
	;and go finish updating the volume status

TAPD.9:	HRRZM	P3,.UCBVL(P2)		;LINK THE VOLUME TO THE UCB
	MOVEM	P2,.VLUCB(P3)		;LINK THE UCB TO THE VOLUME

	;Update the volume status and tell the operator whats going on.

TAPD.A:	LOAD	S1,.STFLG(T1),ST.LOK	;GET THE WRITE LOCK STATUS
	STORE	S1,.UCBST(P2),UC.WLK	;SAVE THE WRITE LOCK STATUS
	LOAD	S1,.STFLG(T1),TS.DEN	;GET THE TAPE DENSITY
	CAXLE	S1,DENLEN		;VALIDATE THE RETURNED CODE
	PUSHJ	P,S..ITD		;DEEP TROUBLE !!!
	MOVE	S2,D$DEN(S1)		;CONVERT THE CODE TO A BIT MAP

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	CAXE	S1,.TFD00		;IS IT SYSTEM DEFAULT (UNREADABLE TAPE)
	TDNE	S2,.UCBST(P2)		;MUST BE A SUPPORTED DENSITY !!!
	SKIPA				;DEFAULT, OR SUPPORTED DENSITY, GO ON
	STOPCD	(ITD,HALT,,<Invalid tape density specified (in .UCBNM(P2))>)
	STORE	S1,.VLFLG(P3),VL.DEN	;OK,,SAVE THE VOLUME DENSITY
	MOVE	P4,S1			;SAVE HERE ALSO FOR WTO
	LOAD	S1,.STFLG(T1),TS.LAB	;GET THE VOLUME LABEL TYPE
	STORE	S1,.VLFLG(P3),VL.LBT	;SAVE IT
	MOVE	P1,S1			;HERE ALSO

	;If Unlabeled,,Just Tell OPR Whats Going On

	PUSHJ	P,GETLBT		;RECODE THE LABEL TYPE
	CAXE	S1,%LABEL		;IS IT LABELED ???
	JRST	TAPD.B			;NO,,FINISH UP

	;If Labeled,See is we can Give the Volume Away

	MOVE	S1,P2			;GET UCB ADR
	PUSHJ	P,MATUNI		;TRY TO MATCH THIS UNIT WITH A REQUEST
	JUMPT	.RETT			;DONE, DON'T BOTHER THE OPERATOR
	LOAD	S1,.UCBST(P2),UC.WLK	;GET THE WRITE LOCKED BIT
	$WTO	(<Volume ^W/.VLNAM(P3)/ mounted>,<^T/@LABELS(P1)/ labels, ^T/@DENSTY(P4)/ BPI, write-^T/@WRTENA(S1)/>,MDAOBJ)
	$RETT				;AND RETURN

TAPD.B:	LOAD	S1,.UCBST(P2),UC.WLK	;GET THE WRITE LOCKED BIT
	$WTO	(<Unlabeled volume mounted>,<Density ^T/@DENSTY(P4)/ BPI, write-^T/@WRTENA(S1)/>,MDAOBJ)
	$RETT				;TELL OPR AND RETURN
>
	SUBTTL	DTADEV - DECTAPE STATUS MESSAGE PROCESSOR

	;CALL:	T1/ The .STSTS block address
	;	T2/ The UCB address
	;	T3/ The .DLSTA block address
	;
	;RET:	Usually True

TOPS10 <
DTADEV:	PUSHJ	P,.SAVE4		;SAVE P1-P4
	MOVE	P1,T3			;SAVE THE MESSAGE DATA ADDRESS
	MOVE	P2,T2			;SAVE THE UCB ADDRESS IN P2
	SKIPN	P3,.UCBVL(P2)		;CHECK AND LOAD THE VOL ADDRESS
	JRST	DTAD.2			;NO VOLUME YET !!!
	MOVE	S1,P3			;GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE VOLUME ???
	JUMPT	[TXO   P3,<1B0>		;YES,,INDICATE PREVIOUS VOL WAS OWNED
		 JRST  DTAD.1 ]		;    AND CONTINUE ON
	SETZM	.VLUCB(P3)		;DELINK THE VOLUME FROM THE UCB
	SETZM	.UCBVL(P2)		;DELINK THE UCB FROM THE VOLUME
	MOVX	S1,%STAWT		;GET VOLUME WAITING STATUS
	STORE	S1,.VLFLG(P3),VL.STA	;   AND SET IT
	MOVE	S1,P3			;AIM AT THE VOL BLK
	PUSHJ	P,DELVOL		;DELETE IT
	SETZM	P3			;INDICATE NO VOLUME FOUND !!!
	JRST	DTAD.2			;ONWARD

DTAD.1:	MOVE	S1,.VLNAM(P3)		;GET THE VOLUME ID
	CAMN	S1,.DLRID(P1)		;DO THEY MATCH ???
	JRST	DTAD.4			;YES,,JUST UPDATE THE STATUS
	$WTO	(<Mount DECtape volume ^W/S1/ on this drive>,,MDAOBJ)
	MOVE	S1,.UCBNM(P2)		;GET THE DEVICE THE VOL IS MOUNTED ON
	PUSHJ	P,UNLOAD		;UNLOAD THE DEVICE
	$RETT				;AND RETURN

DTAD.2:	SKIPN	S1,.DLRID(P1)		;GET THE REELID
	JRST	DTAD.3			;THERE ISN'T ONE
	PUSHJ	P,FNDECT		;FIND IT IN OUR DATA BASE
	JUMPF	DTAD.3			;NOT THERE,,CREATE A NEW VOL BLOCK
	MOVE	P3,S1			;SAVE THE VOL BLOCK ADDRESS
	JUMPE	S2,DTAD.4		;NOT MOUNTED,,LINK THIS VOL TO THE UCB
	MOVE	S1,.UCBNM(P2)		;GET THE DEVICE THE VOL IS MOUNTED ON
	PUSHJ	P,UNLOAD		;UNLOAD THE DEVICE
	$RETT				;RETURN
	;We could not find the mounted volume in our volume list,
	;so we will have to create an entry for it.

DTAD.3:	PUSHJ	P,CREVOL		;CREATE A VOL QUEUE ENTRY
	MOVE	P3,S1			;SAVE THE ENTRY ADDRESS
	MOVE	S1,.DLRID(P1)		;PICK UP THE REELID
	MOVEM	S1,.VLNAM(P3)		;SAVE IT IN THE VOL ENTRY
	SKIPN	S1			;IS THIS REALLY A VOL BLK?
	JRST	DTAD.4			;NO NAME... NO RESOURCE NUMBER
	MOVE	S1,P1			;AIM AT THIS NEW VOL BLK
	PUSHJ	P,D$OVRS		;GO GENERATE A RESOURCE NUMBER

	;Having set everything up, link the VOL and UCB together
	;and go finish updating the volume status

DTAD.4:	HRRZM	P3,.UCBVL(P2)		;LINK THE VOLUME TO THE UCB
	MOVEM	P2,.VLUCB(P3)		;LINK THE UCB TO THE VOLUME

	;Update the volume status and tell the operator whats going on.

DTAD.5:	LOAD	S1,.STFLG(T1),ST.LOK	;GET THE WRITE LOCK STATUS
	STORE	S1,.UCBST(P2),UC.WLK	;SAVE THE WRITE LOCK STATUS
	SKIPN	.DLRID(P1)		;CHECK FOR A REELID
	JRST	DTAD.6			;UNLABELED
	MOVE	S1,P2			;GET UCB ADR
	PUSHJ	P,MATUNI		;TRY TO MATCH THIS UNIT WITH A REQUEST
	JUMPT	.RETT			;DONE, DON'T BOTHER THE OPERATOR
	$WTO	(<Volume ^W/.VLNAM(P3)/ mounted>,,MDAOBJ)
	$RETT				;AND RETURN

DTAD.6:	LOAD	S1,.UCBST(P2),UC.WLK	;GET THE WRITE LOCKED BIT
	$WTO	(<Unlabeled volume mounted>,,MDAOBJ)
	$RETT				;TELL OPR AND RETURN
>
	SUBTTL	DSKDEV - DISK STRUCTURE DEVICE STATUS MESSAGE PROCESSOR

	;CALL:	T1/ The .STSTS block address
	;	T2/ The UCB address
	;	T3/ The .DSSTA block address
	;
	;RET:	Usually True

TOPS10 <
DSKDEV:	PUSHJ	P,.SAVE1		;SAVE P1
	SKIPN	P1,.UCBVL(T2)		;CHECK AND LOAD ANY MOUNTED VOL ADDRESS
	JRST	DSKD.1			;NONE THERE,,SKIP THIS
	MOVE	S1,.VLSTR(P1)		;GET THE MOUNTED STRUCTURE NAME
	LOAD	S2,.VLFLG(P1),VL.LUN	;AND GET ITS LOGICAL UNIT NUMBER
	CAMN	S1,.DSSNM(T3)		;DOES STRUCTURE NAME MATCH
	CAME	S2,.DSLUN(T3)		;   AND ALSO LOGICAL UNIT NUMBER ???
	SKIPA				;NO,,CONTINUE ON
	JRST	DSKD.8			;YES,,JUST UPDATE THE VOLUME STATUS
	MOVE	S1,P1			;GET THE VOL ADDRESS IN S1

DSKD.A:	MOVE	S2,S1			;SAVE THE VOL ADDRESS IN S2
	LOAD	S1,.VLPTR(S2),VL.PRV	;FIND THE PRIMARY VOL BLOCK
	JUMPN	S1,DSKD.A		;NOT 0,,CONTINUE BACK CHAINING !!!
	LOAD	S1,.VLFLG(S2),VL.STA	;GET THE STRUCTURE STATUS
	CAXN	S1,%STAMN		;IS THE STRUCTURE MOUNTED ???
	JRST	DSK.10			;YES,,WE HAVE AN ERROR !!!

DSKD.0:	SETZM	.VLUCB(P1)		;NOT MOUNTED,,ZAP THE VOL/UCB POINTER
	SETZM	.UCBVL(T2)		;ALSO ZAP THE UCB/VOL POINTER
	MOVE	S1,P1			;GET THE VOL ADDRESS IN S1
	PUSHJ	P,DELVOL		;AND TRY TO DELETE THE VOL BLOCK(S)

DSKD.1:	SKIPN	S1,.DSHID(T3)		;GET THE VOLUME BLOCK ID
	JRST	DSK.11			;NONE THERE,,UH OHHHHH !!!!
	PUSHJ	P,FNDDSK		;FIND IT IN THE VOL QUEUE
	JUMPF	[MOVE  S1,.DSSNM(T3)	;NOT THERE,,GET THE STRUCTURE NAME
		 PUSHJ P,FNDISK		;TRY TO FIND THE PRI VOL BLOCK
		 JUMPF DSKD.4		;NOT THERE,,CREATE A NEW VOL BLOCK
		 MOVE  P1,S1		;FOUND,,SAVE THE VOL ADDRESS
		 SKIPE .VLVID(P1)	;IS A VOLID PRESENT ???
		 JRST  DSKD.4		;YES,,CREATE A NEW VOL BLOCK
		 JRST  DSKD.5 ]		;NO,,USE THIS VOL BLOCK
	MOVE	P1,S1			;SAVE THE VOL BLOCK ADDRESS
	MOVE	S1,.VLSTR(P1)		;GET THE MOUNTED STRUCTURE NAME
	LOAD	S2,.VLFLG(P1),VL.LUN	;AND GET ITS LOGICAL UNIT NUMBER
	CAMN	S1,.DSSNM(T3)		;DOES STRUCTURE NAME MATCH
	CAME	S2,.DSLUN(T3)		;   AND ALSO LOGICAL UNIT NUMBER ???
	JRST	DSKD.3			;NO,,PROCESS DUPLICATE VOL BLK
	PUSHJ	P,FNDISK		;FIND ITS PRIMARY VOL BLOCK ADDRESS
	JUMPF	DSKD.2			;NOT THERE,,SKIP MOUNTED CHECK
	LOAD	S1,.VLFLG(S1),VL.STA	;GET THE STRUCTURE STATUS
	MOVE	S2,.DSHID(T3)		;GET GET THE UNIT ID
	CAIN	S1,%STAMN		;MOUNTED?
	CAME	S2,.VLVID(P1)		;AND THE SAME UNIT ID?
	JRST	DSKD.2			;NO PROBLEMS
	JRST	DSKD.9			;YES,,THATS AN ERROR

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

DSKD.2:	SKIPE	S1,.VLUCB(P1)		;GET THE VOL UCB ADDRESS
	SETZM	.UCBVL(S1)		;ZAP THAT UNITS POINTER TO THE VOL BLK
	JRST	DSKD.7			;AND CONTINUE

DSKD.3:	SKIPN	S1,.VLUCB(P1)		;IS THE DUPLICATE VOLUME MOUNTED ???
	JRST	DSKD.4			;NO,,SKIP THIS
	$WTO	(<Warning: ^W/.VLVID(P1)/ is mounted on drive ^W/.UCBNM(S1)/>,,MDAOBJ)
	MOVE	S1,.UCBNM(S1)		;GET THE UNIT ON WHICH VOL IS MOUNTED
	PUSHJ	P,SNDREC		;REQUEST DEVICE STATUS FOR THE VOL

DSKD.4:	PUSHJ	P,CREVOL		;GO CREATE A VOL ENTRY FOR IT
	MOVE	P1,S1			;SAVE THE NEW VOL ADDRESS

DSKD.5:	MOVE	S1,.DSHID(T3)		;GET THIS VOL'S VOLUME NAME
	MOVEM	S1,.VLVID(P1)		;SAVE IT
	MOVE	S1,.DSLUN(T3)		;GET THIS VOL'S LOGICAL UNIT NUMBER
	STORE	S1,.VLFLG(P1),VL.LUN	;SAVE IT
	MOVE	S1,.DSNXV(T3)		;GET THE NEXT VOLUME NAME
	MOVEM	S1,.VLNXT(P1)		;SAVE IT
	MOVE	S1,.DSSNM(T3)		;GET THE STRUCTURE NAME FOR THIS VOL
	MOVEM	S1,.VLSTR(P1)		;SAVE IT
	MOVE	S1,.DSPPN(T3)		;GET OWNER PPN
	MOVEM	S1,.VLOID(P1)		;SAVE IT
	MOVX	S1,%LABEL		;GET 'LABELED' LABEL TYPE
	STORE	S1,.VLFLG(P1),VL.LBT	;AND SET IT

DSKD.7:	MOVEM	P1,.UCBVL(T2)		;LINK THE VOL TO THE UCB
	MOVEM	T2,.VLUCB(P1)		;LINK THE UCB TO THE VOL
	MOVE	S1,.VLSTR(P1)		;GET THE STRUCTURE NAME
	SKIPE	.DSLUN(T3)		;THE THE FIRST UNIT IN THE STRUCTURE ??
	JRST	DSKD.8			;NO, DON'T MAKE A RESOURCE NUMBER
	STORE	S1,.VLNAM(P1)		;YES,,SET THE STR NAME (PRIMARY VOL)
	MOVE	S1,P1			;AIM AT THE STR VOL BLK
	PUSHJ	P,D$SVRS		;GENERATE A STRUCTURE RESOURCE NUMBER

DSKD.8:	LOAD	S1,.STFLG(T1),ST.LOK	;GET THE UNIT WRITE LOCK BIT
	STORE	S1,.UCBST(T2),UC.WLK	;SAVE IT
	LOAD	S2,.UCBS1(T2),U1.FRC	;[1217] GET 'FORCED' MOUNT BIT
	STORE	S2,.VLFLG(P1),VL.FRC	;[1217] SET IN VOL BLOCK ALSO
	MOVEI	S2,[ASCIZ ||]		;ASSUME WRITE ENABLED
	SKIPE	S1			;WAS IT?
	MOVEI	S2,[ASCIZ |Unit is hardware write protected|]
	$WTO	(<Volume ^W/.VLVID(P1)/ for structure ^W/.DSSNM(T3)/ mounted>,<^T/(S2)/>,MDAOBJ)

	MOVE	S1,.VLSTR(P1)		;GET THE STRUCTURE NAME IN S1
	SETZM	S2			;NO ALIAS...
	MOVX	TF,VL.FRC		;[1217] GET 'FORCED' MOUNT BIT
	TDNN	TF,.VLFLG(P1)		;[1217] IS A 'FORCED' MOUNT IN PROGRESS ?
	SKIPE	D$ASR			;IS AUTOMATIC STR RECOGNITION ENABLED ???
	PUSHJ	P,BLDSTR		;YES,,TRY TO BUILD A STR WITH WHAT WE HAVE
	$RETT				;RETURN

DSKD.9:	MOVE	S2,.VLUCB(P1)		;GET THE VOLS UCB ADDRESS
	$WTO	(<Error - Can't mount volume ^W/.DSHID(T3)/ on this unit>,<The volume is already mounted on ^W/.UCBNM(S2)/>,MDAOBJ)
	$RETT				;AND RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

DSK.10:	$WTO	(<Error - Can't mount volume ^W/.DSHID(T3)/ on this Unit>,<Volume ^W/.VLVID(P1)/ for structure ^W/.VLSTR(P1)/ is mounted on this unit>,MDAOBJ)
	SKIPA				;SKIP OVER OTHER ERROR
DSK.11:	$WTO	(<Error - Pack on this unit has a null volume0-ID>,,MDAOBJ,<$WTFLG(WT.SJI)>)
	MOVE	S1,.UCBNM(T2)		;GET THE UNIT NAME
	PUSHJ	P,UNLOAD		;UNLOAD IT
	$RETT				;AND RETURN
>

	SUBTTL	SETOWN - ROUTINE TO SET UP OWNERSHIP FOR A VSL

	;CALL:	S1/ The VSL Address
	;
	;RET:	S1/ The VSL Address (True Always)

SETASK:	TDZA	TF,TF			;INDICATE 'SET MOUNT REQUESTED'
CLRASK:	SETOM	TF			;INDICATE 'CLEAR MOUNT REQUESTED'
	MOVX	S2,VL.ASK		;GET 'MOUNT REQUESTED' STATUS BIT
	JRST	COMMON			;CONTINUE

D$SETO::				;MAKE 'SETOWN' GLOBAL
SETOWN:	TDZA	TF,TF			;INDICATE 'SET ASSIGNED' 
CLROWN:	SETOM	TF			;INDICATE 'CLEAR ASSIGNED'
	MOVX	S2,VL.ASN		;GET THE 'ASSIGNED' STATUS BIT
	SKIPN	TF			;ARE WE SETTING THE BIT ???
	TXO	S2,VL.OWN		;YES,,ALSO LIGHT THE VOLUME OWNED BIT

COMMON:	$SAVE	<S1,P1,P2,P3>		;SAVE SOME ACS
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	MOVE	P2,S2			;SAVE THE BIT TO CLEAR/LITE
	MOVE	P3,TF			;SAVE THE SET/CLEAR FUNCTION CODE
	PUSHJ	P,CHKOWN		;LOCATE THIS GUYS VSL ADDR IN THE VOL
	JUMPN	P3,[ANDCAM P2,0(S1)	;IF CLEAR FUNCTION,,CLEAR THE BIT
		    SETZM  .VSUCB(P1)	;ZAP THE UNIT POINTER
		    $RETT  ]		;AND RETURN
	IORM	P2,0(S1)		;IF SET FUNCTION,,LITE THE BIT(S)
	ZERO	.VSFLG(P1),VS.NMT	;CLEAR THE PSEUDO MOUNTED STATUS BIT
	TXNN	P2,VL.ASN		;IF JUST 'ASKING' THEN
	$RETT				;RETURN NOW
	LOAD	P3,.VSCVL(P1),VS.OFF	;GET THE CURRENT VOLUME OFFSET
	ADDI	P3,.VSVOL(P1)		;POINT TO THE VOL ADDRESS
	MOVE	P3,0(P3)		;GET THE VOL ADDRESS
	MOVE	P3,.VLUCB(P3)		;GET THE UNIT ADDRESS
	MOVEM	P3,.VSUCB(P1)		;AND LINK THE UCB TO THIS VSL
	MOVX	P2,VL.ASK		;GET THE 'ASK' BIT
	ANDCAM	P2,0(S1)		;AND CLEAR IT
	$RETT				;RETURN
	SUBTTL	MNTVSL - ROUTINE TO ATTEMPT TO MOUNT A USERS REQUESTS

	;CALL:	S1/ The VSL Address
	;
	;RET:	True Always

TOPS10<
D$MNTV::				;MAKE IT GLOBAL
MNTVSL:	PUSHJ	P,.SAVE4		;SAVE P1 & P2 & P3 & P4
	$SAVE	<AP,T3,T4>		;SAVE AP & T3 & T4 ALSO
	STKVAR	<NOACK,<VSLIST,^D20>,<MNTLST,^D40>> ;GEN A FLAG & SOME QUEUES
	MOVE	P4,S1			;SAVE THE INITIAL VSL ADDRESS
	MOVE	AP,.VSMDR(P4)		;SETUP THE MDR ADDRESS 
	SETZM	P3			;INDICATE NORMAL MOUNT REQUEST
	SETZM	NOACK			;CLEAR NO ACK FLAG
	MOVX	S1,QE.WAM		;GET WAITING FOR MOUNT STATUS
	LOAD	S2,.MRJOB(AP),MR.JOB	;GET THE REQUEST JOB NUMBER
	TXNE	S2,BA%JOB		;IS THIS A PSEUDO REQUEST ???
	SKIPN	P3,.MRQEA(AP)		;YES,,PICK UP THE QE ADDRESS
	SKIPA				;NOT A PSEUDO REQUEST,,SKIP
	IORM	S1,.QESEQ(P3)		;SET 'MOUNT WAIT' (CLEARED LATER)

MNTV.0:	MOVEI	T4,VSLIST		;GET THE PRIMARY VSL QUEUE ADDRESS
	HRLI	T4,-^D20		;GEN THE PRIMARY VSL QUEUE STACK POINTER
	PUSH	T4,[-1]			;MARK END OF VSL QUEUE
	MOVEI	T3,MNTLST		;GET THE MOUNT VSL QUEUE ADDRESS
	HRLI	T3,-^D40		;GEN MOUNT VSL QUEUE STACK POINTER
	PUSH	T3,[-1]			;MARK END OF VSL QUEUE
	PUSH	T3,[-1]			;HERE ALSO

	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	LOAD	P2,.VSLNK(P4),VS.LNK	;GET THE VSL LINK CODE
	MOVNS	P1			;NEGATE THE VSL COUNT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.MRVSL(AP)		;CREATE VSL AOBJN AC

MNTV.1:	MOVE	S1,0(P1)		;GET A VSL ADDRESS
	LOAD	S2,.VSLNK(S1),VS.LNK	;GET THE VSL LINK CODE
	CAME	S2,P2			;DO THEY MATCH ???
	JRST	MNTV.2			;NO,,TRY NEXT
	MOVE	S2,.VSFLG(S1)		;GET THE VSL FLAG BITS
	TXNE	S2,VS.ALC+VS.WAL	;JUST ALLOCATED OR AWAITING ALLOCATION ?
	JRST	[JUMPE  P3,.RETF	;YES,,IF NOT A PSEUDO PROCESS - RETURN
		 MOVX   S2,QE.WAM	;IF A PSEUDO PROCESS,,GET 'MOUNT WAIT'
		 ANDCAM S2,.QESEQ(P3)	;   AND CLEAR IT
		 $RETF	]		;THEN RETURN
	PUSH	T4,S1			;QUEUE UP THE VSL ADDRESS
	LOAD	S1,.VSFLG(S1),VS.TYP	;GET THE REQUEST TYPE
	CAXN	S1,%UNKN		;IS IT UNKNOWN ???
;**;[1225] Change code at MNTV.1+12L. /LWS
	JRST	[MOVE  S1,P4		;[1225] GET PRIMARY VSL ADDRESS
		 PUSHJ P,TELOPR		;[1225] TELL OPR OF MOUNT
		 $RETF]			;[1225] RETURN FALSE
MNTV.2:	AOBJN	P1,MNTV.1		;LOOK FOR ALL VSL'S WITH THAT LINK CODE
	MOVE	P2,T4			;SAVE THE PRIMARY VSL QUEUE STACK PTR

	;CONTINUED ON THE NEXT PAGE
	;Here to perform deadlock avoidance check

	MOVE	S1,P4			;GET THE INITIAL VSL ADDRESS BACK
	SKIPN	G$DEAD##		;DEADLOCK AVOIDANCE TURNED ON?
	 PUSHJ	P,TELOPR		;NO,,ALWAYS TELL THE OPR ABOUT MOUNTS
	MOVE	S1,P4			;GET BACK VSL ADDRESS IN CASE OF MDA
	PUSHJ	P,D$DLCK		;DO DEADLOCK CHECKING
	JUMPF	.RETF			;IF DEADLOCKED,,JUST RETURN

	;Here to check to make sure we can mount ALL the required volumes

MNT.2A:	POP	T4,S1			;GET A VSL ADDRESS OFF THE QUEUE
	CAMN	S1,[-1]			;END OF THE QUEUE ???
	JRST	MNT.2B			;YES,,CONTINUE ONWARD !!!
	LOAD	S2,.VSFLG(S1),VS.INI	;[1164] GET NEW-VOLUME INITIALIZATION BIT
	JUMPN	S2,MNT.2A		;[1164] IF LIT,,SKIP THIS VSL
	PUSHJ	P,VSLCHK		;CAN WE MOUNT THIS VOLUME ???
	JUMPF	MNTV.9			;NO - TELL THE OPERATOR
	JUMPE	S1,MNT.2A		;THAT VSL ALREADY MOUNTED,,TRY NEXT
	JUMPL	S1,MNTV.8		;REQUIRED VOLUME NOT MOUNTED,,TELL OPR
	PUSH	T3,S1			;QUEUE UP THE VSL ADDRESS
	PUSH	T3,S2			;QUEUE UP THE UCB/VOL ADDRESS
	JRST	MNT.2A			;CONTINUE ON

	;Now check to see if the pseudo process has been allocated 

MNT.2B:	JUMPE	P3,MNTV.3		;NOT A PSEUDO PROCESS,,CONTINUE
	MOVX	S1,QE.WAM		;GET 'WAITING FOR MOUNT' STATUS BIT
	ANDCAM	S1,.QESEQ(P3)		;CLEAR IT FOR THE PSEUDO PROCESS
	MOVE	S1,P3			;GET THE QE ADDRESS IN S1
	PUSHJ	P,I$RALC##		;REQUEST ALLOCATION

	;Try to mount the Volume(s)

MNTV.3:	POP	T3,S2			;RESTORE A VOL/UCB ADDRESS
	POP	T3,S1			;RESTORE A VSL ADDRESS
	CAMN	S1,[-1]			;END OF THE QUEUE ???
	JRST	MNTV.7			;YES,,GO ACK THE USER
	JUMPN	P3,MNTV.4		;IF A PSEUDO PROCESS,,GO MOUNT IT
	LOAD	P1,.VSFLG(S1),VS.TYP	;ELSE GET THE VOLUME TYPE
	CAIE	P1,%DTAP		;DECTAPE?
	CAIN	P1,%TAPE		;MAGTAPE?
	JRST	MNTV.5			;YES,,GO PROCESS IT
	JRST	MNTV.6			;NO,,ASSUME %DISK

	;Here to perform mounts for Pseudo Processes

MNTV.4:	SETOM	NOACK			;LITE 'DEFERED ACK' FLAG
	DOSCHD				;FORCE A SCHEDULING PASS
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	PUSH	P,S2			;SAVE THE VOL/UCB ADDRESS
	PUSHJ	P,SETOWN		;SET VOLUME OWNERSHIP
	POP	P,S2			;RESTORE THE VOL/UCB ADDRESS
	MOVX	S1,VS.NMT		;GET THE 'NOT REALLY MOUNTED' FLAG BIT
	IORM	S1,.VSFLG(P1)		;SET IT FOR THIS PSEUDO PROCESS
	LOAD	S1,.VSFLG(P1),VS.TYP	;GET THE VOLUME TYPE
	CAXE	S1,%TAPE		;IS IT TAPE ???
	JRST	MNTV.3			;NO,,GET NEXT VSL
	MOVEM	S2,.VSUCB(P1)		;LINK THE UCB TO THIS USER
	MOVEM	P1,.UCBVS(S2)		;LINK THIS USER TO THIS DEVICE
	JRST	MNTV.3			;GET THE NEXT VSL

	;CONTINUED ON THE NEXT PAGE
	;Here to mount tape volumes

MNTV.5:	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	EXCH	S1,S2			;GET UCB ADDR IN S1, VSL IN S2
	PUSHJ	P,REASSI		;TRY TO REASSIGN THE DEVICE
	JRST	MNTV.3			;CONTINUE

	;Here to mount structures

MNTV.6:	SETOM	NOACK			;LITE 'DEFERED ACK' FLAG
	PUSH	P,S2			;SAVE THE VOL ADDRESS
	PUSHJ	P,SETASK		;SET THE 'MOUNT REQUESTED' STATUS
	POP	P,S2			;RESTORE THE VOL ADDRESS
	PUSHJ	P,ASLMSG		;GEN 'ADD TO SEARCH LIST' & SEND IT
	JRST	MNTV.3			;CONTINUE

	;Here to ack the user that his request has been satisfied

MNTV.7:	SKIPE	NOACK			;IS 'NO ACK' SET ???
	$RETT				;YES,,RETURN
	MOVE	S1,P4			;GET THE VSL ADDRESS BACK
	PUSHJ	P,ACKUSR		;NOTIFY THE USER
	$RETT				;AND RETURN

MNTV.8:	MOVE	S1,P4			;GET THE ORIGIONAL VSL ADDRESS
	SKIPE	G$DEAD##		;DEADLOCK AVOIDANCE TURNED ON?
	 PUSHJ	P,TELOPR		;ASK THE OPR TO MOUNT THE DEVICES
	JUMPE	P2,.RETF		;NO VSL QUEUE,,EXIT NOW

MNTV.9:	POP	P2,S1			;PICK UP THE VSL ADDRESS OFF THE QUEUE
	CAMN	S1,[-1]			;END OF THE QUEUE ???
	$RETF				;YES,,RETURN
	PUSHJ	P,RETA%C		;RETURN THE 'A' AND 'C' MATRIX ENTRIES
	JRST	MNTV.9			;CONTINUE FOR ALL VSL'S
> ;END TOPS10 CONDITIONAL
	SUBTTL	MNTVSR - ROUTINE TO MOUNT A VOLUME AT VOLUME SWITCH TIME

	;CALL:	S1/ The VSL Address
	;
	;RET:	True if the mount wins, False otherwise

TOPS10<
MNTVSR:	$SAVE	<AP,P1,P2>		;SAVE AP AND P1 & P2 FOR A SECOND
	MOVE	AP,.VSMDR(S1)		;SETUP A NEW MDR POINTER
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	PUSHJ	P,D$CMTX		;LOCATE THIS GUYS 'C' MATRIX ENTRY
	LOAD	S1,.VSCVL(P1),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	S1,.VSVOL(P1)		;POINT TO THE CURRENT VOL ADDRESS
	MOVE	S1,0(S1)		;GET THE CURRENT VOL ADDRESS
	PUSHJ	P,D$TVRS		;CONVERT TO A RESOURCE NUMBER
	MOVE	P2,S1			;SAVE THE RSN FOR LATER IF WE NEED IT
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,ADDAMA		;CLAIM THIS RESOURCE IN 'A' MATRIX
	PUSHJ	P,ADDCMA		;CLAIM THIS RESOURCE IN 'C' MATRIX
	PUSHJ	P,DEADLK		;DEADLOCK CHECK THE WORLD !!!
	JUMPF	TVSR.1			;TOUGH NOUGEEEES !!!
	MOVE	S1,P1			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,VSLCHK		;CAN WE MOUNT THE VOLUME ???
	JUMPF	TVSR.1			;NO,,THIS GUY JUST CAN'T WIN !!!
	JUMPE	S1,.RETT		;SHOULD NOT HAPPEN !!!
	JUMPL	S1,TVSR.0		;NOT MOUNTED,,TELL OPR TO MOUNT IT
	EXCH	S1,S2			;GET UCB ADDR IN S1, VSL ADDR IN S2
	PUSHJ	P,REASSI		;REASSIGN THE VOLUME
	$RETT				;RETURN

TVSR.0:	MOVE	S1,P1			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,TELOPR		;TELL THE OPR TO MOUNT THE VOLUME

TVSR.1:	MOVE	S1,P2			;GET THE VOLUME RSN BACK
	MOVE	S2,P1			;GET THE VSL ADDRESS BACK
	PUSHJ	P,SUBAMA		;DELETE THE CLAIM FROM THE 'A' MATRIX
	PUSHJ	P,SUBCMA		;DELETE THE CLAIM FROM THE 'C' MATRIX
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	VSLCHK - ROUTINE TO TRY TO MOUNT A VOLUME FROM THE VSL

	;CALL:	S1/ The VSL Address
	;
	;RET:	S1/ The VSL Address if %TAPE
	;	S2/ The UCB Address if %TAPE
	;
	;	S1/ The VSL Address if %DISK
	;	S2/ The VOL Address if %DISK
	;
	;Error Return Codes:
	;
	;	S1/  0 If the User Already has the Volume Mounted
	;	S1/ -1 If the requested volume needs mounting

TOPS10<
VSLCHK:	PUSHJ	P,.SAVE3		;SAVE P1 TO P3
	MOVE	P2,S1			;SAVE THE VSL ADDRESS
	LOAD	S1,.VSCVL(P2),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	S1,.VSVOL(P2)		;POINT TO THE CURR VOL ADDRESS
	MOVE	P1,0(S1)		;GET THE CURRENT VOLUME ADDRESS
	SKIPN	P3,.VLUCB(P1)		;CHECK AND LOAD THE UCB ADDRESS
	JRST	[SETOM S1		;NOT MOUNTED,,SET RETURN CODE
		 $RETT  ]		;   AND EXIT
	MOVE	S2,.UCBNM(P3)		;GET THE UNIT NAME
	MOVEM	S2,MDAOBJ+OBJ.UN	;SAVE IT IN THE MDA OBJECT BLOCK
	LOAD	S1,.VSFLG(P2),VS.NMT	;GET THE PSEUDO MOUNTED FLAG BIT
	JUMPE	S1,VSLC.1		;NOT CURRENTLY MOUNTED,,SKIP THIS
	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE JOB NUMBER
	TXNN	S1,BA%JOB		;STILL A PSEUDO PROCESS ???
	JRST	VSLC.5			;NO,,MOUNT IT FOR REAL !!!!
	SETZM	S1			;YES,,SET 'MOUNTED' RETURN CODE
	$RETT				;AND RETURN NOW

VSLC.1:	LOAD	S1,.VSFLG(P2),VS.TYP	;GET REQUEST TYPE
	CAXN	S1,%DISK		;DISK REQUEST?
	JRST	VSLC.6			;YES - DON'T CHECK OWNERSHIP
	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,CHKOWN		;DOES THIS GUY OWN THE VOLUME ???
	JUMPT	[SETZM S1		;YES,,SET 'MOUNTED' RETURN CODE
		 $RETT  ]		;AND RETURN

VSLC.2:	LOAD	S1,.VSFLG(P2),VS.TYP	;GET THE VOLUME SET TYPE
	CAIN	S1,%DTAP		;DECTAPE?
	JRST	VSLC.3			;YES
	CAXE	S1,%TAPE		;IS IT A TAPE REQUEST ???
	JRST	VSLC.6			;NO,,TRY DISK

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here to process magtape requests

	LOAD	S1,.VSFLG(P2),VS.VSW	;IS THIS VSL IN VOLUME SWITCH ???
	JUMPN	S1,VSLC.3		;YES,,SKIP LABEL CHECK
	LOAD	S1,.VLFLG(P1),VL.LBT	;GET THE MOUNTED VOL LABEL TYPE
	PUSHJ	P,GETLBT		;RECODE IT TO SOMETHING UNDERSTANDABLE
	CAXE	S1,%LABEL		;IS IT LABELED ???
;**;[1140]CHANGE 1 LINE AT VSLC.3:-1L 23-JUL-83/CTK
;**;[1150]REMOVE EDIT # 1140 		7-SEP-83/CTK
	$RETF				;NO,,RETURN

VSLC.3:	MOVE	S1,P1			;GET THE VOL ADDRESS IN S1
	PUSHJ	P,FNDOWN		;IS THE VOLUME OWNED ???
	JUMPT	.RETF			;YES,,RETURN

VSLC.4:	DMOVE	S1,P1			;GET VOL ADDR IN S1, VSL ADDR IN S2
	PUSHJ	P,CVLVSB		;GO CHECK DEVICE ATTRIBUTES
	JUMPF	.RETF			;NO MATCH,,RETURN
	LOAD	S1,.UCBST(P3),UC.VSW	;SWITCHING VOLUMES ON THIS UNIT?
	JUMPE	S1,VSLC.5		;NO,,SKIP THIS
	CAME	P2,.UCBVS(P3)		;DOES THIS USER OWN THE UNIT ???
	$RETF				;NO,,RETURN

VSLC.5:	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	LOAD	S2,.VSFLG(P2),VS.TYP	;GET THE REQUEST TYPE
	CAIN	S2,%DISK		;IS IT A STRUCTURE REQUEST ???
	MOVE	P3,.UCBVL(P3)		;YES,,LOAD UP THE VOL BLOCK ADDRESS
	MOVE	S2,P3			;GET THE UCB OR VOL ADDRESS IN S2
	$RETT				;RETURN OK

	;Here to process Disk requests

VSLC.6:	CAXE	S1,%DISK		;IS THIS A DISK REQUEST ???
	$RETF				;NO,,RETURN
	LOAD	S1,.VLFLG(P1),VL.STA	;GET THE STRUCTURE STATUS
	LOAD	S2,.VLFLG(P1),VL.LCK	;GET THE STR LOCK STATUS
	CAIN	S1,%STAWT		;IS IT WAITING TO BE MOUNTED?
	JRST	[MOVX	S1,-1		;YES - SET RETURN CODE
		 $RETT]			;AND RETURN
	CAXN	S1,%STAMN		;MUST BE MOUNTED AND
	CAXN	S2,%LOCKD		;   NOT LOCKED
	SKIPA				;     OR NOT LOCKED
	CAXN	S2,%ULCKP		;        WITH A PENDING UNLOCK
	$RETF				;IF SO,,THATS NO GOOD !!!
	MOVE	S1,P2			;GET THE VSL ADDRESS 
	MOVE	S2,P1			;GET THE VOL ADDRESS
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	MATUNI - ROUTINE TO GIVE A VOLUME TO ANY VALID REQUESTOR

	;CALL:	S1/ The UCB Address of the unit on which the volume is mounted
	;
	;RET:	True Always

TOPS10<
MATUNI:	PUSHJ	P,.SAVE3		;SAVE P1& P2 & P3 FOR A SECOND
	SKIPN	P2,.UCBVL(S1)		;CHECK AND LOAD THE VOL BLOCK ADDRESS
	$RETF				;SHOULD NOT HAPPEN
	LOAD	P1,.VLOWN(P2),VL.CNT	;GET THE REQUEST COUNT
	JUMPE	P1,.RETF		;NONE THERE,,RETURN
	MOVNS	P1			;NEGATE IT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.VLVSL(P2)		;GEN VSL SEARCH AOBJN AC
	LOAD	S1,.UCBST(S1),UC.DVT	;GET THE DEVICE TYPE
	CAIN	S1,%DISK		;STRUCTURE?
	JRST	MATU.2			;YES

	;Here to try to satisfy DECtape or magtape mount requests

MATU.0:	MOVE	S1,0(P1)		;GET A VSL ADDRESS
	LOAD	S2,.VSCVL(S1),VS.OFF	;GET THE CURRENT VOLUME OFFSET
	ADDI	S2,.VSVOL(S1)		;POINT TO THE CURRENT VOL ADDRESS
	CAMN	P2,0(S2)		;IS HE POINTING AT THIS VOL BLOCK ???
	TXNE	S1,VL.ASN		;OR DOES HE ALREADY HAVE IT ASSIGNED ??
	JRST	MATU.1			;ALREADY ASSGNED OR WRONG VOL,SKIP THIS
	HRRZS	S1			;GET ONLY THE VSL ADDRESS (CLEAR FLAGS)
	LOAD	P3,.VSFLG(S1),VS.VSW	;GET THE VOLUME SWITCH STATUS
	SKIPE	P3			;ARE WE SWITCHING VOLUMES ???
	PUSHJ	P,MNTVSR		;YES,,GO PROCESS IT
	SKIPN	P3			;ARE WE SWITCHING VOLUMES ???
	PUSHJ	P,MNTVSL		;NO,,TRY GENERAL MOUNT
	JUMPT	.RETT			;WIN,,RETURN
MATU.1:	AOBJN	P1,MATU.0		;NO GO,,TRY NEXT VSL
	$RETF				;CAN'T,,JUST RETURN

	;Here to try to satisfy structure mount requests

MATU.2:	MOVE	S1,0(P1)		;GET A VSL ADDRESS
	TXNN	S1,VL.ASK+VL.ASN	;ASSIGNED OR PENDING ???
	JRST	[HRRZS	S1		;GET ONLY THE VSL ADDRESS (CLEAR FLAGS)
		 PUSHJ	P,MNTVSL	;TRY TO MOUNT IT FOR THIS USER
		 JRST	MATU.3 ]	;AND CONTINUE
MATU.3:	AOBJN	P1,MATU.2		;CHECK THROUGH ALL VSL'S
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	CVLVSL - Compare Volume with Volume Set

	;This routine will check the user requested attributes of the
	; mount request with the attributes of a particular mounted volume
	; The caller must make sure that the volume is free to be
	; reassigned to the user should the attributes match.
	;
	;CALL:	S1/ addr of VOL block
	;	S2/ addr of VSL block
	;RET:	TRUE, if all the attributes match, FALSE if they don't
	; Alternate entry at CVLVSB which will not match bypass requests

TOPS10<
CVLVSB:	LOAD	TF,.VSFLG(S2),VS.LBT	;GET THE REQUESTED LABEL TYPE
	CAXN	TF,.TFLBP		;BYPASS REQUESTED?
	 $ERJMP	MD$URB,S2		;YES,,MUST COME THROUGH IDENTIFY

CVLVSL:	LOAD	TF,.VSFLG(S2),VS.TYP	;GET DEVICE TYPE
	CAIN	TF,%DTAP		;DECTAPE?
	$RETT				;YES--NOTHING TO CHECK
	$SAVE	<P1,P2,P3>
	DMOVE	P1,S1			;COPY THE VOL, AND VSL PTRS
	SKIPN	P3,.VLUCB(P1)		;GET THE UNIT BLOCK
	 $ERJMP	MD$NVM,P2		;SHOULD NOT HAPPEN !!!

	;Check the state of the write-ring against the user request

	LOAD	S1,.UCBST(P3),UC.WLK	;GET THE LOCK BIT FOR THIS VOLUME
	LOAD	S2,.VSFLG(P2),VS.WLK	;GET THE ENABLE BIT FOR THE REQUEST
	CAME	S1,S2			;DO THEY MATCH ???
	PJRST	[SKIPE S2		;S2 NOT EQUAL TO 0,,WRITE LOCKED
		 $ERJMP MD$URW,P2	;SO TELL THE OPERATOR
		 $ERJMP MD$URE,P2 ]	;ELSE USER WANTS WRITE ENABLED

	;Check for conflicting label types

	LOAD	S1,.VSFLG(P2),VS.LBT	;GET REQUESTED LABEL TYPE
	CAXN	S1,.TFLNV		;IS IT NO LABELS/NO EOV PROCESSING ???
	MOVX	S1,.TFLNL		;YES,,MAKE IT NO LABELS, PERIOD !
	LOAD	S2,.VLFLG(P1),VL.LBT	;GET LABEL TYPE OF THIS VOLUME
	CAXN	S2,.TFLNV		;IS IT NO LABELS/NO EOV PROCESSING ???
	MOVX	S2,.TFLNL		;YES,,MAKE IT NO LABELS, PERIOD !
	CAME	S1,S2			;MATCH?
	CAXN	S1,.TFLBP		;NO, BUT ASKING FOR BYPASS LABELS?
	SKIPA				;MATCH.. OR REQUESTING BLP, WIN
	JRST	[CAXN S1,.TFLNL		;USER WANTED UNLABELED?
		 $ERJMP MD$VIL,P2	;NO,,VOLUME IS LABELED !!!
		 $ERJMP MD$URL,P2 ]	;YES,,COMPLAIN ABOUT THAT !!!
	DMOVE	S1,P2			;GET VSL IN S1, UCB IN S2
	PUSHJ	P,D$MODR		;CHECK TRACK/DENSITY REQUIREMENTS
	JUMPF	.RETF			;NO GOOD,,RETURN
	$RETT				;ELSE OK
>;END TOPS10

	SUBTTL	CHKOWN - ROUTINE TO CHECK IF A USER OWNS A VOLUME

	;CALL:	S1/ The VSL Address
	;
	;RET:	S1/ The VOL block pointer to the VSL address

D$FOWN::				;GLOBALIZE IT
CHKOWN:	LOAD	S2,.VSCVL(S1),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	S2,.VSVOL(S1)		;POINT TO THE OFFSET
	MOVE	S2,0(S2)		;GET THE VOL BLOCK ADDRESS
	EXCH	S1,S2			;WANT S1=VOL ADDR,  S2=VSL ADDR
	PUSH	P,S2			;SAVE THE VSL ADDRESS
	LOAD	S2,.VLOWN(S1),VL.CNT	;GET THE VOLUME REQUEST COUNT
	MOVNS	S2			;NEGATE IT
	MOVSS	S2			;MOVE RIGHT TO LEFT
	HRRI	S2,.VLVSL(S1)		;CREATE AOBJN AC FOR VSL ADDR SEARCH
	MOVE	S1,S2			;GET THE POINTER IN S1
	POP	P,S2			;GET THE VSL ADDRESS BACK

CHKO.1:	CAIN	S2,@0(S1)		;FIND THE USERS VSL ADDR IN THE VOL LIST
	JRST	[MOVX  S2,VL.ASK+VL.ASN	;FOUND,,GET REQUEST+ASSIGNED BITS
		 TDNE  S2,0(S1)		;IF LIT,,THIS GUY WAS ALREADY PROCESSED
		 $RETT			;RETURN VOLUME OWNED
		 $RETF  ]		;RETURN VOLUME NOT OWNED
	AOBJN	S1,CHKO.1		;NOT THIS ONE,,TRY NEXT
	STOPCD	(IVV,HALT,,<Invalid VSL/VOL forward/backchain pointers>) ;NOT FOUND !!!

	SUBTTL	D$UNLO - ROUTINE TO UNLOAD A TAPE DRIVE

	;CALL:	M/ The Unload Message Address
	;
	;RET:	True Always

TOPS10 <
D$UNLO::PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVX	S1,.TAPDV		;GET THE DRIVE BLOCK TYPE CODE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	E$IMO##			;INVALID ORION MESSAGE SENT !!!
	PUSHJ	P,FNDUCB		;FIND THE AFFECTED UCB
	JUMPF	.RETF			;NOT THERE,,THATS AN ERROR
	MOVE	P1,S1			;SAVE THE UCB ADDRESS IN P1
	MOVE	S1,.UCBNM(P1)		;GET THE DEVICE NAME IN S1
	SKIPN	S2,.UCBVL(P1)		;CHECK AND LOAD THE VOLUME ADDRESS
	PJRST	UNLOAD			;NO VOLUME ON IT,,JUST SEND THE MSG
	LOAD	S1,.UCBST(P1),UC.VSW	;IS THIS UNIT IN VOLUME SWITCH MODE ??
	JUMPN	S1,UNLO.1		;YES,,OK TO UNLOAD THE TAPE !!!
	MOVE	S1,S2			;GET THE VOLUME ADDRESS IN S1
	PUSHJ	P,FNDOWN		;ANY OWNERS FOR THIS VOLUME ???
	SKIPF				;NO,,SKIP
	 $ERJMP	MD$VAU			;YES,,CAN THE REQUEST
UNLO.1:	$ACK	(<Unloading>,,MDAOBJ,.MSCOD(M)) ;TELL THE OPERATOR
	MOVE	S1,.UCBVL(P1)		;POINT AT THIS VOLUME
	PJRST	VLUNLO			;AND DELINK ALL THE GOOD STUFF
>;END TOPS10

	SUBTTL	D$DISM - STRUCTURE DISMOUNT PROCESSOR

	;CALL:	M/ The Dismount Message Address
	;
	;RET:	True Always

TOPS10	<
D$DISM::PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVX	S1,.STRDV		;GET THE STRUCTURE DEVICE BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	E$IMO##			;NOT THERE,,THATS AN ERROR
	HRROI	S1,0(S1)		;GET POINTER TO ASCIZ STRUCTURE NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	S1,S2			;PUT IT IN S1
	MOVE	P1,S1			;HERE ALSO
	PUSHJ	P,FNDISK		;FIND THE VOLUME IN THE VOL BLOCK
	JUMPF	DISM.2			;NOT THERE,,THATS AN ERROR
	LOAD	S2,.VLFLG(S1),VL.STA	;GET THE STRUCTURE STATUS BITS
	CAXE	S2,%STAMN		;IS IT MOUNTED ???
	JRST	DISM.1			;NO,,THATS AN ERROR
	MOVX	S2,%STADM		;GET THE DISMOUNT STRUCTURE STATUS BITS
	STORE	S2,.VLFLG(S1),VL.STA	;SET IT IN STRUCTURE BLOCK
	LOAD	S2,.OFLAG(M),.DMRMV	;GET THE /REMOVE BIT
	STORE	S2,.VLFLG(S1),VL.REM	;AND SAVE IT
	MOVX	S2,.DMNCK		;GET THE /NOCHECK FLAG BIT
	TDNN	S2,.OFLAG(M)		;DID HE SPECIFY NO CHECK ???
	SETZM	S2			;NO,,CLEAR IT !!!
	PUSHJ	P,SNDDSM		;SEND DISMOUNT MESSAGE TO TAPE LABELER
	$RETT				;RETURN

DISM.1:	MOVEI	S1,[ASCIZ |is not mounted|] ;[1204] GET STRING ADDR
	CAXN	S2,%STADM		;[1204] DISMOUNT IN PROGRESS?
	MOVEI	S1,[ASCIZ |- dismount already in progress|] ;[1204] YES
	$ACK	(<Structure ^W/P1/ ^T/(S1)/>,,,.MSCOD(M),<$WTFLG(WT.SJI)>) ;[1204]
	$RETT				;RETURN

DISM.2:	$ACK	(Structure ^W/P1/ does not exist,,,.MSCOD(M),<$WTFLG(WT.SJI)>)
	$RETT				;RETURN

>
	SUBTTL	VLUNLO - Unload a unit and break UCB-VOL links

	;CALL:	S1/ The Volume Block Address
	;
	;RET:	True Always

	;This routine will break the VOL - UCB links and request PULSAR
	;	to unload the drive. In addition, if there are no more
	;	requestors for the volume, the volume block is deleted.
	;	Alternate entry - VLBREAK which just breaks the
	;	UCB - VOL link, but does not unload.

TOPS10<
VLBREA: TDZA	S2,S2			;INDICATE 'JUST BREAK' ENTRY
VLUNLO:	MOVEI	S2,1			;INDICATE 'BREAK AND UNLOAD ENTRY'
	$SAVE	<P1>			;SAVE P1 FOR A SECOND
	MOVE	P1,S2			;SAVE THE ENTRY FLAG
	MOVE	S2,.VLUCB(S1)		;GET THE UCB ADDRESS IN S2
	ZERO	.UCBVL(S2)		;DELINK UCB FROM THE VOL
	ZERO	.VLUCB(S1)		;DELINK THE VOL FROM THE UCB
	MOVX	TF,UC.OFL		;GET 'DEVICE OFFLINE' BIT
	IORM	TF,.UCBST(S2)		;LITE IT IN THE UCB
	MOVX	TF,%STAWT		;GET VOLUME WAITING STATUS CODE
	STORE	TF,.VLFLG(S1),VL.STA	;AND SET IT
	LOAD	TF,.VLOWN(S1),VL.CNT	;GET THE NUMBER OF REMAINING REQUESTORS
	EXCH	S1,S2			;GET S1=UCB, S2=VOL ADDRESS
	MOVE	S1,.UCBNM(S1)		;GET THE NAME OF THE UNIT
	JUMPN	TF,VLUN.1		;ANY MORE REQUESTORS ?? YES, KEEP VOL
	PUSH	P,S1			;SAVE UNIT NAME
	MOVE	S1,S2			;GET THE VOL ADDRESS IN S1
	PUSHJ	P,DELVOL		;AND DELETE THE VOLUME
	POP	P,S1			;GET BACK UNIT NAME
VLUN.1:	JUMPE	P1,.RETT		;IF VLBREAK ENTRY, QUIT
	PJRST	UNLOAD			;IF VLUNLO ENTRY, GO UNLOAD THE TAPE
>;END TOPS10
	SUBTTL	D$DELE - ROUTINE TO DELETE REQUESTS FROM THE MOUNT QUEUE

	;CALL:	M/ The Delete Message Address
	;
	;RET:	True if deleted, False otherwise

TOPS10 <
D$DELE::PUSHJ	P,.SAVE4		;SAVE P1 - P4
	MOVX	S1,.ORREA		;GET THE REASON BLOCK TYPE
	SETZM	P4			;DEFAULT TO NO REASON BLOCK
	PUSHJ	P,A$FNDB##		;FIND IT
	SKIPF				;LOSE,,SKIP
	MOVE	P4,S1			;SAVE THE REASON BLOCK ADDRESS
	MOVEI	P1,1			;GET THE BLOCK COUNT
DELZ.1:	MOVE	S1,[EXP .ORREQ,.STRDV,](P1)  ;GET THE BLK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT
	JUMPT	@[EXP DELRID,DELSTR](P1) ;FOUND,,PROCESS IT
	SOJGE	P1,DELZ.1		;NOT FOUND,,TRY NEXT
	SETZM	MDAOBJ+OBJ.UN		;ZAP THE UNIT WORD OF MDA OBJECT BLK
	PJRST	E$IMO##			;RETURN INVALID MESSAGE FROM ORION




	;Routine to delete a mount request by request ID

DELRID:	MOVE	S1,0(S1)		;GET THE REQUEST ID
	CAMN	S1,[-1]			;IS THIS ALL REQUESTS ???
	JRST	DELALL			;YES,,OK YOU ASKED FOR IT !!!
	MOVE	P1,S1			;NO,,SAVE IT
	PUSHJ	P,FNDVSL		;LOCATE THE REQUEST
	JUMPF	DELD.1			;NOT THERE,,RETURN AN ERROR
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	PUSHJ	P,CHKOWN		;DOES HE ALREADY OWN THE VOLUME ???
	JUMPT	DELD.0			;YES,,CAN'T DO THIS
	MOVE	S1,P1			;GET THE VSL ADDRESS BACK
	PUSHJ	P,DELREQ		;DELETE THE REQUEST
	$RET				;AND RETURN

DELD.0:	MOVE	P1,.VSRID(P1)		;PICK UP THE REQUEST ID
DELD.1:	$ACK	(<Mount request #^D/P1/ does not exist>,,,.MSCOD(M))
	$RETT				;RETURN


	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE


	;Routine to delete all pending mount requests

DELALL:	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST
	JRST	DELA.2			;JUMP THE FIRST TIME THROUGH

DELA.1:	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT ENTRY
DELA.2:	JUMPF	.RETT			;DONE,,RETURN
	MOVE	P1,S2			;SAVE THE VSL ADDRESS
	LOAD	S1,.VSFLG(P1),VS.NMT	;GET THE PSEUDO MOUNTED FLAG BIT
	JUMPN	S1,DELA.1		;IF SET,,GET NEXT VSL
	MOVE	S1,P1			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,CHKOWN		;DOES THIS GUY OWN THIS VOLUME ???
	JUMPT	DELA.1			;YES,,GET THE NEXT VSL
	MOVE	S1,P1			;NO,,GET THE VSL ADDRESS IN S1
	PUSHJ	P,DELREQ		;DELETE THE REQUEST
	JRST	DELA.1			;AND GO GET ANOTHER



	;Routine to delete all requests for a specific structure

DELSTR:	HRROI	S1,0(S1)		;GET THE STRUCTURE NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVEM	S2,MDAOBJ+OBJ.UN	;SAVE IT
	MOVE	S1,S2			;GET IT IN S1
	PUSHJ	P,D$FNDV		;LOCATE IT
	JUMPF	E$NSD##			;NOT THERE,,RETURN NO SUCH DEVICE
	MOVE	P1,S1			;SAVE THE VOL ADDRESS
	SETZM	P3			;CLEAR REQUEST DELETION COUNTER
DELS.1:	LOAD	P2,.VLOWN(P1),VL.CNT	;GET THE REQUESTOR COUNT
	JUMPE	P2,DELS.3		;NO MORE,,FINISH UP
	MOVNS	P2			;NEGATE IT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.VLVSL(P1)		;CREATE AOBJN SEARCH AC
DELS.2:	MOVE	S1,0(P2)		;GET A REQUESTED VSL
	TXNN	S1,VL.ASN+VL.ASK	;ASSIGNED OR REQUESTED ???
	JRST	[PUSHJ	P,DELREQ	;NO,,DELETE IT !!!
		 AOS	P3		;BUMP DELETION COUNTER
		 JRST	DELS.1 ]	;START OVER
	AOBJN	P2,DELS.2		;TRY NEXT REQUESTOR
DELS.3:	JUMPN	P3,.RETT		;DELETED SOME,,RETURN
	$ACK	(No requests for this structure deleted,,MDAOBJ,.MSCOD(M))
	$RETT				;RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE


	;Routine to delete the VSL pointed to by S1

DELREQ:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVEI	P1,(S1)			;SAVE THE VSL ADDRESS
	MOVE	AP,.VSMDR(P1)		;SETUP THE MDR ADDRESS
	DOSCHD				;FORCE A SCHEDEULING PASS
	PUSH	P,T1			;SAVE T1
	MOVE	T1,P1			;COPY VSL ADDRESS
	MOVEI	S2,DEMOB		;ASSUME A PSEUDO-PROCESS
	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE PROCESS JOB NUMBER
	TXC	S1,BA%JOB		;SWAP REQUEST STATES
	TXNE	S1,BA%JOB		;IS THIS A REAL REQUEST ???
	MOVEI	S2,DEMOT		;NO--NORMAL TIMESHARING
	$ACK	(<Mount request #^D/.VSRID(P1)/ cancelled>,<^I/(S2)/^M^JVolume-set-name: ^T/.VSVSN(P1)/>,,.MSCOD(M))
	POP	P,T1			;RESTORE T1
	PUSHJ	P,MDASBP		;SET UP FOR CALLS TO MDADBP
;**;[1162] Insert 3 lines after DELREQ+11L. 29-Nov-83 /LWS
	MOVE	S1,.VSFLG(P1)		;[1162] GET VSL FLAGS
	TXNE	S1,VS.VSW		;[1162] SWITCHING VOLUMES?
	JRST	DELVSW			;[1162] YES,,PROCESS DIFFERENTLY !!!
	$TEXT	(MDADBP,<Mount request ^T/.VSVSN(P1)/ canceled by the operator^A>)
	SKIPE	P4			;NO REASON,,SKIP
	$TEXT	(MDADBP,<^M^JReason:^T/0(P4)/^A>) ;ADD THE REASON
	SETZM	S1			;GET A NULL BYTE 
	IDPB	S1,MDBPTR		;MAKE THE MESSAGE TEXT ASCIZ
	SETOM	ERRACK			;INDICATE THIS IS AN ERROR ACK
	MOVE	S1,P1			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;TELL THE SAD STORY TO THE USER
	MOVE	S1,.VSFLG(P1)		;[1164] GET VSL FLAGS
	TXNN	S1,VS.INI		;[1164] REINIT'ING?
	JRST	DELR.0			;[1164] NO,,CONTINUE
	MOVE	S1,.VSVOL(P1)		;[1164] YES,,GET ADDR OF 1ST VOL BLOCK
	MOVE	TF,S1			;[1164] SAVE VOL BLOCK ADDR
	SKIPN	S1,.VLUCB(S1)		;[1164] GET UCB BLOCK ADDR
	JRST	DELR.0			;[1164] NOT THERE,,OH WELL
	MOVX	S2,UC.INI		;[1164] GET UCB INI STATUS BIT
	ANDCAM	S2,.UCBST(S1)		;[1164] CLEAR THE BIT
	MOVE	S1,TF			;[1164] GET VOL BLOCK ADDR BACK
	PUSHJ	P,VLBREA		;[1164] GO BREAK VOL/UCB LINK
DELR.0:	MOVE	S1,P1			;[1164] GET THE VSL ADDRESS
	LOAD	P1,.VSLNK(P1),VS.LNK	;GET THIS VSL'S LINK CODE
	PUSHJ	P,DELVSL		;DELETE THIS REQUEST
	LOAD	S2,.MRCNT(AP),MR.CNT	;GET THE USERS REQUEST COUNT
	JUMPE	S2,DELMDR		;NOTHING LEFT,,DELETE THE MDR
	MOVNS	S2			;NEGATE IT
	MOVSS	S2			;MOVE RIGHT TO LEFT
	HRRI	S2,.MRVSL(AP)		;CREATE VSL AOBJN SEARCH AC

DELR.1:	MOVE	S1,0(S2)		;GET A VSL ADDRESS
	LOAD	TF,.VSLNK(S1),VS.LNK	;GET ITS LINK CODE
	CAMN	TF,P1			;DOES IT MATCH THE ONE WE CANCELED ???
	PJRST	MNTVSL			;YES,,RETRY THE MOUNT
	AOBJN	S2,DELR.1		;NO,,TRY NEXT VSL
	$RETT				;AND RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE


	;Here if user was switching volumes
	;S1 = VSL flag bits !!!

DELVSW:	$SAVE	<T1,T2>			;[1162] SAVE T1 AND T2
	MOVE	T1,S1			;[1162] COPY VSL FLAGS
	TXNN	S1,VS.ALB		;[1162] IS PULSAR THE ONE?
	SKIPA	S2,[[ASCIZ\operator\]]	;[1162] NO,,OPERATOR IS CANCELING
	MOVEI	S2,[ASCIZ\tape labeler\];[1162] YES,,GET CORRECT STRING ADDRESS
	TXZ	S1,VS.VSW!VS.ALB	;[1162] NOT SWITCHING VOLS ANYMORE
	TXO	S1,VS.ABO		;[1162] WE'RE NOW ABORTED
	MOVEM	S1,.VSFLG(P1)		;[1162] UPDATE FLAGS
	$TEXT	(MDADBP,<Volume switch request ^T/.VSVSN(P1)/ canceled by the ^T/(S2)/^A>) ;[1162]
	SKIPE	P4			;NO REASON,,SKIP
	$TEXT	(MDADBP,<^M^JReason:^T/0(P4)/^A>) ;ADD THE REASON
	SETZM	S1			;GET A NULL BYTE
	IDPB	S1,MDBPTR		;MAKE THE MESSAGE TEXT ASCIZ
	SETOM	ERRACK			;INDICATE THIS IS AN ERROR ACK
	MOVE	S1,P1			;[1173] GET VSL ADDRESS
	SETZM	S2			;[1173] USE VSL ACK DATA
	PUSHJ	P,USRNOT		;TELL THE SAD STORY TO THE USER
	MOVE	S1,.VSUCB(P1)		;GET THE UNIT HE CURRENTLY OWNS
	MOVX	S2,UC.VSW		;GET UNIT VOL SWITCH STATUS
	ANDCAM	S2,.UCBST(S1)		;CLEAR IT
	TXNE	T1,VS.ALB		;[1162] ABORTED BY PULSAR?
	JRST	DEL.V1			;[1162] YES,,ALREADY OUT OF 'EW'
	MOVX	S2,%VABT		;GET 'CANCELLED' STATUS
	PUSHJ	P,VSREOV		;GET USER OUT OF 'EW'
DEL.V1:	LOAD	T1,.VSCVL(P1),VS.OFF	;[1162] GET OFFSET TO VOL HE CAN'T HAVE
	LOAD	T2,.VSCVL(P1),VS.PRE	;[1162] GET OFFSET TO VOL HE'S KEEPING
	STORE	T2,.VSCVL(P1),VS.OFF	;[1162] SET CURRENT OFFSET TO PREVIOUS ONE

; Put things back together for tape user is stuck with because of
; volume switch abort.

	MOVE	S1,P1			;[1162] GET VSL ADDRESS
	PUSHJ	P,CHKOWN		;[1162] GET VOL BLOCK POINTER TO VSL ADDR
	MOVX	S2,VL.ASN		;[1162] GET ASSIGNED BIT
	IORM	S2,0(S1)		;[1162] INDICATE THE OLD VOL STILL ASSIGNED
	PUSHJ	P,D$CMTX		;[1162] LOCATE THE GUY'S 'C' MATRIX ENTRY
	ADDI	T2,.VSVOL(P1)		;[1162] GET ITS VOL BLOCK POINTER ADDR
	MOVE	S1,(T2)			;[1162] PUT ADDR INTO S1 FOR D$TVSR
	PUSHJ	P,D$TVRS		;[1162] CONVERT TO RESOURCE NUMBER
	MOVE	S2,P1			;[1162] GET VSL ADDRESS
	PUSHJ	P,ADDAMA		;[1162] PUT VOLUME BACK IN 'A' MATRIX
	PUSHJ	P,ADDCMA		;[1162] PUT VOLUME BACK IN 'C' MATRIX

; If user was trying to extend volume set make sure "scratch" vol
; block is deleted.

	ADDI	T1,.VSVOL(P1)		;[1162] POINT AT THE VOL BLOCK ADDR OF TAPE HE CAN'T HAVE
	MOVE	S2,0(T1)		;[1162] GET THE VOL BLOCK ADDRESS
	LOAD	S1,.VLFLG(S2),VL.SCR	;[1162] GET SCRATCH BIT
	JUMPE	S1,.RETT		;[1162] SCRATCH??? NO, RETURN
	SETZM	0(T1)			;[1162] YES, ZAP THE VOL BLOCK ADDRESS
	DECR	.VSCVL(P1),VS.CNT	;SUBTRACT 1 FROM VOLUME COUNT
	MOVE	S1,VOLQUE		;GET THE VOL QUEUE ID
	PUSHJ	P,L%APOS		;POSITION TO THE VOL BLOCK
	PUSHJ	P,L%DENT		;AND DELETE IT
	$RETT				;RETURN
>;END TOPS10
	SUBTTL	D$SMDA - Set tape drive un/available/ initialize

	;CALL:	M/ The message Address
	;
	;RET:	True Always

TOPS10<
D$SMDA::$SAVE	<P1,P2>			;SAVE SOME SPACE
	MOVX	S1,.TAPDV		;CODE TO FIND A TAPE DEVICE BLOCK
	PUSHJ	P,A$FNDB##		;FIND THAT IN THE MESSAGE
	JUMPF	E$IMO##			;CAN'T THAT'S AN ERROR
	MOVE	P2,S1			;SAVE ADDR OF ASCII DEVICE NAME
	SETZM	P1			;ASSUME WE ARE 'SET AVAILABLE'
	MOVX	S1,.DVAVL		;CODE FOR SET AVAILABLE
	PUSHJ	P,A$FNDB##		;TRY TO FIND THAT ONE
	JUMPT	STAP.1			;SET AVAILABLE.. GO DO IT
	MOVEI	P1,1			;MAKE IT 'SET UNAVAILABLE'
	MOVX	S1,.DVUAV		;CODE FOR SET UNAVAILABLE
	PUSHJ	P,A$FNDB##		;TRY FOR THAT ONE
	JUMPF	STAP.3			;NEITHER OF THOSE, PERHAPS INITIALIZE

	;Here to set unavailable

	MOVE	S1,P2			;GET BACK ADDR OF ASCII DEV NAME
	PUSHJ	P,FNDUCB		;FIND THE AVAILABLE UCB
	JUMPF	.RETF			;CAN'T... GO AWAY AND COMPLAIN
	MOVE	P2,S1			;FOUND THE UCB.. SAVE IT
	SKIPE	S1,.UCBVS(P2)		;ANY OWNERS FOR THIS UNIT ???
	 $ERJMP	MD$VAU,S1		;YES,,CAN THE REQUEST
	MOVEI	S1,[ITEXT (<Drive is currently initializing>)] ;[1472]
	LOAD	S2,.UCBST(P2),UC.INI	;[1472] GET THE INIT BIT FOR THIS DRIVE
	JUMPN	S2,STAP.E		;[1472] IF INITIALIZING, CAN'T SET UNAVAILABLE
	MOVE	S1,P2			;[1472] GET THE UCB ADDRESS IN S1
	PUSHJ	P,D$DECA		;[1472] DECREMENT THE 'A' MATRIX
	PUSHJ	P,DEADLK		;[1472] CHECK WITH DEADLOCK AVOIDANCE ROUTINE
	JUMPT	STAP.0			;[1472] IF OK, CONTINUE ON
	$WTO	(<^T/BELLS/Potential system deadlock detected>,<Cannot set unit ^W/.UCBNM(P2)/ unavailable>,,<$WTFLG(WT.SJI)>) ;[1472]
	MOVE	S1,P2			;[1472] GET UCB ADDRESS AGAIN
	PUSHJ	P,D$INCA		;[1472] MAKE RESOURCE COUNT CORRECT
	PUSHJ	P,DEADLK		;[1472] LET'S BE PARANOID
	$RETIT
	STOPCD	(UDL,HALT,,<Undeserved deadlock in D$SMDA>) ;[1472]

STAP.0:	SKIPE	S1,.UCBVL(P2)		;[1472] AIM AT THE VOLUME
	PUSHJ	P,VLBREA		;DELINK THIS VOLUME
	MOVE	S1,.UCBNM(P2)		;GET THE UNIT NAME
	PUSHJ	P,I$MDAC##		;CLEAR DVCMDA MONITOR BIT
	MOVX	S2,UC.AVA		;GET AVAILABLE BITS
	ANDCAM	S2,.UCBST(P2)		;CLEAR IT
	MOVEI	S1,[ITEXT (< Unavailable for use >)]
	PJRST	STAP.E			;[1472] ACK THE OPR
	;Here to set available

STAP.1:	MOVE	S1,P2			;GET BACK ADDR OF ASCII DEVICE NAME
	PUSHJ	P,LOCUCB		;FIND UCB, UNAVAILABLE OR NOT
	JUMPF	.RETF			;COULDN'T... MUST BE BAD DEVICE
	MOVE	P2,S1			;FOUND IT.. SAVE ADDR OF UCB
	LOAD	S2,.UCBST(P2),UC.AVA	;GET THE AVAILABLE BIT
	JUMPN	S2,[MOVEI S1,[ITEXT (< Already available for use >)]
		    PJRST STAP.E ]	;ALREADY AVAILABLE,,TELL OPR AND RETURN
	PUSHJ	P,I$GATR##		;GET THE DEVICE ATTRIBUTES
	LOAD	S2,.UCBST(P2),UC.AVA	;GET THE AVAILABLE BIT
	JUMPE	S2,STAP.6		;SET AVAILABLE LOST,,COMPLAIN AND QUIT
	MOVEI	S1,[ITEXT (< Available for use >)]
	PUSHJ	P,STAP.E		;TELL THE OPR
	MOVE	S1,.UCBNM(P2)		;GET THE UNIT NAME
	MOVX	S2,UC.AVR		;GET THE AVR BIT
	TDNE	S2,.UCBST(P2)		;NEED TO KICK PULSAR FOR AVR ???
	PUSHJ	P,SNDREC		;YES,,SEND A RECOGNIZE MSG TO PULSAR
	MOVE	S1,P2			;GET THE UCB ADDRESS IN S1
	PUSHJ	P,D$INCA		;INCRIMENT THE 'A' MATRIX
	$RETT				;RETURN

	;Here to see if it is a SET TAP x INITIALIZE

STAP.3:	MOVX	S1,.DVINI		;GET BLOCK TYPE - INTIALIZE
	PUSHJ	P,A$FNDB##		;TRY FOR THAT BLOCK
	JUMPF	E$IMO##			;CAN'T, SO COMPLAIN
	MOVE	S1,P2			;GET BACK ADRS OF DRIVE NAME
	PUSHJ	P,FNDUCB		;FIND THIS GUY'S DATA BASE
	JUMPF	.POPJ			;NOT THERE??!! OH WELL
	MOVE	P2,S1			;SAVE ADRS OF UCB
	MOVX	S1,.SIABO		;GET BLOCK TYPE - /ABORT
	PUSHJ	P,A$FNDB##		;TRY FOR THAT BLOCK
	JUMPT	STAP.5			;FOUND IT,,ABORT THE INITIALIZATION
	MOVEI	S1,[ITEXT (<Already initializing>)]
	MOVE	S2,.UCBST(P2)		;GET DRIVE STATUS
	TXNE	S2,UC.INI		;ALREADY BEEN HERE?
	JRST	STAP.E			;YES, TELL THE OPR THAT
	MOVEI	S1,[ITEXT (<Unavailable for initialization>)]
	TXNN	S2,UC.AVA		;IS DRIVE SET UNAVAILABLE?
	JRST	STAP.E			;TELL THE OPR THE BAD NEWS
	MOVX	S1,UC.VSW		;GET THE VOLUME SWITCH STATE BIT
	TDNN	S1,.UCBST(P2)		;IF SWITCHING REELS,,LETERRIP !!
	SKIPN	S1,.UCBVL(P2)		;GET ADRS OF LOADED VOL BLOCK
	JRST	STAP.4			;NO VOL BLOCK, DO THE INITIALIZE
	PUSHJ	P,FNDOWN		;FIND THIS VOL'S OWNER
	SKIPF				;SKIP IF UNOWNED
	$ERJMP	MD$VAU			;THERE IS ONE! CAN'T INIT THAT TAPE
	MOVE	S1,.UCBVL(P2)		;NO OWNER, AIM AT VOL BLOCK AGAIN
	PUSHJ	P,VLBREA		;BREAK THIS VOL - UCB LINK
STAP.4:	MOVX	S1,UC.INI		;GET THE INITIALIZING BIT
	IORM	S1,.UCBST(P2)		;LITE SO OTHERS WILL SEE
	PJRST	I$FPLR##		;LET PULSAR DO THE WORK

	;Here for /ABORT processing

STAP.5:	MOVX	S1,UC.INI		;GET THE INITIALIZATION BIT
	ANDCAM	S1,.UCBST(P2)		;CLEAR IT
	PJRST	I$FPLR##		;TELL PULSAR NOT TO CONTINUE

	;Here for could not set available

STAP.6:	MOVE	S1,.UCBNM(P2)		;GET THE DEVICE NAME
	PUSHJ	P,I$GOWN##		;TRY TO FIND THE OWNER
	MOVEI	P1,(S1)			;SAVE THE NUMBER IF ANY
	MOVEI	S1,[ITEXT (<Could not set device available for use>)]
	MOVEI	S2,[ITEXT (<Device ^W/.UCBNM(P2)/ already owned by job ^D/P1/>)]
	SKIPT				;IF OWNED,,GO FINISH UP
	MOVEI	S2,[ITEXT (<No such device or error determining owning job number>)]
	$ACK	(<^I/0(S1)/>,<^I/0(S2)/>,MDAOBJ,.MSCOD(M))
	$RETT
	
STAP.E:	$ACK	(<^I/0(S1)/>,,MDAOBJ,.MSCOD(M))
	$RETT				;RETURN
>;END TOPS10

	SUBTTL	D$VSR - VOLUME SWITCH REQUEST FROM PULSAR

	;CALL:	M/ The VSR Message Address
	;
	;RET:	True Always

TOPS10<
D$VSR::	PUSHJ	P,.SAVE4		;SAVE SOME AC'S FOR A MINUTE
	MOVX	S1,.RECDV		;GET THE DEVICE BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	MISC.3			;NOT THERE,,PULSAR MESSAGE ERROR
	MOVE	S1,0(S1)		;GET THE SIXBIT DEVICE NAME
	PUSHJ	P,UCBFND		;FIND ITS UCB ENTRY
	JUMPF	.RETF			;NOT THERE,,JUST RETURN
	MOVE	P1,S1			;SAVE THE UCB ADDRESS
	SKIPN	P2,.UCBVS(P1)		;GET THE OWNERS VSL ADDRESS
	 PJRST	[MOVE  S1,P1		;NONE,,THATS WIERD !!!
		 MOVX  S2,%VTMV		;   GET 'TOO MANY VOLUMES' STATUS
		 PJRST VSREOV ]		;   END EXIT THROUGH VSREOV
	MOVE	AP,.VSMDR(P2)		;GET THE OWNER MDR ADDRESS
;**;[1133]ADD 6 LINES AFTER D$VSR:+12 LINES	2-JUN-83/CTK
	MOVE	S1,.UCBNM(P1)		;[1133]GET TAPE DRIVE NAME
	PUSHJ	P,I$GDEN##		;[1133]READ DENSITY
	 JUMPF	VSR.T1			;[1133]FAILED!!!
	STORE	S2,.VSATR(P2),VS.DEN	;[1133]AND STORE
	MOVE	T1,.UCBVL(P1)		;[1133]GET VL POINTER
	STORE	S2,.VLFLG(T1),VL.DEN	;[1133]AND STORE
VSR.T1:	MOVX	S1,.RLVOL		;[1133]GET RELATIVE VOLUME BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN OUR MESSAGE
	JUMPF	MISC.3			;NOT THERE,,ANOTHER PULSAR ERROR
	MOVE	S2,0(S1)		;GET THE BLOCK DATA IN S2
	SETZM	P4			;DEFAULT TO READING THE VOLUME SET
	TXNE	S2,%VWRT		;IS HE WRITING THE VOLUME SET ???
	SETOM	P4			;YES,,INDICATE WRITING VOLUME
	LOAD	S2,S2,RLV.CD		;GET THE OFFSET CODE FOR THE NEXT VOLUME
;**;[1162] Redo code after D$VSR+18L (approx). 29-Nov-83 /LWS
	CAXE	S2,%RLABO		;[1162] SHOULD WE ABORT THE SWITCH?
	JRST	VSR.T2			;[1162] NO...
	MOVX	S1,VS.ALB		;[1162] YES,,GET ABORTED BY TAPE LBLR BIT
	IORM	S1,.VSFLG(P2)		;[1162] LITE IT IN VSL FLAG WORD
	SETZM	P4			;[1162] NO REASON
	MOVE	S1,P2			;[1162] GET VSL ADDRESS
	PJRST	DELREQ			;[1162] GO DELETE VOLUME SWITCH

VSR.T2:	LOAD	T1,.VSCVL(P2),VS.OFF	;[1162] GET THE OFFSET TO THE CURRENT VOLUME
	MOVE	P3,T1			;[1162] WILL BE USED AS PREVIOUS LATER
	CAXN	S2,%RLNXT		;DO WE WANT THE NEXT VOLUME ???
	ADDI	T1,1			;YES,,BUMP OFFSET BY 1
	CAXN	S2,%RLPRV		;DO WE WANT THE PREVIOUS VOLUME ???
	SUBI	T1,1			;YES,,DECRIMENT OFFSET BY 1
	CAXN	S2,%RLFIR		;DO WE WANT THE FIRST VOLUME ???
	SETZM	T1			;YES,,OFFSET IS 0

	SKIPGE	T1			;OFFSET CAN'T BE NEGATIVE !!
	STOPCD	(ONV,HALT,,<Offset of new volume is invalid>) ;LEAVE THIS FOR A WHILE

	;P4 = -1 Writing Volume Set. 
	;P4 =  0 Reading Volume Set.
	;P4 =  1 Extending Volume Set.

	LOAD	S2,.VSCVL(P2),VS.CNT	;GET THE VOLUME COUNT IN S2
	CAIG	T1,-1(S2)		;NEW OFFSET MUST BE LESS OR EQUAL
	JRST	VSR.0			;OK,,SKIP THIS
	CAILE	T1,^D60			;MORE THEN 60 VOLUMES ???
	PJRST	[MOVE  S1,P1		;YES,,GET THE UCB ADDRESS IN S1
		 MOVX  S2,%VTMV		;GET 'TOO MANY VOLUMES' STATUS
		 PJRST VSREOV ]		;END EXIT THROUGH VSREOV
	MOVE	S1,P1			;GET THE UCB ADDRESS IN S1
	MOVX	S2,%VEOF		;GET 'END OF FILE' STATUS
	JUMPE	P4,VSREOV		;P4=0,,SEND EOV MSG TO PULSAR
	MOVEI	P4,1			;SET FLAG INDICATING VOL SET EXTENSION

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

VSR.0:	MOVE	S1,.UCBNM(P1)		;GET THE DEVICE NAME IN S1
	PUSHJ	P,REWIND		;REWIND THE LAST VOLUME
;;	LOAD	S1,.VSFLG(P2),VS.ABO	;GET ABORTED BY OPERATOR STATUS
;;	JUMPN	S1,VSR.1		;IF ABORTED,,DON'T DEALLOCATE

	;Deallocate the current volume Resource Number

	PUSHJ	P,D$CMTX		;LOCATE THIS GUYS 'C' MATRIX ENTRY
	LOAD	S1,.VSCVL(P2),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	S1,.VSVOL(P2)		;POINT TO ITS ADDRESS
	MOVE	S1,0(S1)		;GET THE CURRENT VOLUME ADDRESS
	PUSHJ	P,D$TVRS		;CONVERT TO A VOLUME RESOURCE NUMBER
	MOVE	S2,P2			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,SUBAMA		;REMOVE FROM THE 'A' MATRIX
	PUSHJ	P,SUBCMA		;REMOVE FROM THE 'C' MATRIX
	MOVE	S1,P2			;GET THE VSL ADDRESS
	PUSHJ	P,CLROWN		;CLEAR OWNERSHIP FLAG

	;Update the VSL status

VSR.1:	MOVX	S1,UC.VSW		;GET THE VOLUME SWITCH STATUS BITS
	IORM	S1,.UCBST(P1)		;LITE IT IN THE UCB
	MOVX	S1,VS.VSW		;GET THE VOLUME SWITCH STATUS BITS
	IORM	S1,.VSFLG(P2)		;LITE IT IN THE VSL
	MOVX	S1,VS.ABO		;GET ABORT FLAG
	ANDCAM	S1,.VSFLG(P2)		;CLEAR IT
	MOVEM	P1,.VSUCB(P2)		;LINK THIS UCB TO THIS VSL
	STORE	T1,.VSCVL(P2),VS.OFF	;SAVE THE OFFSET TO THE NEW VOLUME
;**;[1162] Insert 1 line at VSR.1+7L . 18-Oct-83 /LWS
	STORE	P3,.VSCVL(P2),VS.PRE	;[1162]SAVE OFFSET OF PREVIOUS VOL, TOO
	JUMPG	P4,VSR.2		;IF EXTENDING VOLUME SET,,SKIP THIS

	MOVE	S1,P2			;GET THE VSL ADDRESS
	PUSHJ	P,MNTVSR		;TRY TO MOUNT THE NEXT VOLUME
	$RETT				;WIN OR LOSE, KEEP GOING

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here if we need the next volume in the volume set and there are no
	;more volumes in the VSL. If reading the volume set, return EOV. If
	;writing the volume set, generate a new VOL block for another volume
	;and ask the OPR to mount another volume. Only add volumes up
	;to a max of 60, after which send the EOV msg to PULSAR.

VSR.2:	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	MOVE	S2,P2			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,L%APOS		;POSITION TO THE VSL IN THE QUEUE
	PUSHJ	P,L%SIZE		;GET THIS VSL'S LENGTH (IN S2)
	MOVE	P4,S2			;SAVE THE OLD VSL LENGTH
	ADDI	S2,1			;ADD 1 FOR NEW VOL BLOCK
	PUSHJ	P,L%CENT		;CREATE A NEW VSL FOR THIS GUY
	MOVE	P3,S2			;SAVE THE NEW VSL ADDRESS
	HRL	S2,P2			;GET OLD VSL ADDR,,NEW VSL ADDR
	ADDI	P4,-1(P3)		;GET NEW VSL END -1
	BLT	S2,0(P4)		;COPY OLD VSL TO NEW VSL
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	MOVE	S2,P2			;GET THE OLD VSL ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO THE OLD VSL
	PUSHJ	P,L%DENT		;AND DELETE IT !!!
	MOVE	AP,.VSMDR(P3)		;GET THE MDR ADDRESS
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	MOVNS	S1			;NEGATE IT
	MOVSS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.MRVSL(AP)		;CREATE AOBJN FOR VSL LIST

VSR.2A:	CAMN	P2,0(S1)		;IS THIS THE VSL WE WANT ???
	MOVEM	P3,0(S1)		;YES,,CHANGE OLD VSL PTR TO NEW VSL
	AOBJN	S1,VSR.2A		;CHECK AGAIN

	LOAD	S1,.VSCVL(P3),VS.CNT	;GET THE VOL COUNT FOR THIS VSL
	MOVNS	S1			;NEGATE IT
	MOVSS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.VSVOL(P3)		;CREATE AOBJN FOR VOL LIST

VSR.3:	MOVE	P4,0(S1)		;GET FIRST/NEXT VOL ADDRESS IN P4
	LOAD	S2,.VLOWN(P4),VL.CNT	;GET THE VSL COUNT FOR THIS VOLUME
	MOVNS	S2			;NEGATE IT
	MOVSS	S2			;MOVE RIGHT TO LEFT
	HRRI	S2,.VLVSL(P4)		;CREATE AOBJN FOR VSL LIST

VSR.4:	CAIN	P2,@0(S2)		;IS THIS VOL POINTING AT OLD VSL ???
	JRST	[HRRM P3,0(S2)		;YES,,POINT IT AT THE NEW VSL
		 JRST  VSR.5  ]		;AND CONTINUE
	AOBJN	S2,VSR.4		;CONTINUE THROUGH ALL VSL'S
VSR.5:	AOBJN	S1,VSR.3		;CONTINUE THROUGH ALL VOL'S

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	MOVE	S1,.VSUCB(P3)		;GET THE DEVICE THIS GUY OWNS
	MOVEM	P3,.UCBVS(S1)		;AND POINT IT AT THE OWNERS NEW VSL
	MOVE	S1,P3			;GET OUR VSL ADDRESS
	PUSHJ	P,GENVOL		;CREATE A 'SCRATCH' VOL BLOCK

	LOAD	S1,.VSFLG(P3),VS.WLK	;GET THE WRITE LOCKED BIT 
	LOAD	S2,.VSFLG(P3),VS.LBT	;GET THE LABEL TYPE
	LOAD	P1,.VSATR(P3),VS.TRK	;GET THE TRACK STATUS
	LOAD	P2,.VSATR(P3),VS.DEN	;GET THE REQUESTED DENSITY
	$WTO	(<Magtape mount request #^D/.VSRID(P3)/>,<^I/DEMOT/^M^JVolume-set-name: ^T/.VSVSN(P3)/^T/MTAHDR/Scratch    ^T9/@WRTENA(S1)/^T9/@LABELS(S2)/^W6/TRK(P1)/^T/@DENSTY(P2)/^T/BELLS/>,,<$WTFLG(WT.SJI)>)
	$RETT				;NOTIFY THE OPERATOR AND RETURN
>
SUBTTL	D$XVSL - Extend a VSL


; Routine to extend a VSL
; Call:	MOVE	S1, VSL address
;	MOVE	S2, number of volumes to be added
;	PUSHJ	P,D$XVSL
;
; TRUE return:	VSL extended and volumes added, S1 points to new VSL
; FALSE return:	VSL extension failed for some reason

D$XVSL::PUSHJ	P,.SAVE4		;SAVE SOME ACS
	DMOVE	P1,S1			;COPY ARGUMENTS
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	MOVE	S2,P1			;GET THE OLD VSL ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO THE OLD VSL IN THE QUEUE
	PUSHJ	P,L%SIZE		;GET THE LENGTH OF THE OLD VSL
	MOVE	P4,S2			;SAVE THE OLD VSL LENGTH
	ADDI	S2,(P2)			;PLUS THE NUMBER OF NEW VOL BLOCKS
	PUSHJ	P,L%CENT		;CREATE A NEW VSL
	MOVE	P3,S2			;SAVE THE NEW VSL ADDRESS
	HRL	S2,P1			;GET OLD VSL ADDR,,NEW VSL ADDR
	ADDI	P4,-1(P3)		;GET NEW VSL END -1
	BLT	S2,0(P4)		;COPY OLD VSL TO NEW VSL
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	MOVE	S2,P1			;GET THE OLD VSL ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO THE OLD VSL
	PUSHJ	P,L%DENT		;AND DELETE IT !!!
; Here to fix up all MDR/VSL/VOL links
; The following ACs are setup:
;	P1 = old VSL address
;	P2 = number of new VOL blocks to create
;	P3 = new VSL address
;	P4 = scratch AC

	MOVE	S1,MDRQUE		;GET MDR QUEUE ID
	PUSHJ	P,L%FIRS		;FIND THE FIRST MDR
	JRST	XVSL.2			;ENTER MDR LOOP

XVSL.1:	MOVE	S1,MDRQUE		;GET MDR QUEUE ID
	PUSHJ	P,L%NEXT		;FIND THE NEXT ENTRY

XVSL.2:	JUMPF	XVSL.4			;ALMOST DONE IF NO MORE MDRS
	LOAD	S1,.MRCNT(S2),MR.CNT	;GET THE VSL COUNT
	MOVNS	S1			;NEGATE IT
	MOVSS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.MRVSL(S2)		;CREATE AOBJN FOR VSL LIST

XVSL.3:	CAMN	P1,0(S1)		;FOUND THE OLD VSL?
	MOVEM	P3,0(S1)		;YES--REPLACE WITH NEW VSL ADDRESS
	AOBJN	S1,XVSL.3		;LOOP THROUGH ALL VSLS FOR THIS MDR
	JRST	XVSL.1			;GO DO ANOTHER MDR

XVSL.4:	LOAD	S1,.VSCVL(P3),VS.CNT	;GET THE VOL COUNT FOR THIS VSL
	MOVNS	S1			;NEGATE IT
	MOVSS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.VSVOL(P3)		;CREATE AOBJN FOR VOL LIST

XVSL.5:	MOVE	P4,0(S1)		;GET FIRST/NEXT VOL ADDRESS IN P4
	LOAD	S2,.VLOWN(P4),VL.CNT	;GET THE VSL COUNT FOR THIS VOLUME
	MOVNS	S2			;NEGATE IT
	MOVSS	S2			;MOVE RIGHT TO LEFT
	HRRI	S2,.VLVSL(P4)		;CREATE AOBJN FOR VSL LIST

XVSL.6:	CAIN	P1,@0(S2)		;IS THIS VOL POINTING AT OLD VSL?
	JRST	XVSL.7			;YES
	AOBJN	S2,XVSL.6		;CONTINUE THROUGH ALL VSLS
	JRST	XVSL.8			;ONWARD

XVSL.7:	HRRM	P3,(S2)			;POINT VOL AT THE NEW VSL

XVSL.8:	AOBJN	S1,XVSL.5		;CONTINUE THROUGH ALL VOLS
XVSL.9:	MOVE	S1,VOLQUE		;GET THE VOLUME LIST QUEUE ID
	MOVX	S2,VOLLEN		;GET THE VOL ENTRY LENGTH
	PUSHJ	P,L%CENT		;CREATE SPACE FOR THE VOL ENTRY
	LOAD	S1,.VSCVL(P3),VS.CNT	;GET NUMBER OF VOLUMES SO FAR
	ADDI	S1,1			;PLUS ONE
	STORE	S1,.VSCVL(P3),VS.CNT	;UPDATE
	ADDI	S1,.VSVOL-1(P3)		;POINT TO THE VOL BLOCK ADDRESS
	MOVEM	S2,0(S1)		;LINK THE VOL TO THE VSL
	MOVEM	P3,.VLVSL(S2)		;LINK THE VSL TO THE VOL
	MOVX	S1,%STAWT		;GET 'WAITING' STATUS CODE
	STORE	S1,.VLFLG(S2),VL.STA	;SAVE IT IN THE VOL FLAG WORD
	MOVEI	S1,1			;ONE OWNER
	STORE	S1,.VLOWN(S2),VL.CNT	;SET COUNT IN VOL
	SOJG	P2,XVSL.9		;CREATE THE REQUESTED NUMBER OF VOLS
	MOVE	S1,P3			;RETURN THE NEW VSL ADDRESS IN S1
	$RETT				;RETURN
	SUBTTL	D$DVS - DISMOUNT/DEALLOCATE VOLUME SET PROCESSOR

	;CALL:	M/ The message Address
	;
	;RET:	True Always

TOPS10	<
D$DVS::	SKIPN	G$MDA##			;IS MDA SUPPORTED ???
	JRST	E$MDA##			;NO,,RETURN AN ERROR !!!
	PUSHJ	P,.SAVE3		;SAVE P1 - P3
	LOAD	S1,G$PRVS##,MR.JOB	;GET THE SENDERS JOB NUMBER
	PUSHJ	P,FNDMDR		;FIND HIS MDR
	JUMPF	E$SDY##			;NOT THERE,,THATS AN ERROR
	MOVE	S1,G$SND##		;GET THIS USERS PID
	MOVEM	S1,.MRPID(AP)		;SAVE IT FOR THE ACK
	MOVE	S1,.MSCOD(M)		;GET THE SENDERS ACK CODE
	MOVEM	S1,.MRACK(AP)		;SAVE IT
	SETZM	S1			;NO GENERAL ACK
	STORE	S1,.MRFLG(AP),MR.ACK	;SO CLEAR ACK FLAG BIT
;**;[1170] Insert 1 line after D$DVS+11L. 29-Dec-83 /LWS
	STORE	S1,.MRFLG(AP),MR.GFR	;[1170] CLEAR [SYSTEM]GOPHER BIT (CLEAN UP)
	LOAD	S1,.OFLAG(M),MM.WAT	;GET 'WAITING' FLAG BIT
	STORE	S1,.MRFLG(AP),MR.WAT	;SET/CLEAR IT
	LOAD	S1,.OFLAG(M),MM.NOT	;GET 'NOTIFY' FLAG BIT
	STORE	S1,.MRFLG(AP),MR.NOT	;SET/CLEAR IT
	LOAD	P3,.OFLAG(M),MM.DLC	;SET DISMOUNT(0)/DEALLOCATE(1)
	SETZM	STRVOL			;CLEAR VSL PROCESSED FLAG
	SETZM	G$MSG			;CLEAR THE MDA BUFFER
	MOVX	S1,.RECDV		;GET THE DEVICE NAME BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPT	DVS.3			;FOUND IT,,GO PROCESS IT
	MOVX	S1,.RCTVS		;GET THE VOLUME SET NAME BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	E$IFD##			;NOT THERE,,THATS AN ERROR
DVS.1:	MOVE	P2,S1			;SAVE THE VOLUME SET NAME ADDRESS

	;Here if he passed a Volume Set Name

DVS.2:	PUSHJ	P,FNDLNM		;LOOK FOR A VSL WITH THAT LOGICAL NAME
	JUMPT	DVS.5			;FOUND IT,,GO PROCESS THE VSL
	MOVE	S1,P2			;NOT FOUND,,POINT TO ASCIZ VOL SET NAME
	PUSHJ	P,FNDVSN		;LOOK FOR THE VSL WITH THIS NAME
	JUMPT	DVS.5			;FOUND IT,,GO PROCESS THIS VSL
	JRST	E$IVN##			;RETURN INVALID VOL SET NAME SPECIFIED

	;Here if he passed a device name

DVS.3:	MOVE	P2,0(S1)		;SAVE THE DEVICE NAME
	MOVE	S1,P2			;GET THE SIXBIT DEVICE NAME IN S1
	PUSHJ	P,UCBFND		;GET THE UCB FOR THIS DEVICE
	JUMPF	DVS.4			;NOT THERE,,TRY VOL SET/LOGICAL NAME
	MOVE	P1,S1			;SAVE THE UCB ADDRESS
	SKIPE	S1,.UCBVS(P1)		;CHECK AND LOAD THE OWNING VSL ADDRESS
	CAME	AP,.VSMDR(S1)		;DOES HE OWN THE DEVICE ???
	JRST	E$SDY##			;SPECIFIED DEVICE IS NOT HIS !!!
	PJRST	DVS.5			;HE OWNS THE DEVICE,,PROCESS THE VSL

	;CONTINUED ON THE NEXT PAGE
DVS.4:	$TEXT	(<-1,,TMPVSL>,<^W/P2/^0>) ;NO,,GEN ASCIZ VOL SET NAME
	MOVEI	S1,TMPVSL		;POINT TO THE VOL SET NAME
	JRST	DVS.1			;AND TRY TO FIND A VOL SET BY THAT NAME

	;Here to process the VSL whose address is in S1.

DVS.5:	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	SETZM	G$ACK##			;DO NOT ACK TWICE !!!
	PUSHJ	P,MDR2VS		;[1173] COPY VSL REQUEST DEPENDENT DATA
	SKIPN	S1,.VSUCB(P1)		;CHECK AND LOAD THE UNIT ADDRESS
	JRST	DVS.6			;NOT THERE,,CONTINUE ON
	LOAD	S2,.UCBST(S1),UC.DVT	;GET THE DEVICE TYPE
	CAXE	S2,%DISK		;IS IT A STRUCTURE ???
	JRST	DVS.7			;NO,,THATS AN ERROR
	MOVE	S1,P1			;GET THE VSL ADDRESS
	MOVX	S2,VS.ARD		;GET THE ALWAYS RECOMPUTE BIT
	ANDCAM	S2,.VSFLG(S1)		;CLEAR IT
	MOVE	S2,.VSVOL(S1)		;GET THE VOLUME BLOCK ADDRESS
	PUSHJ	P,DSLMSG		;GEN 'DELETE FROM SEARCH LIST' & SEND IT
	SKIPE	P3			;IS THIS A DEALLOCATE ???
	ZERO	.VSFLG(P1),VS.UAL	;YES,,ZAP THE USER ALLOCATE FLAG
	LOAD	S1,.OFLAG(M),MM.REM	;GET REMOVE STR FLAG BIT
	STORE	S1,.VSFLG(P1),VS.REM	;SET/CLEAR IT
	$RETT				;WAIT FOR PULSAR ACK !!!

DVS.6:	JUMPE	P3,DVS.6A		;IF DISMOUNT,,THATS AN ERROR
	$TEXT	(<-1,,G$MSG>,<Volume set ^T/.VSVSN(P1)/ has been Deallocated^M^J^0>)
	MOVE	S1,P1			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;ACK THE USER
	MOVE	S1,P1			;GET THE VSL ADDRESS
	LOAD	S2,.OFLAG(M),MM.REM	;GET /REMOVE STR FLAG BIT
	SKIPE	S2			;DID USER SPECIFY /REMOVE ???
	PUSHJ	P,TELREM		;YES,,TELL THE OPERATOR
	LOAD	S1,.VSFLG(P1),VS.ALC	;WERE WE JUST ALLOCATED ???
	SKIPN	S1			;YES,,DON'T BOTHER THE OPERATOR
	$WTO	(<Mount Request #^D/.VSRID(P1)/ cancelled by user>,<  ^I/DEMOT/^M^J  Volume-set-name: ^T/.VSVSN(P1)/>,,<$WTFLG(WT.SJI)>)
	MOVE	S1,P1			;GET THE VSL ADDRESS
	PUSHJ	P,DELVSL		;DEALLOCATE/DELETE THIS VOLUME SET
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	JUMPE	S1,DELMDR		;NO MORE,,DELETE THE MDR AND RETURN
	$RETT				;ELSE RETURN

DVS.6A:	$TEXT	(<-1,,G$MSG>,<Volume set ^T/.VSVSN(P1)/ is not Mounted^M^J^0>)
	SETOM	ERRACK			;INDICATE THIS IS AN ERROR
	MOVE	S1,P1			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;TELL THE USER
	$RETT				;AND RETURN

DVS.7:	MOVEI	S2,[ASCIZ/Dismount/]	;DEFAULT TO A DISMOUNT
	SKIPE	P3			;UNLESS IT IS DEALLOCATE
	MOVEI	S2,[ASCIZ/Deallocate/]	;  THEN MAKE IT DEALLOCATE
	$TEXT	(<-1,,G$MSG>,<Can't ^T/0(S2)/ volume set ^T/.VSVSN(P1)/^M^J Unit ^W/.UCBNM(S1)/ must be deassigned^M^J^0>)
	SETOM	ERRACK			;THIS IS AN ERROR
	MOVE	S1,P1			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;TELL THE USER
	$RETT				;AND RETURN
>
	SUBTTL	D$ACK - ROUTINE TO PROCESS MDA ACK MESSAGES

	;CALL:	M/ The ACK Message Address
	;
	;RET:	True Always

TOPS10	<
D$ACK::	MOVX	S1,.RCTVS		;GET VOL SET NAME BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN OUR MESSAGE
	JUMPF	MISC.3			;NOT THERE,,THATS AN ERROR
	HRROI	S1,0(S1)		;GET POINTER TO ASCIZ VOL SET NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	S1,S2			;GET STRUCTURE NAME IN S1
	PUSHJ	P,FNDISK		;FIND ITS VOL BLOCK ADDRESS
	JUMPF	.RETT			;NOT THERE,,RETURN
	LOAD	S2,.MSFLG(M),AK.TYP	;GET THE ACK TYPE
	CAILE	S2,ACKLEN		;VALIDATE IT
	SETZM	S2			;NO GOOD,,ZERO IT
	PJRST	@ACKDSP(S2)		;DISPATCH OFF TO PROCESS THE ACK

ACKDSP:	EXP	MISC.3			;ACK TYPE 0 IS INVALID
	EXP	MNTACK			;ACK TYPE 1 IS MOUNT ACK
	EXP	DSMACK			;ACK TYPE 2 IS DISMOUNT ACK
	EXP	CATACK			;ACK TYPE 3 IS CATALOG ACK (ERROR ONLY)
	EXP	ASLACK			;ACK TYPE 4 IS ADD STR TO SRCH LIST ACK
	EXP	RMSACK			;ACK TYPE 5 REMOVE STR FROM SRCH LIST 
	EXP	MNTOPC			;ACK TYPE 6 IS MOUNT ACK (OWNER PPN CL)

	ACKLEN==.-ACKDSP		;DISPATCH TABLE LENGTH
>
SUBTTL	Structure mount ACK processing


; Here on ACK types %MOUNT and %MNTOPC
; Call:	MOVE	S1, primary VOL block address
;	PUSHJ	P,MNTACK	for normal structure mount ACKs
;	PUSHJ	P,MNTOPC	when owner PPN is cleared
;
; TRUE return:	always
;
TOPS10	<
MNTACK:	TDZA	S2,S2			;INDICATE NORMAL MOUNT ACK
MNTOPC:	MOVEI	S2,1			;INDICATE OWNER PPN CLEARED
	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVE	P1,S1			;SAVE THE VOL BLOCK ADDRESS
	LOAD	S1,.MSFLG(M),AK.NAK	;IS THIS A NAK ???
	JUMPN	S1,MNTA.4		;YES,,OH WELL !!!
MNTA.0:	$COUNT	(STRM)			;[1217] COUNT # OF SUCCESSFUL STR MOUNTS
	MOVX	S1,%STAMN		;GET STRUCTURE MOUNTED BIT
	STORE	S1,.VLFLG(P1),VL.STA	;SAVE IT AS NEW STRUCTURE STATUS
	MOVE	S1,G$NOW##		;GET THE CURRENT TIME
	MOVEM	S1,.VLMTM(P1)		;SAVE THE MOUNTED TIME
	JUMPE	S2,MNTA.3		;SKIP LOOP IF NORMAL MOUNT ACK
	SKIPA	S1,P1			;GET PRIMARY VOL BLOCK ADDRESS

MNTA.1:	LOAD	S1,.VLPTR(S1),VL.NXT	;GET THE NEXT VOL BLK ADDRESS
	JUMPE	S1,MNTA.2		;DONE ALL VOL BLOCKS?
	SETZM	.VLOID(S1)		;CLEAR OWNER PPN
	JRST	MNTA.1			;LOOP FOR ALL VOL BLOCKS

MNTA.2:	MOVE	S1,.VLNAM(P1)		;GET STR NAME
	PUSHJ	P,V$STRG##		;CONVERT TO ASCIZ
	PUSHJ	P,V$FIND##		;GET CATALOG ENTRY
	SKIPF				;WE BLEW IT SOMEWHERE - AVOID A MESS
	SETZM	.CQVUS(S1)		;CLEAR THE OWNER PPN IN THE CATALOG

MNTA.3:	MOVEI	S1,[ASCIZ ||]		;ASSUME NOT WRITE-LOCKED
	MOVX	S2,.MTWLK		;GET A BIT TO TEST
	TDNE	S2,.OFLAG(M)		;WRITE-LOCKED FOR ALL USERS?
	MOVEI	S1,[ASCIZ |Structure is software write-locked for all users|]
	$WTO	(<Structure ^W/.VLNAM(P1)/ mounted>,<^T/(S1)/>,,<$WTFLG(WT.SJI)>)
	DOSCHD				;FORCE A SCHEDULING PASS
	MOVE	S1,P1			;GET THE VOL BLK ADDR IN S1
	PUSHJ	P,I$STRM##		;PERFORM STRUCTURE ACCOUNTING
	MOVE	S1,.VLUCB(P1)		;GET THE UCB ADDRESS
	PUSHJ	P,MATUNI		;TRY TO ASSIGN THE DEVICE
	$RETT				;RETURN

MNTA.4:	$WTO	(<Can't mount structure ^W/.VLNAM(P1)/>,,,<$WTFLG(WT.SJI)>)
	MOVE	S1,.VLSTR(P1)		;GET THE REAL STRUCTURE NAME
	MOVEM	S1,.VLNAM(P1)		;AND SAVE IT

MNTA.5:	LOAD	S1,.VLPTR(P1),VL.NXT	;GET THE NEXT VOL ADDRESS
	SETZM	.VLPTR(P1)		;CLEAR THE OLD POINTERS
	MOVE	P1,S1			;GET THE NEXT VOL ADDRESS IN P1
	JUMPN	P1,MNTA.5		;ANOTHER,,RESET IT ALSO
	$RETT				;DONE,,RETURN
>

	SUBTTL	D$RMS - Routine to process the structure removed message

	;CALL:	M/ The Message address
	;
	;RET:	Through DSMACK (as if from PULSAR)

TOPS10<
D$RMS::	MOVE	S1,1(M)			;GET THE STRUCTURE NAME
	PUSHJ	P,FNDISK		;FIND ITS VOL BLOCK ADDRESS
	JUMPF	.RETT			;NOT THERE,,RETURN
	MOVX	S2,VL.REM		;GET THE /REMOVE FLAG BIT
	ANDCAM	S2,.VLFLG(S1)		;AND CLEAR IT
	SETZM	.MSFLG(M)		;CLEAR THE FLAG BITS (JUST IN CASE)
	PJRST	DSMACK			;REALLY CLEAN THINGS UP AND RETURN
>
	SUBTTL	DSMACK - ROUTINE TO PROCESS DISMOUNT ACKS FROM TAPE LABELER

	;CALL:	S1/ The VOL Address of the Primary VOL Block
	;
	;RET:	True Always

TOPS10	<
DSMACK:	PUSHJ	P,.SAVE4		;SAVE P1 - P4 FOR A MINUTE
	MOVE	P1,S1			;SAVE THE VOL BLOCK ADDRESS
	LOAD	TF,.MSFLG(M),AK.NAK	;IS THIS A NAK ???
	JUMPN	TF,DSMA.4		;YES,,OH WELL !!!!
	PUSHJ	P,DSMOPR		;TELL OPR ITS GONE
	MOVE	S1,P1			;GET THE VOL BLK ADDR IN S1
	PUSHJ	P,I$STRD##		;PERFORM STRUCTURE ACCOUNTING

	;Here to clear mounted bits for the structure since its now offline

	MOVX	S1,%STAWT		;GET 'WAITING' VOLUME STATUS
	STORE	S1,.VLFLG(P1),VL.STA	;SET IT
	LOAD	P2,.VLOWN(P1),VL.CNT	;GET THE REQUEST COUNT
	JUMPE	P2,DSMA.1		;NO REQUESTORS,,SKIP THIS
	$TEXT	(<-1,,G$MSG>,<[Structure ^W/.VLNAM(P1)/ dismounted]^0>)
	PUSH	P,[-1]			;INDICATE END OF VSL QUEUE
	MOVNS	P2			;NEGATE THE COUNT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.VLVSL(P1)		;CREATE AOBJN AC TO VSL ADR LIST
	PUSH	P,0(P2)			;QUEUE UP A VSL ADDRESS
	AOBJN	P2,.-1			;CONTINUE FOR ALL REQUESTORS

	;Here to update the poor users status since the structure is now gone

DSMA.0:	POP	P,P3			;PICK OFF A VSL ADDRESS
	CAMN	P3,[-1]			;IS THIS THE LAST ???
	JRST	DSMA.1			;YES,,CONTINUE ON
	TXNN	P3,VL.ASN+VL.ASK	;DOES HE HAVE IT MOUNTED ?
	JRST	DSMA.0			;NO,,TRY NEXT
	LOAD	AP,.VSMDR(P3)		;SET UP POINTER TO MDR
	MOVE	S1,P3			;[1173] GET VSL ADDRESS
	SETZM	S2			;[1173] USE VSL ACK DATA
	PUSHJ	P,USRNOT		;TELL THE USER IT'S GONE
	LOAD	P4,.MRCNT(AP),MR.CNT	;SAVE THE CURRENT REQUEST COUNT
	MOVE	S1,.VSFLG(P3)		;DID USER ALLOCATE THIS STR OR IS VSL
	TXNN	S1,VS.UAL!VS.CTL	; PART OF PSEUDO PROCESS ALLOCATION?
	JRST	DSMA.Z			;NO TO EITHER - RETURN RESOURCES
	TXO	S1,VS.UAL		;INSURE ALLOC BIT ON INCASE CTL ONLY
	TXZ	S1,VS.NMT		;CLEAR MOUNTED FOR PSEUDO PROCESS
	MOVEM	S1,.VSFLG(P3)		;UPDATE FLAG WORD
	PUSHJ	P,DSMALC		;RETURN ALLOCATED RESOURCES
	MOVE	S1,P3			;GET VSL ADDRESS
	PUSHJ	P,MNTVSL		;TRY TO RE-MOUNT IT
	JRST	DSMA.0			;ON TO THE NEXT VSL

DSMA.Z:	PUSHJ	P,DSMALC		;RETURN ALLOCATED RESOURCES
	JRST	DSMA.0			;GET THEM ALL
	MOVE	S1,P3			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,ALCVSL		;RETURN THE USERS RESOURCES
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE USERS NEW REQUEST COUNT
	CAMN	S1,P4			;WAS THE VSL DELETED ???
	ZERO	.VSFLG(P3),VS.ALC	;NO,,REMOUNT IT !!!
	SKIPN	S1			;STILL SOME REQUESTS LEFT,,SKIP
	PUSHJ	P,DELMDR		;ELSE DELETE THE MDR
	JRST	DSMA.0			;GET THEM ALL !!!

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here to unload the volumes if /REMOVE was specified

DSMA.1:	PUSH	P,P1			;SAVE THE VOL BLK ADDRESS FOR A SECOND
	LOAD	P2,.VLFLG(P1),VL.REM	;SAVE THE 'REMOVE' STRUCTURE STATUS

DSMA.2:	SKIPN	S1,.VLUCB(P1)		;GET THE UCB ADDRESS IN S1
	STOPCD	(IVU,HALT,,<Invalid VOL/UCB forward/backchain pointers>)
	SETZM	.VLUCB(P1)		;ZAP VOL LINK TO UCB
	SETZM	.UCBVL(S1)		;ZAP UCB LINK TO VOL
	MOVE	S1,.UCBNM(S1)		;GET THE UNIT NAME
	SKIPE	P2			;IF 'REMOVING THE STRUCTURE',,THEN
	PUSHJ	P,UNLOAD		;   UNLOAD THE DEVICE
	LOAD	P1,.VLPTR(P1),VL.NXT	;GET THE NEXT VOLUME IN THE STRUCTURE
	JUMPN	P1,DSMA.2		;IF ANOTHER VOLUME,,GO PROCESS IT

	;Here to clear all LOCK status and events

DSMA.3:	MOVE	S1,0(P)			;GET THE VOL BLK ADRS BACK
	MOVE	S1,.VLNAM(S1)		;AND GET THE STR NAME
	PUSHJ	P,DMSLOK		;CLEAR ANY PENDING LOCKS, UNLOCKS
	MOVE	S1,0(P)			;GET THE VOL BLK ADRS BACK
	MOVE	S1,.VLNAM(S1)		;AND GET THE STR NAME
	PUSHJ	P,CLRELN		;CLEAR ANY LOCK NOTIFICATION, TOO
	POP	P,P1			;RESTORE THE VOL BLK ADDRESS
	ZERO	.VLFLG(P1),VL.REM	;CLEAR THE REMOVE BIT
	MOVX	S1,%UNLCK		;GET NORMAL UNLOCKED STATUS
	STORE	S1,.VLFLG(P1),VL.LCK	;SET NEW STATUS FOR NEXT MOUNT

	;Here to update the 'A' matrix if a permanent structure

	MOVE	S1,.VLNAM(P1)		;GET THE STRUCTURE NAME
	PUSHJ	P,D$SRSN		;GET THE STRUCTURE RESOURCE NUMBER
	IMULI	S1,AMALEN		;GET 'A' MATRIX OFFSET
	ADD	S1,AMATRX		;GET THE ENTRY ADDRESS
	LOAD	S2,.AMNAM(S1),AM.PRR	;GET THE PERMANENT RESOURCE BIT
	JUMPE	S2,DSMA.X		;NOT PERMANENT,,SKIP THIS
	MOVX	S2,AM.PRR		;GET THE PERMANENT STRUCTURE BIT
	ANDCAM	S2,.AMNAM(S1)		;CLEAR IT FOR THIS STRUCTURE
	LOAD	S1,.AMNAM(S1),AM.NAM	;POINT TO ASCIZ VOLUME-SET NAME
	PUSHJ	P,V$FIND##		;GET THE CATALOG ENTRY
	SKIPT				;IT MUST BE THERE !!!
	STOPCD	(SCE,HALT,,<Structure catalog entry missing>)
	MOVEI	S2,.CQVSL(S1)		;POINT THE THE CAT VOL LIST
	MOVE	S1,.CQNVL(S1)		;GET THE VOL COUNT
DSMA.A:	MOVE	T1,.CQRSN(S2)		;GET THE VOL RESOURCE NUMBER
	IMULI	T1,AMALEN		;GET THE ENTRY OFFSET
	ADD	T1,AMATRX		;GET THE ENTRY ADDRESS
	INCR	.AMCNT(T1),AM.AVA	;INCRIMENT THE AVAILABLE COUNT BY 1
	ADDI	S2,2			;POINT TO THE NEXT VOL BLK
	SOJG	S1,DSMA.A		;CONTINUE FOR ALL VOLUMES

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE


	;Here when done to try to delete the VOL blocks

DSMA.X:	LOAD	S1,.VLOWN(P1),VL.CNT	;[1465] GET REQUEST COUNT
	JUMPN	S1,DSMA.Y		;[1465] KEEP CATALOG ENTRY IF NONZERO!!
	MOVE	S1,.VLNAM(P1)		;GET STR NAME
	PUSHJ	P,V$STRG##		;CONVERT TO ASCII
	PUSHJ	P,V$DELS##		;DELETE FROM CATALOG CACHE
DSMA.Y:	MOVE	S1,P1			;[1465] GET PRIMARY VOL ADDRESS IN S1
	PUSHJ	P,DELVOL		;TRY TO DELETE THE VOL BLOCKS
	$RETT				;RETURN

	;Here if the structure could not be dismounted

DSMA.4:	MOVX	S1,%STAMN		;GET STRUCTURE MOUNTED BIT
	STORE	S1,.VLFLG(P1),VL.STA	;RESET STATUS TO 'MOUNTED'
	$WTO	(<Can't dismount structure ^W/.VLNAM(P1)/>,,,<$WTFLG(WT.SJI)>)
	ZERO	.VLFLG(P1),VL.REM	;CLEAR ANY REMOVE BITS
	MOVE	S1,.VLUCB(P1)		;GET THE UCB ADDRESS
	PUSHJ	P,MATUNI		;CHECK FOR ANY MOUNTS
	$RETT				;RETURN

; Return the user's allocated resources
DSMALC:	MOVE	S1,P3			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,ALCVSL		;RETURN THE USERS RESOURCES
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE USERS NEW REQUEST COUNT
	CAMN	S1,P4			;WAS THE VSL DELETED ???
	ZERO	.VSFLG(P3),VS.ALC	;NO,,REMOUNT IT !!!
	SKIPN	S1			;STILL SOME REQUESTS LEFT,,SKIP
	PUSHJ	P,DELMDR		;ELSE DELETE THE MDR
	POPJ	P,			;RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	DSMOPR - Tell OPR about a structure just dismounted

;This routine informs the operator that a structure dismount
;	is complete, and on which units
;Call -
;	S1/	Addr of Primary VOL block (VOLs, UCBs still linked)
;Returns -
;	True, after WTOing the OPR

TOPS10<
DSMOPR:
	$SAVE	<P1>
	MOVE	P1,S1			;SAVE ADR OF PRIMARY VOL BLOCK
	PUSHJ	P,MDASBP		;SET UP FOR CALLS TO MDADBP
DSMO.1:	SKIPN	S2,.VLUCB(S1)		;GET ADRS OF THIS VOLUME'S UNIT BLK
	PUSHJ	P,S..IVU		;GONG, CAN'T GET HERE
	$TEXT	(MDADBP,<^W/.UCBNM(S2)/,^A>)
	LOAD	S1,.VLPTR(S1),VL.NXT	;GET POINTER TO NEXT VOL
	JUMPN	S1,DSMO.1		;ANOTHER,,CONTINUE

DSMO.2:	SETZ	S1,			;MAKE A ZERO
	DPB	S1,MDBPTR		;AND TERMINATE THE TEXT
	SKIPE	.VLPTR(P1)		;WAS THERE MORE THAN ONE?
	MOVE	S1,[ASCII/s/]		;YES,,PLURALIZE IT..
	$WTO	(<Structure ^W/.VLNAM(P1)/ dismounted>,<  From unit^T/S1/: ^T/G$MSG/>,,<$WTFLG(WT.SJI)>)
	$RETT
>;END TOPS10
	SUBTTL	CATACK - ROUTINE TO PROCESS CATALOG ACKS FROM TAPE LABELER

	;This routine is run when a volume set cannot be located in
	; the volume set catalog
	;
	;CALL:	S1/ The VOL Address of the Primary VOL Block
	;
	;RET:	True Always

TOPS10	<
D$CACK::
CATACK:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	SKIPG	S1,.MSCOD(M)		;GET THE ACK CODE
	$RETT				;INTERNAL REQUEST,,RETURN NOW
	PUSHJ	P,FNDVSL		;FIND THE VSL
	JUMPF	.RETT			;NOT THERE,,JUST RETURN
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	MOVE	AP,.VSMDR(P1)		;SETUP THE MDR ADDRESS
	$TEXT	(<-1,,G$MSG>,<Structure ^T/.VSVSN(P1)/ not in System Catalog^M^J^0>)
	SETOM	ERRACK			;THIS IS AN ERROR ACK
	MOVE	S1,P1			;[1173] GET VSL ADDRESS
	SETZM	S2			;[1173] USE VSL ACK DATA
	PUSHJ	P,USRNOT		;ACK THE USER
	MOVE	S1,P1			;GET THE VSL ADDRESS BACK
	PUSHJ	P,REMOVE		;GO AND DELETE THIS VSL & RETRY MOUNT
	HRROI	S1,.VSVSN(P1)		;POINT TO THE ASCIZ VOL SET NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	S1,S2			;MOVE IT TO S1
	PUSHJ	P,D$SRSN		;GET THE RESOURCE NUMBER
	PUSHJ	P,GIVRSN		;TRY TO RETURN IT
	$RETT				;RETURN

>
	SUBTTL	ASLACK - ROUTINE TO PROCESS ACKS FOR ADDING STR TO A SEARCH LIST

	;CALL:	S1/ The VOL Address of the Primary VOL Block
	;
	;RET:	True Always

TOPS10	<
ASLACK:	PUSHJ	P,.SAVE3		;SAVE P1 & P2 FOR A MINUTE
	MOVE	P3,S1			;SAVE THE VOL ADDRESS
	MOVE	S1,.MSCOD(M)		;GET THE ACK CODE (REQUEST ID)
	PUSHJ	P,FNDVSL		;FIND THE USER.
	JUMPF	.RETT			;NOT THERE,,OH WELL...
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	SETZM	P2			;NO ADDITIONAL TEXT YET
	MOVX	S1,.OMTXT		;GET SECONDARY TEXT BLOCK
	PUSHJ	P,A$FNDB##		;FIND IT
	SKIPF				;SKIP IN NOT THERE
	MOVE	P2,S1			;ELSE SAVE THE TEXT ADDRESS
	JUMPE	P2,ASLA.1		;NO SECONDARY TEXT,,SKIP THIS
	LOAD	S1,-ARG.DA(P2),AR.LEN	;GET THE BLOCK LENGTH
	PUSHJ	P,M%GMEM		;GET SOME MEMORY
	STORE	S1,.VSTXT(P1),VS.LEN	;SAVE THE BLOCK LENGTH
	STORE	S2,.VSTXT(P1),VS.ADR	;SAVE THE BLOCK ADDRESS
	ADD	S1,S2			;POINT TO THE END OF THE BLOCK
	HRL	S2,P2			;GET SOURCE,,DESTINATION ADDRESS
	BLT	S2,-1(S1)		;COPY THE TEXT AND SAVE IT
ASLA.1:	MOVX	S1,AK.NAK		;GET A BIT
	TDNE	S1,.MSFLG(M)		;WAS IT A NAK?
	JRST	ASLA.2			;YES
	$COUNT	(USTM)			;# of user structure mounts
	MOVE	S1,P1			;GET VSL BLOCK ADDRESS
	MOVE	S2,P3			;GET VOL BLOCK ADDRESS
	PUSHJ	P,AASCLR		;CLEAR VL.AAS
	MOVE	S1,P1			;GET THE VSL ADDRESS
	PUSHJ	P,SETOWN		;SAY THIS GUY OWNS THE UNIT
	MOVE	S1,P1			;GET THE VSL ADDRESS
	PUSHJ	P,I$SMNT##		;PERFORM STRUCTURE ACCOUNTING
	MOVE	S1,P1			;GET THE VSL ADDRESS
	PUSHJ	P,ACKUSR		;TELL THE USER
	$RETT				;AND RETURN

ASLA.2:	SKIPN	P2			;ANY ADDITIONAL TEXT ???
	MOVEI	P2,[0]			;NO,,POINT TO A NULL BLOCK
	$TEXT	(<-1,,G$MSG>,<Can't mount structure ^T/.VSVSN(P1)/^M^J^T/0(P2)/^M^J^0>)
	SETOM	ERRACK			;INDICATE THIS IS AN ERROR ACK
	MOVE	S1,P1			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;NOTIFY THE USER
	MOVE	S1,P1			;GET THE VSL ADDRESS BACK
	PUSHJ	P,ALCVSL		;RETURN THIS VSL TO THE ALLOCATION POOL
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE USERS REQUEST COUNT
	JUMPE	S1,DELMDR		;NOTHING LEFT,,DELETE THE MDR
	$RETT				;AND RETURN
>

	SUBTTL	RMSACK - ROUTINE TO PROCESS 'REMOVE STRUCTURE' ACKS

	;CALL:	S1/ The VOL Address of the Primary VOL Block
	;
	;RET:	True Always

TOPS10<
RMSACK:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2 FOR A SECOND
	MOVE	P1,S1			;SAVE THE VOL BLOCK ADDRESS
	MOVE	S1,.MSCOD(M)		;GET THE ACK CODE (REQUEST ID)
	PUSHJ	P,FNDVSL		;FIND THE VSL
	JUMPF	RMSA.1			;NOT THERE,,GO CHECK OUT THE STR
	PUSH	P,S1			;SAVE THE VSL ADDRESS FOR A SECOND
	MOVX	S1,.OMTXT		;GET THE REASON BLOCK
	PUSHJ	P,A$FNDB##		;FIND IT
	SKIPT				;NOT THERE ???
	MOVEI	S1,[0]			;NOT THERE,,POINT TO NULL WORD
	MOVE	P2,S1			;GET TEXT ADDRESS
	LOAD	TF,.MSFLG(M),AK.NAK	;IS THIS A NAK ???
	JUMPN	TF,RMSA.2		;YES,,OH WELL !!!!
	MOVE	S1,(P)			;GET THE VSL ADDRESS BACK
	$TEXT	(<-1,,G$MSG>,<^T/(P2)/[Structure ^T/.VSVSN(S1)/ dismounted]^M^J^0>)
	PUSHJ	P,I$SDSM##		;PERFORM STRUCTURE ACCOUNTING
	MOVE	S2,(P)			;[1173] GET VSL ADDRESS AGAIN
	MOVE	S1,.VSRFL(S2)		;[1173] GET WAIT/NOTIFY/ACK FLAGS ETC.
	TXNE	S1,MR.WAT		;WAITING?
	TXO	S1,MR.ACK		;THEN WE WANT TO ACK VIA IPCF
	MOVEM	S1,.VSRFL(S2)		;[1173] RESTORE FLAG WORD
	MOVX	S1,MR.DMO		;GET DISMOUNT BIT
	IORM	S1,.VSRFL(S2)		;[1173] LITE IT SO USRNOT DOES PRETTY THINGS
	MOVE	S1,S2			;[1173] GET VSL ADDRESS
	SETZM	S2			;[1173] USE VSL ACK DATA!
	PUSHJ	P,USRNOT		;NOTIFY THE USER
	MOVE	S1,0(P)			;GET THE VSL ADDRESS BACK
	LOAD	S2,.VSFLG(S1),VS.REM	;GET THE /REMOVE STR FLAG BIT
	SKIPE	S2			;DID USER SPECIFY /REMOVE ???
	PUSHJ	P,TELREM		;YES,,TELL THE OPERATOR
	POP	P,S1			;RESTORE THE VSL ADDRESS
	PUSHJ	P,ALCVSL		;DEALLOCATE IF WE CAN
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	SKIPN	S1			;ANY MORE REQUESTS ???
	PUSHJ	P,DELMDR		;NO,,DELETE THIS MDR

RMSA.1:	MOVE	S1,P1			;GET THE VOL BLOCK ADDR BACK
	PUSHJ	P,CHKSTR		;CHECK FOR STRUCTURE AVAILABILITY
	$RETT				;THEN RETURN

RMSA.2:	MOVE	S1,(P)			;[1173] GET VSL ADDRESS
	$TEXT	(<-1,,G$MSG>,<Can't dismount structure ^T/.VSVSN(S1)/^M^J^T/(P2)/^0>)
	SETOM	ERRACK			;IS THIS AN ERROR
	POP	P,S1			;[1173] RESTORE VSL ADDRESS
	SETZM	S2			;[1173] USE VSL ACK DATA
	PUSHJ	P,USRNOT		;SEND IT OFF TO THE USER
	$RETT				;AND RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	D$ALIA - ROUTINE TO MOUNT A STRUCTURE WITH AN ALIAS

	;CALL:	M/ The Mount Message Address (From ORION)
	;
	;RET:	True Always

TOPS10<
D$ALIA::PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A SECOND
	MOVX	S1,.STRDV		;GET STRUCTURE NAME BLOCK TYPE
	PUSHJ	P,A$FNDB##		;LOCATE IT IN THE MESSAGE
	JUMPF	E$IMO##			;NOT THERE,,THATS AN ERROR
	HRLI	S1,(POINT 7,)		;MAKE A POINTER
	$CALL	S%SIXB			;CONVERT TO SIXBIT
	MOVE	P1,S2			;GET THE STRUCTURE NAME
	MOVEM	P1,MDAOBJ+OBJ.UN	;SAVE IT IN THE OBJECT BLOCK
	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST ENTRY
	JRST	ALIA.2			;SKIP THE FIRST TIME THROUGH

ALIA.1:	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT ENTRY
ALIA.2:	JUMPF	ALIA.9			;NO MORE,,THATS AN ERROR
	SKIPE	S1,.VLUCB(S2)		;VOLUME MUST BE MOUNTED !!!
	CAME	P1,.VLNAM(S2)		;AND STRUCTURE NAMES MUST MATCH !!!
	JRST	ALIA.1			;NO,,TRY NEXT VOLUME
	LOAD	S1,.UCBST(S1),UC.DVT	;GET THE DEVICE TYPE
	CAXE	S1,%DISK		;IS IT A STRUCTURE ???
	JRST	ALIA.1			;NO,,TRY NEXT VOLUME
	LOAD	S1,.VLFLG(S2),VL.STA	;GET THE VOLUME STATUS
;**;[1204] Change code at ALIA.2+7L. /LWS
	CAXN	S1,%STAWT		;[1204] IS IT WAITING ???
	JRST	ALIA2A			;[1204] YES,,GO PROCESS
	CAXE	S1,%STADM		;[1204] NO,,DISMOUNTING???
	JRST	ALIA.1			;NO,,TRY NEXT VOLUME
	MOVEI	S1,[ITEXT(<Structure ^W/P1/ is dismounting>)] ;[1204]
	JRST	ALIA.E			;[1204] GO ACK

	;Here to process the primary vol block we found

ALIA2A:	MOVE	P1,S2			;[1204] SAVE THE PRIMARY VOL BLOCK ADDRESS

ALIA.3:	SKIPN	S1,.VLNXT(S2)		;ANY 'NEXT' VOLUME FOR THIS STRUCTURE ??
	JRST	ALIA.4			;NO,,LETERRIP !!!
;**;[1227] Change 1 line and delete 2 lines at ALIA.3+2L. /LWS
	PUSHJ	P,FNDVOL		;[1227] YES,,GO FIND IT IN OUR DATA BASE
	JUMPF	ALIA.9			;NOT FOUND,,THATS AN ERROR
	MOVE	S2,S1			;OK,,SET POINTER TO THIS VOLUME
	JRST	ALIA.3			;AND CHECK OUT THIS VOLUME

ALIA.4:	MOVE	P2,.VLNAM(P1)		;DEFAULT TO THE STRUCTURE NAME
	MOVX	S1,.STALS		;GET THE ALIAS BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT IN THE MESSAGE
	JUMPF	ALIA.5			;NOT THERE,,JUST MOUNT IT

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	HRLI	S1,(POINT 7,)		;MAKE A POINTER TO IT
	$CALL	S%SIXB			;CONVERT IT
	MOVE	P2,S2			;SAVE THE ALIAS NAME
	MOVE	S1,P2			;GET THE ALIAS NAME IN S1
	PUSHJ	P,I$VDEV##		;VALIDATE THE DEVICE NAME
	  JUMPT	ALIA.7			;NO GOOD IF DEVICE ALREADY EXISTS

ALIA.5:	MOVE	S1,P2			;GET THE ALIAS NAME
	PUSHJ	P,V$STRG##		;CONVERT TO ASCIZ
	PUSHJ	P,V$FIND##		;FIND THE CATALOG ENTRY
	JUMPF	ALIA.6			;ITS OK IF WE CAN'T
	MOVE	S1,.CQVSL+.CQVID(S1)	;GET THE PRIMARY VOL NAME
	PUSHJ	P,FNDDSK		;FIND ITS VOL BLOCK
	JUMPF	ALIA.6			;DOESN'T HAVE TO BE THERE
	CAMN	S1,P1			;SAME AS THE ONE WE'RE MOUNTING?
;**;[1227] Change 2 lines at ALIA.5+7L. /LWS
	JRST	ALI.6D			;[1227] YES
	LOAD	S2,.VLFLG(S1),VL.STA	;GET STR STATUS
	CAIN	S2,%STAMN		;MOUNTED?
	JRST	ALI.6D			;[1227] YES, CONTINUE. V$CREA WILL BOMB
	MOVEI	S2,.OTMNT		;GET OBJECT TYPE MOUNT
	MOVEM	S2,CATOBJ+OBJ.TY	;SAVE IT
	SKIPE	S2,.VLUCB(S1)		;[1227] GET UCB ADDR
	MOVE	S2,.UCBNM(S2)		;GET UNIT NAME
	MOVEM	S2,CATOBJ+OBJ.UN	;SAVE IN OBJECT BLOCK
	SETZM	CATOBJ+OBJ.ND		;NO NODE INFO
	LOAD	S2,.VLOWN(S1),VL.CNT	;[1227] GET REQUESTOR COUNT
	JUMPN	S2,ALIA.6		;[1227] IF REQUESTORS EXIST, CANT DELETE
	SKIPE	CATOBJ+OBJ.UN		;[1227] IF NO UCB, DON'T USE OBJECT BLK
	$WTO	(<Deleting duplicate volume>,<Unit ^W/.VLVID(S1)/ for structure ^W/.VLNAM(S1)/>,CATOBJ,<$WTFLG(WT.SJI)>)
	SKIPN	CATOBJ+OBJ.UN		;[1227]
	$WTO	(<Deleting duplicate volume>,<Unit ^W/.VLVID(S1)/ for structure ^W/.VLNAM(S1)/>,,<$WTFLG(WT.SJI)>) ;[1227]
	PUSHJ	P,DELVOL		;DELETE THE OLD ONE

ALIA.6:	LOAD	S1,.VLOWN(P1),VL.CNT	;[1227] SEE IF ANY REQUESTORS
	JUMPE	S1,ALI.6D		;[1227] IF NONE, CONTINUE
	$SAVE	<T1,T2>			;[1227] SAVE T1 & T2
	SETZM	T1			;[1227] INDICATE NO PREVIOUS VOL BLOCK
	MOVE	T2,P1			;[1227] GET PRIMARY (OLD) VOL BLOCK ADDR
ALI.6A:	PUSHJ	P,CREVOL		;[1227] CREATE A NEW VOL BLOCK
	MOVE	S2,S1			;[1227] COPY NEW VOL ADDR
	HRL	S1,T2			;[1227] COPY OLD VOL TO NEW VOL
	BLT	S1,.VLVSL-1(S2)		;[1227] EXCEPT FOR VSL POINTERS
	SETZM	.VLPTR(S2)		;[1227] CLEAR MULTIPLE VOL BLOCK PTRS
	SKIPN	T1			;[1227] SAVE PRIMARY VOL ADDR ONLY ONCE
	PUSH	P,S2			;[1227]
	MOVE	T1,S2			;[1227] GET NEW VOL BLOCK ADDR IN T1
	MOVX	S1,VL.CNT		;[1227] CLEAR REQUEST COUNT IN VOL COPY
	ANDCAM	S1,.VLOWN(T1)		;[1227]
	MOVX	S1,VL.RSN		;[1227] CLEAR RESOURCE NUMBER!
	ANDCAM	S1,.VLFLG(T1)		;[1227]
	SETZM	.VLMTM(T1)		;[1227] CLEAR MOUNT TIME
	SKIPE	S1,.VLUCB(T2)		;[1227] GET POINTER TO UCB
	MOVEM	T1,.UCBVL(S1)		;[1227] LINK UCB TO NEW VOL
	MOVEM	S1,.VLUCB(T1)		;[1227] LINK NEW VOL TO UCB
	SETZM	.VLUCB(T2)		;[1227] UNLINK OLD VOL FROM UCB
	CAME	T1,(P)			;[1227] NEW PRIMARY VOL BLOCK?
	JRST	ALI.6C			;[1227] NO, DON'T GET NEW RESOURCE
	MOVE	S1,T1			;[1227] YES, GET NEW VOL BLOCK ADDRESS
	EXCH	P2,.VLNAM(S1)		;[1227] USE ALIAS NAME FOR NEW RESOURCE
	PUSHJ	P,D$SVRS		;[1227] GET A RESOURCE NUMBER
ALI.6C:	LOAD	T2,.VLPTR(T2),VL.NXT	;[1227] GET POINTER TO NEXT VOL BLOCK
	JUMPN	T2,ALI.6A		;[1227] IF ANOTHER VOL, LOOP.
	POP	P,P1			;[1227] GET NEW PRIMARY VOL ADDR
	TRNA				;[1227] ALREADY EXCH'D NAMES

ALI.6D:	EXCH	P2,.VLNAM(P1)		;[1227] SWAP ALIAS NAME WITH OLD NAME
	MOVE	S1,P1			;GET THE VOLUME BLOCK ADDRESS
	PUSHJ	P,V$CREA##		;GENERATE A CATALOG ENTRY
	JUMPF	ALIA.8			;CAN'T
	LOAD	S1,.OFLAG(M),.MTWLK	;GET WRITE LOCKED BIT
	MOVEM	S1,WRTLCK		;SAVE IT
	LOAD	S1,.OFLAG(M),.DMOSN	;GET OVERRIDE-SET-NUMBER BIT
	MOVEM	S1,OSNFLG		;SAVE IT
	MOVE	S1,P1			;GET VOL BLOCK ADDRESS
	MOVE	S2,.VLNAM(P1)		;GET STR NAME
	PUSHJ	P,SNDBLD		;BUILD THE STRUCTURE
	$RETT				;RETURN

ALIA.7:	MOVEI	S1,[ITEXT (<Device ^W/P2/ already exists>)]
	JRST	ALIA.E			;ACK THE ERROR AND RETURN
ALIA.8:	EXCH	P2,.VLNAM(P1)		;RESTORE ORIGINAL STR NAME
	MOVE	S1,P1			;[1227] GET PRIMARY VOL ADDR
	PUSHJ	P,DELVOL		;[1227] DELETE VOL BLOCKS IF NO REQUESTORS
	SKIPA	S1,[EXP [ITEXT (<^W/P2/ has outstanding allocations>)]] 
ALIA.9:	MOVEI	S1,[ITEXT (<All required volumes are not spinning>)]
ALIA.E:	$ACK	(<Invalid mount request>,<^I/(S1)/>,MDAOBJ,.MSCOD(M))
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL
	SUBTTL	CHKSTR - ROUTINE TO CHECK FOR STRUCTURE AVAILABILITY

	;CALL:	S1/ The VOL Address of the Primary VOL Block
	;
	;RET:	True Always

TOPS10<
D$CCHK::				;[1153]EXTERNAL ENTRY POINT
CHKSTR:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A SECOND
	$SAVE	AP			;SAVE AP ALSO
	MOVE	P1,S1			;SAVE THE VOL BLOCK ADDRESS
	LOAD	S1,.VLFLG(P1),VL.STA	;GET THE STRUCTURE STATUS
	LOAD	S2,.VLFLG(P1),VL.LCK	;GET THE STRUCTURE LOCK CODE
	CAXN	S1,%STAMN		;IS THE STRUCTURE MOUNTED ???
	CAXE	S2,%LOCKD		;   AND IS IT LOCKED ???
	JRST	CHKS.1			;NO,,TRY REASSIGNMENT
	MOVE	S1,P1			;GET THE VOL BLOCK ADDRESS BACK
	PUSHJ	P,FNDOWN		;ANYONE STILL OWN IT ???
	JUMPT	.RETT			;YES,,RETURN NOW
	MOVE	S1,.VLNAM(P1)		;GET THE STRUCTURE NAME
	MOVEM	S1,MDAOBJ+OBJ.UN	;SAVE IT
	$WTO	(<This locked structure has a zero mount count^T/BELLS/>,,MDAOBJ)
	MOVE	S1,P1			;GET THE VOL BLK ADDR IN S1
	SETZ	S2,			;NO DISMOUNT FLAGS
	PUSHJ	P,SNDDSM		;DISMOUNT THE STRUCTURE
	$RETT				;RETURN

CHKS.1:	CAXE	S1,%STAMN		;ARE WE MOUNTED AT LEAST ??
	$RETT				;NO,,RETURN
	MOVE	S1,.VLUCB(P1)		;YES,,GET THE UCB ADDRESS 
	PUSHJ	P,MATUNI		;GO TRY TO REASSIGN THE UNIT
	$RETT				;AND RETURN
> ;END TOPS10 CONDITIONAL
	SUBTTL	D$LOCK - PROCESS LOCK AND UNLOCK MESSAGES

	;CALL:	M/ Addrs of incoming LOCK and UNLOCK message
	;
	;RET:	True, with some of the VOL database changed

TOPS10<
D$LOCK::TDZA	S1,S1			;FLAG THE LOCK ENTRY POINT
D$ULOK::MOVEI	S1,1			;FLAG UNLOCK ENTRY
	$SAVE	<P1,P2>			;SAVE P1 AND P2
	MOVE	P1,S1			;SAVE THE ENTRY FLAG
	MOVX	S1,.STRDV		;BLOCK TYPE - STRUCTURE NAME
	PUSHJ	P,A$FNDB##		;FIND OUT WHAT STR OPR IS TALKING ABOUT
	JUMPF	E$IMO##			;NOT THERE, TOO BAD
	HRROI	S1,0(S1)		;AIM AT THE STR NAME
	$CALL	S%SIXB			;CONVERT IT TO 6BIT
	MOVE	S1,S2			;MOVE THE STR NAME INTO PLACE
	PUSHJ	P,FNDISK		;FIND THE VOL BLOCK FOR THAT STR
	JUMPF	E$NSD##			;CAN'T, THAT'S AN ERROR
	MOVE	P2,S1			;SAVE ADDR OF VOL BLOCK
	LOAD	S1,.VLFLG(P2),VL.LCK	;GET THE LOCK CODE
	MOVEI	S2,[ASCIZ/not/]		;TRYING UNLOCK BUT STR NOT LOCKED !!!
	CAXN	S1,%UNLCK		;IS IT UNLOCKED?
	JUMPN	P1,LOCK.1		;YES, DON'T ALLOW ANOTHER UNLOCK
	MOVEI	S2,[ASCIZ/already/]	;ALREADY LOCKED AND TRYING AGAIN !!!
	CAXN	S1,%LOCKD		;IS IT LOCKED?
	JUMPE	P1,LOCK.1		;YES, DON'T ALLOW ANOTHER LOCK

	MOVX	S1,VL.REM		;ON A LOCK
	SKIPN	P1			;   DEFAULT TO UNLOADING
	IORM	S1,.VLFLG(P2)		;      THE STRUCTURE
	LOAD	S2,.OFLAG(M),LC.NUL	;GET THE /NOUNLOAD BIT
	SKIPN	P1			;ON AN UNLOCK
	SKIPE	S2			;   OR A LOCK /NOUNLOAD
	ANDCAM	S1,.VLFLG(P2)		;      DON'T UNLOAD THE STRUCTURE
	LOAD	S1,.VLFLG(P2),VL.LCK	;GET THE LOCK CODE BACK

	CAXN	S1,%LOCKP		;IS A LOCK PENDING?
	JUMPN	P1,CLRPND		;YES, 'UNLOCK' CLEARS THE LOCK REQUEST
	CAXN	S1,%ULCKP		;IS AN UNLOCK PENDING?
	JUMPE	P1,CLRPND		;YES, 'LOCK' CLEARS THE UNLOCK REQUEST
	CAXE	S1,%LOCKP		;WAS IT PENDING A LOCK
	CAXN	S1,%UNLCK		;  OR AN UNLOCK?
	SKIPA				;ONE OF THOSE, GOT SOME WORK TO DO
	JRST	LOCK.0			;NO PENDING REQUEST, CONTINUE
	LOAD	S1,.VLNAM(P2)		;GET BACK THE STR NAME
	PUSHJ	P,DMSLOK		;PENDING EITHER, CANCEL IT
	LOAD	S1,.VLNAM(P2)		;GET BACK THE STR NAME
	PUSHJ	P,CLRELN		;CLEAR THE EVENT NOTIFICATION, TOO

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Now we've ruled out the funny state transitions

LOCK.0:	MOVX	S1,.ORTIM		;BLOCK TYPE FOR DATE/TIME ARGUMENT
	PUSHJ	P,A$FNDB##		;GET THAT BLOCK
	SKIPT				;IS THERE ONE?
	SKIPA	S1,G$NOW##		;NO, ASSUME ACTION NOW
	MOVE	S1,0(S1)		;YES, GET THE LOCK TIME
	CAMGE	S1,G$NOW##		;IS TIME IN THE FUTURE?
	MOVE	S1,G$NOW##		;NO, MAKE IT THE PRESENT
	MOVX	S2,%LOCKP		;SAY PENDING
	SKIPE	P1			;IS IT A LOCK?
	MOVX	S2,%ULCKP		;NO, SAY UNLOCK PENDING
	STORE	S2,.VLFLG(P2),VL.LCK	;SAVE THE STATUS
	MOVEM	S1,.VLLTM(P2)		;AND NOTE THE TIME AT WHICH IT HAPPENED
	CAMN	S1,G$NOW##		;IS IT TO HAPPEN NOW?
	PJRST	LOKSTR			;YES, GO DO IT!
	$ACK	(<Structure ^W/.VLNAM(P2)/>,<^W/LCKTB1(P1)/ set for ^H/.VLLTM(P2)/>,,.MSCOD(M))
	MOVX	S2,INSVL.(%EVLCK,EV.TYP) ;GET EVENT TYPE OF LOCK
	MOVEM	S2,TMPVSL+.EVTYP	;SAVE IN TEMP BLOCK
	MOVEM	S1,TMPVSL+.EVUDT	;AND SAVE THE TIME TO WAKE UP
	MOVEI	S1,LOCTIM		;ROUTINE TO CALL AT THAT TIME
	MOVEM	S1,TMPVSL+.EVRTN	;SAVE THAT
	LOAD	S1,.VLNAM(P2)		;GET THE STR NAME
	MOVEM	S1,TMPVSL+.EVMSZ	;SAVE THAT, TOO
	MOVEI	S1,.EVMSZ+1		;MINIMAL BLOCK, WITH 1 DATA WORD
	MOVEI	S2,TMPVSL		;THERE'S THE ARG BLOCK
	PUSHJ	P,S$EVENT##		;CALL ME BACK IN A MINUTE OR AN HOUR
	JUMPN	P1,.RETT		;IF AN UNLOCK, THAT'S ALL
	MOVE	S1,P2			;GET THE VOL BLK ADRS
	PJRST	LOCN.I			;NOTIFY THE USERS

LOCK.1:	$ACK	(<Structure ^W/.VLNAM(P2)/ is ^T/0(S2)/ locked>,,,.MSCOD(M))
	MOVE	S1,P2			;GET THE VOL BLK ADDR IN S1
	PUSHJ	P,CHKSTR		;CHECK THE MOUNT STATUS
	$RETT				;TELL OPR HE IS IN ERROR AND RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

;Here to clear a pending lock or unlock and set the
;	state of the vol block back to unlocked or locked, respectively
;	P1/	0 for LOCK, -1 for UNLOCK
;	P2/	VOL BLK adrs

CLRPND:	MOVX	S2,%LOCKD		;ASSUME CANCELLING AN UNLOCK
	SKIPE	P1			;OPR SAID LOCK?
	MOVX	S2,%UNLCK		;NO, CANCELLING A LOCK
	STORE	S2,.VLFLG(P2),VL.LCK	;SAVE IN THE VOL BLOCK
	ZERO	.VLLTM(P2)		;NO MORE LOCK TIME
	$ACK(<Structure ^W/.VLNAM(P2)/ pending ^W/LCKTB2(P1)/ canceled>,,,.MSCOD(M))
	MOVE	S1,.VLNAM(P2)		;GET THE STRUCTURE NAME
	PUSHJ	P,DMSLOK		;REMOVE ALL THE PENDING TIMERS
	MOVE	S1,.VLNAM(P2)		;GET THE STRUCTURE NAME
	PUSHJ	P,CLRELN		;REMOVE THE PENDING NOTIFICATION TIMER
	MOVE	S1,P2			;GET THEN PRIMARY VOL BLOCK
	MOVEI	S2,[ITEXT(<LOCK for structure ^W/.VLNAM(P2)/ canceled>)]
	PUSHJ	P,NSTUSR		;TELL THE USERS THE GOOD NEWS
	$RETT
	SUBTTL	TIMER ROUTINES FOR LOCK AND UNLOCK

;These routines are called when the lock or unlock timer
;	goes off.  The scheduler calls here as the action routine
;	for the timer.
;	S1/	Event block adrs

LOCTIM:	$SAVE	<P1>
	LOAD	S1,.EVMSZ(S1)		;GET THE STRUCTURE NAME
	PUSHJ	P,FNDISK		;GET THE VOL BLOCK
	JUMPF	.RETT			;STR WENT AWAY. STRANGE.
	MOVE	P1,S1			;SAVE THE ADRS OF THE BLOCK
	LOAD	S1,.VLFLG(P1),VL.LCK	;GET THE LOCK STATE
	CAXN	S1,%LOCKP		;LOCK PENDING TIMER GONE OFF?
	JRST	LOKS.1			;YES, LOCK IT UP!
	CAXN	S1,%ULCKP		;UNLOCK PENDING TIMER?
	JRST	UNLOCK			;YES, UNLOCK IT
	$RETT				;WIERD,,TIMER WITH NOTHING PENDING

	;Here to lock or unlock a structure and inform the operator
	;
	;CALL:	P1/	0 for LOCK, -1 for UNLOCK
	;	P2/	VOL block adrs

LOKSTR:	EXCH	P1,P2			;SWAP VOL BLK ADRS AND LOCK/UNLOCK FLAG
	JUMPN	P2,UNLOCK		;GO  UNLOCK THE STR
LOKS.1:	LOAD	S1,.VLNAM(P1)		;GET THE STR NAME BACK
	PUSHJ	P,I$LOCK##		;LOCK IT UP
	JUMPF	[$WTO(<Can't LOCK structure ^W/.VLNAM(P1)/>,,,$WTFLG(WT.SJI))
		 JRST	UNLC.2]		;AND CLEAR THE STATUS
	$WTO	(<Structure ^W/.VLNAM(P1)/ locked>,,,$WTFLG(WT.SJI))
	MOVE	S1,.VLNAM(P1)		;GET THE STR NAME
	PUSHJ	P,CLRELN		;CLEAR ANY OUTSTANDING LOCK NOTIFY EVENTS
					;DON'T CLEAR LOCK TIMER EVENTS,
					;SINCE WE MAY BE HERE ON ONE OF THOSE
					;EVENTS, AND THE SERVICE ROUTINE EXPECTS
					;TO CLEAN IT UP
	MOVE	S1,P1			;AIM AT THE PRIMARY VOL BLOCK
	MOVEI	S2,[ITEXT(<Structure ^W/.VLNAM(P1)/ locked>)]
	PUSHJ	P,NSTUSR		;TELL ALL THE USERS THE BAD NEWS
LOKS.2:	MOVX	S1,%LOCKD		;GET LOCKED STATUS
	STORE	S1,.VLFLG(P1),VL.LCK	;SAVE THE LOCK STATUS
	SETZM	.VLLTM(P1)		;NO TIME, EITHER
	MOVE	S1,P1			;GET THE VOL BLK ADDR IN S1
	PUSHJ	P,CHKSTR		;CHECK FOR OTHER USERS
	$RETT				;RETURN

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here if it is an UNLOCK command. P1/ VOL block adrs

UNLOCK:	LOAD	S1,.VLNAM(P1)		;GET THE STR NAME BACK
	PUSHJ	P,I$UNLK##		;CLEAR THE LOCK
	JUMPT	UNLC.1			;WINS, TELL OPR
	$WTO	(<Can't UNLOCK structure ^W/.VLNAM(P1)/>,,,$WTFLG(WT.SJI))
	PJRST	LOKS.2			;AND SET IT STILL LOCKED

UNLC.1:	MOVEI	S2,[ITEXT(<Structure ^W/.VLNAM(P1)/ unlocked>)]
	$WTO	(<^I/0(S2)/>,,,$WTFLG(WT.SJI)) ;TELL THE OPERATOR
	MOVE	S1,P1			;GET THE VOL ADDRESS IN S1
	PUSHJ	P,NSTUSR		;TELL THE USERS ALSO

UNLC.2:	MOVX	S1,%UNLCK		;GET UNLOCKED CODE
	STORE	S1,.VLFLG(P1),VL.LCK	;SET THE FIELD
	SETZM	.VLLTM(P1)		;NO TIME, EITHER
	MOVE	S1,P1			;GET THE VOL ADDRESS IN S1
	SKIPE	S1,.VLUCB(P1)		;GET THE UCB ADDRESS (SHOULD NOT SKIP)
	PUSHJ	P,MATUNI		;TRY TO MOUNT THE VOLUME
	$RETT				;RETURN IN ANY CASE
>;END TOPS10
	SUBTTL	LOCNOT - Notify users (countdown) of pending locks

;This routine is called when an event timer for a structure lock goes off
; It finds the structure data base, and notifies all remaining users
; of that structure of the time remaining on the str.
; If there are some left, then another entry is put into the timer queue
; for the next countdown time to notify.
;Call -
;	S1/	Adrs of Event block for the countdown notification

TOPS10<
DEFINE	UDTMIN(N),<<<N>*^O1000000>/^D<24*60>> ;UDT REPRESENTATION OF N MINUTES

	MAXLMN==^D7		;MAX EXP OF 2 AT WHICH TO NOTIFY USERS

LMNTAB:	UDTMIN	(^D128)		;2**8 = TOO BIG AN ELEMENT, SAY THE MAX
	UDTMIN	(^D1)		;2**0 = 1 MINUTE
	UDTMIN	(^D2)		;2**1 = 2 MINUTES
	UDTMIN	(^D4)		;2**2 = 4 MINUTES
	UDTMIN	(^D8)		;2**3 = 8 MINUTES
	UDTMIN	(^D16)		;2**4 = 16 MINUTES
	UDTMIN	(^D32)		;2**5 = 32 MINUTES
	UDTMIN	(^D64)		;2**6 = 64 MINUTES


LOCNOT:	MOVE	S1,.EVMSZ+0(S1)		;GET THE STRUCTURE NAME
	PUSHJ	P,FNDISK		;FIND THE PRIMARY VOLUME BLOCK
	JUMPF	.RETT			;NOT THERE, QUIT, NO RE-RENTRY TO TIMER QUEUE

	;Internal entry with S1/  Vol block adrs

LOCN.I:	$SAVE	<P1,P2,P3,P4>		;SOME WORK SPACE
	MOVE	P1,S1			;SAVE PRI VOL BLK ADRS
	MOVE	P2,.VLLTM(P1)		;GET T=0
	SUB	P2,G$NOW##		;FIGURE UDT LEFT IN THIS TIMER
	JUMPLE	P2,.RETT		;WE'RE HERE TOO LATE, GET OUT
	MOVE	P3,P2			;NO, GET UDT LEFT
	IDIVI	P3,UDTMIN(1)		;CONVERT TO MINUTES LEFT
	MOVEI	S2,[ITEXT(<Structure ^W/.VLNAM(P1)/ will be locked in ^D/P3/ minutes>)]
	TLNE	P2,-1			;MORE THAN A DAY LEFT?
	MOVEI	S2,[ITEXT(<Structure ^W/.VLNAM(P1)/ will be locked at ^H/.VLLTM(P1)/>)]
	PUSHJ	P,NSTUSR		;NOTIFY ALL USERS OF THE STRUCTURE
	JFFO	P3,.+2			;FIND ORDER OF MAGNITUDE OF TIME LEFT
	$RETT				;?? CAN'T GET HERE, QUIT
	SUBI	P4,^D35			;CONVERT TO  -35 TO 0  RANGE
	JUMPE	P4,.RETT		;LESS THAN A MINUTE,, QUIT
	MOVNS	P4			;TO 0 TO 35
	CAIL	P4,MAXLMN		;BIGGER THAN MAX LOG MINUTES?
	SETZ	P4,			;YES, JUST SAY THE MOST WE KNOW
	MOVE	S2,LMNTAB(P4)		;GET THEN NUMBER OF MINUTES TO WAIT
	ADD	S2,G$NOW##		;SET THAT AS NEXT NOTIFY TIME
	MOVE	S1,.VLNAM(P1)		;GET THE STR NAME AGAIN
	PJRST	LNEVEN			;MAKE A NEW LOCK NOTIFY EVENT BLOCK
> ;END TOPS10 CONDITIONAL
	SUBTTL	CLEAR LOCKS ON STRUCTURE DISMOUNT

;This routine is called when a structure is dismounted, so that
;	Any pending event blocks can be cleaned up.
;	If we don't clean 'em up, and another structure gets mounted
;	before the timer goes off, then that (new) structure
;	will bear the brunt of the OPRs old LOCK or UNLOCK.
;	Also, any notify request blocks for this structure are cleaned up.

;Call -
;	S1/	Structure name just dismounted
;Returns -
;	TRUE (always)

TOPS10<
CLRELN:	MOVEI	S2,%EVNLC		;GET EVENT TYPE - LOCK NOTIFY
	SKIPA				;ENTER THE COMMON CODE
DMSLOK:	MOVEI	S2,%EVLCK		;GET EVENT TYPE - PENDING LOCK

	$SAVE	<P1,P2>
	DMOVE	P1,S1			;PRESERVE THE STR NAME, EVENT TYPE
	MOVE	S1,G$EVENT##		;GET THE LIST HANDLE
	$CALL	L%FIRST			;GET THE FIRST GUY
DSML.1:	JUMPF	.RETT			;NONE THERE, OH WELL
	LOAD	TF,.EVTYP(S2),EV.TYP	;GET THE EVENT TYPE
	CAMN	TF,P2			;IS IT THE RIGHT TYPE OF EVENT?
	CAME	P1,.EVMSZ(S2)		;YES, IS THIS THE STR BEING DISMOUNTED?
	SKIPA				;NOT A LOCK OR WRONG STRUCTURE,,SKIP
	$CALL	L%DENT			;LOCK OR NOTIFY FOR THIS STR, DELETE IT
	PUSHJ	P,L%NEXT		;EITHER WAY,,GET THE NEXT ENTRY
	JRST	DSML.1			;AND CHECK IT OUT
> ;END TOPS10 CONDITIONAL

	SUBTTL	LNEVEN - Set up a Lock notification event

;This routine is called whenever someone wants to put up a lock
; notification event for a particular structure.
; LOCNOT will be called at the specified time with
; the adrs of the lock notication event block.
; Call -
;	S1/	SIXBIT	 structure name
;	S2/	UDT at which to be notified
;Returns
;	TRUE	 (ALWAYS)

TOPS10<
LNEVEN:	MOVEM	S1,TMPVSL+.EVMSZ+0	;SAVE STR NAME AS FIRST (ONLY) DATA ARG
	MOVEM	S2,TMPVSL+.EVUDT	;SAVE WAKE-UP TIME
	MOVX	S1,INSVL.(%EVNLC,EV.TYP) ;EVENT TYPE
	MOVEM	S1,TMPVSL+.EVTYP	;NO FLAGS,
	MOVEI	S1,LOCNOT		;ROUTINE TO RUN AT THAT TIME
	MOVEM	S1,TMPVSL+.EVRTN	;SAVE THAT TOO
	MOVEI	S1,.EVMSZ+1		;MINIMAL EVENT BLOCK, WITH 1 DATUM
	MOVEI	S2,TMPVSL		;THERE'S THE BLOCK
	PJRST	S$EVENT##		;SEE ME LATER!
> ;END TOPS10 CONDITIONAL
	SUBTTL	D$LCKM - ROUTINE TO PROCESS THE RESET AFTER LOCK MESSAGE

	;CALL:	M/ The Message Address
	;
	;RET:	True Always

TOPS10<	INTERN	D$LCKM			;MAKE IT GLOBAL

D$LCKM:	PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A SECOND
	MOVE	S1,.RSTJB(M)		;GET THE USERS JOB NUMBER
	PUSHJ	P,FNDMDR		;FIND HIS MDR
	JUMPF	.RETT			;NOT THERE,,RETURN NOW
LCKM.0:	LOAD	P2,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	MOVNS	P2			;NEGATE IT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.MRVSL(AP)		;CREATE VSL SEARCH AOBJN AC

LCKM.1:	MOVE	S1,0(P2)		;PICK UP A VSL ADDRESS
	LOAD	P1,.VSFLG(S1),VS.TYP	;GET THE VOL SET TYPE
	SKIPE	.VSUCB(S1)		;IS THE VOL SET MOUNTED
	CAXE	P1,%DISK		;  AND IS IT A STRUCTURE ???
	JRST	LCKM.2			;NO TO EITHER,,TRY NEXT
	MOVE	S2,.VSVOL(S1)		;PICK UP THE VOL BLK ADDRESS
	LOAD	P1,.VLFLG(S2),VL.LCK	;GET THE VOL LOCK CODE
	CAXN	P1,%LOCKD		;IS IT LOCKED ???
	PUSHJ	P,D$DSLM		;YES,,TAKE THE STRUCTURE AWAY !!!

LCKM.2:	AOBJN	P2,LCKM.1		;CHECK ALL VSL'S
	$RETT				;THEN RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	VSREOV - ROUTINE TO SEND END OF VOLUME MSG TO TAPE LABELER

	;Send a End Of Volume-Set Message to the Tape Labeler on a Volume
	;	Switch Request in which there are no more Volumes in the
	;	Set.


	;CALL:	S1/ The UCB Address
	;	S2/ Returned status (%VEOF, %VABT, %VTMV)
	;
	;RET:	True Always

TOPS10	<
VSREOV:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVE	P1,S1			;SAVE THE UCB ADDRESS
	PUSH	P,S2			;SAVE THE STATUS BITS
	MOVX	S1,.QOVSD		;GET VOLUME SET DIRECTIVE MSG TYPE
	PUSHJ	P,LBLHDR		;SETUP THE MSG TO TAPE LABELER
	AOS	G$MSG+.OARGC		;BUMP ARG COUNT BY 1
	POP	P,G$MSG+.MSFLG		;INSERT THE STATUS BITS
	MOVEI	S2,G$MSG+.OHDRS		;GET THE FIRST BLOCK ADDRESS
	MOVX	S1,.VSDBL		;GET THE BLOCK TYPE
	STORE	S1,ARG.HD(S2),AR.TYP	;SAVE IN THE MESSAGE
	MOVX	S1,ARG.DA+VSDLEN	;GET THE BLOCK LENGTH
	STORE	S1,ARG.HD(S2),AR.LEN	;SAVE IT IN THE MESSAGE
	ADDM	S1,G$SAB##+SAB.LN	;BUMP THE SAB LENGTH
	MOVSS	S1			;MOVE RIGHT TO LEFT
	ADDM	S1,G$MSG+.MSTYP		;AND BUMP THE MESSAGE LENGTH
	ADDI	S2,ARG.DA		;POINT TO THE BLOCK DATA
	MOVE	S1,.UCBNM(P1)		;GET THE OLD DEVICE NAME
	MOVEM	S1,.VSDID(S2)		;SAVE IT IN THE MESSAGE
	SETZM	.VSDCD(S2)		;NO NEW DEVICE NAME !!!
	PUSHJ	P,C$SEND##		;SEND THE MSG OFF
	$RETT				;AND RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	REIMSG - ROUTINE TO SEND REINITIALIZATION MESSAGE TO PULSAR

;[1164] The REINIT message is really an device INITIALIZATION message
;[1164] with a couple extra arg blocks. The message is sent to PULSAR
;[1164] when the user specifies /NEW-VOLUME in his/her mount command.
;[1164] The allows to user to reinitalize the tapes before useing them.

;[1164] Offsets for prototype reinit message

	.TAPOF==.OHDRS				;[1164] DEVICE BLOCK OFFSET
	.RIDOF==.TAPOF+ARG.SZ+1			;[1164] REQUEST ID BLOCK OFFSET
	.DVIOF==.RIDOF+ARG.SZ			;[1164] DEVICE INI BLOCK OFFSET
	.LBTOF==.DVIOF+1			;[1164] LABEL TYPE BLOCK OFFSET
	.DENOF==.LBTOF+ARG.SZ			;[1164] DENSITY BLOCK OFFSET
	.PROOF==.DENOF+ARG.SZ			;[1164] PROTECTION BLOCK OFFSET
	.OWNOF==.PROOF+ARG.SZ			;[1164] OWNER PPN
	.HLDOF==.OWNOF+ARG.SZ			;[1164] HOLD TAPE BLOCK OFFSET
	.OVROF==.HLDOF+1			;[1164] OVERRIDE EXP DATE OFFSET
	.CTROF==.OVROF+1			;[1164] COUNT BLOCK OFFSET
	.NEWOF==.CTROF+ARG.SZ			;[1164] NEW-VOLUME BLOCK OFFSET
	.LISOF==.NEWOF+1			;[1164] VOL LIST BLOCK OFFSET
	REIMSZ==.LISOF+ARG.SZ			;[1164] MINIMUM REINIT MSG SIZE

;[1164] Prototype tape reinitialization mesage sent to PULSAR

REIMSG:	$BUILD(REIMSZ)
	  $SET(.MSTYP,MS.TYP,.ODSTP)		;[1164] SET TAPE FUNCTION
	  $SET(.OARGC,,^D12)			;[1164] NUMBER OF ARG BLOCKS
	  $SET(.TAPOF+ARG.HD,,<ARG.SZ+1,,.TAPDV>);[1164] DEVICE BLOCK HEADER
	  $SET(.RIDOF+ARG.HD,,<ARG.SZ,,.ORREQ>)	;[1164] REQUEST ID BLOCK
	  $SET(.DVIOF+ARG.HD,,<1,,.DVINI>)	;[1164] DEVICE INI FUNCTION
	  $SET(.LBTOF+ARG.HD,,<ARG.SZ,,.SILBT>)	;[1164] LABEL TYPE BLOCK HEADER
	  $SET(.DENOF+ARG.HD,,<ARG.SZ,,.SIDEN>)	;[1164] DENSITY BLOCK HEADER
	  $SET(.PROOF+ARG.HD,,<ARG.SZ,,.SIPRO>)	;[1164] PROTECTION BLOCK HEADER
	  $SET(.OWNOF+ARG.HD,,<ARG.SZ,,.SIOWN>)	;[1164] OWNER PPN
	  $SET(.HLDOF+ARG.HD,,<1,,.SIHLD>)	;[1164] HOLD TAPE BLOCK
	  $SET(.OVROF+ARG.HD,,<1,,.SIOVR>)	;[1164] OVERRIDE EXP DATE BLOCK
	  $SET(.CTROF+ARG.HD,,<ARG.SZ,,.SICTR>)	;[1164] COUNT BLOCK HEADER
	  $SET(.NEWOF+ARG.HD,,<1,,.SINEW>)	;[1164] NEW-VOLUME BLOCK
	  $SET(.LISOF+ARG.HD,,<ARG.SZ,,.SILST>)	;[1164] VOL LIST BLOCK
	$EOB

;Build reinit message in prototype and then copy to G$MSG.

REINIT:	PUSHJ	P,.SAVE4		;[1164] SAVE P1-P4
	DMOVE	P1,S1			;[1164] GET P1 = UCB, P2 = VSL
	SETZM	REIMSG+.TAPOF+ARG.DA+1	;[1164] ZERO THIS WORD
	MOVE	S1,[POINT 6,.UCBNM(P1)]	;[1164] MAKE SOURCE BYTE POINTER
	MOVE	S2,[POINT 7,<REIMSG+.TAPOF+ARG.DA>] ;[1164] GET DEST BP
	PUSHJ	P,SX2ASC		;[1164] CONVERT SIXBIT TO ASCII (SIGH)
	MOVE	S1,.VSRID(P2)		;[1164] GET REQUEST ID
	MOVEM	S1,REIMSG+.RIDOF+ARG.DA	;[1164] STORE IN MSG
	LOAD	S1,.VSFLG(P2),VS.LBT	;[1164] GET LABEL TYPE
	MOVEM	S1,REIMSG+.LBTOF+ARG.DA	;[1164] STORE IN MSG
	MOVX	S2,.TFD00		;[1164] ASSUME DENSITY DEFAULTED
	MOVX	S1,VS.DDN		;[1164] GET DEFAULTED DENSITY BIT
	TDNN	S1,.VSATR(P2)		;[1164] DID WE DEFAULT THE DENSITY?
	LOAD	S2,.VSATR(P2),VS.DEN	;[1164] NO,,GET DENSITY USER WANTS
	MOVEM	S2,REIMSG+.DENOF+ARG.DA	;[1164] STORE IN MSG
	SETOM	S2			;[1164] ASSUME PROTECTION NOT SPECIFIED
	MOVX	S1,VS.DPR		;[1164] GET DEFAULT PROTECTION BIT
	TDNN	S1,.VSATR(P2)		;[1164] DID USER SPECIFY /PROT:?
	LOAD	S2,.VSATR(P2),VS.PRT	;[1164] YES,,GET PROTECTION HE WANTS
	MOVEM	S2,REIMSG+.PROOF+ARG.DA	;[1164] STORE IN MSG
	MOVE	S1,.MRUSR(AP)		;[1164] GET REQUESTOR'S PPN
	MOVEM	S1,REIMSG+.OWNOF+ARG.DA	;[1164] STORE IN MSG
	LOAD	S1,.VSCVL(P2),VS.CNT	;[1164] GET VOL COUNT
	MOVEM	S1,REIMSG+.CTROF+ARG.DA	;[1164] STORE IN MSG
	MOVN	P3,S1			;[1164] SAVE NEGATIVE VOL COUNT
	ADDI	S1,1			;[1164] GET CORRECT LENGTH FOR .SILST BLK
	STORE	S1,REIMSG+.LISOF+ARG.HD,AR.LEN ;[1164] SET CORRECT LENGTH
	ADDI	S1,REIMSZ-2		;[1164] COMPUTE MSG SIZE
	STORE	S1,REIMSG+.MSTYP,MS.CNT	;[1164] STORE IN MSG
	MOVE	S2,[REIMSG,,G$MSG]	;[1164] COPY OUR MSG TO G$MSG BUFFER
	BLT	S2,G$MSG-1(S1)		;[1164] ..
	HRLZS	P3			;[1164] MAKE AOBJN PTR FOR VOLS
	HRRI	P3,G$MSG+.LISOF+ARG.DA	;[1164] ..

;[1164] Copy VOLIDs to reinit message.

	MOVEI	P4,.VSVOL(P2)		;[1164] GET ADDR TO 1ST VOL BLOCK PTR
REIN.1:	SKIPN	S1,(P4)			;[1164] GET VOL BLOCK ADDR
	STOPCD	(MVP,HALT,,<Missing VOL block pointer>) ;[1164] OOPS!!!
	MOVE	S2,.VLNAM(S1)		;[1164] GET VOLID
	MOVEM	S2,(P3)			;[1164] STORE IN MESSAGE
	MOVEI	S2,%STAIN		;[1164] STATUS CODE FOR 'INITIALIZING'
	STORE	S2,.VLFLG(S1),VL.STA	;[1164] SET FOR ACCURATE QUEUE LISTINGS
	ADDI	P4,1			;[1164] BUMP VOL BLOCK ADDR PTR
	AOBJN	P3,REIN.1		;[1164] LOOP FOR ALL VOLS

;[1164] Send message to PULSAR and finish up.

	MOVE	S1,.VSFLG(P2)		;[1164] GET VSL FLAGS
	TXZ	S1,VS.NEW		;[1164] TURN OFF NEW-VOLUME BIT
	TXO	S1,VS.INI		;[1164] TURN ON REINIT-PROGRESS BIT
	MOVEM	S1,.VSFLG(P2)		;[1164] PUT FLAGS BACK
	MOVX	S1,UC.INI		;[1164] GET INI BIT FOR UCB
	IORM	S1,.UCBST(P1)		;[1164] LITE IT IN UCB STATUS WORD
	MOVEI	M,G$MSG			;[1164] GET MSG ADDR IN M
	PJRST	I$FPLR##		;[1164] SEND MESSAGE TO PULSAR

;[1164] ;Convert SIXBIT to ASCII
;[1164]
;[1164] 	S1 = Source BP
;[1164] 	S2 = Destination BP
;[1164] 	Only 6 chars are converted and S1, S2 are returned updated

SX2ASC:	$SAVE	<T1,T2>			;[1164] SAVE T1, T2
	MOVEI	T2,6			;[1164] ONLY 6 CHARS CONVERTED
SX2A.1:	ILDB	T1,S1			;[1164] GET A BYTE
	ADDI	T1,40			;[1164] ASCIIZE
	IDPB	T1,S2			;[1164] STORE IN DESTINATION
	SOJG	T2,SX2A.1		;[1164] LOOP FOR 6 CHARS
	POPJ	P,			;[1164] RETURN
	SUBTTL	DELETE - ROUTINE TO DELETE ALL NEW VOL SETS FOR A USER

	;CALL:	S1/ The VSL Address of one of those to be deleted
	;	AP/ The MDR Address
	;
	;RET:	True Always

	;A NEW Volume Set is defined to be one whose LINK code is the
	;same as the one in the VSL that was passed as an argument
	;to this routine AND whose VS.WAL bit is still up.

D$DLVS::				;MAKE IT GLOBAL
DELETE:	PUSHJ	P,.SAVE3		;SAVE P1 & P2 & P3 FOR A MINUTE
	LOAD	P2,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	JUMPE	P2,DELMDR		;NOTHING THERE,,DELETE THE MDR
	LOAD	P1,.VSLNK(S1),VS.LNK	;GET THE LINK CODE WE ARE LOOKING FOR
	MOVEI	P3,.MRVSL(AP)		;POINT TO THE VSL LIST

DELE.1:	MOVE	S1,0(P3)		;GET A VSL ADDRESS
	LOAD	S2,.VSLNK(S1),VS.LNK	;GET ITS LINK CODE
	LOAD	TF,.VSFLG(S1),VS.WAL	;GET THE WAITING FOR ALLOCATION BIT
	CAMN	P1,S2			;DO THE LINK CODES MATCH ???
	SKIPN	TF			;  AND IS HE WAITING FOR ALLOCATION ???
	JRST	DELE.2			;WRONG LINK CODE OR NOT WAITING,,SKIP
	PUSHJ	P,DELVSL		;YES,,DELETE THE VSL
	SKIPA				;LOOK AT NEXT VSL

DELE.2:	AOS	P3			;POINT TO THE NEXT VSL ADDRESS
	SOJG	P2,DELE.1		;CONTINUE FOR ALL VSL'S
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	SKIPN	S1			;THERE ARE MORE,,DON'T DELETE THE MDR
	PUSHJ	P,DELMDR		;NO MORE REQUESTS,,DELETE THIS MDR
	$RETT				;RETURN

	SUBTTL	REMOVE - ROUTINE TO DELETE A SPECIFIC VSL AND RETRY THE MOUNT

	;CALL:	S1/ The VSL Address
	;	AP/ The MDR Address
	;
	;RET:	True Always

TOPS10<
D$REMO::
REMOVE:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A SECOND
	LOAD	P1,.VSLNK(S1),VS.LNK	;GET THE VSL LINK CODE
	PUSHJ	P,DELVSL		;DELETE THE BAD VSL
	LOAD	S2,.MRCNT(AP),MR.CNT	;ANY REQUESTS LEFT ???
	JUMPE	S2,DELMDR		;NO,,DELETE HIS MDR
	MOVNS	S2			;NEGATE THE COUNT
	MOVSS	S2			;MOVE RIGHT TO LEFT
	HRRI	S2,.MRVSL(AP)		;CREATE VSL SEARCH AOBJN AC
REMO.1:	MOVE	S1,0(S2)		;GET A VSL ADDRESS
	LOAD	TF,.VSLNK(S1),VS.LNK	;GET ITS LINK CODE
	CAME	TF,P1			;DO THEY MATCH ???
	JRST	[AOBJN S2,REMO.1	;NO,,TRY NEXT
		 $RETT ]		;NO MORE,,RETURN
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	PUSHJ	P,D$ALOC		;TRY TO PERFORM ALLOCATION ONCE AGAIN
	JUMPF	[JUMPL	S1,.RETT	;ALLOCATION POSTPONED,,JUST RETURN
		 MOVE	S1,P1		;NO GOOD,,GET THE VSL ADDRESS BACK
		 PJRST	DELETE ]	;  AND DELETE THE VOL SETS JUST ADDED
	MOVE	S1,P1			;GET THE VSL ADDRESS BACK
	PUSHJ	P,MNTVSL		;RETRY THE MOUNT
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	DELVSL - ROUTINE TO DELETE A VSL

	;CALL:	S1/ The VSL Address
	;	AP/ The MDR Address
	;
	;RET:	True Always

	;AC Usage in this Subroutine
	;
	;		P1/ VSL Entry
	;		P2/ VOL Entry
	;		P3/ UCB Entry
	;		P4/ VOL AOBJN AC

TOPS10<
D$DVSL::
DELVSL:	PUSHJ	P,.SAVE4		;SAVE P1-P4
	MOVEI	P1,(S1)			;GET THE VSL ADDRESS IN P1
	CAIN	P1,TMPVSL		;IS THIS TEMPORARY VSL?
	JRST	DELV.0			;YES..DON'T TRY TO DELETE IT
	MOVE	S2,.VSFLG(P1)		;GET THE VSL FLAG WORD
	TXO	S2,VS.UAL		;LITE 'USER ALLOCATED' TO STOP RECURSION
	MOVEM	S2,.VSFLG(P1)		;SAVE THE NEW VSL STATE
	MOVE	S1,P1			;GET BACK VSL ADRS
	PUSHJ	P,ALCVSL		;RETURN HIS RESOURCES TO THE ALLOC POOL
	MOVE	S1,P1			;RESTORE THE VSL ADDRESS

	LOAD	S2,.VSFLG(S1),VS.WAL	;GET THE 'WAITING FOR ALLOCATION' BIT
	SKIPN	S2			;IF ALLOCATED,,THEN
	PUSHJ	P,RETBMA		;  REMOVE HIS CLAIM ON THESE RESOURCES

DELV.0:	LOAD	P4,.VSCVL(P1),VS.CNT 	;GET THE VOLUME COUNT
	JUMPE	P4,DEL.8A		;NO VOLUMES,,SKIP THIS
	MOVNS	P4			;MAKE IT NEGATIVE
	HRLZS	P4			;CREATE A VOL AOBJN AC (-COUNT,,0)
	HRRI	P4,.VSVOL(P1)		;GET THE VOL LIST ADDRESS IN RIGHT HALF
DELV.1:	MOVE	P2,0(P4)		;PICK UP THE CURRENT VOL ADDRESS
	LOAD	S1,.VLOWN(P2),VL.CNT	;GET THE VSL COUNT IN S1
	MOVNS	S1			;MAKE IT NEGATIVE
	HRLZS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.VLVSL(P2)		;CREATE A VSL AOBJN AC

DELV.2:	MOVE	P3,0(S1)		;PICK UP THE VSL ADDRESS + FLAGS IN P3
	CAIN	P1,0(P3)		;FIND THIS USERS VSL ADDRESS IN THE VOL
	JRST	DELV.3			;   ENTRY.
	AOBJN	S1,DELV.2		;CONTINUE TILL FOUND
	STOPCD	(CFV,HALT,,<Can't find VSL address in VOL entry>)

DELV.3:	$PACK	S1			;PACK THE VOL VSL LIST
	DECR	.VLOWN(P2),VL.CNT	;AND DECRIMENT THE USER REQUEST COUNT 

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

DELV.5:	SKIPN	S2,.VLUCB(P2)		;IS THE VOLUME MOUNTED ???
	JRST	[MOVE  S1,P2		;NO,,GET THE VOL ADDRESS IN S1
		 PUSHJ P,DELVOL		;   DELETE THE VOLUME
		 JRST  DELV.8 ]		;   AND GET THE NEXT VOLUME
	LOAD	S1,.UCBST(S2),UC.DVT	;GET THE DEVICE TYPE
	CAIN	S1,%DISK		;STRUCTURE?
	JRST	DELV.8			;YES,,GET NEXT VOLUME
	LOAD	S1,.VLOWN(P2),VL.CNT	;GET THE REQUEST COUNT
	JUMPG	S1,DELV.6		;MULTIPLE REQUESTORS,,TRY ALLOCATION
	JRST	DELV.7			;OTHERWISE UNLOAD THE DRIVE

;Here when a volume referenced by the VSL has other requestors
;See if we can give the volume to another requestor.

DELV.6:	LOAD	S1,.UCBST(S2),UC.DVT	;GET THE DEVICE TYPE
	CAIN	S1,%DTAP		;DECTAPE?
	JRST	DEL.6A			;YES--SKIP LABELED MAGTAPE STUFF
	LOAD	S1,.VLFLG(P2),VL.LBT	;GET LABEL TYPE
	PUSHJ	P,GETLBT		;AND MAP TO EASY CODE
	CAXE	S1,%LABEL		;IS IT A LABELED VOLUME?
	JRST	DELV.7			;NO, UNLOAD THIS USER'S TAPE
DEL.6A:	MOVE	S1,.VLUCB(P2)		;COPY UCB NAME TO ARG REG
	PUSHJ	P,MATUNI		;TRY TO GIVE IT AWAY
	JRST	DELV.8			;CONTINUE WITH NEXT VOLUME

DELV.7:	MOVE	S1,P2			;AIM AT THIS VOLUME
	TXNE	P3,VL.OWN		;DID WE EVER OWN THIS VOLUME ???
	PUSHJ	P,VLUNLO		;UNLOAD AND BREAK LINKS FOR THIS VOL

DELV.8:	AOBJN	P4,DELV.1		;CONTINUE THROUGH ALL VOLUMES

DEL.8A:	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT IN S1
	MOVNS	S1			;MAKE THE VSL COUNT NEGATIVE
	HRLZS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.MRVSL(AP)		;POINT TO THE VSL ADDRESS LIST

DELV.9:	CAME	P1,0(S1)		;FIND THE VSL POS IN THE MDR VSL LIST
	JRST	[AOBJN	S1,DELV.9	;NOT FOUND,,TRY ALL VSL ADDRESSES
		 STOPCD	(VAM,HALT,,<VSL address is missing in a MDR>) ] ;NONE,,TROUBLE !
	$PACK	S1			;PACK THE MDR VSL LIST
	DECR	.MRCNT(AP),MR.CNT	;AND DECREMENT THE MDR VSL COUNT BY 1

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	MOVEI	S1,.VSVSN(P1)		;POINT TO THE VOLUME-SET NAME
	LOAD	S2,.VSFLG(P1),VS.TYP	;GET THE REQUEST TYPE
	CAIE	S2,%DISK		;DON'T DELETE STRUCTURES (SHARABLE)
	PUSHJ	P,V$DELE##		;POSSIBLY DELETE CATALOG CACHE ENTRY
	CAIN	P1,TMPVSL		;IS THIS THE TEMP VSL ???
	$RETT				;YES,,JUST RETURN NOW
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID IN S1
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,L%APOS		;POSITION TO THE VSL ENTRY
	PUSHJ	P,L%DENT		;DELETE THIS VSL ENTRY
	$RETT				;RETURN
>


TOPS20 <
D$DVSL::
DELVSL:	PUSHJ	P,.SAVE4		;SAVE P1-P4
	MOVE	P1,S1			;GET THE VSL ADDRESS IN P1
	LOAD	P4,.VSCVL(P1),VS.CNT 	;GET THE VOLUME COUNT
	JUMPE	P4,DELV.2		;NO VOLUMES,,JUST DELETE THE VSL
	MOVNS	P4			;MAKE IT NEGATIVE
	HRLZS	P4			;CREATE A VOL AOBJN AC (-COUNT,,0)
	HRRI	P4,.VSVOL(P1)		;GET THE VOL LIST ADDRESS IN RIGHT HALF
DELV.1:	MOVE	P2,0(P4)		;PICK UP THE CURRENT VOL ADDRESS
	SKIPE	P3,.VLUCB(P2)		;PICK UP THE CURRENT UCB ADDRESS
	SETZM	.UCBVL(P3)		;CLEAR THE VOL POINTER IN THE UCB
	MOVE	S1,VOLQUE		;GET THE VOL QUEUE ID
	MOVE	S2,P2			;GET THE VOLUME ENTRY ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO THE VOLUME ENTRY
	PUSHJ	P,L%DENT		;AND DELETE IT
	AOBJN	P4,DELV.1		;CONTINUE THROUGH ALL VOLUMES
DELV.2:	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT IN S1
	MOVNS	S1			;MAKE THE VSL COUNT NEGATIVE
	HRLZS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.MRVSL(AP)		;POINT TO THE VSL ADDRESS LIST

DELV.3:	CAME	P1,0(S1)		;FIND THE VSL POS IN THE MDR VSL LIST
	JRST	[AOBJN	S1,DELV.3	;NOT FOUND,,TRY ALL VSL ADDRESSES
		STOPCD	(VAM,HALT,,<VSL address is missing in a MDR>) ] ;NONE,,TROUBLE !
	$PACK	S1			;PACK THE MDR VSL LIST
	DECR	.MRCNT(AP),MR.CNT	;AND DECREMENT THE MDR VSL COUNT BY 1

	CAIN	P1,TMPVSL		;IS THIS THE TEMPORARY VSL ???
	$RETT				;YES,,THEN NOTHING TO DELETE !!
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	MOVE	S2,P1			;GET THE VSL ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO THE VSL
	PUSHJ	P,L%DENT		;AND DELETE IT
	$RETT				;RETURN
>
	SUBTTL	ALCVSL - ROUTINE TO RETURN A VSL TO THE ALLOCATION POOL

	;CALL:	S1/ The VSL Address
	;
	;RET:	TRUE ALWAYS

TOPS10<
D$ALCV::				;MAKE IT GLOBAL
ALCVSL:	PUSHJ	P,.SAVE1		;SAVE P1
	HRRZ	P1,S1			;SAVE THE VSL ADDRESS
	MOVE	S1,P1			;GET JUST THE VSL ADDRESS
	PUSHJ	P,CHKOWN		;LOCATE THIS GUYS VSL ADDRESS 
	MOVX	S2,VL.ASK+VL.ASN	;GET ASKED+ASSIGNED STATUS BITS
	ANDCAM	S2,0(S1)		;   AND CLEAR THEM
	MOVE	S1,P1			;RESTORE THE VSL ADDRESS
	PUSHJ	P,RETA%C		;RETURN THE 'A' AND 'C' MATRIX RESOURCES
	SKIPN	S1,.VSUCB(P1)		;GET ANY UCB ADDRESS
	JRST	ALCV.2			;NONE THERE,,SKIP THIS
	SETZM	.VSUCB(P1)		;CLEAR THE VSL'S UCB POINTER
	SETZM	.UCBVS(S1)		;CLEAR THE UCB'S VSL POINTER
	MOVX	S2,UC.VSW		;GET THE VOLUME SWITCH FLAG
	ANDCAM	S2,.UCBST(S1)		;CLEAR IT 
	LOAD	S2,.VSFLG(P1),VS.TYP	;GET VOLUME SET TYPE
	CAXN	S2,%TAPE		;IS THIS A TAPE VOLUME SET?
	PUSHJ	P,SNDVDM		;TELL TAPE LABELER USER IS GONE
ALCV.2:	MOVX	S1,VS.ALC+VS.OPR	;GET THE 'ALLOCATION'+'OPR' BITS
	IORM	S1,.VSFLG(P1)		;LITE THEM
	ZERO	.VSFLG(P1),VS.VSW	;CLEAR THE VOLUME SWITCH FLAG
	ZERO	.VSCVL(P1),VS.OFF	;RESET THE CURRENT VOL OFFSET
	ZERO	.VSLNK(P1),VS.LNK	;ALSO ZAP THE LINK CODE
	SKIPN	S1,.VSTXT(P1)		;ANY SECONDARY TEXT ???
	JRST	ALCV.3			;NO,,SKIP THIS
	LOAD	S2,S1,VS.ADR		;GET THE TEXT ADDRESS IN S2
	LOAD	S1,S1,VS.LEN		;GET THE TEXT LENGTH IN S1
	PUSHJ	P,M%RMEM		;RETURN IT TO THE FREE POOL
	SETZM	.VSTXT(P1)		;AND ZAP THE POINTER

ALCV.3:	MOVE	S1,P1			;GET THE VSL ADDRESS
	LOAD	S2,.VSFLG(S1),VS.UAL	;GET THE 'USER ALLOCATED' BIT
	SKIPN	S2			;IF 'USER ALLOC',DONT DELETE VSL
	PUSHJ	P,DELVSL		;DELETE THE VSL
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL
	SUBTTL	DELMDR - ROUTINE TO DELETE AN MDR

	;CALL:	AP/ The MDR Address
	;
	;RET:	True Always

DELMDR:
TOPS10<	PUSHJ	P,D$BMTX		;FIND THE USERS 'B' MATRIX ENTRY
	JUMPF	DELM.1			;NONE THERE,,SKIP THIS
	PUSHJ	P,L%DENT		;DELETE IT
	PUSHJ	P,D$CMTX		;FIND THE USERS 'C' MATRIX ENTRY
	SKIPF				;NONE THERE,,SKIP
	PUSHJ	P,L%DENT		;DELETE IT
	SOS	PROCNT			;ADJUST THE PROCESS COUNT
> ;END TOPS10 CONDITIONAL

DELM.1:	SKIPE	S1,.MRQEA(AP)		;ANY QE ???
	SETZM	.QEMDR(S1)		;YES,,ZAP IT
	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	MOVE	S2,AP			;GET THE MDR ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO THAT MDR ENTRY
	PUSHJ	P,L%DENT		;DELETE IT
	$RETT				;AND RETURN
	SUBTTL	DELVOL - ROUTINE TO DELETE VOL BLOCKS FROM THE VOL QUEUE

	;CALL:	S1/ The VOL Address of the VOL you want deleted
	;
	;RET:	True Always

	;This routine will delete the volume whose address is passed in S1 
	;And also delete any VOL Blocks connected to that VOL which can
	;Be Deleted

TOPS10	<
DELVOL:	PUSHJ	P,.SAVE3		;SAVE P1 & P2 & P3 FOR A MINUTE
	MOVE	P2,S1			;SAVE ORIGIONAL VOL ADDR HERE
DELX.0:	MOVE	P1,S1			;SAVE AS CURRENT ALSO
	LOAD	S1,.VLPTR(P1),VL.PRV	;FIND THE PRI VOLUME BLOCK
	JUMPN	S1,DELX.0		;   IN THE VOL QUEUE

	LOAD	S1,.VLFLG(P1),VL.STA	;GET THE STRUCTURE STATUS BITS
	CAXN	S1,%STAMN		;IS IT MOUNTED ???
	$RETT				;YES,,JUST RETURN
	SKIPE	S1,.VLUCB(P2)		;IS THE ARG VOLUME MOUNTED ON A DRIVE ?
	SETZM	.UCBVL(S1)		;YES,,BREAK UCB VOL LINK
	SETZM	.VLUCB(P2)		;BREAK VOL UCB LINKS
	LOAD	S1,.VLOWN(P1),VL.CNT	;GET THE REQUEST COUNT
	JUMPN	S1,.RETT		;NOT ZERO,,DON'T DELETE THE VOLUME
	LOAD	S1,.VLFLG(P1),VL.RSN	;GET THE VOLUME RESOURCE NUMBER
	PUSHJ	P,GIVRSN		;GIVE BACK THAT RESOURCE

DELX.1:	MOVE	S2,P1			;GET THE PRI VOL BLK ADDRESS IN S2
	LOAD	P1,.VLPTR(P1),VL.NXT	;GET NEXT VOL BLK ADDRESS
	SKIPE	S1,.VLUCB(S2)		;IS THE VOLUME MOUNTED ???
	SETZM	.UCBVL(S1)		;YES,,ZAP UCB/VOL POINTER
	MOVE	S1,VOLQUE		;NO,,GET THE VOLUME QUEUE ID
	PUSHJ	P,L%APOS		;POSITION TO THAT ENTRY
	PUSHJ	P,L%DENT		;AND DELETE IT
	JUMPN	P1,DELX.1		;IF MORE VOL BLKS,,PROCESS'EM
	$RETT				;ELSE RETURN
>
	SUBTTL	GETLBT - ROUTINE TO RECODE THE VOLUME LABEL TYPE

	;CALL:	S1/ The Volume Label Type
	;
	;RET:	S1/ either %UNLBL (Unlabeled) or %LABEL (Labeled)

TOPS10 <
D$GLBT::
GETLBT:	CAXE	S1,.TFLBP		;IS THE LABEL TYPE BYPASS LABELS ???
	CAXN	S1,.TFLTM		;OR IS IT LEADING TAPE MARK ???
	JRST	GETL.1			;YES,,EXIT
	CAXE	S1,.TFLNS		;IS THE LABEL TYPE NON-STANDARD LABESL ?
	CAXN	S1,.TFLNL		;OR IS IT NO LABELS ???
	SKIPA				;YES,,UNLABELED !!!
	CAXN	S1,.TFLNV		;UNLABELED/NO EOV PROCESSING,,UNLABELED
GETL.1:	SKIPA	S1,[%UNLBL]		;RETURN %UNLBL IN S1
	MOVX	S1,%LABEL		;IF LABELED,,RETURN %LABEL IN S1
	$RETT				;RETURN
>
	SUBTTL	FNDDSK - ROUTINE TO FIND A DSK VOL BLOCK USING VOLUME ID
;		FNDVOL - ROUTINE TO FIND A VOL BLOCK LINKED TO A UCB (SPINNING)

	;CALL:	S1/ The Volume ID in Sixbit
	;
	;RET:	S1/ The VOL Block Address

TOPS10 <
FNDVOL:	TDZA	S2,S2			;[1227] INDICATE ENTRY POINT
FNDDSK:	SETOM	S2			;[1227]
	PUSHJ	P,.SAVE2		;[1227] SAVE P1 & P2 FOR A MINUTE
	DMOVE	P1,S1			;[1227] SAVE THE VOL ID WE ARE LOOKING FOR
	MOVE	S1,VOLQUE		;GET THE VOL QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST ENTRY
	JRST	FNDD.2			;SKIP THE FIRST TIME THROUGH

FNDD.1:	MOVE	S1,VOLQUE		;GET THE VOL QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT VOL BLOCK
FNDD.2:	JUMPF	.RETF			;NO MORE,,RETURN VOL NOT FOUND
	CAME	P1,.VLVID(S2)		;YES,,IS THIS THE VOL WE WANT ???
	JRST	FNDD.1			;NO,,SKIP IT
;**;[1227] Change code at FNDD.2+3L. /LWS
	JUMPL	P2,FNDD.3		;[1227] IF FNDDSK, JUST RETURN VOL ADDR
	SKIPN	.VLUCB(S2)		;[1227] ELSE SEE IF VOL IS LINKED TO UCB
	JRST	FNDD.1			;[1227] IT'S NOT, KEEP LOOKING
FNDD.3:	MOVE	S1,S2			;[1227] RETURN THE VOL BLOCK ADDRESS IN S1
	$RETT				;AND RETURN

> ;END TOPS10
	SUBTTL	CREVOL - ROUTINE TO CREATE A VOL BLOCK IN VOL QUEUE

	;CALL:	No Calling Parms
	;
	;RET:	S1/ The VOL Queue Entry

D$CVOL::
CREVOL:	MOVE	S1,VOLQUE		;GET THE VOL QUEUE ID
	PUSHJ	P,L%LAST		;POSITION TO THE LAST VOL ENTRY
	MOVE	S1,VOLQUE		;GET THE VOL QUEUE ID
	MOVX	S2,VOLLEN		;AND THE VOL ENTRY LENGTH
	PUSHJ	P,L%CENT		;CREATE A VOL QUEUE ENTRY
	MOVE	S1,S2			;GET THE ENTRY ADDRESS IN S1
	$RETT				;AND RETURN

	SUBTTL	USRACK - ROUTINE TO GENERATE AN ACK TO THE USER FOR MOUNT/ALLOC

	;CALL:	AP/ The MDR Address
	;
	;RET: 	True Always

USRACK:	PUSHJ	P,.SAVE4		;[1173] SAVE P1 - P4
	PUSHJ	P,MDASBP		;SET UP FOR CALLS TO MDADBP
	SETZB	P4,G$MSG##		;[1173] CLEAR P4 AND FIRST WORD OF MSG
	SKIPN	G$OPRA##		;OPERATOR ON DUTY?
	$TEXT	(MDADBP,<% No operator on duty>) ;NO
	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	MOVNS	P1			;NEGATE IT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.MRVSL(AP)		;CREATE VSL AOBJN AC
	LOAD	S2,.MRCNT(AP),MR.LNK	;GET THE CURRENT VSL LINK CODE

USRA.1:	MOVE	P2,0(P1)		;GET A VSL ADDRESS
	LOAD	S1,.VSLNK(P2),VS.LNK	;GET THE VSL LINK CODE
	CAME	S1,S2			;DO THEY MATCH ???
	JRST	USRA.2			;NO,,SKIP IT
	LOAD	P3,.VSFLG(P2),VS.ALC	;GET THE ALLOCATE BIT
	$TEXT	(MDADBP,<[^T/@TYPE(P3)/ request ^T/.VSVSN(P2)/ queued, request #^D/.VSRID(P2)/]>)
	MOVE	P4,P2			;[1173] SAVE VSL ADDRESS

USRA.2:	AOBJN	P1,USRA.1		;LOOP THROUGH ALL VSL'S
	JUMPE	P4,.RETT		;[1173] SHOULDN'T HAPPEN, BUT.....
	SETZM	S1			;GET A NULL BYTE
	PUSHJ	P,MDADBP		;MAKE IT ASCIZ
;**;[1170] Insert 3 lines after USRA.2+2L. 29-Dec-83 /LWS
	MOVE	S1,.VSRFL(P4)		;[1173] [1170] GET VSL ACK DATA FLAGS
	TXZE	S1,MR.GFR		;[1173] CLEAR GOPHER BIT
	EXCH	S1,.VSRFL(P4)		;[1173] GET ORIGINAL BITS AND UPDATE TOO
	JUMPN	P3,USRA.3		;[1173] [1170] ALWAYS TRY TO GIVE ALLOC ACK
	TXNE	S1,MR.GFR		;[1173] [1170] GOPHER ONLY WANTS ACK WHEN MOUNTED
	$RETT				;[1173] RETURN
USRA.3:	MOVE	S1,P4			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;NOTIFY THE USER
	$RETT				;AND RETURN

TYPE:	[ASCIZ/Mount/]
	[ASCIZ/Allocate/]

	SUBTTL	ACKUSR - ROUTINE TO CREATE AN ACK AFTER THE VOL SET IS MOUNTED

	;CALL:	S1/ The VSL Address
	;
	;RET:	True Always

ACKUSR:	PUSHJ	P,.SAVE4		;SAVE P1 - P4
	$SAVE	<T3>			;[1173] SAVE T3, TOO
	STKVAR	<<QUE,^D30>>		;SETUP A QUEUE FOR VSL'S
	LOAD	P1,.VSLNK(S1),VS.LNK	;GET THE VOL SET LINK CODE
	MOVE	AP,.VSMDR(S1)		;GET THE MDR ADDRESS
	SETZM	G$MSG##			;CLEAR THE FIRST WORD OF ACK BUFFER
	PUSHJ	P,MDASBP		;SET UP FOR CALLS TO MDADBP
	LOAD	P2,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	MOVNS	P2			;NEGATE IT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.MRVSL(AP)		;CREATE VSL AOBJN AC
	MOVEI	P3,QUE			;GET THE VSL QUEUE ADDRESS
	HRLI	P3,-^D30		;GEN THE QUEUE STACK POINTER
	PUSH	P3,[-1]			;MARK THE END OF THE QUEUE

	;Check to make sure user has all required volume sets assigned

ACKU.1:	MOVE	P4,0(P2)		;GET A VSL ADDRESS
	LOAD	S2,.VSLNK(P4),VS.LNK	;GET ITS LINK CODE
	CAME	S2,P1			;DO THEY MATCH ???
	JRST	ACKU.2			;NO,,TRY NEXT VSL
	MOVE	S1,P4			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,CHKOWN		;DOES HE OWN THE VOLUME ???
	MOVE	S2,(S1)			;GET FLAGS
	TXNN	S2,VL.AAS		;BUT WAS IT ALREADY ASSIGNED BEFORE?
	TXNN	S2,VL.ASN		;IS IT ASSIGNED?
	$RETF				;NO,,RETURN
	PUSH	P3,P4			;YES,,QUEUE UP THE VSL ADDRESS
ACKU.2:	AOBJN	P2,ACKU.1		;LOOK FOR ANOTHER

	;If we get this far, its OK to ack the user

ACKU.3:	POP	P3,P4			;GET A VSL ADDRESS OFF THE QUEUE
	CAMN	P4,[-1]			;ARE WE DONE ???
	JRST	ACKU.6			;YES,,ACK THE USER !!!
	MOVE	T3,P4			;[1173] SAVE VSL ADDR FOR ACKING
	LOAD	P1,.VSCVL(P4),VS.OFF	;GET THE OFFSET TO THE CURRENT VOL
	ADDI	P1,.VSVOL(P4)		;POINT TO ITS ADDRESS
	MOVE	P1,0(P1)		;SAVE THE VOL ADDRESS IN P1
	SKIPE	P2,.VLUCB(P1)		;GET THE UCB ADDRESS IN P2
	JRST	ACKU.4			;MUST BE A NON-MDA DEVICE
; Here for non-MDA devices
TOPS10<
	MOVE	S1,P4			;GET VSL ADDRESS
	PUSHJ	P,I$CGEN##		;GET DEVICE TYPE
	  JUMPF	ACKU.3			;SHOULDN'T HAPPEN
	MOVE	T1,S1			;GET INDEX INTO DEVICE NAME TABLE
	MOVEI	S2,ACKU.X		;ASSUME NO LOGICAL NAME ASSIGNED
	SKIPE	.VSLNM(P4)		;HAVE A LOGICAL NAME?
	MOVEI	S2,ACKU.Y		;YES
	TDZA	TF,TF			;NO JUNK FOR DEVICE TYPE
>

TOPS20 <JRST	ACKU.3			;TOPS20 DOESN'T UNDERSTAND REAL DEVICES
>
; Here for MDA devices
ACKU.4:	LOAD	TF,.UCBST(P2),UC.DVT	;GET THE DEVICE TYPE
	SKIPN	S1,.VSTXT(P4)		;ANY ADDITIONAL TEXT ???
	MOVEI	S1,[0]			;NO,,GET A NULL
	CAXN	TF,%DISK		;IS THIS A STRUCTURE ???
	MOVEI	S2,ACKU.D		;YES,,GET TEXT ADDRESS
	CAXN	TF,%TAPE		;IS IT A TAPE REQUEST ???
	PUSHJ	P,[MOVEI S2,ACKMTN	;YES,,DEFAULT TO NO LOGICAL NAME
		   SKIPE .VSLNM(P4)	;UNLESS HE SPECIFIED ONE
		   MOVEI S2,ACKMTL	;  THEN GET TEXT WITH LOGICAL NAME
		   POPJ  P,  ]		;RETURN
	CAXN	TF,%DTAP		;IS IT A DECTAPE REQUEST?
	PUSHJ	P,[MOVEI S2,ACKDTN	;YES--DEFAULT TO NO LOGICAL NAME
		   SKIPE .VSLNM(P4)	;UNLESS HE SPECIFIED ONE
		   MOVEI S2,ACKDTL	;THEN GET TEXT WITH LOGICAL NAME
		   POPJ  P,]		;RETURN
;**;[1144]ADD 6,CHANGE 1 LINES AT ACKU.4:+9L	2-AUG-83/CTK
	PUSH	P,T2			;[1144]SAVE T2 FOR A BIT
	MOVEI	T2,ACKU.N		;[1144]GET NUL MESSAGE
	LOAD	TF,.VLFLG(P1),VL.LCK	;[1144]GET LOCK BIT
	CAXN	TF,%LOCKP		;[1144]ARE WE LOCKED ???
	MOVEI	T2,ACKU.K		;[1144]YES,,GET TEXT ADDRESS
	$TEXT	(MDADBP,<^T/(S1)/^I/(S2)/^I/(T2)/>) ;[1144]CREATE THE MESSAGE
	POP	P,T2			;[1144]RESTORE T2
	SKIPN	S1,.VSTXT(P4)		;ANY ADDITIONAL TEXT ???
	JRST	ACKU.3			;NO,,GET NEXT VSL
	LOAD	S2,S1,VS.ADR		;GET THE TEXT ADDRESS IN S2
	LOAD	S1,S1,VS.LEN		;GET THE TEXT LENGTH IN S1
	PUSHJ	P,M%RMEM		;RETURN IT TO THE FREE POOL
	SETZM	.VSTXT(P4)		;ZAP THE TEXT POINTER
	JRST	ACKU.3			;GET NEXT VSL

ACKU.6:	SETZM	S1			;GET A NULL BYTE
	IDPB	S1,MDBPTR		;MAKE THE ACK ASCIZ
	MOVE	S1,T3			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,USRNOT		;SEND THE MESSAGE OFF
	ZERO	.VSRFL(P4),MR.WAT	;[1173] CLEAR THE WAITING FOR ACK BIT
	$RETT				;AND RETURN

ACKU.D:	ITEXT	(<[Structure ^W/.VLNAM(P1)/ mounted]>) 
ACKMTN:	ITEXT	(<[Magtape ^W/.VLNAM(P1)/ mounted on ^W/.UCBNM(P2)/]>)
ACKMTL:	ITEXT	(<[Magtape ^W/.VLNAM(P1)/ mounted on ^W/.UCBNM(P2)/ with logical name ^W/.VSLNM(P4)/]>)
ACKDTN:	ITEXT	(<[DECtape ^W/.VLNAM(P1)/ mounted on ^W/.UCBNM(P2)/]>)
ACKDTL:	ITEXT	(<[DECtape ^W/.VLNAM(P1)/ mounted on ^W/.UCBNM(P2)/ with logical name ^W/.VSLNM(P4)/]>)
TOPS10 <
ACKU.K:	ITEXT	(<^M^J[Structure ^W/.VLNAM(P1)/ will be locked at ^C/.VLLTM(P1)/]>);[1144]
ACKU.N:	ITEXT	(<>);[1144]
ACKU.X:	ITEXT (<[^T/@DEVNTB(T1)/ ^W/.VLNAM(P1)/ mounted on ^W/MDAOBJ+OBJ.UN/]>)
ACKU.Y:	ITEXT (<[^T/@DEVNTB(T1)/ ^W/.VLNAM(P1)/ mounted on ^W/MDAOBJ+OBJ.UN/ with logical name ^W/.VSLNM(P4)/]>)
>
	SUBTTL	TELOPR - ROUTINE TO NOTIFY THE OPERATOR TO MOUNT DEVICES

	;CALL:	S1/ The VSL Address of Any VSL to be Mounted
	;	AP/ The MDR Address
	;
	;RET:	True Always

TOPS10<
TELOPR:	PUSHJ	P,.SAVE4		;SAVE P1 - P4
	PUSHJ	P,.SAVET		;SAVE THE 'T' ACs ALSO
	SETOM	STRFLG			;AND SET IT
	LOAD	P1,.VSLNK(S1),VS.LNK	;GET THE VSL LINK CODE
	LOAD	P2,.MRCNT(AP),MR.CNT	;GET THE USERS VOL SET REQUEST COUNT
	MOVNS	P2			;NEGATE IT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.MRVSL(AP)		;CREATE VSL AOBJN SEARCH AC

TELO.1:	MOVE	T1,0(P2)		;GET A VSL ADDRESS
	LOAD	S2,.VSLNK(T1),VS.LNK	;GET ITS LINK CODE
	CAME	S2,P1			;DO THEY MATCH ???
	JRST	TELO.3			;NO,,GET NEXT
	MOVE	S2,.VSFLG(T1)		;GET THE VSL FLAG BITS
	TXNN	S2,VS.INI		;[1164] CHECK FOR /NEW-VOLUME INITIALIZATION
	TXNN	S2,VS.OPR+VS.VSW	;SWITCHING VOLS OR NOTIFY OPR ???
	JRST	TELO.3			;NO,,SKIP THIS
	LOAD	P3,.VSCVL(T1),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	P3,.VSVOL(T1)		;POINT TO THE CURRENT VOLUME ADDRESS
	MOVE	P3,0(P3)		;POINT P3 AT THE CURRENT VOLUME
	LOAD	S2,.VLFLG(P3),VL.STA	;GET THE VOLUME STATUS
	CAXN	S2,%STAMN		;IS IT MOUNTED ???
	JRST	TELO.3			;YES,,DON'T TELL OPR TO REMOUNT IT
	PUSHJ	P,CHKBAT		;CHECK TO SEE IF BATCH REQUEST
	JUMPF	TELO.3			;YES,,DON'T TELL OPR
	PUSHJ	P,MDASBP		;SET UP FOR CALLS TO MDADBP
	MOVEI	S2,DEMOB		;ASSUME A PSEUDO-PROCESS
	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE PROCESS JOB NUMBER
	TXC	S1,BA%JOB		;SWAP REQUEST STATES
	TXNE	S1,BA%JOB		;IS THIS A REAL REQUEST ???
	MOVEI	S2,DEMOT		;NO--NORMAL TIMESHARING
	$TEXT	(MDADBP,<^T/BELLS/^I/(S2)/>) ;DEMOGRAPHIC STUFF
	LOAD	S2,.VSFLG(T1),VS.TYP	;GET THE REQUEST TYPE
	CAIN	S2,%UNKN		;UNKNOWN?
	JRST	TELO.2			;YES
	$TEXT	(MDADBP,<Volume-set name: ^T/.VSVSN(T1)/>)
	MOVEI	S1,.VSVSN(T1)		;POINT TO VOLUME-SET NAME
	PUSHJ	P,V$FIND##		;SEE IF CATALOGED
	JUMPF	TELO.2			;JUMP IF NOT
	MOVEI	S1,.CQVLO(S1)		;POINT TO MEDIA STORAGE LOCATION
	SKIPN	(S1)			;HAVE SOMETHING THERE?
	JRST	TELO.2			;NO
	HRLI	S1,(POINT 8,)		;8-BIT ASCII
	$TEXT	(MDADBP,<Media storage location: ^Q/S1/>)

TELO.2:	SKIPE	.VSREM(T1)		;HAVE A REMARK?
	$TEXT	(MDADBP,<Remark: ^T/.VSREM(T1)/>) ;YES,,GEN IT
	ZERO	.VSFLG(T1),VS.OPR	;CLEAR OPR BIT,,WE'RE TELLING OPR NOW 
	MOVE	S2,G$NOW##		;GET THE CURRENT TIME
	MOVEM	S2,.VSSCH(T1)		;SAVE AS THE SCHEDULED TIME
	LOAD	S2,.VSFLG(T1),VS.TYP	;GET THE REQUEST TYPE
	SETZM	MDAOBJ+OBJ.UN		;[1455] GET RID OF STALE DEVICE NAME
	PUSHJ	P,@TELTAB(S2)		;DISPATCH TO PROPER 'TELL' PROCESSOR
	$RETIF				;RETURN IF FALSE

TELO.3:	AOBJN	P2,TELO.1		;CONTINUE FOR ALL VSL'S
	$RETT				;RETURN


TELTAB:	TELUNK				;%UNKN - UNKNOWN DEVICE
	TELMTA				;%TAPE - MAGTAPE
	TELDSK				;%DISK - STRUCTURE
	TELDTA				;%DTAP - DECTAPE
; Tell OPR about magtape request (%TAPE)
;
TELMTA:	MOVEI	S2,NEWTXT		;ASSUME /SCRATCH
	MOVX	T3,VL.SCR		;GET 'SCRATCH' STATUS BIT
	TDNN	T3,.VLFLG(P3)		;IS THIS A SCRATCH OR NEW VOLUME SET?
	$TEXT	(MDADBP,<^T/MTAHDR/^W11/.VLNAM(P3)/^A>) ;NO
	TDNE	T3,.VLFLG(P3)		;CHECK AGAIN
	$TEXT	(MDADBP,<^T/MTAHDR/Scratch    ^A>)
	LOAD	P4,.VSFLG(T1),VS.WLK	;GET THE WRITE-LOCKED CODE
	$TEXT	(MDADBP,<^T9/@WRTENA(P4)/^A>)
	TDNE	T3,.VLFLG(P3)		;/SCRATCH?
	JRST	TMTA.1			;YES
	MOVEI	S2,NONEWT		;[1164] ASSUME NOT NEW
	MOVX	T3,VS.NEW		;[1164] GET /NEW-VOLUME BIT
	TDNN	T3,.VSFLG(T1)		;[1164] IS IT LIT?
	  JRST	TMTA.1			;[1164] NO,,CONTINUE
	LOAD	S2,.VSCVL(T1),VS.CNT	;[1164] GET COUNT OF VOLS IN VSN
	CAIN	S2,1			;[1164] ONE VOLUME?
	SKIPA	S2,[REITX1]		;[1164] YES
	MOVEI	S2,REITX2		;[1164] ELSE USE MULTI-VOL TEXT
	JRST	TMTA.2			;[1164] SKIP LABEL TYPE CHECK
TMTA.1:	LOAD	S1,.VLFLG(P3),VL.LBT	;[1134]GET THE VOLUME LABEL
	PUSHJ	P,GETLBT		;[1134]GO SEE IF USER SPECIFIED LABELS
	CAXN	S1,%UNLBL		;DID HE?
	MOVEI	S2,NONEWT		;DON'T PROMPT FOR INITIALIZATION AT ALL
TMTA.2:	LOAD	P4,.VSFLG(T1),VS.WLK	;[1164] GET THE WRITE-LOCKED CODE
	LOAD	T2,.VSFLG(T1),VS.LBT	;GET THE REQUESTED LABEL TYPE
	LOAD	T3,.VSATR(T1),VS.TRK	;GET THE TRACK STATUS
	LOAD	T4,.VSATR(T1),VS.DEN	;GET THE REQUESTED DENSITY
	$TEXT(MDADBP,<^T9/@LABELS(T2)/^W6/TRK(T3)/^T/@DENSTY(T4)/^I/(S2)/^0>)
	$WTO	(<Magtape mount request #^D/.VSRID(T1)/>,<^T/G$MSG/>,MDAOBJ,<$WTFLG(WT.SJI)>) ;[1455]
	$RETT				;RETURN

NEWTXT:	ITEXT	(<^M^JInitialize new/scratch tape: - Volume-id: ^W/.VLNAM(P3)/ - Protection: ^O3/.VSATR(T1),VS.PRT/>)
NONEWT:	ITEXT	(<>)			;IF /NEW OR /SCRATCH NOT SEEN

MTAHDR:	ASCIZ/
Volume-ID   Write   Labels  Track  Density
---------  -------  ------  -----  -------
/

REITX1:	ITEXT	(<^M^JUser requesting reinitialization of 1 volume^T/BELLS/>) ;[1164]
REITX2:	ITEXT	(<^M^JUser requesting reinitialization of ^D/.VSCVL(T1),VS.CNT/ volumes^T/BELLS/>) ;[1164]
; Tell OPR about structure request (%DISK)
;
TELDSK:	$TEXT	(MDADBP,<^T/DSKHDR/^A>)	;PUT OUT HEADER
	MOVE	S1,.VLNAM(P3)		;GET THE STRUCTURE NAME
	MOVEM	S1,MDAOBJ+OBJ.UN	;SAVE IT IN THE MDA OBJECT BLOCK
	PUSHJ	P,V$STRG##		;CONVERT TO ASCIZ
	PUSHJ	P,V$FIND##		;FIND ITS CATALOG ENTRY
	SKIPT				;IT MUST BE THERE !!!
	PUSHJ	P,S..SCE		;NO,,DEEEP TROUBLE !!!
	MOVE	T2,.CQNVL(S1)		;GET # OF VOLUMES WORD
	MOVEI	P3,.CQVSL(S1)		;POINT TO THE FIRST BLOCK !!!
	SETZM	T1			;CLEAR LOGICAL UNIT NUMBER COUNTER
	AOSG	STRFLG			;MODIFY AND CHECK STR MOUNT FLAG
	PUSHJ	P,SETSEL		;FIRST TIME THROUGH,,SET UNIT SELECTED
	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%FIRST		;POSITION TO THE FIRST ENTRY

TELD.1:	MOVE	P4,.CQRSN(P3)		;GET THE RESOURCE NUMBER

TELD.2:	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT UCB ADDRESS
	JUMPF	.RETF			;NO MORE AVAILABLE,,JUST RETURN
	LOAD	S1,.UCBST(S2),UC.DVT	;GET THE DEVICE TYPE
	CAXE	S1,%DISK		;IS IT A STRUCTURE ???
	JRST	TELD.2			;NO,,TRY NEXT UCB
	LOAD	S1,.UCBST(S2),UC.RSN	;GET THE DEVICE RESOURCE NUMBER
	CAME	S1,P4			;DO THEY MATCH ???
	JRST	TELD.2			;NO,,TRY NEXT
	LOAD	S1,.UCBST(S2),UC.SEL	;GET THE UNIT SELECTED BIT
	JUMPN	S1,TELD.2		;IF LIT,,SKIP THIS UNIT !!!
	MOVX	S1,UC.SEL		;ELSE GET THE UNIT SELECTED BIT
	IORM	S1,.UCBST(S2)		;  AND SET IT
	IMULI	P4,AMALEN		;GET 'A' MATRIX OFFSET
	ADD	P4,AMATRX		;GET THE 'A' MATRIX ENTRY ADDRESS
	$TEXT(<-1,,TMPVSL>,<^W/MDAOBJ+OBJ.UN/^O/T1/^0>) ;GEN LOGICAL UNIT NAME
	$TEXT(MDADBP,<^T8/TMPVSL/^W8/.CQVID(P3)/^T6/@.AMNAM(P4)/^W/.UCBNM(S2)/>) 
	ADDI	P3,.CQVLL		;BUMP TO THE NEXT CATALOG ENTRY
	AOS	T1			;BUMP THE LOGICAL UNIT NUMBER
	SOJG	T2,TELD.1		;CONTINUE FOR ALL VOLUME BLOCKS
	SETZM	S1			;GET A NULL BYTE
	IDPB	S1,MDBPTR		;MAKE THE TEXT ASCIZ
	MOVE	T1,0(P2)		;PICK UP THE VSL ADDRESS AGAIN
	$WTO	(<Structure mount request #^D/.VSRID(T1)/>,<^T/G$MSG/>,MDAOBJ,<$WTFLG(WT.SJI)>) ;[1455]
	$RETT				;RETURN


DSKHDR:	ASCIZ/
 Unit   Volume  Type  Drive
------  ------  ----  -----
/
; Tell OPR about DECtape request (%DTAP)
;
TELDTA:	MOVX	T3,VS.SCR+VS.NEW	;GET 'SCRATCH+NEW' STATUS BITS
	TDNN	T3,.VSFLG(T1)		;IS THIS A SCRATCH OR NEW VOLUME SET?
	$TEXT	(MDADBP,<^T/DTAHDR/^W11/.VLNAM(P3)/^A>) ;NO
	TDNE	T3,.VSFLG(T1)		;CHECK AGAIN
	$TEXT	(MDADBP,<^T/DTAHDR/Scratch    ^A>)
	LOAD	P4,.VSFLG(T1),VS.WLK	;GET THE WRITE-LOCKED CODE
	$TEXT	(MDADBP,<^T9/@WRTENA(P4)/^0>)
	$WTO	(<DECtape mount request #^D/.VSRID(T1)/>,<^T/G$MSG/>,MDAOBJ,<$WTFLG(WT.SJI)>) ;[1455]
	$RETT				;RETURN


DTAHDR:	ASCIZ/
Volume-ID   Write
---------  -------
/
TELUNK:	MOVE	S1,T1			;GET THE VSL ADDRESS
	PUSHJ	P,I$CGEN##		;GET THE DEVICE TYPE AND INDEX
	MOVE	P4,S1			;SAVE THE DEVICE INDEX
	HRROI	S1,.VSVSN(T1)		;POINT TO THE VOLUME SET NAME
	PUSHJ	P,S%SIXB		;CONVERT TO SIXBIT
	MOVEM	S2,MDAOBJ+OBJ.UN	;SAVE IT IN THE OBJECT BLOCK
	$TEXT	(MDADBP,<Device: ^W/S2/^0>)
	$WTO	(<^T/@DEVNTB(P4)/ mount request #^D/.VSRID(T1)/>,<^T/G$MSG/>,MDAOBJ,<$WTFLG(WT.SJI)>) ;[1455]
	$RETT				;RETURN

> ;END TOPS10 CONDITIONAL
	SUBTTL	MNTOPR - ROUTINE TO NOTIFY THE OPR OF PENDING MOUNT REQUESTS

	;CALL:	No Args
	;
	;RET:	Nothing - Notifies the operator if mounts are pending

MNTOPR:	SKIPN	G$OPRA##		;OPERATOR ON DUTY?
	JRST	MNTO.9			;NOPE - JUST RESCHEDULE THE EVENT
	PUSHJ	P,.SAVE4		;SAVE P1 - P4
	STKVAR	<KOUNT>			;GET SPACE FOR A COUNT
	SETZM	KOUNT			;CLEAR MOUNT COUNTER
	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST VOL IN THE QUEUE
	JRST	MNTO.2			;JUMP THE FIRST TIME THROUGH
MNTO.1:	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT VOLUME IN THE QUEUE
MNTO.2:	JUMPF	MNTO.7			;NO MORE,,GO FINISH UP...
	MOVE	P2,S2			;SAVE THE VOL ENTRY ADDRESS
	LOAD	P4,.VLOWN(P2),VL.CNT	;GET THE VOLUME REQUEST COUNT..
	JUMPE	P4,MNTO.1		;NO REQUESTORS,,SKIP IT..
	MOVNS	P4			;NEGATE THE REQUEST COUNT
	MOVSS	P4			;MOVE RIGHT TO LEFT
	HRRI	P4,.VLVSL(P2)		;CREATE VSL AOBJN AC
	MOVE	P3,.VLUCB(P2)		;GET THE UCB ADDRESS

MNTO.3:	MOVE	P1,0(P4)		;GET A VSL ADDRESS
	MOVE	AP,.VSMDR(P1)		;GET THE MDR ADDRESS
	MOVE	S1,.VSFLG(P1)		;GET THE VSL FLAG BITS
	TXNN	P1,VL.ASN		;DOES HE OWN THE VOLUME ???
	TXNE	S1,VS.ALC+VS.ABO	;JUST ALLOCATED OR ABORTED ???
	JRST	MNTO.6			;YES,,TRY NEXT VSL
	SKIPN	S1,.MRQEA(AP)		;CHECK AND LOAD QE ADDRESS
	JRST	MNTO.4			;NO QE, NO BATCH JOB TO CHECK
	PUSHJ	P,S$INPS##		;FOUND,,CHECK SCHEDULABILITY
	JUMPF	MNTO.6			;NO GO,,SKIP IT
	MOVE	S1,.MRQEA(AP)		;GET THE QE AGAIN
	MOVX	S2,QE.HBO		;GET 'HELD BY OPERATOR BIT'
	TDNE	S2,.QESEQ(S1)		;IS IT?
	JRST	MNTO.6			;HELD JOBS CAN'T MOUNT THINGS

MNTO.4:	LOAD	S1,.VSCVL(P1),VS.OFF	;GET THE OFFSET TO HIS CUR VOL
	ADDI	S1,.VSVOL(P1)		;POINT TO HIS CURRENT VOL ADDR
	CAME	P2,0(S1)		;IS THIS THE VOL HE NEEDS ???
	JRST	MNTO.6			;NO,,SKIP THIS
	LOAD	S1,.VSFLG(P1),VS.TYP	;GET THE VOLUME SET TYPE
	CAXE	S1,%DISK		;IS THIS A STRUCTURE REQUEST ???
	JRST	MNTO.5			;NO,,ADD UP THE TAPE REQUEST
	LOAD	S1,.VLFLG(P2),VL.STA	;GET THE VOLUME STATUS
	CAXN	S1,%STAMN		;IS THE STRUCTURE MOUNTED ???
	JRST	MNTO.6			;YES,,SKIP THIS REQUEST

MNTO.5:	AOS	KOUNT			;BUMP THE MOUNT COUNTER

MNTO.6:	AOBJN	P4,MNTO.3		;CONTINUE THROUGH ALL USERS
	JRST	MNTO.1			;CONTINUE THROUGH ALL VOLUMES

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

MNTO.7:	SKIPN	P1,KOUNT		;ANY MOUNTS PENDING ???
	JRST	MNTO.9			;NO,,JUST ADD THE EVENT BACK
	MOVE	S1,[ASCII/is/]		;DEFAULT TO 1 MOUNT
	SETZM	S2			;GET A NULL
	CAIG	P1,1			;MORE THEN 1 MOUNT ???
	JRST	MNTO.8			;NO,,LETERRIP !!!
	MOVE	S1,[ASCII/are/]		;YES,,SET IT UP
	MOVE	S2,[ASCII/s/]		;TAKES A LOT TO BE NICE !!!
MNTO.8:	SETZM	MDAOBJ+OBJ.UN		;[1455] GET RID OF STALE DEVICE
	$WTO	(<There ^T/S1/ ^D/KOUNT/ mount request^T/S2/ pending^T/BELLS/>,,MDAOBJ,<$WTFLG(WT.SJI)>) ;[1455]
MNTO.9:	SETZM	G$MSG+.EVTYP		;CLEAR THE EVENT TYPE WORD
	MOVX	S1,%EVAFT		;WANT TYPE 'AFTER'
	STORE	S1,G$MSG+.EVTYP,EV.TYP	;SET IT
	MOVEI	S1,3			;GET 3 MINUTES
	PUSHJ	P,A$AFT##		;COMPUTE IT
	MOVEM	S1,G$MSG+.EVUDT		;SET IT
	MOVEI	S1,MNTOPR		;GET THIS ROUTINE ADDRESS
	MOVEM	S1,G$MSG+.EVRTN		;SET IT
	MOVX	S1,.EVMSZ		;GET THE EVENT BLOCK LENGTH
	MOVEI	S2,G$MSG		;AND ITS ADDRESS
	PUSHJ	P,S$EVENT##		;ADD TO THE EVENT LIST
	$RETT				;AND RETURN
	SUBTTL	SETSEL - ROUTINE TO FIND THOSE UCB'S WHICH ARE FREE

	;CALL:	No Args
	;
	;RET:	True Always

TOPS10<
SETSEL:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	MOVX	P1,UC.SEL		;GET THE UNIT SELECTED BIT
	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%FIRST		;POSITION TO THE FIRST ENTRY
	JRST	SETS.2			;JUMP THE FIRST TIME THROUGH

SETS.1:	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT ENTRY
SETS.2:	JUMPF	.RETT			;DONE,,RETURN
	MOVE	P2,S2			;SAVE THE UCB ADDRESS
	ANDCAM	P1,.UCBST(P2)		;CLEAR THE UNIT SELECTED STATUS BIT
	LOAD	S1,.UCBST(P2),UC.DVT	;GET THE UNIT TYPE
	CAXN	S1,%DISK		;IS IT A DISK UNIT ???
	SKIPN	S1,.UCBVL(P2)		;YES,,ANY VOLUME MOUNTED ???
	JRST	SETS.1			;NOT A DISK OR NO VOL MOUNTED,,GET NEXT

SETS.3:	LOAD	S2,.VLPTR(S1),VL.PRV	;FIND THE PRIMARY VOL BLOCK
	JUMPE	S2,SETS.4		;FOUND IT,,SEE IF ANYONE OWNS IT
	MOVE	S1,S2			;ELSE SAVE THIS VOL BLOCK ADDRESS
	JRST	SETS.3			;AND KEEP LOOKING

SETS.4:	PUSHJ	P,FNDOWN		;ANY OWNERS OF THE MOUNTED VOLUME ???
	JUMPF	SETS.1			;NO,,GET NEXT UCB
	IORM	P1,.UCBST(P2)		;YES,,LITE UNIT SELECTED
	JRST	SETS.1			;AND GO GET THE NEXT UCB
> ;END TOPS10 CONDITIONAL

	SUBTTL	USRNOT - SEND A MESSAGE TO THE USER

	;CALL:	AP/ The Users MDR Address
	;	S1/ VSL address (for ACK data)
	;	S2/ nonzero - Use MDR ACK data if valid
	;	    zero - Use VSL ACK data
	;	G$MSG/ The Message to be sent
	;
	;RET:	True Always

D$USRN::				;MAKE IT GLOBAL
USRNOT:	PUSHJ	P,.SAVE4		;[1173] SAVE P1-P4
	TRVAR	<PID,ACKCOD,FLAGS>	;[1173] DEFINE SOME LOCAL STORAGE
	DMOVE	P2,S1			;[1173] ASSUME WE'LL USE VSL ACK DATA
					;[1173] SAVE S2 TOO
	MOVE	S1,.VSPID(P2)		;[1173] GET PID FROM VSL
	MOVEM	S1,PID			;[1173] STORE IT
	MOVE	S1,.VSACK(P2)		;[1173] GET ACK CODE FROM VSL
	MOVEM	S1,ACKCOD		;[1173] STASH IT
	MOVE	S1,.VSRFL(P2)		;[1173] GET ACKING FLAGS
	MOVEM	S1,FLAGS		;[1173] SAVE THEM
	MOVEI	P4,RSTVSL		;[1173] GET ROUTINE ADDRESS FOR EXIT
	JUMPE	P3,USRN.1		;[1173] JUMP IF ASSUMPTION CORRECT
	MOVE	P1,.MRFLG(AP)		;[1173] GET MDR FLAGS
	CAMN	P1,[-1]			;[1173] MDR ACK DATA VALID?
	JRST	[SETZM P3		;[1173] NO,,REMEMBER FOR LATER
		 JRST USRN.1]		;[1173] WE'RE ALREADY SETUP
	MOVE	S1,.MRPID(AP)		;[1173] GET PID FROM MDR
	MOVEM	S1,PID			;[1173] STORE IT LOCALLY
	MOVE	S1,.MRACK(AP)		;[1173] GET ACK CODE FROM MDR
	MOVEM	S1,ACKCOD		;[1173] STORE IT
	MOVE	S1,.MRFLG(AP)		;[1173] GET FLAGS
	MOVEM	S1,FLAGS		;[1173] STORE THEM
	MOVEI	P4,RSTMDR		;[1173] GET EXIT ROUTINE ADDRESS
;**;[1170] Delete 3 lines at USRNOT+1L. 29-Dec-83 /LWS
USRN.1:	LOAD	S2,.MRJOB(AP),MR.JOB	;[1173] GET THE USERS JOB NUMBER
	TXNN	S2,BA%JOB		;IS IT AN INTERNAL REQUEST ???
	TXNN	S1,MR.WAT!MR.NOT!MR.ACK	;OR WANT SOME STYLE NOTIFICATION ???
	JRST	[SETZM ERRACK		;PSEUDO REQ OR NO ACK,,ZAP ERROR
		 $RETT ]		;AND RETURN

	TXNN	S1,MR.WAT!MR.ACK	;WAITING FOR AN ACK ???
	JRST	USRN.N			;NO,,MUST BE NOTIFY
	TXZN	S1,MR.ACK		;ACK REQUESTED ???
	TXZ	S1,MR.WAT		;NO,,CLEAR WAITING
	MOVEM	S1,FLAGS		;[1173] SAVE THE NEW STATUS
	$CALL	M%GPAG			;GET A PAGE TO BUILD THE ACK IN
	MOVE	P1,S1			;SAVE THE ADRS OF THE TEXT PAGE
	MOVEM	P1,G$SAB##+SAB.MS	;AIM THE GLOBAL SAB AT THE PAGE
	MOVE	S1,PID			;[1173] GET USER'S PID
	MOVEM	S1,G$SAB##+SAB.PD	;SEND ACK TO USER

	MOVX	S1,.OMTXT		;MESSAGE TYPE
	STORE	S1,.MSTYP(P1),MS.TYP	;SAVE IN HEADER
	MOVX	S1,MF.FAT		;GET FATAL ACK BIT
	SKIPE	ERRACK			;IS THIS AN 'ERROR' ACK ???
	MOVEM	S1,.MSFLG(P1)		;YES,,SET THE BIT
	MOVX	S1,.OHDRS+ARG.DA+MSGLN## ;LENGTH OF THE MESSAGE
	STORE	S1,.MSTYP(P1),MS.CNT	;SAVE IN MESSAGE HEADER
	MOVX	S1,PAGSIZ		;GET THE PAGE SIZE
	STORE	S1,G$SAB##+SAB.LN	;SAVE IN SEND BLOCK
	MOVE	S1,ACKCOD		;[1173] GET THE MESSAGE ACK CODE
	MOVEM	S1,.MSCOD(P1)		;SAVE IT IN THE MESSAGE
	MOVX	S1,1			;ONE ARG BLOCK
	STORE	S1,.OARGC(P1)		;SAVE IN HEADER
	MOVX	S1,.CMTXT		;BLOCK TYPE-- TEXT
	STORE	S1,.OHDRS+ARG.HD(P1),AR.TYP ;SET BLOCK TYPE
	MOVX	S1,ARG.DA+MSGLN##	;SIZE OF THIS BLOCK
	STORE	S1,.OHDRS+ARG.HD(P1),AR.LEN ;LENGTH INTO BLOCK HEADER
	MOVSI	S1,G$MSG		;GET THE SOURCE ADDRESS
	HRRI	S1,.OHDRS+ARG.DA(P1)	;GET DESTINATION ADDRESS
	BLT	S1,.OHDRS+ARG.DA+MSGLN##-1(P1) ;COPY THE TEXT OVER
	PUSHJ	P,C$SEND##		;ACK THE USER
	MOVE	S1,P2			;[1173] GET VSL ADDRESS
	PUSHJ	P,(P4)			;[1173] RESTORE ACK DATA
	JUMPF	USRN.N			;[1173] TRY TERMINAL IF FAILURE
	SETZM	ERRACK			;[1173] CLEAR ERROR FLAG
	$RETT				;[1173] RETURN

	;HERE TO NOTIFY USER VIA ORION TYPING ON HIS TERMINAL

TOPS10 <
USRN.N:	MOVE	P1,FLAGS		;[1173] GET ACK DATA FLAGS
	TXNE	P1,MR.NOT		;[1173] WANT TO BE NOTIFIED
	JRST	USRN.X			;[1173] YES,,GO TRY IT
	SETZM ERRACK			;[1173] NO,,CLEAR THE ERROR FLAG
	$RETT				;[1173] RETURN

;[1173] USRN.W will always use VSL ack data when called directly.
;[1173] S1/ VSL address

USRN.W:	PUSHJ	P,.SAVE2		;[1173] SAVE P1,P2
	MOVE	P2,S1			;[1173] SAVE VSL ADDRESS
	MOVE	P1,.VSRFL(P2)		;[1173] GET ACK DATA FLAGS FROM VSL
USRN.X:	STKVAR	<FLAGSX>		;[1173] LOCAL STORAGE
	MOVEM	P1,FLAGSX		;[1173] SAVE FLAGS
	MOVX	S1,BA%JOB		;GET THE BATCH JOB BIT
	TDNE	S1,.MRJOB(AP)		;IS THIS REQUEST A BATCH REQUEST?
	JRST	USRN.6			;YES, SKIP THE NOTIFICATION
	$CALL	M%GPAG			;GET A PAGE TO BUILD THE ACK IN
	MOVE	P1,S1			;SAVE THE ADRS OF THE TEXT PAGE
	MOVEM	P1,G$SAB##+SAB.MS	;AIM THE GLOBAL SAB AT THE PAGE
	MOVX	S2,SI.FLG+SP.OPR	;SEND VIA INDEX TO OPR
	STORE	S2,G$SAB##+SAB.SI	;SAVE IN SAB
	SETZM	G$SAB##+SAB.PD		;BE TIDY.. NO PID
	MOVX	S1,.OHDRS+JBI.SZ+ARG.DA+MSGLN## ;SIZE OF THE MESSAGE
	STORE	S1,.MSTYP(P1),MS.CNT	;SAVE IN MESSAGE ITSELF
	MOVX	S1,PAGSIZ		;GET THE PAGE LENGTH
	STORE	S1,G$SAB##+SAB.LN	;SAVE IT IN THE SAB
	MOVX	S1,.OMNFY		;MESSAGE TYPE -- NOTIFY
	STORE	S1,.MSTYP(P1),MS.TYP	;SAVE IN HEADER
	MOVX	S1,2			;TWO BLOCKS
	STORE	S1,.OARGC(P1)		;SAVE IN HEADER
	MOVE	S1,[XWD JBI.SZ,.JOBID]	;LEN,,SIZE OF JOB INFO BLOCK
	MOVEM	S1,.OHDRS+ARG.HD(P1)	; SAVE IN FIRST BLOCK
	MOVE	S1,.MRLOG(AP)		;GET JOB'S UNIV. LOGIN TIME
	MOVEM	S1,.OHDRS+JBI.LI(P1)	;SAVE AS DATA FOR THIS BLOCK
	LOAD	S1,.MRJOB(AP),MD.PJB	;GET JOB NUMBER
	STORE	S1,.OHDRS+JBI.JB(P1)	;SAVE AS MORE DATA IN JOB INFO BLOCK
	MOVEI	P1,.OHDRS+JBI.SZ(P1)	;POINT TO THE LAST BLOCK
	MOVX	S1,.CMTXT		;BLOCK TYPE-- TEXT
	STORE	S1,ARG.HD(P1),AR.TYP	;SET BLOCK TYPE
	MOVX	S1,ARG.DA+MSGLN##	;SIZE OF THIS BLOCK
	STORE	S1,ARG.HD(P1),AR.LEN	;LENGTH INTO BLOCK HEADER
	MOVE	S1,[BYTE(7) 15,12,0,0,0] ;GET A CRLF
	SKIPE	ERRACK			;UNLESS THIS IS AN ERROR ACK !!
	MOVE	S1,[BYTE(7) 15,12,77,0,0] ;  THEN GET A <CRLF>?
	MOVX	S2,MR.DMO		;GET DISMOUNT STR BIT
	TDNE	S2,FLAGSX		;[1173] IS THAT WHAT WE'RE DOING?
	SKIPA	S2,[ASCIZ | |]		;YES
	MOVE	S2,[BYTE (7) 15,12,0]	;ELSE USE A CRLF
	$TEXT	(<-1,,ARG.DA(P1)>,<^T/S1/From system:^T/S2/^T/G$MSG/^T/BELLS/>)
	PUSHJ	P,C$SEND##		;ACK THE USER
USRN.6:	SETZM ERRACK			;CLEAR THE ERROR FLAG
	$RETT				;AND RETURN
>
TOPS20 <
USRN.N:	$RETT	>			;JUST RETURN ON THE -20

;[1173] Routines to restore ACK data flag word in MDR and VSL.
;[1173] USRNOT may modify some of the bits.
;[1173] ** Can only be called from USRNOT **

;[1173] Call:	AP/ MDR address

RSTMDR:	MOVE	S1,FLAGS		;[1173] GET FLAGS
	MOVEM	S1,.MRFLG(AP)		;[1173] RESTORE THEM IN MDR
	$RET				;[1173] RETURN TF INTACT

;[1173] Call:	S1/ VSL address

RSTVSL:	
	MOVE	S2,FLAGS		;[1173] GET FLAGS
	MOVEM	S2,.VSRFL(S1)		;[1173] RESTORE IN VSL
	$RET				;[1173] RETURN TF INTACT

	SUBTTL	NSTUSR - Notify users of pending structure locks

;this routine will notify all the users of a given structure that a
; LOCk has been given by the operator for a structure they own,
; and will not be available for long
;Call -
;	S1/	Prime volume block address
;	S2/	Addrs of ITEXT for message (ITEXT should stay in P acs)
;Returns -
;	TRUE,	messages sent to all requestors

TOPS10<
NSTUSR:	$TEXT	(<-1,,G$MSG>,<^I/0(S2)/^M^J^0>) ;DUMP THE TEXT OF THE MESSAGE
	$SAVE	<P1,AP>			;SAVE P1 AND AP
	MOVE	P1,S1			;COPY ADRS OF PRIMARY VOL BLOCK
	LOAD	S1,.VLOWN(P1),VL.CNT	;FIND OUT HOW MANY REQUESTORS
	JUMPE	S1,.RETT		;NONE, NOTHING TO DO!
	MOVNS	S1			;GET NEGATIVE # OF REQUESTORS
	HRL	P1,S1			;MAKE LOOP POINTER
	SETZM	ERRACK			;DO THE NORMAL STUFF IN USRNOT
NSTU.1:	HRRZ	S1,.VLVSL(P1)		;GET THE NEXT VSL ENTRY
	SKIPN	S1			;BETTER BE ONE!!
	STOPCD	(VSA,HALT,,<VSL address is missing in a VOL>) ;NONE THERE,,END IT
	SKIPN	AP,.VSMDR(S1)		;GOT IT, GET BACK TO THE MDR
	STOPCD	(IMV,HALT,,<Invalid MDR/VSL forward/backchain pointers>)
	PUSHJ	P,USRN.W		;WRITE ON THE REQUESTORS TERMINAL
	AOBJN	P1,NSTU.1		;CHECK ALL REQUESTORS
	$RETT				;DONE
> ;END TOPS10 CONDITIONAL
	SUBTTL	LBLNOT - ROUTINE TO NOTIFY LABEL PROCESS OF DEVICE REASSIGNMENT

TOPS10<	;CALL:	S1/ The volume set list adrs, which points back to
	;	the MDR, and whose current offset points to the VOL just
	;	mounted, and which points to the UCB.

LBLNOT:	$SAVE	<P1,P2,P3>
	MOVE	P1,S1			;SAVE THE VSL ADDR
	MOVX	S1,.QOVMN		;MESSAGE TYPE - VOLUME MOUNTED
	PUSHJ	P,LBLHDR		;SET THE HEADER FOR MESSAGE, SAB, ETC
	MOVEI	P2,G$MSG+.OHDRS	;AIM AT FIRST BLOCK

;Build the First Block, Which Describes the Device Reassigned

	AOS	G$MSG+.OARGC		;ONE MORE BLOCK
	MOVX	S1,.RECDV		;FIRST BLOCK TYPE - RECOGNIZE DEVICE
	STORE	S1,ARG.HD(P2),AR.TYP	;SET THIS BLOCK TYPE
	MOVX	S1,.RECSZ+ARG.DA	;GET LENGTH OF THIS BLOCK
	STORE	S1,ARG.HD(P2),AR.LEN	;SAVE IN BLOCK
	ADDM	S1,G$SAB+SAB.LN		;UPDATE SEND LENGTH
	MOVSS	S1			;GET TO  LH
	ADDM	S1,G$MSG+.MSTYP	;UPDATE TOTAL MESSAGE LENGTH
	LOAD	S1,.VSCVL(P1),VS.OFF	;GET OFFSET TO CURRENT VOLUME
	ADDI	S1,.VSVOL(P1)		;POINT TO THIS VOLUME'S ENTRY
	MOVE	P3,0(S1)		;NOW GET THE VOLUME ADDRS
	MOVE	S2,.VLUCB(P3)		;AND GET TO UCB ADDR
	MOVE	S1,.UCBNM(S2)		;GET THE DEVICE NAME
	MOVEM	S1,.RECDN+ARG.DA(P2)	;SAVE IN MESSAGE
	MOVEI	P2,.RECSZ+ARG.DA(P2)	;ADVANCE TO NEXT BLOCK

;Build the Second Block, Which Describes the Volume Set and User to
;	Which the Drive was Given.

	AOS	G$MSG+.OARGC		;ONE MORE BLOCK
	MOVX	S1,.VOLMN		;GET THE NEXT BLOCK TYPE
	STORE	S1,ARG.HD(P2),AR.TYP	;SAVE AS BLOCK TYPE
	MOVX	S1,.VMNSZ+ARG.DA	;GET THE LENGTH OF THE BLOCK
	STORE	S1,ARG.HD(P2),AR.LEN	;AND SAVE IN BLOCK HEADER
	ADDM	S1,G$SAB+SAB.LN		;UPDATE SEND LENGTH
	MOVSS	S1			;GET TO  LH
	ADDM	S1,G$MSG+.MSTYP	;UPDATE TOTAL MESSAGE LENGTH
	MOVEI	P2,ARG.DA(P2)		;AIM AT THE DATA PORTION OF THE BLOCK
	LOAD	S1,.VLNAM(P3)		;GET THE VOLUME NAME
	STORE	S1,.VMNIV(P2)		;SAVE AS INITIAL VOLUME NAME
	MOVEI	S1,.VSVOL(P1)		;AIM AT THE FIRST VOLUME BLOCK ADR
	MOVE	S1,(S1)			;GET THE ADR OF THE FIRST VOL BLOCK
	LOAD	S1,.VLNAM(S1)		;GET THE NAME OF THE FIRST VOLUME
	STORE	S1,.VMNFV(P2)		;SAVE IN MESSAGE TO LABELLER
	SETZM	.VMNIN(P2)		;CLEAN OUT THE GARBAGE
	LOAD	S1,.VSFLG(P1),VS.LBT	;GET THE LABEL TYPE
	STORE	S1,.VMNIN(P2),VI.LTY	;SAVE IN MESSAGE

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	LOAD	S1,.VSFLG(P1),VS.WLK	;GET THE WRITE LOCK BIT
	STORE	S1,.VMNIN(P2),VI.WLK	;SAVE IN INFO WORD OF MESSAGE
	LOAD	S1,.MRJOB(AP),MD.PJB	;GET THE JOB NUMBER
	STORE	S1,.VMNIN(P2),VI.JOB	;TELL THE LABELLER WHO'S THERE
	PUSHJ	P,C$SEND##			;TELL THE LABELLER
	$RETT

>;END TOPS10
SUBTTL	LBLHDR - Set up for a message to MDA

;Thie routine will set up G$SAB for a message to MDA which
;	will be in G$MSG
;Call -
;	S1/ Message type

TOPS10<
LBLHDR:	STORE	S1,G$MSG+.MSTYP,MS.TYP	;SAVE THE MESSAGE TYPE
	MOVX	S1,.OHDRS		;SIZE OF HEADER ALONE
	STORE	S1,G$MSG+.MSTYP,MS.CNT	;LENGTH SO FAR
	MOVEM	S1,G$SAB##+SAB.LN	;LENGTH TO SEND
	SETZM	G$SAB##+SAB.PD		;NO PID...
	MOVX	S1,<SI.FLG+SP.TLP>	;.. SEND BY SPECIAL INDEX
	MOVEM	S1,G$SAB##+SAB.SI	;MARK IN SAB
	SETZM	G$SAB##+SAB.PB		;SEND ON MY BEHALF
	SETZM	G$MSG+.MSFLG		;NO MESSAGE FLAGS
	SETZM	G$MSG+.MSCOD		;NO ACK CODE
	SETZM	G$MSG+.OFLAG		;AND NO FLAGS (YET)
	SETZM	G$MSG+.OARGC		;NO ARG BLOCKS (YET)
	MOVEI	S1,G$MSG		;THE ADR OF THE MESSAGE
	MOVEM	S1,G$SAB##+SAB.MS	;AIM THE SAB AT US
	$RETT				;ALL SET UP
>;END TOPS10
	SUBTTL	SNDREC - ROUTINE TO SEND A RECOGNIZE MSG TO THE TAPE LABELER

	;CALL:	S1/ The Device Name in Sixbit
	;
	;RET:	True Always


TOPS10 <
RECMSG:	$BUILD	.OHDRS+ARG.DA+1
	 $SET(.MSTYP,MS.TYP,.QOREC)		;TYPE 'RECOGNIZE MESSAGE'
	 $SET(.MSTYP,MS.CNT,.OHDRS+ARG.DA+1)	;MESSAGE LENGTH
	 $SET(.OARGC,,1)			;A BLOCK COUNT OF 1
	 $SET(.OHDRS+ARG.HD,AR.LEN,2)		;THE BLOCK LENGTH
	 $SET(.OHDRS+ARG.HD,AR.TYP,.RECDV)  	;THE BLOCK TYPE
	$EOB


;**;[1175] Change some code at D$SREC. /LWS
D$SREC::				;MAKE IT GLOBAL
SNDREC:	JUMPN	S1,SNDR.0		;[1175] *** MUST BE NON-ZERO ***
	$WTO	(<Null device name detected>,<Recognize message not sent>,MDAOBJ) ;[1175]
	$RETT				;[1175] RETURN
SNDR.0:	MOVEM	S1,RECMSG+.OHDRS+ARG.DA	;[1175] SAVE THE DEVICE NAME IN THE MESSAGE
	MOVEI	S1,.OHDRS+ARG.DA+1	;GET THE MESSAGE LENGTH
	MOVEM	S1,G$SAB##+SAB.LN	;SAVE IT IN THE SAB
	MOVEI	S1,RECMSG		;GET THE MESSAGE ADDRESS
	MOVEM	S1,G$SAB##+SAB.MS	;SAVE IT IN THE SAB

SNDLBR:	MOVX	S1,SI.FLG+SP.TLP	;GET THE SPECIAL INDEX FOR TAPE LABELER
	MOVEM	S1,G$SAB##+SAB.SI	;SAVE IT IN THE SAB
	SETZM	G$SAB##+SAB.PD		;ZAP THE SAB PID WORD
	PUSHJ	P,C$SEND##		;SEND THE MESSAGE OFF
	$RETT				;AND RETURN


	SUBTTL	UNLOAD - TELL PULSAR TO UNLOAD THE TAPE DRIVE

	;CALL:	S1/ The Device Name in Sixbit
	;
	;RET:	True Always

REWIND:	SKIPA	S2,[.QOREW]		;REWIND ENTRY POINT,,GET REWIND MSG TYPE
UNLOAD:	MOVX	S2,.QOUNL		;UNLOAD ENTRY POINT,,GET UNLOAD MSG TYPE
LBLCOM:	STORE	S2,RECMSG+.MSTYP,MS.TYP	;MAKE THE RECOGNIZE MSG AN UNLOAD MSG
	PUSHJ	P,SNDREC		;SEND THE UNLOAD MSG OFF TO PULSAR
	MOVX	S2,.QOREC		;GET 'RECOGNIZE' MSG TYPE
	STORE	S2,RECMSG+.MSTYP,MS.TYP	;RESTORE THE RECOGNIZE MSG TYPE
	$RETT				;AND RETURN

	;STILL IN TOPS10
	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVOIUS PAGE
	;STILL IN TOPS10

	SUBTTL	SNDVDM - Send volume dismount message to tape labeler

;Call -
;	S1/	UCB adrs of drive just deassigned
;Returns -
;	message to tape labeler informing of drive no longer in use

SNDVDM:	LOAD	S2,.UCBST(S1),UC.DVT	;GET DEVICE TYPE
	CAIN	S2,%DTAP		;DECTAPE?
	$RETT				;YES--PULSAR DOESN'T CARE
	LOAD	S1,.UCBNM(S1)		;GET DRIVE NAME
	MOVX	S2,.QOVDM		;MESSAGE TYPE - VOLUME DISMOUNTED
	PJRST	LBLCOM			;GO SEND MESSAGE TO LABELER

>;END TOPS10


	SUBTTL	FNDUCB - ROUTINE TO FIND A UCB IN THE UCB CHAIN

	;CALL:	FNDUCB - S1/ The Address of the message asciz device name
	;	UCBFND - S1/ The sixbit device name
	;	LOCxxx	Get UCB regardless of un/available bit
	;	FNDxxx	Only return UCB if drive is available
	;
	;RET:	True - S1/ The UCB Address, S2/ sixbit device name checked/
	;	False - The UCB Was Not Found or the Device Name was Invalid,
	;	Or the 'Device Available' bit was not on in the UCB

TOPS10 <
LOCUCB:	TDZA	TF,TF			;SET FLAG FOR LOCATE UCB ENTRY POINT
FNDUCB:	SETOM	TF			;SET FLAG FOR FIND UCB ENTRY POINT
	$SAVE	<P1,P2>			;SAVE P1 AND P2
	MOVE	P1,TF			;SAVE THE ENTRY POINT FLAGS IN P1
	HRROI	S1,0(S1)		;GET A BYTE POINTER TO THE DEVICE NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	JRST	GETU.1			;CONTINUE TO SEARCH UCB CHAIN

UCBLOC:	TDZA	TF,TF			;SET FLAG FOR LOCATE UCB ENTRY POINT
D$GUCB::				;GLOBAL ENTRY POINT
UCBFND:	SETOM	TF			;SET FLAG FOR FIND UCB ENTRY POINT
	$SAVE	<P1,P2>			;SAVE P1 AND P2
	MOVE	P1,TF			;SAVE THE ENTRY POINT FLAGS IN T1
	MOVE	S2,S1			;GET THE DEVICE NAME IN S2

GETU.1:	MOVEM	S2,MDAOBJ+OBJ.UN	;SAVE THE DEVICE NAME IN THE OBJ BLOCK
	DEVNAM	S2,			;GET THE REAL DEVICE NAME
	  SKIPA	S2,MDAOBJ+OBJ.UN	;CAN'T - USE WHAT WE HAVE
	MOVEM	S2,MDAOBJ+OBJ.UN	;SAVE THE DEVICE NAME IN THE OBJ BLOCK
	MOVE	P2,S2			;SAVE THE DEVICE NAME IN P2 ALSO
	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%FIRST		;POSITION TO THE FIRST ENTRY
	JUMPF	E$NSD##			;NOT THERE,,RETURN NOW

FNDU.1:	CAME	P2,.UCBAU(S2)		;IS THIS THE UCB WE WANT ???
	CAMN	P2,.UCBNM(S2)		;   OR DO WE MATCH HERE ???
	JRST	FNDU.2			;FOUND,,SEE IF WE OWN IT !!!
	MOVE	S1,UCBQUE		;GET THE UCB QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT UCB ENTRY
	JUMPT	FNDU.1			;THERE IS ONE,,TRY IT OUT
	PJRST	E$NSD##			;RETURN THROUGH 'NO SUCH DEVICE'

FNDU.2:	MOVE	S1,S2			;PLACE UCB ADDR IN RETURN REG
	EXCH	S2,P2			;SWAP SIXBIT DEVICE NAME WITH UCB ADDR
	JUMPE	P1,.RETT		;OK IF DEVICE IS AVAILABLE,,RETURN
	LOAD	P2,.UCBST(P2),UC.AVA	;GET THE DEVICE AVAILABLE BIT
	JUMPN	P2,.RETT		;WE OWN THE DEVICE,,SO RETURN
	 $ERJMP	MD$IUD			;RETURN ERROR
>
	SUBTTL	GETRSN - ROUTINE TO RETURN THE FIRST AVAILABLE RESOURCE NUMBER

	;CALL:	No Args
	;
	;RET:	S1/ The Next Resource Number

TOPS10<
GETRSN:	MOVE	S1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	LOAD	S2,.AMHDR(S1),AM.MCN	;GET THE NUMBER OF SLOTS IN BLOCK
	JUMPE	S2,GETR.2		;NULL COUNT,,SHOULD NOT HAPPEN
	MOVNS	S2			;NEGATE IT
	HRLZS	S2			;TO LH
	ADDI	S2,1			;1 IN RH

GETR.1:	ADDI	S1,AMALEN		;GET NEXT MATRIX ENTRY
	SKIPGE	.AMNAM(S1)		;IS THIS RESOURCE ALLOCATED ???
	AOBJN	S2,GETR.1		;YES, TRY THE NEXT ONE
	JUMPGE	S2,GETR.2		;NO FREE BLOCKS
	HRRZ	S1,S2			;EXTRACT WINNING INDEX
	MOVE	S2,AMATRX		;AIM AT CURRENT BASE
	LOAD	TF,.AMHDR(S2),AM.CNT	;GET HIGHEST SLOT IN USE
	CAIGE	TF,0(S1)		;IS THIS A NEW HIGH?
	STORE	S1,.AMHDR(S2),AM.CNT	;YES, SAVE THE NEW HIGH WATER MARK
	$RETT				;GIVE THE CALLER THE INDEX

	;Here if we have to expand the 'A' matrix

GETR.2:	MOVE	S1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	INCR	.AMHDR(S1),AM.CNT	;BUMP THE HIGH WATER MARK
	INCR	.AMHDR(S1),AM.MCN	;AND THERE WILL BE SPACE FOR 1 MORE, TOO
	PUSH	P,AMATRX		;SAVE THE OLD 'A' MATRIX FOR LATER
	LOAD	S1,.AMHDR(S1),AM.LEN	;GET THE CURRENT MATRIX LENGTH
	ADDI	S1,AMALEN		;ADD 1 MORE ENTRY
	PUSHJ	P,M%GMEM		;GET SOME CORE FOR NEW 'A' MATRIX
	EXCH	S2,AMATRX		;SWAP OLD AND NEW 'A' MATRIX ADDRESSES
	MOVSS	S2			;GET OLD,,0
	HRR	S2,AMATRX		;GET OLD,,NEW ADDRESSES
	ADDI	S1,-AMALEN(S2)		;GET NEW MATRIX END ADDRESS
	BLT	S2,-1(S1)		;COPY OLD MATRIX TO NEW MATRIX
	MOVE	S2,AMATRX		;GET THE NEW 'A' MATRIX ADDRESS
	LOAD	S1,.AMHDR(S2),AM.LEN	;GET THE OLD MATRIX LENGTH
	ADDI	S1,AMALEN		;ADD ANOTHER ENTRY LENGTH
	STORE	S1,.AMHDR(S2),AM.LEN	;AND SAVE THE NEW 'A' MATRIX LENGTH
	POP	P,S2			;GET THE OLD 'A' MATRIX ADDRESS BACK
	LOAD	S1,.AMHDR(S2),AM.LEN	;GET THE OLD 'A' MATRIX LENGTH BACK
	PUSHJ	P,M%RMEM		;RETURN THE MEMORY
	MOVE	S1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	LOAD	S1,.AMHDR(S1),AM.CNT	;RETURN THE LAST MATRIX ENTRY AS A RSN
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	GIVRSN - Return a slot of the A matrix

	;This routine marks a slot of the A matrix as free
	;This routine also keeps track of AM.CNT, the highest
	; slot in use in the A matrix.
	;
	;CALL:	S1/ Resource number
	;
	;RET:	True Always

TOPS10<
D$GVRS::
GIVRSN:	JUMPE	S1,.RETT		;IF NO RSN, JUST RETURN
	MOVE	S2,S1			;GET THE RSN IN S2
	IMULI	S2,AMALEN		;GET THE OFFSET TO THE 'A' MATRIX ENTRY
	ADD	S2,AMATRX		;GET THE 'A' MATRIX ENTRY ADDRESS
	LOAD	S2,.AMCNT(S2),AM.ALO	;GET THE ALLOCATION COUNT
	JUMPN	S2,.RETT		;NOT ZERO,,DON'T DELETE THE ENTRY

	MOVE	S2,AMATRX		;GET THE BASE OF THE MATRIX
	LOAD	TF,.AMHDR(S2),AM.CNT	;GET CURRENT HIGHEST SLOT #
	CAIE	TF,0(S1)		;RETURNING THE HIGHEST SLOT IN USE?
	JRST	GIVR.3			;NO, KEEP GOING
	PUSH	P,S1			;SAVE RSN BEING RETURNED
	IMULI	S1,AMALEN		;INDEX INTO THE TABLE
	ADDI	S1,0(S2)		;AIM AT THIS SLOT

GIVR.1:	SUBI	S1,AMALEN		;BACK OFF TO NEXT LOWER SLOT
	SOJLE	TF,GIVR.2		;ANY SLOTS LEFT?
	SKIPL	.AMNAM(S1)		;IS THIS SLOT FREE?
	JRST	GIVR.1			;YES, TRY THE NEXT

GIVR.2:	STORE	TF,.AMHDR(S2),AM.CNT	;SAVE PRESENT HIGH WATER MARK
	POP	P,S1			;GET BACK RETURNED RSN

GIVR.3:	IMULI	S1,AMALEN		;INDEX INTO THE BLOCK
	ADD	S1,AMATRX		;AIM AT THE ENTRY
	MOVE	S2,.AMNAM(S1)		;GET THE NAME, AND PERMANENT BIT
	SETZM	.AMNAM(S1)		;CLEAR IT ALL OUT
	TXNE	S2,AM.PRM		;IS NAME IN PERMANENT A MATRIX?
	$RETT				;YES, LEAVE IT THERE
	LOAD	S2,S2,AM.NAM		;GET JUST THE STRING ADRS
	MOVEI	S1,AMNMLN		;LENGTH OF THE BLOCK
	$CALL	M%RMEM			;GIVE BACK THE STORAGE
	$RETT
> ;END TOPS10 CONDITIONAL
SUBTTL	FNTAPE - ROUTINE TO FIND A MAGTAPE VOLUME IN THE VOL DATA BASE
;	FNDISK -   ""   ""   ""    DISK      ""   ""  ""  ""  ""   ""
;	FNDECT -   ""   ""   ""    DECTAPE   ""   ""  ""  ""  ""   ""
;CALL:	S1/ The Volume We are Looking For
;
;FNDISK RET:	S1/ The Volume block Address
;
;FNTAPE RET:	S1/ The Volume block Address
;		S2/ The UCB Address if The Volume is Mounted or 0
;
;FNDECT RET:	S1/ The Volume block Address
;		S2/ The UCB Address if The Volume is Mounted or 0

D$FNDV::				;MAKE 'FNDISK' GLOBAL
FNDISK:	SKIPA	S2,[%DISK]		;WANT TO FIND STRUCTURE VOLUMES
FNTAPE:	MOVX	S2,%TAPE		;WANT TO FIND TAPE VOLUMES
	SETZM	TF			;WANT TO WTO THE OPERATOR
	JRST	CHKV.0			;CONTINUE ON

FNDECT:	MOVX	S2,%DTAP		;WANT TO FIND DECTAPE VOLUMES
	SETZM	TF			;WANT TO WTO THE OPERATOR
	JRST	CHKV.0			;CONTINUE ON

D$FTPX::
FNTAPX:	MOVX	S2,%TAPE		;WANT A TAPE VOL
	SETOM	TF			;  BUT NO WTO IF MOUNTED

CHKV.0:	PUSHJ	P,.SAVE3		;SAVE P1 - P3  FOR A MINUTE
	MOVE	P1,S1			;SAVE THE VOL WE ARE LOOKING FOR
	MOVE	P2,S2			;SAVE THE ENTRY POINT INDICATOR
	MOVE	P3,TF			;SAVE THE WTO FLAG

	;See if we can find the mounted volume in our requested volume list.

	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%FIRST		;POSITION TO THE FIRST ENTRY
	JRST	CHKV.2			;SKIP THE FIRST TIME THROUGH
CHKV.1:	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT VOL ENTRY
CHKV.2:	JUMPF	.RETF			;MSG VOLUME NOT FOUND,,RETURN
	MOVE	S1,S2			;GET THE VOLUME ADDRESS IN S1
	CAME	P1,.VLNAM(S1)		;HAVE WE FOUND THE MSG VOLUME ???
	JRST	CHKV.1			;NO,,TRY THE NEXT VOL ENTRY
	SKIPE	S2,.VLVSL(S1)		;GET A VSL ADDRESS
	LOAD	S2,.VSFLG(S2),VS.TYP	;GET THE VOLUME TYPE
	JUMPE	S2,[SKIPN S2,.VLUCB(S1)	;NO VSL ADDRESS,,GET UCB ADDRESS
		    JRST  CHKV.1	;NO UCB, BETTER SKIP IT
		    LOAD  S2,.UCBST(S2),UC.DVT ;GET THE VOLUME TYPE
		    JRST  CHKV.3 ]	;AND CONTINUE
CHKV.3:	CAME	S2,P2			;DO WE HAVE THE CORRECT VOLUME TYPE ???
	JRST	CHKV.1			;NO,,TRY NEXT
	CAIN	P2,%DISK		;LOOKING FOR DECTAPE OR MAGTAPES?
	$RETT				;NO,,RETURN

	;Found the Tape Volume in Our VOL Data Base,,Make Sure its not Mounted

	SKIPN	S2,.VLUCB(S1)		;FOUND IT,,IS THE VOL ALREADY MOUNTED ?
	$RETT				;NO, RETURN TRUE
	JUMPN	P3,.RETT		;YES, IF NO WTO WANTED, RETURN
	$WTO	(<Volume ^W/.VLNAM(S1)/ already mounted on ^W/.UCBNM(S2)/>,,MDAOBJ)
	$RETT				;AND RETURN TRUE (FOUND)

	SUBTTL	FNDOWN - FIND ANY OWNER OF A VOLUME 

	;CALL:	S1/ The VOL Block Address
	;
	;RET:	S1/ The Address of The VSL Address of The First Owner
	;
	;	False if the Volume is not owned

D$VOWN::
FNDOWN:	LOAD	TF,.VLOWN(S1),VL.CNT	;GET THE VOLUME REQUEST COUNT
	JUMPE	TF,.RETF		;NO REQUESTORS,,NO OWNERS...
	MOVNS	TF			;NEGATE IT
	HRL	S1,TF			;GET NEGATIVE COUNT IN LEFT HALF
	MOVX	TF,VL.ASN+VL.ASK	;GET THE VOLUME ASSIGNED+ASK BITS
FNDO.1:	TDNE	TF,.VLVSL(S1)		;DOES THIS USER OWN THE VOLUME ???
	JRST	[MOVEI  S1,.VLVSL(S1)	;YES,,GET THE ADDRESS OF THE VSL ADDRESS
		 $RETT ]		;AND RETURN IT
	AOBJN	S1,FNDO.1		;NO,,TRY NEXT
	$RETF				;AND RETURN
	SUBTTL	FNDMDR - ROUTINE TO FIND AN MDR GIVEN ITS JOB NUMBER

	;CALL:	FNDMDR:	S1/ The Users Job #
	;
	;RET:	AP/ The MDR Address If Found
	;	False if the MDR Can't be Found

D$FMDR::
FNDMDR:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVE	P1,S1			;SAVE THE JOB NUMBER
	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST MDR ENTRY
	JRST	FNDM.2			;JUMP THE FIRST TIME THROUGH

FNDM.1:	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT MDR ENTRY
FNDM.2:	JUMPF	.RETF			;MDR NOT FOUND !!!
	LOAD	S1,.MRJOB(S2),MR.JOB	;LOAD THE MDR JOB NUMBER
	CAME	S1,P1			;DO THEY MATCH ???
	JRST	FNDM.1			;NO,,TRY THE NEXT MDR
	MOVE	AP,S2			;YES,,GET THE MDR ADDRESS IN AP
	$RETT				;RETURN
	SUBTTL	FNDVSL - ROUTINE TO FIND A PARTICULAR VSL IN AN MDR

	;CALL:	S1/ The VSL Request ID
	;
	;RET:	S1/ The VSL Address if Found
	;	AP/ The MDR Address

D$FVSL::
FNDVSL:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;SAVE THE VSL REQUEST ID
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST VSL ENTRY
	JRST	FNDV.2			;JUMP THE FIRST TIME THROUGH

FNDV.1:	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT VSL ENTRY
FNDV.2:	JUMPF	.RETF			;NO MORE,,RETURN
	MOVE	S1,.VSRID(S2)		;GET THE VSL REQUEST ID
	CAME	P1,S1			;DO THEY MATCH ???
	JRST	FNDV.1			;NO,,TRY NEXT VSL
	MOVE	AP,.VSMDR(S2)		;YES,,SETUP THE MDR POINTER
	MOVE	S1,S2			;AND THE VSL ADDRESS
	$RETT				;RETURN

	SUBTTL	FNDVSN - ROUTINE TO FIND A VOLUME SET VIA THE VOL SET NAME

	;CALL:	S1/ The Asciz Vol Set Name Address
	;
	;RET:	S1/ The VSL Address

TOPS10<
D$FVSN::
FNDVSN:	PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A MINUTE
	HRROI	P2,0(S1)		;GET -1,,VOL SET NAME ADDR
	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	MOVNS	P1			;NEGATE IT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.MRVSL(AP)		;CREATE VSL SEARCH AOBJN AC

DVSN.1:	MOVE	S1,0(P1)		;GET A VSL ADDRESS
	HRROI	S1,.VSVSN(S1)		;POINT TO THE VSL VOL SET NAME
	MOVE	S2,P2			;GET THE SOURCE VOL SET NAME POINTER
	PUSHJ	P,S%SCMP		;PERFORM THE STRING COMPARE
	TXNN	S1,SC%LSS+SC%SUB+SC%GTR	;ANY OF THESE BITS LIT ???
	JRST	[MOVE	S1,0(P1)	;NO SO WE MATCH,,GET THE VSL ADDRESS
		 $RETT	]		;AND RETURN

	AOBJN	P1,DVSN.1		;NO MATCH,,TRY NEXT VSL
	$RETF				;NOT THERE !!!
> ;END TOPS10 CONDITIONAL

	SUBTTL	FNDLNM - ROUTINE TO FIND A USERS VSL GIVEN A LOGICAL NAME

	;CALL:	S1/ The Asciz Vole Set Name Address
	;	AP/ The MDR Address
	;
	;RET:	S1/ The VSL Address if Found

TOPS10<
D$FLNM::				;MAKE IT GLOBAL
FNDLNM:	PUSHJ	P,.SAVE1		;SAVE P1 
	HRROI	S1,0(S1)		;POINT TO ASCIZ VOLUME SET NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	LDB	S1,S1			;GET TERMINATOR
	JUMPN	S1,.RETF		;MUST BE NULL FOR LOGICAL NAMES
	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	MOVNS	P1			;NEGATE IT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.MRVSL(AP)		;CREATE VSL SEARCH AOBJN AC

FNDL.1:	MOVE	S1,0(P1)		;GET A VSL ADDRESS
	CAMN	S2,.VSLNM(S1)		;DO THE LOGICAL NAMES MATCH ???
	$RETT				;FOUND IT,,RETURN NOW
	AOBJN	P1,FNDL.1		;CONTINUE THROUGH ALL VSL'S
	$RETF				;NOT THERE,,RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	VSLFND - ROUTINE TO FIND A VSL IN A USERS REQUEST

	;CALL:	S1/ The Mount Msg Entry Address
	;	AP/ The MDR Address
	;
	;RET:	S1/ The VSL Address 

	;This routine searches the users request queue looking for a VSL
	;which has the same name as one which he is currently trying
	;to mount. It first looks for a VSL which has the same logical
	;name, then the one which has the same Vol Set Name.

TOPS10<
VSLFND:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	MOVEI	P1,.MEHSZ(S1)		;POINT TO THE FIRST ENTRY BLOCK
	MOVE	P2,.MECNT(S1)		;GET THE ENTRY COUNT
	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE REQUEST COUNT
	JUMPE	S1,.RETF		;NONE THERE,,RETURN

VSLF.1:	LOAD	S1,ARG.HD(P1),AR.TYP	;GET THIS BLOCK TYPE
	CAXE	S1,.SMNAM		;IS IT THE VOL SET NAME ???
	CAXN	S1,.TMSET		;IS IT THE VOL SET NAME BLOCK ???
	JRST	VSLF.2			;YES,,CHECK IT OUT
	LOAD	S1,ARG.HD(P1),AR.LEN	;NO,,GET THIS BLOCKS LENGTH
	ADD	P1,S1			;POINT TO THE NEXT BLOCK
	SOJG	P2,VSLF.1		;CONTINUE FOR ALL BLOCKS
	$RETF				;NO VOL SET NAME BLOCK FOUND !!!

VSLF.2:	AOS	P1			;POINT TO THE ASCIZ VOL SET NAME
	MOVE	S1,P1			;GET ITS ADDRESS IN S1
	PUSHJ	P,FNDLNM		;LOOK FOR THE LOGICAL NAME 
	JUMPT	.RETT			;FOUND,,RETURN NOW
	MOVE	S1,P1			;GET THE VOL SET NAME ADDR BACK
	PJRST	FNDVSN			;RETURN LOOKING FOR THE VOL SET NAME
> ;END TOPS10 CONTITIONAL

TOPS20<	
VSLFND:	$RETF	>			;ALWAYS RETURN FALSE ON THE -20

	SUBTTL	GENVOL - ROUTINE TO CREATE A 'SCRATCH' VOLUME BLOCK

	;CALL:	S1/ The VSL Address of the User
	;
	;RET:	True Always


GENVOL:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	MOVE	S1,VOLQUE		;GET THE VOLUME LIST QUEUE ID
	MOVX	S2,VOLLEN		;GET THE VOL ENTRY LENGTH
	PUSHJ	P,L%CENT		;CREATE SPACE FOR THE VOL ENTRY
	LOAD	S1,.VSCVL(P1),VS.OFF	;GET THE OFFSET TO THE CURRENT VOL
	ADDI	S1,.VSVOL(P1)		;POINT TO THE VOL BLOCK ADDRESS
	MOVEM	S2,0(S1)		;LINK THE VOL TO THE VSL
	MOVEM	P1,.VLVSL(S2)		;LINK THE VSL TO THE VOL
	MOVX	S1,%STAWT		;GET 'WAITING' STATUS CODE
	STORE	S1,.VLFLG(S2),VL.STA	;SAVE IT IN THE VOL FLAG WORD
	INCR	.VLOWN(S2),VL.CNT	;BUMP THE REQUEST COUNT BY 1
	LOAD	S1,.VSFLG(P1),VS.LBT	;GET THE REQUESTED LABEL TYPE
	STORE	S1,.VLFLG(S2),VL.LBT	;AND SAVE IT IN THE VOL FLAG WRD
	MOVX	S1,VL.SCR		;GET THE VOLUME SCRATCH BIT
	IORM	S1,.VLFLG(S2)		;LITE IT IN THE VOL FLAG WORD
	INCR	.VSCVL(P1),VS.CNT	;MAKE THE VSL COUNT = 1
	$RETT				;AND RETURN
	SUBTTL	ADDVOL -  ROUTINE TO ADD A VOL BLOCK DURING MOUNT PROCESSING

	;CALL:	S1/ The Volume Name
	;	S2/ The VSL Address
	;
	;RET:	The VOL Block Address

ADDVOL:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2 FOR A SECOND
	DMOVE	P1,S1			;SAVE THE CALLING ARGS
	PUSHJ	P,SCNVOL		;GO FIND THE REQUESTED VOLUME
	JUMPT	.RETT			;FOUND ONE,,RETURN NOW
	MOVE	S1,VOLQUE		;GET THE VOLUME LIST QUEUE ID
	MOVX	S2,VOLLEN		;GET THE VOL LIST ENTRY LENGTH
	PUSHJ	P,L%CENT		;CREATE SPACE FOR THE VOL ENTRY
	MOVEM	P1,.VLNAM(S2)		;SAVE THE VOLID IN THE VOL
	MOVEM	P2,.VLVSL(S2)		;LINK THE VSL TO THE VOL
	MOVX	S1,%STAWT		;GET 'VOLUME WAITING' CODE
	STORE	S1,.VLFLG(S2),VL.STA	;SAVE IT AS THE VOLUME STATUS
	INCR	.VLOWN(S2),VL.CNT	;BUMP THE REQUEST COUNT BY 1
	MOVE	S1,S2			;GET THE VOL BLK ADDR IN S1
	$RETT				;RETURN

	SUBTTL	CKUVOL - CHECK FOR MULTIPLE USER REQUESTS FOR THE SAME TAPE VOL
;		CKOVOL - SAME - BUT OPERATOR ENTRY POINT

	;CALL:	S1/ The VSL address
	;	AP/ The MDR Address
	;
	;RET:	True - if ok
	;	False - The error text inserted into the generic ack buffer

TOPS10<
CKTVOL:	PUSHJ	P,.SAVE4		;SAVE P1 - P4
	$SAVE	<T1,T2>			;SAVE T1 AND T2 ALSO
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	LOAD	P2,.MRCNT(AP),MR.CNT	;GET THE VSL COUNT
	MOVNS	P2			;NEGATE IT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.MRVSL(AP)		;CREATE VSL AOBJN AC
CKTV.1:	MOVE	P3,0(P2)		;GET A VSL ADDRESS
	LOAD	S1,.VSFLG(P3),VS.TYP	;GET THE VSL TYPE
	CAXE	S1,%TAPE		;IS IT A TAPE VOLUME SET ???
	JRST	CKTV.6			;NO,,TRY NEXT
CKTV.2:	LOAD	S1,.VSCVL(P1),VS.CNT	;GET THE VOLUME COUNT
	MOVNS	S1			;NEGATE IT
	MOVSS	S1			;MOVE RIGHT TO LEFT
	HRRI	S1,.VSVOL(P1)		;CREATE VOL AOBJN AC
CKTV.3:	LOAD	S2,.VSCVL(P3),VS.CNT	;GET THE VOLUME COUNT
	MOVNS	S2			;NEGATE IT
	MOVSS	S2			;MOVE RIGHT TO LEFT
	HRRI	S2,.VSVOL(P3)		;CREATE VOL AOBJN AC
	MOVE	P4,0(S1)		;GET THE MASTER VOL ADDRESS
	SKIPN	P4,.VLNAM(P4)		;AND GET ITS VOLID
	JRST	CKTV.6			;NONE,,ASSUME A SCRATCH TAPE & CONTINUE
	SETZM	T2			;CLEAR VOLUME COUNTER
CKTV.4:	AOS	T2			;BUMP VOLUME COUNTER BY 1
	MOVE	T1,0(S2)		;GET THE TARGET VOL ADDRESS
	CAME	P4,.VLNAM(T1)		;DO VOLIDS MATCH ???
	JRST	CKTV.5			;NO,,CONTINUE ONWARD !!!
	CAMN	P1,P3			;YES,,SAME VOLUME SET ???
	CAME	S1,S2			;YES,,SAME VOLUME SET INDEX ???
	JRST	CKTV.7			;NO,,THATS AN ERROR
CKTV.5:	AOBJN	S2,CKTV.4		;CHECK THROUGH ALL TARGET VOLUMES
	AOBJN	S1,CKTV.3		;CHECK THROUGH ALL MASTER VOLIDS
CKTV.6:	AOBJN	P2,CKTV.1		;CHECK THROUGH ALL VSL'S
	$RETT				;OK,,RETURN

CKTV.7:	$TEXT	(<-1,,@G$ACKB>,<Volume ^W/P4/ is volume # ^D/T2/ in volume set ^T/.VSVSN(P3)/^0>)
	PJRST	E$XXX##			;RETURN THE ERROR
> ;END TOPS10 CONDITIONAL

TOPS20<
CKTVOL:	$RETT	>			;RETURN OK ON THE -20
SUBTTL	Miscellaneous routines


TOPS10<
MISC.3:	$WTO	(<Invalid message from PULSAR>,<^M^JMSG: ^O/0(M)/, ^O/1(M)/, ^O/2(M)/, ^O/3(M)/, ^O/4(M)/^M^J^O/5(M)/, ^O/6(M)/, ^O/7(M)/, ^O/10(M)/, ^O/11(M)/>,,<$WTFLG(WT.SJI)>)
	$RETT


	;Routine to tell the operator that a user requested a structure
	;be dismounted
	;
	;CALL:	S1/ The VSL Address
	;	AP/ The MDR Address

TELREM:	MOVE	S2,.VSVOL(S1)		;GET THE VOL BLOCK ADDRESS
	MOVE	S1,.VLNAM(S2)		;GET THE STR NAME
	MOVEM	S1,MDAOBJ+OBJ.UN	;SAVE IT IN THE OBJECT BLOCK
	$WTO	(<User requests this structure be dismounted^T/BELLS/>,<^I/DEMOT/>,MDAOBJ)
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL
;Routine to set up byte pointer for call to MDADBP.

MDASBP::PUSH	P,[POINT 7,G$MSG]	;STUFF A BYTE POINTER
	POP	P,MDBPTR		;SET UP FOR CALLS TO MDADBP
	SETZM	G$MSG			;CLEAR THE FIRST WORD
	SETZM	G$MSG+MSGLN##-1		; AND THE LAST WORD FOR EOB CHECK
	$RETT				;WE'RE HAPPY

;$TEXT Action routine and byte pointer

MDADBP:: SKIPN	G$MSG+MSGLN##-1		;CHECK FOR END OF BUFFER
	 IDPB	S1,MDBPTR		;JUST DUMP THE CHAR
	 $RETT				;AND WIN
MDBPTR:: BLOCK	1			;SPACE FOR A BYTE POINTER
	;Routine to copy VSL request dependent data from MDR to VSL
	;Call:	AP = MDR address
	;	S1 = VSL address

MDR2VS:	MOVE	TF,.MRPID(AP)		;[1173] MOVE REQUEST DEPENDENT
	MOVEM	TF,.VSPID(S1)		;[1173] DATA TO VSL
	MOVE	TF,.MRACK(AP)		;[1173] ..
	MOVEM	TF,.VSACK(S1)		;[1173] ..
	MOVE	TF,.MRFLG(AP)		;[1173] ..
	MOVEM	TF,.VSRFL(S1)		;[1173] ..
	$RETT				;[1173] RETURN

	SUBTTL	D$MDAE - ROUTINE TO NOTIFY THE OPERATOR OF ANY ERRORS

	;This routine notifies the operator of any MDA related error
	;
	;CALL:	P/ The address of the Parameter Word
	;
	;RET:	False Always

TOPS10<
D$MDAE::SETZM	TF			;NO VSL ADDRESS
	LOAD	TF,@0(P),AC.VSL		;GET THE AC WHICH CONTAINS THE VSL ADDR
	TXO	TF,MOVE			;CREATE 'MOVE TF,AC' INSTRUCTION
	XCT	TF			;GET THE VSL ADDRESS IN TF
	POP	P,S1			;GET THE ERROR CODE & AC ADDRESS
	LOAD	S1,0(S1),ER.CDE		;PICK UP THE ERROR CODE 
	TXNN	TF,MOVE			;DO WE HAVE A VSL ADDRESS ???
	JRST	MDAE.1			;YES,,PROCESS A LITTLE DIFFERENTLY !!!
	$WTO	(<^T/@MDAERS-1(S1)/>,,MDAOBJ) ;ELSE TELL OPERATOR
	$RETF				;RETURN

MDAE.1:	$SAVE	<S1,S2,T1,T2,AP>	;SAVE SOME AC'S
	MOVE	T1,TF			;GET THE VSL ADDRESS IN T1
	MOVE	AP,.VSMDR(T1)		;GET THE MDR ADDRESS IN AP
	LOAD	T2,.VSCVL(T1),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	T2,.VSVOL(T1)		;POINT TO THE ADDRESS
	MOVE	T2,0(T2)		;LOAD THE CURRENT VOLUME ADDRESS
	LOAD	S2,.MRJOB(AP),MR.JOB	;GET THE USERS JOB NUMBER
	TXC	S2,BA%JOB		;COMPLEMENT
	TXNE	S2,BA%JOB		;A PSEUDO PROCESS?
	SKIPA	S2,[DEMOT]		;NO--NORMAL TIMESHARING
	MOVEI	S2,DEMOB		;PSEUDO-PROCESS
	$WTO	(<^T/@MDAERS-1(S1)/>,<^I/(S2)/Volume Set:^T/.VSVSN(T1)/  Volid:^W/.VLNAM(T2)/  Request-ID: ^D/.VSRID(T1)/>,MDAOBJ)
	$RETF				;RETURN

> ;END TOPS10 CONDITIONAL


	SUBTTL	DSKRSN - ROUTINE TO RETURN RESOURCE NUMBERS FOR DISK DRIVES

	;CALL:	S1/ The .UCBST status word with Kontroller type & Unit Type
	;
	;RET:	S1/ The Device Resource Number

TOPS10<
D$DRSN::
DSKRSN:	PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A SECOND
	LOAD	P1,S1,UC.KTP		;GET THE KONTROLLER TYPE IN P1
	LOAD	P2,S1,UC.UTP		;GET THE UNIT TYPE IN P2
	MOVE	S1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	LOAD	S2,.AMHDR(S1),AM.CNT	;GET THE ENTRY COUNT
	JUMPE	S2,.RETF		;NULL MATRIX,,SHOULD NOT HAPPEN !!!

DSKR.1:	ADDI	S1,AMALEN		;BUMP TO NEXT MATRIX ELEMENT
	LOAD	TF,.AMSTA(S1),AM.DVT	;GET THE RESOURCE TYPE
	SKIPGE	.AMNAM(S1)		;IS THIS ENTRY VALID?
	CAXE	TF,%DISK		;YES,, IS THIS A DISK RESOURCE?
	JRST	DSKR.2			;NO,,TRY NEXT ENTRY
	LOAD	TF,.AMSTA(S1),UC.KTP	;GET THE ENTRY KONTROLLER TYPE
	CAME	TF,P1			;THEY MUST MATCH..
	JRST	DSKR.2			;NO,,TRY NEXT ENTRY
	LOAD	TF,.AMSTA(S1),UC.UTP	;GET THE ENTRY UNIT TYPE
	CAME	TF,P2			;THEY MUST MATCH..
	JRST	DSKR.2			;NO,,TRY NEXT ENTRY
	SUB	S1,AMATRX		;CALC OFFSET INTO MATRIX OF THIS ENTRY
	IDIVI	S1,AMALEN		;CALC RESOURCE NUMBER
	$RETT				;RETURN

DSKR.2:	SOJG	S2,DSKR.1		;LOOK AT ALL MATRIX ENTRIES
	$RETF				;NOT THERE !!!
> ;END TOPS10 CONDITIONAL

	SUBTTL	TAPRSN - ROUTINE TO RETURN RESOURCE NUMBERS FOR TAPE DRIVES

	;CALL:	S1/ The Density Status Bits
	;	S2/ The Track Status Code
	;	T1/ The starting RSN if ANYTAP entry
	;
	;RET:	S1/ The Device Resource Number


TOPS10<
ANYTAP:	PUSHJ	P,.SAVE4		;SAVE P1 - P4
	DMOVE	P1,S1			;SAVE THE DENSITY AND TRACK TYPE
	MOVEI	P3,0			;SET THE ENTRY INDICATOR
	MOVE	S1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	LOAD	P4,.AMHDR(S1),AM.CNT	;GET THE ENTRY COUNT
	SUB	P4,T1			;GET REMAINING COUNT
	JUMPLE	P4,.RETF		;NO MORE ENTRIES,,RETURN
	MOVE	S1,T1			;GET THE STARTING RSN IN S1
	IMULI	S1,AMALEN		;GET THE OFFSET
	ADD	S1,AMATRX		;AND THE RESOURCE ADDRESS
	JRST	TAPR.1			;MEET AT THE PASS

D$TRSN::PUSHJ	P,.SAVE4		;SAVE SOME ACS
	DMOVE	P1,S1			;COPY DENSITY AND TRACK TYPE
	MOVEI	P3,0			;SET ENTRY INDICATOR
	JRST	TAPR.0			;ENTER COMMON CODE

TAPRSN:	PUSHJ	P,.SAVE4		;SAVE P1 & P2 FOR A SECOND
	DMOVE	P1,S1			;SAVE THE DENSITY AND TRACK TYPE 
	MOVEI	P3,1			;SET THE ENTRY INDICATOR

TAPR.0:	MOVE	S1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	LOAD	P4,.AMHDR(S1),AM.CNT	;GET THE ENTRY COUNT
	JUMPE	P4,.RETF		;NULL MATRIX,,SHOULD NOT HAPPEN !!!

TAPR.1:	ADDI	S1,AMALEN		;BUMP TO NEXT MATRIX ENTRY
	LOAD	S2,.AMSTA(S1),AM.DVT	;GET THE RESOURCE TYPE
	SKIPGE	.AMNAM(S1)		;IS THIS ENTRY VALID AT ALL?
	CAXE	S2,%TAPE		;YES,, IS THIS A TAPE RESOURCE?
	JRST	TAPR.2			;NO,,TRY NEXT ENTRY
	LOAD	S2,.AMSTA(S1),UC.TRK	;GET THE ENTRY TRACK TYPE
	CAME	S2,P2			;THEY MUST MATCH..
	JRST	TAPR.2			;NO,,TRY NEXT ENTRY
	MOVE	S2,.AMSTA(S1)		;GET THE STATUS BITS
	AND	S2,[UC.200+UC.556+UC.800+UC.1600+UC.6250] ;SAVE ONLY THESE BITS
	XCT	[TDNN S2,P1		;ANY BITS CAN MATCH !!!
		 CAME S2,P1](P3)	;ALL BITS MUST MATCH !!!
	 JRST	TAPR.2			;NO GOOD,,TRY NEXT ENTRY
	SUB	S1,AMATRX		;CALC OFFSET INTO MATRIX OF THIS ENTRY
	IDIVI	S1,AMALEN		;CALC THE RESOURCE NUMBER
	$RETT				;RETURN

TAPR.2:	SOJG	P4,TAPR.1		;LOOK AT ALL MATRIX ENTRIES
	$RETF				;NOT THERE !!!


D$ORSN::
DTARSN:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	S1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	LOAD	P1,.AMHDR(S1),AM.CNT	;AND THE ENTRY COUNT
	JUMPE	P1,.RETF		;DEFEND AGAINST A NULL MATRIX

DTAR.1:	ADDI	S1,AMALEN		;POINT TO NEXT MATRIX ENTRY
	LOAD	S2,.AMSTA(S1),AM.DVT	;GET RESOURCE TYPE
	SKIPGE	.AMNAM(S1)		;IS THIS ENTRY VALID?
	CAIE	S2,%DTAP		;AND IS THIS A DECTAPE RESOURCE?
	JRST	DTAR.2			;NO
	SUB	S1,AMATRX		;GET OFFSET INTO MATRIX
	IDIVI	S1,AMALEN		;COMPUTE THE RESOURCE NUMBER
	$RETT				;AND RETURN

DTAR.2:	SOJG	P1,DTAR.1		;LOOP
	$RETF				;NO RESOURCE AVAILABLE
> ;END TOPS10 CONDITIONAL

	SUBTTL	D$TNRS - GET A MAGTAPE RESOURCE NUMBER
	;	D$DNRS - GET A DISK RESOURCE NUMBER
	;	D$ONRS - GET A DECTAPE RESOURCE NUMBER


	;CALL:	D$TNRS:	S1/ The Density Status Bits
	;		S2/ The Track Status Code
	;
	;	D$DNRS:	S1/ The UCB Status Word
	;
	;RET:	S1/ The Resource Number if valid, False otherwise

TOPS10<
D$TNRS::$SAVE	<T1>			;SAVE T1
	MOVEI	T1,TAPRSN		;GET STATUS CHECK ROUTINE EXACT MATCH
	PJRST	KNOWRS			;TRY TO FIND ONE , OR A NEW ONE

D$DNRS::$SAVE	<T1>			;SAVE T1
	MOVEI	T1,DSKRSN		;GET THE SERVICE ROUTINE ADRS
	PJRST	KNOWRS			;GO FIND A KNOWN RESOURCE

D$ONRS::$SAVE	<T1>			;SAVE T1
	MOVEI	T1,DTARSN		;SERVICE ROUTINE
;	PJRST	KNOWRS			;TRY TO FIND A RESOURCE

	;This routine will find an existing resource of a given type
	; or look in the permanent A matrix for drives which match
	; If the entry is found in the permanent matrix, it is added
	; to the existing A matrix and the new resource number is returned

KNOWRS:	$SAVE	<P1,P2,P3>		;SAVE P1 - P3
	DMOVE	P1,S1			;SAVE THE CALLING ARGS
	PUSHJ	P,0(T1)			;TRY TO FIND IN THE EXISTING A MATRIX
	JUMPT	.RETT			;IF THAT WINS, WE'RE GOLDEN!
	DMOVE	S1,P1			;GET BACK STATUS BITS
	MOVEI	P1,AMATPM		;AIM AT THE PERMANENT A MATRIX
	EXCH	P1,AMATRX		;AND POINT THE WORLD AT THAT
	PUSHJ	P,0(T1)			;TRY TO FIND ONE OF THOSE
	JUMPF	[MOVEM	P1,AMATRX	;CAN'T GET IT THERE, RESTORE AMATRIX
		$RETF]			;GIVE THE BAD NEWS
	MOVE	P3,S1			;GOT IT, SAVE ITS INDEX
	EXCH	P1,AMATRX		;GET BACK TO OLD A MATRIX
	PUSHJ	P,GETRSN		;FIND A FREE SLOT
	PUSH	P,S1			;SAVE THE NEW RESOURCE NUMBER
	IMULI	S1,AMALEN		;INDEX INTO THE EXISTING A MATRIX
	IMULI	P3,AMALEN		;INDEX INTO PERMANENT A MATRIX
	ADD	S1,AMATRX		;AIM AT EXISTING SLOT
	ADDI	P3,0(P1)		;AIM AT PERMANENT SLOT
	HRL	S1,P3			;SET SOURCE FOR BLT
	MOVE	P3,S1			;COPY FOR TERMINATION ADRS
	BLT	S1,AMALEN-1(P3)		;MOVE THE DATA IN
	POP	P,S1			;GET BACK THE NEW RESOURCE NUMBER
	$RETT
> ;END TOPS10 CONDITIONAL
	SUBTTL	STRRSN - ROUTINE TO RETURN RESOURCE NUMBERS FOR STRUCTURES

	;CALL:	S1/ The Sixbit Structure Name
	;
	;RET:	S1/ The Structure Resource Number

TOPS10<
D$SRSN::
	MOVX	S2,%STRC		;GET RESOURCE TYPE -- FILE STRUCTURE

DEVRSN:	PUSHJ	P,.SAVE3		;SAVE SOME SCRATCH REGS
	MOVE	P3,S2			;SAVE THE RESOURCE TYPE
	$TEXT	(<-1,,TMPVSL>,<^W/S1/^0>) ;CONVERT STR NAME TO ASCII
	MOVE	P1,AMATRX		;GET THE 'A' MATRIX ADDRESS
	LOAD	P2,.AMHDR(P1),AM.CNT	;GET THE ENTRY COUNT
	JUMPE	P2,STRR.2		;NULL MATRIX,,SHOULD NOT HAPPEN !!!

STRR.1:	ADDI	P1,AMALEN		;BUMP TO THE NEXT MATRIX ELEMENT
	LOAD	S2,.AMSTA(P1),AM.DVT	;GET THE RESOURCE TYPE
	SKIPGE	S1,.AMNAM(P1)		;IS THIS ENTRY IN USE?
	CAME	S2,P3			;YES,, IS THIS THE CORRECT TYPE OF RESOURCE??
	JRST	STR.1A			;NOPE, TRY THE NEXT ENTRY
	HRLI	S1,-1			;AIM AT THE STRING
	HRROI	S2,TMPVSL		;AIM AT THE DESIRED NAME
	$CALL	S%SCMP			;COMPARE THE NAMES
	TXNE	S1,SC%LSS!SC%SUB!SC%GTR	;ANY BITS ON?
	JRST	STR.1A			;YES, THAT'S NOT EXACT MATCH
	SUB	P1,AMATRX		;NO,,CALC THE RESOURCE OFFSET
	IDIVI	P1,AMALEN		;CALC THE RESOURCE NUMBER
	MOVE	S1,P1			;MOVE IT INTO RETURN SLOT
	$RETT				;AND RETURN

STR.1A:	SOJG	P2,STRR.1		;LOOK AT ALL MATRIX ENTRIES

	;CONTINUED ON NEXT PAGE
	;CONTINUED FROM PREVIOUS PAGE

	;Here if the structure is not in the 'A' matrix,
	; so add an entry for it!
	;P1-P3 saved
	;P3/	Resource type
	;TMPVSL/	Resource name (ASCIZ)

STRR.2:	PUSHJ	P,GETRSN		;GET A RESOURCE NUMBER
	MOVE	P1,S1			;SAVE IT
	IMULI	P1,AMALEN		;CALC OFFSET INTO THE MATRIX
	ADD	P1,AMATRX		;LOCATE THE ENTRY
	MOVEI	S1,AMNMLN		;GET THE NAME SPACE SIZE
	$CALL	M%GMEM			;GET THE SPACE
	IORX	S2,AM.USE		;LITE THE IN-USE BIT
	MOVEM	S2,.AMNAM(P1)		;SAVE THE ADRS OF THE NAME
	HRLI	S2,TMPVSL		;AIM AT THIS STRUCTURE NAME
	HRRZI	S1,AMNMLN(S2)		;FIGURE TERMINATION ADRS
	BLT	S2,-1(S1)		;MOVE TH NAME IN
	SETZM	.AMSTA(P1)		;ZERO THE STATUS WORD
	STORE	P3,.AMSTA(P1),AM.DVT	;SET DESIRED RESOURCE TYPE
	MOVEI	S2,1			;GET DEFAULT NUMBER AVAILABLE
	CAXN	P3,%STRC		;IS THIS A SHARABLE RESOURCE?
	MOVX	S2,MAXRES		;YES,,GET MAX RESOURCE COUNT
	STORE	S2,.AMCNT(P1),AM.AVA	;MAKE IT THE NUMBER AVAILABLE
	SUB	P1,AMATRX		;CALC THE MATRIX OFFSET
	IDIVI	P1,AMALEN		;CALC THE RESOURCE NUMBER
	MOVE	S1,P1			;COPY THE RSN OVER
	$RETT				;AND RETURN
> ;END TOPS10 CONDITIONAL
	SUBTTL	D$T/SVRS - Generate resource #s for Tape/Structure volumes

	;CALL:	S1/ VOL Block Address
	;
	;RET:	S1/ The Volume RSN
	;	Volume resource number in the vol block

TOPS10<
	INTERN	D$TVRS			;GLOBALIZE IT
	INTERN	D$SVRS			;HERE ALSO

D$TVRS:	SKIPA	S2,[EXP %TVOL]		;RESOURCE TYPE - TAPE VOLUME
D$SVRS:	MOVX	S2,%STRC		;RESOURCE TYPE - STRUCTURE
	JRST	VRSX			;ENTER COMMON CODE
D$OVRS:	MOVX	S2,%DTVOL		;RESOURCE TYPE - DECTAPE
VRSX:	LOAD	TF,.VLFLG(S1),VL.RSN	;IS THERE ALREADY A RSN?
	JUMPN	TF,[MOVE S1,TF		;YES, COPY IT
		    $RETT ]		;AND WIN
	$SAVE	<P1,P2>			;SAVE SOME SPACE
	DMOVE	P1,S1			;SAVE VOL BLK, RESOURCE TYPE
	MOVE	S1,.VLNAM(S1)		;GET THE SIXBIT VOLUME NAME
	PUSHJ	P,DEVRSN		;MAKE UP A RSN
	STORE	S1,.VLFLG(P1),VL.RSN	;SAVE THE RSN
	$RETT				;WIN
> ;END TOPS10 CONDITIONAL
	SUBTTL	VALMSG - ROUTINE TO VALIDATE THE MOUNT/ALLOCATE MESSAGE

	;CALL:	M/ The Mount/Allocate Message Address
	;
	;RET:	True if valid, False otherwise

VALMSG:	PUSHJ	P,.SAVE4		;SAVE P1 - P4
	STKVAR	<MSGLEN,MNTALC>		;GET SPACE FOR MSG LEN & MOUNT STATUS
	LOAD	S1,.MSTYP(M),MS.CNT	;GET THE MESSAGE LENGTH
	CAIL	S1,.MMHSZ		;MUST BE GREATER THEN .MMHSZ AND
	CAIL	S1,.MMUMX		;   LESS THEN .MMUMX
	PJRST	E$IBL##			;ELSE ITS AN ERROR
	ADD	S1,M			;POINT TO THE END OF THE MESSAGE
	MOVEM	S1,MSGLEN		;AND SAVE IT
	MOVE	P1,.MMARC(M)		;GET THE VOLUME SET COUNT IN P1
	JUMPL	P1,E$IBL##		;CAN'T BE NEGATIVE
	JUMPE	P1,VALM.3		;IF 0, THEN REST OF MESSAGE MBZ
	MOVEI	P2,.MMHSZ(M)		;POINT TO THE FIRST MOUNT ENTRY
	LOAD	P3,.MSTYP(M),MS.TYP	;GET THE MSG TYPE (.QIFNC IS INTERNAL)
	LOAD	S1,.MEFLG(P2),ME%ALC	;GET THE FIRST ENTRY'S MOUNT/ALLOC BIT
	MOVEM	S1,MNTALC		;SAVE IT FOR LATER

VALM.1:	CAMLE	P2,MSGLEN		;MUST BE LESS OR EQUAL TO END OF MSG
	PJRST	E$IBL##			;NO GOOD,,RETURN INVALID MESSAGE
	LOAD	S1,.MEFLG(P2),ME%ALC	;GET THE MOUNT/ALLOCATE STATUS BIT
	CAXE	P3,.QIFNC		;IS THIS AN INTERNAL REQUEST ???
	CAMN	S1,MNTALC		;CAN'T MIX MOUNT/ALLOCATE IN SAME MSG
	SKIPA				;INTERNAL OR MATCHING TYPES,,SKIP
	PJRST	E$IBL##			;HE DID,,RETURN INVALID MESSAGE
	LOAD	S1,.MEHDR(P2),AR.LEN	;GET THIS ENTRIES LENGTH
	ADD	S1,P2			;POINT TO THE END OF THE ENTRY
	MOVEI	S2,.MEHSZ(P2)		;POINT TO THE DATA BLOCK AREA
	CAIG	S2,0(S1)		;MUST BE LESS OR EQUAL TO END OF ENTRY
	SKIPG	P4,.MECNT(P2)		; AND ENTRY COUNT MUST BE POSITIVE
	PJRST	E$IBL##			;NO,,THATS AN ERROR

VALM.2:	LOAD	TF,ARG.HD(S2),AR.LEN	;GET THIS BLOCK'S LENGTH
	ADD	S2,TF			;POINT TO THE NEXT BLOCK
	CAILE	S2,0(S1)		;MUST STILL BE WITHIN THE ENTRY
	PJRST	E$IBL##			;NO,,THATS AN ERROR
	SOJG	P4,VALM.2		;CONTINUE CHECKING ALL ENTRY BLOCKS
	MOVE	P2,S2			;POINT TO NEXT 'ME' ENTRY

	SOJG	P1,VALM.1		;CONTINUE THROUGH ALL VOLUME SETS

	CAME	P2,MSGLEN		;CALC AND ACTUAL END ADDRS MUST BE EQUAL
	PJRST	E$IBL##			;NO,,THATS AN ERROR
	$RETT				;RETURN OK

VALM.3:	MOVEI	P1,.OFLAG(M)		;GET FLAG WORD ADDRESS
VALM.4:	AOS	P1			;POINT TO NEXT WORD
	SKIPE	0(P1)			;MUST BE ZERO...
	JRST	E$IBL##			;NO,,THATS AN ERROR
	CAMGE	P1,MSGLEN		;ARE WE DONE ???
	JRST	VALM.4			;NO,,CHECK NEXT
	$RETT				;YES,,RETURN
	SUBTTL	CHKBAT - ROUTINE TO CHECK FOR BATCH REQUESTS DOING MOUNTS

	;CALL:	AP/ The MDR Address
	;
	;RET:	True if OK, False if Illegal

D$CHKB::				;GLOBALIZE IT
CHKBAT:	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE SENDERS JOB NUMBER
	TXNE	S1,BA%JOB		;ARE WE EXECUTING YET ????
	JRST	CHKB.4			;NO,,THEN CHECK SCHEDULABILITY
	SKIPE	S1,.MRQEA(AP)		;LOAD UP THE QE ADDRESS
;**;[1135]ADD AND REVAMP CODE AT CHKBAT:+4L	7-JUL-83/CTK
	SKIPN	.QEOBJ(S1)		;[1135]ONE MORE CHECK BEFORE WE DO IT !!
	$RETT				;NOT A SCHEDULED JOB,,THEN RETURN
	GETLIM	S2,.QELIM(S1),OINT	;[1135]GET USERS /ASSIST: SWITCH
	CAXN	S2,.OPINY		;IS INTERVENTION ALLOWED ???
	$RETT				;YES,,THEN HE IS OK !!!
	MOVE	S1,.QEOBJ(S1)		;[1135]GET ADDR OF OBJECT PARAMETERS

	MOVE	S2,OBJPID(S1)		;GET THE PROCESSORS PID
	MOVEM	S2,G$SAB##+SAB.PD	;SET IT
	MOVE	S2,OBJUNI(S1)		;GET THE STREAM NUMBER
	MOVEM	S2,ABOSTM		;SET IT
	MOVE	S2,OBJNOD(S1)		;GET THE NODE NUMBER
	MOVEM	S2,ABONOD		;SET IT
	MOVX	S1,ABOLEN		;GET THE MSG LENGTH
	MOVEM	S1,G$SAB##+SAB.LN	;SET IT
	MOVEI	S2,ABOMSG		;GET THE MSG ADDRESS
	MOVEM	S2,G$SAB##+SAB.MS	;SET IT
	PUSHJ	P,C$SEND##		;SEND THE CANCEL MSG
	$RETF				;RETURN

CHKB.4:	SKIPN	S1,.MRQEA(AP)		;CHECK AND LOAD QE ADDRESS
	STOPCD	(MQE,HALT,,<Missing QE for a pseudo process>)
	PJRST	S$INPS##		;CHECK SCHEDULABILITY AND RETURN

	;Gen cancel msg here (Cheaper then generating 'on the fly')

ABOMSG:	ABOLEN,,.OMCAN			;.MSTYP - LENGTH,,CANCEL MSG
	0,,0				;.MSFLG - NO FLAG BITS
	-1				;.MSCOD - ACK CODE -1 IS $LOG
	0,,0				;.OFLAG - NO FLAG BITS
	0,,3				;.OARGC - 3 DATA BLOCKS
	4,,.OROBJ			;OBJECT BLOCK
	.OTBAT				;   BATCH QUEUE
ABOSTM:	0,,0				;   STREAM #
ABONOD:	0,,0				;   NODE NAME
	2,,.CANTY			;CANCEL TYPE
	.CNERR				;   WITH ERROR PROCESSING
	5,,.ORREA			;CANCEL REASON
	ASCIZ/MOUNT request in 'No Operator Intervention' batch job is illegal/

	ABOLEN==.-ABOMSG		;MESSAGE LENGTH
	SUBTTL	BLDVSL - ROUTINE TO BREAK DOWN MOUNT MSG ENTRIES

	;CALL:	S1/ The Address of the Mount Msg Entry
	;
	;RET:	S1/ The VSL Address if Mount Entry was Valid

BLDVSL:	PUSHJ	P,.SAVE4		;SAVE P1 & P2 & P3 & P4 FOR A MINUTE
	MOVE	P3,S1			;SAVE THE MOUNT MSG ENTRY ADDR
	PUSHJ	P,VSLFND		;LOOK FOR ANOTHER VSL BY THE SAME VSN
	JUMPT	[MOVE	P2,S1		;FOUND ONE,,SAVE THE VSL ADDRESS
		 TLO	P2,400000	;MARK THIS VSL AS A DUPLICATE REQUEST
		 JRST	BLDV.3 ]	;AND CONTINUE
	MOVEI	S1,VSLLEN		;GET THE VSL LENGTH
	MOVEI	S2,TMPVSL		;GET THE TEMP VSL ADDRESS
	PUSHJ	P,.ZCHNK		;CLEAR THE TEMP VSL
	SETZM	VOLNBR			;CLEAR THE VOLUME-SET VOLUME COUNT
	SETZM	STRVOL			;AND THE STARTING VOLUME ID
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	PUSHJ	P,L%LAST		;POSITION TO THE END OF THE VSL
	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%LAST		;POSITION TO THE END OF THE LIST
	MOVEI	P2,TMPVSL		;POINT TO OUR TEMP VSL
	MOVX	S1,VS.OPR+VS.WAL+VS.ALC	;GET NOTIFY OPR+ALLOCATE WAIT BITS
	MOVEM	S1,.VSFLG(P2)		;SET THEM
	LOAD	S1,.MEHDR(P3),AR.TYP	;GET THE ENTRY TYPE
	MOVX	S2,%UNKN		;DEFAULT TO UNKNOWN
	CAXN	S1,.MNTTP		;IS THIS A TAPE MOUNT REQUEST ???
	MOVX	S2,%TAPE		;YES,,SAY SO
	CAXN	S1,.MNTST		;IS IT A STRUCTURE ???
	MOVX	S2,%DISK		;YES,,SAY SO
TOPS20<	CAXN	S1,.DSMST		;IS IT DISMOUNT STRUCTURE ???
	MOVX	S2,%DSMT >		;YES,,SAY SO
	STORE	S2,.VSFLG(P2),VS.TYP	;SAVE THE REQUEST TYPE
	LOAD	S1,.MEFLG(P3),ME%ALC	;GET THE ALLOCATE BIT
	STORE	S1,.VSFLG(P2),VS.UAL	;SET/CLEAR USER ALLOCATED
TOPS10<	MOVX	S1,DEFLBT		;GET THE DEFAULT LABEL TYPE
	STORE	S1,.VSFLG(P2),VS.LBT >	;AND SAVE IT
	MOVX	S1,VS.DPR		;[1164] GET DEFAULT PROTECTION BIT
	IORM	S1,.VSATR(P2)		;[1164] LITE IT IN ATTRIBUTE WORD
	AOS	S1,REQIDN##		;BUMP AND LOAD THE REQUEST COUNT
	MOVEM	S1,.VSRID(P2)		;SAVE IT FOR THIS VOLUME SET REQUEST
	MOVE	S1,G$NOW##		;GET THE CURRENT TIME
	MOVEM	S1,.VSCRE(P2)		;SAVE AS REQUEST CREATION TIME

	MOVE	P1,P3			;SAVE THE MSG ENTRY START ADDRESS
	ADDI	P1,.MEHSZ		;POINT TO THE FIRST MESSAGE BLOCK
	MOVE	P4,.MECNT(P3)		;GET THE VOLUME SET BLOCK COUNT IN P4
	SETZM	CATFLG			;INIT FLAG TO ALLOW CATALOG SEARCHES

BLDV.1:	LOAD	S1,ARG.HD(P1),AR.TYP	;GET THE BLOCK TYPE
	SKIPE	S1			;BLOCK TYPE CANT BE 0
	CAILE	S1,%MDMAX		;OR GREATER THEN DEFINE BLOCK TYPES
	PJRST	BLDV.4			;ELSE THATS AN ERROR !!!
	LOAD	S1,MDRDSP(S1)		;GET THE BLOCK PROCESSOR ADDRESS

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

BLDV.2:	PUSHJ	P,0(S1)			;GO PROCESS THE BLOCK
	JUMPF	BLDV.4			;NO GOOD,,THATS AN ERROR
	LOAD	S1,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	ADD	P1,S1			;POINT TO THE NEXT BLOCK
	SOJG	P4,BLDV.1		;CONTINUE THROUGH ALL VOL-SET BLOCKS
	MOVX	S1,TM%SCR		;BIT TO TEST
	TDNE	S1,.MEFLG(P3)		;/SCRATCH SPECIFIED?
	AOS	CATFLG			;DISALLOW CATALOG SEARCHES
	SKIPN	.VSVSN(P2)		;ANY VOL SET NAME SPECIFIED ???
	PJRST	E$IVN##			;NO,,THEN INVALID VOLUME SET NAME !!!
	MOVE	S1,P2			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,I$CUNK##		;CHECK FOR 'UNKNOWN' REQUEST TYPES
	CAIE	P2,TMPVSL		;POINTING TO TEMP VSL ???
	JRST	BLDV.3			;NO,,THEN ALLS OK

	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	MOVX	S2,VSLLEN		;GET THE VSL ENTRY LENGTH
	PUSHJ	P,L%CENT		;CREATE SPACE FOR THE VSL ENTRY
	MOVE	P2,S2			;SAVE THE NEW VSL ENTRY ADDRESS
	HRLI	S1,TMPVSL		;GET THE SOURCE VSL ADDRESS
	HRRI	S1,0(P2)		;GET THE DEST VSL ENTRY ADDRESS
	BLT	S1,VSLLEN-1(P2)		;COPY THE VSL OVER
	LOAD	S1,.VSFLG(P2),VS.TYP	;GET THE REQUEST TYPE
	CAXE	S1,%TAPE		;IS IT A TAPE REQUEST ???
	JRST	BLD.2A			;NO,,GEN A VOL BLOCK FOR THE REQUEST
	MOVE	S1,P2			;YES,,GET THE VSL ADDRESS
	PUSHJ	P,GENVOL		;GEN A SCRATCH VOL BLOCK
	MOVX	S1,TM%NEW+TM%SCR	;GET SCRATCH OR NEW STATUS BITS
	TDNE	S1,.MEFLG(P3)		;WAS /SCRATCH OR /NEW REQUESTED ???
	JRST	BLDV.3			;YES,,CONTINUE
	PUSHJ	P,E$RNS##		;UH OH,,A REEL ID IS REQUIRED !!!
	JRST	BLDV.4 			;RETURN THE ERROR !!!

BLD.2A:	HRROI	S1,.VSVSN(P2)		;POINT TO THE VOL SET NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	S1,S2			;SAVE THE VOLUME NAME IN S1
	MOVE	S2,P2			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,ADDVOL		;ADD A VOL BLOCK
	MOVEM	S1,.VSVOL(P2)		;LINK THE VOL TO THE VSL
	INCR	.VSCVL(P2),VS.CNT	;BUMP THE VOLUME COUNT

BLDV.3:	TDZA	P4,P4			;INDICATE A NORMAL RETURN
BLDV.4:	SETOM	P4			;INDICATE AN ERROR RETURN
	LOAD	S1,.MRCNT(AP),MR.LNK	;GET THE VSL LINK CODE
	STORE	S1,.VSLNK(P2),VS.LNK	;SET IT
	LOAD	S1,.MEFLG(P3),TM%WLK	;GET WRITE-LOCK BIT FROM REQUEST
	STORE	S1,.VSFLG(P2),VS.MWL	;SAVE IT FOR LATER
	LOAD	S1,.MEFLG(P3),TM%WEN	;GET WRITE-ENABLE BIT FROM REQUEST
	STORE	S1,.VSFLG(P2),VS.MWE	;SAVE IT FOR LATER
	JUMPN	P4,BLDV.5		;IF AN ERROR,,SKIP THIS

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	LOAD	P1,.VSFLG(P2),VS.TYP	;GET THE VSL TYPE
	JUMPN	P1,BLD.4B		;CONTINUE IF KNOWN TYPE
	MOVX	S1,VS.FDV		;BIT TO TEST
	TDNE	S1,.VSFLG(P2)		;FOREIGN (UNIT RECORD) DEVICE?
	JRST	BLD.4A			;THOSE ARE NEVER CATALOGED
	SKIPE	CATFLG			;OK TO SEARCH CATALOG?
	JRST	BLD.4B			;NO--USER SPEC'ED OUT THE VOLUME-SET
	HRRZ	S1,P2			;ELSE POINT TO VSL
	PUSHJ	P,V$GCAT##		;AND CHECK THE CATALOG
	JUMPF	BLD.4C			;IF NOT FOUND, THEN CAN'T DO DEFAULTING
	HRRZ	P2,S1			;ELSE THE VSL MIGHT HAVE BEEN EXTENDED
	JRST	BLD.4C			;DON'T OVERWRITE VSL AND VOL PARAMETERS
BLD.4A:	MOVX	S1,VS.ALC!VS.WAL	;CLEAR ALLOCATION BITS FOR
	ANDCAM	S1,.VSFLG(P2)		; FOREIGN (UNIT RECORD) DEVICES
BLD.4B:	CAXN	P1,%DISK		;IS IT A STRUCTURE ???
	PUSHJ	P,DEFDSK		;YES,,DEFAULT IT
	CAXN	P1,%TAPE		;IS IT A TAPE REQUEST ???
	PUSHJ	P,DEFTAP		;YES,,DELAULT IT
	CAXN	P1,%DTAP		;IS IT A DECTAPE REQUEST ?
	PUSHJ	P,DEFDTA		;YES - DEFAULT IT
	JUMPT	BLD.4C			;CONTINUE IF NO ERRORS
	MOVNI	P4,1			;ELSE FLAG THE ERROR
	JRST	BLDV.5			;AND FINISH UP
BLD.4C:	LOAD	S1,.MEFLG(P3),ME%ALC	;GET THE ALLOCATE/MOUNT BIT
	LOAD	S2,.VSFLG(P2),VS.ALC	;GET THE VOL SET STATE BIT
	AND	S1,S2			;PERFORM SOME MAGIC !!!
	STORE	S1,.VSFLG(P2),VS.ALC	;SET/CLEAR THE ALLOCATE/MOUNT BIT
	TLZE	P2,400000		;WAS THIS A DUPLICATE VOL SET REQUEST?
	JRST	[MOVE	S1,P2		;YES,,GET THE VSL ADDR IN S1
		 $RETT	]		;   AND RETURN NOW

	;Here to Link to MDR and VSL together and Update the request count

BLDV.5:	LOAD	S1,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	ADDI	S1,.MRVSL(AP)		;POINT TO THE CURRENT VSL ADDRESS
	MOVEM	P2,0(S1)		;LINK THE VSL TO THE MDR
	MOVEM	AP,.VSMDR(P2)		;LINK THE MDR TO THE VSL
	INCR	.MRCNT(AP),MR.CNT	;BUMP THE VSL COUNT BY 1
	MOVE	S1,P2			;GET THE VSL ADDRESS
	JUMPN	P4,.RETF		;NO GOOD,,RETURN NOW
	CAIE	P1,%TAPE		;IS THIS A TAPE MOUNT ???
	$RETT				;NO--JUST RETURN
	PUSHJ	P,CKTVOL		;CHECK OUT THE TAPE VOLUMES REQUESTED
	MOVE	S1,P2			;GET THE VSL ADDRESS BACK
	POPJ	P,			;RETURN GOOD OR BAD...
	SUBTTL	VSL DEFAULTING ROUTINES

DEFTAP:	MOVE	S1,.MEFLG(P3)		;GET THE REQUEST FLAG WORD
	MOVE	S2,.VSFLG(P2)		;GET OUR FLAG WORD
	TLNN	P2,400000		;IS THIS THE FIRST TIME AROUND ??
	TXO	S2,VS.WLK		;YES,,DEFAULT TO WRITE-LOCKED
	TXNE	S1,TM%SCR		;IS THIS A TEMP VOLUME SET ???
	TXO	S2,VS.SCR		;YES,,SAY SO
	TXNE	S1,TM%NEW		;IS THIS A NEW VOLUME SET ???
	TXO	S2,VS.NEW		;YES,,SAY SO
	TXNE	S1,TM%WEN+TM%SCR+TM%NEW	;WRITE ENABLED OR SCRATCH OR NEW ???
	TXZ	S2,VS.WLK		;YES,,MAKE IT WRITE ENABLED !!!
	TXNE	S1,TM%WLK		;ARE WE WRITE LOCKED ???
	TXO	S2,VS.WLK		;YES,,SAY SO
	MOVEM	S2,.VSFLG(P2)		;SAVE OUR FLAG WORD

TOPS10<	TLNE	P2,400000		;IS THIS A DUPLICATE MOUNT REQUEST ???
	$RETT				;YES,,CAN'T MODIFY THE ATTRIBUTES !!!!
	MOVE	S1,.VSATR(P2)		;GET THE REQUESTED ATTRIBUTES
	LOAD	S2,S1,VS.TRK		;GET THE REQUESTED TRACK TYPE
	SKIPN	S2			;SPECIFY ANY TRACK TYPE ???
	TXO	S1,FLD(DEFTRK,VS.TRK)+VS.DTK ;NO,,DEFAULT IT
	LOAD	S2,S1,VS.DEN		;GET THE REQUESTED DENSITY
	JUMPN	S2,DEFT.1		;IF SPECIFIED,,DO NOT DEFAULT
	LOAD	S2,S1,VS.TRK		;GET THE TRACK TYPE
	CAXN	S2,%TRK7		;IS IT A 7 TRACK REQUEST ???
	TXO	S1,FLD(DEF7TK,VS.DEN)+VS.DDN ;YES,,DEFAULT DENSITY
	CAXE	S2,%TRK7		;IS IT A 9 TRACK REQUEST ???
	TXO	S1,FLD(DEF9TK,VS.DEN)+VS.DDN ;YES,,DEFAULT DENSITY

DEFT.1:	MOVEM	S1,.VSATR(P2)		;SAVE THE ATTRIBUTES.

	LOAD	S1,.VSATR(P2),VS.DEN	;GET THE DENSITY STATUS CODE
	MOVE	S1,D$DEN(S1)		;CONVERT IT TO A BIT MASK
	LOAD	S2,.VSATR(P2),VS.TRK	;GET THE TRACK STATUS CODE
	SETZM	T1			;START AT THE TOP OF THE RESOURCE LIST
	PUSHJ	P,ANYTAP		;GET THE TAPE RESOURCE NUMBER
	JUMPF	E$NUA##			;NO,,RETURN 'NO UNITS AVAILABLE'
	STORE	S1,.VSATR(P2),VS.RSN	;SAVE THE REQUESTED DEVICE TYPE
> ;END TOPS10 CONDITIONAL
	$RETT				;RETURN

DEFDSK:
TOPS10<	MOVE	S1,.MEFLG(P3)		;GET THE REQUEST FLAG WORD
	MOVE	S2,.VSFLG(P2)		;GET OUR FLAG WORD
	TXZ	S2,VS.WLK!VS.PAS!VS.NOC!VS.ARD ;RESET BITS FROM MOUNT MESSAGE
	TXNE	S1,TM%WLK		;ARE WE WRITE LOCKED ???
	TXO	S2,VS.WLK		;YES,,SAY SO
	TXNE	S1,SM%PAS		;WANT IT IN PASSIVE HALF?
	TXO	S2,VS.PAS		;YES, LITE IT
	TXNE	S1,SM%NOC		;WANT NO-CREATE?
	TXO	S2,VS.NOC		;YES, LITE THAT
	TXNE	S1,SM%ARD		;WANT TO ALWAYS RECOMPUTE DISK USAGE?
	TXO	S2,VS.ARD		;YES
	TXNE	S1,SM%EXC		;WANT SINGLE ACCESS?
	TLNE	P2,400000		;IS THIS THE FIRST TIME AROUND ?
	SKIPA				;NOT /SINGLE OR MOUNTED AGAIN !
	TXO	S2,VS.SIN		;YES, SAY SO
	MOVEM	S2,.VSFLG(P2)		;SAVE FLAG WORD
> ;END TOPS10 CONDITIONAL
	$RETT				;RETURN

DEFDTA:
TOPS10<	LOAD	S1,.VSCVL(P2),VS.CNT	;GET VOLUME COUNT
	SOJN	S1,E$MRD##		;CAN ONLY HAVE ONE REEL PER VOL-SET
	MOVE	S1,.MEFLG(P3)		;GET THE REQUEST FLAG WORD
	MOVE	S2,.VSFLG(P2)		;GET OUR FLAG WORD
	TLNN	P2,400000		;IS THIS THE FIRST TIME AROUND ??
	TXO	S2,VS.WLK		;YES,,DEFAULT TO WRITE-LOCKED
	TXNE	S1,TM%SCR		;IS THIS A TEMP VOLUME SET ???
	TXO	S2,VS.SCR		;YES,,SAY SO
	TXNE	S1,TM%NEW		;IS THIS A NEW VOLUME SET ???
	TXO	S2,VS.NEW		;YES,,SAY SO
	TXNE	S1,TM%WEN+TM%SCR+TM%NEW	;WRITE ENABLED OR SCRATCH OR NEW ???
	TXZ	S2,VS.WLK		;YES,,MAKE IT WRITE ENABLED !!!
	TXNE	S1,TM%WLK		;ARE WE WRITE LOCKED ???
	TXO	S2,VS.WLK		;YES,,SAY SO
	MOVEM	S2,.VSFLG(P2)		;SAVE OUR FLAG WORD
	PUSHJ	P,DTARSN		;GET A DECTAPE RESOURCE
	JUMPF	E$NUA##			;NONE AVAILABLE
	STORE	S1,.VSATR(P2),VS.RSN	;SAVE
> ;END TOPS10 CONDITIONAL
	$RETT				;RETURN

	SUBTTL	MOUNT REQUEST BLOCK PROCESSOR ROUTINES

	;DENSITY BLOCK PROCESSOR

MNTDEN:	AOS	CATFLG			;DISALLOW CATALOG SEARCHES
TOPS10<	LOAD	S1,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	CAIE	S1,2			;MUST BE 2
	PJRST	E$IDE##			;Else bad density
	MOVE	S1,ARG.DA(P1)		;GET THE DENSITY
	JUMPL	S1,E$IDE		;CAN'T BE NEGATIVE
	CAXLE	S1,DENLEN		;CAN'T BE GREATER THEN TABLE LENGTH
	PJRST	E$IDE			;YES,,THATS AN ERROR
	STORE	S1,.VSATR(P2),VS.DEN	;STORE DENSITY INDEX
> ;END TOPS10 CONDITIONAL
	PJRST	CHKTAP			;MAKE SURE THIS WAS A TAPE REQUEST !!!

MNTPRT:
TOPS10<	LOAD	S1,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	CAIE	S1,2			;MUST BE 2
	$RETF				;ELSE BAD BLOCK
	MOVE	S1,ARG.DA(P1)		;GET THE PROTECTION
	CAIG	S1,777			;SEE IF WITHIN RANGE
	SKIPGE	S1			; .  .  .
	$RETF				;NO, RETURN FALSE
	STORE	S1,.VSATR(P2),VS.PRT	;STORE THE PROTECTION CODE
	MOVX	S1,VS.DPR		;[1164] GET DEFAULT PROTECTION BIT
	ANDCAM	S1,.VSATR(P2)		;[1164] TURN IT OFF
> ;END TOPS10 CONDITIONAL
	PJRST	CHKTAP			;MAKE SURE THIS WAS A TAPE REQUEST !!!


	;DRIVE TYPE BLOCK PROCESSOR

MNTDRV:	AOS	CATFLG			;DISALLOW CATALOG SEARCHES
	LOAD	S1,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	CAIE	S1,2			;MUST BE 2
	$RETF				;ELSE RETURN
	MOVE	S1,ARG.DA(P1)		;GET THE DRIVE TYPE
	MOVX	S2,%TRK9		;DEFAULT TO A 9 TRACK REQUEST
	CAXN	S1,.TMDR7		;IS IT A SEVEN TRACK REQUEST ???
	MOVX	S2,%TRK7		;YES,,SAY SO
	STORE	S2,.VSATR(P2),VS.TRK	;SAVE THE REQUEST TRACK TYPE
	PJRST	CHKTAP			;MAKE SURE THIS WAS A TAPE REQUEST !!!

	;LABEL TYPE BLOCK PROCESSOR

MNTLT:	AOS	CATFLG			;DISALLOW CATALOG SEARCHES
	LOAD	S1,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	CAIE	S1,2			;MUST BE 2
	PJRST	E$ILT##			;ELSE INVALID LABEL TYPE
	MOVE	S1,ARG.DA(P1)		;GET THE LABEL TYPE
	CAXL	S1,%TFMIN		;CHECK RANGE
	CAXLE	S1,%TFMAX		;MUST BE BETWEEN THE MIN AND MAX VALUES
	 PJRST	E$ILT##			;INVALID LABEL TYPE
	STORE	S1,.VSFLG(P2),VS.LBT	;AND SAVE IT
	CAXN	S1,%TFLBP		;DOES HE WANT BYPASS PROCESSING ???
	SKIPE	[NPRTBL]		;YES,,IS IT OK FOR ALL USERS ???
	PJRST	CHKTAP			;NOT BLP OR OK FOR ALL USERS,,WIN
	PUSHJ	P,A$WHEEL##		;IS HE PRIV'D ???
	JUMPF	E$PRB##			;NO,,TOO BAD !!!
	PJRST	CHKTAP			;MAKE SURE THIS WAS A TAPE REQUEST !!!

	;VOLUME SET NAME BLOCK PROCESSOR

MNTSET:	LOAD	S1,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	SUBI	S1,1			;SUBTRACT OFF THE HEADER LENGTH
	CAILE	S1,VSNLEN		;MUST BE LESS OR EQUAL VSNLEN
	PJRST	E$IVN##			;RETURN INVALID VOL SET NAME !

TOPS10<	HRROI	S1,ARG.DA(P1)		;GET THE SOURCE VOLUME SET NAME
	HRROI	S2,.VSVSN(P2)		;GET THE DESTINATION ADDRESS
	PUSHJ	P,STRVSN		;STORE IT
	JUMPF	.RETF			;RETURN IF INVALID VOL SET NAME
> ;End TOPS10 conditional

TOPS20<
SETVSN:	$TEXT	(<-1,,.VSVSN(P2)>,<^W/ARG.DA(P1)/^0>)  ;SIXBIT VSN TO ASCII
	MOVE	S2,ARG.DA(P1)		;Get SIXBIT VSN
> ;End TOPS20 conditional

	SKIPN	.VSLNM(P2)		;Do we have logical name?
	MOVEM	S2,.VSLNM(P2)		;No..store default
	$RETT				;RETURN

	;Here to make sure the request is a tape request

CHKTAP:	LOAD	S1,.VSFLG(P2),VS.TYP	;GET THE VOL SET TYPE
	CAXN	S1,%TAPE		;IS IT A TAPE REQUEST ???
	$RETT				;YES..ALL IS FINE
	CAXE	S1,%UNKN		;IS IT AN UNKNOWN REQUEST ???
	PJRST	E$ISA##			;NO,,Invalid structure attribute
	MOVX	S1,%TAPE		;GET 'TAPE' REQUEST TYPE
	STORE	S1,.VSFLG(P2),VS.TYP	;SET IT
	$RETT				;RETURN


	;Here to make sure the request is a disk request

CHKDSK:	LOAD	S1,.VSFLG(P2),VS.TYP	;GET THE VOL SET TYPE
	CAXN	S1,%DISK		;IS IT A DISK REQUEST??
	$RETT				;YES..ALL IS FINE
	CAXE	S1,%UNKN		;IS IT AN UNKNOWN REQUEST??
	PJRST	E$ITA##			;NO,,Invalid tape attribute
	MOVX	S1,%DISK		;GET 'DISK' REQUEST TYPE
	STORE	S1,.VSFLG(P2),VS.TYP	;SET IT
	$RETT				;RETURN

TOPS10 <

;STRVSN - Routine to validate and store Volume Set name

;Translates lower case to upper and checks to make sure
;that only characters "A-Z", "0-9" and "_" are included

;ACCEPTS	S1/ Pointer to source string
;		S2/ Pointer to destination address

;RETURNS TRUE	S1/ Sixbit equivalent of string or 0
;		S2/ Sixbit abbriviation of string

;RETURNS FALSE	E$IVN (Invalid Volume Set Name)

STRVSN:	$SAVE	<P1,P2>			;Save some AC's
	TLCE	S1,-1			;Make real pointers
	TLCN	S1,-1
	 HRLI	S1,(POINT 7)
	TLCE	S2,-1
	TLCN	S2,-1
	 HRLI	S2,(POINT 7)
	MOVE	P1,S1			;Copy source pointer
STRVS1:	ILDB	P2,P1			;Get a source byte
	CAIL	P2,"a"			;Lower case?
	SUBI	P2,"a"-"A"		;Yes..raise it
	CAIL	P2,"A"			;Alpha?
	CAILE	P2,"Z"
	 JRST	[CAIL	P2,"0"		;No..numeric?
		 CAILE	P2,"9"
		  JRST	[CAIE	P2,"-"	;No..hypen or null?
			 JUMPN	P2,E$IVN##
			 JRST	.+1]	;Yes..then store it
		 JRST	.+1]		;Store numeric
	IDPB	P2,S2			;Store the character
	JUMPN	P2,STRVS1		;Terminate after null
	$CALL	S%SIXB			;Get sixbit abbriv.
	LDB	S1,S1			;Get terminator
	SKIPN	S1			;Was it null?
	SKIPA	S1,S2			;Yes..return sixbit
	SETZM	S1			;No..return 0
	$RETT

> ;End TOPS10 conditional

	;LOGICAL NAME BLOCK PROCESSOR

MDRLNM:	LOAD	S1,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	CAIE	S1,2			;LENGTH MUST BE 2
	$RETF				;ELSE RETURN
	MOVE	S1,ARG.DA(P1)		;GET THE LOGICAL NAME
	MOVEM	S1,.VSLNM(P2)		;SAVE IT
	$RETT				;AND RETURN

	;STARTING VOLUME BLOCK PROCESSOR

MNTSTV:	LOAD	S2,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	MOVE	S1,ARG.DA(P1)		;GET THE FIRST DATA WORD
	CAIN	S2,2			;IS THE BLOCK LENGTH 2 ???
	JRST	MNTS.1			;YES,,GO PROCESS THIS FORMAT
	CAIE	S2,3			;OR IS THE BLOCK LENGTH 3 ???
	$RETF				;ELSE THATS AN ERROR
	SKIPE	ARG.DA(P1)		;THIS MUST BE NULL
	$RETF				;ELSE THATS AN ERROR
	MOVE	S1,ARG.DA+1(P1)		;GET THE SIXBIT STARTING VOLUME ID
MNTS.1:	MOVEM	S1,STRVOL		;SAVE IT HERE FOR A MINUTE
	CAIE	P2,TMPVSL		;ARE WE POINTING AT THE TEMP VSL ???
	PJRST	UPDSVL			;NO,,GO UPDATE STARTING VOLUME INFO
	PJRST	CHKTAP			;MAKE SURE THIS WAS A TAPE REQUEST !!!

	;REMARK BLOCK PROCESSOR

MNTRMK:	$SAVE	<P4>			;SAVE P4 FOR A MINUTE
	LOAD	P4,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	SUBI	P4,1			;GET THE TEXT LENGTH
	IMULI	P4,5			;GET THE LENGTH IN BYTES
	CAILE	P4,^D59			;WILL WE FIT ???
	MOVEI	P4,^D59			;NO,,MAKE IT FIT
	MOVEI	S1,ARG.DA(P1)		;POINT TO THE SOURCE TEXT
	HRLI	S1,(POINT 7,0)		;MAKE IT A BYTE POINTER
	MOVE	S2,[POINT 7,.VSREM(P2)] ;GET THE DESTINATION BYTE POINTER
MNTR.1:	ILDB	TF,S1			;GET A BYTE
	IDPB	TF,S2			;SAVE IT
	JUMPE	TF,.RETT		;END ON A NULL
	SOJG	P4,MNTR.1		;OR 59 CHARACTERS (WHICHEVER IS FIRST)
	$RETT				;AND RETURN

	;VOLUME LIST BLOCK PROCESSOR

MNTVOL:	AOS	CATFLG			;DISALLOW CATALOG SEARCHES
	CAIE	P2,TMPVSL		;MUST BE POINTING AT THE TEMP VSL !!!
	$RETF				;NO,,THATS AN ERROR
TOPS10<	LOAD	S1,.VSFLG(P2),VS.TYP	;GET THE REQUEST TYPE
	CAXN	S1,%DISK		;CAN'T BE A STRUCTURE
	PJRST	E$ISS##			;YES,,THATS AN ERROR
> ;END TOPS10 CONDITIONAL

	;WEED OUT DUPLICATE MSG VOLUME BLOCKS (only last one counts)

	MOVE	S1,P1			;GET THE VOL BLOCK HDR ADDR IN S!
	MOVE	S2,.MECNT(P3)		;GET THE REMAINING BLOCK CNT IN S2
MNTV.A:	LOAD	TF,ARG.HD(S1),AR.LEN	;GET THE BLOCK LENGTH
	ADD	S1,TF			;POINT TO THE NEXT MSG BLOCK
	LOAD	TF,ARG.HD(S1),AR.TYP	;GET ITS TYPE
	CAXE	TF,.TMVOL		;IF THE A TAPE VOLUME ???
	CAXN	TF,.SMALI		;OR IS IT A STRUCTURE VOLUME ???
	$RETT				;YES,,IGNORE THE CURRENT VOL BLOCK
	SOJG	S2,MNTV.A		;NO,,TRY NEXT MSG BLOCK

	LOAD	S2,ARG.HD(P1),AR.LEN	;GET THE BLOCK LENGTH
	SOJLE	S2,.RETF		;CANT BE 1 OR NEGATIVE !!!
	CAILE	S2,^D60			;MUST BE LESS THE 60 VOLUMES 
	$RETF				;ELSE THAT AN ERROR
	MOVEM	S2,VOLNBR		;SAVE THE VOLUME COUNT
	ADDI	S2,VSLLEN-1		;CALC THE VSL LENGTH
	MOVE	S1,VSLQUE		;GET THE VSL QUEUE ID
	PUSHJ	P,L%CENT		;CREATE SPACE FOR THE VSL ENTRY
	MOVE	P2,S2			;SAVE THE NEW VSL ADDRESS
	HRLI	S1,TMPVSL		;GET THE SOURCE VSL ADDRESS
	HRRI	S1,0(P2)		;GET THE DEST VSL ADDRESS
	BLT	S1,VSLLEN-1(P2)		;COPY THE PROTOTYPE VSL OVER
	MOVE	T1,VOLNBR		;GET THE VOLUME COUNT
	MOVEI	T2,.VSVOL(P2)		;POINT T2 AT THE VSL VOL ADDRESSES
	MOVEI	T3,ARG.DA(P1)		;POINT T3 AT THE VOLUME LIST

MNTV.B:	MOVE	S1,0(T3)		;PICK UP THE VOLUME NAME IN S1
	MOVE	S2,P2			;GET THE VSL POINTER IN S2
	PUSHJ	P,ADDVOL		;ADD A VOL BLOCK
	MOVEM	S1,0(T2)		;LINK THE VOL TO THE VSL
	INCR	.VSCVL(P2),VS.CNT	;BUMP THE VOLUME COUNT BY 1
	SKIPN	.VLNAM(S1)		;WAS IT VALID ???
	PJRST	E$VID##			;UH OH,,NULL VOLIDS ARE ILLEGAL !!!

MNTV.C:	AOS	T2			;POINT TO THE NEXT VSL VOLUME
	AOS	T3			;POINT TO THE NEXT MSG VOLUME
	SOJG	T1,MNTV.B		;CONTINUE TILL DONE

TOPS20<	SKIPN	.VSVSN(P2)		;ANY VOLUME SET NAME YET ???
	PUSHJ	P,SETVSN  >		;NO,,GEN ONE !!!

	SKIPE	S1,STRVOL		;CHECK AND LOAD THE STARTING VOLUME ID
	PJRST	UPDSVL			;SOMETHING THERE,,UPDATE STARTING VOLUME
	MOVX	S1,VS.REL		;GET REEL ID SPECIFIED FLAG
	IORM	S1,.VSFLG(P2)		;SET IT
	$RETT				;RETURN
SUBTTL	Count the number of requests needing a structure


; Count up the number of requests requiring a structure
; Call:	MOVE	S1, VOL block address
;	PUSHJ	P,D$NREQ
; On return, S1:= #requests
;
TOPS10	<				;MDA ONLY
D$NREQ::
CTNREQ:	$SAVE	<P1,P2,P3,P4>		;SAVE SOME ACS
	MOVE	P1,S1			;SAVE THE VOL BLK ADRS
	LOAD	P2,.VLOWN(P1),VL.CNT	;GET THE NUMBER OF REQUESTORS
	JUMPE	P2,NREQ.4		;NONE, SAY SO
	MOVNS	P2			;NEGATE IT
	MOVSS	P2			;TO LEFT HALF
	HRRI	P2,.VLVSL(P1)		;AIM AT THE LIST OF VSL POINTERS
	SETZ	P1,			;CLEAR COUNT OF USERS
NREQ.1:	MOVX	TF,VL.ASN		;GET THE 'MOUNTED' BIT
	TDNN	TF,0(P2)		;DOES THIS REQUESTOR (VSL) OWN IT?
	JRST	NREQ.3			;NO, TRY THE NEXT VSL
	MOVE	S1,0(P2)		;AIM AT THE VSL
	SKIPN	S1,.VSMDR(S1)		;BACK UP TO THE MDR
	PUSHJ	P,S..IMV		;OOPS!!
	MOVE	P4,S1			;SAVE THE MDR ADDRESS
	LOAD	S2,.MRJOB(P4),MR.JOB	;GET THE JOB NUMBER
	TXNE	S2,BA%JOB		;PSEUDO PROCESS ???
	AOS	P1			;COUNT IT
NREQ.3:	AOBJN	P2,NREQ.1		;CHECK ALL THE REQUESTORS
	SKIPA	S1,P1			;GET NUMBER OF REQUESTS
NREQ.4:	SETZ	S1,			;HERE IF NO REQUESTS
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL
	SUBTTL	BLDSTR - ROUTINE TO PIECE TOGETHER VOL BLKS AND MAKE A STRUCTURE

	;CALL:	S1/ The Structure Name we want 
	;	S2/ The Alias Name or 0
	;
	;RET:	True if a Structure Can be Built, False Otherwise

TOPS10 <
BLDSTR:	PUSHJ	P,.SAVE2		;SAVE P1 - P2
	SKIPN	S2			;IS S2 NULL ???
	MOVE	S2,S1			;MAKE THE ALIAS THE STRUCTURE NAME
	MOVE	P2,S2			;SAVE THE ALIAS FOR LATER
	MOVE	P1,S1			;SAVE THE STRUCTURE NAME
	PUSHJ	P,FNDISK		;FIND THE PRIMARY STR IN THE VOL QUEUE
	$RETIF				;RETURN IF NOT FOUND
	MOVE	P1,S1			;SAVE THE PRI STR VOL ADDRESS

BLDS.1:	SKIPN	.VLUCB(S1)		;IS THE VOLUME SPINNING ???
	$RETF				;NO
	SKIPN	S1,.VLNXT(S1)		;ANOTHER VOL IN THE STRUCTURE ?
	JRST	BLDS.2			;NO,,WE HAVE ALL THE REQUIRED VOLS !!!
	PUSHJ	P,FNDDSK		;YES,,GO FIND IT IN OUR DATA BASE
	JUMPT	BLDS.1			;FOUND IT,,GO CHECK IT OUT
	$RETF				;RETURN

BLDS.2:	LOAD	S1,.VLFLG(P1),VL.STA	;GET THE STRUCTURE STATUS BITS
	CAXN	S1,%STAMN		;IS IT MOUNTED ???
	$RETT				;YES,,RETURN
	MOVE	S1,P1			;GET PRIMARY VOL BLOCK ADDRESS
	PUSHJ	P,V$CREA##		;GENERATE A CATALOG ENTRY
	JUMPF	BLDS.3			;CAN'T DO IT
	DMOVE	S1,P1			;GET VOL ADDR AND ALIAS NAME
	SETZM	WRTLCK			;CLEAR WRITE-LOCKED FLAG
	SETZM	OSNFLG			;CLEAR OVERRIDE-SET-NUMBER FLAG
	PUSHJ	P,SNDBLD		;TELL PULSAR TO BUILD THE STRUCTURE
	$RETT				;AND RETURN

BLDS.3:	$WTO	(<Cannot mount structure ^W/P2/>,,,<$WTFLG(WT.SJI)>)
	MOVX	S1,VL.FRC		;[1217] STRUCTURE TRYING TO BE 'FORCED'
	TDNN	S1,.VLFLG(P1)		;[1217]   UP BY SOMEONE ??
	$RETF				;RETURN
	MOVE	S1,P1			;[1217] YES, BUT TOO BAD!!!
	MOVX	S2,.DMNCK		;[1217] GET /NOCHECK BIT
	PUSHJ	P,SNDDSM		;[1217] TELL PULSAR TO DISMOUNT STR
	$RETF				;[1217] RETURN FALSE
> ;END TOPS-10 CONDITIONAL
	SUBTTL	SNDBLD - ROUTINE TO LINK THE STR VOL BLKS AND SEND STR BUILD MSG
	;	SNDDSM - ROUTINE TO SEND DISMOUNT STR MSG AND DELETE VOL BLKS

	;CALL:	S1/ The Primary STR VOL Block Address
	;	S2/
	;		SNDBLD - The Structure Name
	;		SNDDSM - Any flag bits (.DMNCK)
	;
	;RET:	True Always

TOPS10	<
SNDDSM:	PUSHJ	P,.SAVE4		;SAVE ALL THE P'S
	MOVE	P3,S2			;SAVE THE FLAGS
	LOAD	S2,.VLNAM(S1)		;GET THE STRUCTURE NAME
	SETZB	TF,WRTLCK		;INDICATE 'SNDDSM' ENTRY POINT
	SETZM	OSNFLG			;CLEAR OVERRIDE-SET-NUMBER FLAG
	JRST	SNDB.0			;AND ENTER THE COMMON CODE

SNDBLD:	PUSHJ	P,.SAVE4		;SAVE ALL P AC'S
	SETOM	TF			;INDICATE 'SNDBLD' ENTRY POINT
	SETZ	P3,			;NO FLAGS
SNDB.0:	MOVE	P1,S1			;SAVE THE PRI STR VOL ADDRESS
	MOVE	P2,TF			;SAVE THE ENTRY POINT INDICATOR
	PUSH	P,S2			;SAVE THE STRUCTURE NAME 
	PUSHJ	P,M%GPAG		;GET A PAGE FOR IPCF
	MOVEM	S1,G$SAB##+SAB.MS	;SAVE ITS ADDRESS IN THE SAB
	MOVE	S2,[.OHDRS+1,,.QOBLD]	;DEFAULT TO BUILD STR MSG HEADER
	SKIPN	P2			;UNLESS WE ARE SENDING DISMOUNT MSG
	MOVE	S2,[.OHDRS+1,,.QODSM]	;   THEN GET THE DISMOUNT MESSAGE HDR
	MOVEM	S2,.MSTYP(S1)		;SAVE IT
	MOVEI	S2,2			;WE ARE PASSING 2 BLOCKS
	MOVEM	S2,.OARGC(S1)		;SO SET THE BLOCK COUNT IN THE MSG
	IORM	P3,.OFLAG(S1)		;LITE ANY FLAG BITS
	MOVEI	P3,.OHDRS(S1)		;POINT TO THE FIRST MSG BLOCK
	JUMPN	P2,SNDB.Y		;SKIP REQUEST COUNT STUFF IN MOUNTING
	PUSH	P,S1			;SAVE S1
	MOVEI	S1,(P1)			;GET VOL BLOCK ADDRESS
	PUSHJ	P,CTNREQ		;GET THE NUMBER OF REQUESTS NEEDING STR
	MOVE	S2,S1			;GET COUNT
	POP	P,S1			;RESTORE MESSAGE ADDRESS
	STORE	S2,.OFLAG(S1),.DMNRQ	;SAVE IN MESSAGE

SNDB.Y:	MOVE	S1,[ARG.DA+.BLDLN,,.BLDSN] ;GET THE BLOCK HEADER
	MOVEM	S1,ARG.HD(P3)		;SET IT UP
	POP	P,ARG.DA+.BLDNM(P3)	;INSERT THE ALIAS NAME (STRUCTURE NAME)
	SETZM	ARG.DA+.BLDOW(P3)	;NO OWNER YET !!!
	JUMPE	P2,SNDB.X		;DISMOUNT,,THEN SKIP OWNER ID
	MOVE	S1,.VLNAM(P1)		;MOUNT,,GET STRUCTURE NAME
	PUSHJ	P,V$STRG##		;CONVERT TO ASCIZ
	PUSHJ	P,V$FIND##		;GET THE CATALOG ENTRY ADDRESS
	JUMPF	SNDB.X			;NOT THERE,,OH WELL WE TRIED !!!
	MOVE	S1,.CQVUS(S1)		;GET THE OWNERS ID
	MOVEM	S1,ARG.DA+.BLDOW(P3)	;SAVE IN MESSAGE
SNDB.X:	MOVSI	S1,ARG.DA+.BLDLN	;GET THE BLOCK LENGTH
	ADDM	S1,@G$SAB##+SAB.MS	;ADD TO THE TOTAL MESSAGE LENGTH
	MOVEI	P3,ARG.DA+.BLDLN(P3)	;POINT TO NEXT MSG BLOCK
	MOVE	S1,[1,,.BLDUN]		;GET UNIT NAME(S) BLOCK HEADER
	MOVEM	S1,ARG.HD(P3)		;SAVE IT IN THE MESSAGE
	MOVE	S1,P1			;GET THE FIRST (PRI) VOL BLOCK ADDRESS
	MOVE	P4,P1			;MAKE THIS THE CURRENT VOLUME
	PUSH	P,P3			;SAVE THIS MSG BLOCK ADDRESS

SNDB.1:	MOVE	S2,.VLUCB(S1)		;GET THE UNIT WE ARE MOUNTED ON.
	LOAD	TF,.UCBST(S2),UC.WLK	;GET WRITE-LOCKED BIT
	IORM	TF,WRTLCK		;REMEMBER IT
	MOVX	TF,U1.FRC		;[1217] GET 'FORCED' MOUNT BIT FOR UCB
	ANDCAM	TF,.UCBS1(S2)		;[1217] CLEAR IT IN UCB.
	MOVE	S2,.UCBNM(S2)		;GET ITS SIXBIT NAME
	MOVEM	S2,ARG.DA(P3)		;SAVE IT IN THE MESSAGE

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	MOVE	S2,.VLVID(S1)		;GET THE HOME BLOCK ID
	MOVEM	S2,ARG.DA+1(P3)		;SAVE IT IN THE MESSAGE
	MOVEI	P3,2(P3)		;POINT TO THE NEXT UNIT ENTRY
	SKIPN	S1,.VLNXT(S1)		;GET THE NEXT VOLUME NAME
	JRST	SNDB.3			;NO MORE,,SEND THE MESSAGE OFF
;**;[1227] Change 1 line at SNDB.1+16L. /LWS
	PUSHJ	P,FNDVOL		;[1227] FIND IT IN OUR DATA BASE
	JUMPE	P2,SNDB.2		;DOING 'DISMOUNT',,SKIP VOL LINK CODE
	STORE	P4,.VLPTR(S1),VL.PRV	;LINK THE NEXT TO THE LAST
	STORE	S1,.VLPTR(P4),VL.NXT	;LINK THE LAST TO THE NEXT
SNDB.2:	MOVE	P4,S1			;MAKE THIS VOL THE CURRENT VOL BLOCK
	JRST	SNDB.1			;AND GO PROCESS THE NEW VOLUME BLK

SNDB.3:	POP	P,S1			;RESTORE OLD BLOCK ADDRESS
	SUBI	P3,0(S1)		;GET THE BLOCK LENGTH
	MOVSS	P3			;MOVE RIGHT TO LEFT
	ADDM	P3,@G$SAB##+SAB.MS	;BUMP TOTAL MESSAGE LENGTH
	ADDM	P3,ARG.HD(S1)		;AND BUMP THE MSG BLOCK LENGTH
	HRRZ	S1,G$SAB##+SAB.MS	;GET MESSAGE ADDRESS
	MOVX	S2,.MTWLK		;GET WRITE-LOCKED FLAG
	SKIPE	WRTLCK			;WANT TO SET IT?
	IORM	S2,.OFLAG(S1)		;YES
	MOVX	S2,.DMOSN		;GET OVERRIDE-SET-NUMBER FLAG
	SKIPE	OSNFLG			;WANT TO SET IT?
	IORM	S2,.OFLAG(S1)		;YES
	MOVX	S1,PAGSIZ		;GET THE PAGE LENGTH
	MOVEM	S1,G$SAB##+SAB.LN	;SAVE IT
	LOAD	TF,.VLFLG(P1),VL.FRC	;[1217] GET 'FORCED' MOUNT BIT
	SKIPE	P2			;[1217] ALWAYS SEND ON DISMOUNT
	JUMPN	TF,SNDB.4		;[1217] DON'T BOTHER PULSAR IF 'FORCED'
	PUSHJ	P,SNDLBR		;SEND THE MSG OFF TO THE TAPE LABELER
	$RETT				;AND RETURN
SNDB.4:	MOVE	S1,P1			;[1217] GET PRIMARY VOL ADDRESS
	SETZM	S2			;[1217] CLEAR S2
	PUSHJ	P,MNTA.0		;[1217] TELL OPR IT'S MOUNTED
	MOVX	S1,VL.FRC		;[1217] GET 'FORCED' MOUNT BIT
	ANDCAM	S1,.VLFLG(P1)		;[1217] DON'T NEED IT ANYMORE
	$RETT				;[1217] RETURN
>
	SUBTTL	ASLMSG - ROUTINE TO BUILD AN 'ADD STRUCTURE' MSG
	;	DSLMSG - ROUTINE TO BUILD A 'DELETE FROM SEARCH LIST' MSG

	;CALL:	S1/ The VSL Block Address
	;	S2/ The VOL Block Address
	;	AP/ The MDR adrs
	;
	;RET:	TRUE ALWAYS

TOPS10<	INTERN	D$DSLM			;MAKE IT GLOBAL

ASLMSG:	TDZA	TF,TF			;NO FLAG BITS IF ENTRY IS HERE
D$DSLM: MOVX	TF,ASL.RM+ASL.NRD+ASL.NQ;REMOVE STR + NO RECOMP + NO QTA CHECK
	SKIPA				;SKIP NEXT ENTRY POINT
DSLMSG:	MOVX	TF,ASL.RM		;GET THE 'REMOVE STRUCTURE' FLAG BIT
	PUSHJ	P,.SAVE2		;SAVE SOME ACS
	DMOVE	P1,S1			;SAVE ARGS
	MOVEM	TF,TMPVSL+.OFLAG	;SAVE THE ACTION BITS
	MOVE	TF,[.OHDRS+ARG.DA+.BLDLN,,.QOASL] ;GET MSG LENGTH,,MSG TYPE
	MOVEM	TF,TMPVSL		;SAVE IT IN THE MESSAGE
	SETZM	TMPVSL+.MSFLG		;NO FLAG BITS
	MOVEI	TF,1			;1 BLOCK
	MOVEM	TF,TMPVSL+.OARGC	;  IN THE MESSAGE
	MOVE	TF,[.BLDLN+1,,.BLDSN]	;GET THE BLOCK LENGTH,,BLOCK TYPE
	MOVEM	TF,TMPVSL+.OHDRS+ARG.HD ;SAVE IT IN THE MESSAGE
	MOVE	TF,.VLNAM(S2)		;GET THE STRUCTURE NAME
	MOVEM	TF,TMPVSL+.OHDRS+ARG.DA+.BLDNM ;SAVE IT IN THE MESSAGE
	MOVE	TF,.VSRID(S1)		;GET THE USERS REQUEST ID
	MOVEM	TF,TMPVSL+.MSCOD	;SAVE IT AS THE ACK CODE
	MOVE	TF,.MRUSR(AP)		;GET THE USERS PPN
	MOVEM	TF,TMPVSL+.OHDRS+ARG.DA+.BLDOW ;SAVE IT IN THE MESSAGE
	LOAD	TF,.MRJOB(AP),MD.PJB	;GET THE USERS JOB NUMBER
	IOR	TF,TMPVSL+.OFLAG	;KEEP THE REMOVAL BIT
	MOVE	S1,.VSFLG(P1)		;GET THE USERS FLAG BITS FROM THE VSL
	TXNE	S1,VS.PAS		;WANT TO BE PASSIVE?
	TXO	TF,ASL.PS		;YES, SAY SO
	TXNE	S1,VS.NOC		;WANT NO-CREATE?
	TXO	TF,ASL.NC		;YES, SAY THAT
	TXNE	S1,VS.WLK		;WANT IT WRITE-LOCKED?
	TXO	TF,ASL.WL		;SAY THAT
	TXNE	S1,VS.SIN		;WANT SINGLE ACCESS
	TXO	TF,ASL.SA		;SAY SO
	TXNE	S1,VS.ARD		;WANT TO ALWAYS RECONPUTE DISK USAGE?
	TXO	TF,ASL.AR		;YES
	MOVEM	TF,TMPVSL+.OFLAG	;SAVE IT IN THE MESSAGE
	MOVEI	TF,TMPVSL		;GET THE MESSAGE ADDRESS
	MOVEM	TF,G$SAB##+SAB.MS	;SAVE IT IN THE SAB
	LOAD	TF,TMPVSL+.MSTYP,MS.CNT	;GET THE MESSAGE LENGTH
	MOVEM	TF,G$SAB##+SAB.LN	;SAVE IT IN THE SAB
	DMOVE	S1,P1			;GET VSL AND VOL BLOCK ADDRESSES
	PUSHJ	P,AASSET		;SET VL.AAS IF NECESSARY
	PUSHJ	P,SNDLBR		;SEND THE MESSAGE OFF
	$RETT				;RETURN
; Set or clear VL.AAS bit.
; Call:	MOVE	S1, VSL block address
;	MOVE	S2, VOL block address
;	PUSHJ	 P,AASSET/ASSCLR
;
AASSET:	TDZA	TF,TF			;SETTING VL.AAS
AASCLR:	MOVEI	TF,1			;CLEARING VL.AAS
	PUSHJ	P,.SAVE2		;SAVE SOME ACS
	DMOVE	P1,S1			;SAVE VOL BLOCK ADDRESS
	LOAD	S1,.VLOWN(P2),VL.CNT	;GET REQUESTOR COUNT
	MOVNS	S1			;NEGATE IT
	HRLI	S1,.VLVSL(P2)		;POINT TO FIRST VSL
	MOVSS	S1			;BUILD AN AOBJN POINTER

AASX.1:	HRRZ	S2,(S1)			;GET A VSL ADDRESS
	CAME	S2,P1			;FOUND THE VSL?
	AOBJN	S1,AASX.1		;LOOP FOR TILL WE FIND A MATCH
	JUMPGE	S1,.POPJ		;AOBJN POINTER RAN OUT?
	MOVE	S2,(S1)			;GET FLAGS,,ADDR
	SKIPN	TF			;ALWAYS CLEAR BIT?
	TXNN	S2,VL.ASN		;BUT IS IT ASSIGNED?
	TXZA	S2,VL.AAS		;NO
	TXO	S2,VL.AAS		;YES - THEN LITE ALREADY ASSIGNED
	MOVEM	S2,(S1)			;REPLACE FLAGS,,ADDR
	POPJ	P,			;RETURN

> ;END TOPS10 CONDITIONAL
	SUBTTL	SCNVOL - ROUTINE TO FIND COMMON VOLUMES REQUESTS AND LINK THEM

	;CALL	S1/ The Volume Name in Sixbit
	;	S2/ The VSL Address
	;
	;RET:	S1/ The VOL Address

TOPS10 <
SCNVOL:	PUSHJ	P,.SAVE4		;SAVE THE P AC'S FOR A MINUTE
	STKVAR	<LENGTH>		;ALLOCATE SOME STORAGE FOR ENTRY LENGTH
	DMOVE	P1,S1			;SAVE THE VOLUME NAME AND VSL ADDRESS
	LOAD	P3,.VSFLG(P2),VS.TYP	;GET THE VOLUME TYPE

	MOVX	TF,FALSE		;MAKE FLAG AC FALSE
	CAIE	P3,%UNKN		;VOLUME UNKNOWN?
	CAIN	P3,%DISK		;OR A DISK?
	PUSHJ	P,FNDISK		;LOOK FOR A DISK
	JUMPT	SCNV.1			;CONTINUE IF FOUND
	CAIE	P3,%UNKN		;VOLUME UNKNOWN?
	CAIN	P3,%TAPE		;OR A MAGTAPE?
	PUSHJ	P,FNTAPX		;LOOK FOR A MAGTAPE
	JUMPT	SCNV.1			;CONTINUE IF FOUND
	CAIE	P3,%UNKN		;VOLUME UNKNOWN?
	CAIN	P3,%DTAP		;OR A DECTAPE?
	PUSHJ	P,FNDECT		;LOOK FOR A DECTAPE
	JUMPT	SCNV.1			;CONTINUE IF FOUND
	$RETF				;ELSE GIVE UP

SCNV.1:	STORE	P3,.VSFLG(P2),VS.TYP	;UPDATE INCASE CHANGED
	MOVE	P1,S1			;SAVE THE VOL BLOCK ADDRESS

	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%SIZE		;GET THIS ENTRY'S LENGTH
	MOVEM	S2,LENGTH		;SAVE THE ENTRY LENGTH FOR LATER
	SUBI	S2,VOLLEN-1		;GET THE TOTAL .VLVSL BLOCK LENGTH
	LOAD	S1,.VLOWN(P1),VL.CNT	;GET THE TOTAL ALLOCATED LENGTH
	CAIN	S1,0(S2)		;ARE THEY EQUAL ???
	JRST	SCNV.3			;YES,,WE NEED MORE ROOM !!!
	CAIL	S1,0(S2)		;IS ALLOCATED MORE THEN TOTAL ???
	STOPCD	(AMT,HALT,,<Allocated is more then total (vol .VLVSL blocks)>)
	ADDI	S1,.VLVSL(P1)		;GET THE NEXT BLOCK ADDRESS
	MOVEM	P2,0(S1)		;LINK THE VSL TO THE VOL
	INCR	.VLOWN(P1),VL.CNT	;BUMP THE REQUEST COUNT BY 1
	MOVE	S1,P1			;GET THE VOL ADDRESS IN S1
	$RETT				;AND RETURN

SCNV.3:	AOS	S2,LENGTH		;GET LENGTH+1 IN S2
	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	PUSHJ	P,L%CENT		;CREATE A NEW VOL ENTRY
	HRL	TF,P1			;GET THE OLD VOL ADDRESS
	HRR	TF,S2			;GET THE NEW VOL ADDRESS
	MOVE	S1,LENGTH		;GET THE ENTRY LENGTH
	ADDI	S1,-2(S2)		;GET VOL ENTRY END ADDRESS -1
	BLT	TF,0(S1)		;COPY OLD VOL TO NEW VOL
	LOAD	S1,.VLOWN(S2),VL.CNT	;GET THE REQUEST COUNT
	ADDI	S1,.VLVSL(S2)		;POINT TO VOL VSL ADDRESS
	MOVEM	P2,0(S1)		;LINK THE VOL TO THE VSL
	MOVE	P2,S2			;GET THE NEW VOL ADDRESS IN P2

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	MOVE	S1,VOLQUE		;GET THE VOLUME QUEUE ID
	MOVE	S2,P1			;GET THE OLD VOL ADDRESS IN S2
	PUSHJ	P,L%APOS		;POSITION TO THE OLD ENTRY
	PUSHJ	P,L%DENT		;DELETE THE OLD ENTRY

;IF A MULTIPLE VOL STRS LINK LIST EXISTS THREAD NEW VOL ENTRY INTO
;EXISTING FORWARD AND BACKWARDS LINKED LIST.

	LOAD	S1,.VLPTR(P2),VL.NXT	;GET THE SECONDARY VOL BLOCK ADDRESS
	SKIPE	S1			;NONE THERE,,SKIP
	STORE	P2,.VLPTR(S1),VL.PRV	;FOUND,,SAVE NEW VOL BLK ADDR AS PRIMARY

	LOAD	S1,.VLPTR(P2),VL.PRV	;CONNECT BACKWARDS VOL LINK
	SKIPE	S1			;NONE THERE,,SKIP
XYZZY:	STORE	P2,.VLPTR(S1),VL.NXT	;OF PREVIOUS VOL BLK

	;Now that we have deleted the old VOL entry and created a new one,
	;   we must go back through this volumes VSL chain and
	;   fixup the VSL's VOL pointer so that it now points to the new VOL
	;   entry instead of the old one.

	LOAD	P3,.VLOWN(P2),VL.CNT	;GET THE VSL COUNT FOR THIS VOL ENTRY
	MOVEI	S1,.VLVSL(P2)		;POINT S1 TO THE VSL ADDRESS LIST
SCNV.4:	MOVE	S2,0(S1)		;PICK UP A VSL ADDRESS IN S2
	LOAD	P4,.VSCVL(S2),VS.CNT	;GET THE VOL COUNT FOR THIS VSL IN P4
	MOVEI	S2,.VSVOL(S2)		;POINT TO THIS VSL'S VOL LIST
SCNV.5:	CAMN	P1,0(S2)		;WE ARE LOOKING FOR THE OLD VOL PTR
	JRST	SCNV.6			;FOUND IT,,CONTINUE ON
	AOS	S2			;POINT TO NEXT VOL POINTER
	SOJG	P4,SCNV.5		;CONTINUE TILL FOUND
	STOPCD	(VPF,HALT,,<Volume pointer not found>) ;NOT THERE,,DEEEEP TROUBLE !!
SCNV.6:	MOVEM	P2,0(S2)		;LINK VSL TO NEW VOL ENTRY
	AOS	S1			;POINT TO NEXT VSL ADDRESS
	SOJG	P3,SCNV.4		;CONTINUE THROUGH ALL VSL'S
	INCR	.VLOWN(P2),VL.CNT	;BUMP THE REQUEST COUNT BY 1 (FOR CURRENT)
	SKIPE	S1,.VLUCB(P2)		;CHECK AND LOAD THE UCB ADDRESS
	MOVEM	P2,.UCBVL(S1)		;FOUND IT,,RELINK IT TO THIS VOL ENTRY
	MOVE	S1,P2			;RETURN THE VOL POINTER IN S1
	$RETT				;AND RETURN
>

TOPS20 <
SCNVOL:	$RETF				;RETURNS FALSE ON THE -20
>

	SUBTTL	UPDSVL - UPDATE THE STARTING VOLUME FOR A VOLUME SET

	;CALL:	S1/ The Sixbit Volume name or the Volume number
	;
	;RET:	True Always

UPDSVL:	TLNE	S1,770000		;IS IT A SIXBIT ID ???
	JRST	UPDS.2			;YES,,GO PROCESS IT
	CAMLE	S1,VOLNBR		;MUST BE LESS OR EQUAL TO VOLUME COUNT
	$RETF				;NO,,OFFSET TOO GREAT - THATS AN ERROR
	SUBI	S1,1			;MAKE THE COUNT AN OFFSET
	STORE	S1,.VSCVL(P2),VS.OFF	;AND SET IT IN VSL
	$RETT				;RETURN

UPDS.2:	LOAD	T1,.VSCVL(P2),VS.CNT	;GET THE VOLUME COUNT
	MOVNS	T1			;MAKE IT NEGATIVE
	HRLZS	T1			;MOVE RIGHT TO LEFT
	HRRI	T1,.VSVOL(P2)		;POINT TO THE VOLUME LIST
	SETZM	T2			;START OFFSET OUT AT 0
UPDS.3:	MOVE	S2,0(T1)		;GET A VOLUME POINTER
	CAMN	S1,0(S2)		;DO WE MATCH - VOLUME FOR VOLUME ???
	JRST	[STORE  T2,.VSCVL(P2),VS.OFF	;YES,,SAVE THE VOLUME OFFSET
		 $RETT  ]		;AND RETURN
	AOS	T2			;BUMP OFFSET COUNT
	AOBJN	T1,UPDS.3		;CONTINUE THROUGH ALL VOLUMES
	$RETF				;NOT FOUND,,TOUGH BREAKEEEE

	SUBTTL	D$INID - Initialization done for tape handler

;This code is executed when the tape labeler send a message saying
; 'done with label initialization' for a particular drive
; This routine clear the UC.INI bit, and arranges to have the labels
; of the drive just freed up read.

TOPS10<
D$INID::PUSHJ	P,.SAVET		;[1164] SAVE T1-T4
	MOVX	S1,.ORREQ		;[1164] GET BLOCK TYPE TO LOOK FOR
	PUSHJ	P,A$FNDB##		;[1164] FIND IT
	SKIPF				;[1164] OLD PULSAR PERHAPS?
	SKIPA	T1,(S1)			;[1164] GET REQUEST ID
	MOVEI	T1,0			;[1164] ASSUME NO REQUEST-ID
	MOVX	S1,.RECDV		;GET THE BLOCK TYPE TO LOOK FOR
	PUSHJ	P,A$FNDB##		;FIND IT
	JUMPF	MISC.3			;CAN'T, SO COMPLAIN
	MOVE	S1,.RECDN(S1)		;GET THE SIXBIT DRIVE NAME
	PUSHJ	P,UCBFND		;GET THE DRIVE DATA BLOCK
	JUMPF	MISC.3			;CAN'T SO COMPLAIN ABOUT THAT
	MOVE	T2,S1			;[1164] SAVE UCB ADDRESS
	MOVE	S2,.UCBST(S1)		;GET THE STATUS BITS
	TXZN	S2,UC.INI		;DID WE THINK IT WAS INITING?
	$RETT				;NO, FORGET THE JUNK MAIL
	MOVEM	S2,.UCBST(S1)		;SAVE BITS WITHOUT UC.INI
	JUMPN	T1,DIND.1		;[1164] IF REQ ID THERE, IT'S REINIT
	$WTO	(<Volume initialization complete>,<Drive is available for use>,MDAOBJ,$WTFLG(WT.SJI))
	MOVE	S1,.UCBNM(S1)		;GET SIXBIT DRIVE NAME
	PJRST	SNDREC			;READ THE (NEW) LABELS

;[1164] Here when reinitialization complete (/NEW-VOLUME).
;[1164] T1 = Request-id, T2 = UCB address

DIND.1:	HRRZ	S1,T1			;[1164] GET RID WITHOUT POSSIBLE ERROR BIT
	PUSHJ	P,FNDVSL		;[1164] GO FIND THIS GUY'S VSL
	JUMPF	.RETT			;[1164] COULD HAVE BEEN CANCELLED
	MOVE	T3,S1			;[1164] SAVE VSL ADDR
	MOVE	S1,.VSVOL(T3)		;[1164] GET VOL BLOCK ADDR FOR 1ST VOL
	SKIPE	.VLUCB(S1)		;[1164] BARF IF VOL NOT MOUNTED
	CAME	T2,.VLUCB(S1)		;[1164] OR WRONG UCB
	STOPCD	(MWL,HALT,,<Missing or wrong VOL/UCB link>) ;[1164] PLEASE,,NO!!
	MOVX	S1,VS.INI		;[1164] GET REINIT-IN-PROGRESS BIT
	TDNN	S1,.VSFLG(T3)		;[1164] WAS IT LIT IN VSL?
	STOPCD	(NVC,HALT,,<NEW-VOLUME code not working>) ;[1164] @$##@#!!
	ANDCAM	S1,.VSFLG(T3)		;[1164] CLEAR BIT IN VSL FLAG WORD
	MOVE	S1,T3			;[1164] GET VSL ADDRESS
	PUSHJ	P,SETAWT		;[1164] SET STATUS TO 'WAITING'
	LOAD	S1,.MSFLG(M),AK.NAK	;[1164] GET NACK BIT
	JUMPN	S1,DIND.2		;[1164] JUMP IF PULSAR IS UPSET
	DMOVE	S1,T2			;[1164] GET S1 = UCB ADDR, S2 = VSL ADDR
	PUSHJ	P,REASSI		;[1164] REASSIGN DRIVE TO USER!
	JUMPF	.RETT			;[1164] RETURN IF REASSIGN FAILS
	MOVE	S1,T3			;[1164] GET VSL ADDR
	PJRST	ACKUSR			;[1164] TELL USER GOOD NEWS

;[1164] Here when operator said ABORT to PULSAR's WTOR to mount a tape

DIND.2:	$SAVE	<P4>			;[1164] SAVE P4
	MOVEI	P4,[ASCIZ\Operator aborted WTOR sent by tape labeler\] ;[1164]
	MOVE	S1,.VSVOL(T3)		;[1164] GET ADDRESS OF 1ST VOL BLOCK
	PUSHJ	P,VLBREA		;[1164] BREAK THE VOL/UCB LINK
	MOVE	S1,T3			;[1164] GET VSL ADDR
	PJRST	DELREQ			;[1164] GO DELETE REQUEST

;[1164] Set vol status to 'waiting' after reinit is done.
;
;	Call:	S1 = VSL address

SETAWT:	LOAD	S2,.VSCVL(S1),VS.CNT	;[1164] GET NUMBER OF VOLS IN THE VSN
	MOVNS	S2			;[1164] NEGATE IT
	HRLI	S2,.VSVOL(S1)		;[1164] GET ADDRESS OF FIRST VOL	PTR
	MOVSS	S2			;[1164] MAKE AN AOBJN POINTER
	MOVEI	TF,%STAWT		;[1164] STATUS CODE FOR 'WAITING'

SETA.1:	MOVE	S1,(S2)			;[1164] GET A VOL BLOCK ADDR
	STORE	TF,.VLFLG(S1),VL.STA	;[1164] RESET STATUS TO WAITING
	AOBJN	S2,SETA.1		;[1164] LOOP THROUGH ALL VOL BLOCKS
	$RETT				;[1164] RETURN

;These bits are defined so that flags can be traced from the point
; of lighting to the point of testing among various calls/levels

;Flag used to signify that a user's request has other volumes
; (already) mounted

	AF.OVL==1B0

;Flag used to signify that during resource removal, there are no
; other users of a 'high level' shared resource

	RF.RSN==RHMASK			;FIELD WHICH HOLDS THE RESOURCE #
	RF.OTU==1B0			;OTHER USERS OF A SHARED DISK DRIVE
> ;END TOPS10 CONDITIONAL
	SUBTTL	D$ALOC - ROUTINE TO PERFORM DEVICE ALLOCATION

	;CALL:	S1/ The VSL Address
	;	AP/ The MDR Address
	;
	;RET:	True if Allocation Wins, False Otherwise
	;
	;	If False is returned then...
	;
	;	S1/  0 if failed because deadlock detected
	;	S1/ -1 if failed because allocation deferred

TOPS10<
D$ALOC::PUSHJ	P,.SAVE4		;SAVE P1 - P4
	PUSHJ	P,.SAVET		;SAVE T1 - T4
	LOAD	P1,.VSLNK(S1),VS.LNK	;GET THE REQUEST LINK CODE
	LOAD	P2,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	MOVNS	P2			;NEGATE THE COUNT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.MRVSL(AP)		;CREATE VSL SEARCH AOBJN AC
	$SAVE	<M>			;PRESERVE WHATEVER IS IN M
	PUSHJ	P,SETSTK		;SETUP THE VSL, RSN STACK

ALOC.1:	MOVE	P3,0(P2)		;GET A VSL ADDRESS
	LOAD	S1,.VSLNK(P3),VS.LNK	;GET ITS LINK CODE
	CAME	P1,S1			;DO WE WANT THIS VSL ???
	JRST	ALOC.2			;NO,,SKIP IT
	LOAD	S1,.VSFLG(P3),VS.WAL	;IS THIS VSL AWATING ALLOCATION ???
	JUMPE	S1,ALOC.2		;NO,,THEN SKIP IT
	MOVE	S1,P3			;COPY VSL POINTER
	PUSHJ	P,VSLRSX		;GET ALL THE RSNS ONTO THE M STACK
	JUMPF	[SETOM S1		;CAN'T, SO RETURN -1
		$RETF ]			;MEANING DEFERRED ALLOCATION

ALOC.2:	AOBJN	P2,ALOC.1		;CHECK ALL VSL'S

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here to find the users 'B' matrix entry, and create one if not there

ALOC.3:	PUSHJ	P,D$BMTX		;FIND THE USERS ENTRY IN THE 'B' MATRIX
	JUMPT	ALOC.4			;FOUND IT,,CONTINUE
	MOVE	S1,BMATRX		;GET THE 'B' MATRIX ID
	PUSHJ	P,L%LAST		;POSITION TO THE END OF THE 'B' MATRIX
	MOVE	S1,BMATRX		;GET THE 'B' MATRIX ID
	MOVX	S2,SMALEN		;GET THE 'B' MATRIX LENGTH
	PUSHJ	P,L%CENT		;CREATE AN ENTRY FOR THE USER
	MOVE	BM,S2			;SAVE THE ENTRY ADDRESS
	MOVE	S1,CMATRX		;GET THE 'C' MATRIX ID
	PUSHJ	P,L%LAST		;POSITION TO THE END OF THE 'C' MATRIX
	MOVE	S1,CMATRX		;GET THE 'C' MATRIX ID
	MOVX	S2,SMALEN		;GET THE 'C' MATRIX LENGTH
	PUSHJ	P,L%CENT		;CREATE AN ENTRY FOR THE USER
	MOVE	CM,S2			;SAVE THE ENTRY ADDRESS
	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE USERS JOB NUMBER
	MOVEM	S1,.SMJOB(BM)		;SAVE IT IN THE 'B' MATRIX ENTRY
	MOVEM	S1,.SMJOB(CM)		;SAVE IT IN THE 'C' MATRIX ENTRY
	MOVEI	S1,1			;GET MAX RSN OFFSET OF 1
	STORE	S1,.SMFLG(BM),SM.CNT	;SET IT
	STORE	S1,.SMFLG(CM),SM.CNT	;HERE ALSO
	AOS	PROCNT			;BUMP THE PRECESS COUNT BY 1

	;Here to create a secondary 'B' Matrix entry for the user which
	;will be used in the deadlock avoidance check. The origional is ignored
	;until the return from the deadlock routine. If the routine returns
	;true, the origional is deleted, if false the secondary is deleted.

ALOC.4:	MOVE	S1,BMATRX		;GET THE 'B' MATRIX ID
	PUSHJ	P,L%RENT		;REMEMBER THE ORIGIONAL ENTRY
	PUSHJ	P,L%SIZE		;GET ITS LENGTH
	MOVE	P3,S2			;SAVE IT FOR A SECOND
	PUSHJ	P,L%CENT		;CREATE A NEW ENTRY
	MOVE	P2,S2			;SAVE ITS ADDRESS FOR A SECOND
	ADDI	P3,0(S2)		;CALC ENTRY END ADDRESS
	HRL	S2,BM			;GET SOURCE,,DESTINATION FOR BLT
	BLT	S2,-1(P3)		;COPY OLD ENTRY TO NEW ENTRY
	MOVX	S1,SM.IGN		;GET THE 'IGNORE' BIT
	IORM	S1,.SMFLG(BM)		;LITE IT FOR THE OLD ENTRY
	MOVE	BM,P2			;POINT TO NEW ENTRY

ALO.4A:	MOVE	T4,[IOWD MSGLN##,G$MSG]	;GET A QUEUE FOR VSL ADDRESSES
	PUSH	T4,[-1]			;SET END OF QUEUE INDICATOR


	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here to perform the actual device allocation ('B' Matrix Update)

ALOC.5:	POP	M,S1			;GET A RSN OFF THE Q
	POP	M,P2			;GET THE VSL ADDRESS OFF THE QUEUE
	CAMN	P2,[-1]			;ARE WE DONE ???
	JRST	ALOC.8			;YES,,GO FINISH UP
	PUSH	T4,P2			;QUEUE UP THE VSL ADDRESS
	LOAD	S1,S1,RF.RSN		;EXTRACT JUST THE RSN
	MOVE	S2,P2			;LOAD UP THE VSL ADDRESS
	PUSHJ	P,ADDBMA		;YES,,UPDATE THE RESOURCE COUNT
	JRST	ALOC.5			;   AND GO PROCESS THE NEXT VSL

	;Here to perform Deadlock Avoidance Check

ALOC.8:	PUSHJ	P,DEADLK		;CALL DEADLOCK AVOIDANCE CHECK
	JUMPT	ALOC.A			;WIN,,CONTINUE ON !!!

	;Here if Deadlock check fails, delete all current VSL's

ALOC.9:	POP	T4,S1			;GET A VSL ADDRESS
	MOVE	T3,S1			;[1173] SAVE VSL ADDRESS
	PUSHJ	P,SHUFFL		;SHUFFEL THIS GUYS ALLOCATION AROUND
	JUMPT	ALOC.A			;WIN,,IT SURE IS HARD BEING NICE !!!
	MOVE	S1,BMATRX		;GET THE 'B' MATRIX ID
	MOVE	S2,BM			;GET THE USERS CURRENT MATRIX ENTRY
	PUSHJ	P,L%APOS		;POSITION TO IT
	PUSHJ	P,L%DENT		;DELETE IT
	MOVE	S1,BMATRX		;GET THE 'B' MATRIX ID
	PUSHJ	P,L%PREM		;POSITION TO THE OLD ENTRY
	ZERO	.SMFLG(S2),SM.IGN	;CLEAR THE 'IGNORE' BIT
	$TEXT(<-1,,G$MSG>,<Volume set allocation failed - insufficient resources available^M^J^0>)
	SETOM	ERRACK			;THIS IS AN ERROR ACK
	MOVE	S1,T3			;[1173] GET VSL ADDRESS BACK
	SETZM	S2			;[1173] USE VSL ACK DATA
	PUSHJ	P,USRNOT		;TELL THE USER
	SETZM	S1			;RETURN ALLOCATION FAILED ERROR CODE
	$RETF				;RETURN NO GOOD !!!

	;Here if the Deadlock Check Wins

ALOC.A:	MOVE	S1,BMATRX		;GET THE 'B' MATRIX ID
	PUSHJ	P,L%PREM		;GET THE OLD USER ENTRY
	PUSHJ	P,L%DENT		;DELETE IT

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here to clear 'Waiting for Allocation' bits in the VSL's

ALOC.B:	POP	T4,S1			;GET THE VSL ADDRESS OFF THE QUEUE
	CAMN	S1,[-1]			;END OF THE QUEUE ???
	JRST	ALO.B0			;YES,,FINISH UP !!!
	ZERO	.VSFLG(S1),VS.WAL	;NO,,CLEAR THIS VSL'S WAITING BIT
	JRST	ALOC.B 			;AND GO GET ANOTHER

ALO.B0:	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE USERS JOB NUMBER
	TXNN	S1,BA%JOB		;IS IT AN INTERNAL REQUEST ???
	PJRST	USRACK			;NO,,RETURN ACKING THE USER

	INCR	.MRCNT(AP),MR.LNK	;YES,,GEN A NEW LINK CODE
	LOAD	P2,.MRCNT(AP),MR.LNK	;AND LOAD IT
	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE REQUEST NUMBER
	MOVNS	P1			;NEGATE IT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.MRVSL(AP)		;CREATE VSL SEARCH AOBJN AC

ALO.B1:	MOVE	S1,0(P1)		;GET A VSL ADDRESS
	LOAD	S2,.VSFLG(S1),VS.ALC	;JUST ALLOCATING ???
	SKIPN	S2			;YES,,SKIP THIS
	STORE	P2,.VSLNK(S1),VS.LNK	;NO,,LINK THIS VSL TO ALL OTHER MOUNTS
	AOBJN	P1,ALO.B1		;LOOK AT ALL VSL'S
	$RETT				;AND RETURN
> ;END TOPS10 CONDITIONAL
	SUBTTL	D$BMTX - ROUTINE TO FIND A USERS ENTRY IN THE 'B' MATRIX
	;	D$CMTX -    ""   ""  ""  "   ""    ""  ""  "" 'C'   ""

	;CALL:	AP/ The Users MDR Address
	;
	;RET:	BM/ The 'B' Matrix Entry Address if using D$BMTX entry point
	;	CM/ The 'C' Matrix Entry Address if using D$CMTX entry point

TOPS10<
D$BMTX::SKIPA	S1,BMATRX		;SKIP AND LOAD THE 'B' MATRIX ID
D$CMTX::MOVE	S1,CMATRX		;LOAD THE 'C' MATRIX ID
	PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A SECOND
	LOAD	P1,.MRJOB(AP),MR.JOB	;GET THE USERS JOB NUMBER
	MOVX	P2,SM.IGN		;GET 'IGNORE ENTRY' FLAG BIT
	PUSHJ	P,L%FIRST		;GET THE FIRST ENTRY
	SKIPA				;SKIP THE FIRST TIME THROUGH
BMTX.1:	PUSHJ	P,L%NEXT		;GET THE NEXT ENTRY
	JUMPF	.RETF			;NOT THERE,,RETURN NOT FOUND
	CAMN	P1,.SMJOB(S2)		;IS THIS THE ONE WE WANT ???
	TDNE	P2,.SMFLG(S2)		;YES, 'IGNORE THIS ONE' ???
	JRST	BMTX.1			;NOT OURS OR IGNORED,,TRY NEXT
	CAMN	S1,BMATRX		;WAS THIS A 'B' MATRIX SEARCH ???
	MOVE	BM,S2			;YES,,GET THE ENTRY ADDRESS IN BM
	CAMN	S1,CMATRX		;WAS THIS A 'C' MATRIX SEARCH ???
	MOVE	CM,S2			;YES,,GET THE ENTRY ADDRESS IN CM
	$RETT				;AND RETURN
> ;END TOPS10 CONDITIONAL
SUBTTL	Deadlock Avoidance -- DEADLK - Interface routine

	;CALL:	AMATRX/ The 'A' Matrix Address
	;	BMATRX/ The 'B' Matrix Link List ID
	;	CMATRX/ The 'C' Matrix Link List ID
	;
	;RET:	True Or False depending on the Deadlock Avoidance check

TOPS10	<
D$DLOK::				;MAKE IT GLOBAL

DEADLK:	SKIPN	G$DEAD##		;DEADLOCK AVOIDANCE CHECKING ENABLED ??
	$RETT				;NO,,ALWAYS WIN !!!
	$COUNT	(DEAD)			;COUNT NUMBER OF DEADLOCK CHECKS
	PUSHJ	P,D$DEAD		;PERFORM DEADLOCK AVOIDANCE
	$RETIT				;RETURN IF OK
	$COUNT	(DFAL)			;COUNT UP THE DEADLOCK FAILURES
	$RET				;PASS FAILURE ON BACK
SUBTTL	Deadlock Avoidance -- D$DEAD - Check for a deadlock


;Check the proposed allocations state to see whether or not it is safe.
;The basis for this algorithm is discussed in:
;
;	Habermann, A. N.  "Prevention of System Deadlocks."
;	_Communications_of_the_ACM_, 12, No. 7 (July 1969), 373-385.
;
;	Krakowiak, Sacha.  _Principles_of_Operating_Systems_.
;	Trans. David Beeson.  Cambridge: The MIT Press, 1988.
;
;	Call:	AMATRX/ Address of 'A' (resource) matrix
;		BMATRX/ 'B' matrix list name
;		CMATRX/ 'C' matrix list name
;		PROCNT/ Process count (length of 'B' and 'C' matrices)
;
;	Return:	TRUE	Proposed state is safe
;		FALSE	Proposed state presents a deadlock

D$DEAD::SKIPG	S1,PROCNT		;ANY PROCESSES?
	$RETT				;NO, CANNOT BE DEADLOCKED
	$SAVE	<T3,T4>			;QSRMDA DOESN'T SAVE THESE (!)
	MOVE	S2,AMATRX		;GET ADDRESS OF HEADER BLOCK
	LOAD	S2,.AMHDR(S2),AM.CNT	;GET NUMBER OF RESOURCES
	JUMPE	S2,.RETT		;NONE: WILL NEVER HAPPEN
	MOVEM	S2,ASIZE		;
	ADD	S1,S2			;ALLOCATE SPACE FOR SIX ARRAYS
	IMULI	S1,3			; (3*ASIZE + 3*PROCNT)
	PUSHJ	P,M%GMEM		;ALLOCATE CLEARED MEMORY
	MOVEM	S2,BHEAD		;ADDRESS OF 'B' MATRIX SM BLOCKS
	ADD	S2,PROCNT		;
	MOVEM	S2,CHEAD		;ADDRESS OF 'C' MATRIX SM BLOCKS
	ADD	S2,PROCNT		;
	MOVEM	S2,BFLAG		;ADDRESS OF PROCESS FLAGS
	ADD	S2,PROCNT		;
	MOVEM	S2,BRESN		;ADDRESS OF 'B' MATRIX RESOURCE COUNTS
	ADD	S2,ASIZE		;
	MOVEM	S2,CRESN		;ADDRESS OF 'C' MATRIX RESOURCE COUNTS
	ADD	S2,ASIZE		;
	MOVEM	S2,ATEMP		;ADDRESS OF 'A' MATRIX SCRATCH ARRAY
	PUSH	P,S1			;SAVE NUMBER OF WORDS OBTAINED
	PUSHJ	P,DEAD00		;DO THE REAL WORK
	EXCH	S1,(P)			;RESTORE NUMBER OF WORDS
	MOVE	S2,BHEAD		;RESTORE ADDRESS OF FIRST WORD
	PUSHJ	P,M%RMEM		;RETURN ALLOCATED MEMORY
	POP	P,TF			;RESTORE RESULT (SAFE/UNSAFE)
	POPJ	P,			;
;This routine performs the actual deadlock avoidance algorithm.

DEAD00:	PUSHJ	P,.SAVE2		;SAVE P1-P2


;For efficiency, create a vector of addresses for the columns.
;Initialize the .AMDLK field of the 'A' matrix, where the computations
;are done.  (No other fields are disturbed.)

	MOVE	S1,BMATRX		;GET LIST NAME FOR 'B' MATRIX
	MOVE	S2,BHEAD		;GET ADDRESS OF ARRAY
	PUSHJ	P,GTHEAD		;BUILD ARRAY OF ADDRESSES
	MOVE	S1,CMATRX		;GET LIST NAME FOR 'C' MATRIX
	MOVE	S2,CHEAD		;GET ADDRESS OF ARRAY
	PUSHJ	P,GTHEAD		;BUILD ARRAY OF ADDRESSES
	MOVE	T1,AMATRX		;GET ADDRESS OF HEADER BLOCK
	MOVE	T2,ASIZE		;GET NUMBER OF RESOURCES
DEAD11:	ADDI	T1,AMALEN		;GET ADDRESS OF NEXT AM BLOCK
	LOAD	S1,.AMCNT(T1),AM.AVA	;GET NUMBER OF UNITS AVAILABLE
	MOVEM	S1,.AMDLK(T1)		;
	SOJG	T2,DEAD11		;COPY ALL COUNTS


;Now that all the preliminaries are out of the way, do the work.

	SETZ	P1,			;INITIALIZE SEQUENCE NUMBER
DEAD21:	PUSHJ	P,GTNEXT		;GET NEXT CANDIDATE
	$RETIF				;ALL DONE: (RESULT IN S1)
	MOVEM	S1,P2			;SAVE PROCESS NUMBER
	ADD	S1,BHEAD		;GET ADDRESS OF SM BLOCK
	MOVE	S1,(S1)			;
	MOVE	S2,BRESN		;GET ADDRESS OF ARRAY TO FILL
	PUSHJ	P,GTCOLM		;FILL IN 'B' MATRIX COUNTS
	MOVE	S1,P2			;GET PROCESS NUMBER
	ADD	S1,CHEAD		;GET ADDRESS OF SM BLOCK
	MOVE	S1,(S1)			;
	MOVE	S2,CRESN		;GET ADDRESS OF ARRAY TO FILL
	PUSHJ	P,GTCOLM		;FILL IN 'C' MATRIX COUNTS
	MOVE	S1,P2			;GET PROCESS NUMBER
	PUSHJ	P,IFPLAY		;SEE IF THIS PROCESS IS PLAYABLE
	JUMPF	DEAD22			;NOT PLAYABLE: SET "TRIED" BIT
	MOVE	S1,P2			;GET PROCESS NUMBER
	PUSHJ	P,DOPLAY		;PLAY THIS PROCESS
	PUSHJ	P,CLTRY			;CLEAR ALL TRIED BITS 
	AOS	S1,P1			;INCREMENT SEQUENCE NUMBER
	TXO	S1,SM.PLY		;MARK PROCESS "PLAYED"
	TRNA				;
DEAD22:	MOVX	S1,SM.DLK		;MARK PROCESS "TRIED"
	ADD	P2,BFLAG		;GET ADDRESS OF FLAG WORD
	MOVEM	S1,(P2)			;MARK PROCESS
	JRST	DEAD21			;LOOK FOR ANOTHER PROCESS
SUBTTL	Deadlock Avoidance -- IFPLAY - See if process is playable


;See if a given process is playable.
;
;A process is playable if there are sufficient resources in the 'A'
;matrix to cover the outstanding allocation (difference between 
;allocated and owned) for all resources the process is requesting.
;
;Before performing the sufficiency check, see if the process is
;requesting sharable resources currently owned by some other process.
;If so, then the requisite low-level resources are removed from the
;outstanding allocation for this process.
;
;	Call:	S1/ Process number (zero to PROCNT minus one)
;		BHEAD/ Address of array of column headers
;		CHEAD/ Address of array of column headers
;		BRESN/ Address of array of resource counts for process
;		CRESN/ Address of array of resource counts for process
;		ATEMP/ Address of 'A' matrix scratch array
;		ASIZE/ Number of resources (length of 'A' matrix)
;		AMATRX/ Address of A (resource) matrix
;		PROCNT/ Process count (length of 'B' and 'C' matrices)
;
;	Return:	TRUE	Given process could play in this state.
;		FALSE	There are insufficient resources for it to play.

IFPLAY:	PUSHJ	P,.SAVE4		;SAVE P1-P4
	MOVEM	S1,P4			;SAVE PROCESS NUMBER
	SKIPG	P3,ASIZE		;GET MAXIMUM NUMBER OF RESOURCES
	JRST	.RETT			;ZERO: WILL NEVER HAPPEN
	MOVN	P3,P3			;BUILD AN AOBJN POINTER
	HRLZ	P3,P3			;
;Calculate the number of each resource that the process will need and
;store the result in the scratch vector.
;While doing this calculation, check for any high-level resources that
;need to be mapped into low-level resources.
;If the process needs any resources that aren't required by a 
;high-level-to-low-level mapping and if there aren't enough, quit.

	SETZ	T1,			;INITIALIZE SHARED RESOURCE FLAG
	MOVE	P1,P3			;COPY 'A' MATRIX AOBJN POINTER
	MOVE	P2,AMATRX		;GET ADDRESS OF 'A' MATRIX HEADER
IFPLA1:	ADDI	P2,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	MOVE	S1,BRESN		;POINT TO 'B' MATRIX ENTRY
	ADDI	S1,(P1)			;
	MOVE	S1,(S1)			;GET 'B' MATRIX RESOURCE COUNT
	MOVE	S2,CRESN		;POINT TO 'C' MATRIX ENTRY
	ADDI	S2,(P1)			;
	SUB	S1,(S2)			;CALCULATE THE NUMBER NEEDED
	SKIPGE	S1			;OWNS MORE THAN ALLOCATED?
	STOPCD	(OMA,HALT,,<Process owns more resources than it has allocated>)
	MOVE	S2,ATEMP		;POINT TO TEMPORARY ARRAY
	ADDI	S2,(P1)			;
	MOVEM	S1,(S2)			;SAVE THIS VALUE
	JUMPE	S1,IFPLA2		;ZERO: SIMPLE CASE
	LOAD	S2,.AMSTA(P2),AM.DVT	;GET DEVICE TYPE
	CAIN	S2,%HLR1		;IS IT A HIGH-LEVEL RESOURCE?
	AOJA	T1,IFPLA2		;YES, REMEMBER IT
	CAIE	S2,%LLR1		;IS IT A LOW-LEVEL RESOURCE?
	JRST	IFPLA2			;NO, SKIP THIS NEXT TEST
	CAMLE	S1,.AMDLK(P2)		;ASKING FOR TOO MUCH?
	$RETF				;YES, NOT ENOUGH RESOURCES
IFPLA2:	AOBJN	P1,IFPLA1		;CALCULATE FOR ALL RESOURCES
;If the process requires any non-permanent high-level resources that are
;in use by some yet-to-be-played process, then reduce this process'
;requirement of mapped low-level resources for each such sharable
;resource.

	JUMPE	T1,IFPLA5		;NO SHARED HIGH-LEVEL RESOURCES
	MOVE	P1,P3			;COPY 'A' MATRIX AOBJN POINTER
	MOVE	P2,AMATRX		;GET ADDRESS OF 'A' MATRIX HEADER
IFPLA3:	ADDI	P2,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	MOVE	S1,ATEMP		;POINT TO TEMPORARY ARRAY
	ADDI	S1,(P1)			;
	SKIPG	(S1)			;ANY OF THIS RESOURCE NEEDED?
	JRST	IFPLA4			;NO, TRY NEXT RESOURCE
	LOAD	S1,.AMSTA(P2),AM.DVT	;GET DEVICE TYPE
	CAIE	S1,%HLR1		;IS IT A HIGH-LEVEL RESOURCE?
	JRST	IFPLA4			;NO, TRY NEXT RESOURCE
	MOVX	S1,AM.PRR		;GET A BIT TO TEST WITH
	TDNE	S1,.AMNAM(P2)		;IS THIS A PERMANENT RESOURCE?
	JRST	IFPLA4			;YES, TRY NEXT RESOURCE
	MOVE	S1,P4			;COPY PROCESS NUMBER MINUS ONE
	HRRZ	S2,P1			;COPY RESOURCE NUMBER MINUS ONE
	PUSHJ	P,IFOTHR		;OTHER PROCESSES NEED IT?
	JUMPF	IFPLA4			;NO: TRY NEXT RESOURCE
	LOAD	S1,.AMNAM(P2),AM.NAM	;GET ADDRESS OF NAME STRING
	HRRZ	S2,P1			;COPY RESOURCE NUMBER MINUS ONE
	PUSHJ	P,UNMAP			;REMOVE LOWER-LEVEL RESOURCES
IFPLA4:	AOBJN	P1,IFPLA3		;CHECK ALL RESOURCES
IFPLA5:	


;Now, after the artificial reduction in the amount claimed (if any),
;see if there are enough resources in the 'A' matrix to add this process.

	MOVE	P1,P3			;COPY 'A' MATRIX AOBJN POINTER
	HRR	P1,ATEMP		;INCLUDE ADDRESS OF SCRATCH ARRAY
	MOVE	P2,AMATRX		;GET ADDRESS OF 'A' MATRIX HEADER
IFPLA6:	ADDI	P2,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	MOVE	S1,(P1)			;GET COUNT FROM SCRATCH ARRAY
	CAMG	S1,.AMDLK(P2)		;TOO MANY FOR THIS RESOURCE?
	AOBJN	P1,IFPLA6		;NO, SEARCH ALL ENTRIES
	JUMPL	P1,.RETF		;NEGATIVE: CANNOT ADD PROCESS
	$RETT				;
SUBTTL	Deadlock Avoidance -- DOPLAY - Play a process


;Play a process from the current sequence.
;
;Return all resources that the process currently owns to the resource
;pool.  If the process owns any high-level resources and there are
;unplayed owners of those resources, then the low-level resources 
;required by the high-level resources are not returned to the resource
;pool.
;
;	Call:	S1/ Process number (zero to PROCNT minus one)
;		BHEAD/ Address of array of column headers
;		CHEAD/ Address of array of column headers
;		CRESN/ Address of array of resource counts for process
;		ATEMP/ Address of 'A' matrix scratch array
;		ASIZE/ Number of resources (length of 'A' matrix)
;		AMATRX/ Address of A (resource) matrix
;		PROCNT/ Process count (length of 'B' and 'C' matrices)
;
;	Return:	TRUE	Always

DOPLAY:	PUSHJ	P,.SAVE4		;SAVE P1-P4
	MOVEM	S1,P4			;SAVE PROCESS NUMBER
	SKIPG	P3,ASIZE		;GET MAXIMUM NUMBER OF RESOURCES
	JRST	.RETT			;ZERO: WILL NEVER HAPPEN
	MOVN	P3,P3			;BUILD AN AOBJN POINTER
	HRLZ	P3,P3			;


;Give back most of what it owns.

	MOVE	T1,CRESN		;POINT TO 'C' MATRIX ENTRIES
	MOVE	T2,P3			;COPY 'A' MATRIX AOBJN POINTER
	HRR	T2,ATEMP		;INCLUDE ADDRESS OF SCRATCH ARRAY
DOPLA1:	MOVE	S1,(T1)			;GET A 'C' MATRIX COLUMN ENTRY
	MOVEM	S1,(T2)			;PUT IT IN SCRATCH ARRAY
	ADDI	T1,1			;POINT TO NEXT 'C' MATRIX ENTRY
	AOBJN	T2,DOPLA1		;COPY ALL ENTRIES
;Unmap lower-level resources required by non-permanent higher-level
;resources that this process is going to give up.

	MOVE	P1,P3			;COPY 'A' MATRIX AOBJN POINTER
	MOVE	P2,AMATRX		;GET ADDRESS OF 'A' MATRIX HEADER
DOPLA2:	ADDI	P2,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	MOVE	S1,ATEMP		;POINT TO TEMPORARY ARRAY
	ADDI	S1,(P1)			;
	SKIPG	(S1)			;ANY FOR THIS RESOURCE?
	JRST	DOPLA3			;NO, TRY NEXT RESOURCE
	LOAD	S1,.AMSTA(P2),AM.DVT	;GET DEVICE TYPE
	CAIE	S1,%HLR1		;IS IT A HIGH-LEVEL RESOURCE?
	JRST	DOPLA3			;NO, TRY NEXT RESOURCE
	MOVX	S1,AM.PRR		;GET A BIT TO TEST WITH
	TDNE	S1,.AMNAM(P2)		;IS THIS A PERMANENT RESOURCE?
	JRST	DOPLA3			;YES, TRY NEXT RESOURCE
	MOVE	S1,P4			;COPY PROCESS NUMBER MINUS ONE
	HRRZ	S2,P1			;COPY RESOURCE NUMBER MINUS ONE
	PUSHJ	P,IFOTHR		;OTHER PROCESSES NEED IT?
	JUMPF	DOPLA3			;NO: TRY NEXT RESOURCE
	LOAD	S1,.AMNAM(P2),AM.NAM	;GET ADDRESS OF NAME STRING
	HRRZ	S2,P1			;COPY RESOURCE NUMBER MINUS ONE
	PUSHJ	P,UNMAP			;REMOVE LOWER-LEVEL RESOURCES
DOPLA3:	AOBJN	P1,DOPLA2		;CHECK ALL RESOURCES


;Now, after the artificial reduction (if any), give back this process'
;resources.

	MOVE	P1,P3			;COPY 'A' MATRIX AOBJN POINTER
	HRR	P1,ATEMP		;INCLUDE ADDRESS OF SCRATCH ARRAY
	MOVE	P2,AMATRX		;GET ADDRESS OF 'A' MATRIX HEADER
DOPLA4:	ADDI	P2,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	MOVE	S1,(P1)			;GET COUNT FROM SCRATCH ARRAY
	ADDM	S1,.AMDLK(P2)		;ADD TO 'A' MATRIX COUNT
	AOBJN	P1,DOPLA4		;ADD ALL ENTRIES
	$RETT				;
SUBTTL	Deadlock Avoidance -- IFOTHR - Check for other owners


;See if any other unplayed process is requesting a given resource.
;
;	Call:	S1/ Process number (zero to PROCNT minus one)
;		S2/ Resource number (zero to ASIZE minus one)
;		BFLAG/ Address of process flags
;		CHEAD/ Address of array of column headers
;		PROCNT/ Process count (length of arrays)
;
;	Return:	TRUE	There are other unplayed owners.
;		FALSE	This process is the last owner.

IFOTHR:	DMOVE	T3,S1			;SAVE ARGUMENTS
	MOVX	T2,SM.PLY		;GET A BIT TO TEST WITH
	MOVN	T1,PROCNT		;BUILD AN AOBJN POINTER
	HRLZ	T1,T1			;
IFOTH1:	CAIN	T3,(T1)			;SAME PROCESS NUMBER?
	JRST	IFOTH2			;YES, LOOK FOR OTHER PROCESSES
	MOVE	S1,BFLAG		;GET ADDRESS OF PROCESS FLAGS
	ADDI	S1,(T1)			;
	TDNE	T2,(S1)			;PROCESS ALREADY BEEN PLAYED?
	JRST	IFOTH2			;YES, TRY NEXT PROCESS
	MOVE	S1,CHEAD		;GET ADDRESS OF 'C' MATRIX
	ADDI	S1,(T1)			;  SM BLOCK
	MOVE	S1,(S1)			;
	LOAD	S2,.SMFLG(S1),SM.CNT	;GET RESOURCE COUNT
	CAIGE	S2,1(T4)		;ENOUGH ROOM FOR THIS RESOURCE?
	JRST	IFOTH2			;NO, TRY NEXT PROCESS
	ADDI	S1,.SMRES+1(T4)		;CALCULATE ADDRESS OF COUNT
	SKIPE	(S1)			;DOES THIS PROCESS OWN IT?
	$RETT				;YES, RETURN TRUE
IFOTH2:	AOBJN	T1,IFOTH1		;CHECK ALL UNPLAYED PROCESSES
	$RETF				;END OF LIST: NONE FOUND
SUBTTL	Deadlock Avoidance -- UNMAP - Remove lower level resources


;Remove lower-level resources required by a given high-level resource.
;
;	Call:	S1/ Address of resource name string
;		S2/ Resource number (zero to ASIZE minus one)
;		ATEMP/ Address of 'A' matrix scratch array
;		ASIZE/ Number of resources (length of 'A' matrix)
;
;	Return:	TRUE	Always

UNMAP:	PUSHJ	P,.SAVE2		;SAVE P1-P2
	DMOVEM	S1,P1			;SAVE ARGUMENTS 
	PUSHJ	P,V$FIND##		;FIND VOLUME-SET IN CACHE
	JUMPF	UNMAP3			;CAN'T: FATAL ERROR
	MOVE	T2,.CQNVL(S1)		;GET NUMBER OF VOLUMES
	JUMPLE	T2,.RETT		;NONE: RETURN
	MOVEI	T1,.CQVSL(S1)		;POINT TO FIRST VOLUME BLOCK
UNMAP1:	SKIPLE	S1,.CQRSN(T1)		;GET VOLUME RESOURCE NUMBER
	CAMLE	S1,ASIZE		;RANGE CHECK THIS VALUE
	JRST	UNMAP2			;OUT OF RANGE: TRY NEXT ONE
	ADD	S1,ATEMP		;POINT TO SCRATCH ENTRY (+1)
	SOS	-1(S1)			;DECREMENT RESOURCE COUNT
UNMAP2:	ADDI	T1,.CQVLL		;POINT TO NEXT VOLUME BLOCK
	SOJG	T2,UNMAP1		;EXAMINE ALL VOLUME BLOCK ENTRIES
	$RETT				;
UNMAP3:	ADDI	P2,1			;GET REAL RESOURCE NUMBER
	STOPCD	(NCI,HALT,,<No Catalog information for resource>)
SUBTTL	Deadlock Avoidance -- GTHEAD - Get column headers


;Fill an array of column headers (addresses of SM blocks).
;
;	Call:	S1/ List name
;		S2/ Address of array of column headers
;		PROCNT/ Process count (length of array)
;
;	Return:	TRUE	Always

GTHEAD:	MOVE	T1,S2			;SAVE ADDRESS OF ARRAY
	SETZ	T2,			;INITIALIZE COUNTER
	MOVX	T3,SM.IGN		;GET A BIT TO TEST WITH
	PUSHJ	P,L%FIRST		;GET ADDRESS OF FIRST ENTRY
	SKIPA				;
GTHEA1:	PUSHJ	P,L%NEXT		;GET ADDRESS OF NEXT ENTRY
	JUMPF	GTHEA2			;CAN'T: SEE IF ARRAY IS FILLED
	TDNE	T3,.SMFLG(S2)		;IGNORE THIS ENTRY?
	JRST	GTHEA1			;YES, TRY NEXT ONE
	ADDI	T2,1			;INCREMENT COUNTER
	CAMLE	T2,PROCNT		;TOO MANY?
	JRST	GTHEA3			;YES, FATAL ERROR
	MOVEM	S2,(T1)			;SAVE ADDRESS OF ENTRY
	AOJA	T1,GTHEA1		;SAVE ADDRESSES OF ALL ENTRIES
GTHEA2:	CAMN	T2,PROCNT		;CORRECT NUMBER OF ENTRIES?
	$RETT				;YES, RETURN TRUE
GTHEA3:	STOPCD	(PCW,HALT,,<Process count (PROCNT) is wrong>)
SUBTTL	Deadlock Avoidance -- GTCOLM - Get column entries


;Fill an array of column entries.
;
;	Call:	S1/ Address of SM block
;		S2/ Address of array to fill
;		ASIZE/ Number of resources (length of array)
;
;	Return:	TRUE	Always

GTCOLM:	LOAD	T1,.SMFLG(S1),SM.CNT	;GET NUMBER OF RESOURCES
	JUMPE	T1,GTCOL2		;ZERO: SHOULD NEVER HAPPEN
	CAMLE	T1,ASIZE		;MORE THAN THE NUMBER DEFINED?
	MOVE	T1,ASIZE		;YES, (OLD 'B' OR 'C' MATRIX ENTRY)
	MOVN	TF,T1			;BUILD AN AOBJN POINTER
	HRLM	TF,S1			;
GTCOL1:	MOVE	TF,.SMRES+1(S1)		;GET A RESOURCE COUNT
	MOVEM	TF,(S2)			;PUT IT IN SCRATCH ARRAY
	ADDI	S2,1			;POINT TO NEXT ARRAY ADDRESS
	AOBJN	S1,GTCOL1		;COPY ALL RESOURCE COUNTS
GTCOL2:	SUB	T1,ASIZE		;GET NEGATIVE NUMBER MISSING
	JUMPGE	T1,.RETT		;ZERO: EVERY LAST ONE IS THERE
GTCOL3:	SETZM	(S2)			;UNDEFINED VALUES ARE ZERO
	ADDI	S2,1			;POINT TO NEXT ARRAY ADDRESS
	AOJL	T1,GTCOL3		;FILL IN REMAINDER OF ARRAY
	$RETT				;
SUBTTL	Deadlock Avoidance -- GTNEXT - Get next process to play


;Find the first process that has not been tried or played.
;If there are none left and all of the processes have been played in the
;sequence, then it is a safe sequence.
;
;	Call:	BFLAG/ Address of process flags
;		PROCNT/ Process count (length of array)
;
;	Return:	TRUE	S1/ Process number (zero to PROCNT minus one)
;		FALSE	All processes have been tried or played:
;			S1/ TRUE if all have been played (safe)

GTNEXT:	SETO	S1,			;ASSUME ALL HAVE BEEN PLAYED
	MOVN	S2,PROCNT		;BUILD AN AOBJN POINTER
	HRLZ	S2,S2			;
	HRR	S2,BFLAG		;
	MOVX	T1,SM.PLY!SM.DLK	;GET BITS TO TEST WITH
	MOVX	T2,SM.PLY		;
GTNEX1:	TDNN	T1,(S2)			;HAS IT BEEN TRIED OR PLAYED?
	JRST	GTNEX2			;NO, RETURN WITH THIS PROCESS
	TDNN	T2,(S2)			;HAS IT BEEN PLAYED?
	SETZ	S1,			;NO, SEQUENCE MAY BE UNSAFE
	AOBJN	S2,GTNEX1		;LOOK AT NEXT PROCESS
	$RETF				;NO MORE PROCESSES
GTNEX2:	HRRZ	S1,S2			;RETURN WITH PROCESS MINUS ONE
	SUB	S1,BFLAG		;
	$RETT				;
SUBTTL	Deadlock Avoidance -- CLTRY - Clear all tried bits


;Clear the tried bits for all processes.
;This allows those processes tried (but rejected) during a previous
;scan to be included in the next scan.
;
;	Call:	BFLAG/ Address of process flags
;		PROCNT/ Process count (length of array)
;
;	Return:	TRUE	Always

CLTRY:	MOVX	TF,SM.DLK		;GET BIT TO CLEAR
	MOVN	S1,PROCNT		;BUILD AN AOBJN POINTER
	HRLZ	S1,S1			;
	HRR	S1,BFLAG		;
CLTRY1:	ANDCAM	TF,(S1)			;CLEAR "TRIED" BIT
	AOBJN	S1,CLTRY1		;CLEAR ALL "TRIED" BITS
	$RETT				;
SUBTTL	Dump MDA Database -- D$DUMP - Dump all matrices


;Dump the 'A', 'B', and 'C' matrices.
;
;	Call:	
;
;	Return:	TRUE	Always

D$DUMP::$SAVE	<TF,S1,S2>		;SINCE THIS IS A DEBUGGING AID,
	PUSHJ	P,.SAVE4##		;  SAVE ALL REGISITERS


;Display the 'A' matrix.

	MOVE	P1,AMATRX		;GET ADDRESS OF HEADER BLOCK
	LOAD	P2,.AMHDR(P1),AM.CNT	;GET NUMBER OF RESOURCES
	SETZB	P3,P4			;INITIALIZE THESE COUNTERS
DUMP11:	ADDI	P1,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	LOAD	S1,.AMNAM(P1),AM.NAM	;GET ADDRESS OF NAME STRING
	JUMPE	S1,DUMP12		;NONE: IGNORE THIS ENTRY
	ADDI	P3,1			;UPDATE THE RESOURCE NUMBER
	$TEXT	(,<^D4/P3/ ^T/(S1)/^A>)	;TYPE RESOURCE NUMBER AND NAME
	ADDI	P4,1			;COUNT ITEMS ON THIS LINE
	CAIGE	P4,5			;MORE THAN THIS MANY?
	JRST	DUMP12			;NO, PUT MORE ON THIS LINE
	$TEXT	(,<>)			;TYPE A CRLF
	SETZ	P4,			;RESET THIS COUNTER
DUMP12:	SOJG	P2,DUMP11		;POSITIVE: MORE TO COME
	SKIPE	P4			;START OF A NEW LINE?
	$TEXT	(,<>)			;NO, TYPE A CRLF
	$TEXT	(,<>)			;TYPE AN EXTRA CRLF
;Display the resource numbers (starting with zero) as column headings.
;We start with zero because the portion of this routine that displays 
;the 'B' and 'C' matrices types the resource number in that position.

	MOVE	P3,AMATRX		;GET ADDRESS OF FIRST BLOCK
	LOAD	P4,.AMHDR(P3),AM.CNT	;GET NUMBER OF RESOURCES
	SETZ	S1,			;INITIALIZE RESOURCE NUMBER
DUMP21:	$TEXT	(,<^D4/S1/ ^A>)		;TYPE THE RESOURCE NUMBER
	CAMGE	S1,P4			;ARE WE FINISHED?
	AOJA	S1,DUMP21		;NO, TYPE ALL RESOURCE NUMBERS


;For each resource number, display the number of units available, the
;number of units allocated, and the number of units claimed (owned).

	$TEXT	(,<^M^J     ^A>)	;BEGIN A NEW LINE OF NUMBERS
	DMOVE	P1,P3			;REINITIALIZE ADDRESS AND COUNT
DUMP22:	ADDI	P1,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	LOAD	S1,.AMCNT(P1),AM.AVA	;GET NUMBER OF UNITS AVAILABLE
	$TEXT	(,<^D4/S1/ ^A>)		;TYPE THAT NUMBER
	SOJG	P2,DUMP22		;TYPE COUNT FOR ALL BLOCKS
	$TEXT	(,<^M^J     ^A>)	;BEGIN A NEW LINE OF NUMBERS
	DMOVE	P1,P3			;REINITIALIZE ADDRESS AND COUNT
DUMP23:	ADDI	P1,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	LOAD	S1,.AMCNT(P1),AM.ALO	;GET NUMBER OF UNITS ALLOCATED
	$TEXT	(,<^D4/S1/ ^A>)		;TYPE THAT NUMBER
	SOJG	P2,DUMP23		;TYPE COUNT FOR ALL BLOCKS
	$TEXT	(,<^M^J     ^A>)	;BEGIN A NEW LINE OF NUMBERS
	DMOVE	P1,P3			;REINITIALIZE ADDRESS AND COUNT
DUMP24:	ADDI	P1,AMALEN		;POINT TO NEXT 'A' MATRIX ENTRY
	LOAD	S1,.AMCNT(P1),AM.CLM	;GET NUMBER OF UNITS CLAIMED
	$TEXT	(,<^D4/S1/ ^A>)		;TYPE THAT NUMBER
	SOJG	P2,DUMP24		;TYPE COUNT FOR ALL BLOCKS
	$TEXT	(,<>)			;TYPE A CRLF
;Display the 'B' and 'C' matrices.

	MOVEI	P1,L%FIRST		;GET FIRST ENTRY IN 'B' MATRIX
	MOVEI	P2,L%FIRST		;GET FIRST ENTRY IN 'C' MATRIX
	SETZ	P3,			;INITIALIZE PROCESS NUMBER
DUMP31:	ADDI	P3,1			;INCREMENT PROCESS NUMBER
	$TEXT	(,<>)			;TYPE AN EXTRA CRLF


;Find a 'B' matrix entry.

	JUMPE	P1,DUMP33		;ZERO: ALREADY AT END-OF-LIST
DUMP32:	MOVE	S1,BMATRX		;
	PUSHJ	P,(P1)			;GET ADDRESS OF NEXT SM BLOCK
	JUMPF	DUMP34			;NO MORE: CHECK THE 'C' MATRIX
	MOVEI	P1,L%NEXT		;ONLY CALL L%FIRST ONCE
	MOVX	S1,SM.IGN		;
	TDNE	S1,.SMFLG(S2)		;IGNORE THIS ENTRY?
	JRST	DUMP32			;YES, GET ANOTHER ENTRY
	$TEXT	(,<^D3/P3/B ^A>)	;
	PUSHJ	P,DMPSM			;DUMP THE SM BLOCK


;Find a 'C' matrix entry.

	JUMPE	P2,DUMP31		;ZERO: ALREADY AT END-OF-LIST
DUMP33:	MOVE	S1,CMATRX		;
	PUSHJ	P,(P2)			;GET ADDRESS OF NEXT SM BLOCK
	JUMPF	DUMP35			;NO MORE: CHECK THE 'B' MATRIX
	MOVEI	P2,L%NEXT		;ONLY CALL L%FIRST ONCE
	MOVX	S1,SM.IGN		;
	TDNE	S1,.SMFLG(S2)		;IGNORE THIS ENTRY?
	JRST	DUMP33			;YES, GET ANOTHER ENTRY
	$TEXT	(,<^D3/P3/C ^A>)	;
	PUSHJ	P,DMPSM			;DUMP THE SM BLOCK
	JRST	DUMP31			;NEXT PROCESS NUMBER


DUMP34:	SETZ	P1,			;REACHED END OF 'B' MATRIX
	JUMPN	P2,DUMP33		;MORE IN 'C' MATRIX: CONTINUE
	$RETT				;
DUMP35:	SETZ	P2,			;REACHED END OF 'C' MATRIX
	JUMPN	P1,DUMP31		;MORE IN 'B' MATRIX: CONTINUE
	$RETT				;
SUBTTL	Dump MDA Database -- DMPSM - Dump an SM Block


;Dump an SM block (helper routine for D$DUMP).
;
;	Call:	S2/ Address of SM block
;		P4/ Number of resources (length of 'A' matrix)
;
;	Return:	TRUE	Always

DMPSM:	LOAD	S1,.SMFLG(S2),SM.CNT	;GET NUMBER OF RESOURCES
	JUMPE	S1,DMPSM2		;ZERO: SHOULD NEVER HAPPEN
	CAMLE	S1,P4			;MORE THAN THE NUMBER DEFINED?
	MOVE	S1,P4			;YES, (OLD 'B' OR 'C' MATRIX ENTRY)
	MOVN	S1,S1			;BUILD AN AOBJN POINTER
	HRLZ	S1,S1			;
	HRRI	S1,.SMRES+1(S2)		;CALCULATE ADDRESS OF COUNTERS
DMPSM1:	$TEXT	(,<^D4/(S1)/ ^A>)	;TYPE THE NUMBER CLAIMED
	AOBJN	S1,DMPSM1		;TYPE ALL COUNTERS IN SM BLOCK
	LOAD	S1,.SMFLG(S2),SM.CNT	;GET THE NUMBER OF RESOURCES
DMPSM2:	SUB	S1,P4			;GET NEGATIVE NUMBER MISSING
	JUMPGE	S1,DMPSM4		;ZERO: EVERY LAST ONE IS THERE
DMPSM3:	$TEXT	(,<   0 ^A>)		;UNDEFINED VALUES ARE ZERO
	AOJL	S1,DMPSM3		;TYPE SEVERAL EXTRA ZEROES
DMPSM4:	$TEXT	(,<>)			;FINISH WITH A CRLF
	$RETT				;
> ;END TOPS10 CONDITIONAL
	SUBTTL	D$DLCK - ROUTINE TO SET UP THE DEADLOCK AVOIDANCE CHECK

	;CALL:	S1/ The VSL Address
	;	AP/ The MDR Address
	;
	;RET:	True if Allocation Wins, False Otherwise

TOPS10<
D$DLCK::PUSHJ	P,.SAVE4		;SAVE P1 - P4
	PUSHJ	P,.SAVET		;SAVE T1 - T4
	MOVEM	S1,SAVVSL		;SAVE THE VSL FOR RETRIES

DLCK.A:	LOAD	P1,.VSLNK(S1),VS.LNK	;GET THE REQUEST LINK CODE
	LOAD	P2,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	MOVNS	P2			;NEGATE THE COUNT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.MRVSL(AP)		;CREATE VSL SEARCH AOBJN AC
	SETZM	P4			;CLEAR THE DEADLOCK CHECK FLAG
	$SAVE	<M>			;PRESERVE WHATEVER IS IN M
	PUSHJ	P,SETSTK		;SETUP THE VSL, RSN STACK
	MOVE	T4,[IOWD MSGLN##,G$MSG]	;GET A QUEUE FOR VSL ADDRESSES
	PUSH	T4,[-1]			;INDICATE 'END OF QUEUE'

DLCK.1:	MOVE	P3,0(P2)		;GET A VSL ADDRESS
	LOAD	S1,.VSLNK(P3),VS.LNK	;GET ITS LINK CODE
	MOVX	S2,VS.CLM		;GET THE 'RESOURCES CLAIMED' STATUS BIT
	CAMN	P1,S1			;DO WE WANT THIS VSL ???
	TDNE	S2,.VSFLG(P3)		;  AND IS HAS IT BEEN CLAIMED YET ???
	JRST	DLCK.3			;WRONG VSL OR CLAIMED,,SKIP IT
	MOVE	S1,P3			;COPY THE VSL ADRS
	PUSHJ	P,VSLRSN		;EXTRACT ALL RSNS FOR THIS VSL
	$RETIF				;RETURN IF NOT ENOUGH RESOURCES
	SETOM	P4			;SET THE DEADLOCK CHECK FLAG
	PUSH	T4,P3			;QUEUE UP THE VSL ADDRESS

DLCK.3:	AOBJN	P2,DLCK.1		;CHECK ALL VSL'S
	JUMPE	P4,.RETT		;NOTHING TO DO, SO RETURN NOW!

	;Here to find the users 'C' matrix entry

	PUSHJ	P,D$CMTX		;LOCATE THE USERS 'C' MATRIX ENTRY
	SKIPT				;IT MUST BE THERE !!!
	STOPCD	(CME,HALT,,<'C' matrix entry is missing>)

	;Here to perform 'A' & 'C' Matrix Updates

	;First, Create a duplicate 'A' matrix 

	MOVE	P4,AMATRX		;GET THE OLD 'A' MATRIX ADDRESS
	LOAD	S1,.AMHDR(P4),AM.LEN	;GET THE MATRIX LENGTH
	PUSHJ	P,M%GMEM		;GET A NEW' 'A' MATRIX 
	MOVEM	S2,AMATRX		;SAVE THE ADDRESS OF THE NEW MATRIX
	ADDI	S1,0(S2)		;CALC THE MATRIX END ADDRESS
	HRL	S2,P4			;GET SOURCE,,DEST FOR BLT
	BLT	S2,-1(S1)		;COPY OLD 'A' MATRIX TO NEW 'A' MATRIX

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Then, Create a duplicate 'C' matrix entry

	MOVE	S1,CMATRX		;GET THE 'C' MATRIX ID
	PUSHJ	P,L%RENT		;REMEMBER THE ORIGIONAL ENTRY
	PUSHJ	P,L%SIZE		;GET ITS LENGTH
	MOVE	P3,S2			;SAVE IT FOR A SECOND
	PUSHJ	P,L%CENT		;CREATE A NEW ENTRY
	MOVE	P2,S2			;SAVE ITS ADDRESS FOR A SECOND
	ADDI	P3,0(S2)		;CALC ENTRY END ADDRESS
	HRL	S2,CM			;GET SOURCE,,DESTINATION FOR BLT
	BLT	S2,-1(P3)		;COPY OLD ENTRY TO NEW ENTRY
	MOVX	S1,SM.IGN		;GET THE 'IGNORE' BIT
	IORM	S1,.SMFLG(CM)		;LITE IT FOR THE OLD ENTRY
	MOVE	CM,P2			;POINT TO NEW ENTRY

	;Here to Update the 'A' and 'C' matricies

DLCK.4:	POP	M,P1			;GET A RSN OFF THE QUEUE
	POP	M,P3			;GET THE VSL ADDRESS OFF THE QUEUE
	CAMN	P1,[-1]			;END OF THE QUEUE ???
	JRST	DLCK.5			;YES,,LETERRIP !!!
	LOAD	S1,P1,RF.RSN		;GET JUST THE RESOURCE NUMBER
	MOVE	S2,P3			;AIM AT THE VSL
	PUSHJ	P,ADDCMA		;UPDATE THE 'C' MATRIX
	LOAD	S1,P1,RF.RSN		;GET JUST THE RESOURCE NUMBER
	MOVE	S2,P3			;AIM AT THE VSL
	TXNN	P1,RF.OTU		;IF OTHER USERS, DON'T TAKE OUT DRIVES
	PUSHJ	P,ADDAMA		;UPDATE THE 'A' MATRIX
	JUMPT	DLCK.4			;WIN,,CONTINUE
	JRST	DLCK.7			;NO GOOD,,RETURN AN ERROR

	;Here to invoke the Deadlock Avoidance Routine

DLCK.5:	PUSHJ	P,DEADLK		;LETERRIP !!!
	JUMPF	DLCK.7			;NO GOOD,,FINISH UP !!!

	;Deadlock Check Wins,,delete the old 'A' Matrix and 'C' Matrix
	;Also Update the VS.CLM status bit for the VSL'S involved

	LOAD	S1,.AMHDR(P4),AM.LEN	;GET THE OLD 'A' MATRIX LENGTH
	MOVE	S2,P4			;GET THE OLD 'A' MATRIX ADDRESS
	PUSHJ	P,M%RMEM		;RETURN IT TO THE MEMORY MANAGER
	MOVE	S1,CMATRX		;GET THE 'C' MATRIX ID
	PUSHJ	P,L%PREM		;POSITION TO THE OLD ENTRY
	PUSHJ	P,L%DENT		;AND DELETE IT
	MOVX	S2,VS.CLM		;GET THE 'RESOURCES CLAIMED' STATUS BIT

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

DLC.5B:	POP	T4,S1			;GET A VSL ADDRESS OFF THE QUEUE
	CAMN	S1,[-1]			;END OF QUEUE ???
	$RETT				;YES,,RETURN OK...
	IORM	S2,.VSFLG(S1)		;LITE THE RESOURCES CLAIMED STATUS BIT
	JRST	DLC.5B			;AND GO TRY AGAIN

	;Here if an error occurs,,delete the new 'A' and 'C' Matricies

DLCK.7:	MOVE	S2,AMATRX		;GET THE NEW 'A' AMATRX ADDRESS
	MOVEM	P4,AMATRX		;RESTORE THE OLD 'A' MATRIX ADDRESS
	LOAD	S1,.AMHDR(S2),AM.LEN	;GET THE OLD 'A' MATRIX LENGTH
	PUSHJ	P,M%RMEM		;RETURN IT TO THE MEMORY MANAGER
	MOVE	S1,CMATRX		;GET THE 'C' MATRIX ID
	MOVE	S2,CM			;GET THE 'C' MATRIX ENTRY
	PUSHJ	P,L%APOS		;POSITION TO THE ENTRY
	PUSHJ	P,L%DENT		;AND DELETE IT
	MOVE	S1,CMATRX		;GET THE 'C' MATRIX ENTRY
	PUSHJ	P,L%PREM		;POSITION TO THE OLD 'C' ENTRY
	ZERO	.SMFLG(S2),SM.IGN	;CLEAR THE IGNORE BIT
	MOVE	S1,SAVVSL		;GET THE VSL ADDRESS
	PUSHJ	P,SHUFFL		;SHUFFLE THE RESOURCES AROUND
	JUMPF	.RETF			;NO GOOD SHUFFLING
	JRST	DLCK.A			;TRY AGAIN WITH NEW RESOURCES

SAVVSL:	BLOCK	1			;PLACE TO SAVE A VSL

> ;END TOPS10 CONDITIONAL
	SUBTTL	RETA%C - ROUTINE TO RETURN RESOURCES TO THE 'A' & 'C' MATRICIES

	;CALL:	S1/ The VSL Being Returned
	;
	;RET:	True Always

TOPS10<
RETA%C:	LOAD	TF,.VSFLG(S1),VS.CLM	;HAS THIS VSL CLAIMED ITS RESOURCES ???
	JUMPE	TF,.RETT		;NO,,NOTHING TO RETURN
	PUSHJ	P,.SAVE4		;SAVE P1 - P4 FOR A SECOND
	MOVE	P2,S1			;SAVE THE VSL ADDRESS
	PUSHJ	P,D$CMTX		;GET THE USERS 'C' MATRIX ADDRESS
	SKIPT				;IT ALSO MUST BE THERE !!!
	PUSHJ	P,S..CME		;NO,,UH OH !!!
	$SAVE	<M>			;PRESERVE WHATEVER IS IN M
	PUSHJ	P,SETSTK		;SETUP THE VSL, RSN STACK
	MOVE	S1,P2			;GET BACK VSL ADRS
	PUSHJ	P,VSLRSN		;GO GET THIS VSL'S RESOURCE NUMBERS
	SKIPT				;CHECK FOR ERRORS
	STOPCD	(RNR,HALT,,<Returning non-existant resource>)
	ZERO	.VSFLG(P2),VS.CLM	;CLEAR RESOURCE CLAIMED STATUS BIT

RETA.1:	POP	M,P1			;GET BACK RSN
	POP	M,0(M)			;THROW OUT VSL (COPY OF P2)
	CAMN	P1,[-1]			;TOP OF STACK?
	$RETT				;YES, ALL DONE
	LOAD	S1,P1,RF.RSN		;GET THE RSN IN S1
	MOVE	S2,P2			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,SUBCMA		;RETURN THE 'C' MATRIX RESOURCE
	TXNN	P1,RF.OTU		;ARE THERE OTHER USERS?
	PUSHJ	P,SUBAMA		;NO, RETURN THE 'A' MATRIX RESOURCE
	SKIPT				;'A' MATRIX NEGATIVE,,THATS ALL FOLKS !!
	STOPCD	(NAM,HALT,,<Negative 'A' matrix entry computed>) ;CNT CAN'T BE NEGATIVE
	JRST	RETA.1			;PROCESS THE NEXT VSL
> ;END TOPS10 CONDITIONAL

	SUBTTL	RETBMA - ROUTINE TO RETURN RESOURCES TO THE 'B' MATRIX

	;CALL:	S1/ The VSL Being Returned
	;
	;RET:	True Always

TOPS10<
RETBMA:	PUSHJ	P,.SAVE4		;SAVE P1 - P4 FOR A SECOND
	MOVE	P2,S1			;SAVE THE VSL ADDRESS
	PUSHJ	P,D$BMTX		;GET THE USERS 'B' MATRIX ADDRESS
	SKIPT				;IT ALSO MUST BE THERE !!!
	STOPCD	(BME,HALT,,<'B' matrix entry is missing>)
	$SAVE	<M>			;PRESERVE WHATEVER IS IN M
	PUSHJ	P,SETSTK		;SETUP THE VSL, RSN STACK
	MOVE	S1,P2			;RESTORE THE VSL ADDRESS
	PUSHJ	P,VSLRSX		;GO GET THIS VSL'S RESOURCE NUMBERS
	JUMPT	RETB.1			;CHECK FOR ERRORS
	PUSHJ	P,S..RNR		;RETURNING NON-EXISTANT RESOURCE

RETB.1:	POP	M,P1			;GET BACK RSN AND FLAGS
	POP	M,0(M)			;THROW OUT VSL ADRS (HAVE IN P2)
	CAMN	P1,[-1]			;TOP OF STACK?
	$RETT				;YES, ALL DONE!
	LOAD	S1,P1,RF.RSN		;GET RESOURCE NUMBER IN S1
	MOVE	S2,P2			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,SUBBMA		;RETURN THE 'B' MATRIX RSN
	JRST	RETB.1			;TRY THE NEXT ONE
> ;END TOPS10 CONDITIONAL
	SUBTTL	ADDBMA - ROUTINE  TO UPDATE A RESOURCE NUMBER FOR A USER
	;	ADDCMA -   ""     ""   ""   "   ""       ""    "" "  ""

	;CALL:	S1/ The Resource Number
	;	S2/ The VSL Address
	;	BM or CM/ The Matrix entry address

TOPS10<
ADDBMA:	PUSHJ	P,.SAVE3		;SAVE P1 - P3
	MOVE	P2,BM			;GET THE ENTRY ADDRESS
	MOVE	P3,BMATRX		;GET THE 'B' MATRIX ID
	JRST	UPDR.1			;MEET AT THE PASS !!!

ADDCMA:	PUSHJ	P,.SAVE3		;SAVE P1 - P3
	MOVE	P2,CM			;GET THE ENTRY ADDRESS
	MOVE	P3,CMATRX		;GET THE 'C' MATRIX ID

UPDR.1:	PUSHJ	P,GETADD		;GET ADDITIVE (S1 = RSN, S2 = VSL)

UPDR.3:	$SAVE	<S1,S2>			;SAVE THE RSN AND COUNT
	LOAD	P1,.SMFLG(P2),SM.CNT	;GET HIS RSN COUNT
	CAIG	S1,0(P1)		;DOES HE HAVE THIS RESOURCE YET ???
	JRST	UPDR.4			;YES,,JUST BUMP THE COUNT

	;Here to add space to the users 'B' matrix entry for the new RSN

	PUSH	P,S1			;SAVE THE RSN 
	PUSH	P,S2			;SAVE THE COUNT
	STORE	S1,.SMFLG(P2),SM.CNT	;SAVE THE NEW MAX RSN OFFSET
	SUB	S1,P1			;CALC NEEDED SPACE FOR NEW RSN
	MOVE	P1,S1			;SAVE IT HERE
	MOVE	S1,P3			;GET THE MATRIX ID
	MOVE	S2,P2			;GET THE ENTRY ADDRESS
	PUSHJ	P,L%APOS		;POSITION TO IT
	PUSHJ	P,L%SIZE		;GET THE ENTRY LENGTH
	PUSH	P,S2			;SAVE THE CURRENT LENGTH
	ADD	S2,P1			;EXTEND IT BY CORRECT AMOUNT
	PUSHJ	P,L%CENT		;CREATE A NEW ENTRY FOR THE USER
	POP	P,S1			;RESTORE THE OLD LENGTH
	ADD	S1,S2			;CALC BLT END ADDRESS
	MOVE	P1,S2			;GET 0,,DESTINATION
	HRL	P1,P2			;GET SOURCE,,DESTINATION FOR BLT
	BLT	P1,-1(S1)		;COPY OLD TO NEW
	EXCH	P2,S2			;GET NEW ENTRY ADDR IN P2, OLD IN S2
	MOVE	S1,P3			;GET THE MATRIX ID
	PUSHJ	P,L%APOS		;POSITION TO THE OLD ENTRY
	PUSHJ	P,L%DENT		;DELETE IT
	CAMN	P3,BMATRX		;IS THIS THE 'B' MATRIX ???
	MOVE	BM,P2			;YES,,SAVE THE NEW ENTRY ADDRESS
	CAMN	P3,CMATRX		;IS THIS THE 'C' MATRIX ???
	MOVE	CM,P2			;YES,,SAVE THE NEW ENTRY ADDRESS
	POP	P,S2			;RESTORE THE COUNT
	POP	P,S1			;RESTORE THE RSN OFFSET

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;Here to just update the RSN claim count for a user

UPDR.4:	ADDI	S1,.SMRES(P2)		;CALC RSN ENTRY ADDRESS
	ADDM	S2,0(S1)		;UPDATE THE MATRIX
	CAME	P2,BM			;ARE WE UPDATING THE 'B' MATRIX ???
	$RETT				;NO,,RETURN
	SUBI	S1,.SMRES(P2)		;YES,,GET THE RSN BACK
	IMULI	S1,AMALEN		;GET THE 'A' MATRIX ENTRY OFFSET
	ADD	S1,AMATRX		;GET THE ENTRY ADDRESS
	INCR	.AMCNT(S1),AM.ALO	;BUMP THE RSN ALLOCATION COUNT
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL
	SUBTTL	SUBCMA - ROUTINE TO RETURN RESOURCES TO THE 'C' MATRIX

	;CALL:	S1/ The RSN
	;	S2/ The VSL Address
	;
	;RET:	True  Always or not at all

TOPS10<
SUBCMA:	$SAVE	<S1,S2>			;SAVE S1 & S2 ACROSS THE CALL
	PUSH	P,S2			;SAVE THE VSL ADDRESS FOR A SECOND
	LOAD	S2,.SMFLG(CM),SM.CNT	;GET THE RSN COUNT
	CAIGE	S2,0(S1)		;RESOURCE NUMBER MUST BE IN RANGE
	STOPCD	(RMC,HALT,,<Resource number missing in 'C' matrix>)
	POP	P,S2			;RESTORE THE VSL ADDRESS
	PUSHJ	P,GETSUB		;CALC SUBTRACT QUANTITY
	ADDI	S1,.SMRES(CM)		;POINT TO THE RSN ENTRY
	ADDM	S2,0(S1)		;UPDATE THE MATRIX
	SKIPGE	0(S1)			;IF STILL VALID,,SKIP
	STOPCD	(NCM,HALT,,<Negative 'C' matrix entry computed>) ;CNT CAN'T BE NEGATIVE
	$RETT				;RETURN



	SUBTTL	SUBBMA - ROUTINE TO RETURN 'B' MATRIX RESOURCES


	;CALL:	S1/ The RSN
	;	S2/ The VSL Address
	;
	;RET:	True Always or not at all

SUBBMA:	$SAVE	<S1,S2>			;SAVE S1 & S2 ACROSS THE CALL
	PUSH	P,S2			;SAVE THE VSL ADDRESS FOR A SECOND
	LOAD	S2,.SMFLG(BM),SM.CNT	;GET THE RSN COUNT
	CAIGE	S2,0(S1)		;RESOURCE NUMBER MUST BE IN RANGE
	STOPCD	(RMB,HALT,,<Resource number missing in 'B' matrix>)
	POP	P,S2			;RESTORE THE VSL ADDRESS
	PUSHJ	P,GETSUB		;GET THE SUBTRACT QUANTITY
	ADDI	S1,.SMRES(BM)		;POINT TO THE RSN ENTRY
	ADDM	S2,0(S1)		;UPDATE THE MATRIX
	SKIPGE	0(S1)			;SKIP IF STILL VALID
	STOPCD	(NBM,HALT,,<Negative 'B' matrix entry computed>) ;CNT CAN'T BE NEGATIVE
	SUBI	S1,.SMRES(BM)		;YES,,GET THE RSN BACK
	IMULI	S1,AMALEN		;GET THE 'A' MATRIX ENTRY OFFSET
	ADD	S1,AMATRX		;GET THE ENTRY ADDRESS
	DECR	.AMCNT(S1),AM.ALO	;REDUCE THE RSN ALLOCATION COUNT
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL

	SUBTTL	ADDAMA - ROUTINE TO REMOVE 'A' MATRIX RESOURCES
	;	SUBAMA - ROUTINE TO RETURN 'A' MATRIX RESOURCES
	;	D$INCA - ROUTINE TO ADD 1 TO THE RESOURCE COUNT
	;	D$DECA - ROUTINE TO SUBTRACT 1 FROM THE RESOURCE COUNT

	;CALL:	S1/ The RSN to be Updated (if ADDAMA or SUBAMA)
	;	S2/ The VSL Address
	;
	;	S1/ The UCB Address (if D$INCA or D$DECA)
	;
	;RET:	False iff the Matrix Count goes Negative

TOPS10<
ADDAMA:	TDZA	TF,TF			;FLAG ADD ENTRY POINT
SUBAMA:	MOVEI	TF,1			;FLAG SUBTRACT ENTRY POINT
	$SAVE	<S1,S2,T1>		;SAVE S1 & S2 ACROSS THE CALL
	MOVE	T1,TF			;GET ENTRY POINT TYPE
	XCT	[PUSHJ P,GETADD
		 PUSHJ P,GETSUB](T1)	;GET ADD/SUBTRACT QUANTITY
	SETZM	T1			;INDICATE CLAIM ADJUSTMENT
	PUSHJ	P,ADJAMA		;UPDATE THE MATRIX FOR THIS RSN
	JUMPF	.RETF			;OVER QUOTA,,RETURN NOW
	$RETT				;ELSE RETURN OK

D$INCA::SKIPA	S2,[-1]			;GET RSN COUNT OF -1 AND SKIP
D$DECA::MOVEI	S2,1			;GET RSN COUNT OF 1
	$SAVE	<T1>			;SAVE T1
	SETOM	T1			;INDICATE NO CLAIM ADJUSTMENT
	LOAD	S1,.UCBST(S1),UC.RSN	;GET THE CURRENT RSN
	PUSHJ	P,ADJAMA		;UPDATE THE MATRIX FOR THIS RSN
	JUMPF	.RETF			;OVER QUOTA,,RETURN NOW
	$RETT				;ELSE RETURN OK
	SUBTTL	ADJAMA - ROUTINE TO ADJUST THE 'A' MATRIX

	;CALL:	S1/ The RSN
	;	S2/ The count
	;	T1/ 0 if claim adjustment wanted, -1 if not
	;
	;RET:	True if OK, False if over quota

ADJAMA:	IMULI	S1,AMALEN		;GET THE ENTRY OFFSET
	ADD	S1,AMATRX		;POINT TO THE ENTRY
	JUMPN	T1,ADJA.1		;NO CLAIM ADJUSTMENT,,SKIP THIS
	LOAD	TF,.AMCNT(S1),AM.CLM	;GET THE NUMBER CLAIMED
	ADDM	S2,TF			;ADD/SUBTRACT 1
	STORE	TF,.AMCNT(S1),AM.CLM	;AND SAVE THE RESULT
ADJA.1:	LOAD	TF,.AMCNT(S1),AM.AVA	;GET THE AVAILABLE COUNT
	MOVNS	S2			;REVERSE THE PROCESS
	ADDM	S2,TF			;ADD/SUBTRACT 1
	STORE	TF,.AMCNT(S1),AM.AVA	;AND SAVE THE RESULT
	TXNE	TF,SGNBIT		;IF FIELD SIGN BIT IS ON,, THEN
	$RETF				;   COUNT IS NEGATIVE SO RETURN FALSE
	$RETT				;ELSE RETURN OK

> ;END TOPS10 CONDITIONAL
	SUBTTL	VSLRSN - ROUTINE TO FIND A VSL'S RESOURCE NUMBERS

	;CALL:	S1/ The VSL Address
	;	M/  Stack pointer to RSN Queue
	;
	;RET:	FALSE if the disk VSL is not in the system catalog
	;	TRUE with the VSL & RSN pairs queued up

TOPS10<
VSLRSN:	TDZA	TF,TF			;INDICATE NORMAL ENTRY POINT
VSLRSX:	SETOM	TF			;INDICATE EXTENDED ENTRY POINT
	PUSHJ	P,.SAVE4		;SAVE P1 - P4
	MOVE	P1,S1			;SAVE VSL ADRS
	MOVE	P2,TF			;SAVE THE ENTRY POINT INDICATOR
	LOAD	S1,.VSFLG(S1),VS.TYP	;GET TYPE OF VOLUME SET
	JRST	@.+1(S1)		;DISPATCH
	EXP	.RETF			;%UNKN
	EXP	VSLMTA			;%TAPE
	EXP	VSLSTR			;%DISK
	EXP	VSLDTA			;%DTAP
;Here to queue up allocation for a tape VSL
;If the Extended entry point was used, we will also queue up
;the volume RSN's for all the volumes in the volume set.
VSLMTA:	LOAD	S1,.VSATR(P1),VS.RSN	;GET THE REQUESTED DEVICE TYPE
	JUMPE	S1,.RETF		;NEED A REAL RESOURCE NUMBER
	PUSH	M,P1			;QUEUE UP THE VSL
	PUSH	M,S1			;QUEUE UP THE DEVICE REQUIREMENTS
	JUMPN	P2,VSLMT1		;EXTENDED ENTRY,,QUEUE ALL VOL RSN'S

	;Queue the VSL's current volume RSN

;;	MOVX	S1,VS.ABO+VS.VSW	;GET ABORTED BY OPR + VOL SWITCH BITS
	MOVX	S1,VS.VSW		;GET VOL SWITCH BIT
	TDNE	S1,.VSFLG(P1)		;EITHER BIT ON ???
	$RETT				;YES,,DON'T QUEUE UP THE VOL RSN
	LOAD	S1,.VSCVL(P1),VS.OFF	;GET OFFSET TO CURRENT VOLUME
	ADDI	S1,.VSVOL(P1)		;POINT TO THE CURRENT VOL ADDRESS
	MOVE	S1,0(S1)		;GET THE VOL ADDRESS
	SKIPN	.VLNAM(S1)		;ANY VOLID SPECIFIED ???
	$RETT				;NO,,DON'T QUEUE ANYTHING UP !!!
	PUSHJ	P,D$TVRS		;YES,,GET THE VOLUME RSN
	PUSH	M,P1			;QUEUE UP THE VSL
	PUSH	M,S1			;QUEUE UP VOLUME RSN
	$RETT

	;Queue all the volumes in the volume set

VSLMT1:	LOAD	P2,.VSCVL(P1),VS.CNT	;GET THE VOLUME COUNT
	MOVNS	P2			;NEGATE IT
	MOVSS	P2			;MOVE RIGHT TO LEFT
	HRRI	P2,.VSVOL(P1)		;CREATE VOL AOBJN AC

VSLMT2:	MOVE	S1,0(P2)		;GET A VOLUME ADDRESS
	SKIPN	.VLNAM(S1)		;ANY VOLID SPECIFIED ???
	JRST	VSLMT3			;NO,,DON'T QUEUE ANYTHING UP !!!
	PUSHJ	P,D$TVRS		;YES,,CONVERT IT TO A RSN
	PUSH	M,P1			;QUEUE UP THE VSL
	PUSH	M,S1			;QUEUE UP THE VOLUME RSN

VSLMT3:	AOBJN	P2,VSLMT2		;CONTINUE FOR ALL VOLUMES
	$RETT				;AND RETURN
;Here to queue up allocation for a disk VSL
VSLSTR:	HRROI	S1,.VSVSN(P1)		;POINT TO THE ASCIZ VOL SET NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	S1,S2			;MOVE IT TO S1
	PUSH	P,S1			;SAVE STR NAME A SECOND
	PUSHJ	P,D$SRSN		;GET THE STRUCTURE RESOURCE NUMBER
	POP	P,TF			;GET BACK STR NAME
	PUSH	M,P1			;QUEUE UP THE VSL ADDRESS
	PUSH	M,S1			;QUEUE UP THE RESOURCE NUMBER
	IMULI	S1,AMALEN		;MAKE A MATRIX INDEX
	ADD	S1,AMATRX		;AIM AT CURRENT SLOT
	MOVX	S2,AM.PRR		;BIT TO TEST
	TDNE	S2,.AMNAM(S1)		;PERMANENT STRUCTURE?
	$RETT				;YES--DONE HERE
	LOAD	S1,.AMNAM(S1),AM.NAM	;GET ADDRESS OF RESOURCE NAME
	PUSHJ	P,V$FIND##		;REQUEST THE CATALOG ENTRY
	JUMPF	.POPJ			;NOT THERE,,IGNORE ALLOCATION FOR NOW
	MOVE	P2,S1			;SAVE CATALOG ADRS
	$CALL	S%SIXB			;CONVERT TO SIXBIT
	MOVE	S1,S2			;COPY RESULT
	PUSHJ	P,D$FNDV		;FIND THE PRIMARY VOL BLOCK
	PUSHJ	P,D$VOWN		;FIND THE OWNER
	SETZ	S1,			;ASSUME NO OTHER USERS
	SKIPF				;ASSUMPTION TRUE?
	MOVX	S1,RF.OTU		;NO, INDICATE OTHER USERS
	EXCH	S1,P2			;SAVE FLAG BIT, GET BACK STR NAME
	LOAD	P3,.CQNVL(S1)		;GET NUMBER OF DRIVES UNDER THIS STR
	MOVEI	P4,.CQVSL(S1)		;AIM AT DEVICE LIST PORTION
VSLST1:	MOVE	S1,.CQRSN(P4)		;GET THIS RESOURCE NUMBER
	PUSH	M,P1			;QUEUE UP THE VSL ADDRESS
	IOR	S1,P2			;LITE (PERHAPS) THE OTHER USER BIT
	PUSH	M,S1			;QUEUE UP THE CATALOG ENTRY ADDRESS
	ADDI	P4,.CQVLL		;STEP TO NEXT DRIVE
	SOJG	P3,VSLST1		;DO 'EM ALL
	$RETT				;DONE,,RETURN
;Here to queue up allocation for a DECtape VSL
VSLDTA:	LOAD	S1,.VSATR(P1),VS.RSN	;GET THE REQUESTED DEVICE TYPE
	JUMPE	S1,.RETF		;NEED A REAL RESOURCE NUMBER
	LOAD	TF,.VSCVL(P1),VS.CNT	;GET VOLUME COUNT
	SOJN	TF,.RETF		;CAN ONLY HAVE ONE REEL PER VOL-SET
	PUSH	M,P1			;QUEUE UP THE VSL
	PUSH	M,S1			;QUEUE UP THE DEVICE REQUIREMENTS

	;Queue the VSL's one and only volume RSN

	MOVEI	P2,.VSVOL(P1)		;POINT TO VOL BLOCK ADDRESS
	MOVE	S1,0(P2)		;GET A VOLUME ADDRESS
	SKIPN	.VLNAM(S1)		;ANY VOLID SPECIFIED ???
	$RETT				;NO
	PUSHJ	P,D$OVRS		;YES,,CONVERT IT TO A RSN
	PUSH	M,P1			;QUEUE UP THE VSL
	PUSH	M,S1			;QUEUE UP THE VOLUME RSN
	$RETT				;AND RETURN

> ;END TOPS10 CONDITIONAL
	SUBTTL	SETSTK - Setup a queue for VSL, RSN pairs

	;This routine sets up a queue so that all resource numbers for a
	; given VSL or group of VSLs can be stashed in one place.

TOPS10<
SETSTK:	MOVE	M,[IOWD RPDLEN,RSNPDL]	;AIM AT THE QUEUE
	PUSH	M,[-1]			;MARK THE END OF THE QUEUE
	PUSH	M,[-1]			;ONE MORE TIME !!!
	$RETT

RPDLEN==^D100*2				;SPACE FOR 100 VSL, RSN PAIRS
RSNPDL:	BLOCK	RPDLEN			;THE RSN STACK
> ;END TOPS10 CONDITIONAL
	SUBTTL	GETADD - ROUTINE TO CALC THE 'A', 'B', 'C' MATRIX ADD VALUE
	;	GETSUB - ROUTINE TO CALC THE 'A', 'B', 'C' MATRIX SUB VALUE


	;CALL:	S1/ The RSN
	;	S2/ The VSL Address whose resource is being updated or 0 if none
	;
	;RET:	S1/ The RSN
	;	S2/ The Additive or Subtractive Quantity


	;This routine returns a vslue in S2 which is then used in updating
	;The deadlock avoidance matricies. This value is determined as
	;follows: If the Resource Type is %STRC, and the VS.SIN
	;flag bit is lit, then return MAXRES in S2. If both of those
	;conditions are not met, then return 1 in S2. If the GETSUB entry
	;Point is used, Then the negative of those 2 values is returned.

TOPS10<
GETADD:	TDZA	TF,TF			;INDICATE 'GETADD' ENTRY POINT
GETSUB:	SETOM	TF			;INDICATE 'GETSUB' ENTRY POINT
	JUMPE	S2,[MOVEI  S2,1		;NO VSL ADDRESS,,GET A 1
		    SKIPE  TF		;WAS 'GETSUB' ENTRY POINT USED ???
		    MOVNS  S2		;YES,,NEGATE THE VALUE
		    $RETT  ]		;AND RETURN
	$SAVE	<S1,P1>			;SAVE S1 AND P1 FOR A SECOND
	IMULI	S1,AMALEN		;GET THE 'A' MATRIX OFFSET
	ADD	S1,AMATRX		;POINT TO THE 'A' MATRIX ENTRY
	LOAD	S1,.AMSTA(S1),AM.DVT	;GET THE RESOURCE TYPE
	LOAD	P1,.VSFLG(S2),VS.SIN	;GET THE 'SINGLE ACCESS' FLAG BIT
	MOVEI	S2,1			;DEFAULT TO A 1
	CAXN	S1,%STRC		;IS THIS A STRUCTURE RESOURCE ???
	SKIPN	P1			;YES,,AND IS SINGLE ACCESS REQUIRED ??
	SKIPA				;NOT A STR OR NOT SINGLE ACCESS,,SKIP
	MOVX	S2,MAXRES		;ELSE LOAD MAX RESOURCE COUNT
	SKIPE	TF			;WAS ENTRY POINT 'GETSUB' ???
	MOVNS	S2			;YES,,THEN NEGATE THE VALUE
	$RETT				;RETURN
> ;END TOPS10 CONDITIONAL

SUBTTL	MDA pseudo process routines -- D$PPRL - Delete an MDR


TOPS10<
D$PPRL::SKIPN	G$MDA##			;ARE WE RUNNING WITH MDA ???
	$RETT				;NO,,RETURN
	$SAVE	<AP,CM,BM>		;SAVE SOME AC'S
	SKIPE	AP,.QEMDR(S1)		;CHECK AND LOAD THE MDR ADDRESS
	PJRST	D$DMDR			;DELETE THE MDR FOR THIS REQUEST
	$RETT				;NONE,,RETURN
> ;END TOPS10 CONDITIONAL

TOPS20<
D$PPRL:	$RETT	>			;A NOOP ON THE -20

SUBTTL	MDA pseudo process routines -- D$PPRE - Reset a real process


D$PPRE::
TOPS10<	SKIPN	G$MDA##			;ARE WE RUNNING WITH MDA ???
	$RETT				;NO,,RETURN
	$SAVE	<P1,P2,P3,P4,AP,CM,BM>	;SAVE ALL THESE AC'S
	MOVE	P1,S1			;SAVE THE QE ADDRESS
	SKIPN	AP,.QEMDR(P1)		;CHECK AND LOAD THE MDR ADDRESS
	$RETT				;RETURN IF NONE...
	PUSHJ	P,D$BMTX		;LOCATE THE PROCESS 'B' MATRIX
	PUSHJ	P,D$CMTX		;LOCATE THE PROCESS 'C' MATRIX
	MOVE	S1,.QERID(P1)		;GET THE PROCESS REQUEST ID
	TXO	S1,BA%JOB		;CREATE THE PSEUDO JOB NUMBER
	STORE	S1,.MRJOB(AP),MR.JOB	;CONVERT THE MDR TO A PSEUDO PROCESS MDR
	STORE	S1,.QEJBN(P1),QE.BJN	;SAVE IT HERE ALSO
	MOVEM	S1,.SMJOB(BM)		;CONVERT THE 'B' MATRIX AND
	MOVEM	S1,.SMJOB(CM)		;CONVERT THE 'C' MATRIX
	SETZM	G$ACK##			;WE DON'T WANT AN ACK LATER !!!
	INCR	.MRCNT(AP),MR.LNK	;GEN A NEW LINK CODE
	LOAD	P3,.MRCNT(AP),MR.LNK	;  AND LOAD IT INTO P3
	LOAD	P4,.MRCNT(AP),MR.CNT	;GET THE VSL REQUEST COUNT
	MOVEI	P2,.MRVSL(AP)		;GET VSL LIST ADDRESS
	ADDI	P2,-1(P4)		;WORK FROM LAST VSL TO FIRST

PPRE.1:	MOVE	S1,0(P2)		;GET A VSL ADDRESS
	MOVE	P1,.VSFLG(S1)		;SAVE THE VOL SET FLAG BITS
	PUSHJ	P,D$ALCV		;RETURN THIS VSL'S ALLOCATION
	MOVE	S1,0(P2)		;GET THE VSL ADDRESS BACK
	TXNE	P1,VS.UAL		;DID THE USER ALLOCATE THIS VSL ???
	TXNE	P1,VS.ALC		;YES,,DID HE HAVE IT MOUNTED ???
	JRST	PPRE.2			;NOT USER ALLOC OR NOT MOUNTED,,SKIP
	ZERO	.VSFLG(S1),VS.ALC	;WANT THIS REMOUNTED !!
	STORE	P3,.VSLNK(S1),VS.LNK	;RESET TO A COMMON LINK CODE

PPRE.2:	SUBI	P2,1			;GET NEXT VSL ADDRESS
	SOJG	P4,PPRE.1		;CONTINUE FOR ALL VSL'S
	MOVE	S1,.MRQEA(AP)		;GET THE QE ADDRESS
	MOVX	S2,QE.WAM+QE.ALR	;GET 'ALLOCATION PRE-SCAN' BITS
	ANDCAM	S2,.QESEQ(S1)		;CLEAR THEM
	MOVX	S2,QE.WAL		;FORCE ANOTHER PRE-SCAN BY
	IORM	S2,.QESEQ(S1)		;  LIGHTING THIS BIT
> ;END TOPS10 CONDITIONAL
	$RETT				;AND RETURN
SUBTTL	MDA pseudo process routines -- D$PMDR - Find a process


	;CALL:	No Args
	;
	;RET:	True Always

TOPS10<
D$PMDR::SKIPN	G$MDA##			;ARE WE RUNNING WITH MDA ???
	$RETT				;NO,,RETURN
	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST ENTRY
	JRST	PMDR.2			;JUMP THE FIRST TIME

PMDR.1:	MOVE	S1,MDRQUE		;GET THE MDR QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT ENTRY
PMDR.2:	JUMPF	.RETT			;DONE,,RETURN
	MOVE	AP,S2			;SAVE THE ENTRY ADDRESS
	LOAD	S1,.MRJOB(AP),MR.JOB	;GET THE JOB NUMBER
	TXNN	S1,BA%JOB		;IS IT A PSEUDO PROCESS
	JRST	PMDR.1			;NO,,SKIP IT
	MOVE	S1,.MRQEA(AP)		;GET THE QE ADDRESS
	ZERO	.QESEQ(S1),QE.ALR	;ZAP THE REQUEST FOR ALLOCATION BIT
	MOVE	S1,.MRVSL(AP)		;GET THE VSL ADDRESS
	PUSHJ	P,D$MNTV		;TRY TO MOUNT IT
	JRST	PMDR.1			;AND GO GET THE NEXT
> ;END TOPS10 CONDITIONAL

TOPS20<
D$PMDR:	$RETT	>			;A NOOP ON THE -20

	SUBTTL	D$MODR - ROUTINE TO MODIFY A USERS ALLOCATION ON THE 'FLY'

	;CALL:	S1/ The VSL to be modified
	;	S2/ The UCB of the device to be added
	;
	;RET:	True if user can have the volume, false otherwise

TOPS10<
D$MODR:	PUSHJ	P,.SAVE3		;SAVE P1 - P3
	DMOVE	P1,S1			;SAVE THE VSL AND UCB ADDRESSES
	SKIPN	P3,.UCBVL(P2)		;CHK AND LOAD THE MOUNTED VOL ADDRESS
	 $ERJMP	MD$NVM,P1		;NONE THERE,,SOMETHING FISHY HERE !!!

	;Check/Validate the Density Status

	MOVX	S1,VL.SRD		;GET SET REQUESTED DENSITY FOR USER BIT
	ANDCAM	S1,.VLFLG(P3)		;CLEAR IT INCASE SECOND TIME THROUGH
	LOAD	S1,.VSATR(P1),VS.DDN	;DID WE DEFAULT THE DENSITY ???
	JUMPN	S1,MODR.1		;YES,,CONTINUE ONWARD
	LOAD	S1,.VSFLG(P1),VS.NEW	;[1164] /NEW-VOLUME REINT?
	JUMPN	S1,MODR.0		;[1164] ..JUMP IF SO
	LOAD	S1,.VSATR(P1),VS.DEN	;NO,,GET THE REQUESTED DENSITY CODE
	LOAD	S2,.VLFLG(P3),VL.DEN	;GET THE VOLUME DENSITY
	CAMN	S1,S2			;IT WOULD BE NICE IF THEY MATCHED
	JRST	MODR.1			;THEY DO
	LOAD	S1,.VLFLG(P3),VL.LBT	;GET THE VOLUME LABEL TYPE
	PUSHJ	P,GETLBT		;CONVERT IT
	MOVX	S2,UC.WLK		;GET THE WRITE LOCKED BIT
	CAIN	S1,%UNLBL		;UNLABELED?
	TDNE	S2,.UCBST(P2)		;CANT SCREW AROUND UNLESS WRITE-ENABLED
	 $ERJMP	MD$RDD,P1		;UNLABELED OR WRITE-LOCKED
MODR.0:	LOAD	S1,.VSATR(P1),VS.DEN	;[1164] GET THE REQUESTED DENSITY
	MOVE	S1,D$DEN(S1)		;CONVERT CODE TO A BIT MAP
	TDNN	S1,.UCBST(P2)		;DRIVE SUPPORT THE REQUESTED DENSITY?
	 $ERJMP	MD$IDD,P1		;OPERATOR IS A JOKER
	MOVX	S1,VL.SRD		;GET SET REQUESTED DENSITY FOR USER BIT
	IORM	S1,.VLFLG(P3)		;REMEMBER FOR LATER

	;Check/Validate the Track Status

MODR.1:	LOAD	S1,.VSATR(P1),VS.DTK	;DID WE DEFAULT THE TRACK STATUS ???
	JUMPN	S1,MODR.2		;YES,,CONTINUE ONWARD
	LOAD	S1,.VSATR(P1),VS.TRK	;GET THE REQUESTED TRACK STATUS
	LOAD	S2,.UCBST(P2),UC.TRK	;GET THE DEVICE TRACK STATUS
	CAME	S1,S2			;THEY MUST MATCH !!!
	 $ERJMP	MD$TDM,P1		;NO,,TOO BAD

	;Check to see if requested resource matches assigned resource

MODR.2:	LOAD	S1,.VSATR(P1),VS.RSN	;GET THE REQUESTED DEVICE TYPE
	SKIPN	S1			;CAN'T BE ZERO !!!
	STOPCD	(MRN,HALT,,<Missing resource number>)
	LOAD	P2,.UCBST(P2),UC.RSN	;GET THE DEVICE RESOURCE NUMBER
	CAMN	S1,P2			;DO WE MATCH ???
	JRST	MODR.3			;YES,,HE WINS BIG !!!

	;See if we can change his allocation to include this device

	PUSHJ	P,D$BMTX		;LOCATE THE USERS 'B'
	PUSHJ	P,D$CMTX		;     AND 'C' MATRIX ENTRIES
	DMOVE	S1,P1			;GET VSL (P1) AND RSN (P2)
	PUSHJ	P,MODALC		;MODIFY THE USERS ALLOCATION
	SKIPT				;WIN,,CONTINUE
	 $ERJMP	MD$DDD,P1		;RETURN THE ERROR (DEADLOCK DETECTED) !!
MODR.3:	LOAD	S1,.VLFLG(P3),VL.DEN	;GET THE MOUNTED VOLUME DENSITY
	MOVX	S2,VL.SRD		;GET SET REQUESTED DENSITY FOR USER BIT
	TDNN	S2,.VLFLG(P3)		;GONNA DO THIS LATER?
	STORE	S1,.VSATR(P1),VS.DEN	;NO - RESET IT FOR THIS VSL
	$RETT				;RETURN
	SUBTTL	SHUFFL - Routine to shuffle resources around for a requestor

	;CALL:	S1/ A 'current' VSL address
	;
	;RET:	True if resources shuffled OK, false otherwise

	;This routine attempts to resolve deadlocks for a user by allocating
	;different resources to a users request. The current (new) requests
	;are shuffled first, then old requests are looked at. If, after all 
	;of this there is still a deadlock, tough noogies !!!

SHUFFL:	$SAVE	<P1,P2,P3,P4,T1>	;SAVE SOME AC'S
	STKVAR	<<VQUEUE,40>>		;ALLOCATE SOME QUEUE SPACE
	LOAD	P2,.VSLNK(S1),VS.LNK	;GET THE LINK CODE (NEW REQUESTS)
	MOVEI	P3,VQUEUE		;GET THE QUEUE ADDRESS
	ADD	P3,[-40,,-1]		;CREATE QUEUE PDL POINTER
	PUSH	P3,[-1]			;SIGNAL END OF 'NEW' REQUEST QUEUE
	MOVE	P4,P			;SAVE THE CURRENT STACK POINTER
	PUSH	P,[-2]			;SIGNAL END OF 'OLD' REQUEST QUEUE
	LOAD	P1,.MRCNT(AP),MR.CNT	;GET THE REQUEST COUNT
	MOVNS	P1			;NEGATE IT
	MOVSS	P1			;MOVE RIGHT TO LEFT
	HRRI	P1,.MRVSL(AP)		;CREATE AOBJN AC

SHUF.1:	MOVE	S1,0(P1)		;GET A VSL ADDRESS
	LOAD	S2,.VSFLG(S1),VS.TYP	;GET THE REQUEST TYPE
	CAXE	S2,%TAPE		;A TAPE ???
	JRST	SHUF.2			;NO,,GET NEXT
	PUSHJ	P,D$FOWN		;DOES HE HAVE IT MOUNTED ???
	JUMPT	SHUF.2			;YES,,SKIP THIS
	MOVE	S1,0(P1)		;GET THE VSL ADDRESS BACK
	LOAD	S2,.VSLNK(S1),VS.LNK	;GET ITS LINK CODE
	CAMN	P2,S2			;A 'NEW' REQUEST ???
	PUSH	P3,S1			;YES,,QUEUE IT UP
	CAME	P2,S2			;AN 'OLD' REQUEST ???
	PUSH	P,S1			;YES,,QUEUE IT UP
SHUF.2:	AOBJN	P1,SHUF.1		;CHECK ALL REQUESTS
	PUSHJ	P,D$BMTX		;LOCATE THIS GUYS 'B' MATRIX ENTRY
	PUSHJ	P,D$CMTX		;LOCATE THIS GUYS 'C' MATRIX ENTRY

SHUF.3:	POP	P3,P1			;DE-QUEUE A VSL ADDRESS
	CAMN	P1,[-1]			;DONE WITH THE 'NEW' QUEUE ???
	JRST	[MOVE P3,P		;YES,,GET POINTER TO 'OLD' QUEUE
		 JRST SHUF.3 ]		;AND KEEP ON TRUCK'N !!!
	CAMN	P1,[-2]			;DONE WITH THE 'OLD' QUEUE ???
	JRST	[MOVE P,P4		;RESTORE THE STACK POINTER
		 $RETF   ]		;JUST NO WAY TO CONTINUE !!!!!

	LOAD	S1,.VSATR(P1),VS.DEN	;GET HIS DENSITY CODE
	MOVE	S1,D$DEN(S1)		;CONVERT TO A BIT MASK
	LOAD	S2,.VSATR(P1),VS.TRK	;GET THE TRACK TYPE
	LOAD	T1,.VSATR(P1),VS.RSN	;GET THE CURRENT RESOURCE
	PUSHJ	P,ANYTAP		;GET THE NEXT RESOURCE WHICH FITS
	JUMPF	SHUF.3			;NO MORE RESOURCES,,TRY NEXT REQUEST
	MOVE	S2,S1			;GET THE NEW RESOURCE IN S2
	MOVE	S1,P1			;GET THE VSL ADDRESS IN S1
	PUSHJ	P,MODALC		;MODIFY HIS ALLOCATION
	JUMPF	SHUF.3			;LOSE,,TRY NEXT REQUEST
	MOVE	P,P4			;RESTORE THE STACK POINTER
	$RETT				;WIN,,RETURN

	SUBTTL	MODALC - Routine to modify a users resource number for a request

	;CALL:	S1/ The VSL Address
	;	S2/ The New Resource Number (RSN)
	;
	;RET:	True -  users matrix entries updated
	;	False - Deadlock detected (no matrix modifications)


MODALC:	PUSHJ	P,.SAVE3		;SAVE P1 AND P3
	DMOVE	P1,S1			;SAVE THE VSL ADDRESS AND NEW RSN
	LOAD	P3,.VSFLG(P1),VS.CLM	;GET THE RESOURCE CLAIMED STATUS IN P2
	LOAD	S1,.VSATR(P1),VS.RSN	;GET THE REQUESTED DEVICE TYPE
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,SUBBMA		;DELETE HIS 'B' MATRIX ENTRY
	JUMPE	P3,.+3			;NOT CLAIMED,,DON'T MODIFY 'A' & 'C'
	PUSHJ	P,SUBAMA		;DELETE HIS 'A' MATRIX ENTRY
	PUSHJ	P,SUBCMA		;DELETE HIS 'C' MATRIX ENTRY
	MOVE	S1,P2			;GET THE NEW RESOURCE NUMBER IN S1
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,ADDBMA		;ADD A NEW 'B' MATRIX ENTRY
	JUMPE	P3,.+3			;NOT CLAIMED,,DON'T MODIFY 'A' & 'C'
	PUSHJ	P,ADDAMA		;ADD A NEW 'A' MATRIX ENTRY
	PUSHJ	P,ADDCMA		;ADD A NEW 'C' MATRIX ENTRY
	PUSHJ	P,DEADLK		;CHECK FOR DEADLOCKS
	JUMPF	MODA.2			;FOUND SOME,,OH WELL WE TRIED !!!!
MODA.1:	STORE	P2,.VSATR(P1),VS.RSN	;WIN,,MODIFY HIS ALLOCATION
	$RETT				;RETURN

	;Here if user caused a deadlock - put matrix back in order

MODA.2:	MOVE	S1,P2			;GET THE NEW RESOURCE NUMBER IN S1
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,SUBBMA		;DELETE HIS 'B' MATRIX ENTRY
	JUMPE	P3,.+3			;NOT CLAIMED,,DON'T MODIFY 'A' & 'C'
	PUSHJ	P,SUBAMA		;DELETE HIS 'A' MATRIX ENTRY
	PUSHJ	P,SUBCMA		;DELETE HIS 'C' MATRIX ENTRY
	LOAD	S1,.VSATR(P1),VS.RSN	;GET THE REQUESTED DEVICE TYPE
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,ADDBMA		;RESTORE HIS 'B' MATRIX ENTRY
	JUMPE	P3,.+3			;NOT CLAIMED,,DON'T MODIFY 'A' & 'C'
	PUSHJ	P,ADDAMA		;RESTORE HIS 'A' MATRIX ENTRY
	PUSHJ	P,ADDCMA		;RESTORE HIS 'C' MATRIX ENTRY
	$RETF				;RETURN NO GOOD
> ;END TOPS10 CONDITIONAL
	SUBTTL	D$ALCT - ROUTINE TO ALLOCATE TAPE VOLUMES FOR 'IDENTIFY' COMMAND

	;CALL:	S1/ The VSL Address
	;
	;RET:	True if no deadlock, False otherwise

TOPS10<
	INTERN	D$ALCT

D$ALCT:	PUSHJ	P,.SAVE2		;SAVE P1 - P2
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	PUSHJ	P,D$CMTX		;LOCATE THIS GUYS 'C' MATRIX ENTRY
	LOAD	S1,.VSCVL(P1),VS.OFF	;GET THE OFFSET TO THE CURRENT VOLUME
	ADDI	S1,.VSVOL(P1)		;POINT TO ITS ADDRESS
	MOVE	S1,0(S1)		;GET THE CURRENT VOLUME ADDRESS
	PUSHJ	P,D$TVRS		;GET THE VOLUME RESOURCE NUMBER
	MOVE	P2,S1			;SAVE THE RSN IN P2
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,ADDAMA		;ADD THIS RESOURCE TO THE 'A' MATRIX
	PUSHJ	P,ADDCMA		;ADD THIS RESOURCE TO THE 'C' MATRIX
	LOAD	S1,.VSFLG(P1),VS.CLM	;HAS THIS DEVICE BEEN CLAIMED ???
	JUMPN	S1,ALCT.1		;YES,,DON'T DO IT AGAIN
	LOAD	S1,.VSATR(P1),VS.RSN	;GET THE REQUESTED DEVICE RSN
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,ADDAMA		;ADD THIS RESOURCE TO THE 'A' MATRIX
	PUSHJ	P,ADDCMA		;ADD THIS RESOURCE TO THE 'C' MATRIX
ALCT.1:	PUSHJ	P,DEADLK		;PERFORM THE DEADLOCK CHECK
	JUMPT	[MOVX  S1,VS.CLM	;WIN,,GET VSL CLAIMED STATUS
		 IORM  S1,.VSFLG(P1)	;SET IT
		 $RETT ]		;AND RETURN
	MOVE	S1,P2			;GET THE VOLUME RSN IN S1
	MOVE	S2,P1			;GET THE VSL ADDRESS IN S2
	PUSHJ	P,SUBAMA		;REMOVE THIS RSN FROM THE 'A' MATRIX
	PUSHJ	P,SUBCMA		;REMOVE THIS RSN FROM THE 'C' MATRIX
	LOAD	S1,.VSFLG(P1),VS.CLM	;GET THE DEVICE CLAIMED STATUS BIT
	JUMPN	S1,ALCT.2		;IF SET,,DON'T RETURN DEVICE ALLOCATION
	LOAD	S1,.VSATR(P1),VS.RSN	;GET THE DEVICE RESOURCE NUMBER
	MOVE	S2,P1			;GET THE VSL ADDRESS
	PUSHJ	P,SUBAMA		;REMOVE THIS RSN FROM THE 'A' MATRIX
	PUSHJ	P,SUBCMA		;REMOVE THIS RSN FROM THE 'C' MATRIX
ALCT.2:	 $ERJMP	MD$DDD,P1		;RETURN AN ERROR
> ;END TOPS10 CONDITIONAL


	END